squircle and 2d collision demo; config auto refresh

This commit is contained in:
frank 2021-08-31 23:55:38 -04:00
parent ba44b8e8d5
commit c8bc86cab7
52 changed files with 1177 additions and 333 deletions

4
.gitignore vendored
View File

@ -1,4 +1,6 @@
*.o
local/
build/
demo/demo
demo/2d_collision/2d_collision
demo/squircle/squircle
demo/cube/cube

162
README
View File

@ -1,26 +1,37 @@
++~~~~~~~~~~~~~~~~~~~~~~~++
++~~~~~~~~~~~~~~~~~~~~~~~++
:: ::
:: SFW (SDL Framework) ::
:: ::
++~~~~~~~~~~~~~~~~~~~~~~~++
++~~~~~~~~~~~~~~~~~~~~~~~++
/\ +--------------------------------------------------------------+
____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - originally created at [http://nugget.fun] |
| ~~~~~~~~~~~~ | +--------------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+--------------+
[SPACE BOX] is a C++ framework that facilitates the creation of SDL + OpenGL projects
through the use of generic objects that can be used and extended by the programmer. It
focuses on game projects but its usefulness is not limited to games.
SFW is a C++ framework that facilitates the creation of SDL projects. It
provides generic game objects that can be used, extended or overwritten. Games
written using this framework can be exported to PC, Mac, Linux, Web GL,
Raspberry Pi, and Android.
The main intention for the project is to make running cross-platform applications easier
and more immediate by providing a universal tool set that exists as a hidden, extensible
layer between SDL + OpenGL and the project.
It is in an early untested state. It comes with a simple program that
demonstrates how to use it for a project that can switch between SDL and OpenGL
contexts.
An important quality of the framework is it should allow the programmer to start a project
by extending only a single function, the Game class's update function. Additionally, the
framework should by default create applications that can be easily exported to many
platforms (PC, OS/X, Linux, Web GL, Raspberry Pi, and Android) by using a standard
Makefile.
Requirements
````````````
The SFW source includes some external libraries in lib/ that the default
Makefile included with the demo shows how to compile, but there are other
libraries that must also be present in order to compile a project which uses the
framework
It is in an early, untested state. It comes with a few simple examples that demonstrate
how in can be used to create interactive graphics programs.
################
# Requirements #
################
The repository includes some external libraries in lib/ that the default Makefile included
with the demo shows how to compile, but there are other requirements, including external
libraries that must be linked to a project in order to compile it.
* libSDL2 (developed against v2.0.14)
* libSDL2-image
@ -29,22 +40,23 @@ framework
* OpenGL/GLES/GLES2
* compiler that supports C++17
Installing Requirements
```````````````````````
libSDL2, libSDL2-image, libSDL2-ttf, and libSDL2-mixer must be available to
link with your project, so you can try your package manager's libSDL2 dev
packages or build from source. The included sdl2-config utility program can be
used to generate flags for linking to SDL2 when it is installed outside of
your platform's usual library location.
###########################
# Installing Requirements #
###########################
libSDL2:
libSDL2, libSDL2-image, libSDL2-ttf, and libSDL2-mixer must be available to link with your
project, so you can try your package manager's libSDL2 dev packages or build from source.
The included sdl2-config utility program can be used to generate flags for linking to SDL2
when it is installed outside of your platform's usual library location.
libSDL2
```````
- Download from http://libsdl.org/download-2.0.php
- Run ./configure --prefix=[YOUR LIBRARIES PATH] (I'm using $HOME/local/sdl)
- Run make && make install
libSDL2-image, libSDL2-ttf, libSDL2-mixer:
libSDL2-image, libSDL2-ttf, libSDL2-mixer
`````````````````````````````````````````
- Download from:
- https://www.libsdl.org/projects/SDL_image/
- https://www.libsdl.org/projects/SDL_ttf/
@ -52,48 +64,80 @@ libSDL2-image, libSDL2-ttf, libSDL2-mixer:
- Run ./configure --prefix=[YOUR LIB PATH] --with-sdl-prefix=[YOUR SDL PATH]
- In my case, prefix and SDL prefix are both $HOME/local/sdl
OpenGL/GLES/GLES2:
OpenGL/GLES/GLES2
`````````````````
- Install GL/GLES according to your platform and link to it during compilation. GLEW is
included in the lib/ folder of this framework and should find GL on your platform if it
is installed.
- Install GL/GLES according to your platform and link to it during compilation.
GLEW is included in the lib/ folder of this framework and should find GL on
your platform if it is installed.
#########
# Demos #
#########
Demo
The `demo/` folder contains programs that demonstrate and test the capabilities of the
framework. In order to compile each, you should edit the definitions in the Makefile.
cube
````
The `demo/` folder contains a simple cube demo. The main purpose of the demo is
to demonstrate switching between 3D and 2D contexts. In order to compile the
demo, you will have to edit the paths in the Makefile to point to the locations
of the necessary libraries on your system.
Switch between GL and SDL contexts by pressing spacebar. The GL context draws a textured,
rotating cube, and the SDL context draws basic geometric shapes and a moving 2D sprite.
Other libraries
```````````````
These are other libraries that have been used in projects that use this
framework but aren't required by the framework
2d_collision
````````````
Test collision detection between a 2D sprite and other 2D sprites and boxes. Per-pixel
collision can be tested.
opencv:
squircle
````````
Map an image from a rectangle to a circle or from a circle to a rectangle using a shader
program. Based on the elliptical grid mapping equations at:
- http://squircular.blogspot.com/2015/09/mapping-circle-to-square.html
###################
# Other libraries #
###################
These are other libraries that have been used in projects that use this framework but
aren't required by the framework
opencv
``````
- Download from https://opencv.org/releases/
- configure (with custom installation path)
cmake -DCMAKE_INSTALL_PREFIX=$HOME/local/opencv ..
- make && make install
zbar:
zbar
````
- Download from http://zbar.sourceforge.net/download.html
- configure to only use image processing features (requires imagemagick) and
choose your installation directory
./configure --without-gtk --without-python --without-qt --disable-video --prefix=$HOME/local/zbar
- make && make install
License
```````
The original code for this framework is licensed to freely use, copy, modify and
sell, without restriction under the zlib license. See LICENSE.txt for details.
########
# Font #
########
When initializing a Game object, the framework will attempt to load the font file
"BPmono.ttf" from the project root (where the compiled executable is located). If this
file isn't found, the program can still run successfully, but the framerate indicator
(mapped to CTRL+f by default) will be disabled. The repository contains "BPmono.ttf", so
you can create a symlink to the file in the project root if you want to use the framerate
indicator.
###########
# License #
###########
The original code for this framework is licensed to freely use, copy, modify and sell,
without restriction under the zlib license. See LICENSE.txt for details.
Included libraries are included under various permissive licenses:
- BPmono.ttf is licensed under the Creative Commons Attribution - No Derivative
Works 3.0 license. See LICENSE_BPmono.txt for details.
- BPmono.ttf is licensed under the Creative Commons Attribution - No Derivative Works 3.0
license. See LICENSE_BPmono.txt for details.
- gif-h is unlicensed, public domain code released under the The Unlicense. See
lib/gif-h/LICENSE
@ -102,14 +146,14 @@ Included libraries are included under various permissive licenses:
- GLM is included under the MIT license in lib/glm/LICENSE
- nlohmann's json library is included under the MIT license in
lib/json/LICENSE.MIT
- nlohmann's json library is included under the MIT license in lib/json/LICENSE.MIT
- SDL2 GFX is included under a permissive license in lib/sdl2-gfx/LICENSE
- superxbr.cpp is included under a permissive license at the top of
lib/superxbr.cpp
- superxbr.cpp is included under the permissive license at the top of lib/superxbr.cpp
Business
````````
420@shampoo.ooo
############
# Business #
############
egg@shampoo.ooo

View File

@ -0,0 +1 @@
../../BPmono.ttf

View File

@ -0,0 +1,173 @@
#include "CollisionTest.hpp"
CollisionTest::CollisionTest() : Game()
{
get_delegate().subscribe(&CollisionTest::respond, this);
load_sdl_context();
enemy.set_color_mod({255, 128, 128, 255});
wooper.load();
enemy.load();
wooper.add_box({80, 200});
enemy.add_box({90, 100});
wooper.add_box({300, 10});
enemy.add_box({90, 200});
wooper.add_box({180, 20});
enemy.add_box({180, 50});
enemy.move({50, 50});
Pixels wooper_pixels = Pixels(wooper);
for (int x = 0; x < wooper.get_w(); x++)
{
wooper_pixels.set(Color(128, 255, 64), x, 12);
}
wooper_pixels.apply();
Box box = {{5, 10}, {20, 4}};
Pixels enemy_pixels = Pixels(enemy, box);
for (int x = -1, y = -1; x > -box.width(); x--, y--)
{
enemy_pixels.set(Color(-1.3, 68.9, 800.8), x, y);
}
enemy_pixels.apply();
canvas = SDL_CreateTexture(get_renderer(), SDL_PIXELFORMAT_RGBA4444, SDL_TEXTUREACCESS_STREAMING, 200, 100);
Pixels canvas_pixels = Pixels(get_renderer(), canvas);
for (int x = 0, y = 0; x < 288; x++, y += x)
{
canvas_pixels.set(Color(x, y, x + y), x, y);
}
canvas_pixels.apply();
Box subsection = Box({5, 10}, {60, 20});
Pixels sub_canvas_pixels = Pixels(get_renderer(), canvas, subsection);
for (int x = 0; x < subsection.width(); x++)
{
for (int y = 0; y < subsection.height(); y++)
{
// *canvas_pixels.operator()<std::uint16_t*>(x, y) = 0xfb60;
*canvas_pixels.operator()<std::uint16_t*>(x, y) = Color(255, 200, 100);
}
}
SDL_Color color = {0, 1, 2, 3};
std::cout << std::boolalpha << (Color(255, 255, 255) == Color(255, 255, 255)) << " " <<
(Color(122.1, 853.8, -1.3) == Color(122, 86, 255)) << " " << (Color(1, 2, 3, 4) == ((SDL_Color){1, 2, 3, 4})) << " " <<
(Color(256, 257, 258, 259) != color) << std::endl;
sub_canvas_pixels.apply();
test_crop(
{
Box({-5, -2}, {10, 5}),
Box({window_box().right() - 30, 10}, {100, 1000}),
Box(window_box().se() - glm::vec2(10, 15), {789, 123}),
Box(window_box().sw() - glm::vec2(1, 1), {5, 5})
});
// std::cout << "out of bounds pixel is " << screen_subsection_pixels.get(0, 0) <<
// " out of bounds pixel is " << screen_subsection_pixels.get(-1, 0) <<
// " in bounds pixel is " << screen_subsection_pixels.get(0, -1) <<
// " out of bounds pixel is " << screen_subsection_pixels.get(-1, -1) << std::endl;
// screen_subsection_pixels.set(Color(255, 0, 0), 0, -1);
// screen_subsection_pixels.set(Color(255, 255, 255), 0, 0);
// screen_subsection_pixels.apply();
}
void CollisionTest::test_crop(const std::vector<Box>& boxes)
{
for (const Box& box : boxes)
{
Pixels screen_subsection_pixels = Pixels(get_renderer(), nullptr, box);
std::cout << box << " cropped by screen to " << screen_subsection_pixels.rect << std::endl;
}
}
void CollisionTest::respond(SDL_Event& event)
{
if (get_delegate().compare(event, "up"))
{
wooper.move_weighted({0, -2});
}
else if (get_delegate().compare(event, "left"))
{
wooper.move_weighted({-2, 0});
}
else if (get_delegate().compare(event, "right"))
{
wooper.move_weighted({2, 0});
}
else if (get_delegate().compare(event, "down"))
{
wooper.move_weighted({0, 2});
}
else if (get_delegate().compare(event, "toggle-collide-all"))
{
collide_all = !collide_all;
}
else if (get_delegate().compare(event, "toggle-collide-all-other"))
{
collide_all_other = !collide_all_other;
}
else if (get_delegate().compare(event, "toggle-precise-collision"))
{
precise = !precise;
}
}
void CollisionTest::update()
{
SDL_SetRenderTarget(get_renderer(), NULL);
SDL_SetRenderDrawColor(get_renderer(), 64, 128, 64, 255);
SDL_RenderClear(get_renderer());
wooper.update();
enemy.update();
SDL_Color white = {255, 255, 255, 255}, red = {255, 0, 0, 255}, color;
Box overlap;
SDL_Rect rect;
for (const Box& box : boxes)
{
color = wooper.collide(box, overlap, precise, collide_all) ? red : white;
SDL_SetRenderTarget(get_renderer(), NULL);
SDL_SetRenderDrawColor(get_renderer(), color.r, color.g, color.b, color.a);
rect = box;
SDL_RenderDrawRect(get_renderer(), &rect);
rect = overlap;
SDL_SetRenderDrawColor(get_renderer(), 255, 255, 0, 255);
SDL_RenderDrawRect(get_renderer(), &rect);
}
glm::vec2 intersection;
for (const Segment& segment : segments)
{
color = wooper.collide(segment, intersection, collide_all) ? red : white;
glm::vec2 start = segment.start(), end = segment.end();
SDL_SetRenderDrawColor(get_renderer(), color.r, color.g, color.b, color.a);
SDL_RenderDrawLine(get_renderer(), start.x, start.y, end.x, end.y);
SDL_SetRenderDrawColor(get_renderer(), 255, 255, 0, 255);
SDL_RenderDrawPoint(get_renderer(), intersection.x, intersection.y);
}
for (const glm::vec2& point : points)
{
color = wooper.collide(point, collide_all) ? red : white;
SDL_SetRenderDrawColor(get_renderer(), color.r, color.g, color.b, color.a);
SDL_RenderDrawPoint(get_renderer(), point.x, point.y);
}
if (wooper.collide(enemy, overlap, precise, collide_all, collide_all_other))
{
SDL_SetRenderTarget(get_renderer(), nullptr);
SDL_SetRenderDrawColor(get_renderer(), 0, 255, 0, 255);
rect = overlap;
SDL_RenderDrawRect(get_renderer(), &rect);
}
Box screen_subsection_box = Box({0, 0}, {30, 60});
screen_subsection_box.sw(window_box().sw());
Pixels screen_subsection_pixels = Pixels(get_renderer(), nullptr, screen_subsection_box);
for (int x = 0; x < screen_subsection_pixels.rect.w; x++)
{
screen_subsection_pixels.set(Color(255, 0, 255), x, 5);
}
screen_subsection_pixels.apply();
SDL_SetRenderTarget(get_renderer(), nullptr);
Box canvas_box = sfw::get_texture_box(canvas);
canvas_box.nw({340, 200});
SDL_RenderCopyF(get_renderer(), canvas, nullptr, &canvas_box);
}
int main()
{
CollisionTest collision_test = CollisionTest();
collision_test.run();
collision_test.quit();
return 0;
}

View File

@ -0,0 +1,42 @@
#ifndef CollisionTest_h_
#define CollisionTest_h_
#include "Game.hpp"
#include "Sprite.hpp"
#include "Pixels.hpp"
#include "Color.hpp"
#include "extension.hpp"
class CollisionTest : public Game
{
private:
Sprite wooper = Sprite(this, "wooper.png");
Sprite enemy = Sprite(this, "wooper.png");
SDL_Texture* canvas;
std::vector<Box> boxes = {
{{50, 20}, {20, 10}},
{{300, 100}, {50, 60}},
{{160, 300}, {30, 10}},
};
std::vector<Segment> segments = {
{{5, 50}, {15, 90}},
{{250, 250}, {200, 240}}
};
std::vector<glm::vec2> points = {{100, 300}, {205, 20}, {450, 300}};
bool collide_all = false;
bool collide_all_other = false;
bool precise = false;
void test_crop(const std::vector<Box>&);
void respond(SDL_Event&);
void update();
public:
CollisionTest();
};
#endif

101
demo/2d_collision/Makefile Normal file
View File

@ -0,0 +1,101 @@
# /\ +--------------------------------------------------------------+
# ____/ \____ /| - 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 2D collision demo ]
#
# This should build the 2D collision demo for Linux. Compilation to other platforms
# hasn't been attempted yet.
#
# 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 := clang
CPPC := 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
SB_H_FILES := $(wildcard $(addprefix $(SB_SRC_DIR),*.hpp))
SB_O_FILES := $(filter-out $(addprefix $(SB_SRC_DIR),filesystem.o),$(SB_H_FILES:.hpp=.o))
SRC_H_FILES := $(wildcard $(addprefix $(SRC_DIR),*.hpp))
SRC_O_FILES := $(SRC_H_FILES:.hpp=.o)
##################################################################
# Targets for building [SPACE BOX], dependencies and 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)
$(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)CollisionTest.o : $(SB_H_FILES)
%.o : %.cpp %.hpp
$(CPPC) $(CPP_FLAGS) $< -c -o $@
##########################
# Target for Linux build #
##########################
linux : $(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) \
$(SB_O_FILES) CollisionTest.o
$(CREATE_FONT_SYMLINK)
$(CPPC) $(LFLAGS) -D__LINUX__ -lGL -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lstdc++fs $^ -o 2d_collision
#######################################
# Target for cleaning up object files #
#######################################
clean :
- rm *.o
- rm $(SB_SRC_DIR)*.o
- rm $(GLEW_DIR)*.o
- rm $(SDLGFX2_DIR)*.o

View File

@ -0,0 +1,8 @@
{
"keys":
{
"toggle-collide-all": ["CTRL", "c"],
"toggle-collide-all-other": ["CTRL", "o"],
"toggle-precise-collision": ["CTRL", "p"]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

View File

@ -1,120 +0,0 @@
SFW_DIR = ../
SFW_SRC_DIR = $(SFW_DIR)src/
SFW_LIB_DIR = $(SFW_DIR)lib/
SDLGFX2_DIR = $(SFW_LIB_DIR)sdl2-gfx/
GLEW_DIR = $(SFW_LIB_DIR)glew/
CC_LINUX = clang-7
CPPC_LINUX = clang++-7
SDLCONFIG = /home/frank/local/sdl/bin/sdl2-config
CFLAGS = -Wall -O0 -c -I$(SFW_LIB_DIR) -I$(SFW_SRC_DIR) -g
CPP_FLAGS = $(CFLAGS) --std=c++17
SDL_FLAGS = $(shell $(SDLCONFIG) --cflags)
LFLAGS = $(shell $(SDLCONFIG) --libs) -lpthread
export ANDROID_HOME = /home/frank/ext/software/android-sdk
export ANDROID_NDK_HOME = /home/frank/ext/software/android-ndk-r8d
BUILDDIR = build
ANDROIDPROJECT = com.tarecontrol.demo
SOFTWARE_ROOT = /home/frank/ext/software
SDLHOME = $(SOFTWARE_ROOT)/SDL2-2.0.9
SDL_IMG_HOME = $(SOFTWARE_ROOT)/SDL2_image-2.0.4
SDL_TTF_HOME = $(SOFTWARE_ROOT)/SDL2_ttf-2.0.14
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
$(SDLGFX2_DIR)%.o: $(SDLGFX2_DIR)%.c $(SDLGFX2_DIR)%.h
$(CC_LINUX) $(CFLAGS) $(SDL_FLAGS) $< -o $@
$(GLEW_DIR)%.o: $(GLEW_DIR)%.c $(GLEW_DIR)%.h
$(CC_LINUX) $(CFLAGS) $< -o $@
$(SFW_SRC_DIR)Sprite.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Box.*pp Node.*pp Animation.*pp)
$(SFW_SRC_DIR)Game.o: $(addprefix $(SFW_SRC_DIR),Sprite.*pp Configuration.*pp Delegate.*pp Display.*pp \
Recorder.*pp Node.*pp Input.*pp)
$(SFW_SRC_DIR)Node.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Configuration.*pp Delegate.*pp)
$(SFW_SRC_DIR)Animation.o: $(addprefix $(SFW_SRC_DIR),Node.*pp Timer.*pp)
$(SFW_SRC_DIR)Recorder.o: $(addprefix $(SFW_SRC_DIR),extension.*pp Node.*pp Delegate.*pp Animation.*pp Display.*pp)
$(SFW_SRC_DIR)Input.o: $(addprefix $(SFW_SRC_DIR),Delegate.*pp Node.*pp)
$(SFW_SRC_DIR)Configuration.o: $(addprefix $(SFW_SRC_DIR),Node.*pp)
$(SFW_SRC_DIR)Delegate.o: $(addprefix $(SFW_SRC_DIR),Node.*pp)
$(SFW_SRC_DIR)Display.o: $(addprefix $(SFW_SRC_DIR),Node.*pp)
$(SFW_SRC_DIR)%.o: $(addprefix $(SFW_SRC_DIR),%.cpp %.hpp)
$(CPPC_LINUX) $(CPP_FLAGS) $(SDL_FLAGS) $< -o $@
Demo.o: Demo.cpp Demo.hpp $(addprefix $(SFW_SRC_DIR),Sprite.*pp Node.*pp Game.*pp Box.*pp Input.*pp \
Recorder.*pp Timer.*pp Animation.*pp extension.*pp)
$(CPPC_LINUX) $(CPP_FLAGS) $(SDL_FLAGS) $< -o $@
linux: Demo.o $(addprefix $(SFW_SRC_DIR),Sprite.o Node.o Game.o Box.o Configuration.o Input.o Delegate.o \
Display.o Recorder.o Timer.o Animation.o extension.o) \
$(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o)
$(CPPC_LINUX) $(LFLAGS) -D__LINUX__ $^ -lGL -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lstdc++fs -o demo
clean:
rm *.o
rm $(SFW_SRC_DIR)*.o
rm $(GLEW_DIR)*.o
rm $(SDLGFX2_DIR)*.o
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
# main : main.o
# g++ -o main $(LFLAGS) -lGL main.o
# main.o : main.cpp
# g++ -c $(CFLAGS) -DLINUX main.cpp

1
demo/cube/BPmono.ttf Symbolic link
View File

@ -0,0 +1 @@
../../BPmono.ttf

View File

@ -27,7 +27,7 @@
***/
#include "Demo.hpp"
#include "Cube.hpp"
char* file_to_buf(const char *path)
{
@ -104,36 +104,6 @@ GLuint get_gl_texture_from_surface(SDL_Surface *surface, GLint mipmap_filter, bo
return id;
}
SDL_Surface* get_framerate_indicator_surface(int frame_count)
{
TTF_Font* font = TTF_OpenFont("resource/SourceCodePro-Regular.otf", 14);
std::string padded = sfw::pad(frame_count, 2);
SDL_Surface* shaded = TTF_RenderText_Shaded(
font, padded.c_str(), {0, 0, 0}, {255, 255, 255});
SDL_Surface* converted = SDL_ConvertSurfaceFormat(
shaded, SDL_PIXELFORMAT_ARGB8888, 0);
SDL_Surface* flipped = zoomSurface(converted, 1, -1, SMOOTHING_OFF);
SDL_FreeSurface(shaded);
SDL_FreeSurface(converted);
if (not flipped)
{
fprintf(stderr, "Could not create text %s\n", SDL_GetError());
}
TTF_CloseFont(font);
return flipped;
}
void set_framerate_indicator(int frame_count, GLuint id)
{
SDL_Surface* message = get_framerate_indicator_surface(frame_count);
glBindTexture(GL_TEXTURE_2D, id);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, message->w, message->h, GL_BGRA,
GL_UNSIGNED_BYTE, message->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
SDL_FreeSurface(message);
}
Mushroom::Mushroom(Node *parent) : Sprite(parent, "resource/shrooms")
{
set_frame_length(500);
@ -142,41 +112,41 @@ Mushroom::Mushroom(Node *parent) : Sprite(parent, "resource/shrooms")
void Mushroom::update()
{
move(direction);
int x = box.left();
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);
move({resolution.x - x, 0});
}
else
{
move(-x);
move({-x, 0});
}
}
Sprite::update();
}
Demo::Demo()
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(&Demo::respond, this);
delegate.subscribe(&Cube::respond, this);
}
void Demo::load_sdl_context()
void Cube::load_sdl_context()
{
Game::load_sdl_context();
grass.load();
mushroom.load();
}
void Demo::load_gl_context()
void Cube::load_gl_context()
{
Game::load_gl_context();
grass.unload();
@ -221,19 +191,12 @@ void Demo::load_gl_context()
};
GLuint background_colors_buffer;
glGenBuffers(1, &background_colors_buffer);
std::array<glm::vec3, 6> framerate_indicator_vertices = {
{
{.9, 1, 0}, {1, 1, 0}, {.9, .9, 0},
{1, 1, 0}, {1, .9, 0}, {.9, .9, 0}
}};
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
std::vector<glm::vec3> vertices;
vertices.reserve(cube.size() + background_vertices.size() + framerate_indicator_vertices.size());
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());
vertices.insert(vertices.end(), framerate_indicator_vertices.begin(),
framerate_indicator_vertices.end());
glm::ivec2 resolution = get_display().window_size();
projection = glm::perspective(
glm::radians(45.0f), resolution.x / (float) resolution.y, 0.1f,
@ -253,11 +216,6 @@ void Demo::load_gl_context()
// face_ids.push_back(get_gl_texture_from_surface(surface, GL_LINEAR));
// SDL_FreeSurface(surface);
// }
std::array<glm::vec2, 6> framerate_indicator_uv = {
{
{0, 1}, {1, 1}, {0, 0},
{1, 1}, {1, 0}, {0, 0}
}};
std::array<glm::vec2, 36> cube_uv = {
{
{1, 1}, {0, 1}, {0, 0},
@ -274,10 +232,8 @@ void Demo::load_gl_context()
{1, 1}, {0, 1}, {0, 0}
}};
std::vector<glm::vec2> uv;
uv.reserve(cube_uv.size() + background_vertices.size() + framerate_indicator_uv.size());
uv.reserve(cube_uv.size() + background_vertices.size());
std::copy(cube_uv.begin(), cube_uv.end(), uv.begin());
std::copy(framerate_indicator_uv.begin(), framerate_indicator_uv.end(),
uv.begin() + cube_uv.size() + background_vertices.size());
GLuint uvbuffer;
glGenBuffers(1, &uvbuffer);
unsigned char fake_texture_color[4] = {255, 255, 255, 255};
@ -330,13 +286,9 @@ void Demo::load_gl_context()
// glBindTexture(GL_TEXTURE_2D, space_texture_id);
// glUniform1i(sampler_uniform_id, 0);
glDepthFunc(GL_LESS);
frame_count_timestamp = SDL_GetTicks();
SDL_Surface* fps_surface = get_framerate_indicator_surface(frame_count);
framerate_texture_id = get_gl_texture_from_surface(fps_surface, GL_LINEAR);
SDL_FreeSurface(fps_surface);
}
void Demo::respond(SDL_Event& event)
void Cube::respond(SDL_Event& event)
{
if (delegate.compare(event, "context"))
{
@ -367,7 +319,7 @@ void Demo::respond(SDL_Event& event)
}
}
void Demo::update()
void Cube::update()
{
// while (SDL_PollEvent(&event))
// {
@ -440,16 +392,7 @@ void Demo::update()
glDisableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glDrawArrays(GL_TRIANGLES, 36, 6);
if (show_framerate)
{
glBindTexture(GL_TEXTURE_2D, framerate_texture_id);
glDisableVertexAttribArray(2);
glEnableVertexAttribArray(1);
glVertexAttrib3f(2, 1, 1, 1);
glDrawArrays(GL_TRIANGLES, 42, 6);
}
// printf("%s\n", glm::to_string(model).c_str());
float rotation = .0005f * frame_length;
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);
@ -482,40 +425,29 @@ void Demo::update()
int speed = 2;
if (up_active)
{
grass.move(0, -speed);
grass.move_weighted({0, -speed});
}
if (right_active)
{
grass.move(speed);
grass.move_weighted({speed, 0});
}
if (down_active)
{
grass.move(0, speed);
grass.move_weighted({0, speed});
}
if (left_active)
{
grass.move(-speed, 0);
grass.move_weighted({-speed, 0});
}
grass.update();
mushroom.update();
SDL_RenderPresent(renderer);
}
frame_count++;
if (ticks - frame_count_timestamp >= 1000)
{
frame_count_timestamp = ticks;
if (is_gl_context and show_framerate)
{
set_framerate_indicator(frame_count, framerate_texture_id);
}
frame_count = 0;
}
}
int main(int argc, char *argv[])
int main()
{
Demo demo = Demo();
demo.run();
demo.quit();
Cube cube = Cube();
cube.run();
cube.quit();
return 0;
}

