updated item and camera to use model class; added carousel class

This commit is contained in:
frank 2021-11-01 17:35:16 -04:00
parent aed8457874
commit 4336f69d98
10 changed files with 203 additions and 124 deletions

View File

@ -44,9 +44,9 @@ CREATE_FONT_SYMLINK := ln -nsf $(SB_DIR)"BPmono.ttf" .
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))
SB_O_FILES := $(filter-out $(addprefix $(SB_SRC_DIR),filesystem.o utility.o),$(SB_H_FILES:.hpp=.o))
SRC_H_FILES := $(wildcard $(addprefix $(SRC_DIR),*.hpp))
SRC_O_FILES := $(SRC_H_FILES:.hpp=.o)
SRC_O_FILES := $(filter-out $(addprefix $(SRC_DIR),Carousel.o),$(SRC_H_FILES:.hpp=.o))
#####################################################################
# Targets for building [SPACE BOX], dependencies and project source #
@ -69,14 +69,14 @@ $(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)
$(SB_SRC_DIR)Pixels.o : $(addprefix $(SB_SRC_DIR),Box.hpp extension.hpp Log.hpp utility.hpp)
$(SB_SRC_DIR)Audio.o : $(addprefix $(SB_SRC_DIR),Node.hpp Display.hpp Configuration.hpp Box.hpp filesystem.hpp extension.hpp)
$(SB_SRC_DIR)GLObject.o : $(addprefix $(SB_SRC_DIR),Log.hpp)
$(SB_SRC_DIR)Texture.o : $(addprefix $(SB_SRC_DIR),GLObject.hpp filesystem.hpp Log.hpp)
$(SB_SRC_DIR)VBO.o : $(addprefix $(SB_SRC_DIR),Log.hpp GLObject.hpp Attributes.hpp extension.hpp)
$(SB_SRC_DIR)Attributes.o : $(addprefix $(SB_SRC_DIR),Log.hpp extension.hpp)
$(SRC_DIR)Model.o : $(addprefix $(SB_SRC_DIR),extension.hpp Attributes.hpp Texture.hpp)
$(SRC_DIR)Item.o : $(addprefix $(SB_SRC_DIR),extension.hpp Node.hpp Texture.hpp Log.hpp) $(SRC_DIR)Model.hpp
$(SRC_DIR)Model.o : $(addprefix $(SB_SRC_DIR),extension.hpp Attributes.hpp Texture.hpp) $(addprefix $(SRC_DIR),Carousel.hpp)
$(SRC_DIR)Item.o : $(addprefix $(SB_SRC_DIR),Texture.hpp Log.hpp) $(addprefix $(SRC_DIR),Model.hpp Carousel.hpp)
$(SRC_DIR)Pudding.o : $(SRC_H_FILES) $(SB_H_FILES)
%.o : %.cpp %.hpp
$(CPPC) $(CPP_FLAGS) $< -c -o $@

View File

@ -47,7 +47,7 @@
"enabled": true,
"json-save": true,
"json-save-directory": "local/scans",
"barcode": "8410076472953",
"barcode": "400063314395",
"capture-device": "/dev/video0"
},
"api":

2
lib/sb

@ -1 +1 @@
Subproject commit 2c0517b9e28ab2be46c1402bab2dafffd24c6637
Subproject commit dd736f341fb49380a4d33d14859c7632853d06e0

73
src/Carousel.hpp Normal file
View File

@ -0,0 +1,73 @@
/* _______________ ,----------------------------------------------------------------.
//`````````````\\ \ \
//~~~~~~~~~~~~~~~\\ \ by @ohsqueezy & @sleepin \
//=================\\ \ [ohsqueezy.itch.io] [sleepin.itch.io] \
// \\ \ \
// \\ \ code released under the zlib license [git.nugget.fun/pudding] \
// GUNKISS \\ \ \
//_________________________\\ `---------------------------------------------------------------*/
#ifndef CAROUSEL_H_
#define CAROUSEL_H_
#include <cstdint>
#include <iterator>
#include "utility.hpp"
class Carousel
{
private:
std::uint32_t offset = 0;
public:
template<typename Container>
auto current(Container& container)
{
auto location = container.begin();
if (location != container.end())
{
std::advance(location, offset);
return location;
}
else
{
throw std::out_of_range("Container is empty");
}
}
template<typename Container>
auto next(const Container& container)
{
offset = ++offset % container.size();
}
template<typename Container>
auto previous(const Container& container)
{
offset = sb::mod<int>(--offset, container.size());
}
template<typename Container>
auto increment(const Container& container, int amount)
{
offset = sb::mod<int>(offset + amount, container.size());
}
template<typename Container>
auto beginning()
{
offset = 0;
}
template<typename Container>
auto end(const Container& container)
{
offset = container.size() - 1;
}
};
#endif

