Skip to content

Commit b27c977

Browse files
committed
Huge rework & update
1 parent b137a39 commit b27c977

18 files changed

+1031
-444
lines changed

Client/game_sa/C2DEffectSA.cpp

+246
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,252 @@
1313
#include "gamesa_renderware.h"
1414
#include "C2DEffectSA.h"
1515
#include "C2DEffectSAInterface.h"
16+
#include "CGameSA.h"
17+
18+
extern CGameSA* pGame;
19+
20+
C2DEffectSA::C2DEffectSA(C2DEffectSAInterface* effectInterface, std::uint32_t modelID) : m_effectInterface(effectInterface), m_model(modelID)
21+
{
22+
pGame->Get2DEffects()->AddToList(this);
23+
}
24+
25+
void C2DEffectSA::Destroy() const
26+
{
27+
CModelInfo* modelInfo = pGame->GetModelInfo(m_model);
28+
if (modelInfo)
29+
modelInfo->Remove2DFX(m_effectInterface, false);
30+
}
31+
32+
void C2DEffectSA::SetPosition(const CVector& position)
33+
{
34+
if (m_effectInterface)
35+
m_effectInterface->position = RwV3d{position.fX, position.fY, position.fZ};
36+
}
37+
38+
CVector& C2DEffectSA::GetPosition()
39+
{
40+
if (m_effectInterface)
41+
return CVector(m_effectInterface->position.x, m_effectInterface->position.y, m_effectInterface->position.z);
42+
43+
return CVector();
44+
}
45+
46+
void C2DEffectSA::SetCoronaFarClip(float clip)
47+
{
48+
if (IsValidLight())
49+
m_effectInterface->effect.light.coronaFarClip = clip;
50+
}
51+
52+
void C2DEffectSA::SetCoronaPointLightRange(float range)
53+
{
54+
if (IsValidLight())
55+
m_effectInterface->effect.light.pointLightRange = range;
56+
}
57+
58+
void C2DEffectSA::SetCoronaSize(float size)
59+
{
60+
if (IsValidLight())
61+
m_effectInterface->effect.light.coronaSize = size;
62+
}
63+
64+
void C2DEffectSA::SetShadowSize(float size)
65+
{
66+
if (IsValidLight())
67+
m_effectInterface->effect.light.shadowSize = size;
68+
}
69+
70+
void C2DEffectSA::SetShadowMultiplier(std::uint8_t multiplier)
71+
{
72+
if (IsValidLight())
73+
m_effectInterface->effect.light.shadowColorMultiplier = multiplier;
74+
}
75+
76+
void C2DEffectSA::SetCoronaShowMode(e2dCoronaFlashType showMode)
77+
{
78+
if (IsValidLight())
79+
m_effectInterface->effect.light.coronaFlashType = showMode;
80+
}
81+
82+
void C2DEffectSA::SetCoronaReflectionsEnabled(bool enable)
83+
{
84+
if (IsValidLight())
85+
m_effectInterface->effect.light.coronaEnableReflection = enable;
86+
}
87+
88+
void C2DEffectSA::SetCoronaFlareType(std::uint8_t flareType)
89+
{
90+
if (IsValidLight())
91+
m_effectInterface->effect.light.coronaFlareType = flareType;
92+
}
93+
94+
void C2DEffectSA::SetLightFlags(std::uint16_t flags)
95+
{
96+
if (IsValidLight())
97+
m_effectInterface->effect.light.flags = flags;
98+
}
99+
100+
void C2DEffectSA::SetShadowDistance(std::int8_t distance)
101+
{
102+
if (IsValidLight())
103+
m_effectInterface->effect.light.shadowZDistance = distance;
104+
}
105+
106+
void C2DEffectSA::SetCoronaOffsets(const CVector& offsets)
107+
{
108+
if (IsValidLight())
109+
{
110+
m_effectInterface->effect.light.offsetX = offsets.fX;
111+
m_effectInterface->effect.light.offsetY = offsets.fY;
112+
m_effectInterface->effect.light.offsetZ = offsets.fZ;
113+
}
114+
}
115+
116+
void C2DEffectSA::SetCoronaColor(const RwColor& color)
117+
{
118+
if (IsValidLight())
119+
m_effectInterface->effect.light.color = color;
120+
}
121+
122+
void C2DEffectSA::SetCoronaTexture(const std::string& name)
123+
{
124+
if (IsValidLight())
125+
{
126+
if (m_effectInterface->effect.light.coronaTex)
127+
RwTextureDestroy(m_effectInterface->effect.light.coronaTex);
128+
129+
// Call CTxdStore::PushCurrentTxd
130+
((void(__cdecl*)())FUNC_PushCurrentTxd)();
131+
// Call CTxdStore::FindTxdSlot
132+
int slot = ((int(__cdecl*)(const char*))FUNC_FindTxdSlot)("particle");
133+
// Call CTxdStore::SetCurrentTxd
134+
((void(__cdecl*)(int))FUNC_SetCurrentTxd)(slot);
135+
136+
m_effectInterface->effect.light.coronaTex = RwReadTexture(name.c_str(), nullptr);
137+
138+
// Call CTxdStore::PopCurrentTxd
139+
((void(__cdecl*)())FUNC_PopCurrentTxd)();
140+
}
141+
}
142+
143+
void C2DEffectSA::SetShadowTexture(const std::string& name)
144+
{
145+
if (IsValidLight())
146+
{
147+
if (m_effectInterface->effect.light.shadowTex)
148+
RwTextureDestroy(m_effectInterface->effect.light.shadowTex);
149+
150+
// Call CTxdStore::PushCurrentTxd
151+
((void(__cdecl*)())FUNC_PushCurrentTxd)();
152+
// Call CTxdStore::FindTxdSlot
153+
int slot = ((int(__cdecl*)(const char*))FUNC_FindTxdSlot)("particle");
154+
// Call CTxdStore::SetCurrentTxd
155+
((void(__cdecl*)(int))FUNC_SetCurrentTxd)(slot);
156+
157+
m_effectInterface->effect.light.shadowTex = RwReadTexture(name.c_str(), nullptr);
158+
159+
// Call CTxdStore::PopCurrentTxd
160+
((void(__cdecl*)())FUNC_PopCurrentTxd)();
161+
}
162+
}
163+
164+
CVector C2DEffectSA::GetCoronaOffsets() const
165+
{
166+
if (IsValidLight())
167+
return CVector(m_effectInterface->effect.light.offsetX, m_effectInterface->effect.light.offsetY, m_effectInterface->effect.light.offsetZ);
168+
169+
return CVector();
170+
}
171+
172+
void C2DEffectSA::SetParticleName(const std::string& name)
173+
{
174+
if (m_effectInterface && m_effectInterface->type == e2dEffectType::PARTICLE)
175+
std::strncpy(m_effectInterface->effect.particle.szName, name.c_str(), 24);
176+
}
177+
178+
void C2DEffectSA::SetRoadsignSize(const RwV2d& size)
179+
{
180+
if (IsValidRoadsign())
181+
m_effectInterface->effect.roadsign.size = size;
182+
}
183+
184+
void C2DEffectSA::SetRoadsignRotation(const RwV3d& rotation)
185+
{
186+
if (IsValidRoadsign())
187+
m_effectInterface->effect.roadsign.rotation = rotation;
188+
}
189+
190+
void C2DEffectSA::SetRoadsignFlags(std::uint8_t flags)
191+
{
192+
if (IsValidRoadsign())
193+
m_effectInterface->effect.roadsign.flags = flags;
194+
}
195+
196+
void C2DEffectSA::SetRoadsignText(const std::string& text, std::uint8_t line)
197+
{
198+
if (IsValidRoadsign())
199+
{
200+
if (!m_effectInterface->effect.roadsign.text)
201+
m_effectInterface->effect.roadsign.text = static_cast<char*>(std::malloc(64));
202+
203+
if (!m_effectInterface->effect.roadsign.text)
204+
return;
205+
206+
std::strncpy(m_effectInterface->effect.roadsign.text + 16 * (line - 1), text.c_str(), 16);
207+
}
208+
}
209+
210+
void C2DEffectSA::SetEscalatorBottom(const RwV3d& bottom)
211+
{
212+
if (IsValidEscalator())
213+
m_effectInterface->effect.escalator.bottom = bottom;
214+
}
215+
216+
void C2DEffectSA::SetEscalatorTop(const RwV3d& top)
217+
{
218+
if (IsValidEscalator())
219+
m_effectInterface->effect.escalator.top = top;
220+
}
221+
222+
void C2DEffectSA::SetEscalatorEnd(const RwV3d& end)
223+
{
224+
if (IsValidEscalator())
225+
m_effectInterface->effect.escalator.end = end;
226+
}
227+
228+
void C2DEffectSA::SetEscalatorDirection(std::uint8_t direction)
229+
{
230+
if (IsValidEscalator())
231+
m_effectInterface->effect.escalator.direction = direction;
232+
}
233+
234+
C2DEffectSAInterface* C2DEffectSA::CreateCopy(C2DEffectSAInterface* effect)
235+
{
236+
C2DEffectSAInterface* copy = new C2DEffectSAInterface();
237+
MemCpyFast(copy, effect, sizeof(C2DEffectSAInterface));
238+
239+
// Create a copy of textures for the lights
240+
// We must to do this, because C2DEffect::Shutdown removes them
241+
if (copy->type == e2dEffectType::LIGHT)
242+
{
243+
if (effect->effect.light.coronaTex && effect->effect.light.shadowTex)
244+
C2DEffectSA::PrepareTexturesForLightEffect(copy->effect.light.coronaTex, copy->effect.light.shadowTex, effect->effect.light.coronaTex->name, effect->effect.light.shadowTex->name, false);
245+
}
246+
else if (copy->type == e2dEffectType::ROADSIGN)
247+
{
248+
// Create a copy of text and atomic for the roadsign
249+
// We must to do this, because C2DEffect::Shutdown removes them
250+
copy->effect.roadsign.text = static_cast<char*>(std::malloc(64));
251+
if (copy->effect.roadsign.text)
252+
{
253+
std::memset(copy->effect.roadsign.text, 0, 64);
254+
std::strncpy(copy->effect.roadsign.text, effect->effect.roadsign.text, 64);
255+
}
256+
257+
copy->effect.roadsign.atomic = RpAtomicClone(effect->effect.roadsign.atomic);
258+
}
259+
260+
return copy;
261+
}
16262

