rem ==================================================================
rem ==================================================================

rem DU kan plocka bort en massa frn berkningen av u i wallcast,
rem eftersom texturens bredd inte lngre r aktuell i naalaa.

visible:
	rem Map ===========================================================
	rem Width and height.
	rc_MapW
	rc_MapH
	rem Walls.
	rc_Map[][]
	rc_Floor[][]
	rc_Ceiling[][]
	rc_Flag[][]
	rc_Items[][]
	rc_ItemParams#[][]
	rc_Doors[][]

	rem View ==========================================================
	rc_Unit#
	rc_AngleOffset#[]
	rc_AngleOffsetCos#[]
	rc_Distance#[][]
	rc_ZBuffer#[]

	rc_Width = 320
	rc_Height = 240

	rc_FogR
	rc_FogG
	rc_FogB
	rc_FogMin#
	rc_FogMax#
	rc_FogSpread#

	rc_ClearScreen = true


constant:
	RC_MAX_OBJECTS 200
	RC_OBJ_ID	0
	RC_OBJ_IMG	1
	RC_OBJ_X		2
	RC_OBJ_Z		3
	RC_OBJ_Y		4
	RC_OBJ_TX	5
	RC_OBJ_TZ	6
	RC_OBJ_W		7
	RC_OBJ_H		8
	RC_OBJ_D		9
	RC_OBJ_IXY	10

	RC_X		0
	RC_Z		1
	RC_ANGLE 2
	RC_FLAG	2

	RC_NORTH 0
	RC_SOUTH 1
	RC_WEST	2
	RC_EAST	3

visible:
	RC_MAX_DOORS = 100

	rc_Objects#[RC_MAX_OBJECTS][11]
	rc_ObjOrder[RC_MAX_OBJECTS]
	rc_ObjCount = 0

	rc_OpenDoorCount = 0
	rc_OpenDoors[RC_MAX_DOORS][2]
	rc_DoorSpeed# = 0.025

	rc_CollisionInfo[4]

hidden:


