165 lines
5.3 KiB
C
165 lines
5.3 KiB
C
/*
|
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely.
|
|
*/
|
|
#include <SDL3/SDL_rect.h>
|
|
#include <SDL3/SDL_render.h>
|
|
#include <SDL3/SDL_surface.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
|
|
#include <SDL3/SDL.h>
|
|
#include <SDL3/SDL_main.h>
|
|
#include <SDL3_ttf/SDL_ttf.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;
|
|
|
|
typedef struct Particle_s {
|
|
QuadTreeLeaf position;
|
|
double velocity;
|
|
double direction;
|
|
} Particle;
|
|
|
|
static Particle particles[1000];
|
|
|
|
scalar QuadTreeLeaf_norm(QuadTreeLeaf* vector)
|
|
{
|
|
return sqrt(pow(vector->x, 2) + pow(vector->y, 2));
|
|
}
|
|
|
|
scalar Particle_AngleBetweenDirectionAndOtherParticle(Particle* this, Particle* 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;
|
|
}
|
|
|
|
/* 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;
|
|
|
|
/* 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;
|
|
}
|
|
|
|
QuadTree_Create(&tree, 600, 600, NULL);
|
|
|
|
Xoshiro256State rand_state = { 0, 10, 10, 0 };
|
|
|
|
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);
|
|
}
|
|
|
|
return SDL_APP_CONTINUE;
|
|
}
|
|
|
|
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
|
|
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
|
|
{
|
|
if (event->type == SDL_EVENT_KEY_DOWN ||
|
|
event->type == SDL_EVENT_QUIT) {
|
|
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
|
|
}
|
|
return SDL_APP_CONTINUE;
|
|
}
|
|
|
|
int QuadTree_DrawTree(void* context, QuadSubTree* tree, QuadTreeDimension dimension)
|
|
{
|
|
SDL_FRect render_rect;
|
|
render_rect.x = dimension.left;
|
|
render_rect.y = dimension.top;
|
|
render_rect.h = dimension.bottom - dimension.top;
|
|
render_rect.w = dimension.right - dimension.left;
|
|
SDL_RenderRect(renderer, &render_rect);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
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);
|
|
|
|
self->position.x = self->position.x > 600 ? self->position.x - 600 : self->position.x;
|
|
self->position.y = self->position.y > 600 ? self->position.y - 600 : self->position.y;
|
|
}
|
|
|
|
void Particle_turnTo(Particle* self, Particle* target)
|
|
{
|
|
scalar angle = Particle_AngleBetweenDirectionAndOtherParticle(self, target);
|
|
self->direction += angle;
|
|
self->direction /= 2;
|
|
}
|
|
|
|
/* This function runs once per frame, and is the heart of the program. */
|
|
SDL_AppResult SDL_AppIterate(void *appstate)
|
|
{
|
|
// clear screen
|
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
|
SDL_RenderClear(renderer);
|
|
|
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
|
|
|
QuadTree new_tree;
|
|
QuadTree_Create(&new_tree, 600, 600, tree.allocator);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < sizeof(particles) / sizeof(particles[0]); i++) {
|
|
Particle_turnTo(particles + i, particles + 0);
|
|
|
|
Particle_Move(particles + i);
|
|
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);
|
|
|
|
SDL_RenderPoint(renderer, particles[0].position.x, particles[0].position.y);
|
|
|
|
QuadTree_Destroy(&tree);
|
|
tree = new_tree;
|
|
//QuadTree_ForEachTree(&tree, QuadTree_DrawTree, NULL);
|
|
|
|
// swap
|
|
SDL_RenderPresent(renderer);
|
|
|
|
return SDL_APP_CONTINUE;
|
|
}
|
|
|
|
/* This function runs once at shutdown. */
|
|
void SDL_AppQuit(void *appstate, SDL_AppResult result)
|
|
{
|
|
QuadTree_Destroy(&tree);
|
|
TTF_Quit();
|
|
SDL_DestroyWindow(window);
|
|
SDL_DestroyRenderer(renderer);
|
|
}
|