TRACK_LUA = true

-- track texture map files
STNDS_FILE = "data/stands.obj"
GRASS_FILE = "data/grass-far.obj"
TRACK_FILE = "data/track.obj"


-- scenery obj files
MOUNT_FILE = "data/mountain2.obj"
POSTS_FILE = "data/posts.obj"
FLINE_FILE = "data/line.obj"

-- hazard obj files
BLOCK_FILE = "data/block.obj"

-- sprite image files
SMIRK_FILE = "data/smirk.png"
AWALL_FILE = "data/arrows_2.png"
STRE1_FILE = "data/snow_tree.png"
STRE2_FILE = "data/snow_tree_2.png"
STRE3_FILE = "data/snow_tree_3.png"
PSIGN_FILE = "data/polarissign.png"
BSIGN_FILE = "data/bmsign.png"
BSIG2_FILE = "data/bmsign2.png"

-- obstacle colormap and heightmap files
OBSBG_FILE = "data/obstacles/obs_bkgrnd.png"
OBS1H_FILE = "data/obstacles/large1.jpg"
OBS2H_FILE = "data/obstacles/med1.jpg"
OBS3H_FILE = "data/obstacles/largeL.jpg"
OBS4H_FILE = "data/obstacles/largeR.jpg"
OBS5H_FILE = "data/obstacles/rampF2.jpg"
OBS6H_FILE = "data/obstacles/rampN2.jpg"
OBS7H_FILE = "data/obstacles/small1.jpg"
OBS8H_FILE = "data/obstacles/wide.jpg"
OBS9H_FILE = "data/obstacles/struc1-1.jpg"
OBS10_FILE = "data/obstacles/struc1-2.jpg"
OBS11_FILE = "data/obstacles/struc1-3.jpg"



track = {}

-- track constants
track.numsegs   = 200     -- number of track segments to maintain
track.finish    = -3000   -- position of the finish line
track.lappoint  = -1500
track.segwidth  = 32      -- each segment is 32 units wide
track.segseclen = 32      -- segments are split into sections,
                          --    each segment section is 32 units long
track.tracksect = 2       -- the section that contains the track
track.fric_grnd = 100
track.fric_ice  = 10
track.fric_dirt = 500

track.wayp_size = 5

track.rnd_min_x = -40     -- x and z boundaries that define a space 
track.rnd_max_x = 5       --   that will be populated with randomly
track.rnd_min_z = -1000   --   positioned items from the 3d scenery
track.rnd_max_z = 50      --   list

track.viewgeoms = false   -- show physics bounding boxes 
track.viewwaypt = false
track.viewobs   = false   -- show the geometry of obstacles
track.makeobs   = true    -- create physics part of obstacles

-- define 3d scenery here:
--     track.object_defs.file : the .obj file path
--     track.object_defs.rnd  : specifies a upper limit to the random 
--                              number of items of this type to create.
--                              If rnd is greater than 0, then the items
--                              will be randomly scattered in an area 
--                              bounded by the rnd_min/rnd_max values 
--                              specified above and offset by translate
--                              values 1-3. If nil, then only one item 
--                              will be created and placed at the 
--                              x, y, z position specified by translate
--                              values 1-3.
--     track.object_defs[1-3] : x, y, z position translation values 
--     track.object_defs[4-6] : x, y, z rotation values
--     track.object_defs[7-9] : x, y, z scale values
track.object_defs = { 
    { file = MOUNT_FILE, rnd = nil; -170, -8,  640,   0, 0,  0, 5, 5, 10 },
    { file = MOUNT_FILE, rnd = nil; -170, -8,  0,     0, 0,  0, 5, 5, 10 },
    { file = MOUNT_FILE, rnd = nil; -170, -8,  -640,  0, 0,  0, 5, 5, 10 },
    { file = MOUNT_FILE, rnd = nil; -170, -8,  -1280, 0, 0,  0, 5, 5, 10 },
    { file = MOUNT_FILE, rnd = nil; -170, -8,  -1920, 0, 0,  0, 5, 5, 10 },
    { file = MOUNT_FILE, rnd = nil; -170, -8,  -2560, 0, 0,  0, 5, 5, 10 },
    { file = MOUNT_FILE, rnd = nil; -170, -8,  -3200, 0, 0,  0, 5, 5, 10 },
    { file = MOUNT_FILE, rnd = nil; -170, -8,  -3840, 0, 0,  0, 5, 5, 10 },
    { file = MOUNT_FILE, rnd = nil; -170, -8,  -4480, 0, 0,  0, 5, 5, 10 },
    { file = FLINE_FILE, rnd = nil; 0,    0,   -5,    10,0,  0, 1, 1, 1  },
    { file = FLINE_FILE, rnd = nil; 0,    0,   track.finish,
	10, 0,  0, 1, 1, 1  },
    { file = POSTS_FILE, rnd = nil; 0,    0,   track.lappoint,
	10, 0,  0, 1, 1, 1  },
}

-- define 2d scenery here:
--     track.billboard_defs.file : the .obj file path
--     track.billboard_defs.rnd  : specifies a upper limit to the random 
--                                 number of items of this type to create.
--                                 If rnd is greater than 0, then the items
--                                 will be randomly scattered in an area 
--                                 bounded by the rnd_min/rnd_max values 
--                                 specified above and offset by translate
--                                 values 1-3. If nil, then only one item 
--                                 will be created and placed at the 
--                                 x, y, z position specified by translate
--                                 values 1-3.
--     track.billboard_defs[1-3] : x, y, z position translation values 
--     track.billboard_defs[4,5] : x and y scale values. For billboarded 
--                                 sprites, the item will always be oriented
--                                 with its Z axis towards the camera. Since
--                                 it's a 2d sprite, it has no depth, so
--                                 scaling the Z axis is not applicable.
--                                 NOTE: scale is 1:1 pixels to units
--                                 which means a 256x256 image map would
--                                 be huge. So they must be scaled down.
--                                 Scale factors can be computed with
--                                 [desired units]/[pixels] along each
--                                 axis. 
track.billboard_defs = {
    { file=STRE1_FILE, rnd=100; -18, 10, -9; -60, 0, -2000; 20/512, 20/512 },
    { file=STRE2_FILE, rnd=100; -18, 10, -9; -60, 0, -2000; 20/512, 20/512 },
    { file=STRE3_FILE, rnd=100; -18, 10, -9; -60, 0, -2000; 20/512, 20/512 },
    { file=STRE1_FILE, rnd=nil; 18,  10, -50; 6,   0, 0; 20/512, 20/512 },
    { file=STRE3_FILE, rnd=nil; 24,  10, -120; 6,   0, 0; 20/512, 20/512 },
    { file=STRE2_FILE, rnd=nil; 22,  10, -320; 6,   0, 0; 20/512, 20/512 },
    { file=STRE3_FILE, rnd=nil; 18,  10, -760; 6,   0, 0; 20/512, 20/512 },
    { file=STRE3_FILE, rnd=nil; 18,  10, -1200; 6,   0, 0; 20/512, 20/512 },
    { file=BSIG2_FILE, rnd=15;  16.1,2,  -9; 3,   0, -2000; 4/256,  4/256  },
}

-- define obstacles here:
--     track.obstacle_defs.col  : the image file to paint on the obstacle
--     track.obstacle_defs.hgt  : the greyscale heightmap that defines the
--                                shape of the obstacle
--     track.obstacle_defs[1-3] : x, y, z position translation values
--     track.obstacle_defs[4-6] : x, y, z rotation values
track.obstacle_defs = { 
    -- unit 1
    { hgt = OBS1H_FILE; -16.1, -0.1, -200, 0, 0, 0, true, false, true },

    -- unit 2
    { hgt = OBS2H_FILE; -16.1, -0.1, -300, 0, 0, 0,  false, false, true},

    -- unit3
    { hgt = OBS2H_FILE; -16.1, -0.1, -400, 0, 0, 0,  false, false, true},
    { hgt = OBS2H_FILE; -16.1, -0.1, -420, 0, 0, 0,  false, false, true},


    -- unit 4
    { hgt = OBS5H_FILE; -16.1, -0.1, -560, 0, 0, 0,  true, false, false},
    { hgt = OBS2H_FILE; -16.1, -0.1, -580, 0, 0, 0,  false, false, true},
    { hgt = OBS2H_FILE; -16.1, -0.1, -600, 0, 0, 0,  false, false, true},
    { hgt = OBS2H_FILE; -16.1, -0.1, -620, 0, 0, 0,  false, false, true},
    
    -- unit 5
    { hgt = OBS8H_FILE; -16.1, -0.1, -700, 0, 0, 0,  false, false, true},
    { hgt = OBS8H_FILE; -16.1, -0.1, -725, 0, 0, 0,  false, false, true},
--[[
    { hgt = OBS8H_FILE; -16.1, -0.1, -760, 0, 0, 0,  false, false, true},
    { hgt = OBS8H_FILE; -16.1, -0.1, -785, 0, 0, 0,  false, false, true},
--]]
    -- unit 6
    { hgt = OBS6H_FILE; -16.1, -0.1, -980, 0, 0, 0,  true, false, false},

    -- unit 8
    { hgt = OBS9H_FILE; -16.1, -0.1, -1300, 0, 0, 0,  true, false, false},
    { hgt = OBS10_FILE; -16.1, -0.1, -1332, 0, 0, 0,  true, true, false},
    { hgt = OBS10_FILE; -16.1, -0.1, -1364, 0, 0, 0,  true, true, false},
    { hgt = OBS11_FILE; -16.1, -0.1, -1396, 0, 0, 0,  true, true, false},
    
}

track.hazard_defs = {

-- unit 1
{ file=BLOCK_FILE; -4,  2, -180;  0,0,0; 2,2,2; 0,0,0; 4,4,4; 32, 100 },
{ file=BLOCK_FILE; 12,  2, -180;  0,0,0; 2,2,2; 0,0,0; 4,4,4; 32, 100 },

-- unit 5
{ file=BLOCK_FILE; 4,   2, -680;  0,0,0; 2,2,2; 0,0,0; 4,4,4; 32, 100 },
{ file=BLOCK_FILE; -12, 2, -680;  0,0,0; 2,2,2; 0,0,0; 4,4,4; 32, 100 },


-- unit 7
{ file=BLOCK_FILE; 4,   2, -1140; 0,0,0; 2,2,2; 0,0,0; 4,4,4; 32, 100 },
{ file=BLOCK_FILE; -12, 2, -1140; 0,0,0; 2,2,2; 0,0,0; 4,4,4; 32, 100 },
{ file=BLOCK_FILE; -4,  2, -1180; 0,0,0; 2,2,2; 0,0,0; 4,4,4; 32, 100 },
{ file=BLOCK_FILE; 12,  2, -1180; 0,0,0; 2,2,2; 0,0,0; 4,4,4; 32, 100 },
{ file=BLOCK_FILE; 4,   2, -1220; 0,0,0; 2,2,2; 0,0,0; 4,4,4; 32, 100 },
{ file=BLOCK_FILE; -12, 2, -1220; 0,0,0; 2,2,2; 0,0,0; 4,4,4; 32, 100 },
{ file=BLOCK_FILE; -4,  2, -1260; 0,0,0; 2,2,2; 0,0,0; 4,4,4; 32, 100 },
{ file=BLOCK_FILE; 12,  2, -1260; 0,0,0; 2,2,2; 0,0,0; 4,4,4; 32, 100 },

}

track.powerup_defs = {
    -- unit 3
    { 8,  0, -380, "COOL"},

    -- unit 4
    { -10,  0, -500, "BOOST"},

    -- unit 6
    { 10,  0, -920,  "BOOST"},
    { -4,  0, -1100, "COOL"},
}

track.surface_defs = {
    -- unit 6
    {0, 0, -1030, 32, 60, "MUD"}, 

    -- unit 8
    {6, 0, -1357, 20, 90, "ICE"}, 
}


track.waypoint_defs = {
	-- each decision line has 3 groups to choose from with 4 WPs to follow

    { -300,  {{9,0, -72}, {-3,0,-191},  {-9,0,-254}, {-10,0,-588}, -- ok(2)
    
              {9,0, -72}, {-9,0,-191},  {-9,0,-254}, { 10,0,-588}, -- best(4)
              
              {3,0, -72}, {-9,0,-191} ,  { 5,0,-254}, {-5, 0,-588}  -- poor(1)
			 },
    },

    { -900,  {{11,0, -70}, { 11,0,-388}, {9, 0,-970}, { 5,  0,-1082}, -- ok(2)

              {11,0, -70}, {-9, 0,-388}, {9, 0,-970}, {-10, 0,-1082}, -- best(4)
              
              {5, 0, -70}, {-9, 0,-388} , {7, 0,-970},  { -5, 0,-1082}  -- poor(1)
			 },
	},

    { -2000,  {{-8, 0, -46}, {-9,0,-383},  {-11,0,-470}, {-10,0,-785}, -- ok(2)
    
              {-8,  0, -46}, { 9,0,-383},  { 11,0,-470}, {-10,0,-785}, -- best(4)
              
              { 8,  0, -46}, { 9,0,-383} ,  { -5,0,-470}, {-2, 0,-785}  -- poor(1)
			 },
	}
}

function track:create( )

    -- create track objects and attatch to the parent ------------------------

    self.pivot      = E.create_pivot()
    self.oppangle   = E.create_pivot()
    self.foreground = E.create_pivot()
    self.midlground = E.create_pivot()
    self.background = E.create_pivot()

    self.physpivot  = E.create_pivot()
    self.floor      = E.create_pivot()

    self.rot        = 0
    self.oppasegs   = {}
    self.foresegs   = {}
    self.midlsegs   = {}
    self.backsegs   = {}

    E.parent_entity(self.oppangle,   self.pivot)
    E.parent_entity(self.foreground, self.pivot)
    E.parent_entity(self.midlground, self.pivot)
    E.parent_entity(self.background, self.pivot)

    E.parent_entity(self.physpivot,  self.midlground)

    -- create track physical walls -------------------------------------------
    
    self.fb     = E.create_pivot()            -- front track boundary
    self.bb     = E.create_pivot()            -- back track boundary
    
    E.set_entity_geom_type(self.fb, E.geom_type_box, 
			   20, 100, math.abs(self.finish) * 2 )
    E.set_entity_geom_type(self.bb, E.geom_type_box, 
			   20, 100, math.abs(self.finish) * 2 )
    
    -- parent boundary geoms to track physics pivot
    
    E.parent_entity(self.fb, self.physpivot)
    E.parent_entity(self.bb, self.physpivot)
    
    E.set_entity_position(self.fb,    26,  1, 0)
    E.set_entity_position(self.bb,    -26, 1, 0)
    
    E.set_entity_flags(self.fb, E.entity_flag_visible_geom, self.viewgeoms)
    E.set_entity_flags(self.bb, E.entity_flag_visible_geom, self.viewgeoms)

    
    E.set_entity_geom_attr(self.fb, E.geom_attr_category, category_rail)
    E.set_entity_geom_attr(self.bb, E.geom_attr_category, category_rail)
    
    E.set_entity_geom_attr(self.fb, E.geom_attr_soft_erp, 0.999) 
    E.set_entity_geom_attr(self.fb, E.geom_attr_soft_cfm, 0.0001)
    E.set_entity_geom_attr(self.bb, E.geom_attr_soft_erp, 0.999)
    E.set_entity_geom_attr(self.bb, E.geom_attr_soft_cfm, 0.0001)
    
    E.set_entity_geom_attr(self.fb, E.geom_attr_friction, 0)
    E.set_entity_geom_attr(self.bb, E.geom_attr_friction, 0)
    
    --------------------------------------------------------------------------

    local offset

    -- create powerups on the track ------------------------------------------

    self.powerups = {}
    for i, line in ipairs(self.powerup_defs) do
	self:add_powerup(line[1], line[2], line[3], line[4], 
			 self.physpivot)
	self:add_powerup(line[1], line[2], line[3] + self.lappoint, line[4], 
			 self.physpivot)
    end

    -- create hazards on the track -------------------------------------------

    self.hazards = {}
    for i, line in ipairs(self.hazard_defs) do
	self:add_hazard(line.file, line[1],  line[2],  line[3], 
			           line[4],  line[5],  line[6],
				   line[7],  line[8],  line[9],
				   line[10], line[11], line[12],
				   line[13], line[14], line[15],
				   line[16], line[17], self.physpivot)
	self:add_hazard(line.file, line[1],  line[2],  line[3] +self.lappoint, 
			           line[4],  line[5],  line[6],
				   line[7],  line[8],  line[9],
				   line[10], line[11], line[12],
				   line[13], line[14], line[15],
				   line[16], line[17], self.physpivot)
    end

    -- create ai waypoints on the track --------------------------------------


    self.waypoints1 = {}          -- for ai 1
    self.waypoints2 = {}          -- for ai 2
    self.waypoints3 = {}          -- for ai 3
    
    for i, line in ipairs(self.waypoint_defs) do
		self:add_waypoint(line, self.physpivot)
    end
	--[[
    table.sort( self.waypoints, 
	       function (a, b) 
		   local ax, ay, az = E.get_entity_position(a.pivot)
		   local bx, by, bz = E.get_entity_position(b.pivot)
		   return az > bz
	       end )
	--]]
    -- create obstacles on the track -----------------------------------------

    self.obstacles = {}

    for i, line in ipairs(self.obstacle_defs) do
	self:add_obstacle(OBSBG_FILE, line.hgt,
			  line[1], line[2], line[3], 
			  line[7], line[8], line[9], 
			  self.physpivot, self.midlground)
    end
    for i, line in ipairs(self.obstacle_defs) do
	self:add_obstacle(OBSBG_FILE, line.hgt,
			  line[1], line[2], line[3] + self.lappoint, 
			  line[7], line[8], line[9], 
			  self.physpivot, self.midlground)
    end

    -- create surfaces -------------------------------------------------------

    self.surfaces = {}
    for i, line in ipairs(self.surface_defs) do
	self:add_surface(line[1], line[2], line[3], 
			 line[4], line[5], line[6], 
			 self.physpivot, self.midlground)
    end
    for i, line in ipairs(self.surface_defs) do
	self:add_surface(line[1], line[2], line[3] + self.lappoint, 
			 line[4], line[5], line[6], 
			 self.physpivot, self.midlground)
    end

    -- create sprites --------------------------------------------------------

    self.billboards       = {}
    local randomized_bb_d = {}

    -- fill a temp table with randomly generated sprites
    for i, line in ipairs(self.billboard_defs) do
	if line.rnd then
	    for j = 1, line.rnd do
		
		local px = math.random() * line[4]
		local pz = math.random() * line[6]
		
		local nl = {}
		nl.file  = line.file
		
		nl[1], nl[2], nl[3] = line[1] + px, line[2], line[3] + pz
		nl[7], nl[8]        = line[7],      line[8]
		
		table.insert(randomized_bb_d, nl)
	    end
	else
	    table.insert(randomized_bb_d, line)
	end
    end

    -- sort so transparency is displayed correctly
    table.sort(randomized_bb_d, function (a, b) return a[1] > b[1] end)

    -- create the sprites
    for i, line in ipairs(randomized_bb_d) do
	local pos  = self.background
	local bb   = true
	local alph = 1

	if     line[1] > 16  then 
	    pos  = self.foreground 
	    bb   = false
	    alph = 0.4
	elseif line[1] > -16 then 
	    pos  = self.midlground
	    bb   = false 
	    alph = 0.4
	end

	self:add_billboard(line.file, 
			   line[1], line[2], line[3], 
			   line[7], line[8], 
			   alph, bb, pos)
	self:add_billboard(line.file, 
			   line[1], line[2], line[3] + self.lappoint, 
			   line[7], line[8], 
			   alph, bb, pos)
    end

    -- create objects --------------------------------------------------------

    self.objects          = {} 
    local randomized_ob_d = {}
    
    -- fill a temp table with randomly generated objects
    for i, line in ipairs(self.object_defs) do
	if line.rnd then
	    for j = 1, line.rnd do

		local px = math.random(self.rnd_min_x, self.rnd_max_x)
		local pz = math.random(self.rnd_min_z, self.rnd_max_z)

		local nl = {}
		nl.file  = line.file
		
		nl[1], nl[2], nl[3] = line[1] + px, line[2], line[3] + pz
		nl[4], nl[5], nl[6] = line[4],      line[5], line[6]
		nl[7], nl[8], nl[9] = line[7],      line[8], line[9]
		
		table.insert(randomized_ob_d, nl)
	    end
	else
	    table.insert(randomized_ob_d, line)
	end
    end

    -- sort so transparency is displayed correctly
    table.sort(randomized_ob_d, function (a, b) return a[1] > b[1] end)

    -- create the objects
    for i, line in ipairs(randomized_ob_d) do
	    self:add_object(line.file, 
			    line[1], line[2], line[3], 
			    line[4], line[5], line[6],
			    line[7], line[8], line[9],
			    self.background)
    end

    -- create the track segments ---------------------------------------------
    --    track segments are 32 wide and contain sections
    --    sections are 32 long
    --    there are [numsegs] segments, centered at the origin

    for i= 1 - self.numsegs / 2, self.numsegs / 2 do
