Esempio n. 1
0
void raster_tri_rgb_swap_rb(CRasterRGBTriangle2DInfo& info)
{
	if (info.clip_left < 0)
		info.clip_left = 0;
	if (info.clip_right > info.dest_width)
		info.clip_right = info.dest_width;
	if (info.clip_top < 0)
		info.clip_top = 0;
	if (info.clip_bottom > info.dest_height)
		info.clip_bottom = info.dest_height;

	typedef struct
	{
		float* v0, *v1;			/* Y(v0) < Y(v1) */
		float* tv0, *tv1;
		BYTE* cv0, *cv1;
		float dx;				/* X(v1) - X(v0) */
		float dy;				/* Y(v1) - Y(v0) */
		int fdxdy;				/* dx/dy in fixed-point */
		int fsx;				/* first sample point x coord */
		int fsy;
		float adjy;				/* adjust from v[0]->fy to fsy, scaled */
		int lines;				/* number of lines to be sampled on this edge */
		int fx0;				/* fixed pt X of lower endpoint */
	} EdgeT;

	EdgeT eMaj, eTop, eBot;
	float oneOverArea;

	float* vMin, *vMid, *vMax;       /* vertex indices:  Y(vMin)<=Y(vMid)<=Y(vMax) */
	float* tvMin, *tvMid, *tvMax;
	BYTE* cvMin, *cvMid, *cvMax;

	/* find the order of the 3 vertices along the Y axis */
	float y0 = info.v0[1];
	float y1 = info.v1[1];
	float y2 = info.v2[1];

	if (y0 <= y1) {
		if (y1 <= y2) {
			vMin = info.v0;   vMid = info.v1;   vMax = info.v2;   /* y0<=y1<=y2 */
			tvMin = info.tv0;   tvMid = info.tv1;   tvMax = info.tv2;   /* y0<=y1<=y2 */
			cvMin = info.cv0;   cvMid = info.cv1;   cvMax = info.cv2;   /* y0<=y1<=y2 */
		}
		else if (y2 <= y0) {
			vMin = info.v2;   vMid = info.v0;   vMax = info.v1;   /* y2<=y0<=y1 */
			tvMin = info.tv2;   tvMid = info.tv0;   tvMax = info.tv1;   /* y2<=y0<=y1 */
			cvMin = info.cv2;   cvMid = info.cv0;   cvMax = info.cv1;   /* y2<=y0<=y1 */
		}
		else {
			vMin = info.v0;   vMid = info.v2;   vMax = info.v1;   /* y0<=y2<=y1 */
			tvMin = info.tv0;   tvMid = info.tv2;   tvMax = info.tv1;   /* y0<=y2<=y1 */
			cvMin = info.cv0;   cvMid = info.cv2;   cvMax = info.cv1;   /* y0<=y2<=y1 */
		}
	}
	else {
		if (y0 <= y2) {
			vMin = info.v1;   vMid = info.v0;   vMax = info.v2;   /* y1<=y0<=y2 */
			tvMin = info.tv1;   tvMid = info.tv0;   tvMax = info.tv2;   /* y1<=y0<=y2 */
			cvMin = info.cv1;   cvMid = info.cv0;   cvMax = info.cv2;   /* y1<=y0<=y2 */
		}
		else if (y2 <= y1) {
			vMin = info.v2;   vMid = info.v1;   vMax = info.v0;   /* y2<=y1<=y0 */
			tvMin = info.tv2;  tvMid = info.tv1;   tvMax = info.tv0;   /* y2<=y1<=y0 */
			cvMin = info.cv2;  cvMid = info.cv1;   cvMax = info.cv0;   /* y2<=y1<=y0 */
		}
		else {
			vMin = info.v1;   vMid = info.v2;   vMax = info.v0;   /* y1<=y2<=y0 */
			tvMin = info.tv1;   tvMid = info.tv2;   tvMax = info.tv0;   /* y1<=y2<=y0 */
			cvMin = info.cv1;   cvMid = info.cv2;   cvMax = info.cv0;   /* y1<=y2<=y0 */
		}
	}

	/* vertex/edge relationship */
	eMaj.v0 = vMin;   eMaj.v1 = vMax;
	eTop.v0 = vMid;   eTop.v1 = vMax;
	eBot.v0 = vMin;   eBot.v1 = vMid;

	eMaj.tv0 = tvMin;   eMaj.tv1 = tvMax;
	eTop.tv0 = tvMid;   eTop.tv1 = tvMax;
	eBot.tv0 = tvMin;   eBot.tv1 = tvMid;

	eMaj.cv0 = cvMin;   eMaj.cv1 = cvMax;
	eTop.cv0 = cvMid;   eTop.cv1 = cvMax;
	eBot.cv0 = cvMin;   eBot.cv1 = cvMid;

	/* compute deltas for each edge:  vertex[v1] - vertex[v0] */
	eMaj.dx = vMax[0] - vMin[0];
	eMaj.dy = vMax[1] - vMin[1];
	eTop.dx = vMax[0] - vMid[0];
	eTop.dy = vMax[1] - vMid[1];
	eBot.dx = vMid[0] - vMin[0];
	eBot.dy = vMid[1] - vMin[1];

	float area = eMaj.dx * eBot.dy - eBot.dx * eMaj.dy;
	if (area > -0.05f && area < 0.05f)
		return;  /* very small; CULLED */

	oneOverArea = 1.0F / area;

	/* fixed point Y coordinates */
	int vMin_fx = FloatToFixed(vMin[0] + 0.5F);
	int vMin_fy = FloatToFixed(vMin[1] - 0.5F);
	int vMid_fx = FloatToFixed(vMid[0] + 0.5F);
	int vMid_fy = FloatToFixed(vMid[1] - 0.5F);
	int vMax_fy = FloatToFixed(vMax[1] - 0.5F);

	eMaj.fsy = FixedCeil(vMin_fy);
	eMaj.lines = FixedToInt(vMax_fy + FIXED_ONE - FIXED_EPSILON - eMaj.fsy);
	if (eMaj.lines > 0)
	{
		float dxdy = eMaj.dx / eMaj.dy;
		eMaj.fdxdy = SignedFloatToFixed(dxdy);
		eMaj.adjy = (float)(eMaj.fsy - vMin_fy);  /* SCALED! */
		eMaj.fx0 = vMin_fx;
		eMaj.fsx = eMaj.fx0 + (int)(eMaj.adjy * dxdy);
	}
	else
		return;  /*CULLED*/

	eTop.fsy = FixedCeil(vMid_fy);
	eTop.lines = FixedToInt(vMax_fy + FIXED_ONE - FIXED_EPSILON - eTop.fsy);
	if (eTop.lines > 0) {
		float dxdy = eTop.dx / eTop.dy;
		eTop.fdxdy = SignedFloatToFixed(dxdy);
		eTop.adjy = (float)(eTop.fsy - vMid_fy); /* SCALED! */
		eTop.fx0 = vMid_fx;
		eTop.fsx = eTop.fx0 + (int)(eTop.adjy * dxdy);
	}

	eBot.fsy = FixedCeil(vMin_fy);
	eBot.lines = FixedToInt(vMid_fy + FIXED_ONE - FIXED_EPSILON - eBot.fsy);
	if (eBot.lines > 0) {
		float dxdy = eBot.dx / eBot.dy;
		eBot.fdxdy = SignedFloatToFixed(dxdy);
		eBot.adjy = (float)(eBot.fsy - vMin_fy);  /* SCALED! */
		eBot.fx0 = vMin_fx;
		eBot.fsx = eBot.fx0 + (int)(eBot.adjy * dxdy);
	}

	int ltor = (oneOverArea < 0.0F);

	float drdx, drdy;      int fdrdx;
	float dgdx, dgdy;      int fdgdx;
	float dbdx, dbdy;      int fdbdx;
	float dadx, dady;      int fdadx;
	{
		float eMaj_dr, eBot_dr;
		eMaj_dr = (int)cvMax[0] - (int)cvMin[0];
		eBot_dr = (int)cvMid[0] - (int)cvMin[0];
		drdx = oneOverArea * (eMaj_dr * eBot.dy - eMaj.dy * eBot_dr);
		fdrdx = SignedFloatToFixed(drdx);
		drdy = oneOverArea * (eMaj.dx * eBot_dr - eMaj_dr * eBot.dx);
	}
	{
		float eMaj_dg, eBot_dg;
		eMaj_dg = (int)cvMax[1] - (int)cvMin[1];
		eBot_dg = (int)cvMid[1] - (int)cvMin[1];
		dgdx = oneOverArea * (eMaj_dg * eBot.dy - eMaj.dy * eBot_dg);
		fdgdx = SignedFloatToFixed(dgdx);
		dgdy = oneOverArea * (eMaj.dx * eBot_dg - eMaj_dg * eBot.dx);
	}
	{
		float eMaj_db, eBot_db;
		eMaj_db = (int)cvMax[2] - (int)cvMin[2];
		eBot_db = (int)cvMid[2] - (int)cvMin[2];
		dbdx = oneOverArea * (eMaj_db * eBot.dy - eMaj.dy * eBot_db);
		fdbdx = SignedFloatToFixed(dbdx);
		dbdy = oneOverArea * (eMaj.dx * eBot_db - eMaj_db * eBot.dx);
	}

	{
		float eMaj_da, eBot_da;
		eMaj_da = (int)cvMax[3] - (int)cvMin[3];
		eBot_da = (int)cvMid[3] - (int)cvMin[3];
		dadx = oneOverArea * (eMaj_da * eBot.dy - eMaj.dy * eBot_da);
		fdadx = SignedFloatToFixed(dadx);
		dady = oneOverArea * (eMaj.dx * eBot_da - eMaj_da * eBot.dx);
	}



	float wMax = 1.0F;
	float wMin = 1.0F;
	float wMid = 1.0F;

	float eMaj_ds = tvMax[0] * wMax - tvMin[0] * wMin;
	float eBot_ds = tvMid[0] * wMid - tvMin[0] * wMin;
	float eMaj_dt = tvMax[1] * wMax - tvMin[1] * wMin;
	float eBot_dt = tvMid[1] * wMid - tvMin[1] * wMin;

	float dsdx = oneOverArea * (eMaj_ds * eBot.dy - eMaj.dy * eBot_ds);
	float dsdy = oneOverArea * (eMaj.dx * eBot_ds - eMaj_ds * eBot.dx);
	float dtdx = oneOverArea * (eMaj_dt * eBot.dy - eMaj.dy * eBot_dt);
	float dtdy = oneOverArea * (eMaj.dx * eBot_dt - eMaj_dt * eBot.dx);

	int fx, fxLeftEdge, fxRightEdge, fdxLeftEdge, fdxRightEdge;
	int fdxOuter;
	int idxOuter;
	float dxOuter;
	int fError, fdError;
	float adjx, adjy;
	int fy;
	int iy;

	int fr, fdrOuter, fdrInner;
	int fg, fdgOuter, fdgInner;
	int fb, fdbOuter, fdbInner;
	int fa, fdaOuter, fdaInner;

	float sLeft, dsOuter, dsInner;
	float tLeft, dtOuter, dtInner;


	for (int subTriangle = 0; subTriangle <= 1; subTriangle++)
	{
		EdgeT *eLeft, *eRight;
		int setupLeft, setupRight;
		int lines;

		if (subTriangle == 0) {
			/* bottom half */
			if (ltor) {
				eLeft = &eMaj;
				eRight = &eBot;
				lines = eRight->lines;
				setupLeft = 1;
				setupRight = 1;
			}
			else {
				eLeft = &eBot;
				eRight = &eMaj;
				lines = eLeft->lines;
				setupLeft = 1;
				setupRight = 1;
			}
		}
		else {
			/* top half */
			if (ltor)
			{
				eLeft = &eMaj;
				eRight = &eTop;
				lines = eRight->lines;
				setupLeft = 0;
				setupRight = 1;
			}
			else
			{
				eLeft = &eTop;
				eRight = &eMaj;
				lines = eLeft->lines;
				setupLeft = 1;
				setupRight = 0;
			}
			if (lines == 0) return;
		}

		if (setupLeft && eLeft->lines > 0)
		{
			int fsx = eLeft->fsx;
			fx = FixedCeil(fsx);
			fError = fx - fsx - FIXED_ONE;
			fxLeftEdge = fsx - FIXED_EPSILON;
			fdxLeftEdge = eLeft->fdxdy;
			fdxOuter = FixedFloor(fdxLeftEdge - FIXED_EPSILON);
			fdError = fdxOuter - fdxLeftEdge + FIXED_ONE;
			idxOuter = FixedToInt(fdxOuter);
			dxOuter = (float)idxOuter;

			fy = eLeft->fsy;
			iy = FixedToInt(fy);

			adjx = (float)(fx - eLeft->fx0);  /* SCALED! */
			adjy = eLeft->adjy;				 /* SCALED! */

			float* vLower = eLeft->v0;
			float* tvLower = eLeft->tv0;
			BYTE* cvLower = eLeft->cv0;

			sLeft = tvLower[0] * 1.0F + (dsdx * adjx + dsdy * adjy) * (1.0F / FIXED_SCALE);
			dsOuter = dsdy + dxOuter * dsdx;

			tLeft = tvLower[1] * 1.0F + (dtdx * adjx + dtdy * adjy) * (1.0F / FIXED_SCALE);
			dtOuter = dtdy + dxOuter * dtdx;

			fr = (int)(IntToFixed(cvLower[0]) + drdx * adjx + drdy * adjy) + FIXED_HALF;
			fdrOuter = SignedFloatToFixed(drdy + dxOuter * drdx);

			fg = (int)(IntToFixed(cvLower[1]) + dgdx * adjx + dgdy * adjy) + FIXED_HALF;
			fdgOuter = SignedFloatToFixed(dgdy + dxOuter * dgdx);

			fb = (int)(IntToFixed(cvLower[2]) + dbdx * adjx + dbdy * adjy) + FIXED_HALF;
			fdbOuter = SignedFloatToFixed(dbdy + dxOuter * dbdx);

			fa = (int)(IntToFixed(cvLower[3]) + dadx * adjx + dady * adjy) + FIXED_HALF;
			fdaOuter = SignedFloatToFixed(dady + dxOuter * dadx);
		}

		if (setupRight && eRight->lines > 0)
		{
			fxRightEdge = eRight->fsx - FIXED_EPSILON;
			fdxRightEdge = eRight->fdxdy;
		}

		if (lines == 0)
			continue;

		fdrInner = fdrOuter + fdrdx;
		fdgInner = fdgOuter + fdgdx;
		fdbInner = fdbOuter + fdbdx;
		fdaInner = fdaOuter + fdadx;

		dsInner = dsOuter + dsdx;
		dtInner = dtOuter + dtdx;

		if (iy + lines >= info.clip_bottom)
			lines = info.clip_bottom - iy;

		while (lines > 0)
		{
			float ss = sLeft, tt = tLeft;
			int ffr = fr, ffg = fg, ffb = fb;
			int ffa = fa;

			int left = FixedToInt(fxLeftEdge);
			int right = FixedToInt(fxRightEdge);

			int ffrend = ffr + (right - left - 1)*fdrdx;
			int ffgend = ffg + (right - left - 1)*fdgdx;
			int ffbend = ffb + (right - left - 1)*fdbdx;
			if (ffrend < 0) ffr -= ffrend;
			if (ffgend < 0) ffg -= ffgend;
			if (ffbend < 0) ffb -= ffbend;
			if (ffr < 0) ffr = 0;
			if (ffg < 0) ffg = 0;
			if (ffb < 0) ffb = 0;

			int ffaend = ffa + (right - left - 1)*fdadx;
			if (ffaend < 0) ffa -= ffaend;
			if (ffa < 0) ffa = 0;

			int i;
			int n = right - left;

			if (iy >= info.clip_top)
			{

				if (n > 0)
					if (left < info.clip_left)
					{
						int diff = info.clip_left - left;
						ss += dsdx	 *diff;
						tt += dtdx	 *diff;
						ffr += fdrdx *diff;
						ffg += fdgdx *diff;
						ffb += fdbdx *diff;
						ffa += fdadx *diff;

						n -= diff;

						left = info.clip_left;
					}

				if (n > 0)
					if (left + n >= info.clip_right)
					{
						n = info.clip_right - left;
					}

				if (n > 0)
					for (i = 0; i < n; i++)
					{
						int i0, j0, i1, j1;
						float u, v;

						u = ss * info.tex_width;
						v = tt * info.tex_height;



						i0 = (int)floor(u - 0.5F);
						i1 = i0 + 1;
						j0 = (int)floor(v - 0.5F);
						j1 = j0 + 1;


						float a = frac(u - 0.5F);
						float b = frac(v - 0.5F);

						int w00 = (int)((1.0F - a)*(1.0F - b) * 256.0F);
						int w10 = (int)(a *(1.0F - b) * 256.0F);
						int w01 = (int)((1.0F - a)*      b  * 256.0F);
						int w11 = (int)(a *      b  * 256.0F);

						unsigned char red00, green00, blue00, alpha00;
						unsigned char red10, green10, blue10, alpha10;
						unsigned char red01, green01, blue01, alpha01;
						unsigned char red11, green11, blue11, alpha11;

						const unsigned char* texel;

						if (info.tex_repeat)
						{
							if (i0 < 0)
								i0 = info.tex_width + i0;
							else
								if (i0 >= info.tex_width)
									i0 = i0 - info.tex_width;

							if (i1 < 0)
								i1 = info.tex_width + i0;
							else
								if (i1 >= info.tex_width)
									i1 = i1 - info.tex_width;

							if (j0 < 0)
								j0 = info.tex_height + j0;
							else
								if (j0 >= info.tex_height)
									j0 = j0 - info.tex_height;

							if (j1 < 0)
								j1 = info.tex_height + j1;
							else
								if (j1 >= info.tex_height)
									j1 = j1 - info.tex_height;
						}

						BYTE* ppix = (BYTE*)(info.dest + (iy*info.dest_width + left) * 4);
						BYTE pix_r = ppix[i * 4 + 0];
						BYTE pix_g = ppix[i * 4 + 1];
						BYTE pix_b = ppix[i * 4 + 2];
						BYTE pix_a = ppix[i * 4 + 3];

						BYTE border_r = pix_r; //mesa3d cannot do this :)
						BYTE border_g = pix_g;
						BYTE border_b = pix_b;
						BYTE border_a = 0;

						bool i0_border = (i0 < 0 || i0 >= info.tex_width);
						bool i1_border = (i1 < 0 || i1 >= info.tex_width);
						bool j0_border = (j0 < 0 || j0 >= info.tex_height);
						bool j1_border = (j1 < 0 || j1 >= info.tex_height);

						if (i0_border | j0_border)
						{
							red00 = border_r;
							green00 = border_g;
							blue00 = border_b;
							alpha00 = border_a;
						}
						else
						{
							texel = info.tex + (info.tex_width * j0 + i0) * 4;
							red00 = texel[0];
							green00 = texel[1];
							blue00 = texel[2];
							alpha00 = texel[3];
						}

						if (i1_border | j0_border)
						{
							red10 = border_r;
							green10 = border_g;
							blue10 = border_b;
							alpha10 = border_a;
						}
						else
						{
							texel = info.tex + (info.tex_width * j0 + i1) * 4;
							red10 = texel[0];
							green10 = texel[1];
							blue10 = texel[2];
							alpha10 = texel[3];
						}

						if (j1_border | i0_border)
						{
							red01 = border_r;
							green01 = border_g;
							blue01 = border_b;
							alpha01 = border_a;
						}
						else
						{
							texel = info.tex + (info.tex_width * j1 + i0) * 4;
							red01 = texel[0];
							green01 = texel[1];
							blue01 = texel[2];
							alpha01 = texel[3];
						}

						if (i1_border | j1_border)
						{
							red11 = border_r;
							green11 = border_g;
							blue11 = border_b;
							alpha11 = border_a;
						}
						else
						{
							texel = info.tex + (info.tex_width * j1 + i1) * 4;
							red11 = texel[0];
							green11 = texel[1];
							blue11 = texel[2];
							alpha11 = texel[3];
						}

						BYTE _r = (w00*red00 + w10*red10 + w01*red01 + w11*red11) / 256;
						BYTE _g = (w00*green00 + w10*green10 + w01*green01 + w11*green11) / 256;
						BYTE _b = (w00*blue00 + w10*blue10 + w01*blue01 + w11*blue11) / 256;
						BYTE _a = (w00*alpha00 + w10*alpha10 + w01*alpha01 + w11*alpha11) / 256;


						_r = (_r * FixedToInt(ffr)) / 256;
						_g = (_g * FixedToInt(ffg)) / 256;
						_b = (_b * FixedToInt(ffb)) / 256;
						_a = (_a * FixedToInt(ffa)) / 256;

						int t = _a;
						int s = 255 - t;

						ppix[i * 4 + 0] = (_b * t + pix_r * s) / 256; //swap rb
						ppix[i * 4 + 1] = (_g * t + pix_g * s) / 256;
						ppix[i * 4 + 2] = (_r * t + pix_b * s) / 256;
						ppix[i * 4 + 3] = (_a * t + pix_a * s) / 256;

						ss += dsdx;
						tt += dtdx;
						ffr += fdrdx;
						ffg += fdgdx;
						ffb += fdbdx;
						ffa += fdadx;
					}
			}

			iy++;
			lines--;

			fxLeftEdge += fdxLeftEdge;
			fxRightEdge += fdxRightEdge;


			fError += fdError;
			if (fError >= 0)
			{
				fError -= FIXED_ONE;

				sLeft += dsOuter;
				tLeft += dtOuter;
				fr += fdrOuter;
				fg += fdgOuter;
				fb += fdbOuter;
				fa += fdaOuter;
			}
			else {
				sLeft += dsInner;
				tLeft += dtInner;
				fr += fdrInner;
				fg += fdgInner;
				fb += fdbInner;
				fa += fdaInner;
			}
		}
	}
}
Esempio n. 2
0
struct list_t *opengl_sc_rast_triangle_gen_pixel_info(struct opengl_pa_triangle_t *triangle, struct opengl_depth_buffer_t *db)
{
	/* List contains info of pixels inside this triangle */
	struct list_t *pxl_lst;
	struct opengl_sc_pixel_info_t *pxl_info;