17263
// C2DEffect::Shutdown causes random unknown crash in ntdll.dll so we need own function
18264
void C2DEffectSA::Shutdown(C2DEffectSAInterface* effect)

Client/game_sa/C2DEffectSA.h

+97-5
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
* PROJECT: Multi Theft Auto
44
* LICENSE: See LICENSE in the top level directory
55
* FILE: game_sa/C2DEffectSA.h
6-
* PURPOSE: Header file for 2dfx static class
6+
* PURPOSE: Header file for 2dfx class
77
*
88
* Multi Theft Auto is available from https://www.multitheftauto.com/
99
*
1010
*****************************************************************************/
1111

1212
#pragma once
13+
#include "game/C2DEffect.h"
14+
#include "C2DEffectSAInterface.h"
15+
#include <variant>
1316

1417
#define ARRAY_2DFXInfoStore 0xB4C2D8 // C2dfxInfoStore d2fxModels
1518

@@ -31,14 +34,103 @@
3134
#define OFFSET_FxSystem_Entities 0xC
3235
#define OFFSET_FxSystem_Link_Prev 0x4
3336

34-
class C2DEffectSAInterface;
35-
36-
class C2DEffectSA
37+
class C2DEffectSA : public C2DEffect
3738
{
3839
public:
39-
static int effect2dPluginOffset;
40+
C2DEffectSA(C2DEffectSAInterface* effectInterface, std::uint32_t modelID);
41+
~C2DEffectSA() = default;
42+
43+
C2DEffectSAInterface* GetInterface() noexcept { return m_effectInterface; }
44+
45+
bool IsValidLight() const noexcept { return m_effectInterface && m_effectInterface->type == e2dEffectType::LIGHT; };
46+
bool IsValidRoadsign() const noexcept { return m_effectInterface && m_effectInterface->type == e2dEffectType::ROADSIGN; }
47+
bool IsValidEscalator() const noexcept { return m_effectInterface && m_effectInterface->type == e2dEffectType::ESCALATOR; }
48+
bool IsValidParticle() const noexcept { return m_effectInterface && m_effectInterface->type == e2dEffectType::PARTICLE; }
49+
50+
void Destroy() const;
51+
52+
void SetPosition(const CVector& position) override;
53+
CVector& GetPosition() override;
54+
55+
// Light properties
56+
// Set
57+
void SetCoronaFarClip(float clip) override;
58+
void SetCoronaPointLightRange(float range) override;
59+
void SetCoronaSize(float size) override;
60+
void SetShadowSize(float size) override;
61+
void SetShadowMultiplier(std::uint8_t multiplier) override;
62+
void SetCoronaShowMode(e2dCoronaFlashType showMode) override;
63+
void SetCoronaReflectionsEnabled(bool enable) override;
64+
void SetCoronaFlareType(std::uint8_t flareType) override;
65+
void SetLightFlags(std::uint16_t flags) override;
66+
void SetShadowDistance(std::int8_t distance) override;
67+
void SetCoronaOffsets(const CVector& offsets) override;
68+
void SetCoronaColor(const RwColor& color) override;
69+
void SetCoronaTexture(const std::string& name) override;
70+
void SetShadowTexture(const std::string& name) override;
71+
72+
// Get
73+
float GetCoronaFarClip() const override { return IsValidLight() ? m_effectInterface->effect.light.coronaFarClip : 0.0f; }
74+
float GetCoronaPointLightRange() const override { return IsValidLight() ? m_effectInterface->effect.light.pointLightRange : 0.0f; }
75+
float GetCoronaSize() const override { return IsValidLight() ? m_effectInterface->effect.light.coronaSize : 0.0f; }
76+
float GetShadowSize() const override { return IsValidLight() ? m_effectInterface->effect.light.shadowSize : 0.0f; }
77+
std::uint8_t GetShadowMultiplier() const override { return IsValidLight() ? m_effectInterface->effect.light.shadowColorMultiplier : 0; }
78+
e2dCoronaFlashType GetCoronaShowMode() const override { return IsValidLight() ? m_effectInterface->effect.light.coronaFlashType : e2dCoronaFlashType::UNUSED; }
79+
bool GetCoronaReflectionsEnabled() const override { return IsValidLight() ? m_effectInterface->effect.light.coronaEnableReflection : false; }
80+
std::uint8_t GetCoronaFlareType() const override { return IsValidLight() ? m_effectInterface->effect.light.coronaFlareType : 0; }
81+
std::uint16_t GetLightFlags() const override { return IsValidLight() ? m_effectInterface->effect.light.flags : 0; }
82+
std::int8_t GetShadowDistance() const override { return IsValidLight() ? m_effectInterface->effect.light.shadowZDistance : 0; }
83+
CVector GetCoronaOffsets() const override;
84+
RwColor GetCoronaColor() const override { return IsValidLight() ? m_effectInterface->effect.light.color : RwColor{0,0,0,0}; }
85+
std::string GetCoronaTexture() const override { return IsValidLight() ? (m_effectInterface->effect.light.coronaTex ? m_effectInterface->effect.light.coronaTex->name : "") : ""; }
86+
std::string GetShadowTexture() const override { return IsValidLight() ? (m_effectInterface->effect.light.shadowTex ? m_effectInterface->effect.light.shadowTex->name : "") : ""; }
87+
88+
// Particle properties
89+
// Set
90+
void SetParticleName(const std::string& name) override;
91+
92+
// Get
93+
std::string GetParticleName() const override { return IsValidParticle() ? (m_effectInterface->effect.particle.szName ? m_effectInterface->effect.particle.szName : "") : ""; }
94+
95+
// Roadsign properties
96+
// Set
97+
void SetRoadsignSize(const RwV2d& size) override;
98+
void SetRoadsignRotation(const RwV3d& rotation) override;
99+
void SetRoadsignFlags(std::uint8_t flags) override;
100+
void SetRoadsignText(const std::string& text, std::uint8_t line) override;
101+
102+
// Get
103+
RwV2d GetRoadsignSize() const override { return IsValidRoadsign() ? m_effectInterface->effect.roadsign.size : RwV2d{0,0}; }
104+
RwV3d GetRoadsignRotation() const override { return IsValidRoadsign() ? m_effectInterface->effect.roadsign.rotation : RwV3d{0,0,0}; }
105+
std::uint16_t GetRoadsignFlags() const override { return IsValidRoadsign() ? m_effectInterface->effect.roadsign.flags : 0; }
106+
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)) : "") : ""; }
107+
108+
// Escalator properties
109+
// Set
110+
void SetEscalatorBottom(const RwV3d& bottom) override;
111+
void SetEscalatorTop(const RwV3d& top) override;
112+
void SetEscalatorEnd(const RwV3d& end) override;
113+
void SetEscalatorDirection(std::uint8_t direction) override;
114+
115+
// Get
116+
RwV3d GetEscalatorBottom() const override { return IsValidEscalator() ? m_effectInterface->effect.escalator.bottom : RwV3d{0, 0, 0}; }
117+
RwV3d GetEscalatorTop() const override { return IsValidEscalator() ? m_effectInterface->effect.escalator.top : RwV3d{0, 0, 0}; }
118+
RwV3d GetEscalatorEnd() const override { return IsValidEscalator() ? m_effectInterface->effect.escalator.end : RwV3d{0, 0, 0}; }
119+
std::uint8_t GetEscalatorDirection() const override { return IsValidEscalator() ? m_effectInterface->effect.escalator.direction : 0; }
120+
121+
e2dEffectType GetEffectType() override { return m_effectInterface ? m_effectInterface->type : e2dEffectType::NONE; }
122+
123+
static C2DEffectSAInterface* CreateCopy(C2DEffectSAInterface* effect);
40124