--    for i = 0,1 do

	local oseg, fseg, mseg, bseg = {}, {}, {}, {}  -- segments

	if table.getn(self.foresegs) == 0 then
    
	    oseg.pivot = E.create_pivot()
	    fseg.pivot = E.create_pivot()             -- pivot for the segment
	    mseg.pivot = E.create_pivot()             -- pivot for the segment
	    bseg.pivot = E.create_pivot()             -- pivot for the segment

	    -- VVV Insert track sections here VVV
	    fseg[1]    = E.create_object(GRASS_FILE)  -- grassy area under cam
	    fseg[2]    = E.create_clone(fseg[1])      -- grassy area near cam
	    fseg[3]    = E.create_clone(fseg[1])      -- grassy area near cam
	    fseg[4]    = E.create_clone(fseg[1])      -- grassy area near cam
	    bseg[1]    = E.create_clone(fseg[1])      -- grassy area near cam
	    bseg[2]    = E.create_clone(fseg[1])      -- grassy area near cam

	    mseg.track  = E.create_object(TRACK_FILE) -- track
	    fseg.ffence = make_sprite(AWALL_FILE, true, true)
	    oseg.ifence = E.create_clone(fseg.ffence)
	    mseg.bfence = E.create_clone(fseg.ffence)
	    
	    --[[
	    mseg.shadow = E.get_mesh(mseg.track, 0)
	    mseg.img    = E.create_image("data/shadow.png")

	    E.set_brush_image(mseg.shadow, mseg.img, 1)
	    E.set_brush_vert_prog(mseg.shadow, "data/shadow.vp")
	    E.set_brush_frag_prog(mseg.shadow, "data/shadow.fp")
	    --]]
	else
	    for k, v in pairs(self.oppasegs[1]) do
		oseg[k] = E.create_clone(v)
	    end
	    for k, v in pairs(self.foresegs[1]) do
		fseg[k] = E.create_clone(v)
	    end
	    for k, v in pairs(self.midlsegs[1]) do
		mseg[k] = E.create_clone(v)
	    end
	    for k, v in pairs(self.backsegs[1]) do
		bseg[k] = E.create_clone(v)
	    end
	end

	-- position fence and make correct size

	E.set_sprite_range(oseg.ifence, 0, 5, 0, 1)
	E.set_sprite_range(fseg.ffence, 0, 5, 0, 1)
	E.set_sprite_range(mseg.bfence, 0, 5, 0, 1)

	local fx, fy, fz, fxx, fyy, fzz = E.get_entity_bound(fseg.ffence)
	local fw, fh = fxx - fx, fyy - fy

	E.set_entity_scale   (oseg.ifence, self.segwidth / fw, 4/fh, 1)
	E.set_entity_position(oseg.ifence, 16,                 2,    0)
	E.set_entity_rotation(oseg.ifence, 0,                  270,  0)

	E.set_entity_scale   (fseg.ffence, self.segwidth / fw, 4/fh, 1)
	E.set_entity_position(fseg.ffence, 16,                 2,    0)
	E.set_entity_rotation(fseg.ffence, 0,                  90,   0)
	E.set_entity_alpha   (fseg.ffence, 0.25)

	E.set_entity_scale   (mseg.bfence, self.segwidth / fw, 4/fh, 1)
	E.set_entity_position(mseg.bfence, -16,                2,    0)
	E.set_entity_rotation(mseg.bfence, 0,                  90,   0)

	-- position sections within pivot's coordinate system
	
	for i, line in ipairs(fseg) do
	    E.set_entity_position(line, 
				  (table.getn(fseg)-i+1) * self.segseclen, 
				  0, 0)
	end

	for i, line in ipairs(bseg) do
	    E.set_entity_position(line, 
				  -i * self.segseclen, 
				  0, 0)
	end

	-- parent segment elements

	E.parent_entity(oseg.ifence, oseg.pivot)

	for i, line in ipairs(fseg) do E.parent_entity(line, fseg.pivot) end
	for i, line in ipairs(bseg) do E.parent_entity(line, bseg.pivot) end
	
	E.parent_entity(fseg.ffence, fseg.pivot)
	E.parent_entity(mseg.bfence, mseg.pivot)
	E.parent_entity(mseg.track,  mseg.pivot)
	E.parent_entity(mseg.posts,  mseg.pivot)


	-- parent the segment to the track

	E.parent_entity(oseg.pivot, self.oppangle)
	E.parent_entity(fseg.pivot, self.foreground)
	E.parent_entity(mseg.pivot, self.midlground)
	E.parent_entity(bseg.pivot, self.background)

	-- position pivots and track boundaries

	E.set_entity_position(oseg.pivot, 0,   0, -i * self.segwidth)
	E.set_entity_position(fseg.pivot, 0,   0, -i * self.segwidth)
	E.set_entity_position(mseg.pivot, 0,   0, -i * self.segwidth)
	E.set_entity_position(bseg.pivot, 0,   0, -i * self.segwidth)

	-- set physical properties of track boundaries 

	table.insert(self.oppasegs, oseg)
	table.insert(self.foresegs, fseg)
	table.insert(self.midlsegs, mseg)
	table.insert(self.backsegs, bseg)
	
    end

    -- create floor of physical system ---------------------------------------

    E.set_entity_geom_type(self.floor, E.geom_type_plane, 0, 1, 0, 0)
    E.set_entity_geom_attr(self.floor, E.geom_attr_category, category_grnd)
    E.set_entity_geom_attr(self.floor, E.geom_attr_bounce,   0.01)

    E.parent_entity(self.floor, self.physpivot)

end


function track:destroy()
    E.delete_entity(self.pivot)
    self.foresegs = nil
    self.midlsegs = nil
    self.backsegs = nil

    self:del_obstacles()
    self:del_objects()
    self:del_billboards()
end

function track:reset()