View File

@ -9,85 +9,91 @@
#include "Item.hpp"
Item::Item(Node* parent) : Node(parent) {};
Item::Item() {};
void Item::set_text_property(const std::string& value, std::string& property, const std::string& property_name)
void Item::text_property(const std::string& value, std::string& property, const std::string& property_name)
{
if (property == "")
{
if (value != "")
{
property = value;
sb::Log::log("set " + property_name + " to " + property + " in " + get_full_name());
sb::Log::log("set " + property_name + " to " + property + " in " + full_name());
}
else
{
sb::Log::log("empty string passed, not setting " + property_name + " in " + get_full_name(), sb::Log::DEBUG);
sb::Log::log("empty string passed, not setting " + property_name + " in " + full_name(), sb::Log::DEBUG);
}
}
else
{
sb::Log::log(property_name + " already set to " + property + " in " + get_full_name() + ", not setting", sb::Log::DEBUG);
sb::Log::log(property_name + " already set to " + property + " in " + full_name() + ", not setting", sb::Log::DEBUG);
}
}
void Item::add_image_texture(sb::Texture texture)
void Item::brand_name(const std::string& name)
{
image_textures.push_back(texture);
text_property(name, item_brand_name, "brand name");
}
const std::vector<sb::Texture>& Item::get_image_textures() const
const std::string& Item::brand_name() const
{
return image_textures;
return item_brand_name;
}
const sb::Texture& Item::get_active_image_texture() const
void Item::product_name(const std::string& name)
{
return get_image_textures()[current_image_index];
text_property(name, item_product_name, "product name");
}
void Item::set_brand_name(const std::string& name)
const std::string& Item::product_name() const
{
set_text_property(name, brand_name, "brand name");
return item_product_name;
}
const std::string& Item::get_brand_name() const
void Item::upc(const std::string& upc)
{
return brand_name;
text_property(upc, item_upc, "UPC");
}
void Item::set_product_name(const std::string& name)
const std::string& Item::upc() const
{
set_text_property(name, product_name, "product name");
return item_upc;
}
const std::string& Item::get_product_name() const
std::string Item::full_name() const
{
return product_name;
}
void Item::set_upc(const std::string& upc)
{
set_text_property(upc, this->upc, "UPC");
}
const std::string& Item::get_upc() const
{
return upc;
}
std::string Item::get_full_name() const
{
std::string name = get_brand_name();
std::string name = brand_name();
if (name != "")
{
name += " ";
}
name += get_product_name();
name += product_name();
return name;
}
void Item::increment_image_index(int increment)
void Item::texture(sb::Texture& texture, const std::string& name)
{
current_image_index = sb::mod(current_image_index + increment, static_cast<int>(get_image_textures().size()));
image.texture(texture, name);
}
sb::Texture& Item::current_texture()
{
// return image.texture().begin()->second;
return carousel.current(image.texture())->second;
}
void Item::next_texture()
{
carousel.next(image.texture());
}
void Item::previous_texture()
{
carousel.previous(image.texture());
}
std::size_t Item::texture_count()
{
return image.texture().size();
}

View File

