Merge ../gzdoom

This commit is contained in:
Rachael Alexanderson 2017-11-23 22:39:52 -05:00
commit f823c6ea3b
21 changed files with 884 additions and 320 deletions

View file

@ -756,6 +756,7 @@ set( POLYRENDER_SOURCES
polyrenderer/scene/poly_wall.cpp
polyrenderer/scene/poly_wallsprite.cpp
polyrenderer/scene/poly_sprite.cpp
polyrenderer/scene/poly_model.cpp
polyrenderer/scene/poly_sky.cpp
polyrenderer/scene/poly_light.cpp
polyrenderer/drawers/poly_buffer.cpp

View file

@ -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];
FModelVertex *vbo_ptr;
@ -305,14 +320,14 @@ public:
FModelVertexBuffer(bool needindex, bool singleframe);
~FModelVertexBuffer();
FModelVertex *LockVertexBuffer(unsigned int size);
void UnlockVertexBuffer();
FModelVertex *LockVertexBuffer(unsigned int size) override;
void UnlockVertexBuffer() override;
unsigned int *LockIndexBuffer(unsigned int size);
void UnlockIndexBuffer();
unsigned int *LockIndexBuffer(unsigned int size) override;
void UnlockIndexBuffer() override;
unsigned int SetupFrame(unsigned int frame1, unsigned int frame2, unsigned int size);
void BindVBO();
void SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) override;
void BindVBO() override;
};
#define VMO ((FModelVertex*)NULL)

View file

@ -53,11 +53,6 @@
#include "gl/renderer/gl_renderstate.h"
#include "gl/shaders/gl_shader.h"
static inline double GetTimeFloat()
{
return (double)screen->FrameTime * (double)TICRATE / 1000.;
}
CVAR(Bool, gl_interpolate_model_frames, true, CVAR_ARCHIVE)
CVAR(Bool, gl_light_models, true, CVAR_ARCHIVE)
EXTERN_CVAR(Int, gl_fogmode)
@ -67,6 +62,332 @@ extern TDeletingArray<FVoxelDef *> VoxelDefs;
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;
double 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 double time = smf->rotationSpeed*GetTimeFloat() / 200.;
rotateOffset = double((time - xs_FloorToInt(time)) *360.);
}
// 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))
{
double 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);
}
double FGLModelRenderer::GetTimeFloat()
{
return (float)I_msTime() * (float)TICRATE / 1000.0f;
}
/////////////////////////////////////////////////////////////////////////////
void gl_LoadModels()
{
@ -239,7 +560,7 @@ void FModelVertexBuffer::UnlockIndexBuffer()
//===========================================================================
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);
if (vbo_id > 0)
@ -277,7 +598,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;
}
}
return frame1;
}
//===========================================================================
@ -863,207 +1183,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) )
{
double 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)
{
FSpriteModelFrame * smf = spr->modelframe;
// 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 double time = smf->rotationSpeed*GetTimeFloat()/200.;
rotateOffset = double((time - xs_FloorToInt(time)) *360. );
}
// 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);
FGLModelRenderer renderer;
renderer.RenderModel(spr->x, spr->y, spr->z, spr->modelframe, spr->actor);
}
//===========================================================================
//
// gl_RenderHUDModel
@ -1072,55 +1197,8 @@ void gl_RenderModel(GLSprite * spr)
void gl_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;
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);
FGLModelRenderer renderer;
renderer.RenderHUDModel(psp, ofsX, ofsY);
}
//===========================================================================

View file

@ -45,6 +45,56 @@ FTextureID LoadSkin(const char * path, const char * fn);
// [JM] Necessary forward declaration
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 double 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;
double GetTimeFloat() override;
};
class FModel
{
public:
@ -57,8 +107,8 @@ public:
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) = 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 BuildVertexBuffer() = 0;
virtual void RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame, int frame2, double inter, int translation=0) = 0;
virtual void BuildVertexBuffer(FModelRenderer *renderer) = 0;
virtual void AddSkins(uint8_t *hitlist) = 0;
void DestroyVertexBuffer()
{
@ -71,7 +121,7 @@ public:
int curMDLIndex;
void PushSpriteMDLFrame(const FSpriteModelFrame *smf, int index) { curSpriteMDLFrame = smf; curMDLIndex = index; };
FModelVertexBuffer *mVBuf;
IModelVertexBuffer *mVBuf;
FString mFileName;
};
@ -183,12 +233,12 @@ public:
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length);
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 AddSkins(uint8_t *hitlist);
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 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 BuildVertexBuffer();
void BuildVertexBuffer(FModelRenderer *renderer);
virtual void AddSkins(uint8_t *hitlist);
};
@ -344,10 +394,10 @@ public:
bool Load(const char * fn, int lumpnum, const char * buffer, int length);
void Initialize();
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);
FTextureID GetPaletteTexture() const { return mPalette; }
void BuildVertexBuffer();
void BuildVertexBuffer(FModelRenderer *renderer);
float getAspectFactor();
};

View file

@ -40,8 +40,6 @@
#include "gl/shaders/gl_shader.h"
#include "gl/data/gl_vertexbuffer.h"
extern int modellightindex;
static float avertexnormals[NUMVERTEXNORMALS][3] = {
#include "tab_anorms.h"
};
@ -286,7 +284,7 @@ FDMDModel::~FDMDModel()
//
//===========================================================================
void FDMDModel::BuildVertexBuffer()
void FDMDModel::BuildVertexBuffer(FModelRenderer *renderer)
{
if (mVBuf == NULL)
{
@ -295,7 +293,7 @@ void FDMDModel::BuildVertexBuffer()
int VertexBufferSize = info.numFrames * lodInfo[0].numTriangles * 3;
unsigned int vindex = 0;
mVBuf = new FModelVertexBuffer(false, info.numFrames == 1);
mVBuf = renderer->CreateVertexBuffer(false, info.numFrames == 1);
FModelVertex *vertptr = mVBuf->LockVertexBuffer(VertexBufferSize);
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;
@ -375,16 +373,11 @@ void FDMDModel::RenderFrame(FTexture * skin, int frameno, int frameno2, double i
if (!skin) return;
}
FMaterial * tex = FMaterial::ValidateTexture(skin, false);
gl_RenderState.SetMaterial(tex, CLAMP_NONE, translation, -1, false);
gl_RenderState.SetInterpolationFactor((float)inter);
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);
renderer->SetInterpolation(inter);
renderer->SetMaterial(skin, CLAMP_NONE, translation);
mVBuf->SetupFrame(renderer, frames[frameno].vindex, frames[frameno2].vindex, lodInfo[0].numTriangles * 3);
renderer->DrawArrays(GL_TRIANGLES, 0, lodInfo[0].numTriangles * 3);
renderer->SetInterpolation(0.f);
}

View file

@ -35,8 +35,6 @@
#define MAX_QPATH 64
extern int modellightindex;
//===========================================================================
//
// 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)
{
@ -256,7 +254,7 @@ void FMD3Model::BuildVertexBuffer()
ibufsize += 3 * surf->numTriangles;
}
mVBuf = new FModelVertexBuffer(true, numFrames == 1);
mVBuf = renderer->CreateVertexBuffer(true, numFrames == 1);
FModelVertex *vertptr = mVBuf->LockVertexBuffer(vbufsize);
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;
gl_RenderState.SetInterpolationFactor((float)inter);
renderer->SetInterpolation(inter);
for(int i=0;i<numSurfaces;i++)
{
MD3Surface * surf = &surfaces[i];
@ -369,16 +367,11 @@ void FMD3Model::RenderFrame(FTexture * skin, int frameno, int frameno2, double i
if (!surfaceSkin) return;
}
FMaterial * tex = FMaterial::ValidateTexture(surfaceSkin, false);
gl_RenderState.SetMaterial(tex, CLAMP_NONE, translation, -1, false);
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)));
renderer->SetMaterial(surfaceSkin, CLAMP_NONE, translation);
mVBuf->SetupFrame(renderer, surf->vindex + frameno * surf->numVertices, surf->vindex + frameno2 * surf->numVertices, surf->numVertices);
renderer->DrawElements(GL_TRIANGLES, surf->numTriangles * 3, GL_UNSIGNED_INT, surf->iindex * sizeof(unsigned int));
}
gl_RenderState.SetInterpolationFactor(0.f);
renderer->SetInterpolation(0.f);
}
//===========================================================================

View file

@ -50,8 +50,6 @@
#include "gl/utility/gl_convert.h"
#include "gl/renderer/gl_renderstate.h"
extern int modellightindex;
//===========================================================================
//
// 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)
{
Initialize();
mVBuf = new FModelVertexBuffer(true, true);
mVBuf = renderer->CreateVertexBuffer(true, true);
FModelVertex *vertptr = mVBuf->LockVertexBuffer(mVertices.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);
gl_RenderState.SetMaterial(tex, CLAMP_NOFILTER, translation, -1, false);
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);
renderer->SetMaterial(skin, CLAMP_NOFILTER, translation);
mVBuf->SetupFrame(renderer, 0, 0, 0);
renderer->DrawElements(GL_TRIANGLES, mNumIndices, GL_UNSIGNED_INT, 0);
}

View file

@ -890,10 +890,11 @@ void gl_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitl
}
// cache all used models
FGLModelRenderer renderer;
for (unsigned i = 0; i < Models.Size(); i++)
{
if (modellist[i])
Models[i]->BuildVertexBuffer();
Models[i]->BuildVertexBuffer(&renderer);
}
}

View file

@ -3,8 +3,8 @@
** Implements the timer
**
**---------------------------------------------------------------------------
** Copyright 1998-2916 Randy Heit
** Copyright 2917 Magnus Norddahl
** Copyright 1998-2016 Randy Heit
** Copyright 2017 Magnus Norddahl
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@ -63,7 +63,7 @@ CUSTOM_CVAR(Float, i_timescale, 1.0f, CVAR_NOINITCALL)
else
{
I_FreezeTime(true);
float clampValue = (self < 0.05) ? 0.05 : self;
float clampValue = (self < 0.05) ? 0.05f : self;
if (self != clampValue)
self = clampValue;
TimeScale = self;
@ -74,7 +74,7 @@ CUSTOM_CVAR(Float, i_timescale, 1.0f, CVAR_NOINITCALL)
static uint64_t GetClockTimeNS()
{
using namespace std::chrono;
return (uint64_t)duration_cast<nanoseconds>(steady_clock::now().time_since_epoch()).count() * TimeScale;
return (uint64_t)((duration_cast<nanoseconds>(steady_clock::now().time_since_epoch()).count()) * TimeScale);
}
static uint64_t MSToNS(unsigned int ms)

View file

@ -130,6 +130,16 @@ void PolyDrawArgs::DrawArray(PolyRenderThread *thread, const TriVertex *vertices
{
mVertices = vertices;
mVertexCount = vcount;
mElements = nullptr;
mDrawMode = mode;
thread->DrawQueue->Push<DrawPolyTrianglesCommand>(*this, PolyTriangleDrawer::is_mirror());
}
void PolyDrawArgs::DrawElements(PolyRenderThread *thread, const TriVertex *vertices, const unsigned int *elements, int count, PolyDrawMode mode)
{
mVertices = vertices;
mElements = elements;
mVertexCount = count;
mDrawMode = mode;
thread->DrawQueue->Push<DrawPolyTrianglesCommand>(*this, PolyTriangleDrawer::is_mirror());
}

View file

@ -83,12 +83,14 @@ public:
void SetLights(PolyLight *lights, int numLights) { mLights = lights; mNumLights = numLights; }
void SetDynLightColor(uint32_t color) { mDynLightColor = color; }
void DrawArray(PolyRenderThread *thread, const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles);
void DrawElements(PolyRenderThread *thread, const TriVertex *vertices, const unsigned int *elements, int count, PolyDrawMode mode = PolyDrawMode::Triangles);
const TriMatrix *ObjectToClip() const { return mObjectToClip; }
const PolyClipPlane &ClipPlane(int index) const { return mClipPlane[index]; }
const TriVertex *Vertices() const { return mVertices; }
int VertexCount() const { return mVertexCount; }
const unsigned int *Elements() const { return mElements; }
PolyDrawMode DrawMode() const { return mDrawMode; }
bool FaceCullCCW() const { return mFaceCullCCW; }
@ -139,6 +141,7 @@ private:
const TriMatrix *mObjectToClip = nullptr;
const TriVertex *mVertices = nullptr;
int mVertexCount = 0;
const unsigned int *mElements = nullptr;
PolyDrawMode mDrawMode = PolyDrawMode::Triangles;
bool mFaceCullCCW = false;
bool mDepthTest = false;

View file

@ -84,6 +84,64 @@ bool PolyTriangleDrawer::is_mirror()
return mirror;
}
void PolyTriangleDrawer::draw_elements(const PolyDrawArgs &drawargs, WorkerThreadData *thread)
{
if (drawargs.VertexCount() < 3)
return;
TriDrawTriangleArgs args;
args.dest = dest;
args.pitch = dest_pitch;
args.clipright = dest_width;
args.clipbottom = dest_height;
args.uniforms = &drawargs;
args.destBgra = dest_bgra;
args.stencilPitch = PolyStencilBuffer::Instance()->BlockWidth();
args.stencilValues = PolyStencilBuffer::Instance()->Values();
args.stencilMasks = PolyStencilBuffer::Instance()->Masks();
args.zbuffer = PolyZBuffer::Instance()->Values();
bool ccw = drawargs.FaceCullCCW();
const TriVertex *vinput = drawargs.Vertices();
const unsigned int *elements = drawargs.Elements();
int vcount = drawargs.VertexCount();
ShadedTriVertex vert[3];
if (drawargs.DrawMode() == PolyDrawMode::Triangles)
{
for (int i = 0; i < vcount / 3; i++)
{
for (int j = 0; j < 3; j++)
vert[j] = shade_vertex(drawargs, vinput[*(elements++)]);
draw_shaded_triangle(vert, ccw, &args, thread);
}
}
else if (drawargs.DrawMode() == PolyDrawMode::TriangleFan)
{
vert[0] = shade_vertex(drawargs, vinput[*(elements++)]);
vert[1] = shade_vertex(drawargs, vinput[*(elements++)]);
for (int i = 2; i < vcount; i++)
{
vert[2] = shade_vertex(drawargs, vinput[*(elements++)]);
draw_shaded_triangle(vert, ccw, &args, thread);
vert[1] = vert[2];
}
}
else // TriangleDrawMode::TriangleStrip
{
vert[0] = shade_vertex(drawargs, vinput[*(elements++)]);
vert[1] = shade_vertex(drawargs, vinput[*(elements++)]);
for (int i = 2; i < vcount; i++)
{
vert[2] = shade_vertex(drawargs, vinput[*(elements++)]);
draw_shaded_triangle(vert, ccw, &args, thread);
vert[0] = vert[1];
vert[1] = vert[2];
ccw = !ccw;
}
}
}
void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, WorkerThreadData *thread)
{
if (drawargs.VertexCount() < 3)
@ -472,7 +530,10 @@ void DrawPolyTrianglesCommand::Execute(DrawerThread *thread)
thread_data.core = thread->core;
thread_data.num_cores = thread->num_cores;
PolyTriangleDrawer::draw_arrays(args, &thread_data);
if (!args.Elements())
PolyTriangleDrawer::draw_arrays(args, &thread_data);
else
PolyTriangleDrawer::draw_elements(args, &thread_data);
}
/////////////////////////////////////////////////////////////////////////////

