LWJGL/Slick texture wrapping

Started by Bingo90, September 02, 2013, 08:03:42

Previous topic - Next topic

Bingo90

When using the drawing code below, some pixels seem to wrap from the back to the front of a texture. I don't know how to fix this, is there a solution?    

public class MainDisplay
{
	public void run() throws LWJGLException
	{
		Game.init();
		
		int width = 800, height = 600;
		
		Display.setDisplayMode(new DisplayMode(800,600));
		Display.setTitle("2D Game Java Test");
	    Display.create();
		
		glEnable(GL11.GL_TEXTURE_2D);

		glEnable(GL11.GL_BLEND);
		glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
		glViewport(0, 0, width, height);
		glMatrixMode(GL11.GL_MODELVIEW);

		glMatrixMode(GL11.GL_PROJECTION);
		glLoadIdentity();
		glOrtho(0, width, height, 0, 1, -1);
		glMatrixMode(GL11.GL_MODELVIEW);
		
		init();
		
		long time = System.nanoTime();

		while (!Display.isCloseRequested())
		{
			
			float deltaSeconds = ((float)(System.nanoTime()-time))/1000000000f;
			time = System.nanoTime();
			Game.update(deltaSeconds);
			
			
			Game.draw();  //In there's the drawing code. 
                           

			
			try
			{
				Thread.sleep(1000/500);
			} catch (InterruptedException e)
			{
				e.printStackTrace();
			}

			Display.update();
		}

		Display.destroy();
	}
	public void init()
	{
		TextureManager.loadContent();
	}
}



public static void drawTexture(Texture texture, Vector2f position, Vector2f translation, Vector2f origin,Vector2f scale,float rotation, Color color, FlipState flipState)
	{
		texture.setTextureFilter(GL11.GL_NEAREST);


		color.bind();
		texture.bind();

		
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
    	GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
		
		GL11.glTranslatef((int)position.x, (int)position.y, 0);
		GL11.glTranslatef(-(int)translation.x, -(int)translation.y, 0);
		GL11.glRotated(rotation, 0f, 0f, 1f);
		
		GL11.glScalef(scale.x, scale.y, 1);
		
		GL11.glTranslatef(-(int)origin.x, -(int)origin.y, 0);
		
		
		GL11.glBegin(GL11.GL_QUADS);
		GL11.glTexCoord2f(0,0);
		GL11.glVertex2f(0,0);
		GL11.glTexCoord2f(1,0);
		GL11.glVertex2f(texture.getTextureWidth(),0);
		GL11.glTexCoord2f(1,1);
		GL11.glVertex2f(texture.getTextureWidth(),texture.getTextureHeight());
		GL11.glTexCoord2f(0,1);
		GL11.glVertex2f(0,texture.getTextureHeight());
	
		GL11.glEnd();
		
		GL11.glLoadIdentity();
	}


The wrapping mentioned above:


Fool Running

You need to specify the GL_CLAMP_TO_EDGE when you create the texture, not when you use it.
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

Bingo90

Okay I'm using this method to load a texture

public static Texture loadTexture(String fileName)
	{
		
		
		Texture texture = null;
		try
		{
			InputStream stream = ClassLoader.getSystemResourceAsStream(fileName);
			
			if(stream!=null)
			{
				texture = TextureLoader.getTexture("PNG",stream);
				System.out.println("Texture loaded: " + fileName+" Width: "+texture.getImageWidth()+" Height: "+texture.getImageHeight());
			}
			else
			{
				System.out.println(String.format("File \"%s\" doesn't exist and wasn't loaded.",fileName));
			}
		}
		catch (Exception e)
		{
			System.out.println(String.format("Error loading %s: %s",fileName,e.toString()));			
		}
		
		
		return texture;
	}

Fool Running

I shouldn't try help people when I'm tired. You can change the texture wrapping at any time. :-[

I should have said what I was going to, originally:
I can't see the picture. Are you saying that you are seeing the texture image on the back and the front of the polygon, or that the texture is repeating itself over the polygon? Is your texture a power-of-two size (on the x and y axis)?
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

Bingo90

I don't know why the image isn't showing up on the first post :/ Well here's a link to the image showing the problem http://i.imgur.com/6TQu9oQ.png

Fool Running

Well, nothing is jumping out at me as being wrong with your code. What happens if you use GL11.GL_CLAMP instead of GL12.GL_CLAMP_TO_EDGE?
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D


Bingo90

Updated the code. Maybe the MainDisplay class could help. Also, I fixed the link to the image.

quew8

My solution to this problem is just to add a 1 pixel, 0 alpha border on the top and right edges. It's not a pretty solution but it gets the job done. If your worried about file sizes of your images you can even add it in when you load it in software.

Bingo90

Besides the code I've shown I've got a lot of other code and I don't want to change it because of this. Isn't there another way?

quew8

For the record, this effect is called texture bleeding so if you don't like my answer, search that and you'll get thousands of solutions.

Firstly, I just want to check that you aren't using mipmapping. You're are in 2D so it doesn't make any sense to, but some people do out of force of habit or just because they haven't thought it through (which is understandable). As I've said I just add a border and be done with it, but the best solution I've heard of, off the top of my head, is half pixel correction.

Normally your tex coords are actually on the border between to pixels. Imagine a 100 pixel wide (1D for simplicity) texture. You sprite starts at the 7th pixel, so your tex coord is 0.07 right? But that position is actually the start of the 7th pixel which in reality is the border between the 6th and 7th pixel. So when OpenGL wants to sample at 0.07, it blends the 6th and 7th pixels together. The solution is to set the tex coord to the centre of the 7th pixel rather than the start. So 7.5 / 100 = 0.075. So a general formula for the nth pixel in an w wide texture (still 1D) is (n + 0.5) / w, right?

But what if the end of you sprite is the 19th pixel, then (19 + 0.5) / 100 is 0.195. Except that is the centre of the 20th pixel. It should be (19 - 0.5) / 100 is 0.185. So you see the problem with this method. When you work out the tex coords (this is mainly a problem for dynamic texture atlases), you need to know where in the sprite that tex coord comes from. Not a massive problem, just watch out for it.

Bingo90

I tried to turn mipmapping off but it didn't work (I haven't turned it on anywhere so it seems to be off by default). But why doesn't the clamping work? Shouldn't it fix the problem?

quew8

All clamp does is clamp the texture coords. So if your tex coords are (0, 0), (0, 1), (1, 1), and (1, 0), then it will make absolutely no difference. And as I explained above tex coord 1 is a blend between the last texel and the first texel.

Mipmapping is only used if you have GL_MIN_FILTER or GL_MAX_FILTER set to GL_(NEAREST | LINEAR)_MIPMAP_(NEAREST | LINEAR). If you use one of those then you have to either explicitly generate mipmaps or explicitly turn on auto generated mipmaps. So from your response I'm guessing you don't use them, which for 2D is good (99% of the time).

You could set the MIN and MAG filters to GL_NEAREST which would work some of them time, but assuming it rounds up (which it probably does), this wouldn't solve this problem. You could try it but it is NOT a 100% solution. At most it is a 50% solution.

Bingo90

Okay I'll try that.

EDIT:

Didn't work :-\ What'd be the best way that works without texture editing? What changes should I make to the code?

Cornix

Have you tried enabling a border for the texture with an invisible border color?
You could then use "clamp_to_border" as the horizontal wrap mode.

I personally have never used border color, but I guess this is the kind of situation it would be used for.