Skip to content

Add wireframe toggle, InstancedMesh class, chunk managment, procedural generation, greedy mesher, and culling (face, back-face, frustum).#5

Open
OwlWorksInnovations wants to merge 5 commits into
masterfrom
dev
Open

Add wireframe toggle, InstancedMesh class, chunk managment, procedural generation, greedy mesher, and culling (face, back-face, frustum).#5
OwlWorksInnovations wants to merge 5 commits into
masterfrom
dev

Conversation

@OwlWorksInnovations
Copy link
Copy Markdown
Owner

No description provided.

…ork on the project the last 2 days was because I got a big flu on Sunday but I feel better now.
@OwlWorksInnovations OwlWorksInnovations self-assigned this Mar 26, 2026
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Add procedural terrain generation with chunk system, greedy meshing, and frustum culling

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Implement procedural terrain generation with chunk-based world system
• Add greedy meshing algorithm for optimized mesh generation
• Implement frustum culling for rendering performance optimization
• Add wireframe toggle mode and back-face culling for rendering
• Create InstancedMesh class for efficient instanced rendering
Diagram
flowchart LR
  A["Engine"] -->|manages| B["ChunkManager"]
  B -->|contains| C["Chunks"]
  C -->|generates| D["Mesh via Greedy Meshing"]
  B -->|applies| E["Frustum Culling"]
  E -->|filters| F["Visible Chunks"]
  F -->|renders| G["InstancedMesh"]
  A -->|toggles| H["Wireframe Mode"]
  A -->|enables| I["Back-face Culling"]
Loading

Grey Divider

File Changes

1. src/Core/Engine.cpp ✨ Enhancement +30/-47

Integrate chunk manager and rendering pipeline

src/Core/Engine.cpp


2. src/Render/InstancedMesh.hpp ✨ Enhancement +28/-0

New instanced mesh rendering class header

src/Render/InstancedMesh.hpp


3. src/Render/InstancedMesh.cpp ✨ Enhancement +73/-0

Instanced mesh implementation with GPU rendering

src/Render/InstancedMesh.cpp


View more (6)
4. src/World/Chunk.hpp ✨ Enhancement +25/-0

Chunk data structure and mesh generation

src/World/Chunk.hpp


5. src/World/Chunk.cpp ✨ Enhancement +166/-0

Greedy meshing and procedural block generation

src/World/Chunk.cpp


6. src/World/ChunkManager.hpp ✨ Enhancement +29/-0

Chunk management and frustum culling system

src/World/ChunkManager.hpp


7. src/World/ChunkManager.cpp ✨ Enhancement +75/-0

Frustum culling implementation for chunks

src/World/ChunkManager.cpp


8. CMakeLists.txt ⚙️ Configuration changes +3/-0

Add new source files to build system

CMakeLists.txt


9. src/shaders/shader.vs ✨ Enhancement +1/-2

Remove model matrix from vertex shader

src/shaders/shader.vs


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Mar 26, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. Wireframe toggle GL calls inverted 🐞 Bug ✓ Correctness
Description
When wireframeMode is true, the code calls glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
(wireframe) and then sets wireframeMode = false; when it is false, it calls GL_FILL (solid)
and sets wireframeMode = true. The GL calls are swapped relative to the flag, so the first
keypress applies GL_FILL (no visible change from default) and the second press activates wireframe
— the toggle is delayed by one press and the feature is non-functional on first use.
Code

src/Core/Engine.cpp[R82-88]

+      if (wireframeMode) {
+        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+        wireframeMode = false;
+      } else if (!wireframeMode) {
+        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+        wireframeMode = true;
+      }
Evidence
wireframeMode is initialized to false (line 51). On first keypress: wireframeMode==false → else-if
branch executes → glPolygonMode(GL_FILL) is called (no visible change, already the default) →
wireframeMode becomes true. On second keypress: wireframeMode==true → if branch executes →
glPolygonMode(GL_LINE) activates wireframe → wireframeMode becomes false. The GL_LINE and GL_FILL
calls are in the wrong branches.

