better performance feedback
[vg.git] / src / vg / vg.h
index f3ed6991690edd23e57b12697a910e2b5ebe557d..4aec2496cdd0024caaa76f9f5546e698c969d932 100644 (file)
@@ -41,20 +41,6 @@ void vg_register_exit( void( *funcptr )(void), const char *name );
 
 #ifndef VG_NON_CLIENT
 
-m4x4f vg_pv;
-
-int vg_window_x = 0;
-int vg_window_y = 0;
-int vg_samples = 0;
-
-v2f vg_mouse;
-v2f vg_mouse_wheel;
-v3f vg_mouse_ws;
-
-double vg_time,
-       vg_time_last,
-       vg_time_delta;
-
 struct vg
 {
    /* Engine sync */
@@ -76,9 +62,38 @@ struct vg
    }
    engine_status;
    const char *str_const_engine_err;
-
    int          is_loaded;
 
+   /* Window information */
+   int window_x,
+       window_y,
+       samples;
+   float refresh_rate;
+
+   v2f mouse,
+       mouse_wheel;
+
+   /* Runtime */
+   double time,
+          time_last,
+          time_delta,
+          accumulator;
+
+   int fixed_iterations;
+
+   enum engine_stage
+   {
+      k_engine_stage_none,
+      k_engine_stage_update,
+      k_engine_stage_update_fixed,
+      k_engine_stage_rendering,
+      k_engine_stage_ui
+   }
+   engine_stage;
+
+   /* graphics */
+   m4x4f pv;
+
    /* Gamepad */
    GLFWgamepadstate  gamepad;
    int                               gamepad_ready;
@@ -242,21 +257,30 @@ static void vg_checkgl( const char *src_info );
 #define VG_STRINGIT( X ) #X
 #define VG_CHECK_GL_ERR() vg_checkgl( __FILE__ ":L" VG_STRINGIT(__LINE__) )
 
+#include "vg_console.h"
+#include "vg_profiler.h"
 #include "vg_audio.h"
 #include "vg_shader.h"
 #include "vg_tex.h"
 #include "vg_input.h"
 #include "vg_ui.h"
-#include "vg_console.h"
 #include "vg_lines.h"
 #include "vg_debug.h"
 #include "vg_loader.h"
 #include "vg_opt.h"
 
+/* Diagnostic */
+static struct vg_profile vg_prof_update = {.name="update()"},
+                         vg_prof_render = {.name="render()"};
+
 #define VG_GAMELOOP
 static void vg_register(void) VG_GAMELOOP;
 static void vg_start(void) VG_GAMELOOP;
+
 static void vg_update(int loaded) VG_GAMELOOP;
+static void vg_update_fixed(int loaded) VG_GAMELOOP;
+static void vg_update_post(int loaded) VG_GAMELOOP;
+
 static void vg_framebuffer_resize(int w, int h) VG_GAMELOOP;
 static void vg_render(void) VG_GAMELOOP;
 static void vg_ui(void) VG_GAMELOOP;
@@ -278,14 +302,14 @@ static void vg_checkgl( const char *src_info )
 
 void vg_mouse_callback( GLFWwindow* ptrW, double xpos, double ypos )
 {
-   vg_mouse[0] = xpos;
-   vg_mouse[1] = ypos;
+   vg.mouse[0] = xpos;
+   vg.mouse[1] = ypos;
 }
 
 void vg_scroll_callback( GLFWwindow* ptrW, double xoffset, double yoffset )
 {
-   vg_mouse_wheel[0] += xoffset;
-   vg_mouse_wheel[1] += yoffset;
+   vg.mouse_wheel[0] += xoffset;
+   vg.mouse_wheel[1] += yoffset;
 }
 
 void vg_framebuffer_resize_callback( GLFWwindow *ptrW, int w, int h )
@@ -296,8 +320,8 @@ void vg_framebuffer_resize_callback( GLFWwindow *ptrW, int w, int h )
       return;
    }
 
-   vg_window_x = w;
-   vg_window_y = h;
+   vg.window_x = w;
+   vg.window_y = h;
 
    vg_framebuffer_resize(w,h);
 }
