Well, I have a basic quad being drawn using VBOs, and I have no idea how to draw a texture. I’ve been trying to search for the video i saw on it a while back but never found it.
Well, first of all you need the geometry to be aware of which part of the texture corresponds to which part of the vertex. These are called “Texture Coordinates” and usually range from 0, to 1. (Or texture UVs)
http://i.msdn.microsoft.com/dynimg/IC282223.jpg
Next, we need to import that into a buffer, then point to that when pointing to the vertices.
Can we have a snippet of code? VBOs have many implementations over many OpenGL versions…
I’m just using coding universe code.
package RenderingModes;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import java.nio.FloatBuffer;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
/**
* Renders a colored triangle using Vertex Buffer Objects
*
* @author Oskar
*/
public class VertexBufferObjectDemo {
public static void main(String[] args) {
try {
Display.setDisplayMode(new DisplayMode(640, 480));
Display.setTitle("Vertex Buffer Object Demo");
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
Display.destroy();
System.exit(1);
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(1, -1, 1, -1, 1, -1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
final int amountOfVertices = 3;
final int vertexSize = 3;
final int colorSize = 3;
//ignor below
float trans = 0.1f;
FloatBuffer vertexData = BufferUtils.createFloatBuffer(amountOfVertices * vertexSize);
vertexData.put(new float[]{-0.5f + trans, -0.5f, 0, 0.5f + trans, -0.5f, 0, 0.5f + trans, 0.5f, 0});
vertexData.flip();
FloatBuffer colorData = BufferUtils.createFloatBuffer(amountOfVertices * colorSize);
colorData.put(new float[]{1, 0, 0, 0, 1, 0, 0, 0, 1/**/});
colorData.flip();
int vboVertexHandle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
int vboColorHandle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboColorHandle);
glBufferData(GL_ARRAY_BUFFER, colorData, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
while (!Display.isCloseRequested()) {
glClear(GL_COLOR_BUFFER_BIT);
vertexData.clear();
glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
glVertexPointer(vertexSize, GL_FLOAT, 0, 0L);
glBindBuffer(GL_ARRAY_BUFFER, vboColorHandle);
glColorPointer(colorSize, GL_FLOAT, 0, 0L);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glDrawArrays(GL_TRIANGLES, 0, amountOfVertices);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
Display.update();
Display.sync(60);
}
glDeleteBuffers(vboVertexHandle);
glDeleteBuffers(vboColorHandle);
Display.destroy();
System.exit(0);
}
}
Good old OpenGL 1.5
We really just need to pack the per-vertex texture coordinates into another buffer…
Here’s a few snippets. And I hope you already know how to load and bind textures. :persecutioncomplex:
//...
FloatBuffer textureUVData = BufferUtils.createFloatBuffer(amountOfVertices * 2); // amount of vertices * two texture coordinates per-vertex
textureUVData.put(new float[]{0, 0, 0, 1, 0, 0, 1, 1, 0});
textureUVData.flip();
//...
int vboTextureUVHandle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboTextureUVHandle);
glBufferData(GL_ARRAY_BUFFER, textureUVData, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//...
glBindTexture(GL_TEXTURE_2D, myTextureID);
//...
glBindBuffer(GL_ARRAY_BUFFER, vboTextureUVHandle);
// 2 Because we have 2 texture coordinates per-vertex
glTexCoordPointer(2, GL_FLOAT, 0, 0L);
//...
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//...
I honestly don’t remember how to bind a texture. I remember doing it in immediate mode.
Read ALL of this: https://open.gl/textures
BufferedImage image = ImageIO.read(new File("..."));
//...
//During setup ONLY!!!
int myTextureID = glGenTextures();
glBindTexture(GL_TEXTURE_2D, myTextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, dataFromImage(bufferedImage));
//...
//During render/draw arrays
glBindTexture(GL_TEXTURE_2D, myTextureID);
/**
* Creates a flipped byte buffer from a given buffered image
* @param source The buffered image source to load from
* @return A byte buffer interpolated from source
*/
private ByteBuffer dataFromImage(BufferedImage source){
int[] pixels = new int[source.getWidth() * source.getHeight()];
source.getRGB(0, 0, source.getWidth(), source.getHeight(), pixels, 0, source.getWidth());
ByteBuffer buffer = BufferUtils.createByteBuffer(source.getWidth() * source.getHeight() * 4);
for (int y = 0; y < source.getHeight(); y++) {
for (int x = 0; x < source.getWidth(); x++) {
int pixel = pixels[y * source.getWidth() + x];
buffer.put((byte) ((pixel >> 16) & 0xFF)); // Red component
buffer.put((byte) ((pixel >> 8) & 0xFF)); // Green component
buffer.put((byte) (pixel & 0xFF)); // Blue component
buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component.
}
}buffer.flip();
return buffer;
}
Also, if you’re doing this in a engine, you probably want a base texture class, then a seperate class for wrapping texture functions to loading image functions. I’ve got a good example of that here:
https://github.com/ecumene-software/LibEcu/tree/master/source/main/ecumene/opengl/texture
EDIT: I’m changing the license of the repo to the un-lisence soon also. So don’t worry about copyright laws.
@Ecumene Textures coordinates always range from 0 to 1, not sometimes like you said. Vertex buffer objects also have not changed from version to version, there aren’t many different versions of VBOs. Just to clear that up.
Yeah, I’ve noticed that in my OP. VBOs can be made using the GL15 buffer & vertex pointer methods, or the 3.0 vertex attribute methods, is what I meant. I shouldn’t have used the words ‘Usually’.
As for the texture coordinates, you can do a matrix transform to convert your texture coordinates from coordinates on the image, to vertex texture coordinates in the vertex shader. I haven’t done it but I’m sure its possible.
Where did that last parameter come from? I might have this working.
Can you explain what you mean by the conversion to vertex coordinates? Texels are normalized so that you can apply them to any size geometry, are you talking about vertex attributes? Honestly, I would like to know, I’ve never heard of that!
Look at the code snippet below my OP.
Can you explain what you mean by the conversion to vertex coordinates? Texels are normalized so that you can apply them to any size geometry, are you talking about vertex attributes? Honestly, I would like to know, I’ve never heard of that!
I mean:
Vertex Positions -> Vertex Shader : Transform with Matrices -> Primitive Assembly -> Rasterization…
Tex Coordinates -> Vertex Shader : Transform from ‘image’ space to normalized space using uniform texture dimensions -> Primative Assembly -> Rasterization…
It’s a concept I’ve been thinking about lately. Using a 2D texture matrix to transform texture coordinates by translation / rotation / scaling done by the vertex shader. It could be broken in many ways. Like for example the texture coordinates are probably clamped by default…
Also, Texel = Pixel from Texture. But even then, OpenGL pixels are usually clamped to 1.0 - 0.0 also… So I guess that’s still right in an ironic sense.
Alright, I did some work and here is my code. It throws an exception where I put the TextureUVData.
Also, the glText2D method; I had to create one, so I don’t really know what goes there or where it comes from.
package RenderingModes;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
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;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import javax.imageio.ImageIO;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
/**
* Renders a colored triangle using Vertex Buffer Objects
*
* @author Oskar
*/
public class VertexBufferObjectDemo {
/**
* Creates a flipped byte buffer from a given buffered image
* @param source The buffered image source to load from
* @return A byte buffer interpolated from source
*/
private static ByteBuffer dataFromImage(BufferedImage source){
int[] pixels = new int[source.getWidth() * source.getHeight()];
source.getRGB(0, 0, source.getWidth(), source.getHeight(), pixels, 0, source.getWidth());
ByteBuffer buffer = BufferUtils.createByteBuffer(source.getWidth() * source.getHeight() * 4);
for (int y = 0; y < source.getHeight(); y++) {
for (int x = 0; x < source.getWidth(); x++) {
int pixel = pixels[y * source.getWidth() + x];
buffer.put((byte) ((pixel >> 16) & 0xFF)); // Red component
buffer.put((byte) ((pixel >> 8) & 0xFF)); // Green component
buffer.put((byte) (pixel & 0xFF)); // Blue component
buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component.
}
}buffer.flip();
return buffer;
}
public static void main(String[] args) {
try {
Display.setDisplayMode(new DisplayMode(640, 480));
Display.setTitle("Vertex Buffer Object Demo");
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
Display.destroy();
System.exit(1);
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(1, -1, 1, -1, 1, -1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
final int amountOfVertices = 3;
final int vertexSize = 3;
final int colorSize = 3;
//ignor below
float trans = 0.1f;
FloatBuffer vertexData = BufferUtils.createFloatBuffer(amountOfVertices * vertexSize);
vertexData.put(new float[]{-0.5f + trans, -0.5f, 0, 0.5f + trans, -0.5f, 0, 0.5f + trans, 0.5f, 0});
vertexData.flip();
FloatBuffer colorData = BufferUtils.createFloatBuffer(amountOfVertices * colorSize);
colorData.put(new float[]{1, 0, 0, 0, 1, 0, 0, 0, 1/**/});
colorData.flip();
FloatBuffer textureUVData = BufferUtils.createFloatBuffer(amountOfVertices * 2); // amount of vertices * two texture coordinates per-vertex
textureUVData.put(new float[]{0, 0, 0, 1, 0, 0, 1, 1, 0});
textureUVData.flip();
int vboVertexHandle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
int vboColorHandle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboColorHandle);
glBufferData(GL_ARRAY_BUFFER, colorData, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
BufferedImage image = null;
try {
image = ImageIO.read(new File("ufo.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//During setup ONLY!!!
int myTextureID = glGenTextures();
glBindTexture(GL_TEXTURE_2D, myTextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE);
int vboTextureUVHandle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboTextureUVHandle);
glBufferData(GL_ARRAY_BUFFER, textureUVData, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenTextures();
while (!Display.isCloseRequested()) {
glClear(GL_COLOR_BUFFER_BIT);
vertexData.clear();
glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
glVertexPointer(vertexSize, GL_FLOAT, 0, 0L);
glBindBuffer(GL_ARRAY_BUFFER, vboColorHandle);
glColorPointer(colorSize, GL_FLOAT, 0, 0L);
glBindBuffer(GL_ARRAY_BUFFER, vboTextureUVHandle);
// 2 Because we have 2 texture coordinates per-vertex
glTexCoordPointer(2, GL_FLOAT, 0, 0L);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindTexture(GL_TEXTURE_2D, myTextureID);
glDrawArrays(GL_TRIANGLES, 0, amountOfVertices);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
Display.update();
Display.sync(60);
}
glDeleteBuffers(vboVertexHandle);
glDeleteBuffers(vboColorHandle);
Display.destroy();
System.exit(0);
}
private static void glTexImage2D(int glTexture2d, int i, int glRgb8,
int width, int height, int j, int glRgba, int glUnsignedByte) {
// TODO Auto-generated method stub
}
}
EXCEPTION:
Exception in thread "main" java.nio.BufferOverflowException
at java.nio.DirectFloatBufferU.put(Unknown Source)
at java.nio.FloatBuffer.put(Unknown Source)
at RenderingModes.VertexBufferObjectDemo.main(VertexBufferObjectDemo.java:87)
Hehehe, oops
textureUVData.put(new float[]{0, 0, 1, 0, 1, 1});
SMOKEBOMB
The area where I load the buffered image. 1. It cant load my file from the res folder. 2. That glTexImage2D, where is that method coming from?
BufferedImage image = null;
try {
image = ImageIO.read(new File("ufo.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//During setup ONLY!!!
int myTextureID = glGenTextures();
glBindTexture(GL_TEXTURE_2D, myTextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE);
This was made by default.
private static void glTexImage2D(int glTexture2d, int i, int glRgb8,
int width, int height, int j, int glRgba, int glUnsignedByte) {
// TODO Auto-generated method stub
}

The area where I load the buffered image. 1. It cant load my file from the res folder. 2. That glTexImage2D, where is that method coming from?
int myTextureID = glGenTextures(); glBindTexture(GL_TEXTURE_2D, myTextureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE);
You forgot the byte buffer holding your pixel data after ‘GL_UNSIGNED_BYTE’. You can get a ByteBuffer from a buffered image through this:
/**
* Creates a flipped byte buffer from a given buffered image
* @param source The buffered image source to load from
* @return A byte buffer interpolated from source
*/
private ByteBuffer dataFromImage(BufferedImage source){
int[] pixels = new int[source.getWidth() * source.getHeight()];
source.getRGB(0, 0, source.getWidth(), source.getHeight(), pixels, 0, source.getWidth());
ByteBuffer buffer = BufferUtils.createByteBuffer(source.getWidth() * source.getHeight() * 4);
for (int y = 0; y < source.getHeight(); y++) {
for (int x = 0; x < source.getWidth(); x++) {
int pixel = pixels[y * source.getWidth() + x];
buffer.put((byte) ((pixel >> 16) & 0xFF)); // Red component
buffer.put((byte) ((pixel >> 8) & 0xFF)); // Green component
buffer.put((byte) (pixel & 0xFF)); // Blue component
buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component.
}
}
buffer.flip();
return buffer;
}
So…
[icode]glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, dataFromImage(image));[/icode]
Thought I did that already, but I get syntax error
The method glTexImage2D(int, int, int, int, int, int, int, int) in the type VertexBufferObjectDemo is not applicable for the arguments (int, int, int, int, int, int, int, int, ByteBuffer)
Remove the method from the base class and make sure it’s imported statically. Or use:
[icode]GL11.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, dataFromImage(image));[/icode]
Okay, now I think that it can’t find my image.
javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(Unknown Source)
at RenderingModes.VertexBufferObjectDemo.main(VertexBufferObjectDemo.java:107)
Exception in thread "main" java.lang.NullPointerException
at RenderingModes.VertexBufferObjectDemo.main(VertexBufferObjectDemo.java:116)
is my image in the right place? In the same package.
Put it here:
For: [icode]new File(“ufo.png”)[/icode]
./project/ufo.png
./project/source/
./project/binaries/

Put it here:
For: [icode]new File(“ufo.png”)[/icode]
./project/ufo.png ./project/source/ ./project/binaries/
I don’t get what you mean by this but I tried dragging the image into the project itself and it didn’t work. I also tried putting it in the src folder alone, and still, it could not find it.