Skip to content

Commit

Permalink
Roadsign support
Browse files Browse the repository at this point in the history
  • Loading branch information
FileEX committed Oct 2, 2024
1 parent b27c977 commit 942c4f9
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 57 deletions.
145 changes: 127 additions & 18 deletions Client/game_sa/C2DEffectSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,10 @@ void C2DEffectSA::SetRoadsignText(const std::string& text, std::uint8_t line)
if (IsValidRoadsign())
{
if (!m_effectInterface->effect.roadsign.text)
{
m_effectInterface->effect.roadsign.text = static_cast<char*>(std::malloc(64));
MemSetFast(m_effectInterface->effect.roadsign.text, 0, 64);
}

if (!m_effectInterface->effect.roadsign.text)
return;
Expand All @@ -207,6 +210,32 @@ void C2DEffectSA::SetRoadsignText(const std::string& text, std::uint8_t line)
}
}

RwV2d& C2DEffectSA::GetRoadsignSize()
{
if (IsValidRoadsign())
return m_effectInterface->effect.roadsign.size;

static RwV2d dummySize{0, 0};
return dummySize;
}

RwV3d& C2DEffectSA::GetRoadsignRotation()
{
if (IsValidRoadsign())
return m_effectInterface->effect.roadsign.rotation;

static RwV3d dummyRotation{0, 0, 0};
return dummyRotation;
}

std::string C2DEffectSA::GetRoadsignText() const
{
if (IsValidRoadsign() && m_effectInterface->effect.roadsign.text)
return std::string(m_effectInterface->effect.roadsign.text, 64);

return "";
}

void C2DEffectSA::SetEscalatorBottom(const RwV3d& bottom)
{
if (IsValidEscalator())
Expand All @@ -231,6 +260,99 @@ void C2DEffectSA::SetEscalatorDirection(std::uint8_t direction)
m_effectInterface->effect.escalator.direction = direction;
}

RwV3d& C2DEffectSA::GetEscalatorBottom()
{
if (IsValidEscalator())
return m_effectInterface->effect.escalator.bottom;

static RwV3d dummyBottom{0, 0, 0};
return dummyBottom;
}

RwV3d& C2DEffectSA::GetEscalatorTop()
{
if (IsValidEscalator())
return m_effectInterface->effect.escalator.top;

static RwV3d dummyTop{0, 0, 0};
return dummyTop;
}

RwV3d& C2DEffectSA::GetEscalatorEnd()
{
if (IsValidEscalator())
return m_effectInterface->effect.escalator.end;

static RwV3d dummyEnd{0, 0, 0};
return dummyEnd;
}

RpAtomic* C2DEffectSA::Roadsign_CreateAtomic(const RwV3d& position, const RwV3d& rotation, float sizeX, float sizeY, std::uint32_t numLines, char* line1, char* line2, char* line3, char* line4, std::uint32_t numLetters, std::uint8_t palleteID)
{
// Call CCustomRoadsignMgr::CreateRoadsignAtomic
RpAtomic* atomic = ((RpAtomic*(__cdecl*)(float, float, std::int32_t, char*, char*, char*, char*, std::int32_t, std::uint8_t))0x6FF2D0)(sizeX, sizeY, numLines, line1, line2, line3, line4, numLetters, palleteID);
RwFrame* frame = RpAtomicGetFrame(atomic);
RwFrameSetIdentity(frame);

const RwV3d axis0{1.0f, 0.0f, 0.0f}, axis1{0.0f, 1.0f, 0.0f}, axis2{0.0f, 0.0f, 1.0f};
RwFrameRotate(frame, &axis2, rotation.z, rwCOMBINEREPLACE);
RwFrameRotate(frame, &axis0, rotation.x, rwCOMBINEPOSTCONCAT);
RwFrameRotate(frame, &axis1, rotation.y, rwCOMBINEPOSTCONCAT);

RwFrameTranslate(frame, &position, TRANSFORM_AFTER);
RwFrameUpdateObjects(frame);

return atomic;
}

std::uint32_t C2DEffectSA::Roadsign_GetPalleteIDFromFlags(std::uint8_t flags)
{
std::uint32_t id = (flags >> 4) & 3;
return id <= 3 ? id : 0;
}

std::uint32_t C2DEffectSA::Roadsign_GetNumLettersFromFlags(std::uint8_t flags)
{
std::uint32_t letters = (flags >> 2) & 3;
switch (letters)
{
case 1u:
return 2;
case 2u:
return 4;
case 3u:
return 8;
default:
return 16;
}
}

