artifacts caused by scaling (2D).. (was mini-map thread)

Started by
18 comments, last by Kalidor 19 years, 2 months ago
hi, im working on a 2d persistant online RPG. anyway, i have been thinking about a mini-map lately. you know, a kind of radar that appeared in the corner of the screen, so that you could see where you were and where other things were in your area. NOTE: the mini-map i am looking for should not display the entire map - only the area around the player. i was thinking this should be relatively fast and easy to do, but im not sure how to approach it. the easiest way would be to do this: take a screenshot of the map zoomed out in my map editor. then, when loading the map, load in that screenshot to a texture. then, just render a portion of this texture using texture coordinates, depending on where the player is on the map. there are a few downsides to this. the first one being that whenever i make a change to the map, i would have to make a new screenshot of the zoomed out map. the other problem is dynamic portions of the map, e.g. player housing. for that, i would have to over-lay the dynamic portion of the map over the static portion, making it about as difficult as my next, more flexible option. the way i want to do it is this - when loading in the map, i render the entire map, scale it to make it zoomed out, and then render this all to a texture. then, i use this texture how i would normally, just render a portion of this texture based on where the player is. my problem is i dont understand how exactly to do this. im using SDL to load in images and to make the window. i *could* create this in SDL, e.g., load in the image as an SDL_Surface, blit the entire map onto one huge SDL Surface, and then turn this SDL_Surface into a texture. but then, how would i scale this texture? its just kind of confusing, i need to use SDL to create the initial image, but OpenGL to scale it. im just not sure what to do.. thanks for any help. [Edited by - graveyard filla on January 23, 2005 1:25:23 AM]
FTA, my 2D futuristic action MMORPG
Advertisement
i'm not familiar with SDL but if its like OpenGL then call glViewport with like 256 for width and height (how big you want the texture), then render your map and copy that viewport area to a texture. Boom automatically scaled down texture of the world. Dont forget to set the viewport back to the windows widht and height.

btw another alternative would be to render a minimap every frame, texture generation at beginning would probably be more efficient tho.

HTH
A simple possibility would actually be to make your map class abstract enough that you can have both the minimap and your normal generator load it. That way, the minimap simply draws it to a specific part of the screen with more "general" textures. What I mean by this, is that if your map says tiles of type 1-8 are different grass tiles, your minimap may just draw them all as green.

Then you could have your minimap scroll, and draw the same way as your regular map...just smaller, and less detailed.

Just an idea.
Quote:Original post by nts
i'm not familiar with SDL but if its like OpenGL then call glViewport with like 256 for width and height (how big you want the texture), then render your map and copy that viewport area to a texture. Boom automatically scaled down texture of the world. Dont forget to set the viewport back to the windows widht and height.

btw another alternative would be to render a minimap every frame, texture generation at beginning would probably be more efficient tho.

HTH


if you dont mind, could you please explain a little more how to do this and how it works? it sounds exactly what im looking for. i googled for glViewPort() but im not even sure what this does exactly (its been months since ive worked on rendering code [grin]).

thanks for any help.
FTA, my 2D futuristic action MMORPG
with my current project, I have my map editor save a small 128x128 color rendering of the map form high above with some modificationtions, but overly it seems to have worked for me. in the game I just load the textures from the map files, and use those for a mini map, making the overhead very small.
"I seek knowledge and to help those who also seek it"
Quote:Original post by Xero-X2
with my current project, I have my map editor save a small 128x128 color rendering of the map form high above with some modificationtions, but overly it seems to have worked for me. in the game I just load the textures from the map files, and use those for a mini map, making the overhead very small.


And then, instead of changing the texture by adding dots for moving units, you could use points.
That would also be quite efficient together with that last idea I've quoted, especially in a vertex array (VBO's are not good for < 100 triangles, so it's only good in a RTS I guess).
Killers don't end up in jailThey end up on a high-score!
Quote:Original post by graveyard filla
Quote:Original post by nts
i'm not familiar with SDL but if its like OpenGL then call glViewport with like 256 for width and height (how big you want the texture), then render your map and copy that viewport area to a texture. Boom automatically scaled down texture of the world. Dont forget to set the viewport back to the windows widht and height.

btw another alternative would be to render a minimap every frame, texture generation at beginning would probably be more efficient tho.

HTH


