fb53847515fe81382283495ec14ec71944506ad7
[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 int 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 if( !vg_loader_highwater( highscores_save_at_exit, NULL ) ) return 0;
63
64 vg_sleep_ms(200);
65
66 if( !steam_init() ) return 0;
67 if( !vg_loader_highwater( steam_end, NULL ) ) return 0;
68
69 if( !network_init() ) return 0;
70 if( !vg_loader_highwater( network_end, NULL ) ) return 0;
71
72 return 1;
73 }
74
75 int vg_load(void)
76 {
77 if( !render_init() ) return 0;
78 if( !vg_loader_highwater( render_free, NULL ) ) return 0;
79
80 if( !world_init() ) return 0;
81
82 if( !player_init() ) return 0;
83 if( !vg_loader_highwater( player_model_free, NULL ) ) return 0;
84
85
86
87 if( !vg_bake_shaders() ) return 0;
88
89
90 if( !audio_init() ) return 0;
91 if( !vg_loader_highwater( audio_free, NULL ) ) return 0;
92
93 /* FInal step */
94 world_load();
95 vg_console_load_autos();
96
97 return 1;
98 }
99
100 static void vg_start(void)
101 {
102 player_load_model( "ch_new" );
103 reset_player( 1, (const char *[]){ "start" } );
104 }
105
106 static void draw_origin_axis(void)
107 {
108 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 );
109 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 );
110 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff );
111 }
112
113 void vg_update( int loaded )
114 {
115 steam_update();
116
117 if( loaded )
118 {
119 draw_origin_axis();
120 network_update();
121 player_update();
122 world_update( player.phys.rb.co );
123 }
124 }
125
126 static void vg_framebuffer_resize( int w, int h )
127 {
128 render_fb_resize();
129 gate_fb_resize();
130 water_fb_resize();
131 }
132
133 static void render_main_game(void)
134 {
135 /* TODO Breakup this & Gen */
136 #if 0
137 float speed = freecam? 0.0f: v3_length( player.phys.rb.v );
138 v3f shake = { vg_randf()-0.5f, vg_randf()-0.5f, vg_randf()-0.5f };
139 v3_muls( shake, speed*0.01f, shake );
140 #endif
141
142 m4x4f world_4x4;
143 m4x3_expand( player.camera_inverse, world_4x4 );
144
145 gpipeline.fov = freecam? 60.0f: 125.0f; /* 120 */
146 m4x4_projection( vg_pv, gpipeline.fov,
147 (float)vg_window_x / (float)vg_window_y,
148 0.02f, 2100.0f );
149
150 m4x4_mul( vg_pv, world_4x4, vg_pv );
151
152 glEnable( GL_DEPTH_TEST );
153
154 /*
155 * Draw world
156 */
157
158 int draw_solid = player.is_dead | freecam;
159
160 render_world( vg_pv, player.camera );
161 if( draw_solid )
162 draw_player();
163 render_water_texture( player.camera );
164
165 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
166 render_water_surface( vg_pv, player.camera );
167
168 render_world_gates( vg_pv, player.phys.rb.co, player.camera );
169
170 /* Copy the RGB of what we have into the background buffer */
171 glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 );
172 glBindFramebuffer( GL_DRAW_FRAMEBUFFER, gpipeline.fb_background );
173 glBlitFramebuffer( 0,0, vg_window_x, vg_window_y,
174 0,0, vg_window_x, vg_window_y,
175 GL_COLOR_BUFFER_BIT,
176 GL_LINEAR );
177
178 /* Clear out the colour buffer, but keep depth */
179 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
180 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
181
182 if( !player.is_dead )
183 glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
184 else
185 glClear( GL_COLOR_BUFFER_BIT );
186
187 if( !draw_solid )
188 {
189 m4x4_projection( vg_pv, gpipeline.fov,
190 (float)vg_window_x / (float)vg_window_y,
191 0.01f, 600.0f );
192 m4x4_mul( vg_pv, world_4x4, vg_pv );
193 draw_player();
194 }
195
196 /* Draw back in the background
197 *
198 * TODO: need to disable alpha write in the terrain shader so this works
199 * again.
200 */
201 glEnable(GL_BLEND);
202 glDisable(GL_DEPTH_TEST);
203 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
204 glBlendEquation(GL_FUNC_ADD);
205
206 shader_blit_use();
207 shader_blit_uTexMain( 0 );
208 glActiveTexture(GL_TEXTURE0);
209 glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background );
210
211 render_fsquad();
212 }
213
214 void vg_render(void)
215 {
216 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
217 glViewport( 0,0, vg_window_x, vg_window_y );
218 glDisable( GL_DEPTH_TEST );
219
220 glClearColor( 0.11f, 0.35f, 0.37f, 1.0f );
221 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
222
223 render_main_game();
224
225
226 /* Other shite */
227 glDisable(GL_BLEND);
228 glDisable( GL_DEPTH_TEST );
229 vg_lines_drawall( (float *)vg_pv );
230 glViewport( 0,0, vg_window_x, vg_window_y );
231 }
232
233 void vg_ui(void)
234 {
235 #if 0
236 if( lightedit )
237 {
238 ui_global_ctx.cursor[0] = 10;
239 ui_global_ctx.cursor[1] = 10;
240 ui_global_ctx.cursor[2] = 200;
241 ui_global_ctx.cursor[3] = 20;
242
243 struct ub_world_lighting *wl = &gpipeline.ub_world_lighting;
244 struct ui_slider_vector
245 s5 = { .min=0.0f, .max=2.0f, .len=3, .data=wl->g_ambient_colour };
246
247 struct ui_slider
248 s8 = { .min=0.0f, .max=2.0f, .data = &gpipeline.shadow_spread },
249 s9 = { .min=0.0f, .max=25.0f, .data = &gpipeline.shadow_length };
250
251 for( int i=0; i<3; i++ )
252 run_light_widget( &gpipeline.widgets[i] );
253
254 gui_text( ui_global_ctx.cursor, "Ambient", 1, 0 );
255 ui_global_ctx.cursor[1] += 16;
256 ui_slider_vector( &ui_global_ctx, &s5 );
257
258 gui_text( ui_global_ctx.cursor, "Shadows", 1, 0 );
259 ui_global_ctx.cursor[1] += 16;
260 ui_slider( &ui_global_ctx, &s8 );
261 ui_slider( &ui_global_ctx, &s9 );
262
263 gui_text( ui_global_ctx.cursor, "Misc", 1, 0 );
264 ui_global_ctx.cursor[1] += 16;
265 struct ui_checkbox c1 = {.data = &wl->g_light_preview};
266 ui_checkbox( &ui_global_ctx, &c1 );
267
268 render_update_lighting_ub();
269 }
270 #endif
271
272 //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
273 if( cl_ui )
274 {
275 render_world_routes_ui();
276 }
277 //glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
278
279 audio_debug_soundscapes();
280 }
281
282 void vg_free(void)
283 {
284 }
285
286 #if 0
287 static void run_light_widget( struct light_widget *lw )
288 {
289 struct ui_checkbox c1 = { .data=&lw->enabled };
290
291 ui_checkbox( &ui_global_ctx, &c1 );
292
293 if( lw->enabled )
294 {
295 struct ui_slider_vector
296 colour = { .min=0.0f, .max=2.0f, .len=3, .data=lw->colour },
297 dir = { .min=-VG_PIf, .max=VG_PIf, .len=2, .data=lw->dir };
298
299 ui_slider_vector( &ui_global_ctx, &colour );
300 ui_global_ctx.cursor[1] += 4;
301 ui_slider_vector( &ui_global_ctx, &dir );
302 }
303 }
304 #endif
305
306 static void run_debug_info(void)
307 {
308 char buf[40];
309
310 snprintf( buf, 40, "%.2fm/s", v3_length( player.phys.rb.v ) );
311 gui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left );
312
313 snprintf( buf, 40, "%.2f %.2f %.2f m/s",
314 player.phys.a[0], player.phys.a[1], player.phys.a[2] );
315 gui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left );
316
317 snprintf( buf, 40, "pos %.2f %.2f %.2f",
318 player.phys.rb.co[0], player.phys.rb.co[1], player.phys.rb.co[2] );
319 gui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left );
320
321 if( vg.gamepad_ready )
322 {
323 for( int i=0; i<6; i++ )
324 {
325 snprintf( buf, 40, "%.2f", vg.gamepad.axes[i] );
326 gui_text( (ui_px [2]){ 0, (i+3)*20 }, buf, 1, k_text_align_left );
327 }
328 }
329 else
330 {
331 gui_text( (ui_px [2]){ 0, 60 },
332 "Gamepad not ready", 1, k_text_align_left );
333 }
334 }