GlfmWindow.cpp
Go to the documentation of this file.
1 #include "GlfmWindow.hpp"
2 #include <ivorium_config.hpp>
3 
4 #if IV_GLPLATFORM_GLFM
5 
7 
8 #include <glfm.h>
9 #include <utf8.h>
10 
11 namespace iv
12 {
13 
14 GlfmWindow::GlfmWindow( GLFMDisplay * display ) :
15  display( display ),
16  listener( nullptr ),
17  _lastFrameTime_s( 0 ),
18  _current_character( 0 ),
19  _gpu( false )
20 {
21  //----------
22  glfmSetDisplayConfig( display,
23  GLFMRenderingAPIOpenGLES3,
24  GLFMColorFormatRGBA8888,
25  GLFMDepthFormat16,
26  GLFMStencilFormatNone,
27  GLFMMultisampleNone );
28 
29  glfmSetUserData( display, this );
30  glfmSetMultitouchEnabled( display, true );
31 
32  //---- window
33  glfmSetSurfaceCreatedFunc( display, GlfmWindow::s_onSurfaceCreated );
34  glfmSetSurfaceDestroyedFunc( display, GlfmWindow::s_onSurfaceDestroyed );
35  glfmSetSurfaceResizedFunc( display, GlfmWindow::s_onSurfaceResized );
36  glfmSetSurfaceErrorFunc( display, GlfmWindow::s_SurfaceErrorFunc );
37  glfmSetMemoryWarningFunc( display, GlfmWindow::s_MemoryWarningFunc );
38  glfmSetAppFocusFunc( display, GlfmWindow::s_FocusFunc );
39  glfmSetMainLoopFunc( display, GlfmWindow::s_onFrame );
40 
41  //----- input
42  glfmSetTouchFunc( display, GlfmWindow::s_TouchFunc );
43  glfmSetKeyFunc( display, GlfmWindow::s_KeyFunc );
44  glfmSetEmscriptenKeyFunc( display, GlfmWindow::s_EmscriptenKeyFunc );
45  glfmSetCharFunc( display, GlfmWindow::s_CharFunc );
46 
47  PopulateEmscriptenKeyMap();
48 
49  //---------
50  this->_render_target.set_geometry( RenderTarget::Geometry( float2( 0, 0 ), 1.0 ) );
51 }
52 
54 {
55 }
56 
58 {
59  return this->_gpu;
60 }
61 
62 void GlfmWindow::set_listener( WindowListener * listener )
63 {
64  this->listener = listener;
65 }
66 
67 RenderTarget::Geometry GlfmWindow::geometry()
68 {
69  return RenderTarget::Geometry( float2( 100, 100 ), 1.0f );
70 }
71 
72 RenderTarget * GlfmWindow::render_target()
73 {
74  return &this->_render_target;
75 }
76 
77 //------------------------- window ---------------------------------------------------
78 void GlfmWindow::render()
79 {
80  // render
81  glGetError(); // clear errors
82  glClear( GL_COLOR_BUFFER_BIT );
83 
84  this->_render_target.frame_setup();
85  this->listener->draw();
86  this->_render_target.frame_close();
87 }
88 
89 #if defined( GLFM_PLATFORM_ANDROID )
90 static double _glfmTimeSeconds(struct timespec t) {
91  return t.tv_sec + (double)t.tv_nsec / 1e9;
92 }
93 
94 static struct timespec _glfmTimeSubstract(struct timespec a, struct timespec b) {
95  struct timespec result;
96  if (b.tv_nsec > a.tv_nsec) {
97  result.tv_sec = a.tv_sec - b.tv_sec - 1;
98  result.tv_nsec = 1000000000 - b.tv_nsec + a.tv_nsec;
99  } else {
100  result.tv_sec = a.tv_sec - b.tv_sec;
101  result.tv_nsec = a.tv_nsec - b.tv_nsec;
102  }
103  return result;
104 }
105 
106 static struct timespec _glfmTimeNow() {
107  struct timespec t;
108  clock_gettime(CLOCK_MONOTONIC_RAW, &t);
109  return t;
110 }
111 #endif
112 
113 void GlfmWindow::onFrame( double frameTime_s )
114 {
115  #if defined( GLFM_PLATFORM_ANDROID )
116  auto start = _glfmTimeNow();
117  #endif
118 
119  // compute delta time
120  uint64_t delta_ms = uint64_t( ( frameTime_s - this->_lastFrameTime_s ) * 1000.0 );
121  this->_lastFrameTime_s = frameTime_s;
122 
123  // update
124  this->listener->update( delta_ms );
125 
126  // render
127  this->render();
128 
129  // extra update
130  #if defined( GLFM_PLATFORM_ANDROID )
131 
132  bool more_extras_needed = this->listener->extra_update(); // at least one extra update
133  while( more_extras_needed )
134  {
135  // check if we have time
136  auto elapsed_s = _glfmTimeSeconds( _glfmTimeSubstract( _glfmTimeNow(), start ) );
137  if( elapsed_s >= 1.0/60.0 )
138  break;
139 
140  // call second extra update
141  more_extras_needed = this->listener->extra_update();
142  }
143 
144  #else
145  #warning "Unimplemented proper extra updates for this platform."
146  this->listener->extra_update();
147  #endif
148 }
149 
150 void GlfmWindow::onSurfaceCreated( int width, int height )
151 {
152  TextOutput << "GlfmWindow: onSurfaceCreated( " << width << ", " << height << " )" << std::endl;
153  TextOutput << " GL_VENDOR : " << glGetString( GL_VENDOR ) << std::endl;
154  TextOutput << " GL_RENDERER : " << glGetString( GL_RENDERER ) << std::endl;
155  TextOutput << " GL_VERSION : " << glGetString( GL_VERSION ) << std::endl;
156  TextOutput << " GL_SHADING_LANGUAGE_VERSION : " << glGetString( GL_SHADING_LANGUAGE_VERSION ) << std::endl;
157 
158  this->_gpu = true;
159  this->setupGL();
160  this->onSurfaceResized( width, height );
161  this->listener->gpu( true, true );
162 }
163 
164 void GlfmWindow::onSurfaceDestroyed()
165 {
166  TextOutput << "GlfmWindow: onSurfaceDestroyed" << std::endl;
167  this->_gpu = false;
168  this->listener->gpu( false, true );
169 }
170 
171 void GlfmWindow::onSurfaceResized( int width, int height )
172 {
173  glViewport( 0, 0, width, height );
174 
175  double scale = glfmGetDisplayScale( this->display );
176  if( scale < 0.01 )
177  scale = 1.0;
178  this->_render_target.set_geometry( RenderTarget::Geometry( int2( width, height ), scale ) );
179 
180  this->listener->resized( this->_render_target.geometry() );
181 }
182 
183 void GlfmWindow::SurfaceErrorFunc( const char * message )
184 {
185  runtime_warning( SRC_INFO, "Glfm surface error:" );
186  runtime_warning( SRC_INFO, message );
187 }
188 
189 void GlfmWindow::MemoryWarningFunc()
190 {
191  runtime_warning( SRC_INFO, "Glfm memory warning." );
192 }
193 
194 void GlfmWindow::FocusFunc( bool focused )
195 {
196  if( !focused )
197  this->listener->focus_lost();
198 }
199 
200 //----------- input ---------------------------------------------------------------------
201 int2 GlfmWindow::input_position( Input::Key key, int device_id )
202 {
203  if( key != Input::Key::Touch )
204  return int2( 0, 0 );
205 
206  auto it = this->_touches.find( device_id );
207  if( it == this->_touches.end() )
208  return int2( 0, 0 );
209 
210  return it->second;
211 }
212 
213 float GlfmWindow::input_value( Input::Key key, int device_id )
214 {
215  return 0.0f;
216 }
217 
219 {
220  return this->_current_character;
221 }
222 
223 bool GlfmWindow::TouchFunc( int touch, GLFMTouchPhase phase, double x, double y )
224 {
225  this->_touches[ touch ] = int2( x, y );
226 
227  if( phase == GLFMTouchPhaseBegan )
228  {
229  Input i( Input::Type::Press, Input::Key::Touch, touch, true );
230  this->listener->input( &i );
231  }
232  else if( phase == GLFMTouchPhaseEnded )
233  {
234  Input i( Input::Type::Release, Input::Key::Touch, touch, true );
235  this->listener->input( &i );
236  }
237  else if( phase == GLFMTouchPhaseCancelled )
238  {
239  Input i( Input::Type::Release, Input::Key::Touch, touch, false );
240  this->listener->input( &i );
241  }
242 
243  return false;
244 }
245 
246 void GlfmWindow::PopulateEmscriptenKeyMap()
247 {
248  this->emscriptenKeyMap[ "Space" ] = Input::Key::Space;
249  this->emscriptenKeyMap[ "Comma" ] = Input::Key::Comma;
250  this->emscriptenKeyMap[ "Minus" ] = Input::Key::Minus;
251  this->emscriptenKeyMap[ "Period" ] = Input::Key::Period;
252  this->emscriptenKeyMap[ "Digit0" ] = Input::Key::Num_0;
253  this->emscriptenKeyMap[ "Digit1" ] = Input::Key::Num_1;
254  this->emscriptenKeyMap[ "Digit2" ] = Input::Key::Num_2;
255  this->emscriptenKeyMap[ "Digit3" ] = Input::Key::Num_3;
256  this->emscriptenKeyMap[ "Digit4" ] = Input::Key::Num_4;
257  this->emscriptenKeyMap[ "Digit5" ] = Input::Key::Num_5;
258  this->emscriptenKeyMap[ "Digit6" ] = Input::Key::Num_6;
259  this->emscriptenKeyMap[ "Digit7" ] = Input::Key::Num_7;
260  this->emscriptenKeyMap[ "Digit8" ] = Input::Key::Num_8;
261  this->emscriptenKeyMap[ "Digit9" ] = Input::Key::Num_9;
262  this->emscriptenKeyMap[ "Semicolon" ] = Input::Key::Semicolon;
263  this->emscriptenKeyMap[ "Equal" ] = Input::Key::Equal;
264  this->emscriptenKeyMap[ "KeyA" ] = Input::Key::Char_A;
265  this->emscriptenKeyMap[ "KeyB" ] = Input::Key::Char_B;
266  this->emscriptenKeyMap[ "KeyC" ] = Input::Key::Char_C;
267  this->emscriptenKeyMap[ "KeyD" ] = Input::Key::Char_D;
268  this->emscriptenKeyMap[ "KeyE" ] = Input::Key::Char_E;
269  this->emscriptenKeyMap[ "KeyF" ] = Input::Key::Char_F;
270  this->emscriptenKeyMap[ "KeyG" ] = Input::Key::Char_G;
271  this->emscriptenKeyMap[ "KeyH" ] = Input::Key::Char_H;
272  this->emscriptenKeyMap[ "KeyI" ] = Input::Key::Char_I;
273  this->emscriptenKeyMap[ "KeyJ" ] = Input::Key::Char_J;
274  this->emscriptenKeyMap[ "KeyK" ] = Input::Key::Char_K;
275  this->emscriptenKeyMap[ "KeyL" ] = Input::Key::Char_L;
276  this->emscriptenKeyMap[ "KeyM" ] = Input::Key::Char_M;
277  this->emscriptenKeyMap[ "KeyN" ] = Input::Key::Char_N;
278  this->emscriptenKeyMap[ "KeyO" ] = Input::Key::Char_O;
279  this->emscriptenKeyMap[ "KeyP" ] = Input::Key::Char_P;
280  this->emscriptenKeyMap[ "KeyQ" ] = Input::Key::Char_Q;
281  this->emscriptenKeyMap[ "KeyR" ] = Input::Key::Char_R;
282  this->emscriptenKeyMap[ "KeyS" ] = Input::Key::Char_S;
283  this->emscriptenKeyMap[ "KeyT" ] = Input::Key::Char_T;
284  this->emscriptenKeyMap[ "KeyU" ] = Input::Key::Char_U;
285  this->emscriptenKeyMap[ "KeyV" ] = Input::Key::Char_V;
286  this->emscriptenKeyMap[ "KeyW" ] = Input::Key::Char_W;
287  this->emscriptenKeyMap[ "KeyX" ] = Input::Key::Char_X;
288  this->emscriptenKeyMap[ "KeyY" ] = Input::Key::Char_Y;
289  this->emscriptenKeyMap[ "KeyZ" ] = Input::Key::Char_Z;
290  this->emscriptenKeyMap[ "BracketLeft" ] = Input::Key::Left_Bracket;
291  this->emscriptenKeyMap[ "Backslash" ] = Input::Key::Backslash;
292  this->emscriptenKeyMap[ "BracketRight" ] = Input::Key::Right_Bracket;
293  this->emscriptenKeyMap[ "Escape" ] = Input::Key::Escape;
294  this->emscriptenKeyMap[ "Enter" ] = Input::Key::Enter;
295  this->emscriptenKeyMap[ "Tab" ] = Input::Key::Tab;
296  this->emscriptenKeyMap[ "Backspace" ] = Input::Key::Backspace;
297  this->emscriptenKeyMap[ "Insert" ] = Input::Key::Insert;
298  this->emscriptenKeyMap[ "Delete" ] = Input::Key::Delete;
299  this->emscriptenKeyMap[ "ArrowRight" ] = Input::Key::Right;
300  this->emscriptenKeyMap[ "ArrowLeft" ] = Input::Key::Left;
301  this->emscriptenKeyMap[ "ArrowDown" ] = Input::Key::Down;
302  this->emscriptenKeyMap[ "ArrowUp" ] = Input::Key::Up;
303  this->emscriptenKeyMap[ "PageUp" ] = Input::Key::Page_Up;
304  this->emscriptenKeyMap[ "PageDown" ] = Input::Key::Page_Down;
305  this->emscriptenKeyMap[ "Home" ] = Input::Key::Home;
306  this->emscriptenKeyMap[ "End" ] = Input::Key::End;
307  this->emscriptenKeyMap[ "CapsLock" ] = Input::Key::Caps_Lock;
308  this->emscriptenKeyMap[ "ScrollLock" ] = Input::Key::Scroll_Lock;
309  this->emscriptenKeyMap[ "NumLock" ] = Input::Key::Num_Lock;
310  this->emscriptenKeyMap[ "Pause" ] = Input::Key::Pause;
311  this->emscriptenKeyMap[ "F1" ] = Input::Key::F1;
312  this->emscriptenKeyMap[ "F2" ] = Input::Key::F2;
313  this->emscriptenKeyMap[ "F3" ] = Input::Key::F3;
314  this->emscriptenKeyMap[ "F4" ] = Input::Key::F4;
315  this->emscriptenKeyMap[ "F5" ] = Input::Key::F5;
316  this->emscriptenKeyMap[ "F6" ] = Input::Key::F6;
317  this->emscriptenKeyMap[ "F7" ] = Input::Key::F7;
318  this->emscriptenKeyMap[ "F8" ] = Input::Key::F8;
319  this->emscriptenKeyMap[ "F9" ] = Input::Key::F9;
320  this->emscriptenKeyMap[ "F10" ] = Input::Key::F10;
321  this->emscriptenKeyMap[ "F11" ] = Input::Key::F11;
322  this->emscriptenKeyMap[ "F12" ] = Input::Key::F12;
323  this->emscriptenKeyMap[ "F13" ] = Input::Key::F13;
324  this->emscriptenKeyMap[ "F14" ] = Input::Key::F14;
325  this->emscriptenKeyMap[ "F15" ] = Input::Key::F15;
326  this->emscriptenKeyMap[ "F16" ] = Input::Key::F16;
327  this->emscriptenKeyMap[ "F17" ] = Input::Key::F17;
328  this->emscriptenKeyMap[ "F18" ] = Input::Key::F18;
329  this->emscriptenKeyMap[ "F19" ] = Input::Key::F19;
330  this->emscriptenKeyMap[ "F20" ] = Input::Key::F20;
331  this->emscriptenKeyMap[ "F21" ] = Input::Key::F21;
332  this->emscriptenKeyMap[ "F22" ] = Input::Key::F22;
333  this->emscriptenKeyMap[ "F23" ] = Input::Key::F23;
334  this->emscriptenKeyMap[ "F24" ] = Input::Key::F24;
335  this->emscriptenKeyMap[ "F25" ] = Input::Key::F25;
336  this->emscriptenKeyMap[ "Numpad0" ] = Input::Key::KeyPad_0;
337  this->emscriptenKeyMap[ "Numpad1" ] = Input::Key::KeyPad_1;
338  this->emscriptenKeyMap[ "Numpad2" ] = Input::Key::KeyPad_2;
339  this->emscriptenKeyMap[ "Numpad3" ] = Input::Key::KeyPad_3;
340  this->emscriptenKeyMap[ "Numpad4" ] = Input::Key::KeyPad_4;
341  this->emscriptenKeyMap[ "Numpad5" ] = Input::Key::KeyPad_5;
342  this->emscriptenKeyMap[ "Numpad6" ] = Input::Key::KeyPad_6;
343  this->emscriptenKeyMap[ "Numpad7" ] = Input::Key::KeyPad_7;
344  this->emscriptenKeyMap[ "Numpad8" ] = Input::Key::KeyPad_8;
345  this->emscriptenKeyMap[ "Numpad9" ] = Input::Key::KeyPad_9;
346  this->emscriptenKeyMap[ "NumpadDecimal" ] = Input::Key::KeyPad_Decimal;
347  this->emscriptenKeyMap[ "NumpadDivide" ] = Input::Key::KeyPad_Divide;
348  this->emscriptenKeyMap[ "NumpadMultiply" ] = Input::Key::KeyPad_Multiply;
349  this->emscriptenKeyMap[ "NumpadSubtract" ] = Input::Key::KeyPad_Subtract;
350  this->emscriptenKeyMap[ "NumpadAdd" ] = Input::Key::KeyPad_Add;
351  this->emscriptenKeyMap[ "NumpadEnter" ] = Input::Key::KeyPad_Enter;
352  this->emscriptenKeyMap[ "ShiftLeft" ] = Input::Key::Left_Shift;
353  this->emscriptenKeyMap[ "ControlLeft" ] = Input::Key::Left_Control;
354  this->emscriptenKeyMap[ "AltLeft" ] = Input::Key::Left_Alt;
355  this->emscriptenKeyMap[ "ShiftRight" ] = Input::Key::Right_Shift;
356  this->emscriptenKeyMap[ "ControlRight" ] = Input::Key::Right_Control;
357  this->emscriptenKeyMap[ "AltRight" ] = Input::Key::Right_Alt;
358 }
359 
360 bool GlfmWindow::EmscriptenKeyFunc( const char * code, GLFMKeyAction action, int modifiers )
361 {
362  auto it = this->emscriptenKeyMap.find( code );
363  if( it == this->emscriptenKeyMap.end() )
364  return false;
365  auto key = it->second;
366 
367  Input::Type type;
368  switch( action )
369  {
370  case GLFMKeyActionPressed: type = Input::Type::Press; break;
371  case GLFMKeyActionReleased: type = Input::Type::Release; break;
372  default: return false;
373  }
374 
375  Input i( type, key, 0, true );
376  return this->listener->input( &i );
377 }
378 
379 bool GlfmWindow::KeyFunc( GLFMKey keyCode, GLFMKeyAction action, int modifiers )
380 {
381  return false;
382 }
383 
384 void GlfmWindow::CharFunc( const char * value, int modifiers )
385 {
386  if( iv::utf8_size( value ) != 1 )
387  return;
388 
389  this->_current_character = ::utf8::next( value, value + strlen( value ) );
391  this->listener->input( &i );
392  this->_current_character = 0;
393 }
394 
395 //-------------------- static redirects --------------------------------------------------------------------------------
396 void GlfmWindow::s_onSurfaceCreated( GLFMDisplay * display, const int width, const int height )
397 {
398  GlfmWindow * window = reinterpret_cast< GlfmWindow * >( glfmGetUserData( display ) );
399  window->onSurfaceCreated( width, height );
400 }
401 
402 void GlfmWindow::s_onSurfaceDestroyed( GLFMDisplay * display )
403 {
404  GlfmWindow * window = reinterpret_cast< GlfmWindow * >( glfmGetUserData( display ) );
405  window->onSurfaceDestroyed();
406 }
407 
408 void GlfmWindow::s_onSurfaceResized( GLFMDisplay * display, int width, int height )
409 {
410  GlfmWindow * window = reinterpret_cast< GlfmWindow * >( glfmGetUserData( display ) );
411  window->onSurfaceResized( width, height );
412 }
413 
414 void GlfmWindow::s_onFrame( GLFMDisplay * display, double frameTime_s )
415 {
416  GlfmWindow * window = reinterpret_cast< GlfmWindow * >( glfmGetUserData( display ) );
417  window->onFrame( frameTime_s );
418 }
419 
420 bool GlfmWindow::s_TouchFunc( GLFMDisplay * display, int touch, GLFMTouchPhase phase, double x, double y )
421 {
422  GlfmWindow * window = reinterpret_cast< GlfmWindow * >( glfmGetUserData( display ) );
423  return window->TouchFunc( touch, phase, x, y );
424 }
425 
426 void GlfmWindow::s_SurfaceErrorFunc( GLFMDisplay * display, const char * message )
427 {
428  GlfmWindow * window = reinterpret_cast< GlfmWindow * >( glfmGetUserData( display ) );
429  window->SurfaceErrorFunc( message );
430 }
431 
432 void GlfmWindow::s_MemoryWarningFunc( GLFMDisplay * display )
433 {
434  GlfmWindow * window = reinterpret_cast< GlfmWindow * >( glfmGetUserData( display ) );
435  window->MemoryWarningFunc();
436 }
437 
438 void GlfmWindow::s_FocusFunc( GLFMDisplay * display, bool focused )
439 {
440  GlfmWindow * window = reinterpret_cast< GlfmWindow * >( glfmGetUserData( display ) );
441  window->FocusFunc( focused );
442 }
443 
444 bool GlfmWindow::s_KeyFunc( GLFMDisplay * display, GLFMKey keyCode, GLFMKeyAction action, int modifiers )
445 {
446  GlfmWindow * window = reinterpret_cast< GlfmWindow * >( glfmGetUserData( display ) );
447  return window->KeyFunc( keyCode, action, modifiers );
448 }
449 
450 void GlfmWindow::s_CharFunc( GLFMDisplay * display, const char * utf8, int modifiers )
451 {
452  GlfmWindow * window = reinterpret_cast< GlfmWindow * >( glfmGetUserData( display ) );
453  window->CharFunc( utf8, modifiers );
454 }
455 
456 bool GlfmWindow::s_EmscriptenKeyFunc( GLFMDisplay * display, const char * code, GLFMKeyAction action, int modifiers )
457 {
458  GlfmWindow * window = reinterpret_cast< GlfmWindow * >( glfmGetUserData( display ) );
459  return window->EmscriptenKeyFunc( code, action, modifiers );
460 }
461 
462 }
463 
464 #endif