diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | window.h | 126 |
2 files changed, 127 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9bf3746 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +compile_commands.json diff --git a/window.h b/window.h new file mode 100644 index 0000000..3ecfe57 --- /dev/null +++ b/window.h @@ -0,0 +1,126 @@ +#pragma once + +// Easy window creation in C++. +// +// This header-only library uses SDL; therefore, on a Linux system, you need to +// add something to the effect of the following to your build system: +// CFLAGS += $(shell pkg-config --cflags sdl2) +// LDFLAGS += $(shell pkg-config --libs sdl2) + +#include <string> +#include <vector> +#include <functional> +#include <stdexcept> +#include <SDL.h> + + +class Window { +public: + class Opts { + public: + inline Opts() = default; + + inline Opts& fullscreen(bool f) { _fullscreen = f; return *this; } + inline Opts& resizeable(bool r) { _resizable = r; return *this; } + + inline bool fullscreen() const { return _fullscreen; } + inline bool resizable() const { return _resizable; } + + private: + bool _fullscreen = false; + bool _resizable = false; + }; + + /// The width and height passed to this function are _suggestions_. + /// The window manager may decide to use some other size instead, and this + /// size may also change during execution (especially if resizable, but + /// perhaps also otherwise). + inline Window(const std::string &title, int wid_sugg, int hei_sugg); + inline Window(const std::string &title, int wid_sugg, int hei_sugg, Opts opts); + + inline ~Window(); + + /// The draw buffer will be of size 3 * width * height; row-major order, RGB pixels. + using DrawHandler = std::function<void(std::vector<uint8_t> &drawbuf, int width, int height)>; + /// Return true to stop the event loop. + using EventHandler = std::function<bool(const SDL_Event&)>; + + /// The draw function will be called after each invocation of the event + /// function, and might also be invoked more often as the user re-focuses the + /// window. + inline void event_loop(EventHandler eventfunc, DrawHandler drawfunc); + +private: + SDL_Window *win = nullptr; + std::vector<uint8_t> drawbuf; + SDL_Surface *surface = nullptr; + int surf_wid = -1, surf_hei = -1; +}; + +inline Window::Window(const std::string &title, int wid_sugg, int hei_sugg) + : Window(title, wid_sugg, hei_sugg, Opts{}) +{} + +inline Window::Window(const std::string &title, int wid_sugg, int hei_sugg, Opts opts) { + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + throw std::runtime_error(std::string{"SDL init error: "} + SDL_GetError()); + } + + Uint32 flags = 0; + if (opts.fullscreen()) flags |= SDL_WINDOW_FULLSCREEN; + if (opts.resizable()) flags |= SDL_WINDOW_RESIZABLE; + + win = SDL_CreateWindow( + title.data(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + wid_sugg, hei_sugg, flags + ); + if (!win) { + throw std::runtime_error(std::string{"SDL window creation error: "} + SDL_GetError()); + } + + SDL_GetWindowSize(win, &surf_wid, &surf_hei); + drawbuf.resize(3 * surf_wid * surf_hei); + surface = SDL_CreateRGBSurfaceFrom( + drawbuf.data(), surf_wid, surf_hei, 24, 3 * surf_wid, + 255, 255 << 8, 255 << 16, 0 + ); + + SDL_BlitSurface(surface, nullptr, SDL_GetWindowSurface(win), nullptr); + SDL_UpdateWindowSurface(win); +} + +inline Window::~Window() { + if (surface) SDL_FreeSurface(surface); + SDL_DestroyWindow(win); + SDL_Quit(); +} + +inline void Window::event_loop(EventHandler eventfunc, DrawHandler drawfunc) { + SDL_Event e; + while (true) { + if (SDL_WaitEvent(&e) == 0) { + throw std::runtime_error(std::string{"SDL event wait error: "} + SDL_GetError()); + } + + if (e.type == SDL_QUIT) break; + + if (eventfunc(e)) break; + + int width, height; + SDL_GetWindowSize(win, &width, &height); + + if (width != surf_wid || height != surf_hei) { + SDL_FreeSurface(surface); + + surf_wid = width; + surf_hei = height; + drawbuf.resize(3 * surf_wid * surf_hei); + surface = SDL_CreateRGBSurfaceFrom( + drawbuf.data(), surf_wid, surf_hei, 24, 3 * surf_wid, + 255, 255 << 8, 255 << 16, 0 + ); + } + + drawfunc(drawbuf, width, height); + } +} |