src/Core/Engine.cpp[51-51]
src/Core/Engine.cpp[82-88]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The wireframe toggle in Engine.cpp has its OpenGL polygon mode calls swapped relative to the `wireframeMode` flag. When `wireframeMode` is `true` (wireframe is active), the code calls `GL_LINE` again instead of `GL_FILL` to turn it off, and vice versa.

## Issue Context
`wireframeMode` starts as `false` (solid fill is the default). The intent is: if currently in wireframe mode, switch to fill; if currently in fill mode, switch to wireframe.

## Fix Focus Areas
- src/Core/Engine.cpp[82-88]: Swap the `glPolygonMode` calls so that the `if (wireframeMode)` branch calls `GL_FILL` and the `else` branch calls `GL_LINE`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. DrawInstanced ignores stored instanceCount 🐞 Bug ⛯ Reliability
Description
InstancedMesh::DrawInstanced(int count) passes the caller-supplied count directly to
glDrawElementsInstanced, completely ignoring the instanceCount member that was stored during
SetData(). If a caller passes a count larger than the number of instance positions uploaded to the
GPU, the GPU will read out-of-bounds from the instance VBO, causing undefined behavior or a GPU
crash.
Code

src/Render/InstancedMesh.cpp[R57-60]

+void InstancedMesh::DrawInstanced(int count) {
+  glBindVertexArray(VAO);
+  glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0, count);
+  glBindVertexArray(0);
Evidence
InstancedMesh.cpp line 53 stores `instanceCount = static_cast<unsigned
int>(instancePositions.size()) during SetData(). Line 59 calls glDrawElementsInstanced(...,
count)` using the parameter, not the stored member. The public API declaration in InstancedMesh.hpp
line 16 names the parameter instanceCount, shadowing the private member of the same name, making
it easy to accidentally pass the wrong value. The stored instanceCount is never used after being
set.

