package com.bitwaffle.spaceguts.entities.particles.trail; import java.nio.FloatBuffer; import java.nio.IntBuffer; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; import com.bitwaffle.spaceout.resources.Textures; /** * Handles creating and updating the vertex arrays for the trail * @author TranquilMarmot * */ public class TrailRenderer { /** Info for rendering */ private int vaoHandle, numIndices; /** The trail we're rendering */ private Trail trail; /** Handles for vertex buffer objects */ IntBuffer vboHandles; private Textures texture; private FloatBuffer vertBuf, normBuf, texBuf; /** * @param trail Trail to render with this renderer */ public TrailRenderer(Trail trail, Textures texture){ this.trail = trail; this.texture = texture; initVBO(); } /** * Updates the vertex arrays to contain the most recent trail data */ public void updateVBO(){ // clear buffers vertBuf.clear(); normBuf.clear(); texBuf.clear(); // iterate through every link for(int i = 0; i < trail.chain.size(); i++){ TrailLink link = trail.chain.get(i); vertBuf.put(link.top.x); vertBuf.put(link.top.y); vertBuf.put(link.top.z); // see the initVBO() method for an explanation of this texBuf.put((float)i * texture.texture().getWidth()); texBuf.put(texture.texture().getHeight()); normBuf.put((float)i * texture.texture().getWidth()); normBuf.put(texture.texture().getHeight()); vertBuf.put(link.bottom.x); vertBuf.put(link.bottom.y); vertBuf.put(link.bottom.z); texBuf.put((float)i * texture.texture().getWidth()); texBuf.put(0.0f); normBuf.put((float)i * texture.texture().getWidth()); normBuf.put(0.0f); } vertBuf.rewind(); texBuf.rewind(); normBuf.rewind(); GL30.glBindVertexArray(vaoHandle); // send data to buffers GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandles.get(0)); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertBuf, GL15.GL_STREAM_DRAW); GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0L); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandles.get(1)); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, normBuf, GL15.GL_STREAM_DRAW); GL20.glVertexAttribPointer(1, 3, GL11.GL_FLOAT, false, 0, 0L); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandles.get(2)); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, texBuf, GL15.GL_STREAM_DRAW); GL20.glVertexAttribPointer(2, 2, GL11.GL_FLOAT, false, 0, 0L); } public void initVBO(){ // 2 indices for the first link, and 2 for every link after numIndices = (trail.length * 2) + 2; // 3 vertices per index, unless it's a texture coordinate vertBuf = BufferUtils.createFloatBuffer(numIndices * 3); normBuf = BufferUtils.createFloatBuffer(numIndices * 3); texBuf = BufferUtils.createFloatBuffer(numIndices * 2); // iterate through every link for(int i = 0; i < trail.chain.size(); i++){ TrailLink link = trail.chain.get(i); vertBuf.put(link.top.x); vertBuf.put(link.top.y); vertBuf.put(link.top.z); /* * In OpenGL, texture coordinates are supposed to be specified as * between 0.0f and 1.0f. If the coordinates are specified as beyond * 1.0f, then the textured is sampled as a loop. That is to say * giving OpenGL a texture coordinate of 1.3f or 2.3f is exactly * the same as specifying 0.3f. * Since the trail is being rendered as a quad strip, * we just give it the index of the link in the chain. * So the top of the first link goes from 0.0f to 1.0f, * and the second link goes from 1.0f to 2.0f and so on. */ texBuf.put((float)i * texture.texture().getWidth()); texBuf.put(1.0f); normBuf.put((float)i * texture.texture().getWidth()); normBuf.put(1.0f); vertBuf.put(link.bottom.x); vertBuf.put(link.bottom.y); vertBuf.put(link.bottom.z); texBuf.put((float)i * texture.texture().getWidth()); texBuf.put(0.0f); normBuf.put((float)i * texture.texture().getWidth()); normBuf.put(0.0f); } vertBuf.rewind(); texBuf.rewind(); normBuf.rewind(); // Send the data to the buffers vaoHandle = GL30.glGenVertexArrays(); GL30.glBindVertexArray(vaoHandle); vboHandles = BufferUtils.createIntBuffer(3); GL15.glGenBuffers(vboHandles); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandles.get(0)); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertBuf, GL15.GL_STREAM_DRAW); GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0L); GL20.glEnableVertexAttribArray(0); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandles.get(1)); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, normBuf, GL15.GL_STREAM_DRAW); GL20.glVertexAttribPointer(1, 3, GL11.GL_FLOAT, false, 0, 0L); GL20.glEnableVertexAttribArray(1); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboHandles.get(2)); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, texBuf, GL15.GL_STREAM_DRAW); GL20.glVertexAttribPointer(2, 2, GL11.GL_FLOAT, false, 0, 0L); GL20.glEnableVertexAttribArray(2); } /** * Draws the trail */ public void draw(){ GL30.glBindVertexArray(vaoHandle); // Don't know why it be like it does, but it do GL11.glDrawArrays(GL11.GL_QUAD_STRIP, 0, numIndices - 1); } }