rem ==================================================================
rem Init view with specified field of view.
rem ==================================================================
procedure RC_InitView(fov#, renderW, renderH)
	rc_Width = renderW
	rc_Height = renderH
	w = rc_Width
	h = rc_Height
	hw = w/2
	hh = h/2
	rc_Unit = float(hw)/tan(fov*0.5)
	rc_AngleOffset#[w]
	rc_AngleOffsetCos#[w]
	rc_ZBuffer#[w]
	for x = 0 to hw - 1
		rc_AngleOffset[hw + x] = atan(float(x)/rc_Unit)
		rc_AngleOffset[hw - 1 - x] = -rc_AngleOffset[hw + x]	
		rc_AngleOffsetCos[hw + x] = cos(rc_AngleOffset[hw + x])
		rc_AngleOffsetCos[hw - 1 - x] = cos(rc_AngleOffset[hw - 1 - x])
	next	

	rc_Distance[w][hh]
	for x = 0 to w - 1
		dconv# = 1.0/cos(rc_AngleOffset[x])
		for y = 0 to hh - 1
			d# = rc_Unit/float(h - 2*y)
			d = d*dconv
			rc_Distance[x][y] = d
		next
	next
endproc

rem ==================================================================
rem Init map.
rem ==================================================================
procedure RC_InitMap(w, h)
	rc_MapW = w
	rc_MapH = h
	rc_Map[rc_MapW][rc_MapH]
	rc_Floor[rc_MapW][rc_MapH]
	rc_Ceiling[rc_MapW][rc_MapH]
	rc_Flag[rc_MapW][rc_MapH]
	rc_Items[rc_MapW][rc_MapH]
	rc_ItemParams#[rc_MapW][rc_MapH]
	rc_Doors[rc_MapW][rc_MapH]
	proc RC_ClearObjects
	proc RC_ClearDoors
endproc

function RC_GetMapWidth()
	return rc_MapW
endproc

function RC_GetMapHeight()
	return rc_MapH
endfunc

procedure RC_SetClearScreen(value)
	rc_ClearScreen = value
endproc

rem ==================================================================
rem Set wall.
rem ==================================================================
procedure RC_SetWall(x, z, img)
	if sizeof(rc_Map) = 0 then return
	rc_Map[x][z] = img
endproc

rem ==================================================================
rem Set floor.
rem ==================================================================
procedure RC_SetFloor(x, z, img)
	if sizeof(rc_Map) = 0 then return
	rc_Floor[x][z] = img
endproc

rem ==================================================================
rem Set ceiling.
rem ==================================================================
procedure RC_SetCeiling(x, z, img)
	if sizeof(rc_Map) = 0 then return
	rc_Ceiling[x][z] = img
endproc

rem ==================================================================
rem Set flag.
rem ==================================================================
procedure RC_SetFlag(x, z, flag)
	if sizeof(rc_Map) = 0 then return
	rc_Flag[x][z] = flag
endproc

procedure RC_SetItem(x, z, item, obstacle)
	if sizeof(rc_Map) = 0 then return
	rc_Items[x][z] = item
	if obstacle then rc_Map[x][z] = -3
endproc

rem ==================================================================
rem Return type of item at x, z.
rem ==================================================================
function RC_GetItem(x, z)
	if sizeof(rc_Map) = 0 then return 0
	return rc_Items[x][z]
endfunc

rem ==================================================================
rem Get wall.
rem ==================================================================
function RC_GetWall(x, z)
	if sizeof(rc_Map) = 0 then return 0
	if rc_Map[x][z] = 0 then return 0
	return rc_Map[x][z] - 1000
endfunc

rem ==================================================================
rem Get floor.
rem ==================================================================
function RC_GetFloor(x, z)
	if sizeof(rc_Map) = 0 then return 0
	return rc_Floor[x][z] - 1000
endfunc

rem ==================================================================
rem Get ceiling.
rem ==================================================================
function RC_GetCeiling(x, z)
	if sizeof(rc_Map) = 0 then return 0
	return rc_Ceiling[x][z] - 1000
endfunc

rem ==================================================================
rem Get flag.
rem ==================================================================
function RC_GetFlag(x, z)
	if sizeof(rc_Map) = 0 then return 0
	return rc_Flag[x][z]
endfunc

function RC_GetFlagPos[](flag)
	pos[]
	if sizeof(rc_Map) = 0 then return pos

	for z = 0 to rc_MapH - 1
		for x = 0 to rc_MapH - 1
			if rc_Flag[x][z] = flag
				pos[] = [x, z]
				break
			endif
		next
		if sizeof(pos) then break
	next

	return pos
endfunc

rem ==================================================================
rem Clear objects.
rem ==================================================================
procedure RC_ClearObjects()
	rc_ObjCount = 0
	rc_ObjOrder[RC_MAX_OBJECTS]
	for i = 0 to RC_MAX_OBJECTS - 1
		MOV#	@0		rc_Objects
		MOV	@1		i
		MUL	@1		11
		STP#	@0		@1
		MOV	[@0]	0
		rc_ObjOrder[i] = 0
	next
endproc

rem ==================================================================
rem Clear doors.
rem ==================================================================
procedure RC_ClearDoors()
	rc_OpenDoorCount = 0
endproc

rem ==================================================================
rem Set door speed.
rem ==================================================================
procedure RC_SetDoorSpeed(speed#)
	rc_DoorSpeed# = speed
endproc

rem ==================================================================
rem Render view.
rem ==================================================================
procedure RC_Render(xpos#, zpos#, angle#)
	if sizeof(rc_Map) = 0 then return
	xdistance#
	zdistance#
	xposi
	zposi
	xposf#
	zposf#
	dzdx_inv#
	dxdz_inv#
	hdzdx_inv#
	hdxdz_inv#
	xtexture
	ztexture
	xutex
	zutex
	y
	t
	texu

	wt

	dzdx_inv#
	dxdz_inv#

	ysize

	if rc_ClearScreen
		set color rc_FogR, rc_FogG, rc_FogB
		draw rect 0, 0, rc_Width, rc_Height, true
	endif

	proc RC_DrawFloorAndCeiling xpos, zpos, angle
	

	alpha

	id
	itm
	col = 0

	do
		dx# = cos(angle + rc_AngleOffset[col])
		dz# = sin(angle + rc_AngleOffset[col])

		if dx <> 0.0
			MOV# dzdx_inv dz
			DIV# dzdx_inv dx
			
			MOV# hdzdx_inv dzdx_inv
			MUL# hdzdx_inv 0.5
			
		endif
		if dz <> 0.0
			MOV# dxdz_inv dx
			DIV# dxdz_inv dz
				
			MOV# hdxdz_inv dxdz_inv
			MUL# hdxdz_inv 0.5
		endif

		MOV# xdistance 0.0
		MOV# zdistance 0.0

		rem Cast x ray.
		xposi = int(xpos)
		if dx = 0.0
			JMP dx_failed
		elseif dx < 0.0
			SUB xposi 1

			MOV @0 xposi
			ITF @0
			ADD# @0 1.0
			MOV# xposf @0

			MOV# zposf xposf
			SUB# zposf xpos
			MUL# zposf dzdx_inv
			ADD# zposf zpos

			rem zposi = int(zposf)
			MOV# @0 zposf
			FTI @0
			MOV zposi @0

			CMP zposi 0
			JL dx_failed
			CMP zposi rc_MapH
			JGE dx_failed			
rem			if zposi < 0 or zposi >= rc_MapH
rem				JMP dx_failed
rem			else

				MOV @2 xposi
				MOV @3 zposi
				MOV @0 rc_Map
				MOV @1 @2
				MUL @1 rc_MapH
				ADD @1 @3
				STP @0 @1
				MOV id [@0]
				MOV# @5	0.0
				@dxn_loop:
					CMP id 0
					JG dxn_end

					rem ==========
					
					MOV	@0 0
					SUB	@0	1
					CMP	id @0
					JNE	dxn_no_door

						MOV# @4 zposf
						SUB#	@4 hdzdx_inv
						MOV#	@0 @4

						FTI	@0

						CMP	@3 @0
						JNE	dxn_no_door


							rem get door param
							MOV# @0	@4

							MOV#	@5		rc_ItemParams
							MOV 	@1		@2
							MUL	@1 	rc_MapH
							ADD	@1 	@3
							STP#	@5 	@1
							MOV#	@5		[@5]
							SUB# 	@0 	@5
							
							FTI	@0
							CMP	@3	@0
							JNE	dxn_no_door

								MOV# zposf	@4
								MOV @0	@2	
								ADD @0	1
								ITF @0
								MOV# xposf	@0
								SUB#	xposf 0.5

								MOV	@0		rc_Items
								MOV 	@1		@2
								MUL	@1 	rc_MapH
								ADD	@1 	@3
								STP	@0 	@1
								MOV	id 	[@0]

								MOV xposi @2
								MOV zposi @3

							JMP	dxn_door_hit
	
					@dxn_no_door:
					MOV# @5 0.0; rem no offset
					rem ==========

					SUB @2 1
					SUB# zposf dzdx_inv
					MOV# @0 zposf
					FTI @0
					MOV @3 @0

					CMP @3 0
					JL dx_failed
					CMP @3 rc_MapH
					JGE dx_failed

					MOV @0 rc_Map
					MOV @1 @2
					MUL @1 rc_MapH
					ADD @1 @3
					STP @0 @1
					MOV id [@0]

					JMP dxn_loop
				@dxn_end:

				MOV xposi @2
				MOV zposi @3
					
				rem xposf = float(xposi) + 1.0
				MOV @0 xposi
				ADD @0 1
				ITF @0
				MOV# xposf @0

				@dxn_door_hit:

				MOV xtexture id
				rem xutex = int((zposf - float(zposi))*float(width(xtexture)))

				xutex = width(xtexture)
				MOV 	@1 	zposi
				ITF 	@1
				MOV#	@0 	zposf
				SUB#	@0		@5
				SUB# 	@0		@1
				MOV	@1		xutex
				ITF 	@1
				MUL#	@0		@1
				FTI	@0
				SUB	xutex	1
				SUB	xutex	@0
					
				MOV# @0 xposf
				SUB# @0 xpos
				MUL# @0 @0
				MOV# @1 zposf
				SUB# @1 zpos
				MUL# @1 @1
				ADD# @0 @1
				MOV# xdistance @0

				JMP dx_done
		else
			ADD xposi 1
			xposf = float(xposi)

			MOV# @0 xposf
			SUB# @0 xpos
			MUL# @0 dzdx_inv
			ADD# @0 zpos
			MOV# zposf @0

			MOV# @0 zposf
			FTI @0
			MOV zposi @0
			
rem			if zposi < 0 or zposi >= rc_MapH
rem				JMP dx_failed
rem			else
			CMP zposi 0
			JL dx_failed
			CMP zposi rc_MapH
			JGE dx_failed
				MOV @2 xposi
				MOV @3 zposi
				MOV @0 rc_Map
				MOV @1 @2
				MUL @1 rc_MapH
				ADD @1 @3
				STP @0 @1
				MOV id [@0]
				MOV# @5 0.0
				@dxp_loop:
					CMP id 0
					JG dxp_end


					rem ==========
					
					MOV	@0 0
					SUB	@0	1
					CMP	id @0
					JNE	dxp_no_door

						MOV#	@4 zposf
						ADD#	@4 hdzdx_inv
						MOV#	@0 @4

						FTI	@0

						CMP	@3 @0
						JNE	dxp_no_door


							rem get door param
							MOV# @0	@4

							MOV#	@5		rc_ItemParams
							MOV 	@1		@2
							MUL	@1 	rc_MapH
							ADD	@1 	@3
							STP#	@5 	@1
							MOV#	@5		[@5]
							SUB# 	@0 	@5
							
							FTI	@0
							CMP	@3	@0
							JNE	dxp_no_door

								MOV# zposf	@4
								MOV @0	@2	
								ADD @0	1
								ITF @0
								MOV# xposf	@0
								SUB#	xposf 0.5

								MOV	@0		rc_Items
								MOV 	@1		@2
								MUL	@1 	rc_MapH
								ADD	@1 	@3
								STP	@0 	@1
								MOV	id 	[@0]

								MOV xposi @2
								MOV zposi @3

							JMP	dxp_door_hit
	
					@dxp_no_door:
					MOV# @5 0.0; rem no offset
					rem ==========

					ADD @2 1
					ADD# zposf dzdx_inv
					MOV# @0 zposf
					FTI @0
					MOV @3 @0

					CMP @3 0
					JL dx_failed
					CMP @3 rc_MapH
					JGE dx_failed

					MOV @0 rc_Map
					MOV @1 @2
					MUL @1 rc_MapH
					ADD @1 @3
					STP @0 @1
					MOV id [@0]

					JMP dxp_loop
				@dxp_end:

				MOV xposi @2
				MOV zposi @3

				rem xposf = float(xposi)
				MOV @0 xposi
				ITF @0
				MOV# xposf @0

				@dxp_door_hit:


				MOV xtexture id

				rem xutex = width(xtexture) - 1 - int((zposf - float(zposi))*float(width(xtexture)))
				xutex = width(xtexture)
				MOV	@0		xutex
				ITF	@0
				MOV#	@1 	zposf
				SUB#	@1		@5; rem !!!!!!!!!!!
				MOV	@2 	zposi
				ITF	@2
				SUB#	@1 	@2
				MUL#	@0 	@1
				FTI	@0
				MOV	xutex	@0

				MOV# xdistance xposf
				SUB# xdistance xpos
				MUL# xdistance xdistance
				MOV# @0 zposf
				SUB# @0 zpos
				MUL# @0 @0
				ADD# xdistance @0

				JMP dx_done

			rem endif
		endif

		@dx_failed:
			MOV# xdistance 100000.0

		@dx_done:
		


		rem Cast z ray
		zposi = int(zpos)
		if dz = 0.0
			rem MOV# zdistance 100000.0
			JMP dz_failed
		elseif dz < 0.0
			SUB zposi 1

			rem zposf = float(zposi) + 1.0
			MOV @0 zposi
			ADD @0 1
			ITF @0
			MOV# zposf @0

			MOV# xposf zposf
			SUB# xposf zpos
			MUL# xposf dxdz_inv
			ADD# xposf xpos

			rem xposi = int(xposf)
			MOV# @0 xposf
			FTI @0
			MOV xposi @0

			rem if xposi < 0 or xposi >= rc_MapW
			rem	JMP dz_failed
			rem else
			CMP xposi 0
			JL dz_failed
			CMP xposi rc_MapW
			JGE dz_failed

				MOV @2 xposi
				MOV @3 zposi
				MOV @0 rc_Map
				MOV @1 @2
				MUL @1 rc_MapH
				ADD @1 @3
				STP @0 @1
				MOV id [@0]
				MOV#	@5 0.0
				@dzn_loop:
					CMP id 0
					JG dzn_end
				
					rem ==========
					
					MOV	@0 0
					SUB	@0	2
					CMP	id @0
					JNE	dzn_no_door

						MOV# @4 xposf
						SUB#	@4 hdxdz_inv
						MOV#	@0 @4

						FTI	@0

						CMP	@2 @0
						JNE	dzn_no_door


							rem get door param
							MOV# @0	@4

							MOV#	@5		rc_ItemParams
							MOV 	@1		@2
							MUL	@1 	rc_MapH
							ADD	@1 	@3
							STP#	@5 	@1
							MOV#	@5		[@5]
							SUB# 	@0 	@5
							
							FTI	@0
							CMP	@2	@0
							JNE	dzn_no_door

								MOV# xposf	@4
								MOV @0	@3	
								ADD @0	1
								ITF @0
								MOV# zposf	@0
								SUB#	zposf 0.5

								MOV	@0		rc_Items
								MOV 	@1		@2
								MUL	@1 	rc_MapH
								ADD	@1 	@3
								STP	@0 	@1
								MOV	id 	[@0]

								MOV xposi @2
								MOV zposi @3

							JMP	dzn_door_hit
	
					@dzn_no_door:
					MOV# @5 0.0; rem no offset
					rem ==========


					SUB @3 1
					SUB# xposf dxdz_inv

					MOV# @0 xposf
					FTI @0
					MOV @2 @0

					CMP @2 0
					JL dz_failed
					CMP @2 rc_MapW
					JGE dz_failed

					MOV @0 rc_Map
					MOV @1 @2
					MUL @1 rc_MapH
					ADD @1 @3
					STP @0 @1
					MOV id [@0]
	
					JMP dzn_loop
				@dzn_end:
				
				MOV xposi @2
				MOV zposi @3

			
				MOV @0 zposi
				ADD @0 1
				ITF @0
				MOV# zposf @0

				@dzn_door_hit:
				MOV ztexture id

				zutex = width(ztexture)
				MOV	@0		zutex
				ITF	@0
				MOV#	@1 	xposf
				SUB#	@1		@5
				MOV	@2 	xposi
				ITF	@2
				SUB#	@1 	@2
				MUL#	@0 	@1
				FTI	@0
				MOV	zutex	@0

				MOV# zdistance xposf
				SUB# zdistance xpos
				MUL# zdistance zdistance
				MOV# @0 zposf
				SUB# @0 zpos
				MUL# @0 @0
				ADD# zdistance @0
				
				JMP dz_done
rem			endif
		else
			ADD zposi 1
			rem zposf = float(zposi)
			MOV @0 zposi
			ITF @0
			MOV# zposf @0

			MOV# xposf zposf
			SUB# xposf zpos
			MUL# xposf dxdz_inv
			ADD# xposf xpos

			rem xposi = int(xposf)
			MOV# @0 xposf
			FTI @0
			MOV xposi @0

	rem		if xposi < 0 or xposi >= rc_MapW
	rem			JMP dz_failed
		rem	else
			CMP xposi 0
			JL dz_failed
			CMP xposi rc_MapW
			JGE dz_failed

				MOV @2 xposi
				MOV @3 zposi
				MOV @0 rc_Map
				MOV @1 @2
				MUL @1 rc_MapH
				ADD @1 @3
				STP @0 @1
				MOV id [@0]
				MOV#	@5		0.0
				@dzp_loop:
					CMP id 0
					JG dzp_end

					rem ==========
					
					MOV	@0 0
					SUB	@0	2
					CMP	id @0
					JNE	dzp_no_door

						MOV#	@4 xposf
						ADD#	@4 hdxdz_inv
						MOV#	@0 @4

						FTI	@0

						CMP	@2 @0
						JNE	dzp_no_door


							rem get door param
							MOV# @0	@4

							MOV#	@5		rc_ItemParams
							MOV 	@1		@2
							MUL	@1 	rc_MapH
							ADD	@1 	@3
							STP#	@5 	@1
							MOV#	@5		[@5]
							SUB# 	@0 	@5
							
							FTI	@0
							CMP	@2	@0
							JNE	dzp_no_door

								MOV# xposf	@4
								MOV @0	@3
								ADD @0	1
								ITF @0
								MOV# zposf	@0
								SUB#	zposf 0.5

								MOV	@0		rc_Items
								MOV 	@1		@2
								MUL	@1 	rc_MapH
								ADD	@1 	@3
								STP	@0 	@1
								MOV	id 	[@0]

								MOV xposi @2
								MOV zposi @3

							JMP	dzp_door_hit
	
					@dzp_no_door:
					MOV# @5 0.0; rem no offset
					rem ==========


					ADD @3 1
					ADD# xposf dxdz_inv
					MOV# @0 xposf
					FTI @0
					MOV @2 @0

					CMP @2 0
					JL dz_failed
					CMP @2 rc_MapW
					JGE dz_failed

					MOV @0 rc_Map
					MOV @1 @2
					MUL @1 rc_MapH
					ADD @1 @3
					STP @0 @1
					MOV id [@0]

					JMP dzp_loop
				@dzp_end:

				MOV xposi @2
				MOV zposi @3

				rem zposf = float(zposi)
				MOV @0 zposi
				ITF @0
				MOV# zposf @0

				@dzp_door_hit:

				MOV ztexture id
				rem zutex = int((xposf - float(xposi))*float(width(ztexture)))
				zutex = width(ztexture)
				MOV 	@1 	xposi
				ITF 	@1
				MOV#	@0 	xposf
				SUB#	@0		@5
				SUB# 	@0		@1
				MOV	@1		zutex
				ITF 	@1
				MUL#	@0		@1
				FTI	@0
				SUB	zutex	1
				SUB	zutex	@0				

				MOV# zdistance xposf
				SUB# zdistance xpos
				MUL# zdistance zdistance
				MOV# @0 zposf
				SUB# @0 zpos
				MUL# @0 @0
				ADD# zdistance @0

				JMP dz_done
		endif

		@dz_failed:
			MOV# zdistance 100000.0
		@dz_done:


		if xdistance < zdistance
			MOV t xtexture
			xdistance = sqr(xdistance)*rc_AngleOffsetCos[col]
			rc_ZBuffer[col] = xdistance

			rem ysize = int(rc_Unit/xdistance)/2
			MOV# @0 rc_Unit
			DIV# @0 xdistance
			FTI @0
			DIV @0 2
			MOV ysize @0

			MOV texu xutex

			rem Darkness.
			MOV# @1 xdistance
			SUB# @1 rc_FogMin
			MUL# @1 rc_FogSpread
			FTI @1
rem			MOV alpha 255
rem			SUB alpha @1
			MOV alpha @1

		else
			MOV t ztexture
			zdistance = sqr(zdistance)*rc_AngleOffsetCos[col]
			rc_ZBuffer[col] = zdistance

			rem ysize = int(rc_Unit/zdistance)/2
			MOV# @0 rc_Unit
			DIV# @0 zdistance
			FTI @0
			DIV @0 2
			MOV ysize @0

			MOV texu zutex

			rem Darkness
			MOV# @1 zdistance
			SUB# @1 rc_FogMin
			MUL# @1 rc_FogSpread
			FTI @1
rem			MOV alpha 255
rem			SUB alpha @1


			MOV alpha @1

		endif

		if alpha < 255			
			set color rc_FogR, rc_FogG, rc_FogB, alpha
			MOV y rc_Height
			DIV y 2
			SUB y ysize
rem			 draw vraster t, texu, col, y, ysize*2

			rem procedure VRASTER(img, ustart#, vstart#, uend#, vend#, x, ystart, yend)
			draw vraster t, col, y, y +ysize*2, float(texu)/float(width(t)), 0.0, float(texu)/float(width(t)), 1.0
		endif
		ADD col 1
	until col = rc_Width

	proc RC_RenderObjects xpos, zpos, angle
endproc

procedure RC_DrawFloorAndCeiling(xpos#, zpos#, angle#)
	xk#
	zk#
	xf#
	zf#
	xi
	zi
	ustart#
	vstart#
	uend#
	vend#

	dstart#
	xstart#
	zstart#
	
	dend#
	xend#

	dx#
	dz#
	
	screenxstart#
	screendx#
	screenxend#

	oldxi
	oldzi
	xk#
	zk#
	
	d#

	h = rc_Height
	hh = rc_Height/2 - 4
	w = rc_Width - 1
	y = 0

	alpha
	id
	do



		dstart# = rc_Distance[0][y]
		xstart# = xpos + dstart*cos(angle + rc_AngleOffset[0])
		zstart# = zpos + dstart*sin(angle + rc_AngleOffset[0])

		dend# = rc_Distance[w][y]
		xend# = xpos + dend*cos(angle + rc_AngleOffset[w])
		zend# = zpos + dend*sin(angle + rc_AngleOffset[w])

		MOV# dx xend
		SUB# dx xstart
		MOV# dz zend
		SUB# dz zstart

		
		rem d# = sqr(dx*dx + dz*dz)
		MOV# d dx
		MUL# d d
		MOV# @0 dz
		MUL# @0 @0
		ADD# d @0
		d# = sqr(d)

		MOV# @0 1.0
		DIV# @0 d
		MUL# dx @0
		MUL# dz @0

		MOV# screenxstart 0.0

		MOV @0 w
		ITF @0
		DIV# @0 d
		MOV# screendx @0

		MOV# @0 xstart
		FTI @0
		MOV xi @0
		MOV# @0 zstart
		FTI @0
		MOV zi @0

		MOV# ustart xstart		
		MOV# @0 xstart
		FTI @0
		ITF @0
		SUB# ustart @0

		MOV# vstart zstart
		MOV# @0 zstart
		FTI @0
		ITF @0
		SUB# vstart @0

			

		rem Fog.
		MOV @3 rc_Height
		DIV @3 2
		MOV @2 rc_Width
		DIV @2 2
		MUL @2 @3
		ADD @2 y

		MOV# @1 rc_Distance
		STP# @1 @2
		MOV# @1 [@1]
		SUB# @1 rc_FogMin
		MUL# @1 rc_FogSpread
		FTI @1
		MOV alpha @1


		if y >= hh or alpha >= 255
			break
		else
			set color rc_FogR, rc_FogG, rc_FogB, alpha
		endif


		rem MOVE SOME STUFF TO REGISTERS, YOU FOOL!!
		@fc_row_loop:
			MOV oldxi xi
			MOV oldzi zi

			rem dx step.

			CMP# dx 0.0
			JE# no_dx
			JG# dxp
				rem dx < 0
				CMP oldxi 0
				JL fc_row_loop_end

				SUB xi 1

				MOV @0 xi
				ADD @0 1
				ITF @0
				MOV# xf @0


				MOV# xk xf
				SUB# xk xstart
				DIV# xk dx

				JMP dx_end

			@dxp:
				rem dx > 0
				CMP oldxi rc_MapW
				JGE fc_row_loop_end

				ADD xi 1

				MOV @0 xi
				ITF @0
				MOV# xf @0

				MOV# xk xf
				SUB# xk xstart
				DIV# xk dx
				
				JMP dx_end
			@no_dx:
				MOV# xk 100000.0
			@dx_end:

			rem dz step.

			CMP# dz 0.0
			JE# no_dz
			JG# dzp
				rem dz < 0
				CMP oldzi 0
				JL fc_row_loop_end
				SUB zi 1

				MOV @0 zi
				ADD @0 1
				ITF @0
				MOV# zf @0

				MOV# zk zf
				SUB# zk zstart
				DIV# zk dz

				JMP dz_end
			@dzp:
				rem dz > 0
				CMP oldzi rc_MapH
				JGE fc_row_loop_end
				ADD zi 1

				MOV @0 zi
				ITF @0
				MOV# zf @0

				MOV# zk zf
				SUB# zk zstart
				DIV# zk dz
			
				JMP dz_end
			@no_dz:
				MOV# zk 100000.0
			@dz_end:

			CMP# xk zk
			JG# fc_zk
			rem if xk < zk

				CMP# dz 0.0
				JE# fc_dz_no_step
				JGE# fc_dz_neg_step
					ADD zi 1
					JMP fc_dz_no_step
				@fc_dz_neg_step:
					SUB zi 1
				@fc_dz_no_step:

				CMP# dx 0.0
				JG# fc_uone
					MOV# uend 0.0
					JMP fc_udone
				@fc_uone:
					MOV# uend 1.0
				@fc_udone:

				MOV# xend xf
				MOV# zend xk
				MUL# zend dz
				ADD# zend zstart
	
				MOV# vend zend
				MOV# @0 zend
				FTI @0
				ITF @0
				SUB# vend @0

				MOV# screenxend xk
				MUL# screenxend screendx
				ADD# screenxend screenxstart
				
				JMP fc_zdone
			rem else
			@fc_zk:
				CMP# dx 0.0
				JE# fc_dx_no_step
				JGE# fc_dx_neg_step
					ADD xi 1
					JMP fc_dx_no_step
				@fc_dx_neg_step:
					SUB xi 1
				@fc_dx_no_step:
		
				CMP# dz 0.0
				JG# fc_vone
					MOV# vend 0.0
					JMP fc_vdone
				@fc_vone:
					MOV# vend 1.0
				@fc_vdone:

				MOV# zend zf
				MOV# xend zk
				MUL# xend dx
				ADD# xend xstart

				MOV# uend xend
				MOV# @0 xend
				FTI @0
				ITF @0
				SUB# uend @0

				MOV# screenxend zk
				MUL# screenxend screendx
				ADD# screenxend screenxstart
			rem endif
			@fc_zdone:

			CMP oldxi 0
			JL no_ceiling_draw
			CMP oldxi rc_MapW
			JGE no_ceiling_draw
			CMP oldzi 0
			JL no_ceiling_draw
			CMP oldzi rc_MapH
			JGE no_ceiling_draw

{			MOV @0 rc_Map
			MOV @1 oldxi
			MUL @1 rc_MapH
			ADD @1 oldzi
			STP @0 @1
			CMP [@0] 0}

			MOV @1 oldxi
			MUL @1 rc_MapH
			ADD @1 oldzi

			MOV @0 rc_Floor
			STP @0 @1
			CMP [@0] 0
			JLE no_floor_draw
				PSH @1
				MOV id [@0]
				draw hraster id, h - 1 - y, int(screenxstart), int(screenxend), ustart, vstart, uend, vend
				POP @1
			@no_floor_draw:
			MOV @0 rc_Ceiling
			STP @0 @1
			CMP [@0] 0
			JLE no_ceiling_draw
				MOV id [@0]
				draw hraster id, y, int(screenxstart), int(screenxend), ustart, vstart, uend, vend
			@no_ceiling_draw:

			MOV# xstart xend
			MOV# zstart zend
			MOV# screenxstart screenxend

			rem Wrap u texture coordinate.
			CMP# uend 0.0
			JE# fc_u_zero
			CMP# uend 1.0
			JE# fc_u_one
				MOV# ustart uend
				JMP fc_u_done
			@fc_u_zero:
				MOV# ustart 1.0
				JMP fc_u_done
			@fc_u_one:
				MOV# ustart 0.0
			@fc_u_done:

			rem Wrap v texture coordinate.
			CMP# vend 0.0
			JE# fc_v_zero
			CMP# vend 1.0
			JE# fc_v_one
				MOV# vstart vend
				JMP fc_v_done
			@fc_v_zero:
				MOV# vstart 1.0
				JMP fc_v_done
			@fc_v_one:
				MOV# vstart 0.0
			@fc_v_done:

			MOV @0 w
			ITF @0
			CMP# screenxend @0
			JGE# fc_row_loop_end
			JMP fc_row_loop
		@fc_row_loop_end:

		ADD y 1
	loop
endproc

function RC_ObstacleAt(x, z)
	m = rc_Map[x][z]
	if m > 0 then return true
	if m < 0 and rc_ItemParams[x][z] < 1.0 then return true
	return false
endfunc

function RC_Move#[](dist#, xpos#, zpos#, dx#, dz#)
	x = int(xpos)
	z = int(zpos)
	upperdist# = 1.0 - dist
	
	xnocol# = xpos + dx
	znocol# = zpos + dz
	xnew# = xnocol
	znew# = znocol
	
	r  = RC_ObstacleAt(x + 1, z)
	br = RC_ObstacleAt(x + 1, z - 1)
	b  = RC_ObstacleAt(x, z-1)
	bl = RC_ObstacleAt(x - 1, z - 1)
	l  = RC_ObstacleAt(x - 1, z)
	tl = RC_ObstacleAt(x - 1, z + 1)
	t  = RC_ObstacleAt(x, z + 1)
	tr = RC_ObstacleAt(x + 1, z + 1)

	rc_CollisionInfo[RC_EAST] = false
	rc_CollisionInfo[RC_WEST] = false
	rc_CollisionInfo[RC_NORTH] = false
	rc_CollisionInfo[RC_SOUTH] = false

	if xpos + dx > float(x) + upperdist
		if r or (t = 0 and tr and zpos > float(z) + upperdist) or (b = 0 and br and zpos < float(z) + dist)
	      xnew = float(x) + upperdist
			rc_CollisionInfo[RC_EAST] = true
		endif
	endif


	if xpos + dx < float(x) + dist
		if l or (t = 0 and tl and zpos > float(z) + upperdist) or (b = 0 and bl and zpos < float(z) + dist)
			xnew = float(x) + dist
			rc_CollisionInfo[RC_WEST] = true
		endif
	endif


	if zpos + dz > float(z) + upperdist
		if t or (r = 0 and tr and xpos > float(x) + upperdist) or (l = 0 and tl and xpos < float(x) + dist)
			znew = float(z) + upperdist
			rc_CollisionInfo[RC_NORTH] = true
		endif
	endif

	if zpos + dz < float(z) + dist
		if b or (r = 0 and br and xpos > float(x) + upperdist) or (l = 0 and bl and xpos < float(x) + dist)
			znew = float(z) + dist
			rc_CollisionInfo[RC_SOUTH] = true
		endif
	endif

	return [xnew, znew]
endproc

function RC_GetCollisionInfo[]()
	return rc_CollisionInfo
endfunc

rem Set fog.
procedure RC_SetFog(r, g, b, zMin#, zMax#)
	rc_FogR = r
	rc_FogG = g
	rc_FogB = b
	rc_FogMin = zMin#
	rc_FogMax = zMax#
	rc_FogSpread = 255.0/(zMax - zMin)
endproc

rem En objektbeskrivning, bara info om en bild, behver:
rem 	x
rem 	z
rem   xtransformed
rem	ztransformed
rem   y
rem	avstnd
rem	bredd
rem   hjd
rem	bild
rem
rem Det r inte den typen av data man bara skyflar runt och
rem kan sortera i naalaa.
rem Jag freslr att alla objekt ligger statiskt i en lista.
rem Givetvis kan anvndaren plocka bort, lgga till och flytta
rem objekt. Mnga objekt r dock bundna till items p ngot
rem vis.
rem    Du har, som i SimpleWidget, en lista som sorteras
rem vid varje rendering med index till den statiska listan.
rem
rem En fundering: Om ett objekt inte fr vara strre n 1.0 och
rem varken dess vnstra eller hgra kant har ett synligt distance,
rem kan d ngon del av objektet vara synligt? Nej, jag tror
rem fanimig inte det.
rem    Vid sorteringen skall du:
rem    Plocka bort objekt som har ett distance >= fogMax
rem	 Plocka bort objekt dr bde hger och vnster r osynliga,
rem       och hr ingr givetvis sdant som faller utanfr syn-
rem       vinkeln 
rem    Sortera efter avstnd

rem S, orrliga objekt kommer frn levelfilen.
rem Anvndaren kan lgga till, ndra och ta bort objekt, vilket
rem krver ID. 
rem    Ev lgger anvndaren redan frn brjan in alla de objekt
rem som behvs, typ fiender och spelarskott men kan sedan av-
rem aktivera dem o.s.v.via deras ID. D slipper du bka runt i
rem listan.
rem    Eller nej. Ej bestmma i frvg. Man kan lgga till och
rem plocka bort. Men listan "defragmenteras" aldrig, utan det
rem finns ett utrymme efter de statiska objekten dr objekt
rem helt enkelt fr frsta bsta plats ...

procedure RC_AddObject(id, img, x#, z#, y#, s#, ix, iz)
	rem Ndvndigt att kolla efter dubletter?
	if width(img) > height(img)
		w# = s
		h# = s*float(height(img))/float(width(img))
	else
		h# = s
		w# = s*float(width(img))/float(height(img))
	endif
	y = 0.5 - y - h
	index = -1
	for i = 0 to RC_MAX_OBJECTS - 1
		MOV#	@0		rc_Objects
		MOV	@1		i
		MUL	@1		11
		STP#	@0		@1
		CMP	[@0]	0
		JNE	rc_ao_no_obj
			MOV	index	i
			break
		@rc_ao_no_obj:
	next
	if index >= 0
		rem Move to index.
		MOV#	@0			rc_Objects
		MOV	@1			index
		MUL	@1			11
		STP#	@0			@1

		rem Set values.
		MOV	[@0]		id
		STP#	@0			1
		MOV	[@0]		img
		STP#	@0			1
		MOV#	[@0]		x
		STP#	@0			1
		MOV#	[@0]		z
		STP#	@0			1
		MOV#	[@0]		y
		STP#	@0			3
		MOV#	[@0]		w
		STP#	@0			1
		MOV#	[@0]		h
		STP#	@0			2
		MOV	@2			iz
		MUL	@2			rc_MapW
		ADD	@2			ix
		MOV	[@0]		@2

		rc_ObjOrder[rc_ObjCount] = index
		ADD	rc_ObjCount		1
	endif
endproc

procedure RC_ModifyObject(id, img, x#, z#, y#)
	index = -1
	for i = 0 to RC_MAX_OBJECTS - 1
		MOV#	@0		rc_Objects
		MOV	@1		i
		MUL	@1		11
		STP#	@0		@1
		CMP	[@0]	id
		JNE	rc_mo_no_obj
			MOV	index	i
			break
		@rc_mo_no_obj:
	next

	if index >= 0
		y = 0.5 - y - rc_Objects[index][RC_OBJ_H]

		rem Move to index.
		MOV#	@0			rc_Objects
		MOV	@1			index
		MUL	@1			11
		ADD	@1			1
		STP#	@0			@1

		rem Set values.
		MOV	[@0]		img
		STP#	@0			1
		MOV#	[@0]		x
		STP#	@0			1
		MOV#	[@0]		z
		STP#	@0			1
		MOV#	[@0]		y
	endif
endproc

procedure RC_SetObjectImage(id, img)
	index = -1
	for i = 0 to RC_MAX_OBJECTS - 1
		MOV#	@0		rc_Objects
		MOV	@1		i
		MUL	@1		11
		STP#	@0		@1
		CMP	[@0]	id
		JNE	rc_soi_no_obj
			MOV	index	i
			break
		@rc_soi_no_obj:
	next

	if index >= 0
		rem Move to index.
		MOV#	@0			rc_Objects
		MOV	@1			index
		MUL	@1			11
		ADD	@1			1
		STP#	@0			@1

		rem Set values.
		MOV	[@0]		img
	endif
endproc

procedure RC_SetObjectPos(id, x#, z#, y#)
	index = -1
	for i = 0 to RC_MAX_OBJECTS - 1
		MOV#	@0		rc_Objects
		MOV	@1		i
		MUL	@1		11
		STP#	@0		@1
		CMP	[@0]	id
		JNE	rc_sop_no_obj
			MOV	index	i
			break
		@rc_sop_no_obj:
	next

	if index >= 0
		y = 0.5 - y - rc_Objects[index][RC_OBJ_H]

		rem Move to index.
		MOV#	@0			rc_Objects
		MOV	@1			index
		MUL	@1			11
		ADD	@1			2
		STP#	@0			@1

		rem Set values.
		MOV#	[@0]		x
		STP#	@0			1
		MOV#	[@0]		z
		STP#	@0			1
		MOV#	[@0]		y
	endif
endproc

rem Remove item at (x, z) and its corresponding object.
procedure RC_RemoveItem(x, z)
	if rc_Items[x][z] = 0 then return

	rc_Items[x][z] = 0

	xz = z*rc_MapW + x
	index = -1
	for i = 0 to RC_MAX_OBJECTS - 1
		MOV#	@0		rc_Objects
		MOV	@1		i
		MUL	@1		11
		ADD	@1		10
		STP#	@0		@1
		CMP	[@0]	xz
		JNE	rc_ri_no_obj
			MOV	index	i
			break
		@rc_ri_no_obj:
	next
	if index >= 0
		MOV#	@0			rc_Objects
		MOV	@1			index
		MUL	@1			11
		STP#	@0			@1
		MOV	[@0]		0

		for i = 0 to RC_MAX_OBJECTS - 1
			if rc_ObjOrder[i] = index
				for j = i to rc_ObjCount - 2
					rc_ObjOrder[j] = rc_ObjOrder[j + 1]
				next
				rc_ObjCount = rc_ObjCount - 1
				break
			endif
		next

		rc_Map[x][z] = 0
	endif

endproc

procedure RC_RemoveObject(id)
	index = -1
	for i = 0 to RC_MAX_OBJECTS - 1
		MOV#	@0		rc_Objects
		MOV	@1		i
		MUL	@1		11
		STP#	@0		@1
		CMP	[@0]	id
		JNE	rc_ro_no_obj
			MOV	index	i
			break
		@rc_ro_no_obj:
	next
	if index >= 0
		rem Move to index.
		MOV#	@0			rc_Objects
		MOV	@1			index
		MUL	@1			11
		STP#	@0			@1

		MOV	[@0]		0

		for i = 0 to RC_MAX_OBJECTS - 1
			if rc_ObjOrder[i] = index
				for j = i to rc_ObjCount - 2
					rc_ObjOrder[j] = rc_ObjOrder[j + 1]
				next
				rc_ObjCount = rc_ObjCount - 1
				break
			endif
		next
	endif
endproc

function RC_HasObject(id)
	index = -1
	for i = 0 to RC_MAX_OBJECTS - 1
		MOV#	@0		rc_Objects
		MOV	@1		i
		MUL	@1		11
		STP#	@0		@1
		CMP	[@0]	id
		JNE	rc_ho_no_obj
			MOV	index	i
			break
		@rc_ho_no_obj:
	next
	if index >= 0 then return true
	return false
endfunc

rem ==================================================================
rem Process objects before rendering.
rem ==================================================================
procedure RC_ProcessObjects(xpos#, zpos#, angle#)
	rem Calculate distance between objects and view point.
	dx#
	dz#
	for i = 0 to RC_MAX_OBJECTS - 1
		MOV#	@0		rc_Objects
		MOV	@1		i
		MUL	@1		11
		STP#	@0		@1
		CMP	[@0]	0
		JE		rc_po_d_no_obj
			rem dx.
			STP# 	@0		2
			MOV#	@1		[@0]; rem obj x.
			SUB#	@1		xpos
			MUL#	@1		@1

			rem dy.
			STP#	@0		1
			MOV#	@2		[@0]; rem obj y.
			SUB#	@2		zpos
			MUL#	@2		@2

			ADD#	@1		@2

			rem d.
			STP#	@0		6
			MOV#	[@0]	@1
		@rc_po_d_no_obj:
	next

	rem Sort the objects.
	proc RC_SortObjects
endproc

rem ==================================================================
rem Sort objects.
rem    Yes, bubble sort is used, since the changes in the list are
rem usually very small.
rem ==================================================================
procedure RC_SortObjects()
{	beg = 0
	endi = rc_ObjCount - 2
	do
		noswap = true
		for i = beg to endi
			if rc_Objects[rc_ObjOrder[i]][RC_OBJ_D] < rc_Objects[rc_ObjOrder[i + 1]][RC_OBJ_D]
				tmp = rc_ObjOrder[i]
				rc_ObjOrder[i] = rc_ObjOrder[i + 1]
				rc_ObjOrder[i + 1] = tmp
				noswap = false
			endif
		next
		beg = beg + 1
	until noswap

}

	beg = 0
	endi = rc_ObjCount - 2
	noswap

	@rc_so_loop:
		MOV	noswap	1

		MOV	@5	beg
		@rc_so_sort:

			MOV	@1	rc_ObjOrder
			STP	@1	@5
			PSH	@1
			MOV	@1	[@1]
			MUL	@1	11
			ADD	@1	9

			MOV	@2	rc_ObjOrder
			STP	@2	@5
			STP	@2	1
			PSH	@2
			MOV	@2	[@2]
			MUL	@2	11
			ADD	@2	9

			MOV#	@0	rc_Objects
			STP#	@0	@1
			MOV#	@1	[@0]
			
			MOV#	@0	rc_Objects
			STP#	@0	@2
			MOV#	@2	[@0]
			
			CMP#	@1	@2
			JGE#	rc_so_no_swap
				MOV	noswap	0
				POP	@2
				POP	@1
				MOV	@3	[@2]
				MOV	[@2]	[@1]
				MOV	[@1]	@3
				JMP rc_so_swap_done
			@rc_so_no_swap:
				POP @0
				POP @0
			@rc_so_swap_done:

		ADD	@5	1
		CMP	@5 endi
		JLE	rc_so_sort
		
		ADD	beg	1

	CMP	noswap	1
	JNE	rc_so_loop



endproc

rem ==================================================================
rem Render objects.
rem ==================================================================
procedure RC_RenderObjects(xpos#, zpos#, angle#)
	rem Process objects before rendering.
	proc RC_ProcessObjects xpos, zpos, angle

	img
	x
	y
	w
	h
	d#
	u_x#
	u_z#
	v_x#
	v_z#
	hyp#
	k#
	dp#
	a#

	index
	for i = 0 to rc_ObjCount - 1
		MOV	@1		rc_ObjOrder
		STP	@1		i
		MOV	@1		[@1]

		MOV 	index @1
		MUL	@1		11

		MOV#	@0		rc_Objects
		STP#	@0		@1

		rem Check if object is active.
		CMP	[@0]	0
		JE 	rc_ro_break

			rem Transform.
			STP#	@0		1
			MOV 	img	[@0]

			u_x = cos(angle)
			u_z = sin(angle)
			v_x = rc_Objects[index][RC_OBJ_X] - xpos
			v_z = rc_Objects[index][RC_OBJ_Z] - zpos

			hyp = sqr(v_x*v_x + v_z*v_z)
			CMP# hyp 0.0
			JE rc_ro_continue
			
			k = 1.0/hyp
			MUL# v_x	k
			MUL# v_z k

			dp = v_x*u_x + v_z*u_z

			if dp <= 0.1 
				JMP rc_ro_continue
			endif

			if dp >= 1.0
				a = 0.0
			else
				a = acos(dp)
			endif

			if u_x*v_z - u_z*v_x < 0.0
				rc_Objects[index][RC_OBJ_TX] = float(rc_Width/2) - rc_Unit*tan(a)
			else
				rc_Objects[index][RC_OBJ_TX] = float(rc_Width/2) + rc_Unit*tan(a)
			endif
		
			rc_Objects[index][RC_OBJ_D] = hyp*cos(a)

			if rc_Objects[index][RC_OBJ_D] >= rc_FogMax
				JMP rc_ro_continue
			endif


			size# = rc_Unit/rc_Objects[index][RC_OBJ_D]
			x = int(rc_Objects[index][RC_OBJ_TX] - size*rc_Objects[index][RC_OBJ_W]*0.5)
			y = int(float(rc_Height/2) + size*rc_Objects[index][RC_OBJ_Y])
			d = rc_Objects[index][RC_OBJ_D]
			w = int(size*rc_Objects[index][RC_OBJ_W])
			h = int(size*rc_Objects[index][RC_OBJ_H])

			if x + w < 0 or x >= rc_Width
				JMP rc_ro_continue
			endif

			proc RC_DrawImage img, x, y, w, h, d
			
			JMP rc_ro_continue
		@rc_ro_break:
			break
		@rc_ro_continue:
		
	next

endproc

procedure RC_DrawImage(img, imgx, imgy, w, h, d#)
	alpha
	MOV# @1 d
	SUB# @1 rc_FogMin
	MUL# @1 rc_FogSpread
	FTI @1
	MOV alpha @1

	set color rc_FogR, rc_FogG, rc_FogB, alpha
rem	uStep# = float(width(img))/float(w)
	uStep# = 1.0/float(w)
	u# = 0.0

	if imgx < 0
		u = u + uStep*float(-imgx)
		w = w + imgx
		imgx = 0
	endif

	xend = min(imgx + w, rc_Width)
	
	h = imgy + h

	x
	MOV	@0		imgx
	MOV#	@1		rc_ZBuffer
	STP#	@1		@0

	@rc_di_loop:
		CMP	@0		xend
		JGE 	rc_di_loop_end
		
		CMP#	d	[@1]
		JG#	rc_di_no_draw
			MOV x @0
			PSH @0
			PSH @1
rem			draw vraster img, int(u), x, imgy, h
			rem draw vraster t, col, y, y +ysize*2, float(texu)/float(width(t)), 0.0, float(texu)/float(width(t)), 1.0
				draw vraster img, x, imgy, h, u, 0.0, u, 1.0
			POP @1
			POP @0
		@rc_di_no_draw:
		ADD	@0		1
		STP#	@1		1
		ADD#	u		uStep

		JMP	rc_di_loop
	@rc_di_loop_end:
endproc

rem ==================================================================
rem Return wall in front of position.
rem ==================================================================
function RC_FacingWall(x#, z#, angle#)
	x# = x# + cos(angle)
	z# = z# + sin(angle)
	ix = int(x)
	iz = int(z)
	if ix < 0 then return 0
	if ix >= rc_MapW then return 0
	if iz < 0 then return 0
	if iz >= rc_MapH then return 0
	return rc_Map[ix][iz]
endfunc

function RC_FacingPos[](x#, z#, angle#)
	x# = x# + cos(angle)
	z# = z# + sin(angle)
	ix = int(x)
	iz = int(z)
	return [ix, iz]
endfunc

function RC_GetDoor(x, z)
	if sizeof(rc_Map) = 0 then return 0
	if rc_Map[x][z] = -1 or rc_Map[x][z] = -2
		return rc_Doors[x][z]
	endif
	return 0
endfunc

rem	rcOpenDoorCount = 0
rem	rc_OpenDoors[RC_MAX_DOORS][2]


procedure RC_OpenDoor(x, y)
	isopen = false
	if RC_GetDoor(x, y) = 0 then return
	if rc_OpenDoorCount > 0
		for i = 0 to rc_OpenDoorCount - 1
			if rc_OpenDoors[i][0] = x and rc_OpenDoors[i][1] = y
				isopen = true
				break
			endif
		next
	endif
	if not isopen
		rc_OpenDoors[rc_OpenDoorCount][0] = x
		rc_OpenDoors[rc_OpenDoorCount][1] = y
		ADD rc_OpenDoorCount 1
	endif
endproc

procedure RC_Update(k#)
	if rc_OpenDoorCount > 0
		for i = 0 to rc_OpenDoorCount - 1
			x = rc_OpenDoors[i][0]
			y = rc_OpenDoors[i][1]
			if rc_ItemParams[x][y] < 1.0	
				rc_ItemParams[x][y] = min#(rc_ItemParams[x][y] + rc_DoorSpeed*k, 1.0)
			endif
		next
	endif
endproc

procedure RC_DrawScaledImage(img, imgx, imgy, w, h)
	uStep# = 1.0/float(w)
	u# = 0.0

	if imgx < 0
		u = u + uStep*float(-imgx)
		w = w + imgx
		imgx = 0
	endif

	h = imgy + h - 1

	set color 255, 255, 255, 0
	for x = imgx to imgx + w - 1
		draw vraster img, x, imgy, h, u, 0.0, u, 1.0
		u = u + uStep
	next
endproc

procedure RC_SetDoor(x, z, type, img, alongZ)
	if sizeof(rc_Map) = 0 then return
	if type = 0
		rc_Map[x][z] = 0
		rc_Items[x][z] = 0
		rc_Doors[x][z] = 0
	else 
		if alongZ
			rc_Map[x][z] = -1
		else
			rc_Map[x][z] = -2
		endif
		rc_Items[x][z] = img
		rc_Doors[x][z] = type
	endif
endproc

procedure DebugMsg(msg$)
	set color 0, 0, 0
	cls
	set color 255, 255, 255
	set caret 0, 0
	wln msg$
	redraw
	wait keydown
endproc

function RC_LoadMap[][](filename$)
	flags[][]
	open file 0, filename$
	if not file(0) then return flags

	for i = len(filename) - 1 downto 0
		if mid$(filename, i) = "/" or mid$(filename$, i) = "\"
			pos = i + 1
			break
		endif
	next
	path$ = left$(filename, pos)

	rem Images.
	count = read(0)
	for i = 0 to count - 1
		index = read(0)
		load image index + 1000, path + read$(0)
		ck = read(0)
		ckr = read(0)
		ckg = read(0)
		ckb = read(0)
		if ck then set image colorkey index + 1000, ckr, ckg, ckb
	next

	rem Objects.
	objects[64][4]
	count = read(0)
	for i = 0 to count - 1
		index = read(0)
		objects[index][0] = read(0)
		objects[index][1] = read(0)
		objects[index][2] = read(0)
		objects[index][3] = read(0)
	next

	rem Fog.
	fogActive = read(0)
	fogR = read(0)
	fogG = read(0)
	fogB = read(0)
	fogZMin# = read#(0)
	fogZMax# = read#(0)

	rem Map.
	mapW = read(0)
	mapH = read(0)
	map[mapW][mapH][6]
	for i = 0 to 5
		for z = 0 to mapH - 1
			for x = 0 to mapW - 1
				map[x][z][i] = read(0)
			next
		next
	next
	playerX = read(0)
	playerZ = read(0)
	playerAngle = read(0)
	free file 0

	proc RC_SetFog fogR, fogG, fogB, fogZMin, fogZMax
	proc RC_InitMap mapW, mapH

	WALL			= 0
	FLOOR			= 1
	CEILING		= 2
	OBJECT		= 3
	GAME_FLAG	= 4
	LOADER_FLAG	= 5
	flagCount = 0
	for z = 0 to mapH - 1
		for x = 0 to mapW - 1
			if map[x][z][LOADER_FLAG] then flagCount = flagCount + 1
			if map[x][z][WALL]
				if map[x][z][WALL] = -1
					proc RC_SetDoor x, z, -map[x][z][OBJECT], 1000 - map[x][z][OBJECT], true
				elseif map[x][z][WALL] = -2
					proc RC_SetDoor x, z, -map[x][z][OBJECT], 1000 - map[x][z][OBJECT], false
				else
					proc RC_SetWall x, z, map[x][z][WALL] + 1000
				endif
			endif
			if map[x][z][FLOOR]
				proc RC_SetFloor x, z, map[x][z][FLOOR] + 1000
			endif
			if map[x][z][CEILING]
				proc RC_SetCeiling x, z, map[x][z][CEILING] + 1000
			endif
			proc RC_SetFlag x, z, map[x][z][GAME_FLAG]
			if map[x][z][OBJECT] and map[x][z][WALL] = 0
				obj = map[x][z][OBJECT]
				rem [index][image, align, obstacle, size]
				img = objects[obj][0]
				if img and image(img + 1000)
					img = img + 1000
					s# = float(objects[obj][3])/1000.0
					if width(img) > height(img)
						h# = s*float(height(img))/float(width(img))
						w# = s*1.0
					else
						w# = s*float(width(img))/float(height(img))
						h# = s*1.0
					endif
					if objects[obj][1] = 0;		rem Floor.
						y# = 0.0
					elseif objects[obj][1] = 1;	rem Centered.
						y# = 0.5 + h*0.5
					else;									rem Ceiling.
						y# = 1.0 + h
					endif
					if objects[obj][2] then proc RC_SetWall x, z, -3
					proc RC_AddObject -1, img, float(x) + 0.5, float(z) + 0.5, y, s, x, z
					proc RC_SetItem x, z, map[x][z][OBJECT], false
				endif
			endif
		next
	next

	flags[flagCount + 1][3]
	flags[0][0] = playerX
	flags[0][1] = playerZ
	flags[0][2] = playerAngle
	index = 1
	for z = 0 to mapH - 1
		for x = 0 to mapW - 1
			if map[x][z][LOADER_FLAG]
				flags[index][0] = x
				flags[index][1] = z
				flags[index][2] = map[x][z][LOADER_FLAG]
				index = index + 1
			endif
		next
	next

	return flags	
endfunc

function RC_GetImage(id)
	return id + 1000
endfunc

rem ==================================================================
rem Return true if there's no obstacle between (x0, z0) and (x1, z1).
rem ==================================================================
function RC_Visible(xpos#, zpos#, dstx#, dstz#)
	dzdx_inv#
	hdzdx_inv#
	dxdz_inv#
	hdxdz_inv#
	xdistance#
	zdistance#
	xposi
	zposi
	xposf#
	zposf#
	id

	dx# = dstx - xpos
	dz# = dstz - zpos
	distance# = dx*dx + dz*dz
	k# = 1.0/sqr(distance)
	dx = dx*k
	dz = dz*k

		if dx <> 0.0
			MOV# dzdx_inv dz
			DIV# dzdx_inv dx
			
			MOV# hdzdx_inv dzdx_inv
			MUL# hdzdx_inv 0.5
			
		endif
		if dz <> 0.0
			MOV# dxdz_inv dx
			DIV# dxdz_inv dz
				
			MOV# hdxdz_inv dxdz_inv
			MUL# hdxdz_inv 0.5
		endif

		MOV# xdistance 0.0
		MOV# zdistance 0.0

		rem Cast x ray.
		xposi = int(xpos)
		if dx = 0.0
			JMP v_dx_failed
		elseif dx < 0.0
			SUB xposi 1

			MOV @0 xposi
			ITF @0
			ADD# @0 1.0
			MOV# xposf @0

			MOV# zposf xposf
			SUB# zposf xpos
			MUL# zposf dzdx_inv
			ADD# zposf zpos

			rem zposi = int(zposf)
			MOV# @0 zposf
			FTI @0
			MOV zposi @0

			CMP zposi 0
			JL v_dx_failed
			CMP zposi rc_MapH
			JGE v_dx_failed			
				MOV @2 xposi
				MOV @3 zposi
				MOV @0 rc_Map
				MOV @1 @2
				MUL @1 rc_MapH
				ADD @1 @3
				STP @0 @1
				MOV id [@0]
				MOV# @5	0.0
				@v_dxn_loop:
					CMP id 0
					JG v_dxn_end

					rem ==========
					
					MOV	@0 0
					SUB	@0	1
					CMP	id @0
					JNE	v_dxn_no_door

						MOV# @4 zposf
						SUB#	@4 hdzdx_inv
						MOV#	@0 @4

						FTI	@0

						CMP	@3 @0
						JNE	v_dxn_no_door


							rem get door param
							MOV# @0	@4

							MOV#	@5		rc_ItemParams
							MOV 	@1		@2
							MUL	@1 	rc_MapH
							ADD	@1 	@3
							STP#	@5 	@1
							MOV#	@5		[@5]
							SUB# 	@0 	@5
							
							FTI	@0
							CMP	@3	@0
							JNE	v_dxn_no_door

								MOV# zposf	@4
								MOV @0	@2	
								ADD @0	1
								ITF @0
								MOV# xposf	@0
								SUB#	xposf 0.5

								MOV	@0		rc_Items
								MOV 	@1		@2
								MUL	@1 	rc_MapH
								ADD	@1 	@3
								STP	@0 	@1
								MOV	id 	[@0]

								MOV xposi @2
								MOV zposi @3

							JMP	v_dxn_door_hit
	
					@v_dxn_no_door:
					MOV# @5 0.0; rem no offset
					rem ==========

					SUB @2 1
					SUB# zposf dzdx_inv
					MOV# @0 zposf
					FTI @0
					MOV @3 @0

					CMP @3 0
					JL v_dx_failed
					CMP @3 rc_MapH
					JGE v_dx_failed

					MOV @0 rc_Map
					MOV @1 @2
					MUL @1 rc_MapH
					ADD @1 @3
					STP @0 @1
					MOV id [@0]

					JMP v_dxn_loop
				@v_dxn_end:

				MOV xposi @2
				MOV zposi @3
					
				rem xposf = float(xposi) + 1.0
				MOV @0 xposi
				ADD @0 1
				ITF @0
				MOV# xposf @0

				@v_dxn_door_hit:

				MOV# @0 xposf
				SUB# @0 xpos
				MUL# @0 @0
				MOV# @1 zposf
				SUB# @1 zpos
				MUL# @1 @1
				ADD# @0 @1
				MOV# xdistance @0

				JMP v_dx_done
		else
			ADD xposi 1
			xposf = float(xposi)

			MOV# @0 xposf
			SUB# @0 xpos
			MUL# @0 dzdx_inv
			ADD# @0 zpos
			MOV# zposf @0

			MOV# @0 zposf
			FTI @0
			MOV zposi @0
			
			CMP zposi 0
			JL v_dx_failed
			CMP zposi rc_MapH
			JGE v_dx_failed
				MOV @2 xposi
				MOV @3 zposi
				MOV @0 rc_Map
				MOV @1 @2
				MUL @1 rc_MapH
				ADD @1 @3
				STP @0 @1
				MOV id [@0]
				MOV# @5 0.0
				@v_dxp_loop:
					CMP id 0
					JG v_dxp_end
					
					MOV	@0 0
					SUB	@0	1
					CMP	id @0
					JNE	v_dxp_no_door

						MOV#	@4 zposf
						ADD#	@4 hdzdx_inv
						MOV#	@0 @4

						FTI	@0

						CMP	@3 @0
						JNE	v_dxp_no_door


							rem get door param
							MOV# @0	@4

							MOV#	@5		rc_ItemParams
							MOV 	@1		@2
							MUL	@1 	rc_MapH
							ADD	@1 	@3
							STP#	@5 	@1
							MOV#	@5		[@5]
							SUB# 	@0 	@5
							
							FTI	@0
							CMP	@3	@0
							JNE	v_dxp_no_door

								MOV# zposf	@4
								MOV @0	@2	
								ADD @0	1
								ITF @0
								MOV# xposf	@0
								SUB#	xposf 0.5

								MOV	@0		rc_Items
								MOV 	@1		@2
								MUL	@1 	rc_MapH
								ADD	@1 	@3
								STP	@0 	@1
								MOV	id 	[@0]

								MOV xposi @2
								MOV zposi @3

							JMP	v_dxp_door_hit
	
					@v_dxp_no_door:
					MOV# @5 0.0; rem no offset
					rem ==========

					ADD @2 1
					ADD# zposf dzdx_inv
					MOV# @0 zposf
					FTI @0
					MOV @3 @0

					CMP @3 0
					JL v_dx_failed
					CMP @3 rc_MapH
					JGE v_dx_failed

					MOV @0 rc_Map
					MOV @1 @2
					MUL @1 rc_MapH
					ADD @1 @3
					STP @0 @1
					MOV id [@0]

					JMP v_dxp_loop
				@v_dxp_end:

				MOV xposi @2
				MOV zposi @3

				rem xposf = float(xposi)
				MOV @0 xposi
				ITF @0
				MOV# xposf @0

				@v_dxp_door_hit:

				MOV# xdistance xposf
				SUB# xdistance xpos
				MUL# xdistance xdistance
				MOV# @0 zposf
				SUB# @0 zpos
				MUL# @0 @0
				ADD# xdistance @0

				JMP v_dx_done

			rem endif
		endif

		@v_dx_failed:
			MOV# xdistance 100000.0

		@v_dx_done:
		


		rem Cast z ray
		zposi = int(zpos)
		if dz = 0.0
			JMP v_dz_failed
		elseif dz < 0.0
			SUB zposi 1

			MOV @0 zposi
			ADD @0 1
			ITF @0
			MOV# zposf @0

			MOV# xposf zposf
			SUB# xposf zpos
			MUL# xposf dxdz_inv
			ADD# xposf xpos

			MOV# @0 xposf
			FTI @0
			MOV xposi @0

			CMP xposi 0
			JL v_dz_failed
			CMP xposi rc_MapW
			JGE v_dz_failed

				MOV @2 xposi
				MOV @3 zposi
				MOV @0 rc_Map
				MOV @1 @2
				MUL @1 rc_MapH
				ADD @1 @3
				STP @0 @1
				MOV id [@0]
				MOV#	@5 0.0
				@v_dzn_loop:
					CMP id 0
					JG v_dzn_end
				
					MOV	@0 0
					SUB	@0	2
					CMP	id @0
					JNE	v_dzn_no_door

						MOV# @4 xposf
						SUB#	@4 hdxdz_inv
						MOV#	@0 @4

						FTI	@0

						CMP	@2 @0
						JNE	v_dzn_no_door


							rem get door param
							MOV# @0	@4

							MOV#	@5		rc_ItemParams
							MOV 	@1		@2
							MUL	@1 	rc_MapH
							ADD	@1 	@3
							STP#	@5 	@1
							MOV#	@5		[@5]
							SUB# 	@0 	@5
							
							FTI	@0
							CMP	@2	@0
							JNE	v_dzn_no_door

								MOV# xposf	@4
								MOV @0	@3	
								ADD @0	1
								ITF @0
								MOV# zposf	@0
								SUB#	zposf 0.5

								MOV	@0		rc_Items
								MOV 	@1		@2
								MUL	@1 	rc_MapH
								ADD	@1 	@3
								STP	@0 	@1
								MOV	id 	[@0]

								MOV xposi @2
								MOV zposi @3

							JMP	v_dzn_door_hit
	
					@v_dzn_no_door:
					MOV# @5 0.0; rem no offset
					rem ==========


					SUB @3 1
					SUB# xposf dxdz_inv

					MOV# @0 xposf
					FTI @0
					MOV @2 @0

					CMP @2 0
					JL v_dz_failed
					CMP @2 rc_MapW
					JGE v_dz_failed

					MOV @0 rc_Map
					MOV @1 @2
					MUL @1 rc_MapH
					ADD @1 @3
					STP @0 @1
					MOV id [@0]
	
					JMP v_dzn_loop
				@v_dzn_end:
				
				MOV xposi @2
				MOV zposi @3

			
				MOV @0 zposi
				ADD @0 1
				ITF @0
				MOV# zposf @0

				@v_dzn_door_hit:

				MOV# zdistance xposf
				SUB# zdistance xpos
				MUL# zdistance zdistance
				MOV# @0 zposf
				SUB# @0 zpos
				MUL# @0 @0
				ADD# zdistance @0
				
				JMP v_dz_done
		else
			ADD zposi 1
			MOV @0 zposi
			ITF @0
			MOV# zposf @0

			MOV# xposf zposf
			SUB# xposf zpos
			MUL# xposf dxdz_inv
			ADD# xposf xpos

			MOV# @0 xposf
			FTI @0
			MOV xposi @0

			CMP xposi 0
			JL v_dz_failed
			CMP xposi rc_MapW
			JGE v_dz_failed

				MOV @2 xposi
				MOV @3 zposi
				MOV @0 rc_Map
				MOV @1 @2
				MUL @1 rc_MapH
				ADD @1 @3
				STP @0 @1
				MOV id [@0]
				MOV#	@5		0.0
				@v_dzp_loop:
					CMP id 0
					JG v_dzp_end

					rem ==========
					
					MOV	@0 0
					SUB	@0	2
					CMP	id @0
					JNE	v_dzp_no_door

						MOV#	@4 xposf
						ADD#	@4 hdxdz_inv
						MOV#	@0 @4

						FTI	@0

						CMP	@2 @0
						JNE	v_dzp_no_door


							rem get door param
							MOV# @0	@4

							MOV#	@5		rc_ItemParams
							MOV 	@1		@2
							MUL	@1 	rc_MapH
							ADD	@1 	@3
							STP#	@5 	@1
							MOV#	@5		[@5]
							SUB# 	@0 	@5
							
							FTI	@0
							CMP	@2	@0
							JNE	v_dzp_no_door

								MOV# xposf	@4
								MOV @0	@3
								ADD @0	1
								ITF @0
								MOV# zposf	@0
								SUB#	zposf 0.5

								MOV	@0		rc_Items
								MOV 	@1		@2
								MUL	@1 	rc_MapH
								ADD	@1 	@3
								STP	@0 	@1
								MOV	id 	[@0]

								MOV xposi @2
								MOV zposi @3

							JMP	v_dzp_door_hit
	
					@v_dzp_no_door:
					MOV# @5 0.0; rem no offset
					rem ==========


					ADD @3 1
					ADD# xposf dxdz_inv
					MOV# @0 xposf
					FTI @0
					MOV @2 @0

					CMP @2 0
					JL v_dz_failed
					CMP @2 rc_MapW
					JGE v_dz_failed

					MOV @0 rc_Map
					MOV @1 @2
					MUL @1 rc_MapH
					ADD @1 @3
					STP @0 @1
					MOV id [@0]

					JMP v_dzp_loop
				@v_dzp_end:

				MOV xposi @2
				MOV zposi @3

				rem zposf = float(zposi)
				MOV @0 zposi
				ITF @0
				MOV# zposf @0

				@v_dzp_door_hit:

				MOV# zdistance xposf
				SUB# zdistance xpos
				MUL# zdistance zdistance
				MOV# @0 zposf
				SUB# @0 zpos
				MUL# @0 @0
				ADD# zdistance @0

				JMP v_dz_done
		endif

		@v_dz_failed:
			MOV# zdistance 100000.0
		@v_dz_done:

		if xdistance < distance or zdistance < distance
			return false
		else
			return true
		endif
endfunc



function RC_GetWallImage(x, z)
	if x < 0 or x >= rc_MapW then return 0
	if z < 0 or z >= rc_MapH then return 0
	return rc_Map[x][z]
endfunc

function RC_GetFloorImage(x, z)
	if x < 0 or x >= rc_MapW then return 0
	if z < 0 or z >= rc_MapH then return 0
	return rc_Floor[x][z]
endfunc

function RC_GetCeilingImage(x, z)
	if x < 0 or x >= rc_MapW then return 0
	if z < 0 or z >= rc_MapH then return 0
	return rc_Ceiling[x][z]
endfunc
