SCENE_LUA = true

-- dependencies
if not FSM_LUA    then dofile("fsm.lua")    end
if not MOBILE_LUA then dofile("mobile.lua") end

STATE_SCENE_SIDE   = "SIDE"
STATE_SCENE_HIGH   = "HIGH"
STATE_SCENE_BOOST  = "BOOST"
STATE_SCENE_LOCK   = "LOCKED"
STATE_SCENE_MENU   = "MENU"

scene = FSM:instantiate{state = STATE_NONE, tostr = "SCENE_FSM"}

-- globals
--scene.side_chase_ofs  = { 90, 15, 0,  0, 0, -15 }
scene.side_chase_ofs  = { 75, 25, 0,  0, 0, -10 }

--scene.side_chase_ofs = {0, 25, 0, 0, 0, 0}
--scene.side_chase_ofs  = { 30, 8, 0,  5, 0, -6 }

--scene.side_chase_ofs  = { 90, 15, 0,  0, 0, -6 }
--scene.side_chase_ofs  = { 90, 25, 90,  0, 0, -30 }
--scene.side_chase_ofs  = { 150, 40, 0,  0, 0, -15 }
--scene.side_chase_ofs  = { 0, 5, 10,  0, 0, -50 }
--scene.side_chase_ofs  = { 25, 10, 0,  5, 0, -6 }
scene.high_chase_ofs  = { 25, 20, 0,  0, 0, 0  }
--scene.boost_chase_ofs = { 18, 6,  3,  0, 0, -4  }
scene.boost_chase_ofs = { 20, 10,  30,  18, 0, -15  }
scene.lock_chase_ofs  = { 0,  0,  0,  0, 0, 0  }
--scene.menu_chase_ofs  = { 100,  50,  0,  0, 0, 0  }
scene.menu_chase_ofs  = { 100,  15,  0,  0, 0, 0  }

scene.camera_smooth_factor = 10

function scene:create()
    -- camera position
    self.camera_pos_x = 90
    self.camera_pos_y = 10
    self.camera_pos_z = 0
    self.camera_ofs_x = 0
    self.camera_ofs_y = 0
    self.camera_ofs_z = 0
    self.camera_tar_x = 0
    self.camera_tar_y = 0
    self.camera_tar_z = 0

    self.camera_shake = true
    self.snow_x_step  = 0
    self.snow_y_step  = 0
    self.snow_z_step  = 0
    self.snow_sz      = 256
    
    -- create camera, light and pivots for world elements

    self.camera = E.create_camera(E.camera_type_perspective)
    self.light  = E.create_light(E.light_type_positional)
    self.stage  = E.create_pivot()
    self.pivot  = E.create_pivot()
    self.mic    = E.create_pivot()

    self.snow   = E.create_brush()
    E.set_brush_vert_prog(self.snow, "data/snow.vp")
    E.set_brush_frag_prog(self.snow, "data/snow.fp")

    self.field  = E.create_galaxy("data/snow.gal", self.snow)
    E.set_galaxy_magnitude(self.field, 25)
    E.set_brush_vert_param(self.snow, 1, self.snow_sz, 
			                 self.snow_sz, 
			                 self.snow_sz, 1)

    E.parent_entity(self.light, self.camera)
    E.parent_entity(self.field, self.light)
    E.parent_entity(self.stage, self.light)
    E.parent_entity(self.pivot, self.stage)

    -- place cam
    E.set_entity_position(self.camera,
			  self.camera_pos_x,
			  self.camera_pos_y,
			  self.camera_pos_z)
    E.set_entity_rotation(self.camera, 0, 90, 0)
    E.turn_entity(self.camera, -30, 0, 0)

    -- place light
    E.set_entity_position(self.light, 0.0,   8.0,   8.0 )
    E.set_entity_rotation(self.stage, -15,   0,     0   )
    E.set_entity_rotation(self.mic,   0,     90,    0   )

    -- set the target that the camera will focus on
    self.chase = self.stage

    self.chase_ofs_x = 0
    self.chase_ofs_y = 0
    self.chase_ofs_z = 0
    self.look_ofs_x  = 0
    self.look_ofs_y  = 0
    self.look_ofs_z  = 0

    -- create sky
    self.sky    = E.create_object("data/sky.obj")
    self.skymap = E.create_image("data/mnt_nx.jpg",
				 "data/mnt_px.jpg",
				 "data/mnt_ny.jpg",
				 "data/mnt_py.jpg",
				 "data/mnt_nz.jpg",
				 "data/mnt_pz.jpg")

    E.set_entity_scale(self.sky, 1000, 1000, 1000)
    E.set_entity_rotation(self.sky, 0, 90, 0)
    E.turn_entity(self.sky, -10, 0, -10)
    self.skybrs = E.get_mesh(self.sky, 0)
    E.set_brush_image(self.skybrs, self.skymap)
    E.set_brush_flags(self.skybrs, E.brush_flag_sky_map_0, true)
    E.set_brush_flags(self.skybrs, E.brush_flag_unlit, true)
    E.parent_entity(self.sky,   self.light)

