/*
	r_aliasa.S

	(description)

	Copyright (C) 1996-1997  Id Software, Inc.

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

	See the GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to:

		Free Software Foundation, Inc.
		59 Temple Place - Suite 330
		Boston, MA  02111-1307, USA

	$Id: r_aliasa.s,v 1.1.1.1 2005/11/24 15:52:52 bigfoot Exp $
*/

/*

// x86 assembly-language Alias model transform and project code.

#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#include "d_ifacea.h"

#ifdef id386

	.data

Lfloat_1:	.single	1.0
Ltemp:		.long	0
Lcoords:	.long	0, 0, 0

	.text

#define fv			12+4
#define pstverts	12+8

.globl C(R_AliasTransformAndProjectFinalVerts)
C(R_AliasTransformAndProjectFinalVerts):
	pushl	%ebp				// preserve caller's stack frame
	pushl	%edi
	pushl	%esi				// preserve register variables

//	int i, temp;
//	float lightcos, zi;
//	trivertx_t *pverts1, *pverts2;
//	vec3_t interpolated_verts, interpolated_norm;

//	pverts1 = r_oldapverts;
//	pverts2 = r_apverts;
	movl	C(r_oldapverts),%esi				//pverts1 = esi
	movl	C(r_apverts),%ebx					//pverts2 = ebx

//	for (i = 0; i < r_anumverts; i++, fv++, pverts1++, pverts2++, pstverts++) {
	movl	pstverts(%esp),%ebp				//pstverts = ebp
	movl	fv(%esp),%edi					//fv = edi
	movl	C(r_anumverts),%ecx				//r_anumverts = ecx
	subl	%edx,%edx						//%edx = 0

Lloop:

// transform and project
//		zi = 1.0 / (DotProduct(pverts->v, aliastransform[2]) + aliastransform[2][3]);
//		fv->v[2] = pstverts->s;
//		fv->v[3] = pstverts->t;

	movb	(%esi),%dl
	movb	%dl,Lcoords
	fildl	Lcoords
	movb	(%ebx),%dl
	movb	%dl,Lcoords
	fildl	Lcoords
	fsub	%st(1),%st(0)
	fmuls	C(r_framelerp)
	faddp	%st(0),%st(1)		// v[0]

	movb	1(%esi),%dl
	movb	%dl,Lcoords+4
	fildl	Lcoords+4
	movb	1(%ebx),%dl
	movb	%dl,Lcoords+4
	fildl	Lcoords+4
	fsub	%st(1),%st(0)
	fmuls	C(r_framelerp)
	faddp	%st(0),%st(1)		// v[1] | v[0]

	movb	2(%esi),%dl
	movb	%dl,Lcoords+8
	fildl	Lcoords+8
	movb	2(%ebx),%dl
	movb	%dl,Lcoords+8
	fildl	Lcoords+8
	fsub	%st(1),%st(0)
	fmuls	C(r_framelerp)
	faddp	%st(0),%st(1)		// v[2] | v[1] | v[0]

	fld		%st(2)				// v[0] | v[2] | v[1] | v[0]
	fmuls	C(aliastransform)+32 // accum | v[2] | v[1] | v[0]
	fld		%st(2)				// v[1] | accum | v[2] | v[1] | v[0]
	fmuls	C(aliastransform)+36 // accum2 | accum | v[2] | v[1] | v[0]
	fxch	%st(1)				// accum | accum2 | v[2] | v[1] | v[0]
	fadds	C(aliastransform)+44 // accum | accum2 | v[2] | v[1] | v[0]
	fld		%st(2)				// v[2] | accum | accum2 | v[2] | v[1] | v[0]
	fmuls	C(aliastransform)+40 // accum3 | accum | accum2 | v[2] | v[1] | v[0]
	fxch	%st(1)				// accum | accum3 | accum2 | v[2] | v[1] | v[0]
	faddp	%st(0),%st(2)		// accum3 | accum | v[2] | v[1] | v[0]
	movl	stv_s(%ebp),%eax
	movl	%eax,fv_v+8(%edi)
	faddp	%st(0),%st(1)		// z | v[2] | v[1] | v[0]

	movl	stv_t(%ebp),%eax
	movl	%eax,fv_v+12(%edi)

	fdivrs	Lfloat_1			// zi | v[2] | v[1] | v[0]

//		fv->flags = pstverts->onseam;
	movl	stv_onseam(%ebp),%eax
	movl	%eax,fv_flags(%edi)

//	// lighting
//		plightnormal = r_avertexnormals[pverts->lightnormalindex];

	fxch	%st(3)				// v[0] | v[2] | v[1] | zi

//		lightcos = DotProduct (plightnormal, r_plightvec);

	pushl	%ebp
	pushl	%ecx

	//%edx is already zero'd
	movb	tv_lightnormalindex(%esi),%dl
	leal	(%edx,%edx,2),%eax	// index*3

	subl	%ecx,%ecx
	movb	tv_lightnormalindex(%ebx),%cl
	leal	(%ecx,%ecx,2),%ebp	// index*3

	flds	C(r_avertexnormals)(,%eax,4)
	flds	C(r_avertexnormals)(,%ebp,4)
	fsub	%st(1),%st(0)
	fmuls	C(r_framelerp)
	faddp	%st(0),%st(1)
	fmuls	C(r_plightvec)						//v[0]

	flds	C(r_avertexnormals)+4(,%eax,4)
	flds	C(r_avertexnormals)+4(,%ebp,4)
	fsub	%st(1),%st(0)
	fmuls	C(r_framelerp)
	faddp	%st(0),%st(1)
	fmuls	C(r_plightvec)+4					//v[1] | v[0]

	flds	C(r_avertexnormals)+8(,%eax,4)
	flds	C(r_avertexnormals)+8(,%ebp,4)
	fsub	%st(1),%st(0)
	fmuls	C(r_framelerp)
	faddp	%st(0),%st(1)
	fmuls	C(r_plightvec)+8					//v[2] | v[1] | v[0]
	
	popl	%ecx								//restore ebp and ecx
	popl	%ebp

	fxch	%st(1)
	faddp	%st(0),%st(2)
	fld		%st(2)				 // v[0] | laccum | laccum2 | v[0] | v[2] | v[1] | zi
	fmuls	C(aliastransform)+0  // xaccum | laccum | laccum2 | v[0] | v[2] | v[1] | zi
	fxch	%st(2)				 // laccum2 | laccum | xaccum | v[0] | v[2] | v[1] | zi
	faddp	%st(0),%st(1)		 // laccum | xaccum | v[0] | v[2] | v[1] | zi

//		temp = r_ambientlight;
//		if (lightcos < 0) {
	fsts	Ltemp
	movl	C(r_ambientlight),%eax
	movb	Ltemp+3,%dl
	testb	$0x80,%dl
	jz		Lsavelight	// no need to clamp if only ambient lit, because r_ambientlight is preclamped

//			temp += (int)(r_shadelight * lightcos);
	fmuls	C(r_shadelight)
// FIXME: fast float->int conversion?
	fistpl	Ltemp
	addl	Ltemp,%eax

//		// clamp; because we limited the minimum ambient and shading light, we
//		// don't have to clamp low light, just bright
//			if (temp < 0)
//				temp = 0;
	jns		Lp1
	subl	%eax,%eax

//		}

Lp1:

//		fv->v[4] = temp;
//
//	// x, y, and z are scaled down by 1/2**31 in the transform, so 1/z is
//	// scaled up by 1/2**31, and the scaling cancels out for x and y in the
//	// projection
//		fv->v[0] = ((DotProduct(pverts->v, aliastransform[0]) +
//				aliastransform[0][3]) * zi) + aliasxcenter;
//		fv->v[1] = ((DotProduct(pverts->v, aliastransform[1]) +
//				aliastransform[1][3]) * zi) + aliasycenter;
//		fv->v[5] = zi;
	fxch	%st(1)				 // v[0] | xaccum | v[2] | v[1] | zi
	fmuls	C(aliastransform)+16 // yaccum | xaccum | v[2] | v[1] | zi
	fxch	%st(3)				 // v[1] | xaccum | v[2] | yaccum | zi
	fld		%st(0)				 // v[1] | v[1] | xaccum | v[2] | yaccum | zi
	fmuls	C(aliastransform)+4	 // xaccum2 | v[1] | xaccum | v[2] | yaccum |zi
	fxch	%st(1)				 // v[1] | xaccum2 | xaccum | v[2] | yaccum |zi
	movl	%eax,fv_v+16(%edi)
	fmuls	C(aliastransform)+20 // yaccum2 | xaccum2 | xaccum | v[2] | yaccum|
								 //  zi
	fxch	%st(2)				 // xaccum | xaccum2 | yaccum2 | v[2] | yaccum|
								 //  zi
	fadds	C(aliastransform)+12 // xaccum | xaccum2 | yaccum2 | v[2] | yaccum|
								 //  zi
	fxch	%st(4)				 // yaccum | xaccum2 | yaccum2 | v[2] | xaccum|
								 //  zi
	fadds	C(aliastransform)+28 // yaccum | xaccum2 | yaccum2 | v[2] | xaccum|
								 //  zi
	fxch	%st(3)				 // v[2] | xaccum2 | yaccum2 | yaccum | xaccum|
								 //  zi
	fld		%st(0)				 // v[2] | v[2] | xaccum2 | yaccum2 | yaccum |
								 //  xaccum | zi
	fmuls	C(aliastransform)+8	 // xaccum3 | v[2] | xaccum2 | yaccum2 |yaccum|
								 //  xaccum | zi
	fxch	%st(1)				 // v[2] | xaccum3 | xaccum2 | yaccum2 |yaccum|
								 //  xaccum | zi
	fmuls	C(aliastransform)+24 // yaccum3 | xaccum3 | xaccum2 | yaccum2 |
								 // yaccum | xaccum | zi
	fxch	%st(5)				 // xaccum | xaccum3 | xaccum2 | yaccum2 |
								 // yaccum | yaccum3 | zi
	faddp	%st(0),%st(2)		 // xaccum3 | xaccum | yaccum2 | yaccum |
								 //  yaccum3 | zi
	fxch	%st(3)				 // yaccum | xaccum | yaccum2 | xaccum3 |
								 //  yaccum3 | zi
	faddp	%st(0),%st(2)		 // xaccum | yaccum | xaccum3 | yaccum3 | zi
	addl	$(tv_size),%esi		 //increment pverts1
	addl	$(tv_size),%ebx		 //increment pverts2
	faddp	%st(0),%st(2)		 // yaccum | x | yaccum3 | zi
	faddp	%st(0),%st(2)		 // x | y | zi
	addl	$(stv_size),%ebp
	fmul	%st(2),%st(0)		 // x/z | y | zi
	fxch	%st(1)				 // y | x/z | zi
	fmul	%st(2),%st(0)		 // y/z | x/z | zi
	fxch	%st(1)				 // x/z | y/z | zi
	fadds	C(aliasxcenter)		 // u | y/z | zi
	fxch	%st(1)				 // y/z | u | zi
	fadds	C(aliasycenter)		 // v | u | zi
	fxch	%st(2)				 // zi | u | v
// FIXME: fast float->int conversion?
	fistpl	fv_v+20(%edi)		 // u | v
	fistpl	fv_v+0(%edi)		 // v
	fistpl	fv_v+4(%edi)

//	}

	addl	$(fv_size),%edi
	decl	%ecx
	jnz		Lloop

	popl	%esi				// restore register variables
	popl	%edi
	popl	%ebp				// restore the caller's stack frame
	ret

Lsavelight:
	fstp	%st(0)
	jmp		Lp1


#endif	// id386


*/
