From 864548607805f2a26c39b36acba5793cb5d1492d Mon Sep 17 00:00:00 2001 From: frank <420@shampoo.ooo> Date: Fri, 7 May 2021 21:26:44 -0400 Subject: [PATCH] initial commit --- .gitignore | 5 ++ .gitmodules | 3 + Makefile | 143 +++++++++++++++++++++++++++++++++++++++++ config.json | 41 ++++++++++++ lib/sfw | 1 + src/Pudding.cpp | 164 ++++++++++++++++++++++++++++++++++++++++++++++++ src/Pudding.hpp | 52 +++++++++++++++ 7 files changed, 409 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Makefile create mode 100644 config.json create mode 160000 lib/sfw create mode 100644 src/Pudding.cpp create mode 100644 src/Pudding.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d79e988 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +local/ +*.o +BPmono.ttf +compile_commands.json +pudding diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c120e81 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/sfw"] + path = lib/sfw + url = frank@shampoo.ooo:/var/www/git/sfw diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f834f59 --- /dev/null +++ b/Makefile @@ -0,0 +1,143 @@ +SRC_DIR := src/ +SFW_DIR := lib/sfw/ +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 +CPPC_LINUX := clang++ +SDLCONFIG := /home/frank/local/sdl/bin/sdl2-config +SDL_FLAGS := $(shell $(SDLCONFIG) --cflags) +BUILDDIR := build +EXT_SRC_ROOT := /home/frank/ext/software +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) +EMSCRIPTENHOME = $(EXT_SRC_ROOT)/emsdk/upstream/emscripten +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 +SFW_H_FILES := $(wildcard $(addprefix $(SFW_SRC_DIR),*.hpp)) +SFW_O_FILES := $(filter-out $(addprefix $(SFW_SRC_DIR),filesystem.o),$(SFW_H_FILES:.hpp=.o)) +GAME_H_FILES := $(wildcard $(addprefix $(SRC_DIR),*.hpp)) +GAME_O_FILES := $(GAME_H_FILES:.hpp=.o) +CREATE_FONT_SYMLINK = ln -nsf $(SFW_DIR)"BPmono.ttf" . +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 MAX_WEBGL_VERSION=1 -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall']" \ + -s EXPORTED_FUNCTIONS="['_main', '_reset_game']" -s ALLOW_MEMORY_GROWTH=1 -s GL_PREINITIALIZED_CONTEXT=1 \ + -s ENVIRONMENT=web --shell-file shell_minimal.html --no-heap-copy -I$(SFW_LIB_DIR) -I$(SFW_SRC_DIR) +EMSCRIPTEN_PRELOADS = --preload-file "BPmono.ttf"@/ --preload-file "config.json" \ + --preload-file "resource" + +$(SDLGFX2_DIR)%.o: $(SDLGFX2_DIR)%.c $(SDLGFX2_DIR)%.h +$(GLEW_DIR)%.o: $(GLEW_DIR)%.c $(GLEW_DIR)%.h + $(CC) $(CFLAGS) $< -c -o $@ + +$(SFW_SRC_DIR)extension.o : $(addprefix $(SFW_SRC_DIR),Box.hpp Segment.hpp Color.hpp filesystem.hpp Pixels.hpp) +$(SFW_SRC_DIR)Node.o : $(addprefix $(SFW_SRC_DIR),Game.hpp Configuration.hpp Delegate.hpp Display.hpp Input.hpp Box.hpp Audio.hpp) +$(SFW_SRC_DIR)Sprite.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Game.hpp Box.hpp Animation.hpp Color.hpp extension.hpp Pixels.hpp) +$(SFW_SRC_DIR)Game.o : $(addprefix $(SFW_SRC_DIR),extension.hpp Node.hpp Sprite.hpp Recorder.hpp Input.hpp Configuration.hpp \ + Delegate.hpp Audio.hpp) +$(SFW_SRC_DIR)Animation.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Timer.hpp) +$(SFW_SRC_DIR)Recorder.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Game.hpp Configuration.hpp Delegate.hpp Animation.hpp extension.hpp) +$(SFW_SRC_DIR)Input.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Animation.hpp Configuration.hpp Delegate.hpp) +$(SFW_SRC_DIR)Configuration.o : $(addprefix $(SFW_SRC_DIR),Node.hpp) +$(SFW_SRC_DIR)Delegate.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Game.hpp Input.hpp) +$(SFW_SRC_DIR)Display.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Game.hpp Box.hpp Configuration.hpp Delegate.hpp) +$(SFW_SRC_DIR)Box.o : $(addprefix $(SFW_SRC_DIR),extension.hpp Segment.hpp) +$(SFW_SRC_DIR)Segment.o : $(addprefix $(SFW_SRC_DIR),extension.hpp Box.hpp) +$(SFW_SRC_DIR)Pixels.o : $(addprefix $(SFW_SRC_DIR),Box.hpp extension.hpp) +$(SFW_SRC_DIR)Audio.o : $(addprefix $(SFW_SRC_DIR),Node.hpp Display.hpp Configuration.hpp Box.hpp filesystem.hpp extension.hpp) +$(SRC_DIR)Pudding.o : $(SFW_H_FILES) +%.o : %.cpp %.hpp + $(CPPC) $(CPP_FLAGS) $< -c -o $@ + +linux : CC = clang +linux : CPPC = clang++ +linux : CFLAGS = -Wall -Wextra -O3 -c -I$(SFW_LIB_DIR) -I$(SFW_SRC_DIR) $(SDL_FLAGS) +linux : CPP_FLAGS = $(CFLAGS) --std=c++17 +linux : LFLAGS = $(shell $(SDLCONFIG) --libs) -lpthread +linux : $(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) \ + $(SFW_O_FILES) $(GAME_O_FILES) + $(CREATE_FONT_SYMLINK) + $(CPPC) $(LFLAGS) -D__LINUX__ -lGL -lGLESv2 -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lcurl -lstdc++fs $^ -o pudding + +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) $(SFW_O_FILES) $(GAME_O_FILES) + $(CREATE_FONT_SYMLINK) + $(CPPC) $(CPP_FLAGS) $(EMSCRIPTEN_PRELOADS) $^ -o "index.html" + +collide_test : CC = clang +collide_test : CPPC = clang++ +collide_test : CFLAGS = -Wall -Wextra -O3 -g -c -I$(SFW_LIB_DIR) -I$(SFW_SRC_DIR) $(SDL_FLAGS) +collide_test : CPP_FLAGS = $(CFLAGS) --std=c++17 +collide_test : LFLAGS = $(shell $(SDLCONFIG) --libs) -lpthread +collide_test : $(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) \ + $(SFW_O_FILES) CollisionTest.o + $(CPPC) $(LFLAGS) -D__LINUX__ -lGL -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lstdc++fs $^ -o collide-test + +collide_test_emscripten : CC = $(EMSCRIPTENHOME)/emcc +collide_test_emscripten : CPPC = $(EMSCRIPTENHOME)/em++ +collide_test_emscripten : CFLAGS = $(EMSCRIPTEN_CFLAGS) +collide_test_emscripten : CPP_FLAGS = $(CFLAGS) --std=c++17 +collide_test_emscripten : $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) $(SFW_O_FILES) CollisionTest.o + $(CREATE_FONT_SYMLINK) + $(CPPC) $(CPP_FLAGS) $(EMSCRIPTEN_PRELOADS) --emrun $^ -o "collision_test.html" + +.PHONY : clean +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 + +mingw : + if [ ! -d $(BUILDDIR)/$(WINBUILDDIR) ]; then mkdir -p $(BUILDDIR)/$(WINBUILDDIR); fi; + cd $(BUILDDIR)/$(WINBUILDDIR) && \ + i686-w64-mingw32-g++ -std=c++17 $(PROJECTHOME)/main.cpp -I$(SDLMINGWHOME)/include/SDL2 \ + -I$(SDL_IMG_MINGW_HOME)/include/SDL2 -I$(SDL_TTF_MINGW_HOME)/include/SDL2 $(INC) \ + $(PROJECTHOME)/sdl2-gfx/SDL2_gfxPrimitives.c $(PROJECTHOME)/sdl2-gfx/SDL2_rotozoom.c $(PROJECTHOME)/glew/glew.c \ + -L$(SDLMINGWHOME)/lib -L$(SDL_IMG_MINGW_HOME)/lib -L$(SDL_TTF_MINGW_HOME)/lib \ + -lmingw32 -lSDL2_image \ + -lSDL2_ttf -lstdc++fs \ + -lSDL2main -lSDL2 -lopengl32 -Wall -O2 -o main.exe && \ + cp $(SDLMINGWHOME)/bin/SDL2.dll $(SDL_IMG_MINGW_HOME)/bin/SDL2_image.dll \ + $(SDL_TTF_MINGW_HOME)/bin/SDL2_ttf.dll . + +osx : + g++ -I $(SYSFWPATH)/SDL2.framework/Headers $(INC) \ + -I $(SYSFWPATH)/SDL2_image.framework/Headers -Wl,-rpath,$(SYSFWPATH) \ + -framework SDL2 -framework SDL2_image -framework OpenGL main.cpp sdl2-gfx/SDL2_rotozoom.c \ + -o main + +osx-bundle : + if [ ! -d "$(APPDIR)" ]; then mkdir -p $(APPDIR); fi; + if [ ! -d "$(APPDIR)" ]; then mkdir $(APPDIR); fi; + if [ ! -d "$(APPDIR)/MacOS" ]; then mkdir $(APPDIR)/MacOS; fi; + if [ ! -d "$(APPDIR)/Frameworks" ]; then mkdir $(APPDIR)/Frameworks; fi; + if [ ! -d "$(APPDIR)/Resources" ]; then mkdir $(APPDIR)/Resources; fi; + touch $(APPDIR)/Info.plist + cp -r $(SYSFWPATH)/SDL2.framework $(APPDIR)/Frameworks + cp -r $(SYSFWPATH)/SDL2_image.framework $(APPDIR)/Frameworks + g++ -I $(SYSFWPATH)/SDL2.framework/Headers -I $(SYSFWPATH)/SDL2_image.framework/Headers \ + -Wl,-rpath,@executable_path/../Frameworks -Wl,-rpath,$(SYSFWPATH) \ + -framework SDL2 -framework SDL2_image -framework OpenGL main.cpp -o $(APPDIR)/MacOS/main + +cross : linux android emscripten mingw diff --git a/config.json b/config.json new file mode 100644 index 0000000..3ffcce9 --- /dev/null +++ b/config.json @@ -0,0 +1,41 @@ +{ + "display": + { + "dimensions": [680, 384], + "framerate": 60, + "title": "Pudding", + "debug": false, + "render driver": "opengl" + }, + "path": + { + "screenshots": "local/screenshots", + "video": "local/video" + }, + "gamepad": + { + }, + "keys": + { + "print-video-memory-size": ["CTRL", "v"], + "print-frame-length-history": ["CTRL", "SHIFT", "h"] + }, + "recording": + { + "enabled": true, + "write-mp4": false, + "video-frame-length": 33.333, + "max-video-memory": 2000 + }, + "input": + { + "any-key-ignore-commands": ["up", "right", "down", "left"], + "suppress-any-key-on-mods": true + }, + "scan": + { + "json-save": true, + "json-save-directory": "local/scans", + "barcode": "02266600" + } +} diff --git a/lib/sfw b/lib/sfw new file mode 160000 index 0000000..a8948bc --- /dev/null +++ b/lib/sfw @@ -0,0 +1 @@ +Subproject commit a8948bca73450be6ec0820f07a6703e245fd1edc diff --git a/src/Pudding.cpp b/src/Pudding.cpp new file mode 100644 index 0000000..04e5439 --- /dev/null +++ b/src/Pudding.cpp @@ -0,0 +1,164 @@ +/* + ______________ + //````````````\\ 😀 Thank you for choosing Pudding Customs for your business 😀 + //~~~~~~~~~~~~~~\\ + //================\\ Custom pudding code provided by 0eggxactly ........... [http://0eggxactly.itch.io] + // \\ Available for copy, modification and redistribution .. [http://git.shampoo.ooo/pudding] + // ''CUSTOM PUDDING'' \\ Updates .............................................. [http://twitter.com/diskmem] +//______________________\\ +`````````````````````````` + +*/ + +#include "Pudding.hpp" + +int main() +{ + Pudding pudding = Pudding(); + pudding.run(); + pudding.quit(); + return 0; +} + +Pudding::Pudding() +{ + load_sdl_context(); +} + +void Pudding::load_sdl_context() +{ + super::load_sdl_context(); +} + +void Pudding::curl_get_bytes(std::string url, std::vector* storage, std::string user_agent) +{ + CURL *curl; + CURLcode result; + result = curl_global_init(CURL_GLOBAL_DEFAULT); + if (result != CURLE_OK) + { + std::cout << "curl initialization failed " << curl_easy_strerror(result) << std::endl; + } + else + { + curl = curl_easy_init(); + if (curl) + { + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Pudding::store_curl_response); + std::vector food_barcode_response; + curl_easy_setopt(curl, CURLOPT_WRITEDATA, storage); + curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent.c_str()); + result = curl_easy_perform(curl); + if (result != CURLE_OK) + { + std::cout << "curl request failed " << curl_easy_strerror(result) << std::endl; + } + } + else + { + std::cout << "curl initialization failed" << std::endl; + } + curl_easy_cleanup(curl); + } + curl_global_cleanup(); +} + +nlohmann::json Pudding::food_json_from_barcode(std::string barcode) +{ + std::string url = "https://world.openfoodfacts.org/api/v0/product/" + barcode; + std::vector storage; + curl_get_bytes(url, &storage, USER_AGENT); + nlohmann::json food_json; + food_json = nlohmann::json::parse(storage); + if (get_configuration()["scan"]["json-save"] && !is_food_json_empty(food_json)) + { + fs::path path = get_configuration()["scan"]["json-save-directory"]; + if (!fs::exists(path)) + { + fs::create_directories(path); + } + std::string prefix = ""; + if (food_json.contains("product")) + { + if (food_json["product"].value("brands", "") != "") + { + prefix += food_json["product"]["brands"].get() + "_"; + } + if (food_json["product"].value("product_name", "") != "") + { + prefix += food_json["product"]["product_name"].get() + "_"; + } + } + if (prefix == "") + { + prefix = "Unknown_"; + } + std::replace_if(prefix.begin(), prefix.end(), [](char c) { return !std::isalnum(c); }, '_'); + path /= prefix + barcode + ".json"; + std::ofstream out(path); + out << std::setw(4) << food_json << std::endl; + SDL_Log("Saved JSON to %s", path.c_str()); + } + return food_json; +} + +size_t Pudding::store_curl_response(std::uint8_t* buffer, size_t size, size_t count, std::vector* storage) +{ + size_t total_size = size * count; + storage->insert(storage->end(), buffer, buffer + total_size); + return total_size; +} + +bool Pudding::is_food_json_empty(nlohmann::json food_json) +{ + return !food_json.value("status", 0) || !food_json.contains("product"); +} + +SDL_Texture* Pudding::texture_from_image_url(std::string url) +{ + std::vector storage; + curl_get_bytes(url, &storage, USER_AGENT); + if (!storage.empty()) + { + SDL_RWops* rw = SDL_RWFromConstMem(storage.data(), storage.size()); + return IMG_LoadTexture_RW(get_renderer(), rw, 0); + } + else + { + return nullptr; + } +} + +void Pudding::refresh() +{ + nlohmann::json food_json = food_json_from_barcode(get_configuration()["scan"]["barcode"]); + if (!is_food_json_empty(food_json)) + { + if (food_json["product"].value("image_url", "") != "") + { + std::string url = food_json["product"]["image_url"]; + SDL_Texture* texture = texture_from_image_url(url); + SDL_Log("looking up image at %s", url.c_str()); + if (texture != nullptr) + { + image.unload(); + image.add_frames(texture); + image.add_wrap(true, true); + } + } + } +} + +void Pudding::update() +{ + get_root()->configuration.load("config.json"); + get_root()->configuration.merge(); + if (current_barcode != get_configuration()["scan"]["barcode"]) + { + current_barcode = get_configuration()["scan"]["barcode"]; + refresh(); + } + image.move_weighted(glm::vec2(1.681, 1)); + image.update(); +} diff --git a/src/Pudding.hpp b/src/Pudding.hpp new file mode 100644 index 0000000..65e097d --- /dev/null +++ b/src/Pudding.hpp @@ -0,0 +1,52 @@ +#ifndef Pudding_h_ +#define Pudding_h_ + +#include +#include +#include +#include +#include "json/json.hpp" +#include "glm/vec2.hpp" +#include "Game.hpp" +#include "Sprite.hpp" +#include "Color.hpp" +#include "extension.hpp" + +struct Pudding : Game +{ + + const std::string USER_AGENT = "Work in progress game for http://shampoo.ooo"; + const std::string OPEN_FOOD_API_URL = "https://world.openfoodfacts.org/api/v0/product/"; + const std::string NUTRONIX_API_URL = "https://trackapi.nutritionix.com/v2/search/item?upc="; + const std::string NUTRONIX_APP_ID = "ea0f2e7e"; + const std::string NUTRONIX_APP_KEY = "39218dde526dd3349daa028deda518ae"; + const std::string BARCODE_MONSTER_API_URL = "https://barcode.monster/api/"; + const std::string EDAMAM_API_URL = "https://api.edamam.com/api/food-database/v2/parser?upc=&app_id=&app_key="; + const std::string EDAMAM_APP_ID = "c23b139f"; + const std::string EDAMAM_APP_KEY = "c54cf8c997534caf7ee92b1ccc7d95a3"; + const std::string BEST_BUY_API_URL = "https://api.bestbuy.com/v1/products(upc=)?format=json&apiKey="; + const std::string BEST_BUY_API_KEY = "cFshpD7C2LtMq07GqlBVpYtY"; + + /* + * images, ingredients, protein weight, nutrition grade, popularity, "serving unit", item name, brand name, keywords, + * allergens, calories, fat, saturated fat, cholesterol, sodium, carbohydrates, fiber, sugar, potassium + */ + + typedef Game super; + Sprite image = Sprite(this); + std::string current_barcode; + + Pudding(); + void load_sdl_context(); + nlohmann::json food_json_from_barcode(std::string); + void curl_get_bytes(std::string url, std::vector*, std::string = ""); + static size_t store_curl_response(std::uint8_t*, size_t, size_t, std::vector*); + bool is_food_json_empty(nlohmann::json); + SDL_Texture* texture_from_image_url(std::string); + void refresh(); + void update(); + std::string get_class_name() { return "Pudding"; } + +}; + +#endif