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

#pragma once

#include "PointerArray.h"
#include "QuadAllocator.h"
#include "Model.h"
#include "../GlobalConstants.h"
#include "../MessageQueue.h"
#include "SoundClass.h"
#include "Physics_FourChannelHeightField.h"
#include "Physics_ModifiedCompound.h"
#include "Physics_ModifiedWorld.h"
#include "../ContactBuffer.h"

// Trap access violation
#define Try_Start __try
#define Try_Else __except(Filter(GetExceptionCode(), GetExceptionInformation()))

#define INPUT_ELEMENT(REGISTER,TYPE) { #REGISTER, 0, TYPE, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }

#define DEC_DEFAULT_METHODS(NAME) \
	void Delete_##NAME(NAME##_Struct* Reference);

#define COMMON_COLLECTION_DEC(NAME) \
	PointerArray m_##NAME; \
	NAME##_Struct* NAME##_GarbagePile; \
	int m_numberOf##NAME; \
	void NAME##_Struct_Release(NAME##_Struct* Reference); \
	void NAME##_CleanUpGarbagePile(void); \
	NAME##_Struct* ##NAME##_PointerFromID(int ID, bool AllowNull); \
	void NAME##_LeaveMemory(NAME##_Struct* NewItem); \
	NAME##_Struct* NAME##_GetMemory(void);

#define DEFAULT_VERTEX_SHADER_INIT(NAME) NAME.pVertexLayout = NULL; NAME.pVertexShader = NULL;
#define DEFAULT_PIXEL_SHADER_INIT(NAME) NAME.pPixelShader = NULL;
#define DEFAULT_VERTEX_SHADER_RELEASE(NAME) SAFE_RELEASE(NAME.pVertexLayout) SAFE_RELEASE(NAME.pVertexShader)
#define DEFAULT_PIXEL_SHADER_RELEASE(NAME) SAFE_RELEASE(NAME.pPixelShader)
#define DISCONNECT(NAME,ERROR_MESSAGE) \
	Try_Start { \
		if (NAME != NULL) { StopUsing(NAME->useCount); } NAME = NULL; \
	} Try_Else { \
		::MessageBoxW(NULL,ERROR_MESSAGE,L"Error!",NULL); \
	}
#define MAKECONSTANTBUFFER(TYPE,NAME,ERROR_MESSAGE) \
	if (FAILED(m_pd3dDevice->CreateBuffer( &MakeBufferDesc(sizeof(TYPE)), NULL, &NAME ))) { \
		MQ->InsertMessage(ERROR_MESSAGE); \
		return false; \
	}
#define MAKERASTERIZER(CONTENT,NAME,ERROR_MESSAGE) \
	if (FAILED(m_pd3dDevice->CreateRasterizerState( &CONTENT, &NAME ))) { \
		MQ->InsertMessage(ERROR_MESSAGE); \
		return false; \
	}

// Data collection macros
	// Variables
		#define CORE_DATA_VAR_DECLARE(DATATYPE,IDENTIFIER,DEFAULTVALUE) DATATYPE IDENTIFIER;
		#define CORE_DATA_VAR_INIT(DATATYPE,IDENTIFIER,DEFAULTVALUE) IDENTIFIER = DEFAULTVALUE;
		#define CORE_DATA_VAR_ALLOCATE(DATATYPE,IDENTIFIER,DEFAULTVALUE) ;
		#define CORE_DATA_VAR_RELEASE(DATATYPE,IDENTIFIER,DEFAULTVALUE) ;
	// Fixed size arrays
		#define CORE_DATA_ARRAY_DECLARE(DATATYPE,IDENTIFIER,ARRAY_SIZE) DATATYPE IDENTIFIER[ARRAY_SIZE];
		#define CORE_DATA_ARRAY_INIT(DATATYPE,IDENTIFIER,ARRAY_SIZE) memset(&(IDENTIFIER),0,sizeof(DATATYPE) * ARRAY_SIZE);
		#define CORE_DATA_ARRAY_ALLOCATE(DATATYPE,IDENTIFIER,ARRAY_SIZE) ;
		#define CORE_DATA_ARRAY_RELEASE(DATATYPE,IDENTIFIER,ARRAY_SIZE) ;
	// Pointers
		#define CORE_DATA_PTR_DECLARE(DATATYPE,IDENTIFIER,ALLOCATE,RELEASE) DATATYPE IDENTIFIER;
		#define CORE_DATA_PTR_INIT(DATATYPE,IDENTIFIER,ALLOCATE,RELEASE) IDENTIFIER = NULL;
		#define CORE_DATA_PTR_ALLOCATE(DATATYPE,IDENTIFIER,ALLOCATE,RELEASE) ALLOCATE;
#define CORE_DATA_PTR_RELEASE(DATATYPE,IDENTIFIER,ALLOCATE,RELEASE) Try_Start { RELEASE; } Try_Else { ::MessageBoxW(NULL,L#IDENTIFIER,L"Releasing the following pointer caused access violation.",NULL); }
	// Anything else
		#define CORE_DATA_ANY_DECLARE(NAME,DECLARATION,INIT,ALLOCATE,RELEASE) DECLARATION;
		#define CORE_DATA_ANY_INIT(NAME,DECLARATION,INIT,ALLOCATE,RELEASE) INIT;
		#define CORE_DATA_ANY_ALLOCATE(NAME,DECLARATION,INIT,ALLOCATE,RELEASE) ALLOCATE;
		#define CORE_DATA_ANY_RELEASE(NAME,DECLARATION,INIT,ALLOCATE,RELEASE) Try_Start { RELEASE; } Try_Else { ::MessageBoxW(NULL,L#NAME,L"Releasing the following data caused access violation.",NULL); }