@@ -330,6 +354,7 @@ static void vg_load_full(void)
    vg_loader_highwater( vg_gamepad_init, NULL, NULL );
    vg_loader_highwater( vg_lines_init, vg_lines_free, NULL );
    vg_loader_highwater( vg_audio_init, vg_audio_free, NULL );
+   vg_loader_highwater( vg_profiler_init, NULL, NULL );
 
    /* client */
    vg_load();
@@ -346,17 +371,17 @@ static void vg_enter( int argc, char *argv[], const char *window_name )
    {
       if( (arg = vg_opt_arg( 'w' )) )
       {
-         vg_window_x = atoi( arg );
+         vg.window_x = atoi( arg );
       }
 
       if( (arg = vg_opt_arg( 'h' )) )
       {
-         vg_window_y = atoi( arg );
+         vg.window_y = atoi( arg );
       }
 
       if( (arg = vg_long_opt_arg( "samples" )) )
       {
-         vg_samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) );
+         vg.samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) );
       }
    }
 
@@ -373,7 +398,7 @@ static void vg_enter( int argc, char *argv[], const char *window_name )
    glfwWindowHint( GLFW_RESIZABLE, GLFW_FALSE );
    glfwWindowHint( GLFW_DOUBLEBUFFER, GLFW_TRUE );
    
-   glfwWindowHint( GLFW_SAMPLES, vg_samples );
+   glfwWindowHint( GLFW_SAMPLES, vg.samples );
    
    GLFWmonitor *monitor_primary = glfwGetPrimaryMonitor();
    
@@ -382,21 +407,21 @@ static void vg_enter( int argc, char *argv[], const char *window_name )
    glfwWindowHint( GLFW_GREEN_BITS, mode->greenBits );
    glfwWindowHint( GLFW_BLUE_BITS, mode->blueBits );
 
-   /* TODO? */
-   glfwWindowHint( GLFW_REFRESH_RATE, 60 );
+   glfwWindowHint( GLFW_REFRESH_RATE, mode->refreshRate );
 
-   if( !vg_window_x )
-      vg_window_x = mode->width;
+   if( !vg.window_x )
+      vg.window_x = mode->width;
 
-   if( !vg_window_y )
-      vg_window_y = mode->height;
+   if( !vg.window_y )
+      vg.window_y = mode->height;
 
+   vg.refresh_rate = mode->refreshRate;
 
