instancerenderer.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 #include "video/renderbackend.h"
00031 #include "video/image.h"
00032 #include "video/sdl/sdlimage.h"
00033 #include "video/imagepool.h"
00034 #include "video/animation.h"
00035 #include "video/animationpool.h"
00036 #include "util/math/fife_math.h"
00037 #include "util/log/logger.h"
00038 #include "model/metamodel/grids/cellgrid.h"
00039 #include "model/metamodel/action.h"
00040 #include "model/structures/instance.h"
00041 #include "model/structures/layer.h"
00042 #include "model/structures/location.h"
00043 
00044 #include "view/camera.h"
00045 #include "view/visual.h"
00046 #include "instancerenderer.h"
00047 
00048 namespace {
00049     unsigned int scale(unsigned int val, double factor) {
00050         return static_cast<unsigned int>(ceil(static_cast<double>(val) * factor));
00051     }
00052 }
00053 
00054 namespace FIFE {
00055     static Logger _log(LM_VIEWVIEW);
00056 
00057     InstanceRenderer::OutlineInfo::OutlineInfo():
00058         r(0),
00059         g(0),
00060         b(0),
00061         width(1),
00062         outline(NULL),
00063         curimg(NULL) {
00064     }
00065     InstanceRenderer::ColoringInfo::ColoringInfo():
00066         r(0),
00067         g(0),
00068         b(0),
00069         overlay(NULL),
00070         curimg(NULL) {
00071     }
00072 
00073     InstanceRenderer::OutlineInfo::~OutlineInfo() {
00074         delete outline;
00075     }
00076 
00077     InstanceRenderer::ColoringInfo::~ColoringInfo() {
00078         delete overlay;
00079     }
00080 
00081     InstanceRenderer* InstanceRenderer::getInstance(IRendererContainer* cnt) {
00082         return dynamic_cast<InstanceRenderer*>(cnt->getRenderer("InstanceRenderer"));
00083     }
00084 
00085     InstanceRenderer::InstanceRenderer(RenderBackend* renderbackend, int position, ImagePool* imagepool, AnimationPool* animpool):
00086         RendererBase(renderbackend, position),
00087         m_imagepool(imagepool),
00088         m_animationpool(animpool) {
00089         setEnabled(true);
00090     }
00091 
00092     InstanceRenderer::InstanceRenderer(const InstanceRenderer& old):
00093         RendererBase(old),
00094         m_imagepool(old.m_imagepool),
00095         m_animationpool(old.m_animationpool) {
00096         setEnabled(true);
00097     }
00098 
00099     RendererBase* InstanceRenderer::clone() {
00100         return new InstanceRenderer(*this);
00101     }
00102 
00103     InstanceRenderer::~InstanceRenderer() {
00104     }
00105 
00106     void InstanceRenderer::render(Camera* cam, Layer* layer, std::vector<Instance*>& instances) {
00107         // patch #335 by abeyer
00108         if (!layer->areInstancesVisible()) {
00109             FL_DBG(_log, "Layer instances hidden");
00110             return;
00111         }
00112 
00113         FL_DBG(_log, "Iterating layer...");
00114         CellGrid* cg = layer->getCellGrid();
00115         if (!cg) {
00116             FL_WARN(_log, "No cellgrid assigned to layer, cannot draw instances");
00117             return;
00118         }
00119 
00120         const bool any_effects = !(m_instance_outlines.empty() && m_instance_colorings.empty());
00121 
00122         std::vector<Instance*>::const_iterator instance_it = instances.begin();
00123         for (;instance_it != instances.end(); ++instance_it) {
00124             FL_DBG(_log, "Iterating instances...");
00125             Instance* instance = (*instance_it);
00126             InstanceVisual* visual = instance->getVisual<InstanceVisual>();
00127 
00128             unsigned char trans = visual->getTransparency();
00129 
00135             if (trans == 0) {
00136                 unsigned char layer_trans = layer->getLayerTransparency();
00137                 trans = layer_trans;
00138             }
00139 
00140             InstanceVisualCacheItem& vc = visual->getCacheItem(cam);
00141             FL_DBG(_log, LMsg("Instance layer coordinates = ") << instance->getLocationRef().getLayerCoordinates());
00142 
00143             if (any_effects) {
00144                 InstanceToOutlines_t::iterator outline_it = m_instance_outlines.find(instance);
00145                 if (outline_it != m_instance_outlines.end()) {
00146                     bindOutline(outline_it->second, vc, cam)->render(vc.dimensions, 255-trans);
00147                 }
00148 
00149                 InstanceToColoring_t::iterator coloring_it = m_instance_colorings.find(instance);
00150                 if (coloring_it != m_instance_colorings.end()) {
00151                     bindColoring(coloring_it->second, vc, cam)->render(vc.dimensions, 255-trans);
00152                     continue; // Skip normal rendering after drawing overlay
00153                 }
00154             }
00155 
00156             vc.image->render(vc.dimensions, 255-trans);
00157         }
00158     }
00159 
00160     Image* InstanceRenderer::bindOutline(OutlineInfo& info, InstanceVisualCacheItem& vc, Camera* cam) {
00161         if (info.curimg == vc.image) {
00162             return info.outline;
00163         } else {
00164             info.curimg = vc.image;
00165         }
00166 
00167         if (info.outline) {
00168             delete info.outline; // delete old mask
00169             info.outline = NULL;
00170         }
00171         SDL_Surface* surface = vc.image->getSurface();
00172         SDL_Surface* outline_surface = SDL_ConvertSurface(surface, surface->format, surface->flags);
00173 
00174         // needs to use SDLImage here, since GlImage does not support drawing primitives atm
00175         SDLImage* img = new SDLImage(outline_surface);
00176 
00177         // TODO: optimize...
00178         uint8_t r, g, b, a = 0;
00179 
00180         // vertical sweep
00181         for (unsigned int x = 0; x < img->getWidth(); x ++) {
00182             uint8_t prev_a = 0;
00183             for (unsigned int y = 0; y < img->getHeight(); y ++) {
00184                 vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
00185                 if ((a == 0 || prev_a == 0) && (a != prev_a)) {
00186                     if (a < prev_a) {
00187                         for (unsigned int yy = y; yy < y + info.width; yy++) {
00188                             img->putPixel(x, yy, info.r, info.g, info.b);
00189                         }
00190                     } else {
00191                         for (unsigned int yy = y - info.width; yy < y; yy++) {
00192                             img->putPixel(x, yy, info.r, info.g, info.b);
00193                         }
00194                     }
00195                 }
00196                 prev_a = a;
00197             }
00198         }
00199         // horizontal sweep
00200         for (unsigned int y = 0; y < img->getHeight(); y ++) {
00201             uint8_t prev_a = 0;
00202             for (unsigned int x = 0; x < img->getWidth(); x ++) {
00203                 vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
00204                 if ((a == 0 || prev_a == 0) && (a != prev_a)) {
00205                     if (a < prev_a) {
00206                         for (unsigned int xx = x; xx < x + info.width; xx++) {
00207                             img->putPixel(xx, y, info.r, info.g, info.b);
00208                         }
00209                     } else {
00210                         for (unsigned int xx = x - info.width; xx < x; xx++) {
00211                             img->putPixel(xx, y, info.r, info.g, info.b);
00212                         }
00213                     }
00214                 }
00215                 prev_a = a;
00216             }
00217         }
00218 
00219         // In case of OpenGL backend, SDLImage needs to be converted
00220         info.outline = m_renderbackend->createImage(img->detachSurface());
00221         delete img;
00222         return info.outline;
00223     }
00224 
00225     Image* InstanceRenderer::bindColoring(ColoringInfo& info, InstanceVisualCacheItem& vc, Camera* cam) {
00226         if (info.curimg == vc.image) {
00227             return info.overlay;
00228         } else {
00229             info.curimg = vc.image;
00230         }
00231         if (info.overlay) {
00232             delete info.overlay; // delete old mask
00233             info.overlay = NULL;
00234         }
00235         SDL_Surface* surface = vc.image->getSurface();
00236         SDL_Surface* overlay_surface = SDL_ConvertSurface(surface, surface->format, surface->flags);
00237 
00238         // needs to use SDLImage here, since GlImage does not support drawing primitives atm
00239         SDLImage* img = new SDLImage(overlay_surface);
00240 
00241         uint8_t r, g, b, a = 0;
00242 
00243         for (unsigned int x = 0; x < img->getWidth(); x ++) {
00244             for (unsigned int y = 0; y < img->getHeight(); y ++) {
00245                 vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
00246                 if (a > 0) {
00247                     img->putPixel(x, y, (r + info.r) >> 1, (g + info.g) >> 1, (b + info.b) >> 1);
00248                 }
00249             }
00250         }
00251 
00252         // In case of OpenGL backend, SDLImage needs to be converted
00253         info.overlay = m_renderbackend->createImage(img->detachSurface());
00254         delete img;
00255         return info.overlay;
00256     }
00257 
00258     void InstanceRenderer::addOutlined(Instance* instance, int r, int g, int b, int width) {
00259         OutlineInfo info;
00260         info.r = r;
00261         info.g = g;
00262         info.b = b;
00263         info.width = width;
00264 
00265         m_instance_outlines[instance] = info;
00266     }
00267 
00268     void InstanceRenderer::addColored(Instance* instance, int r, int g, int b) {
00269         ColoringInfo info;
00270         info.r = r;
00271         info.g = g;
00272         info.b = b;
00273 
00274         m_instance_colorings[instance] = info;
00275     }
00276 
00277     void InstanceRenderer::removeOutlined(Instance* instance) {
00278         m_instance_outlines.erase(instance);
00279     }
00280 
00281     void InstanceRenderer::removeColored(Instance* instance) {
00282         m_instance_colorings.erase(instance);
00283     }
00284 
00285     void InstanceRenderer::removeAllOutlines() {
00286         m_instance_outlines.clear();
00287     }
00288 
00289     void InstanceRenderer::removeAllColored() {
00290         m_instance_colorings.clear();
00291     }
00292 
00293     void InstanceRenderer::reset() {
00294         removeAllOutlines();
00295         removeAllColored();
00296     }
00297 
00298 }