From b770475741b7c33d57331f3139c55a3f237ad274 Mon Sep 17 00:00:00 2001
From: Loek Le Blansch <loek@pipeframe.xyz>
Date: Tue, 5 Nov 2024 16:03:48 +0100
Subject: create facade folder

---
 src/crepe/CMakeLists.txt          |  11 +--
 src/crepe/SDLApp.cpp              |  71 -----------------
 src/crepe/SDLApp.h                |  26 -------
 src/crepe/SDLContext.cpp          | 157 --------------------------------------
 src/crepe/SDLContext.h            |  49 ------------
 src/crepe/Sound.cpp               |  60 ---------------
 src/crepe/Sound.h                 |  81 --------------------
 src/crepe/SoundContext.cpp        |  20 -----
 src/crepe/SoundContext.h          |  26 -------
 src/crepe/api/AudioSource.cpp     |   2 +-
 src/crepe/api/Texture.cpp         |   2 +-
 src/crepe/facade/CMakeLists.txt   |  14 ++++
 src/crepe/facade/SDLApp.cpp       |  71 +++++++++++++++++
 src/crepe/facade/SDLApp.h         |  26 +++++++
 src/crepe/facade/SDLContext.cpp   | 157 ++++++++++++++++++++++++++++++++++++++
 src/crepe/facade/SDLContext.h     |  48 ++++++++++++
 src/crepe/facade/Sound.cpp        |  60 +++++++++++++++
 src/crepe/facade/Sound.h          |  81 ++++++++++++++++++++
 src/crepe/facade/SoundContext.cpp |  20 +++++
 src/crepe/facade/SoundContext.h   |  26 +++++++
 src/crepe/system/RenderSystem.cpp |   2 +-
 21 files changed, 508 insertions(+), 502 deletions(-)
 delete mode 100644 src/crepe/SDLApp.cpp
 delete mode 100644 src/crepe/SDLApp.h
 delete mode 100644 src/crepe/SDLContext.cpp
 delete mode 100644 src/crepe/SDLContext.h
 delete mode 100644 src/crepe/Sound.cpp
 delete mode 100644 src/crepe/Sound.h
 delete mode 100644 src/crepe/SoundContext.cpp
 delete mode 100644 src/crepe/SoundContext.h
 create mode 100644 src/crepe/facade/CMakeLists.txt
 create mode 100644 src/crepe/facade/SDLApp.cpp
 create mode 100644 src/crepe/facade/SDLApp.h
 create mode 100644 src/crepe/facade/SDLContext.cpp
 create mode 100644 src/crepe/facade/SDLContext.h
 create mode 100644 src/crepe/facade/Sound.cpp
 create mode 100644 src/crepe/facade/Sound.h
 create mode 100644 src/crepe/facade/SoundContext.cpp
 create mode 100644 src/crepe/facade/SoundContext.h

(limited to 'src/crepe')

diff --git a/src/crepe/CMakeLists.txt b/src/crepe/CMakeLists.txt
index 7f976db..8830e05 100644
--- a/src/crepe/CMakeLists.txt
+++ b/src/crepe/CMakeLists.txt
@@ -1,28 +1,21 @@
 target_sources(crepe PUBLIC
 	Asset.cpp
-	Sound.cpp
-	SoundContext.cpp
 	Particle.cpp
-	SDLApp.cpp
 	ComponentManager.cpp
 	Component.cpp
 	Collider.cpp
-	SDLContext.cpp
 )
 
 target_sources(crepe PUBLIC FILE_SET HEADERS FILES
 	Asset.h
-	Sound.h
-	SoundContext.h
-	SDLContext.h
 	ComponentManager.h
 	ComponentManager.hpp
 	Component.h
 	Collider.h
-	SDLContext.h
 )
 
 add_subdirectory(api)
-add_subdirectory(util)
+add_subdirectory(facade)
 add_subdirectory(system)
+add_subdirectory(util)
 
