Index: trunk/src/formats/assimp_loader.cc
===================================================================
--- trunk/src/formats/assimp_loader.cc	(revision 475)
+++ trunk/src/formats/assimp_loader.cc	(revision 480)
@@ -462,21 +462,21 @@
 }
 
-mesh_data_pack* nv::assimp_loader::release_mesh_data_pack()
-{
-	if ( m_scene == nullptr || m_mesh_count == 0 ) return nullptr;
-	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
-	bool has_bones = false;
-	data_channel_set* meshes = data_channel_set_creator::create_set_array( m_mesh_count, 2 );
-	for ( size_t m = 0; m < m_mesh_count; ++m )
-	{
-		const aiMesh* mesh = scene->mMeshes[ m ];
-		data_channel_set_creator( &meshes[m] ).set_name( make_name( static_cast<const char*>( mesh->mName.data ) ) );
-		if ( mesh->mNumBones > 0 ) has_bones = true;
-		load_mesh_data(&meshes[m],m);
-	}
-
-	mesh_nodes_data* nodes = ( has_bones ? release_merged_bones( meshes ) : release_mesh_nodes_data(0) );
-	return new mesh_data_pack( m_mesh_count, meshes, nodes );
-}
+// mesh_data_pack* nv::assimp_loader::release_mesh_data_pack()
+// {
+// 	if ( m_scene == nullptr || m_mesh_count == 0 ) return nullptr;
+// 	const aiScene* scene = reinterpret_cast<const aiScene*>( m_scene );
+// 	bool has_bones = false;
+// 	data_channel_set* meshes = data_channel_set_creator::create_set_array( m_mesh_count, 2 );
+// 	for ( size_t m = 0; m < m_mesh_count; ++m )
+// 	{
+// 		const aiMesh* mesh = scene->mMeshes[ m ];
+// 		data_channel_set_creator( &meshes[m] ).set_name( make_name( static_cast<const char*>( mesh->mName.data ) ) );
+// 		if ( mesh->mNumBones > 0 ) has_bones = true;
+// 		load_mesh_data(&meshes[m],m);
+// 	}
+// 
+// 	mesh_nodes_data* nodes = ( has_bones ? release_merged_bones( meshes ) : release_mesh_nodes_data(0) );
+// 	return new mesh_data_pack( m_mesh_count, meshes, nodes );
+// }
 
 nv::size_t nv::assimp_loader::get_nodes_data_count() const
