added rotation to pad transformation, added pointer cursor

This commit is contained in:
frank 2021-11-13 14:58:30 -05:00
parent 80aebaf8de
commit e0b1d1fd53
8 changed files with 132 additions and 76 deletions

View File

@ -79,6 +79,19 @@
},
"resource":
{
"tile-path": "resource/tile"
"tile-path": "resource/tile",
"button-path": "resource/button"
},
"interface":
{
"main-button-y": -0.75,
"main-button-single-x": 0.0,
"main-button-double-x": 0.65,
"main-button-scale": 0.25,
"camera-button-label": "scan",
"inventory-button-label": "inventory",
"arrow-button-location": [0.75, 0.0],
"arrow-button-scale": 0.1,
"arrow-button-label": "arrow"
}
}

2
lib/sb

@ -1 +1 @@
Subproject commit 03d179eed4c8323576157f806806b214e42d07c7
Subproject commit 54cf01246b0e5ec81ba5b9158248bca7492823db

BIN
resource/button/arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
resource/button/home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
resource/button/scan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -29,33 +29,24 @@ Pudding::Pudding()
{
/* subscribe to command events */
get_delegate().subscribe(&Pudding::respond, this);
get_delegate().subscribe(&Pudding::respond, this, SDL_MOUSEMOTION);
get_delegate().subscribe(&Pudding::respond, this, SDL_MOUSEBUTTONDOWN);
/* initialize a zbar image scanner for reading barcodes of any format */
image_scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
/* set up pudding model */
nlohmann::json pudding = get_configuration()["pudding"];
set_pudding_model(pudding["top-radius"], pudding["base-radius"], pudding["ring-vertex-count"], pudding["layer-count"],
load_pudding_model(pudding["top-radius"], pudding["base-radius"], pudding["ring-vertex-count"], pudding["layer-count"],
pudding["y-range"][0], pudding["y-range"][1], pudding["gradient-position"]);
/* loading GL context instead of SDL context for 3D */
load_gl_context();
load_tiles();
glm::vec3 w = glm::mat3({{1, 0, 0}, {0, 1, 0}, {-0.6739, -0.74, 1}}) * glm::mat3({{.1, 0, 0}, {0, .1 * (460.0 / 768.0), 0}, {0, 0, 1}}) *
glm::vec3({-1, -1, 1});
std::cout << w << std::endl << glm::translate(glm::vec3{-0.6739, -0.74, 0}) *
glm::scale(glm::vec3{.1, .1 * (460.0 / 768.0), 1}) * glm::vec4{-1, -1, 0, 1} << std::endl;
Pad p {background.current(), {-0.6739f, -0.74f}, 0.1f, get_display().window_box().aspect(), std::function<void()>()};
const std::vector<glm::vec2>& p_position = *p.attributes("position");
glm::vec4 final_position = p.transformation() * glm::vec4{p_position[2].x, p_position[2].y, 0, 1};
std::cout << p.transformation() << std::endl << final_position << std::endl;
assert(final_position == glm::vec4({w.x, w.y, 0, 1}));
sb::Texture label {"local/button/scan.png"};
label.load();
pad.texture(label);
pad.transform({-0.6739f, -0.74f}, 0.25f, get_display().window_box().aspect());
load_pads();
/* Load a pointer cursor from the system library that will be freed automatically */
poke = std::shared_ptr<SDL_Cursor>(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND), SDL_FreeCursor);
}
/* Assign vertices, colors and texture UV coordinates to the pudding model */
void Pudding::set_pudding_model(
void Pudding::load_pudding_model(
float top_radius, float base_radius, int ring_vertex_count, int layer_count, float min_y, float max_y, float gradient_position)
{
size_t ii;
@ -231,17 +222,31 @@ void Pudding::load_gl_context()
sb::Log::gl_errors("after uniform locations");
}
/* Read every resource/tile/.*.jpg into a GL texture, storing the texture pointer and file name in a std::map */
/* Read every jpg in the folder at tile path into a GL texture and associate with the background object. */
void Pudding::load_tiles()
{
for (fs::path path : sb::glob(get_configuration()["resource"]["tile-path"].get<fs::path>() / ".*.jpg"))
{
sb::Texture texture = sb::Texture(path);
sb::Texture texture {path};
texture.load();
background.texture(texture, path);
}
}
/* Load every png in the button path as a Texture and add to a map. */
void Pudding::load_pads()
{
for (fs::path path : sb::glob(get_configuration()["resource"]["button-path"].get<fs::path>() / ".*.png"))
{
labels[path.stem()] = sb::Texture(path);
labels[path.stem()].load();
}
nlohmann::json interface = get_configuration()["interface"];
camera_button.texture(labels["scan"]);
camera_button.transform({interface["main-button-single-x"], interface["main-button-y"]},
interface["main-button-scale"], window_box().aspect());
}
/* Try to create cv::VideoCapture object using device ID #0. If successful, this will create GL texture IDs and storage
* for the camera frames, so it must be called after GL context has been created. Two textures will be created, so they
* can be used as a double buffer.
@ -312,15 +317,31 @@ void Pudding::respond(SDL_Event& event)
{
background.next();
}
else if (event.type == SDL_MOUSEBUTTONDOWN)
/* Mouse interface */
else if (event.type == SDL_MOUSEMOTION || event.type == SDL_MOUSEBUTTONDOWN)
{
glm::vec2 gl_coordinates {
float(event.button.x) / window_box().width() * 2.0f - 1.0f,
(1.0f - float(event.button.y) / window_box().height()) * 2.0f - 1.0f
glm::vec2 mouse = event.type == SDL_MOUSEBUTTONDOWN ? glm::vec2{event.button.x, event.button.y} :
glm::vec2{event.motion.x, event.motion.y};
glm::vec2 ndc {
float(mouse.x) / window_box().width() * 2.0f - 1.0f, (1.0f - float(mouse.y) / window_box().height()) * 2.0f - 1.0f
};
if (pad.collide(gl_coordinates))
/* Check for collision with the camera button if camera view is open, otherwise check for collision with main viewport. */
if ((!capture.isOpened() && camera_button.collide(ndc)) ||
(capture.isOpened() && get_display().ndc_subsection(main_viewport).collide(ndc)))
{
camera_switch.toggle();
if (SDL_GetCursor() != poke.get())
{
SDL_SetCursor(poke.get());
}
if (event.type == SDL_MOUSEBUTTONDOWN)
{
SDL_SetCursor(SDL_GetDefaultCursor());
camera_switch.toggle();
}
}
else if (SDL_GetCursor() == poke.get())
{
SDL_SetCursor(SDL_GetDefaultCursor());
}
}
}
@ -793,13 +814,15 @@ void Pudding::update()
sb::Log::log(message);
}
/* viewport box will be used to tell GL where to draw */
Box viewport_box = window_box(true);
viewport = window_box(true);
/* shrink viewport if item texture or camera will be displayed */
if (item_display_active() || capture.isOpened())
{
viewport_box.drag_bottom(0.3f * viewport_box.height());
viewport.drag_bottom(0.3f * viewport.height());
}
glViewport(viewport_box);
/* Save the main viewport dimensions */
main_viewport = viewport;
glViewport(viewport);
glDisable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -826,7 +849,7 @@ void Pudding::update()
/* calculate the transformation matrix for displaying pudding in viewport */
model = glm::rotate(model, weight(get_configuration()["pudding"]["rotation-speed"].get<float>()), Y_UNIT_NORMAL_3D);
projection = glm::perspective(
glm::radians(40.0f * 1 / viewport_box.aspect()), viewport_box.aspect(), 0.1f, 100.0f);
glm::radians(40.0f * 1 / viewport.aspect()), viewport.aspect(), 0.1f, 100.0f);
mvp = projection * VIEW_MATRIX * model;
/* uniforms */
glUniform1f(uniform["mvp"]["time"], time_seconds);
@ -875,8 +898,8 @@ void Pudding::update()
glUniform1i(uniform["flat"]["texture"], 0);
glActiveTexture(GL_TEXTURE0);
/* move viewport to the bottom of screen */
viewport_box.top(viewport_box.bottom(), true);
viewport_box.bottom(window_box(true).bottom(), true);
viewport.top(viewport.bottom(), true);
viewport.bottom(window_box(true).bottom(), true);
/* reset blend to display the original texture colors */
glUniform3f(uniform["flat"]["blend"], 0.0f, 0.0f, 1.0f);
/* draw the current item image if we're supposed to */
@ -885,9 +908,9 @@ void Pudding::update()
/* shrink viewport to half size if camera will also be displayed */
if (capture.isOpened())
{
viewport_box.left(viewport_box.cx(), true);
viewport.left(viewport.cx(), true);
}
glViewport(viewport_box);
glViewport(viewport);
current_item().current_texture().bind();
plane.enable();
/* draws rectangle vertices and rectangle texture using UV coords */
@ -896,8 +919,8 @@ void Pudding::update()
/* draw the camera if the camera has been opened */
if (capture.isOpened())
{
viewport_box.left(window_box(true).left());
glViewport(viewport_box);
viewport.left(window_box(true).left());
glViewport(viewport);
/* bind texture for drawing */
camera_view.current().bind();
camera_view.enable();
@ -905,16 +928,17 @@ void Pudding::update()
glDrawArrays(GL_TRIANGLES, 0, camera_view.attributes("position")->count());
}
}
sb::Log::gl_errors("after capture, before test pad");
/* Test Pad */
glUseProgram(flat_program);
glUniformMatrix4fv(uniform["flat"]["transformation"], 1, GL_FALSE, &pad.transformation()[0][0]);
pad.texture().bind();
plane.enable();
glViewport(window_box(true));
glDrawArrays(GL_TRIANGLES, 0, pad.attributes("position")->count());
else
{
/* Draw the camera button if neither the camera or inventory is displayed */
glUseProgram(flat_program);
glUniformMatrix4fv(uniform["flat"]["transformation"], 1, GL_FALSE, &camera_button.transformation()[0][0]);
camera_button.texture().bind();
plane.enable();
glDrawArrays(GL_TRIANGLES, 0, camera_button.attributes("position")->count());
}
SDL_GL_SwapWindow(get_window());
sb::Log::gl_errors("after test pad");
sb::Log::gl_errors("at end of update");
/* add a new item if a new barcode was scanned or entered */
if (current_barcode != previous_barcode)
{
@ -928,21 +952,22 @@ void Pudding::update()
* is relative to (0.0, 0.0), and the scale is relative to the Plane, which has opposite corners at (-1.0, -1.0) and
* (1.0, 1.0). * The texture is the graphic that displays in the Pad location. The callback must be a function that
* doesn't return a value or accept any arguments. */
Pad::Pad(sb::Texture texture, glm::vec2 offset, float scale, float ratio, std::function<void()> on_connect)
Pad::Pad(sb::Texture texture, glm::vec2 offset, float scale, float ratio, std::function<void()> on_connect, float rotation)
{
this->texture(texture);
transform(offset, scale, ratio);
transform(offset, scale, ratio, rotation);
this->on_connect(on_connect);
box.gl(true);
box.invert_y(true);
}
/* Set the Pad's transformation matrix based on an offset, a scale, and an aspect ratio. The offset is amount it will
* be shifted in the (x, y) plane. The scale is a value relative to the (x, y) plane, but it is a single value because
* the aspect ratio will determine how much each axis is scaled. If the aspect ratio is above one, the x-axis's scale
* will be divided by the ratio. If the aspect ratio is below one, the y-axis's scale will be multiplied by the aspect
* ratio. If the aspect ratio of the window is given, this will force the Pad to display as a square, and the ratio
* will be relative to the shorter axis. */
void Pad::transform(glm::vec2 offset, float scale, float ratio)
/* Set the Pad's transformation matrix based on an offset, a scale, an aspect ratio, and a rotation. The offset is the
* amount it will be shifted in the (x, y) plane. The scale is a value relative to the (x, y) plane, and it is a single
* value because the aspect ratio will determine how much each axis is scaled. If the aspect ratio is above one, the
* x-axis's scale will be divided by the ratio. If the aspect ratio is below one, the y-axis's scale will be multiplied
* by the aspect ratio. If the aspect ratio of the window is given, this will force the Pad to display as a square, and
* the ratio will be relative to the shorter axis. The rotation is an angle in radians to rotate the pad object around
* its center after it has been offset and scaled. */
void Pad::transform(glm::vec2 offset, float scale, float ratio, float rotation)
{
glm::vec3 scale_components { scale, scale, 1 };
if (ratio > 1.0f)
@ -956,7 +981,8 @@ void Pad::transform(glm::vec2 offset, float scale, float ratio)
box.size({scale_components.x * 2, scale_components.y * 2});
box.center(offset);
std::cout << "pad box is " << box << std::endl;
Model::transform(glm::translate(glm::vec3{offset.x, offset.y, 0}) * glm::scale(scale_components));
Model::transform(glm::translate(glm::vec3{offset.x, offset.y, 0}) * glm::scale(scale_components) *
glm::rotate(rotation, glm::vec3{0.0f, 0.0f, 1.0f}));
}
/* Set the function that will run when a pad object is clicked. */

View File

@ -44,8 +44,6 @@
#include "utility.hpp"
#include "Box.hpp"
void glViewport(Box);
/* A connection is an object containing a binary state of either on (connected) or off (not connected)
* and user supplied functions that run automatically on each state change. The functions each have the
* same return type, number of arguments, and argument types determined by the template arguments.
@ -180,6 +178,18 @@ public:
* - Has its own response to click
* - Shares mouse collision code
* - Has its own translate + scale transformation
*
* Example:
*
* glm::vec3 w = glm::mat3({{1, 0, 0}, {0, 1, 0}, {-0.6739, -0.74, 1}}) * glm::mat3({{.1, 0, 0}, {0, .1 * (460.0 / 768.0), 0}, {0, 0, 1}}) *
* glm::vec3({-1, -1, 1});
* std::cout << w << std::endl << glm::translate(glm::vec3{-0.6739, -0.74, 0}) *
* glm::scale(glm::vec3{.1, .1 * (460.0 / 768.0), 1}) * glm::vec4{-1, -1, 0, 1} << std::endl;
* Pad p {background.current(), {-0.6739f, -0.74f}, 0.1f, get_display().window_box().aspect(), std::function<void()>()};
* const std::vector<glm::vec2>& p_position = *p.attributes("position");
* glm::vec4 final_position = p.transformation() * glm::vec4{p_position[2].x, p_position[2].y, 0, 1};
* std::cout << p.transformation() << std::endl << final_position << std::endl;
* assert(final_position == glm::vec4({w.x, w.y, 0, 1}));
*/
class Pad : public Plane
{
@ -193,8 +203,8 @@ private:
public:
Pad() {};
Pad(sb::Texture, glm::vec2, float, float, callback);
void transform(glm::vec2, float, float);
Pad(sb::Texture, glm::vec2, float, float, callback, float = 0.0f);
void transform(glm::vec2, float, float = 1.0f, float = 0.0f);
void on_connect(callback);
bool collide(const glm::vec2&) const;
@ -206,7 +216,7 @@ 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 */
* is the default integer, it will be set to the number of effects available. */
enum Effect
{
EFFECT_NONE,
@ -223,20 +233,21 @@ private:
};
typedef Game super;
const std::string OPEN_FOOD_API_URL = "https://world.openfoodfacts.org/api/v0/product/";
const std::string OPEN_PRODUCTS_API_URL = "https://world.openproductsfacts.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 GOOGLE_BOOKS_API_URL = "https://www.googleapis.com/books/v1/volumes?q=isbn:";
const std::string GIANTBOMB_API_URL = "https://www.giantbomb.com/api/release/?api_key=";
const glm::vec3 ZERO_VECTOR_3D {0, 0, 0};
const glm::vec3 Y_UNIT_NORMAL_3D {0, 1, 0};
const glm::mat4 VIEW_MATRIX = glm::lookAt({4.0f, 2.0f, 1.0f}, {0.0f, -0.325f, 0.0f}, Y_UNIT_NORMAL_3D);
const glm::vec3 PUDDING_BROWN {0.713f, 0.359f, 0.224f};
const glm::vec3 PUDDING_YELLOW {0.878f, 0.859f, 0.122f};
inline static const std::string OPEN_FOOD_API_URL = "https://world.openfoodfacts.org/api/v0/product/";
inline static const std::string OPEN_PRODUCTS_API_URL = "https://world.openproductsfacts.org/api/v0/product/";
inline static const std::string NUTRONIX_API_URL = "https://trackapi.nutritionix.com/v2/search/item?upc=";
inline static const std::string BARCODE_MONSTER_API_URL = "https://barcode.monster/api/";
inline static const std::string BEST_BUY_API_URL_1 = "https://api.bestbuy.com/v1/products(upc=";
inline static const std::string BEST_BUY_API_URL_2 = ")?format=json&apiKey=";
inline static const std::string NUTRONIX_NOT_FOUND = "resource not found";
inline static const std::string GOOGLE_BOOKS_API_URL = "https://www.googleapis.com/books/v1/volumes?q=isbn:";
inline static const std::string GIANTBOMB_API_URL = "https://www.giantbomb.com/api/release/?api_key=";
inline static const glm::vec3 ZERO_VECTOR_3D {0, 0, 0};
inline static const glm::vec3 Y_UNIT_NORMAL_3D {0, 1, 0};
inline static const glm::mat4 VIEW_MATRIX = glm::lookAt({4.0f, 2.0f, 1.0f}, {0.0f, -0.325f, 0.0f}, Y_UNIT_NORMAL_3D);
inline static const glm::vec3 PUDDING_BROWN {0.713f, 0.359f, 0.224f};
inline static const glm::vec3 PUDDING_YELLOW {0.878f, 0.859f, 0.122f};
std::shared_ptr<SDL_Cursor> poke;
std::string current_barcode, previous_barcode, current_config_barcode, current_camera_barcode;
std::vector<Item> items;
Carousel item_carousel;
@ -254,11 +265,14 @@ private:
SDL_GLContext capture_frame_thread_context = nullptr;
sb::VAO vao;
sb::VBO vbo;
Pad pad;
std::map<std::string, sb::Texture> labels;
Pad camera_button, previous_button, next_button, inventory_button;
Box viewport, main_viewport;
void set_pudding_model(float, float, int, int = 1, float = -1.0f, float = 1.0f, float = 0.3f);
void load_pudding_model(float, float, int, int = 1, float = -1.0f, float = 1.0f, float = 0.3f);
void load_gl_context();
void load_tiles();
void load_pads();
void initialize_camera();
void incorporate_open_api(Item&, const std::string&);
void incorporate_nutronix_api(Item&);
@ -308,4 +322,7 @@ private:
/* float weighted depression rate */
};
/* Allow a box object to be passed to glViewport instead of four vertices. */
void glViewport(Box);
#endif