Jump to content
  • Advertisement
Sign in to follow this  
CPPNick

fixed point math problem

This topic is 3404 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

I tried to implement fixed point math in my triangle fragment drawer, but got very strange results... I already tried outputing the numbers to a text file, but still couldnt make sense of what I was doing wrong. This same routine works fine if I uncomment the old code back in and use regular floats. I don't think its overflow because after clipping, none of the values can exceed 1280 which is the max width of my screen, and 1280 * 65536 = 83886080 = 27 bits here is pictures of my app using float, and then using the fixed point math: FLOAT:
FIXED:
void GEOM::RenderFragment(UINT16 &index, smlVERTEX4 &lefttop, smlVERTEX4 &righttop, smlVERTEX4 &leftbot, smlVERTEX4 &rightbot)
{	
	float lx = lefttop.pos.x;
	float rx = righttop.pos.x;
	
	float dy = leftbot.pos.y - lefttop.pos.y;

	float ml = (leftbot.pos.x - lx) / dy;
	float mr = (rightbot.pos.x - rx) / dy;
	
	m_dy = _mm_set_ps1(dy);
	l_uvws = _mm_setr_ps(lefttop.tex.u, lefttop.tex.v, lefttop.pos.w, lefttop.shade); //set to top left vert values
	r_uvws = _mm_setr_ps(righttop.tex.u, righttop.tex.v, righttop.pos.w, righttop.shade); //set to top right vert values
	l_duvws = _mm_setr_ps(leftbot.tex.u, leftbot.tex.v, leftbot.pos.w, leftbot.shade); //set to bot left vert values
	r_duvws = _mm_setr_ps(rightbot.tex.u, rightbot.tex.v, rightbot.pos.w, rightbot.shade); //set to bot right vert values
	l_duvws = _mm_sub_ps(l_duvws, l_uvws); //subtract to get d_uvws for left
	r_duvws = _mm_sub_ps(r_duvws, r_uvws); //subtract to get d_uvws for right
	l_duvws = _mm_div_ps(l_duvws, m_dy); // divide by change in y
	r_duvws = _mm_div_ps(r_duvws, m_dy); // divide by change in y
	
	textr = &textures[index];
	widsub1 = short(textr->bm.bmWidth - 1);
	hgtsub1 = short(textr->bm.bmHeight - 1);
	
        //multiply by 65536, then cast to long to create the 16.16 fixed point number
	long flx = (long)(lx * 65536.f); //left edge x
	long frx = (long)(rx * 65536.f); //right edge x
	long fml = (long)(ml * 65536.f); //left edge slope
	long fmr = (long)(mr * 65536.f); //right edge slope

	for(sy = short(lefttop.pos.y); sy < short(leftbot.pos.y); sy++)
	{
		h_uvws = l_uvws;
		h_duvws = _mm_sub_ps(r_uvws, l_uvws);
		m_dx = _mm_set_ps1(rx - lx);
		h_duvws = _mm_div_ps(h_duvws, m_dx);

		//shrt_lx = short(lx);
		//shrt_rx = short(rx);
		short shrt_lx = (short)(flx>>16); //shift right 16 and cast to short
		short shrt_rx = (short)(frx>>16); //same as flooring the float

		pix = bit(shrt_lx, sy); //select the bit in screen and zbuffer that will be plotted
		screen_ptr = &p_bits[pix];
		zbuff_ptr = &z_buffer[pix];

                //loop through the span
		for(sx = shrt_lx; sx < shrt_rx; sx++)
		{
			if(f_uvws[2] > *zbuff_ptr)
			{
				*zbuff_ptr = f_uvws[2];
				m_fin = _mm_set_ps1(f_uvws[2]);
				m_fin = _mm_div_ps(h_uvws, m_fin);

				pixel_x = short(fin[0] * widsub1) % widsub1;
				pixel_y = short(fin[1] * hgtsub1) % hgtsub1;

				texbit = textr->bits[pixel_y * textr->bm.bmWidth + pixel_x];
				*screen_ptr = texbit;
			}
			zbuff_ptr++;
			screen_ptr++;
			h_uvws = _mm_add_ps(h_uvws, h_duvws);
		}
		//lsx += ml;
		//rsx += mr;
		flx += fml; //increment the left edge
		frx += fmr; //increment the right edge

		l_uvws = _mm_add_ps(l_uvws, l_duvws);
		r_uvws = _mm_add_ps(r_uvws, r_duvws);
	}
}


Thanks for any help =)

Share this post


Link to post
Share on other sites
Advertisement
looks to me like you'd might have some sign problem, but without debugging it, it's not that obvious to see.

but I've seen some wtf ;)

pixel_x = short(fin[0] * widsub1) % widsub1;
pixel_y = short(fin[1] * hgtsub1) % hgtsub1;

all your optimisation are kind gone, doing two integer modulo per pixel, really.

maybe you should consider using just power of two textures (and yeah, that's the reason why they've been the only that gfx cards support for a long time), cause then it's a simple


pixel_x = short(fin[0] * widsub1) & (widsub1-1);
pixel_y = short(fin[1] * hgtsub1) & (hgtsub1-1);

beside that, you should consider having fin already multiplied by widsub1 during the triangle setup, that would save you two mul per pixel, so you'd have an inner code with like twice the speed ;)

Share this post


Link to post
Share on other sites
thanks for the suggestion about the fin variable...Ill consider changing that if I can, but on a more shameful note...

m_dx = _mm_set_ps1(rx - lx);

//lsx += ml; <-- forgot to change the above to fixed when i commented these out
//rsx += mr; <-- how did I not see this? ugh...

*sigh*
thanks anyways

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • 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!