mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2025-01-19 05:30:49 +00:00
Merge branch 'master' of https://github.com/coelckers/gzdoom
This commit is contained in:
commit
ae8bc716b2
21 changed files with 470 additions and 184 deletions
|
@ -126,13 +126,16 @@ void ASkyPicker::PostBeginPlay ()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int boxindex = P_GetSkyboxPortal(box);
|
int boxindex = P_GetSkyboxPortal(box);
|
||||||
|
// Do not override special portal types, only regular skies.
|
||||||
if (0 == (args[1] & 2))
|
if (0 == (args[1] & 2))
|
||||||
{
|
{
|
||||||
Sector->Portals[sector_t::ceiling] = boxindex;
|
if (Sector->GetPortalType(sector_t::ceiling) == PORTS_SKYVIEWPOINT)
|
||||||
|
Sector->Portals[sector_t::ceiling] = boxindex;
|
||||||
}
|
}
|
||||||
if (0 == (args[1] & 1))
|
if (0 == (args[1] & 1))
|
||||||
{
|
{
|
||||||
Sector->Portals[sector_t::floor] = boxindex;
|
if (Sector->GetPortalType(sector_t::floor) == PORTS_SKYVIEWPOINT)
|
||||||
|
Sector->Portals[sector_t::floor] = boxindex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Destroy ();
|
Destroy ();
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "gl/dynlights/gl_dynlight.h"
|
#include "gl/dynlights/gl_dynlight.h"
|
||||||
#include "gl/utility/gl_geometric.h"
|
#include "gl/utility/gl_geometric.h"
|
||||||
#include "gl/renderer/gl_renderer.h"
|
#include "gl/renderer/gl_renderer.h"
|
||||||
|
#include "gl/renderer/gl_lightdata.h"
|
||||||
#include "gl/system/gl_interface.h"
|
#include "gl/system/gl_interface.h"
|
||||||
#include "gl/system/gl_cvars.h"
|
#include "gl/system/gl_cvars.h"
|
||||||
#include "gl/renderer/gl_renderstate.h"
|
#include "gl/renderer/gl_renderstate.h"
|
||||||
|
@ -452,7 +453,7 @@ bool gl_SetupLight(int group, Plane & p, ADynamicLight * light, Vector & nearPt,
|
||||||
|
|
||||||
bool gl_SetupLightTexture()
|
bool gl_SetupLightTexture()
|
||||||
{
|
{
|
||||||
if (GLRenderer->gllight == NULL) return false;
|
if (GLRenderer->gllight == nullptr) return false;
|
||||||
FMaterial * pat = FMaterial::ValidateTexture(GLRenderer->gllight, false);
|
FMaterial * pat = FMaterial::ValidateTexture(GLRenderer->gllight, false);
|
||||||
pat->Bind(CLAMP_XY, 0);
|
pat->Bind(CLAMP_XY, 0);
|
||||||
return true;
|
return true;
|
||||||
|
@ -464,6 +465,95 @@ bool gl_SetupLightTexture()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
|
bool GLWall::PutWallCompat(int passflag)
|
||||||
|
{
|
||||||
|
static int list_indices[2][2] =
|
||||||
|
{ { GLLDL_WALLS_PLAIN, GLLDL_WALLS_FOG },{ GLLDL_WALLS_MASKED, GLLDL_WALLS_FOGMASKED } };
|
||||||
|
|
||||||
|
// are lights possible?
|
||||||
|
if (gl_fixedcolormap != CM_DEFAULT || !gl_lights || seg->sidedef == nullptr || type == RENDERWALL_M2SNF || !gltexture) return false;
|
||||||
|
|
||||||
|
// multipassing these is problematic.
|
||||||
|
if ((flags&GLWF_SKYHACK && type == RENDERWALL_M2S)) return false;
|
||||||
|
|
||||||
|
// Any lights affecting this wall?
|
||||||
|
if (!(seg->sidedef->Flags & WALLF_POLYOBJ))
|
||||||
|
{
|
||||||
|
if (seg->sidedef->lighthead == nullptr) return false;
|
||||||
|
}
|
||||||
|
else if (sub)
|
||||||
|
{
|
||||||
|
if (sub->lighthead != nullptr) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool foggy = (!gl_isBlack(Colormap.FadeColor) || level.flags&LEVEL_HASFADETABLE);
|
||||||
|
bool masked = passflag == 2 && gltexture->isMasked();
|
||||||
|
|
||||||
|
int list = list_indices[masked][foggy];
|
||||||
|
if (list == GLLDL_WALLS_PLAIN)
|
||||||
|
{
|
||||||
|
if (gltexture->tex->gl_info.Brightmap && gl.glslversion >= 0.f) list = GLLDL_WALLS_BRIGHT;
|
||||||
|
//if (flags & GLWF_GLOW) list = GLLDL_WALLS_BRIGHT;
|
||||||
|
}
|
||||||
|
gl_drawinfo->dldrawlists[list].AddWall(this);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Fog boundary without any shader support
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void GLWall::RenderFogBoundaryCompat()
|
||||||
|
{
|
||||||
|
// without shaders some approximation is needed. This won't look as good
|
||||||
|
// as the shader version but it's an acceptable compromise.
|
||||||
|
float fogdensity = gl_GetFogDensity(lightlevel, Colormap.FadeColor);
|
||||||
|
|
||||||
|
float dist1 = Dist2(ViewPos.X, ViewPos.Y, glseg.x1, glseg.y1);
|
||||||
|
float dist2 = Dist2(ViewPos.X, ViewPos.Y, glseg.x2, glseg.y2);
|
||||||
|
|
||||||
|
// these values were determined by trial and error and are scale dependent!
|
||||||
|
float fogd1 = (0.95f - exp(-fogdensity*dist1 / 62500.f)) * 1.05f;
|
||||||
|
float fogd2 = (0.95f - exp(-fogdensity*dist2 / 62500.f)) * 1.05f;
|
||||||
|
|
||||||
|
float fc[4] = { Colormap.FadeColor.r / 255.0f,Colormap.FadeColor.g / 255.0f,Colormap.FadeColor.b / 255.0f,fogd2 };
|
||||||
|
|
||||||
|
gl_RenderState.EnableTexture(false);
|
||||||
|
gl_RenderState.EnableFog(false);
|
||||||
|
gl_RenderState.AlphaFunc(GL_GEQUAL, 0);
|
||||||
|
gl_RenderState.Apply();
|
||||||
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||||
|
glPolygonOffset(-1.0f, -128.0f);
|
||||||
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
glColor4f(fc[0], fc[1], fc[2], fogd1);
|
||||||
|
glBegin(GL_TRIANGLE_FAN);
|
||||||
|
glTexCoord2f(lolft.u, lolft.v);
|
||||||
|
glVertex3f(glseg.x1, zbottom[0], glseg.y1);
|
||||||
|
glTexCoord2f(uplft.u, uplft.v);
|
||||||
|
glVertex3f(glseg.x1, ztop[0], glseg.y1);
|
||||||
|
glColor4f(fc[0], fc[1], fc[2], fogd2);
|
||||||
|
glTexCoord2f(uprgt.u, uprgt.v);
|
||||||
|
glVertex3f(glseg.x2, ztop[1], glseg.y2);
|
||||||
|
glTexCoord2f(lorgt.u, lorgt.v);
|
||||||
|
glVertex3f(glseg.x2, zbottom[1], glseg.y2);
|
||||||
|
glEnd();
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
glPolygonOffset(0.0f, 0.0f);
|
||||||
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||||
|
gl_RenderState.EnableFog(true);
|
||||||
|
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f);
|
||||||
|
gl_RenderState.EnableTexture(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
void FGLRenderer::RenderMultipassStuff()
|
void FGLRenderer::RenderMultipassStuff()
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -197,11 +197,12 @@ struct FModelVertex
|
||||||
class FModelVertexBuffer : public FVertexBuffer
|
class FModelVertexBuffer : public FVertexBuffer
|
||||||
{
|
{
|
||||||
int mIndexFrame[2];
|
int mIndexFrame[2];
|
||||||
unsigned int ibo_id;
|
FModelVertex *vbo_ptr;
|
||||||
|
uint32_t ibo_id;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FModelVertexBuffer(bool needindex);
|
FModelVertexBuffer(bool needindex, bool singleframe);
|
||||||
~FModelVertexBuffer();
|
~FModelVertexBuffer();
|
||||||
|
|
||||||
FModelVertex *LockVertexBuffer(unsigned int size);
|
FModelVertex *LockVertexBuffer(unsigned int size);
|
||||||
|
@ -210,7 +211,7 @@ public:
|
||||||
unsigned int *LockIndexBuffer(unsigned int size);
|
unsigned int *LockIndexBuffer(unsigned int size);
|
||||||
void UnlockIndexBuffer();
|
void UnlockIndexBuffer();
|
||||||
|
|
||||||
unsigned int SetupFrame(unsigned int frame1, unsigned int frame2);
|
unsigned int SetupFrame(unsigned int frame1, unsigned int frame2, unsigned int size);
|
||||||
void BindVBO();
|
void BindVBO();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -73,32 +73,17 @@ EXTERN_CVAR(Int, gl_fogmode)
|
||||||
extern TDeletingArray<FVoxel *> Voxels;
|
extern TDeletingArray<FVoxel *> Voxels;
|
||||||
extern TDeletingArray<FVoxelDef *> VoxelDefs;
|
extern TDeletingArray<FVoxelDef *> VoxelDefs;
|
||||||
|
|
||||||
|
|
||||||
class DeletingModelArray : public TArray<FModel *>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
~DeletingModelArray()
|
|
||||||
{
|
|
||||||
for(unsigned i=0;i<Size();i++)
|
|
||||||
{
|
|
||||||
delete (*this)[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
DeletingModelArray Models;
|
DeletingModelArray Models;
|
||||||
|
|
||||||
|
|
||||||
void gl_LoadModels()
|
void gl_LoadModels()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
for (int i = Models.Size() - 1; i >= 0; i--)
|
for (int i = Models.Size() - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
Models[i]->BuildVertexBuffer();
|
Models[i]->BuildVertexBuffer();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void gl_FlushModels()
|
void gl_FlushModels()
|
||||||
|
@ -111,16 +96,22 @@ void gl_FlushModels()
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
|
// Uses a hardware buffer if either single frame (i.e. no interpolation needed)
|
||||||
|
// or shading is available (interpolation is done by the vertex shader)
|
||||||
//
|
//
|
||||||
|
// If interpolation has to be done on the CPU side this will fall back
|
||||||
|
// to CPU-side arrays.
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
FModelVertexBuffer::FModelVertexBuffer(bool needindex)
|
FModelVertexBuffer::FModelVertexBuffer(bool needindex, bool singleframe)
|
||||||
|
: FVertexBuffer(singleframe || gl.glslversion > 0)
|
||||||
{
|
{
|
||||||
|
vbo_ptr = nullptr;
|
||||||
ibo_id = 0;
|
ibo_id = 0;
|
||||||
if (needindex)
|
if (needindex)
|
||||||
{
|
{
|
||||||
glGenBuffers(1, &ibo_id);
|
glGenBuffers(1, &ibo_id); // The index buffer can always be a real buffer.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,6 +152,10 @@ FModelVertexBuffer::~FModelVertexBuffer()
|
||||||
{
|
{
|
||||||
glDeleteBuffers(1, &ibo_id);
|
glDeleteBuffers(1, &ibo_id);
|
||||||
}
|
}
|
||||||
|
if (vbo_ptr != nullptr)
|
||||||
|
{
|
||||||
|
delete[] vbo_ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -171,9 +166,19 @@ FModelVertexBuffer::~FModelVertexBuffer()
|
||||||
|
|
||||||
FModelVertex *FModelVertexBuffer::LockVertexBuffer(unsigned int size)
|
FModelVertex *FModelVertexBuffer::LockVertexBuffer(unsigned int size)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
if (vbo_id > 0)
|
||||||
glBufferData(GL_ARRAY_BUFFER, size * sizeof(FModelVertex), NULL, GL_STATIC_DRAW);
|
{
|
||||||
return (FModelVertex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, size * sizeof(FModelVertex), GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_BUFFER_BIT);
|
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, size * sizeof(FModelVertex), nullptr, GL_STATIC_DRAW);
|
||||||
|
return (FModelVertex*)glMapBufferRange(GL_ARRAY_BUFFER, 0, size * sizeof(FModelVertex), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (vbo_ptr != nullptr) delete[] vbo_ptr;
|
||||||
|
vbo_ptr = new FModelVertex[size];
|
||||||
|
memset(vbo_ptr, 0, size * sizeof(FModelVertex));
|
||||||
|
return vbo_ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -184,8 +189,11 @@ FModelVertex *FModelVertexBuffer::LockVertexBuffer(unsigned int size)
|
||||||
|
|
||||||
void FModelVertexBuffer::UnlockVertexBuffer()
|
void FModelVertexBuffer::UnlockVertexBuffer()
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
if (vbo_id > 0)
|
||||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
{
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
||||||
|
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -204,7 +212,7 @@ unsigned int *FModelVertexBuffer::LockIndexBuffer(unsigned int size)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,8 +224,11 @@ unsigned int *FModelVertexBuffer::LockIndexBuffer(unsigned int size)
|
||||||
|
|
||||||
void FModelVertexBuffer::UnlockIndexBuffer()
|
void FModelVertexBuffer::UnlockIndexBuffer()
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id);
|
if (ibo_id > 0)
|
||||||
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
|
{
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id);
|
||||||
|
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,21 +238,44 @@ void FModelVertexBuffer::UnlockIndexBuffer()
|
||||||
// This must be called after gl_RenderState.Apply!
|
// This must be called after gl_RenderState.Apply!
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
static TArray<FModelVertex> iBuffer;
|
||||||
|
|
||||||
unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int frame2)
|
unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int frame2, unsigned int size)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
||||||
if (gl.glslversion > 0)
|
if (vbo_id > 0)
|
||||||
{
|
{
|
||||||
glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame1].x);
|
if (gl.glslversion > 0)
|
||||||
glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame1].u);
|
{
|
||||||
glVertexAttribPointer(VATTR_VERTEX2, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame2].x);
|
glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame1].x);
|
||||||
|
glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame1].u);
|
||||||
|
glVertexAttribPointer(VATTR_VERTEX2, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame2].x);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// only used for single frame models so there is no vertex2 here, which has no use without a shader.
|
||||||
|
glVertexPointer(3, GL_FLOAT, sizeof(FModelVertex), &VMO[frame1].x);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, sizeof(FModelVertex), &VMO[frame1].u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (frame1 == frame2 || size == 0 || gl_RenderState.GetInterpolationFactor() == 0.f)
|
||||||
|
{
|
||||||
|
glVertexPointer(3, GL_FLOAT, sizeof(FModelVertex), &vbo_ptr[frame1].x);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, sizeof(FModelVertex), &vbo_ptr[frame1].u);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// only used for single frame models so there is no vertex2 here, which has no use without a shader.
|
// must interpolate
|
||||||
glVertexPointer(3, GL_FLOAT, sizeof(FModelVertex), &VMO[frame1].x);
|
iBuffer.Resize(size);
|
||||||
glTexCoordPointer(2, GL_FLOAT, sizeof(FModelVertex), &VMO[frame1].u);
|
glVertexPointer(3, GL_FLOAT, sizeof(FModelVertex), &iBuffer[0].x);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, sizeof(FModelVertex), &vbo_ptr[frame1].u);
|
||||||
|
float frac = gl_RenderState.GetInterpolationFactor();
|
||||||
|
for (unsigned i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
iBuffer[i].x = vbo_ptr[frame1 + i].x * (1.f - frac) + vbo_ptr[frame2 + i].x * frac;
|
||||||
|
iBuffer[i].y = vbo_ptr[frame1 + i].y * (1.f - frac) + vbo_ptr[frame2 + i].y * frac;
|
||||||
|
iBuffer[i].z = vbo_ptr[frame1 + i].z * (1.f - frac) + vbo_ptr[frame2 + i].z * frac;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return frame1;
|
return frame1;
|
||||||
}
|
}
|
||||||
|
@ -254,7 +288,7 @@ unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int fr
|
||||||
|
|
||||||
FModel::~FModel()
|
FModel::~FModel()
|
||||||
{
|
{
|
||||||
if (mVBuf != NULL) delete mVBuf;
|
if (mVBuf != nullptr) delete mVBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -266,8 +300,8 @@ static int * SpriteModelHash;
|
||||||
|
|
||||||
static void DeleteModelHash()
|
static void DeleteModelHash()
|
||||||
{
|
{
|
||||||
if (SpriteModelHash != NULL) delete [] SpriteModelHash;
|
if (SpriteModelHash != nullptr) delete [] SpriteModelHash;
|
||||||
SpriteModelHash = NULL;
|
SpriteModelHash = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -278,12 +312,15 @@ static void DeleteModelHash()
|
||||||
|
|
||||||
static int FindGFXFile(FString & fn)
|
static int FindGFXFile(FString & fn)
|
||||||
{
|
{
|
||||||
|
int lump = Wads.CheckNumForFullName(fn); // if we find something that matches the name plus the extension, return it and do not enter the substitution logic below.
|
||||||
|
if (lump != -1) return lump;
|
||||||
|
|
||||||
int best = -1;
|
int best = -1;
|
||||||
int dot = fn.LastIndexOf('.');
|
int dot = fn.LastIndexOf('.');
|
||||||
int slash = fn.LastIndexOf('/');
|
int slash = fn.LastIndexOf('/');
|
||||||
if (dot > slash) fn.Truncate(dot);
|
if (dot > slash) fn.Truncate(dot);
|
||||||
|
|
||||||
static const char * extensions[] = { ".png", ".jpg", ".tga", ".pcx", NULL };
|
static const char * extensions[] = { ".png", ".jpg", ".tga", ".pcx", nullptr };
|
||||||
|
|
||||||
for (const char ** extp=extensions; *extp; extp++)
|
for (const char ** extp=extensions; *extp; extp++)
|
||||||
{
|
{
|
||||||
|
@ -300,7 +337,7 @@ static int FindGFXFile(FString & fn)
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
FTexture * LoadSkin(const char * path, const char * fn)
|
FTextureID LoadSkin(const char * path, const char * fn)
|
||||||
{
|
{
|
||||||
FString buffer;
|
FString buffer;
|
||||||
|
|
||||||
|
@ -309,11 +346,11 @@ FTexture * LoadSkin(const char * path, const char * fn)
|
||||||
int texlump = FindGFXFile(buffer);
|
int texlump = FindGFXFile(buffer);
|
||||||
if (texlump>=0)
|
if (texlump>=0)
|
||||||
{
|
{
|
||||||
return TexMan.FindTexture(Wads.GetLumpFullName(texlump), FTexture::TEX_Any, FTextureManager::TEXMAN_TryAny);
|
return TexMan.CheckForTexture(Wads.GetLumpFullName(texlump), FTexture::TEX_Any, FTextureManager::TEXMAN_TryAny);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return NULL;
|
return FNullTextureID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,9 +381,9 @@ static int ModelFrameHash(FSpriteModelFrame * smf)
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
static FModel * FindModel(const char * path, const char * modelfile)
|
static unsigned FindModel(const char * path, const char * modelfile)
|
||||||
{
|
{
|
||||||
FModel * model = NULL;
|
FModel * model = nullptr;
|
||||||
FString fullname;
|
FString fullname;
|
||||||
|
|
||||||
fullname.Format("%s%s", path, modelfile);
|
fullname.Format("%s%s", path, modelfile);
|
||||||
|
@ -355,12 +392,12 @@ static FModel * FindModel(const char * path, const char * modelfile)
|
||||||
if (lump<0)
|
if (lump<0)
|
||||||
{
|
{
|
||||||
Printf("FindModel: '%s' not found\n", fullname.GetChars());
|
Printf("FindModel: '%s' not found\n", fullname.GetChars());
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i< (int)Models.Size(); i++)
|
for(unsigned i = 0; i< Models.Size(); i++)
|
||||||
{
|
{
|
||||||
if (!Models[i]->mFileName.CompareNoCase(fullname)) return Models[i];
|
if (!Models[i]->mFileName.CompareNoCase(fullname)) return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int len = Wads.LumpLength(lump);
|
int len = Wads.LumpLength(lump);
|
||||||
|
@ -380,32 +417,31 @@ static FModel * FindModel(const char * path, const char * modelfile)
|
||||||
model = new FMD3Model;
|
model = new FMD3Model;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model != NULL)
|
if (model != nullptr)
|
||||||
{
|
{
|
||||||
if (!model->Load(path, lump, buffer, len))
|
if (!model->Load(path, lump, buffer, len))
|
||||||
{
|
{
|
||||||
delete model;
|
delete model;
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// try loading as a voxel
|
// try loading as a voxel
|
||||||
FVoxel *voxel = R_LoadKVX(lump);
|
FVoxel *voxel = R_LoadKVX(lump);
|
||||||
if (voxel != NULL)
|
if (voxel != nullptr)
|
||||||
{
|
{
|
||||||
model = new FVoxelModel(voxel, true);
|
model = new FVoxelModel(voxel, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Printf("LoadModel: Unknown model format in '%s'\n", fullname.GetChars());
|
Printf("LoadModel: Unknown model format in '%s'\n", fullname.GetChars());
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The vertex buffer cannot be initialized here because this gets called before OpenGL is initialized
|
// The vertex buffer cannot be initialized here because this gets called before OpenGL is initialized
|
||||||
model->mFileName = fullname;
|
model->mFileName = fullname;
|
||||||
Models.Push(model);
|
return Models.Push(model);
|
||||||
return model;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -444,8 +480,9 @@ void gl_InitModels()
|
||||||
{
|
{
|
||||||
FVoxelModel *md = (FVoxelModel*)Models[VoxelDefs[i]->Voxel->VoxelIndex];
|
FVoxelModel *md = (FVoxelModel*)Models[VoxelDefs[i]->Voxel->VoxelIndex];
|
||||||
memset(&smf, 0, sizeof(smf));
|
memset(&smf, 0, sizeof(smf));
|
||||||
smf.models[0] = md;
|
smf.modelIDs[1] = smf.modelIDs[2] = smf.modelIDs[3] = -1;
|
||||||
smf.skins[0] = md->GetPaletteTexture();
|
smf.modelIDs[0] = VoxelDefs[i]->Voxel->VoxelIndex;
|
||||||
|
smf.skinIDs[0] = md->GetPaletteTexture();
|
||||||
smf.xscale = smf.yscale = smf.zscale = VoxelDefs[i]->Scale;
|
smf.xscale = smf.yscale = smf.zscale = VoxelDefs[i]->Scale;
|
||||||
smf.angleoffset = VoxelDefs[i]->AngleOffset.Degrees;
|
smf.angleoffset = VoxelDefs[i]->AngleOffset.Degrees;
|
||||||
if (VoxelDefs[i]->PlacedSpin != 0)
|
if (VoxelDefs[i]->PlacedSpin != 0)
|
||||||
|
@ -474,6 +511,7 @@ void gl_InitModels()
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&smf, 0, sizeof(smf));
|
memset(&smf, 0, sizeof(smf));
|
||||||
|
smf.modelIDs[0] = smf.modelIDs[1] = smf.modelIDs[2] = smf.modelIDs[3] = -1;
|
||||||
while ((Lump = Wads.FindLump("MODELDEF", &lastLump)) != -1)
|
while ((Lump = Wads.FindLump("MODELDEF", &lastLump)) != -1)
|
||||||
{
|
{
|
||||||
FScanner sc(Lump);
|
FScanner sc(Lump);
|
||||||
|
@ -483,10 +521,11 @@ void gl_InitModels()
|
||||||
{
|
{
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
memset(&smf, 0, sizeof(smf));
|
memset(&smf, 0, sizeof(smf));
|
||||||
|
smf.modelIDs[1] = smf.modelIDs[2] = smf.modelIDs[3] = -1;
|
||||||
smf.xscale=smf.yscale=smf.zscale=1.f;
|
smf.xscale=smf.yscale=smf.zscale=1.f;
|
||||||
|
|
||||||
smf.type = PClass::FindClass(sc.String);
|
smf.type = PClass::FindClass(sc.String);
|
||||||
if (!smf.type || smf.type->Defaults == NULL)
|
if (!smf.type || smf.type->Defaults == nullptr)
|
||||||
{
|
{
|
||||||
sc.ScriptError("MODELDEF: Unknown actor type '%s'\n", sc.String);
|
sc.ScriptError("MODELDEF: Unknown actor type '%s'\n", sc.String);
|
||||||
}
|
}
|
||||||
|
@ -505,15 +544,15 @@ void gl_InitModels()
|
||||||
else if (sc.Compare("model"))
|
else if (sc.Compare("model"))
|
||||||
{
|
{
|
||||||
sc.MustGetNumber();
|
sc.MustGetNumber();
|
||||||
index=sc.Number;
|
index = sc.Number;
|
||||||
if (index<0 || index>=MAX_MODELS_PER_FRAME)
|
if (index < 0 || index >= MAX_MODELS_PER_FRAME)
|
||||||
{
|
{
|
||||||
sc.ScriptError("Too many models in %s", smf.type->TypeName.GetChars());
|
sc.ScriptError("Too many models in %s", smf.type->TypeName.GetChars());
|
||||||
}
|
}
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
FixPathSeperator(sc.String);
|
FixPathSeperator(sc.String);
|
||||||
smf.models[index] = FindModel(path.GetChars(), sc.String);
|
smf.modelIDs[index] = FindModel(path.GetChars(), sc.String);
|
||||||
if (!smf.models[index])
|
if (smf.modelIDs[index] == -1)
|
||||||
{
|
{
|
||||||
Printf("%s: model not found in %s\n", sc.String, path.GetChars());
|
Printf("%s: model not found in %s\n", sc.String, path.GetChars());
|
||||||
}
|
}
|
||||||
|
@ -521,11 +560,11 @@ void gl_InitModels()
|
||||||
else if (sc.Compare("scale"))
|
else if (sc.Compare("scale"))
|
||||||
{
|
{
|
||||||
sc.MustGetFloat();
|
sc.MustGetFloat();
|
||||||
smf.xscale=sc.Float;
|
smf.xscale = sc.Float;
|
||||||
sc.MustGetFloat();
|
sc.MustGetFloat();
|
||||||
smf.yscale=sc.Float;
|
smf.yscale = sc.Float;
|
||||||
sc.MustGetFloat();
|
sc.MustGetFloat();
|
||||||
smf.zscale=sc.Float;
|
smf.zscale = sc.Float;
|
||||||
}
|
}
|
||||||
// [BB] Added zoffset reading.
|
// [BB] Added zoffset reading.
|
||||||
// Now it must be considered deprecated.
|
// Now it must be considered deprecated.
|
||||||
|
@ -631,12 +670,12 @@ void gl_InitModels()
|
||||||
FixPathSeperator(sc.String);
|
FixPathSeperator(sc.String);
|
||||||
if (sc.Compare(""))
|
if (sc.Compare(""))
|
||||||
{
|
{
|
||||||
smf.skins[index]=NULL;
|
smf.skinIDs[index]=FNullTextureID();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
smf.skins[index]=LoadSkin(path.GetChars(), sc.String);
|
smf.skinIDs[index] = LoadSkin(path.GetChars(), sc.String);
|
||||||
if (smf.skins[index] == NULL)
|
if (!smf.skinIDs[index].isValid())
|
||||||
{
|
{
|
||||||
Printf("Skin '%s' not found in '%s'\n",
|
Printf("Skin '%s' not found in '%s'\n",
|
||||||
sc.String, smf.type->TypeName.GetChars());
|
sc.String, smf.type->TypeName.GetChars());
|
||||||
|
@ -678,9 +717,10 @@ void gl_InitModels()
|
||||||
if (isframe)
|
if (isframe)
|
||||||
{
|
{
|
||||||
sc.MustGetString();
|
sc.MustGetString();
|
||||||
if (smf.models[index]!=NULL)
|
if (smf.modelIDs[index] != -1)
|
||||||
{
|
{
|
||||||
smf.modelframes[index] = smf.models[index]->FindFrame(sc.String);
|
FModel *model = Models[smf.modelIDs[index]];
|
||||||
|
smf.modelframes[index] = model->FindFrame(sc.String);
|
||||||
if (smf.modelframes[index]==-1) sc.ScriptError("Unknown frame '%s' in %s", sc.String, smf.type->TypeName.GetChars());
|
if (smf.modelframes[index]==-1) sc.ScriptError("Unknown frame '%s' in %s", sc.String, smf.type->TypeName.GetChars());
|
||||||
}
|
}
|
||||||
else smf.modelframes[index] = -1;
|
else smf.modelframes[index] = -1;
|
||||||
|
@ -765,7 +805,7 @@ FSpriteModelFrame * gl_FindModelFrame(const PClass * ti, int sprite, int frame,
|
||||||
if (frame < sprdef->numframes)
|
if (frame < sprdef->numframes)
|
||||||
{
|
{
|
||||||
spriteframe_t *sprframe = &SpriteFrames[sprdef->spriteframes + frame];
|
spriteframe_t *sprframe = &SpriteFrames[sprdef->spriteframes + frame];
|
||||||
if (sprframe->Voxel != NULL)
|
if (sprframe->Voxel != nullptr)
|
||||||
{
|
{
|
||||||
int index = sprframe->Voxel->VoxeldefIndex;
|
int index = sprframe->Voxel->VoxeldefIndex;
|
||||||
if (dropped && sprframe->Voxel->DroppedSpin !=sprframe->Voxel->PlacedSpin) index++;
|
if (dropped && sprframe->Voxel->DroppedSpin !=sprframe->Voxel->PlacedSpin) index++;
|
||||||
|
@ -773,7 +813,7 @@ FSpriteModelFrame * gl_FindModelFrame(const PClass * ti, int sprite, int frame,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -792,7 +832,7 @@ void gl_RenderFrameModels( const FSpriteModelFrame *smf,
|
||||||
{
|
{
|
||||||
// [BB] Frame interpolation: Find the FSpriteModelFrame smfNext which follows after smf in the animation
|
// [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.
|
// and the scalar value inter ( element of [0,1) ), both necessary to determine the interpolated frame.
|
||||||
FSpriteModelFrame * smfNext = NULL;
|
FSpriteModelFrame * smfNext = nullptr;
|
||||||
double inter = 0.;
|
double inter = 0.;
|
||||||
if( gl_interpolate_model_frames && !(smf->flags & MDL_NOINTERPOLATION) )
|
if( gl_interpolate_model_frames && !(smf->flags & MDL_NOINTERPOLATION) )
|
||||||
{
|
{
|
||||||
|
@ -839,17 +879,17 @@ void gl_RenderFrameModels( const FSpriteModelFrame *smf,
|
||||||
|
|
||||||
for(int i=0; i<MAX_MODELS_PER_FRAME; i++)
|
for(int i=0; i<MAX_MODELS_PER_FRAME; i++)
|
||||||
{
|
{
|
||||||
FModel * mdl = smf->models[i];
|
if (smf->modelIDs[i] != -1)
|
||||||
|
|
||||||
if (mdl!=NULL)
|
|
||||||
{
|
{
|
||||||
|
FModel * mdl = Models[smf->modelIDs[i]];
|
||||||
|
FTexture *tex = smf->skinIDs[i].isValid()? TexMan(smf->skinIDs[i]) : nullptr;
|
||||||
mdl->BuildVertexBuffer();
|
mdl->BuildVertexBuffer();
|
||||||
gl_RenderState.SetVertexBuffer(mdl->mVBuf);
|
gl_RenderState.SetVertexBuffer(mdl->mVBuf);
|
||||||
|
|
||||||
if ( smfNext && smf->modelframes[i] != smfNext->modelframes[i] )
|
if ( smfNext && smf->modelframes[i] != smfNext->modelframes[i] )
|
||||||
mdl->RenderFrame(smf->skins[i], smf->modelframes[i], smfNext->modelframes[i], inter, translation);
|
mdl->RenderFrame(tex, smf->modelframes[i], smfNext->modelframes[i], inter, translation);
|
||||||
else
|
else
|
||||||
mdl->RenderFrame(smf->skins[i], smf->modelframes[i], smf->modelframes[i], 0.f, translation);
|
mdl->RenderFrame(tex, smf->modelframes[i], smf->modelframes[i], 0.f, translation);
|
||||||
|
|
||||||
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
|
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
|
||||||
}
|
}
|
||||||
|
@ -949,12 +989,12 @@ void gl_RenderModel(GLSprite * spr)
|
||||||
gl_RenderState.mModelMatrix.rotate(-smf->rolloffset, 1, 0, 0);
|
gl_RenderState.mModelMatrix.rotate(-smf->rolloffset, 1, 0, 0);
|
||||||
|
|
||||||
// consider the pixel stretching. For non-voxels this must be factored out here
|
// consider the pixel stretching. For non-voxels this must be factored out here
|
||||||
float stretch = (smf->models[0] != NULL ? smf->models[0]->getAspectFactor() : 1.f) / glset.pixelstretch;
|
float stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor() : 1.f) / glset.pixelstretch;
|
||||||
gl_RenderState.mModelMatrix.scale(1, stretch, 1);
|
gl_RenderState.mModelMatrix.scale(1, stretch, 1);
|
||||||
|
|
||||||
|
|
||||||
gl_RenderState.EnableModelMatrix(true);
|
gl_RenderState.EnableModelMatrix(true);
|
||||||
gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, spr->actor->GetClass(), NULL, translation );
|
gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, spr->actor->GetClass(), nullptr, translation );
|
||||||
gl_RenderState.EnableModelMatrix(false);
|
gl_RenderState.EnableModelMatrix(false);
|
||||||
|
|
||||||
glDepthFunc(GL_LESS);
|
glDepthFunc(GL_LESS);
|
||||||
|
@ -975,7 +1015,7 @@ void gl_RenderHUDModel(pspdef_t *psp, float ofsX, float ofsY)
|
||||||
FSpriteModelFrame *smf = gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->state->sprite, psp->state->GetFrame(), false);
|
FSpriteModelFrame *smf = gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->state->sprite, psp->state->GetFrame(), false);
|
||||||
|
|
||||||
// [BB] No model found for this sprite, so we can't render anything.
|
// [BB] No model found for this sprite, so we can't render anything.
|
||||||
if ( smf == NULL )
|
if ( smf == nullptr )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
glDepthFunc(GL_LEQUAL);
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
@ -1012,7 +1052,7 @@ void gl_RenderHUDModel(pspdef_t *psp, float ofsX, float ofsY)
|
||||||
gl_RenderState.mViewMatrix.rotate(-smf->rolloffset, 1, 0, 0);
|
gl_RenderState.mViewMatrix.rotate(-smf->rolloffset, 1, 0, 0);
|
||||||
gl_RenderState.ApplyMatrices();
|
gl_RenderState.ApplyMatrices();
|
||||||
|
|
||||||
gl_RenderFrameModels( smf, psp->state, psp->tics, playermo->player->ReadyWeapon->GetClass(), NULL, 0 );
|
gl_RenderFrameModels( smf, psp->state, psp->tics, playermo->player->ReadyWeapon->GetClass(), nullptr, 0 );
|
||||||
|
|
||||||
glDepthFunc(GL_LESS);
|
glDepthFunc(GL_LESS);
|
||||||
if (!( playermo->RenderStyle == LegacyRenderStyles[STYLE_Normal] ))
|
if (!( playermo->RenderStyle == LegacyRenderStyles[STYLE_Normal] ))
|
||||||
|
@ -1027,11 +1067,11 @@ void gl_RenderHUDModel(pspdef_t *psp, float ofsX, float ofsY)
|
||||||
|
|
||||||
bool gl_IsHUDModelForPlayerAvailable (player_t * player)
|
bool gl_IsHUDModelForPlayerAvailable (player_t * player)
|
||||||
{
|
{
|
||||||
if ( (player == NULL) || (player->ReadyWeapon == NULL) || (player->psprites[0].state == NULL) )
|
if ( (player == nullptr) || (player->ReadyWeapon == nullptr) || (player->psprites[0].state == nullptr) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
FState* state = player->psprites[0].state;
|
FState* state = player->psprites[0].state;
|
||||||
FSpriteModelFrame *smf = gl_FindModelFrame(player->ReadyWeapon->GetClass(), state->sprite, state->GetFrame(), false);
|
FSpriteModelFrame *smf = gl_FindModelFrame(player->ReadyWeapon->GetClass(), state->sprite, state->GetFrame(), false);
|
||||||
return ( smf != NULL );
|
return ( smf != nullptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef __GL_MODELS_H_
|
#ifndef __GL_MODELS_H_
|
||||||
#define __GL_MODELS_H_
|
#define __GL_MODELS_H_
|
||||||
|
|
||||||
|
#include "tarray.h"
|
||||||
#include "gl/utility/gl_geometric.h"
|
#include "gl/utility/gl_geometric.h"
|
||||||
#include "gl/data/gl_vertexbuffer.h"
|
#include "gl/data/gl_vertexbuffer.h"
|
||||||
#include "p_pspr.h"
|
#include "p_pspr.h"
|
||||||
|
@ -16,7 +17,7 @@ enum { VX, VZ, VY };
|
||||||
#define MD3_MAGIC 0x33504449
|
#define MD3_MAGIC 0x33504449
|
||||||
#define NUMVERTEXNORMALS 162
|
#define NUMVERTEXNORMALS 162
|
||||||
|
|
||||||
FTexture * LoadSkin(const char * path, const char * fn);
|
FTextureID LoadSkin(const char * path, const char * fn);
|
||||||
|
|
||||||
|
|
||||||
class FModel
|
class FModel
|
||||||
|
@ -33,6 +34,7 @@ public:
|
||||||
virtual int FindFrame(const char * name) = 0;
|
virtual int FindFrame(const char * name) = 0;
|
||||||
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0) = 0;
|
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0) = 0;
|
||||||
virtual void BuildVertexBuffer() = 0;
|
virtual void BuildVertexBuffer() = 0;
|
||||||
|
virtual void AddSkins(BYTE *hitlist) = 0;
|
||||||
void DestroyVertexBuffer()
|
void DestroyVertexBuffer()
|
||||||
{
|
{
|
||||||
delete mVBuf;
|
delete mVBuf;
|
||||||
|
@ -124,7 +126,7 @@ protected:
|
||||||
int mLumpNum;
|
int mLumpNum;
|
||||||
DMDHeader header;
|
DMDHeader header;
|
||||||
DMDInfo info;
|
DMDInfo info;
|
||||||
FTexture ** skins;
|
FTextureID * skins;
|
||||||
ModelFrame * frames;
|
ModelFrame * frames;
|
||||||
bool allowTexComp; // Allow texture compression with this.
|
bool allowTexComp; // Allow texture compression with this.
|
||||||
|
|
||||||
|
@ -154,6 +156,8 @@ public:
|
||||||
virtual int FindFrame(const char * name);
|
virtual int FindFrame(const char * name);
|
||||||
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
||||||
virtual void LoadGeometry();
|
virtual void LoadGeometry();
|
||||||
|
virtual void AddSkins(BYTE *hitlist);
|
||||||
|
|
||||||
void UnloadGeometry();
|
void UnloadGeometry();
|
||||||
void BuildVertexBuffer();
|
void BuildVertexBuffer();
|
||||||
|
|
||||||
|
@ -201,7 +205,7 @@ class FMD3Model : public FModel
|
||||||
int numTriangles;
|
int numTriangles;
|
||||||
int numSkins;
|
int numSkins;
|
||||||
|
|
||||||
FTexture ** skins;
|
FTextureID * skins;
|
||||||
MD3Triangle * tris;
|
MD3Triangle * tris;
|
||||||
MD3TexCoord * texcoords;
|
MD3TexCoord * texcoords;
|
||||||
MD3Vertex * vertices;
|
MD3Vertex * vertices;
|
||||||
|
@ -259,6 +263,7 @@ public:
|
||||||
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
||||||
void LoadGeometry();
|
void LoadGeometry();
|
||||||
void BuildVertexBuffer();
|
void BuildVertexBuffer();
|
||||||
|
virtual void AddSkins(BYTE *hitlist);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FVoxelVertexHash
|
struct FVoxelVertexHash
|
||||||
|
@ -295,7 +300,7 @@ class FVoxelModel : public FModel
|
||||||
protected:
|
protected:
|
||||||
FVoxel *mVoxel;
|
FVoxel *mVoxel;
|
||||||
bool mOwningVoxel; // if created through MODELDEF deleting this object must also delete the voxel object
|
bool mOwningVoxel; // if created through MODELDEF deleting this object must also delete the voxel object
|
||||||
FTexture *mPalette;
|
FTextureID mPalette;
|
||||||
unsigned int mNumIndices;
|
unsigned int mNumIndices;
|
||||||
TArray<FModelVertex> mVertices;
|
TArray<FModelVertex> mVertices;
|
||||||
TArray<unsigned int> mIndices;
|
TArray<unsigned int> mIndices;
|
||||||
|
@ -311,7 +316,8 @@ public:
|
||||||
void Initialize();
|
void Initialize();
|
||||||
virtual int FindFrame(const char * name);
|
virtual int FindFrame(const char * name);
|
||||||
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0);
|
||||||
FTexture *GetPaletteTexture() const { return mPalette; }
|
virtual void AddSkins(BYTE *hitlist);
|
||||||
|
FTextureID GetPaletteTexture() const { return mPalette; }
|
||||||
void BuildVertexBuffer();
|
void BuildVertexBuffer();
|
||||||
float getAspectFactor();
|
float getAspectFactor();
|
||||||
};
|
};
|
||||||
|
@ -338,8 +344,8 @@ enum
|
||||||
|
|
||||||
struct FSpriteModelFrame
|
struct FSpriteModelFrame
|
||||||
{
|
{
|
||||||
FModel * models[MAX_MODELS_PER_FRAME];
|
int modelIDs[MAX_MODELS_PER_FRAME];
|
||||||
FTexture * skins[MAX_MODELS_PER_FRAME];
|
FTextureID skinIDs[MAX_MODELS_PER_FRAME];
|
||||||
int modelframes[MAX_MODELS_PER_FRAME];
|
int modelframes[MAX_MODELS_PER_FRAME];
|
||||||
float xscale, yscale, zscale;
|
float xscale, yscale, zscale;
|
||||||
// [BB] Added zoffset, rotation parameters and flags.
|
// [BB] Added zoffset, rotation parameters and flags.
|
||||||
|
@ -368,4 +374,21 @@ void gl_RenderModel(GLSprite * spr);
|
||||||
void gl_RenderHUDModel(pspdef_t *psp, float ofsx, float ofsy);
|
void gl_RenderHUDModel(pspdef_t *psp, float ofsx, float ofsy);
|
||||||
bool gl_IsHUDModelForPlayerAvailable (player_t * player);
|
bool gl_IsHUDModelForPlayerAvailable (player_t * player);
|
||||||
|
|
||||||
|
|
||||||
|
class DeletingModelArray : public TArray<FModel *>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
~DeletingModelArray()
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i<Size(); i++)
|
||||||
|
{
|
||||||
|
delete (*this)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DeletingModelArray Models;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -159,7 +159,7 @@ bool FDMDModel::Load(const char * path, int lumpnum, const char * buffer, int le
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate and load in the data.
|
// Allocate and load in the data.
|
||||||
skins = new FTexture *[info.numSkins];
|
skins = new FTextureID[info.numSkins];
|
||||||
|
|
||||||
for (i = 0; i < info.numSkins; i++)
|
for (i = 0; i < info.numSkins; i++)
|
||||||
{
|
{
|
||||||
|
@ -304,7 +304,7 @@ void FDMDModel::BuildVertexBuffer()
|
||||||
int VertexBufferSize = info.numFrames * lodInfo[0].numTriangles * 3;
|
int VertexBufferSize = info.numFrames * lodInfo[0].numTriangles * 3;
|
||||||
unsigned int vindex = 0;
|
unsigned int vindex = 0;
|
||||||
|
|
||||||
mVBuf = new FModelVertexBuffer(false);
|
mVBuf = new FModelVertexBuffer(false, info.numFrames == 1);
|
||||||
FModelVertex *vertptr = mVBuf->LockVertexBuffer(VertexBufferSize);
|
FModelVertex *vertptr = mVBuf->LockVertexBuffer(VertexBufferSize);
|
||||||
|
|
||||||
for (int i = 0; i < info.numFrames; i++)
|
for (int i = 0; i < info.numFrames; i++)
|
||||||
|
@ -336,7 +336,22 @@ void FDMDModel::BuildVertexBuffer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// for skin precaching
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
void FDMDModel::AddSkins(BYTE *hitlist)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < info.numSkins; i++)
|
||||||
|
{
|
||||||
|
if (skins[i].isValid())
|
||||||
|
{
|
||||||
|
hitlist[skins[i].GetIndex()] |= FTexture::TEX_Flat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
|
@ -364,8 +379,8 @@ void FDMDModel::RenderFrame(FTexture * skin, int frameno, int frameno2, double i
|
||||||
|
|
||||||
if (!skin)
|
if (!skin)
|
||||||
{
|
{
|
||||||
if (info.numSkins == 0) return;
|
if (info.numSkins == 0 || !skins[0].isValid()) return;
|
||||||
skin = skins[0];
|
skin = TexMan(skins[0]);
|
||||||
if (!skin) return;
|
if (!skin) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,7 +390,7 @@ void FDMDModel::RenderFrame(FTexture * skin, int frameno, int frameno2, double i
|
||||||
gl_RenderState.SetInterpolationFactor((float)inter);
|
gl_RenderState.SetInterpolationFactor((float)inter);
|
||||||
|
|
||||||
gl_RenderState.Apply();
|
gl_RenderState.Apply();
|
||||||
mVBuf->SetupFrame(frames[frameno].vindex, frames[frameno2].vindex);
|
mVBuf->SetupFrame(frames[frameno].vindex, frames[frameno2].vindex, lodInfo[0].numTriangles * 3);
|
||||||
glDrawArrays(GL_TRIANGLES, 0, lodInfo[0].numTriangles * 3);
|
glDrawArrays(GL_TRIANGLES, 0, lodInfo[0].numTriangles * 3);
|
||||||
gl_RenderState.SetInterpolationFactor(0.f);
|
gl_RenderState.SetInterpolationFactor(0.f);
|
||||||
}
|
}
|
||||||
|
@ -469,7 +484,7 @@ bool FMD2Model::Load(const char * path, int lumpnum, const char * buffer, int le
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
skins = new FTexture *[info.numSkins];
|
skins = new FTextureID[info.numSkins];
|
||||||
|
|
||||||
for (i = 0; i < info.numSkins; i++)
|
for (i = 0; i < info.numSkins; i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -179,14 +179,14 @@ bool FMD3Model::Load(const char * path, int lumpnum, const char * buffer, int le
|
||||||
|
|
||||||
// copy shaders (skins)
|
// copy shaders (skins)
|
||||||
md3_shader_t * shader = (md3_shader_t*)(((char*)ss) + LittleLong(ss->Ofs_Shaders));
|
md3_shader_t * shader = (md3_shader_t*)(((char*)ss) + LittleLong(ss->Ofs_Shaders));
|
||||||
s->skins = new FTexture *[s->numSkins];
|
s->skins = new FTextureID[s->numSkins];
|
||||||
|
|
||||||
for (int i = 0; i < s->numSkins; i++)
|
for (int i = 0; i < s->numSkins; i++)
|
||||||
{
|
{
|
||||||
// [BB] According to the MD3 spec, Name is supposed to include the full path.
|
// [BB] According to the MD3 spec, Name is supposed to include the full path.
|
||||||
s->skins[i] = LoadSkin("", shader[i].Name);
|
s->skins[i] = LoadSkin("", shader[i].Name);
|
||||||
// [BB] Fall back and check if Name is relative.
|
// [BB] Fall back and check if Name is relative.
|
||||||
if (s->skins[i] == NULL)
|
if (!s->skins[i].isValid())
|
||||||
s->skins[i] = LoadSkin(path, shader[i].Name);
|
s->skins[i] = LoadSkin(path, shader[i].Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -255,7 +255,7 @@ void FMD3Model::LoadGeometry()
|
||||||
|
|
||||||
void FMD3Model::BuildVertexBuffer()
|
void FMD3Model::BuildVertexBuffer()
|
||||||
{
|
{
|
||||||
if (mVBuf == NULL)
|
if (mVBuf == nullptr)
|
||||||
{
|
{
|
||||||
LoadGeometry();
|
LoadGeometry();
|
||||||
|
|
||||||
|
@ -269,11 +269,11 @@ void FMD3Model::BuildVertexBuffer()
|
||||||
ibufsize += 3 * surf->numTriangles;
|
ibufsize += 3 * surf->numTriangles;
|
||||||
}
|
}
|
||||||
|
|
||||||
mVBuf = new FModelVertexBuffer(true);
|
mVBuf = new FModelVertexBuffer(true, numFrames == 1);
|
||||||
FModelVertex *vertptr = mVBuf->LockVertexBuffer(vbufsize);
|
FModelVertex *vertptr = mVBuf->LockVertexBuffer(vbufsize);
|
||||||
unsigned int *indxptr = mVBuf->LockIndexBuffer(ibufsize);
|
unsigned int *indxptr = mVBuf->LockIndexBuffer(ibufsize);
|
||||||
|
|
||||||
assert(vertptr != NULL && indxptr != NULL);
|
assert(vertptr != nullptr && indxptr != nullptr);
|
||||||
|
|
||||||
unsigned int vindex = 0, iindex = 0;
|
unsigned int vindex = 0, iindex = 0;
|
||||||
|
|
||||||
|
@ -309,6 +309,27 @@ void FMD3Model::BuildVertexBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// for skin precaching
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
void FMD3Model::AddSkins(BYTE *hitlist)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numSurfaces; i++)
|
||||||
|
{
|
||||||
|
MD3Surface * surf = &surfaces[i];
|
||||||
|
for (int j = 0; j < surf->numSkins; j++)
|
||||||
|
{
|
||||||
|
if (surf->skins[j].isValid())
|
||||||
|
{
|
||||||
|
hitlist[surf->skins[j].GetIndex()] |= FTexture::TEX_Flat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -344,8 +365,8 @@ void FMD3Model::RenderFrame(FTexture * skin, int frameno, int frameno2, double i
|
||||||
FTexture *surfaceSkin = skin;
|
FTexture *surfaceSkin = skin;
|
||||||
if (!surfaceSkin)
|
if (!surfaceSkin)
|
||||||
{
|
{
|
||||||
if (surf->numSkins==0) return;
|
if (surf->numSkins==0 || !surf->skins[0].isValid()) return;
|
||||||
surfaceSkin = surf->skins[0];
|
surfaceSkin = TexMan(surf->skins[0]);
|
||||||
if (!surfaceSkin) return;
|
if (!surfaceSkin) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +375,7 @@ void FMD3Model::RenderFrame(FTexture * skin, int frameno, int frameno2, double i
|
||||||
gl_RenderState.SetMaterial(tex, CLAMP_NONE, translation, -1, false);
|
gl_RenderState.SetMaterial(tex, CLAMP_NONE, translation, -1, false);
|
||||||
|
|
||||||
gl_RenderState.Apply();
|
gl_RenderState.Apply();
|
||||||
mVBuf->SetupFrame(surf->vindex + frameno * surf->numVertices, surf->vindex + frameno2 * surf->numVertices);
|
mVBuf->SetupFrame(surf->vindex + frameno * surf->numVertices, surf->vindex + frameno2 * surf->numVertices, surf->numVertices);
|
||||||
glDrawElements(GL_TRIANGLES, surf->numTriangles * 3, GL_UNSIGNED_INT, (void*)(intptr_t)(surf->iindex * sizeof(unsigned int)));
|
glDrawElements(GL_TRIANGLES, surf->numTriangles * 3, GL_UNSIGNED_INT, (void*)(intptr_t)(surf->iindex * sizeof(unsigned int)));
|
||||||
}
|
}
|
||||||
gl_RenderState.SetInterpolationFactor(0.f);
|
gl_RenderState.SetInterpolationFactor(0.f);
|
||||||
|
@ -370,6 +391,6 @@ FMD3Model::~FMD3Model()
|
||||||
{
|
{
|
||||||
if (frames) delete [] frames;
|
if (frames) delete [] frames;
|
||||||
if (surfaces) delete [] surfaces;
|
if (surfaces) delete [] surfaces;
|
||||||
frames = NULL;
|
frames = nullptr;
|
||||||
surfaces = NULL;
|
surfaces = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,7 +213,7 @@ FVoxelModel::FVoxelModel(FVoxel *voxel, bool owned)
|
||||||
{
|
{
|
||||||
mVoxel = voxel;
|
mVoxel = voxel;
|
||||||
mOwningVoxel = owned;
|
mOwningVoxel = owned;
|
||||||
mPalette = new FVoxelTexture(voxel);
|
mPalette = TexMan.AddTexture(new FVoxelTexture(voxel));
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -224,7 +224,6 @@ FVoxelModel::FVoxelModel(FVoxel *voxel, bool owned)
|
||||||
|
|
||||||
FVoxelModel::~FVoxelModel()
|
FVoxelModel::~FVoxelModel()
|
||||||
{
|
{
|
||||||
delete mPalette;
|
|
||||||
if (mOwningVoxel) delete mVoxel;
|
if (mOwningVoxel) delete mVoxel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +377,7 @@ void FVoxelModel::BuildVertexBuffer()
|
||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
|
|
||||||
mVBuf = new FModelVertexBuffer(true);
|
mVBuf = new FModelVertexBuffer(true, true);
|
||||||
FModelVertex *vertptr = mVBuf->LockVertexBuffer(mVertices.Size());
|
FModelVertex *vertptr = mVBuf->LockVertexBuffer(mVertices.Size());
|
||||||
unsigned int *indxptr = mVBuf->LockIndexBuffer(mIndices.Size());
|
unsigned int *indxptr = mVBuf->LockIndexBuffer(mIndices.Size());
|
||||||
|
|
||||||
|
@ -398,6 +397,17 @@ void FVoxelModel::BuildVertexBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// for skin precaching
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
void FVoxelModel::AddSkins(BYTE *hitlist)
|
||||||
|
{
|
||||||
|
hitlist[mPalette.GetIndex()] |= FTexture::TEX_Flat;
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -443,7 +453,7 @@ void FVoxelModel::RenderFrame(FTexture * skin, int frame, int frame2, double int
|
||||||
gl_RenderState.SetMaterial(tex, CLAMP_NOFILTER, translation, -1, false);
|
gl_RenderState.SetMaterial(tex, CLAMP_NOFILTER, translation, -1, false);
|
||||||
|
|
||||||
gl_RenderState.Apply();
|
gl_RenderState.Apply();
|
||||||
mVBuf->SetupFrame(0, 0);
|
mVBuf->SetupFrame(0, 0, 0);
|
||||||
glDrawElements(GL_TRIANGLES, mNumIndices, GL_UNSIGNED_INT, (void*)(intptr_t)0);
|
glDrawElements(GL_TRIANGLES, mNumIndices, GL_UNSIGNED_INT, (void*)(intptr_t)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -439,6 +439,11 @@ public:
|
||||||
mInterpolationFactor = fac;
|
mInterpolationFactor = fac;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float GetInterpolationFactor()
|
||||||
|
{
|
||||||
|
return mInterpolationFactor;
|
||||||
|
}
|
||||||
|
|
||||||
// Backwards compatibility crap follows
|
// Backwards compatibility crap follows
|
||||||
void ApplyFixedFunction();
|
void ApplyFixedFunction();
|
||||||
void DrawColormapOverlay();
|
void DrawColormapOverlay();
|
||||||
|
|
|
@ -1019,23 +1019,10 @@ bool FGLInterface::UsesColormap() const
|
||||||
|
|
||||||
void FGLInterface::PrecacheTexture(FTexture *tex, int cache)
|
void FGLInterface::PrecacheTexture(FTexture *tex, int cache)
|
||||||
{
|
{
|
||||||
if (tex != NULL)
|
if (cache & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky))
|
||||||
{
|
{
|
||||||
if (cache)
|
FMaterial * gltex = FMaterial::ValidateTexture(tex, false);
|
||||||
{
|
if (gltex) gltex->Precache();
|
||||||
if (gl_precache)
|
|
||||||
{
|
|
||||||
if (cache & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky))
|
|
||||||
{
|
|
||||||
FMaterial * gltex = FMaterial::ValidateTexture(tex, false);
|
|
||||||
if (gltex) gltex->Precache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (tex->gl_info.Material[0]) tex->gl_info.Material[0]->Clean(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1047,15 +1034,8 @@ void FGLInterface::PrecacheTexture(FTexture *tex, int cache)
|
||||||
|
|
||||||
void FGLInterface::PrecacheSprite(FTexture *tex, SpriteHits &hits)
|
void FGLInterface::PrecacheSprite(FTexture *tex, SpriteHits &hits)
|
||||||
{
|
{
|
||||||
if (hits.CountUsed() == 0)
|
FMaterial * gltex = FMaterial::ValidateTexture(tex, true);
|
||||||
{
|
if (gltex) gltex->PrecacheList(hits);
|
||||||
if (tex->gl_info.Material[1]) tex->gl_info.Material[1]->Clean(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FMaterial * gltex = FMaterial::ValidateTexture(tex, true);
|
|
||||||
if (gltex) gltex->PrecacheList(hits);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1070,6 +1050,8 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap<PClassActor*, bool> &actorhit
|
||||||
SpriteHits **spritehitlist = new SpriteHits*[TexMan.NumTextures()];
|
SpriteHits **spritehitlist = new SpriteHits*[TexMan.NumTextures()];
|
||||||
TMap<PClassActor*, bool>::Iterator it(actorhitlist);
|
TMap<PClassActor*, bool>::Iterator it(actorhitlist);
|
||||||
TMap<PClassActor*, bool>::Pair *pair;
|
TMap<PClassActor*, bool>::Pair *pair;
|
||||||
|
BYTE *modellist = new BYTE[Models.Size()];
|
||||||
|
memset(modellist, 0, Models.Size());
|
||||||
memset(spritehitlist, 0, sizeof(SpriteHits**) * TexMan.NumTextures());
|
memset(spritehitlist, 0, sizeof(SpriteHits**) * TexMan.NumTextures());
|
||||||
|
|
||||||
// this isn't done by the main code so it needs to be done here first:
|
// this isn't done by the main code so it needs to be done here first:
|
||||||
|
@ -1095,6 +1077,9 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap<PClassActor*, bool> &actorhit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check all used actors.
|
||||||
|
// 1. mark all sprites associated with its states
|
||||||
|
// 2. mark all model data and skins associated with its states
|
||||||
while (it.NextPair(pair))
|
while (it.NextPair(pair))
|
||||||
{
|
{
|
||||||
PClassActor *cls = pair->Key;
|
PClassActor *cls = pair->Key;
|
||||||
|
@ -1103,11 +1088,29 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap<PClassActor*, bool> &actorhit
|
||||||
for (int i = 0; i < cls->NumOwnedStates; i++)
|
for (int i = 0; i < cls->NumOwnedStates; i++)
|
||||||
{
|
{
|
||||||
spritelist[cls->OwnedStates[i].sprite].Insert(gltrans, true);
|
spritelist[cls->OwnedStates[i].sprite].Insert(gltrans, true);
|
||||||
|
FSpriteModelFrame * smf = gl_FindModelFrame(cls, cls->OwnedStates[i].sprite, cls->OwnedStates[i].Frame, false);
|
||||||
|
if (smf != NULL)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_MODELS_PER_FRAME; i++)
|
||||||
|
{
|
||||||
|
if (smf->skinIDs[i].isValid())
|
||||||
|
{
|
||||||
|
texhitlist[smf->skinIDs[i].GetIndex()] |= FTexture::TEX_Flat;
|
||||||
|
}
|
||||||
|
else if (smf->modelIDs[i] != -1)
|
||||||
|
{
|
||||||
|
Models[smf->modelIDs[i]]->AddSkins(texhitlist);
|
||||||
|
}
|
||||||
|
if (smf->modelIDs[i] != -1)
|
||||||
|
{
|
||||||
|
modellist[smf->modelIDs[i]] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Precache textures (and sprites).
|
// mark all sprite textures belonging to the marked sprites.
|
||||||
|
|
||||||
for (int i = (int)(sprites.Size() - 1); i >= 0; i--)
|
for (int i = (int)(sprites.Size() - 1); i >= 0; i--)
|
||||||
{
|
{
|
||||||
if (spritelist[i].CountUsed())
|
if (spritelist[i].CountUsed())
|
||||||
|
@ -1129,14 +1132,59 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap<PClassActor*, bool> &actorhit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete everything unused before creating any new resources to avoid memory usage peaks.
|
||||||
|
|
||||||
|
// delete unused models
|
||||||
|
for (unsigned i = 0; i < Models.Size(); i++)
|
||||||
|
{
|
||||||
|
if (!modellist[i]) Models[i]->DestroyVertexBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete unused textures
|
||||||
int cnt = TexMan.NumTextures();
|
int cnt = TexMan.NumTextures();
|
||||||
for (int i = cnt - 1; i >= 0; i--)
|
for (int i = cnt - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
PrecacheTexture(TexMan.ByIndex(i), texhitlist[i]);
|
FTexture *tex = TexMan.ByIndex(i);
|
||||||
if (spritehitlist[i] != nullptr) PrecacheSprite(TexMan.ByIndex(i), *spritehitlist[i]);
|
if (tex != nullptr)
|
||||||
|
{
|
||||||
|
if (!texhitlist[i])
|
||||||
|
{
|
||||||
|
if (tex->gl_info.Material[0]) tex->gl_info.Material[0]->Clean(true);
|
||||||
|
}
|
||||||
|
if (spritehitlist[i] == nullptr || (*spritehitlist[i]).CountUsed() == 0)
|
||||||
|
{
|
||||||
|
if (tex->gl_info.Material[1]) tex->gl_info.Material[1]->Clean(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gl_precache)
|
||||||
|
{
|
||||||
|
// cache all used textures
|
||||||
|
for (int i = cnt - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
FTexture *tex = TexMan.ByIndex(i);
|
||||||
|
if (tex != nullptr)
|
||||||
|
{
|
||||||
|
PrecacheTexture(tex, texhitlist[i]);
|
||||||
|
if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CountUsed() > 0)
|
||||||
|
{
|
||||||
|
PrecacheSprite(tex, *spritehitlist[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cache all used models
|
||||||
|
for (unsigned i = 0; i < Models.Size(); i++)
|
||||||
|
{
|
||||||
|
if (modellist[i])
|
||||||
|
Models[i]->BuildVertexBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delete[] spritehitlist;
|
delete[] spritehitlist;
|
||||||
delete[] spritelist;
|
delete[] spritelist;
|
||||||
|
delete[] modellist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -287,8 +287,8 @@ void GLSprite::Draw(int pass)
|
||||||
if (drawBillboardFacingCamera) {
|
if (drawBillboardFacingCamera) {
|
||||||
// [CMB] Rotate relative to camera XY position, not just camera direction,
|
// [CMB] Rotate relative to camera XY position, not just camera direction,
|
||||||
// which is nicer in VR
|
// which is nicer in VR
|
||||||
float xrel = xcenter - GLRenderer->mViewActor->X();
|
float xrel = xcenter - ViewPos.X;
|
||||||
float yrel = ycenter - GLRenderer->mViewActor->Y();
|
float yrel = ycenter - ViewPos.Y;
|
||||||
float absAngleDeg = RAD2DEG(atan2(-yrel, xrel));
|
float absAngleDeg = RAD2DEG(atan2(-yrel, xrel));
|
||||||
float counterRotationDeg = 270. - GLRenderer->mAngles.Yaw.Degrees; // counteracts existing sprite rotation
|
float counterRotationDeg = 270. - GLRenderer->mAngles.Yaw.Degrees; // counteracts existing sprite rotation
|
||||||
float relAngleDeg = counterRotationDeg + absAngleDeg;
|
float relAngleDeg = counterRotationDeg + absAngleDeg;
|
||||||
|
|
|
@ -171,10 +171,13 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CheckGlowing();
|
void CheckGlowing();
|
||||||
|
bool PutWallCompat(int passflag);
|
||||||
void PutWall(bool translucent);
|
void PutWall(bool translucent);
|
||||||
void PutPortal(int ptype);
|
void PutPortal(int ptype);
|
||||||
void CheckTexturePosition();
|
void CheckTexturePosition();
|
||||||
|
|
||||||
|
void RenderFogBoundaryCompat();
|
||||||
|
|
||||||
void Put3DWall(lightlist_t * lightlist, bool translucent);
|
void Put3DWall(lightlist_t * lightlist, bool translucent);
|
||||||
void SplitWallComplex(sector_t * frontsector, bool translucent, float maplightbottomleft, float maplightbottomright);
|
void SplitWallComplex(sector_t * frontsector, bool translucent, float maplightbottomleft, float maplightbottomright);
|
||||||
void SplitWall(sector_t * frontsector, bool translucent);
|
void SplitWall(sector_t * frontsector, bool translucent);
|
||||||
|
|
|
@ -139,6 +139,11 @@ void GLWall::PutWall(bool translucent)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (gl.lightmethod == LM_SOFTWARE && !translucent)
|
||||||
|
{
|
||||||
|
// This is not yet ready.
|
||||||
|
//if (PutWallCompat(passflag[type])) return;
|
||||||
|
}
|
||||||
|
|
||||||
bool masked;
|
bool masked;
|
||||||
|
|
||||||
|
|
|
@ -228,16 +228,23 @@ void GLWall::RenderFogBoundary()
|
||||||
{
|
{
|
||||||
if (gl_fogmode && gl_fixedcolormap == 0)
|
if (gl_fogmode && gl_fixedcolormap == 0)
|
||||||
{
|
{
|
||||||
int rel = rellight + getExtraLight();
|
if (gl.glslversion > 0.f)
|
||||||
gl_SetFog(lightlevel, rel, &Colormap, false);
|
{
|
||||||
gl_RenderState.SetEffect(EFF_FOGBOUNDARY);
|
int rel = rellight + getExtraLight();
|
||||||
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
gl_SetFog(lightlevel, rel, &Colormap, false);
|
||||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
gl_RenderState.SetEffect(EFF_FOGBOUNDARY);
|
||||||
glPolygonOffset(-1.0f, -128.0f);
|
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
||||||
RenderWall(RWF_BLANK);
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||||
glPolygonOffset(0.0f, 0.0f);
|
glPolygonOffset(-1.0f, -128.0f);
|
||||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
RenderWall(RWF_BLANK);
|
||||||
gl_RenderState.SetEffect(EFF_NONE);
|
glPolygonOffset(0.0f, 0.0f);
|
||||||
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||||
|
gl_RenderState.SetEffect(EFF_NONE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RenderFogBoundaryCompat();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,12 +262,19 @@ void GLWall::RenderMirrorSurface()
|
||||||
Vector v(glseg.y2-glseg.y1, 0 ,-glseg.x2+glseg.x1);
|
Vector v(glseg.y2-glseg.y1, 0 ,-glseg.x2+glseg.x1);
|
||||||
v.Normalize();
|
v.Normalize();
|
||||||
|
|
||||||
// we use texture coordinates and texture matrix to pass the normal stuff to the shader so that the default vertex buffer format can be used as is.
|
if (gl.glslversion >= 0.f)
|
||||||
lolft.u = lorgt.u = uplft.u = uprgt.u = v.X();
|
{
|
||||||
lolft.v = lorgt.v = uplft.v = uprgt.v = v.Z();
|
// we use texture coordinates and texture matrix to pass the normal stuff to the shader so that the default vertex buffer format can be used as is.
|
||||||
|
lolft.u = lorgt.u = uplft.u = uprgt.u = v.X();
|
||||||
|
lolft.v = lorgt.v = uplft.v = uprgt.v = v.Z();
|
||||||
|
|
||||||
gl_RenderState.EnableTextureMatrix(true);
|
gl_RenderState.EnableTextureMatrix(true);
|
||||||
gl_RenderState.mTextureMatrix.computeNormalMatrix(gl_RenderState.mViewMatrix);
|
gl_RenderState.mTextureMatrix.computeNormalMatrix(gl_RenderState.mViewMatrix);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glNormal3fv(&v[0]);
|
||||||
|
}
|
||||||
|
|
||||||
// Use sphere mapping for this
|
// Use sphere mapping for this
|
||||||
gl_RenderState.SetEffect(EFF_SPHEREMAP);
|
gl_RenderState.SetEffect(EFF_SPHEREMAP);
|
||||||
|
|
|
@ -168,7 +168,7 @@ void gl_LoadExtensions()
|
||||||
gl.vendorstring = (char*)glGetString(GL_VENDOR);
|
gl.vendorstring = (char*)glGetString(GL_VENDOR);
|
||||||
gl.lightmethod = LM_SOFTWARE;
|
gl.lightmethod = LM_SOFTWARE;
|
||||||
|
|
||||||
if (gl.version >= 3.3f || CheckExtension("GL_ARB_sampler_objects"))
|
if ((gl.version >= 3.3f || CheckExtension("GL_ARB_sampler_objects")) && !Args->CheckParm("-nosampler"))
|
||||||
{
|
{
|
||||||
gl.flags |= RFL_SAMPLER_OBJECTS;
|
gl.flags |= RFL_SAMPLER_OBJECTS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,8 @@ static void* SunGetProcAddress (const GLubyte* name)
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
// disable inlining here because it creates an incredible amount of bloat in this file.
|
||||||
|
#pragma inline_depth(0)
|
||||||
#pragma warning(disable: 4055)
|
#pragma warning(disable: 4055)
|
||||||
#pragma warning(disable: 4054)
|
#pragma warning(disable: 4054)
|
||||||
#pragma warning(disable: 4996)
|
#pragma warning(disable: 4996)
|
||||||
|
|
|
@ -300,7 +300,7 @@ const FHardwareTexture *FGLTexture::Bind(int texunit, int clampmode, int transla
|
||||||
translation = GLTranslationPalette::GetInternalTranslation(translation);
|
translation = GLTranslationPalette::GetInternalTranslation(translation);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needmipmap = (clampmode <= CLAMP_XY) || !(gl.flags & RFL_SAMPLER_OBJECTS);
|
bool needmipmap = (clampmode <= CLAMP_XY);
|
||||||
|
|
||||||
FHardwareTexture *hwtex = CreateHwTexture();
|
FHardwareTexture *hwtex = CreateHwTexture();
|
||||||
|
|
||||||
|
@ -345,9 +345,9 @@ const FHardwareTexture *FGLTexture::Bind(int texunit, int clampmode, int transla
|
||||||
}
|
}
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
}
|
}
|
||||||
if (!needmipmap) clampmode = CLAMP_XY_NOMIP;
|
|
||||||
if (tex->bHasCanvas) static_cast<FCanvasTexture*>(tex)->NeedUpdate();
|
if (tex->bHasCanvas) static_cast<FCanvasTexture*>(tex)->NeedUpdate();
|
||||||
if (lastSampler != clampmode || lastTranslation != translation)
|
if (translation != lastTranslation) lastSampler = 254;
|
||||||
|
if (lastSampler != clampmode)
|
||||||
lastSampler = GLRenderer->mSamplerManager->Bind(texunit, clampmode, lastSampler);
|
lastSampler = GLRenderer->mSamplerManager->Bind(texunit, clampmode, lastSampler);
|
||||||
lastTranslation = translation;
|
lastTranslation = translation;
|
||||||
return hwtex;
|
return hwtex;
|
||||||
|
|
|
@ -86,7 +86,6 @@ void FSamplerManager::UnbindAll()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < FHardwareTexture::MAX_TEXTURES; i++)
|
for (int i = 0; i < FHardwareTexture::MAX_TEXTURES; i++)
|
||||||
{
|
{
|
||||||
mLastBound[i] = 0;
|
|
||||||
glBindSampler(i, 0);
|
glBindSampler(i, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,12 +96,8 @@ BYTE FSamplerManager::Bind(int texunit, int num, int lastval)
|
||||||
if (gl.flags & RFL_SAMPLER_OBJECTS)
|
if (gl.flags & RFL_SAMPLER_OBJECTS)
|
||||||
{
|
{
|
||||||
unsigned int samp = mSamplers[num];
|
unsigned int samp = mSamplers[num];
|
||||||
//if (samp != mLastBound[texunit])
|
glBindSampler(texunit, samp);
|
||||||
{
|
return 255;
|
||||||
glBindSampler(texunit, samp);
|
|
||||||
mLastBound[texunit] = samp;
|
|
||||||
return 255;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -112,7 +107,7 @@ BYTE FSamplerManager::Bind(int texunit, int num, int lastval)
|
||||||
case CLAMP_NONE:
|
case CLAMP_NONE:
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
if (lastval > CLAMP_XY_NOMIP)
|
if (lastval >= CLAMP_XY_NOMIP)
|
||||||
{
|
{
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter);
|
||||||
|
@ -123,7 +118,7 @@ BYTE FSamplerManager::Bind(int texunit, int num, int lastval)
|
||||||
case CLAMP_X:
|
case CLAMP_X:
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
if (lastval > CLAMP_XY_NOMIP)
|
if (lastval >= CLAMP_XY_NOMIP)
|
||||||
{
|
{
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter);
|
||||||
|
@ -134,7 +129,18 @@ BYTE FSamplerManager::Bind(int texunit, int num, int lastval)
|
||||||
case CLAMP_Y:
|
case CLAMP_Y:
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
if (lastval > CLAMP_XY_NOMIP)
|
if (lastval >= CLAMP_XY_NOMIP)
|
||||||
|
{
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_filter_anisotropic);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CLAMP_XY:
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
if (lastval >= CLAMP_XY_NOMIP)
|
||||||
{
|
{
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter);
|
||||||
|
@ -143,15 +149,11 @@ BYTE FSamplerManager::Bind(int texunit, int num, int lastval)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CLAMP_XY_NOMIP:
|
case CLAMP_XY_NOMIP:
|
||||||
case CLAMP_XY:
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
if (lastval > CLAMP_XY_NOMIP)
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].magfilter);
|
||||||
{
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TexFilter[gl_texture_filter].minfilter);
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TexFilter[gl_texture_filter].magfilter);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_filter_anisotropic);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CLAMP_NOFILTER:
|
case CLAMP_NOFILTER:
|
||||||
|
|
|
@ -8,7 +8,6 @@ class FSamplerManager
|
||||||
// We need 6 different samplers: 4 for the different clamping modes,
|
// We need 6 different samplers: 4 for the different clamping modes,
|
||||||
// one for 2D-textures and one for voxel textures
|
// one for 2D-textures and one for voxel textures
|
||||||
unsigned int mSamplers[7];
|
unsigned int mSamplers[7];
|
||||||
unsigned int mLastBound[FHardwareTexture::MAX_TEXTURES];
|
|
||||||
|
|
||||||
void UnbindAll();
|
void UnbindAll();
|
||||||
|
|
||||||
|
|
|
@ -5567,6 +5567,11 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
|
||||||
if (argCount >= 2)
|
if (argCount >= 2)
|
||||||
{
|
{
|
||||||
const char *a, *b;
|
const char *a, *b;
|
||||||
|
// If the string indicies are the same, then they are the same string.
|
||||||
|
if (args[0] == args[1])
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
a = FBehavior::StaticLookupString(args[0]);
|
a = FBehavior::StaticLookupString(args[0]);
|
||||||
b = FBehavior::StaticLookupString(args[1]);
|
b = FBehavior::StaticLookupString(args[1]);
|
||||||
|
|
||||||
|
|
|
@ -1132,7 +1132,7 @@ FUNC(LS_Teleport_Line)
|
||||||
|
|
||||||
static void ThrustThingHelper(AActor *it, DAngle angle, double force, INTBOOL nolimit)
|
static void ThrustThingHelper(AActor *it, DAngle angle, double force, INTBOOL nolimit)
|
||||||
{
|
{
|
||||||
it->VelFromAngle(angle, force);
|
it->Thrust(angle, force);
|
||||||
if (!nolimit)
|
if (!nolimit)
|
||||||
{
|
{
|
||||||
it->Vel.X = clamp(it->Vel.X, -MAXMOVE, MAXMOVE);
|
it->Vel.X = clamp(it->Vel.X, -MAXMOVE, MAXMOVE);
|
||||||
|
|
Loading…
Reference in a new issue