Index: trunk/src/core/io_event.cc
===================================================================
--- trunk/src/core/io_event.cc	(revision 504)
+++ trunk/src/core/io_event.cc	(revision 505)
@@ -71,29 +71,33 @@
 
 	db->create_type<key_event>()
-		.field( "ascii",   &key_event::ascii )
-		.field( "code",    &key_event::code )
-		.field( "shift",   &key_event::shift )
-		.field( "control", &key_event::control )
-		.field( "alt",     &key_event::alt )
-		.field( "pressed", &key_event::pressed );
+		.field( "window_id",&key_event::window_id )
+		.field( "ascii",    &key_event::ascii )
+		.field( "code",     &key_event::code )
+		.field( "shift",    &key_event::shift )
+		.field( "control",  &key_event::control )
+		.field( "alt",      &key_event::alt )
+		.field( "pressed",  &key_event::pressed );
 
 	db->create_type<mouse_button_event>()
-		.field( "x",       &mouse_button_event::x )
-		.field( "y",       &mouse_button_event::y )
-		.field( "button",  &mouse_button_event::button )
-		.field( "pressed", &mouse_button_event::pressed )
-		.field( "code",    &mouse_button_event::code );
+		.field( "window_id",&mouse_button_event::window_id )
+		.field( "x",        &mouse_button_event::x )
+		.field( "y",        &mouse_button_event::y )
+		.field( "button",   &mouse_button_event::button )
+		.field( "pressed",  &mouse_button_event::pressed )
+		.field( "code",     &mouse_button_event::code );
 
 	db->create_type<mouse_move_event>()
-		.field( "x",       &mouse_move_event::x )
-		.field( "y",       &mouse_move_event::y )
-		.field( "rx",      &mouse_move_event::rx )
-		.field( "ry",      &mouse_move_event::ry )
-		.field( "pressed", &mouse_move_event::pressed )
-		.field( "code",    &mouse_move_event::code );
+		.field( "window_id",&mouse_move_event::window_id )
+		.field( "x",        &mouse_move_event::x )
+		.field( "y",        &mouse_move_event::y )
+		.field( "rx",       &mouse_move_event::rx )
+		.field( "ry",       &mouse_move_event::ry )
+		.field( "pressed",  &mouse_move_event::pressed )
+		.field( "code",     &mouse_move_event::code );
 
 	db->create_type<mouse_wheel_event>()
-		.field( "x",       &mouse_wheel_event::x )
-		.field( "y",       &mouse_wheel_event::y );
+		.field( "window_id",&mouse_wheel_event::window_id )
+		.field( "x",        &mouse_wheel_event::x )
+		.field( "y",        &mouse_wheel_event::y );
 
 	db->create_type<pad_button_event>()
Index: trunk/src/core/types.cc
===================================================================
--- trunk/src/core/types.cc	(revision 504)
+++ trunk/src/core/types.cc	(revision 505)
@@ -3,4 +3,5 @@
 #include "nv/interface/clear_state.hh"
 #include "nv/interface/render_state.hh"
+#include "nv/stl/string.hh"
 
 using namespace nv;
@@ -26,4 +27,9 @@
 	db->create_type<ivec3>();
 	db->create_type<ivec4>();
+	db->create_type<quat>();
+	db->create_type<string32>();
+	db->create_type<string64>();
+	db->create_type<string128>();
+	db->create_type<string256>();
 
 	db->create_type<color_mask>()
Index: trunk/src/engine/image_manager.cc
===================================================================
--- trunk/src/engine/image_manager.cc	(revision 504)
+++ trunk/src/engine/image_manager.cc	(revision 505)
@@ -12,38 +12,19 @@
 using namespace nv;
 
