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