std::uint32_t C2DEffectSA::Roadsign_GetNumLinesFromFlags(std::uint8_t flags)
{
std::uint32_t lines = flags & 3;
return (lines <= 3 && lines > 0) ? lines : 4;
}

void C2DEffectSA::Roadsign_DestroyAtomic(C2DEffectSAInterface* effect)
{
if (!effect)
return;

t2dEffectRoadsign& roadsign = effect->effect.roadsign;
if (roadsign.atomic)
{
RwFrame* frame = RpAtomicGetFrame(roadsign.atomic);
if (frame)
{
RpAtomicSetFrame(roadsign.atomic, nullptr);
RwFrameDestroy(frame);
}

RpAtomicDestroy(roadsign.atomic);
roadsign.atomic = nullptr;
}
}

C2DEffectSAInterface* C2DEffectSA::CreateCopy(C2DEffectSAInterface* effect)
{
C2DEffectSAInterface* copy = new C2DEffectSAInterface();
Expand All @@ -250,17 +372,16 @@ C2DEffectSAInterface* C2DEffectSA::CreateCopy(C2DEffectSAInterface* effect)
copy->effect.roadsign.text = static_cast<char*>(std::malloc(64));
if (copy->effect.roadsign.text)
{
std::memset(copy->effect.roadsign.text, 0, 64);
std::strncpy(copy->effect.roadsign.text, effect->effect.roadsign.text, 64);
}
MemSetFast(copy->effect.roadsign.text, 0, 64);
MemCpyFast(copy->effect.roadsign.text, effect->effect.roadsign.text, 64);

copy->effect.roadsign.atomic = RpAtomicClone(effect->effect.roadsign.atomic);
copy->effect.roadsign.atomic = Roadsign_CreateAtomic(copy->position, copy->effect.roadsign.rotation, copy->effect.roadsign.size.x, copy->effect.roadsign.size.y, Roadsign_GetNumLinesFromFlags(copy->effect.roadsign.flags), &copy->effect.roadsign.text[0], &copy->effect.roadsign.text[16], &copy->effect.roadsign.text[32], &copy->effect.roadsign.text[48], Roadsign_GetNumLettersFromFlags(copy->effect.roadsign.flags), Roadsign_GetPalleteIDFromFlags(copy->effect.roadsign.flags));
}
}

return copy;
}

// C2DEffect::Shutdown causes random unknown crash in ntdll.dll so we need own function
void C2DEffectSA::Shutdown(C2DEffectSAInterface* effect)
{
if (!effect)
Expand All @@ -269,25 +390,13 @@ void C2DEffectSA::Shutdown(C2DEffectSAInterface* effect)
if (effect->type == e2dEffectType::ROADSIGN)
{
t2dEffectRoadsign& roadsign = effect->effect.roadsign;
Roadsign_DestroyAtomic(effect);

if (roadsign.text)
{
std::free(roadsign.text);
roadsign.text = nullptr;
}

if (roadsign.atomic)
{
RwFrame* frame = RpAtomicGetFrame(roadsign.atomic);
if (frame)
{
RpAtomicSetFrame(roadsign.atomic, nullptr);
RwFrameDestroy(frame);
}

RpAtomicDestroy(roadsign.atomic);
roadsign.atomic = nullptr;
}
}
else if (effect->type == e2dEffectType::LIGHT)
{
Expand Down
21 changes: 13 additions & 8 deletions Client/game_sa/C2DEffectSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class C2DEffectSA : public C2DEffect
~C2DEffectSA() = default;

C2DEffectSAInterface* GetInterface() noexcept { return m_effectInterface; }
e2dEffectType GetEffectType() override { return m_effectInterface ? m_effectInterface->type : e2dEffectType::NONE; }

bool IsValidLight() const noexcept { return m_effectInterface && m_effectInterface->type == e2dEffectType::LIGHT; };
bool IsValidRoadsign() const noexcept { return m_effectInterface && m_effectInterface->type == e2dEffectType::ROADSIGN; }
Expand Down Expand Up @@ -80,7 +81,7 @@ class C2DEffectSA : public C2DEffect
std::uint8_t GetCoronaFlareType() const override { return IsValidLight() ? m_effectInterface->effect.light.coronaFlareType : 0; }
std::uint16_t GetLightFlags() const override { return IsValidLight() ? m_effectInterface->effect.light.flags : 0; }
std::int8_t GetShadowDistance() const override { return IsValidLight() ? m_effectInterface->effect.light.shadowZDistance : 0; }
CVector GetCoronaOffsets() const override;
CVector GetCoronaOffsets() const override;
RwColor GetCoronaColor() const override { return IsValidLight() ? m_effectInterface->effect.light.color : RwColor{0,0,0,0}; }
std::string GetCoronaTexture() const override { return IsValidLight() ? (m_effectInterface->effect.light.coronaTex ? m_effectInterface->effect.light.coronaTex->name : "") : ""; }
std::string GetShadowTexture() const override { return IsValidLight() ? (m_effectInterface->effect.light.shadowTex ? m_effectInterface->effect.light.shadowTex->name : "") : ""; }
Expand All @@ -100,10 +101,10 @@ class C2DEffectSA : public C2DEffect
void SetRoadsignText(const std::string& text, std::uint8_t line) override;

// Get
RwV2d GetRoadsignSize() const override { return IsValidRoadsign() ? m_effectInterface->effect.roadsign.size : RwV2d{0,0}; }
RwV3d GetRoadsignRotation() const override { return IsValidRoadsign() ? m_effectInterface->effect.roadsign.rotation : RwV3d{0,0,0}; }
RwV2d& GetRoadsignSize() override;
RwV3d& GetRoadsignRotation() override;
std::uint16_t GetRoadsignFlags() const override { return IsValidRoadsign() ? m_effectInterface->effect.roadsign.flags : 0; }
std::string GetRoadsignText() const override { return IsValidRoadsign() ? (m_effectInterface->effect.roadsign.text ? std::string(m_effectInterface->effect.roadsign.text, strnlen(m_effectInterface->effect.roadsign.text, 64)) : "") : ""; }
std::string GetRoadsignText() const override;

// Escalator properties
// Set
Expand All @@ -113,12 +114,16 @@ class C2DEffectSA : public C2DEffect
void SetEscalatorDirection(std::uint8_t direction) override;

// Get
RwV3d GetEscalatorBottom() const override { return IsValidEscalator() ? m_effectInterface->effect.escalator.bottom : RwV3d{0, 0, 0}; }
RwV3d GetEscalatorTop() const override { return IsValidEscalator() ? m_effectInterface->effect.escalator.top : RwV3d{0, 0, 0}; }
RwV3d GetEscalatorEnd() const override { return IsValidEscalator() ? m_effectInterface->effect.escalator.end : RwV3d{0, 0, 0}; }
RwV3d& GetEscalatorBottom() override;
RwV3d& GetEscalatorTop() override;
RwV3d& GetEscalatorEnd() override;
std::uint8_t GetEscalatorDirection() const override { return IsValidEscalator() ? m_effectInterface->effect.escalator.direction : 0; }

e2dEffectType GetEffectType() override { return m_effectInterface ? m_effectInterface->type : e2dEffectType::NONE; }
static RpAtomic* Roadsign_CreateAtomic(const RwV3d& position, const RwV3d& rotation, float sizeX, float sizeY, std::uint32_t numLines, char* line1, char* line2, char* line3, char* line4, std::uint32_t numLetters, std::uint8_t palleteID);
static std::uint32_t Roadsign_GetPalleteIDFromFlags(std::uint8_t flags);
static std::uint32_t Roadsign_GetNumLettersFromFlags(std::uint8_t flags);
static std::uint32_t Roadsign_GetNumLinesFromFlags(std::uint8_t flags);
static void Roadsign_DestroyAtomic(C2DEffectSAInterface* effect);

static C2DEffectSAInterface* CreateCopy(C2DEffectSAInterface* effect);

Expand Down
30 changes: 27 additions & 3 deletions Client/game_sa/CModelInfoSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2157,6 +2157,20 @@ void CModelInfoSA::Update2DFXEffect(C2DEffectSA* effect)
// Call Fx_c::CreateEntityFx
((void(__thiscall*)(CFxSAInterface*, CEntitySAInterface*, const char*, RwV3d*, RwMatrix*))FUNC_Fx_c_CreateEntityFx)(fx, entity, effectInterface->effect.particle.szName, &effectInterface->position, matrixTransform);
}

break;
}
case e2dEffectType::ROADSIGN:
{
t2dEffectRoadsign& roadsign = effectInterface->effect.roadsign;
C2DEffectSA::Roadsign_DestroyAtomic(effectInterface);

std::uint32_t numLines = C2DEffectSA::Roadsign_GetNumLinesFromFlags(roadsign.flags);
std::uint32_t numLetters = C2DEffectSA::Roadsign_GetNumLettersFromFlags(roadsign.flags);
std::uint8_t palleteID = C2DEffectSA::Roadsign_GetPalleteIDFromFlags(roadsign.flags);
roadsign.atomic = C2DEffectSA::Roadsign_CreateAtomic(effectInterface->position, roadsign.rotation, roadsign.size.x, roadsign.size.y, numLines, &roadsign.text[0], &roadsign.text[16], &roadsign.text[32], &roadsign.text[48], numLetters, palleteID);

break;
}
}
}
Expand Down Expand Up @@ -2301,6 +2315,7 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault)