-void nv::image_manager::add_base_path( const string_view& path )
+bool image_manager::load_resource( const string_view& filename )
 {
-	m_paths.emplace_back( path );
+	c_file_system fs;
+	if ( stream* file = open_stream( fs, filename ) )
+	{
+		png_loader loader;
+		image_data* result = loader.load( *file );
+		delete file;
+		if ( result )
+		{
+			add( filename, result );
+			return true;
+		}
+	}
+	return false;
 }
 
-bool image_manager::load_resource( const string_view& filename )
-{
-	png_loader loader;
-	c_file_system fs;
-	image_data* result = nullptr;
-	if ( fs.exists( filename ) )
-	{
-		stream* file = fs.open( filename );
-		result = loader.load( *file );
-		delete file;
-	}
-	else if ( m_paths.size() > 0 )
-	{
-		for ( const auto& path : m_paths )
-		{
-			string128 fpath = path;
-			fpath.append( filename );
-			if ( fs.exists( fpath ) )
-			{
-				stream* file = fs.open( fpath );
-				result = loader.load( *file );
-				delete file;
-				break;
-			}
-		}
-	}
-	if ( result ) 
-		add( filename, result );
-	return result != nullptr;
-}
-
Index: trunk/src/engine/material_manager.cc
===================================================================
--- trunk/src/engine/material_manager.cc	(revision 504)
+++ trunk/src/engine/material_manager.cc	(revision 505)
@@ -14,6 +14,5 @@
 
 nv::gpu_material_manager::gpu_material_manager( context* context, material_manager* matmgr, image_manager* imgmgr )
-	: m_context( context )
-	, m_material_manager( matmgr )
+	: dependant_resource_manager( matmgr ), m_context( context )
 	, m_image_manager( imgmgr )
 {
@@ -23,7 +22,8 @@
 }
 
-bool gpu_material_manager::load_resource( const string_view& id )
+nv::resource< nv::gpu_material > nv::gpu_material_manager::create_resource( resource< material > m )
 {
-	if ( auto mat = m_material_manager->get( id ).lock() )
+	resource_id id = m.id();
+	if ( auto mat = m.lock() )
 	{
 		gpu_material* result = new gpu_material;
@@ -39,12 +39,11 @@
 
 		// HACK
- 		for ( uint32 i = 0; i < 8; ++i )
- 			if ( result->textures[i].is_nil() )
- 				result->textures[i] = m_default;
-			
-		add( id, result );
-		return true;
+		for ( uint32 i = 0; i < 8; ++i )
+			if ( result->textures[i].is_nil() )
+				result->textures[i] = m_default;
+
+		return add( id, result );
 	}
-	return false;
+	return resource< nv::gpu_material >();
 }
 
Index: trunk/src/engine/mesh_manager.cc
===================================================================
--- trunk/src/engine/mesh_manager.cc	(revision 504)
+++ trunk/src/engine/mesh_manager.cc	(revision 505)
@@ -6,11 +6,11 @@
 
 #include "nv/engine/mesh_manager.hh"
+#include "nv/formats/nmd_loader.hh"
+#include "nv/io/c_file_system.hh"
 
 using namespace nv;
 
