Created
January 21, 2015 10:49
-
-
Save anonymous/35f9a540a82ad369e4e3 to your computer and use it in GitHub Desktop.
Use LWJGL to render a scende into a PNG without showing windows
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MAJOR; | |
| import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MINOR; | |
| import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_CORE_PROFILE; | |
| import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_FORWARD_COMPAT; | |
| import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_PROFILE; | |
| import static org.lwjgl.glfw.GLFW.GLFW_SAMPLES; | |
| import static org.lwjgl.glfw.GLFW.GLFW_VISIBLE; | |
| import static org.lwjgl.glfw.GLFW.glfwCreateWindow; | |
| import static org.lwjgl.glfw.GLFW.glfwDestroyWindow; | |
| import static org.lwjgl.glfw.GLFW.glfwInit; | |
| import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent; | |
| import static org.lwjgl.glfw.GLFW.glfwTerminate; | |
| import static org.lwjgl.glfw.GLFW.glfwWindowHint; | |
| import static org.lwjgl.opengl.EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT; | |
| import static org.lwjgl.opengl.EXTFramebufferObject.GL_FRAMEBUFFER_EXT; | |
| import static org.lwjgl.opengl.EXTFramebufferObject.glBindFramebufferEXT; | |
| import static org.lwjgl.opengl.EXTFramebufferObject.glFramebufferTexture2DEXT; | |
| import static org.lwjgl.opengl.EXTFramebufferObject.glGenFramebuffersEXT; | |
| import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; | |
| import static org.lwjgl.opengl.GL11.GL_FALSE; | |
| import static org.lwjgl.opengl.GL11.GL_FLOAT; | |
| import static org.lwjgl.opengl.GL11.GL_INT; | |
| import static org.lwjgl.opengl.GL11.GL_LINEAR; | |
| import static org.lwjgl.opengl.GL11.GL_RGBA; | |
| import static org.lwjgl.opengl.GL11.GL_RGBA8; | |
| import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; | |
| import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER; | |
| import static org.lwjgl.opengl.GL11.GL_TRIANGLES; | |
| import static org.lwjgl.opengl.GL11.GL_TRUE; | |
| import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE; | |
| import static org.lwjgl.opengl.GL11.glBindTexture; | |
| import static org.lwjgl.opengl.GL11.glClear; | |
| import static org.lwjgl.opengl.GL11.glDrawArrays; | |
| import static org.lwjgl.opengl.GL11.glGenTextures; | |
| import static org.lwjgl.opengl.GL11.glGetTexImage; | |
| import static org.lwjgl.opengl.GL11.glTexImage2D; | |
| import static org.lwjgl.opengl.GL11.glTexParameterf; | |
| import static org.lwjgl.opengl.GL11.glViewport; | |
| import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER; | |
| import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW; | |
| import static org.lwjgl.opengl.GL15.glBindBuffer; | |
| import static org.lwjgl.opengl.GL15.glBufferData; | |
| import static org.lwjgl.opengl.GL15.glDeleteBuffers; | |
| import static org.lwjgl.opengl.GL15.glGenBuffers; | |
| import static org.lwjgl.opengl.GL20.glDisableVertexAttribArray; | |
| import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray; | |
| import static org.lwjgl.opengl.GL20.glVertexAttribPointer; | |
| import static org.lwjgl.opengl.GL30.glBindVertexArray; | |
| import static org.lwjgl.opengl.GL30.glDeleteVertexArrays; | |
| import static org.lwjgl.opengl.GL30.glGenVertexArrays; | |
| import static org.lwjgl.system.MemoryUtil.NULL; | |
| import java.awt.image.BufferedImage; | |
| import java.io.File; | |
| import java.io.IOException; | |
| import java.nio.ByteBuffer; | |
| import java.nio.ByteOrder; | |
| import java.nio.FloatBuffer; | |
| import javax.imageio.ImageIO; | |
| import org.lwjgl.BufferUtils; | |
| import org.lwjgl.opengl.GLContext; | |
| public class RenderToPng | |
| { | |
| private int vaoID; | |
| private int vboID; | |
| int screenTextureID; | |
| int framebufferID; | |
| private long windowID; | |
| private void initFramebuffer() { | |
| framebufferID = glGenFramebuffersEXT(); // create a new framebuffer | |
| screenTextureID = glGenTextures(); // and a new texture used as a color buffer | |
| glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferID); // switch to the new framebuffer | |
| // initialize color texture | |
| glBindTexture(GL_TEXTURE_2D, screenTextureID); // Bind the colorbuffer texture | |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // make it linear filterd | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 512, 0,GL_RGBA, GL_INT, (java.nio.ByteBuffer) null); // Create the texture data | |
| glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D, screenTextureID, 0); // attach it to the framebuffer | |
| glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Swithch back to normal framebuffer rendering | |
| } | |
| private void initWindow() { | |
| // Window Hints for OpenGL context | |
| glfwWindowHint(GLFW_SAMPLES, 4); | |
| glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); | |
| glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); | |
| glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); | |
| glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |
| glfwWindowHint(GLFW_VISIBLE, GL_FALSE); | |
| windowID = glfwCreateWindow(512, 512, "Invisible", NULL, NULL); | |
| if (windowID == NULL) | |
| { | |
| System.err.println("Error creating a window"); | |
| System.exit(1); | |
| } | |
| glfwMakeContextCurrent(windowID); | |
| GLContext.createFromCurrent(); | |
| } | |
| private void initGeometry() | |
| { | |
| // Generate and bind a Vertex Array | |
| vaoID = glGenVertexArrays(); | |
| glBindVertexArray(vaoID); | |
| // The vertices of our Triangle | |
| float[] vertices = new float[] | |
| { | |
| +0.0f, +0.8f, // Top coordinate | |
| -0.8f, -0.8f, // Bottom-left coordinate | |
| +0.8f, -0.8f // Bottom-right coordinate | |
| }; | |
| // Create a FloatBuffer of vertices | |
| FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(vertices.length); | |
| verticesBuffer.put(vertices).flip(); | |
| // Create a Buffer Object and upload the vertices buffer | |
| vboID = glGenBuffers(); | |
| glBindBuffer(GL_ARRAY_BUFFER, vboID); | |
| glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW); | |
| glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0); | |
| glBindVertexArray(0); | |
| } | |
| public void renderToTexture() { | |
| glViewport (0, 0, 512, 512); // set The Current Viewport to the fbo size | |
| glBindTexture(GL_TEXTURE_2D, 0); // unlink textures because if we dont it all is gonna fail | |
| glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebufferID); // switch to rendering on our FBO | |
| renderAsNormal(); | |
| ByteBuffer buffer = extractRawTextureData(); | |
| encodePng(buffer); | |
| } | |
| private void encodePng(ByteBuffer buffer) | |
| { | |
| BufferedImage image = new BufferedImage(512, 512, BufferedImage.TYPE_INT_RGB); | |
| // possibly there's a faster method? | |
| for(int x = 0; x < 512; x++) | |
| { | |
| for(int y = 0; y < 512; y++) | |
| { | |
| int i = (x + (512 * y)) * 4; | |
| int r = buffer.get(i) & 0xFF; | |
| int g = buffer.get(i + 1) & 0xFF; | |
| int b = buffer.get(i + 2) & 0xFF; | |
| image.setRGB(x, 512 - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b); | |
| } | |
| } | |
| try { | |
| ImageIO.write(image, "PNG", new File("out.png")); | |
| } catch (IOException e) { e.printStackTrace(); } | |
| } | |
| private ByteBuffer extractRawTextureData() { | |
| ByteBuffer buffer = ByteBuffer.allocateDirect(512 * 512 * 4).order(ByteOrder.nativeOrder()); | |
| glBindTexture(GL_TEXTURE_2D, screenTextureID); | |
| glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); | |
| return buffer; | |
| } | |
| public void renderAsNormal() | |
| { | |
| // Clear the screen | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| // Bind the vertex array and enable our location | |
| glBindVertexArray(vaoID); | |
| glEnableVertexAttribArray(0); | |
| // Draw a triangle of 3 vertices | |
| glDrawArrays(GL_TRIANGLES, 0, 3); | |
| // Disable our location | |
| glDisableVertexAttribArray(0); | |
| glBindVertexArray(0); | |
| } | |
| public void disposeAll() | |
| { | |
| // Dispose the vertex array | |
| glBindVertexArray(0); | |
| glDeleteVertexArrays(vaoID); | |
| // Dispose the buffer object | |
| glBindBuffer(GL_ARRAY_BUFFER, 0); | |
| glDeleteBuffers(vboID); | |
| // Destroy the window | |
| glfwDestroyWindow(windowID); | |
| glfwTerminate(); | |
| } | |
| public void run() | |
| { | |
| if (glfwInit() != GL_TRUE) | |
| { | |
| System.err.println("Error initializing GLFW"); | |
| System.exit(1); | |
| } | |
| initWindow(); | |
| initGeometry(); | |
| initFramebuffer(); | |
| renderToTexture(); | |
| disposeAll(); | |
| } | |
| public static void main(String[] args) | |
| { | |
| new RenderToPng().run(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment