Create a 2D Texture pixel data

Started by Cornix, February 20, 2013, 22:28:39

Previous topic - Next topic

quew8

Really sorry, GLException is one of my own classes and the float buffer from array is a utility method of mine. I should have remembered to remove these. Sorry again.
You also have to change the type argument in glTexImage2D from GL_UNSIGNED_BYTE to GL_FLOAT

Cornix

This was the code i used:
final ByteBuffer byteBuf = ByteBuffer.allocateDirect(width * height * 16);
		byteBuf.order(ByteOrder.nativeOrder());
		final FloatBuffer floatBuf = byteBuf.asFloatBuffer();
		for (int y = 0; y < this.height; y++){
			for (int x = 0; x < this.width; x++){
				floatBuf.put(pixel_data[x][y][0]);
				floatBuf.put(pixel_data[x][y][1]);
				floatBuf.put(pixel_data[x][y][2]);
				floatBuf.put(pixel_data[x][y][3]);
			}
		}
		floatBuf.flip();
//		FloatBuffer fb = BufferUtils.createFloatBuffer(width * height * 4);
//		for (int y = 0; y < this.height; y++){
//			for (int x = 0; x < this.width; x++){
//				fb.put(pixel_data[x][y][0]);
//				fb.put(pixel_data[x][y][1]);
//				fb.put(pixel_data[x][y][2]);
//				fb.put(pixel_data[x][y][3]);
//			}
//		}
//		fb.flip();
		
		this.texture_id = GL11.glGenTextures();
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.texture_id);
		set_filter(true, min_filter);
		set_filter(false, mag_filter);
		set_wrap(true, horizontal_wrap);
		set_wrap(false, vertical_wrap);
		GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, this.width, this.height, 0, GL11.GL_RGBA, GL11.GL_FLOAT, floatBuf);

The commented part uses the bufferUtils from lwjgl, it also does not work.
I just cant get any other color but pure white, no matter what i input.

Could maybe somebody try this exact code of mine on his/her machine? Although i highly doubt it it might be hardware related.

abcdef

Can you post some values of you texture data? I can't help but think this is the problem

Cornix

Quote from: abcdef on February 27, 2013, 09:54:18
Can you post some values of you texture data? I can't help but think this is the problem

Here is what i did:
byte[][][] pixel_data = new byte[2][2][4];
		byte i = 0;
		for (int x = 0; x < pixel_data.length; x++){
			for (int y = 0; y < pixel_data[0].length; y++){
				pixel_data[x][y][0] = i;
				pixel_data[x][y][1] = i;
				pixel_data[x][y][2] = i;
				pixel_data[x][y][3] = i;
				i++;
			}
		}
		tex = new CsTexture2D(pixel_data, CsTexture2D.Filter_Mode.NEAREST, CsTexture2D.Filter_Mode.NEAREST, CsTexture2D.Wrap_Mode.REPEAT, CsTexture2D.Wrap_Mode.REPEAT);
		System.out.println(tex.toString());


with
public String test(){
		ByteBuffer buffer = BufferUtils.createByteBuffer(4 * width * height);
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.texture_id);
		GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
		byte[] data = new byte[buffer.limit()];
		buffer.get(data);
		buffer.clear();
		return Arrays.toString(data);
	}


And the output is:
Quote[0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 1, 1, 3, 3, 3, 3]

But the texture looks all pure white.

abcdef

Your alpha number (RGBA...(A part))  has values 0,1,2,3.

Because you are doing GL_UNSIGNED_BYTE you are effectively treating the values like integers. Of course opengl clamps the values to [0,1] but you are passing integers so opengl takes the integer range [0,255] and normalised it to [0,1]

You alpha values therefore map to 0,0.004,0.008,0.012 (basically all close to 0), this means you are almost transparent

Secondly your colors map to  (0,0,0),(0.004,0.004,0.004),...etc. These are so close to all being black. If you want to make it all red then you need to use (255,0,0,1)

Fool Running

Try adding the following to your initialization code:
GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

I think there is some bad texture blending going on.

