⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 r_drawa.s

📁 Quake 2 Source code for students by Theerthan You can also download from idsoftwares.com
💻 S
📖 第 1 页 / 共 2 页
字号:
//
// r_drawa.s
// x86 assembly-language edge clipping and emission code
//

#include "qasm.h"
#include "d_ifacea.h"

#if	id386

// !!! if these are changed, they must be changed in r_draw.c too !!!
#define FULLY_CLIPPED_CACHED	0x80000000
#define FRAMECOUNT_MASK			0x7FFFFFFF

	.data

Ld0:			.single		0.0
Ld1:			.single		0.0
Lstack:			.long		0
Lfp_near_clip:	.single		NEAR_CLIP
Lceilv0:		.long		0
Lv:				.long		0
Lu0:			.long		0
Lv0:			.long		0
Lzi0:			.long		0

	.text

//----------------------------------------------------------------------
// edge clipping code
//----------------------------------------------------------------------

#define pv0		4+12
#define pv1		8+12
#define clip	12+12

	.align 4
.globl C(R_ClipEdge)
C(R_ClipEdge):
	pushl	%esi				// preserve register variables
	pushl	%edi
	pushl	%ebx
	movl	%esp,Lstack			// for clearing the stack later

//	float		d0, d1, f;
//	mvertex_t	clipvert;

	movl	clip(%esp),%ebx
	movl	pv0(%esp),%esi
	movl	pv1(%esp),%edx

//	if (clip)
//	{
	testl	%ebx,%ebx
	jz		Lemit

//		do
//		{

Lcliploop:

//			d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
//			d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
	flds	mv_position+0(%esi)
	fmuls	cp_normal+0(%ebx)
	flds	mv_position+4(%esi)
	fmuls	cp_normal+4(%ebx)
	flds	mv_position+8(%esi)
	fmuls	cp_normal+8(%ebx)
	fxch	%st(1)
	faddp	%st(0),%st(2)		// d0mul2 | d0add0

	flds	mv_position+0(%edx)
	fmuls	cp_normal+0(%ebx)
	flds	mv_position+4(%edx)
	fmuls	cp_normal+4(%ebx)
	flds	mv_position+8(%edx)
	fmuls	cp_normal+8(%ebx)
	fxch	%st(1)
	faddp	%st(0),%st(2)		// d1mul2 | d1add0 | d0mul2 | d0add0
	fxch	%st(3)				// d0add0 | d1add0 | d0mul2 | d1mul2

	faddp	%st(0),%st(2)		// d1add0 | dot0 | d1mul2 
	faddp	%st(0),%st(2)		// dot0 | dot1

	fsubs	cp_dist(%ebx)		// d0 | dot1
	fxch	%st(1)				// dot1 | d0
	fsubs	cp_dist(%ebx)		// d1 | d0
	fxch	%st(1)
	fstps	Ld0
	fstps	Ld1

//			if (d0 >= 0)
//			{
	movl	Ld0,%eax
	movl	Ld1,%ecx
	orl		%eax,%ecx
	js		Lp2

// both points are unclipped

Lcontinue:

//
//				R_ClipEdge (&clipvert, pv1, clip->next);
//				return;
//			}
//		} while ((clip = clip->next) != NULL);
	movl	cp_next(%ebx),%ebx
	testl	%ebx,%ebx
	jnz		Lcliploop

//	}

//// add the edge
//	R_EmitEdge (pv0, pv1);
Lemit:

//
// set integer rounding to ceil mode, set to single precision
//
// FIXME: do away with by manually extracting integers from floats?
// FIXME: set less often
	fldcw	ceil_cw

//	edge_t	*edge, *pcheck;
//	int		u_check;
//	float	u, u_step;
//	vec3_t	local, transformed;
//	float	*world;
//	int		v, v2, ceilv0;
//	float	scale, lzi0, u0, v0;
//	int		side;

//	if (r_lastvertvalid)
//	{
	cmpl	$0,C(r_lastvertvalid)
	jz		LCalcFirst

//		u0 = r_u1;
//		v0 = r_v1;
//		lzi0 = r_lzi1;
//		ceilv0 = r_ceilv1;
	movl	C(r_lzi1),%eax
	movl	C(r_u1),%ecx
	movl	%eax,Lzi0
	movl	%ecx,Lu0
	movl	C(r_v1),%ecx
	movl	C(r_ceilv1),%eax
	movl	%ecx,Lv0
	movl	%eax,Lceilv0
	jmp		LCalcSecond

//	}

LCalcFirst:

