diff --git a/config.json b/config.json index 4fd6d25..51a3329 100644 --- a/config.json +++ b/config.json @@ -47,7 +47,7 @@ "enabled": true, "json-save": true, "json-save-directory": "local/scans", - "barcode": "045496591922", + "barcode": "037600110754", "capture-device": "/dev/video0" }, "api": diff --git a/lib/sb b/lib/sb index 3baaa76..3e5e0fc 160000 --- a/lib/sb +++ b/lib/sb @@ -1 +1 @@ -Subproject commit 3baaa7624e42880a47d55b2e659038019131ee02 +Subproject commit 3e5e0fcbb8aedd5c4ce15aa850e88511af17ad5e diff --git a/src/Pudding.cpp b/src/Pudding.cpp index 1637c6a..ed616e0 100644 --- a/src/Pudding.cpp +++ b/src/Pudding.cpp @@ -92,30 +92,30 @@ void Pudding::set_pudding_model( /* triangle that includes top two vertices and first base vertex */ start_vertex = &layer_top_ring[ii]; end_vertex = &layer_top_ring[(ii + 1) % layer_top_ring.size()]; - pudding_attributes["vertices"].add(start_vertex->x, layer_top_y, start_vertex->y); + pudding_attributes["position"].add(start_vertex->x, layer_top_y, start_vertex->y); pudding_attributes["uv"].add(ring_start_vertex_u, layer_top_percent); - pudding_attributes["vertices"].add(end_vertex->x, layer_top_y, end_vertex->y); + pudding_attributes["position"].add(end_vertex->x, layer_top_y, end_vertex->y); pudding_attributes["uv"].add(ring_start_vertex_u + u_step, layer_top_percent); pudding_attributes["color"].extend(*layer_top_color, 2); - pudding_attributes["vertices"].add(layer_base_ring[ii].x, layer_base_y, layer_base_ring[ii].y); + pudding_attributes["position"].add(layer_base_ring[ii].x, layer_base_y, layer_base_ring[ii].y); pudding_attributes["uv"].add(ring_start_vertex_u, layer_base_percent); pudding_attributes["color"].add(*layer_bottom_color); /* triangle that includes bottom two vertices and second top vertex */ start_vertex = &layer_base_ring[ii]; - pudding_attributes["vertices"].add(start_vertex->x, layer_base_y, start_vertex->y); + pudding_attributes["position"].add(start_vertex->x, layer_base_y, start_vertex->y); pudding_attributes["uv"].add(ring_start_vertex_u, layer_base_percent); - pudding_attributes["colors"].add(*layer_bottom_color); - pudding_attributes["vertices"].add(end_vertex->x, layer_top_y, end_vertex->y); + pudding_attributes["color"].add(*layer_bottom_color); + pudding_attributes["position"].add(end_vertex->x, layer_top_y, end_vertex->y); pudding_attributes["uv"].add(ring_start_vertex_u + u_step, layer_top_percent); pudding_attributes["color"].add(*layer_top_color); end_vertex = &layer_base_ring[(ii + 1) % layer_base_ring.size()]; - pudding_attributes["vertices"].add(end_vertex->x, layer_base_y, end_vertex->y); + pudding_attributes["position"].add(end_vertex->x, layer_base_y, end_vertex->y); pudding_attributes["uv"].add(ring_start_vertex_u + u_step, layer_base_percent); pudding_attributes["color"].add(*layer_bottom_color); ring_start_vertex_u += u_step; } } - pudding_triangle_vertex_count = pudding_attributes["vertices"].count(); + pudding_triangle_vertex_count = pudding_attributes["position"].count(); /* process the top and bottom of pudding, filling each face with a triangle fan */ float y = max_y; const glm::vec3* face_color = &PUDDING_BROWN; @@ -123,7 +123,7 @@ void Pudding::set_pudding_model( for (float radius : {top_radius, base_radius}) { /* first point in a GL_TRIANGLE_FAN is the center */ - pudding_attributes["vertices"].add(0.0f, y, 0.0f); + pudding_attributes["position"].add(0.0f, y, 0.0f); pudding_attributes["uv"].add(0.0f, 0.0f); layer_top_ring.clear(); sb::points_on_circle(layer_top_ring, ring_vertex_count, radius); @@ -132,22 +132,25 @@ void Pudding::set_pudding_model( { start_vertex = &layer_top_ring[ii]; /* for GL_TRIANGLE_FAN we just need to add an outer vertex */ - pudding_attributes["vertices"].add(start_vertex->x, y, start_vertex->y); + pudding_attributes["position"].add(start_vertex->x, y, start_vertex->y); pudding_attributes["uv"].add(*start_vertex); /* connect the ring on the last vertex */ if (ii == layer_top_ring.size() - 1) { end_vertex = &layer_top_ring[(ii + 1) % layer_top_ring.size()]; - pudding_attributes["vertices"].add(end_vertex->x, y, end_vertex->y); + pudding_attributes["position"].add(end_vertex->x, y, end_vertex->y); pudding_attributes["uv"].add(*end_vertex); } } /* single color for the entire layer_top_ring */ - pudding_attributes["colors"].extend(*face_color, layer_top_ring.size() + 2); + pudding_attributes["color"].extend(*face_color, layer_top_ring.size() + 2); y = min_y; face_color = &PUDDING_YELLOW; } - pudding_fan_vertex_count = (pudding_attributes["vertices"].count() - pudding_triangle_vertex_count) / 2; + pudding_fan_vertex_count = (pudding_attributes["position"].count() - pudding_triangle_vertex_count) / 2; + pudding_attributes["position"].index(0); + pudding_attributes["color"].index(1); + pudding_attributes["uv"].index(2); } /* Create GL context via super class and load vertices, UV data, and shaders */ @@ -184,7 +187,6 @@ void Pudding::load_gl_context() * will be copied in one after the other, offset to after the previous data location. The same buffer offset will * be passed to the vertex attributes for each data. */ vbo.generate(); - vbo.target(GL_ARRAY_BUFFER); vbo.bind(); /* Load two shader programs, one for rendering the flat objects, and one for rendering the 3D model. Load and configure * the flat shader program first. */ @@ -193,46 +195,27 @@ void Pudding::load_gl_context() flat_program = glCreateProgram(); glAttachShader(flat_program, vertex_shader); glAttachShader(flat_program, fragment_shader); - glBindAttribLocation(flat_program, rectangle_attributes["position"].index(), "in_position"); - glBindAttribLocation(flat_program, rectangle_attributes["uv"].index(), "vertex_uv"); + glBindAttribLocation(flat_program, rectangle_attributes["position"], "in_position"); + glBindAttribLocation(flat_program, rectangle_attributes["uv"], "vertex_uv"); /* 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); mvp_program = glCreateProgram(); glAttachShader(mvp_program, vertex_shader); glAttachShader(mvp_program, fragment_shader); - glBindAttribLocation(mvp_program, 2, "in_position"); - glBindAttribLocation(mvp_program, 3, "in_color"); - glBindAttribLocation(mvp_program, 4, "vertex_uv"); + glBindAttribLocation(mvp_program, pudding_attributes["position"], "in_position"); + glBindAttribLocation(mvp_program, pudding_attributes["color"], "in_color"); + glBindAttribLocation(mvp_program, pudding_attributes["uv"], "vertex_uv"); sb::Log::gl_errors("after loading shaders"); - /* allocate space for vertices, UV and colors, and copy rectangle vertices in at initialization */ - GLsizeiptr vbo_size = rectangle_attributes["position"].size() + rectangle_attributes["uv"].size() + pudding_attributes["uv"].size() + - pudding_attributes["vertices"].size() + pudding_attributes["colors"].size(); - glBufferData(GL_ARRAY_BUFFER, vbo_size, rectangle_attributes["position"], GL_STATIC_DRAW); - /* specify the rectangle vertex attributes as consecutive 2D float coords */ - glVertexAttribPointer(rectangle_attributes["position"].index(), rectangle_attributes["position"].dimensions(), - rectangle_attributes["position"].type(), GL_FALSE, 0, nullptr); - /* copy rectangle UV data into the VBO, offset to after the vertex data, set up attributes */ - GLintptr offset = rectangle_attributes["position"].size(); - glBufferSubData(GL_ARRAY_BUFFER, offset, rectangle_attributes["uv"].size(), rectangle_attributes["uv"]); - glVertexAttribPointer(rectangle_attributes["uv"].index(), rectangle_attributes["uv"].dimensions(), - rectangle_attributes["uv"].type(), GL_FALSE, 0, reinterpret_cast(offset)); - /* copy pudding vertices into VBO, offset to after the rectangle UV, and set up vertex attributes for 3D */ - offset += rectangle_attributes["uv"].size(); - glBufferSubData(GL_ARRAY_BUFFER, offset, pudding_attributes["vertices"].size(), pudding_attributes["vertices"]); - glVertexAttribPointer(2, pudding_attributes["vertices"].dimensions(), pudding_attributes["vertices"].type(), - GL_FALSE, 0, reinterpret_cast(offset)); - /* copy pudding color values into VBO, offset to after pudding vertices and set as 3D */ - offset += pudding_attributes["vertices"].size(); - glBufferSubData(GL_ARRAY_BUFFER, offset, pudding_attributes["colors"].size(), pudding_attributes["colors"]); - glVertexAttribPointer(3, pudding_attributes["colors"].dimensions(), pudding_attributes["colors"].type(), - GL_FALSE, 0, reinterpret_cast(offset)); - /* copy pudding UV values into VBO, offset to after pudding color vertices and set as 2D */ - offset += pudding_attributes["colors"].size(); - glBufferSubData(GL_ARRAY_BUFFER, offset, pudding_attributes["uv"].size(), pudding_attributes["uv"]); - glVertexAttribPointer(4, pudding_attributes["uv"].dimensions(), pudding_attributes["uv"].type(), - GL_FALSE, 0, reinterpret_cast(offset)); - sb::Log::gl_errors("after loading attributes"); + /* Fill VBO with attribute data */ + vbo.allocate(rectangle_attributes["position"].size() + rectangle_attributes["uv"].size() + pudding_attributes["uv"].size() + + pudding_attributes["position"].size() + pudding_attributes["color"].size(), GL_STATIC_DRAW); + vbo.add(rectangle_attributes["position"]); + vbo.add(rectangle_attributes["uv"]); + vbo.add(pudding_attributes["uv"]); + vbo.add(pudding_attributes["position"]); + vbo.add(pudding_attributes["color"]); + sb::Log::gl_errors("after filling VBO"); /* link shaders */ link_shader(flat_program); link_shader(mvp_program); @@ -762,10 +745,11 @@ void Pudding::update() glUseProgram(flat_program); glUniform1f(flat_time_uniform_location, time_seconds); /* disable pudding attributes and enable rectangle attributes */ - glDisableVertexAttribArray(2); - glDisableVertexAttribArray(3); - glEnableVertexAttribArray(rectangle_attributes["position"].index()); - glEnableVertexAttribArray(rectangle_attributes["uv"].index()); + glDisableVertexAttribArray(pudding_attributes["position"]); + glDisableVertexAttribArray(pudding_attributes["color"]); + glDisableVertexAttribArray(pudding_attributes["uv"]); + glEnableVertexAttribArray(rectangle_attributes["position"]); + glEnableVertexAttribArray(rectangle_attributes["uv"]); glUniform1i(flat_texture_uniform_location, 0); glActiveTexture(GL_TEXTURE0); tiles[current_tile_index].bind(); @@ -787,19 +771,19 @@ void Pudding::update() /* pass the mvp matrix to the shader */ glUniformMatrix4fv(mvp_uniform_location, 1, GL_FALSE, &mvp[0][0]); /* disable rectangle attributes and enable pudding attributes */ - glDisableVertexAttribArray(rectangle_attributes["position"].index()); - glDisableVertexAttribArray(rectangle_attributes["uv"].index()); - glEnableVertexAttribArray(2); + glDisableVertexAttribArray(rectangle_attributes["position"]); + glDisableVertexAttribArray(rectangle_attributes["color"]); + glEnableVertexAttribArray(pudding_attributes["position"]); if (items.size() == 0) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glEnableVertexAttribArray(3); + glEnableVertexAttribArray(pudding_attributes["color"]); } else { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glEnableVertexAttribArray(3); - glEnableVertexAttribArray(4); + glEnableVertexAttribArray(pudding_attributes["color"]); + glEnableVertexAttribArray(pudding_attributes["uv"]); GLuint pudding_texture_location = glGetUniformLocation(mvp_program, "pudding_texture"); glUniform1i(pudding_texture_location, 0); glActiveTexture(GL_TEXTURE0); @@ -825,8 +809,9 @@ void Pudding::update() /* switch to flat shader for item and camera */ glUseProgram(flat_program); /* disable pudding attributes and enable rectangle attributes */ - glDisableVertexAttribArray(2); - glDisableVertexAttribArray(3); + glDisableVertexAttribArray(pudding_attributes["position"]); + glDisableVertexAttribArray(pudding_attributes["color"]); + glDisableVertexAttribArray(pudding_attributes["uv"]); glEnableVertexAttribArray(rectangle_attributes["position"].index()); glEnableVertexAttribArray(rectangle_attributes["uv"].index()); glDisable(GL_DEPTH_TEST); @@ -909,32 +894,46 @@ void vao_deleter(GLuint* id) glDeleteVertexArrays(1, id); } -Buffer::Buffer() : GLObject(buffer_deleter) {} +Buffer::Buffer() : Buffer(GL_INVALID_ENUM) {} -/* Forward the GL generate function to the base class */ +Buffer::Buffer(GLenum target) : GLObject(buffer_deleter), buffer_target(target) {} + +/* Forward the GL generate function to the base class. */ void Buffer::generate() { GLObject::generate(glGenBuffers); } -/* Set the type of data being held in this buffer */ +/* Set the target for this buffer. */ void Buffer::target(GLenum target) { buffer_target = target; } -/* Return the type of data being held in this buffer as a GLenum */ +/* Return the GL enum for target */ GLenum Buffer::target() const { return buffer_target; } -/* Bind this Buffer to the current GL context */ +/* Bind this Buffer to the current GL context. An exception will be thrown if the target has not + * been set. */ void Buffer::bind() const { + if (target() == GL_INVALID_ENUM) + { + throw std::invalid_argument("target must be set before binding buffer"); + } glBindBuffer(target(), id()); } +/* Set the target and bind the buffer. */ +void Buffer::bind(GLenum target) +{ + this->target(target); + bind(); +} + /* This function gets passed to the abstract base class for deleting the Buffer data when the ID * pointer goes out of scope (when all instances of this Buffer and its copies are out of scope) */ void buffer_deleter(GLuint* id) @@ -943,3 +942,54 @@ void buffer_deleter(GLuint* id) SDL_Log("destroying buffer ID %i", *id); glDeleteBuffers(1, id); } + +/* Initialize a Vertex Buffer Object. The base class will be initalized with a target of + * GL_ARRAY_BUFFER. */ +VBO::VBO() : Buffer(GL_ARRAY_BUFFER) {} + +/* Allocate size bytes of vertex attribute memory on the GPU. Usage should be one of GL_STREAM_DRAW, + * GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW, + * GL_DYNAMIC_READ, or GL_DYNAMIC_COPY. The memory will be uninitialized. */ +void VBO::allocate(GLsizeiptr size, GLenum usage) +{ + glBufferData(target(), size, nullptr, usage); + /* Debug */ + std::ostringstream message; + message << "After allocating memory for " << *this; + sb::Log::gl_errors(message.str()); +} + +/* Set memory in the GPU buffer to the values of the attribute data using glBufferSubData. The memory + * set is a contiguous area from the object's current byte offset value to the offset plus the size in + * bytes of the attributes. After the memory is set, the offset is set to the end of the area. + * + * Define an array of vertex attribute data on the GPU by passing the attributes's index, dimensions, + * normalization state, and type to glVertexAttribPointer, along with the buffer object's current + * offset. */ +void VBO::add(sb::Attributes& attributes) +{ + /* Set memory */ + glBufferSubData(target(), offset, attributes.size(), attributes); + /* Debug */ + std::ostringstream initialization_message; + initialization_message << "After setting " << attributes.size() << "bytes in " << *this; + sb::Log::gl_errors(initialization_message.str()); + /* Define array */ + glVertexAttribPointer( + attributes.index(), attributes.dimensions(), attributes.type(), attributes.normalized(), 0, reinterpret_cast(offset)); + /* Debug */ + std::ostringstream pointer_message; + pointer_message << "After defining attribute pointer for "; + sb::Log::gl_errors(pointer_message.str()); + /* Increase offset */ + offset += attributes.size(); +} + +/* Overload the stream operator to support adding the attributes in a VBO. Add each attributes object to + * the output stream. */ +std::ostream& operator<<(std::ostream& out, const VBO& vbo) +{ + out << ""; + return out; +} diff --git a/src/Pudding.hpp b/src/Pudding.hpp index 552561e..b5fc200 100644 --- a/src/Pudding.hpp +++ b/src/Pudding.hpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include "SDL.h" #include "SDL_image.h" @@ -62,32 +64,45 @@ class Buffer : public GLObject private: - GLenum buffer_target, buffer_usage; - std::uint32_t buffer_add_use_count = 0, buffer_calculated_size = 0; + GLenum buffer_target = GL_INVALID_ENUM; + +protected: + + GLenum target() const; public: Buffer(); - Buffer(GLenum, GLenum); - - void generate(); + Buffer(GLenum); void target(GLenum); - GLenum target() const; + void generate(); void bind() const; - void allocate(GLsizeiptr); - void allocate(GLenum, GLenum, GLsizeiptr); - - template - sb::Attributes add(VAO& vao, std::vector vertex_attributes) - { - vao.increment(); - // glVertexAttribPointer(vao.counted(), - } + void bind(GLenum); }; void buffer_deleter(GLuint*); +class VBO; + +std::ostream& operator<<(std::ostream&, const VBO&); + +class VBO : public Buffer +{ + +private: + + GLintptr offset = 0; + +public: + + VBO(); + void allocate(GLsizeiptr, GLenum); + void add(sb::Attributes&); + friend std::ostream& operator<<(std::ostream&, const VBO&); + +}; + class Pudding : public Game { @@ -134,7 +149,7 @@ private: flat_time_uniform_location, scroll_uniform_location; glm::mat4 projection, model = glm::mat4(1.0f), mvp; std::map rectangle_attributes, pudding_attributes = { - {"vertices", sb::Attributes()}, + {"position", sb::Attributes()}, {"uv", sb::Attributes()}, {"color", sb::Attributes()} }; @@ -144,7 +159,7 @@ private: Texture capture_texture_front_buffer, capture_texture_back_buffer; Texture& capture_texture = capture_texture_front_buffer; VAO vao; - Buffer vbo; + VBO vbo, other_vbo; void set_pudding_model(float, float, int, int = 1, float = -1, float = 1, float = 0.3f); void load_gl_context(); @@ -183,12 +198,53 @@ class Plane : public Model { }; -class Billboard : public Plane +/* Apply force until reaching a threshold. Use a connection object to run user functions + * when force reaches threshold and when force goes below threshold. */ +class Button +{ + /* threshold */ + /* force */ + /* close */ + /* open */ + /* apply */ + /* remove */ + /* weighted depression rate */ + /* Animation (?) */ +}; + +class Pad { }; -class Button : public Billboard +/* 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