From b8ca31cb20427ce6184d90dc5b61b720a3f15971 Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Fri, 28 Feb 2025 17:49:44 +0100 Subject: [PATCH] FPS-Counter copied, more stuff done --- .gitignore | 2 + CMakeLists.txt | 2 +- SDL_FPSCounter.c | 51 ++++++++++++ SDL_FPSCounter.h | 19 +++++ hello.c | 197 ++++++++++++++++++++++++++++++++++++----------- 5 files changed, 227 insertions(+), 44 deletions(-) create mode 100644 .gitignore create mode 100644 SDL_FPSCounter.c create mode 100644 SDL_FPSCounter.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f7f4fdf --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +.project \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index b6c26b6..bff39c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ add_subdirectory(submodules/SDL_ttf EXCLUDE_FROM_ALL) add_subdirectory(submodules/utilitiec EXCLUDE_FROM_ALL) # Create your game executable target as usual -add_executable(hello WIN32 hello.c) +add_executable(hello WIN32 hello.c SDL_FPSCounter.c) # Link to the actual SDL3 library. target_link_libraries(hello PRIVATE SDL3_ttf::SDL3_ttf SDL3::SDL3 QuadTree allocator-interface rand m) diff --git a/SDL_FPSCounter.c b/SDL_FPSCounter.c new file mode 100644 index 0000000..7ae04a2 --- /dev/null +++ b/SDL_FPSCounter.c @@ -0,0 +1,51 @@ +#include "SDL_FPSCounter.h" + +#include +#include + +int SDL_CreateFPSCounter(SDL_FPSCounter* counter, uint32_t window_length) +{ + counter->window = malloc(sizeof(uint64_t) * window_length); + if (counter->window == NULL) { + SDL_OutOfMemory(); + return -1; + } + memset(counter->window, 0, window_length * sizeof(uint64_t)); + counter->frequency = SDL_GetPerformanceFrequency(); + counter->window_index = 0; + counter->window_length = window_length; + + return EXIT_SUCCESS; +} + +void SDL_DestroyFPSCounter(SDL_FPSCounter* counter) +{ + free(counter->window); + memset(counter, 0, sizeof *counter); +} + +int SDL_FPSCounterTick(SDL_FPSCounter* counter) +{ + counter->window[counter->window_index] = SDL_GetPerformanceCounter(); + counter->window_index++; + counter->window_index = counter->window_index % counter->window_length; + + return EXIT_SUCCESS; +} + +uint64_t SDL_FPSCounterFPS(SDL_FPSCounter* counter) +{ + uint64_t last = counter->window[counter->window_index]; + uint64_t current; + uint64_t acc_difference = 0; + + for (uint32_t i = (counter->window_index + 1) % counter->window_length; i != counter->window_index; i = (i + 1) % counter->window_length) { + current = counter->window[i]; + acc_difference += current - last; + + last = current; + } + + uint64_t average_difference = acc_difference / (counter->window_length - 1); + return counter->frequency / average_difference; +} diff --git a/SDL_FPSCounter.h b/SDL_FPSCounter.h new file mode 100644 index 0000000..ca18f95 --- /dev/null +++ b/SDL_FPSCounter.h @@ -0,0 +1,19 @@ +#ifndef SDL_FPSCOUNTER_H +#define SDL_FPSCOUNTER_H + +#include + +typedef struct SDL_FPSCounter_s { + uint64_t frequency; + uint32_t window_index; + uint32_t window_length; + uint64_t* window; +} SDL_FPSCounter; + +int SDL_CreateFPSCounter(SDL_FPSCounter* counter, uint32_t window_length); +void SDL_DestroyFPSCounter(SDL_FPSCounter* counter); + +int SDL_FPSCounterTick(SDL_FPSCounter* counter); +uint64_t SDL_FPSCounterFPS(SDL_FPSCounter* counter); + +#endif diff --git a/hello.c b/hello.c index 7929ad7..de92292 100644 --- a/hello.c +++ b/hello.c @@ -14,70 +14,80 @@ #include #include #include +#include +#include #define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ #include #include #include +#include "SDL_FPSCounter.h" + #include "submodules/utilitiec/src/QuadTree/QuadTree.h" #include "submodules/utilitiec/src/rand/xoshiro256.h" static SDL_Window *window = NULL; static SDL_Renderer *renderer = NULL; static QuadTree tree; +static SDL_FPSCounter fps_counter; +static scalar view_angle = 0.25 * M_PI; typedef struct Particle_s { - QuadTreeLeaf position; + QuadTreeLeaf position; double velocity; double direction; } Particle; -static Particle particles[1000]; +static Particle particles[500]; scalar QuadTreeLeaf_norm(QuadTreeLeaf* vector) { - return sqrt(pow(vector->x, 2) + pow(vector->y, 2)); + return sqrt(pow(vector->x, 2) + pow(vector->y, 2)); } -scalar Particle_AngleBetweenDirectionAndOtherParticle(Particle* this, Particle* other) +scalar Particle_AngleTo(Particle* this, QuadTreeLeaf* other) { - QuadTreeLeaf vectorFromThisToOther = {other->position.x - this->position.x, other->position.y - this->position.y}; - QuadTreeLeaf thisDirectionAsVector = {cos(this->direction), sin(this->direction)}; - scalar normProduct = QuadTreeLeaf_norm(&vectorFromThisToOther) * QuadTreeLeaf_norm(&thisDirectionAsVector); - if (normProduct == 0) return 0; - return (vectorFromThisToOther.x * thisDirectionAsVector.x + vectorFromThisToOther.y * thisDirectionAsVector.y) / normProduct; + QuadTreeLeaf distance_vector = {other->x - this->position.x, other->y - this->position.y}; + QuadTreeLeaf direction_vector = {cos(this->direction), sin(this->direction)}; + scalar distance_norm = QuadTreeLeaf_norm(&distance_vector); + if (distance_norm == 0) return 0; + scalar angle = acos((distance_vector.x * direction_vector.x + distance_vector.y * direction_vector.y) / distance_norm); + if (isnan(angle)) return M_PI - 0.01; + return angle; } /* This function runs once at startup. */ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) { - SDL_Color color = { 255, 255, 255, SDL_ALPHA_OPAQUE }; - SDL_Surface *text; + SDL_Color color = { 255, 255, 255, SDL_ALPHA_OPAQUE }; + SDL_Surface *text; - /* Create the window */ - if (!SDL_CreateWindowAndRenderer("Swarm Simulation", 600, 600, 0, &window, &renderer)) { - SDL_Log("Couldn't create window and renderer: %s\n", SDL_GetError()); - return SDL_APP_FAILURE; - } + /* Create the window */ + if (!SDL_CreateWindowAndRenderer("Swarm Simulation", 600, 600, 0, &window, &renderer)) { + SDL_Log("Couldn't create window and renderer: %s\n", SDL_GetError()); + return SDL_APP_FAILURE; + } - if (!TTF_Init()) { - SDL_Log("Couldn't initialise SDL_ttf: %s\n", SDL_GetError()); - return SDL_APP_FAILURE; - } + if (!TTF_Init()) { + SDL_Log("Couldn't initialise SDL_ttf: %s\n", SDL_GetError()); + return SDL_APP_FAILURE; + } - QuadTree_Create(&tree, 600, 600, NULL); + QuadTree_Create(&tree, 600, 600, NULL); - Xoshiro256State rand_state = { 0, 10, 10, 0 }; + Xoshiro256State rand_state = { 0, 10, 10, 10 }; - for (size_t i = 0; i < sizeof(particles) / sizeof(particles[0]); i++) { - particles[i].position.x = xoshiro256_next(&rand_state) % 600; - particles[i].position.y = xoshiro256_next(&rand_state) % 600; - particles[i].velocity = xoshiro256_next(&rand_state) % 7; - particles[i].direction = (xoshiro256_next(&rand_state) % 1000) / 999.0 * acos(0); - QuadTree_Insert(&tree, &particles[i].position); - } + for (size_t i = 0; i < sizeof(particles) / sizeof(particles[0]); i++) { + particles[i].position.x = xoshiro256_next(&rand_state) % 600; + particles[i].position.y = xoshiro256_next(&rand_state) % 600; + particles[i].velocity = 5; + particles[i].direction = 1; + QuadTree_Insert(&tree, &particles[i].position); + } - return SDL_APP_CONTINUE; + SDL_CreateFPSCounter(&fps_counter, 60); + + return SDL_APP_CONTINUE; } /* This function runs when a new event (mouse input, keypresses, etc) occurs. */ @@ -104,23 +114,111 @@ int QuadTree_DrawTree(void* context, QuadSubTree* tree, QuadTreeDimension dimens void Particle_Move(Particle* self) { - self->position.x += 1/60.0 * self->velocity * cos(self->direction); - self->position.y += 1/60.0 * self->velocity * sin(self->direction); + double frame_rate = SDL_FPSCounterFPS(&fps_counter); + if (frame_rate == 0) { + frame_rate = 60; + } + printf("%lu\n", SDL_FPSCounterFPS(&fps_counter)); + + Particle copy = *self; + + self->position.x += 1.0/frame_rate * 50 * self->velocity * cos(self->direction); + self->position.y += 1.0/frame_rate * 50 * self->velocity * sin(self->direction); + + if (self->position.x < 0) { + self->position.x *= -1; + self->direction -= 2 * (self->direction - M_PI_2); + } + if (self->position.y < 0) { + self->position.y *= -1; + self->direction -= 2 * (self->direction - M_PI); + } + if (self->position.x > 600) { + self->position.x -= self->position.x - 600; + self->direction -= 2 * (self->direction - M_PI_2); + } + if (self->position.y > 600) { + self->position.y -= self->position.y - 600; + self->direction -= 2 * (self->direction - M_PI); + } + + /* self->position.x = self->position.x > 600 ? self->position.x - 600 : self->position.x; + self->position.x = self->position.x < 0 ? self->position.x + 600 : self->position.x; self->position.y = self->position.y > 600 ? self->position.y - 600 : self->position.y; + self->position.y = self->position.y < 0 ? self->position.y + 600 : self->position.y; + */ + + if(isnan(self->position.x) || isnan(self->position.y)) { + printf("Before %f, %f, direction %f, velocity %f\n", copy.position.x, copy.position.y, copy.direction, copy.velocity); + } } -void Particle_turnTo(Particle* self, Particle* target) +struct InteractionContext { + int count; + double angleSum; + QuadTreeLeaf positionSum; + Particle* self; +}; + +void Particle_ApplyInteraction(Particle* self, struct InteractionContext* interaction_context) { - scalar angle = Particle_AngleBetweenDirectionAndOtherParticle(self, target); - self->direction += angle; - self->direction /= 2; + self->direction += interaction_context->angleSum; + self->direction /= (interaction_context->count + 1); + + QuadTreeLeaf vectorToPositionSum = { + .x = interaction_context->positionSum.x / (interaction_context->count + 1), + .y = interaction_context->positionSum.y / (interaction_context->count + 1), + }; + + + scalar angleToPositionSum = Particle_AngleTo(self, &vectorToPositionSum); + + if(isnan(angleToPositionSum)) { + printf("self: %f, %f, direction: %f\n", self->position.x, self->position.y, self->direction); + printf("vectorToPosSum: %f, %f\n", vectorToPositionSum.x, vectorToPositionSum.y); + } + + self->direction += angleToPositionSum / 2; +} + +int InteractionContext_NearbyLeafCallback(void* _context, QuadTreeLeaf* leaf) +{ + struct InteractionContext* interaction_context = (struct InteractionContext*) _context; + Particle* particle = (Particle*) leaf; + if (particle == interaction_context->self) return EXIT_SUCCESS; + scalar angle = Particle_AngleTo(interaction_context->self, &particle->position); + if (fabs(angle) <= view_angle) { + interaction_context->angleSum += angle; + interaction_context->count++; + } + + interaction_context->positionSum.x += leaf->x; + interaction_context->positionSum.y += leaf->y; + + return EXIT_SUCCESS; +} + +int QuadTreeCallBack_ColorLeaf(void* context, QuadTreeLeaf* leaf) +{ + SDL_FRect render_rect; + render_rect.x = leaf->x - 5; + render_rect.y = leaf->y - 5; + render_rect.h = 10; + render_rect.w = 10; + SDL_RenderRect(renderer, &render_rect); + + return EXIT_SUCCESS; } /* This function runs once per frame, and is the heart of the program. */ SDL_AppResult SDL_AppIterate(void *appstate) { + + SDL_FPSCounterTick(&fps_counter); + //printf("%lu\n", SDL_FPSCounterFPS(&fps_counter)); + // clear screen SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); @@ -130,24 +228,37 @@ SDL_AppResult SDL_AppIterate(void *appstate) QuadTree new_tree; QuadTree_Create(&new_tree, 600, 600, tree.allocator); + QuadTreeLeaf sumPosition = {0, 0}; - + struct InteractionContext interactionContext = {0, 0, sumPosition, NULL}; for (size_t i = 0; i < sizeof(particles) / sizeof(particles[0]); i++) { - Particle_turnTo(particles + i, particles + 0); + sumPosition = particles[i].position; + interactionContext = (struct InteractionContext) {0, 0, sumPosition, &particles[i]}; + QuadTree_ForEachLeafInRadius(&tree, InteractionContext_NearbyLeafCallback, &interactionContext, particles[i].position, 50); + Particle_ApplyInteraction(&particles[i], &interactionContext); Particle_Move(particles + i); - QuadTree_Insert(&new_tree, &particles[i].position); - SDL_RenderPoint(renderer, particles[i].position.x, particles[i].position.y); + + QuadTree_Insert(&new_tree, &particles[i].position); + + SDL_RenderPoint(renderer, particles[i].position.x, particles[i].position.y); } -SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); + QuadTree_ForEachLeafInRadius(&tree, QuadTreeCallBack_ColorLeaf, &interactionContext, particles[0].position, 50); - SDL_RenderPoint(renderer, particles[0].position.x, particles[0].position.y); + SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); + + SDL_FRect render_rect; + render_rect.x = particles[0].position.x - 5; + render_rect.y = particles[0].position.y - 5; + render_rect.h = 10; + render_rect.w = 10; + SDL_RenderRect(renderer, &render_rect); QuadTree_Destroy(&tree); tree = new_tree; - //QuadTree_ForEachTree(&tree, QuadTree_DrawTree, NULL); + QuadTree_ForEachTree(&tree, QuadTree_DrawTree, NULL); // swap SDL_RenderPresent(renderer);