Add rendering implementation for LWJGL
This commit is contained in:
1 parent
b01fe59dbb
commit
dc59810566
59 files changed
+6728
-16
No files matched your search
@@ -0,0 +1,125 @@
|
||||
import org.lwjgl.glfw.GLFWKeyCallback;
|
||||
import org.lwjgl.glfw.GLFWMouseButtonCallback;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
|
||||
public class InputHandler {
|
||||
private static long window;
|
||||
private static final int KEYBOARD_SIZE = 512;
|
||||
private static final int MOUSE_SIZE = 16;
|
||||
|
||||
private static int[] keyStates = new int[KEYBOARD_SIZE];
|
||||
private static boolean[] activeKeys = new boolean[KEYBOARD_SIZE];
|
||||
|
||||
private static int[] mouseButtonStates = new int[MOUSE_SIZE];
|
||||
private static boolean[] activeMouseButtons = new boolean[MOUSE_SIZE];
|
||||
private static long lastMouseNS = 0;
|
||||
private static long mouseDoubleClickPeriodNS = 1000000000 / 5; //5th of a second for double click.
|
||||
|
||||
private static int NO_STATE = -1;
|
||||
|
||||
protected static GLFWKeyCallback keyboard = new GLFWKeyCallback()
|
||||
{
|
||||
@Override
|
||||
public void invoke(long window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
activeKeys[key] = action != GLFW_RELEASE;
|
||||
keyStates[key] = action;
|
||||
}
|
||||
};
|
||||
|
||||
protected static GLFWMouseButtonCallback mouse = new GLFWMouseButtonCallback()
|
||||
{
|
||||
@Override
|
||||
public void invoke(long window, int button, int action, int mods)
|
||||
{
|
||||
activeMouseButtons[button] = action != GLFW_RELEASE;
|
||||
mouseButtonStates[button] = action;
|
||||
}
|
||||
};
|
||||
|
||||
protected static void init(long window)
|
||||
{
|
||||
InputHandler.window = window;
|
||||
resetKeyboard();
|
||||
resetMouse();
|
||||
}
|
||||
|
||||
protected static void update()
|
||||
{
|
||||
resetKeyboard();
|
||||
resetMouse();
|
||||
}
|
||||
|
||||
private static void resetKeyboard()
|
||||
{
|
||||
for (int i = 0; i < keyStates.length; i++)
|
||||
{
|
||||
keyStates[i] = NO_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
private static void resetMouse()
|
||||
{
|
||||
for (int i = 0; i < mouseButtonStates.length; i++)
|
||||
{
|
||||
mouseButtonStates[i] = NO_STATE;
|
||||
}
|
||||
|
||||
long now = System.nanoTime();
|
||||
|
||||
if (now - lastMouseNS > mouseDoubleClickPeriodNS)
|
||||
lastMouseNS = 0;
|
||||
}
|
||||
|
||||
public static boolean keyDown(int key)
|
||||
{
|
||||
return activeKeys[key];
|
||||
}
|
||||
|
||||
public static boolean keyPressed(int key)
|
||||
{
|
||||
return keyStates[key] == GLFW_PRESS;
|
||||
}
|
||||
|
||||
public static boolean keyReleased(int key)
|
||||
{
|
||||
return keyStates[key] == GLFW_RELEASE;
|
||||
}
|
||||
|
||||
public static boolean mouseButtonDown(int button)
|
||||
{
|
||||
return activeMouseButtons[button];
|
||||
}
|
||||
|
||||
public static boolean mouseButtonPressed(int button)
|
||||
{
|
||||
return mouseButtonStates[button] == GLFW_RELEASE;
|
||||
}
|
||||
|
||||
public static boolean mouseButtonReleased(int button)
|
||||
{
|
||||
boolean flag = mouseButtonStates[button] == GLFW_RELEASE;
|
||||
|
||||
if (flag)
|
||||
lastMouseNS = System.nanoTime();
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
public static boolean mouseButtonDoubleClicked(int button)
|
||||
{
|
||||
long last = lastMouseNS;
|
||||
boolean flag = mouseButtonReleased(button);
|
||||
|
||||
long now = System.nanoTime();
|
||||
|
||||
if (flag && now - last < mouseDoubleClickPeriodNS)
|
||||
{
|
||||
lastMouseNS = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
import imgui.DrawData;
|
||||
import imgui.ImGui;
|
||||
import imgui.gl3.ImGuiImplGl3;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.Version;
|
||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
import org.lwjgl.glfw.GLFWVidMode;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks;
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.system.MemoryStack.stackPush;
|
||||
import static org.lwjgl.system.MemoryUtil.NULL;
|
||||
|
||||
public class Main {
|
||||
// The window handle
|
||||
private long window;
|
||||
private ImGuiImplGl3 imGuiGl = new ImGuiImplGl3();
|
||||
|
||||
public void run() {
|
||||
System.out.println("Hello LWJGL " + Version.getVersion() + "!");
|
||||
|
||||
init();
|
||||
loop();
|
||||
|
||||
// Free the window callbacks and destroy the window
|
||||
glfwFreeCallbacks(window);
|
||||
glfwDestroyWindow(window);
|
||||
|
||||
// Terminate GLFW and free the error callback
|
||||
glfwTerminate();
|
||||
glfwSetErrorCallback(null).free();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
// Setup an error callback. The default implementation
|
||||
// will print the error message in System.err.
|
||||
GLFWErrorCallback.createPrint(System.err).set();
|
||||
|
||||
// Initialize GLFW. Most GLFW functions will not work before doing this.
|
||||
if (!glfwInit())
|
||||
throw new IllegalStateException("Unable to initialize GLFW");
|
||||
|
||||
// Configure GLFW
|
||||
glfwDefaultWindowHints(); // optional, the current window hints are already the default
|
||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable
|
||||
|
||||
// Create the window
|
||||
window = glfwCreateWindow(1024, 768, "Hello World!", NULL, NULL);
|
||||
if (window == NULL)
|
||||
throw new RuntimeException("Failed to create the GLFW window");
|
||||
|
||||
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
|
||||
glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
|
||||
glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
|
||||
});
|
||||
|
||||
glfwSetMouseButtonCallback(window, InputHandler.mouse);
|
||||
|
||||
// Get the thread stack and push a new frame
|
||||
try (MemoryStack stack = stackPush()) {
|
||||
IntBuffer pWidth = stack.mallocInt(1); // int*
|
||||
IntBuffer pHeight = stack.mallocInt(1); // int*
|
||||
|
||||
// Get the window size passed to glfwCreateWindow
|
||||
glfwGetWindowSize(window, pWidth, pHeight);
|
||||
|
||||
// Get the resolution of the primary monitor
|
||||
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
|
||||
// Center the window
|
||||
glfwSetWindowPos(
|
||||
window,
|
||||
(vidmode.width() - pWidth.get(0)) / 2,
|
||||
(vidmode.height() - pHeight.get(0)) / 2
|
||||
);
|
||||
} // the stack frame is popped automatically
|
||||
|
||||
// Make the OpenGL context current
|
||||
glfwMakeContextCurrent(window);
|
||||
// Enable v-sync
|
||||
glfwSwapInterval(1);
|
||||
InputHandler.init(window);
|
||||
// Make the window visible
|
||||
glfwShowWindow(window);
|
||||
}
|
||||
|
||||
long lastFrame = System.nanoTime();
|
||||
|
||||
public float getDelta() {
|
||||
long time = System.nanoTime();
|
||||
int delta_time = (int) ((time - lastFrame) / 1000000);
|
||||
lastFrame = time;
|
||||
return delta_time;
|
||||
}
|
||||
|
||||
private void loop() {
|
||||
// This line is critical for LWJGL's interoperation with GLFW's
|
||||
// OpenGL context, or any context that is managed externally.
|
||||
// LWJGL detects the context that is current in the current thread,
|
||||
// creates the GLCapabilities instance and makes the OpenGL
|
||||
// bindings available for use.
|
||||
GL.createCapabilities();
|
||||
|
||||
ImGui.init();
|
||||
imGuiGl.init();
|
||||
|
||||
// Set the clear color
|
||||
glClearColor(.5f, 0.0f, 0f, 0.0f);
|
||||
|
||||
int[] win_width = new int[1], win_height = new int[1];
|
||||
int[] width = new int[1], height = new int[1];
|
||||
DoubleBuffer xBuffer = BufferUtils.createDoubleBuffer(1);
|
||||
DoubleBuffer yBuffer = BufferUtils.createDoubleBuffer(1);
|
||||
|
||||
// Run the rendering loop until the user has attempted to close
|
||||
// the window or has pressed the ESCAPE key.
|
||||
while (!glfwWindowShouldClose(window)) {
|
||||
xBuffer.clear();
|
||||
yBuffer.clear();
|
||||
|
||||
InputHandler.update();
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
|
||||
|
||||
glfwGetWindowSize(window, win_width, win_height);
|
||||
glfwGetFramebufferSize(window, width, height);
|
||||
glfwGetCursorPos(window, xBuffer, yBuffer);
|
||||
|
||||
int mX = (int) xBuffer.get();
|
||||
int mY = (int) yBuffer.get();
|
||||
|
||||
ImGui.UpdateDisplayAndInputAndFrame(getDelta(), win_width[0], win_height[0], width[0], height[0], mX, mY, InputHandler.mouseButtonDown(0), false, false);
|
||||
ImGui.ShowDemoWindow();
|
||||
ImGui.Render();
|
||||
imGuiGl.render(ImGui.GetDrawData());
|
||||
|
||||
glfwSwapBuffers(window); // swap the color buffers
|
||||
|
||||
// Poll for window events. The key callback above will only be
|
||||
// invoked during this call.
|
||||
glfwPollEvents();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Main().run();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
package imgui.gl3;
|
||||
|
||||
import imgui.DrawData;
|
||||
import imgui.ImGui;
|
||||
import imgui.TexDataRGBA32;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.lwjgl.opengl.GL30.*;
|
||||
|
||||
/**
|
||||
* This class mostly a straightforward port of the https://raw.githubusercontent.com/ocornut/imgui/v1.74/examples/imgui_impl_opengl3.cpp adapted to Java and LWJGL realms.
|
||||
* <p>
|
||||
* It do support a backup of the current GL state before rendering and restoring of its initial state after.
|
||||
* But some specific state variables may be missed (all which are hidden under '#ifdef' macros in the original imgui file).
|
||||
* <p>
|
||||
* By default this implementation uses shaders with 130 version of GLSL (OpenGL 3.0).
|
||||
* You can provide your own shaders into the {@link ImGuiImplGl3#init(CharSequence, CharSequence)} method.
|
||||
*/
|
||||
public class ImGuiImplGl3 {
|
||||
private int vBufferHandle = 0;
|
||||
private int iBufferHandle = 0;
|
||||
|
||||
private boolean isFontInitialized = false;
|
||||
|
||||
// Shader stuff
|
||||
private int programId = 0;
|
||||
private int fragmentShaderId = 0;
|
||||
private int vertexShaderId = 0;
|
||||
|
||||
// Texture used by fonts
|
||||
private int gFontTexture = 0;
|
||||
|
||||
// Projection matrix for ImGui
|
||||
private final float[] projMatrix = new float[4 * 4];
|
||||
|
||||
// Variables used to backup GL state before and after rendering of ImGui
|
||||
private final int[] lastActiveTexture = new int[1];
|
||||
private final int[] lastProgram = new int[1];
|
||||
private final int[] lastTexture = new int[1];
|
||||
private final int[] lastArrayBuffer = new int[1];
|
||||
private final int[] lastViewport = new int[4];
|
||||
private final int[] lastScissorBox = new int[4];
|
||||
private final int[] lastBlendSrcRgb = new int[1];
|
||||
private final int[] lastBlendDstRgb = new int[1];
|
||||
private final int[] lastBlendSrcAlpha = new int[1];
|
||||
private final int[] lastBlendDstAlpha = new int[1];
|
||||
private final int[] lastBlendEquationRgb = new int[1];
|
||||
private final int[] lastBlendEquationAlpha = new int[1];
|
||||
private boolean lastEnableBlend = false;
|
||||
private boolean lastEnableCullFace = false;
|
||||
private boolean lastEnableDepthTest = false;
|
||||
private boolean lastEnableScissorTest = false;
|
||||
|
||||
/**
|
||||
* This method SHOULD be called before calling of {@link ImGuiImplGl3#render(DrawData)} method.
|
||||
* By using this method shaders with 130 version of GLSL will be used for render.
|
||||
*/
|
||||
public void init() {
|
||||
final CharSequence fragShaderSource = readFromResources("default.frag");
|
||||
final CharSequence vertShaderSource = readFromResources("default.vert");
|
||||
prepareShader(fragShaderSource, vertShaderSource);
|
||||
prepareFont();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method SHOULD be called before calling of {@link ImGuiImplGl3#render(DrawData)} method.
|
||||
*
|
||||
* @param fragShaderSource fragment shader to use for render
|
||||
* @param vertShaderSource vertex shader to use for render
|
||||
*/
|
||||
public void init(final CharSequence fragShaderSource, final CharSequence vertShaderSource) {
|
||||
prepareShader(fragShaderSource, vertShaderSource);
|
||||
prepareFont();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method which renders {@link DrawData} from ImGui.
|
||||
*
|
||||
* @param drawData data used to draw ImGui interface to your current OpenGL context
|
||||
*/
|
||||
public void render(final DrawData drawData) {
|
||||
if (drawData.cmdListsCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fbWidth = (int) (drawData.displaySizeX * drawData.framebufferScaleX);
|
||||
int fbHeight = (int) (drawData.displaySizeY * drawData.framebufferScaleY);
|
||||
|
||||
if (fbWidth <= 0 || fbHeight <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isFontInitialized) {
|
||||
isFontInitialized = true;
|
||||
vBufferHandle = glGenBuffers();
|
||||
iBufferHandle = glGenBuffers();
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iBufferHandle);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, drawData.iByteBuffer.capacity(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
backupGlState();
|
||||
bind(drawData);
|
||||
|
||||
int verticesOffset = 0;
|
||||
int indexOffset = 0;
|
||||
|
||||
for (int i = 0; i < drawData.cmdListsCount; i++) {
|
||||
drawData.vByteBuffer.limit(verticesOffset + 4);
|
||||
final int verticesSize = (int) drawData.vByteBuffer.getFloat(verticesOffset);
|
||||
|
||||
drawData.iByteBuffer.limit(indexOffset + 2);
|
||||
final short indexSize = drawData.iByteBuffer.getShort(indexOffset);
|
||||
final int cmdSize = (int) drawData.cmdByteBuffer.getFloat();
|
||||
|
||||
final int verticesStartOffset = verticesOffset + 4;
|
||||
final int indexStartOffset = indexOffset + 2;
|
||||
|
||||
drawData.vByteBuffer.position(verticesStartOffset);
|
||||
drawData.iByteBuffer.position(indexStartOffset);
|
||||
|
||||
final int newVlimit = verticesStartOffset + verticesSize * DrawData.vBufferSize;
|
||||
final int newIlimit = indexStartOffset + indexSize * DrawData.iBufferSize;
|
||||
|
||||
drawData.vByteBuffer.limit(newVlimit);
|
||||
drawData.iByteBuffer.limit(newIlimit);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, drawData.vByteBuffer, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, drawData.iByteBuffer, GL_STATIC_DRAW);
|
||||
|
||||
verticesOffset += ((verticesSize) * DrawData.vBufferSize) + 4;
|
||||
indexOffset += ((indexSize) * DrawData.iBufferSize) + 2;
|
||||
|
||||
final float clipOffX = drawData.displayPosX; // (0,0) unless using multi-viewports
|
||||
final float clipOffY = drawData.displayPosY;
|
||||
final float clipScaleX = drawData.framebufferScaleX; // (1,1) unless using retina display which are often (2,2)
|
||||
final float clipScaleY = drawData.framebufferScaleY;
|
||||
|
||||
int idxBufferOffset = 0;
|
||||
|
||||
for (int j = 0; j < cmdSize; j++) {
|
||||
final int elemCount = (int) drawData.cmdByteBuffer.getFloat();
|
||||
float clipRectX = drawData.cmdByteBuffer.getFloat();
|
||||
float clipRectY = drawData.cmdByteBuffer.getFloat();
|
||||
float clipRectZ = drawData.cmdByteBuffer.getFloat();
|
||||
float clipRectW = drawData.cmdByteBuffer.getFloat();
|
||||
final int textureID = (int) drawData.cmdByteBuffer.getFloat();
|
||||
|
||||
clipRectX = (clipRectX - clipOffX) * clipScaleX;
|
||||
clipRectY = (clipRectY - clipOffY) * clipScaleY;
|
||||
clipRectZ = (clipRectZ - clipOffX) * clipScaleX;
|
||||
clipRectW = (clipRectW - clipOffY) * clipScaleY;
|
||||
|
||||
if (clipRectX < fbWidth && clipRectY < fbHeight && clipRectZ >= 0.0f && clipRectW >= 0.0f) {
|
||||
glScissor((int) clipRectX, (int) (fbHeight - clipRectW), (int) (clipRectZ - clipRectX), (int) (clipRectW - clipRectY));
|
||||
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||
glDrawElements(GL_TRIANGLES, elemCount, GL_UNSIGNED_SHORT, idxBufferOffset);
|
||||
}
|
||||
|
||||
idxBufferOffset += elemCount * 2;
|
||||
}
|
||||
}
|
||||
|
||||
unbind();
|
||||
restoreModifiedGlState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method in the end of your app working state to clear used resources.
|
||||
*/
|
||||
public void dispose() {
|
||||
glDeleteTextures(gFontTexture);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glDeleteBuffers(iBufferHandle);
|
||||
glDeleteBuffers(vBufferHandle);
|
||||
glDetachShader(programId, vertexShaderId);
|
||||
glDetachShader(programId, fragmentShaderId);
|
||||
glDeleteProgram(programId);
|
||||
}
|
||||
|
||||
private void prepareShader(final CharSequence fragShaderSource, final CharSequence vertShaderSource) {
|
||||
fragmentShaderId = loadAndCompileShader(GL_FRAGMENT_SHADER, fragShaderSource);
|
||||
vertexShaderId = loadAndCompileShader(GL_VERTEX_SHADER, vertShaderSource);
|
||||
|
||||
programId = glCreateProgram();
|
||||
glAttachShader(programId, fragmentShaderId);
|
||||
glAttachShader(programId, vertexShaderId);
|
||||
glLinkProgram(programId);
|
||||
|
||||
if (glGetProgrami(programId, GL_LINK_STATUS) != GL_TRUE) {
|
||||
throw new IllegalStateException(glGetProgramInfoLog(programId));
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareFont() {
|
||||
TexDataRGBA32 texData = new TexDataRGBA32();
|
||||
ImGui.GetTexDataAsRGBA32(texData, texData.pixelBuffer);
|
||||
|
||||
gFontTexture = glGenTextures();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, gFontTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texData.width, texData.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData.pixelBuffer);
|
||||
|
||||
ImGui.SetFontTexID(gFontTexture);
|
||||
}
|
||||
|
||||
private void backupGlState() {
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, lastActiveTexture);
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, lastProgram);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, lastTexture);
|
||||
// int[] last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler); // do it by yourself if needed
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, lastArrayBuffer);
|
||||
// int[] last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object); // do it by yourself if needed
|
||||
// int[] last_polygon_mode; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); // do it by yourself if needed
|
||||
glGetIntegerv(GL_VIEWPORT, lastViewport);
|
||||
glGetIntegerv(GL_SCISSOR_BOX, lastScissorBox);
|
||||
glGetIntegerv(GL_BLEND_SRC_RGB, lastBlendSrcRgb);
|
||||
glGetIntegerv(GL_BLEND_DST_RGB, lastBlendDstRgb);
|
||||
glGetIntegerv(GL_BLEND_SRC_ALPHA, lastBlendSrcAlpha);
|
||||
glGetIntegerv(GL_BLEND_DST_ALPHA, lastBlendDstAlpha);
|
||||
glGetIntegerv(GL_BLEND_EQUATION_RGB, lastBlendEquationRgb);
|
||||
glGetIntegerv(GL_BLEND_EQUATION_ALPHA, lastBlendEquationAlpha);
|
||||
lastEnableBlend = glIsEnabled(GL_BLEND);
|
||||
lastEnableCullFace = glIsEnabled(GL_CULL_FACE);
|
||||
lastEnableDepthTest = glIsEnabled(GL_DEPTH_TEST);
|
||||
lastEnableScissorTest = glIsEnabled(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
private void restoreModifiedGlState() {
|
||||
glUseProgram(lastProgram[0]);
|
||||
glBindTexture(GL_TEXTURE_2D, lastTexture[0]);
|
||||
glActiveTexture(lastActiveTexture[0]);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, lastArrayBuffer[0]);
|
||||
glBlendEquationSeparate(lastBlendEquationRgb[0], lastBlendEquationAlpha[0]);
|
||||
glBlendFuncSeparate(lastBlendSrcRgb[0], lastBlendDstRgb[0], lastBlendSrcAlpha[0], lastBlendDstAlpha[0]);
|
||||
// @formatter:off
|
||||
if (lastEnableBlend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||
if (lastEnableCullFace) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||
if (lastEnableDepthTest) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||
if (lastEnableScissorTest) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||
// @formatter:on
|
||||
glViewport(lastViewport[0], lastViewport[1], lastViewport[2], lastViewport[3]);
|
||||
glScissor(lastScissorBox[0], lastScissorBox[1], lastScissorBox[2], lastScissorBox[3]);
|
||||
}
|
||||
|
||||
private void bind(final DrawData drawData) {
|
||||
glViewport(0, 0, (int) drawData.displaySizeX, (int) drawData.displaySizeY);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
final float L = drawData.displayPosX;
|
||||
final float R = drawData.displayPosX + drawData.displaySizeX;
|
||||
final float T = drawData.displayPosY;
|
||||
final float B = drawData.displayPosY + drawData.displaySizeY;
|
||||
|
||||
// Orthographic matrix projection
|
||||
projMatrix[0] = 2.0f / (R - L);
|
||||
projMatrix[5] = 2.0f / (T - B);
|
||||
projMatrix[10] = -1.0f;
|
||||
projMatrix[12] = (R + L) / (L - R);
|
||||
projMatrix[13] = (T + B) / (B - T);
|
||||
projMatrix[15] = 1.0f;
|
||||
|
||||
// Bind vertices
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vBufferHandle);
|
||||
|
||||
int location = glGetAttribLocation(programId, "Position");
|
||||
glEnableVertexAttribArray(location);
|
||||
glVertexAttribPointer(location, 2, GL_FLOAT, false, 20, 0);
|
||||
|
||||
location = glGetAttribLocation(programId, "UV");
|
||||
glEnableVertexAttribArray(location);
|
||||
glVertexAttribPointer(location, 2, GL_FLOAT, false, 20, 8);
|
||||
|
||||
location = glGetAttribLocation(programId, "Color");
|
||||
glEnableVertexAttribArray(location);
|
||||
glVertexAttribPointer(location, 4, GL_UNSIGNED_BYTE, true, 20, 16);
|
||||
|
||||
//Bind index
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iBufferHandle);
|
||||
|
||||
// Bind shader
|
||||
glUseProgram(programId);
|
||||
glUniformMatrix4fv(glGetUniformLocation(programId, "ProjMtx"), false, projMatrix);
|
||||
glUniform1i(glGetUniformLocation(programId, "Texture"), 0);
|
||||
}
|
||||
|
||||
private void unbind() {
|
||||
// Unbind vertices
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glDisableVertexAttribArray(glGetAttribLocation(programId, "Position"));
|
||||
glDisableVertexAttribArray(glGetAttribLocation(programId, "UV"));
|
||||
glDisableVertexAttribArray(glGetAttribLocation(programId, "Color"));
|
||||
|
||||
// Unbind index
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glFlush();
|
||||
|
||||
// Unbind shader
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
private int loadAndCompileShader(final int type, final CharSequence source) {
|
||||
int id = glCreateShader(type);
|
||||
glShaderSource(id, source);
|
||||
glCompileShader(id);
|
||||
if (glGetShaderi(id, GL_COMPILE_STATUS) != GL_TRUE) {
|
||||
throw new IllegalStateException(glGetShaderInfoLog(id));
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
private CharSequence readFromResources(final String path) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
try (InputStream in = getClass().getClassLoader().getResourceAsStream(path);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(in)))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
builder.append(line).append('\n');
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException("Failed to read from resources!", ex);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user