tilemap trouble

Started by
17 comments, last by furiousuk 19 years ago
Hey, I am having this weird bug with my tiles. The pixels seem to wrap 1px in both the x and the y coords. I have tried to fix this bug, but I just can't seem to figure out what it is. I think that it must be in the loading code, i'm not sure. I couldn't get a screen shot for some reason. Here is the project in question (9MB). Here is the most suspect code.

// FILE: TileMap.h by Richard Hughes. 30/11/2003
//
// DESC: This declares the CTileMap and assosiated classs

#pragma once

// INCLUDES
#include "MemoryManager.h"
#include "ErrorLogging.h"
#include "Graphics.h"
#include "Image.h"
#include "Util.h"
#include "FileInfo.h"

/*********************************************************************************************/
//
//	CLASS: tagTile
//
//	DESC: This is a tile
//
/*********************************************************************************************/

typedef struct tagTile : public IMemObject {
	tagTile( void )
	{
	}
	~tagTile( void )
	{
	}
	unsigned char* m_pData;    // the image data
	long           m_lWidth,   // the tiles width
		           m_lHeight;  // the tiles height
	unsigned long  m_dwFormat; // RGB RGBA
	unsigned long  m_dwInternalFormat; // RGB RGBA

	QUICK_SIZE;
}TILE, *LPTILE;

/*********************************************************************************************/
//
//	CLASS: CTileMap
//
//	DESC: This handles tilemaps. see doc for more info
//
/*********************************************************************************************/

class CTileMap : public IError {

	CPointer < TILE > m_Tiles;  // the tiles in the tilemap

public:
	CTileMap( void )
	{
	}
	~CTileMap( void )
	{
	}

	// this loads in a tile map directly
	ERROR_STRING Load( string strFName, int nHeight, int nWidth, long lTWidth, long lTHeight, 
					   int nHBorder, int nVBorder );

	// this loads certain tiles from a tilemap directly
	ERROR_STRING Load( string strFName, int nHeight, int nWidth, long lTWidth, long lTHeight, 
					   int nHBorder, int nVBorder, pint pList );

	// this loads in a tilemap directly via a tilemap file
	ERROR_STRING Load( string strFName );

	// this loads in a tilemap indirectly via a tilemap file
	ERROR_STRING Load( string strFName, pint pList, pstring pNames );

	// this returns a tile
	inline TILE& GetTile( int nIndex )
	{
		return ( m_Tiles[ nIndex ] );
	} // end GetTile

	QUICK_NAME( "CTileMap" );
	QUICK_SIZE;
}; // end CTileMap

// EOF: TileMap.h


// FILE: TileMap.cpp by Richard Hughes. 30/11/2003
//
// DESC: This defines the CTileMap class

// INCLUDES
#include "TileMap.h"

/*********************************************************************************************/
//
//	CLASS: CTileMap
//
//	DESC: This handles tilemaps. see doc for more info
//
/*********************************************************************************************/

// this loads in a tilemap
// it takes the tilemaps filename, the amount of cells heigh and wide, the height and the width of the tiles,
// and the horizontal and vertical border
// it returns the nessercary ERROR_STRING error
ERROR_STRING CTileMap::Load( string strFName, int nHeight, int nWidth, long lTWidth, long lTHeight, 
							 int nHBorder, int nVBorder )
{
	Enter( "Load_Direct" );


	int nBPP = 0; // the images BPP

	// load in the tilemap
	CImage Image;
	ERROR( Image.Load( strFName ) );

	// init the tiles
	m_Tiles.Init( nWidth*nHeight );

	// set the BPP
	nBPP = ( Image.GetFormat( ) == CF_RGB ) ? 3 : 4;

	// compute the tile area
	UCHAR *pSource, *pDest;    // pointers for saving
	long Width = lTWidth * nBPP;
	long Height = lTHeight * nBPP;
	long TileArea = Width*Height;

	/*
		extract the image data into the cells
	*/
	// get the image data
	unsigned char* p = Image.GetData( );
	pSource = Image.GetData( );

	// get the image width in bits ( RGB )
	long lImageWidth = Image.GetWidth( ) * nBPP;
	long l = 0;

	// loop thru and load in all of the cells
	for ( long idx = 0; idx < nWidth; idx++ )
		for ( long idy = 0; idy < nHeight; idy++ ) {
			l = idx+( idy*nWidth );

			// set the image stats
			m_Tiles[ l ].m_pData = new unsigned char[ TileArea ];
			memset( m_Tiles[ l ].m_pData, 0, sizeof ( unsigned char ) * TileArea );
			m_Tiles[ l ].m_lWidth = lTWidth;
			m_Tiles[ l ].m_lHeight = lTHeight;
			m_Tiles[ l ].m_dwFormat = Image.GetFormat( );
			m_Tiles[ l ].m_dwInternalFormat = Image.GetInternalFormat( );
			pDest = m_Tiles[ l ].m_pData;

			int cx = idx*Width;
			int cy = idy*lTHeight;

			// extract bitmap data
			pSource = Image.GetData( ) + cy*lImageWidth+cx;

			for ( int y = 0; y < lTHeight; y++ )
			{
				// copy over the first line of the tile
				memcpy( pDest, pSource, Width );

				// goto the next line
				pSource += lImageWidth;
				pDest += Width;
			} // end for
		} // end for

	RETURN_SUCCESS;
} // end CTileMap::Load

