
// 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 "Engine/EngineCore.h"
#include "GlobalConstants.h"
#include "Engine/QuadAllocator.h"
#include "MessageQueue.h"
#include "ContactBuffer.h"
#include "interface.h"

// Trap access violation
#define Try_Start_Ctrl __try
#define Try_Else_Ctrl __except(Filter_Ctrl(GetExceptionCode(), GetExceptionInformation()))

#define REPORT_NOT_RUNNING(ROUTINE) swprintf_s( MQ->messageBuffer, L"%s: The engine is not running.",ROUTINE ); MQ->InsertMessage(MQ->messageBuffer);

#define GET_FROM_REF(TYPE,REF) TYPE##_Struct* p##REF##; p##REF = DGE.##TYPE##_PointerFromID(##REF##,false);
#define GET_FROM_REF_ALLOW_ZERO(TYPE,REF) TYPE##_Struct* p##REF##; p##REF = DGE.##TYPE##_PointerFromID(##REF##,true);

#define BAD_REF(REF) (p##REF## == NULL)
#define REPORT_TYPE(TYPE,ROUTINE,REF) swprintf_s( MQ->messageBuffer, L"%s: %s equals %i and is not a valid %s reference.",ROUTINE, L#REF, REF, L#TYPE ); MQ->InsertMessage(MQ->messageBuffer);

#define BAD_PART(MODEL,PART) (PART < 0 || PART > p##MODEL##->Model.GetNumberOfParts() - 1)
#define REPORT_PART(ROUTINE,MODEL,PART) swprintf_s( MQ->messageBuffer, L"%s: PartIndex %i is out of bound in model %i. Use 0 to %i.",ROUTINE, PART, MODEL, p##MODEL##->Model.GetNumberOfParts() - 1 ); MQ->InsertMessage(MQ->messageBuffer);

#define BAD_BONE(MODEL,BONE) (BONE < 0 || BONE > p##MODEL##->Model.GetNumberOfBones() - 1)
#define REPORT_BONE(ROUTINE,MODEL,BONE) swprintf_s( MQ->messageBuffer, L"%s: BoneIndex %i is out of bound in model %i. Use 0 to %i.",ROUTINE, BONE, MODEL, p##MODEL##->Model.GetNumberOfBones() - 1 ); MQ->InsertMessage(MQ->messageBuffer);

#define BAD_SHAPE(MODEL,SHAPE) (SHAPE < 0 || SHAPE > p##MODEL##->Model.GetNumberOfShapes() - 1)
#define REPORT_SHAPE(ROUTINE,MODEL,SHAPE) swprintf_s( MQ->messageBuffer, L"%s: ShapeIndex %i is out of bound in model %i. Use 0 to %i.",ROUTINE, SHAPE, MODEL, p##MODEL##->Model.GetNumberOfShapes() - 1 ); MQ->InsertMessage(MQ->messageBuffer);

#define BAD_POINT(MODEL,SHAPE,POINT) (POINT < 0 || POINT > p##MODEL##->Model.Shape_GetNumberOfPoints(SHAPE) - 1)
#define REPORT_POINT(ROUTINE,MODEL,SHAPE,POINT) swprintf_s( MQ->messageBuffer, L"%s: PointIndex %i is out of bound in model %i at shape %i. Use 0 to %i.",ROUTINE, POINT, MODEL, SHAPE, p##MODEL##->Model.Shape_GetNumberOfPoints(##SHAPE##) - 1 ); MQ->InsertMessage(MQ->messageBuffer);

#define BAD_TRI(MODEL,PART,TRI) (TRI < 0 || TRI > p##MODEL##->Model.GetTriangleCountFromPart(PART) - 1)
#define REPORT_TRI(ROUTINE,MODEL,PART,TRI) swprintf_s( MQ->messageBuffer, L"%s: TriangleIndex %i is out of bound in model %i at part %i. Use 0 to %i.",ROUTINE, TRI, MODEL, PART, p##MODEL##->Model.GetTriangleCountFromPart(##PART##) - 1 ); MQ->InsertMessage(MQ->messageBuffer);

#define BAD_TEXTURE_CHANNEL(CHANNEL) ( CHANNEL < 0 || CHANNEL > NumberOfTextureChannels - 1 )
#define REPORT_TEXTURE_CHANNEL(ROUTINE,CHANNEL) swprintf_s( MQ->messageBuffer, L"%s: Texture channel %i is out of bound. Use 0 to %i.",ROUTINE, CHANNEL, NumberOfTextureChannels ); MQ->InsertMessage(MQ->messageBuffer);

#define BAD_SHADER_CHANNEL(CHANNEL) ( CHANNEL < 0 || CHANNEL > NumberOfShaderChannels - 1 )
#define REPORT_SHADER_CHANNEL(ROUTINE,CHANNEL) swprintf_s( MQ->messageBuffer, L"%s: Shader channel %i is out of bound. Use 0 to %i.",ROUTINE, CHANNEL, NumberOfShaderChannels ); MQ->InsertMessage(MQ->messageBuffer);

//#define THREADSAFE
#ifdef THREADSAFE
	#define START_OF_CRITICAL_SECTION EnterCriticalCodeSection();
	#define END_OF_CRITICAL_SECTION LeaveCriticalCodeSection();
#else
	#define START_OF_CRITICAL_SECTION ;
	#define END_OF_CRITICAL_SECTION ;
#endif
#define CRITICAL_CODE_SECTION(CONTENT) START_OF_CRITICAL_SECTION CONTENT; END_OF_CRITICAL_SECTION

class CDFPGECtrl : public COleControl
{
	DECLARE_DYNCREATE(CDFPGECtrl)
public:
	CDFPGECtrl();

	void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid);
	void DoPropExchange(CPropExchange* pPX);
	void OnResetState();

	~CDFPGECtrl();

	#ifdef THREADSAFE
		CRITICAL_SECTION EngineMutex;
		void EnterCriticalCodeSection(void) {
			EnterCriticalSection(&EngineMutex);
		}
		void LeaveCriticalCodeSection(void) {
			LeaveCriticalSection(&EngineMutex);
		}
	#endif

	// The engine
	EngineCore DGE;

	// The message queue
	MessageQueue* MQ;

	// Trap access violation
	int Filter_Ctrl(unsigned int code, struct _EXCEPTION_POINTERS *ep);

	// String buffer
	int lenStringBuffer; // Length of the used content without the terminator.
	int allocatedStringBuffer; // The real number of elements including padding and terminator.
	wchar_t* StringBuffer; // A pointer to the dynamic string buffer.
	void ClearStringBuffer(void);
	void FillSB(wchar_t* NewString);

	// Contact buffer
	ContactBuffer CB;

	// Debug reports
	void FeedString(bool counting,wchar_t* Text);
	void FeedYesOrNo(bool counting,bool Truth);
	void NewLine(bool counting);
	int m_preCalculatedLength;
	int writeIndex;
	bool counting;
	
	// Adding file extensions to given filenames
	wchar_t Filename[260];

	// Vector and matrix buffer
	float X1, Y1, Z1, W1;
	float X2, Y2, Z2, W2;
	float X3, Y3, Z3, W3;
	float X4, Y4, Z4, W4;
	// Returning values from the inside
	void ClearMatrixBuffer(void);
	void Set4x4MatrixToMB(DMatrix NewMatrix);
	void SetVector4ToMB(DVector4 NewVector);
	void SetVector3ToMB(DVector3 NewVector);
	void SetVector2ToMB(DVector2 NewVector);
	void SetBulletTransformToMB(btTransform* NewTrans);
	void SetBulletVector4ToMB(btVector4* NewVector);
	void SetBulletVector3ToMB(btVector3* NewVector);
	
	DECLARE_OLECREATE_EX(CDFPGECtrl)    // Class factory and guid
	DECLARE_OLETYPELIB(CDFPGECtrl)      // GetTypeInfo
	DECLARE_PROPPAGEIDS(CDFPGECtrl)     // Property page IDs
	DECLARE_OLECTLTYPE(CDFPGECtrl)		// Type name and misc status

// Message maps
	DECLARE_MESSAGE_MAP()

// Dispatch maps
	DECLARE_DISPATCH_MAP()

// Event maps
	DECLARE_EVENT_MAP()

// Dispatch and event IDs
	enum {};
	
	InterfaceTable(SUBMACRO_HEADER)
	
	// Internal helper methods
	int Model_LoadFromFile_Aux(void);
	int Model_SaveToFile_Aux(int Model);
	void Instance_PlaceAtBulletTransform(Instance_Struct* pInstance,btTransform* NewTrans); // Internal
	void Instance_PlaceAtBulletTransform_Scaled(Instance_Struct* pInstance, btTransform* NewTrans, btVector3* LocalScaling); // Internal
	void SetLengthOfStringBuffer_Aux(int newSize);
	void PlaceAtRigidBody(Instance_Struct* pInstance, RigidBody_Struct* pRigidBody, bool UseLocalScaling);
	void PlaceAtRigidBody_Interpolated(Instance_Struct* pInstance, RigidBody_Struct* pRigidBody, float TimeOffset, bool UseLocalScaling);
	void FollowRigidBody(RigidBody_Struct* pRigidBody);
	void FollowRigidBody_Interpolated(RigidBody_Struct* pRigidBody,float TimeOffset);
	btConvexHullShape* OptimizeConvexShape(btConvexHullShape* ConvexShape, int Quality, btScalar Treshold);
	btConvexHullShape* WeldConvexShape(btConvexHullShape* ConvexShape, float WeldingTreshold);
	
	int LastMouseX;
	int LastMouseY;
};