	struct opengl_sc_edge_t *edge_major;
	struct opengl_sc_edge_t *edge_top;
	struct opengl_sc_edge_t *edge_bottom;

	struct opengl_pa_vertex_t *vtx_max;
	struct opengl_pa_vertex_t *vtx_mid;
	struct opengl_pa_vertex_t *vtx_min;

	struct opengl_sc_span_t *spn;

	pxl_lst = list_create();
	spn = opengl_sc_span_create();

	float one_over_area;
	int vtx_min_fx, vtx_min_fy;
	int vtx_mid_fx, vtx_mid_fy;
	int vtx_max_fx, vtx_max_fy;
	int scan_from_left_to_right;

	const int snapMask = ~((FIXED_ONE / (1 << SUB_PIXEL_BITS)) - 1); /* for x/y coord snapping */

	const int fy0 = FloatToFixed(triangle->vtx0->pos[Y_COMP] - 0.5F) & snapMask;
	const int fy1 = FloatToFixed(triangle->vtx1->pos[Y_COMP] - 0.5F) & snapMask;
	const int fy2 = FloatToFixed(triangle->vtx2->pos[Y_COMP] - 0.5F) & snapMask;

	/* Find the order of vertex */
	if (fy0 <= fy1)
	{
		if (fy1 <= fy2)
		{
			/* y0 < y1 < y2 */
			vtx_max = triangle->vtx2; vtx_mid = triangle->vtx1; vtx_min = triangle->vtx0;
			vtx_max_fy = fy2; vtx_mid_fy = fy1; vtx_min_fy = fy0;

		}
		else if (fy2 <= fy0)
		{
			/* y2 < y0 < y1 */
			vtx_max = triangle->vtx1; vtx_mid = triangle->vtx0; vtx_min = triangle->vtx2;
			vtx_max_fy = fy1; vtx_mid_fy = fy0; vtx_min_fy = fy2;
		}
		else {
			/* y0 < y2 < y1 */
			vtx_max = triangle->vtx1; vtx_mid = triangle->vtx2; vtx_min = triangle->vtx0;
			vtx_max_fy = fy1; vtx_mid_fy = fy2; vtx_min_fy = fy0;
		}
	}
	else {
		if (fy0 <= fy2)
		{
			/* y1 < y0 < y2 */
			vtx_max = triangle->vtx2; vtx_mid = triangle->vtx0; vtx_min = triangle->vtx1;
			vtx_max_fy = fy2; vtx_mid_fy = fy0; vtx_min_fy = fy1;
		}
		else if (fy2 <= fy1)
		{
			/* y2 < y1 < y0 */
			vtx_max = triangle->vtx0; vtx_mid = triangle->vtx1; vtx_min = triangle->vtx2;
			vtx_max_fy = fy0; vtx_mid_fy = fy1; vtx_min_fy = fy2;
		}
		else {
			/* y1 < y2 < y0 */
			vtx_max = triangle->vtx0; vtx_mid = triangle->vtx2; vtx_min = triangle->vtx1;
			vtx_max_fy = fy0; vtx_mid_fy = fy2; vtx_min_fy = fy1;
		}
	}

	vtx_min_fx = FloatToFixed(vtx_min->pos[X_COMP] + 0.5F) & snapMask;
	vtx_mid_fx = FloatToFixed(vtx_mid->pos[X_COMP] + 0.5F) & snapMask;
	vtx_max_fx = FloatToFixed(vtx_max->pos[X_COMP] + 0.5F) & snapMask;

	/* Create edges */
	edge_major = opengl_sc_edge_create(vtx_max, vtx_min);
	edge_top = opengl_sc_edge_create(vtx_max, vtx_mid);
	edge_bottom = opengl_sc_edge_create(vtx_mid, vtx_min);

	/* compute deltas for each edge:  vertex[upper] - vertex[lower] */
	edge_major->dx = FixedToFloat(vtx_max_fx - vtx_min_fx);
	edge_major->dy = FixedToFloat(vtx_max_fy - vtx_min_fy);
	edge_top->dx = FixedToFloat(vtx_max_fx - vtx_mid_fx);
	edge_top->dy = FixedToFloat(vtx_max_fy - vtx_mid_fy);
	edge_bottom->dx = FixedToFloat(vtx_mid_fx - vtx_min_fx);
	edge_bottom->dy = FixedToFloat(vtx_mid_fy - vtx_min_fy);

	/* Compute area */	
	const float area = edge_major->dx * edge_bottom->dy - edge_bottom->dx * edge_major->dy;
	one_over_area = 1.0f / area;

