
// zlib open source license
//
// Copyright (c) 2010 to 2013 David Forsgren Piuva
// 
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// 
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 
//    1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would be
//    appreciated but is not required.
// 
//    2. Altered source versions must be plainly marked as such, and must not be
//    misrepresented as being the original software.
// 
//    3. This notice may not be removed or altered from any source
//    distribution.

#define ParserState_WaitForStatement		0 // NameSpace -> WaitForStatement, Identifier -> WaitForIndexOrProperty
#define ParserState_WaitForIndexOrProperty	1 // Index -> WaitForProperty, Property -> WaitForStatement
#define ParserState_WaitForProperty			2 // Property -> WaitForStatement
#define ParserSpace_Main					0
	#define ParserSpace_Part					1
		#define ParserSpace_Triangle				2
	#define ParserSpace_Bone					3
	#define ParserSpace_Shape					4
		#define ParserSpace_Point					5
#define PARSER_NOINDEX if (Index != 0) { swprintf_s( MQ->messageBuffer, L"This version of the engine does not have an index for the property %s.",PropertyName); MQ->InsertMessage(MQ->messageBuffer); }
#define PARSER_MATCH(NAME) (CompareStrings_CaseInsensitive(PropertyName,L#NAME))

void EngineCore::Parser_SetProperty(wchar_t* PropertyName, int Index, wchar_t* Content) {
	float Value; int PartIndex; int TriangleIndex; int VerticeIndex;
	wchar_t extensionlessFilename[260];
	wchar_t extensionlessFilenameWithPath[520];
	Try_Start {
		if (Parser_CurrentModel == NULL) {
			MQ->InsertMessage(L"Parser_SetProperty: The current model is NULL.");
			return;
		}
	} Try_Else {
		MQ->InsertMessage(L"Parser_SetProperty: Access violation while checking if the current model is NULL.");
		return;
	}
	Try_Start {
		Try_Start {
			Value = (float)ParseDouble(Content);
		} Try_Else {
			MQ->InsertMessage(L"Parser_SetProperty: Access violation while parsing the content as a floatingpoint value.");
			return;
		}
		if (m_ParserSpace == ParserSpace_Main) {
			Try_Start {
				if			PARSER_MATCH(FilterType) {
					PARSER_NOINDEX
					Parser_CurrentModel->SetFilterUsingName(Content,L"Model_LoadFromFile_InSB");
				} else if	PARSER_MATCH(CullingType) {
					PARSER_NOINDEX
					Parser_CurrentModel->SetCullingUsingName(Content,L"Model_LoadFromFile_InSB");
				} else if	PARSER_MATCH(BoundMultiplier) {
					PARSER_NOINDEX
					Parser_CurrentModel->ModelProperties.BoundMultiplier = Value;
				} else {
					swprintf_s( MQ->messageBuffer, L"\"%s\" is not a known property in the \"Main\" namespace.\n",PropertyName,Index,Content,Value); MQ->InsertMessage(MQ->messageBuffer);
				}
			} Try_Else {
				swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting a part property called \"%s\" using index %i containing the value \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
				return;
			}
		} else if (m_ParserSpace == ParserSpace_Part) {
			Try_Start {
				if			PARSER_MATCH(Name) {
					Try_Start {
						PARSER_NOINDEX
						Parser_CurrentModel->SetPartName((Parser_CurrentModel->GetNumberOfParts()) - 1,Content);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting a part name. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(Texture) {
					Try_Start {
						// Load and assign a texture
						Texture_Struct* TheTexture;
						if (removeExtension(Content,extensionlessFilename)) {
							if (m_Parser_ModelPath[0] == L'\0') {
								Try_Start {
									TheTexture = Texture_Load(extensionlessFilename,false);
								} Try_Else {
									swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while calling Texture_Load with a simple path. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
									return;
								}
							} else {
								Try_Start {
									swprintf_s(extensionlessFilenameWithPath,L"%s/%s",m_Parser_ModelPath,extensionlessFilename);
								} Try_Else {
									swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while concatunating a filename for Texture_Load. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
									return;
								}
								Try_Start {
									TheTexture = Texture_Load(extensionlessFilenameWithPath,false);
								} Try_Else {
									swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while calling Texture_Load with a concatunated path. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
									return;
								}
							}
						} else {
							swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: A path to a texture was too long. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
							return;
						}
						Try_Start {
							Parser_CurrentModel->SetPartTexture((Parser_CurrentModel->GetNumberOfParts()) - 1,Index,TheTexture);
						} Try_Else {
							swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while calling SetPartTexture. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
							return;
						}
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while assigning a texture. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(Shader) {
					Try_Start {
						// Load and assign a shader
						Shader_Struct* TheShader;
						if (removeExtension(Content,extensionlessFilename)) {
							if (m_Parser_ModelPath[0] == L'\0') {
								Try_Start {
									TheShader = Shader_Load(extensionlessFilename,ShaderType_Material,false);
								} Try_Else {
									swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while calling Shader_Load with a simple path. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
									return;
								}
							} else {
								Try_Start {
									swprintf_s(extensionlessFilenameWithPath,L"%s/%s",m_Parser_ModelPath,extensionlessFilename);
								} Try_Else {
									swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while concatunating a filename for Shader_Load. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
									return;
								}
								Try_Start {
									TheShader = Shader_Load(extensionlessFilenameWithPath,ShaderType_Material,false);
								} Try_Else {
									swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while calling Shader_Load with a concatunated path. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
									return;
								}
							}
							Try_Start {
								Parser_CurrentModel->SetPartShader((Parser_CurrentModel->GetNumberOfParts()) - 1,Index,TheShader);
							} Try_Else {
								swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while calling SetPartShader. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
								return;
							}
						} else {
							swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: A path to a shader was too long. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
							return;
						}
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while assigning a shader. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(TextureOverride) {
					Try_Start {
						// Set the texture override channel
						Parser_CurrentModel->SetPartTextureOverride((Parser_CurrentModel->GetNumberOfParts()) - 1,Index,(int)Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting texture override. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(MinDetailLevel) {
					Try_Start {
						// Set the minimum detail level
						Parser_CurrentModel->SetPartMinDetailLevel((Parser_CurrentModel->GetNumberOfParts()) - 1,(int)Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting texture MinDetailLevel. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(MaxDetailLevel) {
					Try_Start {
						// Set the maximum detail level
						Parser_CurrentModel->SetPartMaxDetailLevel((Parser_CurrentModel->GetNumberOfParts()) - 1,(int)Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting texture MaxDetailLevel. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else {
					swprintf_s( MQ->messageBuffer, L"\"%s\" is not a known property in the \"Part\" namespace.\n",PropertyName,Index,Content,Value); MQ->InsertMessage(MQ->messageBuffer);
				}
			} Try_Else {
				swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation was detected while setting a part property called \"%s\" using index %i containing the value \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
				return;
			}
		} else if (m_ParserSpace == ParserSpace_Triangle) {
			Try_Start {
				PartIndex = (Parser_CurrentModel->GetNumberOfParts()) - 1;
				TriangleIndex = Parser_CurrentModel->GetTriangleCountFromPart(PartIndex) - 1;
				VerticeIndex = Index;
				if			PARSER_MATCH(X) {
					Parser_CurrentModel->Vertice_SetPos_X(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(Y) {
					Parser_CurrentModel->Vertice_SetPos_Y(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(Z) {
					Parser_CurrentModel->Vertice_SetPos_Z(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(NX) {
					Parser_CurrentModel->Vertice_SetNormal_X(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(NY) {
					Parser_CurrentModel->Vertice_SetNormal_Y(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(NZ) {
					Parser_CurrentModel->Vertice_SetNormal_Z(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(CR) {
					Parser_CurrentModel->Vertice_SetColor_R(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(CG) {
					Parser_CurrentModel->Vertice_SetColor_G(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(CB) {
					Parser_CurrentModel->Vertice_SetColor_B(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(CA) {
					Parser_CurrentModel->Vertice_SetColor_A(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(U1) {
					Parser_CurrentModel->Vertice_SetTexCoord_U1(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(V1) {
					Parser_CurrentModel->Vertice_SetTexCoord_V1(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(U2) {
					Parser_CurrentModel->Vertice_SetTexCoord_U2(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(V2) {
					Parser_CurrentModel->Vertice_SetTexCoord_V2(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(AX) {
					Parser_CurrentModel->Vertice_SetA_X(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(AY) {
					Parser_CurrentModel->Vertice_SetA_Y(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(AZ) {
					Parser_CurrentModel->Vertice_SetA_Z(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(AW) {
					Parser_CurrentModel->Vertice_SetA_W(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(BX) {
					Parser_CurrentModel->Vertice_SetB_X(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(BY) {
					Parser_CurrentModel->Vertice_SetB_Y(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(BZ) {
					Parser_CurrentModel->Vertice_SetB_Z(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(BW) {
					Parser_CurrentModel->Vertice_SetB_W(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(BDX) {
					Parser_CurrentModel->Vertice_SetBoneData_X(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(BDY) {
					Parser_CurrentModel->Vertice_SetBoneData_Y(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(BDZ) {
					Parser_CurrentModel->Vertice_SetBoneData_Z(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else if	PARSER_MATCH(BDW) {
					Parser_CurrentModel->Vertice_SetBoneData_W(PartIndex, TriangleIndex, VerticeIndex, Value);
				} else {
					swprintf_s( MQ->messageBuffer, L"\"%s\" is not a known property in the \"Triangle\" namespace.",PropertyName,Index,Content,Value); MQ->InsertMessage(MQ->messageBuffer);
				}
			} Try_Else {
				swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation was detected while setting a triangle property called \"%s\" using index %i containing the value \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
				return;
			}
		} else if (m_ParserSpace == ParserSpace_Bone) {
			Try_Start {
				if			PARSER_MATCH(Name) {
					Try_Start {
						PARSER_NOINDEX
						Parser_CurrentModel->SetBoneName(Parser_CurrentModel->GetNumberOfBones() - 1,Content);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting a bone name. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ParentIndex) {
					Try_Start {
						Parser_CurrentModel->Bone_SetParentIndex(Parser_CurrentModel->GetNumberOfBones() - 1,(int)Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting parent index. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(Length) {
					Try_Start {
						Parser_CurrentModel->Bone_SetLength(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting length. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ObjectSpaceX) {
					Try_Start {
						Parser_CurrentModel->Bone_SetObjectSpacePosX(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting ObjectSpaceX. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ObjectSpaceY) {
					Try_Start {
						Parser_CurrentModel->Bone_SetObjectSpacePosY(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting ObjectSpaceY. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ObjectSpaceZ) {
					Try_Start {
						Parser_CurrentModel->Bone_SetObjectSpacePosZ(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting ObjectSpaceZ. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ParentSpaceX) {
					Try_Start {
						Parser_CurrentModel->Bone_SetParentSpacePosX(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting ParentSpaceX. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ParentSpaceY) {
					Try_Start {
						Parser_CurrentModel->Bone_SetParentSpacePosY(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting ParentSpaceY. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ParentSpaceZ) {
					Try_Start {
						Parser_CurrentModel->Bone_SetParentSpacePosZ(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting ParentSpaceZ. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(YAxisX) {
					Try_Start {
						Parser_CurrentModel->Bone_SetYAxisX(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting YAxisX. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(YAxisY) {
					Try_Start {
						Parser_CurrentModel->Bone_SetYAxisY(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting YAxisY. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(YAxisZ) {
					Try_Start {
						Parser_CurrentModel->Bone_SetYAxisZ(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting YAxisZ. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ZAxisX) {
					Try_Start {
						Parser_CurrentModel->Bone_SetZAxisX(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting ZAxisX. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ZAxisY) {
					Try_Start {
						Parser_CurrentModel->Bone_SetZAxisY(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting ZAxisY. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ZAxisZ) {
					Try_Start {
						Parser_CurrentModel->Bone_SetZAxisZ(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting ZAxisZ. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(UserDataX) {
					Try_Start {
						Parser_CurrentModel->Bone_SetUserDataX(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting UserDataX. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(UserDataY) {
					Try_Start {
						Parser_CurrentModel->Bone_SetUserDataY(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting UserDataY. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(UserDataZ) {
					Try_Start {
						Parser_CurrentModel->Bone_SetUserDataZ(Parser_CurrentModel->GetNumberOfBones() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting UserDataZ. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else {
					swprintf_s( MQ->messageBuffer, L"\"%s\" is not a known property in the \"Bone\" namespace.\n",PropertyName,Index,Content,Value); MQ->InsertMessage(MQ->messageBuffer);
				}
			} Try_Else {
				swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation was detected while setting a part property called \"%s\" using index %i containing the value \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
				return;
			}
		} else if (m_ParserSpace == ParserSpace_Shape) {
			Try_Start {
				if			PARSER_MATCH(Name) {
					Try_Start {
						PARSER_NOINDEX
						Parser_CurrentModel->SetShapeName(Parser_CurrentModel->GetNumberOfShapes() - 1,Content);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting a shape name. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ShapeType) {
					Try_Start {
						Parser_CurrentModel->Shape_SetShapeType(Parser_CurrentModel->GetNumberOfShapes() - 1,(int)Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting shape type. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(CollisionType) {
					Try_Start {
						Parser_CurrentModel->Shape_SetCollisionType(Parser_CurrentModel->GetNumberOfShapes() - 1,(int)Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting collision type. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(Radius) {
					Try_Start {
						Parser_CurrentModel->Shape_SetRadius(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting radius. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(HalfWidth) {
					Try_Start {
						Parser_CurrentModel->Shape_SetHalfWidth(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting half width. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(HalfHeight) {
					Try_Start {
						Parser_CurrentModel->Shape_SetHalfHeight(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting half height. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(HalfDepth) {
					Try_Start {
						Parser_CurrentModel->Shape_SetHalfDepth(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting half depth. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(PosX) {
					Try_Start {
						Parser_CurrentModel->Shape_SetPosX(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting position x. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(PosY) {
					Try_Start {
						Parser_CurrentModel->Shape_SetPosY(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting position Y. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(PosZ) {
					Try_Start {
						Parser_CurrentModel->Shape_SetPosZ(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting position z. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(XAxisX) {
					Try_Start {
						Parser_CurrentModel->Shape_SetXAxisX(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting x axis x. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(XAxisY) {
					Try_Start {
						Parser_CurrentModel->Shape_SetXAxisY(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting x axis Y. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(XAxisZ) {
					Try_Start {
						Parser_CurrentModel->Shape_SetXAxisZ(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting x axis z. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}				
				} else if	PARSER_MATCH(YAxisX) {
					Try_Start {
						Parser_CurrentModel->Shape_SetYAxisX(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting y axis x. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(YAxisY) {
					Try_Start {
						Parser_CurrentModel->Shape_SetYAxisY(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting y axis Y. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(YAxisZ) {
					Try_Start {
						Parser_CurrentModel->Shape_SetYAxisZ(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting y axis z. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}				
				} else if	PARSER_MATCH(ZAxisX) {
					Try_Start {
						Parser_CurrentModel->Shape_SetZAxisX(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting z axis x. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ZAxisY) {
					Try_Start {
						Parser_CurrentModel->Shape_SetZAxisY(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting z axis Y. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else if	PARSER_MATCH(ZAxisZ) {
					Try_Start {
						Parser_CurrentModel->Shape_SetZAxisZ(Parser_CurrentModel->GetNumberOfShapes() - 1,Value);
					} Try_Else {
						swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation while setting z axis z. Property = \"%s\", index = %i and content = \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
						return;
					}
				} else {
					swprintf_s( MQ->messageBuffer, L"\"%s\" is not a known property in the \"Shape\" namespace.\n",PropertyName,Index,Content,Value); MQ->InsertMessage(MQ->messageBuffer);
				}
			} Try_Else {
				swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation was detected while setting a shape property called \"%s\" using index %i containing the value \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
				return;
			}
		} else if (m_ParserSpace == ParserSpace_Point) {
			Try_Start {
				int ShapeIndex; int PointIndex;
				ShapeIndex = Parser_CurrentModel->GetNumberOfShapes() - 1;
				PointIndex = Parser_CurrentModel->Shape_GetNumberOfPoints(ShapeIndex) - 1;
				if			PARSER_MATCH(X) {
					Parser_CurrentModel->Shape_SetPointX(ShapeIndex,PointIndex,Value);
				} else if	PARSER_MATCH(Y) {
					Parser_CurrentModel->Shape_SetPointY(ShapeIndex,PointIndex,Value);
				} else if	PARSER_MATCH(Z) {
					Parser_CurrentModel->Shape_SetPointZ(ShapeIndex,PointIndex,Value);
				} else if	PARSER_MATCH(DX) {
					Parser_CurrentModel->Shape_SetPointDirX(ShapeIndex,PointIndex,Value);
				} else if	PARSER_MATCH(DY) {
					Parser_CurrentModel->Shape_SetPointDirY(ShapeIndex,PointIndex,Value);
				} else if	PARSER_MATCH(DZ) {
					Parser_CurrentModel->Shape_SetPointDirZ(ShapeIndex,PointIndex,Value);
				} else {
					swprintf_s( MQ->messageBuffer, L"\"%s\" is not a known property in the \"Point\" namespace.\n",PropertyName,Index,Content,Value); MQ->InsertMessage(MQ->messageBuffer);
				}
			} Try_Else {
				swprintf_s( MQ->messageBuffer, L"Parser_SetProperty: Access violation was detected while setting a point property called \"%s\" using index %i containing the value \"%s\".\n",PropertyName,Index,Content); MQ->InsertMessage(MQ->messageBuffer);
				return;
			}
		}
	} Try_Else {
		MQ->InsertMessage(L"Parser_SetProperty: Access violation was detected.");
		return;
	}
}

void EngineCore::Parser_ChangeNamespace(wchar_t* NewNamespace) {
	Try_Start {
		if (CompareStrings_CaseInsensitive(NewNamespace,L"Part")) {
			// Create a new part
			Try_Start {
				Parser_CurrentModel->CreateNewPart(L"",8);
				m_ParserSpace = ParserSpace_Part;
			} Try_Else {
				MQ->InsertMessage(L"Parser_ChangeNamespace: Access violation while creating a part.");
				return;
			}
		} else if (CompareStrings_CaseInsensitive(NewNamespace,L"Bone")) {
			// Create a new bone
			Try_Start {
				Parser_CurrentModel->CreateNewBone(L"");
				m_ParserSpace = ParserSpace_Bone;
			} Try_Else {
				MQ->InsertMessage(L"Parser_ChangeNamespace: Access violation while creating a bone.");
				return;
			}
		} else if (CompareStrings_CaseInsensitive(NewNamespace,L"Triangle")) {
			if (m_ParserSpace == ParserSpace_Part || m_ParserSpace == ParserSpace_Triangle) {
				// Create a new triangle
				Try_Start {
					if (Parser_CurrentModel != NULL) {
						Parser_CurrentModel->InsertTriangleToPart(Parser_CurrentModel->GetNumberOfParts() - 1);
						m_ParserSpace = ParserSpace_Triangle;
					} else {
						MQ->InsertMessage(L"Parser_ChangeNamespace: Parser_CurrentModel was NULL when creating a triangle.");
						return;
					}
				} Try_Else {
					MQ->InsertMessage(L"Parser_ChangeNamespace: Access violation while creating a triangle in a part.");
					return;
				}
			} else {
				swprintf_s( MQ->messageBuffer, L"Triangles must be created as members of a part!"); MQ->InsertMessage(MQ->messageBuffer);
			}
		} else if (CompareStrings_CaseInsensitive(NewNamespace,L"Shape")) {
			Try_Start {
				if (Parser_CurrentModel != NULL) {
					Parser_CurrentModel->CreateNewShape(L"",0);
					m_ParserSpace = ParserSpace_Shape;
				} else {
					MQ->InsertMessage(L"Parser_ChangeNamespace: Parser_CurrentModel was NULL when creating a shape.");
					return;
				}
			} Try_Else {
				MQ->InsertMessage(L"Parser_ChangeNamespace: Access violation while creating a shape.");
				return;
			}
		} else if (CompareStrings_CaseInsensitive(NewNamespace,L"Point")) {
			if (m_ParserSpace == ParserSpace_Shape || m_ParserSpace == ParserSpace_Point) {
				Try_Start {
					if (Parser_CurrentModel != NULL) {
						Parser_CurrentModel->Shape_InsertPointToShape(Parser_CurrentModel->GetNumberOfShapes() - 1,DVector3(0.0f,0.0f,0.0f));
						m_ParserSpace = ParserSpace_Point;
					} else {
						MQ->InsertMessage(L"Parser_ChangeNamespace: Parser_CurrentModel was NULL when creating a point.");
						return;
					}
				} Try_Else {
					MQ->InsertMessage(L"Parser_ChangeNamespace: Access violation while creating a point in a shape.");
					return;
				}
			} else {
				MQ->InsertMessage(L"Points must be created as members of shapes.");
			}
		} else {
			swprintf_s( MQ->messageBuffer, L"Unknown namespace \"%s\"!", NewNamespace); MQ->InsertMessage(MQ->messageBuffer);
		}
	} Try_Else {
		swprintf_s( MQ->messageBuffer,L"Parser_ChangeNamespace: Access violation was detected when cahnging to namespace \"%s\".", NewNamespace); MQ->InsertMessage(MQ->messageBuffer);
		return;
	}
}

void EngineCore::Parser_ReadToken(wchar_t* ModelData, int Start, int End) {
	int i; int j;
	Try_Start {
		if (End >= Start) {
			if (ModelData[Start] == L'(' && ModelData[End] == L')') {
				// Property
				Try_Start {
					if (m_ParserState == ParserState_WaitForProperty || m_ParserState == ParserState_WaitForIndexOrProperty) {
						j = 0;
						LoopForward(Start + 1,i,End - 1) {
							m_Parser_LastPropertyContent[j] = ModelData[i];
							j++;
						}
						m_Parser_LastPropertyContent[j] = L'\0';
						
						Parser_SetProperty(m_Parser_LastPropertyName,m_Parser_LastIndex,m_Parser_LastPropertyContent);
						m_ParserState = ParserState_WaitForStatement;
						m_Parser_LastIndex = 0;
					} else {
						swprintf_s( MQ->messageBuffer, L"Unexpected property!"); MQ->InsertMessage(MQ->messageBuffer);
					}
				} Try_Else {
					MQ->InsertMessage(L"Parser_ReadToken: Access violation while reading property.");
					return;
				}
			} else if (ModelData[Start] == L'[' && ModelData[End] == L']') {
				// Index
				Try_Start {
					if (m_ParserState == ParserState_WaitForIndexOrProperty) {
						m_Parser_LastIndex = (int)ParseDoubleFromPartOfString(ModelData,Start+1,End-1);
					} else {
						MQ->InsertMessage(L"Unexpected index!");
					}
				} Try_Else {
					MQ->InsertMessage(L"Parser_ReadToken: Access violation while reading index.");
					return;
				}
			} else if (ModelData[Start] == L'<' && ModelData[End] == L'>') {
				// Namespace
				Try_Start {
					if (m_ParserState == ParserState_WaitForStatement) {
						if (End - Start > 258) {
							MQ->InsertMessage(L"Name of namespace is too long!");
						} else {
							// Change namespace and create things
							j = 0;
							LoopForward(Start + 1,i,End - 1) {
								m_Parser_LastNameSpace[j] = ModelData[i];
								j++;
							}
							m_Parser_LastNameSpace[j] = L'\0';
							
							Parser_ChangeNamespace(m_Parser_LastNameSpace);
						}
					} else {
						MQ->InsertMessage(L"Change of namespace before finishing the last statement!");
					}
				} Try_Else {
					MQ->InsertMessage(L"Parser_ReadToken: Access violation while reading namespace.");
					return;
				}
			} else {
				// Identifier
				Try_Start {
					if (m_ParserState == ParserState_WaitForStatement) {
						// Global property
						if (End - Start > 258) {
							MQ->InsertMessage(L"Name of property is too long!");
						} else {
							j = 0;
							LoopForward(Start,i,End) {
								m_Parser_LastPropertyName[j] = ModelData[i];
								j++;
							}
							m_Parser_LastPropertyName[j] = L'\0';
							
							m_ParserState = ParserState_WaitForIndexOrProperty;
						}
					}
				} Try_Else {
					MQ->InsertMessage(L"Parser_ReadToken: Access violation while reading identifier.");
					return;
				}
			}
		}
	} Try_Else {
		MQ->InsertMessage(L"Parser_ReadToken: Access violation was detected.");
		return;
	}
}

void EngineCore::Parser_AddModelDataFromString(ModelClass* CurrentModel, wchar_t* ModelData, wchar_t* ModelName) {
	int length;
	int memoryPos; // Everything before this will no longer be used
	int scanPos; // This is the current scanning position that reads from the string
	wchar_t curChar;
	wchar_t startingChar;
	Try_Start {
		length = lengthOfString_wide(ModelData);
	} Try_Else {
		swprintf_s( MQ->messageBuffer, L"Parser_AddModelDataFromString: The model \"%s\" could not be parsed because of access violation while getting the length of the file content.", ModelName); MQ->InsertMessage(MQ->messageBuffer);
		return;
	}
	startingChar = L'\0';
	if (ModelData == NULL) {
		MQ->InsertMessage(L"Parser_AddModelDataFromString: ModelData == NULL");
		return;
	}
	if (ModelName == NULL) {
		MQ->InsertMessage(L"Parser_AddModelDataFromString: ModelName == NULL");
		return;
	}
	
	// Get the path from the filename so that resources can be loaded from it.
	Try_Start {
		CopyToFixedSizePath(ModelName,m_Parser_ModelPath); OnlyPath(m_Parser_ModelPath);
	} Try_Else {
		swprintf_s( MQ->messageBuffer, L"Model_LoadFromFile_InSB: The model \"%s\" could not be parsed because of access violation while getting the path from the filename.", ModelName); MQ->InsertMessage(MQ->messageBuffer);
		return;
	}
	
	// Tell what model to modify
	Parser_CurrentModel = CurrentModel;
	
	// Initialize the state machine
	m_ParserState = ParserState_WaitForStatement;
	m_ParserSpace = ParserSpace_Main;
	m_Parser_LastIndex = 0;
	
	if (length < 4) {
		MQ->InsertMessage(L"Parser_AddModelDataFromString: The file can't contain the name of the file format because it's too short.");
		return;
	}
	
	Try_Start {
		if (ModelData[0] != L'D' || ModelData[1] != L'M' || ModelData[2] != L'F' || ModelData[3] != L'1') {
			MQ->InsertMessage(L"Parser_AddModelDataFromString: The file does not start with \"DMF1\".");
			return;
		}
	} Try_Else {
		swprintf_s( MQ->messageBuffer, L"Parser_AddModelDataFromString: The model \"%s\" could not be parsed because of access violation while getting the byte order mark.", ModelName); MQ->InsertMessage(MQ->messageBuffer);
		return;
	}
	memoryPos = 4;
	scanPos = 4;
	
	// Scan the string and send tokens to the state machine
	Try_Start {
		LoopForward(0,scanPos,length-1) {
			curChar = ModelData[scanPos];
			if (startingChar == L'\0' && (curChar == Asci_Indent || curChar == Asci_Space || curChar == Asci_LineFeed || curChar == Asci_CarriageReturn)) {
				// Finish the current token and don't save this character
				Parser_ReadToken(ModelData,memoryPos,scanPos-1);
				memoryPos = scanPos + 1;
			} else if (curChar == L'<' || curChar == L'(' || curChar == L'[') {
				// Finish the last token and save this character
				Parser_ReadToken(ModelData,memoryPos,scanPos-1);
				memoryPos = scanPos;
				startingChar = curChar;
			} else if (startingChar == L'<' && curChar == L'>') {
				// Use this token
				Parser_ReadToken(ModelData,memoryPos,scanPos);
				memoryPos = scanPos + 1;
				startingChar = L'\0';
			} else if (startingChar == L'(' && curChar == L')') {
				// Use this token
				Parser_ReadToken(ModelData,memoryPos,scanPos);
				memoryPos = scanPos + 1;
				startingChar = L'\0';
			} else if (startingChar == L'[' && curChar == L']') {
				// Use this token
				Parser_ReadToken(ModelData,memoryPos,scanPos);
				memoryPos = scanPos + 1;
				startingChar = L'\0';
			}
		}
		Parser_ReadToken(ModelData,memoryPos,scanPos-1);
	} Try_Else {
		swprintf_s( MQ->messageBuffer, L"Parser_AddModelDataFromString: The model \"%s\" could not be parsed because of access violation while tokenizing.", ModelName); MQ->InsertMessage(MQ->messageBuffer);
		return;
	}
	if (m_ParserState != ParserState_WaitForStatement) {
		swprintf_s( MQ->messageBuffer, L"The last statement in the model \"%s\" was not finished.",ModelName); MQ->InsertMessage(MQ->messageBuffer);
	}
}

#define FeedTextToGeneratorString(CODE) \
	m_preCalculatedLength = 0; \
	writeIndex = 0; \
	GeneratorString = NULL; \
	counting = true; \
	CODE \
	GeneratorString = new char[m_preCalculatedLength + 1]; \
	if (GeneratorString == NULL) { \
		MQ->InsertMessage(L"FeedTextToGeneratorString: Allocation error while allocating a new string.\n"); \
	} \
	counting = false; \
	CODE \
	GeneratorString[m_preCalculatedLength] = '\0';
#define FEEDSTRING(MESSAGE) FeedString(counting,MESSAGE);
#define FEEDWIDESTRING(MESSAGE) FeedString_wide(counting,MESSAGE);
#define NEWLINE FEEDSTRING("\n")
#define FEEDINTEGER(INTEGER) sprintf_s( NumberString, "%i",INTEGER); FEEDSTRING(NumberString);
#define FEEDFLOAT(FLOAT) sprintf_s( NumberString, "%f",FLOAT); SimplifyFloatInString(NumberString); FEEDSTRING(NumberString)
#define FEEDAS(NAME,INDEX,VAR) FEEDSTRING(NAME) FEEDSTRING("[") FEEDINTEGER(INDEX) FEEDSTRING("](") FEEDFLOAT(VAR) FEEDSTRING(")")

void EngineCore::FeedString(bool counting,char* Text) {
	int i;
	if (counting) {
		m_preCalculatedLength = m_preCalculatedLength + lengthOfString(Text);
	} else {
		i = 0;
		while (Text[i] != 0) {
			GeneratorString[writeIndex] = Text[i]; writeIndex++;
			i++;
		}
	}
}

void EngineCore::FeedString_wide(bool counting,wchar_t* Text) {
	int i;
	if (counting) {
		m_preCalculatedLength = m_preCalculatedLength + lengthOfString_wide(Text);
	} else {
		i = 0;
		while (Text[i] != 0) {
			GeneratorString[writeIndex] = (char)(Text[i]); writeIndex++;
			i++;
		}
	}
}

char* EngineCore::Generator_WriteModelDataToString(Model_Struct* pModel) {
	int I; int I2; int I3; int Channel; Texture_Struct* Tex; Shader_Struct* Sha; int TexO; int TempInt; DVector3 V3; DVector4 V4;
	FeedTextToGeneratorString(
		FEEDSTRING("DMF1") NEWLINE
		FEEDSTRING("FilterType(") FEEDWIDESTRING(pModel->Model.GetFilterName()) FEEDSTRING(")") NEWLINE
		FEEDSTRING("CullingType(") FEEDWIDESTRING(pModel->Model.GetCullingName()) FEEDSTRING(")") NEWLINE
		if (pModel->Model.ModelProperties.BoundMultiplier < 0.9999999 || pModel->Model.ModelProperties.BoundMultiplier > 1.0000001) {
			FEEDSTRING("BoundMultiplier(") FEEDFLOAT(pModel->Model.ModelProperties.BoundMultiplier) FEEDSTRING(")") NEWLINE
		}
		
		LoopForwardLengthFromZero(I,pModel->Model.GetNumberOfBones()) {
			FEEDSTRING("<Bone> Name(") FEEDWIDESTRING(pModel->Model.GetBoneName(I)) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	Length") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetLength(I)) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	ObjectSpaceX") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetObjectSpacePos(I).x) FEEDSTRING(")")
			FEEDSTRING(" ObjectSpaceY") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetObjectSpacePos(I).y) FEEDSTRING(")")
			FEEDSTRING(" ObjectSpaceZ") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetObjectSpacePos(I).z) FEEDSTRING(")") NEWLINE
			TempInt = pModel->Model.Bone_GetParentIndex(I);
			if (TempInt != -1) {
				FEEDSTRING("	ParentIndex") FEEDSTRING("(") FEEDINTEGER(TempInt) FEEDSTRING(")") NEWLINE
				FEEDSTRING("	ParentSpaceX") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetParentSpacePos(I).x) FEEDSTRING(")")
				FEEDSTRING(" ParentSpaceY") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetParentSpacePos(I).y) FEEDSTRING(")")
				FEEDSTRING(" ParentSpaceZ") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetParentSpacePos(I).z) FEEDSTRING(")") NEWLINE
			}
			FEEDSTRING("	YAxisX") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetYAxis(I).x) FEEDSTRING(")")
			FEEDSTRING(" YAxisY") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetYAxis(I).y) FEEDSTRING(")")
			FEEDSTRING(" YAxisZ") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetYAxis(I).z) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	ZAxisX") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetZAxis(I).x) FEEDSTRING(")")
			FEEDSTRING(" ZAxisY") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetZAxis(I).y) FEEDSTRING(")")
			FEEDSTRING(" ZAxisZ") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetZAxis(I).z) FEEDSTRING(")") NEWLINE
			if (pModel->Model.Bone_GetUserData(I).x < -0.0000001 || pModel->Model.Bone_GetUserData(I).x > 0.0000001) {
				FEEDSTRING("	UserDataX") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetUserData(I).x) FEEDSTRING(")") NEWLINE
			}
			if (pModel->Model.Bone_GetUserData(I).y < -0.0000001 || pModel->Model.Bone_GetUserData(I).y > 0.0000001) {
				FEEDSTRING("	UserDataY") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetUserData(I).y) FEEDSTRING(")") NEWLINE
			}
			if (pModel->Model.Bone_GetUserData(I).z < -0.0000001 || pModel->Model.Bone_GetUserData(I).z > 0.0000001) {
				FEEDSTRING("	UserDataZ") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Bone_GetUserData(I).z) FEEDSTRING(")") NEWLINE
			}
		}
		
		LoopForwardLengthFromZero(I,pModel->Model.GetNumberOfShapes()) {
			FEEDSTRING("<Shape> Name(") FEEDWIDESTRING(pModel->Model.GetShapeName(I)) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	ShapeType") FEEDSTRING("(") FEEDINTEGER(pModel->Model.Shape_GetShapeType(I)) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	CollisionType") FEEDSTRING("(") FEEDINTEGER(pModel->Model.Shape_GetCollisionType(I)) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	Radius") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetRadius(I)) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	HalfWidth") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetHalfWidth(I)) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	HalfHeight") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetHalfHeight(I)) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	HalfDepth") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetHalfDepth(I)) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	PosX") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetPos(I).x) FEEDSTRING(")")
			FEEDSTRING(" PosY") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetPos(I).y) FEEDSTRING(")")
			FEEDSTRING(" PosZ") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetPos(I).z) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	XAxisX") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetXAxis(I).x) FEEDSTRING(")")
			FEEDSTRING(" XAxisY") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetXAxis(I).y) FEEDSTRING(")")
			FEEDSTRING(" XAxisZ") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetXAxis(I).z) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	YAxisX") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetYAxis(I).x) FEEDSTRING(")")
			FEEDSTRING(" YAxisY") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetYAxis(I).y) FEEDSTRING(")")
			FEEDSTRING(" YAxisZ") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetYAxis(I).z) FEEDSTRING(")") NEWLINE
			FEEDSTRING("	ZAxisX") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetZAxis(I).x) FEEDSTRING(")")
			FEEDSTRING(" ZAxisY") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetZAxis(I).y) FEEDSTRING(")")
			FEEDSTRING(" ZAxisZ") FEEDSTRING("(") FEEDFLOAT(pModel->Model.Shape_GetZAxis(I).z) FEEDSTRING(")") NEWLINE
			LoopForwardLengthFromZero(I2,pModel->Model.Shape_GetNumberOfPoints(I)) {
				FEEDSTRING("	<Point>")
				V3 = pModel->Model.Shape_GetPoint(I,I2);
				FEEDSTRING(" X") FEEDSTRING("(") FEEDFLOAT(V3.x) FEEDSTRING(")")
				FEEDSTRING(" Y") FEEDSTRING("(") FEEDFLOAT(V3.y) FEEDSTRING(")")
				FEEDSTRING(" Z") FEEDSTRING("(") FEEDFLOAT(V3.z) FEEDSTRING(")")
				V3 = pModel->Model.Shape_GetPointDir(I,I2);
				if (V3.x > 0.0000001f || V3.x < -0.0000001f || V3.y > 0.0000001f || V3.y < -0.0000001f || V3.z > 0.0000001f || V3.z < -0.0000001f) {
					FEEDSTRING(" DX") FEEDSTRING("(") FEEDFLOAT(V3.x) FEEDSTRING(")")
					FEEDSTRING(" DY") FEEDSTRING("(") FEEDFLOAT(V3.y) FEEDSTRING(")")
					FEEDSTRING(" DZ") FEEDSTRING("(") FEEDFLOAT(V3.z) FEEDSTRING(")")
				}
				NEWLINE
			}
		}

		LoopForwardLengthFromZero(I,pModel->Model.GetNumberOfParts()) {
			FEEDSTRING("<Part> Name(") FEEDWIDESTRING(pModel->Model.GetPartName(I)) FEEDSTRING(")") NEWLINE
			LoopForward(0,Channel,NumberOfShaderChannels - 1) {
				Sha = pModel->Model.GetPartShader(I,Channel);
				if (Sha != NULL) {
					FEEDSTRING("	Shader[") FEEDINTEGER(Channel) FEEDSTRING("](") FEEDWIDESTRING(Sha->FileName) FEEDSTRING(")") NEWLINE
				}
			}
			LoopForward(0,Channel,NumberOfTextureChannels - 1) {
				Tex = pModel->Model.GetPartTexture(I,Channel);
				if (Tex != NULL) {
					FEEDSTRING("	Texture[") FEEDINTEGER(Channel) FEEDSTRING("](") FEEDWIDESTRING(Tex->FileName) FEEDSTRING(")") NEWLINE
				}
				TexO = pModel->Model.GetPartTextureOverride(I,Channel);
				if (TexO != -1) {
					FEEDSTRING("	TextureOverride[") FEEDINTEGER(Channel) FEEDSTRING("](") FEEDINTEGER(TexO) FEEDSTRING(")") NEWLINE
				}
			}
			TempInt = pModel->Model.GetPartMinDetailLevel(I);
			if (TempInt != 0) {
				FEEDSTRING("	MinDetailLevel") FEEDSTRING("(") FEEDINTEGER(TempInt) FEEDSTRING(")") NEWLINE
			}
			TempInt = pModel->Model.GetPartMaxDetailLevel(I);
			if (TempInt != 2) {
				FEEDSTRING("	MaxDetailLevel") FEEDSTRING("(") FEEDINTEGER(TempInt) FEEDSTRING(")") NEWLINE
			}
			LoopForwardLengthFromZero(I2,pModel->Model.GetTriangleCountFromPart(I)) {
				FEEDSTRING("	<Triangle>") NEWLINE
				LoopForward(0,I3,2) {
					V3 = pModel->Model.Vertice_GetPos(I,I2,I3);
					FEEDAS("		X",I3,V3.x)
					FEEDAS(" Y",I3,V3.y)
					FEEDAS(" Z",I3,V3.z)
					V3 = pModel->Model.Vertice_GetNormal(I,I2,I3);
					if (V3.x > 0.0000001f || V3.x < -0.0000001f || V3.y > 0.0000001f || V3.y < -0.0000001f || V3.z > 0.0000001f || V3.z < -0.0000001f) {
						FEEDAS(" NX",I3,V3.x)
						FEEDAS(" NY",I3,V3.y)
						FEEDAS(" NZ",I3,V3.z)
					}
					V4 = pModel->Model.Vertice_GetTexCoord(I,I2,I3);
					if (V4.x > 0.0000001f || V4.x < -0.0000001f || V4.y > 0.0000001f || V4.y < -0.0000001f) {
						FEEDAS(" U1",I3,V4.x)
						FEEDAS(" V1",I3,V4.y)
					}
					if (V4.z > 0.0000001f || V4.z < -0.0000001f || V4.w > 0.0000001f || V4.w < -0.0000001f) {
						FEEDAS(" U2",I3,V4.z)
						FEEDAS(" V2",I3,V4.w)
					}
					V4 = pModel->Model.Vertice_GetColor(I,I2,I3);
					if (V4.x > 1.0000001f || V4.x < 0.9999999f || V4.y > 1.0000001f || V4.y < 0.9999999f || V4.z > 1.0000001f || V4.z < 0.9999999f || V4.w > 1.0000001f || V4.w < 0.9999999f) {
						FEEDAS(" CR",I3,V4.x)
						FEEDAS(" CG",I3,V4.y)
						FEEDAS(" CB",I3,V4.z)
						FEEDAS(" CA",I3,V4.w)
					}
					V4 = pModel->Model.Vertice_GetA(I,I2,I3);
					if (V4.x > 0.0000001f || V4.x < -0.0000001f || V4.y > 0.0000001f || V4.y < -0.0000001f || V4.z > 0.0000001f || V4.z < -0.0000001f || V4.w > 0.0000001f || V4.w < -0.0000001f) {
						FEEDAS(" AX",I3,V4.x)
						FEEDAS(" AY",I3,V4.y)
						FEEDAS(" AZ",I3,V4.z)
						FEEDAS(" AW",I3,V4.w)
					}
					V4 = pModel->Model.Vertice_GetB(I,I2,I3);
					if (V4.x > 0.0000001f || V4.x < -0.0000001f || V4.y > 0.0000001f || V4.y < -0.0000001f || V4.z > 0.0000001f || V4.z < -0.0000001f || V4.w > 0.0000001f || V4.w < -0.0000001f) {
						FEEDAS(" BX",I3,V4.x)
						FEEDAS(" BY",I3,V4.y)
						FEEDAS(" BZ",I3,V4.z)
						FEEDAS(" BW",I3,V4.w)
					}
					V4 = pModel->Model.Vertice_GetBoneData(I,I2,I3);
					if (V4.x > 0.0000001f || V4.x < -0.0000001f || V4.y > 0.0000001f || V4.y < -0.0000001f || V4.z > 0.0000001f || V4.z < -0.0000001f || V4.w > -0.9999999f || V4.w < -1.0000001f) {
						FEEDAS(" BDX",I3,V4.x)
						FEEDAS(" BDY",I3,V4.y)
						FEEDAS(" BDZ",I3,V4.z)
						FEEDAS(" BDW",I3,V4.w)
					}
					NEWLINE
				}
			}
		}
	)
	return GeneratorString;
}

Model_Struct* EngineCore::Model_DuplicateModel(Model_Struct* pSrcModel) {
	Model_Struct* pDestModel;
	pDestModel = CreateEmptyModel();
	Model_DuplicateModelContent(pDestModel, pSrcModel,true);
	return pDestModel;
}

void EngineCore::Model_CopyAllParts(Model_Struct* pSrcModel, Model_Struct* pDestModel) {
	Model_DuplicateModelContent(pDestModel, pSrcModel,false);
}

void EngineCore::Model_DuplicateModelContent(Model_Struct* pDstModel, Model_Struct* pSrcModel, bool ReplaceGlobalData) {
	int Part; int NewPart;
	int Bone; int NewBone;
	int Shape; int NewShape; int Point;
	
	// Copy global model data
	if (ReplaceGlobalData) {
		pDstModel->Model.ModelProperties = pSrcModel->Model.ModelProperties;
	}
	
	// Duplicate parts
	LoopForwardLengthFromZero(Part,pSrcModel->Model.GetNumberOfParts()) {
		// Create part and duplicate name
		NewPart = pDstModel->Model.CreateNewPart(pSrcModel->Model.GetPartName(Part),pSrcModel->Model.GetTriangleCountFromPart(Part));
		
		// Duplicate part content
		Model_DuplicatePartContent(pDstModel,NewPart,pSrcModel,Part,true);
	}
	
	// Duplicate bones
	LoopForwardLengthFromZero(Bone,pSrcModel->Model.GetNumberOfBones()) {
		// Create a bone and duplicate the properties
		NewBone = pDstModel->Model.CreateNewBone(pSrcModel->Model.GetBoneName(Bone));
		pDstModel->Model.Bone_SetLength(NewBone,pSrcModel->Model.Bone_GetLength(Bone));
		pDstModel->Model.Bone_SetYAxis(NewBone,pSrcModel->Model.Bone_GetYAxis(Bone));
		pDstModel->Model.Bone_SetZAxis(NewBone,pSrcModel->Model.Bone_GetZAxis(Bone));
		pDstModel->Model.Bone_SetObjectSpacePos(NewBone,pSrcModel->Model.Bone_GetObjectSpacePos(Bone));
		pDstModel->Model.Bone_SetParentIndex(NewBone,pSrcModel->Model.Bone_GetParentIndex(Bone));
		pDstModel->Model.Bone_SetParentSpacePos(NewBone,pSrcModel->Model.Bone_GetParentSpacePos(Bone));
	}

	// Duplicate shapes
	LoopForwardLengthFromZero(Shape,pSrcModel->Model.GetNumberOfShapes()) {
		// Create a shape
		NewShape = pDstModel->Model.CreateNewShape(pSrcModel->Model.GetShapeName(Shape),pSrcModel->Model.Shape_GetShapeType(Shape));
		
		// Duplicate shape properties
		pDstModel->Model.Shape_SetCollisionType(NewShape,pSrcModel->Model.Shape_GetCollisionType(Shape));
		pDstModel->Model.Shape_SetPos(NewShape,pSrcModel->Model.Shape_GetPos(Shape));
		pDstModel->Model.Shape_SetXAxis(NewShape,pSrcModel->Model.Shape_GetXAxis(Shape));
		pDstModel->Model.Shape_SetYAxis(NewShape,pSrcModel->Model.Shape_GetYAxis(Shape));
		pDstModel->Model.Shape_SetZAxis(NewShape,pSrcModel->Model.Shape_GetZAxis(Shape));
		pDstModel->Model.Shape_SetRadius(NewShape,pSrcModel->Model.Shape_GetRadius(Shape));
		pDstModel->Model.Shape_SetHalfWidth(NewShape,pSrcModel->Model.Shape_GetHalfWidth(Shape));
		pDstModel->Model.Shape_SetHalfHeight(NewShape,pSrcModel->Model.Shape_GetHalfHeight(Shape));
		pDstModel->Model.Shape_SetHalfDepth(NewShape,pSrcModel->Model.Shape_GetHalfDepth(Shape));

		// Duplicate shape points
		LoopForwardLengthFromZero(Point,pSrcModel->Model.Shape_GetNumberOfPoints(Shape)) {
			pDstModel->Model.Shape_InsertPointToShape(NewShape,pSrcModel->Model.Shape_GetPoint(Shape,Point));
		}
	}
}

void EngineCore::Model_DuplicatePartContent(Model_Struct* pDstModel, int DstPart, Model_Struct* pSrcModel, int SrcPart, bool ReplaceGlobalData) {
	int NumberOfTri; int Tri;
	int Channel;
	
	// Copy global part data
	if (ReplaceGlobalData) {
		// Copy part textures and override
		LoopForwardLengthFromZero(Channel,NumberOfTextureChannels) {
			pDstModel->Model.SetPartTexture(DstPart,Channel, pSrcModel->Model.GetPartTexture(SrcPart,Channel));
			pDstModel->Model.SetPartTextureOverride(DstPart,Channel,pSrcModel->Model.GetPartTextureOverride(SrcPart,Channel));
		}
		
		// Copy part shader
		LoopForwardLengthFromZero(Channel,NumberOfShaderChannels) {
			pDstModel->Model.SetPartShader(DstPart,Channel, pSrcModel->Model.GetPartShader(SrcPart,Channel));
		}
	}
	
	// Copy multiresolution interval
	pDstModel->Model.SetPartMinDetailLevel(DstPart, pSrcModel->Model.GetPartMinDetailLevel(SrcPart));
	pDstModel->Model.SetPartMaxDetailLevel(DstPart, pSrcModel->Model.GetPartMaxDetailLevel(SrcPart));
	
	// Copy triangles
	NumberOfTri = pSrcModel->Model.GetTriangleCountFromPart(SrcPart);
	LoopForwardLengthFromZero(Tri,NumberOfTri) {
		Model_DuplicateTriangle(pDstModel,DstPart,pSrcModel,SrcPart, Tri);
	}
}

int EngineCore::Model_DuplicateTriangle(Model_Struct* pDstModel, int DstPart, Model_Struct* pSrcModel, int SrcPart, int SrcTri) {
	int Vert; int NewTri;
	NewTri = pDstModel->Model.InsertTriangleToPart(DstPart);
	LoopForward(0,Vert,2) {
		pDstModel->Model.Vertice_SetAll( DstPart,NewTri,Vert,pSrcModel->Model.Vertice_GetAll( SrcPart,SrcTri,Vert));
	}
	return NewTri;
}
