mirror of
https://github.com/UberGames/lilium-voyager.git
synced 2024-11-10 06:31:47 +00:00
OpenGL2: Add GPU vertex skinning for IQM models
Using GPU vertex skinning is significantly faster than CPU vertex skinning. Especially since OpenGL2 has to run R_VaoPackNormal() and R_VaoPackTangent() each vertex each frame which causes CPU vertex skinning to be significantly slower than OpenGL1 renderer.
This commit is contained in:
parent
cccd283be8
commit
11337c9fa2
10 changed files with 533 additions and 34 deletions
|
@ -6,6 +6,9 @@ attribute vec4 attr_TexCoord0;
|
||||||
#if defined(USE_VERTEX_ANIMATION)
|
#if defined(USE_VERTEX_ANIMATION)
|
||||||
attribute vec3 attr_Position2;
|
attribute vec3 attr_Position2;
|
||||||
attribute vec3 attr_Normal2;
|
attribute vec3 attr_Normal2;
|
||||||
|
#elif defined(USE_BONE_ANIMATION)
|
||||||
|
attribute vec4 attr_BoneIndexes;
|
||||||
|
attribute vec4 attr_BoneWeights;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uniform vec4 u_FogDistance;
|
uniform vec4 u_FogDistance;
|
||||||
|
@ -22,6 +25,8 @@ uniform mat4 u_ModelViewProjectionMatrix;
|
||||||
|
|
||||||
#if defined(USE_VERTEX_ANIMATION)
|
#if defined(USE_VERTEX_ANIMATION)
|
||||||
uniform float u_VertexLerp;
|
uniform float u_VertexLerp;
|
||||||
|
#elif defined(USE_BONE_ANIMATION)
|
||||||
|
uniform mat4 u_BoneMatrix[MAX_GLSL_BONES];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uniform vec4 u_Color;
|
uniform vec4 u_Color;
|
||||||
|
@ -102,6 +107,15 @@ void main()
|
||||||
#if defined(USE_VERTEX_ANIMATION)
|
#if defined(USE_VERTEX_ANIMATION)
|
||||||
vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
|
vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
|
||||||
vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
|
vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
|
||||||
|
#elif defined(USE_BONE_ANIMATION)
|
||||||
|
mat4 vtxMat = u_BoneMatrix[int(attr_BoneIndexes.x)] * attr_BoneWeights.x;
|
||||||
|
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.y)] * attr_BoneWeights.y;
|
||||||
|
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.z)] * attr_BoneWeights.z;
|
||||||
|
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.w)] * attr_BoneWeights.w;
|
||||||
|
mat3 nrmMat = mat3(cross(vtxMat[1].xyz, vtxMat[2].xyz), cross(vtxMat[2].xyz, vtxMat[0].xyz), cross(vtxMat[0].xyz, vtxMat[1].xyz));
|
||||||
|
|
||||||
|
vec3 position = vec3(vtxMat * vec4(attr_Position, 1.0));
|
||||||
|
vec3 normal = normalize(nrmMat * attr_Normal);
|
||||||
#else
|
#else
|
||||||
vec3 position = attr_Position;
|
vec3 position = attr_Position;
|
||||||
vec3 normal = attr_Normal;
|
vec3 normal = attr_Normal;
|
||||||
|
|
|
@ -4,6 +4,9 @@ attribute vec3 attr_Normal;
|
||||||
#if defined(USE_VERTEX_ANIMATION)
|
#if defined(USE_VERTEX_ANIMATION)
|
||||||
attribute vec3 attr_Position2;
|
attribute vec3 attr_Position2;
|
||||||
attribute vec3 attr_Normal2;
|
attribute vec3 attr_Normal2;
|
||||||
|
#elif defined(USE_BONE_ANIMATION)
|
||||||
|
attribute vec4 attr_BoneIndexes;
|
||||||
|
attribute vec4 attr_BoneWeights;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
attribute vec4 attr_Color;
|
attribute vec4 attr_Color;
|
||||||
|
@ -54,6 +57,8 @@ uniform float u_PortalRange;
|
||||||
|
|
||||||
#if defined(USE_VERTEX_ANIMATION)
|
#if defined(USE_VERTEX_ANIMATION)
|
||||||
uniform float u_VertexLerp;
|
uniform float u_VertexLerp;
|
||||||
|
#elif defined(USE_BONE_ANIMATION)
|
||||||
|
uniform mat4 u_BoneMatrix[MAX_GLSL_BONES];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
varying vec2 var_DiffuseTex;
|
varying vec2 var_DiffuseTex;
|
||||||
|
@ -204,6 +209,15 @@ void main()
|
||||||
#if defined(USE_VERTEX_ANIMATION)
|
#if defined(USE_VERTEX_ANIMATION)
|
||||||
vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
|
vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
|
||||||
vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
|
vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
|
||||||
|
#elif defined(USE_BONE_ANIMATION)
|
||||||
|
mat4 vtxMat = u_BoneMatrix[int(attr_BoneIndexes.x)] * attr_BoneWeights.x;
|
||||||
|
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.y)] * attr_BoneWeights.y;
|
||||||
|
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.z)] * attr_BoneWeights.z;
|
||||||
|
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.w)] * attr_BoneWeights.w;
|
||||||
|
mat3 nrmMat = mat3(cross(vtxMat[1].xyz, vtxMat[2].xyz), cross(vtxMat[2].xyz, vtxMat[0].xyz), cross(vtxMat[0].xyz, vtxMat[1].xyz));
|
||||||
|
|
||||||
|
vec3 position = vec3(vtxMat * vec4(attr_Position, 1.0));
|
||||||
|
vec3 normal = normalize(nrmMat * attr_Normal);
|
||||||
#else
|
#else
|
||||||
vec3 position = attr_Position;
|
vec3 position = attr_Position;
|
||||||
vec3 normal = attr_Normal;
|
vec3 normal = attr_Normal;
|
||||||
|
|
|
@ -12,6 +12,9 @@ attribute vec4 attr_Tangent;
|
||||||
attribute vec3 attr_Position2;
|
attribute vec3 attr_Position2;
|
||||||
attribute vec3 attr_Normal2;
|
attribute vec3 attr_Normal2;
|
||||||
attribute vec4 attr_Tangent2;
|
attribute vec4 attr_Tangent2;
|
||||||
|
#elif defined(USE_BONE_ANIMATION)
|
||||||
|
attribute vec4 attr_BoneIndexes;
|
||||||
|
attribute vec4 attr_BoneWeights;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(USE_LIGHT) && !defined(USE_LIGHT_VECTOR)
|
#if defined(USE_LIGHT) && !defined(USE_LIGHT_VECTOR)
|
||||||
|
@ -48,6 +51,8 @@ uniform mat4 u_ModelMatrix;
|
||||||
|
|
||||||
#if defined(USE_VERTEX_ANIMATION)
|
#if defined(USE_VERTEX_ANIMATION)
|
||||||
uniform float u_VertexLerp;
|
uniform float u_VertexLerp;
|
||||||
|
#elif defined(USE_BONE_ANIMATION)
|
||||||
|
uniform mat4 u_BoneMatrix[MAX_GLSL_BONES];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(USE_LIGHT_VECTOR)
|
#if defined(USE_LIGHT_VECTOR)
|
||||||
|
@ -151,6 +156,18 @@ void main()
|
||||||
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
|
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
|
||||||
vec3 tangent = mix(attr_Tangent.xyz, attr_Tangent2.xyz, u_VertexLerp);
|
vec3 tangent = mix(attr_Tangent.xyz, attr_Tangent2.xyz, u_VertexLerp);
|
||||||
#endif
|
#endif
|
||||||
|
#elif defined(USE_BONE_ANIMATION)
|
||||||
|
mat4 vtxMat = u_BoneMatrix[int(attr_BoneIndexes.x)] * attr_BoneWeights.x;
|
||||||
|
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.y)] * attr_BoneWeights.y;
|
||||||
|
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.z)] * attr_BoneWeights.z;
|
||||||
|
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.w)] * attr_BoneWeights.w;
|
||||||
|
mat3 nrmMat = mat3(cross(vtxMat[1].xyz, vtxMat[2].xyz), cross(vtxMat[2].xyz, vtxMat[0].xyz), cross(vtxMat[0].xyz, vtxMat[1].xyz));
|
||||||
|
|
||||||
|
vec3 position = vec3(vtxMat * vec4(attr_Position, 1.0));
|
||||||
|
vec3 normal = normalize(nrmMat * attr_Normal);
|
||||||
|
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
|
||||||
|
vec3 tangent = normalize(nrmMat * attr_Tangent.xyz);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
vec3 position = attr_Position;
|
vec3 position = attr_Position;
|
||||||
vec3 normal = attr_Normal;
|
vec3 normal = attr_Normal;
|
||||||
|
|
|
@ -2,10 +2,13 @@ attribute vec3 attr_Position;
|
||||||
attribute vec3 attr_Normal;
|
attribute vec3 attr_Normal;
|
||||||
attribute vec4 attr_TexCoord0;
|
attribute vec4 attr_TexCoord0;
|
||||||
|
|
||||||
//#if defined(USE_VERTEX_ANIMATION)
|
#if defined(USE_VERTEX_ANIMATION)
|
||||||
attribute vec3 attr_Position2;
|
attribute vec3 attr_Position2;
|
||||||
attribute vec3 attr_Normal2;
|
attribute vec3 attr_Normal2;
|
||||||
//#endif
|
#elif defined(USE_BONE_ANIMATION)
|
||||||
|
attribute vec4 attr_BoneIndexes;
|
||||||
|
attribute vec4 attr_BoneWeights;
|
||||||
|
#endif
|
||||||
|
|
||||||
//#if defined(USE_DEFORM_VERTEXES)
|
//#if defined(USE_DEFORM_VERTEXES)
|
||||||
uniform int u_DeformGen;
|
uniform int u_DeformGen;
|
||||||
|
@ -17,9 +20,11 @@ uniform mat4 u_ModelViewProjectionMatrix;
|
||||||
|
|
||||||
uniform mat4 u_ModelMatrix;
|
uniform mat4 u_ModelMatrix;
|
||||||
|
|
||||||
//#if defined(USE_VERTEX_ANIMATION)
|
#if defined(USE_VERTEX_ANIMATION)
|
||||||
uniform float u_VertexLerp;
|
uniform float u_VertexLerp;
|
||||||
//#endif
|
#elif defined(USE_BONE_ANIMATION)
|
||||||
|
uniform mat4 u_BoneMatrix[MAX_GLSL_BONES];
|
||||||
|
#endif
|
||||||
|
|
||||||
varying vec3 var_Position;
|
varying vec3 var_Position;
|
||||||
|
|
||||||
|
@ -78,8 +83,22 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st)
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
#if defined(USE_VERTEX_ANIMATION)
|
||||||
vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
|
vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp);
|
||||||
vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
|
vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp);
|
||||||
|
#elif defined(USE_BONE_ANIMATION)
|
||||||
|
mat4 vtxMat = u_BoneMatrix[int(attr_BoneIndexes.x)] * attr_BoneWeights.x;
|
||||||
|
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.y)] * attr_BoneWeights.y;
|
||||||
|
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.z)] * attr_BoneWeights.z;
|
||||||
|
vtxMat += u_BoneMatrix[int(attr_BoneIndexes.w)] * attr_BoneWeights.w;
|
||||||
|
mat3 nrmMat = mat3(cross(vtxMat[1].xyz, vtxMat[2].xyz), cross(vtxMat[2].xyz, vtxMat[0].xyz), cross(vtxMat[0].xyz, vtxMat[1].xyz));
|
||||||
|
|
||||||
|
vec3 position = vec3(vtxMat * vec4(attr_Position, 1.0));
|
||||||
|
vec3 normal = normalize(nrmMat * attr_Normal);
|
||||||
|
#else
|
||||||
|
vec3 position = attr_Position;
|
||||||
|
vec3 normal = attr_Normal;
|
||||||
|
#endif
|
||||||
|
|
||||||
position = DeformPosition(position, normal, attr_TexCoord0.st);
|
position = DeformPosition(position, normal, attr_TexCoord0.st);
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,8 @@ static uniformInfo_t uniformsInfo[] =
|
||||||
{ "u_CubeMapInfo", GLSL_VEC4 },
|
{ "u_CubeMapInfo", GLSL_VEC4 },
|
||||||
|
|
||||||
{ "u_AlphaTest", GLSL_INT },
|
{ "u_AlphaTest", GLSL_INT },
|
||||||
|
|
||||||
|
{ "u_BoneMatrix", GLSL_MAT16_BONEMATRIX },
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
@ -555,6 +557,12 @@ static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int
|
||||||
if(attribs & ATTR_LIGHTDIRECTION)
|
if(attribs & ATTR_LIGHTDIRECTION)
|
||||||
qglBindAttribLocation(program->program, ATTR_INDEX_LIGHTDIRECTION, "attr_LightDirection");
|
qglBindAttribLocation(program->program, ATTR_INDEX_LIGHTDIRECTION, "attr_LightDirection");
|
||||||
|
|
||||||
|
if(attribs & ATTR_BONE_INDEXES)
|
||||||
|
qglBindAttribLocation(program->program, ATTR_INDEX_BONE_INDEXES, "attr_BoneIndexes");
|
||||||
|
|
||||||
|
if(attribs & ATTR_BONE_WEIGHTS)
|
||||||
|
qglBindAttribLocation(program->program, ATTR_INDEX_BONE_WEIGHTS, "attr_BoneWeights");
|
||||||
|
|
||||||
if(attribs & ATTR_POSITION2)
|
if(attribs & ATTR_POSITION2)
|
||||||
qglBindAttribLocation(program->program, ATTR_INDEX_POSITION2, "attr_Position2");
|
qglBindAttribLocation(program->program, ATTR_INDEX_POSITION2, "attr_Position2");
|
||||||
|
|
||||||
|
@ -660,6 +668,9 @@ void GLSL_InitUniforms(shaderProgram_t *program)
|
||||||
case GLSL_MAT16:
|
case GLSL_MAT16:
|
||||||
size += sizeof(vec_t) * 16;
|
size += sizeof(vec_t) * 16;
|
||||||
break;
|
break;
|
||||||
|
case GLSL_MAT16_BONEMATRIX:
|
||||||
|
size += sizeof(vec_t) * 16 * glRefConfig.glslMaxAnimatedBones;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -843,6 +854,38 @@ void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t
|
||||||
qglProgramUniformMatrix4fvEXT(program->program, uniforms[uniformNum], 1, GL_FALSE, matrix);
|
qglProgramUniformMatrix4fvEXT(program->program, uniforms[uniformNum], 1, GL_FALSE, matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLSL_SetUniformMat4BoneMatrix(shaderProgram_t *program, int uniformNum, /*const*/ mat4_t *matrix, int numMatricies)
|
||||||
|
{
|
||||||
|
GLint *uniforms = program->uniforms;
|
||||||
|
vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]);
|
||||||
|
|
||||||
|
if (uniforms[uniformNum] == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uniformsInfo[uniformNum].type != GLSL_MAT16_BONEMATRIX)
|
||||||
|
{
|
||||||
|
ri.Printf( PRINT_WARNING, "GLSL_SetUniformMat4BoneMatrix: wrong type for uniform %i in program %s\n", uniformNum, program->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numMatricies > glRefConfig.glslMaxAnimatedBones)
|
||||||
|
{
|
||||||
|
ri.Printf( PRINT_WARNING, "GLSL_SetUniformMat4BoneMatrix: too many matricies (%d/%d) for uniform %i in program %s\n",
|
||||||
|
numMatricies, glRefConfig.glslMaxAnimatedBones, uniformNum, program->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(matrix, compare, numMatricies * sizeof(mat4_t)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Com_Memcpy(compare, matrix, numMatricies * sizeof(mat4_t));
|
||||||
|
|
||||||
|
qglProgramUniformMatrix4fvEXT(program->program, uniforms[uniformNum], numMatricies, GL_FALSE, &matrix[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
void GLSL_DeleteGPUShader(shaderProgram_t *program)
|
void GLSL_DeleteGPUShader(shaderProgram_t *program)
|
||||||
{
|
{
|
||||||
if(program->program)
|
if(program->program)
|
||||||
|
@ -886,6 +929,12 @@ void GLSL_InitGPUShaders(void)
|
||||||
|
|
||||||
for (i = 0; i < GENERICDEF_COUNT; i++)
|
for (i = 0; i < GENERICDEF_COUNT; i++)
|
||||||
{
|
{
|
||||||
|
if ((i & GENERICDEF_USE_VERTEX_ANIMATION) && (i & GENERICDEF_USE_BONE_ANIMATION))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((i & GENERICDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
|
||||||
|
continue;
|
||||||
|
|
||||||
attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_NORMAL | ATTR_COLOR;
|
attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_NORMAL | ATTR_COLOR;
|
||||||
extradefines[0] = '\0';
|
extradefines[0] = '\0';
|
||||||
|
|
||||||
|
@ -903,6 +952,11 @@ void GLSL_InitGPUShaders(void)
|
||||||
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
|
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
|
||||||
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
|
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
|
||||||
}
|
}
|
||||||
|
else if (i & GENERICDEF_USE_BONE_ANIMATION)
|
||||||
|
{
|
||||||
|
Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones));
|
||||||
|
attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS;
|
||||||
|
}
|
||||||
|
|
||||||
if (i & GENERICDEF_USE_FOG)
|
if (i & GENERICDEF_USE_FOG)
|
||||||
Q_strcat(extradefines, 1024, "#define USE_FOG\n");
|
Q_strcat(extradefines, 1024, "#define USE_FOG\n");
|
||||||
|
@ -943,14 +997,28 @@ void GLSL_InitGPUShaders(void)
|
||||||
|
|
||||||
for (i = 0; i < FOGDEF_COUNT; i++)
|
for (i = 0; i < FOGDEF_COUNT; i++)
|
||||||
{
|
{
|
||||||
attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD;
|
if ((i & FOGDEF_USE_VERTEX_ANIMATION) && (i & FOGDEF_USE_BONE_ANIMATION))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((i & FOGDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD;
|
||||||
extradefines[0] = '\0';
|
extradefines[0] = '\0';
|
||||||
|
|
||||||
if (i & FOGDEF_USE_DEFORM_VERTEXES)
|
if (i & FOGDEF_USE_DEFORM_VERTEXES)
|
||||||
Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n");
|
Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n");
|
||||||
|
|
||||||
if (i & FOGDEF_USE_VERTEX_ANIMATION)
|
if (i & FOGDEF_USE_VERTEX_ANIMATION)
|
||||||
|
{
|
||||||
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
|
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
|
||||||
|
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
|
||||||
|
}
|
||||||
|
else if (i & FOGDEF_USE_BONE_ANIMATION)
|
||||||
|
{
|
||||||
|
Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones));
|
||||||
|
attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS;
|
||||||
|
}
|
||||||
|
|
||||||
if (!GLSL_InitGPUShader(&tr.fogShader[i], "fogpass", attribs, qtrue, extradefines, qtrue, fallbackShader_fogpass_vp, fallbackShader_fogpass_fp))
|
if (!GLSL_InitGPUShader(&tr.fogShader[i], "fogpass", attribs, qtrue, extradefines, qtrue, fallbackShader_fogpass_vp, fallbackShader_fogpass_fp))
|
||||||
{
|
{
|
||||||
|
@ -1001,6 +1069,12 @@ void GLSL_InitGPUShaders(void)
|
||||||
if ((i & LIGHTDEF_USE_SHADOWMAP) && (!lightType || !r_sunlightMode->integer))
|
if ((i & LIGHTDEF_USE_SHADOWMAP) && (!lightType || !r_sunlightMode->integer))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if ((i & LIGHTDEF_ENTITY_VERTEX_ANIMATION) && (i & LIGHTDEF_ENTITY_BONE_ANIMATION))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((i & LIGHTDEF_ENTITY_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
|
||||||
|
continue;
|
||||||
|
|
||||||
attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL;
|
attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL;
|
||||||
|
|
||||||
extradefines[0] = '\0';
|
extradefines[0] = '\0';
|
||||||
|
@ -1043,7 +1117,7 @@ void GLSL_InitGPUShaders(void)
|
||||||
|
|
||||||
attribs |= ATTR_TANGENT;
|
attribs |= ATTR_TANGENT;
|
||||||
|
|
||||||
if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer)
|
if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY_VERTEX_ANIMATION) && !(i & LIGHTDEF_ENTITY_BONE_ANIMATION) && r_parallaxMapping->integer)
|
||||||
{
|
{
|
||||||
Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n");
|
Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n");
|
||||||
if (r_parallaxMapping->integer > 1)
|
if (r_parallaxMapping->integer > 1)
|
||||||
|
@ -1093,7 +1167,7 @@ void GLSL_InitGPUShaders(void)
|
||||||
Q_strcat(extradefines, 1024, "#define USE_TCMOD\n");
|
Q_strcat(extradefines, 1024, "#define USE_TCMOD\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i & LIGHTDEF_ENTITY)
|
if (i & LIGHTDEF_ENTITY_VERTEX_ANIMATION)
|
||||||
{
|
{
|
||||||
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n#define USE_MODELMATRIX\n");
|
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n#define USE_MODELMATRIX\n");
|
||||||
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
|
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
|
||||||
|
@ -1103,6 +1177,12 @@ void GLSL_InitGPUShaders(void)
|
||||||
attribs |= ATTR_TANGENT2;
|
attribs |= ATTR_TANGENT2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (i & LIGHTDEF_ENTITY_BONE_ANIMATION)
|
||||||
|
{
|
||||||
|
Q_strcat(extradefines, 1024, "#define USE_MODELMATRIX\n");
|
||||||
|
Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones));
|
||||||
|
attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS;
|
||||||
|
}
|
||||||
|
|
||||||
if (!GLSL_InitGPUShader(&tr.lightallShader[i], "lightall", attribs, qtrue, extradefines, qtrue, fallbackShader_lightall_vp, fallbackShader_lightall_fp))
|
if (!GLSL_InitGPUShader(&tr.lightallShader[i], "lightall", attribs, qtrue, extradefines, qtrue, fallbackShader_lightall_vp, fallbackShader_lightall_fp))
|
||||||
{
|
{
|
||||||
|
@ -1124,19 +1204,40 @@ void GLSL_InitGPUShaders(void)
|
||||||
numLightShaders++;
|
numLightShaders++;
|
||||||
}
|
}
|
||||||
|
|
||||||
attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD;
|
for (i = 0; i < SHADOWMAPDEF_COUNT; i++)
|
||||||
|
{
|
||||||
|
if ((i & SHADOWMAPDEF_USE_VERTEX_ANIMATION) && (i & SHADOWMAPDEF_USE_BONE_ANIMATION))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((i & SHADOWMAPDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD;
|
||||||
|
|
||||||
extradefines[0] = '\0';
|
extradefines[0] = '\0';
|
||||||
|
|
||||||
if (!GLSL_InitGPUShader(&tr.shadowmapShader, "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp))
|
if (i & SHADOWMAPDEF_USE_VERTEX_ANIMATION)
|
||||||
|
{
|
||||||
|
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
|
||||||
|
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i & SHADOWMAPDEF_USE_BONE_ANIMATION)
|
||||||
|
{
|
||||||
|
Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones));
|
||||||
|
attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GLSL_InitGPUShader(&tr.shadowmapShader[i], "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp))
|
||||||
{
|
{
|
||||||
ri.Error(ERR_FATAL, "Could not load shadowfill shader!");
|
ri.Error(ERR_FATAL, "Could not load shadowfill shader!");
|
||||||
}
|
}
|
||||||
|
|
||||||
GLSL_InitUniforms(&tr.shadowmapShader);
|
GLSL_InitUniforms(&tr.shadowmapShader[i]);
|
||||||
GLSL_FinishGPUShader(&tr.shadowmapShader);
|
GLSL_FinishGPUShader(&tr.shadowmapShader[i]);
|
||||||
|
|
||||||
numEtcShaders++;
|
numEtcShaders++;
|
||||||
|
}
|
||||||
|
|
||||||
attribs = ATTR_POSITION | ATTR_NORMAL;
|
attribs = ATTR_POSITION | ATTR_NORMAL;
|
||||||
extradefines[0] = '\0';
|
extradefines[0] = '\0';
|
||||||
|
@ -1363,7 +1464,9 @@ void GLSL_ShutdownGPUShaders(void)
|
||||||
for ( i = 0; i < LIGHTDEF_COUNT; i++)
|
for ( i = 0; i < LIGHTDEF_COUNT; i++)
|
||||||
GLSL_DeleteGPUShader(&tr.lightallShader[i]);
|
GLSL_DeleteGPUShader(&tr.lightallShader[i]);
|
||||||
|
|
||||||
GLSL_DeleteGPUShader(&tr.shadowmapShader);
|
for ( i = 0; i < SHADOWMAPDEF_COUNT; i++)
|
||||||
|
GLSL_DeleteGPUShader(&tr.shadowmapShader[i]);
|
||||||
|
|
||||||
GLSL_DeleteGPUShader(&tr.pshadowShader);
|
GLSL_DeleteGPUShader(&tr.pshadowShader);
|
||||||
GLSL_DeleteGPUShader(&tr.down4xShader);
|
GLSL_DeleteGPUShader(&tr.down4xShader);
|
||||||
GLSL_DeleteGPUShader(&tr.bokehShader);
|
GLSL_DeleteGPUShader(&tr.bokehShader);
|
||||||
|
@ -1439,6 +1542,10 @@ shaderProgram_t *GLSL_GetGenericShaderProgram(int stage)
|
||||||
{
|
{
|
||||||
shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION;
|
shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION;
|
||||||
}
|
}
|
||||||
|
else if (glState.boneAnimation)
|
||||||
|
{
|
||||||
|
shaderAttribs |= GENERICDEF_USE_BONE_ANIMATION;
|
||||||
|
}
|
||||||
|
|
||||||
if (pStage->bundle[0].numTexMods)
|
if (pStage->bundle[0].numTexMods)
|
||||||
{
|
{
|
||||||
|
|
|
@ -275,6 +275,13 @@ static void InitOpenGL( void )
|
||||||
|
|
||||||
qglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS, &temp );
|
qglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS, &temp );
|
||||||
glConfig.numTextureUnits = temp;
|
glConfig.numTextureUnits = temp;
|
||||||
|
|
||||||
|
// reserve 160 components for other uniforms
|
||||||
|
qglGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS, &temp );
|
||||||
|
glRefConfig.glslMaxAnimatedBones = Com_Clamp( 0, IQM_MAX_JOINTS, ( temp - 160 ) / 16 );
|
||||||
|
if ( glRefConfig.glslMaxAnimatedBones < 12 ) {
|
||||||
|
glRefConfig.glslMaxAnimatedBones = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set default state
|
// set default state
|
||||||
|
|
|
@ -554,16 +554,18 @@ enum
|
||||||
GENERICDEF_USE_VERTEX_ANIMATION = 0x0004,
|
GENERICDEF_USE_VERTEX_ANIMATION = 0x0004,
|
||||||
GENERICDEF_USE_FOG = 0x0008,
|
GENERICDEF_USE_FOG = 0x0008,
|
||||||
GENERICDEF_USE_RGBAGEN = 0x0010,
|
GENERICDEF_USE_RGBAGEN = 0x0010,
|
||||||
GENERICDEF_ALL = 0x001F,
|
GENERICDEF_USE_BONE_ANIMATION = 0x0020,
|
||||||
GENERICDEF_COUNT = 0x0020,
|
GENERICDEF_ALL = 0x003F,
|
||||||
|
GENERICDEF_COUNT = 0x0040,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
FOGDEF_USE_DEFORM_VERTEXES = 0x0001,
|
FOGDEF_USE_DEFORM_VERTEXES = 0x0001,
|
||||||
FOGDEF_USE_VERTEX_ANIMATION = 0x0002,
|
FOGDEF_USE_VERTEX_ANIMATION = 0x0002,
|
||||||
FOGDEF_ALL = 0x0003,
|
FOGDEF_USE_BONE_ANIMATION = 0x0004,
|
||||||
FOGDEF_COUNT = 0x0004,
|
FOGDEF_ALL = 0x0007,
|
||||||
|
FOGDEF_COUNT = 0x0008,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -579,12 +581,21 @@ enum
|
||||||
LIGHTDEF_USE_LIGHT_VECTOR = 0x0002,
|
LIGHTDEF_USE_LIGHT_VECTOR = 0x0002,
|
||||||
LIGHTDEF_USE_LIGHT_VERTEX = 0x0003,
|
LIGHTDEF_USE_LIGHT_VERTEX = 0x0003,
|
||||||
LIGHTDEF_LIGHTTYPE_MASK = 0x0003,
|
LIGHTDEF_LIGHTTYPE_MASK = 0x0003,
|
||||||
LIGHTDEF_ENTITY = 0x0004,
|
LIGHTDEF_ENTITY_VERTEX_ANIMATION = 0x0004,
|
||||||
LIGHTDEF_USE_TCGEN_AND_TCMOD = 0x0008,
|
LIGHTDEF_USE_TCGEN_AND_TCMOD = 0x0008,
|
||||||
LIGHTDEF_USE_PARALLAXMAP = 0x0010,
|
LIGHTDEF_USE_PARALLAXMAP = 0x0010,
|
||||||
LIGHTDEF_USE_SHADOWMAP = 0x0020,
|
LIGHTDEF_USE_SHADOWMAP = 0x0020,
|
||||||
LIGHTDEF_ALL = 0x003F,
|
LIGHTDEF_ENTITY_BONE_ANIMATION = 0x0040,
|
||||||
LIGHTDEF_COUNT = 0x0040
|
LIGHTDEF_ALL = 0x007F,
|
||||||
|
LIGHTDEF_COUNT = 0x0080
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SHADOWMAPDEF_USE_VERTEX_ANIMATION = 0x0001,
|
||||||
|
SHADOWMAPDEF_USE_BONE_ANIMATION = 0x0002,
|
||||||
|
SHADOWMAPDEF_ALL = 0x0003,
|
||||||
|
SHADOWMAPDEF_COUNT = 0x0004
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -595,7 +606,8 @@ enum
|
||||||
GLSL_VEC2,
|
GLSL_VEC2,
|
||||||
GLSL_VEC3,
|
GLSL_VEC3,
|
||||||
GLSL_VEC4,
|
GLSL_VEC4,
|
||||||
GLSL_MAT16
|
GLSL_MAT16,
|
||||||
|
GLSL_MAT16_BONEMATRIX
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
@ -686,6 +698,8 @@ typedef enum
|
||||||
|
|
||||||
UNIFORM_ALPHATEST,
|
UNIFORM_ALPHATEST,
|
||||||
|
|
||||||
|
UNIFORM_BONEMATRIX,
|
||||||
|
|
||||||
UNIFORM_COUNT
|
UNIFORM_COUNT
|
||||||
} uniform_t;
|
} uniform_t;
|
||||||
|
|
||||||
|
@ -849,6 +863,7 @@ typedef enum {
|
||||||
SF_FLARE,
|
SF_FLARE,
|
||||||
SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
|
SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
|
||||||
SF_VAO_MDVMESH,
|
SF_VAO_MDVMESH,
|
||||||
|
SF_VAO_IQM,
|
||||||
|
|
||||||
SF_NUM_SURFACE_TYPES,
|
SF_NUM_SURFACE_TYPES,
|
||||||
SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
|
SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
|
||||||
|
@ -976,6 +991,9 @@ typedef struct {
|
||||||
float *jointMats;
|
float *jointMats;
|
||||||
float *poseMats;
|
float *poseMats;
|
||||||
float *bounds;
|
float *bounds;
|
||||||
|
|
||||||
|
int numVaoSurfaces;
|
||||||
|
struct srfVaoIQModel_s *vaoSurfaces;
|
||||||
} iqmData_t;
|
} iqmData_t;
|
||||||
|
|
||||||
// inter-quake-model surface
|
// inter-quake-model surface
|
||||||
|
@ -989,6 +1007,21 @@ typedef struct srfIQModel_s {
|
||||||
int first_influence, num_influences;
|
int first_influence, num_influences;
|
||||||
} srfIQModel_t;
|
} srfIQModel_t;
|
||||||
|
|
||||||
|
typedef struct srfVaoIQModel_s
|
||||||
|
{
|
||||||
|
surfaceType_t surfaceType;
|
||||||
|
|
||||||
|
iqmData_t *iqmData;
|
||||||
|
struct srfIQModel_s *iqmSurface;
|
||||||
|
|
||||||
|
// backEnd stats
|
||||||
|
int numIndexes;
|
||||||
|
int numVerts;
|
||||||
|
|
||||||
|
// static render data
|
||||||
|
vao_t *vao;
|
||||||
|
} srfVaoIQModel_t;
|
||||||
|
|
||||||
typedef struct srfVaoMdvMesh_s
|
typedef struct srfVaoMdvMesh_s
|
||||||
{
|
{
|
||||||
surfaceType_t surfaceType;
|
surfaceType_t surfaceType;
|
||||||
|
@ -1332,6 +1365,8 @@ typedef struct {
|
||||||
uint32_t storedGlState;
|
uint32_t storedGlState;
|
||||||
float vertexAttribsInterpolation;
|
float vertexAttribsInterpolation;
|
||||||
qboolean vertexAnimation;
|
qboolean vertexAnimation;
|
||||||
|
int boneAnimation; // number of bones
|
||||||
|
mat4_t boneMatrix[IQM_MAX_JOINTS];
|
||||||
uint32_t vertexAttribsEnabled; // global if no VAOs, tess only otherwise
|
uint32_t vertexAttribsEnabled; // global if no VAOs, tess only otherwise
|
||||||
FBO_t *currentFBO;
|
FBO_t *currentFBO;
|
||||||
vao_t *currentVao;
|
vao_t *currentVao;
|
||||||
|
@ -1361,6 +1396,7 @@ typedef struct {
|
||||||
|
|
||||||
int glslMajorVersion;
|
int glslMajorVersion;
|
||||||
int glslMinorVersion;
|
int glslMinorVersion;
|
||||||
|
int glslMaxAnimatedBones;
|
||||||
|
|
||||||
memInfo_t memInfo;
|
memInfo_t memInfo;
|
||||||
|
|
||||||
|
@ -1541,7 +1577,7 @@ typedef struct {
|
||||||
shaderProgram_t fogShader[FOGDEF_COUNT];
|
shaderProgram_t fogShader[FOGDEF_COUNT];
|
||||||
shaderProgram_t dlightShader[DLIGHTDEF_COUNT];
|
shaderProgram_t dlightShader[DLIGHTDEF_COUNT];
|
||||||
shaderProgram_t lightallShader[LIGHTDEF_COUNT];
|
shaderProgram_t lightallShader[LIGHTDEF_COUNT];
|
||||||
shaderProgram_t shadowmapShader;
|
shaderProgram_t shadowmapShader[SHADOWMAPDEF_COUNT];
|
||||||
shaderProgram_t pshadowShader;
|
shaderProgram_t pshadowShader;
|
||||||
shaderProgram_t down4xShader;
|
shaderProgram_t down4xShader;
|
||||||
shaderProgram_t bokehShader;
|
shaderProgram_t bokehShader;
|
||||||
|
@ -2190,6 +2226,7 @@ void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t
|
||||||
void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v);
|
void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v);
|
||||||
void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v);
|
void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v);
|
||||||
void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix);
|
void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix);
|
||||||
|
void GLSL_SetUniformMat4BoneMatrix(shaderProgram_t *program, int uniformNum, /*const*/ mat4_t *matrix, int numMatricies);
|
||||||
|
|
||||||
shaderProgram_t *GLSL_GetGenericShaderProgram(int stage);
|
shaderProgram_t *GLSL_GetGenericShaderProgram(int stage);
|
||||||
|
|
||||||
|
@ -2244,6 +2281,7 @@ void RB_MDRSurfaceAnim( mdrSurface_t *surface );
|
||||||
qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name );
|
qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name );
|
||||||
void R_AddIQMSurfaces( trRefEntity_t *ent );
|
void R_AddIQMSurfaces( trRefEntity_t *ent );
|
||||||
void RB_IQMSurfaceAnim( surfaceType_t *surface );
|
void RB_IQMSurfaceAnim( surfaceType_t *surface );
|
||||||
|
void RB_IQMSurfaceAnimVao( srfVaoIQModel_t *surface );
|
||||||
int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
|
int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
|
||||||
int startFrame, int endFrame,
|
int startFrame, int endFrame,
|
||||||
float frac, const char *tagName );
|
float frac, const char *tagName );
|
||||||
|
|
|
@ -916,6 +916,170 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create VAO surfaces
|
||||||
|
if ( iqmData->num_surfaces && iqmData->num_joints <= glRefConfig.glslMaxAnimatedBones )
|
||||||
|
{
|
||||||
|
srfVaoIQModel_t *vaoSurf;
|
||||||
|
srfIQModel_t *surf;
|
||||||
|
|
||||||
|
iqmData->numVaoSurfaces = iqmData->num_surfaces;
|
||||||
|
iqmData->vaoSurfaces = ri.Hunk_Alloc(sizeof(*iqmData->vaoSurfaces) * iqmData->numVaoSurfaces, h_low);
|
||||||
|
|
||||||
|
vaoSurf = iqmData->vaoSurfaces;
|
||||||
|
surf = iqmData->surfaces;
|
||||||
|
for (i = 0; i < iqmData->num_surfaces; i++, vaoSurf++, surf++)
|
||||||
|
{
|
||||||
|
uint32_t offset_xyz, offset_st, offset_normal, offset_tangent;
|
||||||
|
uint32_t offset_blendindexes, offset_blendweights, stride;
|
||||||
|
uint32_t dataSize, dataOfs;
|
||||||
|
uint8_t *data;
|
||||||
|
glIndex_t indexes[SHADER_MAX_INDEXES];
|
||||||
|
glIndex_t *ptr;
|
||||||
|
int *tri;
|
||||||
|
|
||||||
|
offset_xyz = 0;
|
||||||
|
offset_st = offset_xyz + sizeof(float) * 3;
|
||||||
|
offset_normal = offset_st + sizeof(float) * 2;
|
||||||
|
offset_tangent = offset_normal + sizeof(int16_t) * 4;
|
||||||
|
|
||||||
|
if ( iqmData->num_joints )
|
||||||
|
{
|
||||||
|
offset_blendindexes = offset_tangent + sizeof(int16_t) * 4;
|
||||||
|
offset_blendweights = offset_blendindexes + sizeof(byte) * 4;
|
||||||
|
|
||||||
|
if ( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) {
|
||||||
|
stride = offset_blendweights + sizeof(float) * 4;
|
||||||
|
} else {
|
||||||
|
stride = offset_blendweights + sizeof(byte) * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stride = offset_tangent + sizeof(int16_t) * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataSize = surf->num_vertexes * stride;
|
||||||
|
|
||||||
|
data = ri.Malloc(dataSize);
|
||||||
|
dataOfs = 0;
|
||||||
|
|
||||||
|
for ( j = 0; j < surf->num_vertexes; j++ )
|
||||||
|
{
|
||||||
|
int vtx = surf->first_vertex + j;
|
||||||
|
|
||||||
|
// xyz
|
||||||
|
memcpy(data + dataOfs, &iqmData->positions[vtx*3], sizeof(float) * 3);
|
||||||
|
dataOfs += sizeof(float) * 3;
|
||||||
|
|
||||||
|
// st
|
||||||
|
memcpy(data + dataOfs, &iqmData->texcoords[vtx*2], sizeof(float) * 2);
|
||||||
|
dataOfs += sizeof(float) * 2;
|
||||||
|
|
||||||
|
// normal
|
||||||
|
R_VaoPackNormal((int16_t*)(data + dataOfs), &iqmData->normals[vtx*3]);
|
||||||
|
dataOfs += sizeof(int16_t) * 4;
|
||||||
|
|
||||||
|
// tangent
|
||||||
|
R_VaoPackTangent((int16_t*)(data + dataOfs), &iqmData->tangents[vtx*4]);
|
||||||
|
dataOfs += sizeof(int16_t) * 4;
|
||||||
|
|
||||||
|
if ( iqmData->num_joints )
|
||||||
|
{
|
||||||
|
// blendindexes
|
||||||
|
memcpy(data + dataOfs, &blendIndexes[vtx*4], sizeof(byte) * 4);
|
||||||
|
dataOfs += sizeof(byte) * 4;
|
||||||
|
|
||||||
|
// blendweights
|
||||||
|
if ( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) {
|
||||||
|
memcpy(data + dataOfs, &blendWeights.f[vtx*4], sizeof(float) * 4);
|
||||||
|
dataOfs += sizeof(float) * 4;
|
||||||
|
} else {
|
||||||
|
memcpy(data + dataOfs, &blendWeights.b[vtx*4], sizeof(byte) * 4);
|
||||||
|
dataOfs += sizeof(byte) * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tri = iqmData->triangles + 3 * surf->first_triangle;
|
||||||
|
ptr = indexes;
|
||||||
|
|
||||||
|
for( j = 0; j < surf->num_triangles; j++ ) {
|
||||||
|
*ptr++ = (*tri++ - surf->first_vertex);
|
||||||
|
*ptr++ = (*tri++ - surf->first_vertex);
|
||||||
|
*ptr++ = (*tri++ - surf->first_vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
vaoSurf->surfaceType = SF_VAO_IQM;
|
||||||
|
vaoSurf->iqmData = iqmData;
|
||||||
|
vaoSurf->iqmSurface = surf;
|
||||||
|
vaoSurf->numIndexes = surf->num_triangles * 3;
|
||||||
|
vaoSurf->numVerts = surf->num_vertexes;
|
||||||
|
|
||||||
|
vaoSurf->vao = R_CreateVao(va("staticIQMMesh_VAO '%s'", surf->name), data, dataSize, (byte *)indexes, surf->num_triangles * 3 * sizeof(indexes[0]), VAO_USAGE_STATIC);
|
||||||
|
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
|
||||||
|
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].count = 3;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].count = 2;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].count = 4;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].count = 4;
|
||||||
|
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT;
|
||||||
|
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
|
||||||
|
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].offset = offset_xyz;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].offset = offset_st;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].offset = offset_normal;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].offset = offset_tangent;
|
||||||
|
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_POSITION].stride = stride;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].stride = stride;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].stride = stride;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].stride = stride;
|
||||||
|
|
||||||
|
if ( iqmData->num_joints )
|
||||||
|
{
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].enabled = 1;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].enabled = 1;
|
||||||
|
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].count = 4;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].count = 4;
|
||||||
|
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].type = GL_UNSIGNED_BYTE;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].normalized = GL_FALSE;
|
||||||
|
|
||||||
|
if ( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) {
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].type = GL_FLOAT;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].normalized = GL_FALSE;
|
||||||
|
} else {
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].type = GL_UNSIGNED_BYTE;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].normalized = GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].offset = offset_blendindexes;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].offset = offset_blendweights;
|
||||||
|
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].stride = stride;
|
||||||
|
vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].stride = stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vao_SetVertexPointers(vaoSurf->vao);
|
||||||
|
|
||||||
|
ri.Free(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return qtrue;
|
return qtrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1017,6 +1181,7 @@ Add all surfaces of this model
|
||||||
void R_AddIQMSurfaces( trRefEntity_t *ent ) {
|
void R_AddIQMSurfaces( trRefEntity_t *ent ) {
|
||||||
iqmData_t *data;
|
iqmData_t *data;
|
||||||
srfIQModel_t *surface;
|
srfIQModel_t *surface;
|
||||||
|
void *drawSurf;
|
||||||
int i, j;
|
int i, j;
|
||||||
qboolean personalModel;
|
qboolean personalModel;
|
||||||
int cull;
|
int cull;
|
||||||
|
@ -1097,6 +1262,12 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
|
||||||
shader = surface->shader;
|
shader = surface->shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( data->numVaoSurfaces ) {
|
||||||
|
drawSurf = &data->vaoSurfaces[i];
|
||||||
|
} else {
|
||||||
|
drawSurf = surface;
|
||||||
|
}
|
||||||
|
|
||||||
// we will add shadows even if the main object isn't visible in the view
|
// we will add shadows even if the main object isn't visible in the view
|
||||||
|
|
||||||
// stencil shadows can't do personal models unless I polyhedron clip
|
// stencil shadows can't do personal models unless I polyhedron clip
|
||||||
|
@ -1105,7 +1276,7 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
|
||||||
&& fogNum == 0
|
&& fogNum == 0
|
||||||
&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
|
&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
|
||||||
&& shader->sort == SS_OPAQUE ) {
|
&& shader->sort == SS_OPAQUE ) {
|
||||||
R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, 0, 0, 0 );
|
R_AddDrawSurf( drawSurf, tr.shadowShader, 0, 0, 0, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// projection shadows work fine with personal models
|
// projection shadows work fine with personal models
|
||||||
|
@ -1113,11 +1284,11 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) {
|
||||||
&& fogNum == 0
|
&& fogNum == 0
|
||||||
&& (ent->e.renderfx & RF_SHADOW_PLANE )
|
&& (ent->e.renderfx & RF_SHADOW_PLANE )
|
||||||
&& shader->sort == SS_OPAQUE ) {
|
&& shader->sort == SS_OPAQUE ) {
|
||||||
R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0, 0, 0 );
|
R_AddDrawSurf( drawSurf, tr.projectionShadowShader, 0, 0, 0, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !personalModel ) {
|
if( !personalModel ) {
|
||||||
R_AddDrawSurf( (void *)surface, shader, fogNum, 0, 0, cubemapIndex );
|
R_AddDrawSurf( drawSurf, shader, fogNum, 0, 0, cubemapIndex );
|
||||||
}
|
}
|
||||||
|
|
||||||
surface++;
|
surface++;
|
||||||
|
@ -1418,6 +1589,73 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) {
|
||||||
tess.numVertexes += surf->num_vertexes;
|
tess.numVertexes += surf->num_vertexes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
RB_IQMSurfaceAnimVao
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
void RB_IQMSurfaceAnimVao(srfVaoIQModel_t * surface)
|
||||||
|
{
|
||||||
|
iqmData_t *data = surface->iqmData;
|
||||||
|
|
||||||
|
if (ShaderRequiresCPUDeforms(tess.shader))
|
||||||
|
{
|
||||||
|
RB_IQMSurfaceAnim((surfaceType_t*)surface->iqmSurface);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!surface->vao)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//RB_CheckVao(surface->vao);
|
||||||
|
RB_EndSurface();
|
||||||
|
RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex);
|
||||||
|
|
||||||
|
R_BindVao(surface->vao);
|
||||||
|
|
||||||
|
tess.useInternalVao = qfalse;
|
||||||
|
|
||||||
|
tess.numIndexes = surface->numIndexes;
|
||||||
|
tess.numVertexes = surface->numVerts;
|
||||||
|
|
||||||
|
glState.boneAnimation = data->num_poses;
|
||||||
|
|
||||||
|
if ( glState.boneAnimation ) {
|
||||||
|
float jointMats[IQM_MAX_JOINTS * 12];
|
||||||
|
int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0;
|
||||||
|
int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0;
|
||||||
|
float backlerp = backEnd.currentEntity->e.backlerp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// compute interpolated joint matrices
|
||||||
|
ComputePoseMats( surface->iqmData, frame, oldframe, backlerp, jointMats );
|
||||||
|
|
||||||
|
// convert row-major order 3x4 matrix to column-major order 4x4 matrix
|
||||||
|
for ( i = 0; i < data->num_poses; i++ ) {
|
||||||
|
glState.boneMatrix[i][0] = jointMats[i*12+0];
|
||||||
|
glState.boneMatrix[i][1] = jointMats[i*12+4];
|
||||||
|
glState.boneMatrix[i][2] = jointMats[i*12+8];
|
||||||
|
glState.boneMatrix[i][3] = 0.0f;
|
||||||
|
glState.boneMatrix[i][4] = jointMats[i*12+1];
|
||||||
|
glState.boneMatrix[i][5] = jointMats[i*12+5];
|
||||||
|
glState.boneMatrix[i][6] = jointMats[i*12+9];
|
||||||
|
glState.boneMatrix[i][7] = 0.0f;
|
||||||
|
glState.boneMatrix[i][8] = jointMats[i*12+2];
|
||||||
|
glState.boneMatrix[i][9] = jointMats[i*12+6];
|
||||||
|
glState.boneMatrix[i][10] = jointMats[i*12+10];
|
||||||
|
glState.boneMatrix[i][11] = 0.0f;
|
||||||
|
glState.boneMatrix[i][12] = jointMats[i*12+3];
|
||||||
|
glState.boneMatrix[i][13] = jointMats[i*12+7];
|
||||||
|
glState.boneMatrix[i][14] = jointMats[i*12+11];
|
||||||
|
glState.boneMatrix[i][15] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RB_EndSurface();
|
||||||
|
|
||||||
|
glState.boneAnimation = 0;
|
||||||
|
}
|
||||||
|
|
||||||
int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
|
int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
|
||||||
int startFrame, int endFrame,
|
int startFrame, int endFrame,
|
||||||
float frac, const char *tagName ) {
|
float frac, const char *tagName ) {
|
||||||
|
|
|
@ -908,6 +908,8 @@ static void RB_FogPass( void ) {
|
||||||
|
|
||||||
if (glState.vertexAnimation)
|
if (glState.vertexAnimation)
|
||||||
index |= FOGDEF_USE_VERTEX_ANIMATION;
|
index |= FOGDEF_USE_VERTEX_ANIMATION;
|
||||||
|
else if (glState.boneAnimation)
|
||||||
|
index |= FOGDEF_USE_BONE_ANIMATION;
|
||||||
|
|
||||||
sp = &tr.fogShader[index];
|
sp = &tr.fogShader[index];
|
||||||
}
|
}
|
||||||
|
@ -922,6 +924,11 @@ static void RB_FogPass( void ) {
|
||||||
|
|
||||||
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
|
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
|
||||||
|
|
||||||
|
if (glState.boneAnimation)
|
||||||
|
{
|
||||||
|
GLSL_SetUniformMat4BoneMatrix(sp, UNIFORM_BONEMATRIX, glState.boneMatrix, glState.boneAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
|
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
|
||||||
if (deformGen != DGEN_NONE)
|
if (deformGen != DGEN_NONE)
|
||||||
{
|
{
|
||||||
|
@ -1005,7 +1012,14 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
|
||||||
|
|
||||||
if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity)
|
if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity)
|
||||||
{
|
{
|
||||||
index |= LIGHTDEF_ENTITY;
|
if (glState.boneAnimation)
|
||||||
|
{
|
||||||
|
index |= LIGHTDEF_ENTITY_BONE_ANIMATION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index |= LIGHTDEF_ENTITY_VERTEX_ANIMATION;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pStage->stateBits & GLS_ATEST_BITS)
|
if (pStage->stateBits & GLS_ATEST_BITS)
|
||||||
|
@ -1028,6 +1042,10 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
|
||||||
{
|
{
|
||||||
shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION;
|
shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION;
|
||||||
}
|
}
|
||||||
|
else if (glState.boneAnimation)
|
||||||
|
{
|
||||||
|
shaderAttribs |= GENERICDEF_USE_BONE_ANIMATION;
|
||||||
|
}
|
||||||
|
|
||||||
if (pStage->stateBits & GLS_ATEST_BITS)
|
if (pStage->stateBits & GLS_ATEST_BITS)
|
||||||
{
|
{
|
||||||
|
@ -1043,7 +1061,14 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
|
||||||
|
|
||||||
if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity)
|
if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity)
|
||||||
{
|
{
|
||||||
index |= LIGHTDEF_ENTITY;
|
if (glState.boneAnimation)
|
||||||
|
{
|
||||||
|
index |= LIGHTDEF_ENTITY_BONE_ANIMATION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index |= LIGHTDEF_ENTITY_VERTEX_ANIMATION;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (index & LIGHTDEF_LIGHTTYPE_MASK))
|
if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (index & LIGHTDEF_LIGHTTYPE_MASK))
|
||||||
|
@ -1075,6 +1100,11 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
|
||||||
|
|
||||||
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
|
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
|
||||||
|
|
||||||
|
if (glState.boneAnimation)
|
||||||
|
{
|
||||||
|
GLSL_SetUniformMat4BoneMatrix(sp, UNIFORM_BONEMATRIX, glState.boneMatrix, glState.boneAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
|
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
|
||||||
if (deformGen != DGEN_NONE)
|
if (deformGen != DGEN_NONE)
|
||||||
{
|
{
|
||||||
|
@ -1368,7 +1398,16 @@ static void RB_RenderShadowmap( shaderCommands_t *input )
|
||||||
ComputeDeformValues(&deformGen, deformParams);
|
ComputeDeformValues(&deformGen, deformParams);
|
||||||
|
|
||||||
{
|
{
|
||||||
shaderProgram_t *sp = &tr.shadowmapShader;
|
shaderProgram_t *sp = &tr.shadowmapShader[0];
|
||||||
|
|
||||||
|
if (glState.vertexAnimation)
|
||||||
|
{
|
||||||
|
sp = &tr.shadowmapShader[SHADOWMAPDEF_USE_VERTEX_ANIMATION];
|
||||||
|
}
|
||||||
|
else if (glState.boneAnimation)
|
||||||
|
{
|
||||||
|
sp = &tr.shadowmapShader[SHADOWMAPDEF_USE_BONE_ANIMATION];
|
||||||
|
}
|
||||||
|
|
||||||
vec4_t vector;
|
vec4_t vector;
|
||||||
|
|
||||||
|
@ -1380,6 +1419,11 @@ static void RB_RenderShadowmap( shaderCommands_t *input )
|
||||||
|
|
||||||
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
|
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
|
||||||
|
|
||||||
|
if (glState.boneAnimation)
|
||||||
|
{
|
||||||
|
GLSL_SetUniformMat4BoneMatrix(sp, UNIFORM_BONEMATRIX, glState.boneMatrix, glState.boneAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
|
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
|
||||||
if (deformGen != DGEN_NONE)
|
if (deformGen != DGEN_NONE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1313,4 +1313,5 @@ void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = {
|
||||||
(void(*)(void*))RB_SurfaceFlare, // SF_FLARE,
|
(void(*)(void*))RB_SurfaceFlare, // SF_FLARE,
|
||||||
(void(*)(void*))RB_SurfaceEntity, // SF_ENTITY
|
(void(*)(void*))RB_SurfaceEntity, // SF_ENTITY
|
||||||
(void(*)(void*))RB_SurfaceVaoMdvMesh, // SF_VAO_MDVMESH
|
(void(*)(void*))RB_SurfaceVaoMdvMesh, // SF_VAO_MDVMESH
|
||||||
|
(void(*)(void*))RB_IQMSurfaceAnimVao, // SF_VAO_IQM
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue