mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-01-18 23:52:02 +00:00
Merge remote-tracking branch 'origin/master' into newtimercode4
# Conflicts: # src/gl/models/gl_models.cpp
This commit is contained in:
commit
fd5b8cdbf7
31 changed files with 1553 additions and 374 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -52,3 +52,5 @@
|
|||
/src/r_drawersasm.obj
|
||||
/src/r_drawersasm.o
|
||||
.vs
|
||||
/src/gl/unused
|
||||
/mapfiles_release/*.map
|
||||
|
|
|
@ -702,6 +702,7 @@ set ( SWRENDER_SOURCES
|
|||
swrenderer/r_swrenderer.cpp
|
||||
swrenderer/r_memory.cpp
|
||||
swrenderer/r_renderthread.cpp
|
||||
swrenderer/drawers/r_draw.cpp
|
||||
swrenderer/drawers/r_draw_pal.cpp
|
||||
swrenderer/drawers/r_draw_rgba.cpp
|
||||
swrenderer/drawers/r_thread.cpp
|
||||
|
@ -755,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
|
||||
|
@ -959,6 +961,7 @@ set (PCH_SOURCES
|
|||
stats.cpp
|
||||
stringtable.cpp
|
||||
teaminfo.cpp
|
||||
umapinfo.cpp
|
||||
v_blend.cpp
|
||||
v_collection.cpp
|
||||
v_draw.cpp
|
||||
|
|
|
@ -253,7 +253,7 @@ struct FSpecialAction
|
|||
{
|
||||
FName Type; // this is initialized before the actors...
|
||||
uint8_t Action;
|
||||
int Args[5]; // must allow 16 bit tags for 666 & 667!
|
||||
int Args[5];
|
||||
};
|
||||
|
||||
class DScroller;
|
||||
|
@ -307,6 +307,11 @@ struct FExitText
|
|||
FString mText;
|
||||
FString mMusic;
|
||||
FString mBackdrop;
|
||||
|
||||
FExitText(int def = 0, int order = -1, const FString &text = "", const FString &backdrop = "", const FString &music = "")
|
||||
: mDefined(int16_t(def)), mOrder(int16_t(order)), mText(text), mMusic(music), mBackdrop(backdrop)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct level_info_t
|
||||
|
@ -619,5 +624,8 @@ struct FEpisode
|
|||
|
||||
extern TArray<FEpisode> AllEpisodes;
|
||||
|
||||
int ParseUMapInfo(int lumpnum);
|
||||
void CommitUMapinfo(level_info_t *defaultinfo);
|
||||
|
||||
|
||||
#endif //__G_LEVEL_H__
|
||||
|
|
|
@ -2206,7 +2206,7 @@ void G_ParseMapInfo (FString basemapinfo)
|
|||
parse.ParseMapInfo(baselump, gamedefaults, defaultinfo);
|
||||
}
|
||||
|
||||
static const char *mapinfonames[] = { "MAPINFO", "ZMAPINFO", NULL };
|
||||
static const char *mapinfonames[] = { "MAPINFO", "ZMAPINFO", "UMAPINFO", NULL };
|
||||
int nindex;
|
||||
|
||||
// Parse any extra MAPINFOs.
|
||||
|
@ -2222,10 +2222,28 @@ void G_ParseMapInfo (FString basemapinfo)
|
|||
|
||||
if (altlump >= 0) continue;
|
||||
}
|
||||
FMapInfoParser parse(nindex == 1? FMapInfoParser::FMT_New : FMapInfoParser::FMT_Unknown);
|
||||
level_info_t defaultinfo;
|
||||
parse.ParseMapInfo(lump, gamedefaults, defaultinfo);
|
||||
else if (nindex == 2)
|
||||
{
|
||||
// MAPINFO and ZMAPINFO will override UMAPINFO if in the same WAD.
|
||||
int wad = Wads.GetLumpFile(lump);
|
||||
int altlump = Wads.CheckNumForName("ZMAPINFO", ns_global, wad, true);
|
||||
if (altlump >= 0) continue;
|
||||
altlump = Wads.CheckNumForName("MAPINFO", ns_global, wad, true);
|
||||
if (altlump >= 0) continue;
|
||||
}
|
||||
if (nindex != 2)
|
||||
{
|
||||
CommitUMapinfo(&gamedefaults); // UMPAINFOs are collected until a regular MAPINFO is found so that they properly use the base settings.
|
||||
FMapInfoParser parse(nindex == 1 ? FMapInfoParser::FMT_New : FMapInfoParser::FMT_Unknown);
|
||||
level_info_t defaultinfo;
|
||||
parse.ParseMapInfo(lump, gamedefaults, defaultinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
ParseUMapInfo(lump);
|
||||
}
|
||||
}
|
||||
CommitUMapinfo(&gamedefaults); // commit remaining UMPAINFOs.
|
||||
|
||||
if (AllEpisodes.Size() == 0)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
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()
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -869,207 +1189,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
|
||||
|
@ -1078,55 +1203,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);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
@ -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 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
|
||||
{
|
||||
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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -724,6 +724,18 @@ FName FMapInfoParser::ParseEndGame()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FName MakeEndPic(const char *string)
|
||||
{
|
||||
FString seqname;
|
||||
seqname << "@EndPic_" << string;
|
||||
FIntermissionDescriptor *desc = new FIntermissionDescriptor;
|
||||
FIntermissionAction *action = new FIntermissionAction;
|
||||
action->mBackground = string;
|
||||
desc->mActions.Push(action);
|
||||
ReplaceIntermission(seqname, desc);
|
||||
return FName(seqname);
|
||||
}
|
||||
|
||||
FName FMapInfoParser::CheckEndSequence()
|
||||
{
|
||||
const char *seqname = NULL;
|
||||
|
@ -756,14 +768,7 @@ FName FMapInfoParser::CheckEndSequence()
|
|||
{
|
||||
ParseComma();
|
||||
sc.MustGetString ();
|
||||
FString seqname;
|
||||
seqname << "@EndPic_" << sc.String;
|
||||
FIntermissionDescriptor *desc = new FIntermissionDescriptor;
|
||||
FIntermissionAction *action = new FIntermissionAction;
|
||||
action->mBackground = sc.String;
|
||||
desc->mActions.Push(action);
|
||||
ReplaceIntermission(seqname, desc);
|
||||
return FName(seqname);
|
||||
return MakeEndPic(sc.String);
|
||||
}
|
||||
else if (sc.Compare("endbunny"))
|
||||
{
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -119,7 +119,7 @@ namespace TriScreenDrawerModes
|
|||
}
|
||||
|
||||
template<typename SamplerT>
|
||||
FORCEINLINE unsigned int SampleShade32(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight, int &fuzzpos)
|
||||
FORCEINLINE unsigned int SampleShade32(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight, int x, int y)
|
||||
{
|
||||
if (SamplerT::Mode == (int)Samplers::Shaded)
|
||||
{
|
||||
|
@ -140,12 +140,23 @@ namespace TriScreenDrawerModes
|
|||
}
|
||||
else if (SamplerT::Mode == (int)Samplers::Fuzz)
|
||||
{
|
||||
using namespace swrenderer;
|
||||
|
||||
uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16;
|
||||
uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16;
|
||||
unsigned int sampleshadeout = APART(texPixels[texelX * texHeight + texelY]);
|
||||
sampleshadeout += sampleshadeout >> 7; // 255 -> 256
|
||||
sampleshadeout = (sampleshadeout * fuzzcolormap[fuzzpos++]) >> 5;
|
||||
if (fuzzpos >= FUZZTABLE) fuzzpos = 0;
|
||||
|
||||
fixed_t fuzzscale = (200 << FRACBITS) / viewheight;
|
||||
|
||||
int scaled_x = (x * fuzzscale) >> FRACBITS;
|
||||
int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + fuzzpos;
|
||||
|
||||
fixed_t fuzzcount = FUZZTABLE << FRACBITS;
|
||||
fixed_t fuzz = ((fuzz_x << FRACBITS) + y * fuzzscale) % fuzzcount;
|
||||
unsigned int alpha = fuzzoffset[fuzz >> FRACBITS];
|
||||
|
||||
sampleshadeout = (sampleshadeout * alpha) >> 5;
|
||||
return sampleshadeout;
|
||||
}
|
||||
else
|
||||
|
@ -373,8 +384,6 @@ private:
|
|||
uint32_t srcalpha = args->uniforms->SrcAlpha();
|
||||
uint32_t destalpha = args->uniforms->DestAlpha();
|
||||
|
||||
int fuzzpos = (ScreenTriangle::FuzzStart + destX * 123 + destY) % FUZZTABLE;
|
||||
|
||||
auto lights = args->uniforms->Lights();
|
||||
auto num_lights = args->uniforms->NumLights();
|
||||
FVector3 worldnormal = args->uniforms->Normal();
|
||||
|
@ -505,7 +514,7 @@ private:
|
|||
// Sample fgcolor
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[ix];
|
||||
unsigned int ifgcolor = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
unsigned int ifgshade = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
unsigned int ifgshade = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, destX + ix, destY + y);
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
|
||||
|
@ -608,7 +617,7 @@ private:
|
|||
// Sample fgcolor
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary && (mask0 & (1 << 31))) color = dest[x];
|
||||
unsigned int ifgcolor = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
unsigned int ifgshade = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
unsigned int ifgshade = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, destX + x, destY + y);
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
|
||||
|
@ -711,7 +720,7 @@ private:
|
|||
// Sample fgcolor
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary && (mask1 & (1 << 31))) color = dest[x];
|
||||
unsigned int ifgcolor = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
unsigned int ifgshade = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
unsigned int ifgshade = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, destX + x, destY + 4 + y);
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
|
||||
|
@ -773,7 +782,11 @@ public:
|
|||
{
|
||||
using namespace TriScreenDrawerModes;
|
||||
|
||||
if (args->SimpleShade())
|
||||
if (SamplerT::Mode == (int)Samplers::Fuzz)
|
||||
{
|
||||
Loop<NoShade, NearestFilter>(destOrg, destWidth, destHeight, destPitch, args, thread);
|
||||
}
|
||||
else if (args->SimpleShade())
|
||||
{
|
||||
Loop<SimpleShade, NearestFilter>(destOrg, destWidth, destHeight, destPitch, args, thread);
|
||||
}
|
||||
|
@ -869,15 +882,12 @@ private:
|
|||
|
||||
int count = x1 - x0;
|
||||
|
||||
int fuzzpos = (ScreenTriangle::FuzzStart + x0 * 123 + y0) % FUZZTABLE;
|
||||
|
||||
uint32_t posV = startV;
|
||||
for (int y = y0; y < y1; y++, posV += stepV)
|
||||
{
|
||||
int coreBlock = y / 8;
|
||||
if (coreBlock % thread->num_cores != thread->core)
|
||||
{
|
||||
fuzzpos = (fuzzpos + count) % FUZZTABLE;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -896,7 +906,7 @@ private:
|
|||
// Sample fgcolor
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = *dest;
|
||||
unsigned int ifgcolor = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
unsigned int ifgshade = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
unsigned int ifgshade = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, x0 + i, y);
|
||||
posU += stepU;
|
||||
|
||||
// Shade and blend
|
||||
|
|
|
@ -107,7 +107,7 @@ namespace TriScreenDrawerModes
|
|||
}
|
||||
|
||||
template<typename SamplerT>
|
||||
FORCEINLINE unsigned int VECTORCALL SampleShade32(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight, int &fuzzpos)
|
||||
FORCEINLINE unsigned int VECTORCALL SampleShade32(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight, int x, int y)
|
||||
{
|
||||
if (SamplerT::Mode == (int)Samplers::Shaded)
|
||||
{
|
||||
|
@ -128,12 +128,23 @@ namespace TriScreenDrawerModes
|
|||
}
|
||||
else if (SamplerT::Mode == (int)Samplers::Fuzz)
|
||||
{
|
||||
using namespace swrenderer;
|
||||
|
||||
uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16;
|
||||
uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16;
|
||||
unsigned int sampleshadeout = APART(texPixels[texelX * texHeight + texelY]);
|
||||
sampleshadeout += sampleshadeout >> 7; // 255 -> 256
|
||||
sampleshadeout = (sampleshadeout * fuzzcolormap[fuzzpos++]) >> 5;
|
||||
if (fuzzpos >= FUZZTABLE) fuzzpos = 0;
|
||||
|
||||
fixed_t fuzzscale = (200 << FRACBITS) / viewheight;
|
||||
|
||||
int scaled_x = (x * fuzzscale) >> FRACBITS;
|
||||
int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + fuzzpos;
|
||||
|
||||
fixed_t fuzzcount = FUZZTABLE << FRACBITS;
|
||||
fixed_t fuzz = ((fuzz_x << FRACBITS) + y * fuzzscale) % fuzzcount;
|
||||
unsigned int alpha = fuzzoffset[fuzz >> FRACBITS];
|
||||
|
||||
sampleshadeout = (sampleshadeout * alpha) >> 5;
|
||||
return sampleshadeout;
|
||||
}
|
||||
else
|
||||
|
@ -392,8 +403,6 @@ private:
|
|||
uint32_t srcalpha = args->uniforms->SrcAlpha();
|
||||
uint32_t destalpha = args->uniforms->DestAlpha();
|
||||
|
||||
int fuzzpos = (ScreenTriangle::FuzzStart + destX * 123 + destY) % FUZZTABLE;
|
||||
|
||||
auto lights = args->uniforms->Lights();
|
||||
auto num_lights = args->uniforms->NumLights();
|
||||
__m128 worldnormal = _mm_setr_ps(args->uniforms->Normal().X, args->uniforms->Normal().Y, args->uniforms->Normal().Z, 0.0f);
|
||||
|
@ -518,13 +527,13 @@ private:
|
|||
unsigned int ifgcolor[2], ifgshade[2];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[ix * 2];
|
||||
ifgcolor[0] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, destX + ix * 2, destY + y);
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[ix * 2 + 1];
|
||||
ifgcolor[1] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[1] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
ifgshade[1] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, destX + ix * 2 + 1, destY + y);
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
|
||||
|
@ -626,13 +635,13 @@ private:
|
|||
unsigned int ifgcolor[2], ifgshade[2];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[x * 2];
|
||||
ifgcolor[0] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, destX + x * 2, destY + y);
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[x * 2 + 1];
|
||||
ifgcolor[1] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[1] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
ifgshade[1] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, destX + x * 2 + 1, destY + y);
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
|
||||
|
@ -736,13 +745,13 @@ private:
|
|||
unsigned int ifgcolor[2], ifgshade[2];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary && (mask1 & (1 << 31))) color = dest[x * 2];
|
||||
ifgcolor[0] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, destX + x * 2, destY + 4 + y);
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary && (mask1 & (1 << 30))) color = dest[x * 2 + 1];
|
||||
ifgcolor[1] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[1] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
ifgshade[1] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, destX + x * 2 + 1, destY + 4 + y);
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
|
||||
|
@ -889,15 +898,12 @@ private:
|
|||
int count = x1 - x0;
|
||||
int sseCount = count / 2;
|
||||
|
||||
int fuzzpos = (ScreenTriangle::FuzzStart + x0 * 123 + y0) % FUZZTABLE;
|
||||
|
||||
uint32_t posV = startV;
|
||||
for (int y = y0; y < y1; y++, posV += stepV)
|
||||
{
|
||||
int coreBlock = y / 8;
|
||||
if (coreBlock % thread->num_cores != thread->core)
|
||||
{
|
||||
fuzzpos = (fuzzpos + count) % FUZZTABLE;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -917,12 +923,12 @@ private:
|
|||
unsigned int ifgcolor[2], ifgshade[2];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[0];
|
||||
ifgcolor[0] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, x0 + i * 2, y);
|
||||
posU += stepU;
|
||||
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[1];
|
||||
ifgcolor[1] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[1] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
ifgshade[1] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, x0 + i * 2 + 1, y);
|
||||
posU += stepU;
|
||||
|
||||
// Shade and blend
|
||||
|
@ -948,7 +954,7 @@ private:
|
|||
unsigned int ifgcolor[2], ifgshade[2];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = *dest;
|
||||
ifgcolor[0] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, x0 + sseCount * 2, y);
|
||||
ifgcolor[1] = 0;
|
||||
ifgshade[1] = 0;
|
||||
posU += stepU;
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace TriScreenDrawerModes
|
|||
}
|
||||
|
||||
template<typename SamplerT>
|
||||
FORCEINLINE unsigned int SampleShade8(int32_t u, int32_t v, const uint8_t *texPixels, int texWidth, int texHeight, int &fuzzpos)
|
||||
FORCEINLINE unsigned int SampleShade8(int32_t u, int32_t v, const uint8_t *texPixels, int texWidth, int texHeight, int x, int y)
|
||||
{
|
||||
if (SamplerT::Mode == (int)Samplers::Shaded)
|
||||
{
|
||||
|
@ -97,11 +97,22 @@ namespace TriScreenDrawerModes
|
|||
}
|
||||
else if (SamplerT::Mode == (int)Samplers::Fuzz)
|
||||
{
|
||||
using namespace swrenderer;
|
||||
|
||||
uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16;
|
||||
uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16;
|
||||
unsigned int sampleshadeout = (texPixels[texelX * texHeight + texelY] != 0) ? 256 : 0;
|
||||
sampleshadeout = (sampleshadeout * fuzzcolormap[fuzzpos++]) >> 5;
|
||||
if (fuzzpos >= FUZZTABLE) fuzzpos = 0;
|
||||
|
||||
fixed_t fuzzscale = (200 << FRACBITS) / viewheight;
|
||||
|
||||
int scaled_x = (x * fuzzscale) >> FRACBITS;
|
||||
int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + fuzzpos;
|
||||
|
||||
fixed_t fuzzcount = FUZZTABLE << FRACBITS;
|
||||
fixed_t fuzz = ((fuzz_x << FRACBITS) + y * fuzzscale) % fuzzcount;
|
||||
unsigned int alpha = fuzzoffset[fuzz >> FRACBITS];
|
||||
|
||||
sampleshadeout = (sampleshadeout * alpha) >> 5;
|
||||
return sampleshadeout;
|
||||
}
|
||||
else
|
||||
|
@ -228,8 +239,6 @@ public:
|
|||
uint32_t srcalpha = args->uniforms->SrcAlpha();
|
||||
uint32_t destalpha = args->uniforms->DestAlpha();
|
||||
|
||||
int fuzzpos = (ScreenTriangle::FuzzStart + destX * 123 + destY) % FUZZTABLE;
|
||||
|
||||
// Calculate gradients
|
||||
const ShadedTriVertex &v1 = *args->v1;
|
||||
ScreenTriangleStepVariables gradientX = args->gradientX;
|
||||
|
@ -292,7 +301,7 @@ public:
|
|||
uint8_t bgcolor = dest[ix];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = bgcolor;
|
||||
uint8_t fgcolor = Sample8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, color, translation);
|
||||
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, destX + ix, destY + y);
|
||||
if (SamplerT::Mode == (int)Samplers::Fuzz) lightshade = 256;
|
||||
dest[ix] = ShadeAndBlend8<BlendT>(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha);
|
||||
posU += stepU;
|
||||
|
@ -342,7 +351,7 @@ public:
|
|||
uint8_t bgcolor = dest[x];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = bgcolor;
|
||||
uint8_t fgcolor = Sample8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, color, translation);
|
||||
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, destX + x, destY + y);
|
||||
if (SamplerT::Mode == (int)Samplers::Fuzz) lightshade = 256;
|
||||
dest[x] = ShadeAndBlend8<BlendT>(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha);
|
||||
}
|
||||
|
@ -394,7 +403,7 @@ public:
|
|||
uint8_t bgcolor = dest[x];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = bgcolor;
|
||||
uint8_t fgcolor = Sample8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, color, translation);
|
||||
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, destX + x, destY + 4 + y);
|
||||
if (SamplerT::Mode == (int)Samplers::Fuzz) lightshade = 256;
|
||||
dest[x] = ShadeAndBlend8<BlendT>(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha);
|
||||
}
|
||||
|
@ -458,15 +467,12 @@ public:
|
|||
|
||||
int count = x1 - x0;
|
||||
|
||||
int fuzzpos = (ScreenTriangle::FuzzStart + x0 * 123 + y0) % FUZZTABLE;
|
||||
|
||||
uint32_t posV = startV;
|
||||
for (int y = y0; y < y1; y++, posV += stepV)
|
||||
{
|
||||
int coreBlock = y / 8;
|
||||
if (coreBlock % thread->num_cores != thread->core)
|
||||
{
|
||||
fuzzpos = (fuzzpos + count) % FUZZTABLE;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -478,7 +484,7 @@ public:
|
|||
uint8_t bgcolor = *dest;
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = bgcolor;
|
||||
uint8_t fgcolor = Sample8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, color, translation);
|
||||
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, x0 + i, y);
|
||||
*dest = ShadeAndBlend8<BlendT>(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha);
|
||||
|
||||
posU += stepU;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -119,6 +119,8 @@ void PolyRenderer::RenderActorView(AActor *actor, bool dontmaplines)
|
|||
P_FindParticleSubsectors();
|
||||
PO_LinkToSubsectors();
|
||||
|
||||
swrenderer::R_UpdateFuzzPosFrameStart();
|
||||
|
||||
if (APART(R_OldBlend)) NormalLight.Maps = realcolormaps.Maps;
|
||||
else NormalLight.Maps = realcolormaps.Maps + NUMCOLORMAPS * 256 * R_OldBlend;
|
||||
|
||||
|
@ -206,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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
255
src/polyrenderer/scene/poly_model.cpp
Normal file
255
src/polyrenderer/scene/poly_model.cpp
Normal 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);
|
||||
}
|
||||
|
||||
float 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];
|
||||
}
|
||||
}
|
82
src/polyrenderer/scene/poly_model.h
Normal file
82
src/polyrenderer/scene/poly_model.h
Normal 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;
|
||||
float 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;
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -102,4 +102,5 @@ private:
|
|||
|
||||
TArray<PolyHWAccelPlayerSprite> AcceleratedSprites;
|
||||
sector_t tempsec;
|
||||
bool renderHUDModel = false;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -949,6 +949,76 @@ bool FScanner::Compare (const char *text)
|
|||
return (stricmp (text, String) == 0);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Convenience helpers that parse an entire number including a leading minus or plus sign
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FScanner::ScanValue(bool allowfloat)
|
||||
{
|
||||
bool neg = false;
|
||||
if (!GetToken())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (TokenType == '-' || TokenType == '+')
|
||||
{
|
||||
neg = TokenType == '-';
|
||||
if (!GetToken())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (TokenType != TK_IntConst && (TokenType != TK_FloatConst || !allowfloat))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (neg)
|
||||
{
|
||||
Number = -Number;
|
||||
Float = -Float;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FScanner::CheckValue(bool allowfloat)
|
||||
{
|
||||
auto savedstate = SavePos();
|
||||
bool res = ScanValue(allowfloat);
|
||||
if (!res) RestorePos(savedstate);
|
||||
return res;
|
||||
}
|
||||
|
||||
void FScanner::MustGetValue(bool allowfloat)
|
||||
{
|
||||
if (!ScanValue(allowfloat)) ScriptError(allowfloat ? "Numeric constant expected" : "Integer constant expected");
|
||||
}
|
||||
|
||||
bool FScanner::CheckBoolToken()
|
||||
{
|
||||
if (CheckToken(TK_True))
|
||||
{
|
||||
Number = 1;
|
||||
Float = 1;
|
||||
return true;
|
||||
}
|
||||
if (CheckToken(TK_False))
|
||||
{
|
||||
Number = 0;
|
||||
Float = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FScanner::MustGetBoolToken()
|
||||
{
|
||||
if (!CheckBoolToken())
|
||||
ScriptError("Expected true or false");
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FScanner :: TokenName
|
||||
|
|
|
@ -57,6 +57,12 @@ public:
|
|||
bool GetFloat();
|
||||
void MustGetFloat();
|
||||
bool CheckFloat();
|
||||
|
||||
// Token based variant
|
||||
bool CheckValue(bool allowfloat);
|
||||
void MustGetValue(bool allowfloat);
|
||||
bool CheckBoolToken();
|
||||
void MustGetBoolToken();
|
||||
|
||||
void UnGet();
|
||||
|
||||
|
@ -107,6 +113,9 @@ protected:
|
|||
bool StateOptions;
|
||||
bool Escape;
|
||||
VersionInfo ParseVersion = { 0, 0, 0 }; // no ZScript extensions by default
|
||||
|
||||
|
||||
bool ScanValue(bool allowfloat);
|
||||
};
|
||||
|
||||
enum
|
||||
|
|
|
@ -193,9 +193,9 @@ namespace swrenderer
|
|||
|
||||
void R_UpdateFuzzPosFrameStart()
|
||||
{
|
||||
if (r_fuzzscale)
|
||||
if (r_fuzzscale || r_polyrenderer)
|
||||
{
|
||||
int next_random = 0;
|
||||
static int next_random = 0;
|
||||
|
||||
fuzzpos = (fuzzpos + fuzz_random_x_offset[next_random] * FUZZTABLE / 100) % FUZZTABLE;
|
||||
|
||||
|
@ -207,7 +207,7 @@ namespace swrenderer
|
|||
|
||||
void R_UpdateFuzzPos(const SpriteDrawerArgs &args)
|
||||
{
|
||||
if (!r_fuzzscale)
|
||||
if (!r_fuzzscale && !r_polyrenderer)
|
||||
{
|
||||
int yl = MAX(args.FuzzY1(), 1);
|
||||
int yh = MIN(args.FuzzY2(), fuzzviewheight);
|
||||
|
|
477
src/umapinfo.cpp
Normal file
477
src/umapinfo.cpp
Normal file
|
@ -0,0 +1,477 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright 2017 Christoph Oelckers
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include "w_wad.h"
|
||||
#include "g_level.h"
|
||||
#include "sc_man.h"
|
||||
#include "r_defs.h"
|
||||
#include "p_setup.h"
|
||||
#include "gi.h"
|
||||
|
||||
FName MakeEndPic(const char *string);
|
||||
|
||||
struct BossAction
|
||||
{
|
||||
int type;
|
||||
int special;
|
||||
int tag;
|
||||
};
|
||||
|
||||
struct UMapEntry
|
||||
{
|
||||
FString MapName;
|
||||
FString LevelName;
|
||||
FString InterText;
|
||||
FString InterTextSecret;
|
||||
TArray<FSpecialAction> BossActions;
|
||||
|
||||
char levelpic[9] = "";
|
||||
char nextmap[9] = "";
|
||||
char nextsecret[9] = "";
|
||||
char music[9] = "";
|
||||
char skytexture[9] = "";
|
||||
char endpic[9] = "";
|
||||
char exitpic[9] = "";
|
||||
char enterpic[9] = "";
|
||||
char interbackdrop[9] = "FLOOR4_8";
|
||||
char intermusic[9] = "";
|
||||
int partime = 0;
|
||||
int nointermission = 0;
|
||||
};
|
||||
|
||||
static TArray<UMapEntry> Maps;
|
||||
|
||||
|
||||
// -----------------------------------------------
|
||||
//
|
||||
// Parses a set of string and concatenates them
|
||||
//
|
||||
// -----------------------------------------------
|
||||
|
||||
static FString ParseMultiString(FScanner &scanner, int error)
|
||||
{
|
||||
FString build;
|
||||
|
||||
if (scanner.CheckToken(TK_Identifier))
|
||||
{
|
||||
if (!stricmp(scanner.String, "clear"))
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
else
|
||||
{
|
||||
scanner.ScriptError("Either 'clear' or string constant expected");
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
scanner.MustGetToken(TK_StringConst);
|
||||
if (build.Len() > 0) build += "\n";
|
||||
build += scanner.String;
|
||||
}
|
||||
while (scanner.CheckToken(','));
|
||||
return build;
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
//
|
||||
// Parses a lump name. The buffer must be at least 9 characters.
|
||||
//
|
||||
// -----------------------------------------------
|
||||
|
||||
static int ParseLumpName(FScanner &scanner, char *buffer)
|
||||
{
|
||||
scanner.MustGetToken(TK_StringConst);
|
||||
if (strlen(scanner.String) > 8)
|
||||
{
|
||||
scanner.ScriptError("String too long. Maximum size is 8 characters.");
|
||||
return 0;
|
||||
}
|
||||
uppercopy(buffer, scanner.String);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
//
|
||||
// Parses a standard property that is already known
|
||||
// These do not get stored in the property list
|
||||
// but in dedicated struct member variables.
|
||||
//
|
||||
// -----------------------------------------------
|
||||
|
||||
static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape)
|
||||
{
|
||||
// find the next line with content.
|
||||
// this line is no property.
|
||||
|
||||
scanner.MustGetToken(TK_Identifier);
|
||||
FString pname = scanner.String;
|
||||
scanner.MustGetToken('=');
|
||||
|
||||
if (!pname.CompareNoCase("levelname"))
|
||||
{
|
||||
scanner.MustGetToken(TK_StringConst);
|
||||
mape->LevelName = scanner.String;
|
||||
}
|
||||
else if (!pname.CompareNoCase("next"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->nextmap);
|
||||
}
|
||||
else if (!pname.CompareNoCase("nextsecret"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->nextsecret);
|
||||
}
|
||||
else if (!pname.CompareNoCase("levelpic"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->levelpic);
|
||||
}
|
||||
else if (!pname.CompareNoCase("skytexture"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->skytexture);
|
||||
}
|
||||
else if (!pname.CompareNoCase("music"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->music);
|
||||
}
|
||||
else if (!pname.CompareNoCase("endpic"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->endpic);
|
||||
}
|
||||
else if (!pname.CompareNoCase("endcast"))
|
||||
{
|
||||
scanner.MustGetBoolToken();
|
||||
if (scanner.Number) strcpy(mape->endpic, "$CAST");
|
||||
else strcpy(mape->endpic, "-");
|
||||
}
|
||||
else if (!pname.CompareNoCase("endbunny"))
|
||||
{
|
||||
scanner.MustGetBoolToken();
|
||||
if (scanner.Number) strcpy(mape->endpic, "$BUNNY");
|
||||
else strcpy(mape->endpic, "-");
|
||||
}
|
||||
else if (!pname.CompareNoCase("endgame"))
|
||||
{
|
||||
scanner.MustGetBoolToken();
|
||||
if (scanner.Number) strcpy(mape->endpic, "!");
|
||||
else strcpy(mape->endpic, "-");
|
||||
}
|
||||
else if (!pname.CompareNoCase("exitpic"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->exitpic);
|
||||
}
|
||||
else if (!pname.CompareNoCase("enterpic"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->enterpic);
|
||||
}
|
||||
else if (!pname.CompareNoCase("nointermission"))
|
||||
{
|
||||
scanner.MustGetBoolToken();
|
||||
mape->nointermission = scanner.Number;
|
||||
}
|
||||
else if (!pname.CompareNoCase("partime"))
|
||||
{
|
||||
scanner.MustGetValue(false);
|
||||
mape->partime = TICRATE * scanner.Number;
|
||||
}
|
||||
else if (!pname.CompareNoCase("intertext"))
|
||||
{
|
||||
mape->InterText = ParseMultiString(scanner, 1);
|
||||
if (mape->InterText.IsEmpty()) return 0;
|
||||
}
|
||||
else if (!pname.CompareNoCase("intertextsecret"))
|
||||
{
|
||||
mape->InterTextSecret = ParseMultiString(scanner, 1);
|
||||
if (mape->InterTextSecret.IsEmpty()) return 0;
|
||||
}
|
||||
else if (!pname.CompareNoCase("interbackdrop"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->interbackdrop);
|
||||
}
|
||||
else if (!pname.CompareNoCase("intermusic"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->intermusic);
|
||||
}
|
||||
else if (!pname.CompareNoCase("episode"))
|
||||
{
|
||||
FString Episode = ParseMultiString(scanner, 1);
|
||||
if (Episode.IsEmpty()) return 0;
|
||||
if (Episode.Compare("-") == 0)
|
||||
{
|
||||
// clear the given episode
|
||||
for (unsigned i = 0; i < AllEpisodes.Size(); i++)
|
||||
{
|
||||
if (AllEpisodes[i].mEpisodeMap.CompareNoCase(mape->MapName) == 0)
|
||||
{
|
||||
AllEpisodes.Delete(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto split = Episode.Split("\n");
|
||||
// add the given episode
|
||||
FEpisode epi;
|
||||
|
||||
epi.mEpisodeName = split[1];
|
||||
epi.mEpisodeMap = mape->MapName;
|
||||
epi.mPicName = split[0];
|
||||
epi.mShortcut = split[2][0];
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < AllEpisodes.Size(); i++)
|
||||
{
|
||||
if (AllEpisodes[i].mEpisodeMap.CompareNoCase(mape->MapName) == 0)
|
||||
{
|
||||
AllEpisodes[i] = std::move(epi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == AllEpisodes.Size())
|
||||
{
|
||||
AllEpisodes.Push(epi);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!pname.CompareNoCase("bossaction"))
|
||||
{
|
||||
scanner.MustGetToken(TK_Identifier);
|
||||
int classnum, special, tag;
|
||||
if (!stricmp(scanner.String, "clear"))
|
||||
{
|
||||
// mark level free of boss actions
|
||||
classnum = special = tag = -1;
|
||||
mape->BossActions.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
FName type = scanner.String;
|
||||
scanner.MustGetToken(',');
|
||||
scanner.MustGetValue(false);
|
||||
int special = scanner.Number;
|
||||
scanner.MustGetToken(',');
|
||||
scanner.MustGetValue(false);
|
||||
int tag = scanner.Number;
|
||||
// allow no 0-tag specials here, unless a level exit.
|
||||
if (tag != 0 || special == 11 || special == 51 || special == 52 || special == 124)
|
||||
{
|
||||
FSpecialAction & bossact = mape->BossActions[mape->BossActions.Reserve(1)];
|
||||
line_t line;
|
||||
maplinedef_t mld;
|
||||
mld.special = special;
|
||||
mld.tag = tag;
|
||||
P_TranslateLineDef(&line, &mld);
|
||||
bossact = { type, (uint8_t)line.special, {line.args[0], line.args[1],line.args[2],line.args[3],line.args[4]} };
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Skip over all unknown properties.
|
||||
do
|
||||
{
|
||||
if (!scanner.CheckValue(true))
|
||||
{
|
||||
scanner.MustGetAnyToken();
|
||||
if (scanner.TokenType != TK_Identifier && scanner.TokenType != TK_StringConst && scanner.TokenType != TK_True && scanner.TokenType != TK_False)
|
||||
{
|
||||
scanner.ScriptError("Identifier or value expected");
|
||||
}
|
||||
}
|
||||
|
||||
} while (scanner.CheckToken(','));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
//
|
||||
// Parses a complete map entry
|
||||
//
|
||||
// -----------------------------------------------
|
||||
|
||||
static int ParseMapEntry(FScanner &scanner, UMapEntry *val)
|
||||
{
|
||||
scanner.MustGetToken(TK_Identifier);
|
||||
|
||||
val->MapName = scanner.String;
|
||||
scanner.MustGetToken('{');
|
||||
while(!scanner.CheckToken('}'))
|
||||
{
|
||||
ParseStandardProperty(scanner, val);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
//
|
||||
// Parses a complete UMAPINFO lump
|
||||
//
|
||||
// -----------------------------------------------
|
||||
|
||||
int ParseUMapInfo(int lumpnum)
|
||||
{
|
||||
FScanner scanner(lumpnum);
|
||||
unsigned int i;
|
||||
|
||||
while (scanner.GetToken())
|
||||
{
|
||||
scanner.TokenMustBe(TK_Map);
|
||||
|
||||
UMapEntry parsed;
|
||||
ParseMapEntry(scanner, &parsed);
|
||||
|
||||
// Endpic overrides level exits.
|
||||
if (parsed.endpic[0])
|
||||
{
|
||||
parsed.nextmap[0] = parsed.nextsecret[0] = 0;
|
||||
if (parsed.endpic[0] == '!') parsed.endpic[0] = 0;
|
||||
}
|
||||
/*
|
||||
else if (!parsed.nextmap[0] && !parsed.endpic[0])
|
||||
{
|
||||
if (!parsed.MapName.CompareNoCase("MAP30")) uppercopy(parsed.endpic, "$CAST");
|
||||
else if (!parsed.MapName.CompareNoCase("E1M8")) uppercopy(parsed.endpic, gameinfo.creditPages.Last());
|
||||
else if (!parsed.MapName.CompareNoCase("E2M8")) uppercopy(parsed.endpic, "VICTORY");
|
||||
else if (!parsed.MapName.CompareNoCase("E3M8")) uppercopy(parsed.endpic, "$BUNNY");
|
||||
else if (!parsed.MapName.CompareNoCase("E4M8")) uppercopy(parsed.endpic, "ENDPIC");
|
||||
else if (gameinfo.gametype == GAME_Chex && !parsed.MapName.CompareNoCase("E1M5")) uppercopy(parsed.endpic, "CREDIT");
|
||||
else
|
||||
{
|
||||
parsed.nextmap[0] = 0; // keep previous setting
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Does this property already exist? If yes, replace it.
|
||||
for(i = 0; i < Maps.Size(); i++)
|
||||
{
|
||||
if (!parsed.MapName.Compare(Maps[i].MapName))
|
||||
{
|
||||
Maps[i] = parsed;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// Not found so create a new one.
|
||||
Maps.Push(parsed);
|
||||
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// This will get called if after an UMAPINFO lump a regular (Z)MAPINFO is found or when MAPINFO parsing is complete.
|
||||
void CommitUMapinfo(level_info_t *defaultinfo)
|
||||
{
|
||||
for (auto &map : Maps)
|
||||
{
|
||||
auto levelinfo = FindLevelInfo(map.MapName);
|
||||
if (levelinfo == nullptr)
|
||||
{
|
||||
// Map did not exist yet.
|
||||
auto levelindex = wadlevelinfos.Reserve(1);
|
||||
levelinfo = &wadlevelinfos[levelindex];
|
||||
*levelinfo = *defaultinfo;
|
||||
}
|
||||
if (map.MapName.IsNotEmpty()) levelinfo->MapName = map.MapName;
|
||||
if (map.LevelName.IsNotEmpty())
|
||||
{
|
||||
levelinfo->LevelName = map.LevelName;
|
||||
levelinfo->PName = ""; // clear the map name patch to force the string version to be shown - unless explicitly overridden right next.
|
||||
}
|
||||
if (map.levelpic[0]) levelinfo->PName = map.levelpic;
|
||||
if (map.nextmap[0]) levelinfo->NextMap = map.nextmap;
|
||||
else if (map.endpic[0])
|
||||
{
|
||||
FName name;
|
||||
|
||||
if (!stricmp(map.endpic, "$CAST"))
|
||||
{
|
||||
name = "INTER_CAST";
|
||||
}
|
||||
else if (!stricmp(map.endpic, "$BUNNY"))
|
||||
{
|
||||
name = "INTER_BUNNY";
|
||||
}
|
||||
else
|
||||
{
|
||||
name = MakeEndPic(map.endpic);
|
||||
}
|
||||
if (name != NAME_None)
|
||||
{
|
||||
levelinfo->NextMap.Format("enDSeQ%04x", int(name));
|
||||
}
|
||||
}
|
||||
|
||||
if (map.nextsecret[0]) levelinfo->NextSecretMap = map.nextsecret;
|
||||
if (map.music[0])
|
||||
{
|
||||
levelinfo->Music = map.music;
|
||||
levelinfo->musicorder = 0;
|
||||
}
|
||||
if (map.skytexture[0])
|
||||
{
|
||||
levelinfo->SkyPic1 = map.skytexture;
|
||||
levelinfo->skyspeed1 = 0;
|
||||
levelinfo->SkyPic2 = "";
|
||||
levelinfo->skyspeed2 = 0;
|
||||
}
|
||||
if (map.partime > 0) levelinfo->partime = map.partime;
|
||||
if (map.enterpic[0]) levelinfo->EnterPic = map.enterpic;
|
||||
if (map.exitpic[0]) levelinfo->ExitPic = map.exitpic;
|
||||
if (map.intermusic[0])
|
||||
{
|
||||
levelinfo->InterMusic = map.intermusic;
|
||||
levelinfo->intermusicorder = 0;
|
||||
}
|
||||
if (map.BossActions.Size() > 0)
|
||||
{
|
||||
// Setting a boss action will deactivate the flag based monster actions.
|
||||
levelinfo->specialactions = std::move(map.BossActions);
|
||||
levelinfo->flags &= ~(LEVEL_BRUISERSPECIAL | LEVEL_CYBORGSPECIAL | LEVEL_SPIDERSPECIAL | LEVEL_MAP07SPECIAL | LEVEL_MINOTAURSPECIAL | LEVEL_HEADSPECIAL | LEVEL_SORCERER2SPECIAL | LEVEL_SPECACTIONSMASK | LEVEL_SPECKILLMONSTERS);
|
||||
}
|
||||
|
||||
const int exflags = FExitText::DEF_TEXT | FExitText::DEF_BACKDROP | FExitText::DEF_MUSIC;
|
||||
if (map.InterText.IsNotEmpty())
|
||||
{
|
||||
if (map.InterText.Compare("-") != 0)
|
||||
levelinfo->ExitMapTexts[NAME_Normal] = { exflags, 0, map.InterText, map.interbackdrop, map.intermusic[0]? map.intermusic : gameinfo.intermissionMusic };
|
||||
else
|
||||
levelinfo->ExitMapTexts[NAME_Normal] = { 0, 0 };
|
||||
}
|
||||
if (map.InterTextSecret.IsNotEmpty())
|
||||
{
|
||||
if (map.InterTextSecret.Compare("-") != 0)
|
||||
levelinfo->ExitMapTexts[NAME_Secret] = { exflags, 0, map.InterTextSecret, map.interbackdrop, map.intermusic[0] ? map.intermusic : gameinfo.intermissionMusic };
|
||||
else
|
||||
levelinfo->ExitMapTexts[NAME_Secret] = { 0, 0 };
|
||||
}
|
||||
if (map.nointermission) levelinfo->flags |= LEVEL_NOINTERMISSION;
|
||||
}
|
||||
|
||||
|
||||
// All done. If we get here again, start fresh.
|
||||
Maps.Clear();
|
||||
Maps.ShrinkToFit();
|
||||
}
|
Loading…
Reference in a new issue