package openblocks.client.renderer.tileentity.guide; import java.nio.ByteBuffer; import java.nio.IntBuffer; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.shader.TesselatorVertexState; import net.minecraft.util.ResourceLocation; import openblocks.shapes.CoordShape; import openmods.renderer.shaders.ArraysHelper; import openmods.renderer.shaders.BufferHelper; import openmods.renderer.shaders.ShaderProgram; import openmods.renderer.shaders.ShaderProgramBuilder; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL20; public class MarkerRenderer { private static final ResourceLocation vertexSource = new ResourceLocation("openblocks:shaders/shader.vert"); private static final ResourceLocation fragmentSource = new ResourceLocation("openblocks:shaders/shader.frag"); private final ShaderProgram shader; private static final int nativeBufferSize = 0x200000; private final ByteBuffer byteBuffer = GLAllocation.createDirectByteBuffer(nativeBufferSize * 4); private final IntBuffer intBuffer = byteBuffer.asIntBuffer(); private final Runnable model; private boolean initialized; private boolean hasTexture; private boolean hasColor; private boolean shouldRefresh = true; private int vertexCount; private int vao; private int vbo; public MarkerRenderer(Runnable model) { this.model = model; final ShaderProgramBuilder shaderProgramBuilder = new ShaderProgramBuilder(); shaderProgramBuilder.addShader(vertexSource, GL20.GL_VERTEX_SHADER); shaderProgramBuilder.addShader(fragmentSource, GL20.GL_FRAGMENT_SHADER); this.shader = shaderProgramBuilder.build(); } public void reset() { shouldRefresh = true; } private void createModel() { model.run(); TesselatorVertexState state = Tessellator.instance.getVertexState(0, 0, 0); Tessellator.instance.draw(); // just discard the state this way. if (state.getRawBuffer().length > nativeBufferSize) throw new UnsupportedOperationException("Big buffers not supported!"); vertexCount = state.getVertexCount(); byteBuffer.position(0); intBuffer.clear(); intBuffer.put(state.getRawBuffer(), 0, vertexCount * 8); byteBuffer.position(0); byteBuffer.limit(vertexCount * 32); hasTexture = state.getHasTexture(); hasColor = state.getHasColor(); } private void createVAO() { if (initialized) { createModel(); if (vao == 0) vao = ArraysHelper.methods().glGenVertexArrays(); ArraysHelper.methods().glBindVertexArray(vao); if (vbo == 0) vbo = BufferHelper.methods().glGenBuffers(); BufferHelper.methods().glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo); BufferHelper.methods().glBufferData(GL15.GL_ARRAY_BUFFER, byteBuffer, GL15.GL_STATIC_DRAW); shader.attributePointer("aVertex", 3, GL11.GL_FLOAT, false, 32, 0); shader.attributePointer("aTexCoord", 2, GL11.GL_FLOAT, false, 32, 12); shader.attributePointer("aColor", 4, GL11.GL_UNSIGNED_BYTE, false, 32, 20); BufferHelper.methods().glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); shader.uniform1f("uHasTexture", hasTexture? 1f : 0f); shader.uniform1f("uHasColor", hasColor? 1f : 0f); shader.uniform1i("uDefaultTexture", 0); ArraysHelper.methods().glBindVertexArray(0); shouldRefresh = false; } } public void drawInstanced(CoordShape shape, int color, float scale) { shader.bind(); initialized = true; if (shouldRefresh) createVAO(); ArraysHelper.methods().glBindVertexArray(vao); shape.bindVBO(); shader.instanceAttributePointer("aPosition", 3, GL11.GL_INT, false, 0, 0); BufferHelper.methods().glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); shader.uniform3f("uColor", ((color >> 16) & 0xFF) / 255f, ((color >> 8) & 0xFF) / 255f, (color & 0xFF) / 255f); shader.uniform1f("uScale", scale); ArraysHelper.methods().glDrawArraysInstanced(GL11.GL_QUADS, 0, vertexCount, shape.size()); ArraysHelper.methods().glBindVertexArray(0); shader.release(); } public void deleteShape(CoordShape shape) { if (initialized) { ArraysHelper.methods().glBindVertexArray(vao); shape.destroy(); ArraysHelper.methods().glBindVertexArray(0); } } }