Index: trunk/nv/gfx/keyframed_mesh.hh
===================================================================
--- trunk/nv/gfx/keyframed_mesh.hh	(revision 295)
+++ trunk/nv/gfx/keyframed_mesh.hh	(revision 296)
@@ -26,5 +26,5 @@
 		virtual mat4 get_node_matrix( uint32 node_id ) const;
 		virtual void update_animation( animation_entry*, uint32 a_anim_time );
-		virtual void update( program* a_program ) const;
+		virtual void update( program* a_program );
 		virtual ~keyframed_mesh();
 	protected:
@@ -67,6 +67,7 @@
 	{
 	public:
-		keyframed_mesh_gpu( device* a_device, const mesh_data* a_data, const mesh_nodes_data* a_tag_map, program* a_program );
+		keyframed_mesh_gpu( device* a_device, const mesh_data* a_data, const mesh_nodes_data* a_tag_map );
 		void update( uint32 ms );
+		virtual void update( program* a_program );
 	private:
 		int m_loc_next_position;
Index: trunk/nv/gfx/skeletal_mesh.hh
===================================================================
--- trunk/nv/gfx/skeletal_mesh.hh	(revision 295)
+++ trunk/nv/gfx/skeletal_mesh.hh	(revision 296)
@@ -16,11 +16,20 @@
 namespace nv
 {
-
-	class skeletal_animation_entry : public animation_entry
+	class skeletal_mesh : public animated_mesh
 	{
 	public:
-		skeletal_animation_entry( const std::string& name, const mesh_nodes_data* a_animation, bool a_looping ) 
+		skeletal_mesh() : animated_mesh() {}
+		virtual void run_animation( animation_entry* a_anim )
+		{
+			update_animation( a_anim, 0 );
+		}
+	};
+
+	class skeletal_animation_entry_cpu : public animation_entry
+	{
+	public:
+		skeletal_animation_entry_cpu( const std::string& name, const mesh_nodes_data* a_animation, bool a_looping ) 
 			: animation_entry( name, a_looping, a_animation->get_frame_rate(), 0.0f, a_animation->get_duration() ), m_node_data( a_animation ) {}
-		skeletal_animation_entry( const std::string& name, mesh_nodes_data* a_animation, float time_start, float time_end, bool a_looping )
+		skeletal_animation_entry_cpu( const std::string& name, mesh_nodes_data* a_animation, float time_start, float time_end, bool a_looping )
 			: animation_entry( name, a_looping, a_animation->get_frame_rate(), time_start, time_end ), m_node_data( a_animation ) {}
 		void update_skeleton( transform* skeleton, float time ) const;
@@ -29,12 +38,11 @@
 	};
 
-	class skeletal_mesh : public animated_mesh
+	class skeletal_mesh_cpu : public skeletal_mesh
 	{
 	public:
-		skeletal_mesh( device* a_device, const mesh_data* a_mesh_data, const mesh_nodes_data* bones );
+		skeletal_mesh_cpu( device* a_device, const mesh_data* a_mesh_data, const mesh_nodes_data* bones );
 		virtual size_t get_index_count() const { return m_indices; }
-		virtual void run_animation( animation_entry* a_anim );
 		virtual void update_animation( animation_entry* a_anim, uint32 a_anim_time );
-		virtual ~skeletal_mesh();
+		virtual ~skeletal_mesh_cpu();
 	protected:
 		uint32                       m_indices;
@@ -80,11 +88,10 @@
  	};
 
-	class skeletal_mesh_gpu : public animated_mesh
+	class skeletal_mesh_gpu : public skeletal_mesh
 	{
 	public:
 		skeletal_mesh_gpu( device* a_device, const mesh_data* a_mesh, const mesh_nodes_data* a_bone_data );
 		virtual size_t get_index_count() const { return m_index_count; }
-		virtual void run_animation( animation_entry* a_anim );
-		virtual void update( program* a_program ) const;
+		virtual void update( program* a_program );
 		virtual void update_animation( animation_entry* a_anim, uint32 
 			a_anim_time );
Index: trunk/nv/interface/animated_mesh.hh
===================================================================
--- trunk/nv/interface/animated_mesh.hh	(revision 295)
+++ trunk/nv/interface/animated_mesh.hh	(revision 296)
@@ -26,5 +26,5 @@
 	public:
 		animation_entry( const std::string& name, bool looping, uint32 frame_rate, float a_start, float a_end ) : m_name( name ), m_looping( looping ), m_frame_rate( frame_rate ),
-		m_start( a_start ), m_end( a_end ), m_duration( m_end - m_start ) {}
+		m_start( a_start ), m_end( a_end ), m_duration( m_end - m_start ), m_material_idx(0) {}
 		const std::string& get_name() const { return m_name; }
 		uint32 get_frame_rate() const { return m_frame_rate; }
@@ -43,4 +43,6 @@
 			m_frame_rate = rate;
 		}
+		void set_material_idx( uint32 idx ) { m_material_idx = idx; }
+		uint32 get_material_idx() const { return m_material_idx; }
 		virtual ~animation_entry() {}
 	protected:
@@ -51,4 +53,5 @@
 		float  m_end;
 		float  m_duration;
+		uint32 m_material_idx;
 	};
 
Index: trunk/nv/interface/context.hh
===================================================================
--- trunk/nv/interface/context.hh	(revision 295)
+++ trunk/nv/interface/context.hh	(revision 296)
@@ -39,5 +39,5 @@
 		explicit mesh_interface( vertex_array* array ) : m_va( array ) {}
 		virtual void update( uint32 ) {}
-		virtual void update( program* ) const {}
+		virtual void update( program* ) {}
 		virtual nv::vertex_array* get_vertex_array() const { return m_va; }
 		virtual size_t get_index_count() const { return 0; }
Index: trunk/nv/lua/lua_state.hh
===================================================================
--- trunk/nv/lua/lua_state.hh	(revision 295)
+++ trunk/nv/lua/lua_state.hh	(revision 296)
@@ -230,5 +230,8 @@
 			float get_float( const std::string& element, float defval = 0.0 );
 			bool get_boolean( const std::string& element, bool defval = false );
-
+			bool is_table( const std::string& element );
+			bool is_number( const std::string& element );
+			bool is_boolean( const std::string& element );
+			bool is_string( const std::string& element );
 		private:
 			int m_level;
Index: trunk/src/gfx/keyframed_mesh.cc
===================================================================
--- trunk/src/gfx/keyframed_mesh.cc	(revision 295)
+++ trunk/src/gfx/keyframed_mesh.cc	(revision 296)
@@ -98,5 +98,5 @@
 
 
-void nv::keyframed_mesh::update( program* a_program ) const
+void nv::keyframed_mesh::update( program* a_program )
 {
 	a_program->set_opt_uniform( "nv_interpolate", m_interpolation );
@@ -123,5 +123,5 @@
 }
 
-nv::keyframed_mesh_gpu::keyframed_mesh_gpu( device* a_device, const mesh_data* a_data, const mesh_nodes_data* a_tag_map, program* a_program )
+nv::keyframed_mesh_gpu::keyframed_mesh_gpu( device* a_device, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
 	: keyframed_mesh( a_device, a_data, a_tag_map )
 	, m_loc_next_position( -1 )
@@ -131,13 +131,5 @@
 	, m_gpu_next_frame( 0xFFFFFFFF )
 {
-	m_loc_next_position = a_program->get_attribute( "nv_next_position" )->get_location();
-	m_loc_next_normal   = a_program->get_attribute( "nv_next_normal" )->get_location();
-	m_loc_next_tangent  = a_program->try_get_attribute_location( "nv_next_tangent" );
 	m_va = a_device->create_vertex_array( a_data, STATIC_DRAW );
-	vertex_buffer* vb = m_va->find_buffer( slot::POSITION );
-	m_va->add_vertex_buffer( m_loc_next_position, vb, FLOAT, 3, 0, m_vsize, false );
-	m_va->add_vertex_buffer( m_loc_next_normal,   vb, FLOAT, 3, sizeof( vec3 ), m_vsize, false );
-	if ( m_has_tangent )
-		m_va->add_vertex_buffer( m_loc_next_tangent, vb, FLOAT, 4, 2*sizeof( vec3 ), m_vsize, false );
 }
 
@@ -145,4 +137,5 @@
 void nv::keyframed_mesh_gpu::update( uint32 ms )
 {
+	if ( m_loc_next_position == -1 ) return;
 	animated_mesh::update( ms );
 
@@ -157,5 +150,5 @@
 		m_gpu_last_frame = m_last_frame;
 	}
-	if ( m_gpu_next_frame != m_next_frame )
+	if ( m_loc_next_position != -1 && m_gpu_next_frame != m_next_frame )
 	{
 		m_va->update_vertex_buffer( m_loc_next_position, m_next_frame * m_vertex_count * m_vsize );
@@ -164,4 +157,22 @@
 		m_gpu_next_frame = m_next_frame;
 	}
+}
+
+void nv::keyframed_mesh_gpu::update( program* a_program )
+{
+	if ( m_loc_next_position == -1 )
+	{
+		m_loc_next_position = a_program->get_attribute( "nv_next_position" )->get_location();
+		m_loc_next_normal   = a_program->get_attribute( "nv_next_normal" )->get_location();
+		if ( m_has_tangent )
+			m_loc_next_tangent  = a_program->get_attribute( "nv_next_tangent" )->get_location();
+
+		vertex_buffer* vb = m_va->find_buffer( slot::POSITION );
+		m_va->add_vertex_buffer( m_loc_next_position, vb, FLOAT, 3, 0, m_vsize, false );
+		m_va->add_vertex_buffer( m_loc_next_normal,   vb, FLOAT, 3, sizeof( vec3 ), m_vsize, false );
+		if ( m_has_tangent )
+			m_va->add_vertex_buffer( m_loc_next_tangent, vb, FLOAT, 4, 2*sizeof( vec3 ), m_vsize, false );
+	}
+	keyframed_mesh::update( a_program );
 }
 
Index: trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- trunk/src/gfx/skeletal_mesh.cc	(revision 295)
+++ trunk/src/gfx/skeletal_mesh.cc	(revision 296)
@@ -11,6 +11,6 @@
 
 
-nv::skeletal_mesh::skeletal_mesh( device* a_device, const mesh_data* a_mesh_data, const mesh_nodes_data* bones )
-	: animated_mesh()
+nv::skeletal_mesh_cpu::skeletal_mesh_cpu( device* a_device, const mesh_data* a_mesh_data, const mesh_nodes_data* bones )
+	: skeletal_mesh()
 	, m_data( a_mesh_data )
 {
@@ -29,9 +29,9 @@
 }
 
-void nv::skeletal_mesh::update_animation( animation_entry* a_anim, uint32 a_anim_time )
+void nv::skeletal_mesh_cpu::update_animation( animation_entry* a_anim, uint32 a_anim_time )
 {
 	if ( a_anim )
 	{
-		skeletal_animation_entry * anim = (skeletal_animation_entry*)a_anim;
+		skeletal_animation_entry_cpu * anim = (skeletal_animation_entry_cpu*)a_anim;
 		anim->update_skeleton( m_transform.data(), (float)a_anim_time );
 		{
@@ -70,5 +70,5 @@
 
 
-void nv::skeletal_animation_entry::update_skeleton( transform* skeleton, float time ) const
+void nv::skeletal_animation_entry_cpu::update_skeleton( transform* skeleton, float time ) const
 {
 	float frame_duration = 1000.f / (float)m_node_data->get_frame_rate();
@@ -85,15 +85,7 @@
 
 
-nv::skeletal_mesh::~skeletal_mesh()
+nv::skeletal_mesh_cpu::~skeletal_mesh_cpu()
 {
 	delete m_va;
-}
-
-void nv::skeletal_mesh::run_animation( animation_entry* a_anim )
-{
-	if ( a_anim != nullptr )
-	{
-		update_animation( a_anim, 0 );
-	}
 }
 
@@ -209,5 +201,5 @@
 
 nv::skeletal_mesh_gpu::skeletal_mesh_gpu( device* a_device, const mesh_data* a_mesh, const mesh_nodes_data* a_bone_data )
-	: animated_mesh(), m_bone_data( a_bone_data ), m_transform( nullptr )
+	: skeletal_mesh(), m_bone_data( a_bone_data ), m_transform( nullptr )
 {
 	m_va          = a_device->create_vertex_array( a_mesh, nv::STATIC_DRAW );
@@ -219,24 +211,15 @@
 }
 
-void nv::skeletal_mesh_gpu::run_animation( animation_entry* a_anim )
-{
-	if ( m_bone_data && a_anim != nullptr )
-	{
-		skeletal_animation_entry_gpu * anim = (skeletal_animation_entry_gpu*)(a_anim);
+void nv::skeletal_mesh_gpu::update_animation( animation_entry* a_anim, uint32 a_anim_time )
+{
+	if ( m_bone_data && a_anim )
+	{
+		skeletal_animation_entry_gpu * anim = (skeletal_animation_entry_gpu*)a_anim;
 		anim->prepare( m_bone_data );
-		update_animation( a_anim, 0 );
-	}
-}
-
-void nv::skeletal_mesh_gpu::update_animation( animation_entry* a_anim, uint32 a_anim_time )
-{
-	if ( m_bone_data && a_anim )
-	{
-		skeletal_animation_entry_gpu * anim = (skeletal_animation_entry_gpu*)a_anim;
 		anim->update_skeleton( m_transform, a_anim_time );
 	}
 }
 
-void nv::skeletal_mesh_gpu::update( program* a_program ) const
+void nv::skeletal_mesh_gpu::update( program* a_program )
 {
 	if ( m_bone_data )
Index: trunk/src/lua/lua_state.cc
===================================================================
--- trunk/src/lua/lua_state.cc	(revision 295)
+++ trunk/src/lua/lua_state.cc	(revision 296)
@@ -209,4 +209,37 @@
 	return result;
 }
+
+bool nv::lua::table_guard::is_table( const std::string& element )
+{
+	lua_getfield( m_state, -1, element.c_str() );
+	bool result = lua_type( m_state, -1 ) == LUA_TTABLE;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+bool nv::lua::table_guard::is_number( const std::string& element )
+{
+	lua_getfield( m_state, -1, element.c_str() );
+	bool result = lua_type( m_state, -1 ) == LUA_TNUMBER;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+bool nv::lua::table_guard::is_boolean( const std::string& element )
+{
+	lua_getfield( m_state, -1, element.c_str() );
+	bool result = lua_type( m_state, -1 ) == LUA_TBOOLEAN;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+bool nv::lua::table_guard::is_string( const std::string& element )
+{
+	lua_getfield( m_state, -1, element.c_str() );
+	bool result = lua_type( m_state, -1 ) == LUA_TSTRING;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
 
 // state