-resource< gpu_mesh > gpu_mesh_manager::load_resource( resource< data_channel_set > mesh )
+resource< gpu_mesh > gpu_mesh_manager::create_resource( resource< data_channel_set > mesh )
 {
-	resource< gpu_mesh > result = get( mesh.id().value() );
-	if ( result ) return result;
 	if ( auto lmesh = mesh.lock() )
 	{
@@ -24,20 +24,106 @@
 }
 
-bool nv::gpu_mesh_manager::load_resource( const string_view& id )
-{
-	if ( auto lmesh = m_mesh_manager->get( id ).lock() )
-	{
-		gpu_mesh* gm = new gpu_mesh;
-		gm->va = m_context->create_vertex_array( &*lmesh, STATIC_DRAW );
-		gm->count = lmesh->get_channel_size( slot::INDEX );
-		gm->shader = lmesh->get_channel( slot::BONEINDEX ) != nullptr ? BONE : NORMAL;
-		add( id, gm );
-		return true;
-	}
-	return false;
-}
-
 void gpu_mesh_manager::release( gpu_mesh* m )
 {
 	m_context->release( m->va );
 }
+
+nv::resource< nv::data_channel_set > nv::mesh_data_manager::get_path( const string_view& path, resource< mesh_data > default /*= resource< mesh_data >()*/, data_node_info* info /*= nullptr */ )
+{
+	nv::resource< nv::mesh_data > mr = default;
+
+	nv::string_view sub_mesh_name;
+	nv::string128 base_mesh_name( path );
+	nv::size_t sub_mesh_pos = path.find( ":" );
+	nv::size_t dot_pos = path.find( "." );
+	if ( sub_mesh_pos != nv::string_view::npos )
+	{
+		sub_mesh_name = path.substr( sub_mesh_pos + 1 );
+		base_mesh_name.assign( path.substr( 0, sub_mesh_pos ) );
+		NV_LOG_INFO( "Requested submesh - [", sub_mesh_name, "] in [", base_mesh_name, "]" );
+	}
+
+	if ( dot_pos != nv::string_view::npos )
+	{
+		mr = get( base_mesh_name );
+	}
+	else
+	{
+		sub_mesh_name = base_mesh_name;
+	}
+
+	if ( !mr )
+	{
+		NV_LOG_ERROR( "MESH FILE NOT FOUND - ", path );
+		NV_ASSERT( false, "MESH FILE NOT FOUND!" );
+		return nv::resource< nv::data_channel_set >();
+	}
+
+	if ( auto mdata = mr.lock() )
+	{
+		sint32 index = -1;
+		if ( sub_mesh_name.empty() )
+		{
+			index = 0;
+		}
+		else if ( sub_mesh_name[0] >= '0' && sub_mesh_name[0] <= '9' )
+		{
+			index = nv::buffer_to_uint32( sub_mesh_name.data(), nullptr );
+		}
+		else
+		{
+			auto itr = mdata->names.find( sub_mesh_name );
+			if ( itr != mdata->names.end() )
+				index = itr->second;
+		}
+		if ( index >= 0 )
+		{
+			if ( info )
+				*info = mdata->infos[index];
+			return mdata->meshes[index];
+		}
+
+		NV_LOG_ERROR( "Resource path fail! - ", path );
+		NV_ASSERT( false, "Resource path fail!" );
+	}
+	else
+	{
+		NV_LOG_ERROR( "Resource lock fail! - ", path );
+		NV_ASSERT( false, "Resource lock fail!" );
+	}
+	return nv::resource< nv::data_channel_set >();
+}
+
+bool nv::mesh_data_manager::load_resource( const string_view& id )
+{
+	nmd_loader* loader = nullptr;
+	c_file_system fs;
+	stream* mesh_file = open_stream( fs, id );
+	if ( !mesh_file ) return false;
+
+	loader = new nmd_loader( m_strings );
+	loader->load( *mesh_file );
+	delete mesh_file;
+
+	mesh_data* result = new mesh_data;
+	result->node_data = loader->release_data_node_list();
+	if ( result->node_data )
+	{
+		data_node_list* nd = result->node_data;
+		for ( uint32 i = 0; i < nd->size(); ++i )
+			result->node_names[(*nd)[i].name] = i;
+	}
+	for ( uint32 i = 0; i < loader->get_mesh_count(); ++i )
+	{
+		data_node_info info;
+		data_channel_set* data = loader->release_mesh_data( i, info );
+		result->infos.push_back( info );
+		result->names[ info.name ] = i;
+		auto mesh = m_mesh_manager->add( shash64( id.get_hash() + i ), data );
+		result->meshes.push_back( mesh );
+	}
+	delete loader;
+	if ( result )
+		add( id, result );
+	return result != nullptr;
+}
Index: trunk/src/engine/program_manager.cc
===================================================================
--- trunk/src/engine/program_manager.cc	(revision 504)
+++ trunk/src/engine/program_manager.cc	(revision 505)
@@ -45,4 +45,16 @@
 }
 
