Pseudo 3D hills

Started by
0 comments, last by Hawkblood 9 years, 10 months ago

I've converted Code Incomplete Pseudo 3D road routine to GLBasic, but have problems with hills, namely that the road "shakes" (moves up and down) as you move up (or down) the hill.

I had thought that it was due to using an integer instead of a float somewhere, but it appears not. The only other thing is that I have converted some code incorrectly somewhere, but have no idea what.

This is the code (rendering order isn't correct, but that is easy to solve) :


// --------------------------------- //
// Project: Test2
// Start: Tuesday, April 01, 2014
// IDE Version: 12.001
CONSTANT PLAYER_STRAIGHT%			=	0
CONSTANT PLAYER_LEFT%				=	1
CONSTANT PLAYER_RIGHT%				=	2
CONSTANT PLAYER_UPHILL_STRAIGHT%	=	3
CONSTANT PLAYER_UPHILL_LEFT%		=	4
CONSTANT PLAYER_UPHILL_RIGHT%		=	5

CONSTANT ROAD_LENGTH_NONE%			=	0
CONSTANT ROAD_LENGTH_SHORT%			=	25
CONSTANT ROAD_LENGTH_MEDIUM%		=	50
CONSTANT ROAD_LENGTH_LONG%			=	100

CONSTANT ROAD_HILL_NONE%			=	0
CONSTANT ROAD_HILL_LOW%				=	20
CONSTANT ROAD_HILL_MEDIUM%			=	40
CONSTANT ROAD_HILL_HIGH%			=	60

CONSTANT ROAD_CURVE_NONE%			=	0
CONSTANT ROAD_CURVE_EASY%			=	2
CONSTANT ROAD_CURVE_MEDIUM%			=	4
CONSTANT ROAD_CURVE_HARD%			=	6

CONSTANT PI							=	3.14159

CONSTANT COLOURS_SKY%				=	7526382
CONSTANT COLOURS_TREE%				=	20744
CONSTANT COLOURS_FOG%				=	20744

CONSTANT SPRITES_BILLBOARD_01%		=	16
CONSTANT SPRITES_BILLBOARD_02%		=	17
CONSTANT SPRITES_BILLBOARD_03%		=	18
CONSTANT SPRITES_BILLBOARD_04%		=	19
CONSTANT SPRITES_BILLBOARD_05%		=	20
CONSTANT SPRITES_BILLBOARD_06%		=	21
CONSTANT SPRITES_BILLBOARD_07%		=	22
CONSTANT SPRITES_BILLBOARD_08%		=	23
CONSTANT SPRITES_BILLBOARD_09%		=	24
CONSTANT SPRITES_PALM_TREE%			=	25
CONSTANT SPRITES_DEAD_TREE1%		=	26
CONSTANT SPRITES_DEAD_TREE2%		=	27
CONSTANT SPRITES_COLUMN%			=	28
CONSTANT SPRITES_CATCUS%			=	29
CONSTANT SPRITES_TREE1%				=	30
CONSTANT SPRITES_TREE2%				=	31
CONSTANT SPRITES_BUSH1%				=	32
CONSTANT SPRITES_BUSH2%				=	33
CONSTANT SPRITES_STUMP%				=	34
CONSTANT SPRITES_BOULDER1%			=	35
CONSTANT SPRITES_BOULDER2%			=	36
CONSTANT SPRITES_BOULDER3%			=	37
CONSTANT SPRITES_TUNNELWALL%		=	38
CONSTANT SPRITES_TUNNELTOP%			=	39

CONSTANT BACKGROUND_SKY%			=	64
CONSTANT BACKGROUND_HILLS%			=	65
CONSTANT BACKGROUND_TREES%			=	66

CONSTANT CARS_CAR_01%				=	70
CONSTANT CARS_CAR_02%				=	71
CONSTANT CARS_CAR_03%				=	72
CONSTANT CARS_CAR_04%				=	73
CONSTANT CARS_SEMI%					=	74
CONSTANT CARS_TRUCK%				=	75

TYPE tGraphic
	id%								// Sprite index
	index%							// Car ID
	roadIndex%						// Which road the graphic is attached too
	orgXSize%;orgYSize%;
	currentXSize%;currentYSize%
	xOffset
	yOffset
	z
	speed
	percent
	moveSpeed						// Movement speed - not used with static objects!
ENDTYPE

//TYPE tCar
//	which%
//	offset
//	z
//	id%
//	speed
//	percent
//ENDTYPE
//
//TYPE tSprite
//	id%
//	offset // Offset of road
//	yOffset
//ENDTYPE

TYPE tScreen
	scale
	x
	y
	w
ENDTYPE

TYPE tCamera
	x
	y
	z
ENDTYPE

TYPE tWorld
	x
	y
	z
ENDTYPE

TYPE tRoadPos
	index%
	xPos
ENDTYPE

TYPE tColour
	rumble%			// Denotes area between the grass and road%
	road%			// Road colour
	leftGrass%		// Area before rumble bit
	rightGrass%		// Area after right rumble bit
	lane%			// Lane colour
ENDTYPE

TYPE tPart
	world AS tWorld
	camera AS tCamera
	screen AS tScreen
	rumbleWidth
ENDTYPE

// Each road can have its own width, number of lines and colours
TYPE tSegmentPart
	numLanes%		// Number of lanes
	rumbleWidth%	// Rumble width
	roadWidth%		// Width of road
	colour AS tColour

	graphics[] AS tGraphic
	cars[] AS tGraphic

	p1 AS tPart
	p2 AS tPart
ENDTYPE

TYPE tSegment
	index%
	roads[] AS tSegmentPart
	tunnel%
	curve
	clip
ENDTYPE

TYPE tPlayerInfo
	graphic AS tGraphic
	playerSegment AS tSegment
	playerPercent
	position
	speed
	segmentIndex%
	cameraHeight
	cameraDepth
	cameraZ
	fov
ENDTYPE


TYPE TRoad
	segments[] AS tSegment
	cars[] AS tGraphic
	playerInfo AS tPlayerInfo

	LIGHT AS tColour
	DARK AS tColour

	SPRITES_SCALE

	fps				=	75.0
	fpsStep			=	0.0
	segmentLength% 	=	200   	// Length of a single segment
	rumbleLength%	=	3		// Number of segments per red/white rumble strip
	//roadWidth%     	=	2000	// Actually half the roads width, easier math if the road spans from -roadWidth to +roadWidth
	//cameraHeight%  	=	1000  	// Z height of camera
	//cameraDepth   	=	0
	centrifugal		=	0.3
	//position      	=	0.0     // Current camera Z position
//	playerX       	= 	0		// Player x offset from center of road (-1 to 1 to stay independent of roadWidth)
//	playerZ       	= 	0		// Player relative z distance from camera (computed)
	//lanes%         	= 	3       // Number of lanes
	//fieldOfView%   	=	100     // angle (degrees) for field of view
//	speed         	= 	0.0     // current speed
	maxSpeed      	=	0       // top speed (ensure we can't move more than 1 segment in a single frame to make collision detection easier)
	accel			=	0		// acceleration rate - tuned until it 'felt' right
    breaking		=	0		// deceleration rate when braking
    decel 			=	0		// 'natural' deceleration rate when neither accelerating, nor braking
    offRoadDecel	=	0 		// off road deceleration is somewhere in between
    offRoadLimit 	= 	0 		// limit when off road deceleration no longer applies (e.g. you can always go at least t
    resolution		=	0.0
    skyOffset		=	0.0     // Current sky scroll offset
    skySpeed		=	0.001	// Background sky layer scroll speed when going around curve (or up hill)
    hillOffset     	= 	0.0     // current hill scroll offset
    treeOffset     	=	0.0     // current tree scroll offset
    hillSpeed      	=	0.002  	// background hill layer scroll speed when going around curve (or up hill)
    treeSpeed      	=	0.003   // background tree layer scroll speed when going around curve (or up hill)
    totalCars%		=	200     // total number of cars on the road

    width%;height%
	keyLeftRight%

	trackLength%

	drawDistance%	=	500

	FUNCTION Initialise%:
	LOCAL tW%,tH%

		GETSCREENSIZE self.width%,self.height%
		SEEDRND GETTIMERALL()

		//self.cameraDepth=1.0 / TAN((self.fieldOfView%/2)) // * 3.141592653/180.0)
		//DEBUG "Camera depth : "+self.cameraDepth+" "+self.fieldOfView%+"\n"

		self.LIGHT.road%=7039851
		self.LIGHT.leftGrass%=1092112
		self.LIGHT.rightGrass=RGB(127,127,127)
		self.LIGHT.rumble%=5592405
		self.LIGHT.lane%=13421772

		self.DARK.road%=6908265
		self.DARK.leftGrass%=39424
		self.DARK.rightGrass%=RGB(255,255,0)
		self.DARK.rumble%=12303291
		self.DARK.lane%=0

		self.fpsStep=1.0/self.fps
		self.maxSpeed=self.segmentLength/self.fpsStep

		self.accel = self.maxSpeed/5.0
    	self.breaking = -self.maxSpeed
    	self.decel = -self.maxSpeed/5.0
    	self.offRoadDecel = -self.maxSpeed/2.0
    	self.offRoadLimit = self.maxSpeed/4.0
//    	self.speed=0.0
//    	self.playerZ=self.cameraHeight * self.cameraDepth
    	self.resolution=self.height%/640.0

		self.keyLeftRight%=0

    	GETSPRITESIZE PLAYER_STRAIGHT%,tW%,tH%
    	self.SPRITES_SCALE= 0.3 * (1.0/tW%)

    	self.playerInfo.graphic.id%=PLAYER_STRAIGHT%
    	GETSPRITESIZE self.playerInfo.graphic.id%,self.playerInfo.graphic.orgXSize%,self.playerInfo.graphic.orgYSize%
    	self.playerInfo.graphic.z=0.0
    	self.playerInfo.playerPercent=0.0
    	self.playerInfo.speed=0.0
    	self.playerInfo.segmentIndex%=0
    	self.playerInfo.cameraHeight=1500.0
    	self.playerInfo.fov=100.0
    	self.playerInfo.cameraDepth=1.0 / TAN((self.playerInfo.fov/2.0))
    	self.playerInfo.cameraZ=(self.playerInfo.cameraHeight * self.playerInfo.cameraDepth)
	ENDFUNCTION

	FUNCTION addSegment%:segments[] AS tSegment,curve,y,roadOffset
	LOCAL size%
	LOCAL segment AS tSegment

		size%=BOUNDS(segments[],0)

		DIM segment.roads[1]

		segment.index%=size%
		segment.curve=curve

		FOR loop%=0 TO BOUNDS(segment.roads[],0)-1
			DIM segment.roads[loop%].cars[0]
			DIM segment.roads[loop%].graphics[0]

			segment.roads[loop%].p1.world.x=IIF(loop%>0,2000*2*loop%,0)
			segment.roads[loop%].p1.world.y=self.lastY(segments)
			segment.roads[loop%].p1.world.z=size%*self.segmentLength%
			segment.roads[loop%].p1.camera.x=0.0
			segment.roads[loop%].p1.camera.y=0.0
			segment.roads[loop%].p1.camera.z=0.0
			segment.roads[loop%].p1.screen.x=0.0
			segment.roads[loop%].p1.screen.y=0.0
			segment.roads[loop%].p1.screen.w=0.0
			segment.roads[loop%].p1.screen.scale=0.0

			segment.roads[loop%].p2.world.x=IIF(loop%>0,2000*2*loop%,0)
			segment.roads[loop%].p2.world.y=y
			segment.roads[loop%].p2.world.z=(size%+1)*self.segmentLength%
			segment.roads[loop%].p2.camera.x=0.0
			segment.roads[loop%].p2.camera.y=0.0
			segment.roads[loop%].p2.camera.z=0.0
			segment.roads[loop%].p2.screen.x=0.0
			segment.roads[loop%].p2.screen.y=0.0
			segment.roads[loop%].p2.screen.w=0.0
			segment.roads[loop%].p2.screen.scale=0.0

			segment.roads[loop%].roadWidth%=2000
			segment.roads[loop%].rumbleWidth%=2

			segment.clip=0.0
			segment.curve=curve

			IF FLOOR(MOD(size%/self.rumbleLength%,2))
				segment.roads[loop%].colour=self.LIGHT
				segment.roads[loop%].colour.lane%=RGB(255,255,255)
				segment.roads[loop%].numLanes%=4

			ELSE
				segment.roads[loop%].colour=self.DARK
				segment.roads[loop%].colour.lane%=RGB(255,255,255)
				segment.roads[loop%].numLanes%=0
			ENDIF

		NEXT

		DIMPUSH segments[],segment
	ENDFUNCTION

	// Add static graphics (billboards, clouds, tunnels etc)
	FUNCTION addGraphic%:isStatic%,z,roadIndex%,id%,xOffset,moveSpeed,yOffset=0.0
	LOCAL graphic AS tGraphic
	LOCAL index%

		IF id%>=0
			GETSPRITESIZE id%,graphic.orgXSize%,graphic.orgYSize%
		ELSE
			IF id%=-1
				graphic.orgXSize%=64
				graphic.orgYSize%=512
			ELSE
				graphic.orgXSize%=1000
				graphic.orgYSize%=64
			ENDIF
		ENDIF

		graphic.id%=id%
		graphic.currentXSize%=graphic.orgXSize%
		graphic.currentYSize%=graphic.orgYSize%
		graphic.xOffset=xOffset
		graphic.yOffset=yOffset
		graphic.z=z
		graphic.percent=0.0
		graphic.roadIndex%=roadIndex%

		index%=FMOD(FLOOR(graphic.z/self.segmentLength%),BOUNDS(self.segments[],0))
		IF isStatic%=TRUE
			graphic.index%=0
			graphic.moveSpeed=0.0
			DIMPUSH self.segments[index%].roads[roadIndex%].graphics[],graphic
		ELSE
			graphic.index%=BOUNDS(self.cars[],0)
			graphic.moveSpeed=moveSpeed
			DIMPUSH self.segments[index%].roads[roadIndex%].cars[],graphic
			DIMPUSH self.cars[],graphic
		ENDIF


//      		LOCAL dx%,dy%
//
//      		IF id%=0
//      		GETSPRITESIZE id%,dx%,dy%
//      		//IF dx%=0 OR dy%=0
//      			DEBUG id%+"\n"
////    			KEYWAIT
//      		ENDIF
//
//
//		spr.id%=id%
//		spr.offset=offset
//		spr.yOffset=yOffset
//		DIMPUSH self.segments[n%].sprites[],spr
	ENDFUNCTION

	FUNCTION addRoad%:segments[] AS tSegment,enter, hold, leave, curve, y, offset
	LOCAL startY,endY,total
	LOCAL n%

		startY=self.lastY(segments)
		endY=startY+(y*self.segmentLength%)
		total=enter+hold+leave

//		DEBUG "Start Y : "+startY+" endY : "+endY+"\n"
//		KEYWAIT
		FOR n%=0 TO enter-1
			self.addSegment(segments[],self.easeIn(0,curve,n%/enter),easeInOut(startY,endY,n%/total),offset)
		NEXT
//		DEBUG "Holding ---\n"
		FOR n%=0 TO hold-1
			self.addSegment(segments[],curve,self.easeInOut(startY,endY,(enter+n%)/total),offset)
		NEXT
//		DEBUG "---\n"

		FOR n%=0 TO leave-1
			self.addSegment(segments[],self.easeInOut(curve,0,n%/leave),self.easeInOut(startY,endY,(enter+hold+n)/total),offset)
		NEXT
	ENDFUNCTION

	FUNCTION addStraight%:segments[] AS tSegment,num=25,offset%=0
		self.addRoad(segments[],num,num,num,0,0,offset%)
	ENDFUNCTION

	FUNCTION addHill%:segments[] AS tSegment,num,height,offset%=0
		self.addRoad(segments[],num,num,num,0,height,offset%)
	ENDFUNCTION

    FUNCTION addCurve%:segments[] AS tSegment,num, curve,height,offset%=0
    	self.addRoad(segments[],num,num,num,curve,height,offset)
    ENDFUNCTION

    FUNCTION addLowRollingHills%:segments[] AS tSegment,num,height,offset%=0
   		self.addRoad(segments[],num, num, num, 0, height/2,offset%)
      	self.addRoad(segments[],num, num, num, 0, -height,offset%)
      	self.addRoad(segments[],num, num, num, 0, height,offset%)
      	self.addRoad(segments[],num, num, num, 0, 0,offset%)
      	self.addRoad(segments[],num, num, num, 0, height/2,offset%)
      	self.addRoad(segments[],num, num, num, 0, 0,offset%)
    ENDFUNCTION

    FUNCTION addSCurves%:segments[] AS tSegment
//      self.addRoad(ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, -ROAD_CURVE_EASY, ROAD_HILL_NONE)
//      self.addRoad(ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_CURVE_MEDIUM, ROAD_HILL_MEDIUM)
//      self.addRoad(ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_CURVE_EASY, -ROAD_HILL_LOW)
//      self.addRoad(ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, -ROAD_CURVE_EASY, ROAD_HILL_MEDIUM)
//      self.addRoad(ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, -ROAD_CURVE_MEDIUM, -ROAD_HILL_MEDIUM)
   	ENDFUNCTION

	FUNCTION addBumps%:
//      self.addRoad(10, 10, 10, 0,  5);
//      self.addRoad(10, 10, 10, 0, -2);
//      self.addRoad(10, 10, 10, 0, -5);
//      self.addRoad(10, 10, 10, 0,  8);
//      self.addRoad(10, 10, 10, 0,  5);
//      self.addRoad(10, 10, 10, 0, -7);
//      self.addRoad(10, 10, 10, 0,  5);
//      self.addRoad(10, 10, 10, 0, -2);
	ENDFUNCTION

   	FUNCTION addDownhillToEnd%:num=200
  //    self.addRoad(num, num, num, -ROAD_CURVE_EASY, -lastY()/self.segmentLength);
    ENDFUNCTION

	FUNCTION resetRoad%:
	LOCAL segment AS tSegment

		DIM self.segments[0]
		DIM self.cars[0]

		self.addStraight(self.segments[],ROAD_LENGTH_SHORT%,0)
		self.addCurve(self.segments[],ROAD_LENGTH_SHORT%,-ROAD_CURVE_MEDIUM%,ROAD_HILL_HIGH%,0)
//		self.addCurve(self.segments[],ROAD_LENGTH_SHORT,-ROAD_CURVE_MEDIUM%,ROAD_HILL_HIGH%,0)
//		self.addCurve(self.segments[],ROAD_LENGTH_SHORT%,-ROAD_CURVE_MEDIUM%,-ROAD_HILL_HIGH%,0)
//		self.addCurve(self.segments[],ROAD_LENGTH_LONG%,ROAD_CURVE_MEDIUM%,ROAD_HILL_NONE%,0)
//		self.addStraight(self.segments[],ROAD_LENGTH_LONG%,0)
//		self.addStraight(self.segments[],ROAD_LENGTH_LONG%,0)
//		self.addStraight(self.segments[],ROAD_LENGTH_LONG%,0)
//		self.addCurve(self.segments[],ROAD_LENGTH_LONG%,-ROAD_CURVE_MEDIUM%,ROAD_HILL_NONE%,0)
//		self.addCurve(self.segments[],ROAD_LENGTH_SHORT%,ROAD_CURVE_MEDIUM%,ROAD_HILL_NONE%,0)
//		self.addStraight(self.segments[],ROAD_LENGTH_LONG%,0)
//		self.addCurve(self.segments[],ROAD_LENGTH_LONG%,-ROAD_CURVE_MEDIUM%,ROAD_HILL_NONE%,0)

		self.addHill(self.segments[],ROAD_LENGTH_SHORT%,ROAD_HILL_HIGH%,0)
		self.addHill(self.segments[],ROAD_LENGTH_MEDIUM%,-ROAD_HILL_HIGH%,0)
//		self.addCurve(self.segments[],ROAD_LENGTH_MEDIUM%, ROAD_CURVE_MEDIUM%, -ROAD_HILL_HIGH%,0)
//		self.addCurve(self.segments[],ROAD_LENGTH_LONG%, -ROAD_CURVE_EASY%, -ROAD_HILL_HIGH%,0)
//		self.addHill(self.segments[],ROAD_LENGTH_LONG%,-ROAD_HILL_HIGH%,0)
//		self.addHill(self.segments[],ROAD_LENGTH_SHORT%,-ROAD_HILL_HIGH%,0)
//		self.addHill(self.segments[],ROAD_LENGTH_LONG%,-ROAD_HILL_HIGH%,0)
//		self.addLowRollingHills(self.segments[],ROAD_LENGTH_SHORT%,ROAD_HILL_LOW%,0)
////		self.addSCurves(segments[])
//		self.addCurve(self.segments[],ROAD_LENGTH_LONG%, ROAD_CURVE_NONE%, ROAD_HILL_HIGH%)
//		self.addCurve(self.segments[],ROAD_LENGTH_MEDIUM%, ROAD_CURVE_MEDIUM%, ROAD_HILL_LOW)
//		self.addBumps()
//		self.addLowRollingHills(ROAD_LENGTH_SHORT%,ROAD_HILL_LOW%)
//		self.addCurve(self.segments[],ROAD_LENGTH_LONG%*2, ROAD_CURVE_MEDIUM%, ROAD_HILL_MEDIUM%)
//		self.addStraight()
//		self.addHill(self.segments[],ROAD_LENGTH_MEDIUM%, ROAD_HILL_HIGH%)
//		self.addSCurves()
//		self.addCurve(self.segments[],ROAD_LENGTH_SHORT%, ROAD_CURVE_NONE%, -ROAD_HILL_HIGH%)
//		self.addCurve(self.segments[],ROAD_LENGTH_LONG%, -ROAD_CURVE_MEDIUM%, ROAD_HILL_NONE%)
//		self.addHill(self.segments[],ROAD_LENGTH_LONG%, -ROAD_HILL_HIGH%)
//		self.addCurve(self.segments[],ROAD_LENGTH_LONG%, ROAD_CURVE_MEDIUM%, -ROAD_HILL_LOW%)
//		self.addBumps()
//		self.addHill(self.segments[],ROAD_LENGTH_LONG%, ROAD_HILL_MEDIUM%)
//		self.addStraight()
//		self.addSCurves()
//		self.addDownhillToEnd()

		self.resetSprites()
		self.resetCars()

		//segment=self.findSegment(self.segments[],self.playerZ)
//      	self.segments[segment.index% + 2].colour.road% = RGB(255,255,255)
//      	self.segments[segment.index% + 2].colour.lane% = RGB(255,255,255)
//      	self.segments[segment.index% + 3].colour.road% = RGB(255,255,255)
//      	self.segments[segment.index% + 3].colour.lane% = RGB(255,255,255)
//
//      	FOR n%=0 TO self.rumbleLength%-1
//	      	self.segments[BOUNDS(self.segments[],0)-1-n%].colour.road% = RGB(255,255,255)
//	      	self.segments[BOUNDS(self.segments[],0)-1-n%].colour.lane% = RGB(255,255,255)
//     	NEXT

//		self.segments[30].tunnel%=1
//		FOR n%=31 TO 501
//			IF n%<501
//				self.segments[n%].tunnel%=2
//			ELSE
//				self.segments[n%].tunnel%=3
//			ENDIF
//		NEXT

		self.trackLength% = BOUNDS(self.segments[],0)*self.segmentLength%
	ENDFUNCTION

	FUNCTION RndFloat:
		RETURN RND(1000)/1000.0
	ENDFUNCTION

 	FUNCTION accelerate:v,accel,dt
 		RETURN v + (accel * dt)
 	ENDFUNCTION

 	FUNCTION limit:value, minV,maxV
 		RETURN MAX(minV,MIN(value,maxV))
 	ENDFUNCTION

	FUNCTION easeIn:a,b,percent
		RETURN a + (b-a)*POW(percent,2)
	ENDFUNCTION

  	FUNCTION easeOut:a,b,percent
  		RETURN a + (b-a)*(1.0-POW(1-percent,2))
  	ENDFUNCTION

  	FUNCTION easeInOut:a,b,percent
  	LOCAL cosV,v

  //		DEBUG "A:"+a+" B:"+b+" Percent:"+percent+"\n"
  		cosV=(percent*PI)*(180.0/PI)
  		v=a + (b-a)*((-COS(cosV)/2.0) + 0.5)
//  		DEBUG "Value : "+v+"\n"
  		RETURN v
  	ENDFUNCTION

 	FUNCTION percentageRemaining:n,total
 		RETURN FMOD(n,total)/total
 	ENDFUNCTION

 	FUNCTION interpolate:a,b,percent
 		RETURN a+(b-a)*percent
 	ENDFUNCTION

	FUNCTION resetSprites%:
	LOCAL n%

    	self.addGraphic(TRUE,self.segmentLength%*20, 0,SPRITES_BILLBOARD_07%, -1,0.0)
    	self.addGraphic(TRUE,self.segmentLength%*40, 0,-1, -1.5,0.0);	self.addGraphic(TRUE,self.segmentLength%*40, 0,-1, 1.5,0.0);	self.addGraphic(TRUE,self.segmentLength%*40, 0,-2, -0.5,0.0,-3800)
    	self.addGraphic(TRUE,self.segmentLength%*60, 0,SPRITES_BILLBOARD_06%, -1,0.0)
    	self.addGraphic(TRUE,self.segmentLength%*80, 0,SPRITES_STUMP%, 0,0.0)
    	self.addGraphic(TRUE,self.segmentLength%*100, 0,SPRITES_STUMP%, -0.5,0.0);
    	self.addGraphic(TRUE,self.segmentLength%*120, 0,SPRITES_STUMP%, 0.5,0.0)
    	self.addGraphic(TRUE,self.segmentLength%*140, 0,SPRITES_BILLBOARD_08%, -1,0.0)
    	RETURN

//    	self.addSprite(80, SPRITES_BILLBOARD_09%, -1)
//    	self.addSprite(100, SPRITES_BILLBOARD_01%, -1)
//    	self.addSprite(120, SPRITES_BILLBOARD_02%, -1)
//    	self.addSprite(140, SPRITES_BILLBOARD_03%, -1)
//    	self.addSprite(160, SPRITES_BILLBOARD_04%, -1)
//		self.addSprite(180, SPRITES_BILLBOARD_05%, -1)
//
//		self.addSprite(240,                  SPRITES_BILLBOARD_07%, -1.2);
//      	self.addSprite(240,                  SPRITES_BILLBOARD_06%,  1.2);
//      	self.addSprite(BOUNDS(self.segments[],0) - 25, SPRITES_BILLBOARD_07%, -1.2);
//      	self.addSprite(BOUNDS(self.segments[],0) - 25, SPRITES_BILLBOARD_06%,  1.2);
//
//      	n%=10
//      	WHILE n%<200
//      		self.addSprite(n,SPRITES_PALM_TREE%,0.5+(self.RndFloat()*0.5))
//      		self.addSprite(n,SPRITES_PALM_TREE%,1+(self.RndFloat()*2))
//      		INC n%,4+FLOOR(n%/100)
//      	WEND
//
//      	FOR n%=250 TO 1000 STEP 5
//      		self.addSprite(n,SPRITES_COLUMN%,1.1)
//      		self.addSprite(n%+RND(5),SPRITES_DEAD_TREE1%,-1-(self.RndFloat()*2))
//      		self.addSprite(n%+RND(5),SPRITES_DEAD_TREE2%,-1-(self.RndFloat()*2))
//      	NEXT
//
//      	FOR n%=200 TO BOUNDS(self.segments[],0) STEP 3
//      	LOCAL index%,i%,v
//
//      		i%=RND(12)
//
//      		SELECT i%
//      			CASE	0
//      						index%=SPRITES_TREE1%
//
//      			CASE	1
//      						index%=SPRITES_TREE2%
//
//      			CASE	2
//      						index%=SPRITES_DEAD_TREE1%
//
//      			CASE	3
//      						index%=SPRITES_DEAD_TREE2%
//
//      			CASE	4
//      						index%=SPRITES_PALM_TREE%
//
//      			CASE	5
//      						index%=SPRITES_BUSH1%
//
//      			CASE	6
//      						index%=SPRITES_BUSH2%
//
//     			CASE	7
//     						index%=SPRITES_BUSH2%
//
//     			CASE	8
//     						index%=SPRITES_CATCUS%
//
//     			CASE	9
//     						index%=SPRITES_STUMP%
//
//     			CASE	10
//     						index%=SPRITES_BOULDER1%
//
//     			CASE	11
//     						index%=SPRITES_BOULDER2%
//
//     			CASE	12
//     						index%=SPRITES_BOULDER3%
//
//     			DEFAULT
//     						DEBUG "Ooops!"
//           	ENDSELECT
//
//      		IF RND(100)<50
//      			v=-1.0
//      		ELSE
//      			v=1
//      		ENDIF
//
//      		self.addSprite(n%,index%,v*(2+self.RndFloat()*5.0))
//      	NEXT
	ENDFUNCTION

	FUNCTION resetCars%:
	LOCAL n%,id%,v%,div%
//	LOCAL car AS tGraphic
//	LOCAL index%,v%,div%

		FOR n%=0 TO self.totalCars%

//			car.offset=RndFloat()*((RND(16)-8)/10)
//			car.z=
			v%=RND(5)
			SELECT v%
				CASE	0
							id%=CARS_CAR_01%
							div%=2

				CASE	1
							id%=CARS_CAR_02%
							div%=2

				CASE	2
							id%=CARS_CAR_03%
							div%=2

				CASE	3
							id%=CARS_CAR_04%
							div%=2

				CASE	4
							id%=CARS_SEMI%
							div%=4

				CASE	5
							id%=CARS_TRUCK%
							div%=2

			ENDSELECT

			self.addGraphic(FALSE,FLOOR(RndFloat()*BOUNDS(self.segments[],0))*self.segmentLength,0,id%,RndFloat()*((RND(16)-8)/10), _
							self.maxSpeed/4.0+RndFloat()*self.maxSpeed/div%)

//			car.speed=self.maxSpeed/4.0+RndFloat()*self.maxSpeed/div%
//			car.percent=0.0
//			car.which%=BOUNDS(self.cars[],0)

//			DIMPUSH self.segments[MOD(FLOOR(car.z/self.segmentLength%),BOUNDS(self.segments[],0))].cars[],car
//			DIMPUSH self.cars[],car
		NEXT
	ENDFUNCTION

	FUNCTION lastY:segments[] AS tSegment
	LOCAL size%

		size%=BOUNDS(segments[],0)
		IF size%=0
			RETURN 0
		ELSE
			RETURN segments[size%-1].roads[0].p2.world.y
		ENDIF
	ENDFUNCTION

	FUNCTION findSegment AS tSegment:segments[] AS tSegment,z
		RETURN segments[MOD(FLOOR(z/self.segmentLength%),BOUNDS(segments[],0))]
	ENDFUNCTION

	FUNCTION increase: start,increment,maxV
	LOCAL result

		result=start+increment
		WHILE result>=maxV
			DEC result,maxV
		WEND

		WHILE result<0
			INC result,maxV
		WEND

		RETURN result
	ENDFUNCTION


	FUNCTION fog%:x%,y%,width%,height%
		ALPHAMODE -0.9
		DRAWRECT x%,y%,width%,height%,RGB(64,64,64)
		ALPHAMODE -1.0
	ENDFUNCTION

	FUNCTION updateCars%:dt,playerSegment AS tSegment,playerW
	LOCAL n%
	LOCAL oldSegment AS tSegment,newSegment AS tSegment
	//LOCAL road AS TRoad
	LOCAL oldIndex%,newIndex%

		FOR n%=0 TO BOUNDS(self.cars[],0)-1
			oldSegment=self.findSegment(self.segments[],self.cars[n%].z)
			oldIndex%=FMOD(FLOOR(self.cars[n%].z/self.segmentLength%),BOUNDS(self.segments[],0))

			INC self.cars[n%].xOffset,self.updateCarOffset(self.cars[n%],oldSegment,playerSegment,playerW)
			self.cars[n%].z=self.increase(self.cars[n%].z,dt*self.cars[n%].moveSpeed,self.trackLength)
			self.cars[n%].percent=self.percentageRemaining(self.cars[n%].z,self.segmentLength)

			newSegment=self.findSegment(self.segments[],self.cars[n%].z)
			newIndex%=FMOD(FLOOR(self.cars[n%].z/self.segmentLength%),BOUNDS(self.segments[],0))
			//DEBUG "NZ:"+self.cars[n%].moveSpeed+"\n"
			//DEBUG "Speed : "+self.cars[n%].speed+"\n"
//			DEBUG "O:"+oldIndex%+" N:"+newIndex%+" "+self.cars[n%].percent+"\n"
			IF oldIndex%<>newIndex%
//				DEBUG "Here1\n"
//				KEYWAIT
				//FOREACH road IN self.segments[oldIndex%].roads[]
				//DEBUG "Road index : "+self.cars[n%].index%
//				DEBUG "Size : "+BOUNDS(self.segments[oldIndex].roads[self.cars[n%].roadIndex%].cars[],0)+"\n"
//				DEBUG "OI:"+oldIndex%+" "+self.cars[n%].roadIndex%+"\n"
//				KEYWAIT
				FOR index%=0 TO BOUNDS(self.segments[oldIndex].roads[self.cars[n%].roadIndex%].cars[],0)-1
					//DEBUG self.segments[oldIndex].roads[self.cars[n%].roadIndex%].cars[index%].index%+" "+self.cars[n%].index%+"\n"
					IF self.segments[oldIndex].roads[self.cars[n%].roadIndex%].cars[index%].index%=self.cars[n%].index%
						DIMDEL self.segments[oldIndex].roads[self.cars[n%].roadIndex%].cars[],index%
						DIMPUSH self.segments[newIndex].roads[self.cars[n%].roadIndex%].cars[],self.cars[n%]
//						DEBUG "Found\n"
//						KEYWAIT
					ENDIF
				NEXT
//				//KEYWAIT
			ENDIF
		NEXT
	ENDFUNCTION

	FUNCTION overlap:x1,w1,x2,w2,percent=1.0
	LOCAL half,min1,min2,max1,max2

    	half = percent/2;
    	min1 = x1 - (w1*half)
    	max1 = x1 + (w1*half)
    	min2 = x2 - (w2*half)
    	max2 = x2 + (w2*half)
    	RETURN IIF(max1<min2 OR min1>max2,FALSE,TRUE)
    ENDFUNCTION

    FUNCTION updateCarOffset:car AS tGraphic,carSegment AS tSegment,playerSegment AS tSegment,playerW
	LOCAL i%,j%
	LOCAL carW,dir,otherCarW
	LOCAL lookAhead%=30
	LOCAL segment AS tSegment
	LOCAL otherCar AS tGraphic
	LOCAL segmentIndex%,playerIndex%

		carW=car.orgXSize*self.SPRITES_SCALE

		IF carSegment.index-playerSegment.index>self.drawDistance THEN RETURN 0.0

		playerIndex%=FMOD(FLOOR(playerSegment.roads[0].p1.world.z/self.segmentLength%),BOUNDS(self.segments[],0))

		FOR i%=1 TO lookAhead%-1
			segmentIndex%=FMOD(FLOOR(carSegment.index+i%),BOUNDS(self.segments[],0))
			IF segmentIndex%=playerIndex% AND car.moveSpeed>self.playerInfo.speed AND self.overlap(self.playerInfo.graphic.xOffset, playerW, car.xOffset, carW, 1.2)
				IF self.playerInfo.graphic.xOffset>0.5
					dir=-1.0
				ELSEIF (self.playerInfo.graphic.xOffset<-0.5)
					dir=1.0
				ELSE
					dir=IIF(car.xOffset>self.playerInfo.graphic.xOffset,1,-1)
				ENDIF

				RETURN dir*1/i*(car.moveSpeed-self.playerInfo.speed)/self.maxSpeed
			ENDIF

			FOR j%=0 TO BOUNDS(self.segments[segmentIndex%].roads[0].cars[],0)-1
				otherCar=self.segments[segmentIndex%].roads[0].cars[j%]
				otherCarW=otherCar.orgXSize*self.SPRITES_SCALE
//
				IF car.speed>otherCar.moveSpeed AND self.overlap(car.xOffset, carW, otherCar.xOffset, otherCarW, 1.2)
					IF otherCar.xOffset>0.5
						dir=-1
					ELSEIF otherCar.xOffset<-0.5
						dir=1
					ELSE
						dir=IIF(car.xOffset>otherCar.xOffset,1,-1)
					ENDIF
//
					RETURN dir*1/i*(car.speed-otherCar.speed)/self.maxSpeed
				ENDIF
			NEXT
		NEXT

		IF car.xOffset<-0.9
			RETURN 0.1
		ELSEIF car.xOffset>0.9
			RETURN -0.1
		ELSE
			RETURN 0.0
		ENDIF
	ENDFUNCTION

	FUNCTION update%:dt
	LOCAL dx
	LOCAL playerSegment AS tSegment
	LOCAL startPosition,speedPercentage
	LOCAL playerW // ,tW%,tH%

//		DEBUG dt+"\n"
//		DEBUG "Speed:"+self.speed+"\n"
//		DEBUG (dt*self.speed)+"\n"

		playerW=self.playerInfo.graphic.orgXSize*self.SPRITES_SCALE

		playerSegment=self.findSegment(self.segments[],self.playerInfo.graphic.z+self.playerInfo.cameraZ)
		startPosition=self.playerInfo.graphic.z
		speedPercentage=self.playerInfo.speed/self.maxSpeed


      	self.playerInfo.segmentIndex%=MOD(FLOOR(self.playerInfo.graphic.z/self.segmentLength%),BOUNDS(self.segments[],0))
      	self.playerInfo.playerPercent=self.percentageRemaining(self.playerInfo.graphic.z+self.playerInfo.cameraZ,self.segmentLength%)
      	self.playerInfo.graphic.z = self.increase(self.playerInfo.graphic.z, dt * self.playerInfo.speed, self.trackLength)
      	//DEBUG self.playerInfo.playerPercent+"\n"
      			//self.playerInfo.playerSegment= findSegment(self.segments[],self.playerInfo.graphic.z+self.playerInfo.graphic.z)
      	dx = dt * 2 * (self.playerInfo.speed/self.maxSpeed); // at top speed, should be able to cross from left to right (-1 to 1) in 1 second

		self.updateCars(dt,playerSegment,playerW)

		IF KEY(203)
			DEC self.playerInfo.graphic.xOffset,dx
			self.keyLeftRight%=-1
		ELSEIF KEY(205)
			INC self.playerInfo.graphic.xOffset,dx
			self.keyLeftRight%=1
		ELSE
			self.keyLeftRight%=0
		ENDIF

		self.playerInfo.graphic.xOffset = self.playerInfo.graphic.xOffset - (dx * speedPercentage * playerSegment.curve * self.centrifugal)

		IF KEY(200)
			self.playerInfo.speed=self.accelerate(self.playerInfo.speed,self.accel,dt)
		ELSEIF KEY(208)
			self.playerInfo.speed=self.accelerate(self.playerInfo.speed,self.breaking,dt)
		ELSE
			self.playerInfo.speed=self.accelerate(self.playerInfo.speed,self.decel,dt)
		ENDIF

		IF self.playerInfo.graphic.xOffset<-1 OR self.playerInfo.graphic.yOffset>1
			IF self.playerInfo.speed>self.offRoadLimit
				self.playerInfo.speed=self.accelerate(self.playerInfo.speed,self.offRoadDecel,dt)
			ENDIF

//			FOR n%=0 TO BOUNDS(playerSegment.sprites[],0)-1
//			LOCAL sprite AS tSprite
//			LOCAL sW,sH,spriteW
//
//				sprite=playerSegment.sprites[n%]
//				GETSPRITESIZE sprite.id%,sW,sH // Need to calculate current size and not the original size
//
//				spriteW=sW*self.SPRITES_SCALE
//
//				IF self.overlap(self.playerX,playerW,sprite.offset+spriteW/2*IIF(sprite.offset>0,1,-1),spriteW)
//					self.speed=self.maxSpeed/5.0
//					self.position=increase(playerSegment.p1.world.z,-self.playerZ,self.trackLength)
//					BREAK
//				ENDIF
//			NEXT
		ENDIF

//		FOR n%=0 TO BOUNDS(playerSegment.cars[],0)-1
//		LOCAL car AS tCar
//		LOCAL sW,sH,carW
//
//			car=playerSegment.cars[n%]
//			GETSPRITESIZE car.id%,sW,sH
//			carW=sW*self.SPRITES_SCALE
//
//			IF self.speed>car.speed
//				IF self.overlap(self.playerX,playerW,car.offset,carW,0.8)
//					self.speed=car.speed*(car.speed/self.speed)
//					self.position=increase(car.z,-self.playerZ,self.trackLength)
//					BREAK
//				ENDIF
//			ENDIF
//		NEXT
//
		self.playerInfo.graphic.xOffset=self.limit(self.playerInfo.graphic.xOffset,-3,3)
		self.playerInfo.speed=self.limit(self.playerInfo.speed,0.0,self.maxSpeed)

		self.skyOffset=self.increase(self.skyOffset,  self.skySpeed  * playerSegment.curve * (self.playerInfo.graphic.z-startPosition)/self.segmentLength, 1);
		self.hillOffset = self.increase(self.hillOffset, self.hillSpeed * playerSegment.curve * (self.playerInfo.graphic.z-startPosition)/self.segmentLength, 1);
      	self.treeOffset = self.increase(self.treeOffset, self.treeSpeed * playerSegment.curve * (self.playerInfo.graphic.z-startPosition)/self.segmentLength, 1);
	ENDFUNCTION

	FUNCTION project%:p AS tPart, cameraX, cameraY, cameraZ, cameraDepth, swidth, sheight, roadWidth%, rumbleWidth%
		p.camera.x=p.world.x - cameraX
		p.camera.y=p.world.y - cameraY
		p.camera.z=p.world.z - cameraZ

		p.screen.scale=cameraDepth/p.camera.z

		p.screen.x=((swidth/2.0)+(p.screen.scale*p.camera.x*swidth/2.0))
		p.screen.y=((sheight/2.0)-(p.screen.scale*p.camera.y*sheight/2.0))
		p.screen.w=(p.screen.scale*roadWidth%*swidth/2.0)

		p.rumbleWidth=p.screen.w/rumbleWidth%
	ENDFUNCTION

	FUNCTION player%:width%, height%, resolution, roadWidth, graphic AS tGraphic, speedPercent, scale, destX, destY, steer, updown
	LOCAL bounce
	LOCAL sprite%

		bounce=(1.5 *RndFloat() * speedPercent * resolution) * (RND(2)-1)
		IF steer<0
			sprite%=IIF(updown>0,PLAYER_UPHILL_LEFT%,PLAYER_LEFT%)
		ELSEIF steer>0
			sprite%=IIF(updown>0,PLAYER_UPHILL_RIGHT%,PLAYER_RIGHT%)
		ELSE
			sprite%=IIF(updown>0,PLAYER_UPHILL_STRAIGHT%,PLAYER_STRAIGHT%)
		ENDIF

		//DEBUG "SP:"+sprite%+"\n"


//DEBUG "Dest Y : "+destY+"\n"

		self.sprite(width%,height%,resolution,roadWidth,graphic,scale,destX,destY+bounce,-0.5,-1)
	ENDFUNCTION

	FUNCTION sprite%:width%, height%, resolution, roadWidth, graphic AS tGraphic, scale, destX, destY, offsetX, offsetY, clipY=0.0
	LOCAL clipH

		graphic.currentXSize=(graphic.orgXSize*scale*width%/2.0)*(self.SPRITES_SCALE*roadWidth)
		graphic.currentYSize=(graphic.orgYSize*scale*width%/2.0)*(self.SPRITES_SCALE*roadWidth)

		INC destX,graphic.currentXSize*offsetX
		INC destY,graphic.currentYSize*offsetY

		clipH=IIF(clipY,MAX(0,destY+graphic.currentYSize-clipY),0)

//		DEBUG destW+" "+(destH-clipH)+"\n"
//		KEYWAIT

		IF clipH<graphic.currentYSize
			IF graphic.id%>=0
				STRETCHSPRITE graphic.id%,destX,destY,graphic.currentXSize,graphic.currentYSize-clipH
		 	ELSE
		 		DRAWRECT destX,destY,graphic.currentXSize,graphic.currentYSize-clipH,RGB(255,255,255)
		 	ENDIF
		 ENDIF
	ENDFUNCTION

	FUNCTION background%:spr%,width%,height%,layer%,rotation=0.0,offset=0.0
	LOCAL w,h,imageW,imageH
	LOCAL sourceX,sourceY,sourceW,sourceH
	LOCAL destX,destY,destW,destH

		GETSPRITESIZE spr%,w,h

		imageW=w/2.0
		imageH=h

		sourceX=0.0+FLOOR(w*rotation)
		sourceY=0.0
		sourceW=MIN(imageW,0+w-sourceX)
		sourceH=imageH

		destX=FLOOR(w * rotation)
		IF destX<=-0.0-width%
			destX=width%
		ELSEIF destX>=width%
			destX=0.0-width%
		ENDIF

		destY=offset
		destW=width% // FLOOR(width*(sourceW/imageW))
		destH=height%

		STRETCHSPRITE spr%,destX,destY,destW,destH
		STRETCHSPRITE spr%,destX-width%,destY,destW,destH
		STRETCHSPRITE spr%,destX+width%,destY,destW,destH
	ENDFUNCTION

	FUNCTION render%:
	LOCAL baseSegment AS tSegment,playerSegment AS tSegment
	//LOCAL basePercentage
	LOCAL playerY,playerPercent
	LOCAL maxy,n%,spriteID%,sIndex%,r%,index%

	LOCAL graphic AS tGraphic
	LOCAL graphicScale,graphicX,graphicY

	LOCAL seg AS tSegment
	LOCAL x,dx
	LOCAL indexes[] AS tRoadPos
	LOCAL indexLoop AS tRoadPos

		maxy=self.height%

		baseSegment = self.findSegment(self.segments[],self.playerInfo.graphic.z)
		playerSegment=self.findSegment(self.segments[],self.playerInfo.graphic.z+self.playerInfo.cameraZ)
		//playerPercent=self.percentageRemaining(self.playerInfo.position+self.playerInfo.graphic.z,self.segmentLength%)
		playerY= self.interpolate(playerSegment.roads[0].p1.world.y, _
								  playerSegment.roads[0].p2.world.y, _
								  self.playerInfo.playerPercent)

		x=0.0
		dx=-(baseSegment.curve*self.percentageRemaining(self.playerInfo.graphic.z,self.segmentLength%))

		self.background(BACKGROUND_SKY%, self.width%, self.height%, BACKGROUND_SKY%,   self.skyOffset,  self.resolution * self.skySpeed  * playerY)
		self.background(BACKGROUND_HILLS%, self.width%, self.height%, BACKGROUND_HILLS%,   self.hillOffset,  self.resolution * self.hillSpeed  * playerY)
		self.background(BACKGROUND_TREES%, self.width%, self.height%, BACKGROUND_TREES%,   self.treeOffset,  self.resolution * self.treeSpeed  * playerY);

		PRINT baseSegment.index%,0,16

		// Part 1 - Calculate all segment positions for all roads
		FOR n%=0 TO self.drawDistance%-1
			sIndex%=MOD(baseSegment.index%+n%,BOUNDS(self.segments[],0))

			// Calculate all segment positions and scaling values
			self.segments[sIndex%].clip=maxy

			FOR index%=0 TO BOUNDS(self.segments[sIndex%].roads[],0)-1
				self.project(self.segments[sIndex%].roads[index%].p1, _
							(self.playerInfo.graphic.xOffset*self.segments[sIndex%].roads[index%].roadWidth%)-x, _
							playerY+self.playerInfo.cameraHeight, _
							self.playerInfo.graphic.z, _
							self.playerInfo.cameraDepth, self.width%,self.height%, _
							self.segments[sIndex%].roads[index%].roadWidth%, _
							self.segments[sIndex%].roads[index%].rumbleWidth%)

				self.project(self.segments[sIndex%].roads[index%].p2, _
							(self.playerInfo.graphic.xOffset*self.segments[sIndex%].roads[index%].roadWidth%)-x-dx, _
							playerY+self.playerInfo.cameraHeight, _
							self.playerInfo.graphic.z, _
							self.playerInfo.cameraDepth, _
							self.width%,self.height%, _
							self.segments[sIndex%].roads[index%].roadWidth%,self.segments[sIndex%].roads[index%].rumbleWidth%)
			NEXT

			INC x,dx
			INC dx,baseSegment.curve

			FOR index%=0 TO 0
				IF self.segments[sIndex%].roads[index%].p1.camera.z<=self.playerInfo.cameraDepth OR _
					self.segments[sIndex%].roads[index%].p2.screen.y >= maxy
					CONTINUE
				ELSE
					self.drawRoad(self.width%,self.segments[sIndex%].roads[index%])
				ENDIF
			NEXT

			maxy=self.segments[sIndex%].roads[0].p1.screen.y
		NEXT

		// Part 2 - Make sure that not duplicate roads would be displayed


		self.player(self.width%, self.height%, self.resolution, 4000 , _
							self.playerInfo.graphic,self.playerInfo.speed/self.maxSpeed, _
							self.playerInfo.cameraDepth/self.playerInfo.cameraZ, _
							self.width%/2, _
							(self.height/2.0)- (self.playerInfo.cameraDepth/self.playerInfo.cameraZ * self.interpolate(playerSegment.roads[0].p1.camera.y, playerSegment.roads[0].p2.camera.y, self.playerInfo.playerPercent) * self.height/2.0), _
							self.playerInfo.speed * SGN(self.keyLeftRight%), _
							self.segments[self.playerInfo.segmentIndex%].roads[0].p2.world.y - self.segments[self.playerInfo.segmentIndex%].roads[0].p1.world.y)


//		IF playerSegment.tunnel%=2
//			ALPHAMODE -0.3
//			DRAWRECT 0,0,self.width,self.height%,RGB(1,1,1)
//		ENDIF


	ENDFUNCTION

	FUNCTION laneMarkerWidth:projectedRoadWidth%,lanes%
		RETURN projectedRoadWidth/MAX(32,8*lanes%)
	ENDFUNCTION

	FUNCTION polygon2%:x%,y%,width%,height%
		STARTPOLY -1
			POLYVECTOR width%,y%,0,0,RGB(0,255,0)
			POLYVECTOR x%,y%,0,0,RGB(255,0,0)
			POLYVECTOR x%,height%,0,0,RGB(0,255,0)
			POLYVECTOR width%,height%,0,0,RGB(0,0,255)
		ENDPOLY

	ENDFUNCTION



	FUNCTION polygon%:x1,y1,x2,y2,x3,y3,x4,y4,colour%
		STARTPOLY -1,0
			POLYVECTOR (x1),(y1),(x2),(y2),colour%
			POLYVECTOR (x2),(y2),(x3),(y3),colour%
			POLYVECTOR (x3),(y3),(x4),(y4),colour%
			POLYVECTOR (x4),(y4),(x1),(y1),colour%
		ENDPOLY

//		DRAWRECT x1,y1,x2,y2,colour%
//		DRAWRECT x3,y3,x4,y4,colour%

		//DRAWLINE x1,y1,x2,y2,colour%
		//DRAWLINE x3,y3,x4,y4,colour%
	ENDFUNCTION

	FUNCTION drawRoad%:width%,segment AS tSegmentPart
	LOCAL r1,r2,l1,l2,lanew1,lanew2,lanex1,lanex2

//		DRAWRECT 0,.p2.screen.y, _
//				self.width%,self.segments[sIndex%].roads[0].p1.screen.y-self.segments[sIndex%].roads[0].p2.screen.y, _
//				self.segments[sIndex%].roads[0].colour.rightGrass%

		self.polygon(segment.p1.screen.x-segment.p1.screen.w, segment.p1.screen.y, _
    				 segment.p1.screen.x+segment.p1.screen.w, segment.p1.screen.y, _
    				 segment.p2.screen.x+segment.p2.screen.w, segment.p2.screen.y, _
    				 segment.p2.screen.x-segment.p2.screen.w, segment.p2.screen.y, _
    				 segment.colour.road)

    	IF segment.numLanes%>0
    		l1=self.laneMarkerWidth(segment.p1.screen.w,segment.numLanes%)
			l2=self.laneMarkerWidth(segment.p2.screen.w,segment.numLanes%)

    		lanew1=segment.p1.screen.w*2.0/segment.numLanes%
    		lanew2=segment.p2.screen.w*2.0/segment.numLanes%

    		lanex1=segment.p1.screen.x-segment.p1.screen.w+lanew1
    		lanex2=segment.p2.screen.x-segment.p2.screen.w+lanew2

    		FOR lane%=1 TO segment.numLanes%-1
    			self.polygon(lanex1-l1/2.0,segment.p1.screen.y, _
    							lanex1+l1/2.0,segment.p1.screen.y, _
    							lanex2+l2/2.0,segment.p2.screen.y, _
    							lanex2-l2/2.0,segment.p2.screen.y, _
    							segment.colour.lane%)
    			INC lanex1,lanew1
    			INC lanex2,lanew2
    		NEXT
    	ENDIF
	ENDFUNCTION

	FUNCTION drawRumble%:roadPos AS tSegmentPart,dir%
		IF dir%>0
			self.polygon( roadPos.p1.screen.x+roadPos.p1.screen.w+roadPos.p1.rumbleWidth,  roadPos.p1.screen.y, _
						  roadPos.p1.screen.x+roadPos.p1.screen.w,  roadPos.p1.screen.y, _
						  roadPos.p2.screen.x+roadPos.p2.screen.w,  roadPos.p2.screen.y, _
						  roadPos.p2.screen.x+roadPos.p2.screen.w+roadPos.p2.rumbleWidth,  roadPos.p2.screen.y, _
						  roadPos.colour.rumble)
		ELSEIF dir%<0
			self.polygon( roadPos.p1.screen.x-roadPos.p1.screen.w-roadPos.p1.rumbleWidth,  roadPos.p1.screen.y, _
						  roadPos.p1.screen.x-roadPos.p1.screen.w,  roadPos.p1.screen.y, _
						  roadPos.p2.screen.x-roadPos.p2.screen.w,  roadPos.p2.screen.y, _
						  roadPos.p2.screen.x-roadPos.p2.screen.w-roadPos.p2.rumbleWidth,  roadPos.p2.screen.y, _
						  roadPos.colour.rumble)
		ENDIF
	ENDFUNCTION

	FUNCTION drawGrass%:roadPos AS tSegmentPart,width%,dir%

		IF dir%=TRUE
		self.polygon(0, roadPos.p1.screen.y, _
						roadPos.p1.screen.x-roadPos.p1.screen.w-roadPos.p1.rumbleWidth, roadPos.p1.screen.y, _
						roadPos.p2.screen.x-roadPos.p2.screen.w-roadPos.p2.rumbleWidth, roadPos.p2.screen.y, _
						0, roadPos.p2.screen.y, _
						roadPos.colour.leftGrass%)
		ELSE
		self.polygon(width%, roadPos.p1.screen.y, _
						roadPos.p1.screen.x+roadPos.p1.screen.w+roadPos.p1.rumbleWidth, roadPos.p1.screen.y, _
						roadPos.p2.screen.x+roadPos.p2.screen.w+roadPos.p2.rumbleWidth, roadPos.p2.screen.y, _
						width%, roadPos.p2.screen.y, _
						roadPos.colour.rightGrass%)
		ENDIF
    ENDFUNCTION
ENDTYPE

LOCAL road AS TRoad
LOCAL now,last,dt=0.0,gdt=0.0,stp=1.0/75.0
SETSCREEN 640,480,FALSE

LIMITFPS -1

PLAYMUSIC "Media/arc_or2_mss.mp3",FALSE

LOADSPRITE "Media/player_straight.png",PLAYER_STRAIGHT%
LOADSPRITE "Media/player_left.png",PLAYER_LEFT%
LOADSPRITE "Media/player_right.png",PLAYER_RIGHT%
LOADSPRITE "Media/player_uphill_straight.png",PLAYER_UPHILL_STRAIGHT%
LOADSPRITE "Media/player_uphill_left.png",PLAYER_UPHILL_LEFT%
LOADSPRITE "Media/player_uphill_right.png",PLAYER_UPHILL_RIGHT%
LOADSPRITE "Media/billboard01.png",SPRITES_BILLBOARD_01%
LOADSPRITE "Media/billboard02.png",SPRITES_BILLBOARD_02%
LOADSPRITE "Media/billboard03.png",SPRITES_BILLBOARD_03%
LOADSPRITE "Media/billboard04.png",SPRITES_BILLBOARD_04%
LOADSPRITE "Media/billboard05.png",SPRITES_BILLBOARD_05%
LOADSPRITE "Media/billboard06.png",SPRITES_BILLBOARD_06%
LOADSPRITE "Media/billboard07.png",SPRITES_BILLBOARD_07%
LOADSPRITE "Media/billboard08.png",SPRITES_BILLBOARD_08%
LOADSPRITE "Media/billboard09.png",SPRITES_BILLBOARD_09%
LOADSPRITE "Media/palm_tree.png",SPRITES_PALM_TREE%
LOADSPRITE "Media/column.png",SPRITES_COLUMN%
LOADSPRITE "Media/dead_tree1.png",SPRITES_DEAD_TREE1%
LOADSPRITE "Media/dead_tree2.png",SPRITES_DEAD_TREE2%
LOADSPRITE "Media/cactus.png",SPRITES_CATCUS%
LOADSPRITE "Media/tree1.png",SPRITES_TREE1%
LOADSPRITE "Media/tree2.png",SPRITES_TREE2%
LOADSPRITE "Media/bush1.png",SPRITES_BUSH1%
LOADSPRITE "Media/bush2.png",SPRITES_BUSH2%
LOADSPRITE "Media/stump.png",SPRITES_STUMP%
LOADSPRITE "Media/boulder1.png",SPRITES_BOULDER1%
LOADSPRITE "Media/boulder2.png",SPRITES_BOULDER2%
LOADSPRITE "Media/boulder3.png",SPRITES_BOULDER3%
LOADSPRITE "Media/tunnelwall.png",SPRITES_TUNNELWALL%
LOADSPRITE "Media/tunneltop.png",SPRITES_TUNNELTOP%
LOADSPRITE "Media/sky.png",BACKGROUND_SKY%
LOADSPRITE "Media/hills.png",BACKGROUND_HILLS%
LOADSPRITE "Media/trees.png",BACKGROUND_TREES%
LOADSPRITE "Media/car01.png",CARS_CAR_01%
LOADSPRITE "Media/car02.png",CARS_CAR_02%
LOADSPRITE "Media/car03.png",CARS_CAR_03%
LOADSPRITE "Media/car04.png",CARS_CAR_04%
LOADSPRITE "Media/semi.png",CARS_SEMI%
LOADSPRITE "Media/truck.png",CARS_TRUCK%


road.Initialise()
road.resetRoad()

now=GETTIMERALL()
last=GETTIMERALL()

WHILE TRUE
	SMOOTHSHADING FALSE
	ALPHAMODE -1.0

	road.render()
	SHOWSCREEN

	dt=MIN(1.0,(now-last)/1000.0)
	INC gdt,dt

	WHILE gdt>stp
		DEC gdt,stp
		road.update(stp)
	WEND

	//road.update(stp)

	last = now
	now=GETTIMERALL()
WEND

I've included a more complete version (although the rendering order is still incorrect). If anyone can find the problem, I would be grateful!

Advertisement
I don't know about GLBasic, but I can give it a shot (generally). Is it gittering as you move or is it doing it constantly? I would make sure you are doing all the position updates at the same time. For instance, if your road "position" is relative to the terrain, you should update the terrain's position BEFORE updating the road. If you use the "old" position for the terrain to update your road, you would see the road "gitter" depending on camera movement.

This topic is closed to new replies.

Advertisement