mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-02-18 01:52:34 +00:00
- Create model renderer abstraction to share more model drawing between renderers
This commit is contained in:
parent
734f5104dd
commit
f1e7df542f
7 changed files with 436 additions and 312 deletions
|
@ -293,8 +293,23 @@ struct FModelVertex
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FModelRenderer;
|
||||||
|
|
||||||
class FModelVertexBuffer : public FVertexBuffer
|
class IModelVertexBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IModelVertexBuffer() { }
|
||||||
|
|
||||||
|
virtual FModelVertex *LockVertexBuffer(unsigned int size) = 0;
|
||||||
|
virtual void UnlockVertexBuffer() = 0;
|
||||||
|
|
||||||
|
virtual unsigned int *LockIndexBuffer(unsigned int size) = 0;
|
||||||
|
virtual void UnlockIndexBuffer() = 0;
|
||||||
|
|
||||||
|
virtual void SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FModelVertexBuffer : public FVertexBuffer, public IModelVertexBuffer
|
||||||
{
|
{
|
||||||
int mIndexFrame[2];
|
int mIndexFrame[2];
|
||||||
FModelVertex *vbo_ptr;
|
FModelVertex *vbo_ptr;
|
||||||
|
@ -305,14 +320,14 @@ public:
|
||||||
FModelVertexBuffer(bool needindex, bool singleframe);
|
FModelVertexBuffer(bool needindex, bool singleframe);
|
||||||
~FModelVertexBuffer();
|
~FModelVertexBuffer();
|
||||||
|
|
||||||
FModelVertex *LockVertexBuffer(unsigned int size);
|
FModelVertex *LockVertexBuffer(unsigned int size) override;
|
||||||
void UnlockVertexBuffer();
|
void UnlockVertexBuffer() override;
|
||||||
|
|
||||||
unsigned int *LockIndexBuffer(unsigned int size);
|
unsigned int *LockIndexBuffer(unsigned int size) override;
|
||||||
void UnlockIndexBuffer();
|
void UnlockIndexBuffer() override;
|
||||||
|
|
||||||
unsigned int SetupFrame(unsigned int frame1, unsigned int frame2, unsigned int size);
|
void SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) override;
|
||||||
void BindVBO();
|
void BindVBO() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define VMO ((FModelVertex*)NULL)
|
#define VMO ((FModelVertex*)NULL)
|
||||||
|
|
|
@ -52,11 +52,6 @@
|
||||||
#include "gl/renderer/gl_renderstate.h"
|
#include "gl/renderer/gl_renderstate.h"
|
||||||
#include "gl/shaders/gl_shader.h"
|
#include "gl/shaders/gl_shader.h"
|
||||||
|
|
||||||
static inline float GetTimeFloat()
|
|
||||||
{
|
|
||||||
return (float)I_MSTime() * (float)TICRATE / 1000.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
CVAR(Bool, gl_interpolate_model_frames, true, CVAR_ARCHIVE)
|
CVAR(Bool, gl_interpolate_model_frames, true, CVAR_ARCHIVE)
|
||||||
CVAR(Bool, gl_light_models, true, CVAR_ARCHIVE)
|
CVAR(Bool, gl_light_models, true, CVAR_ARCHIVE)
|
||||||
EXTERN_CVAR(Int, gl_fogmode)
|
EXTERN_CVAR(Int, gl_fogmode)
|
||||||
|
@ -66,6 +61,332 @@ extern TDeletingArray<FVoxelDef *> VoxelDefs;
|
||||||
|
|
||||||
DeletingModelArray Models;
|
DeletingModelArray Models;
|
||||||
|
|
||||||
|
void FModelRenderer::RenderModel(float x, float y, float z, FSpriteModelFrame *smf, AActor *actor)
|
||||||
|
{
|
||||||
|
// Setup transformation.
|
||||||
|
|
||||||
|
int translation = 0;
|
||||||
|
if (!(smf->flags & MDL_IGNORETRANSLATION))
|
||||||
|
translation = actor->Translation;
|
||||||
|
|
||||||
|
// y scale for a sprite means height, i.e. z in the world!
|
||||||
|
float scaleFactorX = actor->Scale.X * smf->xscale;
|
||||||
|
float scaleFactorY = actor->Scale.X * smf->yscale;
|
||||||
|
float scaleFactorZ = actor->Scale.Y * smf->zscale;
|
||||||
|
float pitch = 0;
|
||||||
|
float roll = 0;
|
||||||
|
float rotateOffset = 0;
|
||||||
|
float angle = actor->Angles.Yaw.Degrees;
|
||||||
|
|
||||||
|
// [BB] Workaround for the missing pitch information.
|
||||||
|
if ((smf->flags & MDL_PITCHFROMMOMENTUM))
|
||||||
|
{
|
||||||
|
const double x = actor->Vel.X;
|
||||||
|
const double y = actor->Vel.Y;
|
||||||
|
const double z = actor->Vel.Z;
|
||||||
|
|
||||||
|
if (actor->Vel.LengthSquared() > EQUAL_EPSILON)
|
||||||
|
{
|
||||||
|
// [BB] Calculate the pitch using spherical coordinates.
|
||||||
|
if (z || x || y) pitch = float(atan(z / sqrt(x*x + y*y)) / M_PI * 180);
|
||||||
|
|
||||||
|
// Correcting pitch if model is moving backwards
|
||||||
|
if (fabs(x) > EQUAL_EPSILON || fabs(y) > EQUAL_EPSILON)
|
||||||
|
{
|
||||||
|
if ((x * cos(angle * M_PI / 180) + y * sin(angle * M_PI / 180)) / sqrt(x * x + y * y) < 0) pitch *= -1;
|
||||||
|
}
|
||||||
|
else pitch = fabs(pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (smf->flags & MDL_ROTATING)
|
||||||
|
{
|
||||||
|
const float time = smf->rotationSpeed*GetTimeFloat() / 200.f;
|
||||||
|
rotateOffset = float((time - xs_FloorToInt(time)) *360.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added MDL_USEACTORPITCH and MDL_USEACTORROLL flags processing.
|
||||||
|
// If both flags MDL_USEACTORPITCH and MDL_PITCHFROMMOMENTUM are set, the pitch sums up the actor pitch and the velocity vector pitch.
|
||||||
|
if (smf->flags & MDL_USEACTORPITCH)
|
||||||
|
{
|
||||||
|
double d = actor->Angles.Pitch.Degrees;
|
||||||
|
if (smf->flags & MDL_BADROTATION) pitch += d;
|
||||||
|
else pitch -= d;
|
||||||
|
}
|
||||||
|
if (smf->flags & MDL_USEACTORROLL) roll += actor->Angles.Roll.Degrees;
|
||||||
|
|
||||||
|
VSMatrix objectToWorldMatrix;
|
||||||
|
objectToWorldMatrix.loadIdentity();
|
||||||
|
|
||||||
|
// Model space => World space
|
||||||
|
objectToWorldMatrix.translate(x, z, y);
|
||||||
|
|
||||||
|
// [Nash] take SpriteRotation into account
|
||||||
|
angle += actor->SpriteRotation.Degrees;
|
||||||
|
|
||||||
|
if (actor->renderflags & RF_INTERPOLATEANGLES)
|
||||||
|
{
|
||||||
|
// [Nash] use interpolated angles
|
||||||
|
DRotator Angles = actor->InterpolatedAngles(r_viewpoint.TicFrac);
|
||||||
|
angle = Angles.Yaw.Degrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Applying model transformations:
|
||||||
|
// 1) Applying actor angle, pitch and roll to the model
|
||||||
|
objectToWorldMatrix.rotate(-angle, 0, 1, 0);
|
||||||
|
objectToWorldMatrix.rotate(pitch, 0, 0, 1);
|
||||||
|
objectToWorldMatrix.rotate(-roll, 1, 0, 0);
|
||||||
|
|
||||||
|
// 2) Applying Doomsday like rotation of the weapon pickup models
|
||||||
|
// The rotation angle is based on the elapsed time.
|
||||||
|
|
||||||
|
if (smf->flags & MDL_ROTATING)
|
||||||
|
{
|
||||||
|
objectToWorldMatrix.translate(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ);
|
||||||
|
objectToWorldMatrix.rotate(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate);
|
||||||
|
objectToWorldMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) Scaling model.
|
||||||
|
objectToWorldMatrix.scale(scaleFactorX, scaleFactorZ, scaleFactorY);
|
||||||
|
|
||||||
|
// 4) Aplying model offsets (model offsets do not depend on model scalings).
|
||||||
|
objectToWorldMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale);
|
||||||
|
|
||||||
|
// 5) Applying model rotations.
|
||||||
|
objectToWorldMatrix.rotate(-smf->angleoffset, 0, 1, 0);
|
||||||
|
objectToWorldMatrix.rotate(smf->pitchoffset, 0, 0, 1);
|
||||||
|
objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0);
|
||||||
|
|
||||||
|
// consider the pixel stretching. For non-voxels this must be factored out here
|
||||||
|
float stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor() : 1.f) / level.info->pixelstretch;
|
||||||
|
objectToWorldMatrix.scale(1, stretch, 1);
|
||||||
|
|
||||||
|
BeginDrawModel(actor, smf, objectToWorldMatrix);
|
||||||
|
RenderFrameModels(smf, actor->state, actor->tics, actor->GetClass(), nullptr, translation);
|
||||||
|
EndDrawModel(actor, smf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FModelRenderer::RenderHUDModel(DPSprite *psp, float ofsX, float ofsY)
|
||||||
|
{
|
||||||
|
AActor * playermo = players[consoleplayer].camera;
|
||||||
|
FSpriteModelFrame *smf = gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->GetState()->sprite, psp->GetState()->GetFrame(), false);
|
||||||
|
|
||||||
|
// [BB] No model found for this sprite, so we can't render anything.
|
||||||
|
if (smf == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The model position and orientation has to be drawn independently from the position of the player,
|
||||||
|
// but we need to position it correctly in the world for light to work properly.
|
||||||
|
VSMatrix objectToWorldMatrix = GetViewToWorldMatrix();
|
||||||
|
|
||||||
|
// Scaling model (y scale for a sprite means height, i.e. z in the world!).
|
||||||
|
objectToWorldMatrix.scale(smf->xscale, smf->zscale, smf->yscale);
|
||||||
|
|
||||||
|
// Aplying model offsets (model offsets do not depend on model scalings).
|
||||||
|
objectToWorldMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale);
|
||||||
|
|
||||||
|
// [BB] Weapon bob, very similar to the normal Doom weapon bob.
|
||||||
|
objectToWorldMatrix.rotate(ofsX / 4, 0, 1, 0);
|
||||||
|
objectToWorldMatrix.rotate((ofsY - WEAPONTOP) / -4., 1, 0, 0);
|
||||||
|
|
||||||
|
// [BB] For some reason the jDoom models need to be rotated.
|
||||||
|
objectToWorldMatrix.rotate(90.f, 0, 1, 0);
|
||||||
|
|
||||||
|
// Applying angleoffset, pitchoffset, rolloffset.
|
||||||
|
objectToWorldMatrix.rotate(-smf->angleoffset, 0, 1, 0);
|
||||||
|
objectToWorldMatrix.rotate(smf->pitchoffset, 0, 0, 1);
|
||||||
|
objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0);
|
||||||
|
|
||||||
|
BeginDrawHUDModel(playermo, objectToWorldMatrix);
|
||||||
|
RenderFrameModels(smf, psp->GetState(), psp->GetTics(), playermo->player->ReadyWeapon->GetClass(), nullptr, 0);
|
||||||
|
EndDrawHUDModel(playermo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FModelRenderer::RenderFrameModels(const FSpriteModelFrame *smf,
|
||||||
|
const FState *curState,
|
||||||
|
const int curTics,
|
||||||
|
const PClass *ti,
|
||||||
|
Matrix3x4 *normaltransform,
|
||||||
|
int translation)
|
||||||
|
{
|
||||||
|
// [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 = nullptr;
|
||||||
|
double inter = 0.;
|
||||||
|
if (gl_interpolate_model_frames && !(smf->flags & MDL_NOINTERPOLATION))
|
||||||
|
{
|
||||||
|
FState *nextState = curState->GetNextState();
|
||||||
|
if (curState != nextState && nextState)
|
||||||
|
{
|
||||||
|
// [BB] To interpolate at more than 35 fps we take tic fractions into account.
|
||||||
|
float ticFraction = 0.;
|
||||||
|
// [BB] In case the tic counter is frozen we have to leave ticFraction at zero.
|
||||||
|
if (ConsoleState == c_up && menuactive != MENU_On && !(level.flags2 & LEVEL2_FROZEN))
|
||||||
|
{
|
||||||
|
float time = GetTimeFloat();
|
||||||
|
ticFraction = (time - static_cast<int>(time));
|
||||||
|
}
|
||||||
|
inter = static_cast<double>(curState->Tics - curTics - ticFraction) / static_cast<double>(curState->Tics);
|
||||||
|
|
||||||
|
// [BB] For some actors (e.g. ZPoisonShroom) spr->actor->tics can be bigger than curState->Tics.
|
||||||
|
// In this case inter is negative and we need to set it to zero.
|
||||||
|
if (inter < 0.)
|
||||||
|
inter = 0.;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// [BB] Workaround for actors that use the same frame twice in a row.
|
||||||
|
// Most of the standard Doom monsters do this in their see state.
|
||||||
|
if ((smf->flags & MDL_INTERPOLATEDOUBLEDFRAMES))
|
||||||
|
{
|
||||||
|
const FState *prevState = curState - 1;
|
||||||
|
if ((curState->sprite == prevState->sprite) && (curState->Frame == prevState->Frame))
|
||||||
|
{
|
||||||
|
inter /= 2.;
|
||||||
|
inter += 0.5;
|
||||||
|
}
|
||||||
|
if ((curState->sprite == nextState->sprite) && (curState->Frame == nextState->Frame))
|
||||||
|
{
|
||||||
|
inter /= 2.;
|
||||||
|
nextState = nextState->GetNextState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inter != 0.0)
|
||||||
|
smfNext = gl_FindModelFrame(ti, nextState->sprite, nextState->Frame, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i<MAX_MODELS_PER_FRAME; i++)
|
||||||
|
{
|
||||||
|
if (smf->modelIDs[i] != -1)
|
||||||
|
{
|
||||||
|
FModel * mdl = Models[smf->modelIDs[i]];
|
||||||
|
FTexture *tex = smf->skinIDs[i].isValid() ? TexMan(smf->skinIDs[i]) : nullptr;
|
||||||
|
mdl->BuildVertexBuffer(this);
|
||||||
|
SetVertexBuffer(mdl->mVBuf);
|
||||||
|
|
||||||
|
mdl->PushSpriteMDLFrame(smf, i);
|
||||||
|
|
||||||
|
if (smfNext && smf->modelframes[i] != smfNext->modelframes[i])
|
||||||
|
mdl->RenderFrame(this, tex, smf->modelframes[i], smfNext->modelframes[i], inter, translation);
|
||||||
|
else
|
||||||
|
mdl->RenderFrame(this, tex, smf->modelframes[i], smf->modelframes[i], 0.f, translation);
|
||||||
|
|
||||||
|
ResetVertexBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
extern int modellightindex;
|
||||||
|
|
||||||
|
VSMatrix FGLModelRenderer::GetViewToWorldMatrix()
|
||||||
|
{
|
||||||
|
VSMatrix objectToWorldMatrix;
|
||||||
|
gl_RenderState.mViewMatrix.inverseMatrix(objectToWorldMatrix);
|
||||||
|
return objectToWorldMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGLModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix)
|
||||||
|
{
|
||||||
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
gl_RenderState.EnableTexture(true);
|
||||||
|
// [BB] In case the model should be rendered translucent, do back face culling.
|
||||||
|
// This solves a few of the problems caused by the lack of depth sorting.
|
||||||
|
// [Nash] Don't do back face culling if explicitly specified in MODELDEF
|
||||||
|
// TO-DO: Implement proper depth sorting.
|
||||||
|
if (!(actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) && !(smf->flags & MDL_DONTCULLBACKFACES))
|
||||||
|
{
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glFrontFace(GL_CW);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_RenderState.mModelMatrix = objectToWorldMatrix;
|
||||||
|
gl_RenderState.EnableModelMatrix(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGLModelRenderer::EndDrawModel(AActor *actor, FSpriteModelFrame *smf)
|
||||||
|
{
|
||||||
|
gl_RenderState.EnableModelMatrix(false);
|
||||||
|
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
if (!(actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) && !(smf->flags & MDL_DONTCULLBACKFACES))
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGLModelRenderer::BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix)
|
||||||
|
{
|
||||||
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
|
||||||
|
// [BB] In case the model should be rendered translucent, do back face culling.
|
||||||
|
// This solves a few of the problems caused by the lack of depth sorting.
|
||||||
|
// TO-DO: Implement proper depth sorting.
|
||||||
|
if (!(actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]))
|
||||||
|
{
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glFrontFace(GL_CCW);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_RenderState.mModelMatrix = objectToWorldMatrix;
|
||||||
|
gl_RenderState.EnableModelMatrix(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGLModelRenderer::EndDrawHUDModel(AActor *actor)
|
||||||
|
{
|
||||||
|
gl_RenderState.EnableModelMatrix(false);
|
||||||
|
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
if (!(actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]))
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
IModelVertexBuffer *FGLModelRenderer::CreateVertexBuffer(bool needindex, bool singleframe)
|
||||||
|
{
|
||||||
|
return new FModelVertexBuffer(needindex, singleframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGLModelRenderer::SetVertexBuffer(IModelVertexBuffer *buffer)
|
||||||
|
{
|
||||||
|
gl_RenderState.SetVertexBuffer((FModelVertexBuffer*)buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGLModelRenderer::ResetVertexBuffer()
|
||||||
|
{
|
||||||
|
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGLModelRenderer::SetInterpolation(double inter)
|
||||||
|
{
|
||||||
|
gl_RenderState.SetInterpolationFactor((float)inter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGLModelRenderer::SetMaterial(FTexture *skin, int clampmode, int translation)
|
||||||
|
{
|
||||||
|
FMaterial * tex = FMaterial::ValidateTexture(skin, false);
|
||||||
|
gl_RenderState.SetMaterial(tex, clampmode, translation, -1, false);
|
||||||
|
|
||||||
|
gl_RenderState.Apply();
|
||||||
|
if (modellightindex != -1) gl_RenderState.ApplyLightIndex(modellightindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGLModelRenderer::DrawArrays(int primitiveType, int start, int count)
|
||||||
|
{
|
||||||
|
glDrawArrays(primitiveType, start, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGLModelRenderer::DrawElements(int primitiveType, int numIndices, int elementType, size_t offset)
|
||||||
|
{
|
||||||
|
glDrawElements(primitiveType, numIndices, elementType, (void*)(intptr_t)offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
float FGLModelRenderer::GetTimeFloat()
|
||||||
|
{
|
||||||
|
return (float)I_MSTime() * (float)TICRATE / 1000.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void gl_LoadModels()
|
void gl_LoadModels()
|
||||||
{
|
{
|
||||||
|
@ -238,7 +559,7 @@ void FModelVertexBuffer::UnlockIndexBuffer()
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
static TArray<FModelVertex> iBuffer;
|
static TArray<FModelVertex> iBuffer;
|
||||||
|
|
||||||
unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int frame2, unsigned int size)
|
void FModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
||||||
if (vbo_id > 0)
|
if (vbo_id > 0)
|
||||||
|
@ -276,7 +597,6 @@ unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int fr
|
||||||
iBuffer[i].z = vbo_ptr[frame1 + i].z * (1.f - frac) + vbo_ptr[frame2 + i].z * frac;
|
iBuffer[i].z = vbo_ptr[frame1 + i].z * (1.f - frac) + vbo_ptr[frame2 + i].z * frac;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return frame1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -868,207 +1188,12 @@ FSpriteModelFrame * gl_FindModelFrame(const PClass * ti, int sprite, int frame,
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
void gl_RenderFrameModels( const FSpriteModelFrame *smf,
|
|
||||||
const FState *curState,
|
|
||||||
const int curTics,
|
|
||||||
const PClass *ti,
|
|
||||||
Matrix3x4 *normaltransform,
|
|
||||||
int translation)
|
|
||||||
{
|
|
||||||
// [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 = nullptr;
|
|
||||||
double inter = 0.;
|
|
||||||
if( gl_interpolate_model_frames && !(smf->flags & MDL_NOINTERPOLATION) )
|
|
||||||
{
|
|
||||||
FState *nextState = curState->GetNextState( );
|
|
||||||
if( curState != nextState && nextState )
|
|
||||||
{
|
|
||||||
// [BB] To interpolate at more than 35 fps we take tic fractions into account.
|
|
||||||
float ticFraction = 0.;
|
|
||||||
// [BB] In case the tic counter is frozen we have to leave ticFraction at zero.
|
|
||||||
if ( ConsoleState == c_up && menuactive != MENU_On && !(level.flags2 & LEVEL2_FROZEN) )
|
|
||||||
{
|
|
||||||
float time = GetTimeFloat();
|
|
||||||
ticFraction = (time - static_cast<int>(time));
|
|
||||||
}
|
|
||||||
inter = static_cast<double>(curState->Tics - curTics - ticFraction)/static_cast<double>(curState->Tics);
|
|
||||||
|
|
||||||
// [BB] For some actors (e.g. ZPoisonShroom) spr->actor->tics can be bigger than curState->Tics.
|
|
||||||
// In this case inter is negative and we need to set it to zero.
|
|
||||||
if ( inter < 0. )
|
|
||||||
inter = 0.;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// [BB] Workaround for actors that use the same frame twice in a row.
|
|
||||||
// Most of the standard Doom monsters do this in their see state.
|
|
||||||
if ( (smf->flags & MDL_INTERPOLATEDOUBLEDFRAMES) )
|
|
||||||
{
|
|
||||||
const FState *prevState = curState - 1;
|
|
||||||
if ( (curState->sprite == prevState->sprite) && ( curState->Frame == prevState->Frame) )
|
|
||||||
{
|
|
||||||
inter /= 2.;
|
|
||||||
inter += 0.5;
|
|
||||||
}
|
|
||||||
if ( (curState->sprite == nextState->sprite) && ( curState->Frame == nextState->Frame) )
|
|
||||||
{
|
|
||||||
inter /= 2.;
|
|
||||||
nextState = nextState->GetNextState( );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( inter != 0.0 )
|
|
||||||
smfNext = gl_FindModelFrame(ti, nextState->sprite, nextState->Frame, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i=0; i<MAX_MODELS_PER_FRAME; i++)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
mdl->PushSpriteMDLFrame(smf, i);
|
|
||||||
|
|
||||||
if ( smfNext && smf->modelframes[i] != smfNext->modelframes[i] )
|
|
||||||
mdl->RenderFrame(tex, smf->modelframes[i], smfNext->modelframes[i], inter, translation);
|
|
||||||
else
|
|
||||||
mdl->RenderFrame(tex, smf->modelframes[i], smf->modelframes[i], 0.f, translation);
|
|
||||||
|
|
||||||
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gl_RenderModel(GLSprite * spr)
|
void gl_RenderModel(GLSprite * spr)
|
||||||
{
|
{
|
||||||
FSpriteModelFrame * smf = spr->modelframe;
|
FGLModelRenderer renderer;
|
||||||
|
renderer.RenderModel(spr->x, spr->y, spr->z, spr->modelframe, spr->actor);
|
||||||
|
|
||||||
// Setup transformation.
|
|
||||||
glDepthFunc(GL_LEQUAL);
|
|
||||||
gl_RenderState.EnableTexture(true);
|
|
||||||
// [BB] In case the model should be rendered translucent, do back face culling.
|
|
||||||
// This solves a few of the problems caused by the lack of depth sorting.
|
|
||||||
// [Nash] Don't do back face culling if explicitly specified in MODELDEF
|
|
||||||
// TO-DO: Implement proper depth sorting.
|
|
||||||
if (!(spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) && !(smf->flags & MDL_DONTCULLBACKFACES))
|
|
||||||
{
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
glFrontFace(GL_CW);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int translation = 0;
|
|
||||||
if ( !(smf->flags & MDL_IGNORETRANSLATION) )
|
|
||||||
translation = spr->actor->Translation;
|
|
||||||
|
|
||||||
|
|
||||||
// y scale for a sprite means height, i.e. z in the world!
|
|
||||||
float scaleFactorX = spr->actor->Scale.X * smf->xscale;
|
|
||||||
float scaleFactorY = spr->actor->Scale.X * smf->yscale;
|
|
||||||
float scaleFactorZ = spr->actor->Scale.Y * smf->zscale;
|
|
||||||
float pitch = 0;
|
|
||||||
float roll = 0;
|
|
||||||
float rotateOffset = 0;
|
|
||||||
float angle = spr->actor->Angles.Yaw.Degrees;
|
|
||||||
|
|
||||||
// [BB] Workaround for the missing pitch information.
|
|
||||||
if ( (smf->flags & MDL_PITCHFROMMOMENTUM) )
|
|
||||||
{
|
|
||||||
const double x = spr->actor->Vel.X;
|
|
||||||
const double y = spr->actor->Vel.Y;
|
|
||||||
const double z = spr->actor->Vel.Z;
|
|
||||||
|
|
||||||
if (spr->actor->Vel.LengthSquared() > EQUAL_EPSILON)
|
|
||||||
{
|
|
||||||
// [BB] Calculate the pitch using spherical coordinates.
|
|
||||||
if (z || x || y) pitch = float(atan(z / sqrt(x*x + y*y)) / M_PI * 180);
|
|
||||||
|
|
||||||
// Correcting pitch if model is moving backwards
|
|
||||||
if (fabs(x) > EQUAL_EPSILON || fabs(y) > EQUAL_EPSILON)
|
|
||||||
{
|
|
||||||
if ((x * cos(angle * M_PI / 180) + y * sin(angle * M_PI / 180)) / sqrt(x * x + y * y) < 0) pitch *= -1;
|
|
||||||
}
|
|
||||||
else pitch = fabs(pitch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( smf->flags & MDL_ROTATING )
|
|
||||||
{
|
|
||||||
const float time = smf->rotationSpeed*GetTimeFloat()/200.f;
|
|
||||||
rotateOffset = float((time - xs_FloorToInt(time)) *360.f );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Added MDL_USEACTORPITCH and MDL_USEACTORROLL flags processing.
|
|
||||||
// If both flags MDL_USEACTORPITCH and MDL_PITCHFROMMOMENTUM are set, the pitch sums up the actor pitch and the velocity vector pitch.
|
|
||||||
if (smf->flags & MDL_USEACTORPITCH)
|
|
||||||
{
|
|
||||||
double d = spr->actor->Angles.Pitch.Degrees;
|
|
||||||
if (smf->flags & MDL_BADROTATION) pitch += d;
|
|
||||||
else pitch -= d;
|
|
||||||
}
|
|
||||||
if(smf->flags & MDL_USEACTORROLL) roll += spr->actor->Angles.Roll.Degrees;
|
|
||||||
|
|
||||||
gl_RenderState.mModelMatrix.loadIdentity();
|
|
||||||
|
|
||||||
// Model space => World space
|
|
||||||
gl_RenderState.mModelMatrix.translate(spr->x, spr->z, spr->y );
|
|
||||||
|
|
||||||
// [Nash] take SpriteRotation into account
|
|
||||||
angle += spr->actor->SpriteRotation.Degrees;
|
|
||||||
|
|
||||||
if (spr->actor->renderflags & RF_INTERPOLATEANGLES)
|
|
||||||
{
|
|
||||||
// [Nash] use interpolated angles
|
|
||||||
DRotator Angles = spr->actor->InterpolatedAngles(r_viewpoint.TicFrac);
|
|
||||||
angle = Angles.Yaw.Degrees;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Applying model transformations:
|
|
||||||
// 1) Applying actor angle, pitch and roll to the model
|
|
||||||
gl_RenderState.mModelMatrix.rotate(-angle, 0, 1, 0);
|
|
||||||
gl_RenderState.mModelMatrix.rotate(pitch, 0, 0, 1);
|
|
||||||
gl_RenderState.mModelMatrix.rotate(-roll, 1, 0, 0);
|
|
||||||
|
|
||||||
// 2) Applying Doomsday like rotation of the weapon pickup models
|
|
||||||
// The rotation angle is based on the elapsed time.
|
|
||||||
|
|
||||||
if( smf->flags & MDL_ROTATING )
|
|
||||||
{
|
|
||||||
gl_RenderState.mModelMatrix.translate(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ);
|
|
||||||
gl_RenderState.mModelMatrix.rotate(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate);
|
|
||||||
gl_RenderState.mModelMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3) Scaling model.
|
|
||||||
gl_RenderState.mModelMatrix.scale(scaleFactorX, scaleFactorZ, scaleFactorY);
|
|
||||||
|
|
||||||
// 4) Aplying model offsets (model offsets do not depend on model scalings).
|
|
||||||
gl_RenderState.mModelMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale);
|
|
||||||
|
|
||||||
// 5) Applying model rotations.
|
|
||||||
gl_RenderState.mModelMatrix.rotate(-smf->angleoffset, 0, 1, 0);
|
|
||||||
gl_RenderState.mModelMatrix.rotate(smf->pitchoffset, 0, 0, 1);
|
|
||||||
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->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor() : 1.f) / level.info->pixelstretch;
|
|
||||||
gl_RenderState.mModelMatrix.scale(1, stretch, 1);
|
|
||||||
|
|
||||||
|
|
||||||
gl_RenderState.EnableModelMatrix(true);
|
|
||||||
gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, spr->actor->GetClass(), nullptr, translation );
|
|
||||||
gl_RenderState.EnableModelMatrix(false);
|
|
||||||
|
|
||||||
glDepthFunc(GL_LESS);
|
|
||||||
if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] ))
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
// gl_RenderHUDModel
|
// gl_RenderHUDModel
|
||||||
|
@ -1077,55 +1202,8 @@ void gl_RenderModel(GLSprite * spr)
|
||||||
|
|
||||||
void gl_RenderHUDModel(DPSprite *psp, float ofsX, float ofsY)
|
void gl_RenderHUDModel(DPSprite *psp, float ofsX, float ofsY)
|
||||||
{
|
{
|
||||||
AActor * playermo=players[consoleplayer].camera;
|
FGLModelRenderer renderer;
|
||||||
FSpriteModelFrame *smf = gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->GetState()->sprite, psp->GetState()->GetFrame(), false);
|
renderer.RenderHUDModel(psp, ofsX, ofsY);
|
||||||
|
|
||||||
// [BB] No model found for this sprite, so we can't render anything.
|
|
||||||
if ( smf == nullptr )
|
|
||||||
return;
|
|
||||||
|
|
||||||
glDepthFunc(GL_LEQUAL);
|
|
||||||
|
|
||||||
// [BB] In case the model should be rendered translucent, do back face culling.
|
|
||||||
// This solves a few of the problems caused by the lack of depth sorting.
|
|
||||||
// TO-DO: Implement proper depth sorting.
|
|
||||||
if (!( playermo->RenderStyle == LegacyRenderStyles[STYLE_Normal] ))
|
|
||||||
{
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
glFrontFace(GL_CCW);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The model position and orientation has to be drawn independently from the position of the player,
|
|
||||||
// but we need to position it correctly in the world for light to work properly.
|
|
||||||
VSMatrix objectToWorldMatrix;
|
|
||||||
gl_RenderState.mViewMatrix.inverseMatrix(objectToWorldMatrix);
|
|
||||||
|
|
||||||
// Scaling model (y scale for a sprite means height, i.e. z in the world!).
|
|
||||||
objectToWorldMatrix.scale(smf->xscale, smf->zscale, smf->yscale);
|
|
||||||
|
|
||||||
// Aplying model offsets (model offsets do not depend on model scalings).
|
|
||||||
objectToWorldMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale);
|
|
||||||
|
|
||||||
// [BB] Weapon bob, very similar to the normal Doom weapon bob.
|
|
||||||
objectToWorldMatrix.rotate(ofsX/4, 0, 1, 0);
|
|
||||||
objectToWorldMatrix.rotate((ofsY-WEAPONTOP)/-4., 1, 0, 0);
|
|
||||||
|
|
||||||
// [BB] For some reason the jDoom models need to be rotated.
|
|
||||||
objectToWorldMatrix.rotate(90.f, 0, 1, 0);
|
|
||||||
|
|
||||||
// Applying angleoffset, pitchoffset, rolloffset.
|
|
||||||
objectToWorldMatrix.rotate(-smf->angleoffset, 0, 1, 0);
|
|
||||||
objectToWorldMatrix.rotate(smf->pitchoffset, 0, 0, 1);
|
|
||||||
objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0);
|
|
||||||
|
|
||||||
gl_RenderState.mModelMatrix = objectToWorldMatrix;
|
|
||||||
gl_RenderState.EnableModelMatrix(true);
|
|
||||||
gl_RenderFrameModels( smf, psp->GetState(), psp->GetTics(), playermo->player->ReadyWeapon->GetClass(), nullptr, 0 );
|
|
||||||
gl_RenderState.EnableModelMatrix(false);
|
|
||||||
|
|
||||||
glDepthFunc(GL_LESS);
|
|
||||||
if (!( playermo->RenderStyle == LegacyRenderStyles[STYLE_Normal] ))
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
|
@ -45,6 +45,56 @@ FTextureID LoadSkin(const char * path, const char * fn);
|
||||||
// [JM] Necessary forward declaration
|
// [JM] Necessary forward declaration
|
||||||
typedef struct FSpriteModelFrame FSpriteModelFrame;
|
typedef struct FSpriteModelFrame FSpriteModelFrame;
|
||||||
|
|
||||||
|
class FModelRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~FModelRenderer() { }
|
||||||
|
|
||||||
|
void RenderModel(float x, float y, float z, FSpriteModelFrame *modelframe, AActor *actor);
|
||||||
|
void RenderHUDModel(DPSprite *psp, float ofsx, float ofsy);
|
||||||
|
|
||||||
|
virtual void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix) = 0;
|
||||||
|
virtual void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) = 0;
|
||||||
|
|
||||||
|
virtual IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) = 0;
|
||||||
|
|
||||||
|
virtual void SetVertexBuffer(IModelVertexBuffer *buffer) = 0;
|
||||||
|
virtual void ResetVertexBuffer() = 0;
|
||||||
|
|
||||||
|
virtual VSMatrix GetViewToWorldMatrix() = 0;
|
||||||
|
|
||||||
|
virtual void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix) = 0;
|
||||||
|
virtual void EndDrawHUDModel(AActor *actor) = 0;
|
||||||
|
|
||||||
|
virtual void SetInterpolation(double interpolation) = 0;
|
||||||
|
virtual void SetMaterial(FTexture *skin, int clampmode, int translation) = 0;
|
||||||
|
virtual void DrawArrays(int primitiveType, int start, int count) = 0;
|
||||||
|
virtual void DrawElements(int primitiveType, int numIndices, int elementType, size_t offset) = 0;
|
||||||
|
|
||||||
|
virtual float GetTimeFloat() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void RenderFrameModels(const FSpriteModelFrame *smf, const FState *curState, const int curTics, const PClass *ti, Matrix3x4 *normaltransform, int translation);
|
||||||
|
};
|
||||||
|
|
||||||
|
class FGLModelRenderer : public FModelRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix) override;
|
||||||
|
void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) override;
|
||||||
|
IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override;
|
||||||
|
void SetVertexBuffer(IModelVertexBuffer *buffer) override;
|
||||||
|
void ResetVertexBuffer() override;
|
||||||
|
VSMatrix GetViewToWorldMatrix() override;
|
||||||
|
void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix) override;
|
||||||
|
void EndDrawHUDModel(AActor *actor) override;
|
||||||
|
void SetInterpolation(double interpolation) override;
|
||||||
|
void SetMaterial(FTexture *skin, int clampmode, int translation) override;
|
||||||
|
void DrawArrays(int primitiveType, int start, int count) override;
|
||||||
|
void DrawElements(int primitiveType, int numIndices, int elementType, size_t offset) override;
|
||||||
|
float GetTimeFloat() override;
|
||||||
|
};
|
||||||
|
|
||||||
class FModel
|
class FModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -57,8 +107,8 @@ public:
|
||||||
|
|
||||||
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) = 0;
|
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) = 0;
|
||||||
virtual int FindFrame(const char * name) = 0;
|
virtual int FindFrame(const char * name) = 0;
|
||||||
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0) = 0;
|
virtual void RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame, int frame2, double inter, int translation=0) = 0;
|
||||||
virtual void BuildVertexBuffer() = 0;
|
virtual void BuildVertexBuffer(FModelRenderer *renderer) = 0;
|
||||||
virtual void AddSkins(uint8_t *hitlist) = 0;
|
virtual void AddSkins(uint8_t *hitlist) = 0;
|
||||||
void DestroyVertexBuffer()
|
void DestroyVertexBuffer()
|
||||||
{
|
{
|
||||||
|
@ -71,7 +121,7 @@ public:
|
||||||
int curMDLIndex;
|
int curMDLIndex;
|
||||||
void PushSpriteMDLFrame(const FSpriteModelFrame *smf, int index) { curSpriteMDLFrame = smf; curMDLIndex = index; };
|
void PushSpriteMDLFrame(const FSpriteModelFrame *smf, int index) { curSpriteMDLFrame = smf; curMDLIndex = index; };
|
||||||
|
|
||||||
FModelVertexBuffer *mVBuf;
|
IModelVertexBuffer *mVBuf;
|
||||||
FString mFileName;
|
FString mFileName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -183,12 +233,12 @@ public:
|
||||||
|
|
||||||
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length);
|
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length);
|
||||||
virtual int FindFrame(const char * name);
|
virtual int FindFrame(const char * name);
|
||||||
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
virtual void RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
||||||
virtual void LoadGeometry();
|
virtual void LoadGeometry();
|
||||||
virtual void AddSkins(uint8_t *hitlist);
|
virtual void AddSkins(uint8_t *hitlist);
|
||||||
|
|
||||||
void UnloadGeometry();
|
void UnloadGeometry();
|
||||||
void BuildVertexBuffer();
|
void BuildVertexBuffer(FModelRenderer *renderer);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -289,9 +339,9 @@ public:
|
||||||
|
|
||||||
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length);
|
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length);
|
||||||
virtual int FindFrame(const char * name);
|
virtual int FindFrame(const char * name);
|
||||||
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
virtual void RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
||||||
void LoadGeometry();
|
void LoadGeometry();
|
||||||
void BuildVertexBuffer();
|
void BuildVertexBuffer(FModelRenderer *renderer);
|
||||||
virtual void AddSkins(uint8_t *hitlist);
|
virtual void AddSkins(uint8_t *hitlist);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -344,10 +394,10 @@ public:
|
||||||
bool Load(const char * fn, int lumpnum, const char * buffer, int length);
|
bool Load(const char * fn, int lumpnum, const char * buffer, int length);
|
||||||
void Initialize();
|
void Initialize();
|
||||||
virtual int FindFrame(const char * name);
|
virtual int FindFrame(const char * name);
|
||||||
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
virtual void RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
||||||
virtual void AddSkins(uint8_t *hitlist);
|
virtual void AddSkins(uint8_t *hitlist);
|
||||||
FTextureID GetPaletteTexture() const { return mPalette; }
|
FTextureID GetPaletteTexture() const { return mPalette; }
|
||||||
void BuildVertexBuffer();
|
void BuildVertexBuffer(FModelRenderer *renderer);
|
||||||
float getAspectFactor();
|
float getAspectFactor();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,6 @@
|
||||||
#include "gl/shaders/gl_shader.h"
|
#include "gl/shaders/gl_shader.h"
|
||||||
#include "gl/data/gl_vertexbuffer.h"
|
#include "gl/data/gl_vertexbuffer.h"
|
||||||
|
|
||||||
extern int modellightindex;
|
|
||||||
|
|
||||||
static float avertexnormals[NUMVERTEXNORMALS][3] = {
|
static float avertexnormals[NUMVERTEXNORMALS][3] = {
|
||||||
#include "tab_anorms.h"
|
#include "tab_anorms.h"
|
||||||
};
|
};
|
||||||
|
@ -286,7 +284,7 @@ FDMDModel::~FDMDModel()
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
void FDMDModel::BuildVertexBuffer()
|
void FDMDModel::BuildVertexBuffer(FModelRenderer *renderer)
|
||||||
{
|
{
|
||||||
if (mVBuf == NULL)
|
if (mVBuf == NULL)
|
||||||
{
|
{
|
||||||
|
@ -295,7 +293,7 @@ void FDMDModel::BuildVertexBuffer()
|
||||||
int VertexBufferSize = info.numFrames * lodInfo[0].numTriangles * 3;
|
int VertexBufferSize = info.numFrames * lodInfo[0].numTriangles * 3;
|
||||||
unsigned int vindex = 0;
|
unsigned int vindex = 0;
|
||||||
|
|
||||||
mVBuf = new FModelVertexBuffer(false, info.numFrames == 1);
|
mVBuf = renderer->CreateVertexBuffer(false, info.numFrames == 1);
|
||||||
FModelVertex *vertptr = mVBuf->LockVertexBuffer(VertexBufferSize);
|
FModelVertex *vertptr = mVBuf->LockVertexBuffer(VertexBufferSize);
|
||||||
|
|
||||||
for (int i = 0; i < info.numFrames; i++)
|
for (int i = 0; i < info.numFrames; i++)
|
||||||
|
@ -364,7 +362,7 @@ int FDMDModel::FindFrame(const char * name)
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
void FDMDModel::RenderFrame(FTexture * skin, int frameno, int frameno2, double inter, int translation)
|
void FDMDModel::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frameno, int frameno2, double inter, int translation)
|
||||||
{
|
{
|
||||||
if (frameno >= info.numFrames || frameno2 >= info.numFrames) return;
|
if (frameno >= info.numFrames || frameno2 >= info.numFrames) return;
|
||||||
|
|
||||||
|
@ -375,16 +373,11 @@ void FDMDModel::RenderFrame(FTexture * skin, int frameno, int frameno2, double i
|
||||||
if (!skin) return;
|
if (!skin) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMaterial * tex = FMaterial::ValidateTexture(skin, false);
|
renderer->SetInterpolation(inter);
|
||||||
|
renderer->SetMaterial(skin, CLAMP_NONE, translation);
|
||||||
gl_RenderState.SetMaterial(tex, CLAMP_NONE, translation, -1, false);
|
mVBuf->SetupFrame(renderer, frames[frameno].vindex, frames[frameno2].vindex, lodInfo[0].numTriangles * 3);
|
||||||
gl_RenderState.SetInterpolationFactor((float)inter);
|
renderer->DrawArrays(GL_TRIANGLES, 0, lodInfo[0].numTriangles * 3);
|
||||||
|
renderer->SetInterpolation(0.f);
|
||||||
gl_RenderState.Apply();
|
|
||||||
if (modellightindex != -1) gl_RenderState.ApplyLightIndex(modellightindex);
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,6 @@
|
||||||
|
|
||||||
#define MAX_QPATH 64
|
#define MAX_QPATH 64
|
||||||
|
|
||||||
extern int modellightindex;
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
// decode the lat/lng normal to a 3 float normal
|
// decode the lat/lng normal to a 3 float normal
|
||||||
|
@ -240,7 +238,7 @@ void FMD3Model::LoadGeometry()
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
void FMD3Model::BuildVertexBuffer()
|
void FMD3Model::BuildVertexBuffer(FModelRenderer *renderer)
|
||||||
{
|
{
|
||||||
if (mVBuf == nullptr)
|
if (mVBuf == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -256,7 +254,7 @@ void FMD3Model::BuildVertexBuffer()
|
||||||
ibufsize += 3 * surf->numTriangles;
|
ibufsize += 3 * surf->numTriangles;
|
||||||
}
|
}
|
||||||
|
|
||||||
mVBuf = new FModelVertexBuffer(true, numFrames == 1);
|
mVBuf = renderer->CreateVertexBuffer(true, numFrames == 1);
|
||||||
FModelVertex *vertptr = mVBuf->LockVertexBuffer(vbufsize);
|
FModelVertex *vertptr = mVBuf->LockVertexBuffer(vbufsize);
|
||||||
unsigned int *indxptr = mVBuf->LockIndexBuffer(ibufsize);
|
unsigned int *indxptr = mVBuf->LockIndexBuffer(ibufsize);
|
||||||
|
|
||||||
|
@ -343,11 +341,11 @@ int FMD3Model::FindFrame(const char * name)
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
void FMD3Model::RenderFrame(FTexture * skin, int frameno, int frameno2, double inter, int translation)
|
void FMD3Model::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frameno, int frameno2, double inter, int translation)
|
||||||
{
|
{
|
||||||
if (frameno>=numFrames || frameno2>=numFrames) return;
|
if (frameno>=numFrames || frameno2>=numFrames) return;
|
||||||
|
|
||||||
gl_RenderState.SetInterpolationFactor((float)inter);
|
renderer->SetInterpolation(inter);
|
||||||
for(int i=0;i<numSurfaces;i++)
|
for(int i=0;i<numSurfaces;i++)
|
||||||
{
|
{
|
||||||
MD3Surface * surf = &surfaces[i];
|
MD3Surface * surf = &surfaces[i];
|
||||||
|
@ -369,16 +367,11 @@ void FMD3Model::RenderFrame(FTexture * skin, int frameno, int frameno2, double i
|
||||||
if (!surfaceSkin) return;
|
if (!surfaceSkin) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMaterial * tex = FMaterial::ValidateTexture(surfaceSkin, false);
|
renderer->SetMaterial(surfaceSkin, CLAMP_NONE, translation);
|
||||||
|
mVBuf->SetupFrame(renderer, surf->vindex + frameno * surf->numVertices, surf->vindex + frameno2 * surf->numVertices, surf->numVertices);
|
||||||
gl_RenderState.SetMaterial(tex, CLAMP_NONE, translation, -1, false);
|
renderer->DrawElements(GL_TRIANGLES, surf->numTriangles * 3, GL_UNSIGNED_INT, surf->iindex * sizeof(unsigned int));
|
||||||
|
|
||||||
gl_RenderState.Apply();
|
|
||||||
if (modellightindex != -1) gl_RenderState.ApplyLightIndex(modellightindex);
|
|
||||||
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);
|
renderer->SetInterpolation(0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
|
@ -50,8 +50,6 @@
|
||||||
#include "gl/utility/gl_convert.h"
|
#include "gl/utility/gl_convert.h"
|
||||||
#include "gl/renderer/gl_renderstate.h"
|
#include "gl/renderer/gl_renderstate.h"
|
||||||
|
|
||||||
extern int modellightindex;
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
// Creates a 16x16 texture from the palette so that we can
|
// Creates a 16x16 texture from the palette so that we can
|
||||||
|
@ -364,13 +362,13 @@ void FVoxelModel::Initialize()
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
void FVoxelModel::BuildVertexBuffer()
|
void FVoxelModel::BuildVertexBuffer(FModelRenderer *renderer)
|
||||||
{
|
{
|
||||||
if (mVBuf == NULL)
|
if (mVBuf == NULL)
|
||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
|
|
||||||
mVBuf = new FModelVertexBuffer(true, true);
|
mVBuf = renderer->CreateVertexBuffer(true, true);
|
||||||
FModelVertex *vertptr = mVBuf->LockVertexBuffer(mVertices.Size());
|
FModelVertex *vertptr = mVBuf->LockVertexBuffer(mVertices.Size());
|
||||||
unsigned int *indxptr = mVBuf->LockIndexBuffer(mIndices.Size());
|
unsigned int *indxptr = mVBuf->LockIndexBuffer(mIndices.Size());
|
||||||
|
|
||||||
|
@ -440,14 +438,10 @@ float FVoxelModel::getAspectFactor()
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
void FVoxelModel::RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation)
|
void FVoxelModel::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame, int frame2, double inter, int translation)
|
||||||
{
|
{
|
||||||
FMaterial * tex = FMaterial::ValidateTexture(skin, false);
|
renderer->SetMaterial(skin, CLAMP_NOFILTER, translation);
|
||||||
gl_RenderState.SetMaterial(tex, CLAMP_NOFILTER, translation, -1, false);
|
mVBuf->SetupFrame(renderer, 0, 0, 0);
|
||||||
|
renderer->DrawElements(GL_TRIANGLES, mNumIndices, GL_UNSIGNED_INT, 0);
|
||||||
gl_RenderState.Apply();
|
|
||||||
if (modellightindex != -1) gl_RenderState.ApplyLightIndex(modellightindex);
|
|
||||||
mVBuf->SetupFrame(0, 0, 0);
|
|
||||||
glDrawElements(GL_TRIANGLES, mNumIndices, GL_UNSIGNED_INT, (void*)(intptr_t)0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -890,10 +890,11 @@ void gl_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitl
|
||||||
}
|
}
|
||||||
|
|
||||||
// cache all used models
|
// cache all used models
|
||||||
|
FGLModelRenderer renderer;
|
||||||
for (unsigned i = 0; i < Models.Size(); i++)
|
for (unsigned i = 0; i < Models.Size(); i++)
|
||||||
{
|
{
|
||||||
if (modellist[i])
|
if (modellist[i])
|
||||||
Models[i]->BuildVertexBuffer();
|
Models[i]->BuildVertexBuffer(&renderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue