#include "stdafx.h"
#include "ogColor.h"
#include "gtasaQueue.h"
#include "ogTexture.h"
#include "ogEngine.h"
#include "ogInput.h"
#include "ogMenu.h"
#include "ogUtil.h"

// day time
short *	currentTimeSeconds = (short *)0xB70150;
char *	currentTimeMinutes = (char *)0xB70152;
char *	currentTimeHours = (char *)0xB70153;
char *	currentMonthDay = (char *)0xB70154;
char *	currentMonth = (char *)0xB70155;
float *	daylightLightingState = (float *)0x8D12C0;
void	calculateDaylightLightingState () {
	float daytime = (float)(*currentTimeHours*60+*currentTimeMinutes)+((float)*currentTimeSeconds)/60.0f;
	if (daytime <= 360.0f || daytime >= 1260.0f)
		*daylightLightingState = 1.0f;
	else if (daytime >= 420.0f && daytime <= 1200.0f) 
		*daylightLightingState = 0.0f;
	else if (daytime < 420.f)	// morning
		*daylightLightingState = (420.0f-daytime)/60.0f;
	else if (daytime > 1200.0f)
		*daylightLightingState = 1.0f-(1260.0f-daytime)/60.0f;
}


void (*releaseModel) (DWORD index) = (void (__cdecl *)(DWORD))0x4089A0;

void (*_40E120)(DWORD _a0) = (void (__cdecl *)(DWORD))0x40E120;

void (*checkCheatcode)(int key) = (void (__cdecl *)(int))0x439AF0;

void (*_53C500)(int player, DWORD _a4) = (void (__cdecl *)(int, DWORD))0x53C500;
void (*resetTimers) () = (void (__cdecl *)())0x561AA0; 
void (*_561B10)() = (void (__cdecl *)())0x561B10;

void _719380 (float scaleX, float scaleY) { // >> 719380
	*(float *)0xC71A64 = scaleX;
	*(float *)0xC71A68 = scaleY;
}

void _7193A0 (float scaleX, float scaleY) { // >> 7193A0
	*(float *)0xC71A64 = (menu->language > 3) ? scaleX : scaleX*0.8f;
	*(float *)0xC71A68 = scaleY;
}
// setTextColor
void _719430 (DWORD color) { // >> 719430
	RGBA * c = (RGBA *)0xC71A60;
	c->color = color;
	float alpha = *(float *)0xC71A80;
	if (alpha < 255.0) 
		c->a = (BYTE)(((float)c->a)*alpha/255.0);
}

void _719490 (BYTE a0) { // >> 717490
	if (a0 == 2) {
		*(BYTE *)0xC71A94 = 0;
		*(BYTE *)0xC71A95 = 2;
	} else if (a0 == 3) {
		*(BYTE *)0xC71A94 = 1;
		*(BYTE *)0xC71A95 = 1;
	} else {
		*(BYTE *)0xC71A94 = a0;
		*(BYTE *)0xC71A95 = 0;
	}
}

void _7194D0 (float c) { // >> 7194D0
	*(float *)0xC71A88 = c;
}

void _7194E0 (float f) { // >> 7194E0
	*(float *)0xC71A8C = f;
}

void _719500 (float f) {	// >> 719500	setTextAlpha
	*(float *)0xC71A80 = f;
}

// setTextBackground
void _719510 (DWORD color) { // >> 719510
	RGBA * c = (RGBA *)0xC71A97;
	c->color = color;

	float alpha = *(float *)0xC71A80;
	if (alpha < 255.0) { 
		RGBA * tc = (RGBA *)0xC71A60;
		c->a = (BYTE)(((float)tc->a)*alpha/255.0);
	}
}

void _719570 (BYTE a0) { // >> 719570
	*(BYTE *)0xC71A9B = 0;
	*(BYTE *)0xC71A9C = 0;
	*(BYTE *)0xC71A96 = a0;
}

void _719590 (BYTE a0) { // >> 719590
	*(BYTE *)0xC71A96 = 0;
	*(BYTE *)0xC71A9B = a0;
	*(BYTE *)0xC71A9C = a0;
}

void _7195B0 (BYTE a0) { // >> 7195B0
	*(BYTE *)0xC71A7D = a0;
}

void _7195C0 (BYTE a0, BYTE a4) { // >> 7195C0
	*(BYTE *)0xC71A7B = a0;
	*(BYTE *)0xC71A7C = a4;
}

void _719610 (BYTE a0) { // >> 719610 
	if (a0 == 0) {
		*(BYTE *)0xC71A79 = 1;
		*(BYTE *)0xC71A7A = 0;
	} else if (a0 == 1) {
		*(BYTE *)0xC71A79 = 0;
		*(BYTE *)0xC71A7A = 0;
	} else if (a0 == 2) {
		*(BYTE *)0xC71A79 = 0;
		*(BYTE *)0xC71A7A = 1;
	}
}

void (*_719800)() = (void (__cdecl *)())0x719800;

int (*getTextLineCount)(float x, float y, char * text) = (int (__cdecl *)(float, float, char *))0x71A5E0;	
void (*_71A700)(float x, float y, const TCHAR * text) = (void (__cdecl *)(float, float, const TCHAR *))0x71A700;
void (*_71A820)(float x, float y, const TCHAR * text) = (void (__cdecl *)(float, float, const TCHAR *))0x71A820;

// 2D graphics
void * vertices = (void *)0xC80468; // (RwD3DVertex9[8])

extern void (*_727350)() = (void (__cdecl *)())0x727350;	// reset2D

void (*_727420) (float * coords, RGBA * rgba1, RGBA * rgba2, RGBA * rgba3, RGBA * rgba4) = 
	(void (__cdecl *)(float *, RGBA *, RGBA *, RGBA *, RGBA *))0x727420;	// prepareIm2DRect

void drawRect(float * coords, RGBA * rgba) { // >> 727B60 (62)
	// fprintf (log, "drawRect ([%d, %d, %d, %d], %08x)\n", (int)coords[0], (int)coords[1], (int)coords[2], (int)coords[3], rgba->color);
	RENDERSTATESET (rwRENDERSTATETEXTURERASTER, 0);
	_727420 (coords, rgba, rgba, rgba, rgba); // prepareIm2DRectCoords
	RENDERSTATESET (rwRENDERSTATEVERTEXALPHAENABLE, (rgba->a == 0xFF) ? 0 : 1);
	RENDERPRIMITIVE (rwPRIMTYPETRIFAN, vertices, 4);
	RENDERSTATESET (rwRENDERSTATEVERTEXALPHAENABLE, 0);
}

void _734750 () {
	RENDERSTATESET (rwRENDERSTATETEXTUREADDRESS, 1);
	RENDERSTATESET (rwRENDERSTATETEXTUREPERSPECTIVE, 0);
	RENDERSTATESET (rwRENDERSTATEZTESTENABLE, 0);
	RENDERSTATESET (rwRENDERSTATEZWRITEENABLE, 0);
	RENDERSTATESET (rwRENDERSTATESHADEMODE, 2);
	RENDERSTATESET (rwRENDERSTATETEXTUREFILTER, 2);
	RENDERSTATESET (rwRENDERSTATEVERTEXALPHAENABLE, 0);
	RENDERSTATESET (rwRENDERSTATESRCBLEND, 5);
	RENDERSTATESET (rwRENDERSTATEDESTBLEND, 6);
	RENDERSTATESET (rwRENDERSTATEBORDERCOLOR, 0xFF000000);
	RENDERSTATESET (rwRENDERSTATEFOGENABLE, 0);
	RENDERSTATESET (rwRENDERSTATECULLMODE, 1);
	RENDERSTATESET (rwRENDERSTATEALPHATESTFUNCTION, 5);
	RENDERSTATESET (rwRENDERSTATEALPHATESTFUNCTIONREF, 2);
}

// ** custom plugins **
DWORD * pl253F2F8_TK = (DWORD *)0xC3A1E0;

// ** Skeleton **
RsEventStatus (*RsEventHandler)(RsEvent event, void *param) = (RsEventStatus (__cdecl *)(RsEvent, void *))0x619B60;

