Index: trunk/src/formats/md2_loader.cc
===================================================================
--- trunk/src/formats/md2_loader.cc	(revision 189)
+++ trunk/src/formats/md2_loader.cc	(revision 189)
@@ -0,0 +1,407 @@
+// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
+// http://chaosforge.org/
+//
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+#include "nv/formats/md2_loader.hh"
+
+#include <glm/gtc/constants.hpp>
+#include <glm/gtx/string_cast.hpp>
+#include "nv/logging.hh"
+#include <cstring>
+
+using namespace nv;
+
+// based on http://tfc.duke.free.fr/coding/md2-specs-en.html
+
+// assuming low-endian
+#define MD2_MAGIC         "IDP2"
+#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
+{
+	unsigned char v[3];
+	unsigned char 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, int 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( LOG_INFO, "num_skins    = " << md2->header.num_skins );
+	NV_LOG( LOG_INFO, "num_vertices = " << md2->header.num_vertices );
+	NV_LOG( LOG_INFO, "num_st       = " << md2->header.num_st );
+	NV_LOG( LOG_INFO, "num_tris     = " << md2->header.num_tris );
+	NV_LOG( 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), md2->header.num_skins );
+
+	source.seek( md2->header.offset_st, origin::SET );
+	source.read( md2->texcoords, sizeof(md2_texcoord_t), md2->header.num_st );
+
+	source.seek( md2->header.offset_tris, origin::SET );
+	source.read( md2->triangles, sizeof(md2_triangle_t), md2->header.num_tris );
+
+	source.seek( md2->header.offset_glcmds, origin::SET);
+	source.read( md2->glcmds, sizeof(int), 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]), 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 inline vec3 md2_normal( char normal )
+{
+	return md2_vec3( md2_normal_table[normal] );
+}
+
+static vec3 s_md2_normal_cache[MD2_NORMAL_COUNT];
+static bool s_md2_normal_ready = false;
+
+md2_loader::md2_loader() : m_md2( nullptr ), m_size( 0 )
+{
+	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()
+{
+	if (m_md2 != nullptr)
+	{
+		free_md2( (md2_t*)(m_md2) );
+		delete (md2_t*)m_md2;
+	}
+}
+
+bool md2_loader::load( stream& source )
+{
+	m_size = 0;
+	m_md2 = (void*)(new md2_t);
+	if ( !read_md2( (md2_t*)m_md2, source ) )
+	{
+		return false;
+	}
+	reindex();
+	m_size = m_new_indexes.size();
+	return true;
+}
+
+mesh* nv::md2_loader::release_mesh()
+{
+	return get_frame( 0 );
+}
+
+mesh* nv::md2_loader::get_frame( sint32 frame )
+{
+	md2_t* md2 = (md2_t*)m_md2;
+	if ( md2 == nullptr || frame >= md2->header.num_frames ) return nullptr;
+	mesh* m = new mesh();
+
+	vertex_attribute< vec3 >*   position = m->add_attribute<vec3>("nv_position");
+	vertex_attribute< vec3 >*   normal   = m->add_attribute<vec3>("nv_normal");
+	vertex_attribute< vec2 >*   texcoord = m->add_attribute<vec2>("nv_texcoord");
+	vertex_attribute< uint16 >* indices  = m->add_indices<uint16>();
+
+	load_positions( position->get(), frame );
+	load_normals( normal->get(), frame );
+
+	load_texcoords( texcoord->get() );
+	load_indicies( indices->get() );
+
+	m_size = indices->get().size();
+	return m;
+}
+
+sint32 md2_loader::get_max_frames() const
+{
+	return ((md2_t*)m_md2)->header.num_frames;
+}
+
+void md2_loader::load_positions( std::vector<vec3>& p, sint32 frame /*=-1*/ )
+{
+	md2_t* md2 = (md2_t*)m_md2;
+	sint32 num_frames = md2->header.num_frames;
+	sint32 num_verts  = m_new_vindexes.size();
+	p.clear();
+	sint32 current_frame = ( frame == -1 ? 0 : frame );
+	sint32 frame_count   = ( frame == -1 ? num_frames : 1 );
+
+	p.reserve( num_verts * frame_count );
+
+	while ( frame_count > 0 )
+	{
+		const md2_frame_t& frame = md2->frames[current_frame];
+		NV_LOG( LOG_INFO, "FrameID = " << frame.name );
+
+		vec3 scale     = md2_vec3( frame.scale );
+		vec3 translate = md2_vec3( frame.translate );
+
+		for (sint32 i = 0; i < num_verts; ++i )
+		{
+			const md2_vertex_t& v = frame.vertices[ m_new_vindexes[ i ] ];
+			p.push_back( vec3( v.v[0], v.v[2], v.v[1] ) * scale + translate );
+		}
+		++current_frame;
+		--frame_count;
+	}
+}
+
+void md2_loader::load_normals( std::vector<vec3>& n, sint32 frame /*=-1*/ )
+{
+	md2_t* md2 = (md2_t*)m_md2;
+	sint32 num_frames = md2->header.num_frames;
+	sint32 num_verts  =	m_new_vindexes.size();
+	n.clear();
+	sint32 current_frame = ( frame == -1 ? 0 : frame );
+	sint32 frame_count   = ( frame == -1 ? num_frames : 1 );
+
+	n.reserve( num_verts * frame_count );
+
+	while ( frame_count > 0 )
+	{
+		const md2_frame_t& frame = md2->frames[current_frame];
+
+		for (sint32 i = 0; i < num_verts; ++i )
+		{
+			const md2_vertex_t& v = frame.vertices[ m_new_vindexes[ i ] ];
+			n.push_back( s_md2_normal_cache[ v.n ] );
+		}
+		++current_frame;
+		--frame_count;
+	}
+}
+
+void md2_loader::load_texcoords( std::vector<vec2>& t )
+{
+	md2_t* md2 = (md2_t*)m_md2;
+	sint32 num_verts  = m_new_vindexes.size();
+
+	t.clear();
+	t.reserve( num_verts );
+
+	vec2 scale( 1.0f / (float) md2->header.skinwidth, 1.0f / (float) md2->header.skinheight );
+
+	for (sint32 i = 0; i < num_verts; ++i )
+	{
+		const md2_texcoord_t& st = md2->texcoords[ m_new_tindexes[ i ] ];
+		t.push_back( scale * vec2( st.s, st.t ) );
+	}
+
+}
+
+void md2_loader::load_indicies( std::vector<uint16>& idx )
+{
+	idx.assign( m_new_indexes.begin(), m_new_indexes.end() );
+}
+
+void nv::md2_loader::reindex()
+{
+	md2_t* md2 = (md2_t*)m_md2;
+	uint32 num_indexes = md2->header.num_tris * 3;
+
+	uint32 stats_reuse      = 0;
+	uint32 stats_collision  = 0;
+
+	std::vector< sint32 > index_translation( 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 )
+		{
+			short index  = t.vertex[j];
+			short tindex = t.st[j];
+
+			if ( index_translation[ index ] != -1 )
+			{
+				uint16 prev = 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( LOG_INFO, "New vertex count = " << m_new_vindexes.size() );
+	NV_LOG( LOG_INFO, "Collisions       = " << stats_collision );
+	NV_LOG( LOG_INFO, "Reuse count      = " << stats_reuse );
+}
Index: trunk/src/formats/md2_normals.inc
===================================================================
--- trunk/src/formats/md2_normals.inc	(revision 189)
+++ trunk/src/formats/md2_normals.inc	(revision 189)
@@ -0,0 +1,162 @@
+{ -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 188)
+++ trunk/src/formats/md3_loader.cc	(revision 189)
@@ -492,5 +492,5 @@
 }
 
-keyframed_mesh_data::keyframed_mesh_data( md3_loader* loader )
+keyframed_mesh_data::keyframed_mesh_data( keyframed_loader* loader )
 {
 	loader->load_positions( m_positions );
@@ -500,8 +500,13 @@
 
 	std::vector< std::string > names;
-	loader->load_tag_names( names );
-	for ( auto& name : names )
-	{
-		loader->load_tags( m_tags[ name ], name );
+
+	md3_loader* md3loader = dynamic_cast< md3_loader* >( loader );
+	if ( md3loader != nullptr )
+	{
+		md3loader->load_tag_names( names );
+		for ( auto& name : names )
+		{
+			md3loader->load_tags( m_tags[ name ], name );
+		}
 	}
 
Index: trunk/src/gui/gui_renderer.cc
===================================================================
--- trunk/src/gui/gui_renderer.cc	(revision 188)
+++ trunk/src/gui/gui_renderer.cc	(revision 189)
@@ -105,5 +105,5 @@
 	white.pos = ivec2();
 	m_atlas.set_region( white, wfill );
-	delete wfill;
+	delete[] wfill;
 
 	screen_render_data* sr = new screen_render_data( w->get_device(), 1024 );
