commit 4bf9b6cf9de33daec1944f9f2e58a214865553b4
Author: frank <420@shampoo.ooo>
Date: Thu Jun 16 15:24:14 2022 -0400
initial commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6460a2d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+index.*
+local/
+*.o
+BPmono.ttf
+pepy
+compile_commands.json
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..ad2d0b1
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "lib/sb"]
+ path = lib/sb
+ url = makar:/var/www/git/sb
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4a8e1c3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,192 @@
+# Pepy by @ohsqueezy [ohsqueezy.itch.io]
+
+#######################
+# Location parameters #
+#######################
+
+# Location of project specific source files
+SRC_DIR := src/
+
+# Locations of [SPACE BOX] source and dependencies required to be compiled from source. These
+# locations are configured to match the structure of the [SPACE BOX] repository but can be
+# modified as necessary.
+SB_DIR := lib/sb/
+SB_SRC_DIR := $(SB_DIR)src/
+SB_LIB_DIR := $(SB_DIR)lib/
+SDLGFX2_DIR := $(SB_LIB_DIR)sdl2-gfx/
+GLEW_DIR := $(SB_LIB_DIR)glew/
+
+# C and C++ compiler commands
+CC := clang
+CPPC := clang++
+
+# Location of SDL config program
+SDLCONFIG := $(HOME)/local/sdl/bin/sdl2-config
+
+# Edit to point to the location of BPmono.ttf
+CREATE_FONT_SYMLINK := ln -nsf $(SB_DIR)"BPmono.ttf" .
+
+#############################
+# Based on above parameters #
+#############################
+
+SDL_CFLAGS = $(shell $(SDLCONFIG) --cflags)
+SDL_LFLAGS := $(shell $(SDLCONFIG) --libs)
+SB_H_FILES := $(wildcard $(addprefix $(SB_SRC_DIR),*.hpp))
+SB_O_FILES := $(filter-out $(addprefix $(SB_SRC_DIR),filesystem.o),$(SB_H_FILES:.hpp=.o))
+SRC_H_FILES := $(wildcard $(addprefix $(SRC_DIR),*.hpp))
+SRC_O_FILES := $(SRC_H_FILES:.hpp=.o)
+
+#####################################################################
+# Targets for building [SPACE BOX], dependencies and project source #
+#####################################################################
+
+$(SDLGFX2_DIR)%.o: $(SDLGFX2_DIR)%.c $(SDLGFX2_DIR)%.h
+$(GLEW_DIR)%.o: $(GLEW_DIR)%.c $(GLEW_DIR)%.h
+ $(CC) $(CFLAGS) $< -c -o $@
+
+$(SB_SRC_DIR)extension.o : $(addprefix $(SB_SRC_DIR),Box.hpp Segment.hpp Color.hpp filesystem.hpp Pixels.hpp Log.hpp)
+$(SB_SRC_DIR)Node.o : $(addprefix $(SB_SRC_DIR),Game.hpp Configuration.hpp Delegate.hpp Display.hpp Input.hpp Box.hpp Audio.hpp Log.hpp)
+$(SB_SRC_DIR)Sprite.o : $(addprefix $(SB_SRC_DIR),Node.hpp Game.hpp Box.hpp Animation.hpp Color.hpp extension.hpp Pixels.hpp Log.hpp)
+$(SB_SRC_DIR)Game.o : $(addprefix $(SB_SRC_DIR),extension.hpp Node.hpp Sprite.hpp Recorder.hpp Input.hpp Configuration.hpp \
+ Delegate.hpp Audio.hpp Log.hpp)
+$(SB_SRC_DIR)Animation.o : $(addprefix $(SB_SRC_DIR),Node.hpp Timer.hpp)
+$(SB_SRC_DIR)Recorder.o : $(addprefix $(SB_SRC_DIR),Node.hpp Game.hpp Configuration.hpp Delegate.hpp Animation.hpp extension.hpp)
+$(SB_SRC_DIR)Input.o : $(addprefix $(SB_SRC_DIR),Node.hpp Animation.hpp Configuration.hpp Delegate.hpp)
+$(SB_SRC_DIR)Configuration.o : $(addprefix $(SB_SRC_DIR),Node.hpp Animation.hpp Log.hpp)
+$(SB_SRC_DIR)Delegate.o : $(addprefix $(SB_SRC_DIR),Node.hpp Game.hpp Input.hpp)
+$(SB_SRC_DIR)Display.o : $(addprefix $(SB_SRC_DIR),Node.hpp Game.hpp Box.hpp Configuration.hpp Delegate.hpp Log.hpp)
+$(SB_SRC_DIR)Box.o : $(addprefix $(SB_SRC_DIR),extension.hpp Segment.hpp)
+$(SB_SRC_DIR)Segment.o : $(addprefix $(SB_SRC_DIR),extension.hpp Box.hpp)
+$(SB_SRC_DIR)Pixels.o : $(addprefix $(SB_SRC_DIR),Box.hpp extension.hpp Log.hpp utility.hpp)
+$(SB_SRC_DIR)Audio.o : $(addprefix $(SB_SRC_DIR),Node.hpp Display.hpp Configuration.hpp Box.hpp filesystem.hpp extension.hpp)
+$(SB_SRC_DIR)GLObject.o : $(addprefix $(SB_SRC_DIR),Log.hpp)
+$(SB_SRC_DIR)Texture.o : $(addprefix $(SB_SRC_DIR),GLObject.hpp filesystem.hpp Log.hpp)
+$(SB_SRC_DIR)VBO.o : $(addprefix $(SB_SRC_DIR),Log.hpp GLObject.hpp Attributes.hpp extension.hpp)
+$(SB_SRC_DIR)Attributes.o : $(addprefix $(SB_SRC_DIR),Log.hpp extension.hpp)
+$(SRC_DIR)Pepy.o : $(SRC_H_FILES) $(SB_H_FILES)
+%.o : %.cpp %.hpp
+ $(CPPC) $(CPP_FLAGS) $< -c -o $@
+
+###############
+# Linux build #
+###############
+
+linux : CC = clang
+linux : CPPC = clang++
+linux : CFLAGS = -g -Wall -Wextra -O0 -c -I$(SB_LIB_DIR) -I$(SB_SRC_DIR) $(SDL_CFLAGS)
+linux : CPP_FLAGS = $(CFLAGS) --std=c++17
+linux : LFLAGS = $(SDL_LFLAGS) -lpthread -lGL -lGLESv2 -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lstdc++fs
+linux : $(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) \
+ $(SB_O_FILES) $(SRC_O_FILES)
+ $(CREATE_FONT_SYMLINK)
+ $(CPPC) $(LFLAGS) -D__LINUX__ $^ -o pepy
+
+#############
+# Web build #
+#############
+
+# Use Emscripten to output JavaScript and an HTML index page for running in the browser
+
+EMSCRIPTENHOME = $(HOME)/ext/software/emsdk/upstream/emscripten
+EMSCRIPTEN_CFLAGS = -O3 -Wall -s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="['png']" -s USE_SDL_TTF=2 \
+ -s USE_SDL_MIXER=2 -s SDL2_MIXER_FORMATS="['ogg','mp3']" -s USE_OGG=1 -s USE_VORBIS=1 -s USE_MPG123=1 \
+ -s USE_MODPLUG=1 --no-heap-copy -I$(SB_LIB_DIR) -I$(SB_SRC_DIR)
+EMSCRIPTEN_LFLAGS = -s MIN_WEBGL_VERSION=2 -s EXPORTED_FUNCTIONS="['_main']" -s ALLOW_MEMORY_GROWTH=1 -s FULL_ES3=1 --shell-file shell.html
+EMSCRIPTEN_PRELOADS = --preload-file "BPmono.ttf"@/ --preload-file "config.json"@/ --preload-file "resource/"@/"resource/" \
+ --preload-file "src/shader.vert"@/"src/" --preload-file "src/shader.frag"@/"src/"
+
+emscripten : CC = $(EMSCRIPTENHOME)/emcc
+emscripten : CPPC = $(EMSCRIPTENHOME)/em++
+emscripten : CFLAGS = $(EMSCRIPTEN_CFLAGS)
+emscripten : CPP_FLAGS = $(CFLAGS) --std=c++17
+emscripten : $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) $(SB_O_FILES) $(SRC_O_FILES)
+ $(CREATE_FONT_SYMLINK)
+ $(CPPC) $(CPP_FLAGS) $(EMSCRIPTEN_LFLAGS) $(EMSCRIPTEN_PRELOADS) $^ -o "index.html"
+
+#########################
+# Clean up object files #
+#########################
+
+clean :
+ -rm $(SRC_DIR)*.o
+
+clean-all :
+ -find . -iname "*.o" -exec rm {} \;
+
+#############
+# compiledb #
+#############
+
+# Generate a clang JSON compilation database file. This can be useful for example for code completion. It requires a
+# compiledb binary (https://pypi.org/project/compiledb/). It should be generated manually every time a file is added,
+# renamed, or the compilation flags change. The generated database is based on the Linux build.
+
+PATH_TO_COMPILEDB = $(HOME)/.local/bin/compiledb
+compiledb :
+ -$(PATH_TO_COMPILEDB) -n make linux -k
+
+#####################
+# cross compilation #
+#####################
+
+# WARNING: untested
+
+# Below assignments and targets are necessary for cross-compiling to Android, web (via emscripten), Windows (via mingw),
+# and OS/X, but cross-compilation targets have not been tested in a while and won't compile without significant changes.
+
+BUILDDIR := build
+SDLHOME := $(EXT_SRC_ROOT)/SDL2-2.0.14
+SDL_IMG_HOME := $(EXT_SRC_ROOT)/SDL2_image-2.0.4
+SDL_TTF_HOME := $(EXT_SRC_ROOT)/SDL2_ttf-2.0.14
+GLEW_WIN32_HOME = $(EXT_SRC_ROOT)/glew-2.1.0-win32
+PROJECTHOME = $(shell pwd)
+WINBUILDDIR = win
+SDLMINGWHOME = $(SDLHOME)/i686-w64-mingw32
+SDL_IMG_MINGW_HOME = $(SDL_IMG_HOME)/i686-w64-mingw32
+SDL_TTF_MINGW_HOME = $(SDL_TTF_HOME)/i686-w64-mingw32
+APPDIR = Main.app/Contents
+SYSFWPATH = /Library/Frameworks
+
+android :
+ if [ ! -d $(BUILDDIR) ]; then mkdir $(BUILDDIR); fi;
+ cd $(SDLHOME)/build-scripts/ && \
+ ./androidbuild.sh $(ANDROIDPROJECT) $(PROJECTHOME)/main.cpp
+ cp -r $(SDLHOME)/build/$(ANDROIDPROJECT) $(BUILDDIR)
+ sed -i s/2\.3\.3/2\.2\.3/g $(BUILDDIR)/$(ANDROIDPROJECT)/build.gradle
+ sed -i s/26\.0\.1/23\.0\.1/g $(BUILDDIR)/$(ANDROIDPROJECT)/app/build.gradle
+ cd $(BUILDDIR)/$(ANDROIDPROJECT) && ./gradlew assembleDebug
+
+mingw :
+ if [ ! -d $(BUILDDIR)/$(WINBUILDDIR) ]; then mkdir -p $(BUILDDIR)/$(WINBUILDDIR); fi;
+ cd $(BUILDDIR)/$(WINBUILDDIR) && \
+ i686-w64-mingw32-g++ -std=c++17 $(PROJECTHOME)/main.cpp -I$(SDLMINGWHOME)/include/SDL2 \
+ -I$(SDL_IMG_MINGW_HOME)/include/SDL2 -I$(SDL_TTF_MINGW_HOME)/include/SDL2 $(INC) \
+ $(PROJECTHOME)/sdl2-gfx/SDL2_gfxPrimitives.c $(PROJECTHOME)/sdl2-gfx/SDL2_rotozoom.c $(PROJECTHOME)/glew/glew.c \
+ -L$(SDLMINGWHOME)/lib -L$(SDL_IMG_MINGW_HOME)/lib -L$(SDL_TTF_MINGW_HOME)/lib \
+ -lmingw32 -lSDL2_image \
+ -lSDL2_ttf -lstdc++fs \
+ -lSDL2main -lSDL2 -lopengl32 -Wall -O2 -o main.exe && \
+ cp $(SDLMINGWHOME)/bin/SDL2.dll $(SDL_IMG_MINGW_HOME)/bin/SDL2_image.dll \
+ $(SDL_TTF_MINGW_HOME)/bin/SDL2_ttf.dll .
+
+osx :
+ g++ -I $(SYSFWPATH)/SDL2.framework/Headers $(INC) \
+ -I $(SYSFWPATH)/SDL2_image.framework/Headers -Wl,-rpath,$(SYSFWPATH) \
+ -framework SDL2 -framework SDL2_image -framework OpenGL main.cpp sdl2-gfx/SDL2_rotozoom.c \
+ -o main
+
+osx-bundle :
+ if [ ! -d "$(APPDIR)" ]; then mkdir -p $(APPDIR); fi;
+ if [ ! -d "$(APPDIR)" ]; then mkdir $(APPDIR); fi;
+ if [ ! -d "$(APPDIR)/MacOS" ]; then mkdir $(APPDIR)/MacOS; fi;
+ if [ ! -d "$(APPDIR)/Frameworks" ]; then mkdir $(APPDIR)/Frameworks; fi;
+ if [ ! -d "$(APPDIR)/Resources" ]; then mkdir $(APPDIR)/Resources; fi;
+ touch $(APPDIR)/Info.plist
+ cp -r $(SYSFWPATH)/SDL2.framework $(APPDIR)/Frameworks
+ cp -r $(SYSFWPATH)/SDL2_image.framework $(APPDIR)/Frameworks
+ g++ -I $(SYSFWPATH)/SDL2.framework/Headers -I $(SYSFWPATH)/SDL2_image.framework/Headers \
+ -Wl,-rpath,@executable_path/../Frameworks -Wl,-rpath,$(SYSFWPATH) \
+ -framework SDL2 -framework SDL2_image -framework OpenGL main.cpp -o $(APPDIR)/MacOS/main
+
+cross : linux android emscripten mingw
diff --git a/config.json b/config.json
new file mode 100644
index 0000000..dc6cc3f
--- /dev/null
+++ b/config.json
@@ -0,0 +1,38 @@
+{
+ "display":
+ {
+ "dimensions": [960, 540],
+ "framerate": 60,
+ "title": "Pepy",
+ "debug": false,
+ "render driver": "opengles3",
+ "show-cursor": true
+ },
+ "configuration":
+ {
+ "auto-refresh": true
+ },
+ "keys":
+ {
+ },
+ "input":
+ {
+ "any-key-ignore-commands": ["up", "right", "down", "left"],
+ "suppress-any-key-on-mods": true
+ },
+ "log":
+ {
+ "enabled": true,
+ "output-directory": "/var/log/sb/",
+ "debug-to-stdout": false,
+ "debug-to-file": true,
+ "info-file-name": "cuckoo_info.log",
+ "debug-file-name": "cuckoo_debug.log"
+ },
+ "sim":
+ {
+ "wall-count": 48,
+ "ball-scale": 0.15,
+ "spawn-radius": 0.35
+ }
+}
diff --git a/lib/sb b/lib/sb
new file mode 160000
index 0000000..ee119ec
--- /dev/null
+++ b/lib/sb
@@ -0,0 +1 @@
+Subproject commit ee119ecc7e4287838cec5aac127820d4738de17f
diff --git a/resource/Book_of_Pepy/1071003012.jpg b/resource/Book_of_Pepy/1071003012.jpg
new file mode 100644
index 0000000..283d388
Binary files /dev/null and b/resource/Book_of_Pepy/1071003012.jpg differ
diff --git a/resource/Book_of_Pepy/129548486_1656033331242674_6748215393958512364_n.jpg b/resource/Book_of_Pepy/129548486_1656033331242674_6748215393958512364_n.jpg
new file mode 100644
index 0000000..ff6e6fe
Binary files /dev/null and b/resource/Book_of_Pepy/129548486_1656033331242674_6748215393958512364_n.jpg differ
diff --git a/resource/Book_of_Pepy/1gfxra.jpg b/resource/Book_of_Pepy/1gfxra.jpg
new file mode 100644
index 0000000..f9cc131
Binary files /dev/null and b/resource/Book_of_Pepy/1gfxra.jpg differ
diff --git a/resource/Book_of_Pepy/E6IhBxRXIAETJ29.jpeg b/resource/Book_of_Pepy/E6IhBxRXIAETJ29.jpeg
new file mode 100644
index 0000000..da13d23
Binary files /dev/null and b/resource/Book_of_Pepy/E6IhBxRXIAETJ29.jpeg differ
diff --git a/resource/Book_of_Pepy/E9GrqOlWYAE2Sgw.jpeg b/resource/Book_of_Pepy/E9GrqOlWYAE2Sgw.jpeg
new file mode 100644
index 0000000..9531016
Binary files /dev/null and b/resource/Book_of_Pepy/E9GrqOlWYAE2Sgw.jpeg differ
diff --git a/resource/Book_of_Pepy/Ea1zDCEUwAAKUcF.jpeg b/resource/Book_of_Pepy/Ea1zDCEUwAAKUcF.jpeg
new file mode 100644
index 0000000..2e653ae
Binary files /dev/null and b/resource/Book_of_Pepy/Ea1zDCEUwAAKUcF.jpeg differ
diff --git a/resource/Book_of_Pepy/EcrFXg5VcAE6tK6.jpeg b/resource/Book_of_Pepy/EcrFXg5VcAE6tK6.jpeg
new file mode 100644
index 0000000..2861dce
Binary files /dev/null and b/resource/Book_of_Pepy/EcrFXg5VcAE6tK6.jpeg differ
diff --git a/resource/Book_of_Pepy/Japanese-chocolate-whisky-Morinaga-twig-big-Koeda-whisky-pairing-buy-special-drink-review-photos-4.webp b/resource/Book_of_Pepy/Japanese-chocolate-whisky-Morinaga-twig-big-Koeda-whisky-pairing-buy-special-drink-review-photos-4.webp
new file mode 100644
index 0000000..cfeedbe
Binary files /dev/null and b/resource/Book_of_Pepy/Japanese-chocolate-whisky-Morinaga-twig-big-Koeda-whisky-pairing-buy-special-drink-review-photos-4.webp differ
diff --git a/resource/Book_of_Pepy/Lenny-Face.png b/resource/Book_of_Pepy/Lenny-Face.png
new file mode 100644
index 0000000..b11e830
Binary files /dev/null and b/resource/Book_of_Pepy/Lenny-Face.png differ
diff --git a/resource/Book_of_Pepy/b89d70e6fb9c4caaed2e797f01bb7575.jpg b/resource/Book_of_Pepy/b89d70e6fb9c4caaed2e797f01bb7575.jpg
new file mode 100644
index 0000000..5479c01
Binary files /dev/null and b/resource/Book_of_Pepy/b89d70e6fb9c4caaed2e797f01bb7575.jpg differ
diff --git a/resource/Book_of_Pepy/cat-party-hat-eats-fish-burger-beige-multi-colored-eating-big-fresh-white-square-plate-drinking-beer-table-183867588.jpg b/resource/Book_of_Pepy/cat-party-hat-eats-fish-burger-beige-multi-colored-eating-big-fresh-white-square-plate-drinking-beer-table-183867588.jpg
new file mode 100644
index 0000000..bbb2575
Binary files /dev/null and b/resource/Book_of_Pepy/cat-party-hat-eats-fish-burger-beige-multi-colored-eating-big-fresh-white-square-plate-drinking-beer-table-183867588.jpg differ
diff --git a/resource/Book_of_Pepy/large.webp b/resource/Book_of_Pepy/large.webp
new file mode 100644
index 0000000..dca0334
Binary files /dev/null and b/resource/Book_of_Pepy/large.webp differ
diff --git a/resource/Book_of_Pepy/necropolis_of_Pepy.png b/resource/Book_of_Pepy/necropolis_of_Pepy.png
new file mode 100644
index 0000000..e798830
Binary files /dev/null and b/resource/Book_of_Pepy/necropolis_of_Pepy.png differ
diff --git a/resource/Book_of_Pepy/vz-ff8724ba-584e-4f9d-bae5-f7c15e462512.jpeg b/resource/Book_of_Pepy/vz-ff8724ba-584e-4f9d-bae5-f7c15e462512.jpeg
new file mode 100644
index 0000000..9031c62
Binary files /dev/null and b/resource/Book_of_Pepy/vz-ff8724ba-584e-4f9d-bae5-f7c15e462512.jpeg differ
diff --git a/resource/Book_of_Pepy/walking_pepy_london.png b/resource/Book_of_Pepy/walking_pepy_london.png
new file mode 100644
index 0000000..50aef8a
Binary files /dev/null and b/resource/Book_of_Pepy/walking_pepy_london.png differ
diff --git a/resource/space.png b/resource/space.png
new file mode 100644
index 0000000..e97dbea
Binary files /dev/null and b/resource/space.png differ
diff --git a/resource/wad.png b/resource/wad.png
new file mode 100644
index 0000000..e12c550
Binary files /dev/null and b/resource/wad.png differ
diff --git a/shell.html b/shell.html
new file mode 100644
index 0000000..922c103
--- /dev/null
+++ b/shell.html
@@ -0,0 +1,180 @@
+
+
+
+
+
+ B.U.D.D.I.
+
+
+
+
+ Pepy, it's cuckoo time! Please make it as big as possible using the arrow keys in
+ 10 seconds.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{{ SCRIPT }}}
+
+
diff --git a/src/Model.cpp b/src/Model.cpp
new file mode 100644
index 0000000..eaf8028
--- /dev/null
+++ b/src/Model.cpp
@@ -0,0 +1,160 @@
+/* Cuckoo by @ohsqueezy [ohsqueezy.itch.io] */
+
+#include "Model.hpp"
+
+/* Default constructor for Model */
+Model::Model() {};
+
+/* Construct a Model, adding Attributes each already wrapped in a shared pointer. The attributes should
+ * be passed as a map with each key being a name and each value being a shared pointer to attributes. */
+Model::Model(const std::map>& attributes_pack)
+{
+ for (auto attributes : attributes_pack)
+ {
+ this->attributes(attributes.second, attributes.first);
+ }
+}
+
+/* Construct a Model, adding Attributes, which will each be wrapped in a shared pointer and stored in the
+ * created object. The attributes should be passed as a map with each key being a name and each value being
+ * an attributes object. */
+Model::Model(const std::map& attributes_pack)
+{
+ for (auto attributes : attributes_pack)
+ {
+ this->attributes(attributes.second, attributes.first);
+ }
+}
+
+/* Construct a new model object by passing a list of names which will be used to initialize
+ * empty attributes objects with the given names */
+Model::Model(const std::initializer_list& names)
+{
+ for (const std::string& name : names)
+ {
+ this->attributes(sb::Attributes(), name);
+ }
+}
+
+/* Get the entire map of attributes, each wrapped in its shared pointer held by this object.
+ * Can be used to iterate through the attributes. */
+std::map>& Model::attributes()
+{
+ return model_attributes;
+}
+
+/* Get the attributes under name, wrapped in the shared pointer held by this object. This
+ * function uses the at method of std::map, so name must refer to attributes already
+ * stored in this model. Use this function to share ownership of the attributes or to gain
+ * access to the public interface of the attributes. */
+std::shared_ptr& Model::attributes(const std::string& name)
+{
+ return attributes().at(name);
+}
+
+/* Get the attributes under name, wrapped in the shared pointer held by this object. This
+ * function uses operator[] or std::map, so this can be used to add new attributes to the
+ * object if they are wrapped in a shared pointer. */
+std::shared_ptr& Model::operator[](const std::string& name)
+{
+ auto element = attributes().find(name);
+ /* add an empty Attributes at name if it doesn't exist yet */
+ if (element == attributes().end())
+ {
+ attributes(sb::Attributes{}, name);
+ }
+ return attributes()[name];
+}
+
+/* Assign name to attributes, copy and wrap in a shared pointer. The model can share
+ * ownership of the created attribute memory with callers that request it. */
+void Model::attributes(const sb::Attributes& attributes, const std::string& name)
+{
+ this->attributes(std::make_shared(attributes), name);
+}
+
+/* Assign name to attributes and share ownership. */
+void Model::attributes(const std::shared_ptr& attributes, const std::string& name)
+{
+ this->attributes()[name] = attributes;
+}
+
+/* Enable all attributes. */
+void Model::enable()
+{
+ for (const auto& attributes : this->attributes())
+ {
+ attributes.second->enable();
+ }
+}
+
+/* Disable all attributes. */
+void Model::disable()
+{
+ for (const auto& attributes : this->attributes())
+ {
+ attributes.second->disable();
+ }
+}
+
+/* Return a reference to the texture container. */
+std::map& Model::textures()
+{
+ return model_textures;
+}
+
+/* Get the texture at name. This can be used to read the texture memory, share ownership of it, or
+ * anything else a Texture object can be used for with direct calls to GL functions. */
+sb::Texture& Model::texture(const std::string& name)
+{
+ return textures().at(name);
+}
+
+/* Get the default texture. The default texture must have previously been set with the default key as
+ * the name, which can be done using Model::texture(sb::Texture). */
+sb::Texture& Model::texture()
+{
+ return texture(DEFAULT_TEXTURE_NAME);
+}
+
+/* Assign name to texture and share ownership. */
+void Model::texture(const sb::Texture& texture, const std::string& name)
+{
+ textures()[name] = texture;
+}
+
+/* If no name is specified, use the default texture. This can be used to conveniently setup a model
+ * with only one texture. */
+void Model::texture(const sb::Texture& texture)
+{
+ this->texture(texture, DEFAULT_TEXTURE_NAME);
+}
+
+/* Get the model's transformation matrix. */
+const glm::mat4& Model::transformation() const
+{
+ return model_transformation;
+}
+
+/* Set the model's transformation matrix. */
+void Model::transformation(const glm::mat4& transformation)
+{
+ model_transformation = transformation;
+}
+
+/* Return the size in bytes of the sum of the attributes. */
+std::size_t Model::size()
+{
+ std::size_t sum = 0;
+ for (const auto& attributes : this->attributes())
+ {
+ sum += attributes.second->size();
+ }
+ return sum;
+}
+
+/* Return the transformation matrix. */
+Model::operator glm::mat4() const
+{
+ return model_transformation;
+}
diff --git a/src/Model.hpp b/src/Model.hpp
new file mode 100644
index 0000000..5145e60
--- /dev/null
+++ b/src/Model.hpp
@@ -0,0 +1,75 @@
+/* Cuckoo by @ohsqueezy [ohsqueezy.itch.io] */
+
+#ifndef MODEL_H_
+#define MODEL_H_
+
+/* GL functions */
+#if defined(__EMSCRIPTEN__)
+#include
+#else
+#include "glew/glew.h"
+#endif
+
+#include
+#include
+#include