EDIT: Also, if you are still doing the following:
GL11.glMatrixMode(GL11.GL_TEXTURE);
GL11.glLoadIdentity();
GL11.glScalef(this.scale_width, this.scale_height, 1);

The GL_TEXTURE should be GL_TEXTURE_MATRIX and you probably should switch back to the GL_MODELVIEW_MATRIX when you are done with your texture scaling.
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

Cornix

Thank you both for the replies!

Quote from: abcdef on February 27, 2013, 13:36:44
Your alpha number (RGBA...(A part))  has values 0,1,2,3.

Because you are doing GL_UNSIGNED_BYTE you are effectively treating the values like integers. Of course opengl clamps the values to [0,1] but you are passing integers so opengl takes the integer range [0,255] and normalised it to [0,1]

You alpha values therefore map to 0,0.004,0.008,0.012 (basically all close to 0), this means you are almost transparent

Secondly your colors map to  (0,0,0),(0.004,0.004,0.004),...etc. These are so close to all being black. If you want to make it all red then you need to use (255,0,0,1)
I know the colors in that example were a bad choice, but believe me, i have tested this with many, many different variations and all kinds of input. It has always been the same white square, with no value has there been any change.

Quote from: Fool Running on February 27, 2013, 14:16:50EDIT: Also, if you are still doing the following:
GL11.glMatrixMode(GL11.GL_TEXTURE);
GL11.glLoadIdentity();
GL11.glScalef(this.scale_width, this.scale_height, 1);

The GL_TEXTURE should be GL_TEXTURE_MATRIX and you probably should switch back to the GL_MODELVIEW_MATRIX when you are done with your texture scaling.
Could you elaborate a little bit more on this? I have been using "GL11.glMatrixMode(GL11.GL_TEXTURE);" for quite some time now and never had any trouble with it. What exactly would be different using "GL11.glMatrixMode(GL11.GL_TEXTURE_MATRIX );"? I am eager to learn more about it.
Also, for what purpose do i need to switch back to the modelview-matrix? I havent done it ever before, it would be nice to know before the next problem emerges.


Quote from: Fool Running on February 27, 2013, 14:16:50
Try adding the following to your initialization code:
GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

I think there is some bad texture blending going on.
I did that, and now finally something changed!
At first i saw nothing, the screen was complete black and nothing was drawn at all.
But then i started to draw a pure white square first and then my own texture and now i can see a grey square instead of a white one.

So i played around a little bit with the blend-functions and i set it to "GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ZERO);" and now i can actually change the color of the square. Before it was only grey, always, no matter what i used as input.
But of course, i can not keep using "GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ZERO);", so, if any of you knows a reason why this is happening i would be happy to hear about it.

Fool Running

Quote from: Cornix on February 27, 2013, 15:24:59
Quote from: Fool Running on February 27, 2013, 14:16:50EDIT: Also, if you are still doing the following:
GL11.glMatrixMode(GL11.GL_TEXTURE);
GL11.glLoadIdentity();
GL11.glScalef(this.scale_width, this.scale_height, 1);

The GL_TEXTURE should be GL_TEXTURE_MATRIX and you probably should switch back to the GL_MODELVIEW_MATRIX when you are done with your texture scaling.
Could you elaborate a little bit more on this? I have been using "GL11.glMatrixMode(GL11.GL_TEXTURE);" for quite some time now and never had any trouble with it. What exactly would be different using "GL11.glMatrixMode(GL11.GL_TEXTURE_MATRIX );"? I am eager to learn more about it.
Also, for what purpose do i need to switch back to the modelview-matrix? I havent done it ever before, it would be nice to know before the next problem emerges.
Sorry, I confused myself. :-\ GL_TEXTURE is correct. GL_TEXTURE_MATRIX is for retrieving the current texture matrix. Also, I meant you should switch back to GL11.glMatrixMode(GL_MODELVIEW) and not GL_MODELVIEW_MATRIX (also used for retrieving the current matrix). If you don't switch back to the GL_MODELVIEW matrix, then any other changes you do to the matrix (glTranslate(), glRotate(), etc.) will change the texture matrix instead of the modelview matrix. You aren't doing anything like that, yet, but you probably will eventually.