// FILE: 25DMap.h by Richard Hughes. 19/02/2005
//
// DESC: This file defines the 25DMap and assosiated classes

#ifndef __25DMap_h__
#define __25DMap_h__

// INCLUDES
#include <vector>
#include "ErrorLogging.h"
#include "Mesh.h"
#include "Tilemap.h"
#include "Animation.h"
#include "SpriteManager.h"

using namespace std;

/*********************************************************************************************/
//
//	CLASS: CTile
//
//	DESC: This is a tile
//
/*********************************************************************************************/

class CTile : public IError {
	
	char               m_strIdx[ MAX_STRING_LENGTH ]; // the tiles index
	CAnimation         m_Anim;   // this tiles animation
	int                m_nFrame; // the current animation frame
	CPointer < CQuad > m_pTiles; // the tile animations
	float              m_fX,     // the tiles x pos
		               m_fY;     // the tiles y pos
	int                m_nW,     // the tiles width
		               m_nH;     // the tiles height
	float              m_fSW,    // the scale width
		               m_fSH;    // the scale height

public:
	CTile( void )
	{
		m_nFrame = 0;
		m_fX = m_fY = 0.0f;
		m_nW = m_nH = 0;
		m_fSW = m_fSH = 1.0f;
	}
	~CTile( void )
	{
	}

