;/*
;* Glide64 - Glide video plugin for Nintendo 64 emulators.
;*
;* 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
;* 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 the Free Software
;* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
;
;****************************************************************
;
; Glide64 - Glide Plugin for Nintendo 64 emulators
; Project started on December 29th, 2001
;
; Authors:
; Dave2001, original author, founded the project in 2001, left it in 2002
; Gugaman, joined the project in 2002, left it in 2002
; Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 2002
; Hiroshi 'KoolSmoky' Morii, joined the project in 2007
;
;****************************************************************
;
; To modify Glide64:
; * Write your name and (optional)email, commented by your work, so I know who did it, and so that you can find which parts you modified when it comes time to send it to me.
; * Do NOT send me the whole project or file that you modified.  Take out your modified code sections, and tell me where to put them.  If people sent the whole thing, I would have many different versions, but no idea how to combine them all.
;
;****************************************************************

%include "inc/c32.mac"

segment .text
*/

extern "C" void __declspec(naked) DetectSIMD(int func, int * iedx, int * iecx)
{
	_asm {
		push ebp
		mov ebp,esp
		mov       eax,[func]
		cpuid
		mov       eax,[iedx]
		mov       [eax],edx
		mov       eax,[iecx]
		mov       [eax],ecx
		leave
		ret
	}
}

/****************************************************************
;
;                     ******** SSE ********
;
;****************************************************************/

extern "C" void __declspec(naked) TransformVectorSSE(float *src, float *dst, float mat[4][4])
{
	__asm
	{
		push ebp
		mov ebp,esp

		mov       ecx,[src]
		mov       eax,[dst]
		mov       edx,[mat]
		           
		movss     xmm0,[ecx]    ; 0 0 0 src[0]
		movss     xmm5,[edx]    ; 0 0 0 mat[0][0]
		movhps    xmm5,[edx+4]  ; mat[0][2] mat[0][1] 0 mat[0][0]
		shufps    xmm0,xmm0, 0  ; src[0] src[0] src[0] src[0]
		movss     xmm1,[ecx+4]  ; 0 0 0 src[1]
		movss     xmm3,[edx+16] ; 0 0 0 mat[1][0]
		movhps    xmm3,[edx+20] ; mat[1][2] mat[1][1] 0 mat[1][0]
		shufps    xmm1,xmm1, 0  ; src[1] src[1] src[1] src[1]
		mulps     xmm0,xmm5     ; mat[0][2]*src[0] mat[0][1]*src[0] 0 mat[0][0]*src[0]
		mulps     xmm1,xmm3     ; mat[1][2]*src[1] mat[1][1]*src[1] 0 mat[1][0]*src[1]
		movss     xmm2,[ecx+8]  ; 0 0 0 src[2]
		shufps    xmm2,xmm2, 0  ; src[2] src[2] src[2] src[2]
		movss     xmm4,[edx+32] ; 0 0 0 mat[2][0]
		movhps    xmm4,[edx+36] ; mat[2][2] mat[2][1] 0 mat[2][0]
		addps     xmm0,xmm1     ; mat[0][2]*src[0]+mat[1][2]*src[1] mat[0][1]*src[0]+mat[1][1]*src[1] 0 mat[0][0]*src[0]+mat[1][0]*src[1]
		mulps     xmm2,xmm4     ; mat[2][2]*src[2] mat[2][1]*src[2] 0 mat[2][0]*src[2]
		addps     xmm0,xmm2     ; mat[0][2]*src[0]+mat[1][2]*src[1]+mat[2][2]*src[2] mat[0][1]*src[0]+mat[1][1]*src[1]+mat[2][1]*src[2] 0 mat[0][0]*src[0]+mat[1][0]*src[1]+mat[2][0]*src[2]
		movss     [eax],xmm0    ; mat[0][0]*src[0]+mat[1][0]*src[1]+mat[2][0]*src[2]
		movhps    [eax+4],xmm0  ; mat[0][2]*src[0]+mat[1][2]*src[1]+mat[2][2]*src[2] mat[0][1]*src[0]+mat[1][1]*src[1]+mat[2][1]*src[2]
		leave
		ret
	}
}

extern "C" void __declspec(naked) MulMatricesSSE(float m1[4][4],float m2[4][4],float r[4][4])
{
	__asm
	{
		push ebp
		mov ebp,esp

      mov       eax,[r]      
      mov       ecx,[m1]
      mov       edx,[m2]
      
      movaps    xmm0,[edx]
      movaps    xmm1,[edx+16]
      movaps    xmm2,[edx+32]
      movaps    xmm3,[edx+48]
      
      ; r[0][0],r[0][1],r[0][2],r[0][3]
      
      movaps    xmm4,[ecx]
      movaps    xmm5,xmm4
      movaps    xmm6,xmm4
      movaps    xmm7,xmm4
      
      shufps    xmm4,xmm4,00000000b
      shufps    xmm5,xmm5,01010101b
      shufps    xmm6,xmm6,10101010b
      shufps    xmm7,xmm7,11111111b
      
      mulps     xmm4,xmm0
      mulps     xmm5,xmm1
      mulps     xmm6,xmm2
      mulps     xmm7,xmm3
      
      addps     xmm4,xmm5
      addps     xmm4,xmm6
      addps     xmm4,xmm7
      
      movaps    [eax],xmm4
      
      ; r[1][0],r[1][1],r[1][2],r[1][3]
      
      movaps    xmm4,[ecx+16]
      movaps    xmm5,xmm4
      movaps    xmm6,xmm4
      movaps    xmm7,xmm4
      
      shufps    xmm4,xmm4,00000000b
      shufps    xmm5,xmm5,01010101b
      shufps    xmm6,xmm6,10101010b
      shufps    xmm7,xmm7,11111111b
      
      mulps     xmm4,xmm0
      mulps     xmm5,xmm1
      mulps     xmm6,xmm2
      mulps     xmm7,xmm3
      
      addps     xmm4,xmm5
      addps     xmm4,xmm6
      addps     xmm4,xmm7
      
      movaps    [eax+16],xmm4
      
      
      ; r[2][0],r[2][1],r[2][2],r[2][3]
      
      movaps    xmm4,[ecx+32]
      movaps    xmm5,xmm4
      movaps    xmm6,xmm4
      movaps    xmm7,xmm4
      
      shufps    xmm4,xmm4,00000000b
      shufps    xmm5,xmm5,01010101b
      shufps    xmm6,xmm6,10101010b
      shufps    xmm7,xmm7,11111111b
      
      mulps     xmm4,xmm0
      mulps     xmm5,xmm1
      mulps     xmm6,xmm2
      mulps     xmm7,xmm3
      
      addps     xmm4,xmm5
      addps     xmm4,xmm6
      addps     xmm4,xmm7
      
      movaps    [eax+32],xmm4
      
      ; r[3][0],r[3][1],r[3][2],r[3][3]
      
      movaps    xmm4,[ecx+48]
      movaps    xmm5,xmm4
      movaps    xmm6,xmm4
      movaps    xmm7,xmm4
      
      shufps    xmm4,xmm4,00000000b
      shufps    xmm5,xmm5,01010101b
      shufps    xmm6,xmm6,10101010b
      shufps    xmm7,xmm7,11111111b
      
      mulps     xmm4,xmm0
      mulps     xmm5,xmm1
      mulps     xmm6,xmm2
      mulps     xmm7,xmm3
      
      addps     xmm4,xmm5
      addps     xmm4,xmm6
      addps     xmm4,xmm7
      
      movaps    [eax+48],xmm4
	  leave
	  ret
	}
}

extern "C" void __declspec(naked) NormalizeVectorSSE (float *v)
{
	_asm
	{
		push ebp
		mov ebp,esp

      mov edx, [v]
      movaps xmm0, [edx]      ; x y z 0
      movaps xmm2, xmm0       ; x y z 0
      mulps  xmm0, xmm0       ; x*x y*y z*z 0
      movaps xmm1, xmm0       ; x*x y*y z*z 0
      shufps xmm0, xmm1, 0x4e ; z*z 0 x*x y*y
      addps  xmm0, xmm1       ; x*x+z*z y*y z*z+x*x y*y
      movaps xmm1, xmm0       ; x*x+z*z y*y z*z+x*x y*y
      shufps xmm1, xmm1, 0x11 ; y*y z*z+x*x y*y z*z+x*x
      addps  xmm0, xmm1       ; x*x+z*z+y*y
      rsqrtps xmm0, xmm0      ; 1.0/sqrt(x*x+z*z+y*y)
      mulps  xmm2, xmm0       ; x/sqrt(x*x+z*z+y*y) y/sqrt(x*x+z*z+y*y) z/sqrt(x*x+z*z+y*y) 0
      movaps [edx], xmm2
	  leave
	  ret
	}
}

