/* +------------------------------------------------------+ ____/ \____ /| - Open source game framework licensed to freely use, | \ / / | copy, modify and sell without restriction | +--\ ^__^ /--+ | | | ~/ \~ | | - created for | | ~~~~~~~~~~~~ | +------------------------------------------------------+ | 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(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(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 << ""; return out; }