FIFE
2008.0
|
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 #include "video/opengl/fife_opengl.h" 00044 00045 #include "view/camera.h" 00046 #include "view/visual.h" 00047 #include "instancerenderer.h" 00048 00049 00050 namespace { 00051 unsigned int scale(unsigned int val, double factor) { 00052 return static_cast<unsigned int>(ceil(static_cast<double>(val) * factor)); 00053 } 00054 } 00055 00056 namespace FIFE { 00057 static Logger _log(LM_VIEWVIEW); 00058 00059 InstanceRenderer::OutlineInfo::OutlineInfo(): 00060 r(0), 00061 g(0), 00062 b(0), 00063 width(1), 00064 dirty(false), 00065 outline(NULL), 00066 curimg(NULL) { 00067 } 00068 InstanceRenderer::ColoringInfo::ColoringInfo(): 00069 r(0), 00070 g(0), 00071 b(0), 00072 dirty(false), 00073 overlay(NULL), 00074 curimg(NULL) { 00075 } 00076 00077 InstanceRenderer::AreaInfo::AreaInfo(): 00078 instance(NULL), 00079 groups(), 00080 w(1), 00081 h(1), 00082 trans(0), 00083 front(true), 00084 z(0) { 00085 } 00086 00087 InstanceRenderer::OutlineInfo::~OutlineInfo() { 00088 delete outline; 00089 } 00090 00091 InstanceRenderer::ColoringInfo::~ColoringInfo() { 00092 delete overlay; 00093 } 00094 00095 InstanceRenderer::AreaInfo::~AreaInfo() { 00096 } 00097 00098 InstanceRenderer* InstanceRenderer::getInstance(IRendererContainer* cnt) { 00099 return dynamic_cast<InstanceRenderer*>(cnt->getRenderer("InstanceRenderer")); 00100 } 00101 00102 InstanceRenderer::InstanceRenderer(RenderBackend* renderbackend, int position, ImagePool* imagepool, AnimationPool* animpool): 00103 RendererBase(renderbackend, position), 00104 m_imagepool(imagepool), 00105 m_animationpool(animpool), 00106 m_area_layer(false) { 00107 setEnabled(true); 00108 } 00109 00110 InstanceRenderer::InstanceRenderer(const InstanceRenderer& old): 00111 RendererBase(old), 00112 m_imagepool(old.m_imagepool), 00113 m_animationpool(old.m_animationpool), 00114 m_area_layer(old.m_area_layer) { 00115 setEnabled(true); 00116 } 00117 00118 RendererBase* InstanceRenderer::clone() { 00119 return new InstanceRenderer(*this); 00120 } 00121 00122 InstanceRenderer::~InstanceRenderer() { 00123 } 00124 00125 void InstanceRenderer::render(Camera* cam, Layer* layer, RenderList& instances) { 00126 FL_DBG(_log, "Iterating layer..."); 00127 CellGrid* cg = layer->getCellGrid(); 00128 if (!cg) { 00129 FL_WARN(_log, "No cellgrid assigned to layer, cannot draw instances"); 00130 return; 00131 } 00132 00133 const bool any_effects = !(m_instance_outlines.empty() && m_instance_colorings.empty()); 00134 const bool unlit = !m_unlit_groups.empty(); 00135 unsigned int lm = m_renderbackend->getLightingModel(); 00136 00137 m_area_layer = false; 00138 if(!m_instance_areas.empty()) { 00139 InstanceToAreas_t::iterator area_it = m_instance_areas.begin(); 00140 for(;area_it != m_instance_areas.end(); area_it++) { 00141 AreaInfo& info = area_it->second; 00142 if(info.instance->getLocation().getLayer() == layer) { 00143 if(info.front) { 00144 DoublePoint3D instance_posv = cam->toVirtualScreenCoordinates(info.instance->getLocation().getMapCoordinates()); 00145 info.z = instance_posv.z; 00146 } 00147 m_area_layer = true; 00148 } 00149 } 00150 } 00151 00152 RenderList::iterator instance_it = instances.begin(); 00153 for (;instance_it != instances.end(); ++instance_it) { 00154 FL_DBG(_log, "Iterating instances..."); 00155 Instance* instance = (*instance_it)->instance; 00156 RenderItem& vc = **instance_it; 00157 00158 if(m_area_layer) { 00159 InstanceToAreas_t::iterator areas_it = m_instance_areas.begin(); 00160 for(;areas_it != m_instance_areas.end(); areas_it++) { 00161 AreaInfo& infoa = areas_it->second; 00162 if(infoa.front) { 00163 if(infoa.z >= vc.screenpoint.z) { 00164 continue; 00165 } 00166 } 00167 00168 std::string str_name = instance->getObject()->getNamespace(); 00169 std::list<std::string>::iterator group_it = infoa.groups.begin(); 00170 for(;group_it != infoa.groups.end(); ++group_it) { 00171 if(str_name.find((*group_it)) != std::string::npos) { 00172 ScreenPoint p; 00173 Rect rec; 00174 p = cam->toScreenCoordinates(infoa.instance->getLocation().getMapCoordinates()); 00175 rec.x = p.x - infoa.w / 2; 00176 rec.y = p.y - infoa.h / 2; 00177 rec.w = infoa.w; 00178 rec.h = infoa.h; 00179 if(infoa.instance != instance && vc.dimensions.intersects(rec)) { 00180 vc.transparency = 255 - infoa.trans; 00181 } 00182 } 00183 } 00184 } 00185 } 00186 00187 FL_DBG(_log, LMsg("Instance layer coordinates = ") << instance->getLocationRef().getLayerCoordinates()); 00188 00189 if (any_effects) { 00190 InstanceToOutlines_t::iterator outline_it = m_instance_outlines.find(instance); 00191 if (outline_it != m_instance_outlines.end()) { 00192 if (lm != 0) { 00193 m_renderbackend->disableLighting(); 00194 m_renderbackend->setStencilTest(255, 2, 7); 00195 m_renderbackend->setAlphaTest(0.0); 00196 bindOutline(outline_it->second, vc, cam)->render(vc.dimensions, vc.transparency); 00197 m_renderbackend->enableLighting(); 00198 m_renderbackend->setStencilTest(0, 2, 7); 00199 vc.image->render(vc.dimensions, vc.transparency); 00200 m_renderbackend->disableAlphaTest(); 00201 m_renderbackend->disableStencilTest(); 00202 continue; 00203 } 00204 bindOutline(outline_it->second, vc, cam)->render(vc.dimensions, vc.transparency); 00205 } 00206 00207 InstanceToColoring_t::iterator coloring_it = m_instance_colorings.find(instance); 00208 if (coloring_it != m_instance_colorings.end()) { 00209 m_renderbackend->disableLighting(); 00210 bindColoring(coloring_it->second, vc, cam)->render(vc.dimensions, vc.transparency); 00211 m_renderbackend->enableLighting(); 00212 continue; // Skip normal rendering after drawing overlay 00213 } 00214 } 00215 if(lm != 0) { 00216 if(unlit) { 00217 bool found = false; 00218 std::string lit_name = instance->getObject()->getNamespace(); 00219 std::list<std::string>::iterator unlit_it = m_unlit_groups.begin(); 00220 for(;unlit_it != m_unlit_groups.end(); ++unlit_it) { 00221 if(lit_name.find(*unlit_it) != std::string::npos) { 00222 m_renderbackend->setStencilTest(255, 2, 7); 00223 found = true; 00224 break; 00225 } 00226 } 00227 // This is very expensiv, we have to change it 00228 if(!found) 00229 m_renderbackend->setStencilTest(0, 1, 7); 00230 00231 m_renderbackend->setAlphaTest(0.0); 00232 vc.image->render(vc.dimensions, vc.transparency); 00233 continue; 00234 } 00235 } 00236 vc.image->render(vc.dimensions, vc.transparency); 00237 00238 } 00239 if(lm != 0) { 00240 m_renderbackend->disableAlphaTest(); 00241 m_renderbackend->disableStencilTest(); 00242 } 00243 } 00244 00245 Image* InstanceRenderer::bindOutline(OutlineInfo& info, RenderItem& vc, Camera* cam) { 00246 if (!info.dirty && info.curimg == vc.image) { 00247 // optimization for outline that has not changed 00248 return info.outline; 00249 } else { 00250 info.curimg = vc.image; 00251 } 00252 00253 if (info.outline) { 00254 delete info.outline; // delete old mask 00255 info.outline = NULL; 00256 } 00257 SDL_Surface* surface = vc.image->getSurface(); 00258 SDL_Surface* outline_surface = SDL_ConvertSurface(surface, surface->format, surface->flags); 00259 00260 // needs to use SDLImage here, since GlImage does not support drawing primitives atm 00261 SDLImage* img = new SDLImage(outline_surface); 00262 00263 // TODO: optimize... 00264 uint8_t r, g, b, a = 0; 00265 00266 // vertical sweep 00267 for (unsigned int x = 0; x < img->getWidth(); x ++) { 00268 uint8_t prev_a = 0; 00269 for (unsigned int y = 0; y < img->getHeight(); y ++) { 00270 vc.image->getPixelRGBA(x, y, &r, &g, &b, &a); 00271 if ((a == 0 || prev_a == 0) && (a != prev_a)) { 00272 if (a < prev_a) { 00273 for (unsigned int yy = y; yy < y + info.width; yy++) { 00274 img->putPixel(x, yy, info.r, info.g, info.b); 00275 } 00276 } else { 00277 for (unsigned int yy = y - info.width; yy < y; yy++) { 00278 img->putPixel(x, yy, info.r, info.g, info.b); 00279 } 00280 } 00281 } 00282 prev_a = a; 00283 } 00284 } 00285 // horizontal sweep 00286 for (unsigned int y = 0; y < img->getHeight(); y ++) { 00287 uint8_t prev_a = 0; 00288 for (unsigned int x = 0; x < img->getWidth(); x ++) { 00289 vc.image->getPixelRGBA(x, y, &r, &g, &b, &a); 00290 if ((a == 0 || prev_a == 0) && (a != prev_a)) { 00291 if (a < prev_a) { 00292 for (unsigned int xx = x; xx < x + info.width; xx++) { 00293 img->putPixel(xx, y, info.r, info.g, info.b); 00294 } 00295 } else { 00296 for (unsigned int xx = x - info.width; xx < x; xx++) { 00297 img->putPixel(xx, y, info.r, info.g, info.b); 00298 } 00299 } 00300 } 00301 prev_a = a; 00302 } 00303 } 00304 00305 // In case of OpenGL backend, SDLImage needs to be converted 00306 info.outline = m_renderbackend->createImage(img->detachSurface()); 00307 delete img; 00308 00309 if (info.outline) { 00310 // mark outline as not dirty since we created it here 00311 info.dirty = false; 00312 } 00313 00314 return info.outline; 00315 } 00316 00317 Image* InstanceRenderer::bindColoring(ColoringInfo& info, RenderItem& vc, Camera* cam) { 00318 if (!info.dirty && info.curimg == vc.image) { 00319 // optimization for coloring overlay that has not changed 00320 return info.overlay; 00321 } 00322 else { 00323 info.curimg = vc.image; 00324 } 00325 00326 if (info.overlay) { 00327 delete info.overlay; // delete old mask 00328 info.overlay = NULL; 00329 } 00330 00331 SDL_Surface* surface = vc.image->getSurface(); 00332 SDL_Surface* overlay_surface = SDL_ConvertSurface(surface, surface->format, surface->flags); 00333 00334 // needs to use SDLImage here, since GlImage does not support drawing primitives atm 00335 SDLImage* img = new SDLImage(overlay_surface); 00336 00337 uint8_t r, g, b, a = 0; 00338 00339 for (unsigned int x = 0; x < img->getWidth(); x ++) { 00340 for (unsigned int y = 0; y < img->getHeight(); y ++) { 00341 vc.image->getPixelRGBA(x, y, &r, &g, &b, &a); 00342 if (a > 0) { 00343 img->putPixel(x, y, (r + info.r) >> 1, (g + info.g) >> 1, (b + info.b) >> 1); 00344 } 00345 } 00346 } 00347 00348 // In case of OpenGL backend, SDLImage needs to be converted 00349 info.overlay = m_renderbackend->createImage(img->detachSurface()); 00350 delete img; 00351 00352 if (info.overlay) { 00353 // mark overlay coloring as not dirty since we created it here 00354 info.dirty = false; 00355 } 00356 00357 return info.overlay; 00358 } 00359 00360 void InstanceRenderer::addOutlined(Instance* instance, int r, int g, int b, int width) { 00361 OutlineInfo newinfo; 00362 newinfo.r = r; 00363 newinfo.g = g; 00364 newinfo.b = b; 00365 newinfo.width = width; 00366 newinfo.dirty = true; 00367 00368 // attempts to insert the element into the outline map 00369 // will return false in the second value of the pair if the instance already exists 00370 // in the map and the first value of the pair will then be an iterator to the 00371 // existing data for the instance 00372 std::pair<InstanceToOutlines_t::iterator, bool> insertiter = m_instance_outlines.insert(std::make_pair(instance, newinfo)); 00373 00374 if (insertiter.second == false) { 00375 // the insertion did not happen because the instance 00376 // already exists in the map so lets just update its outline info 00377 OutlineInfo& info = insertiter.first->second; 00378 00379 if (info.r != r || info.g != g || info.b != b || info.width != width) { 00380 // only update the outline info if its changed since the last call 00381 // flag the outline info as dirty so it will get processed during rendering 00382 info.r = r; 00383 info.b = b; 00384 info.g = g; 00385 info.width = width; 00386 info.dirty = true; 00387 } 00388 } 00389 } 00390 00391 void InstanceRenderer::addColored(Instance* instance, int r, int g, int b) { 00392 ColoringInfo newinfo; 00393 newinfo.r = r; 00394 newinfo.g = g; 00395 newinfo.b = b; 00396 newinfo.dirty = true; 00397 00398 // attempts to insert the element into the coloring map 00399 // will return false in the second value of the pair if the instance already exists 00400 // in the map and the first value of the pair will then be an iterator to the 00401 // existing data for the instance 00402 std::pair<InstanceToColoring_t::iterator, bool> insertiter = m_instance_colorings.insert(std::make_pair(instance, newinfo)); 00403 00404 if (insertiter.second == false) { 00405 // the insertion did not happen because the instance 00406 // already exists in the map so lets just update its coloring info 00407 ColoringInfo& info = insertiter.first->second; 00408 00409 if (info.r != r || info.g != g || info.b != b) { 00410 // only update the coloring info if its changed since the last call 00411 // flag the coloring info as dirty so it will get processed during rendering 00412 info.r = r; 00413 info.b = b; 00414 info.g = g; 00415 info.dirty = true; 00416 } 00417 } 00418 } 00419 00420 void InstanceRenderer::addTransparentArea(Instance* instance, const std::list<std::string> &groups, unsigned int w, unsigned int h, unsigned char trans, bool front) { 00421 AreaInfo newinfo; 00422 newinfo.instance = instance; 00423 newinfo.groups = groups; 00424 00425 newinfo.w = w; 00426 newinfo.h = h; 00427 newinfo.trans = trans; 00428 newinfo.front = front; 00429 00430 00431 // attempts to insert the element into the area map 00432 // will return false in the second value of the pair if the instance already exists 00433 // in the map and the first value of the pair will then be an iterator to the 00434 // existing data for the instance 00435 std::pair<InstanceToAreas_t::iterator, bool> insertiter = m_instance_areas.insert(std::make_pair(instance, newinfo)); 00436 00437 if (insertiter.second == false) { 00438 // the insertion did not happen because the instance 00439 // already exists in the map so lets just update its area info 00440 AreaInfo& info = insertiter.first->second; 00441 } 00442 } 00443 00444 void InstanceRenderer::removeOutlined(Instance* instance) { 00445 m_instance_outlines.erase(instance); 00446 } 00447 00448 void InstanceRenderer::removeColored(Instance* instance) { 00449 m_instance_colorings.erase(instance); 00450 } 00451 00452 void InstanceRenderer::removeTransparentArea(Instance* instance) { 00453 m_instance_areas.erase(instance); 00454 } 00455 00456 void InstanceRenderer::removeAllOutlines() { 00457 m_instance_outlines.clear(); 00458 } 00459 00460 void InstanceRenderer::removeAllColored() { 00461 m_instance_colorings.clear(); 00462 } 00463 00464 void InstanceRenderer::removeAllTransparentAreas() { 00465 m_instance_areas.clear(); 00466 } 00467 00468 void InstanceRenderer::addIgnoreLight(const std::list<std::string> &groups) { 00469 std::list<std::string>::const_iterator group_it = groups.begin(); 00470 for(;group_it != groups.end(); ++group_it) { 00471 m_unlit_groups.push_back(*group_it); 00472 } 00473 m_unlit_groups.sort(); 00474 m_unlit_groups.unique(); 00475 } 00476 00477 void InstanceRenderer::removeIgnoreLight(const std::list<std::string> &groups) { 00478 std::list<std::string>::const_iterator group_it = groups.begin(); 00479 for(;group_it != groups.end(); ++group_it) { 00480 std::list<std::string>::iterator unlit_it = m_unlit_groups.begin(); 00481 for(;unlit_it != m_unlit_groups.end(); ++unlit_it) { 00482 if((*group_it).find(*unlit_it) != std::string::npos) { 00483 m_unlit_groups.remove(*unlit_it); 00484 break; 00485 } 00486 } 00487 } 00488 } 00489 00490 void InstanceRenderer::removeAllIgnoreLight() { 00491 m_unlit_groups.clear(); 00492 } 00493 00494 void InstanceRenderer::reset() { 00495 removeAllOutlines(); 00496 removeAllColored(); 00497 removeAllTransparentAreas(); 00498 removeAllIgnoreLight(); 00499 } 00500 00501 }