@ -24,23 +24,21 @@
#include <functional>
#include <SDL.h>
#include "json/json.hpp"
#include "extension.hpp"
#include "Node.hpp"
#include "Texture.hpp"
#include "Log.hpp"
#include "Model.hpp"
#include "Carousel.hpp"
class Item : public Node
class Item
{
private:
nlohmann::json json = {};
// Plane image;
std::vector<sb::Texture> image_textures;
std::string brand_name = "", product_name = "", upc = "";
int current_image_index = 0;
void set_text_property(const std::string&, std::string&, const std::string&);
Plane image;
Carousel carousel;
std::string item_brand_name = "", item_product_name = "", item_upc = "";
void text_property(const std::string&, std::string&, const std::string&);
/*
* add properties: ingredients, protein weight, nutrition grade, popularity, "serving unit", keywords,
@ -49,18 +47,19 @@ private:
public:
Item(Node*);
void add_image_texture(sb::Texture);
const std::vector<sb::Texture>& get_image_textures() const;
const sb::Texture& get_active_image_texture() const;
void set_brand_name(const std::string&);
const std::string& get_brand_name() const;
void set_product_name(const std::string&);
const std::string& get_product_name() const;
void set_upc(const std::string&);
const std::string& get_upc() const;
std::string get_full_name() const;
void increment_image_index(int = 1);
Item();
void texture(sb::Texture&, const std::string&);
void brand_name(const std::string&);
const std::string& brand_name() const;
void product_name(const std::string&);
const std::string& product_name() const;
void upc(const std::string&);
const std::string& upc() const;
std::string full_name() const;
sb::Texture& current_texture();
void next_texture();
void previous_texture();
std::size_t texture_count();
};

View File

@ -18,7 +18,7 @@ Model::Model(const std::map<std::string, std::shared_ptr<sb::Attributes>>& attri
{
for (auto attributes : attributes_pack)
{
this->attributes(attributes.first, attributes.second);
this->attributes(attributes.second, attributes.first);
}
}
@ -29,7 +29,7 @@ Model::Model(const std::map<std::string, sb::Attributes>& attributes_pack)
{
for (auto attributes : attributes_pack)
{
this->attributes(attributes.first, attributes.second);
this->attributes(attributes.second, attributes.first);
}
}
@ -39,7 +39,7 @@ Model::Model(const std::initializer_list<std::string>& names)
{
for (const std::string& name : names)
{
this->attributes(name, sb::Attributes());
this->attributes(sb::Attributes(), name);
}
}
@ -67,20 +67,20 @@ std::shared_ptr<sb::Attributes>& Model::operator[](const std::string& name)
auto element = model_attributes.find(name);
if (element == model_attributes.end())
{
attributes(name, sb::Attributes{});
attributes(sb::Attributes{}, name);
}
return model_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 std::string& name, const sb::Attributes& attributes)
void Model::attributes(const sb::Attributes& attributes, const std::string& name)
{
this->attributes(name, std::make_shared<sb::Attributes>(attributes));
this->attributes(std::make_shared<sb::Attributes>(attributes), name);
}
/* Assign name to attributes and share ownership. */
void Model::attributes(const std::string& name, const std::shared_ptr<sb::Attributes>& attributes)
void Model::attributes(const std::shared_ptr<sb::Attributes>& attributes, const std::string& name)
{
model_attributes[name] = attributes;
}
@ -103,6 +103,12 @@ void Model::disable()
}
}
/* Return a reference to the texture container. */
std::map<std::string, sb::Texture>& Model::texture()
{
return model_texture;
}
/* 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)
@ -111,7 +117,7 @@ sb::Texture& Model::texture(const std::string& name)
}
/* Assign name to texture and share ownership. */
void Model::texture(const std::string& name, const sb::Texture& texture)
void Model::texture(const sb::Texture& texture, const std::string& name)
{
model_texture[name] = texture;
}
@ -143,21 +149,19 @@ Model::operator glm::mat4() const
* start over from the beginning. */
void Background::next()
{
offset = ++offset % model_texture.size();
carousel.next(model_texture);
}
/* Return the currently active tile texture. */
const sb::Texture& Background::current() const
/* Return the currently active texture. */
sb::Texture& Background::current()
{
auto position = model_texture.begin();
std::advance(position, offset);
return position->second;
return carousel.current(model_texture)->second;
}
CameraView::CameraView() : Plane()
{
texture("front", sb::Texture());
texture("back", sb::Texture());
texture(sb::Texture(), "front");
texture(sb::Texture(), "back");
}
void CameraView::generate(const glm::vec2& size)

View File

@ -25,6 +25,7 @@
#include "glm/glm.hpp"
#include "Attributes.hpp"
#include "Texture.hpp"
#include "Carousel.hpp"
class Model
{
@ -43,13 +44,14 @@ public:
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 std::string&, const sb::Attributes&);
void attributes(const std::string&, const std::shared_ptr<sb::Attributes>&);
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>& texture();
sb::Texture& texture(const std::string&);
void texture(const std::string&, const sb::Texture&);
void texture(const sb::Texture&, const std::string&);
void transformation(const glm::mat4&);
std::size_t size();
operator glm::mat4() const;
@ -74,19 +76,19 @@ public:
};
/* Plane that stores multiple textures which can be cycled through and looped. Only one texture is
* active at a time, returned by Background::current. Cycle only goes forward, using Background::next. */
/* A Plane that contains a Carousel for cycling through active textures. Only one texture is
* active at a time, returned by Background::current. Carousel only goes forward, using Background::next. */
class Background : public Plane
{
private:
std::uint8_t offset = 0;
Carousel carousel;
public:
void next();
const sb::Texture& current() const;
sb::Texture& current();
};

View File

@ -220,7 +220,7 @@ void Pudding::load_tiles()
{
sb::Texture texture = sb::Texture(path);
texture.load();
background.texture(path, texture);
background.texture(texture, path);
}
}
@ -255,24 +255,24 @@ void Pudding::respond(SDL_Event& event)
{
if (get_delegate().compare(event, "up"))
{
increment_item_index();
item_carousel.next(items);
}
else if (get_delegate().compare(event, "right"))
{
if (items.size() > 0)
{
current_item().increment_image_index();
current_item().next_texture();
}
}
else if (get_delegate().compare(event, "down"))
{
increment_item_index(-1);
item_carousel.previous(items);
}
else if (get_delegate().compare(event, "left"))
{
if (items.size() > 0)
{
current_item().increment_image_index(-1);
current_item().previous_texture();
}
}
else if (get_delegate().compare(event, "toggle-camera"))
@ -309,8 +309,8 @@ void Pudding::respond(SDL_Event& event)
*/
void Pudding::add_item(const std::string& upc)
{
Item item(this);
item.set_upc(upc);
Item item;
item.upc(upc);
if (get_configuration()["api"]["open-food-enabled"])
{
incorporate_open_food_api(item);
@ -327,11 +327,11 @@ void Pudding::add_item(const std::string& upc)
{
incorporate_best_buy_api(item);
}
if (item.get_image_textures().size() > 0)
if (item.texture_count() > 0)
{
items.push_back(item);
/* set item index to end so newest item will display */
current_item_index = items.size() - 1;
item_carousel.end(items);
}
else
{
@ -346,7 +346,7 @@ void Pudding::add_item(const std::string& upc)
void Pudding::incorporate_open_food_api(Item& item)
{
sb::Log::log("checking Open Food API");
nlohmann::json json = json_from_url(OPEN_FOOD_API_URL + item.get_upc());
nlohmann::json json = json_from_url(OPEN_FOOD_API_URL + item.upc());
/* test that should determine if an Open Food API response is not empty */
if (json.value("status", 0) && json.contains("product"))
{
@ -356,11 +356,11 @@ void Pudding::incorporate_open_food_api(Item& item)
sb::Texture texture = texture_from_image_url(url);
if (texture.generated())
{
item.add_image_texture(texture);
item.texture(texture, url);
}
}
item.set_brand_name(json["product"].value("brands", ""));
item.set_product_name(json["product"].value("product_name", ""));
item.brand_name(json["product"].value("brands", ""));
item.product_name(json["product"].value("product_name", ""));
save_item_json(json, item, "Open_Food_API");
}
else
@ -376,7 +376,7 @@ void Pudding::incorporate_nutronix_api(Item& item)
sb::Log::log("checking Nutronix API");
/* Nutronix requires API keys in headers for validation */
nlohmann::json json = json_from_url(
NUTRONIX_API_URL + item.get_upc(), {
NUTRONIX_API_URL + item.upc(), {
"x-app-id: " + get_configuration()["api"]["nutronix-app-id"].get<std::string>(),
"x-app-key: " + get_configuration()["api"]["nutronix-app-key"].get<std::string>()
});
@ -391,11 +391,11 @@ void Pudding::incorporate_nutronix_api(Item& item)
sb::Texture texture = texture_from_image_url(url);
if (texture.generated())
{
item.add_image_texture(texture);
item.texture(texture, url);
}
}
item.set_brand_name(food.value("brand_name", ""));
item.set_product_name(food.value("food_name", ""));
item.brand_name(food.value("brand_name", ""));
item.product_name(food.value("food_name", ""));
save_item_json(json, item, "Nutronix_API");
}
else
@ -411,7 +411,7 @@ void Pudding::incorporate_edamam_api(Item& item)
sb::Log::log("checking Edamam API");
/* build API url by concatenating relevant values into query string */
std::stringstream url;
url << "https://api.edamam.com/api/food-database/v2/parser?upc=" << item.get_upc() << "&app_id=" <<
url << "https://api.edamam.com/api/food-database/v2/parser?upc=" << item.upc() << "&app_id=" <<
get_configuration()["api"]["edamam-app-id"].get<std::string>() << "&app_key=" <<
get_configuration()["api"]["edamam-app-key"].get<std::string>();
nlohmann::json json = json_from_url(url.str());
@ -425,9 +425,9 @@ void Pudding::incorporate_edamam_api(Item& item)
sb::Texture texture = texture_from_image_url(url);
if (texture.generated())
{
item.add_image_texture(texture);
item.texture(texture, url);
}
item.set_product_name(food.value("label", ""));
item.product_name(food.value("label", ""));
}
save_item_json(json, item, "Edamam_API");
}
@ -444,7 +444,7 @@ void Pudding::incorporate_best_buy_api(Item& item)
sb::Log::log("checking Best Buy API");
/* build API url by concatenating relevant values into query string */
std::stringstream url;
url << "https://api.bestbuy.com/v1/products(upc=" << item.get_upc() << ")?format=json&apiKey=" <<
url << "https://api.bestbuy.com/v1/products(upc=" << item.upc() << ")?format=json&apiKey=" <<
get_configuration()["api"]["best-buy-api-key"].get<std::string>();
nlohmann::json json = json_from_url(url.str());
/* test that should determine if a Best Buy response has a result */
@ -460,11 +460,11 @@ void Pudding::incorporate_best_buy_api(Item& item)
sb::Texture texture = texture_from_image_url(url);
if (texture.generated())
{
item.add_image_texture(texture);
item.texture(texture, url);
}
}
}
item.set_product_name(product.value("name", ""));
item.product_name(product.value("name", ""));
save_item_json(json, item, "Best_Buy_API");
}
else
@ -486,16 +486,16 @@ void Pudding::save_item_json(const nlohmann::json& json, const Item& item, const
fs::create_directories(path);
}
std::string prefix = api_name;
if (item.get_full_name() != "")
if (item.full_name() != "")
{
prefix += "_" + item.get_full_name();
prefix += "_" + item.full_name();
}
else
{
prefix += "_Unknown";
}
std::replace_if(prefix.begin(), prefix.end(), [](char c) { return !std::isalnum(c); }, '_');
path /= prefix + "_" + item.get_upc() + ".json";
path /= prefix + "_" + item.upc() + ".json";
std::ofstream out(path);
out << std::setw(4) << json << std::endl;
sb::Log::log("Saved JSON to " + path.string());
@ -612,18 +612,12 @@ void Pudding::destroy_texture(GLuint* texture_id)
glDeleteTextures(1, texture_id);
}
/* Change the currently selected item */
void Pudding::increment_item_index(int increment)
{
current_item_index = sb::mod(current_item_index + increment, static_cast<int>(items.size()));
}
/* Return the item currently selected in the inventory */
Item& Pudding::current_item()
{
try
{
return items.at(current_item_index);
return *item_carousel.current(items);
}
catch (const std::out_of_range& exception)
{
@ -774,7 +768,7 @@ void Pudding::update()
pudding_model.attributes("uv")->enable();
glUniform1i(uniform["mvp"]["pudding texture"], 0);
glActiveTexture(GL_TEXTURE0);
current_item().get_active_image_texture().bind();
current_item().current_texture().bind();
}
/* draw pudding model */
glEnable(GL_DEPTH_TEST);
@ -814,7 +808,7 @@ void Pudding::update()
viewport_box.left(viewport_box.cx(), true);
}
glViewport(viewport_box.left(), viewport_box.bottom(), viewport_box.width(), viewport_box.height());
current_item().get_active_image_texture().bind();
current_item().current_texture().bind();
plane.enable();
/* draws rectangle vertices and rectangle texture using UV coords */
glDrawArrays(GL_TRIANGLES, 0, plane.attributes("position")->count());

View File

@ -40,6 +40,7 @@
#include "VBO.hpp"
#include "Item.hpp"
#include "Model.hpp"
#include "utility.hpp"
class Pudding : public Game
{
@ -78,7 +79,8 @@ private:
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<Item> items;
int current_item_index = 0, effect_id = EFFECT_NONE, pudding_triangle_vertex_count = 0, pudding_fan_vertex_count = 0;
Carousel item_carousel;
int effect_id = EFFECT_NONE, pudding_triangle_vertex_count = 0, pudding_fan_vertex_count = 0;
cv::VideoCapture capture;
zbar::ImageScanner image_scanner;
std::map<std::string, std::map<std::string, GLuint>> uniform;
@ -115,7 +117,6 @@ 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"; }