From 4d7be0e20e0b400963661e487924407aa11074fc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 3 May 2016 13:10:00 +0200 Subject: [PATCH] - added software interpolation as a fallback for models. This is not tested yet so no guarantees! --- src/gl/data/gl_vertexbuffer.h | 7 +- src/gl/models/gl_models.cpp | 135 +++++++++++++++++++++---------- src/gl/models/gl_models_md2.cpp | 4 +- src/gl/models/gl_models_md3.cpp | 14 ++-- src/gl/models/gl_voxels.cpp | 4 +- src/gl/renderer/gl_renderstate.h | 5 ++ 6 files changed, 112 insertions(+), 57 deletions(-) diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index c56cadcbac..b88cc6ca16 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -197,11 +197,12 @@ struct FModelVertex class FModelVertexBuffer : public FVertexBuffer { int mIndexFrame[2]; - unsigned int ibo_id; + FModelVertex *vbo_ptr; + uint32_t ibo_id; public: - FModelVertexBuffer(bool needindex); + FModelVertexBuffer(bool needindex, bool singleframe); ~FModelVertexBuffer(); FModelVertex *LockVertexBuffer(unsigned int size); @@ -210,7 +211,7 @@ public: unsigned int *LockIndexBuffer(unsigned int size); void UnlockIndexBuffer(); - unsigned int SetupFrame(unsigned int frame1, unsigned int frame2); + unsigned int SetupFrame(unsigned int frame1, unsigned int frame2, unsigned int size); void BindVBO(); }; diff --git a/src/gl/models/gl_models.cpp b/src/gl/models/gl_models.cpp index dc937ea408..6b586706a6 100644 --- a/src/gl/models/gl_models.cpp +++ b/src/gl/models/gl_models.cpp @@ -111,16 +111,22 @@ void gl_FlushModels() //=========================================================================== // +// Uses a hardware buffer if either single frame (i.e. no interpolation needed) +// or shading is available (interpolation is done by the vertex shader) // +// If interpolation has to be done on the CPU side this will fall back +// to CPU-side arrays. // //=========================================================================== -FModelVertexBuffer::FModelVertexBuffer(bool needindex) +FModelVertexBuffer::FModelVertexBuffer(bool needindex, bool singleframe) + : FVertexBuffer(singleframe || gl.glslversion > 0) { + vbo_ptr = nullptr; ibo_id = 0; if (needindex) { - glGenBuffers(1, &ibo_id); + glGenBuffers(1, &ibo_id); // The index buffer can always be a real buffer. } } @@ -161,6 +167,10 @@ FModelVertexBuffer::~FModelVertexBuffer() { glDeleteBuffers(1, &ibo_id); } + if (vbo_ptr != nullptr) + { + delete[] vbo_ptr; + } } //=========================================================================== @@ -171,9 +181,19 @@ FModelVertexBuffer::~FModelVertexBuffer() FModelVertex *FModelVertexBuffer::LockVertexBuffer(unsigned int size) { - glBindBuffer(GL_ARRAY_BUFFER, vbo_id); - glBufferData(GL_ARRAY_BUFFER, size * sizeof(FModelVertex), NULL, GL_STATIC_DRAW); - return (FModelVertex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, size * sizeof(FModelVertex), GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_BUFFER_BIT); + if (vbo_id > 0) + { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glBufferData(GL_ARRAY_BUFFER, size * sizeof(FModelVertex), nullptr, GL_STATIC_DRAW); + return (FModelVertex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, size * sizeof(FModelVertex), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + } + else + { + if (vbo_ptr != nullptr) delete[] vbo_ptr; + vbo_ptr = new FModelVertex[size]; + memset(vbo_ptr, 0, size * sizeof(FModelVertex)); + return vbo_ptr; + } } //=========================================================================== @@ -184,8 +204,11 @@ FModelVertex *FModelVertexBuffer::LockVertexBuffer(unsigned int size) void FModelVertexBuffer::UnlockVertexBuffer() { - glBindBuffer(GL_ARRAY_BUFFER, vbo_id); - glUnmapBuffer(GL_ARRAY_BUFFER); + if (vbo_id > 0) + { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + glUnmapBuffer(GL_ARRAY_BUFFER); + } } //=========================================================================== @@ -204,7 +227,7 @@ unsigned int *FModelVertexBuffer::LockIndexBuffer(unsigned int size) } else { - return NULL; + return nullptr; } } @@ -216,8 +239,11 @@ unsigned int *FModelVertexBuffer::LockIndexBuffer(unsigned int size) void FModelVertexBuffer::UnlockIndexBuffer() { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id); - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); + if (ibo_id > 0) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id); + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); + } } @@ -227,21 +253,44 @@ void FModelVertexBuffer::UnlockIndexBuffer() // This must be called after gl_RenderState.Apply! // //=========================================================================== +static TArray iBuffer; -unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int frame2) +unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int frame2, unsigned int size) { glBindBuffer(GL_ARRAY_BUFFER, vbo_id); - if (gl.glslversion > 0) + if (vbo_id > 0) { - glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame1].x); - glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame1].u); - glVertexAttribPointer(VATTR_VERTEX2, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame2].x); + if (gl.glslversion > 0) + { + glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame1].x); + glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame1].u); + glVertexAttribPointer(VATTR_VERTEX2, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame2].x); + } + else + { + // only used for single frame models so there is no vertex2 here, which has no use without a shader. + glVertexPointer(3, GL_FLOAT, sizeof(FModelVertex), &VMO[frame1].x); + glTexCoordPointer(2, GL_FLOAT, sizeof(FModelVertex), &VMO[frame1].u); + } + } + else if (frame1 == frame2 || size == 0 || gl_RenderState.GetInterpolationFactor() == 0.f) + { + glVertexPointer(3, GL_FLOAT, sizeof(FModelVertex), &vbo_ptr[frame1].x); + glTexCoordPointer(2, GL_FLOAT, sizeof(FModelVertex), &vbo_ptr[frame1].u); } else { - // only used for single frame models so there is no vertex2 here, which has no use without a shader. - glVertexPointer(3, GL_FLOAT, sizeof(FModelVertex), &VMO[frame1].x); - glTexCoordPointer(2, GL_FLOAT, sizeof(FModelVertex), &VMO[frame1].u); + // must interpolate + iBuffer.Resize(size); + glVertexPointer(3, GL_FLOAT, sizeof(FModelVertex), &iBuffer[0].x); + glTexCoordPointer(2, GL_FLOAT, sizeof(FModelVertex), &vbo_ptr[frame1].u); + float frac = gl_RenderState.GetInterpolationFactor(); + for (unsigned i = 0; i < size; i++) + { + iBuffer[i].x = vbo_ptr[frame1].x * (1.f - frac) + vbo_ptr[frame2].x * frac; + iBuffer[i].y = vbo_ptr[frame1].y * (1.f - frac) + vbo_ptr[frame2].y * frac; + iBuffer[i].z = vbo_ptr[frame1].z * (1.f - frac) + vbo_ptr[frame2].z * frac; + } } return frame1; } @@ -254,7 +303,7 @@ unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int fr FModel::~FModel() { - if (mVBuf != NULL) delete mVBuf; + if (mVBuf != nullptr) delete mVBuf; } @@ -266,8 +315,8 @@ static int * SpriteModelHash; static void DeleteModelHash() { - if (SpriteModelHash != NULL) delete [] SpriteModelHash; - SpriteModelHash = NULL; + if (SpriteModelHash != nullptr) delete [] SpriteModelHash; + SpriteModelHash = nullptr; } //=========================================================================== @@ -283,7 +332,7 @@ static int FindGFXFile(FString & fn) int slash = fn.LastIndexOf('/'); if (dot > slash) fn.Truncate(dot); - static const char * extensions[] = { ".png", ".jpg", ".tga", ".pcx", NULL }; + static const char * extensions[] = { ".png", ".jpg", ".tga", ".pcx", nullptr }; for (const char ** extp=extensions; *extp; extp++) { @@ -313,7 +362,7 @@ FTexture * LoadSkin(const char * path, const char * fn) } else { - return NULL; + return nullptr; } } @@ -346,7 +395,7 @@ static int ModelFrameHash(FSpriteModelFrame * smf) static FModel * FindModel(const char * path, const char * modelfile) { - FModel * model = NULL; + FModel * model = nullptr; FString fullname; fullname.Format("%s%s", path, modelfile); @@ -355,7 +404,7 @@ static FModel * FindModel(const char * path, const char * modelfile) if (lump<0) { Printf("FindModel: '%s' not found\n", fullname.GetChars()); - return NULL; + return nullptr; } for(int i = 0; i< (int)Models.Size(); i++) @@ -380,26 +429,26 @@ static FModel * FindModel(const char * path, const char * modelfile) model = new FMD3Model; } - if (model != NULL) + if (model != nullptr) { if (!model->Load(path, lump, buffer, len)) { delete model; - return NULL; + return nullptr; } } else { // try loading as a voxel FVoxel *voxel = R_LoadKVX(lump); - if (voxel != NULL) + if (voxel != nullptr) { model = new FVoxelModel(voxel, true); } else { Printf("LoadModel: Unknown model format in '%s'\n", fullname.GetChars()); - return NULL; + return nullptr; } } // The vertex buffer cannot be initialized here because this gets called before OpenGL is initialized @@ -486,7 +535,7 @@ void gl_InitModels() smf.xscale=smf.yscale=smf.zscale=1.f; smf.type = PClass::FindClass(sc.String); - if (!smf.type || smf.type->Defaults == NULL) + if (!smf.type || smf.type->Defaults == nullptr) { sc.ScriptError("MODELDEF: Unknown actor type '%s'\n", sc.String); } @@ -631,12 +680,12 @@ void gl_InitModels() FixPathSeperator(sc.String); if (sc.Compare("")) { - smf.skins[index]=NULL; + smf.skins[index]=nullptr; } else { smf.skins[index]=LoadSkin(path.GetChars(), sc.String); - if (smf.skins[index] == NULL) + if (smf.skins[index] == nullptr) { Printf("Skin '%s' not found in '%s'\n", sc.String, smf.type->TypeName.GetChars()); @@ -678,7 +727,7 @@ void gl_InitModels() if (isframe) { sc.MustGetString(); - if (smf.models[index]!=NULL) + if (smf.models[index]!=nullptr) { smf.modelframes[index] = smf.models[index]->FindFrame(sc.String); if (smf.modelframes[index]==-1) sc.ScriptError("Unknown frame '%s' in %s", sc.String, smf.type->TypeName.GetChars()); @@ -765,7 +814,7 @@ FSpriteModelFrame * gl_FindModelFrame(const PClass * ti, int sprite, int frame, if (frame < sprdef->numframes) { spriteframe_t *sprframe = &SpriteFrames[sprdef->spriteframes + frame]; - if (sprframe->Voxel != NULL) + if (sprframe->Voxel != nullptr) { int index = sprframe->Voxel->VoxeldefIndex; if (dropped && sprframe->Voxel->DroppedSpin !=sprframe->Voxel->PlacedSpin) index++; @@ -773,7 +822,7 @@ FSpriteModelFrame * gl_FindModelFrame(const PClass * ti, int sprite, int frame, } } } - return NULL; + return nullptr; } @@ -792,7 +841,7 @@ void gl_RenderFrameModels( const FSpriteModelFrame *smf, { // [BB] Frame interpolation: Find the FSpriteModelFrame smfNext which follows after smf in the animation // and the scalar value inter ( element of [0,1) ), both necessary to determine the interpolated frame. - FSpriteModelFrame * smfNext = NULL; + FSpriteModelFrame * smfNext = nullptr; double inter = 0.; if( gl_interpolate_model_frames && !(smf->flags & MDL_NOINTERPOLATION) ) { @@ -841,7 +890,7 @@ void gl_RenderFrameModels( const FSpriteModelFrame *smf, { FModel * mdl = smf->models[i]; - if (mdl!=NULL) + if (mdl!=nullptr) { mdl->BuildVertexBuffer(); gl_RenderState.SetVertexBuffer(mdl->mVBuf); @@ -949,12 +998,12 @@ void gl_RenderModel(GLSprite * spr) gl_RenderState.mModelMatrix.rotate(-smf->rolloffset, 1, 0, 0); // consider the pixel stretching. For non-voxels this must be factored out here - float stretch = (smf->models[0] != NULL ? smf->models[0]->getAspectFactor() : 1.f) / glset.pixelstretch; + float stretch = (smf->models[0] != nullptr ? smf->models[0]->getAspectFactor() : 1.f) / glset.pixelstretch; gl_RenderState.mModelMatrix.scale(1, stretch, 1); gl_RenderState.EnableModelMatrix(true); - gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, spr->actor->GetClass(), NULL, translation ); + gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, spr->actor->GetClass(), nullptr, translation ); gl_RenderState.EnableModelMatrix(false); glDepthFunc(GL_LESS); @@ -975,7 +1024,7 @@ void gl_RenderHUDModel(pspdef_t *psp, float ofsX, float ofsY) FSpriteModelFrame *smf = gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->state->sprite, psp->state->GetFrame(), false); // [BB] No model found for this sprite, so we can't render anything. - if ( smf == NULL ) + if ( smf == nullptr ) return; glDepthFunc(GL_LEQUAL); @@ -1012,7 +1061,7 @@ void gl_RenderHUDModel(pspdef_t *psp, float ofsX, float ofsY) gl_RenderState.mViewMatrix.rotate(-smf->rolloffset, 1, 0, 0); gl_RenderState.ApplyMatrices(); - gl_RenderFrameModels( smf, psp->state, psp->tics, playermo->player->ReadyWeapon->GetClass(), NULL, 0 ); + gl_RenderFrameModels( smf, psp->state, psp->tics, playermo->player->ReadyWeapon->GetClass(), nullptr, 0 ); glDepthFunc(GL_LESS); if (!( playermo->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) @@ -1027,11 +1076,11 @@ void gl_RenderHUDModel(pspdef_t *psp, float ofsX, float ofsY) bool gl_IsHUDModelForPlayerAvailable (player_t * player) { - if ( (player == NULL) || (player->ReadyWeapon == NULL) || (player->psprites[0].state == NULL) ) + if ( (player == nullptr) || (player->ReadyWeapon == nullptr) || (player->psprites[0].state == nullptr) ) return false; FState* state = player->psprites[0].state; FSpriteModelFrame *smf = gl_FindModelFrame(player->ReadyWeapon->GetClass(), state->sprite, state->GetFrame(), false); - return ( smf != NULL ); + return ( smf != nullptr ); } diff --git a/src/gl/models/gl_models_md2.cpp b/src/gl/models/gl_models_md2.cpp index 7a27e12dc0..b0713ce443 100644 --- a/src/gl/models/gl_models_md2.cpp +++ b/src/gl/models/gl_models_md2.cpp @@ -304,7 +304,7 @@ void FDMDModel::BuildVertexBuffer() int VertexBufferSize = info.numFrames * lodInfo[0].numTriangles * 3; unsigned int vindex = 0; - mVBuf = new FModelVertexBuffer(false); + mVBuf = new FModelVertexBuffer(false, info.numFrames == 1); FModelVertex *vertptr = mVBuf->LockVertexBuffer(VertexBufferSize); for (int i = 0; i < info.numFrames; i++) @@ -375,7 +375,7 @@ void FDMDModel::RenderFrame(FTexture * skin, int frameno, int frameno2, double i gl_RenderState.SetInterpolationFactor((float)inter); gl_RenderState.Apply(); - mVBuf->SetupFrame(frames[frameno].vindex, frames[frameno2].vindex); + mVBuf->SetupFrame(frames[frameno].vindex, frames[frameno2].vindex, lodInfo[0].numTriangles * 3); glDrawArrays(GL_TRIANGLES, 0, lodInfo[0].numTriangles * 3); gl_RenderState.SetInterpolationFactor(0.f); } diff --git a/src/gl/models/gl_models_md3.cpp b/src/gl/models/gl_models_md3.cpp index 024f8ac817..1a49d9691d 100644 --- a/src/gl/models/gl_models_md3.cpp +++ b/src/gl/models/gl_models_md3.cpp @@ -186,7 +186,7 @@ bool FMD3Model::Load(const char * path, int lumpnum, const char * buffer, int le // [BB] According to the MD3 spec, Name is supposed to include the full path. s->skins[i] = LoadSkin("", shader[i].Name); // [BB] Fall back and check if Name is relative. - if (s->skins[i] == NULL) + if (s->skins[i] == nullptr) s->skins[i] = LoadSkin(path, shader[i].Name); } } @@ -255,7 +255,7 @@ void FMD3Model::LoadGeometry() void FMD3Model::BuildVertexBuffer() { - if (mVBuf == NULL) + if (mVBuf == nullptr) { LoadGeometry(); @@ -269,11 +269,11 @@ void FMD3Model::BuildVertexBuffer() ibufsize += 3 * surf->numTriangles; } - mVBuf = new FModelVertexBuffer(true); + mVBuf = new FModelVertexBuffer(true, numFrames == 1); FModelVertex *vertptr = mVBuf->LockVertexBuffer(vbufsize); unsigned int *indxptr = mVBuf->LockIndexBuffer(ibufsize); - assert(vertptr != NULL && indxptr != NULL); + assert(vertptr != nullptr && indxptr != nullptr); unsigned int vindex = 0, iindex = 0; @@ -354,7 +354,7 @@ void FMD3Model::RenderFrame(FTexture * skin, int frameno, int frameno2, double i gl_RenderState.SetMaterial(tex, CLAMP_NONE, translation, -1, false); gl_RenderState.Apply(); - mVBuf->SetupFrame(surf->vindex + frameno * surf->numVertices, surf->vindex + frameno2 * surf->numVertices); + mVBuf->SetupFrame(surf->vindex + frameno * surf->numVertices, surf->vindex + frameno2 * surf->numVertices, surf->numVertices); glDrawElements(GL_TRIANGLES, surf->numTriangles * 3, GL_UNSIGNED_INT, (void*)(intptr_t)(surf->iindex * sizeof(unsigned int))); } gl_RenderState.SetInterpolationFactor(0.f); @@ -370,6 +370,6 @@ FMD3Model::~FMD3Model() { if (frames) delete [] frames; if (surfaces) delete [] surfaces; - frames = NULL; - surfaces = NULL; + frames = nullptr; + surfaces = nullptr; } diff --git a/src/gl/models/gl_voxels.cpp b/src/gl/models/gl_voxels.cpp index 3a34117b9e..2fdb8e1625 100644 --- a/src/gl/models/gl_voxels.cpp +++ b/src/gl/models/gl_voxels.cpp @@ -378,7 +378,7 @@ void FVoxelModel::BuildVertexBuffer() { Initialize(); - mVBuf = new FModelVertexBuffer(true); + mVBuf = new FModelVertexBuffer(true, true); FModelVertex *vertptr = mVBuf->LockVertexBuffer(mVertices.Size()); unsigned int *indxptr = mVBuf->LockIndexBuffer(mIndices.Size()); @@ -443,7 +443,7 @@ void FVoxelModel::RenderFrame(FTexture * skin, int frame, int frame2, double int gl_RenderState.SetMaterial(tex, CLAMP_NOFILTER, translation, -1, false); gl_RenderState.Apply(); - mVBuf->SetupFrame(0, 0); + mVBuf->SetupFrame(0, 0, 0); glDrawElements(GL_TRIANGLES, mNumIndices, GL_UNSIGNED_INT, (void*)(intptr_t)0); } diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index cebbb95704..0172488eb1 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -439,6 +439,11 @@ public: mInterpolationFactor = fac; } + float GetInterpolationFactor() + { + return mInterpolationFactor; + } + // Backwards compatibility crap follows void ApplyFixedFunction(); void DrawColormapOverlay();