diff --git a/src/crepe/SDLApp.cpp b/src/crepe/SDLApp.cpp
deleted file mode 100644
index c6ddeaa..0000000
--- a/src/crepe/SDLApp.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#include <iostream>
-
-#include "SDLApp.h"
-
-SDLApp::SDLApp(int window_width, int window_height)
-	: window_width(window_width), window_height(window_height), window(nullptr),
-	  renderer(nullptr) {}
-
-// FIXME: why is there clean_up and ~SDLApp?
-SDLApp::~SDLApp() { clean_up(); }
-
-bool SDLApp::initialize() {
-	if (SDL_Init(SDL_INIT_VIDEO) != 0) {
-		// FIXME: throw exception
-		std::cerr << "SDL Initialization Error: " << SDL_GetError()
-				  << std::endl;
-		return false;
-	}
-
-	window = SDL_CreateWindow("Particle System", SDL_WINDOWPOS_CENTERED,
-							  SDL_WINDOWPOS_CENTERED, window_width,
-							  window_height, SDL_WINDOW_SHOWN);
-	if (!window) {
-		// FIXME: throw exception
-		std::cerr << "Window Creation Error: " << SDL_GetError() << std::endl;
-		return false;
-	}
-
-	renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
-	if (!renderer) {
-		// FIXME: throw exception
-		std::cerr << "Renderer Creation Error: " << SDL_GetError() << std::endl;
-		return false;
-	}
-
-	return true;
-}
-
-void SDLApp::handle_events(bool & running) {
-	SDL_Event event;
-	while (SDL_PollEvent(&event)) {
-		if (event.type == SDL_QUIT) {
-			running = false;
-		}
-	}
-}
-
-void SDLApp::clear_screen() {
-	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
-	SDL_RenderClear(renderer);
-}
-
-void SDLApp::present_screen() { SDL_RenderPresent(renderer); }
-
-void SDLApp::draw_square(int x, int y, int size) {
-	SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
-	SDL_Rect rect = {x, y, size, size};
-	SDL_RenderFillRect(renderer, &rect);
-}
-
-SDL_Texture * square_texture = nullptr; // Load this with an image or create it
-
-void SDLApp::clean_up() {
-	if (renderer) {
-		SDL_DestroyRenderer(renderer);
-	}
-	if (window) {
-		SDL_DestroyWindow(window);
-	}
-	SDL_Quit();
-}
diff --git a/src/crepe/SDLApp.h b/src/crepe/SDLApp.h
deleted file mode 100644
index e67947b..0000000
--- a/src/crepe/SDLApp.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-
-#include <SDL2/SDL.h>
-
-#include "api/ParticleEmitter.h"
-
-class SDLApp {
-public:
-	SDLApp(int window_width, int window_height);
-	~SDLApp();
-
-	bool initialize();
-	void handle_events(bool & running);
-	void clear_screen();
-	void present_screen();
-	void draw_square(int x, int y, int size);
-	void clean_up();
-	void draw_particles(const std::vector<crepe::ParticleEmitter> & emitters);
-	void draw_multiple_squares(const std::vector<SDL_Rect> & squares);
-
-private:
-	int window_width;
-	int window_height;
-	SDL_Window * window;
-	SDL_Renderer * renderer;
-};
diff --git a/src/crepe/SDLContext.cpp b/src/crepe/SDLContext.cpp
deleted file mode 100644
index e61faa3..0000000
--- a/src/crepe/SDLContext.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-#include <SDL2/SDL.h>
-#include <SDL2/SDL_image.h>
-#include <SDL2/SDL_render.h>
-#include <SDL2/SDL_surface.h>
-#include <SDL2/SDL_video.h>
-#include <cmath>
-#include <cstddef>
-#include <iostream>
-
-#include "api/Sprite.h"
-#include "api/Texture.h"
-#include "api/Transform.h"
-#include "util/log.h"
-
-#include "SDLContext.h"
-
-using namespace crepe;
-
-SDLContext & SDLContext::get_instance() {
-	static SDLContext instance;
-	return instance;
-}
-
-void SDLContext::handle_events(bool & running) {
-	SDL_Event event;
-	while (SDL_PollEvent(&event)) {
-		if (event.type == SDL_QUIT) {
-			running = false;
-		}
-	}
-}
-
-SDLContext::~SDLContext() {
-	dbg_trace();
-
-	if (this->game_renderer != nullptr)
-		SDL_DestroyRenderer(this->game_renderer);
-
-	if (this->game_window != nullptr) {
-		SDL_DestroyWindow(this->game_window);
-	}
-
-	// TODO: how are we going to ensure that these are called from the same
-	// thread that SDL_Init() was called on? This has caused problems for me
-	// before.
-	IMG_Quit();
-	SDL_Quit();
-}
-
-void SDLContext::clear_screen() { SDL_RenderClear(this->game_renderer); }
-
-SDLContext::SDLContext() {
-	dbg_trace();
-	// FIXME: read window defaults from config manager
-
-	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
-		// FIXME: throw exception
-		std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError()
-				  << std::endl;
-		return;
-	}
-
-	this->game_window = SDL_CreateWindow(
-		"Crepe Game Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
-		1920, 1080, SDL_WINDOW_SHOWN);
-	if (!this->game_window) {
-		// FIXME: throw exception
-		std::cerr << "Window could not be created! SDL_Error: "
-				  << SDL_GetError() << std::endl;
-	}
-
-	this->game_renderer
-		= SDL_CreateRenderer(this->game_window, -1, SDL_RENDERER_ACCELERATED);
-	if (!this->game_renderer) {
-		// FIXME: throw exception
-		std::cerr << "Renderer could not be created! SDL_Error: "
-				  << SDL_GetError() << std::endl;
-		SDL_DestroyWindow(this->game_window);
-		return;
-	}
-
-	int img_flags = IMG_INIT_PNG;
-	if (!(IMG_Init(img_flags) & img_flags)) {
-		// FIXME: throw exception
-		std::cout << "SDL_image could not initialize! SDL_image Error: "
-				  << IMG_GetError() << std::endl;
-	}
-}
-
-void SDLContext::present_screen() { SDL_RenderPresent(this->game_renderer); }
-
-void SDLContext::draw(const Sprite & sprite, const Transform & transform) {
-
-	static SDL_RendererFlip render_flip
-		= (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x)
-							  | (SDL_FLIP_VERTICAL * sprite.flip.flip_y));
-
-	int w, h;
-	SDL_QueryTexture(sprite.sprite_image->texture, NULL, NULL, &w, &h);
-	// needs maybe camera for position
-	SDL_Rect dstrect = {
-		.x = static_cast<int>(transform.position.x),
-		.y = static_cast<int>(transform.position.y),
-		.w = static_cast<int>(w * transform.scale),
-		.h = static_cast<int>(h * transform.scale),
-	};
-
-	double degrees = transform.rotation * 180 / M_PI;
-	SDL_RenderCopyEx(this->game_renderer, sprite.sprite_image->texture, NULL,
-					 &dstrect, degrees, NULL, render_flip);
-}
-
-/*
-SDL_Texture * SDLContext::setTextureFromPath(const char * path, SDL_Rect & clip,
-											 const int row, const int col) {
-	dbg_trace();
-
-	SDL_Surface * tmp = IMG_Load(path);
-	if (!tmp) {
-		std::cerr << "Error surface " << IMG_GetError << std::endl;
-	}
-
-	clip.
-		w = tmp->w / col;
-	clip.h = tmp->h / row;
-
-	SDL_Texture * CreatedTexture
-		= SDL_CreateTextureFromSurface(this->game_renderer, tmp);
-
-	if (!CreatedTexture) {
-		std::cerr << "Error could not create texture " << IMG_GetError
-				  << std::endl;
-	}
-	SDL_FreeSurface(tmp);
-
-	return CreatedTexture;
-}
-*/
-
-SDL_Texture * SDLContext::texture_from_path(const char * path) {
-	dbg_trace();
-
-	SDL_Surface * tmp = IMG_Load(path);
-	if (!tmp) {
-		std::cerr << "Error surface " << IMG_GetError << std::endl;
-	}
-	SDL_Texture * created_texture
-		= SDL_CreateTextureFromSurface(this->game_renderer, tmp);
-
-	if (!created_texture) {
-		std::cerr << "Error could not create texture " << IMG_GetError
-				  << std::endl;
-	}
-	SDL_FreeSurface(tmp);
-
-	return created_texture;
-}
diff --git a/src/crepe/SDLContext.h b/src/crepe/SDLContext.h
deleted file mode 100644
index 94fc549..0000000
--- a/src/crepe/SDLContext.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#pragma once
-
-#include <SDL2/SDL_render.h>
-#include <SDL2/SDL_video.h>
-
-#include "api/Sprite.h"
-#include "api/Transform.h"
-
-#include "system/RenderSystem.h"
-
-namespace crepe {
-
-class Texture;
-class SDLContext {
-
-public:
-	// singleton
-	static SDLContext & get_instance();
-	SDLContext(const SDLContext &) = delete;
-	SDLContext(SDLContext &&) = delete;
-	SDLContext & operator=(const SDLContext &) = delete;
-	SDLContext & operator=(SDLContext &&) = delete;
-
-	//TODO decide events wouter?
-
-private:
-	void handle_events(bool & running);
-
-private:
-	SDLContext();
-	virtual ~SDLContext();
-
-private:
-	friend class Texture;
-	SDL_Texture * texture_from_path(const char *);
-	//SDL_Texture* setTextureFromPath(const char*, SDL_Rect& clip, const int row, const int col);
-
-private:
-	friend class RenderSystem;
-	void draw(const Sprite &, const Transform &);
-	void clear_screen();
-	void present_screen();
-
-private:
-	SDL_Window * game_window = nullptr;
-	SDL_Renderer * game_renderer = nullptr;
-};
-
-} // namespace crepe
diff --git a/src/crepe/Sound.cpp b/src/crepe/Sound.cpp
deleted file mode 100644
index 64fa281..0000000
--- a/src/crepe/Sound.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-#include "util/log.h"
-
-#include "Sound.h"
-#include "SoundContext.h"
-
-using namespace crepe;
-
-Sound::Sound(std::unique_ptr<Asset> res) {
-	dbg_trace();
-	this->load(std::move(res));
-}
-
-Sound::Sound(const char * src) {
-	dbg_trace();
-	this->load(std::make_unique<Asset>(src));
-}
-
-void Sound::load(std::unique_ptr<Asset> res) {
-	this->sample.load(res->canonical());
-}
-
-void Sound::play() {
-	SoundContext & ctx = SoundContext::get_instance();
-	if (ctx.engine.getPause(this->handle)) {
-		// resume if paused
-		ctx.engine.setPause(this->handle, false);
-	} else {
-		// or start new sound
-		this->handle = ctx.engine.play(this->sample, this->volume);
-		ctx.engine.setLooping(this->handle, this->looping);
-	}
-}
-
-void Sound::pause() {
-	SoundContext & ctx = SoundContext::get_instance();
-	if (ctx.engine.getPause(this->handle)) return;
-	ctx.engine.setPause(this->handle, true);
-}
-
-void Sound::rewind() {
-	SoundContext & ctx = SoundContext::get_instance();
-	if (!ctx.engine.isValidVoiceHandle(this->handle)) return;
-	ctx.engine.seek(this->handle, 0);
-}
-
-void Sound::set_volume(float volume) {
-	this->volume = volume;
-
-	SoundContext & ctx = SoundContext::get_instance();
-	if (!ctx.engine.isValidVoiceHandle(this->handle)) return;
-	ctx.engine.setVolume(this->handle, this->volume);
-}
-
-void Sound::set_looping(bool looping) {
-	this->looping = looping;
-
-	SoundContext & ctx = SoundContext::get_instance();
-	if (!ctx.engine.isValidVoiceHandle(this->handle)) return;
-	ctx.engine.setLooping(this->handle, this->looping);
-}
diff --git a/src/crepe/Sound.h b/src/crepe/Sound.h
deleted file mode 100644
index 917b57e..0000000
--- a/src/crepe/Sound.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#pragma once
-
-#include <memory>
-#include <soloud/soloud.h>
-#include <soloud/soloud_wav.h>
-
-#include "Asset.h"
-
-namespace crepe {
-
-class Sound {
-public:
-	/**
-	 * \brief Pause this sample
-	 *
-	 * Pauses this sound if it is playing, or does nothing if it is already
-	 * paused. The playhead position is saved, such that calling \c play() after
-	 * this function makes the sound resume.
-	 */
-	void pause();
-	/**
-	 * \brief Play this sample
-	 *
-	 * Resume playback if this sound is paused, or start from the beginning of
-	 * the sample.
-	 *
-	 * \note This class only saves a reference to the most recent 'voice' of this
-	 * sound. Calling \c play() while the sound is already playing causes
-	 * multiple instances of the sample to play simultaniously. The sample
-	 * started last is the one that is controlled afterwards.
-	 */
-	void play();
-	/**
-	 * \brief Reset playhead position
-	 * 
-	 * Resets the playhead position so that calling \c play() after this function
-	 * makes it play from the start of the sample. If the sound is not paused
-	 * before calling this function, this function will stop playback.
-	 */
-	void rewind();
-	/**
-	 * \brief Set playback volume / gain
-	 *
-	 * \param volume  Volume (0 = muted, 1 = full volume)
-	 */
-	void set_volume(float volume);
-	/**
-	 * \brief Get playback volume / gain
-	 *
-	 * \return Volume
-	 */
-	float get_volume() const { return this->volume; }
-	/**
-	 * \brief Set looping behavior for this sample
-	 *
-	 * \param looping  Looping behavior (false = one-shot, true = loop)
-	 */
-	void set_looping(bool looping);
-	/**
-	 * \brief Get looping behavior
-	 *
-	 * \return true if looping, false if one-shot
-	 */
-	bool get_looping() const { return this->looping; }
-
-public:
-	Sound(const char * src);
-	Sound(std::unique_ptr<Asset> res);
-
-private:
-	void load(std::unique_ptr<Asset> res);
-
-private:
-	SoLoud::Wav sample;
-	SoLoud::handle handle;
-
-	float volume = 1.0f;
-	bool looping = false;
-};
-
-} // namespace crepe
diff --git a/src/crepe/SoundContext.cpp b/src/crepe/SoundContext.cpp
deleted file mode 100644
index 72047d2..0000000
--- a/src/crepe/SoundContext.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "util/log.h"
-
-#include "SoundContext.h"
-
-using namespace crepe;
-
-SoundContext & SoundContext::get_instance() {
-	static SoundContext instance;
-	return instance;
-}
-
-SoundContext::SoundContext() {
-	dbg_trace();
-	engine.init();
-}
-
-SoundContext::~SoundContext() {
-	dbg_trace();
-	engine.deinit();
-}
diff --git a/src/crepe/SoundContext.h b/src/crepe/SoundContext.h
deleted file mode 100644
index d3123d2..0000000
--- a/src/crepe/SoundContext.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-
-#include <soloud/soloud.h>
-
-#include "Sound.h"
-
-namespace crepe {
-
-class SoundContext {
-private:
-	SoundContext();
-	virtual ~SoundContext();
-
-	// singleton
-	static SoundContext & get_instance();
-	SoundContext(const SoundContext &) = delete;
-	SoundContext(SoundContext &&) = delete;
-	SoundContext & operator=(const SoundContext &) = delete;
-	SoundContext & operator=(SoundContext &&) = delete;
-
-private:
-	SoLoud::Soloud engine;
-	friend class Sound;
-};
-
-} // namespace crepe
diff --git a/src/crepe/api/AudioSource.cpp b/src/crepe/api/AudioSource.cpp
index 2bacc75..63fd0d7 100644
--- a/src/crepe/api/AudioSource.cpp
+++ b/src/crepe/api/AudioSource.cpp
@@ -1,6 +1,6 @@
 #include <memory>
 
