new DotScene loader

Discussion area about developing or extending OGRE, adding plugins for it or building applications on it. No newbie questions please, use the Help forum for that.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179

Re: new DotScene loader

Post by jacmoe »

cottonbelly wrote:Sent: Tue Feb 10, 2009 1:54 pm
From: cottonbelly
To: wolverine

Hi:

First of all, thanks for your work on the DotSceneFormat.

In my company, we make extensive use of XSI as a modeling tool, and thus we are in need of a good workflow solution between XSI and Ogre. The DotScene format seems a good answer to us.

You said in the forum that "no exporter is currently available", in fact there exists an XSI Exporter (Lodes 2006) but the output .scene can't be parsed by the current DotSceneFormat SVN implementation.

Our proposal is the update Lodes' XSI Tool so that its DotScene validates the current DTD, which can be found on the SVN. Does this idea sound good to you?

You said on the Ogre forum that you were about to commit changes to DotSceneFormat early 2009. Is it ongoing? Shall we wait for these changes to start updating the XSI Tool?

Thanks in advance for your feedback,
François.


Sent: Fri Feb 13, 2009 1:53 am
From: wolverine
To: cottonbelly

Dear François,
First of all, thanks for your work on the DotSceneFormat.
Thank you, we welcome welcome every appreciation. :-)

First I have to apologize but I haven't had the time to do that commit. :-( Unfortunatelly we are working on a game for a really long time by now, it is near to become finished (about 95%), however due to many circimstances we weren't able to get ready with it by the time we originally planned. This game is really important for the whole team, for the whole company and for me too. A lot of things in the future depends on it. So I think I won't have time too much time until we have published it (if everything goes well this will be at the beginning of April 2009).
I didn't even manage to answer to all of the e-mails and private messages relating to the new dotScene loader in the last few weeks :-(. Now I'm writing this letter instead of sleeping :-D.
The web page of the game is going to be http://www.rivalryofgods.com. :-) Currently it is empty, but not for too long... :-)


However I've got good news. :-)
One of my colleague have already developed an up-to-date exporter for XSI, and although as long as I remember it isn't finished fully, it can export *most* of the functionality of the *new* :-) dotScene format. We are planning to release it under LGPL, just as with the other parts of the source (again we just didn't have the time to do it).
Please send an e-mail to Breathing Bytes, reference to this e-mail and ask for it, my colleagues will send it to you. I'm really happy to hear that you wish to further develop it and thank you for it :-).
One of our Ukraine friends have already developed the serialization part for dotScene :-). We didn't had the time to test it (we don't need it in our current game), however for the first look it looks really promising and finished. If you wish we can send this to you as well, it is probably not going to be included in the next commit, because it is untested and probably unstable and uncapable for real production environment.
There were other modifications for the dotScene related projects too (interface for modification, renderWindow, viewport parsing, some minor bugfixes in dotSceneViewer, etc.)
The whole dotSceneInterface gets ported to Macintosh and Linux (the Linux port was done previously) in the next 2 weeks. :-)
We've got plenty of modifications for Ogre core itself by now and we are planning to release them as well (well we wish to and we have to because of LGPL).
BTW, if you can and wish, please post your last e-mail and this e-mail on the Ogre forums as well, so the community still gets informed about what's going on.

Cheers,
Balázs Hajdics
Thanks for letting us know. :)
(A bit late, but..)

I wonder: would be possible to get hold of the source? I'd like to revive the dotscene addon.
I see Wolverine made changes to it, but since it's left in an unfinished state...

Cottonbelly: Did you get any source? If you did, throw it my way. Thanks. :)
Would be cool if we could get those changes into the repository.
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
JulyForToday
Gnoblar
Posts: 4
Joined: Thu Apr 21, 2005 9:20 pm

Re: new DotScene loader

Post by JulyForToday »

Hi everybody!

