source: trunk/src/gl/gl_window.cc @ 304

Last change on this file since 304 was 304, checked in by epyon, 11 years ago
  • mouse wheel support for both SDL 1.2 and 2.0
  • optional unmerged MD3 import
  • selective delete mesh form mesh_creator
  • minor fixes
File size: 12.1 KB
Line 
1// Copyright (C) 2012-2013 Kornel Kisielewicz
2// This file is part of NV Libraries.
3// For conditions of distribution and use, see copyright notice in nv.hh
4
5#include "nv/gl/gl_window.hh"
6
7#include "nv/logging.hh"
8#include "nv/lib/gl.hh"
9#include "nv/lib/sdl.hh"
10
11using namespace nv;
12
13static bool sdl_key_event_to_io_event( const SDL_KeyboardEvent& ke, io_event& kevent )
14{
15        kevent.type        = EV_KEY;
16        kevent.key.pressed = ( ke.state != SDL_RELEASED );
17        kevent.key.ascii   = 0;
18        kevent.key.code    = KEY_NONE;
19
20#if NV_SDL_VERSION == NV_SDL_20
21        uint32 ucode = ke.keysym.sym;
22#else
23        uint32 ucode = ke.keysym.unicode;
24#endif
25
26        // if result is a typable char place it into the structure
27        if (ucode >= 32 && ucode < 128 )
28        {
29                kevent.key.ascii = static_cast<char8>( ucode );
30#if NV_SDL_VERSION == NV_SDL_20
31                if (ucode >= 'a' && ucode <= 'z')
32                {
33                        int shifted = !!(ke.keysym.mod & KMOD_SHIFT);
34                        int capslock = !!(ke.keysym.mod & KMOD_CAPS);
35                        if ((shifted ^ capslock) != 0) {
36                                kevent.key.ascii = (char8)SDL_toupper(ucode);
37                        }
38                }
39#endif
40        }
41
42        // Get the Key value from the SDL Keyboard event
43        int result = ke.keysym.sym;
44
45        // Check the control and shift states
46        kevent.key.alt     = (ke.keysym.mod & KMOD_ALT ) != 0;
47        kevent.key.control = (ke.keysym.mod & KMOD_CTRL ) != 0;
48        kevent.key.shift   = (ke.keysym.mod & KMOD_SHIFT ) != 0;
49
50        // if result is a typable char from the directly transformable ranges
51        if ( ( result >= KEY_A && result <= KEY_Z ) ||
52                ( result >= KEY_0 && result <= KEY_9 ) ||
53                result == ' ' )
54        {
55                kevent.key.code = static_cast<key_code>(result);
56        }
57
58        // if result is a typable char from the a..z range
59        if ( result >= KEY_A + 32 && result <= KEY_Z + 32 )
60        {
61                kevent.key.code = static_cast<key_code>(result - 32);
62        }
63
64        if ( result >= SDLK_F1 && result <= SDLK_F12 )
65        {
66                kevent.key.code = static_cast<key_code>(result - SDLK_F1 + KEY_F1 );
67        }
68
69        // other recognized codes
70        switch ( result )
71        {
72        case SDLK_BACKSPACE    : kevent.key.code = KEY_BACK; break;
73        case SDLK_TAB          : kevent.key.code = KEY_TAB; break;
74        case SDLK_RETURN       : kevent.key.code = KEY_ENTER; break;
75        case SDLK_PAGEUP       : kevent.key.code = KEY_PGUP; break;
76        case SDLK_PAGEDOWN     : kevent.key.code = KEY_PGDOWN; break;
77        case SDLK_END          : kevent.key.code = KEY_END; break;
78        case SDLK_HOME         : kevent.key.code = KEY_HOME; break;
79        case SDLK_LEFT         : kevent.key.code = KEY_LEFT; break;
80        case SDLK_UP           : kevent.key.code = KEY_UP; break;
81        case SDLK_RIGHT        : kevent.key.code = KEY_RIGHT; break;
82        case SDLK_DOWN         : kevent.key.code = KEY_DOWN; break;
83        case SDLK_DELETE       : kevent.key.code = KEY_DELETE; break;
84        case SDLK_INSERT       : kevent.key.code = KEY_INSERT; break;
85        //case SDLK_KP5          : kevent.key.code = KEY_CENTER; break;
86        case SDLK_ESCAPE       : kevent.key.code = KEY_ESCAPE; break;
87        case SDLK_QUOTE        : kevent.key.code = KEY_QUOTE; break;
88        case SDLK_COMMA        : kevent.key.code = KEY_COMMA; break;
89        case SDLK_MINUS        : kevent.key.code = KEY_MINUS; break;
90        case SDLK_PERIOD       : kevent.key.code = KEY_PERIOD; break;
91        case SDLK_SLASH        : kevent.key.code = KEY_SLASH; break;
92        case SDLK_SEMICOLON    : kevent.key.code = KEY_SCOLON; break;
93        case SDLK_LEFTBRACKET  : kevent.key.code = KEY_LBRACKET; break;
94        case SDLK_BACKSLASH    : kevent.key.code = KEY_BSLASH; break;
95        case SDLK_RIGHTBRACKET : kevent.key.code = KEY_RBRACKET; break;
96        case SDLK_BACKQUOTE    : kevent.key.code = KEY_BQUOTE; break;
97        default : break;
98        }
99
100        // If key was understood by nv, then it's valid, otherwise ignored
101        return kevent.key.ascii != 0 || kevent.key.code != 0;
102}
103
104static bool sdl_mouse_button_to_io_event( const SDL_MouseButtonEvent& mb, io_event& mevent )
105{
106        mevent.type            = EV_MOUSE_BUTTON;
107        mevent.mbutton.button  = MOUSE_NONE;
108        mevent.mbutton.pressed = (mb.state != SDL_RELEASED);
109        mevent.mbutton.x       = static_cast< uint16 >( mb.x );
110        mevent.mbutton.y       = static_cast< uint16 >( mb.y );
111
112        switch ( mb.button )
113        {
114        case SDL_BUTTON_LEFT      : mevent.mbutton.button = MOUSE_LEFT; break;
115        case SDL_BUTTON_MIDDLE    : mevent.mbutton.button = MOUSE_MIDDLE; break;
116        case SDL_BUTTON_RIGHT     : mevent.mbutton.button = MOUSE_RIGHT; break;
117#if NV_SDL_VERSION == NV_SDL_12
118        case SDL_BUTTON_WHEELUP   :
119                mevent.type           = EV_MOUSE_WHEEL;
120                mevent.mwheel.x       = 0;
121                mevent.mwheel.y       = 3;
122                return true;
123        case SDL_BUTTON_WHEELDOWN :
124                mevent.type           = EV_MOUSE_WHEEL;
125                mevent.mwheel.x       = 0;
126                mevent.mwheel.y       = -3;
127                return true;
128#endif
129        default : break;
130        }
131
132        return mevent.mbutton.button != MOUSE_NONE;
133}
134
135#if NV_SDL_VERSION == NV_SDL_20
136static bool sdl_mouse_wheel_to_io_event( const SDL_MouseWheelEvent& mm, io_event& mevent )
137{
138        mevent.type          = EV_MOUSE_WHEEL;
139        mevent.mwheel.x      = static_cast< sint32 >( mm.x );
140        mevent.mwheel.y      = static_cast< sint32 >( mm.y );
141        return true;
142}
143#endif
144
145static bool sdl_mouse_motion_to_io_event( const SDL_MouseMotionEvent& mm, io_event& mevent )
146{
147        mevent.type          = EV_MOUSE_MOVE;
148        mevent.mmove.pressed = (mm.state != SDL_RELEASED);
149        mevent.mmove.x       = static_cast< uint16 >( mm.x );
150        mevent.mmove.y       = static_cast< uint16 >( mm.y );
151        mevent.mmove.rx      = static_cast< sint16 >( mm.xrel );
152        mevent.mmove.ry      = static_cast< sint16 >( mm.yrel );
153        return true;
154}
155
156static bool sdl_joy_button_event_to_io_event( const SDL_JoyButtonEvent& jb, io_event& jevent )
157{
158        jevent.type            = EV_JOY_BUTTON;
159        jevent.jbutton.id      = jb.which;
160        jevent.jbutton.button  = jb.button;
161        jevent.jbutton.pressed = (jb.type == SDL_PRESSED);
162        return true;
163}
164
165static bool sdl_joy_axis_event_to_io_event( const SDL_JoyAxisEvent& ja, io_event& jevent )
166{
167        jevent.type          = EV_JOY_AXIS;
168        jevent.jaxis.id      = ja.which;
169        jevent.jaxis.axis    = ja.axis;
170        jevent.jaxis.value   = ja.value;
171        return true;
172}
173
174static bool sdl_joy_hat_event_to_io_event( const SDL_JoyHatEvent& jh, io_event& jevent )
175{
176        jevent.type          = EV_JOY_HAT;
177        jevent.jhat.id       = jh.which;
178        jevent.jhat.hat      = jh.hat;
179        jevent.jhat.value    = jh.value;
180        return true;
181}
182
183static bool sdl_joy_ball_event_to_io_event( const SDL_JoyBallEvent& jb, io_event& jevent )
184{
185        jevent.type          = EV_JOY_HAT;
186        jevent.jball.id      = jb.which;
187        jevent.jball.ball    = jb.ball;
188        jevent.jball.rx      = jb.xrel;
189        jevent.jball.ry      = jb.yrel;
190        return true;
191}
192
193static bool sdl_event_to_io_event( const SDL_Event& e, io_event& ioevent )
194{
195        switch ( e.type )
196        {
197        case SDL_KEYDOWN         : return sdl_key_event_to_io_event( e.key, ioevent );
198        case SDL_KEYUP           : return sdl_key_event_to_io_event( e.key, ioevent );
199        case SDL_MOUSEMOTION     : return sdl_mouse_motion_to_io_event( e.motion, ioevent );
200        case SDL_MOUSEBUTTONDOWN : return sdl_mouse_button_to_io_event( e.button, ioevent );
201        case SDL_MOUSEBUTTONUP   : return sdl_mouse_button_to_io_event( e.button, ioevent );
202#if NV_SDL_VERSION == NV_SDL_20
203        case SDL_MOUSEWHEEL      : return sdl_mouse_wheel_to_io_event( e.wheel, ioevent );
204#endif
205/* // SDL 2.0 incompatible
206        case SDL_ACTIVEEVENT     :
207                ioevent.type = EV_ACTIVE;
208                ioevent.active.gain = (e.active.gain != 0);
209                return e.active.state == SDL_APPINPUTFOCUS;
210        case SDL_VIDEORESIZE     :
211                ioevent.type     = EV_RESIZE;
212                ioevent.resize.x = e.resize.w;
213                ioevent.resize.y = e.resize.h;
214                return true;
215        case SDL_NOEVENT         : return false;
216        case SDL_VIDEOEXPOSE     : return false;
217*/
218        case SDL_SYSWMEVENT      : ioevent.type = EV_SYSTEM; return true;
219        case SDL_QUIT            : ioevent.type = EV_QUIT;   return true;
220        case SDL_JOYAXISMOTION   : return sdl_joy_axis_event_to_io_event( e.jaxis, ioevent );
221        case SDL_JOYBALLMOTION   : return sdl_joy_ball_event_to_io_event( e.jball, ioevent );
222        case SDL_JOYHATMOTION    : return sdl_joy_hat_event_to_io_event( e.jhat, ioevent );
223        case SDL_JOYBUTTONDOWN   : return sdl_joy_button_event_to_io_event( e.jbutton, ioevent );
224        case SDL_JOYBUTTONUP     : return sdl_joy_button_event_to_io_event( e.jbutton, ioevent );
225        default : return false;
226        }
227}
228
229
230gl_window::gl_window( device* dev, uint16 width, uint16 height, bool fullscreen )
231        : m_device( dev ), m_width( width ), m_height( height ), m_title("NV Engine"), m_handle( nullptr ), m_hwnd( 0 ), m_adopted( false )
232{
233        //      bpp = m_info->vfmt->BitsPerPixel;
234
235        SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
236        SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
237        SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
238        SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
239        SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
240
241        //      SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
242        //      SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, 4 );
243
244#if NV_SDL_VERSION == NV_SDL_20
245        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
246        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
247        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
248        SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
249#endif
250
251
252#if NV_SDL_VERSION == NV_SDL_12
253        uint32 flags = SDL_OPENGL;
254        if (fullscreen) flags |= SDL_FULLSCREEN;
255        m_handle = SDL_SetVideoMode( width, height, 32, flags );
256#elif NV_SDL_VERSION == NV_SDL_20
257        uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
258        if (fullscreen) flags |= SDL_WINDOW_FULLSCREEN;
259        m_handle = SDL_CreateWindow("Nova Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
260                width, height, flags );
261#endif
262        if ( m_handle == 0 )
263        {
264                NV_LOG( LOG_CRITICAL, "Video mode set failed: " << SDL_GetError( ) );
265                return; // TODO: Error report
266        }
267
268//      NV_LOG( LOG_INFO, "Joystick count : " << SDL_NumJoysticks() );
269//      SDL_Joystick* j = SDL_JoystickOpen(0);
270//      if (j)
271//      {
272//              NV_LOG( LOG_INFO, "Joystick Name: " << SDL_JoystickNameForIndex(0) );
273//              NV_LOG( LOG_INFO, "Joystick Number of Axes: " << SDL_JoystickNumAxes(j));
274//              NV_LOG( LOG_INFO, "Joystick Number of Buttons: " << SDL_JoystickNumButtons(j));
275//              NV_LOG( LOG_INFO, "Joystick Number of Balls: " << SDL_JoystickNumBalls(j));
276//      }
277
278
279        m_context = new sdl_gl_context( m_device, m_handle );
280        m_context->set_viewport( nv::ivec4( 0, 0, m_width, m_height ) );
281}
282
283uint16 gl_window::get_width() const
284{
285        return m_width;
286}
287
288uint16 gl_window::get_height() const
289{
290        return m_height;
291}
292
293string gl_window::get_title() const
294{
295        return m_title;
296}
297
298void gl_window::set_title( const string& title )
299{
300        if ( m_adopted ) return;
301#if NV_SDL_VERSION == NV_SDL_20
302        SDL_SetWindowTitle( static_cast<SDL_Window*>( m_handle ), title.c_str() );
303#else
304        SDL_WM_SetCaption( title.c_str(), title.c_str() );
305#endif
306        m_title = title;
307}
308
309bool gl_window::is_event_pending()
310{
311        return SDL_PollEvent( nullptr ) != 0;
312}
313
314bool gl_window::poll_event( io_event& event )
315{
316        SDL_Event sdl_event;
317        if ( SDL_PollEvent( &sdl_event ) == 0 ) return false;
318        return sdl_event_to_io_event( sdl_event, event );
319}
320
321void gl_window::swap_buffers()
322{
323        if ( m_adopted )
324        {
325#if NV_PLATFORM == NV_WINDOWS
326                ::SwapBuffers( (HDC)m_hwnd );
327#else
328        NV_ASSERT( false, "Native GL context only working with SDL 2.0!" );
329#endif
330
331        }
332#if NV_SDL_VERSION == NV_SDL_20
333        SDL_GL_SwapWindow( static_cast<SDL_Window*>( m_handle ) );
334#else
335        SDL_GL_SwapBuffers();
336#endif
337}
338
339gl_window::~gl_window()
340{
341        delete m_context;
342#if NV_SDL_VERSION == NV_SDL_20
343        if ( !m_adopted ) SDL_DestroyWindow( static_cast<SDL_Window*>( m_handle ) );
344#endif
345}
346
347nv::gl_window::gl_window( device* dev, void* handle, void* dc )
348        : m_device( dev ), m_width( 0 ), m_height( 0 ), m_title(), m_handle( nullptr ), m_adopted( true )
349{
350#if NV_PLATFORM == NV_WINDOWS
351#if NV_SDL_VERSION == NV_SDL_20
352        nv::load_gl_no_context();
353        m_context = new native_gl_context( m_device, dc );
354        SDL_Window* window = SDL_CreateWindowFrom( handle );
355        // Doesn't work :/
356//      RECT rect;
357//      GetClientRect( (HWND)handle, &rect );
358//      m_width   = (uint16)rect.right;
359//      m_height  = (uint16)rect.bottom;
360        m_handle  = window;
361        m_hwnd    = ::GetDC( (HWND)handle );
362        m_context->set_viewport( nv::ivec4( 0, 0, m_width, m_height ) );
363#else
364        NV_ASSERT( false, "Native GL context only working with SDL 2.0!" );
365#endif
366#else
367        NV_ASSERT( false, "Native GL context adoption not implemented for this platform!" );
368#endif
369}
Note: See TracBrowser for help on using the repository browser.