//	else
//	{
//		world = &pv0->position[0];

	call	LTransformAndProject	// v0 | lzi0 | u0

	fsts	Lv0
	fxch	%st(2)					// u0 | lzi0 | v0
	fstps	Lu0						// lzi0 | v0
	fstps	Lzi0					// v0

//		ceilv0 = (int)(v0 - 2000) + 2000; // ceil(v0);
	fistpl	Lceilv0

//	}

LCalcSecond:

//	world = &pv1->position[0];
	movl	%edx,%esi

	call	LTransformAndProject	// v1 | lzi1 | u1

	flds	Lu0						// u0 | v1 | lzi1 | u1
	fxch	%st(3)					// u1 | v1 | lzi1 | u0
	flds	Lzi0					// lzi0 | u1 | v1 | lzi1 | u0
	fxch	%st(3)					// lzi1 | u1 | v1 | lzi0 | u0
	flds	Lv0						// v0 | lzi1 | u1 | v1 | lzi0 | u0
	fxch	%st(3)					// v1 | lzi1 | u1 | v0 | lzi0 | u0

//	r_ceilv1 = (int)(r_v1 - 2000) + 2000; // ceil(r_v1);
	fistl	C(r_ceilv1)

	fldcw	single_cw				// put back normal floating-point state

	fsts	C(r_v1)
	fxch	%st(4)					// lzi0 | lzi1 | u1 | v0 | v1 | u0

//	if (r_lzi1 > lzi0)
//		lzi0 = r_lzi1;
	fcom	%st(1)
	fnstsw	%ax
	testb	$1,%ah
	jz		LP0
	fstp	%st(0)
	fld		%st(0)
LP0:

	fxch	%st(1)					// lzi1 | lzi0 | u1 | v0 | v1 | u0
	fstps	C(r_lzi1)				// lzi0 | u1 | v0 | v1 | u0
	fxch	%st(1)
	fsts	C(r_u1)
	fxch	%st(1)

//	if (lzi0 > r_nearzi)	// for mipmap finding
//		r_nearzi = lzi0;
	fcoms	C(r_nearzi)
	fnstsw	%ax
	testb	$0x45,%ah
	jnz		LP1
	fsts	C(r_nearzi)
LP1:

// // for right edges, all we want is the effect on 1/z
//	if (r_nearzionly)
//		return;
	movl	C(r_nearzionly),%eax
	testl	%eax,%eax
	jz		LP2
LPop5AndDone:
	movl	C(cacheoffset),%eax
	movl	C(r_framecount),%edx
	cmpl	$0x7FFFFFFF,%eax
	jz		LDoPop
	andl	$(FRAMECOUNT_MASK),%edx
	orl		$(FULLY_CLIPPED_CACHED),%edx
	movl	%edx,C(cacheoffset)

LDoPop:
	fstp	%st(0)			// u1 | v0 | v1 | u0
	fstp	%st(0)			// v0 | v1 | u0
	fstp	%st(0)			// v1 | u0
	fstp	%st(0)			// u0
	fstp	%st(0)
	jmp		Ldone

LP2:

// // create the edge
//	if (ceilv0 == r_ceilv1)
//		return;		// horizontal edge
	movl	Lceilv0,%ebx
	movl	C(edge_p),%edi
	movl	C(r_ceilv1),%ecx
	movl	%edi,%edx
	movl	C(r_pedge),%esi
	addl	$(et_size),%edx
	cmpl	%ecx,%ebx
	jz		LPop5AndDone

	movl	C(r_pedge),%eax
	movl	%eax,et_owner(%edi)

//	side = ceilv0 > r_ceilv1;
//
//	edge->nearzi = lzi0;
	fstps	et_nearzi(%edi)		// u1 | v0 | v1 | u0

//	if (side == 1)
//	{
	jc		LSide0

LSide1:

//	// leading edge (go from p2 to p1)

//		u_step = ((u0 - r_u1) / (v0 - r_v1));
	fsubrp	%st(0),%st(3)		// v0 | v1 | u0-u1
	fsub	%st(1),%st(0)		// v0-v1 | v1 | u0-u1
	fdivrp	%st(0),%st(2)		// v1 | ustep

//	r_emitted = 1;
	movl	$1,C(r_emitted)

//	edge = edge_p++;
	movl	%edx,C(edge_p)

// pretouch next edge
	movl	(%edx),%eax

//		v2 = ceilv0 - 1;
//		v = r_ceilv1;
	movl	%ecx,%eax
	leal	-1(%ebx),%ecx
	movl	%eax,%ebx

//		edge->surfs[0] = 0;
//		edge->surfs[1] = surface_p - surfaces;
	movl	C(surface_p),%eax
	movl	C(surfaces),%esi
	subl	%edx,%edx
	subl	%esi,%eax
	shrl	$(SURF_T_SHIFT),%eax
	movl	%edx,et_surfs(%edi)
	movl	%eax,et_surfs+2(%edi)

	subl	%esi,%esi

//		u = r_u1 + ((float)v - r_v1) * u_step;
	movl	%ebx,Lv
	fildl	Lv					// v | v1 | ustep
	fsubp	%st(0),%st(1)		// v-v1 | ustep
	fmul	%st(1),%st(0)		// (v-v1)*ustep | ustep
	fadds	C(r_u1)				// u | ustep

	jmp		LSideDone

//	}

LSide0:

//	else
//	{
//	// trailing edge (go from p1 to p2)

//		u_step = ((r_u1 - u0) / (r_v1 - v0));
	fsub	%st(3),%st(0)		// u1-u0 | v0 | v1 | u0
	fxch	%st(2)				// v1 | v0 | u1-u0 | u0
	fsub	%st(1),%st(0)		// v1-v0 | v0 | u1-u0 | u0
	fdivrp	%st(0),%st(2)		// v0 | ustep | u0

//	r_emitted = 1;
	movl	$1,C(r_emitted)

//	edge = edge_p++;
	movl	%edx,C(edge_p)

// pretouch next edge
	movl	(%edx),%eax

//		v = ceilv0;
//		v2 = r_ceilv1 - 1;
	decl	%ecx

//		edge->surfs[0] = surface_p - surfaces;
//		edge->surfs[1] = 0;
	movl	C(surface_p),%eax
	movl	C(surfaces),%esi
	subl	%edx,%edx
	subl	%esi,%eax
	shrl	$(SURF_T_SHIFT),%eax
	movl	%edx,et_surfs+2(%edi)
	movl	%eax,et_surfs(%edi)

	movl	$1,%esi

//		u = u0 + ((float)v - v0) * u_step;
	movl	%ebx,Lv
	fildl	Lv					// v | v0 | ustep | u0
	fsubp	%st(0),%st(1)		// v-v0 | ustep | u0
	fmul	%st(1),%st(0)		// (v-v0)*ustep | ustep | u0
	faddp	%st(0),%st(2)		// ustep | u
	fxch	%st(1)				// u | ustep

//	}

LSideDone:

//	edge->u_step = u_step*0x100000;
//	edge->u = u*0x100000 + 0xFFFFF;

	fmuls	fp_1m				// u*0x100000 | ustep
	fxch	%st(1)				// ustep | u*0x100000
	fmuls	fp_1m				// ustep*0x100000 | u*0x100000
	fxch	%st(1)				// u*0x100000 | ustep*0x100000
	fadds	fp_1m_minus_1		// u*0x100000 + 0xFFFFF | ustep*0x100000
	fxch	%st(1)				// ustep*0x100000 | u*0x100000 + 0xFFFFF
	fistpl	et_u_step(%edi)		// u*0x100000 + 0xFFFFF
	fistpl	et_u(%edi)

// // we need to do this to avoid stepping off the edges if a very nearly
// // horizontal edge is less than epsilon above a scan, and numeric error
// // causes it to incorrectly extend to the scan, and the extension of the
// // line goes off the edge of the screen
// // FIXME: is this actually needed?
//	if (edge->u < r_refdef.vrect_x_adj_shift20)
//		edge->u = r_refdef.vrect_x_adj_shift20;
//	if (edge->u > r_refdef.vrectright_adj_shift20)
//		edge->u = r_refdef.vrectright_adj_shift20;
	movl	et_u(%edi),%eax
	movl	C(r_refdef)+rd_vrect_x_adj_shift20,%edx
	cmpl	%edx,%eax
	jl		LP4
	movl	C(r_refdef)+rd_vrectright_adj_shift20,%edx
	cmpl	%edx,%eax
	jng		LP5
LP4:
	movl	%edx,et_u(%edi)
	movl	%edx,%eax
LP5:

// // sort the edge in normally
//	u_check = edge->u;
//
//	if (edge->surfs[0])
//		u_check++;	// sort trailers after leaders
	addl	%esi,%eax

//	if (!newedges[v] || newedges[v]->u >= u_check)
//	{
	movl	C(newedges)(,%ebx,4),%esi
	testl	%esi,%esi

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -