@ -0,0 +1,6 @@
|
||||
index.* |
||||
local/ |
||||
*.o |
||||
BPmono.ttf |
||||
pepy |
||||
compile_commands.json |
@ -0,0 +1,3 @@
|
||||
[submodule "lib/sb"] |
||||
path = lib/sb |
||||
url = makar:/var/www/git/sb |
@ -0,0 +1,192 @@
|
||||
# Pepy by @ohsqueezy [ohsqueezy.itch.io]
|
||||
|
||||
#######################
|
||||
# Location parameters #
|
||||
#######################
|
||||
|
||||
# Location of project specific source files
|
||||
SRC_DIR := src/
|
||||
|
||||
# Locations of [SPACE BOX] source and dependencies required to be compiled from source. These
|
||||
# locations are configured to match the structure of the [SPACE BOX] repository but can be
|
||||
# modified as necessary.
|
||||
SB_DIR := lib/sb/
|
||||
SB_SRC_DIR := $(SB_DIR)src/
|
||||
SB_LIB_DIR := $(SB_DIR)lib/
|
||||
SDLGFX2_DIR := $(SB_LIB_DIR)sdl2-gfx/
|
||||
GLEW_DIR := $(SB_LIB_DIR)glew/
|
||||
|
||||
# C and C++ compiler commands
|
||||
CC := clang
|
||||
CPPC := clang++
|
||||
|
||||
# Location of SDL config program
|
||||
SDLCONFIG := $(HOME)/local/sdl/bin/sdl2-config
|
||||
|
||||
# Edit to point to the location of BPmono.ttf
|
||||
CREATE_FONT_SYMLINK := ln -nsf $(SB_DIR)"BPmono.ttf" .
|
||||
|
||||
#############################
|
||||
# Based on above parameters #
|
||||
#############################
|
||||
|
||||
SDL_CFLAGS = $(shell $(SDLCONFIG) --cflags)
|
||||
SDL_LFLAGS := $(shell $(SDLCONFIG) --libs)
|
||||
SB_H_FILES := $(wildcard $(addprefix $(SB_SRC_DIR),*.hpp))
|
||||
SB_O_FILES := $(filter-out $(addprefix $(SB_SRC_DIR),filesystem.o),$(SB_H_FILES:.hpp=.o))
|
||||
SRC_H_FILES := $(wildcard $(addprefix $(SRC_DIR),*.hpp))
|
||||
SRC_O_FILES := $(SRC_H_FILES:.hpp=.o)
|
||||
|
||||
#####################################################################
|
||||
# Targets for building [SPACE BOX], dependencies and project source #
|
||||
#####################################################################
|
||||
|
||||
$(SDLGFX2_DIR)%.o: $(SDLGFX2_DIR)%.c $(SDLGFX2_DIR)%.h |
||||
$(GLEW_DIR)%.o: $(GLEW_DIR)%.c $(GLEW_DIR)%.h |
||||
$(CC) $(CFLAGS) $< -c -o $@
|
||||
|
||||
$(SB_SRC_DIR)extension.o : $(addprefix $(SB_SRC_DIR),Box.hpp Segment.hpp Color.hpp filesystem.hpp Pixels.hpp Log.hpp) |
||||
$(SB_SRC_DIR)Node.o : $(addprefix $(SB_SRC_DIR),Game.hpp Configuration.hpp Delegate.hpp Display.hpp Input.hpp Box.hpp Audio.hpp Log.hpp) |
||||
$(SB_SRC_DIR)Sprite.o : $(addprefix $(SB_SRC_DIR),Node.hpp Game.hpp Box.hpp Animation.hpp Color.hpp extension.hpp Pixels.hpp Log.hpp) |
||||
$(SB_SRC_DIR)Game.o : $(addprefix $(SB_SRC_DIR),extension.hpp Node.hpp Sprite.hpp Recorder.hpp Input.hpp Configuration.hpp \
|
||||
Delegate.hpp Audio.hpp Log.hpp)
|
||||
$(SB_SRC_DIR)Animation.o : $(addprefix $(SB_SRC_DIR),Node.hpp Timer.hpp) |
||||
$(SB_SRC_DIR)Recorder.o : $(addprefix $(SB_SRC_DIR),Node.hpp Game.hpp Configuration.hpp Delegate.hpp Animation.hpp extension.hpp) |
||||
$(SB_SRC_DIR)Input.o : $(addprefix $(SB_SRC_DIR),Node.hpp Animation.hpp Configuration.hpp Delegate.hpp) |
||||
$(SB_SRC_DIR)Configuration.o : $(addprefix $(SB_SRC_DIR),Node.hpp Animation.hpp Log.hpp) |
||||
$(SB_SRC_DIR)Delegate.o : $(addprefix $(SB_SRC_DIR),Node.hpp Game.hpp Input.hpp) |
||||
$(SB_SRC_DIR)Display.o : $(addprefix $(SB_SRC_DIR),Node.hpp Game.hpp Box.hpp Configuration.hpp Delegate.hpp Log.hpp) |
||||
$(SB_SRC_DIR)Box.o : $(addprefix $(SB_SRC_DIR),extension.hpp Segment.hpp) |
||||
$(SB_SRC_DIR)Segment.o : $(addprefix $(SB_SRC_DIR),extension.hpp Box.hpp) |
||||
$(SB_SRC_DIR)Pixels.o : $(addprefix $(SB_SRC_DIR),Box.hpp extension.hpp Log.hpp utility.hpp) |
||||
$(SB_SRC_DIR)Audio.o : $(addprefix $(SB_SRC_DIR),Node.hpp Display.hpp Configuration.hpp Box.hpp filesystem.hpp extension.hpp) |
||||
$(SB_SRC_DIR)GLObject.o : $(addprefix $(SB_SRC_DIR),Log.hpp) |
||||
$(SB_SRC_DIR)Texture.o : $(addprefix $(SB_SRC_DIR),GLObject.hpp filesystem.hpp Log.hpp) |
||||
$(SB_SRC_DIR)VBO.o : $(addprefix $(SB_SRC_DIR),Log.hpp GLObject.hpp Attributes.hpp extension.hpp) |
||||
$(SB_SRC_DIR)Attributes.o : $(addprefix $(SB_SRC_DIR),Log.hpp extension.hpp) |
||||
$(SRC_DIR)Pepy.o : $(SRC_H_FILES) $(SB_H_FILES) |
||||
%.o : %.cpp %.hpp |
||||
$(CPPC) $(CPP_FLAGS) $< -c -o $@
|
||||
|
||||
###############
|
||||
# Linux build #
|
||||
###############
|
||||
|
||||
linux : CC = clang |
||||
linux : CPPC = clang++ |
||||
linux : CFLAGS = -g -Wall -Wextra -O0 -c -I$(SB_LIB_DIR) -I$(SB_SRC_DIR) $(SDL_CFLAGS) |
||||
linux : CPP_FLAGS = $(CFLAGS) --std=c++17 |
||||
linux : LFLAGS = $(SDL_LFLAGS) -lpthread -lGL -lGLESv2 -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lstdc++fs |
||||
linux : $(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) \
|
||||
$(SB_O_FILES) $(SRC_O_FILES)
|
||||
$(CREATE_FONT_SYMLINK)
|
||||
$(CPPC) $(LFLAGS) -D__LINUX__ $^ -o pepy
|
||||
|
||||
#############
|
||||
# Web build #
|
||||
#############
|
||||
|
||||
# Use Emscripten to output JavaScript and an HTML index page for running in the browser
|
||||
|
||||
EMSCRIPTENHOME = $(HOME)/ext/software/emsdk/upstream/emscripten
|
||||
EMSCRIPTEN_CFLAGS = -O3 -Wall -s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="['png']" -s USE_SDL_TTF=2 \
|
||||
-s USE_SDL_MIXER=2 -s SDL2_MIXER_FORMATS="['ogg','mp3']" -s USE_OGG=1 -s USE_VORBIS=1 -s USE_MPG123=1 \
|
||||
-s USE_MODPLUG=1 --no-heap-copy -I$(SB_LIB_DIR) -I$(SB_SRC_DIR)
|
||||
EMSCRIPTEN_LFLAGS = -s MIN_WEBGL_VERSION=2 -s EXPORTED_FUNCTIONS="['_main']" -s ALLOW_MEMORY_GROWTH=1 -s FULL_ES3=1 --shell-file shell.html
|
||||
EMSCRIPTEN_PRELOADS = --preload-file "BPmono.ttf"@/ --preload-file "config.json"@/ --preload-file "resource/"@/"resource/" \
|
||||
--preload-file "src/shader.vert"@/"src/" --preload-file "src/shader.frag"@/"src/"
|
||||
|
||||
emscripten : CC = $(EMSCRIPTENHOME)/emcc |
||||
emscripten : CPPC = $(EMSCRIPTENHOME)/em++ |
||||
emscripten : CFLAGS = $(EMSCRIPTEN_CFLAGS) |
||||
emscripten : CPP_FLAGS = $(CFLAGS) --std=c++17 |
||||
emscripten : $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) $(SB_O_FILES) $(SRC_O_FILES) |
||||
$(CREATE_FONT_SYMLINK)
|
||||
$(CPPC) $(CPP_FLAGS) $(EMSCRIPTEN_LFLAGS) $(EMSCRIPTEN_PRELOADS) $^ -o "index.html"
|
||||
|
||||
#########################
|
||||
# Clean up object files #
|
||||
#########################
|
||||
|
||||
clean : |
||||
-rm $(SRC_DIR)*.o
|
||||
|
||||
clean-all : |
||||
-find . -iname "*.o" -exec rm {} \;
|
||||
|
||||
#############
|
||||
# compiledb #
|
||||
#############
|
||||
|
||||
# Generate a clang JSON compilation database file. This can be useful for example for code completion. It requires a
|
||||
# compiledb binary (https://pypi.org/project/compiledb/). It should be generated manually every time a file is added,
|
||||
# renamed, or the compilation flags change. The generated database is based on the Linux build.
|
||||
|
||||
PATH_TO_COMPILEDB = $(HOME)/.local/bin/compiledb
|
||||
compiledb : |
||||
-$(PATH_TO_COMPILEDB) -n make linux -k
|
||||
|
||||
#####################
|
||||
# cross compilation #
|
||||
#####################
|
||||
|
||||
# WARNING: untested
|
||||
|
||||
# Below assignments and targets are necessary for cross-compiling to Android, web (via emscripten), Windows (via mingw),
|
||||
# and OS/X, but cross-compilation targets have not been tested in a while and won't compile without significant changes.
|
||||
|
||||
BUILDDIR := build
|
||||
SDLHOME := $(EXT_SRC_ROOT)/SDL2-2.0.14
|
||||
SDL_IMG_HOME := $(EXT_SRC_ROOT)/SDL2_image-2.0.4
|
||||
SDL_TTF_HOME := $(EXT_SRC_ROOT)/SDL2_ttf-2.0.14
|
||||
GLEW_WIN32_HOME = $(EXT_SRC_ROOT)/glew-2.1.0-win32
|
||||
PROJECTHOME = $(shell pwd)
|
||||
WINBUILDDIR = win
|
||||
SDLMINGWHOME = $(SDLHOME)/i686-w64-mingw32
|
||||
SDL_IMG_MINGW_HOME = $(SDL_IMG_HOME)/i686-w64-mingw32
|
||||
SDL_TTF_MINGW_HOME = $(SDL_TTF_HOME)/i686-w64-mingw32
|
||||
APPDIR = Main.app/Contents
|
||||
SYSFWPATH = /Library/Frameworks
|
||||
|
||||
android : |
||||
if [ ! -d $(BUILDDIR) ]; then mkdir $(BUILDDIR); fi;
|
||||
cd $(SDLHOME)/build-scripts/ && \
|
||||
./androidbuild.sh $(ANDROIDPROJECT) $(PROJECTHOME)/main.cpp
|
||||
cp -r $(SDLHOME)/build/$(ANDROIDPROJECT) $(BUILDDIR)
|
||||
sed -i s/2\.3\.3/2\.2\.3/g $(BUILDDIR)/$(ANDROIDPROJECT)/build.gradle
|
||||
sed -i s/26\.0\.1/23\.0\.1/g $(BUILDDIR)/$(ANDROIDPROJECT)/app/build.gradle
|
||||
cd $(BUILDDIR)/$(ANDROIDPROJECT) && ./gradlew assembleDebug
|
||||
|
||||
mingw : |
||||
if [ ! -d $(BUILDDIR)/$(WINBUILDDIR) ]; then mkdir -p $(BUILDDIR)/$(WINBUILDDIR); fi;
|
||||
cd $(BUILDDIR)/$(WINBUILDDIR) && \
|
||||
i686-w64-mingw32-g++ -std=c++17 $(PROJECTHOME)/main.cpp -I$(SDLMINGWHOME)/include/SDL2 \
|
||||
-I$(SDL_IMG_MINGW_HOME)/include/SDL2 -I$(SDL_TTF_MINGW_HOME)/include/SDL2 $(INC) \
|
||||
$(PROJECTHOME)/sdl2-gfx/SDL2_gfxPrimitives.c $(PROJECTHOME)/sdl2-gfx/SDL2_rotozoom.c $(PROJECTHOME)/glew/glew.c \
|
||||
-L$(SDLMINGWHOME)/lib -L$(SDL_IMG_MINGW_HOME)/lib -L$(SDL_TTF_MINGW_HOME)/lib \
|
||||
-lmingw32 -lSDL2_image \
|
||||
-lSDL2_ttf -lstdc++fs \
|
||||
-lSDL2main -lSDL2 -lopengl32 -Wall -O2 -o main.exe && \
|
||||
cp $(SDLMINGWHOME)/bin/SDL2.dll $(SDL_IMG_MINGW_HOME)/bin/SDL2_image.dll \
|
||||
$(SDL_TTF_MINGW_HOME)/bin/SDL2_ttf.dll .
|
||||
|
||||
osx : |
||||
g++ -I $(SYSFWPATH)/SDL2.framework/Headers $(INC) \
|
||||
-I $(SYSFWPATH)/SDL2_image.framework/Headers -Wl,-rpath,$(SYSFWPATH) \
|
||||
-framework SDL2 -framework SDL2_image -framework OpenGL main.cpp sdl2-gfx/SDL2_rotozoom.c \
|
||||
-o main
|
||||
|
||||
osx-bundle : |
||||
if [ ! -d "$(APPDIR)" ]; then mkdir -p $(APPDIR); fi;
|
||||
if [ ! -d "$(APPDIR)" ]; then mkdir $(APPDIR); fi;
|
||||
if [ ! -d "$(APPDIR)/MacOS" ]; then mkdir $(APPDIR)/MacOS; fi;
|
||||
if [ ! -d "$(APPDIR)/Frameworks" ]; then mkdir $(APPDIR)/Frameworks; fi;
|
||||
if [ ! -d "$(APPDIR)/Resources" ]; then mkdir $(APPDIR)/Resources; fi;
|
||||
touch $(APPDIR)/Info.plist
|
||||
cp -r $(SYSFWPATH)/SDL2.framework $(APPDIR)/Frameworks
|
||||
cp -r $(SYSFWPATH)/SDL2_image.framework $(APPDIR)/Frameworks
|
||||
g++ -I $(SYSFWPATH)/SDL2.framework/Headers -I $(SYSFWPATH)/SDL2_image.framework/Headers \
|
||||
-Wl,-rpath,@executable_path/../Frameworks -Wl,-rpath,$(SYSFWPATH) \
|
||||
-framework SDL2 -framework SDL2_image -framework OpenGL main.cpp -o $(APPDIR)/MacOS/main
|
||||
|
||||
cross : linux android emscripten mingw |
@ -0,0 +1,38 @@
|
||||
{ |
||||
"display": |
||||
{ |
||||
"dimensions": [960, 540], |
||||
"framerate": 60, |
||||
"title": "Pepy", |
||||
"debug": false, |
||||
"render driver": "opengles3", |
||||
"show-cursor": true |
||||
}, |
||||
"configuration": |
||||
{ |
||||
"auto-refresh": true |
||||
}, |
||||
"keys": |
||||
{ |
||||
}, |
||||
"input": |
||||
{ |
||||
"any-key-ignore-commands": ["up", "right", "down", "left"], |
||||
"suppress-any-key-on-mods": true |
||||
}, |
||||
"log": |
||||
{ |
||||
"enabled": true, |
||||
"output-directory": "/var/log/sb/", |
||||
"debug-to-stdout": false, |
||||
"debug-to-file": true, |
||||
"info-file-name": "cuckoo_info.log", |
||||
"debug-file-name": "cuckoo_debug.log" |
||||
}, |
||||
"sim": |
||||
{ |
||||
"wall-count": 48, |
||||
"ball-scale": 0.15, |
||||
"spawn-radius": 0.35 |
||||
} |
||||
} |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 349 KiB |
After Width: | Height: | Size: 95 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 471 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 284 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 157 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 33 KiB |
@ -0,0 +1,180 @@
|
||||
<!doctype html> |
||||
<html lang="en-us"> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
||||
<title>B.U.D.D.I.</title> |
||||
<style> |
||||
@import url("../../lib/fonts/notcouriersans/regular/style.css"); |
||||
body {margin: 0; padding: 0} |
||||
.emscripten { display: block; } |
||||
textarea.emscripten { font-family: NotCourierSans; font-size: 24px; width: 960px; resize: none; border: 0px; overflow:hidden } |
||||
div.emscripten_border { border: 0px solid black; } |
||||
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */ |
||||
canvas.emscripten |
||||
{ |
||||
border: 0px none; |
||||
background-color: black; |
||||
width: 960px; |
||||
height: 540px; |
||||
} |
||||
.spinner { |
||||
margin: auto; |
||||
height: 50px; |
||||
width: 50px; |
||||
-webkit-animation: rotation .8s linear infinite; |
||||
-moz-animation: rotation .8s linear infinite; |
||||
-o-animation: rotation .8s linear infinite; |
||||
animation: rotation 0.8s linear infinite; |
||||
border-left: 10px solid rgb(0,150,240); |
||||
border-right: 10px solid rgb(0,150,240); |
||||
border-bottom: 10px solid rgb(0,150,240); |
||||
border-top: 10px solid rgb(100,0,200); |
||||
border-radius: 100%; |
||||
background-color: rgb(200,100,250); |
||||
} |
||||
div#loading |
||||
{ |
||||
text-align: center; |
||||
position: absolute; |
||||
top: 90px; |
||||
width: 960px; |
||||
color: #fff; |
||||
font-size: 22px; |
||||
} |
||||
@-webkit-keyframes rotation { |
||||
from {-webkit-transform: rotate(0deg);} |
||||
to {-webkit-transform: rotate(360deg);} |
||||
} |
||||
@-moz-keyframes rotation { |
||||
from {-moz-transform: rotate(0deg);} |
||||
to {-moz-transform: rotate(360deg);} |
||||
} |
||||
@-o-keyframes rotation { |
||||
from {-o-transform: rotate(0deg);} |
||||
to {-o-transform: rotate(360deg);} |
||||
} |
||||
@keyframes rotation { |
||||
from {transform: rotate(0deg);} |
||||
to {transform: rotate(360deg);} |
||||
} |
||||
div#game |
||||
{ |
||||
position: relative; |
||||
width: 960px; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<div> |
||||
<image style="width: 140px" src="resource/wad/Mike/0.png">Pepy, it's cuckoo time! Please make it as big as possible using the arrow keys in |
||||
10 seconds. |
||||
</div> |
||||
<div id="game"> |
||||
<div id="loading"> |
||||
<figure style="overflow:visible;" id="spinner"><div class="spinner"></div></figure> |
||||
<div class="emscripten" id="status">Downloading...</div> |
||||
<div class="emscripten"> |
||||
<progress value="0" max="100" id="progress" hidden=1></progress> |
||||
</div> |
||||
</div> |
||||
<div class="emscripten_border"> |
||||
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas> |
||||
</div> |
||||
</div> |
||||
<textarea class="emscripten" id="output" rows="8" readonly spellcheck="false" wrap="off"></textarea> |
||||
<img src="resource/Book_of_Pepy/walking_pepy_london.png" /><br /> |
||||
<img src="resource/Book_of_Pepy/1071003012.jpg" /><br /> |
||||
<img src="resource/Book_of_Pepy/129548486_1656033331242674_6748215393958512364_n.jpg" /><br /> |
||||
<img src="resource/Book_of_Pepy/1gfxra.jpg" /><br /> |
||||
<img src="resource/Book_of_Pepy/b89d70e6fb9c4caaed2e797f01bb7575.jpg" /><br /> |
||||
<img src="resource/Book_of_Pepy/cat-party-hat-eats-fish-burger-beige-multi-colored-eating-big-fresh-white-square-plate-drinking-beer-table-183867588.jpg" /><br /> |
||||
<img src="resource/Book_of_Pepy/E6IhBxRXIAETJ29.jpeg" /><br /> |
||||
<img src="resource/Book_of_Pepy/E9GrqOlWYAE2Sgw.jpeg" /><br /> |
||||
<img src="resource/Book_of_Pepy/Ea1zDCEUwAAKUcF.jpeg" /><br /> |
||||
<img src="resource/Book_of_Pepy/EcrFXg5VcAE6tK6.jpeg" /><br /> |
||||
<img src="resource/Book_of_Pepy/Japanese-chocolate-whisky-Morinaga-twig-big-Koeda-whisky-pairing-buy-special-drink-review-photos-4.webp" /><br /> |
||||
<img src="resource/Book_of_Pepy/large.webp" /><br /> |
||||
<img src="resource/Book_of_Pepy/Lenny-Face.png" /><br /> |
||||
<img src="resource/Book_of_Pepy/necropolis_of_Pepy.png" /><br /> |
||||
<img src="resource/Book_of_Pepy/vz-ff8724ba-584e-4f9d-bae5-f7c15e462512.jpeg" /><br /> |
||||
<script type='text/javascript'> |
||||
var statusElement = document.getElementById('status'); |
||||
var progressElement = document.getElementById('progress'); |
||||
var spinnerElement = document.getElementById('spinner'); |
||||
|
||||
var Module = { |
||||
preRun: [], |
||||
postRun: [], |
||||
print: (function() { |
||||
var element = document.getElementById('output'); |
||||
if (element) element.value = ''; // clear browser cache |
||||
return function(text) { |
||||
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); |
||||
// These replacements are necessary if you render to raw HTML |
||||
//text = text.replace(/&/g, "&"); |
||||
//text = text.replace(/</g, "<"); |
||||
//text = text.replace(/>/g, ">"); |
||||
//text = text.replace('\n', '<br>', 'g'); |
||||
console.log(text); |
||||
if (element) { |
||||
element.value += text + "\n"; |
||||
element.scrollTop = element.scrollHeight; // focus on bottom |
||||
} |
||||
}; |
||||
})(), |
||||
printErr: function(text) { |
||||
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); |
||||
console.error(text); |
||||
}, |
||||
canvas: (function() { |
||||
var canvas = document.getElementById('canvas'); |
||||
|
||||
// As a default initial behavior, pop up an alert when webgl context is lost. To make your |
||||
// application robust, you may want to override this behavior before shipping! |
||||
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 |
||||
canvas.addEventListener("webglcontextlost", function(e) { |
||||
alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); |
||||
|
||||
return canvas; |
||||
})(), |
||||
setStatus: function(text) { |
||||
if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' }; |
||||
if (text === Module.setStatus.last.text) return; |
||||
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); |
||||
var now = Date.now(); |
||||
if (m && now - Module.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon |
||||
Module.setStatus.last.time = now; |
||||
Module.setStatus.last.text = text; |
||||
if (m) { |
||||
text = m[1]; |
||||
progressElement.value = parseInt(m[2])*100; |
||||
progressElement.max = parseInt(m[4])*100; |
||||
progressElement.hidden = false; |
||||
spinnerElement.hidden = false; |
||||
} else { |
||||
progressElement.value = null; |
||||
progressElement.max = null; |
||||
progressElement.hidden = true; |
||||
if (!text) spinnerElement.hidden = true; |
||||
} |
||||
statusElement.innerHTML = text; |
||||
}, |
||||
totalDependencies: 0, |
||||
monitorRunDependencies: function(left) { |
||||
this.totalDependencies = Math.max(this.totalDependencies, left); |
||||
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.'); |
||||
} |
||||
}; |
||||
Module.setStatus('Downloading...'); |
||||
window.onerror = function() { |
||||
Module.setStatus('Exception thrown, see JavaScript console'); |
||||
spinnerElement.style.display = 'none'; |
||||
Module.setStatus = function(text) { |
||||
if (text) Module.printErr('[post-exception status] ' + text); |
||||
}; |
||||
}; |
||||
</script> |
||||
{{{ SCRIPT }}} |
||||
</body> |
||||
</html> |
@ -0,0 +1,160 @@
|
||||
/* Cuckoo by @ohsqueezy [ohsqueezy.itch.io] */ |
||||
|
||||
#include "Model.hpp" |
||||
|
||||
/* Default constructor for Model */ |
||||
Model::Model() {}; |
||||
|
||||
/* Construct a Model, adding Attributes each already wrapped in a shared pointer. The attributes should
|
||||
* be passed as a map with each key being a name and each value being a shared pointer to attributes. */ |
||||
Model::Model(const std::map<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; |
||||
} |
@ -0,0 +1,75 @@
|
||||
/* Cuckoo by @ohsqueezy [ohsqueezy.itch.io] */ |
||||
|
||||
#ifndef MODEL_H_ |
||||
#define MODEL_H_ |
||||
|
||||
/* GL functions */ |
||||
#if defined(__EMSCRIPTEN__) |
||||
#include <GL/glew.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}})) {} |
||||
|
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,383 @@
|
||||
/* Pepy by @ohsqueezy [ohsqueezy.itch.io] */ |
||||
|
||||
#include "Pepy.hpp" |
||||
|
||||
/* Launch the Pepy instance's mainloop */ |
||||
int main() |
||||
{ |
||||
Pepy pepy = Pepy(); |
||||
pepy.run(); |
||||
pepy.quit(); |
||||
return 0; |
||||
} |
||||
|
||||
/* Initialize a Pepy instance */ |
||||
Pepy::Pepy() |
||||
{ |
||||
/* subscribe to command events */ |
||||
get_delegate().subscribe(&Pepy::respond, this); |
||||
get_delegate().subscribe(&Pepy::respond, this, SDL_MOUSEBUTTONDOWN); |
||||
get_delegate().subscribe(&Pepy::respond, this, SDL_MOUSEBUTTONUP); |
||||
/* create a glowing ring */ |
||||
int point_count = configuration()["sim"]["wall-count"].get<int>() + 1; |
||||
std::vector<glm::vec2> outer_points = sb::points_on_circle(point_count, 0.75f, {0.0f, 0.0f}); |
||||
std::vector<glm::vec2> inner_points = sb::points_on_circle(point_count, 0.65f, {0.0f, 0.0f}); |
||||
float inner_saturation = 0.1f; |
||||
float inner_value = 1.0f; |
||||
float outer_saturation = 1.0f; |
||||
float outer_value = 0.1f; |
||||
int next; |
||||
for (int ii = 0; ii <= point_count; ii++) |
||||
{ |
||||
next = (ii + 1) % point_count; |
||||
cuckoo["position"]->add(outer_points[ii]); |
||||
cuckoo["position"]->add(outer_points[next]); |
||||
cuckoo["position"]->add(inner_points[ii]); |
||||
cuckoo["position"]->add(inner_points[ii]); |
||||
cuckoo["position"]->add(inner_points[next]); |
||||
cuckoo["position"]->add(outer_points[next]); |
||||
cuckoo["color"]->add(glm::rgbColor(glm::vec3(ii / static_cast<float>(point_count) * 255.0f, outer_saturation, outer_value))); |
||||
cuckoo["color"]->add(glm::rgbColor(glm::vec3(next / static_cast<float>(point_count) * 255.0f, outer_saturation, outer_value))); |
||||
cuckoo["color"]->add(glm::rgbColor(glm::vec3(ii / static_cast<float>(point_count) * 255.0f, inner_saturation, inner_value))); |
||||
cuckoo["color"]->add(glm::rgbColor(glm::vec3(ii / static_cast<float>(point_count) * 255.0f, inner_saturation, inner_value))); |
||||
cuckoo["color"]->add(glm::rgbColor(glm::vec3(next / static_cast<float>(point_count) * 255.0f, inner_saturation, inner_value))); |
||||
cuckoo["color"]->add(glm::rgbColor(glm::vec3(next / static_cast<float>(point_count) * 255.0f, outer_saturation, outer_value))); |
||||
} |
||||
/* create balls */ |
||||
float size = configuration()["sim"]["ball-scale"]; |
||||
auto spawn_points = sb::points_on_circle(5, configuration()["sim"]["spawn-radius"]); |
||||
for (auto spawn_point : spawn_points) |
||||
{ |
||||
Plane ball; |
||||
ball.transformation(glm::translate(glm::vec3{spawn_point.x, spawn_point.y, 1.0f}) * glm::scale(glm::vec3{size, size, 1.0f})); |
||||
wad.push_back(std::pair{ball, glm::vec2{0.0f, 0.0f}}); |
||||
} |
||||
background.transformation(glm::scale(glm::vec3{5.0f, 5.0f, 1.0f})); |
||||
/* load Open GL */ |
||||
load_gl_context(); |
||||
/* load wad textures */ |
||||
sb::Texture wad_texture {"resource/wad.png"}; |
||||
wad_texture.load(); |
||||
/* Apply the wad texture to each wad */ |
||||
for (size_t wad_ii = 0; wad_ii < wad.size(); wad_ii++) |
||||
{ |
||||
wad[wad_ii].first.texture(wad_texture); |
||||
} |
||||
sb::Texture texture {"resource/space.png"}; |
||||
texture.load(); |
||||
background.texture(texture); |
||||
} |
||||
|
||||
/* Create GL context via super class and load vertices, UV data, and shaders */ |
||||
void Pepy::load_gl_context() |
||||
{ |
||||
super::load_gl_context(); |
||||
cuckoo_vao.generate(); |
||||
wad_vao.generate(); |
||||
cuckoo_vao.bind(); |
||||
/* Generate ID for the vertex buffer object that will hold vertex data. Because there is one buffer, data
|
||||
* will be copied in one after the other, offset to after the previous location. */ |
||||
vbo.generate(); |
||||
vbo.bind(); |
||||
vbo.allocate(cuckoo.size() + wad[0].first.size(), GL_STATIC_DRAW); |
||||
GLuint vertex_shader = load_shader("src/shader.vert", GL_VERTEX_SHADER); |
||||
GLuint fragment_shader = load_shader("src/shader.frag", GL_FRAGMENT_SHADER); |
||||
shader = glCreateProgram(); |
||||
glAttachShader(shader, vertex_shader); |
||||
glAttachShader(shader, fragment_shader); |
||||
sb::Log::gl_errors("after attaching shaders"); |
||||
cuckoo.attributes("position")->bind(0, shader, "vertex_position"); |
||||
cuckoo.attributes("color")->bind(1, shader, "vertex_color"); |
||||
vbo.add(*cuckoo.attributes("position")); |
||||
vbo.add(*cuckoo.attributes("color")); |
||||
wad_vao.bind(); |
||||
wad[0].first.attributes("position")->bind(0, shader, "vertex_position"); |
||||
wad[0].first.attributes("uv")->bind(2, shader, "vertex_uv"); |
||||
vbo.add(*wad[0].first.attributes("position")); |
||||
vbo.add(*wad[0].first.attributes("uv")); |
||||
sb::Log::gl_errors("after VBO allocation"); |
||||
link_shader(shader); |
||||
uniform["blend"] = glGetUniformLocation(shader, "blend_min_hsv"); |
||||
uniform["orthographic_projection"] = glGetUniformLocation(shader, "orthographic_projection"); |
||||
uniform["model_transformation"] = glGetUniformLocation(shader, "model_transformation"); |
||||
uniform["base_texture"] = glGetUniformLocation(shader, "base_texture"); |
||||
uniform["textured"] = glGetUniformLocation(shader, "textured"); |
||||
uniform["scroll"] = glGetUniformLocation(shader, "scroll"); |
||||
uniform["time"] = glGetUniformLocation(shader, "time"); |
||||
sb::Log::gl_errors("after uniforms"); |
||||
/* enable alpha rendering */ |
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
||||
glEnable(GL_BLEND); |
||||
sb::Log::gl_errors("at end of load context"); |
||||
} |
||||
|
||||
void Pepy::respond(SDL_Event& event) |
||||
{ |
||||
/* Will check if reset should be triggered */ |
||||
bool reset = false; |
||||
/* Check for any direction when waiting to reset */ |
||||
if (stopped && delegate.compare(event, {"up", "down", "left", "right"})) |
||||
{ |
||||
reset = true; |
||||
} |
||||
if (event.type == SDL_MOUSEBUTTONDOWN) |
||||
{ |
||||
if (shaking) |
||||
{ |
||||
grabbed = true; |
||||
} |
||||
/* Mouse button will trigger reset when stopped */ |
||||
else if (stopped) |
||||
{ |
||||
reset = true; |
||||
} |
||||
} |
||||
else if (event.type == SDL_MOUSEBUTTONUP && shaking) |
||||
{ |
||||
grabbed = false; |
||||
} |
||||
/* Reset to countdown */ |
||||
if (reset) |
||||
{ |
||||
float size = configuration()["sim"]["ball-scale"]; |
||||
auto spawn_points = sb::points_on_circle(5, configuration()["sim"]["spawn-radius"]); |
||||
int ii = 0; |
||||
for (auto& ball : wad) |
||||
{ |
||||
ball.first.transformation(glm::translate(glm::vec3{spawn_points[ii].x, spawn_points[ii++].y, 1.0f}) * glm::scale(glm::vec3{size, size, 1.0f})); |
||||
} |
||||
stopped = false; |
||||
shaking = true; |
||||
} |
||||
} |
||||
|
||||
/* Update state and draw the screen */ |
||||
void Pepy::update() |
||||
{ |
||||
/* number of seconds running */ |
||||
time_seconds = SDL_GetTicks() / 1000.0f; |
||||
if (shaking) |
||||
{ |
||||
countdown -= last_frame_length / 1000.0f; |
||||
if (countdown < 0.0f) |
||||
{ |
||||
shaking = false; |
||||
flying = true; |
||||
countdown = 10.0f; |
||||
} |
||||
} |
||||
/* move cuckoo with mouse */ |
||||
if (grabbed && shaking) |
||||
{ |
||||
/* get mouse coordinates in NDC */ |
||||
SDL_GetMouseState(&mouse_pixel.x, &mouse_pixel.y); |
||||
glm::vec2 mouse_ndc { |
||||
static_cast<float>(mouse_pixel.x) / window_box().width() * 2.0f - 1.0f, |
||||
(1.0f - static_cast<float>(mouse_pixel.y) / window_box().height()) * 2.0f - 1.0f |
||||
}; |
||||
cuckoo_offset.x += weight(mouse_ndc.x / 20.0f) * std::max(std::min(std::abs(1.0f - cuckoo_offset.x), 1.0f), 0.1f); |
||||
cuckoo_offset.y += weight(mouse_ndc.y / 20.0f) * std::max(std::min(std::abs(1.0f - cuckoo_offset.y), 1.0f), 0.1f); |
||||
} |
||||
else |
||||
{ |
||||
/* move cuckoo with keys */ |
||||
const std::uint8_t* state = SDL_GetKeyboardState(nullptr); |
||||
float motion = weight(1 / 25.0f), diagonal = motion * std::sin(glm::pi<float>() * 0.25f); |
||||
if (state[SDL_SCANCODE_UP]) |
||||
{ |
||||
if (state[SDL_SCANCODE_RIGHT]) |
||||
{ |
||||
cuckoo_offset.x += diagonal; |
||||
cuckoo_offset.y += diagonal; |
||||
} |
||||
else if (state[SDL_SCANCODE_LEFT]) |
||||
{ |
||||
cuckoo_offset.x -= diagonal; |
||||
cuckoo_offset.y += diagonal; |
||||
} |
||||
else |
||||
{ |
||||
cuckoo_offset.y += motion; |
||||
} |
||||
} |
||||
else if (state[SDL_SCANCODE_RIGHT]) |
||||
{ |
||||
if (state[SDL_SCANCODE_DOWN]) |
||||
{ |
||||
cuckoo_offset.x += diagonal; |
||||
cuckoo_offset.y -= diagonal; |
||||
} |
||||
else |
||||
{ |
||||
cuckoo_offset.x += motion; |
||||
} |
||||
} |
||||
else if (state[SDL_SCANCODE_DOWN]) |
||||
{ |
||||
if (state[SDL_SCANCODE_LEFT]) |
||||
{ |
||||
cuckoo_offset.x -= diagonal; |
||||
cuckoo_offset.y -= diagonal; |
||||
} |
||||
else |
||||
{ |
||||
cuckoo_offset.y -= motion; |
||||
} |
||||
} |
||||
else if (state[SDL_SCANCODE_LEFT]) |
||||
{ |
||||
cuckoo_offset.x -= motion; |
||||
} |
||||
} |
||||
cuckoo_offset.x -= weight(glm::sign(cuckoo_offset).x * return_speed); |
||||
cuckoo_offset.y -= weight(glm::sign(cuckoo_offset).y * return_speed); |
||||
cuckoo.transformation(glm::translate(cuckoo_offset)); |
||||
hue_offset += weight(0.002f); |
||||
glm::vec2 x_range = {-1.0f, 1.0f}; |
||||
glm::vec2 y_range = {-1.0f, 1.0f}; |
||||
/* move wad */ |
||||
bool all_stopped = true; |
||||
for (auto& ball : wad) |
||||
{ |
||||
const glm::vec2& ball_center = {ball.first.transformation()[3].x, ball.first.transformation()[3].y}; |
||||
const glm::vec2& cuckoo_center = {cuckoo.transformation()[3].x, cuckoo.transformation()[3].y}; |
||||
float distance = glm::distance(ball_center, cuckoo_center); |
||||
if (shaking) |
||||
{ |
||||
if (distance > 0.65f) |
||||
{ |
||||
float angle = glm::atan(cuckoo_center.y - ball_center.y, cuckoo_center.x - ball_center.x); |
||||
ball.second.y += 0.0005f; |
||||
ball.second.x = angle + glm::half_pi<float>(); |
||||
} |
||||
} |
||||
glm::vec2 step {glm::sin(ball.second.x) * ball.second.y, -glm::cos(ball.second.x) * ball.second.y}; |
||||
ball.first.transformation(glm::translate(glm::vec3{step.x, step.y, 0.0f}) * ball.first.transformation()); |
||||
if (ball.second.y > 0) |
||||
{ |
||||
float friction; |
||||
if (shaking) |
||||
{ |
||||
friction = 0.00005f; |
||||
} |
||||
else |
||||
{ |
||||
friction = 0.0001f; |
||||
} |
||||
ball.second.y = std::max(0.0f, ball.second.y - friction); |
||||
} |
||||
if (ball_center.x < x_range[0]) |
||||
{ |
||||
x_range[0] = ball_center.x - 0.1f; |
||||
} |
||||
else if (ball_center.x > x_range[1]) |
||||
{ |
||||
x_range[1] = ball_center.x + 0.1f; |
||||
} |
||||
if (ball_center.y < y_range[0]) |
||||
{ |
||||
y_range[0] = ball_center.y - 0.1f; |
||||
} |
||||
else if (ball_center.y > y_range[1]) |
||||
{ |
||||
y_range[1] = ball_center.y + 0.1f; |
||||
} |
||||
if (ball.second.y > 0.0f) |
||||
{ |
||||
all_stopped = false; |
||||
} |
||||
} |
||||
if (all_stopped && flying) |
||||
{ |
||||
flying = false; |
||||
stopped = true; |
||||
glm::vec2 sum {0.0f, 0.0f}; |
||||
std::vector<glm::vec2> centers; |
||||
for (auto& ball : wad) |
||||
{ |
||||
const glm::vec2& ball_center = {ball.first.transformation()[3].x, ball.first.transformation()[3].y}; |
||||
centers.push_back(ball_center); |
||||
sum += ball_center; |
||||
} |
||||
glm::vec2 centroid = sum / wad.size(); |
||||
angle_sort sorter {centroid, centers[0]}; |
||||
std::sort(centers.begin(), centers.end(), sorter); |
||||
float area = 0.0f; |
||||
for (std::size_t center_ii = 0; center_ii < centers.size() - 1; center_ii++) |
||||
{ |
||||
area += centers[center_ii].x * centers[center_ii + 1].y - centers[center_ii + 1].x * centers[center_ii].y; |
||||
} |
||||
area += centers[centers.size() - 1].x * centers[0].y - centers[0].x * centers[centers.size() - 1].y; |
||||
area = std::abs(area) / 2.0f; |
||||
std::cout << "Your score (size) is " << area << ". Press arrow key to play again." << std::endl; |
||||
} |
||||
/* paint over screen */ |
||||
glClearColor(0, 0, 0, 1); |
||||
sb::Log::gl_errors("after setting clear color"); |
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
||||
sb::Log::gl_errors("after clearing screen"); |
||||
glUseProgram(shader); |
||||
sb::Log::gl_errors("after using program"); |
||||
/* set orthographic project for viewing entire scene at normalized screen ratio */ |
||||
aspect_ratio = window_box().aspect(true); |
||||
if (window_box().width() > window_box().height()) |
||||
{ |
||||
orthographic_projection = glm::ortho(aspect_ratio * x_range[0], aspect_ratio * x_range[1], y_range[0], y_range[1]); |
||||
} |
||||
else |
||||
{ |
||||
orthographic_projection = glm::ortho(x_range[0], x_range[1], aspect_ratio * y_range[0], aspect_ratio * y_range[1]); |
||||
} |
||||
glUniformMatrix4fv(uniform["orthographic_projection"], 1, GL_FALSE, &orthographic_projection[0][0]); |
||||
sb::Log::gl_errors("after setting orthographic projection"); |
||||
/* draw background */ |
||||
wad_vao.bind(); |
||||
glUniform3f(uniform["blend"], hue_offset, 0.0f, 1.0f); |
||||
glUniform1i(uniform["textured"], true); |
||||
glUniform1i(uniform["scroll"], true); |
||||
glUniform1f(uniform["time"], time_seconds); |
||||
glUniform1i(uniform["base_texture"], 0); |
||||
glActiveTexture(GL_TEXTURE0); |
||||
background.texture().bind(); |
||||
glUniformMatrix4fv(uniform["model_transformation"], 1, GL_FALSE, reinterpret_cast<const GLfloat*>(&background.transformation()[0][0])); |
||||
background.enable(); |
||||
glDrawArrays(GL_TRIANGLES, 0, background.attributes("position")->count()); |
||||
background.disable(); |
||||
/* draw wad */ |
||||
wad_vao.bind(); |
||||
glUniform3f(uniform["blend"], 0.0f, 0.0f, 1.0f); |
||||
glUniform1i(uniform["textured"], true); |
||||
glUniform1i(uniform["scroll"], false); |
||||
sb::Log::gl_errors("after setting blending and textured flag"); |
||||
for (std::pair<Plane, glm::vec2>& ball : wad) |
||||
{ |
||||
glUniform1i(uniform["base_texture"], 0); |
||||
sb::Log::gl_errors("after setting texture uniform"); |
||||
glActiveTexture(GL_TEXTURE0); |
||||
sb::Log::gl_errors("after activating texture"); |
||||
ball.first.texture().bind(); |
||||
sb::Log::gl_errors("after binding wad"); |
||||
glUniformMatrix4fv(uniform["model_transformation"], 1, GL_FALSE, reinterpret_cast<const GLfloat*>(&ball.first.transformation()[0][0])); |
||||
ball.first.enable(); |
||||
glDrawArrays(GL_TRIANGLES, 0, ball.first.attributes("position")->count()); |
||||
ball.first.disable(); |
||||
sb::Log::gl_errors("after drawing wad"); |
||||
} |
||||
/* draw cuckoo */ |
||||
if (shaking || stopped) |
||||
{ |
||||
cuckoo_vao.bind(); |
||||
glUniform3f(uniform["blend"], hue_offset, 0.5f, 1.0f); |
||||
glUniform1i(uniform["textured"], false); |
||||
glUniformMatrix4fv(uniform["model_transformation"], 1, GL_FALSE, reinterpret_cast<const GLfloat*>(&cuckoo.transformation()[0][0])); |
||||
cuckoo.enable(); |
||||
glDrawArrays(GL_TRIANGLES, 0, cuckoo.attributes("position")->count()); |
||||
cuckoo.disable(); |
||||
} |
||||
SDL_GL_SwapWindow(window()); |
||||
sb::Log::gl_errors("at end of update"); |
||||
if (shaking) |
||||
{ |
||||
std::cout << countdown << std::endl; |
||||
} |
||||
} |
@ -0,0 +1,85 @@
|
||||
/* Pepy by @ohsqueezy [ohsqueezy.itch.io] */ |
||||
|
||||
#ifndef PEPY_H_ |
||||
#define PEPY_H_ |
||||
|
||||
/* Enable swizzling in GLM */ |
||||
#define GLM_ENABLE_EXPERIMENTAL |
||||
#include <glm/glm.hpp> |
||||
#include <glm/gtx/compatibility.hpp> |
||||
|
||||
/* [SPACE BOX] headers */ |
||||
#include "Game.hpp" |
||||
#include "VBO.hpp" |
||||
|
||||
/* Project headers */ |
||||
#include "Model.hpp" |
||||
|
||||
class angle_sort |
||||
{ |
||||
glm::vec2 m_origin; |
||||
glm::vec2 m_dreference; |
||||
|
||||
// z-coordinate of cross-product, aka determinant
|
||||
static double xp(glm::vec2 a, glm::vec2 b) { return a.x * b.y - a.y * b.x; } |
||||
|
||||
public: |
||||
|
||||
angle_sort(const glm::vec2 origin, const glm::vec2 reference) : m_origin(origin), m_dreference(reference - origin) {} |
||||
|
||||
bool operator()(const glm::vec2 a, const glm::vec2 b) const |
||||
{ |
||||
const glm::vec2 da = a - m_origin, db = b - m_origin; |
||||
const double detb = xp(m_dreference, db); |
||||
|
||||
// nothing is less than zero degrees
|
||||
if (detb == 0 && db.x * m_dreference.x + db.y * m_dreference.y >= 0) return false; |
||||
|
||||
const double deta = xp(m_dreference, da); |
||||
|
||||
// zero degrees is less than anything else
|
||||
if (deta == 0 && da.x * m_dreference.x + da.y * m_dreference.y >= 0) return true; |
||||
|
||||
if (deta * detb >= 0) { |
||||
// both on same side of reference, compare to each other
|
||||
return xp(da, db) > 0; |
||||
} |
||||
|
||||
// vectors "less than" zero degrees are actually large, near 2 pi
|
||||
return deta > 0; |
||||
} |
||||
}; |
||||
|
||||
class Pepy : public Game |
||||
{ |
||||
|
||||
private: |
||||
|
||||
/* Convention for calling parent class in a consistent way across classes */ |
||||
typedef Game super; |
||||
|
||||
bool shaking = true, flying = false, stopped = false; |
||||
sb::VAO cuckoo_vao, wad_vao; |
||||
sb::VBO vbo; |
||||
GLuint shader; |
||||
Model cuckoo; |
||||
std::vector<std::pair<Plane, glm::vec2>> wad; |
||||
std::map<std::string, GLuint> uniform; |
||||
float hue_offset = 0.0f, time_seconds = 0.0f, aspect_ratio = 1.0f, return_speed = 0.0075f, cuckoo_speed = 0.0f, countdown = 10.0f; |
||||
glm::mat4 orthographic_projection {1}; |
||||
glm::vec3 cuckoo_offset {0.0f, 0.0f, 0.0f}; |
||||
bool grabbed = false; |
||||
glm::ivec2 mouse_pixel = {0, 0}; |
||||
Plane background; |
||||
|
||||
void load_gl_context(); |
||||
void update(); |
||||
|
||||
public: |
||||
|
||||
Pepy(); |
||||
void respond(SDL_Event&); |
||||
|
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,44 @@
|
||||
#version 300 es |
||||
|
||||
/* Pepy by @ohsqueezy [ohsqueezy.itch.io] */ |
||||
|
||||
precision mediump float; |
||||
in vec2 uv; |
||||
in vec3 color; |
||||
uniform sampler2D base_texture; |
||||
uniform vec3 blend_min_hsv; |
||||
uniform float time; |
||||
uniform bool scroll; |
||||
uniform bool textured; |
||||
out vec4 myOutputColor; |
||||
|
||||
/* from http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl, licensed under WTFPL */ |
||||
vec3 hsv2rgb(vec3 c) |
||||
{ |
||||
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); |
||||
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); |
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); |
||||
} |
||||
|
||||
void main(void) |
||||
{ |
||||
if (textured) |
||||
{ |
||||
// if (scroll) |
||||
// { |
||||
// ivec2 texture_size = textureSize(base_texture, 0); |
||||
// float speed = time * 35.0; |
||||
// gl_FragColor = texelFetch(base_texture, ivec2(mod(vec2(gl_FragCoord.x + speed, gl_FragCoord.y - speed), texture_size)), 0); |
||||
// } |
||||
// else |
||||
// { |
||||
myOutputColor = texture(base_texture, uv); |
||||
// } |
||||
} |
||||
else |
||||
{ |
||||
myOutputColor = vec4(color, 1.0); |
||||
} |
||||
/* apply blending, leaving alpha unchanged */ |
||||
myOutputColor.xyz = min(myOutputColor.xyz, hsv2rgb(blend_min_hsv)); |
||||
} |
@ -0,0 +1,19 @@
|
||||
#version 300 es |
||||
|
||||
/* Pepy by @ohsqueezy [ohsqueezy.itch.io] */ |
||||
|
||||
precision mediump float; |
||||
in vec2 vertex_position; |
||||
in vec2 vertex_uv; |
||||
in vec3 vertex_color; |
||||
out vec2 uv; |
||||
out vec3 color; |
||||
uniform mat4 model_transformation; |
||||
uniform mat4 orthographic_projection; |
||||
|
||||
void main(void) |
||||
{ |
||||
gl_Position = orthographic_projection * model_transformation * vec4(vertex_position, 0, 1); |
||||
uv = vertex_uv; |
||||
color = vertex_color; |
||||
} |