+nv::const_string nv::program_manager::file_to_string( const string_view& path )
+{
+	c_file_system fs;
+	stream* fstream = open_stream( fs, path );
+	if ( !fstream ) return const_string();
+	uint32 size = fstream->size();
+	const_string result( nullptr, size );
+	fstream->read( const_cast<char*>( result.data() ), size, 1 );
+	delete fstream;
+	return result;
+}
+
 nv::string_buffer nv::program_manager::load_source( lua::table_guard& table, const string_view& append )
 {
@@ -51,5 +63,5 @@
 	if ( table.is_string( "files" ) )
 	{
-		out.append( fs.slurp( table.get_string( "files" ) ) );
+		out.append( file_to_string( table.get_string( "files" ) ) );
 	}
 	else if ( table.is_table( "files" ) )
@@ -61,5 +73,5 @@
 			const_string include( inctable.get<const_string,uint32>(i) );
 			if ( i == count ) out.append( "#line 1\n" );
-			out.append( fs.slurp( include ) );
+			out.append( file_to_string( include ) );
 		}
 	}
@@ -67,5 +79,5 @@
 	if ( table.is_string( "file" ) )
 	{
-		const_string data = fs.slurp( table.get_string( "file" ) );
+		const_string data = file_to_string( table.get_string( "file" ) );
 		out.append( "#line 1\n" + data );
 	}
Index: trunk/src/gfx/image.cc
===================================================================
--- trunk/src/gfx/image.cc	(revision 504)
+++ trunk/src/gfx/image.cc	(revision 505)
@@ -98,4 +98,5 @@
 	const uint8* data = idata->get_data();
 	size_t depth      = idata->get_depth();
+	size_t cdepth     = m_depth > depth ? depth : m_depth;
 	uint32 dstride    = rsizex * depth;
 
@@ -106,5 +107,5 @@
 		{
 			uint32 xy = pos + x * m_depth;
-			for( size_t e = 0; e < depth; ++e )
+			for( size_t e = 0; e < cdepth; ++e )
 			{
 				m_data[ xy + e ] = data[ y*dstride + x * depth + e ];
Index: trunk/src/gl/gl_context.cc
===================================================================
--- trunk/src/gl/gl_context.cc	(revision 504)
+++ trunk/src/gl/gl_context.cc	(revision 505)
@@ -848,5 +848,4 @@
 }
 
-
 nv::gl_context::~gl_context()
 {
Index: trunk/src/gl/gl_device.cc
===================================================================
--- trunk/src/gl/gl_device.cc	(revision 504)
+++ trunk/src/gl/gl_device.cc	(revision 505)
@@ -145,5 +145,4 @@
 {
 	unsigned glid = 0;
-	unsigned glenum = buffer_type_to_enum( type );
 	glGenBuffers( 1, &glid );
 
Index: trunk/src/gl/gl_window.cc
===================================================================
--- trunk/src/gl/gl_window.cc	(revision 504)
+++ trunk/src/gl/gl_window.cc	(revision 505)
@@ -9,4 +9,5 @@
 #include "nv/core/logging.hh"
 #include "nv/lib/gl.hh"
+#include "nv/lib/sdl.hh"
 
 using namespace nv;
@@ -31,5 +32,4 @@
 	delete m_context;
 	m_context = nullptr;
-	delete m_input;
 }
 
@@ -41,4 +41,5 @@
 
 	m_handle = handle;
+	m_dc     = dc;
 
 	// TODO: error checking
@@ -110,2 +111,15 @@
 }
 
+void nv::gl_window::make_current()
+{
+#if NV_PLATFORM == NV_WINDOWS
+	HDC hdc = reinterpret_cast<HDC>( m_hwnd );
+	dynwglMakeCurrent( hdc, reinterpret_cast<HGLRC>( m_context->get_native_handle() ) );
+#endif
+}
+
+nv::uint32 nv::gl_window::window_id()
+{
+	return SDL_GetWindowID( static_cast<SDL_Window*>( m_handle ) );
+}
+
Index: trunk/src/lua/lua_state.cc
===================================================================
--- trunk/src/lua/lua_state.cc	(revision 504)
+++ trunk/src/lua/lua_state.cc	(revision 505)
@@ -201,5 +201,5 @@
 }
 
