Slick Texture loader and glBlendFunc interfering - opengl

I have an issue regarding LWJGL and Slick
If I import a texture using Slick while having alpha blending enabled, the display will stop rendering!
Here is the code. Upon start it will simply render a purple square. Once the button T is pressed it will simply import the texture. Although i never actually bind the texture, the screen still turns black!
Here is my code:
import static org.lwjgl.opengl.GL11.GL_BLEND;
import java.io.IOException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;
public class Game {
public static void main(String[] args) throws Exception {
Display.setDisplayMode(new DisplayMode(800, 600));
Display.create();
Game game = new Game();
while (!Display.isCloseRequested()) {
game.update();
}
game.close();
}
public Game() {
initGL();
}
Texture boxTexture;
public void update() {
clearGL();
// Use the texture!
GL11.glColor3f(0.4f, 0.2f, 0.9f);
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2f(100, 100);
GL11.glVertex2f(140, 100);
GL11.glVertex2f(140, 140);
GL11.glVertex2f(100, 140);
GL11.glEnd();
if(Keyboard.isKeyDown(Keyboard.KEY_T))
{
try {
boxTexture = TextureLoader.getTexture("png",
ResourceLoader.getResourceAsStream("res/ps.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
Display.update();
}
public void close() {
Display.destroy();
System.exit(0);
}
public void initGL() {
// Enable Alpha Blending
GL11.glEnable(GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA,GL11.GL_ONE_MINUS_SRC_ALPHA);
// Opengl init
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, 500, 0, 500, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
// Enable textures
GL11.glEnable(GL11.GL_TEXTURE_2D);
}
public void clearGL() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glLoadIdentity();
}
}

TextureLoader.getTexture() binds the texture. If you look at the Slick source code, you will find the following line in the getTexture() method of the InternalTextureLoader class:
GL.glBindTexture(target, textureID);
It pretty much has to bind the texture, since it needs to call functions like glTexImage2D() to load the texture.
So you will actually use texturing after calling this function, since you now have a texture bound, and you enabled texturing in your own code:
GL11.glEnable(GL11.GL_TEXTURE_2D);
To see the texture image, you'll need to perform additional steps, like specify texture coordinates.

Related

How can I render a quad using LWJGL3? [duplicate]

(This is the second time I am asking this question. Last time I got one answer that didn't solve it (the answer there referred a bit of code that was left accidentally from one of my attempts at fixing this). I also changed the question itself slightly - I changed the order of code to put the part where I believe the mistake higher is and added that I am using macOS, which might be the reason that it doesn't work).
So, I just started learning LWJGL 3 and I used a mixture of a couple of tutorials and example code to make something that should render a rectangle to a magenta screen using VAOs and VBOs. There are no errors but the rectangle doesn't appear on screen (all I can see is a magenta screen). I tried using the old LWJGL pipeline (glBegin() and glEnd()) and it does work so I tried changing random things in the rendering code and the loading to VAOs and VBOs. I also tried to bind the VBO too but it didn't change anything. I also tried debugging and it seems like there is a VAO and a VBO that is created.
Can someone take a look at my code and see if something looks wrong? Here it is (sorry if its a bit messy. Like I said, I don't think the problem is in the Main or Window class but I have no idea about LWJGL so I wanted to put it here anyways. If you have time, please also look at them. Otherwise I would really appreciate it if you could look at the Loader and Renderer classes):
(Btw, I am using macOS, and I do have -XstartOnFirstThread on).
The Raw Model class:
package engine.io;
public class RawModel {
private int vaoID;
private int vertexCount;
public RawModel(int vaoID, int vertexCount) {
this.vaoID = vaoID;
this.vertexCount = vertexCount;
}
public int getVaoID() {
return vaoID;
}
public int getVertexCount() {
return vertexCount;
}
}
The loader class:
package engine.io;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.system.MemoryUtil;
public class Loader {
private List<Integer> vaos = new ArrayList<Integer>();
private List<Integer> vbos = new ArrayList<Integer>();
public RawModel loadToVAO(float[] positions) {
int vaoID = createVAO();
storeDataInAttributeList(0, positions);
unbindVAO();
return new RawModel(vaoID, positions.length/3);
}
private int createVAO() {
int vaoID = GL30.glGenVertexArrays();
vaos.add(vaoID);
GL30.glBindVertexArray(vaoID);
return vaoID;
}
private void storeDataInAttributeList(int attributeNumber, float[] data) {
int vboID = GL15.glGenBuffers();
vbos.add(vboID);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
FloatBuffer buffer = storeDataInFloatBuffer(data);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(attributeNumber, 3, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
private void unbindVAO() {
GL30.glBindVertexArray(0);
}
private FloatBuffer storeDataInFloatBuffer(float[] data) {
FloatBuffer buffer = MemoryUtil.memAllocFloat(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
public void cleanUp() {
for (int vao : vaos) {
GL30.glDeleteVertexArrays(vao);
}
for (int vbo : vbos) {
GL15.glDeleteBuffers(vbo);
}
}
}
The renderer class:
package engine.io;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
public class Renderer {
public void prepare() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
GL11.glClearColor(1f, 0f, 1f, 1f);
}
public void render(RawModel model) {
GL30.glBindVertexArray(model.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, model.getVertexCount());
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
}
}
Here is the Main class:
import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.*;
import engine.io.Loader;
import engine.io.RawModel;
import engine.io.Renderer;
import engine.io.Window;
import java.nio.*;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryStack.*;
import static org.lwjgl.system.MemoryUtil.*;
public class Main {
private Window window;
Loader loader = new Loader();
Renderer renderer = new Renderer();
float[] vertices = {
// Left bottom triangle
-0.5f, 0.5f, 0f,
-0.5f, -0.5f, 0f,
0.5f, -0.5f, 0f,
// Right top triangle
0.5f, -0.5f, 0f,
0.5f, 0.5f, 0f,
-0.5f, 0.5f, 0f
};
RawModel model;
public void run() {
setup();
loop();
loader.cleanUp();
glfwFreeCallbacks(window.getWindowNum());
glfwDestroyWindow(window.getWindowNum());
glfwTerminate();
glfwSetErrorCallback(null).free();
}
private void loop() {
while ( !glfwWindowShouldClose(window.getWindowNum()) ) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
renderer.render(model);
glfwSwapBuffers(window.getWindowNum()); // swap the color buffers
glfwPollEvents();
}
}
public void setup() {
window = new Window(900, 300, "Flappy Bird");
window.create();
GL.createCapabilities();
GLFW.glfwMakeContextCurrent(window.getWindowNum());
model = loader.loadToVAO(vertices);
renderer.prepare();
GL11.glViewport(0, 0, 900, 300);
}
public static void main(String[] args) {
new Main().run();
}
}
Here is the window class:
package engine.io;
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.*;
import java.nio.IntBuffer;
//import static org.lwjgl.glfw.GLFW.*;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.system.MemoryStack;
public class Window {
private int width, height;
private String title;
private long window;
public Window(int width, int height, String title) {
this.width = width;
this.height = height;
this.title = title;
}
public void create() {
GLFWErrorCallback.createPrint(System.err).set();
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(width, height, "Flappy Bird", NULL, NULL);
if (window == NULL)
throw new RuntimeException("Failed to create the GLFW window");
// 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
// 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
});
// Make the OpenGL context current
glfwMakeContextCurrent(window);
// Enable v-sync
glfwSwapInterval(1);
// Make the window visible
glfwShowWindow(window);
}
public long getWindowNum() {
return window;
}
}
Since you are on MacOS, I recommend to set up a 3.2 core profile OpenGL Context. See OpenGL Development on OS X:
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Create the window
window = glfwCreateWindow(width, height, "Flappy Bird", NULL, NULL);

How can I store the previously rendered from from an OpenGL Fragment Shader for later use?

I'm writing a FFGL video effect plugin (using this shadertoy port). I want to store a previously rendered frame to use in a future calculation. Specifically I am trying to make the equivalent of a video delay.
Is it possible to write to an external buffer from a fragment shader and then use that stored value at a later time (say, 30 frames later)?
you create a FBO, and bind it. whatever you render next goes onto it. so if you're using a shader, that still applies like on the default FBO.
here's some code to help you out
import java.nio.ByteBuffer;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.opengl.GL30.*;
public class FBO {
public int fbo,tex,depth;
public void delete() {glDeleteTextures(tex);glDeleteRenderbuffers(depth);glDeleteFramebuffers(fbo);}
public void bindTexture() {glBindTexture(GL_TEXTURE_2D,tex);}
public void bind() {glBindFramebuffer(GL_FRAMEBUFFER,fbo);}
public static void unbind() {glBindFramebuffer(GL_FRAMEBUFFER,0);}
public FBO(){ // create the fbo
glBindTexture(GL_TEXTURE_2D,tex=glGenTextures()); // create texture, set correct filters
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glBindRenderbuffer(GL_RENDERBUFFER,depth=glGenRenderbuffers()); // create buffer for depth
glBindFramebuffer(GL_FRAMEBUFFER,fbo=glGenFramebuffers()); // create framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,tex,0); // attach texture
glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,depth); // attach depth
unbind(); // incase not using immediately
}
public void resize(int w,int h) {
glBindTexture(GL_TEXTURE_2D,tex); // update texture size
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,(ByteBuffer)null);
glBindRenderbuffer(GL_RENDERBUFFER,depth); // update depth size
glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT24,w,h);
}
public void render() {
// glColor4f(1,1,1,1); // you may want to do these customly
// glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, tex);
Tess.begin();
Tess.vertex( 0, height, 0, 0, 0);
Tess.vertex(width, height, 0, 1, 0);
Tess.vertex(width, 0, 0, 1, 1);
Tess.vertex( 0, 0, 0, 0, 1);
Tess.draw();
// Tess btw, just manually handles verts and tex coords
// that could be pure pipeline, or by vbo / vao / interleaved vbo
// width / height are just the 2d size. could render for post processing
}
}

Framebuffer in Libgdx, using glclearcolor() clears whole screen

I'm using glClearColor inside begin() and end() in framebuffer,
but it is clearing the whole screen color, Am I doing something wrong?
public class FrameBufferTest implements ApplicationListener{
OrthographicCamera camera;
SpriteBatch batcher;
FrameBuffer fbo;
Texture tex;
#Override
public void create() {
batcher = new SpriteBatch();
camera = new OrthographicCamera(800, 480);
camera.position.set(camera.viewportWidth/2f, camera.viewportHeight/2f, 0);
fbo = new FrameBuffer(Format.RGBA8888, 100, 100,false);
camera.position.set(camera.viewportWidth/2f, camera.viewportHeight/2f, 0);
tex = new Texture("data/bg.png");
}
#Override
public void render() {
GL20 gl = Gdx.graphics.getGL20();
gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
gl.glClearColor(0.5f,0.5f,0.5f,0.5f); // grey color
camera.update();
batcher.setProjectionMatrix(camera.combined);
batcher.enableBlending();
batcher.begin();
batcher.draw(tex, 0, 0, 256, 256);
batcher.end();
fbo.begin();
gl.glClearColor(1f,0,0,1f);
gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
fbo.end();
batcher.begin();
batcher.draw(fbo.getColorBufferTexture(), 512, 0, 100, 100);
batcher.end();
}
Swap these two lines at the beginning of your render method:
gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
gl.glClearColor(0.5f,0.5f,0.5f,0.5f); // grey color
In the order you have them, it is clearing the color using the most recently set clear color, which is the red that you set farther down in your render method (since this is a loop).

How to debug openGL code?

I have problem with openGL debugging. I find that a lot of the time, OpenGL will show you it failed by not drawing anything. Every time code looks fine but it is not drawing anything on GL window.
For e.g consider the below code.I write it to draw the cube but it is not drawing anything and i am unable to find the cause.
========================================================
// cube_vertex_array.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <glut.h>
static GLfloat vertex[]=
{
100.0,100.0,0.0,
400.0,100.0,0.0,
400.0,400.0,0.0,
100.0,400.0,0.0,
100.0,100.0,-300.0,
400.0,100.0,-300.0,
400.0,400.0,-300.0,
100.0,400.0,-300.0
};
static GLfloat color[]=
{
1.0,0.0,0.0,
0.0,1.0,0.0,
0.0,0.0,1.0,
1.0,1.0,0.0,
1.0,0.0,1.0,
0.0,1.0,1.0
};
static GLubyte frontIndices[] = {0,1,2,3};
static GLubyte leftIndices[] = {1,5,6,2};
static GLubyte backIndices[] = {4,7,6,5};
static GLubyte rightIndices[] = {0,3,7,4};
static GLubyte topIndices[] = {3,2,6,7};
static GLubyte bottomIndices[] = {0,4,5,1};
void init(void)
{
glClearColor(0.0,0.0,0.0,0.0); //Set default background color to black.
glClearDepth(2.0); //Set the depth level for clearing depth buffer.
glShadeModel(GL_FLAT); //Set the shading model to FLAT
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Clear the color and depth buffer.
}
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Clear the color and depth buffer.
glColor3f(1.0,0.0,0.0);
//glBegin(GL_LINE_STRIP);
// glVertex3f(0.0,0.0,0.0);
// glVertex3f(200.0,100.0,0.0);
//glEnd();
glEnableClientState(GL_VERTEX_ARRAY); //Enable vertex array.
glEnableClientState(GL_COLOR_ARRAY); //Enable vertex array color.
glColorPointer(3,GL_FLOAT,0,color); //Specify the array for colors.
glVertexPointer(3,GL_FLOAT,0,vertex); //Specify the array for vertex.
glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,frontIndices); //Draw front face.
glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,leftIndices); //Draw left face.
glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,backIndices); //Draw back face.
glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,rightIndices); //Draw right face.
glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,topIndices); //Draw top face.
glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,bottomIndices); //Draw bottom face.
glutSwapBuffers(); //Swap the buffers.
}
void Reshape(int w,int h)
{
glViewport(0.0,(GLsizei)w,0.0,(GLsizei)h); //Set the viewport according to new window size.
glMatrixMode(GL_PROJECTION); //Set matrix mode to projection.
glLoadIdentity(); //Replace the top matrix in the stack to the identity matrix.
gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h); //Set the orthographic projection.
glMatrixMode(GL_MODELVIEW); //Set matrix mode to modelview.
}
int main(int argc, char **argv)
{
glutInit(&argc,argv); //Initialize the glut.
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); //Set display mode and also enable double buffering.
glutInitWindowSize(500,500); //Set the initial window size.
glutCreateWindow("Cube"); //Create the window and also assign name to it.
init(); //Initialize the app.
glutDisplayFunc(Display); //Register the Display function.
glutReshapeFunc(Reshape); //Register the Reshape function.
glutMainLoop(); //Start the main loop.
return 0;
}
You have put GL_UNSIGNED_BYTE as the type parameter in glDrawElements(). This will cause openGL to interpret the array of indices you throw in as one byte per index. You should use GL_UNSIGNED_INT here instead.
Here's the working code based on the code your provided (I did port it to java though):
import java.nio.ByteBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import static org.lwjgl.opengl.GL11.*;
public class GLTest {
public static void main(String[] args) {
try {
Display.create();
Display.setDisplayMode(new DisplayMode(500, 500));
Display.setResizable(true);
//the same arrays as the ones you specified.
float[] vertices = new float[]{100.0f,100.0f,0.0f,
400.0f,100.0f,0.0f,
400.0f,400.0f,0.0f,
100.0f,400.0f,0.0f,
100.0f,100.0f,-300.0f,
400.0f,100.0f,-300.0f,
400.0f,400.0f,-300.0f,
100.0f,400.0f,-300.0f};
float[] color = new float[]{1,0,0,
0,1,0,
0,0,1,
1,1,0,
1,0,1,
0,1,1};
int[] frontIndices = new int[]{0, 1, 2, 3};
//JWJGL bookkeeping..
ByteBuffer vertexBuffer = BufferUtils.createByteBuffer(vertices.length * 4);
ByteBuffer colourBuffer = BufferUtils.createByteBuffer(color.length * 4);
for(int i = 0; i < vertices.length; i++) {
vertexBuffer.putFloat(vertices[i]);
}
vertexBuffer.rewind();
for(int i = 0; i < color.length; i++) {
colourBuffer.putFloat(color[i]);
}
colourBuffer.rewind();
ByteBuffer indexBuffer = BufferUtils.createByteBuffer(4 * frontIndices.length);
for(int i = 0; i < frontIndices.length; i++) {
indexBuffer.putInt(frontIndices[i]);
}
indexBuffer.rewind();
//back you your code
glClearColor(1,1,1,1);
glShadeModel(GL_SMOOTH);
while(!Display.isCloseRequested()) {
glViewport(0, 0, Display.getWidth(), Display.getHeight());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,Display.getWidth(), 0, Display.getHeight(), -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, 0, colourBuffer);
glVertexPointer(3, GL_FLOAT, 0, vertexBuffer);
glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, indexBuffer);
Display.update();
Display.sync(60);
}
} catch (LWJGLException e) {
e.printStackTrace();
}
}
}
Which results in:
use tools like glTrace / glIntercept (to look at OpenGL call trace), gDebugger (to visualize textures, shaders, OGL state etc.)
There is a list of OpenGL debugging tools here : https://www.opengl.org/wiki/Debugging_Tools
Also your code is using the old fixed pipeline which is considered deprecated since OpenGL 3.3, so i would recommend either not putting the tag "opengl-3" on your questions, or using opengl 3.3 core context and learning the "modern" OpenGL (which is more powerful and more difficult to learn but makes you understand how the GPU works).

