Skip to content

Commit 2f53410

Browse files
committed
-
1 parent b94a61f commit 2f53410

6 files changed

Lines changed: 114 additions & 151 deletions

File tree

src/CarnageGame.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ bool CarnageGame::Initialize()
3030

3131
gGameMap.LoadFromFile(gSystem.mStartupParams.mDebugMapName.c_str());
3232
gSpriteManager.Cleanup();
33-
gRenderManager.mMapRenderer.InvalidateMapMesh();
33+
gRenderManager.mMapRenderer.BuildMapMesh();
3434
if (!gSpriteManager.InitLevelSprites())
3535
{
3636
debug_assert(false);

src/GameCheatsWindow.cpp

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ GameCheatsWindow gGameCheatsWindow;
1010

1111
GameCheatsWindow::GameCheatsWindow()
1212
: DebugWindow("Game Cheats")
13-
, mGenerateFullMeshForMap()
1413
, mEnableMapCollisions(true)
1514
, mEnableGravity(true)
1615
, mEnableBlocksAnimation(true)
@@ -34,6 +33,7 @@ void GameCheatsWindow::DoUI(Timespan deltaTime)
3433
}
3534

3635
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Frame Time: %.3f ms (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
36+
ImGui::Text("Block chunks drawn: %d", gRenderManager.mMapRenderer.mRenderStats.mBlockChunksDrawnCount);
3737

3838
// pedestrian stats
3939
if (Pedestrian* pedestrian = gCarnageGame.mPlayerPedestrian)
@@ -112,18 +112,6 @@ void GameCheatsWindow::DoUI(Timespan deltaTime)
112112

113113
if (ImGui::CollapsingHeader("Map Draw"))
114114
{
115-
for (int ilayer = 0; ilayer < MAP_LAYERS_COUNT; ++ilayer)
116-
{
117-
cxx::string_buffer_16 cbtext;
118-
cbtext.printf("layer %d", ilayer);
119-
ImGui::Checkbox(cbtext.c_str(), &mDrawMapLayers[ilayer]);
120-
}
121-
ImGui::Separator();
122-
if (ImGui::Checkbox("Generate full mesh for map", &mGenerateFullMeshForMap))
123-
{
124-
gRenderManager.mMapRenderer.InvalidateMapMesh();
125-
}
126-
ImGui::Separator();
127115
ImGui::Checkbox("Enable blocks animation", &mEnableBlocksAnimation);
128116
}
129117

src/GameCheatsWindow.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ class GameCheatsWindow: public DebugWindow
66
{
77
public:
88
bool mDrawMapLayers[MAP_LAYERS_COUNT];
9-
bool mGenerateFullMeshForMap;
109
bool mEnableMapCollisions;
1110
bool mEnableGravity;
1211
bool mEnableBlocksAnimation;

src/GameMapHelpers.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ bool GameMapHelpers::BuildMapMesh(GameMapManager& cityScape, const Rect2D& area,
77
{
88
debug_assert(layerIndex > -1 && layerIndex < MAP_LAYERS_COUNT);
99

10-
meshData.SetNull();
11-
1210
// preallocate
1311
meshData.mBlocksIndices.reserve(1 * 1024 * 1024);
1412
meshData.mBlocksVertices.reserve(1 * 1024 * 1024);
@@ -34,11 +32,9 @@ bool GameMapHelpers::BuildMapMesh(GameMapManager& cityScape, const Rect2D& area,
3432

3533
bool GameMapHelpers::BuildMapMesh(GameMapManager& cityScape, const Rect2D& area, MapMeshData& meshData)
3634
{
37-
meshData.SetNull();
38-
3935
// preallocate
40-
meshData.mBlocksIndices.reserve(1 * 1024 * 1024);
41-
meshData.mBlocksVertices.reserve(1 * 1024 * 1024);
36+
meshData.mBlocksIndices.reserve(4 * 1024 * 1024);
37+
meshData.mBlocksVertices.reserve(4 * 1024 * 1024);
4238

4339
// prepare
4440
for (int tilez = 0; tilez < MAP_LAYERS_COUNT; ++tilez)

src/MapRenderer.cpp

Lines changed: 75 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@
1111
#include "Pedestrian.h"
1212
#include "Vehicle.h"
1313

14+
//////////////////////////////////////////////////////////////////////////
15+
16+
void MapRenderStats::FrameStart()
17+
{
18+
mBlockChunksDrawnCount = 0;
19+
}
20+
21+
void MapRenderStats::FrameEnd()
22+
{
23+
}
24+
25+
//////////////////////////////////////////////////////////////////////////
26+
1427
bool MapRenderer::Initialize()
1528
{
1629
mCityMeshBufferV = gGraphicsDevice.CreateBuffer(eBufferContent_Vertices);
@@ -28,7 +41,6 @@ bool MapRenderer::Initialize()
2841
return false;
2942
}
3043

31-
mCityMapRectangle.SetNull();
3244
return true;
3345
}
3446

@@ -46,17 +58,11 @@ void MapRenderer::Deinit()
4658
gGraphicsDevice.DestroyBuffer(mCityMeshBufferI);
4759
mCityMeshBufferI = nullptr;
4860
}
49-
50-
for (int iLayer = 0; iLayer < MAP_LAYERS_COUNT; ++iLayer)
51-
{
52-
mCityMeshData[iLayer].SetNull();
53-
}
54-
mCityMapRectangle.SetNull();
5561
}
5662

5763
void MapRenderer::RenderFrame()
5864
{
59-
BuildMapMesh();
65+
mRenderStats.FrameStart();
6066

6167
gGraphicsDevice.BindTexture(eTextureUnit_3, gSpriteManager.mPalettesTable);
6268
gGraphicsDevice.BindTexture(eTextureUnit_2, gSpriteManager.mPaletteIndicesTable);
@@ -73,107 +79,8 @@ void MapRenderer::RenderFrame()
7379
currVehicle->DrawFrame(mSpritesBatch);
7480
}
7581
mSpritesBatch.Flush();
76-
}
77-
78-
void MapRenderer::CommitCityMeshData()
79-
{
80-
int totalIndexCount = 0;
81-
int totalVertexCount = 0;
82-
83-
for (int iLayer = 0; iLayer < MAP_LAYERS_COUNT; ++iLayer)
84-
{
85-
int numVertices = mCityMeshData[iLayer].mBlocksVertices.size();
86-
totalVertexCount += numVertices;
87-
88-
int numIndices = mCityMeshData[iLayer].mBlocksIndices.size();
89-
totalIndexCount += numIndices;
90-
}
91-
92-
if (totalIndexCount == 0 || totalVertexCount == 0)
93-
return;
94-
95-
int totalIndexDataBytes = totalIndexCount * Sizeof_DrawIndex;
96-
int totalVertexDataBytes = totalVertexCount * Sizeof_CityVertex3D;
97-
98-
// upload vertex data
99-
mCityMeshBufferV->Setup(eBufferUsage_Static, totalVertexDataBytes, nullptr);
100-
if (void* pdata = mCityMeshBufferV->Lock(BufferAccess_Write))
101-
{
102-
char* pcursor = static_cast<char*>(pdata);
103-
for (int iLayer = 0; iLayer < MAP_LAYERS_COUNT; ++iLayer)
104-
{
105-
int dataLength = mCityMeshData[iLayer].mBlocksVertices.size() * Sizeof_CityVertex3D;
106-
if (mCityMeshData[iLayer].mBlocksVertices.empty())
107-
continue;
108-
memcpy(pcursor, mCityMeshData[iLayer].mBlocksVertices.data(), dataLength);
109-
pcursor += dataLength;
110-
}
111-
mCityMeshBufferV->Unlock();
112-
}
113-
114-
// upload index data
115-
mCityMeshBufferI->Setup(eBufferUsage_Static, totalIndexDataBytes, nullptr);
116-
if (void* pdata = mCityMeshBufferI->Lock(BufferAccess_Write))
117-
{
118-
char* pcursor = static_cast<char*>(pdata);
119-
for (int iLayer = 0; iLayer < MAP_LAYERS_COUNT; ++iLayer)
120-
{
121-
int dataLength = mCityMeshData[iLayer].mBlocksIndices.size() * Sizeof_DrawIndex;
122-
if (mCityMeshData[iLayer].mBlocksIndices.empty())
123-
continue;
124-
memcpy(pcursor, mCityMeshData[iLayer].mBlocksIndices.data(), dataLength);
125-
pcursor += dataLength;
126-
}
127-
mCityMeshBufferI->Unlock();
128-
}
129-
}
130-
131-
void MapRenderer::BuildMapMesh()
132-
{
133-
if (gGameCheatsWindow.mGenerateFullMeshForMap && mCityMapRectangle.h == 0 && mCityMapRectangle.w == 0)
134-
{
135-
mCityMapRectangle.x = 0;
136-
mCityMapRectangle.y = 0;
137-
mCityMapRectangle.w = MAP_DIMENSIONS;
138-
mCityMapRectangle.h = MAP_DIMENSIONS;
139-
140-
gConsole.LogMessage(eLogMessage_Debug, "City mesh invalidated [full]");
141-
for (int i = 0; i < MAP_LAYERS_COUNT; ++i)
142-
{
143-
GameMapHelpers::BuildMapMesh(gGameMap, mCityMapRectangle, i, gRenderManager.mMapRenderer.mCityMeshData[i]);
144-
}
145-
gRenderManager.mMapRenderer.CommitCityMeshData();
146-
return;
147-
}
148-
149-
int viewBlocks = 14;
150-
151-
int tilex = static_cast<int>(gCamera.mPosition.x / MAP_BLOCK_LENGTH);
152-
int tiley = static_cast<int>(gCamera.mPosition.z / MAP_BLOCK_LENGTH);
153-
154-
Rect2D rcMapView { -viewBlocks / 2 + tilex, -viewBlocks / 2 + tiley, viewBlocks, viewBlocks };
155-
156-
bool invalidateCache = mCityMapRectangle.w == 0 || mCityMapRectangle.h == 0 ||
157-
rcMapView.x < mCityMapRectangle.x || rcMapView.y < mCityMapRectangle.y ||
158-
rcMapView.x + rcMapView.w > mCityMapRectangle.x + mCityMapRectangle.w ||
159-
rcMapView.y + rcMapView.h > mCityMapRectangle.y + mCityMapRectangle.h;
160-
161-
if (!invalidateCache)
162-
return;
163-
164-
gConsole.LogMessage(eLogMessage_Debug, "City mesh invalidated [partial]");
165-
166-
int cacheNumBlocks = 32;
167-
mCityMapRectangle.x = (-cacheNumBlocks / 2) + tilex;
168-
mCityMapRectangle.y = (-cacheNumBlocks / 2) + tiley;
169-
mCityMapRectangle.w = cacheNumBlocks;
170-
mCityMapRectangle.h = cacheNumBlocks;
171-
172-
for (int i = 0; i < MAP_LAYERS_COUNT; ++i)
173-
{
174-
GameMapHelpers::BuildMapMesh(gGameMap, mCityMapRectangle, i, gRenderManager.mMapRenderer.mCityMeshData[i]);
175-
}
176-
gRenderManager.mMapRenderer.CommitCityMeshData();
82+
83+
mRenderStats.FrameEnd();
17784
}
17885

17986
void MapRenderer::DrawCityMesh()
@@ -192,26 +99,70 @@ void MapRenderer::DrawCityMesh()
19299
gGraphicsDevice.BindTexture(eTextureUnit_0, gSpriteManager.mBlocksTextureArray);
193100
gGraphicsDevice.BindTexture(eTextureUnit_1, gSpriteManager.mBlocksIndicesTable);
194101

195-
int currBaseVertex = 0;
196-
int currIndexOffset = 0;
197-
198-
for (int i = 0; i < MAP_LAYERS_COUNT; ++i)
102+
for (const MapBlocksChunk& currChunk: mMapBlocksChunks)
199103
{
200-
int numIndices = mCityMeshData[i].mBlocksIndices.size();
201-
int numVertices = mCityMeshData[i].mBlocksVertices.size();
202-
if (gGameCheatsWindow.mDrawMapLayers[i])
203-
{
204-
int currIndexOffsetBytes = currIndexOffset * Sizeof_DrawIndex;
205-
gGraphicsDevice.RenderIndexedPrimitives(ePrimitiveType_Triangles, eIndicesType_i32, currIndexOffsetBytes, numIndices, currBaseVertex);
206-
}
207-
currIndexOffset += numIndices;
208-
currBaseVertex += numVertices;
104+
if (!gCamera.mFrustum.contains(currChunk.mBounds))
105+
continue;
106+
107+
gGraphicsDevice.RenderIndexedPrimitives(ePrimitiveType_Triangles, eIndicesType_i32,
108+
currChunk.mIndicesStart * Sizeof_DrawIndex, currChunk.mIndicesCount);
109+
110+
++mRenderStats.mBlockChunksDrawnCount;
209111
}
210112
}
211113
gRenderManager.mCityMeshProgram.Deactivate();
212114
}
213115

214-
void MapRenderer::InvalidateMapMesh()
116+
void MapRenderer::BuildMapMesh()
215117
{
216-
mCityMapRectangle.SetNull();
118+
MapMeshData blocksMesh;
119+
for (int batchy = 0; batchy < BlocksBatchesPerSide; ++batchy)
120+
{
121+
for (int batchx = 0; batchx < BlocksBatchesPerSide; ++batchx)
122+
{
123+
Rect2D mapArea {
124+
batchx * BlocksBatchDims - ExtraBlocksPerSide,
125+
batchy * BlocksBatchDims - ExtraBlocksPerSide,
126+
BlocksBatchDims,
127+
BlocksBatchDims };
128+
129+
unsigned int prevVerticesCount = blocksMesh.mBlocksVertices.size();
130+
unsigned int prevIndicesCount = blocksMesh.mBlocksIndices.size();
131+
132+
MapBlocksChunk& currChunk = mMapBlocksChunks[batchy * BlocksBatchesPerSide + batchx];
133+
currChunk.mBounds.mMin = glm::vec3 { mapArea.x * MAP_BLOCK_LENGTH, 0, mapArea.y * MAP_BLOCK_LENGTH };
134+
currChunk.mBounds.mMax = glm::vec3 {
135+
(mapArea.x + mapArea.w) * MAP_BLOCK_LENGTH, MAP_LAYERS_COUNT * MAP_BLOCK_LENGTH,
136+
(mapArea.y + mapArea.h) * MAP_BLOCK_LENGTH };
137+
138+
currChunk.mVerticesStart = prevVerticesCount;
139+
currChunk.mIndicesStart = prevIndicesCount;
140+
141+
// append new geometry
142+
GameMapHelpers::BuildMapMesh(gGameMap, mapArea, blocksMesh);
143+
144+
currChunk.mVerticesCount = blocksMesh.mBlocksVertices.size() - prevVerticesCount;
145+
currChunk.mIndicesCount = blocksMesh.mBlocksIndices.size() - prevIndicesCount;
146+
}
147+
}
148+
149+
// upload map geometry to video memory
150+
int totalVertexDataBytes = blocksMesh.mBlocksVertices.size() * Sizeof_CityVertex3D;
151+
int totalIndexDataBytes = blocksMesh.mBlocksIndices.size() * Sizeof_DrawIndex;
152+
153+
// upload vertex data
154+
mCityMeshBufferV->Setup(eBufferUsage_Static, totalVertexDataBytes, nullptr);
155+
if (void* pdata = mCityMeshBufferV->Lock(BufferAccess_Write))
156+
{
157+
memcpy(pdata, blocksMesh.mBlocksVertices.data(), totalVertexDataBytes);
158+
mCityMeshBufferV->Unlock();
159+
}
160+
161+
// upload index data
162+
mCityMeshBufferI->Setup(eBufferUsage_Static, totalIndexDataBytes, nullptr);
163+
if (void* pdata = mCityMeshBufferI->Lock(BufferAccess_Write))
164+
{
165+
memcpy(pdata, blocksMesh.mBlocksIndices.data(), totalIndexDataBytes);
166+
mCityMeshBufferI->Unlock();
167+
}
217168
}

