/* _______________ ,----------------------------------------------------------------. //`````````````\\ \ \ //~~~~~~~~~~~~~~~\\ \ by @ohsqueezy & @sleepin \ //=================\\ \ [ohsqueezy.itch.io] [sleepin.itch.io] \ // \\ \ \ // \\ \ code released under the zlib license [git.nugget.fun/pudding] \ // ☆ GUNKISS ☆ \\ \ \ //_________________________\\ `---------------------------------------------------------------*/ #ifndef Pudding_h_ #define Pudding_h_ #include #include #include #include #include #include #include #include #include "SDL.h" #include "SDL_image.h" #include "sdl2-gfx/SDL2_gfxPrimitives.h" #include "json/json.hpp" #include "glm/glm.hpp" #include "opencv2/core.hpp" #include "opencv2/videoio.hpp" #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" #include "zbar.h" #include "Game.hpp" #include "Color.hpp" #include "extension.hpp" #include "filesystem.hpp" #include "Animation.hpp" #include "Texture.hpp" #include "GLObject.hpp" #include "Log.hpp" #include "Attributes.hpp" #include "VBO.hpp" #include "Item.hpp" #include "Model.hpp" class Pudding : public Game { private: /* Defines for effect IDs that will be passed to the shader program. Since COUNT is last and every value * is the default integer, it will define the number of effects available */ enum Effect { EFFECT_NONE, EFFECT_SNAKE, EFFECT_WOBBLE, EFFECT_COUNT }; /* Defines for UV transformations available in the fragment shader program */ enum UVTransformation { UV_NONE, UV_SQUIRCLE }; typedef Game super; 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 BARCODE_MONSTER_API_URL = "https://barcode.monster/api/"; const std::string BEST_BUY_API_URL_1 = "https://api.bestbuy.com/v1/products(upc="; const std::string BEST_BUY_API_URL_2 = ")?format=json&apiKey="; const std::string NUTRONIX_NOT_FOUND = "resource not found"; const std::string GIANTBOMB_API_URL = "https://www.giantbomb.com/api/release/?api_key="; const glm::vec3 ZERO_VECTOR_3D = glm::vec3(0, 0, 0); const glm::vec3 Y_UNIT_NORMAL_3D = glm::vec3(0, 1, 0); const glm::mat4 VIEW_MATRIX = glm::lookAt(glm::vec3(4, 2, 1), glm::vec3(0, -0.325, 0), Y_UNIT_NORMAL_3D); const glm::vec3 PUDDING_BROWN = glm::vec3(0.713f, 0.359f, 0.224f); const glm::vec3 PUDDING_YELLOW = glm::vec3(0.878f, 0.859f, 0.122f); std::string current_barcode, previous_barcode, current_config_barcode, current_camera_barcode; std::vector items; int current_item_index = 0, effect_id = EFFECT_NONE, pudding_triangle_vertex_count = 0, pudding_fan_vertex_count = 0, current_tile_index = 0; cv::VideoCapture capture; zbar::ImageScanner image_scanner; std::map> uniform; GLuint flat_program, mvp_program; glm::mat4 projection, model = glm::mat4(1.0f), mvp; std::map pudding_attributes; Plane plane; bool show_item = false, reading_capture_frame = false; SDL_GLContext capture_frame_thread_context = nullptr; std::vector tiles; sb::Texture capture_texture_front_buffer, capture_texture_back_buffer; sb::Texture& capture_texture = capture_texture_front_buffer; sb::VAO vao; sb::VBO vbo; void set_pudding_model(float, float, int, int = 1, float = -1, float = 1, float = 0.3f); void load_gl_context(); void load_tiles(); void initialize_camera(); void incorporate_open_food_api(Item&); void incorporate_nutronix_api(Item&); void incorporate_edamam_api(Item&); void incorporate_best_buy_api(Item&); void save_item_json(const nlohmann::json&, const Item&, const std::string&) const; nlohmann::json json_from_url(const std::string&, const std::vector& = {}); void curl_get_bytes(const std::string& url, std::vector&, const std::vector& = {}) const; static size_t curl_write_response(std::uint8_t*, size_t, size_t, std::vector*); sb::Texture texture_from_image_url(const std::string&) const; static void destroy_texture(GLuint*); bool item_display_active() const; static int capture_frame(void*); public: Pudding(); void respond(SDL_Event&); void add_item(const std::string&); void increment_item_index(int = 1); Item& current_item(); void update(); virtual std::string class_name() const { return "Pudding"; } }; /* Apply force until reaching a threshold. Use a connection object to run user functions * when force reaches threshold and when force goes below threshold. * * - shares single Plane (vertices in VBO and UV in VBO) * - each has different Texture * - each has different response to click * - shares collision with mouse code * - each has different position */ class Button { /* threshold */ /* force */ /* close */ /* open */ /* apply */ /* remove */ /* weighted depression rate */ /* Animation (?) */ }; class Pad { }; /* An abstract base class of an object in a state of either connected or not connected. * When the state changes, functions that must be overriden by a derived class are run, * one for each state change: from on to off, and from off to on. */ class Connection { private: enum State { STATE_DISCONNECTED, STATE_CONNECTED }; State connection_state = STATE_DISCONNECTED; protected: virtual void on_connect() = 0; virtual void on_disconnect() = 0; public: Connection() {} State state() { return connection_state; } void connect() { if (state() != STATE_CONNECTED) { connection_state = STATE_CONNECTED; on_connect(); } } void disconnect() { if (state() != STATE_DISCONNECTED) { connection_state = STATE_DISCONNECTED; on_disconnect(); } } void toggle() { if (state() == STATE_CONNECTED) disconnect(); else connect(); } bool connected() { return connection_state == STATE_DISCONNECTED ? false : true; } }; #endif