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 
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 
31 #include "model/metamodel/grids/cellgrid.h"
32 #include "model/metamodel/action.h"
33 #include "model/metamodel/timeprovider.h"
34 #include "model/structures/map.h"
35 #include "model/structures/layer.h"
36 #include "model/structures/instancetree.h"
37 #include "model/structures/instance.h"
38 #include "model/structures/location.h"
39 #include "util/log/logger.h"
40 #include "util/math/fife_math.h"
41 #include "util/math/angles.h"
42 #include "util/time/timemanager.h"
43 #include "video/renderbackend.h"
44 #include "video/image.h"
45 #include "video/animation.h"
46 #include "video/imagemanager.h"
47 
48 #include "camera.h"
49 #include "layercache.h"
50 #include "visual.h"
51 
52 
53 namespace FIFE {
54  static Logger _log(LM_CAMERA);
55 
56  class MapObserver : public MapChangeListener {
57  Camera* m_camera;
58 
59  public:
60  MapObserver(Camera* camera) {
61  m_camera = camera;
62  }
63  virtual ~MapObserver() {}
64 
65  virtual void onMapChanged(Map* map, std::vector<Layer*>& changedLayers) {
66  }
67 
68  virtual void onLayerCreate(Map* map, Layer* layer) {
69  m_camera->addLayer(layer);
70  }
71 
72  virtual void onLayerDelete(Map* map, Layer* layer) {
73  m_camera->removeLayer(layer);
74  }
75  };
76 
77  Camera::Camera(const std::string& id,
78  Layer *layer,
79  const Rect& viewport,
80  RenderBackend* renderbackend):
81  m_id(id),
82  m_matrix(),
83  m_inverse_matrix(),
84  m_tilt(0),
85  m_rotation(0),
86  m_zoom(1),
87  m_location(),
88  m_cur_origo(ScreenPoint(0,0,0)),
89  m_viewport(),
90  m_screen_cell_width(1),
91  m_screen_cell_height(1),
92  m_reference_scale(1),
93  m_enabled(true),
94  m_attachedto(NULL),
95  m_image_dimensions(),
96  m_iswarped(false),
97  m_renderers(),
98  m_pipeline(),
99  m_updated(false),
100  m_renderbackend(renderbackend),
101  m_layer_to_instances(),
102  m_lighting(false),
103  m_light_colors(),
104  m_col_overlay(false),
105  m_img_overlay(false),
106  m_ani_overlay(false) {
107  m_viewport = viewport;
108  m_map_observer = new MapObserver(this);
109  m_map = 0;
110  Location location;
111  location.setLayer(layer);
112  setLocation(location);
113  }
114 
116  // Trigger removal of LayerCaches and MapObserver
117  updateMap(NULL);
118 
119  std::map<std::string, RendererBase*>::iterator r_it = m_renderers.begin();
120  for(; r_it != m_renderers.end(); ++r_it) {
121  r_it->second->reset();
122  delete r_it->second;
123  }
124  m_renderers.clear();
125  delete m_map_observer;
126  }
127 
128  void Camera::setTilt(double tilt) {
129  if (!Mathd::Equal(m_tilt, tilt)) {
130  m_tilt = tilt;
131  updateReferenceScale();
132  updateMatrices();
133  m_iswarped = true;
134  }
135  }
136 
137  double Camera::getTilt() const {
138  return m_tilt;
139  }
140 
141  void Camera::setRotation(double rotation) {
142  if (!Mathd::Equal(m_rotation, rotation)) {
143  m_rotation = rotation;
144  updateReferenceScale();
145  updateMatrices();
146  m_iswarped = true;
147  }
148  }
149 
150  double Camera::getRotation() const {
151  return m_rotation;
152  }
153 
154  void Camera::setZoom(double zoom) {
155  if (!Mathd::Equal(m_zoom, zoom)) {
156  m_zoom = zoom;
157  if (m_zoom < 0.001) {
158  m_zoom = 0.001;
159  }
160  updateMatrices();
161  m_updated = false;
162  }
163  }
164 
165  double Camera::getZoom() const {
166  return m_zoom;
167  }
168 
169  void Camera::setCellImageDimensions(uint32_t width, uint32_t height) {
170  m_screen_cell_width = width;
171  m_screen_cell_height = height;
172  updateReferenceScale();
173  updateMatrices();
174  m_iswarped = true;
175  }
176 
177  void Camera::setLocation(const Location& location) {
178  if (m_location == location ) {
179  return;
180  }
181 
182  CellGrid* cell_grid = NULL;
183  if (location.getLayer()) {
184  cell_grid = location.getLayer()->getCellGrid();
185  } else {
186  throw Exception("Location without layer given to Camera::setLocation");
187  }
188  if (!cell_grid) {
189  throw Exception("Camera layer has no cellgrid specified");
190  }
191 
192  m_location = location;
193  updateMatrices();
194 
195  ExactModelCoordinate emc = m_location.getMapCoordinates();
196  m_cur_origo = toScreenCoordinates(emc);
197 
198  // WARNING
199  // It is important that m_location is already set,
200  // as the updates which are triggered here
201  // need to calculate screen-coordinates
202  // which depend on m_location.
203  updateMap(m_location.getMap());
204 
205  m_updated = false;
206  }
207 
208  void Camera::updateMap(Map* map) {
209  if(m_map == map) {
210  return;
211  }
212  if(m_map) {
213  m_map->removeChangeListener(m_map_observer);
214  const std::list<Layer*>& layers = m_map->getLayers();
215  for(std::list<Layer*>::const_iterator i = layers.begin(); i !=layers.end(); ++i) {
216  removeLayer(*i);
217  }
218  }
219  if(map) {
220  map->addChangeListener(m_map_observer);
221  const std::list<Layer*>& layers = map->getLayers();
222  for(std::list<Layer*>::const_iterator i = layers.begin(); i !=layers.end(); ++i) {
223  addLayer(*i);
224  }
225  }
226  m_map = map;
227  }
228 
230  return getCellImageDimensions(m_location.getLayer());
231  }
232 
234  if (layer == m_location.getLayer()) {
235  return Point( m_screen_cell_width, m_screen_cell_height );
236  }
237  std::map<Layer*, Point>::iterator it = m_image_dimensions.find(layer);
238  if (it != m_image_dimensions.end()) {
239  return it->second;
240  }
241  Point p;
242  CellGrid* cg = layer->getCellGrid();
243  assert(cg);
244  DoublePoint dimensions = getLogicalCellDimensions(layer);
245  p.x = static_cast<int32_t>(round(m_reference_scale * dimensions.x));
246  p.y = static_cast<int32_t>(round(m_reference_scale * dimensions.y));
247  m_image_dimensions[layer] = p;
248  return p;
249  }
250 
251  Location Camera::getLocation() const {
252  return m_location;
253  }
254 
256  return m_location;
257  }
258 
259  void Camera::setViewPort(const Rect& viewport) {
260  m_viewport = viewport;
261  }
262 
263  const Rect& Camera::getViewPort() const {
264  return m_viewport;
265  }
266 
267  void Camera::setEnabled(bool enabled) {
268  m_enabled = enabled;
269  }
270 
272  return m_enabled;
273  }
274 
276  return m_cur_origo;
277  }
278 
279  void Camera::updateMatrices() {
280  double scale = m_reference_scale;
281  m_matrix.loadScale(scale, scale, scale);
282  m_vs_matrix.loadScale(scale,scale,scale);
283  if (m_location.getLayer()) {
284  CellGrid* cg = m_location.getLayer()->getCellGrid();
285  if (cg) {
286  ExactModelCoordinate pt = m_location.getMapCoordinates();
287  m_matrix.applyTranslate( -pt.x *m_reference_scale,-pt.y *m_reference_scale, -pt.z*m_reference_scale);
288  }
289  }
290  scale = m_zoom;
291  m_matrix.applyScale(scale, scale, scale);
292  m_matrix.applyRotate(-m_rotation, 0.0, 0.0, 1.0);
293  m_matrix.applyRotate(-m_tilt, 1.0, 0.0, 0.0);
294  m_matrix.applyTranslate(+m_viewport.x+m_viewport.w/2, +m_viewport.y+m_viewport.h/2, 0);
295  m_inverse_matrix = m_matrix.inverse();
296 
297  m_vs_matrix.applyRotate(-m_rotation, 0.0, 0.0, 1.0);
298  m_vs_matrix.applyRotate(-m_tilt, 1.0, 0.0, 0.0);
299  m_vs_inverse_matrix = m_vs_matrix.inverse();
300 
301  // calculate the screen<->virtual screen transformation
302  // this explicitly ignores the z-value.
303  m_vscreen_2_screen = m_matrix;
304  // NOTE: mult4by4 is an in-place modification.
305  m_vscreen_2_screen.mult4by4(m_vs_inverse_matrix);
306  // set the z transformation to unity
307  const int32_t N=4;
308  for(int32_t i=0; i!=N; ++i) {
309  m_vscreen_2_screen[2*N + i] = 0;
310  m_vscreen_2_screen[i*N + 2] = 0;
311  }
312  m_vscreen_2_screen[2*N + 2] = 1;
313  m_screen_2_vscreen = m_vscreen_2_screen.inverse();
314 
315  // FL_WARN(_log, LMsg("matrix: ") << m_matrix << " 1: " << m_matrix.inverse().mult4by4(m_matrix));
316 // FL_WARN(_log, LMsg("vs2s matrix: ") << m_vscreen_2_screen << " s2vs matrix: " << m_screen_2_vscreen);
317  }
318 
319  void Camera::calculateZValue(ScreenPoint& screen_coords) {
320  int32_t dy = -(screen_coords.y - toScreenCoordinates(m_location.getMapCoordinates()).y);
321  screen_coords.z = static_cast<int32_t>(Mathd::Tan(m_tilt * (Mathd::pi() / 180.0)) * static_cast<double>(dy));
322  }
323 
324  ExactModelCoordinate Camera::toMapCoordinates(ScreenPoint screen_coords, bool z_calculated) {
325  if (!z_calculated) {
326  calculateZValue(screen_coords);
327  }
328  return m_inverse_matrix * intPt2doublePt(screen_coords);
329  }
330 
332  ScreenPoint pt = doublePt2intPt(m_matrix * elevation_coords);
333  return pt;
334  }
335 
337  DoublePoint3D pt = (m_vs_matrix * elevation_coords);
338  return pt;
339  }
340 
341  ScreenPoint Camera::virtualScreenToScreen(const DoublePoint3D& p) {
342  return doublePt2intPt(m_vscreen_2_screen * p);
343  }
344 
345  DoublePoint3D Camera::screenToVirtualScreen(const ScreenPoint& p) {
346  return m_screen_2_vscreen * intPt2doublePt(p);
347  }
348 
349  DoublePoint Camera::getLogicalCellDimensions(Layer* layer) {
350  CellGrid* cg = NULL;
351  if (layer) {
352  cg = layer->getCellGrid();
353  }
354  assert(cg);
355 
356  ModelCoordinate cell(0,0);
357  std::vector<ExactModelCoordinate> vertices;
358  cg->getVertices(vertices, cell);
359 
360  DoubleMatrix mtx;
361  mtx.loadRotate(m_rotation, 0.0, 0.0, 1.0);
362  mtx.applyRotate(m_tilt, 1.0, 0.0, 0.0);
363 
364  double x1 = 0;
365  double x2 = 0;
366  double y1 = 0;
367  double y2 = 0;
368 
369  for (uint32_t i = 0; i < vertices.size(); i++) {
370  vertices[i] = cg->toMapCoordinates(vertices[i]);
371  vertices[i] = mtx * vertices[i];
372  if (i == 0) {
373  x1 = x2 = vertices[0].x;
374  y1 = y2 = vertices[0].y;
375  } else {
376  x1 = std::min(vertices[i].x, x1);
377  x2 = std::max(vertices[i].x, x2);
378  y1 = std::min(vertices[i].y, y1);
379  y2 = std::max(vertices[i].y, y2);
380  }
381  }
382  return DoublePoint( x2 - x1, y2 - y1 );
383  }
384 
385  Point Camera::getRealCellDimensions(Layer* layer) {
386  CellGrid* cg = NULL;
387  if (layer) {
388  cg = layer->getCellGrid();
389  }
390  assert(cg);
391 
392  Location loc(layer);
393  ModelCoordinate cell(0,0);
394  loc.setLayerCoordinates(cell);
395  ScreenPoint sp1 = toScreenCoordinates(loc.getMapCoordinates());
396  ++cell.y;
397  loc.setLayerCoordinates(cell);
398  ScreenPoint sp2 = toScreenCoordinates(loc.getMapCoordinates());
399 
400  Point p(ABS(sp2.x - sp1.x), ABS(sp2.y - sp1.y));
401  if (p.x == 0) {
402  p.x = 1;
403  }
404  if (p.y == 0) {
405  p.y = 1;
406  }
407  return p;
408  }
409 
411  CellGrid* cg = NULL;
412  if (layer) {
413  cg = layer->getCellGrid();
414  }
415  assert(cg);
416 
417  Location loc(layer);
418  ModelCoordinate cell(0,0,0);
419  loc.setLayerCoordinates(cell);
420  ScreenPoint sp1 = toScreenCoordinates(loc.getMapCoordinates());
421  ++cell.z;
422  loc.setLayerCoordinates(cell);
423  ScreenPoint sp2 = toScreenCoordinates(loc.getMapCoordinates());
424 
425  return Point3D(sp2.x - sp1.x, sp2.y - sp1.y, sp2.z - sp1.z);
426  }
427 
428  void Camera::updateReferenceScale() {
429  DoublePoint dim = getLogicalCellDimensions(m_location.getLayer());
430  m_reference_scale = static_cast<double>(m_screen_cell_width) / dim.x;
431 
432  FL_DBG(_log, "Updating reference scale");
433  FL_DBG(_log, LMsg(" tilt=") << m_tilt << " rot=" << m_rotation);
434  FL_DBG(_log, LMsg(" m_screen_cell_width=") << m_screen_cell_width);
435  }
436 
437  void Camera::cacheUpdate(Layer* layer) {
438  Map* map = m_location.getMap();
439  if (!map) {
440  FL_ERR(_log, "No map for camera found");
441  return;
442  }
443  // if camera need update, we update all caches
444  if (m_iswarped || !m_updated) {
445  updateRenderLists();
446  } else {
447  LayerCache* cache = m_cache[layer];
448  if(!cache) {
449  addLayer(layer);
450  cache = m_cache[layer];
451  FL_ERR(_log, LMsg("Layer Cache miss! (This shouldn't happen!)") << layer->getId());
452  }
453  // only this cache need an update, e.g. a instance is added/removed
454  if (cache->needUpdate()) {
455  Transform transform = NormalTransform;
456  if (m_iswarped) {
457  transform = WarpedTransform;
458  }
459  RenderList& instances_to_render = m_layer_to_instances[layer];
460  cache->update(transform, instances_to_render);
461  }
462  }
463  }
464 
465  void Camera::getMatchingInstances(ScreenPoint screen_coords, Layer& layer, std::list<Instance*>& instances, uint8_t alpha) {
466  instances.clear();
467  bool zoomed = !Mathd::Equal(m_zoom, 1.0);
468  bool special_alpha = alpha != 0;
469  cacheUpdate(&layer);
470  const RenderList& layer_instances = m_layer_to_instances[&layer];
471  RenderList::const_iterator instance_it = layer_instances.end();
472  while (instance_it != layer_instances.begin()) {
473  --instance_it;
474  Instance* i = (*instance_it)->instance;
475  const RenderItem& vc = **instance_it;
476  if ((vc.dimensions.contains(Point(screen_coords.x, screen_coords.y)))) {
477  if(vc.image->isSharedImage()) {
478  vc.image->forceLoadInternal();
479  }
480  uint8_t r, g, b, a = 0;
481  int32_t x = screen_coords.x - vc.dimensions.x;
482  int32_t y = screen_coords.y - vc.dimensions.y;
483  if (zoomed) {
484  double fx = static_cast<double>(x);
485  double fy = static_cast<double>(y);
486  double fow = static_cast<double>(vc.image->getWidth());
487  double foh = static_cast<double>(vc.image->getHeight());
488  double fsw = static_cast<double>(vc.dimensions.w);
489  double fsh = static_cast<double>(vc.dimensions.h);
490  x = static_cast<int32_t>(round(fx / fsw * fow));
491  y = static_cast<int32_t>(round(fy / fsh * foh));
492  }
493  vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
494  // instance is hit with mouse if not totally transparent
495  if (a == 0 || (special_alpha && a < alpha)) {
496  continue;
497  }
498  instances.push_back(i);
499  }
500  }
501  }
502 
503  void Camera::getMatchingInstances(Rect screen_rect, Layer& layer, std::list<Instance*>& instances, uint8_t alpha) {
504  instances.clear();
505  bool zoomed = !Mathd::Equal(m_zoom, 1.0);
506  bool special_alpha = alpha != 0;
507  cacheUpdate(&layer);
508 
509  const RenderList& layer_instances = m_layer_to_instances[&layer];
510  RenderList::const_iterator instance_it = layer_instances.end();
511  while (instance_it != layer_instances.begin()) {
512  --instance_it;
513  Instance* i = (*instance_it)->instance;;
514  const RenderItem& vc = **instance_it;
515  if ((vc.dimensions.intersects(screen_rect))) {
516  if(vc.image->isSharedImage()) {
517  vc.image->forceLoadInternal();
518  }
519  uint8_t r, g, b, a = 0;
520  for(int32_t xx = screen_rect.x; xx < screen_rect.x + screen_rect.w; xx++) {
521  for(int32_t yy = screen_rect.y; yy < screen_rect.y + screen_rect.h; yy++) {
522  if ((vc.dimensions.contains(Point(xx, yy)))) {
523  int32_t x = xx - vc.dimensions.x;
524  int32_t y = yy - vc.dimensions.y;
525  if (zoomed) {
526  double fx = static_cast<double>(x);
527  double fy = static_cast<double>(y);
528  double fow = static_cast<double>(vc.image->getWidth());
529  double foh = static_cast<double>(vc.image->getHeight());
530  double fsw = static_cast<double>(vc.dimensions.w);
531  double fsh = static_cast<double>(vc.dimensions.h);
532  x = static_cast<int32_t>(round(fx / fsw * fow));
533  y = static_cast<int32_t>(round(fy / fsh * foh));
534  }
535  vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
536  // instance is hit with mouse if not totally transparent
537  if (a == 0 || (special_alpha && a < alpha)) {
538  continue;
539  }
540 
541  instances.push_back(i);
542  goto found_non_transparent_pixel;
543  }
544  }
545  }
546  found_non_transparent_pixel:;
547  }
548  }
549  }
550 
551  void Camera::getMatchingInstances(Location& loc, std::list<Instance*>& instances, bool use_exactcoordinates) {
552  instances.clear();
553  Layer* layer = loc.getLayer();
554  if(!layer) {
555  return;
556  }
557 
558  cacheUpdate(layer);
559  const RenderList& layer_instances = m_layer_to_instances[layer];
560  RenderList::const_iterator instance_it = layer_instances.end();
561  while (instance_it != layer_instances.begin()) {
562  --instance_it;
563  Instance* i = (*instance_it)->instance;
564  if (use_exactcoordinates) {
565  if (i->getLocationRef().getExactLayerCoordinatesRef() == loc.getExactLayerCoordinatesRef()) {
566  instances.push_back(i);
567  }
568  } else {
569  if (i->getLocationRef().getLayerCoordinates() == loc.getLayerCoordinates()) {
570  instances.push_back(i);
571  }
572  }
573  }
574  }
575 
576  void Camera::attach(Instance *instance) {
577  // fail if the layers aren't the same
578  if (m_location.getLayer()->getId() != instance->getLocation().getLayer()->getId()) {
579  FL_WARN(_log, "Tried to attach camera to instance on different layer.");
580  return ;
581  }
582  m_attachedto = instance;
583  }
584 
585  void Camera::detach() {
586  m_attachedto = NULL;
587  }
588 
589  void Camera::update() {
590  if( !m_attachedto ) {
591  return;
592  }
593  Location loc(m_location);
594  loc.setExactLayerCoordinates( m_attachedto->getLocationRef().getExactLayerCoordinates(m_location.getLayer()) );
595  setLocation(loc);
596  updateMatrices();
597  }
598 
600  updateMatrices();
601  m_iswarped = true;
602  }
603 
605  m_iswarped = false;
606  m_updated = true;
607  }
608 
609  bool pipelineSort(const RendererBase* lhs, const RendererBase* rhs) {
610  return (lhs->getPipelinePosition() < rhs->getPipelinePosition());
611  }
612 
614  renderer->setRendererListener(this);
615  m_renderers[renderer->getName()] = renderer;
616  if (renderer->isEnabled()) {
617  m_pipeline.push_back(renderer);
618  }
619  m_pipeline.sort(pipelineSort);
620  }
621 
623  m_pipeline.sort(pipelineSort);
624  }
625 
627  assert(m_renderers[renderer->getName()]);
628  if (renderer->isEnabled()) {
629  FL_LOG(_log, LMsg("Enabling renderer ") << renderer->getName());
630  m_pipeline.push_back(renderer);
631  m_pipeline.sort(pipelineSort);
632  } else {
633  m_pipeline.remove(renderer);
634  }
635  }
636 
637  RendererBase* Camera::getRenderer(const std::string& name) {
638  return m_renderers[name];
639  }
640 
642  std::map<std::string, RendererBase*>::iterator r_it = m_renderers.begin();
643  for (; r_it != m_renderers.end(); ++r_it) {
644  r_it->second->reset();
645  }
646  }
647 
648  void Camera::addLayer(Layer* layer) {
649  m_cache[layer] = new LayerCache(this);
650  m_cache[layer]->setLayer(layer);
651  m_layer_to_instances[layer] = RenderList();
652  }
653 
654  void Camera::removeLayer(Layer* layer) {
655  delete m_cache[layer];
656  m_cache.erase(layer);
657  m_layer_to_instances.erase(layer);
658  }
659 
660  void Camera::setLightingColor(float red, float green, float blue) {
661  m_lighting = true;
662  m_light_colors.clear();
663  m_light_colors.push_back(red);
664  m_light_colors.push_back(green);
665  m_light_colors.push_back(blue);
666  }
667 
668  std::vector<float> Camera::getLightingColor() {
669  if(m_light_colors.empty()) {
670  for(int32_t colors = 0; colors != 3; ++colors) {
671  m_light_colors.push_back(1.0f);
672  }
673  }
674  return m_light_colors;
675  }
676 
678  m_lighting = false;
679  m_renderbackend->resetLighting();
680  }
681 
682  void Camera::setOverlayColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
683  m_col_overlay = true;
684  m_overlay_color.r = red;
685  m_overlay_color.g = green;
686  m_overlay_color.b = blue;
687  m_overlay_color.unused = alpha;
688  }
689 
690  std::vector<uint8_t> Camera::getOverlayColor() {
691  std::vector<uint8_t> colors;
692  if (m_col_overlay) {
693  colors.push_back(m_overlay_color.r);
694  colors.push_back(m_overlay_color.g);
695  colors.push_back(m_overlay_color.b);
696  colors.push_back(m_overlay_color.unused);
697  } else {
698  for(uint8_t cc = 0; cc != 4; ++cc) {
699  colors.push_back(255);
700  }
701  }
702  return colors;
703  }
704 
706  m_col_overlay = false;
707  }
708 
709  void Camera::setOverlayImage(int32_t id, bool fill) {
710  m_img_overlay = true;
711  m_img_id = id;
712  m_img_fill = fill;
713  }
714 
716  int32_t id = -1;
717  if (m_img_overlay) {
718  id = m_img_id;
719  }
720  return id;
721  }
722 
724  m_img_overlay = false;
725  m_img_id = -1;
726  }
727 
729  m_ani_overlay = true;
730  m_ani_ptr = anim;
731  m_ani_fill = fill;
732  m_start_time = 0;
733  }
734 
736  return m_ani_ptr;
737  }
738 
740  m_ani_overlay = false;
741  m_ani_ptr.reset();
742  }
743 
744  void Camera::renderOverlay() {
745  if (!m_col_overlay && !m_img_overlay && !m_ani_overlay) {
746  return;
747  }
748  uint16_t width = m_viewport.w;
749  uint16_t height = m_viewport.h;
750  Point pm = Point(m_viewport.x + width/2, m_viewport.y + height/2);
751  Rect r;
752 
753  // color overlay
754  if (m_col_overlay) {
755  Point p = Point(m_viewport.x, m_viewport.y);
756  m_renderbackend->fillRectangle(p, width, height, m_overlay_color.r, m_overlay_color.g, m_overlay_color.b, m_overlay_color.unused);
757  }
758  // image overlay
759  if (m_img_overlay) {
760  ImagePtr resptr = ImageManager::instance()->get(m_img_id);
761  Image* img = resptr.get();
762  if (img) {
763  if (m_img_fill) {
764  r.w = width;
765  r.h = height;
766  } else {
767  r.w = img->getWidth();
768  r.h = img->getHeight();
769  }
770  r.x = pm.x-r.w/2;
771  r.y = pm.y-r.h/2;
772  img->render(r);
773  }
774  }
775  // animation overlay
776  if (m_ani_overlay) {
777  assert(m_ani_ptr != 0);
778 
779  if (m_start_time == 0) {
780  m_start_time = TimeManager::instance()->getTime();
781  }
782  uint32_t animtime = scaleTime(1.0, TimeManager::instance()->getTime() - m_start_time) % m_ani_ptr->getDuration();
783  ImagePtr img = m_ani_ptr->getFrameByTimestamp(animtime);
784  if (img) {
785  if (m_ani_fill) {
786  r.w = width;
787  r.h = height;
788  } else {
789  r.w = img->getWidth();
790  r.h = img->getHeight();
791  }
792  r.x = pm.x-r.w/2;
793  r.y = pm.y-r.h/2;
794  img->render(r);
795  }
796  }
797  }
798 
799  void Camera::updateRenderLists() {
800  Map* map = m_location.getMap();
801  if (!map) {
802  FL_ERR(_log, "No map for camera found");
803  return;
804  }
805 
806  Transform transform = NormalTransform;
807  if (m_iswarped) {
808  transform = WarpedTransform;
809  }
810  const std::list<Layer*>& layers = map->getLayers();
811  std::list<Layer*>::const_iterator layer_it = layers.begin();
812  for (;layer_it != layers.end(); ++layer_it) {
813  LayerCache* cache = m_cache[*layer_it];
814  if(!cache) {
815  addLayer(*layer_it);
816  cache = m_cache[*layer_it];
817  FL_ERR(_log, LMsg("Layer Cache miss! (This shouldn't happen!)") << (*layer_it)->getId());
818  }
819  RenderList& instances_to_render = m_layer_to_instances[*layer_it];
820  if (m_iswarped || !m_updated || cache->needUpdate()) {
821  cache->update(transform, instances_to_render);
822  }
823  }
824  resetUpdates();
825  }
826 
827  void Camera::render() {
828  static bool renderbackendOpenGLe = (m_renderbackend->getName() == "OpenGLe");
829  updateRenderLists();
830  Map* map = m_location.getMap();
831  if (!map) {
832  return;
833  }
834 
835  uint32_t lm = m_renderbackend->getLightingModel();
836  if (lm != 0) {
837  m_renderbackend->resetStencilBuffer(0);
838  if (m_lighting) {
839  m_renderbackend->setLighting(m_light_colors[0], m_light_colors[1], m_light_colors[2]);
840  }
841  }
842 
843  m_renderbackend->pushClipArea(getViewPort());
844 
845  const std::list<Layer*>& layers = map->getLayers();
846  std::list<Layer*>::const_iterator layer_it = layers.begin();
847  for ( ; layer_it != layers.end(); ++layer_it) {
848  RenderList& instances_to_render = m_layer_to_instances[*layer_it];
849  std::list<RendererBase*>::iterator r_it = m_pipeline.begin();
850  for (; r_it != m_pipeline.end(); ++r_it) {
851  if ((*r_it)->isActivedLayer(*layer_it)) {
852  (*r_it)->render(this, *layer_it, instances_to_render);
853  }
854  }
855  if (renderbackendOpenGLe) {
856  m_renderbackend->renderVertexArrays();
857  }
858  }
859 
860  renderOverlay();
861  m_renderbackend->renderVertexArrays();
862  if (m_lighting && lm != 0) {
863  m_renderbackend->resetLighting();
864  }
865  m_renderbackend->popClipArea();
866  }
867 }