commit 1d12a23e151acafc6cd0a912560b4562d682f287 Author: Diogo Diniz Date: Thu Apr 16 21:30:35 2026 +0100 chore: Initial commit 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 0000000..bfc9e7f Binary files /dev/null and b/i3bgwin differ 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