diff --git a/Makefile b/Makefile index caf6bd9..8975c57 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ ifeq ($(OS),OS_MACOS) -framework Metal -framework QuartzCore \ -framework CoreHaptics else ifeq ($(OS),OS_LINUX) - FLAGS = -ggdb -D_POSIX_C_SOURCE=200809L -no-pie + FLAGS = -ggdb -D_POSIX_C_SOURCE=200809L -no-pie -fno-omit-frame-pointer INCLUDE = -I./libs/include/ LIBS = ./libs/lib/x86_64-linux/libSDL3.a -lm -lX11 FRAMEWORKS = @@ -73,8 +73,11 @@ watch: inotifywait -q -q -e 'modify' . && clear && make -B; \ done +perf: + perf record --call-graph dwarf ./$(EXE) + run: - @ ./$(EXE) + @ clear; ./$(EXE) clean: @ rm -rf $(EXE) $(EXE).dSYM libhandmade.so libhandmade.so.dSYM diff --git a/handmade.c b/handmade.c index 888732a..d5cf743 100644 --- a/handmade.c +++ b/handmade.c @@ -90,9 +90,6 @@ static void draw_rectangle(struct game_offscreen_buffer *buffer, if(max_y > height) max_y = height; - /*unsigned int color = (unsigned int)((round_float_to_int(r * 255.0f) << 16) | - (round_float_to_int(g * 255.0f) << 8) | - (round_float_to_int(b * 255.0f) << 0));*/ color = (unsigned int)((round_float_to_int(255.0f) << 24) | (round_float_to_int(r * 255.0f) << 16) | (round_float_to_int(g * 255.0f) << 8) | @@ -337,19 +334,19 @@ static void move_player(struct game_state *game_state, tile_map = game_state->world->tile_map; if((dd_player.x != 0.0f) && (dd_player.y != 0.0f)) - dd_player = V2Multiply(0.7071067811865475244f, dd_player); + dd_player = v2_multiply(0.7071067811865475244f, dd_player); player_speed = 10.0f; - dd_player = V2Multiply(player_speed, dd_player); + dd_player = v2_multiply(player_speed, dd_player); - dd_player = V2Add(dd_player, V2Unary(V2Multiply(1.5f, entity->dp))); + dd_player = v2_add(dd_player, v2_unary(v2_multiply(1.5f, entity->dp))); old_player_p = entity->p; new_player_p = old_player_p; - player_delta = V2Add(V2Multiply(0.5f, V2Multiply(Square(dt), dd_player)), - V2Multiply(dt, entity->dp)); - new_player_p.offset = V2Add(player_delta, new_player_p.offset); - entity->dp = V2Add(V2Multiply(dt, dd_player), entity->dp); + player_delta = v2_add(v2_multiply(0.5f, v2_multiply(square(dt), dd_player)), + v2_multiply(dt, entity->dp)); + new_player_p.offset = v2_add(player_delta, new_player_p.offset); + entity->dp = v2_add(v2_multiply(dt, dd_player), entity->dp); new_player_p = recannonicalize_position(tile_map, new_player_p); { @@ -402,42 +399,44 @@ static void move_player(struct game_state *game_state, r.y = -1; } - entity->dp = V2Subtract(entity->dp, - V2Multiply(1*InnerProduct(entity->dp, r), r)); + entity->dp = v2_subtract(entity->dp, + v2_multiply(1*inner_product(entity->dp, r), r)); } else { entity->p = new_player_p; } #else - unsigned int MinTileX = 0; - unsigned int MinTileY = 0; - unsigned int OnePastMaxTileX = 0; - unsigned int OnePastMaxTileY = 0; - unsigned int abs_tile_z = game_state->PlayerP.abs_tile_z; - tile_map_position BestPlayerP = game_state->PlayerP; - F32 BestDistance = LengthSq(player_delta); - for(unsigned int abs_tile_y = MinTileY; - abs_tile_y != OnePastMaxTileY; + unsigned int min_tile_x = 0; + unsigned int min_tile_y = 0; + unsigned int one_past_max_tile_x = 0; + unsigned int one_past_max_tile_y = 0; + unsigned int abs_tile_z = game_state->player_p.abs_tile_z; + tile_map_position best_player_p = game_state->player_p; + F32 best_distance = length_sq(player_delta); + for(unsigned int abs_tile_y = min_tile_y; + abs_tile_y != one_past_max_tile_y; abs_tile_y++) { - for(unsigned int abs_tile_x = MinTileX; - abs_tile_x != OnePastMaxTileX; + for(unsigned int abs_tile_x = min_tile_x; + abs_tile_x != one_past_max_tile_x; abs_tile_x++) { - tile_map_position TestTileP = - CenteredTilePoint(abs_tile_x, abs_tile_y, abs_tile_z); - unsigned int TileValue = get_tile_value_by_pos(tile_map, TestTileP); - if(IsTileValueEmpty(TileValue)) { - v2 MinCorner = V2Multiply(-0.5f, + tile_map_position test_tile_p = + centered_tile_point(abs_tile_x, abs_tile_y, abs_tile_z); + unsigned int tile_value = + get_tile_value_by_pos(tile_map, test_tile_p); + if(is_tile_value_empty(tile_value)) { + v2 min_corner = v2_multiply(-0.5f, (v2){ tile_map->tile_side_in_meters, tile_map->tile_side_in_meters }); - v2 MaxCorner = V2Multiply(-0.5f, + v2 max_corner = v2_multiply(-0.5f, (v2){ tile_map->tile_side_in_meters, tile_map->tile_side_in_meters }); - tile_map_difference RelNewPlayerP = - SubtractInF32(tile_map, &TestTileP, &new_player_p); - v2 TestP = ClosestPointInRectangle(MinCorner, MaxCorner, - RelNewPlayerP); + tile_map_difference rel_new_player_p = + subtract_in_f32(tile_map, &test_tile_p, &new_player_p); + v2 test_p = closest_point_in_rectangle(min_corner, + max_corner, + rel_new_player_p); if(...) { } } @@ -846,10 +845,6 @@ void update_and_render(struct thread_context *thread, } } - /*draw_rectangle(buffer, 0.0f, 0.0f, - (F32)buffer->Width, (F32)buffer->Height, - 0.0f, 1.0f, 0.0f);*/ - draw_bitmap(buffer, &game_state->backdrop, 0.0f, 0.0f, 0, 0); screen_center_x = 0.5f * (float)buffer->width; @@ -894,8 +889,8 @@ void update_and_render(struct thread_context *thread, Center.y = screen_center_y + meters_to_pixels * game_state->camera_p.offset.y - (float)rel_row*(float)tile_side_in_pixels; - Min = V2Subtract(Center, TileSide); - Max = V2Add(Center, TileSide); + Min = v2_subtract(Center, TileSide); + Max = v2_add(Center, TileSide); draw_rectangle(buffer, Min, Max, Gray, Gray, Gray); } } @@ -934,12 +929,13 @@ void update_and_render(struct thread_context *thread, player_ground_point_y - meters_to_pixels*entity->height; player_width_height.x = entity->width; - player_width_height.x = entity->height; + player_width_height.y = entity->height; draw_rectangle(buffer, player_left_top, - V2Add(player_left_top, V2Multiply(meters_to_pixels, - player_width_height)), - player_r, player_g, player_b); + v2_add(player_left_top, + v2_multiply(meters_to_pixels, + player_width_height)), + player_r, player_g, player_b); bitmap = &game_state->hero_bitmaps[entity->facing_direction]; draw_bitmap(buffer, &bitmap->torso, diff --git a/handmade_math.h b/handmade_math.h index 4f83daf..a7b4c96 100644 --- a/handmade_math.h +++ b/handmade_math.h @@ -7,7 +7,7 @@ struct v2 { float e[2]; }; -struct v2 V2(float x, float y) +struct v2 v2(float x, float y) { struct v2 result; @@ -17,7 +17,7 @@ struct v2 V2(float x, float y) return result; } -struct v2 V2Multiply(float a, struct v2 b) +struct v2 v2_multiply(float a, struct v2 b) { struct v2 result; @@ -27,7 +27,7 @@ struct v2 V2Multiply(float a, struct v2 b) return result; } -struct v2 V2Unary(struct v2 a) +struct v2 v2_unary(struct v2 a) { struct v2 result; @@ -37,7 +37,7 @@ struct v2 V2Unary(struct v2 a) return result; } -struct v2 V2Add(struct v2 a, struct v2 b) +struct v2 v2_add(struct v2 a, struct v2 b) { struct v2 result; @@ -47,7 +47,7 @@ struct v2 V2Add(struct v2 a, struct v2 b) return result; } -struct v2 V2Subtract(struct v2 a, struct v2 b) +struct v2 v2_subtract(struct v2 a, struct v2 b) { struct v2 result; @@ -57,7 +57,7 @@ struct v2 V2Subtract(struct v2 a, struct v2 b) return result; } -float Square(float a) +float square(float a) { float result; @@ -66,15 +66,15 @@ float Square(float a) return result; } -float InnerProduct(struct v2 a, struct v2 b) +float inner_product(struct v2 a, struct v2 b) { float result = a.x*b.x + a.y*b.y; return result; } -float LengthSq(struct v2 a) +float length_sq(struct v2 a) { - float result = InnerProduct(a, a); + float result = inner_product(a, a); return result; } diff --git a/handmade_tile.c b/handmade_tile.c index ca9f75f..6807981 100644 --- a/handmade_tile.c +++ b/handmade_tile.c @@ -225,9 +225,9 @@ subtract_in_float(struct tile_map *tile_map, d_tile_z = (float)a->abs_tile_z - (float)b->abs_tile_z; - result.d_xy = V2Add(V2Multiply(tile_map->tile_side_in_meters, - d_tile_xy), - V2Subtract(a->offset, b->offset)); + result.d_xy = v2_add(v2_multiply(tile_map->tile_side_in_meters, + d_tile_xy), + v2_subtract(a->offset, b->offset)); /* TODO: Incomplete . . . */ result.d_z = tile_map->tile_side_in_meters*d_tile_z; diff --git a/profiler.h b/profiler.h new file mode 100644 index 0000000..be0c807 --- /dev/null +++ b/profiler.h @@ -0,0 +1,128 @@ +#ifndef PROFILER_H +#define PROFILER_H + +#ifndef PROFILER +#define PROFILER 1 +#endif + +#if PROFILER + +#include /* malloc */ +#include /* memset */ +#include /* clock_gettime */ +#include + +unsigned long long profiler_get_time() +{ + struct timespec ts; + + if(clock_gettime(CLOCK_MONOTONIC_RAW, &ts) == 0) { + return (unsigned long long)ts.tv_sec * 1000000000ULL + + (unsigned long long)ts.tv_nsec; + } + + return 0ULL; +} + +struct profiler_block { + const char *name; + + unsigned long long start; + unsigned long long end; +}; + +struct profiler_tree_node { + struct profiler_block data; + + struct profiler_tree_node *parent; /* null for root node */ + + struct profiler_tree_node *prev_sibling; /* doubly-linked list */ + struct profiler_tree_node *next_sibling; + + int children_count; + struct profiler_tree_node *first_child; + struct profiler_tree_node *last_child; +}; + +struct profiler_tree_node *profiler_root_node = 0; +struct profiler_tree_node *profiler_last_node = 0; + +static struct profiler_tree_node *profiler_tree_node(const char *name) +{ + struct profiler_tree_node *node = + malloc(sizeof(struct profiler_tree_node)); + memset(node, 0, sizeof(struct profiler_tree_node)); + node->data.name = name; + return node; +} + +void profiler_begin(const char *name) +{ + if(!profiler_root_node) { /* create root node */ + profiler_root_node = profiler_tree_node("TOTAL"); + profiler_last_node = profiler_root_node; + } + + struct profiler_tree_node *node = profiler_tree_node(name); + node->data.start = profiler_get_time(); + node->parent = profiler_last_node; + + if(!profiler_last_node->last_child) { + profiler_last_node->first_child = node; + profiler_last_node->last_child = node; + } else { + profiler_last_node->last_child->next_sibling = node; + node->prev_sibling = profiler_last_node->last_child; + profiler_last_node->last_child = node; + } + profiler_last_node->children_count++; + + profiler_last_node = node; +} + +static void profiler_do_print(struct profiler_tree_node *node, + int indent_level) +{ + if(node) { + unsigned long long difference; + + int i; + for(i = 0; i < indent_level; i++) + fprintf(stderr, " "); + + difference = node->data.end - node->data.start; + + fprintf(stderr, "[%s] %lld ns (%.6f ms)\n", + node->data.name, + difference, + (double)(difference) / 1000000.0); + + if(node->first_child) { + profiler_do_print(node->first_child, indent_level+1); + } + if(node->next_sibling) { + profiler_do_print(node->next_sibling, indent_level); + } + } +} + +void profiler_print() +{ + profiler_do_print(profiler_root_node->first_child, 0); +} + +void profiler_end() +{ + profiler_last_node->data.end = profiler_get_time(); + profiler_last_node = profiler_last_node->parent; +} + +#else + +#define profiler_begin(...) +#define profiler_end(...) +#define profiler_print(...) + +#endif + +#endif /* profiler_h */ diff --git a/sdl_handmade.c b/sdl_handmade.c index b401cd2..936146b 100644 --- a/sdl_handmade.c +++ b/sdl_handmade.c @@ -766,26 +766,36 @@ U64 __rdtsc() } #endif +#include "profiler.h" + int main(int argc, char *argv[]) { struct sdl_state sdl_state; SDL_Window *window; + int i; + memset(&sdl_state, 0, sizeof(sdl_state)); - sdl_get_exe_dir_path(sdl_state.exe_dir_path, sizeof(sdl_state.exe_dir_path)); + sdl_get_exe_dir_path(sdl_state.exe_dir_path, + sizeof(sdl_state.exe_dir_path)); sdl_get_dll_path(sdl_state.dll_path, sizeof(sdl_state.dll_path), sdl_state.exe_dir_path); - if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD)) { + if(!SDL_Init(SDL_INIT_VIDEO)) { /* TODO: This didn't work . . . */ } + /* NOTE: It takes roughly half a second to initialize + * SDL_INIT_GAMEPAD. */ + if(!SDL_InitSubSystem(SDL_INIT_GAMEPAD)) { + /* TODO: This didn't work . . . */ + } sdl_init_controllers(); /* NOTE: Create hidden window so that a blank window doesn't appear - * before everything is ready. */ + * before everything is ready. */ /* TODO: SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, in non-debug * build */ window = SDL_CreateWindow("Handmade Hero", @@ -793,6 +803,7 @@ int main(int argc, char *argv[]) SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY /*| SDL_WINDOW_ALWAYS_ON_TOP*/); + if(window) { const SDL_DisplayMode *display_mode; @@ -837,7 +848,8 @@ int main(int argc, char *argv[]) memset(&temp_context, 0, sizeof(temp_context)); /* TODO: Make it a global. */ - pointer_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT); + pointer_cursor = + SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT); SDL_SetCursor(pointer_cursor); #if !BUILD_INTERNAL if(SDL_ShowCursor(SDL_DISABLE) < 0) { @@ -872,6 +884,9 @@ int main(int argc, char *argv[]) sound_output.samples_per_second / 15; #if 0 + if(!SDL_InitSubSystem(SDL_INIT_AUDIO)) { + /* TODO: This didn't work . . . */ + } sdl_init_sound(sound_output.SamplesPerSecond, sound_output.SamplesPerSecond * sound_output.BytesPerSample / 60); @@ -880,7 +895,8 @@ int main(int argc, char *argv[]) sound_output.Samples = calloc(sound_output.SamplesPerSecond, sound_output.BytesPerSample); - /*sound_output.Samples = malloc(sound_output.SecondaryBufferSize);*/ + /*sound_output.Samples = + malloc(sound_output.SecondaryBufferSize);*/ /* NOTE: calloc auto clears to zero */ /* sdl_clear_sound_buffer(&sound_output); */ #endif @@ -947,7 +963,8 @@ int main(int argc, char *argv[]) game = sdl_load_game_code(sdl_state.dll_path); - SDL_ShowWindow(window); // Everything is ready; display the window. + /* Everything is ready; display the window.*/ + SDL_ShowWindow(window); fps_last_counter = sdl_get_wall_clock();