Просмотр исходного кода

Merge 8/13 mcclure screeninfo branch with Ivan Polycode branch

mcc 13 лет назад
Родитель
Сommit
2a02fa1e42

+ 14 - 0
Core/Contents/Include/PolyCore.h

@@ -60,6 +60,20 @@ namespace Polycode {
 		virtual ~PolycodeViewBase(){}
 		void *windowData;
 	};
+	
+	class _PolyExport TimeInfo {
+		public:
+			TimeInfo();
+			
+			int seconds;
+			int minutes;
+			int hours;
+			int month;
+			int monthDay;
+			int weekDay;
+			int year;
+			int yearDay;
+	};	
 
 	/**
 	* The main core of the framework. The core deals with system-level functions, such as window initialization and OS interaction. Each platform has its own implementation of this base class. NOTE: SOME OF THE FUNCTIONALITY IN THE CORE IS NOT FULLY IMPLEMENTED!!

+ 1 - 0
Core/Contents/Include/PolyCoreInput.h

@@ -36,6 +36,7 @@ namespace Polycode {
 			float joystickAxisState[32];
 			bool joystickButtonState[64];
 			unsigned int deviceID;		
+			unsigned int deviceIndex;
 	};
 	
 	class InputEvent;

+ 2 - 5
Core/Contents/Include/PolyEntity.h

@@ -426,11 +426,8 @@ namespace Polycode {
 			void setColorInt(int r, int g, int b, int a);	
 			
 			/**
-			* Sets the color of the entity as 0-255 integers.
-			* @param r Red value as a 0-255 integer.
-			* @param g Green value as a 0-255 integer.
-			* @param b Blue value as a 0-255 integer.
-			* @param a Alpha value as a 0-255 integer.
+			* Sets the color of the entity.
+			* @param color Color to set the entity color to.
 			*/									
 			void setColor(Color color);
 

+ 3 - 2
Core/Contents/Include/PolyGLSLShader.h

