; This function is owned by Onan Farabi.
; For commercial purpose please contact me.

PosCount proto :dword,:dword,:dword,:dword

GetPosLine proto :dword,:dword,:dword,:dword
GetDeltaXY proto :dword,:dword,:dword,:dword
GetHypotenusa proto :dword,:dword
GetPosRound proto :dword,:dword
GetPosRound2 proto :dword,:dword
UMGetPosRound proto :dword,:dword
GetDegree proto :dword,:dword
GetScale proto :dword,:dword
GetPosX proto :dword,:dword
GetSin proto :dword
GetCos proto :dword
GetTan proto :dword
GetFG proto :dword,:dword

RotatePoint proto :dword,:dword,:dword,:dword

fGrad proto :dword,:dword,:dword
IsInsideRect proto :dword,:dword,:dword,:dword,:dword,:dword
IsInsideCircle proto :dword,:dword,:dword

aTan2 proto :dword,:dword
Deg2Rad proto :dword
Rad2Deg proto 


CenterScreen proto :dword,:dword
To3D proto :dword,:dword,:dword
CreateLine proto :dword,:Dword,:dword,:dword
GetLine3D proto :dword,:Dword
GetCountLine3D proto
ResetLine proto 

GetLine3DAll proto :dword,:dword
SetLine3DAll proto :dword,:Dword

MirrorPosA proto :dword,:dword,:dword
Phase1 proto

SetClockCount proto 
AddClockCount proto :dword
GetClockCount proto

FramePosition proto dwInd:dword,y:dword 

line3D struct
	x dword 0
	y dword 0
	z dword 0
	color dword 0
line3D ends

.data?
	SCTbl_sin dword ?
	SCTbl_cos dword ?
	SCTbl_tan dword ?

	
	Line_Table dword ?
	
	SCR_TBL dword ?
	
	nLPtr dword ?
	nLLimit dword ?
	
	VP dword ?
	x_res dword ?
	y_res dword ?
.data
	SinTable db 'SinCosTable.frb',0
.code



IsInsideCircle proc radius:dword,nDX:dword,nDY:dword
	; Not completed yet
	invoke GetHypotenusa,nDX,nDY
	
	.if eax<radius
		xor eax,eax
		inc eax
	.else
		xor eax,eax
	.endif
	
	ret
IsInsideCircle endp

FramePosition proc uses esi edi dwInd:dword,h:dword
	
	xor edx,edx
	mov eax,h
	mov ecx,dwInd
	
	mul ecx
	
	
	
	ret
FramePosition endp ; eax = position heigth 

RotatePoint proc delta:dword,xAng:dword,yAng:dword,zAng:dword
	LOCAL x,y,z:dword
	
	; rotate around z axis (x y)
	invoke UMGetPosRound,delta,zAng
	mov x,edx						; cos
	invoke UMGetPosRound,delta,zAng
	mov y,eax						; sin
	
	; rotate around x axis (y z)
	invoke UMGetPosRound,y,xAng
	mov y,edx						; y is delta*cos(xang)
	invoke UMGetPosRound,delta,xAng
	mov z,eax						; z is delta*sin(xang)
	
	; rotate around y axis (x z)
	invoke UMGetPosRound,z,yAng
	mov z,edx						; cos
	invoke UMGetPosRound,x,yAng
	mov x,eax						; sin
	
	mov edx,x
	mov eax,y
	mov ecx,z
	
	ret
RotatePoint endp ; edx =x eax=y ecx=z

Phase1 proc uses esi 	; 28.8 Kbyte needed
	LOCAL deg,sin,cos,tan:dword
	
	
	invoke GlobalAlloc,LMEM_DISCARDABLE,28800+14400 + 16*10000 +768*4
	invoke GlobalLock,eax
	mov SCTbl_sin,eax
	
	
	mov esi,eax					; 1 Clock cycle
	xor ecx,ecx					; 1 Clock cycle
	mov deg,ecx					; 1 Clock cycle
	
	mov edx,3600				; 1 Clock cycle
	shl edx,2					; 2 Clock cycle
	
	
	@@:
	finit						; 17 Clock cycle
	pushad
	invoke Deg2Rad,deg			; 104 Clock cycle
	popad
	fsincos						; 365 Clock cycle
;	fstp sin					; 8 Clock cycle
;	fstp cos					; 8 Clock cycle
	
	push 1000
	fimul dword ptr[esp]	
	fistp dword ptr[esp]			
	pop sin
	push 1000
	fimul dword ptr[esp]
	fistp dword ptr[esp]					
	pop cos
	
	mov eax,sin					; 1 Clock cycle
	mov dword ptr[esi],eax		; 1 Clock cycle
	mov eax,cos					; 1 Clock cycle
	mov dword ptr[esi+edx],eax	; 1 Clock cycle
	
	add deg,1					; 3 Clock cycle
	add esi,4					; 1 Clock cycle
	add ecx,4					; 1 Clock cycle
	cmp deg,3600				; 2 Clock cycle
	jl @b						; 3 Clock cycle
								; 513 Clock cycle Each loop
	; 1846800 Clock cycle total loop
	; 1846806 Clock cycle
	mov esi,SCTbl_sin
	add esi,14400
	mov SCTbl_cos,esi
	
	mov esi,SCTbl_sin
	add esi,28800
	mov SCTbl_tan,esi
	;Tan
	mov edx,3600				; 1 Clock cycle
	shl edx,2					; 2 Clock cycle
	
	xor ecx,ecx
	mov deg,ecx
	
	@@:
	finit						; 17 Clock cycle
	pushad
	invoke Deg2Rad,deg			; 104 Clock cycle
	popad
	fptan						; 273 Clock cycle
	fxch 
;	fstp tan
	push 1000
	fimul dword ptr[esp]
	fistp dword ptr[esp]
	pop eax
	
	push tan
	pop [esi]
	add deg,1					; 3 Clock cycle
	add esi,4					; 1 Clock cycle
	add ecx,4					; 1 Clock cycle
	cmp deg,3600				; 2 Clock cycle
	jl @b						; 3 Clock cycle
	
	
	mov esi,SCTbl_sin
	add esi,28800+14400
	mov Line_Table,esi
	mov eax,16*10000
	mov nLLimit,eax
	mov nLPtr,0
	
	add esi,eax
	mov SCR_TBL,esi
	
	mov ecx,768
	xor eax,eax
	xor edx,edx
	@@:
	mov [esi+edx*4],eax
	add eax,1024
	inc edx
	dec ecx
	jns @b
	
	ret
Phase1 endp

MirrorPos proc x:dword,y:dword,reg:dword
	
	mov edx,x
	mov eax,y
	
	cmp reg,0
	jz brs
;	cmp reg,1
;	jz rev_plus_plus
	cmp reg,1
	jz min_plus
;	cmp reg,3
;	jz rev_min_plus
	cmp reg,2
	jz min_min
;	cmp reg,5
;	jz rev_min_min
	cmp reg,3
	jz plus_min
;	cmp reg,7
;	jz rev_plus_min
	ret
	min_plus:
		neg edx
		ret
	min_min:
		neg edx
		neg eax
		ret
	plus_min:
		neg eax
		ret
	rev_min_plus:
		neg edx
		xchg eax,edx
		ret
	rev_min_min:
		neg edx
		neg eax
		xchg eax,edx
		ret
	rev_plus_min:
		neg eax
		xchg eax,edx
		ret
	rev_plus_plus:
		xchg eax,edx
		ret
	brs:
	xor eax,eax
	ret
MirrorPos endp

PosCount proc x:dword,y:dword,maxX:dword,maxY:dword

	
	mov eax,maxY			; 1 clock cycle
	cmp y,eax				; 2 clock cycle
	jae brs					; 1 clock cycle
	mov eax,maxX			; 1 clock cycle
	cmp x,eax				; 2 clock cycle
	jae brs					; 1 clock cycle
	xor ecx,ecx
	cmp x,ecx
	jl brs
	cmp y,ecx
	jl brs
		mov ecx,y
	;	mov eax,maxX		; 1 clock cycle eax:=maxX
	;	mul y				; 42 clock cyclee ax:=maxX*y
		shl ecx,10
		mov eax,ecx
		add eax,x			; 2 clock cycle eax:=(MaxX * Y)+x
		ret					; 1 clock cycle
		; 54 clock cycle
	brs:
	xor eax,eax
	dec eax
	ret
PosCount endp

PosCount2 proc uses esi edi x:dword,y:dword
	
	mov esi,SCR_TBL
	mov eax,y
	cmp eax,768
	ja error
	xor ecx,ecx
	cmp eax,ecx
	jl error
		mov eax,[esi+eax*4]
		mov edx,x
		cmp edx,1024
		jae error
		cmp edx,ecx
		jl error
			add eax,edx
			ret
	error:
	xor eax,eax
	dec eax
	ret
PosCount2 endp