Index: trunk/src/formats/md2_loader.cc
===================================================================
--- trunk/src/formats/md2_loader.cc	(revision 475)
+++ 	(revision )
@@ -1,375 +1,0 @@
-// Copyright (C) 2012-2015 ChaosForge Ltd
-// http://chaosforge.org/
-//
-// This file is part of Nova libraries. 
-// For conditions of distribution and use, see copying.txt file in root folder.
-
-#include "nv/formats/md2_loader.hh"
-
-#include "nv/core/logging.hh"
-#include "nv/interface/data_channel_access.hh"
-
-#include <cstring>
-
-using namespace nv;
-
-// based on http://tfc.duke.free.fr/coding/md2-specs-en.html
-
-// assuming low-endian
-#define MD2_MAX_FRAMES    512
-#define MD2_MAX_SKINS     32
-#define MD2_MAX_VERTS     2048
-#define MD2_MAX_TRIANGLES 4096
-#define MD2_MAX_TEXCOORDS 2048
-#define MD2_NORMAL_COUNT  162
-
-typedef float md2_vec3_t[3];
-
-static const md2_vec3_t md2_normal_table[MD2_NORMAL_COUNT] = {
-#include "src/formats/md2_normals.inc"
-};
-
-struct md2_header_t
-{
-	char magic[4];
-	int version;
-
-	int skinwidth;
-	int skinheight;
-
-	int framesize;
-
-	int num_skins;
-	int num_vertices;
-	int num_st;
-	int num_tris;
-	int num_glcmds;
-	int num_frames;
-
-	int offset_skins;
-	int offset_st;
-	int offset_tris;
-	int offset_frames;
-	int offset_glcmds;
-	int offset_end;
-};
-
-struct md2_skin_t
-{
-	char name[64];
-};
-
-struct md2_texcoord_t
-{
-	short s;
-	short t;
-};
-
-struct md2_triangle_t
-{
-	unsigned short vertex[3];
-	unsigned short st[3];
-};
-
-struct md2_vertex_t
-{
-	uint8 v[3];
-	uint8 n;
-};
-
-struct md2_frame_t
-{
-	md2_vec3_t scale;
-	md2_vec3_t translate;
-	char name[16];
-	md2_vertex_t *vertices;
-};
-
-struct md2_glcmd_t
-{
-	float s;
-	float t;
-	int index;
-};
-
-struct md2_t
-{
-	md2_header_t    header;
-	md2_skin_t*     skins;
-	md2_texcoord_t* texcoords;
-	md2_triangle_t* triangles;
-	md2_frame_t*    frames;
-	int*            glcmds;
-};
-
-static bool check_md2_magic( char* magic )
-{
-	return magic[0] == 'I' && magic[1] == 'D' && magic[2] == 'P' && magic[3] == '2';
-}
-
-static void free_md2_frame( md2_frame_t* frame )
-{
-	delete[] frame->vertices;
-}
-
-static void free_md2( md2_t* md2 )
-{
-	delete[] md2->skins;
-	delete[] md2->texcoords;
-	delete[] md2->triangles;
-	delete[] md2->glcmds;
-	for ( int i = 0; i < md2->header.num_frames; ++i )
-	{
-		free_md2_frame( &(md2->frames[i]) );
-	}
-	delete[] md2->frames;
-}
-
-static bool read_md2_frame( md2_frame_t* frame, unsigned vcount, nv::stream& source )
-{
-	frame->vertices = new md2_vertex_t[ vcount ];
-	source.read( frame->scale,     sizeof(md2_vec3_t), 1 );
-	source.read( frame->translate, sizeof(md2_vec3_t), 1 );
-	source.read( frame->name,      sizeof(char), 16 );
-	source.read( frame->vertices,  sizeof(md2_vertex_t), vcount );
-	return true;
-}
-
-static bool read_md2( md2_t* md2, nv::stream& source )
-{
-	md2->frames     = nullptr;
-	md2->skins      = nullptr;
-	md2->texcoords  = nullptr;
-	md2->triangles  = nullptr;
-	md2->glcmds     = nullptr;
-
-	source.read( &(md2->header), sizeof(md2_header_t), 1 );
-
-	if ( !check_md2_magic( md2->header.magic )       ||
-		md2->header.num_skins    > MD2_MAX_SKINS     ||
-		md2->header.num_vertices > MD2_MAX_VERTS     ||
-		md2->header.num_st       > MD2_MAX_TEXCOORDS ||
-		md2->header.num_tris     > MD2_MAX_TRIANGLES ||
-		md2->header.num_frames   > MD2_MAX_FRAMES )
-	{
-		return false;
-	}
-
-	NV_LOG_INFO( "num_skins    = ", md2->header.num_skins );
-	NV_LOG_INFO( "num_vertices = ", md2->header.num_vertices );
-	NV_LOG_INFO( "num_st       = ", md2->header.num_st );
-	NV_LOG_INFO( "num_tris     = ", md2->header.num_tris );
-	NV_LOG_INFO( "num_frames   = ", md2->header.num_frames );
-
-
-	md2->skins      = new md2_skin_t    [ md2->header.num_skins ];
-	md2->texcoords  = new md2_texcoord_t[ md2->header.num_st ];
-	md2->triangles  = new md2_triangle_t[ md2->header.num_tris ];
-	md2->glcmds     = new int           [ md2->header.num_glcmds ];
-	
-	source.seek( md2->header.offset_skins, origin::SET );
-	source.read( md2->skins, sizeof( md2_skin_t ), static_cast<nv::size_t>( md2->header.num_skins ) );
-
-	source.seek( md2->header.offset_st, origin::SET );
-	source.read( md2->texcoords, sizeof( md2_texcoord_t ), static_cast<nv::size_t>( md2->header.num_st ) );
-
-	source.seek( md2->header.offset_tris, origin::SET );
-	source.read( md2->triangles, sizeof( md2_triangle_t ), static_cast<nv::size_t>( md2->header.num_tris ) );
-
-	source.seek( md2->header.offset_glcmds, origin::SET);
-	source.read( md2->glcmds, sizeof( int ), static_cast<nv::size_t>( md2->header.num_glcmds ) );
-
-	md2->frames    = new md2_frame_t   [ md2->header.num_frames ];
-	source.seek( md2->header.offset_frames, origin::SET );
-	for ( int i = 0; i < md2->header.num_frames; ++i )
-	{
-		if (!read_md2_frame( &(md2->frames[i]), static_cast<unsigned>( md2->header.num_vertices ), source ) ) return false;
-	}
-
-	return true;
-}
-
-static inline vec3 md2_vec3( const md2_vec3_t& v )
-{
-	//	return vec3( v[0], v[1], v[2] );
-	return vec3( v[0], v[2], v[1] );
-}
-
-static vec3 s_md2_normal_cache[MD2_NORMAL_COUNT];
-static bool s_md2_normal_ready = false;
-
-md2_loader::md2_loader( string_table* strings ) 
-	: mesh_loader( strings ), m_md2( nullptr )
-{
-	if ( !s_md2_normal_ready )
-	{
-		for ( int i = 0; i < MD2_NORMAL_COUNT; ++i )
-		{
-			s_md2_normal_cache[i].x = md2_normal_table[i][0];
-//			s_md2_normal_cache[i].y = md2_normal_table[i][1];
-//			s_md2_normal_cache[i].z = md2_normal_table[i][2];
-			s_md2_normal_cache[i].y = md2_normal_table[i][2];
-			s_md2_normal_cache[i].z = md2_normal_table[i][1];
-		}
-	}
-}
-
-
-md2_loader::~md2_loader()
-{
-	md2_t* md2 = reinterpret_cast< md2_t* >( m_md2 );
-	if ( md2 != nullptr)
-	{
-		free_md2( md2 );
-		delete md2;
-	}
-}
-
-bool md2_loader::load( stream& source )
-{
-	md2_t* md2 = new md2_t; 
-	m_md2 = md2;
-	if ( !read_md2( md2, source ) )
-	{
-		return false;
-	}
-	reindex();
-	return true;
-}
-
-nv::size_t md2_loader::get_max_frames() const
-{
-	return static_cast<size_t>( reinterpret_cast<md2_t*>( m_md2 )->header.num_frames );
-}
-
-void nv::md2_loader::reindex()
-{
-	md2_t* md2 = reinterpret_cast< md2_t* >( m_md2 );
-	uint32 num_indexes = static_cast< uint32 >( md2->header.num_tris * 3 );
-
-	uint32 stats_reuse      = 0;
-	uint32 stats_collision  = 0;
-
-	vector< sint32 > index_translation( static_cast< uint32 >( md2->header.num_vertices ), -1 );
-
-	m_new_indexes.clear();
-	m_new_indexes.reserve( num_indexes );
-	m_new_vindexes.reserve( num_indexes );
-	m_new_tindexes.reserve( num_indexes );
-
-	uint16 index_count = 0;
-
-	for ( int i = 0; i < md2->header.num_tris; ++i )
-	{
-		const md2_triangle_t& t = md2->triangles[i];
-		for ( int j = 0; j < 3; ++j )
-		{
-			uint16 index  = t.vertex[j];
-			uint16 tindex = t.st[j];
-
-			if ( index_translation[ index ] != -1 )
-			{
-				uint16 prev = static_cast< uint16 >( index_translation[ index ] );
-				if ( m_new_tindexes[ prev ] == tindex )
-				{
-					m_new_indexes.push_back( prev );
-					stats_reuse++;
-					continue;
-				}
-			}
-			
-			m_new_vindexes.push_back( index );
-			m_new_tindexes.push_back( tindex );
-			m_new_indexes.push_back( index_count );
-			if ( index_translation[ index ] == -1 )
-			{
-				index_translation[ index ] = index_count;
-			}
-			else
-			{
-				stats_collision++;
-			}
-			index_count++;
-		}
-	}
-
-	NV_LOG_INFO( "New vertex count = ", m_new_vindexes.size() );
-	NV_LOG_INFO( "Collisions       = ", stats_collision );
-	NV_LOG_INFO( "Reuse count      = ", stats_reuse );
-}
-
-
-struct vtx_md2_pn
-{
-	nv::vec3 position;
-	nv::vec3 normal;
-};
-
-struct vtx_md2_t
-{
-	nv::vec2 texcoord;
-};
-
-
-data_channel_set* nv::md2_loader::release_mesh_data( size_t )
-{
-	data_channel_set* data = data_channel_set_creator::create_set( 3 );
-	release_mesh_frame( data, -1 );
-	return data;
-}
-
-void nv::md2_loader::release_mesh_frame( data_channel_set* data, sint32 frame )
-{
-	md2_t* md2 = reinterpret_cast< md2_t* >( m_md2 );
-	size_t num_frames = static_cast< size_t >( md2->header.num_frames );
-	size_t num_verts  =	m_new_vindexes.size();
-	size_t current_frame = ( frame == -1 ? 0 : static_cast< size_t >( frame ) );
-	size_t frame_count   = ( frame == -1 ? num_frames : 1 );
-
-	data_channel_set_creator maccess( data );
-	vtx_md2_pn* vtx_pn = maccess.add_channel< vtx_md2_pn >( num_verts * frame_count ).data();
-	vtx_md2_t* vtx_t   = maccess.add_channel< vtx_md2_t >( num_verts ).data();
-	uint16* icp        = &maccess.add_channel< index_u16 >( m_new_indexes.size() ).data()->index;
-
-	maccess.set_name( make_name( "md2_mesh" ) );
-
-	uint32 index = 0;
-	while ( frame_count > 0 )
-	{
-		const md2_frame_t& cframe = md2->frames[current_frame];
-		NV_LOG_INFO( "FrameID = ", cframe.name );
-
-		vec3 scale     = md2_vec3( cframe.scale );
-		vec3 translate = md2_vec3( cframe.translate );
-
-		for (size_t i = 0; i < num_verts; ++i )
-		{
-			const md2_vertex_t& v = cframe.vertices[ m_new_vindexes[ i ] ];
-			vtx_pn[index].position = vec3( v.v[0], v.v[2], v.v[1] ) * scale + translate;
-			vtx_pn[index].normal   = s_md2_normal_cache[ v.n ];
-			index++;
-		}
-		++current_frame;
-		--frame_count;
-	}
-
-	vec2 scale( 1.0f / static_cast<float>( md2->header.skinwidth ), 1.0f / static_cast<float>( md2->header.skinheight ) );
-	for (size_t i = 0; i < num_verts; ++i )
-	{
-		const md2_texcoord_t& st = md2->texcoords[ m_new_tindexes[ i ] ];
-		vtx_t[i].texcoord = scale * vec2( st.s, st.t );
-	}
-
-	if ( m_new_indexes.size() > 0 )
-	{
-		raw_copy_n( m_new_indexes.data(), m_new_indexes.size(), icp );
-	}
-
-}
-
-mesh_data_pack* nv::md2_loader::release_mesh_data_pack()
-{
-	data_channel_set* data = data_channel_set_creator::create_set_array( 1, 3 );
-	release_mesh_frame( &data[0], -1 );
-	return new mesh_data_pack( 1, data );
-}
Index: trunk/src/formats/md2_normals.inc
===================================================================
--- trunk/src/formats/md2_normals.inc	(revision 475)
+++ 	(revision )
@@ -1,162 +1,0 @@
-{ -0.525731f,  0.000000f,  0.850651f }, 
-{ -0.442863f,  0.238856f,  0.864188f }, 
-{ -0.295242f,  0.000000f,  0.955423f }, 
-{ -0.309017f,  0.500000f,  0.809017f }, 
-{ -0.162460f,  0.262866f,  0.951056f }, 
-{  0.000000f,  0.000000f,  1.000000f }, 
-{  0.000000f,  0.850651f,  0.525731f }, 
-{ -0.147621f,  0.716567f,  0.681718f }, 
-{  0.147621f,  0.716567f,  0.681718f }, 
-{  0.000000f,  0.525731f,  0.850651f }, 
-{  0.309017f,  0.500000f,  0.809017f }, 
-{  0.525731f,  0.000000f,  0.850651f }, 
-{  0.295242f,  0.000000f,  0.955423f }, 
-{  0.442863f,  0.238856f,  0.864188f }, 
-{  0.162460f,  0.262866f,  0.951056f }, 
-{ -0.681718f,  0.147621f,  0.716567f }, 
-{ -0.809017f,  0.309017f,  0.500000f }, 
-{ -0.587785f,  0.425325f,  0.688191f }, 
-{ -0.850651f,  0.525731f,  0.000000f }, 
-{ -0.864188f,  0.442863f,  0.238856f }, 
-{ -0.716567f,  0.681718f,  0.147621f }, 
-{ -0.688191f,  0.587785f,  0.425325f }, 
-{ -0.500000f,  0.809017f,  0.309017f }, 
-{ -0.238856f,  0.864188f,  0.442863f }, 
-{ -0.425325f,  0.688191f,  0.587785f }, 
-{ -0.716567f,  0.681718f, -0.147621f }, 
-{ -0.500000f,  0.809017f, -0.309017f }, 
-{ -0.525731f,  0.850651f,  0.000000f }, 
-{  0.000000f,  0.850651f, -0.525731f }, 
-{ -0.238856f,  0.864188f, -0.442863f }, 
-{  0.000000f,  0.955423f, -0.295242f }, 
-{ -0.262866f,  0.951056f, -0.162460f }, 
-{  0.000000f,  1.000000f,  0.000000f }, 
-{  0.000000f,  0.955423f,  0.295242f }, 
-{ -0.262866f,  0.951056f,  0.162460f }, 
-{  0.238856f,  0.864188f,  0.442863f }, 
-{  0.262866f,  0.951056f,  0.162460f }, 
-{  0.500000f,  0.809017f,  0.309017f }, 
-{  0.238856f,  0.864188f, -0.442863f }, 
-{  0.262866f,  0.951056f, -0.162460f }, 
-{  0.500000f,  0.809017f, -0.309017f }, 
-{  0.850651f,  0.525731f,  0.000000f }, 
-{  0.716567f,  0.681718f,  0.147621f }, 
-{  0.716567f,  0.681718f, -0.147621f }, 
-{  0.525731f,  0.850651f,  0.000000f }, 
-{  0.425325f,  0.688191f,  0.587785f }, 
-{  0.864188f,  0.442863f,  0.238856f }, 
-{  0.688191f,  0.587785f,  0.425325f }, 
-{  0.809017f,  0.309017f,  0.500000f }, 
-{  0.681718f,  0.147621f,  0.716567f }, 
-{  0.587785f,  0.425325f,  0.688191f }, 
-{  0.955423f,  0.295242f,  0.000000f }, 
-{  1.000000f,  0.000000f,  0.000000f }, 
-{  0.951056f,  0.162460f,  0.262866f }, 
-{  0.850651f, -0.525731f,  0.000000f }, 
-{  0.955423f, -0.295242f,  0.000000f }, 
-{  0.864188f, -0.442863f,  0.238856f }, 
-{  0.951056f, -0.162460f,  0.262866f }, 
-{  0.809017f, -0.309017f,  0.500000f }, 
-{  0.681718f, -0.147621f,  0.716567f }, 
-{  0.850651f,  0.000000f,  0.525731f }, 
-{  0.864188f,  0.442863f, -0.238856f }, 
-{  0.809017f,  0.309017f, -0.500000f }, 
-{  0.951056f,  0.162460f, -0.262866f }, 
-{  0.525731f,  0.000000f, -0.850651f }, 
-{  0.681718f,  0.147621f, -0.716567f }, 
-{  0.681718f, -0.147621f, -0.716567f }, 
-{  0.850651f,  0.000000f, -0.525731f }, 
-{  0.809017f, -0.309017f, -0.500000f }, 
-{  0.864188f, -0.442863f, -0.238856f }, 
-{  0.951056f, -0.162460f, -0.262866f }, 
-{  0.147621f,  0.716567f, -0.681718f }, 
-{  0.309017f,  0.500000f, -0.809017f }, 
-{  0.425325f,  0.688191f, -0.587785f }, 
-{  0.442863f,  0.238856f, -0.864188f }, 
-{  0.587785f,  0.425325f, -0.688191f }, 
-{  0.688191f,  0.587785f, -0.425325f }, 
-{ -0.147621f,  0.716567f, -0.681718f }, 
-{ -0.309017f,  0.500000f, -0.809017f }, 
-{  0.000000f,  0.525731f, -0.850651f }, 
-{ -0.525731f,  0.000000f, -0.850651f }, 
-{ -0.442863f,  0.238856f, -0.864188f }, 
-{ -0.295242f,  0.000000f, -0.955423f }, 
-{ -0.162460f,  0.262866f, -0.951056f }, 
-{  0.000000f,  0.000000f, -1.000000f }, 
-{  0.295242f,  0.000000f, -0.955423f }, 
-{  0.162460f,  0.262866f, -0.951056f }, 
-{ -0.442863f, -0.238856f, -0.864188f }, 
-{ -0.309017f, -0.500000f, -0.809017f }, 
-{ -0.162460f, -0.262866f, -0.951056f }, 
-{  0.000000f, -0.850651f, -0.525731f }, 
-{ -0.147621f, -0.716567f, -0.681718f }, 
-{  0.147621f, -0.716567f, -0.681718f }, 
-{  0.000000f, -0.525731f, -0.850651f }, 
-{  0.309017f, -0.500000f, -0.809017f }, 
-{  0.442863f, -0.238856f, -0.864188f }, 
-{  0.162460f, -0.262866f, -0.951056f }, 
-{  0.238856f, -0.864188f, -0.442863f }, 
-{  0.500000f, -0.809017f, -0.309017f }, 
-{  0.425325f, -0.688191f, -0.587785f }, 
-{  0.716567f, -0.681718f, -0.147621f }, 
-{  0.688191f, -0.587785f, -0.425325f }, 
-{  0.587785f, -0.425325f, -0.688191f }, 
-{  0.000000f, -0.955423f, -0.295242f }, 
-{  0.000000f, -1.000000f,  0.000000f }, 
-{  0.262866f, -0.951056f, -0.162460f }, 
-{  0.000000f, -0.850651f,  0.525731f }, 
-{  0.000000f, -0.955423f,  0.295242f }, 
-{  0.238856f, -0.864188f,  0.442863f }, 
-{  0.262866f, -0.951056f,  0.162460f }, 
-{  0.500000f, -0.809017f,  0.309017f }, 
-{  0.716567f, -0.681718f,  0.147621f }, 
-{  0.525731f, -0.850651f,  0.000000f }, 
-{ -0.238856f, -0.864188f, -0.442863f }, 
-{ -0.500000f, -0.809017f, -0.309017f }, 
-{ -0.262866f, -0.951056f, -0.162460f }, 
-{ -0.850651f, -0.525731f,  0.000000f }, 
-{ -0.716567f, -0.681718f, -0.147621f }, 
-{ -0.716567f, -0.681718f,  0.147621f }, 
-{ -0.525731f, -0.850651f,  0.000000f }, 
-{ -0.500000f, -0.809017f,  0.309017f }, 
-{ -0.238856f, -0.864188f,  0.442863f }, 
-{ -0.262866f, -0.951056f,  0.162460f }, 
-{ -0.864188f, -0.442863f,  0.238856f }, 
-{ -0.809017f, -0.309017f,  0.500000f }, 
-{ -0.688191f, -0.587785f,  0.425325f }, 
-{ -0.681718f, -0.147621f,  0.716567f }, 
-{ -0.442863f, -0.238856f,  0.864188f }, 
-{ -0.587785f, -0.425325f,  0.688191f }, 
-{ -0.309017f, -0.500000f,  0.809017f }, 
-{ -0.147621f, -0.716567f,  0.681718f }, 
-{ -0.425325f, -0.688191f,  0.587785f }, 
-{ -0.162460f, -0.262866f,  0.951056f }, 
-{  0.442863f, -0.238856f,  0.864188f }, 
-{  0.162460f, -0.262866f,  0.951056f }, 
-{  0.309017f, -0.500000f,  0.809017f }, 
-{  0.147621f, -0.716567f,  0.681718f }, 
-{  0.000000f, -0.525731f,  0.850651f }, 
-{  0.425325f, -0.688191f,  0.587785f }, 
-{  0.587785f, -0.425325f,  0.688191f }, 
-{  0.688191f, -0.587785f,  0.425325f }, 
-{ -0.955423f,  0.295242f,  0.000000f }, 
-{ -0.951056f,  0.162460f,  0.262866f }, 
-{ -1.000000f,  0.000000f,  0.000000f }, 
-{ -0.850651f,  0.000000f,  0.525731f }, 
-{ -0.955423f, -0.295242f,  0.000000f }, 
-{ -0.951056f, -0.162460f,  0.262866f }, 
-{ -0.864188f,  0.442863f, -0.238856f }, 
-{ -0.951056f,  0.162460f, -0.262866f }, 
-{ -0.809017f,  0.309017f, -0.500000f }, 
-{ -0.864188f, -0.442863f, -0.238856f }, 
-{ -0.951056f, -0.162460f, -0.262866f }, 
-{ -0.809017f, -0.309017f, -0.500000f }, 
-{ -0.681718f,  0.147621f, -0.716567f }, 
-{ -0.681718f, -0.147621f, -0.716567f }, 
-{ -0.850651f,  0.000000f, -0.525731f }, 
-{ -0.688191f,  0.587785f, -0.425325f }, 
-{ -0.587785f,  0.425325f, -0.688191f }, 
-{ -0.425325f,  0.688191f, -0.587785f }, 
-{ -0.425325f, -0.688191f, -0.587785f }, 
-{ -0.587785f, -0.425325f, -0.688191f }, 
-{ -0.688191f, -0.587785f, -0.425325f }
Index: trunk/src/formats/md3_loader.cc
===================================================================
--- trunk/src/formats/md3_loader.cc	(revision 475)
+++ 	(revision )
@@ -1,463 +1,0 @@
-// Copyright (C) 2012-2015 ChaosForge Ltd
-// http://chaosforge.org/
-//
-// This file is part of Nova libraries. 
-// For conditions of distribution and use, see copying.txt file in root folder.
-
-#include "nv/formats/md3_loader.hh"
-
-#include "nv/core/logging.hh"
-#include "nv/interface/data_channel_access.hh"
-
-using namespace nv;
-
-// based on http://www.icculus.org/~phaethon/q3/formats/md3format.html#Surface
-
-// assuming low-endian
-#define MD3_MAX_FRAMES    1024
-#define MD3_MAX_TAGS      16
-#define MD3_MAX_SURFACES  32
-#define MD3_MAX_SHADERS   256
-#define MD3_MAX_VERTS     4096
-#define MD3_MAX_TRIANGLES 8192
-#define MD3_XYZ_SCALE     (1.0f/64.0f)
-
-struct md3_vec3_t
-{
-	float xyz[3];
-};
-
-struct md3_header_t
-{
-	char   ident[4]; // IDP3
-	sint32 version;  // 15
-	uint8  name[64]; // path name
-	sint32 flags;
-	sint32 num_frames;     // Number of Frame objects, with a maximum of MD3_MAX_FRAMES. Current value of MD3_MAX_FRAMES is 1024.
-	sint32 num_tags;       // Number of Tag objects, with a maximum of MD3_MAX_TAGS. Current value of MD3_MAX_TAGS is 16.
-	sint32 num_surfaces;   // Number of Surface objects, with a maximum of MD3_MAX_SURFACES. Current value of MD3_MAX_SURFACES is 32.
-	sint32 num_skins;      // Number of Skin objects. I should note that I have not seen an MD3 using this particular field for anything; this appears to be an artifact from the Quake 2 MD2 format. Surface objects have their own Shader field.
-	sint32 ofs_frames;     // Relative offset from start of MD3 object where Frame objects start. The Frame objects are written sequentially, that is, when you read one Frame object, you do not need to seek() for the next object.
-	sint32 ofs_tags;       // Relative offset from start of MD3 where Tag objects start. Similarly written sequentially.
-	sint32 ofs_surfaces;   // Relative offset from start of MD3 where Surface objects start. Again, written sequentially.
-	sint32 ofs_eof;        // Relative offset from start of MD3 to the end of the MD3 object. Note there is no offset for Skin objects.
-};
-
-struct md3_frame_t
-{
-	md3_vec3_t min_bounds;
-	md3_vec3_t max_bounds;
-	md3_vec3_t local_origin;
-	float      radius;
-	uint8      name[16];
-};
-
-struct md3_tag_t
-{
-	uint8      name[64];
-	md3_vec3_t origin;
-	md3_vec3_t axis[3];
-};
-
-struct md3_surface_header_t
-{
-	char   ident[4]; // IDP3
-	uint8  name[64]; // path name
-	sint32 flags;
-	sint32 num_frames;
-	sint32 num_shaders;
-	sint32 num_verts;
-	sint32 num_triangles;
-	sint32 ofs_triangles;
-	sint32 ofs_shaders;
-	sint32 ofs_st;
-	sint32 ofs_xyznormal;
-	sint32 ofs_end;
-};
-
-struct md3_shader_t
-{
-	uint8  name[64]; 
-	sint32 shader_index;
-};
-
-struct md3_triangle_t
-{
-	sint32 indexes[3];
-};
-
-struct md3_texcoord_t
-{
-	float  st[2];
-};
-
-struct md3_vertex_t
-{
-	sint16 x;
-	sint16 y;
-	sint16 z;
-	uint16 normal;
-};
-
-struct md3_surface_t
-{
-	md3_surface_header_t header;
-	md3_shader_t*        shaders;
-	md3_triangle_t*      triangles;
-	md3_texcoord_t*      st;
-	md3_vertex_t*        vertices;
-};
-
-struct md3_t
-{
-	md3_header_t   header;
-	md3_frame_t*   frames;
-	md3_tag_t*     tags;
-	md3_surface_t* surfaces;
-	// extra information (not in md3 file)
-	sint32         vertices_per_frame;
-};
-
-static bool check_md3_magic( char* magic )
-{
-	return magic[0] == 'I' && magic[1] == 'D' && magic[2] == 'P' && magic[3] == '3';
-}
-
-static void free_md3_surface( md3_surface_t * surface )
-{
-	delete[] surface->shaders;
-	delete[] surface->triangles;
-	delete[] surface->st;
-	delete[] surface->vertices;
-}
-
-static void free_md3( md3_t * md3 )
-{
-	sint32 count = md3->header.num_surfaces;
-	for ( sint32 i = 0; i < count; ++i )
-	{
-		free_md3_surface( &md3->surfaces[i] );
-	}
-	delete[] md3->frames;
-	delete[] md3->tags;
-	delete[] md3->surfaces;
-}
-
-static bool read_surface( md3_surface_t * surface, nv::stream& source )
-{
-	sint32 pos = static_cast< sint32 >( source.tell() );
-	source.read( &surface->header, sizeof(md3_surface_header_t), 1 );
-
-	if ( !check_md3_magic( surface->header.ident ) )          return false;
-	if ( surface->header.num_frames    >  MD3_MAX_FRAMES )    return false;
-	if ( surface->header.num_shaders   >  MD3_MAX_SHADERS )   return false;
-	if ( surface->header.num_verts     >  MD3_MAX_VERTS )     return false;
-	if ( surface->header.num_triangles >  MD3_MAX_TRIANGLES ) return false;
-
-	surface->shaders   = new md3_shader_t  [ surface->header.num_shaders ];
-	surface->vertices  = new md3_vertex_t  [ surface->header.num_verts * surface->header.num_frames ];
-	surface->st        = new md3_texcoord_t[ surface->header.num_verts ];
-	surface->triangles = new md3_triangle_t[ surface->header.num_triangles ];
-
-	source.seek( pos + surface->header.ofs_shaders, origin::SET );
-	source.read( surface->shaders, sizeof( md3_shader_t ), static_cast<nv::size_t>( surface->header.num_shaders ) );
-
-	source.seek( pos + surface->header.ofs_triangles, origin::SET );
-	source.read( surface->triangles, sizeof( md3_triangle_t ), static_cast<nv::size_t>( surface->header.num_triangles ) );
-
-	source.seek( pos + surface->header.ofs_st, origin::SET );
-	source.read( surface->st, sizeof( md3_texcoord_t ), static_cast<nv::size_t>( surface->header.num_verts ) );
-
-	source.seek( pos + surface->header.ofs_xyznormal, origin::SET );
-	source.read( surface->vertices, sizeof( md3_vertex_t ), static_cast<nv::size_t>( surface->header.num_verts * surface->header.num_frames ) );
-
-	if ( source.tell() != static_cast<nv::size_t>( pos + surface->header.ofs_end ) ) return false;
-
-	return true;
-}
-
-static bool read_md3( md3_t * md3, nv::stream& source )
-{
-	md3->frames   = nullptr;
-	md3->tags     = nullptr;
-	md3->surfaces = nullptr;
-
-	source.read( &md3->header, sizeof(md3_header_t), 1 );
-
-	if ( !check_md3_magic( md3->header.ident ) )        return false;
-	if ( md3->header.num_frames   >  MD3_MAX_FRAMES )   return false;
-	if ( md3->header.num_tags     >  MD3_MAX_TAGS )     return false;
-	if ( md3->header.num_surfaces >  MD3_MAX_SURFACES ) 
-	{
-		// to always have a safe free
-		md3->header.num_surfaces = 0;
-		return false;
-	}
-
-	md3->frames   = new md3_frame_t  [ md3->header.num_frames ];
-	md3->tags     = new md3_tag_t    [ md3->header.num_tags * md3->header.num_frames ];
-	md3->surfaces = new md3_surface_t[ md3->header.num_surfaces ];
-	nv::raw_zero_n( md3->surfaces, static_cast< nv::size_t >( md3->header.num_surfaces ) );
-
-	source.seek( md3->header.ofs_frames, origin::SET );
-	source.read( md3->frames, sizeof( md3_frame_t ), static_cast<nv::size_t>( md3->header.num_frames ) );
-
-	if ( md3->header.num_tags > 0 )
-	{
-		source.seek( md3->header.ofs_tags, origin::SET );
-		source.read( md3->tags, sizeof( md3_tag_t ), static_cast<nv::size_t>( md3->header.num_tags * md3->header.num_frames ) );
-	}
-
-	source.seek( md3->header.ofs_surfaces, origin::SET );
-	md3->vertices_per_frame = 0;
-
-	for ( sint32 i = 0; i < md3->header.num_surfaces; ++i )
-	{
-		if ( !read_surface( md3->surfaces + i, source ) ) return false;
-		if ( md3->header.num_frames != md3->surfaces[i].header.num_frames ) return false;
-		md3->vertices_per_frame += md3->surfaces[i].header.num_verts;
-	}
-	return true;
-}
-
-static inline vec3 md3_vec3( const md3_vec3_t& v )
-{
-//	return vec3( v.xyz[0], v.xyz[1], v.xyz[2] );
-	return vec3( v.xyz[0], v.xyz[2], v.xyz[1] );
-}
-
-static inline vec2 md3_texcoord( const md3_texcoord_t& v )
-{
-	return vec2( v.st[0], v.st[1] );
-}
-
-static vec3 s_normal_cache[256*256];
-static bool s_normal_ready = false;
-
-md3_loader::md3_loader( string_table* strings, bool merge_all )
-	: mesh_loader( strings ), m_merge_all( merge_all ), m_md3( nullptr )
-{
-	if ( !s_normal_ready )
-	{
-		float pi      = math::pi<float>();
-		float convert = (2 * pi) / 255.0f;
-		int n = 0;
-		for ( int lat = 0; lat < 256; ++lat )
-		{
-			float flat    = lat * convert;
-			float sin_lat = nv::sin( flat );
-			float cos_lat = nv::cos( flat );
-			for ( int lng = 0; lng < 256; ++lng, ++n )
-			{
-				float flng    = lng * convert;
-				float sin_lng = nv::sin( flng );
-				float cos_lng = nv::cos( flng );
-				s_normal_cache[n].x = cos_lat * sin_lng;
-//				s_normal_cache[n].y = sin_lat * sin_lng;
-//				s_normal_cache[n].z = cos_lng;
-				s_normal_cache[n].z = sin_lat * sin_lng;
-				s_normal_cache[n].y = cos_lng;
-			}
-		}
-
-		s_normal_ready = true;
-	}
-}
-
-
-nv::md3_loader::~md3_loader()
-{
-	md3_t* md3 = reinterpret_cast< md3_t* >( m_md3 );
-	if ( md3 != nullptr )
-	{
-		free_md3( md3 );
-		delete md3;
-	}
-}
-
-bool nv::md3_loader::load( stream& source )
-{
-	md3_t* md3 = new md3_t;
-	m_md3 = md3;
-	if ( !read_md3( md3, source ) )
-	{
-		return false;
-	}
-	return true;
-}
-
-void nv::md3_loader::load_tags( raw_data_channel* channel, const string_view& tag )
-{
-	md3_t* md3 = reinterpret_cast< md3_t* >( m_md3 );
-	data_channel_access< md3_key > access( channel );
-	// TODO: is this brain damaged in efficiency (loop nest order) or what?
-	for ( sint32 f = 0; f < md3->header.num_frames; ++f )
-	{
-		for ( sint32 i = 0; i < md3->header.num_tags; ++i )
-		{
-			const md3_tag_t& rtag = md3->tags[i + md3->header.num_tags * f];
-			string_view rname( reinterpret_cast< const char* >(rtag.name) );
-			if (rname == tag)
-			{
-				vec3 axisx  ( md3_vec3( rtag.axis[0] ) );
-				vec3 axisz  ( md3_vec3( rtag.axis[1] ) );
-				vec3 axisy  ( md3_vec3( rtag.axis[2] ) );
-				vec3 origin ( md3_vec3( rtag.origin )  );
-				access.data()[f].tform = transform( origin, quat( mat3( axisx, axisy, axisz ) ) );
-			}
-		}
-
-	}
-}
-
-struct vtx_md3_pn
-{
-	nv::vec3 position;
-	nv::vec3 normal;
-};
-
-struct vtx_md3_t
-{
-	nv::vec2 texcoord;
-};
-
-data_channel_set* nv::md3_loader::release_mesh_data( nv::size_t index )
-{
-	data_channel_set* data = data_channel_set_creator::create_set(3);
-	release_mesh_frame( data, -1, static_cast< sint32 >( index ) );
-	return data;
-}
-
-void nv::md3_loader::release_mesh_frame( data_channel_set* data, sint32 frame, sint32 surface )
-{
-	md3_t* md3 = reinterpret_cast< md3_t* >( m_md3 );
-	sint32 num_surfaces  = md3->header.num_surfaces;
-	sint32 num_verts     = 0;
-	sint32 current_frame = ( frame == -1 ? 0 : frame );
-	sint32 frame_count   = ( frame == -1 ? md3->header.num_frames : 1 );
-	sint32 current_surf  = ( surface == -1 ? 0 : surface );
-	sint32 surf_count    = ( surface == -1 ? md3->header.num_surfaces : 1 );
-	sint32 index_count   = 0;
-
-	if ( surface >= 0 )
-	{
-		index_count = md3->surfaces[surface].header.num_triangles * 3;
-		num_verts   = md3->surfaces[surface].header.num_verts;
-	}
-	else
-		for ( sint32 i = 0; i < num_surfaces; ++i )
-		{
-			index_count += md3->surfaces[i].header.num_triangles * 3;
-			num_verts   += md3->surfaces[i].header.num_verts;
-		}
-
-	data_channel_set_creator maccess( data );
-	maccess.set_name( make_name( reinterpret_cast<char*>( md3->header.name ) ) );
-
-
-	vtx_md3_pn* vtx_pn = maccess.add_channel< vtx_md3_pn >( static_cast< uint32 >( num_verts * frame_count ) ).data();
-	vtx_md3_t*  vtx_t  = maccess.add_channel< vtx_md3_t >( static_cast< uint32 >( num_verts ) ).data();
-	uint16*     icp    = reinterpret_cast< uint16* >( maccess.add_channel< index_u16 >( static_cast< uint32 >( index_count ) ).data() );
-
-	uint32 index  = 0;
-	uint32 iindex = 0;
-	sint32 index_base = 0;
-
-	while ( surf_count > 0 )
-	{
-		const md3_surface_t& sface  = md3->surfaces[ current_surf ];
-		const uint32         vcount = static_cast< uint32 >( sface.header.num_verts );
-		const uint32         tcount = static_cast< uint32 >( sface.header.num_triangles );
-
-		for (uint32 j = 0; j < vcount; ++j )
-		{
-			vtx_t[index++].texcoord = md3_texcoord( sface.st[j] );
-		}
-
-		for (size_t j = 0; j < tcount; ++j )
-		{
-			const md3_triangle_t& t = sface.triangles[j];
-			icp[iindex++] = static_cast< uint16 >( index_base + t.indexes[0] );
-			icp[iindex++] = static_cast< uint16 >( index_base + t.indexes[1] );
-			icp[iindex++] = static_cast< uint16 >( index_base + t.indexes[2] );
-		}
-		index_base += sface.header.num_verts;
-		++current_surf;
-		--surf_count;
-	}
-
-	index = 0;
-	while ( frame_count > 0 )
-	{
-		current_surf  = ( surface == -1 ? 0 : surface );
-		surf_count    = ( surface == -1 ? md3->header.num_surfaces : 1 );
-
-		while ( surf_count > 0 )
-		{
-			md3_surface_t& sface  = md3->surfaces[current_surf];
-			sint32 vcount = sface.header.num_verts;
-			sint32 offset = vcount * current_frame;
-			sint32 limit  = vcount + offset;
-			for ( sint32 j = offset; j < limit; ++j )
-			{
-				md3_vertex_t& v = sface.vertices[j];
-				vtx_pn[index].position = vec3( v.x * MD3_XYZ_SCALE, v.z * MD3_XYZ_SCALE, v.y * MD3_XYZ_SCALE );
-				vtx_pn[index].normal   = s_normal_cache[ v.normal ];
-				index++;
-			}
-			++current_surf;
-			--surf_count;
-		}
-		++current_frame;
-		--frame_count;
-	}
-
-}
-
-mesh_nodes_data* nv::md3_loader::release_mesh_nodes_data( nv::size_t )
-{
-	md3_t* md3 = reinterpret_cast< md3_t* >( m_md3 );
-	uint32 node_count = uint32( md3->header.num_tags );
-	if ( node_count == 0 ) return nullptr;
-	mesh_nodes_data* result = new mesh_nodes_data( m_strings ? m_strings->insert( "tags" ) : shash64() );
-	for ( uint32 i = 0; i < node_count; ++i )
-	{
-		const md3_tag_t& rtag = md3->tags[i];
-		string_view name( reinterpret_cast< const char* >(rtag.name) );
-		data_channel_set* set = data_channel_set_creator::create_set( 1 );
-		data_channel_set_creator access( set );
-		access.set_name( make_name( name ) );
-		load_tags( access.add_channel<md3_key>( uint32( md3->header.num_frames ) ).channel(), name );
-		result->append( set );
-	}
-	result->initialize();
-	return result;
-}
-
-mesh_data_pack* nv::md3_loader::release_mesh_data_pack()
-{
-	md3_t* md3 = reinterpret_cast<md3_t*>( m_md3 );
-	int count = 1;
-	data_channel_set* data = nullptr;
-	if ( m_merge_all )
-	{
-		data = data_channel_set_creator::create_set_array(1,3);
-		release_mesh_frame( &data[0], -1, -1 );
-	}
-	else
-	{
-		count = md3->header.num_surfaces;
-		data = data_channel_set_creator::create_set_array( count, 3 );
-		for ( int i = 0; i < count; ++i )
-		{
-			release_mesh_frame( &data[i], -1, i );
-			data_channel_set_creator( &data[i] ).set_name( make_name( reinterpret_cast< char* >( md3->surfaces[i].header.name ) ) );
-		}
-	}
-	return new mesh_data_pack( uint32( count ), data, release_mesh_nodes_data() );
-}
-
-nv::size_t md3_loader::get_max_frames() const
-{
-	return static_cast<size_t>( reinterpret_cast<md3_t*>( m_md3 )->header.num_frames );
-}
Index: trunk/src/formats/nmd_loader.cc
===================================================================
--- trunk/src/formats/nmd_loader.cc	(revision 475)
+++ trunk/src/formats/nmd_loader.cc	(revision 480)
@@ -50,17 +50,4 @@
 }
 
