Jump to content

  • Log In with Google      Sign In   
  • Create Account

Awesome job so far everyone! Please give us your feedback on how our article efforts are going. We still need more finished articles for our May contest theme: Remake the Classics

How do I Extract Tiles from a NPOT Sprite Sheet


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
3 replies to this topic

#1 kelechi96   Members   -  Reputation: 106

Like
0Likes
Like

Posted 07 August 2012 - 08:21 AM

Basically I have created a sprite sheet/tileset with dimentions of 320 x 2048, the tiles are each 32 x 32. I've been able to load individual files with textures in them but I don't seem to be able to load textures from a sprite sheet. Any help ?
Here is the code I'm struggling with:
This is my tiling function

[source lang="cpp"]float VertexX[4], VertexY[4];int TexcoordX, TexcoordY;for (int y = 0; y < WorldSizey; ++y){ for (int x = 0; x < WorldSizex; ++x) { CalculateTextureSheetCoords(TileData[0][y][x], TilesetX,32,TexcoordX,TexcoordY); CalculateTextureVertexCoords(TilesetX,TilesetY,TexcoordX, TexcoordY,32,VertexX[0],VertexY[0],VERTEX_LOWER_LEFT); CalculateTextureVertexCoords(TilesetX,TilesetY,TexcoordX, TexcoordY,32,VertexX[1],VertexY[1],VERTEX_UPPER_LEFT); CalculateTextureVertexCoords(TilesetX,TilesetY,TexcoordX, TexcoordY,32,VertexX[2],VertexY[2],VERTEX_UPPER_RIGHT); CalculateTextureVertexCoords(TilesetX,TilesetY,TexcoordX, TexcoordY,32,VertexX[3],VertexY[3],VERTEX_LOWER_RIGHT); glEnable(GL_TEXTURE_2D); glColor4fv(TextureColour); glBindTexture(GL_TEXTURE_2D,TILESET); glBegin(GL_QUADS); glTexCoord2f(VertexX[0],VertexY[0]); glVertex2f(x/8,(WorldSizey-(y+1))/8); //Lower left glTexCoord2f(VertexX[1],VertexY[1]); glVertex2f(x/8,(WorldSizey-y)/8); //Upper left glTexCoord2f(VertexX[2],VertexY[2]); glVertex2f((x+1)/8,(WorldSizey-y)/8); //Upper Right glTexCoord2f(VertexX[3],VertexY[3]); glVertex2f((x+1)/8,(WorldSizey-(y+1))/8); //Lower Right glEnd(); glDisable(GL_TEXTURE_2D); }}[/source]

And Here's my functions which calculate the coordinates that should work to find the textures but all I'm getting is blank white squares.


[source lang="cpp"]enum VertexMode {VERTEX_LOWER_LEFT, VERTEX_UPPER_LEFT, VERTEX_UPPER_RIGHT, VERTEX_LOWER_RIGHT};void CalculateTextureVertexCoords(float in_ImageSizeX, float in_ImageSizeY, float in_TextureCoordX, float in_TextureCoordY, float in_TextureSize, float &out_VertexCoordX, float &out_VertexCoordY, int in_VertexMode){ switch (in_VertexMode) { case VERTEX_LOWER_LEFT: out_VertexCoordX = (in_TextureSize * in_TextureCoordX)/in_ImageSizeX; out_VertexCoordY = ( 1 - ((in_TextureSize * (in_TextureCoordY + 1))/in_ImageSizeY)); break; case VERTEX_UPPER_LEFT: out_VertexCoordX = (in_TextureSize * in_TextureCoordX)/in_ImageSizeX; out_VertexCoordY = ( 1 - ((in_TextureSize * in_TextureCoordY)/in_ImageSizeY)); break; case VERTEX_UPPER_RIGHT: out_VertexCoordX = ((in_TextureSize * (in_TextureCoordX + 1))/in_ImageSizeX); out_VertexCoordY = ( 1 - ((in_TextureSize * in_TextureCoordY)/in_ImageSizeY)); break; case VERTEX_LOWER_RIGHT: out_VertexCoordX = (in_TextureSize * (in_TextureCoordX + 1))/in_ImageSizeX; out_VertexCoordY = ( 1 - ((in_TextureSize * (in_TextureCoordY + 1))/in_ImageSizeY)); break; }}void CalculateTextureVertexCoordsABS(int in_ImageSizeX, int in_ImageSizeY, int in_TextureCoordX, int in_TextureCoordY, int in_TextureSize, int &out_VertexCoordX, int &out_VertexCoordY, int in_VertexMode){ switch (in_VertexMode) { case VERTEX_LOWER_LEFT: out_VertexCoordX = (in_ImageSizeX - (in_ImageSizeX - in_TextureSize * in_TextureCoordX)); out_VertexCoordY = (in_ImageSizeY - in_TextureSize * (in_TextureCoordY + 1)); break; case VERTEX_UPPER_LEFT: out_VertexCoordX = (in_ImageSizeX - (in_ImageSizeX - in_TextureSize * in_TextureCoordX)); out_VertexCoordY = (in_ImageSizeY - in_TextureSize * in_TextureCoordY); break; case VERTEX_UPPER_RIGHT: out_VertexCoordX = (in_ImageSizeX - (in_ImageSizeX - in_TextureSize * (in_TextureCoordX + 1))); out_VertexCoordY = (in_ImageSizeY - in_TextureSize * in_TextureCoordY); break; case VERTEX_LOWER_RIGHT: out_VertexCoordX = (in_ImageSizeX - (in_ImageSizeX - in_TextureSize * (in_TextureCoordX + 1))); out_VertexCoordY = (in_ImageSizeY - in_TextureSize * (in_TextureCoordY + 1)); break; }}void CalculateTextureSheetCoords(int in_TextureNumber, int in_ImageSizeX, int in_TextureSize, int &out_TextureCoordX, int &out_TextureCoordY){ if (in_TextureNumber != 0) { int TexturesPerRow = in_ImageSizeX/in_TextureSize; out_TextureCoordY = floor(((double)in_TextureNumber - 1) / (double)TexturesPerRow); out_TextureCoordX = (((in_TextureNumber - 1) - TexturesPerRow * out_TextureCoordY) % TexturesPerRow); }}[/source]

Sponsor:

#2 mattdesl   Members   -  Reputation: 142

Like
0Likes
Like

Posted 07 August 2012 - 02:06 PM

Your code looks extremely complicated for something so simple. Are you making a 2D game? Why are you using world coordinates instead of orthographic projection?

In addition to ortho, texture states, etc. you should also read up a little on classes and object oriented programming. For example, you might:
  • Define a "Texture" class which wraps OpenGL textures (bind, wrap modes, filtering, etc) and pads for NPOT
  • Define a "TextureRegion" class utility which determines normalized texture coordinates from un-normalized pixel coordinates
  • Define a "TextureAtlas" (or "SpriteSheet") class which splits a TextureRegion into an array of many TextureRegion objects
Also, the whole point of a sprite sheet is to reduce texture binds and state changes. Bind the texture atlas, glBegin quads, specify the vertices for all of your sprites within that sheet, then glEnd to push the data to the GPU.

Here's a very simple example, similar to what I use:
public class TextureRegion {
	protected float normalizedWidth, normalizedHeight;
	protected float width, height;
	protected float centerX, centerY;
	protected float textureOffsetX, textureOffsetY;
	protected Texture texture;
	public TextureRegion(Texture texture) {
		this.texture = texture;
	  
		//e.g. a 240x240 PNG image would be loaded as a 256x256 texture
		this.normalizedWidth = texture.getImageWidth() / (float) texture.getTextureWidth();
		this.normalizedHeight = texture.getImageHeight() / (float) texture.getTextureHeight();
		this.width = texture.getImageWidth();
		this.height = texture.getImageHeight();
		this.centerX = width / 2f;
		this.centerY = height / 2f;
	}
	public TextureRegion copy() {
		TextureRegion img = new TextureRegion(texture);
		return img;
	}
	public TextureRegion getSubImage(float x, float y, float width, float height) {
		float tx = ( x / this.width * normalizedWidth ) + textureOffsetX;
		float ty = ( y / this.height * normalizedHeight ) + textureOffsetY;
		float tw = width / this.width * normalizedWidth;
		float th = height / this.height * normalizedHeight;
	  
		TextureRegion img = copy();
		img.textureOffsetX = tx;
		img.textureOffsetY = ty;
		img.width = width;
		img.height = height;
		img.normalizedWidth = tw;
		img.normalizedHeight = th;
		img.centerX = width / 2f;
		img.centerY = height / 2f;
		return img;
	}
  
	// ideally you should use a modern solution like VBOs and place rendering elsewhere...
  
	public void begin() {
		GL11.glEnable(GL11.GL_TEXTURE_2D);
		texture.bind();
		GL11.glBegin(GL11.GL_QUADS);
	}
	public void end() {
		GL11.glEnd();
		GL11.glDisable(GL11.GL_TEXTURE_2D);
	}
	public void draw(float x, float y) {
		GL11.glTexCoord2f(textureOffsetX, textureOffsetY; //TOP LEFT
		GL11.glVertex2f(x, y);
		GL11.glTexCoord2f(textureOffsetX, textureOffsetY+normalizedHeight); //BOTTOM LEFT
		GL11.glVertex2f(x, y+height);  
		GL11.glTexCoord2f(textureOffsetX+normalizedWidth, textureOffsetY+normalizedHeight); //BOTTOM RIGHT
		GL11.glVertex2f(x+width, y+height);
		GL11.glTexCoord2f(textureOffsetX+normalizedWidth, textureOffsetY); //TOP RIGHT
		GL11.glVertex2f(x+width, y);
	}
}

Edited by mattdesl, 07 August 2012 - 02:07 PM.


#3 kelechi96   Members   -  Reputation: 106

Like
0Likes
Like

Posted 07 August 2012 - 03:51 PM

Yeah I'm making a 2D game, I don't know how to use orthographic projection.

I generally don't use classes because other than private variables they really don't carry many advantages over just using functions.

Could you explain what your code does from the perspective of "draw" ?

#4 Lazy Foo   Members   -  Reputation: 1030

Like
0Likes
Like

Posted 09 August 2012 - 04:58 AM

Yeah I'm making a 2D game, I don't know how to use orthographic projection.

I generally don't use classes because other than private variables they really don't carry many advantages over just using functions.

Could you explain what your code does from the perspective of "draw" ?


Orthographic projection basically makes it so objects don't get smaller as they move further down the z axis, which is what they would do in a perspective projection. It's a useful projection when you want to render 2D.

When rendering a sprite sheet, you need to map the texture coordinates on a 0 - 1 scale.

Say you have a sprite sheet that's 128x128 and you have a sprite at the top left that's 64x64. To render it on a quad, you map it from 0 to 0.5 on the x and y axis (64 is 0.5 of 128).

And you will soon learn the value of OOP. Having code in loosely packed modules is vital when you have thousands upon thousands of lines of code to manage.
Learn to make games with my SDL Tutorials.
Transition from OpenGL 2 to modern OpenGL using my OpenGL Tutorial.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS