From be7b750e891831bce480d7f1ad516ec7dbdadb8e Mon Sep 17 00:00:00 2001 From: frank <420@shampoo.ooo> Date: Fri, 10 Sep 2021 18:03:06 -0400 Subject: [PATCH] squircle top and bottom of pudding --- config.json | 10 ++++++++-- src/Pudding.cpp | 24 +++++++++++++++------- src/Pudding.hpp | 20 +++++++++++++------ src/mvp.frag | 53 +++++++++++++++++++++++++++++++++++++++++++------ src/mvp.vert | 15 +++++++++----- 5 files changed, 96 insertions(+), 26 deletions(-) diff --git a/config.json b/config.json index 4e1162f..0e2c3a3 100644 --- a/config.json +++ b/config.json @@ -46,7 +46,7 @@ "enabled": true, "json-save": true, "json-save-directory": "local/scans", - "barcode": "1703543090000", + "barcode": "", "capture-device": "/dev/video0" }, "api": @@ -65,6 +65,12 @@ }, "pudding": { - "rotation-speed": 0.005 + "rotation-speed": 0.005, + "top-radius": 1.0, + "base-radius": 1.6, + "ring-vertex-count": 10, + "layer-count": 12, + "y-range": [-0.6, 0.6], + "gradient-position": 0.25 } } diff --git a/src/Pudding.cpp b/src/Pudding.cpp index e06b575..46d549f 100644 --- a/src/Pudding.cpp +++ b/src/Pudding.cpp @@ -33,7 +33,9 @@ Pudding::Pudding() /* 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 */ - set_pudding_model(1.0f, 1.6f, 10, 12, -.6, .6, .25); + nlohmann::json pudding = get_configuration()["pudding"]; + set_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"]); /* use gl context so we can draw 3D */ load_gl_context(); } @@ -222,6 +224,7 @@ void Pudding::load_gl_context() glBindAttribLocation(flat_program, 0, "in_position"); glBindAttribLocation(flat_program, 1, "vertex_uv"); link_shader(flat_program); + flat_texture_uniform_location = glGetUniformLocation(flat_program, "base_texture"); /* load, configure and link the 3D world program */ vertex_shader = load_shader("src/mvp.vert", GL_VERTEX_SHADER); fragment_shader = load_shader("src/mvp.frag", GL_FRAGMENT_SHADER); @@ -235,6 +238,8 @@ void Pudding::load_gl_context() mvp_uniform_location = glGetUniformLocation(mvp_program, "mvp"); time_uniform_location = glGetUniformLocation(mvp_program, "time"); effect_uniform_location = glGetUniformLocation(mvp_program, "effect"); + uv_transformation_uniform_location = glGetUniformLocation(mvp_program, "uv_transformation"); + coordinate_bound_uniform_location = glGetUniformLocation(mvp_program, "coordinate_bound"); log_gl_errors(); } @@ -310,7 +315,7 @@ void Pudding::respond(SDL_Event& event) /* The effect command switches the active effect to the next in the list, wrapping around at the end */ else if (get_delegate().compare(event, "effect")) { - effect_id = ++effect_id % Effect::COUNT; + effect_id = ++effect_id % EFFECT_COUNT; glUseProgram(mvp_program); glUniform1i(effect_uniform_location, effect_id); } @@ -755,13 +760,12 @@ void Pudding::update() glDisableVertexAttribArray(3); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); - GLint base_texture_location = glGetUniformLocation(flat_program, "base_texture"); - glUniform1i(base_texture_location, 0); + glUniform1i(flat_texture_uniform_location, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, background_texture_id); /* 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"); - float hue = std::abs(std::abs(model[0][0]) - 0.5) * 2; + /* blend min with black will create a black blackground regardless of texture */ glUniform3f(blend_min_hsv_location, 0, 0, 0); /* draws rectangle vertices and rectangle texture using UV coords */ glDrawArrays(GL_TRIANGLES, 0, 6); @@ -796,9 +800,16 @@ void Pudding::update() } /* draw pudding model */ glEnable(GL_DEPTH_TEST); + /* draw the sides of the pudding */ glDrawArrays(GL_TRIANGLES, 0, pudding_triangle_vertex_count); + /* enable squircling and draw the top and bottom of pudding */ + glUniform1i(uv_transformation_uniform_location, UV_SQUIRCLE); + glUniform1f(coordinate_bound_uniform_location, get_configuration()["pudding"]["top-radius"]); glDrawArrays(GL_TRIANGLE_FAN, pudding_triangle_vertex_count, pudding_fan_vertex_count); + glUniform1f(coordinate_bound_uniform_location, get_configuration()["pudding"]["base-radius"]); glDrawArrays(GL_TRIANGLE_FAN, pudding_triangle_vertex_count + pudding_fan_vertex_count, pudding_fan_vertex_count); + /* disable squircling for all other drawing */ + glUniform1i(uv_transformation_uniform_location, UV_NONE); /* regular fill mode enabled for all other drawing */ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); /* only do more drawing if items are downloaded or camera is enabled */ @@ -813,8 +824,7 @@ void Pudding::update() glEnableVertexAttribArray(1); glDisable(GL_DEPTH_TEST); /* just need to set these once since we're drawing one texture per viewport */ - GLint base_texture_location = glGetUniformLocation(flat_program, "base_texture"); - glUniform1i(base_texture_location, 0); + glUniform1i(flat_texture_uniform_location, 0); glActiveTexture(GL_TEXTURE0); /* move viewport to the bottom of screen */ viewport_box.top(viewport_box.bottom(), true); diff --git a/src/Pudding.hpp b/src/Pudding.hpp index 14aad8f..89900ed 100644 --- a/src/Pudding.hpp +++ b/src/Pudding.hpp @@ -33,10 +33,17 @@ private: * is the default integer, it will define the number of effects available */ enum Effect { - NONE, - SNAKE, - WOBBLE, - COUNT + 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; @@ -54,11 +61,12 @@ 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 items; - int current_item_index = 0, effect_id = Effect::NONE, pudding_triangle_vertex_count = 0, pudding_fan_vertex_count = 0; + int current_item_index = 0, effect_id = EFFECT_NONE, pudding_triangle_vertex_count = 0, pudding_fan_vertex_count = 0; cv::VideoCapture capture; zbar::ImageScanner image_scanner; GLuint flat_program, mvp_program, capture_texture_front_buffer_id, capture_texture_back_buffer_id, capture_texture_id, - mvp_uniform_location, background_texture_id, time_uniform_location, effect_uniform_location; + mvp_uniform_location, background_texture_id, time_uniform_location, effect_uniform_location, uv_transformation_uniform_location, + flat_texture_uniform_location, coordinate_bound_uniform_location; glm::mat4 projection, model = glm::mat4(1.0f), mvp; std::vector pudding_vertices, pudding_colors; std::vector pudding_uv; diff --git a/src/mvp.frag b/src/mvp.frag index 7dc5a52..07e0de0 100644 --- a/src/mvp.frag +++ b/src/mvp.frag @@ -1,11 +1,46 @@ #version 130 -in vec3 ex_color; -in float x; -in vec2 uv; -uniform sampler2D pudding_texture; +#define TRANSFORMATION_NONE 0 +#define TRANSFORMATION_SQUIRCLE 1 -void color() +in vec2 fragment_uv; +in vec3 ex_color; +in float x_center_proximity; +in vec3 original_coordinates; +in vec3 clip_coordinates; +uniform sampler2D pudding_texture; +uniform int uv_transformation = TRANSFORMATION_NONE; +uniform float coordinate_bound; + +/* [-coordinate_bound, coordinate_bound] arbitrary box coordinates to [-1, 1] normalized coordinates */ +vec2 normalize_coordinates(vec2 coordinates) +{ + return coordinates / coordinate_bound; +} + +/* [-1, 1] box coordinates to [0, 1] UV coordinates */ +vec2 coordinates_to_uv(vec2 coordinates) +{ + return (coordinates + 1) / 2; +} + +/* coordinates in circle with radius <= 1 to box coordinates in [-1, 1] */ +vec2 circle_to_box(vec2 circle) +{ + float u = circle.x; + float v = circle.y; + float u_sq = pow(u, 2); + float v_sq = pow(v, 2); + float rt_2 = sqrt(2); + float x = .5 * sqrt(2 + 2 * u * rt_2 + u_sq - v_sq) - .5 * sqrt(2 - 2 * u * rt_2 + u_sq - v_sq); + float y = .5 * sqrt(2 + 2 * v * rt_2 - u_sq + v_sq) - .5 * sqrt(2 - 2 * v * rt_2 - u_sq + v_sq); + return vec2(x, y); +} + +/* Apply color passed in from the vertex shader, compressing to one of 16 colors. Add retro effect + * by alternately darkening and lightening 2x2 pixel areas in a checker pattern. Add shadowing by + * brightening the color based on how near it is to the center in the X-dimension */ +void retro() { vec3 shadowed = min(ex_color, 1.0); float dx = abs(floor(gl_FragCoord[0]) - 480) / 480.0; @@ -20,10 +55,16 @@ void color() gl_FragColor[0] = int(gl_FragColor[0] * 4) / 4.0; gl_FragColor[1] = int(gl_FragColor[1] * 4) / 4.0; gl_FragColor[2] = int(gl_FragColor[2] * 4) / 4.0; - gl_FragColor *= x; + gl_FragColor *= x_center_proximity; } void main() { + vec2 uv = fragment_uv; + if (uv_transformation == TRANSFORMATION_SQUIRCLE) + { + vec2 normalized_circle_coordinates = normalize_coordinates(vec2(original_coordinates.x, original_coordinates.z)); + uv = coordinates_to_uv(circle_to_box(normalized_circle_coordinates)); + } gl_FragColor = texture(pudding_texture, uv); } diff --git a/src/mvp.vert b/src/mvp.vert index ea86f21..c0bd1d8 100644 --- a/src/mvp.vert +++ b/src/mvp.vert @@ -15,8 +15,10 @@ uniform mat4 mvp; uniform float time; uniform int effect = EFFECT_NONE; out vec3 ex_color; -out float x; -out vec2 uv; +out float x_center_proximity; +out vec2 fragment_uv; +out vec3 original_coordinates; +out vec3 clip_coordinates; /* Offset X-coordinate according to the time step and Y-coordinate to create a wobble effect when run on * flattened coordinates (after projection matrix has been applied) */ @@ -47,11 +49,14 @@ void main() gl_Position = vec4(in_position, 1); } gl_Position = mvp * gl_Position; - ex_color = in_color; - x = 1.8 - abs(in_position[0]); if (effect == EFFECT_WOBBLE) { wobble(); } - uv = vertex_uv; + /* passing to fragment program */ + ex_color = in_color; + x_center_proximity = 1.8 - abs(in_position[0]); + fragment_uv = vertex_uv; + original_coordinates = in_position; + clip_coordinates = gl_Position.xyz; }