FIFE  6e1afdbeda11afe9ac53e6023a4be96ef88f1dc6
instancerenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2017 by the FIFE team *
3  * http://www.fifengine.net *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 
24 // 3rd party library includes
25 #include <boost/bind.hpp>
26 
27 // FIFE includes
28 // These includes are split up in two parts, separated by one empty line
29 // First block: files included from the FIFE root src directory
30 // Second block: files included from the same folder
31 #include "video/renderbackend.h"
32 #include "video/image.h"
33 #include "video/imagemanager.h"
34 #include "video/sdl/sdlimage.h"
35 #include "video/animation.h"
36 #include "util/math/fife_math.h"
37 #include "util/log/logger.h"
38 #include "util/time/timemanager.h"
40 #include "model/metamodel/action.h"
42 #include "model/structures/layer.h"
44 #include "model/structures/map.h"
45 #include "model/structures/cell.h"
48 
49 #include "view/camera.h"
50 #include "view/visual.h"
51 #include "cellrenderer.h"
52 #include "instancerenderer.h"
53 
54 
55 namespace FIFE {
59  static Logger _log(LM_VIEWVIEW);
60 
62  public:
64  m_renderer = r;
65  }
67 
68  virtual void onInstanceDeleted(Instance* instance) {
69  m_renderer->removeInstance(instance);
70  }
71 
72  private:
74  };
75 
77  r(0),
78  g(0),
79  b(0),
80  width(1),
81  threshold(1),
82  dirty(false),
83  curimg(NULL),
84  renderer(r) {
85  }
87  r(0),
88  g(0),
89  b(0),
90  a(128),
91  dirty(false),
92  curimg(NULL),
93  renderer(r) {
94  }
95 
97  instance(NULL),
98  groups(),
99  w(1),
100  h(1),
101  trans(0),
102  front(true),
103  z(0) {
104  }
105 
107  renderer->addToCheck(outline);
108  }
109 
111  if (renderer->needColorBinding()) {
112  renderer->addToCheck(overlay);
113  }
114  }
115 
117  }
118 
120  return dynamic_cast<InstanceRenderer*>(cnt->getRenderer("InstanceRenderer"));
121  }
122 
123  InstanceRenderer::InstanceRenderer(RenderBackend* renderbackend, int32_t position):
124  RendererBase(renderbackend, position),
125  m_area_layer(false),
126  m_interval(60*1000),
127  m_timer_enabled(false) {
128  setEnabled(true);
129  if (m_renderbackend->getName() == "OpenGL" && m_renderbackend->isDepthBufferEnabled()) {
130  m_need_sorting = false;
131  m_need_bind_coloring = false;
132  } else {
133  m_need_sorting = true;
134  if (m_renderbackend->getName() == "SDL") {
135  m_need_bind_coloring = true;
136  } else {
137  m_need_bind_coloring = false;
138  }
139  }
140  // init timer
142  m_timer.setCallback(boost::bind(&InstanceRenderer::check, this));
143  // create delete listener
145  }
146 
148  RendererBase(old),
149  m_area_layer(false),
150  m_interval(old.m_interval),
151  m_timer_enabled(false) {
152  setEnabled(true);
153  if (m_renderbackend->getName() == "OpenGL" && m_renderbackend->isDepthBufferEnabled()) {
154  m_need_sorting = false;
155  m_need_bind_coloring = false;
156  } else {
157  m_need_sorting = true;
158  if (m_renderbackend->getName() == "SDL") {
159  m_need_bind_coloring = true;
160  } else {
161  m_need_bind_coloring = false;
162  }
163  }
164  // init timer
166  m_timer.setCallback(boost::bind(&InstanceRenderer::check, this));
167  // create delete listener
169  }
170 
172  return new InstanceRenderer(*this);
173  }
174 
176  // remove listener from instances
177  if (!m_assigned_instances.empty()) {
178  reset();
179  }
180  // delete listener
181  delete m_delete_listener;
182  }
183 
184  void InstanceRenderer::render(Camera* cam, Layer* layer, RenderList& instances) {
185 // FL_DBG(_log, "Iterating layer...");
186  CellGrid* cg = layer->getCellGrid();
187  if (!cg) {
188  FL_WARN(_log, "No cellgrid assigned to layer, cannot draw instances");
189  return;
190  }
191 
192  if(m_need_sorting) {
193  renderAlreadySorted(cam, layer, instances);
194  } else {
195  renderUnsorted(cam, layer, instances);
196  }
197  }
198 
199  void InstanceRenderer::renderUnsorted(Camera* cam, Layer* layer, RenderList& instances) {
200  // FIXME: Unlit is currently broken, maybe it would be the best to change Lightsystem
201  const bool any_effects = !(m_instance_outlines.empty() && m_instance_colorings.empty());
202  const bool unlit = !m_unlit_groups.empty();
204  // thanks to multimap, we will have transparent instances already sorted by their z value (key)
205  std::multimap<float, RenderItem*> transparentInstances;
206 
207  m_area_layer = false;
208  if(!m_instance_areas.empty()) {
209  InstanceToAreas_t::iterator area_it = m_instance_areas.begin();
210  for(;area_it != m_instance_areas.end(); area_it++) {
211  AreaInfo& info = area_it->second;
212  if(info.instance->getLocation().getLayer() == layer) {
213  if(info.front) {
215  info.z = instance_posv.z;
216  }
217  m_area_layer = true;
218  }
219  }
220  }
221  // Fixme
222  CellRenderer* cr = dynamic_cast<CellRenderer*>(cam->getRenderer("CellRenderer"));
223  Layer* fow_layer = cr->getFowLayer();
224  const bool check_fow = (fow_layer == layer && cr->isEnabledFogOfWar());
225 
226  RenderList::iterator instance_it = instances.begin();
227  for (;instance_it != instances.end(); ++instance_it) {
228 // FL_DBG(_log, "Iterating instances...");
229  Instance* instance = (*instance_it)->instance;
230  RenderItem& vc = **instance_it;
231  float vertexZ = vc.vertexZ;
232 
233  if (check_fow) {
234  Cell* cell = layer->getCellCache()->getCell(instance->getLocationRef().getLayerCoordinates());
235  if (cell) {
236  if (cell->getFoWType() != CELLV_REVEALED) {
237  continue;
238  }
239  }
240  }
241 
242  if (m_area_layer) {
243  InstanceToAreas_t::iterator areas_it = m_instance_areas.begin();
244  for(;areas_it != m_instance_areas.end(); areas_it++) {
245  AreaInfo& infoa = areas_it->second;
246  if (infoa.front) {
247  if (infoa.z >= vc.screenpoint.z) {
248  continue;
249  }
250  }
251 
252  std::string str_name = instance->getObject()->getNamespace();
253  std::list<std::string>::iterator group_it = infoa.groups.begin();
254  for (;group_it != infoa.groups.end(); ++group_it) {
255  if (str_name.find((*group_it)) != std::string::npos) {
256  ScreenPoint p;
257  Rect rec;
259  rec.x = p.x - infoa.w / 2;
260  rec.y = p.y - infoa.h / 2;
261  rec.w = infoa.w;
262  rec.h = infoa.h;
263  if (infoa.instance != instance && vc.dimensions.intersects(rec)) {
264  vc.transparency = 255 - infoa.trans;
265  // dirty hack to reset the transparency on next pump
266  InstanceVisual* visual = instance->getVisual<InstanceVisual>();
267  visual->setVisible(!visual->isVisible());
268  visual->setVisible(!visual->isVisible());
269  }
270  }
271  }
272  }
273  }
274 
275  // if instance is not opacous
276  if (vc.transparency != 255) {
277  transparentInstances.insert(std::pair<float, RenderItem*>(vertexZ, &vc));
278  continue;
279  }
280 
281  uint8_t coloringColor[4] = { 0 };
282  Image* outlineImage = 0;
283  bool recoloring = false;
284  if (any_effects) {
285  // coloring
286  InstanceToColoring_t::iterator coloring_it = m_instance_colorings.find(instance);
287  const bool coloring = coloring_it != m_instance_colorings.end();
288  if (coloring) {
289  coloringColor[0] = coloring_it->second.r;
290  coloringColor[1] = coloring_it->second.g;
291  coloringColor[2] = coloring_it->second.b;
292  coloringColor[3] = coloring_it->second.a;
293  recoloring = true;
294  }
295  // outline
296  InstanceToOutlines_t::iterator outline_it = m_instance_outlines.find(instance);
297  const bool outline = outline_it != m_instance_outlines.end();
298  if (outline) {
299  if (lm != 0) {
300  // first render normal image without stencil and alpha test (0)
301  // so it wont look aliased and then with alpha test render only outline (its 'binary' image)
302  outlineImage = bindOutline(outline_it->second, vc, cam);
303  } else {
304  bindOutline(outline_it->second, vc, cam)->renderZ(vc.dimensions, vertexZ, vc.transparency, static_cast<uint8_t*>(0));
305  }
306  }
307  }
308 // if(lm != 0) {
309 // if(unlit) {
310 // bool found = false;
311 // std::string lit_name = instance->getObject()->getNamespace();
312 // std::list<std::string>::iterator unlit_it = m_unlit_groups.begin();
313 // for(;unlit_it != m_unlit_groups.end(); ++unlit_it) {
314 // if(lit_name.find(*unlit_it) != std::string::npos) {
315 // found = true;
316 // break;
317 // }
318 // }
319 // vc.image->render(vc.dimensions, vc.transparency, recoloring ? coloringColor : 0);
320 // if (found) {
321 // m_renderbackend->changeRenderInfos(1, 4, 5, true, true, 255, REPLACE, ALWAYS, recoloring ? OVERLAY_TYPE_COLOR : OVERLAY_TYPE_NONE);
322 // } else {
323 // m_renderbackend->changeRenderInfos(1, 4, 5, true, true, 0, ZERO, ALWAYS, recoloring ? OVERLAY_TYPE_COLOR : OVERLAY_TYPE_NONE);
324 // }
325 // if (outlineImage) {
326 // outlineImage->render(vc.dimensions, vc.transparency);
327 // m_renderbackend->changeRenderInfos(1, 4, 5, false, true, 255, REPLACE, ALWAYS);
328 // }
329 // continue;
330 // }
331 // }
332  // overlay
333  if (vc.m_overlay) {
334  renderOverlay(RENDER_DATA_MULTITEXTURE_Z, &vc, coloringColor, recoloring);
335  // no overlay
336  } else {
337  vc.image->renderZ(vc.dimensions, vertexZ, vc.transparency, recoloring ? coloringColor : 0);
338  }
339 
340  if (outlineImage) {
341  outlineImage->renderZ(vc.dimensions, vertexZ, vc.transparency, static_cast<uint8_t*>(0));
343  }
344  }
345  // iterate through all (semi) transparent instances
346  std::multimap<float, RenderItem*>::iterator it = transparentInstances.begin();
347  for( ; it != transparentInstances.end(); ++it) {
348  RenderItem& vc = *(it->second);
349  Instance* instance = vc.instance;
350  uint8_t alpha = vc.transparency;
351  float vertexZ = it->first;
352 
353  uint8_t coloringColor[4] = { 0 };
354  Image* outlineImage = 0;
355  bool recoloring = false;
356  if (any_effects) {
357  // coloring
358  InstanceToColoring_t::iterator coloring_it = m_instance_colorings.find(instance);
359  const bool coloring = coloring_it != m_instance_colorings.end();
360  if (coloring) {
361  coloringColor[0] = coloring_it->second.r;
362  coloringColor[1] = coloring_it->second.g;
363  coloringColor[2] = coloring_it->second.b;
364  coloringColor[3] = coloring_it->second.a;
365  recoloring = true;
366  }
367  // outline
368  InstanceToOutlines_t::iterator outline_it = m_instance_outlines.find(instance);
369  const bool outline = outline_it != m_instance_outlines.end();
370  if (outline) {
371  if (lm != 0) {
372  // first render normal image without stencil and alpha test (0)
373  // so it wont look aliased and then with alpha test render only outline (its 'binary' image)
374  outlineImage = bindOutline(outline_it->second, vc, cam);
375  } else {
376  bindOutline(outline_it->second, vc, cam)->renderZ(vc.dimensions, vertexZ, vc.transparency, static_cast<uint8_t*>(0));
377  }
378  }
379  }
380  // overlay
381  if (vc.m_overlay) {
382  renderOverlay(RENDER_DATA_MULTITEXTURE_Z, &vc, coloringColor, recoloring);
383  // no overlay
384  } else {
385  vc.image->renderZ(vc.dimensions, vertexZ, vc.transparency, recoloring ? coloringColor : 0);
386  }
387 
388  if (outlineImage) {
389  outlineImage->renderZ(vc.dimensions, vertexZ, vc.transparency, static_cast<uint8_t*>(0));
391  }
392  }
393  }
394 
396  const bool any_effects = !(m_instance_outlines.empty() && m_instance_colorings.empty());
397  const bool unlit = !m_unlit_groups.empty();
399 
400  m_area_layer = false;
401  if(!m_instance_areas.empty()) {
402  InstanceToAreas_t::iterator area_it = m_instance_areas.begin();
403  for(;area_it != m_instance_areas.end(); area_it++) {
404  AreaInfo& info = area_it->second;
405  if(info.instance->getLocation().getLayer() == layer) {
406  if(info.front) {
408  info.z = instance_posv.z;
409  }
410  m_area_layer = true;
411  }
412  }
413  }
414  // Fixme
415  CellRenderer* cr = dynamic_cast<CellRenderer*>(cam->getRenderer("CellRenderer"));
416  Layer* fow_layer = cr->getFowLayer();
417  bool check_fow = (fow_layer == layer && cr->isEnabledFogOfWar());
418 
419  RenderList::iterator instance_it = instances.begin();
420  for (;instance_it != instances.end(); ++instance_it) {
421 // FL_DBG(_log, "Iterating instances...");
422  Instance* instance = (*instance_it)->instance;
423  RenderItem& vc = **instance_it;
424 
425  if (check_fow) {
426  Cell* cell = layer->getCellCache()->getCell(instance->getLocationRef().getLayerCoordinates());
427  if (cell) {
428  if (cell->getFoWType() != CELLV_REVEALED) {
429  continue;
430  }
431  }
432  }
433 
434  if(m_area_layer) {
435  InstanceToAreas_t::iterator areas_it = m_instance_areas.begin();
436  for(;areas_it != m_instance_areas.end(); areas_it++) {
437  AreaInfo& infoa = areas_it->second;
438  if(infoa.front) {
439  if(infoa.z >= vc.screenpoint.z) {
440  continue;
441  }
442  }
443 
444  std::string str_name = instance->getObject()->getNamespace();
445  std::list<std::string>::iterator group_it = infoa.groups.begin();
446  for(;group_it != infoa.groups.end(); ++group_it) {
447  if(str_name.find((*group_it)) != std::string::npos) {
448  ScreenPoint p;
449  Rect rec;
451  rec.x = p.x - infoa.w / 2;
452  rec.y = p.y - infoa.h / 2;
453  rec.w = infoa.w;
454  rec.h = infoa.h;
455  if(infoa.instance != instance && vc.dimensions.intersects(rec)) {
456  vc.transparency = 255 - infoa.trans;
457  // dirty hack to reset the transparency on next pump
458  InstanceVisual* visual = instance->getVisual<InstanceVisual>();
459  visual->setVisible(!visual->isVisible());
460  visual->setVisible(!visual->isVisible());
461  }
462  }
463  }
464  }
465  }
466 
467 // FL_DBG(_log, LMsg("Instance layer coordinates = ") << instance->getLocationRef().getLayerCoordinates());
468 
469  uint8_t coloringColor[4] = { 0 };
470  Image* outlineImage = 0;
471  bool recoloring = false;
472  if (any_effects) {
473  // coloring
474  InstanceToColoring_t::iterator coloring_it = m_instance_colorings.find(instance);
475  const bool coloring = coloring_it != m_instance_colorings.end();
476  if (coloring && !m_need_bind_coloring) {
477  coloringColor[0] = coloring_it->second.r;
478  coloringColor[1] = coloring_it->second.g;
479  coloringColor[2] = coloring_it->second.b;
480  coloringColor[3] = coloring_it->second.a;
481  recoloring = true;
482  }
483  // outline
484  InstanceToOutlines_t::iterator outline_it = m_instance_outlines.find(instance);
485  const bool outline = outline_it != m_instance_outlines.end();
486  if (outline) {
487  if (lm != 0) {
488  // first render normal image without stencil and alpha test (0)
489  // so it wont look aliased and then with alpha test render only outline (its 'binary' image)
490  outlineImage = bindOutline(outline_it->second, vc, cam);
491  } else {
492  bindOutline(outline_it->second, vc, cam)->render(vc.dimensions, vc.transparency);
493  }
494  }
495  // coloring for SDL
496  if (coloring && m_need_bind_coloring) {
497  bindColoring(coloring_it->second, vc, cam)->render(vc.dimensions, vc.transparency);
499  continue;
500  }
501  }
502  if(lm != 0) {
503  if(unlit) {
504  bool found = false;
505  std::string lit_name = instance->getObject()->getNamespace();
506  std::list<std::string>::iterator unlit_it = m_unlit_groups.begin();
507  for(;unlit_it != m_unlit_groups.end(); ++unlit_it) {
508  if(lit_name.find(*unlit_it) != std::string::npos) {
509  found = true;
510  break;
511  }
512  }
513  vc.image->render(vc.dimensions, vc.transparency, recoloring ? coloringColor : 0);
514  if (found) {
516  } else {
518  }
519  if (outlineImage) {
520  outlineImage->render(vc.dimensions, vc.transparency);
522  }
523  continue;
524  }
525  }
526  // overlay
527  if (vc.m_overlay) {
528  renderOverlay(RENDER_DATA_WITHOUT_Z, &vc, coloringColor, recoloring);
529  // no overlay
530  } else {
531  vc.image->render(vc.dimensions, vc.transparency, recoloring ? coloringColor : 0);
532  }
533 
534  if (outlineImage) {
535  outlineImage->render(vc.dimensions, vc.transparency);
537  }
538  }
539  }
540 
541  void InstanceRenderer::renderOverlay(RenderDataType type, RenderItem* item, uint8_t const* coloringColor, bool recoloring) {
542  RenderItem& vc = *item;
543  Instance* instance = vc.instance;
544  bool withZ = type != RENDER_DATA_WITHOUT_Z;
545  float vertexZ = vc.vertexZ;
546 
547  // animation overlay
548  std::vector<ImagePtr>* animationOverlay = vc.getAnimationOverlay();
549  // animation color overlay
550  std::vector<OverlayColors*>* animationColorOverlay = vc.getAnimationColorOverlay();
551 
552  // animation overlay without color overlay
553  if (animationOverlay && !animationColorOverlay) {
554  if (withZ) {
555  for (std::vector<ImagePtr>::iterator it = animationOverlay->begin(); it != animationOverlay->end(); ++it) {
556  (*it)->renderZ(vc.dimensions, vertexZ, vc.transparency, recoloring ? coloringColor : 0);
557  }
558  } else {
559  for (std::vector<ImagePtr>::iterator it = animationOverlay->begin(); it != animationOverlay->end(); ++it) {
560  (*it)->render(vc.dimensions, vc.transparency, recoloring ? coloringColor : 0);
561  }
562  }
563  // animation overlay with color overlay
564  } else if (animationOverlay && animationColorOverlay) {
565  std::vector<OverlayColors*>::iterator ovit = animationColorOverlay->begin();
566  std::vector<ImagePtr>::iterator it = animationOverlay->begin();
567  for (; it != animationOverlay->end(); ++it, ++ovit) {
568  OverlayColors* oc = (*ovit);
569  if (!oc) {
570  if (withZ) {
571  (*it)->renderZ(vc.dimensions, vertexZ, vc.transparency, recoloring ? coloringColor : 0);
572  } else {
573  (*it)->render(vc.dimensions, vc.transparency, recoloring ? coloringColor : 0);
574  }
575  } else {
576  if (oc->getColors().size() > 1) {
577  std::map<Color, Color>::const_iterator cit = oc->getColors().begin();
578  uint8_t factor[4] = { 0, 0, 0, cit->second.getAlpha() };
579  // multi color overlay
580  ImagePtr multiColorOverlay;
581  if (recoloring) {
582  // create temp OverlayColors
584  float alphaFactor1 = static_cast<float>(coloringColor[3] / 255.0);
585  const std::map<Color, Color>& defaultColors = oc->getColors();
586  for (std::map<Color, Color>::const_iterator c_it = defaultColors.begin(); c_it != defaultColors.end(); ++c_it) {
587  if (c_it->second.getAlpha() == 0) {
588  continue;
589  }
590  float alphaFactor2 = static_cast<float>(c_it->second.getAlpha() / 255.0);
591  Color c(coloringColor[0]*(1.0-alphaFactor1) + (c_it->second.getR()*alphaFactor2)*alphaFactor1,
592  coloringColor[1]*(1.0-alphaFactor1) + (c_it->second.getG()*alphaFactor2)*alphaFactor1,
593  coloringColor[2]*(1.0-alphaFactor1) + (c_it->second.getB()*alphaFactor2)*alphaFactor1, 255);
594  temp->changeColor(c_it->first, c);
595  }
596  // create new factor
597  factor[3] = static_cast<uint8_t>(255 - factor[3]);
598  factor[3] = std::min(coloringColor[3], factor[3]);
599  // get overlay image with temp colors
600  multiColorOverlay = getMultiColorOverlay(vc, temp);
601  delete temp;
602  } else {
603  multiColorOverlay = getMultiColorOverlay(vc, oc);
604  factor[3] = 0;
605  }
606  if (withZ) {
607  (*it)->renderZ(vc.dimensions, vertexZ, vc.transparency, recoloring ? coloringColor : 0);
608  (*it)->renderZ(vc.dimensions, vertexZ, multiColorOverlay, vc.transparency, factor);
609  } else {
610  (*it)->render(vc.dimensions, vc.transparency, recoloring ? coloringColor : 0);
611  (*it)->render(vc.dimensions, multiColorOverlay, vc.transparency, factor);
612  }
613  continue;
614  }
615  // single color overlay
616  std::map<Color, Color>::const_iterator color_it = oc->getColors().begin();
617  uint8_t rgba[4] = { color_it->second.getR(), color_it->second.getG(), color_it->second.getB(), static_cast<uint8_t>(255-color_it->second.getAlpha()) };
618  bool noOverlay = rgba[3] == 255;
619  if (recoloring) {
620  if (!noOverlay) {
621  float alphaFactor1 = static_cast<float>(coloringColor[3] / 255.0);
622  float alphaFactor2 = 1.0-static_cast<float>(rgba[3] / 255.0);
623  rgba[0] = coloringColor[0]*(1.0-alphaFactor1) + (rgba[0]*alphaFactor2)*alphaFactor1;
624  rgba[1] = coloringColor[1]*(1.0-alphaFactor1) + (rgba[1]*alphaFactor2)*alphaFactor1;
625  rgba[2] = coloringColor[2]*(1.0-alphaFactor1) + (rgba[2]*alphaFactor2)*alphaFactor1;
626  rgba[3] = std::min(coloringColor[3], rgba[3]);
627  }
628  }
629  if (withZ) {
630  (*it)->renderZ(vc.dimensions, vertexZ, vc.transparency, recoloring ? coloringColor : 0);
631  if (!noOverlay) {
632  (*it)->renderZ(vc.dimensions, vertexZ, oc->getColorOverlayImage(), vc.transparency, rgba);
634  }
635  } else {
636  (*it)->render(vc.dimensions, vc.transparency, recoloring ? coloringColor : 0);
637  if (!noOverlay) {
638  (*it)->render(vc.dimensions, oc->getColorOverlayImage(), vc.transparency, rgba);
640  }
641  }
642  }
643  }
644  } else {
645  OverlayColors* colorOverlay = vc.getColorOverlay();
646  if (colorOverlay->getColors().size() > 1) {
647  // multi color overlay
648  ImagePtr multiColorOverlay;
649  // interpolation factor
650  std::map<Color, Color>::const_iterator it = colorOverlay->getColors().begin();
651  uint8_t factor[4] = { 0, 0, 0, it->second.getAlpha() };
652  if (recoloring) {
653  // create temp OverlayColors
654  OverlayColors* temp = new OverlayColors(colorOverlay->getColorOverlayImage());
655  float alphaFactor1 = static_cast<float>(coloringColor[3] / 255.0);
656  const std::map<Color, Color>& defaultColors = colorOverlay->getColors();
657  for (std::map<Color, Color>::const_iterator c_it = defaultColors.begin(); c_it != defaultColors.end(); ++c_it) {
658  if (c_it->second.getAlpha() == 0) {
659  continue;
660  }
661  float alphaFactor2 = static_cast<float>(c_it->second.getAlpha() / 255.0);
662  Color c(coloringColor[0]*(1.0-alphaFactor1) + (c_it->second.getR()*alphaFactor2)*alphaFactor1,
663  coloringColor[1]*(1.0-alphaFactor1) + (c_it->second.getG()*alphaFactor2)*alphaFactor1,
664  coloringColor[2]*(1.0-alphaFactor1) + (c_it->second.getB()*alphaFactor2)*alphaFactor1, 255);
665  temp->changeColor(c_it->first, c);
666  }
667  // create new factor
668  factor[3] = static_cast<uint8_t>(255 - factor[3]);
669  factor[3] = std::min(coloringColor[3], factor[3]);
670  // get overlay image with temp colors
671  multiColorOverlay = getMultiColorOverlay(vc, temp);
672  delete temp;
673  }
674  if (!multiColorOverlay) {
675  multiColorOverlay = getMultiColorOverlay(vc);
676  factor[3] = 0;
677  }
678  if (withZ) {
679  vc.image->renderZ(vc.dimensions, vertexZ, vc.transparency, recoloring ? coloringColor : 0);
680  vc.image->renderZ(vc.dimensions, vertexZ, multiColorOverlay, vc.transparency, factor);
681  } else {
682  vc.image->render(vc.dimensions, vc.transparency, recoloring ? coloringColor : 0);
683  vc.image->render(vc.dimensions, multiColorOverlay, vc.transparency, factor);
684  }
685  } else {
686  // single color overlay
687  std::map<Color, Color>::const_iterator color_it = colorOverlay->getColors().begin();
688  uint8_t rgba[4] = { color_it->second.getR(), color_it->second.getG(), color_it->second.getB(), static_cast<uint8_t>(255-color_it->second.getAlpha()) };
689  bool noOverlay = rgba[3] == 255;
690  if (recoloring) {
691  if (!noOverlay) {
692  float alphaFactor1 = static_cast<float>(coloringColor[3] / 255.0);
693  float alphaFactor2 = 1.0-static_cast<float>(rgba[3] / 255.0);
694  rgba[0] = coloringColor[0]*(1.0-alphaFactor1) + (rgba[0]*alphaFactor2)*alphaFactor1;
695  rgba[1] = coloringColor[1]*(1.0-alphaFactor1) + (rgba[1]*alphaFactor2)*alphaFactor1;
696  rgba[2] = coloringColor[2]*(1.0-alphaFactor1) + (rgba[2]*alphaFactor2)*alphaFactor1;
697  rgba[3] = std::min(coloringColor[3], rgba[3]);
698  }
699  }
700  if (withZ) {
701  vc.image->renderZ(vc.dimensions, vertexZ, vc.transparency, recoloring ? coloringColor : 0);
702  if (!noOverlay) {
703  vc.image->renderZ(vc.dimensions, vertexZ, colorOverlay->getColorOverlayImage(), vc.transparency, rgba);
705  }
706  } else {
707  vc.image->render(vc.dimensions, vc.transparency, recoloring ? coloringColor : 0);
708  if (!noOverlay) {
709  vc.image->render(vc.dimensions, colorOverlay->getColorOverlayImage(), vc.transparency, rgba);
711  }
712  }
713  }
714  }
715  }
716 
717  inline bool aboveThreshold(int32_t threshold, int32_t alpha, int32_t prev_alpha) {
718  if(threshold > 1) {
719  // new behavior
720  if (((alpha - threshold) >= 0 || (prev_alpha - threshold) >= 0) && (alpha != prev_alpha)) {
721  return true;
722  } else {
723  return false;
724  }
725  } else {
726  // old behavior
727  if((alpha == 0 || prev_alpha == 0) && (alpha != prev_alpha)) {
728  return true;
729  } else {
730  return false;
731  }
732  }
733  }
734 
736  bool valid = isValidImage(info.outline);
737  if (!info.dirty && info.curimg == vc.image.get() && valid) {
738  removeFromCheck(info.outline);
739  // optimization for outline that has not changed
740  return info.outline.get();
741  } else {
742  info.curimg = vc.image.get();
743  }
744 
745  // if outline has changed we can maybe free the old effect image
746  if (valid) {
747  addToCheck(info.outline);
748  }
749  // special case for animation overlay
750  if (vc.getAnimationOverlay()) {
751  return bindMultiOutline(info, vc, cam);
752  }
753  // NOTE: Since r3721 outline is just the 'border' so to render everything correctly
754  // we need to first render normal image, and then its outline.
755  // This helps much with lighting stuff and doesn't require from us to copy image.
756 
757  bool found = false;
758  // create name
759  std::stringstream sts;
760  sts << vc.image.get()->getName() << "," << static_cast<uint32_t>(info.r) << "," <<
761  static_cast<uint32_t>(info.g) << "," << static_cast<uint32_t>(info.b) << "," << info.width;
762  // search image
763  if (ImageManager::instance()->exists(sts.str())) {
764  info.outline = ImageManager::instance()->getPtr(sts.str());
765  if (isValidImage(info.outline)) {
766  removeFromCheck(info.outline);
767  // mark outline as not dirty since we found it here
768  info.dirty = false;
769  return info.outline.get();
770  }
771  found = true;
772  }
773 
774 
775  // With lazy loading we can come upon a situation where we need to generate outline from
776  // uninitialised shared image
777  if(vc.image->isSharedImage()) {
778  vc.image->forceLoadInternal();
779  }
780 
781  SDL_Surface* outline_surface = SDL_CreateRGBSurface(0,
782  vc.image->getWidth(), vc.image->getHeight(), 32,
783  RMASK, GMASK, BMASK, AMASK);
784 
785  // TODO: optimize...
786  uint8_t r, g, b, a = 0;
787 
788  // vertical sweep
789  for (int32_t x = 0; x < outline_surface->w; x ++) {
790  int32_t prev_a = 0;
791  for (int32_t y = 0; y < outline_surface->h; y ++) {
792  vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
793  if (aboveThreshold(info.threshold, static_cast<int32_t>(a), prev_a)) {
794  if (a < prev_a) {
795  for (int32_t yy = y; yy < y + info.width; yy++) {
796  Image::putPixel(outline_surface, x, yy, info.r, info.g, info.b);
797  }
798  } else {
799  for (int32_t yy = y - info.width; yy < y; yy++) {
800  Image::putPixel(outline_surface, x, yy, info.r, info.g, info.b);
801  }
802  }
803  }
804  prev_a = a;
805  }
806  }
807  // horizontal sweep
808  for (int32_t y = 0; y < outline_surface->h; y ++) {
809  int32_t prev_a = 0;
810  for (int32_t x = 0; x < outline_surface->w; x ++) {
811  vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
812  if (aboveThreshold(info.threshold, static_cast<int32_t>(a), prev_a)) {
813  if (a < prev_a) {
814  for (int32_t xx = x; xx < x + info.width; xx++) {
815  Image::putPixel(outline_surface, xx, y, info.r, info.g, info.b);
816  }
817  } else {
818  for (int32_t xx = x - info.width; xx < x; xx++) {
819  Image::putPixel(outline_surface, xx, y, info.r, info.g, info.b);
820  }
821  }
822  }
823  prev_a = a;
824  }
825  }
826 
827  // In case of OpenGL backend, SDLImage needs to be converted
828  Image* img = m_renderbackend->createImage(sts.str(), outline_surface);
830 
831  if (found) {
832  // image exists but is not "loaded"
833  removeFromCheck(info.outline);
834  ImagePtr temp(img);
835  info.outline.get()->copySubimage(0, 0, temp);
837  } else {
838  // create and add image
839  info.outline = ImageManager::instance()->add(img);
840  }
841  // mark outline as not dirty since we created/recreated it here
842  info.dirty = false;
843 
844  return info.outline.get();
845  }
846 
848  // NOTE: Since r3721 outline is just the 'border' so to render everything correctly
849  // we need to first render normal image, and then its outline.
850  // This helps much with lighting stuff and doesn't require from us to copy image.
851 
852  bool found = false;
853  // create name
854  std::stringstream sts;
855  uint32_t mw = 0;
856  uint32_t mh = 0;
857  std::vector<ImagePtr>* animationOverlays = vc.getAnimationOverlay();
858  std::vector<ImagePtr>::iterator it = animationOverlays->begin();
859  for (; it != animationOverlays->end(); ++it) {
860  // With lazy loading we can come upon a situation where we need to generate outline from
861  // uninitialised shared image
862  if ((*it)->isSharedImage()) {
863  (*it)->forceLoadInternal();
864  }
865  sts << (*it)->getName() << ",";
866  mw = std::max(mw, (*it)->getWidth());
867  mh = std::max(mh, (*it)->getHeight());
868  }
869  sts << static_cast<uint32_t>(info.r) << "," <<
870  static_cast<uint32_t>(info.g) << "," << static_cast<uint32_t>(info.b) << "," << info.width;
871  // search image
872  if (ImageManager::instance()->exists(sts.str())) {
873  info.outline = ImageManager::instance()->getPtr(sts.str());
874  if (isValidImage(info.outline)) {
875  removeFromCheck(info.outline);
876  // mark outline as not dirty since we found it here
877  info.dirty = false;
878  return info.outline.get();
879  }
880  found = true;
881  }
882 
883  SDL_Surface* outline_surface = SDL_CreateRGBSurface(0, mw, mh, 32,
884  RMASK, GMASK, BMASK, AMASK);
885 
886  // TODO: optimize...
887  uint8_t r, g, b, a = 0;
888 
889  it = animationOverlays->begin();
890  for (; it != animationOverlays->end(); ++it) {
891  // vertical sweep
892  for (uint32_t x = 0; x < (*it)->getWidth(); x++) {
893  int32_t prev_a = 0;
894  for (uint32_t y = 0; y < (*it)->getHeight(); y++) {
895  (*it)->getPixelRGBA(x, y, &r, &g, &b, &a);
896  if (aboveThreshold(info.threshold, static_cast<int32_t>(a), prev_a)) {
897  if (a < prev_a) {
898  for (uint32_t yy = y; yy < y + info.width; yy++) {
899  int32_t tx = x + (mw/2 - (*it)->getWidth()/2);
900  int32_t ty = yy + (mh/2 - (*it)->getHeight()/2);
901  Image::putPixel(outline_surface, tx, ty, info.r, info.g, info.b);
902  }
903  } else {
904  for (uint32_t yy = y - info.width; yy < y; yy++) {
905  int32_t tx = x + (mw/2 - (*it)->getWidth()/2);
906  int32_t ty = yy + (mh/2 - (*it)->getHeight()/2);
907  Image::putPixel(outline_surface, tx, ty, info.r, info.g, info.b);
908  }
909  }
910  }
911  prev_a = a;
912  }
913  }
914 
915  // horizontal sweep
916  for (uint32_t y = 0; y < (*it)->getHeight(); y++) {
917  int32_t prev_a = 0;
918  for (uint32_t x = 0; x < (*it)->getWidth(); x++) {
919  (*it)->getPixelRGBA(x, y, &r, &g, &b, &a);
920  if (aboveThreshold(info.threshold, static_cast<int32_t>(a), prev_a)) {
921  if (a < prev_a) {
922  for (uint32_t xx = x; xx < x + info.width; xx++) {
923  int32_t tx = xx + (mw/2 - (*it)->getWidth()/2);
924  int32_t ty = y + (mh/2 - (*it)->getHeight()/2);
925  Image::putPixel(outline_surface, tx, ty, info.r, info.g, info.b);
926  }
927  } else {
928  for (uint32_t xx = x - info.width; xx < x; xx++) {
929  int32_t tx = xx + (mw/2 - (*it)->getWidth()/2);
930  int32_t ty = y + (mh/2 - (*it)->getHeight()/2);
931  Image::putPixel(outline_surface, tx, ty, info.r, info.g, info.b);
932  }
933  }
934  }
935  prev_a = a;
936  }
937  }
938  }
939 
940  // In case of OpenGL backend, SDLImage needs to be converted
941  Image* img = m_renderbackend->createImage(sts.str(), outline_surface);
943 
944  if (found) {
945  // image exists but is not "loaded"
946  removeFromCheck(info.outline);
947  ImagePtr temp(img);
948  info.outline.get()->copySubimage(0, 0, temp);
950  } else {
951  // create and add image
952  info.outline = ImageManager::instance()->add(img);
953  }
954  // mark outline as not dirty since we created/recreated it here
955  info.dirty = false;
956 
957  return info.outline.get();
958  }
959 
961  bool valid = isValidImage(info.overlay);
962  if (!info.dirty && info.curimg == vc.image.get() && valid) {
963  removeFromCheck(info.overlay);
964  // optimization for coloring that has not changed
965  return info.overlay.get();
966  } else {
967  info.curimg = vc.image.get();
968  }
969 
970  // if coloring has changed we can maybe free the old effect image
971  if (valid) {
972  addToCheck(info.overlay);
973  }
974 
975  bool found = false;
976  // create name
977  std::stringstream sts;
978  sts << vc.image.get()->getName() << "," << static_cast<uint32_t>(info.r) << "," <<
979  static_cast<uint32_t>(info.g) << "," << static_cast<uint32_t>(info.b) << "," << static_cast<uint32_t>(info.a);
980  // search image
981  if (ImageManager::instance()->exists(sts.str())) {
982  info.overlay = ImageManager::instance()->getPtr(sts.str());
983  valid = isValidImage(info.overlay);
984  if (valid) {
985  removeFromCheck(info.overlay);
986  // mark overlay as not dirty since we found it here
987  info.dirty = false;
988  return info.overlay.get();
989  }
990  found = true;
991  }
992 
993  // With lazy loading we can come upon a situation where we need to generate coloring from
994  // uninitialised shared image
995  if(vc.image->isSharedImage()) {
996  vc.image->forceLoadInternal();
997  }
998 
999  // not found so we create it
1000  SDL_Surface* overlay_surface = SDL_CreateRGBSurface(0,
1001  vc.image->getWidth(), vc.image->getHeight(), 32,
1002  RMASK, GMASK, BMASK, AMASK);
1003 
1004  uint8_t r, g, b, a = 0;
1005  float alphaFactor = static_cast<float>(info.a/255.0);
1006  for (int32_t x = 0; x < overlay_surface->w; x ++) {
1007  for (int32_t y = 0; y < overlay_surface->h; y ++) {
1008  vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
1009  if (a > 0) {
1010  Image::putPixel(overlay_surface, x, y, info.r*(1.0-alphaFactor) + r*alphaFactor, info.g*(1.0-alphaFactor) + g*alphaFactor, info.b*(1.0-alphaFactor) + b*alphaFactor, a);
1011  }
1012  }
1013  }
1014 
1015  // In case of OpenGL backend, SDLImage needs to be converted
1016  Image* img = m_renderbackend->createImage(sts.str(), overlay_surface);
1017 
1018  if (found) {
1019  // image exists but is not "loaded"
1020  removeFromCheck(info.overlay);
1021  ImagePtr temp(img);
1022  info.overlay.get()->copySubimage(0, 0, temp);
1024  } else {
1025  // add image
1027  info.overlay = ImageManager::instance()->add(img);
1028  }
1029  // mark overlay as not dirty since we created/recreated it here
1030  info.dirty = false;
1031 
1032  return info.overlay.get();
1033  }
1034 
1036  // multi color overlay
1037  const std::map<Color, Color>& colorMap = colors ? colors->getColors() : vc.getColorOverlay()->getColors();
1038  std::map<Color, Color>::const_iterator it = colorMap.begin();
1039  ImagePtr colorOverlayImage = colors ? colors->getColorOverlayImage() : vc.getColorOverlay()->getColorOverlayImage();
1040  ImagePtr colorOverlay;
1041 
1042  // create name
1043  std::stringstream sts;
1044  sts << colorOverlayImage.get()->getName();
1045  for (; it != colorMap.end(); ++it) {
1046  sts << "," << static_cast<uint32_t>(it->second.getR() | (it->second.getG() << 8) | (it->second.getB() << 16) | (it->second.getAlpha()<<24));
1047  }
1048  bool exist = false;
1049  bool found = false;
1050  if (ImageManager::instance()->exists(sts.str())) {
1051  exist = true;
1052  colorOverlay = ImageManager::instance()->getPtr(sts.str());
1053  if (isValidImage(colorOverlay)) {
1054  removeFromCheck(colorOverlay);
1055  found = true;
1056  }
1057  }
1058  if (!exist || !found) {
1059  // With lazy loading we can come upon a situation where we need to generate color overlay from
1060  // uninitialised shared image
1061  if (colorOverlayImage->isSharedImage()) {
1062  colorOverlayImage->forceLoadInternal();
1063  }
1064 
1065  // not found so we create it
1066  SDL_Surface* overlay_surface = SDL_CreateRGBSurface(0,
1067  colorOverlayImage->getWidth(), colorOverlayImage->getHeight(), 32,
1068  RMASK, GMASK, BMASK, AMASK);
1069 
1070  uint8_t r, g, b, a = 0;
1071  for (int32_t x = 0; x < overlay_surface->w; x++) {
1072  for (int32_t y = 0; y < overlay_surface->h; y++) {
1073  colorOverlayImage->getPixelRGBA(x, y, &r, &g, &b, &a);
1074  Color c(r, g, b, a);
1075  it = colorMap.find(c);
1076  if (it != colorMap.end()) {
1077  Image::putPixel(overlay_surface, x, y, it->second.getR(), it->second.getG(), it->second.getB(), it->second.getAlpha());
1078  } else {
1079  Image::putPixel(overlay_surface, x, y, r, g, b, a);
1080  }
1081  }
1082  }
1083 
1084  // In case of OpenGL backend, SDLImage needs to be converted
1085  Image* img = m_renderbackend->createImage(sts.str(), overlay_surface);
1086 
1087  if (exist) {
1088  // image exists but is not "loaded"
1089  removeFromCheck(colorOverlay);
1090  ImagePtr temp(img);
1091  colorOverlay.get()->setSurface(img->detachSurface());
1092  colorOverlay.get()->setState(IResource::RES_LOADED);
1093  } else {
1094  // add image
1096  colorOverlay = ImageManager::instance()->add(img);
1097  }
1098  }
1099  addToCheck(colorOverlay);
1100  return colorOverlay;
1101  }
1102 
1103  void InstanceRenderer::addOutlined(Instance* instance, int32_t r, int32_t g, int32_t b, int32_t width, int32_t threshold) {
1104  OutlineInfo newinfo(this);
1105  newinfo.r = r;
1106  newinfo.g = g;
1107  newinfo.b = b;
1108  newinfo.threshold = threshold;
1109  newinfo.width = width;
1110  newinfo.dirty = true;
1111 
1112  // attempts to insert the element into the outline map
1113  // will return false in the second value of the pair if the instance already exists
1114  // in the map and the first value of the pair will then be an iterator to the
1115  // existing data for the instance
1116  std::pair<InstanceToOutlines_t::iterator, bool> insertiter = m_instance_outlines.insert(std::make_pair(instance, newinfo));
1117 
1118  if (insertiter.second == false) {
1119  // the insertion did not happen because the instance
1120  // already exists in the map so lets just update its outline info
1121  OutlineInfo& info = insertiter.first->second;
1122 
1123  if (info.r != r || info.g != g || info.b != b || info.width != width) {
1124  // only update the outline info if its changed since the last call
1125  // flag the outline info as dirty so it will get processed during rendering
1126  info.r = r;
1127  info.b = b;
1128  info.g = g;
1129  info.width = width;
1130  info.threshold = threshold;
1131  info.dirty = true;
1132  }
1133  } else {
1134  std::pair<InstanceToEffects_t::iterator, bool> iter = m_assigned_instances.insert(std::make_pair(instance, OUTLINE));
1135  if (iter.second) {
1137  } else {
1138  Effect& effect = iter.first->second;
1139  if ((effect & OUTLINE) != OUTLINE) {
1140  effect += OUTLINE;
1141  }
1142  }
1143  }
1144  }
1145 
1146  void InstanceRenderer::addColored(Instance* instance, int32_t r, int32_t g, int32_t b, int32_t a) {
1147  ColoringInfo newinfo(this);
1148  newinfo.r = r;
1149  newinfo.g = g;
1150  newinfo.b = b;
1151  newinfo.a = a;
1152  newinfo.dirty = true;
1153 
1154  // attempts to insert the element into the coloring map
1155  // will return false in the second value of the pair if the instance already exists
1156  // in the map and the first value of the pair will then be an iterator to the
1157  // existing data for the instance
1158  std::pair<InstanceToColoring_t::iterator, bool> insertiter = m_instance_colorings.insert(std::make_pair(instance, newinfo));
1159 
1160  if (insertiter.second == false) {
1161  // the insertion did not happen because the instance
1162  // already exists in the map so lets just update its coloring info
1163  ColoringInfo& info = insertiter.first->second;
1164 
1165  if (info.r != r || info.g != g || info.b != b || info.a != a) {
1166  // only update the coloring info if its changed since the last call
1167  info.r = r;
1168  info.b = b;
1169  info.g = g;
1170  info.a = a;
1171  info.dirty = true;
1172  }
1173  } else {
1174  std::pair<InstanceToEffects_t::iterator, bool> iter = m_assigned_instances.insert(std::make_pair(instance, COLOR));
1175  if (iter.second) {
1177  } else {
1178  Effect& effect = iter.first->second;
1179  if ((effect & COLOR) != COLOR) {
1180  effect += COLOR;
1181  }
1182  }
1183  }
1184  }
1185 
1186  void InstanceRenderer::addTransparentArea(Instance* instance, const std::list<std::string> &groups, uint32_t w, uint32_t h, uint8_t trans, bool front) {
1187  AreaInfo newinfo;
1188  newinfo.instance = instance;
1189  newinfo.groups = groups;
1190 
1191  newinfo.w = w;
1192  newinfo.h = h;
1193  newinfo.trans = trans;
1194  newinfo.front = front;
1195 
1196 
1197  // attempts to insert the element into the area map
1198  // will return false in the second value of the pair if the instance already exists
1199  // in the map and the first value of the pair will then be an iterator to the
1200  // existing data for the instance
1201  std::pair<InstanceToAreas_t::iterator, bool> insertiter = m_instance_areas.insert(std::make_pair(instance, newinfo));
1202 
1203  if (insertiter.second == false) {
1204  // the insertion did not happen because the instance
1205  // already exists in the map so lets just update its area info
1206  AreaInfo& info = insertiter.first->second;
1207  info.groups = groups;
1208  info.w = w;
1209  info.h = h;
1210  info.trans = trans;
1211  info.front = front;
1212  } else {
1213  std::pair<InstanceToEffects_t::iterator, bool> iter = m_assigned_instances.insert(std::make_pair(instance, AREA));
1214  if (iter.second) {
1216  } else {
1217  Effect& effect = iter.first->second;
1218  if ((effect & AREA) != AREA) {
1219  effect += AREA;
1220  }
1221  }
1222  }
1223  }
1224 
1226  InstanceToEffects_t::iterator it = m_assigned_instances.find(instance);
1227  if (it != m_assigned_instances.end()) {
1228  if (it->second == OUTLINE) {
1230  m_instance_outlines.erase(instance);
1231  m_assigned_instances.erase(it);
1232  } else if ((it->second & OUTLINE) == OUTLINE) {
1233  it->second -= OUTLINE;
1234  m_instance_outlines.erase(instance);
1235  }
1236  }
1237  }
1238 
1240  InstanceToEffects_t::iterator it = m_assigned_instances.find(instance);
1241  if (it != m_assigned_instances.end()) {
1242  if (it->second == COLOR) {
1244  m_instance_colorings.erase(instance);
1245  m_assigned_instances.erase(it);
1246  } else if ((it->second & COLOR) == COLOR) {
1247  it->second -= COLOR;
1248  m_instance_colorings.erase(instance);
1249  }
1250  }
1251  }
1252 
1254  InstanceToEffects_t::iterator it = m_assigned_instances.find(instance);
1255  if (it != m_assigned_instances.end()) {
1256  if (it->second == AREA) {
1258  m_instance_areas.erase(instance);
1259  m_assigned_instances.erase(it);
1260  } else if ((it->second & AREA) == AREA) {
1261  it->second -= AREA;
1262  m_instance_areas.erase(instance);
1263  }
1264  }
1265  }
1266 
1268  if (!m_instance_outlines.empty()) {
1269  InstanceToOutlines_t::iterator outline_it = m_instance_outlines.begin();
1270  for (; outline_it != m_instance_outlines.end(); ++outline_it) {
1271  InstanceToEffects_t::iterator it = m_assigned_instances.find((*outline_it).first);
1272  if (it != m_assigned_instances.end()) {
1273  if (it->second == OUTLINE) {
1274  (*outline_it).first->removeDeleteListener(m_delete_listener);
1275  m_assigned_instances.erase(it);
1276  } else if ((it->second & OUTLINE) == OUTLINE) {
1277  it->second -= OUTLINE;
1278  }
1279  }
1280  }
1281  m_instance_outlines.clear();
1282  }
1283  }
1284 
1286  if (!m_instance_colorings.empty()) {
1287  InstanceToColoring_t::iterator color_it = m_instance_colorings.begin();
1288  for (; color_it != m_instance_colorings.end(); ++color_it) {
1289  InstanceToEffects_t::iterator it = m_assigned_instances.find((*color_it).first);
1290  if (it != m_assigned_instances.end()) {
1291  if (it->second == COLOR) {
1292  (*color_it).first->removeDeleteListener(m_delete_listener);
1293  m_assigned_instances.erase(it);
1294  } else if ((it->second & COLOR) == COLOR) {
1295  it->second -= COLOR;
1296  }
1297  }
1298  }
1299  m_instance_colorings.clear();
1300  }
1301  }
1302 
1304  if (!m_instance_areas.empty()) {
1305  InstanceToAreas_t::iterator area_it = m_instance_areas.begin();
1306  for (; area_it != m_instance_areas.end(); ++area_it) {
1307  InstanceToEffects_t::iterator it = m_assigned_instances.find((*area_it).first);
1308  if (it != m_assigned_instances.end()) {
1309  if (it->second == AREA) {
1310  (*area_it).first->removeDeleteListener(m_delete_listener);
1311  m_assigned_instances.erase(it);
1312  } else if ((it->second & AREA) == AREA) {
1313  it->second -= AREA;
1314  }
1315  }
1316  }
1317  m_instance_areas.clear();
1318  }
1319  }
1320 
1321  void InstanceRenderer::addIgnoreLight(const std::list<std::string> &groups) {
1322  std::list<std::string>::const_iterator group_it = groups.begin();
1323  for(;group_it != groups.end(); ++group_it) {
1324  m_unlit_groups.push_back(*group_it);
1325  }
1326  m_unlit_groups.sort();
1327  m_unlit_groups.unique();
1328  }
1329 
1330  void InstanceRenderer::removeIgnoreLight(const std::list<std::string> &groups) {
1331  std::list<std::string>::const_iterator group_it = groups.begin();
1332  for(;group_it != groups.end(); ++group_it) {
1333  std::list<std::string>::iterator unlit_it = m_unlit_groups.begin();
1334  for(;unlit_it != m_unlit_groups.end(); ++unlit_it) {
1335  if((*group_it).find(*unlit_it) != std::string::npos) {
1336  m_unlit_groups.remove(*unlit_it);
1337  break;
1338  }
1339  }
1340  }
1341  }
1342 
1344  m_unlit_groups.clear();
1345  }
1346 
1348  // stop timer
1349  if (m_timer_enabled) {
1350  m_timer.stop();
1351  }
1352  // remove all effects and listener
1354  removeAllColored();
1357  // removes the references to the effect images
1358  m_check_images.clear();
1359  }
1360 
1362  if (m_interval != interval*1000) {
1363  m_interval = interval*1000;
1365  }
1366  }
1367 
1369  return m_interval/1000;
1370  }
1371 
1373  if (isValidImage(image)) {
1374  // if image is already inserted then return
1375  ImagesToCheck_t::iterator it = m_check_images.begin();
1376  for (; it != m_check_images.end(); ++it) {
1377  if (it->image.get()->getName() == image.get()->getName()) {
1378  return;
1379  }
1380  }
1381  s_image_entry entry;
1382  entry.image = image;
1384  m_check_images.push_front(entry);
1385 
1386  if (!m_timer_enabled) {
1387  m_timer_enabled = true;
1388  m_timer.start();
1389  }
1390  }
1391  }
1392 
1395  ImagesToCheck_t::iterator it = m_check_images.begin();
1396  // free unused images
1397  while (it != m_check_images.end()) {
1398  if (now - it->timestamp > m_interval) {
1399  if (isValidImage(it->image)) {
1400  ImageManager::instance()->free(it->image.get()->getName());
1401  }
1402  it = m_check_images.erase(it);
1403  } else {
1404  ++it;
1405  }
1406  }
1407 
1408  if (m_check_images.empty() && m_timer_enabled) {
1409  m_timer_enabled = false;
1410  m_timer.stop();
1411  }
1412  }
1413 
1415  if (isValidImage(image)) {
1416  // if the image is used then remove it here
1417  ImagesToCheck_t::iterator it = m_check_images.begin();
1418  for (; it != m_check_images.end(); ++it) {
1419  if (it->image.get()->getName() == image.get()->getName()) {
1420  m_check_images.erase(it);
1421  break;
1422  }
1423  }
1424 
1425  if (m_check_images.empty() && m_timer_enabled) {
1426  m_timer_enabled = false;
1427  m_timer.stop();
1428  }
1429  }
1430  }
1431 
1433  InstanceToEffects_t::iterator it = m_assigned_instances.find(instance);
1434  if (it != m_assigned_instances.end()) {
1435  m_instance_outlines.erase(instance);
1436  m_instance_colorings.erase(instance);
1437  m_instance_areas.erase(instance);
1439  m_assigned_instances.erase(it);
1440  }
1441  }
1442 
1444  if (image.get()) {
1445  if (image.get()->getState() == IResource::RES_LOADED) {
1446  return true;
1447  }
1448  }
1449  return false;
1450  }
1451 }
std::vector< ImagePtr > * getAnimationOverlay() const
Returns pointer to AnimationOverlay vector.
Definition: renderitem.cpp:101
#define FL_WARN(logger, msg)
Definition: logger.h:72
ImagePtr getMultiColorOverlay(const RenderItem &vc, OverlayColors *colors=0)
Abstract interface for all the renderbackends.
T * get() const
allows direct access to underlying pointer
Definition: sharedptr.h:155
static bool putPixel(SDL_Surface *surface, int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Definition: image.cpp:364
virtual bool exists(const std::string &name)
Checks to see if an Image exists.
std::vector< RenderItem * > RenderList
Definition: renderitem.h:130
virtual ResourceState getState()
Definition: resource.h:70
void addOutlined(Instance *instance, int32_t r, int32_t g, int32_t b, int32_t width, int32_t threshold=1)
Marks given instance to be outlined with given parameters.
Base Class for Images.
Definition: image.h:48
const std::string & getNamespace() const
Definition: object.h:69
T h
Height of the rectangle.
Definition: rect.h:93
void addDeleteListener(InstanceDeleteListener *listener)
Adds new instance delete listener.
Definition: instance.cpp:1283
Instance visual contains data that is needed to visualize the instance on screen. ...
Definition: visual.h:158
InstanceToEffects_t m_assigned_instances
T x
The X Coordinate.
Definition: rect.h:84
bool isEnabledFogOfWar()
Gets whether Fog of War visualization is enabled.
uint32_t getRemoveInterval() const
Gets the interval in seconds (default is 60).
virtual const std::string & getName() const =0
The name of the renderbackend.
DoublePoint3D toVirtualScreenCoordinates(const ExactModelCoordinate &map_coords)
Transforms given point from map coordinates to virtual screen coordinates.
Definition: camera.cpp:433
Image * bindColoring(ColoringInfo &info, RenderItem &vc, Camera *cam)
void removeInstance(Instance *instance)
Removes instance from all effects.
DoublePoint3D screenpoint
Definition: renderitem.h:100
InstanceRenderer(RenderBackend *renderbackend, int32_t position)
constructor.
Instance * instance
Definition: renderitem.h:58
SDL_Surface * detachSurface()
Removes underlying SDL_Surface from the image (if exists) and returns this.
Definition: image.cpp:145
void getPixelRGBA(int32_t x, int32_t y, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *a)
Definition: image.cpp:181
CellCache * getCellCache()
Returns the CellCache of this layer.
Definition: layer.cpp:573
Interface to class owning the renderers Used to get correct subclass of renderer in scripting side (v...
Definition: rendererbase.h:66
T * getVisual() const
Gets used visualization.
Definition: instance.h:349
const uint32_t RMASK
Definition: fife_stdint.h:53
static Logger _log(LM_AUDIO)
void setInterval(int32_t msec)
Set the interval in milliseconds.
Definition: timer.cpp:60
std::list< std::string > m_unlit_groups
InstanceToOutlines_t m_instance_outlines
void start()
Start the timer.
Definition: timer.cpp:45
const uint32_t AMASK
Definition: fife_stdint.h:56
virtual void onInstanceDeleted(Instance *instance)
RendererBase * clone()
Makes copy of this renderer.
void removeAllIgnoreLight()
Removes all groups(Namespaces)
void removeOutlined(Instance *instance)
Removes instance from outlining list.
virtual RendererBase * getRenderer(const std::string &renderername)=0
Returns renderer with given name.
Camera describes properties of a view port shown in the main screen Main screen can have multiple cam...
Definition: camera.h:59
void check()
Timer callback, tried to remove old effect images.
Layer * getLayer() const
Gets the layer where this location is pointing to.
Definition: location.cpp:83
InstanceDeleteListener * m_delete_listener
static ImageManager * instance()
Definition: singleton.h:84
Location & getLocationRef()
Gets reference of current location of instance.
Definition: instance.cpp:318
ModelCoordinate getLayerCoordinates() const
Gets cell precision layer coordinates set to this location.
Definition: location.cpp:113
RendererBase * getRenderer(const std::string &name)
Gets renderer with given name.
Definition: camera.cpp:744
virtual ImagePtr getPtr(const std::string &name)
void addIgnoreLight(const std::list< std::string > &groups)
Add groups(Namespaces) into a list.
virtual uint32_t getLightingModel() const =0
Gets the current light model.
void removeDeleteListener(InstanceDeleteListener *listener)
Removes associated instance delete listener.
Definition: instance.cpp:1287
InstanceRendererDeleteListener(InstanceRenderer *r)
uint32_t getHeight() const
Definition: image.cpp:160
RenderBackend * m_renderbackend
Definition: rendererbase.h:171
bool aboveThreshold(int32_t threshold, int32_t alpha, int32_t prev_alpha)
unsigned char uint8_t
Definition: core.h:38
virtual void changeRenderInfos(RenderDataType type, uint16_t elements, int32_t src, int32_t dst, bool light, bool stentest, uint8_t stenref, GLConstants stenop, GLConstants stenfunc, OverlayType otype=OVERLAY_TYPE_NONE)=0
Dirty helper function to change the render infos.
bool isVisible()
Is instance visible or not.
Definition: visual.cpp:210
void changeColor(const Color &source, const Color &target)
Definition: visual.cpp:76
uint32_t getTime() const
Get the time.
const uint32_t GMASK
Definition: fife_stdint.h:54
void removeIgnoreLight(const std::list< std::string > &groups)
Removes groups(Namespaces) from the list.
virtual void copySubimage(uint32_t xoffset, uint32_t yoffset, const ImagePtr &img)
Copies given image into this one with respect to given offsets.
Definition: image.cpp:315
InstanceToAreas_t m_instance_areas
void setVisible(bool visible)
Sets visibility value for object to be visualized.
Definition: visual.cpp:203
Base class for all view renderers View renderer renders one aspect of the view shown on screen...
Definition: rendererbase.h:78
OverlayColors * getColorOverlay() const
Returns pointer to single ColorOverlay.
Definition: renderitem.cpp:122
Object * getObject()
Gets object where this instance is instantiated from.
Definition: instance.cpp:295
Cell * getCell(const ModelCoordinate &mc)
Returns cell on this coordinate.
Definition: cellcache.cpp:706
bool isValidImage(const ImagePtr &image)
void renderAlreadySorted(Camera *cam, Layer *layer, RenderList &instances)
virtual ~InstanceRenderer()
Destructor.
A basic layer on a map.
Definition: layer.h:99
virtual void setSurface(SDL_Surface *surface)=0
This frees the current suface and replaces it with the surface passed in the parameter (which can be ...
const std::map< Color, Color > & getColors()
Definition: visual.cpp:84
void render(Camera *cam, Layer *layer, RenderList &instances)
This method is called by the view to ask renderer to draw its rendering aspect based on given paramet...
Location getLocation() const
Gets current location of instance.
Definition: instance.cpp:314
void addColored(Instance *instance, int32_t r, int32_t g, int32_t b, int32_t a=128)
Marks given instance to be colored with given parameters.
virtual void renderZ(const Rect &rect, float vertexZ, uint8_t alpha=255, uint8_t const *rgb=0)
Definition: image.h:86
virtual const std::string & getName()
Definition: resource.h:66
const uint32_t BMASK
Definition: fife_stdint.h:55
virtual void setEnabled(bool enabled)
Enables renderer.
uint32_t getWidth() const
Definition: image.cpp:151
A basic cell on a CellCache.
Definition: cell.h:136
T y
The Y Coordinate.
Definition: rect.h:87
CellGrid * getCellGrid() const
Get the Cellgrid.
Definition: layer.cpp:93
void renderOverlay(RenderDataType type, RenderItem *item, uint8_t const *coloringColor, bool recoloring)
Layer * getFowLayer()
Returns the layer that is used for Fog of War visualization.
ImagePtr getColorOverlayImage()
Definition: visual.cpp:64
CellVisualEffect getFoWType()
Returns the cell visual.
Definition: cell.cpp:402
void renderUnsorted(Camera *cam, Layer *layer, RenderList &instances)
void removeTransparentArea(Instance *instance)
Removes instance form area list.
void removeAllTransparentAreas()
Removes all transparent areas.
virtual void free(const std::string &name)
Frees an Image from memory.
bool intersects(const RectType< T > &rect) const
Check whether two rectangles share some area.
Definition: rect.h:227
void addTransparentArea(Instance *instance, const std::list< std::string > &groups, uint32_t w, uint32_t h, uint8_t trans, bool front=true)
Marks given instance to have a transparent area with given parameters.
bool isSharedImage() const
Returns true if this image shares data with another one.
Definition: image.h:148
ImagePtr image
Definition: renderitem.h:112
virtual void setState(const ResourceState &state)
Definition: resource.h:71
virtual void render(const Rect &rect, uint8_t alpha=255, uint8_t const *rgb=0)=0
Renders itself to the current render target (main screen or attached destination image) at the rectan...
ScreenPoint toScreenCoordinates(const ExactModelCoordinate &map_coords)
Transforms given point from map coordinates to screen coordinates.
Definition: camera.cpp:428
void stop()
Stop the timer.
Definition: timer.cpp:53
uint32_t timestamp
virtual Image * createImage(IResourceLoader *loader=0)=0
virtual void forceLoadInternal()=0
Forces to load the image into internal memory of GPU.
void reset()
Removes all stuff.
void removeAllOutlines()
Removes all outlines.
ImagePtr image
RenderDataType
static InstanceRenderer * getInstance(IRendererContainer *cnt)
Gets instance for interface access.
unsigned int uint32_t
Definition: core.h:40
void setRemoveInterval(uint32_t interval)
Sets the interval in seconds (default is 60).
std::list< std::string > groups
bool isDepthBufferEnabled() const
ImagesToCheck_t m_check_images
void removeAllColored()
Removes all coloring.
Image * bindMultiOutline(OutlineInfo &info, RenderItem &vc, Camera *cam)
OverlayData * m_overlay
Definition: renderitem.h:124
void addToCheck(const ImagePtr &image)
Add properly old ImagePtr into a check list.
uint8_t transparency
Definition: renderitem.h:118
T w
Width of the rectangle.
Definition: rect.h:90
std::vector< OverlayColors * > * getAnimationColorOverlay() const
Returns pointer to AnimationColorOverlay vector.
Definition: renderitem.cpp:108
void removeFromCheck(const ImagePtr &image)
An Instance is an "instantiation" of an Object at a Location.
Definition: instance.h:101
void setCallback(const type_callback &callback)
Set the callback that will be called.
Definition: timer.cpp:64
ExactModelCoordinate getMapCoordinates() const
Gets map coordinates set to this location.
Definition: location.cpp:117
void removeColored(Instance *instance)
Removes instance from coloring list.
virtual ImagePtr add(Image *res)
Add an Image to the manager.
InstanceToColoring_t m_instance_colorings
Image * bindOutline(OutlineInfo &info, RenderItem &vc, Camera *cam)
Binds new outline (if needed) to the instance&#39;s OutlineInfo.