	/* Edge setup */
	edge_major->fsy = FixedCeil(vtx_min_fy);
	edge_major->lines = FixedToInt(FixedCeil(vtx_max_fy - edge_major->fsy));
	if (edge_major->lines > 0) {
		edge_major->dxdy = edge_major->dx / edge_major->dy;
		edge_major->fdxdy = SignedFloatToFixed(edge_major->dxdy);		
		edge_major->adjy = (float) (edge_major->fsy - vtx_min_fy);  /* SCALED! */
		edge_major->fx0 = vtx_min_fx;
		edge_major->fsx = edge_major->fx0 + (int) (edge_major->adjy * edge_major->dxdy);
	}
	else
	{
		/* Free edges */
		opengl_sc_edge_free(edge_major);
		opengl_sc_edge_free(edge_top);
		opengl_sc_edge_free(edge_bottom);

		/* Free span*/
		opengl_sc_span_free(spn);
		list_free(pxl_lst);

		/*CULLED*/
		return NULL;  
	}

	edge_top->fsy = FixedCeil(vtx_mid_fy);
	edge_top->lines = FixedToInt(FixedCeil(vtx_max_fy - edge_top->fsy));
	if (edge_top->lines > 0)
	{
		edge_top->dxdy = edge_top->dx / edge_top->dy;
		edge_top->fdxdy = SignedFloatToFixed(edge_top->dxdy);		
		edge_top->adjy = (float) (edge_top->fsy - vtx_mid_fy); /* SCALED! */
		edge_top->fx0 = vtx_mid_fx;
		edge_top->fsx = edge_top->fx0 + (int) (edge_top->adjy * edge_top->dxdy);
	}

