/*
	r_aliasa.S

	x86 assembly-language Alias model transform and project code.

	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$
*/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#include "d_ifacea.h"

#ifdef PIC
#undef USE_INTEL_ASM //XXX asm pic hack
#endif

#ifdef USE_INTEL_ASM

	.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, *plightnormal, zi;
//	trivertx_t	*pverts;

//	pverts = r_apverts;
	movl	C(r_apverts),%esi

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

Lloop:

//	// transform and project
//		zi = 1.0 / (DotProduct(pverts->v, aliastransform[2]) +
//				aliastransform[2][3]);
	movb	(%esi),%dl
	movb	%dl,Lcoords
	fildl	Lcoords				// v[0]
	movb	1(%esi),%dl
	movb	%dl,Lcoords+4
	fildl	Lcoords+4			// v[1] | v[0]
	movb	2(%esi),%dl	
	movb	%dl,Lcoords+8
	fildl	Lcoords+8			// 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]
	movb	tv_lightnormalindex(%esi),%dl
	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)

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

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

//		fv->v[2] = pstverts->s;
//		fv->v[3] = pstverts->t;
//		fv->flags = pstverts->onseam;
	movl	stv_onseam(%ebp),%eax
	movl	%eax,fv_flags(%edi)

	movl	fv_size(%edi),%eax
	movl	stv_size(%ebp),%eax
	movl	4(%esi),%eax

	leal	(%edx,%edx,2),%eax	// index*3

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

//		lightcos = DotProduct (plightnormal, r_plightvec);
	flds	C(r_avertexnormals)(,%eax,4)
	fmuls	C(r_plightvec)
	flds	C(r_avertexnormals)+4(,%eax,4)
	fmuls	C(r_plightvec)+4
	flds	C(r_avertexnormals)+8(,%eax,4)
	fmuls	C(r_plightvec)+8
	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
	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	// USE_INTEL_ASM

