From 5854016ec51458711eacc7b1ac1fa415ee9db979 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 28 Sep 2019 21:39:58 +0300 Subject: [PATCH] PlayerSkin --- src/core/Frontend.cpp | 2 +- src/core/PlayerInfo.cpp | 24 +++++- src/core/PlayerInfo.h | 1 + src/core/PlayerSkin.cpp | 166 +++++++++++++++++++++++++++++++++++++++- src/core/PlayerSkin.h | 16 +++- 5 files changed, 205 insertions(+), 4 deletions(-) diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index effcb0b4..30b80634 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -2383,7 +2383,7 @@ void CMenuManager::SwitchToNewScreen(int32 screen) // Set player skin. if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { - CPlayerSkin::BeginFrontEndSkinEdit(); + CPlayerSkin::BeginFrontendSkinEdit(); m_bSkinsFound = false; } diff --git a/src/core/PlayerInfo.cpp b/src/core/PlayerInfo.cpp index 8c505eb4..dc72848d 100644 --- a/src/core/PlayerInfo.cpp +++ b/src/core/PlayerInfo.cpp @@ -4,9 +4,9 @@ #include "PlayerInfo.h" #include "Frontend.h" #include "Vehicle.h" +#include "PlayerSkin.h" WRAPPER void CPlayerInfo::MakePlayerSafe(bool) { EAXJMP(0x4A1400); } -WRAPPER void CPlayerInfo::LoadPlayerSkin() { EAXJMP(0x4A1700); } WRAPPER void CPlayerInfo::AwardMoneyForExplosion(CVehicle *vehicle) { EAXJMP(0x4A15F0); } WRAPPER void CPlayerInfo::Process(void) { EAXJMP(0x49FD30); } @@ -22,3 +22,25 @@ CVector& CPlayerInfo::GetPos() return m_pPed->m_pMyVehicle->GetPosition(); return m_pPed->GetPosition(); } + +void CPlayerInfo::LoadPlayerSkin() +{ + DeletePlayerSkin(); + + m_pSkinTexture = CPlayerSkin::GetSkinTexture(m_aSkinName); + if (!m_pSkinTexture) + m_pSkinTexture = CPlayerSkin::GetSkinTexture(DEFAULT_SKIN_NAME); +} + +void CPlayerInfo::DeletePlayerSkin() +{ + if (m_pSkinTexture) { + RwTextureDestroy(m_pSkinTexture); + m_pSkinTexture = NULL; + } +} + +STARTPATCHES +InjectHook(0x4A1700, &CPlayerInfo::LoadPlayerSkin, PATCH_JUMP); +InjectHook(0x4A1750, &CPlayerInfo::DeletePlayerSkin, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h index 29290f6e..f0b879ee 100644 --- a/src/core/PlayerInfo.h +++ b/src/core/PlayerInfo.h @@ -68,6 +68,7 @@ public: void MakePlayerSafe(bool); void LoadPlayerSkin(); + void DeletePlayerSkin(); void AwardMoneyForExplosion(CVehicle *vehicle); void SetPlayerSkin(char* skin); CVector& GetPos(); diff --git a/src/core/PlayerSkin.cpp b/src/core/PlayerSkin.cpp index 1c9ca2c6..6290351a 100644 --- a/src/core/PlayerSkin.cpp +++ b/src/core/PlayerSkin.cpp @@ -1,5 +1,169 @@ #include "common.h" #include "patcher.h" +#include "main.h" #include "PlayerSkin.h" +#include "TxdStore.h" +#include "rtbmp.h" +#include "ClumpModelInfo.h" +#include "VisibilityPlugins.h" +#include "World.h" +#include "PlayerInfo.h" +#include "CdStream.h" +#include "FileMgr.h" +#include "Directory.h" +#include "RwHelper.h" +#include "Timer.h" +#include "Lights.h" -WRAPPER void CPlayerSkin::BeginFrontEndSkinEdit() { EAXJMP(0x59BC70); } +int CPlayerSkin::m_txdSlot; + +void +FindPlayerDff(uint32 &offset, uint32 &size) +{ + int file; + CDirectory::DirectoryInfo info; + + file = CFileMgr::OpenFile("models\\gta3.dir", "rb"); + + do { + if (!CFileMgr::Read(file, (char*)&info, sizeof(CDirectory::DirectoryInfo))) + return; + } while (strcmpi("player.dff", info.name)); + + offset = info.offset; + size = info.size; +} + +void +LoadPlayerDff(void) +{ + RwStream *stream; + RwMemory mem; + uint32 offset, size; + uint8 *buffer; + bool streamWasAdded = false; + + if (!CdStreamGetNumImages()) { + CdStreamAddImage("models\\gta3.img"); + streamWasAdded = true; + } + + FindPlayerDff(offset, size); + buffer = (uint8*)RwMallocAlign(size << 11, 2048); + CdStreamRead(0, buffer, offset, size); + CdStreamSync(0); + + mem.start = buffer; + mem.length = size << 11; + stream = RwStreamOpen(rwSTREAMMEMORY, rwSTREAMREAD, &mem); + + if (RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)) + gpPlayerClump = RpClumpStreamRead(stream); + + RwStreamClose(stream, &mem); + RwFreeAlign(buffer); + + if (streamWasAdded) + CdStreamRemoveImages(); +} + +void +CPlayerSkin::Initialise(void) +{ + m_txdSlot = CTxdStore::AddTxdSlot("skin"); + CTxdStore::Create(m_txdSlot); + CTxdStore::AddRef(m_txdSlot); +} + +void +CPlayerSkin::Shutdown(void) +{ + CTxdStore::RemoveTxdSlot(m_txdSlot); +} + +RwTexture * +CPlayerSkin::GetSkinTexture(const char *texName) +{ + RwTexture *tex; + RwRaster *raster; + int32 width, height, depth, format; + + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(m_txdSlot); + tex = RwTextureRead(texName, NULL); + CTxdStore::PopCurrentTxd(); + if (tex) return tex; + + if (!strcmp(DEFAULT_SKIN_NAME, texName)) + sprintf(gString, "models\\generic\\player.bmp"); + else + sprintf(gString, "skins\\%s.bmp", texName); + + if (RwImage *image = RtBMPImageRead(gString)) { + RwImageFindRasterFormat(image, rwRASTERTYPETEXTURE, &width, &height, &depth, &format); + raster = RwRasterCreate(width, height, depth, format); + RwRasterSetFromImage(raster, image); + + tex = RwTextureCreate(raster); + RwTextureSetName(tex, texName); + RwTextureSetFilterMode(tex, rwFILTERLINEAR); // filtering bugfix from VC + RwTexDictionaryAddTexture(CTxdStore::GetSlot(m_txdSlot)->texDict, tex); + + RwImageDestroy(image); + } + return tex; +} + +void +CPlayerSkin::BeginFrontendSkinEdit(void) +{ + LoadPlayerDff(); + RpClumpForAllAtomics(gpPlayerClump, CClumpModelInfo::SetAtomicRendererCB, CVisibilityPlugins::RenderPlayerCB); + CWorld::Players[0].LoadPlayerSkin(); + gOldFov = CDraw::GetFOV(); + CDraw::SetFOV(30.0f); +} + +void +CPlayerSkin::EndFrontendSkinEdit(void) +{ + RpClumpDestroy(gpPlayerClump); + gpPlayerClump = NULL; + CDraw::SetFOV(gOldFov); +} + +void +CPlayerSkin::RenderFrontendSkinEdit(void) +{ + static float rotation = 0.0f; + RwRGBAReal AmbientColor = { 0.65f, 0.65f, 0.65f, 1.0f }; + const RwV3d pos = { 1.35f, 0.35f, 7.725f }; + const RwV3d axis1 = { 1.0f, 0.0f, 0.0f }; + const RwV3d axis2 = { 0.0f, 0.0f, 1.0f }; + static uint32 LastFlash = 0; + + RwFrame *frame = RpClumpGetFrame(gpPlayerClump); + + if (CTimer::GetTimeInMillisecondsPauseMode() - LastFlash > 7) { + rotation += 2.0f; + if (rotation > 360.0f) + rotation -= 360.0f; + LastFlash = CTimer::GetTimeInMillisecondsPauseMode(); + } + RwFrameTransform(frame, RwFrameGetMatrix(RwCameraGetFrame(Scene.camera)), rwCOMBINEREPLACE); + RwFrameTranslate(frame, &pos, rwCOMBINEPRECONCAT); + RwFrameRotate(frame, &axis1, -90.0f, rwCOMBINEPRECONCAT); + RwFrameRotate(frame, &axis2, rotation, rwCOMBINEPRECONCAT); + RwFrameUpdateObjects(frame); + SetAmbientColours(&AmbientColor); + RpClumpRender(gpPlayerClump); +} + +STARTPATCHES +InjectHook(0x59B9B0, &CPlayerSkin::Initialise, PATCH_JUMP); +InjectHook(0x59B9E0, &CPlayerSkin::Shutdown, PATCH_JUMP); +InjectHook(0x59B9F0, &CPlayerSkin::GetSkinTexture, PATCH_JUMP); +InjectHook(0x59BC70, &CPlayerSkin::BeginFrontendSkinEdit, PATCH_JUMP); +InjectHook(0x59BCB0, &CPlayerSkin::EndFrontendSkinEdit, PATCH_JUMP); +InjectHook(0x59BCE0, &CPlayerSkin::RenderFrontendSkinEdit, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/core/PlayerSkin.h b/src/core/PlayerSkin.h index 61e09cdf..2d82ec12 100644 --- a/src/core/PlayerSkin.h +++ b/src/core/PlayerSkin.h @@ -1,7 +1,21 @@ #pragma once +#define DEFAULT_SKIN_NAME "$$\"\"" + +static RpClump *gpPlayerClump;// = *(RpClump**)0x660FF8; +static float gOldFov;// = *(float*)0x660FFC; + +void LoadPlayerDff(void); +void FindPlayerDff(uint32 &offset, uint32 &size); + class CPlayerSkin { + static int m_txdSlot; public: - static void BeginFrontEndSkinEdit(); + static void Initialise(); + static void Shutdown(); + static RwTexture *GetSkinTexture(const char *texName); + static void BeginFrontendSkinEdit(); + static void EndFrontendSkinEdit(); + static void RenderFrontendSkinEdit(); }; \ No newline at end of file