From fd2152923c514d58226f2356ba4b8f43de02dccf Mon Sep 17 00:00:00 2001
From: Sergeanur <s.anureev@yandex.ua>
Date: Thu, 9 Apr 2020 10:06:30 +0300
Subject: [PATCH] txd.img creator

---
 src/core/RwHelper.cpp  |   7 --
 src/core/RwTexRead.cpp | 203 +++++++++++++++++++++++++++++++++++++++++
 src/render/TexList.cpp |  41 +++++++++
 src/render/TexList.h   |  14 +++
 4 files changed, 258 insertions(+), 7 deletions(-)
 create mode 100644 src/render/TexList.cpp
 create mode 100644 src/render/TexList.h

diff --git a/src/core/RwHelper.cpp b/src/core/RwHelper.cpp
index 6325bf15..44866f4f 100644
--- a/src/core/RwHelper.cpp
+++ b/src/core/RwHelper.cpp
@@ -347,13 +347,6 @@ CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer)
 	return (nil);
 }
 
-WRAPPER void ReadVideoCardCapsFile(uint32&, uint32&, uint32&, uint32&) { EAXJMP(0x5926C0); }
-WRAPPER bool CheckVideoCardCaps(void) { EAXJMP(0x592740); }
-WRAPPER void WriteVideoCardCapsFile(void) { EAXJMP(0x5927D0); }
-WRAPPER void ConvertingTexturesScreen(uint32, uint32, const char*) { EAXJMP(0x592880); }
-WRAPPER void DealWithTxdWriteError(uint32, uint32, const char*) { EAXJMP(0x592BF0); }
-WRAPPER bool CreateTxdImageForVideoCard() { EAXJMP(0x592C70); }
-
 void CreateDebugFont()
 {
 	;
diff --git a/src/core/RwTexRead.cpp b/src/core/RwTexRead.cpp
index 6b717b34..ef1ac197 100644
--- a/src/core/RwTexRead.cpp
+++ b/src/core/RwTexRead.cpp
@@ -3,10 +3,24 @@
 #define DIRECTINPUT_VERSION 0x0800
 #include <dinput.h>
 #pragma warning( pop )
+#define WITHWINDOWS
 #include "common.h"
 #include "win.h"
 #include "patcher.h"
 #include "Timer.h"
+#ifdef GTA_PC
+#include "FileMgr.h"
+#include "Pad.h"
+#include "main.h"
+#include "Directory.h"
+#include "Streaming.h"
+#include "TxdStore.h"
+#include "CdStream.h"
+#include "Font.h"
+#include "Sprite2d.h"
+#include "Text.h"
+#include "RwHelper.h"
+#endif //GTA_PC
 
 float &texLoadTime = *(float*)0x8F1B50;
 int32 &texNumLoaded = *(int32*)0x8F252C;
@@ -132,9 +146,198 @@ RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict)
 	return texDict;
 }
 
+#ifdef GTA_PC
+WRAPPER RwInt32 _rwD3D8FindCorrectRasterFormat(RwRasterType type, RwInt32 flags) { EAXJMP(0x59A350); }
+
+void
+ReadVideoCardCapsFile(uint32 &cap32, uint32 &cap24, uint32 &cap16, uint32 &cap8)
+{
+	cap32 = UINT32_MAX;
+	cap24 = UINT32_MAX;
+	cap16 = UINT32_MAX;
+	cap8 = UINT32_MAX;
+
+	int32 file = CFileMgr::OpenFile("DATA\\CAPS.DAT", "rb");
+	if (file != 0) {
+		CFileMgr::Read(file, (char*)&cap32, 4);
+		CFileMgr::Read(file, (char*)&cap24, 4);
+		CFileMgr::Read(file, (char*)&cap16, 4);
+		CFileMgr::Read(file, (char*)&cap8, 4);
+		CFileMgr::CloseFile(file);
+	}
+}
+
+bool
+CheckVideoCardCaps(void)
+{
+	uint32 cap32 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT8888);
+	uint32 cap24 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT888);
+	uint32 cap16 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT1555);
+	uint32 cap8 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMATPAL8 | rwRASTERFORMAT8888);
+	uint32 fcap32, fcap24, fcap16, fcap8;
+	ReadVideoCardCapsFile(fcap32, fcap24, fcap16, fcap8);
+	return cap32 != fcap32 || cap24 != fcap24 || cap16 != fcap16 || cap8 != fcap8;
+}
+
+void
+WriteVideoCardCapsFile(void)
+{
+	uint32 cap32 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT8888);
+	uint32 cap24 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT888);
+	uint32 cap16 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT1555);
+	uint32 cap8 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMATPAL8 | rwRASTERFORMAT8888);
+	int32 file = CFileMgr::OpenFile("DATA\\CAPS.DAT", "wb");
+	if (file != 0) {
+		CFileMgr::Write(file, (char*)&cap32, 4);
+		CFileMgr::Write(file, (char*)&cap24, 4);
+		CFileMgr::Write(file, (char*)&cap16, 4);
+		CFileMgr::Write(file, (char*)&cap8, 4);
+		CFileMgr::CloseFile(file);
+	}
+}
+
+bool DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
+void DoRWStuffEndOfFrame(void);
+
+void
+ConvertingTexturesScreen(uint32 num, uint32 count, const char *text)
+{
+	HandleExit();
+
+	CSprite2d *splash = LoadSplash(nil);
+	if (!DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255))
+		return;
+
+	CSprite2d::SetRecipNearClip();
+	CSprite2d::InitPerFrame();
+	CFont::InitPerFrame();
+	DefinedState();
+
+	RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
+	splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
+
+	CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(200.0f), SCREEN_SCALE_Y(240.0f), SCREEN_SCALE_FROM_RIGHT(200.0f), SCREEN_SCALE_Y(248.0f)), CRGBA(64, 64, 64, 255));
+	CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(200.0f), SCREEN_SCALE_Y(240.0f), (SCREEN_SCALE_FROM_RIGHT(200.0f) - SCREEN_SCALE_X(200.0f)) * ((float)num / (float)count) + SCREEN_SCALE_X(200.0f), SCREEN_SCALE_Y(248.0f)), CRGBA(255, 217, 106, 255));
+	CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(120.0f), SCREEN_SCALE_Y(150.0f), SCREEN_SCALE_FROM_RIGHT(120.0f), SCREEN_HEIGHT - SCREEN_SCALE_Y(220.0f)), CRGBA(50, 50, 50, 210));
+
+	CFont::SetBackgroundOff();
+	CFont::SetPropOn();
+	CFont::SetScale(SCREEN_SCALE_X(0.45f), SCREEN_SCALE_Y(0.7f));
+	CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(170.0f));
+	CFont::SetJustifyOff();
+	CFont::SetColor(CRGBA(255, 217, 106, 255));
+	CFont::SetBackGroundOnlyTextOff();
+	CFont::SetFontStyle(FONT_BANK);
+	CFont::PrintString(SCREEN_SCALE_X(170.0f), SCREEN_SCALE_Y(160.0f), TheText.Get(text));
+	CFont::DrawFonts();
+	DoRWStuffEndOfFrame();
+}
+
+void
+DealWithTxdWriteError(uint32 num, uint32 count, const char *text)
+{
+	while (!RsGlobal.quit) {
+		ConvertingTexturesScreen(num, count, text);
+		CPad::UpdatePads();
+		if (CPad::GetPad(0)->GetEscapeJustDown())
+			break;
+	}
+	RsGlobal.quit = false;
+	LoadingScreen(nil, nil, nil);
+	RsGlobal.quit = true;
+}
+
+bool
+CreateTxdImageForVideoCard()
+{
+	uint8 *buf = new uint8[CDSTREAM_SECTOR_SIZE];
+	CDirectory *pDir = new CDirectory(TXDSTORESIZE);
+	CDirectory::DirectoryInfo dirInfo;
+
+	CStreaming::FlushRequestList();
+
+	RwFileFunctions *filesys = RwOsGetFileInterface();
+
+	RwStream *img = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMWRITE, "models\\txd.img");
+	if (img == nil) {
+		if (_dwOperatingSystemVersion == OS_WINNT || _dwOperatingSystemVersion == OS_WIN2000 || _dwOperatingSystemVersion == OS_WINXP) {
+			DealWithTxdWriteError(0, TXDSTORESIZE, "CVT_CRT");
+			delete []buf;
+			delete pDir;
+		}
+		return false;
+	}
+
+	int32 i;
+	for (i = 0; i < TXDSTORESIZE; i++) {
+		ConvertingTexturesScreen(i, TXDSTORESIZE, "CVT_MSG");
+
+		if (CTxdStore::GetSlot(i) != nil && CStreaming::IsObjectInCdImage(i + STREAM_OFFSET_TXD)) {
+			CStreaming::RequestTxd(i, STREAMFLAGS_KEEP_IN_MEMORY);
+			CStreaming::RequestModelStream(0);
+			CStreaming::FlushChannels();
+
+			char filename[64];
+			sprintf(filename, "%s.txd", CTxdStore::GetTxdName(i));
+
+			if (CTxdStore::GetSlot(i)->texDict) {
+				int32 pos = filesys->rwftell(img->Type.file.fpFile);
+
+				if (RwTexDictionaryStreamWrite(CTxdStore::GetSlot(i)->texDict, img) == nil) {
+					DealWithTxdWriteError(i, TXDSTORESIZE, "CVT_ERR");
+					RwStreamClose(img, nil);
+					delete []buf;
+					delete pDir;
+					CStreaming::RemoveTxd(i);
+					return false;
+				}
+
+				int32 size = filesys->rwftell(img->Type.file.fpFile) - pos;
+				int32 num = size % CDSTREAM_SECTOR_SIZE;
+
+				size /= CDSTREAM_SECTOR_SIZE;
+				if (num != 0) {
+					size++;
+					num = CDSTREAM_SECTOR_SIZE - num;
+					RwStreamWrite(img, buf, num);
+				}
+
+				dirInfo.offset = pos / CDSTREAM_SECTOR_SIZE;
+				dirInfo.size = size;
+				strncpy(dirInfo.name, filename, sizeof(dirInfo.name));
+				pDir->AddItem(dirInfo);
+				CStreaming::RemoveTxd(i);
+			}
+			CStreaming::FlushRequestList();
+		}
+	}
+
+	RwStreamClose(img, nil);
+	delete []buf;
+
+	if (!pDir->WriteDirFile("models\\txd.dir")) {
+		DealWithTxdWriteError(i, TXDSTORESIZE, "CVT_ERR");
+		delete pDir;
+		return false;
+	}
+
+	delete pDir;
+
+	WriteVideoCardCapsFile();
+	return true;
+}
+#endif // GTA_PC
+
 STARTPATCHES
 	InjectHook(0x592380, RwTextureGtaStreamRead, PATCH_JUMP);
 	InjectHook(0x5924A0, RwTexDictionaryGtaStreamRead, PATCH_JUMP);
 	InjectHook(0x592550, RwTexDictionaryGtaStreamRead1, PATCH_JUMP);
 	InjectHook(0x592650, RwTexDictionaryGtaStreamRead2, PATCH_JUMP);
+
+	InjectHook(0x5926C0, ReadVideoCardCapsFile, PATCH_JUMP);
+	InjectHook(0x592740, CheckVideoCardCaps, PATCH_JUMP);
+	InjectHook(0x5927D0, WriteVideoCardCapsFile, PATCH_JUMP);
+	InjectHook(0x592880, ConvertingTexturesScreen, PATCH_JUMP);
+	InjectHook(0x592BF0, DealWithTxdWriteError, PATCH_JUMP);
+	InjectHook(0x592C70, CreateTxdImageForVideoCard, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/render/TexList.cpp b/src/render/TexList.cpp
new file mode 100644
index 00000000..daed620a
--- /dev/null
+++ b/src/render/TexList.cpp
@@ -0,0 +1,41 @@
+#include "common.h"
+#include "TexList.h"
+#include "rtbmp.h"
+#include "FileMgr.h"
+
+bool CTexList::ms_nTexUsed[MAX_TEXUSED];
+
+void
+CTexList::Initialise()
+{}
+
+void
+CTexList::Shutdown()
+{}
+
+RwTexture *
+CTexList::SetTexture(int32 slot, char *name)
+{
+	return nil;
+}
+
+int32
+CTexList::GetFirstFreeTexture()
+{
+	for (int32 i = 0; i < MAX_TEXUSED; i++)
+		if (!ms_nTexUsed[i])
+			return i;
+	return -1;
+}
+
+RwTexture *
+CTexList::LoadFileNameTexture(char *name)
+{
+	return SetTexture(GetFirstFreeTexture(), name);
+}
+
+void
+CTexList::LoadGlobalTextureList()
+{
+	CFileMgr::SetDir("TEXTURES");
+}
\ No newline at end of file
diff --git a/src/render/TexList.h b/src/render/TexList.h
new file mode 100644
index 00000000..c6618fba
--- /dev/null
+++ b/src/render/TexList.h
@@ -0,0 +1,14 @@
+#pragma once
+
+class CTexList
+{
+	enum { MAX_TEXUSED = 400, };
+	static bool ms_nTexUsed[MAX_TEXUSED];
+public:
+	static void Initialise();
+	static void Shutdown();
+	static RwTexture *SetTexture(int32 slot, char *name);
+	static int32 GetFirstFreeTexture();
+	static RwTexture *LoadFileNameTexture(char *name);
+	static void LoadGlobalTextureList();
+};
\ No newline at end of file