From 1d12a23e151acafc6cd0a912560b4562d682f287 Mon Sep 17 00:00:00 2001 From: Diogo Diniz Date: Thu, 16 Apr 2026 21:30:35 +0100 Subject: [PATCH] chore: Initial commit --- .gitignore | 2 + i3bgwin | Bin 0 -> 14704 bytes makefile | 46 ++++++++++++++++++ src/main.cpp | 67 +++++++++++++++++++++++++ src/math.hpp | 102 +++++++++++++++++++++++++++++++++++++++ src/renderer.hpp | 79 ++++++++++++++++++++++++++++++ src/sim/aircraft.cpp | 12 +++++ src/sim/aircraft.hpp | 24 +++++++++ src/sim/airfield.cpp | 11 +++++ src/sim/airfield.hpp | 23 +++++++++ src/sim/world.cpp | 17 +++++++ src/sim/world.hpp | 29 +++++++++++ src/sim/world_object.hpp | 18 +++++++ 13 files changed, 430 insertions(+) create mode 100644 .gitignore create mode 100755 i3bgwin create mode 100644 makefile create mode 100644 src/main.cpp create mode 100644 src/math.hpp create mode 100644 src/renderer.hpp create mode 100644 src/sim/aircraft.cpp create mode 100644 src/sim/aircraft.hpp create mode 100644 src/sim/airfield.cpp create mode 100644 src/sim/airfield.hpp create mode 100644 src/sim/world.cpp create mode 100644 src/sim/world.hpp create mode 100644 src/sim/world_object.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c7614e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +**.vscode/ +build/ diff --git a/i3bgwin b/i3bgwin new file mode 100755 index 0000000000000000000000000000000000000000..bfc9e7f58c499f5fa0009aa0b931816d96889b32 GIT binary patch literal 14704 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 literal 0 HcmV?d00001 diff --git a/makefile b/makefile new file mode 100644 index 0000000..417a3d1 --- /dev/null +++ b/makefile @@ -0,0 +1,46 @@ +CC=g++ +C_FLAGS=-g -Wall -Wextra -O0 -Wno-unused-function +#C_FLAGS=-Wall -Wextra -O3 -Wno-unused-function +VAL_FLAGS=--leak-check=full --show-leak-kinds=all --track-origins=yes -s + +DIR_SRC=src +DIR_INC=include +DIR_BUILD=build +DEPS=SDL3 + +OUTBIN=$(DIR_BUILD)/bin/main + +SRCS=$(shell find $(DIR_SRC)/ -type f -name '*.cpp') +OBJS=$(patsubst $(DIR_SRC)/%.cpp,$(DIR_BUILD)/obj/%.o,$(SRCS)) + +DEPS_EXT=$(patsubst %,-l%,$(DEPS)) +INCS_EXT=$(patsubst %,-I%,$(DIR_INC)) + + +.PHONY: all build run dbg val clean test clean-tests + + +all: build +build: $(OUTBIN) +rebuild: clean .WAIT build + + +run: $(OUTBIN) + ./i3bgwin $(OUTBIN) {windowid} + +$(OUTBIN): $(OBJS) + @mkdir -p $(@D) + $(CC) $(OBJS) $(DEPS_EXT) -o $@ + +$(DIR_BUILD)/obj/%.o: $(DIR_SRC)/%.cpp + @mkdir -p $(@D) + $(CC) $(C_FLAGS) $(INCS_EXT) -c $< -o $@ + +dbg: $(DBG_BIN) + gdb $(GDB_FLAGS) ./$(OUTBIN) + +val: $(DBG_BIN) + valgrind $(VAL_FLAGS) ./$(OUTBIN) + +clean: + $(RM) -r $(DIR_BUILD) diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..d5c2b59 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,67 @@ +#include +#include +#include + +#include + +#include "renderer.hpp" + +#include "sim/world.hpp" +#include "sim/aircraft.hpp" + +static SDL_Window *window; +static SDL_Renderer *sdl_renderer; +static int width, height; + +int main(int argc, char *argv[]) +{ + if (argc != 2) + { + printf("Usage: %s \n", argv[0]); + exit(1); + } + + int wid = 0; + sscanf(argv[1], "%d", &wid); + + SDL_Init(SDL_INIT_VIDEO); + + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X11_WINDOW_NUMBER, wid); + + window = SDL_CreateWindowWithProperties(props); + sdl_renderer = SDL_CreateRenderer(window, NULL); + + SDL_GetWindowSize(window, &width, &height); + dxd::Renderer renderer = dxd::Renderer(sdl_renderer, width, height); + + // World init + dxd::sim::World world = dxd::sim::World({ .x = 10, .y = 10 }); + dxd::sim::Aircraft *ac = new dxd::sim::Aircraft({ 0, 0 }, 1, 0.1); + world.add_obj(ac); + + SDL_Event event; + bool running = true; + + while (running) { + while (SDL_PollEvent(&event)) { + if (event.type == SDL_EVENT_QUIT) running = false; + } + + // Clear + renderer.color(0, 0, 0, 255); + SDL_RenderClear(sdl_renderer); + + // World draw + renderer.color(255, 255, 255, 255); + world.draw(&renderer); + world.tick(1.0f / 60.0f); + + // Usual test + renderer.color(127, 0, 0, 255); + renderer.line(-vec2_one, vec2_one); + + SDL_RenderPresent(sdl_renderer); + SDL_Delay(1000 / 60); + } +} diff --git a/src/math.hpp b/src/math.hpp new file mode 100644 index 0000000..387d692 --- /dev/null +++ b/src/math.hpp @@ -0,0 +1,102 @@ +#pragma once + +#include +#include + +//#define epsilon 0.0000001 + + + +typedef struct vec2 { float x, y; } vec2; +typedef struct vec2i { int x, y; } vec2i; + +static const vec2 vec2_zero = { 0, 0 }; +static const vec2 vec2_one = { 1, 1 }; +static const vec2 vec2_max = { FLT_MAX, FLT_MAX }; +static const vec2 vec2_min = { -FLT_MAX, -FLT_MAX }; +static const vec2i vec2i_zero = { 0, 0 }; +static const vec2i vec2i_one = { 1, 1 }; + +static vec2 operator-(vec2 const &v) +{ + return { .x = -v.x, .y = -v.y }; +} + +static vec2 operator+(vec2 const &a, vec2 const &b) +{ + return { .x = a.x + b.x, .y = a.y + b.y }; +} + +static vec2 operator-(vec2 const &a, vec2 const &b) +{ + return { .x = a.x - b.x, .y = a.y - b.y }; +} + +static vec2 operator*(vec2 const &a, float const &b) +{ + return { .x = a.x * b, .y = a.y * b }; +} + +static vec2 operator/(vec2 const &a, float const &b) +{ + return { .x = a.x / b, .y = a.y / b }; +} + +static bool operator<(vec2 const &a, vec2 const &b) +{ + return a.x < b.x && a.y < b.y; +} + +static bool operator>(vec2 const &a, vec2 const &b) +{ + return a.x > b.x && a.y > b.y; +} + +static float dot(vec2 const &a, vec2 const &b) +{ + return a.x * b.x + a.y * b.y; +} + +static float norm2(vec2 const &v) +{ + return v.x * v.x + v.y * v.y; +} + +static float norm(vec2 const &v) +{ + return std::sqrtf(v.x * v.x + v.y * v.y); +} + +static vec2 normalize(vec2 const &v) +{ + return v / norm(v); +} + +static inline vec2 normalize_h(vec2 const &v) +{ + return v / std::sqrt(v.x * v.x + v.y * v.y); +} + +static vec2 min2(vec2 const &a, vec2 const &b) +{ + return { + .x = a.x < b.x ? a.x : b.x, + .y = a.y < b.y ? a.y : b.y, + }; +} + +static vec2 max2(vec2 const &a, vec2 const &b) +{ + return { + .x = a.x > b.x ? a.x : b.x, + .y = a.y > b.y ? a.y : b.y, + }; +} + +static vec2 polar_to_vec2(const float angle, const float len) +{ + return { + .x = len * sinf(angle), + .y = len * cosf(angle) + }; +} diff --git a/src/renderer.hpp b/src/renderer.hpp new file mode 100644 index 0000000..9cfeb22 --- /dev/null +++ b/src/renderer.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include + +#include + +#include "math.hpp" + +namespace dxd +{ + +class Renderer +{ +private: + SDL_Renderer *_sdl; + int _width, _height; + vec2 _center; + float _scale; + + float to_screenf(float f) + { + //FIXME: Aspect ratio + return (f/2) * _height; + } + vec2 to_screenv2(vec2 p) + { + //TODO: Handle aspect ratio + return { + .x = ((p.x/2) + .5f) * _height, + .y = (.5f - (p.y/2)) * _height, + }; + } + + float to_viewf(float f) + { + return f * _scale; + } + vec2 to_viewv2(vec2 p) + { + return { + .x = (p.x - _center.x) * _scale, + .y = (p.y - _center.y) * _scale, + }; + } + +public: + Renderer(SDL_Renderer *sdl, int width, int height) : _sdl(sdl), _width(width), _height(height) + { + _center = { 0, 0 }; + _scale = 1; + } + + void color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) + { + SDL_SetRenderDrawColor(_sdl, r, g, b, a); + } + + void line(vec2 a, vec2 b) + { + vec2 as = to_screenv2(to_viewv2(a)), bs = to_screenv2(to_viewv2(b)); + SDL_RenderLine(_sdl, as.x, as.y, bs.x, bs.y); + } + + void dot(vec2 center, float size) + { + vec2 view = to_viewv2(center - vec2_one * (size/2)); + vec2 screen = to_screenv2(view); + float scr_size = to_screenf(to_viewf(size)); + SDL_FRect rect = { + .x = screen.x, + .y = screen.y - scr_size, //HACK: Do this somewhere else? Rect function? + .w = scr_size, + .h = scr_size, + }; + SDL_RenderFillRect(_sdl, &rect); + } +}; + +} // namespace dxd diff --git a/src/sim/aircraft.cpp b/src/sim/aircraft.cpp new file mode 100644 index 0000000..a0cf55c --- /dev/null +++ b/src/sim/aircraft.cpp @@ -0,0 +1,12 @@ +#include "aircraft.hpp" + +void dxd::sim::Aircraft::tick(float timestep, vec2 bounds) +{ + _position = _position + polar_to_vec2(_direction, _speed) * timestep; +} + +void dxd::sim::Aircraft::draw(Renderer *rend) +{ + rend->dot(_position, 0.02); + rend->line(_position, _position + polar_to_vec2(_direction, 0.05)); +} diff --git a/src/sim/aircraft.hpp b/src/sim/aircraft.hpp new file mode 100644 index 0000000..9effcf2 --- /dev/null +++ b/src/sim/aircraft.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "../math.hpp" +#include "world_object.hpp" + +namespace dxd::sim +{ + +class Aircraft : public WorldObject +{ +private: + vec2 _position; + float _direction; + float _speed; + +public: + Aircraft(vec2 position, float direction, float speed) + : _position(position), _direction(direction), _speed(speed) {} + + void tick(float timestep, vec2 bounds) override; + void draw(Renderer *rend) override; +}; + +} // namespace dxd::sim diff --git a/src/sim/airfield.cpp b/src/sim/airfield.cpp new file mode 100644 index 0000000..5b58f2d --- /dev/null +++ b/src/sim/airfield.cpp @@ -0,0 +1,11 @@ +#include "airfield.hpp" + +void dxd::sim::Airfield::tick(float timestep, vec2 bounds) +{ + +} + +void dxd::sim::Airfield::draw(Renderer *rend) +{ + +} diff --git a/src/sim/airfield.hpp b/src/sim/airfield.hpp new file mode 100644 index 0000000..d0f76e7 --- /dev/null +++ b/src/sim/airfield.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include "../math.hpp" +#include "world_object.hpp" + +namespace dxd::sim +{ + +class Airfield : public WorldObject +{ +private: + vec2 _position; + +public: + Airfield(vec2 position) : _position(position) {} + + void tick(float timestep, vec2 bounds) override; + void draw(Renderer *rend) override; +}; + +} // namespace dxd::sim diff --git a/src/sim/world.cpp b/src/sim/world.cpp new file mode 100644 index 0000000..610c616 --- /dev/null +++ b/src/sim/world.cpp @@ -0,0 +1,17 @@ +#include "world.hpp" + +void dxd::sim::World::tick(float timestep) +{ + for (auto obj : _objs) + { + obj->tick(timestep, _size); + } +} + +void dxd::sim::World::draw(Renderer *rend) +{ + for (auto obj : _objs) + { + obj->draw(rend); + } +} diff --git a/src/sim/world.hpp b/src/sim/world.hpp new file mode 100644 index 0000000..d16e323 --- /dev/null +++ b/src/sim/world.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "../math.hpp" +#include "world_object.hpp" + +namespace dxd::sim +{ + +class World +{ +private: + vec2 _size; + std::vector _objs; + +public: + World(vec2 size) : _size(size) + { + _objs = std::vector(); + } + + void add_obj(WorldObject *obj) { _objs.push_back(obj); } + + void tick(float timestep); + void draw(Renderer *rend); +}; + +} // namespace dxd::sim diff --git a/src/sim/world_object.hpp b/src/sim/world_object.hpp new file mode 100644 index 0000000..1412b1b --- /dev/null +++ b/src/sim/world_object.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "../math.hpp" +#include "../renderer.hpp" + +namespace dxd::sim +{ + +class WorldObject +{ +public: + WorldObject() {} + + virtual void tick(float timestep, vec2 bounds) = 0; + virtual void draw(Renderer *rend) = 0; +}; + +} // namespace dxd::sim