mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-15 17:01:28 +00:00
6e49f0bf8f
Bone model support in GLES and ZScript quaternions.
495 lines
11 KiB
C++
495 lines
11 KiB
C++
//
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Copyright(C) 2004-2016 Christoph Oelckers
|
|
// All rights reserved.
|
|
//
|
|
// 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 Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with this program. If not, see http://www.gnu.org/licenses/
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
|
|
#ifndef __GL_SHADERS_H__
|
|
#define __GL_SHADERS_H__
|
|
|
|
#include <map>
|
|
|
|
#include "gles_renderstate.h"
|
|
#include "name.h"
|
|
|
|
extern bool gl_shaderactive;
|
|
|
|
struct HWViewpointUniforms;
|
|
|
|
namespace OpenGLESRenderer
|
|
{
|
|
class FShaderCollection;
|
|
|
|
//==========================================================================
|
|
//
|
|
//
|
|
//==========================================================================
|
|
|
|
class FUniform1i
|
|
{
|
|
int mIndex;
|
|
|
|
public:
|
|
void Init(GLuint hShader, const GLchar *name)
|
|
{
|
|
mIndex = glGetUniformLocation(hShader, name);
|
|
}
|
|
|
|
void Set(int newvalue)
|
|
{
|
|
glUniform1i(mIndex, newvalue);
|
|
}
|
|
};
|
|
|
|
class FBufferedUniform1i
|
|
{
|
|
int mBuffer;
|
|
int mIndex;
|
|
|
|
public:
|
|
void Init(GLuint hShader, const GLchar *name)
|
|
{
|
|
mIndex = glGetUniformLocation(hShader, name);
|
|
mBuffer = 0;
|
|
}
|
|
|
|
void Set(int newvalue)
|
|
{
|
|
if (newvalue != mBuffer)
|
|
{
|
|
mBuffer = newvalue;
|
|
glUniform1i(mIndex, newvalue);
|
|
}
|
|
}
|
|
};
|
|
|
|
class FBufferedUniform4i
|
|
{
|
|
int mBuffer[4];
|
|
int mIndex;
|
|
|
|
public:
|
|
void Init(GLuint hShader, const GLchar *name)
|
|
{
|
|
mIndex = glGetUniformLocation(hShader, name);
|
|
memset(mBuffer, 0, sizeof(mBuffer));
|
|
}
|
|
|
|
void Set(const int *newvalue)
|
|
{
|
|
if (memcmp(newvalue, mBuffer, sizeof(mBuffer)))
|
|
{
|
|
memcpy(mBuffer, newvalue, sizeof(mBuffer));
|
|
glUniform4iv(mIndex, 1, newvalue);
|
|
}
|
|
}
|
|
};
|
|
|
|
class FBufferedUniform1f
|
|
{
|
|
float mBuffer;
|
|
int mIndex;
|
|
|
|
public:
|
|
void Init(GLuint hShader, const GLchar *name)
|
|
{
|
|
mIndex = glGetUniformLocation(hShader, name);
|
|
mBuffer = 0;
|
|
}
|
|
|
|
void Set(float newvalue)
|
|
{
|
|
if (newvalue != mBuffer)
|
|
{
|
|
mBuffer = newvalue;
|
|
glUniform1f(mIndex, newvalue);
|
|
}
|
|
}
|
|
};
|
|
|
|
class FBufferedUniform2f
|
|
{
|
|
float mBuffer[2];
|
|
int mIndex;
|
|
|
|
public:
|
|
void Init(GLuint hShader, const GLchar *name)
|
|
{
|
|
mIndex = glGetUniformLocation(hShader, name);
|
|
memset(mBuffer, 0, sizeof(mBuffer));
|
|
}
|
|
|
|
void Set(const float *newvalue)
|
|
{
|
|
if (memcmp(newvalue, mBuffer, sizeof(mBuffer)))
|
|
{
|
|
memcpy(mBuffer, newvalue, sizeof(mBuffer));
|
|
glUniform2fv(mIndex, 1, newvalue);
|
|
}
|
|
}
|
|
|
|
void Set(float f1, float f2)
|
|
{
|
|
if (mBuffer[0] != f1 || mBuffer[1] != f2)
|
|
{
|
|
mBuffer[0] = f1;
|
|
mBuffer[1] = f2;
|
|
glUniform2fv(mIndex, 1, mBuffer);
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
class FBufferedUniform4f
|
|
{
|
|
float mBuffer[4];
|
|
int mIndex;
|
|
|
|
public:
|
|
void Init(GLuint hShader, const GLchar *name)
|
|
{
|
|
mIndex = glGetUniformLocation(hShader, name);
|
|
memset(mBuffer, 0, sizeof(mBuffer));
|
|
}
|
|
|
|
void Set(const float *newvalue)
|
|
{
|
|
if (memcmp(newvalue, mBuffer, sizeof(mBuffer)))
|
|
{
|
|
memcpy(mBuffer, newvalue, sizeof(mBuffer));
|
|
glUniform4fv(mIndex, 1, newvalue);
|
|
}
|
|
}
|
|
};
|
|
|
|
class FUniform4f
|
|
{
|
|
int mIndex;
|
|
|
|
public:
|
|
void Init(GLuint hShader, const GLchar *name)
|
|
{
|
|
mIndex = glGetUniformLocation(hShader, name);
|
|
}
|
|
|
|
void Set(const float *newvalue)
|
|
{
|
|
glUniform4fv(mIndex, 1, newvalue);
|
|
}
|
|
|
|
void Set(float a, float b, float c, float d)
|
|
{
|
|
glUniform4f(mIndex, a, b, c, d);
|
|
}
|
|
|
|
void Set(PalEntry newvalue)
|
|
{
|
|
glUniform4f(mIndex, newvalue.r / 255.f, newvalue.g / 255.f, newvalue.b / 255.f, newvalue.a / 255.f);
|
|
}
|
|
|
|
};
|
|
|
|
class FBufferedUniformPE
|
|
{
|
|
FVector4PalEntry mBuffer;
|
|
int mIndex;
|
|
|
|
public:
|
|
void Init(GLuint hShader, const GLchar *name)
|
|
{
|
|
mIndex = glGetUniformLocation(hShader, name);
|
|
mBuffer = 0;
|
|
}
|
|
|
|
void Set(const FVector4PalEntry &newvalue)
|
|
{
|
|
if (newvalue != mBuffer)
|
|
{
|
|
mBuffer = newvalue;
|
|
glUniform4f(mIndex, newvalue.r, newvalue.g, newvalue.b, newvalue.a);
|
|
}
|
|
}
|
|
};
|
|
|
|
class FBufferedUniformMat4fv
|
|
{
|
|
VSMatrix mBuffer;
|
|
int mIndex;
|
|
|
|
public:
|
|
void Init(GLuint hShader, const GLchar* name)
|
|
{
|
|
mIndex = glGetUniformLocation(hShader, name);
|
|
mBuffer = 0;
|
|
}
|
|
|
|
void Set(const VSMatrix* newvalue)
|
|
{
|
|
//if (memcmp(newvalue, &mBuffer, sizeof(mBuffer))) // Breaks 2D menu for some reason..
|
|
{
|
|
mBuffer = *newvalue;
|
|
glUniformMatrix4fv(mIndex, 1, false, (float*)newvalue);
|
|
}
|
|
}
|
|
};
|
|
|
|
class ShaderFlavourData
|
|
{
|
|
public:
|
|
int textureMode;
|
|
int texFlags;
|
|
int blendFlags;
|
|
bool twoDFog;
|
|
bool fogEnabled;
|
|
bool fogEquationRadial;
|
|
bool colouredFog;
|
|
bool doDesaturate;
|
|
bool dynLightsMod;
|
|
bool dynLightsSub;
|
|
bool dynLightsAdd;
|
|
bool useULightLevel;
|
|
bool useObjectColor2;
|
|
bool useGlowTopColor;
|
|
bool useGlowBottomColor;
|
|
bool useColorMap;
|
|
|
|
bool buildLighting;
|
|
bool bandedSwLight;
|
|
|
|
#ifdef NPOT_EMULATION
|
|
bool npotEmulation;
|
|
#endif
|
|
|
|
bool hasSpotLight;
|
|
bool paletteInterpolate;
|
|
};
|
|
|
|
class FShader
|
|
{
|
|
friend class FShaderCollection;
|
|
friend class FGLRenderState;
|
|
|
|
FName mName;
|
|
|
|
FString mVertProg;
|
|
FString mFragProg;
|
|
FString mFragProg2;
|
|
FString mLightProg;
|
|
FString mDefinesBase;
|
|
|
|
/////
|
|
public: class ShaderVariantData
|
|
{
|
|
public:
|
|
|
|
unsigned int hShader = 0;
|
|
unsigned int hVertProg = 0;
|
|
unsigned int hFragProg = 0;
|
|
|
|
//int ProjectionMatrix_index = 0;
|
|
//int ViewMatrix_index = 0;
|
|
//int NormalViewMatrix_index = 0;
|
|
|
|
FBufferedUniformMat4fv muProjectionMatrix;
|
|
FBufferedUniformMat4fv muViewMatrix;
|
|
FBufferedUniformMat4fv muNormalViewMatrix;
|
|
|
|
FUniform4f muCameraPos;
|
|
FUniform4f muClipLine;
|
|
|
|
FBufferedUniform1f muGlobVis;
|
|
FBufferedUniform1i muPalLightLevels;
|
|
FBufferedUniform1i muViewHeight;
|
|
FBufferedUniform1f muClipHeight;
|
|
FBufferedUniform1f muClipHeightDirection;
|
|
FBufferedUniform1i muShadowmapFilter;
|
|
/////
|
|
|
|
FBufferedUniform1f muDesaturation;
|
|
FBufferedUniform1i muFogEnabled;
|
|
FBufferedUniform1i muTextureMode;
|
|
FBufferedUniform4f muLightParms;
|
|
FBufferedUniform2f muClipSplit;
|
|
FBufferedUniform1i muBoneIndexBase;
|
|
FBufferedUniform4i muLightRange;
|
|
FBufferedUniformPE muFogColor;
|
|
FBufferedUniform4f muDynLightColor;
|
|
FBufferedUniformPE muObjectColor;
|
|
FBufferedUniformPE muObjectColor2;
|
|
FBufferedUniformPE muAddColor;
|
|
FBufferedUniformPE muTextureBlendColor;
|
|
FBufferedUniformPE muTextureModulateColor;
|
|
FBufferedUniformPE muTextureAddColor;
|
|
FUniform4f muGlowBottomColor;
|
|
FUniform4f muGlowTopColor;
|
|
FUniform4f muGlowBottomPlane;
|
|
FUniform4f muGlowTopPlane;
|
|
FUniform4f muGradientBottomPlane;
|
|
FUniform4f muGradientTopPlane;
|
|
FUniform4f muSplitBottomPlane;
|
|
FUniform4f muSplitTopPlane;
|
|
FUniform4f muDetailParms;
|
|
FBufferedUniform1f muInterpolationFactor;
|
|
FBufferedUniform1f muAlphaThreshold;
|
|
FBufferedUniform2f muSpecularMaterial;
|
|
FBufferedUniform1f muTimer;
|
|
#ifdef NPOT_EMULATION
|
|
FBufferedUniform2f muNpotEmulation;
|
|
#endif
|
|
FUniform4f muFixedColormapStart;
|
|
FUniform4f muFixedColormapRange;
|
|
|
|
|
|
int lights_index = 0;
|
|
int bones_index = 0;
|
|
int modelmatrix_index = 0;
|
|
int normalmodelmatrix_index = 0;
|
|
int texturematrix_index = 0;
|
|
|
|
int currentglowstate = 0;
|
|
int currentgradientstate = 0;
|
|
int currentsplitstate = 0;
|
|
int currentcliplinestate = 0;
|
|
int currentfixedcolormap = 0;
|
|
bool currentTextureMatrixState = true;// by setting the matrix state to 'true' it is guaranteed to be set the first time the render state gets applied.
|
|
bool currentModelMatrixState = true;
|
|
|
|
unsigned int GetHandle() const { return hShader; }
|
|
};
|
|
|
|
std::map<uint32_t, ShaderVariantData*> variants;
|
|
|
|
ShaderVariantData* cur = 0;
|
|
|
|
public:
|
|
FShader(const char *name)
|
|
: mName(name)
|
|
{
|
|
|
|
}
|
|
|
|
~FShader();
|
|
|
|
bool Load(const char * name, const char * vert_prog_lump, const char * fragprog, const char * fragprog2, const char * light_fragprog, const char *defines);
|
|
bool Configure(const char* name, const char* vert_prog_lump, const char* fragprog, const char* fragprog2, const char* light_fragprog, const char* defines);
|
|
|
|
void LoadVariant();
|
|
|
|
|
|
uint32_t CreateShaderTag(ShaderFlavourData &flavour)
|
|
{
|
|
uint32_t tag = 0;
|
|
tag |= (flavour.textureMode & 0x7);
|
|
|
|
tag |= (flavour.texFlags & 7) << 3;
|
|
|
|
tag |= (flavour.blendFlags & 7) << 6;
|
|
|
|
tag |= (flavour.twoDFog & 1) << 7;
|
|
tag |= (flavour.fogEnabled & 1) << 8;
|
|
tag |= (flavour.fogEquationRadial & 1) << 9;
|
|
tag |= (flavour.colouredFog & 1) << 10;
|
|
|
|
tag |= (flavour.doDesaturate & 1) << 11;
|
|
|
|
tag |= (flavour.dynLightsMod & 1) << 12;
|
|
tag |= (flavour.dynLightsSub & 1) << 13;
|
|
tag |= (flavour.dynLightsAdd & 1) << 14;
|
|
tag |= (flavour.useULightLevel & 1) << 15;
|
|
tag |= (flavour.useObjectColor2 & 1) << 16;
|
|
tag |= (flavour.useGlowTopColor & 1) << 17;
|
|
tag |= (flavour.useGlowBottomColor & 1) << 18;
|
|
tag |= (flavour.useColorMap & 1) << 19;
|
|
tag |= (flavour.buildLighting & 1) << 20;
|
|
tag |= (flavour.bandedSwLight & 1) << 21;
|
|
|
|
#ifdef NPOT_EMULATION
|
|
tag |= (flavour.npotEmulation & 1) << 22;
|
|
#endif
|
|
tag |= (flavour.hasSpotLight & 1) << 23;
|
|
tag |= (flavour.paletteInterpolate & 1) << 24;
|
|
|
|
return tag;
|
|
}
|
|
|
|
bool Bind(ShaderFlavourData& flavour);
|
|
|
|
|
|
};
|
|
|
|
//==========================================================================
|
|
//
|
|
// The global shader manager
|
|
//
|
|
//==========================================================================
|
|
class FShaderManager
|
|
{
|
|
public:
|
|
FShaderManager();
|
|
~FShaderManager();
|
|
|
|
FShader *BindEffect(int effect, EPassType passType, ShaderFlavourData& flavour);
|
|
FShader *Get(unsigned int eff, bool alphateston, EPassType passType);
|
|
|
|
void SetActiveShader(FShader::ShaderVariantData *sh);
|
|
private:
|
|
|
|
FShader::ShaderVariantData *mActiveShader = nullptr;
|
|
TArray<FShaderCollection*> mPassShaders;
|
|
|
|
friend class FShader;
|
|
};
|
|
|
|
class FShaderCollection
|
|
{
|
|
TArray<FShader*> mMaterialShaders;
|
|
TArray<FShader*> mMaterialShadersNAT;
|
|
FShader *mEffectShaders[MAX_EFFECTS];
|
|
|
|
void Clean();
|
|
void CompileShaders(EPassType passType);
|
|
|
|
public:
|
|
FShaderCollection(EPassType passType);
|
|
~FShaderCollection();
|
|
FShader *Compile(const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType);
|
|
int Find(const char *mame);
|
|
FShader *BindEffect(int effect, ShaderFlavourData& flavour);
|
|
|
|
FShader *Get(unsigned int eff, bool alphateston)
|
|
{
|
|
// indices 0-2 match the warping modes, 3 no texture, the following are custom
|
|
if (!alphateston && eff <= 2)
|
|
{
|
|
return mMaterialShadersNAT[eff]; // Non-alphatest shaders are only created for default, warp1+2 and brightmap. The rest won't get used anyway
|
|
}
|
|
if (eff < mMaterialShaders.Size())
|
|
{
|
|
return mMaterialShaders[eff];
|
|
}
|
|
else // This can happen if we try and active a user shader which is not loaded, so return default shader so it does not crash
|
|
{
|
|
return mMaterialShaders[0];
|
|
}
|
|
}
|
|
};
|
|
|
|
}
|
|
#endif
|
|
|