00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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;
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
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
00248 return info.outline;
00249 } else {
00250 info.curimg = vc.image;
00251 }
00252
00253 if (info.outline) {
00254 delete info.outline;
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
00261 SDLImage* img = new SDLImage(outline_surface);
00262
00263
00264 uint8_t r, g, b, a = 0;
00265
00266
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
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
00306 info.outline = m_renderbackend->createImage(img->detachSurface());
00307 delete img;
00308
00309 if (info.outline) {
00310
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
00320 return info.overlay;
00321 }
00322 else {
00323 info.curimg = vc.image;
00324 }
00325
00326 if (info.overlay) {
00327 delete info.overlay;
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
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
00349 info.overlay = m_renderbackend->createImage(img->detachSurface());
00350 delete img;
00351
00352 if (info.overlay) {
00353
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
00369
00370
00371
00372 std::pair<InstanceToOutlines_t::iterator, bool> insertiter = m_instance_outlines.insert(std::make_pair(instance, newinfo));
00373
00374 if (insertiter.second == false) {
00375
00376
00377 OutlineInfo& info = insertiter.first->second;
00378
00379 if (info.r != r || info.g != g || info.b != b || info.width != width) {
00380
00381
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
00399
00400
00401
00402 std::pair<InstanceToColoring_t::iterator, bool> insertiter = m_instance_colorings.insert(std::make_pair(instance, newinfo));
00403
00404 if (insertiter.second == false) {
00405
00406
00407 ColoringInfo& info = insertiter.first->second;
00408
00409 if (info.r != r || info.g != g || info.b != b) {
00410
00411
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
00432
00433
00434
00435 std::pair<InstanceToAreas_t::iterator, bool> insertiter = m_instance_areas.insert(std::make_pair(instance, newinfo));
00436
00437 if (insertiter.second == false) {
00438
00439
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 }