;ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
;º  Name:Electronic_Birthday_Cake________  V01.10  º
;º                                                 º
;º	 Date:23-Nov-93 			   º
;º                                                 º
;º Copyright (C) 1993 by F.Becker aka -=* SliQ *=- º
;ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
;
;Normal Assembly Program Header
; (Simplified Segment Definitions)

MaxPts          EQU     1146

 DOSSEG
;**************************************************
.MODEL Compact
.386
;**************************************************
.STACK 100h
;**************************************************
.DATA

;Sines and cosines used in rotations
Xsin            dd 0
Xcos            dd 0
Ysin            dd 0
Ycos            dd 0
Zsin            dd 0
Zcos            dd 0

palblack        db 3*256 DUP (0)        ;
palwhite        db 3*256 DUP (63)       ;
pal2            db 3*256 DUP (0)        ;
pal3            db 3*256 DUP (0)        ;

eyeposX         dd 0
eyeposY         dd 0
eyeposZ         dd 0

lookatX         dd 0
lookatY         dd 0
lookatZ         dd 0

VRCount         dw 0
FrameReady      dw 0
Frame           dw 0
PalChanged      dw 0

ClearColor      db 0
WriteOffset     dw 0
CurrPage        dw 0
NextPage        dw 19200
ClipMinX        dw 1
ClipMinY        dw 1
ClipMaxX        dw 319
ClipMaxY        dw 239

deg1            dw 0
deg2            dw 40

;**************************************************
.FARDATA @dataseg2

xtmp            dd 0
ytmp            dd 0
ztmp            dd 0

dispptr         dw offset starbuff1
clearptr        dw offset starbuff2
staroffset      dw 0
		dw 1*MaxPts
		dw 2*MaxPts
		dw 3*MaxPts

sphere          dd 3*MaxPts DUP (0)
bday            dd 3*MaxPts DUP (0)
deltas          dd 3*MaxPts DUP (0)

colors          db MaxPts DUP (0)
		db MaxPts DUP (0)
		db MaxPts DUP (0)
		db MaxPts DUP (0)

starbuff1       dw MaxPts DUP (0)
		dw MaxPts DUP (0)
		dw MaxPts DUP (0)
		dw MaxPts DUP (0)

starbuff2       dw MaxPts DUP (0)
		dw MaxPts DUP (0)
INCLUDE Birthday.inc        ;the arrays in birthday.inc are part of starbuff2!

;**************************************************
.FARDATA @dataseg3

;**************************************************
.CODE

INCLUDE ModeX.inc
INCLUDE Fixed.inc
INCLUDE Random.inc
INCLUDE IntMisc.inc

;--------------------------------------------------
main      proc      ;main part of program

ASSUME  gs:@dataseg2
ASSUME  fs:@dataseg3

start:
	Call    DisableKbd

	;set up datasegments
	mov     ax,@data
	mov     ds,ax
	mov     ax,@dataseg2
	mov     gs,ax
	mov     ax,@dataseg3
	mov     fs,ax
	mov     ax,0a000h
	mov     es,ax

	; Fade to Black!
	mov     si,offset palblack
	mov     ax,200h
	mov     cx,256
	Call    FadeIn

	Call    InitPalette
	Call    Scron

	mov     si,offset pal2
	mov     al,0
	mov     cx,256
	Call    SetPal

	;reorganize 'Happy Birthday' data
	Call    MakeBirthday
	;create sphere points
	Call    MakeSphere

	mov     ax,NextPage
	Call    SetPage
	mov     ax,CurrPage
	Call    ShowPage
	mov     ax,CurrPage
	xchg    ax,NextPage
	mov     CurrPage,ax

	;set up interrupts
	Call    SetINT9
	Call    SetINT8

main1:
	;calc new eyeposition and lookat
	Call    CalcEye
	;rotate and draw
	Call    DrawPoints

	;change page - will take effect next VR
	mov     ax,CurrPage
	Call    ShowPage
	inc     FrameReady

