openmohaa/code/renderer_gl3/tr_shade_calc.c

1281 lines
26 KiB
C
Raw Normal View History

2016-03-27 11:49:47 +02:00
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2006-2008 Robert Beckebans <trebor_7@users.sourceforge.net>
This file is part of XreaL source code.
XreaL source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
XreaL source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with XreaL source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_shade_calc.c
#include "tr_local.h"
#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ Q_ftol( ( ( (phase) + backEnd.refdef.floatTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))
static float *TableForFunc(genFunc_t func)
{
switch (func)
{
case GF_SIN:
return tr.sinTable;
case GF_TRIANGLE:
return tr.triangleTable;
case GF_SQUARE:
return tr.squareTable;
case GF_SAWTOOTH:
return tr.sawToothTable;
case GF_INVERSE_SAWTOOTH:
return tr.inverseSawToothTable;
case GF_NONE:
default:
break;
}
#if 0
ri.Error(ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'\n", func, tess.surfaceShader->name);
return NULL;
#else
// FIXME ri.Printf(PRINT_WARNING, "TableForFunc called with invalid function '%d' in shader '%s'\n", func, tess.surfaceShader->name);
return tr.sinTable;
#endif
}
/*
** EvalWaveForm
**
** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly
*/
float RB_EvalWaveForm(const waveForm_t * wf)
{
float *table;
table = TableForFunc(wf->func);
return WAVEVALUE(table, wf->base, wf->amplitude, wf->phase, wf->frequency);
}
float RB_EvalWaveFormClamped(const waveForm_t * wf)
{
float glow = RB_EvalWaveForm(wf);
if(glow < 0)
{
return 0;
}
if(glow > 1)
{
return 1;
}
return glow;
}
static float GetOpValue(const expOperation_t * op)
{
float value;
float inv255 = 1.0f / 255.0f;
switch (op->type)
{
case OP_NUM:
value = op->value;
break;
case OP_TIME:
value = backEnd.refdef.floatTime;
break;
case OP_PARM0:
if(backEnd.currentLight)
{
value = backEnd.currentLight->l.color[0];
break;
}
else if(backEnd.currentEntity)
{
value = backEnd.currentEntity->e.shaderRGBA[0] * inv255;
}
else
{
value = 1.0;
}
break;
case OP_PARM1:
if(backEnd.currentLight)
{
value = backEnd.currentLight->l.color[1];
break;
}
else if(backEnd.currentEntity)
{
value = backEnd.currentEntity->e.shaderRGBA[1] * inv255;
}
else
{
value = 1.0;
}
break;
case OP_PARM2:
if(backEnd.currentLight)
{
value = backEnd.currentLight->l.color[2];
break;
}
else if(backEnd.currentEntity)
{
value = backEnd.currentEntity->e.shaderRGBA[2] * inv255;
}
else
{
value = 1.0;
}
break;
case OP_PARM3:
if(backEnd.currentLight)
{
value = 1.0;
break;
}
else if(backEnd.currentEntity)
{
value = backEnd.currentEntity->e.shaderRGBA[3] * inv255;
}
else
{
value = 1.0;
}
break;
case OP_PARM4:
if(backEnd.currentEntity)
{
value = -backEnd.currentEntity->e.shaderTime;
}
else
{
value = 0.0;
}
break;
case OP_PARM5:
case OP_PARM6:
case OP_PARM7:
case OP_PARM8:
case OP_PARM9:
case OP_PARM10:
case OP_PARM11:
case OP_GLOBAL0:
case OP_GLOBAL1:
case OP_GLOBAL2:
case OP_GLOBAL3:
case OP_GLOBAL4:
case OP_GLOBAL5:
case OP_GLOBAL6:
case OP_GLOBAL7:
value = 1.0;
break;
case OP_FRAGMENTSHADERS:
value = 1.0;
break;
case OP_FRAMEBUFFEROBJECTS:
value = glConfig2.framebufferObjectAvailable;
break;
case OP_SOUND:
value = 0.5;
break;
case OP_DISTANCE:
value = 0.0; // FIXME ?
break;
default:
value = 0.0;
break;
}
return value;
}
float RB_EvalExpression(const expression_t * exp, float defaultValue)
{
#if 1
int i;
expOperation_t op;
expOperation_t ops[MAX_EXPRESSION_OPS];
int numOps;
float value;
float value1;
float value2;
extern const opstring_t opStrings[];
numOps = 0;
value = 0;
value1 = 0;
value2 = 0;
if(!exp || !exp->active)
{
return defaultValue;
}
// http://www.qiksearch.com/articles/cs/postfix-evaluation/
// http://www.kyz.uklinux.net/evaluate/
for(i = 0; i < exp->numOps; i++)
{
op = exp->ops[i];
switch (op.type)
{
case OP_BAD:
return defaultValue;
case OP_NEG:
{
if(numOps < 1)
{
ri.Printf(PRINT_ALL, "WARNING: shader %s has numOps < 1 for unary - operator\n", tess.surfaceShader->name);
return defaultValue;
}
value1 = GetOpValue(&ops[numOps - 1]);
numOps--;
value = -value1;
// push result
op.type = OP_NUM;
op.value = value;
ops[numOps++] = op;
break;
}
case OP_NUM:
case OP_TIME:
case OP_PARM0:
case OP_PARM1:
case OP_PARM2:
case OP_PARM3:
case OP_PARM4:
case OP_PARM5:
case OP_PARM6:
case OP_PARM7:
case OP_PARM8:
case OP_PARM9:
case OP_PARM10:
case OP_PARM11:
case OP_GLOBAL0:
case OP_GLOBAL1:
case OP_GLOBAL2:
case OP_GLOBAL3:
case OP_GLOBAL4:
case OP_GLOBAL5:
case OP_GLOBAL6:
case OP_GLOBAL7:
case OP_FRAGMENTSHADERS:
case OP_FRAMEBUFFEROBJECTS:
case OP_SOUND:
case OP_DISTANCE:
ops[numOps++] = op;
break;
case OP_TABLE:
{
shaderTable_t *table;
int numValues;
float index;
float lerp;
int oldIndex;
int newIndex;
if(numOps < 1)
{
ri.Printf(PRINT_ALL, "WARNING: shader %s has numOps < 1 for table operator\n", tess.surfaceShader->name);
return defaultValue;
}
value1 = GetOpValue(&ops[numOps - 1]);
numOps--;
table = tr.shaderTables[(int)op.value];
numValues = table->numValues;
index = value1 * numValues; // float index into the table?s elements
lerp = index - floor(index); // being inbetween two elements of the table
oldIndex = (int)index;
newIndex = (int)index + 1;
if(table->clamp)
{
// clamp indices to table-range
Q_clamp(oldIndex, 0, numValues - 1);
Q_clamp(newIndex, 0, numValues - 1);
}
else
{
// wrap around indices
oldIndex %= numValues;
newIndex %= numValues;
}
if(table->snap)
{
// use fixed value
value = table->values[oldIndex];
}
else
{
// lerp value
value = table->values[oldIndex] + ((table->values[newIndex] - table->values[oldIndex]) * lerp);
}
//ri.Printf(PRINT_ALL, "%s: %i %i %f\n", table->name, oldIndex, newIndex, value);
// push result
op.type = OP_NUM;
op.value = value;
ops[numOps++] = op;
break;
}
default:
{
if(numOps < 2)
{
ri.Printf(PRINT_ALL, "WARNING: shader %s has numOps < 2 for binary operator %s\n", tess.surfaceShader->name,
opStrings[op.type].s);
return defaultValue;
}
value2 = GetOpValue(&ops[numOps - 1]);
numOps--;
value1 = GetOpValue(&ops[numOps - 1]);
numOps--;
switch (op.type)
{
case OP_LAND:
value = value1 && value2;
break;
case OP_LOR:
value = value1 || value2;
break;
case OP_GE:
value = value1 >= value2;
break;
case OP_LE:
value = value1 <= value2;
break;
case OP_LEQ:
value = value1 == value2;
break;
case OP_LNE:
value = value1 != value2;
break;
case OP_ADD:
value = value1 + value2;
break;
case OP_SUB:
value = value1 - value2;
break;
case OP_DIV:
if(value2 == 0)
{
// don't divide by zero
value = value1;
}
else
{
value = value1 / value2;
}
break;
case OP_MOD:
value = (float)((int)value1 % (int)value2);
break;
case OP_MUL:
value = value1 * value2;
break;
case OP_LT:
value = value1 < value2;
break;
case OP_GT:
value = value1 > value2;
break;
default:
value = value1 = value2 = 0;
break;
}
//ri.Printf(PRINT_ALL, "%s: %f %f %f\n", opStrings[op.type].s, value, value1, value2);
// push result
op.type = OP_NUM;
op.value = value;
ops[numOps++] = op;
break;
}
}
}
return GetOpValue(&ops[0]);
#else
return defaultValue;
#endif
}
/*
====================================================================
DEFORMATIONS
====================================================================
*/
/*
========================
RB_CalcDeformVertexes
========================
*/
void RB_CalcDeformVertexes(deformStage_t * ds)
{
int i;
vec3_t offset;
float scale;
float *xyz = (float *)tess.xyz;
float *normal = (float *)tess.normals;
float *table;
#if defined(COMPAT_ET)
if(ds->deformationWave.frequency < 0)
{
qboolean inverse = qfalse;
vec3_t worldUp;
//static vec3_t up = {0,0,1};
if(VectorCompare(backEnd.currentEntity->e.fireRiseDir, vec3_origin))
{
VectorSet(backEnd.currentEntity->e.fireRiseDir, 0, 0, 1);
}
// get the world up vector in local coordinates
if(backEnd.currentEntity->e.hModel)
{ // world surfaces dont have an axis
VectorRotate(backEnd.currentEntity->e.fireRiseDir, backEnd.currentEntity->e.axis, worldUp);
}
else
{
VectorCopy(backEnd.currentEntity->e.fireRiseDir, worldUp);
}
// don't go so far if sideways, since they must be moving
VectorScale(worldUp, 0.4 + 0.6 * Q_fabs(backEnd.currentEntity->e.fireRiseDir[2]), worldUp);
ds->deformationWave.frequency *= -1;
if(ds->deformationWave.frequency > 999)
{ // hack for negative Z deformation (ack)
inverse = qtrue;
ds->deformationWave.frequency -= 999;
}
table = TableForFunc(ds->deformationWave.func);
for(i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4)
{
float off = (xyz[0] + xyz[1] + xyz[2]) * ds->deformationSpread;
float dot;
scale = WAVEVALUE(table, ds->deformationWave.base,
ds->deformationWave.amplitude, ds->deformationWave.phase + off, ds->deformationWave.frequency);
dot = DotProduct(worldUp, normal);
if(dot * scale > 0)
{
if(inverse)
{
scale *= -1;
}
VectorMA(xyz, dot * scale, worldUp, xyz);
}
}
if(inverse)
{
ds->deformationWave.frequency += 999;
}
ds->deformationWave.frequency *= -1;
}
else
#endif // #if defined(COMPAT_ET)
if(ds->deformationWave.frequency == 0)
{
scale = RB_EvalWaveForm(&ds->deformationWave);
for(i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4)
{
VectorScale(normal, scale, offset);
xyz[0] += offset[0];
xyz[1] += offset[1];
xyz[2] += offset[2];
}
}
else
{
table = TableForFunc(ds->deformationWave.func);
for(i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4)
{
float off = (xyz[0] + xyz[1] + xyz[2]) * ds->deformationSpread;
scale = WAVEVALUE(table, ds->deformationWave.base,
ds->deformationWave.amplitude, ds->deformationWave.phase + off, ds->deformationWave.frequency);
VectorScale(normal, scale, offset);
xyz[0] += offset[0];
xyz[1] += offset[1];
xyz[2] += offset[2];
}
}
}
/*
=========================
RB_CalcDeformNormals
Wiggle the normals for wavy environment mapping
=========================
*/
void RB_CalcDeformNormals(deformStage_t * ds)
{
int i;
float scale;
float *xyz = (float *)tess.xyz;
float *normal = (float *)tess.normals;
for(i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4)
{
scale = 0.98f;
scale =
R_NoiseGet4f(xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
backEnd.refdef.floatTime * ds->deformationWave.frequency);
normal[0] += ds->deformationWave.amplitude * scale;
scale = 0.98f;
scale = R_NoiseGet4f(100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
backEnd.refdef.floatTime * ds->deformationWave.frequency);
normal[1] += ds->deformationWave.amplitude * scale;
scale = 0.98f;
scale = R_NoiseGet4f(200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
backEnd.refdef.floatTime * ds->deformationWave.frequency);
normal[2] += ds->deformationWave.amplitude * scale;
VectorNormalizeFast(normal);
}
}
/*
========================
RB_CalcBulgeVertexes
========================
*/
void RB_CalcBulgeVertexes(deformStage_t * ds)
{
int i;
const float *st = (const float *)tess.texCoords[0];
float *xyz = (float *)tess.xyz;
float *normal = (float *)tess.normals;
float now;
now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f;
for(i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4)
{
int off;
float scale;
off = (float)(FUNCTABLE_SIZE / (M_PI * 2)) * (st[0] * ds->bulgeWidth + now);
scale = tr.sinTable[off & FUNCTABLE_MASK] * ds->bulgeHeight;
xyz[0] += normal[0] * scale;
xyz[1] += normal[1] * scale;
xyz[2] += normal[2] * scale;
}
}
/*
======================
RB_CalcMoveVertexes
A deformation that can move an entire surface along a wave path
======================
*/
void RB_CalcMoveVertexes(deformStage_t * ds)
{
int i;
float *xyz;
float *table;
float scale;
vec3_t offset;
table = TableForFunc(ds->deformationWave.func);
scale = WAVEVALUE(table, ds->deformationWave.base,
ds->deformationWave.amplitude, ds->deformationWave.phase, ds->deformationWave.frequency);
VectorScale(ds->moveVector, scale, offset);
xyz = (float *)tess.xyz;
for(i = 0; i < tess.numVertexes; i++, xyz += 4)
{
VectorAdd(xyz, offset, xyz);
}
}
/*
=============
DeformText
Change a polygon into a bunch of text polygons
=============
*/
void DeformText(const char *text)
{
int i;
vec3_t origin, width, height;
int len;
int ch;
float bottom, top;
vec3_t mid;
height[0] = 0;
height[1] = 0;
height[2] = -1;
CrossProduct(tess.normals[0], height, width);
// find the midpoint of the box
VectorClear(mid);
bottom = 999999;
top = -999999;
for(i = 0; i < 4; i++)
{
VectorAdd(tess.xyz[i], mid, mid);
if(tess.xyz[i][2] < bottom)
{
bottom = tess.xyz[i][2];
}
if(tess.xyz[i][2] > top)
{
top = tess.xyz[i][2];
}
}
VectorScale(mid, 0.25f, origin);
// determine the individual character size
height[0] = 0;
height[1] = 0;
height[2] = (top - bottom) * 0.5f;
VectorScale(width, height[2] * -0.75f, width);
// determine the starting position
len = strlen(text);
VectorMA(origin, (len - 1), width, origin);
// clear the shader indexes
tess.multiDrawPrimitives = 0;
tess.numIndexes = 0;
tess.numVertexes = 0;
// draw each character
for(i = 0; i < len; i++)
{
ch = text[i];
ch &= 255;
if(ch != ' ')
{
int row, col;
float frow, fcol, size;
row = ch >> 4;
col = ch & 15;
frow = row * 0.0625f;
fcol = col * 0.0625f;
size = 0.0625f;
Tess_AddQuadStampExt(origin, width, height, colorWhite, fcol, frow, fcol + size, frow + size);
}
VectorMA(origin, -2, width, origin);
}
}
/*
==================
GlobalVectorToLocal
==================
*/
static void GlobalVectorToLocal(const vec3_t in, vec3_t out)
{
out[0] = DotProduct(in, backEnd.orientation.axis[0]);
out[1] = DotProduct(in, backEnd.orientation.axis[1]);
out[2] = DotProduct(in, backEnd.orientation.axis[2]);
}
/*
=====================
AutospriteDeform
Assuming all the triangles for this shader are independant
quads, rebuild them as forward facing sprites
=====================
*/
static void AutospriteDeform(void)
{
int i;
int oldVerts;
float *xyz;
vec3_t mid, delta;
float radius;
vec3_t left, up;
vec3_t leftDir, upDir;
if(tess.numVertexes & 3)
{
ri.Printf(PRINT_WARNING, "Autosprite shader %s had odd vertex count", tess.surfaceShader->name);
}
if(tess.numIndexes != (tess.numVertexes >> 2) * 6)
{
ri.Printf(PRINT_WARNING, "Autosprite shader %s had odd index count", tess.surfaceShader->name);
}
oldVerts = tess.numVertexes;
tess.numVertexes = 0;
tess.numIndexes = 0;
tess.multiDrawPrimitives = 0;
if(backEnd.currentEntity != &tr.worldEntity)
{
GlobalVectorToLocal(backEnd.viewParms.orientation.axis[1], leftDir);
GlobalVectorToLocal(backEnd.viewParms.orientation.axis[2], upDir);
}
else
{
VectorCopy(backEnd.viewParms.orientation.axis[1], leftDir);
VectorCopy(backEnd.viewParms.orientation.axis[2], upDir);
}
for(i = 0; i < oldVerts; i += 4)
{
// find the midpoint
xyz = tess.xyz[i];
mid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]);
mid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]);
mid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]);
VectorSubtract(xyz, mid, delta);
radius = VectorLength(delta) * 0.707f; // / sqrt(2)
VectorScale(leftDir, radius, left);
VectorScale(upDir, radius, up);
if(backEnd.viewParms.isMirror)
{
VectorSubtract(vec3_origin, left, left);
}
// compensate for scale in the axes if necessary
if(backEnd.currentEntity->e.nonNormalizedAxes)
{
float axisLength;
axisLength = VectorLength(backEnd.currentEntity->e.axis[0]);
if(!axisLength)
{
axisLength = 0;
}
else
{
axisLength = 1.0f / axisLength;
}
VectorScale(left, axisLength, left);
VectorScale(up, axisLength, up);
}
Tess_AddQuadStamp(mid, left, up, tess.colors[i]);
}
}
/*
=====================
Autosprite2Deform
Autosprite2 will pivot a rectangular quad along the center of its long axis
=====================
*/
int edgeVerts[6][2] = {
{0, 1},
{0, 2},
{0, 3},
{1, 2},
{1, 3},
{2, 3}
};
static void Autosprite2Deform(void)
{
int i, j, k;
int indexes;
float *xyz;
vec3_t forward;
if(tess.numVertexes & 3)
{
ri.Printf(PRINT_WARNING, "Autosprite2 shader %s had odd vertex count", tess.surfaceShader->name);
}
if(tess.numIndexes != (tess.numVertexes >> 2) * 6)
{
ri.Printf(PRINT_WARNING, "Autosprite2 shader %s had odd index count", tess.surfaceShader->name);
}
if(backEnd.currentEntity != &tr.worldEntity)
{
GlobalVectorToLocal(backEnd.viewParms.orientation.axis[0], forward);
}
else
{
VectorCopy(backEnd.viewParms.orientation.axis[0], forward);
}
// this is a lot of work for two triangles...
// we could precalculate a lot of it is an issue, but it would mess up
// the shader abstraction
for(i = 0, indexes = 0; i < tess.numVertexes; i += 4, indexes += 6)
{
float lengths[2];
int nums[2];
vec3_t mid[2];
vec3_t major, minor;
float *v1, *v2;
// find the midpoint
xyz = tess.xyz[i];
// identify the two shortest edges
nums[0] = nums[1] = 0;
lengths[0] = lengths[1] = 999999;
for(j = 0; j < 6; j++)
{
float l;
vec3_t temp;
v1 = xyz + 4 * edgeVerts[j][0];
v2 = xyz + 4 * edgeVerts[j][1];
VectorSubtract(v1, v2, temp);
l = DotProduct(temp, temp);
if(l < lengths[0])
{
nums[1] = nums[0];
lengths[1] = lengths[0];
nums[0] = j;
lengths[0] = l;
}
else if(l < lengths[1])
{
nums[1] = j;
lengths[1] = l;
}
}
for(j = 0; j < 2; j++)
{
v1 = xyz + 4 * edgeVerts[nums[j]][0];
v2 = xyz + 4 * edgeVerts[nums[j]][1];
mid[j][0] = 0.5f * (v1[0] + v2[0]);
mid[j][1] = 0.5f * (v1[1] + v2[1]);
mid[j][2] = 0.5f * (v1[2] + v2[2]);
}
// find the vector of the major axis
VectorSubtract(mid[1], mid[0], major);
// cross this with the view direction to get minor axis
CrossProduct(major, forward, minor);
VectorNormalize(minor);
// re-project the points
for(j = 0; j < 2; j++)
{
float l;
v1 = xyz + 4 * edgeVerts[nums[j]][0];
v2 = xyz + 4 * edgeVerts[nums[j]][1];
l = 0.5 * sqrt(lengths[j]);
// we need to see which direction this edge
// is used to determine direction of projection
for(k = 0; k < 5; k++)
{
if(tess.indexes[indexes + k] == i + edgeVerts[nums[j]][0]
&& tess.indexes[indexes + k + 1] == i + edgeVerts[nums[j]][1])
{
break;
}
}
if(k == 5)
{
VectorMA(mid[j], l, minor, v1);
VectorMA(mid[j], -l, minor, v2);
}
else
{
VectorMA(mid[j], -l, minor, v1);
VectorMA(mid[j], l, minor, v2);
}
}
}
}
qboolean ShaderRequiresCPUDeforms(const shader_t * shader)
{
if(shader->numDeforms)
{
int i;
qboolean cpuDeforms = qfalse;
if(glConfig.driverType != GLDRV_OPENGL3 || !r_vboDeformVertexes->integer)
return qtrue;
for(i = 0; i < shader->numDeforms; i++)
{
const deformStage_t *ds = &shader->deforms[0];
switch (ds->deformation)
{
case DEFORM_WAVE:
case DEFORM_BULGE:
case DEFORM_MOVE:
break;
default:
cpuDeforms = qtrue;
}
}
return cpuDeforms;
}
return qfalse;
}
/*
=====================
Tess_DeformGeometry
=====================
*/
void Tess_DeformGeometry(void)
{
int i;
deformStage_t *ds;
#if defined(USE_D3D10)
// TODO
#else
if(glState.currentVBO != tess.vbo || glState.currentIBO != tess.ibo)
{
// static VBOs are incompatible with deformVertexes
return;
}
#endif
if(!ShaderRequiresCPUDeforms(tess.surfaceShader))
{
// we don't need the following CPU deforms
return;
}
for(i = 0; i < tess.surfaceShader->numDeforms; i++)
{
ds = &tess.surfaceShader->deforms[i];
switch (ds->deformation)
{
case DEFORM_NONE:
break;
case DEFORM_NORMALS:
RB_CalcDeformNormals(ds);
break;
case DEFORM_WAVE:
RB_CalcDeformVertexes(ds);
break;
case DEFORM_BULGE:
RB_CalcBulgeVertexes(ds);
break;
case DEFORM_MOVE:
RB_CalcMoveVertexes(ds);
break;
case DEFORM_PROJECTION_SHADOW:
RB_ProjectionShadowDeform();
break;
case DEFORM_AUTOSPRITE:
AutospriteDeform();
break;
case DEFORM_AUTOSPRITE2:
Autosprite2Deform();
break;
case DEFORM_TEXT0:
case DEFORM_TEXT1:
case DEFORM_TEXT2:
case DEFORM_TEXT3:
case DEFORM_TEXT4:
case DEFORM_TEXT5:
case DEFORM_TEXT6:
case DEFORM_TEXT7:
DeformText(backEnd.refdef.text[ds->deformation - DEFORM_TEXT0]);
break;
case DEFORM_SPRITE:
//AutospriteDeform();
break;
case DEFORM_FLARE:
//Autosprite2Deform();
break;
}
}
#if !defined(USE_D3D10)
GL_CheckErrors();
#endif
}
/*
====================================================================
TEX COORDS
====================================================================
*/
/*
===============
RB_CalcTexMatrix
===============
*/
void RB_CalcTexMatrix(const textureBundle_t * bundle, matrix_t matrix)
{
int j;
float x, y;
MatrixIdentity(matrix);
for(j = 0; j < bundle->numTexMods; j++)
{
switch (bundle->texMods[j].type)
{
case TMOD_NONE:
j = TR_MAX_TEXMODS; // break out of for loop
break;
case TMOD_TURBULENT:
{
waveForm_t *wf;
wf = &bundle->texMods[j].wave;
x = (1.0 / 4.0);
y = (wf->phase + backEnd.refdef.floatTime * wf->frequency);
MatrixMultiplyScale(matrix, 1 + (wf->amplitude * sin(y) + wf->base) * x,
1 + (wf->amplitude * sin(y + 0.25) + wf->base) * x, 0.0);
break;
}
case TMOD_ENTITY_TRANSLATE:
{
x = backEnd.currentEntity->e.shaderTexCoord[0] * backEnd.refdef.floatTime;
y = backEnd.currentEntity->e.shaderTexCoord[1] * backEnd.refdef.floatTime;
// clamp so coordinates don't continuously get larger, causing problems
// with hardware limits
x = x - floor(x);
y = y - floor(y);
MatrixMultiplyTranslation(matrix, x, y, 0.0);
break;
}
case TMOD_SCROLL:
{
x = bundle->texMods[j].scroll[0] * backEnd.refdef.floatTime;
y = bundle->texMods[j].scroll[1] * backEnd.refdef.floatTime;
// clamp so coordinates don't continuously get larger, causing problems
// with hardware limits
x = x - floor(x);
y = y - floor(y);
MatrixMultiplyTranslation(matrix, x, y, 0.0);
break;
}
case TMOD_SCALE:
{
x = bundle->texMods[j].scale[0];
y = bundle->texMods[j].scale[1];
MatrixMultiplyScale(matrix, x, y, 0.0);
break;
}
case TMOD_STRETCH:
{
float p;
p = 1.0f / RB_EvalWaveForm(&bundle->texMods[j].wave);
MatrixMultiplyTranslation(matrix, 0.5, 0.5, 0.0);
MatrixMultiplyScale(matrix, p, p, 0.0);
MatrixMultiplyTranslation(matrix, -0.5, -0.5, 0.0);
break;
}
case TMOD_TRANSFORM:
{
const texModInfo_t *tmi = &bundle->texMods[j];
MatrixMultiply2(matrix, tmi->matrix);
break;
}
case TMOD_ROTATE:
{
x = -bundle->texMods[j].rotateSpeed * backEnd.refdef.floatTime;
MatrixMultiplyTranslation(matrix, 0.5, 0.5, 0.0);
MatrixMultiplyZRotation(matrix, x);
MatrixMultiplyTranslation(matrix, -0.5, -0.5, 0.0);
break;
}
case TMOD_SCROLL2:
{
x = RB_EvalExpression(&bundle->texMods[j].sExp, 0);
y = RB_EvalExpression(&bundle->texMods[j].tExp, 0);
// clamp so coordinates don't continuously get larger, causing problems
// with hardware limits
x = x - floor(x);
y = y - floor(y);
MatrixMultiplyTranslation(matrix, x, y, 0.0);
break;
}
case TMOD_SCALE2:
{
x = RB_EvalExpression(&bundle->texMods[j].sExp, 0);
y = RB_EvalExpression(&bundle->texMods[j].tExp, 0);
MatrixMultiplyScale(matrix, x, y, 0.0);
break;
}
case TMOD_CENTERSCALE:
{
x = RB_EvalExpression(&bundle->texMods[j].sExp, 0);
y = RB_EvalExpression(&bundle->texMods[j].tExp, 0);
MatrixMultiplyTranslation(matrix, 0.5, 0.5, 0.0);
MatrixMultiplyScale(matrix, x, y, 0.0);
MatrixMultiplyTranslation(matrix, -0.5, -0.5, 0.0);
break;
}
case TMOD_SHEAR:
{
x = RB_EvalExpression(&bundle->texMods[j].sExp, 0);
y = RB_EvalExpression(&bundle->texMods[j].tExp, 0);
MatrixMultiplyTranslation(matrix, 0.5, 0.5, 0.0);
MatrixMultiplyShear(matrix, x, y);
MatrixMultiplyTranslation(matrix, -0.5, -0.5, 0.0);
break;
}
case TMOD_ROTATE2:
{
x = RB_EvalExpression(&bundle->texMods[j].rExp, 0);
MatrixMultiplyTranslation(matrix, 0.5, 0.5, 0.0);
MatrixMultiplyZRotation(matrix, x);
MatrixMultiplyTranslation(matrix, -0.5, -0.5, 0.0);
break;
}
default:
break;
}
}
}