Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

Zefrieg

My texture-mapped polygon rendering function...

This topic is 5476 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Well, I created this with nothing but a description of how to do it. This method creates an array of scanline positions. One set of coordinates relate to the outline of the polygon, and the other one relates to the texture coordinates. It is all integer based, and for better precision I did some bit shifting to allow me to use integers with comparable precision to a float. It also does a simple test for clipping. Anyway, I thought I would throw it up here in case anyone wanted to see it. Hopefully some of you can give me ideas on how I can make it even faster. Rendering Function
void PolygonFloat::RenderFilledTexture(USHORT* _surface, ImageArray& _image)
{
	static int x1;
	static int y1;
	static int x2;
	static int y2;
	static int yCutoff;
	static int width;
	static int height;
	static int numberScanlines;
	static int tu1;
	static int tv1;
	static int tu2;
	static int tv2;
	static int dtu;
	static int dtv;
	static int dtu2;
	static int dtv2;
	static int uInc;
	static int vInc;
	static int scanWidth;
	static int imageWidth;
	static int address;
	static TextureScanline scanline[MAX_HEIGHT];
	lib::Rectangle<float> rect;

	width = m_GDevice->GetWidth() - 1;
	height = m_GDevice->GetHeight() - 1;	

	this->GetBoundingBox(rect);

	x1 = int(rect.GetTopLeftX());
	y1 = int(rect.GetTopLeftY());
	x2 = int(rect.GetBottomRightX());
	y2 = int(rect.GetBottomRightY());

	if(!(x2 < 0 || y2 < 0 || x1 > width || y1 > height))
	{
		numberScanlines = y2 - y1;

		for(int j = 0; j < numberScanlines; j++)
		{
			scanline[j].start = x2;
			scanline[j].end = x1;
		}
	
		this->BuildTextureScanlines(scanline, numberScanlines, y1);
		
		if(y1 < 0)
		{
			yCutoff = 0;
		}
		else
		{
			yCutoff = y1;
		}
		if(y2 > height)
		{
			y2 = height;
		}

		int surfaceWidth = m_GDevice->GetPitch();
		USHORT* surface = _surface;
		USHORT* texture = _image.GetSurface();
		surface += yCutoff * surfaceWidth;

		imageWidth = _image.GetWidth();

		for(int i = yCutoff; i < y2; i++)
		{
			address = i - y1;
			x1 = scanline[address].start;
			x2 = scanline[address].end;
			tu1 = (scanline[address].startTU);
			tv1 = (scanline[address].startTV);
			tu2 = (scanline[address].endTU);
			tv2 = (scanline[address].endTV);
			dtu = (tu2 - tu1) << 15;
			dtv = (tv2 - tv1) << 15;
			scanWidth = (x2 - x1);

			if(scanWidth > 0)
			{
				dtu = dtu / scanWidth;
				dtv = dtv / scanWidth;
			}
			else
			{
				dtu = 0;
				dtv = 0;
				dtu2 = 0;
				dtv2 = 0;
			}

			tu2 = tu1 << 15;
			tv2 = tv1 << 15;
			
			for(int j = x1; j < x2; j++)
			{
				tu1 = tu2 >> 15;
				tv1 = tv2 >> 15;
				
				if(j >= 0 && j <= width)
				{
					surface[j] = texture[tu1 + (tv1 * imageWidth)];
				}
				tu2 += dtu;
				tv2 += dtv;
			}
			surface += surfaceWidth;
		}
	}
}
Scanline-building Function
void PolygonFloat::BuildTextureScanlines(TextureScanline* _scanlines, int _size, int _ymin)
{
	static int x1;
	static int y1;
	static int x2;
	static int y2;
	static int dx;
	static int dy;
	static int dx2;
	static int dy2;
	static int xInc;
	static int yInc;
	static int error;
	static int tu1;
	static int tv1;
	static int tu2;
	static int tv2;	
	static int dtu;
	static int dtv;
	static int uInc;
	static int vInc;
	static int dtu2;
	static int dtv2;
	static int distance;
	static int address;

	for(int i = 0; i < m_count; i++)
	{
		address = (i + 1) % m_count;
		x1 = int(m_vertexList[i].GetX() + m_position.GetX());
		y1 = int(m_vertexList[i].GetY() + m_position.GetY());
		x2 = int(m_vertexList[address].GetX() + m_position.GetX());
		y2 = int(m_vertexList[address].GetY() + m_position.GetY());
		
		dx = x2 - x1;
		dy = y2 - y1;
		m_lights[i].GetTextureCoord(tu1, tv1);
		m_lights[address].GetTextureCoord(tu2, tv2);

		if(dx >= 0)
		{
			xInc = 1;
		}
		else
		{
			xInc = -1;
			dx = -dx;
		}
	
		if(dy >= 0)
		{
			yInc = 1;
		}
		else
		{
			yInc = -1;
			dy = -dy;
		}
		
		dx2 = dx << 1;
		dy2 = dy << 1;

		dtu = (tu2 - tu1) << 15;
		dtv = (tv2 - tv1) << 15;

		if(dx > dy)
		{
			distance = dx;
		}
		else
		{
			distance = dy;
		}

		if(distance > 0)
		{
			dtu = dtu / distance;
			dtv = dtv / distance;
		}
		else
		{
			dtu = 0;
			dtv = 0;
			dtu2 = 0;
			dtv2 = 0;
		}

		tu2 = tu1 << 15;
		tv2 = tv1 << 15;

		if(dx > dy)
		{
			error = dy2 - dx;
			for(int i = 0; i <= dx; i++)
			{
				address = y1 - _ymin;
				
				tu1 = (tu2 >> 15);
				tv1 = (tv2 >> 15);

				if((address) >= 0 && (address) < _size)
				{
					if(x1 < _scanlines[address].start)
					{
						_scanlines[address].start = x1;
						_scanlines[address].startTU = tu1;
						_scanlines[address].startTV = tv1;
					}
					if(x1 > _scanlines[address].end)
					{
						_scanlines[address].end = x1;
						_scanlines[address].endTU = tu1;
						_scanlines[address].endTV = tv1;
					}
				}
				if(error >= 0)
				{
					error -= dx2;
					y1 += yInc;
				}
				error += dy2;
				x1 += xInc;	
				tu2 += dtu;
				tv2 += dtv;
			}
		}
		else
		{
			error = dx2 - dy;
			for(int i = 0; i <= dy; i++)
			{
				address = y1 - _ymin;	

				tu1 = tu2 >> 15;
				tv1 = tv2 >> 15;

				if((address) >= 0 && (address) < _size)
				{
					if(x1 < _scanlines[address].start)
					{
						_scanlines[address].start = x1;
						_scanlines[address].startTU = tu1;
						_scanlines[address].startTV = tv1;
					}
					if(x1 > _scanlines[address].end)
					{
						_scanlines[address].end = x1;
						_scanlines[address].endTU = tu1;
						_scanlines[address].endTV = tv1;
					}
				}		
				if(error >= 0)
				{
					error -= dy2;
					x1 += xInc;
				}
				error += dx2;
				y1 += yInc;
				tu2 += dtu;
				tv2 += dtv;
			}
		}
	}
}

