Is there a better way to flip texture in OpenGL

Started by
4 comments, last by L. Spiro 9 years, 5 months ago

I am using LWJGL and Slick-util to make a game. I made a helper class TextureAtlas, which helps me draw parts of image (to avoid unnecessary binding).

I managed to create it the following way:


public class TextureAtlas {
	private Texture tex;

	public TextureAtlas(String fileName) {
		try {
			tex = TextureLoader.getTexture("PNG",
					ResourceLoader.getResourceAsStream(fileName));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println("Added texture \"" + fileName + "\" with id: "
				+ tex.getTextureID());
	}

	public void bind() {
		tex.bind();
	}
	
	public void draw(int x, int y, int width, int height, float xp, float yp,
			boolean flipHorz, boolean flipVert) {
		float spriteX = (float) x / (float) tex.getTextureWidth();
		float spriteY = (float) y / (float) tex.getTextureHeight();

		float spriteWidth = (float) width / (float) tex.getTextureWidth();
		float spriteHeight = (float) height / (float) tex.getTextureHeight();

		float spriteX2 = spriteX + spriteWidth;
		float spriteY2 = spriteY + spriteHeight;

		if (flipHorz) {
			float tmp = spriteX;
			spriteX = spriteX2;
			spriteX2 = tmp;
		}

		if (flipVert) {
			float tmp = spriteY;
			spriteY = spriteY2;
			spriteY2 = tmp;
		}

		glBegin(GL_QUADS);
		glTexCoord2f(spriteX, spriteY);
		glVertex2f(xp, yp);

		glTexCoord2f(spriteX2, spriteY);
		glVertex2f(xp + (float) width, yp);

		glTexCoord2f(spriteX2, spriteY2);
		glVertex2f(xp + (float) width, yp + (float) height);

		glTexCoord2f(spriteX, spriteY2);
		glVertex2f(xp, yp + (float) height);

		glEnd();

	}
}

And then when drawing:


TextureAtlas atlas = new TextureAtlas("res/atlas.png");
atlas.bind();

// in game loop:
atlas.draw(0, 0, 16, 16, 0.0f, 0.0f, true, false); // flips horizontal

It works and there are no performance drops, but I still think it's not good. I mean, two if-s and six temporary variables for one sprite! And I plan on having lots of sprites in my game. Is there a better way to do this? By shaders or something?

Thanks

Mateja

Advertisement

You can scale the 3D object by -1 in the horizontal axis and the result will be mirrored on that axis.

Anyway, why are you concerned about 2 ifs and some variables? You said your plan is to have lots of sprites so it sounds it's about performance, do you know if those if's and some temporary variables will have an impact?

For the if's, half of the times (or maybe less) the condition will be false, and it's a simple boolean check, so it costs nothing. For the cases where the sprite should be flipped, inside that if you're just moving some variables, it's also a pretty fast operation. The rest of the variables look like necessary even for non flipped sprites.

I know it won't make big (if any) performance difference, but the code looks messy to me. I thought there might be another way.

And about scaling by -1, then the coordinates are translated by -width / -height so I still need to use ifs to correct them, then to calculate the reversed coordinates of image part...

I think I'll stick with my code for now :)

Yes, you'll need to correct the position, scaling has less issues if the quad's center is at the origin. Anyway, it doesn't look messy (you're not doing any unnecessary step), but maybe you can rename "spriteX" and "spriteX2" to "spriteLeft" and "spriteRight". The same with "spriteY" and "spriteY2" as "spriteTop" and "spriteBottom"... or just "left", "right", "top" and "bottom", and the code will look cleaner.

Well, you could get rid of the if's with a few tweaks and some math tricks. Something like (note: untested, but you should get the idea):


public void draw(int x, int y, int width, int height, float xp, float yp,
            float xdirection, float ydirection) {
        x = x + ( 1.0f - xdirection ) / 2.0f * (float) width;
        float spriteX = (float) x / (float) tex.getTextureWidth();
        y = y + ( 1.0f - ydirection ) / 2.0f * (float) height;
        float spriteY = (float) y / (float) tex.getTextureHeight();

        float spriteWidth = (float) width / (float) tex.getTextureWidth();
        float spriteHeight = (float) height / (float) tex.getTextureHeight();

        float spriteX2 = spriteX + xdirection * spriteWidth;
        float spriteY2 = spriteY + ydirection * spriteHeight;

...

then:


// in game loop:
atlas.draw(0, 0, 16, 16, 0.0f, 0.0f, -1.0f, 1.0f); // flips horizontal

I'm not entirely sure this will be any faster than just using the 2 if statements, though. You'd want to test and be sure.

Hmm, thinking more... you could probably pre-compute all this stuff, as well, and save all of the floating point math. Presumably right now for a sprite you are storing x, y, width, height, flipHoriz, and flipVert. If you store spriteX, spriteY, spriteX2, and spriteY2, then you only calculate them once, not every rendering loop. That seems like the best option if performance is an issue.

Just some thoughts!

Geoff

You are using immediate mode. A few if’s are the absolute least of your concerns.

Use VBO’s and IBO’s.

Batch.

Double-buffer and update an IBO properly.

It’s absolutely crazy to worry about branching when you haven’t even done the most important optimizations yet.

L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

This topic is closed to new replies.

Advertisement