-   if( (vg.window = glfwCreateWindow(  vg_window_x, vg_window_y,
+   if( (vg.window = glfwCreateWindow(  vg.window_x, vg.window_y,
                                        window_name, monitor_primary, NULL)) )
    {
-      glfwGetFramebufferSize( vg.window, &vg_window_x, &vg_window_y );
-      vg_success( "Window created (%dx%d)\n", vg_window_x, vg_window_y );
+      glfwGetFramebufferSize( vg.window, &vg.window_x, &vg.window_y );
+      vg_success( "Window created (%dx%d)\n", vg.window_x, vg.window_y );
    }
    else
    {
@@ -462,22 +487,21 @@ static void vg_enter( int argc, char *argv[], const char *window_name )
    vg_loader_start();
 
    int loaded = 0;
-   int counter =0;
    while(1)
    {
       if( glfwWindowShouldClose( vg.window ) )
          break;
 
-      v2_copy( (v2f){ 0.0f, 0.0f }, vg_mouse_wheel );
+      v2_copy( (v2f){ 0.0f, 0.0f }, vg.mouse_wheel );
       glfwPollEvents();
 
-      vg_time_last = vg_time;
-      vg_time = glfwGetTime();
-      vg_time_delta = vg_minf( vg_time - vg_time_last, 0.1f );
+      vg.time_last = vg.time;
+      vg.time = glfwGetTime();
+      vg.time_delta = vg.time-vg.time_last;
       
       if( vg.is_loaded )
       {
-         glClearColor( 0.0f,sinf(vg_time*20.0)*0.5f+0.5f,0.0f,1.0f );
+         glClearColor( 0.0f,sinf(vg.time*20.0)*0.5f+0.5f,0.0f,1.0f );
          glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
          
          if( !loaded )
@@ -491,27 +515,65 @@ static void vg_enter( int argc, char *argv[], const char *window_name )
          vg_loader_render();
       }
 
+      /* 
+       * Game logic 
+       * -------------------------------------------------------
+       */
+      vg_profile_begin( &vg_prof_update );
       vg_update_inputs();
+
+      vg.engine_stage = k_engine_stage_update;
       vg_update( loaded );
 
-      counter ++;
+      /* Fixed update loop */
+      vg.engine_stage = k_engine_stage_update_fixed;
+      vg.accumulator += vg.time_delta;
 
-#if 0
-      if( counter == 30 )
-         vg_fatal_exit_loop( "Test crash from main, while loading (-O0)" );
-#endif
+      vg.fixed_iterations = 0;
+      while( vg.accumulator >= (VG_TIMESTEP_FIXED-0.00125) )
+      {
+         vg_update_fixed( loaded );
+
+         vg.accumulator -= VG_TIMESTEP_FIXED;
+         vg.accumulator  = VG_MAX( 0.0, vg.accumulator );
+
+         vg.fixed_iterations ++;
+         if( vg.fixed_iterations == 8 )
+         {
+            break;
+         }
+      }
+
+      /* 
+       * Rendering 
+       * ---------------------------------------------
+       */
+      vg.engine_stage = k_engine_stage_update;
+      vg_update_post( loaded );
+      vg_profile_end( &vg_prof_update );
+
+      vg_profile_begin( &vg_prof_render );
 
       if( loaded )
       {
+         /* render */
+         vg.engine_stage = k_engine_stage_rendering;
          vg_render();
 
          /* ui */
+         vg.engine_stage = k_engine_stage_ui;
          {
-            ui_begin( &ui_global_ctx, vg_window_x, vg_window_y );
-            ui_set_mouse( &ui_global_ctx, vg_mouse[0], vg_mouse[1], 
+            ui_begin( &ui_global_ctx, vg.window_x, vg.window_y );
+            ui_set_mouse( &ui_global_ctx, vg.mouse[0], vg.mouse[1], 
                   vg_get_button_state( "primary" ) );
             
-            audio_debug_ui( vg_pv );
+            vg_profile_drawn( 
+                  (struct vg_profile *[]){&vg_prof_update,&vg_prof_render}, 2,
+                  (1.0f/(float)vg.refresh_rate)*1000.0f, 
+                  (ui_rect){ 4, 4, 250, 0 }, 0
+            );
+
+            audio_debug_ui( vg.pv );
             vg_ui();
             vg_console_draw();
             
@@ -520,6 +582,8 @@ static void vg_enter( int argc, char *argv[], const char *window_name )
          }
       }
 
+      vg_profile_end( &vg_prof_render );
+
       glfwSwapBuffers( vg.window );
       vg_run_synced_content();
    }
@@ -542,6 +606,11 @@ il_exit_ui:
 /*
  * Immediately transfer away from calling thread into a safe loop, signal for 
  * others to shutdown, then free everything once the user closes the window.
+ *
+ * FIXME(bug): glfwWindowShouldClose() never returns 1 in windows via wine, only
+ *             when calling the program from outside its normal directory.
+ *
+ *             A workaround is placed to skip the error loop on windows builds
  */
 static void vg_fatal_exit_loop( const char *error )
 {
@@ -595,24 +664,29 @@ static void vg_fatal_exit_loop( const char *error )
       }
       vg_audio_free(NULL);
 
-      /*
-       * todo: draw error loop
-       */
+#ifndef _WIN32
       while(1)
       {
          if( glfwWindowShouldClose( vg.window ) )
             break;
 
          glfwPollEvents();
+         
+         glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+         glEnable(GL_BLEND);
+         glDisable(GL_DEPTH_TEST);
+         glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
+         glBlendEquation(GL_FUNC_ADD);
 
          glClearColor( 0.15f + sinf(glfwGetTime())*0.1f, 0.0f, 0.0f,1.0f );
          glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
-         glViewport( 0,0, vg_window_x, vg_window_y );
+         glViewport( 0,0, vg.window_x, vg.window_y );
 
          vg_render_log();
 
          glfwSwapBuffers( vg.window );
       }
+#endif
 
       /* Can now shutdown and EXIT */
       vg_loader_free();