FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator
lightrenderer.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 <SDL.h>
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 #include "video/renderbackend.h"
00032 #include "video/imagepool.h"
00033 #include "video/animation.h"
00034 #include "video/animationpool.h"
00035 #include "video/fonts/abstractfont.h"
00036 #include "video/image.h"
00037 #include "video/opengl/glimage.h"
00038 #include "util/math/fife_math.h"
00039 #include "util/log/logger.h"
00040 #include "util/time/timemanager.h"
00041 #include "model/metamodel/grids/cellgrid.h"
00042 #include "model/metamodel/timeprovider.h"
00043 #include "model/structures/instance.h"
00044 #include "model/structures/layer.h"
00045 #include "model/structures/location.h"
00046 
00047 #include "view/camera.h"
00048 #include "lightrenderer.h"
00049 
00050 
00051 namespace FIFE {
00052     static Logger _log(LM_VIEWVIEW);
00053 
00054     LightRendererNode::LightRendererNode(Instance* attached_instance, const Location &relative_location, Layer* relative_layer, const Point &relative_point):
00055         m_instance(attached_instance),
00056         m_location(relative_location),
00057         m_layer(relative_layer),
00058         m_point(relative_point) {
00059     }
00060     LightRendererNode::LightRendererNode(Instance* attached_instance, const Location &relative_location, const Point &relative_point):
00061         m_instance(attached_instance),
00062         m_location(relative_location),
00063         m_layer(NULL),
00064         m_point(relative_point) {
00065     }
00066     LightRendererNode::LightRendererNode(Instance* attached_instance, Layer* relative_layer, const Point &relative_point):
00067         m_instance(attached_instance),
00068         m_location(NULL),
00069         m_layer(relative_layer),
00070         m_point(relative_point) {
00071     }
00072     LightRendererNode::LightRendererNode(Instance* attached_instance, const Point &relative_point):
00073         m_instance(attached_instance),
00074         m_location(NULL),
00075         m_layer(NULL),
00076         m_point(relative_point) {
00077     }
00078     LightRendererNode::LightRendererNode(const Location &attached_location, Layer* relative_layer, const Point &relative_point):
00079         m_instance(NULL),
00080         m_location(attached_location),
00081         m_layer(relative_layer),
00082         m_point(relative_point) {
00083     }
00084     LightRendererNode::LightRendererNode(const Location &attached_location, const Point &relative_point):
00085         m_instance(NULL),
00086         m_location(attached_location),
00087         m_layer(NULL),
00088         m_point(relative_point) {
00089     }
00090     LightRendererNode::LightRendererNode(Layer* attached_layer, const Point &relative_point):
00091         m_instance(NULL),
00092         m_location(NULL),
00093         m_layer(attached_layer),
00094         m_point(relative_point) {
00095     }
00096     LightRendererNode::LightRendererNode(const Point &attached_point):
00097         m_instance(NULL),
00098         m_location(NULL),
00099         m_layer(NULL),
00100         m_point(attached_point) {
00101     }
00102     LightRendererNode::~LightRendererNode() {
00103     }
00104 
00105     void LightRendererNode::setAttached(Instance* attached_instance, const Location &relative_location, const Point &relative_point) {
00106         m_instance = attached_instance;
00107         m_location = relative_location;
00108         m_point = relative_point;
00109     }
00110     void LightRendererNode::setAttached(Instance* attached_instance, const Location &relative_location) {
00111         m_instance = attached_instance;
00112         m_location = relative_location;
00113     }
00114     void LightRendererNode::setAttached(Instance* attached_instance, const Point &relative_point) {
00115         m_instance = attached_instance;
00116         m_point = relative_point;
00117     }
00118     void LightRendererNode::setAttached(Instance* attached_instance) {
00119         m_instance = attached_instance;
00120     }
00121     void LightRendererNode::setAttached(const Location &attached_location, const Point &relative_point) {
00122         m_instance = NULL;
00123         m_location = attached_location;
00124         m_point = relative_point;
00125     }
00126     void LightRendererNode::setAttached(const Location &attached_location) {
00127         m_instance = NULL;
00128         m_location = attached_location;
00129     }
00130     void LightRendererNode::setAttached(Layer* attached_layer) {
00131         m_layer = attached_layer;
00132     }
00133     void LightRendererNode::setAttached(const Point &attached_point) {
00134         m_instance = NULL;
00135         m_location = NULL;
00136         m_point = attached_point;
00137     }
00138 
00139     void LightRendererNode::setRelative(const Location &relative_location) {
00140         if(m_instance == NULL) {
00141             throw NotSupported("No instance attached.");
00142         }
00143         m_location = relative_location;
00144     }
00145     void LightRendererNode::setRelative(const Location &relative_location, Point relative_point) {
00146         if(m_instance == NULL) {
00147             throw NotSupported("No instance attached.");
00148         }
00149         m_location = relative_location;
00150         m_point = relative_point;
00151     }
00152     void LightRendererNode::setRelative(const Point &relative_point) {
00153         if(m_instance == NULL || m_location == NULL) {
00154             throw NotSupported("No instance or location attached.");
00155         }
00156         m_point = relative_point;
00157     }
00158 
00159     Instance* LightRendererNode::getAttachedInstance() {
00160         if(m_instance == NULL) {
00161             throw NotSupported("No instance attached.");
00162         }
00163         return m_instance;
00164     }
00165     Location LightRendererNode::getAttachedLocation() {
00166         if(m_instance != NULL || m_location == NULL) {
00167             throw NotSupported("No location attached.");
00168         }
00169         return m_location;
00170     }
00171     Layer* LightRendererNode::getAttachedLayer() {
00172         if(m_layer == NULL) {
00173             throw NotSupported("No layer attached.");
00174         }
00175         return m_layer;
00176     }
00177     Point LightRendererNode::getAttachedPoint() {
00178         if(m_instance != NULL || m_location != NULL) {
00179             throw NotSupported("No point attached.");
00180         }
00181         return m_point;
00182     }
00183 
00184     Location LightRendererNode::getOffsetLocation() {
00185         if(m_instance == NULL || m_location == NULL) {
00186             throw NotSupported("No location as offset used.");
00187         }
00188         return m_location;
00189     }
00190     Point LightRendererNode::getOffsetPoint() {
00191         if(m_instance == NULL && m_location == NULL) {
00192             throw NotSupported("No point as offset used.");
00193         }
00194         return m_point;
00195     }
00196 
00197     Instance* LightRendererNode::getInstance() {
00198         return m_instance;
00199     }
00200     Location LightRendererNode::getLocation() {
00201         return m_location;
00202     }
00203     Layer* LightRendererNode::getLayer() {
00204         return m_layer;
00205     }
00206     Point LightRendererNode::getPoint() {
00207         return m_point;
00208     }
00209 
00210     Point LightRendererNode::getCalculatedPoint(Camera* cam, Layer* layer) {
00211         ScreenPoint p;
00212         if(m_instance != NULL) {
00213             if(m_layer == NULL) {
00214                 m_layer = m_instance->getLocation().getLayer();
00215             }
00216             if(m_location != NULL) {
00217                 p = cam->toScreenCoordinates(m_instance->getLocationRef().getMapCoordinates() + m_location.getMapCoordinates());
00218             } else {
00219                 p = cam->toScreenCoordinates(m_instance->getLocation().getMapCoordinates());
00220             }
00221         } else if(m_location != NULL) {
00222             if(m_layer == NULL) {
00223                 m_layer = m_location.getLayer();
00224             }
00225             p = cam->toScreenCoordinates(m_location.getMapCoordinates());
00226         } else if(m_layer == NULL) {
00227             const std::list<Layer*>& layers = cam->getRenderer("LightRenderer")->getActiveLayers();
00228             std::list<Layer*>::const_reverse_iterator layer_it = layers.rbegin();
00229             setAttached(*layer_it);
00230         }
00231         return Point(m_point.x + p.x, m_point.y + p.y);
00232     }
00233 
00234     LightRendererImageInfo::LightRendererImageInfo(LightRendererNode anchor, int image, int src, int dst):
00235         LightRendererElementInfo(),
00236         m_anchor(anchor),
00237         m_image(image),
00238         m_src(src),
00239         m_dst(dst),
00240         m_stencil(false),
00241         m_stencil_ref(0),
00242         m_alpha_ref(0.0) {
00243     }
00244     void LightRendererImageInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend, ImagePool* imagepool, AnimationPool* animpool) {
00245         Point p = m_anchor.getCalculatedPoint(cam, layer);
00246         if(m_anchor.getLayer() == layer) {
00247             Image* img = &imagepool->getImage(m_image);
00248             Rect r;
00249             Rect viewport = cam->getViewPort();
00250             unsigned int widtht = round(img->getWidth() * cam->getZoom());
00251             unsigned int height = round(img->getHeight() * cam->getZoom());
00252             r.x = p.x-widtht/2;
00253             r.y = p.y-height/2;
00254             r.w = widtht;
00255             r.h = height;
00256             renderbackend->changeBlending(m_src, m_dst);
00257             if(r.intersects(viewport))
00258                 img->render(r);
00259         }
00260     }
00261     void LightRendererImageInfo::setStencil(uint8_t stencil_ref, float alpha_ref) {
00262         m_stencil = true;
00263         m_stencil_ref = stencil_ref;
00264         m_alpha_ref = alpha_ref;
00265     }
00266     int LightRendererImageInfo::getStencil() {
00267         if(!m_stencil) {
00268             return -1;
00269         }
00270         return m_stencil_ref;
00271     }
00272     float LightRendererImageInfo::getAlpha() {
00273         return m_alpha_ref;
00274     }
00275     void LightRendererImageInfo::removeStencil() {
00276         m_stencil = false;
00277         m_stencil_ref = 0;
00278         m_alpha_ref = 0.0;
00279     }
00280     
00281     LightRendererAnimationInfo::LightRendererAnimationInfo(LightRendererNode anchor, int animation, int src, int dst):
00282         LightRendererElementInfo(),
00283         m_anchor(anchor),
00284         m_animation(animation),
00285         m_src(src),
00286         m_dst(dst),
00287         m_start_time(TimeManager::instance()->getTime()),
00288         m_time_scale(1.0),
00289         m_stencil(false),
00290         m_stencil_ref(0),
00291         m_alpha_ref(0.0) {
00292     }
00293     void LightRendererAnimationInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend, ImagePool* imagepool, AnimationPool* animpool) { 
00294         Point p = m_anchor.getCalculatedPoint(cam, layer);
00295         if(m_anchor.getLayer() == layer) {
00296             Animation& animation = animpool->getAnimation(m_animation);
00297             int animtime = scaleTime(m_time_scale, TimeManager::instance()->getTime() - m_start_time) % animation.getDuration();
00298             Image* img = animation.getFrameByTimestamp(animtime);
00299             Rect r;
00300             Rect viewport = cam->getViewPort();
00301             unsigned int widtht = round(img->getWidth() * cam->getZoom());
00302             unsigned int height = round(img->getHeight() * cam->getZoom());
00303             r.x = p.x-widtht/2;
00304             r.y = p.y-height/2;
00305             r.w = widtht;
00306             r.h = height;
00307             renderbackend->changeBlending(m_src, m_dst);
00308             if(r.intersects(viewport))
00309                 img->render(r);
00310         }
00311     }
00312     void LightRendererAnimationInfo::setStencil(uint8_t stencil_ref, float alpha_ref) {
00313         m_stencil = true;
00314         m_stencil_ref = stencil_ref;
00315         m_alpha_ref = alpha_ref;
00316     }
00317     int LightRendererAnimationInfo::getStencil() {
00318         if(!m_stencil) {
00319             return -1;
00320         }
00321         return m_stencil_ref;
00322     }
00323     float LightRendererAnimationInfo::getAlpha() {
00324         return m_alpha_ref;
00325     }
00326     void LightRendererAnimationInfo::removeStencil() {
00327         m_stencil = false;
00328         m_stencil_ref = 0;
00329         m_alpha_ref = 0.0;
00330     }
00331 
00332     LightRendererResizeInfo::LightRendererResizeInfo(LightRendererNode anchor, int image, int width, int height, int src, int dst):
00333         LightRendererElementInfo(),
00334         m_anchor(anchor),
00335         m_image(image),
00336         m_width(width),
00337         m_height(height),
00338         m_src(src),
00339         m_dst(dst),
00340         m_stencil(false),
00341         m_stencil_ref(0),
00342         m_alpha_ref(0.0) {
00343     }
00344     void LightRendererResizeInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend, ImagePool* imagepool, AnimationPool* animpool) {
00345         Point p = m_anchor.getCalculatedPoint(cam, layer);
00346         if(m_anchor.getLayer() == layer) {
00347             Image* img = &imagepool->getImage(m_image);
00348             Rect r;
00349             Rect viewport = cam->getViewPort();
00350             unsigned int widtht = round(m_width * cam->getZoom());
00351             unsigned int height = round(m_height * cam->getZoom());
00352             r.x = p.x-widtht/2;
00353             r.y = p.y-height/2;
00354             r.w = widtht;
00355             r.h = height;
00356             renderbackend->changeBlending(m_src, m_dst);
00357             if(r.intersects(viewport))
00358                 img->render(r);
00359         }
00360     }
00361     void LightRendererResizeInfo::setStencil(uint8_t stencil_ref, float alpha_ref) {
00362         m_stencil = true;
00363         m_stencil_ref = stencil_ref;
00364         m_alpha_ref = alpha_ref;
00365     }
00366     int LightRendererResizeInfo::getStencil() {
00367         if(!m_stencil) {
00368             return -1;
00369         }
00370         return m_stencil_ref;
00371     }
00372     float LightRendererResizeInfo::getAlpha() {
00373         return m_alpha_ref;
00374     }
00375     void LightRendererResizeInfo::removeStencil() {
00376         m_stencil = false;
00377         m_stencil_ref = 0;
00378         m_alpha_ref = 0.0;
00379     }
00380 
00381     LightRendererSimpleLightInfo::LightRendererSimpleLightInfo(LightRendererNode anchor, uint8_t intensity, float radius, int subdivisions, float xstretch, float ystretch, uint8_t r, uint8_t g, uint8_t b, int src, int dst):
00382         LightRendererElementInfo(),
00383         m_anchor(anchor),
00384         m_intensity(intensity),
00385         m_radius(radius),
00386         m_subdivisions(subdivisions),
00387         m_xstretch(xstretch),
00388         m_ystretch(ystretch),
00389         m_red(r),
00390         m_green(g),
00391         m_blue(b),
00392         m_src(src),
00393         m_dst(dst),
00394         m_stencil(false),
00395         m_stencil_ref(0),
00396         m_alpha_ref(0.0) {
00397     }
00398     void LightRendererSimpleLightInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend, ImagePool* imagepool, AnimationPool* animpool) {
00399         Point p = m_anchor.getCalculatedPoint(cam, layer);
00400         if(m_anchor.getLayer() == layer) {
00401             double zoom = cam->getZoom();
00402             renderbackend->changeBlending(m_src, m_dst);
00403             renderbackend->drawLightPrimitive(p, m_intensity, m_radius, m_subdivisions, m_xstretch * zoom, m_ystretch * zoom, m_red, m_green, m_blue);
00404         }
00405     }
00406     void LightRendererSimpleLightInfo::setStencil(uint8_t stencil_ref, float alpha_ref) {
00407         m_stencil = true;
00408         m_stencil_ref = stencil_ref;
00409         m_alpha_ref = alpha_ref;
00410     }
00411     int LightRendererSimpleLightInfo::getStencil() {
00412         if(!m_stencil) {
00413             return -1;
00414         }
00415         return m_stencil_ref;
00416     }
00417     float LightRendererSimpleLightInfo::getAlpha() {
00418         return m_alpha_ref;
00419     }
00420     void LightRendererSimpleLightInfo::removeStencil() {
00421         m_stencil = false;
00422         m_stencil_ref = 0;
00423         m_alpha_ref = 0.0;
00424     }
00425     std::vector<uint8_t> LightRendererSimpleLightInfo::getColor() {
00426         std::vector<uint8_t> colors;
00427         colors.push_back(m_red);
00428         colors.push_back(m_green);
00429         colors.push_back(m_blue);
00430         colors.push_back(m_intensity);
00431         return colors;
00432     }
00433 
00434     LightRenderer* LightRenderer::getInstance(IRendererContainer* cnt) {
00435         return dynamic_cast<LightRenderer*>(cnt->getRenderer("LightRenderer"));
00436     }
00437     
00438     LightRenderer::LightRenderer(RenderBackend* renderbackend, int position, ImagePool* imagepool, AnimationPool* animpool):
00439         RendererBase(renderbackend, position),
00440         m_imagepool(imagepool),
00441         m_animationpool(animpool),
00442         m_groups() {
00443         setEnabled(false);
00444     }
00445 
00446     LightRenderer::LightRenderer(const LightRenderer& old):
00447         RendererBase(old),
00448         m_imagepool(old.m_imagepool),
00449         m_animationpool(old.m_animationpool),
00450         m_groups() {
00451         setEnabled(false);
00452     }
00453 
00454     RendererBase* LightRenderer::clone() {
00455         return new LightRenderer(*this);
00456     }
00457 
00458     LightRenderer::~LightRenderer() {
00459     }
00460     // Add a static lightmap
00461     void LightRenderer::addImage(const std::string &group, LightRendererNode n, int image, int src, int dst) {
00462         LightRendererElementInfo* info = new LightRendererImageInfo(n, image, src, dst);
00463         m_groups[group].push_back(info);
00464     }
00465     // Add a animation lightmap
00466     void LightRenderer::addAnimation(const std::string &group, LightRendererNode n, int animation, int src, int dst) {
00467         LightRendererElementInfo* info = new LightRendererAnimationInfo(n, animation, src, dst);
00468         m_groups[group].push_back(info);
00469     }
00470     // Add a simple light
00471     void LightRenderer::addSimpleLight(const std::string &group, LightRendererNode n, uint8_t intensity, float radius, int subdivisions, float xstretch, float ystretch, uint8_t r, uint8_t g, uint8_t b, int src, int dst) {
00472         LightRendererElementInfo* info = new LightRendererSimpleLightInfo(n, intensity, radius, subdivisions, xstretch, ystretch, r, g, b, src, dst);
00473         m_groups[group].push_back(info);
00474     }
00475     // Resize an Image
00476     void LightRenderer::resizeImage(const std::string &group, LightRendererNode n, int image, int width, int height, int src, int dst) {
00477         LightRendererElementInfo* info = new LightRendererResizeInfo(n, image, width, height, src, dst);
00478         m_groups[group].push_back(info);
00479     }
00480     // Enable stencil test for the group
00481     void LightRenderer::addStencilTest(const std::string &group, uint8_t stencil_ref, float alpha_ref) {
00482         std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
00483         for (;info_it != m_groups[group].end(); ++info_it) {
00484             (*info_it)->setStencil(stencil_ref, alpha_ref);
00485         }
00486     }
00487     // Disable stencil test for the group
00488     void LightRenderer::removeStencilTest(const std::string &group) {
00489         std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
00490         for (;info_it != m_groups[group].end(); ++info_it) {
00491             (*info_it)->removeStencil();
00492         }
00493     }
00494     // Return a list of all groups
00495     std::list<std::string> LightRenderer::getGroups() {
00496         std::list<std::string> groups;
00497         std::map<std::string, std::vector<LightRendererElementInfo*> >::iterator group_it = m_groups.begin();
00498         for(; group_it != m_groups.end(); ++group_it) {
00499             groups.push_back(group_it->first);
00500         }
00501         groups.sort();
00502         groups.unique();
00503         return groups;
00504     }
00505     // Return a vector of all LightElementInfos
00506     std::vector<LightRendererElementInfo*> LightRenderer::getLightInfo(const std::string &group) {
00507         std::vector<LightRendererElementInfo*> info;
00508         std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
00509         for (;info_it != m_groups[group].end(); ++info_it) {
00510             info.push_back(*info_it);
00511         }
00512         return info;
00513     }
00514     // Remove the group
00515     void LightRenderer::removeAll(const std::string &group) {
00516         std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
00517         for (;info_it != m_groups[group].end(); ++info_it) {
00518             delete *info_it;
00519         }
00520         m_groups[group].clear();
00521         m_groups.erase(group);
00522     }
00523     // Render
00524     void LightRenderer::render(Camera* cam, Layer* layer, RenderList& instances) {
00525         uint8_t lm = m_renderbackend->getLightingModel();
00526         
00527         if (!layer->areInstancesVisible()) {
00528             return;
00529         }
00530         m_renderbackend->disableLighting();
00531         std::map<std::string, std::vector<LightRendererElementInfo*> >::iterator group_it = m_groups.begin();
00532         for (; group_it != m_groups.end(); ++group_it) {
00533             std::vector<LightRendererElementInfo*>::const_iterator info_it = group_it->second.begin();
00534             for (;info_it != group_it->second.end(); ++info_it) {
00535                 if (lm != 0) {
00536                     if ((*info_it)->getStencil() != -1) {
00537                         uint8_t sref = (*info_it)->getStencil();
00538                         float aref = (*info_it)->getAlpha();
00539                         if(info_it != group_it->second.begin())
00540                             sref += 1;
00541                         m_renderbackend->setStencilTest(sref, 3, 4);
00542                         m_renderbackend->setAlphaTest(aref);
00543                     } else if(lm == 1) {
00544                         m_renderbackend->setStencilTest(255, 0, 6);
00545                         m_renderbackend->setAlphaTest(0);
00546                     } else if(lm == 2) {
00547                         m_renderbackend->setStencilTest(1, 2, 4);
00548                         m_renderbackend->setAlphaTest(0);
00549                     }
00550                     (*info_it)->render(cam, layer, instances, m_renderbackend, m_imagepool, m_animationpool);
00551                     m_renderbackend->disableAlphaTest();
00552                     m_renderbackend->disableStencilTest();
00553                 } else {
00554                     (*info_it)->render(cam, layer, instances, m_renderbackend, m_imagepool, m_animationpool);
00555                 }
00556             }
00557         }
00558         m_renderbackend->changeBlending(4, 5);
00559         m_renderbackend->enableLighting();
00560     }
00561 
00562 }