41125
static void Shutdown(C2DEffectSAInterface* effect);
42126
static void SafeDelete2DFXEffect(C2DEffectSAInterface* effect);
43127
static void PrepareTexturesForLightEffect(RwTexture*& coronaTex, RwTexture*& shadowTex, const char* coronaName, const char* shadowName, bool removeIfExist);
128+
129+
public:
130+
static int effect2dPluginOffset;
131+
132+
private:
133+
C2DEffectSAInterface* m_effectInterface;
134+
std::uint32_t m_model;
135+
44136
};

Client/game_sa/C2DEffectSAInterface.h

+1-6
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
#include "game/RenderWare.h"
1414
#include "game/CModelInfo.h"
15+
#include "game/C2DEffects.h"
1516
#include "CObjectSA.h"
16-
#include "C2DEffectSA.h"
1717

1818
struct t2dEffectLight
1919
{
@@ -248,8 +248,3 @@ class CEscalatorSAInterface
248248
CEntitySAInterface* entity;
249249
CObjectSAInterface* objects[42];
250250
};
251-
252-
static void StaticPrepareTexturesForLightEffect(RwTexture*& coronaTex, RwTexture*& shadowTex, const char* coronaName, const char* shadowName, bool removeIfExist)
253-
{
254-
C2DEffectSA::PrepareTexturesForLightEffect(coronaTex, shadowTex, coronaName, shadowName, removeIfExist);
255-
}

0 commit comments

Comments
 (0)