FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
camera.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2008 by the FIFE team *
3  * http://www.fifengine.de *
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 <SDL.h>
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 
32 #include "model/metamodel/grids/cellgrid.h"
33 #include "model/metamodel/action.h"
34 #include "model/metamodel/timeprovider.h"
35 #include "model/structures/map.h"
36 #include "model/structures/layer.h"
37 #include "model/structures/instancetree.h"
38 #include "model/structures/instance.h"
39 #include "model/structures/location.h"
40 #include "util/log/logger.h"
41 #include "util/math/fife_math.h"
42 #include "util/math/angles.h"
43 #include "util/time/timemanager.h"
44 #include "video/renderbackend.h"
45 #include "video/image.h"
46 #include "video/imagepool.h"
47 #include "video/animation.h"
48 #include "video/animationpool.h"
49 
50 #include "camera.h"
51 #include "layercache.h"
52 #include "visual.h"
53 
54 
55 namespace FIFE {
56  static Logger _log(LM_CAMERA);
57 
58  class MapObserver : public MapChangeListener {
59  Camera* m_camera;
60 
61  public:
62  MapObserver(Camera* camera) {
63  m_camera = camera;
64  }
65  virtual ~MapObserver() {}
66 
67  virtual void onMapChanged(Map* map, std::vector<Layer*>& changedLayers) {
68  }
69 
70  virtual void onLayerCreate(Map* map, Layer* layer) {
71  m_camera->addLayer(layer);
72  }
73 
74  virtual void onLayerDelete(Map* map, Layer* layer) {
75  m_camera->removeLayer(layer);
76  }
77  };
78 
79  Camera::Camera(const std::string& id,
80  Layer *layer,
81  const Rect& viewport,
82  RenderBackend* renderbackend,
83  ImagePool* ipool,
84  AnimationPool* apool):
85  m_id(id),
86  m_matrix(),
87  m_inverse_matrix(),
88  m_tilt(0),
89  m_rotation(0),
90  m_zoom(1),
91  m_location(),
92  m_prev_origo(ScreenPoint(0,0,0)),
93  m_cur_origo(ScreenPoint(0,0,0)),
94  m_viewport(),
95  m_screen_cell_width(1),
96  m_screen_cell_height(1),
97  m_reference_scale(1),
98  m_enabled(true),
99  m_attachedto(NULL),
100  m_image_dimensions(),
101  m_iswarped(false),
102  m_renderers(),
103  m_pipeline(),
104  m_updated(false),
105  m_renderbackend(renderbackend),
106  m_ipool(ipool),
107  m_apool(apool),
108  m_layer_to_instances(),
109  m_lighting(false),
110  m_light_colors() {
111 
112  m_viewport = viewport;
113  m_map_observer = new MapObserver(this);
114  m_map = 0;
115  Location location;
116  location.setLayer(layer);
117  setLocation(location);
118  if(m_renderbackend->getName() == "SDL") {
119  m_backendSDL = true;
120  } else {
121  m_backendSDL = false;
122  }
123  }
124 
126  // Trigger removal of LayerCaches and MapObserver
127  updateMap(NULL);
128 
129  std::map<std::string, RendererBase*>::iterator r_it = m_renderers.begin();
130  for(; r_it != m_renderers.end(); ++r_it) {
131  delete r_it->second;
132  }
133  m_renderers.clear();
134  delete m_map_observer;
135  }
136 
137  void Camera::setTilt(double tilt) {
138  if(m_tilt != tilt) {
139  m_tilt = tilt;
140  updateReferenceScale();
141  updateMatrices();
142  m_iswarped = true;
143  }
144  }
145 
146  double Camera::getTilt() const {
147  return m_tilt;
148  }
149 
150  void Camera::setRotation(double rotation) {
151  if(m_rotation != rotation) {
152  m_rotation = rotation;
153  updateReferenceScale();
154  updateMatrices();
155  m_iswarped = true;
156  }
157  }
158 
159  double Camera::getRotation() const {
160  return m_rotation;
161  }
162 
163  void Camera::setZoom(double zoom) {
164  if(m_zoom!=zoom) {
165  m_zoom = zoom;
166  if (m_zoom < 0.001) {
167  m_zoom = 0.001;
168  }
169  updateMatrices();
170  }
171  }
172 
173  double Camera::getZoom() const {
174  return m_zoom;
175  }
176 
177  void Camera::setCellImageDimensions(unsigned int width, unsigned int height) {
178  m_screen_cell_width = width;
179  m_screen_cell_height = height;
180  updateReferenceScale();
181  updateMatrices();
182  m_iswarped = true;
183  }
184 
185  void Camera::setLocation(const Location& location) {
186  // initialize first set properly
187  if ((m_prev_origo == m_cur_origo) && (m_prev_origo == ScreenPoint(0,0,0))) {
188  m_cur_origo = toScreenCoordinates(ExactModelCoordinate(0,0,0));
189  m_prev_origo = m_cur_origo;
190  }
191 
192  CellGrid* cell_grid = NULL;
193  if (location.getLayer()) {
194  cell_grid = location.getLayer()->getCellGrid();
195  } else {
196  throw Exception("Location without layer given to Camera::setLocation");
197  }
198  if (!cell_grid) {
199  throw Exception("Camera layer has no cellgrid specified");
200  }
201 
202  m_location = location;
203  updateMatrices();
204 
205  // WARNING
206  // It is important that m_location is already set,
207  // as the updates which are triggered here
208  // need to calculate screen-coordinates
209  // which depend on m_location.
210  updateMap(location.getMap());
211 
212  m_cur_origo = toScreenCoordinates(ExactModelCoordinate(0,0,0));
213  }
214 
215  void Camera::updateMap(Map* map)
216  {
217  if(m_map == map)
218  {
219  return;
220  }
221  if(m_map) {
222  m_map->removeChangeListener(m_map_observer);
223  const std::list<Layer*>& layers = m_map->getLayers();
224  for(std::list<Layer*>::const_iterator i = layers.begin(); i !=layers.end(); ++i) {
225  removeLayer(*i);
226  }
227  }
228  if(map) {
229  map->addChangeListener(m_map_observer);
230  const std::list<Layer*>& layers = map->getLayers();
231  for(std::list<Layer*>::const_iterator i = layers.begin(); i !=layers.end(); ++i)
232  addLayer(*i);
233  }
234  m_map = map;
235  }
236 
238  return getCellImageDimensions(m_location.getLayer());
239  }
240 
242  if (layer == m_location.getLayer()) {
243  return Point( m_screen_cell_width, m_screen_cell_height );
244  }
245  std::map<Layer*, Point>::iterator it = m_image_dimensions.find(layer);
246  if (it != m_image_dimensions.end()) {
247  return it->second;
248  }
249  Point p;
250  CellGrid* cg = layer->getCellGrid();
251  assert(cg);
252  DoublePoint dimensions = getLogicalCellDimensions(layer);
253  p.x = static_cast<int>(round(m_reference_scale * dimensions.x));
254  p.y = static_cast<int>(round(m_reference_scale * dimensions.y));
255  m_image_dimensions[layer] = p;
256  return p;
257  }
258 
259  Location Camera::getLocation() const {
260  return m_location;
261  }
262 
264  return m_location;
265  }
266 
267  void Camera::setViewPort(const Rect& viewport) {
268  m_viewport = viewport;
269  }
270 
271  const Rect& Camera::getViewPort() const {
272  return m_viewport;
273  }
274 
275  void Camera::setEnabled(bool enabled) {
276  m_enabled = enabled;
277  }
278 
280  return m_enabled;
281  }
282 
283  Point3D Camera::getOrigin() const {
284  return m_cur_origo;
285  }
286 
287  void Camera::updateMatrices() {
288  double scale = m_reference_scale;
289  m_matrix.loadScale(scale, scale, scale);
290  m_vs_matrix.loadScale(scale,scale,scale);
291  if (m_location.getLayer()) {
292  CellGrid* cg = m_location.getLayer()->getCellGrid();
293  if (cg) {
294  ExactModelCoordinate pt = m_location.getMapCoordinates();
295  m_matrix.applyTranslate( -pt.x *m_reference_scale,-pt.y *m_reference_scale, 0);
296  }
297  }
298  scale = m_zoom;
299  m_matrix.applyScale(scale, scale, scale);
300  m_matrix.applyRotate(-m_rotation, 0.0, 0.0, 1.0);
301  m_matrix.applyRotate(-m_tilt, 1.0, 0.0, 0.0);
302  m_matrix.applyTranslate(+m_viewport.x+m_viewport.w/2, +m_viewport.y+m_viewport.h/2, 0);
303  m_inverse_matrix = m_matrix.inverse();
304 
305 
306  m_vs_matrix.applyTranslate(0,0,0);
307  m_vs_matrix.applyRotate(-m_rotation, 0.0, 0.0, 1.0);
308  m_vs_matrix.applyRotate(-m_tilt, 1.0, 0.0, 0.0);
309  m_vs_inverse_matrix = m_vs_matrix.inverse();
310 
311  // calculate the screen<->virtual screen transformation
312  // this explicitly ignores the z-value.
313  m_vscreen_2_screen = m_matrix;
314  // NOTE: mult4by4 is an in-place modification.
315  m_vscreen_2_screen.mult4by4(m_vs_inverse_matrix);
316  // set the z transformation to unity
317  const int N=4;
318  for(int i=0; i!=N; ++i) {
319  m_vscreen_2_screen[2*N + i] = 0;
320  m_vscreen_2_screen[i*N + 2] = 0;
321  }
322  m_vscreen_2_screen[2*N + 2] = 1;
323  m_screen_2_vscreen = m_vscreen_2_screen.inverse();
324 
325  // FL_WARN(_log, LMsg("matrix: ") << m_matrix << " 1: " << m_matrix.inverse().mult4by4(m_matrix));
326 // FL_WARN(_log, LMsg("vs2s matrix: ") << m_vscreen_2_screen << " s2vs matrix: " << m_screen_2_vscreen);
327  }
328 
329  void Camera::calculateZValue(ScreenPoint& screen_coords) {
330  int dy = -(screen_coords.y - toScreenCoordinates(m_location.getMapCoordinates()).y);
331  screen_coords.z = static_cast<int>(Mathd::Tan(m_tilt * (Mathd::pi() / 180.0)) * static_cast<double>(dy));
332  }
333 
334  ExactModelCoordinate Camera::toMapCoordinates(ScreenPoint screen_coords, bool z_calculated) {
335  if (!z_calculated) {
336  calculateZValue(screen_coords);
337  }
338  return m_inverse_matrix * intPt2doublePt(screen_coords);
339  }
340 
342  ExactModelCoordinate p = elevation_coords;
343  ScreenPoint pt = doublePt2intPt( m_matrix* p );
344  return pt;
345  }
346 
348  ExactModelCoordinate p = elevation_coords;
349  DoublePoint3D pt = (m_vs_matrix * p);
350  return pt;
351  }
352 
353  ScreenPoint Camera::virtualScreenToScreen(const DoublePoint3D& p) {
354  return doublePt2intPt(m_vscreen_2_screen * p);
355  }
356 
357  DoublePoint3D Camera::screenToVirtualScreen(const ScreenPoint& p) {
358  return m_screen_2_vscreen * intPt2doublePt(p);
359  }
360 
361  DoublePoint Camera::getLogicalCellDimensions(Layer* layer) {
362  CellGrid* cg = NULL;
363  if (layer) {
364  cg = layer->getCellGrid();
365  }
366  assert(cg);
367 
368  ModelCoordinate cell(0,0);
369  std::vector<ExactModelCoordinate> vertices;
370  cg->getVertices(vertices, cell);
371 
372  DoubleMatrix mtx;
373  mtx.loadRotate(m_rotation, 0.0, 0.0, 1.0);
374  mtx.applyRotate(m_tilt, 1.0, 0.0, 0.0);
375 
376  double x1 = 0;
377  double x2 = 0;
378  double y1 = 0;
379  double y2 = 0;
380 
381  for (unsigned int i = 0; i < vertices.size(); i++) {
382  vertices[i] = cg->toMapCoordinates(vertices[i]);
383  vertices[i] = mtx * vertices[i];
384  if (i == 0) {
385  x1 = x2 = vertices[0].x;
386  y1 = y2 = vertices[0].y;
387  } else {
388  x1 = std::min(vertices[i].x, x1);
389  x2 = std::max(vertices[i].x, x2);
390  y1 = std::min(vertices[i].y, y1);
391  y2 = std::max(vertices[i].y, y2);
392  }
393  }
394  return DoublePoint( x2 - x1, y2 - y1 );
395  }
396 
397  void Camera::updateReferenceScale() {
398  DoublePoint dim = getLogicalCellDimensions(m_location.getLayer());
399  m_reference_scale = static_cast<double>(m_screen_cell_width) / dim.x;
400 
401  FL_DBG(_log, "Updating reference scale");
402  FL_DBG(_log, LMsg(" tilt=") << m_tilt << " rot=" << m_rotation);
403  FL_DBG(_log, LMsg(" m_screen_cell_width=") << m_screen_cell_width);
404  }
405 
407  Map* map = m_location.getMap();
408  Rect cv = m_viewport;
409  int cv2x = cv.x+cv.w;
410  int cv2y = cv.y+cv.h;
411  bool trec1 = false, trec2 = false, trec3 = false, trec4 = false;
412  Rect rec1 = Rect(cv.x, cv.y, 1, 1);
413  Rect rec2 = Rect(cv.x, cv2y, 1, 1);
414  Rect rec3 = Rect(cv2x, cv.y, 1, 1);
415  Rect rec4 = Rect(cv2x, cv2y, 1, 1);
416 
417  const std::list<Layer*>& layers = map->getLayers();
418  std::list<Layer*>::const_iterator layer_it = layers.begin();
419  m_layer_to_instances.clear();
420  const RenderList& layer_instances = m_layer_to_instances[*layer_it];
421  RenderList::const_iterator instance_it = layer_instances.begin();
422  for(; instance_it != layer_instances.end(); ++instance_it) {
423  const RenderItem& vc = **instance_it;
424  if(vc.dimensions.intersects(rec1) && !trec1) {
425  trec1 = true;
426  }
427  if(vc.dimensions.intersects(rec2) && !trec2) {
428  trec2 = true;
429  }
430  if(trec1 && trec2) {
431  break;
432  }
433  }
434  if(trec1 && trec2) {
435  RenderList::const_reverse_iterator instance_itr = layer_instances.rbegin();
436  for(; instance_itr != layer_instances.rend(); ++instance_itr) {
437  const RenderItem& vc = **instance_itr;
438  if(vc.dimensions.intersects(rec3) && !trec3) {
439  trec3 = true;
440  }
441  if(vc.dimensions.intersects(rec4) && !trec4) {
442  trec4 = true;
443  }
444  if(trec3 && trec4) {
445  break;
446  }
447  }
448  }
449 
450  if(trec1 && trec2 && trec3 && trec4) {
451  return false;
452  }
453  return true;
454  }
455 
456  void Camera::getMatchingInstances(ScreenPoint screen_coords, Layer& layer, std::list<Instance*>& instances) {
457  instances.clear();
458  const RenderList& layer_instances = m_layer_to_instances[&layer];
459  RenderList::const_iterator instance_it = layer_instances.end();
460  while (instance_it != layer_instances.begin()) {
461  --instance_it;
462  Instance* i = (*instance_it)->instance;
463  const RenderItem& vc = **instance_it;
464  if ((vc.dimensions.contains(Point(screen_coords.x, screen_coords.y)))) {
465  assert(vc.image);
466  Uint8 r, g, b, a;
467  int x = screen_coords.x - vc.dimensions.x;
468  int y = screen_coords.y - vc.dimensions.y;
469  if (m_zoom != 1.0) {
470  double fx = static_cast<double>(x);
471  double fy = static_cast<double>(y);
472  double fow = static_cast<double>(vc.image->getWidth());
473  double foh = static_cast<double>(vc.image->getHeight());
474  double fsw = static_cast<double>(vc.dimensions.w);
475  double fsh = static_cast<double>(vc.dimensions.h);
476  x = static_cast<int>(round(fx / fsw * fow));
477  y = static_cast<int>(round(fy / fsh * foh));
478  }
479  vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
480  // instance is hit with mouse if not totally transparent
481  if (a != 0) {
482  instances.push_back(i);
483  }
484  }
485  }
486  }
487 
488  void Camera::getMatchingInstances(Rect screen_rect, Layer& layer, std::list<Instance*>& instances) {
489  instances.clear();
490  const RenderList& layer_instances = m_layer_to_instances[&layer];
491  RenderList::const_iterator instance_it = layer_instances.end();
492  while (instance_it != layer_instances.begin()) {
493  --instance_it;
494  Instance* i = (*instance_it)->instance;;
495  const RenderItem& vc = **instance_it;
496  if ((vc.dimensions.intersects(screen_rect))) {
497  assert(vc.image);
498  Uint8 r, g, b, a;
499  for(int xx = screen_rect.x; xx < screen_rect.x + screen_rect.w; xx++) {
500  for(int yy = screen_rect.y; yy < screen_rect.y + screen_rect.h; yy++) {
501  if ((vc.dimensions.contains(Point(xx, yy)))) {
502  int x = xx - vc.dimensions.x;
503  int y = yy - vc.dimensions.y;
504  if (m_zoom != 1.0) {
505  double fx = static_cast<double>(x);
506  double fy = static_cast<double>(y);
507  double fow = static_cast<double>(vc.image->getWidth());
508  double foh = static_cast<double>(vc.image->getHeight());
509  double fsw = static_cast<double>(vc.dimensions.w);
510  double fsh = static_cast<double>(vc.dimensions.h);
511  x = static_cast<int>(round(fx / fsw * fow));
512  y = static_cast<int>(round(fy / fsh * foh));
513  }
514  vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
515  // instance is hit with mouse if not totally transparent
516  if (a != 0) {
517  instances.push_back(i);
518  goto found_non_transparent_pixel;
519  }
520  }
521  }
522  }
523  found_non_transparent_pixel:;
524  }
525  }
526  }
527 
528  void Camera::getMatchingInstances(Location& loc, std::list<Instance*>& instances, bool use_exactcoordinates) {
529  instances.clear();
530  const RenderList& layer_instances = m_layer_to_instances[loc.getLayer()];
531  RenderList::const_iterator instance_it = layer_instances.end();
532  while (instance_it != layer_instances.begin()) {
533  --instance_it;
534  Instance* i = (*instance_it)->instance;
535  if (use_exactcoordinates) {
536  if (i->getLocationRef().getExactLayerCoordinatesRef() == loc.getExactLayerCoordinatesRef()) {
537  instances.push_back(i);
538  }
539  } else {
540  if (i->getLocationRef().getLayerCoordinates() == loc.getLayerCoordinates()) {
541  instances.push_back(i);
542  }
543  }
544  }
545  }
546 
547  void Camera::attach(Instance *instance) {
548  // fail if the layers aren't the same
549  if (m_location.getLayer()->getId() != instance->getLocation().getLayer()->getId()) {
550  FL_WARN(_log, "Tried to attach camera to instance on different layer.");
551  return ;
552  }
553  m_attachedto = instance;
554  }
555 
556  void Camera::detach() {
557  m_attachedto = NULL;
558  }
559 
560  void Camera::update() {
561  if( !m_attachedto ) {
562  return;
563  }
564  Location loc(m_location);
565  loc.setExactLayerCoordinates( m_attachedto->getLocationRef().getExactLayerCoordinates(m_location.getLayer()) );
566  setLocation(loc);
567  updateMatrices();
568  }
569 
571  updateMatrices();
572  m_iswarped = true;
573  }
574 
576  m_iswarped = false;
577  m_prev_origo = m_cur_origo;
578  }
579 
580  bool pipelineSort(const RendererBase* lhs, const RendererBase* rhs) {
581  return (lhs->getPipelinePosition() < rhs->getPipelinePosition());
582  }
583 
585  renderer->setRendererListener(this);
586  m_renderers[renderer->getName()] = renderer;
587  if (renderer->isEnabled()) {
588  m_pipeline.push_back(renderer);
589  }
590  m_pipeline.sort(pipelineSort);
591  }
592 
594  m_pipeline.sort(pipelineSort);
595  }
596 
598  assert(m_renderers[renderer->getName()]);
599  if (renderer->isEnabled()) {
600  FL_LOG(_log, LMsg("Enabling renderer ") << renderer->getName());
601  m_pipeline.push_back(renderer);
602  m_pipeline.sort(pipelineSort);
603  } else {
604  m_pipeline.remove(renderer);
605  }
606  }
607 
608  RendererBase* Camera::getRenderer(const std::string& name) {
609  return m_renderers[name];
610  }
611 
613  std::map<std::string, RendererBase*>::iterator r_it = m_renderers.begin();
614  for (; r_it != m_renderers.end(); ++r_it) {
615  Map* map = m_location.getMap();
616  r_it->second->reset();
617  }
618  }
619 
620  void Camera::addLayer(Layer* layer) {
621  m_cache[layer] = new LayerCache(this, m_ipool, m_apool);
622  m_cache[layer]->setLayer(layer);
623  m_layer_to_instances[layer] = RenderList();
624  }
625 
626  void Camera::removeLayer(Layer* layer) {
627  delete m_cache[layer];
628  m_cache.erase(layer);
629  m_layer_to_instances.erase(layer);
630  }
631 
632  void Camera::setLightingColor(float red, float green, float blue, float alpha) {
633  m_lighting = true;
634  m_light_colors.clear();
635  m_light_colors.push_back(red);
636  m_light_colors.push_back(green);
637  m_light_colors.push_back(blue);
638  m_light_colors.push_back(alpha);
639  }
640 
641  std::vector<float> Camera::getLightingColor() {
642  if(m_light_colors.empty()) {
643  for(int colors = 0; colors != 4; ++colors) {
644  m_light_colors.push_back(1.0f);
645  }
646  }
647  return m_light_colors;
648  }
649 
650  void Camera::resetLightingColor() {
651  m_lighting = false;
652  m_renderbackend->resetLighting();
653  }
654 
655  void Camera::render() {
656  Transform transform = NormalTransform;
657  if(m_iswarped)
658  transform = WarpedTransform;
659  m_iswarped = false;
660 
661  Map* map = m_location.getMap();
662  if (!map) {
663  FL_ERR(_log, "No map for camera found");
664  return;
665  }
666  //if ((!map->isChanged()) && (!m_iswarped) && (cammove == ScreenPoint(0,0,0))) {
667  // return;
668  //}
669 
670  if (m_renderbackend->getLightingModel() != 0) {
671  m_renderbackend->resetStencilBuffer(0);
672  if (m_lighting) {
673  m_renderbackend->setLighting(m_light_colors[0], m_light_colors[1], m_light_colors[2], m_light_colors[3]);
674  }
675  }
676 
677  if(m_backendSDL) {
678  m_renderbackend->pushClipArea(getViewPort());
679  } else {
680  m_renderbackend->pushClipArea(getViewPort(), testRenderedViewPort());
681  }
682 
683  // update each layer
684 // m_layer_to_instances.clear();
685 
686  const std::list<Layer*>& layers = map->getLayers();
687  std::list<Layer*>::const_iterator layer_it = layers.begin();
688  for (;layer_it != layers.end(); ++layer_it) {
689  LayerCache* cache = m_cache[*layer_it];
690  if(!cache) {
691  addLayer(*layer_it);
692  cache = m_cache[*layer_it];
693  FL_ERR(_log, LMsg("Layer Cache miss! (This shouldn't happen!)") << (*layer_it)->getId());
694  }
695  RenderList& instances_to_render = m_layer_to_instances[*layer_it];
696  cache->update(transform, instances_to_render);
697 
698  std::list<RendererBase*>::iterator r_it = m_pipeline.begin();
699  for (; r_it != m_pipeline.end(); ++r_it) {
700  if ((*r_it)->isActivedLayer(*layer_it)) {
701  (*r_it)->render(this, *layer_it, instances_to_render);
702  }
703  }
704  }
705 
706  if (m_lighting) {
707  m_renderbackend->resetLighting();
708  }
709 
710  m_renderbackend->popClipArea();
711  resetUpdates();
712  m_updated = true;
713  }
714 
715 }