// The table
#define CORE_DATA_TABLE(SUBMACRO) \
	CORE_DATA_VAR_##SUBMACRO(int,m_SeenInstances,0) \
	CORE_DATA_VAR_##SUBMACRO(int,m_SeenLightSources,0) \
	CORE_DATA_VAR_##SUBMACRO(int,m_CulledLightSources,0) \
	CORE_DATA_VAR_##SUBMACRO(int,m_CulledInstances,0) \
	CORE_DATA_VAR_##SUBMACRO(float,m_DepthAtlas_PartUsed,0.0f) \
	CORE_DATA_VAR_##SUBMACRO(int,m_DepthAtlas_DeniedAllocation,0) \
	CORE_DATA_VAR_##SUBMACRO(int,m_lenReferences,128) \
	CORE_DATA_VAR_##SUBMACRO(int,m_usedReferences,1) \
	CORE_DATA_VAR_##SUBMACRO(int,m_ParserState,0) \
	CORE_DATA_VAR_##SUBMACRO(int,m_ParserSpace,0) \
	CORE_DATA_VAR_##SUBMACRO(int,m_Parser_LastIndex,0) \
	CORE_DATA_VAR_##SUBMACRO(int,m_preCalculatedLength,0) \
	CORE_DATA_VAR_##SUBMACRO(float,m_GlobalTime,0) \
	CORE_DATA_VAR_##SUBMACRO(float,m_FarClipPlane,100.0f) \
	CORE_DATA_VAR_##SUBMACRO(float,m_NearClipPlane,0.01f) \
	CORE_DATA_VAR_##SUBMACRO(float,m_MaxFogIntensity,0.0f) \
	CORE_DATA_VAR_##SUBMACRO(float,m_MediumHighDetailLimit,25.0f) \
	CORE_DATA_VAR_##SUBMACRO(float,m_LowMediumDetailLimit,50.0f) \
	CORE_DATA_VAR_##SUBMACRO(float,m_Sound_MetersPerDistanceUnit,1.0f) \
	CORE_DATA_VAR_##SUBMACRO(float,m_DebugDrawRadius,10.0f) \
	CORE_DATA_VAR_##SUBMACRO(bool,m_ArgumentBufferIsDirty,true) \
	CORE_DATA_VAR_##SUBMACRO(bool,m_Running,false) \
	CORE_DATA_VAR_##SUBMACRO(bool,m_HasRenderedToFinalSurface,false) \
	CORE_DATA_VAR_##SUBMACRO(bool,m_CollectGarbage,true) \
	CORE_DATA_VAR_##SUBMACRO(bool,m_AutomaticSwapChain,true) \
	CORE_DATA_VAR_##SUBMACRO(bool,m_SilentTermination,false) \
	CORE_DATA_VAR_##SUBMACRO(D3D_FEATURE_LEVEL,m_featureLevel,D3D_FEATURE_LEVEL_11_0) \
	CORE_DATA_VAR_##SUBMACRO(DVector4,m_vBackgroundColor,DVector4( 0.0f, 0.0f, 0.0f, 1.0f )) \
	CORE_DATA_VAR_##SUBMACRO(DVector4,m_Draw_Color,DVector4( 1.0f, 1.0f, 1.0f, 1.0f )) \
	CORE_DATA_VAR_##SUBMACRO(DVector4,m_Draw_SrcRectUV1,DVector4( 0.0f, 1.0f, 0.0f, 1.0f )) \
	CORE_DATA_VAR_##SUBMACRO(DVector4,m_Draw_SrcRectUV2,DVector4( 0.0f, 1.0f, 0.0f, 1.0f )) \
	CORE_DATA_VAR_##SUBMACRO(DVector3,m_AmbientLight,DVector3(1.0f, 1.0f, 1.0f)) \
	CORE_DATA_VAR_##SUBMACRO(DVector3,m_Sound_ListenerPosition,DVector3(0.0f,0.0f,0.0f)) \
	CORE_DATA_VAR_##SUBMACRO(HWND,m_hWnd,0) \
	CORE_DATA_ANY_##SUBMACRO(m_PostEffectVS,VertexShader m_PostEffectVS,DEFAULT_VERTEX_SHADER_INIT(m_PostEffectVS),m_PostEffectVS = Shader_CreateVSFromString(CommonPostEffectVertexShader,ShaderType_PostEffect),DEFAULT_VERTEX_SHADER_RELEASE(m_PostEffectVS)) \
	CORE_DATA_ANY_##SUBMACRO(m_DrawVS,VertexShader m_DrawVS,DEFAULT_VERTEX_SHADER_INIT(m_DrawVS),m_DrawVS = Shader_CreateVSFromString(CommonDrawVertexShader,ShaderType_Draw),DEFAULT_VERTEX_SHADER_RELEASE(m_DrawVS)) \
	CORE_DATA_ANY_##SUBMACRO(m_LineVS,VertexShader m_LineVS,DEFAULT_VERTEX_SHADER_INIT(m_LineVS),m_LineVS = Shader_CreateVSFromString(LineVertexShader,ShaderType_Line),DEFAULT_VERTEX_SHADER_RELEASE(m_LineVS)) \
	CORE_DATA_ANY_##SUBMACRO(m_LinePS,PixelShader m_LinePS,DEFAULT_PIXEL_SHADER_INIT(m_LinePS),m_LinePS = Shader_CreatePSFromString(LinePixelShader,ShaderType_Line),DEFAULT_PIXEL_SHADER_RELEASE(m_LinePS)) \
	CORE_DATA_ANY_##SUBMACRO(m_DepthAtlas,DepthBuffer_Struct m_DepthAtlas,ZeroMemory( &m_DepthAtlas, sizeof( DepthBuffer_Struct ) );DepthBuffer_InitEmpty(&m_DepthAtlas),;,DepthBuffer_Release(&m_DepthAtlas)) \
	CORE_DATA_ANY_##SUBMACRO(m_SurfaceScreen,DrawSurface_Struct m_SurfaceScreen,ZeroMemory( &m_SurfaceScreen, sizeof( DrawSurface_Struct ) );DrawSurface_InitEmpty(&m_SurfaceScreen),;,DrawSurface_Struct_Release(&m_SurfaceScreen)) \
	CORE_DATA_ARRAY_##SUBMACRO(int,m_PostEffect_InputTextures,16) \
	CORE_DATA_ARRAY_##SUBMACRO(int,m_PostEffect_InputTextureSubresourceTypes,16) \
	CORE_DATA_ARRAY_##SUBMACRO(int,m_Draw_InputTextures,16) \
	CORE_DATA_ARRAY_##SUBMACRO(wchar_t,m_Parser_LastPropertyName,260) \
	CORE_DATA_ARRAY_##SUBMACRO(wchar_t,m_Parser_LastPropertyContent,260) \
	CORE_DATA_ARRAY_##SUBMACRO(wchar_t,m_Parser_LastNameSpace,260) \
	CORE_DATA_ARRAY_##SUBMACRO(wchar_t,m_Parser_ModelPath,260) \
	CORE_DATA_ARRAY_##SUBMACRO(DVector4,m_PostEffect_InputArguments,NumberOfUserVectorsPerPostEffect) \
	CORE_DATA_ARRAY_##SUBMACRO(DVector4,m_Draw_InputArguments,NumberOfUserVectorsPerDrawing) \
	CORE_DATA_PTR_##SUBMACRO(Shader_Struct*,m_pDefaultMaterialShader,;,;) \
	CORE_DATA_PTR_##SUBMACRO(Texture_Struct*,m_pLightProjectionAtlas,;,;) \
	CORE_DATA_PTR_##SUBMACRO(Texture_Struct*,m_pDefaultTexture,;,;) \
	CORE_DATA_PTR_##SUBMACRO(Instance_Struct*,m_pSkyInstance,;,;) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Buffer*,m_pCBEveryRender,MAKECONSTANTBUFFER(CBEveryRender,m_pCBEveryRender,L"Could not create the every render constant buffer."),SAFE_RELEASE(m_pCBEveryRender)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Buffer*,m_pCBEveryObject,MAKECONSTANTBUFFER(CBEveryObject,m_pCBEveryObject,L"Could not create the every object constant buffer."),SAFE_RELEASE(m_pCBEveryObject)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Buffer*,m_pCBArgBuffer,MAKECONSTANTBUFFER(CBArgBuffer,m_pCBArgBuffer,L"Could not create the argument constant buffer."),SAFE_RELEASE(m_pCBArgBuffer)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Buffer*,m_pCBPostEffect,MAKECONSTANTBUFFER(CBPostEffect,m_pCBPostEffect,L"Could not create the post effect constant buffer."),SAFE_RELEASE(m_pCBPostEffect)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Buffer*,m_pCBDraw,MAKECONSTANTBUFFER(CBDraw,m_pCBDraw,L"Could not create the draw shader constant buffer."),SAFE_RELEASE(m_pCBDraw)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Buffer*,m_pCBBoneFrame_8,MAKECONSTANTBUFFER(CBBoneFrame_8,m_pCBBoneFrame_8,L"Could not create the bone frame constant buffer for up to 8 bones."),SAFE_RELEASE(m_pCBBoneFrame_8)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Buffer*,m_pCBBoneFrame_16,MAKECONSTANTBUFFER(CBBoneFrame_16,m_pCBBoneFrame_16,L"Could not create the bone frame constant buffer for up to 16 bones."),SAFE_RELEASE(m_pCBBoneFrame_16)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Buffer*,m_pCBBoneFrame_32,MAKECONSTANTBUFFER(CBBoneFrame_32,m_pCBBoneFrame_32,L"Could not create the bone frame constant buffer for up to 32 bones."),SAFE_RELEASE(m_pCBBoneFrame_32)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Buffer*,m_pCBBoneFrame_64,MAKECONSTANTBUFFER(CBBoneFrame_64,m_pCBBoneFrame_64,L"Could not create the bone frame constant buffer for up to 64 bones."),SAFE_RELEASE(m_pCBBoneFrame_64)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Buffer*,m_pCBEveryDebugRender,MAKECONSTANTBUFFER(CBEveryDebugRender,m_pCBEveryDebugRender,L"Could not create the every debug draw constant buffer."),SAFE_RELEASE(m_pCBEveryDebugRender)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11RasterizerState*,m_StateFrontFace,MAKERASTERIZER(MakeRasterizerDesc(D3D11_CULL_FRONT,true,D3D11_FILL_SOLID),m_StateFrontFace,L"Could not create the front face raster state."),SAFE_RELEASE(m_StateFrontFace)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11RasterizerState*,m_StateBackFace,MAKERASTERIZER(MakeRasterizerDesc(D3D11_CULL_BACK,true,D3D11_FILL_SOLID),m_StateBackFace,L"Could not create the back face raster state."),SAFE_RELEASE(m_StateBackFace)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11RasterizerState*,m_StateDoubleFace,MAKERASTERIZER(MakeRasterizerDesc(D3D11_CULL_NONE,true,D3D11_FILL_SOLID),m_StateDoubleFace,L"Could not create the double face raster state."),SAFE_RELEASE(m_StateDoubleFace)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11RasterizerState*,m_StateDoubleFaceNoDepthClip,MAKERASTERIZER(MakeRasterizerDesc(D3D11_CULL_NONE,false,D3D11_FILL_SOLID),m_StateDoubleFaceNoDepthClip,L"Could not create the double face no depth clip raster state."),SAFE_RELEASE(m_StateDoubleFaceNoDepthClip)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11RasterizerState*,m_StateWireFrame,MAKERASTERIZER(MakeRasterizerDesc(D3D11_CULL_NONE,false,D3D11_FILL_WIREFRAME),m_StateWireFrame,L"Could not create the wireframe raster state."),SAFE_RELEASE(m_StateWireFrame)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11SamplerState*,m_pSamConstant,if (FAILED(CreateSampler(false, false, 0, false,&m_pSamConstant))) { MQ->InsertMessage(L"Could not create the sampler m_pSamConstant."); return false; },SAFE_RELEASE(m_pSamConstant)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11SamplerState*,m_pSamSharp,if (FAILED(CreateSampler(false, true, 0, false,&m_pSamSharp))) { MQ->InsertMessage(L"Could not create the sampler m_pSamSharp."); return false; },SAFE_RELEASE(m_pSamSharp)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11SamplerState*,m_pSamAnisotropicMipmap,if (FAILED(CreateSampler(false, true, 7, true,&m_pSamAnisotropicMipmap))) { MQ->InsertMessage(L"Could not create the sampler m_pSamAnisotropicMipmap."); return false; },SAFE_RELEASE(m_pSamAnisotropicMipmap)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11SamplerState*,m_pSamMipmap,if (FAILED(CreateSampler(false, true, 0, true,&m_pSamMipmap))) { MQ->InsertMessage(L"Could not create the sampler m_pSamMipmap."); return false; },SAFE_RELEASE(m_pSamMipmap)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11SamplerState*,m_pSamClampedConstant,if (FAILED(CreateSampler(true, false, 0, false,&m_pSamClampedConstant))) { MQ->InsertMessage(L"Could not create the sampler m_pSamClampedConstant."); return false; },SAFE_RELEASE(m_pSamClampedConstant)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11SamplerState*,m_pSamClampedSharp,if (FAILED(CreateSampler(true, true, 0, false,&m_pSamClampedSharp))) { MQ->InsertMessage(L"Could not create the sampler m_pSamClampedSharp."); return false; },SAFE_RELEASE(m_pSamClampedSharp)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11SamplerState*,m_pSamShadow,if (FAILED(m_pd3dDevice->CreateSamplerState( &ConstSamDescShad, &m_pSamShadow ))) { MQ->InsertMessage(L"Could not create the sampler m_pSamShadow."); return false; },SAFE_RELEASE(m_pSamShadow)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11DepthStencilState*,m_pDepthStencilDefault,if (FAILED(m_pd3dDevice->CreateDepthStencilState(&MakeDepthStencilDesc(D3D11_DEPTH_WRITE_MASK_ALL), &m_pDepthStencilDefault))) { MQ->InsertMessage(L"Could not create the default depth stencil state."); return false; },SAFE_RELEASE(m_pDepthStencilDefault)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11DepthStencilState*,m_pDepthStencilDisableDepthWrite,if (FAILED(m_pd3dDevice->CreateDepthStencilState(&MakeDepthStencilDesc(D3D11_DEPTH_WRITE_MASK_ZERO), &m_pDepthStencilDisableDepthWrite))) { MQ->InsertMessage(L"Could not create the read only depth stencil state."); return false; },SAFE_RELEASE(m_pDepthStencilDisableDepthWrite)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11BlendState*,m_pBS_AlphaFilter,if (FAILED(m_pd3dDevice->CreateBlendState( &MakeBlendDesc(), &m_pBS_AlphaFilter ))) { MQ->InsertMessage(L"Could not create the alpha filter blend state."); return false; },SAFE_RELEASE(m_pBS_AlphaFilter)) \
	CORE_DATA_PTR_##SUBMACRO(QuadAllocator*,m_pDepthAltasQuadAllocator,m_pDepthAltasQuadAllocator = new QuadAllocator(),SAFE_DELETE(m_pDepthAltasQuadAllocator)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Texture2D*,m_pSinglePixelCPUOutput,if (FAILED(m_pd3dDevice->CreateTexture2D( &ConstStaged1x1Desc, NULL, &m_pSinglePixelCPUOutput ))) { MQ->InsertMessage(L"Could not create the single pixel CPU output buffer."); return false; },SAFE_RELEASE(m_pSinglePixelCPUOutput)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Texture2D*,m_pSinglePixelCPUInput,if (FAILED(m_pd3dDevice->CreateTexture2D( &ConstDynamic1x1Desc, NULL, &m_pSinglePixelCPUInput ))) { MQ->InsertMessage(L"Could not create the single pixel CPU input buffer."); return false; },SAFE_RELEASE(m_pSinglePixelCPUInput)) \
	CORE_DATA_PTR_##SUBMACRO(ID3D11Buffer*,m_pQuad_VertexBuffer,if (FAILED(CreateFullScreenQuad(&m_pQuad_VertexBuffer))) { MQ->InsertMessage(L"Could not create the effect quad."); return false; },SAFE_RELEASE(m_pQuad_VertexBuffer)) \
	CORE_DATA_PTR_##SUBMACRO(IDirectSound8*,m_pSoundEngineInterface,;,;) \
	CORE_DATA_PTR_##SUBMACRO(IDirectSoundBuffer*,m_pMixingBuffer,;,;) \
	CORE_DATA_PTR_##SUBMACRO(IDirectSound3DListener8*,m_pListener,;,;)

