layercache.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005-2008 by the FIFE team                              *
00003  *   http://www.fifengine.de                                               *
00004  *   This file is part of FIFE.                                            *
00005  *                                                                         *
00006  *   FIFE is free software; you can redistribute it and/or                 *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the                 *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00020  ***************************************************************************/
00021 
00022 // Standard C++ library includes
00023 #include <cfloat>
00024 
00025 // 3rd party library includes
00026 
00027 // FIFE includes
00028 // These includes are split up in two parts, separated by one empty line
00029 // First block: files included from the FIFE root src directory
00030 // Second block: files included from the same folder
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/animation.h"
00044 #include "video/imagemanager.h"
00045 
00046 #include "camera.h"
00047 #include "layercache.h"
00048 #include "visual.h"
00049 
00050 
00051 namespace FIFE {
00052     static Logger _log(LM_CAMERA);
00053 
00054     class CacheLayerChangeListener : public LayerChangeListener {
00055     public:
00056         CacheLayerChangeListener(LayerCache* cache) {
00057             m_cache = cache;
00058         }
00059         virtual ~CacheLayerChangeListener() {};
00060 
00061         virtual void onLayerChanged(Layer* layer, std::vector<Instance*>& instances) {
00062             for(std::vector<Instance*>::iterator i = instances.begin();
00063                 i != instances.end(); ++i) {
00064                 m_cache->updateInstance(*i);
00065             }
00066         }
00067 
00068         virtual void onInstanceCreate(Layer* layer, Instance* instance) {
00069             m_cache->addInstance(instance);
00070         }
00071 
00072         virtual void onInstanceDelete(Layer* layer, Instance* instance) {
00073             m_cache->removeInstance(instance);
00074         }
00075     private:
00076         LayerCache* m_cache;
00077     };
00078 
00079     LayerCache::LayerCache(Camera* camera) {
00080         m_camera = camera;
00081         m_layer = 0;
00082         m_tree = 0;
00083         m_needupdate = false;
00084         m_need_sorting = true;
00085 
00086         if(RenderBackend::instance()->getName() == "OpenGLe") {
00087             m_need_sorting = false;
00088         }
00089     }
00090 
00091     LayerCache::~LayerCache() {
00092         m_layer->removeChangeListener(m_layer_observer);
00093         delete m_layer_observer;
00094         delete m_tree;
00095     }
00096 
00097     void LayerCache::setLayer(Layer* layer) {
00098         m_layer = layer;
00099         m_layer_observer = new CacheLayerChangeListener(this);
00100         layer->addChangeListener(m_layer_observer);
00101         reset();
00102     }
00103 
00104     void LayerCache::reset() {
00105         m_instances.clear();
00106         delete m_tree;
00107         m_tree = new CacheTree;
00108         const std::vector<Instance*>& instances = m_layer->getInstances();
00109         for(std::vector<Instance*>::const_iterator i = instances.begin();
00110             i != instances.end(); ++i) {
00111             addInstance(*i);
00112         }
00113         m_needupdate = true;
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         m_needupdate = true;
00133     }
00134 
00135     void LayerCache::removeInstance(Instance* instance) {
00136         // FIXME
00137         // The way LayerCache stores it's data
00138         // it's pretty much impossible to cleanly remove
00139         // added instances.
00140 
00141         // This has to get fixed.
00142         if(m_instance_map.find(instance) == m_instance_map.end()) {
00143             throw new NotFound(instance->getId());
00144         }
00145         Entry& item = m_entries[m_instance_map[instance]];
00146         assert(item.instance_index == m_instance_map[instance]);
00147 
00148         if(item.node) {
00149             item.node->data().erase(item.entry_index);
00150         }
00151         item.node = 0;
00152         item.instance_index = -1;
00153         m_instance_map.erase(instance);
00154         m_needupdate = true;
00155     }
00156 
00157     void LayerCache::updateInstance(Instance* instance) {
00158         Entry& entry = m_entries[m_instance_map[instance]];
00159         updateEntry(entry);
00160     }
00161 
00162     void LayerCache::updateEntry(LayerCache::Entry& item) {
00163         if(item.instance_index == -1) {
00164             return;
00165         }
00166 
00167         RenderItem& render_item = m_instances[item.instance_index];
00168         Instance* instance = render_item.instance;
00169 
00170         ExactModelCoordinate map_coords = instance->getLocationRef().getMapCoordinates();
00171         DoublePoint3D screen_position = m_camera->toVirtualScreenCoordinates(map_coords);
00172         render_item.instance_z = instance->getLocationRef().getExactLayerCoordinates().z;
00173 
00174         render_item.facing_angle = getAngleBetween(instance->getLocationRef(), instance->getFacingLocation());
00175         int32_t angle = static_cast<int32_t>(m_camera->getRotation()) +
00176             render_item.facing_angle + instance->getRotation();
00177 
00178         ImagePtr image;
00179         Action* action = instance->getCurrentAction();
00180         int32_t w = 0;
00181         int32_t h = 0;
00182 
00183         if(!action) {
00184             // Try static images then default action.
00185             int32_t image_id = render_item.getStaticImageIndexByAngle(angle, instance);
00186             if(image_id == -1) {
00187                 if (!instance->getObject()->isStatic()) {
00188                     action = instance->getObject()->getDefaultAction();
00189                 }
00190             } else {
00191                 image = ImageManager::instance()->get(image_id);
00192             }
00193         }
00194         item.force_update = (action != 0);
00195 
00196         if(action) {
00197             AnimationPtr animation = action->getVisual<ActionVisual>()->getAnimationByAngle(
00198                 render_item.facing_angle + static_cast<int32_t>(m_camera->getRotation()));
00199             unsigned animation_time = instance->getActionRuntime() % animation->getDuration();
00200 
00201             image = animation->getFrameByTimestamp(animation_time);
00202 
00203             int32_t action_frame = animation->getActionFrame();
00204             if (action_frame != -1) {
00205                 if (render_item.image != image) {
00206                     if (action_frame == animation->getFrameIndex(animation_time)) {
00207                         instance->callOnActionFrame(action, action_frame);
00208                     }
00209                 }
00210             }
00211 
00212             int32_t facing_angle = render_item.facing_angle;
00213             if (facing_angle < 0){
00214                 facing_angle += 360;
00215             }
00216             instance->setRotation(facing_angle);
00217             m_needupdate = true;
00218         }
00219 
00220         if (image) {
00221             w = image->getWidth();
00222             h = image->getHeight();
00223 
00224             screen_position.x -= w / 2;
00225             screen_position.x += image->getXShift();
00226             screen_position.y -= h / 2;
00227             screen_position.y += image->getYShift();
00228         }
00229 
00230         render_item.image = image;
00231         if (render_item.screenpoint == screen_position) {
00232             return;
00233         }
00234         m_needupdate = true;
00235         render_item.screenpoint = screen_position;
00236 
00237         render_item.bbox.x = static_cast<int32_t>(screen_position.x);
00238         render_item.bbox.y = static_cast<int32_t>(screen_position.y);
00239         render_item.bbox.w = w;
00240         render_item.bbox.h = h;
00241 
00242         render_item.dimensions = render_item.bbox;
00243 
00244         CacheTree::Node* node = m_tree->find_container(render_item.bbox);
00245         if (node) {
00246             if(item.node) {
00247                 item.node->data().erase(item.entry_index);
00248             }
00249             item.node = node;
00250             node->data().insert(item.entry_index);
00251         }
00252     }
00253 
00254     class CacheTreeCollector {
00255             std::vector<int32_t>& m_indices;
00256             Rect m_viewport;
00257         public:
00258             CacheTreeCollector(std::vector<int32_t>& indices, const Rect& _viewport)
00259             : m_indices(indices), m_viewport(_viewport) {
00260             }
00261             bool visit(LayerCache::CacheTree::Node* node, int32_t d = -1);
00262     };
00263 
00264     bool CacheTreeCollector::visit(LayerCache::CacheTree::Node* node, int32_t d) {
00265         if(!m_viewport.intersects(Rect(node->x(), node->y(),node->size(),node->size()))) {
00266             return false;
00267         }
00268         std::set<int32_t>& list = node->data();
00269         for(std::set<int32_t>::iterator i = list.begin(); i!=list.end();++i) {
00270             m_indices.push_back(*i);
00271         }
00272         return true;
00273     }
00274 
00275     void LayerCache::collect(const Rect& viewport, std::vector<int32_t>& index_list) {
00276         CacheTree::Node * node = m_tree->find_container(viewport);
00277         CacheTreeCollector collector(index_list, viewport);
00278         node->apply_visitor(collector);
00279         node = node->parent();
00280         while(node) {
00281             collector.visit(node);
00282             node = node->parent();
00283         }
00284     }
00285 
00286     void LayerCache::fullUpdate() {
00287         for(unsigned i=0; i!=m_entries.size(); ++i) {
00288             updateEntry(m_entries[i]);
00289         }
00290     }
00291 
00292     class InstanceDistanceSort {
00293     public:
00294         inline bool operator()(RenderItem* const & lhs, RenderItem* const & rhs) {
00295             if (lhs->screenpoint.z == rhs->screenpoint.z) {
00296                 InstanceVisual* liv = lhs->instance->getVisual<InstanceVisual>();
00297                 InstanceVisual* riv = rhs->instance->getVisual<InstanceVisual>();
00298                 return liv->getStackPosition() < riv->getStackPosition();
00299             }
00300             return lhs->screenpoint.z < rhs->screenpoint.z;
00301         }
00302     };
00303 
00304     void LayerCache::update(Camera::Transform transform, RenderList& renderlist) {
00305         const double OVERDRAW = 2.5;
00306         renderlist.clear();
00307         m_needupdate = false;
00308         if(!m_layer->areInstancesVisible()) {
00309             FL_DBG(_log, "Layer instances hidden");
00310             return;
00311         }
00312         bool isWarped = transform == Camera::WarpedTransform;
00313         if( isWarped ) {
00314             fullUpdate();
00315         }
00316 
00317         Rect viewport = m_camera->getViewPort();
00318         Rect screen_viewport = viewport;
00319         double zoom = m_camera->getZoom();
00320         DoublePoint3D viewport_a = m_camera->screenToVirtualScreen(Point3D(viewport.x, viewport.y));
00321         DoublePoint3D viewport_b = m_camera->screenToVirtualScreen(Point3D(viewport.right(), viewport.bottom()));
00322         viewport.x = static_cast<int32_t>(std::min(viewport_a.x, viewport_b.x));
00323         viewport.y = static_cast<int32_t>(std::min(viewport_a.y, viewport_b.y));
00324         viewport.w = static_cast<int32_t>(std::max(viewport_a.x, viewport_b.x) - viewport.x);
00325         viewport.h = static_cast<int32_t>(std::max(viewport_a.y, viewport_b.y) - viewport.y);
00326         uint8_t layer_trans = m_layer->getLayerTransparency();
00327 
00328         double zmin = 0.0, zmax = 0.0;
00329 
00330         // FL_LOG(_log, LMsg("camera-update viewport") << viewport);
00331         std::vector<int32_t> index_list;
00332         collect(viewport, index_list);
00333         for(unsigned i=0; i!=index_list.size();++i) {
00334             Entry& entry = m_entries[index_list[i]];
00335             // NOTE
00336             // An update is forced if the item has an animation/action.
00337             // This update only happens if it is _already_ included in the viewport
00338             // Nevertheless: Moving instances - which might move into the viewport will be updated
00339             // By the layer change listener.
00340             if(entry.force_update || !isWarped) {
00341                 updateEntry(entry);
00342             }
00343 
00344             RenderItem& item = m_instances[entry.instance_index];
00345             InstanceVisual* visual = item.instance->getVisual<InstanceVisual>();
00346             bool visible = (visual->isVisible() != 0);
00347             uint8_t instance_trans = visual->getTransparency();
00348             if(!item.image || !visible || (instance_trans == 255 && layer_trans == 0)
00349                                        || (instance_trans == 0 && layer_trans == 255)) {
00350                 continue;
00351             }
00352 
00353             if(layer_trans != 0) {
00354                 if(instance_trans != 0) {
00355                     uint8_t calc_trans = layer_trans - instance_trans;
00356                     if(calc_trans >= 0) {
00357                         instance_trans = calc_trans;
00358                     } else {
00359                         instance_trans = 0;
00360                     }
00361                 } else {
00362                     instance_trans = layer_trans;
00363                 }
00364             }
00365 
00366             Point3D screen_point = m_camera->virtualScreenToScreen(item.screenpoint);
00367             // NOTE:
00368             // One would expect this to be necessary here,
00369             // however it works the same without, sofar
00370             // m_camera->calculateZValue(screen_point);
00371             // item.screenpoint.z = -screen_point.z;
00372 
00373             item.dimensions.x = screen_point.x;
00374             item.dimensions.y = screen_point.y;
00375             item.dimensions.w = item.bbox.w;
00376             item.dimensions.h = item.bbox.h;
00377 
00378             item.transparency = 255 - instance_trans;
00379 
00380             if (zoom != 1.0) {
00381                 // NOTE: Due to image alignment, there is additional additions on image dimensions
00382                 //       There's probabaly some better solution for this, but works "good enough" for now.
00383                 //       In case additions are removed, gaps appear between tiles.
00384                 item.dimensions.w = unsigned(double(item.bbox.w) * zoom + OVERDRAW);
00385                 item.dimensions.h = unsigned(double(item.bbox.h) * zoom + OVERDRAW);
00386             }
00387 
00388             if (!m_need_sorting) {
00389                 zmin = std::min(zmin, item.screenpoint.z);
00390                 zmax = std::max(zmax, item.screenpoint.z);
00391             }
00392 
00393             if(item.dimensions.intersects(screen_viewport)) {
00394                 renderlist.push_back(&item);
00395             }
00396         }
00397 
00398         if (m_need_sorting) {
00399             InstanceDistanceSort ids;
00400             std::stable_sort(renderlist.begin(), renderlist.end(), ids);
00401         } else {
00402             zmin -= 0.5;
00403             zmax += 0.5;
00404 
00405             // We want to put every z value in [-10,10] range.
00406             // To do it, we simply solve 
00407             // { y1 = a*x1 + b
00408             // { y2 = a*x2 + b
00409             // where [y1,y2]' = [-10,10]' is required z range, 
00410             // and [x1,x2]' is expected min,max z coords.
00411             double det = zmin - zmax;
00412             if (fabs(det) > FLT_EPSILON) {
00413                 double det_a = -10.0 - 10.0;
00414                 double det_b = 10.0 * zmin - (-10.0) * zmax;
00415                 double a = static_cast<float>(det_a / det);
00416                 double b = static_cast<float>(det_b / det);
00417                 float estimate = sqrtf(static_cast<float>(renderlist.size()));
00418                 float stack_delta = fabs(-10.0f - 10.0f) / estimate * 0.1f;
00419 
00420                 RenderList::iterator it = renderlist.begin();
00421                 for ( ; it != renderlist.end(); ++it) {
00422                     double& z = (*it)->screenpoint.z;
00423                     z = a * z + b;
00424                     InstanceVisual* vis = (*it)->instance->getVisual<InstanceVisual>();
00425                     z += vis->getStackPosition() * stack_delta;                 
00426                 }
00427             }
00428         }
00429         //  FL_LOG(_log, LMsg("camera-update ") << " N=" <<renderlist.size() << "/" << m_instances.size() << "/" << index_list.size());
00430     }
00431 }