camera.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 
00024 // 3rd party library includes
00025 
00026 // FIFE includes
00027 // These includes are split up in two parts, separated by one empty line
00028 // First block: files included from the FIFE root src directory
00029 // Second block: files included from the same folder
00030 
00031 #include "model/metamodel/grids/cellgrid.h"
00032 #include "model/metamodel/action.h"
00033 #include "model/metamodel/timeprovider.h"
00034 #include "model/structures/map.h"
00035 #include "model/structures/layer.h"
00036 #include "model/structures/instancetree.h"
00037 #include "model/structures/instance.h"
00038 #include "model/structures/location.h"
00039 #include "util/log/logger.h"
00040 #include "util/math/fife_math.h"
00041 #include "util/math/angles.h"
00042 #include "util/time/timemanager.h"
00043 #include "video/renderbackend.h"
00044 #include "video/image.h"
00045 #include "video/animation.h"
00046 #include "video/imagemanager.h"
00047 
00048 #include "camera.h"
00049 #include "layercache.h"
00050 #include "visual.h"
00051 
00052 
00053 namespace FIFE {
00054     static Logger _log(LM_CAMERA);
00055 
00056     class MapObserver : public MapChangeListener {
00057         Camera* m_camera;
00058 
00059     public:
00060         MapObserver(Camera* camera) {
00061             m_camera = camera;
00062         }
00063         virtual ~MapObserver() {}
00064 
00065         virtual void onMapChanged(Map* map, std::vector<Layer*>& changedLayers) {
00066         }
00067 
00068         virtual void onLayerCreate(Map* map, Layer* layer) {
00069             m_camera->addLayer(layer);
00070         }
00071 
00072         virtual void onLayerDelete(Map* map, Layer* layer) {
00073             m_camera->removeLayer(layer);
00074         }
00075     };
00076 
00077     Camera::Camera(const std::string& id,
00078         Layer *layer,
00079         const Rect& viewport,
00080         RenderBackend* renderbackend):
00081             m_id(id),
00082             m_matrix(),
00083             m_inverse_matrix(),
00084             m_tilt(0),
00085             m_rotation(0),
00086             m_zoom(1),
00087             m_location(),
00088             m_cur_origo(ScreenPoint(0,0,0)),
00089             m_viewport(),
00090             m_screen_cell_width(1),
00091             m_screen_cell_height(1),
00092             m_reference_scale(1),
00093             m_enabled(true),
00094             m_attachedto(NULL),
00095             m_image_dimensions(),
00096             m_iswarped(false),
00097             m_renderers(),
00098             m_pipeline(),
00099             m_updated(false),
00100             m_renderbackend(renderbackend),
00101             m_layer_to_instances(),
00102             m_lighting(false),
00103             m_light_colors(),
00104             m_col_overlay(false),
00105             m_img_overlay(false),
00106             m_ani_overlay(false) {
00107         m_viewport = viewport;
00108         m_map_observer = new MapObserver(this);
00109         m_map = 0;
00110         Location location;
00111         location.setLayer(layer);
00112         setLocation(location);
00113     }
00114 
00115     Camera::~Camera() {
00116         // Trigger removal of LayerCaches and MapObserver
00117         updateMap(NULL);
00118 
00119         std::map<std::string, RendererBase*>::iterator r_it = m_renderers.begin();
00120         for(; r_it != m_renderers.end(); ++r_it) {
00121             r_it->second->reset();
00122             delete r_it->second;
00123         }
00124         m_renderers.clear();
00125         delete m_map_observer;
00126     }
00127 
00128     void Camera::setTilt(double tilt) {
00129         if (!Mathd::Equal(m_tilt, tilt)) {
00130             m_tilt = tilt;
00131             updateReferenceScale();
00132             updateMatrices();
00133             m_iswarped = true;
00134         }
00135     }
00136 
00137     double Camera::getTilt() const {
00138         return m_tilt;
00139     }
00140 
00141     void Camera::setRotation(double rotation) {
00142         if (!Mathd::Equal(m_rotation, rotation)) {
00143             m_rotation = rotation;
00144             updateReferenceScale();
00145             updateMatrices();
00146             m_iswarped = true;
00147         }
00148     }
00149 
00150     double Camera::getRotation() const {
00151         return m_rotation;
00152     }
00153 
00154     void Camera::setZoom(double zoom) {
00155         if (!Mathd::Equal(m_zoom, zoom)) {
00156             m_zoom = zoom;
00157             if (m_zoom < 0.001) {
00158                 m_zoom = 0.001;
00159             }
00160             updateMatrices();
00161             m_updated = false;
00162         }
00163     }
00164 
00165     double Camera::getZoom() const {
00166         return m_zoom;
00167     }
00168 
00169     void Camera::setCellImageDimensions(uint32_t width, uint32_t height) {
00170         m_screen_cell_width = width;
00171         m_screen_cell_height = height;
00172         updateReferenceScale();
00173         updateMatrices();
00174         m_iswarped = true;
00175     }
00176 
00177     void Camera::setLocation(const Location& location) {
00178         if (m_location == location ) {
00179             return;
00180         }
00181 
00182         CellGrid* cell_grid = NULL;
00183         if (location.getLayer()) {
00184             cell_grid = location.getLayer()->getCellGrid();
00185         } else {
00186             throw Exception("Location without layer given to Camera::setLocation");
00187         }
00188         if (!cell_grid) {
00189             throw Exception("Camera layer has no cellgrid specified");
00190         }
00191 
00192         m_location = location;
00193         updateMatrices();
00194 
00195         ExactModelCoordinate emc = m_location.getMapCoordinates();
00196         m_cur_origo = toScreenCoordinates(emc);
00197 
00198         // WARNING
00199         // It is important that m_location is already set,
00200         // as the updates which are triggered here
00201         // need to calculate screen-coordinates
00202         // which depend on m_location.
00203         updateMap(m_location.getMap());
00204 
00205         m_updated = false;
00206     }
00207 
00208     void Camera::updateMap(Map* map) {
00209         if(m_map == map) {
00210             return;
00211         }
00212         if(m_map) {
00213             m_map->removeChangeListener(m_map_observer);
00214             const std::list<Layer*>& layers = m_map->getLayers();
00215             for(std::list<Layer*>::const_iterator i = layers.begin(); i !=layers.end(); ++i) {
00216                 removeLayer(*i);
00217             }
00218         }
00219         if(map) {
00220             map->addChangeListener(m_map_observer);
00221             const std::list<Layer*>& layers = map->getLayers();
00222             for(std::list<Layer*>::const_iterator i = layers.begin(); i !=layers.end(); ++i) {
00223                 addLayer(*i);
00224             }
00225         }
00226         m_map = map;
00227     }
00228 
00229     Point Camera::getCellImageDimensions() {
00230         return getCellImageDimensions(m_location.getLayer());
00231     }
00232 
00233     Point Camera::getCellImageDimensions(Layer* layer) {
00234         if (layer == m_location.getLayer()) {
00235             return Point( m_screen_cell_width, m_screen_cell_height );
00236         }
00237         std::map<Layer*, Point>::iterator it = m_image_dimensions.find(layer);
00238         if (it != m_image_dimensions.end()) {
00239             return it->second;
00240         }
00241         Point p;
00242         CellGrid* cg = layer->getCellGrid();
00243         assert(cg);
00244         DoublePoint dimensions = getLogicalCellDimensions(layer);
00245         p.x = static_cast<int32_t>(round(m_reference_scale * dimensions.x));
00246         p.y = static_cast<int32_t>(round(m_reference_scale * dimensions.y));
00247         m_image_dimensions[layer] = p;
00248         return p;
00249     }
00250 
00251     Location Camera::getLocation() const {
00252         return m_location;
00253     }
00254 
00255     Location& Camera::getLocationRef() {
00256         return m_location;
00257     }
00258 
00259     void Camera::setViewPort(const Rect& viewport) {
00260         m_viewport = viewport;
00261     }
00262 
00263     const Rect& Camera::getViewPort() const {
00264         return m_viewport;
00265     }
00266 
00267     void Camera::setEnabled(bool enabled) {
00268         m_enabled = enabled;
00269     }
00270 
00271     bool Camera::isEnabled() {
00272         return m_enabled;
00273     }
00274 
00275     Point3D Camera::getOrigin() const {
00276         return m_cur_origo;
00277     }
00278 
00279     void Camera::updateMatrices() {
00280         double scale = m_reference_scale;
00281         m_matrix.loadScale(scale, scale, scale);
00282         m_vs_matrix.loadScale(scale,scale,scale);
00283         if (m_location.getLayer()) {
00284             CellGrid* cg = m_location.getLayer()->getCellGrid();
00285             if (cg) {
00286                 ExactModelCoordinate pt = m_location.getMapCoordinates();
00287                 m_matrix.applyTranslate( -pt.x *m_reference_scale,-pt.y *m_reference_scale, -pt.z*m_reference_scale);
00288             }
00289         }
00290         scale = m_zoom;
00291         m_matrix.applyScale(scale, scale, scale);
00292         m_matrix.applyRotate(-m_rotation, 0.0, 0.0, 1.0);
00293         m_matrix.applyRotate(-m_tilt, 1.0, 0.0, 0.0);
00294         m_matrix.applyTranslate(+m_viewport.x+m_viewport.w/2, +m_viewport.y+m_viewport.h/2, 0);
00295         m_inverse_matrix = m_matrix.inverse();
00296 
00297         m_vs_matrix.applyRotate(-m_rotation, 0.0, 0.0, 1.0);
00298         m_vs_matrix.applyRotate(-m_tilt, 1.0, 0.0, 0.0);
00299         m_vs_inverse_matrix = m_vs_matrix.inverse();
00300 
00301         // calculate the screen<->virtual screen transformation
00302         // this explicitly ignores the z-value.
00303         m_vscreen_2_screen = m_matrix;
00304         // NOTE: mult4by4 is an in-place modification.
00305         m_vscreen_2_screen.mult4by4(m_vs_inverse_matrix);
00306         // set the z transformation to unity
00307         const int32_t N=4;
00308         for(int32_t i=0; i!=N; ++i) {
00309               m_vscreen_2_screen[2*N + i] = 0;
00310               m_vscreen_2_screen[i*N + 2] = 0;
00311         }
00312         m_vscreen_2_screen[2*N + 2] = 1;
00313         m_screen_2_vscreen = m_vscreen_2_screen.inverse();
00314 
00315         // FL_WARN(_log, LMsg("matrix: ") << m_matrix << " 1: " << m_matrix.inverse().mult4by4(m_matrix));
00316 //      FL_WARN(_log, LMsg("vs2s matrix: ") << m_vscreen_2_screen << " s2vs matrix: " << m_screen_2_vscreen);
00317     }
00318 
00319     void Camera::calculateZValue(ScreenPoint& screen_coords) {
00320         int32_t dy = -(screen_coords.y - toScreenCoordinates(m_location.getMapCoordinates()).y);
00321         screen_coords.z = static_cast<int32_t>(Mathd::Tan(m_tilt * (Mathd::pi() / 180.0)) * static_cast<double>(dy));
00322     }
00323 
00324     ExactModelCoordinate Camera::toMapCoordinates(ScreenPoint screen_coords, bool z_calculated) {
00325         if (!z_calculated) {
00326             calculateZValue(screen_coords);
00327         }
00328         return m_inverse_matrix  * intPt2doublePt(screen_coords);
00329     }
00330 
00331     ScreenPoint Camera::toScreenCoordinates(const ExactModelCoordinate& elevation_coords) {
00332         ScreenPoint pt = doublePt2intPt(m_matrix * elevation_coords);
00333         return pt;
00334     }
00335 
00336     DoublePoint3D Camera::toVirtualScreenCoordinates(const ExactModelCoordinate& elevation_coords) {
00337         DoublePoint3D pt = (m_vs_matrix * elevation_coords);
00338         return pt;
00339     }
00340 
00341     ScreenPoint Camera::virtualScreenToScreen(const DoublePoint3D& p) {
00342         return doublePt2intPt(m_vscreen_2_screen * p);
00343     }
00344 
00345     DoublePoint3D Camera::screenToVirtualScreen(const ScreenPoint& p) {
00346         return m_screen_2_vscreen * intPt2doublePt(p);
00347     }
00348 
00349     DoublePoint Camera::getLogicalCellDimensions(Layer* layer) {
00350         CellGrid* cg = NULL;
00351         if (layer) {
00352             cg = layer->getCellGrid();
00353         }
00354         assert(cg);
00355 
00356         ModelCoordinate cell(0,0);
00357         std::vector<ExactModelCoordinate> vertices;
00358         cg->getVertices(vertices, cell);
00359 
00360         DoubleMatrix mtx;
00361         mtx.loadRotate(m_rotation, 0.0, 0.0, 1.0);
00362         mtx.applyRotate(m_tilt, 1.0, 0.0, 0.0);
00363 
00364         double x1 = 0;
00365         double x2 = 0;
00366         double y1 = 0;
00367         double y2 = 0;
00368 
00369         for (uint32_t i = 0; i < vertices.size(); i++) {
00370             vertices[i] = cg->toMapCoordinates(vertices[i]);
00371             vertices[i] = mtx * vertices[i];
00372             if (i == 0) {
00373                 x1 = x2 = vertices[0].x;
00374                 y1 = y2 = vertices[0].y;
00375             } else {
00376                 x1 = std::min(vertices[i].x, x1);
00377                 x2 = std::max(vertices[i].x, x2);
00378                 y1 = std::min(vertices[i].y, y1);
00379                 y2 = std::max(vertices[i].y, y2);
00380             }
00381         }
00382         return DoublePoint( x2 - x1, y2 - y1 );
00383     }
00384 
00385     Point Camera::getRealCellDimensions(Layer* layer) {
00386         CellGrid* cg = NULL;
00387         if (layer) {
00388             cg = layer->getCellGrid();
00389         }
00390         assert(cg);
00391 
00392         Location loc(layer);
00393         ModelCoordinate cell(0,0);
00394         loc.setLayerCoordinates(cell);
00395         ScreenPoint sp1 = toScreenCoordinates(loc.getMapCoordinates());
00396         ++cell.y;
00397         loc.setLayerCoordinates(cell);
00398         ScreenPoint sp2 = toScreenCoordinates(loc.getMapCoordinates());
00399 
00400         Point p(ABS(sp2.x - sp1.x), ABS(sp2.y - sp1.y));
00401         if (p.x == 0) {
00402             p.x = 1;
00403         }
00404         if (p.y == 0) {
00405             p.y = 1;
00406         }
00407         return p;
00408     }
00409 
00410     Point3D Camera::getZOffset(Layer* layer) {
00411         CellGrid* cg = NULL;
00412         if (layer) {
00413             cg = layer->getCellGrid();
00414         }
00415         assert(cg);
00416 
00417         Location loc(layer);
00418         ModelCoordinate cell(0,0,0);
00419         loc.setLayerCoordinates(cell);
00420         ScreenPoint sp1 = toScreenCoordinates(loc.getMapCoordinates());
00421         ++cell.z;
00422         loc.setLayerCoordinates(cell);
00423         ScreenPoint sp2 = toScreenCoordinates(loc.getMapCoordinates());
00424 
00425         return Point3D(sp2.x - sp1.x, sp2.y - sp1.y, sp2.z - sp1.z);
00426     }
00427 
00428     void Camera::updateReferenceScale() {
00429         DoublePoint dim = getLogicalCellDimensions(m_location.getLayer());
00430         m_reference_scale = static_cast<double>(m_screen_cell_width) / dim.x;
00431 
00432         FL_DBG(_log, "Updating reference scale");
00433         FL_DBG(_log, LMsg("   tilt=") << m_tilt << " rot=" << m_rotation);
00434         FL_DBG(_log, LMsg("   m_screen_cell_width=") << m_screen_cell_width);
00435     }
00436 
00437     void Camera::cacheUpdate(Layer* layer) {
00438         Map* map = m_location.getMap();
00439         if (!map) {
00440             FL_ERR(_log, "No map for camera found");
00441             return;
00442         }
00443         // if camera need update, we update all caches
00444         if (m_iswarped || !m_updated) {
00445             updateRenderLists();
00446         } else {
00447             LayerCache* cache = m_cache[layer];
00448             if(!cache) {
00449                 addLayer(layer);
00450                 cache = m_cache[layer];
00451                 FL_ERR(_log, LMsg("Layer Cache miss! (This shouldn't happen!)") << layer->getId());
00452             }
00453             // only this cache need an update, e.g. a instance is added/removed
00454             if (cache->needUpdate()) {
00455                 Transform transform = NormalTransform;
00456                 if (m_iswarped) {
00457                     transform = WarpedTransform;
00458                 }
00459                 RenderList& instances_to_render = m_layer_to_instances[layer];
00460                 cache->update(transform, instances_to_render);
00461             }
00462         }
00463     }
00464 
00465     void Camera::getMatchingInstances(ScreenPoint screen_coords, Layer& layer, std::list<Instance*>& instances, uint8_t alpha) {
00466         instances.clear();
00467         bool zoomed = !Mathd::Equal(m_zoom, 1.0);
00468         bool special_alpha = alpha != 0;
00469         cacheUpdate(&layer);
00470         const RenderList& layer_instances = m_layer_to_instances[&layer];
00471         RenderList::const_iterator instance_it = layer_instances.end();
00472         while (instance_it != layer_instances.begin()) {
00473             --instance_it;
00474             Instance* i = (*instance_it)->instance;
00475             const RenderItem& vc = **instance_it;
00476             if ((vc.dimensions.contains(Point(screen_coords.x, screen_coords.y)))) {
00477                 if(vc.image->isSharedImage()) {
00478                     vc.image->forceLoadInternal();
00479                 }
00480                 uint8_t r, g, b, a = 0;
00481                 int32_t x = screen_coords.x - vc.dimensions.x;
00482                 int32_t y = screen_coords.y - vc.dimensions.y;
00483                 if (zoomed) {
00484                     double fx = static_cast<double>(x);
00485                     double fy = static_cast<double>(y);
00486                     double fow = static_cast<double>(vc.image->getWidth());
00487                     double foh = static_cast<double>(vc.image->getHeight());
00488                     double fsw = static_cast<double>(vc.dimensions.w);
00489                     double fsh = static_cast<double>(vc.dimensions.h);
00490                     x = static_cast<int32_t>(round(fx / fsw * fow));
00491                     y = static_cast<int32_t>(round(fy / fsh * foh));
00492                 }
00493                 vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
00494                 // instance is hit with mouse if not totally transparent
00495                 if (a == 0 || (special_alpha && a < alpha)) {
00496                     continue;
00497                 }
00498                 instances.push_back(i);
00499             }
00500         }
00501     }
00502 
00503     void Camera::getMatchingInstances(Rect screen_rect, Layer& layer, std::list<Instance*>& instances, uint8_t alpha) {
00504         instances.clear();
00505         bool zoomed = !Mathd::Equal(m_zoom, 1.0);
00506         bool special_alpha = alpha != 0;
00507         cacheUpdate(&layer);
00508 
00509         const RenderList& layer_instances = m_layer_to_instances[&layer];
00510         RenderList::const_iterator instance_it = layer_instances.end();
00511         while (instance_it != layer_instances.begin()) {
00512             --instance_it;
00513             Instance* i = (*instance_it)->instance;;
00514             const RenderItem& vc = **instance_it;
00515             if ((vc.dimensions.intersects(screen_rect))) {
00516                 if(vc.image->isSharedImage()) {
00517                     vc.image->forceLoadInternal();
00518                 }
00519                 uint8_t r, g, b, a = 0;
00520                 for(int32_t xx = screen_rect.x; xx < screen_rect.x + screen_rect.w; xx++) {
00521                     for(int32_t yy = screen_rect.y; yy < screen_rect.y + screen_rect.h; yy++) {
00522                         if ((vc.dimensions.contains(Point(xx, yy)))) {
00523                             int32_t x = xx - vc.dimensions.x;
00524                             int32_t y = yy - vc.dimensions.y;
00525                             if (zoomed) {
00526                                 double fx = static_cast<double>(x);
00527                                 double fy = static_cast<double>(y);
00528                                 double fow = static_cast<double>(vc.image->getWidth());
00529                                 double foh = static_cast<double>(vc.image->getHeight());
00530                                 double fsw = static_cast<double>(vc.dimensions.w);
00531                                 double fsh = static_cast<double>(vc.dimensions.h);
00532                                 x = static_cast<int32_t>(round(fx / fsw * fow));
00533                                 y = static_cast<int32_t>(round(fy / fsh * foh));
00534                             }
00535                             vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
00536                             // instance is hit with mouse if not totally transparent
00537                             if (a == 0 || (special_alpha && a < alpha)) {
00538                                 continue;
00539                             }
00540 
00541                             instances.push_back(i);
00542                             goto found_non_transparent_pixel;
00543                         }
00544                     }
00545                 }
00546                 found_non_transparent_pixel:;
00547             }
00548         }
00549     }
00550 
00551     void Camera::getMatchingInstances(Location& loc, std::list<Instance*>& instances, bool use_exactcoordinates) {
00552         instances.clear();
00553         Layer* layer = loc.getLayer();
00554         if(!layer) {
00555             return;
00556         }
00557 
00558         cacheUpdate(layer);
00559         const RenderList& layer_instances = m_layer_to_instances[layer];
00560         RenderList::const_iterator instance_it = layer_instances.end();
00561         while (instance_it != layer_instances.begin()) {
00562             --instance_it;
00563             Instance* i = (*instance_it)->instance;
00564             if (use_exactcoordinates) {
00565                 if (i->getLocationRef().getExactLayerCoordinatesRef() == loc.getExactLayerCoordinatesRef()) {
00566                     instances.push_back(i);
00567                 }
00568             } else {
00569                 if (i->getLocationRef().getLayerCoordinates() == loc.getLayerCoordinates()) {
00570                     instances.push_back(i);
00571                 }
00572             }
00573         }
00574     }
00575 
00576     void Camera::attach(Instance *instance) {
00577         // fail if the layers aren't the same
00578         if (m_location.getLayer()->getId() != instance->getLocation().getLayer()->getId()) {
00579             FL_WARN(_log, "Tried to attach camera to instance on different layer.");
00580             return ;
00581         }
00582         m_attachedto = instance;
00583     }
00584 
00585     void Camera::detach() {
00586         m_attachedto = NULL;
00587     }
00588 
00589     void Camera::update() {
00590         if( !m_attachedto ) {
00591             return;
00592         }
00593         Location loc(m_location);
00594         loc.setExactLayerCoordinates( m_attachedto->getLocationRef().getExactLayerCoordinates(m_location.getLayer()) );
00595         setLocation(loc);
00596         updateMatrices();
00597     }
00598 
00599     void Camera::refresh() {
00600         updateMatrices();
00601         m_iswarped = true;
00602     }
00603 
00604     void Camera::resetUpdates() {
00605         m_iswarped = false;
00606         m_updated = true;
00607     }
00608 
00609     bool pipelineSort(const RendererBase* lhs, const RendererBase* rhs) {
00610         return (lhs->getPipelinePosition() < rhs->getPipelinePosition());
00611     }
00612 
00613     void Camera::addRenderer(RendererBase* renderer) {
00614         renderer->setRendererListener(this);
00615         m_renderers[renderer->getName()] = renderer;
00616         if (renderer->isEnabled()) {
00617             m_pipeline.push_back(renderer);
00618         }
00619         m_pipeline.sort(pipelineSort);
00620     }
00621 
00622     void Camera::onRendererPipelinePositionChanged(RendererBase* renderer) {
00623         m_pipeline.sort(pipelineSort);
00624     }
00625 
00626     void Camera::onRendererEnabledChanged(RendererBase* renderer) {
00627         assert(m_renderers[renderer->getName()]);
00628         if (renderer->isEnabled()) {
00629             FL_LOG(_log, LMsg("Enabling renderer ") << renderer->getName());
00630             m_pipeline.push_back(renderer);
00631             m_pipeline.sort(pipelineSort);
00632         } else {
00633             m_pipeline.remove(renderer);
00634         }
00635     }
00636 
00637     RendererBase* Camera::getRenderer(const std::string& name) {
00638         return m_renderers[name];
00639     }
00640 
00641     void Camera::resetRenderers() {
00642         std::map<std::string, RendererBase*>::iterator r_it = m_renderers.begin();
00643         for (; r_it != m_renderers.end(); ++r_it) {
00644             r_it->second->reset();
00645         }
00646     }
00647 
00648     void Camera::addLayer(Layer* layer) {
00649         m_cache[layer] = new LayerCache(this);
00650         m_cache[layer]->setLayer(layer);
00651         m_layer_to_instances[layer] = RenderList();
00652     }
00653 
00654     void Camera::removeLayer(Layer* layer) {
00655         delete m_cache[layer];
00656         m_cache.erase(layer);
00657         m_layer_to_instances.erase(layer);
00658     }
00659 
00660     void Camera::setLightingColor(float red, float green, float blue) {
00661         m_lighting = true;
00662         m_light_colors.clear();
00663         m_light_colors.push_back(red);
00664         m_light_colors.push_back(green);
00665         m_light_colors.push_back(blue);
00666     }
00667 
00668     std::vector<float> Camera::getLightingColor() {
00669         if(m_light_colors.empty()) {
00670             for(int32_t colors = 0; colors != 3; ++colors) {
00671                 m_light_colors.push_back(1.0f);
00672             }
00673         }
00674         return m_light_colors;
00675     }
00676 
00677     void Camera::resetLightingColor() {
00678         m_lighting = false;
00679         m_renderbackend->resetLighting();
00680     }
00681 
00682     void Camera::setOverlayColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
00683         m_col_overlay = true;
00684         m_overlay_color.r = red;
00685         m_overlay_color.g = green;
00686         m_overlay_color.b = blue;
00687         m_overlay_color.unused = alpha;
00688     }
00689 
00690     std::vector<uint8_t> Camera::getOverlayColor() {
00691         std::vector<uint8_t> colors;
00692         if (m_col_overlay) {
00693             colors.push_back(m_overlay_color.r);
00694             colors.push_back(m_overlay_color.g);
00695             colors.push_back(m_overlay_color.b);
00696             colors.push_back(m_overlay_color.unused);
00697         } else {
00698             for(uint8_t cc = 0; cc != 4; ++cc) {
00699                 colors.push_back(255);
00700             }
00701         }
00702         return colors;
00703     }
00704 
00705     void Camera::resetOverlayColor() {
00706         m_col_overlay = false;
00707     }
00708 
00709     void Camera::setOverlayImage(int32_t id, bool fill) {
00710         m_img_overlay = true;
00711         m_img_id = id;
00712         m_img_fill = fill;
00713     }
00714 
00715     int32_t Camera::getOverlayImage() {
00716         int32_t id = -1;
00717         if (m_img_overlay) {
00718             id = m_img_id;
00719         }
00720         return id;
00721     }
00722 
00723     void Camera::resetOverlayImage() {
00724         m_img_overlay = false;
00725         m_img_id = -1;
00726     }
00727 
00728     void Camera::setOverlayAnimation(AnimationPtr anim, bool fill) {
00729         m_ani_overlay = true;
00730         m_ani_ptr = anim;
00731         m_ani_fill = fill;
00732         m_start_time = 0;
00733     }
00734 
00735     AnimationPtr Camera::getOverlayAnimation() {
00736         return m_ani_ptr;
00737     }
00738 
00739     void Camera::resetOverlayAnimation() {
00740         m_ani_overlay = false;
00741         m_ani_ptr.reset();
00742     }
00743 
00744     void Camera::renderOverlay() {
00745         if (!m_col_overlay && !m_img_overlay && !m_ani_overlay) {
00746             return;
00747         }
00748         uint16_t width = m_viewport.w;
00749         uint16_t height = m_viewport.h;
00750         Point pm = Point(m_viewport.x + width/2, m_viewport.y + height/2);
00751         Rect r;
00752 
00753         // color overlay
00754         if (m_col_overlay) {
00755             Point p = Point(m_viewport.x, m_viewport.y);
00756             m_renderbackend->fillRectangle(p, width, height, m_overlay_color.r, m_overlay_color.g, m_overlay_color.b, m_overlay_color.unused);
00757         }
00758         // image overlay
00759         if (m_img_overlay) {
00760             ImagePtr resptr = ImageManager::instance()->get(m_img_id);
00761             Image* img = resptr.get();
00762             if (img) {
00763                 if (m_img_fill) {
00764                     r.w = width;
00765                     r.h = height;
00766                 } else {
00767                     r.w = img->getWidth();
00768                     r.h = img->getHeight();
00769                 }
00770                 r.x = pm.x-r.w/2;
00771                 r.y = pm.y-r.h/2;
00772                 img->render(r);
00773             }
00774         }
00775         // animation overlay
00776         if (m_ani_overlay) {
00777             assert(m_ani_ptr != 0);
00778 
00779             if (m_start_time == 0) {
00780                 m_start_time = TimeManager::instance()->getTime();
00781             }
00782             uint32_t animtime = scaleTime(1.0, TimeManager::instance()->getTime() - m_start_time) % m_ani_ptr->getDuration();
00783             ImagePtr img = m_ani_ptr->getFrameByTimestamp(animtime);
00784             if (img) {
00785                 if (m_ani_fill) {
00786                     r.w = width;
00787                     r.h = height;
00788                 } else {
00789                     r.w = img->getWidth();
00790                     r.h = img->getHeight();
00791                 }
00792                 r.x = pm.x-r.w/2;
00793                 r.y = pm.y-r.h/2;
00794                 img->render(r);
00795             }
00796         }
00797     }
00798 
00799     void Camera::updateRenderLists() {
00800         Map* map = m_location.getMap();
00801         if (!map) {
00802             FL_ERR(_log, "No map for camera found");
00803             return;
00804         }
00805 
00806         Transform transform = NormalTransform;
00807         if (m_iswarped) {
00808             transform = WarpedTransform;
00809         }
00810         const std::list<Layer*>& layers = map->getLayers();
00811         std::list<Layer*>::const_iterator layer_it = layers.begin();
00812         for (;layer_it != layers.end(); ++layer_it) {
00813             LayerCache* cache = m_cache[*layer_it];
00814             if(!cache) {
00815                 addLayer(*layer_it);
00816                 cache = m_cache[*layer_it];
00817                 FL_ERR(_log, LMsg("Layer Cache miss! (This shouldn't happen!)") << (*layer_it)->getId());
00818             }
00819             RenderList& instances_to_render = m_layer_to_instances[*layer_it];
00820             if (m_iswarped || !m_updated || cache->needUpdate()) {
00821                 cache->update(transform, instances_to_render);
00822             }
00823         }
00824         resetUpdates();
00825     }
00826 
00827     void Camera::render() {
00828         static bool renderbackendOpenGLe = (m_renderbackend->getName() == "OpenGLe");
00829         updateRenderLists();
00830         Map* map = m_location.getMap();
00831         if (!map) {
00832             return;
00833         }
00834 
00835         uint32_t lm = m_renderbackend->getLightingModel();
00836         if (lm != 0) {
00837             m_renderbackend->resetStencilBuffer(0);
00838             if (m_lighting) {
00839                 m_renderbackend->setLighting(m_light_colors[0], m_light_colors[1], m_light_colors[2]);
00840             }
00841         }
00842 
00843         m_renderbackend->pushClipArea(getViewPort());
00844 
00845         const std::list<Layer*>& layers = map->getLayers();
00846         std::list<Layer*>::const_iterator layer_it = layers.begin();
00847         for ( ; layer_it != layers.end(); ++layer_it) {
00848             RenderList& instances_to_render = m_layer_to_instances[*layer_it];
00849             std::list<RendererBase*>::iterator r_it = m_pipeline.begin();
00850             for (; r_it != m_pipeline.end(); ++r_it) {
00851                 if ((*r_it)->isActivedLayer(*layer_it)) {
00852                     (*r_it)->render(this, *layer_it, instances_to_render);
00853                 }
00854             }
00855             if (renderbackendOpenGLe) {
00856                 m_renderbackend->renderVertexArrays();
00857             }
00858         }
00859 
00860         renderOverlay();
00861         m_renderbackend->renderVertexArrays();
00862         if (m_lighting && lm != 0) {
00863             m_renderbackend->resetLighting();
00864         }
00865         m_renderbackend->popClipArea();
00866     }
00867 }