Skip to content

Commit

Permalink
Add support for software mode.
Browse files Browse the repository at this point in the history
  • Loading branch information
hzqst committed Feb 9, 2025
1 parent 4cb135e commit a73b0d1
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 104 deletions.
203 changes: 165 additions & 38 deletions Plugins/BulletPhysics/BasePhysicManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@

#include <KeyValues.h>

template<class T>
inline T* GetWorldSurfaceByIndex(int index)
{
return (((T*)r_worldmodel->surfaces) + index);
}

template<class T>
inline int GetWorldSurfaceIndex(T* surf)
{
auto surf25 = (T*)surf;
auto surfbase = (T*)r_worldmodel->surfaces;

return surf25 - surfbase;
}

IClientPhysicManager* g_pClientPhysicManager{};

IClientPhysicManager* ClientPhysicManager()
Expand Down Expand Up @@ -4158,34 +4173,84 @@ void CBasePhysicManager::UpdateAllPhysicObjects(TEMPENTITY** ppTempEntFree, TEMP

}

std::shared_ptr<CPhysicVertexArray> CBasePhysicManager::GenerateWorldVertexArray(model_t *mod)
template<class T, class T2>
void CBasePhysicManager::BuildSurfaceDisplayList(model_t* mod, T *fa, std::deque<glpoly_t*>& glpolys)
{
std::string worldModelName;
#define BLOCK_WIDTH 128
#define BLOCK_HEIGHT 128
int i, lindex, lnumverts;
medge_t* pedges, * r_pedge;
float* vec;
float s, t;
glpoly_t* poly;

if (mod->name[0] == '*')
pedges = mod->edges;
lnumverts = fa->numedges;

int allocSize = (int)sizeof(glpoly_t) + ((lnumverts - 4) * VERTEXSIZE * sizeof(float));

if (allocSize < 0)
return;

poly = (glpoly_t*)malloc(allocSize);

glpolys.push_front(poly);

poly->next = NULL;
poly->flags = fa->flags;
//fa->polys = poly;
poly->numverts = lnumverts;
poly->chain = NULL;

for (i = 0; i < lnumverts; i++)
{
auto worldmodel = EngineFindWorldModelBySubModel(mod);
lindex = mod->surfedges[fa->firstedge + i];

if (!worldmodel)
if (lindex > 0)
{
gEngfuncs.Con_Printf("CBasePhysicManager::GenerateWorldVertexArray: Failed to find worldmodel for submodel \"%s\"!\n", mod->name);
return nullptr;
r_pedge = &pedges[lindex];
vec = mod->vertexes[r_pedge->v[0]].position;
}
else
{
r_pedge = &pedges[-lindex];
vec = mod->vertexes[r_pedge->v[1]].position;
}

worldModelName = worldmodel->name;
}
else
{
worldModelName = mod->name;
}
s = DotProduct(vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
s /= fa->texinfo->texture->width;

auto found = m_worldVertexResources.find(worldModelName);
t = DotProduct(vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
t /= fa->texinfo->texture->height;

if (found != m_worldVertexResources.end())
{
return found->second;
poly->verts[i][0] = vec[0];
poly->verts[i][1] = vec[1];
poly->verts[i][2] = vec[2];
poly->verts[i][3] = s;
poly->verts[i][4] = t;
#if 0
s = DotProduct(vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
s -= fa->texturemins[0];
s += fa->light_s * 16;
s += 8;
s /= BLOCK_WIDTH * 16;

t = DotProduct(vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
t -= fa->texturemins[1];
t += fa->light_t * 16;
t += 8;
t /= BLOCK_HEIGHT * 16;
#endif
poly->verts[i][5] = 0;
poly->verts[i][6] = 0;
}

poly->numverts = lnumverts;
}

template<class T, class T2>
std::shared_ptr<CPhysicVertexArray> CBasePhysicManager::GenerateWorldVertexArrayInternal(model_t* mod)
{
auto worldVertexArray = std::make_shared<CPhysicVertexArray>();

CPhysicBrushVertex Vertexes[3];
Expand All @@ -4197,20 +4262,25 @@ std::shared_ptr<CPhysicVertexArray> CBasePhysicManager::GenerateWorldVertexArray

for (int i = 0; i < mod->numsurfaces; i++)
{
auto surf = GetWorldSurfaceByIndex(i);
auto surf = GetWorldSurfaceByIndex<T>(i);

if ((surf->flags & (SURF_DRAWTURB | SURF_UNDERWATER | SURF_DRAWSKY)))
continue;

auto poly = surf->polys;
std::deque<glpoly_t*> glpolys;

BuildSurfaceDisplayList<T, T2>(mod, surf, glpolys);

if (glpolys.empty())
continue;

auto brushface = &worldVertexArray->vFaceBuffer[i];

int iStartVert = iNumVerts;

brushface->start_vertex = iStartVert;

for (poly = surf->polys; poly; poly = poly->next)
for (const auto& poly : glpolys)
{
auto v = poly->verts[0];

Expand Down Expand Up @@ -4247,24 +4317,67 @@ std::shared_ptr<CPhysicVertexArray> CBasePhysicManager::GenerateWorldVertexArray
}
}

for (auto& poly : glpolys)
{
free(poly);
}

brushface->num_vertexes = iNumVerts - iStartVert;
}

//Always shrink to save system memory
worldVertexArray->vVertexBuffer.shrink_to_fit();

m_worldVertexResources[worldModelName] = worldVertexArray;

return worldVertexArray;
}

/*void CBasePhysicManager::FreeWorldVertexArray()
std::shared_ptr<CPhysicVertexArray> CBasePhysicManager::GenerateWorldVertexArray(model_t *mod)
{
if (m_worldVertexArray) {
delete m_worldVertexArray;
m_worldVertexArray = NULL;
std::string worldModelName;

if (mod->name[0] == '*')
{
auto worldmodel = EngineFindWorldModelBySubModel(mod);

if (!worldmodel)
{
gEngfuncs.Con_Printf("CBasePhysicManager::GenerateWorldVertexArray: Failed to find worldmodel for submodel \"%s\"!\n", mod->name);
return nullptr;
}

worldModelName = worldmodel->name;
}
else
{
worldModelName = mod->name;
}

auto found = m_worldVertexResources.find(worldModelName);

if (found != m_worldVertexResources.end())
{
return found->second;
}

std::shared_ptr<CPhysicVertexArray> worldVertexArray;

if (g_dwVideoMode == VIDEOMODE_SOFTWARE)
{
worldVertexArray = GenerateWorldVertexArrayInternal<msurface_sw_t, mnode_sw_t>(mod);
}
else if (g_iEngineType == ENGINE_GOLDSRC_HL25)
{
worldVertexArray = GenerateWorldVertexArrayInternal<msurface_hl25_t, mnode_t>(mod);
}
else
{
worldVertexArray = GenerateWorldVertexArrayInternal<msurface_t, mnode_t>(mod);
}
}*/

m_worldVertexResources[worldModelName] = worldVertexArray;

return worldVertexArray;
}

/*
Purpose : Generate IndexArray for world and all brush models
Expand All @@ -4276,7 +4389,18 @@ std::shared_ptr<CPhysicIndexArray> CBasePhysicManager::GenerateBrushIndexArray(m
pIndexArray->flags |= PhysicIndexArrayFlag_FromBSP;
pIndexArray->pVertexArray = pWorldVertexArray;

GenerateIndexArrayForBrushModel(mod, pIndexArray.get());
if (g_dwVideoMode == VIDEOMODE_SOFTWARE)
{
GenerateIndexArrayForBrushModel<msurface_sw_t, mnode_sw_t>(mod, pIndexArray.get());
}
else if (g_iEngineType == ENGINE_GOLDSRC_HL25)
{
GenerateIndexArrayForBrushModel<msurface_hl25_t, mnode_t>(mod, pIndexArray.get());
}
else
{
GenerateIndexArrayForBrushModel<msurface_t, mnode_t>(mod, pIndexArray.get());
}

auto name = UTIL_GetAbsoluteModelName(mod);

Expand All @@ -4302,27 +4426,29 @@ void CBasePhysicManager::FreeAllIndexArrays(int withflags, int withoutflags)
}
}

template<class T, class T2>
void CBasePhysicManager::GenerateIndexArrayForBrushModel(model_t* mod, CPhysicIndexArray* pIndexArray)
{
if (mod == r_worldmodel)
{
GenerateIndexArrayRecursiveWorldNode(mod, mod->nodes, pIndexArray);
GenerateIndexArrayRecursiveWorldNode<T, T2>(mod, (T2 *)mod->nodes, pIndexArray);
}
else
{
for (int i = 0; i < mod->nummodelsurfaces; i++)
{
auto surf = GetWorldSurfaceByIndex(mod->firstmodelsurface + i);
auto surf = GetWorldSurfaceByIndex<T>(mod->firstmodelsurface + i);

GenerateIndexArrayForSurface(mod, surf, pIndexArray);
GenerateIndexArrayForSurface<T>(mod, surf, pIndexArray);
}
}

//Always shrink to save system memory
pIndexArray->vIndexBuffer.shrink_to_fit();
}

void CBasePhysicManager::GenerateIndexArrayForSurface(model_t* mod, msurface_t* surf, CPhysicIndexArray* pIndexArray)
template<class T>
void CBasePhysicManager::GenerateIndexArrayForSurface(model_t* mod, T* surf, CPhysicIndexArray* pIndexArray)
{
if (surf->flags & SURF_DRAWTURB)
{
Expand All @@ -4339,29 +4465,30 @@ void CBasePhysicManager::GenerateIndexArrayForSurface(model_t* mod, msurface_t*
return;
}

auto surfIndex = GetWorldSurfaceIndex(surf);
auto surfIndex = GetWorldSurfaceIndex<T>(surf);

GenerateIndexArrayForBrushface(&pIndexArray->pVertexArray->vFaceBuffer[surfIndex], pIndexArray);
}

void CBasePhysicManager::GenerateIndexArrayRecursiveWorldNode(model_t* mod, mnode_t* node, CPhysicIndexArray* pIndexArray)
template<class T, class T2>
void CBasePhysicManager::GenerateIndexArrayRecursiveWorldNode(model_t* mod, T2* node, CPhysicIndexArray* pIndexArray)
{
if (node->contents == CONTENTS_SOLID)
return;

if (node->contents < 0)
return;

GenerateIndexArrayRecursiveWorldNode(mod, node->children[0], pIndexArray);
GenerateIndexArrayRecursiveWorldNode<T, T2>(mod, node->children[0], pIndexArray);

for (int i = 0; i < node->numsurfaces; ++i)
{
auto surf = GetWorldSurfaceByIndex(node->firstsurface + i);
auto surf = GetWorldSurfaceByIndex<T>(node->firstsurface + i);

GenerateIndexArrayForSurface(mod, surf, pIndexArray);
GenerateIndexArrayForSurface<T>(mod, surf, pIndexArray);
}

GenerateIndexArrayRecursiveWorldNode(mod, node->children[1], pIndexArray);
GenerateIndexArrayRecursiveWorldNode<T, T2>(mod, node->children[1], pIndexArray);
}

void CBasePhysicManager::GenerateIndexArrayForBrushface(CPhysicBrushFace* brushface, CPhysicIndexArray* pIndexArray)
Expand Down
18 changes: 16 additions & 2 deletions Plugins/BulletPhysics/BasePhysicManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <vector>
#include <map>
#include <unordered_map>
#include <deque>

#include "ClientPhysicManager.h"
#include "ClientPhysicConfig.h"
Expand Down Expand Up @@ -135,11 +136,24 @@ class CBasePhysicManager : public IClientPhysicManager
private:
//WorldVertexArray and WorldIndexArray Management
std::shared_ptr<CPhysicVertexArray> GenerateWorldVertexArray(model_t* mod);

template<class T, class T2>
std::shared_ptr<CPhysicVertexArray> GenerateWorldVertexArrayInternal(model_t* mod);

template<class T, class T2>
void BuildSurfaceDisplayList(model_t* mod, T *fa, std::deque<glpoly_t*>& glpolys);

std::shared_ptr<CPhysicIndexArray> GenerateBrushIndexArray(model_t* mod, const std::shared_ptr<CPhysicVertexArray> & pWorldVertexArray);

template<class T, class T2>
void GenerateIndexArrayForBrushModel(model_t* mod, CPhysicIndexArray* pIndexArray);
void GenerateIndexArrayRecursiveWorldNode(model_t* mod, mnode_t* node, CPhysicIndexArray* pIndexArray);
void GenerateIndexArrayForSurface(model_t* mod, msurface_t* psurf, CPhysicIndexArray* pIndexArray);

template<class T, class T2>
void GenerateIndexArrayRecursiveWorldNode(model_t* mod, T2* node, CPhysicIndexArray* pIndexArray);

template<class T>
void GenerateIndexArrayForSurface(model_t* mod, T* psurf, CPhysicIndexArray* pIndexArray);

void GenerateIndexArrayForBrushface(CPhysicBrushFace* brushface, CPhysicIndexArray* pIndexArray);

//Deprecated: use Resource Management now
Expand Down
1 change: 0 additions & 1 deletion Plugins/BulletPhysics/BulletPhysicManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1437,7 +1437,6 @@ CBulletPhysicsDebugDraw : public btIDebugDraw
void drawLine(const btVector3& from1, const btVector3& to1, const btVector3& color1) override
{
//The texture must be reset to zero upon drawing.
vgui::surface()->DrawSetTexture(-1);
vgui::surface()->DrawSetTexture(0);

if (IsDebugDrawWallHackEnabled())
Expand Down
Loading

0 comments on commit a73b0d1

Please sign in to comment.