if you dont mind, could you please explain a little more how to do this and how it works? it sounds exactly what im looking for. i googled for glViewPort() but im not even sure what this does exactly (its been months since ive worked on rendering code [grin]).

thanks for any help.



glViewport will set the rendering area in your window, usually set to left and top to 0 and the width and height to the window size. If you modify this to (0,0, 256, 256) then everything will be rendered into a very small section of the window (depending on what you use for width and height). You can then copy this viewport area to a texture which will give you your resized minimap texture. Reset the viewport back to the windows size when your done.

HTH

[nts] - If i'm not logged in
hey everyone,

ok, ive been working on this, but im stuck. i just cant get it to work.

first of all, it seems like only a screen's worth of the map is being rendered. im not sure how to get the entire map rendered on the screen. i tried scaling(), but then my texture is completely black.

next, what does show up on the screen is a mirrored, or flipped version of what it should be. im not sure why this happends. i was playing with it for awhile and im just getting nowhere. im thinking it appears mirrored because of the parameters of glCopyTexImage2D(), but i played with them and im still not sure..

anyway, let me show the code. first, here is the function which generates the mini-map texture: (notice i followed NeHe tutorials [grin])

GLuint Map::Generate_Mini_Map()							// Create An Empty Texture{	GLuint txtnumber;						// Texture ID	unsigned int* data;						// Stored Data	// Create Storage Space For Texture Data (128x128x4)	data = (unsigned int*)new GLuint[((256 * 256)* 4 * sizeof(unsigned int))];		std::fill(data,data+((256 * 256)* 4 * sizeof(unsigned int)),0);	// Clear Storage Memory	glGenTextures(1, &txtnumber);					// Create 1 Texture	glBindTexture(GL_TEXTURE_2D, txtnumber);			// Bind The Texture	glTexImage2D(GL_TEXTURE_2D, 0, 4, 256,256, 0,		GL_RGBA, GL_UNSIGNED_BYTE, data);			// Build Texture Using Information In data	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);	delete [] data;							// Release data	//return txtnumber;						// Return The Texture ID	glViewport(0,0,256,256);					// Set Our Viewport (Match Texture Size)	Draw_Map_For_Mini_Map();							// Render The Helix	glBindTexture(GL_TEXTURE_2D,txtnumber);			// Bind To The Blur Texture	// Copy Our ViewPort To The Blur Texture (From 0,0 To 128,128... No Border)	glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 256, 256, 0);	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		// Clear The Screen And Depth Buffer	glViewport(0 , 0,SCREEN_RESW , SCREEN_RESH);					// Set Viewport (0,0 to 640x480)	return txtnumber;}


