Hello,
I'm trying to write an example for rendering to texture with LWJGL 3.0.0. However, I do not manage to get it to work. That's the code:
package de.thoffbauer.cameraexample;
import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL32.*;
import static org.lwjgl.system.MemoryUtil.NULL;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import javax.imageio.ImageIO;
import org.lwjgl.BufferUtils;
import org.lwjgl.Version;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;
public class CameraExample {
// The window handle
private long window;
private int triangleVao;
private int triangleVbo;
private int framebuffer;
private int renderedTexture;
private int screenVao;
private int screenVbo;
private int program;
private int vertexShader;
private int fragmentShader;
public void run() {
System.out.println("Hello LWJGL " + Version.getVersion() + "!");
try {
init();
loop();
// Free the window callbacks and destroy the window
glfwFreeCallbacks(window);
glfwDestroyWindow(window);
} finally {
// 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 our window
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
int WIDTH = 800;
int HEIGHT = 600;
// Create the window
window = glfwCreateWindow(WIDTH, HEIGHT, "Camera Example", 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 our rendering loop
});
// Get the resolution of the primary monitor
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center our window
glfwSetWindowPos(
window,
(vidmode.width() - WIDTH) / 2,
(vidmode.height() - HEIGHT) / 2
);
// Make the OpenGL context current
glfwMakeContextCurrent(window);
// Enable v-sync
glfwSwapInterval(1);
// Make the window visible
glfwShowWindow(window);
// 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();
// Set the clear color
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
program = glCreateProgram();
attachVertexShader("quadtextured.vs");
attachFragmentShader("quadtextured.fs");
glBindAttribLocation(program, 0, "in_Position");
glBindAttribLocation(program, 1, "in_TextureCoord");
linkProgram();
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
initCamera();
initScreen();
initTriangle();
}
private void loop() {
// Run the rendering loop until the user has attempted to close
// the window or has pressed the ESCAPE key.
int i = 0;
while ( !glfwWindowShouldClose(window) ) {
renderToCamera();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
glUseProgram(program);
renderTriangle();
renderScreen();
// if(i == 100) {
// try {
// saveCamera("framebuffer.png");
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
glUseProgram(0);
glfwSwapBuffers(window); // swap the color buffers
// Poll for window events. The key callback above will only be
// invoked during this call.
glfwPollEvents();
i++;
}
}
private void initTriangle() {
triangleVao = glGenVertexArrays();
glBindVertexArray(triangleVao);
float[] vertices = new float[] {
0, 0.8f, 0,
-0.8f, -0.8f, 0,
0.8f, -0.8f, 0
};
FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(vertices.length);
verticesBuffer.put(vertices).flip();
triangleVbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, triangleVbo);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glBindVertexArray(0);
}
private void renderTriangle() {
glBindVertexArray(triangleVao);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glBindVertexArray(0);
}
private void initCamera() {
framebuffer = glGenFramebuffers();
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
renderedTexture = glGenTextures();
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
int depthRenderBuffer = glGenRenderbuffers();
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 800, 600);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderBuffer);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);
glDrawBuffers(GL_COLOR_ATTACHMENT0);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
System.err.println("Framebuffer not complete!");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
private void renderToCamera() {
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glViewport(0, 0, 800, 600);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
private void initScreen() {
screenVao = glGenVertexArrays();
glBindVertexArray(screenVao);
float[] vertices = new float[] {
// Vertices
-1, -1, 0,
0, -1, 0,
-1, 0, 0,
-1, 0, 0,
0, -1, 0,
0, 0, 0
// UV
-1, -1,
1, -1,
-1, 1,
-1, 1,
1, -1,
1, 1
};
FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(vertices.length);
verticesBuffer.put(vertices).flip();
screenVbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, screenVbo);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, vertices.length, GL_FLOAT, false, 0, 0);
glVertexAttribPointer(1, vertices.length, GL_FLOAT, false, 0, 3 * 6);
glBindBuffer(GL_VERTEX_ARRAY, 0);
}
private void renderScreen() {
// glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glBindVertexArray(screenVao);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
private void saveCamera(String name) throws IOException {
glBindTexture(GL_TEXTURE_2D, renderedTexture);
ByteBuffer buffer = ByteBuffer.allocate(800 * 600 * 3);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
BufferedImage image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);
int width = 800;
int height = 600;
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
int i = (x + (width * y)) * 3;
int r = buffer.get(i) & 0xFF;
int g = buffer.get(i + 1) & 0xFF;
int b = buffer.get(i + 2) & 0xFF;
image.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b);
}
}
ImageIO.write(image, "PNG", new File(name));
}
private String readShader(String name) {
StringBuilder source = new StringBuilder();
try
{
BufferedReader reader = new BufferedReader(new FileReader("shaders/" + name));
String line;
while ((line = reader.readLine()) != null)
{
source.append(line).append("\n");
}
reader.close();
}
catch (Exception e)
{
System.err.println("Error loading source code: " + name);
e.printStackTrace();
}
return source.toString();
}
private void attachVertexShader(String name) {
String source = readShader(name);
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, source);
glCompileShader(vertexShader);
if(glGetShaderi(vertexShader, GL_COMPILE_STATUS) == GL_FALSE)
System.err.println("Error creating vertexShader\n" + glGetShaderInfoLog(vertexShader));
glAttachShader(program, vertexShader);
}
private void attachFragmentShader(String name) {
String source = readShader(name);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, source);
glCompileShader(fragmentShader);
if(glGetShaderi(fragmentShader, GL_COMPILE_STATUS) == GL_FALSE)
System.err.println("Error creating fragmentShader\n" + glGetShaderInfoLog(fragmentShader));
glAttachShader(program, fragmentShader);
}
private void linkProgram() {
glLinkProgram(program);
if(glGetProgrami(program, GL_LINK_STATUS) == GL_FALSE) {
System.err.println("Unable to link shader program");
System.err.println(glGetProgramInfoLog(program));
}
}
public static void main(String[] args) {
new CameraExample().run();
}
}
The shaders (first vertex, then fragment):
#version 150 core
in vec4 in_Position;
in vec2 in_TextureCoord;
out vec2 pass_TextureCoord;
void main(void) {
gl_Position = in_Position;
pass_TextureCoord = in_TextureCoord;
}
#version 150 core
uniform sampler2D texture_diffuse;
in vec2 pass_TextureCoord;
out vec4 out_Color;
void main(void) {
out_Color = texture(texture_diffuse, pass_TextureCoord);
}
And the output:
WARNING in native method: JNI call made without checking exceptions when required to from CallStaticObjectMethod
Hello LWJGL 3.0.0 build 90!
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x0000000041030f41, pid=7622, tid=139991872743168
#
# JRE version: Java(TM) SE Runtime Environment (8.0_77-b03) (build 1.8.0_77-b03)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.77-b03 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C 0x0000000041030f41
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /eclipseworkspace/CameraExample/hs_err_pid7622.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
If you need this hs_err_pid I can publish it, but I does not seem to be human-readable. (Btw, I'm really disappointed of those informative error descriptions...)
With the help of the eclipse debugger I was able to find out that the JRE exception arises at glDrawArrays in renderScreen(), that's line 273.
I'm using an Nvidia GTX 960 with Linux x64 (Fedora). I have the propietary drivers installed.
Thank you in advance for any help,
Turakar
Please look at the documentation of glVertexAttribPointer: https://www.opengl.org/sdk/docs/man/html/glVertexAttribPointer.xhtml
You supply invalid values for three of its parameters (size, stride and pointer) in the calls at line 260-261.
Thank you for that hint. I also made some other changes to get it to work:
- unbind with glVertexArray() in initScreen
- set the texture to CLAMP_TO_BORDER
- different glClearColors to see the difference better
- set last parameter to 6 in glDrawArrays in renderScreen (prior rendered just one triangle)
The full code now: (no changes in the shaders)
package de.thoffbauer.cameraexample;
import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL32.*;
import static org.lwjgl.system.MemoryUtil.NULL;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import javax.imageio.ImageIO;
import org.lwjgl.BufferUtils;
import org.lwjgl.Version;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;
public class CameraExample {
private final int width = 1024;
private final int height = 1024;
// The window handle
private long window;
private int triangleVao;
private int triangleVbo;
private int framebuffer;
private int renderedTexture;
private int screenVao;
private int screenVbo;
private int program;
private int vertexShader;
private int fragmentShader;
public void run() {
System.out.println("Hello LWJGL " + Version.getVersion() + "!");
try {
init();
loop();
// Free the window callbacks and destroy the window
glfwFreeCallbacks(window);
glfwDestroyWindow(window);
} finally {
// 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 our window
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(width, height, "Camera Example", 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 our rendering loop
});
// Get the resolution of the primary monitor
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center our window
glfwSetWindowPos(
window,
(vidmode.width() - width) / 2,
(vidmode.height() - height) / 2
);
// Make the OpenGL context current
glfwMakeContextCurrent(window);
// Enable v-sync
glfwSwapInterval(1);
// Make the window visible
glfwShowWindow(window);
// 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();
program = glCreateProgram();
attachVertexShader("quadtextured.vs");
attachFragmentShader("quadtextured.fs");
glBindAttribLocation(program, 0, "in_Position");
glBindAttribLocation(program, 1, "in_TextureCoord");
linkProgram();
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
checkError("init");
initCamera();
initScreen();
initTriangle();
}
private void checkError(String where) {
int glError = glGetError();
if(glError != 0) {
System.out.println("[" + where + "] GL error: " + glError);
}
}
private void loop() {
// Run the rendering loop until the user has attempted to close
// the window or has pressed the ESCAPE key.
int i = 0;
while ( !glfwWindowShouldClose(window) ) {
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
renderToCamera();
glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
glUseProgram(program);
renderTriangle();
renderScreen();
// if(i == 100) {
// try {
// saveCamera("framebuffer.png");
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
glUseProgram(0);
glfwSwapBuffers(window); // swap the color buffers
// Poll for window events. The key callback above will only be
// invoked during this call.
glfwPollEvents();
i++;
}
}
private void initTriangle() {
triangleVao = glGenVertexArrays();
glBindVertexArray(triangleVao);
float[] vertices = new float[] {
0, 0.8f, -1,
-0.8f, -0.8f, -1,
0.8f, -0.8f, -1
};
FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(vertices.length);
verticesBuffer.put(vertices).flip();
triangleVbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, triangleVbo);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glBindVertexArray(0);
checkError("initTriangle");
}
private void renderTriangle() {
glBindVertexArray(triangleVao);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glBindVertexArray(0);
checkError("renderTriangle");
}
private void initCamera() {
framebuffer = glGenFramebuffers();
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
renderedTexture = glGenTextures();
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
int depthRenderBuffer = glGenRenderbuffers();
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderBuffer);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);
glDrawBuffers(GL_COLOR_ATTACHMENT0);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
System.err.println("Framebuffer not complete!");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
checkError("initCamera");
}
private void renderToCamera() {
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
renderTriangle();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
checkError("renderToCamera");
}
private void initScreen() {
screenVao = glGenVertexArrays();
glBindVertexArray(screenVao);
float[] vertices = new float[] {
// Vertices UV
-1, -1, 0, 1, 0,
0, -1, 0, 0, 0,
-1, 0, 0, 1, 1,
-1, 0, 0, 1, 1,
0, -1, 0, 0, 0,
0, 0, 0, 0, 1
};
FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(vertices.length);
verticesBuffer.put(vertices).flip();
screenVbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, screenVbo);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, (3 + 2) * 4, 0);
glVertexAttribPointer(1, 2, GL_FLOAT, false, (3 + 2) * 4, 3 * 4);
glBindVertexArray(0);
checkError("initScreen");
}
private void renderScreen() {
// glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glBindVertexArray(screenVao);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
checkError("renderScreen");
}
private void saveCamera(String name) throws IOException {
glBindTexture(GL_TEXTURE_2D, renderedTexture);
ByteBuffer buffer = ByteBuffer.allocate(width * height * 3);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
int i = (x + (width * y)) * 3;
int r = buffer.get(i) & 0xFF;
int g = buffer.get(i + 1) & 0xFF;
int b = buffer.get(i + 2) & 0xFF;
image.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b);
}
}
ImageIO.write(image, "PNG", new File(name));
}
private String readShader(String name) {
StringBuilder source = new StringBuilder();
try
{
BufferedReader reader = new BufferedReader(new FileReader("shaders/" + name));
String line;
while ((line = reader.readLine()) != null)
{
source.append(line).append("\n");
}
reader.close();
}
catch (Exception e)
{
System.err.println("Error loading source code: " + name);
e.printStackTrace();
}
return source.toString();
}
private void attachVertexShader(String name) {
String source = readShader(name);
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, source);
glCompileShader(vertexShader);
if(glGetShaderi(vertexShader, GL_COMPILE_STATUS) == GL_FALSE)
System.err.println("Error creating vertexShader\n" + glGetShaderInfoLog(vertexShader));
glAttachShader(program, vertexShader);
checkError("attachVertexShader");
}
private void attachFragmentShader(String name) {
String source = readShader(name);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, source);
glCompileShader(fragmentShader);
if(glGetShaderi(fragmentShader, GL_COMPILE_STATUS) == GL_FALSE)
System.err.println("Error creating fragmentShader\n" + glGetShaderInfoLog(fragmentShader));
glAttachShader(program, fragmentShader);
checkError("attachFragmentShader");
}
private void linkProgram() {
glLinkProgram(program);
if(glGetProgrami(program, GL_LINK_STATUS) == GL_FALSE) {
System.err.println("Unable to link shader program");
System.err.println(glGetProgramInfoLog(program));
}
checkError("linkProgram");
}
public static void main(String[] args) {
new CameraExample().run();
}
}