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

// DFPGECtrl.cpp : Implementation of the CDFPGECtrl ActiveX Control class.

#include "stdafx.h"
#include "DFPGE.h"
#include "DFPGECtrl.h"
#include "DFPGEPropPage.h"
#include "Interface.h"
#include "GlobalConstants.h"
#include "MessageQueue.h"

// Divide code into separate files
#include "Interface_PostEffect.h"
#include "Interface_Shader.h"
#include "Interface_Camera.h"
#include "Interface_Model.h"
#include "Interface_Instance.h"
#include "Interface_DrawSurface.h"
#include "Interface_CPUSurface.h"
#include "Interface_Texture.h"
#include "Interface_Buffer.h"
#include "Interface_Report.h"
#include "Interface_Enviroment.h"
#include "Interface_LightSource.h"
#include "Interface_Sound.h"
#include "Interface_BoneFrame.h"
#include "Interface_Draw.h"
#include "Interface_Physics.h"
#include "Interface_Physics_Constraint.h"
#include "Interface_Physics_RigidBody.h"
#include "Interface_Physics_CollisionShape.h"

#pragma once

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#include "Register.h"

CDFPGECtrl::CDFPGECtrl() {
	#ifdef THREADSAFE
		if (!InitializeCriticalSectionAndSpinCount(&EngineMutex,0x00000001)) {
			::MessageBoxW(NULL,L"The graphics engine could not initialize the mutex.",L"Error!",NULL);
		}
	#endif
	InitializeIIDs(&IID_DDFPGE, &IID_DDFPGEEvents);
	MQ = new MessageQueue();
	DGE.MQ = MQ;
	allocatedStringBuffer = 1000;
	StringBuffer = new wchar_t[allocatedStringBuffer];
	lenStringBuffer = 0;
}

CDFPGECtrl::~CDFPGECtrl() {
	SAFE_DELETE_ARRAY(StringBuffer)
	SAFE_DELETE(MQ);
	#ifdef THREADSAFE
		DeleteCriticalSection(&EngineMutex);
	#endif
}

// Trap access violation
int CDFPGECtrl::Filter_Ctrl(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
}

void CDFPGECtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid) {
	if (!pdc)
		return;
	
	if (DGE.m_HasRenderedToFinalSurface) {
		// Repaint the last render
		DGE.ShowLastRender();
	} else {
		// Draw black because a first render would be black anyway
		pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
	}
}

void CDFPGECtrl::DoPropExchange(CPropExchange* pPX) {
	ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
	COleControl::DoPropExchange(pPX);
}

void CDFPGECtrl::OnResetState() {
	COleControl::OnResetState();  // Resets defaults found in DoPropExchange
}

void CDFPGECtrl::Engine_SetCurrentDirectory_InSB(void) {
	CRITICAL_CODE_SECTION(
		if (::SetCurrentDirectoryW(StringBuffer) == 0) {
			swprintf_s( MQ->messageBuffer, L"Engine_SetCurrentDirectory_InSB: Invalid application path. \"%s\"", StringBuffer); MQ->InsertMessage(MQ->messageBuffer);
		}
	)
}

void CDFPGECtrl::Engine_SetCurrentDirectoryRelativeToApplicationPath_InSB(void) {
	START_OF_CRITICAL_SECTION
		wchar_t ApplicationPath[260]; int lenAppPath;
		wchar_t FinalPath[260];
		if (GetModuleFileNameW(NULL,ApplicationPath,260)) {
			OnlyPath(ApplicationPath);
			lenAppPath = lengthOfString_wide(ApplicationPath);
			if (lenAppPath + 1 + lenStringBuffer < 260) {
				swprintf_s(FinalPath,L"%s\\%s",ApplicationPath,StringBuffer);
				if (::SetCurrentDirectoryW(FinalPath) == 0) {
					swprintf_s( MQ->messageBuffer, L"Engine_SetCurrentDirectoryRelativeToApplicationPath_InSB: Invalid application path. Application path = \"%s\" Relative path = \"%s\" Complete path = \"%s\"", ApplicationPath, StringBuffer, FinalPath); MQ->InsertMessage(MQ->messageBuffer);
				}
			} else {
				swprintf_s( MQ->messageBuffer, L"Engine_SetCurrentDirectoryRelativeToApplicationPath_InSB: The application path concatunated with the relative path is longer than Windows allow. Application path = \"%s\" Relative path = \"%s\" Complete path = \"%s\"", ApplicationPath, StringBuffer, FinalPath); MQ->InsertMessage(MQ->messageBuffer);
			}
		} else {
			MQ->InsertMessage(L"Engine_SetCurrentDirectoryRelativeToApplicationPath_InSB: The path to the application is too long.");
		}
	END_OF_CRITICAL_SECTION
}