--[[
    track.rot = 0

    local pos = 1 - self.numsegs / 2
    for i=1, table.getn(self.foresegs) do

	E.set_entity_position(self.oppasegs[i].pivot, 
			      0,   0, -pos * self.segwidth)
	E.set_entity_position(self.foresegs[i].pivot, 
			      0,   0, -pos * self.segwidth)
	E.set_entity_position(self.midlsegs[i].pivot,
			      0,   0, -pos * self.segwidth)
	E.set_entity_position(self.backsegs[i].pivot, 
			      0,   0, -pos * self.segwidth)

	E.set_entity_position(self.midlsegs[i].fb,
			      26,   1, -pos * self.segwidth)
	E.set_entity_position(self.midlsegs[i].bb,
			      -26,  1, -pos * self.segwidth)
 
	pos = pos + 1
    end
    --]]
    self:enable_hazards(false)

    for i=1, table.getn(self.hazard_defs) do

	local hazd = self.hazard_defs[i]
	local haz1 = self.hazards[(i-1)*2+1]
	local haz2 = self.hazards[(i-1)*2+2]

	E.set_entity_position(haz1.geom, hazd[1], hazd[2], hazd[3])
	E.set_entity_rotation(haz1.geom, hazd[4], hazd[5], hazd[6])
	E.set_entity_position(haz2.geom, hazd[1], hazd[2], 
			      hazd[3] + self.lappoint)
	E.set_entity_rotation(haz2.geom, hazd[4], hazd[5], hazd[6])

    end

end

function track:set_shadow_ofs(px, py, pz, dt)
    for i, v in ipairs(self.midlsegs) do
	local vx, vy, vz = E.get_entity_position(v.pivot)
	local vu, pu     = math.ceil(vz/32), math.ceil(pz/32)
	local dx, dz

	if vu == pu 
	then dx, dz = px - vx, pz - vz
	    E.set_brush_vert_param(v.shadow, 0, dx, 0, dz)
	else dx, dz = 0,       0
	end
	--[[
	E.print_console(string.format(
               "%8.2f: vu %3d, pu %3d, dx %3d, dz %3d, brush: %d\n",
               dt, vu, pu, dx, dz, 0))
	--]]
    end
end

function track:rotate()
    local lastentity = self.foresegs[self.numsegs].pivot
    local ox, oy, oz = E.get_entity_position(lastentity)
    local oseg = self.oppasegs[1]
    local fseg = self.foresegs[1]
    local mseg = self.midlsegs[1]
    local bseg = self.backsegs[1]

    E.set_entity_position(oseg.pivot, 0,   0, oz - self.segwidth) 
    E.set_entity_position(fseg.pivot, 0,   0, oz - self.segwidth) 
    E.set_entity_position(mseg.pivot, 0,   0, oz - self.segwidth) 
    E.set_entity_position(bseg.pivot, 0,   0, oz - self.segwidth) 

    table.insert(self.oppasegs, oseg)
    table.insert(self.foresegs, fseg)
    table.insert(self.midlsegs, mseg)
    table.insert(self.backsegs, bseg)

    table.remove(self.oppasegs, 1)
    table.remove(self.foresegs, 1)
    table.remove(self.midlsegs, 1)
    table.remove(self.backsegs, 1)

    self.rot = self.rot + 1
end

function track:rotate_rev()
    local firstentity = self.foresegs[1].pivot
    local ox, oy, oz = E.get_entity_position(firstentity)
    local oseg = self.oppasegs[self.numsegs]
    local fseg = self.foresegs[self.numsegs]
    local mseg = self.midlsegs[self.numsegs]
    local bseg = self.backsegs[self.numsegs]

    E.set_entity_position(oseg.pivot, 0,   0, oz + self.segwidth) 
    E.set_entity_position(fseg.pivot, 0,   0, oz + self.segwidth) 
    E.set_entity_position(mseg.pivot, 0,   0, oz + self.segwidth) 
    E.set_entity_position(bseg.pivot, 0,   0, oz + self.segwidth) 

    table.insert(self.oppasegs, 1, oseg)
    table.insert(self.foresegs, 1, fseg)
    table.insert(self.midlsegs, 1, mseg)
    table.insert(self.backsegs, 1, bseg)

    table.remove(self.oppasegs)
    table.remove(self.foresegs)
    table.remove(self.midlsegs)
    table.remove(self.backsegs)

    self.rot = self.rot - 1
end


function track:in_bounds( x, y, z )
    if math.abs(x) > 16 then
	return false
    else
	return true
    end
end


-- called for each decision marker
-- randomly choose a group for a decision marker
-- store in a table and draw the 4 waypoints
function track:add_waypoint( def, parent, numAI)
    -- draws all 3 waypoints for each decision line
    -- def is the decision line's 3 groups

	-- way is the table that includes decision line
	-- and stores the chosen group for the decision line
	-- k disignates number of tracks that will be used by that num of AIs
	for k = 1, 3 do

        local way = {}

		way.dec     = def[1]
		way.offsets = {}  -- will contain a group of WPs that is rand chosen below

		local wp_group = math.random(0, 2)
		-- correct for poor randomness
		local i=0
		--while(i <= 3) do
		--	wp_group = math.random(0, 2)
		--	i=i+1
		--end

		--E.print_console("k = " ..k.. " RANDOM GROUP: " ..wp_group.. "\n")

		-- i is the wp counter in a randomly chosen group
		for i = 1, 4 do
		    -- px, py, pz are coordinates for one wp
		    local px = def[2][wp_group * 3 + i][1]
		    local py = def[2][wp_group * 3 + i][2]
		    local pz = def[2][wp_group * 3 + i][3]

	    	way.offsets[i] = E.create_pivot()

			-- draw the waypoints of the randomly chosen
			-- group on the track
		    E.parent_entity       ( way.offsets[i], parent )
		    E.set_entity_position ( way.offsets[i], px, py, pz + way.dec )

		    E.set_entity_flags    ( way.offsets[i], E.entity_flag_visible_geom,
					    self.viewwaypt )

		    E.set_entity_body_type( way.offsets[i], false )

		    E.set_entity_geom_type( way.offsets[i], E.geom_type_sphere,   self.wayp_size )
		    E.set_entity_geom_attr( way.offsets[i], E.geom_attr_category, category_aitag )
		    E.set_entity_geom_attr( way.offsets[i], E.geom_attr_collider, category_bike  )
		    E.set_entity_geom_attr( way.offsets[i], E.geom_attr_response, category_none  )
		    E.set_entity_geom_attr( way.offsets[i], E.geom_attr_callback, category_bike  )

		end

	    if (k == 1) then
    		table.insert(self.waypoints1, way)
		elseif (k == 2) then
    		table.insert(self.waypoints2, way)
		elseif (k == 3) then
    		table.insert(self.waypoints3, way)
		end

	end

end