I tried to get your code working. Without the texture scaling code, it works fine for me:
EDIT: Got it to work with the scaling:
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;


public class TestIt
{
	Tex2D tex;
	int width, height;
	
	public static void main(String[] args) {
		TestIt game = new TestIt();
		game.init();
		game.loop();
	}

	private void loop() {
		while(!Display.isCloseRequested())
		{
			//DRAW
			GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); 
			GL11.glLoadIdentity();
			
			tex.bind();
			GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
			GL11.glBegin(GL11.GL_QUADS);
				GL11.glTexCoord2f(0.0f, 0.0f);
					GL11.glVertex2f((width - 150)/2, 10f);
				GL11.glTexCoord2f(10.0f, 0.0f);
					GL11.glVertex2f((width + 150)/2, 10f);
				GL11.glTexCoord2f(10.0f, 10.0f);
					GL11.glVertex2f((width + 150)/2, 150 + 10);
				GL11.glTexCoord2f(0.0f, 10.0f);
					GL11.glVertex2f((width - 150)/2, 150 + 10);
			GL11.glEnd();
			
			Display.update();
			Display.sync(60);
		}
		Display.destroy();
	}

	private void init() {
		//Display
		try {
			Display.setTitle("Initialising...");
			Display.setFullscreen(false);
			Display.create();
			
			GL11.glMatrixMode(GL11.GL_PROJECTION);
			GL11.glLoadIdentity();
			
			width = Display.getDisplayMode().getWidth();
			height = Display.getDisplayMode().getHeight();
			GL11.glOrtho(0, width, height, 0, -1, 1);
			
			GL11.glMatrixMode(GL11.GL_MODELVIEW);
			GL11.glLoadIdentity();
			
			GL11.glEnable(GL11.GL_TEXTURE_2D);
			GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
			GL11.glEnable(GL11.GL_BLEND);
			GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
			
			byte[][][] pixel_data = new byte[16][16][4];
			int i = 0;
			for (int x = 0; x < pixel_data.length; x++){
				for (int y = 0; y < pixel_data[0].length; y++){
					pixel_data[x][y][0] = (byte)(Math.random() * 255);
					pixel_data[x][y][1] = (byte)(Math.random() * 255);
					pixel_data[x][y][2] = (byte)(Math.random() * 255);
					pixel_data[x][y][3] = (byte)(i % 0xFF);
					i++;
				}
			}
			tex = new Tex2D(pixel_data, Tex2D.Filter_Mode.NEAREST, 
					Tex2D.Filter_Mode.NEAREST, Tex2D.Wrap_Mode.REPEAT, 
					Tex2D.Wrap_Mode.REPEAT);
			
		} catch(LWJGLException e) {
			e.printStackTrace();
			System.exit(0);
		}
	}

}

and
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Arrays;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL14;
import org.lwjgl.util.Color;


public class Tex2D
{
	private final float scale_width;
	private final float scale_height;
	private final int width;
	private final int height;
	private final int texture_id;
	
	public Tex2D(final byte[][][] pixel_data, final Filter_Mode min_filter, 
			final Filter_Mode mag_filter, final Wrap_Mode vertical_wrap, 
			final Wrap_Mode horizontal_wrap){
		int w;
		int h;
		w = pixel_data.length;
		if (w == 0){
			throw new TextureSizeException("Can not create texture with width of 0");
		}else{
			h = pixel_data[0].length;
			if (h == 0){
				throw new TextureSizeException("Can not create texture with height of 0");
			}
		}
		if (!is_power_of_two(w)){
			w = next_power_of_two(w);
		}
		if (!is_power_of_two(h)){
			h = next_power_of_two(h);
		}
		this.width = w;
		this.height = h;
		this.scale_width = 1f / this.width;
		this.scale_height = 1f / this.height;
		
		final ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4).order(ByteOrder.nativeOrder());
		for (int y = 0; y < this.height; y++){
			for (int x = 0; x < this.width; x++){
				buf.put(pixel_data[x][y][0]);
				buf.put(pixel_data[x][y][1]);
				buf.put(pixel_data[x][y][2]);
				buf.put(pixel_data[x][y][3]);
			}
		}
		buf.flip();
		
