thirtyflightsofloving/renderer/r_backend.c
Knightmare66 4eea7036b8 Added Ethan Lee's Linux porting changes.
Moved loadingMessage, loadingMessages, and loadingPercent variables in client into client_static_t struct.
2021-10-11 15:38:20 -04:00

343 lines
8.6 KiB
C

/*
===========================================================================
Copyright (C) 1997-2001 Id Software, Inc.
Copyright (C) 2000-2002 Knightmare
This file is part of Quake 2 source code.
Quake 2 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.
Quake 2 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 Quake 2 source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// r_backend.c: array and texture coord handling for protoshaders
#include "r_local.h"
#define TABLE_SIZE 1024
#define TABLE_MASK 1023
static float rb_sinTable[TABLE_SIZE];
static float rb_triangleTable[TABLE_SIZE];
static float rb_squareTable[TABLE_SIZE];
static float rb_sawtoothTable[TABLE_SIZE];
static float rb_inverseSawtoothTable[TABLE_SIZE];
static float rb_noiseTable[TABLE_SIZE];
// vertex arrays
unsigned indexArray[MAX_INDICES];
float texCoordArray[MAX_TEXTURE_UNITS][MAX_VERTICES][2];
float vertexArray[MAX_VERTICES][3];
float colorArray[MAX_VERTICES][4];
float inTexCoordArray[MAX_VERTICES][2];
float celTexCoordArray[MAX_VERTICES][2]; // for cel shading
unsigned rb_vertex, rb_index;
/*
=================
RB_BuildTables
=================
*/
static void RB_BuildTables (void)
{
int i;
float f;
for (i = 0; i < TABLE_SIZE; i++)
{
f = (float)i / (float)TABLE_SIZE;
rb_sinTable[i] = sin(f * M_PI2);
if (f < 0.25)
rb_triangleTable[i] = 4.0 * f;
else if (f < 0.75)
rb_triangleTable[i] = 2.0 - 4.0 * f;
else
rb_triangleTable[i] = (f - 0.75) * 4.0 - 1.0;
if (f < 0.5)
rb_squareTable[i] = 1.0;
else
rb_squareTable[i] = -1.0;
rb_sawtoothTable[i] = f;
rb_inverseSawtoothTable[i] = 1.0 - f;
rb_noiseTable[i] = crand();
}
}
/*
=================
RB_TableForFunc
=================
*/
static float *RB_TableForFunc (const waveFunc_t *func)
{
switch (func->type)
{
case WAVEFORM_SIN:
return rb_sinTable;
case WAVEFORM_TRIANGLE:
return rb_triangleTable;
case WAVEFORM_SQUARE:
return rb_squareTable;
case WAVEFORM_SAWTOOTH:
return rb_sawtoothTable;
case WAVEFORM_INVERSESAWTOOTH:
return rb_inverseSawtoothTable;
case WAVEFORM_NOISE:
return rb_noiseTable;
}
VID_Error (ERR_DROP, "RB_TableForFunc: unknown waveform type %i", func->type);
return rb_sinTable;
}
/*
=================
RB_InitBackend
=================
*/
void RB_InitBackend (void)
{
// Build waveform tables
RB_BuildTables();
}
/*
=================
RB_CalcGlowColor
=================
*/
float RB_CalcGlowColor (renderparms_t *parms)
{
float *table, rad, out=1.0f;
if (!parms) return 0.0f;
if (parms->glow.type > -1)
{
table = RB_TableForFunc(&parms->glow);
rad = parms->glow.params[2] + parms->glow.params[3] * r_newrefdef.time;
out = table[((int)(rad * TABLE_SIZE)) & TABLE_MASK] * parms->glow.params[1] + parms->glow.params[0];
out = max(min(out, 1.0f), 0.0f); // clamp
}
return out;
}
/*
=================
RB_ModifyTextureCoords
borrowed from EGL & Q2E
=================
*/
void RB_ModifyTextureCoords (float *inArray, float *inVerts, int numVerts, tcmodParms_t *parms)
{
int i;
float t1, t2, sint, cost, rad;
float *tcArray, *vertArray, *table;
if (!inArray || !inVerts || !parms)
return;
if (parms->translate_x != 0.0f)
for (tcArray=inArray, i=0; i<numVerts; i++, tcArray+=2)
tcArray[0] += parms->translate_x;
if (parms->translate_y != 0.0f)
for (tcArray=inArray, i=0; i<numVerts; i++, tcArray+=2)
tcArray[1] += parms->translate_y;
if (parms->rotate != 0.0f)
{
rad = -DEG2RAD(parms->rotate * r_newrefdef.time);
sint = sin(rad);
cost = cos(rad);
for (tcArray=inArray, i=0; i<numVerts; i++, tcArray+=2) {
t1 = tcArray[0];
t2 = tcArray[1];
tcArray[0] = cost * (t1 - 0.5) - sint * (t2 - 0.5) + 0.5;
tcArray[1] = cost * (t2 - 0.5) + sint * (t1 - 0.5) + 0.5;
}
}
if (parms->stretch.type > -1)
{
table = RB_TableForFunc(&parms->stretch);
rad = parms->stretch.params[2] + parms->stretch.params[3] * r_newrefdef.time;
t1 = table[((int)(rad * TABLE_SIZE)) & TABLE_MASK] * parms->stretch.params[1] + parms->stretch.params[0];
t1 = (t1) ? 1.0 / t1 : 1.0;
t2 = 0.5 - 0.5 * t1;
for (tcArray=inArray, i=0; i<numVerts; i++, tcArray+=2) {
tcArray[0] = tcArray[0] * t1 + t2;
tcArray[1] = tcArray[1] * t1 + t2;
}
}
if (parms->scale_x != 1.0f)
for (tcArray=inArray, i=0; i<numVerts; i++, tcArray+=2)
tcArray[0] = tcArray[0] / parms->scale_x;
if (parms->scale_y != 1.0f)
for (tcArray=inArray, i=0; i<numVerts; i++, tcArray+=2)
tcArray[1] = tcArray[1] / parms->scale_y;
if (parms->turb.type > -1)
{
table = RB_TableForFunc(&parms->turb);
t1 = parms->turb.params[2] + parms->turb.params[3] * r_newrefdef.time;
for (tcArray=inArray, vertArray=inVerts, i=0; i<numVerts; i++, tcArray+=2, vertArray+=3) {
tcArray[0] += (table[((int)(((vertArray[0] + vertArray[2]) * 1.0/128 * 0.125 + t1) * TABLE_SIZE)) & TABLE_MASK] * parms->turb.params[1] + parms->turb.params[0]);
tcArray[1] += (table[((int)(((vertArray[1]) * 1.0/128 * 0.125 + t1) * TABLE_SIZE)) & TABLE_MASK] * parms->turb.params[1] + parms->turb.params[0]);
}
}
if (parms->scroll_x != 0.0f)
for (tcArray=inArray, i=0; i<numVerts; i++, tcArray+=2)
tcArray[0] += r_newrefdef.time * parms->scroll_x;
if (parms->scroll_y != 0.0f)
for (tcArray=inArray, i=0; i<numVerts; i++, tcArray+=2)
tcArray[1] += r_newrefdef.time * parms->scroll_y;
}
/*
=================
RB_CheckArrayOverflow
=================
*/
qboolean RB_CheckArrayOverflow (int numVerts, int numIndex)
{
if (rb_vertex == 0 || rb_index == 0) return false; // nothing to purge
if (numVerts > MAX_VERTICES || numIndex > MAX_INDICES)
Com_Error(ERR_DROP, "RB_CheckArrayOverflow: %i > MAX_VERTICES or %i > MAX_INDICES", numVerts, numIndex);
if (rb_vertex + numVerts <= MAX_VERTICES && rb_index + numIndex <= MAX_INDICES)
return false;
// VID_Printf(PRINT_DEVELOPER, "RB_CheckArrayOverflow: purging %i verts and %i indices to prevent overflow from %i, %i more\n", rb_vertex, rb_index, numVerts, numIndex);
return true;
}
/*
=================
RB_DrawArrays
=================
*/
void RB_DrawArrays (void)
{
if (rb_vertex == 0 || rb_index == 0) // nothing to render
return;
// GL_LockArrays (rb_vertex);
if (glConfig.drawRangeElements)
qglDrawRangeElements(GL_TRIANGLES, 0, rb_vertex, rb_index, GL_UNSIGNED_INT, indexArray);
else
qglDrawElements(GL_TRIANGLES, rb_index, GL_UNSIGNED_INT, indexArray);
// GL_UnlockArrays ();
}
/*
=================
RB_DrawRangeArrays
=================
*/
void RB_DrawRangeArrays (unsigned start, unsigned end)
{
unsigned count;
if (rb_vertex == 0 || end == 0 || end <= start) // nothing to render
return;
count = end - start + 1;
// GL_LockArrays (rb_vertex);
if (glConfig.drawRangeElements)
qglDrawRangeElements(GL_TRIANGLES, 0, rb_vertex, count, GL_UNSIGNED_INT, &indexArray[start]);
else
qglDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, &indexArray[start]);
// GL_UnlockArrays ();
}
/*
=================
RB_DrawPrimitiveArrays
=================
*/
void RB_DrawPrimitiveArrays (GLenum mode)
{
if (rb_vertex == 0 || rb_index == 0) // nothing to render
return;
// GL_LockArrays (rb_vertex);
if (glConfig.drawRangeElements)
qglDrawRangeElements(mode, 0, rb_vertex, rb_index, GL_UNSIGNED_INT, indexArray);
else
qglDrawElements(mode, rb_index, GL_UNSIGNED_INT, indexArray);
// GL_UnlockArrays ();
}
/*
=============
RB_DrawMeshTris
Re-draws a mesh in outline mode
=============
*/
void RB_DrawMeshTris (void)
{
int i, numTMUs = 0;
if (!r_showtris->integer)
return;
if (r_showtris->integer == 1)
GL_Disable(GL_DEPTH_TEST);
qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
for (i=0; i<glConfig.max_texunits; i++)
if (glState.activetmu[i])
{ numTMUs++; GL_DisableTexture (i); }
qglDisableClientState (GL_COLOR_ARRAY);
qglColor4f(1.0, 1.0, 1.0, 1.0);
RB_DrawArrays ();
qglEnableClientState (GL_COLOR_ARRAY);
for (i=0; i<numTMUs; i++)
GL_EnableTexture(i);
qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
if (r_showtris->integer == 1)
GL_Enable(GL_DEPTH_TEST);
}
/*
=================
RB_RenderMeshGeneric
=================
*/
void RB_RenderMeshGeneric (qboolean drawTris)
{
RB_DrawArrays ();
if (drawTris)
RB_DrawMeshTris ();
rb_vertex = rb_index = 0;
}