function track:add_obstacle( colmap, heightmap, 
			     px, py, pz, 
			     wood, seam, spanx,
			     gparent, mparent )
    
    local obs = {}
    
    obs.pivot = E.create_pivot()
    obs.geoms = {}

    local xvertmax  = 8
    local zvertmax  = 8
    local xvertstp  = self.segseclen / xvertmax
    local zvertstp  = self.segwidth  / zvertmax
    local obsheight = 8

    if not self.obstacles[heightmap] then

	self.obstacles[heightmap] = { }

	obs.mesh1    = E.create_object()
	obs.mesh2    = E.create_object()

	local cimg1  = E.create_image(colmap)
	local cimg2  = E.create_image("data/structure.png")
	local cimg3  = E.create_image("data/structure.jpg")
	local himg   = E.create_image(heightmap)
	local brush1 = E.create_brush()
	local brush2 = E.create_brush()
	local brush3 = E.create_brush()

	E.set_brush_image(brush1, cimg1)
	E.set_brush_image(brush2, cimg2)
	E.set_brush_image(brush3, cimg3)

	local wi, he = E.get_image_size(himg)
	
	local m1 = E.create_mesh(obs.mesh1, brush1)
	local m2 = E.create_mesh(obs.mesh2, brush2)
	local m3 = E.create_mesh(obs.mesh1, brush3)
	local m4 = E.create_mesh(obs.mesh2, brush1)

	local v  = 0

	for z = 0, -zvertmax, -1 do 
	    for x = 0, xvertmax, 1 do
		
		local y0, y1 = 0, 0

		local i = math.floor(x*(wi/xvertmax))
		if i > wi-1 then i = wi-1 end

		local j
		if z < 0 then
		    j  = math.floor(-(z + 0.5) * (he / zvertmax))
		    y0 = E.get_image_pixel(himg, i, j)
		end
		
		j = math.floor(-(z - 0.5) * (he / zvertmax))
		if j > wi-1 then j = wi-1 end
		if x < xvertmax then
		    y1 = E.get_image_pixel(himg, i, j)
		end
		
		local y
		if seam and (z == 0) then 
		    y = math.max(y0, y1)
		else 
		    y = math.min(y0, y1)
		end

		local ztcoord = - z / zvertmax

		if ztcoord == 1 then ztcoord = 0.99 end
		if ztcoord == 0 then ztcoord = 0.01 end
		
		E.create_vert(obs.mesh1, 
			      x*xvertstp, y*obsheight, z*zvertstp, 
			      0, 1, 0, 
			      ztcoord, y)

		
		if x < xvertmax then
		    
		    local xtcoord = x / xvertmax
		    E.create_vert(obs.mesh1, 
				  x*xvertstp, y*obsheight, z*zvertstp, 
				  0, 1, 0, 
				  xtcoord, ztcoord)

		    xtcoord = (x+1) / xvertmax
		    E.create_vert(obs.mesh1, 
				  (x+1)*xvertstp, y*obsheight, z*zvertstp, 
				  0, 1, 0, 
				  xtcoord, ztcoord)

		    E.create_vert(obs.mesh2, 
				  (x+1)*xvertstp, y*obsheight, z*zvertstp, 
				  0, 1, 0, 
				  ztcoord, .99)

		    E.create_vert(obs.mesh2, 
				  (x+1)*xvertstp, 0, z*zvertstp, 
				  0, 1, 0, 
				  ztcoord, 1-y)

		    E.create_vert(obs.mesh1, 
				  (x+1) * xvertstp - 0.1, 
				  y * obsheight-0.1, 
				  z * zvertstp, 
				  0, 1, 0, 
				  ztcoord, y)

		end
	    end 
	end

	for z = 0, zvertmax - 1 do 
	    for x = 0, xvertmax - 1 do
		local l, u = {}, {}
		for i=0, 3 do
		    l[i] = z * (xvertmax*4 + 1) + x*4 + i + 1
		    u[i] = (z + 1) * (xvertmax*4 + 1) + x*4 + i + 1
		end
		
		E.create_face(obs.mesh1, m1, l[0], l[1], u[0])
		E.create_face(obs.mesh1, m1, l[1], u[1], u[0])

		local x1, y1 = E.get_vert(obs.mesh1, l[2])
		local x2, y2 = E.get_vert(obs.mesh1, l[3])
		local x3, y3 = E.get_vert(obs.mesh1, u[2])
		local x4, y4 = E.get_vert(obs.mesh1, u[3])
		if not ((y1 == y2) and (y3 == y4)) then

		    local pl = z * (zvertmax * 2) + x * 2
		    local pr = z * (zvertmax * 2) + x * 2 + 1
		    local ql = (z+1) * (zvertmax * 2) + x * 2
		    local qr = (z+1) * (zvertmax * 2) + x * 2 + 1
		    
		    if wood then
			E.create_face(obs.mesh2, m2, pl, pr, ql)
			E.create_face(obs.mesh2, m2, pr, qr, ql)

			E.create_face(obs.mesh1, m3, l[2], l[3], u[2])
			E.create_face(obs.mesh1, m3, l[3], u[3], u[2])
		    else
			E.create_face(obs.mesh2, m4, pl, pr, ql)
			E.create_face(obs.mesh2, m4, pr, qr, ql)
		    end
		end
	    end
	end
	
    else
	obs.mesh1 = E.create_clone(self.obstacles[heightmap][1].mesh1)
	obs.mesh2 = E.create_clone(self.obstacles[heightmap][1].mesh2)
    end

    E.set_entity_flags(obs.mesh1, E.entity_flag_wireframe, false)
    E.set_entity_flags(obs.mesh2, E.entity_flag_wireframe, false)
    local dins, ins = 0.0, 0
    
    if self.makeobs then
	
    local geomw, xmax
    if spanx then 
	geomw = self.segseclen 
	xmax  = 0
    else 
	geomw = xvertstp + 0.1
	xmax  = xvertmax - 1
    end
    
    for z = 0, zvertmax - 1 do 
	for x = 0, xmax do
	    
	    local ll = z * (xvertmax*4 + 1) + x*4 + 1
	    local lr = z * (xvertmax*4 + 1) + x*4 + 2
	    local ul = (z + 1) * (xvertmax*4 + 1) + x*4 + 1

	    local ox, oy, oz = E.get_vert(obs.mesh1, ll)
	    local xx, xy, xz = E.get_vert(obs.mesh1, lr)
	    local zx, zy, zz = E.get_vert(obs.mesh1, ul)

	    --local my = (oy + xy)/2
	    local my = oy
	    
	    local dz = math.sqrt((zz-oz)*(zz-oz) + (zy-oy)*(zy-oy))
	    local tx = math.deg(math.asin((zy-oy)/dz))

	    local geom =  E.create_pivot()
	    local geomp = E.create_pivot()

	    E.set_entity_geom_type(geom, E.geom_type_box, 
				   geomw, obsheight, dz)

	    E.set_entity_geom_attr(geom, E.geom_attr_category, category_obst)

	    E.set_entity_geom_attr(geom, E.geom_attr_bounce,   0.01)
	    E.set_entity_geom_attr(geom, E.geom_attr_soft_erp, 0.999)
	    E.set_entity_geom_attr(geom, E.geom_attr_soft_cfm, 0.00001)
	    
	    local zz = (dz / 2) * math.cos(math.rad(tx))
	    local zy = (dz / 2) * math.sin(math.rad(tx))
	    local yz = (obsheight / 2) * math.sin(math.rad(tx))
	    local yy = (obsheight / 2) * math.cos(math.rad(tx))

	    E.set_entity_position(geom, 
				  ox + px + geomw / 2, 
				  my + py - yy + zy - ins, 
				  oz + pz - zz - yz )

	    E.set_entity_rotation(geom, tx, 0, 0)

	    E.parent_entity(geom, gparent)

	    E.set_entity_flags(geom, E.entity_flag_visible_geom, self.viewobs)
	    
	    obs.geoms.p = {}
	    obs.geoms.b = {}
	    obs.geoms.p[z*xvertmax + x] = geomp
	    obs.geoms.b[z*xvertmax + x] = geom
	    
	end
	ins = ins + dins
    end
    end

    E.parent_entity(obs.mesh2, mparent)
    E.parent_entity(obs.mesh1, mparent)
    E.set_entity_position(obs.mesh1, px, py, pz)
    E.set_entity_position(obs.mesh2, px, py, pz)

    table.insert(self.obstacles[heightmap], obs)