end

function scene:destroy()
    -- since delete_entity recursively deletes heirarchies,
    --  only delete the root node.
    E.delete_entity(self.camera)
end

function scene:do_idle( dt )
    self.state_time = self.state_time + dt

    local pos_x = self.camera_pos_x
    local pos_y = self.camera_pos_y
    local pos_z = self.camera_pos_z
    local ofs_x = self.camera_ofs_x
    local ofs_y = self.camera_ofs_y
    local ofs_z = self.camera_ofs_z
    local tar_x = self.camera_tar_x
    local tar_y = self.camera_tar_y
    local tar_z = self.camera_tar_z
    local k     = self.camera_smooth_factor

    -- get location of chase target

    stage_coords = get_vectors( self.stage )
    ident_coords = {1, 0, 0, 0, 1, 0, 0, 0, 1}
--    chase_coords = get_vectors( self.chase )

    local px, py, pz = E.get_entity_position(self.chase)

    local xx, xy, xz = 1, 0, 0
    local yx, yy, yz = 0, 1, 0
    local zx, zy, zz = 0, 0, 1

    -- calculate camera offset from target
    
    local x, y, z = 0, 0, 0
    
    if self.state == STATE_SCENE_SIDE  or
       self.state == STATE_SCENE_HIGH  or
       self.state == STATE_SCENE_BOOST or
       self.state == STATE_SCENE_MENU  then

        local kx = self.chase_ofs_x
	local ky = self.chase_ofs_y
	local kz = self.chase_ofs_z
       
        if self.state == STATE_SCENE_SIDE then
	    kx = kx * (.6 + .4*scenerate/50)
	    ky = ky * (.6 + .4*scenerate/50)
	end
	
	kx, ky, kz = convert_coord( kx, ky, kz, ident_coords )
	
	-- smooth offset travel
	
	ofs_x = ((k - 1) * ofs_x + kx) / k
	ofs_y = ((k - 1) * ofs_y + ky) / k
	ofs_z = ((k - 1) * ofs_z + kz) / k
	
	-- apply offset
	
	x, y, z = px + ofs_x, py + ofs_y, pz + ofs_z
	
    elseif self.state == STATE_SCENE_LOCK then
	
	x, y, z = pos_x, 20, pos_z
	
    end

    -- smooth camera motion
    
    pos_x = ((k - 1) * pos_x + x) / k
    pos_y = ((k - 1) * pos_y + y) / k
    pos_z = ((k - 1) * pos_z + z) / k
    
    if pos_y < 10 then pos_y = 10 end
    if pos_x < 15 then pos_x = 15 end
    if pos_x > 90 then pos_x = 90 end
    -- point camera at target's current position

    local lx = self.look_ofs_x
    local ly = self.look_ofs_y
    local lz = self.look_ofs_z

    if self.state == STATE_SCENE_SIDE then
	lz = lz * (.2 + .8*scenerate/50)
    end

    -- smooth target travel
    
    tar_x = ((k - 1) * tar_x + lx) / k
    tar_y = ((k - 1) * tar_y + ly) / k
    tar_z = ((k - 1) * tar_z + lz) / k

    local s_tx, s_ty, s_tz = convert_coord( tar_x, tar_y, tar_z, stage_coords)
    local s_x,  s_y,  s_z  = convert_coord( pos_x, pos_y, pos_z, stage_coords)
    local s_px, s_py, s_pz = convert_coord( px,    py,    pz,    stage_coords)

    local d = math.sqrt((s_x - (s_px + s_tx)) * (s_x - (s_px + s_tx)) +
			(s_z - (s_pz + s_tz)) * (s_z - (s_pz + s_tz)));
    
    local a = math.deg(math.atan2(s_x - (s_px + s_tx), s_z - (s_pz + s_tz))) 
    local b = math.deg(math.atan2(s_y - (s_py + s_ty), d))
    
    --[[
    if a > 155 then a = 155 end
    if a < 25  then a = 25  end
    --]]

    local shake = 0
    if self.state == STATE_SCENE_BOOST then
	local t    = self.state_time
	local wave = math.sin(t * 15 * math.pi)
	local env  = 0
	if t < 1 then env = 1 / (t * 500 + 1) end
	shake = wave * env * 45
	if self.camera_shake then
	    shake = shake + math.random(0, 3)/6
	end
	--[[
	E.print_console(string.format("t:%8.2f; w:%8.2f; e:%8.2f; s:%8.2f\n",
				      t, wave, env, shake))
	--]]
    elseif self.camera_shake then
	shake = shake + math.random(0, 3)/300
    end

    -- set camera and light