View File

@ -14,17 +14,6 @@
#include "sdl2-gfx/SDL2_gfxPrimitives.h"
#include "sdl2-gfx/SDL2_rotozoom.h"
// #if defined(__LINUX__) or defined(__MINGW32__)
// #define GL_GLEXT_PROTOTYPES
// #include <GL/gl.h>
// #elif defined(__ANDROID__)
// #include <GLES/gl.h>
// #elif defined(__EMSCRIPTEN__)
// #include <GLES2/gl2.h>
// #elif defined(__APPLE__)
// #include <OpenGL/gl3.h>
// #endif
#define GLM_ENABLE_EXPERIMENTAL
#include "glm/gtx/string_cast.hpp"
#include "glm/gtx/transform.hpp"
@ -50,7 +39,7 @@ struct Mushroom : Sprite
};
struct Demo : Game
struct Cube : Game
{
SDL_Texture *grass_texture;
@ -66,7 +55,7 @@ struct Demo : Game
std::vector<GLuint> face_ids;
float amount_rotated;
Demo();
Cube();
void load_sdl_context();
void load_gl_context();
void respond(SDL_Event&);

175
demo/cube/Makefile Normal file
View File

@ -0,0 +1,175 @@
# /\ +--------------------------------------------------------------+
# ____/ \____ /| - 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

View File

@ -10,10 +10,14 @@
"print-video-memory-size": "v",
"play-sound": ""
},
"input":
{
"suppress-any-key-on-mods": true
},
"recording":
{
"screenshot-directory": "local/screenshots",
"video-directory": "local/video"
"video-directory": "local/video",
"enabled": true,
"write-mp4": true,
"video-frame-length": 16.667,

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 282 B

View File

Before

Width:  |  Height:  |  Size: 274 B

After

Width:  |  Height:  |  Size: 274 B

View File

Before

Width:  |  Height:  |  Size: 258 B

After

Width:  |  Height:  |  Size: 258 B

View File

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 282 B

View File

Before

Width:  |  Height:  |  Size: 251 B

After

Width:  |  Height:  |  Size: 251 B

View File

Before

Width:  |  Height:  |  Size: 307 B

After

Width:  |  Height:  |  Size: 307 B

View File

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 289 B

View File

Before

Width:  |  Height:  |  Size: 281 B

After

Width:  |  Height:  |  Size: 281 B

View File

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 270 B

View File

Before

Width:  |  Height:  |  Size: 703 B

After

Width:  |  Height:  |  Size: 703 B

1
demo/squircle/BPmono.ttf Symbolic link
View File

@ -0,0 +1 @@
../../BPmono.ttf

101
demo/squircle/Makefile Normal file
View File

@ -0,0 +1,101 @@
# /\ +--------------------------------------------------------------+
# ____/ \____ /| - 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 squircle demo ]
#
# This should build the squircle for Linux. Compilation to other platforms hasn't been
# attempted yet.
#
# 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 := clang
CPPC := 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) $(shell $(SDLCONFIG) --cflags) -g
CPP_FLAGS := $(CFLAGS) --std=c++17
LFLAGS := $(shell $(SDLCONFIG) --libs) -lpthread
SB_H_FILES := $(wildcard $(addprefix $(SB_SRC_DIR),*.hpp))
SB_O_FILES := $(filter-out $(addprefix $(SB_SRC_DIR),filesystem.o),$(SB_H_FILES:.hpp=.o))
SRC_H_FILES := $(wildcard $(addprefix $(SRC_DIR),*.hpp))
SRC_O_FILES := $(SRC_H_FILES:.hpp=.o)
##################################################################
# Targets for building [SPACE BOX], dependencies and 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)
$(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)Squircle.o : $(SB_H_FILES)
%.o : %.cpp %.hpp
$(CPPC) $(CPP_FLAGS) $< -c -o $@
##########################
# Target for Linux build #
##########################
linux : $(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) \
$(SB_O_FILES) $(SRC_O_FILES)
$(CREATE_FONT_SYMLINK)
$(CPPC) $(LFLAGS) -D__LINUX__ -lGL -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lstdc++fs $^ -o squircle
#######################################
# Target for cleaning up object files #
#######################################
clean :
- rm *.o
- rm $(SB_SRC_DIR)*.o
- rm $(GLEW_DIR)*.o
- rm $(SDLGFX2_DIR)*.o

