vertex buffer object class for adding attribute data to gpu

This commit is contained in:
frank 2021-10-17 03:27:53 -04:00
parent 25e2a7ad4f
commit cdf4b8ce0e
4 changed files with 191 additions and 85 deletions

View File

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

2
lib/sb

@ -1 +1 @@
Subproject commit 3baaa7624e42880a47d55b2e659038019131ee02 Subproject commit 3e5e0fcbb8aedd5c4ce15aa850e88511af17ad5e

View File

@ -92,30 +92,30 @@ void Pudding::set_pudding_model(
/* triangle that includes top two vertices and first base vertex */ /* triangle that includes top two vertices and first base vertex */
start_vertex = &layer_top_ring[ii]; start_vertex = &layer_top_ring[ii];
end_vertex = &layer_top_ring[(ii + 1) % layer_top_ring.size()]; 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["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["uv"].add(ring_start_vertex_u + u_step, layer_top_percent);
pudding_attributes["color"].extend(*layer_top_color, 2); 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["uv"].add(ring_start_vertex_u, layer_base_percent);
pudding_attributes["color"].add(*layer_bottom_color); pudding_attributes["color"].add(*layer_bottom_color);
/* triangle that includes bottom two vertices and second top vertex */ /* triangle that includes bottom two vertices and second top vertex */
start_vertex = &layer_base_ring[ii]; 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["uv"].add(ring_start_vertex_u, layer_base_percent);
pudding_attributes["colors"].add(*layer_bottom_color); pudding_attributes["color"].add(*layer_bottom_color);
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["uv"].add(ring_start_vertex_u + u_step, layer_top_percent);
pudding_attributes["color"].add(*layer_top_color); pudding_attributes["color"].add(*layer_top_color);
end_vertex = &layer_base_ring[(ii + 1) % layer_base_ring.size()]; 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["uv"].add(ring_start_vertex_u + u_step, layer_base_percent);
pudding_attributes["color"].add(*layer_bottom_color); pudding_attributes["color"].add(*layer_bottom_color);
ring_start_vertex_u += u_step; 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 */ /* process the top and bottom of pudding, filling each face with a triangle fan */
float y = max_y; float y = max_y;
const glm::vec3* face_color = &PUDDING_BROWN; const glm::vec3* face_color = &PUDDING_BROWN;
@ -123,7 +123,7 @@ void Pudding::set_pudding_model(
for (float radius : {top_radius, base_radius}) for (float radius : {top_radius, base_radius})
{ {
/* first point in a GL_TRIANGLE_FAN is the center */ /* 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); pudding_attributes["uv"].add(0.0f, 0.0f);
layer_top_ring.clear(); layer_top_ring.clear();
sb::points_on_circle(layer_top_ring, ring_vertex_count, radius); 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]; start_vertex = &layer_top_ring[ii];
/* for GL_TRIANGLE_FAN we just need to add an outer vertex */ /* 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); pudding_attributes["uv"].add(*start_vertex);
/* connect the ring on the last vertex */ /* connect the ring on the last vertex */
if (ii == layer_top_ring.size() - 1) if (ii == layer_top_ring.size() - 1)
{ {
end_vertex = &layer_top_ring[(ii + 1) % layer_top_ring.size()]; 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); pudding_attributes["uv"].add(*end_vertex);
} }
} }
/* single color for the entire layer_top_ring */ /* 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; y = min_y;
face_color = &PUDDING_YELLOW; 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 */ /* 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 * 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. */ * be passed to the vertex attributes for each data. */
vbo.generate(); vbo.generate();
vbo.target(GL_ARRAY_BUFFER);
vbo.bind(); vbo.bind();
/* Load two shader programs, one for rendering the flat objects, and one for rendering the 3D model. Load and configure /* 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. */ * the flat shader program first. */
@ -193,46 +195,27 @@ void Pudding::load_gl_context()
flat_program = glCreateProgram(); flat_program = glCreateProgram();
glAttachShader(flat_program, vertex_shader); glAttachShader(flat_program, vertex_shader);
glAttachShader(flat_program, fragment_shader); glAttachShader(flat_program, fragment_shader);
glBindAttribLocation(flat_program, rectangle_attributes["position"].index(), "in_position"); glBindAttribLocation(flat_program, rectangle_attributes["position"], "in_position");
glBindAttribLocation(flat_program, rectangle_attributes["uv"].index(), "vertex_uv"); glBindAttribLocation(flat_program, rectangle_attributes["uv"], "vertex_uv");
/* load, configure and link the 3D world program */ /* load, configure and link the 3D world program */
vertex_shader = load_shader("src/mvp.vert", GL_VERTEX_SHADER); vertex_shader = load_shader("src/mvp.vert", GL_VERTEX_SHADER);
fragment_shader = load_shader("src/mvp.frag", GL_FRAGMENT_SHADER); fragment_shader = load_shader("src/mvp.frag", GL_FRAGMENT_SHADER);
mvp_program = glCreateProgram(); mvp_program = glCreateProgram();
glAttachShader(mvp_program, vertex_shader); glAttachShader(mvp_program, vertex_shader);
glAttachShader(mvp_program, fragment_shader); glAttachShader(mvp_program, fragment_shader);
glBindAttribLocation(mvp_program, 2, "in_position"); glBindAttribLocation(mvp_program, pudding_attributes["position"], "in_position");
glBindAttribLocation(mvp_program, 3, "in_color"); glBindAttribLocation(mvp_program, pudding_attributes["color"], "in_color");
glBindAttribLocation(mvp_program, 4, "vertex_uv"); glBindAttribLocation(mvp_program, pudding_attributes["uv"], "vertex_uv");
sb::Log::gl_errors("after loading shaders"); sb::Log::gl_errors("after loading shaders");
/* allocate space for vertices, UV and colors, and copy rectangle vertices in at initialization */ /* Fill VBO with attribute data */
GLsizeiptr vbo_size = rectangle_attributes["position"].size() + rectangle_attributes["uv"].size() + pudding_attributes["uv"].size() + vbo.allocate(rectangle_attributes["position"].size() + rectangle_attributes["uv"].size() + pudding_attributes["uv"].size() +
pudding_attributes["vertices"].size() + pudding_attributes["colors"].size(); pudding_attributes["position"].size() + pudding_attributes["color"].size(), GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, vbo_size, rectangle_attributes["position"], GL_STATIC_DRAW); vbo.add(rectangle_attributes["position"]);
/* specify the rectangle vertex attributes as consecutive 2D float coords */ vbo.add(rectangle_attributes["uv"]);
glVertexAttribPointer(rectangle_attributes["position"].index(), rectangle_attributes["position"].dimensions(), vbo.add(pudding_attributes["uv"]);
rectangle_attributes["position"].type(), GL_FALSE, 0, nullptr); vbo.add(pudding_attributes["position"]);
/* copy rectangle UV data into the VBO, offset to after the vertex data, set up attributes */ vbo.add(pudding_attributes["color"]);
GLintptr offset = rectangle_attributes["position"].size(); sb::Log::gl_errors("after filling VBO");
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<GLvoid*>(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<GLvoid*>(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<GLvoid*>(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<GLvoid*>(offset));
sb::Log::gl_errors("after loading attributes");
/* link shaders */ /* link shaders */
link_shader(flat_program); link_shader(flat_program);
link_shader(mvp_program); link_shader(mvp_program);
@ -762,10 +745,11 @@ void Pudding::update()
glUseProgram(flat_program); glUseProgram(flat_program);
glUniform1f(flat_time_uniform_location, time_seconds); glUniform1f(flat_time_uniform_location, time_seconds);
/* disable pudding attributes and enable rectangle attributes */ /* disable pudding attributes and enable rectangle attributes */
glDisableVertexAttribArray(2); glDisableVertexAttribArray(pudding_attributes["position"]);
glDisableVertexAttribArray(3); glDisableVertexAttribArray(pudding_attributes["color"]);
glEnableVertexAttribArray(rectangle_attributes["position"].index()); glDisableVertexAttribArray(pudding_attributes["uv"]);
glEnableVertexAttribArray(rectangle_attributes["uv"].index()); glEnableVertexAttribArray(rectangle_attributes["position"]);
glEnableVertexAttribArray(rectangle_attributes["uv"]);
glUniform1i(flat_texture_uniform_location, 0); glUniform1i(flat_texture_uniform_location, 0);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
tiles[current_tile_index].bind(); tiles[current_tile_index].bind();
@ -787,19 +771,19 @@ void Pudding::update()
/* pass the mvp matrix to the shader */ /* pass the mvp matrix to the shader */
glUniformMatrix4fv(mvp_uniform_location, 1, GL_FALSE, &mvp[0][0]); glUniformMatrix4fv(mvp_uniform_location, 1, GL_FALSE, &mvp[0][0]);
/* disable rectangle attributes and enable pudding attributes */ /* disable rectangle attributes and enable pudding attributes */
glDisableVertexAttribArray(rectangle_attributes["position"].index()); glDisableVertexAttribArray(rectangle_attributes["position"]);
glDisableVertexAttribArray(rectangle_attributes["uv"].index()); glDisableVertexAttribArray(rectangle_attributes["color"]);
glEnableVertexAttribArray(2); glEnableVertexAttribArray(pudding_attributes["position"]);
if (items.size() == 0) if (items.size() == 0)
{ {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glEnableVertexAttribArray(3); glEnableVertexAttribArray(pudding_attributes["color"]);
} }
else else
{ {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnableVertexAttribArray(3); glEnableVertexAttribArray(pudding_attributes["color"]);
glEnableVertexAttribArray(4); glEnableVertexAttribArray(pudding_attributes["uv"]);
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);
@ -825,8 +809,9 @@ void Pudding::update()
/* switch to flat shader for item and camera */ /* switch to flat shader for item and camera */
glUseProgram(flat_program); glUseProgram(flat_program);
/* disable pudding attributes and enable rectangle attributes */ /* disable pudding attributes and enable rectangle attributes */
glDisableVertexAttribArray(2); glDisableVertexAttribArray(pudding_attributes["position"]);
glDisableVertexAttribArray(3); glDisableVertexAttribArray(pudding_attributes["color"]);
glDisableVertexAttribArray(pudding_attributes["uv"]);
glEnableVertexAttribArray(rectangle_attributes["position"].index()); glEnableVertexAttribArray(rectangle_attributes["position"].index());
glEnableVertexAttribArray(rectangle_attributes["uv"].index()); glEnableVertexAttribArray(rectangle_attributes["uv"].index());
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
@ -909,32 +894,46 @@ void vao_deleter(GLuint* id)
glDeleteVertexArrays(1, 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() void Buffer::generate()
{ {
GLObject::generate(glGenBuffers); GLObject::generate(glGenBuffers);
} }
/* Set the type of data being held in this buffer */ /* Set the target for this buffer. */
void Buffer::target(GLenum target) void Buffer::target(GLenum target)
{ {
buffer_target = 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 GLenum Buffer::target() const
{ {
return buffer_target; 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 void Buffer::bind() const
{ {
if (target() == GL_INVALID_ENUM)
{
throw std::invalid_argument("target must be set before binding buffer");
}
glBindBuffer(target(), id()); 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 /* 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) */ * pointer goes out of scope (when all instances of this Buffer and its copies are out of scope) */
void buffer_deleter(GLuint* id) void buffer_deleter(GLuint* id)
@ -943,3 +942,54 @@ void buffer_deleter(GLuint* id)
SDL_Log("destroying buffer ID %i", *id); SDL_Log("destroying buffer ID %i", *id);
glDeleteBuffers(1, 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<GLvoid*>(offset));
/* Debug */
std::ostringstream pointer_message;
pointer_message << "After defining attribute pointer for <Attributes (" << attributes.dimensions() << "D, id: " <<
attributes.index() << ", size:" << attributes.size() << ")>";
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 << "<Vertex Buffer Object (id: " << vbo.id() << ")>";
return out;
}

View File

@ -16,6 +16,8 @@
#include <algorithm> #include <algorithm>
#include <thread> #include <thread>
#include <memory> #include <memory>
#include <stdexcept>
#include <functional>
#include <curl/curl.h> #include <curl/curl.h>
#include "SDL.h" #include "SDL.h"
#include "SDL_image.h" #include "SDL_image.h"
@ -62,32 +64,45 @@ class Buffer : public GLObject
private: private:
GLenum buffer_target, buffer_usage; GLenum buffer_target = GL_INVALID_ENUM;
std::uint32_t buffer_add_use_count = 0, buffer_calculated_size = 0;
protected:
GLenum target() const;
public: public:
Buffer(); Buffer();
Buffer(GLenum, GLenum); Buffer(GLenum);
void generate();
void target(GLenum); void target(GLenum);
GLenum target() const; void generate();
void bind() const; void bind() const;
void allocate(GLsizeiptr); void bind(GLenum);
void allocate(GLenum, GLenum, GLsizeiptr);
template<typename T>
sb::Attributes add(VAO& vao, std::vector<T> vertex_attributes)
{
vao.increment();
// glVertexAttribPointer(vao.counted(),
}
}; };
void buffer_deleter(GLuint*); 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 class Pudding : public Game
{ {
@ -134,7 +149,7 @@ private:
flat_time_uniform_location, scroll_uniform_location; flat_time_uniform_location, scroll_uniform_location;
glm::mat4 projection, model = glm::mat4(1.0f), mvp; glm::mat4 projection, model = glm::mat4(1.0f), mvp;
std::map<std::string, sb::Attributes> rectangle_attributes, pudding_attributes = { std::map<std::string, sb::Attributes> rectangle_attributes, pudding_attributes = {
{"vertices", sb::Attributes()}, {"position", sb::Attributes()},
{"uv", sb::Attributes()}, {"uv", sb::Attributes()},
{"color", sb::Attributes()} {"color", sb::Attributes()}
}; };
@ -144,7 +159,7 @@ private:
Texture capture_texture_front_buffer, capture_texture_back_buffer; Texture capture_texture_front_buffer, capture_texture_back_buffer;
Texture& capture_texture = capture_texture_front_buffer; Texture& capture_texture = capture_texture_front_buffer;
VAO vao; 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 set_pudding_model(float, float, int, int = 1, float = -1, float = 1, float = 0.3f);
void load_gl_context(); 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 #endif