// This may not change the connection between type and number
// New types must be documented for Engine_GetTypeFromID
#define ColType_None 0
#define ColType_Texture 1
#define ColType_DrawSurface 2
#define ColType_Instance 3
#define ColType_Model 4
#define ColType_Camera 5
#define ColType_Shader 6
#define ColType_LightSource 7
#define ColType_CPUSurface 8
#define ColType_SoundBuffer 9
#define ColType_BoneFrame 10
#define ColType_Constraint 11
#define ColType_RigidBody 12
#define ColType_CollisionShape 13

// All collections in order of releasing
#define COLLECTION_TABLE(METHOD) \
	METHOD(Instance) \
	METHOD(Model) \
	METHOD(Texture) \
	METHOD(DrawSurface) \
	METHOD(Camera) \
	METHOD(Shader) \
	METHOD(LightSource) \
	METHOD(SoundBuffer) \
	METHOD(BoneFrame) \
	METHOD(Constraint) \
	METHOD(RigidBody) \
	METHOD(CollisionShape) \
	METHOD(CPUSurface)

class DebugDrawer;
class EngineCore;
struct Model_Struct;
struct SoundBuffer_Struct;
struct Instance_Struct;
struct Camera_Struct;
struct LightSource_Struct;
struct CPUSurface_Struct;
struct CollisionShape_Struct;
struct RigidBody_Struct;
struct Constraint_Struct;
struct PhysicsCore;