/*****************************************************************
;
;                     ******** SSE3 ********
;
;****************************************************************/

float __declspec(naked) DotProductSSE3(register float *v1, register float *v2)
{
	_asm {
		push ebp
		mov ebp,esp

      mov eax,[v1]
      mov edx,[v2]
      movaps xmm0, [eax]
      mulps xmm0, [edx]
      haddps xmm0, xmm0
      haddps xmm0, xmm0
;      movss eax, xmm0
		leave
		ret
	}
}

/****************************************************************
;
;                     ******** 3DNOW ********
;
;****************************************************************/

extern "C" void __declspec(naked) TransformVector3DNOW(float *src, float *dst, float mat[4][4])
{
	_asm {
		push ebp
		mov ebp,esp

    femms
      mov         ecx,[src]
      mov         eax,[dst]
      mov         edx,[mat]
      movq        mm0,[ecx]     ; src[1] src[0]
      movd        mm2,[ecx+8]   ; 0 src[2]
      movq        mm1,mm0       ; src[1] src[0]
      punpckldq   mm0,mm0       ; src[0] src[0]
      punpckhdq   mm1,mm1       ; src[1] src[1]
      punpckldq   mm2,mm2       ; src[2] src[2]
      movq        mm3,mm0       ; src[0] src[0]
      movq        mm4,mm1       ; src[1] src[1]
      movq        mm5,mm2       ; src[2] src[2]
      pfmul       mm0,[edx]     ; src[0]*mat[0][1] src[0]*mat[0][0]
      pfmul       mm3,[edx+8]   ; 0 src[0]*mat[0][2]
      pfmul       mm1,[edx+16]  ; src[1]*mat[1][1] src[1]*mat[1][0]
      pfmul       mm4,[edx+24]  ; 0 src[1]*mat[1][2]
      pfmul       mm2,[edx+32]  ; src[2]*mat[2][1] src[2]*mat[2][0]
      pfmul       mm5,[edx+40]  ; 0 src[2]*mat[2][2]
      pfadd       mm0,mm1       ; src[0]*mat[0][1]+src[1]*mat[1][1] src[0]*mat[0][0]+src[1]*mat[1][0]
      pfadd       mm3,mm4       ; 0 src[0]*mat[0][2]+src[1]*mat[1][2]
      pfadd       mm0,mm2       ; src[0]*mat[0][1]+src[1]*mat[1][1]+src[2]*mat[2][1] src[0]*mat[0][0]+src[1]*mat[1][0]+src[2]*mat[2][0]
      pfadd       mm3,mm5       ; 0 src[0]*mat[0][2]+src[1]*mat[1][2]+src[2]*mat[2][2]
      movq        [eax],mm0     ; mat[0][1]*src[0]+mat[1][1]*src[1]+mat[2][1]*src[2] mat[0][0]*src[0]+mat[1][0]*src[1]+mat[2][0]*src[2]
      movd        [eax+8],mm3   ; mat[0][2]*src[0]+mat[1][2]*src[1]+mat[2][2]*src[2]
      femms
		  leave
		  ret
	}
}