So I've been trying to get the loader to work for a little while. I had similar issues with tinyXML and string errors like some in the beginning of this thread, and was able to fix it based on that information. The I got endless other linking errors, and went about tinkering with include paths to make sure I had everything available to the compiler. Eventually I added an include for every tinyXML file (only tinyxml.h was in the source code), except XMLtester, into my DotSceneLoader.cpp and now I only have 1 error message. It says
L:\Work\GameDev\_IDE\CodeBlocks\MinGW\bin\..\lib\gcc\mingw32\3.4.5\..\..\..\libmingw32.a(main.o):main.c:(.text+0x104)||undefined reference to `_WinMain@16'|
||=== Build finished: 1 errors, 0 warnings ===|
I get the same error message if I try compiling TinyXML by itself. After googling around, supposedly such a message is related to a lack of a main function, yet tinyxml and dotscene shouldn't really have a main function since they are going to be referenced by an app that has a main function. So I'm guessing I still have something setup wrong, or that maybe I haven't installed the mingw toolbox properly. But honestly, I have no idea how to actually fix this. It's 2am and I'm going crazy. lol

Thanks for helping out another noob. :)
soldans
Halfling
Posts: 53
Joined: Sat May 19, 2007 10:27 pm
x 1

Re: new DotScene loader

Post by soldans »

NIce, it works and stuff, will save my and my teammembers lot of time.

But really, what license is it released under? :?
User avatar
typist
Kobold
Posts: 36
Joined: Mon Apr 02, 2007 3:48 am
Location: Toronto, Canada

Re: new DotScene loader

Post by typist »

Are there sample .scene files to check and demonstrate all the capabilities of the new DotScene
Loader. I did not find any sample .scene files anywhere other than the simple one posted on this wiki.

Also does the exisiting Blender dotScene Exporter script, from the subversion trunk ver. 2753 - the same as the
direct download from the wiki (at the time of writing this post), create .scene files conforming to
the new DotScene Loader parser? I think not because if one tries to export a simple cube, or the
monkey (Suzanne) from Blender those .scene files are not read by the new DotScene Loader correctly.

Any help on some sample .scene files and whether the Blender script conforms to the new DotScene
Loader format or not, is much appreciated.
venomjiamer
Gnoblar
Posts: 3
Joined: Sun Nov 08, 2009 2:38 pm

Re: new DotScene loader

Post by venomjiamer »

Hi , JeDi
I' m a new boy learning OGRE.
Now I don't know how to load a .scene file into my OGRE project.
I have read your code and could you tell me how should I make use of your class. :lol:
User avatar
spacegaier
OGRE Team Member
OGRE Team Member
Posts: 4308
Joined: Mon Feb 04, 2008 2:02 pm
Location: Germany
x 137

Re: new DotScene loader

Post by spacegaier »

I've shown that in my AdvancedOgreFramework in the wiki in the createScene() method in this class.
Ogre Admin [Admin, Dev, PR, Finance, Wiki, etc.] | BasicOgreFramework | AdvancedOgreFramework
Don't know what to do in your spare time? Help the Ogre wiki grow! Or squash a bug...
JeDi
Gnome
Posts: 351
Joined: Thu Oct 21, 2004 1:34 pm
Location: Diepenbeek, Belgium
x 3

Re: new DotScene loader

Post by JeDi »

You should compile it together with libxml, than you can use it as shown above.

Note that my dotscene loader class is very old, and doesn't conform with the new dotscene scheme (which seems to be half-baked anyway, but that's another thing). I guess there are better, more complete loaders around, including the one bundled with ogremax.

We still use a slightly modified version of this loader, but we only need a very limited subset of Ogre's scene features, as we only use dotScene for our static level meshes.

Greetz,
JeDi
venomjiamer
Gnoblar
Posts: 3
Joined: Sun Nov 08, 2009 2:38 pm

Re: new DotScene loader

Post by venomjiamer »

JeDi wrote:You should compile it together with libxml, than you can use it as shown above.

Note that my dotscene loader class is very old, and doesn't conform with the new dotscene scheme (which seems to be half-baked anyway, but that's another thing). I guess there are better, more complete loaders around, including the one bundled with ogremax.

We still use a slightly modified version of this loader, but we only need a very limited subset of Ogre's scene features, as we only use dotScene for our static level meshes.

Greetz,
JeDi
Thank you JeDi!
I have built your Loader with tinyXML and it works. As you say , I only need dotScene for my static objects rightnow.
venomjiamer
Gnoblar
Posts: 3
Joined: Sun Nov 08, 2009 2:38 pm

Re: new DotScene loader

Post by venomjiamer »

spacegaier wrote:I've shown that in my AdvancedOgreFramework in the wiki in the createScene() method in this class.
Thank you so much!
I am the boy and you are the magician, your article is exactly what I looking for~ :D :lol: :lol:
Zamx
Halfling
Posts: 54
Joined: Sat Feb 14, 2009 5:40 pm

Re: new DotScene loader

Post by Zamx »

Hi,

I'm trying to load a .scene file with the new DotScene Loader from JeDI, but I'm getting heap errors while parsing the.scene file with visual studio. I have build TinyXML and linked the lib file to my project. Do I need to use libxml like JeDi said above or TinyXML like on the wiki page?
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179

Re: new DotScene loader

Post by jacmoe »

His loader was new in 2006. :)
You can use the advanced Ogre framework, or TinyXML as you read on the wiki.
You could, of course, use JeDi's loader, but that requires libXml (as he pointed out).

Another option, which I haven't tried (yet) is to use FastXML:
http://www.amillionpixels.us/FastXml.h
http://www.amillionpixels.us/FastXml.cpp
(From John W. Ratcliff)

It's important that you realise that a .scene file is just a regular XML file. :wink:
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
Zamx
Halfling
Posts: 54
Joined: Sat Feb 14, 2009 5:40 pm

Re: new DotScene loader

Post by Zamx »

I'm using the loader from the advanced Ogre framework. Every time I load in my scene file it crashes in TinyXML during parsing (in TiXmlDocument) . There is nothing wrong with the scene file. Can it be that I'm doing something wrong with my scene manager?
Zamx
Halfling
Posts: 54
Joined: Sat Feb 14, 2009 5:40 pm

Re: new DotScene loader

Post by Zamx »

I fixed the problem. It had nothing to do with Ogre. I had to change my runtime libary to Multi-threaded Debug DLL (/MDd) in the properties of my project.
Thanks jacmoe for trying to help me.
xecola
Kobold
Posts: 29
Joined: Tue Nov 17, 2009 11:19 pm

Re:

Post by xecola »

metaldev wrote:Jedi,

you were correct, being a noob at C++ i didnt know that it made a difference if you linked to a file than actually having it built in with your project.

So it compiles now (with the tinyXML from sourceforge).

The change to the code included adding .c_str() and making sure tinyXml source are listed in the same project.

it seems to use your code properly i will have to learn to use the ResourceGroupManager first which i will do next.

thanks for your help!
Hi, I could u please make this more specifically?

Many thx
xecola
Kobold
Posts: 29
Joined: Tue Nov 17, 2009 11:19 pm

Re:

Post by xecola »

JeDi wrote:Glad I could help. You can enable stl support with some flag in tinyxml by the way, so the .c_str() additions aren't necessary. But it works exactly the same.

Greetz,
JeDi
Hi Jedi, which flag i shoud set for TIXML_USE_STL?

Mant thx
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179

Re: new DotScene loader

Post by jacmoe »

I've updated this fine loader to using RapidXml instead of TinyXML. :)
Works great.

Header:

Code: Select all

#ifndef DOT_SCENELOADER_H
#define DOT_SCENELOADER_H

// Includes
#include <Ogre/OgreString.h>
#include <Ogre/OgreVector3.h>
#include <Ogre/OgreQuaternion.h>
#include <Ogre/OgreResourceGroupManager.h>
#include <vector>

#include "rapidxml.hpp"

namespace Ogre
{
	// Forward declarations
	class SceneManager;
	class SceneNode;

	class nodeProperty
	{
	public:
		String nodeName;
		String propertyNm;
		String valueName;
		String typeName;

		nodeProperty(const String &node, const String &propertyName, const String &value, const String &type)
			: nodeName(node), propertyNm(propertyName), valueName(value), typeName(type) {}
	};

	class DotSceneLoader
	{
	public:
		DotSceneLoader() : mSceneMgr(0) {}
		virtual ~DotSceneLoader() {}

		class FileLocator : public Ogre::ResourceGroupManager
		{
		public:
			FileLocator() {}
			~FileLocator() {}

			Ogre::Archive *Find(Ogre::String &filename)
			{
				ResourceGroup* grp = getResourceGroup("General");
				if (!grp)
					OGRE_EXCEPT(Ogre::Exception::ERR_ITEM_NOT_FOUND, "Cannot locate a resource group called 'General'", "ResourceGroupManager::openResource");

				OGRE_LOCK_MUTEX(grp->OGRE_AUTO_MUTEX_NAME) // lock group mutex
					ResourceLocationIndex::iterator rit = grp->resourceIndexCaseSensitive.find(filename);
				if (rit != grp->resourceIndexCaseSensitive.end())
				{
					// Found in the index
					Ogre::Archive *fileArchive = rit->second;
					filename = fileArchive->getName() + "/" + filename;
					return fileArchive;
				}
				return NULL;
			}
		};
		
		void parseDotScene(const String &SceneName, const String &groupName, SceneManager *yourSceneMgr, SceneNode *pAttachNode = NULL, const String &sPrependNode = "");
		String getProperty(const String &ndNm, const String &prop);

		std::vector<nodeProperty> nodeProperties;
		std::vector<String> staticObjects;
		std::vector<String> dynamicObjects;

	protected:
		void processScene(rapidxml::xml_node<>* XMLRoot);

		void processNodes(rapidxml::xml_node<>* XMLNode);
		void processExternals(rapidxml::xml_node<>* XMLNode);
		void processEnvironment(rapidxml::xml_node<>* XMLNode);
		void processTerrain(rapidxml::xml_node<>* XMLNode);
		void processUserDataReference(rapidxml::xml_node<>* XMLNode, SceneNode *pParent = 0);
		void processUserDataReference(rapidxml::xml_node<>* XMLNode, Entity *pEntity);
		void processOctree(rapidxml::xml_node<>* XMLNode);
		void processLight(rapidxml::xml_node<>* XMLNode, SceneNode *pParent = 0);
		void processCamera(rapidxml::xml_node<>* XMLNode, SceneNode *pParent = 0);

		void processNode(rapidxml::xml_node<>* XMLNode, SceneNode *pParent = 0);
		void processLookTarget(rapidxml::xml_node<>* XMLNode, SceneNode *pParent);
		void processTrackTarget(rapidxml::xml_node<>* XMLNode, SceneNode *pParent);
		void processEntity(rapidxml::xml_node<>* XMLNode, SceneNode *pParent);
		void processParticleSystem(rapidxml::xml_node<>* XMLNode, SceneNode *pParent);
		void processBillboardSet(rapidxml::xml_node<>* XMLNode, SceneNode *pParent);
		void processPlane(rapidxml::xml_node<>* XMLNode, SceneNode *pParent);

		void processFog(rapidxml::xml_node<>* XMLNode);
		void processSkyBox(rapidxml::xml_node<>* XMLNode);
		void processSkyDome(rapidxml::xml_node<>* XMLNode);
		void processSkyPlane(rapidxml::xml_node<>* XMLNode);
		void processClipping(rapidxml::xml_node<>* XMLNode);

		void processLightRange(rapidxml::xml_node<>* XMLNode, Light *pLight);
		void processLightAttenuation(rapidxml::xml_node<>* XMLNode, Light *pLight);

		String getAttrib(rapidxml::xml_node<>* XMLNode, const String &parameter, const String &defaultValue = "");
		Real getAttribReal(rapidxml::xml_node<>* XMLNode, const String &parameter, Real defaultValue = 0);
		bool getAttribBool(rapidxml::xml_node<>* XMLNode, const String &parameter, bool defaultValue = false);

		Vector3 parseVector3(rapidxml::xml_node<>* XMLNode);
		Quaternion parseQuaternion(rapidxml::xml_node<>* XMLNode);
		ColourValue parseColour(rapidxml::xml_node<>* XMLNode);
		

		SceneManager *mSceneMgr;
		SceneNode *mAttachNode;
		String m_sGroupName;
		String m_sPrependNode;
	};
}

#endif // DOT_SCENELOADER_H
Implementation:

Code: Select all

#include "DotSceneLoader.h"
#include <Ogre/Ogre.h>

#include "rapidxml_utils.hpp"

using namespace std;
using namespace Ogre;

void DotSceneLoader::parseDotScene(const String &SceneName, const String &groupName, SceneManager *yourSceneMgr, SceneNode *pAttachNode, const String &sPrependNode)
{
	// set up shared object values
	m_sGroupName = groupName;
	mSceneMgr = yourSceneMgr;
	m_sPrependNode = sPrependNode;
	staticObjects.clear();
	dynamicObjects.clear();

	rapidxml::xml_document<> XMLDoc;    // character type defaults to char

	rapidxml::xml_node<>* XMLRoot;

	String fileName = SceneName;
	FileLocator * fileLocator = (FileLocator * )Ogre::ResourceGroupManager::getSingletonPtr();
	Ogre::Archive* fileArchive = fileLocator->Find(fileName);

	rapidxml::file<> file(fileName.c_str());

	// Open the .scene File
	XMLDoc.parse<0>( file.data() );

	// Grab the scene node
	XMLRoot = XMLDoc.first_node("scene");

	// Validate the File
	//if( String( XMLRoot->first_attribute()->value()) != "formatVersion"  ) {
	//	LogManager::getSingleton().logMessage( "[DotSceneLoader] Error: Invalid .scene File. Missing <scene>" );
	//	return;
	//}

	// figure out where to attach any nodes we create
	mAttachNode = pAttachNode;
	if(!mAttachNode)
		mAttachNode = mSceneMgr->getRootSceneNode();

	// Process the scene
	processScene(XMLRoot);
}

void DotSceneLoader::processScene(rapidxml::xml_node<>* XMLRoot)
{
	// Process the scene parameters
	String version = getAttrib(XMLRoot, "formatVersion", "unknown");

	String message = "[DotSceneLoader] Parsing dotScene file with version " + version;
	if(XMLRoot->first_attribute("ID"))
		message += ", id " + String(XMLRoot->first_attribute("ID")->value());
	if(XMLRoot->first_attribute("sceneManager"))
		message += ", scene manager " + String(XMLRoot->first_attribute("sceneManager")->value());
	if(XMLRoot->first_attribute("minOgreVersion"))
		message += ", min. Ogre version " + String(XMLRoot->first_attribute("minOgreVersion")->value());
	if(XMLRoot->first_attribute("author"))
		message += ", author " + String(XMLRoot->first_attribute("author")->value());

	LogManager::getSingleton().logMessage(message);

	rapidxml::xml_node<>* pElement;

	// Process nodes (?)
	pElement = XMLRoot->first_node("nodes");
	if(pElement)
		processNodes(pElement);

	// Process externals (?)
	pElement = XMLRoot->first_node("externals");
	if(pElement)
		processExternals(pElement);

	// Process environment (?)
	pElement = XMLRoot->first_node("environment");
	if(pElement)
		processEnvironment(pElement);

	// Process terrain (?)
	pElement = XMLRoot->first_node("terrain");
	if(pElement)
		processTerrain(pElement);

	// Process userDataReference (?)
	pElement = XMLRoot->first_node("userDataReference");
	if(pElement)
		processUserDataReference(pElement);

	// Process octree (?)
	pElement = XMLRoot->first_node("octree");
	if(pElement)
		processOctree(pElement);

	// Process light (?)
	pElement = XMLRoot->first_node("light");
	if(pElement)
		processLight(pElement);

	// Process camera (?)
	pElement = XMLRoot->first_node("camera");
	if(pElement)
		processCamera(pElement);
}

void DotSceneLoader::processNodes(rapidxml::xml_node<>* XMLNode)
{
	rapidxml::xml_node<>* pElement;

	// Process node (*)
	pElement = XMLNode->first_node("node");
	while(pElement)
	{
		processNode(pElement);
		pElement = pElement->next_sibling("node");
	}

	// Process position (?)
	pElement = XMLNode->first_node("position");
	if(pElement)
	{
		mAttachNode->setPosition(parseVector3(pElement));
		mAttachNode->setInitialState();
	}

	// Process rotation (?)
	pElement = XMLNode->first_node("rotation");
	if(pElement)
	{
		mAttachNode->setOrientation(parseQuaternion(pElement));
		mAttachNode->setInitialState();
	}

	// Process scale (?)
	pElement = XMLNode->first_node("scale");
	if(pElement)
	{
		mAttachNode->setScale(parseVector3(pElement));
		mAttachNode->setInitialState();
	}
}

void DotSceneLoader::processExternals(rapidxml::xml_node<>* XMLNode)
{
	//! @todo Implement this
}

void DotSceneLoader::processEnvironment(rapidxml::xml_node<>* XMLNode)
{
	rapidxml::xml_node<>* pElement;

	// Process fog (?)
	pElement = XMLNode->first_node("fog");
	if(pElement)
		processFog(pElement);

	// Process skyBox (?)
	pElement = XMLNode->first_node("skyBox");
	if(pElement)
		processSkyBox(pElement);

	// Process skyDome (?)
	pElement = XMLNode->first_node("skyDome");
	if(pElement)
		processSkyDome(pElement);

	// Process skyPlane (?)
	pElement = XMLNode->first_node("skyPlane");
	if(pElement)
		processSkyPlane(pElement);

	// Process clipping (?)
	pElement = XMLNode->first_node("clipping");
	if(pElement)
		processClipping(pElement);

	// Process colourAmbient (?)
	pElement = XMLNode->first_node("colourAmbient");
	if(pElement)
		mSceneMgr->setAmbientLight(parseColour(pElement));

	// Process colourBackground (?)
	//! @todo Set the background colour of all viewports (RenderWindow has to be provided then)
	pElement = XMLNode->first_node("colourBackground");
	if(pElement)
		;//mSceneMgr->set(parseColour(pElement));

	// Process userDataReference (?)
	pElement = XMLNode->first_node("userDataReference");
	if(pElement)
		processUserDataReference(pElement);
}

void DotSceneLoader::processTerrain(rapidxml::xml_node<>* XMLNode)
{
	//! @todo Implement this
}

void DotSceneLoader::processUserDataReference(rapidxml::xml_node<>* XMLNode, SceneNode *pParent)
{
	//! @todo Implement this
}

void DotSceneLoader::processOctree(rapidxml::xml_node<>* XMLNode)
{
	//! @todo Implement this
}

void DotSceneLoader::processLight(rapidxml::xml_node<>* XMLNode, SceneNode *pParent)
{
	// Process attributes
	String name = getAttrib(XMLNode, "name");
	String id = getAttrib(XMLNode, "id");

	// Create the light
	Light *pLight = mSceneMgr->createLight(name);
	if(pParent)
		pParent->attachObject(pLight);

	String sValue = getAttrib(XMLNode, "type");
	if(sValue == "point")
		pLight->setType(Light::LT_POINT);
	else if(sValue == "directional")
		pLight->setType(Light::LT_DIRECTIONAL);
	else if(sValue == "spot")
		pLight->setType(Light::LT_SPOTLIGHT);
	else if(sValue == "radPoint")
		pLight->setType(Light::LT_POINT);

	pLight->setVisible(getAttribBool(XMLNode, "visible", true));
	pLight->setCastShadows(getAttribBool(XMLNode, "castShadows", true));

	rapidxml::xml_node<>* pElement;

	// Process position (?)
	pElement = XMLNode->first_node("position");
	if(pElement)
		pLight->setPosition(parseVector3(pElement));

	// Process normal (?)
	pElement = XMLNode->first_node("normal");
	if(pElement)
		pLight->setDirection(parseVector3(pElement));

	// Process colourDiffuse (?)
	pElement = XMLNode->first_node("colourDiffuse");
	if(pElement)
		pLight->setDiffuseColour(parseColour(pElement));

	// Process colourSpecular (?)
	pElement = XMLNode->first_node("colourSpecular");
	if(pElement)
		pLight->setSpecularColour(parseColour(pElement));

	if(sValue != "directional")
	{
		// Process lightRange (?)
		pElement = XMLNode->first_node("lightRange");
		if(pElement)
			processLightRange(pElement, pLight);

		// Process lightAttenuation (?)
		pElement = XMLNode->first_node("lightAttenuation");
		if(pElement)
			processLightAttenuation(pElement, pLight);
	}
	// Process userDataReference (?)
	pElement = XMLNode->first_node("userDataReference");
	if(pElement)
		;//processUserDataReference(pElement, pLight);
}

void DotSceneLoader::processCamera(rapidxml::xml_node<>* XMLNode, SceneNode *pParent)
{
	// Process attributes
	String name = getAttrib(XMLNode, "name");
	String id = getAttrib(XMLNode, "id");
	Real fov = getAttribReal(XMLNode, "fov", 45);
	Real aspectRatio = getAttribReal(XMLNode, "aspectRatio", 1.3333);
	String projectionType = getAttrib(XMLNode, "projectionType", "perspective");

	// Create the camera
	Camera *pCamera = mSceneMgr->createCamera(name);
	Ogre::LogManager::getSingleton().logMessage(Ogre::String("[DotsceneLoader] Created camera with the name of ") + name);
	if(pParent)
		pParent->attachObject(pCamera);
	
	// Set the field-of-view
	//! @todo Is this always in degrees?
	pCamera->setFOVy(Ogre::Degree(fov));

	// Set the aspect ratio
	pCamera->setAspectRatio(aspectRatio);
	
	// Set the projection type
	if(projectionType == "perspective")
		pCamera->setProjectionType(PT_PERSPECTIVE);
	else if(projectionType == "orthographic")
		pCamera->setProjectionType(PT_ORTHOGRAPHIC);


	rapidxml::xml_node<>* pElement;

	// Process clipping (?)
	pElement = XMLNode->first_node("clipping");
	if(pElement)
	{
		Real nearDist = getAttribReal(pElement, "near");
		pCamera->setNearClipDistance(nearDist);

		Real farDist =  getAttribReal(pElement, "far");
		pCamera->setFarClipDistance(farDist);
	}

	// Process position (?)
	pElement = XMLNode->first_node("position");
	if(pElement)
		pCamera->setPosition(parseVector3(pElement));

	// Process rotation (?)
	pElement = XMLNode->first_node("rotation");
	if(pElement)
		pCamera->setOrientation(parseQuaternion(pElement));

	// Process normal (?)
	pElement = XMLNode->first_node("normal");
	if(pElement)
		;//!< @todo What to do with this element?

	// Process lookTarget (?)
	pElement = XMLNode->first_node("lookTarget");
	if(pElement)
		;//!< @todo Implement the camera look target

	// Process trackTarget (?)
	pElement = XMLNode->first_node("trackTarget");
	if(pElement)
		;//!< @todo Implement the camera track target

	// Process userDataReference (?)
	pElement = XMLNode->first_node("userDataReference");
	if(pElement)
		;//!< @todo Implement the camera user data reference
}

void DotSceneLoader::processNode(rapidxml::xml_node<>* XMLNode, SceneNode *pParent)
{
	// Construct the node's name
	String name = m_sPrependNode + getAttrib(XMLNode, "name");

	// Create the scene node
	SceneNode *pNode;
	if(name.empty())
	{
		// Let Ogre choose the name
		if(pParent)
			pNode = pParent->createChildSceneNode();
		else
			pNode = mAttachNode->createChildSceneNode();
	}
	else
	{
		// Provide the name
		if(pParent)
			pNode = pParent->createChildSceneNode(name);
		else
			pNode = mAttachNode->createChildSceneNode(name);
	}

	// Process other attributes
	String id = getAttrib(XMLNode, "id");
	bool isTarget = getAttribBool(XMLNode, "isTarget");

	rapidxml::xml_node<>* pElement;

	// Process position (?)
	pElement = XMLNode->first_node("position");
	if(pElement)
	{
		pNode->setPosition(parseVector3(pElement));
		pNode->setInitialState();
	}

	// Process rotation (?)
	pElement = XMLNode->first_node("rotation");
	if(pElement)
	{
		pNode->setOrientation(parseQuaternion(pElement));
		pNode->setInitialState();
	}

	// Process scale (?)
	pElement = XMLNode->first_node("scale");
	if(pElement)
	{
		pNode->setScale(parseVector3(pElement));
		pNode->setInitialState();
	}

	// Process lookTarget (?)
	pElement = XMLNode->first_node("lookTarget");
	if(pElement)
		processLookTarget(pElement, pNode);

	// Process trackTarget (?)
	pElement = XMLNode->first_node("trackTarget");
	if(pElement)
		processTrackTarget(pElement, pNode);

	// Process node (*)
	pElement = XMLNode->first_node("node");
	while(pElement)
	{
		processNode(pElement, pNode);
		pElement = pElement->next_sibling("node");
	}

	// Process entity (*)
	pElement = XMLNode->first_node("entity");
	while(pElement)
	{
		processEntity(pElement, pNode);
		pElement = pElement->next_sibling("entity");
	}

	// Process light (*)
	pElement = XMLNode->first_node("light");
	while(pElement)
	{
		processLight(pElement, pNode);
		pElement = pElement->next_sibling("light");
	}

	// Process camera (*)
	pElement = XMLNode->first_node("camera");
	while(pElement)
	{
		processCamera(pElement, pNode);
		pElement = pElement->next_sibling("camera");
	}

	// Process particleSystem (*)
	pElement = XMLNode->first_node("particleSystem");
	while(pElement)
	{
		processParticleSystem(pElement, pNode);
		pElement = pElement->next_sibling("particleSystem");
	}

	// Process billboardSet (*)
	pElement = XMLNode->first_node("billboardSet");
	while(pElement)
	{
		processBillboardSet(pElement, pNode);
		pElement = pElement->next_sibling("billboardSet");
	}

	// Process plane (*)
	pElement = XMLNode->first_node("plane");
	while(pElement)
	{
		processPlane(pElement, pNode);
		pElement = pElement->next_sibling("plane");
	}

	// Process userDataReference (?)
	pElement = XMLNode->first_node("userDataReference");
	if(pElement)
		processUserDataReference(pElement, pNode);
}

void DotSceneLoader::processLookTarget(rapidxml::xml_node<>* XMLNode, SceneNode *pParent)
{
	//! @todo Is this correct? Cause I don't have a clue actually

	// Process attributes
	String nodeName = getAttrib(XMLNode, "nodeName");

	Node::TransformSpace relativeTo = Node::TS_PARENT;
	String sValue = getAttrib(XMLNode, "relativeTo");
	if(sValue == "local")
		relativeTo = Node::TS_LOCAL;
	else if(sValue == "parent")
		relativeTo = Node::TS_PARENT;
	else if(sValue == "world")
		relativeTo = Node::TS_WORLD;

	rapidxml::xml_node<>* pElement;

	// Process position (?)
	Vector3 position;
	pElement = XMLNode->first_node("position");
	if(pElement)
		position = parseVector3(pElement);

	// Process localDirection (?)
	Vector3 localDirection = Vector3::NEGATIVE_UNIT_Z;
	pElement = XMLNode->first_node("localDirection");
	if(pElement)
		localDirection = parseVector3(pElement);

	// Setup the look target
	try
	{
		if(!nodeName.empty())
		{
			SceneNode *pLookNode = mSceneMgr->getSceneNode(nodeName);
			position = pLookNode->_getDerivedPosition();
		}

		pParent->lookAt(position, relativeTo, localDirection);
	}
	catch(Ogre::Exception &/*e*/)
	{
		LogManager::getSingleton().logMessage("[DotSceneLoader] Error processing a look target!");
	}
}

void DotSceneLoader::processTrackTarget(rapidxml::xml_node<>* XMLNode, SceneNode *pParent)
{
	// Process attributes
	String nodeName = getAttrib(XMLNode, "nodeName");

	rapidxml::xml_node<>* pElement;

	// Process localDirection (?)
	Vector3 localDirection = Vector3::NEGATIVE_UNIT_Z;
	pElement = XMLNode->first_node("localDirection");
	if(pElement)
		localDirection = parseVector3(pElement);

	// Process offset (?)
	Vector3 offset = Vector3::ZERO;
	pElement = XMLNode->first_node("offset");
	if(pElement)
		offset = parseVector3(pElement);

	// Setup the track target
	try
	{
		SceneNode *pTrackNode = mSceneMgr->getSceneNode(nodeName);
		pParent->setAutoTracking(true, pTrackNode, localDirection, offset);
	}
	catch(Ogre::Exception &/*e*/)
	{
		LogManager::getSingleton().logMessage("[DotSceneLoader] Error processing a track target!");
	}
}

void DotSceneLoader::processEntity(rapidxml::xml_node<>* XMLNode, SceneNode *pParent)
{
	// Process attributes
	String name = getAttrib(XMLNode, "name");
	String id = getAttrib(XMLNode, "id");
	String meshFile = getAttrib(XMLNode, "meshFile");
	String materialFile = getAttrib(XMLNode, "materialFile");
	bool isStatic = getAttribBool(XMLNode, "static", false);;
	bool castShadows = getAttribBool(XMLNode, "castShadows", true);

	// TEMP: Maintain a list of static and dynamic objects
	if(isStatic)
		staticObjects.push_back(name);
	else
		dynamicObjects.push_back(name);

	rapidxml::xml_node<>* pElement;

	// Process vertexBuffer (?)
	pElement = XMLNode->first_node("vertexBuffer");
	if(pElement)
		;//processVertexBuffer(pElement);

	// Process indexBuffer (?)
	pElement = XMLNode->first_node("indexBuffer");
	if(pElement)
		;//processIndexBuffer(pElement);

	// Create the entity
	Entity *pEntity = 0;
	try
	{
		MeshManager::getSingleton().load(meshFile, m_sGroupName);
		pEntity = mSceneMgr->createEntity(name, meshFile);
		pEntity->setCastShadows(castShadows);
		pParent->attachObject(pEntity);
		
		if(!materialFile.empty())
			pEntity->setMaterialName(materialFile);
	}
	catch(Ogre::Exception &/*e*/)
	{
		LogManager::getSingleton().logMessage("[DotSceneLoader] Error loading an entity!");
	}

	// Process userDataReference (?)
	pElement = XMLNode->first_node("userDataReference");
	if(pElement)
		processUserDataReference(pElement, pEntity);

	
}

void DotSceneLoader::processParticleSystem(rapidxml::xml_node<>* XMLNode, SceneNode *pParent)
{
	// Process attributes
	String name = getAttrib(XMLNode, "name");
	String id = getAttrib(XMLNode, "id");
	String file = getAttrib(XMLNode, "file");

	// Create the particle system
	try
	{
		ParticleSystem *pParticles = mSceneMgr->createParticleSystem(name, file);
		pParent->attachObject(pParticles);
	}
	catch(Ogre::Exception &/*e*/)
	{
		LogManager::getSingleton().logMessage("[DotSceneLoader] Error creating a particle system!");
	}
}

void DotSceneLoader::processBillboardSet(rapidxml::xml_node<>* XMLNode, SceneNode *pParent)
{
	//! @todo Implement this
}

void DotSceneLoader::processPlane(rapidxml::xml_node<>* XMLNode, SceneNode *pParent)
{
	//! @todo Implement this
}

void DotSceneLoader::processFog(rapidxml::xml_node<>* XMLNode)
{
	// Process attributes
	Real expDensity = getAttribReal(XMLNode, "expDensity", 0.001);
	Real linearStart = getAttribReal(XMLNode, "linearStart", 0.0);
	Real linearEnd = getAttribReal(XMLNode, "linearEnd", 1.0);

	FogMode mode = FOG_NONE;
	String sMode = getAttrib(XMLNode, "mode");
	if(sMode == "none")
		mode = FOG_NONE;
	else if(sMode == "exp")
		mode = FOG_EXP;
	else if(sMode == "exp2")
		mode = FOG_EXP2;
	else if(sMode == "linear")
		mode = FOG_LINEAR;

	rapidxml::xml_node<>* pElement;

	// Process colourDiffuse (?)
	ColourValue colourDiffuse = ColourValue::White;
	pElement = XMLNode->first_node("colourDiffuse");
	if(pElement)
		colourDiffuse = parseColour(pElement);

	// Setup the fog
	mSceneMgr->setFog(mode, colourDiffuse, expDensity, linearStart, linearEnd);
}

void DotSceneLoader::processSkyBox(rapidxml::xml_node<>* XMLNode)
{
	// Process attributes
	String material = getAttrib(XMLNode, "material");
	Real distance = getAttribReal(XMLNode, "distance", 5000);
	bool drawFirst = getAttribBool(XMLNode, "drawFirst", true);

	rapidxml::xml_node<>* pElement;

	// Process rotation (?)
	Quaternion rotation = Quaternion::IDENTITY;
	pElement = XMLNode->first_node("rotation");
	if(pElement)
		rotation = parseQuaternion(pElement);

	// Setup the sky box
	mSceneMgr->setSkyBox(true, material, distance, drawFirst, rotation, m_sGroupName);
}

void DotSceneLoader::processSkyDome(rapidxml::xml_node<>* XMLNode)
{
	// Process attributes
	String material = XMLNode->first_attribute("material")->value();
	Real curvature = getAttribReal(XMLNode, "curvature", 10);
	Real tiling = getAttribReal(XMLNode, "tiling", 8);
	Real distance = getAttribReal(XMLNode, "distance", 4000);
	bool drawFirst = getAttribBool(XMLNode, "drawFirst", true);

	rapidxml::xml_node<>* pElement;

	// Process rotation (?)
	Quaternion rotation = Quaternion::IDENTITY;
	pElement = XMLNode->first_node("rotation");
	if(pElement)
		rotation = parseQuaternion(pElement);

	// Setup the sky dome
	mSceneMgr->setSkyDome(true, material, curvature, tiling, distance, drawFirst, rotation, 16, 16, -1, m_sGroupName);
}

void DotSceneLoader::processSkyPlane(rapidxml::xml_node<>* XMLNode)
{
	// Process attributes
	String material = getAttrib(XMLNode, "material");
	Real planeX = getAttribReal(XMLNode, "planeX", 0);
	Real planeY = getAttribReal(XMLNode, "planeY", -1);
	Real planeZ = getAttribReal(XMLNode, "planeX", 0);
	Real planeD = getAttribReal(XMLNode, "planeD", 5000);
	Real scale = getAttribReal(XMLNode, "scale", 1000);
	Real bow = getAttribReal(XMLNode, "bow", 0);
	Real tiling = getAttribReal(XMLNode, "tiling", 10);
	bool drawFirst = getAttribBool(XMLNode, "drawFirst", true);

	// Setup the sky plane
	Plane plane;
	plane.normal = Vector3(planeX, planeY, planeZ);
	plane.d = planeD;
	mSceneMgr->setSkyPlane(true, plane, material, scale, tiling, drawFirst, bow, 1, 1, m_sGroupName);
}

void DotSceneLoader::processClipping(rapidxml::xml_node<>* XMLNode)
{
	//! @todo Implement this

	// Process attributes
	Real fNear = getAttribReal(XMLNode, "near", 0);
	Real fFar = getAttribReal(XMLNode, "far", 1);
}

void DotSceneLoader::processLightRange(rapidxml::xml_node<>* XMLNode, Light *pLight)
{
	// Process attributes
	Real inner = getAttribReal(XMLNode, "inner");
	Real outer = getAttribReal(XMLNode, "outer");
	Real falloff = getAttribReal(XMLNode, "falloff", 1.0);

	// Setup the light range
	pLight->setSpotlightRange(Angle(inner), Angle(outer), falloff);
}

void DotSceneLoader::processLightAttenuation(rapidxml::xml_node<>* XMLNode, Light *pLight)
{
	// Process attributes
	Real range = getAttribReal(XMLNode, "range");
	Real constant = getAttribReal(XMLNode, "constant");
	Real linear = getAttribReal(XMLNode, "linear");
	Real quadratic = getAttribReal(XMLNode, "quadratic");

	// Setup the light attenuation
	pLight->setAttenuation(range, constant, linear, quadratic);
}


String DotSceneLoader::getAttrib(rapidxml::xml_node<>* XMLNode, const String &attrib, const String &defaultValue)
{
	if(XMLNode->first_attribute(attrib.c_str()))
		return XMLNode->first_attribute(attrib.c_str())->value();
	else
		return defaultValue;
}

Real DotSceneLoader::getAttribReal(rapidxml::xml_node<>* XMLNode, const String &attrib, Real defaultValue)
{
	if(XMLNode->first_attribute(attrib.c_str()))
		return StringConverter::parseReal(XMLNode->first_attribute(attrib.c_str())->value());
	else
		return defaultValue;
}

bool DotSceneLoader::getAttribBool(rapidxml::xml_node<>* XMLNode, const String &attrib, bool defaultValue)
{
	if(!XMLNode->first_attribute(attrib.c_str()))
		return defaultValue;

	if(String(XMLNode->first_attribute(attrib.c_str())->value()) == "true")
		return true;

	return false;
}

Vector3 DotSceneLoader::parseVector3(rapidxml::xml_node<>* XMLNode)
{
	return Vector3(
		StringConverter::parseReal(XMLNode->first_attribute("x")->value()),
		StringConverter::parseReal(XMLNode->first_attribute("y")->value()),
		StringConverter::parseReal(XMLNode->first_attribute("z")->value())
	);
}

Quaternion DotSceneLoader::parseQuaternion(rapidxml::xml_node<>* XMLNode)
{
	//! @todo Fix this crap!

	Quaternion orientation;

	if(XMLNode->first_attribute("qx"))
	{
		orientation.x = StringConverter::parseReal(XMLNode->first_attribute("qx")->value());
		orientation.y = StringConverter::parseReal(XMLNode->first_attribute("qy")->value());
		orientation.z = StringConverter::parseReal(XMLNode->first_attribute("qz")->value());
		orientation.w = StringConverter::parseReal(XMLNode->first_attribute("qw")->value());
	}
	else if(XMLNode->first_attribute("axisX"))
	{
		Vector3 axis;
		axis.x = StringConverter::parseReal(XMLNode->first_attribute("axisX")->value());
		axis.y = StringConverter::parseReal(XMLNode->first_attribute("axisY")->value());
		axis.z = StringConverter::parseReal(XMLNode->first_attribute("axisZ")->value());
		Real angle = StringConverter::parseReal(XMLNode->first_attribute("angle")->value());;
		orientation.FromAngleAxis(Ogre::Angle(angle), axis);
	}
	else if(XMLNode->first_attribute("angleX"))
	{
		Vector3 axis;
		axis.x = StringConverter::parseReal(XMLNode->first_attribute("angleX")->value());
		axis.y = StringConverter::parseReal(XMLNode->first_attribute("angleY")->value());
		axis.z = StringConverter::parseReal(XMLNode->first_attribute("angleZ")->value());
		//orientation.FromAxes(&axis);
		//orientation.F
	}

	return orientation;
}

ColourValue DotSceneLoader::parseColour(rapidxml::xml_node<>* XMLNode)
{
	return ColourValue(
		StringConverter::parseReal(XMLNode->first_attribute("r")->value()),
		StringConverter::parseReal(XMLNode->first_attribute("g")->value()),
		StringConverter::parseReal(XMLNode->first_attribute("b")->value()),
		XMLNode->first_attribute("a") != NULL ? StringConverter::parseReal(XMLNode->first_attribute("a")->value()) : 1
	);
}

String DotSceneLoader::getProperty(const String &ndNm, const String &prop)
{
	for ( unsigned int i = 0 ; i < nodeProperties.size(); i++ )
	{
		if ( nodeProperties[i].nodeName == ndNm && nodeProperties[i].propertyNm == prop )
		{
			return nodeProperties[i].valueName;
		}
	}

	return "";
}

void DotSceneLoader::processUserDataReference(rapidxml::xml_node<>* XMLNode, Entity *pEntity)
{
	String str = XMLNode->first_attribute("id")->value();
	pEntity->setUserAny(Any(str));
}
Why RapidXml ?
It's only two headers - one if you don't use the utilities - so it's much more manageable than TinyXML.

To use the code, get RapidXml from here:
http://rapidxml.sourceforge.net/

I am going to do a wiki article, but I need to make it more robust first.
And it wouldn't hurt to get some feedback and putting it to some tests.

Thanks JeDi, for the original.
Enjoy. :wink:
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179

Re: new DotScene loader

Post by jacmoe »

Here's how I use it:

Code: Select all

void SampleApp::createScene(void)
{
	Ogre::DotSceneLoader loader;
	loader.parseDotScene("SampleScene2.xml","General", mSceneMgr);

	// Set ambient light
	mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));

	// Grab the first available camera, for now
	std::vector<Ogre::String> camNames;
	Ogre::SceneManager::CameraIterator cameras = mSceneMgr->getCameraIterator();
	while (cameras.hasMoreElements())
	{
		Ogre::Camera* camera = cameras.getNext();
		camNames.push_back(camera->getName());
	}
	Ogre::String camName = camNames[0];
	mCamera->setPosition(mSceneMgr->getCamera(camName)->getPosition());
	mCamera->setOrientation(mSceneMgr->getCamera(camName)->getOrientation());
	mCamera->setNearClipDistance(mSceneMgr->getCamera(camName)->getNearClipDistance());
	mCamera->setFarClipDistance(mSceneMgr->getCamera(camName)->getFarClipDistance());
}
The last bit of code is not the most elegant code in the world, but it does the job. :wink:

As long as the xml/scene file is somewhere in your resource directories, it will work.
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
JeDi
Gnome
Posts: 351
Joined: Thu Oct 21, 2004 1:34 pm
Location: Diepenbeek, Belgium
x 3

Re: new DotScene loader

Post by JeDi »

jacmoe wrote:Thanks JeDi, for the original.
Well, I just cleaned up the parser found in the wiki, so you should be thanking them too ;)
modred11
Gnoblar
Posts: 4
Joined: Fri Feb 12, 2010 5:55 am

Re: new DotScene loader

Post by modred11 »

I think we should put Jacmoe's FastXML version onto the Wiki as the new version, as I also had that problem with the "if(XMLNode->Attribute(attrib))"s, and #define TIXML_USE_STL didn't do anything. But the FastXML version works fine for me.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179

Re: new DotScene loader

Post by jacmoe »

RapidXML is great! :)
It's only one header - I found a way to get rid of rapidxml_utils.hpp - so it's really only one single header.
No library, no cpp's - just drop rapidxml.h in your project and you're ready to parse.
And the syntax is very similar to TinyXML which makes it a breeze to port.

I'll post something once it's matured a bit more. :wink:
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179

Re: new DotScene loader

Post by jacmoe »

The RapidXML loader has been updated:

Usage:

Code: Select all

   mLoader = new DotSceneLoader();
   mLoader->parseDotScene(mSceneFile, "General", mSceneMgr);
Due to the loader being used for loading terrain, it has a getTerrainGroup accessor function, since it manages the terrain objects internally.

It's a work in progress, and lives in the Ogitor repository:
http://hg.ogitor.org/unstable

Get rapidxml.hpp from RapidXML website, and just add it to your project. That's it. Only one single header. :)

DotSceneLoader.h:

Code: Select all

#ifndef DOT_SCENELOADER_H
#define DOT_SCENELOADER_H

// Includes
#include <OgreString.h>
#include <OgreVector3.h>
#include <OgreQuaternion.h>
#include <OgreResourceGroupManager.h>
#include <vector>

#include "rapidxml.hpp"

	// Forward declarations
	namespace Ogre
	{
		class SceneManager;
		class SceneNode;
		class TerrainGroup;
        class TerrainGlobalOptions;
	}

	class nodeProperty
	{
	public:
		Ogre::String nodeName;
		Ogre::String propertyNm;
		Ogre::String valueName;
		Ogre::String typeName;

		nodeProperty(const Ogre::String &node, const Ogre::String &propertyName, const Ogre::String &value, const Ogre::String &type)
			: nodeName(node), propertyNm(propertyName), valueName(value), typeName(type) {}
	};

	class DotSceneLoader
	{
	public:
        Ogre::TerrainGlobalOptions *mTerrainGlobalOptions;
        
        DotSceneLoader();
		virtual ~DotSceneLoader();

		void parseDotScene(const Ogre::String &SceneName, const Ogre::String &groupName, Ogre::SceneManager *yourSceneMgr, Ogre::SceneNode *pAttachNode = NULL, const Ogre::String &sPrependNode = "");
		Ogre::String getProperty(const Ogre::String &ndNm, const Ogre::String &prop);

		Ogre::TerrainGroup* getTerrainGroup() { return mTerrainGroup; }

		std::vector<nodeProperty> nodeProperties;
		std::vector<Ogre::String> staticObjects;
		std::vector<Ogre::String> dynamicObjects;

	protected:
		void processScene(rapidxml::xml_node<>* XMLRoot);

		void processNodes(rapidxml::xml_node<>* XMLNode);
		void processExternals(rapidxml::xml_node<>* XMLNode);
		void processEnvironment(rapidxml::xml_node<>* XMLNode);
		void processTerrain(rapidxml::xml_node<>* XMLNode);
		void processTerrainPage(rapidxml::xml_node<>* XMLNode);
		void processBlendmaps(rapidxml::xml_node<>* XMLNode);
		void processUserDataReference(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent = 0);
		void processUserDataReference(rapidxml::xml_node<>* XMLNode, Ogre::Entity *pEntity);
		void processOctree(rapidxml::xml_node<>* XMLNode);
		void processLight(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent = 0);
		void processCamera(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent = 0);

		void processNode(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent = 0);
		void processLookTarget(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent);
		void processTrackTarget(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent);
		void processEntity(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent);
		void processParticleSystem(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent);
		void processBillboardSet(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent);
		void processPlane(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent);

		void processFog(rapidxml::xml_node<>* XMLNode);
		void processSkyBox(rapidxml::xml_node<>* XMLNode);
		void processSkyDome(rapidxml::xml_node<>* XMLNode);
		void processSkyPlane(rapidxml::xml_node<>* XMLNode);
		void processClipping(rapidxml::xml_node<>* XMLNode);

		void processLightRange(rapidxml::xml_node<>* XMLNode, Ogre::Light *pLight);
		void processLightAttenuation(rapidxml::xml_node<>* XMLNode, Ogre::Light *pLight);

		Ogre::String getAttrib(rapidxml::xml_node<>* XMLNode, const Ogre::String &parameter, const Ogre::String &defaultValue = "");
		Ogre::Real getAttribReal(rapidxml::xml_node<>* XMLNode, const Ogre::String &parameter, Ogre::Real defaultValue = 0);
		bool getAttribBool(rapidxml::xml_node<>* XMLNode, const Ogre::String &parameter, bool defaultValue = false);

		Ogre::Vector3 parseVector3(rapidxml::xml_node<>* XMLNode);
		Ogre::Quaternion parseQuaternion(rapidxml::xml_node<>* XMLNode);
		Ogre::ColourValue parseColour(rapidxml::xml_node<>* XMLNode);
		

		Ogre::SceneManager *mSceneMgr;
		Ogre::SceneNode *mAttachNode;
		Ogre::String m_sGroupName;
		Ogre::String m_sPrependNode;
		Ogre::TerrainGroup* mTerrainGroup;
		Ogre::Vector3 mTerrainPosition;
		Ogre::Vector3 mLightDirection;
	};

#endif // DOT_SCENELOADER_H
DotSceneLoader.cpp:

Code: Select all

#include "DotSceneLoader.h"
#include <Ogre.h>
#include <Terrain/OgreTerrain.h>
#include <Terrain/OgreTerrainGroup.h>
#include <Terrain/OgreTerrainMaterialGeneratorA.h>

#pragma warning(disable:4390)
#pragma warning(disable:4305)


DotSceneLoader::DotSceneLoader() : mSceneMgr(0), mTerrainGroup(0) 
{
    mTerrainGlobalOptions = OGRE_NEW Ogre::TerrainGlobalOptions();
}


DotSceneLoader::~DotSceneLoader()
{
    if(mTerrainGroup)
	{
		OGRE_DELETE mTerrainGroup;
	}

    OGRE_DELETE mTerrainGlobalOptions;
}

void DotSceneLoader::parseDotScene(const Ogre::String &SceneName, const Ogre::String &groupName, Ogre::SceneManager *yourSceneMgr, Ogre::SceneNode *pAttachNode, const Ogre::String &sPrependNode)
{
	// set up shared object values
	m_sGroupName = groupName;
	mSceneMgr = yourSceneMgr;
	m_sPrependNode = sPrependNode;
	staticObjects.clear();
	dynamicObjects.clear();

	rapidxml::xml_document<> XMLDoc;    // character type defaults to char

	rapidxml::xml_node<>* XMLRoot;

	Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton().openResource(SceneName, groupName );
	char* scene = strdup(stream->getAsString().c_str());
	XMLDoc.parse<0>(scene);

	// Grab the scene node
	XMLRoot = XMLDoc.first_node("scene");

	// Validate the File
	if( getAttrib(XMLRoot, "formatVersion", "") == "")
	{
		Ogre::LogManager::getSingleton().logMessage( "[DotSceneLoader] Error: Invalid .scene File. Missing <scene>" );
		return;
	}

	// figure out where to attach any nodes we create
	mAttachNode = pAttachNode;
	if(!mAttachNode)
		mAttachNode = mSceneMgr->getRootSceneNode();

	// Process the scene
	processScene(XMLRoot);
}

void DotSceneLoader::processScene(rapidxml::xml_node<>* XMLRoot)
{
	// Process the scene parameters
	Ogre::String version = getAttrib(XMLRoot, "formatVersion", "unknown");

	Ogre::String message = "[DotSceneLoader] Parsing dotScene file with version " + version;
	if(XMLRoot->first_attribute("ID"))
		message += ", id " + Ogre::String(XMLRoot->first_attribute("ID")->value());
	if(XMLRoot->first_attribute("sceneManager"))
		message += ", scene manager " + Ogre::String(XMLRoot->first_attribute("sceneManager")->value());
	if(XMLRoot->first_attribute("minOgreVersion"))
		message += ", min. Ogre version " + Ogre::String(XMLRoot->first_attribute("minOgreVersion")->value());
	if(XMLRoot->first_attribute("author"))
		message += ", author " + Ogre::String(XMLRoot->first_attribute("author")->value());

	Ogre::LogManager::getSingleton().logMessage(message);

	rapidxml::xml_node<>* pElement;

	// Process environment (?)
	pElement = XMLRoot->first_node("environment");
	if(pElement)
		processEnvironment(pElement);

	// Process nodes (?)
	pElement = XMLRoot->first_node("nodes");
	if(pElement)
		processNodes(pElement);

	// Process externals (?)
	pElement = XMLRoot->first_node("externals");
	if(pElement)
		processExternals(pElement);

	// Process userDataReference (?)
	pElement = XMLRoot->first_node("userDataReference");
	if(pElement)
		processUserDataReference(pElement);

	// Process octree (?)
	pElement = XMLRoot->first_node("octree");
	if(pElement)
		processOctree(pElement);

	// Process light (?)
	//pElement = XMLRoot->first_node("light");
	//if(pElement)
	//	processLight(pElement);

	// Process camera (?)
	pElement = XMLRoot->first_node("camera");
	if(pElement)
		processCamera(pElement);

	// Process terrain (?)
	pElement = XMLRoot->first_node("terrain");
	if(pElement)
		processTerrain(pElement);
}

void DotSceneLoader::processNodes(rapidxml::xml_node<>* XMLNode)
{
	rapidxml::xml_node<>* pElement;

	// Process node (*)
	pElement = XMLNode->first_node("node");
	while(pElement)
	{
		processNode(pElement);
		pElement = pElement->next_sibling("node");
	}

	// Process position (?)
	pElement = XMLNode->first_node("position");
	if(pElement)
	{
		mAttachNode->setPosition(parseVector3(pElement));
		mAttachNode->setInitialState();
	}

	// Process rotation (?)
	pElement = XMLNode->first_node("rotation");
	if(pElement)
	{
		mAttachNode->setOrientation(parseQuaternion(pElement));
		mAttachNode->setInitialState();
	}

	// Process scale (?)
	pElement = XMLNode->first_node("scale");
	if(pElement)
	{
		mAttachNode->setScale(parseVector3(pElement));
		mAttachNode->setInitialState();
	}
}

void DotSceneLoader::processExternals(rapidxml::xml_node<>* XMLNode)
{
	//! @todo Implement this
}

void DotSceneLoader::processEnvironment(rapidxml::xml_node<>* XMLNode)
{
	rapidxml::xml_node<>* pElement;

	// Process camera (?)
	pElement = XMLNode->first_node("camera");
	if(pElement)
		processCamera(pElement);

	// Process fog (?)
	pElement = XMLNode->first_node("fog");
	if(pElement)
		processFog(pElement);

	// Process skyBox (?)
	pElement = XMLNode->first_node("skyBox");
	if(pElement)
		processSkyBox(pElement);

	// Process skyDome (?)
	pElement = XMLNode->first_node("skyDome");
	if(pElement)
		processSkyDome(pElement);

	// Process skyPlane (?)
	pElement = XMLNode->first_node("skyPlane");
	if(pElement)
		processSkyPlane(pElement);

	// Process clipping (?)
	pElement = XMLNode->first_node("clipping");
	if(pElement)
		processClipping(pElement);

	// Process colourAmbient (?)
	pElement = XMLNode->first_node("colourAmbient");
	if(pElement)
		mSceneMgr->setAmbientLight(parseColour(pElement));

	// Process colourBackground (?)
	//! @todo Set the background colour of all viewports (RenderWindow has to be provided then)
	pElement = XMLNode->first_node("colourBackground");
	if(pElement)
		;//mSceneMgr->set(parseColour(pElement));

	// Process userDataReference (?)
	pElement = XMLNode->first_node("userDataReference");
	if(pElement)
		processUserDataReference(pElement);
}

void DotSceneLoader::processTerrain(rapidxml::xml_node<>* XMLNode)
{
	Ogre::Real worldSize = getAttribReal(XMLNode, "worldSize");
	int mapSize = Ogre::StringConverter::parseInt(XMLNode->first_attribute("mapSize")->value());
	int rows = Ogre::StringConverter::parseInt(XMLNode->first_attribute("rows")->value());
	int columns = Ogre::StringConverter::parseInt(XMLNode->first_attribute("columns")->value());
	bool colourmapEnabled = getAttribBool(XMLNode, "colourmapEnabled");
	int colourMapTextureSize = Ogre::StringConverter::parseInt(XMLNode->first_attribute("colourMapTextureSize")->value());

	Ogre::Vector3 lightdir(0, -0.3, 0.75);
	lightdir.normalise();
	Ogre::Light* l = mSceneMgr->createLight("tstLight");
	l->setType(Ogre::Light::LT_DIRECTIONAL);
	l->setDirection(lightdir);
	l->setDiffuseColour(Ogre::ColourValue(1.0, 1.0, 1.0));
	l->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4));
	mSceneMgr->setAmbientLight(Ogre::ColourValue(0.6, 0.6, 0.6));

	mTerrainGlobalOptions->setMaxPixelError(1);
	mTerrainGlobalOptions->setCompositeMapDistance(2000);
	mTerrainGlobalOptions->setLightMapDirection(lightdir);
	mTerrainGlobalOptions->setCompositeMapAmbient(mSceneMgr->getAmbientLight());
	mTerrainGlobalOptions->setCompositeMapDiffuse(l->getDiffuseColour());

	mTerrainGroup = OGRE_NEW Ogre::TerrainGroup(mSceneMgr, Ogre::Terrain::ALIGN_X_Z, mapSize, worldSize);
	mTerrainGroup->setOrigin(Ogre::Vector3::ZERO);

	rapidxml::xml_node<>* pElement;
	rapidxml::xml_node<>* pPageElement;

	// Process terrain pages (*)
	pElement = XMLNode->first_node("terrainPages");
	while(pElement)
	{
		pPageElement = pElement->first_node("terrainPage");
		while(pPageElement)
		{
			processTerrainPage(pPageElement);
			pPageElement = pPageElement->next_sibling("terrainPage");
		}
		pElement = pElement->next_sibling("terrainPages");
	}
	mTerrainGroup->loadAllTerrains(true);

	// process blendmaps
	pElement = XMLNode->first_node("terrainPages");
	while(pElement)
	{
		pPageElement = pElement->first_node("terrainPage");
		while(pPageElement)
		{
			processBlendmaps(pPageElement);
			pPageElement = pPageElement->next_sibling("terrainPage");
		}
		pElement = pElement->next_sibling("terrainPages");
	}
	mTerrainGroup->freeTemporaryResources();
	//mTerrain->setPosition(mTerrainPosition);
}

void DotSceneLoader::processTerrainPage(rapidxml::xml_node<>* XMLNode)
{
	Ogre::String name = getAttrib(XMLNode, "name");
	int pageX = Ogre::StringConverter::parseInt(XMLNode->first_attribute("pageX")->value());
	int pageY = Ogre::StringConverter::parseInt(XMLNode->first_attribute("pageY")->value());
	Ogre::Real worldSize = getAttribReal(XMLNode, "worldSize");
	int mapSize = Ogre::StringConverter::parseInt(XMLNode->first_attribute("mapSize")->value());
	bool colourmapEnabled = getAttribBool(XMLNode, "colourmapEnabled");
	int colourmapTexturesize = Ogre::StringConverter::parseInt(XMLNode->first_attribute("colourmapTexturesize")->value());
	int layerCount = Ogre::StringConverter::parseInt(XMLNode->first_attribute("layerCount")->value());

	Ogre::String filename = mTerrainGroup->generateFilename(pageX, pageY);
	if (Ogre::ResourceGroupManager::getSingleton().resourceExists(mTerrainGroup->getResourceGroup(), filename))
	{
		mTerrainGroup->defineTerrain(pageX, pageY);
	}
	else
	{
		rapidxml::xml_node<>* pElement;

		pElement = XMLNode->first_node("position");
		if(pElement)
			mTerrainPosition = parseVector3(pElement);

		Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton().openResource(name + Ogre::String(".ohm"), "General" );
		size_t size = stream.get()->size();
		if(size != mapSize * mapSize * 4)
		{
			OGRE_EXCEPT( Ogre::Exception::ERR_INTERNAL_ERROR, "Size of stream does not match terrainsize!", "TerrainPage" );
		}
		float* buffer = OGRE_ALLOC_T(float, size, Ogre::MEMCATEGORY_GEOMETRY);
		stream->read(buffer, size);

		Ogre::Terrain::ImportData& imp = mTerrainGroup->getDefaultImportSettings();
		imp.terrainSize = mapSize;
		imp.worldSize = worldSize;
		imp.inputFloat = buffer;
		imp.inputImage = 0;
		imp.deleteInputData = true;
		imp.minBatchSize = 33;
		imp.maxBatchSize = 65;

		imp.layerList.resize(layerCount);

		int count = 0;

		// Process layers (*)
		rapidxml::xml_node<>* pTerrainLayer;
		rapidxml::xml_node<>* pTerrainTextures;
		rapidxml::xml_node<>* pTerrainTexture;
		pElement = XMLNode->first_node("layers");
		while(pElement)
		{
			pTerrainLayer = pElement->first_node("layer");
			while(pTerrainLayer)
			{
				int worldSize = Ogre::StringConverter::parseInt(pTerrainLayer->first_attribute("worldSize")->value());
				pTerrainTextures = pTerrainLayer->first_node("textures");
				pTerrainTexture = pTerrainTextures->first_node("texture");
				while(pTerrainTexture)
				{
					imp.layerList[count].textureNames.push_back(getAttrib(pTerrainTexture,"name",""));
                    imp.layerList[count].worldSize = (Ogre::Real)worldSize;
					pTerrainTexture = pTerrainTexture->next_sibling("texture");
				}
				count++;
				// do stuff
				pTerrainLayer = pTerrainLayer->next_sibling("layer");
			}
			pElement = pElement->next_sibling("layers");
		}
		
		mTerrainGroup->defineTerrain(pageX, pageY, &imp);
	}
}

void DotSceneLoader::processBlendmaps(rapidxml::xml_node<>* XMLNode)
{
	int pageX = Ogre::StringConverter::parseInt(XMLNode->first_attribute("pageX")->value());
	int pageY = Ogre::StringConverter::parseInt(XMLNode->first_attribute("pageY")->value());

	Ogre::String filename = mTerrainGroup->generateFilename(pageX, pageY);
	// skip this is terrain page has been saved already
	if (!Ogre::ResourceGroupManager::getSingleton().resourceExists(mTerrainGroup->getResourceGroup(), filename))
	{
		rapidxml::xml_node<>* pElement;

		// Process blendmaps (*)
		std::vector<Ogre::String> blendMaps;
		rapidxml::xml_node<>* pBlendmap;
		pElement = XMLNode->first_node("blendMaps");
		pBlendmap = pElement->first_node("blendMap");
		while(pBlendmap)
		{
			blendMaps.push_back(getAttrib(pBlendmap, "texture",""));
			pBlendmap = pBlendmap->next_sibling("blendMap");
		}

		for(int j = 1;j < mTerrainGroup->getTerrain(pageX, pageY)->getLayerCount();j++)
		{
			Ogre::TerrainLayerBlendMap *blendmap = mTerrainGroup->getTerrain(pageX, pageY)->getLayerBlendMap(j);
			Ogre::Image img;
			img.load(blendMaps[j-1],"General");
			int blendmapsize = mTerrainGroup->getTerrain(pageX, pageY)->getLayerBlendMapSize();
			if(img.getWidth() != blendmapsize)
				img.resize(blendmapsize, blendmapsize);

			float *ptr = blendmap->getBlendPointer();
			Ogre::uint8 *data = static_cast<Ogre::uint8*>(img.getPixelBox().data);

			for(int bp = 0;bp < blendmapsize * blendmapsize;bp++)
				ptr[bp] = static_cast<float>(data[bp]) / 255.0f;

			blendmap->dirty();
			blendmap->update();
		}
	}
}

void DotSceneLoader::processUserDataReference(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent)
{
	//! @todo Implement this
}

void DotSceneLoader::processOctree(rapidxml::xml_node<>* XMLNode)
{
	//! @todo Implement this
}

void DotSceneLoader::processLight(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent)
{
	// Process attributes
	Ogre::String name = getAttrib(XMLNode, "name");
	Ogre::String id = getAttrib(XMLNode, "id");

	// Create the light
	Ogre::Light *pLight = mSceneMgr->createLight(name);
	if(pParent)
		pParent->attachObject(pLight);

	Ogre::String sValue = getAttrib(XMLNode, "type");
	if(sValue == "point")
		pLight->setType(Ogre::Light::LT_POINT);
	else if(sValue == "directional")
		pLight->setType(Ogre::Light::LT_DIRECTIONAL);
	else if(sValue == "spot")
		pLight->setType(Ogre::Light::LT_SPOTLIGHT);
	else if(sValue == "radPoint")
		pLight->setType(Ogre::Light::LT_POINT);

	pLight->setVisible(getAttribBool(XMLNode, "visible", true));
	pLight->setCastShadows(getAttribBool(XMLNode, "castShadows", true));

	rapidxml::xml_node<>* pElement;

	// Process position (?)
	pElement = XMLNode->first_node("position");
	if(pElement)
		pLight->setPosition(parseVector3(pElement));

	// Process normal (?)
	pElement = XMLNode->first_node("normal");
	if(pElement)
		pLight->setDirection(parseVector3(pElement));

	pElement = XMLNode->first_node("directionVector");
	if(pElement)
	{
		pLight->setDirection(parseVector3(pElement));
		mLightDirection = parseVector3(pElement);
	}

	// Process colourDiffuse (?)
	pElement = XMLNode->first_node("colourDiffuse");
	if(pElement)
		pLight->setDiffuseColour(parseColour(pElement));

	// Process colourSpecular (?)
	pElement = XMLNode->first_node("colourSpecular");
	if(pElement)
		pLight->setSpecularColour(parseColour(pElement));

	if(sValue != "directional")
	{
		// Process lightRange (?)
		pElement = XMLNode->first_node("lightRange");
		if(pElement)
			processLightRange(pElement, pLight);

		// Process lightAttenuation (?)
		pElement = XMLNode->first_node("lightAttenuation");
		if(pElement)
			processLightAttenuation(pElement, pLight);
	}
	// Process userDataReference (?)
	pElement = XMLNode->first_node("userDataReference");
	if(pElement)
		;//processUserDataReference(pElement, pLight);
}

void DotSceneLoader::processCamera(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent)
{
	// Process attributes
	Ogre::String name = getAttrib(XMLNode, "name");
	Ogre::String id = getAttrib(XMLNode, "id");
	Ogre::Real fov = getAttribReal(XMLNode, "fov", 45);
	Ogre::Real aspectRatio = getAttribReal(XMLNode, "aspectRatio", 1.3333);
	Ogre::String projectionType = getAttrib(XMLNode, "projectionType", "perspective");

	// Create the camera
	Ogre::Camera *pCamera = mSceneMgr->createCamera(name);
	
	//TODO: make a flag or attribute indicating whether or not the camera should be attached to any parent node.
	//if(pParent)
	//	pParent->attachObject(pCamera);

	// Set the field-of-view
	//! @todo Is this always in degrees?
	//pCamera->setFOVy(Ogre::Degree(fov));

	// Set the aspect ratio
	//pCamera->setAspectRatio(aspectRatio);
	
	// Set the projection type
	if(projectionType == "perspective")
		pCamera->setProjectionType(Ogre::PT_PERSPECTIVE);
	else if(projectionType == "orthographic")
		pCamera->setProjectionType(Ogre::PT_ORTHOGRAPHIC);

	rapidxml::xml_node<>* pElement;

	// Process clipping (?)
	pElement = XMLNode->first_node("clipping");
	if(pElement)
	{
		Ogre::Real nearDist = getAttribReal(pElement, "near");
		pCamera->setNearClipDistance(nearDist);

		Ogre::Real farDist =  getAttribReal(pElement, "far");
		pCamera->setFarClipDistance(farDist);
	}

	// Process position (?)
	pElement = XMLNode->first_node("position");
	if(pElement)
		pCamera->setPosition(parseVector3(pElement));

	// Process rotation (?)
	pElement = XMLNode->first_node("rotation");
	if(pElement)
		pCamera->setOrientation(parseQuaternion(pElement));

	// Process normal (?)
	pElement = XMLNode->first_node("normal");
	if(pElement)
		;//!< @todo What to do with this element?

	// Process lookTarget (?)
	pElement = XMLNode->first_node("lookTarget");
	if(pElement)
		;//!< @todo Implement the camera look target

	// Process trackTarget (?)
	pElement = XMLNode->first_node("trackTarget");
	if(pElement)
		;//!< @todo Implement the camera track target

	// Process userDataReference (?)
	pElement = XMLNode->first_node("userDataReference");
	if(pElement)
		;//!< @todo Implement the camera user data reference

	// construct a scenenode is no parent
	if(!pParent)
	{
		Ogre::SceneNode* pNode = mAttachNode->createChildSceneNode(name);
		pNode->setPosition(pCamera->getPosition());
		pNode->setOrientation(pCamera->getOrientation());
		pNode->scale(1,1,1);
	}
}

void DotSceneLoader::processNode(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent)
{
	// Construct the node's name
	Ogre::String name = m_sPrependNode + getAttrib(XMLNode, "name");

	// Create the scene node
	Ogre::SceneNode *pNode;
	if(name.empty())
	{
		// Let Ogre choose the name
		if(pParent)
			pNode = pParent->createChildSceneNode();
		else
			pNode = mAttachNode->createChildSceneNode();
	}
	else
	{
		// Provide the name
		if(pParent)
			pNode = pParent->createChildSceneNode(name);
		else
			pNode = mAttachNode->createChildSceneNode(name);
	}

	// Process other attributes
	Ogre::String id = getAttrib(XMLNode, "id");
	bool isTarget = getAttribBool(XMLNode, "isTarget");

	rapidxml::xml_node<>* pElement;

	// Process position (?)
	pElement = XMLNode->first_node("position");
	if(pElement)
	{
		pNode->setPosition(parseVector3(pElement));
		pNode->setInitialState();
	}

	// Process rotation (?)
	pElement = XMLNode->first_node("rotation");
	if(pElement)
	{
		pNode->setOrientation(parseQuaternion(pElement));
		pNode->setInitialState();
	}

	// Process scale (?)
	pElement = XMLNode->first_node("scale");
	if(pElement)
	{
		pNode->setScale(parseVector3(pElement));
		pNode->setInitialState();
	}

	// Process lookTarget (?)
	pElement = XMLNode->first_node("lookTarget");
	if(pElement)
		processLookTarget(pElement, pNode);

	// Process trackTarget (?)
	pElement = XMLNode->first_node("trackTarget");
	if(pElement)
		processTrackTarget(pElement, pNode);

	// Process node (*)
	pElement = XMLNode->first_node("node");
	while(pElement)
	{
		processNode(pElement, pNode);
		pElement = pElement->next_sibling("node");
	}

	// Process entity (*)
	pElement = XMLNode->first_node("entity");
	while(pElement)
	{
		processEntity(pElement, pNode);
		pElement = pElement->next_sibling("entity");
	}

	// Process light (*)
	//pElement = XMLNode->first_node("light");
	//while(pElement)
	//{
	//	processLight(pElement, pNode);
	//	pElement = pElement->next_sibling("light");
	//}

	// Process camera (*)
	pElement = XMLNode->first_node("camera");
	while(pElement)
	{
		processCamera(pElement, pNode);
		pElement = pElement->next_sibling("camera");
	}

	// Process particleSystem (*)
	pElement = XMLNode->first_node("particleSystem");
	while(pElement)
	{
		processParticleSystem(pElement, pNode);
		pElement = pElement->next_sibling("particleSystem");
	}

	// Process billboardSet (*)
	pElement = XMLNode->first_node("billboardSet");
	while(pElement)
	{
		processBillboardSet(pElement, pNode);
		pElement = pElement->next_sibling("billboardSet");
	}

	// Process plane (*)
	pElement = XMLNode->first_node("plane");
	while(pElement)
	{
		processPlane(pElement, pNode);
		pElement = pElement->next_sibling("plane");
	}

	// Process userDataReference (?)
	pElement = XMLNode->first_node("userDataReference");
	if(pElement)
		processUserDataReference(pElement, pNode);
}

void DotSceneLoader::processLookTarget(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent)
{
	//! @todo Is this correct? Cause I don't have a clue actually

	// Process attributes
	Ogre::String nodeName = getAttrib(XMLNode, "nodeName");

	Ogre::Node::TransformSpace relativeTo = Ogre::Node::TS_PARENT;
	Ogre::String sValue = getAttrib(XMLNode, "relativeTo");
	if(sValue == "local")
		relativeTo = Ogre::Node::TS_LOCAL;
	else if(sValue == "parent")
		relativeTo = Ogre::Node::TS_PARENT;
	else if(sValue == "world")
		relativeTo = Ogre::Node::TS_WORLD;

	rapidxml::xml_node<>* pElement;

	// Process position (?)
	Ogre::Vector3 position;
	pElement = XMLNode->first_node("position");
	if(pElement)
		position = parseVector3(pElement);

	// Process localDirection (?)
	Ogre::Vector3 localDirection = Ogre::Vector3::NEGATIVE_UNIT_Z;
	pElement = XMLNode->first_node("localDirection");
	if(pElement)
		localDirection = parseVector3(pElement);

	// Setup the look target
	try
	{
		if(!nodeName.empty())
		{
			Ogre::SceneNode *pLookNode = mSceneMgr->getSceneNode(nodeName);
			position = pLookNode->_getDerivedPosition();
		}

		pParent->lookAt(position, relativeTo, localDirection);
	}
	catch(Ogre::Exception &/*e*/)
	{
		Ogre::LogManager::getSingleton().logMessage("[DotSceneLoader] Error processing a look target!");
	}
}

void DotSceneLoader::processTrackTarget(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent)
{
	// Process attributes
	Ogre::String nodeName = getAttrib(XMLNode, "nodeName");

	rapidxml::xml_node<>* pElement;

	// Process localDirection (?)
	Ogre::Vector3 localDirection = Ogre::Vector3::NEGATIVE_UNIT_Z;
	pElement = XMLNode->first_node("localDirection");
	if(pElement)
		localDirection = parseVector3(pElement);

	// Process offset (?)
	Ogre::Vector3 offset = Ogre::Vector3::ZERO;
	pElement = XMLNode->first_node("offset");
	if(pElement)
		offset = parseVector3(pElement);

	// Setup the track target
	try
	{
		Ogre::SceneNode *pTrackNode = mSceneMgr->getSceneNode(nodeName);
		pParent->setAutoTracking(true, pTrackNode, localDirection, offset);
	}
	catch(Ogre::Exception &/*e*/)
	{
		Ogre::LogManager::getSingleton().logMessage("[DotSceneLoader] Error processing a track target!");
	}
}

void DotSceneLoader::processEntity(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent)
{
	// Process attributes
	Ogre::String name = getAttrib(XMLNode, "name");
	Ogre::String id = getAttrib(XMLNode, "id");
	Ogre::String meshFile = getAttrib(XMLNode, "meshFile");
	Ogre::String materialFile = getAttrib(XMLNode, "materialFile");
	bool isStatic = getAttribBool(XMLNode, "static", false);;
	bool castShadows = getAttribBool(XMLNode, "castShadows", true);

	// TEMP: Maintain a list of static and dynamic objects
	if(isStatic)
		staticObjects.push_back(name);
	else
		dynamicObjects.push_back(name);

	rapidxml::xml_node<>* pElement;

	// Process vertexBuffer (?)
	pElement = XMLNode->first_node("vertexBuffer");
	if(pElement)
		;//processVertexBuffer(pElement);

	// Process indexBuffer (?)
	pElement = XMLNode->first_node("indexBuffer");
	if(pElement)
		;//processIndexBuffer(pElement);

	// Create the entity
	Ogre::Entity *pEntity = 0;
	try
	{
		Ogre::MeshManager::getSingleton().load(meshFile, m_sGroupName);
		pEntity = mSceneMgr->createEntity(name, meshFile);
		pEntity->setCastShadows(castShadows);
		pParent->attachObject(pEntity);
		
		if(!materialFile.empty())
			pEntity->setMaterialName(materialFile);
	}
	catch(Ogre::Exception &/*e*/)
	{
		Ogre::LogManager::getSingleton().logMessage("[DotSceneLoader] Error loading an entity!");
	}

	// Process userDataReference (?)
	pElement = XMLNode->first_node("userDataReference");
	if(pElement)
		processUserDataReference(pElement, pEntity);

	
}

void DotSceneLoader::processParticleSystem(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent)
{
	// Process attributes
	Ogre::String name = getAttrib(XMLNode, "name");
	Ogre::String id = getAttrib(XMLNode, "id");
	Ogre::String file = getAttrib(XMLNode, "file");

	// Create the particle system
	try
	{
		Ogre::ParticleSystem *pParticles = mSceneMgr->createParticleSystem(name, file);
		pParent->attachObject(pParticles);
	}
	catch(Ogre::Exception &/*e*/)
	{
		Ogre::LogManager::getSingleton().logMessage("[DotSceneLoader] Error creating a particle system!");
	}
}

void DotSceneLoader::processBillboardSet(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent)
{
	//! @todo Implement this
}

void DotSceneLoader::processPlane(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent)
{
	//! @todo Implement this
}

void DotSceneLoader::processFog(rapidxml::xml_node<>* XMLNode)
{
	// Process attributes
	Ogre::Real expDensity = getAttribReal(XMLNode, "density", 0.001);
	Ogre::Real linearStart = getAttribReal(XMLNode, "start", 0.0);
	Ogre::Real linearEnd = getAttribReal(XMLNode, "end", 1.0);

	Ogre::FogMode mode = Ogre::FOG_NONE;
	Ogre::String sMode = getAttrib(XMLNode, "mode");
	if(sMode == "none")
		mode = Ogre::FOG_NONE;
	else if(sMode == "exp")
		mode = Ogre::FOG_EXP;
	else if(sMode == "exp2")
		mode = Ogre::FOG_EXP2;
	else if(sMode == "linear")
		mode = Ogre::FOG_LINEAR;

	rapidxml::xml_node<>* pElement;

	// Process colourDiffuse (?)
	Ogre::ColourValue colourDiffuse = Ogre::ColourValue::White;
	pElement = XMLNode->first_node("colour");
	if(pElement)
		colourDiffuse = parseColour(pElement);

	// Setup the fog
	mSceneMgr->setFog(mode, colourDiffuse, expDensity, linearStart, linearEnd);
}

void DotSceneLoader::processSkyBox(rapidxml::xml_node<>* XMLNode)
{
	// Process attributes
	Ogre::String material = getAttrib(XMLNode, "material", "BaseWhite");
	Ogre::Real distance = getAttribReal(XMLNode, "distance", 5000);
	bool drawFirst = getAttribBool(XMLNode, "drawFirst", true);
	bool active = getAttribBool(XMLNode, "active", false);
	if(!active)
		return;

	rapidxml::xml_node<>* pElement;

	// Process rotation (?)
	Ogre::Quaternion rotation = Ogre::Quaternion::IDENTITY;
	pElement = XMLNode->first_node("rotation");
	if(pElement)
		rotation = parseQuaternion(pElement);

	// Setup the sky box
	mSceneMgr->setSkyBox(true, material, distance, drawFirst, rotation, m_sGroupName);
}

void DotSceneLoader::processSkyDome(rapidxml::xml_node<>* XMLNode)
{
	// Process attributes
	Ogre::String material = XMLNode->first_attribute("material")->value();
	Ogre::Real curvature = getAttribReal(XMLNode, "curvature", 10);
	Ogre::Real tiling = getAttribReal(XMLNode, "tiling", 8);
	Ogre::Real distance = getAttribReal(XMLNode, "distance", 4000);
	bool drawFirst = getAttribBool(XMLNode, "drawFirst", true);

	rapidxml::xml_node<>* pElement;

	// Process rotation (?)
	Ogre::Quaternion rotation = Ogre::Quaternion::IDENTITY;
	pElement = XMLNode->first_node("rotation");
	if(pElement)
		rotation = parseQuaternion(pElement);

	// Setup the sky dome
	mSceneMgr->setSkyDome(true, material, curvature, tiling, distance, drawFirst, rotation, 16, 16, -1, m_sGroupName);
}

void DotSceneLoader::processSkyPlane(rapidxml::xml_node<>* XMLNode)
{
	// Process attributes
	Ogre::String material = getAttrib(XMLNode, "material");
	Ogre::Real planeX = getAttribReal(XMLNode, "planeX", 0);
	Ogre::Real planeY = getAttribReal(XMLNode, "planeY", -1);
	Ogre::Real planeZ = getAttribReal(XMLNode, "planeX", 0);
	Ogre::Real planeD = getAttribReal(XMLNode, "planeD", 5000);
	Ogre::Real scale = getAttribReal(XMLNode, "scale", 1000);
	Ogre::Real bow = getAttribReal(XMLNode, "bow", 0);
	Ogre::Real tiling = getAttribReal(XMLNode, "tiling", 10);
	bool drawFirst = getAttribBool(XMLNode, "drawFirst", true);

	// Setup the sky plane
	Ogre::Plane plane;
	plane.normal = Ogre::Vector3(planeX, planeY, planeZ);
	plane.d = planeD;
	mSceneMgr->setSkyPlane(true, plane, material, scale, tiling, drawFirst, bow, 1, 1, m_sGroupName);
}

void DotSceneLoader::processClipping(rapidxml::xml_node<>* XMLNode)
{
	//! @todo Implement this

	// Process attributes
	Ogre::Real fNear = getAttribReal(XMLNode, "near", 0);
	Ogre::Real fFar = getAttribReal(XMLNode, "far", 1);
}

void DotSceneLoader::processLightRange(rapidxml::xml_node<>* XMLNode, Ogre::Light *pLight)
{
	// Process attributes
	Ogre::Real inner = getAttribReal(XMLNode, "inner");
	Ogre::Real outer = getAttribReal(XMLNode, "outer");
	Ogre::Real falloff = getAttribReal(XMLNode, "falloff", 1.0);

	// Setup the light range
	pLight->setSpotlightRange(Ogre::Angle(inner), Ogre::Angle(outer), falloff);
}

void DotSceneLoader::processLightAttenuation(rapidxml::xml_node<>* XMLNode, Ogre::Light *pLight)
{
	// Process attributes
	Ogre::Real range = getAttribReal(XMLNode, "range");
	Ogre::Real constant = getAttribReal(XMLNode, "constant");
	Ogre::Real linear = getAttribReal(XMLNode, "linear");
	Ogre::Real quadratic = getAttribReal(XMLNode, "quadratic");

	// Setup the light attenuation
	pLight->setAttenuation(range, constant, linear, quadratic);
}


Ogre::String DotSceneLoader::getAttrib(rapidxml::xml_node<>* XMLNode, const Ogre::String &attrib, const Ogre::String &defaultValue)
{
	if(XMLNode->first_attribute(attrib.c_str()))
		return XMLNode->first_attribute(attrib.c_str())->value();
	else
		return defaultValue;
}

Ogre::Real DotSceneLoader::getAttribReal(rapidxml::xml_node<>* XMLNode, const Ogre::String &attrib, Ogre::Real defaultValue)
{
	if(XMLNode->first_attribute(attrib.c_str()))
		return Ogre::StringConverter::parseReal(XMLNode->first_attribute(attrib.c_str())->value());
	else
		return defaultValue;
}

bool DotSceneLoader::getAttribBool(rapidxml::xml_node<>* XMLNode, const Ogre::String &attrib, bool defaultValue)
{
	if(!XMLNode->first_attribute(attrib.c_str()))
		return defaultValue;

	if(Ogre::String(XMLNode->first_attribute(attrib.c_str())->value()) == "true")
		return true;

	return false;
}

Ogre::Vector3 DotSceneLoader::parseVector3(rapidxml::xml_node<>* XMLNode)
{
	return Ogre::Vector3(
		Ogre::StringConverter::parseReal(XMLNode->first_attribute("x")->value()),
		Ogre::StringConverter::parseReal(XMLNode->first_attribute("y")->value()),
		Ogre::StringConverter::parseReal(XMLNode->first_attribute("z")->value())
	);
}

Ogre::Quaternion DotSceneLoader::parseQuaternion(rapidxml::xml_node<>* XMLNode)
{
	//! @todo Fix this crap!

	Ogre::Quaternion orientation;

	if(XMLNode->first_attribute("qx"))
	{
		orientation.x = Ogre::StringConverter::parseReal(XMLNode->first_attribute("qx")->value());
		orientation.y = Ogre::StringConverter::parseReal(XMLNode->first_attribute("qy")->value());
		orientation.z = Ogre::StringConverter::parseReal(XMLNode->first_attribute("qz")->value());
		orientation.w = Ogre::StringConverter::parseReal(XMLNode->first_attribute("qw")->value());
	}
	if(XMLNode->first_attribute("qw"))
	{
		orientation.w = Ogre::StringConverter::parseReal(XMLNode->first_attribute("qw")->value());
		orientation.x = Ogre::StringConverter::parseReal(XMLNode->first_attribute("qx")->value());
		orientation.y = Ogre::StringConverter::parseReal(XMLNode->first_attribute("qy")->value());
		orientation.z = Ogre::StringConverter::parseReal(XMLNode->first_attribute("qz")->value());
	}
	else if(XMLNode->first_attribute("axisX"))
	{
		Ogre::Vector3 axis;
		axis.x = Ogre::StringConverter::parseReal(XMLNode->first_attribute("axisX")->value());
		axis.y = Ogre::StringConverter::parseReal(XMLNode->first_attribute("axisY")->value());
		axis.z = Ogre::StringConverter::parseReal(XMLNode->first_attribute("axisZ")->value());
		Ogre::Real angle = Ogre::StringConverter::parseReal(XMLNode->first_attribute("angle")->value());;
		orientation.FromAngleAxis(Ogre::Angle(angle), axis);
	}
	else if(XMLNode->first_attribute("angleX"))
	{
		Ogre::Vector3 axis;
		axis.x = Ogre::StringConverter::parseReal(XMLNode->first_attribute("angleX")->value());
		axis.y = Ogre::StringConverter::parseReal(XMLNode->first_attribute("angleY")->value());
		axis.z = Ogre::StringConverter::parseReal(XMLNode->first_attribute("angleZ")->value());
		//orientation.FromAxes(&axis);
		//orientation.F
	}
	else if(XMLNode->first_attribute("x"))
	{
		orientation.x = Ogre::StringConverter::parseReal(XMLNode->first_attribute("x")->value());
		orientation.y = Ogre::StringConverter::parseReal(XMLNode->first_attribute("y")->value());
		orientation.z = Ogre::StringConverter::parseReal(XMLNode->first_attribute("z")->value());
		orientation.w = Ogre::StringConverter::parseReal(XMLNode->first_attribute("w")->value());
	}
	else if(XMLNode->first_attribute("w"))
	{
		orientation.w = Ogre::StringConverter::parseReal(XMLNode->first_attribute("w")->value());
		orientation.x = Ogre::StringConverter::parseReal(XMLNode->first_attribute("x")->value());
		orientation.y = Ogre::StringConverter::parseReal(XMLNode->first_attribute("y")->value());
		orientation.z = Ogre::StringConverter::parseReal(XMLNode->first_attribute("z")->value());
	}

	return orientation;
}

Ogre::ColourValue DotSceneLoader::parseColour(rapidxml::xml_node<>* XMLNode)
{
	return Ogre::ColourValue(
		Ogre::StringConverter::parseReal(XMLNode->first_attribute("r")->value()),
		Ogre::StringConverter::parseReal(XMLNode->first_attribute("g")->value()),
		Ogre::StringConverter::parseReal(XMLNode->first_attribute("b")->value()),
		XMLNode->first_attribute("a") != NULL ? Ogre::StringConverter::parseReal(XMLNode->first_attribute("a")->value()) : 1
	);
}

Ogre::String DotSceneLoader::getProperty(const Ogre::String &ndNm, const Ogre::String &prop)
{
	for ( unsigned int i = 0 ; i < nodeProperties.size(); i++ )
	{
		if ( nodeProperties[i].nodeName == ndNm && nodeProperties[i].propertyNm == prop )
		{
			return nodeProperties[i].valueName;
		}
	}

	return "";
}

void DotSceneLoader::processUserDataReference(rapidxml::xml_node<>* XMLNode, Ogre::Entity *pEntity)
{
	Ogre::String str = XMLNode->first_attribute("id")->value();
	pEntity->setUserAny(Ogre::Any(str));
}
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
N0vember
Gremlin
Posts: 196
Joined: Tue Jan 27, 2009 12:27 am
x 24

Re: new DotScene loader

Post by N0vember »

Reporting a bug here :
In the processSkyDome function, you aren't checking for the active flag, which can lead to a crash/exception (attempting to set a skydome without material) if skydome is set as inactive.
I must admit it's a bit strange to write a SkyDome node if set to inactive, but Ogitor exported my file like this so...
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179

Re: new DotScene loader

Post by jacmoe »

Thanks for reporting - I must have missed that. :)
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
modred11
Gnoblar
Posts: 4
Joined: Fri Feb 12, 2010 5:55 am

Re: new DotScene loader

Post by modred11 »

Do these loaders support declaring stuff as Static Geometry?

I've been trying to use this/these dotscene loader(s) for an entirely indoor scene without any terrain in it, and performance-wise this isn't working.

I think declaring it as one big Static Geometry might help, and I saw " static='false' " on the Dotscene wikipage, but that didn't help. Would it be possible to extend the loaders to allow for marking stuff as static geometry?
AwAk3e
Gnoblar
Posts: 17
Joined: Sat May 01, 2010 9:23 pm

Re: new DotScene loader

Post by AwAk3e »

I have added the, 'DotSceneLoader.h' and 'DotSceneLoader.cpp' too my project along with the required TinyXML files.
In doing so I can cleanly compile the code.

However when I try to initialise it with this code:

Code: Select all

Ogre::DotSceneLoader* dotLoader = new Ogre::DotSceneLoader();
I just get these errors:

Code: Select all

error C2039: 'DotSceneLoader' : is not a member of 'Ogre'
error C2065: 'DotSceneLoader' : undeclared identifier
error C2065: 'dotLoader' : undeclared identifier
error C2039: 'DotSceneLoader' : is not a member of 'Ogre'
error C2061: syntax error : identifier 'DotSceneLoader'
Is that the correct way of initializing the DotSceneLoader?

Thanks in advance AwAk3e.

Edit: Sigh I'm an idiot, I didn't realise that I didn't include the header file. :roll: Sorry ;)