Skip to content

Instantly share code, notes, and snippets.

@digz6666
Last active July 11, 2017 09:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save digz6666/48bb433c83801ea4b82fa194f05b4f02 to your computer and use it in GitHub Desktop.
Save digz6666/48bb433c83801ea4b82fa194f05b4f02 to your computer and use it in GitHub Desktop.
OpenGL graph render
package mn.digz.lwjgl;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.system.MemoryUtil.NULL;
import java.io.IOException;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
import mn.digz.lwjgl.model.GLColor;
import mn.digz.lwjgl.model.GLLine;
import mn.digz.lwjgl.model.GLPoint;
import mn.digz.lwjgl.model.GLTriangle;
import mn.digz.lwjgl.util.ShaderUtil;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWFramebufferSizeCallback;
import org.lwjgl.glfw.GLFWKeyCallback;
import org.lwjgl.glfw.GLFWMouseButtonCallback;
import org.lwjgl.glfw.GLFWScrollCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLUtil;
import org.lwjgl.system.Callback;
/**
*
* @author MethoD
*/
public class OpenGLGraphRender {
private long window;
private int width = 1024;
private int height = 768;
private int program;
// view projection
private int viewProjMatrixUniform;
private Matrix4f viewProjMatrix = new Matrix4f();
private FloatBuffer matrixBuffer = BufferUtils.createFloatBuffer(16);
// view port
private IntBuffer viewportBuffer = BufferUtils.createIntBuffer(4);
private int[] viewport = new int[4];
// vertices
private List<GLTriangle> vertices;
private FloatBuffer verticesBuffer;
private int vertexPositionAttribute;
private int vertexColorAttribute;
private int pointSize = 3 + 4; // x,y,z + r,g,b,a
private int step = Float.SIZE / 8; // byte per element
private int stride = step * pointSize; // need?
// edges
//private List<GLLine> edges;
// eye
private float eye_x = 0f;
private float eye_y = 0f;
private float eye_z = 7f;
// mouse
private DoubleBuffer mouseXBuffer = BufferUtils.createDoubleBuffer(1);
private DoubleBuffer mouseYBuffer = BufferUtils.createDoubleBuffer(1);
private GLFWErrorCallback errCallback;
private GLFWKeyCallback keyCallback;
private GLFWFramebufferSizeCallback fbCallback;
private Callback debugProc;
private void init() {
glfwSetErrorCallback(errCallback = GLFWErrorCallback.createPrint(System.err));
if (!glfwInit())
throw new IllegalStateException("Unable to initialize GLFW");
glfwDefaultWindowHints();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
//glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
window = glfwCreateWindow(width, height, "Silhouette rendering with geometry shader", NULL, NULL);
if (window == NULL) {
throw new AssertionError("Failed to create the GLFW window");
}
// resize callback
glfwSetFramebufferSizeCallback(window, fbCallback = new GLFWFramebufferSizeCallback() {
@Override
public void invoke(long window, int width, int height) {
if (width > 0 && height > 0
&& (OpenGLGraphRender.this.width != width || OpenGLGraphRender.this.height != height)) {
OpenGLGraphRender.this.width = width;
OpenGLGraphRender.this.height = height;
}
}
});
glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
@Override
public void invoke(long window, int key, int scancode, int action, int mods) {
if (action != GLFW_RELEASE)
return;
if (key == GLFW_KEY_ESCAPE) {
glfwSetWindowShouldClose(window, true);
}
if (key == GLFW_KEY_UP) {
eye_y += 0.5f;
}
if (key == GLFW_KEY_DOWN) {
eye_y -= 0.5f;
}
if (key == GLFW_KEY_LEFT) {
eye_x -= 0.5f;
}
if (key == GLFW_KEY_RIGHT) {
eye_x += 0.5f;
}
if (key == GLFW_KEY_UP || key == GLFW_KEY_DOWN || key == GLFW_KEY_LEFT || key == GLFW_KEY_RIGHT) {
updatePerspective();
}
}
});
// mouse click callback
glfwSetMouseButtonCallback(window, new GLFWMouseButtonCallback() {
@Override
public void invoke(long window, int button, int action, int mods) {
if (button == GLFW_MOUSE_BUTTON_1) {
glfwGetCursorPos(window, mouseXBuffer, mouseYBuffer);
double x = mouseXBuffer.get(0);
double y = mouseYBuffer.get(0);
System.out.println("clicked at: " + x + " - " + y);
Vector3f v3f = new Vector3f();
viewProjMatrix.unproject((float)x, (float)y, 0f, viewport, v3f);
System.out.println("world coordinate: " + v3f.x + " - " + v3f.y);
// check if any shape clicked
for (GLTriangle glTriangle : vertices) {
if (glTriangle.contains(v3f.x, v3f.y)) {
System.out.println("clicked glTriangle");
glTriangle.setPoint1Color(new GLColor(0.5f, 0.5f, 0f, 1.f));
break;
}
}
}
}
});
/*glfwSetCursorPosCallback(window, new GLFWCursorPosCallback() {
@Override
public void invoke(long window, double xpos, double ypos) {
}
});*/
// scroll callback
glfwSetScrollCallback(window, new GLFWScrollCallback() {
@Override
public void invoke(long window, double xoffset, double yoffset) {
if (eye_z - yoffset > 0) {
eye_z -= yoffset;
}
updatePerspective();
}
});
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);
glfwMakeContextCurrent(window);
glfwSwapInterval(1); // enable v sync
glfwShowWindow(window);
}
private void createProgram() throws IOException {
int program = glCreateProgram();
int vshader = ShaderUtil.createShader("mn/digz/lwjgl/shader/vs.glsl", GL_VERTEX_SHADER);
int fshader = ShaderUtil.createShader("mn/digz/lwjgl/shader/fs.glsl", GL_FRAGMENT_SHADER);
//int gshader = ShaderUtil.createShader("mn/digz/lwjgl/shader/gs.glsl", GL_GEOMETRY_SHADER_EXT);
glAttachShader(program, vshader);
glAttachShader(program, fshader);
//glAttachShader(program, gshader);
glLinkProgram(program);
int linked = glGetProgrami(program, GL_LINK_STATUS);
String programLog = glGetProgramInfoLog(program);
if (programLog != null && programLog.trim().length() > 0) {
System.err.println(programLog);
}
if (linked == 0) {
throw new AssertionError("Could not link program");
}
this.program = program;
}
/**
* Initialize the shader program.
*/
private void initProgram() {
glUseProgram(this.program);
viewProjMatrixUniform = glGetUniformLocation(this.program, "viewProjMatrix");
glBindAttribLocation(program, 0, "vertexPosition");
glBindAttribLocation(program, 1, "vertexColor");
vertexPositionAttribute = glGetAttribLocation(program, "vertexPosition");
vertexColorAttribute = glGetAttribLocation(program, "vertexColor");
verticesBuffer = BufferUtils.createFloatBuffer(pointSize * 3 * 3); // point size * 3 points * 3 triangles = 21 floats per triangle
vertices = new ArrayList<>(3);
vertices.add(new GLTriangle(
new GLPoint(0f, 0f, 1f, 1f, 1f, 0f, 1f),
new GLPoint(2f, 0f, 1f, 1f, 0f, 1f, 1f),
new GLPoint(1f, 1.7f, 1f, 0f, 1f, 1f, 1f)));
vertices.add(new GLTriangle(
new GLPoint(4f, 4f, 1f, 1f, 1f, 0f, 1f),
new GLPoint(6f, 4f, 1f, 1f, 0f, 1f, 1f),
new GLPoint(5f, 5.7f, 1f, 0f, 1f, 1f, 1f)));
vertices.add(new GLTriangle(
new GLPoint(4f, 1f, 1f, 1f, 1f, 0f, 1f),
new GLPoint(6f, 1f, 1f, 1f, 0f, 1f, 1f),
new GLPoint(5f, 2.7f, 1f, 0f, 1f, 1f, 1f)));
int vbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(vertexPositionAttribute);
glEnableVertexAttribArray(vertexColorAttribute);
glVertexAttribPointer(vertexPositionAttribute, 3, GL_FLOAT, false, stride, 0);
glVertexAttribPointer(vertexColorAttribute, 4, GL_FLOAT, false, stride, step * 3);
glGetIntegerv(GL_VIEWPORT, viewportBuffer);
viewportBuffer.get(viewport);
glUseProgram(0);
}
private void updatePerspective() {
glUseProgram(this.program);
viewProjMatrix
.setPerspective((float) Math.toRadians(30), (float) width / height, 0.01f, 500.0f) // define min and max planes
.lookAt(eye_x, eye_y, eye_z,
eye_x, eye_y, 0.0f,
0.0f, 2.0f, 0.0f);
glUniformMatrix4fv(viewProjMatrixUniform, false, viewProjMatrix.get(matrixBuffer));
glUseProgram(0);
}
private void render() {
glUseProgram(this.program);
verticesBuffer.clear();
vertices.forEach((glTriangle) -> {
verticesBuffer.put(glTriangle.toFloatArray());
});
verticesBuffer.flip();
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glDrawArrays(GL_TRIANGLES, 0, vertices.size() * 3); // 3 indices per triangle
glUseProgram(0);
}
private void loop() throws IOException {
GL.createCapabilities();
debugProc = GLUtil.setupDebugMessageCallback();
glClearColor(0.55f, 0.75f, 0.95f, 1.0f);
glEnable(GL_DEPTH_TEST);
/* Create all needed GL resources */
createProgram();
initProgram();
updatePerspective();
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glMatrixMode(GL_PROJECTION);
//float aspect = (float)width/height;
//glLoadIdentity();
//glOrtho(-aspect, aspect, -1, 1, -1, 1);
render();
glfwSwapBuffers(window);
}
}
public void run() {
try {
init();
loop();
if (debugProc != null)
debugProc.free();
errCallback.free();
keyCallback.free();
fbCallback.free();
glfwDestroyWindow(window);
} catch (Throwable t) {
t.printStackTrace();
} finally {
glfwTerminate();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment