diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index d1adc82b..08cf711b 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1939,6 +1939,8 @@ Floating point starting to play nice with engine Fix geom-body collision sending wrong vector to body Per-mesh draw calls in batched static draw calls Main content pipeline tracking +Error checking on mesh rendering (making sure not trying to draw 0-element meshes) +Fix generating rendering geometry for blocks/terrain with 0 elements diff --git a/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java b/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java index 7ac0d0c5..46727e08 100644 --- a/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java +++ b/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java @@ -343,6 +343,9 @@ public class ClientTerrainManager { * @return The model path that is promised to eventually reflect the terrain model when it makes it to gpu */ public static String queueTerrainGridGeneration(TerrainChunkData data, VoxelTextureAtlas atlas, DrawCell notifyTarget, Entity toDelete){ + if(data.getFaceElements().length < 1){ + throw new Error("Invalid data!"); + } String promisedHash = ""; UUID newUUID = UUID.randomUUID(); promisedHash = newUUID.toString(); diff --git a/src/main/java/electrosphere/entity/types/terrain/BlockChunkEntity.java b/src/main/java/electrosphere/entity/types/terrain/BlockChunkEntity.java index 7dafb65d..69a26b7d 100644 --- a/src/main/java/electrosphere/entity/types/terrain/BlockChunkEntity.java +++ b/src/main/java/electrosphere/entity/types/terrain/BlockChunkEntity.java @@ -72,7 +72,7 @@ public class BlockChunkEntity { BlockMeshData data; try { data = BlockMeshgen.rasterize(chunkData, true, solidsMap); - if(Globals.clientState.clientScene.containsEntity(solidsEnt)){ + if(Globals.clientState.clientScene.containsEntity(solidsEnt) && data.getFaceElements().length > 0){ String modelPath = Globals.assetManager.queuedAsset(new QueuedModel(() -> { return BlockMeshgen.generateBlockModel(data); })); @@ -123,7 +123,7 @@ public class BlockChunkEntity { BlockMeshData data; try { data = BlockMeshgen.rasterize(chunkData, false, solidsMap); - if(Globals.clientState.clientScene.containsEntity(transparentEnt)){ + if(Globals.clientState.clientScene.containsEntity(transparentEnt) && data.getFaceElements().length > 0){ String modelPath = Globals.assetManager.queuedAsset(new QueuedModel(() -> { return BlockMeshgen.generateBlockModel(data); })); diff --git a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java index 6ef83fdc..70383231 100644 --- a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java +++ b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java @@ -70,7 +70,7 @@ public class TerrainChunk { try { data = TransvoxelModelGeneration.generateTerrainChunkData(chunkData); data.constructBuffers(); - if(Globals.clientState.clientScene.containsEntity(rVal)){ + if(Globals.clientState.clientScene.containsEntity(rVal) && data.getFaceElements().length > 0){ String modelPath = ClientTerrainManager.queueTerrainGridGeneration(data, atlas, notifyTarget, toDelete); EntityCreationUtils.makeEntityDrawablePreexistingModel(rVal, modelPath); if(levelOfDetail == BlockChunkData.LOD_FULL_RES && data.getFaceElements().length > 0){ diff --git a/src/main/java/electrosphere/renderer/meshgen/BlockMeshgen.java b/src/main/java/electrosphere/renderer/meshgen/BlockMeshgen.java index 1879c21b..5f417f64 100644 --- a/src/main/java/electrosphere/renderer/meshgen/BlockMeshgen.java +++ b/src/main/java/electrosphere/renderer/meshgen/BlockMeshgen.java @@ -564,6 +564,9 @@ public class BlockMeshgen { // Buffer data to GPU // int elementCount = meshData.faceElements.length; + if(elementCount < 1){ + throw new Error("Invalid mesh data!"); + } try { //actually buffer vertices if(vertexArrayBufferData.position() > 0){ diff --git a/src/main/java/electrosphere/renderer/meshgen/TerrainChunkModelGeneration.java b/src/main/java/electrosphere/renderer/meshgen/TerrainChunkModelGeneration.java index ad09c4ab..26a40094 100644 --- a/src/main/java/electrosphere/renderer/meshgen/TerrainChunkModelGeneration.java +++ b/src/main/java/electrosphere/renderer/meshgen/TerrainChunkModelGeneration.java @@ -795,6 +795,9 @@ public class TerrainChunkModelGeneration { // Buffer data to GPU // int elementCount = data.getFaceElements().length; + if(elementCount < 1){ + throw new Error("Invalid mesh data!"); + } try { //actually buffer vertices diff --git a/src/main/java/electrosphere/renderer/meshgen/TransvoxelModelGeneration.java b/src/main/java/electrosphere/renderer/meshgen/TransvoxelModelGeneration.java index 3a6138fd..ec097c42 100644 --- a/src/main/java/electrosphere/renderer/meshgen/TransvoxelModelGeneration.java +++ b/src/main/java/electrosphere/renderer/meshgen/TransvoxelModelGeneration.java @@ -2206,6 +2206,9 @@ public class TransvoxelModelGeneration { // Buffer data to GPU // int elementCount = data.getFaceElements().length; + if(elementCount < 1){ + throw new Error("Invalid mesh data!"); + } try { //actually buffer vertices diff --git a/src/main/java/electrosphere/renderer/model/Mesh.java b/src/main/java/electrosphere/renderer/model/Mesh.java index aaa5ae5d..6d4f9339 100644 --- a/src/main/java/electrosphere/renderer/model/Mesh.java +++ b/src/main/java/electrosphere/renderer/model/Mesh.java @@ -223,6 +223,9 @@ public class Mesh { * @param elementCount The number of faces */ public void bufferFaces(IntBuffer faces, int elementCount){ + if(elementCount < 1){ + throw new Error("Sending mesh with 0 faces!"); + } if(!EngineState.EngineFlags.HEADLESS){ elementArrayBuffer = GL45.glGenBuffers(); GL45.glBindBuffer(GL45.GL_ELEMENT_ARRAY_BUFFER, elementArrayBuffer); @@ -573,26 +576,46 @@ public class Mesh { if(renderPipelineState.getInstanced()){ - if(this.elementCount > 0 ){ - GL45.glDrawElementsInstanced(GL45.GL_TRIANGLES, this.elementCount, GL45.GL_UNSIGNED_INT, 0, renderPipelineState.getInstanceCount()); - Globals.renderingEngine.checkError(); + if(renderPipelineState.getInstanceCount() < 1){ + throw new Error("Failed to render instanced mesh with invalid instance count! " + this.getDebugData()); } + GL45.glDrawElementsInstanced(GL45.GL_TRIANGLES, this.elementCount, GL45.GL_UNSIGNED_INT, 0, renderPipelineState.getInstanceCount()); + Globals.renderingEngine.checkError(); + } else if(this.useElementArray){ + if(this.elementCount < 1){ + throw new Error("Failed to render mesh with invalid element count! " + this.getDebugData()); + } + GL45.glDrawElements(GL45.GL_TRIANGLES, this.elementCount, GL45.GL_UNSIGNED_INT, 0); + Globals.renderingEngine.checkError(); } else { - if(this.useElementArray){ - if(this.elementCount > 0){ - GL45.glDrawElements(GL45.GL_TRIANGLES, this.elementCount, GL45.GL_UNSIGNED_INT, 0); - Globals.renderingEngine.checkError(); - } - } else { - if(this.elementCount > 0){ - GL45.glDrawArrays(GL45.GL_TRIANGLES, 0, this.elementCount); - Globals.renderingEngine.checkError(); - } + if(this.elementCount < 1){ + throw new Error("Failed to render mesh with invalid element count! " + this.getDebugData()); } + GL45.glDrawArrays(GL45.GL_TRIANGLES, 0, this.elementCount); + Globals.renderingEngine.checkError(); } Globals.profiler.endCpuSample(); } + /** + * Gets debug data for the mesh + * @return The debug data in a string + */ + private String getDebugData(){ + String rVal = "\n" + + "Mesh name: " + this.meshName + "\n" + + "Vertex buffer: " + this.vertexBuffer + "\n" + + "Normal buffer: " + this.normalBuffer + "\n" + + "Texture buffer: " + this.textureCoordBuffer + "\n" + + "Bone Index buffer: " + this.boneIndexBuffer + "\n" + + "Bone Weight buffer: " + this.boneWeightBuffer + "\n" + + "Element buffer: " + this.elementArrayBuffer + "\n" + + "Element count: " + this.elementCount + "\n" + + "Use element array: " + this.useElementArray + "\n" + + ""; + return rVal; + } + /** * Updates the bounding sphere of the mesh * @param x