-#include "../Sound.h"
+#include "../facade/Sound.h"
 
 #include "AudioSource.h"
 
diff --git a/src/crepe/api/Texture.cpp b/src/crepe/api/Texture.cpp
index b5001a6..8fc5c13 100644
--- a/src/crepe/api/Texture.cpp
+++ b/src/crepe/api/Texture.cpp
@@ -1,6 +1,6 @@
 #include <SDL2/SDL_render.h>
 
-#include "../SDLContext.h"
+#include "../facade/SDLContext.h"
 #include "../util/log.h"
 
 #include "Asset.h"
diff --git a/src/crepe/facade/CMakeLists.txt b/src/crepe/facade/CMakeLists.txt
new file mode 100644
index 0000000..dbddcc6
--- /dev/null
+++ b/src/crepe/facade/CMakeLists.txt
@@ -0,0 +1,14 @@
+target_sources(crepe PUBLIC
+	Sound.cpp
+	SoundContext.cpp
+	SDLApp.cpp
+	SDLContext.cpp
+)
+
+target_sources(crepe PUBLIC FILE_SET HEADERS FILES
+	Sound.h
+	SoundContext.h
+	SDLContext.h
+	SDLContext.h
+)
+
diff --git a/src/crepe/facade/SDLApp.cpp b/src/crepe/facade/SDLApp.cpp
new file mode 100644
index 0000000..c6ddeaa
--- /dev/null
+++ b/src/crepe/facade/SDLApp.cpp
@@ -0,0 +1,71 @@
+#include <iostream>
+
+#include "SDLApp.h"
+
+SDLApp::SDLApp(int window_width, int window_height)
+	: window_width(window_width), window_height(window_height), window(nullptr),
+	  renderer(nullptr) {}
+
+// FIXME: why is there clean_up and ~SDLApp?
+SDLApp::~SDLApp() { clean_up(); }
+
+bool SDLApp::initialize() {
+	if (SDL_Init(SDL_INIT_VIDEO) != 0) {
+		// FIXME: throw exception
+		std::cerr << "SDL Initialization Error: " << SDL_GetError()
+				  << std::endl;
+		return false;
+	}
+
+	window = SDL_CreateWindow("Particle System", SDL_WINDOWPOS_CENTERED,
+							  SDL_WINDOWPOS_CENTERED, window_width,
+							  window_height, SDL_WINDOW_SHOWN);
+	if (!window) {
+		// FIXME: throw exception
+		std::cerr << "Window Creation Error: " << SDL_GetError() << std::endl;
+		return false;
+	}
+
+	renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
+	if (!renderer) {
+		// FIXME: throw exception
+		std::cerr << "Renderer Creation Error: " << SDL_GetError() << std::endl;
+		return false;
+	}
+
+	return true;
+}
+
+void SDLApp::handle_events(bool & running) {
+	SDL_Event event;
+	while (SDL_PollEvent(&event)) {
+		if (event.type == SDL_QUIT) {
+			running = false;
+		}
+	}
+}
+
+void SDLApp::clear_screen() {
+	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+	SDL_RenderClear(renderer);
+}
+
+void SDLApp::present_screen() { SDL_RenderPresent(renderer); }
+
+void SDLApp::draw_square(int x, int y, int size) {
+	SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
+	SDL_Rect rect = {x, y, size, size};
+	SDL_RenderFillRect(renderer, &rect);
+}
+
+SDL_Texture * square_texture = nullptr; // Load this with an image or create it
+
+void SDLApp::clean_up() {
+	if (renderer) {
+		SDL_DestroyRenderer(renderer);
+	}
+	if (window) {
+		SDL_DestroyWindow(window);
+	}
+	SDL_Quit();
+}
diff --git a/src/crepe/facade/SDLApp.h b/src/crepe/facade/SDLApp.h
new file mode 100644
index 0000000..6d8f3f4
--- /dev/null
+++ b/src/crepe/facade/SDLApp.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <SDL2/SDL.h>
+
+#include "../api/ParticleEmitter.h"
+
+class SDLApp {
+public:
+	SDLApp(int window_width, int window_height);
+	~SDLApp();
+
+	bool initialize();
+	void handle_events(bool & running);
+	void clear_screen();
+	void present_screen();
+	void draw_square(int x, int y, int size);
+	void clean_up();
+	void draw_particles(const std::vector<crepe::ParticleEmitter> & emitters);
+	void draw_multiple_squares(const std::vector<SDL_Rect> & squares);
+
+private:
+	int window_width;
+	int window_height;
+	SDL_Window * window;
+	SDL_Renderer * renderer;
+};
diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp
new file mode 100644
index 0000000..8da93e9
--- /dev/null
+++ b/src/crepe/facade/SDLContext.cpp
@@ -0,0 +1,157 @@
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
+#include <SDL2/SDL_render.h>
+#include <SDL2/SDL_surface.h>
+#include <SDL2/SDL_video.h>
+#include <cmath>
+#include <cstddef>
+#include <iostream>
+
+#include "../api/Sprite.h"
+#include "../api/Texture.h"
+#include "../api/Transform.h"
+#include "../util/log.h"
+
+#include "SDLContext.h"
+
+using namespace crepe;
+
+SDLContext & SDLContext::get_instance() {
+	static SDLContext instance;
+	return instance;
+}
+
+void SDLContext::handle_events(bool & running) {
+	SDL_Event event;
+	while (SDL_PollEvent(&event)) {
+		if (event.type == SDL_QUIT) {
+			running = false;
+		}
+	}
+}
+
+SDLContext::~SDLContext() {
+	dbg_trace();
+
+	if (this->game_renderer != nullptr)
+		SDL_DestroyRenderer(this->game_renderer);
+
+	if (this->game_window != nullptr) {
+		SDL_DestroyWindow(this->game_window);
+	}
+
+	// TODO: how are we going to ensure that these are called from the same
+	// thread that SDL_Init() was called on? This has caused problems for me
+	// before.
+	IMG_Quit();
+	SDL_Quit();
+}
+
+void SDLContext::clear_screen() { SDL_RenderClear(this->game_renderer); }
+
+SDLContext::SDLContext() {
+	dbg_trace();
+	// FIXME: read window defaults from config manager
+
+	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+		// FIXME: throw exception
+		std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError()
+				  << std::endl;
+		return;
+	}
+
+	this->game_window = SDL_CreateWindow(
+		"Crepe Game Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+		1920, 1080, SDL_WINDOW_SHOWN);
+	if (!this->game_window) {
+		// FIXME: throw exception
+		std::cerr << "Window could not be created! SDL_Error: "
+				  << SDL_GetError() << std::endl;
+	}
+
+	this->game_renderer
+		= SDL_CreateRenderer(this->game_window, -1, SDL_RENDERER_ACCELERATED);
+	if (!this->game_renderer) {
+		// FIXME: throw exception
+		std::cerr << "Renderer could not be created! SDL_Error: "
+				  << SDL_GetError() << std::endl;
+		SDL_DestroyWindow(this->game_window);
+		return;
+	}
+
+	int img_flags = IMG_INIT_PNG;
+	if (!(IMG_Init(img_flags) & img_flags)) {
+		// FIXME: throw exception
+		std::cout << "SDL_image could not initialize! SDL_image Error: "
+				  << IMG_GetError() << std::endl;
+	}
+}
+
+void SDLContext::present_screen() { SDL_RenderPresent(this->game_renderer); }
+
+void SDLContext::draw(const Sprite & sprite, const Transform & transform) {
+
+	static SDL_RendererFlip render_flip
+		= (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x)
+							  | (SDL_FLIP_VERTICAL * sprite.flip.flip_y));
+
+	int w, h;
+	SDL_QueryTexture(sprite.sprite_image->texture, NULL, NULL, &w, &h);
+	// needs maybe camera for position
+	SDL_Rect dstrect = {
+		.x = static_cast<int>(transform.position.x),
+		.y = static_cast<int>(transform.position.y),
+		.w = static_cast<int>(w * transform.scale),
+		.h = static_cast<int>(h * transform.scale),
+	};
+
+	double degrees = transform.rotation * 180 / M_PI;
+	SDL_RenderCopyEx(this->game_renderer, sprite.sprite_image->texture, NULL,
+					 &dstrect, degrees, NULL, render_flip);
+}
+
+/*
+SDL_Texture * SDLContext::setTextureFromPath(const char * path, SDL_Rect & clip,
+											 const int row, const int col) {
+	dbg_trace();
+
+	SDL_Surface * tmp = IMG_Load(path);
+	if (!tmp) {
+		std::cerr << "Error surface " << IMG_GetError << std::endl;
+	}
+
+	clip.
+		w = tmp->w / col;
+	clip.h = tmp->h / row;
+
+	SDL_Texture * CreatedTexture
+		= SDL_CreateTextureFromSurface(this->game_renderer, tmp);
+
+	if (!CreatedTexture) {
+		std::cerr << "Error could not create texture " << IMG_GetError
+				  << std::endl;
+	}
+	SDL_FreeSurface(tmp);
+
+	return CreatedTexture;
+}
+*/
+
+SDL_Texture * SDLContext::texture_from_path(const char * path) {
+	dbg_trace();
+
+	SDL_Surface * tmp = IMG_Load(path);
+	if (!tmp) {
+		std::cerr << "Error surface " << IMG_GetError << std::endl;
+	}
+	SDL_Texture * created_texture
+		= SDL_CreateTextureFromSurface(this->game_renderer, tmp);
+
+	if (!created_texture) {
+		std::cerr << "Error could not create texture " << IMG_GetError
+				  << std::endl;
+	}
+	SDL_FreeSurface(tmp);
+
+	return created_texture;
+}
diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h
new file mode 100644
index 0000000..f1ba8a6
--- /dev/null
+++ b/src/crepe/facade/SDLContext.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <SDL2/SDL_render.h>
+#include <SDL2/SDL_video.h>
+
+#include "../api/Sprite.h"
+#include "../api/Transform.h"
+#include "../system/RenderSystem.h"
+
+namespace crepe {
+
+class Texture;
+class SDLContext {
+
+public:
+	// singleton
+	static SDLContext & get_instance();
+	SDLContext(const SDLContext &) = delete;
+	SDLContext(SDLContext &&) = delete;
+	SDLContext & operator=(const SDLContext &) = delete;
+	SDLContext & operator=(SDLContext &&) = delete;
+
+	//TODO decide events wouter?
+
+private:
+	void handle_events(bool & running);
+
+private:
+	SDLContext();
+	virtual ~SDLContext();
+
+private:
+	friend class Texture;
+	SDL_Texture * texture_from_path(const char *);
+	//SDL_Texture* setTextureFromPath(const char*, SDL_Rect& clip, const int row, const int col);
+
+private:
+	friend class RenderSystem;
+	void draw(const Sprite &, const Transform &);
+	void clear_screen();
+	void present_screen();
+
+private:
+	SDL_Window * game_window = nullptr;
+	SDL_Renderer * game_renderer = nullptr;
+};
+
+} // namespace crepe
diff --git a/src/crepe/facade/Sound.cpp b/src/crepe/facade/Sound.cpp
new file mode 100644
index 0000000..648ec81
--- /dev/null
+++ b/src/crepe/facade/Sound.cpp
@@ -0,0 +1,60 @@
+#include "../util/log.h"
+
+#include "Sound.h"
+#include "SoundContext.h"
+
+using namespace crepe;
+
+Sound::Sound(std::unique_ptr<Asset> res) {
+	dbg_trace();
+	this->load(std::move(res));
+}
+
+Sound::Sound(const char * src) {
+	dbg_trace();
+	this->load(std::make_unique<Asset>(src));
+}
+
+void Sound::load(std::unique_ptr<Asset> res) {
+	this->sample.load(res->canonical());
+}
+
+void Sound::play() {
+	SoundContext & ctx = SoundContext::get_instance();
+	if (ctx.engine.getPause(this->handle)) {
+		// resume if paused
+		ctx.engine.setPause(this->handle, false);
+	} else {
+		// or start new sound
+		this->handle = ctx.engine.play(this->sample, this->volume);
+		ctx.engine.setLooping(this->handle, this->looping);
+	}
+}
+
+void Sound::pause() {
+	SoundContext & ctx = SoundContext::get_instance();
+	if (ctx.engine.getPause(this->handle)) return;
+	ctx.engine.setPause(this->handle, true);
+}
+
+void Sound::rewind() {
+	SoundContext & ctx = SoundContext::get_instance();
+	if (!ctx.engine.isValidVoiceHandle(this->handle)) return;
+	ctx.engine.seek(this->handle, 0);
+}
+
+void Sound::set_volume(float volume) {
+	this->volume = volume;
+
+	SoundContext & ctx = SoundContext::get_instance();
+	if (!ctx.engine.isValidVoiceHandle(this->handle)) return;
+	ctx.engine.setVolume(this->handle, this->volume);
+}
+
+void Sound::set_looping(bool looping) {
+	this->looping = looping;
+
+	SoundContext & ctx = SoundContext::get_instance();
+	if (!ctx.engine.isValidVoiceHandle(this->handle)) return;
+	ctx.engine.setLooping(this->handle, this->looping);
+}
diff --git a/src/crepe/facade/Sound.h b/src/crepe/facade/Sound.h
new file mode 100644
index 0000000..183bd7c
--- /dev/null
+++ b/src/crepe/facade/Sound.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include <memory>
+#include <soloud/soloud.h>
+#include <soloud/soloud_wav.h>
+
+#include "../Asset.h"
+
+namespace crepe {
+
+class Sound {
+public:
+	/**
+	 * \brief Pause this sample
+	 *
+	 * Pauses this sound if it is playing, or does nothing if it is already
+	 * paused. The playhead position is saved, such that calling \c play() after
+	 * this function makes the sound resume.
+	 */
+	void pause();
+	/**
+	 * \brief Play this sample
+	 *
+	 * Resume playback if this sound is paused, or start from the beginning of
+	 * the sample.
+	 *
+	 * \note This class only saves a reference to the most recent 'voice' of this
+	 * sound. Calling \c play() while the sound is already playing causes
+	 * multiple instances of the sample to play simultaniously. The sample
+	 * started last is the one that is controlled afterwards.
+	 */
+	void play();
+	/**
+	 * \brief Reset playhead position
+	 * 
+	 * Resets the playhead position so that calling \c play() after this function
+	 * makes it play from the start of the sample. If the sound is not paused
+	 * before calling this function, this function will stop playback.
+	 */
+	void rewind();
+	/**
+	 * \brief Set playback volume / gain
+	 *
+	 * \param volume  Volume (0 = muted, 1 = full volume)
+	 */
+	void set_volume(float volume);
+	/**
+	 * \brief Get playback volume / gain
+	 *
+	 * \return Volume
+	 */
+	float get_volume() const { return this->volume; }
+	/**
+	 * \brief Set looping behavior for this sample
+	 *
+	 * \param looping  Looping behavior (false = one-shot, true = loop)
+	 */
+	void set_looping(bool looping);
+	/**
+	 * \brief Get looping behavior
+	 *
+	 * \return true if looping, false if one-shot
+	 */
+	bool get_looping() const { return this->looping; }
+
+public:
+	Sound(const char * src);
+	Sound(std::unique_ptr<Asset> res);
+
+private:
+	void load(std::unique_ptr<Asset> res);
+
+private:
+	SoLoud::Wav sample;
+	SoLoud::handle handle;
+
+	float volume = 1.0f;
+	bool looping = false;
+};
+
+} // namespace crepe
diff --git a/src/crepe/facade/SoundContext.cpp b/src/crepe/facade/SoundContext.cpp
new file mode 100644
index 0000000..5e5a3a9
--- /dev/null
+++ b/src/crepe/facade/SoundContext.cpp
@@ -0,0 +1,20 @@
+#include "../util/log.h"
+
+#include "SoundContext.h"
+
+using namespace crepe;
+
+SoundContext & SoundContext::get_instance() {
+	static SoundContext instance;
+	return instance;
+}
+
+SoundContext::SoundContext() {
+	dbg_trace();
+	engine.init();
+}
+
+SoundContext::~SoundContext() {
+	dbg_trace();
+	engine.deinit();
+}
diff --git a/src/crepe/facade/SoundContext.h b/src/crepe/facade/SoundContext.h
new file mode 100644
index 0000000..d3123d2
--- /dev/null
+++ b/src/crepe/facade/SoundContext.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <soloud/soloud.h>
+
+#include "Sound.h"
+
+namespace crepe {
+
+class SoundContext {
+private:
+	SoundContext();
+	virtual ~SoundContext();
+
+	// singleton
+	static SoundContext & get_instance();
+	SoundContext(const SoundContext &) = delete;
+	SoundContext(SoundContext &&) = delete;
+	SoundContext & operator=(const SoundContext &) = delete;
+	SoundContext & operator=(SoundContext &&) = delete;
+
+private:
+	SoLoud::Soloud engine;
+	friend class Sound;
+};
+
+} // namespace crepe
diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp
index ee3cdf2..96c94e9 100644
--- a/src/crepe/system/RenderSystem.cpp
+++ b/src/crepe/system/RenderSystem.cpp
@@ -2,7 +2,7 @@
 #include <vector>
 
 #include "../ComponentManager.h"
-#include "../SDLContext.h"
+#include "../facade/SDLContext.h"
 #include "../api/Sprite.h"
 #include "../api/Transform.h"
 #include "../util/log.h"
-- 
cgit v1.2.3