	// this loads the tile
	ERROR_STRING Load( CPointer < CTileMap > pMap, int w, int h, string strFName );

//.....

#endif /* __25DMap_h__*/

// EOF: 25DMap.h


// FILE: 25DMap.cpp by Richard Hughes. 19/02/2005
//
// DESC: This file defines the 25DMap and assosiated classes

// INCLUDES
#include "25DMap.h"
#include "TexturePool.h"
#include "Texture.h"
#include "Sprite.h"

/*********************************************************************************************/
//
//	CLASS: CTile
//
//	DESC: This is a tile
//
/*********************************************************************************************/

// this loads the tile
// it takes the tilemap to load the tiles from, the tile dimentions and the tile file name
// it returns the necessary ERROR_STRING error
ERROR_STRING CTile::Load( CPointer < CTileMap > pMap, int w, int h, string strFName )
{
	Enter( "Load" );

	if ( !pMap )
		RETURN_POINTER_NULL( "pMap" );

	FILE*  fp      = NULL;  // the file pointer
	string str     = "";    // temp
	int    n       = 0;     // temp
	float  f       = 0.0f;  // temp
	bool   bKey    = false; // whether to use a color key for this tile
	int    r1      = 0;     // the min red component of the color key
	int    r2      = 0;     // the max red component of the color key
	int    g1      = 0;     // the min green component of the color key
	int    g2      = 0;     // the max green component of the color key
	int    b1      = 0;     // the min blue component of the color key
	int    b2      = 0;     // the max blue component of the color key
	int    nSize   = 0;     // the size of the animation
	pint   pAnim;           // the animation indexes
	pfloat pTimes;          // the frame times

	// set the tile dimentions
	m_nW = w; m_nH = h;

	// load in the tile file
	// open the file
	fp = fopen( strFName.data( ), "r" );
	if ( POINTER_NULL( fp ) )
		RETURN_NOT_OPENED( strFName );

	// read in the index
	fscanf( fp, "%s", m_strIdx );

	// read in the number of frames
	fscanf( fp, "%d", &nSize );

	// init the animations
	m_pTiles.Init( nSize );
	pAnim.Init( nSize );
	pTimes.Init( nSize );

	// read in the animations
	for ( int i = 0; i < nSize; i++ )
	{
		fscanf( fp, "%d", &n );
		fscanf( fp, "%f", &f );
		pAnim = n;
		pTimes = f;
	} <span class="cpp-comment">// end for</span>

	<span class="cpp-comment">// read in the color key if there is one</span>
	<span class="cpp-keyword">if</span> ( fscanf( fp, <span class="cpp-literal">"%d"</span>, &amp;r1 ) != EOF &amp;&amp;
		 fscanf( fp, <span class="cpp-literal">"%d"</span>, &amp;r2 ) != EOF &amp;&amp;
		 fscanf( fp, <span class="cpp-literal">"%d"</span>, &amp;g1 ) != EOF &amp;&amp;
		 fscanf( fp, <span class="cpp-literal">"%d"</span>, &amp;g2 ) != EOF &amp;&amp;
		 fscanf( fp, <span class="cpp-literal">"%d"</span>, &amp;b1 ) != EOF &amp;&amp;
		 fscanf( fp, <span class="cpp-literal">"%d"</span>, &amp;b2 ) != EOF )
			bKey = <span class="cpp-keyword">true</span>;

	<span class="cpp-comment">// close the file</span>
	fclose( fp );
	fflush( fp );
	fp = NULL;

	<span class="cpp-comment">// load in the indexes</span>
	<span class="cpp-keyword">for</span> ( i = <span class="cpp-number">0</span>; i &lt; nSize; i++ )
	{
		<span class="cpp-comment">// setup the quad</span>
		m_pTiles.Init( w,h, <span class="cpp-number">0</span>,<span class="cpp-number">0</span>, VB_TEX2D_1 );

		<span class="cpp-comment">// load in the tile</span>
		str = strFName + ToString( <span class="cpp-literal">" : %d"</span>, i );
		CTexturePool::GetSingleton( ).LoadTex( pMap-&gt;GetTile( *pAnim ), str, bKey, r1,r2, g1,g2, b1,b2 );

		<span class="cpp-comment">// attach tex</span>
		CTexturePool::GetSingleton( ).AttachTex( &amp;m_pTiles, str, <span class="cpp-keyword">false</span> );

		<span class="cpp-comment">// set the animation index</span>
		pAnim = i;
	} <span class="cpp-comment">// end for</span>

	<span class="cpp-comment">// create the animation</span>
	m_Anim.Set( pAnim, pTimes, <span class="cpp-number">0</span>, m_strIdx );
    
	RETURN_SUCCESS;
} <span class="cpp-comment">// end CTile::Load</span>
<span class="cpp-comment">// EOF: 25DMap.cpp</span>

</pre></div><!–ENDSCRIPT–>

NOTE: The code above has now been edited down to be more specific.

Thanks,

<!–EDIT–><span class=editedby><!–/EDIT–>[Edited by - rpg_code_master on April 1, 2005 5:38:48 AM]<!–EDIT–></span><!–/EDIT–>
Advertisement
That's quite a lot of code for us to look through! Perhaps you can narrow it down somewhat..?
I just skimmed through your code. You seem to use OpenGL or something to render your tiles? I didn't quite get what you meant by "wrap 1px in both x an the y coords", but if it is what I think it is, then you could try to shrink your tiles' texture size 0.5 pixels from all edges.

So if your texture co-ordinates are (0, 0) to (32, 32) then make that (0.5, 0.5) to (31.5, 31.5).
I have narrowed down the code and have also mustered up a screen shot.

If you notice, the tiles seem to have wrapped 1px in the x and y directions. Note the top left, the sand path has grass on the wrong side and the ship in the bottom right the decking is incorect etc... This incorectness is only 1px I believe.

In that code I don't see any indication (a) of how you load the textures, (b) how you set up the rendering system, or (c) how you do the rendering. These are the areas that are likely to be the problem, not the (edited) samples above.

The only suggestion I can give without any information on your rendering system is that your texture mode might be set to 'wrap' when it needs to be set to 'clamp'. How to do that will all depend on how you're actually rendering those graphics.
There are two questions:
- what is your tile drawing code ?
Do you draw textured quads using integer coordinates or floating point vertices coords ? What is the unit width and height of your quad in world coordinates ?
- what is your texture tile loading code ?
What is the unit size of a texture tile in pixel ? If you load from a big texture bitmap multiple texture tiles, how do you calculate starting and ending texture coordinates for each tile ?

Ghostly yours,
Red.
Ghostly yours,Red.
Ah, yes! Read my post again. I'm sure that will fix this problem :)

Basically you want your texture co-ordinates to point to the middle of the pixels, not their edges. That's why you add/subtract 0.5 pixels from the its size. Note that you do not change the actual size of the tile.

Otherwise the colour of the pixel next to it will have an influence.
I'm pretty sure that your getting these results from using linear filtering, switch to point filtering and it will look just as it does on your images. If you want to use linear filtering without these borders render everything to a texture and then use linear filtering on the render texture.
Yes, I use linear filtering. Whats point filtering? How do I implement that in OpenGL?

The tile drawing code is simply rendering a quad. The texture coords for that are 0,0 0,1 1,1 1,0. If you would like to see the code, download the project. It's all self explanitory.

I'm not going to post anymore code because there is alot of code posted.

To get the tile data, I copy the pixels from the main loaded image. That code is posted in the tile loading code.
Machinoid, I use 0.0,0.0 1.0,1.0 0.0,1.0 1.0,0.0 as texture coordinates because the quad does not know the size of the tile. How can I point to the middle of the pixels?

I tried 0.05 and 0.95, the produces better results but it squashes the tile.

This topic is closed to new replies.

Advertisement