;----------------------------------------------------------------------------
; 4K 3d-thingamajig (C) 1999 by Sami Ky”stil„ (hiteck@utanet.fi)
;
; This could be a lot smaller, as it's a bit too rationally structured for a 
; 4k intro.
;
; This code is released under the GNU GPL. See http://www.gnu.org for details.
;----------------------------------------------------------------------------
; http://www.utanet.fi/~hiteck
;----------------------------------------------------------------------------

.model tiny
.386
.387

;----------------------------------------------------------------------------
; Segmentation:
;
;	CS		code, translated, clipped & rotated vertices
;	CS+1000h	framebuffer (64000 bytes)
;	CS+2000h	first texture
;
;----------------------------------------------------------------------------
; Rendering Pipeline:
;
;	render_scene -> rotate_vertices
;			        
;                             \/
;			        
;			render_hull /__ 
;			            \  \ portal
;              ______________/   \_____/
;	     |/                
;	     `- 
;	clip_polygon -> render_polygon -> render_trigon -> render_scanline
;
;----------------------------------------------------------------------------
INT_VIDEO	= 10h
INT_DOS		= 21h
PTR_VIDEO	= 0a000h
SCREENWIDTH	= 320

RENDER_PORTALS		= 1
CLIP_TO_PORTAL		= 1
BACKFACE_CULLING	= 1
INTERACTIVE_MULTIMEDIA	= 0
MAX_RECURSIONS		= 32
COMPOVERSION		= 0

FLAG_DONE	= 1h
FLAG_TEXT	= 2h
KEYFRAME_END	= 0000000000000001b
KEYFRAME_TEXT	= 0000000000000010b

POLY_FLAG_PORTAL	= 10000000b
POLY_FLAG_NEW_TEXTURE	= 01000000b

PLANE_XY	= 0
PLANE_XZ	= 1
PLANE_YZ	= 2

COLOR0		= 0
COLOR1		= 64
COLOR2		= 128
COLOR3		= 192

TEXT_LF		= 129
TEXT_SLANT	= 130
TEXT_COLOR	= 131
TEXT_RASTER	= 132

MATRIX_X_X	= 0*3*4+VECTOR3D.x
MATRIX_X_Y	= 0*3*4+VECTOR3D.y
MATRIX_X_Z	= 0*3*4+VECTOR3D.z
MATRIX_Y_X	= 1*3*4+VECTOR3D.x
MATRIX_Y_Y	= 1*3*4+VECTOR3D.y
MATRIX_Y_Z	= 1*3*4+VECTOR3D.z
MATRIX_Z_X	= 2*3*4+VECTOR3D.x
MATRIX_Z_Y	= 2*3*4+VECTOR3D.y
MATRIX_Z_Z	= 2*3*4+VECTOR3D.z

.data

MATRIX struc
	_m	dd	9	dup(?)
MATRIX ends

VECTOR3D struc
	x	dd	?
	y	dd	?
	z	dd	?
VECTOR3D ends

HULLHEADER struc
	faces	db	?
HULLHEADER ends

VERTEX struc
	pos	VECTOR3D	?
	color	db		?
VERTEX ends

VERTEX_EX struc
	pos	VECTOR3D	?
	sx	dd		?
	sy	dd		?
	color32	dd		?
	u32	dd		?
	v32	dd		?
	inv_z	dd		?	; 1/z
	inv_u32	dd		?	; u/z
	inv_v32	dd		?	; v/z
VERTEX_EX ends

if COMPOVERSION
introname	db	TEXT_SLANT,1,'tubular',TEXT_LF,100,'vectors',TEXT_LF,128,TEXT_SLANT,0,TEXT_LF,0,'ASM',39,'2k 4k ',0
else
introname	db	TEXT_SLANT,1,'tubular',TEXT_LF,100,'vectors',TEXT_LF,128,TEXT_SLANT,0,TEXT_LF,0,'ASM',39,'2k 4k ',TEXT_LF,0,TEXT_RASTER,1,'hiteck^uv',0
endif

perspective	dd 216.0
aspectratio	dd 0.83
center_x	dd 160.0
center_y	dd 100.0
fshift		dd 65536.0
znear		dd 1.0

demoflags	db 0
current_hull	dw offset hulldata

vertices	dw 98
vertexdata:
; pool
dd -100.0	;0
dd -10.0
dd 80.0
db 50

dd 100.0	;1
dd -10.0
dd 80.0
db 50

dd 100.0	;2
dd -10.0
dd -80.0
db 50

dd -100.0	;3
dd -10.0
dd -80.0
db 50

dd -100.0	;4
dd 0.0
dd 80.0
db 0

dd 100.0	;5
dd 0.0
dd 80.0
db 0

dd 100.0	;6
dd 0.0
dd -80.0
db 0

dd -100.0	;7
dd 0.0
dd -80.0
db 0

dd -100.0	;8
dd 140.0
dd 80.0
db 0

dd 100.0	;9
dd 140.0
dd 80.0
db 0

dd 100.0	;10
dd 140.0
dd -80.0
db 0

dd -100.0	;11
dd 140.0
dd -80.0
db 0

dd -100.0	;12
dd 0.0
dd -90.0
db 0

dd -110.0	;13
dd 0.0
dd -90.0
db 0

dd -110.0	;14
dd 0.0
dd -80.0
db 0

dd -100.0	;15
dd 0.0
dd 90.0
db 0

dd -110.0	;16
dd 0.0
dd 90.0
db 0

dd -110.0	;17
dd 0.0
dd 80.0
db 0

dd -100.0	;18
dd 140.0
dd -90.0
db 0

dd -110.0	;19
dd 140.0
dd -90.0
db 0

dd -110.0	;20
dd 140.0
dd -80.0
db 0

dd -100.0	;21
dd 140.0
dd 90.0
db 0

dd -110.0	;22
dd 140.0
dd 90.0
db 0

dd -110.0	;23
dd 140.0
dd 80.0
db 0

; outer wall

dd 100.0	;24
dd 0.0
dd -300.0
db 200

dd -300.0	;25
dd 0.0
dd -300.0
db 200

dd -300.0	;26
dd 0.0
dd -80.0
db 0

dd -300.0	;27
dd 0.0
dd 80.0
db 0

dd -300.0	;28
dd 0.0
dd 300.0
db 128

dd -120.0	;29
dd 0.0
dd 300.0
db 200

dd -80.0	;30
dd 0.0
dd 340.0
db 200

dd 0.0		;31
dd 0.0
dd 340.0
db 0

dd 100.0	;32
dd 0.0
dd 340.0
db 200

; outer wall (top)

dd 100.0	;33
dd 100.0
dd -300.0
db 200

dd -300.0	;34
dd 100.0
dd -300.0
db 200

dd -300.0	;35
dd 100.0
dd -80.0
db 0

dd -300.0	;36
dd 100.0
dd 80.0
db 0

dd -300.0	;37
dd 100.0
dd 300.0
db 128

dd -120.0	;38
dd 140.0
dd 300.0
db 200

dd -80.0	;39
dd 140.0
dd 340.0
db 200

dd 0.0		;40
dd 140.0
dd 340.0
db 200

dd 100.0	;41
dd 140.0
dd 340.0
db 200

dd 0.0		;42
dd 80.0
dd 340.0
db 200

dd 100.0	;43
dd 80.0
dd 340.0
db 200

; sky
dd -100.0	;44
dd 300.0
dd 100000.0
db 0

dd 1000.0	;45
dd 0.0
dd 100000.0
db 150

dd -100.0	;46
dd 300.0
dd -100000.0
db 0

dd 1000.0	;47
dd 0.0
dd -100000.0
db 150

; ramp
dd -600.0	;48
dd 180.0
dd 60.0
db 255

dd -600.0	;49
dd 180.0
dd -60.0
db 255

dd -600.0	;50
dd 80.0
dd -60.0
db 255

dd -600.0	;51
dd 80.0
dd 60.0
db 255

; ground
dd -800.0	;52
dd -80.0
dd -100000.0
db 0	
      
dd -800.0	;53
dd -80.0
dd -100000.0
db 0

; beginning
dd -150.0	;54
dd 200.0
dd 200.0
db 255
      
dd 250.0	;55
dd 200.0
dd 200.0
db 0	

dd 250.0	;56
dd 200.0
dd -200.0
db 0	
      
dd -150.0	;57
dd 200.0
dd -200.0
db 0	

dd -150.0	;58
dd -200.0
dd 200.0
db 0	
      
dd  250.0	;59
dd -200.0
dd 200.0
db 0	

dd 250.0	;60
dd -200.0
dd -200.0
db 255
      
dd -150.0	;61
dd -200.0
dd -200.0
db 0

dd 0.0		;62
dd 100.0
dd 50.0
db 0

dd 100.0	;63
dd 100.0
dd 50.0
db 0

dd 100.0	;64
dd 100.0
dd -50.0
db 0

dd 0.0		;65
dd 100.0
dd -50.0
db 0

dd 0.0		;66
dd 0.0
dd 50.0
db 0	

dd 100.0	;67
dd 0.0
dd 50.0
db 0	

dd 100.0	;68
dd 0.0		   
dd -50.0
db 255

dd 0.0		;69
dd 0.0
dd -50.0
db 0

dd 2000.0	;70
dd 200.0
dd 200.0
db 255

dd 2000.0	;71
dd 200.0
dd -200.0
db 0	

dd 2000.0	;72
dd -200.0
dd 200.0
db 0	

dd 2000.0	;73
dd -200.0
dd -200.0
db 0	

dd -800.0	;74
dd 80.0
dd -400.0
db 255

dd -800.0	;75
dd 80.0
dd 400.0
db 255

dd -2000.0	;76
dd 300.0
dd 1000.0
db 0

dd -400.0	;77
dd 300.0
dd 1000.0
db 255

dd -400.0	;78
dd 300.0
dd -1000.0
db 255

dd -2000.0	;79
dd 300.0
dd -1000.0
db 0

dd -800.0	;80
dd -1000.0
dd 1000.0
db 255

dd -800.0	;81
dd -1000.0
dd -1000.0
db 255

dd 200.0	;82
dd 140.0
dd 800.0
db 0

dd 300.0	;83
dd 140.0
dd 700.0
db 0

dd 300.0	;84
dd 0.0
dd 700.0
db 0

dd 200.0	;85
dd 0.0
dd 800.0
db 0

dd 600.0	;86
dd 200.0
dd 800.0
db 64

dd 600.0	;87
dd 200.0
dd 700.0
db 64

dd 600.0	;88
dd 100.0
dd 800.0
db 64

dd 600.0	;89
dd 100.0
dd 700.0
db 64

; loppu?

dd 500.0	;90
dd 0.0
dd 1000.0
db 255

dd 900.0	;91
dd 0.0
dd 1000.0
db 255

dd 900.0	;92
dd 0.0
dd 600.0
db 255

dd 500.0	;93
dd 0.0
dd 600.0
db 255

dd 500.0	;94
dd 400.0
dd 1000.0
db 0

dd 900.0	;95
dd 400.0
dd 1000.0
db 0

dd 900.0	;96
dd 400.0
dd 600.0
db 0

dd 500.0	;97
dd 400.0
dd 600.0
db 0


;hulldata:
pool0:
db 10

db PLANE_XZ+COLOR2
db POLY_FLAG_NEW_TEXTURE+4
dw offset texture1
db 0
db 1
db 2
db 3

db PLANE_XY+COLOR3
db POLY_FLAG_NEW_TEXTURE+4
dw offset texture0
db 0
db 4
db 5
db 1

db PLANE_XY+COLOR3
db 4
db 7
db 3
db 2
db 6

db PLANE_YZ+COLOR3
db 4
db 3
db 7
db 4
db 0

db PLANE_YZ+COLOR3
db 4
db 5
db 6
db 2
db 1

db PLANE_XZ+COLOR3
db 4
db 11
db 10
db 9
db 8

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset column_gap
db 11
db 8
db 4
db 7

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall0
db 10
db 11
db 7
db 6

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall4
db 4
db 8
db 9
db 5

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset sky
db 9
db 10
db 6
db 5

column_gap:
db 6

db PLANE_XY+COLOR3
db 4
db 14
db 7
db 11
db 20

db PLANE_XY+COLOR3
db 4
db 4
db 17
db 23
db 8

db PLANE_XZ+COLOR3
db 4
db 7
db 14
db 17
db 4

db PLANE_XZ+COLOR3
db 4
db 20
db 11
db 8
db 23

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset pool0
db 8
db 11
db 7
db 4

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall2
db 14
db 20
db 23
db 17

hall0:
db 6

db PLANE_XZ+COLOR3
db 4
db 7
db 6
db 24
db 12

db PLANE_YZ+COLOR3
db 4
db 10
db 33
db 24
db 6

db PLANE_XZ+COLOR3
db 4
db 33
db 10
db 11
db 18

db PLANE_YZ+COLOR3
db 4
db 12
db 18
db 11
db 7

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset pool0
db 11
db 10
db 6
db 7

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall1
db 33
db 18
db 12
db 24

hall1:
db 6

db PLANE_XZ+COLOR3
db 4
db 13
db 12
db 24
db 25

db PLANE_XY+COLOR3
db 4
db 33
db 34
db 25
db 24

db PLANE_XY+COLOR3
db 4
db 19
db 18
db 12
db 13

db PLANE_XZ+COLOR3
db 4
db 33
db 18
db 19
db 34

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall0
db 18
db 33
db 24
db 12

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall2
db 34
db 19
db 13
db 25

hall2:
db 12

db PLANE_YZ+COLOR3
db 4
db 25
db 34
db 35
db 26

db PLANE_YZ+COLOR3
db 4
db 27
db 36
db 37
db 28

db PLANE_XZ+COLOR3
db 9
db 13
db 25
db 26
db 27
db 28
db 29
db 16
db 17
db 14

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall1
db 19
db 34
db 25
db 13

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset column_gap
db 20
db 14
db 17
db 23

db PLANE_XZ+COLOR3
db 8
db 22
db 37
db 36
db 35
db 34
db 19
db 20
db 23

db PLANE_XZ+COLOR3
db 3
db 22
db 38
db 37

db PLANE_YZ+COLOR3
db 4
db 20
db 19
db 13
db 14

db PLANE_YZ+COLOR3
db 4
db 22
db 23
db 17
db 16

db PLANE_XY+COLOR3
db 4
db 28
db 37
db 38
db 29

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall3
db 38
db 22
db 16
db 29

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset ramp
db 26
db 35
db 36
db 27

hall3:
db 7

db PLANE_XZ+COLOR3
db 5
db 16
db 29
db 30
db 31
db 15

db PLANE_XZ+COLOR3
db 5
db 21
db 40
db 39
db 38
db 22

db PLANE_XY+COLOR3
db 4
db 29
db 38
db 39
db 30

db PLANE_XY+COLOR3
db 4
db 30
db 39
db 40
db 31

db PLANE_XY+COLOR3
db 4
db 21
db 22
db 16
db 15

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall2
db 22
db 38
db 29
db 16

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall4
db 40
db 21
db 15
db 31

hall4:
db 8

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset tunnel2
db 42
db 43
db 32
db 31

db PLANE_XZ+COLOR3
db 5
db 4
db 15
db 31
db 32
db 5

db PLANE_XZ+COLOR3
db 5
db 8
db 9
db 41
db 40
db 21

db PLANE_XY+COLOR3
db 4
db 40
db 41
db 43
db 42

db PLANE_YZ+COLOR3
db 4
db 4
db 8
db 21
db 15

db PLANE_YZ+COLOR3
db 4
db 41
db 9
db 5
db 32

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset pool0
db 8
db 4
db 5
db 9

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall3
db 21
db 40
db 31
db 15

sky:
db 2

db PLANE_XZ+COLOR0
db 4
db 46
db 47
db 45
db 44

db PLANE_XZ+COLOR1
db 4
db 53
db 52
db 45
db 47

ramp:
db 7

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall2
db 35
db 26
db 27
db 36


db PLANE_XZ+COLOR3
db 4
db 35
db 36
db 48
db 49

db PLANE_XZ+COLOR3
db 4
db 27
db 26
db 50
db 51

db PLANE_XY+COLOR3
db 4
db 48
db 36
db 27
db 51

db PLANE_XY+COLOR3
db 4
db 35
db 49
db 50
db 26

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset hall2
db 35
db 26
db 27
db 36

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset canyon
db 49
db 48
db 51
db 50

;hulldata:
begincube1:
db 6

db PLANE_YZ+COLOR0
db POLY_FLAG_NEW_TEXTURE+4
dw texture0
db 55
db 56
db 60
db 59

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube2
db 63
db 55
db 59
db 67

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset pool0
db 64
db 63
db 67
db 68

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube4
db 60
db 56
db 64
db 68

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube5
db 68
db 67
db 59
db 60

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube6
db 63
db 64
db 56
db 55

begincube2:
db 6

db PLANE_XY+COLOR0
db POLY_FLAG_NEW_TEXTURE+4
dw texture0
db 54
db 55
db 59
db 58

db PLANE_XY+COLOR2
db POLY_FLAG_NEW_TEXTURE+4
dw texture2
db 63
db 62
db 66
db 67

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+POLY_FLAG_NEW_TEXTURE+4
dw texture0
dw offset begincube1
db 63
db 67
db 59
db 55

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube3
db 62
db 54
db 58
db 66

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube5
db 67
db 66
db 58
db 59

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube6
db 55
db 54
db 62
db 63

begincube3:
db 6

db PLANE_YZ+COLOR0
db POLY_FLAG_NEW_TEXTURE+4
dw texture0
db 57
db 54
db 58
db 61

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube2
db 54
db 62
db 66
db 58

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube4
db 65
db 57
db 61
db 69

db PLANE_XY+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube5
db 66
db 69
db 61
db 58

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube6
db 54
db 57
db 65
db 62

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset tunnel
db 62
db 65
db 69
db 66

begincube4:
db 6

db PLANE_XY+COLOR0
db POLY_FLAG_NEW_TEXTURE+4
dw texture0
db 56
db 57
db 61
db 60

db PLANE_XY+COLOR2
db POLY_FLAG_NEW_TEXTURE+4
dw texture2
db 65
db 64
db 68
db 69

db PLANE_XY+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube3
db 57
db 65
db 69
db 61

db PLANE_XY+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube1
db 56
db 60
db 68
db 64

db PLANE_XY+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube5
db 69
db 68
db 60
db 61

db PLANE_YZ+COLOR2
db POLY_FLAG_NEW_TEXTURE+POLY_FLAG_PORTAL+4
dw texture0
dw offset begincube6
db 57
db 56
db 64
db 65

begincube5:
db 6

db PLANE_XZ+COLOR0
db POLY_FLAG_NEW_TEXTURE+4
dw texture0
db 61
db 58
db 59
db 60

db PLANE_XZ+COLOR2
db POLY_FLAG_NEW_TEXTURE+4
dw texture2
db 69
db 68
db 67
db 66

db PLANE_YZ+COLOR2
db POLY_FLAG_NEW_TEXTURE+POLY_FLAG_PORTAL+4
dw texture0
dw offset begincube1
db 67
db 68
db 60
db 59

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube2
db 66
db 67
db 59
db 58

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube3
db 69
db 66
db 58
db 61

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube4
db 68
db 69
db 61
db 60

begincube6:
db 6

db PLANE_XZ+COLOR0
db POLY_FLAG_NEW_TEXTURE+4
dw texture0
db 54
db 57
db 56
db 55

db PLANE_XZ+COLOR2
db POLY_FLAG_NEW_TEXTURE+4
dw texture2
db 62
db 63
db 64
db 65

db PLANE_YZ+COLOR2
db POLY_FLAG_NEW_TEXTURE+POLY_FLAG_PORTAL+4
dw texture0
dw offset begincube1
db 55
db 56
db 64
db 63

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube2
db 54
db 55
db 63
db 62

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube3
db 57
db 54
db 62
db 65

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube4
db 56
db 57
db 65
db 64

; beginning
hulldata:
tunnel:
db 10

db PLANE_XZ+COLOR1
db POLY_FLAG_NEW_TEXTURE+4
dw texture2
db 55
db 56
db 71
db 70

db PLANE_XZ+COLOR1
db POLY_FLAG_NEW_TEXTURE+4
dw texture2
db 59
db 72
db 73
db 60

db PLANE_XY+COLOR1
db 4
db 55
db 70
db 72
db 59

db PLANE_XY+COLOR1
db 4
db 71
db 56
db 60
db 73

db PLANE_YZ+COLOR1
db 4
db 70
db 71
db 73
db 72

db PLANE_XZ+COLOR1
db 4
db 69
db 66
db 59
db 60

db PLANE_XY+COLOR1
db 4
db 62
db 55
db 59
db 66

db PLANE_XZ+COLOR1
db 4
db 62
db 65
db 56
db 55

db PLANE_XY+COLOR1
db 4
db 56
db 65
db 69
db 60

db PLANE_YZ+COLOR2
db POLY_FLAG_PORTAL+4
dw offset begincube3
db 65
db 62
db 66
db 69

canyon:
db 6

db PLANE_XZ+COLOR0
db 4
db 77
db 76
db 79
db 78

db PLANE_XY+COLOR1
db 3
db 76
db 77
db 80

db PLANE_XY+COLOR1
db 3
db 78
db 79
db 81

db PLANE_YZ+COLOR1
db 4
db 79
db 76
db 80
db 81

db PLANE_YZ+COLOR1
db 4
db 77
db 78
db 81
db 80

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset ramp
db 48
db 49
db 50
db 51

tunnel2:
db 5

db PLANE_XY+COLOR3
db 4
db 42
db 82
db 85
db 31

db PLANE_XY+COLOR3
db 4
db 83
db 43
db 32
db 84

db PLANE_XZ+COLOR3
db 4
db 85
db 84
db 32
db 31

db PLANE_XZ+COLOR3
db 4
db 83
db 82
db 42
db 43

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset tunnel3
db 82
db 83
db 84
db 85

tunnel3:
db 5

db PLANE_XY+COLOR3
db 4
db 82
db 86
db 88
db 85

db PLANE_XY+COLOR3
db 4
db 87
db 83
db 84
db 89

db PLANE_XZ+COLOR3
db 4
db 85
db 88
db 89
db 84

db PLANE_XZ+COLOR3
db 4
db 86
db 82
db 83
db 87

db PLANE_YZ+COLOR3
db POLY_FLAG_PORTAL+4
dw offset endcube
db 86
db 87
db 89
db 88

endcube:
db 4

db PLANE_XZ+COLOR2
db 4
db 94
db 97
db 96
db 95

db PLANE_XY+COLOR2
db 4
db 92
db 96
db 97
db 93

db PLANE_YZ+COLOR2
db 4
db 94
db 95
db 91
db 90

db PLANE_YZ+COLOR2
db 4
db 95
db 96
db 92
db 91

camera		VECTOR3D	?
camera_target	VECTOR3D	?
camera_roll	dd		?

camera_speed	dd	1.0
camera_counter	dw	500
camera_ip	dw	offset keyframes

keyframes:
dw	500	; tick delta
dw	1990	; x
dw	50	; y
dw	50	; z
dw	2000	; x
dw	50	; y
dw	50	; z
dw	4	; w

dw	2000	; tick delta
dw	1900	; x
dw	0	; y
dw	0	; z
dw	2000	; x
dw	0	; y
dw	0	; z
dw	0	; w

dw	1000	; tick delta
dw	1000	; x
dw	-100	; y
dw	0	; z
dw	800	; x
dw	50	; y
dw	100	; z
dw	3	; w

; pois tunnelista

dw	500	; tick delta
dw	-190	; x
dw	50	; y
dw	0	; z
dw	0	; x
dw	50	; y
dw	0	; z
dw	0	; w

dw	500	; tick delta
dw	-100	; x
dw	190	; y
dw	190	; z
dw	0	; x
dw	50	; y
dw	0	; z
dw	1	; w

dw	500	; tick delta
dw	-50	; x
dw	190	; y
dw	-190	; z
dw	0	; x
dw	50	; y
dw	0	; z
dw	-1	; w

dw	500	; tick delta
dw	-50	; x
dw	-100	; y
dw	190	; z
dw	0	; x
dw	50	; y
dw	0	; z
dw	0	; w

; laatikon toinen puoli

dw	400	; tick delta
dw	190	; x
dw	-25	; y
dw	-100	; z
dw	0	; x
dw	50	; y
dw	0	; z
dw	0	; w

dw	400	; tick delta
dw	190	; x
dw	190	; y
dw	125	; z
dw	0	; x
dw	50	; y
dw	0	; z
dw	-1	; w

dw	800	; tick delta
dw	190	; x
dw	75	; y
dw	25	; z
dw	0	; x
dw	50	; y
dw	0	; z
dw	0	; w

; hallissa
dw	1000	; tick delta
dw	-290	; x
dw	75	; y
dw	-25	; z
dw	-50	; x
dw	50	; y
dw	-100	; z
dw	1	; w

dw	1000	; tick delta
dw	-190	; x
dw	10	; y
dw	-290 	; z
dw	0	; x
dw	0	; y
dw	0	; z
dw	0	; w

dw	1500	; tick delta
dw	90	; x
dw	90	; y
dw	-290 	; z
dw	0	; x
dw	0	; y
dw	0	; z
dw	0	; w

dw	1000	; tick delta
dw	-290	; x
dw	50	; y
dw	45 	; z
dw	-100	; x
dw	100	; y
dw	0	; z
dw	0	; w

dw	1500	; tick delta
dw	-290	; x
dw	10	; y
dw	45 	; z
dw	-400	; x
dw	100	; y
dw	0	; z
dw	0	; w

; tunnelissa
dw	500	; tick delta
dw	-700	; x
dw	225	; y
dw	-45 	; z
dw	-1000	; x
dw	200	; y
dw	0	; z
dw	0	; w

dw	1000	; tick delta
dw	-700	; x
dw	225	; y
dw	-45 	; z
dw	-1000	; x
dw	0	; y
dw	-200	; z
dw	6	; w

;keyframes:
; takaisin hallissa
dw	1000	; tick delta
dw	-290	; x
dw	50	; y
dw	45 	; z
dw	0	; x
dw	0	; y
dw	0	; z
dw	0	; w

dw	800	; tick delta
dw	-210	; x
dw	10	; y
dw	310 	; z
dw	0	; x
dw	0	; y
dw	0	; z
dw	0	; w

dw	1000	; tick delta
dw	0	; x
dw	90	; y
dw	-210 	; z
dw	0	; x
dw	0	; y
dw	0	; z
dw	0	; w

dw	1000	; tick delta
dw	0	; x
dw	50	; y
dw	200 	; z
dw	0	; x
dw	0	; y
dw	750	; z
dw	0	; w

; tunnel2
dw	500	; tick delta
dw	300	; x
dw	50	; y
dw	750 	; z
dw	500	; x
dw	80	; y
dw	750	; z
dw	1	; w

; tunnel3 & endcube
dw	KEYFRAME_TEXT+1500	; tick delta
;dw	1500	; tick delta
dw	700	; x
dw	150	; y
dw	750 	; z
dw	800	; x
dw	180	; y
dw	750	; z
dw	0	; w

dw	KEYFRAME_END+8000	; tick delta
dw	800	; x
dw	10	; y
dw	800 	; z
dw	800	; x
dw	180	; y
dw	750	; z
dw	3	; w

dw	16383	; tick delta
dw	800	; x
dw	10	; y
dw	800 	; z
dw	700	; x
dw	80	; y
dw	850	; z
dw	0	; w

planedata:	; normalized normals!
dd 0.0		; near plane
dd 0.0
dd 1.0

; project_dist = -134.000000, project_scale = 86.000000

; plane 0:
dd      0.803617
dd      0.000000
dd      0.595147
; plane 1:
dd      -0.803617
dd      0.000000
dd      0.595147
; plane 2:
dd      0.000000
dd      0.874206
dd      0.485555
; plane 3:
dd      0.000000
dd      -0.874206
dd      0.485555

planearray	VECTOR3D 128 dup(?)

; unitialized variables

planeptr	dw ?
fbufferseg	dw ?
oldtimer	dd ?
tick		dd ?
retfloat	dd ?
retvec		VECTOR3D ?
;camera_delta	dd 7 dup(0)
;camera_waypoint	dd 7 dup(0)

camera_matrix	MATRIX	?
camera_roll_cos	dd	?
camera_roll_sin	dd	?

romfont 	dd	?

texture0	dw	?
texture1	dw	?
texture2	dw	?

.code
org 100h
start:
	jmp main

;----------------------------------------------------------------------------
; RANDOM
;
; Returns a pseudorandom number between in the range of dx-cx in ax.
;
;----------------------------------------------------------------------------
randseed dw 31337
random:
	push bx
	push cx
	push dx

	mov ax, randseed
	mov bx, 1021
	mul bx      
	inc ax      
	mov bx, 32768
	div bx	    
	mov randseed, dx
	mov ax, dx      
	xor dx, dx      
	mov bx, dx
	cmp bx, cx      
	jg  swap
resume:
	inc cx        
	sub cx, bx    
	div cx        
	mov ax, bx    
	add ax, dx     
	jmp randdone
swap:
	xchg bx, cx
	jmp resume

randdone:
	pop dx
	pop cx
	pop bx
ret ; random

;----------------------------------------------------------------------------
;	RENDER_TEXT
;
;	Prints text into the virtual frame buffer.
;
; al:		text color
; ds:si:	pointer to a null terminated string.
; lfnumber:	lines to draw
;
;----------------------------------------------------------------------------
slant dw 0
raster db 0
lfnumber db 16
.data
lfcount db ?
.code
render_text:
	push ds
	push ax
	push bx
	push cx
	push dx

	mov cx, word ptr romfont+2

	mov bp, ds

	mov dl, al
	shl edx, 8
	mov dl, al
	shl edx, 8
	mov dl, al
	shl edx, 8
	mov dl, al

	mov di, 16*320+32

	mov raster, 0
	mov slant, 0
	mov lfcount, 0

cloop:
	xor bx, bx

	xor eax, eax
	mov al, byte ptr ds:[si]
	test al, 128
	jnz controlchar

	test al, al
	jz pois

	add bx, ax
	shl bx, 4

	add bx, cx

	mov ah, 16

fyloop:
	mov es, word ptr romfont
	mov al, byte ptr es:[bx]
	mov es, fbufferseg

	test al, 128
	jz f_no1
	or dword ptr es:[di], edx
	cmp raster, 0
	jnz f_no1
	or dword ptr es:[di+320], edx
f_no1:
	test al, 64
	jz f_no2
	or dword ptr es:[di+4], edx
	cmp raster, 0
	jnz f_no2
	or dword ptr es:[di+4+320], edx
f_no2:
	test al, 32
	jz f_no3
	or dword ptr es:[di+8], edx
	cmp raster, 0
	jnz f_no3
	or dword ptr es:[di+8+320], edx
f_no3:					 
	test al, 16
	jz f_no4
	or dword ptr es:[di+12], edx
	cmp raster, 0
	jnz f_no4
	or dword ptr es:[di+12+320], edx
f_no4:
	test al, 8
	jz f_no5
	or dword ptr es:[di+16], edx
	cmp raster, 0
	jnz f_no5
	or dword ptr es:[di+16+320], edx
f_no5:
	test al, 4
	jz f_no6
	or dword ptr es:[di+20], edx
	cmp raster, 0
	jnz f_no6
	or dword ptr es:[di+20+320], edx
f_no6:
	test al, 2
	jz f_no7
	or dword ptr es:[di+24], edx
	cmp raster, 0
	jnz f_no7
	or dword ptr es:[di+24+320], edx
f_no7:
	test al, 1
	jz f_no8
	or dword ptr es:[di+28], edx
	cmp raster, 0
	jnz f_no8
	or dword ptr es:[di+28+320], edx
f_no8:

	add di, 640
	sub di, slant
	inc bx
	dec ah
	jnz fyloop

	sub di, (639*16)-8
	mov ax, slant
	shl ax, 4
	add ax, 8
	add di, ax

	inc si	
	jmp cloop

controlchar:
	cmp al, TEXT_LF
	jnz no_lf

	inc lfcount
	mov al, lfnumber
	cmp lfcount, al
	ja pois

	inc si
	mov al, byte ptr ds:[si]
	shl ax, 1
	add di, 320*32
	sub di, ax
no_lf:
	cmp al, TEXT_SLANT
	jnz no_slant
	inc si
	mov al, byte ptr ds:[si]
	mov slant, ax
no_slant:
	cmp al, TEXT_COLOR
	jnz no_color
	inc si
	mov al, byte ptr ds:[si]
	mov dl, al
	shl edx, 8
	mov dl, al
	shl edx, 8
	mov dl, al
	shl edx, 8
	mov dl, al
no_color:
	cmp al, TEXT_RASTER
	jnz no_raster
	inc si
	mov al, byte ptr ds:[si]
	mov raster, al
no_raster:
	inc si
	jmp cloop

pois:
	pop dx
	pop cx
	pop bx
	pop ax
	pop ds
ret ; render_text


;----------------------------------------------------------------------------
;	HOOKTIMER
;
; Hooks the int8 vector.
;
;----------------------------------------------------------------------------
hooktimer:
	cli
	mov ax, 3508h
	int INT_DOS
	mov word ptr oldtimer, es
	mov word ptr oldtimer+2, bx
	
	mov dx, offset kernel
	
	mov ax, 2000h

	mov tick, 0

	mov al,36h
	out 43h,al
	mov al,0
	out 40h,al
	mov al,ah
	out 40h,al
	mov ax, 2508h
	int INT_DOS
	sti
ret ; hooktimer

;----------------------------------------------------------------------------
; UNHOOKTIMER
;
; Restores the int8 vector.
;
;----------------------------------------------------------------------------
unhooktimer:
	push ds
	push ax
	cli
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov dx, word ptr es:oldtimer+2
	mov ds, word ptr es:oldtimer
	
	mov ax, 2508h
	int 21h
	sti
	pop ax
	pop ds
ret ; unhooktimer

;----------------------------------------------------------------------------
;	DOT
;
;	Returns the dot product of two vectors in retfloat.
;
;	bx:		pointer to vector 1
;	di:		pointer to vector 2
;
;	double dot(v3 v1, v3 v2)
;		return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
;
;	Trashes:
; 	retfloat
;----------------------------------------------------------------------------
;dot:
;	fld [bx + VECTOR3D.x]
;	fmul [di + VECTOR3D.x]
;	fld [bx + VECTOR3D.y]
;	fmul [di + VECTOR3D.y]
;	fld [bx + VECTOR3D.z]
;	fmul [di + VECTOR3D.z]
;
;	faddp										; (z2*z1)+(y2*y1):(x2*x1)
;	faddp										; (z2*z1)+(y2*y1)+(x2*x1)
;
;	fstp retfloat
;ret

;----------------------------------------------------------------------------
; COMBINE
;
; Adds scaled vector A into vector B and returns the result in retvec.
;
; retfloat:	magnitute (floating point)
;	bx: 	pointer to vector A
; di: 	pointer to vector B
;
;	v3 combine(v3 v1, double a, v3 v2)
;		v2.x += a * v1.x;
;		v2.y += a * v1.y;
;		v2.z += a * v1.z;
;		return v2;
;
; Trashes:
; 	retvec
;----------------------------------------------------------------------------
;combine:
;	fld retfloat
;	fld [bx + VECTOR3D.x]
;	fmul st(0),st(1)
;	fadd [di + VECTOR3D.x]
;	fstp retvec.x
;
;	fld [bx + VECTOR3D.y]
;	fmul st(0),st(1)
;	fadd [di + VECTOR3D.y]
;	fstp retvec.y
;
;	fld [bx + VECTOR3D.z]
;	fmul st(0),st(1)
;	fadd [di + VECTOR3D.z]
;	fstp retvec.z
;	fstp st(0)
;ret

;----------------------------------------------------------------------------
; VECTADD
;
; Adds scaled vector A into vector B and returns the result in retvec.
;
;	bx: 	pointer to vector A
; di: 	pointer to vector B
;
; Trashes:
; 	retvec
;----------------------------------------------------------------------------
;vectadd:
;	fld [bx + VECTOR3D.x]
;	fadd [di + VECTOR3D.x]
;	fstp retvec.x
;
;	fld [bx + VECTOR3D.y]
;	fadd [di + VECTOR3D.y]
;	fstp retvec.y
;
;	fld [bx + VECTOR3D.z]
;	fadd [di + VECTOR3D.z]
;	fstp retvec.z
;ret

;----------------------------------------------------------------------------
; VECTSUB
;
; Subtracts scaled vector B from vector A and returns the result in retvec.
;
;	bx: 	pointer to vector A
; di: 	pointer to vector B
;
; Trashes:
; 	retvec
;----------------------------------------------------------------------------
;vectsub:
;	fld [bx + VECTOR3D.x]
;	fsub [di + VECTOR3D.x]
;	fstp retvec.x
;
;	fld [bx + VECTOR3D.y]
;	fsub [di + VECTOR3D.y]
;	fstp retvec.y
;
;	fld [bx + VECTOR3D.z]
;	fsub [di + VECTOR3D.z]
;	fstp retvec.z
;ret


;----------------------------------------------------------------------------
;	NORMALIZE
;
; Normalizes the vector pointed to by bx.
;
;----------------------------------------------------------------------------
normalize:
	fld [bx + VECTOR3D.x]
	fmul st(0),st(0)
	fld [bx + VECTOR3D.y]
	fmul st(0),st(0)
	fld [bx + VECTOR3D.z]
	fmul st(0),st(0)

	faddp
	faddp

	fsqrt

	fld1
	fdivrp

	fld [bx + VECTOR3D.x]
	fmul st(0), st(1)
	fstp [bx + VECTOR3D.x]
	fld [bx + VECTOR3D.y]
	fmul st(0), st(1)
	fstp [bx + VECTOR3D.y]
	fld [bx + VECTOR3D.z]
	fmul st(0), st(1)
	fstp [bx + VECTOR3D.z]

	fstp st(0)
ret ; normalize

;----------------------------------------------------------------------------
;	CROSS
;
; Calculates the cross product of the two given vectors.
;
; IN:	si:	pointer to first vector  (A)
;	di:	pointer to second vector (B)
;	bx:	pointer to output vector
;
;	(Ay*Bz-By*Az), (Az*Bx-Bz*Ax), (Ax*By-Bx*Ay)
;
;----------------------------------------------------------------------------
cross:
	fld [si + VECTOR3D.y]
	fmul [di + VECTOR3D.z]
	fld [si + VECTOR3D.z]
	fmul [di + VECTOR3D.y]
	fsubp st(1), st(0)
	fstp dword ptr [bx + VECTOR3D.x]

	fld [si + VECTOR3D.z]
	fmul [di + VECTOR3D.x]
	fld [si + VECTOR3D.x]
	fmul [di + VECTOR3D.z]
	fsubp st(1), st(0)
	fstp dword ptr [bx + VECTOR3D.y]

	fld [si + VECTOR3D.x]
	fmul [di + VECTOR3D.y]
	fld [si + VECTOR3D.y]
	fmul [di + VECTOR3D.x]
	fsubp st(1), st(0)
	fstp dword ptr [bx + VECTOR3D.z]
ret ; cross


;----------------------------------------------------------------------------
;	VECT_MUL_MAT_INVERSE
;
; Multiplies a vector by the inverse of a rotation matrix.
;
; IN:	bx:	pointer to matrix
;	di:	pointer to output vector
;	st(0)	vector x
;	st(1)	vector y
;	st(2)	vector z
;
;	X = X0*a + Y0*e + Z0*i + center_x
;	Y = X0*b + Y0*f + Z0*j + center_y
;	Z = X0*c + Y0*g + Z0*k + center_z
;
;----------------------------------------------------------------------------
vect_mul_mat_inverse:
	fld dword ptr [bx + MATRIX_X_X]
	fmul st(0), st(1)
	fld dword ptr [bx + MATRIX_X_Y]
	fmul st(0), st(3)
	faddp
	fld dword ptr [bx + MATRIX_X_Z]
	fmul st(0), st(4)
	faddp
	fstp dword ptr [di + VECTOR3D.x]

	fld dword ptr [bx + MATRIX_Y_X]
	fmul st(0), st(1)
	fld dword ptr [bx + MATRIX_Y_Y]
	fmul st(0), st(3)
	faddp
	fld dword ptr [bx + MATRIX_Y_Z]
	fmul st(0), st(4)
	faddp
	fstp dword ptr [di + VECTOR3D.y]

	fld dword ptr [bx + MATRIX_Z_X]
	fmul st(0), st(1)
	fld dword ptr [bx + MATRIX_Z_Y]
	fmul st(0), st(3)
	faddp
	fld dword ptr [bx + MATRIX_Z_Z]
	fmul st(0), st(4)
	faddp
	fstp dword ptr [di + VECTOR3D.z]

	fstp st(0)
	fstp st(0)
	fstp st(0)
ret ; vect_mul_mat_inverse

;----------------------------------------------------------------------------
;	SETPALETTE
;
; Guess.
;
; Regs destroyed.
;
;----------------------------------------------------------------------------
setpalette:
if 1
	mov bp, 03c8h
	mov bx, 03c9h
	mov cx, 64
	xor ax, ax

palloop:
	mov dx, bp
	out dx, al
	mov dx, bx
	out dx, al
	xchg al, ah
	out dx, al
	out dx, al
	xchg al, ah

	mov dx, bp
	add al, 64
	out dx, al
	mov dx, bx
	out dx, al
	out dx, al
	xchg al, ah
	out dx, al
	xchg al, ah

	mov dx, bp
	add al, 64
	out dx, al
	mov dx, bx
;	xchg al, ah
	push ax
;	shl al, 1
;	add al, 8
	out dx, al
;	xchg al, ah
	out dx, al
;	shr al, 1
;	xchg al, ah
	mov al, 255
	out dx, al
;	xchg al, ah
	pop ax

	mov dx, bp
	add al, 64
	out dx, al
	mov dx, bx
	out dx, al
	out dx, al
	out dx, al
	sub al, 191
	loop palloop
endif

if 0
	mov dx, 03c8h
	mov al, 0
	out dx, al
	mov bx, 64
	mov dx, 03c9h

palloop:
	mov cx, 12
palloop_inner:
	out dx, al
	loop palloop_inner

;	inc al
	add al, 4
	dec bx
	jnz palloop
endif
ret ; setpalette


;----------------------------------------------------------------------------
;	FLIP
;
;	Flips the virtual frame buffer to the VGA frame buffer.
;
;----------------------------------------------------------------------------
flip:
	push es
	push ds

	mov ax, fbufferseg
	mov ds, ax

	mov ax, PTR_VIDEO
	mov es, ax

	xor si, si
	xor di, di
	mov ecx, 64000/4
if 1
	rep movsd
else
flip_loop:
	mov eax, dword ptr es:[si]
	mov ebx, dword ptr ds:[di]
	shr eax, 1
	shr ebx, 1
	and eax, 01111111011111110111111101111111b
	and ebx, 01111111011111110111111101111111b
	add eax, ebx
	mov dword ptr es:[di], eax
	add di, 4
	add si, 4
	dec ecx
	jnz flip_loop
endif
	pop ds
	pop es
ret ; flip

;----------------------------------------------------------------------------
;	CLEAR
;
;	Clears the virtual frame buffer
;
;----------------------------------------------------------------------------
clear:
	push ds
	push es
	mov ax, fbufferseg
	mov es, ax

	xor di, di
	mov ecx, 64000/4
	xor eax, eax
;	mov eax, 0ffffffffh

	rep stosd
	pop es
	pop ds
ret ; clear

;----------------------------------------------------------------------------
;	FUSS
;
;	Renders pseudorandom noise.
;
;----------------------------------------------------------------------------
;fuss_i dw 20
;fuss:
;	push es
;	mov ax, fbufferseg
;	mov es, ax
;	xor di, di
;
;	mov bx, 64000
;fussloop:
;	mov cx, fuss_i
;	mov dx, 0
;	call random
;	add byte ptr es:[di], al
;	jnc fuss_ok
;	mov byte ptr es:[di], 255
;fuss_ok:
;	inc di
;
;	dec bx
;	jnz fussloop
;
;	pop es
;ret ; fuss

;----------------------------------------------------------------------------
;	RENDER_SCANLINE
;
;	Renders a horizontal scanline. No clipping is performed!
;
;	eax	x1	(fixed point)
;	edx	x2	(fixed point)
;	st(0)	z1
;	st(1)	z2		 
;	es:	buffer segment
;	ds:	texture segment
;
;----------------------------------------------------------------------------
.data
current_colorbase	db	?
scan_tmp	dd	6	dup(?)
scan_c1		dd	?
scan_c2		dd	?
scan_c_d	dd	?
scan_invz	dd	?
scan_invz_d	dd	?
scan_u1		dd	?
scan_v1		dd	?
scan_u2		dd	?
scan_v2		dd	?
scan_u_d	dd	?
scan_v_d	dd	?
scan_y		dw	?
.code
f8	dd 8.0
fhalf	dd 0.5
render_scanline:
	push si
	push di
	push bx
	push ecx
	push eax
	push edx

	fld st(1)
	fld st(1)

	shr eax, 16
	shr edx, 16

	cmp eax, edx
	ja x1_left

	; no swap
	mov ecx, edx
	mov ebx, eax
	sub ecx, eax
	fxch
	mov eax, dword ptr [c1]
	mov edx, dword ptr [c2]
	mov scan_c1, eax
	mov scan_c2, edx
	mov eax, dword ptr [u1]
	mov edx, dword ptr [v1]
	mov scan_u1, eax
	mov scan_v1, edx
	mov eax, dword ptr [u2]
	mov edx, dword ptr [v2]
	mov scan_u2, eax
	mov scan_v2, edx

	jmp short x1_right
x1_left:
	; swap
	mov ecx, eax
	mov ebx, edx
	sub ecx, edx
	mov eax, dword ptr [c2]
	mov edx, dword ptr [c1]
	mov scan_c1, eax
	mov scan_c2, edx
	mov eax, dword ptr [u2]
	mov edx, dword ptr [v2]
	mov scan_u1, eax
	mov scan_v1, edx
	mov eax, dword ptr [u1]
	mov edx, dword ptr [v1]
	mov scan_u2, eax
	mov scan_v2, edx
x1_right:
	add bx, scan_y
	mov di, bx

	inc cx
	jz invalid_scanline
	mov scan_tmp, ecx

	; FPU stack: z_right, z_left, ...

	fld st(1)
	fsubp st(1), st(0)
	fidiv scan_tmp
	fmul f8
	fxch

	; FPU stack: z_left, z_delta, ...

	fld scan_u2
	fsub scan_u1
	fidiv scan_tmp
	fmul f8
	fstp scan_u_d

	fld scan_v2
	fsub scan_v1
	fidiv scan_tmp
	fmul f8
	fstp scan_v_d

	fld scan_c2
	fsub scan_c1
	fidiv scan_tmp
	fmul f8
	fstp scan_c_d

;	mov dword ptr [scan_u], eax
;	mov dword ptr [scan_v], edx
;	fld scan_u
;	pop eax
;	sub eax, dword ptr [scan_u]
;	cdq
;	idiv ecx
;	mov ebx, eax

;	pop eax
;	sub eax, dword ptr [scan_v]
;	cdq
;	idiv ecx
;	mov edx, eax

	fld st(0)
	fld1
	fdivrp

	fld st(0)
	fmul scan_v1
	fistp dword ptr [scan_tmp]

	fmul scan_u1		  
	fistp dword ptr [scan_tmp+4]

	fld scan_c1
	fistp [scan_tmp+4+8+4]

scanline_inner:
	fadd st(0), st(1)
	fld scan_u1
	fadd scan_u_d
	fstp scan_u1

	fld scan_v1
	fadd scan_v_d
	fstp scan_v1

	fld scan_c1
	fadd scan_c_d
	fstp scan_c1

	fld st(0)
	fld1
	fdivrp

	fld st(0)
	fmul scan_v1
	fistp dword ptr [scan_tmp+8]

	fmul scan_u1
	fistp dword ptr [scan_tmp+4+8]

	fld scan_c1
	fistp [scan_tmp+4+8+4+4]

	mov esi, dword ptr [scan_tmp+4+8+4+4]
	mov eax, dword ptr [scan_tmp+8]
	mov ebp, dword ptr [scan_tmp+4+8]
	sub eax, dword ptr [scan_tmp]
	sub ebp, dword ptr [scan_tmp+4]
	sub esi, dword ptr [scan_tmp+4+8+4]
	shr eax, 3
	shr ebp, 3
	shr esi, 3

if 1
	mov dx, 8
	test cx, 01111111111111000b
	jnz scanline_inner2
	mov dx, cx
	test dx, dx
	jz scanline_abort

scanline_inner2:
	mov bh, byte ptr [scan_tmp+4+2]
	mov bl, byte ptr [scan_tmp+2]
	add dword ptr [scan_tmp+4], ebp
	mov dh, byte ptr fs:[bx]
	add dword ptr [scan_tmp], eax
	sub dh, byte ptr [scan_tmp+4+8+4+2]
	jnb scanline_noflow
	mov dh, 0
scanline_noflow:
	shr dh, 2
	add dh, current_colorbase
;	shr dh, 1
;	shr byte ptr es:[di], 1
	add dword ptr [scan_tmp+4+8+4], esi
	mov byte ptr es:[di], dh
	inc di
	dec dl
	jnz scanline_inner2

else
	stosb
endif
	mov eax, dword ptr [scan_tmp+8]
	mov ebx, dword ptr [scan_tmp+4+8]
	mov ebp, dword ptr [scan_tmp+4+8+4+4]
	mov dword ptr [scan_tmp], eax
	mov dword ptr [scan_tmp+4], ebx
	sub cx, 8
	mov dword ptr [scan_tmp+4+8+4], ebp

	jnb scanline_inner

scanline_abort:
	fstp st(0)
	fstp st(0)

invalid_scanline:
	pop edx
	pop eax
	pop ecx
	pop bx
	pop di
	pop si
ret ; render_scanline


;----------------------------------------------------------------------------
;	RENDER_TRIGON
;
;	Renders a single trigon. No clipping whatsoever is performed!
;	FPU stack must be empty on entry.
;
;	bx:	pointer to first vertex
;	di:	pointer to second vertex
;	si:	pointer to third vertex
;	es:	output buffer segment
;	fs:	texture segment
;
;	x and y of each vertex are assumed to have been transformed into 
;	screen-space coordinates.
;
;----------------------------------------------------------------------------
.data
dx1	dd	?
dx2	dd	?
dy1	dd	?
dy2	dd	?
du1	dd	?
dv1	dd	?
du2	dd	?
dv2	dd	?
u1	dd	?
v1	dd	?
u2	dd	?
v2	dd	?
dc1	dd	?
dc2	dd	?
c1	dd	?
c2	dd	?
.code
render_trigon:
	push ax
	push cx
	push bx
	push di
	push si

	mov eax, dword ptr [bx + VERTEX_EX.sy]
	cmp dword ptr [di + VERTEX_EX.sy], eax
	ja y1_above
	xchg bx, di
y1_above:
	mov eax, dword ptr [bx + VERTEX_EX.sy]
	cmp dword ptr [si + VERTEX_EX.sy], eax
	ja y2_above
	xchg bx, si
y2_above:
	mov eax, dword ptr [di + VERTEX_EX.sy]
	cmp dword ptr [si + VERTEX_EX.sy], eax
	ja y3_above
	xchg di, si
y3_above:
	; vertex order now from top: bx, di, si

	; 320 bytes wide buffer assumed!
	mov eax, dword ptr [bx + VERTEX_EX.sy]
	shr eax, 16
	mov dx, ax
	shl dx, 6
	shl ax, 8
	add ax, dx
	mov scan_y, ax

	mov ecx, dword ptr [di + VERTEX_EX.sy]
	mov eax, dword ptr [bx + VERTEX_EX.sy]
	and ecx, 0ffff0000h
	and eax, 0ffff0000h
	sub ecx, eax
	shr ecx, 16
	mov dy1, ecx
	test cx, 1000000000000000b
	jnz lowerportion

	; don't trash eax!
	mov eax, dword ptr [bx + VERTEX_EX.sx]

	fild dword ptr [di + VERTEX_EX.sx]
	fild dword ptr [bx + VERTEX_EX.sx]
	fsubp st(1), st(0)
	fidiv dy1
	fistp dx1

	fld [di + VERTEX_EX.inv_u32]
	fsub [bx + VERTEX_EX.inv_u32]
	fidiv dy1
	fstp du1

	fld [di + VERTEX_EX.inv_v32]
	fsub [bx + VERTEX_EX.inv_v32]
	fidiv dy1
	fstp dv1

	fld [di + VERTEX_EX.color32]
	fsub [bx + VERTEX_EX.color32]
	fidiv dy1
	fstp dc1

	fld [di + VERTEX_EX.inv_z]
	fsub [bx + VERTEX_EX.inv_z]
	fidiv dy1

	; add more interpolation precalc here

	mov ecx, dword ptr [si + VERTEX_EX.sy]
	mov edx, dword ptr [bx + VERTEX_EX.sy]
	and ecx, 0ffff0000h
	and edx, 0ffff0000h
	sub ecx, edx
	shr ecx, 16
	mov dy2, ecx
	mov edx, eax
	test cx, 1000000000000000b
	jnz lowerportion

	fild [si + VERTEX_EX.sx]
	fisub [bx + VERTEX_EX.sx]
	fidiv dy2
	fistp dx2

	fld [si + VERTEX_EX.inv_u32]
	fsub [bx + VERTEX_EX.inv_u32]
	fidiv dy2
	fstp du2

	fld [si + VERTEX_EX.inv_v32]
	fsub [bx + VERTEX_EX.inv_v32]
	fidiv dy2
	fstp dv2

	fld [si + VERTEX_EX.color32]
	fsub [bx + VERTEX_EX.color32]
	fidiv dy2
	fstp dc2

	fld [si + VERTEX_EX.inv_z]
	fsub [bx + VERTEX_EX.inv_z]
	fidiv dy2

	; add more interpolation precalc here

	; FPU stack: dz2, dz1
	fxch
	fld [bx + VERTEX_EX.inv_z]
	fld st(0)

	mov ecx, [bx + VERTEX_EX.color32]
	mov c1, ecx
	mov c2, ecx

	mov ecx, [bx + VERTEX_EX.inv_u32]
	mov u1, ecx
	mov u2, ecx
	mov ecx, [bx + VERTEX_EX.inv_v32]
	mov v1, ecx
	mov v2, ecx

	mov ecx, dy1
	test ecx, ecx
	jz lowerportion

	; FPU stack: z1, z2, dz1, dz2

	; EBX is destroyed!

scanloop1:
	call render_scanline
	
	fld u1
	fadd du1
	fstp u1
	fld v1
	fadd dv1
	fstp v1
	fld u2
	fadd du2
	fstp u2
	fld v2
	fadd dv2
	fstp v2
	fld c1
	fadd dc1
	fstp c1
	fld c2
	fadd dc2
	fstp c2
	add eax, [dx1]
	add edx, [dx2]
	add scan_y, SCREENWIDTH
	fadd st(0), st(2)
	fxch
	fadd st(0), st(3)
	fxch

	loop scanloop1

lowerportion:
;	jmp poly_abort

	; FPU stack: z1, z2, dz1, dz2
	fstp st(0)
	fxch
	fstp st(0)
	; FPU stack: z2, dz2

	mov ecx, dword ptr [si + VERTEX_EX.sy]
	mov eax, dword ptr [di + VERTEX_EX.sy]
	and ecx, 0ffff0000h
	and eax, 0ffff0000h
	sub ecx, eax
	shr ecx, 16
	mov dy1, ecx
	test cx, 1000000000000000b
	jnz poly_abort

	mov eax, [di + VERTEX_EX.inv_u32]
	mov ebx, [di + VERTEX_EX.inv_v32]
	mov dword ptr u1, eax
	mov dword ptr v1, ebx

	mov eax, [di + VERTEX_EX.color32]
	mov dword ptr c1, eax

	mov eax, dword ptr [di + VERTEX_EX.sx]

	fild [si + VERTEX_EX.sx]
	fisub [di + VERTEX_EX.sx]
	fidiv dy1
	fistp dx1

	fld [si + VERTEX_EX.inv_u32]
	fsub [di + VERTEX_EX.inv_u32]
	fidiv dy1
	fstp du1

	fld [si + VERTEX_EX.inv_v32]
	fsub [di + VERTEX_EX.inv_v32]
	fidiv dy1
	fstp dv1

	fld [si + VERTEX_EX.color32]
	fsub [di + VERTEX_EX.color32]
	fidiv dy1
	fstp dc1

	fld [si + VERTEX_EX.inv_z]
	fsub [di + VERTEX_EX.inv_z]
	fidiv dy1

	; FPU stack: dz1, z2, dz2

	fxch
	fld [di + VERTEX_EX.inv_z]

	; FPU stack: z1, z2, dz1, dz2
	test ecx, ecx
	jz poly_abort

scanloop2:
	call render_scanline

	fld u1
	fadd du1
	fstp u1
	fld v1
	fadd dv1
	fstp v1
	fld u2
	fadd du2
	fstp u2
	fld v2
	fadd dv2
	fstp v2
	fld c1
	fadd dc1
	fstp c1
	fld c2
	fadd dc2
	fstp c2
	add eax, [dx1]
	add edx, [dx2]
	add scan_y, SCREENWIDTH
	fadd st(0), st(2)
	fxch
	fadd st(0), st(3)
	fxch

	loop scanloop2

poly_abort:
	fstp st(0)
	fstp st(0)
	fstp st(0)
	fstp st(0)

	pop si
	pop di
	pop bx
	pop cx
	pop ax
ret ; render_trigon

;----------------------------------------------------------------------------
;	PROJECT
;
;	Projects a 3D vertex into screen-space.
;
;	bp:	pointer to vertex to project
;
;----------------------------------------------------------------------------
project:
	fld dword ptr [bp + VERTEX_EX.z]
	fld1
	fdiv st(0), st(1)
	fstp dword ptr [bp + VERTEX_EX.inv_z]

	fld dword ptr [bp + VERTEX_EX.u32]
	fdiv st(0), st(1)
	fstp [bp + VERTEX_EX.inv_u32]
	
	fld dword ptr [bp + VERTEX_EX.v32]
	fdivrp st(1)
	fstp [bp + VERTEX_EX.inv_v32]

	fld perspective
	fdiv dword ptr [bp + VERTEX_EX.z]

	fld dword ptr [bp + VERTEX_EX.x]
	fmul st(0), st(1)
	fadd center_x
	fmul fshift
	fistp dword ptr [bp + VERTEX_EX.sx]

	fld dword ptr [bp + VERTEX_EX.y]
	fmul st(0), st(1)
	fmul aspectratio
	fadd center_y
	fmul fshift
	fistp dword ptr [bp + VERTEX_EX.sy]
	fstp st(0)
ret ; project


;----------------------------------------------------------------------------
;	RENDER_POLYGON
;
;	Renders a single polygon. No clipping whatsoever is done!
;	FPU stack must be empty on entry.
;
;	Vertex pointers must be in a clockwise order.
;
;IN:	ecx:	number of edges
;	ds:bx	pointer to vertex list
;
;	Trashes: ax, bx, si, di, ecx, es
;
;----------------------------------------------------------------------------
render_polygon:
	mov ax, fbufferseg
	mov es, ax

	cmp ecx, 3
	jb render_abort

	mov si, bx
	add si, size VERTEX_EX

	mov ax, si

	push bp
	mov bp, bx
	call project
	mov bp, si
	call project
	pop bp

	sub ecx, 2

render_edgeloop:
	mov di, si
	add ax, size VERTEX_EX
	mov si, ax

	push bp
	mov bp, si
	call project
	pop bp

	call render_trigon
	loop render_edgeloop
render_abort:
ret ; render_polygon

;----------------------------------------------------------------------------
;	CULL_PORTAL
;
;	Renders all the convex hulls and other portals visible through a 
;	portal.
;
;IN:	si:	pointer to vertices (at least three, VERTEX_EX format)
;OUT:	flags:	cmp normal.z, 0
;
;	Trashes:	flags
;
;            c = (x3*((z1*y2)-(y1*z2))+
;                (y3*((x1*z2)-(z1*x2))+
;                (z3*((y1*x2)-(x1*y2))+
;
;----------------------------------------------------------------------------
cull_polygon:
	push ax
	fld dword ptr [si + size VERTEX_EX*0 + VERTEX_EX.z]
	fmul dword ptr [si + size VERTEX_EX*1 + VERTEX_EX.y]
	fld dword ptr [si + size VERTEX_EX*0 + VERTEX_EX.y]
	fmul dword ptr [si + size VERTEX_EX*1 + VERTEX_EX.z]
	fsubp st(1), st(0)
	fmul dword ptr [si + size VERTEX_EX*2 + VERTEX_EX.x]

	fld dword ptr [si + size VERTEX_EX*0 + VERTEX_EX.x]
	fmul dword ptr [si + size VERTEX_EX*1 + VERTEX_EX.z]
	fld dword ptr [si + size VERTEX_EX*0 + VERTEX_EX.z]
	fmul dword ptr [si + size VERTEX_EX*1 + VERTEX_EX.x]
	fsubp st(1), st(0)
	fmul dword ptr [si + size VERTEX_EX*2 + VERTEX_EX.y]

	fld dword ptr [si + size VERTEX_EX*0 + VERTEX_EX.y]
	fmul dword ptr [si + size VERTEX_EX*1 + VERTEX_EX.x]
	fld dword ptr [si + size VERTEX_EX*0 + VERTEX_EX.x]
	fmul dword ptr [si + size VERTEX_EX*1 + VERTEX_EX.y]
	fsubp st(1), st(0)
	fmul dword ptr [si + size VERTEX_EX*2 + VERTEX_EX.z]

	faddp
	faddp

	fldz
	fcompp st(1)
	fstsw ax
	sahf

	pop ax
ret ; cull_polygon


;----------------------------------------------------------------------------
;	VERTEX_COPY
;
;	Copies a single vertex (VERTEX_EX) from si to di.
;
;IN:	si:	pointer to source vertex
;	di:	pointer to destination vertex
;
;----------------------------------------------------------------------------
vertex_copy:
	push ecx
	push esi

	mov ecx, size VERTEX_EX
	rep movsb

	pop esi
	pop ecx
ret ; vertex_copy

;----------------------------------------------------------------------------
;	CLIP_POLYGON
;
;	Takes a polygon through the current clipping plane stack and
;	finally renders the clipped counterpart.
;
;IN:	si:	pointer to vertices
;	ecx:	number of edges
;
;	Trashes:
;
;----------------------------------------------------------------------------
clip_polygon:
	push eax
	push bx
	push cx
	push dx
	push si
	push di

	mov ax, cs
	mov es, ax

	mov di, offset tmp_vertexdata_a

	mov eax, znear
	mov retfloat, eax
	mov bx, offset planedata
	call clip_to_plane
	test cx, cx
	jz clipper_abort

	mov si, di
	mov di, offset tmp_vertexdata_b
	add bx, size VECTOR3D

	mov retfloat, 0

clipper_loop:
	call clip_to_plane
	xchg si, di

	test cx, cx
	jz clipper_abort

	add bx, size VECTOR3D
	cmp bx, [planeptr]
	jnz clipper_loop

	mov bx, si
	call render_polygon

clipper_abort:
	pop di
	pop si
	pop dx
	pop cx
	pop bx
	pop eax
ret ; clip_polygon

;----------------------------------------------------------------------------
;	CLIP_TO_PLANE
;
;	Clips a convex polygon to a single plane.
;
;IN:	si:		pointer to 'in' vertices
;	es:di:		pointer to 'out' vertices
;	bx:		pointer to clipping plane
;	retfloat:	distance from origin to plane
;	
;	ecx:	initial number of edges
;
;OUT:	ecx:	number of edges after clipping
;
;	Trashes: ecx
;
;----------------------------------------------------------------------------
clip_to_plane:
	push ax
	push bx
	push dx
	push di
	push si

	mov edx, ecx
	mov ax, si

clip_preloop:
	; replace with a call to dot
	fld [si + VECTOR3D.x]
	fmul [bx + VECTOR3D.x]
	fld [si + VECTOR3D.y]
	fmul [bx + VECTOR3D.y]
	fld [si + VECTOR3D.z]
	fmul [bx + VECTOR3D.z]
	faddp
	faddp
	fsub dword ptr retfloat
	fstp [si + VERTEX_EX.sx]	; sx = distance

	add si, size VERTEX_EX
	loop clip_preloop

	xchg ecx, edx	; edx=0, ecx=count

	mov si, ax
	mov bx, si
	add bx, size VERTEX_EX

	; si = current vertex, bx = next vertex, es:di = output vertex
	; dl = output counter

clip_loop:
	cmp cx, 1
	jnz clip_notlast
	mov bx, ax
clip_notlast:
	test byte ptr [si + VERTEX_EX.sx + 3], 128
	jnz clip_not_visible

	inc dx
	call vertex_copy

clip_not_visible:
	; does current edge intersect with the clipping plane?
	push ax
	; test for sign mismatch
	test byte ptr [si + VERTEX_EX.sx + 3], 128
	setnz al
	test byte ptr [bx + VERTEX_EX.sx + 3], 128
	setnz ah
	cmp al, ah
	pop ax
	jz clip_no_intersection
 
	; edge must be clipped
	fld dword ptr [si + VERTEX_EX.sx]
	fld st(0)
	fxch
	fsub dword ptr [bx + VERTEX_EX.sx]
	fdivp st(1)

	; FPU stack: scale

	fld dword ptr [bx + VECTOR3D.x]
	fsub dword ptr [si + VECTOR3D.x]
	fmul st(0), st(1)
	fadd dword ptr [si + VECTOR3D.x]
	fstp dword ptr [di + VECTOR3D.x]

	fld dword ptr [bx + VECTOR3D.y]
	fsub dword ptr [si + VECTOR3D.y]
	fmul st(0), st(1)
	fadd dword ptr [si + VECTOR3D.y]
	fstp dword ptr [di + VECTOR3D.y]

	fld dword ptr [bx + VECTOR3D.z]
	fsub dword ptr [si + VECTOR3D.z]
	fmul st(0), st(1)
	fadd dword ptr [si + VECTOR3D.z]
	fstp dword ptr [di + VECTOR3D.z]

	fld dword ptr [bx + VECTOR3D.color32]
	fsub dword ptr [si + VECTOR3D.color32]
	fmul st(0), st(1)
	fadd dword ptr [si + VECTOR3D.color32]
	fstp dword ptr [di + VECTOR3D.color32]

	fld dword ptr [bx + VECTOR3D.u32]
	fsub dword ptr [si + VECTOR3D.u32]
	fmul st(0), st(1)
	fadd dword ptr [si + VECTOR3D.u32]
	fstp dword ptr [di + VECTOR3D.u32]

	fld dword ptr [bx + VECTOR3D.v32]
	fsub dword ptr [si + VECTOR3D.v32]
	fmul st(0), st(1)
	fadd dword ptr [si + VECTOR3D.v32]
	fstp dword ptr [di + VECTOR3D.v32]

	; add more interpolation here
	fstp st(0)
	inc dx
	add di, size VERTEX_EX

clip_no_intersection:
	add si, size VERTEX_EX
	add bx, size VERTEX_EX
	dec cx
	jnz clip_loop

	mov cx, dx

	pop si
	pop di
	pop dx
	pop bx
	pop ax
ret ; clip_to_plane

;----------------------------------------------------------------------------
;	ROTATE_VERTICES
;
;	Calculates the camera matrix and rotates all the vertices accordingly.
;
;IN:	si:		pointer to 'in' vertices
;	di:		pointer to 'out' vertices
;	
;OUT:	di:		next free vertex in 'out' buffer
;
;	Trashes:	di, ecx
;
;----------------------------------------------------------------------------
rotate_vertices:
	push si
	push di

	fld dword ptr [camera_target + VECTOR3D.x]
	fsub dword ptr [camera + VECTOR3D.x]
	fstp dword ptr [camera_matrix + MATRIX_Z_X]

	fld dword ptr [camera_target + VECTOR3D.y]
	fsub dword ptr [camera + VECTOR3D.y]
	fstp dword ptr [camera_matrix + MATRIX_Z_Y]

	fld dword ptr [camera_target + VECTOR3D.z]
	fsub dword ptr [camera + VECTOR3D.z]
	fstp dword ptr [camera_matrix + MATRIX_Z_Z]

	mov bx, offset camera_matrix + MATRIX_Z_X
	call normalize

	; z, 0, -x
	mov eax, dword ptr [camera_matrix + MATRIX_Z_Z]
	xor ebx, ebx
	mov dword ptr [camera_matrix + MATRIX_X_X], eax
	mov dword ptr [camera_matrix + MATRIX_X_Y], ebx
	mov eax, dword ptr [camera_matrix + MATRIX_Z_X]
	xor eax, 128*65536*256
	mov dword ptr [camera_matrix + MATRIX_X_Z], eax

	mov bx, offset camera_matrix + MATRIX_X_X
	call normalize

	mov si, bx
	mov di, offset camera_matrix + MATRIX_Z_X
	mov bx, offset camera_matrix + MATRIX_Y_X
	call cross

	mov bx, si

	pop di
	pop si

	mov cx, vertices

;	bx: offset camera_matrix

	mov ax, cs
	mov es, ax

	fld dword ptr camera_roll
	fsincos
	fstp camera_roll_sin
	fstp camera_roll_cos

rotate_loop:
	fld dword ptr [si + VECTOR3D.z]
	fsub dword ptr [camera + VECTOR3D.z]
	fld dword ptr [si + VECTOR3D.y]
	fsub dword ptr [camera + VECTOR3D.y]
	fld dword ptr [si + VECTOR3D.x]
	fsub dword ptr [camera + VECTOR3D.x]
	call vect_mul_mat_inverse

	fld dword ptr [di + VECTOR3D.y]
	fmul camera_roll_cos
	fld dword ptr [di + VECTOR3D.x]
	fmul camera_roll_sin
	faddp

	fld dword ptr [di + VECTOR3D.y]
	fmul camera_roll_sin
	fld dword ptr [di + VECTOR3D.x]
	fmul camera_roll_cos
	fsubp st(1), st(0)
	fstp dword ptr [di + VECTOR3D.y]
	fstp dword ptr [di + VECTOR3D.x]

	mov dx, cx
	mov cx, size VERTEX - size VECTOR3D
	add si, size VECTOR3D
	add di, size VECTOR3D
	rep movsb
	mov cx, dx
	loop rotate_loop
ret ; rotate_vertices


;----------------------------------------------------------------------------
;	RENDER_PORTAL
;
;	Renders all the convex hulls and other portals visible through a 
;	portal.
;
;IN:	si:	pointer to portal vertices
;	di:	pointer to vertex data
;	ah:	flags + number of edges
;	current_portal:	pointer to convex hull portal points to
;OUT:
;
;	Trashes:	camera_matrix, si
;
;----------------------------------------------------------------------------
.data
current_portal		dw	?
portal_tmp		dw	?
portal_count		db	?
.code
render_portal:
	inc portal_count
	cmp portal_count, MAX_RECURSIONS
	jnb portal_abort

	push di
	push cx
	push bx
	push ax

	xor cx, cx
	mov cl, ah
	and cl, 00111111b

	push portal_tmp
	push planeptr

	push di

	mov di, si
	add di, size VERTEX_EX
	mov portal_tmp, si

if CLIP_TO_PORTAL

portal_loop:
	; si = current vertex, di = next vertex
	cmp cx, 1
	jnz portal_notlast
	mov di, portal_tmp

portal_notlast:
	fld [di + VERTEX_EX.x]
	fsubr dword ptr [si + VECTOR3D.x]
	fstp dword ptr [camera_matrix + VECTOR3D.x]
	fld [di + VERTEX_EX.y]
	fsubr dword ptr [si + VECTOR3D.y]
	fstp dword ptr [camera_matrix + VECTOR3D.y]
	fld [di + VERTEX_EX.z]
	fsubr dword ptr [si + VECTOR3D.z]
	fstp dword ptr [camera_matrix + VECTOR3D.z]

	mov ax, si
	mov dx, di
	mov di, si
	mov si, offset camera_matrix
	mov bx, planeptr
	call cross
	call normalize
	mov si, ax
	mov di, dx

	add si, size VERTEX_EX
	add di, size VERTEX_EX
	add planeptr, size VECTOR3D

	loop portal_loop

endif

	pop di
	mov si, current_portal
	call render_hull

	pop planeptr
	pop portal_tmp

	pop ax
	pop bx
	pop cx
	pop di
portal_abort:
	dec portal_count
ret ; render_portal

;----------------------------------------------------------------------------
;	RENDER_HULL
;
;	Renders a single convex hull.
;
;IN:	si:	pointer to hull header
;	di:	pointer to vertex data
;OUT:
;
;	Trashes:
;
;----------------------------------------------------------------------------
.data
hull_tmp	dw	?
.code
render_hull:
	push si
	push di
	push ax
	push bx
	push cx
	push dx

	push hull_tmp
	push current_portal

	xor cx, cx
	mov hull_tmp, si
	mov cl, byte ptr [si + HULLHEADER.faces]
	inc si	; skip HULLHEADER

hull_loop:
	mov ax, cs
	mov es, ax

	; grab relevant vertices from tmp_vertexdata and copy them over
	; to tmp_vertexdata_b for clipping.
	mov al, byte ptr [si]	; mapping mode
	mov current_colorbase, al
	and al, 3
	test al, al
	jnz not_xy
	mov ebp, 00040000h	;XY
	jmp plane_found
not_xy:
	cmp al, PLANE_XZ
	jnz not_xz
	mov ebp, 00080000h	;XZ
	jmp plane_found
not_xz:
	mov ebp, 00080004h	;YZ

	and byte ptr [current_colorbase], 11111100b

plane_found:
	inc si

	mov al, byte ptr [si]	; number of edges

	mov dx, di
	mov di, offset tmp_vertexdata_b

	inc si
	mov ah, al
	and al, 00111111b

	test ah, POLY_FLAG_NEW_TEXTURE
	jz no_new_texture
	mov bx, word ptr [si]
	mov fs, [bx]
	add si, 2

no_new_texture:
	test ah, POLY_FLAG_PORTAL
	jz hull_inner

	mov bx, word ptr [si]
	mov current_portal, bx
	add si, 2

hull_inner:
	mov bx, dx
	push ax
	push dx
	mov ax, size VERTEX
	mul byte ptr [si]
	add bx, ax
	pop dx

	push si
	mov si, bx

	push ecx
;	mov cx, size VERTEX
	mov cx, size VECTOR3D
	rep movsb
;	xor eax, eax
;	mov ecx, size VERTEX_EX - size VERTEX
;	rep stosb
;	add di, size VERTEX_EX - size VERTEX
	add di, size VERTEX_EX - size VECTOR3D

	push si
	mov si, offset vertexdata	; unrotated vertices
	add si, ax

	mov eax, dword ptr [si + bp]
	rol ebp, 16
	mov ecx, dword ptr [si + bp]
	rol ebp, 16

	mov [di - size VERTEX_EX + VERTEX_EX.u32], eax
	mov [di - size VERTEX_EX + VERTEX_EX.v32], ecx

	fld dword ptr [di - size VERTEX_EX + VERTEX_EX.u32]
	fmul fshift
	fstp dword ptr [di - size VERTEX_EX + VERTEX_EX.u32]

	fld dword ptr [di - size VERTEX_EX + VERTEX_EX.v32]
	fmul fshift
	fstp dword ptr [di - size VERTEX_EX + VERTEX_EX.v32]

	pop si

	mov dword ptr retfloat, 0
	mov al, byte ptr [si - size VECTOR3D + VERTEX.color]
	mov byte ptr [retfloat+2], al
	fild retfloat
	fstp dword ptr [di - size VERTEX_EX + VERTEX_EX.color32]

	pop ecx
	pop si
	pop ax

	inc si
	dec al
	jnz hull_inner

	mov di, dx

	push cx
	xor cx, cx
	push si
	mov cl, ah		; number of edges
	mov si, offset tmp_vertexdata_b

if BACKFACE_CULLING
	call cull_polygon
	jb culled
endif

	test ah, POLY_FLAG_PORTAL
	jz no_portal

if RENDER_PORTALS
	call render_portal
endif
	jmp done
no_portal:
	and cl, 00111111b
	call clip_polygon
	jmp done
culled:
	test ah, POLY_FLAG_PORTAL
	jz done
	mov bp, current_hull
	cmp hull_tmp, bp
	jnz done

	push ax
	mov ax, current_portal
	mov current_hull, ax
        mov si, ax
	pop ax

;	call render_hull

	pop si
	pop cx
	jmp hull_abort
done:
	pop si
	pop cx

	dec cx
	jnz hull_loop

hull_abort:
	pop current_portal
	pop hull_tmp

	pop dx
	pop cx
	pop bx
	pop ax
	pop di
	pop si
ret ; render_hull

;----------------------------------------------------------------------------
;	RENDER_SCENE
;
;	Calculates and renders the entire scene.
;
;IN:	si:	pointer to scene vertex data
;	di:	pointer to scene hull data
;OUT:
;
;	Trashes:
;
;----------------------------------------------------------------------------
render_scene:
	mov si, offset vertexdata
	mov di, offset tmp_vertexdata
	call rotate_vertices

	mov portal_count, 0
	mov si, current_hull
	mov di, offset tmp_vertexdata
	call render_hull
ret ; render_scene

;----------------------------------------------------------------------------
;	CALC_TEXTURE0
;
;IN:	es:	pointer to texture data
;	bp:	roughness
;OUT:
;
;	Trashes: Just about everything
;
;----------------------------------------------------------------------------
calc_texture0:
;	mov dx, 64
;	mov cx, 128
;	call random
;	mov bx, ax
;	add bx, 255

	xor di, di

	mov cx, 256*4
calc_loop0:
	push cx
	mov cx, 256
calc_innerloop0:
	push cx
	mov dx, 0
	mov cx, 128
	call random
	test al, 1
	jz baz
	add bx, bp
	jmp bar
baz:
	sub bx, bp
bar:
	cmp byte ptr es:[di-255], 150
	jb spamalamadingdong
	mov al, byte ptr es:[di-255]
	shr al, 1
	shr bl, 1
	add bl, al
spamalamadingdong:
	mov al, bl
	pop cx
	stosb
	loop calc_innerloop0
	pop cx
	loop calc_loop0
ret ; calc_texture0


;----------------------------------------------------------------------------
;	CALC_TEXTURE1
;
;IN:	es:	pointer to texture data
;OUT:
;
;	Trashes: Just about everything
;
;----------------------------------------------------------------------------
calc_texture1:
	xor di, di
	mov cx, 256
calc_loop1:
	push cx
	mov bl, cl
	mov cx, 256
calc_innerloop1:
	mov al, cl
	xor al, bl
	sub al, 4
	jnc foo
	mov al, 0
foo:
	stosb
	loop calc_innerloop1
	pop cx
	loop calc_loop1
ret ; calc_texture1


update_camera:
	mov si, camera_ip

if INTERACTIVE_MULTIMEDIA
	push es
	mov ax, 040h
	mov es, ax
	test byte ptr es:[018h], 1
	jz no_ctrl
	sub camera_counter, 16
	jz hmm
	jnc no_ctrl
hmm:
	mov camera_counter, 1
no_ctrl:
	pop es
endif

	dec camera_counter
	jnz cam_no_advance
	add camera_ip, 8*2
	mov si, camera_ip
	mov ax, word ptr [si]
	mov camera_counter, ax
	test ax, KEYFRAME_TEXT
	jz cam_no_text
	xor demoflags, FLAG_TEXT
cam_no_text:
	test ax, KEYFRAME_END
	jz cam_no_advance
	or demoflags, FLAG_DONE
cam_no_advance:
	mov cx, 7

	mov bx, offset camera

	fild word ptr [camera_counter]
	fidiv word ptr [si]
;	fld1
;	fsubrp
	
	fldpi
	fmulp st(1)
	fcos
	fmul fhalf
	fadd fhalf

	add si, 2

cameraloop:
	fild word ptr [si]
	fld st(0)
	fisubr word ptr [si+8*2]
	fmul st(0), st(2)
	faddp st(1), st(0)
	fstp dword ptr [bx]
	add si, 2
	add bx, 4
	loop cameraloop

	fstp st(0)
ret ; update_camera

;----------------------------------------------------------------------------
;	KERNEL
;
;	An ISR that runs the intro and keeps it in sync.
;
;----------------------------------------------------------------------------
.data
fpusave		db 96 dup(?)
.code
frange dd 200.0
kernel:
	pushad
	pushf
	push es
	push ds
	push gs
	cld

	mov ax, cs
	mov ds, ax

	fsave fpusave

;	mov step, 0
;	mov eax, tick
;	and ax, 63
;	cmp ax, 63
;	jnz no_step
;	mov step, 1
;no_step:

	inc tick
	call update_camera

cycle_done:
	frstor fpusave

	mov al,020h                    ; return with iret
	out 020h,al
	pop gs
	pop ds
	pop es
	popf
	popad
iret ; kernel

main:
	mov ax, 13h
	int INT_VIDEO

	finit

	; lower FPU precision
	fstcw word ptr tmp
       	and word ptr tmp,1111110011111111b
	fldcw word ptr tmp

	mov ax, ds
	add ax, 1000h
	mov fbufferseg, ax

	add ax, 1000h
	mov es, ax
	mov texture0, ax
	push ax
	mov bp, 8
	call calc_texture0
	pop ax

	add ax, 1000h
	mov es, ax
	mov texture1, ax
	push ax
	mov bp, 2
	call calc_texture0
	pop ax

	add ax, 1000h
	mov es, ax
	mov texture2, ax
	call calc_texture1

	mov fs, [texture0]

	mov ax, offset planearray
	mov planeptr, ax

	call setpalette
	call clear

	mov ax, offset hulldata
	mov current_hull, ax

	mov dx, bp
	mov ax,1130h
	mov bh,6h
	int INT_VIDEO
	mov word ptr romfont, es
	mov word ptr romfont+2, bp
	mov bp, dx

	call hooktimer
prewait:
	cmp tick, 0
	jz prewait

mainloop:
	mov ax, fbufferseg
	mov es, ax

if 0
	xor di, di
	mov ecx, 64000
dwako:
	mov al, es:[di]
	sub al, 2
	jnc fawjio
	xor al, al
fawjio:
	mov es:[di], al
	inc di
	loop dwako

	xor di, di
	mov ebx, tick
	mov dword ptr es:[di], ebx
else
;	call clear
endif
     
	call render_scene

	test demoflags, FLAG_TEXT
	jz no_text
	mov al, 120
	mov si, offset introname
	call render_text

no_text:
	call flip

	in al, 60h
	cmp al, 1
	jnz no_abort
	or demoflags, FLAG_DONE
no_abort:

	test demoflags, FLAG_DONE
	jz mainloop

	call unhooktimer

	mov ax, 3h
	int INT_VIDEO
ret ; main

.data
tmp_vertexdata_a VERTEX_EX 32 dup (?)
tmp_vertexdata_b VERTEX_EX 32 dup (?)
tmp_vertexdata VERTEX_EX 256 dup (?)
tmp dd ?

END start