now, the function Draw_Map_For_Mini_Map() looks like this:
void Map::Draw_Map_For_Mini_Map(){	glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);	glPushMatrix();	glColor4f(1.0,1.0f,1.0f,1.0f);	float scale_x = 1.0f;//SCREEN_RESW / (width*32);	float scale_y = 1.0f;//SCREEN_RESH / (height*32);	float invx = 1.0f / scale_x;	float invy = 1.0f / scale_y;	glScalef(scale_x,scale_y,1.0f);	for(int t = 0; t < tilesets.size(); t++)	{		glBindTexture(GL_TEXTURE_2D,tilesets[t].tilemap_texture);//map_data.tilemap_texture[0]		glBegin(GL_QUADS);			for(int y = 0; y < height; ++y)		{					//y draw coordinate, the offset is for smooth scrolling			for(int x = 0; x < width; ++x)			{									Tile &tmp = current_map[y][x];					for(int q = 0; q < tmp.layers.size(); q++)					{						if(tmp.layers[q].layer == -2 && tmp.layers[q].texture == tilesets[t].tilemap_texture)							Draw_Tile((float)(x*32)*invx,(float)(y*32)*invy,tmp.layers[q].x_map_loc,									    		tmp.layers[q].y_map_loc,tmp.layers[q].t_perc_w,tmp.layers[q].t_perc_h);					}										for(int q = 0; q < tmp.layers.size(); q++)					{						if(tmp.layers[q].layer == -1 && tmp.layers[q].texture == tilesets[t].tilemap_texture)							Draw_Tile((float)(x*32)*invx,(float)(y*32)*invy,tmp.layers[q].x_map_loc,									    		tmp.layers[q].y_map_loc,tmp.layers[q].t_perc_w,tmp.layers[q].t_perc_h);					}										for(int q = 0; q < tmp.layers.size(); q++)					{						if(tmp.layers[q].layer == 0 && tmp.layers[q].texture == tilesets[t].tilemap_texture)							Draw_Tile((float)(x*32)*invx,(float)(y*32)*invy,tmp.layers[q].x_map_loc,									    		tmp.layers[q].y_map_loc,tmp.layers[q].t_perc_w,tmp.layers[q].t_perc_h);					}							}//end inner for loop		}//end outer for loop		glEnd();	}		glColor4f(1.0,1.0f,1.0f,1.0f);		for(int t = 0; t < tilesets.size(); t++)	{		glBindTexture(GL_TEXTURE_2D,tilesets[t].tilemap_texture);//map_data.tilemap_texture[0]		glBegin(GL_QUADS);		for(int y = 0; y < height; ++y)		{					//y draw coordinate, the offset is for smooth scrolling			for(int x = 0; x < width; ++x)			{										Tile &tmp = current_map[y][x];				for(int q = 0; q < tmp.layers.size(); q++)				{					if(tmp.layers[q].layer == 1 && tmp.layers[q].texture == tilesets[t].tilemap_texture)						Draw_Tile((float)(x*32)*invx,(float)(y*32)*invy,tmp.layers[q].x_map_loc,									    	tmp.layers[q].y_map_loc,tmp.layers[q].t_perc_w,tmp.layers[q].t_perc_h);				}									for(int q = 0; q < tmp.layers.size(); q++)				{					if(tmp.layers[q].layer == 2 && tmp.layers[q].texture == tilesets[t].tilemap_texture)						Draw_Tile((float)(x*32)*invx,(float)(y*32)*invy,tmp.layers[q].x_map_loc,									    	tmp.layers[q].y_map_loc,tmp.layers[q].t_perc_w,tmp.layers[q].t_perc_h);				}											}//end inner for loop				}//end outer for loop		glEnd();	}//end for each texture	glPopMatrix();	SDL_GL_SwapBuffers();				}


if you see, im scaling and trying to render the entire map onto the space, but its just not working like that, so i commented out this line (at around the 5th line of the function) to look like this:

float scale_x = 1.0f;//SCREEN_RESW / (width*32);
float scale_y = 1.0f;//SCREEN_RESH / (height*32);

i only commented out this line and set the scale to 1.0 so that everything would work (except, well, only a screens worth of the map is drawn into the mini-map..i want the entire map). however, in theory, if i make it

float scale_x = SCREEN_RESW / (width*32);
float scale_y = SCREEN_RESH / (height*32);

this should scale enough to fit the entire map into the texture (i think? im not really sure). SCREEN_RESW/H is the resolution of the window (800x600). width/height are the size of the map in tiles. 32 is the tilesize.

maybe i have to scale in relation to the size of the view port, and not of the window? im just not sure...

thanks a lot for any help..

NOTE: some more info

the tilesize is 32x32
the size i want the mini-map texture to be is 256x256

thanks again.
FTA, my 2D futuristic action MMORPG
I think you are scaling down the map way to much, (assuming your width/height is 256) your scale value is 0.07.
I'm going to assume you realise that a scale of 1 is defaut size, 0.5 half size, 0.25 a quarter....
As for the minimap being mirrored either flip the verts around or the texcoords.

If you are trying to make a minimap as seen in HalfLife, they simply have a pre-generated image, they then render the ents ontop of it.
Yes copying the buffer will get everyting into the minimap, and is easier than drawing each ent ontop, but there is also a price to pay for reading back (although it is diminishing).
thanks for the reply.

yes, i understand what scaling is. and no, width/height is the width/height of the map in tiles. a big map is 250x250. a small map is 35x35. yeah, maybe i am scaling wrong.. maybe i dont need to scale at all? but then why is only a screens worth of the map being rendered to the texture? wouldnt i have to scale to fit the whole map?

also, what do you mean by flip the verts/tex coords? and why would i have to do that? im using the same Draw_Tile() function that i use to draw my map each frame. why would it have to be different?

thanks again.
FTA, my 2D futuristic action MMORPG

This topic is closed to new replies.

Advertisement