Index: trunk/src/sdl/sdl_input.cc
===================================================================
--- trunk/src/sdl/sdl_input.cc	(revision 336)
+++ trunk/src/sdl/sdl_input.cc	(revision 336)
@@ -0,0 +1,224 @@
+// Copyright (C) 2014 ChaosForge Ltd
+// http://chaosforge.org/
+//
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+#include "nv/sdl/sdl_input.hh"
+
+#include "nv/lib/sdl.hh"
+#include "nv/core/logging.hh"
+
+using namespace nv;
+
+nv::sdl::input::input()
+{
+	if ( ! SDL_WasInit( SDL_INIT_JOYSTICK ) ) SDL_InitSubSystem( SDL_INIT_JOYSTICK );
+}
+
+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;
+
+	uint32 ucode = (uint32)ke.keysym.sym;
+
+	// if result is a typable char place it into the structure
+	if (ucode >= 32 && ucode < 128 )
+	{
+		kevent.key.ascii = static_cast<char8>( ucode );
+		if (ucode >= 'a' && ucode <= 'z')
+		{
+			int shifted = !!(ke.keysym.mod & KMOD_SHIFT);
+			int capslock = !!(ke.keysym.mod & KMOD_CAPS);
+			if ((shifted ^ capslock) != 0) {
+				kevent.key.ascii = (char8)SDL_toupper((int)ucode);
+			}
+		}
+	}
+
+	// Get the Key value from the SDL Keyboard event
+	int result = ke.keysym.sym;
+
+	// Check the control and shift states
+	kevent.key.alt     = (ke.keysym.mod & KMOD_ALT ) != 0;
+	kevent.key.control = (ke.keysym.mod & KMOD_CTRL ) != 0;
+	kevent.key.shift   = (ke.keysym.mod & KMOD_SHIFT ) != 0;
+
+	// if result is a typable char from the directly transformable ranges
+	if ( ( result >= KEY_A && result <= KEY_Z ) || 
+		( result >= KEY_0 && result <= KEY_9 ) ||
+		result == ' ' )
+	{
+		kevent.key.code = static_cast<key_code>(result);
+	}
+
+	// if result is a typable char from the a..z range
+	if ( result >= KEY_A + 32 && result <= KEY_Z + 32 )
+	{
+		kevent.key.code = static_cast<key_code>(result - 32);
+	}
+
+	if ( result >= SDLK_F1 && result <= SDLK_F12 )
+	{
+		kevent.key.code = static_cast<key_code>(result - SDLK_F1 + KEY_F1 );
+	}
+
+	// other recognized codes
+	switch ( result ) 
+	{
+	case SDLK_BACKSPACE    : kevent.key.code = KEY_BACK; break;
+	case SDLK_TAB          : kevent.key.code = KEY_TAB; break;
+	case SDLK_RETURN       : kevent.key.code = KEY_ENTER; break;
+	case SDLK_PAGEUP       : kevent.key.code = KEY_PGUP; break;
+	case SDLK_PAGEDOWN     : kevent.key.code = KEY_PGDOWN; break;
+	case SDLK_END          : kevent.key.code = KEY_END; break;
+	case SDLK_HOME         : kevent.key.code = KEY_HOME; break;
+	case SDLK_LEFT         : kevent.key.code = KEY_LEFT; break;
+	case SDLK_UP           : kevent.key.code = KEY_UP; break;
+	case SDLK_RIGHT        : kevent.key.code = KEY_RIGHT; break;
+	case SDLK_DOWN         : kevent.key.code = KEY_DOWN; break;
+	case SDLK_DELETE       : kevent.key.code = KEY_DELETE; break;
+	case SDLK_INSERT       : kevent.key.code = KEY_INSERT; break;
+	//case SDLK_KP5          : kevent.key.code = KEY_CENTER; break;
+	case SDLK_ESCAPE       : kevent.key.code = KEY_ESCAPE; break;
+	case SDLK_QUOTE        : kevent.key.code = KEY_QUOTE; break;
+	case SDLK_COMMA        : kevent.key.code = KEY_COMMA; break;
+	case SDLK_MINUS        : kevent.key.code = KEY_MINUS; break;
+	case SDLK_PERIOD       : kevent.key.code = KEY_PERIOD; break;
+	case SDLK_SLASH        : kevent.key.code = KEY_SLASH; break;
+	case SDLK_SEMICOLON    : kevent.key.code = KEY_SCOLON; break;
+	case SDLK_LEFTBRACKET  : kevent.key.code = KEY_LBRACKET; break;
+	case SDLK_BACKSLASH    : kevent.key.code = KEY_BSLASH; break;
+	case SDLK_RIGHTBRACKET : kevent.key.code = KEY_RBRACKET; break;
+	case SDLK_BACKQUOTE    : kevent.key.code = KEY_BQUOTE; break;
+	default : break;
+	}
+
+	// If key was understood by nv, then it's valid, otherwise ignored
+	return kevent.key.ascii != 0 || kevent.key.code != 0;
+}
+
+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 );
+
+	switch ( mb.button )
+	{
+	case SDL_BUTTON_LEFT      : mevent.mbutton.button = MOUSE_LEFT; break;
+	case SDL_BUTTON_MIDDLE    : mevent.mbutton.button = MOUSE_MIDDLE; break;
+	case SDL_BUTTON_RIGHT     : mevent.mbutton.button = MOUSE_RIGHT; break;
+	default : break;
+	}
+
+	return mevent.mbutton.button != MOUSE_NONE;
+}
+
+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;
+}
+
+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 );
+	return true;
+}
+
+static bool sdl_joy_button_event_to_io_event( const SDL_JoyButtonEvent& jb, io_event& jevent )
+{
+	jevent.type            = EV_JOY_BUTTON;
+	jevent.jbutton.id      = jb.which;
+	jevent.jbutton.button  = jb.button;
+	jevent.jbutton.pressed = (jb.type == SDL_PRESSED);
+	return true;
+}
+
+static bool sdl_joy_axis_event_to_io_event( const SDL_JoyAxisEvent& ja, io_event& jevent )
+{
+	jevent.type          = EV_JOY_AXIS;
+	jevent.jaxis.id      = ja.which;
+	jevent.jaxis.axis    = ja.axis;
+	jevent.jaxis.value   = ja.value;
+	return true;
+}
+
+static bool sdl_joy_hat_event_to_io_event( const SDL_JoyHatEvent& jh, io_event& jevent )
+{
+	jevent.type          = EV_JOY_HAT;
+	jevent.jhat.id       = jh.which;
+	jevent.jhat.hat      = jh.hat;
+	jevent.jhat.value    = jh.value;
+	return true;
+}
+
+static bool sdl_joy_ball_event_to_io_event( const SDL_JoyBallEvent& jb, io_event& jevent )
+{
+	jevent.type          = EV_JOY_HAT;
+	jevent.jball.id      = jb.which;
+	jevent.jball.ball    = jb.ball;
+	jevent.jball.rx      = jb.xrel;
+	jevent.jball.ry      = jb.yrel;
+	return true;
+}
+
+static bool sdl_event_to_io_event( const SDL_Event& e, io_event& ioevent )
+{
+	switch ( e.type )
+	{
+	case SDL_KEYDOWN         : return sdl_key_event_to_io_event( e.key, ioevent );
+	case SDL_KEYUP           : return sdl_key_event_to_io_event( e.key, ioevent );
+	case SDL_MOUSEMOTION     : return sdl_mouse_motion_to_io_event( e.motion, ioevent );
+	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 );
+	case SDL_MOUSEWHEEL      : return sdl_mouse_wheel_to_io_event( e.wheel, ioevent );
+/* // SDL 2.0 incompatible 
+	case SDL_ACTIVEEVENT     : 
+		ioevent.type = EV_ACTIVE; 
+		ioevent.active.gain = (e.active.gain != 0); 
+		return e.active.state == SDL_APPINPUTFOCUS;
+	case SDL_VIDEORESIZE     : 
+		ioevent.type     = EV_RESIZE; 
+		ioevent.resize.x = e.resize.w;
+		ioevent.resize.y = e.resize.h;
+		return true;
+	case SDL_NOEVENT         : return false;
+	case SDL_VIDEOEXPOSE     : return false;
+*/
+	case SDL_SYSWMEVENT      : ioevent.type = EV_SYSTEM; return true;
+	case SDL_QUIT            : ioevent.type = EV_QUIT;   return true;
+	case SDL_JOYAXISMOTION   : return sdl_joy_axis_event_to_io_event( e.jaxis, ioevent ); 
+	case SDL_JOYBALLMOTION   : return sdl_joy_ball_event_to_io_event( e.jball, ioevent ); 
+	case SDL_JOYHATMOTION    : return sdl_joy_hat_event_to_io_event( e.jhat, ioevent ); 
+	case SDL_JOYBUTTONDOWN   : return sdl_joy_button_event_to_io_event( e.jbutton, ioevent );
+	case SDL_JOYBUTTONUP     : return sdl_joy_button_event_to_io_event( e.jbutton, ioevent );
+	default : return false;
+	}
+}
+
+bool sdl::input::is_event_pending()
+{
+	return SDL_PollEvent( nullptr ) != 0;
+}
+
+bool sdl::input::poll_event( io_event& event )
+{
+	SDL_Event sdl_event;
+	if ( SDL_PollEvent( &sdl_event ) == 0 ) return false;
+	return sdl_event_to_io_event( sdl_event, event );
+}
+
Index: trunk/src/sdl/sdl_window.cc
===================================================================
--- trunk/src/sdl/sdl_window.cc	(revision 336)
+++ trunk/src/sdl/sdl_window.cc	(revision 336)
@@ -0,0 +1,99 @@
+// Copyright (C) 2014 ChaosForge Ltd
+// This file is part of Nova Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+#include "nv/sdl/sdl_window.hh"
+
+#include "nv/core/logging.hh"
+#include "nv/lib/gl.hh"
+#include "nv/lib/sdl.hh"
+#include "nv/sdl/sdl_input.hh"
+
+using namespace nv;
+
+sdl::window::window( device* dev, uint16 width, uint16 height, bool fullscreen )
+	: m_device( dev ), m_width( width ), m_height( height ), m_title("Nova Engine"), m_handle( nullptr )
+{
+	m_input = new sdl::input();
+	//	bpp = m_info->vfmt->BitsPerPixel;
+
+	SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
+	SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
+	SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
+	SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
+	SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+
+	//	SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
+	//	SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, 4 );
+
+	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
+	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
+
+	uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
+	if (fullscreen) flags |= SDL_WINDOW_FULLSCREEN;
+	m_title  = "Nova Engine";
+	m_handle = SDL_CreateWindow( m_title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+		width, height, flags );
+	if ( m_handle == 0 )
+	{
+		NV_LOG( LOG_CRITICAL, "Video mode set failed: " << SDL_GetError( ) );
+		return; // TODO: Error report
+	}
+
+	// 	NV_LOG( LOG_INFO, "Joystick count : " << SDL_NumJoysticks() );
+	// 	SDL_Joystick* j = SDL_JoystickOpen(0);
+	// 	if (j)
+	// 	{
+	// 		NV_LOG( LOG_INFO, "Joystick Name: " << SDL_JoystickNameForIndex(0) );
+	// 		NV_LOG( LOG_INFO, "Joystick Number of Axes: " << SDL_JoystickNumAxes(j));
+	// 		NV_LOG( LOG_INFO, "Joystick Number of Buttons: " << SDL_JoystickNumButtons(j));
+	// 		NV_LOG( LOG_INFO, "Joystick Number of Balls: " << SDL_JoystickNumBalls(j));
+	// 	}
+
+	void* ctx_handle = SDL_GL_CreateContext( static_cast<SDL_Window*>( m_handle ) );
+
+	if ( ctx_handle == 0 )
+	{
+		NV_LOG( LOG_CRITICAL, "GL Context creation failed: " << SDL_GetError( ) );
+		return; // TODO: Error report
+	}
+
+	nv::load_gl_library();
+	NV_LOG( LOG_INFO, "OpenGL Vendor       : " << glGetString(GL_VENDOR) );
+	NV_LOG( LOG_INFO, "OpenGL Renderer     : " << glGetString(GL_RENDERER) );
+	NV_LOG( LOG_INFO, "OpenGL Version      : " << glGetString(GL_VERSION) );
+	NV_LOG( LOG_INFO, "OpenGL GLSL Version : " << glGetString(GL_SHADING_LANGUAGE_VERSION) );
+	// SDL_GL_SetSwapInterval(1);
+
+	// TODO: do we really need this?
+	glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+	m_context = new gl_context( m_device, ctx_handle );
+	m_context->set_viewport( nv::ivec4( 0, 0, m_width, m_height ) );
+}
+
+void sdl::window::set_title( const string& title )
+{
+	SDL_SetWindowTitle( static_cast<SDL_Window*>( m_handle ), title.c_str() );
+	m_title = title;
+}
+
+void sdl::window::swap_buffers()
+{
+	SDL_GL_SwapWindow( static_cast<SDL_Window*>( m_handle ) );
+}
+
+sdl::window::~window()
+{
+	delete m_input;
+	if ( m_context )
+	{
+		SDL_GLContext native = static_cast<SDL_GLContext>( m_context->get_native_handle() );
+		delete m_context;
+		SDL_GL_DeleteContext( native );
+	}
+	m_context = nullptr;
+	SDL_DestroyWindow( static_cast<SDL_Window*>( m_handle ) );
+}
Index: trunk/src/sdl/sdl_window_manager.cc
===================================================================
--- trunk/src/sdl/sdl_window_manager.cc	(revision 336)
+++ trunk/src/sdl/sdl_window_manager.cc	(revision 336)
@@ -0,0 +1,52 @@
+// Copyright (C) 2014 ChaosForge Ltd
+// This file is part of Nova Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+#include "nv/sdl/sdl_window_manager.hh"
+
+#include "nv/sdl/sdl_window.hh"
+#include "nv/core/logging.hh"
+#include "nv/lib/sdl.hh"
+#include "nv/lib/sdl_image.hh"
+#include "nv/interface/image_data.hh"
+
+using namespace nv;
+
+sdl::window_manager::window_manager()
+{
+	nv::load_sdl_library();
+
+	if ( SDL_Init(0) < 0 )
+	{
+		NV_LOG( LOG_CRITICAL, "SDL initialization failed: " << SDL_GetError( ) );
+		return; // TODO: Error report
+	}
+}
+
+window* sdl::window_manager::create_window( device* dev, uint16 width, uint16 height, bool fullscreen )
+{
+	if ( ! SDL_WasInit( SDL_INIT_VIDEO ) ) SDL_InitSubSystem( SDL_INIT_VIDEO );
+	return new sdl::window( dev, width, height, fullscreen );
+}
+
+void* sdl::window_manager::adopt_window( void* sys_w_handle )
+{
+	if ( ! SDL_WasInit( SDL_INIT_VIDEO ) ) SDL_InitSubSystem( SDL_INIT_VIDEO );
+	return SDL_CreateWindowFrom( sys_w_handle );
+}
+
+void nv::sdl::window_manager::sleep( uint32 ms )
+{
+	SDL_Delay( ms );
+}
+
+nv::uint32 nv::sdl::window_manager::get_ticks()
+{
+	return SDL_GetTicks();
+}
+
+nv::sdl::window_manager::~window_manager()
+{
+	SDL_Quit();
+}
+