extern "C" void __declspec(naked) InverseTransformVector3DNOW(float *src, float *dst, float mat[4][4])
{
	_asm {
		push ebp
		mov ebp,esp

    femms
      mov         ecx,[src]
      mov         eax,[dst]
      mov         edx,[mat]
      movq        mm0,[ecx]     ; src[1] src[0]
      movd        mm4,[ecx+8]   ; 0 src[2]
      movq        mm1,mm0       ; src[1] src[0]
      pfmul       mm0,[edx]     ; src[1]*mat[0][1] src[0]*mat[0][0]
      movq        mm5,mm4       ; 0 src[2]
      pfmul       mm4,[edx+8]   ; 0 src[2]*mat[0][2]
      movq        mm2,mm1       ; src[1] src[0]
      pfmul       mm1,[edx+16]  ; src[1]*mat[1][1] src[0]*mat[1][0]
      movq        mm6,mm5       ; 0 src[2]
      pfmul       mm5,[edx+24]  ; 0 src[2]*mat[1][2]
      movq        mm3,mm2       ; src[1] src[0]
      pfmul       mm2,[edx+32]  ; src[1]*mat[2][1] src[0]*mat[2][0]
      movq        mm7,mm6       ; 0 src[2]
      pfmul       mm6,[edx+40]  ; 0 src[2]*mat[2][2]
      pfacc       mm0,mm4       ; src[2]*mat[0][2] src[1]*mat[0][1]+src[0]*mat[0][0]
      pfacc       mm1,mm5       ; src[2]*mat[1][2] src[1]*mat[1][1]+src[0]*mat[1][0]
      pfacc       mm2,mm6       ; src[2]*mat[2][2] src[1]*mat[2][1]+src[0]*mat[2][0]
      pfacc       mm0,mm1       ; src[2]*mat[1][2]+src[1]*mat[1][1]+src[0]*mat[1][0] src[2]*mat[0][2]+src[1]*mat[0][1]+src[0]*mat[0][0]
      pfacc       mm2,mm3       ; 0 src[2]*mat[2][2]+src[1]*mat[2][1]+src[0]*mat[2][0]
      movq        [eax],mm0     ; mat[1][0]*src[0]+mat[1][1]*src[1]+mat[1][2]*src[2] mat[0][0]*src[0]+mat[0][1]*src[1]+mat[0][2]*src[2]
      movd        [eax+8],mm2   ; mat[2][0]*src[0]+mat[2][1]*src[1]+mat[2][2]*src[2]
      femms                    
		  leave
		  ret
	}
}