		this.texture_id = GL11.glGenTextures();
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.texture_id);
		set_filter(true, min_filter);
		set_filter(false, mag_filter);
		set_wrap(true, horizontal_wrap);
		set_wrap(false, vertical_wrap);
		GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, this.width, this.height, 
				0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buf);
	}
	
	public void print_buffer(){
		ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4);
		buf.order(ByteOrder.nativeOrder());
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.texture_id);
		GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buf);
		byte[] data = new byte[buf.limit()];
		buf.get(data);
		buf.clear();
		System.out.println(Arrays.toString(data));
	}
	
	public void bind(){
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.texture_id);
		GL11.glMatrixMode(GL11.GL_TEXTURE);
		GL11.glLoadIdentity();
		GL11.glScalef(this.scale_width, this.scale_height, 1);
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
	}
	
	public void remove(){
		IntBuffer texBuf = ByteBuffer.allocateDirect(4).asIntBuffer();
		texBuf.put(this.texture_id);
		texBuf.flip();
		GL11.glDeleteTextures(texBuf);
	}
	
	private static final int next_power_of_two(int value){
		value--;
		value |= value >> 1;
		value |= value >> 2;
		value |= value >> 4;
		value |= value >> 8;
		value |= value >> 16;
		value++;
		return value;
	}
	
	private static final boolean is_power_of_two(final int value){
		return (value & (~value + 1)) == value;
	}
	
	private static final void set_wrap(final boolean horizontal, final Wrap_Mode wrap){
		final int type = horizontal ? GL11.GL_TEXTURE_WRAP_S : GL11.GL_TEXTURE_WRAP_T;
		switch (wrap){
		case REPEAT :
			GL11.glTexParameteri(GL11.GL_TEXTURE_2D, type, GL11.GL_REPEAT);
			break;
		case MIRRORED_REPEAT :
			GL11.glTexParameteri(GL11.GL_TEXTURE_2D, type, GL14.GL_MIRRORED_REPEAT);
			break;
		case CLAMP :
			GL11.glTexParameteri(GL11.GL_TEXTURE_2D, type, GL11.GL_CLAMP);
			break;
		case CLAMP_TO_BORDER :
			GL11.glTexParameteri(GL11.GL_TEXTURE_2D, type, GL13.GL_CLAMP_TO_BORDER);
			break;
		case CLAMP_TO_EDGE :
			GL11.glTexParameteri(GL11.GL_TEXTURE_2D, type, GL12.GL_CLAMP_TO_EDGE);
			break;
		}
	}
	
	private static final void set_filter(final boolean min, final Filter_Mode filter){
		final int type = min ? GL11.GL_TEXTURE_MIN_FILTER : GL11.GL_TEXTURE_MAG_FILTER;
		switch (filter){
		case LINEAR :
			GL11.glTexParameteri(GL11.GL_TEXTURE_2D, type, GL11.GL_LINEAR);
			break;
		case NEAREST :
			GL11.glTexParameteri(GL11.GL_TEXTURE_2D, type, GL11.GL_NEAREST);
			break;
		}
	}
	
	public static enum Filter_Mode {
		LINEAR, NEAREST;
	}
	
	public static enum Wrap_Mode {
		REPEAT, MIRRORED_REPEAT, CLAMP, CLAMP_TO_BORDER, CLAMP_TO_EDGE;
	}
	
	private static final class TextureSizeException extends RuntimeException{
		private static final long serialVersionUID = -8911712330468875206L;
		public TextureSizeException(String string) {
			super(string);
		}
	}
}
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

Cornix

Your program works for me, i will look into this and see what the difference between yours and mine is.
Thank you very much, this will be a great help.

Cornix

Wow, i feel so stupid now. I really do.
As it seems the only problem was, that i forgot to enable 2D-Textures in my testing enviroment. T_T
All this trouble because of such a little mistake, i am sorry guys.

But thank you all, once again, for the awesome help.