/* This file is part of the Pangolin Project. * http://github.com/stevenlovegrove/Pangolin * * Copyright (c) 2011 Steven Lovegrove * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #include #include #include #include #include #include namespace pangolin { //////////////////////////////////////////////// // Implementation of gl.h //////////////////////////////////////////////// #ifndef HAVE_GLES const int MAX_ATTACHMENTS = 8; const static GLuint attachment_buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT, GL_COLOR_ATTACHMENT4_EXT, GL_COLOR_ATTACHMENT5_EXT, GL_COLOR_ATTACHMENT6_EXT, GL_COLOR_ATTACHMENT7_EXT }; #else // HAVE_GLES const int MAX_ATTACHMENTS = 1; const static GLuint attachment_buffers[] = { GL_COLOR_ATTACHMENT0_EXT }; #endif // HAVE_GLES const static size_t datatype_bytes[] = { 1, // #define GL_BYTE 0x1400 1, // #define GL_UNSIGNED_BYTE 0x1401 2, // #define GL_SHORT 0x1402 2, // #define GL_UNSIGNED_SHORT 0x1403 4, // #define GL_INT 0x1404 4, // #define GL_UNSIGNED_INT 0x1405 4, // #define GL_FLOAT 0x1406 2, // #define GL_2_BYTES 0x1407 3, // #define GL_3_BYTES 0x1408 4, // #define GL_4_BYTES 0x1409 8 // #define GL_DOUBLE 0x140A }; const static size_t format_channels[] = { 1, // #define GL_RED 0x1903 1, // #define GL_GREEN 0x1904 1, // #define GL_BLUE 0x1905 1, // #define GL_ALPHA 0x1906 3, // #define GL_RGB 0x1907 4, // #define GL_RGBA 0x1908 1, // #define GL_LUMINANCE 0x1909 2 // #define GL_LUMINANCE_ALPHA 0x190A }; inline size_t GlDataTypeBytes(GLenum type) { return datatype_bytes[type - GL_BYTE]; } inline size_t GlFormatChannels(GLenum data_layout) { if (data_layout == GL_BGR) return 3; if (data_layout == GL_BGRA) return 4; return format_channels[data_layout - GL_RED]; } //template //struct GlDataTypeTrait {}; //template<> struct GlDataTypeTrait{ static const GLenum type = GL_FLOAT; }; //template<> struct GlDataTypeTrait{ static const GLenum type = GL_INT; }; //template<> struct GlDataTypeTrait{ static const GLenum type = GL_UNSIGNED_BYTE; }; inline GlTexture::GlTexture() : internal_format(0), tid(0), width(0), height(0) { // Not a texture constructor } inline GlTexture::GlTexture(GLint width, GLint height, GLint internal_format, bool sampling_linear, int border, GLenum glformat, GLenum gltype, GLvoid* data ) : internal_format(0), tid(0) { Reinitialise(width,height,internal_format,sampling_linear,border,glformat,gltype,data); } inline GlTexture::GlTexture(const TypedImage& img, bool sampling_linear) { this->Load(img, sampling_linear); } inline GlTexture::GlTexture(GlTexture&& tex) { *this = std::move(tex); } inline GlTexture& GlTexture::operator=(GlTexture&& tex) { if (&tex != this) { internal_format = tex.internal_format; tid = tex.tid; width = tex.width; height = tex.height; tex.internal_format = 0; tex.tid = 0; } return *this; } inline bool GlTexture::IsValid() const { return tid != 0; } inline void GlTexture::Delete() { // We have no GL context whilst exiting. if(internal_format!=0 && !pangolin::ShouldQuit() ) { glDeleteTextures(1,&tid); internal_format = 0; tid = 0; width = 0; height = 0; } } inline GlTexture::~GlTexture() { // We have no GL context whilst exiting. if(internal_format!=0 && !pangolin::ShouldQuit() ) { glDeleteTextures(1,&tid); } } inline void GlTexture::Bind() const { glBindTexture(GL_TEXTURE_2D, tid); } inline void GlTexture::Unbind() const { glBindTexture(GL_TEXTURE_2D, 0); } inline void GlTexture::Reinitialise(GLsizei w, GLsizei h, GLint int_format, bool sampling_linear, int border, GLenum glformat, GLenum gltype, GLvoid* data ) { if(tid!=0) { glDeleteTextures(1,&tid); } internal_format = int_format; width = w; height = h; glGenTextures(1,&tid); Bind(); // GL_LUMINANCE and GL_FLOAT don't seem to actually affect buffer, but some values are required // for call to succeed. glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, border, glformat, gltype, data); if(sampling_linear) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); }else{ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); CheckGlDieOnError(); } inline void GlTexture::Upload( const void* data, GLenum data_format, GLenum data_type ) { Bind(); glTexSubImage2D(GL_TEXTURE_2D,0,0,0,width,height,data_format,data_type,data); CheckGlDieOnError(); } inline void GlTexture::Upload( const void* data, GLsizei tex_x_offset, GLsizei tex_y_offset, GLsizei data_w, GLsizei data_h, GLenum data_format, GLenum data_type ) { Bind(); glTexSubImage2D(GL_TEXTURE_2D,0,tex_x_offset,tex_y_offset,data_w,data_h,data_format,data_type,data); CheckGlDieOnError(); } inline void GlTexture::Load(const TypedImage& image, bool sampling_linear) { GlPixFormat fmt(image.fmt); Reinitialise((GLint)image.w, (GLint)image.h, GL_RGBA32F, sampling_linear, 0, fmt.glformat, fmt.gltype, image.ptr ); } inline void GlTexture::LoadFromFile(const std::string& filename, bool sampling_linear) { TypedImage image = LoadImage(filename); Load(image, sampling_linear); } #ifndef HAVE_GLES inline void GlTexture::Download(void* image, GLenum data_layout, GLenum data_type) const { Bind(); glGetTexImage(GL_TEXTURE_2D, 0, data_layout, data_type, image); Unbind(); } inline void GlTexture::Download(TypedImage& image) const { switch (internal_format) { case GL_LUMINANCE8: image.Reinitialise(width, height, PixelFormatFromString("GRAY8") ); Download(image.ptr, GL_LUMINANCE, GL_UNSIGNED_BYTE); break; case GL_LUMINANCE16: image.Reinitialise(width, height, PixelFormatFromString("GRAY16LE") ); Download(image.ptr, GL_LUMINANCE, GL_UNSIGNED_SHORT); break; case GL_RGB8: image.Reinitialise(width, height, PixelFormatFromString("RGB24")); Download(image.ptr, GL_RGB, GL_UNSIGNED_BYTE); break; case GL_RGBA8: image.Reinitialise(width, height, PixelFormatFromString("RGBA32")); Download(image.ptr, GL_RGBA, GL_UNSIGNED_BYTE); break; case GL_RGB16: image.Reinitialise(width, height, PixelFormatFromString("RGB48")); Download(image.ptr, GL_RGB, GL_UNSIGNED_SHORT); break; case GL_RGBA16: image.Reinitialise(width, height, PixelFormatFromString("RGBA64")); Download(image.ptr, GL_RGBA, GL_UNSIGNED_SHORT); break; case GL_LUMINANCE: case GL_LUMINANCE32F_ARB: image.Reinitialise(width, height, PixelFormatFromString("GRAY32F")); Download(image.ptr, GL_LUMINANCE, GL_FLOAT); break; case GL_RGB: case GL_RGB32F: image.Reinitialise(width, height, PixelFormatFromString("RGB96F")); Download(image.ptr, GL_RGB, GL_FLOAT); break; case GL_RGBA: case GL_RGBA32F: image.Reinitialise(width, height, PixelFormatFromString("RGBA128F")); Download(image.ptr, GL_RGBA, GL_FLOAT); break; default: throw std::runtime_error( "GlTexture::Download - Unknown internal format (" + pangolin::Convert::Do(internal_format) + ")" ); } } inline void GlTexture::CopyFrom(const GlTexture& tex) { if(!tid || width != tex.width || height != tex.height || internal_format != tex.internal_format) { Reinitialise(tex.width, tex.height, tex.internal_format, true); } glCopyImageSubData(tex.tid, GL_TEXTURE_2D, 0, 0, 0, 0, tid, GL_TEXTURE_2D, 0, 0, 0, 0, width, height, 1); CheckGlDieOnError(); } inline void GlTexture::Save(const std::string& filename, bool top_line_first) { TypedImage image; Download(image); pangolin::SaveImage(image, filename, top_line_first); } #endif // HAVE_GLES inline void GlTexture::SetLinear() { Bind(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); Unbind(); } inline void GlTexture::SetNearestNeighbour() { Bind(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); Unbind(); } inline void GlTexture::RenderToViewport(const bool flip) const { if(flip) { RenderToViewportFlipY(); }else{ RenderToViewport(); } } inline void GlTexture::RenderToViewport() const { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); GLfloat sq_vert[] = { -1,-1, 1,-1, 1, 1, -1, 1 }; glVertexPointer(2, GL_FLOAT, 0, sq_vert); glEnableClientState(GL_VERTEX_ARRAY); GLfloat sq_tex[] = { 0,0, 1,0, 1,1, 0,1 }; glTexCoordPointer(2, GL_FLOAT, 0, sq_tex); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_TEXTURE_2D); Bind(); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); } inline void GlTexture::RenderToViewport(Viewport tex_vp, bool flipx, bool flipy) const { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); GLfloat sq_vert[] = { -1,-1, 1,-1, 1, 1, -1, 1 }; glVertexPointer(2, GL_FLOAT, 0, sq_vert); glEnableClientState(GL_VERTEX_ARRAY); GLfloat l = tex_vp.l / (float)(width); GLfloat b = tex_vp.b / (float)(height); GLfloat r = (tex_vp.l+tex_vp.w) / (float)(width); GLfloat t = (tex_vp.b+tex_vp.h) / (float)(height); if(flipx) std::swap(l,r); if(flipy) std::swap(b,t); GLfloat sq_tex[] = { l,b, r,b, r,t, l,t }; glTexCoordPointer(2, GL_FLOAT, 0, sq_tex); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_TEXTURE_2D); Bind(); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); } inline void GlTexture::RenderToViewportFlipY() const { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); GLfloat sq_vert[] = { -1,-1, 1,-1, 1, 1, -1, 1 }; glVertexPointer(2, GL_FLOAT, 0, sq_vert); glEnableClientState(GL_VERTEX_ARRAY); GLfloat sq_tex[] = { 0,1, 1,1, 1,0, 0,0 }; glTexCoordPointer(2, GL_FLOAT, 0, sq_tex); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_TEXTURE_2D); Bind(); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); } inline void GlTexture::RenderToViewportFlipXFlipY() const { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); GLfloat sq_vert[] = { 1,1, -1,1, -1,-1, 1,-1 }; glVertexPointer(2, GL_FLOAT, 0, sq_vert); glEnableClientState(GL_VERTEX_ARRAY); GLfloat sq_tex[] = { 0,0, 1,0, 1,1, 0,1 }; glTexCoordPointer(2, GL_FLOAT, 0, sq_tex); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_TEXTURE_2D); Bind(); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); } //////////////////////////////////////////////////////////////////////////// inline GlRenderBuffer::GlRenderBuffer() : width(0), height(0), rbid(0) { } inline GlRenderBuffer::GlRenderBuffer(GLint width, GLint height, GLint internal_format ) : width(0), height(0), rbid(0) { Reinitialise(width,height,internal_format); } #ifndef HAVE_GLES inline void GlRenderBuffer::Reinitialise(GLint width, GLint height, GLint internal_format) { if( this->width != 0 ) { glDeleteRenderbuffersEXT(1, &rbid); } this->width = width; this->height = height; glGenRenderbuffersEXT(1, &rbid); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbid); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internal_format, width, height); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); } inline GlRenderBuffer::~GlRenderBuffer() { // We have no GL context whilst exiting. if( width!=0 && !pangolin::ShouldQuit() ) { glDeleteRenderbuffersEXT(1, &rbid); } } #else inline void GlRenderBuffer::Reinitialise(GLint width, GLint height, GLint internal_format) { if( width!=0 ) { glDeleteTextures(1, &rbid); } // Use a texture instead... glGenTextures(1, &rbid); glBindTexture(GL_TEXTURE_2D, rbid); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, internal_format, GL_UNSIGNED_SHORT, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } inline GlRenderBuffer::~GlRenderBuffer() { // We have no GL context whilst exiting. if( width!=0 && !pangolin::ShouldQuit() ) { glDeleteTextures(1, &rbid); } } #endif // HAVE_GLES inline GlRenderBuffer::GlRenderBuffer(GlRenderBuffer&& tex) : width(tex.width), height(tex.height), rbid(tex.rbid) { tex.rbid = tex.width = tex.height = 0; } //////////////////////////////////////////////////////////////////////////// inline GlFramebuffer::GlFramebuffer() : fbid(0), attachments(0) { } inline GlFramebuffer::~GlFramebuffer() { if(fbid) { glDeleteFramebuffersEXT(1, &fbid); } } inline GlFramebuffer::GlFramebuffer(GlTexture& colour, GlRenderBuffer& depth) : attachments(0) { glGenFramebuffersEXT(1, &fbid); AttachColour(colour); AttachDepth(depth); CheckGlDieOnError(); } inline GlFramebuffer::GlFramebuffer(GlTexture& colour0, GlTexture& colour1, GlRenderBuffer& depth) : attachments(0) { glGenFramebuffersEXT(1, &fbid); AttachColour(colour0); AttachColour(colour1); AttachDepth(depth); CheckGlDieOnError(); } inline GlFramebuffer::GlFramebuffer(GlTexture& colour0, GlTexture& colour1, GlTexture& colour2, GlRenderBuffer& depth) : attachments(0) { glGenFramebuffersEXT(1, &fbid); AttachColour(colour0); AttachColour(colour1); AttachColour(colour2); AttachDepth(depth); CheckGlDieOnError(); } inline GlFramebuffer::GlFramebuffer(GlTexture& colour0, GlTexture& colour1, GlTexture& colour2, GlTexture& colour3, GlRenderBuffer& depth) : attachments(0) { glGenFramebuffersEXT(1, &fbid); AttachColour(colour0); AttachColour(colour1); AttachColour(colour2); AttachColour(colour3); AttachDepth(depth); CheckGlDieOnError(); } inline void GlFramebuffer::Bind() const { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbid); #ifndef HAVE_GLES glDrawBuffers( attachments, attachment_buffers ); #endif } inline void GlFramebuffer::Reinitialise() { if(fbid) { glDeleteFramebuffersEXT(1, &fbid); } glGenFramebuffersEXT(1, &fbid); } inline void GlFramebuffer::Unbind() const { #ifndef HAVE_GLES glDrawBuffers( 1, attachment_buffers ); #endif glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } inline GLenum GlFramebuffer::AttachColour(GlTexture& tex ) { if(!fbid) Reinitialise(); const GLenum color_attachment = GL_COLOR_ATTACHMENT0_EXT + attachments; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbid); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, color_attachment, GL_TEXTURE_2D, tex.tid, 0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); attachments++; CheckGlDieOnError(); return color_attachment; } inline void GlFramebuffer::AttachDepth(GlRenderBuffer& rb ) { if(!fbid) Reinitialise(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbid); #if !defined(HAVE_GLES) glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rb.rbid); #elif defined(HAVE_GLES_2) glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, rb.rbid, 0); #else throw std::exception(); #endif glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); CheckGlDieOnError(); } //////////////////////////////////////////////////////////////////////////// inline GlBufferData::GlBufferData() : bo(0) { } inline GlBufferData::GlBufferData(GlBufferType buffer_type, GLuint size_bytes, GLenum gluse, const unsigned char* data ) : bo(0) { Reinitialise(buffer_type, size_bytes, gluse, data ); } //! Move Constructor inline GlBufferData::GlBufferData(GlBufferData&& tex) : bo(0) { *this = std::move(tex); } inline GlBufferData& GlBufferData::operator=(GlBufferData&& tex) { Free(); this->bo = tex.bo; this->buffer_type = tex.buffer_type; this->gluse = tex.gluse; this->size_bytes = tex.size_bytes; tex.bo = 0; return *this; } inline GlBufferData::~GlBufferData() { Free(); } inline void GlBufferData::Free() { if(bo!=0) { glDeleteBuffers(1, &bo); } } inline bool GlBufferData::IsValid() const { return bo != 0; } inline size_t GlBufferData::SizeBytes() const { return size_bytes; } inline void GlBufferData::Reinitialise(GlBufferType buffer_type, GLuint size_bytes, GLenum gluse, const unsigned char* data ) { if(!bo) { glGenBuffers(1, &bo); } this->buffer_type = buffer_type; this->gluse = gluse; this->size_bytes = size_bytes; Bind(); glBufferData(buffer_type, size_bytes, data, gluse); Unbind(); } inline void GlBufferData::Bind() const { glBindBuffer(buffer_type, bo); } inline void GlBufferData::Unbind() const { glBindBuffer(buffer_type, 0); } inline void GlBufferData::Upload(const GLvoid* data, GLsizeiptr size_bytes, GLintptr offset) { if(offset + size_bytes > this->size_bytes) { throw std::runtime_error("GlBufferData: Trying to upload past capacity."); } Bind(); glBufferSubData(buffer_type,offset,size_bytes,data); Unbind(); } inline void GlBufferData::Download(GLvoid* data, GLsizeiptr size_bytes, GLintptr offset) const { Bind(); glGetBufferSubData(buffer_type, offset, size_bytes, data); Unbind(); } //////////////////////////////////////////////////////////////////////////// inline GlBuffer::GlBuffer() : GlBufferData(), num_elements(0) { } inline GlBuffer::GlBuffer(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, GLenum gluse ) : GlBufferData(buffer_type, num_elements * count_per_element * GlDataTypeBytes(datatype), gluse), datatype(datatype), num_elements(num_elements), count_per_element(count_per_element) { } inline GlBuffer::GlBuffer(GlBuffer&& o) : GlBufferData() { *this = std::move(o); } inline GlBuffer& GlBuffer::operator=(GlBuffer&& o) { datatype = o.datatype; num_elements = o.num_elements; count_per_element = o.count_per_element; GlBufferData::operator =(std::move(o)); return *this; } inline void GlBuffer::Reinitialise(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, GLenum gluse, const unsigned char* data ) { this->datatype = datatype; this->num_elements = num_elements; this->count_per_element = count_per_element; const GLuint size_bytes = num_elements * count_per_element * GlDataTypeBytes(datatype); GlBufferData::Reinitialise(buffer_type, size_bytes, gluse, data); } inline void GlBuffer::Reinitialise(GlBuffer const& other ) { Reinitialise(other.buffer_type, other.num_elements, other.datatype, other.count_per_element, other.gluse); } inline void GlBuffer::Resize(GLuint new_num_elements) { if(bo!=0) { #ifndef HAVE_GLES // Backup current data, reinit memory, restore old data const size_t backup_elements = std::min(new_num_elements,num_elements); const size_t backup_size_bytes = backup_elements*GlDataTypeBytes(datatype)*count_per_element; unsigned char* backup = new unsigned char[backup_size_bytes]; Bind(); glGetBufferSubData(buffer_type, 0, backup_size_bytes, backup); glBufferData(buffer_type, new_num_elements*GlDataTypeBytes(datatype)*count_per_element, 0, gluse); glBufferSubData(buffer_type, 0, backup_size_bytes, backup); Unbind(); delete[] backup; #else throw std::exception(); #endif }else{ Reinitialise(buffer_type, new_num_elements, datatype, count_per_element, gluse); } num_elements = new_num_elements; } //////////////////////////////////////////////////////////////////////////// inline GlSizeableBuffer::GlSizeableBuffer(GlBufferType buffer_type, GLuint initial_num_elements, GLenum datatype, GLuint count_per_element, GLenum gluse ) : GlBuffer(buffer_type, initial_num_elements, datatype, count_per_element, gluse), m_num_verts(0) { } inline void GlSizeableBuffer::Clear() { m_num_verts = 0; } #ifdef USE_EIGEN template inline void GlSizeableBuffer::Add(const Eigen::DenseBase& vec) { typedef typename Eigen::DenseBase::Scalar Scalar; assert(vec.rows()==GlBuffer::count_per_element); CheckResize(m_num_verts + 1); // TODO: taking address of first element is really dodgey. Need to work out // when this is okay! Upload(&vec(0,0), sizeof(Scalar)*vec.rows()*vec.cols(), sizeof(Scalar)*vec.rows()*m_num_verts); m_num_verts += vec.cols(); } template inline void GlSizeableBuffer::Update(const Eigen::DenseBase& vec, size_t position ) { typedef typename Eigen::DenseBase::Scalar Scalar; assert(vec.rows()==GlBuffer::count_per_element); CheckResize(position + vec.cols() ); // TODO: taking address of first element is really dodgey. Need to work out // when this is okay! Upload(&vec(0,0), sizeof(Scalar)*vec.rows()*vec.cols(), sizeof(Scalar)*vec.rows()*position ); m_num_verts = std::max(position+vec.cols(), m_num_verts); } #endif inline size_t GlSizeableBuffer::start() const { return 0; } inline size_t GlSizeableBuffer::size() const { return m_num_verts; } inline void GlSizeableBuffer::CheckResize(size_t num_verts) { if( num_verts > GlBuffer::num_elements) { const size_t new_size = NextSize(num_verts); GlBuffer::Resize((GLuint)new_size); } } inline size_t GlSizeableBuffer::NextSize(size_t min_size) const { size_t new_size = std::max(GlBuffer::num_elements, 1u); while(new_size < min_size) { new_size *= 2; } return new_size; } }