-mesh_data_pack* nv::nmd_loader::release_mesh_data_pack()
-{
-	uint32 size = m_meshes.size();
-	data_channel_set* meshes = data_channel_set_creator::create_set_array( size, 0 );
-	for ( uint32 i = 0; i < size; ++i )
-	{
-		meshes[i] = move( *m_meshes[i] );
-		delete m_meshes[i];
-	}
-	m_meshes.clear();
-	return new mesh_data_pack( size, meshes, release_mesh_nodes_data() );
-}
-
 void nv::nmd_loader::reset()
 {
@@ -240,19 +227,20 @@
 }
 
-void nv::nmd_dump( stream& stream_out, const mesh_data_pack* model, const string_table* strings, uint64 name )
+void nv::nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, const mesh_nodes_data* nodes, const string_table* strings /*= nullptr*/, uint64 name /*= 0 */ )
 {
 	uint32 elements = ( strings ? 1 : 0 ) // +1 string array
-		+ model->get_count() // meshes
-		+ ( model->get_node_count() > 0 ? 1 : 0 ); // nodes
+		+ meshes.size() // meshes
+		+ ( nodes && nodes->size() > 0 ? 1 : 0 ); // nodes
 	nmd_dump_header( stream_out, elements, name );
 
-	for ( uint32 i = 0; i < model->get_count(); ++i )
-	{
-		nmd_dump_element( stream_out, *model->get_mesh( i ), nv::nmd_type::MESH );
-	}
-
-	if ( model->get_node_count() > 0 )
-	{
-		nmd_dump_nodes( stream_out, *model->get_nodes() );
+	for ( uint32 i = 0; i < meshes.size(); ++i )
+	{
+		NV_ASSERT( meshes[i], "mesh is null!" );
+		nmd_dump_element( stream_out, *meshes[i], nv::nmd_type::MESH );
+	}
+
+	if ( nodes && nodes->size() > 0 )
+	{
+		nmd_dump_nodes( stream_out, *nodes );
 	}
 
@@ -262,2 +250,19 @@
 	}
 }
