2015-02-23 02:52:03 +03:00
# define _WIN32_WINNT 0x400
# include <assert.h>
# include <windows.h>
2015-03-12 10:07:50 +03:00
// stb.h
2015-02-23 02:52:03 +03:00
# define STB_DEFINE
# include "stb.h"
2015-03-12 10:07:50 +03:00
// stb_gl.h
# define STB_GL_IMPLEMENTATION
# define STB_GLEXT_DEFINE "glext_list.h"
# include "stb_gl.h"
2015-02-23 02:52:03 +03:00
2015-03-12 10:07:50 +03:00
// SDL
2015-02-23 02:52:03 +03:00
# include "sdl.h"
# include "SDL_opengl.h"
2015-03-12 10:07:50 +03:00
// stb_glprog.h
2015-02-23 02:52:03 +03:00
# define STB_GLPROG_IMPLEMENTATION
# define STB_GLPROG_ARB_DEFINE_EXTENSIONS
# include "stb_glprog.h"
2015-03-12 10:07:50 +03:00
// stb_image.h
# define STB_IMAGE_IMPLEMENTATION
# include "stb_image.h"
// stb_easy_font.h
2015-02-23 02:52:03 +03:00
# include "stb_easy_font.h" // doesn't require an IMPLEMENTATION
# include "caveview.h"
char * game_name = " caveview " ;
2015-03-12 10:07:50 +03:00
# define REVERSE_DEPTH
2015-02-23 02:52:03 +03:00
2015-03-12 10:07:50 +03:00
static void print_string ( float x , float y , char * text , float r , float g , float b )
2015-02-23 02:52:03 +03:00
{
static char buffer [ 99999 ] ;
int num_quads ;
num_quads = stb_easy_font_print ( x , y , text , NULL , buffer , sizeof ( buffer ) ) ;
glColor3f ( r , g , b ) ;
glEnableClientState ( GL_VERTEX_ARRAY ) ;
glVertexPointer ( 2 , GL_FLOAT , 16 , buffer ) ;
glDrawArrays ( GL_QUADS , 0 , num_quads * 4 ) ;
glDisableClientState ( GL_VERTEX_ARRAY ) ;
}
2015-03-12 10:07:50 +03:00
static float text_color [ 3 ] ;
static float pos_x = 10 ;
static float pos_y = 10 ;
2015-02-23 02:52:03 +03:00
2015-03-12 10:07:50 +03:00
static void print ( char * text , . . . )
2015-02-23 02:52:03 +03:00
{
char buffer [ 999 ] ;
va_list va ;
va_start ( va , text ) ;
vsprintf ( buffer , text , va ) ;
va_end ( va ) ;
print_string ( pos_x , pos_y , buffer , text_color [ 0 ] , text_color [ 1 ] , text_color [ 2 ] ) ;
pos_y + = 10 ;
}
2015-03-13 05:03:49 +03:00
float camang [ 3 ] , camloc [ 3 ] = { 60 , 22 , 77 } ;
2015-02-23 02:52:03 +03:00
float player_zoom = 1.0 ;
float rotate_view = 0.0 ;
void camera_to_worldspace ( float world [ 3 ] , float cam_x , float cam_y , float cam_z )
{
float vec [ 3 ] = { cam_x , cam_y , cam_z } ;
float t [ 3 ] ;
float s , c ;
s = ( float ) sin ( camang [ 0 ] * 3.141592 / 180 ) ;
c = ( float ) cos ( camang [ 0 ] * 3.141592 / 180 ) ;
t [ 0 ] = vec [ 0 ] ;
t [ 1 ] = c * vec [ 1 ] - s * vec [ 2 ] ;
t [ 2 ] = s * vec [ 1 ] + c * vec [ 2 ] ;
s = ( float ) sin ( camang [ 2 ] * 3.141592 / 180 ) ;
c = ( float ) cos ( camang [ 2 ] * 3.141592 / 180 ) ;
world [ 0 ] = c * t [ 0 ] - s * t [ 1 ] ;
world [ 1 ] = s * t [ 0 ] + c * t [ 1 ] ;
world [ 2 ] = t [ 2 ] ;
}
// camera worldspace velocity
float cam_vel [ 3 ] ;
int controls ;
# define MAX_VEL 150.0f // blocks per second
# define ACCEL 6.0f
# define DECEL 3.0f
# define STATIC_FRICTION DECEL
# define EFFECTIVE_ACCEL (ACCEL+DECEL)
// dynamic friction:
//
// if going at MAX_VEL, ACCEL and friction must cancel
// EFFECTIVE_ACCEL = DECEL + DYNAMIC_FRIC*MAX_VEL
# define DYNAMIC_FRICTION (ACCEL / (float)MAX_VEL)
float view_x_vel = 0 ;
float view_z_vel = 0 ;
float pending_view_x ;
float pending_view_z ;
float pending_view_x ;
float pending_view_z ;
void process_tick_raw ( float dt )
{
int i ;
float thrust [ 3 ] = { 0 , 0 , 0 } ;
float world_thrust [ 3 ] ;
// choose direction to apply thrust
thrust [ 0 ] = ( controls & 3 ) = = 1 ? EFFECTIVE_ACCEL : ( controls & 3 ) = = 2 ? - EFFECTIVE_ACCEL : 0 ;
thrust [ 1 ] = ( controls & 12 ) = = 4 ? EFFECTIVE_ACCEL : ( controls & 12 ) = = 8 ? - EFFECTIVE_ACCEL : 0 ;
thrust [ 2 ] = ( controls & 48 ) = = 16 ? EFFECTIVE_ACCEL : ( controls & 48 ) = = 32 ? - EFFECTIVE_ACCEL : 0 ;
// @TODO clamp thrust[0] & thrust[1] vector length to EFFECTIVE_ACCEL
camera_to_worldspace ( world_thrust , thrust [ 0 ] , thrust [ 1 ] , 0 ) ;
world_thrust [ 2 ] + = thrust [ 2 ] ;
for ( i = 0 ; i < 3 ; + + i ) {
float acc = world_thrust [ i ] ;
cam_vel [ i ] + = acc * dt ;
}
if ( cam_vel [ 0 ] | | cam_vel [ 1 ] | | cam_vel [ 2 ] )
{
float vel = ( float ) sqrt ( cam_vel [ 0 ] * cam_vel [ 0 ] + cam_vel [ 1 ] * cam_vel [ 1 ] + cam_vel [ 2 ] * cam_vel [ 2 ] ) ;
float newvel = vel ;
float dec = STATIC_FRICTION + DYNAMIC_FRICTION * vel ;
newvel = vel - dec * dt ;
if ( newvel < 0 )
newvel = 0 ;
cam_vel [ 0 ] * = newvel / vel ;
cam_vel [ 1 ] * = newvel / vel ;
cam_vel [ 2 ] * = newvel / vel ;
}
camloc [ 0 ] + = cam_vel [ 0 ] * dt ;
camloc [ 1 ] + = cam_vel [ 1 ] * dt ;
camloc [ 2 ] + = cam_vel [ 2 ] * dt ;
view_x_vel * = ( float ) pow ( 0.75 , dt ) ;
view_z_vel * = ( float ) pow ( 0.75 , dt ) ;
view_x_vel + = ( pending_view_x - view_x_vel ) * dt * 60 ;
view_z_vel + = ( pending_view_z - view_z_vel ) * dt * 60 ;
pending_view_x - = view_x_vel * dt ;
pending_view_z - = view_z_vel * dt ;
camang [ 0 ] + = view_x_vel * dt ;
camang [ 2 ] + = view_z_vel * dt ;
camang [ 0 ] = stb_clamp ( camang [ 0 ] , - 90 , 90 ) ;
camang [ 2 ] = ( float ) fmod ( camang [ 2 ] , 360 ) ;
}
void process_tick ( float dt )
{
while ( dt > 1.0f / 60 ) {
process_tick_raw ( 1.0f / 60 ) ;
dt - = 1.0f / 60 ;
}
process_tick_raw ( dt ) ;
}
void update_view ( float dx , float dy )
{
// hard-coded mouse sensitivity, not resolution independent?
pending_view_z - = dx * 300 ;
pending_view_x - = dy * 700 ;
}
extern int screen_x , screen_y ;
extern int is_synchronous_debug ;
float render_time ;
extern int chunk_locations , chunks_considered , chunks_in_frustum ;
extern int quads_considered , quads_rendered ;
extern int chunk_storage_rendered , chunk_storage_considered , chunk_storage_total ;
extern int view_dist_in_chunks ;
extern int num_threads_active , num_meshes_started , num_meshes_uploaded ;
extern float chunk_server_activity ;
static Uint64 start_time , end_time ; // render time
float chunk_server_status [ 32 ] ;
int chunk_server_pos ;
void draw_stats ( void )
{
int i ;
static Uint64 last_frame_time ;
Uint64 cur_time = SDL_GetPerformanceCounter ( ) ;
float chunk_server = 0 ;
float frame_time = ( cur_time - last_frame_time ) / ( float ) SDL_GetPerformanceFrequency ( ) ;
last_frame_time = cur_time ;
chunk_server_status [ chunk_server_pos ] = chunk_server_activity ;
chunk_server_pos = ( chunk_server_pos + 1 ) % 32 ;
for ( i = 0 ; i < 32 ; + + i )
chunk_server + = chunk_server_status [ i ] / 32.0f ;
stb_easy_font_spacing ( - 0.75 ) ;
pos_y = 10 ;
text_color [ 0 ] = text_color [ 1 ] = text_color [ 2 ] = 1.0f ;
print ( " Frame time: %6.2fms, CPU frame render time: %5.2fms " , frame_time * 1000 , render_time * 1000 ) ;
print ( " Tris: %4.1fM drawn of %4.1fM in range " , 2 * quads_rendered / 1000000.0f , 2 * quads_considered / 1000000.0f ) ;
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 ) ;
print ( " Num mesh builds started this frame: %d; num uploaded this frame: %d \n " , num_meshes_started , num_meshes_uploaded ) ;
print ( " QChunks: %3d in frustum of %3d valid of %3d in range " , chunks_in_frustum , chunks_considered , chunk_locations ) ;
print ( " Mesh worker threads active: %d " , num_threads_active ) ;
print ( " View distance: %d blocks " , view_dist_in_chunks * 16 ) ;
print ( " %s " , glGetString ( GL_RENDERER ) ) ;
if ( is_synchronous_debug ) {
text_color [ 0 ] = 1.0 ;
text_color [ 1 ] = 0.5 ;
text_color [ 2 ] = 0.5 ;
print ( " SLOWNESS: Synchronous debug output is enabled! " ) ;
}
}
void draw_main ( void )
{
glEnable ( GL_CULL_FACE ) ;
glDisable ( GL_TEXTURE_2D ) ;
glDisable ( GL_LIGHTING ) ;
glEnable ( GL_DEPTH_TEST ) ;
# ifdef REVERSE_DEPTH
glDepthFunc ( GL_GREATER ) ;
glClearDepth ( 0 ) ;
# else
glDepthFunc ( GL_LESS ) ;
glClearDepth ( 1 ) ;
# endif
glDepthMask ( GL_TRUE ) ;
glDisable ( GL_SCISSOR_TEST ) ;
glClearColor ( 0.6f , 0.7f , 0.9f , 0.0f ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
glColor3f ( 1 , 1 , 1 ) ;
glFrontFace ( GL_CW ) ;
glEnable ( GL_TEXTURE_2D ) ;
glDisable ( GL_BLEND ) ;
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
# ifdef REVERSE_DEPTH
stbgl_Perspective ( player_zoom , 90 , 70 , 3000 , 1.0 / 16 ) ;
# else
stbgl_Perspective ( player_zoom , 90 , 70 , 1.0 / 16 , 3000 ) ;
# endif
// now compute where the camera should be
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
stbgl_initCamera_zup_facing_y ( ) ;
2015-03-12 10:07:50 +03:00
glRotatef ( - camang [ 0 ] , 1 , 0 , 0 ) ;
glRotatef ( - camang [ 2 ] , 0 , 0 , 1 ) ;
2015-02-23 02:52:03 +03:00
glTranslatef ( - camloc [ 0 ] , - camloc [ 1 ] , - camloc [ 2 ] ) ;
start_time = SDL_GetPerformanceCounter ( ) ;
render_caves ( camloc ) ;
end_time = SDL_GetPerformanceCounter ( ) ;
render_time = ( end_time - start_time ) / ( float ) SDL_GetPerformanceFrequency ( ) ;
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
gluOrtho2D ( 0 , screen_x / 2 , screen_y / 2 , 0 ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
glDisable ( GL_TEXTURE_2D ) ;
glDisable ( GL_BLEND ) ;
glDisable ( GL_CULL_FACE ) ;
draw_stats ( ) ;
}
# pragma warning(disable:4244; disable:4305; disable:4018)
# define SCALE 2
void error ( char * s )
{
SDL_ShowSimpleMessageBox ( SDL_MESSAGEBOX_ERROR , " Error " , s , NULL ) ;
exit ( 0 ) ;
}
void ods ( char * fmt , . . . )
{
char buffer [ 1000 ] ;
va_list va ;
va_start ( va , fmt ) ;
vsprintf ( buffer , fmt , va ) ;
va_end ( va ) ;
SDL_Log ( " %s " , buffer ) ;
}
# define TICKS_PER_SECOND 60
static SDL_Window * window ;
extern void draw_main ( void ) ;
extern void process_tick ( float dt ) ;
extern void editor_init ( void ) ;
void draw ( void )
{
draw_main ( ) ;
SDL_GL_SwapWindow ( window ) ;
}
static int initialized = 0 ;
static float last_dt ;
int screen_x , screen_y ;
float carried_dt = 0 ;
# define TICKRATE 60
2015-03-31 12:32:17 +03:00
float tex2_alpha = 1.0 ;
2015-02-23 02:52:03 +03:00
int raw_level_time ;
float global_timer ;
2015-03-31 12:32:17 +03:00
int global_hack ;
2015-02-23 02:52:03 +03:00
int loopmode ( float dt , int real , int in_client )
{
if ( ! initialized ) return 0 ;
if ( ! real )
return 0 ;
// don't allow more than 6 frames to update at a time
if ( dt > 0.075 ) dt = 0.075 ;
global_timer + = dt ;
carried_dt + = dt ;
while ( carried_dt > 1.0 / TICKRATE ) {
2015-03-31 12:32:17 +03:00
if ( global_hack ) {
tex2_alpha + = global_hack / 60.0f ;
if ( tex2_alpha < 0 ) tex2_alpha = 0 ;
if ( tex2_alpha > 1 ) tex2_alpha = 1 ;
}
2015-02-23 02:52:03 +03:00
//update_input();
// if the player is dead, stop the sim
carried_dt - = 1.0 / TICKRATE ;
}
process_tick ( dt ) ;
draw ( ) ;
return 0 ;
}
static int quit ;
extern int controls ;
void active_control_set ( int key )
{
controls | = 1 < < key ;
}
void active_control_clear ( int key )
{
controls & = ~ ( 1 < < key ) ;
}
extern void update_view ( float dx , float dy ) ;
void process_sdl_mouse ( SDL_Event * e )
{
update_view ( ( float ) e - > motion . xrel / screen_x , ( float ) e - > motion . yrel / screen_y ) ;
}
void process_event ( SDL_Event * e )
{
switch ( e - > type ) {
case SDL_MOUSEMOTION :
process_sdl_mouse ( e ) ;
break ;
case SDL_MOUSEBUTTONDOWN :
case SDL_MOUSEBUTTONUP :
break ;
case SDL_QUIT :
quit = 1 ;
break ;
case SDL_WINDOWEVENT :
switch ( e - > window . event ) {
case SDL_WINDOWEVENT_SIZE_CHANGED :
screen_x = e - > window . data1 ;
screen_y = e - > window . data2 ;
loopmode ( 0 , 1 , 0 ) ;
break ;
}
break ;
case SDL_KEYDOWN : {
int k = e - > key . keysym . sym ;
int s = e - > key . keysym . scancode ;
SDL_Keymod mod ;
mod = SDL_GetModState ( ) ;
2015-03-12 10:07:50 +03:00
if ( k = = SDLK_ESCAPE )
2015-02-23 02:52:03 +03:00
quit = 1 ;
if ( s = = SDL_SCANCODE_D ) active_control_set ( 0 ) ;
if ( s = = SDL_SCANCODE_A ) active_control_set ( 1 ) ;
if ( s = = SDL_SCANCODE_W ) active_control_set ( 2 ) ;
if ( s = = SDL_SCANCODE_S ) active_control_set ( 3 ) ;
if ( k = = SDLK_SPACE ) active_control_set ( 4 ) ;
if ( s = = SDL_SCANCODE_LCTRL ) active_control_set ( 5 ) ;
if ( s = = SDL_SCANCODE_S ) active_control_set ( 6 ) ;
if ( s = = SDL_SCANCODE_D ) active_control_set ( 7 ) ;
2015-03-31 12:32:17 +03:00
if ( k = = ' 1 ' ) global_hack = ! global_hack ;
if ( k = = ' 2 ' ) global_hack = - 1 ;
2015-02-23 02:52:03 +03:00
#if 0
if ( game_mode = = GAME_editor ) {
switch ( k ) {
case SDLK_RIGHT : editor_key ( STBTE_scroll_right ) ; break ;
case SDLK_LEFT : editor_key ( STBTE_scroll_left ) ; break ;
case SDLK_UP : editor_key ( STBTE_scroll_up ) ; break ;
case SDLK_DOWN : editor_key ( STBTE_scroll_down ) ; break ;
}
switch ( s ) {
case SDL_SCANCODE_S : editor_key ( STBTE_tool_select ) ; break ;
case SDL_SCANCODE_B : editor_key ( STBTE_tool_brush ) ; break ;
case SDL_SCANCODE_E : editor_key ( STBTE_tool_erase ) ; break ;
case SDL_SCANCODE_R : editor_key ( STBTE_tool_rectangle ) ; break ;
case SDL_SCANCODE_I : editor_key ( STBTE_tool_eyedropper ) ; break ;
case SDL_SCANCODE_L : editor_key ( STBTE_tool_link ) ; break ;
case SDL_SCANCODE_G : editor_key ( STBTE_act_toggle_grid ) ; break ;
}
if ( ( e - > key . keysym . mod & KMOD_CTRL ) & & ! ( e - > key . keysym . mod & ~ KMOD_CTRL ) ) {
switch ( s ) {
case SDL_SCANCODE_X : editor_key ( STBTE_act_cut ) ; break ;
case SDL_SCANCODE_C : editor_key ( STBTE_act_copy ) ; break ;
case SDL_SCANCODE_V : editor_key ( STBTE_act_paste ) ; break ;
case SDL_SCANCODE_Z : editor_key ( STBTE_act_undo ) ; break ;
case SDL_SCANCODE_Y : editor_key ( STBTE_act_redo ) ; break ;
}
}
}
# endif
break ;
}
case SDL_KEYUP : {
int k = e - > key . keysym . sym ;
int s = e - > key . keysym . scancode ;
if ( s = = SDL_SCANCODE_D ) active_control_clear ( 0 ) ;
if ( s = = SDL_SCANCODE_A ) active_control_clear ( 1 ) ;
if ( s = = SDL_SCANCODE_W ) active_control_clear ( 2 ) ;
if ( s = = SDL_SCANCODE_S ) active_control_clear ( 3 ) ;
if ( k = = SDLK_SPACE ) active_control_clear ( 4 ) ;
if ( s = = SDL_SCANCODE_LCTRL ) active_control_clear ( 5 ) ;
if ( s = = SDL_SCANCODE_S ) active_control_clear ( 6 ) ;
if ( s = = SDL_SCANCODE_D ) active_control_clear ( 7 ) ;
break ;
}
}
}
static SDL_GLContext * context ;
static float getTimestep ( float minimum_time )
{
float elapsedTime ;
double thisTime ;
static double lastTime = - 1 ;
if ( lastTime = = - 1 )
lastTime = SDL_GetTicks ( ) / 1000.0 - minimum_time ;
for ( ; ; ) {
thisTime = SDL_GetTicks ( ) / 1000.0 ;
elapsedTime = ( float ) ( thisTime - lastTime ) ;
if ( elapsedTime > = minimum_time ) {
lastTime = thisTime ;
return elapsedTime ;
}
// @TODO: compute correct delay
SDL_Delay ( 1 ) ;
}
}
void APIENTRY gl_debug ( GLenum source , GLenum type , GLuint id , GLenum severity , GLsizei length , const GLchar * message , const void * param )
{
ods ( " %s \n " , message ) ;
}
int is_synchronous_debug ;
void enable_synchronous ( void )
{
glEnable ( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB ) ;
is_synchronous_debug = 1 ;
}
void prepare_threads ( void ) ;
//void stbwingraph_main(void)
int SDL_main ( int argc , char * * argv )
{
SDL_Init ( SDL_INIT_VIDEO ) ;
prepare_threads ( ) ;
SDL_GL_SetAttribute ( SDL_GL_RED_SIZE , 8 ) ;
SDL_GL_SetAttribute ( SDL_GL_GREEN_SIZE , 8 ) ;
SDL_GL_SetAttribute ( SDL_GL_BLUE_SIZE , 8 ) ;
2015-04-01 20:41:49 +03:00
SDL_GL_SetAttribute ( SDL_GL_DEPTH_SIZE , 24 ) ;
2015-02-23 02:52:03 +03:00
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_PROFILE_MASK , SDL_GL_CONTEXT_PROFILE_COMPATIBILITY ) ;
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_MAJOR_VERSION , 3 ) ;
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_MINOR_VERSION , 1 ) ;
# ifdef GL_DEBUG
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_FLAGS , SDL_GL_CONTEXT_DEBUG_FLAG ) ;
# endif
SDL_GL_SetAttribute ( SDL_GL_MULTISAMPLESAMPLES , 4 ) ;
screen_x = 1920 ;
screen_y = 1080 ;
window = SDL_CreateWindow ( " caveview " , SDL_WINDOWPOS_UNDEFINED , SDL_WINDOWPOS_UNDEFINED ,
screen_x , screen_y ,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
) ;
if ( ! window ) error ( " Couldn't create window " ) ;
context = SDL_GL_CreateContext ( window ) ;
if ( ! context ) error ( " Couldn't create context " ) ;
SDL_GL_MakeCurrent ( window , context ) ; // is this true by default?
SDL_SetRelativeMouseMode ( SDL_TRUE ) ;
2015-03-13 05:03:49 +03:00
# if defined(_MSC_VER) && _MSC_VER < 1300
// work around broken behavior in VC6 debugging
if ( IsDebuggerPresent ( ) )
SDL_SetHint ( SDL_HINT_MOUSE_RELATIVE_MODE_WARP , " 1 " ) ;
# endif
2015-02-23 02:52:03 +03:00
stbgl_initExtensions ( ) ;
# ifdef GL_DEBUG
if ( glDebugMessageCallbackARB ) {
glDebugMessageCallbackARB ( gl_debug , NULL ) ;
enable_synchronous ( ) ;
}
# endif
2015-03-31 12:32:17 +03:00
SDL_GL_SetSwapInterval ( 1 ) ;
2015-02-23 02:52:03 +03:00
render_init ( ) ;
mesh_init ( ) ;
world_init ( ) ;
initialized = 1 ;
while ( ! quit ) {
SDL_Event e ;
while ( SDL_PollEvent ( & e ) )
process_event ( & e ) ;
loopmode ( getTimestep ( 0.0166f / 8 ) , 1 , 1 ) ;
}
return 0 ;
}