// The string buffer must contain the application path
int CDFPGECtrl::Engine_Initiate(void) {
	CRITICAL_CODE_SECTION(
		int Result;
		if (DGE.InitDevice(this->GetSafeHwnd())) {
			Result = 1;
		} else {
			Result = 0;
		};
		return Result;
	)
}

void CDFPGECtrl::Engine_RemoveUnusedResources(void) {
	CRITICAL_CODE_SECTION(
		DGE.RemoveUnusedResources();
	)
}

int CDFPGECtrl::Engine_GetTypeFromID(int ID) {
	CRITICAL_CODE_SECTION(
		return DGE.TypeFromID(ID);
	)
}

void CDFPGECtrl::Engine_SetAutomaticSwapChain(bool Automatic) {
	CRITICAL_CODE_SECTION(
		DGE.m_AutomaticSwapChain = Automatic;
	)
}

int CDFPGECtrl::Engine_GetAutomaticSwapChain() {
	CRITICAL_CODE_SECTION(
		int Result;
		if (DGE.m_AutomaticSwapChain) {
			Result = 1;
		} else {
			Result = 0;
		}
		return Result;
	)
}

void CDFPGECtrl::Engine_UpdateSwapChain() {
	CRITICAL_CODE_SECTION(
		if (DGE.m_AutomaticSwapChain) {
			MQ->InsertMessage(L"Engine_UpdateSwapChain: It is pointless to update the SwapChain manually when the swap chain is automatic.\nUse Engine_SetAutomaticSwapChain to turn it off.");
		} else {
			DGE.ShowLastRender();
		}
	)
}

int CDFPGECtrl::Message_GetCount(void) {
	CRITICAL_CODE_SECTION(
		return MQ->MessageCount;
	)
}

void CDFPGECtrl::Message_GetContent_OutSB(void) {
	CRITICAL_CODE_SECTION(
		wchar_t* NewMessage;
		if (MQ->MessageCount > 0) {
			NewMessage = MQ->GetTextFromFirstMessage();
			if (NewMessage != NULL) {
				FillSB(NewMessage);
				SAFE_DELETE(NewMessage)
				MQ->DeleteFirstMessage();
			}
		} else {
			FillSB(L"");
		}
	)
}

int CDFPGECtrl::Windows_GetCursorPos_X(void) {
	CRITICAL_CODE_SECTION(
		POINT Pos;
		if (GetCursorPos(&Pos) != 0) {
			return Pos.x;
			LastMouseX = Pos.x;
			LastMouseY = Pos.y;
		} else {
			return LastMouseX;
		}
	)
}

int CDFPGECtrl::Windows_GetCursorPos_Y(void) {
	CRITICAL_CODE_SECTION(
		POINT Pos;
		if (GetCursorPos(&Pos) != 0) {
			return Pos.y;
			LastMouseX = Pos.x;
			LastMouseY = Pos.y;
		} else {
			return LastMouseY;
		}
	)
}

void CDFPGECtrl::Windows_SetCursorPos(int X, int Y) {
	CRITICAL_CODE_SECTION(
		SetCursorPos(X,Y);
		LastMouseX = X;
		LastMouseY = Y;
	)
}