+
+void nv::nmd_dump( stream& stream_out, const mesh_nodes_data& animation, const string_table* strings, uint64 name )
+{
+	uint32 elements = ( strings ? 1 : 0 ) // +1 string array
+		+ ( animation.size() > 0 ? 1 : 0 ); // nodes
+	nmd_dump_header( stream_out, elements, name );
+
+	if ( animation.size() > 0 )
+	{
+		nmd_dump_nodes( stream_out, animation );
+	}
+
+	if ( strings )
+	{
+		nmd_dump_strings( stream_out, *strings );
+	}
+}
Index: trunk/src/formats/obj_loader.cc
===================================================================
--- trunk/src/formats/obj_loader.cc	(revision 475)
+++ trunk/src/formats/obj_loader.cc	(revision 480)
@@ -357,14 +357,2 @@
 }
 
-mesh_data_pack* nv::obj_loader::release_mesh_data_pack()
-{
-	uint32 size = m_meshes.size();
-	data_channel_set* meshes = data_channel_set_creator::create_set_array( size, 1 );
-	for ( uint32 i = 0; i < size; ++i )
-	{
-		meshes[i] = move( *m_meshes[i] );
-		delete m_meshes[i];
-	}
-	m_meshes.clear();
-	return new mesh_data_pack( size, meshes );
-}
