+ vg_error( "Fatal error: %s\n", error );
+ assert( vg_semaphore_trywait( &vg.sem_fatal ) );
+
+ vg_mutex_lock( &vg.mux_engine_status );
+
+ if( vg.engine_status == k_engine_status_none )
+ {
+ vg_mutex_unlock( &vg.mux_engine_status );
+
+ /* TODO: Correct shutdown before other systems */
+ exit(0);
+ }
+ else
+ {
+ vg_mutex_unlock( &vg.mux_engine_status );
+
+ /*
+ * if main
+ * if loader running
+ * wait until loader checks in, it will die
+ * else
+ * pass immediately
+ * else
+ * if have context
+ * pass immediately
+ * else
+ * wait for main to get to us, it will never be used again
+ *
+ * undefined behaviour:
+ * fatal_exit_loop is called in both threads, preventing an appropriate
+ * reaction to the crash. This *should* be made
+ * obvious by the assertion
+ */
+ vg_acquire_thread_sync();
+
+ vg_mutex_lock( &vg.mux_engine_status );
+ vg.engine_status = k_engine_status_crashed;
+ vg.str_const_engine_err = error;
+ vg_mutex_unlock( &vg.mux_engine_status );
+
+ /*
+ * Wait for loader to finish what it was doing, if it was running.
+ * Then we can continue in our nice error screen
+ */
+ if( vg_thread_info.purpose == k_thread_purpose_main )
+ {
+ vg_semaphore_wait( &vg.sem_loader );
+ }
+ vg_audio_free(NULL);
+
+ while(1)
+ {
+ if( glfwWindowShouldClose( vg.window ) )
+ break;
+
+ if( glfwGetKey( vg.window, GLFW_KEY_ESCAPE ) )
+ 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 );
+
+ vg_render_log();
+
+ glfwSwapBuffers( vg.window );
+ }
+
+ /* Can now shutdown and EXIT */
+ vg_loader_free();
+ glfwTerminate();
+ exit(0);
+ }
+}
+
+#else
+
+VG_STATIC void vg_fatal_exit_loop( const char *error )
+{
+ vg_error( "Fatal error: %s\n", error );
+ exit(0);
+}
+