box demo android support, android file to string for reading files inside APK

This commit is contained in:
frank 2022-11-08 17:16:05 -05:00
parent ec993b7337
commit f47c080d72
56 changed files with 1386 additions and 1032 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2021 Nuggets Select <420@shampoo.ooo>
Copyright (c) 2021-22 shampoo.ooo <mailbox@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

View File

@ -1,19 +1,19 @@
SPACEBOX
========
<pre>
/\ +------------------------------------------------------------+
____/ \____ /| zlib/MIT/Unlicenced game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | Learn more about *SPACEBOX* at [shampoo.ooo][] |
| ~~~~~~~~~~~~ | +------------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+--------------+ </pre>
![logo](icon/static.png)
<pre>
/\ +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+--------------+ </pre>
*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.

5
demo/box/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
box
*_log.txt
*.data
box_demo.js
*.wasm

235
demo/box/BoxDemo.cpp Normal file
View File

@ -0,0 +1,235 @@
/*!<pre>
* /\ +------------------------------------------------------+
* ____/ \____ /| - Open source game framework licensed to freely use, |
* \ / / | copy, modify and sell without restriction |
* +--\ ^__^ /--+ | |
* | ~/ \~ | | - created for <https://foam.shampoo.ooo> |
* | ~~~~~~~~~~~~ | +------------------------------------------------------+
* | SPACE ~~~~~ | /
* | ~~~~~~~ BOX |/
* +--------------+ </pre>
*
* Display a rotating box with a space texture and gradient background using SDL, OpenGL, and Spacebox.
*/
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <vector>
#include <array>
#include <list>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <functional>
#include <fstream>
#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;
}

247
demo/box/Makefile Normal file
View File

@ -0,0 +1,247 @@
# /\ +------------------------------------------------------+
# ____/ \____ /| - Open source game framework licensed to freely use, |
# \ / / | copy, modify and sell without restriction |
# +--\ ^__^ /--+ | |
# | ~/ \~ | | - created for <https://foam.shampoo.ooo> |
# | ~~~~~~~~~~~~ | +------------------------------------------------------+
# | 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
# <https://imagemagick.org/>. 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

196
demo/box/Model.cpp Normal file
View File

@ -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<std::string, std::shared_ptr<sb::Attributes>>& 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<std::string, sb::Attributes>& 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<std::string>& 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<std::string, std::shared_ptr<sb::Attributes>>& 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<sb::Attributes>& 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<sb::Attributes>& 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<sb::Attributes>(attributes), name);
}
/* Assign name to attributes and share ownership. */
void Model::attributes(const std::shared_ptr<sb::Attributes>& 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<std::string, sb::Texture>& 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;
}

105
demo/box/Model.hpp Normal file
View File

@ -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 <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#else
#include "glew/glew.h"
#endif
#include <iostream>
#include <string>
#include <map>
#include <memory>
#include <iterator>
#include "glm/glm.hpp"
#include "Attributes.hpp"
#include "Texture.hpp"
class Model
{
private:
inline static const std::string DEFAULT_TEXTURE_NAME = "default";
std::map<std::string, sb::Texture> model_textures;
std::map<std::string, std::shared_ptr<sb::Attributes>> model_attributes;
glm::mat4 model_transformation {1.0f};
public:
Model();
Model(const std::map<std::string, std::shared_ptr<sb::Attributes>>&);
Model(const std::map<std::string, sb::Attributes>&);
Model(const std::initializer_list<std::string>&);
std::map<std::string, std::shared_ptr<sb::Attributes>>& attributes();
std::shared_ptr<sb::Attributes>& attributes(const std::string&);
void attributes(const sb::Attributes&, const std::string&);
void attributes(const std::shared_ptr<sb::Attributes>&, const std::string&);
std::shared_ptr<sb::Attributes>& operator[](const std::string&);
void enable();
void disable();
std::map<std::string, sb::Texture>& 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<sb::Attributes> position = std::make_shared<sb::Attributes>(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<sb::Attributes> uv = std::make_shared<sb::Attributes>(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<std::string, std::shared_ptr<sb::Attributes>>({{"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

View File

@ -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
}
}

31
demo/box/index.html Normal file
View File

@ -0,0 +1,31 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta charset="utf-8">
<style>
body
{
background: #000;
}
</style>
</head>
<body>
<!-- WebGL output will be drawn here through Emscripten. The dimensions will be set by Emscripten. -->
<canvas id="canvas"></canvas>
<script>
var Module = {
/* Set Emscripten to use the canvas for display. */
canvas: document.getElementById("canvas")
};
</script>
<!-- This file is built by Emscripten when compiling the program -->
<script src="box_demo.js"></script>
</body>
</html>

BIN
demo/box/resource/tile.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 B

24
demo/box/shaders/all.frag Normal file
View File

@ -0,0 +1,24 @@
#version 300 es
/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| 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;
}

View File

@ -0,0 +1,28 @@
#version 300 es
/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| 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);
}

View File

@ -0,0 +1,30 @@
#version 300 es
/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| 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;
}

