Fix major overstep with last commit
[carveJwlIkooP6JGAAIwe30JlM.git] / main.c
1 /*
2 * =============================================================================
3 *
4 * Copyright . . . -----, ,----- ,---. .---.
5 * 2021-2022 |\ /| | / | | | | /|
6 * | \ / | +-- / +----- +---' | / |
7 * | \ / | | / | | \ | / |
8 * | \/ | | / | | \ | / |
9 * ' ' '--' [] '----- '----- ' ' '---' SOFTWARE
10 *
11 * =============================================================================
12 *
13 * register: shader register & init scheduling
14 * init: initialization
15 * update: logic
16 * render: graphics
17 * free: resource free
18 *
19 */
20
21 #define SR_NETWORKED
22 #define VG_3D
23 #include "common.h"
24 #include "steam.h"
25 #include "render.h"
26 #include "audio.h"
27 #include "world.h"
28 #include "player.h"
29
30 static int cl_ui = 1;
31
32 int main( int argc, char *argv[] )
33 {
34 vg_enter( argc, argv, "Voyager Game Engine" );
35 }
36
37 static void highscores_save_at_exit(void*_)
38 {
39 highscores_serialize_all();
40 highscores_free();
41 }
42
43 void vg_preload(void)
44 {
45 vg_convar_push( (struct vg_convar){
46 .name = "cl_ui",
47 .data = &cl_ui,
48 .data_type = k_convar_dtype_i32,
49 .opt_i32 = { .min=0, .max=1, .clamp=1 },
50 .persistent = 1
51 });
52
53 vg_info(" Copyright . . . -----, ,----- ,---. .---. " );
54 vg_info(" 2021-2022 |\\ /| | / | | | | /| " );
55 vg_info(" | \\ / | +-- / +----- +---' | / | " );
56 vg_info(" | \\ / | | / | | \\ | / | " );
57 vg_info(" | \\/ | | / | | \\ | / | " );
58 vg_info(" ' ' '--' [] '----- '----- ' ' '---' "
59 "SOFTWARE" );
60
61 highscores_init( 2000, 50 );
62 vg_loader_highwater( NULL, highscores_save_at_exit, NULL );
63
64 vg_sleep_ms(200);
65
66 steam_init();
67 vg_loader_highwater( NULL, steam_end, NULL );
68
69 vg_loader_highwater( network_init, network_end, NULL );
70 }
71
72 void vg_load(void)
73 {
74 vg_loader_highwater( render_init, render_free, NULL );
75 vg_loader_highwater( world_init, world_free, NULL );
76 vg_loader_highwater( player_init, NULL, NULL );
77
78 if( !vg_bake_shaders() )
79 vg_fatal_exit_loop( "Did not load all shaders" );
80
81 vg_loader_highwater( audio_init, audio_free, NULL );
82
83 /* FInal step */
84 world_load();
85 vg_console_load_autos();
86 }
87
88 static void vg_start(void)
89 {
90 player_load_model( "ch_new" );
91 reset_player( 1, (const char *[]){ "start" } );
92 }
93
94 static void draw_origin_axis(void)
95 {
96 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 );
97 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 );
98 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff );
99 }
100
101 void vg_update( int loaded )
102 {
103 steam_update();
104
105 if( loaded )
106 {
107 draw_origin_axis();
108 network_update();
109 player_update();
110 world_update( player.phys.rb.co );
111 }
112 }
113
114 static void vg_framebuffer_resize( int w, int h )
115 {
116 render_fb_resize();
117 gate_fb_resize();
118 water_fb_resize();
119 }
120
121 static void render_main_game(void)
122 {
123 /* TODO Breakup this & Gen */
124 #if 0
125 float speed = freecam? 0.0f: v3_length( player.phys.rb.v );
126 v3f shake = { vg_randf()-0.5f, vg_randf()-0.5f, vg_randf()-0.5f };
127 v3_muls( shake, speed*0.01f, shake );
128 #endif
129
130 m4x4f world_4x4;
131 m4x3_expand( player.camera_inverse, world_4x4 );
132
133 gpipeline.fov = freecam? 60.0f: 125.0f; /* 120 */
134 m4x4_projection( vg_pv, gpipeline.fov,
135 (float)vg_window_x / (float)vg_window_y,
136 0.02f, 2100.0f );
137
138 m4x4_mul( vg_pv, world_4x4, vg_pv );
139
140 glEnable( GL_DEPTH_TEST );
141
142 /*
143 * Draw world
144 */
145
146 int draw_solid = player.is_dead | freecam;
147
148 render_world( vg_pv, player.camera );
149 if( draw_solid )
150 draw_player();
151 render_water_texture( player.camera );
152
153 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
154 render_water_surface( vg_pv, player.camera );
155
156 render_world_gates( vg_pv, player.phys.rb.co, player.camera );
157
158 /* Copy the RGB of what we have into the background buffer */
159 glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 );
160 glBindFramebuffer( GL_DRAW_FRAMEBUFFER, gpipeline.fb_background );
161 glBlitFramebuffer( 0,0, vg_window_x, vg_window_y,
162 0,0, vg_window_x, vg_window_y,
163 GL_COLOR_BUFFER_BIT,
164 GL_LINEAR );
165
166 /* Clear out the colour buffer, but keep depth */
167 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
168 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
169
170 if( !player.is_dead )
171 glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
172 else
173 glClear( GL_COLOR_BUFFER_BIT );
174
175 if( !draw_solid )
176 {
177 m4x4_projection( vg_pv, gpipeline.fov,
178 (float)vg_window_x / (float)vg_window_y,
179 0.01f, 600.0f );
180 m4x4_mul( vg_pv, world_4x4, vg_pv );
181 draw_player();
182 }
183
184 /* Draw back in the background
185 *
186 * TODO: need to disable alpha write in the terrain shader so this works
187 * again.
188 */
189 glEnable(GL_BLEND);
190 glDisable(GL_DEPTH_TEST);
191 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
192 glBlendEquation(GL_FUNC_ADD);
193
194 shader_blit_use();
195 shader_blit_uTexMain( 0 );
196 glActiveTexture(GL_TEXTURE0);
197 glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background );
198
199 render_fsquad();
200 }
201
202 void vg_render(void)
203 {
204 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
205 glViewport( 0,0, vg_window_x, vg_window_y );
206 glDisable( GL_DEPTH_TEST );
207
208 glClearColor( 0.11f, 0.35f, 0.37f, 1.0f );
209 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
210
211 render_main_game();
212
213
214 /* Other shite */
215 glDisable(GL_BLEND);
216 glDisable( GL_DEPTH_TEST );
217 vg_lines_drawall( (float *)vg_pv );
218 glViewport( 0,0, vg_window_x, vg_window_y );
219 }
220
221 void vg_ui(void)
222 {
223 #if 0
224 if( lightedit )
225 {
226 ui_global_ctx.cursor[0] = 10;
227 ui_global_ctx.cursor[1] = 10;
228 ui_global_ctx.cursor[2] = 200;
229 ui_global_ctx.cursor[3] = 20;
230
231 struct ub_world_lighting *wl = &gpipeline.ub_world_lighting;
232 struct ui_slider_vector
233 s5 = { .min=0.0f, .max=2.0f, .len=3, .data=wl->g_ambient_colour };
234
235 struct ui_slider
236 s8 = { .min=0.0f, .max=2.0f, .data = &gpipeline.shadow_spread },
237 s9 = { .min=0.0f, .max=25.0f, .data = &gpipeline.shadow_length };
238
239 for( int i=0; i<3; i++ )
240 run_light_widget( &gpipeline.widgets[i] );
241
242 gui_text( ui_global_ctx.cursor, "Ambient", 1, 0 );
243 ui_global_ctx.cursor[1] += 16;
244 ui_slider_vector( &ui_global_ctx, &s5 );
245
246 gui_text( ui_global_ctx.cursor, "Shadows", 1, 0 );
247 ui_global_ctx.cursor[1] += 16;
248 ui_slider( &ui_global_ctx, &s8 );
249 ui_slider( &ui_global_ctx, &s9 );
250
251 gui_text( ui_global_ctx.cursor, "Misc", 1, 0 );
252 ui_global_ctx.cursor[1] += 16;
253 struct ui_checkbox c1 = {.data = &wl->g_light_preview};
254 ui_checkbox( &ui_global_ctx, &c1 );
255
256 render_update_lighting_ub();
257 }
258 #endif
259
260 //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
261 if( cl_ui )
262 {
263 render_world_routes_ui();
264 }
265 //glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
266
267 audio_debug_soundscapes();
268 }
269
270 #if 0
271 static void run_light_widget( struct light_widget *lw )
272 {
273 struct ui_checkbox c1 = { .data=&lw->enabled };
274
275 ui_checkbox( &ui_global_ctx, &c1 );
276
277 if( lw->enabled )
278 {
279 struct ui_slider_vector
280 colour = { .min=0.0f, .max=2.0f, .len=3, .data=lw->colour },
281 dir = { .min=-VG_PIf, .max=VG_PIf, .len=2, .data=lw->dir };
282
283 ui_slider_vector( &ui_global_ctx, &colour );
284 ui_global_ctx.cursor[1] += 4;
285 ui_slider_vector( &ui_global_ctx, &dir );
286 }
287 }
288 #endif
289
290 static void run_debug_info(void)
291 {
292 char buf[40];
293
294 snprintf( buf, 40, "%.2fm/s", v3_length( player.phys.rb.v ) );
295 gui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left );
296
297 snprintf( buf, 40, "%.2f %.2f %.2f m/s",
298 player.phys.a[0], player.phys.a[1], player.phys.a[2] );
299 gui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left );
300
301 snprintf( buf, 40, "pos %.2f %.2f %.2f",
302 player.phys.rb.co[0], player.phys.rb.co[1], player.phys.rb.co[2] );
303 gui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left );
304
305 if( vg.gamepad_ready )
306 {
307 for( int i=0; i<6; i++ )
308 {
309 snprintf( buf, 40, "%.2f", vg.gamepad.axes[i] );
310 gui_text( (ui_px [2]){ 0, (i+3)*20 }, buf, 1, k_text_align_left );
311 }
312 }
313 else
314 {
315 gui_text( (ui_px [2]){ 0, 60 },
316 "Gamepad not ready", 1, k_text_align_left );
317 }
318 }