1 #define _WIN32_WINNT 0x400
11 #define STB_GL_IMPLEMENTATION
12 #define STB_GLEXT_DEFINE "glext_list.h"
17 #include "SDL_opengl.h"
20 #define STB_GLPROG_IMPLEMENTATION
21 #define STB_GLPROG_ARB_DEFINE_EXTENSIONS
22 #include "stb_glprog.h"
25 #define STB_IMAGE_IMPLEMENTATION
26 #include "stb_image.h"
29 #include "stb_easy_font.h" // doesn't require an IMPLEMENTATION
33 char *game_name
= "caveview";
40 static void print_string(float x
, float y
, char *text
, float r
, float g
, float b
)
42 static char buffer
[99999];
45 num_quads
= stb_easy_font_print(x
, y
, text
, NULL
, buffer
, sizeof(buffer
));
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
);
54 static float text_color
[3];
55 static float pos_x
= 10;
56 static float pos_y
= 10;
58 static void print(char *text
, ...)
63 vsprintf(buffer
, text
, va
);
65 print_string(pos_x
, pos_y
, buffer
, text_color
[0], text_color
[1], text_color
[2]);
69 float camang
[3], camloc
[3] = { 60,22,77 };
70 float player_zoom
= 1.0;
71 float rotate_view
= 0.0;
74 void camera_to_worldspace(float world
[3], float cam_x
, float cam_y
, float cam_z
)
76 float vec
[3] = { cam_x
, cam_y
, cam_z
};
79 s
= (float) sin(camang
[0]*3.141592/180);
80 c
= (float) cos(camang
[0]*3.141592/180);
83 t
[1] = c
*vec
[1] - s
*vec
[2];
84 t
[2] = s
*vec
[1] + c
*vec
[2];
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];
93 // camera worldspace velocity
98 #define MAX_VEL 150.0f // blocks per second
102 #define STATIC_FRICTION DECEL
103 #define EFFECTIVE_ACCEL (ACCEL+DECEL)
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)
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
;
118 void process_tick_raw(float dt
)
121 float thrust
[3] = { 0,0,0 };
122 float world_thrust
[3];
124 // choose direction to apply thrust
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;
130 // @TODO clamp thrust[0] & thrust[1] vector length to EFFECTIVE_ACCEL
132 camera_to_worldspace(world_thrust
, thrust
[0], thrust
[1], 0);
133 world_thrust
[2] += thrust
[2];
135 for (i
=0; i
< 3; ++i
) {
136 float acc
= world_thrust
[i
];
137 cam_vel
[i
] += acc
*dt
;
140 if (cam_vel
[0] || cam_vel
[1] || cam_vel
[2])
142 float vel
= (float) sqrt(cam_vel
[0]*cam_vel
[0] + cam_vel
[1]*cam_vel
[1] + cam_vel
[2]*cam_vel
[2]);
144 float dec
= STATIC_FRICTION
+ DYNAMIC_FRICTION
*vel
;
145 newvel
= vel
- dec
*dt
;
148 cam_vel
[0] *= newvel
/vel
;
149 cam_vel
[1] *= newvel
/vel
;
150 cam_vel
[2] *= newvel
/vel
;
153 camloc
[0] += cam_vel
[0] * dt
;
154 camloc
[1] += cam_vel
[1] * dt
;
155 camloc
[2] += cam_vel
[2] * dt
;
157 view_x_vel
*= (float) pow(0.75, dt
);
158 view_z_vel
*= (float) pow(0.75, dt
);
160 view_x_vel
+= (pending_view_x
- view_x_vel
)*dt
*60;
161 view_z_vel
+= (pending_view_z
- view_z_vel
)*dt
*60;
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);
171 void process_tick(float dt
)
173 while (dt
> 1.0f
/60) {
174 process_tick_raw(1.0f
/60);
177 process_tick_raw(dt
);
180 void update_view(float dx
, float dy
)
182 // hard-coded mouse sensitivity, not resolution independent?
183 pending_view_z
-= dx
*300;
184 pending_view_x
-= dy
*700;
187 extern int screen_x
, screen_y
;
188 extern int is_synchronous_debug
;
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
;
198 static Uint64 start_time
, end_time
; // render time
200 float chunk_server_status
[32];
201 int chunk_server_pos
;
203 void draw_stats(void)
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
;
213 chunk_server_status
[chunk_server_pos
] = chunk_server_activity
;
214 chunk_server_pos
= (chunk_server_pos
+1) %32;
216 for (i
=0; i
< 32; ++i
)
217 chunk_server
+= chunk_server_status
[i
] / 32.0f
;
219 stb_easy_font_spacing(-0.75);
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
));
231 if (is_synchronous_debug
) {
235 print("SLOWNESS: Synchronous debug output is enabled!");
241 glEnable(GL_CULL_FACE
);
242 glDisable(GL_TEXTURE_2D
);
243 glDisable(GL_LIGHTING
);
244 glEnable(GL_DEPTH_TEST
);
246 glDepthFunc(GL_GREATER
);
249 glDepthFunc(GL_LESS
);
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
);
257 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
260 glEnable(GL_TEXTURE_2D
);
264 glMatrixMode(GL_PROJECTION
);
268 stbgl_Perspective(player_zoom
, 90, 70, 3000, 1.0/16);
270 stbgl_Perspective(player_zoom
, 90, 70, 1.0/16, 3000);
273 // now compute where the camera should be
274 glMatrixMode(GL_MODELVIEW
);
276 stbgl_initCamera_zup_facing_y();
278 glRotatef(-camang
[0],1,0,0);
279 glRotatef(-camang
[2],0,0,1);
280 glTranslatef(-camloc
[0], -camloc
[1], -camloc
[2]);
282 start_time
= SDL_GetPerformanceCounter();
283 render_caves(camloc
);
284 end_time
= SDL_GetPerformanceCounter();
286 render_time
= (end_time
- start_time
) / (float) SDL_GetPerformanceFrequency();
288 glMatrixMode(GL_PROJECTION
);
290 gluOrtho2D(0,screen_x
/2,screen_y
/2,0);
291 glMatrixMode(GL_MODELVIEW
);
293 glDisable(GL_TEXTURE_2D
);
295 glDisable(GL_CULL_FACE
);
301 #pragma warning(disable:4244; disable:4305; disable:4018)
307 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR
, "Error", s
, NULL
);
311 void ods(char *fmt
, ...)
316 vsprintf(buffer
, fmt
, va
);
318 SDL_Log("%s", buffer
);
321 #define TICKS_PER_SECOND 60
323 static SDL_Window
*window
;
325 extern void draw_main(void);
326 extern void process_tick(float dt
);
327 extern void editor_init(void);
332 SDL_GL_SwapWindow(window
);
336 static int initialized
=0;
337 static float last_dt
;
339 int screen_x
,screen_y
;
341 float carried_dt
= 0;
344 float tex2_alpha
= 1.0;
351 int loopmode(float dt
, int real
, int in_client
)
353 if (!initialized
) return 0;
358 // don't allow more than 6 frames to update at a time
359 if (dt
> 0.075) dt
= 0.075;
364 while (carried_dt
> 1.0/TICKRATE
) {
366 tex2_alpha
+= global_hack
/ 60.0f
;
367 if (tex2_alpha
< 0) tex2_alpha
= 0;
368 if (tex2_alpha
> 1) tex2_alpha
= 1;
371 // if the player is dead, stop the sim
372 carried_dt
-= 1.0/TICKRATE
;
385 void active_control_set(int key
)
387 controls
|= 1 << key
;
390 void active_control_clear(int key
)
392 controls
&= ~(1 << key
);
395 extern void update_view(float dx
, float dy
);
397 void process_sdl_mouse(SDL_Event
*e
)
399 update_view((float) e
->motion
.xrel
/ screen_x
, (float) e
->motion
.yrel
/ screen_y
);
402 void process_event(SDL_Event
*e
)
405 case SDL_MOUSEMOTION
:
406 process_sdl_mouse(e
);
408 case SDL_MOUSEBUTTONDOWN
:
409 case SDL_MOUSEBUTTONUP
:
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
;
427 int k
= e
->key
.keysym
.sym
;
428 int s
= e
->key
.keysym
.scancode
;
430 mod
= SDL_GetModState();
431 if (k
== SDLK_ESCAPE
)
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;
446 if (game_mode
== GAME_editor
) {
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;
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;
462 if ((e
->key
.keysym
.mod
& KMOD_CTRL
) && !(e
->key
.keysym
.mod
& ~KMOD_CTRL
)) {
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;
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);
491 static SDL_GLContext
*context
;
493 static float getTimestep(float minimum_time
)
497 static double lastTime
= -1;
500 lastTime
= SDL_GetTicks() / 1000.0 - minimum_time
;
503 thisTime
= SDL_GetTicks() / 1000.0;
504 elapsedTime
= (float) (thisTime
- lastTime
);
505 if (elapsedTime
>= minimum_time
) {
509 // @TODO: compute correct delay
514 void APIENTRY
gl_debug(GLenum source
, GLenum type
, GLuint id
, GLenum severity
, GLsizei length
, const GLchar
*message
, const void *param
)
516 ods("%s\n", message
);
519 int is_synchronous_debug
;
520 void enable_synchronous(void)
522 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB
);
523 is_synchronous_debug
= 1;
526 void prepare_threads(void);
528 //void stbwingraph_main(void)
529 int SDL_main(int argc
, char **argv
)
531 SDL_Init(SDL_INIT_VIDEO
);
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);
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);
545 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS
, SDL_GL_CONTEXT_DEBUG_FLAG
);
548 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES
, 4);
553 window
= SDL_CreateWindow("caveview", SDL_WINDOWPOS_UNDEFINED
, SDL_WINDOWPOS_UNDEFINED
,
555 SDL_WINDOW_OPENGL
| SDL_WINDOW_RESIZABLE
557 if (!window
) error("Couldn't create window");
559 context
= SDL_GL_CreateContext(window
);
560 if (!context
) error("Couldn't create context");
562 SDL_GL_MakeCurrent(window
, context
); // is this true by default?
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");
571 stbgl_initExtensions();
574 if (glDebugMessageCallbackARB
) {
575 glDebugMessageCallbackARB(gl_debug
, NULL
);
577 enable_synchronous();
581 SDL_GL_SetSwapInterval(1);
591 while (SDL_PollEvent(&e
))
594 loopmode(getTimestep(0.0166f
/8), 1, 1);