Reputation: 92
I just got a test texture working in my LWJGL code using an array of float
s. Now, though, I need to load an image from a file and store it in the texture. I have gotten the image loaded and the data into a ByteBuffer
object, but when I use glTexImage2D
like so:
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB,
4, 4, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer);
the texture is empty and will render as completely black. I've looked at how other people do this but nothing seems to be helping... The function call is also the same as with the float
array, except for the type parameter, of course. And yes, my image is RGB and yes, it's 4x4. There's probably something really simple I'm not getting, so any help is appreciated.
Full working test program:
static org.lwjgl.system.MemoryUtil.NULL;
import java.nio.ByteBuffer;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
public class Example {
public static void main(String[] args) {
if (!GLFW.glfwInit()) {
throw new IllegalStateException("Unable to initialize GLFW");
}
// Create a window as the GL context
long window = GLFW.glfwCreateWindow(100, 100, "", NULL, NULL);
if (window == NULL) {
GLFW.glfwTerminate();
throw new RuntimeException("Failed to create the GLFW window");
}
GLFW.glfwMakeContextCurrent(window);
GL.createCapabilities();
// Generate the texture and set parameters
int textureID = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
// A byte array of 4x4 RBG values
byte[] data = new byte[] {
127, 127, 0, 127, 127, 0, 127, 127, 0, 127, 127, 0,
127, 127, 0, 127, 127, 0, 127, 127, 0, 127, 127, 0,
127, 127, 0, 127, 127, 0, 127, 127, 0, 127, 127, 0,
127, 127, 0, 127, 127, 0, 127, 127, 0, 127, 127, 0,
};
ByteBuffer buffer = ByteBuffer.wrap(data);
// Load the data to the texture
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, 4, 4, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer);
// glGetError returns 0.
// Test if the buffer data is correctly stored in the texture.
// I have unrelated problems while getting the data using a
// ByteBuffer, so it's a float array for debug purposes.
float[] floats = new float[data.length];
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, GL11.GL_FLOAT, floats);
// glGetError returns 0.
for (float f : floats) {
System.out.println(f);
}
// Expected output is 16 times the following:
// 0.5
// 0.5
// 0.0
// Actual output: Random (garbage?) values
// Examples:
// 0.003921569
// 0.87843144
// 1.0
}
}
This reproduced the problem for me. Usual LWJGL libs (lwjgl, opengl and glfw) are needed for this. As mentioned in the code comments, glGetError
returns zero after each GL call.
Upvotes: 2
Views: 1353
Reputation: 7180
You should read this wiki and then use "Stack Allocation" or MemoryUtil
class.
There is actually an even faster method. When you know that you won't never exceed a given quantity per frame, you can allocate it just once, and then use for all your short lived allocations, like that one required by your texture. And then after each frame, you will clear the whole buffer.
I have applied exactly this concept in one of my project
Upvotes: 0
Reputation: 211219
If you use
ByteBuffer buffer = ByteBuffer.wrap(data);
the the buffer is not "direct".
You have to use BufferUtils.createByteBuffer
:
ByteBuffer buffer = BufferUtils.createByteBuffer(data.length);
buffer.put(data);
buffer.flip();
Explanation:
BufferUtils.createByteBuffer
allocates a direct native-ordered bytebuffer with the specified capacity.
put(vboData)
transfers the the data to the buffer, beginning at the current position (which is the start of the buffer in this case). The buffer position is incremented by the size of the data. So the new buffer position is at the end of the new data.
flip()
sets the limit (length) of the buffer to the current position and then the position is set to zero.
Upvotes: 2