// Prevent creation when stream in but keep in memory so we can restore it later
effect->type = e2dEffectType::NONE;
break;
}
case e2dEffectType::SUN_GLARE:
{
Expand All @@ -2318,8 +2333,11 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault)
MapGet(ms_NumOfCustom2DFXEffects, m_pInterface)--;
ms_Custom2DFXEffects.erase(it);

delete effect;
effect = nullptr;
if (effect)
{
delete effect;
effect = nullptr;
}
}
}

Expand Down Expand Up @@ -2432,8 +2450,14 @@ void CModelInfoSA::RestoreModified2DFXEffects()
if (tempVec && (*tempVec)[i])
{
MemCpyFast(effectInterface, (*tempVec)[i], sizeof(C2DEffectSAInterface));
C2DEffectSA::SafeDelete2DFXEffect((*tempVec)[i]);
effectInterface->effect.roadsign.text = static_cast<char*>(std::malloc(64));
if (effectInterface->effect.roadsign.text)
{
MemSetFast(effectInterface->effect.roadsign.text, 0, 64);
MemCpyFast(effectInterface->effect.roadsign.text, (*tempVec)[i]->effect.roadsign.text, 64);
}

C2DEffectSA::SafeDelete2DFXEffect((*tempVec)[i]);
Update2DFXEffect(effect);
}
}
Expand Down
3 changes: 2 additions & 1 deletion Client/game_sa/gamesa_renderware.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ typedef int(__cdecl* RpHAnimIDGetIndex_t)(RpHAnimHierarchy*, int);
typedef RwMatrix*(__cdecl* RpHAnimHierarchyGetMatrixArray_t)(RpHAnimHierarchy*);
typedef RtQuat*(__cdecl* RtQuatRotate_t)(RtQuat* quat, const RwV3d* axis, float angle, RwOpCombineType combineOp);
typedef RwTexture*(__cdecl* RwReadTexture_t)(const char* name, const char* mask);
typedef RwFrame*(__cdecl* RwFrameRotate_t)(RwFrame* frame, const RwV3d* axis, float angle, RwOpCombineType combine);

/*****************************************************************************/
/** Renderware function mappings **/
Expand Down Expand Up @@ -197,7 +198,7 @@ RWFUNC(RpHAnimIDGetIndex_t RpHAnimIDGetIndex, (RpHAnimIDGetIndex_t)0xDEAD)
RWFUNC(RpHAnimHierarchyGetMatrixArray_t RpHAnimHierarchyGetMatrixArray, (RpHAnimHierarchyGetMatrixArray_t)0xDEAD)
RWFUNC(RtQuatRotate_t RtQuatRotate, (RtQuatRotate_t)0xDEAD)
RWFUNC(RwReadTexture_t RwReadTexture, reinterpret_cast<RwReadTexture_t>(0xDEAD))

RWFUNC(RwFrameRotate_t RwFrameRotate, reinterpret_cast<RwFrameRotate_t>(0xDEAD))
/*****************************************************************************/
/** GTA function definitions and mappings **/
/*****************************************************************************/
Expand Down
1 change: 1 addition & 0 deletions Client/game_sa/gamesa_renderware.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ void InitRwFunctions()
RpHAnimHierarchyGetMatrixArray = (RpHAnimHierarchyGetMatrixArray_t)0x7C5120;
RtQuatRotate = (RtQuatRotate_t)0x7EB7C0;
RwReadTexture = reinterpret_cast<RwReadTexture_t>(0x7F3AC0);
RwFrameRotate = reinterpret_cast<RwFrameRotate_t>(0x7F1010);

SetTextureDict = (SetTextureDict_t)0x007319C0;
LoadClumpFile = (LoadClumpFile_t)0x005371F0;
Expand Down
Loading

0 comments on commit 942c4f9

Please sign in to comment.