--  E.set_entity_position( self.mic,    pos_x, pos_y,     pos_z    )
    E.set_entity_position( self.mic,    px,    py,        pz       )
    E.set_entity_position( self.camera, s_x,   s_y,       s_z      )
    E.set_entity_rotation( self.camera, -b,    a,         shake    )
    E.set_entity_position( self.light,  s_px + 20,  s_py + 150, s_z - 30 )

    self.camera_pos_x = pos_x
    self.camera_pos_y = pos_y
    self.camera_pos_z = pos_z
    self.camera_ofs_x = ofs_x
    self.camera_ofs_y = ofs_y
    self.camera_ofs_z = ofs_z
    self.camera_tar_x = tar_x
    self.camera_tar_y = tar_y
    self.camera_tar_z = tar_z


    -- set snowfield position relative to camera

    local sox, soy, soz = 0, 0, -20
    sox, soy, soz = convert_coord(sox, soy, soz, get_vectors(self.camera))
    E.set_entity_position(self.field, s_x+sox, s_y+soy, s_z+soz)
end


function scene:update_snow( vx, vy, vz, dt)
    -- rotate snow
    self.snow_x_step = self.snow_x_step + vx * dt/2
    self.snow_y_step = self.snow_y_step + vy * dt/2
    self.snow_z_step = self.snow_z_step + vz * dt/2
    
    if self.snow_x_step > self.snow_sz then 
	self.snow_x_step = self.snow_x_step - self.snow_sz end
    if self.snow_x_step < 0 then 
	self.snow_x_step = self.snow_x_step + self.snow_sz end

    if self.snow_y_step > self.snow_sz then 
	self.snow_y_step = self.snow_y_step - self.snow_sz end
    if self.snow_y_step < 0 then 
	self.snow_y_step = self.snow_y_step + self.snow_sz end

    if self.snow_z_step > self.snow_sz then 
	self.snow_z_step = self.snow_z_step - self.snow_sz end
    if self.snow_z_step < 0 then 
	self.snow_z_step = self.snow_z_step + self.snow_sz end

   E.set_brush_vert_param(self.snow, 0, 
			   -self.snow_x_step, 
			   -self.snow_y_step, 
			   -self.snow_z_step, 0)

end

function scene:do_change_state( pstate, nstate )

    if nstate == STATE_SCENE_SIDE then
	self.chase_ofs_x = self.side_chase_ofs[1]
	self.chase_ofs_y = self.side_chase_ofs[2]
	self.chase_ofs_z = self.side_chase_ofs[3]
	self.look_ofs_x  = self.side_chase_ofs[4]
	self.look_ofs_y  = self.side_chase_ofs[5]
	self.look_ofs_z  = self.side_chase_ofs[6]
    elseif nstate == STATE_SCENE_HIGH then
	self.chase_ofs_x = self.high_chase_ofs[1]
	self.chase_ofs_y = self.high_chase_ofs[2]
	self.chase_ofs_z = self.high_chase_ofs[3]
	self.look_ofs_x  = self.high_chase_ofs[4]
	self.look_ofs_x  = self.high_chase_ofs[5]
	self.look_ofs_x  = self.high_chase_ofs[6]
    elseif nstate == STATE_SCENE_BOOST then
	self.chase_ofs_x = self.boost_chase_ofs[1]
	self.chase_ofs_y = self.boost_chase_ofs[2]
	self.chase_ofs_z = self.boost_chase_ofs[3]
	self.look_ofs_z  = self.boost_chase_ofs[4]
	self.look_ofs_z  = self.boost_chase_ofs[5]
	self.look_ofs_z  = self.boost_chase_ofs[6]
    elseif nstate == STATE_SCENE_LOCK then
	self.chase_ofs_x = self.lock_chase_ofs[1]
	self.chase_ofs_y = self.lock_chase_ofs[2]
	self.chase_ofs_z = self.lock_chase_ofs[3]
	self.look_ofs_z  = self.lock_chase_ofs[4]
	self.look_ofs_z  = self.lock_chase_ofs[5]
	self.look_ofs_z  = self.lock_chase_ofs[6]
    elseif nstate == STATE_SCENE_MENU then
	self.chase_ofs_x = self.menu_chase_ofs[1]
	self.chase_ofs_y = self.menu_chase_ofs[2]
	self.chase_ofs_z = self.menu_chase_ofs[3]
	self.look_ofs_z  = self.menu_chase_ofs[4]
	self.look_ofs_z  = self.menu_chase_ofs[5]
	self.look_ofs_z  = self.menu_chase_ofs[6]
    end
    
end
