Skip to content

Commit

Permalink
Implement remaining shadow code (#1042)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonwil authored Jan 15, 2024
1 parent 49ca309 commit 1bc69b0
Show file tree
Hide file tree
Showing 11 changed files with 2,338 additions and 63 deletions.
19 changes: 18 additions & 1 deletion src/hooker/setupglobals_zh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ RTS3DInterfaceScene *&W3DDisplay::s_3DInterfaceScene =

// w3dshadow.cpp
#include "w3dshadow.h"
const FrustumClass *&g_shadowCameraFrustum = Make_Global<const FrustumClass *>(PICK_ADDRESS(0x00A3AE3C, 0x00E1A604));
W3DShadowManager *&g_theW3DShadowManager = Make_Global<W3DShadowManager *>(PICK_ADDRESS(0x00A3AE4C, 0x00E1A614));

// thingfactory.cpp
Expand Down Expand Up @@ -578,10 +579,12 @@ ScriptEngine *&g_theScriptEngine = Make_Global<ScriptEngine *>(PICK_ADDRESS(0x00

// w3dprojectedshadow.cpp
class W3DProjectedShadowManager;
class ProjectedShadowManager;
W3DProjectedShadowManager *&g_theW3DProjectedShadowManager =
Make_Global<W3DProjectedShadowManager *>(PICK_ADDRESS(0x00A3ACD4, 0x00E1AFC8));
ProjectedShadowManager *&g_theProjectedShadowManager =
Make_Global<ProjectedShadowManager *>(PICK_ADDRESS(0x00A3AC58, 0x00E1AF44));
class FrustumClass;
FrustumClass *&g_shadowCameraFrustum = Make_Global<FrustumClass *>(PICK_ADDRESS(0x00A3AE3C, 0x00E1A604));
#ifdef BUILD_WITH_D3D8
IDirect3DVertexBuffer8 *&g_shadowDecalVertexBufferD3D =
Make_Global<IDirect3DVertexBuffer8 *>(PICK_ADDRESS(0x00A3ACE8, 0x00E1AFDC));
Expand Down Expand Up @@ -836,3 +839,17 @@ HotKeyManager *&g_theHotKeyManager = Make_Global<HotKeyManager *>(PICK_ADDRESS(0
// disconnectmenu.cpp
class DisconnectMenu;
DisconnectMenu *&g_theDisconnectMenu = Make_Global<DisconnectMenu *>(PICK_ADDRESS(0x00A31DA0, 0x04CAD314));

// w3dbuffermanager.cpp
class W3DBufferManager;
W3DBufferManager *&g_theW3DBufferManager = Make_Global<W3DBufferManager *>(PICK_ADDRESS(0x00A3C2B8, 0x00E1B298));

// w3dvolumetricshadow.cpp
class W3DVolumetricShadowManager;
W3DVolumetricShadowManager *&g_theW3DVolumetricShadowManager =
Make_Global<W3DVolumetricShadowManager *>(PICK_ADDRESS(0x00A3B0F0, 0x00E1AE90));
#ifdef BUILD_WITH_D3D8
IDirect3DVertexBuffer8 *&g_shadowVertexBufferD3D =
Make_Global<IDirect3DVertexBuffer8 *>(PICK_ADDRESS(0x00A3B0F4, 0x00E1AE94));
IDirect3DIndexBuffer8 *&g_shadowIndexBufferD3D = Make_Global<IDirect3DIndexBuffer8 *>(PICK_ADDRESS(0x00A3B0F8, 0x00E1AE98));
#endif
38 changes: 38 additions & 0 deletions src/hooker/setuphooks_zh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@
#include "w3dpropbuffer.h"
#include "w3droadbuffer.h"
#include "w3dscene.h"
#include "w3dshadow.h"
#include "w3dshroud.h"
#include "w3dsmudge.h"
#include "w3dsnow.h"
Expand Down Expand Up @@ -2070,6 +2071,7 @@ void Setup_Hooks()
Hook_Any(0x00762F90, W3DShadowTextureManager::Create_Texture);
Hook_Any(0x00762130, W3DProjectedShadowManager::Remove_Shadow);
Hook_Any(0x00761290, W3DProjectedShadow::Release);
Hook_Any(0x0075F1D0, W3DProjectedShadowManager::Render_Projected_Terrain_Shadow);

// worldheightmap.cpp
Hook_Any(0x007440C0, WorldHeightMap::Hook_Dtor);
Expand Down Expand Up @@ -2124,6 +2126,29 @@ void Setup_Hooks()
Hook_Any(0x007A7AF0, W3DShadowGeometryManager::Free_All_Geoms);
Hook_Any(0x007A7B70, W3DShadowGeometryManager::Load_Geom);

Hook_Any(0x007A3BA0, W3DVolumetricShadow::Update_Optimal_Extrusion_Padding);
Hook_Any(0x007A4110, W3DVolumetricShadow::Render_Volume);
Hook_Any(0x007A41A0, W3DVolumetricShadow::Render_Mesh_Volume);
Hook_Any(0x007A43D0, W3DVolumetricShadow::Render_Dynamic_Mesh_Volume);
Hook_Any(0x007A4970, W3DVolumetricShadow::Update);
Hook_Any(0x007A4C10, W3DVolumetricShadow::Update_Volumes);
Hook_Any(0x007A4F10, W3DVolumetricShadow::Update_Mesh_Volume);
Hook_Any(0x007A5B20, W3DVolumetricShadow::Add_Silhouette_Edge);
Hook_Any(0x007A5C30, W3DVolumetricShadow::Add_Neighborless_Edges);
Hook_Any(0x007A5D30, W3DVolumetricShadow::Build_Silhouette);
Hook_Any(0x007A5F50, W3DVolumetricShadow::Construct_Volume);
Hook_Any(0x007A6530, W3DVolumetricShadow::Construct_Volume_VB);
Hook_Any(0x007A6B20, W3DVolumetricShadow::Allocate_Shadow_Volume);
Hook_Any(0x007A6C50, W3DVolumetricShadow::Reset_Shadow_Volume);
Hook_Any(0x007A6D00, W3DVolumetricShadow::Allocate_Silhouette);
Hook_Any(0x007A6D50, W3DVolumetricShadowManager::Render_Stencil_Shadows);
Hook_Any(0x007A6FB0, W3DVolumetricShadowManager::Render_Shadows);
Hook_Any(0x007A7760, W3DVolumetricShadowManager::Release_Resources);
Hook_Any(0x007A77D0, W3DVolumetricShadowManager::Re_Acquire_Resources);
Hook_Any(0x007A78B0, W3DVolumetricShadowManager::Reset);
Hook_Any(0x007A78D0, W3DVolumetricShadowManager::Add_Shadow);
Hook_Any(0x007A7DB0, W3DVolumetricShadow::Release);

// w3dbuffermanager.h
Hook_Any(0x007D5420, W3DBufferManager::Hook_Ctor);
Hook_Any(0x007D5470, W3DBufferManager::Hook_Dtor);
Expand Down Expand Up @@ -3742,4 +3767,17 @@ void Setup_Hooks()

// w3dingameui.h
Hook_Any(0x007A9B30, W3DInGameUI::Create_View);

// w3dshadow.h
Hook_Any(0x00781F40, Do_Shadows);
Hook_Any(0x00781FC0, W3DShadowManager::Hook_Ctor);
Hook_Any(0x00782120, W3DShadowManager::Hook_Dtor);
Hook_Any(0x00782170, W3DShadowManager::Init);
Hook_Any(0x007821B0, W3DShadowManager::Reset);
Hook_Any(0x007821D0, W3DShadowManager::Re_Acquire_Resources);
Hook_Any(0x00782210, W3DShadowManager::Release_Resources);
Hook_Any(0x00782230, W3DShadowManager::Add_Shadow);
Hook_Any(0x00782290, W3DShadowManager::Remove_Shadow);
Hook_Any(0x007822A0, W3DShadowManager::Get_Light_Pos_World);
Hook_Any(0x007822C0, W3DShadowManager::Set_Time_Of_Day);
}
4 changes: 2 additions & 2 deletions src/platform/w3dengine/client/drawable/draw/w3dmodeldraw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1921,8 +1921,8 @@ void W3DModelDraw::Set_Terrain_Decal(TerrainDecalType decal)
info.m_offsetX = tmplate->Get_Shadow_Offset_X();
info.m_offsetY = tmplate->Get_Shadow_Offset_Y();

if (g_theW3DProjectedShadowManager != nullptr) {
m_decalShadow = g_theW3DProjectedShadowManager->Add_Decal(m_renderObject, &info);
if (g_theProjectedShadowManager != nullptr) {
m_decalShadow = g_theProjectedShadowManager->Add_Decal(m_renderObject, &info);
}

if (m_decalShadow != nullptr) {
Expand Down
4 changes: 4 additions & 0 deletions src/platform/w3dengine/client/shadow/w3dbuffermanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#include "dx8vertexbuffer.h"
#include <algorithm>

#ifndef GAME_DLL
W3DBufferManager *g_theW3DBufferManager;
#endif

// TODO need general cleanup advice
// TODO what is going on with count

Expand Down
8 changes: 7 additions & 1 deletion src/platform/w3dengine/client/shadow/w3dbuffermanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* A full copy of the GNU General Public License can be found in
* LICENSE
*/

#pragma once
#include "always.h"
#include <new>

Expand Down Expand Up @@ -173,3 +173,9 @@ class W3DBufferManager
W3DIndexBuffer m_W3DEmptyIndexBuffers[MAX_INDEX_BUFFERS_CREATED];
int m_numEmptyIndexBuffersAllocated;
};

#ifdef GAME_DLL
extern W3DBufferManager *&g_theW3DBufferManager;
#else
extern W3DBufferManager *g_theW3DBufferManager;
#endif
176 changes: 170 additions & 6 deletions src/platform/w3dengine/client/shadow/w3dprojectedshadow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "texproject.h"
#include "texture.h"
#include "w3dmodeldraw.h"
#include "w3dvolumetricshadow.h"
#include "worldheightmap.h"
#include <cstring>
#ifdef BUILD_WITH_D3D8
Expand All @@ -54,7 +55,7 @@ IDirect3DVertexBuffer8 *g_shadowDecalVertexBufferD3D;
IDirect3DIndexBuffer8 *g_shadowDecalIndexBufferD3D;
#endif
W3DProjectedShadowManager *g_theW3DProjectedShadowManager = nullptr;
FrustumClass *g_shadowCameraFrustum;
ProjectedShadowManager *g_theProjectedShadowManager = nullptr;
int g_nShadowDecalVertsInBuf;
int g_nShadowDecalStartBatchVertex;
int g_nShadowDecalIndicesInBuf;
Expand Down Expand Up @@ -555,12 +556,175 @@ void W3DProjectedShadowManager::Update_Render_Target_Textures()

int W3DProjectedShadowManager::Render_Projected_Terrain_Shadow(W3DProjectedShadow *shadow, AABoxClass &box)
{
#ifdef GAME_DLL
return Call_Method<int, W3DProjectedShadowManager, W3DProjectedShadow *, AABoxClass &>(
PICK_ADDRESS(0x0075F1D0, 0x0067D4FB), this, shadow, box);
#else
return 0;
#ifdef BUILD_WITH_D3D8
struct SHADOW_VOLUME_VERTEX
{
float x;
float y;
float z;
};

static Matrix4 mWorld(true);

if (g_theTerrainRenderObject == nullptr) {
return 0;
}

WorldHeightMap *map = g_theTerrainRenderObject->Get_Map();
float cx = box.m_center.X;
float cy = box.m_center.Y;
float dx = box.m_extent.X;
float dy = box.m_extent.Y;
IDirect3DDevice8 *dev = DX8Wrapper::Get_D3D_Device8();

if (dev == nullptr) {
return 0;
}

int start_x = GameMath::Fast_To_Int_Floor((cx - dx) * 0.1f);
int end_x = GameMath::Fast_To_Int_Floor((cx + dx) * 0.1f);
int start_y = GameMath::Fast_To_Int_Floor((cy - dy) * 0.1f);
int end_y = GameMath::Fast_To_Int_Floor((cy + dy) * 0.1f);
start_x &= (start_x <= 0) - 1;

if (end_x >= map->Get_X_Extent() - 1) {
end_x = map->Get_X_Extent() - 1;
}

start_y &= (start_y <= 0) - 1;

if (end_y >= map->Get_Y_Extent() - 1) {
end_y = map->Get_Y_Extent() - 1;
}

int width = end_x - start_x + 1;
int height = end_y - start_y + 1;

if (end_x == start_x || height == 1) {
return 0;
}

int num_verts = height * width;
SHADOW_VOLUME_VERTEX *vertices;

if (g_nShadowVertsInBuf <= SHADOW_VERTEX_SIZE - num_verts) {

if (g_shadowVertexBufferD3D->Lock(
12 * g_nShadowVertsInBuf, 12 * num_verts, reinterpret_cast<BYTE **>(&vertices), D3DLOCK_NOOVERWRITE)
!= S_OK) {
return 0;
}
} else {
if (g_shadowVertexBufferD3D->Lock(0, 12 * num_verts, reinterpret_cast<BYTE **>(&vertices), D3DLOCK_DISCARD)
!= S_OK) {
return 0;
}

g_nShadowVertsInBuf = 0;
g_nShadowStartBatchVertex = 0;
}

if (vertices != nullptr) {
for (int y = start_y; y <= end_y; y++) {
float f1 = y * 10.0f;

for (int x = start_x; x <= end_x; x++) {
vertices->x = x * 10.0f;
vertices->y = f1;
vertices->z = map->Get_Height(x, y) * HEIGHTMAP_SCALE;
vertices++;
}
}
}

g_shadowVertexBufferD3D->Unlock();
int num_indices = 6 * (end_y - start_y) * (end_x - start_x);
short *indices;

if (g_nShadowIndicesInBuf <= SHADOW_INDEX_SIZE - num_indices) {
if (g_shadowIndexBufferD3D->Lock(
2 * g_nShadowIndicesInBuf, 2 * num_indices, reinterpret_cast<BYTE **>(&indices), D3DLOCK_NOOVERWRITE)
!= S_OK) {
return 0;
}
} else {
if (g_shadowIndexBufferD3D->Lock(0, 2 * num_indices, reinterpret_cast<BYTE **>(&indices), D3DLOCK_DISCARD) != S_OK) {
return 0;
}

g_nShadowIndicesInBuf = 0;
g_nShadowStartBatchIndex = 0;
}

if (indices != nullptr) {
int y = start_y;
int x = 0;

while (y < end_y) {
for (int x_index = start_x; x_index < end_x; x_index++) {
float ua[4];
float va[4];
unsigned char alpha[4];
bool flip_for_blend;
map->Get_Alpha_UV_Data(x_index, y, ua, va, alpha, &flip_for_blend, false);

if (flip_for_blend) {
indices[0] = x + 1;
indices[1] = width + x;
indices[2] = x;
indices[3] = x + 1;
indices[4] = x + width + 1;
indices[5] = width + x;
} else {
indices[0] = x;
indices[1] = x + width + 1;
indices[2] = width + x;
indices[3] = x;
indices[4] = x + 1;
indices[5] = x + width + 1;
}

indices += 6;
x++;
}

y++;
x += width;
}
}

g_shadowIndexBufferD3D->Unlock();
dev->SetIndices(g_shadowIndexBufferD3D, g_nShadowStartBatchVertex);
dev->SetTransform(D3DTS_WORLD, reinterpret_cast<D3DMATRIX *>(&mWorld));
dev->SetStreamSource(0, g_shadowVertexBufferD3D, sizeof(SHADOW_VOLUME_VERTEX));
dev->SetVertexShader(D3DFVF_XYZ);
int count = 2 * (end_y - start_y) * (end_x - start_x);
dev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
dev->SetRenderState(D3DRS_STENCILENABLE, TRUE);
dev->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
dev->SetRenderState(D3DRS_STENCILREF, 1);
dev->SetRenderState(D3DRS_STENCILMASK, -1);
dev->SetRenderState(D3DRS_STENCILWRITEMASK, -1);
dev->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
dev->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
dev->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);
dev->SetRenderState(D3DRS_LIGHTING, FALSE);
dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR);
dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);

if (DX8Wrapper::Is_Triangle_Draw_Enabled()) {
dev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, num_verts, g_nShadowStartBatchIndex, count);
}

dev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
dev->SetRenderState(D3DRS_STENCILENABLE, FALSE);
dev->SetRenderState(D3DRS_LIGHTING, TRUE);
g_nShadowVertsInBuf += num_verts;
g_nShadowStartBatchVertex = g_nShadowVertsInBuf;
g_nShadowIndicesInBuf += num_indices;
g_nShadowStartBatchIndex = g_nShadowIndicesInBuf;
#endif
return 1;
}

void W3DProjectedShadowManager::Flush_Decals(W3DShadowTexture *texture, ShadowType type)
Expand Down
6 changes: 3 additions & 3 deletions src/platform/w3dengine/client/shadow/w3dprojectedshadow.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ class ProjectedShadowManager
virtual Shadow *Add_Decal(Shadow::ShadowTypeInfo *shadow_info) = 0;
};

class W3DProjectedShadowManager : ProjectedShadowManager
class W3DProjectedShadowManager : public ProjectedShadowManager
{
public:
W3DProjectedShadowManager();
Expand Down Expand Up @@ -207,8 +207,8 @@ class W3DProjectedShadowManager : ProjectedShadowManager

#ifdef GAME_DLL
extern W3DProjectedShadowManager *&g_theW3DProjectedShadowManager;
extern FrustumClass *&g_shadowCameraFrustum;
extern ProjectedShadowManager *&g_theProjectedShadowManager;
#else
extern W3DProjectedShadowManager *g_theW3DProjectedShadowManager;
extern FrustumClass *g_shadowCameraFrustum;
extern ProjectedShadowManager *g_theProjectedShadowManager;
#endif
Loading

0 comments on commit 1bc69b0

Please sign in to comment.