struct ReferenceTable {
	bool Valid;
	int CollectionType;
	void* pointer;
};

struct VertexStructure_Quad {
	DVector3 Pos;
};

struct VertexStructure_Line {
	DVector3 Pos;
	DVector3 Color;
};

// This struct is only used for casting pointers
struct Abstract_Struct {
	COLLECTION_STRUCT_DATA(Abstract)
};

struct SoundBuffer_Struct {
	COLLECTION_STRUCT_DATA(SoundBuffer)
	SoundClass* Buffer;
};

struct Instance_Struct {
	COLLECTION_STRUCT_DATA(Instance)
	Model_Struct* VisualModel;
	BoneFrame_Struct* BoneFrame;
	int DetailLevel_Int;
	float DetailLevel_Float;
	bool Visible[NumberOfShaderChannels];
	bool AutoDetailLevel;
	bool Mirrored;
	bool ModifiedArguments;
	RigidBody_Struct* FollowedRigidBody;
		bool UseLocalScaling;
		DoubleLinkListBody<Instance_Struct> LL_Follow;
	DMatrix Transformation;
	DVector4 UserProperties_Instance[NumberOfUserVectorsPerInstance];
	DVector4 Color;
	SurfaceCombo OverrideSurfaces[NumberOfOverrideChannels];
};

