
// 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.

#include "../stdafx.h"
#include "Model.h"
#include "../MessageQueue.h"

#define InitialNumberOfParts 8

#define CheckTextureChannelBound(ROUTINE,CHANNEL) \
	if (CHANNEL < 0 || CHANNEL >= NumberOfTextureChannels) { \
		swprintf_s( MQ->messageBuffer, L"%s: Texture channel %i is out of bound. Use [0..%i].",ROUTINE,CHANNEL,NumberOfTextureChannels - 1); MQ->InsertMessage(MQ->messageBuffer); \
	} else

#define CheckShaderChannelBound(ROUTINE,CHANNEL) \
	if (CHANNEL < 0 || CHANNEL >= NumberOfShaderChannels) { \
		swprintf_s( MQ->messageBuffer, L"%s: Shader channel %i is out of bound. Use [0..%i].",ROUTINE,CHANNEL,NumberOfShaderChannels - 1); MQ->InsertMessage(MQ->messageBuffer); \
	} else

#define CheckPartIndex(ROUTINE,INDEX) \
	if (INDEX < 0 || INDEX > NumberOfParts - 1) { \
		swprintf_s( MQ->messageBuffer, L"%s: Part index %i is out of bound. Use [0..%i].",ROUTINE,INDEX,NumberOfParts - 1); MQ->InsertMessage(MQ->messageBuffer); \
	} else

#define CheckBoneIndex(ROUTINE,INDEX) \
	if (INDEX < 0 || INDEX > NumberOfBones - 1) { \
		swprintf_s( MQ->messageBuffer, L"%s: Bone index %i is out of bound. Use [0..%i].",ROUTINE,INDEX,NumberOfParts - 1); MQ->InsertMessage(MQ->messageBuffer); \
	} else

#define CheckShapeIndex(ROUTINE,INDEX) \
	if (INDEX < 0 || INDEX > NumberOfShapes - 1) { \
		swprintf_s( MQ->messageBuffer, L"%s: Shape index %i is out of bound. Use [0..%i].",ROUTINE,INDEX,NumberOfShapes - 1); MQ->InsertMessage(MQ->messageBuffer); \
	} else

#define CheckPointIndex(ROUTINE,SHAPE,INDEX) \
	if (INDEX < 0 || INDEX > Shapes[SHAPE].NumberOfPoints - 1) { \
		swprintf_s( MQ->messageBuffer, L"%s: Point index %i is out of bound. The shape called %s have points in the range [0..%i].",ROUTINE,INDEX,Shapes[SHAPE].ShapeName,Shapes[SHAPE].NumberOfPoints - 1); MQ->InsertMessage(MQ->messageBuffer); \
	} else

#define CheckTriangleIndex(ROUTINE,PART,INDEX) \
	if (INDEX < 0 || INDEX > (Parts[PART].UsedVertices / 3) - 1) { \
		swprintf_s( MQ->messageBuffer, L"%s: Triangle index %i is out of bound. The part called %s have triangles in the range [0..%i].",ROUTINE,INDEX,Parts[PART].PartName,(Parts[PART].UsedVertices / 3) - 1); MQ->InsertMessage(MQ->messageBuffer); \
	} else

#define CheckVertexIndex(ROUTINE,INDEX) \
	if (INDEX < 0 || INDEX > 2) { \
		swprintf_s( MQ->messageBuffer, L"%s: Vertex index %i is out of bound. Use [0..2] for the three vertices in a triangle.",ROUTINE,INDEX); MQ->InsertMessage(MQ->messageBuffer); \
	} else

#define CheckPTV(ROUTINE,CODE) CheckPartIndex(ROUTINE,PartIndex){CheckTriangleIndex(ROUTINE,PartIndex,TriangleIndex){CheckVertexIndex(ROUTINE,VerticeIndex){CODE}}}
#define VerticeFromPTV Parts[PartIndex].VertexBuffer[(TriangleIndex * 3) + VerticeIndex]
#define NumberOfTriangles(PART) (Parts[PART].UsedVertices / 3)

#define ForAllParts(var) LoopForward(0,var,NumberOfParts-1)
#define ForAllVerticesInPart(var,part) LoopForward(0,var,Parts[part].UsedVertices-1)
#define ForAllBones(var) LoopForward(0,var,NumberOfBones-1)
#define ForAllShapes(var) LoopForward(0,var,NumberOfShapes-1)

// Trap access violation
int ModelClass::Filter_Model(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
#ifdef _DEBUG
	return EXCEPTION_CONTINUE_SEARCH;
#else
	if (code == EXCEPTION_ACCESS_VIOLATION) {
		return EXCEPTION_EXECUTE_HANDLER;
	} else {
		return EXCEPTION_CONTINUE_SEARCH;
	};
#endif
}

// Class lifetime

void ModelClass::Init(ID3D11Device* new_pd3dDevice, ID3D11DeviceContext* new_pImmediateContext, MessageQueue* new_MQ) {
	// Initiate
	MQ = new_MQ;
	ModelProperties.FilterType = Filter_None;
	ModelProperties.CullingMethod = Culling_AABB;
	ModelProperties.BoundMultiplier = 1.0f;
	ModelProperties.NeedNewBounds = false;
	ModelProperties.NeedAnyUpdate = false;
	VertexStructureSize = sizeof( VertexStructure );
	NoOffset = 0;
	
	NumberOfParts = 0;
	AllocateParts(InitialNumberOfParts);
	
	NumberOfShapes = 0;
	Shapes = NULL;

	NumberOfBones = 0;
	Bones = NULL;
	
	OldBuffer = NULL;
	m_pd3dDevice = new_pd3dDevice;
	m_pImmediateContext = new_pImmediateContext;
	ObjectSpaceMin = DVector3(0.0f, 0.0f, 0.0f);
	ObjectSpaceMax = DVector3(0.0f, 0.0f, 0.0f);
	ObjectSpaceCenter = DVector3(0.0f, 0.0f, 0.0f);
	Radius = 0;
	ModelProperties.FileName[0] = L'\0';
}

void ModelClass::Terminate() {
	DeallocateCollections();
}

// Part collection helper methods

void ModelClass::AllocateParts(int newSize) {
	AllocatedParts = newSize;
	Parts = new Part_Type[AllocatedParts];
	if (Parts == NULL) {
		MQ->InsertMessage(L"ModelClass::AllocateParts: Allocation error while allocating a new part list.\n");
	}
}

void ModelClass::ReallocateParts(int newSize) {
	int i;
	Part_Type* SwapArray;
	int oldSize;
	Try_Start_Model {
		oldSize = AllocatedParts;
		AllocatedParts = newSize;
		SwapArray = Parts;
		Try_Start_Model {
			Parts = new Part_Type[AllocatedParts];
			if (Parts == NULL) {
				MQ->InsertMessage(L"ModelClass::ReallocateParts: Allocation error while allocating a new part list.\n");
			}
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::ReallocateParts: Access violation while allocating a new part list.\n");
			return;
		}
		// Preserve
		Try_Start_Model {
			LoopForwardLengthFromZero(i, AllocatedParts) {
				if (i < oldSize) {
					Parts[i] = SwapArray[i];
				}
			}
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::ReallocateParts: Access violation while filling new part list with old data.\n");
			return;
		}
		Try_Start_Model {
			SAFE_DELETE_ARRAY(SwapArray)
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::ReallocateParts: Access violation while deleting the old part list.\n");
			return;
		}
		SwapArray = NULL;
	} Try_Else_Model {
		MQ->InsertMessage(L"ModelClass::ReallocateParts: Access violation in the outer layer.\n");
		return;
	}
}

void ModelClass::DeallocateCollections(void) {
	int I;
	ForAllBones(I) {
		ReleaseBone(I);
	}
	NumberOfBones = 0;
	Try_Start_Model {
		SAFE_DELETE_ARRAY(Bones)
	} Try_Else_Model {
		MQ->InsertMessage(L"ModelClass::DeallocateCollections: Access violation while deleting the bone collection.\n");
	}
	ForAllParts(I) {
		ReleasePart(I);
	}
	AllocatedParts = 0;
	Try_Start_Model {
		SAFE_DELETE_ARRAY(Parts)
	} Try_Else_Model {
		MQ->InsertMessage(L"ModelClass::DeallocateCollections: Access violation while deleting the part collection.\n");
	}
}

void ModelClass::SetPartSizeAux2(int PartIndex, int newSize) {
	Parts[PartIndex].VertexBuffer = new VertexStructure[newSize];
	if (Parts[PartIndex].VertexBuffer == NULL) {
		MQ->InsertMessage(L"ModelClass::SetPartSizeAux2: Allocation error while allocating a new vertex buffer.\n");
		return;
	}
}
void ModelClass::SetPartSizeAux(int PartIndex, int newSize) {
	int oldSize;
	int i;
	if (newSize < 1) {
		MQ->InsertMessage(L"ModelClass::SetPartSizeAux: newSize < 1.\n");
		return;
	}
	CheckPartIndex(L"SetPartSize",PartIndex)
	Try_Start_Model {
		Try_Start_Model {
			OldBuffer = Parts[PartIndex].VertexBuffer;
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::SetPartSizeAux: Access violation while getting the old buffer.\n");
			return;
		}
		Try_Start_Model {
			oldSize = Parts[PartIndex].AllocatedVertices;
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::SetPartSizeAux: Access violation while getting the old size.\n");
			return;
		}
		Try_Start_Model {
			Parts[PartIndex].AllocatedVertices = newSize;
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::SetPartSizeAux: Access violation while assigning the new size.\n");
			return;
		}
		Try_Start_Model {
			SetPartSizeAux2(PartIndex,newSize);
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::SetPartSizeAux: Access violation while allocating a new vertex buffer.\n");
			return;
		}
		Try_Start_Model {
		if (Parts[PartIndex].VertexBuffer != NULL && OldBuffer != NULL && newSize != oldSize) {
			if (newSize > oldSize) {
				Try_Start_Model {
					LoopForwardLengthFromZero(i,oldSize) {
						Parts[PartIndex].VertexBuffer[i] = OldBuffer[i];
					}
				} Try_Else_Model {
					MQ->InsertMessage(L"ModelClass::SetPartSizeAux: Access violation while getting old data to a larger new vertex buffer.\n");
					return;
				}
			} else {
				Try_Start_Model {
					LoopForwardLengthFromZero(i,newSize) {
						Parts[PartIndex].VertexBuffer[i] = OldBuffer[i];
					}
				} Try_Else_Model {
					MQ->InsertMessage(L"ModelClass::SetPartSizeAux: Access violation while getting old data to a smaller new vertex buffer.\n");
					return;
				}
			}
		}
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::SetPartSizeAux: Access violation while checking if the vertex buffer is NULL.\n");
			return;
		}
	} Try_Else_Model {
		MQ->InsertMessage(L"ModelClass::SetPartSizeAux: Access violation in the outer layer.\n");
		return;
	}
}
void ModelClass::SetPartSize(int PartIndex, int newSize) {
	OldBuffer = NULL;
	SetPartSizeAux(PartIndex,newSize);
	SAFE_DELETE_ARRAY(OldBuffer)
}

// Part methods

void ModelClass::UpdatePartsGeometry( int PartIndex ) {
	// bd
	D3D11_BUFFER_DESC bd;
	ZeroMemory( &bd, sizeof(bd) );
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( VertexStructure ) * Parts[PartIndex].UsedVertices;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	// Parts is loaded to InitData
	D3D11_SUBRESOURCE_DATA InitData; 
	ZeroMemory( &InitData, sizeof(InitData) );
	InitData.pSysMem = Parts[PartIndex].VertexBuffer;
	// Release any old buffer
	SAFE_RELEASE( Parts[PartIndex].D3DVertexBuffer );
	// CreateBuffer(bd, InitData)
	if (bd.ByteWidth > 0) {
		m_pd3dDevice->CreateBuffer( &bd, &InitData, &Parts[PartIndex].D3DVertexBuffer );
	}
}

void ModelClass::UpdateEverythingIfNeeded(void) {
	int PartIndex;
	if (ModelProperties.NeedAnyUpdate) {
		// Update parts if needed
		ForAllParts(PartIndex) {
			UpdatePartsGeometryIfNeeded(PartIndex);
		}
		
		// Remeasure if needed
		if (ModelProperties.NeedNewBounds) {
			ModelProperties.NeedNewBounds = false;
			MeasureBounds();
		}
		
		ModelProperties.NeedAnyUpdate = false;
	}
}

void ModelClass::UpdatePartsGeometryIfNeeded(int PartIndex) {
	if ( Parts[PartIndex].NeedGeometryUpdate ) {
		UpdatePartsGeometry(PartIndex);
		Parts[PartIndex].NeedGeometryUpdate = false;
	}
}

int ModelClass::AddTriangle(int PartIndex) {
	int TriangleIndex; int VerticeIndex; int i;
	CheckPartIndex(L"AddTriangle",PartIndex) {
		if (NumberOfTriangles(PartIndex) < 1000000) {
			//TriangleIndex = NumberOfTriangles(PartIndex);
			TriangleIndex = (Parts[PartIndex].UsedVertices / 3);
			Parts[PartIndex].UsedVertices += 3;
			if (Parts[PartIndex].UsedVertices > Parts[PartIndex].AllocatedVertices) {
				SetPartSize(PartIndex,Parts[PartIndex].AllocatedVertices * 2);
			}
			LoopForward(0,VerticeIndex,2) {
				i = (TriangleIndex * 3) + VerticeIndex;
				Parts[PartIndex].VertexBuffer[i] = DefaultVertexStructure;
			}
			PartHasBeenModified(PartIndex);
			NeedNewBounds();
			return TriangleIndex;
		} else {
			MQ->InsertMessage(L"ModelClass::AddTriangle: The maximum number of triangles per model is exceeded. You can not have more than 1000000 triangles in the same model.");
			return -1;
		}
	}
	return -1;
}

void ModelClass::ReleasePart(int PartIndex) {
	SAFE_DELETE_ARRAY(Parts[PartIndex].VertexBuffer)
	SAFE_DELETE_ARRAY(Parts[PartIndex].PartName)
	SAFE_RELEASE( Parts[PartIndex].D3DVertexBuffer );
	int i;
	LoopForwardLengthFromZero(i,NumberOfShaderChannels) {
		if (Parts[PartIndex].pShaders[i] != NULL) {
			StopUsing(Parts[PartIndex].pShaders[i]->useCount);
		}
	}
	LoopForwardLengthFromZero(i,NumberOfTextureChannels) {
		if (Parts[PartIndex].pTexture[i] != NULL) {
			StopUsing(Parts[PartIndex].pTexture[i]->useCount);
		}
	}
}

void ModelClass::PartHasBeenModified(int PartIndex) {
	CheckPartIndex(L"PartHasBeenModified",PartIndex) {
		Parts[PartIndex].NeedGeometryUpdate = true;
	}
	ModelProperties.NeedAnyUpdate = true;
}

void ModelClass::NeedNewBounds(void) {
	ModelProperties.NeedNewBounds = true;
	ModelProperties.NeedAnyUpdate = true;
}

// Public interface

int ModelClass::CreateNewPart( wchar_t* strPartName, int PreallocatedTriangleCount ) {
	int i;
	Try_Start_Model {
		if (PreallocatedTriangleCount < 1) PreallocatedTriangleCount = 1;
		// Add to the counter
		NumberOfParts++;
		// Allocate if needed
		Try_Start_Model {
			if (NumberOfParts > AllocatedParts) { ReallocateParts(AllocatedParts * 2); }
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::CreateNewPart: Access violation while calling ReallocateParts.\n");
			return -1;
		}
		// Reset unused memory for easier debugging of uninitialized data.
		Try_Start_Model {
			Parts[NumberOfParts-1].UsedVertices = 0;
			Parts[NumberOfParts-1].AllocatedVertices = 0;
			Parts[NumberOfParts-1].VertexBuffer = NULL;
			Parts[NumberOfParts-1].D3DVertexBuffer = NULL;
			PartHasBeenModified(NumberOfParts-1);
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::CreateNewPart: Access violation while reseting unused memory.\n");
			return -1;
		}
		Try_Start_Model {
			SetPartSize(NumberOfParts-1,PreallocatedTriangleCount * 3);
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::CreateNewPart: Access violation while calling SetPartSize.\n");
			return -1;
		}
		Try_Start_Model {
			LoopForwardLengthFromZero(i,NumberOfTextureChannels) {
				Parts[NumberOfParts-1].pTexture[i] = NULL;
				Parts[NumberOfParts-1].iTextureOverride[i] = -1;
			}
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::CreateNewPart: Access violation while reseting textures.\n");
			return -1;
		}
		Try_Start_Model {
			LoopForwardLengthFromZero(i,NumberOfShaderChannels) {
				Parts[NumberOfParts-1].pShaders[i] = NULL;
			}
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::CreateNewPart: Access violation while reseting shaders.\n");
			return -1;
		}
		Try_Start_Model {
			Parts[NumberOfParts-1].MinDetailLevel = 0;
			Parts[NumberOfParts-1].MaxDetailLevel = 2;
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::CreateNewPart: Access violation while reseting multi resolution intervals.\n");
			return -1;
		}
		Try_Start_Model {
			Parts[NumberOfParts-1].PartName = CopyToNewString(strPartName);
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::CreateNewPart: Access violation while duplicating the part name.\n");
			return -1;
		}
		PartHasBeenModified(NumberOfParts-1);
		return NumberOfParts-1;
	} Try_Else_Model {
		MQ->InsertMessage(L"ModelClass::CreateNewPart: Access violation in the outer layer.\n");
		return -1;
	}
}

void ModelClass::DeletePart( int PartIndex ) {
	CheckPartIndex(L"DeletePart",PartIndex) {
		ReleasePart(PartIndex);
		if (PartIndex < NumberOfParts-1) {
			Parts[PartIndex] = Parts[NumberOfParts-1];
		}
		NumberOfParts--;
	}
}

void ModelClass::DeletePart_PreserveOrder( int PartIndex ) {
	int i;
	CheckPartIndex(L"DeletePart_PreserveOrder",PartIndex) {
		ReleasePart(PartIndex);
		LoopForward(PartIndex, i, NumberOfParts - 2) {
			Parts[i] = Parts[i + 1];
		}
		NeedNewBounds();
		NumberOfParts--;
	}
}

void ModelClass::SwapPartRenderingOrder( int PartIndexA, int PartIndexB ) {
	Part_Type Swap;
	CheckPartIndex(L"SwapPartRenderingOrder",PartIndexA) { CheckPartIndex(L"SwapPartRenderingOrder",PartIndexB) {
		Swap = Parts[PartIndexA];
		Parts[PartIndexA] = Parts[PartIndexB];
		Parts[PartIndexB] = Swap;
	} }
}

void ModelClass::SetPartTexture( int PartIndex, int TextureChannel, Texture_Struct* Texture ) {
	Try_Start_Model {
		CheckPartIndex(L"SetPartTexture",PartIndex) {
			CheckTextureChannelBound(L"SetPartTexture",TextureChannel) {
				Try_Start_Model {
					if (Parts[PartIndex].pTexture[TextureChannel] != NULL) {
						Try_Start_Model {
							StopUsing(Parts[PartIndex].pTexture[TextureChannel]->useCount);
						} Try_Else_Model {
							MQ->InsertMessage(L"SetPartTexture: Access violation while decreasing the previous texture's use count.\n");
							return;
						}
					}
				} Try_Else_Model {
					MQ->InsertMessage(L"SetPartTexture: Access violation while checking if there is a previous texture.\n");
					return;
				}
				Try_Start_Model {
					Parts[PartIndex].pTexture[TextureChannel] = Texture;
				} Try_Else_Model {
					MQ->InsertMessage(L"SetPartTexture: Access violation while assigning the new texture.\n");
					return;
				}
				Try_Start_Model {
					if (Texture != NULL) {
						StartUsing(Texture->useCount);
					}
				} Try_Else_Model {
					MQ->InsertMessage(L"SetPartTexture: Access violation while increasing the new texture's use count.\n");
					return;
				}
			}
		}
	} Try_Else_Model {
		MQ->InsertMessage(L"SetPartTexture: Access violation in the outer layer.\n");
		return;
	}
}

Texture_Struct* ModelClass::GetPartTexture(int PartIndex, int TextureChannel) {
	CheckPartIndex(L"GetPartTexture",PartIndex) {
		CheckTextureChannelBound(L"GetPartTexture",TextureChannel) {
			return Parts[PartIndex].pTexture[TextureChannel];
		}
	}
	return NULL;
}

void ModelClass::SetPartTextureOverride( int PartIndex, int TextureChannel, int TextureOverride ) {
	CheckPartIndex(L"SetPartTextureOverride",PartIndex) {
		CheckTextureChannelBound(L"SetPartTextureOverride",TextureChannel) {
			Parts[PartIndex].iTextureOverride[TextureChannel] = TextureOverride;
		}
	}
}

int ModelClass::GetPartTextureOverride(int PartIndex, int TextureChannel) {
	CheckPartIndex(L"GetPartTextureOverride",PartIndex) {
		CheckTextureChannelBound(L"GetPartTextureOverride",TextureChannel) {
			return Parts[PartIndex].iTextureOverride[TextureChannel];
		}
	}
	return -1;
}

void ModelClass::SetPartShader( int PartIndex, int ShaderChannel, Shader_Struct* Shader ) {
	Try_Start_Model {
		CheckPartIndex(L"SetPartShader",PartIndex) {
			CheckShaderChannelBound(L"SetPartShader",ShaderChannel) {
				Try_Start_Model {
					if (Parts[PartIndex].pShaders[ShaderChannel] != NULL) {
						Try_Start_Model {
							StopUsing(Parts[PartIndex].pShaders[ShaderChannel]->useCount);
						} Try_Else_Model {
							MQ->InsertMessage(L"SetPartShader: Access violation while decreasing the previous shader's use count.\n");
							return;
						}
					}
				} Try_Else_Model {
					MQ->InsertMessage(L"SetPartShader: Access violation while checking if there is a previous shader.\n");
					return;
				}
				Try_Start_Model {
					Parts[PartIndex].pShaders[ShaderChannel] = Shader;
				} Try_Else_Model {
					MQ->InsertMessage(L"SetPartShader: Access violation while assigning the new shader.\n");
					return;
				}
				Try_Start_Model {
					if (Shader != NULL) {
						StartUsing(Shader->useCount);
					}
				} Try_Else_Model {
					MQ->InsertMessage(L"SetPartShader: Access violation while increasing the new shader's use count.\n");
					return;
				}
			}
		}
	} Try_Else_Model {
		MQ->InsertMessage(L"SetPartShader: Access violation in the outer layer.\n");
		return;
	}
}

Shader_Struct* ModelClass::GetPartShader(int PartIndex, int ShaderChannel) {
	CheckPartIndex(L"GetPartShader",PartIndex) {
		CheckShaderChannelBound(L"GetPartShader",ShaderChannel) {
			return Parts[PartIndex].pShaders[ShaderChannel];
		}
	}
	return NULL;
}

int ModelClass::InsertTriangleToPart( int PartIndex ) {
	CheckPartIndex(L"InsertTriangleToPart",PartIndex) {
		PartHasBeenModified(PartIndex);
		NeedNewBounds();
		return AddTriangle(PartIndex);
	}
	return -1;
}

// Set vector
void ModelClass::Vertice_SetPos( int PartIndex, int TriangleIndex, int VerticeIndex, DVector3 Pos ) { CheckPTV( L"Vertice_SetPos",VerticeFromPTV.Pos = Pos;PartHasBeenModified(PartIndex);NeedNewBounds();) }
void ModelClass::Vertice_SetTexCoord( int PartIndex, int TriangleIndex, int VerticeIndex, DVector4 TexCoord ) { CheckPTV( L"Vertice_SetTexCoord",VerticeFromPTV.TexCoord = TexCoord; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetColor( int PartIndex, int TriangleIndex, int VerticeIndex, DVector4 Color ) { CheckPTV( L"Vertice_SetColor",VerticeFromPTV.Color = Color; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetNormal( int PartIndex, int TriangleIndex, int VerticeIndex, DVector3 Normal ) { CheckPTV( L"Vertice_SetNormal",VerticeFromPTV.Normal = Normal; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetA( int PartIndex, int TriangleIndex, int VerticeIndex, DVector4 A ) { CheckPTV( L"Vertice_SetA",VerticeFromPTV.A = A; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetB( int PartIndex, int TriangleIndex, int VerticeIndex, DVector4 B ) { CheckPTV( L"Vertice_SetB",VerticeFromPTV.B = B; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetBoneData( int PartIndex, int TriangleIndex, int VerticeIndex, DVector4 BD ) { CheckPTV( L"Vertice_SetBoneData",VerticeFromPTV.BoneData = BD; PartHasBeenModified(PartIndex); ) }

// Set/get single values
void ModelClass::Vertice_SetSelected( int PartIndex, int TriangleIndex, int VerticeIndex, float Selected ) { CheckPTV(L"Vertice_SetSelected",VerticeFromPTV.Selected = Selected;PartHasBeenModified(PartIndex);) }
float ModelClass::Vertice_GetSelected( int PartIndex, int TriangleIndex, int VerticeIndex ) { CheckPTV( L"Vertice_GetSelected",return VerticeFromPTV.Selected; ) return 0.0f; }

// Set element
void ModelClass::Vertice_SetPos_X( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) {CheckPTV(L"Vertice_SetPos_X",VerticeFromPTV.Pos.x = Value;PartHasBeenModified(PartIndex);NeedNewBounds();)}
void ModelClass::Vertice_SetPos_Y( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) {CheckPTV(L"Vertice_SetPos_Y",VerticeFromPTV.Pos.y = Value;PartHasBeenModified(PartIndex);NeedNewBounds();)}
void ModelClass::Vertice_SetPos_Z( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) {CheckPTV(L"Vertice_SetPos_Z",VerticeFromPTV.Pos.z = Value;PartHasBeenModified(PartIndex);NeedNewBounds();)}
void ModelClass::Vertice_SetTexCoord_U1( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetTexCoord_U1",VerticeFromPTV.TexCoord.x = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetTexCoord_V1( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetTexCoord_V1",VerticeFromPTV.TexCoord.y = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetTexCoord_U2( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetTexCoord_U2",VerticeFromPTV.TexCoord.z = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetTexCoord_V2( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetTexCoord_V2",VerticeFromPTV.TexCoord.w = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetColor_R( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetColor_R",VerticeFromPTV.Color.x = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetColor_G( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetColor_G",VerticeFromPTV.Color.y = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetColor_B( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetColor_B",VerticeFromPTV.Color.z = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetColor_A( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetColor_A",VerticeFromPTV.Color.w = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetNormal_X( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetNormal_X",VerticeFromPTV.Normal.x = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetNormal_Y( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetNormal_Y",VerticeFromPTV.Normal.y = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetNormal_Z( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetNormal_Z",VerticeFromPTV.Normal.z = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetA_X( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetA_X",VerticeFromPTV.A.x = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetA_Y( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetA_Y",VerticeFromPTV.A.y = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetA_Z( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetA_Z",VerticeFromPTV.A.z = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetA_W( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetA_W",VerticeFromPTV.A.w = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetB_X( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetB_X",VerticeFromPTV.B.x = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetB_Y( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetB_Y",VerticeFromPTV.B.y = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetB_Z( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetB_Z",VerticeFromPTV.B.z = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetB_W( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetB_W",VerticeFromPTV.B.w = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetBoneData_X( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetBoneData_X",VerticeFromPTV.BoneData.x = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetBoneData_Y( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetBoneData_Y",VerticeFromPTV.BoneData.y = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetBoneData_Z( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetBoneData_Z",VerticeFromPTV.BoneData.z = Value; PartHasBeenModified(PartIndex); ) }
void ModelClass::Vertice_SetBoneData_W( int PartIndex, int TriangleIndex, int VerticeIndex, float Value ) { CheckPTV( L"Vertice_SetBoneData_W",VerticeFromPTV.BoneData.w = Value; PartHasBeenModified(PartIndex); ) }

// Get vector
DVector3 ModelClass::Vertice_GetPos( int PartIndex, int TriangleIndex, int VerticeIndex ) { CheckPTV( L"Vertice_GetPos",return VerticeFromPTV.Pos; ) return DVector3(0.0f, 0.0f, 0.0f); }
DVector4 ModelClass::Vertice_GetTexCoord( int PartIndex, int TriangleIndex, int VerticeIndex ) { CheckPTV( L"Vertice_GetTexCoord",return VerticeFromPTV.TexCoord; ) return DVector4(0.0f, 0.0f, 0.0f, 0.0f); }
DVector4 ModelClass::Vertice_GetColor( int PartIndex, int TriangleIndex, int VerticeIndex ) { CheckPTV( L"Vertice_GetColor",return VerticeFromPTV.Color; ) return DVector4(0.0f, 0.0f, 0.0f, 0.0f); }
DVector3 ModelClass::Vertice_GetNormal( int PartIndex, int TriangleIndex, int VerticeIndex ) { CheckPTV( L"Vertice_GetNormal",return VerticeFromPTV.Normal; ) return DVector3(0.0f, 0.0f, 0.0f); }
DVector4 ModelClass::Vertice_GetA( int PartIndex, int TriangleIndex, int VerticeIndex ) { CheckPTV( L"Vertice_GetA",return VerticeFromPTV.A; ) return DVector4(0.0f, 0.0f, 0.0f, 0.0f); }
DVector4 ModelClass::Vertice_GetB( int PartIndex, int TriangleIndex, int VerticeIndex ) { CheckPTV( L"Vertice_GetB",return VerticeFromPTV.B; ) return DVector4(0.0f, 0.0f, 0.0f, 0.0f); }
DVector4 ModelClass::Vertice_GetBoneData( int PartIndex, int TriangleIndex, int VerticeIndex ) { CheckPTV( L"Vertice_GetBoneData",return VerticeFromPTV.BoneData; ) return DVector4(0.0f, 0.0f, 0.0f, -1.0f); }

void ModelClass::Vertice_SetAll( int PartIndex, int TriangleIndex, int VerticeIndex,VertexStructure VertexData ) {
	CheckPTV( L"Vertice_SetAll",VerticeFromPTV = VertexData; PartHasBeenModified(PartIndex); NeedNewBounds(); )
}

VertexStructure ModelClass::Vertice_GetAll( int PartIndex, int TriangleIndex, int VerticeIndex ) {
	CheckPTV( L"Vertice_GetAll",return VerticeFromPTV; )
	return DefaultVertexStructure;
}

void ModelClass::MeasureBounds(void) {
	int PartIndex; int vertex; DVector3 newPos; float Dist;
	ObjectSpaceMin = DVector3( 1000000000000.0f, 1000000000000.0f, 1000000000000.0f);
	ObjectSpaceMax = DVector3(-1000000000000.0f,-1000000000000.0f,-1000000000000.0f);
	Radius = 0;
	ForAllParts(PartIndex) {
		ForAllVerticesInPart(vertex, PartIndex) {
			newPos = Parts[PartIndex].VertexBuffer[vertex].Pos;
			if (ObjectSpaceMin.x > newPos.x) { ObjectSpaceMin.x = newPos.x; }
			if (ObjectSpaceMin.y > newPos.y) { ObjectSpaceMin.y = newPos.y; }
			if (ObjectSpaceMin.z > newPos.z) { ObjectSpaceMin.z = newPos.z; }
			if (ObjectSpaceMax.x < newPos.x) { ObjectSpaceMax.x = newPos.x; }
			if (ObjectSpaceMax.y < newPos.y) { ObjectSpaceMax.y = newPos.y; }
			if (ObjectSpaceMax.z < newPos.z) { ObjectSpaceMax.z = newPos.z; }
			Dist = AbsVec3(newPos);
			if (Dist > Radius) { Radius = Dist; }
		}
	}
	ObjectSpaceCenter.x = (ObjectSpaceMin.x + ObjectSpaceMax.x) / 2.0f;
	ObjectSpaceCenter.y = (ObjectSpaceMin.y + ObjectSpaceMax.y) / 2.0f;
	ObjectSpaceCenter.z = (ObjectSpaceMin.z + ObjectSpaceMax.z) / 2.0f;
}

int ModelClass::GetNumberOfParts(void) {
	return NumberOfParts;
}

wchar_t* ModelClass::GetPartName(int PartIndex) {
	CheckPartIndex(L"GetPartName",PartIndex) {
		return Parts[PartIndex].PartName;
	}
	return L"";
}

void ModelClass::SetPartName(int PartIndex, wchar_t* Name) {
	Try_Start_Model {
		CheckPartIndex(L"SetPartName",PartIndex) {
			Try_Start_Model {
				SAFE_DELETE_ARRAY(Parts[PartIndex].PartName)
			} Try_Else_Model {
				MQ->InsertMessage(L"SetPartName: Access violation while deleting the old name.\n");
				return;
			}
			Try_Start_Model {
				Parts[PartIndex].PartName = CopyToNewString(Name);
			} Try_Else_Model {
				MQ->InsertMessage(L"SetPartName: Access violation while duplicating the new name.\n");
				return;
			}
		}
	} Try_Else_Model {
		MQ->InsertMessage(L"SetPartName: Access violation in the outer layer.\n");
		return;
	}
}

int ModelClass::GetTriangleCountFromPart(int PartIndex) {
	CheckPartIndex(L"GetTriangleCountFromPart",PartIndex) {
		return NumberOfTriangles(PartIndex);
	}
	return -1;
}

wchar_t* ModelClass::GetFilterName(void) {
	if (ModelProperties.FilterType == Filter_Alpha) {
		return L"Alpha";
	} else {
		return L"None";
	}
}

void ModelClass::SetFilterUsingName(wchar_t* FilterName,wchar_t* MethodName) {
	if (CompareStrings_CaseInsensitive(FilterName,L"None")) {
		ModelProperties.FilterType = Filter_None;
	} else if (CompareStrings_CaseInsensitive(FilterName,L"Alpha")) {
		ModelProperties.FilterType = Filter_Alpha;
	} else {
		swprintf_s( MQ->messageBuffer, L"%s: \"%s\" is not a valid filter name. Use \"None\" or \"Alpha\".",MethodName,FilterName); MQ->InsertMessage(MQ->messageBuffer); \
		ModelProperties.FilterType = Filter_None;
	}
}

wchar_t* ModelClass::GetCullingName(void) {
	if (ModelProperties.CullingMethod == Culling_AABB) {
		return L"AABB";
	} else if (ModelProperties.CullingMethod == Culling_Radius) {
		return L"Radius";
	} else {
		return L"None";
	}
}

void ModelClass::SetCullingUsingName(wchar_t* CullingName,wchar_t* MethodName) {
	if (CompareStrings_CaseInsensitive(CullingName,L"None")) {
		ModelProperties.CullingMethod = Culling_None;
	} else if (CompareStrings_CaseInsensitive(CullingName,L"AABB")) {
		ModelProperties.CullingMethod = Culling_AABB;
	} else if (CompareStrings_CaseInsensitive(CullingName,L"Radius")) {
		ModelProperties.CullingMethod = Culling_Radius;
	} else {
		swprintf_s( MQ->messageBuffer, L"%s: \"%s\" is not a valid culling name. Use \"None\", \"AABB\" or \"Radius\".",MethodName,CullingName); MQ->InsertMessage(MQ->messageBuffer); \
		ModelProperties.CullingMethod = Culling_None;
	}
}

#define CopyTriangleaData(TRIANGLE_DST,TRIANGLE_SRC) \
	Parts[PartIndex].VertexBuffer[((TRIANGLE_DST) * 3) + 0] = Parts[PartIndex].VertexBuffer[((TRIANGLE_SRC) * 3) + 0]; \
	Parts[PartIndex].VertexBuffer[((TRIANGLE_DST) * 3) + 1] = Parts[PartIndex].VertexBuffer[((TRIANGLE_SRC) * 3) + 1]; \
	Parts[PartIndex].VertexBuffer[((TRIANGLE_DST) * 3) + 2] = Parts[PartIndex].VertexBuffer[((TRIANGLE_SRC) * 3) + 2];

void ModelClass::DeleteTriangle(int PartIndex, int TriangleIndex) {
	int LastTriangleIndex;
	CheckPartIndex(L"DeleteTriangle",PartIndex) {
		CheckTriangleIndex(L"DeleteTriangle",PartIndex,TriangleIndex) {
			LastTriangleIndex = (NumberOfTriangles(PartIndex)) - 1;
			if (TriangleIndex < LastTriangleIndex) {
				CopyTriangleaData(TriangleIndex,LastTriangleIndex)
			}
			Parts[PartIndex].UsedVertices -= 3;
			PartHasBeenModified(PartIndex);
			NeedNewBounds();
		}
	}
}

void ModelClass::DeleteTriangle_PreserveOrder(int PartIndex, int TriangleIndex) {
	int LastTriangleIndex; int i;
	CheckPartIndex(L"DeleteTriangle_PreserveOrder",PartIndex) {
		CheckTriangleIndex(L"DeleteTriangle_PreserveOrder",PartIndex,TriangleIndex) {
			LastTriangleIndex = (NumberOfTriangles(PartIndex)) - 1;
			LoopForward(TriangleIndex, i, LastTriangleIndex - 1) {
				CopyTriangleaData(i, i + 1)
			}
			Parts[PartIndex].UsedVertices -= 3;
			PartHasBeenModified(PartIndex);
			NeedNewBounds();
		}
	}
}

void ModelClass::SwapTriangleRenderingOrder(int PartIndex, int TriangleIndexA, int TriangleIndexB) {
	VertexStructure VertexStructureSwap[3];
	CheckPartIndex(L"SwapTriangleRenderingOrder",PartIndex) {
		CheckTriangleIndex(L"SwapTriangleRenderingOrder",PartIndex,TriangleIndexA) {
			CheckTriangleIndex(L"SwapTriangleRenderingOrder",PartIndex,TriangleIndexB) {
				// Swap = A
				VertexStructureSwap[0] = Parts[PartIndex].VertexBuffer[(TriangleIndexA * 3) + 0];
				VertexStructureSwap[1] = Parts[PartIndex].VertexBuffer[(TriangleIndexA * 3) + 1];
				VertexStructureSwap[2] = Parts[PartIndex].VertexBuffer[(TriangleIndexA * 3) + 2];
				// A = B
				CopyTriangleaData(TriangleIndexA, TriangleIndexB)
				Parts[PartIndex].VertexBuffer[(TriangleIndexA * 3) + 0] = Parts[PartIndex].VertexBuffer[(TriangleIndexB * 3) + 0];
				Parts[PartIndex].VertexBuffer[(TriangleIndexA * 3) + 1] = Parts[PartIndex].VertexBuffer[(TriangleIndexB * 3) + 1];
				Parts[PartIndex].VertexBuffer[(TriangleIndexA * 3) + 2] = Parts[PartIndex].VertexBuffer[(TriangleIndexB * 3) + 2];
				// B = Swap
				Parts[PartIndex].VertexBuffer[(TriangleIndexB * 3) + 0] = VertexStructureSwap[0];
				Parts[PartIndex].VertexBuffer[(TriangleIndexB * 3) + 1] = VertexStructureSwap[1];
				Parts[PartIndex].VertexBuffer[(TriangleIndexB * 3) + 2] = VertexStructureSwap[2];
				PartHasBeenModified(PartIndex);
			}
		}
	}
}

void ModelClass::FlipTriangle(int PartIndex, int TriangleIndex) {
	VertexStructure VertexStructureSwap;
	CheckPartIndex(L"FlipTriangle",PartIndex) {
		CheckTriangleIndex(L"FlipTriangle",PartIndex,TriangleIndex) {
			VertexStructureSwap = Parts[PartIndex].VertexBuffer[(TriangleIndex * 3) + 0];
			Parts[PartIndex].VertexBuffer[(TriangleIndex * 3) + 0] = Parts[PartIndex].VertexBuffer[(TriangleIndex * 3) + 2];
			Parts[PartIndex].VertexBuffer[(TriangleIndex * 3) + 2] = VertexStructureSwap;
			PartHasBeenModified(PartIndex);
		}
	}
}

void ModelClass::SetPartMinDetailLevel( int PartIndex, int DetailLevel ) {
	CheckPartIndex(L"SetPartMinDetailLevel",PartIndex) {
		Parts[PartIndex].MinDetailLevel = DetailLevel;
	}
}

int ModelClass::GetPartMinDetailLevel(int PartIndex) {
	CheckPartIndex(L"GetPartMinDetailLevel",PartIndex) {
		return Parts[PartIndex].MinDetailLevel;
	}
	return -1;
}

void ModelClass::SetPartMaxDetailLevel( int PartIndex, int DetailLevel ) {
	CheckPartIndex(L"SetPartMaxDetailLevel",PartIndex) {
		Parts[PartIndex].MaxDetailLevel = DetailLevel;
	}
}

int ModelClass::GetPartMaxDetailLevel(int PartIndex) {
	CheckPartIndex(L"GetPartMaxDetailLevel",PartIndex) {
		return Parts[PartIndex].MaxDetailLevel;
	}
	return -1;
}

bool ModelClass::IsPartVisible(int DetailLevel_Int, int PartIndex) {
	if (PartIndex == -1) {
		// All
		return true;
	} else if (PartIndex < -1 || PartIndex > NumberOfParts - 1) {
		// Out of bound
		return false;
	} else {
		// From PartIndex
		return  (Parts[PartIndex].UsedVertices > 0 && DetailLevel_Int >= Parts[PartIndex].MinDetailLevel && DetailLevel_Int <= Parts[PartIndex].MaxDetailLevel);
	}
}

// Let Part be -1 to render all parts
void ModelClass::Render(int ShaderChannel, Shader_Struct* DefaultShader, Texture_Struct* DefaultTexture, SurfaceCombo OverrideSurfaces[16], Texture_Struct* LightProjectionAtlas, int DetailLevel_Int, Shader_Struct* ShaderOverride, int Part, bool IsShadow) {
	CheckShaderChannelBound(L"Render",ShaderChannel) {
		// Start loop
		int PartIndex;
		int MinPartIndex;
		int MaxPartIndex;
		if (Part == -1) {
			MinPartIndex = 0;
			MaxPartIndex = NumberOfParts - 1;
		} else {
			MinPartIndex = Part;
			MaxPartIndex = Part;
		}
		LoopForward(MinPartIndex,PartIndex,MaxPartIndex) {
			if (Parts[PartIndex].UsedVertices > 0 && DetailLevel_Int >= Parts[PartIndex].MinDetailLevel && DetailLevel_Int <= Parts[PartIndex].MaxDetailLevel) {
				bool HasShader;
				Shader_Struct* Shader;
				if (ShaderOverride) {
					Shader = ShaderOverride;
				} else {
					Shader = Parts[PartIndex].pShaders[ShaderChannel];
				}

				if (Shader == NULL) {
					// No shader is assigned
					HasShader = false;
				} else if (Shader->Compiled == false) {
					// The shader had compilation errors
					HasShader = false;
				} else {
					// The shader is good
					HasShader = true;
				}

				if ( !(Shader == NULL && IsShadow) ) { // Draw unless this is a shadow without a shader
					if (HasShader == false) {
						if (DefaultShader == NULL) {
							swprintf_s( MQ->messageBuffer, L"ModelClass::Render: You tried to render a part called %s without a shader assigned to shader channel %i. Use Shader_UseAsDefaultMaterialShader with a material shader when starting your appilcation if you don't want to see this warning again.",Parts[PartIndex].PartName,ShaderChannel); MQ->InsertMessage(MQ->messageBuffer); \
							return;
						} else {
							// Use the default shader
							m_pImmediateContext->IASetInputLayout( DefaultShader->VS.pVertexLayout );
							m_pImmediateContext->VSSetShader( DefaultShader->VS.pVertexShader, NULL, 0 );
							m_pImmediateContext->PSSetShader( DefaultShader->PS.pPixelShader, NULL, 0 );
							m_pImmediateContext->GSSetShader( DefaultShader->GS.pGeometryShader, NULL, 0);
						}
					} else {
						// Use the part's shader
						m_pImmediateContext->IASetInputLayout( Shader->VS.pVertexLayout );
						m_pImmediateContext->VSSetShader( Shader->VS.pVertexShader, NULL, 0 );
						m_pImmediateContext->PSSetShader( Shader->PS.pPixelShader, NULL, 0 );
						m_pImmediateContext->GSSetShader( Shader->GS.pGeometryShader, NULL, 0);
					}
					
					Try_Start_Model {
						// Set the vertex buffer
						m_pImmediateContext->IASetVertexBuffers( 0, 1, &Parts[PartIndex].D3DVertexBuffer, &VertexStructureSize, &NoOffset );
					} Try_Else_Model {
						MQ->InsertMessage(L"ModelClass::Render: Access violation while selecting vertex buffer.\n");
						return;
					}

					Try_Start_Model {
						// Use a triangle list
						m_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
					} Try_Else_Model {
						MQ->InsertMessage(L"ModelClass::Render: Access violation while setting primitive topology.\n");
						return;
					}

					Try_Start_Model {
						// Assign the used textures
						int i;
						ID3D11ShaderResourceView* Tex;
						ID3D11ShaderResourceView* NoTexture = NULL;
						LoopForwardLengthFromZero(i,NumberOfTextureChannels) {
							if (Parts[PartIndex].iTextureOverride[i] > -1 && OverrideSurfaces[Parts[PartIndex].iTextureOverride[i]].iSurfaceType != SurfaceType_Empty) {
								// Overriding texture
								if (OverrideSurfaces[Parts[PartIndex].iTextureOverride[i]].iSurfaceType == SurfaceType_Texture) {
									Try_Start_Model {
										m_pImmediateContext->PSSetShaderResources(i,1,&(((Texture_Struct*)(OverrideSurfaces[Parts[PartIndex].iTextureOverride[i]].pSurface))->ColorOutput));
										m_pImmediateContext->VSSetShaderResources(i,1,&(((Texture_Struct*)(OverrideSurfaces[Parts[PartIndex].iTextureOverride[i]].pSurface))->ColorOutput));
										m_pImmediateContext->GSSetShaderResources(i,1,&(((Texture_Struct*)(OverrideSurfaces[Parts[PartIndex].iTextureOverride[i]].pSurface))->ColorOutput));
									} Try_Else_Model {
										MQ->InsertMessage(L"ModelClass::Render: Access violation while overriding with a texture.\n");
										return;
									}
								} else if (OverrideSurfaces[Parts[PartIndex].iTextureOverride[i]].iSurfaceType == SurfaceType_DrawSurface) {
									int TextureOverride;
									DrawSurface_Struct* Surface;
									Try_Start_Model {
										TextureOverride = Parts[PartIndex].iTextureOverride[i];
									} Try_Else_Model {
										MQ->InsertMessage(L"ModelClass::Render: Access violation while getting the texture override channel.\n");
										return;
									}
									Try_Start_Model {
										Surface = (DrawSurface_Struct*)(OverrideSurfaces[TextureOverride].pSurface);
									} Try_Else_Model {
										MQ->InsertMessage(L"ModelClass::Render: Access violation while getting the draw surface.\n");
										return;
									}
									Try_Start_Model {
										Tex = Surface->ColorOutput;
									} Try_Else_Model {
										MQ->InsertMessage(L"ModelClass::Render: Access violation while getting the shader resource view from the draw surface.\n");
										return;
									}
									Try_Start_Model {
										m_pImmediateContext->PSSetShaderResources(i,1,&Tex);
										m_pImmediateContext->VSSetShaderResources(i,1,&Tex);
										m_pImmediateContext->GSSetShaderResources(i,1,&Tex);
										//m_pImmediateContext->GSSetShaderResources(i,1,&(((DrawSurface_Struct*)(OverrideSurfaces[Parts[PartIndex].iTextureOverride[i]].pSurface))->ColorOutput));
									} Try_Else_Model {
										MQ->InsertMessage(L"ModelClass::Render: Access violation while overriding with a draw surface.\n");
										return;
									}
								} else {
									MQ->InsertMessage(L"ModelClass::Render: Invalid SurfaceType");
								}
							} else if (Parts[PartIndex].pTexture[i]) {
								Try_Start_Model {
									// Model's texture
									m_pImmediateContext->PSSetShaderResources(i,1,&Parts[PartIndex].pTexture[i]->ColorOutput);
									m_pImmediateContext->VSSetShaderResources(i,1,&Parts[PartIndex].pTexture[i]->ColorOutput);
									m_pImmediateContext->GSSetShaderResources(i,1,&Parts[PartIndex].pTexture[i]->ColorOutput);
								} Try_Else_Model {
									MQ->InsertMessage(L"ModelClass::Render: Access violation while using the model's texture.\n");
									return;
								}
							} else {
								if (DefaultTexture == NULL) {
									Try_Start_Model {
										// NULL texture
										m_pImmediateContext->PSSetShaderResources(i,1,&NoTexture);
										m_pImmediateContext->VSSetShaderResources(i,1,&NoTexture);
										m_pImmediateContext->GSSetShaderResources(i,1,&NoTexture);
									} Try_Else_Model {
										MQ->InsertMessage(L"ModelClass::Render: Access violation while using a NULL texture.\n");
										return;
									}
								} else {
									Try_Start_Model {
										// Default texture
										m_pImmediateContext->PSSetShaderResources(i,1,&(DefaultTexture->ColorOutput));
										m_pImmediateContext->VSSetShaderResources(i,1,&(DefaultTexture->ColorOutput));
										m_pImmediateContext->GSSetShaderResources(i,1,&(DefaultTexture->ColorOutput));
									} Try_Else_Model {
										MQ->InsertMessage(L"ModelClass::Render: Access violation while using the default texture.\n");
										return;
									}
								}
							}
						}
					} Try_Else_Model {
						MQ->InsertMessage(L"ModelClass::Render: Access violation while assigning textures.\n");
						return;
					}
					Try_Start_Model {
						// An interval of indexes are choosing points for triangles
						m_pImmediateContext->Draw(Parts[PartIndex].UsedVertices,0);
					} Try_Else_Model {
						MQ->InsertMessage(L"ModelClass::Render: Access violation while drawing the triangles.\n");
						return;
					}
				}
			}
		}
	}
}

void ModelClass::ReleaseBone(int BoneIndex) {
	SAFE_DELETE_ARRAY(Bones[BoneIndex].BoneName)
}

int ModelClass::GetNumberOfBones(void) {
	return NumberOfBones;
}

int ModelClass::CreateNewBone(wchar_t* strBoneName) {
	if (NumberOfBones < MaxNumberOfBones) {
		// Add to the counter
		NumberOfBones++;
		if (Bones == NULL) {
			Bones = new Bone_Type[MaxNumberOfBones];
			if (Bones == NULL) {
				NumberOfBones = 0;
				MQ->InsertMessage(L"ModelClass::CreateNewBone: Could not allocate a new bone.\n");
				return -1;
			}
		}
		Bones[NumberOfBones-1].Length = 1.0f;
		Bones[NumberOfBones-1].ParentIndex = -1;
		Bones[NumberOfBones-1].ObjectSpacePos = DVector3(0.0f,0.0f,0.0f);
		Bones[NumberOfBones-1].ParentSpacePos = DVector3(0.0f,0.0f,0.0f);
		Bones[NumberOfBones-1].YAxis = DVector3(0.0f,1.0f,0.0f);
		Bones[NumberOfBones-1].ZAxis = DVector3(0.0f,0.0f,1.0f);
		Bones[NumberOfBones-1].UserData = DVector3(0.0f,0.0f,0.0f);
		Bones[NumberOfBones-1].BoneName = NULL;
		Bones[NumberOfBones-1].BoneName = CopyToNewString(strBoneName);
		return NumberOfBones-1;
	} else {
		MQ->InsertMessage(L"ModelClass::CreateNewBone: The maximum number of bones is reached.\n");
		return -1;
	}
}

void ModelClass::DeleteBone(int BoneIndex) {
	CheckBoneIndex(L"DeleteBone",BoneIndex) {
		ReleaseBone(BoneIndex);
		if (BoneIndex < NumberOfBones-1) {
			Bones[BoneIndex] = Bones[NumberOfBones-1];
		}
		NumberOfBones--;
	}
}

void ModelClass::DeleteBone_PreserveOrder(int BoneIndex) {
	int i;
	CheckBoneIndex(L"DeleteBone_PreserveOrder",BoneIndex) {
		// Clear memory
		ReleaseBone(BoneIndex);
		LoopForward(BoneIndex, i, NumberOfBones - 2) {
			Bones[i] = Bones[i + 1];
		}
		NumberOfBones--;
		
		// Handle reference integrity for child bones
		int Bone;
		int OldParent;
		ForAllBones(Bone) {
			OldParent = Bone_GetParentIndex(Bone);
			if (OldParent == BoneIndex) {
				Bone_SetParentIndex(Bone, -1);
				Bone_SetParentSpacePos(Bone, DVector3(0.0f,0.0f,0.0f));
			} else if (OldParent > BoneIndex) {
				Bone_SetParentIndex(Bone, OldParent - 1);
			}
		}
		
		// Handle reference integrity for connected vertices
		int Part;
		int Tri;
		int Vert;
		DVector4 BoneData;
		ForAllParts(Part) {
			LoopForwardLengthFromZero(Tri,NumberOfTriangles(Part)) {
				LoopForwardLengthFromZero(Vert,3) {
					BoneData = Vertice_GetBoneData(Part, Tri, Vert);
					if (BoneData.w == BoneIndex) {
						Vertice_SetBoneData(Part, Tri, Vert, DVector4(0.0f, 0.0f, 0.0f, -1.0f));
					} else if (BoneData.w > BoneIndex) {
						Vertice_SetBoneData(Part, Tri, Vert, DVector4(BoneData.x, BoneData.y, BoneData.z, BoneData.w - 1.0f));
					}
				}
			}
		}
	}
}

void ModelClass::SwapBoneHierarchyOrder( int BoneIndexA, int BoneIndexB ) {
	Bone_Type Swap;
	CheckBoneIndex(L"SwapBoneHierarchyOrder",BoneIndexA) { CheckBoneIndex(L"SwapBoneHierarchyOrder",BoneIndexB) {
		// Swap memory
		Swap = Bones[BoneIndexA];
		Bones[BoneIndexA] = Bones[BoneIndexB];
		Bones[BoneIndexB] = Swap;
		
		// Handle reference integrity for child bones
		int Bone;
		int OldParent;
		ForAllBones(Bone) {
			OldParent = Bone_GetParentIndex(Bone);
			if (OldParent == BoneIndexA) {
				Bone_SetParentIndex(Bone, BoneIndexB);
			} else if (OldParent == BoneIndexB) {
				Bone_SetParentIndex(Bone, BoneIndexA);
			}
		}
		
		// Handle reference integrity for connected vertices
		int Part;
		int Tri;
		int Vert;
		DVector4 BoneData;
		ForAllParts(Part) {
			LoopForwardLengthFromZero(Tri,NumberOfTriangles(Part)) {
				LoopForwardLengthFromZero(Vert,3) {
					BoneData = Vertice_GetBoneData(Part, Tri, Vert);
					if (((int)BoneData.w) == BoneIndexA) {
						Vertice_SetBoneData(Part, Tri, Vert, DVector4(BoneData.x, BoneData.y, BoneData.z, (float)BoneIndexB));
					} else if (((int)BoneData.w) == BoneIndexB) {
						Vertice_SetBoneData(Part, Tri, Vert, DVector4(BoneData.x, BoneData.y, BoneData.z, (float)BoneIndexA));
					}
				}
			}
		}
	} }
}

wchar_t* ModelClass::GetBoneName(int BoneIndex) {
	CheckBoneIndex(L"GetBoneName",BoneIndex) {
		return Bones[BoneIndex].BoneName;
	}
	return L"";
}

void ModelClass::SetBoneName(int BoneIndex, wchar_t* Name) {
	Try_Start_Model {
		CheckBoneIndex(L"SetBoneName",BoneIndex) {
			Try_Start_Model {
				SAFE_DELETE_ARRAY(Bones[BoneIndex].BoneName)
			} Try_Else_Model {
				MQ->InsertMessage(L"SetBoneName: Access violation while deleting the old name.\n");
				return;
			}
			Try_Start_Model {
				Bones[BoneIndex].BoneName = CopyToNewString(Name);
			} Try_Else_Model {
				MQ->InsertMessage(L"SetBoneName: Access violation while duplicating the new name.\n");
				return;
			}
		}
	} Try_Else_Model {
		MQ->InsertMessage(L"SetBoneName: Access violation in the outer layer.\n");
		return;
	}
}

void ModelClass::Bone_SetParentIndex(int BoneIndex, int ParentIndex) {
	CheckBoneIndex(L"Bone_SetParentIndex",BoneIndex) {
		Bones[BoneIndex].ParentIndex = ParentIndex;
	}
}

int ModelClass::Bone_GetParentIndex(int BoneIndex) {
	CheckBoneIndex(L"Bone_GetParentIndex",BoneIndex) {
		return Bones[BoneIndex].ParentIndex;
	}
	return -1;
}

void ModelClass::Bone_SetLength(int BoneIndex, float Length) {
	CheckBoneIndex(L"Bone_SetLength",BoneIndex) {
		Bones[BoneIndex].Length = Length;
	}
}

float ModelClass::Bone_GetLength(int BoneIndex) {
	CheckBoneIndex(L"Bone_GetLength",BoneIndex) {
		return Bones[BoneIndex].Length;
	}
	return 0.0f;
}

void ModelClass::Bone_SetObjectSpacePos(int BoneIndex, DVector3 ObjectSpacePos) {
	CheckBoneIndex(L"Bone_SetObjectSpacePos",BoneIndex) {
		Bones[BoneIndex].ObjectSpacePos = ObjectSpacePos;
	}
}

void ModelClass::Bone_SetObjectSpacePosX(int BoneIndex, float ObjectSpacePosX) {
	CheckBoneIndex(L"Bone_SetObjectSpacePosX",BoneIndex) {
		Bones[BoneIndex].ObjectSpacePos.x = ObjectSpacePosX;
	}
}

void ModelClass::Bone_SetObjectSpacePosY(int BoneIndex, float ObjectSpacePosY) {
	CheckBoneIndex(L"Bone_SetObjectSpacePosY",BoneIndex) {
		Bones[BoneIndex].ObjectSpacePos.y = ObjectSpacePosY;
	}
}

void ModelClass::Bone_SetObjectSpacePosZ(int BoneIndex, float ObjectSpacePosZ) {
	CheckBoneIndex(L"Bone_SetObjectSpacePosZ",BoneIndex) {
		Bones[BoneIndex].ObjectSpacePos.z = ObjectSpacePosZ;
	}
}

DVector3 ModelClass::Bone_GetObjectSpacePos(int BoneIndex) {
	CheckBoneIndex(L"Bone_GetObjectSpacePos",BoneIndex) {
		return Bones[BoneIndex].ObjectSpacePos;
	}
	return DVector3(0.0f,0.0f,0.0f);
}

void ModelClass::Bone_SetParentSpacePos(int BoneIndex, DVector3 ParentSpacePos) {
	CheckBoneIndex(L"Bone_SetParentSpacePos",BoneIndex) {
		Bones[BoneIndex].ParentSpacePos = ParentSpacePos;
	}
}

void ModelClass::Bone_SetParentSpacePosX(int BoneIndex, float ParentSpacePosX) {
	CheckBoneIndex(L"Bone_SetParentSpaceX",BoneIndex) {
		Bones[BoneIndex].ParentSpacePos.x = ParentSpacePosX;
	}
}

void ModelClass::Bone_SetParentSpacePosY(int BoneIndex, float ParentSpacePosY) {
	CheckBoneIndex(L"Bone_SetParentSpaceY",BoneIndex) {
		Bones[BoneIndex].ParentSpacePos.y = ParentSpacePosY;
	}
}

void ModelClass::Bone_SetParentSpacePosZ(int BoneIndex, float ParentSpacePosZ) {
	CheckBoneIndex(L"Bone_SetParentSpaceZ",BoneIndex) {
		Bones[BoneIndex].ParentSpacePos.z = ParentSpacePosZ;
	}
}

DVector3 ModelClass::Bone_GetParentSpacePos(int BoneIndex) {
	CheckBoneIndex(L"Bone_GetParentSpacePos",BoneIndex) {
		return Bones[BoneIndex].ParentSpacePos;
	}
	return DVector3(0.0f,0.0f,0.0f);
}

void ModelClass::Bone_SetYAxis(int BoneIndex, DVector3 YAxis) {
	CheckBoneIndex(L"Bone_SetYAxis",BoneIndex) {
		Bones[BoneIndex].YAxis = YAxis;
	}
}

void ModelClass::Bone_SetYAxisX(int BoneIndex, float YAxisX) {
	CheckBoneIndex(L"Bone_SetYAxisX",BoneIndex) {
		Bones[BoneIndex].YAxis.x = YAxisX;
	}
}

void ModelClass::Bone_SetYAxisY(int BoneIndex, float YAxisY) {
	CheckBoneIndex(L"Bone_SetYAxisY",BoneIndex) {
		Bones[BoneIndex].YAxis.y = YAxisY;
	}
}

void ModelClass::Bone_SetYAxisZ(int BoneIndex, float YAxisZ) {
	CheckBoneIndex(L"Bone_SetYAxisZ",BoneIndex) {
		Bones[BoneIndex].YAxis.z = YAxisZ;
	}
}

DVector3 ModelClass::Bone_GetYAxis(int BoneIndex) {
	CheckBoneIndex(L"Bone_GetYAxis",BoneIndex) {
		return Bones[BoneIndex].YAxis;
	}
	return DVector3(0.0f,0.0f,0.0f);
}

void ModelClass::Bone_SetZAxis(int BoneIndex, DVector3 ZAxis) {
	CheckBoneIndex(L"Bone_SetZAxis",BoneIndex) {
		Bones[BoneIndex].ZAxis = ZAxis;
	}
}

void ModelClass::Bone_SetZAxisX(int BoneIndex, float ZAxisX) {
	CheckBoneIndex(L"Bone_SetZAxisX",BoneIndex) {
		Bones[BoneIndex].ZAxis.x = ZAxisX;
	}
}

void ModelClass::Bone_SetZAxisY(int BoneIndex, float ZAxisY) {
	CheckBoneIndex(L"Bone_SetZAxisY",BoneIndex) {
		Bones[BoneIndex].ZAxis.y = ZAxisY;
	}
}

void ModelClass::Bone_SetZAxisZ(int BoneIndex, float ZAxisZ) {
	CheckBoneIndex(L"Bone_SetZAxisZ",BoneIndex) {
		Bones[BoneIndex].ZAxis.z = ZAxisZ;
	}
}

DVector3 ModelClass::Bone_GetZAxis(int BoneIndex) {
	CheckBoneIndex(L"Bone_GetZAxis",BoneIndex) {
		return Bones[BoneIndex].ZAxis;
	}
	return DVector3(0.0f,0.0f,0.0f);
}

void ModelClass::Bone_SetUserData(int BoneIndex, DVector3 UserData) {
	CheckBoneIndex(L"Bone_SetUserData",BoneIndex) {
		Bones[BoneIndex].UserData = UserData;
	}
}

void ModelClass::Bone_SetUserDataX(int BoneIndex, float UserDataX) {
	CheckBoneIndex(L"Bone_SetUserDataX",BoneIndex) {
		Bones[BoneIndex].UserData.x = UserDataX;
	}
}

void ModelClass::Bone_SetUserDataY(int BoneIndex, float UserDataY) {
	CheckBoneIndex(L"Bone_SetUserDataY",BoneIndex) {
		Bones[BoneIndex].UserData.y = UserDataY;
	}
}

void ModelClass::Bone_SetUserDataZ(int BoneIndex, float UserDataZ) {
	CheckBoneIndex(L"Bone_SetUserDataZ",BoneIndex) {
		Bones[BoneIndex].UserData.z = UserDataZ;
	}
}

DVector3 ModelClass::Bone_GetUserData(int BoneIndex) {
	CheckBoneIndex(L"Bone_GetUserData",BoneIndex) {
		return Bones[BoneIndex].UserData;
	}
	return DVector3(0.0f,0.0f,0.0f);
}

SingleBone ModelClass::Bone_GetBone(int BoneIndex) {
	SingleBone Result;
	CheckBoneIndex(L"Bone_GetBone",BoneIndex) {
		Result.Start = DVector4(Bones[BoneIndex].ObjectSpacePos.x,Bones[BoneIndex].ObjectSpacePos.y,Bones[BoneIndex].ObjectSpacePos.z,Bones[BoneIndex].UserData.x);
		Result.YAxis = DVector4(Bones[BoneIndex].YAxis.x,Bones[BoneIndex].YAxis.y,Bones[BoneIndex].YAxis.z,Bones[BoneIndex].UserData.y);
		Result.ZAxis = DVector4(Bones[BoneIndex].ZAxis.x,Bones[BoneIndex].ZAxis.y,Bones[BoneIndex].ZAxis.z,Bones[BoneIndex].UserData.z);
		return Result;
	}
	Result.Start = DVector4(0.0f,0.0f,0.0f,0.0f);
	Result.YAxis = DVector4(0.0f,0.0f,0.0f,0.0f);
	Result.ZAxis = DVector4(0.0f,0.0f,0.0f,0.0f);
	return Result;
}

void ModelClass::ReallocateShapes(int newSize) {
	int i;
	Shape_Type* SwapArray;
	int oldSize;
	oldSize = AllocatedShapes;
	AllocatedShapes = newSize;
	SwapArray = Shapes;
	Shapes = new Shape_Type[AllocatedShapes];
	if (Shapes == NULL) {
		MQ->InsertMessage(L"ModelClass::ReallocateShapes: Allocation error while allocating a new Shape list.\n");
	}
	// Preserve
	LoopForwardLengthFromZero(i, AllocatedShapes) {
		if (i < oldSize) {
			Shapes[i] = SwapArray[i];
		}
	}
	SAFE_DELETE_ARRAY(SwapArray)
	SwapArray = NULL;
}

void ModelClass::ReleaseShape(int ShapeIndex) {
	SAFE_DELETE_ARRAY(Shapes[ShapeIndex].ShapeName)
	SAFE_DELETE_ARRAY(Shapes[ShapeIndex].Points)
}

void ModelClass::DeleteShape( int ShapeIndex ) {
	CheckShapeIndex(L"DeleteShape",ShapeIndex) {
		ReleaseShape(ShapeIndex);
		if (ShapeIndex < NumberOfShapes-1) {
			Shapes[ShapeIndex] = Shapes[NumberOfShapes-1];
		}
		NumberOfShapes--;
	}
}

void ModelClass::DeleteShape_PreserveOrder(int ShapeIndex) {
	int i;
	CheckShapeIndex(L"DeleteShape_PreserveOrder",ShapeIndex) {
		ReleaseShape(ShapeIndex);
		LoopForward(ShapeIndex, i, NumberOfShapes - 2) {
			Shapes[i] = Shapes[i + 1];
		}
		NumberOfShapes--;
	}
}

wchar_t* ModelClass::GetShapeName(int ShapeIndex) {
	CheckShapeIndex(L"GetShapeName",ShapeIndex) {
		return Shapes[ShapeIndex].ShapeName;
	}
	return L"";
}

void ModelClass::SetShapeName(int ShapeIndex, wchar_t* Name) {
	Try_Start_Model {
		CheckShapeIndex(L"SetShapeName",ShapeIndex) {
			Try_Start_Model {
				SAFE_DELETE_ARRAY(Shapes[ShapeIndex].ShapeName)
			} Try_Else_Model {
				MQ->InsertMessage(L"SetShapeName: Access violation while deleting the old name.\n");
				return;
			}
			Try_Start_Model {
				Shapes[ShapeIndex].ShapeName = CopyToNewString(Name);
			} Try_Else_Model {
				MQ->InsertMessage(L"SetShapeName: Access violation while duplicating the new name.\n");
				return;
			}
		}
	} Try_Else_Model {
		MQ->InsertMessage(L"SetShapeName: Access violation in the outer layer.\n");
		return;
	}
}

int ModelClass::GetNumberOfShapes(void) {
	return NumberOfShapes;
}

void ModelClass::Shape_SetShapeType(int ShapeIndex, int ShapeType) {
	CheckShapeIndex(L"Shape_SetShapeType",ShapeIndex) {
		Shapes[ShapeIndex].ShapeType = ShapeType;
	}
}

int ModelClass::Shape_GetShapeType(int ShapeIndex) {
	CheckShapeIndex(L"Shape_GetShapeType",ShapeIndex) {
		return Shapes[ShapeIndex].ShapeType;
	}
	return -1;
}

void ModelClass::Shape_SetCollisionType(int ShapeIndex, int CollisionType) {
	CheckShapeIndex(L"Shape_SetCollisionType",ShapeIndex) {
		Shapes[ShapeIndex].CollisionType = CollisionType;
	}
}

int ModelClass::Shape_GetCollisionType(int ShapeIndex) {
	CheckShapeIndex(L"Shape_GetCollisionType",ShapeIndex) {
		return Shapes[ShapeIndex].CollisionType;
	}
	return -1;
}

void ModelClass::Shape_SetRadius(int ShapeIndex, float Radius) {
	CheckShapeIndex(L"Shape_SetRadius",ShapeIndex) {
		Shapes[ShapeIndex].Radius = Radius;
	}
}

float ModelClass::Shape_GetRadius(int ShapeIndex) {
	CheckShapeIndex(L"Shape_GetRadius",ShapeIndex) {
		return Shapes[ShapeIndex].Radius;
	}
	return -1.0f;
}

void ModelClass::Shape_SetHalfWidth(int ShapeIndex, float HalfWidth) {
	CheckShapeIndex(L"Shape_SetHalfWidth",ShapeIndex) {
		Shapes[ShapeIndex].HalfWidth = HalfWidth;
	}
}

float ModelClass::Shape_GetHalfWidth(int ShapeIndex) {
	CheckShapeIndex(L"Shape_GetHalfWidth",ShapeIndex) {
		return Shapes[ShapeIndex].HalfWidth;
	}
	return -1.0f;
}

void ModelClass::Shape_SetHalfHeight(int ShapeIndex, float HalfHeight) {
	CheckShapeIndex(L"Shape_SetHalfHeight",ShapeIndex) {
		Shapes[ShapeIndex].HalfHeight = HalfHeight;
	}
}

float ModelClass::Shape_GetHalfHeight(int ShapeIndex) {
	CheckShapeIndex(L"Shape_GetHalfHeight",ShapeIndex) {
		return Shapes[ShapeIndex].HalfHeight;
	}
	return -1.0f;
}

void ModelClass::Shape_SetHalfDepth(int ShapeIndex, float HalfDepth) {
	CheckShapeIndex(L"Shape_SetHalfDepth",ShapeIndex) {
		Shapes[ShapeIndex].HalfDepth = HalfDepth;
	}
}

float ModelClass::Shape_GetHalfDepth(int ShapeIndex) {
	CheckShapeIndex(L"Shape_GetHalfDepth",ShapeIndex) {
		return Shapes[ShapeIndex].HalfDepth;
	}
	return -1.0f;
}

void ModelClass::Shape_SetPos(int ShapeIndex, DVector3 Pos) {
	CheckShapeIndex(L"Shape_SetPos",ShapeIndex) {
		Shapes[ShapeIndex].Pos = Pos;
	}
}

void ModelClass::Shape_SetPosX(int ShapeIndex, float PosX) {
	CheckShapeIndex(L"Shape_SetPosX",ShapeIndex) {
		Shapes[ShapeIndex].Pos.x = PosX;
	}
}

void ModelClass::Shape_SetPosY(int ShapeIndex, float PosY) {
	CheckShapeIndex(L"Shape_SetPosY",ShapeIndex) {
		Shapes[ShapeIndex].Pos.y = PosY;
	}
}

void ModelClass::Shape_SetPosZ(int ShapeIndex, float PosZ) {
	CheckShapeIndex(L"Shape_SetPosZ",ShapeIndex) {
		Shapes[ShapeIndex].Pos.z = PosZ;
	}
}

DVector3 ModelClass::Shape_GetPos(int ShapeIndex) {
	CheckShapeIndex(L"Shape_GetPos",ShapeIndex) {
		return Shapes[ShapeIndex].Pos;
	}
	return DVector3(0.0f,0.0f,0.0f);
}

void ModelClass::Shape_SetXAxis(int ShapeIndex, DVector3 XAxis) {
	CheckShapeIndex(L"Shape_SetXAxis",ShapeIndex) {
		Shapes[ShapeIndex].XAxis = XAxis;
	}
}

void ModelClass::Shape_SetXAxisX(int ShapeIndex, float XAxisX) {
	CheckShapeIndex(L"Shape_SetXAxisX",ShapeIndex) {
		Shapes[ShapeIndex].XAxis.x = XAxisX;
	}
}

void ModelClass::Shape_SetXAxisY(int ShapeIndex, float XAxisY) {
	CheckShapeIndex(L"Shape_SetXAxisY",ShapeIndex) {
		Shapes[ShapeIndex].XAxis.y = XAxisY;
	}
}

void ModelClass::Shape_SetXAxisZ(int ShapeIndex, float XAxisZ) {
	CheckShapeIndex(L"Shape_SetXAxisZ",ShapeIndex) {
		Shapes[ShapeIndex].XAxis.z = XAxisZ;
	}
}

DVector3 ModelClass::Shape_GetXAxis(int ShapeIndex) {
	CheckShapeIndex(L"Shape_GetXAxis",ShapeIndex) {
		return Shapes[ShapeIndex].XAxis;
	}
	return DVector3(0.0f,0.0f,0.0f);
}

void ModelClass::Shape_SetYAxis(int ShapeIndex, DVector3 YAxis) {
	CheckShapeIndex(L"Shape_SetYAxis",ShapeIndex) {
		Shapes[ShapeIndex].YAxis = YAxis;
	}
}

void ModelClass::Shape_SetYAxisX(int ShapeIndex, float YAxisX) {
	CheckShapeIndex(L"Shape_SetYAxisX",ShapeIndex) {
		Shapes[ShapeIndex].YAxis.x = YAxisX;
	}
}

void ModelClass::Shape_SetYAxisY(int ShapeIndex, float YAxisY) {
	CheckShapeIndex(L"Shape_SetYAxisY",ShapeIndex) {
		Shapes[ShapeIndex].YAxis.y = YAxisY;
	}
}

void ModelClass::Shape_SetYAxisZ(int ShapeIndex, float YAxisZ) {
	CheckShapeIndex(L"Shape_SetYAxisZ",ShapeIndex) {
		Shapes[ShapeIndex].YAxis.z = YAxisZ;
	}
}

DVector3 ModelClass::Shape_GetYAxis(int ShapeIndex) {
	CheckShapeIndex(L"Shape_GetYAxis",ShapeIndex) {
		return Shapes[ShapeIndex].YAxis;
	}
	return DVector3(0.0f,0.0f,0.0f);
}

void ModelClass::Shape_SetZAxis(int ShapeIndex, DVector3 ZAxis) {
	CheckShapeIndex(L"Shape_SetZAxis",ShapeIndex) {
		Shapes[ShapeIndex].ZAxis = ZAxis;
	}
}

void ModelClass::Shape_SetZAxisX(int ShapeIndex, float ZAxisX) {
	CheckShapeIndex(L"Shape_SetZAxisX",ShapeIndex) {
		Shapes[ShapeIndex].ZAxis.x = ZAxisX;
	}
}

void ModelClass::Shape_SetZAxisY(int ShapeIndex, float ZAxisY) {
	CheckShapeIndex(L"Shape_SetZAxisY",ShapeIndex) {
		Shapes[ShapeIndex].ZAxis.y = ZAxisY;
	}
}

void ModelClass::Shape_SetZAxisZ(int ShapeIndex, float ZAxisZ) {
	CheckShapeIndex(L"Shape_SetZAxisZ",ShapeIndex) {
		Shapes[ShapeIndex].ZAxis.z = ZAxisZ;
	}
}

DVector3 ModelClass::Shape_GetZAxis(int ShapeIndex) {
	CheckShapeIndex(L"Shape_GetZAxis",ShapeIndex) {
		return Shapes[ShapeIndex].ZAxis;
	}
	return DVector3(0.0f,0.0f,0.0f);
}

int ModelClass::Shape_GetNumberOfPoints(int ShapeIndex) {
	CheckShapeIndex(L"Shape_GetNumberOfPoints",ShapeIndex) {
		return Shapes[ShapeIndex].NumberOfPoints;
	}
	return -1;
}

DVector3 ModelClass::Shape_GetPoint(int ShapeIndex, int PointIndex) {
	CheckShapeIndex(L"Shape_GetPoint",ShapeIndex) {
		CheckPointIndex(L"Shape_GetPoint",ShapeIndex,PointIndex) {
			return Shapes[ShapeIndex].Points[PointIndex].Pos;
		}
	}
	return DVector3(0.0f,0.0f,0.0f);
}

DVector3 ModelClass::Shape_GetPointDir(int ShapeIndex, int PointIndex) {
	CheckShapeIndex(L"Shape_GetPointDir",ShapeIndex) {
		CheckPointIndex(L"Shape_GetPointDir",ShapeIndex,PointIndex) {
			return Shapes[ShapeIndex].Points[PointIndex].Dir;
		}
	}
	return DVector3(0.0f,0.0f,0.0f);
}

int ModelClass::CreateNewShape(wchar_t* strShapeName, int ShapeType) {
	// Add to the counter
	NumberOfShapes++;

	if (Shapes == NULL) {
		AllocatedShapes = 32;
		Shapes = new Shape_Type[AllocatedShapes];
		if (Shapes == NULL) {
			AllocatedShapes = 0;
			NumberOfShapes = 0;
			MQ->InsertMessage(L"ModelClass::CreateNewShape: Could not allocate a new shape.\n");
			return -1;
		}
	} else if (NumberOfShapes > AllocatedShapes) {
		ReallocateShapes(AllocatedShapes * 2);
	}

	// Fill the shape with data
	Shapes[NumberOfShapes-1].ShapeType = ShapeType;
	Shapes[NumberOfShapes-1].CollisionType = 0;
	Shapes[NumberOfShapes-1].Pos = DVector3(0.0f,0.0f,0.0f);
	Shapes[NumberOfShapes-1].XAxis = DVector3(1.0f,0.0f,0.0f);
	Shapes[NumberOfShapes-1].YAxis = DVector3(0.0f,1.0f,0.0f);
	Shapes[NumberOfShapes-1].ZAxis = DVector3(0.0f,0.0f,1.0f);
	Shapes[NumberOfShapes-1].Radius = 1.0f;
	Shapes[NumberOfShapes-1].HalfWidth = 1.0f;
	Shapes[NumberOfShapes-1].HalfHeight = 1.0f;
	Shapes[NumberOfShapes-1].HalfDepth = 1.0f;
	Shapes[NumberOfShapes-1].Points = NULL;
	Shapes[NumberOfShapes-1].NumberOfPoints = 0;
	Shapes[NumberOfShapes-1].AllocatedPoints = 0;
	Shapes[NumberOfShapes-1].ShapeName = CopyToNewString(strShapeName);

	// Return the shape index
	return NumberOfShapes - 1;
}

int ModelClass::Shape_InsertPointToShape( int ShapeIndex, DVector3 Pos ) {
	CheckShapeIndex(L"Shape_GetPoint",ShapeIndex) {
		// Add to the counter
		Shapes[ShapeIndex].NumberOfPoints++;
		if (Shapes[ShapeIndex].Points == NULL) {
			Shapes[ShapeIndex].AllocatedPoints = 32;
			Shapes[ShapeIndex].Points = new DirPoint_Type[Shapes[ShapeIndex].AllocatedPoints];
			if (Shapes[ShapeIndex].Points == NULL) {
				Shapes[ShapeIndex].AllocatedPoints = 0;
				Shapes[ShapeIndex].NumberOfPoints = 0;
				MQ->InsertMessage(L"ModelClass::Shape_InsertPointToShape: Could not allocate a new array of points.\n");
				return -1;
			}
		} else if (Shapes[ShapeIndex].NumberOfPoints > Shapes[ShapeIndex].AllocatedPoints) {
			SetPointArraySize(ShapeIndex, Shapes[ShapeIndex].AllocatedPoints * 2);
		}

		// Fill the new point with data
		Shapes[ShapeIndex].Points[Shapes[ShapeIndex].NumberOfPoints-1].Pos = Pos;
		Shapes[ShapeIndex].Points[Shapes[ShapeIndex].NumberOfPoints-1].Dir = DVector3(0.0f,0.0f,0.0f);

		// Return the point index
		return Shapes[ShapeIndex].NumberOfPoints-1;
	}
	return -1;
}

void ModelClass::SetPointArraySizeAux2(int ShapeIndex, int newSize) {
	Shapes[ShapeIndex].Points = new DirPoint_Type[newSize];
	if (Shapes[ShapeIndex].Points == NULL) {
		MQ->InsertMessage(L"ModelClass::SetPointArraySizeAux2: Allocation error while allocating a new point array.\n");
		return;
	}
}
void ModelClass::SetPointArraySizeAux(int ShapeIndex, int newSize) {
	int oldSize;
	int i;
	if (newSize < 1) {
		MQ->InsertMessage(L"ModelClass::SetPointArraySizeAux: newSize < 1.\n");
		return;
	}
	CheckShapeIndex(L"SetPointArraySize",ShapeIndex)
	Try_Start_Model {
		Try_Start_Model {
			OldPointBuffer = Shapes[ShapeIndex].Points;
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::SetPointArraySizeAux: Access violation while getting the old buffer.\n");
			return;
		}
		Try_Start_Model {
			oldSize = Shapes[ShapeIndex].AllocatedPoints;
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::SetPointArraySizeAux: Access violation while getting the old size.\n");
			return;
		}
		Try_Start_Model {
			Shapes[ShapeIndex].AllocatedPoints = newSize;
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::SetPointArraySizeAux: Access violation while assigning the new size.\n");
			return;
		}
		Try_Start_Model {
			SetPointArraySizeAux2(ShapeIndex,newSize);
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::SetPointArraySizeAux: Access violation while allocating a new point array.\n");
			return;
		}
		Try_Start_Model {
		if (Shapes[ShapeIndex].Points != NULL && OldPointBuffer != NULL && newSize != oldSize) {
			if (newSize > oldSize) {
				Try_Start_Model {
					LoopForwardLengthFromZero(i,oldSize) {
						Shapes[ShapeIndex].Points[i] = OldPointBuffer[i];
					}
				} Try_Else_Model {
					MQ->InsertMessage(L"ModelClass::SetPointArraySizeAux: Access violation while getting old data to a larger new point array.\n");
					return;
				}
			} else {
				Try_Start_Model {
					LoopForwardLengthFromZero(i,newSize) {
						Shapes[ShapeIndex].Points[i] = OldPointBuffer[i];
					}
				} Try_Else_Model {
					MQ->InsertMessage(L"ModelClass::SetPointArraySizeAux: Access violation while getting old data to a smaller new point array.\n");
					return;
				}
			}
		}
		} Try_Else_Model {
			MQ->InsertMessage(L"ModelClass::SetPointArraySizeAux: Access violation while checking if the point array is NULL.\n");
			return;
		}
	} Try_Else_Model {
		MQ->InsertMessage(L"ModelClass::SetPointArraySizeAux: Access violation in the outer layer.\n");
		return;
	}
}
void ModelClass::SetPointArraySize(int ShapeIndex, int newSize) {
	OldPointBuffer = NULL;
	SetPointArraySizeAux(ShapeIndex,newSize);
	SAFE_DELETE_ARRAY(OldPointBuffer)
}

void ModelClass::Shape_SetPoint(int ShapeIndex, int PointIndex, DVector3 Point) {
	CheckShapeIndex(L"Shape_SetPoint",ShapeIndex) {
		CheckPointIndex(L"Shape_SetPoint",ShapeIndex,PointIndex) {
			Shapes[ShapeIndex].Points[PointIndex].Pos = Point;
		}
	}
}

void ModelClass::Shape_SetPointX(int ShapeIndex, int PointIndex, float PointX) {
	CheckShapeIndex(L"Shape_SetPointX",ShapeIndex) {
		CheckPointIndex(L"Shape_SetPointX",ShapeIndex,PointIndex) {
			Shapes[ShapeIndex].Points[PointIndex].Pos.x = PointX;
		}
	}
}

void ModelClass::Shape_SetPointY(int ShapeIndex, int PointIndex, float PointY) {
	CheckShapeIndex(L"Shape_SetPointY",ShapeIndex) {
		CheckPointIndex(L"Shape_SetPointY",ShapeIndex,PointIndex) {
			Shapes[ShapeIndex].Points[PointIndex].Pos.y = PointY;
		}
	}
}

void ModelClass::Shape_SetPointZ(int ShapeIndex, int PointIndex, float PointZ) {
	CheckShapeIndex(L"Shape_SetPointZ",ShapeIndex) {
		CheckPointIndex(L"Shape_SetPointZ",ShapeIndex,PointIndex) {
			Shapes[ShapeIndex].Points[PointIndex].Pos.z = PointZ;
		}
	}
}

void ModelClass::Shape_SetPointDir(int ShapeIndex, int PointIndex, DVector3 Dir) {
	CheckShapeIndex(L"Shape_SetPointDir",ShapeIndex) {
		CheckPointIndex(L"Shape_SetPointDir",ShapeIndex,PointIndex) {
			Shapes[ShapeIndex].Points[PointIndex].Dir = Dir;
		}
	}
}

void ModelClass::Shape_SetPointDirX(int ShapeIndex, int PointIndex, float DirX) {
	CheckShapeIndex(L"Shape_SetPointDirX",ShapeIndex) {
		CheckPointIndex(L"Shape_SetPointDirX",ShapeIndex,PointIndex) {
			Shapes[ShapeIndex].Points[PointIndex].Dir.x = DirX;
		}
	}
}

void ModelClass::Shape_SetPointDirY(int ShapeIndex, int PointIndex, float DirY) {
	CheckShapeIndex(L"Shape_SetPointDirY",ShapeIndex) {
		CheckPointIndex(L"Shape_SetPointDirY",ShapeIndex,PointIndex) {
			Shapes[ShapeIndex].Points[PointIndex].Dir.y = DirY;
		}
	}
}

void ModelClass::Shape_SetPointDirZ(int ShapeIndex, int PointIndex, float DirZ) {
	CheckShapeIndex(L"Shape_SetPointDirZ",ShapeIndex) {
		CheckPointIndex(L"Shape_SetPointDirZ",ShapeIndex,PointIndex) {
			Shapes[ShapeIndex].Points[PointIndex].Dir.z = DirZ;
		}
	}
}

void ModelClass::Shape_DeletePoint(int ShapeIndex, int PointIndex) {
	int LastPointIndex;
	CheckShapeIndex(L"Shape_DeletePoint",ShapeIndex) {
		CheckPointIndex(L"Shape_DeletePoint",ShapeIndex,PointIndex) {
			LastPointIndex = Shapes[ShapeIndex].NumberOfPoints - 1;
			if (PointIndex < LastPointIndex) {
				Shapes[ShapeIndex].Points[PointIndex] = Shapes[ShapeIndex].Points[LastPointIndex];
			}
			Shapes[ShapeIndex].NumberOfPoints--;
		}
	}
}

void ModelClass::Shape_DeletePoint_PreserveOrder(int ShapeIndex, int PointIndex) {
	int CurrentPointIndex;
	CheckShapeIndex(L"Shape_DeletePoint",ShapeIndex) {
		CheckPointIndex(L"Shape_DeletePoint",ShapeIndex,PointIndex) {
			LoopForward(PointIndex,CurrentPointIndex,Shapes[ShapeIndex].NumberOfPoints - 2) {
				Shapes[ShapeIndex].Points[CurrentPointIndex] = Shapes[ShapeIndex].Points[CurrentPointIndex + 1];
			}
			Shapes[ShapeIndex].NumberOfPoints--;
		}
	}
}

void ModelClass::SwapShapeOrder( int ShapeIndexA, int ShapeIndexB ) {
	Shape_Type Swap;
	CheckShapeIndex(L"SwapShapeOrder",ShapeIndexA) { CheckShapeIndex(L"SwapShapeOrder",ShapeIndexB) {
		Swap = Shapes[ShapeIndexA];
		Shapes[ShapeIndexA] = Shapes[ShapeIndexB];
		Shapes[ShapeIndexB] = Swap;
	} }
}

void ModelClass::SwapPointOrder( int ShapeIndex, int PointIndexA, int PointIndexB ) {
	DirPoint_Type Swap;
	CheckShapeIndex(L"SwapShapeOrder",ShapeIndex) { CheckPointIndex(L"SwapShapeOrder",ShapeIndex,PointIndexA) { CheckPointIndex(L"SwapShapeOrder",ShapeIndex,PointIndexB) {
		Swap = Shapes[ShapeIndex].Points[PointIndexA];
		Shapes[ShapeIndex].Points[PointIndexA] = Shapes[ShapeIndex].Points[PointIndexB];
		Shapes[ShapeIndex].Points[PointIndexB] = Swap;
	} } }
}