main2:  ;synchronize with timer
	cmp     FrameReady,0
	jne     main2

	mov     ax,NextPage
	Call    SetPage
	mov     ax,NextPage
	xchg    ax,CurrPage
	mov     NextPage,ax

	; clear points on other page
	Call    ClearPoints

	mov     ax,dispptr
	xchg    ax,clearptr
	mov     dispptr,ax

	;NOTE : transformations are still CPU-speed dependent
	;	(it'll always take 32 frames to transform)
	;       I was to lazy to fix this. Maybe you would
	;	like to get frustrated over this |-)
	mov     ax,Frame
	and     ax,1ffh
	cmp     ax,112
	jle     main4
	cmp     ax,144
	jg      main3
	Call    Transform1
	jmp     short main4
main3:
	cmp     ax,368
	jle     main4
	cmp     ax,400
	jg      main4
	Call    Transform2
main4:

	inc     Frame
	in      al,60h
	dec     al          ;someone hugged ESC?
	jz      main6
	jmp     main1

main6:
	; Fade White!
	mov     si,offset palwhite
	mov     ax,0a00h    ;fade towards white - fast
	mov     cx,256
	Call    FadeIn

	; Fade   Out!
	mov     si,offset palblack
	mov     ax,0400h    ;fade towards black - medium speed
	mov     cx,256
	Call    FadeIn

	; get those old int vectors back in place
	Call    RestoreINT8
	Call    RestoreINT9

	Call    Scroff

	Call    EnableKbd

	;back to DOS
	mov     ax,4c00h
	int     21h

main      endp
;--------------------------------------------------
;called every VR - from INT8handler
HouseKeeper   PROC

	pusha
	inc     VRCount

	mov     FrameReady,0

	add	deg1,3
	add	deg2,2
	popa
	ret

HouseKeeper   ENDP
;--------------------------------------------------

MakeSphere      PROC

	xor     di,di
makesp1:
	Call    CalcSphere

	mov     eax,xtmp
	mov     sphere[di],eax
	mov     ebx,bday[di]
	sub     ebx,eax
	sar     ebx,5
	mov     deltas[di],ebx

	mov     eax,ytmp
	mov     sphere[di+4],eax
	mov     ebx,bday[di+4]
	sub     ebx,eax
	sar     ebx,5
	mov     deltas[di+4],ebx

	mov     eax,ztmp
	mov     sphere[di+8],eax
	mov     ebx,bday[di+8]
	sub     ebx,eax
	sar     ebx,5
	mov     deltas[di+8],ebx

	add     di,12
	cmp     di,12*(MaxPts-1)
	jle     makesp1

MakeSphere      ENDP

; modifies  : eax,ebx,ecx,edx,si
CalcSphere  PROC

	mov     ecx,4096

	Call    Random
	xor     edx,edx
	div     ecx
	mov     xtmp,edx

	sub     ecx,edx
	Call    Random
	xor     edx,edx
	div     ecx
	mov     ytmp,edx

	sub     ecx,edx
	mov     ztmp,ecx

	mov     ecx,xtmp
	shl     ecx,14
	Call    Sqrt
	mov     xtmp,eax

	mov     ecx,ytmp
	shl     ecx,14
	Call    Sqrt
	mov     ytmp,eax

	mov     ecx,ztmp
	shl     ecx,14
	Call    Sqrt
	mov     ztmp,eax

	Call    Random

	test    ax,1
	jz      noneg1
	neg     xtmp
noneg1:

	test    ax,2
	jz      noneg2
	neg     ytmp
noneg2:

	test    ax,4
	jz      noneg3
	neg     ztmp
noneg3:

	ret

CalcSphere  ENDP
;--------------------------------------------------
MakeBirthday PROC

	xor     si,si
	xor     ebx,ebx

	mov     cx,MaxPts
MBir1:
	xor     eax,eax
	mov     ax,oldstars1[ebx]
	sub     ax,150
	cwde
	shl     eax,16
	mov     dword ptr bday[si],eax
	add     si,4

	xor     eax,eax
	mov     ax,oldstars2[ebx]
	sub     ax,55
	cwde
	shl     eax,16
	mov     dword ptr bday[si],eax
	add     si,8
	add     ebx,2
	loop    MBir1

	ret

MakeBirthday ENDP
;--------------------------------------------------
CalcEye         PROC

	;calc eye position
	mov     bx,deg1
	Call    Sin
	shl     eax,6
	mov     ebx,12*(750)
	add     eax,sphere[ebx]
	mov     eyeposX,eax

	mov     bx,deg2
	Call    Cos
	shl     eax,5
       ;mov     ebx,12*(750)+4
	sub	eax,65536*20
       ;add     eax,sphere[ebx]
	mov     eyeposZ,eax

	mov     bx,deg1
	add     bx,50
	Call    Cos
	shl     eax,6
	neg     eax
	mov     eyeposY,eax

	;calc lookat (currently looking at point 750 which
	;is part of the D in 'happy birthDay'
	mov     ebx,12*(750)
	mov     eax,sphere[ebx]
	sub     eax,eyeposX
	sar     eax,7
	mov     lookatX,eax

	mov     ebx,12*(750)+4
	mov     eax,sphere[ebx]
	sub     eax,eyeposY
	sar     eax,7
	mov     lookatY,eax

	mov     ebx,12*(750)+8
	mov     eax,sphere[ebx]
	sub     eax,eyeposZ
	sar     eax,7
	mov     lookatZ,eax

	;calc sines and cosines for X and Y rotations
	mov     eax,lookatX
	imul    lookatX
	add     eax,8000h
	adc     edx,0
	shrd    eax,edx,16
	mov     ecx,eax

	mov     eax,lookatZ
	imul    lookatZ
	add     eax,8000h
	adc     edx,0
	shrd    eax,edx,16      ;                  2         2         2
	add     ecx,eax         ;ecx is (distance1) = lookatX + lookatZ

	mov     eax,lookatY
	imul    lookatY
	add     eax,8000h
	adc     edx,0
	shrd    eax,edx,16      ;                  2       2         2
	add     eax,ecx         ;eax is (distance2) = dist1 + lookatY

	push    eax
	Call    Sqrt
	mov     ebx,eax         ;eax is dist1
	mov     edx,lookatX
	xor     eax,eax
	shrd    eax,edx,16
	sar     edx,16
	idiv    ebx
	mov     Ysin,eax        ;sin = lookatX/dist1

	mov     edx,lookatZ
	xor     eax,eax
	shrd    eax,edx,16
	sar     edx,16
	idiv    ebx
	mov     Ycos,eax
	pop     ecx             ;cos = lookatZ/dist1

	push    ebx
	Call    Sqrt
	mov     ebx,eax         ;eax is dist2
	mov     edx,lookatY
	xor     eax,eax
	shrd    eax,edx,16
	sar     edx,16
	idiv    ebx
	mov     Xsin,eax        ;sin = lookatY/dist2

	pop     edx             ;edx = dist1
	xor     eax,eax
	shrd    eax,edx,16
	sar     edx,16
	idiv    ebx
	mov     Xcos,eax        ;cos = dist1/dist2

	ret

CalcEye         ENDP
;--------------------------------------------------
InitPalette PROC

	xor     bx,bx
	mov     cx,256
initpal1:
	mov     al,cl
	shr     al,2
	mov     pal2[bx+0],0        ;red
	mov     pal2[bx+1],al       ;green
	mov     pal2[bx+2],0        ;blue
	mov     pal3[bx],al       ;help entry
	add     bx,3
	loop    initpal1
	ret

InitPalette ENDP
;--------------------------------------------------
DrawPoints      PROC


	xor     ecx,ecx
	mov     cx,dispptr
	mov     word ptr gs:[ecx],0
	mov     word ptr gs:[ecx+(2*MaxPts)],0
	mov     word ptr gs:[ecx+(4*MaxPts)],0
	mov     word ptr gs:[ecx+(6*MaxPts)],0

	mov     ecx,12*(MaxPts-1)
dpts1:
	push    ecx
	mov     eax,sphere[ecx]
	sub     eax,eyeposX
	mov     Xtmp,eax

	mov     eax,sphere[ecx+4]
	sub     eax,eyeposY
	mov     Ytmp,eax

	mov     eax,sphere[ecx+8]
	sub     eax,eyeposZ
	mov     Ztmp,eax

	mov     si,offset Xtmp
	Call    RotateY
	mov     Xtmp,ebx
	mov     Ztmp,ecx

	Call    RotateX
	mov     Ytmp,ebx
	mov     Ztmp,ecx

	cmp     ecx,65536       ;ignore points with Z<1
	jl      dpts2

	mov     ebx,ecx
	Call    Three2TwoD
	shr     ecx,16
	shr     edx,16
	add     ecx,160
	add     edx,120
	shr     ebx,15
	sub     bx,10
	cmp     bx,256
	jl      dpts3
	mov     bl,255          ;bl - color, ecx-X, edx-Y
dpts3:
	mov     al,bl
	Call    EnterDot
dpts2:
	pop     ecx
	sub     ecx,12
	jge     dpts1

	Call    ShootEm

	ret

DrawPoints      ENDP
;--------------------------------------------------
EnterDot        PROC

	cmp     dx,[ClipMaxY]
	jae     NoEnter
	cmp     dx,[ClipMinY]
	jb      NoEnter

	cmp     cx,[ClipMaxX]
	jae     NoEnter
	cmp     cx,[ClipMinX]
	jb      NoEnter

	nop
	mov     bx,cx
	and     bx,011b
	shl     bx,1
	mov     bx,staroffset[bx]
	mov     si,bx
	shl     si,1
	add     si,dispptr
	add     bx,gs:[si]
	inc     word ptr gs:[si]
	mov     colors[bx],al
	shl     bx,1
	mov     si,bx
	add     si,dispptr
	add     si,2
	shr     cx,2
	xor     ebx,ebx
	mov     bx,dx
	shl     bx,4
	lea     ebx,[ebx+4*ebx]
	add     bx,cx
	add     bx,[WriteOffset]
	mov     gs:[si],bx

NoEnter:
	ret

EnterDot        ENDP
;--------------------------------------------------
ShootEm         PROC

	nop
	mov     bx,dispptr
	xor     si,si

	mov     cx,gs:[bx]
	or      cx,cx
	jz      shoot2
	add     bx,2

	mov     ax,0100h + MAP_MASK ;AL = index in SC of Map Mask reg
	mov     dx,SC_INDEX         ;set the Map Mask to enable only the
	out     dx,ax               ; pixel's plane
shoot1:
	mov     al,colors[si]
	mov     di,gs:[bx]
	mov     es:[di],al
	add     bx,2
	inc     si
	loop    shoot1
shoot2:

	mov     bx,dispptr
	add     bx,MaxPts*2
	xor     si,si

	mov     cx,gs:[bx]
	or      cx,cx
	jz      shoot4
	add     bx,2

	mov     ax,0200h + MAP_MASK ;AL = index in SC of Map Mask reg
	mov     dx,SC_INDEX         ;set the Map Mask to enable only the
	out     dx,ax               ; pixel's plane
shoot3:
	mov     al,colors[si+MaxPts]
	mov     di,gs:[bx]
	mov     es:[di],al
	add     bx,2
	inc     si
	;stosb
	loop    shoot3
shoot4:

	mov     bx,dispptr
	add     bx,MaxPts*4
	xor     si,si

	mov     cx,gs:[bx]
	or      cx,cx
	jz      shoot6
	add     bx,2

	mov     ax,0400h + MAP_MASK ;AL = index in SC of Map Mask reg
	mov     dx,SC_INDEX         ;set the Map Mask to enable only the
	out     dx,ax               ; pixel's plane
shoot5:
	mov     al,colors[si+2*MaxPts]
	mov     di,gs:[bx]
	mov     es:[di],al
	add     bx,2
	inc     si
	;stosb
	loop    shoot5
shoot6:

	mov     bx,dispptr
	add     bx,MaxPts*6
	xor     si,si

	mov     cx,gs:[bx]
	or      cx,cx
	jz      shoot8
	add     bx,2

	mov     ax,0800h + MAP_MASK ;AL = index in SC of Map Mask reg
	mov     dx,SC_INDEX         ;set the Map Mask to enable only the
	out     dx,ax               ; pixel's plane
shoot7:
	mov     al,colors[si+3*MaxPts]
	mov     di,gs:[bx]
	mov     es:[di],al
	add     bx,2
	inc     si
	;stosb
	loop    shoot7
shoot8:

	ret

ShootEm         ENDP
;--------------------------------------------------
ClearPoints     PROC

	nop
	mov     bx,clearptr

	mov     cx,gs:[bx]
	or      cx,cx
	jz      clrem2
	add     bx,2

	mov     ax,0100h + MAP_MASK ;AL = index in SC of Map Mask reg
	mov     dx,SC_INDEX         ;set the Map Mask to enable only the
	out     dx,ax               ; pixel's plane
clrem1:
	mov     di,gs:[bx]
	mov     byte ptr es:[di], 0
	add     bx,2
	loop    clrem1
clrem2:

	mov     bx,clearptr
	add     bx,MaxPts*2

	mov     cx,gs:[bx]
	or      cx,cx
	jz      clrem4
	add     bx,2

	mov     ax,0200h + MAP_MASK ;AL = index in SC of Map Mask reg
	mov     dx,SC_INDEX         ;set the Map Mask to enable only the
	out     dx,ax               ; pixel's plane
clrem3:
	mov     di,gs:[bx]
	mov     byte ptr es:[di], 0
	add     bx,2
	loop    clrem3
clrem4:

	mov     bx,clearptr
	add     bx,MaxPts*4

	mov     cx,gs:[bx]
	or      cx,cx
	jz      clrem6
	add     bx,2

	mov     ax,0400h + MAP_MASK ;AL = index in SC of Map Mask reg
	mov     dx,SC_INDEX         ;set the Map Mask to enable only the
	out     dx,ax               ; pixel's plane
clrem5:
	mov     di,gs:[bx]
	mov     byte ptr es:[di], 0
	add     bx,2
	loop    clrem5
clrem6:

	mov     bx,clearptr
	add     bx,MaxPts*6

	mov     cx,gs:[bx]
	or      cx,cx
	jz      clrem8
	add     bx,2

	mov     ax,0800h + MAP_MASK ;AL = index in SC of Map Mask reg
	mov     dx,SC_INDEX         ;set the Map Mask to enable only the
	out     dx,ax               ; pixel's plane
clrem7:
	mov     di,gs:[bx]
	mov     byte ptr es:[di], 0
	add     bx,2
	loop    clrem7
clrem8:

	ret

ClearPoints     ENDP
;--------------------------------------------------
Transform1      PROC

	mov     ecx,12*(MaxPts-1)
trans1:
	mov     eax,deltas[ecx]
	add     sphere[ecx],eax
	mov     eax,deltas[ecx+4]
	add     sphere[ecx+4],eax
	mov     eax,deltas[ecx+8]
	add     sphere[ecx+8],eax
	sub     ecx,12
	jge     trans1

	xor     bx,bx
trans4:
	mov     al,pal3[bx]
	dec     al
	cmp     pal2[bx],al
	jge     trans2
	add     pal2[bx],2
	sub     pal2[bx+1],2
	jmp     short trans3
trans2:
	inc     al
	mov     pal2[bx],al
	mov     pal2[bx+1],0
trans3:
	add     bx,3
	cmp     bx,768
	jl      trans4

	mov     si,offset pal2
	mov     al,0
	mov     cx,256
	Call    SetPal

	ret

Transform1      ENDP
;--------------------------------------------------
Transform2      PROC

	mov     ecx,12*(MaxPts-1)
transf1:
	mov     eax,deltas[ecx]
	sub     sphere[ecx],eax
	mov     eax,deltas[ecx+4]
	sub     sphere[ecx+4],eax
	mov     eax,deltas[ecx+8]
	sub     sphere[ecx+8],eax
	sub     ecx,12
	jge     transf1

	xor     bx,bx
transf4:
	mov     al,pal2[bx]
	sub     al,2
	jb      transf2
	mov     pal2[bx],al
	add     pal2[bx+1],2
	jmp     short transf3
transf2:
	mov     al,pal3[bx]
	mov     pal2[bx+1],al
	mov     pal2[bx],0
transf3:
	add     bx,3
	cmp     bx,768
	jl      transf4

	mov     si,offset pal2
	mov     al,0
	mov     cx,256
	Call    SetPal

	ret

Transform2      ENDP
;--------------------------------------------------
;**************************************************
END start