src/Render/InstancedMesh.cpp[53-53]
src/Render/InstancedMesh.cpp[57-60]
src/Render/InstancedMesh.hpp[16-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`DrawInstanced(int count)` ignores the `instanceCount` member set during `SetData()` and uses the caller-supplied `count` instead. This allows callers to accidentally pass an incorrect count, causing out-of-bounds GPU memory reads.

## Issue Context
The `instanceCount` member is correctly set in `SetData()` (InstancedMesh.cpp line 53) but is never used in `DrawInstanced`. The parameter name `instanceCount` in the public API (InstancedMesh.hpp line 16) shadows the private member.

## Fix Focus Areas
- src/Render/InstancedMesh.cpp[57-60]: Remove the `count` parameter and use `this->instanceCount` in the `glDrawElementsInstanced` call.
- src/Render/InstancedMesh.hpp[16-16]: Update the declaration to `void DrawInstanced()` (no parameter).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Full mesh rebuild on every block change 🐞 Bug ➹ Performance
Description
Chunk::SetBlock calls UpdateMesh() on every single block modification, which rebuilds the entire
greedy mesh for all 16×16×16 blocks and re-uploads all vertex/index data to the GPU with
GL_STATIC_DRAW buffers. This is both semantically incorrect (GL_STATIC_DRAW signals data will not
change) and a severe performance issue for any interactive block editing.
Code

src/World/Chunk.cpp[R38-42]

+void Chunk::SetBlock(int x, int y, int z, uint8_t id) {
+    if (x >= 0 && x < CHUNK_SIZE && y >= 0 && y < CHUNK_SIZE && z >= 0 && z < CHUNK_SIZE) {
+        blocks[x][y][z] = id;
+        UpdateMesh();
+    }
Evidence
Chunk.cpp line 41: SetBlock calls UpdateMesh() unconditionally after every block write.
UpdateMesh() (line 52-165) iterates all three dimensions of the 16³ block array to rebuild the
greedy mesh, then calls mesh.SetData() (line 165). Mesh::SetData calls `glBufferData(...,
GL_STATIC_DRAW)` (Mesh.cpp lines 18-23), which reallocates the GPU buffer on every call.
GL_STATIC_DRAW is a hint that the data will be set once and not changed, contradicting the repeated
reallocation pattern.

src/World/Chunk.cpp[38-42]
src/World/Chunk.cpp[165-165]
src/Render/Mesh.cpp[18-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Chunk::SetBlock` triggers a full greedy mesh rebuild and GPU buffer re-upload on every block modification. The GPU buffers are also allocated with `GL_STATIC_DRAW`, which is semantically incorrect for data that is repeatedly updated.

## Issue Context
- `SetBlock` (Chunk.cpp line 41) calls `UpdateMesh()` immediately.
- `UpdateMesh()` rebuilds the entire mesh for all 16³ blocks.
- `Mesh::SetData` calls `glBufferData(..., GL_STATIC_DRAW)` (Mesh.cpp lines 18-23).

## Fix Focus Areas
- src/World/Chunk.cpp[38-42]: Add a `dirty` flag to `Chunk`; set it in `SetBlock` instead of calling `UpdateMesh()` directly. Call `UpdateMesh()` lazily before rendering if `dirty == true`.
- src/World/Chunk.hpp[19-24]: Add `bool dirty = false;` member.
- src/Render/Mesh.cpp[18-23]: Change `GL_STATIC_DRAW` to `GL_DYNAMIC_DRAW` to correctly signal that buffer contents will be updated.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment thread src/Core/Engine.cpp
Comment on lines +82 to +88
if (wireframeMode) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
wireframeMode = false;
} else if (!wireframeMode) {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
wireframeMode = true;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Wireframe toggle gl calls inverted 🐞 Bug ✓ Correctness

When wireframeMode is true, the code calls glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
(wireframe) and then sets wireframeMode = false; when it is false, it calls GL_FILL (solid)
and sets wireframeMode = true. The GL calls are swapped relative to the flag, so the first
keypress applies GL_FILL (no visible change from default) and the second press activates wireframe
— the toggle is delayed by one press and the feature is non-functional on first use.
Agent Prompt
## Issue description
The wireframe toggle in Engine.cpp has its OpenGL polygon mode calls swapped relative to the `wireframeMode` flag. When `wireframeMode` is `true` (wireframe is active), the code calls `GL_LINE` again instead of `GL_FILL` to turn it off, and vice versa.

## Issue Context
`wireframeMode` starts as `false` (solid fill is the default). The intent is: if currently in wireframe mode, switch to fill; if currently in fill mode, switch to wireframe.

## Fix Focus Areas
- src/Core/Engine.cpp[82-88]: Swap the `glPolygonMode` calls so that the `if (wireframeMode)` branch calls `GL_FILL` and the `else` branch calls `GL_LINE`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +57 to +60
void InstancedMesh::DrawInstanced(int count) {
glBindVertexArray(VAO);
glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0, count);
glBindVertexArray(0);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Drawinstanced ignores stored instancecount 🐞 Bug ⛯ Reliability

InstancedMesh::DrawInstanced(int count) passes the caller-supplied count directly to
glDrawElementsInstanced, completely ignoring the instanceCount member that was stored during
SetData(). If a caller passes a count larger than the number of instance positions uploaded to the
GPU, the GPU will read out-of-bounds from the instance VBO, causing undefined behavior or a GPU
crash.
Agent Prompt
## Issue description
`DrawInstanced(int count)` ignores the `instanceCount` member set during `SetData()` and uses the caller-supplied `count` instead. This allows callers to accidentally pass an incorrect count, causing out-of-bounds GPU memory reads.

## Issue Context
The `instanceCount` member is correctly set in `SetData()` (InstancedMesh.cpp line 53) but is never used in `DrawInstanced`. The parameter name `instanceCount` in the public API (InstancedMesh.hpp line 16) shadows the private member.

## Fix Focus Areas
- src/Render/InstancedMesh.cpp[57-60]: Remove the `count` parameter and use `this->instanceCount` in the `glDrawElementsInstanced` call.
- src/Render/InstancedMesh.hpp[16-16]: Update the declaration to `void DrawInstanced()` (no parameter).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant