Home | History | Annotate | Download | only in client
      1 /*
      2 Copyright (C) 1996-1997 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 //
     21 // r_drawa.s
     22 // x86 assembly-language edge clipping and emission code
     23 //
     24 
     25 #include "asm_i386.h"
     26 #include "quakeasm.h"
     27 #include "asm_draw.h"
     28 #include "d_ifacea.h"
     29 
     30 #if	id386
     31 
     32 // !!! if these are changed, they must be changed in r_draw.c too !!!
     33 #define FULLY_CLIPPED_CACHED	0x80000000
     34 #define FRAMECOUNT_MASK			0x7FFFFFFF
     35 
     36 	.data
     37 
     38 Ld0:			.single		0.0
     39 Ld1:			.single		0.0
     40 Lstack:			.long		0
     41 Lfp_near_clip:	.single		NEAR_CLIP
     42 Lceilv0:		.long		0
     43 Lv:				.long		0
     44 Lu0:			.long		0
     45 Lv0:			.long		0
     46 Lzi0:			.long		0
     47 
     48 	.text
     49 
     50 //----------------------------------------------------------------------
     51 // edge clipping code
     52 //----------------------------------------------------------------------
     53 
     54 #define pv0		4+12
     55 #define pv1		8+12
     56 #define clip	12+12
     57 
     58 	.align 4
     59 .globl C(R_ClipEdge)
     60 C(R_ClipEdge):
     61 	pushl	%esi				// preserve register variables
     62 	pushl	%edi
     63 	pushl	%ebx
     64 	movl	%esp,Lstack			// for clearing the stack later
     65 
     66 //	float		d0, d1, f;
     67 //	mvertex_t	clipvert;
     68 
     69 	movl	clip(%esp),%ebx
     70 	movl	pv0(%esp),%esi
     71 	movl	pv1(%esp),%edx
     72 
     73 //	if (clip)
     74 //	{
     75 	testl	%ebx,%ebx
     76 	jz		Lemit
     77 
     78 //		do
     79 //		{
     80 
     81 Lcliploop:
     82 
     83 //			d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
     84 //			d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
     85 	flds	mv_position+0(%esi)
     86 	fmuls	cp_normal+0(%ebx)
     87 	flds	mv_position+4(%esi)
     88 	fmuls	cp_normal+4(%ebx)
     89 	flds	mv_position+8(%esi)
     90 	fmuls	cp_normal+8(%ebx)
     91 	fxch	%st(1)
     92 	faddp	%st(0),%st(2)		// d0mul2 | d0add0
     93 
     94 	flds	mv_position+0(%edx)
     95 	fmuls	cp_normal+0(%ebx)
     96 	flds	mv_position+4(%edx)
     97 	fmuls	cp_normal+4(%ebx)
     98 	flds	mv_position+8(%edx)
     99 	fmuls	cp_normal+8(%ebx)
    100 	fxch	%st(1)
    101 	faddp	%st(0),%st(2)		// d1mul2 | d1add0 | d0mul2 | d0add0
    102 	fxch	%st(3)				// d0add0 | d1add0 | d0mul2 | d1mul2
    103 
    104 	faddp	%st(0),%st(2)		// d1add0 | dot0 | d1mul2
    105 	faddp	%st(0),%st(2)		// dot0 | dot1
    106 
    107 	fsubs	cp_dist(%ebx)		// d0 | dot1
    108 	fxch	%st(1)				// dot1 | d0
    109 	fsubs	cp_dist(%ebx)		// d1 | d0
    110 	fxch	%st(1)
    111 	fstps	Ld0
    112 	fstps	Ld1
    113 
    114 //			if (d0 >= 0)
    115 //			{
    116 	movl	Ld0,%eax
    117 	movl	Ld1,%ecx
    118 	orl		%eax,%ecx
    119 	js		Lp2
    120 
    121 // both points are unclipped
    122 
    123 Lcontinue:
    124 
    125 //
    126 //				R_ClipEdge (&clipvert, pv1, clip->next);
    127 //				return;
    128 //			}
    129 //		} while ((clip = clip->next) != NULL);
    130 	movl	cp_next(%ebx),%ebx
    131 	testl	%ebx,%ebx
    132 	jnz		Lcliploop
    133 
    134 //	}
    135 
    136 //// add the edge
    137 //	R_EmitEdge (pv0, pv1);
    138 Lemit:
    139 
    140 //
    141 // set integer rounding to ceil mode, set to single precision
    142 //
    143 // FIXME: do away with by manually extracting integers from floats?
    144 // FIXME: set less often
    145 	fldcw	ceil_cw
    146 
    147 //	edge_t	*edge, *pcheck;
    148 //	int		u_check;
    149 //	float	u, u_step;
    150 //	vec3_t	local, transformed;
    151 //	float	*world;
    152 //	int		v, v2, ceilv0;
    153 //	float	scale, lzi0, u0, v0;
    154 //	int		side;
    155 
    156 //	if (r_lastvertvalid)
    157 //	{
    158 	cmpl	$0,C(r_lastvertvalid)
    159 	jz		LCalcFirst
    160 
    161 //		u0 = r_u1;
    162 //		v0 = r_v1;
    163 //		lzi0 = r_lzi1;
    164 //		ceilv0 = r_ceilv1;
    165 	movl	C(r_lzi1),%eax
    166 	movl	C(r_u1),%ecx
    167 	movl	%eax,Lzi0
    168 	movl	%ecx,Lu0
    169 	movl	C(r_v1),%ecx
    170 	movl	C(r_ceilv1),%eax
    171 	movl	%ecx,Lv0
    172 	movl	%eax,Lceilv0
    173 	jmp		LCalcSecond
    174 
    175 //	}
    176 
    177 LCalcFirst:
    178 
    179 //	else
    180 //	{
    181 //		world = &pv0->position[0];
    182 
    183 	call	LTransformAndProject	// v0 | lzi0 | u0
    184 
    185 	fsts	Lv0
    186 	fxch	%st(2)					// u0 | lzi0 | v0
    187 	fstps	Lu0						// lzi0 | v0
    188 	fstps	Lzi0					// v0
    189 
    190 //		ceilv0 = (int)(v0 - 2000) + 2000; // ceil(v0);
    191 	fistpl	Lceilv0
    192 
    193 //	}
    194 
    195 LCalcSecond:
    196 
    197 //	world = &pv1->position[0];
    198 	movl	%edx,%esi
    199 
    200 	call	LTransformAndProject	// v1 | lzi1 | u1
    201 
    202 	flds	Lu0						// u0 | v1 | lzi1 | u1
    203 	fxch	%st(3)					// u1 | v1 | lzi1 | u0
    204 	flds	Lzi0					// lzi0 | u1 | v1 | lzi1 | u0
    205 	fxch	%st(3)					// lzi1 | u1 | v1 | lzi0 | u0
    206 	flds	Lv0						// v0 | lzi1 | u1 | v1 | lzi0 | u0
    207 	fxch	%st(3)					// v1 | lzi1 | u1 | v0 | lzi0 | u0
    208 
    209 //	r_ceilv1 = (int)(r_v1 - 2000) + 2000; // ceil(r_v1);
    210 	fistl	C(r_ceilv1)
    211 
    212 	fldcw	single_cw				// put back normal floating-point state
    213 
    214 	fsts	C(r_v1)
    215 	fxch	%st(4)					// lzi0 | lzi1 | u1 | v0 | v1 | u0
    216 
    217 //	if (r_lzi1 > lzi0)
    218 //		lzi0 = r_lzi1;
    219 	fcom	%st(1)
    220 	fnstsw	%ax
    221 	testb	$1,%ah
    222 	jz		LP0
    223 	fstp	%st(0)
    224 	fld		%st(0)
    225 LP0:
    226 
    227 	fxch	%st(1)					// lzi1 | lzi0 | u1 | v0 | v1 | u0
    228 	fstps	C(r_lzi1)				// lzi0 | u1 | v0 | v1 | u0
    229 	fxch	%st(1)
    230 	fsts	C(r_u1)
    231 	fxch	%st(1)
    232 
    233 //	if (lzi0 > r_nearzi)	// for mipmap finding
    234 //		r_nearzi = lzi0;
    235 	fcoms	C(r_nearzi)
    236 	fnstsw	%ax
    237 	testb	$0x45,%ah
    238 	jnz		LP1
    239 	fsts	C(r_nearzi)
    240 LP1:
    241 
    242 // // for right edges, all we want is the effect on 1/z
    243 //	if (r_nearzionly)
    244 //		return;
    245 	movl	C(r_nearzionly),%eax
    246 	testl	%eax,%eax
    247 	jz		LP2
    248 LPop5AndDone:
    249 	movl	C(cacheoffset),%eax
    250 	movl	C(r_framecount),%edx
    251 	cmpl	$0x7FFFFFFF,%eax
    252 	jz		LDoPop
    253 	andl	$(FRAMECOUNT_MASK),%edx
    254 	orl		$(FULLY_CLIPPED_CACHED),%edx
    255 	movl	%edx,C(cacheoffset)
    256 
    257 LDoPop:
    258 	fstp	%st(0)			// u1 | v0 | v1 | u0
    259 	fstp	%st(0)			// v0 | v1 | u0
    260 	fstp	%st(0)			// v1 | u0
    261 	fstp	%st(0)			// u0
    262 	fstp	%st(0)
    263 	jmp		Ldone
    264 
    265 LP2:
    266 
    267 // // create the edge
    268 //	if (ceilv0 == r_ceilv1)
    269 //		return;		// horizontal edge
    270 	movl	Lceilv0,%ebx
    271 	movl	C(edge_p),%edi
    272 	movl	C(r_ceilv1),%ecx
    273 	movl	%edi,%edx
    274 	movl	C(r_pedge),%esi
    275 	addl	$(et_size),%edx
    276 	cmpl	%ecx,%ebx
    277 	jz		LPop5AndDone
    278 
    279 	movl	C(r_pedge),%eax
    280 	movl	%eax,et_owner(%edi)
    281 
    282 //	side = ceilv0 > r_ceilv1;
    283 //
    284 //	edge->nearzi = lzi0;
    285 	fstps	et_nearzi(%edi)		// u1 | v0 | v1 | u0
    286 
    287 //	if (side == 1)
    288 //	{
    289 	jc		LSide0
    290 
    291 LSide1:
    292 
    293 //	// leading edge (go from p2 to p1)
    294 
    295 //		u_step = ((u0 - r_u1) / (v0 - r_v1));
    296 	fsubrp	%st(0),%st(3)		// v0 | v1 | u0-u1
    297 	fsub	%st(1),%st(0)		// v0-v1 | v1 | u0-u1
    298 	fdivrp	%st(0),%st(2)		// v1 | ustep
    299 
    300 //	r_emitted = 1;
    301 	movl	$1,C(r_emitted)
    302 
    303 //	edge = edge_p++;
    304 	movl	%edx,C(edge_p)
    305 
    306 // pretouch next edge
    307 	movl	(%edx),%eax
    308 
    309 //		v2 = ceilv0 - 1;
    310 //		v = r_ceilv1;
    311 	movl	%ecx,%eax
    312 	leal	-1(%ebx),%ecx
    313 	movl	%eax,%ebx
    314 
    315 //		edge->surfs[0] = 0;
    316 //		edge->surfs[1] = surface_p - surfaces;
    317 	movl	C(surface_p),%eax
    318 	movl	C(surfaces),%esi
    319 	subl	%edx,%edx
    320 	subl	%esi,%eax
    321 	shrl	$(SURF_T_SHIFT),%eax
    322 	movl	%edx,et_surfs(%edi)
    323 	movl	%eax,et_surfs+2(%edi)
    324 
    325 	subl	%esi,%esi
    326 
    327 //		u = r_u1 + ((float)v - r_v1) * u_step;
    328 	movl	%ebx,Lv
    329 	fildl	Lv					// v | v1 | ustep
    330 	fsubp	%st(0),%st(1)		// v-v1 | ustep
    331 	fmul	%st(1),%st(0)		// (v-v1)*ustep | ustep
    332 	fadds	C(r_u1)				// u | ustep
    333 
    334 	jmp		LSideDone
    335 
    336 //	}
    337 
    338 LSide0:
    339 
    340 //	else
    341 //	{
    342 //	// trailing edge (go from p1 to p2)
    343 
    344 //		u_step = ((r_u1 - u0) / (r_v1 - v0));
    345 	fsub	%st(3),%st(0)		// u1-u0 | v0 | v1 | u0
    346 	fxch	%st(2)				// v1 | v0 | u1-u0 | u0
    347 	fsub	%st(1),%st(0)		// v1-v0 | v0 | u1-u0 | u0
    348 	fdivrp	%st(0),%st(2)		// v0 | ustep | u0
    349 
    350 //	r_emitted = 1;
    351 	movl	$1,C(r_emitted)
    352 
    353 //	edge = edge_p++;
    354 	movl	%edx,C(edge_p)
    355 
    356 // pretouch next edge
    357 	movl	(%edx),%eax
    358 
    359 //		v = ceilv0;
    360 //		v2 = r_ceilv1 - 1;
    361 	decl	%ecx
    362 
    363 //		edge->surfs[0] = surface_p - surfaces;
    364 //		edge->surfs[1] = 0;
    365 	movl	C(surface_p),%eax
    366 	movl	C(surfaces),%esi
    367 	subl	%edx,%edx
    368 	subl	%esi,%eax
    369 	shrl	$(SURF_T_SHIFT),%eax
    370 	movl	%edx,et_surfs+2(%edi)
    371 	movl	%eax,et_surfs(%edi)
    372 
    373 	movl	$1,%esi
    374 
    375 //		u = u0 + ((float)v - v0) * u_step;
    376 	movl	%ebx,Lv
    377 	fildl	Lv					// v | v0 | ustep | u0
    378 	fsubp	%st(0),%st(1)		// v-v0 | ustep | u0
    379 	fmul	%st(1),%st(0)		// (v-v0)*ustep | ustep | u0
    380 	faddp	%st(0),%st(2)		// ustep | u
    381 	fxch	%st(1)				// u | ustep
    382 
    383 //	}
    384 
    385 LSideDone:
    386 
    387 //	edge->u_step = u_step*0x100000;
    388 //	edge->u = u*0x100000 + 0xFFFFF;
    389 
    390 	fmuls	fp_1m				// u*0x100000 | ustep
    391 	fxch	%st(1)				// ustep | u*0x100000
    392 	fmuls	fp_1m				// ustep*0x100000 | u*0x100000
    393 	fxch	%st(1)				// u*0x100000 | ustep*0x100000
    394 	fadds	fp_1m_minus_1		// u*0x100000 + 0xFFFFF | ustep*0x100000
    395 	fxch	%st(1)				// ustep*0x100000 | u*0x100000 + 0xFFFFF
    396 	fistpl	et_u_step(%edi)		// u*0x100000 + 0xFFFFF
    397 	fistpl	et_u(%edi)
    398 
    399 // // we need to do this to avoid stepping off the edges if a very nearly
    400 // // horizontal edge is less than epsilon above a scan, and numeric error
    401 // // causes it to incorrectly extend to the scan, and the extension of the
    402 // // line goes off the edge of the screen
    403 // // FIXME: is this actually needed?
    404 //	if (edge->u < r_refdef.vrect_x_adj_shift20)
    405 //		edge->u = r_refdef.vrect_x_adj_shift20;
    406 //	if (edge->u > r_refdef.vrectright_adj_shift20)
    407 //		edge->u = r_refdef.vrectright_adj_shift20;
    408 	movl	et_u(%edi),%eax
    409 	movl	C(r_refdef)+rd_vrect_x_adj_shift20,%edx
    410 	cmpl	%edx,%eax
    411 	jl		LP4
    412 	movl	C(r_refdef)+rd_vrectright_adj_shift20,%edx
    413 	cmpl	%edx,%eax
    414 	jng		LP5
    415 LP4:
    416 	movl	%edx,et_u(%edi)
    417 	movl	%edx,%eax
    418 LP5:
    419 
    420 // // sort the edge in normally
    421 //	u_check = edge->u;
    422 //
    423 //	if (edge->surfs[0])
    424 //		u_check++;	// sort trailers after leaders
    425 	addl	%esi,%eax
    426 
    427 //	if (!newedges[v] || newedges[v]->u >= u_check)
    428 //	{
    429 	movl	C(newedges)(,%ebx,4),%esi
    430 	testl	%esi,%esi
    431 	jz		LDoFirst
    432 	cmpl	%eax,et_u(%esi)
    433 	jl		LNotFirst
    434 LDoFirst:
    435 
    436 //		edge->next = newedges[v];
    437 //		newedges[v] = edge;
    438 	movl	%esi,et_next(%edi)
    439 	movl	%edi,C(newedges)(,%ebx,4)
    440 
    441 	jmp		LSetRemove
    442 
    443 //	}
    444 
    445 LNotFirst:
    446 
    447 //	else
    448 //	{
    449 //		pcheck = newedges[v];
    450 //
    451 //		while (pcheck->next && pcheck->next->u < u_check)
    452 //			pcheck = pcheck->next;
    453 LFindInsertLoop:
    454 	movl	%esi,%edx
    455 	movl	et_next(%esi),%esi
    456 	testl	%esi,%esi
    457 	jz		LInsertFound
    458 	cmpl	%eax,et_u(%esi)
    459 	jl		LFindInsertLoop
    460 
    461 LInsertFound:
    462 
    463 //		edge->next = pcheck->next;
    464 //		pcheck->next = edge;
    465 	movl	%esi,et_next(%edi)
    466 	movl	%edi,et_next(%edx)
    467 
    468 //	}
    469 
    470 LSetRemove:
    471 
    472 //	edge->nextremove = removeedges[v2];
    473 //	removeedges[v2] = edge;
    474 	movl	C(removeedges)(,%ecx,4),%eax
    475 	movl	%edi,C(removeedges)(,%ecx,4)
    476 	movl	%eax,et_nextremove(%edi)
    477 
    478 Ldone:
    479 	movl	Lstack,%esp			// clear temporary variables from stack
    480 
    481 	popl	%ebx				// restore register variables
    482 	popl	%edi
    483 	popl	%esi
    484 	ret
    485 
    486 // at least one point is clipped
    487 
    488 Lp2:
    489 	testl	%eax,%eax
    490 	jns		Lp1
    491 
    492 //			else
    493 //			{
    494 //			// point 0 is clipped
    495 
    496 //				if (d1 < 0)
    497 //				{
    498 	movl	Ld1,%eax
    499 	testl	%eax,%eax
    500 	jns		Lp3
    501 
    502 //				// both points are clipped
    503 //				// we do cache fully clipped edges
    504 //					if (!leftclipped)
    505 	movl	C(r_leftclipped),%eax
    506 	movl	C(r_pedge),%ecx
    507 	testl	%eax,%eax
    508 	jnz		Ldone
    509 
    510 //						r_pedge->framecount = r_framecount;
    511 	movl	C(r_framecount),%eax
    512 	andl	$(FRAMECOUNT_MASK),%eax
    513 	orl		$(FULLY_CLIPPED_CACHED),%eax
    514 	movl	%eax,C(cacheoffset)
    515 
    516 //					return;
    517 	jmp		Ldone
    518 
    519 //				}
    520 
    521 Lp1:
    522 
    523 //			// point 0 is unclipped
    524 //				if (d1 >= 0)
    525 //				{
    526 //				// both points are unclipped
    527 //					continue;
    528 
    529 //			// only point 1 is clipped
    530 
    531 //				f = d0 / (d0 - d1);
    532 	flds	Ld0
    533 	flds	Ld1
    534 	fsubr	%st(1),%st(0)
    535 
    536 //			// we don't cache partially clipped edges
    537 	movl	$0x7FFFFFFF,C(cacheoffset)
    538 
    539 	fdivrp	%st(0),%st(1)
    540 
    541 	subl	$(mv_size),%esp			// allocate space for clipvert
    542 
    543 //				clipvert.position[0] = pv0->position[0] +
    544 //						f * (pv1->position[0] - pv0->position[0]);
    545 //				clipvert.position[1] = pv0->position[1] +
    546 //						f * (pv1->position[1] - pv0->position[1]);
    547 //				clipvert.position[2] = pv0->position[2] +
    548 //						f * (pv1->position[2] - pv0->position[2]);
    549 	flds	mv_position+8(%edx)
    550 	fsubs	mv_position+8(%esi)
    551 	flds	mv_position+4(%edx)
    552 	fsubs	mv_position+4(%esi)
    553 	flds	mv_position+0(%edx)
    554 	fsubs	mv_position+0(%esi)		// 0 | 1 | 2
    555 
    556 // replace pv1 with the clip point
    557 	movl	%esp,%edx
    558 	movl	cp_leftedge(%ebx),%eax
    559 	testb	%al,%al
    560 
    561 	fmul	%st(3),%st(0)
    562 	fxch	%st(1)					// 1 | 0 | 2
    563 	fmul	%st(3),%st(0)
    564 	fxch	%st(2)					// 2 | 0 | 1
    565 	fmulp	%st(0),%st(3)			// 0 | 1 | 2
    566 	fadds	mv_position+0(%esi)
    567 	fxch	%st(1)					// 1 | 0 | 2
    568 	fadds	mv_position+4(%esi)
    569 	fxch	%st(2)					// 2 | 0 | 1
    570 	fadds	mv_position+8(%esi)
    571 	fxch	%st(1)					// 0 | 2 | 1
    572 	fstps	mv_position+0(%esp)		// 2 | 1
    573 	fstps	mv_position+8(%esp)		// 1
    574 	fstps	mv_position+4(%esp)
    575 
    576 //				if (clip->leftedge)
    577 //				{
    578 	jz		Ltestright
    579 
    580 //					r_leftclipped = true;
    581 //					r_leftexit = clipvert;
    582 	movl	$1,C(r_leftclipped)
    583 	movl	mv_position+0(%esp),%eax
    584 	movl	%eax,C(r_leftexit)+mv_position+0
    585 	movl	mv_position+4(%esp),%eax
    586 	movl	%eax,C(r_leftexit)+mv_position+4
    587 	movl	mv_position+8(%esp),%eax
    588 	movl	%eax,C(r_leftexit)+mv_position+8
    589 
    590 	jmp		Lcontinue
    591 
    592 //				}
    593 
    594 Ltestright:
    595 //				else if (clip->rightedge)
    596 //				{
    597 	testb	%ah,%ah
    598 	jz		Lcontinue
    599 
    600 //					r_rightclipped = true;
    601 //					r_rightexit = clipvert;
    602 	movl	$1,C(r_rightclipped)
    603 	movl	mv_position+0(%esp),%eax
    604 	movl	%eax,C(r_rightexit)+mv_position+0
    605 	movl	mv_position+4(%esp),%eax
    606 	movl	%eax,C(r_rightexit)+mv_position+4
    607 	movl	mv_position+8(%esp),%eax
    608 	movl	%eax,C(r_rightexit)+mv_position+8
    609 
    610 //				}
    611 //
    612 //				R_ClipEdge (pv0, &clipvert, clip->next);
    613 //				return;
    614 //			}
    615 	jmp		Lcontinue
    616 
    617 //			}
    618 
    619 Lp3:
    620 
    621 //			// only point 0 is clipped
    622 //				r_lastvertvalid = false;
    623 
    624 	movl	$0,C(r_lastvertvalid)
    625 
    626 //				f = d0 / (d0 - d1);
    627 	flds	Ld0
    628 	flds	Ld1
    629 	fsubr	%st(1),%st(0)
    630 
    631 //			// we don't cache partially clipped edges
    632 	movl	$0x7FFFFFFF,C(cacheoffset)
    633 
    634 	fdivrp	%st(0),%st(1)
    635 
    636 	subl	$(mv_size),%esp			// allocate space for clipvert
    637 
    638 //				clipvert.position[0] = pv0->position[0] +
    639 //						f * (pv1->position[0] - pv0->position[0]);
    640 //				clipvert.position[1] = pv0->position[1] +
    641 //						f * (pv1->position[1] - pv0->position[1]);
    642 //				clipvert.position[2] = pv0->position[2] +
    643 //						f * (pv1->position[2] - pv0->position[2]);
    644 	flds	mv_position+8(%edx)
    645 	fsubs	mv_position+8(%esi)
    646 	flds	mv_position+4(%edx)
    647 	fsubs	mv_position+4(%esi)
    648 	flds	mv_position+0(%edx)
    649 	fsubs	mv_position+0(%esi)		// 0 | 1 | 2
    650 
    651 	movl	cp_leftedge(%ebx),%eax
    652 	testb	%al,%al
    653 
    654 	fmul	%st(3),%st(0)
    655 	fxch	%st(1)					// 1 | 0 | 2
    656 	fmul	%st(3),%st(0)
    657 	fxch	%st(2)					// 2 | 0 | 1
    658 	fmulp	%st(0),%st(3)			// 0 | 1 | 2
    659 	fadds	mv_position+0(%esi)
    660 	fxch	%st(1)					// 1 | 0 | 2
    661 	fadds	mv_position+4(%esi)
    662 	fxch	%st(2)					// 2 | 0 | 1
    663 	fadds	mv_position+8(%esi)
    664 	fxch	%st(1)					// 0 | 2 | 1
    665 	fstps	mv_position+0(%esp)		// 2 | 1
    666 	fstps	mv_position+8(%esp)		// 1
    667 	fstps	mv_position+4(%esp)
    668 
    669 // replace pv0 with the clip point
    670 	movl	%esp,%esi
    671 
    672 //				if (clip->leftedge)
    673 //				{
    674 	jz		Ltestright2
    675 
    676 //					r_leftclipped = true;
    677 //					r_leftenter = clipvert;
    678 	movl	$1,C(r_leftclipped)
    679 	movl	mv_position+0(%esp),%eax
    680 	movl	%eax,C(r_leftenter)+mv_position+0
    681 	movl	mv_position+4(%esp),%eax
    682 	movl	%eax,C(r_leftenter)+mv_position+4
    683 	movl	mv_position+8(%esp),%eax
    684 	movl	%eax,C(r_leftenter)+mv_position+8
    685 
    686 	jmp		Lcontinue
    687 
    688 //				}
    689 
    690 Ltestright2:
    691 //				else if (clip->rightedge)
    692 //				{
    693 	testb	%ah,%ah
    694 	jz		Lcontinue
    695 
    696 //					r_rightclipped = true;
    697 //					r_rightenter = clipvert;
    698 	movl	$1,C(r_rightclipped)
    699 	movl	mv_position+0(%esp),%eax
    700 	movl	%eax,C(r_rightenter)+mv_position+0
    701 	movl	mv_position+4(%esp),%eax
    702 	movl	%eax,C(r_rightenter)+mv_position+4
    703 	movl	mv_position+8(%esp),%eax
    704 	movl	%eax,C(r_rightenter)+mv_position+8
    705 
    706 //				}
    707 	jmp		Lcontinue
    708 
    709 // %esi = vec3_t point to transform and project
    710 // %edx preserved
    711 LTransformAndProject:
    712 
    713 //	// transform and project
    714 //		VectorSubtract (world, modelorg, local);
    715 	flds	mv_position+0(%esi)
    716 	fsubs	C(modelorg)+0
    717 	flds	mv_position+4(%esi)
    718 	fsubs	C(modelorg)+4
    719 	flds	mv_position+8(%esi)
    720 	fsubs	C(modelorg)+8
    721 	fxch	%st(2)				// local[0] | local[1] | local[2]
    722 
    723 //		TransformVector (local, transformed);
    724 //
    725 //		if (transformed[2] < NEAR_CLIP)
    726 //			transformed[2] = NEAR_CLIP;
    727 //
    728 //		lzi0 = 1.0 / transformed[2];
    729 	fld		%st(0)				// local[0] | local[0] | local[1] | local[2]
    730 	fmuls	C(vpn)+0			// zm0 | local[0] | local[1] | local[2]
    731 	fld		%st(1)				// local[0] | zm0 | local[0] | local[1] |
    732 								//  local[2]
    733 	fmuls	C(vright)+0			// xm0 | zm0 | local[0] | local[1] | local[2]
    734 	fxch	%st(2)				// local[0] | zm0 | xm0 | local[1] | local[2]
    735 	fmuls	C(vup)+0			// ym0 |  zm0 | xm0 | local[1] | local[2]
    736 	fld		%st(3)				// local[1] | ym0 |  zm0 | xm0 | local[1] |
    737 								//  local[2]
    738 	fmuls	C(vpn)+4			// zm1 | ym0 | zm0 | xm0 | local[1] |
    739 								//  local[2]
    740 	fld		%st(4)				// local[1] | zm1 | ym0 | zm0 | xm0 |
    741 								//  local[1] | local[2]
    742 	fmuls	C(vright)+4			// xm1 | zm1 | ym0 |  zm0 | xm0 |
    743 								//  local[1] | local[2]
    744 	fxch	%st(5)				// local[1] | zm1 | ym0 | zm0 | xm0 |
    745 								//  xm1 | local[2]
    746 	fmuls	C(vup)+4			// ym1 | zm1 | ym0 | zm0 | xm0 |
    747 								//  xm1 | local[2]
    748 	fxch	%st(1)				// zm1 | ym1 | ym0 | zm0 | xm0 |
    749 								//  xm1 | local[2]
    750 	faddp	%st(0),%st(3)		// ym1 | ym0 | zm2 | xm0 | xm1 | local[2]
    751 	fxch	%st(3)				// xm0 | ym0 | zm2 | ym1 | xm1 | local[2]
    752 	faddp	%st(0),%st(4)		// ym0 | zm2 | ym1 | xm2 | local[2]
    753 	faddp	%st(0),%st(2)		// zm2 | ym2 | xm2 | local[2]
    754 	fld		%st(3)				// local[2] | zm2 | ym2 | xm2 | local[2]
    755 	fmuls	C(vpn)+8			// zm3 | zm2 | ym2 | xm2 | local[2]
    756 	fld		%st(4)				// local[2] | zm3 | zm2 | ym2 | xm2 | local[2]
    757 	fmuls	C(vright)+8			// xm3 | zm3 | zm2 | ym2 | xm2 | local[2]
    758 	fxch	%st(5)				// local[2] | zm3 | zm2 | ym2 | xm2 | xm3
    759 	fmuls	C(vup)+8			// ym3 | zm3 | zm2 | ym2 | xm2 | xm3
    760 	fxch	%st(1)				// zm3 | ym3 | zm2 | ym2 | xm2 | xm3
    761 	faddp	%st(0),%st(2)		// ym3 | zm4 | ym2 | xm2 | xm3
    762 	fxch	%st(4)				// xm3 | zm4 | ym2 | xm2 | ym3
    763 	faddp	%st(0),%st(3)		// zm4 | ym2 | xm4 | ym3
    764 	fxch	%st(1)				// ym2 | zm4 | xm4 | ym3
    765 	faddp	%st(0),%st(3)		// zm4 | xm4 | ym4
    766 
    767 	fcoms	Lfp_near_clip
    768 	fnstsw	%ax
    769 	testb	$1,%ah
    770 	jz		LNoClip
    771 	fstp	%st(0)
    772 	flds	Lfp_near_clip
    773 
    774 LNoClip:
    775 
    776 	fdivrs	float_1				// lzi0 | x | y
    777 	fxch	%st(1)				// x | lzi0 | y
    778 
    779 //	// FIXME: build x/yscale into transform?
    780 //		scale = xscale * lzi0;
    781 //		u0 = (xcenter + scale*transformed[0]);
    782 	flds	C(xscale)			// xscale | x | lzi0 | y
    783 	fmul	%st(2),%st(0)		// scale | x | lzi0 | y
    784 	fmulp	%st(0),%st(1)		// scale*x | lzi0 | y
    785 	fadds	C(xcenter)			// u0 | lzi0 | y
    786 
    787 //		if (u0 < r_refdef.fvrectx_adj)
    788 //			u0 = r_refdef.fvrectx_adj;
    789 //		if (u0 > r_refdef.fvrectright_adj)
    790 //			u0 = r_refdef.fvrectright_adj;
    791 // FIXME: use integer compares of floats?
    792 	fcoms	C(r_refdef)+rd_fvrectx_adj
    793 	fnstsw	%ax
    794 	testb	$1,%ah
    795 	jz		LClampP0
    796 	fstp	%st(0)
    797 	flds	C(r_refdef)+rd_fvrectx_adj
    798 LClampP0:
    799 	fcoms	C(r_refdef)+rd_fvrectright_adj
    800 	fnstsw	%ax
    801 	testb	$0x45,%ah
    802 	jnz		LClampP1
    803 	fstp	%st(0)
    804 	flds	C(r_refdef)+rd_fvrectright_adj
    805 LClampP1:
    806 
    807 	fld		%st(1)				// lzi0 | u0 | lzi0 | y
    808 
    809 //		scale = yscale * lzi0;
    810 //		v0 = (ycenter - scale*transformed[1]);
    811 	fmuls	C(yscale)			// scale | u0 | lzi0 | y
    812 	fmulp	%st(0),%st(3)		// u0 | lzi0 | scale*y
    813 	fxch	%st(2)				// scale*y | lzi0 | u0
    814 	fsubrs	C(ycenter)			// v0 | lzi0 | u0
    815 
    816 //		if (v0 < r_refdef.fvrecty_adj)
    817 //			v0 = r_refdef.fvrecty_adj;
    818 //		if (v0 > r_refdef.fvrectbottom_adj)
    819 //			v0 = r_refdef.fvrectbottom_adj;
    820 // FIXME: use integer compares of floats?
    821 	fcoms	C(r_refdef)+rd_fvrecty_adj
    822 	fnstsw	%ax
    823 	testb	$1,%ah
    824 	jz		LClampP2
    825 	fstp	%st(0)
    826 	flds	C(r_refdef)+rd_fvrecty_adj
    827 LClampP2:
    828 	fcoms	C(r_refdef)+rd_fvrectbottom_adj
    829 	fnstsw	%ax
    830 	testb	$0x45,%ah
    831 	jnz		LClampP3
    832 	fstp	%st(0)
    833 	flds	C(r_refdef)+rd_fvrectbottom_adj
    834 LClampP3:
    835 	ret
    836 
    837 #endif	// id386
    838 
    839