1 /** 2 * Copyright (c) 2006-2012 LOVE Development Team 3 * 4 * This software is provided 'as-is', without any express or implied 5 * warranty. In no event will the authors be held liable for any damages 6 * arising from the use of this software. 7 * 8 * Permission is granted to anyone to use this software for any purpose, 9 * including commercial applications, and to alter it and redistribute it 10 * freely, subject to the following restrictions: 11 * 12 * 1. The origin of this software must not be misrepresented; you must not 13 * claim that you wrote the original software. If you use this software 14 * in a product, an acknowledgment in the product documentation would be 15 * appreciated but is not required. 16 * 2. Altered source versions must be plainly marked as such, and must not be 17 * misrepresented as being the original software. 18 * 3. This notice may not be removed or altered from any source distribution. 19 **/ 20 21 #define GL_GLEXT_PROTOTYPES 22 #include "VertexBuffer.h" 23 24 #include "common/Exception.h" 25 #include <common/config.h> 26 27 #include <cstdlib> 28 #include <cstring> 29 30 namespace love 31 { 32 namespace graphics 33 { 34 namespace opengl 35 { 36 // VertexBuffer 37 Create(size_t size,GLenum target,GLenum usage)38 VertexBuffer *VertexBuffer::Create(size_t size, GLenum target, GLenum usage) 39 { 40 try 41 { 42 // Try to create a VBO. 43 return new VBO(size, target, usage); 44 } 45 catch (const love::Exception &) 46 { 47 // VBO not supported ... create regular array. 48 return new VertexArray(size, target, usage); 49 } 50 } 51 VertexBuffer(size_t size,GLenum target,GLenum usage)52 VertexBuffer::VertexBuffer(size_t size, GLenum target, GLenum usage) 53 : size(size) 54 , target(target) 55 , usage(usage) 56 { 57 } 58 ~VertexBuffer()59 VertexBuffer::~VertexBuffer() 60 { 61 } 62 63 // VertexArray 64 VertexArray(size_t size,GLenum target,GLenum usage)65 VertexArray::VertexArray(size_t size, GLenum target, GLenum usage) 66 : VertexBuffer(size, target, usage) 67 , buf(new char[size]) 68 { 69 } 70 ~VertexArray()71 VertexArray::~VertexArray() 72 { 73 delete [] buf; 74 } 75 map()76 void *VertexArray::map() 77 { 78 return buf; 79 } 80 unmap()81 void VertexArray::unmap() 82 { 83 } 84 bind()85 void VertexArray::bind() 86 { 87 } 88 unbind()89 void VertexArray::unbind() 90 { 91 } 92 fill(size_t offset,size_t size,const void * data)93 void VertexArray::fill(size_t offset, size_t size, const void *data) 94 { 95 memcpy(buf + offset, data, size); 96 } 97 getPointer(size_t offset) const98 const void *VertexArray::getPointer(size_t offset) const 99 { 100 return buf + offset; 101 } 102 103 // VBO 104 VBO(size_t size,GLenum target,GLenum usage)105 VBO::VBO(size_t size, GLenum target, GLenum usage) 106 : VertexBuffer(size, target, usage) 107 , vbo(0) 108 , buffer_copy(0) 109 , mapped(0) 110 { 111 if (!(GLEE_ARB_vertex_buffer_object || GLEE_VERSION_1_5)) 112 throw love::Exception("Not supported"); 113 114 bool ok = load(false); 115 116 if (!ok) 117 throw love::Exception("Could not load VBO."); 118 } 119 ~VBO()120 VBO::~VBO() 121 { 122 if (vbo != 0) 123 unload(false); 124 } 125 map()126 void *VBO::map() 127 { 128 // mapping twice could result in memory leaks 129 if (mapped) 130 throw love::Exception("VBO is already mapped!"); 131 132 mapped = malloc(getSize()); 133 if (!mapped) 134 throw love::Exception("Out of memory (oh the humanity!)"); 135 glGetBufferSubDataARB(getTarget(), 0, getSize(), mapped); 136 137 return mapped; 138 } 139 unmap()140 void VBO::unmap() 141 { 142 glBufferSubDataARB(getTarget(), 0, getSize(), mapped); 143 free(mapped); 144 mapped = 0; 145 } 146 bind()147 void VBO::bind() 148 { 149 glBindBufferARB(getTarget(), vbo); 150 } 151 unbind()152 void VBO::unbind() 153 { 154 glBindBufferARB(getTarget(), 0); 155 } 156 fill(size_t offset,size_t size,const void * data)157 void VBO::fill(size_t offset, size_t size, const void *data) 158 { 159 if (mapped) 160 memcpy(static_cast<char*>(mapped) + offset, data, size); 161 else 162 glBufferSubDataARB(getTarget(), offset, size, data); 163 } 164 getPointer(size_t offset) const165 const void *VBO::getPointer(size_t offset) const 166 { 167 return reinterpret_cast<const void*>(offset); 168 } 169 loadVolatile()170 bool VBO::loadVolatile() 171 { 172 return load(true); 173 } 174 unloadVolatile()175 void VBO::unloadVolatile() 176 { 177 unload(true); 178 } 179 load(bool restore)180 bool VBO::load(bool restore) 181 { 182 glGenBuffersARB(1, &vbo); 183 184 VertexBuffer::Bind bind(*this); 185 186 // Copy the old buffer only if 'restore' was requested. 187 const GLvoid *src = restore ? buffer_copy : 0; 188 189 while (GL_NO_ERROR != glGetError()) 190 /* clear error messages */; 191 192 // Note that if 'src' is '0', no data will be copied. 193 glBufferDataARB(getTarget(), getSize(), src, getUsage()); 194 GLenum err = glGetError(); 195 196 // Clean up buffer_copy, if it exists. 197 delete[] buffer_copy; 198 buffer_copy = 0; 199 200 return (GL_NO_ERROR == err); 201 } 202 unload(bool save)203 void VBO::unload(bool save) 204 { 205 // Clean up buffer_copy, if it exists. 206 delete[] buffer_copy; 207 buffer_copy = 0; 208 209 // Save data before unloading. 210 if (save) 211 { 212 VertexBuffer::Bind bind(*this); 213 214 GLint size; 215 glGetBufferParameterivARB(getTarget(), GL_BUFFER_SIZE, &size); 216 217 const char *src = static_cast<char *>(map()); 218 219 if (src) 220 { 221 buffer_copy = new char[size]; 222 memcpy(buffer_copy, src, size); 223 unmap(); 224 } 225 } 226 227 glDeleteBuffers(1, &vbo); 228 vbo = 0; 229 } 230 231 } // opengl 232 } // graphics 233 } // love 234