[SOLVED] Windows 7 colors problem

Started by cyril.chandelier, March 10, 2010, 18:00:02

Previous topic - Next topic

cyril.chandelier

Hi there, first at all : sorry for my "poor" english.

I recently started to use LWJGL to develop a 2D game for a school project but i'm currently encoutering a color display problem.

I use some code to textures objects with images (transparancy ON), it works fine on Linux Ubuntu and Windows XP but the colors are totally bugged on windows 7.

I attached a screenshot of the game, the pink must be yellow/orange and the blue must be transparent.

Did you ever encounter this problem ? Is there any solution ?

Thanks for your help.

Cyril.

Kai

Hi,

this sounds like you expect your images to be loaded in the RGBA-Format whereas they are actually in ABGR or some other format. If you load your images with Java ImageIO, the most likely format your get is ABGR (BufferedImage.TYPE_4BYTE_ABGR) when loading images with an alpha channel; at least that's what I experience under Windows 7.

Indicators for that are the blue color (_GB_), that should be transparent (___A) and the pink (R_B_) which should be yellow (RG__).
But looking at the RGBA-values for these colors, that does not make much sense, because they do not align with any formats.

Then, please provide us with some source code that shows how you load the images and how you setup the textures in OpenGL.

cyril.chandelier

Thanks for your time,

here is the method I did from here and there and I used to load a texture, I tried to print the result of this :

System.out.println(bufferedImage.getColorModel());


and I obtained this : (we can clearly see the problem)
ColorModel: #pixelBits = 32 numComponents = 4 color space = java.awt.color.ICC_ColorSpace@67ac19 transparency = 3 has alpha = true isAlphaPre = false


Code :
HashMap<String, BufferedImage> imageDatabase = new HashMap<String, BufferedImage>();

	private Texture loadTexture(String path, int xOffSet, int yOffSet,
			int width, int height) {

		BufferedImage bufferedImage = null;
		try {
			if (imageDatabase.get(path) != null)
				bufferedImage = (BufferedImage) imageDatabase.get(path);
			else {
				System.out.println("Chargement de l'image : " + path);
				bufferedImage = ImageIO.read(new File(path));
				imageDatabase.put(path, bufferedImage);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		int bytesPerPixel = bufferedImage.getColorModel().getPixelSize() / 8;

		ByteBuffer scratch = ByteBuffer.allocateDirect(
				width * height * bytesPerPixel).order(ByteOrder.nativeOrder());
		DataBufferByte data = ((DataBufferByte) bufferedImage.getRaster()
				.getDataBuffer());

		for (int i = 0; i < height; i++)
			scratch.put(data.getData(), (xOffSet + (yOffSet + i)
					* bufferedImage.getWidth())
					* bytesPerPixel, width * bytesPerPixel);

		scratch.rewind();

		// Create A IntBuffer For Image Address In Memory
		IntBuffer buffer = ByteBuffer.allocateDirect(4).order(
				ByteOrder.nativeOrder()).asIntBuffer();
		GL11.glGenTextures(buffer); // Create Texture In OpenGL

		// Create Nearest Filtered Texture
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, buffer.get(0));
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER,
				GL11.GL_LINEAR);
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,
				GL11.GL_LINEAR);
		GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height,
				0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, scratch);

		Texture craftedTexture = new Texture();
		craftedTexture.textureId = buffer.get(0);
		craftedTexture.textureHeight = height;
		craftedTexture.textureWidth = width;

		return craftedTexture;
	}


Kai

You can check what the result of "bufferedImage.getType()" is.
Depending of that, you can alter the OpenGL texture format (e.g. use EXTAbgr.GL_ABGR_EXT as texture format if getType() reports BufferedImage.TYPE_4BYTE_ABGR). This will give you a fast solution but might not be supported on all cards/drivers.

The other solution would be to swizzle the bytes in your "scratch" buffer.

cyril.chandelier

the result of "bufferedImage.getType()" give me a "6" and using BufferedImage.TYPE_4BYTE_ABG crash the game.

Is there any solution to fix the colors order ? Do you know why it work on linux and windows XP and not under windows 7 ?

Thanks for your time.

Cyril

Kai

the result of "bufferedImage.getType()" give me a "6" and using BufferedImage.TYPE_4BYTE_ABG crash the game.

There was some misunderstanding, I did not mean to tell OpenGL to use BufferedImage.TYPE_4BYTE_ABGR as texture format, since OpenGL does not know of AWT. I suggested, you check whether BufferedImage.getType() would return EXTAbgr.GL_ABGR_EXT (which is 6 actually) and then use the mentioned OpenGL format constant.

Again, you can try to use EXTAbgr.GL_ABGR_EXT as texture format.

cyril.chandelier

I tried to replace GL11.GL_RGBA to obtain this :
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0,EXTAbgr.GL_ABGR_EXT, width, height,
				0, EXTAbgr.GL_ABGR_EXT, GL11.GL_UNSIGNED_BYTE, scratch);


the result is an exception :
Exception in thread "main" org.lwjgl.opengl.OpenGLException: Invalid value (1281)
	at org.lwjgl.opengl.Util.checkGLError(Util.java:54)
	at org.lwjgl.opengl.GL11.glTexImage2D(GL11.java:2874)
	at textures.TextureLoader.loadTexture(TextureLoader.java:81)
	at textures.TextureLoader.init(TextureLoader.java:28)
	at game.Game.initGL(Game.java:116)
	at game.Game.<init>(Game.java:39)
	at game.Game.main(Game.java:192)

Kai

The internal format needs to remain RGBA.

Please use:

GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, EXTAbgr.GL_ABGR_EXT, GL11.GL_UNSIGNED_BYTE, scratch);

cyril.chandelier

FINE IT WORKS !

I'll check tomorrow on other operating system to see if the probleme is 100% solved.

Thanks a lot !

Cyril.

Kai

QuoteI'll check tomorrow on other operating system to see if the probleme is 100% solved.
Of course, if that problem did not occur on Linux and on Windows XP in the first place, then with ABGR format you will now have a problem there.
You need to check whether the type of the BufferedImage is ABGR and only then use that specific OpenGL format.

And just in case that extension is not supported on any machine, you can still change the byte order in your scratch buffer by reading each 4 bytes (as ABGR) and putting them back in the right order (as RGBA).

QuoteThanks a lot !
You're welcome.

cyril.chandelier

I think now the problem is solved.

Thanks again Kai.

Code to alternate according the computer color format :
if(bufferedImage.getType() == BufferedImage.TYPE_4BYTE_ABGR){
			GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, EXTAbgr.GL_ABGR_EXT, GL11.GL_UNSIGNED_BYTE, scratch);
		} else {
			GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, scratch);
		}

Matthias

Or you could just drop ImageIO and load directly into a direct ByteBuffer with eg TWL's PNGDecoder - this will be faster.