FIFE
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
instancerenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2013 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 #include "video/opengle/gleimage.h"
55 
56 
57 namespace FIFE {
61  static Logger _log(LM_VIEWVIEW);
62 
64  public:
66  m_renderer = r;
67  }
69 
70  virtual void onInstanceDeleted(Instance* instance) {
71  m_renderer->removeInstance(instance);
72  }
73 
74  private:
76  };
77 
79  r(0),
80  g(0),
81  b(0),
82  width(1),
83  dirty(false),
84  curimg(NULL),
85  renderer(r) {
86  }
88  r(0),
89  g(0),
90  b(0),
91  a(128),
92  dirty(false),
93  curimg(NULL),
94  renderer(r) {
95  }
96 
98  instance(NULL),
99  groups(),
100  w(1),
101  h(1),
102  trans(0),
103  front(true),
104  z(0) {
105  }
106 
108  renderer->addToCheck(outline);
109  }
110 
112  if (renderer->needColorBinding()) {
113  renderer->addToCheck(overlay);
114  }
115  }
116 
118  }
119 
121  return dynamic_cast<InstanceRenderer*>(cnt->getRenderer("InstanceRenderer"));
122  }
123 
124  InstanceRenderer::InstanceRenderer(RenderBackend* renderbackend, int32_t position):
125  RendererBase(renderbackend, position),
126  m_area_layer(false),
127  m_interval(60*1000),
128  m_timer_enabled(false) {
129  setEnabled(true);
130  if(m_renderbackend->getName() == "OpenGLe") {
131  m_need_sorting = 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() == "OpenGLe") {
154  m_need_sorting = false;
155  } else {
156  m_need_sorting = true;
157  if(m_renderbackend->getName() == "SDL") {
158  m_need_bind_coloring = true;
159  } else {
160  m_need_bind_coloring = false;
161  }
162  }
163  // init timer
165  m_timer.setCallback(boost::bind(&InstanceRenderer::check, this));
166  // create delete listener
168  }
169 
171  return new InstanceRenderer(*this);
172  }
173 
175  // remove listener from instances
176  if (!m_assigned_instances.empty()) {
177  reset();
178  }
179  // delete listener
180  delete m_delete_listener;
181  }
182 
183  void InstanceRenderer::render(Camera* cam, Layer* layer, RenderList& instances) {
184 // FL_DBG(_log, "Iterating layer...");
185  CellGrid* cg = layer->getCellGrid();
186  if (!cg) {
187  FL_WARN(_log, "No cellgrid assigned to layer, cannot draw instances");
188  return;
189  }
190 
191  if(m_need_sorting) {
192  renderAlreadySorted(cam, layer, instances);
193  } else {
194  renderUnsorted(cam, layer, instances);
195  }
196  }
197 
199  {
200  // TODO transparent area stuff was cut off
201  const bool any_effects = !(m_instance_outlines.empty() && m_instance_colorings.empty());
202  const bool unlit = !m_unlit_groups.empty();
204 
205  // Get layer index (this is needed for tweaking vertexZ for OpenGL renderbackend)
206  Map* parent = layer->getMap();
207  int num_layers = parent->getLayerCount();
208  int this_layer = 1; // we don't need 0 indexed
209  const std::list<Layer*>& layers = parent->getLayers();
210  std::list<Layer*>::const_iterator iter = layers.begin();
211  for (; iter != layers.end(); ++iter, ++this_layer) {
212  if (*iter == layer) {
213  break;
214  }
215  }
216 
217  // These values come from glOrtho settings
218  static const double global_z_max = 100.0;
219 #if 0
220  static const double global_z_min = -100.0;
221  static const double depth_range = fabs(global_z_min - global_z_max);
222 
223  // This is how much depth we can sacrifice for given layer
224  // f.e: We have 200 depth range and 4 layers. That means we can assign
225  // each layer 50 depth range:
226  // 1st layer gets -100..-50
227  // 2nd layer gets -50..0
228  // 3rd layer gets 0..50
229  // 4th layer gets 50..100
230  double layer_depth_range = depth_range / static_cast<double>(num_layers);
231  // What's left, is to compute z offset for given layer
232  double layer_z_offset = global_z_min +
233  layer_depth_range * static_cast<double>(this_layer) -
234  layer_depth_range * 0.5;
235 #else
236 
237  // 2nd version, better usage of depth buffer as values closer to near plane in depth buffer have more precise (1/z)
238  double layer_z_offset = global_z_max - (num_layers - (this_layer - 1)) * 20;
239 #endif
240  // thanks to multimap, we will have transparent instances already sorted by their z value (key)
241  std::multimap<float, RenderItem*> transparentInstances;
242 
243  RenderList::iterator instance_it = instances.begin();
244  for (;instance_it != instances.end(); ++instance_it) {
245 // FL_DBG(_log, "Iterating instances...");
246  Instance* instance = (*instance_it)->instance;
247  RenderItem& vc = **instance_it;
248  float vertexZ = static_cast<float>(layer_z_offset + vc.screenpoint.z);
249 
250  // if the instance is opacous
251  if(vc.transparency == 255) {
252  if (any_effects) {
253  InstanceToOutlines_t::iterator outline_it = m_instance_outlines.find(instance);
254  const bool outline = outline_it != m_instance_outlines.end();
255  if (outline) {
256  Image* outline = bindOutline(outline_it->second, vc, cam);
257  outline->renderZ(vc.dimensions, vertexZ, 255, lm != 0 ? true : false);
258  vc.image->renderZ(vc.dimensions, vertexZ, 255);
259  }
260 
261  InstanceToColoring_t::iterator coloring_it = m_instance_colorings.find(instance);
262  const bool coloring = coloring_it != m_instance_colorings.end();
263  if (coloring) {
264  uint8_t rgba[4] = { coloring_it->second.r, coloring_it->second.g, coloring_it->second.b, coloring_it->second.a };
265  vc.image->renderZ(vc.dimensions, vertexZ, 255, false, rgba);
266  }
267 
268  if (outline || coloring) {
269  continue;
270  }
271  }
272 
273  // if we use lighting and appointed some of the instances as unlit
274  if(lm != 0 && unlit) {
275  bool found = false;
276  std::string lit_name = instance->getObject()->getNamespace();
277  std::list<std::string>::iterator unlit_it = m_unlit_groups.begin();
278  for(;unlit_it != m_unlit_groups.end(); ++unlit_it) {
279  if(lit_name.find(*unlit_it) != std::string::npos) {
280  found = true;
281  break;
282  }
283  }
284 
285  vc.image->renderZ(vc.dimensions, vertexZ, 255, found ? true : false);
286  continue;
287  }
288 
289  vc.image->renderZ(vc.dimensions, vertexZ, 255);
290  } else {
291  transparentInstances.insert(std::pair<float, RenderItem*>(vertexZ, &vc));
292  }
293  }
294 
295  // iterate through all (semi) transparent instances
296  if(!transparentInstances.empty()) {
297  std::multimap<float, RenderItem*>::iterator it = transparentInstances.begin();
298  for( ; it != transparentInstances.end(); ++it) {
299  RenderItem& vc = *(it->second);
300  uint8_t alpha = vc.transparency;// or? 255 - vc.transparency;
301  float vertexZ = it->first;
302 
303  if (any_effects) {
304  InstanceToOutlines_t::iterator outline_it = m_instance_outlines.find(vc.instance);
305  const bool outline = outline_it != m_instance_outlines.end();
306  if (outline) {
307  Image* outline = bindOutline(outline_it->second, vc, cam);
308  outline->renderZ(vc.dimensions, vertexZ, alpha, lm != 0 ? true : false);
309  vc.image->renderZ(vc.dimensions, vertexZ, alpha);
310  }
311 
312  InstanceToColoring_t::iterator coloring_it = m_instance_colorings.find(vc.instance);
313  const bool coloring = coloring_it != m_instance_colorings.end();
314  if (coloring) {
315  uint8_t rgb[3] = { coloring_it->second.r, coloring_it->second.g, coloring_it->second.b };
316  vc.image->renderZ(vc.dimensions, vertexZ, alpha, false, rgb);
317  }
318 
319  if (outline || coloring) {
320  continue;
321  }
322  }
323 
324  // if we use lighting and appointed some of the instances as unlit
325  if(lm != 0 && unlit) {
326  bool found = false;
327  std::string lit_name = vc.instance->getObject()->getNamespace();
328  std::list<std::string>::iterator unlit_it = m_unlit_groups.begin();
329  for(;unlit_it != m_unlit_groups.end(); ++unlit_it) {
330  if(lit_name.find(*unlit_it) != std::string::npos) {
331  found = true;
332  break;
333  }
334  }
335 
336  vc.image->renderZ(vc.dimensions, vertexZ, alpha, found ? true : false);
337  continue;
338  }
339 
340  vc.image->renderZ(vc.dimensions, vertexZ, alpha);
341  }
342  }
343  }
344 
346  const bool any_effects = !(m_instance_outlines.empty() && m_instance_colorings.empty());
347  const bool unlit = !m_unlit_groups.empty();
349 
350  m_area_layer = false;
351  if(!m_instance_areas.empty()) {
352  InstanceToAreas_t::iterator area_it = m_instance_areas.begin();
353  for(;area_it != m_instance_areas.end(); area_it++) {
354  AreaInfo& info = area_it->second;
355  if(info.instance->getLocation().getLayer() == layer) {
356  if(info.front) {
358  info.z = instance_posv.z;
359  }
360  m_area_layer = true;
361  }
362  }
363  }
364  // Fixme
365  CellRenderer* cr = dynamic_cast<CellRenderer*>(cam->getRenderer("CellRenderer"));
366  Layer* fow_layer = cr->getFowLayer();
367  bool check_fow = (fow_layer == layer && cr->isEnabledFogOfWar());
368 
369  RenderList::iterator instance_it = instances.begin();
370  for (;instance_it != instances.end(); ++instance_it) {
371 // FL_DBG(_log, "Iterating instances...");
372  Instance* instance = (*instance_it)->instance;
373  RenderItem& vc = **instance_it;
374 
375  if (check_fow) {
376  Cell* cell = layer->getCellCache()->getCell(instance->getLocationRef().getLayerCoordinates());
377  if (cell) {
378  if (cell->getFoWType() != CELLV_REVEALED) {
379  continue;
380  }
381  }
382  }
383 
384  if(m_area_layer) {
385  InstanceToAreas_t::iterator areas_it = m_instance_areas.begin();
386  for(;areas_it != m_instance_areas.end(); areas_it++) {
387  AreaInfo& infoa = areas_it->second;
388  if(infoa.front) {
389  if(infoa.z >= vc.screenpoint.z) {
390  continue;
391  }
392  }
393 
394  std::string str_name = instance->getObject()->getNamespace();
395  std::list<std::string>::iterator group_it = infoa.groups.begin();
396  for(;group_it != infoa.groups.end(); ++group_it) {
397  if(str_name.find((*group_it)) != std::string::npos) {
398  ScreenPoint p;
399  Rect rec;
401  rec.x = p.x - infoa.w / 2;
402  rec.y = p.y - infoa.h / 2;
403  rec.w = infoa.w;
404  rec.h = infoa.h;
405  if(infoa.instance != instance && vc.dimensions.intersects(rec)) {
406  vc.transparency = 255 - infoa.trans;
407  // dirty hack to reset the transparency on next pump
408  InstanceVisual* visual = instance->getVisual<InstanceVisual>();
409  visual->setVisible(!visual->isVisible());
410  visual->setVisible(!visual->isVisible());
411  }
412  }
413  }
414  }
415  }
416 
417 // FL_DBG(_log, LMsg("Instance layer coordinates = ") << instance->getLocationRef().getLayerCoordinates());
418 
419  if (any_effects) {
420  InstanceToOutlines_t::iterator outline_it = m_instance_outlines.find(instance);
421  const bool outline = outline_it != m_instance_outlines.end();
422  if (outline) {
423  if (lm != 0) {
424  // first render normal image without stencil and alpha test (0)
425  // so it wont look aliased and then with alpha test render only outline (its 'binary' image)
426  vc.image->render(vc.dimensions, vc.transparency);
427  bindOutline(outline_it->second, vc, cam)->render(vc.dimensions, vc.transparency);
428  m_renderbackend->changeRenderInfos(1, 4, 5, false, true, 255, REPLACE, ALWAYS);
429  } else {
430  bindOutline(outline_it->second, vc, cam)->render(vc.dimensions, vc.transparency);
431  vc.image->render(vc.dimensions, vc.transparency);
432  }
433  }
434 
435  InstanceToColoring_t::iterator coloring_it = m_instance_colorings.find(instance);
436  const bool coloring = coloring_it != m_instance_colorings.end();
437  if (coloring) {
439  bindColoring(coloring_it->second, vc, cam)->render(vc.dimensions, vc.transparency);
440  m_renderbackend->changeRenderInfos(1, 4, 5, true, false, 0, KEEP, ALWAYS);
441  } else {
442  uint8_t rgba[4] = { coloring_it->second.r, coloring_it->second.g, coloring_it->second.b, coloring_it->second.a };
443  vc.image->render(vc.dimensions, vc.transparency, rgba);
444  m_renderbackend->changeRenderInfos(1, 4, 5, true, false, 0, KEEP, ALWAYS);
445  }
446  }
447 
448  if (outline || coloring) {
449  continue;
450  }
451  }
452  if(lm != 0) {
453  if(unlit) {
454  bool found = false;
455  std::string lit_name = instance->getObject()->getNamespace();
456  std::list<std::string>::iterator unlit_it = m_unlit_groups.begin();
457  for(;unlit_it != m_unlit_groups.end(); ++unlit_it) {
458  if(lit_name.find(*unlit_it) != std::string::npos) {
459  found = true;
460  break;
461  }
462  }
463  vc.image->render(vc.dimensions, vc.transparency);
464  if (found) {
465  m_renderbackend->changeRenderInfos(1, 4, 5, true, true, 255, REPLACE, ALWAYS);
466  } else {
467  m_renderbackend->changeRenderInfos(1, 4, 5, true, true, 0, ZERO, ALWAYS);
468  }
469  continue;
470  }
471  }
472  vc.image->render(vc.dimensions, vc.transparency);
473 
474  }
475  }
476 
477  inline bool aboveThreshold(int32_t threshold, int32_t alpha, int32_t prev_alpha) {
478  if(threshold > 1) {
479  // new behavior
480  if (((alpha - threshold) >= 0 || (prev_alpha - threshold) >= 0) && (alpha != prev_alpha)) {
481  return true;
482  } else {
483  return false;
484  }
485  } else {
486  // old behavior
487  if((alpha == 0 || prev_alpha == 0) && (alpha != prev_alpha)) {
488  return true;
489  } else {
490  return false;
491  }
492  }
493  }
494 
496  bool valid = isValidImage(info.outline);
497  if (!info.dirty && info.curimg == vc.image.get() && valid) {
498  removeFromCheck(info.outline);
499  // optimization for outline that has not changed
500  return info.outline.get();
501  } else {
502  info.curimg = vc.image.get();
503  }
504 
505  // if outline has changed we can maybe free the old effect image
506  if (valid) {
507  addToCheck(info.outline);
508  }
509 
510  // NOTE: Since r3721 outline is just the 'border' so to render everything correctly
511  // we need to first render normal image, and then its outline.
512  // This helps much with lighting stuff and doesn't require from us to copy image.
513 
514  bool found = false;
515  // create name
516  std::stringstream sts;
517  sts << vc.image.get()->getName() << "," << static_cast<uint32_t>(info.r) << "," <<
518  static_cast<uint32_t>(info.g) << "," << static_cast<uint32_t>(info.b) << "," << info.width;
519  // search image
520  if (ImageManager::instance()->exists(sts.str())) {
521  info.outline = ImageManager::instance()->getPtr(sts.str());
522  if (isValidImage(info.outline)) {
523  removeFromCheck(info.outline);
524  // mark outline as not dirty since we found it here
525  info.dirty = false;
526  return info.outline.get();
527  }
528  found = true;
529  }
530 
531 
532  // With lazy loading we can come upon a situation where we need to generate outline from
533  // uninitialised shared image
534  if(vc.image->isSharedImage()) {
535  vc.image->forceLoadInternal();
536  }
537 
538  SDL_Surface* outline_surface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA,
539  vc.image->getWidth(), vc.image->getHeight(), 32,
540  RMASK, GMASK, BMASK, AMASK);
541 
542  // TODO: optimize...
543  uint8_t r, g, b, a = 0;
544 
545  // vertical sweep
546  for (int32_t x = 0; x < outline_surface->w; x ++) {
547  int32_t prev_a = 0;
548  for (int32_t y = 0; y < outline_surface->h; y ++) {
549  vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
550  if (aboveThreshold(info.threshold, static_cast<int32_t>(a), prev_a)) {
551  if (a < prev_a) {
552  for (int32_t yy = y; yy < y + info.width; yy++) {
553  Image::putPixel(outline_surface, x, yy, info.r, info.g, info.b);
554  }
555  } else {
556  for (int32_t yy = y - info.width; yy < y; yy++) {
557  Image::putPixel(outline_surface, x, yy, info.r, info.g, info.b);
558  }
559  }
560  }
561  prev_a = a;
562  }
563  }
564  // horizontal sweep
565  for (int32_t y = 0; y < outline_surface->h; y ++) {
566  int32_t prev_a = 0;
567  for (int32_t x = 0; x < outline_surface->w; x ++) {
568  vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
569  if (aboveThreshold(info.threshold, static_cast<int32_t>(a), prev_a)) {
570  if (a < prev_a) {
571  for (int32_t xx = x; xx < x + info.width; xx++) {
572  Image::putPixel(outline_surface, xx, y, info.r, info.g, info.b);
573  }
574  } else {
575  for (int32_t xx = x - info.width; xx < x; xx++) {
576  Image::putPixel(outline_surface, xx, y, info.r, info.g, info.b);
577  }
578  }
579  }
580  prev_a = a;
581  }
582  }
583 
584  // In case of OpenGL backend, SDLImage needs to be converted
585  Image* img = m_renderbackend->createImage(sts.str(), outline_surface);
587 
588  if (found) {
589  // image exists but is not "loaded"
590  removeFromCheck(info.outline);
591  ImagePtr temp(img);
592  info.outline.get()->copySubimage(0, 0, temp);
594  } else {
595  // create and add image
596  info.outline = ImageManager::instance()->add(img);
597  }
598  // mark outline as not dirty since we created/recreated it here
599  info.dirty = false;
600 
601  return info.outline.get();
602  }
603 
605  bool valid = isValidImage(info.overlay);
606  if (!info.dirty && info.curimg == vc.image.get() && valid) {
607  removeFromCheck(info.overlay);
608  // optimization for coloring that has not changed
609  return info.overlay.get();
610  } else {
611  info.curimg = vc.image.get();
612  }
613 
614  // if coloring has changed we can maybe free the old effect image
615  if (valid) {
616  addToCheck(info.overlay);
617  }
618 
619  bool found = false;
620  // create name
621  std::stringstream sts;
622  sts << vc.image.get()->getName() << "," << static_cast<uint32_t>(info.r) << "," <<
623  static_cast<uint32_t>(info.g) << "," << static_cast<uint32_t>(info.b) << "," << static_cast<uint32_t>(info.a);
624  // search image
625  if (ImageManager::instance()->exists(sts.str())) {
626  info.overlay = ImageManager::instance()->getPtr(sts.str());
627  valid = isValidImage(info.overlay);
628  if (valid) {
629  removeFromCheck(info.overlay);
630  // mark overlay as not dirty since we found it here
631  info.dirty = false;
632  return info.overlay.get();
633  }
634  found = true;
635  }
636 
637  // With lazy loading we can come upon a situation where we need to generate coloring from
638  // uninitialised shared image
639  if(vc.image->isSharedImage()) {
640  vc.image->forceLoadInternal();
641  }
642 
643  // not found so we create it
644  SDL_Surface* overlay_surface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA,
645  vc.image->getWidth(), vc.image->getHeight(), 32,
646  RMASK, GMASK, BMASK, AMASK);
647 
648  uint8_t r, g, b, a = 0;
649  float alphaFactor = static_cast<float>(info.a/255.0);
650  for (int32_t x = 0; x < overlay_surface->w; x ++) {
651  for (int32_t y = 0; y < overlay_surface->h; y ++) {
652  vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
653  if (a > 0) {
654  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);
655  }
656  }
657  }
658 
659  // In case of OpenGL backend, SDLImage needs to be converted
660  Image* img = m_renderbackend->createImage(sts.str(), overlay_surface);
661 
662  if (found) {
663  // image exists but is not "loaded"
664  removeFromCheck(info.overlay);
665  ImagePtr temp(img);
666  info.overlay.get()->copySubimage(0, 0, temp);
668  } else {
669  // add image
671  info.overlay = ImageManager::instance()->add(img);
672  }
673  // mark overlay as not dirty since we created/recreated it here
674  info.dirty = false;
675 
676  return info.overlay.get();
677  }
678 
679  void InstanceRenderer::addOutlined(Instance* instance, int32_t r, int32_t g, int32_t b, int32_t width, int32_t threshold) {
680  OutlineInfo newinfo(this);
681  newinfo.r = r;
682  newinfo.g = g;
683  newinfo.b = b;
684  newinfo.threshold = threshold;
685  newinfo.width = width;
686  newinfo.dirty = true;
687 
688  // attempts to insert the element into the outline map
689  // will return false in the second value of the pair if the instance already exists
690  // in the map and the first value of the pair will then be an iterator to the
691  // existing data for the instance
692  std::pair<InstanceToOutlines_t::iterator, bool> insertiter = m_instance_outlines.insert(std::make_pair(instance, newinfo));
693 
694  if (insertiter.second == false) {
695  // the insertion did not happen because the instance
696  // already exists in the map so lets just update its outline info
697  OutlineInfo& info = insertiter.first->second;
698 
699  if (info.r != r || info.g != g || info.b != b || info.width != width) {
700  // only update the outline info if its changed since the last call
701  // flag the outline info as dirty so it will get processed during rendering
702  info.r = r;
703  info.b = b;
704  info.g = g;
705  info.width = width;
706  info.threshold = threshold;
707  info.dirty = true;
708  }
709  } else {
710  std::pair<InstanceToEffects_t::iterator, bool> iter = m_assigned_instances.insert(std::make_pair(instance, OUTLINE));
711  if (iter.second) {
713  } else {
714  Effect& effect = iter.first->second;
715  if ((effect & OUTLINE) != OUTLINE) {
716  effect += OUTLINE;
717  }
718  }
719  }
720  }
721 
722  void InstanceRenderer::addColored(Instance* instance, int32_t r, int32_t g, int32_t b, int32_t a) {
723  ColoringInfo newinfo(this);
724  newinfo.r = r;
725  newinfo.g = g;
726  newinfo.b = b;
727  newinfo.a = a;
728  newinfo.dirty = true;
729 
730  // attempts to insert the element into the coloring map
731  // will return false in the second value of the pair if the instance already exists
732  // in the map and the first value of the pair will then be an iterator to the
733  // existing data for the instance
734  std::pair<InstanceToColoring_t::iterator, bool> insertiter = m_instance_colorings.insert(std::make_pair(instance, newinfo));
735 
736  if (insertiter.second == false) {
737  // the insertion did not happen because the instance
738  // already exists in the map so lets just update its coloring info
739  ColoringInfo& info = insertiter.first->second;
740 
741  if (info.r != r || info.g != g || info.b != b || info.a != a) {
742  // only update the coloring info if its changed since the last call
743  info.r = r;
744  info.b = b;
745  info.g = g;
746  info.a = a;
747  info.dirty = true;
748  }
749  } else {
750  std::pair<InstanceToEffects_t::iterator, bool> iter = m_assigned_instances.insert(std::make_pair(instance, COLOR));
751  if (iter.second) {
753  } else {
754  Effect& effect = iter.first->second;
755  if ((effect & COLOR) != COLOR) {
756  effect += COLOR;
757  }
758  }
759  }
760  }
761 
762  void InstanceRenderer::addTransparentArea(Instance* instance, const std::list<std::string> &groups, uint32_t w, uint32_t h, uint8_t trans, bool front) {
763  AreaInfo newinfo;
764  newinfo.instance = instance;
765  newinfo.groups = groups;
766 
767  newinfo.w = w;
768  newinfo.h = h;
769  newinfo.trans = trans;
770  newinfo.front = front;
771 
772 
773  // attempts to insert the element into the area map
774  // will return false in the second value of the pair if the instance already exists
775  // in the map and the first value of the pair will then be an iterator to the
776  // existing data for the instance
777  std::pair<InstanceToAreas_t::iterator, bool> insertiter = m_instance_areas.insert(std::make_pair(instance, newinfo));
778 
779  if (insertiter.second == false) {
780  // the insertion did not happen because the instance
781  // already exists in the map so lets just update its area info
782  AreaInfo& info = insertiter.first->second;
783  info.groups = groups;
784  info.w = w;
785  info.h = h;
786  info.trans = trans;
787  info.front = front;
788  } else {
789  std::pair<InstanceToEffects_t::iterator, bool> iter = m_assigned_instances.insert(std::make_pair(instance, AREA));
790  if (iter.second) {
792  } else {
793  Effect& effect = iter.first->second;
794  if ((effect & AREA) != AREA) {
795  effect += AREA;
796  }
797  }
798  }
799  }
800 
802  InstanceToEffects_t::iterator it = m_assigned_instances.find(instance);
803  if (it != m_assigned_instances.end()) {
804  if (it->second == OUTLINE) {
806  m_instance_outlines.erase(instance);
807  m_assigned_instances.erase(it);
808  } else if ((it->second & OUTLINE) == OUTLINE) {
809  it->second -= OUTLINE;
810  m_instance_outlines.erase(instance);
811  }
812  }
813  }
814 
816  InstanceToEffects_t::iterator it = m_assigned_instances.find(instance);
817  if (it != m_assigned_instances.end()) {
818  if (it->second == COLOR) {
820  m_instance_colorings.erase(instance);
821  m_assigned_instances.erase(it);
822  } else if ((it->second & COLOR) == COLOR) {
823  it->second -= COLOR;
824  m_instance_colorings.erase(instance);
825  }
826  }
827  }
828 
830  InstanceToEffects_t::iterator it = m_assigned_instances.find(instance);
831  if (it != m_assigned_instances.end()) {
832  if (it->second == AREA) {
834  m_instance_areas.erase(instance);
835  m_assigned_instances.erase(it);
836  } else if ((it->second & AREA) == AREA) {
837  it->second -= AREA;
838  m_instance_areas.erase(instance);
839  }
840  }
841  }
842 
844  if (!m_instance_outlines.empty()) {
845  InstanceToOutlines_t::iterator outline_it = m_instance_outlines.begin();
846  for (; outline_it != m_instance_outlines.end(); ++outline_it) {
847  InstanceToEffects_t::iterator it = m_assigned_instances.find((*outline_it).first);
848  if (it != m_assigned_instances.end()) {
849  if (it->second == OUTLINE) {
850  (*outline_it).first->removeDeleteListener(m_delete_listener);
851  m_assigned_instances.erase(it);
852  } else if ((it->second & OUTLINE) == OUTLINE) {
853  it->second -= OUTLINE;
854  }
855  }
856  }
857  m_instance_outlines.clear();
858  }
859  }
860 
862  if (!m_instance_colorings.empty()) {
863  InstanceToColoring_t::iterator color_it = m_instance_colorings.begin();
864  for (; color_it != m_instance_colorings.end(); ++color_it) {
865  InstanceToEffects_t::iterator it = m_assigned_instances.find((*color_it).first);
866  if (it != m_assigned_instances.end()) {
867  if (it->second == COLOR) {
868  (*color_it).first->removeDeleteListener(m_delete_listener);
869  m_assigned_instances.erase(it);
870  } else if ((it->second & COLOR) == COLOR) {
871  it->second -= COLOR;
872  }
873  }
874  }
875  m_instance_colorings.clear();
876  }
877  }
878 
880  if (!m_instance_areas.empty()) {
881  InstanceToAreas_t::iterator area_it = m_instance_areas.begin();
882  for (; area_it != m_instance_areas.end(); ++area_it) {
883  InstanceToEffects_t::iterator it = m_assigned_instances.find((*area_it).first);
884  if (it != m_assigned_instances.end()) {
885  if (it->second == AREA) {
886  (*area_it).first->removeDeleteListener(m_delete_listener);
887  m_assigned_instances.erase(it);
888  } else if ((it->second & AREA) == AREA) {
889  it->second -= AREA;
890  }
891  }
892  }
893  m_instance_areas.clear();
894  }
895  }
896 
897  void InstanceRenderer::addIgnoreLight(const std::list<std::string> &groups) {
898  std::list<std::string>::const_iterator group_it = groups.begin();
899  for(;group_it != groups.end(); ++group_it) {
900  m_unlit_groups.push_back(*group_it);
901  }
902  m_unlit_groups.sort();
903  m_unlit_groups.unique();
904  }
905 
906  void InstanceRenderer::removeIgnoreLight(const std::list<std::string> &groups) {
907  std::list<std::string>::const_iterator group_it = groups.begin();
908  for(;group_it != groups.end(); ++group_it) {
909  std::list<std::string>::iterator unlit_it = m_unlit_groups.begin();
910  for(;unlit_it != m_unlit_groups.end(); ++unlit_it) {
911  if((*group_it).find(*unlit_it) != std::string::npos) {
912  m_unlit_groups.remove(*unlit_it);
913  break;
914  }
915  }
916  }
917  }
918 
920  m_unlit_groups.clear();
921  }
922 
924  // stop timer
925  if (m_timer_enabled) {
926  m_timer.stop();
927  }
928  // remove all effects and listener
933  // removes the references to the effect images
934  m_check_images.clear();
935  }
936 
938  if (m_interval != interval*1000) {
939  m_interval = interval*1000;
941  }
942  }
943 
945  return m_interval/1000;
946  }
947 
949  if (isValidImage(image)) {
950  // if image is already inserted then return
951  ImagesToCheck_t::iterator it = m_check_images.begin();
952  for (; it != m_check_images.end(); ++it) {
953  if (it->image.get()->getName() == image.get()->getName()) {
954  return;
955  }
956  }
957  s_image_entry entry;
958  entry.image = image;
960  m_check_images.push_front(entry);
961 
962  if (!m_timer_enabled) {
963  m_timer_enabled = true;
964  m_timer.start();
965  }
966  }
967  }
968 
971  ImagesToCheck_t::iterator it = m_check_images.begin();
972  // free unused images
973  while (it != m_check_images.end()) {
974  if (now - it->timestamp > m_interval) {
975  if (isValidImage(it->image)) {
976  ImageManager::instance()->free(it->image.get()->getName());
977  }
978  it = m_check_images.erase(it);
979  } else {
980  ++it;
981  }
982  }
983 
984  if (m_check_images.empty() && m_timer_enabled) {
985  m_timer_enabled = false;
986  m_timer.stop();
987  }
988  }
989 
991  if (isValidImage(image)) {
992  // if the image is used then remove it here
993  ImagesToCheck_t::iterator it = m_check_images.begin();
994  for (; it != m_check_images.end(); ++it) {
995  if (it->image.get()->getName() == image.get()->getName()) {
996  m_check_images.erase(it);
997  break;
998  }
999  }
1000 
1001  if (m_check_images.empty() && m_timer_enabled) {
1002  m_timer_enabled = false;
1003  m_timer.stop();
1004  }
1005  }
1006  }
1007 
1009  InstanceToEffects_t::iterator it = m_assigned_instances.find(instance);
1010  if (it != m_assigned_instances.end()) {
1011  m_instance_outlines.erase(instance);
1012  m_instance_colorings.erase(instance);
1013  m_instance_areas.erase(instance);
1015  m_assigned_instances.erase(it);
1016  }
1017  }
1018 
1020  if (image.get()) {
1021  if (image.get()->getState() == IResource::RES_LOADED) {
1022  return true;
1023  }
1024  }
1025  return false;
1026  }
1027 }
#define FL_WARN(logger, msg)
Definition: logger.h:72
Abstract interface for all the renderbackends.
Definition: renderbackend.h:92
Map * getMap() const
Get the map this layer is contained in.
Definition: layer.cpp:88
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:346
virtual bool exists(const std::string &name)
Checks to see if an Image exists.
std::vector< RenderItem * > RenderList
Definition: renderitem.h:82
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.
virtual void changeRenderInfos(uint16_t elements, int32_t src, int32_t dst, bool light, bool stentest, uint8_t stenref, GLConstants stenop, GLConstants stenfunc)=0
Dirty helper function to change the render infos.
Base Class for Images.
Definition: image.h:47
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:1031
Instance visual contains data that is needed to visualize the instance on screen. ...
Definition: visual.h:111
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:428
Image * bindColoring(ColoringInfo &info, RenderItem &vc, Camera *cam)
void removeInstance(Instance *instance)
Removes instance from all effects.
DoublePoint3D screenpoint
Definition: renderitem.h:58
InstanceRenderer(RenderBackend *renderbackend, int32_t position)
constructor.
Instance * instance
Definition: renderitem.h:45
void getPixelRGBA(int32_t x, int32_t y, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *a)
Definition: image.cpp:176
CellCache * getCellCache()
Returns the CellCache of this layer.
Definition: layer.cpp:453
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:331
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:58
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:307
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:701
virtual ImagePtr getPtr(const std::string &name)
uint32_t getLayerCount() const
Get the overall number of layers.
Definition: map.cpp:78
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:1035
InstanceRendererDeleteListener(InstanceRenderer *r)
uint32_t getHeight() const
Definition: image.cpp:155
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
bool isVisible()
Is instance visible or not.
Definition: visual.cpp:129
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:310
InstanceToAreas_t m_instance_areas
void setVisible(bool visible)
Sets visibility value for object to be visualized.
Definition: visual.cpp:122
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:280
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:98
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:303
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 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:146
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:92
Layer * getFowLayer()
Returns the layer that is used for Fog of War visualization.
CellVisualEffect getFoWType()
Returns the cell visual.
Definition: cell.cpp:383
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 an transparent area with given paramters.
bool isSharedImage() const
Returns true if this image shares data with another one.
Definition: image.h:143
ImagePtr image
Definition: renderitem.h:67
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
uint32_t timestamp
const std::list< Layer * > & getLayers() const
Get the layers on this map.
Definition: map.h:119
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
A container of Layer(s).
Definition: map.h:87
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
ImagesToCheck_t m_check_images
void removeAllColored()
Removes all coloring.
void addToCheck(const ImagePtr &image)
Add properly old ImagePtr into a check list.
uint8_t transparency
Definition: renderitem.h:73
T w
Width of the rectangle.
Definition: rect.h:90
void removeFromCheck(const ImagePtr &image)
An Instance is an &quot;instantiation&quot; of an Object at a Location.
Definition: instance.h:97
void setCallback(const type_callback &callback)
Set the callback that will be called.
Definition: timer.cpp:64
virtual void renderZ(const Rect &rect, float vertexZ, uint8_t alpha=255, bool forceNewBatch=false, uint8_t const *rgb=0)
Definition: image.h:84
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.