layercache.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <SDL.h>
00026
00027
00028
00029
00030
00031
00032 #include "model/metamodel/grids/cellgrid.h"
00033 #include "model/metamodel/action.h"
00034 #include "model/structures/layer.h"
00035 #include "model/structures/instance.h"
00036 #include "model/structures/location.h"
00037 #include "util/base/exception.h"
00038 #include "util/log/logger.h"
00039 #include "util/math/fife_math.h"
00040 #include "util/math/angles.h"
00041 #include "video/renderbackend.h"
00042 #include "video/image.h"
00043 #include "video/imagepool.h"
00044 #include "video/animation.h"
00045 #include "video/animationpool.h"
00046
00047 #include "camera.h"
00048 #include "layercache.h"
00049 #include "visual.h"
00050
00051
00052 namespace FIFE {
00053 static Logger _log(LM_CAMERA);
00054
00055 class CacheLayerChangeListener : public LayerChangeListener {
00056 public:
00057 CacheLayerChangeListener(LayerCache* cache)
00058 {
00059 m_cache = cache;
00060 }
00061 virtual ~CacheLayerChangeListener() {};
00062
00063 virtual void onLayerChanged(Layer* layer, std::vector<Instance*>& instances)
00064 {
00065 for(std::vector<Instance*>::iterator i = instances.begin();
00066 i != instances.end(); ++i) {
00067 m_cache->updateInstance(*i);
00068 }
00069 }
00070
00071 virtual void onInstanceCreate(Layer* layer, Instance* instance)
00072 {
00073 m_cache->addInstance(instance);
00074 }
00075
00076 virtual void onInstanceDelete(Layer* layer, Instance* instance)
00077 {
00078 m_cache->removeInstance(instance);
00079 }
00080 private:
00081 LayerCache* m_cache;
00082 };
00083
00084 LayerCache::LayerCache(Camera* camera, ImagePool* image_pool, AnimationPool* animation_pool) {
00085 m_camera = camera;
00086 m_image_pool = image_pool;
00087 m_animation_pool = animation_pool;
00088 m_layer = 0;
00089 m_tree = 0;
00090 }
00091
00092 LayerCache::~LayerCache() {
00093 m_layer->removeChangeListener(m_layer_observer);
00094 delete m_layer_observer;
00095 delete m_tree;
00096 }
00097
00098 void LayerCache::setLayer(Layer* layer) {
00099 m_layer = layer;
00100 m_layer_observer = new CacheLayerChangeListener(this);
00101 layer->addChangeListener(m_layer_observer);
00102 reset();
00103 }
00104
00105 void LayerCache::reset() {
00106 m_instances.clear();
00107 delete m_tree;
00108 m_tree = new CacheTree;
00109 const std::vector<Instance*>& instances = m_layer->getInstances();
00110 for(std::vector<Instance*>::const_iterator i = instances.begin();
00111 i != instances.end(); ++i) {
00112 addInstance(*i);
00113 }
00114 }
00115
00116 void LayerCache::addInstance(Instance* instance) {
00117 if(m_instance_map.find(instance)!=m_instance_map.end()) {
00118 throw new Duplicate(instance->getId());
00119 }
00120
00121 RenderItem item;
00122 Entry entry;
00123 item.instance = instance;
00124 m_instances.push_back(item);
00125 m_instance_map[instance] = m_instances.size() - 1;
00126
00127 entry.node = 0;
00128 entry.instance_index = m_instances.size() - 1;
00129 entry.entry_index = m_entries.size();
00130 m_entries.push_back(entry);
00131 updateEntry(m_entries.back());
00132 }
00133
00134 void LayerCache::removeInstance(Instance* instance) {
00135
00136
00137
00138
00139
00140
00141 if(m_instance_map.find(instance) == m_instance_map.end()) {
00142 throw new NotFound(instance->getId());
00143 }
00144 Entry& item = m_entries[m_instance_map[instance]];
00145 assert(item.instance_index == m_instance_map[instance]);
00146
00147 if(item.node)
00148 item.node->data().erase(item.entry_index);
00149 item.node = 0;
00150 item.instance_index = unsigned(-1);
00151 m_instance_map.erase(instance);
00152 }
00153
00154 void LayerCache::updateInstance(Instance* instance) {
00155 Entry& entry = m_entries[m_instance_map[instance]];
00156 updateEntry(entry);
00157 }
00158
00159 void LayerCache::updateEntry(LayerCache::Entry& item) {
00160 if(item.instance_index == unsigned(-1)) {
00161 return;
00162 }
00163 if(item.node) {
00164 item.node->data().erase(item.entry_index);
00165 }
00166 RenderItem& render_item = m_instances[item.instance_index];
00167 Instance* instance = render_item.instance;
00168
00169 DoublePoint3D screen_position = m_camera->toVirtualScreenCoordinates(instance->getLocationRef().getMapCoordinates());
00170
00171 render_item.facing_angle = getAngleBetween(instance->getLocationRef(), instance->getFacingLocation());
00172 int angle = m_camera->getRotation() + render_item.facing_angle + instance->getRotation();
00173
00174 Image* image = NULL;
00175 Action* action = instance->getCurrentAction();
00176 int w = 0;
00177 int h = 0;
00178 int xshift = 0;
00179 int yshift = 0;
00180
00181 if(!action) {
00182
00183 int image_id = render_item.getStaticImageIndexByAngle(angle, instance);
00184 if(image_id == Pool::INVALID_ID) {
00185 action = instance->getObject()->getDefaultAction();
00186 } else {
00187 image = &m_image_pool->getImage(image_id);
00188 }
00189 }
00190 item.force_update = bool(action);
00191
00192 if(action) {
00193 int animation_id = action->getVisual<ActionVisual>()->getAnimationIndexByAngle(render_item.facing_angle + m_camera->getRotation());
00194 Animation& animation = m_animation_pool->getAnimation(animation_id);
00195 unsigned animation_time = instance->getActionRuntime() % animation.getDuration();
00196 image = animation.getFrameByTimestamp(animation_time);
00197
00198 int facing_angle = render_item.facing_angle;
00199 if (facing_angle < 0){
00200 facing_angle += 360;
00201 }
00202 instance->setRotation(facing_angle);
00203 }
00204
00205 if (image) {
00206 w = image->getWidth();
00207 h = image->getHeight();
00208 xshift = image->getXShift();
00209 yshift = image->getYShift();
00210 }
00211
00212 screen_position.x -= w / 2;
00213 screen_position.x += xshift;
00214 screen_position.y -= h / 2;
00215 screen_position.y += yshift;
00216
00217 render_item.image = image;
00218 render_item.screenpoint = screen_position;
00219
00220 render_item.bbox.x = screen_position.x;
00221 render_item.bbox.y = screen_position.y;
00222 render_item.bbox.w = w;
00223 render_item.bbox.h = h;
00224
00225 render_item.dimensions.x = screen_position.x;
00226 render_item.dimensions.y = screen_position.y;
00227 render_item.dimensions.w = w;
00228 render_item.dimensions.h = h;
00229
00230 CacheTree::Node* node = m_tree->find_container(render_item.bbox);
00231 item.node = node;
00232 node->data().insert(item.entry_index);
00233 }
00234
00235 class CacheTreeCollector {
00236 std::vector<int>& m_indices;
00237 Rect m_viewport;
00238 public:
00239 CacheTreeCollector(std::vector<int>& indices, const Rect& _viewport)
00240 : m_indices(indices), m_viewport(_viewport) {
00241 }
00242 bool visit(LayerCache::CacheTree::Node* node, int d = -1);
00243 };
00244
00245 bool CacheTreeCollector::visit(LayerCache::CacheTree::Node* node, int d) {
00246 if(!m_viewport.intersects(Rect(node->x(), node->y(),node->size(),node->size())))
00247 return false;
00248 std::set<int>& list = node->data();
00249 for(std::set<int>::iterator i = list.begin(); i!=list.end();++i) {
00250 m_indices.push_back(*i);
00251 }
00252 return true;
00253 }
00254
00255 void LayerCache::collect(const Rect& viewport, std::vector<int>& index_list) {
00256 CacheTree::Node * node = m_tree->find_container(viewport);
00257 CacheTreeCollector collector(index_list, viewport);
00258 node->apply_visitor(collector);
00259 node = node->parent();
00260 while(node) {
00261 collector.visit(node);
00262 node = node->parent();
00263 }
00264 }
00265
00266 void LayerCache::fullUpdate() {
00267 for(unsigned i=0; i!=m_entries.size(); ++i)
00268 updateEntry(m_entries[i]);
00269 }
00270
00271 class InstanceDistanceSort {
00272 public:
00273 inline bool operator()(RenderItem* const & lhs, RenderItem* const & rhs) {
00274 if (lhs->screenpoint.z == rhs->screenpoint.z) {
00275 InstanceVisual* liv = lhs->instance->getVisual<InstanceVisual>();
00276 InstanceVisual* riv = rhs->instance->getVisual<InstanceVisual>();
00277 return liv->getStackPosition() < riv->getStackPosition();
00278 }
00279 return lhs->screenpoint.z < rhs->screenpoint.z;
00280 }
00281 };
00282
00283 void LayerCache::update(Camera::Transform transform, RenderList& renderlist) {
00284 const double OVERDRAW = 2.5;
00285 renderlist.clear();
00286 if(!m_layer->areInstancesVisible()) {
00287 FL_DBG(_log, "Layer instances hidden");
00288 return;
00289 }
00290 bool isWarped = transform == Camera::WarpedTransform;
00291 if( isWarped )
00292 fullUpdate();
00293
00294 Rect viewport = m_camera->getViewPort();
00295 Rect screen_viewport = viewport;
00296 float zoom = m_camera->getZoom();
00297 DoublePoint3D viewport_a = m_camera->screenToVirtualScreen(Point3D(viewport.x, viewport.y));
00298 DoublePoint3D viewport_b = m_camera->screenToVirtualScreen(Point3D(viewport.right(), viewport.bottom()));
00299 viewport.x = std::min(viewport_a.x, viewport_b.x);
00300 viewport.y = std::min(viewport_a.y, viewport_b.y);
00301 viewport.w = std::max(viewport_a.x, viewport_b.x) - viewport.x;
00302 viewport.h = std::max(viewport_a.y, viewport_b.y) - viewport.y;
00303 unsigned char layer_trans = m_layer->getLayerTransparency();
00304
00305
00306 std::vector<int> index_list;
00307 collect(viewport, index_list);
00308 for(unsigned i=0; i!=index_list.size();++i) {
00309 Entry& entry = m_entries[index_list[i]];
00310
00311
00312
00313
00314
00315 if(entry.force_update)
00316 updateEntry(entry);
00317
00318 RenderItem& item = m_instances[entry.instance_index];
00319 InstanceVisual* visual = item.instance->getVisual<InstanceVisual>();
00320 bool visible = visual->isVisible();
00321 unsigned char instance_trans = visual->getTransparency();
00322 if(!item.image || !visible || (instance_trans == 255 && layer_trans == 0)
00323 || (instance_trans == 0 && layer_trans == 255)) {
00324 continue;
00325 }
00326
00327 if(layer_trans != 0) {
00328 if(instance_trans != 0) {
00329 short calc_trans = layer_trans - instance_trans;
00330 if(calc_trans >= 0) {
00331 instance_trans = calc_trans;
00332 } else {
00333 instance_trans = 0;
00334 }
00335 } else {
00336 instance_trans = layer_trans;
00337 }
00338 }
00339
00340 Point3D screen_point = m_camera->virtualScreenToScreen(item.screenpoint);
00341
00342
00343
00344
00345
00346
00347 item.dimensions.x = screen_point.x;
00348 item.dimensions.y = screen_point.y;
00349 item.dimensions.w = item.bbox.w;
00350 item.dimensions.h = item.bbox.h;
00351
00352 item.transparency = 255 - instance_trans;
00353
00354 if (zoom != 1.0) {
00355
00356
00357
00358 item.dimensions.w = unsigned(double(item.bbox.w) * zoom + OVERDRAW);
00359 item.dimensions.h = unsigned(double(item.bbox.h) * zoom + OVERDRAW);
00360 }
00361
00362 if(item.dimensions.intersects(screen_viewport))
00363 renderlist.push_back(&item);
00364 }
00365
00366 InstanceDistanceSort ids;
00367 std::stable_sort(renderlist.begin(), renderlist.end(), ids);
00368
00369 }
00370 }