View File

@ -1,4 +1,14 @@
# Browser Webcam Test
# /\ +------------------------------------------------------+
# ____/ \____ /| - Open source game framework licensed to freely use, |
# \ / / | copy, modify and sell without restriction |
# +--\ ^__^ /--+ | |
# | ~/ \~ | | - created for <https://foam.shampoo.ooo> |
# | ~~~~~~~~~~~~ | +------------------------------------------------------+
# | SPACE ~~~~~ | /
# | ~~~~~~~ BOX |/
# +--------------+
#
# Modify location parameters to match locations for each directory on the system and run `make emscripten`
#######################
# Location parameters #

View File

@ -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 <https://foam.shampoo.ooo> |
* | ~~~~~~~~~~~~ | +------------------------------------------------------+
* | 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 <emscripten/bind.h>
@ -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) */

View File

@ -1,6 +1,19 @@
<!doctype html>
<html>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta charset="utf-8">
<style>
body
{
background: #000;
}
</style>
</head>
<body>
<!-- WebGL output will be drawn here through Emscripten -->
<canvas id="canvas"></canvas>

View File

@ -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<glm::vec3, 36> 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<glm::vec3, 6> 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<glm::vec3> 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<fs::path> 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<glm::vec2, 36> 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<glm::vec2> 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;
}

View File

@ -1,65 +0,0 @@
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <vector>
#include <array>
#include <list>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <functional>
#include <fstream>
#include <SDL_image.h>
#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<GLuint> 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"; }
};

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 703 B

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -1,4 +1,14 @@
/*
/*!<pre>
* /\ +------------------------------------------------------+
* ____/ \____ /| - Open source game framework licensed to freely use, |
* \ / / | copy, modify and sell without restriction |
* +--\ ^__^ /--+ | |
* | ~/ \~ | | - created for <https://foam.shampoo.ooo> |
* | ~~~~~~~~~~~~ | +------------------------------------------------------+
* | SPACE ~~~~~ | /
* | ~~~~~~~ BOX |/
* +--------------+ </pre>
*
* 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

BIN
icon/static_alt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

BIN
icon/static_solid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -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 |/
+-------------*/
/*!<pre>
* /\ +------------------------------------------------------+
* ____/ \____ /| - Open source game framework licensed to freely use, |
* \ / / | copy, modify and sell without restriction |
* +--\ ^__^ /--+ | |
* | ~/ \~ | | - created for <https://foam.shampoo.ooo> |
* | ~~~~~~~~~~~~ | +------------------------------------------------------+
* | SPACE ~~~~~ | /
* | ~~~~~~~ BOX |/
* +--------------+ </pre>*/
#include "Attributes.hpp"

View File

