add jumping
[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 . . . -----, ,----- ,---. .---. \n" );
54 vg_info(" 2021-2022 |\\ /| | / | | | | /| \n" );
55 vg_info(" | \\ / | +-- / +----- +---' | / | \n" );
56 vg_info(" | \\ / | | / | | \\ | / | \n" );
57 vg_info(" | \\/ | | / | | \\ | / | \n" );
58 vg_info(" ' ' '--' [] '----- '----- ' ' '---' "
59 "SOFTWARE\n" );
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_pre();
110 world_update( player.phys.rb.co );
111 }
112 }
113
114 static void vg_update_fixed( int loaded )
115 {
116 if( loaded )
117 {
118 player_update_fixed();
119 }
120 }
121
122 static void vg_update_post( int loaded )
123 {
124 if( loaded )
125 {
126 player_update_post();
127 }
128 }
129
130 static void vg_framebuffer_resize( int w, int h )
131 {
132 render_fb_resize();
133 gate_fb_resize();
134 water_fb_resize();
135 }
136
137 static void render_main_game(void)
138 {
139 m4x4f world_4x4;
140 m4x3_expand( player.camera_inverse, world_4x4 );
141
142 static float fov = 97.0f;
143 float fov_target = player.phys.on_board? 125.0f: 108.0f;
144 fov = vg_lerpf( fov, fov_target, vg.time_delta * 2.0f );
145
146 gpipeline.fov = freecam? 60.0f: fov; /* 120 */
147 m4x4_projection( vg.pv, gpipeline.fov,
148 (float)vg.window_x / (float)vg.window_y,
149 0.02f, 2100.0f );
150
151 m4x4_mul( vg.pv, world_4x4, vg.pv );
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 #if 0
283 static void run_light_widget( struct light_widget *lw )
284 {
285 struct ui_checkbox c1 = { .data=&lw->enabled };
286
287 ui_checkbox( &ui_global_ctx, &c1 );
288
289 if( lw->enabled )
290 {
291 struct ui_slider_vector
292 colour = { .min=0.0f, .max=2.0f, .len=3, .data=lw->colour },
293 dir = { .min=-VG_PIf, .max=VG_PIf, .len=2, .data=lw->dir };
294
295 ui_slider_vector( &ui_global_ctx, &colour );
296 ui_global_ctx.cursor[1] += 4;
297 ui_slider_vector( &ui_global_ctx, &dir );
298 }
299 }
300 #endif
301
302 static void run_debug_info(void)
303 {
304 char buf[40];
305
306 snprintf( buf, 40, "%.2fm/s", v3_length( player.phys.rb.v ) );
307 gui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left );
308
309 snprintf( buf, 40, "%.2f %.2f %.2f m/s",
310 player.phys.a[0], player.phys.a[1], player.phys.a[2] );
311 gui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left );
312
313 snprintf( buf, 40, "pos %.2f %.2f %.2f",
314 player.phys.rb.co[0], player.phys.rb.co[1], player.phys.rb.co[2] );
315 gui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left );
316
317 if( vg.gamepad_ready )
318 {
319 for( int i=0; i<6; i++ )
320 {
321 snprintf( buf, 40, "%.2f", vg.gamepad.axes[i] );
322 gui_text( (ui_px [2]){ 0, (i+3)*20 }, buf, 1, k_text_align_left );
323 }
324 }
325 else
326 {
327 gui_text( (ui_px [2]){ 0, 60 },
328 "Gamepad not ready", 1, k_text_align_left );
329 }
330 }