package com.bitwaffle.spaceguts.graphics.shapes;
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;
public class VBOTorus {
private int vaoHandle;
private int faces, rings, sides;
private float[] verts, norms, tex;
private int[] el;
public VBOTorus(float outerRadius, float innerRadius, int sides, int rings){
this.rings = rings;
this.sides = sides;
// generate vertices
generateVerts(outerRadius, innerRadius);
FloatBuffer v = BufferUtils.createFloatBuffer(verts.length);
v.put(verts);
v.rewind();
FloatBuffer n = BufferUtils.createFloatBuffer(norms.length);
n.put(norms);
n.rewind();
FloatBuffer t = BufferUtils.createFloatBuffer(tex.length);
t.put(tex);
t.rewind();
IntBuffer ele = BufferUtils.createIntBuffer(el.length);
ele.put(el);
ele.rewind();
vaoHandle = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vaoHandle);
// create and populate buffer objects
IntBuffer handle = BufferUtils.createIntBuffer(3);
GL15.glGenBuffers(handle);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, handle.get(0));
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, v, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0L);
GL20.glEnableVertexAttribArray(0); // vertex position
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, handle.get(1));
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, n, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(1, 3, GL11.GL_FLOAT, false, 0, 0L);
GL20.glEnableVertexAttribArray(1); // vertex normal
//GL20.glEnableVertexAttribArray(2); // texture coords
//GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, handle.get(2));
//GL20.glVertexAttribPointer(2, 2, GL11.GL_FLOAT, false, 0, 0L);
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, handle.get(2));
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, ele, GL15.GL_STATIC_DRAW);
GL30.glBindVertexArray(0);
}
public void render(){
GL30.glBindVertexArray(vaoHandle);
GL11.glDrawElements(GL11.GL_TRIANGLES, faces * 6, GL11.GL_UNSIGNED_INT, 0L);
}
private void generateVerts(float outerRadius, float innerRadius){
faces = sides * rings;
int nVerts = sides * (rings + 1); //one extra to duplicate first ring
verts = new float[nVerts * 3];
norms = new float[nVerts * 3];
tex = new float[nVerts * 2];
el = new int[faces * 6];
float ringFactor = (float) (Math.PI * 2.0 / (double)rings);
float sideFactor = (float) (Math.PI * 2.0 / (double)sides);
// create vertices, normals and tex coords
int idx = 0, tidx = 0;
for(int ring = 0; ring <= rings; ring++){
double u = (double)(ring * ringFactor);
float cu = (float)(Math.cos(u));
float su = (float)(Math.sin(u));
for(int side = 0; side < sides; side++){
double v = (double)(side * sideFactor);
float cv = (float)(Math.cos(v));
float sv = (float)(Math.sin(v));
float r = (outerRadius + innerRadius * cv);
verts[idx] = r * cu;
verts[idx + 1] = r * su;
verts[idx + 2] = innerRadius * sv;
norms[idx] = cv * cu * r;
norms[idx + 1] = cv * su * r;
norms[idx + 2] = sv * r;
tex[tidx] = (float)(u / Math.PI * 2.0);
tex[tidx+1] = (float)(v / Math.PI * 2.0);
tidx += 2;
// Normalize
float len = (float)(Math.sqrt(
(double)(
norms[idx] * norms[idx] +
norms[idx+1] * norms[idx+1] +
norms[idx+2] * norms[idx+2] )
));
norms[idx] /= len;
norms[idx+1] /= len;
norms[idx+2] /= len;
idx += 3;
}
}
// create indices
idx = 0;
for(int ring = 0; ring < rings; ring++){
int ringStart = ring * sides;
int nextRingStart = (ring + 1) * sides;
for(int side = 0; side < sides; side++){
int nextSide = (side+1) % sides;
// The quad
el[idx] = (ringStart + side);
el[idx+1] = (nextRingStart + side);
el[idx+2] = (nextRingStart + nextSide);
el[idx+3] = ringStart + side;
el[idx+4] = nextRingStart + nextSide;
el[idx+5] = (ringStart + nextSide);
idx += 6;
}
}
}
}