#include #include #include "game.h" #include "game/physics/movement.h" #include "game/world/bsp.h" #include "game/world/draw.h" #include "render/gl_2d.h" #include "render/gl_3d.h" #include "render/gl_2d_font.h" #include "editor/editor.h" #include "game/assets.h" #include "game/vars.h" #include "game/objlist.h" #include "game/world/map.h" #include "gui.h" #include "render/gl_batch.h" #include "util.h" #include "util/profiler.h" #include "util/time.h" CVAR* g_timescale = var_new( "g_timescale", 1.f ); static void game_realtime_resize_repaint( void* userdata ); GAME_DATA* game_init( GL_DATA* gl ) { GAME_DATA* game = (GAME_DATA*)malloc( sizeof( GAME_DATA ) ); memset( game, 0, sizeof(GAME_DATA) ); game->gl = gl; profiler_init(); VEC2 screensize = { (F32)gl->canvas_size[0], (F32)gl->canvas_size[1] }; game->shaders.gl2d = gl_2d_init( gl, screensize, "2d" ); game->shaders.gl3d = gl_3d_init( gl, screensize, "3d" ); game_create_batches( game ); assets_init( game ); assets_on_frame( game ); objl = objl_init(); gmove_init( game ); #if IS_EDITOR game->editor = editor_create( game ); #else gui_create( game ); game->state.ingame = 1; #endif gl_set_resize_repaint_callback( gl, game_realtime_resize_repaint, game ); return game; } void game_create_batches( GAME_DATA *game ) { game->render.batch_2d = gl_batch_create( game->gl, game->shaders.gl2d, &gl_2d_batch_setup ); game->render.batch_3d = gl_batch_create( game->gl, game->shaders.gl3d, &gl_3d_batch_setup ); } #if defined(DEBUG) && !IS_EDITOR void game_draw_fpsoverlay( GAME_DATA* game ) { GL_DATA* gl = game->gl; char buf[256]; sprintf( buf, "fps: %1.3f (%2.5f ms) %dx%d", gl->fps, gl->frametime, canvas[0], canvas[1] ); VEC2 dim = gl_font_dim( game->assets.font, buf ); gl_font_draw( game->assets.font, game->shaders.gl2d_texcoord, s_tr({ -dim.x - 30.f, dim.y + 5.f }), buf, (CLR){ 1.f, 1.f, 1.f, 1.f } ); } void game_draw_fontoverlay( GAME_DATA* game ) { for( U32 i = 0; i < 255; ++i ) { char str[64]; sprintf( str, "%d:%c", i, (char)i ); gl_font_draw( game->assets.jpn12, game->shaders.gl2d_texcoord, s_tl({ 10.f + ( i % 18 ) * 33, 280.f + floorf( i / 18.f ) * 14.f }), str, CLR::WHITE() ); } } #endif WORLD_MAP* game_load_map( GAME_DATA* game, const char* mapname ) { WORLD_MAP* m = map_from_file( game, mapname ); if( !m ) { dlog( "game_load_map() : failed to load file %s", mapname ); return 0; } bsp_build_map( m ); objl_load_world( game, m ); game->state.map = m; return m; } void game_unload_map( GAME_DATA* game ) { map_free( game, game->state.map ); game->state.map = 0; objl_clear( 1 ); } void game_draw( GAME_DATA* game ) { if( !objl->pl || !objl->world ) { dlog( "game_draw() : no world" ); return; } VEC2 window = { 270.f, 25.f }; VEC2 winsize = { 480.f, 360.f }; gl_2d_rect( game->shaders.gl2d, window, winsize, (CLR){ 0.3f, 0.3f, 0.3f, 1.f } ); world_draw( game, objl->world, window, winsize ); } void game_realtime_resize_repaint( void* userdata ) { GAME_DATA* game = (GAME_DATA*)userdata; if( !game || !game->gl ) return; GL_DATA* gl = game->gl; GL_SHADER_PROGRAM* gl2d = game->shaders.gl2d; if( !assets_on_frame( game ) ) return; gl_sync_window_size( gl ); #if IS_EDITOR if( game->editor && game->editor->wnd ) { if( game->editor->wnd->w != gl->canvas_size[0] || game->editor->wnd->h != gl->canvas_size[1] ) { editor_resize( game->editor, gl->canvas_size[0], gl->canvas_size[1] ); } } #endif gl_beginframe( gl ); gl_2d_frect( gl2d, s_tl(), s_br(), { 0.f, 0.f, 0.f, 1.f } ); if( game->state.ingame ) game_draw( game ); gui_draw( game ); #if defined(DEBUG) && !IS_EDITOR game_draw_fpsoverlay( game ); #endif SDL_GL_SwapWindow( gl->window ); } U8 game_main_loop( GAME_DATA* game ) { _profiled GL_DATA* gl = game->gl; GL_SHADER_PROGRAM* gl2d = game->shaders.gl2d; if( !OK( gl_poll_events( gl ) ) ) return 1; if( !assets_on_frame( game ) ) return 0; gl_sync_window_size( gl ); gl_beginframe( gl ); #if IS_EDITOR if( game->editor && game->editor->wnd ) { if( game->editor->wnd->w != gl->canvas_size[0] || game->editor->wnd->h != gl->canvas_size[1] ) { editor_resize( game->editor, gl->canvas_size[0], gl->canvas_size[1] ); } } #endif gl_2d_frect( gl2d, s_tl(), s_br(), { 0.f, 0.f, 0.f, 1.f } ); player_input( game, objl->pl ); if( game->state.ingame ) { game_on_tick( game ); game_draw( game ); } gui_onframe( game ); profiler_draw_tree( game->assets.jpn12 ); #if defined(DEBUG) && !IS_EDITOR game_draw_fpsoverlay( game ); #endif if( !OK( gl_endframe( gl ) ) ) return 1; return 0; } void game_on_tick( GAME_DATA* game ) { _profiled U64 tick = u_tick(); U64 ticks = TICK_INTERVAL * TICK_RESOLUTION; F32 ts = var_getf( g_timescale ); if( ts != 1.f && ts > 0.f ) ticks *= (1.f / ts); else if( !ts ) ticks = INT64_MAX; if( tick - game->state.last_tick > ticks ) { player_move( game, objl->pl ); game->state.last_tick = tick; } } void game_destroy( GAME_DATA *game ) { gl_batch_destroy( game->render.batch_2d ); gl_batch_destroy( game->render.batch_3d ); free( game ); }