159 lines
5.2 KiB
C++
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;
|
|
}
|