Rotating sprites in homemade "2d engine"

Started by
13 comments, last by Fingers_ 16 years, 1 month ago
Hallo everyone. Im working on a small project where I am trying to make a simple 2d game using a very limited API. The API only gives you the ability to create a window and return a pointer for all the pixels in the window. Then it is up to me to manipulate that pointer in order to create something useful. So far everything is good, but I am having troubles with getting my sprite rotation to work. The problem is that a screen pixel has a x,y integer value, and the rotated sprite has a x,y float value for all its pixels. Therefor roundoff errors cause some pixels to be on to of each other leaving some blank spaces where I am drawing. Does anyone know of a way to fix this? Here is a picture of the problem [img=http://img257.imageshack.us/img257/7503/spritetroublecf2.jpg] And here is the code

void rotatPixelList(std::vector<pixel> &list, float rotation)
{
	float PI =  3.14159265;

	float r = rotation * PI / 180.0;

	for(int i = 0; i < list.size(); i++)
	{
		float x = list.xPos;
		float y = list.yPos;

		list.xPos = x * cos(r) - y * sin(r);
		list.yPos = y * cos(r) + x * sin(r);
	}
}

void movePixelList(std::vector<pixel> &list, float x, float y)
{
	for(int i = 0; i < list.size(); i++)
	{
		list.xPos += x;
		list.yPos += y;
	}
}

void Visualisation::setPixel(std::vector<pixel> list)
{
	for(int i = 0; i < list.size(); i++)
	{
		int offset = 4 * (((int)list.yPos * screenRec.getWidth()) + (int)list.xPos);

		screenPnt[offset+0] = list.b;
		screenPnt[offset+1] = list.g;
		screenPnt[offset+2] = list.r;
	}
}

Thanks in advance
Advertisement
Instead of rotating every pixel, you should rotate the sprites corners and use scanline rendering (http://en.wikipedia.org/wiki/Scanline_rendering) to display it on the screen.
Instead of calculating where the pixels of the sprite image are in the screenbuffer, I'd fill the region on the screenbuffer and look up the sprite image to find what colour each pixel should be filled with.

For sprites I'd probably go for 2 triangles with affine texture mapping and possibly bi linear filtering.
Thats sounded like a lot of work.

So basically I have to rewrite my "engine" to a scanline render? As it is now I dont have polygons at all and I am writing directly to the screen (I have a rectangle for each sprite, but the sprite is not really inside it, its just to pass position values around)

Thanks for the replies
if dont want a scan line renderer, you could always use this approach, although i don't recommend it - scan line rendering would be much better.

rotate corners of sprite, calculate min-max along x and y directions for an axis aligned bounding box. then run through all the pixels in this box, determine whether pixel is inside the actual sprite rotated box or not, and if it is. look up what is the nearest pixel in the sprite image to this point.
Quote:Original post by luca-deltodesco
if dont want a scan line renderer, you could always use this approach, although i don't recommend it - scan line rendering would be much better.

Its for a introduction to games programming class which im not even taking, so I think that would be a bit over my current skill level. I might look into it though, I find rendering quite interesting.

Quote:Original post by luca-deltodesco
rotate corners of sprite, calculate min-max along x and y directions for an axis aligned bounding box. then run through all the pixels in this box, determine whether pixel is inside the actual sprite rotated box or not, and if it is. look up what is the nearest pixel in the sprite image to this point.

Not sure if I fully understand what do to here.

1. Rotate the sprite using one of the corners (Does it only work using corners?)
2. Create a new boundingBox (The bounding box should not be rotated, but be aligned to the axis)
3. Not sure what do to here

Thanks for you reply :)

heres an image to help describe what i mean:
http://www.ngup.net/view?file=527

the black box is your rotated sprite. the red box is the axis aligned bounding box for it calculated from the min-max values of the sprite's corners. the circles are the pixels.

from here, easiest way is that for each pixel, do the opposite rotation to take you into the sprite's coordinate system - this way its very easy to check whether the pixel is within the black sprite box or not, if it is, then you also have the coordinate to use for the texture look-up.
Again, thank you.

Just let me see if I have gotten this right:

1. Rotate the texture
2. Create the bounding box
3. For each pixel(screen pixel, right?) inside the bounding box: Rotate back to get to texture space and find the right pixel in the texture.

After fooling around for a while I got it working, but the problem is that its dead slow. I currently get 8 fps (140fps with a blank screen) when I try to rotate a texture.

My problem is that I loop trough the data to many times, but im not sure how to make it faster. Assembly is not an alternative for me :P

Here is the current Code
// Create bounding box// Rotate the bounding box// Move the bounding box// Create a axis aligned bounding box// Transform the bounding box so that one of the vertex are at 0,0// For each pixel in the aliignedBox go back to the texture and see if there is a pixel there.// if it is, copy the color of itfor(int y = lowestY; y < higestY; y++){	for(int x = lowestX; x < highestX; x++)	{		// Check if the pixel is inside the texture		//---------------------------------------------		// Move the point from screen space to texture space		float newX = x - moveX;		float newY = y - moveY;		// See if the point is inside the texture		Vector3D c = Vector3D(boundingBox[1].x,boundingBox[1].y, 0);		Vector3D p = Vector3D(newX, newY, 0);					Vector3D v = p - c;		Vector3D v1 = Vector3D(boundingBox[0].x,boundingBox[0].y, 0);		Vector3D v2 = Vector3D(boundingBox[3].x,boundingBox[3].y, 0);		    		if( ( 0 <= Dot(v,v1) && Dot(v,v1) <= Dot(v1,v1) ) && 			( 0 <= Dot(v,v2) && Dot(v,v2) <= Dot(v2,v2) )    )		{			// Find the closest texture pixel			// ----------------------------------			// Rotate the point back, to find the correct pixel			float newXtemp = newX;			float newYtemp = newY;			newX = abs(newXtemp * cos(-r) - newY * sin(-r));			newY = abs(newY * cos(-r) + newXtemp * sin(-r));				// Loop through the pixelList and find the pixel with the same position value			for(int i = 0; i < curSprite.pixelList.size(); i++)			{				if( ((int)newX == (int)curSprite.pixelList.xPos) && ((int)newY == (int)curSprite.pixelList.yPos) )				{					// Copy the colors of the pixel into the screenPointer					int offset = 4 * (((int)y * screenRec.getWidth()) + (int)x);					screenPnt[offset+0] = curSprite.pixelList.b;					screenPnt[offset+1] = curSprite.pixelList.g;					screenPnt[offset+2] = curSprite.pixelList.r;				}				}		}	}}


Thanks,
I think you're doing unnecessary work there.
All you need to do is perform the opposite of the rotation for every pixel in the bounding box, then use that coordinate to get the colour from the texture. You certainly shouldn't have to loop through the texture pixels. Unless they are in a random order, surely you can just use (y * texwidth + x)

I made a fairly decent 2D engine myself, but I quit before I finished rotation. :P

This topic is closed to new replies.

Advertisement