Česky
Kamil Dudka

RRV - Radiosity Renderer and Visualizer (C++, OpenGL)

File detail

Name:DownloadEntity.cpp [Download]
Location: rrv > src
Size:11.0 KB
Last modification:2009-10-21 22:58

Source code

/*
 * Copyright (C) 2007 TODO
 *
 * This file is part of rrv (Radiosity Renderer and Visualizer).
 *
 * rrv is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * rrv 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rrv.  If not, see <http://www.gnu.org/licenses/>.
 */
 
#include "Entity.h"
#include "PatchSequenceEnumerator.h"
#include "CuboidEntity.h"
#include "BarrelEntity.h"
#include "GlobeEntity.h"
#include "TeapotEntity.h"
#include "TriangleEntity.h"
#include "TriangleSetExt.h"
 
#include <cassert>
#include <cstring>
#include <iostream>
#include <sstream>
#include <queue>
#include <vector>
 
using namespace std;
using namespace XML;
 
Entity::Entity():
	spec_(1.0),	
	refl_(.0),	
	refr_(.0),	
	patchSet_(0)
{
}
 
// Virtual destructor
Entity::~Entity() {
	delete patchSet_;
}
 
Entity::Entity(const Entity &e) {
  operator=(e);
}
 
Entity& Entity::operator=(const Entity &e) {
	if( this != &e )
	{
		transformMatrix_ = e.transformMatrix_;
		triangleSet_ = e.triangleSet_;
		name_ = e.name_;
 
		patchSet_ = (e.patchSet_)?
			new TriangleSet(*e.patchSet_):
			0;
	}
 
	return *this;
}
 
/**
 * @return Entity*
 * @param  from
 * @author Jakub Filak
 * @date   2007-10-25
 */
Entity* Entity::create (XMLNode *from ) {
 
	XMLCSTR nodeName = from->getName();
 
#ifndef NDEBUG
	if( 0 == nodeName )
	{
		std::cerr << "WARNING: entity not created!" << std::endl;
	}
#endif
 
	if( !strcmp( nodeName, XMLNames::TAGS[ Cuboid ] ) )
	{
		return new CuboidEntity();
	}
	else if( !strcmp( nodeName,XMLNames::TAGS[ Barrel ]) )
	{
		return new BarrelEntity();
	}
	else if( !strcmp( nodeName,XMLNames::TAGS[ Globe ]) )
	{
		return new GlobeEntity();
	}
	else if( !strcmp( nodeName,XMLNames::TAGS[ Teapot ]) )
	{
		return new TeapotEntity();
	}
	else if( !strcmp( nodeName,XMLNames::TAGS[ TriangleSetNode ]) )
	{
		return new TriangleEntity();
	}
#ifndef NDEBUG
	else
	{
		std::cerr << "WARNING: unknow entity type : " << nodeName << std::endl;
	}
#endif
 
	return 0;
}
 
void Entity::setName( XMLNode *from, const char* implicit )
{
	XMLCSTR name = from->getAttribute( XMLNames::ATTRIBUTES[ Name ] );
 
	if( 0 != name )
		setName( std::string( name ));
	else
		setName( std::string( implicit ));
}
 
/**
 * @param matrix
 */
void Entity::setTransformMatrix (TransformMatrix *matrix) {
	transformMatrix_ = *matrix;
}
 
 
/**
 * @param  from
 */
void Entity::deserialize (XMLNode *from) {
	this->setColors(from,this->emission_,this->reflectivity_,this->radiosity_);
	XMLHelper::fromAttribute<double>( spec_,  1, from, XMLNames::ATTRIBUTES[ Spec ], false );   
	XMLHelper::fromAttribute<double>( refl_, .0, from, XMLNames::ATTRIBUTES[ Refl ], false );   
	XMLHelper::fromAttribute<double>( refr_, .0, from, XMLNames::ATTRIBUTES[ Refr ], false );   
	impl_deserialize( from );
}
 
void Entity::impl_deserialize( XMLNode* ) {
	assert( !"Not implemented deserialization method" );
}
 
/**
 * @param  size
 */
void Entity::divide (float size ) {
 	TriangleSet *pset = new TriangleSet;
 
// Patched for old versions of MinGW
// 	class {
	class AnonStack {
		std::queue<Triangle> stack_;
		public:
			Triangle pop() {
				Triangle top = stack_.front();
				stack_.pop();
				return top;
			}
			void push(const Triangle &t) {
				stack_.push(t);
			}
			void push(TriangleSet *pTset) {
				TriangleSet &tset = *pTset;
				for (size_t i=0; i< tset.count(); i++)
					this->push(tset[i]);
			}
			bool empty() const {
				return stack_.empty();
			}
// Patched for old versions of MinGW
// 	} stack;
	}; AnonStack stack;
 
	for (size_t i=0; i<triangleSet_.count(); i++)
		stack.push(triangleSet_[i]);
 
	while (!stack.empty()) {
		Triangle top = stack.pop();
		if (TriangleSet::size<1>(&top) <= size)
			pset->add(&top);
		else {
			TriangleSet *tset = TriangleSet::divide(&top);
			stack.push(tset);
			delete tset;
		}
	}
 
 	delete patchSet_;
 	patchSet_ = pset;
}
 
 
/**
 * @return PatchSequenceEnumerator*
 */
PatchSequenceEnumerator* Entity::createPatchSequenceEnumerator ( ) {
	TriangleSet *tset = patchSet_;
	if (0== tset)
		tset = &triangleSet_;
	return new DirectPatchSequenceEnumerator(tset);
}
 
 
	class Converter {
		public:
		char* colorToStr( Color& c )
		{
			ostringstream oss;
			oss << c.r << "," << c.g << "," << c.b;
			return XMLWriter::copyString(oss.str().c_str());
		}
 
		template<typename V> char* valToS( V& f )
		{
			ostringstream oss;
			oss << f;
			return XMLWriter::copyString(oss.str().c_str());		
		}
	} converter;	
 
 
/**
 * @return XMLNode
 */
XMLNode Entity::serialize ( ) 
{
	XMLNode n = XMLNode::createXMLTopNode((XMLNames::TAGS[TriangleSetNode] ));
	n.addAttribute_WOSD( XMLWriter::copyString( XMLNames::ATTRIBUTES[Name]), XMLWriter::copyString( getName().c_str() ) );
	PatchSequenceEnumerator *e = createPatchSequenceEnumerator();
 
	Triangle *t = 0;
	XMLNode tnode;
	while( 0 != ( t = e->nextPatch() ) )
	{
		tnode = n.addChild_WOSD( XMLWriter::copyString( XMLNames::TAGS[TriangleNode] ) );
 
		tnode.addAttribute_WOSD( 
				XMLWriter::copyString( XMLNames::ATTRIBUTES[Emission] ), 
				converter.colorToStr(t->emission) );
 
		tnode.addAttribute_WOSD( 
				XMLWriter::copyString( XMLNames::ATTRIBUTES[Reflectivity] ),
				converter.colorToStr(t->reflectivity) );
 
		tnode.addAttribute_WOSD(
				XMLWriter::copyString( XMLNames::ATTRIBUTES[Radiosity] ),
				converter.colorToStr(t->radiosity) );
 
		tnode.addAttribute_WOSD(
				XMLWriter::copyString( XMLNames::ATTRIBUTES[Spec] ),
				converter.valToS<double>(t->spec) );
 
		tnode.addAttribute_WOSD(
				XMLWriter::copyString( XMLNames::ATTRIBUTES[Refl] ),
				converter.valToS<double>(t->refl) );
 
		tnode.addAttribute_WOSD(
				XMLWriter::copyString( XMLNames::ATTRIBUTES[Refr] ),
				converter.valToS<double>(t->refr) );
 
		for( int i = 0; i < 3; i++ )
		{
			XMLNode vnode = tnode.addChild_WOSD( XMLWriter::copyString( XMLNames::TAGS[VertexNode] ) );
 
			vnode.addAttribute_WOSD(
					XMLWriter::copyString( XMLNames::ATTRIBUTES[VertexX] ), 
					converter.valToS<float>( t->vertex[i].x ) );
 
			vnode.addAttribute_WOSD( 
					XMLWriter::copyString( XMLNames::ATTRIBUTES[VertexY] ), 
					converter.valToS<float>( t->vertex[i].y ) );
 
			vnode.addAttribute_WOSD( 
					XMLWriter::copyString( XMLNames::ATTRIBUTES[VertexZ] ), 
					converter.valToS<float>( t->vertex[i].z ) );
		}
	}
 
	delete e;
	return n;
}
 
void Entity::setTriangleProperties( Triangle& triangle )
{
	triangle.emission = this->emission_;
	triangle.reflectivity = this->reflectivity_;
	triangle.radiosity = this->radiosity_;
 
	triangle.spec = this->spec_;
	triangle.refl = this->refl_;
	triangle.refr = this->refr_;
}
 
/**
 * @param  triangle
 */
void Entity::addTriangle ( Triangle *triangle ) {
	// Transform all vertex using transformMatrix_ matrix
	Triangle t = *triangle;
 
	for (int i=0; i<3; i++) {
		Vertex &v = t.vertex[i];
		v = transformMatrix_.transform(v);
	}
 
	// Add transformed triangle to container
	triangleSet_.add(&t);
}
 
