Index: trunk/src/formats/md2_loader.cc
===================================================================
--- trunk/src/formats/md2_loader.cc	(revision 239)
+++ trunk/src/formats/md2_loader.cc	(revision 240)
@@ -313,10 +313,10 @@
 
 
-mesh_data* nv::md2_loader::release_mesh_data()
-{
-	return release_mesh_data( -1 );
-}
-
-mesh_data* nv::md2_loader::release_mesh_data( sint32 frame )
+mesh_data* nv::md2_loader::release_mesh_data( size_t )
+{
+	return release_mesh_frame( -1 );
+}
+
+mesh_data* nv::md2_loader::release_mesh_frame( sint32 frame )
 {
 	md2_t* md2 = (md2_t*)m_md2;
Index: trunk/src/formats/md3_loader.cc
===================================================================
--- trunk/src/formats/md3_loader.cc	(revision 239)
+++ trunk/src/formats/md3_loader.cc	(revision 240)
@@ -319,10 +319,10 @@
 };
 
-mesh_data* nv::md3_loader::release_mesh_data()
-{
-	return release_mesh_data( -1 );
-}
-
-mesh_data* nv::md3_loader::release_mesh_data( sint32 frame )
+mesh_data* nv::md3_loader::release_mesh_data( size_t )
+{
+	return release_mesh_frame( -1 );
+}
+
+mesh_data* nv::md3_loader::release_mesh_frame( sint32 frame )
 {
 	md3_t* md3 = (md3_t*)m_md3;
Index: trunk/src/formats/md5_loader.cc
===================================================================
--- trunk/src/formats/md5_loader.cc	(revision 239)
+++ trunk/src/formats/md5_loader.cc	(revision 240)
@@ -534,8 +534,8 @@
 }
 
-mesh_data* nv::md5_loader::release_mesh_data( uint32 mesh )
-{
-	mesh_data* result = m_meshes[ mesh ];
-	m_meshes[ mesh ] = nullptr;
+mesh_data* nv::md5_loader::release_mesh_data( size_t index )
+{
+	mesh_data* result = m_meshes[ index ];
+	m_meshes[ index ] = nullptr;
 	return result;
 }
Index: trunk/src/formats/obj_loader.cc
===================================================================
--- trunk/src/formats/obj_loader.cc	(revision 239)
+++ trunk/src/formats/obj_loader.cc	(revision 240)
@@ -16,5 +16,5 @@
 	vec2 texcoord;
 
-	obj_vertex_vt( vec3 a_position, vec2 a_texcoord ) 
+	obj_vertex_vt( vec3 a_position, vec2 a_texcoord, vec3 ) 
 		: position( a_position ), texcoord( a_texcoord ) {}
 };
@@ -52,4 +52,5 @@
 
 	std::size_t size;
+	bool        eof;
 
 	obj_reader();
@@ -57,4 +58,5 @@
 	virtual size_t add_face( uint32* vi, uint32* ti, uint32* ni, size_t count ) = 0;
 	virtual size_t raw_size() const = 0;
+	virtual void reset() = 0;
 	virtual const uint8* raw_pointer() const = 0;
 	virtual void calculate_tangents() {}
@@ -70,9 +72,12 @@
 	t.push_back( vec2() );
 	size = 0;
+	eof = false;
 }
 
 bool obj_reader::read_stream( std::istream& stream )
 {
+	bool added_faces = false;
 	f32 x, y, z;
+	if ( eof ) return false;
 
 	while ( std::getline( stream, line ) )
@@ -109,4 +114,5 @@
 		if ( cmd == "f" )
 		{
+			added_faces = true;
 			ss >> cmd;
 
@@ -138,7 +144,12 @@
 		}
 
-		if ( cmd == "g" || cmd == "s" )
-		{
-			// ignored
+		if ( cmd == "g" )
+		{
+			if (added_faces) return true;
+			continue;
+		}
+
+		if ( cmd == "s" )
+		{
 			continue;
 		}
@@ -147,76 +158,64 @@
 	}
 
+	eof = true;
 	return true;
 }
 
