lightrenderer.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005-2011 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/animation.h"
00033 #include "video/fonts/ifont.h"
00034 #include "video/imagemanager.h"
00035 #include "video/image.h"
00036 #include "video/opengl/glimage.h"
00037 #include "video/opengle/gleimage.h"
00038 #include "video/opengl/renderbackendopengl.h"
00039 #include "video/opengle/renderbackendopengle.h"
00040 #include "util/math/fife_math.h"
00041 #include "util/log/logger.h"
00042 #include "util/time/timemanager.h"
00043 #include "model/metamodel/grids/cellgrid.h"
00044 #include "model/metamodel/timeprovider.h"
00045 #include "model/structures/instance.h"
00046 #include "model/structures/layer.h"
00047 #include "model/structures/location.h"
00048 
00049 #include "view/camera.h"
00050 #include "lightrenderer.h"
00051 
00052 
00053 namespace FIFE {
00054     static Logger _log(LM_VIEWVIEW);
00055 
00056     LightRendererElementInfo::LightRendererElementInfo(RendererNode n, int32_t src, int32_t dst):
00057         m_anchor(n),
00058         m_src(src),
00059         m_dst(dst),
00060         m_stencil(false),
00061         m_stencil_ref(0) {
00062     }
00063     void LightRendererElementInfo::setStencil(uint8_t stencil_ref) {
00064         m_stencil = true;
00065         m_stencil_ref = stencil_ref;
00066     }
00067     int32_t LightRendererElementInfo::getStencil() {
00068         if(!m_stencil) {
00069             return -1;
00070         }
00071         return m_stencil_ref;
00072     }
00073     void LightRendererElementInfo::removeStencil() {
00074         m_stencil = false;
00075         m_stencil_ref = 0;
00076     }
00077     LightRendererImageInfo::LightRendererImageInfo(RendererNode anchor, ImagePtr image, int32_t src, int32_t dst):
00078         LightRendererElementInfo(anchor, src, dst),
00079         m_image(image){
00080     }
00081     void LightRendererImageInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend) {
00082         Point p = m_anchor.getCalculatedPoint(cam, layer);
00083         if(m_anchor.getLayer() == layer) {
00084             Rect r;
00085             Rect viewport = cam->getViewPort();
00086             uint32_t width = static_cast<uint32_t>(round(m_image->getWidth() * cam->getZoom()));
00087             uint32_t height = static_cast<uint32_t>(round(m_image->getHeight() * cam->getZoom()));
00088             r.x = p.x-width/2;
00089             r.y = p.y-height/2;
00090             r.w = width;
00091             r.h = height;
00092 
00093             if(r.intersects(viewport)) {
00094                 uint8_t lm = renderbackend->getLightingModel();
00095                 m_image->render(r);
00096                 if (m_stencil) {
00097                     renderbackend->changeRenderInfos(1, m_src, m_dst, false, true, m_stencil_ref, INCR, GEQUAL);
00098                 } else if (lm == 1) {
00099                     renderbackend->changeRenderInfos(1, m_src, m_dst, false, true, 255, KEEP, NOTEQUAL);
00100                 }
00101             }
00102         }
00103     }
00104     LightRendererAnimationInfo::LightRendererAnimationInfo(RendererNode anchor, AnimationPtr animation, int32_t src, int32_t dst):
00105         LightRendererElementInfo(anchor, src, dst),
00106         m_animation(animation),
00107         m_start_time(TimeManager::instance()->getTime()),
00108         m_time_scale(1.0){
00109     }
00110     void LightRendererAnimationInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend) {
00111         Point p = m_anchor.getCalculatedPoint(cam, layer);
00112         if(m_anchor.getLayer() == layer) {
00113             int32_t animtime = scaleTime(m_time_scale, TimeManager::instance()->getTime() - m_start_time) % m_animation->getDuration();
00114             ImagePtr img = m_animation->getFrameByTimestamp(animtime);
00115             Rect r;
00116             Rect viewport = cam->getViewPort();
00117             uint32_t width = static_cast<uint32_t>(round(img->getWidth() * cam->getZoom()));
00118             uint32_t height = static_cast<uint32_t>(round(img->getHeight() * cam->getZoom()));
00119             r.x = p.x-width/2;
00120             r.y = p.y-height/2;
00121             r.w = width;
00122             r.h = height;
00123 
00124             if(r.intersects(viewport)) {
00125                 uint8_t lm = renderbackend->getLightingModel();
00126                 img->render(r);
00127                 if (m_stencil) {
00128                     renderbackend->changeRenderInfos(1, m_src, m_dst, false, true, m_stencil_ref, INCR, GEQUAL);
00129                 } else if (lm == 1) {
00130                     renderbackend->changeRenderInfos(1, m_src, m_dst, false, true, 255, KEEP, NOTEQUAL);
00131                 }
00132             }
00133         }
00134     }
00135     LightRendererResizeInfo::LightRendererResizeInfo(RendererNode anchor, ImagePtr image, int32_t width, int32_t height, int32_t src, int32_t dst):
00136         LightRendererElementInfo(anchor, src, dst),
00137         m_image(image),
00138         m_width(width),
00139         m_height(height) {
00140     }
00141     void LightRendererResizeInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend) {
00142         Point p = m_anchor.getCalculatedPoint(cam, layer);
00143         if(m_anchor.getLayer() == layer) {
00144             Rect r;
00145             Rect viewport = cam->getViewPort();
00146             uint32_t width = static_cast<uint32_t>(round(m_width * cam->getZoom()));
00147             uint32_t height = static_cast<uint32_t>(round(m_height * cam->getZoom()));
00148             r.x = p.x-width/2;
00149             r.y = p.y-height/2;
00150             r.w = width;
00151             r.h = height;
00152 
00153             if(r.intersects(viewport)) {
00154                 uint8_t lm = renderbackend->getLightingModel();
00155                 m_image->render(r);
00156                 if (m_stencil) {
00157                     renderbackend->changeRenderInfos(1, m_src, m_dst, false, true, m_stencil_ref, INCR, GEQUAL);
00158                 } else if (lm == 1) {
00159                     renderbackend->changeRenderInfos(1, m_src, m_dst, false, true, 255, KEEP, NOTEQUAL);
00160                 }
00161             }
00162         }
00163     }
00164     LightRendererSimpleLightInfo::LightRendererSimpleLightInfo(RendererNode anchor, uint8_t intensity, float radius, int32_t subdivisions, float xstretch, float ystretch, uint8_t r, uint8_t g, uint8_t b, int32_t src, int32_t dst):
00165         LightRendererElementInfo(anchor, src, dst),
00166         m_intensity(intensity),
00167         m_radius(radius),
00168         m_subdivisions(subdivisions),
00169         m_xstretch(xstretch),
00170         m_ystretch(ystretch),
00171         m_red(r),
00172         m_green(g),
00173         m_blue(b){
00174     }
00175     void LightRendererSimpleLightInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend) {
00176         Point p = m_anchor.getCalculatedPoint(cam, layer);
00177         if(m_anchor.getLayer() == layer) {
00178             double zoom = cam->getZoom();
00179 
00180             uint8_t lm = renderbackend->getLightingModel();
00181             renderbackend->drawLightPrimitive(p, m_intensity, m_radius, m_subdivisions,
00182                 static_cast<float>(m_xstretch * zoom), static_cast<float>(m_ystretch * zoom),
00183                 m_red, m_green, m_blue);
00184 
00185             if (m_stencil) {
00186                 renderbackend->changeRenderInfos(m_subdivisions, m_src, m_dst, false, true, m_stencil_ref, INCR, GEQUAL);
00187             } else if (lm == 1) {
00188                 renderbackend->changeRenderInfos(m_subdivisions, m_src, m_dst, false, true, 255, KEEP, NOTEQUAL);
00189             }
00190         }
00191     }
00192     std::vector<uint8_t> LightRendererSimpleLightInfo::getColor() {
00193         std::vector<uint8_t> colors;
00194         colors.push_back(m_red);
00195         colors.push_back(m_green);
00196         colors.push_back(m_blue);
00197         colors.push_back(m_intensity);
00198         return colors;
00199     }
00200     LightRenderer* LightRenderer::getInstance(IRendererContainer* cnt) {
00201         return dynamic_cast<LightRenderer*>(cnt->getRenderer("LightRenderer"));
00202     }
00203     LightRenderer::LightRenderer(RenderBackend* renderbackend, int32_t position):
00204         RendererBase(renderbackend, position),
00205         m_groups() {
00206         setEnabled(false);
00207     }
00208     LightRenderer::LightRenderer(const LightRenderer& old):
00209         RendererBase(old),
00210         m_groups() {
00211         setEnabled(false);
00212     }
00213     RendererBase* LightRenderer::clone() {
00214         return new LightRenderer(*this);
00215     }
00216     LightRenderer::~LightRenderer() {
00217     }
00218     // Add a static lightmap
00219     void LightRenderer::addImage(const std::string &group, RendererNode n, ImagePtr image, int32_t src, int32_t dst) {
00220         LightRendererElementInfo* info = new LightRendererImageInfo(n, image, src, dst);
00221         m_groups[group].push_back(info);
00222     }
00223     // Add a animation lightmap
00224     void LightRenderer::addAnimation(const std::string &group, RendererNode n, AnimationPtr animation, int32_t src, int32_t dst) {
00225         LightRendererElementInfo* info = new LightRendererAnimationInfo(n, animation, src, dst);
00226         m_groups[group].push_back(info);
00227     }
00228     // Add a simple light
00229     void LightRenderer::addSimpleLight(const std::string &group, RendererNode n, uint8_t intensity, float radius, int32_t subdivisions, float xstretch, float ystretch, uint8_t r, uint8_t g, uint8_t b, int32_t src, int32_t dst) {
00230         LightRendererElementInfo* info = new LightRendererSimpleLightInfo(n, intensity, radius, subdivisions, xstretch, ystretch, r, g, b, src, dst);
00231         m_groups[group].push_back(info);
00232     }
00233     // Resize an Image
00234     void LightRenderer::resizeImage(const std::string &group, RendererNode n, ImagePtr image, int32_t width, int32_t height, int32_t src, int32_t dst) {
00235         LightRendererElementInfo* info = new LightRendererResizeInfo(n, image, width, height, src, dst);
00236         m_groups[group].push_back(info);
00237     }
00238     // Enable stencil test for the group
00239     void LightRenderer::addStencilTest(const std::string &group, uint8_t stencil_ref) {
00240         std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
00241         for (;info_it != m_groups[group].end(); ++info_it) {
00242             (*info_it)->setStencil(stencil_ref);
00243         }
00244     }
00245     // Disable stencil test for the group
00246     void LightRenderer::removeStencilTest(const std::string &group) {
00247         std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
00248         for (;info_it != m_groups[group].end(); ++info_it) {
00249             (*info_it)->removeStencil();
00250         }
00251     }
00252     // Return a list of all groups
00253     std::list<std::string> LightRenderer::getGroups() {
00254         std::list<std::string> groups;
00255         std::map<std::string, std::vector<LightRendererElementInfo*> >::iterator group_it = m_groups.begin();
00256         for(; group_it != m_groups.end(); ++group_it) {
00257             groups.push_back(group_it->first);
00258         }
00259         groups.sort();
00260         groups.unique();
00261         return groups;
00262     }
00263     // Return a vector of all LightElementInfos
00264     std::vector<LightRendererElementInfo*> LightRenderer::getLightInfo(const std::string &group) {
00265         std::vector<LightRendererElementInfo*> info;
00266         std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
00267         for (;info_it != m_groups[group].end(); ++info_it) {
00268             info.push_back(*info_it);
00269         }
00270         return info;
00271     }
00272     // Remove the group
00273     void LightRenderer::removeAll(const std::string &group) {
00274         std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
00275         for (;info_it != m_groups[group].end(); ++info_it) {
00276             delete *info_it;
00277         }
00278         m_groups[group].clear();
00279         m_groups.erase(group);
00280     }
00281     // Remove all groups
00282     void LightRenderer::removeAll() {
00283         m_groups.clear();
00284     }
00285     // Clear all groups
00286     void LightRenderer::reset() {
00287         removeAll();
00288     }
00289     // Render
00290     void LightRenderer::render(Camera* cam, Layer* layer, RenderList& instances) {
00291         uint8_t lm = m_renderbackend->getLightingModel();
00292 
00293         if (!layer->areInstancesVisible()) {
00294             return;
00295         }
00296 
00297         std::map<std::string, std::vector<LightRendererElementInfo*> >::iterator group_it = m_groups.begin();
00298         for (; group_it != m_groups.end(); ++group_it) {
00299             std::vector<LightRendererElementInfo*>::const_iterator info_it = group_it->second.begin();
00300             for (;info_it != group_it->second.end(); ++info_it) {
00301                 if (lm != 0) {
00302                     if ((*info_it)->getStencil() != -1 && (*info_it)->getStencil() < 255) {
00303                         if(info_it != group_it->second.begin()) {
00304                             (*info_it)->setStencil((*info_it)->getStencil()+1);
00305                         }
00306                     }
00307                 }
00308                 (*info_it)->render(cam, layer, instances, m_renderbackend);
00309             }
00310         }
00311     }
00312 
00313 }