shader compilation
[fishladder.git] / vg / vg.h
1 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <dirent.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <stdarg.h>
9
10 #include "gl/glad/glad.h"
11 #include "gl/glfw3.h"
12
13 #define STB_DS_IMPLEMENTATION
14 #include "stb/stb_ds.h"
15
16 void vg_register_exit( void( *funcptr )(void), const char *name );
17 void vg_exiterr( const char *strErr );
18
19 #include "vg/vg_platform.h"
20 #include "vg/vg_io.h"
21 #include "vg/vg_audio.h"
22 #include "vg/vg_shader.h"
23
24 #include "steam/steamworks_thin.h"
25
26 static inline float vg_get_axis( const char *axis ) __attribute__((unused));
27 static inline int vg_get_button( const char *button ) __attribute__((unused));
28 static inline int vg_get_button_down( const char *button ) __attribute__((unused));
29 static inline int vg_get_button_up( const char *button ) __attribute__((unused));
30
31 // Globals
32 GLFWwindow* vg_window;
33 int vg_window_x = 1280;
34 int vg_window_y = 720;
35
36 float vg_mouse_x;
37 float vg_mouse_y;
38
39 float vg_time;
40 float vg_time_last;
41 float vg_time_delta;
42
43 // Input
44 // ===========================================================================================================
45 GLFWgamepadstate vg_gamepad;
46 int vg_gamepad_ready = 0;
47 const char *vg_gamepad_name = NULL;
48 int vg_gamepad_id;
49
50 enum EInputMode
51 {
52 k_EInputMode_pc,
53 k_EInputMode_gamepad
54 }
55 vg_input_mode;
56
57 static struct axis_binding
58 {
59 const char *name;
60 union
61 {
62 int positive;
63 int bind;
64 };
65 int negative;
66
67 float value;
68 }
69 vg_axis_binds[];
70
71 static struct button_binding
72 {
73 const char *name;
74 int bind;
75
76 int value; int prev;
77 }
78 vg_button_binds[];
79
80 #include "vg/config.h"
81
82 #pragma GCC diagnostic push
83 #pragma GCC diagnostic ignored "-Wreturn-type"
84
85 static inline float vg_get_axis( const char *axis )
86 {
87 for( int i = 0; i < vg_list_size( vg_axis_binds ); i ++ )
88 {
89 if( !strcmp( axis, vg_axis_binds[i].name ) )
90 {
91 return vg_axis_binds[i].value;
92 }
93 }
94 }
95
96 static inline struct button_binding *vg_get_button_ptr( const char *button )
97 {
98 for( int i = 0; i < vg_list_size( vg_button_binds ); i ++ )
99 {
100 if( !strcmp( button, vg_button_binds[i].name ) )
101 {
102 return vg_button_binds + i;
103 }
104 }
105 }
106 #pragma GCC diagnostic pop
107
108 static inline int vg_get_button( const char *button )
109 {
110 return vg_get_button_ptr( button )->value;
111 }
112
113 static inline int vg_get_button_down( const char *button )
114 {
115 struct button_binding *bind = vg_get_button_ptr( button );
116 return bind->value & (bind->value ^ bind->prev);
117 }
118
119 static inline int vg_get_button_up( const char *button )
120 {
121 struct button_binding *bind = vg_get_button_ptr( button );
122 return bind->prev & (bind->value ^ bind->prev);
123 }
124
125 static inline int key_is_keyboard( int const id )
126 {
127 static_assert( GLFW_MOUSE_BUTTON_LAST < GLFW_KEY_SPACE, "GLFW: Mouse has too many buttons" );
128 return id > GLFW_MOUSE_BUTTON_LAST;
129 }
130
131 // Mouse AND Keyboard get button press
132 int get_button_cross_device( int const id )
133 {
134 if( key_is_keyboard( id ) )
135 {
136 return glfwGetKey( vg_window, id );
137 }
138 else
139 {
140 return glfwGetMouseButton( vg_window, id ) == GLFW_PRESS;
141 }
142 }
143
144 void vg_update_inputs(void)
145 {
146 // Update button inputs
147 for( int i = 0; i < vg_list_size( vg_button_binds ); i ++ )
148 {
149 struct button_binding *binding = vg_button_binds + i;
150 binding->prev = binding->value;
151
152 if( vg_input_mode == k_EInputMode_pc )
153 {
154 binding->value = get_button_cross_device( binding->bind );
155 }
156 else
157 {
158 binding->value = vg_gamepad.buttons[ binding->bind ];
159 }
160 }
161
162 // Update axis inputs
163 for( int i = 0; i < vg_list_size( vg_axis_binds ); i ++ )
164 {
165 struct axis_binding *binding = vg_axis_binds + i;
166
167 if( vg_input_mode == k_EInputMode_pc )
168 {
169 binding->value = get_button_cross_device( binding->positive );
170 binding->value -= get_button_cross_device( binding->negative );
171 }
172 else
173 {
174 binding->value = vg_gamepad.axes[ binding->bind ];
175 }
176 }
177 }
178
179 // Engine main
180 // ===========================================================================================================
181
182 #define VG_GAMELOOP
183
184 void( *vg_on_exit[16] )(void);
185 u32 vg_exit_count = 0;
186
187 // Add a shutdown step
188 void vg_register_exit( void( *funcptr )(void), const char *name )
189 {
190 vg_info( "exit registered: (%u)'%s'\n", vg_exit_count, name );
191 vg_on_exit[ vg_exit_count ++ ] = funcptr;
192 }
193
194 void vg_exit(void)
195 {
196 for( int i = vg_exit_count-1; i >= 0; i -- )
197 {
198 vg_info( "engine_exit[%d]()\n", i );
199 vg_on_exit[i]();
200 }
201
202 vg_info( "done\n" );
203 }
204
205 // Forcefully exit program after error
206 void vg_exiterr( const char *strErr )
207 {
208 vg_error( "Engine Fatal: %s\n", strErr );
209 vg_exit();
210 exit(0);
211 }
212
213 // Callbacks
214 // ---------
215
216 void vg_mouse_callback( GLFWwindow* ptrW, double xpos, double ypos )
217 {
218 vg_mouse_x = xpos;
219 vg_mouse_y = ypos;
220 }
221
222 void vg_scroll_callback( GLFWwindow* ptrW, double xoffset, double yoffset )
223 {
224
225 }
226
227 void vg_framebuffer_resize_callback( GLFWwindow *ptrW, int w, int h )
228 {
229 vg_window_x = w;
230 vg_window_y = h;
231 }
232
233 static void vg_start(void) VG_GAMELOOP;
234 static void vg_update(void) VG_GAMELOOP;
235 static void vg_render(void) VG_GAMELOOP;
236 static void vg_ui(void) VG_GAMELOOP;
237 static void vg_free(void) VG_GAMELOOP;
238
239 static void vg_init( int argc, char *argv[], const char *window_name )
240 {
241 #ifdef VG_STEAM
242 // Initialize steamworks
243 if( !sw_init( 1218140U ) )
244 {
245 vg_exiterr( "Steamworks failed to initialize" );
246 }
247 else
248 {
249 vg_register_exit( &sw_SteamAPI_Shutdown, "SteamAPI" );
250 }
251 #endif
252
253 // Context creation
254 // ==========================================================================================================================
255 glfwInit();
256 glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
257 glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
258 glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
259 glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE );
260
261 glfwWindowHint( GLFW_SAMPLES, 4 );
262
263 GLFWmonitor *monitor_primary = glfwGetPrimaryMonitor();
264
265 const GLFWvidmode *mode = glfwGetVideoMode( monitor_primary );
266 glfwWindowHint( GLFW_RED_BITS, mode->redBits );
267 glfwWindowHint( GLFW_GREEN_BITS, mode->greenBits );
268 glfwWindowHint( GLFW_BLUE_BITS, mode->blueBits );
269 glfwWindowHint( GLFW_REFRESH_RATE, mode->refreshRate );
270
271 if( !(vg_window = glfwCreateWindow( vg_window_x, vg_window_y, window_name, NULL, NULL)) )
272 {
273 vg_exiterr( "GLFW Failed to initialize" );
274 }
275 else
276 {
277 vg_register_exit( &glfwTerminate, "glfwTerminate" );
278 }
279
280 glfwMakeContextCurrent( vg_window );
281 glfwSwapInterval( 1 );
282
283 // Set callbacks
284 glfwSetFramebufferSizeCallback( vg_window, vg_framebuffer_resize_callback );
285
286 glfwSetCursorPosCallback( vg_window, vg_mouse_callback );
287 glfwSetScrollCallback( vg_window, vg_scroll_callback );
288
289 //glfwSetCharCallback( vg_window, console_proc_wchar );
290 //glfwSetKeyCallback( vg_window, console_proc_key );
291 //glfwSetInputMode(vg_window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
292
293 if( !gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) )
294 {
295 vg_exiterr( "Glad failed to initialize" );
296 }
297
298 const unsigned char* glver = glGetString( GL_VERSION );
299 vg_success( "Load setup complete, OpenGL version: %s\n", glver );
300
301 for( int id = 0; id <= GLFW_JOYSTICK_LAST; id ++ )
302 {
303 if( glfwJoystickIsGamepad( id ) )
304 {
305 vg_gamepad_name = glfwGetGamepadName( id );
306 vg_success( "Gamepad with mapping registered: %s\n", vg_gamepad_name );
307
308 vg_gamepad_ready = 1;
309 vg_gamepad_id = id;
310
311 return;
312 }
313 }
314
315 vg_audio_init();
316 vg_register_exit( &vg_audio_free, "vg_audio_free" );
317
318 vg_start();
319 if( vg_shaders_compile() )
320 {
321 // Main gameloop
322 while( !glfwWindowShouldClose( vg_window ) )
323 {
324 glfwPollEvents();
325
326 #ifdef VG_STEAM
327 sw_RunSteamEventLoop();
328 #endif
329
330 vg_time_last = vg_time;
331 vg_time = glfwGetTime();
332 vg_time_delta = vg_min( vg_time - vg_time_last, 0.1f );
333
334 vg_update_inputs();
335
336 vg_update();
337
338 // Update mashed projections etc
339
340 vg_render();
341 vg_ui();
342
343 glfwSwapBuffers( vg_window );
344 }
345 }
346
347 vg_free();
348 vg_exit();
349 }
350
351 u32 NvOptimusEnablement = 0x00000001;
352 int AmdPowerXpressRequestHighPerformance = 1;