2009-07-22 22:00:00 +02:00
|
|
|
|
//=======================================================================
|
|
|
|
|
// Copyright XashXT Group 2007 <20>
|
|
|
|
|
// r_draw.c - draw 2d pictures
|
|
|
|
|
//=======================================================================
|
|
|
|
|
|
|
|
|
|
#include "r_local.h"
|
|
|
|
|
#include "mathlib.h"
|
2010-07-13 22:00:00 +02:00
|
|
|
|
#include "matrix_lib.h"
|
2009-12-07 22:00:00 +01:00
|
|
|
|
#include "triangle_api.h"
|
2009-07-22 22:00:00 +02:00
|
|
|
|
|
2009-12-07 22:00:00 +01:00
|
|
|
|
static vec4_t pic_xyz[4] = { {0,0,0,1}, {0,0,0,1}, {0,0,0,1}, {0,0,0,1} };
|
|
|
|
|
static vec2_t pic_st[4];
|
|
|
|
|
static rgba_t pic_colors[4];
|
2010-05-22 22:00:00 +02:00
|
|
|
|
static mesh_t pic_mesh = { 4, 6, pic_xyz, pic_xyz, NULL, NULL, pic_st, NULL, pic_colors, NULL, NULL };
|
2009-12-07 22:00:00 +01:00
|
|
|
|
meshbuffer_t pic_mbuffer;
|
2009-07-22 22:00:00 +02:00
|
|
|
|
|
2009-08-07 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
===============
|
|
|
|
|
R_DrawSetColor
|
|
|
|
|
===============
|
|
|
|
|
*/
|
2009-09-10 22:00:00 +02:00
|
|
|
|
void R_DrawSetColor( const rgba_t color )
|
2009-08-07 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
if( color ) Vector4Copy( color, glState.draw_color );
|
2009-09-10 22:00:00 +02:00
|
|
|
|
else Vector4Set( glState.draw_color, 255, 255, 255, 255 );
|
2009-08-07 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2009-07-22 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
===============
|
|
|
|
|
R_DrawStretchPic
|
|
|
|
|
===============
|
|
|
|
|
*/
|
2009-07-27 22:00:00 +02:00
|
|
|
|
void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, shader_t handle )
|
2009-07-22 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
int bcolor;
|
2009-07-27 22:00:00 +02:00
|
|
|
|
ref_shader_t *shader;
|
2009-08-25 22:00:00 +02:00
|
|
|
|
static int oldframe;
|
2009-07-22 22:00:00 +02:00
|
|
|
|
|
2009-07-27 22:00:00 +02:00
|
|
|
|
if( handle < 0 || handle > MAX_SHADERS || !(shader = &r_shaders[handle]))
|
|
|
|
|
return;
|
2009-07-22 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// lower-left
|
|
|
|
|
Vector2Set( pic_xyz[0], x, y );
|
|
|
|
|
Vector2Set( pic_st[0], s1, t1 );
|
2009-09-10 22:00:00 +02:00
|
|
|
|
Vector4Copy( glState.draw_color, pic_colors[0] );
|
2009-07-22 22:00:00 +02:00
|
|
|
|
bcolor = *(int *)pic_colors[0];
|
|
|
|
|
|
|
|
|
|
// lower-right
|
|
|
|
|
Vector2Set( pic_xyz[1], x+w, y );
|
|
|
|
|
Vector2Set( pic_st[1], s2, t1 );
|
|
|
|
|
*(int *)pic_colors[1] = bcolor;
|
|
|
|
|
|
|
|
|
|
// upper-right
|
|
|
|
|
Vector2Set( pic_xyz[2], x+w, y+h );
|
|
|
|
|
Vector2Set( pic_st[2], s2, t2 );
|
|
|
|
|
*(int *)pic_colors[2] = bcolor;
|
|
|
|
|
|
|
|
|
|
// upper-left
|
|
|
|
|
Vector2Set( pic_xyz[3], x, y+h );
|
|
|
|
|
Vector2Set( pic_st[3], s1, t2 );
|
|
|
|
|
*(int *)pic_colors[3] = bcolor;
|
|
|
|
|
|
|
|
|
|
if( pic_mbuffer.shaderkey != (int)shader->sortkey || -pic_mbuffer.infokey-1+4 > MAX_ARRAY_VERTS )
|
|
|
|
|
{
|
|
|
|
|
if( pic_mbuffer.shaderkey )
|
|
|
|
|
{
|
|
|
|
|
pic_mbuffer.infokey = -1;
|
|
|
|
|
R_RenderMeshBuffer( &pic_mbuffer );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-03 22:00:00 +02:00
|
|
|
|
tr.iRenderMode = glState.draw_rendermode;
|
2009-07-22 22:00:00 +02:00
|
|
|
|
pic_mbuffer.shaderkey = shader->sortkey;
|
2009-08-04 22:00:00 +02:00
|
|
|
|
pic_mbuffer.infokey -= 4;
|
2009-07-22 22:00:00 +02:00
|
|
|
|
|
2009-07-27 22:00:00 +02:00
|
|
|
|
R_PushMesh( &pic_mesh, MF_TRIFAN|shader->features | ( r_shownormals->integer ? MF_NORMALS : 0 ));
|
2009-08-25 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if( oldframe != glState.draw_frame )
|
|
|
|
|
{
|
2010-03-17 22:00:00 +01:00
|
|
|
|
if( pic_mbuffer.shaderkey != shader->sortkey )
|
2009-08-25 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// will be rendering on next call
|
|
|
|
|
oldframe = glState.draw_frame;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if( pic_mbuffer.shaderkey )
|
|
|
|
|
{
|
|
|
|
|
pic_mbuffer.infokey = -1;
|
|
|
|
|
R_RenderMeshBuffer( &pic_mbuffer );
|
|
|
|
|
}
|
|
|
|
|
oldframe = glState.draw_frame;
|
|
|
|
|
}
|
2009-07-22 22:00:00 +02:00
|
|
|
|
}
|
2010-10-01 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
R_ResampleRaw
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
static byte *R_ResampleRaw( const byte *source, int inWidth, int inHeight, int outWidth, int outHeight )
|
|
|
|
|
{
|
|
|
|
|
uint frac, fracStep;
|
|
|
|
|
uint *in = (uint *)source;
|
|
|
|
|
uint p1[0x1000], p2[0x1000];
|
|
|
|
|
byte *pix1, *pix2, *pix3, *pix4;
|
|
|
|
|
uint *inRow1, *inRow2, *out;
|
|
|
|
|
static byte *resampled = NULL;
|
|
|
|
|
int i, x, y;
|
|
|
|
|
|
|
|
|
|
// clean frames doesn't contain raw buffer
|
|
|
|
|
if( !source ) return NULL;
|
|
|
|
|
|
|
|
|
|
resampled = Mem_Realloc( r_temppool, resampled, outWidth * outHeight * 4 );
|
|
|
|
|
out = (uint *)resampled;
|
|
|
|
|
|
|
|
|
|
fracStep = inWidth * 0x10000 / outWidth;
|
|
|
|
|
|
|
|
|
|
frac = fracStep >> 2;
|
|
|
|
|
for( i = 0; i < outWidth; i++ )
|
|
|
|
|
{
|
|
|
|
|
p1[i] = 4 * (frac >> 16);
|
|
|
|
|
frac += fracStep;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
frac = (fracStep >> 2) * 3;
|
|
|
|
|
for( i = 0; i < outWidth; i++ )
|
|
|
|
|
{
|
|
|
|
|
p2[i] = 4 * (frac >> 16);
|
|
|
|
|
frac += fracStep;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for( y = 0; y < outHeight; y++, out += outWidth )
|
|
|
|
|
{
|
|
|
|
|
inRow1 = in + inWidth * (int)(((float)y + 0.25) * inHeight/outHeight);
|
|
|
|
|
inRow2 = in + inWidth * (int)(((float)y + 0.75) * inHeight/outHeight);
|
|
|
|
|
|
|
|
|
|
for( x = 0; x < outWidth; x++ )
|
|
|
|
|
{
|
|
|
|
|
pix1 = (byte *)inRow1 + p1[x];
|
|
|
|
|
pix2 = (byte *)inRow1 + p2[x];
|
|
|
|
|
pix3 = (byte *)inRow2 + p1[x];
|
|
|
|
|
pix4 = (byte *)inRow2 + p2[x];
|
|
|
|
|
|
|
|
|
|
((byte *)(out+x))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0]) >> 2;
|
|
|
|
|
((byte *)(out+x))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1]) >> 2;
|
|
|
|
|
((byte *)(out+x))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2]) >> 2;
|
|
|
|
|
((byte *)(out+x))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3]) >> 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return resampled;
|
|
|
|
|
}
|
2009-07-22 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_DrawStretchRaw
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2010-10-26 22:00:00 +02:00
|
|
|
|
void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty )
|
2009-07-22 22:00:00 +02:00
|
|
|
|
{
|
2010-10-01 22:00:00 +02:00
|
|
|
|
byte *raw;
|
|
|
|
|
|
2009-08-05 22:00:00 +02:00
|
|
|
|
if( !GL_Support( R_ARB_TEXTURE_NPOT_EXT ))
|
|
|
|
|
{
|
|
|
|
|
int width = 1, height = 1;
|
|
|
|
|
|
|
|
|
|
// check the dimensions
|
|
|
|
|
while( width < cols ) width <<= 1;
|
|
|
|
|
while( height < rows ) height <<= 1;
|
|
|
|
|
|
|
|
|
|
if( cols != width || rows != height )
|
2010-10-01 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
raw = R_ResampleRaw( data, cols, rows, width, height );
|
|
|
|
|
cols = width;
|
|
|
|
|
rows = height;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
raw = (byte *)data;
|
2009-08-05 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( cols > glConfig.max_2d_texture_size )
|
|
|
|
|
Host_Error( "R_DrawStretchRaw: size exceeds hardware limits (%i > %i)\n", cols, glConfig.max_2d_texture_size );
|
|
|
|
|
if( rows > glConfig.max_2d_texture_size )
|
|
|
|
|
Host_Error( "R_DrawStretchRaw: size exceeds hardware limits (%i > %i)\n", rows, glConfig.max_2d_texture_size );
|
2009-07-22 22:00:00 +02:00
|
|
|
|
|
2010-10-01 22:00:00 +02:00
|
|
|
|
// draw logo may be called between two draw pic calls.
|
|
|
|
|
// so we need flush it here
|
2010-09-30 22:00:00 +02:00
|
|
|
|
if( pic_mbuffer.infokey != -1 )
|
|
|
|
|
{
|
|
|
|
|
R_RenderMeshBuffer( &pic_mbuffer );
|
|
|
|
|
pic_mbuffer.infokey = -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-27 22:00:00 +02:00
|
|
|
|
GL_Bind( 0, tr.cinTexture );
|
2009-07-22 22:00:00 +02:00
|
|
|
|
|
2009-07-27 22:00:00 +02:00
|
|
|
|
if( cols == tr.cinTexture->width && rows == tr.cinTexture->height )
|
2009-07-26 22:00:00 +02:00
|
|
|
|
{
|
2010-10-01 22:00:00 +02:00
|
|
|
|
if( dirty ) pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_BGRA, GL_UNSIGNED_BYTE, raw );
|
2009-07-26 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-07-27 22:00:00 +02:00
|
|
|
|
tr.cinTexture->width = cols;
|
|
|
|
|
tr.cinTexture->height = rows;
|
2010-10-01 22:00:00 +02:00
|
|
|
|
if( dirty ) pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw );
|
2009-07-26 22:00:00 +02:00
|
|
|
|
}
|
2009-11-23 22:00:00 +01:00
|
|
|
|
|
2009-07-26 22:00:00 +02:00
|
|
|
|
R_CheckForErrors();
|
2009-07-22 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
pglBegin( GL_QUADS );
|
|
|
|
|
pglTexCoord2f( 0, 0 );
|
|
|
|
|
pglVertex2f( x, y );
|
|
|
|
|
pglTexCoord2f( 1, 0 );
|
|
|
|
|
pglVertex2f( x + w, y );
|
|
|
|
|
pglTexCoord2f( 1, 1 );
|
|
|
|
|
pglVertex2f( x + w, y + h );
|
|
|
|
|
pglTexCoord2f( 0, 1 );
|
|
|
|
|
pglVertex2f( x, y + h );
|
|
|
|
|
pglEnd();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void R_DrawGetParms( int *w, int *h, int *f, int frame, shader_t handle )
|
|
|
|
|
{
|
2009-07-27 22:00:00 +02:00
|
|
|
|
ref_shader_t *shader;
|
|
|
|
|
int cur = 0;
|
2009-07-22 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if( !w && !h && !f ) return;
|
|
|
|
|
|
|
|
|
|
// assume error
|
|
|
|
|
if( w ) *w = 0;
|
|
|
|
|
if( h ) *h = 0;
|
|
|
|
|
if( f ) *f = 1;
|
|
|
|
|
|
|
|
|
|
if( handle < 0 || handle > MAX_SHADERS || !(shader = &r_shaders[handle]))
|
|
|
|
|
return;
|
|
|
|
|
|
2009-07-29 22:00:00 +02:00
|
|
|
|
if( !shader->num_stages || !shader->stages[0].textures[0] )
|
2009-07-22 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
|
2009-07-29 22:00:00 +02:00
|
|
|
|
if( shader->stages[0].textures[0] && shader->stages[0].num_textures && frame > 0 )
|
|
|
|
|
cur = bound( 0, frame, shader->stages[0].num_textures );
|
2009-07-22 22:00:00 +02:00
|
|
|
|
|
2009-07-29 22:00:00 +02:00
|
|
|
|
if( w ) *w = (int)shader->stages[0].textures[cur]->srcWidth;
|
|
|
|
|
if( h ) *h = (int)shader->stages[0].textures[cur]->srcHeight;
|
|
|
|
|
if( f ) *f = (int)shader->stages[0].num_textures;
|
2009-07-22 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-10-26 22:00:00 +02:00
|
|
|
|
void R_DrawSetParms( shader_t handle, int rendermode, int frame )
|
2009-07-27 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
ref_shader_t *shader;
|
|
|
|
|
|
2009-07-29 22:00:00 +02:00
|
|
|
|
if( handle < 0 || handle > MAX_SHADERS || !(shader = &r_shaders[handle]) || !shader->num_stages )
|
2009-07-27 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
|
2010-07-20 22:00:00 +02:00
|
|
|
|
if( glState.draw_rendermode != rendermode )
|
|
|
|
|
{
|
|
|
|
|
if( pic_mbuffer.shaderkey )
|
|
|
|
|
{
|
|
|
|
|
pic_mbuffer.infokey = -1;
|
|
|
|
|
R_RenderMeshBuffer( &pic_mbuffer );
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-27 22:00:00 +02:00
|
|
|
|
glState.draw_rendermode = rendermode;
|
|
|
|
|
|
2009-07-29 22:00:00 +02:00
|
|
|
|
if( !shader->stages[0].num_textures )
|
2009-07-27 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// change frame if need
|
2009-07-29 22:00:00 +02:00
|
|
|
|
if( shader->stages[0].flags & SHADERSTAGE_FRAMES )
|
2009-07-27 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// make sure what frame inbound
|
2009-07-29 22:00:00 +02:00
|
|
|
|
glState.draw_frame = bound( 0, frame, shader->stages[0].num_textures - 1 );
|
2009-07-27 22:00:00 +02:00
|
|
|
|
}
|
2009-12-07 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============================================================
|
|
|
|
|
|
|
|
|
|
TRIAPI IMPLEMENTATION
|
|
|
|
|
|
|
|
|
|
=============================================================
|
|
|
|
|
*/
|
|
|
|
|
#define MAX_TRIVERTS 1024
|
|
|
|
|
#define MAX_TRIELEMS MAX_TRIVERTS * 6
|
|
|
|
|
#define MAX_TRIANGLES MAX_TRIELEMS / 3
|
|
|
|
|
|
|
|
|
|
static vec4_t tri_vertex[MAX_TRIVERTS];
|
|
|
|
|
static vec4_t tri_normal[MAX_TRIVERTS];
|
|
|
|
|
static vec2_t tri_coords[MAX_TRIVERTS];
|
|
|
|
|
static rgba_t tri_colors[MAX_TRIVERTS];
|
|
|
|
|
static elem_t tri_elems[MAX_TRIELEMS];
|
|
|
|
|
static mesh_t tri_mesh;
|
2010-10-26 22:00:00 +02:00
|
|
|
|
static qboolean tri_caps[3];
|
2009-12-07 22:00:00 +01:00
|
|
|
|
meshbuffer_t tri_mbuffer;
|
|
|
|
|
tristate_t triState;
|
2010-03-22 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
static void Tri_ClearBounds( void )
|
|
|
|
|
{
|
|
|
|
|
// clear bounds that uses for polygon lighting
|
|
|
|
|
VectorClear( triState.lightingOrigin );
|
|
|
|
|
ClearBounds( triState.mins, triState.maxs );
|
|
|
|
|
}
|
2009-12-07 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
static void Tri_DrawPolygon( void )
|
|
|
|
|
{
|
|
|
|
|
ref_shader_t *shader;
|
2010-03-15 22:00:00 +01:00
|
|
|
|
static int i, oldframe;
|
2009-12-07 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
if( tri_caps[TRI_SHADER] )
|
|
|
|
|
shader = &r_shaders[triState.currentShader];
|
|
|
|
|
else shader = tr.fillShader;
|
|
|
|
|
|
2010-05-22 22:00:00 +02:00
|
|
|
|
tri_mesh.numVerts = triState.numVertex;
|
2009-12-07 22:00:00 +01:00
|
|
|
|
tri_mesh.numElems = triState.numIndex;
|
|
|
|
|
|
|
|
|
|
if( triState.hasNormals )
|
|
|
|
|
tri_mesh.normalsArray = tri_normal;
|
|
|
|
|
else tri_mesh.normalsArray = NULL; // no normals
|
|
|
|
|
|
2010-03-15 22:00:00 +01:00
|
|
|
|
if( triState.numColor == 1 )
|
|
|
|
|
{
|
|
|
|
|
// global color for all vertexes
|
|
|
|
|
for( i = 0; i < triState.numVertex - 1; i++ )
|
|
|
|
|
Vector4Copy( tri_colors[0], tri_colors[i+1] );
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-22 22:00:00 +01:00
|
|
|
|
// compute lightingOrigin
|
|
|
|
|
VectorAverage( triState.mins, triState.maxs, triState.lightingOrigin );
|
|
|
|
|
|
2010-05-22 22:00:00 +02:00
|
|
|
|
tri_mesh.vertexArray = tri_vertex;
|
|
|
|
|
tri_mesh.stCoordArray = tri_coords;
|
|
|
|
|
tri_mesh.colorsArray = tri_colors;
|
2009-12-07 22:00:00 +01:00
|
|
|
|
tri_mesh.elems = tri_elems;
|
|
|
|
|
|
2010-05-28 22:00:00 +02:00
|
|
|
|
if( tri_mbuffer.shaderkey != (int)shader->sortkey || -tri_mbuffer.infokey-1+256 > MAX_ARRAY_VERTS )
|
2009-12-07 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
if( tri_mbuffer.shaderkey )
|
|
|
|
|
{
|
|
|
|
|
tri_mbuffer.infokey = -1;
|
|
|
|
|
R_RenderMeshBuffer( &tri_mbuffer );
|
2010-03-22 22:00:00 +01:00
|
|
|
|
Tri_ClearBounds();
|
2009-12-07 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tr.iRenderMode = triState.currentRenderMode;
|
|
|
|
|
tri_mbuffer.shaderkey = shader->sortkey;
|
2010-03-17 22:00:00 +01:00
|
|
|
|
tri_mbuffer.infokey -= triState.numVertex;
|
2009-12-07 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
triState.features = shader->features;
|
|
|
|
|
triState.features |= MF_COLORS;
|
|
|
|
|
if( r_shownormals->integer || triState.hasNormals )
|
|
|
|
|
triState.features |= MF_NORMALS;
|
|
|
|
|
|
|
|
|
|
if( triState.noCulling )
|
|
|
|
|
triState.features |= MF_NOCULL;
|
|
|
|
|
|
|
|
|
|
R_PushMesh( &tri_mesh, triState.features );
|
|
|
|
|
|
|
|
|
|
if( oldframe != glState.draw_frame )
|
|
|
|
|
{
|
2010-03-17 22:00:00 +01:00
|
|
|
|
if( tri_mbuffer.shaderkey != shader->sortkey )
|
2009-12-07 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
// will be rendering on next call
|
|
|
|
|
oldframe = glState.draw_frame;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if( tri_mbuffer.shaderkey )
|
|
|
|
|
{
|
|
|
|
|
tri_mbuffer.infokey = -1;
|
|
|
|
|
R_RenderMeshBuffer( &tri_mbuffer );
|
2010-03-22 22:00:00 +01:00
|
|
|
|
Tri_ClearBounds();
|
2009-12-07 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
oldframe = glState.draw_frame;
|
|
|
|
|
}
|
2010-03-17 22:00:00 +01:00
|
|
|
|
triState.numVertex = triState.numIndex = triState.numColor = 0;
|
2009-12-07 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Tri_CheckOverflow( int numIndices, int numVertices )
|
|
|
|
|
{
|
|
|
|
|
if( numIndices > MAX_TRIELEMS )
|
|
|
|
|
Host_Error( "Tri_Overflow: %i > MAX_TRIELEMS\n", numIndices );
|
|
|
|
|
if( numVertices > MAX_TRIVERTS )
|
|
|
|
|
Host_Error( "Tri_Overflow: %i > MAX_TRIVERTS\n", numVertices );
|
|
|
|
|
|
|
|
|
|
if( triState.numIndex + numIndices <= MAX_TRIELEMS && triState.numVertex + numVertices <= MAX_TRIVERTS )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Tri_DrawPolygon();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tri_Fog( float flFogColor[3], float flStart, float flEnd, int bOn )
|
|
|
|
|
{
|
2010-03-18 22:00:00 +01:00
|
|
|
|
// ignore fog calls from TriApi callbacks
|
|
|
|
|
// to avoid strange artefacts and other issues
|
|
|
|
|
if( triState.fActive ) return;
|
|
|
|
|
|
|
|
|
|
// change fog params
|
|
|
|
|
triState.fogColor[0] = bound( 0.0f, flFogColor[0], 1.0f );
|
|
|
|
|
triState.fogColor[1] = bound( 0.0f, flFogColor[1], 1.0f );
|
|
|
|
|
triState.fogColor[2] = bound( 0.0f, flFogColor[2], 1.0f );
|
|
|
|
|
triState.fogColor[3] = 1.0f;
|
|
|
|
|
triState.fogStartDist = min( flStart, flEnd );
|
|
|
|
|
triState.fogEndDist = max( flStart, flEnd );
|
|
|
|
|
triState.fogEnabled = bOn;
|
2009-12-07 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tri_CullFace( int mode )
|
|
|
|
|
{
|
|
|
|
|
if( mode == TRI_FRONT )
|
|
|
|
|
triState.noCulling = false;
|
|
|
|
|
else if( mode == TRI_NONE )
|
|
|
|
|
triState.noCulling = true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-26 22:00:00 +02:00
|
|
|
|
void Tri_RenderMode( const int mode )
|
2009-12-07 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
triState.currentRenderMode = mode;
|
|
|
|
|
}
|
2010-07-13 22:00:00 +02:00
|
|
|
|
|
2009-12-07 22:00:00 +01:00
|
|
|
|
void Tri_Vertex3f( const float x, const float y, const float z )
|
|
|
|
|
{
|
|
|
|
|
uint oldIndex = triState.numIndex;
|
|
|
|
|
|
|
|
|
|
switch( triState.drawMode )
|
|
|
|
|
{
|
|
|
|
|
case TRI_LINES:
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex;
|
|
|
|
|
if( triState.vertexState++ == 1 )
|
|
|
|
|
{
|
|
|
|
|
Tri_Vertex3f( x + 1, y + 1, z + 1 );
|
|
|
|
|
triState.vertexState = 0;
|
|
|
|
|
triState.checkFlush = true; // flush for long sequences of quads.
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case TRI_TRIANGLES:
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex;
|
|
|
|
|
if( triState.vertexState++ == 2 )
|
|
|
|
|
{
|
|
|
|
|
triState.vertexState = 0;
|
|
|
|
|
triState.checkFlush = true; // flush for long sequences of triangles.
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case TRI_QUADS:
|
|
|
|
|
if( triState.vertexState++ < 3 )
|
|
|
|
|
{
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// we've already done triangle (0, 1, 2), now draw (2, 3, 0)
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex - 1;
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex;
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex - 3;
|
|
|
|
|
triState.vertexState = 0;
|
|
|
|
|
triState.checkFlush = true; // flush for long sequences of quads.
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case TRI_TRIANGLE_STRIP:
|
|
|
|
|
if( triState.numVertex + triState.vertexState > MAX_TRIVERTS )
|
|
|
|
|
{
|
|
|
|
|
// This is a strip that's too big for us to buffer.
|
|
|
|
|
// (We can't just flush the buffer because we have to keep
|
|
|
|
|
// track of the last two vertices.
|
2010-05-28 22:00:00 +02:00
|
|
|
|
Host_Error( "Tri_Vertex3f: overflow: %i > MAX_TRIVERTS\n", triState.numVertex + triState.vertexState );
|
|
|
|
|
}
|
|
|
|
|
if( triState.numIndex > MAX_TRIELEMS )
|
|
|
|
|
{
|
|
|
|
|
// This is a strip that's too big for us to buffer.
|
|
|
|
|
// (We can't just flush the buffer because we have to keep
|
|
|
|
|
// track of the last two vertices.
|
|
|
|
|
Host_Error( "Tri_Vertex3f: overflow: %i > MAX_TRIELEMS\n", triState.numIndex );
|
2009-12-07 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
if( triState.vertexState++ < 3 )
|
|
|
|
|
{
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// flip triangles between clockwise and counter clockwise
|
|
|
|
|
if( triState.vertexState & 1 )
|
|
|
|
|
{
|
|
|
|
|
// draw triangle [n-2 n-1 n]
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex - 2;
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex - 1;
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// draw triangle [n-1 n-2 n]
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex - 1;
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex - 2;
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case TRI_POLYGON:
|
|
|
|
|
case TRI_TRIANGLE_FAN: // same as polygon
|
|
|
|
|
if( triState.numVertex + triState.vertexState > MAX_TRIVERTS )
|
|
|
|
|
{
|
|
|
|
|
// This is a polygon or fan that's too big for us to buffer.
|
|
|
|
|
// (We can't just flush the buffer because we have to keep
|
|
|
|
|
// track of the starting vertex.
|
|
|
|
|
Host_Error( "Tri_Vertex3f: overflow: %i > MAX_TRIVERTS\n", triState.numVertex + triState.vertexState );
|
|
|
|
|
}
|
|
|
|
|
if( triState.vertexState++ < 3 )
|
|
|
|
|
{
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// draw triangle [0 n-1 n]
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex - ( triState.vertexState - 1 );
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex - 1;
|
|
|
|
|
tri_elems[triState.numIndex++] = triState.numVertex;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
Host_Error( "Tri_SetVertex: unknown mode: %i\n", triState.drawMode );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// copy current vertex
|
|
|
|
|
tri_vertex[triState.numVertex][0] = x;
|
|
|
|
|
tri_vertex[triState.numVertex][1] = y;
|
|
|
|
|
tri_vertex[triState.numVertex][2] = z;
|
2010-03-15 22:00:00 +01:00
|
|
|
|
tri_vertex[triState.numVertex][3] = 1;
|
2009-12-07 22:00:00 +01:00
|
|
|
|
|
2010-03-22 22:00:00 +01:00
|
|
|
|
// for compute lighting origin
|
|
|
|
|
AddPointToBounds( tri_vertex[triState.numVertex], triState.mins, triState.maxs );
|
|
|
|
|
|
2009-12-07 22:00:00 +01:00
|
|
|
|
triState.numVertex++;
|
|
|
|
|
|
|
|
|
|
// flush buffer if needed
|
|
|
|
|
if( triState.checkFlush )
|
|
|
|
|
Tri_CheckOverflow( triState.numIndex - oldIndex, triState.vertexState );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tri_Color4ub( const byte r, const byte g, const byte b, const byte a )
|
|
|
|
|
{
|
2010-03-16 22:00:00 +01:00
|
|
|
|
tri_colors[triState.numVertex][0] = r;
|
|
|
|
|
tri_colors[triState.numVertex][1] = g;
|
|
|
|
|
tri_colors[triState.numVertex][2] = b;
|
|
|
|
|
tri_colors[triState.numVertex][3] = a;
|
2009-12-07 22:00:00 +01:00
|
|
|
|
triState.numColor++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tri_Normal3f( const float x, const float y, const float z )
|
|
|
|
|
{
|
|
|
|
|
triState.hasNormals = true; // curstate has normals
|
|
|
|
|
tri_normal[triState.numVertex][0] = x;
|
|
|
|
|
tri_normal[triState.numVertex][1] = y;
|
|
|
|
|
tri_normal[triState.numVertex][2] = z;
|
2010-03-15 22:00:00 +01:00
|
|
|
|
tri_normal[triState.numVertex][3] = 1;
|
2009-12-07 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tri_TexCoord2f( const float u, const float v )
|
|
|
|
|
{
|
|
|
|
|
tri_coords[triState.numVertex][0] = u;
|
|
|
|
|
tri_coords[triState.numVertex][1] = v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tri_Bind( shader_t handle, int frame )
|
|
|
|
|
{
|
|
|
|
|
ref_shader_t *shader;
|
|
|
|
|
|
|
|
|
|
if( handle < 0 || handle > MAX_SHADERS || !(shader = &r_shaders[handle]))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "TriBind: bad shader %i\n", handle );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !shader->num_stages || !shader->stages[0].textures[0] )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "TriBind: bad shader %i\n", handle );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
triState.currentShader = handle;
|
|
|
|
|
|
|
|
|
|
// FIXME: scan stages while( frame < stage->num_textures ) ?
|
|
|
|
|
if( shader->stages[0].textures[0] && shader->stages[0].num_textures && frame > 0 )
|
|
|
|
|
glState.draw_frame = bound( 0, frame, shader->stages[0].num_textures );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tri_Enable( int cap )
|
|
|
|
|
{
|
|
|
|
|
if( cap < 0 || cap > TRI_MAXCAPS ) return;
|
|
|
|
|
tri_caps[cap] = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tri_Disable( int cap )
|
|
|
|
|
{
|
|
|
|
|
if( cap < 0 || cap > TRI_MAXCAPS ) return;
|
|
|
|
|
tri_caps[cap] = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tri_Begin( int mode )
|
|
|
|
|
{
|
|
|
|
|
triState.drawMode = mode;
|
|
|
|
|
triState.vertexState = 0;
|
|
|
|
|
triState.checkFlush = false;
|
|
|
|
|
triState.hasNormals = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tri_End( void )
|
|
|
|
|
{
|
|
|
|
|
if( triState.numIndex )
|
|
|
|
|
Tri_DrawPolygon();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tri_RenderCallback( int fTrans )
|
|
|
|
|
{
|
2009-12-11 22:00:00 +01:00
|
|
|
|
if( RI.refdef.flags & RDF_NOWORLDMODEL )
|
|
|
|
|
return;
|
|
|
|
|
|
2009-12-07 22:00:00 +01:00
|
|
|
|
triState.fActive = true;
|
|
|
|
|
|
|
|
|
|
if( fTrans ) GL_SetState( GLSTATE_NO_DEPTH_TEST );
|
2010-03-22 22:00:00 +01:00
|
|
|
|
R_LoadIdentity ();
|
|
|
|
|
Tri_ClearBounds ();
|
2009-12-07 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
pglColor4f( 1, 1, 1, 1 );
|
|
|
|
|
|
|
|
|
|
RI.currententity = RI.previousentity = NULL;
|
|
|
|
|
RI.currentmodel = NULL;
|
|
|
|
|
|
|
|
|
|
tri_mbuffer.infokey = -1;
|
|
|
|
|
tri_mbuffer.shaderkey = 0;
|
2010-03-15 22:00:00 +01:00
|
|
|
|
triState.numColor = 0;
|
2009-12-07 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
ri.DrawTriangles( fTrans );
|
|
|
|
|
|
|
|
|
|
// fulsh remaining tris
|
|
|
|
|
if( tri_mbuffer.infokey != -1 )
|
|
|
|
|
{
|
|
|
|
|
R_RenderMeshBuffer( &tri_mbuffer );
|
|
|
|
|
tri_mbuffer.infokey = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
triState.fActive = false;
|
|
|
|
|
}
|
2010-08-20 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
===============
|
|
|
|
|
R_Set2DMode
|
|
|
|
|
===============
|
|
|
|
|
*/
|
2010-10-26 22:00:00 +02:00
|
|
|
|
void R_Set2DMode( qboolean enable )
|
2010-08-20 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
if( enable )
|
|
|
|
|
{
|
|
|
|
|
if( glState.in2DMode )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// set 2D virtual screen size
|
|
|
|
|
pglScissor( 0, 0, glState.width, glState.height );
|
|
|
|
|
pglViewport( 0, 0, glState.width, glState.height );
|
|
|
|
|
pglMatrixMode( GL_PROJECTION );
|
|
|
|
|
pglLoadIdentity();
|
|
|
|
|
pglOrtho( 0, glState.width, glState.height, 0, -99999, 99999 );
|
|
|
|
|
pglMatrixMode( GL_MODELVIEW );
|
|
|
|
|
pglLoadIdentity();
|
|
|
|
|
|
|
|
|
|
GL_Cull( 0 );
|
|
|
|
|
GL_SetState( GLSTATE_NO_DEPTH_TEST );
|
|
|
|
|
|
|
|
|
|
pglColor4f( 1, 1, 1, 1 );
|
|
|
|
|
|
|
|
|
|
glState.in2DMode = true;
|
|
|
|
|
RI.currententity = RI.previousentity = NULL;
|
|
|
|
|
RI.currentmodel = NULL;
|
|
|
|
|
|
|
|
|
|
pic_mbuffer.infokey = -1;
|
|
|
|
|
pic_mbuffer.shaderkey = 0;
|
|
|
|
|
|
|
|
|
|
// reset TriApi state too in case we want use it in 2d mode
|
|
|
|
|
Tri_ClearBounds ();
|
|
|
|
|
|
|
|
|
|
tri_mbuffer.infokey = -1;
|
|
|
|
|
tri_mbuffer.shaderkey = 0;
|
|
|
|
|
triState.numColor = 0;
|
|
|
|
|
triState.fActive = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if( pic_mbuffer.infokey != -1 )
|
|
|
|
|
{
|
|
|
|
|
R_RenderMeshBuffer( &pic_mbuffer );
|
|
|
|
|
pic_mbuffer.infokey = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fulsh remaining tris
|
|
|
|
|
if( tri_mbuffer.infokey != -1 )
|
|
|
|
|
{
|
|
|
|
|
R_RenderMeshBuffer( &tri_mbuffer );
|
|
|
|
|
tri_mbuffer.infokey = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
triState.fActive = false;
|
|
|
|
|
glState.in2DMode = false;
|
|
|
|
|
}
|
|
|
|
|
}
|