	edge_bottom->fsy = FixedCeil(vtx_min_fy);
	edge_bottom->lines = FixedToInt(FixedCeil(vtx_mid_fy - edge_bottom->fsy));
	if (edge_bottom->lines > 0)
	{
		edge_bottom->dxdy = edge_bottom->dx / edge_bottom->dy;
		edge_bottom->fdxdy = SignedFloatToFixed(edge_bottom->dxdy);		
		edge_bottom->adjy = (float) (edge_bottom->fsy - vtx_min_fy);  /* SCALED! */
		edge_bottom->fx0 = vtx_min_fx;
		edge_bottom->fsx = edge_bottom->fx0 + (int) (edge_bottom->adjy * edge_bottom->dxdy);
	}

	/* Decide scan direction */
	scan_from_left_to_right = (one_over_area < 0.0F);

	/* Interpolate depth */
	float edge_major_dz = vtx_max->pos[Z_COMP] - vtx_min->pos[Z_COMP];
	float edge_bottom_dz = vtx_mid->pos[Z_COMP] - vtx_min->pos[Z_COMP];
	spn->attrStepX[2] = one_over_area * (edge_major_dz * edge_bottom->dy - edge_major->dy * edge_bottom_dz);
	spn->attrStepY[2] = one_over_area * (edge_major->dx * edge_bottom_dz - edge_major_dz * edge_bottom->dx);
	spn->zStep = SignedFloatToFixed(spn->attrStepX[2]);