struct Camera_Struct {
	COLLECTION_STRUCT_DATA(Camera)
	DVector3						Eye;
	DVector3						At;
	DVector3						Up;
	float							FieldOfView;
	bool							VerticalFieldOfView;
	bool							IsOrthogonal;
	bool							EnableCuttingPlane;
	UINT16							DebugDraw; // Bitmask with the DebugDraw_? constants
	DVector4						CuttingPlane;
	float							RefractiveMultiplier;
	// Below is not persistent data
	DMatrix						WorldToCamera;
	DMatrix						RefractedWorldToCamera;
	DMatrix						CameraToImage;
	float							WidthSlope;
	float							HeightSlope;
	float							OrthogonalHalfWidth;
	float							OrthogonalHalfHeight;
	float							NearClipPlane;
	float							FarClipPlane;
};

struct LightSource_Struct {
	COLLECTION_STRUCT_DATA(LightSource)
	LightSource ShaderData;
	int ShadowlessType;
	int ResolutionGroup; //0..4 How many times will the depth atlas be divided by 4
	bool HasDepthTile;
	bool WantDepthTile;
	bool SeenThisRender;
	bool IsOrthogonal;
	bool EnabledByUser; // Only visible if the user choose it
	float OutsideIntensity; //Used in ShaderData.ZWCorrection.x
	float FadeSize; //Used in ShaderData.ZWCorrection.y
};

// Forward declaration
struct CollisionShape_Struct;
struct RigidBody_Struct;

struct CPUSurface_Struct {
	COLLECTION_STRUCT_DATA(CPUSurface)
	
	ID3D11Texture2D* StagingBuffer;
	
	// Index = X + (Y * Width)
	// Size = Width * Height
	DVector4* CPUContent;
	
	// Dimensions
	int Width;
	int Height;
	
	DoubleLinkListHead<CollisionShape_Struct> LL_HeightField;
	DoubleLinkListBody<CPUSurface_Struct> LL_ModifiedCPUSurface;
};

struct CollisionShape_Struct {
	COLLECTION_STRUCT_DATA(CollisionShape)
	int ShapeType;
	CPUSurface_Struct* CPUSurface;
	btCollisionShape* CollisionShape;
	btVector3 LocalInertiaPerMass;
	bool HasValidLocalInertiaPerMass;
	bool HasCompoundParent;
	DoubleLinkListHead<RigidBody_Struct> LL_BodyUseShape;
	DoubleLinkListBody<CollisionShape_Struct> LL_HeightField;
	DoubleLinkListBody<CollisionShape_Struct> LL_ModifiedShape;
};

struct RigidBody_Struct {
	COLLECTION_STRUCT_DATA(RigidBody)
	btRigidBody* Body;
	CollisionShape_Struct* CollisionShape;
	bool Dynamic;
	float LinearMass;
	DVector3 LocalInertia;
	DoubleLinkListBody<RigidBody_Struct> LL_BodyUseShape;
	DoubleLinkListHead<Instance_Struct> LL_Follow;
	int UserData[NumberOfUserElementsPerRigidBody];
};

struct Constraint_Struct {
	COLLECTION_STRUCT_DATA(Constraint)
	int ConstraintType;
	RigidBody_Struct* BodyA;
	RigidBody_Struct* BodyB;
	btTypedConstraint* Constraint;
};

struct Model_Struct {
	COLLECTION_STRUCT_DATA(Model)
	ModelClass Model;
};

struct PhysicsCore {
	// The Bullet physics engine
	btDefaultCollisionConfiguration* collisionConfiguration;
	btCollisionDispatcher* dispatcher;
	btDbvtBroadphase* overlappingPairCache;
	btSequentialImpulseConstraintSolver* solver;
	ModifiedWorld* dynamicsWorld;
	DebugDrawer* debugDrawer;
};
void Physics_Init(PhysicsCore* Core, EngineCore* NewEngineCore);
void Physics_Terminate(PhysicsCore* Core);

class EngineCore {
public:
	// Internal methods
	bool LoadPrecompiledShader(wchar_t* Filename, UINT64 CheckSum, ByteArray** BinaryShader);
	bool SavePrecompiledShader(wchar_t* Filename, UINT64 CheckSum, ByteArray** BinaryShader);
	
	// See CompilationResult_ constants for return values
	int CompileShaderFromFile(int shadertype, wchar_t* filename, wchar_t* precompiledExtension, LPCSTR szEntryPoint, LPCSTR szShaderModel, ByteArray** BinaryShader, bool Optional);
	int CompileShaderFromString( int shadertype, char* shader, LPCSTR szEntryPoint, LPCSTR szShaderModel, ByteArray** BinaryShader, bool Optional);
	
	VertexShader Shader_CreateVSFromString(char* content, int ShaderType);
	PixelShader Shader_CreatePSFromString(char* content, int ShaderType);
	void AutoSizeSurface(DrawSurface_Struct* ResultSurface);
	void SetFilter(int FilterIndex);
	void RenderItem(Instance_Struct* Item, int ShaderChannel, Shader_Struct* ShaderOverride, int FilterIndex, int RenderingMethod, int Part, DVector4 Color);
	void RenderShadow(Instance_Struct* Item);
	void ClearResourcesAfterRender(void);
	HRESULT CreateSampler(bool Clamp, bool Linear, int ExtraSamples, boolean MipMap, ID3D11SamplerState** Sampler);
	void SetRenderTargetRect(float left, float top, float width, float height);
	void LoadGlobalTextures(DrawSurface_Struct* ResultSurface);
	void FillBoneFrameBuffer(Instance_Struct* pInstance,ModelClass* pMesh);
	void FillInstanceConstantBuffers(Instance_Struct* Item, ModelClass* Mesh, DVector4 Color);
	D3D11_BUFFER_DESC MakeBufferDesc(int Size);
	D3D11_RASTERIZER_DESC MakeRasterizerDesc(D3D11_CULL_MODE CullMode,bool DepthClipEnable,D3D11_FILL_MODE FillMode);
	D3D11_DEPTH_STENCIL_DESC MakeDepthStencilDesc(D3D11_DEPTH_WRITE_MASK DepthWriteMask);
	D3D11_BLEND_DESC MakeBlendDesc(void);
	HRESULT CreateFullScreenQuad(ID3D11Buffer** Buffer);
	
	// Parser
	ModelClass* Parser_CurrentModel;
	void Parser_ReadToken(wchar_t* ModelData, int Start, int End);
	void Parser_ChangeNamespace(wchar_t* Namespace);
	void Parser_SetProperty(wchar_t* PropertyName, int Index, wchar_t* Content);
	void Parser_AddModelDataFromString(ModelClass* CurrentModel, wchar_t* ModelData, wchar_t* ModelName);
	
