summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--CMakeLists.txt48
-rw-r--r--assets/shaders/2d_texcoord.fsh9
-rw-r--r--assets/shaders/2d_texcoord.vsh4
-rw-r--r--assets/shaders/3d.fsh2
-rw-r--r--src/editor/editor.h6
-rw-r--r--src/editor/gui.cpp52
-rw-r--r--src/editor/view2d.cpp144
-rw-r--r--src/editor/view3d.cpp56
-rw-r--r--src/game.cpp3
-rw-r--r--src/game.h2
-rw-r--r--src/game/assets.cpp5
-rw-r--r--src/game/camera.h9
-rw-r--r--src/game/player.cpp133
-rw-r--r--src/game/player.h13
-rw-r--r--src/game/raycast.cpp2
-rw-r--r--src/game/world/bsp.cpp89
-rw-r--r--src/game/world/bsp.h5
-rw-r--r--src/game/world/draw.cpp2
-rw-r--r--src/game/world/trace.cpp4
-rw-r--r--src/gui/base.h1
-rw-r--r--src/main.cpp2
-rw-r--r--src/render/gl.cpp62
-rw-r--r--src/render/gl.h5
-rw-r--r--src/render/gl_2d.cpp60
-rw-r--r--src/render/gl_2d_font.cpp13
-rw-r--r--src/render/gl_3d.cpp10
-rw-r--r--src/render/gl_3d.h4
-rw-r--r--src/util/aabb.h1
-rw-r--r--src/util/allocator.h26
-rw-r--r--src/util/config/config.cpp92
-rw-r--r--src/util/input.cpp16
-rw-r--r--src/util/input.h21
33 files changed, 702 insertions, 202 deletions
diff --git a/.gitignore b/.gitignore
index d53f885..c332cef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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;
}
}
diff --git a/src/game.h b/src/game.h
index b0307a1..653eb91 100644
--- a/src/game.h
+++ b/src/game.h
@@ -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 )