	int subTriangle;
	int fxLeftEdge = 0, fxRightEdge = 0;
	int fdxLeftEdge = 0, fdxRightEdge = 0;
	int fError = 0, fdError = 0;

	unsigned int zLeft = 0;
	int fdzOuter = 0, fdzInner;


	/* Setup order of edges */
	for (subTriangle=0; subTriangle<=1; subTriangle++)
	{
		struct opengl_sc_edge_t *edge_left;
		struct opengl_sc_edge_t *edge_right;
		int setupLeft, setupRight;
		int lines;

		if (subTriangle==0) {
			/* bottom half */
			if (scan_from_left_to_right) {
				edge_left = edge_major;
				edge_right = edge_bottom;
				lines = edge_right->lines;
				setupLeft = 1;
				setupRight = 1;
			}
			else {
				edge_left = edge_bottom;
				edge_right = edge_major;
				lines = edge_left->lines;
				setupLeft = 1;
				setupRight = 1;
			}
		} 
		else {
			/* top half */
			if (scan_from_left_to_right) 
			{
				edge_left = edge_major;
				edge_right = edge_top;
				lines = edge_right->lines;
				setupLeft = 0;
				setupRight = 1;
			}
			else {
				edge_left = edge_top;
				edge_right = edge_major;
				lines = edge_left->lines;
				setupLeft = 1;
				setupRight = 0;
			}
			if (lines == 0)
				return NULL;
		}

		if (setupLeft && edge_left->lines > 0)
		{
			const struct opengl_pa_vertex_t *vtx_lower = edge_left->vtx1;
			const int fsy = edge_left->fsy;
			const int fsx = edge_left->fsx;  /* no fractional part */
			const int fx = FixedCeil(fsx);  /* no fractional part */
			const int adjx = (int) (fx - edge_left->fx0); /* SCALED! */
			const int adjy = (int) edge_left->adjy;      /* SCALED! */			
			int idxOuter;
			float dxOuter;			
			int fdxOuter;

			fError = fx - fsx - FIXED_ONE;
			fxLeftEdge = fsx - FIXED_EPSILON;
			fdxLeftEdge = edge_left->fdxdy;
			fdxOuter = FixedFloor(fdxLeftEdge - FIXED_EPSILON);
			fdError = fdxOuter - fdxLeftEdge + FIXED_ONE;
			idxOuter = FixedToInt(fdxOuter);
			dxOuter = (float) idxOuter;
			spn->y = FixedToInt(fsy);

			/* Interpolate Z */
			float z0 = vtx_lower->pos[Z_COMP];
			float tmp = (z0 * FIXED_SCALE + spn->attrStepX[2] * adjx + spn->attrStepY[2] * adjy) + FIXED_HALF;
			if (tmp < MAX_GLUINT / 2)
				zLeft = (int) tmp;
			else
				zLeft = MAX_GLUINT / 2;
			fdzOuter = SignedFloatToFixed(spn->attrStepY[2] + dxOuter * spn->attrStepX[2]);								

		}

		if (setupRight && edge_right->lines>0) 
		{
			fxRightEdge = edge_right->fsx - FIXED_EPSILON;
			fdxRightEdge = edge_right->fdxdy;
		}

		if (lines==0)
			continue;

		/* Interpolate Z */
		fdzInner = fdzOuter + spn->zStep;		

		/* Rasterize setup */
		while (lines > 0)
		{

			/* initialize the spn->interpolants to the leftmost value */
			/* ff = fixed-pt fragment */
			const int right = FixedToInt(fxRightEdge);
			spn->x = FixedToInt(fxLeftEdge);
			if (right <= spn->x)
				spn->end = 0;
			else
				spn->end = right - spn->x;

			/* Interpolate Z */
			spn->z = zLeft;

			/* This is where we actually generate fragments */
			if (spn->end > 0 && spn->y >= 0)
			{
				const int len = spn->end;

				int i;
				for (i = 0; i < len; ++i)
				{
					/* Add if pass depth test */
					if(opengl_depth_buffer_test_and_set_pixel(db, spn->x, spn->y, FixedToFloat(spn->z), db->depth_func))
					{
						pxl_info = opengl_sc_pixel_info_create();
						opengl_sc_pixel_info_set_wndw_cood(pxl_info, spn->x, spn->y, spn->z);
						opengl_sc_pixel_info_set_brctrc_cood(pxl_info, triangle);
						list_add(pxl_lst, pxl_info);
					}
					spn->z += spn->zStep;
					spn->x++;
				}
			}

			/*
			* Advance to the next scan line.  Compute the new edge coordinates, and adjust the
			* pixel-center x coordinate so that it stays on or inside the major edge.
			*/
			spn->y++;
			lines--;

			fxLeftEdge += fdxLeftEdge;
			fxRightEdge += fdxRightEdge;

			fError += fdError;

			if (fError >= 0)
			{
				zLeft += fdzOuter;
				fError -= FIXED_ONE;				
			}
			else
				zLeft += fdzInner;
			
		} /*while lines>0*/
	}

	/* Free edges */
	opengl_sc_edge_free(edge_major);
	opengl_sc_edge_free(edge_top);
	opengl_sc_edge_free(edge_bottom);

	/* Free span*/
	opengl_sc_span_free(spn);

	/* Return */
	return pxl_lst;
}