src/MapRenderer.h

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,54 @@
11
#pragma once
22

33
#include "SpriteBatch.h"
4+
#include "GameDefs.h"
5+
6+
// map renderer statistics info
7+
struct MapRenderStats
8+
{
9+
public:
10+
MapRenderStats() = default;
11+
void FrameStart();
12+
void FrameEnd();
13+
14+
public:
15+
int mBlockChunksDrawnCount = 0; // per frame
16+
};
417

518
// renders map mesh, peds, cars and map objects
619
class MapRenderer final: public cxx::noncopyable
720
{
21+
public:
22+
MapRenderStats mRenderStats;
23+
824
public:
925
bool Initialize();
1026
void Deinit();
1127
void RenderFrame();
12-
void InvalidateMapMesh();
28+
void BuildMapMesh();
1329

1430
private:
15-
void BuildMapMesh();
16-
void CommitCityMeshData();
1731
void DrawCityMesh();
1832

1933
private:
20-
Rect2D mCityMapRectangle; // cached map area in tiles
21-
SpriteBatch mSpritesBatch;
22-
MapMeshData mCityMeshData[MAP_LAYERS_COUNT];
34+
enum
35+
{
36+
BlocksBatchDims = 22, // 22 x 22 x 6 blocks per batch
37+
ExtraBlocksPerSide = 4,
38+
BlocksBatchesPerSide = ((MAP_DIMENSIONS + (ExtraBlocksPerSide * 2)) + BlocksBatchDims - 1) / BlocksBatchDims,
39+
BlocksBatchCount = BlocksBatchesPerSide * BlocksBatchesPerSide,
40+
};
41+
struct MapBlocksChunk
42+
{
43+
cxx::aabbox_t mBounds; // for culling
44+
// index/vertex data offset in vbo
45+
unsigned int mIndicesStart = 0, mIndicesCount = 0;
46+
unsigned int mVerticesStart = 0, mVerticesCount = 0;
47+
};
48+
MapBlocksChunk mMapBlocksChunks[BlocksBatchCount];
49+
2350
GpuBuffer* mCityMeshBufferV;
2451
GpuBuffer* mCityMeshBufferI;
52+
53+
SpriteBatch mSpritesBatch;
2554
};

0 commit comments

Comments
 (0)