182
demo/squircle/Squircle.cpp Normal file
View File

@ -0,0 +1,182 @@
/*
/\ +--------------------------------------------------------------+
____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - originally created at [http:nugget.fun] |
| ~~~~~~~~~~~~ | +--------------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+--------------+
Demonstrates functions from the Box class that map vertices from a square to a circle
and from a circle to a square. The functions are based on the equations described at
http://squircular.blogspot.com/2015/09/mapping-circle-to-square.html
*/
#include "Squircle.hpp"
int main()
{
Squircle squircle = Squircle();
squircle.run();
squircle.quit();
return 0;
}
Squircle::Squircle()
{
/* subscribe to command events */
get_delegate().subscribe(&Squircle::respond, this);
/* testing graphics in GL context */
load_gl_context();
}
void Squircle::load_gl_context()
{
super::load_gl_context();
/* 2D vertices for any texture that is a plane spanning the screen */
std::array<glm::vec2, 6> plane_vertices = {{
{-1.0f, 1.0f}, {1.0f, 1.0f}, {-1.0f, -1.0f},
{1.0f, 1.0f}, {1.0f, -1.0f}, {-1.0f, -1.0f}
}};
std::vector<glm::vec2> circle_vertices = sfw::points_on_circle(get_configuration()["circle-resolution"]);
circle_vertices.insert(circle_vertices.begin(), {0.0f, 0.0f});
circle_vertices.insert(circle_vertices.end(), circle_vertices[1]);
circle_vertices_count = circle_vertices.size();
/* Generate vertex buffer object to hold both mapped and unmapped data */
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
/* Allocate space for plane and circle and copy plane vertices in VBO */
GLsizeiptr vbo_size = (plane_vertices.size() + circle_vertices.size()) * sizeof(glm::vec2);
glBufferData(GL_ARRAY_BUFFER, vbo_size, plane_vertices.data(), GL_STATIC_DRAW);
/* Allocate VAO for the plane vertices and connect attributes to the VBO */
glGenVertexArrays(1, &unmapped_vao);
glBindVertexArray(unmapped_vao);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
/* Copy circle vertices into VBO */
GLintptr offset = plane_vertices.size() * sizeof(glm::vec2);
glBufferSubData(GL_ARRAY_BUFFER, offset, circle_vertices.size() * sizeof(glm::vec2), circle_vertices.data());
/* Allocate VAO for the circle vertices and connect attributes to the VBO */
glGenVertexArrays(1, &mapped_vao);
glBindVertexArray(mapped_vao);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<GLvoid*>(offset));
glEnableVertexAttribArray(0);
/* Load flat shader program */
GLuint vertex_shader = load_shader("flat.vert", GL_VERTEX_SHADER);
GLuint fragment_shader = load_shader("flat.frag", GL_FRAGMENT_SHADER);
flat_program = glCreateProgram();
glBindAttribLocation(flat_program, 0, "position");
glAttachShader(flat_program, vertex_shader);
glAttachShader(flat_program, fragment_shader);
link_shader(flat_program);
glUseProgram(flat_program);
/* load image */
load_image_index(0);
base_texture_shader_location = glGetUniformLocation(flat_program, "base_texture");
mode_uniform_location = glGetUniformLocation(flat_program, "mode");
transformation_uniform_location = glGetUniformLocation(flat_program, "transformation");
log_gl_errors();
}
/* Load image at path as an SDL surface, generate texture to load pixel data into, allocate storage, and bind
* and edit texture properties. Returns the ID of the generated texture. */
GLuint Squircle::load_file_into_texture(fs::path path) const
{
GLuint texture_id;
std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)> surface(IMG_Load(path.c_str()), SDL_FreeSurface);
std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)> flipped_surface(rotozoomSurfaceXY(surface.get(), 0, 1, -1, 0), SDL_FreeSurface);
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, flipped_surface->w, flipped_surface->h);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, flipped_surface->w, flipped_surface->h, GL_RGBA, GL_UNSIGNED_BYTE, flipped_surface->pixels);
std::ostringstream message;
message << "loaded image into texture id #" << texture_id << " " << flipped_surface->w << " x " << flipped_surface->h;
log(message.str());
return texture_id;
}
void Squircle::load_image_index(int index)
{
std::vector<fs::path> paths = sfw::glob("images/.*");
fs::path path = paths[index % paths.size()];
std::ostringstream message;
message << "loading " << path;
log(message.str());
image_index = index;
base_texture_id = load_file_into_texture(path);
}
void Squircle::respond(SDL_Event& event)
{
if (get_delegate().compare(event, "next"))
{
load_image_index(image_index + 1);
}
else if (get_delegate().compare(event, "mode"))
{
mode = mode == Mode::SQUIRCLE ? Mode::UNSQUIRCLE : Mode::SQUIRCLE;
}
else if (get_delegate().compare(event, "left"))
{
spin_z = Spin::NEGATIVE;
}
else if (get_delegate().compare(event, "right"))
{
spin_z = Spin::POSITIVE;
}
else if (get_delegate().compare(event, {std::string("left"), std::string("right")}, false, true))
{
spin_z = Spin::NONE;
}
else if (get_delegate().compare(event, "up"))
{
spin_x = Spin::NEGATIVE;
}
else if (get_delegate().compare(event, "down"))
{
spin_x = Spin::POSITIVE;
}
else if (get_delegate().compare(event, {std::string("up"), std::string("down")}, false, true))
{
spin_x = Spin::NONE;
}
}
void Squircle::update()
{
/* apply rotation to transformation matrix */
float rotation_speed = get_configuration()["rotation-speed"];
transformation = glm::rotate(transformation, spin_z * rotation_speed, {0, 0, 1});
transformation = glm::rotate(transformation, spin_x * rotation_speed, {1, 0, 0});
glUniformMatrix4fv(transformation_uniform_location, 1, false, &transformation[0][0]);
/* viewport box will be used to tell GL where to draw */
Box viewport_box = window_box();
glDisable(GL_DEPTH_TEST);
/* paint the screen black */
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* set uniform and activate texture */
glUniform1i(base_texture_shader_location, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, base_texture_id);
/* set viewport to left side of screen for unmapped plane */
glViewport(viewport_box.left(), viewport_box.top(), viewport_box.width() / 2, viewport_box.height());
/* draws plane vertices and plane UV */
glBindVertexArray(unmapped_vao);
glUniform1i(mode_uniform_location, mode == Mode::UNSQUIRCLE ? 2 : 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
/* set viewport to right side of screen for mapped plane */
glUseProgram(flat_program);
glViewport(viewport_box.cx(), viewport_box.top(), viewport_box.width() / 2, viewport_box.height());
/* draws mapped plane vertices and plane UV */
glBindVertexArray(mapped_vao);
glUniform1i(mode_uniform_location, mode == Mode::SQUIRCLE ? 1 : 0);
glDrawArrays(GL_TRIANGLE_FAN, 0, circle_vertices_count);
SDL_GL_SwapWindow(get_window());
}

View File

@ -0,0 +1,47 @@
#ifndef Squircle_h_
#define Squircle_h_
#include "glm/glm.hpp"
#include "SDL.h"
#include "Game.hpp"
#include "filesystem.hpp"
class Squircle : public Game
{
private:
enum Mode : bool
{
SQUIRCLE,
UNSQUIRCLE
};
enum Spin
{
NEGATIVE = -1,
NONE,
POSITIVE = 1
};
GLuint base_texture_shader_location = 0, base_texture_id = 0, flat_program = 0, unmapped_vao = 0, mapped_vao = 0,
mode_uniform_location = 0, transformation_uniform_location = 0;
int circle_vertices_count = 0, image_index = 0;
Mode mode = Mode::SQUIRCLE;
glm::mat4 transformation = glm::mat4(1.0f);
Spin spin_z = Spin::NONE, spin_x = Spin::NONE;
typedef Game super;
void load_gl_context();
GLuint load_file_into_texture(fs::path) const;
void load_image_index(int);
void update();
public:
Squircle();
void respond(SDL_Event&);
};
#endif

27
demo/squircle/config.json Normal file
View File

@ -0,0 +1,27 @@
{
"circle-resolution": 48,
"rotation-speed": 0.1,
"recording":
{
"screenshot-directory": "local/screenshots",
"video-directory": "local/video",
"enabled": true,
"write-mp4": true,
"video-frame-length": 33.333,
"max-video-memory": 2000,
"mp4-pixel-format": "yuv420p"
},
"log":
{
"debug-to-stdout": false
},
"configuration":
{
"auto-refresh": true
},
"keys":
{
"next": "space",
"mode": "enter"
}
}

51
demo/squircle/flat.frag Normal file
View File

@ -0,0 +1,51 @@
#version 130
in vec2 frag_uv;
in vec2 original_coordinates;
in vec4 clip_coordinates;
uniform sampler2D base_texture;
uniform int mode;
/* [-1, 1] normalized device coordinates to [0, 1] UV coordinates */
vec2 ndc_to_uv(vec2 coordinates)
{
return (coordinates + 1) / 2;
}
/* coordinates in circle with radius <= 1 to box coordinates in [-1, 1] */
vec2 circle_to_box(vec2 circle)
{
float u = circle.x;
float v = circle.y;
float u_sq = pow(u, 2);
float v_sq = pow(v, 2);
float rt_2 = sqrt(2);
float x = .5 * sqrt(2 + 2 * u * rt_2 + u_sq - v_sq) - .5 * sqrt(2 - 2 * u * rt_2 + u_sq - v_sq);
float y = .5 * sqrt(2 + 2 * v * rt_2 - u_sq + v_sq) - .5 * sqrt(2 - 2 * v * rt_2 - u_sq + v_sq);
return vec2(x, y);
}
/* box coordinates in [-1, 1] to coordinates in circle with radius <= 1 */
vec2 box_to_circle(vec2 box)
{
float u = box.x * sqrt(1 - .5 * pow(box.y, 2));
float v = box.y * sqrt(1 - .5 * pow(box.x, 2));
return vec2(u, v);
}
void main()
{
/* normalized device coordinates (coordinates in [-1, 1] space within viewport) */
vec2 ndc = original_coordinates;
/* map to circle if requested */
if (mode == 1)
{
ndc = circle_to_box(ndc);
}
else if (mode == 2)
{
ndc = box_to_circle(ndc);
}
/* translate ndc to uv space and get texel */
gl_FragColor = texture(base_texture, ndc_to_uv(ndc));
}

21
demo/squircle/flat.vert Normal file
View File

@ -0,0 +1,21 @@
#version 130
in vec2 position;
in vec2 vertex_uv;
uniform mat4 transformation;
uniform int mode;
out vec2 original_coordinates;
out vec4 clip_coordinates;
out vec2 frag_uv;
void main(void)
{
gl_Position = vec4(position, 0, 1);
if (mode > 0)
{
gl_Position *= transformation;
}
original_coordinates = position;
clip_coordinates = gl_Position;
frag_uv = vertex_uv;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -52,7 +52,7 @@ bool Animation::is_playing(bool include_delay)
void Animation::update()
{
timer.update();
if (playing and not paused and containing_object->is_active())
if (playing && !paused && containing_object->is_active())
{
if (delay > 0)
{

View File

@ -515,13 +515,6 @@ bool Box::collide(const Box& box, Box& overlap) const
return collide(box, &overlap);
}
/* Map any point in the bounds of a square with x and y between [-, radius] to a circle with specified radius. If
* center is specified, both the square and circle are centered at specified point. The default radius is 1, and the
* default center is (0, 0). Formula taken from http://squircular.blogspot.com/2015/09/mapping-circle-to-square.html */
glm::vec2 Box::map_point_to_circle(const glm::vec2& point, float radius, const glm::vec2& center) const
{
}
/* Return the string representation of a Box "{left, top, width, height}" */
std::string Box::string() const
{

View File

@ -77,7 +77,6 @@ public:
bool collide(const Segment&, glm::vec2&) const;
bool collide(const Box&, Box* = nullptr) const;
bool collide(const Box&, Box&) const;
glm::vec2 map_point_to_circle(const glm::vec2&, float, const glm::vec2&) const;
virtual std::string class_name() const { return "Box"; }
std::string string() const;

View File

@ -4,17 +4,20 @@
#include "Configuration.hpp"
Configuration::Configuration(Node *parent) : Configuration(parent, "config.json") {}
/* Initialize a Configuration object. The path argument is the location where the config file is stored.
* If there is no file located at the path, it will be created if the write method is called. System level
* default assignments defined in this file can be added to and overwritten by user supplied JSON file at
* the specified path or at a path passed to the load function. */
Configuration::Configuration(Node *parent, fs::path path) : Node(parent)
{
config_path = path;
set_defaults();
load();
merge();
auto_refresher.set_frame_length(config["configuration"]["auto-refresh-interval"].get<float>());
auto_refresh(config["configuration"]["auto-refresh"]);
}
/* Fill the system level config JSON with default values set by the framework */
/* Fill the system level config JSON dict with default values set by the framework */
void Configuration::set_defaults()
{
sys_config["keys"] = {
@ -34,14 +37,14 @@ void Configuration::set_defaults()
sys_config["input"] = {
{"suppress-any-key-on-mods", true},
{"system-any-key-ignore-commands", {"fullscreen", "screenshot", "toggle-framerate", "record", "quit"}},
{"any-key-ignore-commands", {}},
{"any-key-ignore-commands", nlohmann::json::array()},
{"default-unsuppress-delay", 700},
{"ignore-repeat-keypress", true}
};
sys_config["display"] = {
{"dimensions", {640, 480}},
{"framerate", 60},
{"title", "sfw"},
{"title", "[SPACE BOX]"},
{"debug", false},
{"show-cursor", false},
{"render-test-spacing", 2},
@ -83,41 +86,90 @@ void Configuration::set_defaults()
{"info-file-name", "log.txt"},
{"debug-file-name", "debug_log.txt"}
};
sys_config["configuration"] = {
{"auto-refresh", false},
{"auto-refresh-interval", 1000}
};
config = sys_config;
}
/* Load the configuration file at path */
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();
}
}
/* Load the configuration file at Configuration::config_path */
void Configuration::load()
{
load(config_path);
}
void Configuration::load(fs::path path)
{
if (fs::exists(path))
{
std::ifstream contents(path);
contents >> game_config;
}
}
/* Merge the system level config JSON dict (hard-coded in this file) with the user level config JSON
* dict (loaded from disk by the load function) */
void Configuration::merge()
{
config = sys_config;
if (not game_config.empty())
if (not user_config.empty())
{
for (auto& section: game_config.items())
/* loop over first level key/value pairs */
for (auto& item: user_config.items())
{
config[section.key()].update(game_config[section.key()]);
/* if the value is an object (dict), merge it into the config, overwriting keys already in the config */
if (item.value().is_object())
{
config[item.key()].update(item.value());
}
/* otherwise just assign config key to this value */
else
{
config[item.key()] = item.value();
}
}
}
}
/* Set auto refresh to on or off */
void Configuration::auto_refresh(bool on)
{
on ? auto_refresher.play() : auto_refresher.pause();
}
/* Refresh the config contents by calling the default load function */
void Configuration::refresh()
{
if (fs::exists(config_path) && fs::last_write_time(config_path) > config_file_modification_time)
{
std::ostringstream message;
message << "config file modified, reloading " << config_path;
debug(message.str());
load();
}
}
/* Write configuration to specified path in JSON format */
void Configuration::write(fs::path path)
{
std::ofstream output(path);
output << std::setw(tab_width) << user_config << std::endl;
}
/* Write configuration to config_path (set at initialization) */
void Configuration::write()
{
write(config_path);
}
void Configuration::write(fs::path path)
/* Updates the auto refresher */
void Configuration::update()
{
std::ofstream output(path);
output << std::setw(tab_width) << game_config << std::endl;
auto_refresher.update();
}

View File

@ -2,28 +2,41 @@
#define Configuration_h_
#include "json/json.hpp"
#include "filesystem.hpp"
#include "Node.hpp"
#include "Animation.hpp"
struct Configuration : Node
class Configuration : public Node
{
nlohmann::json sys_config, game_config, config;
private:
nlohmann::json sys_config, user_config;
fs::path config_path;
int tab_width = 4;
Animation auto_refresher = Animation(&Configuration::refresh, this);
fs::file_time_type config_file_modification_time;
Configuration(Node*);
Configuration(Node*, fs::path);
void set_defaults();
void load();
void load(fs::path path);
void merge();
void write();
public:
nlohmann::json config;
Configuration(Node*, fs::path = "config.json");
void load(fs::path path);
void load();
void auto_refresh(bool);
void refresh();
void write(fs::path path);
void write();
void update();
virtual std::string class_name() const { return "Configuration"; }
};
/* Extend GLM so nlohmann::json can read and write glm::vec2 */
namespace glm
{
template <typename T>
@ -40,6 +53,7 @@ namespace glm
}
}
/* Extend std::filesystem so nlohmann::json can read and write std::filesystem::path */
#if defined(__MINGW32__)
namespace std::experimental::filesystem
#else

View File

@ -28,7 +28,7 @@ SDL_Surface* FramerateIndicator::get_surface()
void FramerateIndicator::refresh()
{
if (!is_hidden() && get_root()->bp_mono_font != NULL)
if (!is_hidden() && get_root()->bp_mono_font != nullptr)
{
unload();
SDL_Surface* surface = get_surface();
@ -133,7 +133,7 @@ Game::Game()
SDL_Log("initialized SDL ttf %d.%d.%d", SDL_TTF_MAJOR_VERSION,
SDL_TTF_MINOR_VERSION, SDL_TTF_PATCHLEVEL);
}
if ((bp_mono_font = TTF_OpenFont("BPmono.ttf", 14)) == NULL)
if ((bp_mono_font = TTF_OpenFont("BPmono.ttf", 14)) == nullptr)
{
print_error("Could not load BPmono.ttf");
}
@ -671,15 +671,13 @@ void Game::frame(float ticks)
// std::cout << ", last_frame_length: " << last_frame_length << " [rendering frame]";
if (last_frame_length < 1000)
{
// if (!is_gl_context)
// {
recorder.update();
// }
recorder.update();
delegate.dispatch();
audio.update();
input.unsuppress_animation.update();
update();
framerate_indicator.update();
configuration.update();
if (!is_gl_context)
{
SDL_SetRenderTarget(renderer, nullptr);

View File

@ -57,6 +57,12 @@ private:
public:
/* two-state enum equivalent to a boolean that can improve readability depending on the context */
enum class Flip {
OFF,
ON
};
/* Prevent an instance of this class from being copied or moved */
Game(const Game&) = delete;
Game& operator=(const Game&) = delete;
@ -77,7 +83,7 @@ public:
Input input = Input(this);
Audio audio = Audio(this);
std::vector<float> frame_length_history;
TTF_Font* bp_mono_font = NULL;
TTF_Font* bp_mono_font = nullptr;
FramerateIndicator framerate_indicator = FramerateIndicator(this);
Game();

View File

@ -15,7 +15,7 @@ Segment::Segment(const glm::vec2& location) : Segment(location, location) {};
Segment::Segment(const Box& start, const Box& end) : Segment(start.center(), end.center()) {};
inline glm::vec2 Segment::start() const
glm::vec2 Segment::start() const
{
return start_;
}

View File

@ -24,7 +24,7 @@ public:
Segment(const glm::vec2&);
Segment(const Box&, const Box&);
Segment(const Sprite&, const Sprite&);
inline glm::vec2 start() const;
glm::vec2 start() const;
void start(const glm::vec2&);
glm::vec2 end() const;
void end(const glm::vec2&);

View File

@ -1,6 +1,7 @@
#include "Pixels.hpp"
#include "extension.hpp"
/* Edit a vector in place, giving it the specified magnitude while maintaining the direction */
void sfw::set_magnitude(glm::vec2& vector, float magnitude)
{
vector = glm::normalize(vector) * magnitude;

View File

@ -40,7 +40,6 @@ namespace sfw
glm::vec2 point_on_circle(float, float = 1.0f);
void points_on_circle(std::vector<glm::vec2>&, int, float = 1.0f, const glm::vec2& = {0, 0}, float = 0.0f);
std::vector<glm::vec2> points_on_circle(int, float = 1.0f, const glm::vec2& = {0, 0}, float = 0.0f);
glm::vec2 map_rectangle_xy_to_circle(const glm::vec2&, float = 1.0f, const glm::vec2& = {0, 0});
Box get_texture_box(SDL_Texture*);
glm::vec2 fit_and_preserve_aspect(const glm::vec2&, const glm::vec2&);
std::vector<std::vector<Box>> get_blinds_boxes(glm::vec2, float = 0.05f, int = 4);