diff --git a/redhorizon-classic/source/nz/net/ultraq/redhorizon/classic/maps/Map.groovy b/redhorizon-classic/source/nz/net/ultraq/redhorizon/classic/maps/Map.groovy index ae1a0f27..e07eb964 100644 --- a/redhorizon-classic/source/nz/net/ultraq/redhorizon/classic/maps/Map.groovy +++ b/redhorizon-classic/source/nz/net/ultraq/redhorizon/classic/maps/Map.groovy @@ -364,7 +364,7 @@ class Map extends Node { return scene .requestCreateOrGet(new MeshRequest(MeshType.TRIANGLES, new VertexBufferLayout(Attribute.POSITION, Attribute.COLOUR, Attribute.TEXTURE_UVS), - allVertices, Colour.WHITE, allTextureUVs, allIndices, false)) + allVertices, Colour.WHITE, allTextureUVs, allIndices)) .thenAcceptAsync { newMesh -> fullMesh = newMesh } diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/GraphicsRenderer.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/GraphicsRenderer.groovy index 682fd8db..7f681ca3 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/GraphicsRenderer.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/GraphicsRenderer.groovy @@ -58,14 +58,14 @@ interface GraphicsRenderer extends AutoCloseable, EventTarget { */ default Mesh createMesh(MeshType type, VertexBufferLayout layout, Vector2f[] vertices, Colour colour) { - return createMesh(type, layout, vertices, colour, null, null, false) + return createMesh(type, layout, vertices, colour, null, null) } /** * Create a mesh with all of the mesh parts. */ Mesh createMesh(MeshType type, VertexBufferLayout layout, Vector2f[] vertices, Colour colour, Vector2f[] textureUVs, - int[] indices, boolean dynamic) + int[] indices) /** * Create a new shader program from the given configuration, or return the diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/GraphicsRequests.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/GraphicsRequests.groovy index 3fc52320..50bf3e9f 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/GraphicsRequests.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/GraphicsRequests.groovy @@ -40,14 +40,14 @@ interface GraphicsRequests { @ImmutableOptions(knownImmutables = ['layout', 'colour']) static record MeshRequest(MeshType type, VertexBufferLayout layout, Vector2f[] vertices, Colour colour, - Vector2f[] textureUVs, int[] indices, boolean dynamic) implements Request { + Vector2f[] textureUVs, int[] indices) implements Request { - MeshRequest(MeshType type, VertexBufferLayout layout, Vector2f[] vertices, Colour colour, int[] indices, boolean dynamic) { - this(type, layout, vertices, colour, null, indices, dynamic) + MeshRequest(MeshType type, VertexBufferLayout layout, Vector2f[] vertices, Colour colour, int[] indices) { + this(type, layout, vertices, colour, null, indices) } MeshRequest(MeshType type, VertexBufferLayout layout, Vector2f[] vertices, Colour colour) { - this(type, layout, vertices, colour, null, null, false) + this(type, layout, vertices, colour, null, null) } } diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/GraphicsSystem.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/GraphicsSystem.groovy index 718bd087..9f3dd493 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/GraphicsSystem.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/GraphicsSystem.groovy @@ -136,7 +136,7 @@ class GraphicsSystem extends EngineSystem implements GraphicsRequests { var resource = switch (request) { case ShaderRequest -> renderer.createShader(request.shaderConfig()) case MeshRequest -> renderer.createMesh(request.type(), request.layout(), request.vertices(), request.colour(), - request.textureUVs(), request.indices(), request.dynamic()) + request.textureUVs(), request.indices()) case SpriteMeshRequest -> renderer.createSpriteMesh(request.surface(), request.textureUVs()) case TextureRequest -> renderer.createTexture(request.width(), request.height(), request.format(), request.data()) case SpriteSheetRequest -> renderer.createSpriteSheet(request.width(), request.height(), request.format(), request.data()) diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/Mesh.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/Mesh.groovy index b5d21f14..1018e240 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/Mesh.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/Mesh.groovy @@ -40,10 +40,4 @@ abstract class Mesh implements GraphicsResource { * Use this mesh in upcoming render operations. */ abstract void bind() - - /** - * Update the textureUVs part of the mesh data. This is only allowed on - * meshes that have been configured to use dynamic buffer data. - */ - abstract void updateTextureUvs(Vector2f[] textureUVs) } diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/Shader.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/Shader.groovy index 5e612471..2117d6ee 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/Shader.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/Shader.groovy @@ -34,6 +34,8 @@ abstract class Shader implements GraphicsResource { final Attribute[] attributes final Uniform[] uniforms + private final Map lastValues = [:] + /** * Update a shader's uniforms using the given context. */ @@ -49,7 +51,26 @@ abstract class Shader implements GraphicsResource { * Apply a data uniform to the shader. If {@code data} is an array, it can be * used to determine the shader type (eg: 2 floats = vec2). */ - abstract void setUniformGeneric(String name, Object data) + void setUniformGeneric(String name, Object data) { + + if (data == null) { + throw new IllegalArgumentException("Data value for key ${name} was null") + } + + // Only perform an update if there was a change in the value since last time + if (lastValues[name] != data) { + lastValues[name] = data + + switch (data) { + case Float -> setUniform(name, data) + case Float[] -> setUniform(name, (float[])data) + case Integer -> setUniform(name, data) + case Integer[] -> setUniform(name, (int[])data) + case Matrix4f -> setUniform(name, data) + default -> throw new UnsupportedOperationException("Data type of ${data.class.simpleName} not supported") + } + } + } /** * Apply a data uniform to the shader. The type of data is determined by the diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/opengl/OpenGLMesh.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/opengl/OpenGLMesh.groovy index 78968484..525426a8 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/opengl/OpenGLMesh.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/opengl/OpenGLMesh.groovy @@ -39,15 +39,13 @@ class OpenGLMesh extends Mesh { final int vertexArrayId final int vertexBufferId final int elementBufferId - final boolean dynamic private Vector2f[] lastTextureUVs /** * Constructor, creates a new OpenGL mesh. */ - OpenGLMesh(int type, VertexBufferLayout layout, Vector2f[] vertices, Colour colour, Vector2f[] textureUVs, - int[] indices, boolean dynamic) { + OpenGLMesh(int type, VertexBufferLayout layout, Vector2f[] vertices, Colour colour, Vector2f[] textureUVs, int[] indices) { super(type, layout, vertices, colour, textureUVs, indices) @@ -73,7 +71,7 @@ class OpenGLMesh extends Mesh { } } vertexBuffer.flip() - glBufferData(GL_ARRAY_BUFFER, vertexBuffer, dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW) + glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STATIC_DRAW) layout.attributes.each { attribute -> glEnableVertexAttribArray(attribute.location) @@ -96,7 +94,6 @@ class OpenGLMesh extends Mesh { elementBufferId = 0 } - this.dynamic = dynamic lastTextureUVs = textureUVs } @@ -115,28 +112,4 @@ class OpenGLMesh extends Mesh { glDeleteBuffers(vertexBufferId) glDeleteVertexArrays(vertexArrayId) } - - @Override - void updateTextureUvs(Vector2f[] textureUVs) { - - if (!this.textureUVs) { - throw new IllegalStateException('Cannot update textureUVs on a mesh that has no textureUVs to begin with') - } - - if (!dynamic) { - throw new IllegalStateException('Cannot update textureUVs on a mesh that was created without a dynamic buffer') - } - - if (textureUVs != lastTextureUVs) { - stackPush().withCloseable { stack -> - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId) - textureUVs.eachWithIndex { textureUv, index -> - glBufferSubData(GL_ARRAY_BUFFER, - (layout.sizeInBytes() * index) + layout.offsetOfInBytes(Attribute.TEXTURE_UVS), - textureUv.get(stack.mallocFloat(Vector2f.FLOATS))) - } - } - lastTextureUVs = textureUVs - } - } } diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/opengl/OpenGLRenderer.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/opengl/OpenGLRenderer.groovy index 5c42aa89..20d1b0d3 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/opengl/OpenGLRenderer.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/opengl/OpenGLRenderer.groovy @@ -192,10 +192,10 @@ class OpenGLRenderer implements GraphicsRenderer { @Override Mesh createMesh(MeshType type, VertexBufferLayout layout, Vector2f[] vertices, Colour colour, Vector2f[] textureUVs, - int[] indices, boolean dynamic) { + int[] indices) { var mesh = new OpenGLMesh(type == MeshType.LINES ? GL_LINES : type == MeshType.LINE_LOOP ? GL_LINE_LOOP : GL_TRIANGLES, - layout, vertices, colour, textureUVs, indices, dynamic) + layout, vertices, colour, textureUVs, indices) trigger(new MeshCreatedEvent(mesh)) return mesh } @@ -229,8 +229,7 @@ class OpenGLRenderer implements GraphicsRenderer { surface as Vector2f[], Colour.WHITE, textureUVs as Vector2f[], - [0, 1, 3, 1, 2, 3] as int[], - true + 0, 1, 3, 1, 2, 3 ) } diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/opengl/OpenGLShader.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/opengl/OpenGLShader.groovy index 54f6f16e..d2a4ee93 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/opengl/OpenGLShader.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/opengl/OpenGLShader.groovy @@ -118,23 +118,6 @@ class OpenGLShader extends Shader { return glGetUniformLocation(programId, name) } - @Override - void setUniformGeneric(String name, Object data) { - - if (data == null) { - throw new IllegalArgumentException("Data value for key ${name} was null") - } - - switch (data) { - case float, Float -> setUniform(name, (float)data) - case float[], Float[] -> setUniform(name, (float[])data) - case int, Integer -> setUniform(name, (int)data) - case int[], Integer[] -> setUniform(name, (int[])data) - case Matrix4f -> setUniform(name, data) - default -> throw new UnsupportedOperationException("Data type of ${data.class.simpleName} not supported") - } - } - @Override void setUniform(String name, float[] data) { diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/nodes/Primitive.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/nodes/Primitive.groovy index c9358a2f..f61211f0 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/nodes/Primitive.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/nodes/Primitive.groovy @@ -80,7 +80,7 @@ class Primitive extends Node implements GraphicsElement { scene .requestCreateOrGet(type == MeshType.TRIANGLES ? new MeshRequest(type, new VertexBufferLayout(Attribute.POSITION, Attribute.COLOUR), this.points, colour, - [0, 1, 3, 1, 2, 3] as int[], false) : + [0, 1, 3, 1, 2, 3] as int[]) : new MeshRequest(type, new VertexBufferLayout(Attribute.POSITION, Attribute.COLOUR), this.points, colour)) .thenAcceptAsync { newMesh -> mesh = newMesh