	// Generator
	void FeedString(bool counting,char* Text);
	void FeedString_wide(bool counting,wchar_t* Text);

	char* Generator_WriteModelDataToString(Model_Struct* pModel);
	
	// Safe duplication
	Model_Struct* Model_DuplicateModel(Model_Struct* pSrcModel);
	void Model_CopyAllParts(Model_Struct* pSrcModel, Model_Struct* pDestModel);
	void Model_DuplicateModelContent(Model_Struct* pDstModel, Model_Struct* pSrcModel, bool ReplaceGlobalData);
	void Model_DuplicatePartContent(Model_Struct* pDstModel, int DstPart, Model_Struct* pSrcModel, int SrcPart, bool ReplaceGlobalData);
	int Model_DuplicateTriangle(Model_Struct* pDstModel, int DstPart, Model_Struct* pSrcModel, int SrcPart, int SrcTri);
	
	// External ID system
	int InsertToPointerTable(void* pointer, int CollectionType);
	void* VoidPointerFromID(int ID);
	int TypeFromID(int ID);
	int IDFromPointer(void* Pointer);
	
	// DrawSurfaces
	COMMON_COLLECTION_DEC(DrawSurface)
	void DrawSurface_SetSwapState(DrawSurface_Struct* Surface, bool NewSwapState);
	void DrawSurface_InitEmpty(DrawSurface_Struct* Surface);
	void DrawSurface_SetSize(DrawSurface_Struct* Surface, int NewWidth, int NewHeight, bool FinalSurface, int DepthBuffers, bool HaveExtraColorBuffer);
	void DrawSurface_SetSize_Linear(DrawSurface_Struct* Surface, float widthMultiplier, float heightMultiplier, int widthAdder, int heightAdder, bool FinalSurface, int DepthBuffers, bool HaveExtraColorBuffer, int WindowWidth, int WindowHeight);
	DrawSurface_Struct* DrawSurface_CreateFixed(int newWidth, int newHeight, int numberOfDepthBuffers, bool useExtraColorBuffer);
	DrawSurface_Struct* DrawSurface_CreateAutoSized(float widthMultiplier, float heightMultiplier, int widthAdder, int heightAdder, int numberOfDepthBuffers, bool useExtraColorBuffer);
	int GetWantedSurfaceWidth(DrawSurface_Struct* Surface);
	int GetWantedSurfaceHeight(DrawSurface_Struct* Surface);
	int DrawSurface_GetWidth(DrawSurface_Struct* Surface);
	int DrawSurface_GetHeight(DrawSurface_Struct* Surface);
	void DrawSurface_Clear(DrawSurface_Struct* Surface);
	void DrawSurface_ClearColor(DrawSurface_Struct* Surface);
	void DrawSurface_ClearDepthBuffer(DrawSurface_Struct* Surface);
	void DrawSurface_Swap(DrawSurface_Struct* Surface);
	int DrawSurface_SaveToFile(DrawSurface_Struct* Surface, wchar_t* Filename);
	void DrawSurface_FillWithColor(DrawSurface_Struct* Surface, float Red, float Green, float Blue, float Alpha);
	DVector4 DrawSurface_GetPixelColor(DrawSurface_Struct* Surface, int X, int Y);
	void DrawSurface_SetPixelColor(DrawSurface_Struct* Surface, int X, int Y, DVector4 Color);
	
	// CPUSurfaces
	COMMON_COLLECTION_DEC(CPUSurface)
	CPUSurface_Struct* CPUSurface_CreateFixed(int newWidth, int newHeight, float Red, float Green, float Blue, float Alpha);
	void CPUSurface_SetSize(CPUSurface_Struct* Surface, int NewWidth, int NewHeight, float Red, float Green, float Blue, float Alpha);
	DVector4 CPUSurface_GetPixelColor_Clamped(CPUSurface_Struct* Surface, int X, int Y);
	DVector4 CPUSurface_GetPixelColor_Border(CPUSurface_Struct* Surface, int X, int Y, float DefaultRed, float DefaultGreen, float DefaultBlue, float DefaultAlpha);
	void CPUSurface_SetPixelColor(CPUSurface_Struct* Surface, int X, int Y, float Red, float Green, float Blue, float Alpha, bool GiveWarning);
	void CPUSurface_FillWithColor(CPUSurface_Struct* Surface, float Red, float Green, float Blue, float Alpha);
	void CPUSurface_CopyRectFromDrawSurface(DrawSurface_Struct* Input_DrawSurface, CPUSurface_Struct* Output_CPUSurface, int SourceLeft, int SourceTop, int DestLeft, int DestTop, int Width, int Height);
	
	// Textures
	COMMON_COLLECTION_DEC(Texture)
	int FindTextureIndexByName(wchar_t* filename);
	Texture_Struct* Texture_Load(wchar_t* filename, bool LockResource);
	void SetDefaultTexture(Texture_Struct* Texture);
	
	// Shaders
	COMMON_COLLECTION_DEC(Shader)
	int FindShaderIndexByName(wchar_t* filename);
	Shader_Struct* Shader_Load(wchar_t* filename, int ShaderType, bool LockResource);
	void SetDefaultMaterialShader(Shader_Struct* MaterialShader);
	
	// Post effects
	void PostEffect_RenderShader(DrawSurface_Struct* OutputSurface, Shader_Struct* PostEffect);
	void PostEffect_CleanUpInput(void);
	
	
	// Draw methods
	void Draw_RenderQuad(DrawSurface_Struct* OutputSurface, Shader_Struct* DrawShader, DVector2 Center, DVector2 XAxis, DVector2 YAxis, int FilterType);
	void Draw_CleanUpInput(void);
	
	// Models
	COMMON_COLLECTION_DEC(Model)
	Model_Struct* CreateEmptyModel(void);
	void UpdateModels(void);
	
	// Sound
	COMMON_COLLECTION_DEC(SoundBuffer)
	bool InitiateSound(void);
	SoundBuffer_Struct* CreateSoundBufferFromFile(wchar_t* Filename,int NewNumberOfCopies, bool LoadAs3DSound, bool Editable);
	SoundBuffer_Struct* CreateEmptySoundBuffer(int NewNumberOfCopies, bool LoadAs3DSound, int SamplesPerSecond, int NumberOfChannels, int SamplesPerChannel);
	void PlaceListener(DVector3 Pos, DVector3 Front, DVector3 Up);
	void SetMetersPerDistanceUnit(float Meters);
	
	// Instances
	COMMON_COLLECTION_DEC(Instance)
	Instance_Struct* Instance_Create(Model_Struct* Model);
	void Instance_ReplaceModel(Instance_Struct* Instance, Model_Struct* Model);
	void Instance_RemoveBoneFrame(Instance_Struct* Instance);
	void Instance_AssignBoneFrame(Instance_Struct* Instance, BoneFrame_Struct* BoneFrame);
	void Instance_ReleaseOverride(Instance_Struct* Instance, int OverrideChannel);
	int Instance_GetIDFromOverride(Instance_Struct* Instance, int OverrideChannel);
	void Instance_SetOverrideUsingTexture(Instance_Struct* Instance, int OverrideChannel, Texture_Struct* Texture);
	void Instance_SetOverrideUsingDrawSurface(Instance_Struct* Instance, int OverrideChannel, DrawSurface_Struct* DrawSurface);
	void SortInstances(Camera_Struct* Camera);
	void RenderTwoSteps(Camera_Struct* InputCamera, int ShaderChannel, DrawSurface_Struct* Surface);
	void RenderOneStep(Camera_Struct* InputCamera);
	void SetSkyInstance(Instance_Struct* Instance);
	
	// Camera
	COMMON_COLLECTION_DEC(Camera)
	Camera_Struct* Camera_Create(void);
	void Camera_Place(Camera_Struct* Camera, DVector3 Eye, DVector3 At, DVector3 Up);
	void Camera_SetVerticalFOV_InRadians(Camera_Struct* Camera, float FieldOfView);
	void Camera_SetHorizontalFOV_InRadians(Camera_Struct* Camera, float FieldOfView);
	void Camera_SetVerticalFOV_InDegrees(Camera_Struct* Camera, float FieldOfView);
	void Camera_SetHorizontalFOV_InDegrees(Camera_Struct* Camera, float FieldOfView);
	DMatrix Camera_GetAxisSystem(Camera_Struct* Camera);
	float GetBoundingSphereRadius(DMatrix Transformation, ModelClass* Model);
	void GetBoundingBoxCorners(DMatrix Transformation, ModelClass* Model, DVector3* EightWorldSpaceOutputPositions);
	bool CanInstanceBeSeenFromCamera(Camera_Struct* InputCamera, Instance_Struct* Instance,bool CullUsingFarClip,bool CullUsingCuttingPlane);
	bool CanLightBeSeenFromCamera(Camera_Struct* InputCamera, LightSource* TheLight);
	DMatrix Camera_GetRefractedWorldTransformation(Camera_Struct* Camera);
	void Camera_Prepare(Camera_Struct* InputCamera, float AspectRatio);
	void Camera_CreateStructFromLight(Camera_Struct* InputCamera, LightSource_Struct* InputLight);
	void Camera_GetViewFrustum(Camera_Struct* InputCamera,DVector3* EightWorldSpaceOutputPositions,float Near,float Far); // Assumes that Camera_Prepare has been called since the last modification
		void GetBoundingBoxFromPoints(DVector3* Points,int NumberOfPoints,DVector3* AABBMinOut,DVector3* AABBMaxOut);
	void SetDefaultShaderResources(void);

	// Light sources
	COMMON_COLLECTION_DEC(LightSource)
	LightSource_Struct* LightSource_Create_Point_Shadowless(DVector3 Pos, float Radius, DVector3 RGBIntensity);
	LightSource_Struct* LightSource_Create_Sun_Shadowless(DVector3 Direction, DVector3 RGBIntensity);
	LightSource_Struct* LightSource_Create_Sun_Shadowcasting_SingleLayer(DVector3 Pos, DVector3 Direction, DVector3 UpVector, float NearClip, float FarClip, DVector3 RGBIntensity, float HalfWidth, float HalfHeight, float ShadowTransparency, int ResolutionGroup, float OutsideIntensity, float FadeSize);
	LightSource_Struct* LightSource_Create_Spotlight_RoundAndSoft_Shadowless(DVector3 Pos, DVector3 Direction, DVector3 UpVector, float Radius, DVector3 RGBIntensity, float WidthSlope, float HeightSlope);
	LightSource_Struct* LightSource_Create_Spotlight_Atlas_Shadowless(DVector3 Pos, DVector3 Direction, DVector3 UpVector, float Radius, DVector3 RGBIntensity, float WidthSlope, float HeightSlope, float MinU, float MaxU, float MinV, float MaxV);
	LightSource_Struct* LightSource_Create_Spotlight_RoundAndSoft_Shadowcasting(DVector3 Pos, DVector3 Direction, DVector3 UpVector, float Radius, DVector3 RGBIntensity, float WidthSlope, float HeightSlope, float NearClip, float ShadowTransparency, int ResolutionGroup);
	LightSource_Struct* LightSource_Create_Spotlight_Atlas_Shadowcasting(DVector3 Pos, DVector3 Direction, DVector3 UpVector, float Radius, DVector3 RGBIntensity, float WidthSlope, float HeightSlope, float MinU, float MaxU, float MinV, float MaxV, float NearClip, float ShadowTransparency, int ResolutionGroup);
	void SetLightProjectionAtlas(Texture_Struct* Texture);
	void CreateDefaultDepthAtlasIfNeeded(void);
	
	// Bone frames
	COMMON_COLLECTION_DEC(BoneFrame)
	BoneFrame_Struct* BoneFrame_CreateEmpty(void);
	BoneFrame_Struct* BoneFrame_CreateFromDefaultPose(Model_Struct* Model);
	
	// Physics
	PhysicsCore m_PhysicsCore;
	DoubleLinkListHead<CPUSurface_Struct> LL_ModifiedCPUSurface;
	DoubleLinkListHead<CollisionShape_Struct> LL_ModifiedShape;
	void Physics_CPUSurfaceHasChanged(CPUSurface_Struct* CPUSurface);
	void Physics_CollisionShapeHasChanged(CollisionShape_Struct* CollisionShape);
	void Physics_Step(float TimeStep);
	