Texturing a lwjgl/opengl heightmap?

how do i add textures for a height map? I followed TheCodingUniverse's tutorial #36 (i think thats the number) for creating height maps, he covers using shaders to set X colour for X height, However i would like to set XX texture for X height instead of a colour for each height. How do i do this?
I have tried binding the texture as i am drawing the triangle strip (like i would do on a 3D square of GL_QUADS), but then the heightmap fails to render. All other things in the world continue to render, however.
StackOverflow is complaining about how i have given too little info, but i am unsure what more i have got to tell you, apart from code samples.
Current Heightmap Code:
package Terrain;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL20;
import org.lwjgl.util.glu.GLU;
import org.lwjgl.util.glu.Sphere;
import com.bulletphysics.collision.broadphase.BroadphaseInterface;
import com.bulletphysics.collision.broadphase.DbvtBroadphase;
import com.bulletphysics.collision.dispatch.CollisionConfiguration;
import com.bulletphysics.collision.dispatch.CollisionDispatcher;
import com.bulletphysics.collision.dispatch.CollisionObject;
import com.bulletphysics.collision.dispatch.DefaultCollisionConfiguration;
import com.bulletphysics.collision.shapes.CollisionShape;
import com.bulletphysics.collision.shapes.SphereShape;
import com.bulletphysics.collision.shapes.StaticPlaneShape;
import com.bulletphysics.dynamics.DiscreteDynamicsWorld;
import com.bulletphysics.dynamics.RigidBody;
import com.bulletphysics.dynamics.RigidBodyConstructionInfo;
import com.bulletphysics.dynamics.constraintsolver.ConstraintSolver;
import com.bulletphysics.dynamics.constraintsolver.SequentialImpulseConstraintSolver;
import com.bulletphysics.linearmath.DefaultMotionState;
import com.bulletphysics.linearmath.MotionState;
import com.bulletphysics.linearmath.Transform;
import utility.EulerCamera;
import utility.ShaderLoader;
import javax.imageio.ImageIO;
import javax.vecmath.Matrix4f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector3f;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL20.*;
/**
* A 3D terrain loaded from a height-map and a lookup texture. Press 'L' to reload the shader and texture files. Press
* 'P' to switch between normal, point, and wire-frame mode. Press 'F' to flatten the terrain. Click here for an image:
* https://twitter.com/i/#!/CodingUniverse/media/slideshow?url=pic.twitter.com%2FDgMdZ5jm.
*
* #author Oskar Veerhoek
*/
public class TexturedTerrain {
private static final String WINDOW_TITLE = "Terrain!";
private static final int[] WINDOW_DIMENSIONS = {1200, 650};
// private static final EulerCamera camera = new EulerCamera.Builder().setPosition(-5.4f, 19.2f,
// 33.2f).setRotation(30, 61, 0).setAspectRatio(ASPECT_RATIO).setFieldOfView(60).build();
private static EulerCamera camera = new EulerCamera.Builder()
.setFieldOfView(60)
.setNearClippingPane(0.3f)
.setFarClippingPane(500)
.setPosition(0, 25, 15)
.build();
/**
* The shader program that will use the lookup texture and the height-map's vertex data to draw the terrain.
*/
public static int shaderProgram;
/**
* The texture that will be used to find out which colours correspond to which heights.
*/
public static int lookupTexture;
public static int textureTerrain;
/**
* The display list that will contain the height-map's vertex data.
*/
public static int heightmapDisplayList;
/**
* The points of the height. The first dimension represents the z-coordinate. The second dimension represents the
* x-coordinate. The float value represents the height.
*/
public static float[][] data;
/**
* Whether the terrain should vary in height or be displayed on a grid.
*/
private static boolean flatten = false;
public static void render() {
// Clear the pixels on the screen and clear the contents of the depth buffer (3D contents of the scene)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset any translations the camera made last frame update
glLoadIdentity();
// Apply the camera position and orientation to the scene
camera.applyTranslations();
if (flatten) {
glScalef(1, 0, 1);
}
// Render the heightmap using the shaders that are being used
glCallList(heightmapDisplayList);
}
private static void input() {
while (Keyboard.next()) {
if (Keyboard.getEventKeyState()) {
if (Keyboard.isKeyDown(Keyboard.KEY_F)) {
flatten = !flatten;
}
if (Keyboard.getEventKey() == Keyboard.KEY_ESCAPE){
Display.destroy();
System.exit(0);
}
if (Keyboard.getEventKey() == Keyboard.KEY_L) {
// Reload the shaders and the heightmap data.
glUseProgram(0);
glDeleteProgram(shaderProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteTextures(lookupTexture);
glDeleteTextures(textureTerrain);
setUpShaders();
setUpHeightmap();
}
if (Keyboard.getEventKey() == Keyboard.KEY_P) {
// Switch between normal mode, point mode, and wire-frame mode.
int polygonMode = glGetInteger(GL_POLYGON_MODE);
if (polygonMode == GL_LINE) {
glPolygonMode(GL_FRONT, GL_FILL);
} else if (polygonMode == GL_FILL) {
glPolygonMode(GL_FRONT, GL_POINT);
} else if (polygonMode == GL_POINT) {
glPolygonMode(GL_FRONT, GL_LINE);
}
}
}
}
if (Mouse.isButtonDown(0)) {
Mouse.setGrabbed(true);
} else if (Mouse.isButtonDown(1)) {
Mouse.setGrabbed(false);
}
if (Mouse.isGrabbed()) {
camera.processMouse(1, 80, -80);
}
camera.processKeyboard(16, 1);
}
private static int loadTexture(String path) throws IOException {
// Create an input stream for the 'lookup texture', a texture that will used by the fragment shader to
// determine which colour matches which height on the heightmap
FileInputStream inputStream = new FileInputStream(path);
// Create a class that will give us information about the image file (width and height) and give us the
// texture data in an OpenGL-friendly manner
PNGDecoder decoder = new PNGDecoder(inputStream);
// Create a ByteBuffer in which to store the contents of the texture. Its size is the width multiplied by
// the height and 4, which stands for the amount of bytes a float is in Java.
ByteBuffer buffer = BufferUtils.createByteBuffer(4 * decoder.getWidth() * decoder.getHeight());
// 'Decode' the texture and store its data in the buffer we just created
decoder.decode(buffer, decoder.getWidth() * 4, PNGDecoder.Format.RGBA);
// Make the contents of the ByteBuffer readable to OpenGL (and unreadable to us)
buffer.flip();
// Close the input stream for the heightmap 'lookup texture'
inputStream.close();
// Generate a texture handle for the 'lookup texture'
int texture = glGenTextures();
glBindTexture(GL_TEXTURE_2D, texture);
// Hand the texture data to OpenGL
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, decoder.getWidth(), decoder.getHeight(), 0, GL_RGBA,
GL_UNSIGNED_BYTE, buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
return texture;
}
public static BufferedImage image(){
BufferedImage heightmapImage = null;
try{
heightmapImage = ImageIO.read(new File("res/heightmap.bmp"));
}catch (IOException e){
e.printStackTrace();
}
if (heightmapImage == null){
return null;
}
return heightmapImage;
}
public static void setUpHeightmap() {
try {
// Load the heightmap-image from its resource file
BufferedImage heightmapImage = ImageIO.read(new File("res/heightmap.bmp"));
// Initialise the data array, which holds the heights of the heightmap-vertices, with the correct dimensions
data = new float[heightmapImage.getWidth()][heightmapImage.getHeight()];
// Lazily initialise the convenience class for extracting the separate red, green, blue, or alpha channels
// an int in the default RGB color model and default sRGB colourspace.
Color colour;
// Iterate over the pixels in the image on the x-axis
for (int z = 0; z < data.length; z++) {
// Iterate over the pixels in the image on the y-axis
for (int x = 0; x < data[z].length; x++) {
// Retrieve the colour at the current x-location and y-location in the image
colour = new Color(heightmapImage.getRGB(z, x));
// Store the value of the red channel as the height of a heightmap-vertex in 'data'. The choice for
// the red channel is arbitrary, since the heightmap-image itself only has white, gray, and black.
int y = colour.getRed();;
data[z][x] = y;
//xheight.put(x, y);
//zheight.put(z, y);
}
}
lookupTexture = loadTexture("res/heightmap_lookup.png");
//textureTerrain = loadTexture("res/heightmap.png");
} catch (IOException e) {
e.printStackTrace();
}
glBindTexture(GL_TEXTURE_2D, lookupTexture);
// Generate a display list handle for the display list that will store the heightmap vertex data
heightmapDisplayList = glGenLists(1);
// TODO: Add alternative VBO rendering for pseudo-compatibility with version 3 and higher.
glNewList(heightmapDisplayList, GL_COMPILE);
// Scale back the display list so that its proportions are acceptable.
//glScalef(0.4f, 0.4f, 0.4f);
// Iterate over the 'strips' of heightmap data.
for (int z = 0; z < data.length - 1; z++) {
// Render a triangle strip for each 'strip'.
glBegin(GL_TRIANGLE_STRIP);
for (int x = 0; x < data[z].length; x++) {
// Take a vertex from the current strip
//glTexCoord2f(0, 0);
//GL20.glUseProgram(0);
glVertex3f(x, data[z][x], z);
// Take a vertex from the next strip
//glTexCoord2f(1, 1);
glVertex3f(x, data[z + 1][x], z + 1);
/*
glColor3f(0.9f, 0.9f, 0.9f);
glBegin(GL_QUADS);
glTexCoord2f(0, 1); // put before every vertex
glVertex3f(-50,0 ,-50);
glTexCoord2f(1, 1);
glVertex3f(50, 0 ,-50);
glTexCoord2f(1, 0);
glVertex3f(50, 0 ,50);
glTexCoord2f(0, 0);
glVertex3f(-50, 0 ,50);
glEnd();
*/
}
glEnd();
}
glEndList();
}
public static void setUpShaders() {
shaderProgram = ShaderLoader.loadShaderPair("res/landscape.vs", "res/landscape.fs");
glUseProgram(shaderProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, lookupTexture);
glUniform1i(glGetUniformLocation(shaderProgram, "lookup"), 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureTerrain);
glUniform1i(glGetUniformLocation(shaderProgram, "terrain"), 1);
}
private static void cleanUp(boolean asCrash) {
glUseProgram(0);
glDeleteProgram(shaderProgram);
glDeleteLists(heightmapDisplayList, 1);
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteTextures(lookupTexture);
System.err.println(GLU.gluErrorString(glGetError()));
Display.destroy();
System.exit(asCrash ? 1 : 0);
}
private static void setUpMatrices() {
camera.applyPerspectiveMatrix();
}
private static void setUpStates() {
camera.applyOptimalStates();
glPointSize(1);
// Enable the sorting of shapes from far to near
glEnable(GL_DEPTH_TEST);
// Set the background to a blue sky colour
glClearColor(0, 0.75f, 1, 1);
// Remove the back (bottom) faces of shapes for performance
glEnable(GL_CULL_FACE);
}
private static void update() {
Display.update();
Display.sync(60);
}
private static void enterGameLoop() {
while (!Display.isCloseRequested()) {
render();
input();
update();
//TODO
//TODO
}
}
private static void setUpDisplay() {
try {
Display.setDisplayMode(new DisplayMode(WINDOW_DIMENSIONS[0], WINDOW_DIMENSIONS[1]));
Display.setVSyncEnabled(true);
Display.setTitle(WINDOW_TITLE);
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
cleanUp(true);
}
}
public static void main(String[] args) {
setUpDisplay();
setUpStates();
setUpHeightmap();
setUpShaders();
//setUpPhysics();
setUpMatrices();
enterGameLoop();
cleanUp(false);
}
}