diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b8e5a39 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.sw* +*.o +game diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..3f53ce8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "entt"] + path = entt + url = https://github.com/skypjack/entt diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f0ad0d1 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +CXXFLAGS := -std=c++23 -O0 -g3 -ggdb \ + -Ientt/single_include +LDFLAGS := -lSDL2 -lSDL2_image + +OBJS := $(subst .cpp,.o,$(wildcard *.cpp)) + +all: game + +clean: + rm -f game $(OBJS) + +game: $(OBJS) + $(CXX) $(CXXFLAGS) $^ -o $@ $(LDFLAGS) + diff --git a/entt b/entt new file mode 160000 index 0000000..93f7d51 --- /dev/null +++ b/entt @@ -0,0 +1 @@ +Subproject commit 93f7d516f21e5f63422df983c02827ab1c8e050e diff --git a/img/player.png b/img/player.png new file mode 100644 index 0000000..810c152 Binary files /dev/null and b/img/player.png differ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..409e66b --- /dev/null +++ b/main.cpp @@ -0,0 +1,184 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +static constexpr auto WINDOW_WIDTH = 640; +static constexpr auto WINDOW_HEIGHT = 480; + +static SDL_Window *window = nullptr; +static SDL_Renderer *renderer = nullptr; + +static int sdl2Initialize(); +static SDL_Texture *sdl2LoadTexture(const char *path); + +struct Player { + char unused = 0; +}; + +struct Vec2 { + float x, y; + + auto& operator+=(const Vec2& o) noexcept { + x += o.x; + y += o.y; + return *this; + } +}; + +struct Point : public Vec2 {}; +struct Velocity : public Vec2 {}; + +class Texture +{ +public: + Texture(const char *path) { + tex = sdl2LoadTexture(path); + } + + ~Texture() { + if (tex != nullptr) + SDL_DestroyTexture(tex); + } + + void operator()(SDL_Renderer *rend, Point p) const noexcept { + const int x = static_cast(p.x); + const int y = static_cast(p.y); + SDL_Rect rect {x, y, 0, 0}; + + /* TODO err check */ + SDL_QueryTexture(tex, nullptr, nullptr, &rect.w, &rect.h); + SDL_RenderCopy(rend, tex, nullptr, &rect); + } + +private: + SDL_Texture *tex; +}; + +int main() +{ + if (auto err = sdl2Initialize(); err) + return err; + + entt::registry registry; + + const auto ent = registry.create(); + registry.emplace(ent); + registry.emplace(ent, 0.f, WINDOW_HEIGHT - 100.f); + registry.emplace(ent, 0.f, 0.f); + registry.emplace(ent, "img/player.png"); + + SDL_Event e; + bool quit = false; + while (!quit) { + const auto nextFrame = std::chrono::high_resolution_clock::now() + + std::chrono::microseconds(1'000'000 / 60); + + SDL_RenderClear(renderer); + registry.view().each( + [](Texture& tex, Point& p) { tex(renderer, p); }); + SDL_RenderPresent(renderer); + + registry.view().each( + [](Velocity& v, Point& p) { p += v; }); + + while (SDL_PollEvent(&e)) { + if (e.type == SDL_QUIT) { + quit = true; + } else if (e.type == SDL_KEYDOWN) { + auto view = registry.view(); + + if (e.key.repeat) { + // do nothing + } else if (e.key.keysym.sym == SDLK_d) { + view.each([](Player& p, Velocity& v) { v.x += 1.5f; }); + } else if (e.key.keysym.sym == SDLK_a) { + view.each([](Player& p, Velocity& v) { v.x -= 1.5f; }); + } + } else if (e.type == SDL_KEYUP) { + auto view = registry.view(); + + if (e.key.repeat) { + // do nothing + } else if (e.key.keysym.sym == SDLK_d) { + view.each([](Player& p, Velocity& v) { v.x -= 1.5f; }); + } else if (e.key.keysym.sym == SDLK_a) { + view.each([](Player& p, Velocity& v) { v.x += 1.5f; }); + } + } + } + + std::this_thread::sleep_until(nextFrame); + } + + SDL_DestroyWindow(window); + SDL_Quit(); +} + +int sdl2Initialize() +{ + if (auto err = SDL_Init(SDL_INIT_VIDEO); err < 0) { + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + return EXIT_FAILURE; + } else { + atexit(SDL_Quit); + } + + if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) { + std::cerr << "IMG error: " << IMG_GetError() << std::endl; + return EXIT_FAILURE; + } else { + atexit(IMG_Quit); + } + + window = SDL_CreateWindow("game", + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + WINDOW_WIDTH, WINDOW_HEIGHT, + SDL_WINDOW_SHOWN); + + if (window == nullptr) { + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + return EXIT_FAILURE; + } else { + atexit([] { SDL_DestroyWindow(window); }); + } + + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + + if (renderer == nullptr) { + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + return EXIT_FAILURE; + } else { + atexit([] { SDL_DestroyRenderer(renderer); }); + } + + return 0; +} + +SDL_Texture *sdl2LoadTexture(const char *path) +{ + SDL_Texture *tex = nullptr; + + auto surface = IMG_Load(path); + if (surface == nullptr) { + std::cerr << "Unable to load image " << path << '!' << std::endl; + std::cerr << "SDL error: " << IMG_GetError() << std::endl; + } else { + tex = SDL_CreateTextureFromSurface(renderer, surface); + + if (tex == nullptr) { + std::cerr << "Unable to create texture for " << path << '!' << std::endl; + std::cerr << "SDL error: " << SDL_GetError() << std::endl; + } else { + SDL_FreeSurface(surface); + } + } + + return tex; +} +