// ** RenderWare **
int (*RwEngineGetCurrentSubSystem)() = (int (__cdecl *)())0x7F2C60;
void (*RwTextureDestroy)(RwTexture *) = (void (__cdecl *)(RwTexture *))0x7F3820;
DWORD (*RwTexDictionaryCreate)() = (DWORD (__cdecl *)())0x7F3600;
void  (*RwTexDictionaryDestroy)(DWORD dict) = (void (__cdecl *)(DWORD))0x7F36A0;
void (*RwTexDictionarySetCurrent)(DWORD txd) = (void (__cdecl *)(DWORD))0x7F3A70;
DWORD (*RwTexDictionaryGetCurrent)() = (DWORD (__cdecl *)())0x7F3A90;
///DWORD (*RwTexDictionaryForAllTextures)(DWORD dict, DWORD (*callback)(RwTexture *, void * param), void * param) =
	///(DWORD (__cdecl *)(DWORD, DWORD (__cdecl *)(RwTexture *, void *), void *))0x7F3730;
RwTexture * (*RwReadTexture)(char * name, char * maskName) = (RwTexture *(__cdecl *)(char *, char *))0x7F3AC0;
DWORD (*RwTexDictionaryAddTexture)(DWORD dict, RwTexture * tex) = (DWORD (__cdecl *)(DWORD, RwTexture *))0x7F3980;
RwTexture *(*RwTexDictionaryRemoveTexture)(RwTexture * texture) = (RwTexture *(__cdecl *)(RwTexture *))0x7F39C0;

bool (*RwTextureSetFindCallBack)(RwTextureCallBackFind callBack) = (bool (__cdecl *)(RwTextureCallBackFind))0x7F34D0;
bool (*RwTextureSetReadCallBack)(RwTextureCallBackRead callBack) = (bool (__cdecl *)(RwTextureCallBackRead))0x7F3500;
RwTexture * (*RwTexDictionaryFindNamedTexture)(RwTexDictionary * dict, const char * name) = 
	(RwTexture * (__cdecl *)(RwTexDictionary *, const char *))0x7F39F0; 
const RwTexDictionary *(* RwTexDictionaryForAllTextures)(const RwTexDictionary * dict, RwTextureCallBack fpCallBack, void *pData) = 
(const RwTexDictionary * (__cdecl *)(const RwTexDictionary *, RwTextureCallBack, void *))0x7F3730;

//void * (*RwStreamOpen) (int type, int accessType, void * data) = (void *(__cdecl *)(int, int, void *))0x7ECEF0;
//void (*RwStreamClose) (void * stream, void * data) = (void (__cdecl *)(void *, void *))0x7ECE20;
//int (*RwStreamFindChunk) (void * stream, int type, int * lengthOut, int * versionOut) = (int (__cdecl *)(void *, int, int *, int *))0x7ED2D0;


void * (*RpClumpStreamRead)(void * stream) = (void *(__cdecl *)(void *))0x74B420;
void (*RpClumpForAllAtomics)(void *, RpAtomic * (__cdecl *)(RpAtomic *, void *), void *) = 
	(void (__cdecl *)(void *, RpAtomic * (__cdecl *)(RpAtomic *, void *), void *))0x749B70;
void (*RpClumpDestroy)(void *) = (void (__cdecl *)(void *))0x74A310;
RpClump * (*RpClumpClone)(RpClump *) = (RpClump *(__cdecl *)(RpClump *))0x749F70; 

RpClump * RpClumpAddAtomic (RpClump * c, RpAtomic * a) {
	a->inClumpLink.next = c->atomicList.next;
	c->atomicList.next->prev = c->atomicList.next = &(a->inClumpLink);
	a->clump = c;
	return c;
}

RpClump * RpClumpRemoveAtomic (RpClump * c, RpAtomic * a) {
	a->inClumpLink.prev->next = a->inClumpLink.next;
	a->inClumpLink.next->prev = a->inClumpLink.prev;
	a->clump = NULL;
	return c;
}

