Index: trunk/src/formats/obj_loader.cc
===================================================================
--- trunk/src/formats/obj_loader.cc	(revision 433)
+++ trunk/src/formats/obj_loader.cc	(revision 442)
@@ -6,8 +6,7 @@
 
 #include "nv/formats/obj_loader.hh"
-#include "nv/io/std_stream.hh"
 #include "nv/interface/data_channel_access.hh"
 
-#include <sstream>
+#include <cstdio>
 
 using namespace nv;
@@ -50,8 +49,6 @@
 	vector< vec2 > t;
 
-	std::string line;
-	std::string cmd;
-	std::string name;
-	std::string next_name;
+	string32 name;
+	string32 next_name;
 
 	nv::size_t size;
@@ -59,5 +56,5 @@
 
 	obj_reader();
-	bool read_stream( std::istream& stream );
+	bool read_stream( stream& str );
 	virtual nv::size_t add_face( uint32* vi, uint32* ti, uint32* ni, nv::size_t count ) = 0;
 	virtual nv::size_t raw_size() const = 0;
@@ -79,46 +76,45 @@
 }
 
-bool obj_reader::read_stream( std::istream& stream )
-{
-	name = next_name;
+bool obj_reader::read_stream( stream& str )
+{
+	name.assign( next_name );
 	bool added_faces = false;
 	f32 x, y, z;
 	if ( eof ) return false;
-
-	while ( std::getline( stream, line ) )
-	{
-		if ( line.length() < 3 || line[0] == '#' )
-		{
-			continue;
-		}
-
-		std::istringstream ss(line);
-		ss >> cmd;
-
-		if ( cmd == "v" )
-		{
-			ss >> x >> y >> z;
+	char buffer[256];
+	while ( str.gets( buffer, 256 ) )
+	{
+		string_view cline( static_cast<const char*>( buffer ) );
+		cline = nv::trimmed( cline );
+
+		if ( cline.length() < 3 || cline[0] == '#' )
+		{
+			continue;
+		}
+
+		if ( cline.starts_with( "vn " ) )
+		{
+			sscanf( cline.data(), "vn %f %f %f", &x, &y, &z );
+			n.push_back( vec3( x, y, z ) );
+			continue;
+		}
+
+		if ( cline.starts_with( "vt " ) )
+		{
+			sscanf( cline.data(), "vt %f %f", &x, &y );
+			t.push_back( vec2( x, 1.0f - y ) );
+			continue;
+		}
+
+		if ( cline.starts_with( "v " ) )
+		{
+			sscanf( cline.data(), "v %f %f %f", &x, &y, &z );
 			v.push_back( vec3( x, y, z ) );
 			continue;
 		}
 
-		if ( cmd == "vn" )
-		{
-			ss >> x >> y >> z;
-			n.push_back( vec3( x, y, z ) );
-			continue;
-		}
-
-		if ( cmd == "vt" )
-		{
-			ss >> x >> y;
-			t.push_back( vec2( x, 1.0f - y ) );
-			continue;
-		}
-
-		if ( cmd == "f" )
+		if ( cline.starts_with( "f " ) )
 		{
 			added_faces = true;
-			ss >> cmd;
 
 			uint32 vis[8];
@@ -128,19 +124,25 @@
 			uint32 count = 0;
 
-			while ( !ss.fail() )
+			string_view scan( cline );
+			scan.remove_prefix( 2 );
+			size_t pos = 0;
+			while ( pos != string_view::npos )
 			{
-				char ch;
-
-				std::istringstream ss2( cmd );
-				ss2 >> vis[count] >> ch;
-				ss2 >> tis[count] >> ch;
-				if ( ch == '/')
+				scan.remove_prefix( pos );
+				scan = nv::trimmed( scan );
+				if ( sscanf( scan.data(), "%u/%u/%u", &vis[count], &tis[count], &nis[count] ) == 3 )
 				{
 					normals = true;
-					ss2 >> nis[count];
 				}
-
-				ss >> cmd;
+				else if ( !normals && sscanf( scan.data(), "%u/%u", &vis[count], &tis[count] ) == 2 )
+				{
+
+				}
+				else
+				{
+					break;
+				}
 				count++;
+				pos = scan.find_first_of( "\t " );
 			}
 
@@ -149,14 +151,14 @@
 		}
 
-		if ( cmd == "g" )
-		{
-			ss >> next_name;
+		if ( cline.starts_with( "g " ) )
+		{
+			next_name.assign( nv::trimmed( cline.without_prefix( 2 ) ) );
 			if (added_faces) 
 				return true;
-			name = next_name;
-			continue;
-		}
-
-		if ( cmd == "s" )
+			name.assign( next_name );
+			continue;
+		}
+
+		if ( cline.starts_with( "s " ) )
 		{
 			continue;
@@ -317,7 +319,5 @@
 	else
 		reader = new mesh_data_reader_vt();
-	std_stream sstream( &source );
-
-	while ( reader->read_stream( sstream ) )
+	while ( reader->read_stream( source ) )
 	{
 		if ( m_tangents )
@@ -328,5 +328,5 @@
 		data_channel_set* result = data_channel_set_creator::create_set( 1 );
 		data_channel_set_creator raccess( result );
-		raccess.set_name( make_name( reader->name.c_str() ) );
+		raccess.set_name( make_name( reader->name ) );
 		uint8* rdata = raccess.add_channel( m_descriptor, reader->size * 3 ).raw_data();
 