@@ -48,13 +48,14 @@ namespace Polycode {
 			virtual ~GLSLShader();
 
 			ShaderBinding *createBinding();
-			
+			virtual void reload();
+		
 			unsigned int shader_id;		
 			GLSLProgram *vp;
 			GLSLProgram *fp;			
 			
 		protected:
-			
+			void linkProgram();
 	};
 	
 	class _PolyExport GLSLShaderBinding : public ShaderBinding {

+ 1 - 0
Core/Contents/Include/PolyInputEvent.h

@@ -112,6 +112,7 @@ namespace Polycode {
 		float joystickAxisValue;
 		unsigned int joystickButton;
 		unsigned int joystickAxis;
+		unsigned int joystickIndex;
 		
 		protected:
 		

+ 5 - 1
Core/Contents/Include/PolyObject.h

@@ -37,7 +37,7 @@ namespace Polycode {
 		/**
 		* Default constructor
 		*/
-		ObjectEntry() { type = ObjectEntry::CONTAINER_ENTRY; }
+		ObjectEntry() { type = ObjectEntry::CONTAINER_ENTRY; type = UNKNOWN_ENTRY; length = 0; }
 				
 		/**
 		* Type of entry. Possible values are (FLOAT_ENTRY, INT_ENTRY, BOOL_ENTRY, ARRAY_ENTRY, STRING_ENTRY, CONTAINER_ENTRY).
@@ -160,8 +160,12 @@ namespace Polycode {
 			return entry;			
 		}		
 		
+		String getTypedName() const;
+		void setTypedName(const String &str);
+		
 		void Clear();
 		
+		static const int UNKNOWN_ENTRY = -1;
 		static const int FLOAT_ENTRY = 0;		
 		static const int INT_ENTRY = 1;
 		static const int BOOL_ENTRY = 2;

+ 2 - 1
Core/Contents/Include/PolyRenderer.h

@@ -224,7 +224,8 @@ namespace Polycode {
 		static const int BLEND_MODE_LIGHTEN = 1;
 		static const int BLEND_MODE_COLOR = 2;
 		static const int BLEND_MODE_PREMULTIPLIED = 3;
-				
+		static const int BLEND_MODE_MULTIPLY = 4;
+						
 		static const int FOG_LINEAR = 0;
 		static const int FOG_EXP = 1;
 		static const int FOG_EXP2 = 2;

+ 6 - 0
Core/Contents/Include/PolyResourceManager.h

@@ -73,6 +73,12 @@ namespace Polycode {
 			*/
 			Resource *getResource(int resourceType, const String& resourceName) const;
 		
+			/**
+			 * Request a full set of loaded resources. You need to manually cast them to their subclasses based on their type.
+			 * @param resourceType Type of resource. See Resource for available resource types.
+			 */
+			std::vector<Resource *> getResources(int resourceType);
+		
 			void addShaderModule(PolycodeShaderModule *module);
 		
 		

+ 3 - 0
Core/Contents/Include/PolyScreen.h

@@ -131,6 +131,9 @@ namespace Polycode {
 		*/		
 		ScreenEntity *getRootEntity() { return rootEntity; }
 		
+		int getNumChildren() { return children.size(); }
+		ScreenEntity *getChild(int index) { return children[index]; }
+		
 		/**
 		* If set to false, the screen will not be rendered or updated.
 		*/

+ 10 - 2
Core/Contents/Include/PolyShader.h

@@ -23,7 +23,9 @@ THE SOFTWARE.
 #pragma once
 #include "PolyString.h"
 #include "PolyGlobals.h"
+#include "PolyVector3.h"
 #include "PolyResource.h"
+#include <string.h>
 
 namespace Polycode {
 
@@ -41,6 +43,7 @@ namespace Polycode {
 			const String& getName() const;
 			
 			virtual ShaderBinding *createBinding() = 0;
+			virtual void reload() {}
 
 			static const int FIXED_SHADER = 0;
 			static const int MODULE_SHADER = 1;
@@ -70,7 +73,10 @@ namespace Polycode {
 	class LocalShaderParam {
 		public:	
 			String name;
-			void *data;		
+			void *data;
+			
+			void setNumber(Number n) { memcpy(data, &n, sizeof(n)); }
+			void setVector3(Vector3 v) { memcpy(data, &v, sizeof(v)); }
 	};	
 	
 	class RenderTargetBinding {
@@ -111,7 +117,9 @@ namespace Polycode {
 			RenderTargetBinding *getOutTargetBinding(unsigned int index);
 			
 			void addLocalParam(const String& name, void *ptr);
-			
+			void addLocalParamNumber(const String& name, Number n);
+			void addLocalParamVector3(const String& name, Vector3 v);
+		
 			Shader* shader;
 			std::vector<LocalShaderParam*> localParams;
 			std::vector<RenderTargetBinding*> renderTargetBindings;

+ 5 - 2
Core/Contents/Source/PolyConfig.cpp

@@ -48,9 +48,12 @@ void Config::loadConfig(const String& configNamespace, const String& fileName) {
 	TiXmlNode *pChild;
 	ConfigEntry *entry;
 	for(pChild = rootElement->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) {
+		TiXmlElement *pChildElement = pChild->ToElement();
+		if (!pChildElement) continue; // Skip comment nodes
+		
 		entry = getEntry(configNamespace, pChild->Value());
-		entry->stringVal = pChild->ToElement()->GetText();		
-		entry->numVal = atof(pChild->ToElement()->GetText());
+		entry->stringVal = pChildElement->GetText();		
+		entry->numVal = atof(pChildElement->GetText());
 		entry->isString = true;
 		entry->configNamespace = configNamespace;
 	}

+ 19 - 0
Core/Contents/Source/PolyCore.cpp

@@ -29,8 +29,27 @@
 
 #endif
 
+#include <time.h>
+
 namespace Polycode {
 	
+	TimeInfo::TimeInfo() {
+		time_t rawtime;
+		struct tm * timeinfo;
+		
+		time( &rawtime );
+		timeinfo = localtime ( &rawtime );
+	
+		seconds = timeinfo->tm_sec;
+		minutes = timeinfo->tm_min;
+		hours = timeinfo->tm_hour;
+		month = timeinfo->tm_mon;
+		monthDay = timeinfo->tm_mday;
+		weekDay = timeinfo->tm_wday;
+		year = timeinfo->tm_year;
+		yearDay = timeinfo->tm_yday;
+	}
+	
 	Core::Core(int _xRes, int _yRes, bool fullScreen, bool vSync, int aaLevel, int anisotropyLevel, int frameRate, int monitorIndex) : EventDispatcher() {
 		services = CoreServices::getInstance();
 		input = new CoreInput();

+ 6 - 0
Core/Contents/Source/PolyCoreInput.cpp

@@ -59,6 +59,7 @@ namespace Polycode {
 	JoystickInfo *CoreInput::getJoystickInfoByID(unsigned int deviceID) {
 		for(int i=0;i<joysticks.size();i++) {
 			if(joysticks[i].deviceID == deviceID) {
+				joysticks[i].deviceIndex = i;
 				return &joysticks[i];
 			}
 		}
@@ -71,6 +72,7 @@ namespace Polycode {
 		joysticks.push_back(joystick);
 		InputEvent *evt = new InputEvent();
 		evt->joystickDeviceID = deviceID;
+		evt->joystickIndex = joysticks.size()-1;
 		dispatchEvent(evt, InputEvent::EVENT_JOYDEVICE_ATTACHED);				
 	}
 	
@@ -80,6 +82,7 @@ namespace Polycode {
 				joysticks.erase(joysticks.begin()+i);
 				InputEvent *evt = new InputEvent();
 				evt->joystickDeviceID = deviceID;
+				evt->joystickIndex = i;
 				dispatchEvent(evt, InputEvent::EVENT_JOYDEVICE_DETACHED);
 				return;
 			}
@@ -94,6 +97,7 @@ namespace Polycode {
 			evt->joystickDeviceID = deviceID;
 			evt->joystickAxis = axisID;
 			evt->joystickAxisValue = value;
+			evt->joystickIndex = info->deviceIndex;
 			dispatchEvent(evt, InputEvent::EVENT_JOYAXIS_MOVED);
 		}	
 	}
@@ -105,6 +109,7 @@ namespace Polycode {
 			InputEvent *evt = new InputEvent();
 			evt->joystickDeviceID = deviceID;
 			evt->joystickButton = buttonID;
+			evt->joystickIndex = info->deviceIndex;			
 			dispatchEvent(evt, InputEvent::EVENT_JOYBUTTON_DOWN);
 		}		
 	}
@@ -116,6 +121,7 @@ namespace Polycode {
 			InputEvent *evt = new InputEvent();
 			evt->joystickDeviceID = deviceID;
 			evt->joystickButton = buttonID;
+			evt->joystickIndex = info->deviceIndex;			
 			dispatchEvent(evt, InputEvent::EVENT_JOYBUTTON_UP);
 		}	
 	}

+ 3 - 0
Core/Contents/Source/PolyGLRenderer.cpp

@@ -402,6 +402,9 @@ void OpenGLRenderer::setBlendingMode(int blendingMode) {
 		case BLEND_MODE_PREMULTIPLIED:
 			glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 		break;
+		case BLEND_MODE_MULTIPLY:
+			glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
+		break;		
 		default:
 			glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 		break;

+ 15 - 6
Core/Contents/Source/PolyGLSLShader.cpp

@@ -102,17 +102,26 @@ void GLSLShaderBinding::addParam(const String& type, const String& name, const S
 	localParams.push_back(newParam);
 }
 
-GLSLShader::GLSLShader(GLSLProgram *vp, GLSLProgram *fp) : Shader(Shader::MODULE_SHADER) {
-	this->vp = vp;
-	this->fp = fp;
-		
+void GLSLShader::linkProgram() {
 	shader_id = glCreateProgram();
     glAttachShader(shader_id, fp->program);
     glAttachShader(shader_id, vp->program);
 	
 	glBindAttribLocation(shader_id, 6, "vTangent");
-		
-    glLinkProgram(shader_id);	
+	
+    glLinkProgram(shader_id);
+}
+
+GLSLShader::GLSLShader(GLSLProgram *vp, GLSLProgram *fp) : Shader(Shader::MODULE_SHADER) {
+	this->vp = vp;
+	this->fp = fp;
+	
+	linkProgram();
+}
+
+void GLSLShader::reload() {
+	glDeleteProgram(shader_id);
+	linkProgram();
 }
 
 GLSLShader::~GLSLShader() {

+ 14 - 7
Core/Contents/Source/PolyGLSLShaderModule.cpp

@@ -116,10 +116,15 @@ Shader *GLSLShaderModule::createShader(TiXmlNode *node) {
 	GLSLProgram *vp = NULL;
 	GLSLProgram *fp = NULL;
 	GLSLShader *retShader = NULL;
+	TiXmlElement *nodeElement = node->ToElement();
+	if (!nodeElement) return NULL; // Skip comment nodes
 	
 	for (pChild = node->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) {
+		TiXmlElement *pChildElement = pChild->ToElement();
+		if (!pChildElement) continue; // Skip comment nodes
+		
 		if(strcmp(pChild->Value(), "vp") == 0) {
-			vp = (GLSLProgram*)CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_PROGRAM, String(pChild->ToElement()->Attribute("source")));
+			vp = (GLSLProgram*)CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_PROGRAM, String(pChildElement->Attribute("source")));
 			if(vp) {
 				for (pChild2 = pChild->FirstChild(); pChild2 != 0; pChild2 = pChild2->NextSibling()) {
 					if(strcmp(pChild2->Value(), "params") == 0) {
@@ -133,7 +138,7 @@ Shader *GLSLShaderModule::createShader(TiXmlNode *node) {
 			}
 		}
 		if(strcmp(pChild->Value(), "fp") == 0) {
-			fp = (GLSLProgram*)CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_PROGRAM, String(pChild->ToElement()->Attribute("source")));
+			fp = (GLSLProgram*)CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_PROGRAM, String(pChildElement->Attribute("source")));
 			if(fp) {
 				for (pChild2 = pChild->FirstChild(); pChild2 != 0; pChild2 = pChild2->NextSibling()) {
 					if(strcmp(pChild2->Value(), "params") == 0) {
@@ -150,7 +155,7 @@ Shader *GLSLShaderModule::createShader(TiXmlNode *node) {
 	}
 	if(vp != NULL && fp != NULL) {
 		GLSLShader *cgShader = new GLSLShader(vp,fp);
-		cgShader->setName(String(node->ToElement()->Attribute("name")));
+		cgShader->setName(String(nodeElement->Attribute("name")));
 		retShader = cgShader;
 		shaders.push_back((Shader*)cgShader);
 	}
@@ -710,10 +715,12 @@ void GLSLShaderModule::addParamToProgram(GLSLProgram *program,TiXmlNode *node) {
 		int autoID = 0;
 		int paramType = GLSLProgramParam::PARAM_UNKNOWN;
 		void *defaultData = NULL;
+		TiXmlElement *nodeElement = node->ToElement();
+		if (!nodeElement) return; // Skip comment nodes
 		
-		if(strcmp(node->ToElement()->Attribute("type"), "auto") == 0) {
+		if(strcmp(nodeElement->Attribute("type"), "auto") == 0) {
 			isAuto = true;
-			String pid = node->ToElement()->Attribute("id");
+			String pid = nodeElement->Attribute("id");
 			if(pid == "POLY_MODELVIEWPROJ_MATRIX")
 				autoID = GLSLProgramParam::POLY_MODELVIEWPROJ_MATRIX;
 			else if(pid == "POLY_AREA_LIGHT_POSITION_0")
@@ -800,10 +807,10 @@ void GLSLShaderModule::addParamToProgram(GLSLProgram *program,TiXmlNode *node) {
 			else
 				isAuto = false;
 		} else {
-			defaultData = GLSLProgramParam::createParamData(&paramType, node->ToElement()->Attribute("type"), node->ToElement()->Attribute("default"));
+			defaultData = GLSLProgramParam::createParamData(&paramType, nodeElement->Attribute("type"), nodeElement->Attribute("default"));
 		}
 		
-		program->addParam(node->ToElement()->Attribute("name"), isAuto, autoID, paramType, defaultData);
+		program->addParam(nodeElement->Attribute("name"), isAuto, autoID, paramType, defaultData);
 }
 
 void GLSLShaderModule::reloadPrograms() {

+ 76 - 40
Core/Contents/Source/PolyMaterialManager.cpp

@@ -78,6 +78,11 @@ void MaterialManager::reloadPrograms() {
 		PolycodeShaderModule *shaderModule = shaderModules[m];
 		shaderModule->reloadPrograms();
 	}
+	vector<Resource *> shaders = CoreServices::getInstance()->getResourceManager()->getResources(Resource::RESOURCE_SHADER);
+	for(int s = 0; s < shaders.size(); s++) {
+		Shader *shader = (Shader *)shaders[s];
+		shader->reload();
+	}
 }
 
 void MaterialManager::addShaderModule(PolycodeShaderModule *module) {
@@ -155,11 +160,13 @@ void MaterialManager::loadMaterialsFromFile(String fileName) {
 }
 
 Shader *MaterialManager::createShaderFromXMLNode(TiXmlNode *node) {
-	Shader *retShader = NULL;
+	TiXmlElement *nodeElement = node->ToElement();
+	if (!nodeElement) return NULL; // Skip comment nodes
 	
+	Shader *retShader = NULL;
 	
-	if(node->ToElement()->Attribute("type")) {
-		String shaderType = node->ToElement()->Attribute("type");
+	if(nodeElement->Attribute("type")) {
+		String shaderType = nodeElement->Attribute("type");
 //		Logger::log("Attempting to create %s shader\n", shaderType.c_str());
 		for(int m=0; m < shaderModules.size(); m++) {
 			PolycodeShaderModule *shaderModule = shaderModules[m];
@@ -172,11 +179,11 @@ Shader *MaterialManager::createShaderFromXMLNode(TiXmlNode *node) {
 	int numAreaLights = 0;
 	int numSpotLights = 0;
 		
-	if(node->ToElement()->Attribute("numAreaLights")) {
-		numAreaLights = atoi(node->ToElement()->Attribute("numAreaLights"));
+	if(nodeElement->Attribute("numAreaLights")) {
+		numAreaLights = atoi(nodeElement->Attribute("numAreaLights"));
 	}
-	if(node->ToElement()->Attribute("numSpotLights")) {
-		numSpotLights = atoi(node->ToElement()->Attribute("numSpotLights"));
+	if(nodeElement->Attribute("numSpotLights")) {
+		numSpotLights = atoi(nodeElement->Attribute("numSpotLights"));
 	}
 	
 	if(retShader) {
@@ -188,15 +195,18 @@ Shader *MaterialManager::createShaderFromXMLNode(TiXmlNode *node) {
 }
 
 Shader *MaterialManager::setShaderFromXMLNode(TiXmlNode *node) {
+	TiXmlElement *nodeElement = node->ToElement();
+	if (!nodeElement) return NULL; // Skip comment nodes
+	
 	Shader *retShader = NULL;
-	if(node->ToElement()->Attribute("type")) {
-		String shaderType = node->ToElement()->Attribute("type");
+	if(nodeElement->Attribute("type")) {
+		String shaderType = nodeElement->Attribute("type");
 		if(shaderType == "fixed") {
 			FixedShader *fShader =  new FixedShader();		
 			retShader = fShader;
 		}
 	} else {
-		retShader = (Shader*)CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_SHADER, node->ToElement()->Attribute("name"));
+		retShader = (Shader*)CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_SHADER, nodeElement->Attribute("name"));
 	}
 	return retShader;
 }
@@ -213,10 +223,13 @@ Shader *MaterialManager::setShaderFromXMLNode(TiXmlNode *node) {
 
 
 Cubemap *MaterialManager::cubemapFromXMLNode(TiXmlNode *node) {
-	Cubemap *newCubemap;
+	TiXmlElement *nodeElement = node->ToElement();
+	if (!nodeElement) return NULL; // Skip comment nodes
 	
-	String name = node->ToElement()->Attribute("name");
-	String mapString = node->ToElement()->GetText();
+	Cubemap *newCubemap = NULL;
+	
+	String name = nodeElement->Attribute("name");
+	String mapString = nodeElement->GetText();
 	
 	vector<String> maps = mapString.split(",");	
 	if(maps.size() != 6) {
@@ -237,7 +250,10 @@ Cubemap *MaterialManager::cubemapFromXMLNode(TiXmlNode *node) {
 }
 
 Material *MaterialManager::materialFromXMLNode(TiXmlNode *node) {
-	String mname = node->ToElement()->Attribute("name");
+	TiXmlElement *nodeElement = node->ToElement();
+	if (!nodeElement) return NULL; // Skip comment nodes
+
+	String mname = nodeElement->Attribute("name");
 	TiXmlNode* pChild, *pChild2,*pChild3;
 	Shader *materialShader;
 	ShaderBinding *newShaderBinding;
@@ -249,26 +265,32 @@ Material *MaterialManager::materialFromXMLNode(TiXmlNode *node) {
 	Material *newMaterial = new Material(mname);
 
 	for (pChild3 = node->FirstChild(); pChild3 != 0; pChild3 = pChild3->NextSibling()) {
+		TiXmlElement *pChild3Element = pChild3->ToElement();
+		if (!pChild3Element) continue; // Skip comment nodes
+
 		if(strcmp(pChild3->Value(), "rendertargets") == 0) {
 			
-			if(pChild3->ToElement()->Attribute("type")) {
-				if(strcmp(pChild3->ToElement()->Attribute("type"), "rgba_fp16") == 0) {
+			if(pChild3Element->Attribute("type")) {
+				if(strcmp(pChild3Element->Attribute("type"), "rgba_fp16") == 0) {
 					newMaterial->fp16RenderTargets = true;
 				}			
 			}
 		
 			for (pChild = pChild3->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) {
+				TiXmlElement *pChildElement = pChild->ToElement();
+				if (!pChildElement) continue; // Skip comment nodes
+
 				if(strcmp(pChild->Value(), "rendertarget") == 0) {
 					ShaderRenderTarget *newTarget = new ShaderRenderTarget;
-					newTarget->id = pChild->ToElement()->Attribute("id");
+					newTarget->id = pChildElement->Attribute("id");
 					newTarget->width = CoreServices::getInstance()->getRenderer()->getXRes();
 					newTarget->height = CoreServices::getInstance()->getRenderer()->getYRes();
 					newTarget->sizeMode = ShaderRenderTarget::SIZE_MODE_PIXELS;					
-					if(pChild->ToElement()->Attribute("width") && pChild->ToElement()->Attribute("height")) {
-						newTarget->width = atof(pChild->ToElement()->Attribute("width"));
-						newTarget->height = atof(pChild->ToElement()->Attribute("height"));	
-						if(pChild->ToElement()->Attribute("sizeMode")) {
-							if(strcmp(pChild->ToElement()->Attribute("sizeMode"), "normalized") == 0) {
+					if(pChildElement->Attribute("width") && pChildElement->Attribute("height")) {
+						newTarget->width = atof(pChildElement->Attribute("width"));
+						newTarget->height = atof(pChildElement->Attribute("height"));	
+						if(pChildElement->Attribute("sizeMode")) {
+							if(strcmp(pChildElement->Attribute("sizeMode"), "normalized") == 0) {
 								if(newTarget->width > 1.0f)
 									newTarget->width = 1.0f;
 								if(newTarget->height > 1.0f)
@@ -293,18 +315,20 @@ Material *MaterialManager::materialFromXMLNode(TiXmlNode *node) {
 	}
 	
 	for (pChild3 = node->FirstChild(); pChild3 != 0; pChild3 = pChild3->NextSibling()) {
-	
+		TiXmlElement *pChild3Element = pChild3->ToElement();
+		if (!pChild3Element) continue; // Skip comment nodes
+
 		if(strcmp(pChild3->Value(), "specularValue") == 0) {
-			newMaterial->specularValue = atof(pChild3->ToElement()->GetText());
+			newMaterial->specularValue = atof(pChild3Element->GetText());
 		}
 
 		if(strcmp(pChild3->Value(), "specularStrength") == 0) {
-			newMaterial->specularStrength = atof(pChild3->ToElement()->GetText());
+			newMaterial->specularStrength = atof(pChild3Element->GetText());
 		}
 
 
 		if(strcmp(pChild3->Value(), "specularColor") == 0) {		
-			String value = pChild3->ToElement()->GetText();
+			String value = pChild3Element->GetText();
 			vector<String> values = value.split(" ");
 			if(values.size() == 4) {
 				newMaterial->specularColor.setColor(atof(values[0].c_str()), atof(values[1].c_str()), atof(values[2].c_str()),atof(values[3].c_str()));
@@ -314,7 +338,7 @@ Material *MaterialManager::materialFromXMLNode(TiXmlNode *node) {
 		}
 
 		if(strcmp(pChild3->Value(), "diffuseColor") == 0) {
-			String value = pChild3->ToElement()->GetText();
+			String value = pChild3Element->GetText();
 			vector<String> values = value.split(" ");
 			if(values.size() == 4) {
 				newMaterial->diffuseColor.setColor(atof(values[0].c_str()), atof(values[1].c_str()), atof(values[2].c_str()),atof(values[3].c_str()));
@@ -331,28 +355,37 @@ Material *MaterialManager::materialFromXMLNode(TiXmlNode *node) {
 				materialShaders.push_back(materialShader);
 				newShaderBindings.push_back(newShaderBinding);
 				for (pChild = pChild3->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) {
+					TiXmlElement *pChildElement = pChild->ToElement();
+					if (!pChildElement) continue; // Skip comment nodes
+
 					if(strcmp(pChild->Value(), "params") == 0) {
 						for (pChild2 = pChild->FirstChild(); pChild2 != 0; pChild2 = pChild2->NextSibling()) {
+							TiXmlElement *pChild2Element = pChild2->ToElement();
+							if (!pChild2Element) continue; // Skip comment nodes
+
 							if(strcmp(pChild2->Value(), "param") == 0){
-								String pname =  pChild2->ToElement()->Attribute("name");
-								String ptype =  pChild2->ToElement()->Attribute("type");
-								String pvalue =  pChild2->ToElement()->Attribute("value");
+								String pname =  pChild2Element->Attribute("name");
+								String ptype =  pChild2Element->Attribute("type");
+								String pvalue =  pChild2Element->Attribute("value");
 								newShaderBinding->addParam(ptype, pname, pvalue);
 							}						
 						}
 					}
 					if(strcmp(pChild->Value(), "targettextures") == 0) {
 						for (pChild2 = pChild->FirstChild(); pChild2 != 0; pChild2 = pChild2->NextSibling()) {
+							TiXmlElement *pChild2Element = pChild2->ToElement();
+							if (!pChild2Element) continue; // Skip comment nodes
+
 							if(strcmp(pChild2->Value(), "targettexture") == 0){
 							
 								RenderTargetBinding* newBinding = new RenderTargetBinding;
-								newBinding->id = pChild2->ToElement()->Attribute("id");
+								newBinding->id = pChild2Element->Attribute("id");
 								
 								newBinding->name = "";
-								if(pChild2->ToElement()->Attribute("name")) {
-									newBinding->name = pChild2->ToElement()->Attribute("name");
+								if(pChild2Element->Attribute("name")) {
+									newBinding->name = pChild2Element->Attribute("name");
 								}
-								String mode = pChild2->ToElement()->Attribute("mode");
+								String mode = pChild2Element->Attribute("mode");
 								if(strcmp(mode.c_str(), "in") == 0) {
 									newBinding->mode = RenderTargetBinding::MODE_IN;
 								} else {
@@ -380,20 +413,23 @@ Material *MaterialManager::materialFromXMLNode(TiXmlNode *node) {
 					}					
 					if(strcmp(pChild->Value(), "textures") == 0) {
 						for (pChild2 = pChild->FirstChild(); pChild2 != 0; pChild2 = pChild2->NextSibling()) {
+							TiXmlElement *pChild2Element = pChild2->ToElement();
+							if (!pChild2Element) continue; // Skip comment nodes
+
 							if(strcmp(pChild2->Value(), "texture") == 0){
 								String tname = "";
-								if(pChild2->ToElement()->Attribute("name")) {
-									tname =  pChild2->ToElement()->Attribute("name");
+								if(pChild2Element->Attribute("name")) {
+									tname =  pChild2Element->Attribute("name");
 								}
-								newShaderBinding->addTexture(tname, (Texture*)CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_TEXTURE, pChild2->ToElement()->GetText()));
+								newShaderBinding->addTexture(tname, (Texture*)CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_TEXTURE, pChild2Element->GetText()));
 							}
 							
 							if(strcmp(pChild2->Value(), "cubemap") == 0){
 								String tname = "";
-								if(pChild2->ToElement()->Attribute("name")) {
-									tname =  pChild2->ToElement()->Attribute("name");
+								if(pChild2Element->Attribute("name")) {
+									tname =  pChild2Element->Attribute("name");
 								}
-								newShaderBinding->addCubemap(tname, (Cubemap*)CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_CUBEMAP, pChild2->ToElement()->GetText()));
+								newShaderBinding->addCubemap(tname, (Cubemap*)CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_CUBEMAP, pChild2Element->GetText()));
 							}
 							
 						}

+ 149 - 67
Core/Contents/Source/PolyObject.cpp

@@ -22,6 +22,7 @@
  
 #include "PolyObject.h"
 #include "tinyxml.h"
+#include <sstream>
 
 using namespace Polycode;
 
@@ -33,6 +34,46 @@ void ObjectEntry::Clear() {
 	children.clear();
 }
 
+String ObjectEntry::getTypedName() const {
+	const String _name = name.size() > 0 ? name : String("nil");
+	if (type == ObjectEntry::ARRAY_ENTRY)
+		return String("polyarray:") + _name;
+	if (type == ObjectEntry::STRING_ENTRY && stringVal.size() == 0)
+		return String("polystring:") + _name;
+	
+	// TODO: In interest of consistency, make sure that STRING_ENTRYs stay STRING_ENTRYs (etc) if they're ambiguous (i.e. contain numbers)
+	
+	return _name;
+}	
+	
+void ObjectEntry::setTypedName(const String &str) {
+	size_t firstColon = str.find(":");
+	// Note: This will split up a:b:c as having type "a" and name "b:c". Is this appropriate?
+	if (firstColon == -1) {
+		name = str;
+	} else { // There was a namespace
+		name = str.substr(firstColon+1);
+		
+		String sty = str.substr(0,firstColon);
+		if (sty == "polyfloat")
+			type = ObjectEntry::FLOAT_ENTRY;
+		else if (sty == "polyint")
+			type = ObjectEntry::INT_ENTRY;
+		else if (sty == "polybool")
+			type = ObjectEntry::BOOL_ENTRY;
+		else if (sty == "polyarray")
+			type = ObjectEntry::ARRAY_ENTRY;
+		else if (sty == "polystring")
+			type = ObjectEntry::STRING_ENTRY;
+		else if (sty == "polycontainer")
+			type = ObjectEntry::CONTAINER_ENTRY;
+			
+	}
+	if (name == "nil")
+		name.contents.clear();
+	
+}
+
 Object::Object() {
 	
 }
@@ -54,40 +95,65 @@ void Object::saveToXML(const String& fileName) {
 
 
 TiXmlElement *Object::createElementFromObjectEntry(ObjectEntry *entry) {
-	TiXmlElement *newElement = new TiXmlElement(entry->name.c_str());  
+	TiXmlElement *newElement = new TiXmlElement(entry->getTypedName().c_str());
 	
-	for(int i=0; i < entry->children.size(); i++) {
-		ObjectEntry *childEntry = entry->children[i];
-		
-//		printf("Parsing %s (type: %d)\n", childEntry->name.c_str(), childEntry->type);
-		
-		switch(childEntry->type) {
-			case ObjectEntry::BOOL_ENTRY:
-				if(childEntry->boolVal)
-					newElement->SetAttribute(childEntry->name.c_str(), "true");
-				else
-					newElement->SetAttribute(childEntry->name.c_str(), "false");
-			break;
-			case ObjectEntry::FLOAT_ENTRY:
-				newElement->SetAttribute(childEntry->name.c_str(), String::NumberToString(childEntry->NumberVal).c_str());								
-			break;
-			case ObjectEntry::INT_ENTRY:				
-				newElement->SetAttribute(childEntry->name.c_str(), childEntry->intVal);												
-			break;
-			case ObjectEntry::STRING_ENTRY: 
-			{
-				TiXmlElement *childElement = new TiXmlElement(childEntry->name.c_str());  
-				childElement->LinkEndChild( new TiXmlText(childEntry->stringVal.c_str()));
-				newElement->LinkEndChild(childElement);								
+	switch(entry->type) {
+		case ObjectEntry::BOOL_ENTRY: {
+			newElement->LinkEndChild(new TiXmlText( entry->boolVal ? "true" : "false" ));
+		} break;
+		case ObjectEntry::FLOAT_ENTRY: case ObjectEntry::INT_ENTRY: {
+			std::ostringstream o;
+			if (entry->type == ObjectEntry::FLOAT_ENTRY)
+				o << entry->NumberVal;
+			else
+				o << entry->intVal;
+			newElement->LinkEndChild(new TiXmlText( o.str().c_str() ));
+		} break;
+		case ObjectEntry::STRING_ENTRY: {
+			newElement->LinkEndChild(new TiXmlText( entry->stringVal.c_str() ));
+		} break;
+		default: { // Some sort of container.
+			for(int i=0; i < entry->children.size(); i++) {
+				ObjectEntry *childEntry = entry->children[i];
+				bool needLinkChild = entry->type == ObjectEntry::ARRAY_ENTRY;
+				
+		//		printf("Parsing %s (type: %d)\n", childEntry->name.c_str(), childEntry->type);
+				
+				if (!needLinkChild) {
+					const String &childTypedName = childEntry->getTypedName();
+					switch(childEntry->type) {
+						case ObjectEntry::BOOL_ENTRY:
+							if(childEntry->boolVal)
+								newElement->SetAttribute(childTypedName.c_str(), "true");
+							else
+								newElement->SetAttribute(childTypedName.c_str(), "false");
+						break;
+						case ObjectEntry::FLOAT_ENTRY: {
+							std::ostringstream o; // Avoid NumberToString, it truncates
+							o << childEntry->NumberVal;
+							newElement->SetAttribute(childTypedName.c_str(), o.str().c_str());
+						} break;
+						case ObjectEntry::INT_ENTRY:				
+							newElement->SetAttribute(childTypedName.c_str(), childEntry->intVal);												
+						break;
+						case ObjectEntry::STRING_ENTRY: 
+						{
+							TiXmlElement *childElement = new TiXmlElement(childTypedName.c_str());  
+							childElement->LinkEndChild( new TiXmlText(childEntry->stringVal.c_str()));
+							newElement->LinkEndChild(childElement);								
+						} break;
+						default:
+							needLinkChild = true;
+						break;
+					}
+				}
+				
+				if (needLinkChild) {
+					TiXmlElement *childElement = createElementFromObjectEntry(childEntry);
+					newElement->LinkEndChild(childElement);
+				}
 			}
-				break;				
-			default:
-			{
-				TiXmlElement *childElement = createElementFromObjectEntry(entry->children[i]);
-				newElement->LinkEndChild(childElement);				
-			}
-			break;
-		}
+		} break;
 	}
 	
 	return newElement;
@@ -125,9 +191,8 @@ bool Object::loadFromXML(const String& fileName) {
 
 
 void Object::createFromXMLElement(TiXmlElement *element, ObjectEntry *entry) {
-	entry->name = element->Value();
 	entry->type = ObjectEntry::CONTAINER_ENTRY;
-
+	
 	int ival;
 	double dval;	
 	
@@ -139,29 +204,31 @@ void Object::createFromXMLElement(TiXmlElement *element, ObjectEntry *entry) {
 		ObjectEntry *newEntry = new ObjectEntry();
 		newEntry->type = ObjectEntry::STRING_ENTRY;		
 		newEntry->stringVal = pAttrib->Value();
-		newEntry->name = pAttrib->Name();
 		
-		if (pAttrib->QueryIntValue(&ival)==TIXML_SUCCESS) {
-			if(newEntry->stringVal.find(".") != -1 && pAttrib->QueryDoubleValue(&dval)==TIXML_SUCCESS) {
-				newEntry->NumberVal = dval;
-				newEntry->intVal = dval;				
-				newEntry->type = ObjectEntry::FLOAT_ENTRY;				
-			} else {
-				newEntry->intVal = ival;
-				newEntry->NumberVal = (Number)ival;				
-				newEntry->type = ObjectEntry::INT_ENTRY;
-			}
+		if (newEntry->stringVal.find(".") == -1 && pAttrib->QueryIntValue(&ival)==TIXML_SUCCESS) {
+			newEntry->intVal = ival;
+			newEntry->NumberVal = (Number)ival;
+			newEntry->type = ObjectEntry::INT_ENTRY;
+		} else if (pAttrib->QueryDoubleValue(&dval)==TIXML_SUCCESS) {
+			newEntry->NumberVal = dval;
+			newEntry->intVal = dval;
+			newEntry->type = ObjectEntry::FLOAT_ENTRY;
 		}
-
 		
 		if(newEntry->stringVal == "true") {
 			newEntry->boolVal = true;
+			newEntry->intVal = 1;
+			newEntry->NumberVal = 1;
 			newEntry->type = ObjectEntry::BOOL_ENTRY;
 		}
 		if(newEntry->stringVal == "false") {
 			newEntry->boolVal = false;
+			newEntry->intVal = 0;
+			newEntry->NumberVal = 0;
 			newEntry->type = ObjectEntry::BOOL_ENTRY;
 		}
+	
+		newEntry->setTypedName(pAttrib->Name()); // Set name last because we might override type
 		
 		entry->children.push_back(newEntry);
 	
@@ -174,8 +241,21 @@ void Object::createFromXMLElement(TiXmlElement *element, ObjectEntry *entry) {
 		entry->stringVal = element->GetText();
 		entry->type = ObjectEntry::STRING_ENTRY;
 		
-		entry->intVal = atoi(entry->stringVal.c_str());
-		entry->NumberVal = atof(entry->stringVal.c_str());
+		const char *rawVal = entry->stringVal.c_str();
+		char *endResult = NULL; const char *success = rawVal + entry->stringVal.size();
+		entry->intVal = strtol(rawVal, &endResult, 10);
+		if (endResult == success) { // If integer part exhausts string
+			entry->type = ObjectEntry::INT_ENTRY;
+			entry->NumberVal = entry->intVal;
+			entry->boolVal = entry->intVal;
+		} else {
+			entry->NumberVal = strtof(rawVal, &endResult);
+			entry->intVal = entry->NumberVal;
+			entry->boolVal = entry->NumberVal;
+			if (endResult == success) {
+				entry->type = ObjectEntry::FLOAT_ENTRY;
+			}
+		}
 		
 		if(entry->stringVal == "true") {
 			entry->boolVal = true;
@@ -185,26 +265,28 @@ void Object::createFromXMLElement(TiXmlElement *element, ObjectEntry *entry) {
 			entry->boolVal = false;
 			entry->type = ObjectEntry::BOOL_ENTRY;
 		}
-		
-		return;
-	}
-		
-	// then through the children	
-	TiXmlNode* pChild;	
-
-	String lastName = "";
-	int count = 0;
-	for (pChild = element->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) {
-		ObjectEntry *newEntry = new ObjectEntry();		
-		createFromXMLElement(pChild->ToElement(), newEntry);
-		entry->children.push_back(newEntry);		
-		if(entry->name == lastName) {
-			entry->type = ObjectEntry::ARRAY_ENTRY;
+	} else {
+		// then through the children	
+		TiXmlNode* pChild;	
+
+		String lastName = "";
+		int count = 0;
+		for (pChild = element->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) {
+			TiXmlElement *pChildElement = pChild->ToElement();
+			if (!pChildElement) continue; // Skip comment nodes
+			
+			ObjectEntry *newEntry = new ObjectEntry();
+			createFromXMLElement(pChildElement, newEntry);
+			entry->children.push_back(newEntry);		
+			if(newEntry->name == lastName) { // Keys cannot repeat in a CONTAINER
+				entry->type = ObjectEntry::ARRAY_ENTRY;
+			}
+			lastName = newEntry->name;			
+			count++;
 		}
-		lastName = entry->name;			
-		count++;
+		
+		entry->length = count;
 	}
-	
-	entry->length = count;
 
+	entry->setTypedName(element->Value()); // Set name last because we might override type
 }

+ 17 - 2
Core/Contents/Source/PolyResourceManager.cpp

@@ -131,8 +131,10 @@ void ResourceManager::parseMaterials(const String& dirPath, bool recursive) {
 						TiXmlNode* pChild;					
 						for (pChild = mElem->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) {
 							Material *newMat = CoreServices::getInstance()->getMaterialManager()->materialFromXMLNode(pChild);
-							newMat->setResourceName(newMat->getName());
-							resources.push_back(newMat);
+							if (newMat) {
+								newMat->setResourceName(newMat->getName());
+								resources.push_back(newMat);
+							}
 						}
 					}
 				}
@@ -251,3 +253,16 @@ Resource *ResourceManager::getResource(int resourceType, const String& resourceN
 	// need to add some sort of default resource for each type
 	return NULL;
 }
+
+// Would it make more sense to pass back, like, something like an ObjectEntry here? Lua hates vectors.
+vector<Resource *> ResourceManager::getResources(int resourceType) {
+	vector<Resource *> result;
+	Logger::log("requested all of type %d\n", resourceType);
+	for(int i =0; i < resources.size(); i++) {
+		//		Logger::log("is it %s?\n", resources[i]->getResourceName().c_str());		
+		if(resources[i]->getResourceType() == resourceType) {
+			result.push_back(resources[i]);
+		}
+	}
+	return result;
+}

+ 5 - 0
Core/Contents/Source/PolySceneLabel.cpp

@@ -61,6 +61,11 @@ void SceneLabel::setText(const String& newText) {
 	mesh = new Mesh(Mesh::QUAD_MESH);
 	mesh->createVPlane(label->getWidth()*scale,label->getHeight()*scale);
 	
+	bBox.x = label->getWidth()*scale;
+	bBox.y = label->getHeight()*scale;
+	bBox.z = 0;
+	
+	
 	for(int i=0; i < mesh->getPolygonCount(); i++) {
 		mesh->getPolygon(i)->flipUVY();
 	}

+ 12 - 0
Core/Contents/Source/PolyShader.cpp

@@ -56,6 +56,18 @@ void ShaderBinding::addLocalParam(const String& name, void *ptr) {
 	localParams.push_back(newParam);
 }
 
+void ShaderBinding::addLocalParamNumber(const String& name, Number n) {
+	Number *value = new Number;
+	*value = n;
+	addLocalParam(name, value);
+}
+
+void ShaderBinding::addLocalParamVector3(const String& name, Vector3 v) {
+	Vector3 *value = new Vector3;
+	memcpy(value, &v, sizeof(v));
+	addLocalParam(name, value);
+}
+
 void ShaderBinding::addRenderTargetBinding(RenderTargetBinding *binding) {
 	renderTargetBindings.push_back(binding);
 	if(binding->mode == RenderTargetBinding::MODE_IN) {

+ 17 - 0
Modules/Contents/3DPhysics/Include/PolyPhysicsScene.h

@@ -31,6 +31,7 @@ class btSequentialImpulseConstraintSolver;
 class btGhostPairCallback;
 class btTypedConstraint;
 class btHingeConstraint;
+class btGeneric6DofConstraint;
 
 namespace Polycode {
 
@@ -55,6 +56,18 @@ namespace Polycode {
 			Vector3 positionOnB;
 			Vector3 worldNormalOnB;				
 	};
+	
+	class _PolyExport PhysicsGenericConstraint {
+		public:
+			
+			void setLinearLowerLimit(Vector3 limit);
+			void setLinearUpperLimit(Vector3 limit);
+						
+			void setAngularLowerLimit(Vector3 limit);
+			void setAngularUpperLimit(Vector3 limit);
+					
+			btGeneric6DofConstraint *btConstraint;
+	};
 
 	class _PolyExport PhysicsHingeConstraint  {
 		public:
@@ -101,10 +114,14 @@ namespace Polycode {
 		PhysicsHingeConstraint *createHingeConstraint(SceneEntity *entity, Vector3 pivot, Vector3 axis, Number minLimit, Number maxLimit);
 
 		PhysicsHingeConstraint *createHingeJoint(SceneEntity *entity1, SceneEntity *entity2, Vector3 pivot1, Vector3 axis1, Vector3 pivot2, Vector3 axis2, Number minLimit, Number maxLimit);
+		
+		PhysicsGenericConstraint *createGenericConstraint(SceneEntity *entity);
 				
 		void setVelocity(SceneEntity *entity, Vector3 velocity);
 		void warpEntity(SceneEntity *entity, Vector3 position, bool resetRotation = false);
 		
+		void applyImpulse(SceneEntity *entity, Vector3 force, Vector3 point);
+		
 		PhysicsVehicle *addVehicleChild(SceneEntity *newEntity, Number mass, Number friction, int group  = 1);
 		
 		void setGravity(Vector3 gravity);

+ 2 - 0
Modules/Contents/3DPhysics/Include/PolyPhysicsSceneEntity.h

@@ -52,6 +52,8 @@ namespace Polycode {
 		
 			void setVelocity(Vector3 velocity);
 			void warpTo(Vector3 position, bool resetRotation);
+			
+			void applyImpulse(Vector3 direction, Vector3 point);
 			//@}
 			// ----------------------------------------------------------------------------------------------------------------
 			

+ 47 - 0
Modules/Contents/3DPhysics/Source/PolyPhysicsScene.cpp

@@ -169,10 +169,19 @@ void PhysicsScene::setVelocity(SceneEntity *entity, Vector3 velocity) {
 void PhysicsScene::warpEntity(SceneEntity *entity, Vector3 position, bool resetRotation) {
 	PhysicsSceneEntity *physicsEntity = getPhysicsEntityBySceneEntity(entity);
 	if(physicsEntity) {
+		physicsEntity->rigidBody->setActivationState(DISABLE_DEACTIVATION);	
 		physicsEntity->warpTo(position, resetRotation);
 	}
 }
 
+void PhysicsScene::applyImpulse(SceneEntity *entity, Vector3 force, Vector3 point) {
+	PhysicsSceneEntity *physicsEntity = getPhysicsEntityBySceneEntity(entity);	
+	if(physicsEntity) {
+		physicsEntity->rigidBody->setActivationState(DISABLE_DEACTIVATION);		
+		physicsEntity->applyImpulse(force, point);
+	}
+}
+
 PhysicsCharacter *PhysicsScene::addCharacterChild(SceneEntity *newEntity,Number mass, Number friction, Number stepSize, int group) {
 	addEntity(newEntity);	
 	PhysicsCharacter *newPhysicsEntity = new PhysicsCharacter(newEntity, mass, friction, stepSize);
@@ -285,6 +294,44 @@ Number PhysicsHingeConstraint::getAngle() {
 	return btConstraint->getHingeAngle();
 }
 
+void PhysicsGenericConstraint::setLinearLowerLimit(Vector3 limit) {
+	btVector3 btLimit = btVector3(limit.x, limit.y, limit.z);
+	btConstraint->setLinearLowerLimit(btLimit);
+}
+
+void PhysicsGenericConstraint::setLinearUpperLimit(Vector3 limit) {
+	btVector3 btLimit = btVector3(limit.x, limit.y, limit.z);
+	btConstraint->setLinearUpperLimit(btLimit);
+}
+
+void PhysicsGenericConstraint::setAngularLowerLimit(Vector3 limit) {
+	btVector3 btLimit = btVector3(limit.x, limit.y, limit.z);
+	btConstraint->setAngularLowerLimit(btLimit);
+}
+
+void PhysicsGenericConstraint::setAngularUpperLimit(Vector3 limit) {
+	btVector3 btLimit = btVector3(limit.x, limit.y, limit.z);
+	btConstraint->setAngularUpperLimit(btLimit);
+}
+
+PhysicsGenericConstraint *PhysicsScene::createGenericConstraint(SceneEntity *entity) {
+
+	PhysicsSceneEntity *pEnt = getPhysicsEntityBySceneEntity(entity);
+	if(!pEnt) {
+		return NULL;
+	}
+	
+	PhysicsGenericConstraint *constraint = new PhysicsGenericConstraint();
+	
+	btTransform frame;
+	frame.setIdentity();
+	
+	constraint->btConstraint = new btGeneric6DofConstraint(*pEnt->rigidBody, frame, true);
+	physicsWorld->addConstraint(constraint->btConstraint);
+	
+	return constraint;
+}
+
 PhysicsHingeConstraint * PhysicsScene::createHingeConstraint(SceneEntity *entity, Vector3 pivot, Vector3 axis, Number minLimit, Number maxLimit) {
 	PhysicsSceneEntity *pEnt = getPhysicsEntityBySceneEntity(entity);
 	if(!pEnt) {

+ 7 - 0
Modules/Contents/3DPhysics/Source/PolyPhysicsSceneEntity.cpp

@@ -244,6 +244,13 @@ void PhysicsSceneEntity::setVelocity(Vector3 velocity) {
 //	rigidBody->applyForce(btVector3(velocity.x, velocity.y, velocity.z), btVector3(0,0,0));
 }
 
+void PhysicsSceneEntity::applyImpulse(Vector3 direction, Vector3 point) {
+	btVector3 imp = btVector3(direction.x, direction.y, direction.z);
+	btVector3 pos = btVector3(point.x, point.y, point.z);
+		 
+	rigidBody->applyImpulse(imp, pos);
+}
+
 void PhysicsSceneEntity::warpTo(Vector3 position, bool resetRotation) {
 	btTransform transform;
 	transform.setIdentity();

+ 5 - 2
Tools/Contents/polyimport/Source/polyimport.cpp

@@ -185,8 +185,11 @@ int main(int argc, char **argv) {
 
 	printf("Loading %s...\n", argv[1]);
 	scene = aiImportFile(argv[1],aiProcessPreset_TargetRealtime_Quality);
-
-	exportToFile(argv[2], strcmp(argv[3], "true") == 0);
+	if(scene) {
+		exportToFile(argv[2], strcmp(argv[3], "true") == 0);
+	} else {
+		printf("Error opening scene...\n");
+	}
 
 	aiReleaseImport(scene);
 	return 1;