Skip to content

Commit

Permalink
Vertex array object (#2644)
Browse files Browse the repository at this point in the history
Do not use vertex array object as this is not supported in OpenGL 2 on all operating systems.
  • Loading branch information
breiler authored Nov 26, 2024
1 parent fdedbbc commit f5a09a4
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 148 deletions.
2 changes: 1 addition & 1 deletion ugs-platform/ugs-platform-visualizer/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
<dependency>
<groupId>com.breiler.jcsg</groupId>
<artifactId>jcsg-core</artifactId>
<version>0.0.1</version>
<version>0.0.2</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ This file is part of Universal Gcode Sender (UGS).
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.opengl.fixedfunc.GLPointerFunc;
import com.willwinder.ugs.nbm.visualizer.options.VisualizerOptions;
import com.willwinder.ugs.nbm.visualizer.shader.PlainShader;
import com.willwinder.ugs.nbm.visualizer.shared.VertexObjectRenderable;
Expand Down Expand Up @@ -114,6 +113,7 @@ private CSG generateModel() {
}

private void generateBuffers(CSG csg) {
clear();
List<Polygon> polygons = csg.triangulate().getPolygons();

for (Polygon polygon : polygons) {
Expand All @@ -126,13 +126,17 @@ private void generateBuffers(CSG csg) {
Vector3d normal = b.minus(a).cross(c.minus(a)).normalized();

polygon.getPoints().forEach(point -> {
addVertex(point.getX(), point.getY(), point.getZ());
addNormal(normal.getX(), normal.getY(), normal.getZ());
addColor(colorArray);
addPoint(point, normal, colorArray);
});
}
}

private void addPoint(Vector3d point, Vector3d normal, float[] colorArray) {
addVertex(point.getX(), point.getY(), point.getZ());
addNormal(normal.getX(), normal.getY(), normal.getZ());
addColor(colorArray);
}

@Override
public void render(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
Expand All @@ -155,10 +159,6 @@ public void render(GLAutoDrawable drawable) {
int count = getVertexCount();
gl.glDrawArrays(GL.GL_TRIANGLES, 0, count);

gl.glDisableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
gl.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
gl.glDisableClientState(GLPointerFunc.GL_COLOR_ARRAY);

gl.glViewport(0, 0, xSize, ySize);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,30 +59,11 @@ public void init(GL2 gl) {
}

shaderProgramId = ShaderLoader.loadProgram(gl, IOUtils.toString(vertexShaderInputStream, StandardCharsets.UTF_8), IOUtils.toString(fragmentShaderInputStream, StandardCharsets.UTF_8));

gl.glBindAttribLocation(shaderProgramId, 0, "vertexPosition");
gl.glBindAttribLocation(shaderProgramId, 1, "vertexNormal");
gl.glBindAttribLocation(shaderProgramId, 2, "vertexColor");
} catch (IOException e) {
throw new GLException(e);
}
}

@Override
public int getShaderVertexIndex() {
return 0;
}

@Override
public int getShaderNormalIndex() {
return 1;
}

@Override
public int getShaderColorIndex() {
return 3;
}

public void dispose(GL2 gl) {
if (shaderProgramId <= 0) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,25 +45,4 @@ public interface Shader {
* @return the id of the shader program
*/
int getProgramId();

/**
* Get the shader parameter index for vertices
*
* @return the index
*/
int getShaderVertexIndex();

/**
* Get the shader parameter index for colors
*
* @return the index
*/
int getShaderColorIndex();

/**
* Get the shader parameter index for normals
*
* @return the index
*/
int getShaderNormalIndex();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.util.GLBuffers;
import com.willwinder.ugs.nbm.visualizer.options.VisualizerOptions;
import com.willwinder.ugs.nbm.visualizer.shader.Shader;
import com.willwinder.ugs.nbm.visualizer.utils.RenderableUtils;
import com.willwinder.universalgcodesender.model.Position;

import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -25,11 +27,17 @@ public abstract class VertexObjectRenderable extends Renderable {
private Position objectMax = Position.ZERO;
private Shader shader;

private interface Buffer {
int VERTEX = 0;
int NORMAL = 1;
int COLOR = 2;
int MAX = 3;
}

private IntBuffer bufferName = GLBuffers.newDirectIntBuffer(Buffer.MAX);


private boolean reloadModel;
private int vertexObjectId;
private int vertexBufferId;
private int colorBufferId;
private int normalBufferId;


protected double getStepSize() {
Expand Down Expand Up @@ -71,7 +79,7 @@ protected void addColor(float[] color) {
}

protected int getVertexCount() {
return vertexList.size();
return vertexList.size() / 3;
}

@Override
Expand All @@ -84,7 +92,10 @@ public void reloadPreferences(VisualizerOptions vo) {

@Override
public void init(GLAutoDrawable drawable) {
shader.init(drawable.getGL().getGL2());
GL2 gl = drawable.getGL().getGL2();
gl.glGenBuffers(Buffer.MAX, bufferName);
shader.init(gl);
checkGLError(gl);
}

private double padMinMaxPoint(double stepSize, double point, boolean negativeDirection) {
Expand All @@ -97,7 +108,7 @@ private double padMinMaxPoint(double stepSize, double point, boolean negativeDir

@Override
public final void draw(GLAutoDrawable drawable, boolean idle, Position machineCoord, Position workCoord, Position objectMin, Position objectMax, double scaleFactor, Position mouseWorldCoordinates, Position rotation) {
GL2 gl = (GL2) drawable.getGL();
GL2 gl = drawable.getGL().getGL2();

double newStepSize = RenderableUtils.getStepSize(scaleFactor);
if (!this.objectMin.equals(objectMin) || !this.objectMax.equals(objectMax) || reloadModel || this.stepSize != newStepSize) {
Expand All @@ -120,23 +131,51 @@ public final void draw(GLAutoDrawable drawable, boolean idle, Position machineCo

// Use the shader program
gl.glUseProgram(shader.getProgramId());
checkGLError(gl);

int positionAttribute = gl.glGetAttribLocation(shader.getProgramId(), "position");
gl.glEnableVertexAttribArray(positionAttribute);
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, bufferName.get(Buffer.VERTEX));
gl.glVertexAttribPointer(positionAttribute, 3, GL2.GL_FLOAT, false, 0, 0);
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
checkGLError(gl);

int colorAttribute = gl.glGetAttribLocation(shader.getProgramId(), "color");
gl.glEnableVertexAttribArray(colorAttribute);
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, bufferName.get(Buffer.COLOR));
gl.glVertexAttribPointer(colorAttribute, 4, GL2.GL_FLOAT, false, 0, 0);
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
checkGLError(gl);

// Bind the VAO containing the vertex data
gl.glBindVertexArray(vertexObjectId);
render(drawable);

// Unbind the VAO
gl.glBindVertexArray(0);
// Disable the attribute after drawing
gl.glDisableVertexAttribArray(positionAttribute);
gl.glDisableVertexAttribArray(colorAttribute);
checkGLError(gl);

gl.glUseProgram(0);
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
checkGLError(gl);
}

private void checkGLError(GL2 gl) {
int error = gl.glGetError();
if (error != GL2.GL_NO_ERROR) {
throw new RuntimeException("GL error: " + error);
}
}

private void updateBuffers(GL2 gl) {
gl.glDeleteBuffers(2, new int[]{vertexBufferId, colorBufferId, normalBufferId}, 0);
vertexObjectId = bindVertexObject(gl);
vertexBufferId = bindVertexBuffer(gl, vertexList, shader.getShaderVertexIndex());
colorBufferId = bindColorBuffer(gl, colorList, shader.getShaderColorIndex());
normalBufferId = bindNormalBuffer(gl, normalList, shader.getShaderNormalIndex());
gl.glDeleteBuffers(3, new int[]{
bufferName.get(Buffer.VERTEX),
bufferName.get(Buffer.COLOR),
bufferName.get(Buffer.NORMAL)},
0);

bindVertexBuffer(gl, bufferName.get(Buffer.VERTEX), vertexList);
bindVertexBuffer(gl, bufferName.get(Buffer.COLOR), colorList);
bindVertexBuffer(gl, bufferName.get(Buffer.NORMAL), normalList);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,90 +18,21 @@ This file is part of Universal Gcode Sender (UGS).
*/
package com.willwinder.ugs.nbm.visualizer.utils;

import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import org.apache.commons.lang3.ArrayUtils;

import java.nio.FloatBuffer;
import java.util.List;

public class RenderableUtils {
/**
* Generates and binds a color buffer
*
* @param gl the GL context to use
* @param colorList a list of float values containing the color RGBA values
* @param vertexBufferIndex the parameter index of the shader to bind to
* @return the id of the color buffer to be reference to when rendering
*/
public static int bindColorBuffer(GL2 gl, List<Float> colorList, int vertexBufferIndex) {
// Create and upload the Color Buffer Object (CBO) for colors
int[] cbo = new int[1];
gl.glGenBuffers(1, cbo, 0);

gl.glBindBuffer(GL.GL_ARRAY_BUFFER, cbo[0]);

// Upload vertex colors to the GPU
FloatBuffer colorBuffer = Buffers.newDirectFloatBuffer(ArrayUtils.toPrimitive(colorList.toArray(new Float[0])));
gl.glBufferData(GL.GL_ARRAY_BUFFER, colorBuffer.capacity() * Float.BYTES, colorBuffer, GL.GL_STATIC_DRAW);

// Specify vertex attribute layout (index 1 for color)
gl.glEnableVertexAttribArray(vertexBufferIndex);
gl.glVertexAttribPointer(vertexBufferIndex, 4, GL.GL_FLOAT, false, 4 * Float.BYTES, 0);

return cbo[0];
}

/**
* Generates and binds a color buffer
*
* @param gl the GL context to use
* @param normalList a list of float values containing the vertex normal
* @param normalBufferIndex the parameter index of the shader to bind to
* @return the id of the color buffer to be reference to when rendering
*/
public static int bindNormalBuffer(GL2 gl, List<Float> normalList, int normalBufferIndex) {
// Create and upload the Normal Buffer Object (NBO) for colors
int[] nbo = new int[1];
gl.glGenBuffers(1, nbo, 0);

gl.glBindBuffer(GL.GL_ARRAY_BUFFER, nbo[0]);

// Upload vertex colors to the GPU
FloatBuffer normalBuffer = Buffers.newDirectFloatBuffer(ArrayUtils.toPrimitive(normalList.toArray(new Float[0])));
gl.glBufferData(GL.GL_ARRAY_BUFFER, normalBuffer.capacity() * Float.BYTES, normalBuffer, GL.GL_STATIC_DRAW);

// Specify vertex attribute layout (index 1 for color)
gl.glEnableVertexAttribArray(normalBufferIndex);
gl.glVertexAttribPointer(normalBufferIndex, 4, GL.GL_FLOAT, false, 4 * Float.BYTES, 0);

return nbo[0];
}


public static int bindVertexBuffer(GL2 gl, List<Float> vertexList, int positionIndex) {
// Create a Vertex Buffer Object (VBO)
int[] vbo = new int[1];
gl.glGenBuffers(1, vbo, 0);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo[0]);
public static void bindVertexBuffer(GL gl, int vertexBufferId, List<Float> vertexList) {
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vertexBufferId);

// Send vertex data to the GPU
FloatBuffer vertexBuffer = Buffers.newDirectFloatBuffer(ArrayUtils.toPrimitive(vertexList.toArray(new Float[0])));
gl.glBufferData(GL.GL_ARRAY_BUFFER, vertexBuffer.capacity() * Float.BYTES, vertexBuffer, GL.GL_STATIC_DRAW);

// Specify the layout of the vertex data
gl.glEnableVertexAttribArray(positionIndex);
gl.glVertexAttribPointer(positionIndex, 3, GL.GL_FLOAT, false, 3 * Float.BYTES, 0);

return vbo[0];
}

public static int bindVertexObject(GL2 gl) {
int[] vao = new int[1];
gl.glGenVertexArrays(1, vao, 0);
gl.glBindVertexArray(vao[0]);
return vao[0];
float[] floatArray = ArrayUtils.toPrimitive(vertexList.toArray(new Float[0]));
gl.glBufferData(GL.GL_ARRAY_BUFFER, (long) floatArray.length * Float.BYTES, FloatBuffer.wrap(floatArray), GL.GL_DYNAMIC_DRAW);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
}

public static void addColor(List<Float> colorList, float[] color) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,6 @@ public static int loadProgram(final GL2ES2 gl, final String vertexShaderSource,
throw new GLException(log);
}

// Explicitly bind the parameters locations
gl.glBindAttribLocation(program, 0, "gl_Position");
gl.glBindAttribLocation(program, 1, "gl_Normal");
gl.glBindAttribLocation(program, 3, "gl_Color");

// Clean up the shaders
gl.glDeleteShader(vertexShaderId);
gl.glDeleteShader(fragmentShaderId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#version 110
#version 120

// Input color from the vertex shader
varying vec4 fragColor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#version 110
#version 120

attribute vec3 position;
attribute vec4 color;

// Output color to the fragment shader
varying vec4 fragColor;

void main() {
// Set the vertex position
gl_Position = ftransform();
gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 1.0);

// Pass the vertex color to the fragment shader
fragColor = gl_Color;
fragColor = color;
}

0 comments on commit f5a09a4

Please sign in to comment.