View file

@ -40,6 +40,7 @@ public:
private:
static ShadedTriVertex shade_vertex(const PolyDrawArgs &drawargs, const TriVertex &v);
static void draw_elements(const PolyDrawArgs &args, WorkerThreadData *thread);
static void draw_arrays(const PolyDrawArgs &args, WorkerThreadData *thread);
static void draw_shaded_triangle(const ShadedTriVertex *vertices, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread);
static bool is_degenerate(const ShadedTriVertex *vertices);

View file

@ -14,6 +14,7 @@
#include "scene/poly_scene.cpp"
#include "scene/poly_sky.cpp"
#include "scene/poly_sprite.cpp"
#include "scene/poly_model.cpp"
#include "scene/poly_wall.cpp"
#include "scene/poly_wallsprite.cpp"
#include "scene/poly_light.cpp"

View file

@ -208,12 +208,12 @@ void PolyRenderer::SetupPerspectiveMatrix()
float fovratio = (Viewwindow.WidescreenRatio >= 1.3f) ? 1.333333f : ratio;
float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(Viewpoint.FieldOfView.Radians() / 2) / fovratio)).Degrees);
TriMatrix worldToView =
WorldToView =
TriMatrix::rotate(adjustedPitch, 1.0f, 0.0f, 0.0f) *
TriMatrix::rotate(adjustedViewAngle, 0.0f, -1.0f, 0.0f) *
TriMatrix::scale(1.0f, level.info->pixelstretch, 1.0f) *
TriMatrix::swapYZ() *
TriMatrix::translate((float)-Viewpoint.Pos.X, (float)-Viewpoint.Pos.Y, (float)-Viewpoint.Pos.Z);
WorldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
WorldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * WorldToView;
}

View file

@ -61,13 +61,15 @@ public:
FRenderViewpoint Viewpoint;
PolyLightVisibility Light;
TriMatrix WorldToView;
TriMatrix WorldToClip;
private:
void RenderActorView(AActor *actor, bool dontmaplines);
void ClearBuffers();
void SetSceneViewport();
void SetupPerspectiveMatrix();
TriMatrix WorldToClip;
RenderPolyScene MainPortal;
PolySkyDome Skydome;
RenderPolyPlayerSprites PlayerSprites;

View file

@ -0,0 +1,255 @@
/*
** Polygon Doom software renderer
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "sbar.h"
#include "r_data/r_translate.h"
#include "poly_model.h"
#include "polyrenderer/poly_renderer.h"
#include "polyrenderer/scene/poly_light.h"
#include "polyrenderer/poly_renderthread.h"
#include "r_data/r_vanillatrans.h"
#include "actorinlines.h"
void PolyRenderModel(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor)
{
PolyModelRenderer renderer(thread, worldToClip, clipPlane, stencilValue);
renderer.RenderModel(x, y, z, smf, actor);
}
void PolyRenderHUDModel(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue, DPSprite *psp, float ofsx, float ofsy)
{
PolyModelRenderer renderer(thread, worldToClip, clipPlane, stencilValue);
renderer.RenderHUDModel(psp, ofsx, ofsy);
}
/////////////////////////////////////////////////////////////////////////////
void PolyModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix)
{
ModelActor = actor;
const_cast<VSMatrix &>(objectToWorldMatrix).copy(ObjectToWorld.matrix);
}
void PolyModelRenderer::EndDrawModel(AActor *actor, FSpriteModelFrame *smf)
{
ModelActor = nullptr;
}
IModelVertexBuffer *PolyModelRenderer::CreateVertexBuffer(bool needindex, bool singleframe)
{
return new PolyModelVertexBuffer(needindex, singleframe);
}
void PolyModelRenderer::SetVertexBuffer(IModelVertexBuffer *buffer)
{
}
void PolyModelRenderer::ResetVertexBuffer()
{
}
VSMatrix PolyModelRenderer::GetViewToWorldMatrix()
{
TriMatrix swapYZ = TriMatrix::null();
swapYZ.matrix[0 + 0 * 4] = 1.0f;
swapYZ.matrix[1 + 2 * 4] = 1.0f;
swapYZ.matrix[2 + 1 * 4] = 1.0f;
swapYZ.matrix[3 + 3 * 4] = 1.0f;
VSMatrix worldToView;
worldToView.loadMatrix((PolyRenderer::Instance()->WorldToView * swapYZ).matrix);
VSMatrix objectToWorld;
worldToView.inverseMatrix(objectToWorld);
return objectToWorld;
}
void PolyModelRenderer::BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix)
{
ModelActor = actor;
const_cast<VSMatrix &>(objectToWorldMatrix).copy(ObjectToWorld.matrix);
}
void PolyModelRenderer::EndDrawHUDModel(AActor *actor)
{
ModelActor = nullptr;
}
void PolyModelRenderer::SetInterpolation(double interpolation)
{
InterpolationFactor = (float)interpolation;
}
void PolyModelRenderer::SetMaterial(FTexture *skin, int clampmode, int translation)
{
SkinTexture = skin;
}
void PolyModelRenderer::DrawArrays(int primitiveType, int start, int count)
{
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
bool foggy = false;
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
sector_t *sector = ModelActor->Sector;
bool fullbrightSprite = ((ModelActor->renderflags & RF_FULLBRIGHT) || (ModelActor->flags5 & MF5_BRIGHT));
int lightlevel = fullbrightSprite ? 255 : ModelActor->Sector->lightlevel + actualextralight;
TriMatrix swapYZ = TriMatrix::null();
swapYZ.matrix[0 + 0 * 4] = 1.0f;
swapYZ.matrix[1 + 2 * 4] = 1.0f;
swapYZ.matrix[2 + 1 * 4] = 1.0f;
swapYZ.matrix[3 + 3 * 4] = 1.0f;
TriMatrix *transform = Thread->FrameMemory->NewObject<TriMatrix>();
*transform = WorldToClip * swapYZ * ObjectToWorld;
PolyDrawArgs args;
args.SetLight(GetColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], true), lightlevel, PolyRenderer::Instance()->Light.SpriteGlobVis(foggy), fullbrightSprite);
args.SetTransform(transform);
args.SetFaceCullCCW(true);
args.SetStencilTestValue(StencilValue);
args.SetClipPlane(0, PolyClipPlane());
args.SetStyle(TriBlendMode::TextureOpaque);
args.SetTexture(SkinTexture);
args.SetDepthTest(true);
args.SetWriteDepth(true);
args.SetWriteStencil(false);
args.DrawArray(Thread, VertexBuffer + start, count);
}
void PolyModelRenderer::DrawElements(int primitiveType, int numIndices, int elementType, size_t offset)
{
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
bool foggy = false;
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
sector_t *sector = ModelActor->Sector;
bool fullbrightSprite = ((ModelActor->renderflags & RF_FULLBRIGHT) || (ModelActor->flags5 & MF5_BRIGHT));
int lightlevel = fullbrightSprite ? 255 : ModelActor->Sector->lightlevel + actualextralight;
TriMatrix swapYZ = TriMatrix::null();
swapYZ.matrix[0 + 0 * 4] = 1.0f;
swapYZ.matrix[1 + 2 * 4] = 1.0f;
swapYZ.matrix[2 + 1 * 4] = 1.0f;
swapYZ.matrix[3 + 3 * 4] = 1.0f;
TriMatrix *transform = Thread->FrameMemory->NewObject<TriMatrix>();
*transform = WorldToClip * swapYZ * ObjectToWorld;
PolyDrawArgs args;
args.SetLight(GetColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], true), lightlevel, PolyRenderer::Instance()->Light.SpriteGlobVis(foggy), fullbrightSprite);
args.SetTransform(transform);
args.SetFaceCullCCW(true);
args.SetStencilTestValue(StencilValue);
args.SetClipPlane(0, PolyClipPlane());
args.SetStyle(TriBlendMode::TextureOpaque);
args.SetTexture(SkinTexture);
args.SetDepthTest(true);
args.SetWriteDepth(true);
args.SetWriteStencil(false);
args.DrawElements(Thread, VertexBuffer, IndexBuffer + offset / sizeof(unsigned int), numIndices);
}
double PolyModelRenderer::GetTimeFloat()
{
return 0.0f; // (float)gl_frameMS * (float)TICRATE / 1000.0f;
}
/////////////////////////////////////////////////////////////////////////////
PolyModelVertexBuffer::PolyModelVertexBuffer(bool needindex, bool singleframe)
{
}
PolyModelVertexBuffer::~PolyModelVertexBuffer()
{
}
FModelVertex *PolyModelVertexBuffer::LockVertexBuffer(unsigned int size)
{
mVertexBuffer.Resize(size);
return &mVertexBuffer[0];
}
void PolyModelVertexBuffer::UnlockVertexBuffer()
{
}
unsigned int *PolyModelVertexBuffer::LockIndexBuffer(unsigned int size)
{
mIndexBuffer.Resize(size);
return &mIndexBuffer[0];
}
void PolyModelVertexBuffer::UnlockIndexBuffer()
{
}
void PolyModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size)
{
PolyModelRenderer *polyrenderer = (PolyModelRenderer *)renderer;
if (true)//if (frame1 == frame2 || size == 0 || polyrenderer->InterpolationFactor == 0.f)
{
TriVertex *vertices = polyrenderer->Thread->FrameMemory->AllocMemory<TriVertex>(size);
for (unsigned int i = 0; i < size; i++)
{
vertices[i] =
{
mVertexBuffer[frame1 + i].x,
mVertexBuffer[frame1 + i].y,
mVertexBuffer[frame1 + i].z,
1.0f,
mVertexBuffer[frame1 + i].u,
mVertexBuffer[frame1 + i].v
};
}
polyrenderer->VertexBuffer = vertices;
polyrenderer->IndexBuffer = &mIndexBuffer[0];
}
else
{
TriVertex *vertices = polyrenderer->Thread->FrameMemory->AllocMemory<TriVertex>(size);
float frac = polyrenderer->InterpolationFactor;
for (unsigned int i = 0; i < size; i++)
{
vertices[i].x = mVertexBuffer[frame1 + i].x * (1.0f - frac) + mVertexBuffer[frame2 + i].x * frac;
vertices[i].y = mVertexBuffer[frame1 + i].y * (1.0f - frac) + mVertexBuffer[frame2 + i].y * frac;
vertices[i].z = mVertexBuffer[frame1 + i].z * (1.0f - frac) + mVertexBuffer[frame2 + i].z * frac;
vertices[i].w = 1.0f;
vertices[i].u = mVertexBuffer[frame1 + i].u;
vertices[i].v = mVertexBuffer[frame1 + i].v;
}
polyrenderer->VertexBuffer = vertices;
polyrenderer->IndexBuffer = &mIndexBuffer[0];
}
}

View file

@ -0,0 +1,82 @@
/*
** Polygon Doom software renderer
** Copyright (c) 2016 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#pragma once
#include "polyrenderer/drawers/poly_triangle.h"
#include "gl/data/gl_matrix.h"
#include "gl/models/gl_models.h"
void PolyRenderModel(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor);
void PolyRenderHUDModel(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue, DPSprite *psp, float ofsx, float ofsy);
class PolyModelRenderer : public FModelRenderer
{
public:
PolyModelRenderer(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue) : Thread(thread), WorldToClip(worldToClip), ClipPlane(clipPlane), StencilValue(stencilValue) { }
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;
double GetTimeFloat() override;
PolyRenderThread *Thread = nullptr;
const TriMatrix &WorldToClip;
const PolyClipPlane &ClipPlane;
uint32_t StencilValue = 0;
AActor *ModelActor = nullptr;
TriMatrix ObjectToWorld;
FTexture *SkinTexture = nullptr;
unsigned int *IndexBuffer = nullptr;
TriVertex *VertexBuffer = nullptr;
float InterpolationFactor = 0.0;
};
class PolyModelVertexBuffer : public IModelVertexBuffer
{
public:
PolyModelVertexBuffer(bool needindex, bool singleframe);
~PolyModelVertexBuffer();
FModelVertex *LockVertexBuffer(unsigned int size) override;
void UnlockVertexBuffer() override;
unsigned int *LockIndexBuffer(unsigned int size) override;
void UnlockIndexBuffer() override;
void SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) override;
private:
int mIndexFrame[2];
TArray<FModelVertex> mVertexBuffer;
TArray<unsigned int> mIndexBuffer;
};

View file

@ -29,6 +29,7 @@
#include "polyrenderer/poly_renderer.h"
#include "d_player.h"
#include "polyrenderer/scene/poly_light.h"
#include "polyrenderer/scene/poly_model.h"
EXTERN_CVAR(Bool, r_drawplayersprites)
EXTERN_CVAR(Bool, r_deathcamera)
@ -39,6 +40,10 @@ void RenderPolyPlayerSprites::Render(PolyRenderThread *thread)
{
// This code cannot be moved directly to RenderRemainingSprites because the engine
// draws the canvas textures between this call and the final call to RenderRemainingSprites..
//
// We also can't move it because the model render code relies on it
renderHUDModel = gl_IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player);
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
@ -244,6 +249,12 @@ void RenderPolyPlayerSprites::RenderSprite(PolyRenderThread *thread, DPSprite *p
sy += wy;
}
if (renderHUDModel)
{
PolyRenderHUDModel(thread, PolyRenderer::Instance()->WorldToClip, PolyClipPlane(), 1, pspr, (float)sx, (float)sy);
return;
}
double yaspectMul = 1.2 * ((double)SCREENHEIGHT / SCREENWIDTH) * r_viewwindow.WidescreenRatio;
double pspritexscale = viewwindow.centerxwide / 160.0;

View file

@ -102,4 +102,5 @@ private:
TArray<PolyHWAccelPlayerSprite> AcceleratedSprites;
sector_t tempsec;
bool renderHUDModel = false;
};

View file

@ -29,6 +29,7 @@
#include "polyrenderer/poly_renderer.h"
#include "polyrenderer/scene/poly_light.h"
#include "polyrenderer/poly_renderthread.h"
#include "polyrenderer/scene/poly_model.h"
#include "r_data/r_vanillatrans.h"
#include "actorinlines.h"
@ -73,6 +74,17 @@ bool RenderPolySprite::GetLine(AActor *thing, DVector2 &left, DVector2 &right)
void RenderPolySprite::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t stencilValue, float t1, float t2)
{
int spritenum = thing->sprite;
bool isPicnumOverride = thing->picnum.isValid();
FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : gl_FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
if (modelframe)
{
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
PolyRenderModel(thread, worldToClip, clipPlane, stencilValue, (float)pos.X, (float)pos.Y, (float)pos.Z, modelframe, thing);
return;
}
DVector2 line[2];
if (!GetLine(thing, line[0], line[1]))
return;