end


function track:add_billboard( file, px, py, pz, sx, sy, alpha, isbb, parent )

    local bb = nil

    -- if this is the first occurance of this image, then create
    -- a new sprite, otherwise just clone the first one

    if not self.billboards[file] then
	self.billboards[file] = { }
	bb = make_sprite(file, true, true )
    else
	bb = E.create_clone( self.billboards[file][1] )
    end

    E.parent_entity(bb, parent)
    E.set_entity_flags(bb, E.entity_flag_billboard, true)
    E.set_sprite_range(bb, 0.1, 0.99, 0.01, 0.99)

--    E.set_entity_alpha(bb, alpha)
    
    if px and py and pz then E.set_entity_position(bb, px, py, pz) end
    if sx and sy        then E.set_entity_scale   (bb, sx, sy, 1 ) end
    
    table.insert(self.billboards[file], bb)

end


function track:del_billboards(  )
    for k, v in pairs(self.billboards) do
	for i in ipairs(v) do
	    E.delete_entity(v[i])
	    v[i] = nil
	end
	self.billboards[k] = nil
    end
end

function track:add_surface( px, py, pz, width, length, type, gparent, sparent )
    local surf = {}
    surf.type  = type
    surf.geom  = E.create_pivot()

    E.set_entity_geom_type(surf.geom, E.geom_type_box, width, 100, length)
    E.set_entity_geom_attr(surf.geom, E.geom_attr_category, category_srfc)
    E.set_entity_geom_attr(surf.geom, E.geom_attr_collider, category_bike)
    E.set_entity_geom_attr(surf.geom, E.geom_attr_response, category_none)
    E.set_entity_geom_attr(surf.geom, E.geom_attr_callback, category_bike)

    E.set_entity_position(surf.geom, px, py, pz)

    E.set_entity_flags(surf.geom, E.entity_flag_visible_geom, self.viewgeoms)

    E.parent_entity(surf.geom, gparent)

    local brush = E.create_brush()

    if type == "ICE" then

	local img1 = E.create_image("data/ice_slick.png")
	local img2 = E.create_image("data/sky_nx.png",
				    "data/sky_px.png",
				    "data/sky_ny.png",
				    "data/sky_py.png",
				    "data/sky_nz.png",
				    "data/sky_pz.png")
	
	E.set_brush_image(brush, img1, 0)
	E.set_brush_image(brush, img2, 1)
	
	E.set_brush_flags(brush, E.brush_flag_env_map_1, true)
	E.set_brush_flags(brush, E.brush_flag_transparent, true)
	E.set_brush_flags(brush, E.brush_flag_unlit, true)

    elseif type == "MUD" then

	local img   = E.create_image("data/mud_slick.png")

	E.set_brush_image(brush, img)
	E.set_brush_flags(brush, E.brush_flag_transparent, true)
	E.set_brush_flags(brush, E.brush_flag_unlit, true)

    end

    surf.sprite = E.create_sprite(brush)

    E.set_entity_scale(surf.sprite, width/256, length/1024, 1)
    E.set_entity_rotation(surf.sprite, -90, 0, 0)
    E.set_entity_position(surf.sprite, px, surface_layer, pz)
    E.parent_entity(surf.sprite, sparent)

    table.insert(self.surfaces, surf)
end

function track:get_nearest_surf_type( x, y, z )
    local dist = math.abs(track.finish)
    local type
    for i, v in ipairs(self.surfaces) do
	local px, py, pz = E.get_entity_position(v.geom)
	local delt = pos_distance(x, y, z, px, py, pz)
	--[[
	E.print_console(string.format("compare: delt %d, dist %d, type %s\n", 
				      delt, dist, v.type))
	--]]
	if delt < dist then
	    type = v.type
	    dist = delt
	end
    end
    return type
end

function track:add_object( file, px, py, pz, rx, ry, rz, sx, sy, sz, parent )

    local obj = nil

    -- if this is the first occurance of this .obj file, then create
    -- a new object, otherwise just clone the first one

    if not self.objects[file] then
	self.objects[file] = { }
	obj = E.create_object(file)
    else
	obj = E.create_clone( self.objects[file][1] )
    end

    E.parent_entity(obj, parent)
    
    if px and py and pz then E.set_entity_position(obj, px, py, pz) end
    if rx and ry and rz then E.set_entity_rotation(obj, rx, ry, rz) end
    if sx and sy and sz then E.set_entity_scale   (obj, sx, sy, sz) end
    
    table.insert(self.objects[file], obj)

end


function track:del_objects( )
    for k, v in pairs(self.objects) do
	for i in ipairs(v) do
	    E.delete_entity(v[i])
	    v[i] = nil
	end
	self.objects[k] = nil
    end
end

