diff engine/core/view/renderers/lightrenderer.cpp @ 661:e3140f01749d

* Merged the light branch back into trunk. * Modified the demos so they work with the new loaders and setting.
author helios2000@33b003aa-7bff-0310-803a-e67f0ece8222
date Fri, 05 Nov 2010 15:21:10 +0000
parents
children 60621d858548
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/engine/core/view/renderers/lightrenderer.cpp	Fri Nov 05 15:21:10 2010 +0000
@@ -0,0 +1,555 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2008 by the FIFE team                              *
+ *   http://www.fifengine.de                                               *
+ *   This file is part of FIFE.                                            *
+ *                                                                         *
+ *   FIFE is free software; you can redistribute it and/or                 *
+ *   modify it under the terms of the GNU Lesser General Public            *
+ *   License as published by the Free Software Foundation; either          *
+ *   version 2.1 of the License, or (at your option) any later version.    *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the                 *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
+ ***************************************************************************/
+
+// Standard C++ library includes
+#include <SDL.h>
+
+// 3rd party library includes
+
+// FIFE includes
+// These includes are split up in two parts, separated by one empty line
+// First block: files included from the FIFE root src directory
+// Second block: files included from the same folder
+#include "video/renderbackend.h"
+#include "video/imagepool.h"
+#include "video/animation.h"
+#include "video/animationpool.h"
+#include "video/fonts/abstractfont.h"
+#include "video/image.h"
+#include "video/opengl/glimage.h"
+#include "util/math/fife_math.h"
+#include "util/log/logger.h"
+#include "util/time/timemanager.h"
+#include "model/metamodel/grids/cellgrid.h"
+#include "model/metamodel/timeprovider.h"
+#include "model/structures/instance.h"
+#include "model/structures/layer.h"
+#include "model/structures/location.h"
+
+#include "view/camera.h"
+#include "lightrenderer.h"
+
+
+namespace FIFE {
+	static Logger _log(LM_VIEWVIEW);
+
+	LightRendererNode::LightRendererNode(Instance* attached_instance, const Location &relative_location, Layer* relative_layer, const Point &relative_point):
+		m_instance(attached_instance),
+		m_location(relative_location),
+		m_layer(relative_layer),
+		m_point(relative_point) {
+	}
+	LightRendererNode::LightRendererNode(Instance* attached_instance, const Location &relative_location, const Point &relative_point):
+		m_instance(attached_instance),
+		m_location(relative_location),
+		m_layer(NULL),
+		m_point(relative_point) {
+	}
+	LightRendererNode::LightRendererNode(Instance* attached_instance, Layer* relative_layer, const Point &relative_point):
+		m_instance(attached_instance),
+		m_location(NULL),
+		m_layer(relative_layer),
+		m_point(relative_point) {
+	}
+	LightRendererNode::LightRendererNode(Instance* attached_instance, const Point &relative_point):
+		m_instance(attached_instance),
+		m_location(NULL),
+		m_layer(NULL),
+		m_point(relative_point) {
+	}
+	LightRendererNode::LightRendererNode(const Location &attached_location, Layer* relative_layer, const Point &relative_point):
+		m_instance(NULL),
+		m_location(attached_location),
+		m_layer(relative_layer),
+		m_point(relative_point) {
+	}
+	LightRendererNode::LightRendererNode(const Location &attached_location, const Point &relative_point):
+		m_instance(NULL),
+		m_location(attached_location),
+		m_layer(NULL),
+		m_point(relative_point) {
+	}
+	LightRendererNode::LightRendererNode(Layer* attached_layer, const Point &relative_point):
+		m_instance(NULL),
+		m_location(NULL),
+		m_layer(attached_layer),
+		m_point(relative_point) {
+	}
+	LightRendererNode::LightRendererNode(const Point &attached_point):
+		m_instance(NULL),
+		m_location(NULL),
+		m_layer(NULL),
+		m_point(attached_point) {
+	}
+	LightRendererNode::~LightRendererNode() {
+	}
+
+	void LightRendererNode::setAttached(Instance* attached_instance, const Location &relative_location, const Point &relative_point) {
+		m_instance = attached_instance;
+		m_location = relative_location;
+		m_point = relative_point;
+	}
+	void LightRendererNode::setAttached(Instance* attached_instance, const Location &relative_location) {
+		m_instance = attached_instance;
+		m_location = relative_location;
+	}
+	void LightRendererNode::setAttached(Instance* attached_instance, const Point &relative_point) {
+		m_instance = attached_instance;
+		m_point = relative_point;
+	}
+	void LightRendererNode::setAttached(Instance* attached_instance) {
+		m_instance = attached_instance;
+	}
+	void LightRendererNode::setAttached(const Location &attached_location, const Point &relative_point) {
+		m_instance = NULL;
+		m_location = attached_location;
+		m_point = relative_point;
+	}
+	void LightRendererNode::setAttached(const Location &attached_location) {
+		m_instance = NULL;
+		m_location = attached_location;
+	}
+	void LightRendererNode::setAttached(Layer* attached_layer) {
+		m_layer = attached_layer;
+	}
+	void LightRendererNode::setAttached(const Point &attached_point) {
+		m_instance = NULL;
+		m_location = NULL;
+		m_point = attached_point;
+	}
+
+	void LightRendererNode::setRelative(const Location &relative_location) {
+		if(m_instance == NULL) {
+			throw NotSupported("No instance attached.");
+		}
+		m_location = relative_location;
+	}
+	void LightRendererNode::setRelative(const Location &relative_location, Point relative_point) {
+		if(m_instance == NULL) {
+			throw NotSupported("No instance attached.");
+		}
+		m_location = relative_location;
+		m_point = relative_point;
+	}
+	void LightRendererNode::setRelative(const Point &relative_point) {
+		if(m_instance == NULL || m_location == NULL) {
+			throw NotSupported("No instance or location attached.");
+		}
+		m_point = relative_point;
+	}
+
+	Instance* LightRendererNode::getAttachedInstance() {
+		if(m_instance == NULL) {
+			throw NotSupported("No instance attached.");
+		}
+		return m_instance;
+	}
+	Location LightRendererNode::getAttachedLocation() {
+		if(m_instance != NULL || m_location == NULL) {
+			throw NotSupported("No location attached.");
+		}
+		return m_location;
+	}
+	Layer* LightRendererNode::getAttachedLayer() {
+		if(m_layer == NULL) {
+			throw NotSupported("No layer attached.");
+		}
+		return m_layer;
+	}
+	Point LightRendererNode::getAttachedPoint() {
+		if(m_instance != NULL || m_location != NULL) {
+			throw NotSupported("No point attached.");
+		}
+		return m_point;
+	}
+
+	Location LightRendererNode::getOffsetLocation() {
+		if(m_instance == NULL || m_location == NULL) {
+			throw NotSupported("No location as offset used.");
+		}
+		return m_location;
+	}
+	Point LightRendererNode::getOffsetPoint() {
+		if(m_instance == NULL && m_location == NULL) {
+			throw NotSupported("No point as offset used.");
+		}
+		return m_point;
+	}
+
+	Instance* LightRendererNode::getInstance() {
+		return m_instance;
+	}
+	Location LightRendererNode::getLocation() {
+		return m_location;
+	}
+	Layer* LightRendererNode::getLayer() {
+		return m_layer;
+	}
+	Point LightRendererNode::getPoint() {
+		return m_point;
+	}
+
+	Point LightRendererNode::getCalculatedPoint(Camera* cam, Layer* layer) {
+		ScreenPoint p;
+		if(m_instance != NULL) {
+			if(m_layer == NULL) {
+				m_layer = m_instance->getLocation().getLayer();
+			}
+			if(m_location != NULL) {
+				p = cam->toScreenCoordinates(m_instance->getLocationRef().getMapCoordinates() + m_location.getMapCoordinates());
+			} else {
+				p = cam->toScreenCoordinates(m_instance->getLocation().getMapCoordinates());
+			}
+		} else if(m_location != NULL) {
+			if(m_layer == NULL) {
+				m_layer = m_location.getLayer();
+			}
+			p = cam->toScreenCoordinates(m_location.getMapCoordinates());
+		} else if(m_layer == NULL) {
+			const std::list<Layer*>& layers = cam->getRenderer("LightRenderer")->getActiveLayers();
+			std::list<Layer*>::const_reverse_iterator layer_it = layers.rbegin();
+			setAttached(*layer_it);
+		}
+		return Point(m_point.x + p.x, m_point.y + p.y);
+	}
+
+	LightRendererImageInfo::LightRendererImageInfo(LightRendererNode anchor, int image, int src, int dst):
+		LightRendererElementInfo(),
+		m_anchor(anchor),
+		m_image(image),
+		m_src(src),
+		m_dst(dst),
+		m_stencil(false),
+		m_stencil_ref(0),
+		m_alpha_ref(0.0) {
+	}
+	void LightRendererImageInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend, ImagePool* imagepool, AnimationPool* animpool) {
+		Point p = m_anchor.getCalculatedPoint(cam, layer);
+		if(m_anchor.getLayer() == layer) {
+			Image* img = &imagepool->getImage(m_image);
+			Rect r;
+			Rect viewport = cam->getViewPort();
+			r.x = p.x-img->getWidth()/2;
+			r.y = p.y-img->getHeight()/2;
+			r.w = img->getWidth();
+			r.h = img->getHeight();
+			renderbackend->changeBlending(m_src, m_dst);
+			if(r.intersects(viewport))
+				img->render(r);
+		}
+	}
+	void LightRendererImageInfo::setStencil(uint8_t stencil_ref, float alpha_ref) {
+		m_stencil = true;
+		m_stencil_ref = stencil_ref;
+		m_alpha_ref = alpha_ref;
+	}
+	int LightRendererImageInfo::getStencil() {
+		if(!m_stencil) {
+			return -1;
+		}
+		return m_stencil_ref;
+	}
+	float LightRendererImageInfo::getAlpha() {
+		return m_alpha_ref;
+	}
+	void LightRendererImageInfo::removeStencil() {
+		m_stencil = false;
+		m_stencil_ref = 0;
+		m_alpha_ref = 0.0;
+	}
+	
+	LightRendererAnimationInfo::LightRendererAnimationInfo(LightRendererNode anchor, int animation, int src, int dst):
+		LightRendererElementInfo(),
+		m_anchor(anchor),
+		m_animation(animation),
+		m_src(src),
+		m_dst(dst),
+		m_start_time(TimeManager::instance()->getTime()),
+		m_time_scale(1.0),
+		m_stencil(false),
+		m_stencil_ref(0),
+		m_alpha_ref(0.0) {
+	}
+	void LightRendererAnimationInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend, ImagePool* imagepool, AnimationPool* animpool) { 
+		Point p = m_anchor.getCalculatedPoint(cam, layer);
+		if(m_anchor.getLayer() == layer) {
+			Animation& animation = animpool->getAnimation(m_animation);
+			int animtime = scaleTime(m_time_scale, TimeManager::instance()->getTime() - m_start_time) % animation.getDuration();
+			Image* img = animation.getFrameByTimestamp(animtime);
+			Rect r;
+			Rect viewport = cam->getViewPort();
+			r.x = p.x-img->getWidth()/2;
+			r.y = p.y-img->getHeight()/2;
+			r.w = img->getWidth();
+			r.h = img->getHeight();
+			renderbackend->changeBlending(m_src, m_dst);
+			if(r.intersects(viewport))
+				img->render(r);
+		}
+	}
+	void LightRendererAnimationInfo::setStencil(uint8_t stencil_ref, float alpha_ref) {
+		m_stencil = true;
+		m_stencil_ref = stencil_ref;
+		m_alpha_ref = alpha_ref;
+	}
+	int LightRendererAnimationInfo::getStencil() {
+		if(!m_stencil) {
+			return -1;
+		}
+		return m_stencil_ref;
+	}
+	float LightRendererAnimationInfo::getAlpha() {
+		return m_alpha_ref;
+	}
+	void LightRendererAnimationInfo::removeStencil() {
+		m_stencil = false;
+		m_stencil_ref = 0;
+		m_alpha_ref = 0.0;
+	}
+
+	LightRendererResizeInfo::LightRendererResizeInfo(LightRendererNode anchor, int image, int width, int height, int src, int dst):
+		LightRendererElementInfo(),
+		m_anchor(anchor),
+		m_image(image),
+		m_width(width),
+		m_height(height),
+		m_src(src),
+		m_dst(dst),
+		m_stencil(false),
+		m_stencil_ref(0),
+		m_alpha_ref(0.0) {
+	}
+	void LightRendererResizeInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend, ImagePool* imagepool, AnimationPool* animpool) {
+		Point p = m_anchor.getCalculatedPoint(cam, layer);
+		if(m_anchor.getLayer() == layer) {
+			Image* img = &imagepool->getImage(m_image);
+			Rect r;
+			Rect viewport = cam->getViewPort();
+			r.x = p.x-m_width/2;
+			r.y = p.y-m_height/2;
+			r.w = m_width;
+			r.h = m_height;
+			renderbackend->changeBlending(m_src, m_dst);
+			if(r.intersects(viewport))
+				img->render(r);
+		}
+	}
+	void LightRendererResizeInfo::setStencil(uint8_t stencil_ref, float alpha_ref) {
+		m_stencil = true;
+		m_stencil_ref = stencil_ref;
+		m_alpha_ref = alpha_ref;
+	}
+	int LightRendererResizeInfo::getStencil() {
+		if(!m_stencil) {
+			return -1;
+		}
+		return m_stencil_ref;
+	}
+	float LightRendererResizeInfo::getAlpha() {
+		return m_alpha_ref;
+	}
+	void LightRendererResizeInfo::removeStencil() {
+		m_stencil = false;
+		m_stencil_ref = 0;
+		m_alpha_ref = 0.0;
+	}
+
+	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):
+		LightRendererElementInfo(),
+		m_anchor(anchor),
+		m_intensity(intensity),
+		m_radius(radius),
+		m_subdivisions(subdivisions),
+		m_xstretch(xstretch),
+		m_ystretch(ystretch),
+		m_red(r),
+		m_green(g),
+		m_blue(b),
+		m_src(src),
+		m_dst(dst),
+		m_stencil(false),
+		m_stencil_ref(0),
+		m_alpha_ref(0.0) {
+	}
+	void LightRendererSimpleLightInfo::render(Camera* cam, Layer* layer, RenderList& instances, RenderBackend* renderbackend, ImagePool* imagepool, AnimationPool* animpool) {
+		Point p = m_anchor.getCalculatedPoint(cam, layer);
+		if(m_anchor.getLayer() == layer) {
+			renderbackend->changeBlending(m_src, m_dst);
+			renderbackend->drawLightPrimitive(p, m_intensity, m_radius, m_subdivisions, m_xstretch, m_ystretch, m_red, m_green, m_blue);
+		}
+	}
+	void LightRendererSimpleLightInfo::setStencil(uint8_t stencil_ref, float alpha_ref) {
+		m_stencil = true;
+		m_stencil_ref = stencil_ref;
+		m_alpha_ref = alpha_ref;
+	}
+	int LightRendererSimpleLightInfo::getStencil() {
+		if(!m_stencil) {
+			return -1;
+		}
+		return m_stencil_ref;
+	}
+	float LightRendererSimpleLightInfo::getAlpha() {
+		return m_alpha_ref;
+	}
+	void LightRendererSimpleLightInfo::removeStencil() {
+		m_stencil = false;
+		m_stencil_ref = 0;
+		m_alpha_ref = 0.0;
+	}
+	std::vector<uint8_t> LightRendererSimpleLightInfo::getColor() {
+		std::vector<uint8_t> colors;
+		colors.push_back(m_red);
+		colors.push_back(m_green);
+		colors.push_back(m_blue);
+		colors.push_back(m_intensity);
+		return colors;
+	}
+
+	LightRenderer* LightRenderer::getInstance(IRendererContainer* cnt) {
+		return dynamic_cast<LightRenderer*>(cnt->getRenderer("LightRenderer"));
+	}
+	
+	LightRenderer::LightRenderer(RenderBackend* renderbackend, int position, ImagePool* imagepool, AnimationPool* animpool):
+		RendererBase(renderbackend, position),
+		m_imagepool(imagepool),
+		m_animationpool(animpool),
+		m_groups() {
+		setEnabled(false);
+	}
+
+	LightRenderer::LightRenderer(const LightRenderer& old):
+		RendererBase(old),
+		m_imagepool(old.m_imagepool),
+		m_animationpool(old.m_animationpool),
+		m_groups() {
+		setEnabled(false);
+	}
+
+	RendererBase* LightRenderer::clone() {
+		return new LightRenderer(*this);
+	}
+
+	LightRenderer::~LightRenderer() {
+	}
+	// Add a static lightmap
+	void LightRenderer::addImage(const std::string &group, LightRendererNode n, int image, int src, int dst) {
+		LightRendererElementInfo* info = new LightRendererImageInfo(n, image, src, dst);
+		m_groups[group].push_back(info);
+	}
+	// Add a animation lightmap
+	void LightRenderer::addAnimation(const std::string &group, LightRendererNode n, int animation, int src, int dst) {
+		LightRendererElementInfo* info = new LightRendererAnimationInfo(n, animation, src, dst);
+		m_groups[group].push_back(info);
+	}
+	// Add a simple light
+	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) {
+		LightRendererElementInfo* info = new LightRendererSimpleLightInfo(n, intensity, radius, subdivisions, xstretch, ystretch, r, g, b, src, dst);
+		m_groups[group].push_back(info);
+	}
+	// Resize an Image
+	void LightRenderer::resizeImage(const std::string &group, LightRendererNode n, int image, int width, int height, int src, int dst) {
+		LightRendererElementInfo* info = new LightRendererResizeInfo(n, image, width, height, src, dst);
+		m_groups[group].push_back(info);
+	}
+	// Enable stencil test for the group
+	void LightRenderer::addStencilTest(const std::string &group, uint8_t stencil_ref, float alpha_ref) {
+		std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
+		for (;info_it != m_groups[group].end(); ++info_it) {
+			(*info_it)->setStencil(stencil_ref, alpha_ref);
+		}
+	}
+	// Disable stencil test for the group
+	void LightRenderer::removeStencilTest(const std::string &group) {
+		std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
+		for (;info_it != m_groups[group].end(); ++info_it) {
+			(*info_it)->removeStencil();
+		}
+	}
+	// Return a list of all groups
+	std::list<std::string> LightRenderer::getGroups() {
+		std::list<std::string> groups;
+		std::map<std::string, std::vector<LightRendererElementInfo*> >::iterator group_it = m_groups.begin();
+		for(; group_it != m_groups.end(); ++group_it) {
+			groups.push_back(group_it->first);
+		}
+		groups.sort();
+		groups.unique();
+		return groups;
+	}
+	// Return a vector of all LightElementInfos
+	std::vector<LightRendererElementInfo*> LightRenderer::getLightInfo(const std::string &group) {
+		std::vector<LightRendererElementInfo*> info;
+		std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
+		for (;info_it != m_groups[group].end(); ++info_it) {
+			info.push_back(*info_it);
+		}
+		return info;
+	}
+	// Remove the group
+	void LightRenderer::removeAll(const std::string &group) {
+		std::vector<LightRendererElementInfo*>::const_iterator info_it = m_groups[group].begin();
+		for (;info_it != m_groups[group].end(); ++info_it) {
+			delete *info_it;
+		}
+		m_groups[group].clear();
+		m_groups.erase(group);
+	}
+	// Render
+	void LightRenderer::render(Camera* cam, Layer* layer, RenderList& instances) {
+		uint8_t lm = m_renderbackend->getLightingModel();
+		
+		if (!layer->areInstancesVisible()) {
+			return;
+		}
+		m_renderbackend->disableLighting();
+		std::map<std::string, std::vector<LightRendererElementInfo*> >::iterator group_it = m_groups.begin();
+		for (; group_it != m_groups.end(); ++group_it) {
+			std::vector<LightRendererElementInfo*>::const_iterator info_it = group_it->second.begin();
+			for (;info_it != group_it->second.end(); ++info_it) {
+				if (lm != 0) {
+					if ((*info_it)->getStencil() != -1) {
+						uint8_t sref = (*info_it)->getStencil();
+						float aref = (*info_it)->getAlpha();
+						if(info_it != group_it->second.begin())
+							sref += 1;
+						m_renderbackend->setStencilTest(sref, 3, 4);
+						m_renderbackend->setAlphaTest(aref);
+					} else if(lm == 1) {
+						m_renderbackend->setStencilTest(255, 0, 6);
+						m_renderbackend->setAlphaTest(0);
+					} else if(lm == 2) {
+						m_renderbackend->setStencilTest(1, 2, 4);
+						m_renderbackend->setAlphaTest(0);
+					}
+					(*info_it)->render(cam, layer, instances, m_renderbackend, m_imagepool, m_animationpool);
+					m_renderbackend->disableAlphaTest();
+					m_renderbackend->disableStencilTest();
+				} else {
+					(*info_it)->render(cam, layer, instances, m_renderbackend, m_imagepool, m_animationpool);
+				}
+			}
+		}
+		m_renderbackend->changeBlending(4, 5);
+		m_renderbackend->enableLighting();
+	}
+
+}
\ No newline at end of file