/*
* I've been trying and failing to get an -exact- blit of a 2D sprite and have boiled it down to this:
*
* This example makes and draws a 16x16 texture of rgb:f2/f2/f2
* resulting in a 16x16 on-screen box of an entirely different colour: rgb:ef/f3/ef
* which is very strange!
*
* Please help a noob who's pulling his hair out and point out what I'm not seeing :)
*/
import java.nio.ByteBuffer;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
public class TextureExample {
private static final int SCREEN_HEIGHT = 600;
private static final int SCREEN_WIDTH = 800;
private static final int TEXTURE_WIDTH = 16;
private static final int TEXTURE_HEIGHT = 16;
private static final int TEXTURE_PIXELS = TEXTURE_WIDTH * TEXTURE_HEIGHT;
private static final int TEXTURE_CHANNELS = 3;
private static final int TEXTURE_BUFFER_SIZE = TEXTURE_CHANNELS * TEXTURE_PIXELS;
private int textureId;
private void bindTexture() {
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
}
private void initLwjglDisplay() {
try {
Display.setDisplayMode(new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT));
Display.create();
Display.setVSyncEnabled(true);
}
catch (LWJGLException e) {
throw new RuntimeException(e);
}
}
private void initOpenGL() {
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// GL11.glEnable(GL11.GL_BLEND);
// GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glDisable(GL11.GL_BLEND);
GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_DECAL);
GL11.glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glDisable(GL11.GL_DITHER);
}
private void initTexture() {
textureId = GL11.glGenTextures();
bindTexture();
ByteBuffer buffer = ByteBuffer.allocateDirect(TEXTURE_BUFFER_SIZE);
for (int x = 0; x < TEXTURE_PIXELS; x++) {
for (int c = 0; c < TEXTURE_CHANNELS; c++) {
buffer.put((byte) 0x0f2);
}
}
buffer.rewind();
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB8, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0,
GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer);
}
/**
* Draw a quad with the texture on it.
*/
private void render() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
bindTexture();
float destination = 100f;
int scale = 1;
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(destination, destination);
GL11.glTexCoord2f(1, 0);
GL11.glVertex2f(destination + TEXTURE_WIDTH * scale, destination);
GL11.glTexCoord2f(1, 1);
GL11.glVertex2f(destination + TEXTURE_WIDTH * scale, destination + TEXTURE_HEIGHT * scale);
GL11.glTexCoord2f(0, 1);
GL11.glVertex2f(destination, destination + TEXTURE_HEIGHT * scale);
GL11.glEnd();
}
private void startTheExample() {
initLwjglDisplay();
initOpenGL();
initTexture();
while (true) {
render();
Display.update();
Display.sync(10);
if (Display.isCloseRequested()) {
Display.destroy();
break;
}
}
}
public static void main(String[] argv) {
TextureExample textureExample = new TextureExample();
textureExample.startTheExample();
}
}
I've been trying and failing to get an exact blit of a 2D sprite.
My code was originally based on.
http://lwjgl.org/wiki/index.php?title=Slick-Util_Library_-_Part_1_-_Loading_Images_for_LWJGL (http://lwjgl.org/wiki/index.php?title=Slick-Util_Library_-_Part_1_-_Loading_Images_for_LWJGL)
That was not exact although it improved a lot when I added:
GL11.glDisable(GL11.GL_DITHER);
After that it still wasn't exact. e.g. 248/256 shades of gray came through with a colour change - mostly slightly towards purple(??)
I thought it might be the "Slick" library image-loading that was at fault so I generated the texture in code and removed Slick - one less thing to be suspicious of. Then I reduced it to just a single color (rgb:f2/f2/f2) "texture" (the code you see above) but it drew as rgb:ef/f3/ef ???
I could go simpler still and forget further about my original 2D sprite mission and forget about textures and regress to just painting an rgb:f2/f2/f2 quad. Surely that will work ...
float colorValue = ((float)0xf2)/((float)0xff);
GL11.glColor4f(colorValue,colorValue,colorValue,0.0f);
// paint the quad
But no :( that comes out as rgb:ef/f3/ef too! I can see there must be something astonishingly basic that I'm not getting here about how colors work in OpenGL :-\
Hmm - strange. TWL does 1:1 pixel rendering of textures - you might want to check how your textures are displayed when you load them in the Theme editor (http://twl.l33tlabs.org/themer/themer.jnlp).
It could also be related to some gamma settings etc.
Perhaps the very outside pixel colors are crossing over or something.
Try a 32x32 image with a 16x16 image inside (pad with black pixels and make black transparent), or just try a 2 pixel border around the image.
Thank you for your suggestions but, digging around, the problem seems more about
colors than
textures. I've solved it -- well, kind of ... :-\
My "game" runs in a window on my 16bit true-color desktop. The color I want (namely rgb:f2/f2/f2) is a valid 12-bit color and is possible on my 16-bit true-color desktop. I can fire up Photoshop and draw a box of it onto a screenshot of my game right next to the place where my game failed to draw the box of it and only managed to draw rgb:ef/f3/ef instead. :(
However, raising my desktop to 32bit true-color fixes it and my game is suddenly able to do what, before, I could only do in Photoshop. It can suddenly draw a box of rgb:f2/f2/f2 for the first time just as my Java code asks it to. :)
In summary:
- In 32bit true-color rgb:f2/f2/f2 is available and when my code requests it it gets it.
In 16bit true-color rgb:f2/f2/f2 is available and when my code requests it it gets rgb:ef/f3/ef instead.
More generally speaking, 248/256 of 12bit grayscales, though all available, do not draw correctly (though they all do in 32bit).
So that is how it works ... but why? ???
Drawing a quad on a black background its more than you need to show this problem. Just clearing the screen will do ...
public class ColorBox {
private static final int SCREEN_HEIGHT = 600;
private static final int SCREEN_WIDTH = 800;
private void initLwjglDisplay() {
try {
Display.setDisplayMode(new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT));
Display.create();
Display.setVSyncEnabled(true);
}
catch (LWJGLException e) {
throw new RuntimeException(e);
}
}
private void initOpenGL() {
float colorValue = ((float)0xf2)/((float)0xff);
GL11.glClearColor(colorValue, colorValue, colorValue, 0.0f);
}
private void render() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
}
private void startTheExample() {
initLwjglDisplay();
initOpenGL();
while (true) {
render();
Display.update();
Display.sync(10);
if (Display.isCloseRequested()) {
Display.destroy();
break;
}
}
}
public static void main(String[] argv) {
ColorBox cb= new ColorBox();
cb.startTheExample();
}
}
Be lucky that it works in 16 bit color mode at all - most 3D hardware can't do 16 bit at all.
Hang on. I think I've got confused between 12bit and 24bit color somewhere along the way. I started off with 12bit graphics from my Amiga. 0x0RGB. As PNM files those are #R0G0B0 but that doesn't use the whole color range so its common to scale it up to #RRGGBB so that white is #FFFFFF rather than #F0F0F0. However, all of a sudden we're talking 24bit color. Of course some of these don't come out right on a 16bit display! Photoshop didn't help by dithering to make it seem as if #F2F2F2 is available in a 16bit display when it can't be.
OpenGL tells me the bits 16bits are allocated r=5/g=6/b=5 btw.
int r = GL11.glGetInteger(GL11.GL_RED_BITS);
int g = GL11.glGetInteger(GL11.GL_GREEN_BITS);
int b = GL11.glGetInteger(GL11.GL_BLUE_BITS);
System.out.println("colour bits:");
System.out.println(r);
System.out.println(g);
System.out.println(b);
I'll revisit this tomorrow with my head on straight :D
zzzzzz