function track:add_powerup( x, y, z, type, parent )

    local pu = {}
    
    pu.type  = type
    pu.pivot = E.create_pivot()

    E.set_entity_geom_type(pu.pivot, E.geom_type_sphere, 4)
    E.set_entity_geom_attr(pu.pivot, E.geom_attr_category, category_pwrup)
    E.set_entity_geom_attr(pu.pivot, E.geom_attr_collider, category_bike)
    E.set_entity_geom_attr(pu.pivot, E.geom_attr_response, category_none)
    E.set_entity_geom_attr(pu.pivot, E.geom_attr_callback, category_bike)
    
    if type == "BOOST" then 
	
	pu.base = E.create_pivot()
	pu.sub  = E.create_object("data/cane.obj")

	E.set_entity_position( pu.sub, -2, 0, 0)
	local brush = E.get_mesh(pu.sub, 0)
	E.set_brush_flags(brush, E.brush_flag_unlit, true)
	E.parent_entity(pu.sub, pu.base)

	E.set_entity_position( pu.base, 0, 4, 0 )
	E.set_entity_rotation( pu.base, 0, 0, -30 )
	E.set_entity_scale (pu.base, .7, .7, .7)
	E.parent_entity(pu.base, pu.pivot)
	
	--[[
	pu.base  = make_sprite( "data/pwrup-base.png", true, true)
	pu.halo1 = make_sprite( "data/pwrup-halo.png", true, true)
	pu.halo2 = make_sprite( "data/pwrup-halo.png", true, true)

	E.set_entity_position( pu.base,  0,     powerup_layer,  0 )
	E.set_entity_rotation( pu.base,  -90,   0,     0 )
	E.set_entity_scale   ( pu.base,  8/128, 8/128, 1 )
	E.set_entity_position( pu.halo1, 0,     1,     0 )
	E.set_entity_rotation( pu.halo1, -90,   0,     0 )
	E.set_entity_scale   ( pu.halo1, 8/128, 8/128, 1 )
	E.set_entity_position( pu.halo2, 0,     1.2,   0 )
	E.set_entity_rotation( pu.halo2, -90,   0,     0 )
	E.set_entity_scale   ( pu.halo2, 8/128, 8/128, 1 )

	E.parent_entity(pu.halo2, pu.pivot)
	E.parent_entity(pu.halo1, pu.pivot)
	E.parent_entity(pu.base,  pu.pivot)
	--]]
    elseif type == "COOL" then
	pu.base = E.create_object("data/wreath_color.obj")
	E.set_entity_position( pu.base, 0, 2, 0 )
	E.set_entity_scale(pu.base, 1.4, 1.4, 1.4)
	local brush = E.get_mesh(pu.base, 0)
	E.set_brush_flags(brush, E.brush_flag_unlit, true)
	E.parent_entity(pu.base, pu.pivot)
    end

    E.parent_entity(pu.pivot, parent)
    E.set_entity_alpha(pu.pivot, .75)
    E.set_entity_position(pu.pivot, x, y, z )
    --E.set_entity_rotation(pu.pivot, 0, 90, 0)

    table.insert(self.powerups, pu)
end

function track:rotate_pwrups( dt )
    
    local dr = dt * 135

    for i, v in ipairs(self.powerups) do
	if v.type == "COOL" then
	    E.turn_entity(v.base, 0, 0, dr)
	else
	    E.turn_entity(v.base, 0, dr, 0)
	end
    end
end

function track:get_nearest_pwrup_type( x, y, z )
    local dist = math.abs(track.finish)
    local type
    for i, v in ipairs(self.powerups) do
	local px, py, pz = E.get_entity_position(v.pivot)
	local delt = pos_distance(x, y, z, px, py, pz)
	--E.print_console(string.format("compare: delt %d, dist %d\n", 
	--			      delt, dist))
	if delt < dist then
	    type = v.type
	    dist = delt
	end
    end
    return type
end

function track:enable_hazards( value )

    if not value then
	table.foreachi(self.hazards, 
		       function(i, v) 
			   E.set_entity_body_type(v.geom, false)
		       end
		   )
    else

	for i=1, table.getn(self.hazard_defs) do
	    
	    local hazd = self.hazard_defs[i]
	    local haz1 = self.hazards[(i-1)*2+1]
	    local haz2 = self.hazards[(i-1)*2+2]
	    
	    E.set_entity_body_type(haz1.geom, true)
	    E.set_entity_geom_type(haz1.geom, E.geom_type_box, 
				   hazd[13], hazd[14], hazd[15])
	    E.set_entity_geom_attr(haz1.geom, E.geom_attr_category, 
				   category_haz)
	    E.set_entity_geom_attr(haz1.geom, E.geom_attr_collider, 
				   category_all)
	    E.set_entity_geom_attr(haz1.geom, E.geom_attr_response, 
				   category_all)
	    E.set_entity_geom_attr(haz1.geom, E.geom_attr_callback, 
				   category_none)
	    E.set_entity_geom_attr(haz1.geom, E.geom_attr_mass,     hazd[16])
	    E.set_entity_geom_attr(haz1.geom, E.geom_attr_friction, hazd[17])
	    E.set_entity_geom_attr(haz1.geom, E.geom_attr_bounce,   0.01)
	    E.set_entity_geom_attr(haz1.geom, E.geom_attr_soft_erp, 0.999)
	    E.set_entity_geom_attr(haz1.geom, E.geom_attr_soft_cfm, 0.001)

	    E.set_entity_body_type(haz2.geom, true)
	    E.set_entity_geom_type(haz2.geom, E.geom_type_box, 
				   hazd[13], hazd[14], hazd[15])
	    E.set_entity_geom_attr(haz2.geom, E.geom_attr_category, 
				   category_haz)
	    E.set_entity_geom_attr(haz2.geom, E.geom_attr_collider, 
				   category_all)
	    E.set_entity_geom_attr(haz2.geom, E.geom_attr_response, 
				   category_all)
	    E.set_entity_geom_attr(haz2.geom, E.geom_attr_callback, 
				   category_none)
	    E.set_entity_geom_attr(haz2.geom, E.geom_attr_mass,     hazd[16])
	    E.set_entity_geom_attr(haz2.geom, E.geom_attr_friction, hazd[17])
	    E.set_entity_geom_attr(haz2.geom, E.geom_attr_bounce,   0.01)
	    E.set_entity_geom_attr(haz2.geom, E.geom_attr_soft_erp, 0.999)
	    E.set_entity_geom_attr(haz2.geom, E.geom_attr_soft_cfm, 0.001)
	end

    end


end

function track:add_hazard( file, px, py, pz, 
			         rx, ry, rz, 
			         sx, sy, sz, 
			         ox, oy, oz,
			         gw, gh, gd, 
			         mass, fric, parent )
    local haz = {}
    
    haz.obj  = E.create_object(file)
    haz.geom = E.create_pivot()

    E.parent_entity(haz.geom, parent)
    E.parent_entity(haz.obj,  haz.geom)

    E.set_entity_position( haz.geom, px, py, pz )
    E.set_entity_rotation( haz.geom, rx, ry, rz )
    E.set_entity_position( haz.obj,  ox, oy, oz )
    E.set_entity_scale   ( haz.obj,  sx, sy, sz )

    E.set_entity_flags( haz.geom, E.entity_flag_visible_geom, self.viewgeoms)

    table.insert(self.hazards, haz)
end