FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
lightrenderer.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2008 by the FIFE team *
3  * http://www.fifengine.de *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 #include <SDL.h>
24 
25 // 3rd party library includes
26 
27 // FIFE includes
28 // These includes are split up in two parts, separated by one empty line
29 // First block: files included from the FIFE root src directory
30 // Second block: files included from the same folder
31 #include "video/renderbackend.h"
32 #include "video/imagepool.h"
33 #include "video/animation.h"
34 #include "video/animationpool.h"
35 #include "video/fonts/abstractfont.h"
36 #include "video/image.h"
37 #include "video/opengl/glimage.h"
38 #include "util/math/fife_math.h"
39 #include "util/log/logger.h"
40 #include "util/time/timemanager.h"
41 #include "model/metamodel/grids/cellgrid.h"
42 #include "model/metamodel/timeprovider.h"
43 #include "model/structures/instance.h"
44 #include "model/structures/layer.h"
45 #include "model/structures/location.h"
46 
47 #include "view/camera.h"
48 #include "lightrenderer.h"
49 
50 
51 namespace FIFE {
52  static Logger _log(LM_VIEWVIEW);
53 
54  LightRendererNode::LightRendererNode(Instance* attached_instance, const Location &relative_location, Layer* relative_layer, const Point &relative_point):
55  m_instance(attached_instance),
56  m_location(relative_location),
57  m_layer(relative_layer),
58  m_point(relative_point) {
59  }
60  LightRendererNode::LightRendererNode(Instance* attached_instance, const Location &relative_location, const Point &relative_point):
61  m_instance(attached_instance),
62  m_location(relative_location),
63  m_layer(NULL),
64  m_point(relative_point) {
65  }
66  LightRendererNode::LightRendererNode(Instance* attached_instance, Layer* relative_layer, const Point &relative_point):
67  m_instance(attached_instance),
68  m_location(NULL),
69  m_layer(relative_layer),
70  m_point(relative_point) {
71  }
72  LightRendererNode::LightRendererNode(Instance* attached_instance, const Point &relative_point):
73  m_instance(attached_instance),
74  m_location(NULL),
75  m_layer(NULL),
76  m_point(relative_point) {
77  }
78  LightRendererNode::LightRendererNode(const Location &attached_location, Layer* relative_layer, const Point &relative_point):
79  m_instance(NULL),
80  m_location(attached_location),
81  m_layer(relative_layer),
82  m_point(relative_point) {
83  }
84  LightRendererNode::LightRendererNode(const Location &attached_location, const Point &relative_point):
85  m_instance(NULL),
86  m_location(attached_location),
87  m_layer(NULL),
88  m_point(relative_point) {
89  }
90  LightRendererNode::LightRendererNode(Layer* attached_layer, const Point &relative_point):
91  m_instance(NULL),
92  m_location(NULL),
93  m_layer(attached_layer),
94  m_point(relative_point) {
95  }
96  LightRendererNode::LightRendererNode(const Point &attached_point):
97  m_instance(NULL),
98  m_location(NULL),
99  m_layer(NULL),
100  m_point(attached_point) {
101  }
102  LightRendererNode::~LightRendererNode() {
103  }
104 
105  void LightRendererNode::setAttached(Instance* attached_instance, const Location &relative_location, const Point &relative_point) {
106  m_instance = attached_instance;
107  m_location = relative_location;
108  m_point = relative_point;
109  }
110  void LightRendererNode::setAttached(Instance* attached_instance, const Location &relative_location) {
111  m_instance = attached_instance;
112  m_location = relative_location;
113  }
114  void LightRendererNode::setAttached(Instance* attached_instance, const Point &relative_point) {
115  m_instance = attached_instance;
116  m_point = relative_point;
117  }
118  void LightRendererNode::setAttached(Instance* attached_instance) {
119  m_instance = attached_instance;
120  }
121  void LightRendererNode::setAttached(const Location &attached_location, const Point &relative_point) {
122  m_instance = NULL;
123  m_location = attached_location;
124  m_point = relative_point;
125  }
126  void LightRendererNode::setAttached(const Location &attached_location) {
127  m_instance = NULL;
128  m_location = attached_location;
129  }
130  void LightRendererNode::setAttached(Layer* attached_layer) {
131  m_layer = attached_layer;
132  }
133  void LightRendererNode::setAttached(const Point &attached_point) {
134  m_instance = NULL;
135  m_location = NULL;
136  m_point = attached_point;
137  }
138 
139  void LightRendererNode::setRelative(const Location &relative_location) {
140  if(m_instance == NULL) {
141  throw NotSupported("No instance attached.");
142  }
143  m_location = relative_location;
144  }
145  void LightRendererNode::setRelative(const Location &relative_location, Point relative_point) {
146  if(m_instance == NULL) {
147  throw NotSupported("No instance attached.");
148  }
149  m_location = relative_location;
150  m_point = relative_point;
151  }
152  void LightRendererNode::setRelative(const Point &relative_point) {
153  if(m_instance == NULL || m_location == NULL) {
154  throw NotSupported("No instance or location attached.");
155  }
156  m_point = relative_point;
157  }
158 
159  Instance* LightRendererNode::getAttachedInstance() {
160  if(m_instance == NULL) {
161  throw NotSupported("No instance attached.");
162  }
163  return m_instance;
164  }
165  Location LightRendererNode::getAttachedLocation() {
166  if(m_instance != NULL || m_location == NULL) {
167  throw NotSupported("No location attached.");
168  }
169  return m_location;
170  }
171  Layer* LightRendererNode::getAttachedLayer() {
172  if(m_layer == NULL) {
173  throw NotSupported("No layer attached.");
174  }
175  return m_layer;
176  }
177  Point LightRendererNode::getAttachedPoint() {
178  if(m_instance != NULL || m_location != NULL) {
179  throw NotSupported("No point attached.");
180  }
181  return m_point;
182  }
183 
184  Location LightRendererNode::getOffsetLocation() {
185  if(m_instance == NULL || m_location == NULL) {
186  throw NotSupported("No location as offset used.");
187  }
188  return m_location;
189  }
190  Point LightRendererNode::getOffsetPoint() {
191  if(m_instance == NULL && m_location == NULL) {
192  throw NotSupported("No point as offset used.");
193  }
194  return m_point;
195  }
196 
197  Instance* LightRendererNode::getInstance() {
198  return m_instance;
199  }
200  Location LightRendererNode::getLocation() {
201  return m_location;
202  }
203  Layer* LightRendererNode::getLayer() {
204  return m_layer;
205  }
206  Point LightRendererNode::getPoint() {
207  return m_point;
208  }
209 
210  Point LightRendererNode::getCalculatedPoint(Camera* cam, Layer* layer) {
211  ScreenPoint p;
212  if(m_instance != NULL) {
213  if(m_layer == NULL) {
214  m_layer = m_instance->getLocation().getLayer();
215  }
216  if(m_location != NULL) {
217  p = cam->toScreenCoordinates(m_instance->getLocationRef().getMapCoordinates() + m_location.getMapCoordinates());
218  } else {
219  p = cam->toScreenCoordinates(m_instance->getLocation().getMapCoordinates());
220  }
221  } else if(m_location != NULL) {
222  if(m_layer == NULL) {
223  m_layer = m_location.getLayer();
224  }
225  p = cam->toScreenCoordinates(m_location.getMapCoordinates());
226  } else if(m_layer == NULL) {
227  const std::list<Layer*>& layers = cam->getRenderer("LightRenderer")->getActiveLayers();
228  std::list<Layer*>::const_reverse_iterator layer_it = layers.rbegin();
229  setAttached(*layer_it);
230  }
231  return Point(m_point.x + p.x, m_point.y + p.y);
232  }
233 
234  LightRendererImageInfo::LightRendererImageInfo(LightRendererNode anchor, int image, int src, int dst):
235  LightRendererElementInfo(),
236  m_anchor(anchor),
237  m_image(image),
238  m_src(src),
239  m_dst(dst),
240  m_stencil(false),
241  m_stencil_ref(0),
242  m_alpha_ref(0.0) {
243  }
244  void LightRendererImageInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend, ImagePool* imagepool, AnimationPool* animpool) {
245  Point p = m_anchor.getCalculatedPoint(cam, layer);
246  if(m_anchor.getLayer() == layer) {
247  Image* img = &imagepool->getImage(m_image);
248  Rect r;
249  Rect viewport = cam->getViewPort();
250  unsigned int widtht = round(img->getWidth() * cam->getZoom());
251  unsigned int height = round(img->getHeight() * cam->getZoom());
252  r.x = p.x-widtht/2;
253  r.y = p.y-height/2;
254  r.w = widtht;
255  r.h = height;
256  renderbackend->changeBlending(m_src, m_dst);
257  if(r.intersects(viewport))
258  img->render(r);
259  }
260  }
261  void LightRendererImageInfo::setStencil(uint8_t stencil_ref, float alpha_ref) {
262  m_stencil = true;
263  m_stencil_ref = stencil_ref;
264  m_alpha_ref = alpha_ref;
265  }
266  int LightRendererImageInfo::getStencil() {
267  if(!m_stencil) {
268  return -1;
269  }
270  return m_stencil_ref;
271  }
272  float LightRendererImageInfo::getAlpha() {
273  return m_alpha_ref;
274  }
275  void LightRendererImageInfo::removeStencil() {
276  m_stencil = false;
277  m_stencil_ref = 0;
278  m_alpha_ref = 0.0;
279  }
280 
281  LightRendererAnimationInfo::LightRendererAnimationInfo(LightRendererNode anchor, int animation, int src, int dst):
282  LightRendererElementInfo(),
283  m_anchor(anchor),
284  m_animation(animation),
285  m_src(src),
286  m_dst(dst),
287  m_start_time(TimeManager::instance()->getTime()),
288  m_time_scale(1.0),
289  m_stencil(false),
290  m_stencil_ref(0),
291  m_alpha_ref(0.0) {
292  }
293  void LightRendererAnimationInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend, ImagePool* imagepool, AnimationPool* animpool) {
294  Point p = m_anchor.getCalculatedPoint(cam, layer);
295  if(m_anchor.getLayer() == layer) {
296  Animation& animation = animpool->getAnimation(m_animation);
297  int animtime = scaleTime(m_time_scale, TimeManager::instance()->getTime() - m_start_time) % animation.getDuration();
298  Image* img = animation.getFrameByTimestamp(animtime);
299  Rect r;
300  Rect viewport = cam->getViewPort();
301  unsigned int widtht = round(img->getWidth() * cam->getZoom());
302  unsigned int height = round(img->getHeight() * cam->getZoom());
303  r.x = p.x-widtht/2;
304  r.y = p.y-height/2;
305  r.w = widtht;
306  r.h = height;
307  renderbackend->changeBlending(m_src, m_dst);
308  if(r.intersects(viewport))
309  img->render(r);
310  }
311  }
312  void LightRendererAnimationInfo::setStencil(uint8_t stencil_ref, float alpha_ref) {
313  m_stencil = true;
314  m_stencil_ref = stencil_ref;
315  m_alpha_ref = alpha_ref;
316  }
317  int LightRendererAnimationInfo::getStencil() {
318  if(!m_stencil) {
319  return -1;
320  }
321  return m_stencil_ref;
322  }
323  float LightRendererAnimationInfo::getAlpha() {
324  return m_alpha_ref;
325  }
326  void LightRendererAnimationInfo::removeStencil() {
327  m_stencil = false;
328  m_stencil_ref = 0;
329  m_alpha_ref = 0.0;
330  }
331 
332  LightRendererResizeInfo::LightRendererResizeInfo(LightRendererNode anchor, int image, int width, int height, int src, int dst):
333  LightRendererElementInfo(),
334  m_anchor(anchor),
335  m_image(image),
336  m_width(width),
337  m_height(height),
338  m_src(src),
339  m_dst(dst),
340  m_stencil(false),
341  m_stencil_ref(0),
342  m_alpha_ref(0.0) {
343  }
344  void LightRendererResizeInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend, ImagePool* imagepool, AnimationPool* animpool) {
345  Point p = m_anchor.getCalculatedPoint(cam, layer);
346  if(m_anchor.getLayer() == layer) {
347  Image* img = &imagepool->getImage(m_image);
348  Rect r;
349  Rect viewport = cam->getViewPort();
350  unsigned int widtht = round(m_width * cam->getZoom());
351  unsigned int height = round(m_height * cam->getZoom());
352  r.x = p.x-widtht/2;
353  r.y = p.y-height/2;
354  r.w = widtht;
355  r.h = height;
356  renderbackend->changeBlending(m_src, m_dst);
357  if(r.intersects(viewport))
358  img->render(r);
359  }
360  }
361  void LightRendererResizeInfo::setStencil(uint8_t stencil_ref, float alpha_ref) {
362  m_stencil = true;
363  m_stencil_ref = stencil_ref;
364  m_alpha_ref = alpha_ref;
365  }
366  int LightRendererResizeInfo::getStencil() {
367  if(!m_stencil) {
368  return -1;
369  }
370  return m_stencil_ref;
371  }
372  float LightRendererResizeInfo::getAlpha() {
373  return m_alpha_ref;
374  }
375  void LightRendererResizeInfo::removeStencil() {
376  m_stencil = false;
377  m_stencil_ref = 0;
378  m_alpha_ref = 0.0;
379  }
380 
381  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):
382  LightRendererElementInfo(),
383  m_anchor(anchor),
384  m_intensity(intensity),
385  m_radius(radius),
386  m_subdivisions(subdivisions),
387  m_xstretch(xstretch),
388  m_ystretch(ystretch),
389  m_red(r),
390  m_green(g),
391  m_blue(b),
392  m_src(src),
393  m_dst(dst),
394  m_stencil(false),
395  m_stencil_ref(0),
396  m_alpha_ref(0.0) {
397  }
398  void LightRendererSimpleLightInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend, ImagePool* imagepool, AnimationPool* animpool) {
399  Point p = m_anchor.getCalculatedPoint(cam, layer);
400  if(m_anchor.getLayer() == layer) {
401  double zoom = cam->getZoom();
402  renderbackend->changeBlending(m_src, m_dst);
403  renderbackend->drawLightPrimitive(p, m_intensity, m_radius, m_subdivisions, m_xstretch * zoom, m_ystretch * zoom, m_red, m_green, m_blue);
404  }
405  }
406  void LightRendererSimpleLightInfo::setStencil(uint8_t stencil_ref, float alpha_ref) {
407  m_stencil = true;
408  m_stencil_ref = stencil_ref;
409  m_alpha_ref = alpha_ref;
410  }
411  int LightRendererSimpleLightInfo::getStencil() {
412  if(!m_stencil) {
413  return -1;
414  }
415  return m_stencil_ref;
416  }
417  float LightRendererSimpleLightInfo::getAlpha() {
418  return m_alpha_ref;
419  }
420  void LightRendererSimpleLightInfo::removeStencil() {
421  m_stencil = false;
422  m_stencil_ref = 0;
423  m_alpha_ref = 0.0;
424  }
425  std::vector<uint8_t> LightRendererSimpleLightInfo::getColor() {
426  std::vector<uint8_t> colors;
427  colors.push_back(m_red);
428  colors.push_back(m_green);
429  colors.push_back(m_blue);
430  colors.push_back(m_intensity);
431  return colors;
432  }
433 
434  LightRenderer* LightRenderer::getInstance(IRendererContainer* cnt) {
435  return dynamic_cast<LightRenderer*>(cnt->getRenderer("LightRenderer"));
436  }
437 
438  LightRenderer::LightRenderer(RenderBackend* renderbackend, int position, ImagePool* imagepool, AnimationPool* animpool):
439  RendererBase(renderbackend, position),
440  m_imagepool(imagepool),
441  m_animationpool(animpool),
442  m_groups() {
443  setEnabled(false);
444  }
445 
446  LightRenderer::LightRenderer(const LightRenderer& old):
447  RendererBase(old),
448  m_imagepool(old.m_imagepool),
449  m_animationpool(old.m_animationpool),
450  m_groups() {
451  setEnabled(false);
452  }
453 
454  RendererBase* LightRenderer::clone() {
455  return new LightRenderer(*this);
456  }
457 
458  LightRenderer::~LightRenderer() {
459  }
460  // Add a static lightmap
461  void LightRenderer::addImage(const std::string &group, LightRendererNode n, int image, int src, int dst) {
462  LightRendererElementInfo* info = new LightRendererImageInfo(n, image, src, dst);
463  m_groups[group].push_back(info);
464  }
465  // Add a animation lightmap
466  void LightRenderer::addAnimation(const std::string &group, LightRendererNode n, int animation, int src, int dst) {
467  LightRendererElementInfo* info = new LightRendererAnimationInfo(n, animation, src, dst);
468  m_groups[group].push_back(info);
469  }
470  // Add a simple light
471  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) {
472  LightRendererElementInfo* info = new LightRendererSimpleLightInfo(n, intensity, radius, subdivisions, xstretch, ystretch, r, g, b, src, dst);
473  m_groups[group].push_back(info);
474  }
475  // Resize an Image
476  void LightRenderer::resizeImage(const std::string &group, LightRendererNode n, int image, int width, int height, int src, int dst) {
477  LightRendererElementInfo* info = new LightRendererResizeInfo(n, image, width, height, src, dst);
478  m_groups[group].push_back(info);
479  }
480  // Enable stencil test for the group
481  void LightRenderer::addStencilTest(const std::string &group, uint8_t stencil_ref, float alpha_ref) {
482  std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
483  for (;info_it != m_groups[group].end(); ++info_it) {
484  (*info_it)->setStencil(stencil_ref, alpha_ref);
485  }
486  }
487  // Disable stencil test for the group
488  void LightRenderer::removeStencilTest(const std::string &group) {
489  std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
490  for (;info_it != m_groups[group].end(); ++info_it) {
491  (*info_it)->removeStencil();
492  }
493  }
494  // Return a list of all groups
495  std::list<std::string> LightRenderer::getGroups() {
496  std::list<std::string> groups;
497  std::map<std::string, std::vector<LightRendererElementInfo*> >::iterator group_it = m_groups.begin();
498  for(; group_it != m_groups.end(); ++group_it) {
499  groups.push_back(group_it->first);
500  }
501  groups.sort();
502  groups.unique();
503  return groups;
504  }
505  // Return a vector of all LightElementInfos
506  std::vector<LightRendererElementInfo*> LightRenderer::getLightInfo(const std::string &group) {
507  std::vector<LightRendererElementInfo*> info;
508  std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
509  for (;info_it != m_groups[group].end(); ++info_it) {
510  info.push_back(*info_it);
511  }
512  return info;
513  }
514  // Remove the group
515  void LightRenderer::removeAll(const std::string &group) {
516  std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
517  for (;info_it != m_groups[group].end(); ++info_it) {
518  delete *info_it;
519  }
520  m_groups[group].clear();
521  m_groups.erase(group);
522  }
523  // Render
524  void LightRenderer::render(Camera* cam, Layer* layer, RenderList& instances) {
525  uint8_t lm = m_renderbackend->getLightingModel();
526 
527  if (!layer->areInstancesVisible()) {
528  return;
529  }
530  m_renderbackend->disableLighting();
531  std::map<std::string, std::vector<LightRendererElementInfo*> >::iterator group_it = m_groups.begin();
532  for (; group_it != m_groups.end(); ++group_it) {
533  std::vector<LightRendererElementInfo*>::const_iterator info_it = group_it->second.begin();
534  for (;info_it != group_it->second.end(); ++info_it) {
535  if (lm != 0) {
536  if ((*info_it)->getStencil() != -1) {
537  uint8_t sref = (*info_it)->getStencil();
538  float aref = (*info_it)->getAlpha();
539  if(info_it != group_it->second.begin())
540  sref += 1;
541  m_renderbackend->setStencilTest(sref, 3, 4);
542  m_renderbackend->setAlphaTest(aref);
543  } else if(lm == 1) {
544  m_renderbackend->setStencilTest(255, 0, 6);
545  m_renderbackend->setAlphaTest(0);
546  } else if(lm == 2) {
547  m_renderbackend->setStencilTest(1, 2, 4);
548  m_renderbackend->setAlphaTest(0);
549  }
550  (*info_it)->render(cam, layer, instances, m_renderbackend, m_imagepool, m_animationpool);
551  m_renderbackend->disableAlphaTest();
552  m_renderbackend->disableStencilTest();
553  } else {
554  (*info_it)->render(cam, layer, instances, m_renderbackend, m_imagepool, m_animationpool);
555  }
556  }
557  }
558  m_renderbackend->changeBlending(4, 5);
559  m_renderbackend->enableLighting();
560  }
561 
562 }