diff --git a/LICENSE.txt b/LICENSE.txt index c422805..48c7e0e 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2021 Nuggets Select <420@shampoo.ooo> +Copyright (c) 2021-22 shampoo.ooo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of diff --git a/README.md b/README.md index ab98a5a..159232e 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ SPACEBOX ======== -
-         /\         +------------------------------------------------------------+ 
-    ____/  \____   /| zlib/MIT/Unlicenced game framework licensed to freely use, |
-    \          /  / | copy, modify and sell without restriction                  |
-  +--\ ^__^   /--+  |                                                            |
-  | ~/        \~ |  | Learn more about *SPACEBOX* at [shampoo.ooo][]             |
-  | ~~~~~~~~~~~~ |  +------------------------------------------------------------+
-  | SPACE ~~~~~  | /
-  |  ~~~~~~~ BOX |/
-  +--------------+   
- ![logo](icon/static.png) +
+       /\         +------------------------------------------------------+ 
+  ____/  \____   /| - Open source game framework licensed to freely use, |
+  \          /  / |   copy, modify and sell without restriction          |
++--\ ^__^   /--+  |                                                      |
+| ~/        \~ |  | - created for              |
+| ~~~~~~~~~~~~ |  +------------------------------------------------------+
+| SPACE ~~~~~  | /
+|  ~~~~~~~ BOX |/
++--------------+  
+ *SPACEBOX* is a C++ framework that makes creating cross-platform games and other interactive applications easier and faster by providing an added layer of abstraction between SDL + OpenGL and the project. Users can start a project by extending only a single function, the Game class's update function. Using a standard Makefile that can be taken from the examples, the framework can export the same code to multiple platforms like, in order of current stability, Linux, Web, Android, OS X, Windows, and Raspberry Pi. diff --git a/demo/box/.gitignore b/demo/box/.gitignore new file mode 100644 index 0000000..9dc24a1 --- /dev/null +++ b/demo/box/.gitignore @@ -0,0 +1,5 @@ +box +*_log.txt +*.data +box_demo.js +*.wasm diff --git a/demo/cube/BPmono.ttf b/demo/box/BPmono.ttf similarity index 100% rename from demo/cube/BPmono.ttf rename to demo/box/BPmono.ttf diff --git a/demo/box/BoxDemo.cpp b/demo/box/BoxDemo.cpp new file mode 100644 index 0000000..6e58335 --- /dev/null +++ b/demo/box/BoxDemo.cpp @@ -0,0 +1,235 @@ +/*!
+ *        /\         +------------------------------------------------------+ 
+ *   ____/  \____   /| - Open source game framework licensed to freely use, |
+ *   \          /  / |   copy, modify and sell without restriction          |
+ * +--\ ^__^   /--+  |                                                      |
+ * | ~/        \~ |  | - created for              |
+ * | ~~~~~~~~~~~~ |  +------------------------------------------------------+
+ * | SPACE ~~~~~  | /
+ * |  ~~~~~~~ BOX |/
+ * +--------------+                                                    
+ * + * Display a rotating box with a space texture and gradient background using SDL, OpenGL, and Spacebox. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "glm/glm.hpp" +#include "Game.hpp" +#include "GLObject.hpp" +#include "VBO.hpp" +#include "Model.hpp" + +struct BoxDemo : Game +{ + +private: + + Model box; + Plane background; + bool right_active = false, down_active = false, left_active = false, up_active = false, is_writing_audio = true; + SDL_Event event; + sb::Texture fake; + GLuint mvp_uniform_id, flat_program, world_program; + glm::mat4 projection, view, model = glm::mat4(1.0f), mvp; + sb::VAO vao; + sb::VBO vbo; + +public: + + BoxDemo() + { + Mix_Music *music = Mix_LoadMUS("resource/Field.mp3"); + Mix_PlayMusic(music, -1); + load_gl_context(); + delegate.subscribe(&BoxDemo::respond, this); + delegate.subscribe(&BoxDemo::respond, this, SDL_MOUSEBUTTONDOWN); + } + + void load_gl_context() + { + Game::load_gl_context(); + + /* Generate a vertex array object ID, bind it as current (requirement of OpenGL) */ + vao.generate(); + vao.bind(); + + /* Generate ID for the vertex buffer object that will hold all vertex data. Using one buffer for all attributes, data + * will be copied in one after the other. */ + vbo.generate(); + vbo.bind(); + + /* + v0-v1-v2 (front) + v2-v3-v0 + v0-v3-v4 (right) + v4-v5-v0 + v0-v5-v6 (top) + v6-v1-v0 + v1-v6-v7 (left) + v7-v2-v1 + v7-v4-v3 (bottom) + v3-v2-v7 + v4-v7-v6 (back) + v6-v5-v4 + */ + box = Model({ + {"position", { + {1, 1, 1}, {-1, 1, 1}, {-1,-1, 1}, + {-1,-1, 1}, {1,-1, 1}, {1, 1, 1}, + {1, 1, 1}, {1,-1, 1}, {1,-1,-1}, + {1,-1,-1}, {1, 1,-1}, {1, 1, 1}, + {1, 1, 1}, {1, 1,-1}, {-1, 1,-1}, + {-1, 1,-1}, {-1, 1, 1}, {1, 1, 1}, + {-1, 1, 1}, {-1, 1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1, 1}, {-1, 1, 1}, + {-1,-1,-1}, {1,-1,-1}, {1,-1, 1}, + {1,-1, 1}, {-1,-1, 1}, {-1,-1,-1}, + {1,-1,-1}, {-1,-1,-1}, {-1, 1,-1}, + {-1, 1,-1}, {1, 1,-1}, {1,-1,-1} + }}, + {"uv", { + {1, 1}, {0, 1}, {0, 0}, + {0, 0}, {1, 0}, {1, 1}, + {0, 1}, {0, 0}, {1, 0}, + {1, 0}, {1, 1}, {0, 1}, + {0, 1}, {0, 0}, {1, 0}, + {1, 0}, {1, 1}, {0, 1}, + {1, 1}, {0, 1}, {0, 0}, + {0, 0}, {1, 0}, {1, 1}, + {0, 0}, {1, 0}, {1, 1}, + {1, 1}, {0, 1}, {0, 0}, + {0, 0}, {1, 0}, {1, 1}, + {1, 1}, {0, 1}, {0, 0} + }} + }); + box.texture(sb::Texture()); + box.texture().load("resource/tile.png"); + + /* Create a 1x1 white texture */ + glm::vec2 fake_size = {1, 1}; + unsigned char fake_color[4] = {255, 255, 255, 255}; + fake.generate(fake_size); + fake.load(fake_color, fake_size); + + /* Add color attributes and a full white texture */ + background.attributes({ + {0.2f, 0.6f, 0.8f}, {0.2f, 0.6f, 0.8f}, {1.0f, 1.0f, 0.0f}, + {0.2f, 0.6f, 0.8f}, {1.0f, 1.0f, 0.0f}, {1.0f, 1.0f, 0.0f} + }, "color"); + background.texture(fake); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /* Create a projection matrix */ + glm::ivec2 resolution = get_display().window_size(); + float aspect = resolution.x / (float) resolution.y; + projection = glm::perspective(glm::radians(40.0f) / aspect, aspect, 0.1f, 100.0f); + view = glm::lookAt(glm::vec3{4.0f, 3.0f, 3.0f}, glm::vec3{0.0f, 0.65f, 0.0f}, glm::vec3{0.0f, 1.0f, 0.0f}); + + /* Load shader programs, associate model attributes with shader variables, read uniform IDs */ + GLuint triangle_vertex_shader = load_shader("shaders/triangle.vert", GL_VERTEX_SHADER); + GLuint fragment_shader = load_shader("shaders/all.frag", GL_FRAGMENT_SHADER); + GLuint flat_vertex_shader = load_shader("shaders/flat.vert", GL_VERTEX_SHADER); + + world_program = glCreateProgram(); + glAttachShader(world_program, triangle_vertex_shader); + glAttachShader(world_program, fragment_shader); + box.attributes("position")->bind(3, world_program, "in_Position"); + box.attributes("uv")->bind(4, world_program, "vertexUV"); + link_shader(world_program); + + flat_program = glCreateProgram(); + glAttachShader(flat_program, flat_vertex_shader); + glAttachShader(flat_program, fragment_shader); + background.attributes("position")->bind(0, flat_program, "in_Position"); + background.attributes("uv")->bind(1, flat_program, "vertexUV"); + background.attributes("color")->bind(2, flat_program, "in_Color"); + link_shader(flat_program); + + mvp_uniform_id = glGetUniformLocation(world_program, "MVP"); + + /* Fill VBO with attribute data */ + vbo.allocate(background.size() + box.size(), GL_STATIC_DRAW); + vbo.add(*Plane::position); + vbo.add(*Plane::uv); + vbo.add(*background.attributes("color")); + vbo.add(*box.attributes("position")); + vbo.add(*box.attributes("uv")); + sb::Log::gl_errors("after filling VBO"); + + for (GLuint program : {flat_program, world_program}) + { + /* Set the active texture unit to #0, Get the texture uniform from the shader and set it use texture #0. See + * https://www.khronos.org/opengl/wiki/Sampler_(GLSL)#Binding_textures_to_samplers */ + glUseProgram(program); + glActiveTexture(GL_TEXTURE0); + glUniform1i(glGetUniformLocation(program, "myTextureSampler"), 0); + } + + glDepthFunc(GL_LESS); + } + + void respond(SDL_Event& event) + { + if (delegate.compare(event, "play-sound") || event.type == SDL_MOUSEBUTTONDOWN) + { + Mix_Chunk* music = Mix_LoadWAV("resource/Ag.ogg"); + Mix_PlayChannel(-1, music, 0); + } + } + + void update() + { + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDisable(GL_DEPTH_TEST); + + /* Draw background */ + glUseProgram(flat_program); + box.disable(); + background.enable(); + background.texture().bind(); + glDrawArrays(GL_TRIANGLES, 0, background.attributes("position")->count()); + + /* Rotate projection matrix */ + float rotation = .0005f * get_frame_length(); + model = glm::rotate(model, rotation, glm::vec3(0.0f, 1.0f, 0.0f)); + mvp = projection * view * model; + + glUseProgram(world_program); + + /* Pass the MVP matrix to the triangle vertex shader using the memory address of the top left value */ + glUniformMatrix4fv(mvp_uniform_id, 1, GL_FALSE, &mvp[0][0]); + + /* Set the color attribute to white so the texture will not be modified */ + glVertexAttrib3f(glGetAttribLocation(world_program, "in_Color"), 1, 1, 1); + + /* Draw the box */ + glEnable(GL_DEPTH_TEST); + background.disable(); + box.enable(); + box.texture().bind(); + glDrawArrays(GL_TRIANGLES, 0, box.attributes("position")->count()); + SDL_GL_SwapWindow(window()); + } + +}; + +int main() +{ + BoxDemo demo = BoxDemo(); + demo.run(); + demo.quit(); + return 0; +} diff --git a/demo/box/Makefile b/demo/box/Makefile new file mode 100644 index 0000000..654850b --- /dev/null +++ b/demo/box/Makefile @@ -0,0 +1,247 @@ +# /\ +------------------------------------------------------+ +# ____/ \____ /| - Open source game framework licensed to freely use, | +# \ / / | copy, modify and sell without restriction | +# +--\ ^__^ /--+ | | +# | ~/ \~ | | - created for | +# | ~~~~~~~~~~~~ | +------------------------------------------------------+ +# | SPACE ~~~~~ | / +# | ~~~~~~~ BOX |/ +# +--------------+ +# +# These are build targets for the box demo for Linux, Android, and web. Other platforms haven't been tested in a while +# and won't work without significant editing. Modify variables as necessary to match the system this is running on and +# run `make box`, `make build/android/ooo.shampoo.box/app_debug.apk`, or `make box_demo.js` in the current directory. + +####################### +# Location parameters # +####################### + +# Location of source files for the demo +SRC_DIR := ./ + +# Locations of [SPACEBOX] source and dependencies required to be compiled from source. These locations are configured to match +# the structure of the [SPACEBOX] repository but can be modified as necessary. +SB_DIR := ../../ +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 +CXX := clang++ + +# Location of SDL config program +SDLCONFIG := ~/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 := BoxDemo.o $(SRC_H_FILES:.hpp=.o) + +################################################################# +# Targets for building [SPACEBOX], dependencies and demo 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)Model.o: $(addprefix $(SB_SRC_DIR),extension.hpp Attributes.hpp Texture.hpp utility.hpp) +$(SRC_DIR)BoxDemo.o: $(SRC_H_FILES) $(SB_H_FILES) +%.o: %.cpp %.hpp + $(CXX) $(CXXFLAGS) $< -c -o $@ + +######### +# Linux # +######### + +box: CFLAGS = -Wall -Wextra -g -O3 -c -I$(SB_LIB_DIR) -I$(SB_SRC_DIR) $(SDL_CFLAGS) +box: CXXFLAGS = $(CFLAGS) --std=c++17 +box: LFLAGS = $(SDL_LFLAGS) -Wl,--enable-new-dtags -lpthread -lGL -lGLESv2 -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lstdc++fs +box: $(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) $(SB_O_FILES) $(SRC_O_FILES) + $(CREATE_FONT_SYMLINK) + $(CXX) $^ $(LFLAGS) -D__LINUX__ -o box + +####### +# Web # +####### + +# Use Emscripten to output JavaScript and an HTML index page for running in the browser + +EMSCRIPTENHOME = $(HOME)/ext/software/emsdk/upstream/emscripten +EMSCRIPTEN_CFLAGS = -O1 -Wall -s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="['png', 'jpg']" -s USE_SDL_TTF=2 -s USE_SDL_MIXER=2 \ + -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 -s LLD_REPORT_UNDEFINED +EMSCRIPTEN_PRELOADS = --preload-file "BPmono.ttf"@/ --preload-file "shaders/"@/"shaders/" --preload-file "config.json"@/ --preload-file "resource/"@/"resource/" + +box_demo.js: CC = $(EMSCRIPTENHOME)/emcc +box_demo.js: CXX = $(EMSCRIPTENHOME)/em++ +box_demo.js: CFLAGS = $(EMSCRIPTEN_CFLAGS) +box_demo.js: CXXFLAGS = $(CFLAGS) --std=c++17 +box_demo.js: $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) $(SB_O_FILES) $(SRC_O_FILES) index.html config.json resource/* shaders/* + $(CREATE_FONT_SYMLINK) + $(CXX) $(filter %.o,$^) $(CXXFLAGS) $(EMSCRIPTEN_LFLAGS) $(EMSCRIPTEN_PRELOADS) -o box_demo.js + +########### +# Android # +########### + +# Detailed info on how this build target was created is in README.md at the root of the repository. It requires the Android SDK and the source packages +# for SDL, SDL_image, SDL_mixer, and SDL_ttf. The paths below should be customized. The icon creation requires Imagemagick's convert tool from +# . The project source files are assumed to be just `$(SRC_DIR)/*.cpp`. If that is not the case, the revise_skeleton.sh script +# must be edited. + +SDL_SRC := $(HOME)/ext/software/SDL2-2.24.0-android +SDL_IMAGE_SRC := $(HOME)/ext/software/SDL2_image-2.6.2-android +SDL_MIXER_SRC := $(HOME)/ext/software/SDL2_mixer-2.6.2-android +SDL_TTF_SRC := $(HOME)/ext/software/SDL2_ttf-2.20.1-android +SDL_ANDROID_PROJECT := $(SDL_SRC)/android-project +ANDROID_MK := app/jni/src/Android.mk +ANDROID_APP_MK := app/jni/Application.mk +ANDROID_MANIFEST := app/src/main/AndroidManifest.xml +ANDROID_SDK := $(HOME)/local/Android +ANDROID_PACKAGE := ooo.shampoo.spacebox +ANDROID_BUILD_DIR := build/android/$(ANDROID_PACKAGE) +ANDROID_CLASS := BoxDemo +ANDROID_CLASS_DIR := app/src/main/java/$(subst .,/,$(ANDROID_PACKAGE)) + +# The skeleton for the Android build is based on the SDL android-project. The libraries are symlinked in. If the script that rewrites the skeleton +# has changed, start with a fresh skeleton. +$(ANDROID_BUILD_DIR): $(SDL_SRC)/android-project/ $(SB_SRC_DIR)/android/revise_skeleton.sh + -mkdir -p $(ANDROID_BUILD_DIR) + rsync -ar $(SDL_SRC)/android-project/ $(ANDROID_BUILD_DIR) + ln -nsf $(SDL_SRC) $(ANDROID_BUILD_DIR)/app/jni/SDL + ln -nsf $(SDL_IMAGE_SRC) $(ANDROID_BUILD_DIR)/app/jni/SDL2_image + ln -nsf $(SDL_MIXER_SRC) $(ANDROID_BUILD_DIR)/app/jni/SDL2_mixer + ln -nsf $(SDL_TTF_SRC) $(ANDROID_BUILD_DIR)/app/jni/SDL2_ttf + $(SB_SRC_DIR)/android/revise_skeleton.sh $(ANDROID_PACKAGE) $(ANDROID_BUILD_DIR) $(ANDROID_MANIFEST) $(ANDROID_APP_MK) $(ANDROID_MK) $(ANDROID_CLASS) \ + $(ANDROID_APP_NAME) $(ANDROID_MIN_TARGET) $(ANDROID_NDK) "Box Demo" "18" "22.1.7171670" $(SB_SRC_DIR) $(SB_LIB_DIR) $(SRC_DIR) + +# Extend the SDLActivity class +$(ANDROID_BUILD_DIR)/$(ANDROID_CLASS_DIR)/$(ANDROID_CLASS).java: $(SB_SRC_DIR)/android/main_class.sh + $(SB_SRC_DIR)/android/main_class.sh $(ANDROID_PACKAGE) $(ANDROID_CLASS) $(ANDROID_BUILD_DIR)/$(ANDROID_CLASS_DIR) + +# Generate icon +$(ANDROID_BUILD_DIR)/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: $(SB_SRC_DIR)/android/generate_icon.sh $(SB_DIR)/icon + $(SB_SRC_DIR)/android/generate_icon.sh $(ANDROID_BUILD_DIR) "../../icon/foreground.png" "../../icon/background.png" + +# Custom assets +$(ANDROID_BUILD_DIR)/app/src/main/assets: config.json resource/* shaders/* + -mkdir -p $(ANDROID_BUILD_DIR)/app/src/main/assets + rsync -ar resource shaders config.json $(ANDROID_BUILD_DIR)/app/src/main/assets + +# Run gradle and generate an APK +$(ANDROID_BUILD_DIR)/app-debug.apk: $(ANDROID_BUILD_DIR) $(ANDROID_BUILD_DIR)/$(ANDROID_CLASS_DIR)/$(ANDROID_CLASS).java \ + $(ANDROID_BUILD_DIR)/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml $(ANDROID_BUILD_DIR)/app/src/main/assets + ANDROID_SDK_ROOT=$(ANDROID_SDK) $(ANDROID_BUILD_DIR)/gradlew -p $(ANDROID_BUILD_DIR) build + ln -nsf app/build/outputs/apk/debug/app-debug.apk $(ANDROID_BUILD_DIR) + ln -nsf app/build/outputs/apk/debug/app-release-unsigned.apk $(ANDROID_BUILD_DIR) + +###################### +# Clean object files # +###################### + +clean: + -find $(SRC_DIR) -iname "*.o" -delete + rm -f BPmono.ttf + rm -f box + +clean-all: clean + -find $(SB_SRC_DIR) -iname "*.o" -delete + -find $(SB_LIB_DIR) -iname "*.o" -delete + +.PHONY = clean clean-all + +############# +# 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 +compile_commands.json: + -$(PATH_TO_COMPILEDB) -n make box -k + +############################################################################################ +# WARNING: these targets are out of date and only here for reference until they're updated # +############################################################################################ + +BUILDDIR := build +SOFTWARE_ROOT := /home/frank/ext/software +SDLHOME := $(SOFTWARE_ROOT)/SDL2-2.0.14 +SDL_IMG_HOME := $(SOFTWARE_ROOT)/SDL2_image-2.0.5 +SDL_TTF_HOME := $(SOFTWARE_ROOT)/SDL2_ttf-2.0.15 +GLEW_WIN32_HOME := $(SOFTWARE_ROOT)/glew-2.1.0-win32 +PROJECTHOME := $(shell pwd) +SDLEMLIBSHOME := $(SDLHOME)/build/em/build/.libs +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 + +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/demo/box/Model.cpp b/demo/box/Model.cpp new file mode 100644 index 0000000..3927d72 --- /dev/null +++ b/demo/box/Model.cpp @@ -0,0 +1,196 @@ +/* _______________ ,----------------------------------------------------------------. + //`````````````\\ \ \ + //~~~~~~~~~~~~~~~\\ \ by @ohsqueezy & @sleepin \ + //=================\\ \ [ohsqueezy.itch.io] [sleepin.itch.io] \ + // \\ \ \ + // \\ \ code released under the zlib license [git.nugget.fun/pudding] \ + // ☆ GUNKISS ☆ \\ \ \ +//_________________________\\ `---------------------------------------------------------------*/ + +#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; +} + +PlaneDoubleBuffer::PlaneDoubleBuffer() : Plane() +{ + texture(sb::Texture(), "front"); + texture(sb::Texture(), "back"); +} + +void PlaneDoubleBuffer::generate(const glm::vec2& size) +{ + for (sb::Texture* buffer : {&texture("front"), &texture("back")}) + { + buffer->generate(size); + } +} + +sb::Texture& PlaneDoubleBuffer::active() +{ + return swapped ? texture("back") : texture("front"); +} + +sb::Texture& PlaneDoubleBuffer::inactive() +{ + return swapped ? texture("front") : texture("back"); +} + +void PlaneDoubleBuffer::swap() +{ + swapped = !swapped; +} diff --git a/demo/box/Model.hpp b/demo/box/Model.hpp new file mode 100644 index 0000000..9552fa7 --- /dev/null +++ b/demo/box/Model.hpp @@ -0,0 +1,105 @@ +/* _______________ ,----------------------------------------------------------------. + //`````````````\\ \ \ + //~~~~~~~~~~~~~~~\\ \ by @ohsqueezy & @sleepin \ + //=================\\ \ [ohsqueezy.itch.io] [sleepin.itch.io] \ + // \\ \ \ + // \\ \ code released under the zlib license [git.nugget.fun/pudding] \ + // ☆ GUNKISS ☆ \\ \ \ +//_________________________\\ `---------------------------------------------------------------*/ + +#ifndef MODEL_H_ +#define MODEL_H_ + +/* GL functions */ +#if defined(__ANDROID__) || defined(ANDROID) +#include +#include +#else +#include "glew/glew.h" +#endif + +#include +#include +#include +#include +#include +#include "glm/glm.hpp" +#include "Attributes.hpp" +#include "Texture.hpp" + +class Model +{ + +private: + + inline static const std::string DEFAULT_TEXTURE_NAME = "default"; + std::map model_textures; + std::map> model_attributes; + glm::mat4 model_transformation {1.0f}; + +public: + + Model(); + Model(const std::map>&); + Model(const std::map&); + Model(const std::initializer_list&); + std::map>& attributes(); + std::shared_ptr& attributes(const std::string&); + void attributes(const sb::Attributes&, const std::string&); + void attributes(const std::shared_ptr&, const std::string&); + std::shared_ptr& operator[](const std::string&); + void enable(); + void disable(); + std::map& textures(); + sb::Texture& texture(const std::string&); + sb::Texture& texture(); + void texture(const sb::Texture&, const std::string&); + void texture(const sb::Texture&); + const glm::mat4& transformation() const; + void transformation(const glm::mat4&); + std::size_t size(); + operator glm::mat4() const; + +}; + +class Plane : public Model +{ + +public: + + inline const static std::shared_ptr position = std::make_shared(sb::Attributes{ + {-1.0f, 1.0f}, {1.0f, 1.0f}, {-1.0f, -1.0f}, + {1.0f, 1.0f}, {1.0f, -1.0f}, {-1.0f, -1.0f} + }); + inline const static std::shared_ptr uv = std::make_shared(sb::Attributes{ + {0.0f, 1.0f}, {1.0f, 1.0f}, {0.0f, 0.0f}, + {1.0f, 1.0f}, {1.0f, 0.0f}, {0.0f, 0.0f} + }); + + Plane() : Model(std::map>({{"position", position}, {"uv", uv}})) {} + +}; + +/*! + * A version of `Plane` which contains two texture objects, one of which is active at a time. A reference + * to the active `sb::Texture` object is available from `PlaneDoubleBuffer.active`, and the inactive object is + * available from `PlaneDoubleBuffer.inactive`. The buffers can be swapped using `PlaneDoubleBuffer.swap`. + */ +class PlaneDoubleBuffer : public Plane +{ + +private: + + bool swapped = false; + +public: + + PlaneDoubleBuffer(); + void generate(const glm::vec2&); + sb::Texture& active(); + sb::Texture& inactive(); + void swap(); + +}; + +#endif diff --git a/demo/cube/config.json b/demo/box/config.json similarity index 71% rename from demo/cube/config.json rename to demo/box/config.json index bb174db..4daf856 100644 --- a/demo/cube/config.json +++ b/demo/box/config.json @@ -1,14 +1,14 @@ { "display": { - "dimensions": [864, 486], + "dimensions": [480, 800], "fps": 60 }, "keys": { "context": " ", "print-video-memory-size": "v", - "play-sound": "" + "play-sound": "s" }, "input": { @@ -18,9 +18,14 @@ { "screenshot-directory": "local/screenshots", "video-directory": "local/video", - "enabled": true, - "write-mp4": true, + "enabled": false, + "write-mp4": false, "video-frame-length": 16.667, "max-video-memory": 2000 + }, + "log": + { + "enabled": true, + "debug-to-file": true } } diff --git a/demo/box/index.html b/demo/box/index.html new file mode 100644 index 0000000..68109ad --- /dev/null +++ b/demo/box/index.html @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + diff --git a/demo/cube/resource/Ag.ogg b/demo/box/resource/Ag.ogg similarity index 100% rename from demo/cube/resource/Ag.ogg rename to demo/box/resource/Ag.ogg diff --git a/demo/cube/resource/Field.mp3 b/demo/box/resource/Field.mp3 similarity index 100% rename from demo/cube/resource/Field.mp3 rename to demo/box/resource/Field.mp3 diff --git a/demo/box/resource/tile.png b/demo/box/resource/tile.png new file mode 100644 index 0000000..3afb674 Binary files /dev/null and b/demo/box/resource/tile.png differ diff --git a/demo/box/shaders/all.frag b/demo/box/shaders/all.frag new file mode 100644 index 0000000..db0311d --- /dev/null +++ b/demo/box/shaders/all.frag @@ -0,0 +1,24 @@ +#version 300 es + + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + +/* The precision declaration is required by OpenGL ES */ +precision mediump float; + +in vec4 ex_Color; +in vec2 UV; +uniform sampler2D myTextureSampler; +out vec4 outputColor; + +void main(void) +{ + outputColor = texture(myTextureSampler, UV) * ex_Color; +} diff --git a/demo/box/shaders/flat.vert b/demo/box/shaders/flat.vert new file mode 100644 index 0000000..ab2de99 --- /dev/null +++ b/demo/box/shaders/flat.vert @@ -0,0 +1,28 @@ +#version 300 es + + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + +/* The precision declaration is required by OpenGL ES */ +precision mediump float; + +in vec2 in_Position; +in vec2 vertexUV; +in vec3 in_Color; + +out vec2 UV; +out vec4 ex_Color; + +void main(void) +{ + gl_Position = vec4(in_Position, 0.0, 1.0); + UV = vertexUV; + ex_Color = vec4(in_Color, 1.0); +} diff --git a/demo/box/shaders/triangle.vert b/demo/box/shaders/triangle.vert new file mode 100644 index 0000000..cd45194 --- /dev/null +++ b/demo/box/shaders/triangle.vert @@ -0,0 +1,30 @@ +#version 300 es + + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + +/* The precision declaration is required by OpenGL ES */ +precision mediump float; + +in vec3 in_Position; +in vec3 in_Color; +in vec2 vertexUV; + +out vec4 ex_Color; +out vec2 UV; + +uniform mat4 MVP; + +void main(void) +{ + gl_Position = MVP * vec4(in_Position, 1); + ex_Color = vec4(in_Color, 1); + UV = vertexUV; +} diff --git a/demo/browser_webcam_test/Makefile b/demo/browser_webcam_test/Makefile index 0fd1bf8..81e3797 100644 --- a/demo/browser_webcam_test/Makefile +++ b/demo/browser_webcam_test/Makefile @@ -1,4 +1,14 @@ -# Browser Webcam Test +# /\ +------------------------------------------------------+ +# ____/ \____ /| - Open source game framework licensed to freely use, | +# \ / / | copy, modify and sell without restriction | +# +--\ ^__^ /--+ | | +# | ~/ \~ | | - created for | +# | ~~~~~~~~~~~~ | +------------------------------------------------------+ +# | SPACE ~~~~~ | / +# | ~~~~~~~ BOX |/ +# +--------------+ +# +# Modify location parameters to match locations for each directory on the system and run `make emscripten` ####################### # Location parameters # diff --git a/demo/browser_webcam_test/browser_webcam_test.cpp b/demo/browser_webcam_test/browser_webcam_test.cpp index a6a0978..7f4a560 100644 --- a/demo/browser_webcam_test/browser_webcam_test.cpp +++ b/demo/browser_webcam_test/browser_webcam_test.cpp @@ -1,12 +1,20 @@ /* - * Browser Webcam Test by frank at shampoo.ooo + * /\ +------------------------------------------------------+ + * ____/ \____ /| - Open source game framework licensed to freely use, | + * \ / / | copy, modify and sell without restriction | + * +--\ ^__^ /--+ | | + * | ~/ \~ | | - created for | + * | ~~~~~~~~~~~~ | +------------------------------------------------------+ + * | SPACE ~~~~~ | / + * | ~~~~~~~ BOX |/ + * +--------------+ * - * Program for testing passing image data from an HTML5 canvas object in JavaScript to an OpenGL context in this C++ program. - * This can be useful, for example, for developing cross-platform applications that use the same codebase to export both desktop - * and web versions, or for using C++ libraries and code to edit and display images on a web page. + * This tests passing image data from an HTML5 canvas object in JavaScript to an OpenGL context. It can be useful, for example, + * for developing cross-platform applications that use the same codebase to export both desktop and web versions, or for using + * C++ libraries to edit and display images on a web page. * - * It uses the [SPACE BOX] engine (https://git.shampoo.ooo/nugget/spacebox) to set up an SDL + GL environment and create a model - * conveniently, but it can be ported to just Emscripten. + * It was written to test transferring webcam image data to OpenCV. The OpenCV dependency was dropped since it isn't necessary just + * for displaying the webcam, but there is an example line in the code where the OpenCV call could be substituted. */ #include @@ -78,7 +86,7 @@ public: /* Set up GL buffers for attributes. Set up shaders and uniforms. Create the texture that will hold the camera pixel data. */ void load_gl_context() { - /* [SPACE BOX] creates an SDL GL context and initializes GLEW. */ + /* [SPACEBOX] uses SDL to create GL context */ Game::load_gl_context(); /* Generate a vertex array object ID, bind it as current (requirement of OpenGL) */ diff --git a/demo/browser_webcam_test/index.html b/demo/browser_webcam_test/index.html index a77004d..21441cf 100644 --- a/demo/browser_webcam_test/index.html +++ b/demo/browser_webcam_test/index.html @@ -1,6 +1,19 @@ - - + + + + + + + + + + diff --git a/demo/cube/Cube.cpp b/demo/cube/Cube.cpp deleted file mode 100644 index 7b9fde1..0000000 --- a/demo/cube/Cube.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/*** - - reset, pause, auto reset, analog d-pad, gamepad config, any key, confirm exit - game, screen + sprite wipes, screen offset, screen scale, networking, post - processing, all objects deactivatable, all objects subscribed to events, all - objects resetable, wrapable & scrollable surface, separate window for - configuration console and variable viewer, text editor for config json, asset - favoriting, audio filters, enforce consistent angle orientation, floating - point coordinates, relative coordinates, relative lengths, relative sizes, - delta time, specify config parameters on command line, effects chain, asset - dict with metadata, move added sprite locations by offset when location is - changed, gradients, level select code input, log to stdout and file, variable - screen resolution, debug display, loading wheel animation, shadowed sprite, - separate update and draw, sprite movement cage, multiple windows, multiple - renderers, node children list, node animations list, copy constructor for all - base classes (esp. sprite, audio, pixels), private and public class members, - pixel class iterator, sprite movement history, input history, use seconds - instead of milliseconds, store a node's animations in list, frame object for - sprite class, inline short functions, add box2d to library, load in separate - thread and display progress, add anchor to box class, add comments to code, - generate documentation from comments, get resource function, automatically - update animations, add arguments list to animation call, queue multiple calls - to animation, print list of chunk and music decoders available, allow nodes - that aren't connected to root, add imagemagick to library, add curl to library, - fail if command line flag is unrecognized - - :) SWEATY HANDS :) OILY SNACKS :) AND BAD HYGIENE :) - -***/ - -#include "Cube.hpp" - -char* file_to_buf(const char *path) -{ - FILE *fp; - long length; - char *buf; - fp = fopen(path, "rb"); - if (not fp) - { - return NULL; - } - fseek(fp, 0, SEEK_END); - length = ftell(fp); - buf = (char*) malloc(length + 1); - fseek(fp, 0, SEEK_SET); - fread(buf, length, 1, fp); - fclose(fp); - buf[length] = 0; - return buf; -} - -GLuint load_shader(const char* path, GLenum type) -{ - char *source = file_to_buf(path); - GLuint shader = glCreateShader(type); - int is_compiled, max_length; - glShaderSource(shader, 1, (const GLchar**) &source, 0); - glCompileShader(shader); - glGetShaderiv(shader, GL_COMPILE_STATUS, &is_compiled); - if(is_compiled == 0) - { - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length); - char *log = (char *) malloc(max_length); - glGetShaderInfoLog(shader, max_length, &max_length, log); - fprintf(stderr, "%s -- shader compilation failed %s\n", path, log); - free(log); - return -1; - } - return shader; -} - -int link_shader(GLuint program) -{ - glLinkProgram(program); - int is_linked, max_length; - glGetProgramiv(program, GL_LINK_STATUS, (int *) &is_linked); - if(is_linked == 0) - { - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length); - char *log = (char *) malloc(max_length); - glGetProgramInfoLog(program, max_length, &max_length, log); - fprintf(stderr, "shader program %i linking failed %s\n", program, log); - free(log); - return -1; - } - return 0; -} - -GLuint get_gl_texture_from_surface(SDL_Surface *surface, GLint mipmap_filter, bool invert = false) -{ - GLuint id; - glCreateTextures(GL_TEXTURE_2D, 1, &id); - glBindTexture(GL_TEXTURE_2D, id); - GLenum format; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - format = invert ? GL_RGBA : GL_BGRA; -#else - format = invert ? GL_BGRA : GL_RGBA; -#endif - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, format, - GL_UNSIGNED_BYTE, surface->pixels); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mipmap_filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmap_filter); - return id; -} - -Mushroom::Mushroom(Node *parent) : Sprite(parent, "resource/shrooms") -{ - set_frame_length(500); - std::cout << "mushroom constructor " << this << std::endl; -} - -void Mushroom::update() -{ - move_weighted({direction, 0}); - int x = get_left(); - glm::ivec2 resolution = get_display().window_size(); - if (x > resolution.x or x < 0) - { - direction = -direction; - if (x > resolution.x) - { - move({resolution.x - x, 0}); - } - else - { - move({-x, 0}); - } - } - Sprite::update(); -} - -Cube::Cube() -{ - Mix_Music *music = Mix_LoadMUS("resource/Field.mp3"); - // Mix_Music *music = Mix_LoadMUS("/home/frank/WATERMELON-clean.mp3"); - Mix_PlayMusic(music, -1); - load_gl_context(); - delegate.subscribe(&Cube::respond, this); -} - -void Cube::load_sdl_context() -{ - Game::load_sdl_context(); - grass.load(); - mushroom.load(); -} - -void Cube::load_gl_context() -{ - Game::load_gl_context(); - grass.unload(); - mushroom.unload(); - /* - v0-v1-v2 (front) - v2-v3-v0 - v0-v3-v4 (right) - v4-v5-v0 - v0-v5-v6 (top) - v6-v1-v0 - v1-v6-v7 (left) - v7-v2-v1 - v7-v4-v3 (bottom) - v3-v2-v7 - v4-v7-v6 (back) - v6-v5-v4 - */ - std::array cube = { - { - {1, 1, 1}, {-1, 1, 1}, {-1,-1, 1}, - {-1,-1, 1}, {1,-1, 1}, {1, 1, 1}, - {1, 1, 1}, {1,-1, 1}, {1,-1,-1}, - {1,-1,-1}, {1, 1,-1}, {1, 1, 1}, - {1, 1, 1}, {1, 1,-1}, {-1, 1,-1}, - {-1, 1,-1}, {-1, 1, 1}, {1, 1, 1}, - {-1, 1, 1}, {-1, 1,-1}, {-1,-1,-1}, - {-1,-1,-1}, {-1,-1, 1}, {-1, 1, 1}, - {-1,-1,-1}, {1,-1,-1}, {1,-1, 1}, - {1,-1, 1}, {-1,-1, 1}, {-1,-1,-1}, - {1,-1,-1}, {-1,-1,-1}, {-1, 1,-1}, - {-1, 1,-1}, {1, 1,-1}, {1,-1,-1} - }}; - std::array background_vertices = { - { - {-1, 1, 0}, {1, 1, 0}, {-1, -1, 0}, - {1, 1, 0}, {1, -1, 0}, {-1, -1, 0} - }}; - GLfloat background_colors[40][3] = { - {.2, .6, .8}, {.2, .6, .8}, {1, 1, 0}, - {.2, .6, .8}, {1, 1, 0}, {1, 1, 0} - }; - GLuint background_colors_buffer; - glGenBuffers(1, &background_colors_buffer); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - std::vector vertices; - vertices.reserve(cube.size() + background_vertices.size()); - vertices.insert(vertices.begin(), cube.begin(), cube.end()); - vertices.insert(vertices.end(), background_vertices.begin(), background_vertices.end()); - glm::ivec2 resolution = get_display().window_size(); - projection = glm::perspective( - glm::radians(45.0f), resolution.x / (float) resolution.y, 0.1f, - 100.0f); - view = glm::lookAt( - glm::vec3(4, 3, 3), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)); - SDL_Surface* surface = zoomSurface( - rotateSurface90Degrees(IMG_Load("resource/tile.png"), 2), -1, 1, SMOOTHING_OFF); - SDL_Log("tile.png bytes per pixel %i", surface->format->BytesPerPixel); - space_texture_id = get_gl_texture_from_surface(surface, GL_LINEAR, true); - SDL_FreeSurface(surface); - // std::vector paths = sb::glob("/home/frank/projects/public/games/buddi/local/face03/[0-9]+\\-.+\\.png"); - // for (fs::path path : paths) - // { - // surface = zoomSurface(rotateSurface90Degrees(IMG_Load(path.c_str()), 2), -1, 1, SMOOTHING_OFF); - // SDL_Log("loading %s", path.c_str()); - // face_ids.push_back(get_gl_texture_from_surface(surface, GL_LINEAR)); - // SDL_FreeSurface(surface); - // } - std::array cube_uv = { - { - {1, 1}, {0, 1}, {0, 0}, - {0, 0}, {1, 0}, {1, 1}, - {0, 1}, {0, 0}, {1, 0}, - {1, 0}, {1, 1}, {0, 1}, - {0, 1}, {0, 0}, {1, 0}, - {1, 0}, {1, 1}, {0, 1}, - {1, 1}, {0, 1}, {0, 0}, - {0, 0}, {1, 0}, {1, 1}, - {0, 0}, {1, 0}, {1, 1}, - {1, 1}, {0, 1}, {0, 0}, - {0, 0}, {1, 0}, {1, 1}, - {1, 1}, {0, 1}, {0, 0} - }}; - std::vector uv; - uv.reserve(cube_uv.size() + background_vertices.size()); - std::copy(cube_uv.begin(), cube_uv.end(), uv.begin()); - GLuint uvbuffer; - glGenBuffers(1, &uvbuffer); - unsigned char fake_texture_color[4] = {255, 255, 255, 255}; - glCreateTextures(GL_TEXTURE_2D, 1, &fake_texture_id); - glBindTexture(GL_TEXTURE_2D, fake_texture_id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, - fake_texture_color); - GLuint vao; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat) * 3, &vertices.front(), - GL_STATIC_DRAW); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, uvbuffer); - glBufferData(GL_ARRAY_BUFFER, uv.capacity() * sizeof(GLfloat) * 2, &uv.front(), GL_STATIC_DRAW); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, background_colors_buffer); - glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat) * 3, 0, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, - (cube.size()) * sizeof(GLfloat) * 3, - background_vertices.size() * sizeof(GLfloat) * 3, background_colors); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(2); - GLuint vertex_shader = load_shader("shaders/triangle.vert", GL_VERTEX_SHADER); - GLuint fragment_shader = load_shader("shaders/triangle.frag", GL_FRAGMENT_SHADER); - GLuint flat_shader = load_shader("shaders/flat.vert", GL_VERTEX_SHADER); - world_program = glCreateProgram(); - glAttachShader(world_program, vertex_shader); - glAttachShader(world_program, fragment_shader); - glBindAttribLocation(world_program, 0, "in_Position"); - glBindAttribLocation(world_program, 1, "vertexUV"); - glBindAttribLocation(world_program, 2, "in_Color"); - glBindAttribLocation(world_program, 3, "pos"); - link_shader(world_program); - flat_program = glCreateProgram(); - glAttachShader(flat_program, flat_shader); - glAttachShader(flat_program, fragment_shader); - glBindAttribLocation(flat_program, 0, "in_Position"); - glBindAttribLocation(flat_program, 1, "vertexUV"); - glBindAttribLocation(flat_program, 2, "in_Color"); - glBindAttribLocation(flat_program, 3, "pos"); - link_shader(flat_program); - mvp_id = glGetUniformLocation(world_program, "MVP"); - // GLuint sampler_uniform_id = glGetUniformLocation(world_program, "myTextureSampler"); - // glActiveTexture(GL_TEXTURE0); - // glBindTexture(GL_TEXTURE_2D, space_texture_id); - // glUniform1i(sampler_uniform_id, 0); - glDepthFunc(GL_LESS); -} - -void Cube::respond(SDL_Event& event) -{ - if (delegate.compare(event, "context")) - { - if (is_gl_context) - { - load_sdl_context(); - } - else - { - load_gl_context(); - } - } - else if (delegate.compare(event, "play-sound")) - { - Mix_Chunk* music = Mix_LoadWAV("resource/Ag.ogg"); - Mix_PlayChannel(-1, music, 0); - } - else if (delegate.compare(event, "fullscreen")) - { - if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) - { - SDL_SetWindowFullscreen(window, 0); - } - else - { - SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN); - } - } -} - -void Cube::update() -{ - // while (SDL_PollEvent(&event)) - // { - // if (event.type == SDL_KEYDOWN) - // { - // if (SDL_GetModState() & KMOD_CTRL) - // { - // if (event.key.keysym.sym == SDLK_f) - // { - // show_framerate = not show_framerate; - // } - // else if (event.key.keysym.sym == SDLK_UP) - // { - // set_framerate(framerate + 1); - // } - // else if (event.key.keysym.sym == SDLK_DOWN) - // { - // set_framerate(framerate - 1); - // } - // } - // else if (event.key.keysym.sym == SDLK_UP) - // { - // up_active = true; - // } - // else if (event.key.keysym.sym == SDLK_RIGHT) - // { - // right_active = true; - // } - // else if (event.key.keysym.sym == SDLK_DOWN) - // { - // down_active = true; - // } - // else if (event.key.keysym.sym == SDLK_LEFT) - // { - // left_active = true; - // } - // } - // else if (event.type == SDL_KEYUP) - // { - // if (event.key.keysym.sym == SDLK_UP) - // { - // up_active = false; - // } - // else if (event.key.keysym.sym == SDLK_RIGHT) - // { - // right_active = false; - // } - // else if (event.key.keysym.sym == SDLK_DOWN) - // { - // down_active = false; - // } - // else if (event.key.keysym.sym == SDLK_LEFT) - // { - // left_active = false; - // } - // } - // } - if (is_gl_context) - { - // glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); - // glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), diamond, GL_STATIC_DRAW); - // glColorMask(false, false, false, true); - // glClearColor(.7, .7, .5, 1); - glClearColor(0, 0, 0, 1); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glDisable(GL_DEPTH_TEST); - glUseProgram(flat_program); - glUniform1f(glGetUniformLocation(flat_program, "r"), mvp[0][0]); - glBindTexture(GL_TEXTURE_2D, fake_texture_id); - glDisableVertexAttribArray(1); - glEnableVertexAttribArray(2); - glDrawArrays(GL_TRIANGLES, 36, 6); - float rotation = .0005f * get_frame_length(); - model = glm::rotate(model, rotation, glm::vec3(0.0f, 1.0f, 0.0f)); - mvp = projection * view * model; - glEnable(GL_DEPTH_TEST); - glUseProgram(world_program); - glUniformMatrix4fv(mvp_id, 1, GL_FALSE, &mvp[0][0]); - glEnableVertexAttribArray(1); - glDisableVertexAttribArray(2); - glVertexAttrib3f(2, 1, 1, 1); - // for (int ii = 0; ii < 6; ii++) - // { - // glBindTexture(GL_TEXTURE_2D, face_ids[ii]); - // glDrawArrays(GL_TRIANGLES, ii * 6, 6); - // } - glBindTexture(GL_TEXTURE_2D, space_texture_id); - glDrawArrays(GL_TRIANGLES, 0, 36); - //glFlush(); - SDL_GL_SwapWindow(window); - // if (amount_rotated < 3.14f * 2) - // { - // recorder.capture_screen(); - // } - amount_rotated += rotation; - } - else - { - SDL_SetRenderDrawColor(renderer, 0x0f, 0x4f, 0x8f, 0xff); - SDL_RenderClear(renderer); - roundedBoxColor(renderer, 300, 200, 500, 300, 10, 0x8f8fdfff); - aacircleColor(renderer, 300, 200, 30, 0xffef3fff); - int speed = 2; - if (up_active) - { - grass.move_weighted({0, -speed}); - } - if (right_active) - { - grass.move_weighted({speed, 0}); - } - if (down_active) - { - grass.move_weighted({0, speed}); - } - if (left_active) - { - grass.move_weighted({-speed, 0}); - } - grass.update(); - mushroom.update(); - } -} - -int main() -{ - Cube cube = Cube(); - cube.run(); - cube.quit(); - return 0; -} diff --git a/demo/cube/Cube.hpp b/demo/cube/Cube.hpp deleted file mode 100644 index 292fe5f..0000000 --- a/demo/cube/Cube.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "sdl2-gfx/SDL2_gfxPrimitives.h" -#include "sdl2-gfx/SDL2_rotozoom.h" - -#define GLM_ENABLE_EXPERIMENTAL -#include "glm/gtx/string_cast.hpp" -#include "glm/gtx/transform.hpp" -#include "glm/gtc/matrix_transform.hpp" - -#include "filesystem.hpp" -#include "Node.hpp" -#include "Game.hpp" -#include "Box.hpp" -#include "Sprite.hpp" -#include "Input.hpp" -#include "Delegate.hpp" -#include "extension.hpp" - -struct Mushroom : Sprite -{ - - int direction = 1; - - Mushroom(Node*); - void update(); - virtual std::string class_name() const { return "Mushroom"; } - -}; - -struct Cube : Game -{ - - SDL_Texture *grass_texture; - int frame_count = 0, frame_count_timestamp; - bool right_active = false, down_active = false, left_active = false, - up_active = false, is_writing_audio = true; - SDL_Event event; - GLuint vbo, space_texture_id, mvp_id, framerate_texture_id, flat_program, - world_program, fake_texture_id; - glm::mat4 projection, view, model = glm::mat4(1.0f), mvp; - Mushroom mushroom = Mushroom(this); - Sprite grass = Sprite(this, "resource/Field.png"); - std::vector face_ids; - float amount_rotated; - - Cube(); - void load_sdl_context(); - void load_gl_context(); - void respond(SDL_Event&); - void update(); - virtual std::string class_name() const { return "Demo"; } - -}; diff --git a/demo/cube/Makefile b/demo/cube/Makefile deleted file mode 100644 index 34c289c..0000000 --- a/demo/cube/Makefile +++ /dev/null @@ -1,175 +0,0 @@ -# /\ +--------------------------------------------------------------+ -# ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | -# \ / / | copy, modify and sell without restriction | -# +--\ ^__^ /--+ | | -# | ~/ \~ | | - originally created at [http://nugget.fun] | -# | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ -# | SPACE ~~~~~ | / -# | ~~~~~~~ BOX |/ -# +--------------+ -# -# [ Makefile for cube demo ] -# -# This should build the cube demo for Linux. Other platforms haven't been tested in -# a while and won't work without significant editing. -# -# Edit the parameters as necessary and run `make linux` in the current directory. -# - -####################### -# Location parameters # -####################### - -# Location of source files for the demo -SRC_DIR := ./ - -# 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 := ../../ -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_LINUX := clang -CPPC_LINUX := clang++ - -# Location of SDL config program -SDLCONFIG := ~/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 # -############################# - -CFLAGS := -Wall -O0 -c -I$(SB_LIB_DIR) -I$(SB_SRC_DIR) -g $(shell $(SDLCONFIG) --cflags) -CPP_FLAGS := $(CFLAGS) --std=c++17 -LFLAGS := $(shell $(SDLCONFIG) --libs) -lpthread -SFW_H_FILES := $(wildcard $(addprefix $(SB_SRC_DIR),*.hpp)) -SFW_O_FILES := $(filter-out $(addprefix $(SB_SRC_DIR),filesystem.o),$(SFW_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 demo source # -################################################################## - -$(SDLGFX2_DIR)%.o: $(SDLGFX2_DIR)%.c $(SDLGFX2_DIR)%.h -$(GLEW_DIR)%.o: $(GLEW_DIR)%.c $(GLEW_DIR)%.h - $(CC_LINUX) $(CFLAGS) $< -c -o $@ - -$(SB_SRC_DIR)extension.o : $(addprefix $(SB_SRC_DIR),Box.hpp Segment.hpp Color.hpp filesystem.hpp Pixels.hpp) -$(SB_SRC_DIR)Node.o : $(addprefix $(SB_SRC_DIR),Game.hpp Configuration.hpp Delegate.hpp Display.hpp Input.hpp Box.hpp Audio.hpp) -$(SB_SRC_DIR)Sprite.o : $(addprefix $(SB_SRC_DIR),Node.hpp Game.hpp Box.hpp Animation.hpp Color.hpp extension.hpp Pixels.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) -$(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) -$(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) -$(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) -$(SB_SRC_DIR)Audio.o : $(addprefix $(SB_SRC_DIR),Node.hpp Display.hpp Configuration.hpp Box.hpp filesystem.hpp extension.hpp) -$(SRC_DIR)Cube.o : $(SFW_H_FILES) -%.o : %.cpp %.hpp - $(CPPC_LINUX) $(CPP_FLAGS) $< -c -o $@ - -########################## -# Target for Linux build # -########################## - -linux : $(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) \ - $(SRC_O_FILES) $(SFW_O_FILES) - $(CREATE_FONT_SYMLINK) - $(CPPC_LINUX) $(LFLAGS) -D__LINUX__ $^ -lGL -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lstdc++fs -o cube - -####################################### -# Target for cleaning up object files # -####################################### - -clean : - - rm *.o - - rm $(SB_SRC_DIR)*.o - - rm $(GLEW_DIR)*.o - - rm $(SDLGFX2_DIR)*.o - -# -# These assignments are necessary for cross-compiling to Android, web (via emscripten), Windows (via mingw), -# and OS/X. Cross-compilation targets have not been tested in a while and won't compile without significant changes. -# - -export ANDROID_HOME = /home/frank/ext/software/android-sdk -export ANDROID_NDK_HOME = /home/frank/ext/software/android-ndk-r8d -BUILDDIR := build -ANDROIDPROJECT := com.nuggetsselect.demo -SOFTWARE_ROOT := /home/frank/ext/software -SDLHOME := $(SOFTWARE_ROOT)/SDL2-2.0.14 -SDL_IMG_HOME := $(SOFTWARE_ROOT)/SDL2_image-2.0.5 -SDL_TTF_HOME := $(SOFTWARE_ROOT)/SDL2_ttf-2.0.15 -GLEW_WIN32_HOME := $(SOFTWARE_ROOT)/glew-2.1.0-win32 -PROJECTHOME := $(shell pwd) -EMSCRIPTENHOME := /home/frank/ext/software/emsdk/emscripten/tag-1.38.12 -SDLEMLIBSHOME := $(SDLHOME)/build/em/build/.libs -EMBUILDDIR := em -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 - -emscripten : - if [ ! -d $(BUILDDIR)/$(EMBUILDDIR) ]; then mkdir -p $(BUILDDIR)/$(EMBUILDDIR); fi; - cd $(BUILDDIR)/$(EMBUILDDIR) && \ - $(EMSCRIPTENHOME)/em++ -O2 $(PROJECTHOME)/main.cpp -I$(SDLHOME)/include \ - -Wall -s USE_SDL=2 -o main.html - -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/demo/cube/resource/Field.png b/demo/cube/resource/Field.png deleted file mode 100644 index d5e74b2..0000000 Binary files a/demo/cube/resource/Field.png and /dev/null differ diff --git a/demo/cube/resource/background.png b/demo/cube/resource/background.png deleted file mode 100644 index e97dbea..0000000 Binary files a/demo/cube/resource/background.png and /dev/null differ diff --git a/demo/cube/resource/shrooms/anxiety.png b/demo/cube/resource/shrooms/anxiety.png deleted file mode 100644 index d8907e6..0000000 Binary files a/demo/cube/resource/shrooms/anxiety.png and /dev/null differ diff --git a/demo/cube/resource/shrooms/lapis-lazuli.png b/demo/cube/resource/shrooms/lapis-lazuli.png deleted file mode 100644 index 3340328..0000000 Binary files a/demo/cube/resource/shrooms/lapis-lazuli.png and /dev/null differ diff --git a/demo/cube/resource/shrooms/mr-plummy.png b/demo/cube/resource/shrooms/mr-plummy.png deleted file mode 100644 index 1977ce7..0000000 Binary files a/demo/cube/resource/shrooms/mr-plummy.png and /dev/null differ diff --git a/demo/cube/resource/shrooms/poison-shibake.png b/demo/cube/resource/shrooms/poison-shibake.png deleted file mode 100644 index 11dffc3..0000000 Binary files a/demo/cube/resource/shrooms/poison-shibake.png and /dev/null differ diff --git a/demo/cube/resource/shrooms/shaver-buzz.png b/demo/cube/resource/shrooms/shaver-buzz.png deleted file mode 100644 index 9d52884..0000000 Binary files a/demo/cube/resource/shrooms/shaver-buzz.png and /dev/null differ diff --git a/demo/cube/resource/shrooms/sombrero.png b/demo/cube/resource/shrooms/sombrero.png deleted file mode 100644 index 0e57bc0..0000000 Binary files a/demo/cube/resource/shrooms/sombrero.png and /dev/null differ diff --git a/demo/cube/resource/shrooms/spider-house.png b/demo/cube/resource/shrooms/spider-house.png deleted file mode 100644 index 3176dd5..0000000 Binary files a/demo/cube/resource/shrooms/spider-house.png and /dev/null differ diff --git a/demo/cube/resource/shrooms/teethmouth.png b/demo/cube/resource/shrooms/teethmouth.png deleted file mode 100644 index 4a7b1c4..0000000 Binary files a/demo/cube/resource/shrooms/teethmouth.png and /dev/null differ diff --git a/demo/cube/resource/shrooms/terraformer.png b/demo/cube/resource/shrooms/terraformer.png deleted file mode 100644 index 0d66af4..0000000 Binary files a/demo/cube/resource/shrooms/terraformer.png and /dev/null differ diff --git a/demo/cube/resource/tile.png b/demo/cube/resource/tile.png deleted file mode 100644 index ac71631..0000000 Binary files a/demo/cube/resource/tile.png and /dev/null differ diff --git a/demo/cube/shaders/flat.frag b/demo/cube/shaders/flat.frag deleted file mode 100644 index 61ec63d..0000000 --- a/demo/cube/shaders/flat.frag +++ /dev/null @@ -1,10 +0,0 @@ -#version 130 - -in vec4 ex_Color; -in vec2 UV; -uniform sampler2D myTextureSampler; - -void main(void) -{ - gl_FragColor = texture(myTextureSampler, UV) * ex_Color; -} diff --git a/demo/cube/shaders/flat.vert b/demo/cube/shaders/flat.vert deleted file mode 100644 index 7ebb009..0000000 --- a/demo/cube/shaders/flat.vert +++ /dev/null @@ -1,15 +0,0 @@ -#version 130 - -in vec3 in_Position; -in vec2 vertexUV; -in vec3 in_Color; - -out vec2 UV; -out vec4 ex_Color; - -void main(void) -{ - gl_Position = vec4(in_Position, 1); - UV = vertexUV; - ex_Color = vec4(in_Color, 1); -} diff --git a/demo/cube/shaders/triangle.frag b/demo/cube/shaders/triangle.frag deleted file mode 100644 index 61ec63d..0000000 --- a/demo/cube/shaders/triangle.frag +++ /dev/null @@ -1,10 +0,0 @@ -#version 130 - -in vec4 ex_Color; -in vec2 UV; -uniform sampler2D myTextureSampler; - -void main(void) -{ - gl_FragColor = texture(myTextureSampler, UV) * ex_Color; -} diff --git a/demo/cube/shaders/triangle.vert b/demo/cube/shaders/triangle.vert deleted file mode 100644 index 0e4da5a..0000000 --- a/demo/cube/shaders/triangle.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 130 - -in vec3 in_Position; -in vec3 in_Color; -in vec2 vertexUV; - -out vec4 ex_Color; -out vec2 UV; - -uniform mat4 MVP; - -void main(void) -{ - gl_Position = MVP * vec4(in_Position, 1); - ex_Color = vec4(in_Color, 1); - UV = vertexUV; -} diff --git a/demo/fill_screen/Makefile b/demo/fill_screen/Makefile index 781b96b..add1328 100644 --- a/demo/fill_screen/Makefile +++ b/demo/fill_screen/Makefile @@ -57,8 +57,7 @@ $(GLEW_DIR)%.o: $(GLEW_DIR)%.c $(GLEW_DIR)%.h $(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)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) @@ -137,7 +136,7 @@ $(ANDROID_BUILD_DIR)/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: $(SB_SR # Run gradle and generate an APK -$(ANDROID_BUILD_DIR)/app-debug.apk: $(ANDROID_BUILD_DIR) $(ANDROID_BUILD_DIR)/$(ANDROID_MK) $(ANDROID_BUILD_DIR)/$(ANDROID_CLASS_DIR)/$(ANDROID_CLASS).java \ +$(ANDROID_BUILD_DIR)/app-debug.apk: $(ANDROID_BUILD_DIR) $(ANDROID_BUILD_DIR)/$(ANDROID_CLASS_DIR)/$(ANDROID_CLASS).java \ $(ANDROID_BUILD_DIR)/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml ANDROID_SDK_ROOT=$(ANDROID_SDK) $(ANDROID_BUILD_DIR)/gradlew -p $(ANDROID_BUILD_DIR) build ln -nsf app/build/outputs/apk/debug/app-debug.apk $(ANDROID_BUILD_DIR) diff --git a/demo/fill_screen/fill_screen.cpp b/demo/fill_screen/fill_screen.cpp index ceea70d..224bd1e 100644 --- a/demo/fill_screen/fill_screen.cpp +++ b/demo/fill_screen/fill_screen.cpp @@ -1,4 +1,14 @@ -/* +/*!
+ *        /\         +------------------------------------------------------+ 
+ *   ____/  \____   /| - Open source game framework licensed to freely use, |
+ *   \          /  / |   copy, modify and sell without restriction          |
+ * +--\ ^__^   /--+  |                                                      |
+ * | ~/        \~ |  | - created for              |
+ * | ~~~~~~~~~~~~ |  +------------------------------------------------------+
+ * | SPACE ~~~~~  | /
+ * |  ~~~~~~~ BOX |/
+ * +--------------+                                                    
+ * * Fill screen example by frank at shampoo.ooo * * This is an example program that fills the screen with a color every frame. It is a minimal example of a SPACEBOX program @@ -28,16 +38,6 @@ public: }; -// #if defined(__ANDROID__) || defined(ANDROID) -// int SDL_main() -// { -// FillScreen fill_screen = FillScreen(); -// fill_screen.load_gl_context(); -// fill_screen.run(); -// fill_screen.quit(); -// return 0; -// } -// #else /* Create a game object, load its GL context, and run the game. */ int main(int argc, char* argv[]) { @@ -47,4 +47,3 @@ int main(int argc, char* argv[]) fill_screen.quit(); return 0; } -// #endif diff --git a/icon/static_alt.png b/icon/static_alt.png new file mode 100644 index 0000000..ed8c758 Binary files /dev/null and b/icon/static_alt.png differ diff --git a/icon/static_solid.png b/icon/static_solid.png new file mode 100644 index 0000000..7045800 Binary files /dev/null and b/icon/static_solid.png differ diff --git a/src/Attributes.cpp b/src/Attributes.cpp index d4c4e76..35f402b 100644 --- a/src/Attributes.cpp +++ b/src/Attributes.cpp @@ -1,12 +1,13 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, modify and sell without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +-------------*/ +/*!
+ *        /\         +------------------------------------------------------+ 
+ *   ____/  \____   /| - Open source game framework licensed to freely use, |
+ *   \          /  / |   copy, modify and sell without restriction          |
+ * +--\ ^__^   /--+  |                                                      |
+ * | ~/        \~ |  | - created for              |
+ * | ~~~~~~~~~~~~ |  +------------------------------------------------------+
+ * | SPACE ~~~~~  | /
+ * |  ~~~~~~~ BOX |/
+ * +--------------+                                                  
*/ #include "Attributes.hpp" diff --git a/src/Attributes.hpp b/src/Attributes.hpp index f9be5b0..b9e4d37 100644 --- a/src/Attributes.hpp +++ b/src/Attributes.hpp @@ -1,88 +1,88 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, modify and sell without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +--------------+ - - [Attributes.hpp] - - An Attributes object is a container that acts as a limited, but dynamically typed vector for - vertex properties to be passed to a GL buffer object and described by a vertex array object. - It uses the variant library and type inference to determine the vertex type for an object. The - appropriate variant will be applied based on the first vertices submitted to the object. - - The object can contain float, int, or unsigned int vertices of any dimension from 1D to 4D. It - can also contain bool vertices from 2D to 4D. Vertices can be submitted at initialization through - the constructor or added and appended later using the add function. If the object is initialized - without any vertices, it will be in an empty state indicated by the std::monostate variant - alternative. - - The constructor accepts initializer lists, so unknown types can be submitted as long as a single type - can be inferred. For example, - - Attributes({1.0f, 0.5f, -1.0f}); // glm::vec3 attributes containing one vertex - Attributes({ // glm::vec3 attributes containing two vertices - {1.0f, 0.5f, -1.0f}, - {0.0f, 1.0f, 1.0f} - }); - Attributes({1, 2}); // glm::ivec2 attributes containing one vertex - Attributes(glm::uvec2{1, 2}); // glm::uvec2 attributes containing one vertex - Attributes(1, 2); // same as Attributes({1, 2}), each argument is treated as a - // coordinate - Attributes({ // inferred as glm::uvec3, so the -5, -555, and the - {-5, 55, -555}, // decimal precision are lost - glm::uvec3{8, 88, 888}, - {9.9, 9.99, 9.999} - }); - - The add function also accepts initializer lists and any type that can be converted into the original. - - sb::Attributes attr, attr2, attr3, attr4; - attr.add(420); - attr.add({69, 9000}); - attr.add({}); - attr.add({{1}}); - std::cout << attr << std::endl; - attr2.add(glm::ivec4{1, 1, 2, 3}); - attr2.add({{5.0f, 8.0f, 13.0f, 21.0f}, {34.0f, 55.0f, 89.0f, 144.0f}}); - attr2.add({glm::uvec4{5, 8, 13, 21}, glm::uvec4{34, 55, 89, 144}}); - attr2.add({0.0f, 0.0f, 0.0f, 0.0f}); - std::cout << attr2 << std::endl; - attr3.add(1.1f); - attr3.add(2); - attr3.add(std::vector{3, 4}); - std::cout << attr3 << std::endl; - attr3 = attr2; - attr2 = attr4; - std::cout << attr3 << std::endl; - std::cout << attr2 << std::endl; - attr4 = sb::Attributes({{-5, 55, -555}, glm::ivec3{8, 88, 888}, {9.99, 9.9, 9.0}}); - attr4.add(1000, 10000, 100000); - attr4.add(1, 11); - std::cout << attr4 << std::endl; - attr2 = sb::Attributes(std::vector{5.5, 6.6, 7.7, 8.8}); - attr2.add(glm::vec2{9.9f, 10.10f}); - std::cout << attr2 << std::endl; - - This prints - - warning: was not added to the attributes because its type is incompatible - { 420 69 9000 1 } - warning: { 0 0 0 0 } was not added to the attributes because its type is incompatible - { {1, 1, 2, 3} {5, 8, 13, 21} {34, 55, 89, 144} {5, 8, 13, 21} {34, 55, 89, 144} } - { 1.1 2 3 4 } - { {1, 1, 2, 3} {5, 8, 13, 21} {34, 55, 89, 144} {5, 8, 13, 21} {34, 55, 89, 144} } - - warning: { {1, 11} } was not added to the attributes because its type is incompatible - { {-5, 55, -555} {8, 88, 888} {9, 9, 9} {1000, 10000, 100000} } - warning: { {9.9, 10.1} } was not added to the attributes because its type is incompatible - { 5.5 6.6 7.7 8.8 } - -*/ +/*!
+ *        /\         +------------------------------------------------------+
+ *   ____/  \____   /| - Open source game framework licensed to freely use, |
+ *   \          /  / |   copy, modify and sell without restriction          |
+ * +--\ ^__^   /--+  |                                                      |
+ * | ~/        \~ |  | - created for              |
+ * | ~~~~~~~~~~~~ |  +------------------------------------------------------+
+ * | SPACE ~~~~~  | /
+ * |  ~~~~~~~ BOX |/
+ * +--------------+   
+ * + * Attributes + * ========== + * + * An Attributes object is a container that acts as a limited, but dynamically typed vector for + * vertex properties to be passed to a GL buffer object and described by a vertex array object. + * It uses the variant library and type inference to determine the vertex type for an object. The + * appropriate variant will be applied based on the first vertices submitted to the object. + * + * The object can contain float, int, or unsigned int vertices of any dimension from 1D to 4D. It + * can also contain bool vertices from 2D to 4D. Vertices can be submitted at initialization through + * the constructor or added and appended later using the add function. If the object is initialized + * without any vertices, it will be in an empty state indicated by the std::monostate variant + * alternative. + * + * The constructor accepts initializer lists, so unknown types can be submitted as long as a single type + * can be inferred. For example, + * + * Attributes({1.0f, 0.5f, -1.0f}); // glm::vec3 attributes containing one vertex + * Attributes({ // glm::vec3 attributes containing two vertices + * {1.0f, 0.5f, -1.0f}, + * {0.0f, 1.0f, 1.0f} + * }); + * Attributes({1, 2}); // glm::ivec2 attributes containing one vertex + * Attributes(glm::uvec2{1, 2}); // glm::uvec2 attributes containing one vertex + * Attributes(1, 2); // same as Attributes({1, 2}), each argument is treated as a coordinate + * Attributes({ // inferred as glm::uvec3, so the -5, -555, and the decimal precision are lost + * {-5, 55, -555}, + * glm::uvec3{8, 88, 888}, + * {9.9, 9.99, 9.999} + * }); + * + * The add function also accepts initializer lists and any type that can be converted into the original. + * + * sb::Attributes attr, attr2, attr3, attr4; + * attr.add(420); + * attr.add({69, 9000}); + * attr.add({}); + * attr.add({{1}}); + * std::cout << attr << std::endl; + * attr2.add(glm::ivec4{1, 1, 2, 3}); + * attr2.add({{5.0f, 8.0f, 13.0f, 21.0f}, {34.0f, 55.0f, 89.0f, 144.0f}}); + * attr2.add({glm::uvec4{5, 8, 13, 21}, glm::uvec4{34, 55, 89, 144}}); + * attr2.add({0.0f, 0.0f, 0.0f, 0.0f}); + * std::cout << attr2 << std::endl; + * attr3.add(1.1f); + * attr3.add(2); + * attr3.add(std::vector{3, 4}); + * std::cout << attr3 << std::endl; + * attr3 = attr2; + * attr2 = attr4; + * std::cout << attr3 << std::endl; + * std::cout << attr2 << std::endl; + * attr4 = sb::Attributes({{-5, 55, -555}, glm::ivec3{8, 88, 888}, {9.99, 9.9, 9.0}}); + * attr4.add(1000, 10000, 100000); + * attr4.add(1, 11); + * std::cout << attr4 << std::endl; + * attr2 = sb::Attributes(std::vector{5.5, 6.6, 7.7, 8.8}); + * attr2.add(glm::vec2{9.9f, 10.10f}); + * std::cout << attr2 << std::endl; + * + * This prints + * + * warning: was not added to the attributes because its type is incompatible + * { 420 69 9000 1 } + * warning: { 0 0 0 0 } was not added to the attributes because its type is incompatible + * { {1, 1, 2, 3} {5, 8, 13, 21} {34, 55, 89, 144} {5, 8, 13, 21} {34, 55, 89, 144} } + * { 1.1 2 3 4 } + * { {1, 1, 2, 3} {5, 8, 13, 21} {34, 55, 89, 144} {5, 8, 13, 21} {34, 55, 89, 144} } + * + * warning: { {1, 11} } was not added to the attributes because its type is incompatible + * { {-5, 55, -555} {8, 88, 888} {9, 9, 9} {1000, 10000, 100000} } + * warning: { {9.9, 10.1} } was not added to the attributes because its type is incompatible + * { 5.5 6.6 7.7 8.8 } + */ #ifndef SB_ATTRIBUTES_H_ #define SB_ATTRIBUTES_H_ @@ -135,11 +135,15 @@ namespace sb public: - /* The default constructor creates an empty set of attributes. An empty set of attributes is indicated by - * the class's vertex variant having the std::monostate variant. */ + /*! + * The default constructor creates an empty set of attributes. An empty set of attributes is indicated by + * the class's vertex variant having the std::monostate variant. + */ Attributes() {}; - /* Construct a new Attributes object with vertices set to the vertices contained in this vector */ + /*! + * Construct a new Attributes object with vertices set to the vertices contained in this vector + */ template Attributes(const std::vector& vertices) : vertices(vertices) { @@ -153,26 +157,34 @@ namespace sb sb::Log::log(message, sb::Log::DEBUG); } - /* Add a vertex. The vertex can be any of the variant types. */ + /*! + * Add a vertex. The vertex can be any of the variant types. + */ template Attributes(const Type& vertex) : Attributes({vertex}) {} - /* Add a vertex by specifying each coordinate as a separate argument. All arguments must have idential type. */ + /*! + * Add a vertex by specifying each coordinate as a separate argument. All arguments must have idential type. + */ template), std::nullptr_t> = nullptr> Attributes(const XType& coordinate_0, const CoordinateTypes&... coordinates) : Attributes({std::initializer_list({coordinate_0, coordinates ...})}) {} - /* Add vertices by passing an uninitialized list of vertices. This template applies to a list of + /*! + * Add vertices by passing an uninitialized list of vertices. This template applies to a list of * vertices where the list type is undeclared but the containing vertices have been initialized - * or the type can be inferred because the vertices are 1D scalars */ + * or the type can be inferred because the vertices are 1D scalars. + */ template Attributes(const std::initializer_list& vertices) : Attributes(std::vector(vertices.begin(), vertices.end())) {} - /* Add vertices by passing a two-dimensional initializer list, a list of uninitialized vertices. + /*! + * Add vertices by passing a two-dimensional initializer list, a list of uninitialized vertices. * The appropriate glm vertex size is applied by looking at the length of the first uninitialized - * vertex in the initializer list. */ + * vertex in the initializer list. + */ template Attributes(const std::initializer_list>& vertices) { @@ -200,8 +212,15 @@ namespace sb void add(const Attributes&); - /* Add a 2D, 3D or 4D vertex by specifying each coordinate as a separate argument. All arguments must have - * identical type. */ + /*! + * Add a 2D, 3D or 4D vertex by specifying each coordinate as a separate argument. All arguments must have + * identical type. + * + * @param coordinate_0 x-coordinate + * @param coordinate_1 y-coordinate + * @param coordinate_2 z-coordinate (optional) + * @param coordinate_3 w-coordinate (optional) + */ template && (... && std::is_same_v), std::nullptr_t> = nullptr> @@ -213,23 +232,38 @@ namespace sb add({std::initializer_list({coordinate_0, coordinate_1, coordinates ...})}); } - /* Return a const reference to the vertex at the specified index in the attributes vector. */ + /*! + * Return a const reference to the vertex at the specified index in the attributes vector. + * + * @param index vertex index + * @return std::vector of type VertexType + */ template const VertexType& read(std::size_t index) const { return std::get>(vertices)[index]; } - /* 2D lookup of a value in the attributes. Return a const reference to the coordinate value at inner index - * within a vertex at outer index in the attributes vector. */ + /*! + * 2D lookup of a value in the attributes. Return a const reference to the coordinate value at inner index + * within a vertex at outer index in the attributes vector. + * + * @param outer vertex index + * @param inner coordinate index within vertex + * @return value of type CoordinateType + */ template const CoordinateType& read(std::size_t outer, std::size_t inner) { return std::get>(vertices)[outer][inner]; } - /* Return the attributes as a reference to a typed vector. If the type is not the alternative in use by the - * attributes, std::bad_variant_access will be thrown. */ + /*! + * Return the attributes as a reference to a typed vector. If the type is not the alternative in use by the + * attributes, std::bad_variant_access will be thrown. + * + * @return std::vector of type VertexType + */ template operator const std::vector&() const { diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 1c439c1..279bd36 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -48,10 +48,9 @@ void Configuration::set_defaults() {"ignore-repeat-keypress", true} }; sys_config["display"] = { - // {"dimensions", {960, 540}}, - {"dimensions", {480, 800}}, + {"dimensions", {960, 540}}, {"framerate", 60}, - {"title", "[SPACE BOX]"}, + {"title", "[SPACEBOX]"}, {"debug", false}, {"show-cursor", false}, {"render-test-spacing", 2}, @@ -99,9 +98,10 @@ void Configuration::set_defaults() {"enabled", false}, {"debug-to-stdout", false}, {"debug-to-file", false}, - {"ouput-directory", "."}, + {"output-directory", "."}, {"info-file-name", "space_box_log.txt"}, - {"debug-file-name", "space_box_debug_log.txt"} + {"debug-file-name", "space_box_debug_log.txt"}, + {"short-name", "spacebox"} }; sys_config["configuration"] = { {"auto-refresh", false}, @@ -114,15 +114,10 @@ void Configuration::set_defaults() void Configuration::load(fs::path path) { /* read contents of path into the game level config JSON dict */ - if (fs::exists(path)) - { - std::ifstream contents(path); - contents >> user_config; - /* store modification time */ - config_file_modification_time = fs::last_write_time(path); - /* merge into the full config JSON dict */ - merge(); - } + user_config = nlohmann::json::parse(sb::file_to_string(path)); + + /* merge into the full config JSON dict */ + merge(); } /* Load the configuration file at Configuration::config_path */ @@ -135,7 +130,7 @@ void Configuration::load() * dict (loaded from disk by the load function) */ void Configuration::merge() { - if (not user_config.empty()) + if (!user_config.empty()) { /* loop over first level key/value pairs */ for (auto& item: user_config.items()) diff --git a/src/Configuration.hpp b/src/Configuration.hpp index bf305ba..53cf907 100644 --- a/src/Configuration.hpp +++ b/src/Configuration.hpp @@ -1,4 +1,4 @@ -/* /\ +--------------------------------------------------------------+ + /* +--------------------------------------------------------------+ ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | \ / / | copy, modify and sell without restriction | +--\ ^__^ /--+ | | @@ -19,6 +19,7 @@ #include "Node.hpp" #include "Animation.hpp" #include "Log.hpp" +#include "extension.hpp" class Configuration : public Node { @@ -70,8 +71,6 @@ namespace glm /* Extend std::filesystem so nlohmann::json can read and write std::filesystem::path */ #if defined(__MINGW32__) namespace std::experimental::filesystem -// #elif defined(__ANDROID__) || defined(ANDROID) -// namespace std::__fs::filesystem #else namespace std::filesystem #endif diff --git a/src/Game.cpp b/src/Game.cpp index 380f4a8..d299f47 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -1,3 +1,13 @@ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + #include "Game.hpp" Game::Game() @@ -14,21 +24,43 @@ Game::Game() default_log_category_priority = SDL_LOG_PRIORITY_INFO; } SDL_LogSetPriority(sb::Log::DEFAULT_CATEGORY, default_log_category_priority); - /* set custom log function that prints to stdout/stderr and to file if enabled */ + + /* Set custom log function that prints to stdout/stderr and to file if enabled */ SDL_LogSetOutputFunction(&Game::sdl_log_override, this); - /* pretty print config to debug log */ + + /* Log the current working directory as seen by std::filesystem */ std::ostringstream log_message; + log_message << "Current path is " << std::filesystem::current_path(); + sb::Log::log(log_message); + + /* Log Android storage paths as determined by SDL */ +#if defined(__ANDROID__) || defined(ANDROID) + log_message = std::ostringstream(); + log_message << "SDL_AndroidGetInternalStoragePath() is " << SDL_AndroidGetInternalStoragePath() << std::endl; + log_message << "SDL_AndroidGetExternalStorageState() is " << SDL_AndroidGetExternalStorageState() << std::endl; + log_message << "SDL_AndroidGetExternalStoragePath() is " << SDL_AndroidGetExternalStoragePath(); + sb::Log::log(log_message); +#endif + + /* Pretty print config JSON to debug log */ + log_message = std::ostringstream(); log_message << std::setw(4) << configuration() << std::endl; sb::Log::log(log_message, sb::Log::DEBUG); - /* tell SDL which render driver you will be requesting when calling SDL_CreateRenderer */ + + /* Tell SDL which render driver you will be requesting when calling SDL_CreateRenderer */ SDL_SetHint(SDL_HINT_RENDER_DRIVER, configuration()["display"]["render driver"].get().c_str()); - /* initialize the buffer of frame lengths which will be used to calculate FPS */ + + /* Initialize the buffer of frame lengths which will be used to calculate FPS */ frame_length_history.reserve(5000); set_framerate(configuration()["display"]["framerate"]); + + /* Subscribe to SDL's quit event */ delegate.subscribe(&Game::handle_quit_event, this, SDL_QUIT); + /* Needed for displaying fullscreen correctly on Linux (?) Also might need SDL_VIDEO_CENTERED (?) */ std::string fullscreen_env_assigment = "SDL_VIDEO_X11_LEGACY_FULLSCREEN=0"; putenv(const_cast(fullscreen_env_assigment.c_str())); + /* log compiled and linked SDL versions */ SDL_version version; log_message = std::ostringstream(); @@ -223,19 +255,29 @@ void Game::load_gl_context() log_display_mode(); } -/* Overrides SDL's default log function to log a message to stdout/stderr and, if log is enabled in the - * global configuration, to a file. Debug level statements may be suppressed, printed to stdout, or printed to - * both stdout and file, depending on the global configuration. */ void Game::sdl_log_override(void* userdata, int category, SDL_LogPriority priority, const char* message) { Game* game = static_cast(userdata); std::ostream& out = (priority > SDL_LOG_PRIORITY_WARN) ? std::cerr : std::cout; - /* print to stdout/stderr if priority is higher than debug or debug statements are enabled */ + + /* Print to stdout/stderr if priority is higher than debug or debug statements are enabled */ if (priority > SDL_LOG_PRIORITY_DEBUG || game->configuration()["log"]["debug-to-stdout"]) { out << message << std::endl; + + /* If printing to stdout, print to Android log as well */ +#if defined(__ANDROID__) || defined(ANDROID) + __android_log_print(ANDROID_LOG_VERBOSE, game->configuration()["log"]["short-name"].get_ref().c_str(), "%s", message); +#endif + } - /* handle writing to log file */ + + /* Create a date + time timestamp */ + std::ostringstream timestamp; + std::time_t now = std::time(nullptr); + timestamp << std::put_time(std::localtime(&now), "%F %T "); + + /* Handle writing to log file */ if (game->configuration()["log"]["enabled"]) { fs::path path = game->configuration()["log"]["output-directory"]; @@ -243,18 +285,20 @@ void Game::sdl_log_override(void* userdata, int category, SDL_LogPriority priori { fs::create_directories(path); } - /* prepend a timestamp to the message */ - std::time_t now = std::time(nullptr); + + /* Prepend timestamp to the message */ std::stringstream stamped_message; - stamped_message << std::put_time(std::localtime(&now), "%F %T ") << message; - /* if debug is enabled, append message to debug log file */ + stamped_message << timestamp.str() << message; + + /* If debug is enabled, append message to debug log file */ if (game->configuration()["log"]["debug-to-file"]) { fs::path debug_path = path / game->configuration()["log"]["debug-file-name"]; std::ofstream debug_stream(debug_path, std::ios_base::app); debug_stream << stamped_message.str() << std::endl; } - /* only append messages to the info log that are higher than debug priority */ + + /* Only append messages to the info log that are higher than debug priority */ if (priority > SDL_LOG_PRIORITY_DEBUG) { fs::path info_path = path / game->configuration()["log"]["info-file-name"]; @@ -277,10 +321,10 @@ void Game::print_frame_length_history() GLuint Game::load_shader(const fs::path& path, GLenum type) const { GLuint shader = glCreateShader(type); - std::fstream file = std::fstream(path); std::ostringstream message; std::string contents = sb::file_to_string(path); - glShaderSource(shader, 1, reinterpret_cast(&contents), 0); + const char *c_str = contents.c_str(); + glShaderSource(shader, 1, &c_str, 0); glCompileShader(shader); GLint is_compiled; glGetShaderiv(shader, GL_COMPILE_STATUS, &is_compiled); diff --git a/src/Game.hpp b/src/Game.hpp index 2166718..8fd486e 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -1,3 +1,13 @@ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + #pragma once #include @@ -26,6 +36,10 @@ #include "glew/glew.h" #endif +#if defined(__ANDROID__) || defined(ANDROID) +#include +#endif + #include "Node.hpp" #include "Input.hpp" #include "Display.hpp" @@ -60,7 +74,20 @@ private: Configuration _configuration {this}; SDL_Window* _window; - static void sdl_log_override(void*, int, SDL_LogPriority, const char*); + /*! + * Overrides SDL's default log function to log a message to stdout/stderr and, if log is enabled in the + * global configuration, to a file. Debug level statements may be suppressed, printed to stdout, or printed to + * both stdout and file, depending on the global configuration. This shouldn't be called directly. Use + * `sb::Log::log` instead. + * + * @see sb::Log::log(const std::string&) + * + * @param userdata must be a pointer to Game + * @param category SDL log category. It is not used by SPACEBOX, so it should be sb::Log::DEFAULT_CATEGORY + * @param priority SDL log priority, which is equivalent to the values in sb::Log::Level + * @param message message as a C-style string + */ + static void sdl_log_override(void* userdata, int category, SDL_LogPriority priority, const char* message); public: @@ -131,9 +158,14 @@ public: virtual std::string class_name() const { return "Game"; } ~Game(); - /* Applies delta timing to a value: returns the value as weighted by the amount of time passed since the + /*! + * Applies delta timing to a value: returns the value as weighted by the amount of time passed since the * last frame update, allowing for values to change the same amount over time independent of the frame rate. - * The amount is how much the value should change per second. */ + * The amount is how much the value should change per second. + * + * @param amount any scalar value to be weighted + * @return weighted value + */ template T weight(T amount) { diff --git a/src/Log.cpp b/src/Log.cpp index ae64d52..2067fd9 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -1,12 +1,12 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, modify and sell without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +-------------*/ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ #include "Log.hpp" diff --git a/src/Log.hpp b/src/Log.hpp index 770994c..0bedd4f 100644 --- a/src/Log.hpp +++ b/src/Log.hpp @@ -1,20 +1,21 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, modify and sell without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +--------------+ - - [Log.hpp] - - Log messages of specified priority through the SDL logging method, which is overridden in - the Game class to write to stdout, file, or both, depending on the user's configuration - settings. - -*/ +/*!
+ *        /\         +------------------------------------------------------+
+ *   ____/  \____   /| - Open source game framework licensed to freely use, |
+ *   \          /  / |   copy, modify and sell without restriction          |
+ * +--\ ^__^   /--+  |                                                      |
+ * | ~/        \~ |  | - created for              |
+ * | ~~~~~~~~~~~~ |  +------------------------------------------------------+
+ * | SPACE ~~~~~  | /
+ * |  ~~~~~~~ BOX |/
+ * +--------------+                                                    
+ * + * Log + * === + * + * Log messages of specified priority through the SDL logging method, which is overridden in + * the Game class to write to stdout, file, or both, depending on the user's configuration + * settings. + */ #ifndef SB_LOG_H_ #define SB_LOG_H_ diff --git a/src/Texture.cpp b/src/Texture.cpp index 1274ff2..11b0c1a 100644 --- a/src/Texture.cpp +++ b/src/Texture.cpp @@ -1,12 +1,12 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, modify and sell without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +-------------*/ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ #include "Texture.hpp" using namespace sb; diff --git a/src/Texture.hpp b/src/Texture.hpp index a43903c..82f6f74 100644 --- a/src/Texture.hpp +++ b/src/Texture.hpp @@ -1,23 +1,24 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, modify and sell without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +--------------+ - - [Texture.hpp] - - The Texture class abstracts the file opening, data loading and binding steps of Open GL - texture creation. Currently it only supports loading GL_TEXTURE_2D with GL_RGB8 pixels - and automatic GL_NEAREST mipmapping. Support may be added for users to pass in their own - pixel data, to customize mipmapping, and more. The class can also be used in a custom - way by passing the Texture ID to GL functions instead of using the class's member - functions. - -*/ +/*!
+ *        /\         +------------------------------------------------------+ 
+ *   ____/  \____   /| - Open source game framework licensed to freely use, |
+ *   \          /  / |   copy, modify and sell without restriction          |
+ * +--\ ^__^   /--+  |                                                      |
+ * | ~/        \~ |  | - created for              |
+ * | ~~~~~~~~~~~~ |  +------------------------------------------------------+
+ * | SPACE ~~~~~  | /
+ * |  ~~~~~~~ BOX |/
+ * +--------------+                                                    
+ * + * Texture + * ======= + * + * The Texture class abstracts the file opening, data loading and binding steps of Open GL + * texture creation. Currently it only supports loading GL_TEXTURE_2D with GL_RGB8 pixels + * and automatic GL_NEAREST mipmapping. Support may be added for users to pass in their own + * pixel data, to customize mipmapping, and more. The class can also be used in a custom + * way by passing the Texture ID to GL functions instead of using the class's member + * functions. + */ #ifndef SB_TEXTURE_H_ #define SB_TEXTURE_H_ @@ -104,7 +105,7 @@ namespace sb * * The texture must have been previously generated with a size to use this generic pixel data load function. The size is * determined with `glGetTexLevelParameter`, which is only available to OpenGL ES 3.1+, so this overload is not available - * for Emscripten builds. + * for Emscripten or Android builds. * * see OpenGL's `glTexSubImage2D` * @@ -117,7 +118,7 @@ namespace sb /*! * Return the size in pixels of mipmap level 0 (the only mipmap level supported by this class). If the texture hasn't been, * generated, return {0, 0}. `glGetTexLevelParameter` is only available in OpenGL ES 3.1+, so this function is removed from - * Emscripten builds. + * Emscripten and Android builds. * * @return glm::vec2 A vector consisting of {TEXTURE_MIPMAP_WIDTH, TEXTURE_MIPMAP_HEIGHT} */ diff --git a/src/android/revise_skeleton.sh b/src/android/revise_skeleton.sh index 1f5cbbf..550221d 100755 --- a/src/android/revise_skeleton.sh +++ b/src/android/revise_skeleton.sh @@ -21,11 +21,14 @@ ANDROID_CLASS=$6 ANDROID_APP_NAME=$7 ANDROID_MIN_TARGET=$8 ANDROID_NDK=$9 +SB_SRC="${10}" +SB_LIB_SRC="${11}" +SRC="${12}" sed -i "s/org.libsdl.app/$ANDROID_PACKAGE/" "$ANDROID_BUILD_DIR/app/build.gradle" "$ANDROID_BUILD_DIR/$ANDROID_MANIFEST" sed -i "s/^#.*\(APP_STL\)/\1/" "$ANDROID_BUILD_DIR/$ANDROID_APP_MK" echo "APP_CPPFLAGS := -std=c++17 -fexceptions -frtti" >> "$ANDROID_BUILD_DIR/$ANDROID_APP_MK" -sed -i -e 's/^LOCAL_LDLIBS.*/& -lGLESv3/' "$ANDROID_BUILD_DIR/$ANDROID_MK" +sed -i -e 's/^LOCAL_LDLIBS.*/& -lGLESv3 -llog/' "$ANDROID_BUILD_DIR/$ANDROID_MK" sed -i 's/0x0002/0x0003/' "$ANDROID_BUILD_DIR/$ANDROID_MANIFEST" sed -i "s/\(minSdkVersion\).*16/\1 $ANDROID_MIN_TARGET/" "$ANDROID_BUILD_DIR/app/build.gradle" "$ANDROID_BUILD_DIR/$ANDROID_APP_MK" sed -i "s/\(android\)-16/\1-$ANDROID_MIN_TARGET/" "$ANDROID_BUILD_DIR/app/build.gradle" "$ANDROID_BUILD_DIR/$ANDROID_APP_MK" @@ -33,9 +36,9 @@ sed -i "11i\ ndkVersion \"$ANDROID_NDK\"" "$ANDROID_BUILD_DIR/app/build.gradl sed -i 's/1536m/4096m/' "$ANDROID_BUILD_DIR/gradle.properties" sed -i "s/^#.*\(org.gradle.parallel\)/\1/" "$ANDROID_BUILD_DIR/gradle.properties" sed -i 's/^LOCAL_SHARED_LIBRARIES.*/& SDL2_image SDL2_mixer SDL2_ttf/' "$ANDROID_BUILD_DIR/$ANDROID_MK" -sed -i 's#^LOCAL_C_INCLUDES.*#& $(LOCAL_PATH)/../../../../../../../../lib $(LOCAL_PATH)/../../../../../../../../src#' \ +sed -i "s#^LOCAL_C_INCLUDES.*#& \$(LOCAL_PATH)/../../../../../../$SB_LIB_SRC \$(LOCAL_PATH)/../../../../../../$SB_SRC#" \ "$ANDROID_BUILD_DIR/$ANDROID_MK" -sed -i 's#YourSourceHere.c#$(LOCAL_PATH)/../../../../../../fill_screen.cpp#' "$ANDROID_BUILD_DIR/$ANDROID_MK" +sed -i "s#YourSourceHere.c#\$(wildcard \$(LOCAL_PATH)/../../../../../../*.cpp)#" "$ANDROID_BUILD_DIR/$ANDROID_MK" sed -i 's#^LOCAL_SRC_FILES.*#& $(wildcard $(LOCAL_PATH)/../../../../../../../../src/*.cpp)#' "$ANDROID_BUILD_DIR/$ANDROID_MK" sed -i 's#^LOCAL_SRC_FILES.*#& $(wildcard $(LOCAL_PATH)/../../../../../../../../lib/sdl2-gfx/*.c)#' "$ANDROID_BUILD_DIR/$ANDROID_MK" sed -i "s/\(name=\)\"SDLActivity\"/\1\"$ANDROID_CLASS\"/" "$ANDROID_BUILD_DIR/$ANDROID_MANIFEST" diff --git a/src/extension.cpp b/src/extension.cpp index 47dc08a..54363ad 100644 --- a/src/extension.cpp +++ b/src/extension.cpp @@ -1,3 +1,13 @@ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + #include "Pixels.hpp" #include "extension.hpp" @@ -593,35 +603,72 @@ fs::path sb::get_next_file_name(fs::path directory, int zfill, std::string prefi return path; } -/* Read the file at path into a string and return the string */ std::string sb::file_to_string(const fs::path& path) { - std::fstream file; - file.open(path); - std::ostringstream message; - std::string m_str; - if (!file.is_open()) + std::string contents = ""; + +#if !defined(__ANDROID__) && !defined(ANDROID) + + std::ostringstream log_message; + if (!fs::exists(path)) { - message << "failed to open " << path; - message.str(); - SDL_Log("%s", m_str.c_str()); - return ""; + log_message << "No file found at " << path; + sb::Log::log(log_message, sb::Log::Level::WARN); } else { - message << "opened file " << path; - m_str = message.str(); - SDL_Log("%s", m_str.c_str()); - file.seekg(0, std::ios::end); - size_t size = file.tellg(); - std::string contents; - contents.resize(size + 1, '\0'); - file.seekg(0, std::ios::beg); - file.read(contents.data(), size); - contents[size] = '\0'; - SDL_LogDebug(SDL_LOG_CATEGORY_CUSTOM, "%s", contents.c_str()); - return contents; + std::ifstream file; + file.open(path); + if (!file.is_open()) + { + log_message << "Failed to open " << path; + sb::Log::log(log_message, sb::Log::Level::WARN); + } + else + { + /* Read file using std::string's range constructor, from the beginning of the file stream to end of stream (represented + * by {} (?)) */ + contents = std::string(std::istreambuf_iterator(file), {}); + std::size_t size = file.tellg(); + log_message << "Opened file " << path << " (" << (size / 1000.0f) << "KB)"; + sb::Log::log(log_message); + sb::Log::log(contents, sb::Log::Level::DEBUG); + } } + +#else + + std::unique_ptr sdl_rw(SDL_RWFromFile(path.c_str(), "r"), SDL_RWclose); + if (sdl_rw.get() == nullptr) + { + __android_log_print(ANDROID_LOG_VERBOSE, "spacebox", "Unable to open file %s", SDL_GetError()); + } + else + { + int byte_count = SDL_RWsize(sdl_rw.get()); + __android_log_print(ANDROID_LOG_VERBOSE, "spacebox", "File at %s is %fKB", path.c_str(), (byte_count / 1000.0f)); + + contents.resize(byte_count); + + int nb_read_total = 0, nb_read = 1; + while (nb_read_total < byte_count && nb_read != 0) + { + nb_read = SDL_RWread(sdl_rw.get(), &contents[nb_read_total], 1, (byte_count - nb_read_total)); + nb_read_total += nb_read; + } + if (nb_read_total != byte_count) + { + __android_log_print(ANDROID_LOG_VERBOSE, "spacebox", "File could not be read because of a mismatch in file size and number of bytes read"); + } + else + { + __android_log_print(ANDROID_LOG_VERBOSE, "spacebox", "%s", contents.c_str()); + } + } + +#endif + + return contents; } int SDL_SetRenderDrawColor(SDL_Renderer* renderer, const Color& color) diff --git a/src/extension.hpp b/src/extension.hpp index e07be89..7f49ddf 100644 --- a/src/extension.hpp +++ b/src/extension.hpp @@ -1,16 +1,21 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, modify and sell without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +-------------*/ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ #ifndef SB_EXTENSION_H_ #define SB_EXTENSION_H_ +/* For logging pre-SPACEBOX messages in sb::file_to_string */ +#if defined(__ANDROID__) || defined(ANDROID) +#include +#endif + #include #include #include @@ -75,6 +80,16 @@ namespace sb SDL_Surface* get_surface_from_pixels(Pixels&); std::vector glob(fs::path); fs::path get_next_file_name(fs::path, int = 0, std::string = "", std::string = ""); + + /*! + * Read the file at path into a string and return the string. + * + * Android builds use SDL_RWops to extract the file from an APK. Otherwise, the file will be read using C++ STL. + * + * @param path Path to file, relative to working directory, or on Android, relative to app/src/main/assets/ in + * the build directory. + * @return std::string containing file contents + */ std::string file_to_string(const fs::path&); /* Returns an unsorted vector of keys from the passed map */ diff --git a/src/filesystem.hpp b/src/filesystem.hpp index de191ec..529f640 100644 --- a/src/filesystem.hpp +++ b/src/filesystem.hpp @@ -4,12 +4,5 @@ namespace fs = std::experimental::filesystem; #else #include - -/* Android uses a different path to the filesystem namespace */ -// #if defined(__ANDROID__) || defined(ANDROID) -// namespace fs = std::__fs::filesystem; -// #else namespace fs = std::filesystem; -// #endif - #endif