-
-
-struct mesh_data_reader_vt : public obj_reader
-{
-	mesh_data_reader_vt()  {}
-	virtual std::size_t add_face( uint32* vi, uint32* ti, uint32*, size_t count )
+template < typename VTX >
+struct mesh_data_reader : public obj_reader
+{
+	mesh_data_reader( bool normals ) : m_normals( normals ) {}
+	virtual std::size_t add_face( uint32* vi, uint32* ti, uint32* ni, size_t count )
 	{
 		if ( count < 3 ) return 0; // TODO : report error?
+
 		// TODO : support if normals not present;
+		vec3 nullvec;
 		std::size_t result = 0;
 		// Simple triangulation - obj's shouldn't have more than quads anyway
-		for ( size_t i = 2; i < count; ++i )
-		{
-			result++;
-			m_data.emplace_back( v[ vi[ 0 ]   ], t[ ti[ 0   ] ] );
-			m_data.emplace_back( v[ vi[ i-1 ] ], t[ ti[ i-1 ] ] );
-			m_data.emplace_back( v[ vi[ i ]   ], t[ ti[ i   ] ] );
+
+		if ( m_normals )
+		{
+			for ( size_t i = 2; i < count; ++i )
+			{
+				result++;
+				m_data.emplace_back( v[ vi[ 0 ]   ], t[ ti[ 0   ] ], n[ ni[ 0   ] ] );
+				m_data.emplace_back( v[ vi[ i-1 ] ], t[ ti[ i-1 ] ], n[ ni[ i-1 ] ] );
+				m_data.emplace_back( v[ vi[ i ]   ], t[ ti[ i   ] ], n[ ni[ i   ] ] );
+			}
+		}
+		else
+		{
+			for ( size_t i = 2; i < count; ++i )
+			{
+				result++;
+				m_data.emplace_back( v[ vi[ 0 ]   ], t[ ti[ 0   ] ], nullvec );
+				m_data.emplace_back( v[ vi[ i-1 ] ], t[ ti[ i-1 ] ], nullvec );
+				m_data.emplace_back( v[ vi[ i ]   ], t[ ti[ i   ] ], nullvec );
+			}
 		}
 		return result;
 	}
-	std::vector< obj_vertex_vt > m_data;
-	virtual size_t raw_size() const { return m_data.size() * sizeof( obj_vertex_vt ); }
+	bool m_normals;
+	std::vector< VTX > m_data;
+	virtual void reset() { m_data.clear(); }
+	virtual size_t raw_size() const { return m_data.size() * sizeof( VTX ); }
 	virtual const uint8* raw_pointer() const { return (const uint8*)m_data.data(); }
 };
 
-struct mesh_data_reader_vtn : public obj_reader
-{
-	mesh_data_reader_vtn()  {}
-	virtual std::size_t add_face( uint32* vi, uint32* ti, uint32* ni, size_t count )
-	{
-		if ( count < 3 ) return 0; // TODO : report error?
-		// TODO : support if normals not present;
-		std::size_t result = 0;
-		// Simple triangulation - obj's shouldn't have more than quads anyway
-		for ( size_t i = 2; i < count; ++i )
-		{
-			result++;
-			m_data.emplace_back( v[ vi[ 0 ]   ], t[ ti[ 0   ] ], n[ ni[ 0   ] ] );
-			m_data.emplace_back( v[ vi[ i-1 ] ], t[ ti[ i-1 ] ], n[ ni[ i-1 ] ] );
-			m_data.emplace_back( v[ vi[ i ]   ], t[ ti[ i   ] ], n[ ni[ i   ] ] );
-		}
-		return result;
-	}
-	std::vector< obj_vertex_vtn > m_data;
-	virtual size_t raw_size() const { return m_data.size() * sizeof( obj_vertex_vtn ); }
-	virtual const uint8* raw_pointer() const { return (const uint8*)m_data.data(); }
-};
-
-struct mesh_data_reader_vtnt : public obj_reader
-{
-	mesh_data_reader_vtnt()  {}
-	virtual std::size_t add_face( uint32* vi, uint32* ti, uint32* ni, size_t count )
-	{
-		if ( count < 3 ) return 0; // TODO : report error?
-		// TODO : support if normals not present;
-		std::size_t result = 0;
-		// Simple triangulation - obj's shouldn't have more than quads anyway
-		for ( size_t i = 2; i < count; ++i )
-		{
-			result++;
-			m_data.emplace_back( v[ vi[ 0 ]   ], t[ ti[ 0   ] ], n[ ni[ 0   ] ] );
-			m_data.emplace_back( v[ vi[ i-1 ] ], t[ ti[ i-1 ] ], n[ ni[ i-1 ] ] );
-			m_data.emplace_back( v[ vi[ i ]   ], t[ ti[ i   ] ], n[ ni[ i   ] ] );
-		}
-		return result;
-	}
-	std::vector< obj_vertex_vtnt > m_data;
-	virtual size_t raw_size() const { return m_data.size() * sizeof( obj_vertex_vtnt ); }
-	virtual const uint8* raw_pointer() const { return (const uint8*)m_data.data(); }
+
+struct mesh_data_reader_vt : public mesh_data_reader< obj_vertex_vt >
+{
+	mesh_data_reader_vt() : mesh_data_reader( false ) {}
+};
+
+struct mesh_data_reader_vtn : public mesh_data_reader< obj_vertex_vtn >
+{
+	mesh_data_reader_vtn() : mesh_data_reader( true ) {}
+};
+
+struct mesh_data_reader_vtnt : public mesh_data_reader< obj_vertex_vtnt >
+{
+	mesh_data_reader_vtnt() : mesh_data_reader( true ) {}
 
 	// based on http://www.terathon.com/code/tangent.html
@@ -290,5 +289,5 @@
 
 nv::obj_loader::obj_loader( bool normals /*= true*/, bool tangents /*= false */ )
-	: m_normals( normals ), m_tangents( tangents ), m_mesh( nullptr )
+	: m_normals( normals ), m_tangents( tangents )
 {
 	if ( normals )
@@ -305,6 +304,4 @@
 bool nv::obj_loader::load( stream& source )
 {
-	if ( m_mesh ) delete m_mesh;
-	
 	obj_reader* reader = nullptr;
 	if ( m_normals )
@@ -318,36 +315,40 @@
 		reader = new mesh_data_reader_vt();
 	std_stream sstream( &source );
-	reader->read_stream( sstream );
-
-	if ( m_tangents )
-	{
-		reader->calculate_tangents();
-	}
+
+	while ( reader->read_stream( sstream ) )
+	{
+		if ( m_tangents )
+		{
+			reader->calculate_tangents();
+		}
 	
-
-	mesh_raw_channel* channel = new mesh_raw_channel();
-	nv::uint8* data = nullptr;
-
-	if ( reader->raw_size() > 0 ) 
-	{
-		data = new uint8[ reader->raw_size() ];
-		std::copy_n( reader->raw_pointer(), reader->raw_size(), data );
-	}
-	channel->data  = data;
-	channel->desc  = m_descriptor;
-	channel->count = reader->size * 3;
-	channel->size  = reader->raw_size();
+		mesh_raw_channel* channel = new mesh_raw_channel();
+		nv::uint8* data = nullptr;
+
+		if ( reader->raw_size() > 0 ) 
+		{
+			data = new uint8[ reader->raw_size() ];
+			std::copy_n( reader->raw_pointer(), reader->raw_size(), data );
+		}
+		channel->data  = data;
+		channel->desc  = m_descriptor;
+		channel->count = reader->size * 3;
+		channel->size  = reader->raw_size();
+
+		mesh_data* mesh = new mesh_data();
+		mesh->add_channel( channel );
+		m_meshes.push_back( mesh );
+
+		reader->reset();
+	}
 	delete reader;
-
-	m_mesh = new mesh_data();
-	m_mesh->add_channel( channel );
 	return true;
 
 }
 
-mesh_data* nv::obj_loader::release_mesh_data()
-{
-	mesh_data* result = m_mesh;
-	m_mesh = nullptr;
+mesh_data* nv::obj_loader::release_mesh_data( size_t index )
+{
+	mesh_data* result = m_meshes[ index ];
+	m_meshes[ index ] = nullptr;
 	return result;
 }
@@ -355,4 +356,4 @@
 nv::obj_loader::~obj_loader()
 {
-	if ( m_mesh ) delete m_mesh;
-}
+	for ( auto mesh : m_meshes ) if ( mesh ) delete mesh;
+}
Index: trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- trunk/src/gfx/skeletal_mesh.cc	(revision 239)
+++ trunk/src/gfx/skeletal_mesh.cc	(revision 240)
@@ -45,5 +45,6 @@
 {
 	delete m_va;
-	delete m_mesh_data;
+	// TODO : INSTANCE!
+	//	delete m_mesh_data;
 }
 
