FIFE  6e1afdbeda11afe9ac53e6023a4be96ef88f1dc6
layercache.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2017 by the FIFE team *
3  * http://www.fifengine.net *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 #include <cfloat>
24 
25 // 3rd party library includes
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 
33 #include "model/metamodel/action.h"
34 #include "model/structures/layer.h"
37 #include "util/base/exception.h"
38 #include "util/log/logger.h"
39 #include "util/math/fife_math.h"
40 #include "util/math/angles.h"
41 #include "video/renderbackend.h"
42 #include "video/image.h"
43 #include "video/animation.h"
44 #include "video/imagemanager.h"
45 
46 #include "camera.h"
47 #include "layercache.h"
48 #include "visual.h"
49 
50 
51 namespace FIFE {
55  static Logger _log(LM_CAMERA);
56 
58  public:
60  m_cache = cache;
61  }
63 
64  virtual void onLayerChanged(Layer* layer, std::vector<Instance*>& instances) {
65  for(std::vector<Instance*>::iterator i = instances.begin();
66  i != instances.end(); ++i) {
68  }
69  }
70 
71  virtual void onInstanceCreate(Layer* layer, Instance* instance) {
72  m_cache->addInstance(instance);
73  }
74 
75  virtual void onInstanceDelete(Layer* layer, Instance* instance) {
76  m_cache->removeInstance(instance);
77  }
78  private:
80  };
81 
84  // used screenpoint z for sorting, calculated from camera
86  public:
87  inline bool operator()(RenderItem* const & lhs, RenderItem* const & rhs) {
88  if (Mathd::Equal(lhs->screenpoint.z, rhs->screenpoint.z)) {
91  return liv->getStackPosition() < riv->getStackPosition();
92  }
93  return lhs->screenpoint.z < rhs->screenpoint.z;
94  }
95  };
96  // used instance location and camera rotation for sorting
98  public:
99  InstanceDistanceSortLocation(double rotation) {
100  if ((rotation >= 0) && (rotation <= 60)) { // 30 deg
101  xtox = 0;
102  xtoy = -1;
103  ytox = 1;
104  ytoy = 0.5;
105  } else if ((rotation >= 60) && (rotation <= 120)) { // 90 deg
106  xtox = -1;
107  xtoy = -1;
108  ytox = 0.5;
109  ytoy = -0.5;
110  } else if ((rotation >= 120) && (rotation <= 180)) { // 150 deg
111  xtox = 0;
112  xtoy = -1;
113  ytox = -1;
114  ytoy = -0.5;
115  } else if ((rotation >= 180) && (rotation <= 240)) { // 210 deg
116  xtox = 0;
117  xtoy = 1;
118  ytox = -1;
119  ytoy = -0.5;
120  } else if ((rotation >= 240) && (rotation <= 300)) { // 270 deg
121  xtox = 1;
122  xtoy = 1;
123  ytox = -0.5;
124  ytoy = 0.5;
125  } else if ((rotation >= 300) && (rotation <= 360)) { // 330 deg
126  xtox = 0;
127  xtoy = 1;
128  ytox = 1;
129  ytoy = 0.5;
130  }
131  }
132 
133  inline bool operator()(RenderItem* const & lhs, RenderItem* const & rhs) {
136  lpos.x += lpos.y / 2;
137  rpos.x += rpos.y / 2;
140  int32_t lvc = ceil(xtox*lpos.x + ytox*lpos.y) + ceil(xtoy*lpos.x + ytoy*lpos.y) + liv->getStackPosition();
141  int32_t rvc = ceil(xtox*rpos.x + ytox*rpos.y) + ceil(xtoy*rpos.x + ytoy*rpos.y) + riv->getStackPosition();
142  if (lvc == rvc) {
143  if (Mathd::Equal(lpos.z, rpos.z)) {
144  return liv->getStackPosition() < riv->getStackPosition();
145  }
146  return lpos.z < rpos.z;
147  }
148  return lvc < rvc;
149  }
150  private:
151  double xtox;
152  double xtoy;
153  double ytox;
154  double ytoy;
155  };
156  // used screenpoint z for sorting and as fallback first the instance location z and then the stack position
158  public:
159  inline bool operator()(RenderItem* const & lhs, RenderItem* const & rhs) {
160  if (Mathd::Equal(lhs->screenpoint.z, rhs->screenpoint.z)) {
163  if (Mathd::Equal(lpos.z, rpos.z)) {
166  return liv->getStackPosition() < riv->getStackPosition();
167  }
168  return lpos.z < rpos.z;
169  }
170  return lhs->screenpoint.z < rhs->screenpoint.z;
171  }
172  };
173 
175  m_camera = camera;
176  m_layer = 0;
177  m_layerObserver = 0;
178  m_tree = 0;
179  m_zMin = 0.0;
180  m_zMax = 0.0;
181  m_zoom = camera->getZoom();
182  m_zoomed = !Mathd::Equal(m_zoom, 1.0);
183  m_straightZoom = Mathd::Equal(fmod(m_zoom, 1.0), 0.0);
184 
185  if(RenderBackend::instance()->getName() == "OpenGL" && RenderBackend::instance()->isDepthBufferEnabled()) {
186  m_needSorting = false;
187  } else {
188  m_needSorting = true;
189  }
190  }
191 
193  // removes all Entries
194  for (std::vector<Entry*>::iterator it = m_entries.begin(); it != m_entries.end(); ++it) {
195  delete *it;
196  }
197  // removes all RenderItems
198  for (std::vector<RenderItem*>::iterator it = m_renderItems.begin(); it != m_renderItems.end(); ++it) {
199  delete *it;
200  }
201  m_layer->removeChangeListener(m_layerObserver);
202  delete m_layerObserver;
203  delete m_tree;
204  }
205 
207  if (m_layer != layer) {
208  if (m_layer) {
209  m_layer->removeChangeListener(m_layerObserver);
210  delete m_layerObserver;
211  }
212  m_layer = layer;
213  m_layerObserver = new CacheLayerChangeListener(this);
214  layer->addChangeListener(m_layerObserver);
215  reset();
216  }
217  }
218 
220  // removes all Entries
221  for (std::vector<Entry*>::iterator it = m_entries.begin(); it != m_entries.end(); ++it) {
222  delete *it;
223  }
224  m_entries.clear();
225  // removes all RenderItems
226  for (std::vector<RenderItem*>::iterator it = m_renderItems.begin(); it != m_renderItems.end(); ++it) {
227  delete *it;
228  }
229  m_renderItems.clear();
230  m_instance_map.clear();
231  m_entriesToUpdate.clear();
232  m_freeEntries.clear();
233  m_cacheImage.reset();
234 
235  delete m_tree;
236  m_tree = new CacheTree;
237  const std::vector<Instance*>& instances = m_layer->getInstances();
238  for(std::vector<Instance*>::const_iterator i = instances.begin();
239  i != instances.end(); ++i) {
240  addInstance(*i);
241  }
242  }
243 
245  assert(m_instance_map.find(instance) == m_instance_map.end());
246 
247  RenderItem* item;
248  Entry* entry;
249  if (m_freeEntries.empty()) {
250  // creates new RenderItem
251  item = new RenderItem(instance);
252  m_renderItems.push_back(item);
253  m_instance_map[instance] = m_renderItems.size() - 1;
254  // creates new Entry
255  entry = new Entry();
256  m_entries.push_back(entry);
257  entry->instanceIndex = m_renderItems.size() - 1;
258  entry->entryIndex = m_entries.size() - 1;
259  } else {
260  // uses free/unused RenderItem
261  int32_t index = m_freeEntries.front();
262  m_freeEntries.pop_front();
263  item = m_renderItems[index];
264  item->instance = instance;
265  m_instance_map[instance] = index;
266  // uses free/unused Entry
267  entry = m_entries[index];
268  entry->instanceIndex = index;
269  entry->entryIndex = index;
270  }
271 
272  entry->node = 0;
273  entry->forceUpdate = true;
274  entry->visible = true;
275  entry->updateInfo = EntryFullUpdate;
276 
277  m_entriesToUpdate.insert(entry->entryIndex);
278  }
279 
281  assert(m_instance_map.find(instance) != m_instance_map.end());
282 
283  Entry* entry = m_entries[m_instance_map[instance]];
284  assert(entry->instanceIndex == m_instance_map[instance]);
285  RenderItem* item = m_renderItems[entry->instanceIndex];
286  // removes entry from updates
287  std::set<int32_t>::iterator it = m_entriesToUpdate.find(entry->entryIndex);
288  if (it != m_entriesToUpdate.end()) {
289  m_entriesToUpdate.erase(it);
290  }
291  // removes entry from CacheTree
292  if (entry->node) {
293  entry->node->data().erase(entry->entryIndex);
294  entry->node = 0;
295  }
296  entry->instanceIndex = -1;
297  entry->forceUpdate = false;
298  m_instance_map.erase(instance);
299 
300  // removes instance from RenderList
301  RenderList& renderList = m_camera->getRenderListRef(m_layer);
302  for (RenderList::iterator it = renderList.begin(); it != renderList.end(); ++it) {
303  if ((*it)->instance == instance) {
304  renderList.erase(it);
305  break;
306  }
307  }
308  // resets RenderItem
309  item->reset();
310  // adds free entry
311  m_freeEntries.push_back(entry->entryIndex);
312  }
313 
315  Entry* entry = m_entries[m_instance_map[instance]];
316  if (entry->instanceIndex == -1) {
317  return;
318  }
319 
320  // convert necessary instance update flags to entry update flags
321  const InstanceChangeInfo ici = instance->getChangeInfo();
322  if ((ici & ICHANGE_LOC) == ICHANGE_LOC) {
323  entry->updateInfo |= EntryPositionUpdate;
324  }
325  if ((ici & ICHANGE_ROTATION) == ICHANGE_ROTATION ||
326  (ici & ICHANGE_ACTION) == ICHANGE_ACTION ||
327  (ici & ICHANGE_TRANSPARENCY) == ICHANGE_TRANSPARENCY ||
328  (ici & ICHANGE_VISIBLE) == ICHANGE_VISIBLE ||
329  (ici & ICHANGE_VISUAL) == ICHANGE_VISUAL) {
330  entry->updateInfo |= EntryVisualUpdate;
331  }
332 
333  // if entry is not already inserted
334  if (!entry->forceUpdate && entry->updateInfo != EntryNoneUpdate) {
335  entry->forceUpdate = true;
336  m_entriesToUpdate.insert(entry->entryIndex);
337  }
338  }
339 
341  std::vector<int32_t>& m_indices;
343  public:
344  CacheTreeCollector(std::vector<int32_t>& indices, const Rect& viewport)
345  : m_indices(indices), m_viewport(viewport) {
346  }
347  bool visit(LayerCache::CacheTree::Node* node, int32_t d = -1);
348  };
349 
351  if(!m_viewport.intersects(Rect(node->x(), node->y(),node->size(),node->size()))) {
352  return false;
353  }
354  m_indices.insert(m_indices.end(), node->data().begin(), node->data().end());
355  return true;
356  }
357 
358  void LayerCache::collect(const Rect& viewport, std::vector<int32_t>& index_list) {
359  CacheTree::Node * node = m_tree->find_container(viewport);
360  CacheTreeCollector collector(index_list, viewport);
361  node->apply_visitor(collector);
362  node = node->parent();
363  while(node) {
364  collector.visit(node);
365  node = node->parent();
366  }
367  }
368 
369  void LayerCache::update(Camera::Transform transform, RenderList& renderlist) {
370  // this is only a bit faster, but works without this block too.
371  if(!m_layer->areInstancesVisible()) {
372  FL_DBG(_log, "Layer instances hidden");
373  std::set<int32_t>::const_iterator entry_it = m_entriesToUpdate.begin();
374  for (; entry_it != m_entriesToUpdate.end(); ++entry_it) {
375  Entry* entry = m_entries[*entry_it];
376  entry->forceUpdate = false;
377  entry->visible = false;
378  }
379  m_entriesToUpdate.clear();
380  renderlist.clear();
381  return;
382  }
383  // if transform is none then we have only to update the instances with an update info.
384  if (transform == Camera::NoneTransform) {
385  if (!m_entriesToUpdate.empty()) {
386  std::set<int32_t> entryToRemove;
387  updateEntries(entryToRemove, renderlist);
388  //std::cout << "update entries: " << int32_t(m_entriesToUpdate.size()) << " remove entries: " << int32_t(entryToRemove.size()) <<"\n";
389  if (!entryToRemove.empty()) {
390  std::set<int32_t>::iterator entry_it = entryToRemove.begin();
391  for (; entry_it != entryToRemove.end(); ++entry_it) {
392  m_entriesToUpdate.erase(*entry_it);
393  }
394  }
395  }
396  } else {
397  m_zoom = m_camera->getZoom();
398  m_zoomed = !Mathd::Equal(m_zoom, 1.0);
399  m_straightZoom = Mathd::Equal(fmod(m_zoom, 1.0), 0.0);
400  // clear old renderlist
401  renderlist.clear();
402  // update all entries
403  if ((transform & Camera::RotationTransform) == Camera::RotationTransform ||
404  (transform & Camera::TiltTransform) == Camera::TiltTransform ||
405  (transform & Camera::ZTransform) == Camera::ZTransform) {
406  fullUpdate(transform);
407  } else {
408  fullCoordinateUpdate(transform);
409  }
410 
411  // create viewport coordinates to collect entries
412  Rect viewport = m_camera->getViewPort();
413  Rect screenViewport = viewport;
414  DoublePoint3D viewport_a = m_camera->screenToVirtualScreen(Point3D(viewport.x, viewport.y));
415  DoublePoint3D viewport_b = m_camera->screenToVirtualScreen(Point3D(viewport.right(), viewport.bottom()));
416  viewport.x = static_cast<int32_t>(std::min(viewport_a.x, viewport_b.x));
417  viewport.y = static_cast<int32_t>(std::min(viewport_a.y, viewport_b.y));
418  viewport.w = static_cast<int32_t>(std::max(viewport_a.x, viewport_b.x) - viewport.x);
419  viewport.h = static_cast<int32_t>(std::max(viewport_a.y, viewport_b.y) - viewport.y);
420  m_zMin = 0.0;
421  m_zMax = 0.0;
422 
423  // FL_LOG(_log, LMsg("camera-update viewport") << viewport);
424  std::vector<int32_t> index_list;
425  collect(viewport, index_list);
426  // fill renderlist
427  for (uint32_t i = 0; i != index_list.size(); ++i) {
428  Entry* entry = m_entries[index_list[i]];
429  RenderItem* item = m_renderItems[entry->instanceIndex];
430  if (!item->image || !entry->visible) {
431  continue;
432  }
433 
434  if (item->dimensions.intersects(screenViewport)) {
435  renderlist.push_back(item);
436  }
437  }
438 
439  if (m_needSorting) {
440  sortRenderList(renderlist);
441  } else {
442  // calculates zmin and zmax of the current viewport
443  Rect r = m_camera->getMapViewPort();
444  std::vector<ExactModelCoordinate> coords;
445  coords.push_back(ExactModelCoordinate(r.x, r.y));
446  coords.push_back(ExactModelCoordinate(r.x, r.y+r.h));
447  coords.push_back(ExactModelCoordinate(r.x+r.w, r.y));
448  coords.push_back(ExactModelCoordinate(r.x+r.w, r.y+r.h));
449  for (uint8_t i = 0; i < 4; ++i) {
450  double z = m_camera->toVirtualScreenCoordinates(coords[i]).z;
451  m_zMin = std::min(z, m_zMin);
452  m_zMax = std::max(z, m_zMax);
453  }
454 
455  sortRenderList(renderlist);
456  }
457  }
458  }
459 
461  bool rotationChange = (transform & Camera::RotationTransform) == Camera::RotationTransform;
462  for (uint32_t i = 0; i != m_entries.size(); ++i) {
463  Entry* entry = m_entries[i];
464  if (entry->instanceIndex != -1) {
465  if (rotationChange || entry->forceUpdate) {
466  bool force = entry->forceUpdate;
467  updateVisual(entry);
468  if (force && !entry->forceUpdate) {
469  // no action
470  entry->updateInfo = EntryNoneUpdate;
471  m_entriesToUpdate.erase(entry->entryIndex);
472  } else if (!force && entry->forceUpdate) {
473  // new action
474  entry->updateInfo |= EntryVisualUpdate;
475  m_entriesToUpdate.insert(entry->entryIndex);
476  }
477  }
478  updatePosition(entry);
479  }
480  }
481  }
482 
484  bool zoomChange = (transform & Camera::ZoomTransform) == Camera::ZoomTransform;
485  for (uint32_t i = 0; i != m_entries.size(); ++i) {
486  Entry* entry = m_entries[i];
487  if (entry->instanceIndex != -1) {
488  if (entry->forceUpdate) {
489  updateVisual(entry);
490  updatePosition(entry);
491  if (!entry->forceUpdate) {
492  // no action
493  entry->updateInfo = EntryNoneUpdate;
494  m_entriesToUpdate.erase(entry->entryIndex);
495  }
496  continue;
497  }
498  updateScreenCoordinate(m_renderItems[entry->instanceIndex], zoomChange);
499  }
500  }
501  }
502 
503  void LayerCache::updateEntries(std::set<int32_t>& removes, RenderList& renderlist) {
504  RenderList needSorting;
505  Rect viewport = m_camera->getViewPort();
506  std::set<int32_t>::const_iterator entry_it = m_entriesToUpdate.begin();
507  for (; entry_it != m_entriesToUpdate.end(); ++entry_it) {
508  Entry* entry = m_entries[*entry_it];
509  entry->forceUpdate = false;
510  if (entry->instanceIndex == -1) {
511  entry->updateInfo = EntryNoneUpdate;
512  removes.insert(*entry_it);
513  continue;
514  }
515  RenderItem* item = m_renderItems[entry->instanceIndex];
516  bool onScreenA = entry->visible && item->image && item->dimensions.intersects(viewport);
517  bool positionUpdate = (entry->updateInfo & EntryPositionUpdate) == EntryPositionUpdate;
518  if ((entry->updateInfo & EntryVisualUpdate) == EntryVisualUpdate) {
519  positionUpdate |= updateVisual(entry);
520  }
521  if (positionUpdate) {
522  updatePosition(entry);
523  }
524  bool onScreenB = entry->visible && item->image && item->dimensions.intersects(viewport);
525  if (onScreenA != onScreenB) {
526  if (!onScreenA) {
527  // add to renderlist and sort
528  renderlist.push_back(item);
529  needSorting.push_back(item);
530  } else {
531  // remove from renderlist
532  for (RenderList::iterator it = renderlist.begin(); it != renderlist.end(); ++it) {
533  if ((*it)->instance == item->instance) {
534  renderlist.erase(it);
535  break;
536  }
537  }
538  }
539  } else if (onScreenA && onScreenB && positionUpdate) {
540  // sort
541  needSorting.push_back(item);
542  }
543 
544  if (!entry->forceUpdate) {
545  entry->forceUpdate = false;
546  entry->updateInfo = EntryNoneUpdate;
547  removes.insert(*entry_it);
548  } else {
549  entry->updateInfo = EntryVisualUpdate;
550  }
551  }
552 
553  if (!needSorting.empty()) {
554  if (m_needSorting) {
555  sortRenderList(renderlist);
556  } else {
557  sortRenderList(needSorting);
558  }
559  }
560  }
561 
563  RenderItem* item = m_renderItems[entry->instanceIndex];
564  Instance* instance = item->instance;
565  InstanceVisual* visual = instance->getVisual<InstanceVisual>();
566  item->facingAngle = instance->getRotation();
567  int32_t angle = static_cast<int32_t>(m_camera->getRotation()) + item->facingAngle;
568  Action* action = instance->getCurrentAction();
569  ImagePtr image;
570 
571  if (visual) {
572  uint8_t layerTrans = m_layer->getLayerTransparency();
573  uint8_t instanceTrans = visual->getTransparency();
574  if (layerTrans != 0) {
575  if (instanceTrans != 0) {
576  uint8_t calcTrans = layerTrans - instanceTrans;
577  if (calcTrans >= 0) {
578  instanceTrans = calcTrans;
579  } else {
580  instanceTrans = 0;
581  }
582  } else {
583  instanceTrans = layerTrans;
584  }
585  }
586  item->transparency = 255 - instanceTrans;
587  // only visible if visual and layer are visible and item is not totally transparent
588  entry->visible = (visual->isVisible() && item->transparency != 0) && m_layer->areInstancesVisible();
589  }
590  // delete old overlay
591  item->deleteOverlayData();
592 
593  if (!action) {
594  // Try static images then default action.
595  int32_t image_id = item->getStaticImageIndexByAngle(angle, instance);
596  if (image_id == -1) {
597  if (!instance->getObject()->isStatic()) {
598  action = instance->getObject()->getDefaultAction();
599  }
600  } else {
601  image = ImageManager::instance()->get(image_id);
602  }
603  }
604  entry->forceUpdate = (action != 0);
605 
606  if (action) {
607  ActionVisual* actionVisual = action->getVisual<ActionVisual>();
608  bool colorOverlay = actionVisual->isColorOverlay();
609  // assumed all have the same size
610  if (actionVisual->isAnimationOverlay()) {
611  std::map<int32_t, AnimationPtr> animations = actionVisual->getAnimationOverlay(angle);
612  std::map<int32_t, AnimationPtr>::iterator it = animations.begin();
613  std::vector<ImagePtr>* animOverlays = new std::vector<ImagePtr>();
614  std::vector<OverlayColors*>* animationColorOverlays = colorOverlay ? new std::vector<OverlayColors*>() : 0;
615  for (; it != animations.end(); ++it) {
616  uint32_t animationTime = instance->getActionRuntime() % it->second->getDuration();
617  image = it->second->getFrameByTimestamp(animationTime);
618  animOverlays->push_back(image);
619 
620  if (colorOverlay) {
621  OverlayColors* co = actionVisual->getColorOverlay(angle, it->first);
622  if (co) {
623  AnimationPtr ovAnim = co->getColorOverlayAnimation();
624  animationTime = instance->getActionRuntime() % ovAnim->getDuration();
625  co->setColorOverlayImage(ovAnim->getFrameByTimestamp(animationTime));
626  }
627  animationColorOverlays->push_back(co);
628  }
629  // works only for one animation
630  int32_t actionFrame = it->second->getActionFrame();
631  if (actionFrame != -1) {
632  int32_t newFrame = it->second->getFrameIndex(animationTime);
633  if (item->currentFrame != newFrame) {
634  if (actionFrame == newFrame) {
635  instance->callOnActionFrame(action, actionFrame);
636  // if action frame was skipped
637  } else if (newFrame > actionFrame && item->currentFrame < actionFrame) {
638  instance->callOnActionFrame(action, actionFrame);
639  }
640  item->currentFrame = newFrame;
641  }
642  }
643  }
644  // transfer ownership of the vectors to RenderItem
645  item->setAnimationOverlay(animOverlays, animationColorOverlays);
646  } else {
647  AnimationPtr animation = action->getVisual<ActionVisual>()->getAnimationByAngle(angle);
648  uint32_t animationTime = instance->getActionRuntime() % animation->getDuration();
649  image = animation->getFrameByTimestamp(animationTime);
650  // if the action have an animation with only one frame (idle animation) then
651  // a forced update is not necessary.
652  if (animation->getFrameCount() <= 1) {
653  entry->forceUpdate = false;
654  }
655  if (colorOverlay) {
656  OverlayColors* co = actionVisual->getColorOverlay(angle);
657  if (co) {
658  AnimationPtr ovAnim = co->getColorOverlayAnimation();
659  animationTime = instance->getActionRuntime() % ovAnim->getDuration();
660  co->setColorOverlayImage(ovAnim->getFrameByTimestamp(animationTime));
661  item->setColorOverlay(co);
662  }
663  }
664  int32_t actionFrame = animation->getActionFrame();
665  if (actionFrame != -1) {
666  if (item->image != image) {
667  int32_t newFrame = animation->getFrameIndex(animationTime);
668  if (actionFrame == newFrame) {
669  instance->callOnActionFrame(action, actionFrame);
670  // if action frame was skipped
671  } else if (newFrame > actionFrame && item->currentFrame < actionFrame) {
672  instance->callOnActionFrame(action, actionFrame);
673  }
674  item->currentFrame = newFrame;
675  }
676  }
677  }
678  }
679 
680  bool newPosition = false;
681  if (image != item->image) {
682  if (!item->image || !image) {
683  newPosition = true;
684  } else if (image->getWidth() != item->image->getWidth() ||
685  image->getHeight() != item->image->getHeight() ||
686  image->getXShift() != item->image->getXShift() ||
687  image->getYShift() != item->image->getYShift()) {
688  newPosition = true;
689  }
690  item->image = image;
691  }
692  return newPosition;
693  }
694 
696  RenderItem* item = m_renderItems[entry->instanceIndex];
697  Instance* instance = item->instance;
698  ExactModelCoordinate mapCoords = instance->getLocationRef().getMapCoordinates();
699  DoublePoint3D screenPosition = m_camera->toVirtualScreenCoordinates(mapCoords);
700  ImagePtr image = item->image;
701 
702  if (image) {
703  int32_t w = image->getWidth();
704  int32_t h = image->getHeight();
705  screenPosition.x = (screenPosition.x - w / 2) + image->getXShift();
706  screenPosition.y = (screenPosition.y - h / 2) + image->getYShift();
707  item->bbox.w = w;
708  item->bbox.h = h;
709  } else {
710  item->bbox.w = 0;
711  item->bbox.h = 0;
712  }
713  item->screenpoint = screenPosition;
714  item->bbox.x = static_cast<int32_t>(screenPosition.x);
715  item->bbox.y = static_cast<int32_t>(screenPosition.y);
716 
717  updateScreenCoordinate(item);
718 
719  CacheTree::Node* node = m_tree->find_container(item->bbox);
720  if (node) {
721  if (node != entry->node) {
722  if (entry->node) {
723  entry->node->data().erase(entry->entryIndex);
724  }
725  entry->node = node;
726  node->data().insert(entry->entryIndex);
727  }
728  }
729  }
730 
731  inline void LayerCache::updateScreenCoordinate(RenderItem* item, bool changedZoom) {
732  Point3D screenPoint = m_camera->virtualScreenToScreen(item->screenpoint);
733  // NOTE:
734  // One would expect this to be necessary here,
735  // however it works the same without, sofar
736  // m_camera->calculateZValue(screenPoint);
737  // item->screenpoint.z = -screenPoint.z;
738  item->dimensions.x = screenPoint.x;
739  item->dimensions.y = screenPoint.y;
740 
741  if (changedZoom) {
742  if (m_zoomed) {
743  item->dimensions.w = round(static_cast<double>(item->bbox.w) * m_zoom);
744  item->dimensions.h = round(static_cast<double>(item->bbox.h) * m_zoom);
745  } else {
746  item->dimensions.w = item->bbox.w;
747  item->dimensions.h = item->bbox.h;
748  }
749  }
750  }
751 
753  if (renderlist.empty()) {
754  return;
755  }
756  // We want to put every z value in layer z range.
757  // To do it, we simply solve
758  // { y1 = a*x1 + b
759  // { y2 = a*x2 + b
760  // where [y1,y2]' = layer z offset min/max is required z range,
761  // and [x1,x2]' is expected min,max z coords.
762 
763  // more an workaround, because z values are wrong in case of inverted top with bottom
764  if (!m_needSorting && !m_layer->isStatic()) {
765  //if (!m_needSorting) {
766  float det = m_zMin - m_zMax;
767  if (fabs(det) > FLT_EPSILON) {
768  static const float globalrange = 200.0;
769  static const float stackdelta = (FLT_EPSILON * 100.0);
770  int32_t numlayers = m_layer->getLayerCount();
771  float lmin = m_layer->getZOffset();
772  float lmax = lmin + globalrange/numlayers;
773  float a = (lmin - lmax) / det;
774  float b = (lmax * m_zMin - lmin * m_zMax) / det;
775 
776  RenderList::iterator it = renderlist.begin();
777  for ( ; it != renderlist.end(); ++it) {
778  InstanceVisual* vis = (*it)->instance->getVisual<InstanceVisual>();
779  float& z = (*it)->vertexZ;
780  z = (a * (*it)->screenpoint.z + b) + vis->getStackPosition() * stackdelta;
781  }
782  }
783  } else {
784  SortingStrategy strat = m_layer->getSortingStrategy();
785  switch (strat) {
786  case SORTING_CAMERA: {
788  std::stable_sort(renderlist.begin(), renderlist.end(), ids);
789  } break;
790  case SORTING_LOCATION: {
791  InstanceDistanceSortLocation ids(m_camera->getRotation());
792  std::stable_sort(renderlist.begin(), renderlist.end(), ids);
793  } break;
796  std::stable_sort(renderlist.begin(), renderlist.end(), ids);
797  } break;
798  default: {
800  std::stable_sort(renderlist.begin(), renderlist.end(), ids);
801  } break;
802  }
803  }
804  }
805 
807  return m_cacheImage;
808  }
809 
811  m_cacheImage = image;
812  }
813 }
bool visible
Definition: layercache.h:86
void setColorOverlay(OverlayColors *co)
Sets single ColorOverlay.
Definition: renderitem.cpp:115
bool operator()(RenderItem *const &lhs, RenderItem *const &rhs)
Definition: layercache.cpp:87
void fullUpdate(Camera::Transform transform)
Definition: layercache.cpp:460
std::vector< RenderItem * > RenderList
Definition: renderitem.h:130
void updatePosition(Entry *entry)
Definition: layercache.cpp:695
void setLayer(Layer *layer)
Definition: layercache.cpp:206
QuadNode * parent()
Return the parent node.
Definition: quadtree.h:133
int32_t getStaticImageIndexByAngle(uint32_t angle, Instance *instance)
Returns closest matching static image for given angle.
Definition: renderitem.cpp:69
int32_t getStackPosition()
Gets current stack position of instance.
Definition: visual.cpp:221
T h
Height of the rectangle.
Definition: rect.h:93
void fullCoordinateUpdate(Camera::Transform transform)
Definition: layercache.cpp:483
virtual ImagePtr get(const std::string &name)
Gets a shared pointer to the Image.
Instance visual contains data that is needed to visualize the instance on screen. ...
Definition: visual.h:158
void callOnActionFrame(Action *action, int32_t frame)
Auxiliary function to inform ActionListeners about the active ActionFrame.
Definition: instance.cpp:389
int32_t getXShift() const
Definition: image.h:122
T x
The X Coordinate.
Definition: rect.h:84
void updateScreenCoordinate(RenderItem *item, bool changedZoom=true)
Definition: layercache.cpp:731
DoublePoint3D screenpoint
Definition: renderitem.h:100
Action visual contains data that is needed to visualize different actions on screen.
Definition: visual.h:212
bool isStatic() const
Gets if object moves.
Definition: object.cpp:240
Instance * instance
Definition: renderitem.h:58
uint32_t getDuration() const
Gets the total duration for the whole animation.
Definition: animation.h:138
InstanceChangeInfo getChangeInfo()
Returns a bitmask of changes of the last update.
Definition: instance.cpp:969
int32_t facingAngle
Definition: renderitem.h:115
T * getVisual() const
Gets used visualization.
Definition: instance.h:349
void deleteOverlayData()
Deletes OverlayData.
Definition: renderitem.cpp:129
int32_t getYShift() const
Definition: image.h:128
static Logger _log(LM_AUDIO)
PointType3D< int32_t > Point3D
Definition: point.h:328
DataType & data()
Return a reference to the data of the node.
Definition: quadtree.h:116
uint32_t getActionRuntime()
Gets the time in milliseconds how long action has been active In case there is no current action...
Definition: instance.cpp:931
bool operator()(RenderItem *const &lhs, RenderItem *const &rhs)
Definition: layercache.cpp:159
Action * getCurrentAction() const
Gets the currently active action.
Definition: instance.cpp:888
virtual void onInstanceCreate(Layer *layer, Instance *instance)
Called when some instance gets created on layer.
Definition: layercache.cpp:71
Camera describes properties of a view port shown in the main screen Main screen can have multiple cam...
Definition: camera.h:59
int32_t entryIndex
Definition: layercache.h:82
static RenderBackend * instance()
Definition: singleton.h:84
Location & getLocationRef()
Gets reference of current location of instance.
Definition: instance.cpp:318
void apply_visitor(Visitor &visitor, int32_t d=0)
Apply a visitor recursively to the QuadTree A visitor is an object which has a visit method which tak...
Definition: quadtree.h:93
void sortRenderList(RenderList &renderlist)
Definition: layercache.cpp:752
void setAnimationOverlay(std::vector< ImagePtr > *ao, std::vector< OverlayColors * > *aco)
Sets AnimationOverlay and if available AnimationOverlayColors.
Definition: renderitem.cpp:93
virtual void onLayerChanged(Layer *layer, std::vector< Instance * > &instances)
Called when some instance is changed on layer.
Definition: layercache.cpp:64
RenderEntryUpdate updateInfo
Definition: layercache.h:88
int32_t getActionFrame() const
Gets the action frame.
Definition: animation.h:119
uint32_t getHeight() const
Definition: image.cpp:160
OverlayColors * getColorOverlay(int32_t angle)
Gets OverlayColors for given angle (degrees).
Definition: visual.cpp:291
unsigned char uint8_t
Definition: core.h:38
bool isVisible()
Is instance visible or not.
Definition: visual.cpp:210
Comparison functions for sorting.
Definition: layercache.cpp:85
void setColorOverlayImage(ImagePtr image)
Definition: visual.cpp:60
ImagePtr getFrameByTimestamp(uint32_t timestamp)
Gets the frame image that matches the given timestamp.
Definition: animation.cpp:150
T bottom() const
The Y coordinate of the bottom edge.
Definition: rect.h:173
static bool Equal(T _val1, T _val2)
Definition: fife_math.h:287
Definition: layercache.h:76
Object * getObject()
Gets object where this instance is instantiated from.
Definition: instance.cpp:295
uint32_t InstanceChangeInfo
Definition: instance.h:77
Dynamic QuadTree A space partitioning tree automatically expanding to adjust to any object size put i...
Definition: quadtree.h:150
ImagePtr getCacheImage()
Definition: layercache.cpp:806
int32_t getRotation() const
Get the rotation offset of this instance Returns direction where instance is heading.
Definition: instance.cpp:333
A basic layer on a map.
Definition: layer.h:99
uint32_t getFrameCount() const
Get the number of frames.
Definition: animation.cpp:178
double getZoom() const
Gets camera zoom.
Definition: camera.cpp:172
CacheTreeCollector(std::vector< int32_t > &indices, const Rect &viewport)
Definition: layercache.cpp:344
Listener interface for changes happening on a layer.
Definition: layer.h:71
int32_t getFrameIndex(uint32_t timestamp)
Get the frame index that matches given timestamp.
Definition: animation.cpp:124
SortingStrategy
Definition: layer.h:63
void addChangeListener(LayerChangeListener *listener)
Adds new change listener.
Definition: layer.cpp:628
void setCacheImage(ImagePtr image)
Definition: layercache.cpp:810
bool forceUpdate
Definition: layercache.h:84
ExactModelCoordinate & getExactLayerCoordinatesRef()
Gets reference to exact layer coordinates.
Definition: location.cpp:105
uint32_t getWidth() const
Definition: image.cpp:151
T y
The Y Coordinate.
Definition: rect.h:87
CacheLayerChangeListener(LayerCache *cache)
Definition: layercache.cpp:59
virtual void onInstanceDelete(Layer *layer, Instance *instance)
Called when some instance gets deleted on layer.
Definition: layercache.cpp:75
void collect(const Rect &viewport, std::vector< int32_t > &indices)
Definition: layercache.cpp:358
std::vector< int32_t > & m_indices
Definition: layercache.cpp:341
QuadTree Node.
Definition: quadtree.h:41
int32_t instanceIndex
Definition: layercache.h:80
T right() const
The X coordinate of the right edge.
Definition: rect.h:168
DoublePoint3D ExactModelCoordinate
Definition: modelcoords.h:37
bool intersects(const RectType< T > &rect) const
Check whether two rectangles share some area.
Definition: rect.h:227
uint32_t Transform
Definition: camera.h:69
ImagePtr image
Definition: renderitem.h:112
bool visit(LayerCache::CacheTree::Node *node, int32_t d=-1)
Definition: layercache.cpp:350
LayerCache(Camera *camera)
Definition: layercache.cpp:174
uint8_t getTransparency()
Gets current transparency value (0-255)
Definition: visual.cpp:199
bool operator()(RenderItem *const &lhs, RenderItem *const &rhs)
Definition: layercache.cpp:133
int32_t y() const
Return the Y position of the node.
Definition: quadtree.h:108
CacheTree::Node * node
Definition: layercache.h:78
void update(Camera::Transform transform, RenderList &renderlist)
Definition: layercache.cpp:369
void removeInstance(Instance *instance)
Definition: layercache.cpp:280
InstanceDistanceSortLocation(double rotation)
Definition: layercache.cpp:99
void updateEntries(std::set< int32_t > &removes, RenderList &renderlist)
Definition: layercache.cpp:503
AnimationPtr getColorOverlayAnimation()
Definition: visual.cpp:72
void addInstance(Instance *instance)
Definition: layercache.cpp:244
int32_t size() const
Return the size (width and height) of the node.
Definition: quadtree.h:112
QuadNode * find_container(int32_t x, int32_t y, int32_t w, int32_t h)
Find a container node for a given rectangle.
Definition: quadtree.h:254
unsigned int uint32_t
Definition: core.h:40
int32_t x() const
Return the X position of the node.
Definition: quadtree.h:104
Action * getDefaultAction() const
Gets default action assigned to this object.
Definition: object.cpp:178
bool updateVisual(Entry *entry)
Definition: layercache.cpp:562
ExactModelCoordinate getExactLayerCoordinates() const
Gets exact layer coordinates set to this location.
Definition: location.cpp:109
uint8_t transparency
Definition: renderitem.h:118
T w
Width of the rectangle.
Definition: rect.h:90
#define FL_DBG(logger, msg)
Definition: logger.h:70
An Instance is an "instantiation" of an Object at a Location.
Definition: instance.h:101
std::map< int32_t, AnimationPtr > getAnimationOverlay(int32_t angle)
Gets map with animations closest to given angle.
Definition: visual.cpp:256
ExactModelCoordinate getMapCoordinates() const
Gets map coordinates set to this location.
Definition: location.cpp:117
bool isAnimationOverlay()
Returns true if it exists a animation overlay, otherwise false.
Definition: visual.h:284
void reset()
Resets the important values.
Definition: renderitem.cpp:136
bool isColorOverlay()
Returns true if it exists a color overlay, otherwise false.
Definition: visual.h:288
void updateInstance(Instance *instance)
Definition: layercache.cpp:314
int32_t currentFrame
Definition: renderitem.h:121