RpAtomic * (*RpAtomicClone)(RpAtomic *) = (RpAtomic * (__cdecl *)(RpAtomic *))0x749E60;
bool (* RpAtomicDestroy)(RpAtomic *) = (bool (__cdecl *)(RpAtomic *))0x749DC0;
RpAtomic * (*RpAtomicSetFrame)(RpAtomic *, RwFrame *) = (RpAtomic *(__cdecl *)(RpAtomic *, RwFrame *))0x74BF20;

RwFrame * (*RwFrameCreate)() = (RwFrame * (__cdecl *)())0x7F0410;
bool (*RwFrameDestroy)(RwFrame *) = (bool (__cdecl *)(RwFrame *))0x7F05A0;
RwFrame * (*RwFrameForAllChildren)(RwFrame * frame, RwFrameCallBack callBack, void *data) = 
(RwFrame * (__cdecl *)(RwFrame *, RwFrameCallBack, void *))0x7F0DC0 ;
RwFrame * (*RwFrameForAllObjects)(RwFrame * frame, RwFrameCallBack callBack, void *data) = 
(RwFrame * (__cdecl *)(RwFrame *, RwFrameCallBack, void *))0x7F1200;
RwFrame * (*RwFrameTransform)(RwFrame *, RwMatrix *, int combineOp) = (RwFrame * (__cdecl *)(RwFrame *, RwMatrix *, int))0x7F0F70;
RwFrame * (*RwFrameAddChild)(RwFrame * frame, RwFrame * child) = (RwFrame * (__cdecl *)(RwFrame *, RwFrame *))0x7F0B00;
RwFrame * (*RwFrameUpdateObject)(RwFrame *) = (RwFrame * (__cdecl *)(RwFrame *))0x7F0910;
RwMatrix * (*RwFrameGetLTM)(RwFrame *) = (RwMatrix *(__cdecl *)(RwFrame *))0x7F0990;

RwFrame * (*RwFrameRemoveChild)(RwFrame *child) = (RwFrame *(__cdecl *)(RwFrame *))0x7F0CD0;

RpSkin * (*RpSkinGeometryGetSkin)( RpGeometry *geometry ) = (RpSkin * (__cdecl *)(RpGeometry *))0x7C7550;

RsGlobalType * rsGlobal = (RsGlobalType *)0xC17040;

CEngine ** engine = (CEngine **)0xC97B24;

// save/restore current texture dictionary (TODO: move to RW-related file)
static DWORD savedTexDictionary;	//  >> C88010
void saveTexDictionary () {		// >> 7316A0 (29)
	savedTexDictionary = RwTexDictionaryGetCurrent ();
}
void restoreTexDictionary () {	// >> 7316B0 (36)
	RwTexDictionarySetCurrent (savedTexDictionary);
	savedTexDictionary = 0;
}


// 
extern void injectFunction (DWORD address, DWORD function);
void mainInject () {
	injectFunction (0x727B60, (DWORD)drawRect);
	injectFunction (0x7316A0, (DWORD)saveTexDictionary);
	injectFunction (0x7316B0, (DWORD)restoreTexDictionary);
	// injectFunction (0x7272B0, (DWORD)(CTexture::read));

	injectFunction (0x744FB0, (DWORD)initUserDir);
	injectFunction (0x5387D0, (DWORD)chdirProgramDir);
	injectFunction (0x538860, (DWORD)chdirUserDir);

	// assorted 3D
	injectFunction (0x5D5AC0, (DWORD)allocMapPipe);	
	injectFunction (0x5DA130, (DWORD)freeMapPipe);	

	// TXD
	injectFunction (0x7316D0, (DWORD)getDefaultTxd);	
	injectFunction (0x7320B0, (DWORD)txdLoad);	
	injectFunction (0x731DD0, (DWORD)txdRead);	
	injectFunction (0x731A00, (DWORD)txdAddRef);
	injectFunction (0x731A30, (DWORD)txdRelease);
	
	injectFunction (0x74A490, (DWORD)RpClumpAddAtomic);
	injectFunction (0x74A4C0, (DWORD)RpClumpRemoveAtomic);	
	// injectFunction (0x, (DWORD));	

	injectFunction (0x5D7F80, (DWORD)calculateDaylightLightingState);	

	injectFunction (0x407180, (DWORD)random);
}