From 4fbe77fb82f7a5b761fdbfc2e0bf4c9e2c95e15b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 1 May 2016 16:49:35 -0500 Subject: [PATCH 01/11] Very minor optimization for ACS str(i)cmp - If the two strings compared both point to the same location in memory, then we know they are the same string without having to bother actually comparing their contents. Note that the opposite is not neccessarily true: If they point to two different locations, they could still match a case-sensitive comparison because there are still two ACS string tables: the one that belongs to the map's script and the one that belongs to everything else. --- src/p_acs.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 003138211..032abbc27 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5567,6 +5567,11 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) if (argCount >= 2) { const char *a, *b; + // If the string indicies are the same, then they are the same string. + if (args[0] == args[1]) + { + return 0; + } a = FBehavior::StaticLookupString(args[0]); b = FBehavior::StaticLookupString(args[1]); From a576243ff28af07760a504a9a326b51382973b81 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 3 May 2016 10:26:29 +0200 Subject: [PATCH 02/11] - fixed: ThrustThing should add to the velocity, not set it. --- src/p_lnspec.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 2f3052203..103ac1264 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -75,6 +75,10 @@ */ static const BYTE ChangeMap[8] = { 0, 1, 5, 3, 7, 2, 6, 0 }; +int LS_Sector_SetPlaneReflection(line_t *ln, AActor *it, bool backSide, int arg0, int arg1, int arg2, int arg3, int arg4); +int LS_SetGlobalFogParameter(line_t *ln, AActor *it, bool backSide, int arg0, int arg1, int arg2, int arg3, int arg4); + + #define FUNC(a) static int a (line_t *ln, AActor *it, bool backSide, \ int arg0, int arg1, int arg2, int arg3, int arg4) @@ -1128,7 +1132,7 @@ FUNC(LS_Teleport_Line) static void ThrustThingHelper(AActor *it, DAngle angle, double force, INTBOOL nolimit) { - it->VelFromAngle(angle, force); + it->Thrust(angle, force); if (!nolimit) { it->Vel.X = clamp(it->Vel.X, -MAXMOVE, MAXMOVE); @@ -3440,9 +3444,9 @@ static lnSpecFunc LineSpecials[] = /* 154 */ LS_Teleport_NoStop, /* 155 */ LS_NOP, /* 156 */ LS_NOP, - /* 157 */ LS_NOP, // SetGlobalFogParameter // in GZDoom + /* 157 */ LS_SetGlobalFogParameter, /* 158 */ LS_FS_Execute, - /* 159 */ LS_NOP, // Sector_SetPlaneReflection in GZDoom + /* 159 */ LS_Sector_SetPlaneReflection, /* 160 */ LS_NOP, // Sector_Set3DFloor /* 161 */ LS_NOP, // Sector_SetContents /* 162 */ LS_NOP, // Reserved Doom64 branch From 942138b307672f552f6137bdcde196a749c2c637 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 3 May 2016 11:27:52 +0200 Subject: [PATCH 03/11] - undid some leftover texture state checks from the first attempt to handle this without sampler objects. This code was written under the assumption that the glGenerateMipmap function does not exist. But all supported hardware has this function through the GL_EXT_framebuffer_object extension. --- src/gl/textures/gl_material.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gl/textures/gl_material.cpp b/src/gl/textures/gl_material.cpp index 5207ea00d..ee51bb2b9 100644 --- a/src/gl/textures/gl_material.cpp +++ b/src/gl/textures/gl_material.cpp @@ -300,7 +300,7 @@ const FHardwareTexture *FGLTexture::Bind(int texunit, int clampmode, int transla translation = GLTranslationPalette::GetInternalTranslation(translation); } - bool needmipmap = (clampmode <= CLAMP_XY) || !(gl.flags & RFL_SAMPLER_OBJECTS); + bool needmipmap = (clampmode <= CLAMP_XY); FHardwareTexture *hwtex = CreateHwTexture(); @@ -345,7 +345,6 @@ const FHardwareTexture *FGLTexture::Bind(int texunit, int clampmode, int transla } delete[] buffer; } - if (!needmipmap) clampmode = CLAMP_XY_NOMIP; if (tex->bHasCanvas) static_cast(tex)->NeedUpdate(); if (lastSampler != clampmode || lastTranslation != translation) lastSampler = GLRenderer->mSamplerManager->Bind(texunit, clampmode, lastSampler); From 4d7be0e20e0b400963661e487924407aa11074fc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 3 May 2016 13:10:00 +0200 Subject: [PATCH 04/11] - 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 c56cadcba..b88cc6ca1 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 dc937ea40..6b586706a 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 7a27e12dc..b0713ce44 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 024f8ac81..1a49d9691 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 3a34117b9..2fdb8e162 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 cebbb9570..0172488eb 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(); From 0e14f00b51aee74c2aec6c9e48ecd4289a4e3abd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 3 May 2016 13:39:41 +0200 Subject: [PATCH 05/11] - fixed caching of texture sampler state for old hardware. - fixed handling of CLAMP_XY_NOMIP sampler mode. This cannot be lumped together with CLAMP_XY because it has different mipmap requirements. --- src/gl/system/gl_interface.cpp | 2 +- src/gl/textures/gl_material.cpp | 3 ++- src/gl/textures/gl_samplers.cpp | 36 +++++++++++++++++---------------- src/gl/textures/gl_samplers.h | 1 - 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/gl/system/gl_interface.cpp b/src/gl/system/gl_interface.cpp index e6e802e5c..7d091ebb6 100644 --- a/src/gl/system/gl_interface.cpp +++ b/src/gl/system/gl_interface.cpp @@ -168,7 +168,7 @@ void gl_LoadExtensions() gl.vendorstring = (char*)glGetString(GL_VENDOR); gl.lightmethod = LM_SOFTWARE; - if (gl.version >= 3.3f || CheckExtension("GL_ARB_sampler_objects")) + if ((gl.version >= 3.3f || CheckExtension("GL_ARB_sampler_objects")) && !Args->CheckParm("-nosampler")) { gl.flags |= RFL_SAMPLER_OBJECTS; } diff --git a/src/gl/textures/gl_material.cpp b/src/gl/textures/gl_material.cpp index ee51bb2b9..6a579b0d5 100644 --- a/src/gl/textures/gl_material.cpp +++ b/src/gl/textures/gl_material.cpp @@ -346,7 +346,8 @@ const FHardwareTexture *FGLTexture::Bind(int texunit, int clampmode, int transla delete[] buffer; } if (tex->bHasCanvas) static_cast(tex)->NeedUpdate(); - if (lastSampler != clampmode || lastTranslation != translation) + if (translation != lastTranslation) lastSampler = 254; + if (lastSampler != clampmode) lastSampler = GLRenderer->mSamplerManager->Bind(texunit, clampmode, lastSampler); lastTranslation = translation; return hwtex; diff --git a/src/gl/textures/gl_samplers.cpp b/src/gl/textures/gl_samplers.cpp index db0193c69..cee2fd894 100644 --- a/src/gl/textures/gl_samplers.cpp +++ b/src/gl/textures/gl_samplers.cpp @@ -86,7 +86,6 @@ void FSamplerManager::UnbindAll() { for (int i = 0; i < FHardwareTexture::MAX_TEXTURES; i++) { - mLastBound[i] = 0; glBindSampler(i, 0); } } @@ -97,12 +96,8 @@ BYTE FSamplerManager::Bind(int texunit, int num, int lastval) if (gl.flags & RFL_SAMPLER_OBJECTS) { unsigned int samp = mSamplers[num]; - //if (samp != mLastBound[texunit]) - { - glBindSampler(texunit, samp); - mLastBound[texunit] = samp; - return 255; - } + glBindSampler(texunit, samp); + return 255; } else { @@ -112,7 +107,7 @@ BYTE FSamplerManager::Bind(int texunit, int num, int lastval) case CLAMP_NONE: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - if (lastval > CLAMP_XY_NOMIP) + if (lastval >= CLAMP_XY_NOMIP) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter); @@ -123,7 +118,7 @@ BYTE FSamplerManager::Bind(int texunit, int num, int lastval) case CLAMP_X: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - if (lastval > CLAMP_XY_NOMIP) + if (lastval >= CLAMP_XY_NOMIP) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter); @@ -134,7 +129,18 @@ BYTE FSamplerManager::Bind(int texunit, int num, int lastval) case CLAMP_Y: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (lastval > CLAMP_XY_NOMIP) + if (lastval >= CLAMP_XY_NOMIP) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_filter_anisotropic); + } + break; + + case CLAMP_XY: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (lastval >= CLAMP_XY_NOMIP) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter); @@ -143,15 +149,11 @@ BYTE FSamplerManager::Bind(int texunit, int num, int lastval) break; case CLAMP_XY_NOMIP: - case CLAMP_XY: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (lastval > CLAMP_XY_NOMIP) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_filter_anisotropic); - } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].magfilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1); break; case CLAMP_NOFILTER: diff --git a/src/gl/textures/gl_samplers.h b/src/gl/textures/gl_samplers.h index daba65d45..b74d49a33 100644 --- a/src/gl/textures/gl_samplers.h +++ b/src/gl/textures/gl_samplers.h @@ -8,7 +8,6 @@ class FSamplerManager // We need 6 different samplers: 4 for the different clamping modes, // one for 2D-textures and one for voxel textures unsigned int mSamplers[7]; - unsigned int mLastBound[FHardwareTexture::MAX_TEXTURES]; void UnbindAll(); From f7fda94ec9d2e9aa7b49549411062f95c90df7c5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 3 May 2016 15:45:21 +0200 Subject: [PATCH 06/11] - changed model data to store models and textures by index instead of by pointer. The indices are needed for efficient precaching and actual changes to the logic are minor so that this was the best option overall. --- src/gl/models/gl_models.cpp | 87 +++++++++++++++------------------ src/gl/models/gl_models.h | 32 +++++++++--- src/gl/models/gl_models_md2.cpp | 8 +-- src/gl/models/gl_models_md3.cpp | 8 +-- src/gl/models/gl_voxels.cpp | 3 +- 5 files changed, 73 insertions(+), 65 deletions(-) diff --git a/src/gl/models/gl_models.cpp b/src/gl/models/gl_models.cpp index 6b586706a..88c179567 100644 --- a/src/gl/models/gl_models.cpp +++ b/src/gl/models/gl_models.cpp @@ -73,32 +73,17 @@ EXTERN_CVAR(Int, gl_fogmode) extern TDeletingArray Voxels; extern TDeletingArray VoxelDefs; - -class DeletingModelArray : public TArray -{ -public: - -#if 1 - ~DeletingModelArray() - { - for(unsigned i=0;i= 0; i--) { Models[i]->BuildVertexBuffer(); } + */ } void gl_FlushModels() @@ -327,6 +312,9 @@ static void DeleteModelHash() static int FindGFXFile(FString & fn) { + int lump = Wads.CheckNumForFullName(fn); // if we find something that matches the name plus the extension, return it and do not enter the substitution logic below. + if (lump != -1) return lump; + int best = -1; int dot = fn.LastIndexOf('.'); int slash = fn.LastIndexOf('/'); @@ -349,7 +337,7 @@ static int FindGFXFile(FString & fn) // //=========================================================================== -FTexture * LoadSkin(const char * path, const char * fn) +FTextureID LoadSkin(const char * path, const char * fn) { FString buffer; @@ -358,11 +346,11 @@ FTexture * LoadSkin(const char * path, const char * fn) int texlump = FindGFXFile(buffer); if (texlump>=0) { - return TexMan.FindTexture(Wads.GetLumpFullName(texlump), FTexture::TEX_Any, FTextureManager::TEXMAN_TryAny); + return TexMan.CheckForTexture(Wads.GetLumpFullName(texlump), FTexture::TEX_Any, FTextureManager::TEXMAN_TryAny); } else { - return nullptr; + return FNullTextureID(); } } @@ -393,7 +381,7 @@ static int ModelFrameHash(FSpriteModelFrame * smf) // //=========================================================================== -static FModel * FindModel(const char * path, const char * modelfile) +static unsigned FindModel(const char * path, const char * modelfile) { FModel * model = nullptr; FString fullname; @@ -404,12 +392,12 @@ static FModel * FindModel(const char * path, const char * modelfile) if (lump<0) { Printf("FindModel: '%s' not found\n", fullname.GetChars()); - return nullptr; + return -1; } - for(int i = 0; i< (int)Models.Size(); i++) + for(unsigned i = 0; i< Models.Size(); i++) { - if (!Models[i]->mFileName.CompareNoCase(fullname)) return Models[i]; + if (!Models[i]->mFileName.CompareNoCase(fullname)) return i; } int len = Wads.LumpLength(lump); @@ -434,7 +422,7 @@ static FModel * FindModel(const char * path, const char * modelfile) if (!model->Load(path, lump, buffer, len)) { delete model; - return nullptr; + return -1; } } else @@ -448,13 +436,12 @@ static FModel * FindModel(const char * path, const char * modelfile) else { Printf("LoadModel: Unknown model format in '%s'\n", fullname.GetChars()); - return nullptr; + return -1; } } // The vertex buffer cannot be initialized here because this gets called before OpenGL is initialized model->mFileName = fullname; - Models.Push(model); - return model; + return Models.Push(model); } //=========================================================================== @@ -493,8 +480,9 @@ void gl_InitModels() { FVoxelModel *md = (FVoxelModel*)Models[VoxelDefs[i]->Voxel->VoxelIndex]; memset(&smf, 0, sizeof(smf)); - smf.models[0] = md; - smf.skins[0] = md->GetPaletteTexture(); + smf.modelIDs[1] = smf.modelIDs[2] = smf.modelIDs[3] = -1; + smf.modelIDs[0] = VoxelDefs[i]->Voxel->VoxelIndex; + smf.skinIDs[0] = md->GetPaletteTexture(); smf.xscale = smf.yscale = smf.zscale = VoxelDefs[i]->Scale; smf.angleoffset = VoxelDefs[i]->AngleOffset.Degrees; if (VoxelDefs[i]->PlacedSpin != 0) @@ -523,6 +511,7 @@ void gl_InitModels() } memset(&smf, 0, sizeof(smf)); + smf.modelIDs[0] = smf.modelIDs[1] = smf.modelIDs[2] = smf.modelIDs[3] = -1; while ((Lump = Wads.FindLump("MODELDEF", &lastLump)) != -1) { FScanner sc(Lump); @@ -532,6 +521,7 @@ void gl_InitModels() { sc.MustGetString(); memset(&smf, 0, sizeof(smf)); + smf.modelIDs[1] = smf.modelIDs[2] = smf.modelIDs[3] = -1; smf.xscale=smf.yscale=smf.zscale=1.f; smf.type = PClass::FindClass(sc.String); @@ -554,15 +544,15 @@ void gl_InitModels() else if (sc.Compare("model")) { sc.MustGetNumber(); - index=sc.Number; - if (index<0 || index>=MAX_MODELS_PER_FRAME) + index = sc.Number; + if (index < 0 || index >= MAX_MODELS_PER_FRAME) { sc.ScriptError("Too many models in %s", smf.type->TypeName.GetChars()); } sc.MustGetString(); FixPathSeperator(sc.String); - smf.models[index] = FindModel(path.GetChars(), sc.String); - if (!smf.models[index]) + smf.modelIDs[index] = FindModel(path.GetChars(), sc.String); + if (smf.modelIDs[index] == -1) { Printf("%s: model not found in %s\n", sc.String, path.GetChars()); } @@ -570,11 +560,11 @@ void gl_InitModels() else if (sc.Compare("scale")) { sc.MustGetFloat(); - smf.xscale=sc.Float; + smf.xscale = sc.Float; sc.MustGetFloat(); - smf.yscale=sc.Float; + smf.yscale = sc.Float; sc.MustGetFloat(); - smf.zscale=sc.Float; + smf.zscale = sc.Float; } // [BB] Added zoffset reading. // Now it must be considered deprecated. @@ -680,12 +670,12 @@ void gl_InitModels() FixPathSeperator(sc.String); if (sc.Compare("")) { - smf.skins[index]=nullptr; + smf.skinIDs[index]=FNullTextureID(); } else { - smf.skins[index]=LoadSkin(path.GetChars(), sc.String); - if (smf.skins[index] == nullptr) + smf.skinIDs[index] = LoadSkin(path.GetChars(), sc.String); + if (!smf.skinIDs[index].isValid()) { Printf("Skin '%s' not found in '%s'\n", sc.String, smf.type->TypeName.GetChars()); @@ -727,9 +717,10 @@ void gl_InitModels() if (isframe) { sc.MustGetString(); - if (smf.models[index]!=nullptr) + if (smf.modelIDs[index] != -1) { - smf.modelframes[index] = smf.models[index]->FindFrame(sc.String); + FModel *model = Models[smf.modelIDs[index]]; + smf.modelframes[index] = model->FindFrame(sc.String); if (smf.modelframes[index]==-1) sc.ScriptError("Unknown frame '%s' in %s", sc.String, smf.type->TypeName.GetChars()); } else smf.modelframes[index] = -1; @@ -888,17 +879,17 @@ void gl_RenderFrameModels( const FSpriteModelFrame *smf, for(int i=0; imodels[i]; - - if (mdl!=nullptr) + if (smf->modelIDs[i] != -1) { + FModel * mdl = Models[smf->modelIDs[i]]; + FTexture *tex = smf->skinIDs[i].isValid()? TexMan(smf->skinIDs[i]) : nullptr; mdl->BuildVertexBuffer(); gl_RenderState.SetVertexBuffer(mdl->mVBuf); if ( smfNext && smf->modelframes[i] != smfNext->modelframes[i] ) - mdl->RenderFrame(smf->skins[i], smf->modelframes[i], smfNext->modelframes[i], inter, translation); + mdl->RenderFrame(tex, smf->modelframes[i], smfNext->modelframes[i], inter, translation); else - mdl->RenderFrame(smf->skins[i], smf->modelframes[i], smf->modelframes[i], 0.f, translation); + mdl->RenderFrame(tex, smf->modelframes[i], smf->modelframes[i], 0.f, translation); gl_RenderState.SetVertexBuffer(GLRenderer->mVBO); } @@ -998,7 +989,7 @@ 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] != nullptr ? smf->models[0]->getAspectFactor() : 1.f) / glset.pixelstretch; + float stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor() : 1.f) / glset.pixelstretch; gl_RenderState.mModelMatrix.scale(1, stretch, 1); diff --git a/src/gl/models/gl_models.h b/src/gl/models/gl_models.h index a99f81322..70379a3d2 100644 --- a/src/gl/models/gl_models.h +++ b/src/gl/models/gl_models.h @@ -1,6 +1,7 @@ #ifndef __GL_MODELS_H_ #define __GL_MODELS_H_ +#include "tarray.h" #include "gl/utility/gl_geometric.h" #include "gl/data/gl_vertexbuffer.h" #include "p_pspr.h" @@ -16,7 +17,7 @@ enum { VX, VZ, VY }; #define MD3_MAGIC 0x33504449 #define NUMVERTEXNORMALS 162 -FTexture * LoadSkin(const char * path, const char * fn); +FTextureID LoadSkin(const char * path, const char * fn); class FModel @@ -124,7 +125,7 @@ protected: int mLumpNum; DMDHeader header; DMDInfo info; - FTexture ** skins; + FTextureID * skins; ModelFrame * frames; bool allowTexComp; // Allow texture compression with this. @@ -201,7 +202,7 @@ class FMD3Model : public FModel int numTriangles; int numSkins; - FTexture ** skins; + FTextureID * skins; MD3Triangle * tris; MD3TexCoord * texcoords; MD3Vertex * vertices; @@ -295,7 +296,7 @@ class FVoxelModel : public FModel protected: FVoxel *mVoxel; bool mOwningVoxel; // if created through MODELDEF deleting this object must also delete the voxel object - FTexture *mPalette; + FTextureID mPalette; unsigned int mNumIndices; TArray mVertices; TArray mIndices; @@ -311,7 +312,7 @@ public: void Initialize(); virtual int FindFrame(const char * name); virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0); - FTexture *GetPaletteTexture() const { return mPalette; } + FTextureID GetPaletteTexture() const { return mPalette; } void BuildVertexBuffer(); float getAspectFactor(); }; @@ -338,8 +339,8 @@ enum struct FSpriteModelFrame { - FModel * models[MAX_MODELS_PER_FRAME]; - FTexture * skins[MAX_MODELS_PER_FRAME]; + int modelIDs[MAX_MODELS_PER_FRAME]; + FTextureID skinIDs[MAX_MODELS_PER_FRAME]; int modelframes[MAX_MODELS_PER_FRAME]; float xscale, yscale, zscale; // [BB] Added zoffset, rotation parameters and flags. @@ -368,4 +369,21 @@ void gl_RenderModel(GLSprite * spr); void gl_RenderHUDModel(pspdef_t *psp, float ofsx, float ofsy); bool gl_IsHUDModelForPlayerAvailable (player_t * player); + +class DeletingModelArray : public TArray +{ +public: + + ~DeletingModelArray() + { + for (unsigned i = 0; iOfs_Shaders)); - s->skins = new FTexture *[s->numSkins]; + s->skins = new FTextureID[s->numSkins]; for (int i = 0; i < s->numSkins; i++) { // [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] == nullptr) + if (!s->skins[i].isValid()) s->skins[i] = LoadSkin(path, shader[i].Name); } } @@ -344,8 +344,8 @@ void FMD3Model::RenderFrame(FTexture * skin, int frameno, int frameno2, double i FTexture *surfaceSkin = skin; if (!surfaceSkin) { - if (surf->numSkins==0) return; - surfaceSkin = surf->skins[0]; + if (surf->numSkins==0 || !surf->skins[0].isValid()) return; + surfaceSkin = TexMan(surf->skins[0]); if (!surfaceSkin) return; } diff --git a/src/gl/models/gl_voxels.cpp b/src/gl/models/gl_voxels.cpp index 2fdb8e162..babb62d10 100644 --- a/src/gl/models/gl_voxels.cpp +++ b/src/gl/models/gl_voxels.cpp @@ -213,7 +213,7 @@ FVoxelModel::FVoxelModel(FVoxel *voxel, bool owned) { mVoxel = voxel; mOwningVoxel = owned; - mPalette = new FVoxelTexture(voxel); + mPalette = TexMan.AddTexture(new FVoxelTexture(voxel)); } //=========================================================================== @@ -224,7 +224,6 @@ FVoxelModel::FVoxelModel(FVoxel *voxel, bool owned) FVoxelModel::~FVoxelModel() { - delete mPalette; if (mOwningVoxel) delete mVoxel; } From 534500f36d5c87e3262cd289d73abbc39713610e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 3 May 2016 16:49:10 +0200 Subject: [PATCH 07/11] - fixed software-based model interpolation. --- src/gl/models/gl_models.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gl/models/gl_models.cpp b/src/gl/models/gl_models.cpp index 88c179567..e2187c59c 100644 --- a/src/gl/models/gl_models.cpp +++ b/src/gl/models/gl_models.cpp @@ -272,9 +272,9 @@ unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int fr 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; + iBuffer[i].x = vbo_ptr[frame1 + i].x * (1.f - frac) + vbo_ptr[frame2 + i].x * frac; + iBuffer[i].y = vbo_ptr[frame1 + i].y * (1.f - frac) + vbo_ptr[frame2 + i].y * frac; + iBuffer[i].z = vbo_ptr[frame1 + i].z * (1.f - frac) + vbo_ptr[frame2 + i].z * frac; } } return frame1; From b6af4677f362869250c1092e892db568a7b2809a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 3 May 2016 18:14:16 +0200 Subject: [PATCH 08/11] - implemented model precaching. --- src/gl/models/gl_models.h | 5 ++ src/gl/models/gl_models_md2.cpp | 15 +++++ src/gl/models/gl_models_md3.cpp | 21 +++++++ src/gl/models/gl_voxels.cpp | 11 ++++ src/gl/scene/gl_scene.cpp | 106 +++++++++++++++++++++++--------- 5 files changed, 129 insertions(+), 29 deletions(-) diff --git a/src/gl/models/gl_models.h b/src/gl/models/gl_models.h index 70379a3d2..33fa00736 100644 --- a/src/gl/models/gl_models.h +++ b/src/gl/models/gl_models.h @@ -34,6 +34,7 @@ public: virtual int FindFrame(const char * name) = 0; virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0) = 0; virtual void BuildVertexBuffer() = 0; + virtual void AddSkins(BYTE *hitlist) = 0; void DestroyVertexBuffer() { delete mVBuf; @@ -155,6 +156,8 @@ public: virtual int FindFrame(const char * name); virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0); virtual void LoadGeometry(); + virtual void AddSkins(BYTE *hitlist); + void UnloadGeometry(); void BuildVertexBuffer(); @@ -260,6 +263,7 @@ public: virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0); void LoadGeometry(); void BuildVertexBuffer(); + virtual void AddSkins(BYTE *hitlist); }; struct FVoxelVertexHash @@ -312,6 +316,7 @@ public: void Initialize(); virtual int FindFrame(const char * name); virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0); + virtual void AddSkins(BYTE *hitlist); FTextureID GetPaletteTexture() const { return mPalette; } void BuildVertexBuffer(); float getAspectFactor(); diff --git a/src/gl/models/gl_models_md2.cpp b/src/gl/models/gl_models_md2.cpp index c45569df9..c0bd155fb 100644 --- a/src/gl/models/gl_models_md2.cpp +++ b/src/gl/models/gl_models_md2.cpp @@ -336,7 +336,22 @@ void FDMDModel::BuildVertexBuffer() } } +//=========================================================================== +// +// for skin precaching +// +//=========================================================================== +void FDMDModel::AddSkins(BYTE *hitlist) +{ + for (int i = 0; i < info.numSkins; i++) + { + if (skins[i].isValid()) + { + hitlist[skins[i].GetIndex()] |= FTexture::TEX_Flat; + } + } +} //=========================================================================== // diff --git a/src/gl/models/gl_models_md3.cpp b/src/gl/models/gl_models_md3.cpp index 3da5bd1c0..267e85c91 100644 --- a/src/gl/models/gl_models_md3.cpp +++ b/src/gl/models/gl_models_md3.cpp @@ -309,6 +309,27 @@ void FMD3Model::BuildVertexBuffer() } +//=========================================================================== +// +// for skin precaching +// +//=========================================================================== + +void FMD3Model::AddSkins(BYTE *hitlist) +{ + for (int i = 0; i < numSurfaces; i++) + { + MD3Surface * surf = &surfaces[i]; + for (int j = 0; j < surf->numSkins; j++) + { + if (surf->skins[j].isValid()) + { + hitlist[surf->skins[j].GetIndex()] |= FTexture::TEX_Flat; + } + } + } +} + //=========================================================================== // // diff --git a/src/gl/models/gl_voxels.cpp b/src/gl/models/gl_voxels.cpp index babb62d10..ec7f0573b 100644 --- a/src/gl/models/gl_voxels.cpp +++ b/src/gl/models/gl_voxels.cpp @@ -397,6 +397,17 @@ void FVoxelModel::BuildVertexBuffer() } +//=========================================================================== +// +// for skin precaching +// +//=========================================================================== + +void FVoxelModel::AddSkins(BYTE *hitlist) +{ + hitlist[mPalette.GetIndex()] |= FTexture::TEX_Flat; +} + //=========================================================================== // // diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index a87e522d3..44368775a 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -1019,23 +1019,10 @@ bool FGLInterface::UsesColormap() const void FGLInterface::PrecacheTexture(FTexture *tex, int cache) { - if (tex != NULL) + if (cache & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) { - if (cache) - { - if (gl_precache) - { - if (cache & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) - { - FMaterial * gltex = FMaterial::ValidateTexture(tex, false); - if (gltex) gltex->Precache(); - } - } - } - else - { - if (tex->gl_info.Material[0]) tex->gl_info.Material[0]->Clean(true); - } + FMaterial * gltex = FMaterial::ValidateTexture(tex, false); + if (gltex) gltex->Precache(); } } @@ -1047,15 +1034,8 @@ void FGLInterface::PrecacheTexture(FTexture *tex, int cache) void FGLInterface::PrecacheSprite(FTexture *tex, SpriteHits &hits) { - if (hits.CountUsed() == 0) - { - if (tex->gl_info.Material[1]) tex->gl_info.Material[1]->Clean(true); - } - else - { - FMaterial * gltex = FMaterial::ValidateTexture(tex, true); - if (gltex) gltex->PrecacheList(hits); - } + FMaterial * gltex = FMaterial::ValidateTexture(tex, true); + if (gltex) gltex->PrecacheList(hits); } //========================================================================== @@ -1070,6 +1050,8 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap &actorhit SpriteHits **spritehitlist = new SpriteHits*[TexMan.NumTextures()]; TMap::Iterator it(actorhitlist); TMap::Pair *pair; + BYTE *modellist = new BYTE[Models.Size()]; + memset(modellist, 0, Models.Size()); memset(spritehitlist, 0, sizeof(SpriteHits**) * TexMan.NumTextures()); // this isn't done by the main code so it needs to be done here first: @@ -1095,6 +1077,9 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap &actorhit } } + // Check all used actors. + // 1. mark all sprites associated with its states + // 2. mark all model data and skins associated with its states while (it.NextPair(pair)) { PClassActor *cls = pair->Key; @@ -1103,11 +1088,29 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap &actorhit for (int i = 0; i < cls->NumOwnedStates; i++) { spritelist[cls->OwnedStates[i].sprite].Insert(gltrans, true); + FSpriteModelFrame * smf = gl_FindModelFrame(cls, cls->OwnedStates[i].sprite, cls->OwnedStates[i].Frame, false); + if (smf != NULL) + { + for (int i = 0; i < MAX_MODELS_PER_FRAME; i++) + { + if (smf->skinIDs[i].isValid()) + { + texhitlist[smf->skinIDs[i].GetIndex()] |= FTexture::TEX_Flat; + } + else if (smf->modelIDs[i] != -1) + { + Models[smf->modelIDs[i]]->AddSkins(texhitlist); + } + if (smf->modelIDs[i] != -1) + { + modellist[smf->modelIDs[i]] = 1; + } + } + } } } - // Precache textures (and sprites). - + // mark all sprite textures belonging to the marked sprites. for (int i = (int)(sprites.Size() - 1); i >= 0; i--) { if (spritelist[i].CountUsed()) @@ -1129,14 +1132,59 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap &actorhit } } + // delete everything unused before creating any new resources to avoid memory usage peaks. + + // delete unused models + for (unsigned i = 0; i < Models.Size(); i++) + { + if (!modellist[i]) Models[i]->DestroyVertexBuffer(); + } + + // delete unused textures int cnt = TexMan.NumTextures(); for (int i = cnt - 1; i >= 0; i--) { - PrecacheTexture(TexMan.ByIndex(i), texhitlist[i]); - if (spritehitlist[i] != nullptr) PrecacheSprite(TexMan.ByIndex(i), *spritehitlist[i]); + FTexture *tex = TexMan.ByIndex(i); + if (tex != nullptr) + { + if (!texhitlist[i]) + { + if (tex->gl_info.Material[0]) tex->gl_info.Material[0]->Clean(true); + } + if (spritehitlist[i] == nullptr || (*spritehitlist[i]).CountUsed() == 0) + { + if (tex->gl_info.Material[1]) tex->gl_info.Material[1]->Clean(true); + } + } } + + if (gl_precache) + { + // cache all used textures + for (int i = cnt - 1; i >= 0; i--) + { + FTexture *tex = TexMan.ByIndex(i); + if (tex != nullptr) + { + PrecacheTexture(tex, texhitlist[i]); + if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CountUsed() > 0) + { + PrecacheSprite(tex, *spritehitlist[i]); + } + } + } + + // cache all used models + for (unsigned i = 0; i < Models.Size(); i++) + { + if (modellist[i]) + Models[i]->BuildVertexBuffer(); + } + } + delete[] spritehitlist; delete[] spritelist; + delete[] modellist; } From 0f8f08edfd5c9657f5429ad332ad57fe2ec4a53e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 3 May 2016 19:24:28 +0200 Subject: [PATCH 09/11] - fixed: camera facing sprites need to orient themselves toward the actual camera position, not the view actor (which may be invalid or in a completely different part of the map if a portal is being rendered.) --- src/gl/scene/gl_sprite.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index 3f90b251e..c85de8a0d 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -287,8 +287,8 @@ void GLSprite::Draw(int pass) if (drawBillboardFacingCamera) { // [CMB] Rotate relative to camera XY position, not just camera direction, // which is nicer in VR - float xrel = xcenter - GLRenderer->mViewActor->X(); - float yrel = ycenter - GLRenderer->mViewActor->Y(); + float xrel = xcenter - ViewPos.X; + float yrel = ycenter - ViewPos.Y; float absAngleDeg = RAD2DEG(atan2(-yrel, xrel)); float counterRotationDeg = 270. - GLRenderer->mAngles.Yaw.Degrees; // counteracts existing sprite rotation float relAngleDeg = counterRotationDeg + absAngleDeg; From be3b126f7b9a3e20d68a0ff9825a7424536a9ea0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 3 May 2016 19:42:53 +0200 Subject: [PATCH 10/11] - fixed: Order of skybox and portal initialization was not well defined. It was always the last item to get initialized that got set. Changed it so that skyboxes cannot override portals at all. --- src/g_shared/a_skies.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index 4e57c638e..57fce23fd 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -126,13 +126,16 @@ void ASkyPicker::PostBeginPlay () else { int boxindex = P_GetSkyboxPortal(box); + // Do not override special portal types, only regular skies. if (0 == (args[1] & 2)) { - Sector->Portals[sector_t::ceiling] = boxindex; + if (Sector->GetPortalType(sector_t::ceiling) == PORTS_SKYVIEWPOINT) + Sector->Portals[sector_t::ceiling] = boxindex; } if (0 == (args[1] & 1)) { - Sector->Portals[sector_t::floor] = boxindex; + if (Sector->GetPortalType(sector_t::floor) == PORTS_SKYVIEWPOINT) + Sector->Portals[sector_t::floor] = boxindex; } } Destroy (); From 0a943719748a4b672628211313f7b7fd53885abf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 3 May 2016 23:28:42 +0200 Subject: [PATCH 11/11] - reinstated old code for rendering fog boundaries and mirrot surfaces without shaders. - added code for filling the render list for textured dynamic lights. This is not yet active because no code is present to handle this data. --- src/gl/compatibility/gl_20.cpp | 92 +++++++++++++++++++++++++++++++++- src/gl/scene/gl_wall.h | 3 ++ src/gl/scene/gl_walls.cpp | 5 ++ src/gl/scene/gl_walls_draw.cpp | 44 ++++++++++------ src/gl/system/gl_load.c | 2 + 5 files changed, 130 insertions(+), 16 deletions(-) diff --git a/src/gl/compatibility/gl_20.cpp b/src/gl/compatibility/gl_20.cpp index e059a3563..1dac5ac38 100644 --- a/src/gl/compatibility/gl_20.cpp +++ b/src/gl/compatibility/gl_20.cpp @@ -49,6 +49,7 @@ #include "gl/dynlights/gl_dynlight.h" #include "gl/utility/gl_geometric.h" #include "gl/renderer/gl_renderer.h" +#include "gl/renderer/gl_lightdata.h" #include "gl/system/gl_interface.h" #include "gl/system/gl_cvars.h" #include "gl/renderer/gl_renderstate.h" @@ -452,7 +453,7 @@ bool gl_SetupLight(int group, Plane & p, ADynamicLight * light, Vector & nearPt, bool gl_SetupLightTexture() { - if (GLRenderer->gllight == NULL) return false; + if (GLRenderer->gllight == nullptr) return false; FMaterial * pat = FMaterial::ValidateTexture(GLRenderer->gllight, false); pat->Bind(CLAMP_XY, 0); return true; @@ -464,6 +465,95 @@ bool gl_SetupLightTexture() // //========================================================================== +bool GLWall::PutWallCompat(int passflag) +{ + static int list_indices[2][2] = + { { GLLDL_WALLS_PLAIN, GLLDL_WALLS_FOG },{ GLLDL_WALLS_MASKED, GLLDL_WALLS_FOGMASKED } }; + + // are lights possible? + if (gl_fixedcolormap != CM_DEFAULT || !gl_lights || seg->sidedef == nullptr || type == RENDERWALL_M2SNF || !gltexture) return false; + + // multipassing these is problematic. + if ((flags&GLWF_SKYHACK && type == RENDERWALL_M2S)) return false; + + // Any lights affecting this wall? + if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) + { + if (seg->sidedef->lighthead == nullptr) return false; + } + else if (sub) + { + if (sub->lighthead != nullptr) return false; + } + + bool foggy = (!gl_isBlack(Colormap.FadeColor) || level.flags&LEVEL_HASFADETABLE); + bool masked = passflag == 2 && gltexture->isMasked(); + + int list = list_indices[masked][foggy]; + if (list == GLLDL_WALLS_PLAIN) + { + if (gltexture->tex->gl_info.Brightmap && gl.glslversion >= 0.f) list = GLLDL_WALLS_BRIGHT; + //if (flags & GLWF_GLOW) list = GLLDL_WALLS_BRIGHT; + } + gl_drawinfo->dldrawlists[list].AddWall(this); + return true; + +} + +//========================================================================== +// +// Fog boundary without any shader support +// +//========================================================================== + +void GLWall::RenderFogBoundaryCompat() +{ + // without shaders some approximation is needed. This won't look as good + // as the shader version but it's an acceptable compromise. + float fogdensity = gl_GetFogDensity(lightlevel, Colormap.FadeColor); + + float dist1 = Dist2(ViewPos.X, ViewPos.Y, glseg.x1, glseg.y1); + float dist2 = Dist2(ViewPos.X, ViewPos.Y, glseg.x2, glseg.y2); + + // these values were determined by trial and error and are scale dependent! + float fogd1 = (0.95f - exp(-fogdensity*dist1 / 62500.f)) * 1.05f; + float fogd2 = (0.95f - exp(-fogdensity*dist2 / 62500.f)) * 1.05f; + + float fc[4] = { Colormap.FadeColor.r / 255.0f,Colormap.FadeColor.g / 255.0f,Colormap.FadeColor.b / 255.0f,fogd2 }; + + gl_RenderState.EnableTexture(false); + gl_RenderState.EnableFog(false); + gl_RenderState.AlphaFunc(GL_GEQUAL, 0); + gl_RenderState.Apply(); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-1.0f, -128.0f); + glDepthFunc(GL_LEQUAL); + glColor4f(fc[0], fc[1], fc[2], fogd1); + glBegin(GL_TRIANGLE_FAN); + glTexCoord2f(lolft.u, lolft.v); + glVertex3f(glseg.x1, zbottom[0], glseg.y1); + glTexCoord2f(uplft.u, uplft.v); + glVertex3f(glseg.x1, ztop[0], glseg.y1); + glColor4f(fc[0], fc[1], fc[2], fogd2); + glTexCoord2f(uprgt.u, uprgt.v); + glVertex3f(glseg.x2, ztop[1], glseg.y2); + glTexCoord2f(lorgt.u, lorgt.v); + glVertex3f(glseg.x2, zbottom[1], glseg.y2); + glEnd(); + glDepthFunc(GL_LESS); + glPolygonOffset(0.0f, 0.0f); + glDisable(GL_POLYGON_OFFSET_FILL); + gl_RenderState.EnableFog(true); + gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f); + gl_RenderState.EnableTexture(true); +} + +//========================================================================== +// +// +// +//========================================================================== + void FGLRenderer::RenderMultipassStuff() { return; diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index 0d8096e76..fdf78ee6f 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -171,10 +171,13 @@ public: private: void CheckGlowing(); + bool PutWallCompat(int passflag); void PutWall(bool translucent); void PutPortal(int ptype); void CheckTexturePosition(); + void RenderFogBoundaryCompat(); + void Put3DWall(lightlist_t * lightlist, bool translucent); void SplitWallComplex(sector_t * frontsector, bool translucent, float maplightbottomleft, float maplightbottomright); void SplitWall(sector_t * frontsector, bool translucent); diff --git a/src/gl/scene/gl_walls.cpp b/src/gl/scene/gl_walls.cpp index ae7cb70c8..906f7f3e1 100644 --- a/src/gl/scene/gl_walls.cpp +++ b/src/gl/scene/gl_walls.cpp @@ -139,6 +139,11 @@ void GLWall::PutWall(bool translucent) } else { + if (gl.lightmethod == LM_SOFTWARE && !translucent) + { + // This is not yet ready. + //if (PutWallCompat(passflag[type])) return; + } bool masked; diff --git a/src/gl/scene/gl_walls_draw.cpp b/src/gl/scene/gl_walls_draw.cpp index 8fe9d948e..9fe120ae2 100644 --- a/src/gl/scene/gl_walls_draw.cpp +++ b/src/gl/scene/gl_walls_draw.cpp @@ -228,16 +228,23 @@ void GLWall::RenderFogBoundary() { if (gl_fogmode && gl_fixedcolormap == 0) { - int rel = rellight + getExtraLight(); - gl_SetFog(lightlevel, rel, &Colormap, false); - gl_RenderState.SetEffect(EFF_FOGBOUNDARY); - gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -128.0f); - RenderWall(RWF_BLANK); - glPolygonOffset(0.0f, 0.0f); - glDisable(GL_POLYGON_OFFSET_FILL); - gl_RenderState.SetEffect(EFF_NONE); + if (gl.glslversion > 0.f) + { + int rel = rellight + getExtraLight(); + gl_SetFog(lightlevel, rel, &Colormap, false); + gl_RenderState.SetEffect(EFF_FOGBOUNDARY); + gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-1.0f, -128.0f); + RenderWall(RWF_BLANK); + glPolygonOffset(0.0f, 0.0f); + glDisable(GL_POLYGON_OFFSET_FILL); + gl_RenderState.SetEffect(EFF_NONE); + } + else + { + RenderFogBoundaryCompat(); + } } } @@ -255,12 +262,19 @@ void GLWall::RenderMirrorSurface() Vector v(glseg.y2-glseg.y1, 0 ,-glseg.x2+glseg.x1); v.Normalize(); - // we use texture coordinates and texture matrix to pass the normal stuff to the shader so that the default vertex buffer format can be used as is. - lolft.u = lorgt.u = uplft.u = uprgt.u = v.X(); - lolft.v = lorgt.v = uplft.v = uprgt.v = v.Z(); + if (gl.glslversion >= 0.f) + { + // we use texture coordinates and texture matrix to pass the normal stuff to the shader so that the default vertex buffer format can be used as is. + lolft.u = lorgt.u = uplft.u = uprgt.u = v.X(); + lolft.v = lorgt.v = uplft.v = uprgt.v = v.Z(); - gl_RenderState.EnableTextureMatrix(true); - gl_RenderState.mTextureMatrix.computeNormalMatrix(gl_RenderState.mViewMatrix); + gl_RenderState.EnableTextureMatrix(true); + gl_RenderState.mTextureMatrix.computeNormalMatrix(gl_RenderState.mViewMatrix); + } + else + { + glNormal3fv(&v[0]); + } // Use sphere mapping for this gl_RenderState.SetEffect(EFF_SPHEREMAP); diff --git a/src/gl/system/gl_load.c b/src/gl/system/gl_load.c index 9b89f2880..aed4e0ff8 100644 --- a/src/gl/system/gl_load.c +++ b/src/gl/system/gl_load.c @@ -42,6 +42,8 @@ static void* SunGetProcAddress (const GLubyte* name) #if defined(_WIN32) #ifdef _MSC_VER +// disable inlining here because it creates an incredible amount of bloat in this file. +#pragma inline_depth(0) #pragma warning(disable: 4055) #pragma warning(disable: 4054) #pragma warning(disable: 4996)