From 1efc2938b77925bb931b1063e6aa2814aaae6dce Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 29 Jun 2014 23:24:16 +0200 Subject: [PATCH] - implement model vertex buffer and draw MD2 models using it instead of using the GLCommands from the model. --- src/gl/data/gl_vertexbuffer.cpp | 2 + src/gl/data/gl_vertexbuffer.h | 3 +- src/gl/models/gl_models.cpp | 77 ++++++++++++++- src/gl/models/gl_models.h | 15 ++- src/gl/models/gl_models_md2.cpp | 154 ++++++----------------------- src/gl/models/gl_models_md3.cpp | 1 + src/gl/renderer/gl_renderer.cpp | 2 + src/gl/renderer/gl_renderer.h | 2 + src/gl/scene/gl_skydome.cpp | 1 + wadsrc/static/shaders/glsl/main.vp | 2 +- 10 files changed, 122 insertions(+), 137 deletions(-) diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index 6ba9f794e2..3ea401dcd3 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -45,6 +45,7 @@ #include "c_cvars.h" #include "gl/system/gl_interface.h" #include "gl/renderer/gl_renderer.h" +#include "gl/shaders/gl_shader.h" #include "gl/data/gl_data.h" #include "gl/data/gl_vertexbuffer.h" @@ -332,6 +333,7 @@ void FFlatVertexBuffer::BindVBO() glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); + glDisableVertexAttribArray(VATTR_VERTEX2); } } diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index ad09fb5d95..a183a7a2ec 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -193,6 +193,7 @@ struct FModelVertex class FModelVertexBuffer : public FVertexBuffer { int mIndexFrame[2]; + unsigned int ibo_id; public: // these are public because it's the models having to fill them in. @@ -203,7 +204,7 @@ public: ~FModelVertexBuffer(); void BindVBO(); - void UpdateBufferPointers(int frame1, int frame2); + unsigned int SetupFrame(unsigned int frame1, unsigned int frame2, float factor); }; #define VMO ((FModelVertex*)NULL) diff --git a/src/gl/models/gl_models.cpp b/src/gl/models/gl_models.cpp index 0ee9c563fa..f6aad15fa5 100644 --- a/src/gl/models/gl_models.cpp +++ b/src/gl/models/gl_models.cpp @@ -59,6 +59,7 @@ #include "gl/utility/gl_geometric.h" #include "gl/utility/gl_convert.h" #include "gl/renderer/gl_renderstate.h" +#include "gl/shaders/gl_shader.h" static inline float GetTimeFloat() { @@ -91,6 +92,76 @@ public: DeletingModelArray Models; + +//=========================================================================== +// +// +// +//=========================================================================== + +FModelVertexBuffer::FModelVertexBuffer() +{ + ibo_id = 0; + glGenBuffers(1, &ibo_id); + //for (unsigned i = 1; i < Models.Size(); i++) + for (int i = Models.Size() - 1; i >= 0; i--) + { + Models[i]->BuildVertexBuffer(this); + } + + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glBufferData(GL_ARRAY_BUFFER,vbo_shadowdata.Size() * sizeof(FModelVertex), &vbo_shadowdata[0], GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER,ibo_shadowdata.Size() * sizeof(unsigned int), &ibo_shadowdata[0], GL_STATIC_DRAW); + +} + +FModelVertexBuffer::~FModelVertexBuffer() +{ + if (ibo_id != 0) + { + glDeleteBuffers(1, &ibo_id); + } +} + + +//=========================================================================== +// +// +// +//=========================================================================== + +void FModelVertexBuffer::BindVBO() +{ + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id); + //glVertexPointer(3, GL_FLOAT, sizeof(FModelVertex), &VMO->x); + //glTexCoordPointer(2, GL_FLOAT, sizeof(FModelVertex), &VMO->u); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glEnableVertexAttribArray(VATTR_VERTEX2); +} + +//=========================================================================== +// +// Sets up the buffer starts for frame interpolation +// This must be called after gl_RenderState.Apply! +// +//=========================================================================== + +unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int frame2, float factor) +{ + glVertexPointer(3, GL_FLOAT, sizeof(FModelVertex), &VMO[frame1].x); + glTexCoordPointer(2, GL_FLOAT, sizeof(FModelVertex), &VMO[frame1].u); + glVertexAttribPointer(VATTR_VERTEX2, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame2].x); + return frame1; +} + + + + + static TArray SpriteModelFrames; static int * SpriteModelHash; //TArray StateModelFrames; @@ -674,10 +745,14 @@ void gl_RenderFrameModels( const FSpriteModelFrame *smf, if (mdl!=NULL) { + gl_RenderState.SetVertexBuffer(GLRenderer->mModelVBO); + if ( smfNext && smf->modelframes[i] != smfNext->modelframes[i] ) mdl->RenderFrame(smf->skins[i], smf->modelframes[i], smfNext->modelframes[i], inter, translation); else - mdl->RenderFrame(smf->skins[i], smf->modelframes[i], NULL, 0.f, translation); + mdl->RenderFrame(smf->skins[i], smf->modelframes[i], smf->modelframes[i], 0.f, translation); + + gl_RenderState.SetVertexBuffer(GLRenderer->mVBO); } } } diff --git a/src/gl/models/gl_models.h b/src/gl/models/gl_models.h index f9f8f4f221..00df383ba3 100644 --- a/src/gl/models/gl_models.h +++ b/src/gl/models/gl_models.h @@ -107,7 +107,6 @@ protected: struct DMDLoD { FTriangle * triangles; - int * glCommands; }; @@ -116,27 +115,24 @@ protected: DMDInfo info; FTexture ** skins; FTexCoord * texCoords; - - unsigned int ib_index; - unsigned int ib_count; ModelFrame * frames; DMDLoDInfo lodInfo[MAX_LODS]; DMDLoD lods[MAX_LODS]; - char *vertexUsage; // Bitfield for each vertex. bool allowTexComp; // Allow texture compression with this. - static void RenderGLCommands(void *glCommands, unsigned int numVertices,DMDModelVertex * vertices, DMDModelVertex *vertices2, double inter); - public: FDMDModel() { loaded = false; frames = NULL; skins = NULL; - lods[0].glCommands = NULL; + for (int i = 0; i < MAX_LODS; i++) + { + lods[i].triangles = NULL; + } info.numLODs = 0; - ib_count = 0; + texCoords = NULL; } virtual ~FDMDModel(); @@ -195,6 +191,7 @@ class FMD3Model : public FModel unsigned int vindex; // contains numframes arrays of vertices unsigned int iindex; + unsigned int icount; MD3Surface() { diff --git a/src/gl/models/gl_models_md2.cpp b/src/gl/models/gl_models_md2.cpp index ccf604dca4..df6d8f88e0 100644 --- a/src/gl/models/gl_models_md2.cpp +++ b/src/gl/models/gl_models_md2.cpp @@ -43,11 +43,13 @@ #include "sc_man.h" #include "m_crc32.h" +#include "gl/renderer/gl_renderer.h" #include "gl/renderer/gl_renderstate.h" #include "gl/scene/gl_drawinfo.h" #include "gl/models/gl_models.h" #include "gl/textures/gl_material.h" #include "gl/shaders/gl_shader.h" +#include "gl/data/gl_vertexbuffer.h" static float avertexnormals[NUMVERTEXNORMALS][3] = { #include "tab_anorms.h" @@ -160,10 +162,11 @@ bool FDMDModel::Load(const char * path, int, const char * buffer, int length) skins[i] = LoadSkin(path, buffer + info.offsetSkins + i*64); } + texCoords = new FTexCoord[info.numTexCoords]; + memcpy(texCoords, (byte*)buffer + info.offsetTexCoords, info.numTexCoords * sizeof(FTexCoord)); temp = (char*)buffer + info.offsetFrames; frames = new ModelFrame[info.numFrames]; - ib_count = 0; for(i = 0, frame = frames; i < info.numFrames; i++, frame++) { @@ -193,25 +196,11 @@ bool FDMDModel::Load(const char * path, int, const char * buffer, int length) for(i = 0; i < info.numLODs; i++) { lodInfo[i].numTriangles = LittleLong(lodInfo[i].numTriangles); - lodInfo[i].numGlCommands = LittleLong(lodInfo[i].numGlCommands); lodInfo[i].offsetTriangles = LittleLong(lodInfo[i].offsetTriangles); - lodInfo[i].offsetGlCommands = LittleLong(lodInfo[i].offsetGlCommands); - triangles[i] = (FTriangle*)(buffer + lodInfo[i].offsetTriangles); - - lods[i].glCommands = new int[lodInfo[i].numGlCommands]; - memcpy(lods[i].glCommands, buffer + lodInfo[i].offsetGlCommands, sizeof(int) * lodInfo[i].numGlCommands); + lods[i].triangles = triangles[i] = (FTriangle*)(buffer + lodInfo[i].offsetTriangles); } - // Determine vertex usage at each LOD level. - vertexUsage = new char[info.numVertices]; - memset(vertexUsage, 0, info.numVertices); - - for(i = 0; i < info.numLODs; i++) - for(k = 0; k < lodInfo[i].numTriangles; k++) - for(c = 0; c < 3; c++) - vertexUsage[short(triangles[i][k].vertexIndices[c])] |= 1 << i; - loaded=true; return true; } @@ -240,10 +229,10 @@ FDMDModel::~FDMDModel() for(i = 0; i < info.numLODs; i++) { - delete [] lods[i].glCommands; + if (lods[i].triangles != NULL) delete[] lods[i].triangles; } - if (vertexUsage != NULL) delete [] vertexUsage; + if (texCoords != NULL) delete[] texCoords; } @@ -254,83 +243,33 @@ void FDMDModel::BuildVertexBuffer(FModelVertexBuffer *buf) ModelFrame *frame = &frames[i]; DMDModelVertex *vert = frame->vertices; DMDModelVertex *norm = frame->normals; - void *glCommands = lods[0].glCommands; frame->vindex = buf->vbo_shadowdata.Size(); - for (char *pos = (char*)glCommands; *pos;) + + FTriangle *tri = lods[0].triangles; + + for (int i = 0; i < lodInfo[0].numTriangles; i++) { - int count = *(int *)pos; - pos += 4; - - // The type of primitive depends on the sign. - int primtype = count > 0 ? GL_TRIANGLE_STRIP : GL_TRIANGLE_FAN; - count = abs(count); - - if (i == 0) - { - // build the index buffer - we'll use the same buffer for all frames so only create it once - unsigned int bufindex = buf->vbo_shadowdata.Size() - frame->vindex; - unsigned int bufp = bufindex; - - if (primtype == GL_TRIANGLE_STRIP) - { - for (int t = 0; t < count - 2; t++) - { - unsigned int *p = &buf->ibo_shadowdata[buf->ibo_shadowdata.Reserve(3)]; - if ((t & 1) == 0) - { - p[0] = bufp; - p[1] = bufp + 1; - p[2] = bufp + 2; - } - else - { - p[0] = bufp; - p[2] = bufp + 2; - p[1] = bufp + 1; - } - bufp++; - } - } - else - { - bufp++; - for (int t = 0; t < count - 2; t++) - { - unsigned int *p = &buf->ibo_shadowdata[buf->ibo_shadowdata.Reserve(3)]; - p[0] = bufindex; - p[1] = bufp; - p[2] = bufp + 1; - bufp++; - } - } - } - - while (count--) + for (int j = 0; j < 3; j++) { FModelVertex bvert; - FGLCommandVertex * v = (FGLCommandVertex *)pos; - pos += sizeof(FGLCommandVertex); + int ti = tri->textureIndices[j]; + int vi = tri->vertexIndices[j]; - bvert.Set(vert[v->index].xyz[0], vert[v->index].xyz[1], vert[v->index].xyz[2], v->s, v->t); - bvert.SetNormal(norm[v->index].xyz[0], norm[v->index].xyz[1], norm[v->index].xyz[2]); + bvert.Set(vert[vi].xyz[0], vert[vi].xyz[1], vert[vi].xyz[2], (float)texCoords[ti].s /info.skinWidth, (float)texCoords[ti].t/info.skinHeight); + bvert.SetNormal(norm[vi].xyz[0], norm[vi].xyz[1], norm[vi].xyz[2]); buf->vbo_shadowdata.Push(bvert); } + tri++; } + } } - - - - - - - //=========================================================================== // // FDMDModel::FindFrame @@ -347,50 +286,10 @@ int FDMDModel::FindFrame(const char * name) //=========================================================================== // -// Render a set of GL commands using the given data. +// // //=========================================================================== -void FDMDModel::RenderGLCommands(void *glCommands, unsigned int numVertices, DMDModelVertex * vertices, DMDModelVertex *vertices2, double inter) -{ - char *pos; - FGLCommandVertex * v; - int count; - const bool interpolate = (vertices2 != NULL && inter != 0. && vertices != vertices2); - - gl_RenderState.Apply(); - for(pos = (char*)glCommands; *pos;) - { - count = *(int *) pos; - pos += 4; - - // The type of primitive depends on the sign. - glBegin(count > 0 ? GL_TRIANGLE_STRIP : GL_TRIANGLE_FAN); - - count = abs(count); - - while (count--) - { - v = (FGLCommandVertex *)pos; - pos += sizeof(FGLCommandVertex); - - glTexCoord2fv(&v->s); - if (!interpolate) - { - glVertex3fv(vertices[v->index].xyz); - } - else - { - float interp[3]; - for (int i = 0; i < 3; i++) - interp[i] = inter * vertices[v->index].xyz[i] + (1. - inter) * vertices2[v->index].xyz[i]; - glVertex3fv(interp); - } - } - glEnd(); - } -} - void FDMDModel::RenderFrame(FTexture * skin, int frameno, int frameno2, double inter, int translation) { if (frameno >= info.numFrames || frameno2 >= info.numFrames) return; @@ -406,7 +305,9 @@ void FDMDModel::RenderFrame(FTexture * skin, int frameno, int frameno2, double i tex->Bind(0, translation); - RenderGLCommands(lods[0].glCommands, info.numVertices, frames[frameno].vertices, frames[frameno2].vertices, inter); + gl_RenderState.Apply(); + GLRenderer->mModelVBO->SetupFrame(frames[frameno].vindex, frames[frameno2].vindex, inter); + glDrawArrays(GL_TRIANGLES, 0, lodInfo[0].numTriangles * 3); } @@ -464,7 +365,6 @@ bool FMD2Model::Load(const char * path, int, const char * buffer, int length) header.magic = MD2_MAGIC; header.version = 8; header.flags = 0; - vertexUsage = NULL; info.skinWidth = LittleLong(md2header->skinWidth); info.skinHeight = LittleLong(md2header->skinHeight); info.frameSize = LittleLong(md2header->frameSize); @@ -496,9 +396,12 @@ bool FMD2Model::Load(const char * path, int, const char * buffer, int length) // The frames need to be unpacked. md2_frames = (byte*)buffer + info.offsetFrames; - frames = new ModelFrame[info.numFrames]; + texCoords = new FTexCoord[info.numTexCoords]; + memcpy(texCoords, (byte*)buffer + info.offsetTexCoords, info.numTexCoords * sizeof(FTexCoord)); + + for(i = 0, frame = frames; i < info.numFrames; i++, frame++) { md2_packedFrame_t *pfr = (md2_packedFrame_t *) (md2_frames + info.frameSize * i); @@ -526,8 +429,9 @@ bool FMD2Model::Load(const char * path, int, const char * buffer, int length) } - lods[0].glCommands = new int[lodInfo[0].numGlCommands]; - memcpy(lods[0].glCommands, buffer + lodInfo[0].offsetGlCommands, sizeof(int) * lodInfo[0].numGlCommands); + lods[0].triangles = new FTriangle[lodInfo[0].numTriangles]; + + memcpy(lods[0].triangles, buffer + lodInfo[0].offsetTriangles, sizeof(FTriangle) * lodInfo[0].numTriangles); skins = new FTexture *[info.numSkins]; diff --git a/src/gl/models/gl_models_md3.cpp b/src/gl/models/gl_models_md3.cpp index 2c6f39d05f..4ae403fb41 100644 --- a/src/gl/models/gl_models_md3.cpp +++ b/src/gl/models/gl_models_md3.cpp @@ -233,6 +233,7 @@ void FMD3Model::BuildVertexBuffer(FModelVertexBuffer *buf) buf->ibo_shadowdata.Push(surf->tris[k].VertIndex[l]); } } + surf->icount = buf->ibo_shadowdata.Size() - surf->iindex; } } diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 97cf6d10f2..b2b3edd8e6 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -109,6 +109,7 @@ void FGLRenderer::Initialize() mVBO = new FFlatVertexBuffer; mSkyVBO = new FSkyVertexBuffer; + mModelVBO = new FModelVertexBuffer; gl_RenderState.SetVertexBuffer(mVBO); mFBID = 0; SetupLevel(); @@ -123,6 +124,7 @@ FGLRenderer::~FGLRenderer() //if (mThreadManager != NULL) delete mThreadManager; if (mShaderManager != NULL) delete mShaderManager; if (mVBO != NULL) delete mVBO; + if (mModelVBO) delete mModelVBO; if (mSkyVBO != NULL) delete mSkyVBO; if (glpart2) delete glpart2; if (glpart) delete glpart; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 77a38e7aef..7331235994 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -10,6 +10,7 @@ struct particle_t; class FCanvasTexture; class FFlatVertexBuffer; class FSkyVertexBuffer; +class FModelVertexBuffer; class OpenGLFrameBuffer; struct FDrawInfo; struct pspdef_t; @@ -71,6 +72,7 @@ public: FFlatVertexBuffer *mVBO; FSkyVertexBuffer *mSkyVBO; + FModelVertexBuffer *mModelVBO; FGLRenderer(OpenGLFrameBuffer *fb); diff --git a/src/gl/scene/gl_skydome.cpp b/src/gl/scene/gl_skydome.cpp index ad3b1c90b9..0d9026ea6e 100644 --- a/src/gl/scene/gl_skydome.cpp +++ b/src/gl/scene/gl_skydome.cpp @@ -93,6 +93,7 @@ void FSkyVertexBuffer::BindVBO() glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_COLOR_ARRAY); + glDisableVertexAttribArray(VATTR_VERTEX2); } diff --git a/wadsrc/static/shaders/glsl/main.vp b/wadsrc/static/shaders/glsl/main.vp index 66ef3b51ee..3ec5990b26 100644 --- a/wadsrc/static/shaders/glsl/main.vp +++ b/wadsrc/static/shaders/glsl/main.vp @@ -6,7 +6,7 @@ out vec2 glowdist; void main() { - vec4 worldcoord = mix(gl_Vertex, aVertex2, uInterpolationFactor); + vec4 worldcoord = ModelMatrix * mix(gl_Vertex, aVertex2, uInterpolationFactor); vec4 eyeCoordPos = ViewMatrix * worldcoord; gl_FrontColor = gl_Color;