From 704981dd0029da70b46af2ba4c2f83020c66dd19 Mon Sep 17 00:00:00 2001 From: fgenesis Date: Thu, 20 Jul 2023 22:30:56 +0200 Subject: [PATCH] initial support for static vertex buffers. TileRender uses that now. --- BBGE/CMakeLists.txt | 2 + BBGE/Core.cpp | 9 +- BBGE/Core.h | 6 +- BBGE/GLLoad.cpp | 28 +++++ BBGE/OpenGLStubs.h | 6 +- BBGE/RenderBase.h | 10 +- BBGE/Tile.cpp | 14 +-- BBGE/Tile.h | 5 +- BBGE/TileRender.cpp | 33 ++---- BBGE/TileRender.h | 2 - BBGE/Tileset.cpp | 32 +++--- BBGE/Tileset.h | 9 +- BBGE/VertexBuffer.cpp | 262 ++++++++++++++++++++++++++++++++++++++++++ BBGE/VertexBuffer.h | 91 +++++++++++++++ 14 files changed, 448 insertions(+), 61 deletions(-) create mode 100644 BBGE/VertexBuffer.cpp create mode 100644 BBGE/VertexBuffer.h diff --git a/BBGE/CMakeLists.txt b/BBGE/CMakeLists.txt index 2ceccac..ca4a9b1 100644 --- a/BBGE/CMakeLists.txt +++ b/BBGE/CMakeLists.txt @@ -116,6 +116,8 @@ set(BBGE_SRCS TileRender.h Tileset.cpp Tileset.h + VertexBuffer.cpp + VertexBuffer.h Vector.cpp Vector.h Window.cpp diff --git a/BBGE/Core.cpp b/BBGE/Core.cpp index 6502c26..5b1fe1f 100644 --- a/BBGE/Core.cpp +++ b/BBGE/Core.cpp @@ -145,7 +145,8 @@ void Core::setup_opengl() glEnable(GL_TEXTURE_2D); // Enable Texture Mapping glClearDepth(1.0); // Depth Buffer Setup glDisable(GL_CULL_FACE); - + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); glLoadIdentity(); setClearColor(clearColor); @@ -153,6 +154,8 @@ void Core::setup_opengl() frameBuffer.init(-1, -1, true); if(afterEffectManager) afterEffectManager->updateDevice(); + + defaultQuadVertexBuf.initQuadVertices(0, 0, 1, 1); } void Core::resizeWindow(int w, int h, int full, int bpp, int vsync, int display, int hz) @@ -276,7 +279,7 @@ static bool checkWritable(const std::string& path, bool warn, bool critical) Core::Core(const std::string &filesystem, const std::string& extraDataDir, int numRenderLayers, const std::string &appName, int particleSize, std::string userDataSubFolder) -: ActionMapper(), StateManager(), appName(appName) +: ActionMapper(), StateManager(), appName(appName), defaultQuadVertexBuf(GPUBUF_STATIC | GPUBUF_VERTEXBUF) { window = NULL; sound = NULL; @@ -1917,6 +1920,8 @@ void Core::shutdown() frameBuffer.unloadDevice(); debugLog("OK"); + defaultQuadVertexBuf.dropBuffer(); + debugLog("Shutdown Graphics Library..."); shutdownGraphicsLibrary(); debugLog("OK"); diff --git a/BBGE/Core.h b/BBGE/Core.h index e1e3ff3..ba8214c 100644 --- a/BBGE/Core.h +++ b/BBGE/Core.h @@ -29,7 +29,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "Localization.h" #include "Window.h" #include "TextureMgr.h" - +#include "VertexBuffer.h" #include "DarkLayer.h" #include "GameKeys.h" @@ -413,6 +413,8 @@ public: TextureMgr texmgr; + inline const DynamicGPUBuffer *getDefaultQuadVertexBuffer() const { return &defaultQuadVertexBuf; } + protected: CoreWindow *window; @@ -490,6 +492,8 @@ protected: virtual void updateActionButtons(); void clearActionButtons(); + DynamicGPUBuffer defaultQuadVertexBuf; + public: // inclusive! inline int getMaxActionStatusIndex() const { return int(actionStatus.size()) - 2; } diff --git a/BBGE/GLLoad.cpp b/BBGE/GLLoad.cpp index 9cb6a9f..efc942e 100644 --- a/BBGE/GLLoad.cpp +++ b/BBGE/GLLoad.cpp @@ -68,9 +68,19 @@ PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL; PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL; PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL; +// ARB_vertex_buffer_object +PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL; +PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL; +PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL; +PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB = NULL; +PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL; +PFNGLMAPBUFFERARBPROC glMapBufferARB = NULL; +PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL; + // extern unsigned g_dbg_numRenderCalls = 0; bool g_has_GL_GENERATE_MIPMAP = false; +bool g_has_GL_BUFFERS = false; #define GL_FUNC(ret,fn,params,call,rt) \ @@ -164,6 +174,15 @@ bool lookup_all_glsyms() glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC)SDL_GL_GetProcAddress("glUniform3ivARB"); glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC)SDL_GL_GetProcAddress("glUniform4ivARB"); + // VBOs + glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)SDL_GL_GetProcAddress("glGenBuffersARB"); + glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)SDL_GL_GetProcAddress("glDeleteBuffersARB"); + glBufferDataARB = (PFNGLBUFFERDATAARBPROC)SDL_GL_GetProcAddress("glBufferData"); + glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)SDL_GL_GetProcAddress("glBufferSubData"); + glBindBufferARB = (PFNGLBINDBUFFERARBPROC)SDL_GL_GetProcAddress("glBindBufferARB"); + glMapBufferARB = (PFNGLMAPBUFFERARBPROC)SDL_GL_GetProcAddress("glMapBufferARB"); + glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)SDL_GL_GetProcAddress("glUnmapBufferARB"); + return retval; } @@ -217,6 +236,15 @@ void unload_all_glsyms() glUniform2ivARB = NULL; glUniform3ivARB = NULL; glUniform4ivARB = NULL; + + glGenBuffersARB = NULL; + glDeleteBuffersARB = NULL; + glBufferDataARB = NULL; + glBufferSubDataARB = NULL; + glBindBufferARB = NULL; + glMapBufferARB = NULL; + glUnmapBufferARB = NULL; + } #endif // BBGE_BUILD_OPENGL_STATIC diff --git a/BBGE/OpenGLStubs.h b/BBGE/OpenGLStubs.h index 63c9b41..494f34f 100644 --- a/BBGE/OpenGLStubs.h +++ b/BBGE/OpenGLStubs.h @@ -26,14 +26,15 @@ GL_FUNC(void,glClear,(GLbitfield a),(a),) GL_FUNC(void,glClearColor,(GLclampf r,GLclampf g,GLclampf b,GLclampf a),(r,g,b,a),) GL_FUNC(void,glColor4f,(GLfloat r,GLfloat g,GLfloat b,GLfloat a),(r,g,b,a),) GL_FUNC(void,glColor4ub,(GLubyte r,GLubyte g,GLubyte b,GLubyte a),(r,g,b,a),) +GL_FUNC(void,glColorPointer,(GLint size,GLenum type,GLsizei stride,const GLvoid* pointer),(size,type,stride,pointer),); GL_FUNC(void,glCopyPixels,(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type),(x,y,width,height,type),) GL_FUNC(void,glCopyTexImage2D,(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border),(target, level, internalFormat, x, y, width, height, border),) GL_FUNC(void,glCopyTexSubImage2D,(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height),(target, level, xoffset, yoffset, x, y, width, height),) GL_FUNC(void,glDeleteTextures,(GLsizei n, const GLuint *textures),(n,textures),) GL_FUNC(void,glDisable,(GLenum cap),(cap),) GL_FUNC(void,glDisableClientState,(GLenum array),(array),) -//GL_FUNC(void,glDrawArrays,(GLenum mode, GLint first, GLsizei count),(mode,first,count),) -//GL_FUNC(void,glDrawElements,(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices),(mode,count,type,indices),) +GL_FUNC(void,glDrawArrays,(GLenum mode, GLint first, GLsizei count),(mode,first,count),) +GL_FUNC(void,glDrawElements,(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices),(mode,count,type,indices),) GL_FUNC(void,glEnable,(GLenum cap),(cap),) GL_FUNC(void,glEnableClientState,(GLenum array),(array),) GL_FUNC(void,glFinish,(void),(),) @@ -70,7 +71,6 @@ GL_FUNC(void,glEnd,(void),(),) GL_FUNC(void,glClearDepth,(GLclampd x),(x),) GL_FUNC(void,glColor3f,(GLfloat r,GLfloat g,GLfloat b),(r,g,b),) //GL_FUNC(void,glDeleteLists,(GLuint list, GLsizei range),(list,range),) -GL_FUNC(void,glDrawArrays,(GLenum mode, GLint first, GLsizei count), (mode,first,count),) //GL_FUNC(void,glDrawPixels,(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels),(width,height,format,type,pixels),) //GL_FUNC(GLuint,glGenLists,(GLsizei range),(range),return) //GL_FUNC(void,glNewList,(GLuint list, GLenum mode),(list,mode),) diff --git a/BBGE/RenderBase.h b/BBGE/RenderBase.h index e533c2e..f88dbec 100644 --- a/BBGE/RenderBase.h +++ b/BBGE/RenderBase.h @@ -39,7 +39,7 @@ extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB; extern PFNGLLINKPROGRAMARBPROC glLinkProgramARB; extern PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB; extern PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB; -extern PFNGLUNIFORM1FVARBPROC glUniform1fvARB ; +extern PFNGLUNIFORM1FVARBPROC glUniform1fvARB; extern PFNGLUNIFORM2FVARBPROC glUniform2fvARB; extern PFNGLUNIFORM3FVARBPROC glUniform3fvARB; extern PFNGLUNIFORM4FVARBPROC glUniform4fvARB; @@ -65,6 +65,12 @@ extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT; extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; - +extern PFNGLGENBUFFERSARBPROC glGenBuffersARB; +extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB; +extern PFNGLBUFFERDATAARBPROC glBufferDataARB; +extern PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB; +extern PFNGLBINDBUFFERARBPROC glBindBufferARB; +extern PFNGLMAPBUFFERARBPROC glMapBufferARB; +extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB; #endif diff --git a/BBGE/Tile.cpp b/BBGE/Tile.cpp index 24ad28f..9c5ee4b 100644 --- a/BBGE/Tile.cpp +++ b/BBGE/Tile.cpp @@ -531,6 +531,11 @@ bool TileData::isCoordinateInside(float cx, float cy, float minsize) const && cy >= y - hh && cy <= y + hh; } +TileRepeatData::TileRepeatData() + : vertexbuf(GPUBUF_STATIC | GPUBUF_VERTEXBUF) +{ +} + void TileRepeatData::refresh(const ElementTemplate& et, float scalex, float scaley) { float tw, th; @@ -555,14 +560,7 @@ void TileRepeatData::refresh(const ElementTemplate& et, float scalex, float scal this->tu2 = tu2; this->tv2 = tv2; - texcoords[0] = tu1; - texcoords[1] = 1.0f-tv1; - texcoords[2] = tu2; - texcoords[3] = 1.0f-tv1; - texcoords[4] = tu2; - texcoords[5] = 1.0f-tv2; - texcoords[6] = tu1; - texcoords[7] = 1.0f-tv2; + vertexbuf.initQuadVertices(tu1, tv1, tu2, tv2); } TileRepeatData* TileData::setRepeatOn(float texscalex, float texscaley, float offx, float offy) diff --git a/BBGE/Tile.h b/BBGE/Tile.h index f30b990..5a201d3 100644 --- a/BBGE/Tile.h +++ b/BBGE/Tile.h @@ -4,6 +4,7 @@ #include #include "Vector.h" #include "EngineEnums.h" +#include "VertexBuffer.h" // A Tile is a very stripped down RenderObject that bypasses the default // rendering pipeline for efficiency reasons. @@ -132,8 +133,10 @@ private: struct TileRepeatData { + TileRepeatData(); + // written via refresh() - float texcoords[8]; + DynamicGPUBuffer vertexbuf; float tu1, tv1, tu2, tv2; // set by user diff --git a/BBGE/TileRender.cpp b/BBGE/TileRender.cpp index f84572e..81cb6dc 100644 --- a/BBGE/TileRender.cpp +++ b/BBGE/TileRender.cpp @@ -41,24 +41,11 @@ static inline const Vector& getTagColor(int tag) } -static const float s_quadVerts[] = -{ - -0.5f, +0.5f, - +0.5f, +0.5f, - +0.5f, -0.5f, - -0.5f, -0.5f, -}; - void TileRender::onRender(const RenderState& rs) const { if(storage.tiles.empty()) return; - glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, s_quadVerts); - RenderState rx(rs); // prepare. get parallax scroll factors @@ -78,7 +65,7 @@ void TileRender::onRender(const RenderState& rs) const const bool renderExtras = renderBorders || RenderObject::renderCollisionShape; const TileEffectData *prevEff = ((TileEffectData*)NULL)+1; // initial value is different from anything else const RenderGrid *grid = NULL; - const float *lastTexcoordBuf = NULL; + const DynamicGPUBuffer *lastVertexBuf = NULL; for(size_t i = 0; i < storage.tiles.size(); ++i) { @@ -181,16 +168,16 @@ void TileRender::onRender(const RenderState& rs) const if(!grid) { - const float *tcbuf = (tile.flags & TILEFLAG_REPEAT) - ? &tile.rep->texcoords[0] - : tile.et->texcoordQuadPtr; - assert(tcbuf); - if(lastTexcoordBuf != tcbuf) + const DynamicGPUBuffer *vb = !(tile.flags & TILEFLAG_REPEAT) + ? tile.et->vertexbuf + : &tile.rep->vertexbuf; + assert(vb); + if(vb != lastVertexBuf) { - lastTexcoordBuf = tcbuf; - glTexCoordPointer(2, GL_FLOAT, 0, tcbuf); + lastVertexBuf = vb; + vb->apply(); } - glDrawArrays(GL_QUADS, 0, 4); + vb->DrawArrays(GL_TRIANGLE_FAN, 4); } else { @@ -248,7 +235,7 @@ void TileRender::onRender(const RenderState& rs) const glPopMatrix(); } - glPopClientAttrib(); + glBindBufferARB(GL_ARRAY_BUFFER, 0); RenderObject::lastTextureApplied = lastTexId; RenderObject::lastTextureRepeat = !!lastTexRepeat; diff --git a/BBGE/TileRender.h b/BBGE/TileRender.h index 10981eb..e37af5e 100644 --- a/BBGE/TileRender.h +++ b/BBGE/TileRender.h @@ -18,8 +18,6 @@ public: virtual void onUpdate(float dt) OVERRIDE; bool renderBorders; - -private: }; diff --git a/BBGE/Tileset.cpp b/BBGE/Tileset.cpp index aee51fa..e2dc4ee 100644 --- a/BBGE/Tileset.cpp +++ b/BBGE/Tileset.cpp @@ -169,13 +169,12 @@ const ElementTemplate* Tileset::getAdjacent(size_t idx, int direction, bool wrap return et; } -static const float s_defaultTexcoordBuf[] = + +ElementTemplate::~ElementTemplate() { - 0, 1, - 1, 1, - 1, 0, - 0, 0 -}; + if(ownsVertexbuf) + delete const_cast(vertexbuf); +} void ElementTemplate::finalize() { @@ -197,18 +196,19 @@ void ElementTemplate::finalize() } if(tu1 == 0 && tv1 == 0 && tu2 == 1 && tv2 == 1) - texcoordQuadPtr = s_defaultTexcoordBuf; + { + // this avoids buffer switches later on + vertexbuf = core->getDefaultQuadVertexBuffer(); + ownsVertexbuf = false; + } else { - texcoordQuadPtr = &texcoordQuadBuffer[0]; - texcoordQuadBuffer[0] = tu1; - texcoordQuadBuffer[1] = 1.0f-tv1; - texcoordQuadBuffer[2] = tu2; - texcoordQuadBuffer[3] = 1.0f-tv1; - texcoordQuadBuffer[4] = tu2; - texcoordQuadBuffer[5] = 1.0f-tv2; - texcoordQuadBuffer[6] = tu1; - texcoordQuadBuffer[7] = 1.0f-tv2; + DynamicGPUBuffer *vb = ownsVertexbuf + ? const_cast(vertexbuf) + : new DynamicGPUBuffer(GPUBUF_STATIC | GPUBUF_VERTEXBUF); + vb->initQuadVertices(tu1, tv1, tu2, tv2); + vertexbuf = vb; + ownsVertexbuf = true; } } diff --git a/BBGE/Tileset.h b/BBGE/Tileset.h index ec919b3..70aad0f 100644 --- a/BBGE/Tileset.h +++ b/BBGE/Tileset.h @@ -4,11 +4,13 @@ #include "Vector.h" #include #include "Texture.h" +#include "VertexBuffer.h" class ElementTemplate { public: - ElementTemplate() { w=0; h=0; idx=-1; tu1=tv1=0; tu2=tv2=1; texcoordQuadPtr=NULL; } + ElementTemplate() { w=0; h=0; idx=-1; tu1=tv1=0; tu2=tv2=1; vertexbuf = NULL; ownsVertexbuf = false; } + ~ElementTemplate(); inline bool operator<(const ElementTemplate& o) const { return idx < o.idx; } void finalize(); // call after settings params @@ -16,8 +18,8 @@ public: // lazily assigned when tex is loaded CountedPtr tex; // NULL if failed to load or not yet loaded float w,h; // custom size if used, otherwise texture size - const float *texcoordQuadPtr; - float texcoordQuadBuffer[8]; + const DynamicGPUBuffer * vertexbuf; // never NULL + bool ownsVertexbuf; // fixed float tu1, tu2, tv1, tv2; // texcoords @@ -26,6 +28,7 @@ public: private: ElementTemplate(const ElementTemplate&); // no copy + ElementTemplate& operator=(const ElementTemplate&); // no assign }; class Tileset diff --git a/BBGE/VertexBuffer.cpp b/BBGE/VertexBuffer.cpp new file mode 100644 index 0000000..a6c4660 --- /dev/null +++ b/BBGE/VertexBuffer.cpp @@ -0,0 +1,262 @@ +#include "VertexBuffer.h" +#include "RenderBase.h" +#include "Base.h" +#include + +bool DynamicGPUBuffer::_HasARB = false; + +static unsigned s_lastVertexBuffer = 0; +static unsigned s_lastIndexBuffer = 0; +static void *s_lastHostPtr = NULL; +static BufDataType s_lastDataType = BufDataType(-1); +static unsigned s_lastState = 0; // StateBits + +enum StateBits +{ + SB_COLOR_FROM_BUFFER = 0x01 +}; + +static unsigned toGlUsage(unsigned usage) +{ + if(usage & GPUBUF_STATIC) + return GL_STATIC_DRAW_ARB; + return GL_DYNAMIC_DRAW; +} + +void DynamicGPUBuffer::StaticInit() +{ + _HasARB = glGenBuffersARB && glDeleteBuffersARB + && glBufferDataARB && glBufferSubDataARB + && glBindBufferARB && glMapBufferARB && glUnmapBufferARB; +} + +DynamicGPUBuffer::DynamicGPUBuffer(unsigned usage) + : _bufid(0) + , _binding((usage & GPUBUF_INDEXBUF) ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB) + , _size(0) + , _cap(0) + , _h_data(NULL) + , _d_map(NULL) + , _usage(toGlUsage(usage)) + , _datatype(BufDataType(-1)) +{ +} + +DynamicGPUBuffer::~DynamicGPUBuffer() +{ + dropBuffer(); +} + +void* DynamicGPUBuffer::_allocBytes(size_t bytes) +{ + if(s_lastHostPtr == _h_data) + s_lastHostPtr = NULL; + + void *p = realloc(_h_data, bytes); + if(p) + { + _cap = bytes; + _h_data = p; + } + return p; +} + +void* DynamicGPUBuffer::_ensureBytes(size_t bytes) +{ + if(bytes < _cap) + return _h_data; + + size_t newsize = 2 * _size; + if(newsize < bytes) + newsize += bytes; + + return _allocBytes(newsize); +} + +void* DynamicGPUBuffer::beginWrite(BufDataType type, size_t newsize, unsigned access) +{ + _size = newsize; + _datatype = type; + + if(_HasARB) + { + glBindBufferARB(_binding, _ensureDBuf()); + glBufferDataARB(_binding, newsize, NULL, _usage); // orphan buffer + if(!(access & GPUACCESS_HOSTCOPY)) + { + void *p = glMapBufferARB(_binding, GL_WRITE_ONLY_ARB); + _d_map = p; + if(p) + return p; + } + } + + return _ensureBytes(newsize); +} + +bool DynamicGPUBuffer::commitWrite() +{ + if(_HasARB) + { + if(_d_map) + { + _d_map = NULL; + return glUnmapBufferARB(_binding); // can fail + } + // otherwise, the prev. call to glMapBufferARB failed (or GPUACCESS_NOMAP was set). + // -> didn't map, but wrote to host memory. upload it. + assert(_h_data); + glBufferSubDataARB(_binding, 0, _size, _h_data); + } + // else nothing to do + + return true; +} + +void DynamicGPUBuffer::upload(BufDataType type, const void* data, size_t size) +{ + _datatype = type; + + if(_HasARB) + { + glBindBufferARB(_binding, _ensureDBuf()); + glBufferDataARB(_binding, size, data, _usage); + } + else + memcpy(_ensureBytes(size), data, size); +} + +static const unsigned s_gltype[] = +{ + GL_SHORT, + GL_FLOAT, +}; + +struct BufPtrConfig +{ + uintptr_t bufidOrPtr; + BufDataType datatype; + +}; + +void DynamicGPUBuffer::apply(BufDataType usetype) const +{ + if(!usetype) + usetype = _datatype; + + void *p; + if(_HasARB) + { + unsigned bufid = this->_bufid; + assert(bufid != s_lastVertexBuffer); // check that it's no redundant state change + if(bufid == s_lastVertexBuffer && usetype == s_lastDataType) + return; + p = NULL; + s_lastVertexBuffer = bufid; + glBindBufferARB(GL_ARRAY_BUFFER_ARB, bufid); + } + else + { + p = (void*)this->_h_data; + assert(p != s_lastHostPtr); // check that it's no redundant state change + if(p == s_lastHostPtr && usetype == s_lastDataType) // don't need to check for datatype since that's const for the buffer with that ptr + return; + } + + s_lastDataType = usetype; + + assert((ty & 0xf) < Countof(s_gltype)); + const unsigned gltype = s_gltype[usetype & 0xf]; + const unsigned scalars = (usetype >> 4) & 0xf; + const unsigned stride = (usetype >> 8) & 0xff; + const unsigned tcoffset = (usetype >> 16) & 0xff; + const unsigned coloroffset = usetype >> 24; + + // vertex and texcoords are always enabled + glVertexPointer(scalars, gltype, stride, p); + if(tcoffset) + glTexCoordPointer(2, gltype, stride, (void*)((uintptr_t)p + tcoffset)); + + unsigned wantedstate = 0; + if(coloroffset) + { + wantedstate |= SB_COLOR_FROM_BUFFER; + glColorPointer(4, gltype, stride, (void*)((uintptr_t)p + coloroffset)); + } + + unsigned wrongbits = wantedstate ^ s_lastState; + if(wrongbits) + { + if(wrongbits & SB_COLOR_FROM_BUFFER) + { + if(wantedstate & SB_COLOR_FROM_BUFFER) + glEnableClientState(GL_COLOR_ARRAY); + else + glDisableClientState(GL_COLOR_ARRAY); + } + s_lastState = wantedstate; + } +} + +unsigned DynamicGPUBuffer::_ensureDBuf() +{ + assert(_HasARB); + if(!_bufid) + glGenBuffersARB(1, &_bufid); + return _bufid; +} + +void DynamicGPUBuffer::dropBuffer() +{ + if(s_lastHostPtr == _h_data) + s_lastHostPtr = NULL; + free(_h_data); + _h_data = NULL; + if(_bufid) + { + if(s_lastVertexBuffer == _bufid) + s_lastVertexBuffer = 0; + if(s_lastIndexBuffer == _bufid) + s_lastIndexBuffer = 0; + + glDeleteBuffersARB(1, &_bufid); + _bufid = 0; + } + _size = 0; +} + +void DynamicGPUBuffer::DrawArrays(unsigned glmode, size_t n, size_t first) +{ + glDrawArrays(glmode, first, n); +} + +void DynamicGPUBuffer::drawElements(unsigned glmode, size_t n, size_t first) +{ + assert(_binding == GL_ELEMENT_ARRAY_BUFFER_ARB); + assert(s_gltype[_datatype & 0xf] == GL_SHORT); + + if(s_lastIndexBuffer != _bufid) + { + s_lastIndexBuffer = _bufid; + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _bufid); + } + + glDrawElements(glmode, n, GL_SHORT, NULL); +} + +void DynamicGPUBuffer::initQuadVertices(float tu1, float tv1, float tu2, float tv2) +{ + do + { + float *p = (float*)beginWrite(GPUBUFTYPE_VEC2_TC, (4*4) * sizeof(float), GPUACCESS_DEFAULT); + *p++ = -0.5f; *p++ = +0.5f; // xy + *p++ = tu1; *p++ = 1.0f-tv1; // uv + *p++ = +0.5f; *p++ = +0.5f; // xy + *p++ = tu2; *p++ = 1.0f-tv1; // uv + *p++ = +0.5f; *p++ = -0.5f; // xy + *p++ = tu2; *p++ = 1.0f-tv2; // uv + *p++ = -0.5f; *p++ = -0.5f; // xy + *p++ = tu1; *p++ = 1.0f-tv2; // uv + } + while(!commitWrite()); +} diff --git a/BBGE/VertexBuffer.h b/BBGE/VertexBuffer.h new file mode 100644 index 0000000..7864424 --- /dev/null +++ b/BBGE/VertexBuffer.h @@ -0,0 +1,91 @@ +#ifndef BBGE_VERTEXBUFFER_H +#define BBGE_VERTEXBUFFER_H + +#include // size_t + +enum BufUsage +{ + // usage + GPUBUF_DYNAMIC = 0x00, + GPUBUF_STATIC = 0x01, + // binding point + GPUBUF_VERTEXBUF = 0x00, + GPUBUF_INDEXBUF = 0x02 +}; + +enum BufDataType +{ + GPUBUFTYPE_NONE = 0, +/* ccoossnt -- + ^-- type of each scalar + ^-- number of coordinate scalars (eg. xyz would be 3) + ^^-- stride (distance to next vertex), in bytes + ^^-- offset of texcoords, in bytes, if present + ^^-- offset of colors, if present */ + GPUBUFTYPE_U16 = 0x00000010, // densely packed u16, for indexing + GPUBUFTYPE_VEC2_TC = 0x00081021, // xyuv xyuv xyuv + GPUBUFTYPE_VEC2_TC_RGBA = 0x10082021, // xyuvrgba xyuvrgba xyuvrgba + // ccoossnt + GPUBUFTYPE_VEC2_TC_RGBA_BUT_NO_COLOR = GPUBUFTYPE_VEC2_TC_RGBA & 0xffffff +}; + +enum AccessFlags +{ + // Use whatever works. May directly map in GPU memory so that there is no + // copy on the host; or if there is a previous copy, it may remain untouched. + GPUACCESS_DEFAULT = 0x00, + + // Don't use memory mapping. Prepare buffer on the host and upload it in one go. + // The copy remains on the host. + GPUACCESS_HOSTCOPY = 0x01 +}; + + +class DynamicGPUBuffer +{ + friend class BufMapW; +public: + void StaticInit(); + DynamicGPUBuffer(unsigned usage); + ~DynamicGPUBuffer(); + void dropBuffer(); + + size_t size() const { return _size; } + + // beginWrite(), then write exactly newsize bytes, then commit + void *beginWrite(BufDataType type, size_t newsize, unsigned access); // AccessFlags + bool commitWrite(); + + void upload(BufDataType type, const void *data, size_t size); + + static void DrawArrays(unsigned glmode, size_t n, size_t first = 0); // uses last applied buffer for drawing + + // uses own data for indexing and prev. applied buffer for the data to draw + void drawElements(unsigned glmode, size_t n, size_t first = 0); + + + void apply(BufDataType usetype = GPUBUFTYPE_NONE) const; + + // Inteded for use with DrawArrays(4) and GL_TRIANGLE_FAN or GL_QUADS (both work) + void initQuadVertices(float tu1, float tu2, float tv1, float tv2); + +private: + + void* _allocBytes(size_t bytes); + void* _ensureBytes(size_t bytes); + unsigned _ensureDBuf(); + + unsigned _bufid; + unsigned _binding; + size_t _size; + size_t _cap; + void *_h_data; + void *_d_map; + const unsigned _usage; + BufDataType _datatype; + + static bool _HasARB; +}; + + +#endif // BBGE_VERTEXBUFFER_H \ No newline at end of file