@ -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<std::uint32_t>{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<float>{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 }
*/
/*!<pre>
* /\ +------------------------------------------------------+
* ____/ \____ /| - Open source game framework licensed to freely use, |
* \ / / | copy, modify and sell without restriction |
* +--\ ^__^ /--+ | |
* | ~/ \~ | | - created for <https://foam.shampoo.ooo> |
* | ~~~~~~~~~~~~ | +------------------------------------------------------+
* | SPACE ~~~~~ | /
* | ~~~~~~~ BOX |/
* +--------------+ </pre>
*
* 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<std::uint32_t>{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<float>{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<typename Type>
Attributes(const std::vector<Type>& 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<typename Type>
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<typename XType, typename... CoordinateTypes,
std::enable_if_t<(... && std::is_same_v<CoordinateTypes, XType>), std::nullptr_t> = nullptr>
Attributes(const XType& coordinate_0, const CoordinateTypes&... coordinates) :
Attributes({std::initializer_list<XType>({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<typename VertexType>
Attributes(const std::initializer_list<VertexType>& vertices) :
Attributes(std::vector<VertexType>(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<typename CoordinateType>
Attributes(const std::initializer_list<std::initializer_list<CoordinateType>>& 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<typename XType, typename YType, typename... CoordinateTypes,
std::enable_if_t<std::is_same_v<XType, YType> && (... && std::is_same_v<CoordinateTypes, XType>),
std::nullptr_t> = nullptr>
@ -213,23 +232,38 @@ namespace sb
add({std::initializer_list<XType>({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<typename VertexType>
const VertexType& read(std::size_t index) const
{
return std::get<std::vector<VertexType>>(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<typename VertexType, typename CoordinateType = float>
const CoordinateType& read(std::size_t outer, std::size_t inner)
{
return std::get<std::vector<VertexType>>(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<typename VertexType>
operator const std::vector<VertexType>&() const
{

View File

@ -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())

View File

@ -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

View File

@ -1,3 +1,13 @@
/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| 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<std::string>().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<char*>(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<Game*>(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<const std::string&>().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<const GLchar**>(&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);

View File

@ -1,3 +1,13 @@
/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
#pragma once
#include <stdlib.h>
@ -26,6 +36,10 @@
#include "glew/glew.h"
#endif
#if defined(__ANDROID__) || defined(ANDROID)
#include <android/log.h>
#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<typename T>
T weight(T amount)
{

View File

@ -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 <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
#include "Log.hpp"

View File

@ -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.
*/
/*!<pre>
* /\ +------------------------------------------------------+
* ____/ \____ /| - Open source game framework licensed to freely use, |
* \ / / | copy, modify and sell without restriction |
* +--\ ^__^ /--+ | |
* | ~/ \~ | | - created for <https://foam.shampoo.ooo> |
* | ~~~~~~~~~~~~ | +------------------------------------------------------+
* | SPACE ~~~~~ | /
* | ~~~~~~~ BOX |/
* +--------------+ </pre>
*
* 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_

View File

@ -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 <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
#include "Texture.hpp"
using namespace sb;

View File

@ -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.
*/
/*!<pre>
* /\ +------------------------------------------------------+
* ____/ \____ /| - Open source game framework licensed to freely use, |
* \ / / | copy, modify and sell without restriction |
* +--\ ^__^ /--+ | |
* | ~/ \~ | | - created for <https://foam.shampoo.ooo> |
* | ~~~~~~~~~~~~ | +------------------------------------------------------+
* | SPACE ~~~~~ | /
* | ~~~~~~~ BOX |/
* +--------------+ </pre>
*
* 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}
*/

View File

@ -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"

View File

@ -1,3 +1,13 @@
/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| 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_RWops, decltype(&SDL_RWclose)> 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)

View File

@ -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 <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| 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 <android/log.h>
#endif
#include <vector>
#include <iostream>
#include <regex>
@ -75,6 +80,16 @@ namespace sb
SDL_Surface* get_surface_from_pixels(Pixels&);
std::vector<fs::path> 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 */

View File

@ -4,12 +4,5 @@
namespace fs = std::experimental::filesystem;
#else
#include <filesystem>
/* 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