From: hgn Date: Fri, 7 Oct 2022 23:57:02 +0000 (+0100) Subject: dont remember X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=b9dedb4dd2a1e94ae76a3986716ee3c57e568213;p=carveJwlIkooP6JGAAIwe30JlM.git dont remember --- diff --git a/bvh.h b/bvh.h index 25be1e5..637b553 100644 --- a/bvh.h +++ b/bvh.h @@ -156,6 +156,11 @@ static void bh_create( bh_tree *bh, bh_system *sys, void *user, u32 item_count ) #endif } +static void bh_free( bh_tree *bh ) +{ + vg_free( bh->nodes ); +} + static void bh_debug_node( bh_tree *bh, u32 inode, v3f pos, u32 colour ) { bh_node *node = &bh->nodes[ inode ]; diff --git a/common.h b/common.h index a1cad24..3a3a23a 100644 --- a/common.h +++ b/common.h @@ -5,28 +5,8 @@ #define VG_FRAMEBUFFER_RESIZE 1 #include "vg/vg.h" -/* TODO: he needs a home somewhere */ static float ktimestep = 1.0f/60.0f; -/* TODO: he needs a home somewhere */ -enum classtype -{ - k_classtype_none = 0, - k_classtype_gate = 1, - k_classtype_block = 2, - k_classtype_spawn = 3, - k_classtype_water = 4, - k_classtype_car_path = 5, - k_classtype_instance = 6, - k_classtype_capsule = 7, - k_classtype_route_node = 8, - k_classtype_route = 9, - k_classtype_bone = 10, - k_classtype_skeleton = 11, - k_classtype_skin = 12 -}; - -/* TODO: he needs a home somewhere */ typedef struct ray_hit ray_hit; struct ray_hit { @@ -37,5 +17,4 @@ struct ray_hit static int network_scores_updated = 0; - #endif /* COMMON_H */ diff --git a/example_client.c b/example_client.c deleted file mode 100644 index d6a08a3..0000000 --- a/example_client.c +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved - -#define _DEFAULT_SOURCE -#include -#include - -#define VG_SERVER -#include "vg/vg.h" -#include "vg/vg_steam.h" -#include "vg/vg_steam_networking.h" -#include "vg/vg_steam_auth.h" -#include "/home/harry/Documents/carve/network_msg.h" - -volatile sig_atomic_t sig_stop; - -void inthandler( int signum ) -{ - sig_stop = 1; -} - -/* - * Runtime connection stuff - */ - -static u8 steam_app_ticket[ 1024 ]; -static u32 steam_app_ticket_length; - -static HSteamNetConnection cremote; -static ESteamNetworkingConnectionState cremote_state = - k_ESteamNetworkingConnectionState_None; - -/* - * Steam API - */ -void *hSteamNetworkingSockets, - *hSteamUser; - -static void scores_update(void); - -static void handle_steam_callback( CallbackMsg_t *msg ) -{ - if( msg->m_iCallback == k_iSteamNetConnectionStatusChangedCallBack ) - { - SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam; - vg_info( " Connection status changed for %lu\n", info->m_hConn ); - - vg_info( " %s -> %s\n", - string_ESteamNetworkingConnectionState(info->m_info.m_eState) ); - string_ESteamNetworkingConnectionState(info->m_eOldState) ); - - if( info->m_hConn == cremote ) - { - cremote_state = info->m_info.m_eState; - if( info->m_info.m_eState == - k_ESteamNetworkingConnectionState_Connected ) - { - vg_success(" Connected to remote server\n"); - scores_update(); - } - } - else - { - vg_warn( " Recieved signal from unkown connection\n" ); - } - } -} - -static void on_auth_ticket_recieved( void *result, void *context ) -{ - EncryptedAppTicketResponse_t *response = result; - - if( response->m_eResult == k_EResultOK ) - { - vg_info( " New app ticket ready\n" ); - } - else - { - vg_warn( " Could not request new encrypted app ticket (%u)\n", - response->m_eResult ); - } - - if( SteamAPI_ISteamUser_GetEncryptedAppTicket( hSteamUser, - steam_app_ticket, - vg_list_size(steam_app_ticket), - &steam_app_ticket_length )) - { - vg_success( " Loaded app ticket (%u bytes)\n", steam_app_ticket_length ); - } - else - { - vg_error( " No ticket availible\n" ); - steam_app_ticket_length = 0; - } -} - -static void request_auth_ticket(void) -{ - /* - * TODO Check for one thats cached on the disk and load it. - * This might be OK though because steam seems to cache the result - */ - - vg_info( "Requesting new authorization ticket\n" ); - steam_async *call = steam_new_async(); - call->data = NULL; - call->p_handler = on_auth_ticket_recieved; - call->id = SteamAPI_ISteamUser_RequestEncryptedAppTicket( hSteamUser, - NULL, 0 ); -} - -static void server_connect(void) -{ - /* Connect to server if not connected */ - - SteamNetworkingIPAddr remoteAddr; - -#define USE_LOCALHOST -#ifdef USE_LOCALHOST - SteamAPI_SteamNetworkingIPAddr_SetIPv6LocalHost( &remoteAddr, 27402 ); -#else - const char *server_lon1 = "46.101.34.155:27402"; - SteamAPI_SteamNetworkingIPAddr_ParseString( &remoteAddr, server_lon1 ); -#endif - - char buf[256]; - SteamAPI_SteamNetworkingIPAddr_ToString( &remoteAddr, buf, 256, 1 ); - vg_info( "connect to: %s\n", buf ); - - cremote = SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress( - hSteamNetworkingSockets, &remoteAddr, 0, NULL ); -} - -static void scores_update(void) -{ - vg_log( "scores_update()\n" ); - - if( cremote_state == k_ESteamNetworkingConnectionState_Connected ) - { - /* - * request updated scores - */ - netmsg_scores_request req; - req.inetmsg_id = k_inetmsg_scores_request; - - SteamAPI_ISteamNetworkingSockets_SendMessageToConnection( - hSteamNetworkingSockets, cremote, &req, - sizeof(netmsg_scores_request), - k_nSteamNetworkingSend_Reliable, NULL ); - } - else - { - /* - * if we are not connected, make a connection to the server and then in - * the future this function will be called again when it is connected - */ - server_connect(); - } -} - -static void poll_connection(void) -{ - SteamNetworkingMessage_t *messages[32]; - int len; - - while(1) - { - len = SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnConnection( - hSteamNetworkingSockets, cremote, messages, vg_list_size(messages)); - - if( len <= 0 ) - return; - - for( int i=0; im_cbSize < sizeof(netmsg_blank) ) - { - vg_warn( "Discarding message (too small: %d)\n", - msg->m_cbSize ); - continue; - } - - netmsg_blank *tmp = msg->m_pData; - if( tmp->inetmsg_id == k_inetmsg_scores_info ) - { - netmsg_scores_info *info = msg->m_pData; - vg_log( "Recieved %u score records\n", info->record_count ); - - SteamAPI_ISteamNetworkingSockets_CloseConnection( - hSteamNetworkingSockets, cremote, 0, NULL, 1 ); - cremote_state = k_ESteamNetworkingConnectionState_None; - } - - SteamAPI_SteamNetworkingMessage_t_Release( msg ); - } - } -} - -static u64 in_server_ticks( double seconds ) -{ - return (u64)(seconds / 0.1); -} - -int main( int argc, char *argv[] ) -{ - signal( SIGINT, inthandler ); - - if( !SteamAPI_Init() ) - { - vg_error( "Steamworks failed to initialize\n" ); - return 0; - } - - SteamAPI_ManualDispatch_Init(); - HSteamPipe hsteampipe = SteamAPI_GetHSteamPipe(); - vg_success( "Steamworks API running\n" ); - - /* Connect interfaces */ - hSteamNetworkingSockets = SteamAPI_SteamNetworkingSockets_SteamAPI(); - hSteamUser = SteamAPI_SteamUser(); - - request_auth_ticket(); - - /* TODO: Request current scores */ - -#if 0 - -#endif - - u64 server_ticks = 8000, last_update = 0; - - while( !sig_stop ) - { - steamworks_event_loop( hsteampipe, handle_steam_callback ); - poll_connection(); - - usleep(100000); - server_ticks ++; - - if( server_ticks > (last_update + in_server_ticks(60.0)) ) - { - last_update = server_ticks; - scores_update(); - } - } - - vg_info( "Shutting down\n..." ); - SteamAPI_Shutdown(); - - return 0; -} diff --git a/highscores.h b/highscores.h index 7ea5413..0136886 100644 --- a/highscores.h +++ b/highscores.h @@ -314,7 +314,6 @@ static aatree_ptr highscores_push_record( highscore_record *record ) { struct highscore_system *sys = &highscore_system; - /* TODO: Verify steam ID */ vg_low( "Inserting record into database for track %hu\n",record->trackid ); if( record->trackid >= vg_list_size(sys->dbheader.tracks) ) diff --git a/model.h b/model.h index d72e93c..02e85bc 100644 --- a/model.h +++ b/model.h @@ -21,6 +21,24 @@ typedef struct mdl_keyframe mdl_keyframe; #define MDL_SUBMESH_MAX 8000 #define MDL_STRING_LENGTH_MAX 64 +enum classtype +{ + k_classtype_none = 0, + k_classtype_gate = 1, + k_classtype_block = 2, + k_classtype_spawn = 3, + k_classtype_water = 4, + k_classtype_car_path = 5, + k_classtype_instance = 6, + k_classtype_capsule = 7, + k_classtype_route_node = 8, + k_classtype_route = 9, + k_classtype_bone = 10, + k_classtype_skeleton = 11, + k_classtype_skin = 12 +}; + + #pragma pack(push,1) struct mdl_vert diff --git a/player_ragdoll.h b/player_ragdoll.h index 7fff465..be75064 100644 --- a/player_ragdoll.h +++ b/player_ragdoll.h @@ -3,7 +3,7 @@ #include "player.h" -static float k_ragdoll_floatyiness = 10.0f, +static float k_ragdoll_floatyiness = 40.0f, k_ragdoll_floatydrag = 1.0f; /* @@ -58,7 +58,6 @@ static void player_init_ragdoll( mdl_header *src ) } } - /* TODO: refactor to use this style elswhere */ struct mdl_node *pnode = mdl_node_from_id( src, bone->orig_node ); struct classtype_bone *bone_inf = mdl_get_entdata( src, pnode ); diff --git a/render.h b/render.h index 706cf9b..cac188d 100644 --- a/render.h +++ b/render.h @@ -257,9 +257,87 @@ static void render_fb_resize(void) } } -/* - * Vg - */ +/* used for drawing player onto */ +static void render_init_temp_buffer(void) +{ + vg_info( "[render] Allocate temporary framebuffer\n" ); + + glGenFramebuffers( 1, &gpipeline.fb_background ); + glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_background ); + + glGenTextures( 1, &gpipeline.rgb_background ); + glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg_window_x, vg_window_y, + 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + gpipeline.rgb_background, 0); + + VG_CHECK_GL_ERR(); +} + +/* used for drawing world depth from the top view, used in our water and + * lighting calculations */ +static void render_init_depthmap_buffer(void) +{ + vg_info( "[render] Allocate depth map buffer\n" ); + + glGenFramebuffers( 1, &gpipeline.fb_depthmap ); + glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap ); + + glGenTextures( 1, &gpipeline.rgb_depthmap ); + glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_depthmap ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_R32F, 1024, 1024, 0, + GL_RED, GL_FLOAT, NULL ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + vg_tex2d_clamp(); + + glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + gpipeline.rgb_depthmap, 0); + + VG_CHECK_GL_ERR(); +} + +static void render_init_fs_quad(void) +{ + vg_info( "[render] Allocate quad\n" ); + + float quad[] = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f }; + + glGenVertexArrays( 1, &gpipeline.fsquad.vao ); + glGenBuffers( 1, &gpipeline.fsquad.vbo ); + glBindVertexArray( gpipeline.fsquad.vao ); + glBindBuffer( GL_ARRAY_BUFFER, gpipeline.fsquad.vbo ); + glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW ); + glBindVertexArray( gpipeline.fsquad.vao ); + glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, + sizeof(float)*2, (void*)0 ); + glEnableVertexAttribArray( 0 ); + + VG_CHECK_GL_ERR(); +} + +static void render_init_uniform_buffers(void) +{ + vg_info( "[render] Allocate uniform buffer\n" ); + + glGenBuffers( 1, &gpipeline.ubo_world_lighting ); + glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting ); + glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting), + NULL, GL_DYNAMIC_DRAW ); + + render_update_lighting_ub(); + glBindBufferBase( GL_UNIFORM_BUFFER, 0, gpipeline.ubo_world_lighting ); + + VG_CHECK_GL_ERR(); +} + static void render_init(void) { shader_blit_register(); @@ -269,73 +347,12 @@ static void render_init(void) vg_acquire_thread_sync(); { - vg_info( "Allocating framebuffers\n" ); - - glGenFramebuffers( 1, &gpipeline.fb_background ); - glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_background ); - - glGenTextures( 1, &gpipeline.rgb_background ); - glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg_window_x, vg_window_y, - 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - gpipeline.rgb_background, 0); - - VG_CHECK_GL_ERR(); - - /* - * World depth map, maybe this should be moved to world.h - * TODO: review - */ - glGenFramebuffers( 1, &gpipeline.fb_depthmap ); - glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap ); - - glGenTextures( 1, &gpipeline.rgb_depthmap ); - glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_depthmap ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_R32F, 1024, 1024, 0, - GL_RED, GL_FLOAT, NULL ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - vg_tex2d_clamp(); - - glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - gpipeline.rgb_depthmap, 0); - - VG_CHECK_GL_ERR(); - - float quad[] = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f }; - - glGenVertexArrays( 1, &gpipeline.fsquad.vao ); - glGenBuffers( 1, &gpipeline.fsquad.vbo ); - glBindVertexArray( gpipeline.fsquad.vao ); - glBindBuffer( GL_ARRAY_BUFFER, gpipeline.fsquad.vbo ); - glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW ); - glBindVertexArray( gpipeline.fsquad.vao ); - glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, - sizeof(float)*2, (void*)0 ); - glEnableVertexAttribArray( 0 ); - - VG_CHECK_GL_ERR(); - - glGenBuffers( 1, &gpipeline.ubo_world_lighting ); - glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting ); - glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting), - NULL, GL_DYNAMIC_DRAW ); - - render_update_lighting_ub(); - glBindBufferBase( GL_UNIFORM_BUFFER, 0, gpipeline.ubo_world_lighting ); - - VG_CHECK_GL_ERR(); + render_init_temp_buffer(); + render_init_depthmap_buffer(); + render_init_fs_quad(); + render_init_uniform_buffers(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - vg_success( "Done\n" ); - gpipeline.ready = 1; } @@ -344,14 +361,16 @@ static void render_init(void) static void render_free(void *_) { + glDeleteBuffers( 1, &gpipeline.ubo_world_lighting ); + glDeleteVertexArrays( 1, &gpipeline.fsquad.vao ); glDeleteBuffers( 1, &gpipeline.fsquad.vbo ); - glDeleteFramebuffers( 1, &gpipeline.fb_background ); glDeleteFramebuffers( 1, &gpipeline.fb_depthmap ); + glDeleteTextures( 1, &gpipeline.rgb_depthmap ); + glDeleteFramebuffers( 1, &gpipeline.fb_background ); glDeleteTextures( 1, &gpipeline.rgb_background ); - glDeleteTextures( 1, &gpipeline.rgb_depthmap ); } /* diff --git a/rigidbody.h b/rigidbody.h index 29e8cea..0a95bdd 100644 --- a/rigidbody.h +++ b/rigidbody.h @@ -629,7 +629,6 @@ static void closest_on_triangle( v3f p, v3f tri[3], v3f dest ) v3_muladds( dest, ac, w, dest ); } -/* TODO */ static void closest_on_triangle_1( v3f p, v3f tri[3], v3f dest ) { v3f ab, ac, ap; @@ -1073,7 +1072,6 @@ static int rb_capsule_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf ) v3_sub( c1, p1, d1 ); v3_sub( p1, p0, da ); - /* TODO: ? */ v3_normalize(d0); v3_normalize(d1); v3_normalize(da); @@ -1331,7 +1329,6 @@ static int rb_box_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf ) axis = 1; } - /* TODO: THIS IS WRONG DIRECTION */ float cz = -v3_dot( rba->forward, n ); if( fabsf(cz) > fabsf(best) ) { @@ -1477,7 +1474,7 @@ static int rb_collide( rigidbody *rba, rigidbody *rbb ) } /* - * TODO: Replace this with a more dedicated broad phase pass + * FUTURE: Replace this with a more dedicated broad phase pass */ if( box_overlap( rba->bbx_world, rbb->bbx_world ) ) { @@ -1738,7 +1735,6 @@ static void rb_limit_cure( rigidbody *ra, rigidbody *rb, v3f axis, float d ) static void rb_constraint_limits( rigidbody *ra, v3f lca, rigidbody *rb, v3f lcb, v3f limits[2] ) { - /* TODO: Code dupe remover */ v3f ax, ay, az, bx, by, bz; m3x3_mulv( ra->to_world, (v3f){1.0f,0.0f,0.0f}, ax ); m3x3_mulv( ra->to_world, (v3f){0.0f,1.0f,0.0f}, ay ); diff --git a/scene.h b/scene.h index d4d81ec..a4f6bd1 100644 --- a/scene.h +++ b/scene.h @@ -169,8 +169,6 @@ static void scene_free_offline_buffers( scene *pscene ) static void scene_free( scene *pscene ) { scene_free_offline_buffers( pscene ); - - /* TODO: bvh */ } /* diff --git a/world_gate.h b/world_gate.h index 083d68b..89945b9 100644 --- a/world_gate.h +++ b/world_gate.h @@ -1,27 +1,30 @@ #ifndef WORLD_GATE_H #define WORLD_GATE_H +#define GATE_RENDER_PERFORMANCE + #include "common.h" #include "model.h" #include "render.h" -#include "shaders/gate.h" -#include "shaders/gatelq.h" + +#ifndef GATE_RENDER_PERFORMANCE + #include "shaders/gate.h" +#else + #include "shaders/gatelq.h" +#endif + #include "world_water.h" + typedef struct teleport_gate teleport_gate; static struct { struct framebuffer fb; glmesh mdl; - - int high_qual; /* If in high performance mode, we don't use RT's, and - instead use stencil buffers. - There is therefore no heat warp effect. */ } grender = { - .high_qual = 0, .fb = { .format = GL_RGB, .div = 1 @@ -45,8 +48,12 @@ static void gate_transform_update( teleport_gate *gate ) static void world_gates_init(void) { vg_info( "world_gates_init\n" ); + +#ifndef GATE_RENDER_PERFORMANCE shader_gate_register(); +#else shader_gatelq_register(); +#endif mdl_header *mgate = mdl_load( "models/rs_gate.mdl" ); @@ -126,14 +133,11 @@ static int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera ) m4x4_mul( projection, view, projection ); - if( grender.high_qual ) - { +#ifndef GATE_RENDER_PERFORMANCE fb_use( &grender.fb ); glClearColor( 0.11f, 0.35f, 0.37f, 1.0f ); glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); - } - else - { +#else shader_gatelq_use(); shader_gatelq_uPv( vg_pv ); shader_gatelq_uMdl( gate_xform ); @@ -154,14 +158,14 @@ static int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera ) glClear( GL_DEPTH_BUFFER_BIT ); glStencilFunc( GL_EQUAL, 1, 0xFF ); glStencilMask( 0x00 ); - } +#endif render_world( projection, cam_new ); - if( grender.high_qual ) - { +#ifndef GATE_RENDER_PERFORMANCE + /* - * TODO: Need to find a way to draw a stencil buffer into the water + * NOTE: Need to find a way to draw a stencil buffer into the water * rendering */ @@ -194,9 +198,7 @@ static int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera ) mesh_draw( &grender.mdl ); glDisable(GL_BLEND); - } - else - { +#else glDisable( GL_STENCIL_TEST ); render_water_texture( cam_new ); @@ -208,7 +210,7 @@ static int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera ) glStencilMask( 0xFF ); glStencilFunc( GL_ALWAYS, 1, 0xFF ); glDisable( GL_STENCIL_TEST ); - } +#endif return 1; } diff --git a/world_gen.h b/world_gen.h index 4906603..030af6b 100644 --- a/world_gen.h +++ b/world_gen.h @@ -1,6 +1,11 @@ #ifndef WORLD_GEN_H #define WORLD_GEN_H +/* + * FUTURE: + * If we have multiple levels, write an unloader + */ + #include "world.h" static void world_add_all_if_material( m4x3f transform, scene *pscene,