Share this post


Link to post
Share on other sites
Advertisement
Ehm...seems pretty enourmous.U can try making it A LOT smaller.Even with perspective mapping,mip-mapping and scanline subdivision my code looks smaller.Are u using DDraw?

"Tonight we strike,there is thunder in the sky,together we''ll fight,some of us will die,but they''ll always remember that we''ve made a stand and many will die by hand!" - ManOwaR

Share this post


Link to post
Share on other sites
Why do you use statics for all your local variables? They ain't any faster, if not slower, than normal locals. I used to think that they would be faster too, because you wouldn't have to allocate them each time you run the function, but that's not true. Local variables are placed on the stack, a block of memory of 1 or 2 mb or so (depending on the compiler), and the only extra time local variables cost, is on a function call, when it has to update the stack pointer so that it points to the top of the stack again. static variables can be slower, because there's more chance that they are not in the cache.

My Site

[edited by - Quasar3D on August 17, 2003 4:32:36 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Don''t cast a float to an int with (int). Its hella slow.

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
Don''t cast a float to an int with (int). Its hella slow.



In the DOS GFX programming there is a term called ''cast table''.Check it out!

"Tonight we strike,there is thunder in the sky,together we''ll fight,some of us will die,but they''ll always remember that we''ve made a stand and many will die by hand!" - ManOwaR

Share this post


Link to post
Share on other sites
Well, I always rendered each scanline as I came to it, rather than wasting the memory to store a list, then drawing the list... I just drew as I got values (each scanline). It was rather fast, and more efficient (memory wise, and probably speed wise due to not first building, then traversing a list).

Share this post


Link to post
Share on other sites
Good thing with mapping polygons like Zefrieg does is that it''s really simple to allow >3 sides, you just scan a few sides more. This is good for clipped triangles, but I guess the direct method might be quicker for full, non-clipped triangles.

You can also reduce the two checks for the extreme bounds into two functions doing it directly, but I won''t go into that...

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!