GetPosLine proc nDX:dword,nDY:dword,hyp:dword,nPos:dword
	LOCAL x,y:dword
	
	fild nDX		
	fidiv hyp		
	fimul nPos		
	fistp x			
	
	; (nPos*nDX)/hyp
	xor edx,edx		; 1
	xor eax,eax		; 1
	
	mov eax,nDX		; 1
	imul nPos		; 42
	idiv hyp		; 42
	mov x,eax		; 1
		
;	fild nDY		
;	fidiv hyp		
;	fimul nPos		
;	fistp y			
	
	; (nPos*nDY)/hyp
	
	xor edx,edx		; 1
	xor eax,eax		; 1
	
	mov eax,nDY		; 1
	imul nPos		; 42
	idiv hyp		; 42
	mov y,eax		; 1
	
	mov edx,x		
	mov eax,y		
	
	; FPU 		= 169 Clock cycle
	; No FPU 	= 177 Clock cycle
	ret
GetPosLine endp		; Result on edx:eax

GetDeltaXY proc x:dword,y:dword,x2:dword,y2:dword
	
	mov edx,x2
	sub edx,x
	mov eax,y2
	sub eax,y
	
	ret
GetDeltaXY endp		; Result on edx:eax

GetHypotenusa proc nDX:dword,nDY:dword
	LOCAL res:dword
	
	xor edx,edx
	mov eax,nDY
	mul eax
	
	mov res,eax
	
	xor edx,edx
	mov eax,nDX
	mul eax
	
	add res,eax
	fild res
	fsqrt
	fistp res
	mov eax,res
	
	ret
GetHypotenusa endp	;

GetDegree proc nDX:dword,nDY:dword
	
	invoke aTan2,nDX,nDY
	invoke Rad2Deg
	
	ret
GetDegree endp				; eax=(atan(dy,dx)) * 20

GetPosX proc p:dword,d:dword
	
	
	ret
GetPosX endp

fGrad proc x:dword,nMaxx:dword,nNum:dword
	
	xor edx,edx		; 1
	mov eax,nNum	; 2
	mul x			; 42
					
	div nMaxx		; 40
	; 85 clock cycle
	
	ret
fGrad endp  				; eax result	; edx the rest;

IsInsideRect proc mX:dword,mY:dword,x:dword,y:dword,l:dword,t:dword
	
	mov eax,x
	mov edx,y
	
	cmp mX,eax
	jl brs
	cmp mY,edx
	jl brs
		add eax,l
		add edx,t
		cmp mX,eax
		ja brs
			cmp mY,edx
			ja brs
		xor eax,eax
		inc eax
		ret
	brs:
	xor eax,eax
	dec eax
	ret
IsInsideRect endp 			; Result eax=1 if on the rect

aTan2 proc	nDX:dword, nDY:dword
	
	fild nDX				;
	fild nDY				;
	fpatan
	
	ret
aTan2 endp					; result at st(0)

Deg2Rad proc deg:dword								; 104 Clock cycle
	
	fldpi					; Load Phi							8  Clock cycle
	push 180				; Push 180 degree					1  Clock cycle
	fidiv dword ptr[esp]	; Div it with #180					86 Clock cycle
	pop eax					; eax are Junk						4  Clock cycle
	
	fild deg				; Rot								
	push 10					;									1  Clock cycle
	fidiv dword ptr[esp]	; Rot/#100, We got float here		
	pop eax					; eax are Junk						4  Clock cycle
	
	fmul st,st(1)			; Mul, a = (rot/#100) * (Phi/180)	
	
	ret
Deg2Rad endp				; Result at FPU

Rad2Deg proc 				; Source must be at st(0)
	
	push 3600
		fldpi
		fidivr dword ptr[esp]
		fmul st,st(1)
		fistp dword ptr[esp]
	pop eax
	
	ret
Rad2Deg endp

To3D proc x:dword,y:dword,z:dword
	LOCAL f,g,sx,sy,sz:dword
	LOCAL xc,yc:dword
	; sx=x*f/z + 1/2 nMaxX
	; sy=y*g/z + 1/2 nMaxY
	; f=w/tan(a)
	; g=h/tan(b)
	
	; Not bad. This function now shorter and faster.
	
;	cmp z,0
;	jnle @f
;		inc z
;	@@:
	add z,400
	
	invoke CenterScreen,x_res,y_res 
	mov xc,edx							
	mov yc,eax							
	
	xor edx,edx
	mov eax,x
	mov ecx,VP
	imul ecx
	idiv z
	add eax,xc
	mov xc,eax
	
	xor edx,edx
	mov eax,y
	mov ecx,VP
	imul ecx
	idiv z
	add eax,yc
	mov yc,eax
	
	mov edx,xc
	mov eax,yc
	
	
	
	ret
To3D endp											; 16213/10000000

SetVP proc ViewPoint:dword

	
	push ViewPoint
	pop VP	
	
	ret
SetVP endp

SetResolution proc x:dword,y:dword
	
	push x
	pop x_res
	push y
	pop y_res
	
	ret
SetResolution endp

CenterScreen proc nMaxX:dword,nMaxY:dword			; 8 Clock cycle
			
	mov edx,nMaxX						; 1 Clock cycle
	mov eax,nMaxY						; 1 Clock cycle
	
	shr edx,1							; 3 Clock cycle
	shr eax,1							; 3 Clock cycle
	; 8 Clock cycle
	
	ret
CenterScreen endp

GetPosRound proc delta:dword,nRot:dword
	LOCAL r_sin:dword,r_cos:dword
	LOCAL divider:dword
	
	; sin(nRot/20)=sin(radian)
	
	mov divider,20
	
	fild nRot
	fidiv divider
	fsincos
	
	fimul delta
	fistp r_sin
	
	fimul delta
	fistp r_cos
	
	mov edx,r_cos
	mov eax,r_sin
	
	
	ret
GetPosRound endp									; edx= cos(nRot)*delta, eax= sin(nRot)*Delta

GetPosRound2 proc delta:dword,deg:dword 			; 604 Clock cycle
	LOCAL r_sin:dword,r_cos:dword
	
	finit				; 17 Clock cycle
	invoke Deg2Rad,deg	; 104 Clock cycle
	fsincos				; 365 Clock cycle
	
	fimul delta			; 24 Clock cycle
	fistp r_sin			; 34 Clock cycle
	
	fimul delta			; 24 Clock cycle
	fistp r_cos			; 34 Clock cycle
	
	mov edx,r_cos		; 1 Clock cycle
	mov eax,r_sin		; 1 Clock cycle
	
	ret
GetPosRound2 endp

UMGetPosRound proc uses esi delta:dword,deg:dword 	; 138 Clock cycle
	LOCAL r_sin,r_cos:dword
	
	
	cmp deg,3600
	jl @f
		sub deg,3600
	@@:
	cmp deg,0
	jae @f
		add deg,3600
	@@:
	
	invoke GetSin,deg		
;	push eax				
;		fld dword ptr[esp]	
;	pop eax					
;	fimul delta				
;	fistp r_sin
					
	xor edx,edx
	mov ecx,delta
	imul ecx
	mov ecx,1000
	idiv ecx
	mov r_sin,eax
	
	invoke GetCos,deg		
;	push eax				
;		fld dword ptr[esp]	
;	pop eax					
;	fimul delta				
;	fistp r_cos
		
	xor edx,edx
	mov ecx,delta
	imul ecx
	mov ecx,1000
	idiv ecx
	mov r_cos,eax
	
	mov edx,r_sin			
	mov eax,r_cos			
							
	
	ret
UMGetPosRound endp

GetSin proc uses esi deg:dword						; 3 Clock cycle
	
	mov esi,SCTbl_sin					; 1 Clock cycle
	mov ecx,deg						; 1 Clock cycle
	mov eax,dword ptr[esi+ecx*4]	; 1 Clock cycle
	
	ret
GetSin endp

GetCos proc uses esi deg:dword						; 4 Clock cycle
	
	mov esi,SCTbl_cos					; 1 Clock cycle
	mov ecx,deg						; 1 Clock cycle
	mov eax,dword ptr[esi+ecx*4]	; 1 Clock cycle
	
	ret
GetCos endp

GetTan proc uses esi deg:dword						; 4 Clock cycle
	
	mov esi,SCTbl_tan					; 1 Clock cycle
	mov ecx,deg						; 1 Clock cycle
	mov eax,dword ptr[esi+ecx*4]	; 1 Clock cycle
	
	ret
GetTan endp

GetFG proc uses esi w:dword,deg:dword				; 129 Clock cycle
	
	
	invoke GetTan,deg					; 4 Clock cycle
	push eax							; 1 Clock cycle
		fld dword ptr[esp]				; 3 Clock cycle
		fidivr w						; 86 Clock cycle
		fistp dword ptr[esp]			; 34 Clock cycle
	pop eax								; 1 Clock cycle
	; 129 Clock cycle
	; eax= result
	ret
GetFG endp