	// Debug drawing
	void DebugLine_Init(void);
		VertexStructure_Line m_LineVertexBuffer[2];
		ID3D11Buffer* m_D3DLineVertexBuffer;
		UINT DebugLine_VertexStructureSize;
		UINT DebugLine_NoOffset;
	void DebugLine_Terminate(void);
	void DebugDraw(Camera_Struct* InputCamera);
	void DrawSphere(DVector3 Center,float Radius,DVector3 Color,int DetailLevel);
	void DrawLine(DVector3 from,DVector3 to, DVector3 fromColor, DVector3 toColor);
	
	// Constraints
	COMMON_COLLECTION_DEC(Constraint)
	Constraint_Struct* Constraint_Create_PointToPoint_1(RigidBody_Struct* Body,float Point_X,float Point_Y,float Point_Z);
	Constraint_Struct* Constraint_Create_PointToPoint_2(RigidBody_Struct* BodyA,RigidBody_Struct* BodyB,float PointA_X,float PointA_Y,float PointA_Z,float PointB_X,float PointB_Y,float PointB_Z);
	Constraint_Struct* Constraint_Create_Hinge_1(RigidBody_Struct* Body,float Pivot_X,float Pivot_Y,float Pivot_Z,float Axis_X,float Axis_Y,float Axis_Z);
	Constraint_Struct* Constraint_Create_Hinge_2(RigidBody_Struct* BodyA,RigidBody_Struct* BodyB,float PivotA_X,float PivotA_Y,float PivotA_Z,float PivotB_X,float PivotB_Y,float PivotB_Z,float AxisA_X,float AxisA_Y,float AxisA_Z,float AxisB_X,float AxisB_Y,float AxisB_Z);
	
	// Rigid bodies
	COMMON_COLLECTION_DEC(RigidBody)
	void RigidBody_SetTransformation_Aux(RigidBody_Struct* RigidBody,btTransform* NewTrans);
	void RigidBody_SetTransformation(RigidBody_Struct* RigidBody,DVector3 Pos, DVector3 XAxis, DVector3 YAxis);
	void RigidBody_ClearProxy(RigidBody_Struct* RigidBody);
	RigidBody_Struct* RigidBody_Create(CollisionShape_Struct* CollisionShape, float Mass, DVector3 Pos, DVector3 XAxis, DVector3 YAxis, bool Dynamic, bool Kinematic);
	
	// Collision shapes
	COMMON_COLLECTION_DEC(CollisionShape)
	void CollisionShape_Compound_DeleteAllChildren(CollisionShape_Struct* CollisionShape);
	CollisionShape_Struct* GeneralCollisionShapeConstructor(int ShapeType,btCollisionShape* CollisionShape,CPUSurface_Struct* CPUSurface);
	CollisionShape_Struct* CollisionShape_Create_Box(float HalfWidth, float HalfHeight, float HalfDepth,CPUSurface_Struct* Surface);
	CollisionShape_Struct* CollisionShape_Create_Sphere(float Radius,CPUSurface_Struct* Surface);
	CollisionShape_Struct* CollisionShape_Create_StaticPlane(float NX, float NY, float NZ, float D,CPUSurface_Struct* Surface);
	CollisionShape_Struct* CollisionShape_Create_Cylinder(float HalfWidth, float HalfHeight, float HalfDepth,CPUSurface_Struct* Surface);
	CollisionShape_Struct* CollisionShape_Create_Capsule(float Radius, float Height,CPUSurface_Struct* Surface);
	CollisionShape_Struct* CollisionShape_Create_Cone(float Radius, float Height,CPUSurface_Struct* Surface);
	CollisionShape_Struct* CollisionShape_Create_HeightField_UsingCPUSurface(int HeightStickWidth, int HeightStickLength,void* heightfieldData,float minHeight,float maxHeight,int upDimension,int channelIndex,bool flipQuadEdges,bool diamondPattern,CPUSurface_Struct* Surface);
	CollisionShape_Struct* CollisionShape_Create_Compound(CPUSurface_Struct* Surface);
	CollisionShape_Struct* CollisionShape_Create_ConvexHull(CPUSurface_Struct* CPUSurface);
	
	void DepthBuffer_InitEmpty(DepthBuffer_Struct* Surface);
	void DepthBuffer_Release(DepthBuffer_Struct* Reference);
	void DepthBuffer_SetSize(DepthBuffer_Struct* Surface, int NewWidth, int NewHeight);
	void DepthBuffer_Clear(DepthBuffer_Struct* Reference);
	void ClearShadows(void);
	
	// Automatic detail level
	void UpdateAutomaticDetailLevels(DVector3 Center);
	
	// Safety
	int Filter(unsigned int code, struct _EXCEPTION_POINTERS *ep);
	COLLECTION_TABLE(DEC_DEFAULT_METHODS)
	
	// Main interface methods
	EngineCore(void);
	~EngineCore(void);
	bool InitDevice(HWND m_hWnd);
	int SetApplicationPath(LPCWSTR ApplicationPath);
	void Camera_Render(Camera_Struct* InputCamera, DrawSurface_Struct* ResultSurface, int ShaderChannel, Instance_Struct* OptionalSingleInstance, Shader_Struct* ShaderOverride, int FilterIndex, int RenderingMethod, bool UseDepthBuffer, DVector4 InstanceColor, int Part);
	void ShowLastRender(void);
	void RemoveUnusedResources(void);
	
	MessageQueue* MQ;
	
	// String generation
	int								writeIndex;
	bool							counting;
	char*							GeneratorString;
	char							NumberString[32];
	
	CORE_DATA_TABLE(DECLARE)
	
	// The most important pointers
	ID3D11Device*					m_pd3dDevice;
	ID3D11DeviceContext*			m_pImmediateContext;
	IDXGISwapChain*					m_pSwapChain;
	ReferenceTable*					m_pReferences;
	
};

class DebugDrawer : public btIDebugDraw
{
public:
	EngineCore* TheEngineCore;
	DebugDrawer(EngineCore* NewEngineCore);
	~DebugDrawer(void);
	int DebugMode;
	void drawLine(const btVector3& from,const btVector3& to,const btVector3& color);
	void drawLine(const btVector3& from,const btVector3& to, const btVector3& fromColor, const btVector3& toColor);
	void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color);
	void reportErrorWarning(const char* warningString);
	void draw3dText(const btVector3& location,const char* textString);
	void setDebugMode(int debugMode);
	int getDebugMode() const;
};