#ifndef  NDEBUG
bool Entity::colorFromXMLNode( XMLNode *node, XMLCSTR attName, Color& to, int wlevel) 
#else
bool Entity::colorFromXMLNode( XMLNode *node, XMLCSTR attName, Color& to) 
#endif
{
	float rgb[] = {0.0,0.0,0.0}; 			// array for colors
 
	XMLCSTR fRGBValues = node->getAttribute( attName );	// try take attribute color
 
	if ( 0 == fRGBValues || strlen(fRGBValues) < 5 ) // "1,1,1"
	{	
#ifndef NDEBUG
		if ( wlevel > 1 )
		{
			cerr << "WARNING: node: " << 
				node->getName() << " - " << attName 
				<< " , color unrecognized, using default BLACK" << endl;	
		}
#endif
 
		to = Color( rgb );
		return false; 
	}
 
	XMLCSTR mPtr = fRGBValues;
	int i = 0;
 
	while( 0 != *mPtr )
	{
		ostringstream oss;
 
		while( 0 != *mPtr && ',' != *mPtr )
		{
			oss << *mPtr;
			mPtr++;
		}
 
		string fln = oss.str();
		istringstream iss( fln );
 
		float tmp;
 
		if ( ( iss >> tmp ).fail() )
		{	
#ifndef NDEBUG
			if ( wlevel > 0 )
			{
				cerr << "WARNING: node: " << node->getName() << " , bad color format : " << fRGBValues << endl;
			}
#endif
 
			to = Color( rgb );
			return false;
		}
		else
		{
			if ( i < 3 )
			{
				rgb[i] = tmp;
				i++;
			}
		}
 
		if( 0 != *mPtr )
			mPtr++;
	}	
 
	to = Color( rgb );
	return true;
}
 
void Entity::setColors( XMLNode* from, Color& em, Color& refl, Color& rad )
{
	Entity::colorFromXMLNode( from, XMLNames::ATTRIBUTES[ Emission     ] , em );
	Entity::colorFromXMLNode( from, XMLNames::ATTRIBUTES[ Reflectivity ] , refl );
	Entity::colorFromXMLNode( from, XMLNames::ATTRIBUTES[ Radiosity    ] , rad );
}
 
namespace {
	inline std::string vertexToString(const Vertex &v) {
		std::ostringstream oss;
		oss << v.x << "," << v.y << "," << v.z;
		return oss.str();
	}
}
 
TriangleSetExt* Entity::computeVertexColors() {
	// Create and fill TriangleSetExt
	TriangleSetExt *tset = new TriangleSetExt;
	PatchSequenceEnumerator *patchEnumerator = createPatchSequenceEnumerator();
	Triangle *t;
	while (0!= (t= patchEnumerator->nextPatch())) {
		TriangleExt te(*t);
		tset->add(&te);
	}
	delete patchEnumerator;
 
	// Build map Vertex -> list of colors
	typedef std::vector<Color *> TColorPtrList;
	typedef std::map<std::string, TColorPtrList> TVertexMap;
	TVertexMap vertexMap;
	for(size_t i=0; i<tset->count(); i++) {
		TriangleExt &te = tset->operator[](i);
 
		for(int j=0; j<3; j++) {
			TColorPtrList &cpList = vertexMap[vertexToString(te.vertex[j])];
			cpList.push_back(te.vertexColor+j);
		}
	}
 
	// Interpolate vertex colors from triangle colors
	TVertexMap::iterator i;
	for(i= vertexMap.begin(); i!= vertexMap.end(); i++) {
		TColorPtrList &cpList= i->second;
		TColorPtrList::iterator j;
 
		Color sum(0.0, 0.0, 0.0);
		int n=0;
		for(j= cpList.begin(); j!= cpList.end(); j++) {
			Color &color= **j;
			if (Color(0.0,0.0,0.0)==color)
				// Ignore black triangles
				continue;
			sum += color;
			n++;
		}
		if (n>1)
			sum *= 1.0f/n;
 
		for(j= cpList.begin(); j!= cpList.end(); j++) {
			Color &color= **j;
			color = sum;
		}
	}
 
	// Save 1st level interpolation
	for(size_t i=0; i<tset->count(); i++) {
		TriangleExt &te = tset->operator[](i);
 
		for(int j=0; j<3; j++)
			te.vertexColorRaw[j] = te.vertexColor[j];
	}
 
	// Interpolate triangle colors from vertex colors
	for(size_t i=0; i<tset->count(); i++) {
		TriangleExt &te = tset->operator[](i);
 
		Color sum(0.0, 0.0, 0.0);
		for(int j=0; j<3; j++) {
			sum += te.vertexColor[j];
		}
		sum *= 1.0f/3;
		te.radiosityLast = sum;
		for(int n=0; n<3; n++)
			te.vertexColor[n] = sum;
	}
 
	// Interpolate vertex colors from trinagle colors again
	for(i= vertexMap.begin(); i!= vertexMap.end(); i++) {
		TColorPtrList &cpList= i->second;
		TColorPtrList::iterator j;
		Color sum(0.0, 0.0, 0.0);
		for(j= cpList.begin(); j!= cpList.end(); j++) {
			Color &color= **j;
			sum += color;
		}
		sum *= 1.0f/cpList.size();
		for(j= cpList.begin(); j!= cpList.end(); j++) {
			Color &color= **j;
			color = sum;
		}
	}
 
	return tset;
}