-- $LastChangedDate: 2010-04-16 22:43:07 -0500 (Fri, 16 Apr 2010) $
-- Scene class.
-- See module.txt for documentation and pitfalls.

--------------
-- NodeSort --
--------------

-- This is a Lua table, created on the Lua side, that the C++ binding understands.
-- Used with sim.SceneGraph:AttachObject( object, nodeSort )
--
-- Usage:
-- Pass a table to the ctor.
-- Example:
-- nodeSort = NodeSort:New( { shader="metallic", transparent=true } )
-- Arg table corresponds to C++ NodeSort:
-- { shader="name", no_shader=true, transparent=true, no_depth_test=true }

NodeSort = { }

function NodeSort:New( attribTable )
    -- The arg table IS the object (idiom).
    return attribTable
end

-----------
-- Scene --
-----------

Scene = {
    reload = false,

    -- General way to load objects into scene using tables:
    objects = { },

    -- Special way to load objects into scene using user-defined functors:
    loadObjectFunctors = { },
}

-- Map location names to scene scripts.
Scene.scriptLocationMap = {
    [defs.SCENE_BASENAME] = "scene_" .. defs.SCENE_BASENAME .. ".lua",
}

-- Register a functor that creates an object in the scene.
-- This is for special objects.
function Scene:RegisterLoadObjectFunctor( functor )
    self.loadObjectFunctors[functor] = functor
end

-- (private)
function Scene:CopyObject( obj )
    return lib.CopyTable( obj )
end

-- Load Object as defined by table in Scene.objects.
function Scene:LoadObject( t )
    -- Default.
    if ( not t.scale ) then
        t.scale = 1.0
    end

    -- In case of reloading.
    sim.ZombifyObject( t, "object" )

    t.object = sim.Object:New( t.pos, t.file, t.scale, t.load )
    t.Rotate( t.object )
    t.object:SetCollidable( t.collidable )
    if ( t.nodeSort ) then
        sim.SceneGraph:AttachObjectSpecial( t.object, t.nodeSort )
    else
        sim.SceneGraph:AttachObject( t.object )
    end
end

-- (private)
function Scene:LoadObjects()
    -- Load objects as defined by tables (data structs).
    for k,t in KEYS_VALS(self.objects) do
        self:LoadObject( t )
    end

    -- Specially load objects as defined by functors.
    for LoadObjectFunctor in KEYS(self.loadObjectFunctors) do
        LoadObjectFunctor()
    end
end

-- Load scene according to location name.
-- Then optimize the scene-graph.
function Scene:Load( locationName )
    self.locationName = locationName  -- remember for Reload()
    local script = self.scriptLocationMap[locationName]
    if ( script ) then
        dofile( sim.scriptDir .. "/" .. script )
        self:LoadObjects()

        -- Optional hook function.
        if ( self.PostLoad ) then
            self:PostLoad()
        end

        -- Optimize scene-graph.
        sim.SceneGraph:OptimizeSceneGraph()

        return true
    else
        return false
    end

end

-- The ability to dynamically reload a scene is useful
-- for placing objects while editing a scene script.
function Scene:Reload()
    Log( "Reloading scene-graph..." )

    -- To tell registered object-load functors that reloading is occuring.
    self.reload = true

    -- If this is a reload, detach old Objects.
    if ( self.objects ) then
        for k,t in KEYS_VALS(self.objects) do
            sim.SceneGraph:DetachObject( t.object )
        end
    end

    -- Tell simulator core to flush scene-graph and reload essential parts.
    sim.Program:FlushSceneGraph()

    -- Reload the rest of the scene (as defined by Lua scripts).
    self:Load( self.locationName )

    Log( "...done reloading scene-graph." )
end

-- If scene is being reloaded.
function Scene:IfReload()
    return self.reload
end
