using texture class to store texture data

This commit is contained in:
frank 2021-09-20 02:33:32 -04:00
parent b22302a021
commit ea255f5247
6 changed files with 57 additions and 89 deletions

View File

@ -47,12 +47,12 @@
"enabled": true, "enabled": true,
"json-save": true, "json-save": true,
"json-save-directory": "local/scans", "json-save-directory": "local/scans",
"barcode": "", "barcode": "613008719548",
"capture-device": "/dev/video0" "capture-device": "/dev/video0"
}, },
"api": "api":
{ {
"user-agent": "Custom pudding creation game for http://shampoo.ooo", "user-agent": "Custom pudding creation game for http://nugget.fun",
"nutronix-app-id": "ea0f2e7e", "nutronix-app-id": "ea0f2e7e",
"nutronix-app-key": "39218dde526dd3349daa028deda518ae", "nutronix-app-key": "39218dde526dd3349daa028deda518ae",
"edamam-app-id": "c23b139f", "edamam-app-id": "c23b139f",

2
lib/sb

@ -1 +1 @@
Subproject commit 1f8de2f5f1b6a83a6c235d65030a709441f3cd37 Subproject commit 1a4b8507e3886e02ab1b6589ed3823d7fafd1654

View File

@ -22,17 +22,17 @@ void Item::set_text_property(const std::string& value, std::string& property, co
} }
} }
void Item::add_image_texture(std::shared_ptr<GLuint> texture_id) void Item::add_image_texture(Texture texture)
{ {
image_textures.push_back(texture_id); image_textures.push_back(texture);
} }
const std::vector<std::shared_ptr<GLuint>>& Item::get_image_textures() const const std::vector<Texture>& Item::get_image_textures() const
{ {
return image_textures; return image_textures;
} }
const std::shared_ptr<GLuint>& Item::get_active_image_texture() const const Texture& Item::get_active_image_texture() const
{ {
return get_image_textures()[current_image_index]; return get_image_textures()[current_image_index];
} }

View File

@ -2,11 +2,7 @@
#define Item_h_ #define Item_h_
/* including so we can use GLuint type */ /* including so we can use GLuint type */
#define GL_GLEXT_PROTOTYPES
#define GLEW_STATIC
#if defined(__EMSCRIPTEN__) #if defined(__EMSCRIPTEN__)
#include <emscripten.h>
#include <emscripten/html5.h>
#include <GL/glew.h> #include <GL/glew.h>
#else #else
#include "glew/glew.h" #include "glew/glew.h"
@ -21,6 +17,7 @@
#include <extension.hpp> #include <extension.hpp>
#include "json/json.hpp" #include "json/json.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "Texture.hpp"
class Item : public Node class Item : public Node
{ {
@ -28,7 +25,7 @@ class Item : public Node
private: private:
nlohmann::json json = {}; nlohmann::json json = {};
std::vector<std::shared_ptr<GLuint>> image_textures; std::vector<Texture> image_textures;
std::string brand_name = "", product_name = "", upc = ""; std::string brand_name = "", product_name = "", upc = "";
int current_image_index = 0; int current_image_index = 0;
void set_text_property(const std::string&, std::string&, const std::string&); void set_text_property(const std::string&, std::string&, const std::string&);
@ -41,9 +38,9 @@ private:
public: public:
Item(Node*); Item(Node*);
void add_image_texture(std::shared_ptr<GLuint> SDL_Texture); void add_image_texture(Texture);
const std::vector<std::shared_ptr<GLuint>>& get_image_textures() const; const std::vector<Texture>& get_image_textures() const;
const std::shared_ptr<GLuint>& get_active_image_texture() const; const Texture& get_active_image_texture() const;
void set_brand_name(const std::string&); void set_brand_name(const std::string&);
const std::string& get_brand_name() const; const std::string& get_brand_name() const;
void set_product_name(const std::string&); void set_product_name(const std::string&);

View File

@ -239,22 +239,9 @@ void Pudding::load_tiles()
{ {
for (fs::path path : sb::glob(get_configuration()["resource"]["tile-path"].get<fs::path>() / ".*.jpg")) for (fs::path path : sb::glob(get_configuration()["resource"]["tile-path"].get<fs::path>() / ".*.jpg"))
{ {
/* load background as surface */ Texture texture = Texture(path);
std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)> surface(IMG_Load(path.c_str()), SDL_FreeSurface); texture.load();
std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)> flipped_surface(rotozoomSurfaceXY(surface.get(), 0, 1, -1, 0), SDL_FreeSurface); tiles.push_back(texture);
/* generate a GL texture, allocate space and set properties */
std::shared_ptr<GLuint> texture_id(new GLuint, Pudding::destroy_texture);
glGenTextures(1, texture_id.get());
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);
log_gl_errors();
std::ostringstream message;
message << "loaded background image " << path.stem() << " from " << path << "(" << flipped_surface->w << "x" << flipped_surface->h << ")";
log(message.str());
tiles.push_back(texture_id);
} }
} }
@ -275,16 +262,10 @@ void Pudding::initialize_camera()
"fps video capture device ID #" << device_id << " using " << capture.getBackendName(); "fps video capture device ID #" << device_id << " using " << capture.getBackendName();
/* generate two textures that will store the video frames with the intention of double buffering them /* generate two textures that will store the video frames with the intention of double buffering them
* for threaded texture loading */ * for threaded texture loading */
for (GLuint* buffer_id : {&capture_texture_front_buffer_id, &capture_texture_back_buffer_id}) for (Texture* texture : {&capture_texture_front_buffer, &capture_texture_back_buffer})
{ {
glGenTextures(1, buffer_id); texture->generate({capture.get(cv::CAP_PROP_FRAME_WIDTH), capture.get(cv::CAP_PROP_FRAME_HEIGHT)});
glBindTexture(GL_TEXTURE_2D, *buffer_id);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, capture.get(cv::CAP_PROP_FRAME_WIDTH), capture.get(cv::CAP_PROP_FRAME_HEIGHT));
// glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, 320, 240);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
} }
capture_texture_id = capture_texture_front_buffer_id;
} }
else else
{ {
@ -390,10 +371,10 @@ void Pudding::incorporate_open_food_api(Item& item)
if (json["product"].value("image_url", "") != "") if (json["product"].value("image_url", "") != "")
{ {
std::string url = json["product"]["image_url"]; std::string url = json["product"]["image_url"];
std::shared_ptr<GLuint> texture_id = texture_from_image_url(url); Texture texture = texture_from_image_url(url);
if (texture_id != nullptr) if (texture.generated())
{ {
item.add_image_texture(texture_id); item.add_image_texture(texture);
} }
} }
item.set_brand_name(json["product"].value("brands", "")); item.set_brand_name(json["product"].value("brands", ""));
@ -425,10 +406,10 @@ void Pudding::incorporate_nutronix_api(Item& item)
{ {
std::string url = food["photo"]["thumb"]; std::string url = food["photo"]["thumb"];
log("adding image listed in Nutronix API at " + url); log("adding image listed in Nutronix API at " + url);
std::shared_ptr<GLuint> texture_id = texture_from_image_url(url); Texture texture = texture_from_image_url(url);
if (texture_id != nullptr) if (texture.generated())
{ {
item.add_image_texture(texture_id); item.add_image_texture(texture);
} }
} }
item.set_brand_name(food.value("brand_name", "")); item.set_brand_name(food.value("brand_name", ""));
@ -459,10 +440,10 @@ void Pudding::incorporate_edamam_api(Item& item)
if (food.value("image", "") != "") if (food.value("image", "") != "")
{ {
std::string url = food["image"]; std::string url = food["image"];
std::shared_ptr<GLuint> texture_id = texture_from_image_url(url); Texture texture = texture_from_image_url(url);
if (texture_id != nullptr) if (texture.generated())
{ {
item.add_image_texture(texture_id); item.add_image_texture(texture);
} }
item.set_product_name(food.value("label", "")); item.set_product_name(food.value("label", ""));
} }
@ -494,10 +475,10 @@ void Pudding::incorporate_best_buy_api(Item& item)
if (product.value(key, "") != "") if (product.value(key, "") != "")
{ {
std::string url = product[key]; std::string url = product[key];
std::shared_ptr<GLuint> texture_id = texture_from_image_url(url); Texture texture = texture_from_image_url(url);
if (texture_id != nullptr) if (texture.generated())
{ {
item.add_image_texture(texture_id); item.add_image_texture(texture);
} }
} }
} }
@ -558,7 +539,7 @@ nlohmann::json Pudding::json_from_url(const std::string& url, const std::vector<
/* Store the byte buffer from the submitted URL downloaded by cURL into the supplied storage vector /* Store the byte buffer from the submitted URL downloaded by cURL into the supplied storage vector
*/ */
void Pudding::curl_get_bytes(const std::string& url, std::vector<std::uint8_t>& storage, const std::vector<std::string>& headers) void Pudding::curl_get_bytes(const std::string& url, std::vector<std::uint8_t>& storage, const std::vector<std::string>& headers) const
{ {
CURL *curl; CURL *curl;
CURLcode result; CURLcode result;
@ -614,40 +595,26 @@ size_t Pudding::curl_write_response(std::uint8_t* buffer, size_t size, size_t co
/* Allocate storage for a texture, copy the cURL response data into the storage, and return the ID that corresponds to the GL texture /* Allocate storage for a texture, copy the cURL response data into the storage, and return the ID that corresponds to the GL texture
*/ */
std::shared_ptr<GLuint> Pudding::texture_from_image_url(const std::string& url) Texture Pudding::texture_from_image_url(const std::string& url) const
{ {
/* this texture will be returned whether we load pixels into it or not */
Texture texture;
log("looking up image at " + url); log("looking up image at " + url);
std::vector<std::uint8_t> storage; std::vector<std::uint8_t> storage;
curl_get_bytes(url, storage); curl_get_bytes(url, storage);
if (!storage.empty()) if (!storage.empty())
{ {
debug("received image data"); debug("received image data");
/* load as an SDL surface to translate image format into pixel data, flip, and get dimensions */ /* get a Texture by passing the bytes through an RW ops which will enable the Texture object to load a Surface */
SDL_RWops* rw = SDL_RWFromConstMem(storage.data(), storage.size()); SDL_RWops* rw = SDL_RWFromConstMem(storage.data(), storage.size());
SDL_Surface* surface = IMG_Load_RW(rw, 0); texture.load(rw);
SDL_Surface* flipped_surface = rotozoomSurfaceXY(surface, 0, 1, -1, 0); SDL_RWclose(rw);
std::ostringstream message;
message << "image is " << flipped_surface->w << "x" << flipped_surface->h;
log(message.str());
/* generate a GL texture, allocate space and set properties */
std::shared_ptr<GLuint> texture_id = std::shared_ptr<GLuint>(new GLuint, Pudding::destroy_texture);
glGenTextures(1, texture_id.get());
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);
/* copy image bytes into GL texture */
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surface->w, surface->h, GL_RGBA, GL_UNSIGNED_BYTE, flipped_surface->pixels);
log_gl_errors();
SDL_FreeSurface(surface);
SDL_FreeSurface(flipped_surface);
return texture_id;
} }
else else
{ {
SDL_LogWarn(SDL_LOG_CATEGORY_CUSTOM, "image url returned no data"); SDL_LogWarn(SDL_LOG_CATEGORY_CUSTOM, "image url returned no data");
return nullptr;
} }
return texture;
} }
/* Call GL's delete texture function, and print a debug statement for testing. This is defined as a static member /* Call GL's delete texture function, and print a debug statement for testing. This is defined as a static member
@ -701,13 +668,13 @@ int Pudding::capture_frame(void* game)
/* rotate the opencv matrix 180 to work with opengl coords */ /* rotate the opencv matrix 180 to work with opengl coords */
cv::flip(frame, frame, -1); cv::flip(frame, frame, -1);
/* use whichever texture ID is not being used by the main rendering thread */ /* use whichever texture ID is not being used by the main rendering thread */
GLuint texture_id = pudding->capture_texture_id == pudding->capture_texture_front_buffer_id ? Texture& texture = pudding->capture_texture == pudding->capture_texture_front_buffer ?
pudding->capture_texture_back_buffer_id : pudding->capture_texture_front_buffer_id; pudding->capture_texture_back_buffer : pudding->capture_texture_front_buffer;
/* bind texture for accepting pixel data */ /* bind texture for accepting pixel data */
glBindTexture(GL_TEXTURE_2D, texture_id); texture.bind();
/* fill texture memory with last frame's pixels */ /* fill texture memory with last frame's pixels */
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame.cols, frame.rows, GL_BGR, GL_UNSIGNED_BYTE, frame.ptr()); texture.load(frame.ptr(), {frame.cols, frame.rows}, GL_BGR, GL_UNSIGNED_BYTE);
pudding->capture_texture_id = texture_id; pudding->capture_texture = texture;
if (pudding->get_configuration()["scan"]["enabled"]) if (pudding->get_configuration()["scan"]["enabled"])
{ {
/* convert to gray and scan with zbar */ /* convert to gray and scan with zbar */
@ -784,7 +751,7 @@ void Pudding::update()
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glUniform1i(flat_texture_uniform_location, 0); glUniform1i(flat_texture_uniform_location, 0);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, *tiles[current_tile_index]); tiles[current_tile_index].bind();
/* set blend to modify white part of background, color passed is in HSV format */ /* set blend to modify white part of background, color passed is in HSV format */
GLint blend_min_hsv_location = glGetUniformLocation(flat_program, "blend_min_hsv"); GLint blend_min_hsv_location = glGetUniformLocation(flat_program, "blend_min_hsv");
glUniform3f(blend_min_hsv_location, 0.0f, 0.0f, 1.0f); glUniform3f(blend_min_hsv_location, 0.0f, 0.0f, 1.0f);
@ -819,7 +786,7 @@ void Pudding::update()
GLuint pudding_texture_location = glGetUniformLocation(mvp_program, "pudding_texture"); GLuint pudding_texture_location = glGetUniformLocation(mvp_program, "pudding_texture");
glUniform1i(pudding_texture_location, 0); glUniform1i(pudding_texture_location, 0);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, *get_current_item().get_active_image_texture().get()); get_current_item().get_active_image_texture().bind();
} }
/* draw pudding model */ /* draw pudding model */
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
@ -864,7 +831,7 @@ void Pudding::update()
viewport_box.left(viewport_box.cx(), true); viewport_box.left(viewport_box.cx(), true);
} }
glViewport(viewport_box.left(), viewport_box.bottom(), viewport_box.width(), viewport_box.height()); glViewport(viewport_box.left(), viewport_box.bottom(), viewport_box.width(), viewport_box.height());
glBindTexture(GL_TEXTURE_2D, *get_current_item().get_active_image_texture().get()); get_current_item().get_active_image_texture().bind();
/* draws rectangle vertices and rectangle texture using UV coords */ /* draws rectangle vertices and rectangle texture using UV coords */
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
} }
@ -874,7 +841,7 @@ void Pudding::update()
viewport_box.left(window_box(true).left()); viewport_box.left(window_box(true).left());
glViewport(viewport_box.left(), viewport_box.bottom(), viewport_box.width(), viewport_box.height()); glViewport(viewport_box.left(), viewport_box.bottom(), viewport_box.width(), viewport_box.height());
/* bind texture for drawing */ /* bind texture for drawing */
glBindTexture(GL_TEXTURE_2D, capture_texture_id); capture_texture.bind();
/* draws rectangle vertices and rectangle texture using UV coords */ /* draws rectangle vertices and rectangle texture using UV coords */
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
} }

View File

@ -11,6 +11,8 @@
#include <filesystem> #include <filesystem>
#include <curl/curl.h> #include <curl/curl.h>
#include "SDL.h" #include "SDL.h"
#include "SDL_image.h"
#include "sdl2-gfx/SDL2_gfxPrimitives.h"
#include "json/json.hpp" #include "json/json.hpp"
#include "glm/vec2.hpp" #include "glm/vec2.hpp"
#include "opencv2/core.hpp" #include "opencv2/core.hpp"
@ -23,6 +25,7 @@
#include "extension.hpp" #include "extension.hpp"
#include "Item.hpp" #include "Item.hpp"
#include "Animation.hpp" #include "Animation.hpp"
#include "Texture.hpp"
class Pudding : public Game class Pudding : public Game
{ {
@ -65,16 +68,17 @@ private:
current_tile_index = 0; current_tile_index = 0;
cv::VideoCapture capture; cv::VideoCapture capture;
zbar::ImageScanner image_scanner; zbar::ImageScanner image_scanner;
GLuint flat_program, mvp_program, capture_texture_front_buffer_id, capture_texture_back_buffer_id, capture_texture_id, GLuint flat_program, mvp_program, mvp_uniform_location, time_uniform_location, effect_uniform_location,
mvp_uniform_location, time_uniform_location, effect_uniform_location, uv_transformation_uniform_location, uv_transformation_uniform_location, flat_texture_uniform_location, coordinate_bound_uniform_location,
flat_texture_uniform_location, coordinate_bound_uniform_location, flat_time_uniform_location, flat_time_uniform_location, scroll_uniform_location;
scroll_uniform_location;
glm::mat4 projection, model = glm::mat4(1.0f), mvp; glm::mat4 projection, model = glm::mat4(1.0f), mvp;
std::vector<glm::vec3> pudding_vertices, pudding_colors; std::vector<glm::vec3> pudding_vertices, pudding_colors;
std::vector<glm::vec2> pudding_uv; std::vector<glm::vec2> pudding_uv;
bool show_item = false, reading_capture_frame = false; bool show_item = false, reading_capture_frame = false;
SDL_GLContext capture_frame_thread_context = nullptr; SDL_GLContext capture_frame_thread_context = nullptr;
std::vector<std::shared_ptr<GLuint>> tiles; std::vector<Texture> tiles;
Texture capture_texture_front_buffer, capture_texture_back_buffer;
Texture& capture_texture = capture_texture_front_buffer;
void set_pudding_model(float, float, int, int = 1, float = -1, float = 1, float = 0.3f); void set_pudding_model(float, float, int, int = 1, float = -1, float = 1, float = 0.3f);
void load_gl_context(); void load_gl_context();
@ -86,9 +90,9 @@ private:
void incorporate_best_buy_api(Item&); void incorporate_best_buy_api(Item&);
void save_item_json(const nlohmann::json&, const Item&, const std::string&) const; void save_item_json(const nlohmann::json&, const Item&, const std::string&) const;
nlohmann::json json_from_url(const std::string&, const std::vector<std::string>& = {}); nlohmann::json json_from_url(const std::string&, const std::vector<std::string>& = {});
void curl_get_bytes(const std::string& url, std::vector<std::uint8_t>&, const std::vector<std::string>& = {}); void curl_get_bytes(const std::string& url, std::vector<std::uint8_t>&, const std::vector<std::string>& = {}) const;
static size_t curl_write_response(std::uint8_t*, size_t, size_t, std::vector<std::uint8_t>*); static size_t curl_write_response(std::uint8_t*, size_t, size_t, std::vector<std::uint8_t>*);
std::shared_ptr<GLuint> texture_from_image_url(const std::string&); Texture texture_from_image_url(const std::string&) const;
static void destroy_texture(GLuint*); static void destroy_texture(GLuint*);
bool item_display_active() const; bool item_display_active() const;
static int capture_frame(void*); static int capture_frame(void*);