-shash64 nv::lua::table_guard::get_string( string_view element, string_table& table, uint64 defval /*= 0 */ )
+nv::shash64 nv::lua::table_guard::get_string( string_view element, string_table* table, uint64 defval /*= 0 */ )
 {
 	lua_getfield( m_state, -1, element.data() );
@@ -210,13 +210,68 @@
 	{
 		str = lua_tolstring( m_state, -1, &l );
-		result = table.insert( string_view( str, l ) );
-	}
-	lua_pop( m_state, 1 );
-	return result;
-}
-
-nv::shash64 nv::lua::table_guard::get_string( string_view element, string_table* table, uint64 defval /*= 0 */ )
-{
-	lua_getfield( m_state, -1, element.data() );
+		string_view sv( str, l );
+		result = table ? table->insert( sv ) : shash64( sv );
+	}
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+shash64 nv::lua::table_guard::get_string_hash_64( int i, uint64 defval /*= 0 */ )
+{
+	lua_rawgeti( m_state, -1, i );
+	size_t l = 0;
+	const char* str = nullptr;
+	uint64 result = defval;
+	if ( lua_type( m_state, -1 ) == LUA_TSTRING )
+	{
+		str = lua_tolstring( m_state, -1, &l );
+		result = hash_string< uint64 >( str, l );
+		//NV_LOG_DEBUG( str );
+	}
+	lua_pop( m_state, 1 );
+	return shash64( result );
+}
+
+nv::string128 nv::lua::table_guard::get_string128( int i, string_view defval /*= string_view() */ )
+{
+	lua_rawgeti( m_state, -1, i );
+	size_t l = 0;
+	const char* str = nullptr;
+	if ( lua_type( m_state, -1 ) == LUA_TSTRING )
+	{
+		str = lua_tolstring( m_state, -1, &l );
+	}
+	else
+	{
+		l = defval.size();
+		str = defval.data();
+	}
+	string128 result( str, l );
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+const_string nv::lua::table_guard::get_string( int i, string_view defval /*= string_view() */ )
+{
+	lua_rawgeti( m_state, -1, i );
+	size_t l = 0;
+	const char* str = nullptr;
+	if ( lua_type( m_state, -1 ) == LUA_TSTRING )
+	{
+		str = lua_tolstring( m_state, -1, &l );
+	}
+	else
+	{
+		l = defval.size();
+		str = defval.data();
+	}
+	const_string result( str, l );
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+shash64 nv::lua::table_guard::get_string( int i, string_table* table, uint64 defval /*= 0 */ )
+{
+	lua_rawgeti( m_state, -1, i );
 	size_t l = 0;
 	const char* str = nullptr;
@@ -302,4 +357,52 @@
 }
 
+char nv::lua::table_guard::get_char( int i, char defval /*= ' ' */ )
+{
+	lua_rawgeti( m_state, -1, i );
+	char result = ( lua_type( m_state, -1 ) == LUA_TSTRING && nlua_rawlen( m_state, -1 ) > 0 ) ? lua_tostring( m_state, -1 )[0] : defval;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+int nv::lua::table_guard::get_integer( int i, int defval /*= 0 */ )
+{
+	lua_rawgeti( m_state, -1, i );
+	lua_Integer result = lua_type( m_state, -1 ) == LUA_TNUMBER ? lua_tointeger( m_state, -1 ) : defval;
+	lua_pop( m_state, 1 );
+	return static_cast<int>( result );
+}
+
+unsigned nv::lua::table_guard::get_unsigned( int i, unsigned defval /*= 0 */ )
+{
+	lua_rawgeti( m_state, -1, i );
+	unsigned result = lua_type( m_state, -1 ) == LUA_TNUMBER ? nlua_tounsigned( m_state, -1 ) : defval;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+double nv::lua::table_guard::get_double( int i, double defval /*= 0.0 */ )
+{
+	lua_rawgeti( m_state, -1, i );
+	double result = lua_type( m_state, -1 ) == LUA_TNUMBER ? lua_tonumber( m_state, -1 ) : defval;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+float nv::lua::table_guard::get_float( int i, float defval /*= 0.0 */ )
+{
+	lua_rawgeti( m_state, -1, i );
+	float result = lua_type( m_state, -1 ) == LUA_TNUMBER ? static_cast<float>( lua_tonumber( m_state, -1 ) ) : defval;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+bool nv::lua::table_guard::get_boolean( int i, bool defval /*= false */ )
+{
+	lua_rawgeti( m_state, -1, i );
+	bool result = lua_type( m_state, -1 ) == LUA_TBOOLEAN ? lua_toboolean( m_state, -1 ) != 0 : defval;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
 float nv::lua::table_guard::get_float( string_view element, float defval /*= 0.0 */ )
 {
@@ -326,4 +429,36 @@
 }
 
+bool nv::lua::table_guard::is_table( int i )
+{
+	lua_rawgeti( m_state, -1, i );
+	bool result = lua_type( m_state, -1 ) == LUA_TTABLE;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+bool nv::lua::table_guard::is_number( int i )
+{
+	lua_rawgeti( m_state, -1, i );
+	bool result = lua_type( m_state, -1 ) == LUA_TNUMBER;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+bool nv::lua::table_guard::is_boolean( int i )
+{
+	lua_rawgeti( m_state, -1, i );
+	bool result = lua_type( m_state, -1 ) == LUA_TBOOLEAN;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
+bool nv::lua::table_guard::is_string( int i )
+{
+	lua_rawgeti( m_state, -1, i );
+	bool result = lua_type( m_state, -1 ) == LUA_TSTRING;
+	lua_pop( m_state, 1 );
+	return result;
+}
+
 bool nv::lua::table_guard::is_number( string_view element )
 {
@@ -349,5 +484,4 @@
 	return result;
 }
-
 
 bool nv::lua::table_guard::read( const string_view& element, const type_entry* entry, void* object )
Index: trunk/src/sdl/sdl_input.cc
===================================================================
--- trunk/src/sdl/sdl_input.cc	(revision 504)
+++ trunk/src/sdl/sdl_input.cc	(revision 505)
@@ -20,8 +20,9 @@
 static bool sdl_key_event_to_io_event( const SDL_KeyboardEvent& ke, io_event& kevent )
 {
-	kevent.type        = EV_KEY;
-	kevent.key.pressed = ( ke.state != SDL_RELEASED );
-	kevent.key.ascii   = 0;
-	kevent.key.code    = KEY_NONE;
+	kevent.type          = EV_KEY;
+	kevent.key.window_id = ke.windowID;
+	kevent.key.pressed   = ( ke.state != SDL_RELEASED );
+	kevent.key.ascii     = 0;
+	kevent.key.code      = KEY_NONE;
 
 	uint32 ucode = static_cast<uint32>( ke.keysym.sym );
@@ -107,9 +108,10 @@
 static bool sdl_mouse_button_to_io_event( const SDL_MouseButtonEvent& mb, io_event& mevent )
 {
-	mevent.type            = EV_MOUSE_BUTTON;
-	mevent.mbutton.button  = MOUSE_NONE;
-	mevent.mbutton.pressed = (mb.state != SDL_RELEASED);
-	mevent.mbutton.x       = static_cast< uint16 >( mb.x );
-	mevent.mbutton.y       = static_cast< uint16 >( mb.y );
+	mevent.type              = EV_MOUSE_BUTTON;
+	mevent.mbutton.window_id = mb.windowID;
+	mevent.mbutton.button    = MOUSE_NONE;
+	mevent.mbutton.pressed   = (mb.state != SDL_RELEASED);
+	mevent.mbutton.x         = static_cast< uint16 >( mb.x );
+	mevent.mbutton.y         = static_cast< uint16 >( mb.y );
 
 	switch ( mb.button )
@@ -126,7 +128,8 @@
 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 );
+	mevent.type             = EV_MOUSE_WHEEL;
+	mevent.mwheel.window_id = mm.windowID;
+	mevent.mwheel.x         = static_cast< sint32 >( mm.x );
+	mevent.mwheel.y         = static_cast< sint32 >( mm.y );
 	return true;
 }
@@ -134,10 +137,11 @@
 static bool sdl_mouse_motion_to_io_event( const SDL_MouseMotionEvent& mm, io_event& mevent )
 {
-	mevent.type          = EV_MOUSE_MOVE;
-	mevent.mmove.pressed = (mm.state != SDL_RELEASED);
-	mevent.mmove.x       = static_cast< uint16 >( mm.x );
-	mevent.mmove.y       = static_cast< uint16 >( mm.y );
-	mevent.mmove.rx      = static_cast< sint16 >( mm.xrel );
-	mevent.mmove.ry      = static_cast< sint16 >( mm.yrel );
+	mevent.type            = EV_MOUSE_MOVE;
+	mevent.mmove.window_id = mm.windowID;
+	mevent.mmove.pressed   = (mm.state != SDL_RELEASED);
+	mevent.mmove.x         = static_cast< uint16 >( mm.x );
+	mevent.mmove.y         = static_cast< uint16 >( mm.y );
+	mevent.mmove.rx        = static_cast< sint16 >( mm.xrel );
+	mevent.mmove.ry        = static_cast< sint16 >( mm.yrel );
 	return true;
 }
@@ -222,4 +226,6 @@
 	case SDL_VIDEOEXPOSE     : return false;
 */
+	case SDL_WINDOWEVENT_ENTER: ioevent.type = EV_SYSTEM; ioevent.system.param1 = 1; ioevent.system.param1 = e.window.windowID; return true;
+	case SDL_WINDOWEVENT_LEAVE: ioevent.type = EV_SYSTEM; ioevent.system.param1 = 0; ioevent.system.param1 = e.window.windowID; return true;
 	case SDL_SYSWMEVENT      : ioevent.type = EV_SYSTEM; return true;
 	case SDL_QUIT            : ioevent.type = EV_QUIT;   return true;
Index: trunk/src/sdl/sdl_window.cc
===================================================================
--- trunk/src/sdl/sdl_window.cc	(revision 504)
+++ trunk/src/sdl/sdl_window.cc	(revision 505)
@@ -133,2 +133,13 @@
 	SDL_GL_SetSwapInterval( enabled ? 1 : 0 );
 }
+
+void nv::sdl::window::make_current()
+{
+	SDL_GLContext native = static_cast<SDL_GLContext>( m_context->get_native_handle() );
+	SDL_GL_MakeCurrent( static_cast<SDL_Window*>( m_handle ), native );
+}
+
+nv::uint32 nv::sdl::window::window_id()
+{
+	return SDL_GetWindowID( static_cast<SDL_Window*>( m_handle ) );
+}
Index: trunk/src/sdl/sdl_window_manager.cc
===================================================================
--- trunk/src/sdl/sdl_window_manager.cc	(revision 504)
+++ trunk/src/sdl/sdl_window_manager.cc	(revision 505)
@@ -17,4 +17,5 @@
 sdl::window_manager::window_manager()
 {
+	primal_window = nullptr;
 	nv::load_sdl_library();
 
@@ -29,5 +30,7 @@
 {
 	if ( ! SDL_WasInit( SDL_INIT_VIDEO ) ) SDL_InitSubSystem( SDL_INIT_VIDEO );
-	return new sdl::window( dev, width, height, fullscreen );
+	sdl::window* result = new sdl::window( dev, width, height, fullscreen );
+	primal_window = result->get_handle();
+	return result;
 }
 
@@ -35,5 +38,12 @@
 {
 	if ( ! SDL_WasInit( SDL_INIT_VIDEO ) ) SDL_InitSubSystem( SDL_INIT_VIDEO );
-	return SDL_CreateWindowFrom( sys_w_handle );
+	if ( primal_window )
+	{
+		char buffer[128];
+		sprintf( buffer, "%p", primal_window );
+		NV_ASSERT( SDL_SetHint( "SDL_VIDEO_WINDOW_SHARE_PIXEL_FORMAT", buffer ) == SDL_TRUE );
+	}
+	primal_window = SDL_CreateWindowFrom( sys_w_handle );
+	return primal_window;
 }
 
Index: trunk/src/wx/wx_canvas.cc
===================================================================
--- trunk/src/wx/wx_canvas.cc	(revision 504)
+++ trunk/src/wx/wx_canvas.cc	(revision 505)
@@ -13,5 +13,5 @@
 wxEND_EVENT_TABLE()
 
-nv::wx_gl_canvas::wx_gl_canvas( wxWindow *parent )
+nv::wx_gl_canvas::wx_gl_canvas( wxWindow *parent, input* in )
 	: wxWindow( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
 	wxFULL_REPAINT_ON_RESIZE )
@@ -19,13 +19,32 @@
 	nv::load_gl_no_context();
 	wxClientDC dc( this );
+	m_render  = true;
+	m_wm      = new nv::sdl::window_manager;
+	m_device  = new nv::gl_device();
+	if ( !in ) in = new nv::sdl::input;
+	m_window = new nv::gl_window( m_device, m_wm, in, GetHWND(), dc.GetHDC() );
+	m_context = m_window->get_context();
+	m_main    = true;
+}
+
+nv::wx_gl_canvas::wx_gl_canvas( wxWindow *parent, wx_gl_canvas *sibling, input* in )
+	: wxWindow( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
+		wxFULL_REPAINT_ON_RESIZE )
+{
+	wxClientDC dc( this );
 	m_render = true;
-	m_wm = new nv::sdl::window_manager;
+	m_wm = sibling->m_wm;
 	m_device = new nv::gl_device();
-	m_window = new nv::gl_window( m_device, m_wm, new nv::sdl::input(), GetHWND(), dc.GetHDC() );
+	if ( !in ) in = new nv::sdl::input;
+	m_window = new nv::gl_window( m_device, m_wm, in, GetHWND(), dc.GetHDC() );
 	m_context = m_window->get_context();
+	make_current();
+	m_main = false;
+
 }
 
 nv::wx_gl_canvas::~wx_gl_canvas()
 {
+	make_current();
 	delete m_window;
 	delete m_device;
@@ -34,4 +53,5 @@
 void nv::wx_gl_canvas::on_paint( wxPaintEvent& )
 {
+	make_current();
 	const wxSize client_size = GetClientSize();
 	m_context->set_viewport( nv::ivec4( nv::ivec2(), client_size.x, client_size.y ) );
@@ -53,10 +73,16 @@
 void nv::wx_gl_canvas::on_idle( wxIdleEvent& evt )
 {
-	nv::sleep( 10 );
+	nv::sleep( 1 );
 	if ( m_render )
 	{
+		make_current();
 		on_update();
 		evt.RequestMore(); // render continuously, not only once on idle
 	}
+}
+
+void nv::wx_gl_canvas::make_current()
+{
+	m_window->make_current();
 }
 
