
	#undef longint
	type longint as long

	#lang "fb"

	#Include Once ".\KSDK\Support\Constants.bi"	
	dim shared as string Value

	type pixel
		union
			type
				 as ubyte B,G,R,x
			end type
			u as ulong
		end union
	end type

	#Include Once ".\KSDK\Support\File Support.bi"

	#Include Once ".\KSDK\Support\String Support.bi"
	
	#Include Once ".\KSDK\Support\VGA Lookup.bi"

	#Include Once ".\KSDK\Support\Simple Input.bi"
				
	#Include Once ".\KSDK\Support\Memory Management.bi"
	
	#Include Once ".\KSDK\Support\Text Box.bi"
	
	#Include Once "fbgfx.bi"
	#Include Once "fbimage.bi"
	#Include Once "vbcompat.bi"
	#Include Once "crt.bi"
	
	#include once "fbgfx.bi"
	'#include once "inc\fbpng.bi"
	'#include once "inc\png_image.bi"

	#Include Once ".\KSDK\Support\Property Core.bi"

	#include once ".\KSDK\Support\Property Shorthand.bi"
	
	#include once ".\KSDK\Support\Random.bas"
	
	redim shared as Property_DB_Type ParamDB(any)
	redim shared as Property_DB_Type BoardDB(any)
	redim shared as Property_DB_Type TextureDB(any)

	declare sub __SortAll()

	#include once ".\Keal's LabDemo2 Macros (No1).bi"
	
	using fb
	
	dim shared as string Property_Echo
	Property_Echo = EMPTY
	
	'DEFINT A-Z
	'dim shared as longint XDIM, YDIM, PPL
	dim shared as double TURNRATE, FWMOVERATE, REVMOVERATE

	'XDIM = 640
	'YDIM = 480
	'PPL = XDIM

	Value = EMPTY
		
	type axis
		as longint x,y,z
	end type
	
	dim shared xyz as axis
	
	redim shared as longint hasAlpha(Any)
	declare function pic2axis(addr as longint) as axis
	
	declare Function bmp_load( ByRef Filename As Const String ) As Any Ptr
	
	declare sub generateBoardDB()	
	declare sub main()
	
	declare sub loadTextures(Filename as string)
	declare function pixelfix(o as longint) as longint
	declare sub texturerotate(pic as fb.image ptr)
	
	declare Function AdjustGamma(ByVal cca As Double) As Double
	declare Function AdjustDepth(sy1 as longint) As longint
	
	declare function percentileOffSet(subjectSpan as longint = 0,containerSpan as longint = 0, percentile as double = 0) as longint

	dim shared as double posx, posy, posz, cosang, sinang, ang, vxinc, vx, vyinc, vy, incx, incy, xtemp, ytemp, d, hx, hy, dist
	dim shared as longint byi, by, by2, xscan, yscan, sx, xdir, ydir, bbx, sy1, sy2, p, pe, ccr, ccg, ccb, cca, Nct

	Dim shared As Double adjustedGamma
	'gamma = 2.2 ' Set your desired gamma value here

	Dim shared As Double projectionPercentile
	
	dim shared as string r
		
	redim shared pic(any) as fb.image ptr

	type filetype
		as longint mode
		as string Filename
	end type
	
	redim shared as filetype filemode(any)
	redim filemode(ZERO to 255)
	
	dim shared as longint texturemode=ZERO,paramMode=POSONE
	
	with filemode(paramMode)
		.mode=ZERO
		.Filename="params.property"
	end with
	
	with filemode(texturemode)
		.mode=ZERO
		.Filename="textures.property"
	end with

	'declare function label2value(label as string = EMPTY) as string
	
	declare sub loadParamDB(Filename as string)

	declare sub AddCube(x as longint,y as longint,Index as longint)

	'loadTextures(filemode(texturemode).Filename)
	'texturesrotate(pic())

	redim shared as longint regs(Any)
	dim shared as longint bstatus
	dim shared as string cii
	
	redim preserve regs(ZERO to POSFOUR)
	
	ScreenRes XDIM, YDIM, POSTHIRTYTWO, POSSIXTEEN, FB.GFX_ALPHA_PRIMITIVES
	ScreenSet POSONE,ZERO
	
	RANDOMIZE TIMER
	
	'Square aspect is actually XDIM*.5, but I think 128 looks nicer
	'dim shared as longint hval
	'hval = XDIM*.5
	
		'Code originally from LABDEMO.BAS
		'Modified on 10/14/1999 by Ken Silverman for rendering cleanliness
	
	'OUT H3C8, ZERO	'Make interesting palette
	
	dim shared as longint x=ZERO
	/'
	FOR x = ZERO TO POSSIXTYTHREE: OUT H3C9, x: OUT H3C9, ZERO: OUT H3C9, ZERO: NEXT x
	FOR x = ZERO TO POSSIXTYTHREE: OUT H3C9, ZERO: OUT H3C9, x: OUT H3C9, ZERO: NEXT x
	FOR x = ZERO TO POSSIXTYTHREE: OUT H3C9, ZERO: OUT H3C9, ZERO: OUT H3C9, x: NEXT x
	FOR x = ZERO TO POSSIXTYTHREE: OUT H3C9, x: OUT H3C9, x: OUT H3C9, x: NEXT x
	
	OUT H3C4, H4: OUT H3C5, H6	'Set Mode X (unchained mode)
	OUT H3D4, H14: OUT H3D5, H0
	OUT H3D4, H17: OUT H3D5, HE3
	'/
	
	redim shared as any ptr textures(Any)
	redim shared as longint board(Any, Any)
	'redim shared as any ptr pic(Any)
	
	'redim preserve pic(ZERO to POSSIXTYFOUR,ZERO to POSSIXTYFOUR,ZERO to POSFOUR)
	redim preserve board(ZERO to POSSIXTYFOUR,ZERO to POSSIXTYFOUR)
		
	redim preserve pic(POSONE to POSFOUR)
	
	dim shared as longint y=ZERO
	
	/'
	FOR y = ZERO TO POSSIXTYTHREE	'Generate interesting bitmaps (without loading a file)
	FOR x = ZERO TO POSSIXTYTHREE
		pic(x * POSSIXTYFOUR + y + ZERO) = (x + y) \ POSTWO + ZERO
		pic(x * POSSIXTYFOUR + y + POSFOURK) = ((x XOR y) * .875 + RND * POSSIXTYFOUR * .125) * POSHALF + POSSIXTYFOUR
		pic(x * POSSIXTYFOUR + y + 8192) = ((x OR y) * .875 + RND * POSSIXTYFOUR * .125) * POSHALF + 128
		pic(x * POSSIXTYFOUR + y + 12288) = (x * x + y * y) \ 128 + 192
		NEXT x
	NEXT y
	'/

	dim shared as longint z=ZERO
		
	declare sub raytrace()
	
	declare sub render()	
	
	declare sub renderCeilings()
	declare sub renderWalls()
	declare sub renderFloors()

	declare sub keyboardControl()
	declare sub mouseControl()
	declare sub constrainView()
	
	dim shared pPix as pixel ptr
	
	loadParamDB("params")
	
	ScreenRes XDIM,YDIM,32,POSTWO
	ScreenSet POSONE,ZERO
	
	'generateBoardDB()
	main()
	
	sub main()
	
		DO
			raytrace()
			'render()
		
			screencopy POSONE,ZERO
			cls

			keyboardControl()
			mouseControl()
			constrainView()
		
		LOOP
	end sub
	
	sub raytrace()
		
		dim as Property_DB_Type DBBoard, DBTexture
		dim as any ptr Value
		pPix = screenptr	

		cosang = COS(ang)
		sinang = SIN(ang)
		vxinc = sinang * NEGTWO / XDIM: vx = cosang + sinang + vxinc * POSHALF
		vyinc = cosang * POSTWO / XDIM: vy = sinang - cosang + vyinc * POSHALF
		
		FOR sx = ZERO TO XDIM - POSONE

			'Raytrace in 2D to see what block is hit, and where it Gets hit
			xscan = INT(posx): xdir = SGN(vx): incx = ABS(vx)
			yscan = INT(posy): ydir = SGN(vy): incy = ABS(vy)
			xtemp = posx - xscan: IF xdir GTR ZERO THEN xtemp = POSONE - xtemp
			ytemp = posy - yscan: IF ydir GTR ZERO THEN ytemp = POSONE - ytemp
			d = xtemp * incy - ytemp * incx
			DO				
				select case d
				case is LSS ZERO
					xscan = xscan + xdir

					DBBoard=Property_Get( BoardDB(), xscan & COMMA & yscan )
					
					select case DBBoard.Label
					case is NEQ EMPTY
						hx = xscan
						select case xdir
						case is LSS ZERO
							hx+=POSONE
						end select
						hy = posy + vy * (hx - posx) / vx
						bbx = INT((hy - INT(hy)) * POSSIXTYFOUR)
						select case xdir
						case is LSS ZERO
							bbx = POSSIXTYFOUR - bbx
						end select
						EXIT DO
					case else
					END select
					d = d + incy
				case else
					yscan = yscan + ydir

					DBBoard=Property_Get( BoardDB(), xscan & COMMA & yscan )
					
					select case DBBoard.Label
					case is NEQ EMPTY
						hy = yscan
						select case ydir
						case is LSS ZERO
							hy+=POSONE
						end select
						hx = posx + vx * (hy - posy) / vy
						bbx = INT((hx - INT(hx)) * POSSIXTYFOUR)
						select case ydir
						case is GTR ZERO
							bbx = POSSIXTYTHREE - bbx
						end select
						EXIT DO
					case else
					END select
					d = d - incx
				END select
			LOOP
			dist = cosang * (hx - posx) + sinang * (hy - posy)
		
			render()
	
		NEXT sx

	end sub
	
	sub render()

		dim as Property_DB_Type DBBoard, DBTexture
		pPix = screenptr	
	
		'Find the ceiling & floor borders, and the texture mapping equation
		IF dist GTR POSONE / POSSIXTYFOUR THEN
			sy1 = INT(YDIM \ POSTWO + (-posz - POSHALF) * hval / dist)
			sy2 = INT(YDIM \ POSTWO + (-posz + POSHALF) * hval / dist)
			IF sy1 LSS ZERO THEN sy1 = ZERO
			IF sy2 GTR YDIM THEN sy2 = YDIM
			byi = INT(dist * POSSIXTYFOURK * POSSIXTYFOUR / hval)
			by = (sy1 + POSONE - YDIM \ POSTWO) * byi + (posz + POSHALF) * POSSIXTYFOURK * POSSIXTYFOUR - POSONE
			by = by + ((board(xscan, yscan) - POSONE) * POSFOURK + bbx * POSSIXTYFOUR) * POSSIXTYFOURK
		ELSE
			sy1 = YDIM \ POSTWO: sy2 = sy1
		END IF

		'Draw vertical line at column sx:
		
		'ccr=((YDIM\POSTWO-sy1)*38)*POSTWO\YDIM
		'ccg=((YDIM\POSTWO-sy1)*196)*POSTWO\YDIM
		'ccb=((YDIM\POSTWO-sy1)*128)*POSTWO\YDIM
		
		' Calculate adjusted depth value
		cca = AdjustDepth(sy1)
		
		' Calculate adjusted gamma value
		adjustedGamma = AdjustGamma(cca) ', gamma)
		'line(sx,sy1)-(sx,YDIM-sy1),RGBA(ccr,ccg,ccb,cca)

		'OUT H3C5, POSTWO ^ (sx AND 3): DEF SEG = HA000 + pagoffs * 16
	
		renderCeilings()
		renderWalls()
		renderFloors()
		
	end sub
	
	sub renderCeilings()

		pPix = screenptr	

		'Ceilings
		p = sx: pe = sy1 * PPL
		DO WHILE p LSS pe
			pPix[p].u=255-(p\960)
			p = p + PPL
		LOOP
	end sub
	
	sub renderWalls()
		
		dim as Property_DB_Type DBBoard, DBTexture
		dim as string bValue=EMPTY, pValue=EMPTY
		
		'"pPix = screenptr" its declared and Set before drawing starts...
		pPix = screenptr	
	
		'Walls
		pe = sy2 * PPL
      
		'xyz=pic2axis(by\POSSIXTYFOURKMASK)
		'point(xyz.x,xyz.y,pic(POSONE))
            
		'dim as pixel ptr pTex = pic(board(xscan, yscan))+sizeof(fb.image)
		
		'''var pTex = __VideoDirect ( BoardDB (), TextureDB (), xscan, yscan)
		
		'"pe" is the current screen row
		
		'the texture index is retrieved from the board() itself
		
		'var pTex = cast(pixel ptr,pic(board(xscan, yscan))+1)
		'"by" is texture row
		
		'"p" pointer to current pixel in the screen
		'"pPix[p]" current pixel in screen
		
		'"by" is current texture pixel
		
		DO WHILE p LSS pe
			
			dim as long addr = by\POSSIXTYFOURK
			dim as long x = addr and POSSIXTYTHREE, y = (addr\POSSIXTYFOUR) and POSSIXTYTHREE
			
			'pPix[p].u=point(X,Y,pic(POSONE))
			
			DBBoard=Property_Get( BoardDB(), xscan & COMMA & yscan )
			
			DBTexture=Property_Get( TextureDB(), DBBoard.value )
			
			if DBTexture.image NEQ NULL then
				pPix[p].u = point( x, y, DBTexture.image)
			end if
			
			'''pPix[p] = pTex[(by\POSSIXTYFOURK) and ((POSSIXTYFOUR*POSSIXTYFOUR)-POSONE)]
			
			' Apply gamma adjustment
			pPix[p].r = (pPix[p].r * adjustedGamma) \ 255
			pPix[p].g = (pPix[p].g * adjustedGamma) \ 255
			pPix[p].b = (pPix[p].b * adjustedGamma) \ 255
			pPix[p].x = (pPix[p].x * adjustedGamma) \ 255
			
			'light
			'pPix[p].r=(pPix[p].r*cca)\255
			'pPix[p].g=(pPix[p].g*cca)\255
			'pPix[p].b=(pPix[p].b*cca)\255
			'pPix[p].x=(pPix[p].x*cca)\255
        
			'next pixel and texture
			p = p + PPL : by = by + byi
			
		LOOP			
	end sub
	
	sub renderFloors()	

		pPix = screenptr	

		'Floors
		pe = YDIM * PPL
		DO WHILE p LSS pe
			pPix[p].u=p\(960*POSTWO)
			p = p + PPL
		LOOP

		vx = vx + vxinc
		vy = vy + vyinc

	end sub
	
	'Flip page
	'OUT H3D5, pagoffs: pagoffs = (pagoffs + POSSIXTYFOUR) AND 255
		
	sub keyboardControl()
		'Keyboard control code
		DO
			cii = INKEY
			select case true
			case cii EQU LEFTARROW
				ang = ang - POSONE * TURNRATE
			case cii EQU RIGHTARROW
				ang = ang + POSONE * TURNRATE
			case cii EQU "<", cii EQU COMMA
				posx = posx + sinang * POSQUART
				posy = posy - cosang * POSQUART
			case cii EQU ">", cii EQU "."
				posx = posx - sinang * POSQUART
				posy = posy + cosang * POSQUART
			case cii EQU UPARROW
				posx = posx + cosang * POSQUART * FWMOVERATE
				posy = posy + sinang * POSQUART * FWMOVERATE
			case cii EQU DOWNARROW
				posx = posx - cosang * POSQUART * REVMOVERATE
				posy = posy - sinang * POSQUART * REVMOVERATE
			case UCASE(cii) EQU "A"
				posz = posz - POSPTZEROFIVE
			case UCASE(cii) EQU "Z"
				posz = posz + POSPTZEROFIVE
			case cii EQU ESC, cii EQU MouseCloseEvent
				SCREEN ZERO
				END
			end select
		LOOP WHILE cii NEQ EMPTY
	end sub
	
	sub mouseControl()
		
		'Mouse control code (enable this, unless you're stuck using QBasic!)
		'regs(ZERO) = 5: CALL int86old(H33, regs(), regs()): bstatus = regs(ZERO)
		'regs(ZERO) = 11: CALL int86old(H33, regs(), regs())
		
		select case true
		case (bstatus AND POSTWO) EQU ZERO
			ang = ang + regs(POSTWO) * POSPTZEROONE
		case else
			posx = posx + sinang * regs(POSTWO) * NEGPTZEROTWO
			posy = posy - cosang * regs(POSTWO) * NEGPTZEROTWO
		end select
		
		select case true
		case (bstatus AND POSONE) EQU ZERO
			posx = posx + cosang * regs(3) * NEGPTZEROTWO
			posy = posy + sinang * regs(3) * NEGPTZEROTWO
		case else
			posz = posz + regs(3) * POSPTZEROTWO
		end select
	
	end sub
	
	sub constrainView()
		'Don't let your view escape the board
		
		select case posx
		case is LSS POSONE + POSQUART
			posx = POSONE + POSQUART
		case is GTR POSSIXTYTWO + POS3QUART
			posx = POSSIXTYTWO + POS3QUART
		end select
		
		select case posy
		case is LSS POSONE + POSQUART
			posy = POSONE + POSQUART
		case is GTR POSSIXTYTWO + POS3QUART
			posy = POSSIXTYTWO + POS3QUART
		end select
		
		select case posz
		case is LSS NEGHALF
			posz = NEGHALF
		case is GTR POSHALF
			posz = POSHALF
		end select
		
	end sub
	
	function pic2axis(addr as longint) as axis
	
		dim as axis temp = any
	
		'horizontal pixel
		temp.x =(addr and POSSIXTYTHREE)
		
		'vertical pixel
		temp.y =(addr mod POSSIXTYFOUR) and (POSSIXTYFOUR^POSTWO-POSONE)
		
		'texture index
		temp.z =(addr mod POSSIXTYFOUR*POSSIXTYFOUR)
	
		return temp
	
	end function

	' A function that creates an image buffer with the same
	'' dimensions as a BMP image, and loads a file into it.
	
	Function bmp_load( ByRef Filename As Const String ) As Any Ptr
	
	    Dim As Long filenum, bmpwidth, bmpheight
	    Dim As Any Ptr img
	
	    '' open BMP file
	    filenum = FreeFile()
	    If Open( Filename For Binary Access Read As #filenum ) NEQ ZERO Then Return NULL
	
	        '' retrieve BMP dimensions
	        Get #filenum, 19, bmpwidth
	        Get #filenum, 23, bmpheight
	
	    Close #filenum
	
	    '' create image with BMP dimensions
	    img = ImageCreate( bmpwidth, Abs(bmpheight) )
	
	    If img EQU NULL Then Return NULL
	
	    '' load BMP file into image buffer
	    If BLoad( Filename, img ) NEQ ZERO Then ImageDestroy( img ): Return NULL
	
	    Return img
	
	End Function
	
	sub loadTextureDB(Filename as string)
		
		dim as longint index=ZERO
		
		Filename = prefix(Property_DB_EXT,Filename) & Property_DB_EXT
		
		Property_Database_Delete ( TextureDB() )
		
		Property_Database_Load ( TextureDB(), Filename & Property_DB_EXT )
		
		for index=lbound(TextureDB,POSONE) to ubound(TextureDB,POSONE) step POSONE
			
			TextureDB(index).image = bmp_load( TextureDB(index).value )
			
		next index
				
	end sub

	/'
	sub loadTextures(Filename as string)
		
		filemode(texturemode).Filename=Filename
		
		for N as long = POSONE to ubound(pic) step POSONE
			imagedestroy(pic(N))
		next N
		
		erase pic
		
		filemode(texturemode).mode=freefile
		if open(filemode(texturemode).Filename for input as filemode(texturemode).mode) then
			end
		end if
		
		do while not eof(filemode(texturemode).mode)
			line input #filemode(texturemode).mode,r
			Nct=valint(prefix("=",r))
			select case true
			case Nct GTR ubound(pic,1)
				redim preserve pic(POSONE to Nct)
			end select
			pic(Nct) = bmp_load(suffix("=",r))
		loop
				
		close #filemode(texturemode).mode
		
	end sub
	'/
	
	function pixelfix(o as longint) as longint
		dim as longint x,y,p,pp
		p=o mod POSSIXTYFOURK
		pp=o\POSSIXTYFOURK
		x=pp and POSSIXTYTHREE
		y=(pp mod POSSIXTYFOUR) and POSSIXTYTHREE
		return (((y * 8) or x) * 8) or (p)
	end function
		
	sub texturerotate(pic as fb.image ptr)
		
		dim as longint x,y,z
		
		dim as fb.image ptr pic2
	
			pic2=imagecreate(POSSIXTYFOUR,POSSIXTYFOUR,ZERO,32)
			
			for y=ZERO to POSSIXTYTHREE step POSONE
			for x=ZERO to POSSIXTYTHREE step POSONE
				
				select case (point(y,x,pic) shr POSALPHASHIFT) and &HFF
				case is LSS &HFF
					hasAlpha(z)=POSONE
				end select
				
				pSet pic2,(x,y),point(y,x,pic)
				
			next x
			next y
			
			line pic,(ZERO,ZERO)-(POSSIXTYTHREE,POSSIXTYTHREE),rgba(ZERO,ZERO,ZERO,255),bf
			put pic,(ZERO,ZERO),pic2,alpha
			imagedestroy pic2
			
			line (ZERO,ZERO)-(XDIM-POSONE,YDIM-POSONE),rgba(ZERO,ZERO,ZERO,255),bf
			put (ZERO,ZERO),pic,alpha
			screencopy POSONE,ZERO
			do while inkey EQU EMPTY:loop
	end sub
	
	Function AdjustGamma(ByVal cca As Double) As Double
		return 255 * ((cca / 255) ^ (POSONE / GAMMA))
	End Function

	Function AdjustDepth(sy1 as longint) As longint
		return ((YDIM\POSTWO-sy1)*POSSIXTYFOUR)*POSTWO\YDIM
	End Function
		
	sub generateBoardDB()
		
		dim as longint Index=0
		dim as string xy=EMPTY, Tex=EMPTY
		'redim shared as Property_DB_Type BoardDB(any)
		
		FOR z = ZERO TO POSSIXTYTHREE step POSONE	'Generate random board (ZERO is invisible, POSONE-POSFOUR are walls)

			AddCube(z,ZERO,Rando(lbound(TextureDB,1),ubound(TextureDB,1)))
			
			AddCube(ZERO,z,Rando(lbound(TextureDB,1),ubound(TextureDB,1)))

			AddCube(z,POSSIXTYTHREE,Rando(lbound(TextureDB,1),ubound(TextureDB,1)))

			AddCube(POSSIXTYTHREE,z,Rando(lbound(TextureDB,1),ubound(TextureDB,1)))

		NEXT z
	
		FOR z = ZERO TO POSKMASK step POSONE
		
			AddCube(Rando(POSONE,POSSIXTYTWO),Rando(POSONE,POSSIXTYTWO),Rando(lbound(TextureDB,1),ubound(TextureDB,1)))

		NEXT z

		__SortAll()
		
		'The length of the side of a cube is POSONE
		'Since the 2D board map is POSSIXTYFOUR*POSSIXTYFOUR, posx and posy range from ZERO-POSSIXTYFOUR
		'posz ranges from NEGHALF to POSHALF (ZERO is the middle)
		DO	'Make sure starting position isn't inside a cube
			
			x = Rando(POSTWO,POSSIXTYTWO)
			y = Rando(POSTWO,POSSIXTYTWO)

			__Tinker ( BoardDB(), Property_Echo, "retrieve", x & COMMA & y, value)
			
			Index=0
			Tex=EMPTY
			
			xy=x & COMMA & y

			__Tinker ( BoardDB(), Property_Echo, "remove", xy, Tex)
			
		LOOP WHILE value NEQ EMPTY

		__SortAll()
		
		posx = x + POSHALF: posy = y + POSHALF: posz = ZERO: ang = RandoFloat(0,PI * POSTWO)
	
		'pagoffs = ZERO: OUT H3C4, H2: OUT H3D4, HC
	end sub

	/'
	sub generateBoard()
		FOR z = ZERO TO POSSIXTYTHREE	'Generate random board (ZERO is invisible, POSONE-POSFOUR are walls)
			board(z, ZERO) = INT(POSFOUR * RND) + POSONE
			board(ZERO, z) = INT(POSFOUR * RND) + POSONE
			board(z, POSSIXTYTHREE) = INT(POSFOUR * RND) + POSONE
			board(POSSIXTYTHREE, z) = INT(POSFOUR * RND) + POSONE
		NEXT z
	
		FOR z = ZERO TO 1023
			board(INT(POSSIXTYTWO * RND) + POSONE, INT(POSSIXTYTWO * RND) + POSONE) = INT(POSFOUR * RND) + POSONE
		NEXT z

		'The length of the side of a cube is POSONE
		'Since the 2D board map is POSSIXTYFOUR*POSSIXTYFOUR, posx and posy range from ZERO-POSSIXTYFOUR
		'posz ranges from NEGHALF to POSHALF (ZERO is the middle)
		DO	'Make sure starting position isn't inside a cube
			x = INT(POSSIXTYTWO * RND) + POSTWO
			y = INT(POSSIXTYTWO * RND) + POSTWO
		LOOP WHILE board(x, y) NEQ ZERO
		posx = x + POSHALF: posy = y + POSHALF: posz = ZERO: ang = PI * POSTWO * RND
	
		'pagoffs = ZERO: OUT H3C4, H2: OUT H3D4, HC
	end sub
	'/
		
	sub loadParamDB(Filename as string)
		
		dim as ulongint i,o
		
		Filename = prefix(Property_DB_EXT,Filename) & Property_DB_EXT
		
		'redim as Property_DB_Type paramDB(any)
		
		Property_Database_Load ( paramDB(), Filename)
		
		for i = lbound(paramDB,1) to ubound(paramDB,1) step 1
			color rgba(255,255,255,255)
			print paramDB(i).label & "=" & paramDB(i).value
			screencopy 1,0
		next i
		
		__SortAll()
		
		HVALSYNC
		'SYNC1 "hval", "xdim"
		
		'kDIV(HVAL,XDIM,HVAL)

		
		print XDIM & COLON & YDIM & COLON & HVAL & COLON & PPL & COLON & GAMMA
		screencopy 1,0

		loadTextureDB( prefix( __Get(paramDB(),"textures").value, Property_DB_EXT ) & Property_DB_EXT )
		
		generateBoardDB()
		
		TURNRATE = val(__Get(paramDB(),"turnrate").value)
		FWMOVERATE = val(__Get(paramDB(),"fwmoverate").value)
		REVMOVERATE = val(__Get(paramDB(),"revmoverate").value)
		
		'Property_Erase paramDB()

	end sub
	
	'offSet from percentile function

	function percentileOffSet(subjectSpan as longint = 0,containerSpan as longint = 0, percentile as double = 0) as longint
		'calculate offSet (either vertical or horizontal)
		'returns offSet from reference
		
		return int(containerSpan * percentile / 100 - subjectSpan * percentile / 100)
		
	end function

sub AddCube(x as longint,y as longint,Index as longint)
		
	Dim As String Tex = EMPTY
	Tex=TextureDB(Index).label
	
	__Tinker ( BoardDB(), Property_Echo, "add", x & COMMA & y, Tex)
	
end sub

sub __SortAll()

	__Sort(ParamDB())
	__Sort(TextureDB())
	__Sort(BoardDB())

end sub