diff options
33 files changed, 702 insertions, 202 deletions
@@ -6,3 +6,6 @@ cmake_install.cmake Makefile .cache/clangd/index compile_commands.json +build/* +settings.json +c_cpp_properties.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 3931ec5..fc2ce17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,30 +7,51 @@ set(CMAKE_CXX_STANDARD 17) file(GLOB_RECURSE SRC_FILES ./src/*.cpp ./src/game/*.cpp ./src/util/config/*.cpp) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build) +if(UNIX) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build) +else() + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +endif() add_executable(app ${SRC_FILES}) find_package(PkgConfig REQUIRED) -pkg_check_modules(GL REQUIRED gl) pkg_check_modules(SDL2 REQUIRED sdl2) pkg_check_modules(FREETYPE REQUIRED freetype2) +pkg_check_modules(GLEW REQUIRED glew) + +find_package(OpenGL REQUIRED) +# release build settings +set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wno-nontrivial-memcall") +# debug build settings +set(CMAKE_CXX_FLAGS_DEBUG "-g -DDEBUG=1 -fsanitize=address -Wno-nontrivial-memcall") -target_compile_options(app PRIVATE -Wall) target_include_directories(app PRIVATE ${SDL2_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS} - ${GL_INCLUDE_DIRS} -) -target_link_libraries(app PRIVATE - ${SDL2_LIBRARIES} - ${FREETYPE_LIBRARIES} - ${GL_LIBRARIES} + ${GLEW_INCLUDE_DIRS} + ${OPENGL_INCLUDE_DIR} ) -# release build settings -set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wno-nontrivial-memcall") -# debug build settings -set(CMAKE_CXX_FLAGS_DEBUG "-g -DDEBUG=1 -fsanitize=address -Wno-nontrivial-memcall") +# Platform-specific linking +if(WIN32) + target_link_libraries(app PRIVATE + ${SDL2_LIBRARIES} + ${FREETYPE_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + winmm # For timeGetDevCaps, timeBeginPeriod, timeEndPeriod + ) +else() + target_link_libraries(app PRIVATE + ${SDL2_LIBRARIES} + ${FREETYPE_LIBRARIES} + ${GLEW_LIBRARIES} + ${OPENGL_LIBRARIES} + ) +endif() + +target_compile_options(app PRIVATE -Wall) +target_compile_options(app PRIVATE -Wno-nontrivial-memcall) add_custom_target(debug COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_BINARY_DIR} @@ -44,4 +65,3 @@ add_custom_target(release WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Building ~~**RELEASE**~~" ) - diff --git a/assets/shaders/2d_texcoord.fsh b/assets/shaders/2d_texcoord.fsh index 276f305..38dc69c 100644 --- a/assets/shaders/2d_texcoord.fsh +++ b/assets/shaders/2d_texcoord.fsh @@ -2,17 +2,18 @@ uniform sampler2D g_samplers[255]; -const uint SAMPLER_ID_NONE = 255u; +const int SAMPLER_ID_NONE = 255; in vec2 g_texcoord; in vec4 g_color; -flat in uint g_sampler; +flat in int g_sampler; void main() { vec4 color = g_color; if( g_sampler != SAMPLER_ID_NONE ) { - color = texture2D( g_samplers[g_sampler], g_texcoord ); - color *= g_color; + vec4 tex_color = texture2D( g_samplers[g_sampler], g_texcoord ); + color *= tex_color; + if (color.a < 0.01) discard; } gl_FragColor = color; } diff --git a/assets/shaders/2d_texcoord.vsh b/assets/shaders/2d_texcoord.vsh index 3ccc8e7..80c7597 100644 --- a/assets/shaders/2d_texcoord.vsh +++ b/assets/shaders/2d_texcoord.vsh @@ -9,7 +9,7 @@ in float in_sampler; out vec2 g_texcoord; out vec4 g_color; -flat out uint g_sampler; +flat out int g_sampler; uniform vec4 g_screenratio; @@ -23,6 +23,6 @@ void main() { g_texcoord = in_texcoord; g_color = in_clr; - g_sampler = uint(in_sampler * 255 + 0.5); + g_sampler = int(in_sampler * 255.0 + 0.5); gl_Position = ( pos ) * g_screenratio; } diff --git a/assets/shaders/3d.fsh b/assets/shaders/3d.fsh index ee1208c..276f305 100644 --- a/assets/shaders/3d.fsh +++ b/assets/shaders/3d.fsh @@ -11,7 +11,7 @@ flat in uint g_sampler; void main() { vec4 color = g_color; if( g_sampler != SAMPLER_ID_NONE ) { - color = texture2D( g_samplers[int(g_sampler)], g_texcoord ); + color = texture2D( g_samplers[g_sampler], g_texcoord ); color *= g_color; } gl_FragColor = color; diff --git a/src/editor/editor.h b/src/editor/editor.h index 0bf2ab4..a4b1f1a 100644 --- a/src/editor/editor.h +++ b/src/editor/editor.h @@ -70,9 +70,13 @@ extern void editor_load_map_cb( void* ); extern void editor_new_map_cb( void* ); extern void editor_create_map_view( GAME_EDITOR* e ); +extern void editor_update_properties_column( GAME_EDITOR* e ); struct GUI_EDITORWINDOW : GUI_WINDOW {}; -struct GUI_EDITOR_3DVIEW : GUI_VIEW {}; +struct GUI_EDITOR_3DVIEW : GUI_VIEW { + U8 heldoutbounds; +}; + struct GUI_EDITOR_2DVIEW : GUI_VIEW { F32 scale; F32 posx, posy; diff --git a/src/editor/gui.cpp b/src/editor/gui.cpp index 71ce113..1060c00 100644 --- a/src/editor/gui.cpp +++ b/src/editor/gui.cpp @@ -121,57 +121,6 @@ void editor_create_tools_row( GAME_EDITOR* e ) { editor_update_active_tool_label( e ); } -void editor_update_view_settings( GAME_EDITOR* e ) { - GAME_EDITOR::EDITOR_GUI* egui = &e->gui; - - sprintf( egui->gridlabel->name, "grid size: %1.2f", e->grid ); -} - -void editor_grid_increment_cb( void* ) { - if( editor->grid < 16.f ) editor->grid *= 2.f; - editor_update_view_settings( editor ); - - if( editor->propgrid ) - editor_update_properties_column( editor ); -} - -void editor_grid_decrement_cb( void* ) { - if( editor->grid > 0.25f ) editor->grid *= 0.5f; - editor_update_view_settings( editor ); - - if( editor->propgrid ) - editor_update_properties_column( editor ); -} - -void editor_grid_propgrid_cb( void* ) { - editor_update_properties_column( editor ); -} - -void editor_create_view_settings_row( GAME_EDITOR* e ) { - I32 x = 320, y = 426; - - gui_label( x, y, "view settings:" ); x += 95; - editor->gui.gridlabel = gui_label( x, y, "grid size: %1.2f", e->grid ); - x += 95; - gui_button( x, y, 20, 20, "+", editor_grid_increment_cb ); - gui_button( x + 25, y, 20, 20, "-", editor_grid_decrement_cb ); - x += 55; - GUI_CHECKBOX* check = gui_checkbox( x, y, "properties grid", &e->propgrid ); - check->cb = editor_grid_propgrid_cb; - x += 120; - gui_checkbox( x, y, "wireframe", &e->wireframe ); - - x = 320; - y = 440; - gui_button( x, y, 100, 20, "compile bsp", pfn( void* b ) { - if( editor->map->bsp ) - bsp_free( editor->map->bsp ); - editor->map->bsp = bsp_build_map( editor->map ); - } ); x += 110; - - gui_checkbox( x, y, "draw bsp", &e->drawbsp ); -} - void editor_create_map_view( GAME_EDITOR* e ) { if( !e->map ) { dlog( "editor_create_map_views() : no map loaded\n" ); @@ -192,7 +141,6 @@ void editor_create_map_view( GAME_EDITOR* e ) { editor_create_properties_column( e ); editor_create_game_view_column( e ); editor_create_tools_row( e ); - editor_create_view_settings_row( e ); } void close_new_map_popup( void* ) { diff --git a/src/editor/view2d.cpp b/src/editor/view2d.cpp index 35fd208..1445cfc 100644 --- a/src/editor/view2d.cpp +++ b/src/editor/view2d.cpp @@ -1,12 +1,13 @@ #include <math.h> #include "editor.h" #include "../render/gl_2d.h" - #include "../game/objlist.h" +#include "../game/world/bsp.h" const I32 EDITORVIEW_TITLE_OFFSET = 15; const I32 EDITORVIEW_GUTTERS_OFFSETX = 22; const I32 EDITORVIEW_GUTTERS_OFFSETY = 16; +const I32 EDITORVIEW_TOOLBAR_OFFSET = 20; F32 gui_editor_2dview_calc_scale( GUI_EDITOR_2DVIEW* view ) { WORLD_MAP* m = editor->map; @@ -337,13 +338,23 @@ void gui_editor_2dview_draw_fn( void* ptr ) { U32 offx = EDITORVIEW_GUTTERS_OFFSETX; U32 offy = EDITORVIEW_GUTTERS_OFFSETY; - gui_draw_push_clip( x + offx, y + offy, w - offx, h - offy ); + gui_draw_push_clip( x + offx, y + offy, w - offx, h - offy - EDITORVIEW_TOOLBAR_OFFSET ); gui_editor_2dview_draw_polygons( view, x + offx, y + offy ); gui_editor_2dview_draw_walls( view, x + offx, y + offy ); gui_editor_2dview_draw_sprites( view, x + offx, y + offy ); gui_editor_2dview_draw_player( view, x + offx, y + offy ); gui_editor_2dview_draw_origin( view, x + offx, y + offy ); gui_draw_pop_clip(); + + gui_draw_push_clip( x, y + 16, view->w, view->h ); + view->children.each( fn( GUI_BASE** childptr ) { + GUI_BASE* child = *childptr; + if( !child->enabled ) return; + + if( child->draw_fn ) child->draw_fn( child ); + else dlog( "gui_view_draw_fn(): child %p no draw_fn\n", child ); + } ); + gui_draw_pop_clip(); } U8 gui_editor_2dview_input_drag( GUI_EDITOR_2DVIEW* view, U8 mouse ) { @@ -876,11 +887,91 @@ void gui_editor_2dview_input_tool_draw( GUI_EDITOR_2DVIEW* view ) { } } +void gui_editor_view2d_delete_obj( GUI_EDITOR_2DVIEW* view ) { + void* it; + U8 type; + + if( view->curdrag && view->dragtype ) { + it = view->curdrag; + type = view->dragtype; + view->curdrag = 0; + view->dragtype = EDITOR_SELECT_NONE; + } else if( editor->gui.props->curselect ) { + it = editor->gui.props->curselect; + type = editor->gui.props->seltype; + view->curselect = 0; + view->seltype = EDITOR_SELECT_NONE; + } + else return; + + U8 cleared = 1; + switch( type ) { + case EDITOR_SELECT_POLY: { + I32 idx = editor->map->polygons.idx_of( (MAP_POLYGON*)it ); + if( idx != -1 ) + editor->map->polygons.erase( idx ); + } break; + case EDITOR_SELECT_WALL: { + I32 idx = editor->map->walls.idx_of( (MAP_WALL*)it ); + if( idx != -1 ) + editor->map->walls.erase( idx ); + }; break; + case EDITOR_SELECT_SPRITE: { + I32 idx = editor->map->sprites.idx_of( (MAP_SPRITE*)it ); + if( idx != -1 ) + editor->map->sprites.erase( idx ); + }; break; + case EDITOR_SELECT_PVERTEX: { + I32 vidx = -1, idx = editor->map->polygons.idx_where( fn( MAP_POLYGON* p ) { + vidx = p->vertices.idx_where( fn( MAP_VERTEX* v ) { + return v == it; + } ); + return vidx != -1; + } ); + + if( idx != -1 && vidx != -1 ) { + MAP_POLYGON* p = &editor->map->polygons[idx]; + if( p->vertices.size <= 3 ) { + editor->map->polygons.erase( idx ); + break; + } + editor->map->polygons[idx].vertices.erase( vidx ); + } + }; break; + case EDITOR_SELECT_WVERTEX: { + I32 idx = editor->map->walls.idx_where( fn( MAP_WALL* w ) { + return &w->end == it || &w->start == it; + } ); + + if( idx != -1 ) + editor->map->walls.erase( idx ); + }; break; + default: + cleared = 0; break; + } + + if( cleared && it == editor->gui.props->curselect ) { + gui_editor_propview_select( editor->gui.props, 0, 0 ); + } +} + +void gui_editor_2dview_key_input( GUI_EDITOR_2DVIEW* view ) { + static U8 del_held = 0; + if( kb_down( SDLK_DELETE ) && !input.mouselock ) { + if( !del_held ) + gui_editor_view2d_delete_obj( view ); + + del_held = 1; + } else del_held = 0; +} + void gui_editor_2dview_input_fn( void* ptr ) { GUI_EDITOR_2DVIEW* view = (GUI_EDITOR_2DVIEW*)ptr; if( !editor->map ) return; + gui_editor_2dview_key_input( view ); + I32 x = gui_relx( view ); I32 y = gui_rely( view ) + EDITORVIEW_TITLE_OFFSET; I32 w = view->w; @@ -902,6 +993,10 @@ void gui_editor_2dview_input_fn( void* ptr ) { if( view->heldoutbounds ) return; + gui_base_input_fn( view ); + if( my >= y + h - 18 ) + return; + switch( editor->tool ) { case EDITOR_TOOL_SELECT: return gui_editor_2dview_input_tool_select( view ); case EDITOR_TOOL_WALL: @@ -913,6 +1008,47 @@ void gui_editor_2dview_input_fn( void* ptr ) { } } +void update_view_settings( GAME_EDITOR* e ) { + GAME_EDITOR::EDITOR_GUI* egui = &e->gui; + + sprintf( egui->gridlabel->name, "grid: %1.2f", e->grid ); +} + +void grid_increment_cb( void* ) { + if( editor->grid < 16.f ) editor->grid *= 2.f; + update_view_settings( editor ); + + if( editor->propgrid ) + editor_update_properties_column( editor ); +} + +void grid_decrement_cb( void* ) { + if( editor->grid > 0.25f ) editor->grid *= 0.5f; + update_view_settings( editor ); + + if( editor->propgrid ) + editor_update_properties_column( editor ); +} + +void grid_propgrid_cb( void* ) { + editor_update_properties_column( editor ); +} + +void gui_editor_2dview_create_toolbar( GUI_EDITOR_2DVIEW* view ) { + GAME_EDITOR* e = editor; + I32 x = 150, y = view->h - 4; + + editor->gui.gridlabel = gui_label( x, y + 1, "grid: %1.2f", e->grid ); + x += 70; + gui_button( x, y, 18, 18, "+", grid_increment_cb ); + gui_button( x + 23, y, 18, 18, "-", grid_decrement_cb ); + x += 50; + GUI_CHECKBOX* check = gui_checkbox( x, y, "properties grid", &e->propgrid ); + check->cb = grid_propgrid_cb; + x += 120; + gui_checkbox( x, y, "wireframe", &e->wireframe ); +} + GUI_EDITOR_2DVIEW* gui_editor_2dview( I32 x, I32 y, I32 w, I32 h ) { GUI_EDITOR_2DVIEW* view = new GUI_EDITOR_2DVIEW; view->x = x; @@ -934,5 +1070,9 @@ GUI_EDITOR_2DVIEW* gui_editor_2dview( I32 x, I32 y, I32 w, I32 h ) { parent->children.push( view ); view->parent = parent; + gui_set_view( view ); + gui_editor_2dview_create_toolbar( view ); + gui_set_view( (GUI_VIEW*)parent ); + return view; } diff --git a/src/editor/view3d.cpp b/src/editor/view3d.cpp index f9bd60e..f8d1def 100644 --- a/src/editor/view3d.cpp +++ b/src/editor/view3d.cpp @@ -6,6 +6,7 @@ #include "../game.h" const I32 EDITORVIEW_TITLE_OFFSET = 15; +const I32 EDITORVIEW_TOOLBAR_OFFSET = 20; void gui_editor_3dview_draw_showpos( GUI_EDITOR_3DVIEW* view ) { I32 x = gui_relx( view ); @@ -31,6 +32,16 @@ void gui_editor_3dview_draw_showpos( GUI_EDITOR_3DVIEW* view ) { objl->pl->rot.y, objl->pl->rot.x ); + + if( input.mouselock ) { + gui_draw_str( + x + 2, y + 2, + ALIGN_L, + FNT_JPN12, + ui_clr.txt, + "[capturing mouse]" + ); + } } void gui_editor_3dview_draw_fn( void* ptr ) { @@ -55,17 +66,55 @@ void gui_editor_3dview_draw_fn( void* ptr ) { bsp_draw( editor->map->bsp, editor->game, wnd, winsize ); else world_draw( editor->game, objl->world, wnd, winsize ); - + + gui_draw_push_clip( x, y, view->w, view->h ); + view->children.each( fn( GUI_BASE** childptr ) { + GUI_BASE* child = *childptr; + if( !child->enabled ) return; + + if( child->draw_fn ) child->draw_fn( child ); + else dlog( "gui_view_draw_fn(): child %p no draw_fn\n", child ); + } ); + gui_draw_pop_clip(); gui_editor_3dview_draw_showpos( view ); } void gui_editor_3dview_input_fn( void* ptr ) { + GUI_EDITOR_3DVIEW* view = (GUI_EDITOR_3DVIEW*)ptr; + if( !input.mouselock ) + gui_base_input_fn( view ); + if( !objl->pl ) return; + if( input.mouse.left ) { + I32 view_x = gui_relx( view ); + I32 view_y = gui_rely( view ) + EDITORVIEW_TITLE_OFFSET; + if( input.mouse.pos.x >= view_x && input.mouse.pos.x < view_x + view->w && + input.mouse.pos.y >= view_y && input.mouse.pos.y < view_y + view->h - EDITORVIEW_TOOLBAR_OFFSET ) { + if( !input.mouselock && !view->heldoutbounds ) + input_capture_mouse( true ); + } else { + view->heldoutbounds = 1; + } + } else view->heldoutbounds = 0; + game_on_tick( editor->game ); } +void gui_editor_3dview_create_toolbar( GUI_EDITOR_3DVIEW* view ) { + GAME_EDITOR* e = editor; + I32 x = 1, y = view->h - 4; + + gui_button( x, y, 90, 18, "compile bsp", pfn( void* b ) { + if( editor->map->bsp ) + bsp_free( editor->map->bsp ); + editor->map->bsp = bsp_build_map( editor->map ); + } ); x += 100; + + gui_checkbox( x, y, "draw bsp", &e->drawbsp ); +} + GUI_EDITOR_3DVIEW* gui_editor_3dview( I32 x, I32 y, I32 w, I32 h ) { GUI_EDITOR_3DVIEW* view = new GUI_EDITOR_3DVIEW; view->x = x; @@ -84,5 +133,10 @@ GUI_EDITOR_3DVIEW* gui_editor_3dview( I32 x, I32 y, I32 w, I32 h ) { parent->children.push( view ); view->parent = parent; + + gui_set_view( view ); + gui_editor_3dview_create_toolbar( view ); + gui_set_view( (GUI_VIEW*)parent ); + return view; } diff --git a/src/game.cpp b/src/game.cpp index bd3c4c8..285f288 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -120,6 +120,7 @@ void game_main_loop( GAME_DATA* game ) { gl_beginframe( gl ); 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 ); @@ -139,7 +140,7 @@ void game_main_loop( GAME_DATA* game ) { void game_on_tick( GAME_DATA* game ) { U64 tick = u_tick(); if( tick - game->state.last_tick > (U64)(TICK_INTERVAL * 10000) ) { - player_input( game, objl->pl ); + player_move( game, objl->pl ); game->state.last_tick = tick; } } @@ -19,7 +19,7 @@ typedef struct { GL_SHADER_PROGRAM* gl2d; GL_SHADER_PROGRAM* gl2d_texcoord; - struct GL_3D* gl3d; + struct GL3D* gl3d; } GAME_SHADERS; typedef struct { diff --git a/src/game/assets.cpp b/src/game/assets.cpp index 7d755c0..62663a9 100644 --- a/src/game/assets.cpp +++ b/src/game/assets.cpp @@ -3,8 +3,11 @@ #include "../game.h" #include "../render/gl_2d_font.h" +#include "../util/stb_image.h" +#include "../util/anim.h" + void assets_init( GAME_DATA *game ) { - game->assets.test = gl_texture_create( game->gl, "assets/test.png" ); + game->assets.test = gl_texture_from_file( game->gl, "uvtest.png" ); game->assets.fonts_init = 0; } diff --git a/src/game/camera.h b/src/game/camera.h new file mode 100644 index 0000000..b9fe402 --- /dev/null +++ b/src/game/camera.h @@ -0,0 +1,9 @@ +#pragma once + +#include "../util/vector.h" + +struct PLAYER_CAMERA { + VEC3 pos; + VEC3 rot; + F32 fov; +}; diff --git a/src/game/player.cpp b/src/game/player.cpp index 87786df..51d1cf8 100644 --- a/src/game/player.cpp +++ b/src/game/player.cpp @@ -2,6 +2,7 @@ #include "SDL_scancode.h" #include "objlist.h" #include "world/trace.h" +#include <cmath> #include "player.h" F32 PLAYER_HULL_HEIGHT = 50.f; @@ -30,50 +31,132 @@ PLAYER* player_create( VEC3 origin, F32 yaw ) { return p; } -void player_input( GAME_DATA* game, PLAYER* p ) { - F32* yaw = &p->rot.y; - VEC3* pos = &p->pos; +void capture_mouse( PLAYER* p ) { + F32* yaw = &p->input.cam.pos.y; + F32* pitch = &p->input.cam.pos.x; + if( input.keys[SDL_SCANCODE_F1] ) { + input_capture_mouse( false ); + } - if( input.keys[(U8)'a'] ) - *yaw -= 360.f * TICK_INTERVAL * 0.5f; - if( input.keys[(U8)'d'] ) - *yaw += 360.f * TICK_INTERVAL * 0.5f; + if( input.mouselock ) { + *yaw += input.mouse.pos_delta.x * input.msens; + *pitch -= input.mouse.pos_delta.y * input.msens; - if( input.keys[SDL_SCANCODE_UP] ) { - if( p->rot.x < 89.f ) - p->rot.x += 360.f * TICK_INTERVAL * 0.5f; - } - if( input.keys[SDL_SCANCODE_DOWN] ) { - if( p->rot.x > -89.f ) - p->rot.x -= 360.f * TICK_INTERVAL * 0.5f; + if( *pitch > 89.f ) *pitch = 89.f; + if( *pitch < -89.f ) *pitch = -89.f; + + input_reset_mouse_accumulator(); } *yaw = remainderf( *yaw, 360.f ); + p->rot.x = *pitch; + p->rot.y = *yaw; +} +void capture_move_keys( PLAYER* p ) { + VEC2* move = &p->input.move; + if( input.keys[input.binds.fwd] ) { + if( !p->input.fwd_held ) + move->x = 1.f; + p->input.fwd_held = true; + } else { + if( p->input.fwd_held ) { + if( p->input.bk_held ) + move->x = -1.f; + else + move->x = 0.f; + } + p->input.fwd_held = false; + } - VEC3 wishmove; - VEC3 dir = m_radial_offset( *yaw, 70.f ); - if( input.keys[(U8)'w'] ) { - wishmove = dir * TICK_INTERVAL; + if( input.keys[input.binds.back] ) { + if( !p->input.bk_held ) + move->x = -1.f; + p->input.bk_held = true; + } else { + if( p->input.bk_held ) { + if( p->input.fwd_held ) + move->x = 1.f; + else + move->x = 0.f; + } + p->input.bk_held = false; } - if( input.keys[(U8)'s'] ) { - wishmove = dir * -TICK_INTERVAL; + + if( input.keys[input.binds.left] ) { + if( !p->input.left_held ) + move->y = -1.f; + p->input.left_held = true; + } else { + if( p->input.left_held ) { + if( p->input.right_held ) + move->y = 1.f; + else + move->y = 0.f; + } + p->input.left_held = false; } + if( input.keys[input.binds.right] ) { + if( !p->input.right_held ) + move->y = 1.f; + p->input.right_held = true; + } else { + if( p->input.right_held ) { + if( p->input.left_held ) + move->y = -1.f; + else + move->y = 0.f; + } + p->input.right_held = false; + } +} + +void player_input( GAME_DATA* game, PLAYER* p ) { + if( !p ) + return; + + capture_mouse( p ); + capture_move_keys( p ); +} + +void player_move( GAME_DATA* game, PLAYER* p ) { + VEC2 move = p->input.move; + F32 yawrad = m_deg2rad( p->rot.y ); + + VEC3 wishdir = { + move.x * cosf( yawrad ) - move.y * sinf( yawrad ), + move.y * cosf( yawrad ) + move.x * sinf( yawrad ), + 0 + }; + + VEC3 vel = wishdir * 70.f; + p->velocity = vel; + VEC3 wishmove = vel * TICK_INTERVAL; // todo : should never be false if( vec_len( wishmove ) > BSP_TRACE_EPSILON && game->state.map->bsp ) { BSP_TRACE tr{}; AABB aabb{}; - tr.in_start = *pos; - tr.in_end = *pos + wishmove * 2.f; + tr.in_start = p->pos; + tr.in_end = tr.in_start + wishmove; aabb.min = p->mins; aabb.max = p->maxs; bsp_trace( &tr, game->state.map->bsp, aabb ); if( !tr.hit ) - *pos += wishmove; - else - *pos += wishmove * tr.frac; + p->pos += wishmove; + else { + p->pos += wishmove * tr.frac; + + + // TODO: clipvelocity fixes this, clips velocity to 1 wall (should do 4) + VEC3 left = wishmove * (1.f - tr.frac); + F32 into = vec_dot( left, tr.normal ); + if( into < 0.f ) + left -= tr.normal * into; + + p->pos += left; + } } } diff --git a/src/game/player.h b/src/game/player.h index 71b1c02..6617f01 100644 --- a/src/game/player.h +++ b/src/game/player.h @@ -1,8 +1,16 @@ #pragma once #include "object.h" +#include "camera.h" + struct PLAYER_INPUT { - + PLAYER_CAMERA cam; + struct PLAYER* pobj; + + // for nulls + U8 fwd_held{}, bk_held{}, left_held{}, right_held{}; + + VEC2 move; }; struct PLAYER : OBJECT { @@ -11,6 +19,8 @@ struct PLAYER : OBJECT { F32 fov{72.f}; F32 eyeoffset{40.f}; + PLAYER_INPUT input; + VEC3 mins; VEC3 maxs; @@ -19,4 +29,5 @@ struct PLAYER : OBJECT { extern PLAYER* player_create( VEC3 origin, F32 yaw ); extern void player_input( struct GAME_DATA* game, PLAYER* player ); +extern void player_move( struct GAME_DATA* game, PLAYER* player ); extern VEC3 player_get_view_pos( PLAYER* player ); diff --git a/src/game/raycast.cpp b/src/game/raycast.cpp index c82a3ed..d38eb0a 100644 --- a/src/game/raycast.cpp +++ b/src/game/raycast.cpp @@ -126,7 +126,7 @@ U32 ray_trace( TRACE* tr, VEC3 end ) { } void draw_player( GAME_DATA* game, PLAYER* pl ) { - GL_PROGRAM* gl2d = game->shaders.gl2d; + GL_SHADER_PROGRAM* gl2d = game->shaders.gl2d; VEC2 xy = { pl->pos.x, pl->pos.y }; gl_2d_frect( gl2d, xy - VEC2{ 5.f, 5.f }, { 10.f, 10.f }, CLR::RED() ); diff --git a/src/game/world/bsp.cpp b/src/game/world/bsp.cpp index 9aa94d7..a95a693 100644 --- a/src/game/world/bsp.cpp +++ b/src/game/world/bsp.cpp @@ -637,7 +637,89 @@ U8 pvs_get( BSP_BITSET* pvs, U32 count, U32 cluster, U32 seen ) { U32 w = seen / 32, b = seen % 32; if( base + w >= pvs->size ) return 0; - return ( pvs->data[base + w] >> b) & 1u; + return (pvs->data[base + w] >> b) & 1u; +} + +void bsp_build_pvs( BSP* bsp ) { + U32 nclusters = bsp->leaves.size; + bsp->pvs_bits.clear(); + bsp->clusters.clear(); + bsp->clusters.reserve( nclusters ); + + LIST<LIST<I32>> leaf_portals; + leaf_portals.resize( nclusters ); + + for( U32 i = 0; i < bsp->portals.size; ++i ) { + BSP_PORTAL* p = &bsp->portals.data[i]; + I32 lf = bsp_leaf_index( p->front ); + I32 rf = bsp_leaf_index( p->back ); + + leaf_portals.data[lf].push( i ); + leaf_portals.data[rf].push( i ); + } + + for( U32 i = 0; i < nclusters; ++i ) { + BSP_CLUSTER* c = &bsp->clusters.data[i]; + c->first = 0; + c->count = 0; + c->pvs_off = 0; + } + + for( U32 from = 0; from < nclusters; ++from ) { + LIST<I32>* plist = &leaf_portals.data[from]; + pvs_set( &bsp->pvs_bits, nclusters, from, from ); + + LIST<BSP_PORTAL_QUEUE> queue; + for( U32 i = 0; i < plist->size; ++i ) { + I32 pid = plist->data[i]; + BSP_PORTAL* p = &bsp->portals.data[pid]; + + BSP_PORTAL_QUEUE it{ + .front = (I32)from, + .frustum = p->w + }; + + queue.push( it ) ; + } + + while( queue.size ) { + BSP_PORTAL_QUEUE it = queue.pop(); + LIST<I32>* plist = &leaf_portals.data[it.front]; + + for( U32 i = 0; plist->size; ++i ) { + BSP_PORTAL* p = &bsp->portals.data[plist->data[i]]; + I32 lf = bsp_leaf_index( p->front ); + I32 lb = bsp_leaf_index( p->back ); + + I32 neighbor = (lf == it.front) ? lb : (lb == it.front) ? lf : -1; + if( neighbor < 0 ) + continue; + + BSP_WINDING next_w; + if( !bsp_winding_intersect_plane( &p->plane, &it.frustum, &p->w, &next_w ) ) + continue; + + if( !pvs_get( &bsp->pvs_bits, nclusters, from, (U32)neighbor ) ) { + pvs_set( &bsp->pvs_bits, nclusters, from, (U32)neighbor ); + + LIST<I32>* nbr_plist = &leaf_portals.data[neighbor]; + for( U32 i2 = 0; i2 < nbr_plist->size; ++i2 ) { + BSP_PORTAL* nbr_p = &bsp->portals.data[nbr_plist->data[i2]]; + if( nbr_p == p ) + continue; + + BSP_WINDING clipped = next_w; + if( bsp_winding_intersect_plane( &nbr_p->plane, &clipped, &nbr_p->w, &clipped ) ) { + BSP_PORTAL_QUEUE n{}; + n.front = neighbor; + n.frustum = clipped; + queue.push( n ); + } + } + } + } + } + } } BSP* bsp_build_map( WORLD_MAP* m ) { @@ -647,12 +729,13 @@ BSP* bsp_build_map( WORLD_MAP* m ) { LIST<BSP_PLANE> planes = bsp_map_get_planes( m ); bsp->root = bsp_build_nodes( bsp, planes, faces, 0 ); - U32 vertc = 0; - m->polygons.each( fn( MAP_POLYGON* p ) { vertc += p->vertices.size; } ); for( U32 i = 0; i < bsp->faces.size; ++i ) { bsp->faces.data[i].id = i; } bsp_gen_render_vertices( bsp ); + + bsp_build_portals( bsp ); + bsp_build_pvs( bsp ); return bsp; } diff --git a/src/game/world/bsp.h b/src/game/world/bsp.h index 439fce1..457bcb9 100644 --- a/src/game/world/bsp.h +++ b/src/game/world/bsp.h @@ -71,6 +71,11 @@ struct BSP_PORTAL_NODE { BSP_WINDING w; }; +struct BSP_PORTAL_QUEUE { + I32 front; + BSP_WINDING frustum; +}; + struct BSP_BITSET : public LIST<U32> {}; struct BSP { diff --git a/src/game/world/draw.cpp b/src/game/world/draw.cpp index 9269a21..aad4d09 100644 --- a/src/game/world/draw.cpp +++ b/src/game/world/draw.cpp @@ -11,7 +11,7 @@ VEC2 world_project_pos( GAME_DATA* game, VEC3 pos ) { - GL_3D* gl3d = (GL_3D*)game->shaders.gl3d; + GL3D* gl3d = (GL3D*)game->shaders.gl3d; VEC4 clip = { pos.x, pos.z, pos.y, 1.f }; VEC4 ndc; diff --git a/src/game/world/trace.cpp b/src/game/world/trace.cpp index b3a0041..c8ad3be 100644 --- a/src/game/world/trace.cpp +++ b/src/game/world/trace.cpp @@ -200,9 +200,7 @@ inline U8 point_in_inflated_poly( in = in * -1.0f; F32 dist = vec_dot( point - a, in ); - VEC2 feet = aabb_extend_at_feet( hull, in ); - F32 pos_r = feet.x, neg_r = feet.y; - F32 expand = norm.z >= 0 ? neg_r : pos_r; + F32 expand = aabb_extend_at_feet( hull, in ).x; if( dist < -expand - BSP_TRACE_EPSILON ) return 0; } diff --git a/src/gui/base.h b/src/gui/base.h index 96e0fa5..7b95d34 100644 --- a/src/gui/base.h +++ b/src/gui/base.h @@ -115,6 +115,7 @@ typedef void( *GUI_DRAW_FN )( void* el ); typedef void( *GUI_INPUT_FN )( void* el ); extern void gui_base_input_fn( void* ); +extern void gui_view_draw_fn( void* ); struct GUI_BASE { I32 x{}, y{}; diff --git a/src/main.cpp b/src/main.cpp index 28886fa..5d70ef8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,7 +33,7 @@ void loop() { game_main_loop( game ); } -int main() { +int main(int argc, char* argv[]) { if( !canvas ) canvas = (I32*)malloc( sizeof(I32) * 2 ); diff --git a/src/render/gl.cpp b/src/render/gl.cpp index 915722e..e44a165 100644 --- a/src/render/gl.cpp +++ b/src/render/gl.cpp @@ -29,7 +29,7 @@ GL_DATA* gl_create( I32* _canvas ) { return 0; } - SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE ); SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 ); SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 ); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); @@ -43,8 +43,8 @@ GL_DATA* gl_create( I32* _canvas ) { GL_DATA* gl = new GL_DATA; gl->window = SDL_CreateWindow( "game", - 0, - 0, + SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, _canvas[0], _canvas[1], SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN @@ -52,22 +52,32 @@ GL_DATA* gl_create( I32* _canvas ) { if( !gl->window ) { dlog( "gl_init() could not create window: %s\n", SDL_GetError() ); - return 0; - } - - U32 renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE; - gl->renderer = SDL_CreateRenderer( gl->window, -1, renderer_flags ); - if( !gl->renderer ) { - dlog( "gl_init() could not create renderer: %s\n", SDL_GetError() ); + delete gl; return 0; } gl->ctx = SDL_GL_CreateContext( gl->window ); if( !gl->ctx ) { dlog( "gl_init() could not create context: %s\n", SDL_GetError() ); + SDL_DestroyWindow( gl->window ); + delete gl; + return 0; + } + + SDL_GL_SetSwapInterval(0); + SDL_GL_MakeCurrent( gl->window, gl->ctx ); + + GLenum glewError = glewInit(); + if( glewError != GLEW_OK ) { + dlog( "gl_create() : Failed to initialize GLEW: %s\n", glewGetErrorString(glewError) ); + SDL_GL_DeleteContext( gl->ctx ); + SDL_DestroyWindow( gl->window ); + delete gl; return 0; } + while( glGetError() != GL_NO_ERROR ); // clear errors + // glGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS, &gl->shader_texture_limit ); if( gl->shader_texture_limit > 255 ) gl->shader_texture_limit = 255; @@ -78,17 +88,19 @@ GL_DATA* gl_create( I32* _canvas ) { memcpy( gl->canvas_size, _canvas, sizeof(I32) * 2 ); gl->clip_start = { 0, 0 }; gl->clip_dim = { (F32)gl->canvas_size[0], (F32)gl->canvas_size[1] }; + glViewport( 0, 0, gl->canvas_size[0], gl->canvas_size[1] ); gl_inst = gl; return gl; } void gl_gen_buffers( GL_DATA* gl ) { - glGenBuffers( 1, &gl->vbuffer ); + glGenVertexArrays( 1, &gl->vao ); + glBindVertexArray( gl->vao ); + glGenBuffers( 1, &gl->vbuffer ); glBindBuffer( GL_ARRAY_BUFFER, gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, 8192, 0, GL_STATIC_DRAW ); - glBindBuffer( GL_ARRAY_BUFFER, 0 ); } @@ -131,7 +143,7 @@ void gl_update_window( GL_DATA* gl, I32* size ) { glUseProgram( 0 ); } -STAT gl_shader_compile( GL_DATA* gl, GL_SHADER* shader ) { +STAT gl_shader_compile( GL_DATA* gl, GL_SHADER_DEF* shader ) { static char* log_buf = 0; if( !log_buf ) log_buf = (char*)malloc( 8192 ); @@ -154,7 +166,7 @@ STAT gl_shader_compile( GL_DATA* gl, GL_SHADER* shader ) { return STAT_OK; } -void gl_shader_destroy( GL_DATA* gl, GL_SHADER* shader ) { +void gl_shader_destroy( GL_DATA* gl, GL_SHADER_DEF* shader ) { if( shader->code ) free( (void*)shader->code ); } @@ -264,7 +276,7 @@ GL_TEX2D* gl_texture_from_file( GL_DATA* gl, const char* name ) { return tex; } -GL_TEX2D* gl_texture_from_bitmap( GL_DATA* gl, const char* name, U8* bitmap, U32 width, U32 height ) { +GL_TEX2D* gl_texture_from_bitmap( GL_DATA* gl, const char* name, U8* bitmap, U32 w, U32 h ) { GL_TEX2D* tex = gl_texture_create( gl, name ); glBindTexture( GL_TEXTURE_2D, tex->id ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); @@ -272,22 +284,16 @@ GL_TEX2D* gl_texture_from_bitmap( GL_DATA* gl, const char* name, U8* bitmap, U32 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - tex->width = width; - tex->height = height; - - glTexImage2D( - GL_TEXTURE_2D, - 0, GL_RGBA, - (I32)width, (I32)height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, bitmap - ); - + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap ); + glGenerateMipmap( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, 0 ); + tex->width = w; + tex->height = h; + return tex; } - GL_TEX2D* gl_texture_create( GL_DATA* gl, const char* name ) { GL_TEX2D* tex = (GL_TEX2D*)malloc( sizeof(GL_TEX2D) ); strcpy( tex->name, name ); @@ -307,10 +313,6 @@ void gl_texture_destroy( GL_DATA* gl, GL_TEX2D* tex ) { } STAT gl_beginframe( GL_DATA* gl ) { - SDL_SetRenderTarget( gl->renderer, 0 ); - SDL_SetRenderDrawColor( gl->renderer, 0, 0, 0, 255 ); - SDL_RenderClear( gl->renderer ); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); gl->last_tick = u_tick(); return STAT_OK; diff --git a/src/render/gl.h b/src/render/gl.h index cf2b5dd..e4e2d5a 100644 --- a/src/render/gl.h +++ b/src/render/gl.h @@ -1,7 +1,8 @@ #pragma once #include <SDL.h> -#include <GLES2/gl2.h> +// #include <GLES2/gl2.h> +#include <GL/glew.h> #include "../util.h" #include "../util/matrix.h" @@ -68,6 +69,8 @@ typedef struct GL_DATA { VEC2 viewport_dim; MAT4* proj_matrix; + + GLuint vao; } *PGL_DATA; GL_DATA* gl_instance(); diff --git a/src/render/gl_2d.cpp b/src/render/gl_2d.cpp index 44e7e00..78af1da 100644 --- a/src/render/gl_2d.cpp +++ b/src/render/gl_2d.cpp @@ -1,8 +1,8 @@ #include "gl_2d.h" #include "../util.h" -GL_PROGRAM* gl_2d_init( GL_DATA* gl, VEC2 screensize, const char* shadername ) { - GL_PROGRAM* program = gl_program_create( gl, shadername ); +GL_SHADER_PROGRAM* gl_2d_init( GL_DATA* gl, VEC2 screensize, const char* shadername ) { + GL_SHADER_PROGRAM* program = gl_program_create( gl, shadername ); if( !OK( gl_program_compile( gl, program ) ) ) dlog( "gl_2d_init() : error compiling shader %s\n", shadername ); @@ -26,7 +26,7 @@ GL_PROGRAM* gl_2d_init( GL_DATA* gl, VEC2 screensize, const char* shadername ) { return program; } -void gl_2d_line( GL_PROGRAM* gl2d, VEC2 start, VEC2 end, CLR col ) { +void gl_2d_line( GL_SHADER_PROGRAM* gl2d, VEC2 start, VEC2 end, CLR col ) { static const U16 order[] = { 0, 1 }; glUseProgram( gl2d->id ); @@ -49,7 +49,7 @@ void gl_2d_line( GL_PROGRAM* gl2d, VEC2 start, VEC2 end, CLR col ) { glDrawElements( GL_LINES, 2, GL_UNSIGNED_SHORT, order ); } -void gl_2d_rect( GL_PROGRAM* gl2d, VEC2 origin, VEC2 dim, CLR col ) { +void gl_2d_rect( GL_SHADER_PROGRAM* gl2d, VEC2 origin, VEC2 dim, CLR col ) { static const U16 order[] = { 0, 1, 2, 3, 4 }; glUseProgram( gl2d->id ); @@ -75,10 +75,11 @@ void gl_2d_rect( GL_PROGRAM* gl2d, VEC2 origin, VEC2 dim, CLR col ) { glDrawElements( GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, order ); } -void gl_2d_textured_frect( GL_PROGRAM* gl2d, VEC2 origin, VEC2 dim, GL_TEX2D* texture, CLR col, VEC2* uv, F32 rotation ) { +void gl_2d_textured_frect( GL_SHADER_PROGRAM* gl2d, VEC2 origin, VEC2 dim, GL_TEX2D* texture, CLR col, VEC2* uv, F32 rotation ) { static const U16 order[] = { 0, 1, 2, 3 }; glUseProgram( gl2d->id ); + VERTEX vertices[] = { { { origin.x, origin.y }, uv? uv[0] : VEC2{ 0.f, 0.f }, col, 0 }, { { origin.x + dim.x, origin.y }, uv? uv[1] : VEC2{ 1.f, 0.f }, col, 0 }, @@ -103,34 +104,43 @@ void gl_2d_textured_frect( GL_PROGRAM* gl2d, VEC2 origin, VEC2 dim, GL_TEX2D* te glBindBuffer( GL_ARRAY_BUFFER, gl2d->gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_DYNAMIC_DRAW ); + I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); + I32 color = glGetAttribLocation( gl2d->id, "in_col" ); + I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); + I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); + glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); - I32 color = glGetAttribLocation( gl2d->id, "in_col" ); + glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); - I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); + glEnableVertexAttribArray( texcoord ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); - I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); + glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, texture->id ); + glBindBuffer( GL_ARRAY_BUFFER, 0 ); glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, texture->id ); - glUniform1f( glGetUniformLocation( gl2d->id, "in_time" ), u_time() ); + // glUniform1f( glGetUniformLocation( gl2d->id, "in_time" ), u_time() ); glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, order ); glBindTexture( GL_TEXTURE_2D, 0 ); } -void gl_2d_frect( GL_PROGRAM* gl2d, VEC2 origin, VEC2 dim, CLR col ) { +void gl_2d_frect( GL_SHADER_PROGRAM* gl2d, VEC2 origin, VEC2 dim, CLR col ) { static const U16 order[] = { 0, 1, 2, 3 }; glUseProgram( gl2d->id ); + VERTEX vertices[] = { { .pos = { origin.x, origin.y }, .uv = { 0.f, 0.f }, .clr = col }, { .pos = { origin.x + dim.x, origin.y }, .uv = { 1.f, 0.f }, .clr = col }, @@ -140,21 +150,31 @@ void gl_2d_frect( GL_PROGRAM* gl2d, VEC2 origin, VEC2 dim, CLR col ) { glBindBuffer( GL_ARRAY_BUFFER, gl2d->gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_DYNAMIC_DRAW ); + I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); - glEnableVertexAttribArray( position ); - glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); I32 color = glGetAttribLocation( gl2d->id, "in_col" ); - glEnableVertexAttribArray( color ); - glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); + + if (position >= 0) { + glEnableVertexAttribArray( position ); + glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); + } + + if (color >= 0) { + glEnableVertexAttribArray( color ); + glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); + } + I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); - glEnableVertexAttribArray( texcoord ); - glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); + if (texcoord >= 0) { + glEnableVertexAttribArray( texcoord ); + glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); + } glBindBuffer( GL_ARRAY_BUFFER, 0 ); glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, order ); } -void gl_2d_circle( GL_PROGRAM* gl2d, VEC2 origin, F32 radius, CLR col, U32 res ) { +void gl_2d_circle( GL_SHADER_PROGRAM* gl2d, VEC2 origin, F32 radius, CLR col, U32 res ) { static U16* order = 0; const F32 step = 360.f / (F32)res; @@ -195,7 +215,7 @@ void gl_2d_circle( GL_PROGRAM* gl2d, VEC2 origin, F32 radius, CLR col, U32 res ) free( vertices ); } -void gl_2d_fcircle( GL_PROGRAM* gl2d, VEC2 origin, F32 radius, CLR col, U32 res ) { +void gl_2d_fcircle( GL_SHADER_PROGRAM* gl2d, VEC2 origin, F32 radius, CLR col, U32 res ) { static U16* order = 0; const F32 step = 360.f / (F32)res; @@ -248,7 +268,7 @@ void gl_2d_fcircle( GL_PROGRAM* gl2d, VEC2 origin, F32 radius, CLR col, U32 res free( vertices ); } -void gl_polygon( GL_PROGRAM* gl2d, VERTEX* vertices, U32 vertices_count ) { +void gl_polygon( GL_SHADER_PROGRAM* gl2d, VERTEX* vertices, U32 vertices_count ) { glUseProgram( gl2d->id ); glBindBuffer( GL_ARRAY_BUFFER, gl2d->gl->vbuffer ); @@ -274,7 +294,7 @@ void gl_polygon( GL_PROGRAM* gl2d, VERTEX* vertices, U32 vertices_count ) { } void gl_textured_polygon( - GL_PROGRAM *gl2d, + GL_SHADER_PROGRAM *gl2d, VERTEX *vertices, U32 vertices_count, GL_TEX2D *tex diff --git a/src/render/gl_2d_font.cpp b/src/render/gl_2d_font.cpp index 1dc498b..10ae71a 100644 --- a/src/render/gl_2d_font.cpp +++ b/src/render/gl_2d_font.cpp @@ -210,22 +210,27 @@ void gl_font_draw( GL_FONT* font, GL_SHADER_PROGRAM* shader, VEC2 origin, const glBindBuffer( GL_ARRAY_BUFFER, shader->gl->vbuffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(VERTEX) * 6 * len, vertices, GL_STATIC_DRAW ); + I32 position = glGetAttribLocation( shader->id, "in_pos" ); + I32 color = glGetAttribLocation( shader->id, "in_clr" ); + I32 texcoord = glGetAttribLocation( shader->id, "in_texcoord" ); + I32 sampler = glGetAttribLocation( shader->id, "in_sampler" ); + glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->pos ); - I32 color = glGetAttribLocation( shader->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); - I32 texcoord = glGetAttribLocation( shader->id, "in_texcoord" ); glEnableVertexAttribArray( texcoord ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); - I32 sampler = glGetAttribLocation( shader->id, "in_sampler" ); glEnableVertexAttribArray( sampler ); glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, font->atlas->id ); + glBindBuffer( GL_ARRAY_BUFFER, 0 ); glActiveTexture( GL_TEXTURE0 ); @@ -234,7 +239,7 @@ void gl_font_draw( GL_FONT* font, GL_SHADER_PROGRAM* shader, VEC2 origin, const glDrawElements( GL_TRIANGLES, len * 6, GL_UNSIGNED_SHORT, indices ); glBindTexture( GL_TEXTURE_2D, 0 ); - + free( vertices ); free( indices ); free( coords ); diff --git a/src/render/gl_3d.cpp b/src/render/gl_3d.cpp index 78e7f5e..40162e8 100644 --- a/src/render/gl_3d.cpp +++ b/src/render/gl_3d.cpp @@ -3,8 +3,8 @@ #include "gl.h" #include "gl_batch.h" -GL_3D* gl_3d_init( GL_DATA* gl, VEC2 screensize, const char* shadername ) { - GL_3D *gl3d = (GL_3D*)gl_program_create( gl, shadername, sizeof(GL_3D) ); +GL3D* gl_3d_init( GL_DATA* gl, VEC2 screensize, const char* shadername ) { + GL3D *gl3d = (GL3D*)gl_program_create( gl, shadername, sizeof(GL3D) ); if( !OK( gl_program_compile( gl, gl3d ) ) ) dlog( "gl_2d_init() : error compiling shader %s\n", shadername ); @@ -17,8 +17,8 @@ GL_3D* gl_3d_init( GL_DATA* gl, VEC2 screensize, const char* shadername ) { return gl3d; } -void gl_3d_projection_setup( GL_PROGRAM *_gl3d, VEC3 pos, F32 fov_deg, F32 yaw, F32 pitch, F32 near, F32 far, VEC2 winsize ) { - GL_3D* gl3d = (GL_3D*)_gl3d; +void gl_3d_projection_setup( GL_SHADER_PROGRAM *_gl3d, VEC3 pos, F32 fov_deg, F32 yaw, F32 pitch, F32 near, F32 far, VEC2 winsize ) { + GL3D* gl3d = (GL3D*)_gl3d; MAT4 proj, yaw_rot, pitch_rot, view, transl, tmp; F32 fov_rad = m_deg2rad( fov_deg ); @@ -63,7 +63,7 @@ void gl_3d_batch_setup( GL_BATCH3D *batch ) { } void gl_3d_polygon( - GL_PROGRAM* gl3d, + GL_SHADER_PROGRAM* gl3d, VERTEX3D* vertices, U32 vertices_count, GL_TEX2D* tex diff --git a/src/render/gl_3d.h b/src/render/gl_3d.h index 531c3a3..69f171a 100644 --- a/src/render/gl_3d.h +++ b/src/render/gl_3d.h @@ -13,7 +13,7 @@ struct VERTEX3D { }; using GL_BATCH3D = GL_BATCH<VERTEX3D>; -struct GL_3D : GL_SHADER_PROGRAM { +struct GL3D : GL_SHADER_PROGRAM { F32 aspect; MAT4 projmat; @@ -21,7 +21,7 @@ struct GL_3D : GL_SHADER_PROGRAM { }; // shader init ----------------------------------------------------------- -extern GL_3D* gl_3d_init( GL_DATA* gl, VEC2 screensize, const char* shadername ); +extern GL3D* gl_3d_init( GL_DATA* gl, VEC2 screensize, const char* shadername ); // sets up projection matrix and sends it to the gpu ------------------------------------------------------------ extern void gl_3d_projection_setup( GL_SHADER_PROGRAM* gl3d, VEC3 pos, F32 fov_deg, F32 yaw, F32 pitch, F32 near, F32 far, VEC2 winsize ); extern void gl_3d_batch_setup( GL_BATCH3D* batch ); diff --git a/src/util/aabb.h b/src/util/aabb.h index f2fd251..4d74c88 100644 --- a/src/util/aabb.h +++ b/src/util/aabb.h @@ -14,6 +14,7 @@ inline F32 aabb_support_radius( const AABB& aabb, const VEC3& dir ) { return fabsf(dir.x) * half.x + fabsf(dir.y) * half.y + fabsf(dir.z) * half.z; } +// returns positive radius in X and negative in Y inline VEC2 aabb_extend_at_feet( const AABB& aabb, const VEC3& dir ) { VEC3 half = aabb_half( aabb ); diff --git a/src/util/allocator.h b/src/util/allocator.h index ee0ddd8..27b21c0 100644 --- a/src/util/allocator.h +++ b/src/util/allocator.h @@ -161,6 +161,22 @@ struct LIST { return &data[size - 1]; } + void resize( U32 size ) { + if( size > capacity ) + reserve( size * 2 ); + + if( size < capacity / 4 ) + shrink(); + + if( this->size < size ) { + memset( &data[this->size], 0, sizeof(T) * (size - this->size) ); + for( U32 i = this->size; i < size; ++i ) + data[i] = T(); + } + + this->size = size; + } + // does not call copy constructors, raw memcpy void emplace_list( const LIST<T>& list ) { if( !list.size ) @@ -250,6 +266,16 @@ struct LIST { return -1; } + I32 idx_of( const T* what ) { + for( U32 i = 0; i < size; ++i ) { + if( &data[i] == what ) { + return i; + } + } + + return -1; + } + I32 idx_where( ON_SEARCH_FN what ) { for( U32 i = 0; i < size; ++i ) { if( what( &data[i] ) ) { diff --git a/src/util/config/config.cpp b/src/util/config/config.cpp index 1601afe..a41e455 100644 --- a/src/util/config/config.cpp +++ b/src/util/config/config.cpp @@ -12,20 +12,21 @@ void cfg_seterr( CFG_PARSER* p, const char* fmt, ... ) { } inline U8 is_whitespace( char c ) { - return c == ' ' || c == '\t' || c == '\n'; + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; } inline void trim_whitespace( char* buf ) { - U32 i; - for( i = 0; !!buf[i]; ++i ) - if( !is_whitespace( buf[i] ) ) break; - for( U32 i2 = i; !!buf[i2]; ++i2 ) { - if( is_whitespace( buf[i2] ) ) { - buf[i2 - i] = 0; - return; - } - buf[i2 - i] = buf[i2]; - } + if (!buf || !*buf) return; + + U32 start = 0; + while( buf[start] && is_whitespace( buf[start] ) ) start++; + + U32 end = strlen( buf ); + while( end > start && is_whitespace( buf[end - 1] ) ) end--; + + U32 len = end - start; + memmove( buf, buf + start, len ); + buf[len] = '\0'; } inline void init_cfg_node( CFG_NODE* node, const char* name, CFG_NODE* parent, U8 type ) { @@ -179,65 +180,108 @@ void parse_section( CFG_PARSER* parser, CFG_SECTION* current_section ) { char* next_token; while( fgets( line, sizeof(line), parser->file ) ) { - token = strtok( line, " \t\n" ); + parser->linen++; + + trim_whitespace( line ); + if( strlen( line ) == 0 ) + continue; + + char line_copy[8192]; + strcpy( line_copy, line ); + + token = strtok( line_copy, " \t\r\n" ); if( !token ) continue; - if( strcmp( token, "{" ) == 0 ) + + if( strcmp( token, "{" ) == 0 ) { continue; - else if( strcmp( token, "}" ) == 0 ) { + } else if( strcmp( token, "}" ) == 0 ) { return; } else if( strcmp( token, cfg_types[CFGT_SECTION].def ) == 0 ) { - next_token = strtok( NULL, " \t\n" ); + next_token = strtok( NULL, " \t\r\n" ); + if( !next_token ) { + cfg_seterr( parser, "missing section name at line %d", parser->linen ); + return; + } + char sectname[64]; - strcpy( sectname, next_token ); + strncpy( sectname, next_token, sizeof(sectname) - 1 ); + sectname[sizeof(sectname) - 1] = '\0'; trim_whitespace( sectname ); CFG_SECTION* new_section = cfg_section_new( sectname, (CFG_NODE*)current_section ); - strtok( NULL, " \t\n" ); + + char* brace = strtok( NULL, " \t\r\n" ); + if( !brace || strcmp( brace, "{" ) != 0 ) { + cfg_seterr( parser, "expected '{' after section name at line %d", parser->linen ); + return; + } + parse_section( parser, new_section ); } else { char name[64]; - strcpy( name, token ); + strncpy( name, token, sizeof(name) - 1 ); + name[sizeof(name) - 1] = '\0'; trim_whitespace( name ); token = strtok( NULL, "=[" ); - if( !token ) + if( !token ) { + cfg_seterr( parser, "invalid variable declaration at line %d", parser->linen ); continue; + } char varname[64]; - strcpy( varname, token ); + strncpy( varname, token, sizeof(varname) - 1 ); + varname[sizeof(varname) - 1] = '\0'; trim_whitespace( varname ); + U8 found = 0; for( I32 i = 0; i < sizeof(cfg_types) / sizeof(CFG_TYPE); ++i ) { const CFG_TYPE* fn = &cfg_types[i]; - if( strncmp( name, fn->def, strlen( fn->def ) ) == 0 ) { + if( strcmp( name, fn->def ) == 0 ) { + strcpy( line_copy, line ); + strtok( line_copy, " \t\r\n" ); + strtok( NULL, "=[" ); + fn->parser( parser, current_section, varname ); + found = true; break; } } + if( !found ) { + cfg_seterr( parser, "unknown type '%s' at line %d", name, parser->linen ); + return; + } + if( parser->iserr ) { dlog( "parse_section() : %s parse error:\n - %s\n", name, parser->err ); return; } } - - parser->linen++; } } CFG_SECTION* cfg_load( const char* path ) { - FILE* f = fopen( path, "rb" ); + FILE* f = fopen( path, "r" ); if( !f ) return 0; CFG_PARSER p; + memset( &p, 0, sizeof(p) ); p.iserr = 0; p.file = f; p.linen = 0; p.root = cfg_section_new( "root", 0 ); + parse_section( &p, p.root ); fclose( f ); + + if( p.iserr ) { + cfg_free( (CFG_NODE*)p.root ); + return 0; + } + return p.root; } diff --git a/src/util/input.cpp b/src/util/input.cpp index 4a786aa..284ebfe 100644 --- a/src/util/input.cpp +++ b/src/util/input.cpp @@ -27,6 +27,8 @@ void input_on_event( SDL_Event* e ) { case SDL_MOUSEMOTION: { input.mouse.pos.x = (F32)e->motion.x; input.mouse.pos.y = (F32)e->motion.y; + input.mouse.pos_delta.x += (F32)e->motion.xrel * input.mpitch; + input.mouse.pos_delta.y += (F32)e->motion.yrel * input.myaw; } break; case SDL_KEYDOWN: { input.keys[e->key.keysym.sym & 0xff] = 1; @@ -37,6 +39,10 @@ void input_on_event( SDL_Event* e ) { } } +extern void input_reset_mouse_accumulator() { + input.mouse.pos_delta.x = 0; + input.mouse.pos_delta.y = 0; +} void input_on_mouse( I32 type, I32 x, I32 y ) { if( type == MOUSEEV_MOVE ) { @@ -72,3 +78,13 @@ void input_on_mouse( I32 type, I32 x, I32 y ) { void input_frame_end() { input.mouse.wheel = 0; } + +U8 input_is_key_down( U32 key ) { + return input.keys[key]; +} + +void input_capture_mouse( bool capture ) { + input_reset_mouse_accumulator(); + input.mouselock = capture; + SDL_SetRelativeMouseMode( capture ? SDL_TRUE : SDL_FALSE ); +} diff --git a/src/util/input.h b/src/util/input.h index e174fe6..86d715c 100644 --- a/src/util/input.h +++ b/src/util/input.h @@ -16,19 +16,36 @@ const U32 MOUSE_WHEEL = 0x4; struct MOUSE_DATA { VEC2 pos; + VEC2 pos_delta; U8 left; U8 right; U8 middle; U8 wheel; }; +struct INPUT_KEYBINDS { + U8 fwd = 'w'; + U8 back = 's'; + U8 left = 'a'; + U8 right = 'd'; + + U8 jump = ' '; + U8 crouch = SDL_SCANCODE_LCTRL; +}; + using ON_INPUT_FN = std::function<void( SDL_Event* )>; struct INPUT_DATA { MOUSE_DATA mouse; U8 keys[0xff]; + bool mouselock; + F32 msens = .3f; + F32 myaw = 1.f; + F32 mpitch = 1.f; + INPUT_KEYBINDS binds; LIST<ON_INPUT_FN> on_input; + }; extern INPUT_DATA input; @@ -36,6 +53,8 @@ extern INPUT_DATA input; extern void input_frame_end(); extern void input_on_event( SDL_Event* e ); extern void input_on_mouse( I32 type, I32 x, I32 y ); -extern void input_is_key_down( U32 key ); +extern U8 input_is_key_down( U32 key ); +extern void input_capture_mouse( bool capture ); +extern void input_reset_mouse_accumulator(); #define kb_down( key ) input_is_key_down( key ) |