extern "C" void  __declspec(naked) MulMatrices3DNOW(float m1[4][4],float m2[4][4],float r[4][4])
{
	_asm {
		push ebp
		mov ebp,esp

    femms
      mov         ecx,[m1]
      mov         eax,[r]
      mov         edx,[m2]
      
      movq        mm0,[ecx]
      movq        mm1,[ecx+8]
      movq        mm4,[edx]
      punpckhdq   mm2,mm0
      movq        mm5,[edx+16]
      punpckhdq   mm3,mm1
      movq        mm6,[edx+32]
      punpckldq   mm0,mm0
      punpckldq   mm1,mm1
      pfmul       mm4,mm0
      punpckhdq   mm2,mm2
      pfmul       mm0,[edx+8]
      movq        mm7,[edx+48]
      pfmul       mm5,mm2
      punpckhdq   mm3,mm3
      pfmul       mm2,[edx+24]
      pfmul       mm6,mm1
      pfadd       mm5,mm4
      pfmul       mm1,[edx+40]
      pfadd       mm2,mm0
      pfmul       mm7,mm3
      pfadd       mm6,mm5
      pfmul       mm3,[edx+56]
      pfadd       mm2,mm1
      pfadd       mm7,mm6
      movq        mm0,[ecx+16]
      pfadd       mm3,mm2
      movq        mm1,[ecx+24]
      movq        [eax],mm7
      movq        mm4,[edx]
      movq        [eax+8],mm3
      
      punpckhdq   mm2,mm0
      movq        mm5,[edx+16]
      punpckhdq   mm3,mm1
      movq        mm6,[edx+32]
      punpckldq   mm0,mm0
      punpckldq   mm1,mm1
      pfmul       mm4,mm0
      punpckhdq   mm2,mm2
      pfmul       mm0,[edx+8]
      movq        mm7,[edx+48]
      pfmul       mm5,mm2
      punpckhdq   mm3,mm3
      pfmul       mm2,[edx+24]
      pfmul       mm6,mm1
      pfadd       mm5,mm4
      pfmul       mm1,[edx+40]
      pfadd       mm2,mm0
      pfmul       mm7,mm3
      pfadd       mm6,mm5
      pfmul       mm3,[edx+56]
      pfadd       mm2,mm1
      pfadd       mm7,mm6
      movq        mm0,[ecx+32]
      pfadd       mm3,mm2
      movq        mm1,[ecx+40]
      movq        [eax+16],mm7
      movq        mm4,[edx]
      movq        [eax+24],mm3
      
      punpckhdq   mm2,mm0
      movq        mm5,[edx+16]
      punpckhdq   mm3,mm1
      movq        mm6,[edx+32]
      punpckldq   mm0,mm0
      punpckldq   mm1,mm1
      pfmul       mm4,mm0
      punpckhdq   mm2,mm2
      pfmul       mm0,[edx+8]
      movq        mm7,[edx+48]
      pfmul       mm5,mm2
      punpckhdq   mm3,mm3
      pfmul       mm2,[edx+24]
      pfmul       mm6,mm1
      pfadd       mm5,mm4
      pfmul       mm1,[edx+40]
      pfadd       mm2,mm0
      pfmul       mm7,mm3
      pfadd       mm6,mm5
      pfmul       mm3,[edx+56]
      pfadd       mm2,mm1
      pfadd       mm7,mm6
      movq        mm0,[ecx+48]
      pfadd       mm3,mm2
      movq        mm1,[ecx+56]
      movq        [eax+32],mm7
      movq        mm4,[edx]
      movq        [eax+40],mm3
      
      punpckhdq   mm2,mm0
      movq        mm5,[edx+16]
      punpckhdq   mm3,mm1
      movq        mm6,[edx+32]
      punpckldq   mm0,mm0
      punpckldq   mm1,mm1
      pfmul       mm4,mm0
      punpckhdq   mm2,mm2
      pfmul       mm0,[edx+8]
      movq        mm7,[edx+48]
      pfmul       mm5,mm2
      punpckhdq   mm3,mm3
      pfmul       mm2,[edx+24]
      pfmul       mm6,mm1
      pfadd       mm5,mm4
      pfmul       mm1,[edx+40]
      pfadd       mm2,mm0
      pfmul       mm7,mm3
      pfadd       mm6,mm5
      pfmul       mm3,[edx+56]
      pfadd       mm2,mm1
      pfadd       mm7,mm6
      pfadd       mm3,mm2
      movq        [eax+48],mm7
      movq        [eax+56],mm3
      femms
	  leave
	  ret
	}
}

extern "C" float  __declspec(naked) DotProduct3DNOW(register float *v1, register float *v2)
{
	_asm {
		push ebp
		mov ebp,esp
      
      femms
      mov         edx,[v1]
      mov         eax,[v2]
      movq        mm0,[edx]
      movq        mm3,[eax]
      pfmul       mm0,mm3
      movq        mm2,[edx+8]
      movq        mm1,[eax+8]
      pfacc       mm0,mm0
      pfmul       mm1,mm2
      pfadd       mm0,mm1
      movd        eax,mm0
      femms
	  leave
	  ret
	}
}

extern "C" void __declspec(naked) NormalizeVector3DNOW(float *v)
{
	_asm {
		push ebp
		mov ebp,esp      
      femms
      mov          edx,[v]
      movq         mm0,[edx]
      movq         mm3,[edx+8]
      movq         mm1,mm0
      movq         mm2,mm3
      pfmul        mm0,mm0
      pfmul        mm3,mm3
      pfacc        mm0,mm0
      pfadd        mm0,mm3
      ;movq mm4,mm0 ; prepare for 24bit precision
      ;punpckldq mm4,mm4 ; prepare for 24bit precision
      pfrsqrt      mm0,mm0 ; 15bit precision 1/sqrtf(v)
      ;movq mm3,mm0
      ;pfmul mm0,mm0
      ;pfrsqit1 mm0,mm4
      ;pfrcpit2 mm0,mm3 ; 24bit precision 1/sqrtf(v)
      pfmul        mm1,mm0
      pfmul        mm2,mm0
      movq         [edx],mm1
      movq         [edx+8],mm2
      femms
	  leave
	  ret
	}
}
