spacebox/src/GLObject.cpp

159 lines
5.2 KiB
C++

/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
#include "GLObject.hpp"
using namespace sb;
/* The deleter function is used for freeing the memory allocated to the object (for example, glDeleteTextures,
* or a custom function that does something in addition to calling the appropriate GL deleter function). */
GLObject::GLObject(deleter_function deleter) : deleter(deleter) {}
/*!
* The supplied `sb::GLObject::generator_function` will be called to generate a new ID. This can be used, for example,
* by a member function override in a derived class to specify which OpenGL generate function to use, like `glGenTextures`
* or `glGenBuffers`.
*
* Although OpenGL generation functions support generating multiple object IDs, generation through this function is limited
* to a single ID. For generating and managing multiple IDs with a single class, this method and others will have to be
* overwritten.
*
* Because the ID is being reassigned to a new `std::shared_ptr`, the `sb::GLObject::deleter_function` passed to the
* constructor will be automatically called, meaning the currently allocated GL object memory will be freed if this object
* had previously generated an ID. To keep the object in memory, create a new `sb::GLObject` instead of calling
* `sb::GLObject::generate` again.
*
* @param generator A function that will be called to generate an OpenGL ID for this object
*/
void GLObject::generate(generator_function generator)
{
if (SDL_GL_GetCurrentContext() != nullptr)
{
GLuint id;
generator(1, &id);
this->id(id);
std::ostringstream message;
message << "Generated ID " << this->id() << " for GL object";
sb::Log::log(message, sb::Log::VERBOSE);
}
else
{
throw std::runtime_error("Cannot generate ID for GL object before GL context is created");
}
}
/* Set the shared pointer to point to a new GLuint with specified ID value */
void GLObject::id(GLuint id)
{
/* The deleter will be called when the object and all of its copies have gone out of scope */
object_id = std::shared_ptr<GLuint>(new GLuint, deleter);
*object_id = id;
}
/* Return the GL ID that was set for this object */
GLuint GLObject::id() const
{
if (generated())
{
return *object_id;
}
else
{
throw std::runtime_error("Cannot get ID for GL object that has no ID generated yet");
}
}
/* Returns true if an ID has been generated */
bool GLObject::generated() const
{
return static_cast<bool>(object_id);
};
VAO::VAO() : GLObject(vao_deleter) {}
/* Bind this VAO to the current GL context */
void VAO::bind() const
{
glBindVertexArray(id());
}
/* Forward the GL VAO generate function to the base class */
void VAO::generate()
{
GLObject::generate(glGenVertexArrays);
}
/* This function gets passed to the abstract base class for deleting the VAO data when the ID
* pointer goes out of scope (when all instances of this VAO and its copies are out of scope) */
void sb::vao_deleter(GLuint* id)
{
/* not sure why SDL_Log works here on program exit but SDL_LogDebug and SDL_LogInfo don't */
SDL_Log("destroying VAO ID %i", *id);
glDeleteVertexArrays(1, id);
delete id;
}
Buffer::Buffer() : Buffer(GL_INVALID_ENUM) {}
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 target for this buffer. */
void Buffer::target(GLenum target)
{
buffer_target = target;
}
/* Return the GL enum for target */
GLenum Buffer::target() const
{
return buffer_target;
}
/* 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 sb::buffer_deleter(GLuint* id)
{
/* not sure why SDL_Log works here on program exit but SDL_LogDebug and SDL_LogInfo don't */
SDL_Log("destroying buffer ID %i", *id);
glDeleteBuffers(1, id);
delete id;
}
/* Overload the stream operator to support GLObject. Add a string representation of the object that
* displays its ID to the output stream. */
std::ostream& sb::operator<<(std::ostream& out, const GLObject& gl_object)
{
out << "<GL Object (id: " << gl_object.id() << ")>";
return out;
}