Index: trunk/src/formats/md3_loader.cc
===================================================================
--- trunk/src/formats/md3_loader.cc	(revision 303)
+++ trunk/src/formats/md3_loader.cc	(revision 304)
@@ -233,6 +233,6 @@
 static bool s_normal_ready = false;
 
-md3_loader::md3_loader()
-	: m_md3( nullptr )
+md3_loader::md3_loader( bool merge_all )
+	: m_md3( nullptr ), m_merge_all( merge_all )
 {
 	if ( !s_normal_ready )
@@ -319,28 +319,77 @@
 };
 
-mesh_data* nv::md3_loader::release_mesh_data( size_t )
+mesh_data* nv::md3_loader::release_mesh_data( size_t index )
 {
 	mesh_data* data = new mesh_data;
-	release_mesh_frame( data, -1 );
+	release_mesh_frame( data, -1, index );
 	return data;
 }
 
-void nv::md3_loader::release_mesh_frame( mesh_data* data, sint32 frame )
+void nv::md3_loader::release_mesh_frame( mesh_data* data, sint32 frame, sint32 surface )
 {
 	md3_t* md3 = (md3_t*)m_md3;
-	sint32 num_surfaces = md3->header.num_surfaces;
-	sint32 num_verts    = md3->vertices_per_frame;
+	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;
+		}
 
 	mesh_raw_channel* mc_pn = mesh_raw_channel::create< vtx_md3_pn >( num_verts * frame_count );
+	mesh_raw_channel* mc_t  = mesh_raw_channel::create< vtx_md3_t >( num_verts );
+	mesh_raw_channel* ic = mesh_raw_channel::create_index< uint16 >( index_count );
 	vtx_md3_pn* vtx_pn = (vtx_md3_pn*)mc_pn->data;
-
-	uint32 index = 0;
+	vtx_md3_t*  vtx_t  = (vtx_md3_t*) mc_t->data;
+	uint16*     icp    = (uint16*)ic->data;
+
+	uint32 index  = 0;
+	uint32 iindex = 0;
+	sint32 index_base = 0;
+
+	while ( surf_count > 0 )
+	{
+		const md3_surface_t& surface = md3->surfaces[ current_surf ];
+		const uint32         vcount  = static_cast< uint32 >( surface.header.num_verts );
+		const uint32         tcount  = static_cast< uint32 >( surface.header.num_triangles );
+
+		for (uint32 j = 0; j < vcount; ++j )
+		{
+			vtx_t[index++].texcoord = md3_texcoord( surface.st[j] );
+		}
+
+		for (size_t j = 0; j < tcount; ++j )
+		{
+			const md3_triangle_t& t = surface.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 += surface.header.num_verts;
+		++current_surf;
+		--surf_count;
+	}
+
+	index = 0;
 	while ( frame_count > 0 )
 	{
-		for ( sint32 i = 0; i < num_surfaces; ++i )
-		{
-			md3_surface_t& surface = md3->surfaces[i];
+		current_surf  = ( surface == -1 ? 0 : surface );
+		surf_count    = ( surface == -1 ? md3->header.num_surfaces : 1 );
+
+		while ( surf_count > 0 )
+		{
+			md3_surface_t& surface = md3->surfaces[current_surf];
 			sint32         vcount  = surface.header.num_verts;
 			sint32         offset  = vcount * current_frame;
@@ -353,45 +402,9 @@
 				index++;
 			}
-
+			++current_surf;
+			--surf_count;
 		}
 		++current_frame;
 		--frame_count;
-	}
-
-	index = 0;
-	mesh_raw_channel* mc_t = mesh_raw_channel::create< vtx_md3_t >( num_verts );
-	vtx_md3_t* vtx_t = (vtx_md3_t*)mc_t->data;
-	for ( sint32 i = 0; i < num_surfaces; ++i )
-	{
-		const md3_surface_t& surface = md3->surfaces[i];
-		const uint32         vcount  = static_cast< uint32 >( surface.header.num_verts );
-		for (uint32 j = 0; j < vcount; ++j )
-		{
-			vtx_t[index++].texcoord = md3_texcoord( surface.st[j] );
-		}
-	}
-
-	sint32 index_count = 0;
-	for ( sint32 i = 0; i < num_surfaces; ++i )
-	{
-		index_count += md3->surfaces[i].header.num_triangles * 3;
-	}
-
-	index = 0;
-	sint32 index_base = 0;
-	mesh_raw_channel* ic = mesh_raw_channel::create_index< uint16 >( index_count );
-	uint16* icp = (uint16*)ic->data;
-	for ( sint32 i = 0; i < num_surfaces; ++i )
-	{
-		const md3_surface_t& surface = md3->surfaces[i];
-		const size_t         tcount  = static_cast< size_t >( surface.header.num_triangles );
-		for (size_t j = 0; j < tcount; ++j )
-		{
-			const md3_triangle_t& t = surface.triangles[j];
-			icp[index++] = static_cast< uint16 >( index_base + t.indexes[0] );
-			icp[index++] = static_cast< uint16 >( index_base + t.indexes[1] );
-			icp[index++] = static_cast< uint16 >( index_base + t.indexes[2] );
-		}
-		index_base += surface.header.num_verts;
 	}
 
@@ -427,7 +440,24 @@
 mesh_data_pack* nv::md3_loader::release_mesh_data_pack()
 {
-	mesh_data* data = new mesh_data[1];
-	release_mesh_frame( &data[0], -1 );
-	return new mesh_data_pack( 1, data, release_mesh_nodes_data() );
+	md3_t* md3 = (md3_t*)m_md3;
+	uint32 count = 1;
+	mesh_data* data = nullptr;
+	if ( m_merge_all )
+	{
+		data = new mesh_data[1];
+		release_mesh_frame( &data[0], -1, -1 );
+		data[0].set_name( (char*)md3->header.name );
+	}
+	else
+	{
+		count = md3->header.num_surfaces;
+		data = new mesh_data[ count ];
+		for ( uint32 i = 0; i < count; ++i )
+		{
+			release_mesh_frame( &data[i], -1, i );
+			data[i].set_name( (char*)md3->surfaces[i].header.name );
+		}
+	}
+	return new mesh_data_pack( count, data, release_mesh_nodes_data() );
 }
 
Index: trunk/src/gfx/keyframed_mesh.cc
===================================================================
--- trunk/src/gfx/keyframed_mesh.cc	(revision 303)
+++ trunk/src/gfx/keyframed_mesh.cc	(revision 304)
@@ -47,5 +47,5 @@
 transform keyframed_mesh::get_node_transform( uint32 node_id ) const
 {
-	NV_ASSERT( m_tag_map, "TAGMAP FAIL" );
+	if ( !m_tag_map ) return transform();
 	NV_ASSERT( node_id < m_tag_map->get_count(), "TAGMAP FAIL" );
 	const key_data* data = m_tag_map->get_node( node_id )->data;
Index: trunk/src/gl/gl_window.cc
===================================================================
--- trunk/src/gl/gl_window.cc	(revision 303)
+++ trunk/src/gl/gl_window.cc	(revision 304)
@@ -115,6 +115,16 @@
 	case SDL_BUTTON_MIDDLE    : mevent.mbutton.button = MOUSE_MIDDLE; break;
 	case SDL_BUTTON_RIGHT     : mevent.mbutton.button = MOUSE_RIGHT; break;
-	//case SDL_BUTTON_WHEELUP   : mevent.mbutton.button = MOUSE_WHEEL_UP; break;
-	//case SDL_BUTTON_WHEELDOWN : mevent.mbutton.button = MOUSE_WHEEL_DOWN; break;
+#if NV_SDL_VERSION == NV_SDL_12
+	case SDL_BUTTON_WHEELUP   : 
+		mevent.type           = EV_MOUSE_WHEEL;
+		mevent.mwheel.x       = 0;
+		mevent.mwheel.y       = 3;
+		return true;
+	case SDL_BUTTON_WHEELDOWN : 
+		mevent.type           = EV_MOUSE_WHEEL;
+		mevent.mwheel.x       = 0;
+		mevent.mwheel.y       = -3;
+		return true;
+#endif
 	default : break;
 	}
@@ -122,4 +132,14 @@
 	return mevent.mbutton.button != MOUSE_NONE;
 }
+
+#if NV_SDL_VERSION == NV_SDL_20
+static bool sdl_mouse_wheel_to_io_event( const SDL_MouseWheelEvent& mm, io_event& mevent )
+{
+	mevent.type          = EV_MOUSE_WHEEL;
+	mevent.mwheel.x      = static_cast< sint32 >( mm.x );
+	mevent.mwheel.y      = static_cast< sint32 >( mm.y );
+	return true;
+}
+#endif
 
 static bool sdl_mouse_motion_to_io_event( const SDL_MouseMotionEvent& mm, io_event& mevent )
@@ -180,4 +200,7 @@
 	case SDL_MOUSEBUTTONDOWN : return sdl_mouse_button_to_io_event( e.button, ioevent );
 	case SDL_MOUSEBUTTONUP   : return sdl_mouse_button_to_io_event( e.button, ioevent );
+#if NV_SDL_VERSION == NV_SDL_20
+	case SDL_MOUSEWHEEL      : return sdl_mouse_wheel_to_io_event( e.wheel, ioevent );
+#endif
 /* // SDL 2.0 incompatible 
 	case SDL_ACTIVEEVENT     : 
Index: trunk/src/io_event.cc
===================================================================
--- trunk/src/io_event.cc	(revision 303)
+++ trunk/src/io_event.cc	(revision 304)
@@ -96,4 +96,10 @@
 	db->create_type<mouse_move_event>("mouse_move_event").fields( mouse_move_fields );
 
+	type_field mouse_wheel_fields[] = {
+		type_field( "x",       &mouse_wheel_event::x ),
+		type_field( "y",       &mouse_wheel_event::y ),
+	};
+	db->create_type<mouse_wheel_event>("mouse_wheel_event").fields( mouse_wheel_fields );
+
 	type_field joy_button_fields[] = {
 		type_field( "id",      &joy_button_event::id ),
