added stb, more binaryout changes"
[henge/apc.git] / stb / tests / caveview / cave_main.c
1 #define _WIN32_WINNT 0x400
2
3 #include <assert.h>
4 #include <windows.h>
5
6 // stb.h
7 #define STB_DEFINE
8 #include "stb.h"
9
10 // stb_gl.h
11 #define STB_GL_IMPLEMENTATION
12 #define STB_GLEXT_DEFINE "glext_list.h"
13 #include "stb_gl.h"
14
15 // SDL
16 #include "sdl.h"
17 #include "SDL_opengl.h"
18
19 // stb_glprog.h
20 #define STB_GLPROG_IMPLEMENTATION
21 #define STB_GLPROG_ARB_DEFINE_EXTENSIONS
22 #include "stb_glprog.h"
23
24 // stb_image.h
25 #define STB_IMAGE_IMPLEMENTATION
26 #include "stb_image.h"
27
28 // stb_easy_font.h
29 #include "stb_easy_font.h" // doesn't require an IMPLEMENTATION
30
31 #include "caveview.h"
32
33 char *game_name = "caveview";
34
35
36 #define REVERSE_DEPTH
37
38
39
40 static void print_string(float x, float y, char *text, float r, float g, float b)
41 {
42 static char buffer[99999];
43 int num_quads;
44
45 num_quads = stb_easy_font_print(x, y, text, NULL, buffer, sizeof(buffer));
46
47 glColor3f(r,g,b);
48 glEnableClientState(GL_VERTEX_ARRAY);
49 glVertexPointer(2, GL_FLOAT, 16, buffer);
50 glDrawArrays(GL_QUADS, 0, num_quads*4);
51 glDisableClientState(GL_VERTEX_ARRAY);
52 }
53
54 static float text_color[3];
55 static float pos_x = 10;
56 static float pos_y = 10;
57
58 static void print(char *text, ...)
59 {
60 char buffer[999];
61 va_list va;
62 va_start(va, text);
63 vsprintf(buffer, text, va);
64 va_end(va);
65 print_string(pos_x, pos_y, buffer, text_color[0], text_color[1], text_color[2]);
66 pos_y += 10;
67 }
68
69 float camang[3], camloc[3] = { 60,22,77 };
70 float player_zoom = 1.0;
71 float rotate_view = 0.0;
72
73
74 void camera_to_worldspace(float world[3], float cam_x, float cam_y, float cam_z)
75 {
76 float vec[3] = { cam_x, cam_y, cam_z };
77 float t[3];
78 float s,c;
79 s = (float) sin(camang[0]*3.141592/180);
80 c = (float) cos(camang[0]*3.141592/180);
81
82 t[0] = vec[0];
83 t[1] = c*vec[1] - s*vec[2];
84 t[2] = s*vec[1] + c*vec[2];
85
86 s = (float) sin(camang[2]*3.141592/180);
87 c = (float) cos(camang[2]*3.141592/180);
88 world[0] = c*t[0] - s*t[1];
89 world[1] = s*t[0] + c*t[1];
90 world[2] = t[2];
91 }
92
93 // camera worldspace velocity
94 float cam_vel[3];
95
96 int controls;
97
98 #define MAX_VEL 150.0f // blocks per second
99 #define ACCEL 6.0f
100 #define DECEL 3.0f
101
102 #define STATIC_FRICTION DECEL
103 #define EFFECTIVE_ACCEL (ACCEL+DECEL)
104
105 // dynamic friction:
106 //
107 // if going at MAX_VEL, ACCEL and friction must cancel
108 // EFFECTIVE_ACCEL = DECEL + DYNAMIC_FRIC*MAX_VEL
109 #define DYNAMIC_FRICTION (ACCEL/(float)MAX_VEL)
110
111 float view_x_vel = 0;
112 float view_z_vel = 0;
113 float pending_view_x;
114 float pending_view_z;
115 float pending_view_x;
116 float pending_view_z;
117
118 void process_tick_raw(float dt)
119 {
120 int i;
121 float thrust[3] = { 0,0,0 };
122 float world_thrust[3];
123
124 // choose direction to apply thrust
125
126 thrust[0] = (controls & 3)== 1 ? EFFECTIVE_ACCEL : (controls & 3)== 2 ? -EFFECTIVE_ACCEL : 0;
127 thrust[1] = (controls & 12)== 4 ? EFFECTIVE_ACCEL : (controls & 12)== 8 ? -EFFECTIVE_ACCEL : 0;
128 thrust[2] = (controls & 48)==16 ? EFFECTIVE_ACCEL : (controls & 48)==32 ? -EFFECTIVE_ACCEL : 0;
129
130 // @TODO clamp thrust[0] & thrust[1] vector length to EFFECTIVE_ACCEL
131
132 camera_to_worldspace(world_thrust, thrust[0], thrust[1], 0);
133 world_thrust[2] += thrust[2];
134
135 for (i=0; i < 3; ++i) {
136 float acc = world_thrust[i];
137 cam_vel[i] += acc*dt;
138 }
139
140 if (cam_vel[0] || cam_vel[1] || cam_vel[2])
141 {
142 float vel = (float) sqrt(cam_vel[0]*cam_vel[0] + cam_vel[1]*cam_vel[1] + cam_vel[2]*cam_vel[2]);
143 float newvel = vel;
144 float dec = STATIC_FRICTION + DYNAMIC_FRICTION*vel;
145 newvel = vel - dec*dt;
146 if (newvel < 0)
147 newvel = 0;
148 cam_vel[0] *= newvel/vel;
149 cam_vel[1] *= newvel/vel;
150 cam_vel[2] *= newvel/vel;
151 }
152
153 camloc[0] += cam_vel[0] * dt;
154 camloc[1] += cam_vel[1] * dt;
155 camloc[2] += cam_vel[2] * dt;
156
157 view_x_vel *= (float) pow(0.75, dt);
158 view_z_vel *= (float) pow(0.75, dt);
159
160 view_x_vel += (pending_view_x - view_x_vel)*dt*60;
161 view_z_vel += (pending_view_z - view_z_vel)*dt*60;
162
163 pending_view_x -= view_x_vel * dt;
164 pending_view_z -= view_z_vel * dt;
165 camang[0] += view_x_vel * dt;
166 camang[2] += view_z_vel * dt;
167 camang[0] = stb_clamp(camang[0], -90, 90);
168 camang[2] = (float) fmod(camang[2], 360);
169 }
170
171 void process_tick(float dt)
172 {
173 while (dt > 1.0f/60) {
174 process_tick_raw(1.0f/60);
175 dt -= 1.0f/60;
176 }
177 process_tick_raw(dt);
178 }
179
180 void update_view(float dx, float dy)
181 {
182 // hard-coded mouse sensitivity, not resolution independent?
183 pending_view_z -= dx*300;
184 pending_view_x -= dy*700;
185 }
186
187 extern int screen_x, screen_y;
188 extern int is_synchronous_debug;
189 float render_time;
190
191 extern int chunk_locations, chunks_considered, chunks_in_frustum;
192 extern int quads_considered, quads_rendered;
193 extern int chunk_storage_rendered, chunk_storage_considered, chunk_storage_total;
194 extern int view_dist_in_chunks;
195 extern int num_threads_active, num_meshes_started, num_meshes_uploaded;
196 extern float chunk_server_activity;
197
198 static Uint64 start_time, end_time; // render time
199
200 float chunk_server_status[32];
201 int chunk_server_pos;
202
203 void draw_stats(void)
204 {
205 int i;
206
207 static Uint64 last_frame_time;
208 Uint64 cur_time = SDL_GetPerformanceCounter();
209 float chunk_server=0;
210 float frame_time = (cur_time - last_frame_time) / (float) SDL_GetPerformanceFrequency();
211 last_frame_time = cur_time;
212
213 chunk_server_status[chunk_server_pos] = chunk_server_activity;
214 chunk_server_pos = (chunk_server_pos+1) %32;
215
216 for (i=0; i < 32; ++i)
217 chunk_server += chunk_server_status[i] / 32.0f;
218
219 stb_easy_font_spacing(-0.75);
220 pos_y = 10;
221 text_color[0] = text_color[1] = text_color[2] = 1.0f;
222 print("Frame time: %6.2fms, CPU frame render time: %5.2fms", frame_time*1000, render_time*1000);
223 print("Tris: %4.1fM drawn of %4.1fM in range", 2*quads_rendered/1000000.0f, 2*quads_considered/1000000.0f);
224 print("Vbuf storage: %dMB in frustum of %dMB in range of %dMB in cache", chunk_storage_rendered>>20, chunk_storage_considered>>20, chunk_storage_total>>20);
225 print("Num mesh builds started this frame: %d; num uploaded this frame: %d\n", num_meshes_started, num_meshes_uploaded);
226 print("QChunks: %3d in frustum of %3d valid of %3d in range", chunks_in_frustum, chunks_considered, chunk_locations);
227 print("Mesh worker threads active: %d", num_threads_active);
228 print("View distance: %d blocks", view_dist_in_chunks*16);
229 print("%s", glGetString(GL_RENDERER));
230
231 if (is_synchronous_debug) {
232 text_color[0] = 1.0;
233 text_color[1] = 0.5;
234 text_color[2] = 0.5;
235 print("SLOWNESS: Synchronous debug output is enabled!");
236 }
237 }
238
239 void draw_main(void)
240 {
241 glEnable(GL_CULL_FACE);
242 glDisable(GL_TEXTURE_2D);
243 glDisable(GL_LIGHTING);
244 glEnable(GL_DEPTH_TEST);
245 #ifdef REVERSE_DEPTH
246 glDepthFunc(GL_GREATER);
247 glClearDepth(0);
248 #else
249 glDepthFunc(GL_LESS);
250 glClearDepth(1);
251 #endif
252 glDepthMask(GL_TRUE);
253 glDisable(GL_SCISSOR_TEST);
254 glClearColor(0.6f,0.7f,0.9f,0.0f);
255 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
256
257 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
258 glColor3f(1,1,1);
259 glFrontFace(GL_CW);
260 glEnable(GL_TEXTURE_2D);
261 glDisable(GL_BLEND);
262
263
264 glMatrixMode(GL_PROJECTION);
265 glLoadIdentity();
266
267 #ifdef REVERSE_DEPTH
268 stbgl_Perspective(player_zoom, 90, 70, 3000, 1.0/16);
269 #else
270 stbgl_Perspective(player_zoom, 90, 70, 1.0/16, 3000);
271 #endif
272
273 // now compute where the camera should be
274 glMatrixMode(GL_MODELVIEW);
275 glLoadIdentity();
276 stbgl_initCamera_zup_facing_y();
277
278 glRotatef(-camang[0],1,0,0);
279 glRotatef(-camang[2],0,0,1);
280 glTranslatef(-camloc[0], -camloc[1], -camloc[2]);
281
282 start_time = SDL_GetPerformanceCounter();
283 render_caves(camloc);
284 end_time = SDL_GetPerformanceCounter();
285
286 render_time = (end_time - start_time) / (float) SDL_GetPerformanceFrequency();
287
288 glMatrixMode(GL_PROJECTION);
289 glLoadIdentity();
290 gluOrtho2D(0,screen_x/2,screen_y/2,0);
291 glMatrixMode(GL_MODELVIEW);
292 glLoadIdentity();
293 glDisable(GL_TEXTURE_2D);
294 glDisable(GL_BLEND);
295 glDisable(GL_CULL_FACE);
296 draw_stats();
297 }
298
299
300
301 #pragma warning(disable:4244; disable:4305; disable:4018)
302
303 #define SCALE 2
304
305 void error(char *s)
306 {
307 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", s, NULL);
308 exit(0);
309 }
310
311 void ods(char *fmt, ...)
312 {
313 char buffer[1000];
314 va_list va;
315 va_start(va, fmt);
316 vsprintf(buffer, fmt, va);
317 va_end(va);
318 SDL_Log("%s", buffer);
319 }
320
321 #define TICKS_PER_SECOND 60
322
323 static SDL_Window *window;
324
325 extern void draw_main(void);
326 extern void process_tick(float dt);
327 extern void editor_init(void);
328
329 void draw(void)
330 {
331 draw_main();
332 SDL_GL_SwapWindow(window);
333 }
334
335
336 static int initialized=0;
337 static float last_dt;
338
339 int screen_x,screen_y;
340
341 float carried_dt = 0;
342 #define TICKRATE 60
343
344 float tex2_alpha = 1.0;
345
346 int raw_level_time;
347
348 float global_timer;
349 int global_hack;
350
351 int loopmode(float dt, int real, int in_client)
352 {
353 if (!initialized) return 0;
354
355 if (!real)
356 return 0;
357
358 // don't allow more than 6 frames to update at a time
359 if (dt > 0.075) dt = 0.075;
360
361 global_timer += dt;
362
363 carried_dt += dt;
364 while (carried_dt > 1.0/TICKRATE) {
365 if (global_hack) {
366 tex2_alpha += global_hack / 60.0f;
367 if (tex2_alpha < 0) tex2_alpha = 0;
368 if (tex2_alpha > 1) tex2_alpha = 1;
369 }
370 //update_input();
371 // if the player is dead, stop the sim
372 carried_dt -= 1.0/TICKRATE;
373 }
374
375 process_tick(dt);
376 draw();
377
378 return 0;
379 }
380
381 static int quit;
382
383 extern int controls;
384
385 void active_control_set(int key)
386 {
387 controls |= 1 << key;
388 }
389
390 void active_control_clear(int key)
391 {
392 controls &= ~(1 << key);
393 }
394
395 extern void update_view(float dx, float dy);
396
397 void process_sdl_mouse(SDL_Event *e)
398 {
399 update_view((float) e->motion.xrel / screen_x, (float) e->motion.yrel / screen_y);
400 }
401
402 void process_event(SDL_Event *e)
403 {
404 switch (e->type) {
405 case SDL_MOUSEMOTION:
406 process_sdl_mouse(e);
407 break;
408 case SDL_MOUSEBUTTONDOWN:
409 case SDL_MOUSEBUTTONUP:
410 break;
411
412 case SDL_QUIT:
413 quit = 1;
414 break;
415
416 case SDL_WINDOWEVENT:
417 switch (e->window.event) {
418 case SDL_WINDOWEVENT_SIZE_CHANGED:
419 screen_x = e->window.data1;
420 screen_y = e->window.data2;
421 loopmode(0,1,0);
422 break;
423 }
424 break;
425
426 case SDL_KEYDOWN: {
427 int k = e->key.keysym.sym;
428 int s = e->key.keysym.scancode;
429 SDL_Keymod mod;
430 mod = SDL_GetModState();
431 if (k == SDLK_ESCAPE)
432 quit = 1;
433
434 if (s == SDL_SCANCODE_D) active_control_set(0);
435 if (s == SDL_SCANCODE_A) active_control_set(1);
436 if (s == SDL_SCANCODE_W) active_control_set(2);
437 if (s == SDL_SCANCODE_S) active_control_set(3);
438 if (k == SDLK_SPACE) active_control_set(4);
439 if (s == SDL_SCANCODE_LCTRL) active_control_set(5);
440 if (s == SDL_SCANCODE_S) active_control_set(6);
441 if (s == SDL_SCANCODE_D) active_control_set(7);
442 if (k == '1') global_hack = !global_hack;
443 if (k == '2') global_hack = -1;
444
445 #if 0
446 if (game_mode == GAME_editor) {
447 switch (k) {
448 case SDLK_RIGHT: editor_key(STBTE_scroll_right); break;
449 case SDLK_LEFT : editor_key(STBTE_scroll_left ); break;
450 case SDLK_UP : editor_key(STBTE_scroll_up ); break;
451 case SDLK_DOWN : editor_key(STBTE_scroll_down ); break;
452 }
453 switch (s) {
454 case SDL_SCANCODE_S: editor_key(STBTE_tool_select); break;
455 case SDL_SCANCODE_B: editor_key(STBTE_tool_brush ); break;
456 case SDL_SCANCODE_E: editor_key(STBTE_tool_erase ); break;
457 case SDL_SCANCODE_R: editor_key(STBTE_tool_rectangle ); break;
458 case SDL_SCANCODE_I: editor_key(STBTE_tool_eyedropper); break;
459 case SDL_SCANCODE_L: editor_key(STBTE_tool_link); break;
460 case SDL_SCANCODE_G: editor_key(STBTE_act_toggle_grid); break;
461 }
462 if ((e->key.keysym.mod & KMOD_CTRL) && !(e->key.keysym.mod & ~KMOD_CTRL)) {
463 switch (s) {
464 case SDL_SCANCODE_X: editor_key(STBTE_act_cut ); break;
465 case SDL_SCANCODE_C: editor_key(STBTE_act_copy ); break;
466 case SDL_SCANCODE_V: editor_key(STBTE_act_paste); break;
467 case SDL_SCANCODE_Z: editor_key(STBTE_act_undo ); break;
468 case SDL_SCANCODE_Y: editor_key(STBTE_act_redo ); break;
469 }
470 }
471 }
472 #endif
473 break;
474 }
475 case SDL_KEYUP: {
476 int k = e->key.keysym.sym;
477 int s = e->key.keysym.scancode;
478 if (s == SDL_SCANCODE_D) active_control_clear(0);
479 if (s == SDL_SCANCODE_A) active_control_clear(1);
480 if (s == SDL_SCANCODE_W) active_control_clear(2);
481 if (s == SDL_SCANCODE_S) active_control_clear(3);
482 if (k == SDLK_SPACE) active_control_clear(4);
483 if (s == SDL_SCANCODE_LCTRL) active_control_clear(5);
484 if (s == SDL_SCANCODE_S) active_control_clear(6);
485 if (s == SDL_SCANCODE_D) active_control_clear(7);
486 break;
487 }
488 }
489 }
490
491 static SDL_GLContext *context;
492
493 static float getTimestep(float minimum_time)
494 {
495 float elapsedTime;
496 double thisTime;
497 static double lastTime = -1;
498
499 if (lastTime == -1)
500 lastTime = SDL_GetTicks() / 1000.0 - minimum_time;
501
502 for(;;) {
503 thisTime = SDL_GetTicks() / 1000.0;
504 elapsedTime = (float) (thisTime - lastTime);
505 if (elapsedTime >= minimum_time) {
506 lastTime = thisTime;
507 return elapsedTime;
508 }
509 // @TODO: compute correct delay
510 SDL_Delay(1);
511 }
512 }
513
514 void APIENTRY gl_debug(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *param)
515 {
516 ods("%s\n", message);
517 }
518
519 int is_synchronous_debug;
520 void enable_synchronous(void)
521 {
522 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
523 is_synchronous_debug = 1;
524 }
525
526 void prepare_threads(void);
527
528 //void stbwingraph_main(void)
529 int SDL_main(int argc, char **argv)
530 {
531 SDL_Init(SDL_INIT_VIDEO);
532
533 prepare_threads();
534
535 SDL_GL_SetAttribute(SDL_GL_RED_SIZE , 8);
536 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
537 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE , 8);
538 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
539
540 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
541 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
542 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
543
544 #ifdef GL_DEBUG
545 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
546 #endif
547
548 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
549
550 screen_x = 1920;
551 screen_y = 1080;
552
553 window = SDL_CreateWindow("caveview", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
554 screen_x, screen_y,
555 SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
556 );
557 if (!window) error("Couldn't create window");
558
559 context = SDL_GL_CreateContext(window);
560 if (!context) error("Couldn't create context");
561
562 SDL_GL_MakeCurrent(window, context); // is this true by default?
563
564 SDL_SetRelativeMouseMode(SDL_TRUE);
565 #if defined(_MSC_VER) && _MSC_VER < 1300
566 // work around broken behavior in VC6 debugging
567 if (IsDebuggerPresent())
568 SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1");
569 #endif
570
571 stbgl_initExtensions();
572
573 #ifdef GL_DEBUG
574 if (glDebugMessageCallbackARB) {
575 glDebugMessageCallbackARB(gl_debug, NULL);
576
577 enable_synchronous();
578 }
579 #endif
580
581 SDL_GL_SetSwapInterval(1);
582
583 render_init();
584 mesh_init();
585 world_init();
586
587 initialized = 1;
588
589 while (!quit) {
590 SDL_Event e;
591 while (SDL_PollEvent(&e))
592 process_event(&e);
593
594 loopmode(getTimestep(0.0166f/8), 1, 1);
595 }
596
597 return 0;
598 }