Readded ioq3 renderer

This commit is contained in:
L 2023-05-08 19:53:53 +02:00
parent 410fa7ac15
commit e2910930da
90 changed files with 29872 additions and 12427 deletions

View file

@ -335,10 +335,4 @@ extern int qglesMajorVersion, qglesMinorVersion;
#define QGL_VERSION_ATLEAST( major, minor ) ( qglMajorVersion > major || ( qglMajorVersion == major && qglMinorVersion >= minor ) ) #define QGL_VERSION_ATLEAST( major, minor ) ( qglMajorVersion > major || ( qglMajorVersion == major && qglMinorVersion >= minor ) )
#define QGLES_VERSION_ATLEAST( major, minor ) ( qglesMajorVersion > major || ( qglesMajorVersion == major && qglesMinorVersion >= minor ) ) #define QGLES_VERSION_ATLEAST( major, minor ) ( qglesMajorVersion > major || ( qglesMajorVersion == major && qglesMinorVersion >= minor ) )
#define qglCopyTexImage2D glCopyTexImage2D
#define qglColor4fv glColor4fv
#define qglLineStipple glLineStipple
#define qglVertex2i glVertex2i
#define qglReadBuffer glReadBuffer
#endif #endif

View file

@ -23,14 +23,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define TR_COMMON_H #define TR_COMMON_H
#include "../qcommon/q_shared.h" #include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#include "../renderercommon/tr_public.h" #include "../renderercommon/tr_public.h"
#include "qgl.h" #include "qgl.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum typedef enum
{ {
IMGTYPE_COLORALPHA, // for color, lightmap, diffuse, and specular IMGTYPE_COLORALPHA, // for color, lightmap, diffuse, and specular
@ -48,8 +43,7 @@ typedef enum
IMGFLAG_NO_COMPRESSION = 0x0010, IMGFLAG_NO_COMPRESSION = 0x0010,
IMGFLAG_NOLIGHTSCALE = 0x0020, IMGFLAG_NOLIGHTSCALE = 0x0020,
IMGFLAG_CLAMPTOEDGE = 0x0040, IMGFLAG_CLAMPTOEDGE = 0x0040,
IMGFLAG_SRGB = 0x0080, IMGFLAG_GENNORMALMAP = 0x0080,
IMGFLAG_GENNORMALMAP = 0x0100,
} imgFlags_t; } imgFlags_t;
typedef struct image_s { typedef struct image_s {
@ -123,12 +117,11 @@ extern cvar_t *r_saveFontData;
qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ); qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode );
float R_NoiseGet4f( float x, float y, float z, float t ); float R_NoiseGet4f( float x, float y, float z, double t );
void R_NoiseInit( void ); void R_NoiseInit( void );
image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ); image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags );
image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgType_t type, imgFlags_t flags, int internalFormat ); image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgType_t type, imgFlags_t flags, int internalFormat );
qboolean R_ImageExists( const char *name );
void R_IssuePendingRenderCommands( void ); void R_IssuePendingRenderCommands( void );
qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ); qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex );
@ -140,16 +133,6 @@ qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_
void R_InitFreeType( void ); void R_InitFreeType( void );
void R_DoneFreeType( void ); void R_DoneFreeType( void );
void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font); void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);
fontheader_t *R_LoadFont( const char *name );
void R_LoadFontShader( fontheader_t *font );
void R_DrawString( fontheader_t *font, const char *text, float x, float y, int maxlen, qboolean bVirtualScreen );
void R_DrawFloatingString( fontheader_t *font, const char *text, const vec3_t org, float *color, float scale, int maxlen );
float R_GetFontHeight( fontheader_t *font );
float R_GetFontStringWidth( fontheader_t *font, const char *s );
int RE_Text_Width( fontInfo_t *font, const char *text, int limit, qboolean useColourCodes );
int RE_Text_Height( fontInfo_t *font, const char *text, int limit, qboolean useColourCodes );
void RE_Text_PaintChar( fontInfo_t *font, float x, float y, float scale, int c, qboolean is640 );
void RE_Text_Paint( fontInfo_t *font, float x, float y, float scale, float alpha, const char *text, float adjust, int limit, qboolean useColourCodes, qboolean is640 );
/* /*
============================================================= =============================================================
@ -173,19 +156,16 @@ IMPLEMENTATION SPECIFIC FUNCTIONS
==================================================================== ====================================================================
*/ */
void GLimp_Init( void ); void GLimp_Init( qboolean fixedFunction );
void GLimp_Shutdown( void ); void GLimp_Shutdown( void );
void GLimp_EndFrame( void ); void GLimp_EndFrame( void );
void GLimp_LogComment( const char *comment ); void GLimp_LogComment( char *comment );
void GLimp_Minimize(void); void GLimp_Minimize(void);
void GLimp_SetGamma( unsigned char red[256], void GLimp_SetGamma( unsigned char red[256],
unsigned char green[256], unsigned char green[256],
unsigned char blue[256] ); unsigned char blue[256] );
#ifdef __cplusplus
}
#endif
#endif #endif

View file

@ -70,7 +70,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_common.h" #include "tr_common.h"
#include "../qcommon/qcommon.h" #include "../qcommon/qcommon.h"
#include "../renderergl2/tr_local.h"
#ifdef BUILD_FREETYPE #ifdef BUILD_FREETYPE
#include <ft2build.h> #include <ft2build.h>
@ -87,12 +86,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
FT_Library ftLibrary = NULL; FT_Library ftLibrary = NULL;
#endif #endif
#define MAX_FONTS 255 #define MAX_FONTS 6
static int registeredFontCount = 0; static int registeredFontCount = 0;
static fontInfo_t registeredFont[MAX_FONTS]; static fontInfo_t registeredFont[MAX_FONTS];
static fontheader_t s_loadedFonts[MAX_FONTS];
#ifdef BUILD_FREETYPE #ifdef BUILD_FREETYPE
void R_GetGlyphInfo(FT_GlyphSlot glyph, int *left, int *right, int *width, int *top, int *bottom, int *height, int *pitch) { void R_GetGlyphInfo(FT_GlyphSlot glyph, int *left, int *right, int *width, int *top, int *bottom, int *height, int *pitch) {
*left = _FLOOR( glyph->metrics.horiBearingX ); *left = _FLOOR( glyph->metrics.horiBearingX );
@ -306,7 +303,7 @@ static int fdOffset;
static byte *fdFile; static byte *fdFile;
int readInt( void ) { int readInt( void ) {
int i = fdFile[fdOffset]+(fdFile[fdOffset+1]<<8)+(fdFile[fdOffset+2]<<16)+(fdFile[fdOffset+3]<<24); int i = ((unsigned int)fdFile[fdOffset] | ((unsigned int)fdFile[fdOffset+1]<<8) | ((unsigned int)fdFile[fdOffset+2]<<16) | ((unsigned int)fdFile[fdOffset+3]<<24));
fdOffset += 4; fdOffset += 4;
return i; return i;
} }
@ -366,109 +363,6 @@ void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) {
return; return;
} }
// IneQuation: try a RitualFont first
Com_sprintf( name, sizeof( name ), "fonts/%s.RitualFont", fontName );
for( i = 0; i < registeredFontCount; i++ ) {
if( !Q_stricmp( name, registeredFont[ i ].name ) ) {
Com_Memcpy( font, &registeredFont[ i ], sizeof( fontInfo_t ) );
return;
}
}
len = ri.FS_ReadFile( name, &faceData );
if( len > 0 ) {
char *p = ( char * )faceData;
const char *token;
Q_strncpyz( font->name, name, sizeof( font->name ) );
token = COM_Parse( &p );
if( !strcmp( token, "RitFont" ) ) {
int j;
float height, aspect; // aspect is the aspect ratio of the tga file
char indirections[ 256 ];
shader_t *fontShader;
vec4_t locations;
Com_sprintf( name, sizeof( name ), "gfx/fonts/%s", fontName );
fontShader = R_FindShader( name, LIGHTMAP_2D, qfalse );
Com_Memset( font->glyphs, 0, sizeof( font->glyphs ) );
font->glyphScale = 1.f;
token = COM_Parse( &p );
while( token && token[ 0 ] ) {
if( !Q_stricmp( token, "height" ) ) {
token = COM_Parse( &p );
height = atof( token );
}
else if( !Q_stricmp( token, "aspect" ) ) {
token = COM_Parse( &p );
aspect = atof( token );
}
else if( !Q_stricmp( token, "indirections" ) ) {
// skip the opening brace
COM_Parse( &p );
for( i = 0; i < 256; i++ ) {
token = COM_Parse( &p );
indirections[ i ] = atoi( token );
}
// skip the trailing brace
COM_Parse( &p );
}
else if( !Q_stricmp( token, "locations" ) ) {
// skip the opening brace
COM_Parse( &p );
for( i = 0; i < 256; i++ ) {
for( j = 0; j < 256; j++ ) {
if( indirections[ j ] == i )
break;
}
// we'll need the value of j in a while, and parsing all the locations is required anyway in order to exit cleanly
// skip the opening brace
COM_Parse( &p );
token = COM_Parse( &p );
locations[ 0 ] = atoi( token );
token = COM_Parse( &p );
locations[ 1 ] = atoi( token );
token = COM_Parse( &p );
locations[ 2 ] = atoi( token );
token = COM_Parse( &p );
locations[ 3 ] = atoi( token );
// skip the trailing brace
COM_Parse( &p );
if( j == 256 )
continue; // character not supported by font, skip it
//font->glyphs[i].top = locations[1];
//font->glyphs[i].bottom = font->glyphs[i].top + locations[3];
font->glyphs[ j ].s = ( float )locations[ 0 ] / fontShader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->width;
font->glyphs[ j ].t = ( float )locations[ 1 ] / fontShader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->height;
font->glyphs[ j ].s2 = ( float )( locations[ 0 ] + locations[ 2 ] ) / fontShader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->width;
font->glyphs[ j ].t2 = ( float )( locations[ 1 ] + locations[ 3 ] ) / fontShader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->height;
font->glyphs[ j ].imageWidth = font->glyphs[ j ].xSkip = font->glyphs[ j ].pitch = locations[ 2 ];
font->glyphs[ j ].imageHeight = font->glyphs[ j ].height = locations[ 3 ];
font->glyphs[ j ].glyph = fontShader->index;
Q_strncpyz( font->glyphs[ j ].shaderName, name, sizeof( font->glyphs[ 0 ].shaderName ) );
}
// skip the trailing brace
COM_Parse( &p );
}
else {
ri.Printf( PRINT_WARNING, "RE_RegisterFont: unknown token %s.\n", token );
return;
}
token = COM_Parse( &p );
}
if( registeredFontCount < MAX_FONTS - 1 )
Com_Memcpy( &registeredFont[ registeredFontCount++ ], font, sizeof( fontInfo_t ) );
else
ri.Printf( PRINT_WARNING, "RE_RegisterFont: MAX_FONTS (%d) exceeded.\n", MAX_FONTS );
return; // successfully loaded a RitualFont
}
else
ri.Printf( PRINT_WARNING, "RE_RegisterFont: %s is not a valid RitualFont (invalid ident %s).\n", name, token );
}
// if this fails, try loading the FreeType-rendered fonts
Com_sprintf(name, sizeof(name), "fonts/fontImage_%i.dat",pointSize); Com_sprintf(name, sizeof(name), "fonts/fontImage_%i.dat",pointSize);
for (i = 0; i < registeredFontCount; i++) { for (i = 0; i < registeredFontCount; i++) {
if (Q_stricmp(name, registeredFont[i].name) == 0) { if (Q_stricmp(name, registeredFont[i].name) == 0) {
@ -665,688 +559,3 @@ void R_DoneFreeType(void) {
registeredFontCount = 0; registeredFontCount = 0;
} }
static int s_numLoadedFonts = 0;
static float s_fontHeightScale = 1.0;
static float s_fontGeneralScale = 1.0;
static float s_fontZ = 0.0;
void R_SetFontHeightScale( float scale ) {
s_fontHeightScale = scale;
}
void R_SetFontScale( float scale ) {
s_fontGeneralScale = scale;
}
void R_SetFontZ( float zed ) {
s_fontZ = zed;
}
fontheader_t *R_LoadFont( const char *name ) {
int i;
const char *theFile;
fontheader_t *header;
char *ref;
const char *token;
qboolean error = qfalse;
char *p;
for( i = 0; i < s_numLoadedFonts; i++ )
{
if( !Q_stricmp( name, s_loadedFonts[ i ].name ) ) {
return &s_loadedFonts[ i ];
}
}
if( s_numLoadedFonts >= MAX_FONTS ) {
ri.Printf( PRINT_WARNING, "LoadFont: Too many fonts loaded! Couldn't load %s\n", name );
return NULL;
}
theFile = va( "fonts/%s.RitualFont", name );
if( ri.FS_ReadFile( theFile, ( void ** )&ref ) == -1 )
{
ri.Printf( PRINT_WARNING, "LoadFont: Couldn't load font %s\n", name );
return NULL;
}
header = &s_loadedFonts[ s_numLoadedFonts ];
header->height = 0.0;
header->aspectRatio = 0.0;
strcpy( header->name, name );
p = ref;
token = COM_Parse( &p );
if( !strcmp( token, "RitFont" ) ) {
token = COM_Parse( &p );
while( token && token[ 0 ] ) {
if( !Q_stricmp( token, "height" ) ) {
token = COM_Parse( &p );
header->height = atof( token );
}
else if( !Q_stricmp( token, "aspect" ) ) {
token = COM_Parse( &p );
header->aspectRatio = atof( token );
}
else if( !Q_stricmp( token, "indirections" ) ) {
// check the opening brace
token = COM_Parse( &p );
if( Q_stricmp( token, "{" ) )
{
error = qtrue;
break;
}
for( i = 0; i < 256; i++ ) {
token = COM_Parse( &p );
if( !*token ) {
error = qtrue;
break;
}
header->indirection[ i ] = atoi( token );
}
if( error ) {
break;
}
// check the trailing brace
token = COM_Parse( &p );
if( Q_stricmp( token, "}" ) )
{
error = qtrue;
break;
}
}
else if( !Q_stricmp( token, "locations" ) ) {
// check the opening brace
token = COM_Parse( &p );
if( Q_stricmp( token, "{" ) )
{
error = qtrue;
break;
}
for( i = 0; i < 256; i++ ) {
/*for( j = 0; j < 256; j++ ) {
if( indirections[ j ] == i )
break;
}*/
// we'll need the value of j in a while, and parsing all the locations is required anyway in order to exit cleanly
// check the opening brace
token = COM_Parse( &p );
if( Q_stricmp( token, "{" ) )
{
error = qtrue;
break;
}
token = COM_Parse( &p );
header->locations[ i ].pos[ 0 ] = ( float )atoi( token ) * 0.00390625;
token = COM_Parse( &p );
header->locations[ i ].pos[ 1 ] = ( float )atoi( token ) * header->aspectRatio * 0.00390625;
token = COM_Parse( &p );
header->locations[ i ].pos[ 2 ] = ( float )atoi( token ) * 0.00390625;
token = COM_Parse( &p );
header->locations[ i ].pos[ 3 ] = ( float )atoi( token ) * header->aspectRatio * 0.00390625;
// check the trailing brace
token = COM_Parse( &p );
if( Q_stricmp( token, "}" ) )
{
error = qtrue;
break;
}
}
if( error ) {
break;
}
// check the trailing brace
token = COM_Parse( &p );
if( Q_stricmp( token, "}" ) )
{
error = qtrue;
break;
}
} else {
ri.Printf( PRINT_WARNING, "WARNING: Unknown token '%s' parsing font '%s'.\n", token, name );
error = qtrue;
break;
}
token = COM_Parse( &p );
}
} else {
ri.Printf( PRINT_WARNING, "WARNING: %s is not a valid RitualFont (invalid ident '%s').\n", name, token );
}
R_LoadFontShader( header );
if( header->height == 0.0 || header->aspectRatio == 0.0 ) {
error = qtrue;
}
ri.FS_FreeFile( ref );
if( error )
{
ri.Printf( PRINT_WARNING, "WARNING: Error parsing font %s.\n", name );
return NULL;
}
s_numLoadedFonts++;
return header;
}
void R_LoadFontShader( fontheader_t *font ) {
int i;
int save;
shader_t *fontshader;
char filename[ 64 ];
save = r_sequencenumber;
r_sequencenumber = -1;
Com_sprintf( filename, sizeof( filename ), "gfx/fonts/%s", font->name );
fontshader = R_FindShader( filename, -1, qfalse );
font->shader = fontshader;
r_sequencenumber = save;
if( !fontshader ) {
ri.Error( ERR_DROP, "Could not load font shader for %s\n", filename );
}
// set the font to use the global color/alpha
for( i = 0; i < fontshader->numUnfoggedPasses; i++ )
{
if( fontshader->stages[ i ] && fontshader->stages[ i ]->active )
{
fontshader->stages[ i ]->rgbGen = CGEN_GLOBAL_COLOR;
fontshader->stages[ i ]->alphaGen = AGEN_GLOBAL_ALPHA;
}
}
font->trhandle = r_sequencenumber;
}
void R_DrawString( fontheader_t *font, const char *text, float x, float y, int maxlen, qboolean bVirtualScreen ) {
shader_t *fontshader;
float charHeight;
float startx, starty;
int i;
float fWidthScale, fHeightScale;
if( !font ) {
return;
}
startx = x;
starty = y;
fWidthScale = glConfig.vidWidth / 640.0;
fHeightScale = glConfig.vidHeight / 480.0;
R_IssuePendingRenderCommands();
if( font->trhandle != r_sequencenumber ) {
font->shader = NULL;
}
fontshader = font->shader;
if( !fontshader ) {
R_LoadFontShader( font );
}
charHeight = s_fontGeneralScale * s_fontHeightScale * font->height;
RB_Prepare2D();
RB_BeginSurface( fontshader, 0, 0 );
for( i = 0; text[ i ] && ( maxlen == -1 || i < maxlen ); i++ )
{
unsigned char c = text[ i ];
int indirected;
letterloc_t *loc;
if( c == '\n' )
{
starty += charHeight;
}
else if( c == '\r' )
{
x = startx;
}
else if( c == '\t' )
{
indirected = font->indirection[ ' ' ];
if( indirected == -1 )
{
Com_DPrintf( "R_DrawString: no space-character in font!\n" );
continue;
}
x += font->locations[ indirected ].size[ 0 ] * 256.0 * s_fontGeneralScale * 3.0;
}
else
{
indirected = font->indirection[ c ];
if( indirected == -1 )
{
Com_DPrintf( "R_DrawString: no 0x%02x-character in font!\n", c );
indirected = font->indirection[ '?' ];
if( indirected == -1 )
{
Com_DPrintf( "R_DrawString: no '?' character in font!\n" );
continue;
}
font->indirection[ c ] = indirected;
}
// draw the character
if( tess.numVertexes + 4 >= 1000 || tess.numIndexes + 6 >= 6000 ) {
RB_CheckOverflow( 4, 6 );
}
loc = &font->locations[ indirected ];
tess.texCoords[ tess.numVertexes + 0 ][ 0 ][ 0 ] = loc->pos[ 0 ];
tess.texCoords[ tess.numVertexes + 0 ][ 0 ][ 1 ] = loc->pos[ 1 ];
tess.texCoords[ tess.numVertexes + 1 ][ 0 ][ 0 ] = loc->pos[ 0 ] + loc->size[ 0 ];
tess.texCoords[ tess.numVertexes + 1 ][ 0 ][ 1 ] = loc->pos[ 1 ];
tess.texCoords[ tess.numVertexes + 2 ][ 0 ][ 0 ] = loc->pos[ 0 ];
tess.texCoords[ tess.numVertexes + 2 ][ 0 ][ 1 ] = loc->pos[ 1 ] + loc->size[ 1 ];
tess.texCoords[ tess.numVertexes + 3 ][ 0 ][ 0 ] = loc->pos[ 0 ] + loc->size[ 0 ];
tess.texCoords[ tess.numVertexes + 3 ][ 0 ][ 1 ] = loc->pos[ 1 ] + loc->size[ 1 ];
tess.xyz[ tess.numVertexes + 0 ][ 0 ] = x;
tess.xyz[ tess.numVertexes + 0 ][ 1 ] = y;
tess.xyz[ tess.numVertexes + 0 ][ 2 ] = s_fontZ;
tess.xyz[ tess.numVertexes + 1 ][ 0 ] = x + loc->size[ 0 ] * 256.0 * s_fontGeneralScale;
tess.xyz[ tess.numVertexes + 1 ][ 1 ] = y;
tess.xyz[ tess.numVertexes + 1 ][ 2 ] = s_fontZ;
tess.xyz[ tess.numVertexes + 2 ][ 0 ] = x;
tess.xyz[ tess.numVertexes + 2 ][ 1 ] = y + charHeight;
tess.xyz[ tess.numVertexes + 2 ][ 2 ] = s_fontZ;
tess.xyz[ tess.numVertexes + 3 ][ 0 ] = x + loc->size[ 0 ] * 256.0 * s_fontGeneralScale;
tess.xyz[ tess.numVertexes + 3 ][ 1 ] = y + charHeight;
tess.xyz[ tess.numVertexes + 3 ][ 2 ] = s_fontZ;
tess.indexes[ tess.numIndexes + 0 ] = tess.numVertexes + 0;
tess.indexes[ tess.numIndexes + 1 ] = tess.numVertexes + 1;
tess.indexes[ tess.numIndexes + 2 ] = tess.numVertexes + 2;
tess.indexes[ tess.numIndexes + 3 ] = tess.numVertexes + 1;
tess.indexes[ tess.numIndexes + 4 ] = tess.numVertexes + 3;
tess.indexes[ tess.numIndexes + 5 ] = tess.numVertexes + 2;
if( bVirtualScreen )
{
tess.xyz[ tess.numVertexes + 0 ][ 0 ] *= fWidthScale;
tess.xyz[ tess.numVertexes + 0 ][ 1 ] *= fHeightScale;
tess.xyz[ tess.numVertexes + 1 ][ 0 ] *= fWidthScale;
tess.xyz[ tess.numVertexes + 1 ][ 1 ] *= fHeightScale;
tess.xyz[ tess.numVertexes + 2 ][ 0 ] *= fWidthScale;
tess.xyz[ tess.numVertexes + 2 ][ 1 ] *= fHeightScale;
tess.xyz[ tess.numVertexes + 3 ][ 0 ] *= fWidthScale;
tess.xyz[ tess.numVertexes + 3 ][ 1 ] *= fHeightScale;
}
tess.numVertexes += 4;
tess.numIndexes += 6;
x += loc->size[ 0 ] * 256.0 * s_fontGeneralScale;
}
}
RB_EndSurface();
}
void R_DrawFloatingString( fontheader_t *font, const char *text, const vec3_t org, float *color, float scale, int maxlen ) {
shader_t *fontshader;
qhandle_t fsh;
float charWidth;
float charHeight;
int i;
vec3_t pos;
polyVert_t verts[ 4 ];
if( !font ) {
return;
}
R_IssuePendingRenderCommands();
if( font->trhandle != r_sequencenumber ) {
font->shader = NULL;
}
if( !font->shader ) {
R_LoadFontShader( font );
}
fontshader = font->shader;
fsh = 0;
for( i = 0; i < tr.numShaders; i++ )
{
if( fontshader == tr.shaders[ i ] ) {
fsh = i;
}
}
charHeight = font->height * s_fontHeightScale * s_fontGeneralScale * scale;
VectorCopy( org, pos );
for( i = 0; text[ i ] && ( maxlen == -1 || i < maxlen ); i++ )
{
unsigned char c = text[ i ];
int indirected;
letterloc_t *loc;
indirected = font->indirection[ c ];
if( indirected == -1 )
{
Com_Printf( "R_DrawFloatingString: no 0x%02x-character in font!\n", c );
continue;
}
loc = &font->locations[ indirected ];
charWidth = loc->size[ 0 ] * 256.0 * s_fontGeneralScale * scale;
verts[ 0 ].modulate[ 0 ] = color[ 0 ] * 255.0;
verts[ 0 ].modulate[ 1 ] = color[ 1 ] * 255.0;
verts[ 0 ].modulate[ 2 ] = color[ 2 ] * 255.0;
verts[ 1 ].modulate[ 0 ] = verts[ 0 ].modulate[ 0 ];
verts[ 1 ].modulate[ 1 ] = verts[ 0 ].modulate[ 1 ];
verts[ 1 ].modulate[ 2 ] = verts[ 0 ].modulate[ 2 ];
verts[ 2 ].modulate[ 0 ] = verts[ 0 ].modulate[ 0 ];
verts[ 2 ].modulate[ 1 ] = verts[ 0 ].modulate[ 1 ];
verts[ 2 ].modulate[ 2 ] = verts[ 0 ].modulate[ 2 ];
verts[ 3 ].modulate[ 0 ] = verts[ 0 ].modulate[ 0 ];
verts[ 3 ].modulate[ 1 ] = verts[ 0 ].modulate[ 1 ];
verts[ 3 ].modulate[ 2 ] = verts[ 0 ].modulate[ 2 ];
verts[ 0 ].st[ 0 ] = loc->pos[ 0 ];
verts[ 0 ].st[ 1 ] = loc->pos[ 1 ];
verts[ 1 ].st[ 0 ] = loc->pos[ 0 ] + loc->size[ 0 ];
verts[ 1 ].st[ 1 ] = loc->pos[ 1 ];
verts[ 2 ].st[ 0 ] = loc->pos[ 0 ] + loc->size[ 0 ];
verts[ 2 ].st[ 1 ] = loc->pos[ 1 ] + loc->size[ 1 ];
verts[ 3 ].st[ 0 ] = loc->pos[ 0 ];
verts[ 3 ].st[ 1 ] = loc->pos[ 1 ] + loc->size[ 1 ];
verts[ 0 ].xyz[ 0 ] = pos[ 0 ] + tr.refdef.viewaxis[ 1 ][ 0 ] * -charWidth + tr.refdef.viewaxis[ 1 ][ 0 ] * charWidth + tr.refdef.viewaxis[ 2 ][ 0 ] * charHeight;
verts[ 0 ].xyz[ 1 ] = pos[ 1 ] + tr.refdef.viewaxis[ 1 ][ 1 ] * -charWidth + tr.refdef.viewaxis[ 1 ][ 1 ] * charWidth + tr.refdef.viewaxis[ 2 ][ 1 ] * charHeight;
verts[ 0 ].xyz[ 2 ] = pos[ 2 ] + tr.refdef.viewaxis[ 1 ][ 2 ] * -charWidth + tr.refdef.viewaxis[ 1 ][ 2 ] * charWidth + tr.refdef.viewaxis[ 2 ][ 2 ] * charHeight;
verts[ 1 ].xyz[ 0 ] = pos[ 0 ] + tr.refdef.viewaxis[ 1 ][ 0 ] * -charWidth + tr.refdef.viewaxis[ 2 ][ 0 ] * charHeight;
verts[ 1 ].xyz[ 1 ] = pos[ 1 ] + tr.refdef.viewaxis[ 1 ][ 1 ] * -charWidth + tr.refdef.viewaxis[ 2 ][ 1 ] * charHeight;
verts[ 1 ].xyz[ 2 ] = pos[ 2 ] + tr.refdef.viewaxis[ 1 ][ 2 ] * -charWidth + tr.refdef.viewaxis[ 2 ][ 2 ] * charHeight;
verts[ 2 ].xyz[ 0 ] = pos[ 0 ] + tr.refdef.viewaxis[ 1 ][ 0 ] * -charWidth;
verts[ 2 ].xyz[ 1 ] = pos[ 1 ] + tr.refdef.viewaxis[ 1 ][ 1 ] * -charWidth;
verts[ 2 ].xyz[ 2 ] = pos[ 2 ] + tr.refdef.viewaxis[ 1 ][ 2 ] * -charWidth;
verts[ 3 ].xyz[ 0 ] = pos[ 0 ];
verts[ 3 ].xyz[ 1 ] = pos[ 1 ];
verts[ 3 ].xyz[ 2 ] = pos[ 2 ];
if( RE_AddPolyToScene( fsh, 4, verts, 0 ) ) {
tr.refdef.numPolys++;
}
VectorCopy( verts[ 2 ].xyz, pos );
}
}
float R_GetFontHeight( fontheader_t *font ) {
if( font ) {
return s_fontGeneralScale * s_fontHeightScale * font->height;
} else {
return 0.0;
}
}
float R_GetFontStringWidth( fontheader_t *font, const char *s ) {
float widths = 0.0;
int i;
if( !font ) {
return 0.0;
}
for( i = 0; s[ i ]; i++ )
{
unsigned char c = s[ i ];
int indirected;
if( c == '\t' )
{
indirected = font->indirection[ ' ' ];
if( indirected == -1 ) {
Com_Printf( "R_GetFontStringWidth: no space-character in font!\n" );
} else {
widths += font->locations[ indirected ].size[ 0 ] * 3.0;
}
}
else
{
indirected = font->indirection[ c ];
if( indirected == -1 ) {
Com_Printf( "R_GetFontStringWidth: no 0x%02x-character in font!\n", c );
} else {
widths += font->locations[ indirected ].size[ 0 ];
}
}
}
widths *= s_fontGeneralScale * 256.0;
return widths;
}
// IneQuation: exports to deal with universal text drawing; adapted from cgame
/*
===================
RE_Text_Width
===================
Returns text width in pixels.
*/
int RE_Text_Width( fontInfo_t *font, const char *text, int limit, qboolean useColourCodes ) {
int count, len;
float out;
glyphInfo_t *glyph;
// FIXME: see ui_main.c, same problem
// const unsigned char *s = text;
const char *s = text;
if( !font ) {
font = &registeredFont[ 0 ];
if( !font ) {
ri.Printf( PRINT_WARNING, "RE_Text_Width: no fonts registered!\n" );
return strlen( text ) * 16; // return something
}
}
out = 0;
if( text ) {
len = strlen( text );
if( limit > 0 && len > limit )
len = limit;
count = 0;
while( s && *s && count < len ) {
if( useColourCodes && Q_IsColorString( s ) ) {
s += 2;
continue;
}
else {
glyph = &font->glyphs[ ( int )*s ];
out += glyph->xSkip;
s++;
count++;
}
}
}
return out * font->glyphScale;
}
/*
===================
RE_Text_Height
===================
Returns text height in pixels.
*/
int RE_Text_Height( fontInfo_t *font, const char *text, int limit, qboolean useColourCodes ) {
int len, count;
float max;
glyphInfo_t *glyph;
// TTimo: FIXME
// const unsigned char *s = text;
const char *s = text;
if( !font ) {
font = &registeredFont[ 0 ];
if( !font ) {
ri.Printf( PRINT_WARNING, "RE_Text_Height: no fonts registered!\n" );
return 16; // return something
}
}
max = 0;
if( text ) {
len = strlen( text );
if( limit > 0 && len > limit )
len = limit;
count = 0;
while( s && *s && count < len ) {
if( useColourCodes && Q_IsColorString( s ) ) {
s += 2;
continue;
}
else {
glyph = &font->glyphs[ ( int )*s ]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
if( max < glyph->height )
max = glyph->height;
s++;
count++;
}
}
}
return max * font->glyphScale;
}
/*
===================
RE_Text_PaintChar
===================
Paints a single character.
*/
void RE_Text_PaintChar( fontInfo_t *font, float x, float y, float scale, int c, qboolean is640 ) {
glyphInfo_t *glyph;
float xscale;
float yscale;
if( is640 ) {
xscale = glConfig.vidWidth / 640.0f;
yscale = glConfig.vidHeight / 480.0f;
}
else {
xscale = 1.0f;
yscale = 1.0f;
}
glyph = &font->glyphs[ c ];
if( c != '\n' && glyph->imageWidth == 0 && glyph->imageHeight == 0 ) {
glyph = &font->glyphs[ '?' ];
// this is so annoying..
//ri.Printf(PRINT_WARNING, "RE_Text_PaintChar: no #%d character in font %s!\n", (int)c, font->name);
}
RE_StretchPic( x * xscale, y*yscale - font->glyphScale * glyph->top,
glyph->imageWidth * font->glyphScale * scale * xscale,
glyph->imageHeight * font->glyphScale * scale * yscale,
glyph->s,
glyph->t,
glyph->s2,
glyph->t2,
glyph->glyph );
}
/*
===================
RE_Text_Paint
===================
Paints a string. The alpha value will be ignored unless useColourCodes is qtrue.
*/
void RE_Text_Paint( fontInfo_t *font, float x, float y, float scale, float alpha, const char *text, float adjust, int limit, qboolean useColourCodes, qboolean is640 ) {
int len, count;
vec4_t newColor;
glyphInfo_t *glyph;
float xscale;
float yscale;
if( !font ) {
if( !registeredFontCount )
return;
font = &registeredFont[ 0 ];
}
if( is640 ) {
xscale = glConfig.vidWidth / 640.0f;
yscale = glConfig.vidHeight / 480.0f;
}
else {
xscale = 1.0f;
yscale = 1.0f;
}
if( text ) {
// TTimo: FIXME
// const unsigned char *s = text;
const char *s = text;
len = strlen( text );
if( limit > 0 && len > limit )
len = limit;
count = 0;
while( s && *s && count < len ) {
glyph = &font->glyphs[ ( int )*s ]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
if( *s != '\n' && glyph->imageWidth == 0 && glyph->imageHeight == 0 ) {
glyph = &font->glyphs[ '?' ];
//ri.Printf(PRINT_WARNING, "RE_Text_Paint: no #%d character in font %s!\n", (int)*s, font->name);
}
if( useColourCodes && Q_IsColorString( s ) ) {
memcpy( newColor, g_color_table[ ColorIndex( *( s + 1 ) ) ], sizeof( newColor ) );
newColor[ 3 ] = alpha;
RE_SetColor( newColor );
s += 2;
continue;
}
else {
float yadj = font->glyphScale * scale * glyph->top;
/*if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
colorBlack[3] = newColor[3];
RE_SetColor(colorBlack);
RE_StretchPic(x + ofs, y - yadj + ofs,
glyph->imageWidth * font->glyphScale,
glyph->imageHeight * font->glyphScale,
glyph->s,
glyph->t,
glyph->s2,
glyph->t2,
glyph->glyph);
colorBlack[3] = 1.0;
RE_SetColor( newColor );
}*/
RE_StretchPic( x*xscale, ( y - yadj )*yscale,
glyph->imageWidth * font->glyphScale * scale*xscale,
glyph->imageHeight * font->glyphScale * scale*yscale,
glyph->s,
glyph->t,
glyph->s2,
glyph->t2,
glyph->glyph );
x += ( glyph->xSkip * font->glyphScale * scale ) + adjust;
s++;
count++;
}
}
if( useColourCodes ) {
RE_SetColor( NULL );
}
}
}

View file

@ -20,38 +20,51 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=========================================================================== ===========================================================================
*/ */
/* #include <setjmp.h>
* Include file for users of JPEG library.
* You will need to have included system headers that define at least
* the typedefs FILE and size_t before you can include jpeglib.h.
* (stdio.h is sufficient on ANSI-conforming systems.)
* You may also wish to include "jerror.h".
*/
#define JPEG_INTERNALS
#include "../jpeg-8c/jinclude.h"
#include "../jpeg-8c/jpeglib.h"
#include "tr_common.h" #include "tr_common.h"
/*
* Include file for users of JPEG library.
* You will need to have included system headers that define at least
* the typedefs FILE and size_t before you can include jpeglib.h.
* (stdio.h is sufficient on ANSI-conforming systems.)
* You may also wish to include "jerror.h".
*/
#ifdef USE_INTERNAL_JPEG
# define JPEG_INTERNALS
#endif
#include <jpeglib.h>
#ifndef USE_INTERNAL_JPEG #ifndef USE_INTERNAL_JPEG
# if JPEG_LIB_VERSION < 80 && !defined(MEM_SRCDST_SUPPORTED) # if JPEG_LIB_VERSION < 80 && !defined(MEM_SRCDST_SUPPORTED)
# error Need system libjpeg >= 80 or jpeg_mem_ support # error Need system libjpeg >= 80 or jpeg_mem_ support
# endif # endif
#endif #endif
static void __attribute__((__noreturn__)) R_JPGErrorExit(j_common_ptr cinfo) /* Catching errors, as done in libjpeg's example.c */
typedef struct q_jpeg_error_mgr_s
{
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
} q_jpeg_error_mgr_t;
static void R_JPGErrorExit(j_common_ptr cinfo)
{ {
char buffer[JMSG_LENGTH_MAX]; char buffer[JMSG_LENGTH_MAX];
/* cinfo->err really points to a q_jpeg_error_mgr_s struct, so coerce pointer */
q_jpeg_error_mgr_t *jerr = (q_jpeg_error_mgr_t *)cinfo->err;
(*cinfo->err->format_message) (cinfo, buffer); (*cinfo->err->format_message) (cinfo, buffer);
/* Let the memory manager delete any temp files before we die */ ri.Printf(PRINT_ALL, "Error: %s", buffer);
jpeg_destroy(cinfo);
/* Return control to the setjmp point */
ri.Error(ERR_FATAL, "%s", buffer); longjmp(jerr->setjmp_buffer, 1);
} }
static void R_JPGOutputMessage(j_common_ptr cinfo) static void R_JPGOutputMessage(j_common_ptr cinfo)
@ -83,7 +96,7 @@ void R_LoadJPG(const char *filename, unsigned char **pic, int *width, int *heigh
* Note that this struct must live as long as the main JPEG parameter * Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems. * struct, to avoid dangling-pointer problems.
*/ */
struct jpeg_error_mgr jerr; q_jpeg_error_mgr_t jerr;
/* More stuff */ /* More stuff */
JSAMPARRAY buffer; /* Output row buffer */ JSAMPARRAY buffer; /* Output row buffer */
unsigned int row_stride; /* physical row width in output buffer */ unsigned int row_stride; /* physical row width in output buffer */
@ -115,10 +128,24 @@ void R_LoadJPG(const char *filename, unsigned char **pic, int *width, int *heigh
* This routine fills in the contents of struct jerr, and returns jerr's * This routine fills in the contents of struct jerr, and returns jerr's
* address which we place into the link field in cinfo. * address which we place into the link field in cinfo.
*/ */
cinfo.err = jpeg_std_error(&jerr); cinfo.err = jpeg_std_error(&jerr.pub);
cinfo.err->error_exit = R_JPGErrorExit; cinfo.err->error_exit = R_JPGErrorExit;
cinfo.err->output_message = R_JPGOutputMessage; cinfo.err->output_message = R_JPGOutputMessage;
/* Establish the setjmp return context for R_JPGErrorExit to use. */
if (setjmp(jerr.setjmp_buffer))
{
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
jpeg_destroy_decompress(&cinfo);
ri.FS_FreeFile(fbuffer.v);
/* Append the filename to the error for easier debugging */
ri.Printf(PRINT_ALL, ", loading file %s\n", filename);
return;
}
/* Now we can initialize the JPEG decompression object. */ /* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo); jpeg_create_decompress(&cinfo);
@ -361,17 +388,29 @@ size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality,
int image_width, int image_height, byte *image_buffer, int padding) int image_width, int image_height, byte *image_buffer, int padding)
{ {
struct jpeg_compress_struct cinfo; struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr; q_jpeg_error_mgr_t jerr;
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
my_dest_ptr dest; my_dest_ptr dest;
int row_stride; /* physical row width in image buffer */ int row_stride; /* physical row width in image buffer */
size_t outcount; size_t outcount;
/* Step 1: allocate and initialize JPEG compression object */ /* Step 1: allocate and initialize JPEG compression object */
cinfo.err = jpeg_std_error(&jerr); cinfo.err = jpeg_std_error(&jerr.pub);
cinfo.err->error_exit = R_JPGErrorExit; cinfo.err->error_exit = R_JPGErrorExit;
cinfo.err->output_message = R_JPGOutputMessage; cinfo.err->output_message = R_JPGOutputMessage;
/* Establish the setjmp return context for R_JPGErrorExit to use. */
if (setjmp(jerr.setjmp_buffer))
{
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object and return.
*/
jpeg_destroy_compress(&cinfo);
ri.Printf(PRINT_ALL, "\n");
return 0;
}
/* Now we can initialize the JPEG compression object. */ /* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo); jpeg_create_compress(&cinfo);

View file

@ -23,6 +23,31 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_common.h" #include "tr_common.h"
/*
========================================================================
PCX files are used for 8 bit images
========================================================================
*/
typedef struct {
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
unsigned short xmin,ymin,xmax,ymax;
unsigned short hres,vres;
unsigned char palette[48];
char reserved;
char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
unsigned short hscreensize, vscreensize;
char filler[54];
unsigned char data[];
} pcx_t;
void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height) void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height)
{ {
union { union {

View file

@ -571,7 +571,7 @@ static uint32_t DecompressIDATs(struct BufferedFile *BF, uint8_t **Buffer)
{ {
/* /*
* Rewind to the start of this adventure * Rewind to the start of this adventure
* and return unsuccessfull * and return unsuccessful
*/ */
BufferedFileRewind(BF, BytesToRewind); BufferedFileRewind(BF, BytesToRewind);
@ -754,7 +754,7 @@ static uint32_t DecompressIDATs(struct BufferedFile *BF, uint8_t **Buffer)
ri.Free(CompressedData); ri.Free(CompressedData);
/* /*
* Check if the last puff() was successfull. * Check if the last puff() was successful.
*/ */
if(!((puffResult == 0) && (puffDestLen > 0))) if(!((puffResult == 0) && (puffDestLen > 0)))

View file

@ -30,6 +30,14 @@ TGA files are used for 24/32 bit images
======================================================================== ========================================================================
*/ */
typedef struct _TargaHeader {
unsigned char id_length, colormap_type, image_type;
unsigned short colormap_index, colormap_length;
unsigned char colormap_size;
unsigned short x_origin, y_origin, width, height;
unsigned char pixel_size, attributes;
} TargaHeader;
void R_LoadTGA ( const char *name, byte **pic, int *width, int *height) void R_LoadTGA ( const char *name, byte **pic, int *width, int *height)
{ {
unsigned columns, rows, numPixels; unsigned columns, rows, numPixels;

View file

@ -49,7 +49,7 @@ void R_NoiseInit( void )
} }
} }
float R_NoiseGet4f( float x, float y, float z, float t ) float R_NoiseGet4f( float x, float y, float z, double t )
{ {
int i; int i;
int ix, iy, iz, it; int ix, iy, iz, it;

View file

@ -22,15 +22,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef __TR_PUBLIC_H #ifndef __TR_PUBLIC_H
#define __TR_PUBLIC_H #define __TR_PUBLIC_H
#include "../cgame/tr_types.h" #include "tr_types.h"
#include "q_shared.h"
#ifdef __cplusplus
extern "C" {
#endif
#define REF_API_VERSION 14
#define REF_API_VERSION 8
typedef struct dtiki_s dtiki_t; typedef struct dtiki_s dtiki_t;
typedef struct skelAnimFrame_s skelAnimFrame_t; typedef struct skelAnimFrame_s skelAnimFrame_t;
@ -39,255 +33,205 @@ typedef struct skelAnimFrame_s skelAnimFrame_t;
// these are the functions exported by the refresh module // these are the functions exported by the refresh module
// //
typedef struct { typedef struct {
// called before the library is unloaded // called before the library is unloaded
// if the system is just reconfiguring, pass destroyWindow = qfalse, // if the system is just reconfiguring, pass destroyWindow = qfalse,
// which will keep the screen from flashing to the desktop. // which will keep the screen from flashing to the desktop.
void (*Shutdown)( qboolean destroyWindow ); void (*Shutdown)(qboolean destroyWindow);
// All data that will be used in a level should be // All data that will be used in a level should be
// registered before rendering any frames to prevent disk hits, // registered before rendering any frames to prevent disk hits,
// but they can still be registered at a later time // but they can still be registered at a later time
// if necessary. // if necessary.
// //
// BeginRegistration makes any existing media pointers invalid // BeginRegistration makes any existing media pointers invalid
// and returns the current gl configuration, including screen width // and returns the current gl configuration, including screen width
// and height, which can be used by the client to intelligently // and height, which can be used by the client to intelligently
// size display elements // size display elements
void ( *BeginRegistration )( glconfig_t *glConfigOut ); void (*BeginRegistration)(glconfig_t* glConfigOut);
qhandle_t ( *RegisterModel )( const char *name ); qhandle_t(*RegisterModel)(const char* name);
qhandle_t ( *SpawnEffectModel )( const char *name, vec3_t pos, vec3_t axis[3] ); qhandle_t(*SpawnEffectModel)(const char* name, vec3_t pos, vec3_t axis[3]);
qhandle_t ( *RegisterServerModel )( const char *name ); qhandle_t(*RegisterServerModel)(const char* name);
void ( *UnregisterServerModel )( qhandle_t model ); void (*UnregisterServerModel)(qhandle_t model);
qhandle_t ( *RegisterShader )( const char *name ); qhandle_t(*RegisterShader)(const char* name);
qhandle_t ( *RegisterShaderNoMip )( const char *name ); qhandle_t(*RegisterShaderNoMip)(const char* name);
qhandle_t ( *RefreshShaderNoMip )( const char *name ); qhandle_t(*RefreshShaderNoMip)(const char* name);
// EndRegistration will draw a tiny polygon with each texture, forcing // EndRegistration will draw a tiny polygon with each texture, forcing
// them to be loaded into card memory // them to be loaded into card memory
void ( *EndRegistration )( void ); void (*EndRegistration)();
void ( *FreeModels )( void ); void (*FreeModels)();
// the vis data is a large enough block of data that we go to the trouble // the vis data is a large enough block of data that we go to the trouble
// of sharing it with the clipmodel subsystem // of sharing it with the clipmodel subsystem
void ( *SetWorldVisData )( const byte *vis ); void (*SetWorldVisData)(const byte* vis);
void ( *LoadWorld )( const char *name ); void (*LoadWorld)(const char* name);
void ( *PrintBSPFileSizes )( void ); void (*PrintBSPFileSizes)();
int ( *MapVersion )( void ); int (*MapVersion)();
// a scene is built up by calls to R_ClearScene and the various R_Add functions. // a scene is built up by calls to R_ClearScene and the various R_Add functions.
// Nothing is drawn until R_RenderScene is called. // Nothing is drawn until R_RenderScene is called.
void (*ClearScene)( void ); void (*ClearScene)(void);
void (*AddRefEntityToScene)( const refEntity_t *re, int parentEntityNumber ); void (*AddRefEntityToScene)(const refEntity_t* re, int parentEntityNumber);
void (*AddRefSpriteToScene )( const refEntity_t *ent ); void (*AddRefSpriteToScene)(const refEntity_t* ent);
qboolean (*AddPolyToScene)( qhandle_t hShader , int numVerts, const polyVert_t *verts, int renderFx ); qboolean(*AddPolyToScene)(qhandle_t hShader, int numVerts, const polyVert_t* verts, int renderfx);
void (*AddTerrainMarkToScene)( int terrainIndex, qhandle_t hShader, int numVerts, polyVert_t *verts, int renderfx ); void (*AddTerrainMarkToScene)(int terrainIndex, qhandle_t hShader, int numVerts, const polyVert_t* verts, int renderfx);
void (*AddLightToScene)( const vec3_t org, float intensity, float r, float g, float b, int type ); void (*AddLightToScene)(const vec3_t org, float intensity, float r, float g, float b, int type);
void (*AddAdditiveLightToScene)( const vec3_t org, float intensity, float r, float g, float b ); void (*RenderScene)(const refdef_t* fd);
void (*RenderScene)( const refdef_t *fd );
refEntity_t *(*GetRenderEntity )( int entityNumber ); refEntity_t* (*GetRenderEntity)(int entityNumber);
void (*SavePerformanceCounters)( void ); void (*SavePerformanceCounters)();
void (*SetColor)(const float* rgba); // NULL = 1,1,1,1
void (*Set2DWindow)(int x, int y, int w, int h, float left, float right, float bottom, float top, float n, float f);
void (*DrawStretchPic) (float x, float y, float w, float h,
float s1, float t1, float s2, float t2, qhandle_t hShader); // 0 = white
void (*SetColor)( const vec4_t rgba ); // NULL = 1,1,1,1 void (*DrawTilePic)(float x, float y, float w, float h, qhandle_t hShader);
void (*Set2DWindow)( int x, int y, int w, int h, float left, float right, float bottom, float top, float n, float f ); void (*DrawTilePicOffset)(float x, float y, float w, float h, qhandle_t hShader, int offsetX, int offsetY);
void (*DrawStretchPic) ( float x, float y, float w, float h, void (*DrawTrianglePic)(vec2_t* points, vec2_t* texCoords, qhandle_t hShader);
float s1, float t1, float s2, float t2, qhandle_t hShader ); // 0 = white void (*DrawBackground)(int cols, int rows, int bgr, uint8_t* data);
void (*DrawTilePic)( float x, float y, float w, float h, qhandle_t hShader ); // Draw images for cinematic rendering, pass as 32 bit rgba
void (*DrawTilePicOffset)( float x, float y, float w, float h, qhandle_t hShader, int offsetX, int offsetY ); void (*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, int components, const byte* data);
void (*DrawTrianglePic)( vec2_t *points, vec2_t *texCoords, qhandle_t hShader ); void (*DebugLine)(const vec3_t start, const vec3_t end, float r, float g, float b, float alpha);
void (*DrawBackground)( int cols, int rows, int bgr, unsigned char *data ); void (*DrawBox)(float x, float y, float w, float h);
void (*AddBox)(float x, float y, float w, float h);
// Draw images for cinematic rendering, pass as 32 bit rgba void (*BeginFrame)(stereoFrame_t stereoFrame);
void (*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, int components, const byte *data); void (*Scissor)(int x, int y, int width, int height);
void (*DrawLineLoop)(const vec2_t* points, int count, int stippleFactor, int stippleMask);
void (*DebugLine)( vec3_t start, vec3_t end, float r, float g, float b, float alpha ); // if the pointers are not NULL, timing info will be returned
void (*DrawBox)( float x, float y, float w, float h ); void (*EndFrame)(int* frontEndMsec, int* backEndMsec);
void (*AddBox)( float x, float y, float w, float h );
void (*BeginFrame)( stereoFrame_t stereoFrame );
void (*Scissor)( int x, int y, int width, int height );
void (*DrawLineLoop)( vec2_t *points, int count, int stippleFactor, int stippleMask );
// if the pointers are not NULL, timing info will be returned
void (*EndFrame)( int *frontEndMsec, int *backEndMsec );
int (*MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection, int (*MarkFragments)(int numPoints, const vec3_t* points, const vec3_t projection,
int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer, float fRadiusSquared ); int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t* fragmentBuffer, float fRadiusSquared);
int (*MarkFragmentsForInlineModel)(clipHandle_t bmodel, const vec3_t angles, const vec3_t origin, int numPoints,
const vec3_t* points, const vec3_t projection, int maxPoints, vec3_t pointBuffer,
int maxFragments, markFragment_t* fragmentBuffer, float radiusSquared);
int (*MarkFragmentsForInlineModel)( clipHandle_t bmodel, vec3_t vAngles, vec3_t vOrigin, void (*GetInlineModelBounds)(int index, vec3_t mins, vec3_t maxs);
int numPoints, const vec3_t *points, const vec3_t projection, void (*GetLightingForDecal)(vec3_t light, vec3_t facing, vec3_t origin);
int maxPoints, vec3_t pointBuffer, void (*GetLightingForSmoke)(vec3_t light, vec3_t origin);
int maxFragments, markFragment_t *fragmentBuffer, float fRadiusSquared ); int (*R_GatherLightSources)(const vec3_t pos, vec3_t* lightPos, vec3_t* lightIntensity, int maxLights);
void ( *GetInlineModelBounds )( int index, vec3_t mins, vec3_t maxs ); void (*ModelBounds)(qhandle_t model, vec3_t mins, vec3_t maxs);
void ( *GetLightingForDecal )( vec3_t light, vec3_t facing, vec3_t origin ); float (*ModelRadius)(qhandle_t handle);
void ( *GetLightingForSmoke )( vec3_t light, vec3_t origin );
int ( *R_GatherLightSources )( vec3_t pos, vec3_t *lightPos, vec3_t *lightIntensity, int maxLights );
void ( *ModelBounds )( qhandle_t handle, vec3_t mins, vec3_t maxs );
float ( *ModelRadius )( qhandle_t handle );
dtiki_t *( *R_Model_GetHandle )( qhandle_t handle );
void ( *DrawString )( fontheader_t *font, const char *text, float x, float y, int maxLen, qboolean virtualScreen );
float ( *GetFontHeight )( fontheader_t *font );
float ( *GetFontStringWidth )( fontheader_t *font, const char *string );
fontheader_t *(*LoadFont)( const char *name ); dtiki_t* (*R_Model_GetHandle)(qhandle_t handle);
void (*DrawString)(const fontheader_t* font, const char* text, float x, float y, int maxLen, qboolean virtualScreen);
void (*SwipeBegin)( float thisTime, float life, qhandle_t hShader ); float (*GetFontHeight)(const fontheader_t* font);
void (*SwipePoint)( vec3_t point1, vec3_t point2, float time ); float (*GetFontStringWidth)(const fontheader_t* font, char* string);
void (*SwipeEnd)( ); fontheader_t* (*LoadFont)(const char* name);
void (*SetRenderTime)( int t ); void (*SwipeBegin)(float thisTime, float life, qhandle_t hShader);
float (*Noise)( float x, float y, float z, float t ); void (*SwipePoint)(vec3_t point1, vec3_t point2, float time);
qboolean (*SetMode)( int mode, glconfig_t *glConfig ); void (*SwipeEnd)();
void (*SetFullscreen)( qboolean fullscreen, glconfig_t *config ); void (*SetRenderTime)(int t);
float (*Noise)(float x, float y, float z, float t);
#ifdef __USEA3D qboolean(*SetMode)(int mode, const glconfig_t* glConfig);
void (*A3D_RenderGeometry) (void *pVoidA3D, void *pVoidGeom, void *pVoidMat, void *pVoidGeomStatus); void (*SetFullscreen)(qboolean fullScreen);
#endif int (*GetShaderWidth)(qhandle_t hShader);
int (*GetShaderHeight)(qhandle_t hShader);
// IneQuation char* (*GetGraphicsInfo)();
int (*Text_Width)(fontInfo_t *font, const char *text, int limit, qboolean useColourCodes); void (*ForceUpdatePose)(refEntity_t* model);
int (*Text_Height)(fontInfo_t *font, const char *text, int limit, qboolean useColourCodes); orientation_t(*TIKI_Orientation)(refEntity_t* model, int tagNum);
// Paints a string. The alpha value will be ignored unless useColourCodes is qtrue. qboolean(*TIKI_IsOnGround)(refEntity_t* model, int tagNum, float threshold);
void (*Text_Paint)(fontInfo_t *font, float x, float y, float scale, float alpha, const char *text, float adjust, int limit, qboolean useColourCodes, qboolean is640); void (*SetFrameNumber)(int frameNumber);
void (*Text_PaintChar)(fontInfo_t *font, float x, float y, float scale, int c, qboolean is640);
// su44
int (*GetShaderWidth)(qhandle_t shader);
int (*GetShaderHeight)(qhandle_t shader);
const char *(*GetGraphicsInfo)( );
void (*ForceUpdatePose)( refEntity_t *model );
orientation_t (*TIKI_Orientation)( refEntity_t *model, int tagNum );
qboolean (*TIKI_IsOnGround)( refEntity_t *model, int tagNum, float threshold );
void (*SetFrameNumber)( int frameNumber );
// obsolete functions
//void (*TakeVideoFrame)( int h, int w, byte* captureBuffer, byte *encodeBuffer, qboolean motionJpeg );
const char *(*GetShaderName)(qhandle_t shader);
void (*RegisterFont)(const char *fontName, int pointSize, fontInfo_t *font);
qboolean (*inPVS)( const vec3_t p1, const vec3_t p2 );
void (*UploadCinematic) (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
} refexport_t; } refexport_t;
// //
// these are the functions imported by the refresh module // these are the functions imported by the refresh module
// //
typedef struct { typedef struct {
// print message on the local console // print message on the local console
void (QDECL *Printf)( int printLevel, const char *fmt, ...); void (QDECL* Printf)(int printLevel, const char* fmt, ...);
// abort the game // abort the game
void (QDECL *Error)( int errorLevel, const char *fmt, ...); void (QDECL* Error)(int errorLevel, const char* fmt, ...);
// milliseconds should only be used for profiling, never // milliseconds should only be used for profiling, never
// for anything game related. Get time from the refdef // for anything game related. Get time from the refdef
int (*Milliseconds)( void ); int (*Milliseconds)(void);
// transform the text into its localized version char* (*LV_ConvertString)(char* string);
const char *(*LV_ConvertString)( const char *text ); void (*Hunk_Clear)();
// stack based memory allocation for per-level things that // stack based memory allocation for per-level things that
// won't be freed // won't be freed
void (*Hunk_Clear )( void ); #ifdef HUNK_DEBUG
void *(*Hunk_Alloc)(size_t size ); void* (*Hunk_AllocDebug)(size_t size, const char* label, const char* file, int line);
void *(*Hunk_AllocateTempMemory)(size_t size ); #else
void (*Hunk_FreeTempMemory)( void *block ); void* (*Hunk_Alloc)(size_t size);
#endif
void* (*Hunk_AllocateTempMemory)(size_t size);
void (*Hunk_FreeTempMemory)(void* block);
// dynamic memory allocator for things that need to be freed // dynamic memory allocator for things that need to be freed
void *(*Malloc)(size_t bytes ); void* (*Malloc)(size_t bytes);
void (*Free)( void *buf ); void (*Free)(void* buf);
void (*Clear)( void ); void (*Clear)();
cvar_t *(*Cvar_Get)( const char *name, const char *value, int flags ); cvar_t* (*Cvar_Get)(const char* name, const char* value, int flags);
void (*Cvar_Set)( const char *name, const char *value ); void (*Cvar_Set)(const char* name, const char* value);
void (*Cvar_SetDefault)( cvar_t *var, const char *value ); void (*Cvar_SetDefault)(cvar_t* var, const char* varValue);
void (*Cmd_AddCommand)( const char *name, void(*cmd)(void) ); void (*Cmd_AddCommand)(const char* name, void (*command) (void));
void (*Cmd_RemoveCommand)( const char *name ); void (*Cmd_RemoveCommand)(const char* name);
int (*Cmd_Argc) (void); int (*Cmd_Argc) (void);
char *(*Cmd_Argv) (int i); char* (*Cmd_Argv) (int i);
void (*Cmd_ExecuteText) (cbufExec_t exec_when, const char *text); void (*Cmd_ExecuteText) (cbufExec_t exec_when, const char* text);
// visualization for debugging collision detection // visualization for debugging collision detection
void (*CM_DrawDebugSurface)( void (*drawPoly)(int color, int numPoints, float *points) ); void (*CM_DrawDebugSurface)(void (*drawPoly)(int color, int numPoints, float* points));
// a -1 return means the file does not exist // a -1 return means the file does not exist
// NULL can be passed for buf to just determine existance // NULL can be passed for buf to just determine existance
int (*FS_FOpenFile)( const char *filename, fileHandle_t *file, qboolean uniqueFILE, qboolean quiet ); int (*FS_OpenFile)(const char* qpath, fileHandle_t* file, qboolean uniqueFILE, qboolean quiet);
size_t (*FS_Read)( void *buffer, size_t len, fileHandle_t f ); size_t(*FS_Read)(void* buffer, size_t len, fileHandle_t fileHandle);
void (*FS_CloseFile)( fileHandle_t f ); void (*FS_CloseFile)(fileHandle_t fileHandle);
int (*FS_Seek)( fileHandle_t f, long offset, fsOrigin_t origin ); int (*FS_Seek)(fileHandle_t fileHandle, long offset, fsOrigin_t origin);
int (*FS_FileIsInPAK)( const char *filename, int *pChecksum ); int (*FS_FileIsInPAK)(const char* name, int* pCheckSum);
int (*FS_ReadFile)( const char *name, void **buf ); int (*FS_ReadFile)(const char* name, void** buf);
int (*FS_ReadFileEx)( const char *name, void **buf, qboolean quiet ); int (*FS_ReadFileEx)(const char* qpath, void** buffer, qboolean quiet);
void (*FS_FreeFile)( void *buf ); void (*FS_FreeFile)(void* buf);
char ** (*FS_ListFiles)( const char *name, const char *extension, qboolean wantStubs, int *numfilesfound ); char** (*FS_ListFiles)(const char* name, const char* extension, qboolean wantSubs, int* numFiles);
void (*FS_FreeFileList)( char **filelist ); void (*FS_FreeFileList)(char** filelist);
int (*FS_WriteFile)( const char *qpath, const void *buffer, int size ); int (*FS_WriteFile)(const char* qpath, const void* buffer, int size);
qboolean (*FS_FileExists)( const char *file ); qboolean(*FS_FileExists)(const char* file);
// cm stuff void (*CM_BoxTrace)(trace_t* results, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, int model, int brushMask, int cylinder);
void (*CM_BoxTrace)( trace_t *results, const vec3_t start, const vec3_t end, int (*CM_TerrainSquareType)(int terrainPatch, int i, int j);
const vec3_t mins, const vec3_t maxs, char* (*CM_EntityString)();
clipHandle_t model, int brushmask, int cylinder ); const char* (*CM_MapTime)();
int (*CM_TerrainSquareType)( int iTerrainPatch, int i, int j ); int (*CG_PermanentMark)(const vec3_t origin, const vec3_t dir, float orientation, float sScale, float tScale, float red, float green, float blue, float alpha, qboolean doLighting, float sCenter, float tCenter, markFragment_t* markFragments, void* polyVerts);
char *(*CM_EntityString)( void ); int (*CG_PermanentTreadMarkDecal)(treadMark_t* treadMark, qboolean startSegment, qboolean doLighting, markFragment_t* markFragments, void* polyVerts);
const char *(*CM_MapTime)( void ); int (*CG_PermanentUpdateTreadMark)(treadMark_t* treadMark, float alpha, float minSegment, float maxSegment, float maxOffset, float texScale);
void (*CG_ProcessInitCommands)(dtiki_t* tiki, refEntity_t* ent);
void (*CG_EndTiki)(dtiki_t* tiki);
void (*SetPerformanceCounters)(int totalTris, int totalVerts, int totalTexels, int worldTris, int worldVerts, int characterLights);
// client game stuff debugline_t** DebugLines;
int (*CG_PermanentMark)( vec3_t origin, vec3_t dir, float orientation, int* numDebugLines;
float fSScale, float fTScale, float red, float green, float blue, float alpha, debugstring_t** DebugStrings;
qboolean dolighting, float fSCenter, float fTCenter, int* numDebugStrings;
markFragment_t *pMarkFragments, void *pPolyVerts );
int (*CG_PermanentTreadMarkDecal)( treadMark_t *pTread, qboolean bStartSegment, qboolean dolighting,
markFragment_t *pMarkFragments, void *pVoidPolyVerts );
int (*CG_PermanentUpdateTreadMark)( treadMark_t *pTread, float fAlpha, float fMinSegment, float fMaxSegment, float fMaxOffset, float fTexScale );
void (*CG_ProcessInitCommands)( dtiki_t *tiki, refEntity_t *ent );
void (*CG_EndTiki)( dtiki_t *tiki );
orientation_t(*TIKI_OrientationInternal)(dtiki_t* tiki, int entNum, int tagNum, float scale);
void (*SetPerformanceCounters)( int total_tris, int total_verts, int total_texels, int world_tris, int world_verts, int character_lights ); qboolean(*TIKI_IsOnGroundInternal)(dtiki_t* tiki, int entNum, int tagNum, float thresHold);
void (*TIKI_SetPoseInternal)(void* skeletor, const frameInfo_t* frameInfo, const int* boneTag, const vec4_t* boneQuat, float actionWeight);
// debugging stuff void* (*TIKI_Alloc)(size_t size);
debugline_t **DebugLines; float (*GetRadiusInternal)(dtiki_t* tiki, int entNum, float scale);
int *numDebugLines; float (*GetCentroidRadiusInternal)(dtiki_t* tiki, int entNum, float scale, vec3_t centroid);
debugstring_t **DebugStrings; void (*GetFrameInternal)(dtiki_t* tiki, int entNum, skelAnimFrame_t* newFrame);
int *numDebugStrings;
// TIKI stuff
orientation_t (*TIKI_OrientationInternal)( dtiki_t *tiki, int entnum, int tagnum, float scale );
qboolean (*TIKI_IsOnGroundInternal) (dtiki_t *tiki, int entnum, int tagnum, float threshold );
void (*TIKI_SetPoseInternal)( void *skeletor, const frameInfo_t *frameInfo, int *bone_tag, vec4_t *bone_quat, float actionWeight );
void *(*TIKI_Alloc)(size_t size );
float (*GetRadiusInternal)( dtiki_t *tiki, int entnum, float scale );
float (*GetCentroidRadiusInternal)( dtiki_t *tiki, int entnum, float scale, float *centroid );
void (*GetFrameInternal)( dtiki_t *tiki, int entnum, skelAnimFrame_t *newFrame );
// cinematic stuff
void (*CIN_UploadCinematic)(int handle);
int (*CIN_PlayCinematic)( const char *arg0, int xpos, int ypos, int width, int height, int bits);
e_status (*CIN_RunCinematic) (int handle);
void (*CL_WriteAVIVideoFrame)( const byte *buffer, int size );
// su44 - plugable renderer architecture
byte *(*CM_ClusterPVS)(int cluster);
// input event handling
void (*IN_Init)(void *windowData);
void (*IN_Shutdown)(void);
void (*IN_Restart)(void);
// system stuff // system stuff
void (*Sys_SetEnv)(const char* name, const char* value); void (*Sys_SetEnv)(const char* name, const char* value);
void (*Sys_GLimpSafeInit)(void); void (*Sys_GLimpSafeInit)(void);
void (*Sys_GLimpInit)(void); void (*Sys_GLimpInit)(void);
qboolean(*Sys_LowPhysicalMemory)(void); qboolean(*Sys_LowPhysicalMemory)(void);
} refimport_t; } refimport_t;
@ -300,8 +244,4 @@ typedef refexport_t* (QDECL *GetRefAPI_t) (int apiVersion, refimport_t * rimp);
refexport_t*GetRefAPI( int apiVersion, refimport_t *rimp ); refexport_t*GetRefAPI( int apiVersion, refimport_t *rimp );
#endif #endif
#ifdef __cplusplus
}
#endif
#endif // __TR_PUBLIC_H #endif // __TR_PUBLIC_H

View file

@ -20,19 +20,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=========================================================================== ===========================================================================
*/ */
// //
#pragma once #pragma once
#include "../cgame/tr_types.h"
#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces #define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces
#define REFENTITYNUM_BITS 10 // can't be increased without changing drawsurf bit packing #define REFENTITYNUM_BITS 10 // can't be increased without changing drawsurf bit packing
#define REFSPRITE_BITS 10 // can't be increased without changing drawsurf bit packing
#define REFENTITYNUM_MASK ((1<<REFENTITYNUM_BITS) - 1) #define REFENTITYNUM_MASK ((1<<REFENTITYNUM_BITS) - 1)
// the last N-bit number (2^REFENTITYNUM_BITS - 1) is reserved for the special world refentity, // the last N-bit number (2^REFENTITYNUM_BITS - 1) is reserved for the special world refentity,
// and this is reflected by the value of MAX_REFENTITIES (which therefore is not a power-of-2) // and this is reflected by the value of MAX_REFENTITIES (which therefore is not a power-of-2)
#define MAX_REFENTITIES ((1<<REFENTITYNUM_BITS) - 1) #define MAX_REFENTITIES ((1<<REFENTITYNUM_BITS) - 1)
#define MAX_REFSPRITES ((1<<REFSPRITE_BITS) - 1)
#define REFENTITYNUM_WORLD ((1<<REFENTITYNUM_BITS) - 1) #define REFENTITYNUM_WORLD ((1<<REFENTITYNUM_BITS) - 1)
#define MAX_RENDER_STRINGS 8
#define MAX_RENDER_STRING_LENGTH 32

View file

@ -0,0 +1,414 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
/* This file is only compiled for PowerPC builds with Altivec support.
Altivec intrinsics need to be in a separate file, so GCC's -maltivec
command line can enable them, but give us the option to _not_ use that
on other files, where the compiler might then generate Altivec
instructions for normal floating point, crashing on G3 (etc) processors. */
#include "tr_local.h"
#if idppc_altivec
#if !defined(__APPLE__)
#include <altivec.h>
#endif
void ProjectDlightTexture_altivec( void ) {
int i, l;
vec_t origin0, origin1, origin2;
float texCoords0, texCoords1;
vector float floatColorVec0, floatColorVec1;
vector float modulateVec, colorVec, zero;
vector short colorShort;
vector signed int colorInt;
vector unsigned char floatColorVecPerm, modulatePerm, colorChar;
vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff);
float *texCoords;
byte *colors;
byte clipBits[SHADER_MAX_VERTEXES];
float texCoordsArray[SHADER_MAX_VERTEXES][2];
byte colorArray[SHADER_MAX_VERTEXES][4];
glIndex_t hitIndexes[SHADER_MAX_INDEXES];
int numIndexes;
float scale;
float radius;
vec3_t floatColor;
float modulate = 0.0f;
if ( !backEnd.refdef.num_dlights ) {
return;
}
// There has to be a better way to do this so that floatColor
// and/or modulate are already 16-byte aligned.
floatColorVecPerm = vec_lvsl(0,(float *)floatColor);
modulatePerm = vec_lvsl(0,(float *)&modulate);
modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0);
zero = (vector float)vec_splat_s8(0);
for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
dlight_t *dl;
if ( !( tess.dlightBits & ( 1 << l ) ) ) {
continue; // this surface definitely doesn't have any of this light
}
texCoords = texCoordsArray[0];
colors = colorArray[0];
dl = &backEnd.refdef.dlights[l];
origin0 = dl->transformed[0];
origin1 = dl->transformed[1];
origin2 = dl->transformed[2];
radius = dl->radius;
scale = 1.0f / radius;
if(r_greyscale->integer)
{
float luminance;
luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f;
floatColor[0] = floatColor[1] = floatColor[2] = luminance;
}
else if(r_greyscale->value)
{
float luminance;
luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f;
floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value);
floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value);
floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value);
}
else
{
floatColor[0] = dl->color[0] * 255.0f;
floatColor[1] = dl->color[1] * 255.0f;
floatColor[2] = dl->color[2] * 255.0f;
}
floatColorVec0 = vec_ld(0, floatColor);
floatColorVec1 = vec_ld(11, floatColor);
floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm);
for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
int clip = 0;
vec_t dist0, dist1, dist2;
dist0 = origin0 - tess.xyz[i][0];
dist1 = origin1 - tess.xyz[i][1];
dist2 = origin2 - tess.xyz[i][2];
backEnd.pc.c_dlightVertexes++;
texCoords0 = 0.5f + dist0 * scale;
texCoords1 = 0.5f + dist1 * scale;
if( !r_dlightBacks->integer &&
// dist . tess.normal[i]
( dist0 * tess.normal[i][0] +
dist1 * tess.normal[i][1] +
dist2 * tess.normal[i][2] ) < 0.0f ) {
clip = 63;
} else {
if ( texCoords0 < 0.0f ) {
clip |= 1;
} else if ( texCoords0 > 1.0f ) {
clip |= 2;
}
if ( texCoords1 < 0.0f ) {
clip |= 4;
} else if ( texCoords1 > 1.0f ) {
clip |= 8;
}
texCoords[0] = texCoords0;
texCoords[1] = texCoords1;
// modulate the strength based on the height and color
if ( dist2 > radius ) {
clip |= 16;
modulate = 0.0f;
} else if ( dist2 < -radius ) {
clip |= 32;
modulate = 0.0f;
} else {
dist2 = Q_fabs(dist2);
if ( dist2 < radius * 0.5f ) {
modulate = 1.0f;
} else {
modulate = 2.0f * (radius - dist2) * scale;
}
}
}
clipBits[i] = clip;
modulateVec = vec_ld(0,(float *)&modulate);
modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm);
colorVec = vec_madd(floatColorVec0,modulateVec,zero);
colorInt = vec_cts(colorVec,0); // RGBx
colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx
colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx
colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255
vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color
}
// build a list of triangles that need light
numIndexes = 0;
for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
int a, b, c;
a = tess.indexes[i];
b = tess.indexes[i+1];
c = tess.indexes[i+2];
if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
continue; // not lighted
}
hitIndexes[numIndexes] = a;
hitIndexes[numIndexes+1] = b;
hitIndexes[numIndexes+2] = c;
numIndexes += 3;
}
if ( !numIndexes ) {
continue;
}
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );
qglEnableClientState( GL_COLOR_ARRAY );
qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );
GL_Bind( tr.dlightImage );
// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
// where they aren't rendered
if ( dl->additive ) {
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
}
else {
GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
}
R_DrawElements( numIndexes, hitIndexes );
backEnd.pc.c_totalIndexes += numIndexes;
backEnd.pc.c_dlightIndexes += numIndexes;
}
}
void RB_CalcDiffuseColor_altivec( unsigned char *colors )
{
int i;
float *v, *normal;
trRefEntity_t *ent;
int ambientLightInt;
vec3_t lightDir;
int numVertexes;
vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff);
vector float ambientLightVec;
vector float directedLightVec;
vector float lightDirVec;
vector float normalVec0, normalVec1;
vector float incomingVec0, incomingVec1, incomingVec2;
vector float zero, jVec;
vector signed int jVecInt;
vector signed short jVecShort;
vector unsigned char jVecChar, normalPerm;
ent = backEnd.currentEntity;
ambientLightInt = ent->ambientLightInt;
// A lot of this could be simplified if we made sure
// entities light info was 16-byte aligned.
jVecChar = vec_lvsl(0, ent->ambientLight);
ambientLightVec = vec_ld(0, (vector float *)ent->ambientLight);
jVec = vec_ld(11, (vector float *)ent->ambientLight);
ambientLightVec = vec_perm(ambientLightVec,jVec,jVecChar);
jVecChar = vec_lvsl(0, ent->directedLight);
directedLightVec = vec_ld(0,(vector float *)ent->directedLight);
jVec = vec_ld(11,(vector float *)ent->directedLight);
directedLightVec = vec_perm(directedLightVec,jVec,jVecChar);
jVecChar = vec_lvsl(0, ent->lightDir);
lightDirVec = vec_ld(0,(vector float *)ent->lightDir);
jVec = vec_ld(11,(vector float *)ent->lightDir);
lightDirVec = vec_perm(lightDirVec,jVec,jVecChar);
zero = (vector float)vec_splat_s8(0);
VectorCopy( ent->lightDir, lightDir );
v = tess.xyz[0];
normal = tess.normal[0];
normalPerm = vec_lvsl(0,normal);
numVertexes = tess.numVertexes;
for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) {
normalVec0 = vec_ld(0,(vector float *)normal);
normalVec1 = vec_ld(11,(vector float *)normal);
normalVec0 = vec_perm(normalVec0,normalVec1,normalPerm);
incomingVec0 = vec_madd(normalVec0, lightDirVec, zero);
incomingVec1 = vec_sld(incomingVec0,incomingVec0,4);
incomingVec2 = vec_add(incomingVec0,incomingVec1);
incomingVec1 = vec_sld(incomingVec1,incomingVec1,4);
incomingVec2 = vec_add(incomingVec2,incomingVec1);
incomingVec0 = vec_splat(incomingVec2,0);
incomingVec0 = vec_max(incomingVec0,zero);
normalPerm = vec_lvsl(12,normal);
jVec = vec_madd(incomingVec0, directedLightVec, ambientLightVec);
jVecInt = vec_cts(jVec,0); // RGBx
jVecShort = vec_pack(jVecInt,jVecInt); // RGBxRGBx
jVecChar = vec_packsu(jVecShort,jVecShort); // RGBxRGBxRGBxRGBx
jVecChar = vec_sel(jVecChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255
vec_ste((vector unsigned int)jVecChar,0,(unsigned int *)&colors[i*4]); // store color
}
}
void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp)
{
short *oldXyz, *newXyz, *oldNormals, *newNormals;
float *outXyz, *outNormal;
float oldXyzScale QALIGN(16);
float newXyzScale QALIGN(16);
float oldNormalScale QALIGN(16);
float newNormalScale QALIGN(16);
int vertNum;
unsigned lat, lng;
int numVerts;
outXyz = tess.xyz[tess.numVertexes];
outNormal = tess.normal[tess.numVertexes];
newXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
+ (backEnd.currentEntity->e.frame * surf->numVerts * 4);
newNormals = newXyz + 3;
newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp);
newNormalScale = 1.0 - backlerp;
numVerts = surf->numVerts;
if ( backlerp == 0 ) {
vector signed short newNormalsVec0;
vector signed short newNormalsVec1;
vector signed int newNormalsIntVec;
vector float newNormalsFloatVec;
vector float newXyzScaleVec;
vector unsigned char newNormalsLoadPermute;
vector unsigned char newNormalsStorePermute;
vector float zero;
newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec);
newXyzScaleVec = *(vector float *)&newXyzScale;
newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute);
newXyzScaleVec = vec_splat(newXyzScaleVec,0);
newNormalsLoadPermute = vec_lvsl(0,newXyz);
newNormalsStorePermute = vec_lvsr(0,outXyz);
zero = (vector float)vec_splat_s8(0);
//
// just copy the vertexes
//
for (vertNum=0 ; vertNum < numVerts ; vertNum++,
newXyz += 4, newNormals += 4,
outXyz += 4, outNormal += 4)
{
newNormalsLoadPermute = vec_lvsl(0,newXyz);
newNormalsStorePermute = vec_lvsr(0,outXyz);
newNormalsVec0 = vec_ld(0,newXyz);
newNormalsVec1 = vec_ld(16,newXyz);
newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute);
newNormalsIntVec = vec_unpackh(newNormalsVec0);
newNormalsFloatVec = vec_ctf(newNormalsIntVec,0);
newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero);
newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute);
//outXyz[0] = newXyz[0] * newXyzScale;
//outXyz[1] = newXyz[1] * newXyzScale;
//outXyz[2] = newXyz[2] * newXyzScale;
lat = ( newNormals[0] >> 8 ) & 0xff;
lng = ( newNormals[0] & 0xff );
lat *= (FUNCTABLE_SIZE/256);
lng *= (FUNCTABLE_SIZE/256);
// decode X as cos( lat ) * sin( long )
// decode Y as sin( lat ) * sin( long )
// decode Z as cos( long )
outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
vec_ste(newNormalsFloatVec,0,outXyz);
vec_ste(newNormalsFloatVec,4,outXyz);
vec_ste(newNormalsFloatVec,8,outXyz);
}
} else {
//
// interpolate and copy the vertex and normal
//
oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals)
+ (backEnd.currentEntity->e.oldframe * surf->numVerts * 4);
oldNormals = oldXyz + 3;
oldXyzScale = MD3_XYZ_SCALE * backlerp;
oldNormalScale = backlerp;
for (vertNum=0 ; vertNum < numVerts ; vertNum++,
oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4,
outXyz += 4, outNormal += 4)
{
vec3_t uncompressedOldNormal, uncompressedNewNormal;
// interpolate the xyz
outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale;
outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale;
outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale;
// FIXME: interpolate lat/long instead?
lat = ( newNormals[0] >> 8 ) & 0xff;
lng = ( newNormals[0] & 0xff );
lat *= 4;
lng *= 4;
uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
lat = ( oldNormals[0] >> 8 ) & 0xff;
lng = ( oldNormals[0] & 0xff );
lat *= 4;
lng *= 4;
uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng];
uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale;
outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale;
outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale;
// VectorNormalize (outNormal);
}
VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts);
}
}
#endif

View file

@ -35,7 +35,6 @@ frame.
// copied and adapted from tr_mesh.c // copied and adapted from tr_mesh.c
#if 0
/* /*
============= =============
@ -189,13 +188,11 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
int lodnum = 0; int lodnum = 0;
int fogNum = 0; int fogNum = 0;
int cull; int cull;
int cubemapIndex;
qboolean personalModel; qboolean personalModel;
header = (mdrHeader_t *) tr.currentModel->modelData; header = (mdrHeader_t *) tr.currentModel->modelData;
personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !(tr.viewParms.isPortal personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
|| (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW)));
if ( ent->e.renderfx & RF_WRAP_FRAMES ) if ( ent->e.renderfx & RF_WRAP_FRAMES )
{ {
@ -252,8 +249,6 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
// fogNum? // fogNum?
fogNum = R_MDRComputeFogNum( header, ent ); fogNum = R_MDRComputeFogNum( header, ent );
cubemapIndex = R_CubemapForPoint(ent->e.origin);
surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces ); surface = (mdrSurface_t *)( (byte *)lod + lod->ofsSurfaces );
for ( i = 0 ; i < lod->numSurfaces ; i++ ) for ( i = 0 ; i < lod->numSurfaces ; i++ )
@ -268,9 +263,9 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
for(j = 0; j < skin->numSurfaces; j++) for(j = 0; j < skin->numSurfaces; j++)
{ {
if (!strcmp(skin->surfaces[j]->name, surface->name)) if (!strcmp(skin->surfaces[j].name, surface->name))
{ {
shader = skin->surfaces[j]->shader; shader = skin->surfaces[j].shader;
break; break;
} }
} }
@ -289,7 +284,7 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
&& !(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, qfalse, qfalse, 0 ); R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse );
} }
// projection shadows work fine with personal models // projection shadows work fine with personal models
@ -298,11 +293,11 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) {
&& (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, qfalse, qfalse, 0 ); R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
} }
if (!personalModel) if (!personalModel)
R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse, cubemapIndex ); R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse );
surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd ); surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
} }
@ -413,7 +408,9 @@ void RB_MDRSurfaceAnim( mdrSurface_t *surface )
tess.xyz[baseVertex + j][1] = tempVert[1]; tess.xyz[baseVertex + j][1] = tempVert[1];
tess.xyz[baseVertex + j][2] = tempVert[2]; tess.xyz[baseVertex + j][2] = tempVert[2];
R_VaoPackNormal((byte *)&tess.normal[baseVertex + j], tempNormal); tess.normal[baseVertex + j][0] = tempNormal[0];
tess.normal[baseVertex + j][1] = tempNormal[1];
tess.normal[baseVertex + j][2] = tempNormal[2];
tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; tess.texCoords[baseVertex + j][0][0] = v->texCoords[0];
tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; tess.texCoords[baseVertex + j][0][1] = v->texCoords[1];
@ -522,5 +519,3 @@ void MC_UnCompress(float mat[3][4],const unsigned char * comp)
val-=1<<(MC_BITS_VECT-1); val-=1<<(MC_BITS_VECT-1);
mat[2][2]=((float)(val))*MC_SCALE_VECT; mat[2][2]=((float)(val))*MC_SCALE_VECT;
} }
#endif

File diff suppressed because it is too large Load diff

1870
code/renderergl1/tr_bsp.c Normal file

File diff suppressed because it is too large Load diff

514
code/renderergl1/tr_cmds.c Normal file
View file

@ -0,0 +1,514 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
/*
=====================
R_PerformanceCounters
=====================
*/
void R_PerformanceCounters( void ) {
if ( !r_speeds->integer ) {
// clear the counters even if we aren't printing
Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
return;
}
if (r_speeds->integer == 1) {
ri.Printf (PRINT_ALL, "%i/%i shaders/surfs %i leafs %i verts %i/%i tris %.2f mtex %.2f dc\n",
backEnd.pc.c_shaders, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes,
backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3,
R_SumOfUsedImages()/(1000000.0f), backEnd.pc.c_overDraw / (float)(glConfig.vidWidth * glConfig.vidHeight) );
} else if (r_speeds->integer == 2) {
ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out,
tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out );
ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out,
tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out );
} else if (r_speeds->integer == 3) {
ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster );
} else if (r_speeds->integer == 4) {
if ( backEnd.pc.c_dlightVertexes ) {
ri.Printf (PRINT_ALL, "dlight srf:%i culled:%i verts:%i tris:%i\n",
tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled,
backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 );
}
}
else if (r_speeds->integer == 5 )
{
ri.Printf( PRINT_ALL, "zFar: %.0f\n", tr.viewParms.zFar );
}
else if (r_speeds->integer == 6 )
{
ri.Printf( PRINT_ALL, "flare adds:%i tests:%i renders:%i\n",
backEnd.pc.c_flareAdds, backEnd.pc.c_flareTests, backEnd.pc.c_flareRenders );
}
Com_Memset( &tr.pc, 0, sizeof( tr.pc ) );
Com_Memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
}
/*
====================
R_IssueRenderCommands
====================
*/
void R_IssueRenderCommands( qboolean runPerformanceCounters ) {
renderCommandList_t *cmdList;
cmdList = &backEndData->commands;
assert(cmdList);
// add an end-of-list command
*(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST;
// clear it out, in case this is a sync and not a buffer flip
cmdList->used = 0;
if ( runPerformanceCounters ) {
R_PerformanceCounters();
}
// actually start the commands going
if ( !r_skipBackEnd->integer ) {
// let it start on the new batch
RB_ExecuteRenderCommands( cmdList->cmds );
}
}
/*
====================
R_IssuePendingRenderCommands
Issue any pending commands and wait for them to complete.
====================
*/
void R_IssuePendingRenderCommands( void ) {
if ( !tr.registered ) {
return;
}
R_IssueRenderCommands( qfalse );
}
/*
============
R_GetCommandBufferReserved
make sure there is enough command space
============
*/
void *R_GetCommandBufferReserved( int bytes, int reservedBytes ) {
renderCommandList_t *cmdList;
cmdList = &backEndData->commands;
bytes = PAD(bytes, sizeof(void *));
// always leave room for the end of list command
if ( cmdList->used + bytes + sizeof( int ) + reservedBytes > MAX_RENDER_COMMANDS ) {
if ( bytes > MAX_RENDER_COMMANDS - sizeof( int ) ) {
ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
}
// if we run out of room, just start dropping commands
return NULL;
}
cmdList->used += bytes;
return cmdList->cmds + cmdList->used - bytes;
}
/*
=============
R_GetCommandBuffer
returns NULL if there is not enough space for important commands
=============
*/
void *R_GetCommandBuffer( int bytes ) {
return R_GetCommandBufferReserved( bytes, PAD( sizeof( swapBuffersCommand_t ), sizeof(void *) ) );
}
/*
=============
R_AddDrawSurfCmd
=============
*/
void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ) {
drawSurfsCommand_t *cmd;
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_DRAW_SURFS;
cmd->drawSurfs = drawSurfs;
cmd->numDrawSurfs = numDrawSurfs;
cmd->refdef = tr.refdef;
cmd->viewParms = tr.viewParms;
}
/*
=============
RE_SetColor
Passing NULL will set the color to white
=============
*/
void RE_SetColor( const float *rgba ) {
setColorCommand_t *cmd;
if ( !tr.registered ) {
return;
}
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_SET_COLOR;
if ( !rgba ) {
static float colorWhite[4] = { 1, 1, 1, 1 };
rgba = colorWhite;
}
cmd->color[0] = rgba[0];
cmd->color[1] = rgba[1];
cmd->color[2] = rgba[2];
cmd->color[3] = rgba[3];
}
/*
=============
RE_StretchPic
=============
*/
void RE_StretchPic ( float x, float y, float w, float h,
float s1, float t1, float s2, float t2, qhandle_t hShader ) {
stretchPicCommand_t *cmd;
if (!tr.registered) {
return;
}
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_STRETCH_PIC;
cmd->shader = R_GetShaderByHandle( hShader );
cmd->x = x;
cmd->y = y;
cmd->w = w;
cmd->h = h;
cmd->s1 = s1;
cmd->t1 = t1;
cmd->s2 = s2;
cmd->t2 = t2;
}
#define MODE_RED_CYAN 1
#define MODE_RED_BLUE 2
#define MODE_RED_GREEN 3
#define MODE_GREEN_MAGENTA 4
#define MODE_MAX MODE_GREEN_MAGENTA
void R_SetColorMode(GLboolean *rgba, stereoFrame_t stereoFrame, int colormode)
{
rgba[0] = rgba[1] = rgba[2] = rgba[3] = GL_TRUE;
if(colormode > MODE_MAX)
{
if(stereoFrame == STEREO_LEFT)
stereoFrame = STEREO_RIGHT;
else if(stereoFrame == STEREO_RIGHT)
stereoFrame = STEREO_LEFT;
colormode -= MODE_MAX;
}
if(colormode == MODE_GREEN_MAGENTA)
{
if(stereoFrame == STEREO_LEFT)
rgba[0] = rgba[2] = GL_FALSE;
else if(stereoFrame == STEREO_RIGHT)
rgba[1] = GL_FALSE;
}
else
{
if(stereoFrame == STEREO_LEFT)
rgba[1] = rgba[2] = GL_FALSE;
else if(stereoFrame == STEREO_RIGHT)
{
rgba[0] = GL_FALSE;
if(colormode == MODE_RED_BLUE)
rgba[1] = GL_FALSE;
else if(colormode == MODE_RED_GREEN)
rgba[2] = GL_FALSE;
}
}
}
/*
====================
RE_BeginFrame
If running in stereo, RE_BeginFrame will be called twice
for each RE_EndFrame
====================
*/
void RE_BeginFrame( stereoFrame_t stereoFrame ) {
drawBufferCommand_t *cmd = NULL;
colorMaskCommand_t *colcmd = NULL;
if ( !tr.registered ) {
return;
}
glState.finishCalled = qfalse;
tr.frameCount++;
tr.frameSceneNum = 0;
//
// do overdraw measurement
//
if ( r_measureOverdraw->integer )
{
if ( glConfig.stencilBits < 4 )
{
ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits );
ri.Cvar_Set( "r_measureOverdraw", "0" );
r_measureOverdraw->modified = qfalse;
}
else if ( r_shadows->integer == 2 )
{
ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" );
ri.Cvar_Set( "r_measureOverdraw", "0" );
r_measureOverdraw->modified = qfalse;
}
else
{
R_IssuePendingRenderCommands();
qglEnable( GL_STENCIL_TEST );
qglStencilMask( ~0U );
qglClearStencil( 0U );
qglStencilFunc( GL_ALWAYS, 0U, ~0U );
qglStencilOp( GL_KEEP, GL_INCR, GL_INCR );
}
r_measureOverdraw->modified = qfalse;
}
else
{
// this is only reached if it was on and is now off
if ( r_measureOverdraw->modified ) {
R_IssuePendingRenderCommands();
qglDisable( GL_STENCIL_TEST );
}
r_measureOverdraw->modified = qfalse;
}
//
// texturemode stuff
//
if ( r_textureMode->modified ) {
R_IssuePendingRenderCommands();
GL_TextureMode( r_textureMode->string );
r_textureMode->modified = qfalse;
}
//
// gamma stuff
//
if ( r_gamma->modified ) {
r_gamma->modified = qfalse;
R_IssuePendingRenderCommands();
R_SetColorMappings();
}
// check for errors
if ( !r_ignoreGLErrors->integer )
{
int err;
R_IssuePendingRenderCommands();
if ((err = qglGetError()) != GL_NO_ERROR)
ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err);
}
if (glConfig.stereoEnabled) {
if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
return;
cmd->commandId = RC_DRAW_BUFFER;
if ( stereoFrame == STEREO_LEFT ) {
cmd->buffer = (int)GL_BACK_LEFT;
} else if ( stereoFrame == STEREO_RIGHT ) {
cmd->buffer = (int)GL_BACK_RIGHT;
} else {
ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
}
}
else
{
if(r_anaglyphMode->integer)
{
if(r_anaglyphMode->modified)
{
// clear both, front and backbuffer.
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
qglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
qglDrawBuffer(GL_FRONT);
qglClear(GL_COLOR_BUFFER_BIT);
qglDrawBuffer(GL_BACK);
qglClear(GL_COLOR_BUFFER_BIT);
r_anaglyphMode->modified = qfalse;
}
if(stereoFrame == STEREO_LEFT)
{
if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
return;
if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
return;
}
else if(stereoFrame == STEREO_RIGHT)
{
clearDepthCommand_t *cldcmd;
if( !(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))) )
return;
cldcmd->commandId = RC_CLEARDEPTH;
if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) )
return;
}
else
ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame );
R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer);
colcmd->commandId = RC_COLORMASK;
}
else
{
if(stereoFrame != STEREO_CENTER)
ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame );
if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) )
return;
}
if(cmd)
{
cmd->commandId = RC_DRAW_BUFFER;
if(r_anaglyphMode->modified)
{
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
r_anaglyphMode->modified = qfalse;
}
if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT"))
cmd->buffer = (int)GL_FRONT;
else
cmd->buffer = (int)GL_BACK;
}
}
tr.refdef.stereoFrame = stereoFrame;
}
/*
=============
RE_EndFrame
Returns the number of msec spent in the back end
=============
*/
void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
swapBuffersCommand_t *cmd;
if ( !tr.registered ) {
return;
}
cmd = R_GetCommandBufferReserved( sizeof( *cmd ), 0 );
if ( !cmd ) {
return;
}
cmd->commandId = RC_SWAP_BUFFERS;
R_IssueRenderCommands( qtrue );
R_InitNextFrame();
if ( frontEndMsec ) {
*frontEndMsec = tr.frontEndMsec;
}
tr.frontEndMsec = 0;
if ( backEndMsec ) {
*backEndMsec = backEnd.pc.msec;
}
backEnd.pc.msec = 0;
}
/*
=============
RE_TakeVideoFrame
=============
*/
void RE_TakeVideoFrame( int width, int height,
byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg )
{
videoFrameCommand_t *cmd;
if( !tr.registered ) {
return;
}
cmd = R_GetCommandBuffer( sizeof( *cmd ) );
if( !cmd ) {
return;
}
cmd->commandId = RC_VIDEOFRAME;
cmd->width = width;
cmd->height = height;
cmd->captureBuffer = captureBuffer;
cmd->encodeBuffer = encodeBuffer;
cmd->motionJpeg = motionJpeg;
}

625
code/renderergl1/tr_curve.c Normal file
View file

@ -0,0 +1,625 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
/*
This file does all of the processing necessary to turn a raw grid of points
read from the map file into a srfGridMesh_t ready for rendering.
The level of detail solution is direction independent, based only on subdivided
distance from the true curve.
Only a single entry point:
srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
*/
/*
============
LerpDrawVert
============
*/
static void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out ) {
out->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]);
out->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]);
out->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]);
out->st[0] = 0.5f * (a->st[0] + b->st[0]);
out->st[1] = 0.5f * (a->st[1] + b->st[1]);
out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]);
out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]);
out->color[0] = (a->color[0] + b->color[0]) >> 1;
out->color[1] = (a->color[1] + b->color[1]) >> 1;
out->color[2] = (a->color[2] + b->color[2]) >> 1;
out->color[3] = (a->color[3] + b->color[3]) >> 1;
}
/*
============
Transpose
============
*/
static void Transpose( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
int i, j;
drawVert_t temp;
if ( width > height ) {
for ( i = 0 ; i < height ; i++ ) {
for ( j = i + 1 ; j < width ; j++ ) {
if ( j < height ) {
// swap the value
temp = ctrl[j][i];
ctrl[j][i] = ctrl[i][j];
ctrl[i][j] = temp;
} else {
// just copy
ctrl[j][i] = ctrl[i][j];
}
}
}
} else {
for ( i = 0 ; i < width ; i++ ) {
for ( j = i + 1 ; j < height ; j++ ) {
if ( j < width ) {
// swap the value
temp = ctrl[i][j];
ctrl[i][j] = ctrl[j][i];
ctrl[j][i] = temp;
} else {
// just copy
ctrl[i][j] = ctrl[j][i];
}
}
}
}
}
/*
=================
MakeMeshNormals
Handles all the complicated wrapping and degenerate cases
=================
*/
static void MakeMeshNormals( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
int i, j, k, dist;
vec3_t normal;
vec3_t sum;
int count = 0;
vec3_t base;
vec3_t delta;
int x, y;
drawVert_t *dv;
vec3_t around[8], temp;
qboolean good[8];
qboolean wrapWidth, wrapHeight;
float len;
static int neighbors[8][2] = {
{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
};
wrapWidth = qfalse;
for ( i = 0 ; i < height ; i++ ) {
VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta );
len = VectorLengthSquared( delta );
if ( len > 1.0 ) {
break;
}
}
if ( i == height ) {
wrapWidth = qtrue;
}
wrapHeight = qfalse;
for ( i = 0 ; i < width ; i++ ) {
VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta );
len = VectorLengthSquared( delta );
if ( len > 1.0 ) {
break;
}
}
if ( i == width) {
wrapHeight = qtrue;
}
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
count = 0;
dv = &ctrl[j][i];
VectorCopy( dv->xyz, base );
for ( k = 0 ; k < 8 ; k++ ) {
VectorClear( around[k] );
good[k] = qfalse;
for ( dist = 1 ; dist <= 3 ; dist++ ) {
x = i + neighbors[k][0] * dist;
y = j + neighbors[k][1] * dist;
if ( wrapWidth ) {
if ( x < 0 ) {
x = width - 1 + x;
} else if ( x >= width ) {
x = 1 + x - width;
}
}
if ( wrapHeight ) {
if ( y < 0 ) {
y = height - 1 + y;
} else if ( y >= height ) {
y = 1 + y - height;
}
}
if ( x < 0 || x >= width || y < 0 || y >= height ) {
break; // edge of patch
}
VectorSubtract( ctrl[y][x].xyz, base, temp );
if ( VectorNormalize( temp ) < 0.001f ) {
continue; // degenerate edge, get more dist
} else {
good[k] = qtrue;
VectorCopy( temp, around[k] );
break; // good edge
}
}
}
VectorClear( sum );
for ( k = 0 ; k < 8 ; k++ ) {
if ( !good[k] || !good[(k+1)&7] ) {
continue; // didn't get two points
}
CrossProduct( around[(k+1)&7], around[k], normal );
if ( VectorNormalize( normal ) < 0.001f ) {
continue;
}
VectorAdd( normal, sum, sum );
count++;
}
//if ( count == 0 ) {
// printf("bad normal\n");
//}
VectorNormalize2( sum, dv->normal );
}
}
}
/*
============
InvertCtrl
============
*/
static void InvertCtrl( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
int i, j;
drawVert_t temp;
for ( i = 0 ; i < height ; i++ ) {
for ( j = 0 ; j < width/2 ; j++ ) {
temp = ctrl[i][j];
ctrl[i][j] = ctrl[i][width-1-j];
ctrl[i][width-1-j] = temp;
}
}
}
/*
=================
InvertErrorTable
=================
*/
static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) {
int i;
float copy[2][MAX_GRID_SIZE];
Com_Memcpy( copy, errorTable, sizeof( copy ) );
for ( i = 0 ; i < width ; i++ ) {
errorTable[1][i] = copy[0][i]; //[width-1-i];
}
for ( i = 0 ; i < height ; i++ ) {
errorTable[0][i] = copy[1][height-1-i];
}
}
/*
==================
PutPointsOnCurve
==================
*/
static void PutPointsOnCurve( drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
int width, int height ) {
int i, j;
drawVert_t prev, next;
for ( i = 0 ; i < width ; i++ ) {
for ( j = 1 ; j < height ; j += 2 ) {
LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev );
LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next );
LerpDrawVert( &prev, &next, &ctrl[j][i] );
}
}
for ( j = 0 ; j < height ; j++ ) {
for ( i = 1 ; i < width ; i += 2 ) {
LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev );
LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next );
LerpDrawVert( &prev, &next, &ctrl[j][i] );
}
}
}
/*
=================
R_CreateSurfaceGridMesh
=================
*/
srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height,
drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE] ) {
int i, j, size;
drawVert_t *vert;
vec3_t tmpVec;
srfGridMesh_t *grid;
// copy the results out to a grid
size = (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid );
#ifdef PATCH_STITCHING
grid = /*ri.Hunk_Alloc*/ ri.Malloc( size );
Com_Memset(grid, 0, size);
grid->widthLodError = /*ri.Hunk_Alloc*/ ri.Malloc( width * 4 );
Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
grid->heightLodError = /*ri.Hunk_Alloc*/ ri.Malloc( height * 4 );
Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
#else
grid = ri.Hunk_Alloc( size );
Com_Memset(grid, 0, size);
grid->widthLodError = ri.Hunk_Alloc( width * 4 );
Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
grid->heightLodError = ri.Hunk_Alloc( height * 4 );
Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 );
#endif
grid->width = width;
grid->height = height;
grid->surfaceType = SF_GRID;
ClearBounds( grid->meshBounds[0], grid->meshBounds[1] );
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
vert = &grid->verts[j*width+i];
*vert = ctrl[j][i];
AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] );
}
}
// compute local origin and bounds
VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin );
VectorScale( grid->localOrigin, 0.5f, grid->localOrigin );
VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec );
grid->meshRadius = VectorLength( tmpVec );
VectorCopy( grid->localOrigin, grid->lodOrigin );
grid->lodRadius = grid->meshRadius;
//
return grid;
}
/*
=================
R_FreeSurfaceGridMesh
=================
*/
void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) {
ri.Free(grid->widthLodError);
ri.Free(grid->heightLodError);
ri.Free(grid);
}
/*
=================
R_SubdividePatchToGrid
=================
*/
srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
int i, j, k, l;
drawVert_t_cleared( prev );
drawVert_t_cleared( next );
drawVert_t_cleared( mid );
float len, maxLen;
int dir;
int t;
drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
float errorTable[2][MAX_GRID_SIZE];
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
ctrl[j][i] = points[j*width+i];
}
}
for ( dir = 0 ; dir < 2 ; dir++ ) {
for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) {
errorTable[dir][j] = 0;
}
// horizontal subdivisions
for ( j = 0 ; j + 2 < width ; j += 2 ) {
// check subdivided midpoints against control points
// FIXME: also check midpoints of adjacent patches against the control points
// this would basically stitch all patches in the same LOD group together.
maxLen = 0;
for ( i = 0 ; i < height ; i++ ) {
vec3_t midxyz;
vec3_t midxyz2;
vec3_t dir;
vec3_t projected;
float d;
// calculate the point on the curve
for ( l = 0 ; l < 3 ; l++ ) {
midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2
+ ctrl[i][j+2].xyz[l] ) * 0.25f;
}
// see how far off the line it is
// using dist-from-line will not account for internal
// texture warping, but it gives a lot less polygons than
// dist-from-midpoint
VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz );
VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir );
VectorNormalize( dir );
d = DotProduct( midxyz, dir );
VectorScale( dir, d, projected );
VectorSubtract( midxyz, projected, midxyz2);
len = VectorLengthSquared( midxyz2 ); // we will do the sqrt later
if ( len > maxLen ) {
maxLen = len;
}
}
maxLen = sqrt(maxLen);
// if all the points are on the lines, remove the entire columns
if ( maxLen < 0.1f ) {
errorTable[dir][j+1] = 999;
continue;
}
// see if we want to insert subdivided columns
if ( width + 2 > MAX_GRID_SIZE ) {
errorTable[dir][j+1] = 1.0f/maxLen;
continue; // can't subdivide any more
}
if ( maxLen <= r_subdivisions->value ) {
errorTable[dir][j+1] = 1.0f/maxLen;
continue; // didn't need subdivision
}
errorTable[dir][j+2] = 1.0f/maxLen;
// insert two columns and replace the peak
width += 2;
for ( i = 0 ; i < height ; i++ ) {
LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev );
LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next );
LerpDrawVert( &prev, &next, &mid );
for ( k = width - 1 ; k > j + 3 ; k-- ) {
ctrl[i][k] = ctrl[i][k-2];
}
ctrl[i][j + 1] = prev;
ctrl[i][j + 2] = mid;
ctrl[i][j + 3] = next;
}
// back up and recheck this set again, it may need more subdivision
j -= 2;
}
Transpose( width, height, ctrl );
t = width;
width = height;
height = t;
}
// put all the aproximating points on the curve
PutPointsOnCurve( ctrl, width, height );
// cull out any rows or columns that are colinear
for ( i = 1 ; i < width-1 ; i++ ) {
if ( errorTable[0][i] != 999 ) {
continue;
}
for ( j = i+1 ; j < width ; j++ ) {
for ( k = 0 ; k < height ; k++ ) {
ctrl[k][j-1] = ctrl[k][j];
}
errorTable[0][j-1] = errorTable[0][j];
}
width--;
}
for ( i = 1 ; i < height-1 ; i++ ) {
if ( errorTable[1][i] != 999 ) {
continue;
}
for ( j = i+1 ; j < height ; j++ ) {
for ( k = 0 ; k < width ; k++ ) {
ctrl[j-1][k] = ctrl[j][k];
}
errorTable[1][j-1] = errorTable[1][j];
}
height--;
}
#if 1
// flip for longest tristrips as an optimization
// the results should be visually identical with or
// without this step
if ( height > width ) {
Transpose( width, height, ctrl );
InvertErrorTable( errorTable, width, height );
t = width;
width = height;
height = t;
InvertCtrl( width, height, ctrl );
}
#endif
// calculate normals
MakeMeshNormals( width, height, ctrl );
return R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
}
/*
===============
R_GridInsertColumn
===============
*/
srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ) {
int i, j;
int width, height, oldwidth;
drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
float errorTable[2][MAX_GRID_SIZE];
float lodRadius;
vec3_t lodOrigin;
oldwidth = 0;
width = grid->width + 1;
if (width > MAX_GRID_SIZE)
return NULL;
height = grid->height;
for (i = 0; i < width; i++) {
if (i == column) {
//insert new column
for (j = 0; j < grid->height; j++) {
LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] );
if (j == row)
VectorCopy(point, ctrl[j][i].xyz);
}
errorTable[0][i] = loderror;
continue;
}
errorTable[0][i] = grid->widthLodError[oldwidth];
for (j = 0; j < grid->height; j++) {
ctrl[j][i] = grid->verts[j * grid->width + oldwidth];
}
oldwidth++;
}
for (j = 0; j < grid->height; j++) {
errorTable[1][j] = grid->heightLodError[j];
}
// put all the aproximating points on the curve
//PutPointsOnCurve( ctrl, width, height );
// calculate normals
MakeMeshNormals( width, height, ctrl );
VectorCopy(grid->lodOrigin, lodOrigin);
lodRadius = grid->lodRadius;
// free the old grid
R_FreeSurfaceGridMesh(grid);
// create a new grid
grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
grid->lodRadius = lodRadius;
VectorCopy(lodOrigin, grid->lodOrigin);
return grid;
}
/*
===============
R_GridInsertRow
===============
*/
srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) {
int i, j;
int width, height, oldheight;
drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
float errorTable[2][MAX_GRID_SIZE];
float lodRadius;
vec3_t lodOrigin;
oldheight = 0;
width = grid->width;
height = grid->height + 1;
if (height > MAX_GRID_SIZE)
return NULL;
for (i = 0; i < height; i++) {
if (i == row) {
//insert new row
for (j = 0; j < grid->width; j++) {
LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] );
if (j == column)
VectorCopy(point, ctrl[i][j].xyz);
}
errorTable[1][i] = loderror;
continue;
}
errorTable[1][i] = grid->heightLodError[oldheight];
for (j = 0; j < grid->width; j++) {
ctrl[i][j] = grid->verts[oldheight * grid->width + j];
}
oldheight++;
}
for (j = 0; j < grid->width; j++) {
errorTable[0][j] = grid->widthLodError[j];
}
// put all the aproximating points on the curve
//PutPointsOnCurve( ctrl, width, height );
// calculate normals
MakeMeshNormals( width, height, ctrl );
VectorCopy(grid->lodOrigin, lodOrigin);
lodRadius = grid->lodRadius;
// free the old grid
R_FreeSurfaceGridMesh(grid);
// create a new grid
grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
grid->lodRadius = lodRadius;
VectorCopy(lodOrigin, grid->lodOrigin);
return grid;
}

View file

@ -0,0 +1,539 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_flares.c
#include "tr_local.h"
/*
=============================================================================
LIGHT FLARES
A light flare is an effect that takes place inside the eye when bright light
sources are visible. The size of the flare relative to the screen is nearly
constant, irrespective of distance, but the intensity should be proportional to the
projected area of the light source.
A surface that has been flagged as having a light flare will calculate the depth
buffer value that its midpoint should have when the surface is added.
After all opaque surfaces have been rendered, the depth buffer is read back for
each flare in view. If the point has not been obscured by a closer surface, the
flare should be drawn.
Surfaces that have a repeated texture should never be flagged as flaring, because
there will only be a single flare added at the midpoint of the polygon.
To prevent abrupt popping, the intensity of the flare is interpolated up and
down as it changes visibility. This involves scene to scene state, unlike almost
all other aspects of the renderer, and is complicated by the fact that a single
frame may have multiple scenes.
RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially
up to five or more times in a frame with 3D status bar icons).
=============================================================================
*/
// flare states maintain visibility over multiple frames for fading
// layers: view, mirror, menu
typedef struct flare_s {
struct flare_s *next; // for active chain
int addedFrame;
qboolean inPortal; // true if in a portal view of the scene
int frameSceneNum;
void *surface;
int fogNum;
int fadeTime;
qboolean visible; // state of last test
float drawIntensity; // may be non 0 even if !visible due to fading
int windowX, windowY;
float eyeZ;
vec3_t origin;
vec3_t color;
} flare_t;
#define MAX_FLARES 256
flare_t r_flareStructs[MAX_FLARES];
flare_t *r_activeFlares, *r_inactiveFlares;
int flareCoeff;
/*
==================
R_SetFlareCoeff
==================
*/
static void R_SetFlareCoeff( void ) {
if(r_flareCoeff->value == 0.0f)
flareCoeff = atof(FLARE_STDCOEFF);
else
flareCoeff = r_flareCoeff->value;
}
/*
==================
R_ClearFlares
==================
*/
void R_ClearFlares( void ) {
int i;
Com_Memset( r_flareStructs, 0, sizeof( r_flareStructs ) );
r_activeFlares = NULL;
r_inactiveFlares = NULL;
for ( i = 0 ; i < MAX_FLARES ; i++ ) {
r_flareStructs[i].next = r_inactiveFlares;
r_inactiveFlares = &r_flareStructs[i];
}
R_SetFlareCoeff();
}
/*
==================
RB_AddFlare
This is called at surface tesselation time
==================
*/
void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) {
int i;
flare_t *f;
vec3_t local;
float d = 1;
vec4_t eye, clip, normalized, window;
backEnd.pc.c_flareAdds++;
if(normal && (normal[0] || normal[1] || normal[2]))
{
VectorSubtract( backEnd.viewParms.or.origin, point, local );
VectorNormalizeFast(local);
d = DotProduct(local, normal);
// If the viewer is behind the flare don't add it.
if(d < 0)
return;
}
// if the point is off the screen, don't bother adding it
// calculate screen coordinates and depth
R_TransformModelToClip( point, backEnd.or.modelMatrix,
backEnd.viewParms.projectionMatrix, eye, clip );
// check to see if the point is completely off screen
for ( i = 0 ; i < 3 ; i++ ) {
if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) {
return;
}
}
R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window );
if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth
|| window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) {
return; // shouldn't happen, since we check the clip[] above, except for FP rounding
}
// see if a flare with a matching surface, scene, and view exists
for ( f = r_activeFlares ; f ; f = f->next ) {
if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum
&& f->inPortal == backEnd.viewParms.isPortal ) {
break;
}
}
// allocate a new one
if (!f ) {
if ( !r_inactiveFlares ) {
// the list is completely full
return;
}
f = r_inactiveFlares;
r_inactiveFlares = r_inactiveFlares->next;
f->next = r_activeFlares;
r_activeFlares = f;
f->surface = surface;
f->frameSceneNum = backEnd.viewParms.frameSceneNum;
f->inPortal = backEnd.viewParms.isPortal;
f->addedFrame = -1;
}
if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) {
f->visible = qfalse;
f->fadeTime = backEnd.refdef.time - 2000;
}
f->addedFrame = backEnd.viewParms.frameCount;
f->fogNum = fogNum;
VectorCopy(point, f->origin);
VectorCopy( color, f->color );
// fade the intensity of the flare down as the
// light surface turns away from the viewer
VectorScale( f->color, d, f->color );
// save info needed to test
f->windowX = backEnd.viewParms.viewportX + window[0];
f->windowY = backEnd.viewParms.viewportY + window[1];
f->eyeZ = eye[2];
}
/*
==================
RB_AddDlightFlares
==================
*/
void RB_AddDlightFlares( void ) {
dlight_t *l;
int i, j, k;
fog_t *fog = NULL;
if ( !r_flares->integer ) {
return;
}
l = backEnd.refdef.dlights;
if(tr.world)
fog = tr.world->fogs;
for (i=0 ; i<backEnd.refdef.num_dlights ; i++, l++) {
if(fog)
{
// find which fog volume the light is in
for ( j = 1 ; j < tr.world->numfogs ; j++ ) {
fog = &tr.world->fogs[j];
for ( k = 0 ; k < 3 ; k++ ) {
if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) {
break;
}
}
if ( k == 3 ) {
break;
}
}
if ( j == tr.world->numfogs ) {
j = 0;
}
}
else
j = 0;
RB_AddFlare( (void *)l, j, l->origin, l->color, NULL );
}
}
/*
===============================================================================
FLARE BACK END
===============================================================================
*/
/*
==================
RB_TestFlare
==================
*/
void RB_TestFlare( flare_t *f ) {
float depth;
qboolean visible;
float fade;
float screenZ;
backEnd.pc.c_flareTests++;
// doing a readpixels is as good as doing a glFinish(), so
// don't bother with another sync
glState.finishCalled = qfalse;
// read back the z buffer contents
qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth );
screenZ = backEnd.viewParms.projectionMatrix[14] /
( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] );
visible = ( -f->eyeZ - -screenZ ) < 24;
if ( visible ) {
if ( !f->visible ) {
f->visible = qtrue;
f->fadeTime = backEnd.refdef.time - 1;
}
fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value;
} else {
if ( f->visible ) {
f->visible = qfalse;
f->fadeTime = backEnd.refdef.time - 1;
}
fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value;
}
if ( fade < 0 ) {
fade = 0;
}
if ( fade > 1 ) {
fade = 1;
}
f->drawIntensity = fade;
}
/*
==================
RB_RenderFlare
==================
*/
void RB_RenderFlare( flare_t *f ) {
float size;
vec3_t color;
int iColor[3];
float distance, intensity, factor;
byte fogFactors[3] = {255, 255, 255};
backEnd.pc.c_flareRenders++;
// We don't want too big values anyways when dividing by distance.
if(f->eyeZ > -1.0f)
distance = 1.0f;
else
distance = -f->eyeZ;
// calculate the flare size..
size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance );
/*
* This is an alternative to intensity scaling. It changes the size of the flare on screen instead
* with growing distance. See in the description at the top why this is not the way to go.
// size will change ~ 1/r.
size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f));
*/
/*
* As flare sizes stay nearly constant with increasing distance we must decrease the intensity
* to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be
* got by considering the ratio of
* (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare)
* An important requirement is:
* intensity <= 1 for all distances.
*
* The formula used here to compute the intensity is as follows:
* intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2
* As you can see, the intensity will have a max. of 1 when the distance is 0.
* The coefficient flareCoeff will determine the falloff speed with increasing distance.
*/
factor = distance + size * sqrt(flareCoeff);
intensity = flareCoeff * size * size / (factor * factor);
VectorScale(f->color, f->drawIntensity * intensity, color);
// Calculations for fogging
if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs)
{
tess.numVertexes = 1;
VectorCopy(f->origin, tess.xyz[0]);
tess.fogNum = f->fogNum;
RB_CalcModulateColorsByFog(fogFactors);
// We don't need to render the flare if colors are 0 anyways.
if(!(fogFactors[0] || fogFactors[1] || fogFactors[2]))
return;
}
iColor[0] = color[0] * fogFactors[0];
iColor[1] = color[1] * fogFactors[1];
iColor[2] = color[2] * fogFactors[2];
RB_BeginSurface( tr.flareShader, f->fogNum );
// FIXME: use quadstamp?
tess.xyz[tess.numVertexes][0] = f->windowX - size;
tess.xyz[tess.numVertexes][1] = f->windowY - size;
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 255;
tess.numVertexes++;
tess.xyz[tess.numVertexes][0] = f->windowX - size;
tess.xyz[tess.numVertexes][1] = f->windowY + size;
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 255;
tess.numVertexes++;
tess.xyz[tess.numVertexes][0] = f->windowX + size;
tess.xyz[tess.numVertexes][1] = f->windowY + size;
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 255;
tess.numVertexes++;
tess.xyz[tess.numVertexes][0] = f->windowX + size;
tess.xyz[tess.numVertexes][1] = f->windowY - size;
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 255;
tess.numVertexes++;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 1;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 3;
RB_EndSurface();
}
/*
==================
RB_RenderFlares
Because flares are simulating an occular effect, they should be drawn after
everything (all views) in the entire frame has been drawn.
Because of the way portals use the depth buffer to mark off areas, the
needed information would be lost after each view, so we are forced to draw
flares after each view.
The resulting artifact is that flares in mirrors or portals don't dim properly
when occluded by something in the main view, and portal flares that should
extend past the portal edge will be overwritten.
==================
*/
void RB_RenderFlares (void) {
flare_t *f;
flare_t **prev;
qboolean draw;
if ( !r_flares->integer ) {
return;
}
if(r_flareCoeff->modified)
{
R_SetFlareCoeff();
r_flareCoeff->modified = qfalse;
}
// Reset currentEntity to world so that any previously referenced entities
// don't have influence on the rendering of these flares (i.e. RF_ renderer flags).
backEnd.currentEntity = &tr.worldEntity;
backEnd.or = backEnd.viewParms.world;
// RB_AddDlightFlares();
// perform z buffer readback on each flare in this view
draw = qfalse;
prev = &r_activeFlares;
while ( ( f = *prev ) != NULL ) {
// throw out any flares that weren't added last frame
if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) {
*prev = f->next;
f->next = r_inactiveFlares;
r_inactiveFlares = f;
continue;
}
// don't draw any here that aren't from this scene / portal
f->drawIntensity = 0;
if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
&& f->inPortal == backEnd.viewParms.isPortal ) {
RB_TestFlare( f );
if ( f->drawIntensity ) {
draw = qtrue;
} else {
// this flare has completely faded out, so remove it from the chain
*prev = f->next;
f->next = r_inactiveFlares;
r_inactiveFlares = f;
continue;
}
}
prev = &f->next;
}
if ( !draw ) {
return; // none visible
}
if ( backEnd.viewParms.isPortal ) {
qglDisable (GL_CLIP_PLANE0);
}
qglPushMatrix();
qglLoadIdentity();
qglMatrixMode( GL_PROJECTION );
qglPushMatrix();
qglLoadIdentity();
qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
-99999, 99999 );
for ( f = r_activeFlares ; f ; f = f->next ) {
if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
&& f->inPortal == backEnd.viewParms.isPortal
&& f->drawIntensity ) {
RB_RenderFlare( f );
}
}
qglPopMatrix();
qglMatrixMode( GL_MODELVIEW );
qglPopMatrix();
}

1673
code/renderergl1/tr_image.c Normal file

File diff suppressed because it is too large Load diff

1388
code/renderergl1/tr_init.c Normal file

File diff suppressed because it is too large Load diff

400
code/renderergl1/tr_light.c Normal file
View file

@ -0,0 +1,400 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_light.c
#include "tr_local.h"
#define DLIGHT_AT_RADIUS 16
// at the edge of a dlight's influence, this amount of light will be added
#define DLIGHT_MINIMUM_RADIUS 16
// never calculate a range less than this to prevent huge light numbers
/*
===============
R_TransformDlights
Transforms the origins of an array of dlights.
Used by both the front end (for DlightBmodel) and
the back end (before doing the lighting calculation)
===============
*/
void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) {
int i;
vec3_t temp;
for ( i = 0 ; i < count ; i++, dl++ ) {
VectorSubtract( dl->origin, or->origin, temp );
dl->transformed[0] = DotProduct( temp, or->axis[0] );
dl->transformed[1] = DotProduct( temp, or->axis[1] );
dl->transformed[2] = DotProduct( temp, or->axis[2] );
}
}
/*
=============
R_DlightBmodel
Determine which dynamic lights may effect this bmodel
=============
*/
void R_DlightBmodel( bmodel_t *bmodel ) {
int i, j;
dlight_t *dl;
int mask;
msurface_t *surf;
// transform all the lights
R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.or );
mask = 0;
for ( i=0 ; i<tr.refdef.num_dlights ; i++ ) {
dl = &tr.refdef.dlights[i];
// see if the point is close enough to the bounds to matter
for ( j = 0 ; j < 3 ; j++ ) {
if ( dl->transformed[j] - bmodel->bounds[1][j] > dl->radius ) {
break;
}
if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) {
break;
}
}
if ( j < 3 ) {
continue;
}
// we need to check this light
mask |= 1 << i;
}
tr.currentEntity->needDlights = (mask != 0);
// set the dlight bits in all the surfaces
for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
surf = bmodel->firstSurface + i;
if ( *surf->data == SF_FACE ) {
((srfSurfaceFace_t *)surf->data)->dlightBits = mask;
} else if ( *surf->data == SF_GRID ) {
((srfGridMesh_t *)surf->data)->dlightBits = mask;
} else if ( *surf->data == SF_TRIANGLES ) {
((srfTriangles_t *)surf->data)->dlightBits = mask;
}
}
}
/*
=============================================================================
LIGHT SAMPLING
=============================================================================
*/
extern cvar_t *r_ambientScale;
extern cvar_t *r_directedScale;
extern cvar_t *r_debugLight;
/*
=================
R_SetupEntityLightingGrid
=================
*/
static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
vec3_t lightOrigin;
int pos[3];
int i, j;
byte *gridData;
float frac[3];
int gridStep[3];
vec3_t direction;
float totalFactor;
if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
// separate lightOrigins are needed so an object that is
// sinking into the ground can still be lit, and so
// multi-part models can be lit identically
VectorCopy( ent->e.lightingOrigin, lightOrigin );
} else {
VectorCopy( ent->e.origin, lightOrigin );
}
VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );
for ( i = 0 ; i < 3 ; i++ ) {
float v;
v = lightOrigin[i]*tr.world->lightGridInverseSize[i];
pos[i] = floor( v );
frac[i] = v - pos[i];
if ( pos[i] < 0 ) {
pos[i] = 0;
} else if ( pos[i] > tr.world->lightGridBounds[i] - 1 ) {
pos[i] = tr.world->lightGridBounds[i] - 1;
}
}
VectorClear( ent->ambientLight );
VectorClear( ent->directedLight );
VectorClear( direction );
assert( tr.world->lightGridData ); // NULL with -nolight maps
// trilerp the light value
gridStep[0] = 8;
gridStep[1] = 8 * tr.world->lightGridBounds[0];
gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
gridData = tr.world->lightGridData + pos[0] * gridStep[0]
+ pos[1] * gridStep[1] + pos[2] * gridStep[2];
totalFactor = 0;
for ( i = 0 ; i < 8 ; i++ ) {
float factor;
byte *data;
int lat, lng;
vec3_t normal;
#if idppc
float d0, d1, d2, d3, d4, d5;
#endif
factor = 1.0;
data = gridData;
for ( j = 0 ; j < 3 ; j++ ) {
if ( i & (1<<j) ) {
if ( pos[j] + 1 > tr.world->lightGridBounds[j] - 1 ) {
break; // ignore values outside lightgrid
}
factor *= frac[j];
data += gridStep[j];
} else {
factor *= (1.0f - frac[j]);
}
}
if ( j != 3 ) {
continue;
}
if ( !(data[0]+data[1]+data[2]) ) {
continue; // ignore samples in walls
}
totalFactor += factor;
#if idppc
d0 = data[0]; d1 = data[1]; d2 = data[2];
d3 = data[3]; d4 = data[4]; d5 = data[5];
ent->ambientLight[0] += factor * d0;
ent->ambientLight[1] += factor * d1;
ent->ambientLight[2] += factor * d2;
ent->directedLight[0] += factor * d3;
ent->directedLight[1] += factor * d4;
ent->directedLight[2] += factor * d5;
#else
ent->ambientLight[0] += factor * data[0];
ent->ambientLight[1] += factor * data[1];
ent->ambientLight[2] += factor * data[2];
ent->directedLight[0] += factor * data[3];
ent->directedLight[1] += factor * data[4];
ent->directedLight[2] += factor * data[5];
#endif
lat = data[7];
lng = data[6];
lat *= (FUNCTABLE_SIZE/256);
lng *= (FUNCTABLE_SIZE/256);
// decode X as cos( lat ) * sin( long )
// decode Y as sin( lat ) * sin( long )
// decode Z as cos( long )
normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
VectorMA( direction, factor, normal, direction );
}
if ( totalFactor > 0 && totalFactor < 0.99 ) {
totalFactor = 1.0f / totalFactor;
VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
VectorScale( ent->directedLight, totalFactor, ent->directedLight );
}
VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );
VectorNormalize2( direction, ent->lightDir );
}
/*
===============
LogLight
===============
*/
static void LogLight( trRefEntity_t *ent ) {
int max1, max2;
if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) {
return;
}
max1 = ent->ambientLight[0];
if ( ent->ambientLight[1] > max1 ) {
max1 = ent->ambientLight[1];
} else if ( ent->ambientLight[2] > max1 ) {
max1 = ent->ambientLight[2];
}
max2 = ent->directedLight[0];
if ( ent->directedLight[1] > max2 ) {
max2 = ent->directedLight[1];
} else if ( ent->directedLight[2] > max2 ) {
max2 = ent->directedLight[2];
}
ri.Printf( PRINT_ALL, "amb:%i dir:%i\n", max1, max2 );
}
/*
=================
R_SetupEntityLighting
Calculates all the lighting values that will be used
by the Calc_* functions
=================
*/
void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
int i;
dlight_t *dl;
float power;
vec3_t dir;
float d;
vec3_t lightDir;
vec3_t lightOrigin;
// lighting calculations
if ( ent->lightingCalculated ) {
return;
}
ent->lightingCalculated = qtrue;
//
// trace a sample point down to find ambient light
//
if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
// separate lightOrigins are needed so an object that is
// sinking into the ground can still be lit, and so
// multi-part models can be lit identically
VectorCopy( ent->e.lightingOrigin, lightOrigin );
} else {
VectorCopy( ent->e.origin, lightOrigin );
}
// if NOWORLDMODEL, only use dynamic lights (menu system, etc)
if ( !(refdef->rdflags & RDF_NOWORLDMODEL )
&& tr.world->lightGridData ) {
R_SetupEntityLightingGrid( ent );
} else {
ent->ambientLight[0] = ent->ambientLight[1] =
ent->ambientLight[2] = tr.identityLight * 150;
ent->directedLight[0] = ent->directedLight[1] =
ent->directedLight[2] = tr.identityLight * 150;
VectorCopy( tr.sunDirection, ent->lightDir );
}
// bonus items and view weapons have a fixed minimum add
if ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) {
// give everything a minimum light add
ent->ambientLight[0] += tr.identityLight * 32;
ent->ambientLight[1] += tr.identityLight * 32;
ent->ambientLight[2] += tr.identityLight * 32;
}
//
// modify the light by dynamic lights
//
d = VectorLength( ent->directedLight );
VectorScale( ent->lightDir, d, lightDir );
for ( i = 0 ; i < refdef->num_dlights ; i++ ) {
dl = &refdef->dlights[i];
VectorSubtract( dl->origin, lightOrigin, dir );
d = VectorNormalize( dir );
power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius );
if ( d < DLIGHT_MINIMUM_RADIUS ) {
d = DLIGHT_MINIMUM_RADIUS;
}
d = power / ( d * d );
VectorMA( ent->directedLight, d, dl->color, ent->directedLight );
VectorMA( lightDir, d, dir, lightDir );
}
// clamp ambient
for ( i = 0 ; i < 3 ; i++ ) {
if ( ent->ambientLight[i] > tr.identityLightByte ) {
ent->ambientLight[i] = tr.identityLightByte;
}
}
if ( r_debugLight->integer ) {
LogLight( ent );
}
// save out the byte packet version
((byte *)&ent->ambientLightInt)[0] = ri.ftol(ent->ambientLight[0]);
((byte *)&ent->ambientLightInt)[1] = ri.ftol(ent->ambientLight[1]);
((byte *)&ent->ambientLightInt)[2] = ri.ftol(ent->ambientLight[2]);
((byte *)&ent->ambientLightInt)[3] = 0xff;
// transform the direction to local space
VectorNormalize( lightDir );
ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] );
ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] );
ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] );
}
/*
=================
R_LightForPoint
=================
*/
int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir )
{
trRefEntity_t ent;
if ( tr.world->lightGridData == NULL )
return qfalse;
Com_Memset(&ent, 0, sizeof(ent));
VectorCopy( point, ent.e.origin );
R_SetupEntityLightingGrid( &ent );
VectorCopy(ent.ambientLight, ambientLight);
VectorCopy(ent.directedLight, directedLight);
VectorCopy(ent.lightDir, lightDir);
return qtrue;
}

1616
code/renderergl1/tr_local.h Normal file

File diff suppressed because it is too large Load diff

1398
code/renderergl1/tr_main.c Normal file

File diff suppressed because it is too large Load diff

458
code/renderergl1/tr_marks.c Normal file
View file

@ -0,0 +1,458 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_marks.c -- polygon projection on the world polygons
#include "tr_local.h"
//#include "assert.h"
#define MAX_VERTS_ON_POLY 64
#define MARKER_OFFSET 0 // 1
/*
=============
R_ChopPolyBehindPlane
Out must have space for two more vertexes than in
=============
*/
#define SIDE_FRONT 0
#define SIDE_BACK 1
#define SIDE_ON 2
static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY],
int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY],
vec3_t normal, vec_t dist, vec_t epsilon) {
float dists[MAX_VERTS_ON_POLY+4] = { 0 };
int sides[MAX_VERTS_ON_POLY+4] = { 0 };
int counts[3];
float dot;
int i, j;
float *p1, *p2, *clip;
float d;
// don't clip if it might overflow
if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) {
*numOutPoints = 0;
return;
}
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for ( i = 0 ; i < numInPoints ; i++ ) {
dot = DotProduct( inPoints[i], normal );
dot -= dist;
dists[i] = dot;
if ( dot > epsilon ) {
sides[i] = SIDE_FRONT;
} else if ( dot < -epsilon ) {
sides[i] = SIDE_BACK;
} else {
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
*numOutPoints = 0;
if ( !counts[0] ) {
return;
}
if ( !counts[1] ) {
*numOutPoints = numInPoints;
Com_Memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) );
return;
}
for ( i = 0 ; i < numInPoints ; i++ ) {
p1 = inPoints[i];
clip = outPoints[ *numOutPoints ];
if ( sides[i] == SIDE_ON ) {
VectorCopy( p1, clip );
(*numOutPoints)++;
continue;
}
if ( sides[i] == SIDE_FRONT ) {
VectorCopy( p1, clip );
(*numOutPoints)++;
clip = outPoints[ *numOutPoints ];
}
if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
continue;
}
// generate a split point
p2 = inPoints[ (i+1) % numInPoints ];
d = dists[i] - dists[i+1];
if ( d == 0 ) {
dot = 0;
} else {
dot = dists[i] / d;
}
// clip xyz
for (j=0 ; j<3 ; j++) {
clip[j] = p1[j] + dot * ( p2[j] - p1[j] );
}
(*numOutPoints)++;
}
}
/*
=================
R_BoxSurfaces_r
=================
*/
void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) {
int s, c;
msurface_t *surf, **mark;
// do the tail recursion in a loop
while ( node->contents == -1 ) {
s = BoxOnPlaneSide( mins, maxs, node->plane );
if (s == 1) {
node = node->children[0];
} else if (s == 2) {
node = node->children[1];
} else {
R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir);
node = node->children[1];
}
}
// add the individual surfaces
mark = node->firstmarksurface;
c = node->nummarksurfaces;
while (c--) {
//
if (*listlength >= listsize) break;
//
surf = *mark;
// check if the surface has NOIMPACT or NOMARKS set
if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
|| ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
surf->viewCount = tr.viewCount;
}
// extra check for surfaces to avoid list overflows
else if (*(surf->data) == SF_FACE) {
// the face plane should go through the box
s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane );
if (s == 1 || s == 2) {
surf->viewCount = tr.viewCount;
} else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) {
// don't add faces that make sharp angles with the projection direction
surf->viewCount = tr.viewCount;
}
}
else if (*(surfaceType_t *) (surf->data) != SF_GRID &&
*(surfaceType_t *) (surf->data) != SF_TRIANGLES)
surf->viewCount = tr.viewCount;
// check the viewCount because the surface may have
// already been added if it spans multiple leafs
if (surf->viewCount != tr.viewCount) {
surf->viewCount = tr.viewCount;
list[*listlength] = (surfaceType_t *) surf->data;
(*listlength)++;
}
mark++;
}
}
/*
=================
R_AddMarkFragments
=================
*/
void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY],
int numPlanes, vec3_t *normals, float *dists,
int maxPoints, vec3_t pointBuffer,
int maxFragments, markFragment_t *fragmentBuffer,
int *returnedPoints, int *returnedFragments,
vec3_t mins, vec3_t maxs) {
int pingPong, i;
markFragment_t *mf;
// chop the surface by all the bounding planes of the to be projected polygon
pingPong = 0;
for ( i = 0 ; i < numPlanes ; i++ ) {
R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong],
&numClipPoints, clipPoints[!pingPong],
normals[i], dists[i], 0.5 );
pingPong ^= 1;
if ( numClipPoints == 0 ) {
break;
}
}
// completely clipped away?
if ( numClipPoints == 0 ) {
return;
}
// add this fragment to the returned list
if ( numClipPoints + (*returnedPoints) > maxPoints ) {
return; // not enough space for this polygon
}
/*
// all the clip points should be within the bounding box
for ( i = 0 ; i < numClipPoints ; i++ ) {
int j;
for ( j = 0 ; j < 3 ; j++ ) {
if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break;
if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break;
}
if (j < 3) break;
}
if (i < numClipPoints) return;
*/
mf = fragmentBuffer + (*returnedFragments);
mf->firstPoint = (*returnedPoints);
mf->numPoints = numClipPoints;
Com_Memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) );
(*returnedPoints) += numClipPoints;
(*returnedFragments)++;
}
/*
=================
R_MarkFragments
=================
*/
int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
int numsurfaces, numPlanes;
int i, j, k, m, n;
surfaceType_t *surfaces[64];
vec3_t mins, maxs;
int returnedFragments;
int returnedPoints;
vec3_t normals[MAX_VERTS_ON_POLY+2];
float dists[MAX_VERTS_ON_POLY+2];
vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
int numClipPoints;
float *v;
srfGridMesh_t *cv;
drawVert_t *dv;
vec3_t normal;
vec3_t projectionDir;
vec3_t v1, v2;
int *indexes;
if (numPoints <= 0) {
return 0;
}
//increment view count for double check prevention
tr.viewCount++;
//
VectorNormalize2( projection, projectionDir );
// find all the brushes that are to be considered
ClearBounds( mins, maxs );
for ( i = 0 ; i < numPoints ; i++ ) {
vec3_t temp;
AddPointToBounds( points[i], mins, maxs );
VectorAdd( points[i], projection, temp );
AddPointToBounds( temp, mins, maxs );
// make sure we get all the leafs (also the one(s) in front of the hit surface)
VectorMA( points[i], -20, projectionDir, temp );
AddPointToBounds( temp, mins, maxs );
}
if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY;
// create the bounding planes for the to be projected polygon
for ( i = 0 ; i < numPoints ; i++ ) {
VectorSubtract(points[(i+1)%numPoints], points[i], v1);
VectorAdd(points[i], projection, v2);
VectorSubtract(points[i], v2, v2);
CrossProduct(v1, v2, normals[i]);
VectorNormalizeFast(normals[i]);
dists[i] = DotProduct(normals[i], points[i]);
}
// add near and far clipping planes for projection
VectorCopy(projectionDir, normals[numPoints]);
dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
VectorCopy(projectionDir, normals[numPoints+1]);
VectorInverse(normals[numPoints+1]);
dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20;
numPlanes = numPoints + 2;
numsurfaces = 0;
R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);
//assert(numsurfaces <= 64);
//assert(numsurfaces != 64);
returnedPoints = 0;
returnedFragments = 0;
for ( i = 0 ; i < numsurfaces ; i++ ) {
if (*surfaces[i] == SF_GRID) {
cv = (srfGridMesh_t *) surfaces[i];
for ( m = 0 ; m < cv->height - 1 ; m++ ) {
for ( n = 0 ; n < cv->width - 1 ; n++ ) {
// We triangulate the grid and chop all triangles within
// the bounding planes of the to be projected polygon.
// LOD is not taken into account, not such a big deal though.
//
// It's probably much nicer to chop the grid itself and deal
// with this grid as a normal SF_GRID surface so LOD will
// be applied. However the LOD of that chopped grid must
// be synced with the LOD of the original curve.
// One way to do this; the chopped grid shares vertices with
// the original curve. When LOD is applied to the original
// curve the unused vertices are flagged. Now the chopped curve
// should skip the flagged vertices. This still leaves the
// problems with the vertices at the chopped grid edges.
//
// To avoid issues when LOD applied to "hollow curves" (like
// the ones around many jump pads) we now just add a 2 unit
// offset to the triangle vertices.
// The offset is added in the vertex normal vector direction
// so all triangles will still fit together.
// The 2 unit offset should avoid pretty much all LOD problems.
numClipPoints = 3;
dv = cv->verts + m * cv->width + n;
VectorCopy(dv[0].xyz, clipPoints[0][0]);
VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);
VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
VectorCopy(dv[1].xyz, clipPoints[0][2]);
VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);
// check the normal of this triangle
VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
CrossProduct(v1, v2, normal);
VectorNormalizeFast(normal);
if (DotProduct(normal, projectionDir) < -0.1) {
// add the fragments of this triangle
R_AddMarkFragments(numClipPoints, clipPoints,
numPlanes, normals, dists,
maxPoints, pointBuffer,
maxFragments, fragmentBuffer,
&returnedPoints, &returnedFragments, mins, maxs);
if ( returnedFragments == maxFragments ) {
return returnedFragments; // not enough space for more fragments
}
}
VectorCopy(dv[1].xyz, clipPoints[0][0]);
VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);
VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);
VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]);
// check the normal of this triangle
VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
CrossProduct(v1, v2, normal);
VectorNormalizeFast(normal);
if (DotProduct(normal, projectionDir) < -0.05) {
// add the fragments of this triangle
R_AddMarkFragments(numClipPoints, clipPoints,
numPlanes, normals, dists,
maxPoints, pointBuffer,
maxFragments, fragmentBuffer,
&returnedPoints, &returnedFragments, mins, maxs);
if ( returnedFragments == maxFragments ) {
return returnedFragments; // not enough space for more fragments
}
}
}
}
}
else if (*surfaces[i] == SF_FACE) {
srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i];
// check the normal of this face
if (DotProduct(surf->plane.normal, projectionDir) > -0.5) {
continue;
}
indexes = (int *)( (byte *)surf + surf->ofsIndices );
for ( k = 0 ; k < surf->numIndices ; k += 3 ) {
for ( j = 0 ; j < 3 ; j++ ) {
v = &surf->points[0][0] + VERTEXSIZE * indexes[k+j];
VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );
}
// add the fragments of this face
R_AddMarkFragments( 3 , clipPoints,
numPlanes, normals, dists,
maxPoints, pointBuffer,
maxFragments, fragmentBuffer,
&returnedPoints, &returnedFragments, mins, maxs);
if ( returnedFragments == maxFragments ) {
return returnedFragments; // not enough space for more fragments
}
}
}
else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {
srfTriangles_t *surf = (srfTriangles_t *) surfaces[i];
for (k = 0; k < surf->numIndexes; k += 3)
{
for(j = 0; j < 3; j++)
{
v = surf->verts[surf->indexes[k + j]].xyz;
VectorMA(v, MARKER_OFFSET, surf->verts[surf->indexes[k + j]].normal, clipPoints[0][j]);
}
// add the fragments of this face
R_AddMarkFragments(3, clipPoints,
numPlanes, normals, dists,
maxPoints, pointBuffer,
maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
if(returnedFragments == maxFragments)
{
return returnedFragments; // not enough space for more fragments
}
}
}
}
return returnedFragments;
}

View file

@ -23,21 +23,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_local.h" #include "tr_local.h"
int TIKI_Skel_Bones_Index;
int skeletorMorphCacheIndex;
skelBoneCache_t TIKI_Skel_Bones[ MAX_SKELBONES ];
int skeletorMorphCache[ MAX_SKELMORPH ];
/*
=============
TIKI_Reset_Caches
=============
*/
void TIKI_Reset_Caches( void ) {
TIKI_Skel_Bones_Index = 0;
skeletorMorphCacheIndex = 0;
}
static float ProjectRadius( float r, vec3_t location ) static float ProjectRadius( float r, vec3_t location )
{ {
float pr; float pr;
@ -85,20 +70,19 @@ static float ProjectRadius( float r, vec3_t location )
return pr; return pr;
} }
#if 0
/* /*
============= =============
R_CullModel R_CullModel
============= =============
*/ */
static int R_CullModel( mdvModel_t *model, trRefEntity_t *ent ) { static int R_CullModel( md3Header_t *header, trRefEntity_t *ent ) {
vec3_t bounds[2]; vec3_t bounds[2];
mdvFrame_t *oldFrame, *newFrame; md3Frame_t *oldFrame, *newFrame;
int i; int i;
// compute frame pointers // compute frame pointers
newFrame = model->frames + ent->e.frame; newFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
oldFrame = model->frames + ent->e.oldframe; oldFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.oldframe;
// cull bounding sphere ONLY if this is not an upscaled entity // cull bounding sphere ONLY if this is not an upscaled entity
if ( !ent->e.nonNormalizedAxes ) if ( !ent->e.nonNormalizedAxes )
@ -172,6 +156,7 @@ static int R_CullModel( mdvModel_t *model, trRefEntity_t *ent ) {
} }
} }
/* /*
================= =================
R_ComputeLOD R_ComputeLOD
@ -182,7 +167,7 @@ int R_ComputeLOD( trRefEntity_t *ent ) {
float radius; float radius;
float flod, lodscale; float flod, lodscale;
float projectedRadius; float projectedRadius;
mdvFrame_t *frame; md3Frame_t *frame;
mdrHeader_t *mdr; mdrHeader_t *mdr;
mdrFrame_t *mdrframe; mdrFrame_t *mdrframe;
int lod; int lod;
@ -209,8 +194,7 @@ int R_ComputeLOD( trRefEntity_t *ent ) {
} }
else else
{ {
//frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames ); frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );
frame = tr.currentModel->mdv[0]->frames;
frame += ent->e.frame; frame += ent->e.frame;
@ -230,7 +214,7 @@ int R_ComputeLOD( trRefEntity_t *ent ) {
} }
flod *= tr.currentModel->numLods; flod *= tr.currentModel->numLods;
lod = ftol(flod); lod = ri.ftol(flod);
if ( lod < 0 ) if ( lod < 0 )
{ {
@ -251,19 +235,17 @@ int R_ComputeLOD( trRefEntity_t *ent ) {
return lod; return lod;
} }
#endif
#if 0
/* /*
================= =================
R_ComputeFogNum R_ComputeFogNum
================= =================
*/ */
int R_ComputeFogNum( mdvModel_t *model, trRefEntity_t *ent ) { int R_ComputeFogNum( md3Header_t *header, trRefEntity_t *ent ) {
int i, j; int i, j;
fog_t *fog; fog_t *fog;
mdvFrame_t *mdvFrame; md3Frame_t *md3Frame;
vec3_t localOrigin; vec3_t localOrigin;
if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
@ -271,15 +253,15 @@ int R_ComputeFogNum( mdvModel_t *model, trRefEntity_t *ent ) {
} }
// FIXME: non-normalized axis issues // FIXME: non-normalized axis issues
mdvFrame = model->frames + ent->e.frame; md3Frame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
VectorAdd( ent->e.origin, mdvFrame->localOrigin, localOrigin ); VectorAdd( ent->e.origin, md3Frame->localOrigin, localOrigin );
for ( i = 1 ; i < tr.world->numfogs ; i++ ) { for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
fog = &tr.world->fogs[i]; fog = &tr.world->fogs[i];
for ( j = 0 ; j < 3 ; j++ ) { for ( j = 0 ; j < 3 ; j++ ) {
if ( localOrigin[j] - mdvFrame->radius >= fog->bounds[1][j] ) { if ( localOrigin[j] - md3Frame->radius >= fog->bounds[1][j] ) {
break; break;
} }
if ( localOrigin[j] + mdvFrame->radius <= fog->bounds[0][j] ) { if ( localOrigin[j] + md3Frame->radius <= fog->bounds[0][j] ) {
break; break;
} }
} }
@ -287,10 +269,10 @@ int R_ComputeFogNum( mdvModel_t *model, trRefEntity_t *ent ) {
return i; return i;
} }
} }
return 0; return 0;
} }
/* /*
================= =================
R_AddMD3Surfaces R_AddMD3Surfaces
@ -299,22 +281,21 @@ R_AddMD3Surfaces
*/ */
void R_AddMD3Surfaces( trRefEntity_t *ent ) { void R_AddMD3Surfaces( trRefEntity_t *ent ) {
int i; int i;
mdvModel_t *model = NULL; md3Header_t *header = NULL;
mdvSurface_t *surface = NULL; md3Surface_t *surface = NULL;
md3Shader_t *md3Shader = NULL;
shader_t *shader = NULL; shader_t *shader = NULL;
int cull; int cull;
int lod; int lod;
int fogNum; int fogNum;
int cubemapIndex;
qboolean personalModel; qboolean personalModel;
// don't add third_person objects if not in a portal // don't add third_person objects if not in a portal
personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !(tr.viewParms.isPortal personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
|| (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW)));
if ( ent->e.renderfx & RF_WRAP_FRAMES ) { if ( ent->e.renderfx & RF_WRAP_FRAMES ) {
ent->e.frame %= tr.currentModel->mdv[0]->numFrames; ent->e.frame %= tr.currentModel->md3[0]->numFrames;
ent->e.oldframe %= tr.currentModel->mdv[0]->numFrames; ent->e.oldframe %= tr.currentModel->md3[0]->numFrames;
} }
// //
@ -323,9 +304,9 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
// when the surfaces are rendered, they don't need to be // when the surfaces are rendered, they don't need to be
// range checked again. // range checked again.
// //
if ( (ent->e.frame >= tr.currentModel->mdv[0]->numFrames) if ( (ent->e.frame >= tr.currentModel->md3[0]->numFrames)
|| (ent->e.frame < 0) || (ent->e.frame < 0)
|| (ent->e.oldframe >= tr.currentModel->mdv[0]->numFrames) || (ent->e.oldframe >= tr.currentModel->md3[0]->numFrames)
|| (ent->e.oldframe < 0) ) { || (ent->e.oldframe < 0) ) {
ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n", ri.Printf( PRINT_DEVELOPER, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n",
ent->e.oldframe, ent->e.frame, ent->e.oldframe, ent->e.frame,
@ -339,13 +320,13 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
// //
lod = R_ComputeLOD( ent ); lod = R_ComputeLOD( ent );
model = tr.currentModel->mdv[lod]; header = tr.currentModel->md3[lod];
// //
// cull the entire model if merged bounding box of both frames // cull the entire model if merged bounding box of both frames
// is outside the view frustum. // is outside the view frustum.
// //
cull = R_CullModel ( model, ent ); cull = R_CullModel ( header, ent );
if ( cull == CULL_OUT ) { if ( cull == CULL_OUT ) {
return; return;
} }
@ -360,15 +341,13 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
// //
// see if we are in a fog volume // see if we are in a fog volume
// //
fogNum = R_ComputeFogNum( model, ent ); fogNum = R_ComputeFogNum( header, ent );
cubemapIndex = R_CubemapForPoint(ent->e.origin);
// //
// draw all surfaces // draw all surfaces
// //
surface = model->surfaces; surface = (md3Surface_t *)( (byte *)header + header->ofsSurfaces );
for ( i = 0 ; i < model->numSurfaces ; i++ ) { for ( i = 0 ; i < header->numSurfaces ; i++ ) {
if ( ent->e.customShader ) { if ( ent->e.customShader ) {
shader = R_GetShaderByHandle( ent->e.customShader ); shader = R_GetShaderByHandle( ent->e.customShader );
@ -382,8 +361,8 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
shader = tr.defaultShader; shader = tr.defaultShader;
for ( j = 0 ; j < skin->numSurfaces ; j++ ) { for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
// the names have both been lowercased // the names have both been lowercased
if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) { if ( !strcmp( skin->surfaces[j].name, surface->name ) ) {
shader = skin->surfaces[j]->shader; shader = skin->surfaces[j].shader;
break; break;
} }
} }
@ -393,29 +372,41 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) {
else if (shader->defaultShader) { else if (shader->defaultShader) {
ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name); ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
} }
//} else if ( surface->numShaders <= 0 ) { } else if ( surface->numShaders <= 0 ) {
//shader = tr.defaultShader; shader = tr.defaultShader;
} else { } else {
//md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders ); md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders );
//md3Shader += ent->e.skinNum % surface->numShaders; md3Shader += ent->e.skinNum % surface->numShaders;
//shader = tr.shaders[ md3Shader->shaderIndex ]; shader = tr.shaders[ md3Shader->shaderIndex ];
shader = tr.shaders[ surface->shaderIndexes[ ent->e.skinNum % surface->numShaderIndexes ] ]; }
// 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
if ( !personalModel
&& r_shadows->integer == 2
&& fogNum == 0
&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
&& shader->sort == SS_OPAQUE ) {
R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse );
}
// projection shadows work fine with personal models
if ( r_shadows->integer == 3
&& fogNum == 0
&& (ent->e.renderfx & RF_SHADOW_PLANE )
&& shader->sort == SS_OPAQUE ) {
R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
} }
// don't add third_person objects if not viewing through a portal // don't add third_person objects if not viewing through a portal
if(!personalModel) if ( !personalModel ) {
{ R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse );
srfVaoMdvMesh_t *vaoSurface = &model->vaoSurfaces[i];
R_AddDrawSurf((void *)vaoSurface, shader, fogNum, qfalse, qfalse, cubemapIndex );
} }
surface++; surface = (md3Surface_t *)( (byte *)surface + surface->ofsEnd );
} }
} }
#endif

1120
code/renderergl1/tr_model.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

411
code/renderergl1/tr_scene.c Normal file
View file

@ -0,0 +1,411 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
int r_firstSceneDrawSurf;
int r_numdlights;
int r_firstSceneDlight;
int r_numentities;
int r_firstSceneEntity;
int r_numpolys;
int r_firstScenePoly;
int r_numpolyverts;
/*
====================
R_InitNextFrame
====================
*/
void R_InitNextFrame( void ) {
backEndData->commands.used = 0;
r_firstSceneDrawSurf = 0;
r_numdlights = 0;
r_firstSceneDlight = 0;
r_numentities = 0;
r_firstSceneEntity = 0;
r_numpolys = 0;
r_firstScenePoly = 0;
r_numpolyverts = 0;
}
/*
====================
RE_ClearScene
====================
*/
void RE_ClearScene( void ) {
r_firstSceneDlight = r_numdlights;
r_firstSceneEntity = r_numentities;
r_firstScenePoly = r_numpolys;
}
/*
===========================================================================
DISCRETE POLYS
===========================================================================
*/
/*
=====================
R_AddPolygonSurfaces
Adds all the scene's polys into this view's drawsurf list
=====================
*/
void R_AddPolygonSurfaces( void ) {
int i;
shader_t *sh;
srfPoly_t *poly;
tr.currentEntityNum = REFENTITYNUM_WORLD;
tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) {
sh = R_GetShaderByHandle( poly->hShader );
R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );
}
}
/*
=====================
RE_AddPolyToScene
=====================
*/
void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) {
srfPoly_t *poly;
int i, j;
int fogIndex;
fog_t *fog;
vec3_t bounds[2];
if ( !tr.registered ) {
return;
}
if ( !hShader ) {
ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n");
return;
}
for ( j = 0; j < numPolys; j++ ) {
if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) {
/*
NOTE TTimo this was initially a PRINT_WARNING
but it happens a lot with high fighting scenes and particles
since we don't plan on changing the const and making for room for those effects
simply cut this message to developer only
*/
ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n");
return;
}
poly = &backEndData->polys[r_numpolys];
poly->surfaceType = SF_POLY;
poly->hShader = hShader;
poly->numVerts = numVerts;
poly->verts = &backEndData->polyVerts[r_numpolyverts];
Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) );
if ( glConfig.hardwareType == GLHW_RAGEPRO ) {
poly->verts->modulate[0] = 255;
poly->verts->modulate[1] = 255;
poly->verts->modulate[2] = 255;
poly->verts->modulate[3] = 255;
}
// done.
r_numpolys++;
r_numpolyverts += numVerts;
// if no world is loaded
if ( tr.world == NULL ) {
fogIndex = 0;
}
// see if it is in a fog volume
else if ( tr.world->numfogs == 1 ) {
fogIndex = 0;
} else {
// find which fog volume the poly is in
VectorCopy( poly->verts[0].xyz, bounds[0] );
VectorCopy( poly->verts[0].xyz, bounds[1] );
for ( i = 1 ; i < poly->numVerts ; i++ ) {
AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
}
for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
fog = &tr.world->fogs[fogIndex];
if ( bounds[1][0] >= fog->bounds[0][0]
&& bounds[1][1] >= fog->bounds[0][1]
&& bounds[1][2] >= fog->bounds[0][2]
&& bounds[0][0] <= fog->bounds[1][0]
&& bounds[0][1] <= fog->bounds[1][1]
&& bounds[0][2] <= fog->bounds[1][2] ) {
break;
}
}
if ( fogIndex == tr.world->numfogs ) {
fogIndex = 0;
}
}
poly->fogIndex = fogIndex;
}
}
//=================================================================================
/*
=====================
RE_AddRefEntityToScene
=====================
*/
void RE_AddRefEntityToScene( const refEntity_t *ent ) {
if ( !tr.registered ) {
return;
}
if ( r_numentities >= MAX_REFENTITIES ) {
ri.Printf(PRINT_DEVELOPER, "RE_AddRefEntityToScene: Dropping refEntity, reached MAX_REFENTITIES\n");
return;
}
if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) {
static qboolean firstTime = qtrue;
if (firstTime) {
firstTime = qfalse;
ri.Printf( PRINT_WARNING, "RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n");
}
return;
}
if ( (int)ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {
ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
}
backEndData->entities[r_numentities].e = *ent;
backEndData->entities[r_numentities].lightingCalculated = qfalse;
r_numentities++;
}
/*
=====================
RE_AddDynamicLightToScene
=====================
*/
void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, float g, float b, int additive ) {
dlight_t *dl;
if ( !tr.registered ) {
return;
}
if ( r_numdlights >= MAX_DLIGHTS ) {
return;
}
if ( intensity <= 0 ) {
return;
}
// these cards don't have the correct blend mode
if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
return;
}
dl = &backEndData->dlights[r_numdlights++];
VectorCopy (org, dl->origin);
dl->radius = intensity;
dl->color[0] = r;
dl->color[1] = g;
dl->color[2] = b;
dl->additive = additive;
}
/*
=====================
RE_AddLightToScene
=====================
*/
void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse );
}
/*
=====================
RE_AddAdditiveLightToScene
=====================
*/
void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue );
}
/*
@@@@@@@@@@@@@@@@@@@@@
RE_RenderScene
Draw a 3D view into a part of the window, then return
to 2D drawing.
Rendering a scene may require multiple views to be rendered
to handle mirrors,
@@@@@@@@@@@@@@@@@@@@@
*/
void RE_RenderScene( const refdef_t *fd ) {
viewParms_t parms;
int startTime;
if ( !tr.registered ) {
return;
}
GLimp_LogComment( "====== RE_RenderScene =====\n" );
if ( r_norefresh->integer ) {
return;
}
startTime = ri.Milliseconds();
if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
}
Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
tr.refdef.x = fd->x;
tr.refdef.y = fd->y;
tr.refdef.width = fd->width;
tr.refdef.height = fd->height;
tr.refdef.fov_x = fd->fov_x;
tr.refdef.fov_y = fd->fov_y;
VectorCopy( fd->vieworg, tr.refdef.vieworg );
VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] );
VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] );
VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );
tr.refdef.time = fd->time;
tr.refdef.rdflags = fd->rdflags;
// copy the areamask data over and note if it has changed, which
// will force a reset of the visible leafs even if the view hasn't moved
tr.refdef.areamaskModified = qfalse;
if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) {
int areaDiff;
int i;
// compare the area bits
areaDiff = 0;
for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) {
areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i];
((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i];
}
if ( areaDiff ) {
// a door just opened or something
tr.refdef.areamaskModified = qtrue;
}
}
// derived info
tr.refdef.floatTime = tr.refdef.time * 0.001;
tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
tr.refdef.drawSurfs = backEndData->drawSurfs;
tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
tr.refdef.entities = &backEndData->entities[r_firstSceneEntity];
tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight];
tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
tr.refdef.polys = &backEndData->polys[r_firstScenePoly];
// turn off dynamic lighting globally by clearing all the
// dlights if it needs to be disabled or if vertex lighting is enabled
if ( r_dynamiclight->integer == 0 ||
r_vertexLight->integer == 1 ||
glConfig.hardwareType == GLHW_PERMEDIA2 ) {
tr.refdef.num_dlights = 0;
}
// a single frame may have multiple scenes draw inside it --
// a 3D game view, 3D status bar renderings, 3D menus, etc.
// They need to be distinguished by the light flare code, because
// the visibility state for a given surface may be different in
// each scene / view.
tr.frameSceneNum++;
tr.sceneCount++;
// setup view parms for the initial view
//
// set up viewport
// The refdef takes 0-at-the-top y coordinates, so
// convert to GL's 0-at-the-bottom space
//
Com_Memset( &parms, 0, sizeof( parms ) );
parms.viewportX = tr.refdef.x;
parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
parms.viewportWidth = tr.refdef.width;
parms.viewportHeight = tr.refdef.height;
parms.isPortal = qfalse;
parms.fovX = tr.refdef.fov_x;
parms.fovY = tr.refdef.fov_y;
parms.stereoFrame = tr.refdef.stereoFrame;
VectorCopy( fd->vieworg, parms.or.origin );
VectorCopy( fd->viewaxis[0], parms.or.axis[0] );
VectorCopy( fd->viewaxis[1], parms.or.axis[1] );
VectorCopy( fd->viewaxis[2], parms.or.axis[2] );
VectorCopy( fd->vieworg, parms.pvsOrigin );
R_RenderView( &parms );
// the next scene rendered in this frame will tack on after this one
r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
r_firstSceneEntity = r_numentities;
r_firstSceneDlight = r_numdlights;
r_firstScenePoly = r_numpolys;
tr.frontEndMsec += ri.Milliseconds() - startTime;
}

1341
code/renderergl1/tr_shade.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

3155
code/renderergl1/tr_shader.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,325 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
/*
for a projection shadow:
point[x] += light vector * ( z - shadow plane )
point[y] +=
point[z] = shadow plane
1 0 light[x] / light[z]
*/
typedef struct {
int i2;
int facing;
} edgeDef_t;
#define MAX_EDGE_DEFS 32
static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS];
static int numEdgeDefs[SHADER_MAX_VERTEXES];
static int facing[SHADER_MAX_INDEXES/3];
static vec3_t shadowXyz[SHADER_MAX_VERTEXES];
void R_AddEdgeDef( int i1, int i2, int facing ) {
int c;
c = numEdgeDefs[ i1 ];
if ( c == MAX_EDGE_DEFS ) {
return; // overflow
}
edgeDefs[ i1 ][ c ].i2 = i2;
edgeDefs[ i1 ][ c ].facing = facing;
numEdgeDefs[ i1 ]++;
}
void R_RenderShadowEdges( void ) {
int i;
#if 0
int numTris;
// dumb way -- render every triangle's edges
numTris = tess.numIndexes / 3;
for ( i = 0 ; i < numTris ; i++ ) {
int i1, i2, i3;
if ( !facing[i] ) {
continue;
}
i1 = tess.indexes[ i*3 + 0 ];
i2 = tess.indexes[ i*3 + 1 ];
i3 = tess.indexes[ i*3 + 2 ];
qglBegin( GL_TRIANGLE_STRIP );
qglVertex3fv( tess.xyz[ i1 ] );
qglVertex3fv( shadowXyz[ i1 ] );
qglVertex3fv( tess.xyz[ i2 ] );
qglVertex3fv( shadowXyz[ i2 ] );
qglVertex3fv( tess.xyz[ i3 ] );
qglVertex3fv( shadowXyz[ i3 ] );
qglVertex3fv( tess.xyz[ i1 ] );
qglVertex3fv( shadowXyz[ i1 ] );
qglEnd();
}
#else
int c, c2;
int j, k;
int i2;
int c_edges, c_rejected;
int hit[2];
// an edge is NOT a silhouette edge if its face doesn't face the light,
// or if it has a reverse paired edge that also faces the light.
// A well behaved polyhedron would have exactly two faces for each edge,
// but lots of models have dangling edges or overfanned edges
c_edges = 0;
c_rejected = 0;
for ( i = 0 ; i < tess.numVertexes ; i++ ) {
c = numEdgeDefs[ i ];
for ( j = 0 ; j < c ; j++ ) {
if ( !edgeDefs[ i ][ j ].facing ) {
continue;
}
hit[0] = 0;
hit[1] = 0;
i2 = edgeDefs[ i ][ j ].i2;
c2 = numEdgeDefs[ i2 ];
for ( k = 0 ; k < c2 ; k++ ) {
if ( edgeDefs[ i2 ][ k ].i2 == i ) {
hit[ edgeDefs[ i2 ][ k ].facing ]++;
}
}
// if it doesn't share the edge with another front facing
// triangle, it is a sil edge
if ( hit[ 1 ] == 0 ) {
qglBegin( GL_TRIANGLE_STRIP );
qglVertex3fv( tess.xyz[ i ] );
qglVertex3fv( shadowXyz[ i ] );
qglVertex3fv( tess.xyz[ i2 ] );
qglVertex3fv( shadowXyz[ i2 ] );
qglEnd();
c_edges++;
} else {
c_rejected++;
}
}
}
#endif
}
/*
=================
RB_ShadowTessEnd
triangleFromEdge[ v1 ][ v2 ]
set triangle from edge( v1, v2, tri )
if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) {
}
=================
*/
void RB_ShadowTessEnd( void ) {
int i;
int numTris;
vec3_t lightDir;
GLboolean rgba[4];
if ( glConfig.stencilBits < 4 ) {
return;
}
VectorCopy( backEnd.currentEntity->lightDir, lightDir );
// project vertexes away from light direction
for ( i = 0 ; i < tess.numVertexes ; i++ ) {
VectorMA( tess.xyz[i], -512, lightDir, shadowXyz[i] );
}
// decide which triangles face the light
Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes );
numTris = tess.numIndexes / 3;
for ( i = 0 ; i < numTris ; i++ ) {
int i1, i2, i3;
vec3_t d1, d2, normal;
float *v1, *v2, *v3;
float d;
i1 = tess.indexes[ i*3 + 0 ];
i2 = tess.indexes[ i*3 + 1 ];
i3 = tess.indexes[ i*3 + 2 ];
v1 = tess.xyz[ i1 ];
v2 = tess.xyz[ i2 ];
v3 = tess.xyz[ i3 ];
VectorSubtract( v2, v1, d1 );
VectorSubtract( v3, v1, d2 );
CrossProduct( d1, d2, normal );
d = DotProduct( normal, lightDir );
if ( d > 0 ) {
facing[ i ] = 1;
} else {
facing[ i ] = 0;
}
// create the edges
R_AddEdgeDef( i1, i2, facing[ i ] );
R_AddEdgeDef( i2, i3, facing[ i ] );
R_AddEdgeDef( i3, i1, facing[ i ] );
}
// draw the silhouette edges
GL_Bind( tr.whiteImage );
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
qglColor3f( 0.2f, 0.2f, 0.2f );
// don't write to the color buffer
qglGetBooleanv(GL_COLOR_WRITEMASK, rgba);
qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
qglEnable( GL_STENCIL_TEST );
qglStencilFunc( GL_ALWAYS, 1, 255 );
GL_Cull( CT_BACK_SIDED );
qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
R_RenderShadowEdges();
GL_Cull( CT_FRONT_SIDED );
qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
R_RenderShadowEdges();
// reenable writing to the color buffer
qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]);
}
/*
=================
RB_ShadowFinish
Darken everything that is is a shadow volume.
We have to delay this until everything has been shadowed,
because otherwise shadows from different body parts would
overlap and double darken.
=================
*/
void RB_ShadowFinish( void ) {
if ( r_shadows->integer != 2 ) {
return;
}
if ( glConfig.stencilBits < 4 ) {
return;
}
qglEnable( GL_STENCIL_TEST );
qglStencilFunc( GL_NOTEQUAL, 0, 255 );
qglDisable (GL_CLIP_PLANE0);
GL_Cull( CT_TWO_SIDED );
GL_Bind( tr.whiteImage );
qglLoadIdentity ();
qglColor3f( 0.6f, 0.6f, 0.6f );
GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO );
// qglColor3f( 1, 0, 0 );
// GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
qglBegin( GL_QUADS );
qglVertex3f( -100, 100, -10 );
qglVertex3f( 100, 100, -10 );
qglVertex3f( 100, -100, -10 );
qglVertex3f( -100, -100, -10 );
qglEnd ();
qglColor4f(1,1,1,1);
qglDisable( GL_STENCIL_TEST );
}
/*
=================
RB_ProjectionShadowDeform
=================
*/
void RB_ProjectionShadowDeform( void ) {
float *xyz;
int i;
float h;
vec3_t ground;
vec3_t light;
float groundDist;
float d;
vec3_t lightDir;
xyz = ( float * ) tess.xyz;
ground[0] = backEnd.or.axis[0][2];
ground[1] = backEnd.or.axis[1][2];
ground[2] = backEnd.or.axis[2][2];
groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane;
VectorCopy( backEnd.currentEntity->lightDir, lightDir );
d = DotProduct( lightDir, ground );
// don't let the shadows get too long or go negative
if ( d < 0.5 ) {
VectorMA( lightDir, (0.5 - d), ground, lightDir );
d = DotProduct( lightDir, ground );
}
d = 1.0 / d;
light[0] = lightDir[0] * d;
light[1] = lightDir[1] * d;
light[2] = lightDir[2] * d;
for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
h = DotProduct( xyz, ground ) + groundDist;
xyz[0] -= light[0] * h;
xyz[1] -= light[1] * h;
xyz[2] -= light[2] * h;
}
}

795
code/renderergl1/tr_sky.c Normal file
View file

@ -0,0 +1,795 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_sky.c
#include "tr_local.h"
#define SKY_SUBDIVISIONS 8
#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2)
static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
/*
===================================================================================
POLYGON TO BOX SIDE PROJECTION
===================================================================================
*/
static vec3_t sky_clip[6] =
{
{1,1,0},
{1,-1,0},
{0,-1,1},
{0,1,1},
{1,0,1},
{-1,0,1}
};
static float sky_mins[2][6], sky_maxs[2][6];
static float sky_min, sky_max;
/*
================
AddSkyPolygon
================
*/
static void AddSkyPolygon (int nump, vec3_t vecs)
{
int i,j;
vec3_t v, av;
float s, t, dv;
int axis;
float *vp;
// s = [0]/[2], t = [1]/[2]
static int vec_to_st[6][3] =
{
{-2,3,1},
{2,3,-1},
{1,3,2},
{-1,3,-2},
{-2,-1,3},
{-2,1,-3}
// {-1,2,3},
// {1,2,-3}
};
// decide which face it maps to
VectorCopy (vec3_origin, v);
for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
{
VectorAdd (vp, v, v);
}
av[0] = fabs(v[0]);
av[1] = fabs(v[1]);
av[2] = fabs(v[2]);
if (av[0] > av[1] && av[0] > av[2])
{
if (v[0] < 0)
axis = 1;
else
axis = 0;
}
else if (av[1] > av[2] && av[1] > av[0])
{
if (v[1] < 0)
axis = 3;
else
axis = 2;
}
else
{
if (v[2] < 0)
axis = 5;
else
axis = 4;
}
// project new texture coords
for (i=0 ; i<nump ; i++, vecs+=3)
{
j = vec_to_st[axis][2];
if (j > 0)
dv = vecs[j - 1];
else
dv = -vecs[-j - 1];
if (dv < 0.001)
continue; // don't divide by zero
j = vec_to_st[axis][0];
if (j < 0)
s = -vecs[-j -1] / dv;
else
s = vecs[j-1] / dv;
j = vec_to_st[axis][1];
if (j < 0)
t = -vecs[-j -1] / dv;
else
t = vecs[j-1] / dv;
if (s < sky_mins[0][axis])
sky_mins[0][axis] = s;
if (t < sky_mins[1][axis])
sky_mins[1][axis] = t;
if (s > sky_maxs[0][axis])
sky_maxs[0][axis] = s;
if (t > sky_maxs[1][axis])
sky_maxs[1][axis] = t;
}
}
#define ON_EPSILON 0.1f // point on plane side epsilon
#define MAX_CLIP_VERTS 64
/*
================
ClipSkyPolygon
================
*/
static void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
{
float *norm;
float *v;
qboolean front, back;
float d, e;
float dists[MAX_CLIP_VERTS];
int sides[MAX_CLIP_VERTS];
vec3_t newv[2][MAX_CLIP_VERTS];
int newc[2];
int i, j;
if (nump > MAX_CLIP_VERTS-2)
ri.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS");
if (stage == 6)
{ // fully clipped, so draw it
AddSkyPolygon (nump, vecs);
return;
}
front = back = qfalse;
norm = sky_clip[stage];
for (i=0, v = vecs ; i<nump ; i++, v+=3)
{
d = DotProduct (v, norm);
if (d > ON_EPSILON)
{
front = qtrue;
sides[i] = SIDE_FRONT;
}
else if (d < -ON_EPSILON)
{
back = qtrue;
sides[i] = SIDE_BACK;
}
else
sides[i] = SIDE_ON;
dists[i] = d;
}
if (!front || !back)
{ // not clipped
ClipSkyPolygon (nump, vecs, stage+1);
return;
}
// clip it
sides[i] = sides[0];
dists[i] = dists[0];
VectorCopy (vecs, (vecs+(i*3)) );
newc[0] = newc[1] = 0;
for (i=0, v = vecs ; i<nump ; i++, v+=3)
{
switch (sides[i])
{
case SIDE_FRONT:
VectorCopy (v, newv[0][newc[0]]);
newc[0]++;
break;
case SIDE_BACK:
VectorCopy (v, newv[1][newc[1]]);
newc[1]++;
break;
case SIDE_ON:
VectorCopy (v, newv[0][newc[0]]);
newc[0]++;
VectorCopy (v, newv[1][newc[1]]);
newc[1]++;
break;
}
if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
continue;
d = dists[i] / (dists[i] - dists[i+1]);
for (j=0 ; j<3 ; j++)
{
e = v[j] + d*(v[j+3] - v[j]);
newv[0][newc[0]][j] = e;
newv[1][newc[1]][j] = e;
}
newc[0]++;
newc[1]++;
}
// continue
ClipSkyPolygon (newc[0], newv[0][0], stage+1);
ClipSkyPolygon (newc[1], newv[1][0], stage+1);
}
/*
==============
ClearSkyBox
==============
*/
static void ClearSkyBox (void) {
int i;
for (i=0 ; i<6 ; i++) {
sky_mins[0][i] = sky_mins[1][i] = 9999;
sky_maxs[0][i] = sky_maxs[1][i] = -9999;
}
}
/*
================
RB_ClipSkyPolygons
================
*/
void RB_ClipSkyPolygons( shaderCommands_t *input )
{
vec3_t p[5]; // need one extra point for clipping
int i, j;
ClearSkyBox();
for ( i = 0; i < input->numIndexes; i += 3 )
{
for (j = 0 ; j < 3 ; j++)
{
VectorSubtract( input->xyz[input->indexes[i+j]],
backEnd.viewParms.or.origin,
p[j] );
}
ClipSkyPolygon( 3, p[0], 0 );
}
}
/*
===================================================================================
CLOUD VERTEX GENERATION
===================================================================================
*/
/*
** MakeSkyVec
**
** Parms: s, t range from -1 to 1
*/
static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ )
{
// 1 = s, 2 = t, 3 = 2048
static int st_to_vec[6][3] =
{
{3,-1,2},
{-3,1,2},
{1,3,2},
{-1,-3,2},
{-2,-1,3}, // 0 degrees yaw, look straight up
{2,-1,-3} // look straight down
};
vec3_t b;
int j, k;
float boxSize;
boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
b[0] = s*boxSize;
b[1] = t*boxSize;
b[2] = boxSize;
for (j=0 ; j<3 ; j++)
{
k = st_to_vec[axis][j];
if (k < 0)
{
outXYZ[j] = -b[-k - 1];
}
else
{
outXYZ[j] = b[k - 1];
}
}
// avoid bilerp seam
s = (s+1)*0.5;
t = (t+1)*0.5;
if (s < sky_min)
{
s = sky_min;
}
else if (s > sky_max)
{
s = sky_max;
}
if (t < sky_min)
{
t = sky_min;
}
else if (t > sky_max)
{
t = sky_max;
}
t = 1.0 - t;
if ( outSt )
{
outSt[0] = s;
outSt[1] = t;
}
}
static int sky_texorder[6] = {0,2,1,3,4,5};
static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
{
int s, t;
GL_Bind( image );
for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
{
qglBegin( GL_TRIANGLE_STRIP );
for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
{
qglTexCoord2fv( s_skyTexCoords[t][s] );
qglVertex3fv( s_skyPoints[t][s] );
qglTexCoord2fv( s_skyTexCoords[t+1][s] );
qglVertex3fv( s_skyPoints[t+1][s] );
}
qglEnd();
}
}
static void DrawSkyBox( shader_t *shader )
{
int i;
sky_min = 0;
sky_max = 1;
Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) );
for (i=0 ; i<6 ; i++)
{
int sky_mins_subd[2], sky_maxs_subd[2];
int s, t;
sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
( sky_mins[1][i] >= sky_maxs[1][i] ) )
{
continue;
}
sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS;
sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS;
sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS;
sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS;
if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS )
sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
//
// iterate through the subdivisions
//
for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
{
for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
{
MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
i,
s_skyTexCoords[t][s],
s_skyPoints[t][s] );
}
}
DrawSkySide( shader->sky.outerbox[sky_texorder[i]],
sky_mins_subd,
sky_maxs_subd );
}
}
static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes )
{
int s, t;
int vertexStart = tess.numVertexes;
int tHeight, sWidth;
tHeight = maxs[1] - mins[1] + 1;
sWidth = maxs[0] - mins[0] + 1;
for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
{
for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
{
VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0];
tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1];
tess.numVertexes++;
if ( tess.numVertexes >= SHADER_MAX_VERTEXES )
{
ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()" );
}
}
}
// only add indexes for one pass, otherwise it would draw multiple times for each pass
if ( addIndexes ) {
for ( t = 0; t < tHeight-1; t++ )
{
for ( s = 0; s < sWidth-1; s++ )
{
tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
tess.numIndexes++;
}
}
}
}
static void FillCloudBox( const shader_t *shader, int stage )
{
int i;
for ( i =0; i < 6; i++ )
{
int sky_mins_subd[2], sky_maxs_subd[2];
int s, t;
float MIN_T;
if ( 1 ) // FIXME? shader->sky.fullClouds )
{
MIN_T = -HALF_SKY_SUBDIVISIONS;
// still don't want to draw the bottom, even if fullClouds
if ( i == 5 )
continue;
}
else
{
switch( i )
{
case 0:
case 1:
case 2:
case 3:
MIN_T = -1;
break;
case 5:
// don't draw clouds beneath you
continue;
case 4: // top
default:
MIN_T = -HALF_SKY_SUBDIVISIONS;
break;
}
}
sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
( sky_mins[1][i] >= sky_maxs[1][i] ) )
{
continue;
}
sky_mins_subd[0] = ri.ftol(sky_mins[0][i] * HALF_SKY_SUBDIVISIONS);
sky_mins_subd[1] = ri.ftol(sky_mins[1][i] * HALF_SKY_SUBDIVISIONS);
sky_maxs_subd[0] = ri.ftol(sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS);
sky_maxs_subd[1] = ri.ftol(sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS);
if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
if ( sky_mins_subd[1] < MIN_T )
sky_mins_subd[1] = MIN_T;
else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
if ( sky_maxs_subd[1] < MIN_T )
sky_maxs_subd[1] = MIN_T;
else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
//
// iterate through the subdivisions
//
for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
{
for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
{
MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
i,
NULL,
s_skyPoints[t][s] );
s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0];
s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1];
}
}
// only add indexes for first stage
FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) );
}
}
/*
** R_BuildCloudData
*/
void R_BuildCloudData( shaderCommands_t *input )
{
int i;
shader_t *shader;
shader = input->shader;
assert( shader->isSky );
sky_min = 1.0 / 256.0f; // FIXME: not correct?
sky_max = 255.0 / 256.0f;
// set up for drawing
tess.numIndexes = 0;
tess.numVertexes = 0;
if ( shader->sky.cloudHeight )
{
for ( i = 0; i < MAX_SHADER_STAGES; i++ )
{
if ( !tess.xstages[i] ) {
break;
}
FillCloudBox( shader, i );
}
}
}
/*
** R_InitSkyTexCoords
** Called when a sky shader is parsed
*/
#define SQR( a ) ((a)*(a))
void R_InitSkyTexCoords( float heightCloud )
{
int i, s, t;
float radiusWorld = 4096;
float p;
float sRad, tRad;
vec3_t skyVec;
vec3_t v;
// init zfar so MakeSkyVec works even though
// a world hasn't been bounded
backEnd.viewParms.zFar = 1024;
for ( i = 0; i < 6; i++ )
{
for ( t = 0; t <= SKY_SUBDIVISIONS; t++ )
{
for ( s = 0; s <= SKY_SUBDIVISIONS; s++ )
{
// compute vector from view origin to sky side integral point
MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
i,
NULL,
skyVec );
// compute parametric value 'p' that intersects with cloud layer
p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) *
( -2 * skyVec[2] * radiusWorld +
2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) +
2 * SQR( skyVec[0] ) * radiusWorld * heightCloud +
SQR( skyVec[0] ) * SQR( heightCloud ) +
2 * SQR( skyVec[1] ) * radiusWorld * heightCloud +
SQR( skyVec[1] ) * SQR( heightCloud ) +
2 * SQR( skyVec[2] ) * radiusWorld * heightCloud +
SQR( skyVec[2] ) * SQR( heightCloud ) ) );
s_cloudTexP[i][t][s] = p;
// compute intersection point based on p
VectorScale( skyVec, p, v );
v[2] += radiusWorld;
// compute vector from world origin to intersection point 'v'
VectorNormalize( v );
sRad = Q_acos( v[0] );
tRad = Q_acos( v[1] );
s_cloudTexCoords[i][t][s][0] = sRad;
s_cloudTexCoords[i][t][s][1] = tRad;
}
}
}
}
//======================================================================================
/*
** RB_DrawSun
*/
void RB_DrawSun( float scale, shader_t *shader ) {
float size;
float dist;
vec3_t origin, vec1, vec2;
byte sunColor[4] = { 255, 255, 255, 255 };
if ( !backEnd.skyRenderedThisView ) {
return;
}
qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
size = dist * scale;
VectorScale( tr.sunDirection, dist, origin );
PerpendicularVector( vec1, tr.sunDirection );
CrossProduct( tr.sunDirection, vec1, vec2 );
VectorScale( vec1, size, vec1 );
VectorScale( vec2, size, vec2 );
// farthest depth range
qglDepthRange( 1.0, 1.0 );
RB_BeginSurface( shader, 0 );
RB_AddQuadStamp(origin, vec1, vec2, sunColor);
RB_EndSurface();
// back to normal depth range
qglDepthRange( 0.0, 1.0 );
}
/*
================
RB_StageIteratorSky
All of the visible sky triangles are in tess
Other things could be stuck in here, like birds in the sky, etc
================
*/
void RB_StageIteratorSky( void ) {
if ( r_fastsky->integer ) {
return;
}
// go through all the polygons and project them onto
// the sky box to see which blocks on each side need
// to be drawn
RB_ClipSkyPolygons( &tess );
// r_showsky will let all the sky blocks be drawn in
// front of everything to allow developers to see how
// much sky is getting sucked in
if ( r_showsky->integer ) {
qglDepthRange( 0.0, 0.0 );
} else {
qglDepthRange( 1.0, 1.0 );
}
// draw the outer skybox
if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
qglPushMatrix ();
GL_State( 0 );
GL_Cull( CT_FRONT_SIDED );
qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
DrawSkyBox( tess.shader );
qglPopMatrix();
}
// generate the vertexes for all the clouds, which will be drawn
// by the generic shader routine
R_BuildCloudData( &tess );
RB_StageIteratorGeneric();
// draw the inner skybox
// back to normal depth range
qglDepthRange( 0.0, 1.0 );
// note that sky was drawn so we will draw a sun later
backEnd.skyRenderedThisView = qtrue;
}

View file

@ -0,0 +1,48 @@
/*
===========================================================================
Copyright (C) 2010 James Canete (use.less01@gmail.com)
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_subs.c - common function replacements for modular renderer
#include "tr_local.h"
void QDECL Com_Printf( const char *msg, ... )
{
va_list argptr;
char text[1024];
va_start(argptr, msg);
Q_vsnprintf(text, sizeof(text), msg, argptr);
va_end(argptr);
ri.Printf(PRINT_ALL, "%s", text);
}
void QDECL Com_Error( int level, const char *error, ... )
{
va_list argptr;
char text[1024];
va_start(argptr, error);
Q_vsnprintf(text, sizeof(text), error, argptr);
va_end(argptr);
ri.Error(level, "%s", text);
}

File diff suppressed because it is too large Load diff

668
code/renderergl1/tr_world.c Normal file
View file

@ -0,0 +1,668 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
/*
=================
R_CullTriSurf
Returns true if the grid is completely culled away.
Also sets the clipped hint bit in tess
=================
*/
static qboolean R_CullTriSurf( srfTriangles_t *cv ) {
int boxCull;
boxCull = R_CullLocalBox( cv->bounds );
if ( boxCull == CULL_OUT ) {
return qtrue;
}
return qfalse;
}
/*
=================
R_CullGrid
Returns true if the grid is completely culled away.
Also sets the clipped hint bit in tess
=================
*/
static qboolean R_CullGrid( srfGridMesh_t *cv ) {
int boxCull;
int sphereCull;
if ( r_nocurves->integer ) {
return qtrue;
}
if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) {
sphereCull = R_CullLocalPointAndRadius( cv->localOrigin, cv->meshRadius );
} else {
sphereCull = R_CullPointAndRadius( cv->localOrigin, cv->meshRadius );
}
// check for trivial reject
if ( sphereCull == CULL_OUT )
{
tr.pc.c_sphere_cull_patch_out++;
return qtrue;
}
// check bounding box if necessary
else if ( sphereCull == CULL_CLIP )
{
tr.pc.c_sphere_cull_patch_clip++;
boxCull = R_CullLocalBox( cv->meshBounds );
if ( boxCull == CULL_OUT )
{
tr.pc.c_box_cull_patch_out++;
return qtrue;
}
else if ( boxCull == CULL_IN )
{
tr.pc.c_box_cull_patch_in++;
}
else
{
tr.pc.c_box_cull_patch_clip++;
}
}
else
{
tr.pc.c_sphere_cull_patch_in++;
}
return qfalse;
}
/*
================
R_CullSurface
Tries to back face cull surfaces before they are lighted or
added to the sorting list.
This will also allow mirrors on both sides of a model without recursion.
================
*/
static qboolean R_CullSurface( surfaceType_t *surface, shader_t *shader ) {
srfSurfaceFace_t *sface;
float d;
if ( r_nocull->integer ) {
return qfalse;
}
if ( *surface == SF_GRID ) {
return R_CullGrid( (srfGridMesh_t *)surface );
}
if ( *surface == SF_TRIANGLES ) {
return R_CullTriSurf( (srfTriangles_t *)surface );
}
if ( *surface != SF_FACE ) {
return qfalse;
}
if ( shader->cullType == CT_TWO_SIDED ) {
return qfalse;
}
// face culling
if ( !r_facePlaneCull->integer ) {
return qfalse;
}
sface = ( srfSurfaceFace_t * ) surface;
d = DotProduct (tr.or.viewOrigin, sface->plane.normal);
// don't cull exactly on the plane, because there are levels of rounding
// through the BSP, ICD, and hardware that may cause pixel gaps if an
// epsilon isn't allowed here
if ( shader->cullType == CT_FRONT_SIDED ) {
if ( d < sface->plane.dist - 8 ) {
return qtrue;
}
} else {
if ( d > sface->plane.dist + 8 ) {
return qtrue;
}
}
return qfalse;
}
static int R_DlightFace( srfSurfaceFace_t *face, int dlightBits ) {
float d;
int i;
dlight_t *dl;
for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
if ( ! ( dlightBits & ( 1 << i ) ) ) {
continue;
}
dl = &tr.refdef.dlights[i];
d = DotProduct( dl->origin, face->plane.normal ) - face->plane.dist;
if ( d < -dl->radius || d > dl->radius ) {
// dlight doesn't reach the plane
dlightBits &= ~( 1 << i );
}
}
if ( !dlightBits ) {
tr.pc.c_dlightSurfacesCulled++;
}
face->dlightBits = dlightBits;
return dlightBits;
}
static int R_DlightGrid( srfGridMesh_t *grid, int dlightBits ) {
int i;
dlight_t *dl;
for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
if ( ! ( dlightBits & ( 1 << i ) ) ) {
continue;
}
dl = &tr.refdef.dlights[i];
if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0]
|| dl->origin[0] + dl->radius < grid->meshBounds[0][0]
|| dl->origin[1] - dl->radius > grid->meshBounds[1][1]
|| dl->origin[1] + dl->radius < grid->meshBounds[0][1]
|| dl->origin[2] - dl->radius > grid->meshBounds[1][2]
|| dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) {
// dlight doesn't reach the bounds
dlightBits &= ~( 1 << i );
}
}
if ( !dlightBits ) {
tr.pc.c_dlightSurfacesCulled++;
}
grid->dlightBits = dlightBits;
return dlightBits;
}
static int R_DlightTrisurf( srfTriangles_t *surf, int dlightBits ) {
// FIXME: more dlight culling to trisurfs...
surf->dlightBits = dlightBits;
return dlightBits;
#if 0
int i;
dlight_t *dl;
for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
if ( ! ( dlightBits & ( 1 << i ) ) ) {
continue;
}
dl = &tr.refdef.dlights[i];
if ( dl->origin[0] - dl->radius > grid->meshBounds[1][0]
|| dl->origin[0] + dl->radius < grid->meshBounds[0][0]
|| dl->origin[1] - dl->radius > grid->meshBounds[1][1]
|| dl->origin[1] + dl->radius < grid->meshBounds[0][1]
|| dl->origin[2] - dl->radius > grid->meshBounds[1][2]
|| dl->origin[2] + dl->radius < grid->meshBounds[0][2] ) {
// dlight doesn't reach the bounds
dlightBits &= ~( 1 << i );
}
}
if ( !dlightBits ) {
tr.pc.c_dlightSurfacesCulled++;
}
grid->dlightBits = dlightBits;
return dlightBits;
#endif
}
/*
====================
R_DlightSurface
The given surface is going to be drawn, and it touches a leaf
that is touched by one or more dlights, so try to throw out
more dlights if possible.
====================
*/
static int R_DlightSurface( msurface_t *surf, int dlightBits ) {
if ( *surf->data == SF_FACE ) {
dlightBits = R_DlightFace( (srfSurfaceFace_t *)surf->data, dlightBits );
} else if ( *surf->data == SF_GRID ) {
dlightBits = R_DlightGrid( (srfGridMesh_t *)surf->data, dlightBits );
} else if ( *surf->data == SF_TRIANGLES ) {
dlightBits = R_DlightTrisurf( (srfTriangles_t *)surf->data, dlightBits );
} else {
dlightBits = 0;
}
if ( dlightBits ) {
tr.pc.c_dlightSurfaces++;
}
return dlightBits;
}
/*
======================
R_AddWorldSurface
======================
*/
static void R_AddWorldSurface( msurface_t *surf, int dlightBits ) {
if ( surf->viewCount == tr.viewCount ) {
return; // already in this view
}
surf->viewCount = tr.viewCount;
// FIXME: bmodel fog?
// try to cull before dlighting or adding
if ( R_CullSurface( surf->data, surf->shader ) ) {
return;
}
// check for dlighting
if ( dlightBits ) {
dlightBits = R_DlightSurface( surf, dlightBits );
dlightBits = ( dlightBits != 0 );
}
R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits );
}
/*
=============================================================
BRUSH MODELS
=============================================================
*/
/*
=================
R_AddBrushModelSurfaces
=================
*/
void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) {
bmodel_t *bmodel;
int clip;
model_t *pModel;
int i;
pModel = R_GetModelByHandle( ent->e.hModel );
bmodel = pModel->bmodel;
clip = R_CullLocalBox( bmodel->bounds );
if ( clip == CULL_OUT ) {
return;
}
R_SetupEntityLighting( &tr.refdef, ent );
R_DlightBmodel( bmodel );
for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
R_AddWorldSurface( bmodel->firstSurface + i, tr.currentEntity->needDlights );
}
}
/*
=============================================================
WORLD MODEL
=============================================================
*/
/*
================
R_RecursiveWorldNode
================
*/
static void R_RecursiveWorldNode( mnode_t *node, unsigned int planeBits, unsigned int dlightBits ) {
do {
unsigned int newDlights[2];
// if the node wasn't marked as potentially visible, exit
if (node->visframe != tr.visCount) {
return;
}
// if the bounding volume is outside the frustum, nothing
// inside can be visible OPTIMIZE: don't do this all the way to leafs?
if ( !r_nocull->integer ) {
int r;
if ( planeBits & 1 ) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]);
if (r == 2) {
return; // culled
}
if ( r == 1 ) {
planeBits &= ~1; // all descendants will also be in front
}
}
if ( planeBits & 2 ) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]);
if (r == 2) {
return; // culled
}
if ( r == 1 ) {
planeBits &= ~2; // all descendants will also be in front
}
}
if ( planeBits & 4 ) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]);
if (r == 2) {
return; // culled
}
if ( r == 1 ) {
planeBits &= ~4; // all descendants will also be in front
}
}
if ( planeBits & 8 ) {
r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]);
if (r == 2) {
return; // culled
}
if ( r == 1 ) {
planeBits &= ~8; // all descendants will also be in front
}
}
}
if ( node->contents != -1 ) {
break;
}
// node is just a decision point, so go down both sides
// since we don't care about sort orders, just go positive to negative
// determine which dlights are needed
newDlights[0] = 0;
newDlights[1] = 0;
if ( dlightBits ) {
int i;
for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
dlight_t *dl;
float dist;
if ( dlightBits & ( 1 << i ) ) {
dl = &tr.refdef.dlights[i];
dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist;
if ( dist > -dl->radius ) {
newDlights[0] |= ( 1 << i );
}
if ( dist < dl->radius ) {
newDlights[1] |= ( 1 << i );
}
}
}
}
// recurse down the children, front side first
R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0] );
// tail recurse
node = node->children[1];
dlightBits = newDlights[1];
} while ( 1 );
{
// leaf node, so add mark surfaces
int c;
msurface_t *surf, **mark;
tr.pc.c_leafs++;
// add to z buffer bounds
if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) {
tr.viewParms.visBounds[0][0] = node->mins[0];
}
if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) {
tr.viewParms.visBounds[0][1] = node->mins[1];
}
if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) {
tr.viewParms.visBounds[0][2] = node->mins[2];
}
if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) {
tr.viewParms.visBounds[1][0] = node->maxs[0];
}
if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) {
tr.viewParms.visBounds[1][1] = node->maxs[1];
}
if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) {
tr.viewParms.visBounds[1][2] = node->maxs[2];
}
// add the individual surfaces
mark = node->firstmarksurface;
c = node->nummarksurfaces;
while (c--) {
// the surface may have already been added if it
// spans multiple leafs
surf = *mark;
R_AddWorldSurface( surf, dlightBits );
mark++;
}
}
}
/*
===============
R_PointInLeaf
===============
*/
static mnode_t *R_PointInLeaf( const vec3_t p ) {
mnode_t *node;
float d;
cplane_t *plane;
if ( !tr.world ) {
ri.Error (ERR_DROP, "R_PointInLeaf: bad model");
}
node = tr.world->nodes;
while( 1 ) {
if (node->contents != -1) {
break;
}
plane = node->plane;
d = DotProduct (p,plane->normal) - plane->dist;
if (d > 0) {
node = node->children[0];
} else {
node = node->children[1];
}
}
return node;
}
/*
==============
R_ClusterPVS
==============
*/
static const byte *R_ClusterPVS (int cluster) {
if (!tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) {
return tr.world->novis;
}
return tr.world->vis + cluster * tr.world->clusterBytes;
}
/*
=================
R_inPVS
=================
*/
qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ) {
mnode_t *leaf;
byte *vis;
leaf = R_PointInLeaf( p1 );
vis = ri.CM_ClusterPVS( leaf->cluster ); // why not R_ClusterPVS ??
leaf = R_PointInLeaf( p2 );
if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) {
return qfalse;
}
return qtrue;
}
/*
===============
R_MarkLeaves
Mark the leaves and nodes that are in the PVS for the current
cluster
===============
*/
static void R_MarkLeaves (void) {
const byte *vis;
mnode_t *leaf, *parent;
int i;
int cluster;
// lockpvs lets designers walk around to determine the
// extent of the current pvs
if ( r_lockpvs->integer ) {
return;
}
// current viewcluster
leaf = R_PointInLeaf( tr.viewParms.pvsOrigin );
cluster = leaf->cluster;
// if the cluster is the same and the area visibility matrix
// hasn't changed, we don't need to mark everything again
// if r_showcluster was just turned on, remark everything
if ( tr.viewCluster == cluster && !tr.refdef.areamaskModified
&& !r_showcluster->modified ) {
return;
}
if ( r_showcluster->modified || r_showcluster->integer ) {
r_showcluster->modified = qfalse;
if ( r_showcluster->integer ) {
ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area );
}
}
tr.visCount++;
tr.viewCluster = cluster;
if ( r_novis->integer || tr.viewCluster == -1 ) {
for (i=0 ; i<tr.world->numnodes ; i++) {
if (tr.world->nodes[i].contents != CONTENTS_SOLID) {
tr.world->nodes[i].visframe = tr.visCount;
}
}
return;
}
vis = R_ClusterPVS (tr.viewCluster);
for (i=0,leaf=tr.world->nodes ; i<tr.world->numnodes ; i++, leaf++) {
cluster = leaf->cluster;
if ( cluster < 0 || cluster >= tr.world->numClusters ) {
continue;
}
// check general pvs
if ( !(vis[cluster>>3] & (1<<(cluster&7))) ) {
continue;
}
// check for door connection
if ( (tr.refdef.areamask[leaf->area>>3] & (1<<(leaf->area&7)) ) ) {
continue; // not visible
}
parent = leaf;
do {
if (parent->visframe == tr.visCount)
break;
parent->visframe = tr.visCount;
parent = parent->parent;
} while (parent);
}
}
/*
=============
R_AddWorldSurfaces
=============
*/
void R_AddWorldSurfaces (void) {
if ( !r_drawworld->integer ) {
return;
}
if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
return;
}
tr.currentEntityNum = REFENTITYNUM_WORLD;
tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
// determine which leaves are in the PVS / areamask
R_MarkLeaves ();
// clear out the visible min/max
ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] );
// perform frustum culling and add all the potentially visible surfaces
if ( tr.refdef.num_dlights > MAX_DLIGHTS ) {
tr.refdef.num_dlights = MAX_DLIGHTS ;
}
R_RecursiveWorldNode( tr.world->nodes, 15, ( 1ULL << tr.refdef.num_dlights ) - 1 );
}

View file

@ -11,7 +11,15 @@ void main()
vec2 tc; vec2 tc;
#if 0 #if 0
float c[7] = float[7](1.0, 0.9659258263, 0.8660254038, 0.7071067812, 0.5, 0.2588190451, 0.0); float c[7];
c[0] = 1.0;
c[1] = 0.9659258263;
c[2] = 0.8660254038;
c[3] = 0.7071067812;
c[4] = 0.5;
c[5] = 0.2588190451;
c[6] = 0.0;
tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[6]); color = texture2D(u_TextureMap, tc); tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[6]); color = texture2D(u_TextureMap, tc);
tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[5]); color += texture2D(u_TextureMap, tc); tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[5]); color += texture2D(u_TextureMap, tc);
@ -44,7 +52,13 @@ void main()
gl_FragColor = color * 0.04166667 * u_Color; gl_FragColor = color * 0.04166667 * u_Color;
#endif #endif
float c[5] = float[5](1.0, 0.9238795325, 0.7071067812, 0.3826834324, 0.0); float c[5];
c[0] = 1.0;
c[1] = 0.9238795325;
c[2] = 0.7071067812;
c[3] = 0.3826834324;
c[4] = 0.0;
tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[4]); color = texture2D(u_TextureMap, tc); tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[4]); color = texture2D(u_TextureMap, tc);
tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[3]); color += texture2D(u_TextureMap, tc); tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[3]); color += texture2D(u_TextureMap, tc);

View file

@ -14,8 +14,8 @@ vec3 GetValues(vec2 offset, vec3 current)
#ifdef FIRST_PASS #ifdef FIRST_PASS
#if defined(r_framebufferGamma) #if defined(USE_PBR)
minAvgMax = pow(minAvgMax, vec3(r_framebufferGamma)); minAvgMax *= minAvgMax;
#endif #endif
float lumi = max(dot(LUMINANCE_VECTOR, minAvgMax), 0.000001); float lumi = max(dot(LUMINANCE_VECTOR, minAvgMax), 0.000001);
@ -56,5 +56,5 @@ void main()
current.y *= 0.0625; current.y *= 0.0625;
#endif #endif
gl_FragColor = vec4(current, 1.0f); gl_FragColor = vec4(current, 1.0);
} }

View file

@ -1,58 +1,88 @@
uniform sampler2D u_ScreenImageMap; uniform sampler2D u_ScreenImageMap;
uniform sampler2D u_ScreenDepthMap; uniform sampler2D u_ScreenDepthMap;
uniform vec4 u_ViewInfo; // zfar / znear, zfar uniform vec4 u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height
varying vec2 var_ScreenTex; varying vec2 var_ScreenTex;
//float gauss[8] = float[8](0.17, 0.17, 0.16, 0.14, 0.12, 0.1, 0.08, 0.06);
//float gauss[5] = float[5](0.30, 0.23, 0.097, 0.024, 0.0033); //float gauss[5] = float[5](0.30, 0.23, 0.097, 0.024, 0.0033);
float gauss[4] = float[4](0.40, 0.24, 0.054, 0.0044); //float gauss[4] = float[4](0.40, 0.24, 0.054, 0.0044);
//float gauss[3] = float[3](0.60, 0.19, 0.0066); //float gauss[3] = float[3](0.60, 0.19, 0.0066);
#define GAUSS_SIZE 4 #define BLUR_SIZE 4
#if !defined(USE_DEPTH)
//#define USE_GAUSS
#endif
float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear) float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear)
{ {
float sampleZDivW = texture2D(depthMap, tex).r; float sampleZDivW = texture2D(depthMap, tex).r;
return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW); return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
} }
vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFarDivZNear, float zFar) vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFarDivZNear, float zFar, vec2 scale)
{ {
float scale = 1.0 / 256.0; float gauss[4];
gauss[0] = 0.40;
gauss[1] = 0.24;
gauss[2] = 0.054;
gauss[3] = 0.0044;
#if defined(USE_DEPTH)
float depthCenter = getLinearDepth(depthMap, tex, zFarDivZNear);
vec2 slope = vec2(dFdx(depthCenter), dFdy(depthCenter)) / vec2(dFdx(tex.x), dFdy(tex.y));
scale /= clamp(zFarDivZNear * depthCenter / 32.0, 1.0, 2.0);
#endif
#if defined(USE_HORIZONTAL_BLUR) #if defined(USE_HORIZONTAL_BLUR)
vec2 direction = vec2(1.0, 0.0) * scale; vec2 direction = vec2(scale.x * 2.0, 0.0);
vec2 nudge = vec2(0.0, scale.y * 0.5);
#else // if defined(USE_VERTICAL_BLUR) #else // if defined(USE_VERTICAL_BLUR)
vec2 direction = vec2(0.0, 1.0) * scale; vec2 direction = vec2(0.0, scale.y * 2.0);
vec2 nudge = vec2(-scale.x * 0.5, 0.0);
#endif #endif
float depthCenter = zFar * getLinearDepth(depthMap, tex, zFarDivZNear); #if defined(USE_GAUSS)
vec2 centerSlope = vec2(dFdx(depthCenter), dFdy(depthCenter)) / vec2(dFdx(tex.x), dFdy(tex.y));
vec4 result = texture2D(imageMap, tex) * gauss[0]; vec4 result = texture2D(imageMap, tex) * gauss[0];
float total = gauss[0]; float total = gauss[0];
#else
vec4 result = texture2D(imageMap, tex);
float total = 1.0;
#endif
float zLimit = 5.0 / zFar;
int i, j; int i, j;
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
{ {
for (j = 1; j < GAUSS_SIZE; j++) for (j = 1; j < BLUR_SIZE; j++)
{ {
vec2 offset = direction * j; vec2 offset = direction * (float(j) - 0.25) + nudge;
float depthSample = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear); #if defined(USE_DEPTH)
float depthExpected = depthCenter + dot(centerSlope, offset); float depthSample = getLinearDepth(depthMap, tex + offset, zFarDivZNear);
if(abs(depthSample - depthExpected) < 5.0) float depthExpected = depthCenter + dot(slope, offset);
{ float useSample = float(abs(depthSample - depthExpected) < zLimit);
result += texture2D(imageMap, tex + offset) * gauss[j]; #else
total += gauss[j]; float useSample = 1.0;
} #endif
#if defined(USE_GAUSS)
result += texture2D(imageMap, tex + offset) * (gauss[j] * useSample);
total += gauss[j] * useSample;
#else
result += texture2D(imageMap, tex + offset) * useSample;
total += useSample;
#endif
nudge = -nudge;
} }
direction = -direction; direction = -direction;
} nudge = -nudge;
}
return result / total; return result / total;
} }
void main() void main()
{ {
gl_FragColor = depthGaussian1D(u_ScreenImageMap, u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y); gl_FragColor = depthGaussian1D(u_ScreenImageMap, u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y, u_ViewInfo.zw);
} }

View file

@ -1,12 +1,16 @@
attribute vec4 attr_Position; attribute vec4 attr_Position;
attribute vec4 attr_TexCoord0; attribute vec4 attr_TexCoord0;
uniform vec4 u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height
varying vec2 var_ScreenTex; varying vec2 var_ScreenTex;
void main() void main()
{ {
gl_Position = attr_Position; gl_Position = attr_Position;
var_ScreenTex = attr_TexCoord0.xy; vec2 wh = vec2(1.0) / u_ViewInfo.zw - vec2(1.0);
var_ScreenTex = (floor(attr_TexCoord0.xy * wh) + vec2(0.5)) * u_ViewInfo.zw;
//vec2 screenCoords = gl_Position.xy / gl_Position.w; //vec2 screenCoords = gl_Position.xy / gl_Position.w;
//var_ScreenTex = screenCoords * 0.5 + 0.5; //var_ScreenTex = screenCoords * 0.5 + 0.5;
} }

View file

@ -1,5 +1,7 @@
uniform sampler2D u_DiffuseMap; uniform sampler2D u_DiffuseMap;
uniform int u_AlphaTest;
varying vec2 var_Tex1; varying vec2 var_Tex1;
varying vec4 var_Color; varying vec4 var_Color;
@ -8,5 +10,23 @@ void main()
{ {
vec4 color = texture2D(u_DiffuseMap, var_Tex1); vec4 color = texture2D(u_DiffuseMap, var_Tex1);
gl_FragColor = color * var_Color; float alpha = color.a * var_Color.a;
if (u_AlphaTest == 1)
{
if (alpha == 0.0)
discard;
}
else if (u_AlphaTest == 2)
{
if (alpha >= 0.5)
discard;
}
else if (u_AlphaTest == 3)
{
if (alpha < 0.5)
discard;
}
gl_FragColor.rgb = color.rgb * var_Color.rgb;
gl_FragColor.a = alpha;
} }

View file

@ -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;

View file

@ -1,5 +1,7 @@
uniform sampler2D u_DiffuseMap; uniform sampler2D u_DiffuseMap;
uniform int u_AlphaTest;
varying vec2 var_DiffuseTex; varying vec2 var_DiffuseTex;
varying vec4 var_Color; varying vec4 var_Color;
@ -8,5 +10,24 @@ varying vec4 var_Color;
void main() void main()
{ {
vec4 color = texture2D(u_DiffuseMap, var_DiffuseTex); vec4 color = texture2D(u_DiffuseMap, var_DiffuseTex);
gl_FragColor = color * var_Color;
float alpha = color.a * var_Color.a;
if (u_AlphaTest == 1)
{
if (alpha == 0.0)
discard;
}
else if (u_AlphaTest == 2)
{
if (alpha >= 0.5)
discard;
}
else if (u_AlphaTest == 3)
{
if (alpha < 0.5)
discard;
}
gl_FragColor.rgb = color.rgb * var_Color.rgb;
gl_FragColor.a = alpha;
} }

View file

@ -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;

View file

@ -29,11 +29,6 @@ uniform samplerCube u_CubeMap;
uniform vec4 u_EnableTextures; uniform vec4 u_EnableTextures;
#endif #endif
#if defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT)
uniform vec3 u_DirectedLight;
uniform vec3 u_AmbientLight;
#endif
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
uniform vec3 u_PrimaryLightColor; uniform vec3 u_PrimaryLightColor;
uniform vec3 u_PrimaryLightAmbient; uniform vec3 u_PrimaryLightAmbient;
@ -50,19 +45,19 @@ uniform vec4 u_CubeMapInfo;
#endif #endif
#endif #endif
uniform int u_AlphaTest;
varying vec4 var_TexCoords; varying vec4 var_TexCoords;
varying vec4 var_Color; varying vec4 var_Color;
#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
varying vec4 var_ColorAmbient;
#endif
#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) #if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
#if defined(USE_VERT_TANGENT_SPACE)
varying vec4 var_Normal; varying vec4 var_Normal;
varying vec4 var_Tangent; varying vec4 var_Tangent;
varying vec4 var_Bitangent; varying vec4 var_Bitangent;
#else
varying vec3 var_Normal;
varying vec3 var_ViewDir;
#endif
#endif #endif
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
@ -94,6 +89,9 @@ float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap)
// current size of search window // current size of search window
float size = 1.0 / float(linearSearchSteps); float size = 1.0 / float(linearSearchSteps);
// adjust position if offset above surface
dp -= ds * r_parallaxMapOffset;
// current depth position // current depth position
float depth = 0.0; float depth = 0.0;
@ -146,160 +144,68 @@ float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap)
} }
#endif #endif
return bestDepth; return bestDepth - r_parallaxMapOffset;
} }
#endif
vec3 CalcDiffuse(vec3 diffuseAlbedo, vec3 N, vec3 L, vec3 E, float NE, float NL, float shininess) float LightRay(vec2 dp, vec2 ds, sampler2D normalMap)
{ {
#if defined(USE_OREN_NAYAR) || defined(USE_TRIACE_OREN_NAYAR) const int linearSearchSteps = 16;
float gamma = dot(E, L) - NE * NL;
float B = 2.22222 + 0.1 * shininess;
#if defined(USE_OREN_NAYAR)
float A = 1.0 - 1.0 / (2.0 + 0.33 * shininess);
gamma = clamp(gamma, 0.0, 1.0);
#endif
#if defined(USE_TRIACE_OREN_NAYAR)
float A = 1.0 - 1.0 / (2.0 + 0.65 * shininess);
if (gamma >= 0.0) // current size of search window
#endif float size = 1.0 / float(linearSearchSteps);
// current height from initial texel depth
float height = 0.0;
float startDepth = SampleDepth(normalMap, dp);
// find a collision or escape
for(int i = 0; i < linearSearchSteps - 1; ++i)
{ {
B = max(B * max(NL, NE), EPSILON); height += size;
if (startDepth < height)
return 1.0;
float t = SampleDepth(normalMap, dp + ds * height);
if (startDepth > t + height)
return 0.0;
} }
return diffuseAlbedo * (A + gamma / B);
#else
return diffuseAlbedo;
#endif
}
vec3 EnvironmentBRDF(float gloss, float NE, vec3 specular)
{
#if 1
// from http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
vec4 t = vec4( 1.0/0.96, 0.475, (0.0275 - 0.25 * 0.04)/0.96,0.25 ) * gloss;
t += vec4( 0.0, 0.0, (0.015 - 0.75 * 0.04)/0.96,0.75 );
float a0 = t.x * min( t.y, exp2( -9.28 * NE ) ) + t.z;
float a1 = t.w;
return clamp( a0 + specular * ( a1 - a0 ), 0.0, 1.0 );
#elif 0
// from http://seblagarde.wordpress.com/2011/08/17/hello-world/
return specular + CalcFresnel(NE) * clamp(vec3(gloss) - specular, 0.0, 1.0);
#else
// from http://advances.realtimerendering.com/s2011/Lazarov-Physically-Based-Lighting-in-Black-Ops%20%28Siggraph%202011%20Advances%20in%20Real-Time%20Rendering%20Course%29.pptx
return mix(specular.rgb, vec3(1.0), CalcFresnel(NE) / (4.0 - 3.0 * gloss));
#endif
}
float CalcBlinn(float NH, float shininess)
{
#if defined(USE_BLINN) || defined(USE_BLINN_FRESNEL)
// Normalized Blinn-Phong
float norm = shininess * 0.125 + 1.0;
#elif defined(USE_MCAULEY)
// Cook-Torrance as done by Stephen McAuley
// http://blog.selfshadow.com/publications/s2012-shading-course/mcauley/s2012_pbs_farcry3_notes_v2.pdf
float norm = shininess * 0.25 + 0.125;
#elif defined(USE_GOTANDA)
// Neumann-Neumann as done by Yoshiharu Gotanda
// http://research.tri-ace.com/Data/s2012_beyond_CourseNotes.pdf
float norm = shininess * 0.124858 + 0.269182;
#elif defined(USE_LAZAROV)
// Cook-Torrance as done by Dimitar Lazarov
// http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
float norm = shininess * 0.125 + 0.25;
#else
float norm = 1.0;
#endif
#if 0
// from http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/
float a = shininess + 0.775;
return norm * exp(a * NH - a);
#else
return norm * pow(NH, shininess);
#endif
}
float CalcGGX(float NH, float gloss)
{
// from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
float a_sq = exp2(gloss * -13.0 + 1.0);
float d = ((NH * NH) * (a_sq - 1.0) + 1.0);
return a_sq / (d * d);
}
float CalcFresnel(float EH)
{
#if 1
// From http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
// not accurate, but fast
return exp2(-10.0 * EH);
#elif 0
// From http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/
return exp2((-5.55473 * EH - 6.98316) * EH);
#elif 0
float blend = 1.0 - EH;
float blend2 = blend * blend;
blend *= blend2 * blend2;
return blend;
#else
return pow(1.0 - EH, 5.0);
#endif
}
float CalcVisibility(float NH, float NL, float NE, float EH, float gloss)
{
#if defined(USE_GOTANDA)
// Neumann-Neumann as done by Yoshiharu Gotanda
// http://research.tri-ace.com/Data/s2012_beyond_CourseNotes.pdf
return 1.0 / max(max(NL, NE), EPSILON);
#elif defined(USE_LAZAROV)
// Cook-Torrance as done by Dimitar Lazarov
// http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
float k = min(1.0, gloss + 0.545);
return 1.0 / (k * (EH * EH - 1.0) + 1.0);
#elif defined(USE_GGX)
float roughness = exp2(gloss * -6.5);
// Modified from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
// NL, NE in numerator factored out from cook-torrance
float k = roughness + 1.0;
k *= k * 0.125;
float k2 = 1.0 - k;
float invGeo1 = NL * k2 + k;
float invGeo2 = NE * k2 + k;
return 1.0 / (invGeo1 * invGeo2);
#else
return 1.0; return 1.0;
}
#endif
vec3 CalcDiffuse(vec3 diffuseAlbedo, float NH, float EH, float roughness)
{
#if defined(USE_BURLEY)
// modified from https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf
float fd90 = -0.5 + EH * EH * roughness;
float burley = 1.0 + fd90 * 0.04 / NH;
burley *= burley;
return diffuseAlbedo * burley;
#else
return diffuseAlbedo;
#endif #endif
} }
vec3 EnvironmentBRDF(float roughness, float NE, vec3 specular)
vec3 CalcSpecular(vec3 specular, float NH, float NL, float NE, float EH, float gloss, float shininess)
{ {
#if defined(USE_GGX) // from http://community.arm.com/servlet/JiveServlet/download/96891546-19496/siggraph2015-mmg-renaldas-slides.pdf
float distrib = CalcGGX(NH, gloss); float v = 1.0 - max(roughness, NE);
#else v *= v * v;
float distrib = CalcBlinn(NH, shininess); return vec3(v) + specular;
#endif }
#if defined(USE_BLINN) vec3 CalcSpecular(vec3 specular, float NH, float EH, float roughness)
vec3 fSpecular = specular; {
#else // from http://community.arm.com/servlet/JiveServlet/download/96891546-19496/siggraph2015-mmg-renaldas-slides.pdf
vec3 fSpecular = mix(specular, vec3(1.0), CalcFresnel(EH)); float rr = roughness*roughness;
#endif float rrrr = rr*rr;
float d = (NH * NH) * (rrrr - 1.0) + 1.0;
float vis = CalcVisibility(NH, NL, NE, EH, gloss); float v = (EH * EH) * (roughness + 0.5) + EPSILON;
return specular * (rrrr / (4.0 * d * d * v));
return fSpecular * (distrib * vis);
} }
@ -319,61 +225,68 @@ float CalcLightAttenuation(float point, float normDist)
return attenuation; return attenuation;
} }
// from http://www.thetenthplanet.de/archives/1180 #if defined(USE_BOX_CUBEMAP_PARALLAX)
mat3 cotangent_frame( vec3 N, vec3 p, vec2 uv ) vec4 hitCube(vec3 ray, vec3 pos, vec3 invSize, float lod, samplerCube tex)
{ {
// get edge vectors of the pixel triangle // find any hits on cubemap faces facing the camera
vec3 dp1 = dFdx( p ); vec3 scale = (sign(ray) - pos) / ray;
vec3 dp2 = dFdy( p );
vec2 duv1 = dFdx( uv );
vec2 duv2 = dFdy( uv );
// solve the linear system // find the nearest hit
vec3 dp2perp = cross( dp2, N ); float minScale = min(min(scale.x, scale.y), scale.z);
vec3 dp1perp = cross( N, dp1 );
vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;
vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;
// construct a scale-invariant frame // if the nearest hit is behind the camera, ignore
float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) ); // should not be necessary as long as pos is inside the cube
return mat3( T * invmax, B * invmax, N ); //if (minScale < 0.0)
//return vec4(0.0);
// calculate the hit position, that's our texture coordinates
vec3 tc = pos + ray * minScale;
// if the texture coordinates are outside the cube, ignore
// necessary since we're not fading out outside the cube
if (any(greaterThan(abs(tc), vec3(1.00001))))
return vec4(0.0);
// fade out when approaching the cubemap edges
//vec3 fade3 = abs(pos);
//float fade = max(max(fade3.x, fade3.y), fade3.z);
//fade = clamp(1.0 - fade, 0.0, 1.0);
//return vec4(textureCubeLod(tex, tc, lod).rgb * fade, fade);
return vec4(textureCubeLod(tex, tc, lod).rgb, 1.0);
} }
#endif
void main() void main()
{ {
vec3 viewDir, lightColor, ambientColor; vec3 viewDir, lightColor, ambientColor, reflectance;
vec3 L, N, E, H; vec3 L, N, E, H;
float NL, NH, NE, EH, attenuation; float NL, NH, NE, EH, attenuation;
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
#if defined(USE_VERT_TANGENT_SPACE) vec3 surfNormal = (!gl_FrontFacing ? var_Normal : -var_Normal).xyz;
mat3 tangentToWorld = mat3(var_Tangent.xyz, var_Bitangent.xyz, var_Normal.xyz); mat3 tangentToWorld = mat3(var_Tangent.xyz, var_Bitangent.xyz, surfNormal);
viewDir = vec3(var_Normal.w, var_Tangent.w, var_Bitangent.w); viewDir = vec3(var_Normal.w, var_Tangent.w, var_Bitangent.w);
#else
mat3 tangentToWorld = cotangent_frame(var_Normal, -var_ViewDir, var_TexCoords.xy);
viewDir = var_ViewDir;
#endif
E = normalize(viewDir); E = normalize(viewDir);
L = var_LightDir.xyz;
#if defined(USE_DELUXEMAP)
L += (texture2D(u_DeluxeMap, var_TexCoords.zw).xyz - vec3(0.5)) * u_EnableTextures.y;
#endif
float sqrLightDist = dot(L, L);
#endif #endif
lightColor = var_Color.rgb;
#if defined(USE_LIGHTMAP) #if defined(USE_LIGHTMAP)
vec4 lightmapColor = texture2D(u_LightMap, var_TexCoords.zw); vec4 lightmapColor = texture2D(u_LightMap, var_TexCoords.zw);
#if defined(RGBM_LIGHTMAP) #if defined(RGBM_LIGHTMAP)
lightmapColor.rgb *= lightmapColor.a; lightmapColor.rgb *= lightmapColor.a;
#endif #endif
#if defined(USE_PBR) && !defined(USE_FAST_LIGHT)
lightmapColor.rgb *= lightmapColor.rgb;
#endif
lightColor *= lightmapColor.rgb;
#endif #endif
vec2 texCoords = var_TexCoords.xy; vec2 texCoords = var_TexCoords.xy;
#if defined(USE_PARALLAXMAP) #if defined(USE_PARALLAXMAP)
vec3 offsetDir = viewDir * tangentToWorld; vec3 offsetDir = E * tangentToWorld;
offsetDir.xy *= -u_NormalScale.a / offsetDir.z; offsetDir.xy *= -u_NormalScale.a / offsetDir.z;
@ -381,19 +294,35 @@ void main()
#endif #endif
vec4 diffuse = texture2D(u_DiffuseMap, texCoords); vec4 diffuse = texture2D(u_DiffuseMap, texCoords);
float alpha = diffuse.a * var_Color.a;
if (u_AlphaTest == 1)
{
if (alpha == 0.0)
discard;
}
else if (u_AlphaTest == 2)
{
if (alpha >= 0.5)
discard;
}
else if (u_AlphaTest == 3)
{
if (alpha < 0.5)
discard;
}
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
#if defined(USE_LIGHTMAP) L = var_LightDir.xyz;
lightColor = lightmapColor.rgb * var_Color.rgb; #if defined(USE_DELUXEMAP)
ambientColor = vec3(0.0); L += (texture2D(u_DeluxeMap, var_TexCoords.zw).xyz - vec3(0.5)) * u_EnableTextures.y;
attenuation = 1.0; #endif
#elif defined(USE_LIGHT_VECTOR) float sqrLightDist = dot(L, L);
lightColor = u_DirectedLight * var_Color.rgb; L /= sqrt(sqrLightDist);
ambientColor = u_AmbientLight * var_Color.rgb;
#if defined(USE_LIGHT_VECTOR)
attenuation = CalcLightAttenuation(float(var_LightDir.w > 0.0), var_LightDir.w / sqrLightDist); attenuation = CalcLightAttenuation(float(var_LightDir.w > 0.0), var_LightDir.w / sqrLightDist);
#elif defined(USE_LIGHT_VERTEX) #else
lightColor = var_Color.rgb;
ambientColor = vec3(0.0);
attenuation = 1.0; attenuation = 1.0;
#endif #endif
@ -407,39 +336,36 @@ void main()
N.z = sqrt(clamp((0.25 - N.x * N.x) - N.y * N.y, 0.0, 1.0)); N.z = sqrt(clamp((0.25 - N.x * N.x) - N.y * N.y, 0.0, 1.0));
N = tangentToWorld * N; N = tangentToWorld * N;
#else #else
N = var_Normal.xyz; N = surfNormal;
#endif #endif
N = normalize(N); N = normalize(N);
L /= sqrt(sqrLightDist);
#if defined(USE_SHADOWMAP) #if defined(USE_SHADOWMAP)
vec2 shadowTex = gl_FragCoord.xy * r_FBufScale; vec2 shadowTex = gl_FragCoord.xy * r_FBufScale;
float shadowValue = texture2D(u_ShadowMap, shadowTex).r; float shadowValue = texture2D(u_ShadowMap, shadowTex).r;
// surfaces not facing the light are always shadowed // surfaces not facing the light are always shadowed
shadowValue *= float(dot(var_Normal.xyz, var_PrimaryLightDir.xyz) > 0.0); shadowValue *= clamp(dot(N, var_PrimaryLightDir.xyz), 0.0, 1.0);
#if defined(SHADOWMAP_MODULATE) #if defined(SHADOWMAP_MODULATE)
//vec3 shadowColor = min(u_PrimaryLightAmbient, lightColor); lightColor *= shadowValue * (1.0 - u_PrimaryLightAmbient.r) + u_PrimaryLightAmbient.r;
vec3 shadowColor = u_PrimaryLightAmbient * lightColor;
#if 0
// Only shadow when the world light is parallel to the primary light
shadowValue = 1.0 + (shadowValue - 1.0) * clamp(dot(L, var_PrimaryLightDir.xyz), 0.0, 1.0);
#endif
lightColor = mix(shadowColor, lightColor, shadowValue);
#endif #endif
#endif #endif
#if defined(r_lightGamma) #if defined(USE_PARALLAXMAP) && defined(USE_PARALLAXMAP_SHADOWS)
lightColor = pow(lightColor, vec3(r_lightGamma)); offsetDir = L * tangentToWorld;
ambientColor = pow(ambientColor, vec3(r_lightGamma)); offsetDir.xy *= u_NormalScale.a / offsetDir.z;
lightColor *= LightRay(texCoords, offsetDir.xy, u_NormalMap);
#endif #endif
#if defined(USE_LIGHTMAP) || defined(USE_LIGHT_VERTEX)
#if !defined(USE_LIGHT_VECTOR)
ambientColor = lightColor; ambientColor = lightColor;
float surfNL = clamp(dot(var_Normal.xyz, L), 0.0, 1.0); float surfNL = clamp(dot(surfNormal, L), 0.0, 1.0);
// reserve 25% ambient to avoid black areas on normalmaps
lightColor *= 0.75;
// Scale the incoming light to compensate for the baked-in light angle // Scale the incoming light to compensate for the baked-in light angle
// attenuation. // attenuation.
@ -447,83 +373,71 @@ void main()
// Recover any unused light as ambient, in case attenuation is over 4x or // Recover any unused light as ambient, in case attenuation is over 4x or
// light is below the surface // light is below the surface
ambientColor = clamp(ambientColor - lightColor * surfNL, 0.0, 1.0); ambientColor = max(ambientColor - lightColor * surfNL, vec3(0.0));
#else
ambientColor = var_ColorAmbient.rgb;
#endif #endif
vec3 reflectance;
NL = clamp(dot(N, L), 0.0, 1.0); NL = clamp(dot(N, L), 0.0, 1.0);
NE = clamp(dot(N, E), 0.0, 1.0); NE = clamp(dot(N, E), 0.0, 1.0);
H = normalize(L + E);
EH = clamp(dot(E, H), 0.0, 1.0);
NH = clamp(dot(N, H), 0.0, 1.0);
#if defined(USE_SPECULARMAP) #if defined(USE_SPECULARMAP)
vec4 specular = texture2D(u_SpecularMap, texCoords); vec4 specular = texture2D(u_SpecularMap, texCoords);
#else #else
vec4 specular = vec4(1.0); vec4 specular = vec4(1.0);
#endif #endif
specular *= u_SpecularScale; specular *= u_SpecularScale;
#if defined(r_materialGamma) #if defined(USE_PBR)
diffuse.rgb = pow(diffuse.rgb, vec3(r_materialGamma)); diffuse.rgb *= diffuse.rgb;
specular.rgb = pow(specular.rgb, vec3(r_materialGamma));
#endif #endif
float gloss = specular.a; #if defined(USE_PBR)
float shininess = exp2(gloss * 13.0); // diffuse rgb is base color
// specular red is gloss
#if defined(SPECULAR_IS_METALLIC) // specular green is metallicness
// diffuse is actually base color, and red of specular is metallicness float gloss = specular.r;
float metallic = specular.r; float metal = specular.g;
specular.rgb = metal * diffuse.rgb + vec3(0.04 - 0.04 * metal);
specular.rgb = (0.96 * metallic) * diffuse.rgb + vec3(0.04); diffuse.rgb *= 1.0 - metal;
diffuse.rgb *= 1.0 - metallic;
#else #else
// diffuse rgb is diffuse
// specular rgb is specular reflectance at normal incidence
// specular alpha is gloss
float gloss = specular.a;
// adjust diffuse by specular reflectance, to maintain energy conservation // adjust diffuse by specular reflectance, to maintain energy conservation
diffuse.rgb *= vec3(1.0) - specular.rgb; diffuse.rgb *= vec3(1.0) - specular.rgb;
#endif #endif
reflectance = CalcDiffuse(diffuse.rgb, N, L, E, NE, NL, shininess); #if defined(GLOSS_IS_GLOSS)
float roughness = exp2(-3.0 * gloss);
#elif defined(GLOSS_IS_SMOOTHNESS)
float roughness = 1.0 - gloss;
#elif defined(GLOSS_IS_ROUGHNESS)
float roughness = gloss;
#elif defined(GLOSS_IS_SHININESS)
float roughness = pow(2.0 / (8190.0 * gloss + 2.0), 0.25);
#endif
#if defined(r_deluxeSpecular) || defined(USE_LIGHT_VECTOR) reflectance = CalcDiffuse(diffuse.rgb, NH, EH, roughness);
float adjGloss = gloss;
float adjShininess = shininess;
#if !defined(USE_LIGHT_VECTOR) #if defined(r_deluxeSpecular)
adjGloss *= r_deluxeSpecular; #if defined(USE_LIGHT_VECTOR)
adjShininess = exp2(adjGloss * 13.0); reflectance += CalcSpecular(specular.rgb, NH, EH, roughness) * r_deluxeSpecular;
#endif
H = normalize(L + E);
EH = clamp(dot(E, H), 0.0, 1.0);
NH = clamp(dot(N, H), 0.0, 1.0);
#if !defined(USE_LIGHT_VECTOR)
reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjGloss, adjShininess) * r_deluxeSpecular;
#else #else
reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjGloss, adjShininess); reflectance += CalcSpecular(specular.rgb, NH, EH, pow(roughness, r_deluxeSpecular));
#endif #endif
#endif #endif
gl_FragColor.rgb = lightColor * reflectance * (attenuation * NL); gl_FragColor.rgb = lightColor * reflectance * (attenuation * NL);
gl_FragColor.rgb += ambientColor * diffuse.rgb;
#if 0
vec3 aSpecular = EnvironmentBRDF(gloss, NE, specular.rgb);
// do ambient as two hemisphere lights, one straight up one straight down
float hemiDiffuseUp = N.z * 0.5 + 0.5;
float hemiDiffuseDown = 1.0 - hemiDiffuseUp;
float hemiSpecularUp = mix(hemiDiffuseUp, float(N.z >= 0.0), gloss);
float hemiSpecularDown = 1.0 - hemiSpecularUp;
gl_FragColor.rgb += ambientColor * 0.75 * (diffuse.rgb * hemiDiffuseUp + aSpecular * hemiSpecularUp);
gl_FragColor.rgb += ambientColor * 0.25 * (diffuse.rgb * hemiDiffuseDown + aSpecular * hemiSpecularDown);
#else
gl_FragColor.rgb += ambientColor * (diffuse.rgb + specular.rgb);
#endif
#if defined(USE_CUBEMAP) #if defined(USE_CUBEMAP)
reflectance = EnvironmentBRDF(gloss, NE, specular.rgb); reflectance = EnvironmentBRDF(roughness, NE, specular.rgb);
vec3 R = reflect(E, N); vec3 R = reflect(E, N);
@ -531,15 +445,19 @@ void main()
// from http://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ // from http://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
vec3 parallax = u_CubeMapInfo.xyz + u_CubeMapInfo.w * viewDir; vec3 parallax = u_CubeMapInfo.xyz + u_CubeMapInfo.w * viewDir;
vec3 cubeLightColor = textureCubeLod(u_CubeMap, R + parallax, 7.0 - gloss * 7.0).rgb * u_EnableTextures.w; #if defined(USE_BOX_CUBEMAP_PARALLAX)
vec3 cubeLightColor = hitCube(R * u_CubeMapInfo.w, parallax, u_CubeMapInfo.www, ROUGHNESS_MIPS * roughness, u_CubeMap).rgb * u_EnableTextures.w;
#else
vec3 cubeLightColor = textureCubeLod(u_CubeMap, R + parallax, ROUGHNESS_MIPS * roughness).rgb * u_EnableTextures.w;
#endif
// normalize cubemap based on lowest mip (~diffuse) // normalize cubemap based on last roughness mip (~diffuse)
// multiplying cubemap values by lighting below depends on either this or the cubemap being normalized at generation // multiplying cubemap values by lighting below depends on either this or the cubemap being normalized at generation
//vec3 cubeLightDiffuse = max(textureCubeLod(u_CubeMap, N, 6.0).rgb, 0.5 / 255.0); //vec3 cubeLightDiffuse = max(textureCubeLod(u_CubeMap, N, ROUGHNESS_MIPS).rgb, 0.5 / 255.0);
//cubeLightColor /= dot(cubeLightDiffuse, vec3(0.2125, 0.7154, 0.0721)); //cubeLightColor /= dot(cubeLightDiffuse, vec3(0.2125, 0.7154, 0.0721));
#if defined(r_framebufferGamma) #if defined(USE_PBR)
cubeLightColor = pow(cubeLightColor, vec3(r_framebufferGamma)); cubeLightColor *= cubeLightColor;
#endif #endif
// multiply cubemap values by lighting // multiply cubemap values by lighting
@ -549,7 +467,7 @@ void main()
gl_FragColor.rgb += cubeLightColor * reflectance; gl_FragColor.rgb += cubeLightColor * reflectance;
#endif #endif
#if defined(USE_PRIMARY_LIGHT) #if defined(USE_PRIMARY_LIGHT) || defined(SHADOWMAP_MODULATE)
vec3 L2, H2; vec3 L2, H2;
float NL2, EH2, NH2; float NL2, EH2, NH2;
@ -560,20 +478,19 @@ void main()
//L2 /= sqrt(sqrLightDist); //L2 /= sqrt(sqrLightDist);
NL2 = clamp(dot(N, L2), 0.0, 1.0); NL2 = clamp(dot(N, L2), 0.0, 1.0);
H2 = normalize(L2 + E); H2 = normalize(L2 + E);
EH2 = clamp(dot(E, H2), 0.0, 1.0); EH2 = clamp(dot(E, H2), 0.0, 1.0);
NH2 = clamp(dot(N, H2), 0.0, 1.0); NH2 = clamp(dot(N, H2), 0.0, 1.0);
reflectance = CalcDiffuse(diffuse.rgb, N, L2, E, NE, NL2, shininess); reflectance = CalcSpecular(specular.rgb, NH2, EH2, roughness);
reflectance += CalcSpecular(specular.rgb, NH2, NL2, NE, EH2, gloss, shininess);
lightColor = u_PrimaryLightColor * var_Color.rgb; // bit of a hack, with modulated shadowmaps, ignore diffuse
#if !defined(SHADOWMAP_MODULATE)
#if defined(r_lightGamma) reflectance += CalcDiffuse(diffuse.rgb, NH2, EH2, roughness);
lightColor = pow(lightColor, vec3(r_lightGamma));
#endif #endif
lightColor = u_PrimaryLightColor;
#if defined(USE_SHADOWMAP) #if defined(USE_SHADOWMAP)
lightColor *= shadowValue; lightColor *= shadowValue;
#endif #endif
@ -581,30 +498,24 @@ void main()
// enable when point lights are supported as primary lights // enable when point lights are supported as primary lights
//lightColor *= CalcLightAttenuation(float(u_PrimaryLightDir.w > 0.0), u_PrimaryLightDir.w / sqrLightDist); //lightColor *= CalcLightAttenuation(float(u_PrimaryLightDir.w > 0.0), u_PrimaryLightDir.w / sqrLightDist);
#if defined(USE_PARALLAXMAP) && defined(USE_PARALLAXMAP_SHADOWS)
offsetDir = L2 * tangentToWorld;
offsetDir.xy *= u_NormalScale.a / offsetDir.z;
lightColor *= LightRay(texCoords, offsetDir.xy, u_NormalMap);
#endif
gl_FragColor.rgb += lightColor * reflectance * NL2; gl_FragColor.rgb += lightColor * reflectance * NL2;
#endif #endif
#if defined(USE_PBR)
gl_FragColor.rgb = sqrt(gl_FragColor.rgb);
#endif
#else #else
lightColor = var_Color.rgb;
#if defined(USE_LIGHTMAP)
lightColor *= lightmapColor.rgb;
#endif
#if defined(r_lightGamma)
lightColor = pow(lightColor, vec3(r_lightGamma));
#endif
#if defined(r_materialGamma)
diffuse.rgb = pow(diffuse.rgb, vec3(r_materialGamma));
#endif
gl_FragColor.rgb = diffuse.rgb * lightColor; gl_FragColor.rgb = diffuse.rgb * lightColor;
#endif #endif
#if defined(r_framebufferGamma) gl_FragColor.a = alpha;
gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / r_framebufferGamma));
#endif
gl_FragColor.a = diffuse.a * var_Color.a;
} }

View file

@ -6,16 +6,15 @@ attribute vec4 attr_Color;
attribute vec3 attr_Position; attribute vec3 attr_Position;
attribute vec3 attr_Normal; attribute vec3 attr_Normal;
#if defined(USE_VERT_TANGENT_SPACE)
attribute vec4 attr_Tangent; attribute vec4 attr_Tangent;
#endif
#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;
#if defined(USE_VERT_TANGENT_SPACE)
attribute vec4 attr_Tangent2; attribute vec4 attr_Tangent2;
#endif #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)
@ -52,15 +51,15 @@ 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)
uniform vec4 u_LightOrigin; uniform vec4 u_LightOrigin;
uniform float u_LightRadius; uniform float u_LightRadius;
#if defined(USE_FAST_LIGHT)
uniform vec3 u_DirectedLight; uniform vec3 u_DirectedLight;
uniform vec3 u_AmbientLight; uniform vec3 u_AmbientLight;
#endif
#endif #endif
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
@ -71,16 +70,14 @@ uniform float u_PrimaryLightRadius;
varying vec4 var_TexCoords; varying vec4 var_TexCoords;
varying vec4 var_Color; varying vec4 var_Color;
#if defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT)
varying vec4 var_ColorAmbient;
#endif
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
#if defined(USE_VERT_TANGENT_SPACE)
varying vec4 var_Normal; varying vec4 var_Normal;
varying vec4 var_Tangent; varying vec4 var_Tangent;
varying vec4 var_Bitangent; varying vec4 var_Bitangent;
#else
varying vec3 var_Normal;
varying vec3 var_ViewDir;
#endif
#endif #endif
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
@ -156,13 +153,25 @@ 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);
#if defined(USE_VERT_TANGENT_SPACE) && 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;
#if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
vec3 tangent = attr_Tangent.xyz; vec3 tangent = attr_Tangent.xyz;
#endif #endif
#endif #endif
@ -184,12 +193,12 @@ void main()
#if defined(USE_MODELMATRIX) #if defined(USE_MODELMATRIX)
position = (u_ModelMatrix * vec4(position, 1.0)).xyz; position = (u_ModelMatrix * vec4(position, 1.0)).xyz;
normal = (u_ModelMatrix * vec4(normal, 0.0)).xyz; normal = (u_ModelMatrix * vec4(normal, 0.0)).xyz;
#if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
tangent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz; tangent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz;
#endif #endif
#endif #endif
#if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
vec3 bitangent = cross(normal, tangent) * attr_Tangent.w; vec3 bitangent = cross(normal, tangent) * attr_Tangent.w;
#endif #endif
@ -208,12 +217,24 @@ void main()
var_Color = u_VertColor * attr_Color + u_BaseColor; var_Color = u_VertColor * attr_Color + u_BaseColor;
#if defined(USE_LIGHT_VECTOR) && defined(USE_FAST_LIGHT) #if defined(USE_LIGHT_VECTOR)
#if defined(USE_FAST_LIGHT)
float sqrLightDist = dot(L, L); float sqrLightDist = dot(L, L);
float attenuation = CalcLightAttenuation(u_LightOrigin.w, u_LightRadius * u_LightRadius / sqrLightDist);
float NL = clamp(dot(normalize(normal), L) / sqrt(sqrLightDist), 0.0, 1.0); float NL = clamp(dot(normalize(normal), L) / sqrt(sqrLightDist), 0.0, 1.0);
float attenuation = CalcLightAttenuation(u_LightOrigin.w, u_LightRadius * u_LightRadius / sqrLightDist);
var_Color.rgb *= u_DirectedLight * (attenuation * NL) + u_AmbientLight; var_Color.rgb *= u_DirectedLight * (attenuation * NL) + u_AmbientLight;
#else
var_ColorAmbient.rgb = u_AmbientLight * var_Color.rgb;
var_Color.rgb *= u_DirectedLight;
#if defined(USE_PBR)
var_ColorAmbient.rgb *= var_ColorAmbient.rgb;
#endif
#endif
#endif
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) && defined(USE_PBR)
var_Color.rgb *= var_Color.rgb;
#endif #endif
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
@ -234,14 +255,9 @@ void main()
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
vec3 viewDir = u_ViewOrigin - position; vec3 viewDir = u_ViewOrigin - position;
#if defined(USE_VERT_TANGENT_SPACE)
// store view direction in tangent space to save on varyings // store view direction in tangent space to save on varyings
var_Normal = vec4(normal, viewDir.x); var_Normal = vec4(normal, viewDir.x);
var_Tangent = vec4(tangent, viewDir.y); var_Tangent = vec4(tangent, viewDir.y);
var_Bitangent = vec4(bitangent, viewDir.z); var_Bitangent = vec4(bitangent, viewDir.z);
#else
var_Normal = normal;
var_ViewDir = viewDir;
#endif
#endif #endif
} }

View file

@ -8,12 +8,6 @@ uniform float u_LightRadius;
varying vec3 var_Position; varying vec3 var_Position;
varying vec3 var_Normal; varying vec3 var_Normal;
float sampleDistMap(sampler2D texMap, vec2 uv, float scale)
{
vec3 distv = texture2D(texMap, uv).xyz;
return dot(distv, vec3(1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0)) * scale;
}
void main() void main()
{ {
vec3 lightToPos = var_Position - u_LightOrigin.xyz; vec3 lightToPos = var_Position - u_LightOrigin.xyz;
@ -57,42 +51,28 @@ void main()
#endif #endif
intensity *= fade; intensity *= fade;
#if defined(USE_PCF)
float part; float part;
#if defined(USE_PCF)
dist = sampleDistMap(u_ShadowMap, st + vec2(-1.0/512.0, -1.0/512.0), u_LightRadius); part = float(texture2D(u_ShadowMap, st + vec2(-1.0/512.0, -1.0/512.0)).r != 1.0);
part = max(sign(lightDist - dist), 0.0); part += float(texture2D(u_ShadowMap, st + vec2( 1.0/512.0, -1.0/512.0)).r != 1.0);
part += float(texture2D(u_ShadowMap, st + vec2(-1.0/512.0, 1.0/512.0)).r != 1.0);
part += float(texture2D(u_ShadowMap, st + vec2( 1.0/512.0, 1.0/512.0)).r != 1.0);
#else
part = float(texture2D(u_ShadowMap, st).r != 1.0);
#endif
dist = sampleDistMap(u_ShadowMap, st + vec2( 1.0/512.0, -1.0/512.0), u_LightRadius);
part += max(sign(lightDist - dist), 0.0);
dist = sampleDistMap(u_ShadowMap, st + vec2(-1.0/512.0, 1.0/512.0), u_LightRadius);
part += max(sign(lightDist - dist), 0.0);
dist = sampleDistMap(u_ShadowMap, st + vec2( 1.0/512.0, 1.0/512.0), u_LightRadius);
part += max(sign(lightDist - dist), 0.0);
#if defined(USE_DISCARD)
if (part <= 0.0) if (part <= 0.0)
{ {
discard; discard;
} }
#endif
#if defined(USE_PCF)
intensity *= part * 0.25; intensity *= part * 0.25;
#else #else
dist = sampleDistMap(u_ShadowMap, st, u_LightRadius); intensity *= part;
#if defined(USE_DISCARD)
if (lightDist - dist <= 0.0)
{
discard;
}
#endif
intensity *= max(sign(lightDist - dist), 0.0);
#endif #endif
gl_FragColor.rgb = vec3(0); gl_FragColor.rgb = vec3(0);
gl_FragColor.a = clamp(intensity, 0.0, 0.75); gl_FragColor.a = clamp(intensity, 0.0, 0.75);
} }

View file

@ -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);

View file

@ -52,10 +52,10 @@ float PCF(const sampler2DShadow shadowmap, const vec2 st, const float dist)
offset.y += offset.x; offset.y += offset.x;
if (offset.y > 1.1) offset.y = 0.0; if (offset.y > 1.1) offset.y = 0.0;
mult = shadow2D(shadowmap, vec3(st + (offset + vec2(-1.5, 0.5)) * scale, dist)).r mult = shadow2D(shadowmap, vec3(st + (offset + vec2(-1.5, 0.5)) * scale, dist))
+ shadow2D(shadowmap, vec3(st + (offset + vec2( 0.5, 0.5)) * scale, dist)).r + shadow2D(shadowmap, vec3(st + (offset + vec2( 0.5, 0.5)) * scale, dist))
+ shadow2D(shadowmap, vec3(st + (offset + vec2(-1.5, -1.5)) * scale, dist)).r + shadow2D(shadowmap, vec3(st + (offset + vec2(-1.5, -1.5)) * scale, dist))
+ shadow2D(shadowmap, vec3(st + (offset + vec2( 0.5, -1.5)) * scale, dist)).r; + shadow2D(shadowmap, vec3(st + (offset + vec2( 0.5, -1.5)) * scale, dist));
mult *= 0.25; mult *= 0.25;
#endif #endif
@ -66,23 +66,23 @@ float PCF(const sampler2DShadow shadowmap, const vec2 st, const float dist)
float cosr = cos(r) * scale; float cosr = cos(r) * scale;
mat2 rmat = mat2(cosr, sinr, -sinr, cosr); mat2 rmat = mat2(cosr, sinr, -sinr, cosr);
mult = shadow2D(shadowmap, vec3(st + rmat * vec2(-0.7055767, 0.196515), dist)).r; mult = shadow2D(shadowmap, vec3(st + rmat * vec2(-0.7055767, 0.196515), dist));
mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.3524343, -0.7791386), dist)).r; mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.3524343, -0.7791386), dist));
mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.2391056, 0.9189604), dist)).r; mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.2391056, 0.9189604), dist));
#if defined(USE_SHADOW_FILTER2) #if defined(USE_SHADOW_FILTER2)
mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.07580382, -0.09224417), dist)).r; mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.07580382, -0.09224417), dist));
mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.5784913, -0.002528916), dist)).r; mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.5784913, -0.002528916), dist));
mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.192888, 0.4064181), dist)).r; mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.192888, 0.4064181), dist));
mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.6335801, -0.5247476), dist)).r; mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.6335801, -0.5247476), dist));
mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.5579782, 0.7491854), dist)).r; mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.5579782, 0.7491854), dist));
mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.7320465, 0.6317794), dist)).r; mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.7320465, 0.6317794), dist));
mult *= 0.11111; mult *= 0.11111;
#else #else
mult *= 0.33333; mult *= 0.33333;
#endif #endif
#else #else
mult = shadow2D(shadowmap, vec3(st, dist)).r; mult = shadow2D(shadowmap, vec3(st, dist));
#endif #endif
return mult; return mult;

View file

@ -1,9 +1,10 @@
uniform sampler2D u_ScreenDepthMap; uniform sampler2D u_ScreenDepthMap;
uniform vec4 u_ViewInfo; // zfar / znear, zfar uniform vec4 u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height
varying vec2 var_ScreenTex; varying vec2 var_ScreenTex;
#if 0
vec2 poissonDisc[9] = vec2[9]( vec2 poissonDisc[9] = vec2[9](
vec2(-0.7055767, 0.196515), vec2(0.3524343, -0.7791386), vec2(-0.7055767, 0.196515), vec2(0.3524343, -0.7791386),
vec2(0.2391056, 0.9189604), vec2(-0.07580382, -0.09224417), vec2(0.2391056, 0.9189604), vec2(-0.07580382, -0.09224417),
@ -11,6 +12,9 @@ vec2(0.5784913, -0.002528916), vec2(0.192888, 0.4064181),
vec2(-0.6335801, -0.5247476), vec2(-0.5579782, 0.7491854), vec2(-0.6335801, -0.5247476), vec2(-0.5579782, 0.7491854),
vec2(0.7320465, 0.6317794) vec2(0.7320465, 0.6317794)
); );
#endif
#define NUM_SAMPLES 3
// Input: It uses texture coords as the random number seed. // Input: It uses texture coords as the random number seed.
// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive. // Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive.
@ -39,48 +43,59 @@ mat2 randomRotation( const vec2 p )
float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear) float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear)
{ {
float sampleZDivW = texture2D(depthMap, tex).r; float sampleZDivW = texture2D(depthMap, tex).r;
return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW); return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW);
} }
float ambientOcclusion(sampler2D depthMap, const vec2 tex, const float zFarDivZNear, const float zFar) float ambientOcclusion(sampler2D depthMap, const vec2 tex, const float zFarDivZNear, const float zFar, const vec2 scale)
{ {
float result = 0; vec2 poissonDisc[9];
float sampleZ = zFar * getLinearDepth(depthMap, tex, zFarDivZNear); poissonDisc[0] = vec2(-0.7055767, 0.196515);
poissonDisc[1] = vec2(0.3524343, -0.7791386);
poissonDisc[2] = vec2(0.2391056, 0.9189604);
poissonDisc[3] = vec2(-0.07580382, -0.09224417);
poissonDisc[4] = vec2(0.5784913, -0.002528916);
poissonDisc[5] = vec2(0.192888, 0.4064181);
poissonDisc[6] = vec2(-0.6335801, -0.5247476);
poissonDisc[7] = vec2(-0.5579782, 0.7491854);
poissonDisc[8] = vec2(0.7320465, 0.6317794);
vec2 expectedSlope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y)); float result = 0.0;
if (length(expectedSlope) > 5000.0) float sampleZ = getLinearDepth(depthMap, tex, zFarDivZNear);
float scaleZ = zFarDivZNear * sampleZ;
vec2 slope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y));
if (length(slope) * zFar > 5000.0)
return 1.0; return 1.0;
vec2 offsetScale = vec2(3.0 / sampleZ); vec2 offsetScale = vec2(scale * 1024.0 / scaleZ);
mat2 rmat = randomRotation(tex); mat2 rmat = randomRotation(tex);
float invZFar = 1.0 / zFar;
float zLimit = 20.0 * invZFar;
int i; int i;
for (i = 0; i < 3; i++) for (i = 0; i < NUM_SAMPLES; i++)
{ {
vec2 offset = rmat * poissonDisc[i] * offsetScale; vec2 offset = rmat * poissonDisc[i] * offsetScale;
float sampleZ2 = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear); float sampleDiff = getLinearDepth(depthMap, tex + offset, zFarDivZNear) - sampleZ;
if (abs(sampleZ - sampleZ2) > 20.0) bool s1 = abs(sampleDiff) > zLimit;
result += 1.0; bool s2 = sampleDiff + invZFar > dot(slope, offset);
else result += float(s1 || s2);
{
float expectedZ = sampleZ + dot(expectedSlope, offset);
result += step(expectedZ - 1.0, sampleZ2);
}
} }
result *= 0.33333; result *= 1.0 / float(NUM_SAMPLES);
return result; return result;
} }
void main() void main()
{ {
float result = ambientOcclusion(u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y); float result = ambientOcclusion(u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y, u_ViewInfo.wz);
gl_FragColor = vec4(vec3(result), 1.0); gl_FragColor = vec4(vec3(result), 1.0);
} }

View file

@ -28,8 +28,8 @@ void main()
{ {
vec4 color = texture2D(u_TextureMap, var_TexCoords) * u_Color; vec4 color = texture2D(u_TextureMap, var_TexCoords) * u_Color;
#if defined(r_framebufferGamma) #if defined(USE_PBR)
color.rgb = pow(color.rgb, vec3(r_framebufferGamma)); color.rgb *= color.rgb;
#endif #endif
vec3 minAvgMax = texture2D(u_LevelsMap, var_TexCoords).rgb; vec3 minAvgMax = texture2D(u_LevelsMap, var_TexCoords).rgb;
@ -46,9 +46,12 @@ void main()
color.rgb = clamp(color.rgb * var_InvWhite, 0.0, 1.0); color.rgb = clamp(color.rgb * var_InvWhite, 0.0, 1.0);
#if defined(r_tonemapGamma) #if defined(USE_PBR)
color.rgb = pow(color.rgb, vec3(1.0 / r_tonemapGamma)); color.rgb = sqrt(color.rgb);
#endif #endif
// add a bit of dither to reduce banding
color.rgb += vec3(1.0/510.0 * mod(gl_FragCoord.x + gl_FragCoord.y, 2.0) - 1.0/1020.0);
gl_FragColor = color; gl_FragColor = color;
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -21,17 +21,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "tr_local.h" #include "tr_local.h"
static backEndCounters_t pc_save;
/*
=====================
R_PerformanceCounters
=====================
*/
void R_SavePerformanceCounters( void ) {
memcpy( &pc_save, &backEnd.pc, sizeof( pc_save ) );
}
/* /*
===================== =====================
R_PerformanceCounters R_PerformanceCounters
@ -77,8 +66,8 @@ void R_PerformanceCounters( void ) {
} }
else if (r_speeds->integer == 7 ) else if (r_speeds->integer == 7 )
{ {
ri.Printf( PRINT_ALL, "VAO draws: static %i dynamic %i\nMultidraws: %i merged %i\n", ri.Printf( PRINT_ALL, "VAO draws: static %i dynamic %i\n",
backEnd.pc.c_staticVaoDraws, backEnd.pc.c_dynamicVaoDraws, backEnd.pc.c_multidraws, backEnd.pc.c_multidrawsMerged ); backEnd.pc.c_staticVaoDraws, backEnd.pc.c_dynamicVaoDraws);
ri.Printf( PRINT_ALL, "GLSL binds: %i draws: gen %i light %i fog %i dlight %i\n", ri.Printf( PRINT_ALL, "GLSL binds: %i draws: gen %i light %i fog %i dlight %i\n",
backEnd.pc.c_glslShaderBinds, backEnd.pc.c_genericDraws, backEnd.pc.c_lightallDraws, backEnd.pc.c_fogDraws, backEnd.pc.c_dlightDraws); backEnd.pc.c_glslShaderBinds, backEnd.pc.c_genericDraws, backEnd.pc.c_lightallDraws, backEnd.pc.c_fogDraws, backEnd.pc.c_dlightDraws);
} }
@ -214,11 +203,11 @@ void R_AddCapShadowmapCmd( int map, int cubeSide ) {
/* /*
============= =============
R_PostProcessingCmd R_AddPostProcessCmd
============= =============
*/ */
void R_AddPostProcessCmd( ) { void R_AddPostProcessCmd( void ) {
postProcessCommand_t *cmd; postProcessCommand_t *cmd;
cmd = R_GetCommandBuffer( sizeof( *cmd ) ); cmd = R_GetCommandBuffer( sizeof( *cmd ) );
@ -353,7 +342,6 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) {
tr.frameCount++; tr.frameCount++;
tr.frameSceneNum = 0; tr.frameSceneNum = 0;
g_nStaticSurfaces = 0;
// //
// do overdraw measurement // do overdraw measurement

View file

@ -54,10 +54,10 @@ static void LerpDrawVert( srfVert_t *a, srfVert_t *b, srfVert_t *out ) {
out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]); out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]);
out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]); out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]);
out->vertexColors[0] = 0.5f * (a->vertexColors[0] + b->vertexColors[0]); out->color[0] = ((int)a->color[0] + (int)b->color[0]) >> 1;
out->vertexColors[1] = 0.5f * (a->vertexColors[1] + b->vertexColors[1]); out->color[1] = ((int)a->color[1] + (int)b->color[1]) >> 1;
out->vertexColors[2] = 0.5f * (a->vertexColors[2] + b->vertexColors[2]); out->color[2] = ((int)a->color[2] + (int)b->color[2]) >> 1;
out->vertexColors[3] = 0.5f * (a->vertexColors[3] + b->vertexColors[3]); out->color[3] = ((int)a->color[3] + (int)b->color[3]) >> 1;
} }
/* /*
@ -182,7 +182,7 @@ static int neighbors[8][2] = {
break; // edge of patch break; // edge of patch
} }
VectorSubtract( ctrl[y][x].xyz, base, temp ); VectorSubtract( ctrl[y][x].xyz, base, temp );
if ( VectorNormalize2( temp, temp ) == 0 ) { if ( VectorNormalize( temp ) < 0.001f ) {
continue; // degenerate edge, get more dist continue; // degenerate edge, get more dist
} else { } else {
good[k] = qtrue; good[k] = qtrue;
@ -198,7 +198,7 @@ static int neighbors[8][2] = {
continue; // didn't get two points continue; // didn't get two points
} }
CrossProduct( around[(k+1)&7], around[k], normal ); CrossProduct( around[(k+1)&7], around[k], normal );
if ( VectorNormalize2( normal, normal ) == 0 ) { if ( VectorNormalize( normal ) < 0.001f ) {
continue; continue;
} }
VectorAdd( normal, sum, sum ); VectorAdd( normal, sum, sum );
@ -207,12 +207,15 @@ static int neighbors[8][2] = {
//if ( count == 0 ) { //if ( count == 0 ) {
// printf("bad normal\n"); // printf("bad normal\n");
//} //}
VectorNormalize2( sum, dv->normal ); {
vec3_t fNormal;
VectorNormalize2(sum, fNormal);
R_VaoPackNormal(dv->normal, fNormal);
}
} }
} }
} }
#ifdef USE_VERT_TANGENT_SPACE
static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int numIndexes, static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int numIndexes,
glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3])
{ {
@ -251,17 +254,13 @@ static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRI
} }
} }
} }
#endif
static int MakeMeshIndexes(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], static int MakeMeshIndexes(int width, int height, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3])
glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3])
{ {
int i, j; int i, j;
int numIndexes; int numIndexes;
int w, h; int w, h;
srfVert_t *dv;
static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE];
h = height - 1; h = height - 1;
w = width - 1; w = width - 1;
@ -288,16 +287,6 @@ static int MakeMeshIndexes(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][
} }
} }
// FIXME: use more elegant way
for(i = 0; i < width; i++)
{
for(j = 0; j < height; j++)
{
dv = &ctrl2[j * width + i];
*dv = ctrl[j][i];
}
}
return numIndexes; return numIndexes;
} }
@ -375,21 +364,17 @@ static void PutPointsOnCurve( srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
R_CreateSurfaceGridMesh R_CreateSurfaceGridMesh
================= =================
*/ */
srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height, void R_CreateSurfaceGridMesh(srfBspSurface_t *grid, int width, int height,
srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE], srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE],
int numIndexes, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) { int numIndexes, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) {
int i, j, size; int i, j;
srfVert_t *vert; srfVert_t *vert;
vec3_t tmpVec; vec3_t tmpVec;
srfBspSurface_t *grid;
// copy the results out to a grid // copy the results out to a grid
size = (width * height - 1) * sizeof( srfVert_t ) + sizeof( *grid ); Com_Memset(grid, 0, sizeof(*grid));
#ifdef PATCH_STITCHING #ifdef PATCH_STITCHING
grid = /*ri.Hunk_Alloc*/ ri.Malloc( size );
Com_Memset(grid, 0, size);
grid->widthLodError = /*ri.Hunk_Alloc*/ ri.Malloc( width * 4 ); grid->widthLodError = /*ri.Hunk_Alloc*/ ri.Malloc( width * 4 );
Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
@ -403,9 +388,6 @@ srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height,
grid->numVerts = (width * height); grid->numVerts = (width * height);
grid->verts = ri.Malloc(grid->numVerts * sizeof(srfVert_t)); grid->verts = ri.Malloc(grid->numVerts * sizeof(srfVert_t));
#else #else
grid = ri.Hunk_Alloc( size );
Com_Memset(grid, 0, size);
grid->widthLodError = ri.Hunk_Alloc( width * 4 ); grid->widthLodError = ri.Hunk_Alloc( width * 4 );
Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 );
@ -441,7 +423,6 @@ srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height,
VectorCopy( grid->cullOrigin, grid->lodOrigin ); VectorCopy( grid->cullOrigin, grid->lodOrigin );
grid->lodRadius = grid->cullRadius; grid->lodRadius = grid->cullRadius;
// //
return grid;
} }
/* /*
@ -449,12 +430,11 @@ srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height,
R_FreeSurfaceGridMesh R_FreeSurfaceGridMesh
================= =================
*/ */
void R_FreeSurfaceGridMesh( srfBspSurface_t *grid ) { static void R_FreeSurfaceGridMeshData( srfBspSurface_t *grid ) {
ri.Free(grid->widthLodError); ri.Free(grid->widthLodError);
ri.Free(grid->heightLodError); ri.Free(grid->heightLodError);
ri.Free(grid->indexes); ri.Free(grid->indexes);
ri.Free(grid->verts); ri.Free(grid->verts);
ri.Free(grid);
} }
/* /*
@ -462,7 +442,7 @@ void R_FreeSurfaceGridMesh( srfBspSurface_t *grid ) {
R_SubdividePatchToGrid R_SubdividePatchToGrid
================= =================
*/ */
srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, void R_SubdividePatchToGrid( srfBspSurface_t *grid, int width, int height,
srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
int i, j, k, l; int i, j, k, l;
srfVert_t_cleared( prev ); srfVert_t_cleared( prev );
@ -629,15 +609,13 @@ srfBspSurface_t *R_SubdividePatchToGrid( int width, int height,
#endif #endif
// calculate indexes // calculate indexes
numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); numIndexes = MakeMeshIndexes(width, height, indexes);
// calculate normals // calculate normals
MakeMeshNormals( width, height, ctrl ); MakeMeshNormals( width, height, ctrl );
#ifdef USE_VERT_TANGENT_SPACE
MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes); MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes);
#endif
return R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); R_CreateSurfaceGridMesh(grid, width, height, ctrl, errorTable, numIndexes, indexes);
} }
/* /*
@ -645,7 +623,7 @@ srfBspSurface_t *R_SubdividePatchToGrid( int width, int height,
R_GridInsertColumn R_GridInsertColumn
=============== ===============
*/ */
srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ) { void R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ) {
int i, j; int i, j;
int width, height, oldwidth; int width, height, oldwidth;
srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
@ -658,7 +636,7 @@ srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row,
oldwidth = 0; oldwidth = 0;
width = grid->width + 1; width = grid->width + 1;
if (width > MAX_GRID_SIZE) if (width > MAX_GRID_SIZE)
return NULL; return;
height = grid->height; height = grid->height;
for (i = 0; i < width; i++) { for (i = 0; i < width; i++) {
if (i == column) { if (i == column) {
@ -684,20 +662,20 @@ srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row,
//PutPointsOnCurve( ctrl, width, height ); //PutPointsOnCurve( ctrl, width, height );
// calculate indexes // calculate indexes
numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); numIndexes = MakeMeshIndexes(width, height, indexes);
// calculate normals // calculate normals
MakeMeshNormals( width, height, ctrl ); MakeMeshNormals( width, height, ctrl );
MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes);
VectorCopy(grid->lodOrigin, lodOrigin); VectorCopy(grid->lodOrigin, lodOrigin);
lodRadius = grid->lodRadius; lodRadius = grid->lodRadius;
// free the old grid // free the old grid
R_FreeSurfaceGridMesh(grid); R_FreeSurfaceGridMeshData(grid);
// create a new grid // create a new grid
grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); R_CreateSurfaceGridMesh(grid, width, height, ctrl, errorTable, numIndexes, indexes);
grid->lodRadius = lodRadius; grid->lodRadius = lodRadius;
VectorCopy(lodOrigin, grid->lodOrigin); VectorCopy(lodOrigin, grid->lodOrigin);
return grid;
} }
/* /*
@ -705,7 +683,7 @@ srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row,
R_GridInsertRow R_GridInsertRow
=============== ===============
*/ */
srfBspSurface_t *R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ) { void R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ) {
int i, j; int i, j;
int width, height, oldheight; int width, height, oldheight;
srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
@ -719,7 +697,7 @@ srfBspSurface_t *R_GridInsertRow( srfBspSurface_t *grid, int row, int column, ve
width = grid->width; width = grid->width;
height = grid->height + 1; height = grid->height + 1;
if (height > MAX_GRID_SIZE) if (height > MAX_GRID_SIZE)
return NULL; return;
for (i = 0; i < height; i++) { for (i = 0; i < height; i++) {
if (i == row) { if (i == row) {
//insert new row //insert new row
@ -744,18 +722,18 @@ srfBspSurface_t *R_GridInsertRow( srfBspSurface_t *grid, int row, int column, ve
//PutPointsOnCurve( ctrl, width, height ); //PutPointsOnCurve( ctrl, width, height );
// calculate indexes // calculate indexes
numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); numIndexes = MakeMeshIndexes(width, height, indexes);
// calculate normals // calculate normals
MakeMeshNormals( width, height, ctrl ); MakeMeshNormals( width, height, ctrl );
MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes);
VectorCopy(grid->lodOrigin, lodOrigin); VectorCopy(grid->lodOrigin, lodOrigin);
lodRadius = grid->lodRadius; lodRadius = grid->lodRadius;
// free the old grid // free the old grid
R_FreeSurfaceGridMesh(grid); R_FreeSurfaceGridMeshData(grid);
// create a new grid // create a new grid
grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); R_CreateSurfaceGridMesh(grid, width, height, ctrl, errorTable, numIndexes, indexes);
grid->lodRadius = lodRadius; grid->lodRadius = lodRadius;
VectorCopy(lodOrigin, grid->lodOrigin); VectorCopy(lodOrigin, grid->lodOrigin);
return grid;
} }

View file

@ -1,505 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_draw.c -- drawing
#include "tr_local.h"
vec4_t r_colorWhite = { 1.0, 1.0, 1.0, 1.0 };
/*
================
Draw_SetColor
================
*/
void Draw_SetColor( const vec4_t rgba ) {
#if 1
if( !rgba ) {
rgba = r_colorWhite;
}
backEnd.color2D[ 0 ] = rgba[ 0 ] * tr.identityLight;
backEnd.color2D[ 1 ] = rgba[ 1 ] * tr.identityLight;
backEnd.color2D[ 2 ] = rgba[ 2 ] * tr.identityLight;
backEnd.color2D[ 3 ] = rgba[ 3 ];
qglColor4fv( backEnd.color2D );
#else
RE_SetColor( rgba );
#endif
}
/*
================
Draw_StretchPic
================
*/
void Draw_StretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader ) {
#if 1
shader_t *shader;
R_IssuePendingRenderCommands();
if( hShader ) {
shader = R_GetShaderByHandle( hShader );
} else {
shader = tr.defaultShader;
}
if( w <= 0 ) {
w = shader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->width;
h = shader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->height;
}
RB_Prepare2D();
// draw the pic
RB_Color4f( backEnd.color2D[ 0 ], backEnd.color2D[ 1 ], backEnd.color2D[ 2 ], backEnd.color2D[ 3 ] );
RB_BeginSurface( shader, 0, 0 );
RB_Texcoord2f( s1, t1 );
RB_Vertex2f( x, y );
RB_Texcoord2f( s2, t1 );
RB_Vertex2f( x + w, y );
RB_Texcoord2f( s1, t2 );
RB_Vertex2f( x, y + h );
RB_Texcoord2f( s2, t2 );
RB_Vertex2f( x + w, y + h );
RB_StreamEnd();
#else
RE_StretchPic( x, y, w, h, s1, t1, s2, t2, hShader );
#endif
}
/*
================
Draw_TilePic
================
*/
void Draw_TilePic( float x, float y, float w, float h , qhandle_t hShader ) {
shader_t *shader;
float picw, pich;
R_IssuePendingRenderCommands();
if( hShader ) {
shader = R_GetShaderByHandle( hShader );
}
else {
shader = tr.defaultShader;
}
if( w <= 0 ) {
w = shader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->width;
h = shader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->height;
}
picw = shader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->uploadWidth;
pich = shader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->uploadHeight;
RB_Prepare2D();
// draw the pic
RB_Color4f( backEnd.color2D[ 0 ], backEnd.color2D[ 1 ], backEnd.color2D[ 2 ], backEnd.color2D[ 3 ] );
RB_StreamBegin( shader );
RB_Texcoord2f( x / picw, y / pich );
RB_Vertex2f( x, y );
RB_Texcoord2f( ( x + w ) / picw, y / pich );
RB_Vertex2f( x + w, y );
RB_Texcoord2f( x / picw, ( y + h ) / pich );
RB_Vertex2f( x, y + h );
RB_Texcoord2f( ( x + w ) / picw, ( y + h ) / pich );
RB_Vertex2f( x + w, y + h );
RB_StreamEnd();
}
/*
================
Draw_TilePicOffset
================
*/
void Draw_TilePicOffset( float x, float y, float w, float h, qhandle_t hShader, int offsetX, int offsetY ) {
shader_t *shader;
float picw, pich;
R_IssuePendingRenderCommands();
if( hShader ) {
shader = R_GetShaderByHandle( hShader );
} else {
shader = tr.defaultShader;
}
if( w <= 0 ) {
w = shader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->width;
h = shader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->height;
}
picw = shader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->uploadWidth;
pich = shader->stages[ 0 ]->bundle[ 0 ].image[ 0 ]->uploadHeight;
RB_Prepare2D();
// draw the pic
RB_Color4f( backEnd.color2D[ 0 ], backEnd.color2D[ 1 ], backEnd.color2D[ 2 ], backEnd.color2D[ 3 ] );
RB_StreamBegin( shader );
RB_Texcoord2f( x / picw, y / pich );
RB_Vertex2f( x + offsetX, y + offsetY );
RB_Texcoord2f( ( x + w ) / picw, y / pich );
RB_Vertex2f( x + offsetX + w, y + offsetY );
RB_Texcoord2f( x / picw, ( y + h ) / pich );
RB_Vertex2f( x + offsetX, y + offsetY + h );
RB_Texcoord2f( ( x + w ) / picw, ( y + h ) / pich );
RB_Vertex2f( x + offsetX + w, y + offsetY + h );
RB_StreamEnd();
}
/*
================
Draw_TrianglePic
================
*/
void Draw_TrianglePic( const vec2_t vPoints[ 3 ], const vec2_t vTexCoords[ 3 ], qhandle_t hShader ) {
int i;
shader_t *shader;
R_IssuePendingRenderCommands();
if( hShader ) {
shader = R_GetShaderByHandle( hShader );
} else {
shader = tr.defaultShader;
}
RB_Prepare2D();
// draw the pic
RB_Color4f( backEnd.color2D[ 0 ], backEnd.color2D[ 1 ], backEnd.color2D[ 2 ], backEnd.color2D[ 3 ] );
RB_BeginSurface( shader, 0, 0 );
for( i = 0; i < 3; i++ ) {
RB_Texcoord2f( vTexCoords[ i ][ 0 ], vTexCoords[ i ][ 1 ] );
RB_Vertex2f( vPoints[ i ][ 0 ], vPoints[ i ][ 1 ] );
}
RB_StreamEnd();
}
/*
================
RE_DrawBackground_TexSubImage
================
*/
void RE_DrawBackground_TexSubImage( int cols, int rows, int bgr, byte *data ) {
GLenum format;
int w, h;
w = glConfig.vidWidth;
h = glConfig.vidHeight;
R_IssuePendingRenderCommands();
qglFinish();
if( bgr ) {
format = GL_BGR_EXT;
} else {
format = GL_RGB;
}
GL_Bind( tr.scratchImage[ 0 ] );
if( cols == tr.scratchImage[ 0 ]->width && rows == tr.scratchImage[ 0 ]->height && format == tr.scratchImage[ 0 ]->internalFormat )
{
qglTexSubImage2D( 3553, 0, 0, 0, cols, rows, format, 5121, data );
}
else
{
tr.scratchImage[ 0 ]->uploadWidth = cols;
tr.scratchImage[ 0 ]->uploadHeight = rows;
tr.scratchImage[ 0 ]->internalFormat = format;
qglTexImage2D( GL_TEXTURE_2D, 0, 3, cols, rows, 0, format, 5121, data );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 9729.0 );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 9729.0 );
}
qglDisable( GL_CULL_FACE );
qglDisable( GL_DEPTH_TEST );
qglEnable( GL_TEXTURE_2D );
qglBegin( GL_QUADS );
qglTexCoord2f( 0.5 / ( GLfloat )cols, ( ( GLfloat )rows - 0.5 ) / rows );
qglVertex2f( 0, 0 );
qglTexCoord2f( ( ( GLfloat )cols - 0.5 ) / cols, ( ( GLfloat )rows - 0.5 ) / rows );
qglVertex2f( w, 0 );
qglTexCoord2f( ( ( GLfloat )cols - 0.5 ) / cols, 0.5 / ( GLfloat )rows );
qglVertex2f( w, h );
qglTexCoord2f( 0.5 / ( GLfloat )rows, 0.5 / ( GLfloat )rows );
qglVertex2f( 0, h );
qglEnd();
}
/*
================
RE_DrawBackground_DrawPixels
================
*/
void RE_DrawBackground_DrawPixels( int cols, int rows, int bgr, byte *data ) {
// FIXME: stub
}
/*
=============
RE_StretchRaw
Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
Used for cinematics.
=============
*/
void RE_StretchRaw( int x, int y, int w, int h, int cols, int rows, int components, const byte *data ) {
int i, j;
int start, end;
vec4_t quadVerts[4];
vec2_t texCoords[4];
if ( !tr.registered ) {
return;
}
R_IssuePendingRenderCommands();
if ( tess.numIndexes ) {
RB_EndSurface();
}
// we definately want to sync every frame for the cinematics
qglFinish();
start = 0;
if ( r_speeds->integer ) {
start = ri.Milliseconds();
}
// make sure rows and cols are powers of 2
for ( i = 0 ; ( 1 << i ) < cols ; i++ ) {
}
for ( j = 0 ; ( 1 << j ) < rows ; j++ ) {
}
if ( ( 1 << i ) != cols || ( 1 << j ) != rows) {
ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows);
}
RE_UploadCinematic (w, h, cols, rows, data, 0, qtrue);
if ( r_speeds->integer ) {
end = ri.Milliseconds();
ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start );
}
RB_Prepare2D();
RB_SetGL2D();
VectorSet4(quadVerts[0], x, y, 0.0f, 1.0f);
VectorSet4(quadVerts[1], x + w, y, 0.0f, 1.0f);
VectorSet4(quadVerts[2], x + w, y + h, 0.0f, 1.0f);
VectorSet4(quadVerts[3], x, y + h, 0.0f, 1.0f);
VectorSet2(texCoords[0], 0.5f / cols, 0.5f / rows);
VectorSet2(texCoords[1], (cols - 0.5f) / cols, 0.5f / rows);
VectorSet2(texCoords[2], (cols - 0.5f) / cols, (rows - 0.5f) / rows);
VectorSet2(texCoords[3], 0.5f / cols, (rows - 0.5f) / rows);
GLSL_BindProgram(&tr.textureColorShader);
GLSL_SetUniformMat4(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite);
RB_InstantQuad2(quadVerts, texCoords);
}
/*
================
AddBox
================
*/
void AddBox( float x, float y, float w, float h ) {
R_IssuePendingRenderCommands();
qglColor4fv( backEnd.color2D );
qglDisable( GL_TEXTURE_2D );
GL_State( 0x422 );
qglBegin( GL_QUADS );
qglVertex2f( x, y );
qglVertex2f( x + w, y );
qglVertex2f( x + w, y + h );
qglVertex2f( x, y + h );
qglEnd();
qglEnable( GL_TEXTURE_2D );
}
/*
================
DrawBox
================
*/
void DrawBox( float x, float y, float w, float h ) {
R_IssuePendingRenderCommands();
qglColor4fv( backEnd.color2D );
qglDisable( GL_TEXTURE_2D );
GL_State( 0x465 );
qglBegin( GL_QUADS );
qglVertex2f( x, y );
qglVertex2f( x + w, y );
qglVertex2f( x + w, y + h );
qglVertex2f( x, y + h );
qglEnd();
qglEnable( GL_TEXTURE_2D );
}
/*
================
DrawLineLoop
================
*/
void DrawLineLoop( const vec2_t *points, int count, int stipple_factor, int stipple_mask ) {
int i;
R_IssuePendingRenderCommands();
qglDisable( GL_TEXTURE_2D );
if( stipple_factor ) {
qglEnable( GL_LINE_STIPPLE );
qglLineStipple( stipple_factor, stipple_mask );
}
qglBegin( GL_LINE_LOOP );
for( i = 0; i < count; i++ ) {
qglVertex2i( points[ i ][ 0 ], points[ i ][ 1 ] );
}
qglEnd();
qglEnable( GL_TEXTURE_2D );
if( stipple_factor ) {
qglDisable( GL_LINE_STIPPLE );
}
}
/*
================
Set2DWindow
================
*/
void Set2DWindow( int x, int y, int w, int h, float left, float right, float bottom, float top, float n, float f ) {
matrix_t matrix;
backEnd.projection2D = qtrue;
backEnd.last2DFBO = glState.currentFBO;
// set 2D virtual screen size
qglViewport( 0, 0, w, h );
qglScissor( 0, 0, w, h );
Mat4Ortho( 0, w, h, 0, 0, 1, matrix );
GL_SetProjectionMatrix( matrix );
Mat4Identity( matrix );
GL_SetModelviewMatrix( matrix );
GL_State( GLS_DEPTHTEST_DISABLE |
GLS_SRCBLEND_SRC_ALPHA |
GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
GL_Cull( CT_TWO_SIDED );
qglDisable( GL_CLIP_PLANE0 );
// set time for 2D shaders
backEnd.refdef.time = ri.Milliseconds();
backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f;
// reset color scaling
backEnd.refdef.colorScale = 1.0f;
/*qglViewport( x, y, w, h );
qglScissor( x, y, w, h );
qglMatrixMode( GL_MODELVIEW0_ARB + 1 );
qglLoadIdentity();
qglOrtho( left, right, bottom, top, n, f );
qglMatrixMode( GL_MODELVIEW0_ARB );
qglLoadIdentity();
GL_State( 0x465 );
qglEnable( GL_BLEND );
qglDisable( GL_CULL_FACE );
qglDisable( GL_CLIP_PLANE0 );
//if( r_reset_tc_array->integer )
// qglDisableClientState( 32888 );
if( !backEnd.projection2D )
{
backEnd.refdef.time = ri.Milliseconds();
backEnd.projection2D = qtrue;
backEnd.refdef.floatTime = ( float )backEnd.refdef.time * 0.001;
}*/
}
/*
================
RE_Scissor
================
*/
void RE_Scissor( int x, int y, int width, int height ) {
qglEnable( GL_SCISSOR_TEST );
qglScissor( x, y, width, height );
}

287
code/renderergl2/tr_dsa.c Normal file
View file

@ -0,0 +1,287 @@
/*
===========================================================================
Copyright (C) 2016 James Canete
This program 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
===========================================================================
*/
#include "tr_local.h"
#include "tr_dsa.h"
static struct
{
GLuint textures[NUM_TEXTURE_BUNDLES];
GLenum texunit;
GLuint program;
GLuint drawFramebuffer;
GLuint readFramebuffer;
GLuint renderbuffer;
}
glDsaState;
void GL_BindNullTextures(void)
{
int i;
if (glRefConfig.directStateAccess)
{
for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
{
qglBindMultiTextureEXT(GL_TEXTURE0 + i, GL_TEXTURE_2D, 0);
glDsaState.textures[i] = 0;
}
}
else
{
for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
{
qglActiveTexture(GL_TEXTURE0 + i);
qglBindTexture(GL_TEXTURE_2D, 0);
glDsaState.textures[i] = 0;
}
qglActiveTexture(GL_TEXTURE0);
glDsaState.texunit = GL_TEXTURE0;
}
}
int GL_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture)
{
GLuint tmu = texunit - GL_TEXTURE0;
if (glDsaState.textures[tmu] == texture)
return 0;
if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
target = GL_TEXTURE_CUBE_MAP;
qglBindMultiTextureEXT(texunit, target, texture);
glDsaState.textures[tmu] = texture;
return 1;
}
GLvoid APIENTRY GLDSA_BindMultiTextureEXT(GLenum texunit, GLenum target, GLuint texture)
{
if (glDsaState.texunit != texunit)
{
qglActiveTexture(texunit);
glDsaState.texunit = texunit;
}
qglBindTexture(target, texture);
}
GLvoid APIENTRY GLDSA_TextureParameterfEXT(GLuint texture, GLenum target, GLenum pname, GLfloat param)
{
GL_BindMultiTexture(glDsaState.texunit, target, texture);
qglTexParameterf(target, pname, param);
}
GLvoid APIENTRY GLDSA_TextureParameteriEXT(GLuint texture, GLenum target, GLenum pname, GLint param)
{
GL_BindMultiTexture(glDsaState.texunit, target, texture);
qglTexParameteri(target, pname, param);
}
GLvoid APIENTRY GLDSA_TextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
{
GL_BindMultiTexture(glDsaState.texunit, target, texture);
qglTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
}
GLvoid APIENTRY GLDSA_TextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
{
GL_BindMultiTexture(glDsaState.texunit, target, texture);
qglTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
}
GLvoid APIENTRY GLDSA_CopyTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLint x, GLint y, GLsizei width, GLsizei height)
{
GL_BindMultiTexture(glDsaState.texunit, target, texture);
qglCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
}
GLvoid APIENTRY GLDSA_CompressedTextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLenum internalformat,
GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
{
GL_BindMultiTexture(glDsaState.texunit, target, texture);
qglCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
}
GLvoid APIENTRY GLDSA_CompressedTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
GLsizei imageSize, const GLvoid *data)
{
GL_BindMultiTexture(glDsaState.texunit, target, texture);
qglCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
}
GLvoid APIENTRY GLDSA_GenerateTextureMipmapEXT(GLuint texture, GLenum target)
{
GL_BindMultiTexture(glDsaState.texunit, target, texture);
qglGenerateMipmap(target);
}
void GL_BindNullProgram(void)
{
qglUseProgram(0);
glDsaState.program = 0;
}
int GL_UseProgram(GLuint program)
{
if (glDsaState.program == program)
return 0;
qglUseProgram(program);
glDsaState.program = program;
return 1;
}
GLvoid APIENTRY GLDSA_ProgramUniform1iEXT(GLuint program, GLint location, GLint v0)
{
GL_UseProgram(program);
qglUniform1i(location, v0);
}
GLvoid APIENTRY GLDSA_ProgramUniform1fEXT(GLuint program, GLint location, GLfloat v0)
{
GL_UseProgram(program);
qglUniform1f(location, v0);
}
GLvoid APIENTRY GLDSA_ProgramUniform2fEXT(GLuint program, GLint location,
GLfloat v0, GLfloat v1)
{
GL_UseProgram(program);
qglUniform2f(location, v0, v1);
}
GLvoid APIENTRY GLDSA_ProgramUniform3fEXT(GLuint program, GLint location,
GLfloat v0, GLfloat v1, GLfloat v2)
{
GL_UseProgram(program);
qglUniform3f(location, v0, v1, v2);
}
GLvoid APIENTRY GLDSA_ProgramUniform4fEXT(GLuint program, GLint location,
GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
{
GL_UseProgram(program);
qglUniform4f(location, v0, v1, v2, v3);
}
GLvoid APIENTRY GLDSA_ProgramUniform1fvEXT(GLuint program, GLint location,
GLsizei count, const GLfloat *value)
{
GL_UseProgram(program);
qglUniform1fv(location, count, value);
}
GLvoid APIENTRY GLDSA_ProgramUniformMatrix4fvEXT(GLuint program, GLint location,
GLsizei count, GLboolean transpose,
const GLfloat *value)
{
GL_UseProgram(program);
qglUniformMatrix4fv(location, count, transpose, value);
}
void GL_BindNullFramebuffers(void)
{
qglBindFramebuffer(GL_FRAMEBUFFER, 0);
glDsaState.drawFramebuffer = glDsaState.readFramebuffer = 0;
qglBindRenderbuffer(GL_RENDERBUFFER, 0);
glDsaState.renderbuffer = 0;
}
void GL_BindFramebuffer(GLenum target, GLuint framebuffer)
{
switch (target)
{
case GL_FRAMEBUFFER:
if (framebuffer != glDsaState.drawFramebuffer || framebuffer != glDsaState.readFramebuffer)
{
qglBindFramebuffer(target, framebuffer);
glDsaState.drawFramebuffer = glDsaState.readFramebuffer = framebuffer;
}
break;
case GL_DRAW_FRAMEBUFFER:
if (framebuffer != glDsaState.drawFramebuffer)
{
qglBindFramebuffer(target, framebuffer);
glDsaState.drawFramebuffer = framebuffer;
}
break;
case GL_READ_FRAMEBUFFER:
if (framebuffer != glDsaState.readFramebuffer)
{
qglBindFramebuffer(target, framebuffer);
glDsaState.readFramebuffer = framebuffer;
}
break;
}
}
void GL_BindRenderbuffer(GLuint renderbuffer)
{
if (renderbuffer != glDsaState.renderbuffer)
{
qglBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
glDsaState.renderbuffer = renderbuffer;
}
}
GLvoid APIENTRY GLDSA_NamedRenderbufferStorageEXT(GLuint renderbuffer,
GLenum internalformat, GLsizei width, GLsizei height)
{
GL_BindRenderbuffer(renderbuffer);
qglRenderbufferStorage(GL_RENDERBUFFER, internalformat, width, height);
}
GLvoid APIENTRY GLDSA_NamedRenderbufferStorageMultisampleEXT(GLuint renderbuffer,
GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
{
GL_BindRenderbuffer(renderbuffer);
qglRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalformat, width, height);
}
GLenum APIENTRY GLDSA_CheckNamedFramebufferStatusEXT(GLuint framebuffer, GLenum target)
{
GL_BindFramebuffer(target, framebuffer);
return qglCheckFramebufferStatus(target);
}
GLvoid APIENTRY GLDSA_NamedFramebufferTexture2DEXT(GLuint framebuffer,
GLenum attachment, GLenum textarget, GLuint texture, GLint level)
{
GL_BindFramebuffer(GL_FRAMEBUFFER, framebuffer);
qglFramebufferTexture2D(GL_FRAMEBUFFER, attachment, textarget, texture, level);
}
GLvoid APIENTRY GLDSA_NamedFramebufferRenderbufferEXT(GLuint framebuffer,
GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
{
GL_BindFramebuffer(GL_FRAMEBUFFER, framebuffer);
qglFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, renderbuffertarget, renderbuffer);
}

80
code/renderergl2/tr_dsa.h Normal file
View file

@ -0,0 +1,80 @@
/*
===========================================================================
Copyright (C) 2016 James Canete
This program 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
===========================================================================
*/
#ifndef __TR_DSA_H__
#define __TR_DSA_H__
#include "../renderercommon/qgl.h"
void GL_BindNullTextures(void);
int GL_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture);
GLvoid APIENTRY GLDSA_BindMultiTextureEXT(GLenum texunit, GLenum target, GLuint texture);
GLvoid APIENTRY GLDSA_TextureParameterfEXT(GLuint texture, GLenum target, GLenum pname, GLfloat param);
GLvoid APIENTRY GLDSA_TextureParameteriEXT(GLuint texture, GLenum target, GLenum pname, GLint param);
GLvoid APIENTRY GLDSA_TextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
GLvoid APIENTRY GLDSA_TextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
GLvoid APIENTRY GLDSA_CopyTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLint x, GLint y, GLsizei width, GLsizei height);
GLvoid APIENTRY GLDSA_CompressedTextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLenum internalformat,
GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
GLvoid APIENTRY GLDSA_CompressedTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
GLsizei imageSize, const GLvoid *data);
GLvoid APIENTRY GLDSA_GenerateTextureMipmapEXT(GLuint texture, GLenum target);
void GL_BindNullProgram(void);
int GL_UseProgram(GLuint program);
GLvoid APIENTRY GLDSA_ProgramUniform1iEXT(GLuint program, GLint location, GLint v0);
GLvoid APIENTRY GLDSA_ProgramUniform1fEXT(GLuint program, GLint location, GLfloat v0);
GLvoid APIENTRY GLDSA_ProgramUniform2fEXT(GLuint program, GLint location,
GLfloat v0, GLfloat v1);
GLvoid APIENTRY GLDSA_ProgramUniform3fEXT(GLuint program, GLint location,
GLfloat v0, GLfloat v1, GLfloat v2);
GLvoid APIENTRY GLDSA_ProgramUniform4fEXT(GLuint program, GLint location,
GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
GLvoid APIENTRY GLDSA_ProgramUniform1fvEXT(GLuint program, GLint location,
GLsizei count, const GLfloat *value);
GLvoid APIENTRY GLDSA_ProgramUniformMatrix4fvEXT(GLuint program, GLint location,
GLsizei count, GLboolean transpose,
const GLfloat *value);
void GL_BindNullFramebuffers(void);
void GL_BindFramebuffer(GLenum target, GLuint framebuffer);
void GL_BindRenderbuffer(GLuint renderbuffer);
GLvoid APIENTRY GLDSA_NamedRenderbufferStorageEXT(GLuint renderbuffer,
GLenum internalformat, GLsizei width, GLsizei height);
GLvoid APIENTRY GLDSA_NamedRenderbufferStorageMultisampleEXT(GLuint renderbuffer,
GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
GLenum APIENTRY GLDSA_CheckNamedFramebufferStatusEXT(GLuint framebuffer, GLenum target);
GLvoid APIENTRY GLDSA_NamedFramebufferTexture2DEXT(GLuint framebuffer,
GLenum attachment, GLenum textarget, GLuint texture, GLint level);
GLvoid APIENTRY GLDSA_NamedFramebufferRenderbufferEXT(GLuint framebuffer,
GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
#endif

View file

@ -28,507 +28,50 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif #endif
#include "tr_local.h" #include "tr_local.h"
#include "tr_dsa.h"
// GL_EXT_draw_range_elements void GLimp_InitExtraExtensions(void)
void (APIENTRY * qglDrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
// GL_EXT_multi_draw_arrays
void (APIENTRY * qglMultiDrawArraysEXT) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
void (APIENTRY * qglMultiDrawElementsEXT) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
// GL_ARB_vertex_shader
void (APIENTRY * qglBindAttribLocationARB) (GLhandleARB programObj, GLuint index, const GLcharARB * name);
void (APIENTRY * qglGetActiveAttribARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei * length,
GLint * size, GLenum * type, GLcharARB * name);
GLint(APIENTRY * qglGetAttribLocationARB) (GLhandleARB programObj, const GLcharARB * name);
// GL_ARB_vertex_program
void (APIENTRY * qglVertexAttrib4fARB) (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
void (APIENTRY * qglVertexAttrib4fvARB) (GLuint, const GLfloat *);
void (APIENTRY * qglVertexAttribPointerARB) (GLuint index, GLint size, GLenum type, GLboolean normalized,
GLsizei stride, const GLvoid * pointer);
void (APIENTRY * qglEnableVertexAttribArrayARB) (GLuint index);
void (APIENTRY * qglDisableVertexAttribArrayARB) (GLuint index);
// GL_ARB_vertex_buffer_object
void (APIENTRY * qglBindBufferARB) (GLenum target, GLuint buffer);
void (APIENTRY * qglDeleteBuffersARB) (GLsizei n, const GLuint * buffers);
void (APIENTRY * qglGenBuffersARB) (GLsizei n, GLuint * buffers);
GLboolean(APIENTRY * qglIsBufferARB) (GLuint buffer);
void (APIENTRY * qglBufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage);
void (APIENTRY * qglBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data);
void (APIENTRY * qglGetBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid * data);
void (APIENTRY * qglGetBufferParameterivARB) (GLenum target, GLenum pname, GLint * params);
void (APIENTRY * qglGetBufferPointervARB) (GLenum target, GLenum pname, GLvoid * *params);
// GL_ARB_shader_objects
void (APIENTRY * qglDeleteObjectARB) (GLhandleARB obj);
GLhandleARB(APIENTRY * qglGetHandleARB) (GLenum pname);
void (APIENTRY * qglDetachObjectARB) (GLhandleARB containerObj, GLhandleARB attachedObj);
GLhandleARB(APIENTRY * qglCreateShaderObjectARB) (GLenum shaderType);
void (APIENTRY * qglShaderSourceARB) (GLhandleARB shaderObj, GLsizei count, const GLcharARB * *string,
const GLint * length);
void (APIENTRY * qglCompileShaderARB) (GLhandleARB shaderObj);
GLhandleARB(APIENTRY * qglCreateProgramObjectARB) (void);
void (APIENTRY * qglAttachObjectARB) (GLhandleARB containerObj, GLhandleARB obj);
void (APIENTRY * qglLinkProgramARB) (GLhandleARB programObj);
void (APIENTRY * qglUseProgramObjectARB) (GLhandleARB programObj);
void (APIENTRY * qglValidateProgramARB) (GLhandleARB programObj);
void (APIENTRY * qglUniform1fARB) (GLint location, GLfloat v0);
void (APIENTRY * qglUniform2fARB) (GLint location, GLfloat v0, GLfloat v1);
void (APIENTRY * qglUniform3fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
void (APIENTRY * qglUniform4fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
void (APIENTRY * qglUniform1iARB) (GLint location, GLint v0);
void (APIENTRY * qglUniform2iARB) (GLint location, GLint v0, GLint v1);
void (APIENTRY * qglUniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2);
void (APIENTRY * qglUniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
void (APIENTRY * qglUniform1fvARB) (GLint location, GLsizei count, const GLfloat * value);
void (APIENTRY * qglUniform2fvARB) (GLint location, GLsizei count, const GLfloat * value);
void (APIENTRY * qglUniform3fvARB) (GLint location, GLsizei count, const GLfloat * value);
void (APIENTRY * qglUniform4fvARB) (GLint location, GLsizei count, const GLfloat * value);
void (APIENTRY * qglUniform2ivARB) (GLint location, GLsizei count, const GLint * value);
void (APIENTRY * qglUniform3ivARB) (GLint location, GLsizei count, const GLint * value);
void (APIENTRY * qglUniform4ivARB) (GLint location, GLsizei count, const GLint * value);
void (APIENTRY * qglUniformMatrix2fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
void (APIENTRY * qglUniformMatrix3fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
void (APIENTRY * qglUniformMatrix4fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
void (APIENTRY * qglGetObjectParameterfvARB) (GLhandleARB obj, GLenum pname, GLfloat * params);
void (APIENTRY * qglGetObjectParameterivARB) (GLhandleARB obj, GLenum pname, GLint * params);
void (APIENTRY * qglGetInfoLogARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog);
void (APIENTRY * qglGetAttachedObjectsARB) (GLhandleARB containerObj, GLsizei maxCount, GLsizei * count,
GLhandleARB * obj);
GLint(APIENTRY * qglGetUniformLocationARB) (GLhandleARB programObj, const GLcharARB * name);
void (APIENTRY * qglGetActiveUniformARB) (GLhandleARB programObj, GLuint index, GLsizei maxIndex, GLsizei * length,
GLint * size, GLenum * type, GLcharARB * name);
void (APIENTRY * qglGetUniformfvARB) (GLhandleARB programObj, GLint location, GLfloat * params);
void (APIENTRY * qglGetUniformivARB) (GLhandleARB programObj, GLint location, GLint * params);
void (APIENTRY * qglGetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * source);
// GL_ARB_texture_compression
void (APIENTRY * qglCompressedTexImage3DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
void (APIENTRY * qglCompressedTexImage2DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
GLint border, GLsizei imageSize, const GLvoid *data);
void (APIENTRY * qglCompressedTexImage1DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border,
GLsizei imageSize, const GLvoid *data);
void (APIENTRY * qglCompressedTexSubImage3DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
void (APIENTRY * qglCompressedTexSubImage2DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
void (APIENTRY * qglCompressedTexSubImage1DARB)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format,
GLsizei imageSize, const GLvoid *data);
void (APIENTRY * qglGetCompressedTexImageARB)(GLenum target, GLint lod,
GLvoid *img);
// GL_EXT_framebuffer_object
GLboolean (APIENTRY * qglIsRenderbufferEXT)(GLuint renderbuffer);
void (APIENTRY * qglBindRenderbufferEXT)(GLenum target, GLuint renderbuffer);
void (APIENTRY * qglDeleteRenderbuffersEXT)(GLsizei n, const GLuint *renderbuffers);
void (APIENTRY * qglGenRenderbuffersEXT)(GLsizei n, GLuint *renderbuffers);
void (APIENTRY * qglRenderbufferStorageEXT)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
void (APIENTRY * qglGetRenderbufferParameterivEXT)(GLenum target, GLenum pname, GLint *params);
GLboolean (APIENTRY * qglIsFramebufferEXT)(GLuint framebuffer);
void (APIENTRY * qglBindFramebufferEXT)(GLenum target, GLuint framebuffer);
void (APIENTRY * qglDeleteFramebuffersEXT)(GLsizei n, const GLuint *framebuffers);
void (APIENTRY * qglGenFramebuffersEXT)(GLsizei n, GLuint *framebuffers);
GLenum (APIENTRY * qglCheckFramebufferStatusEXT)(GLenum target);
void (APIENTRY * qglFramebufferTexture1DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
GLint level);
void (APIENTRY * qglFramebufferTexture2DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
GLint level);
void (APIENTRY * qglFramebufferTexture3DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
GLint level, GLint zoffset);
void (APIENTRY * qglFramebufferRenderbufferEXT)(GLenum target, GLenum attachment, GLenum renderbuffertarget,
GLuint renderbuffer);
void (APIENTRY * qglGetFramebufferAttachmentParameterivEXT)(GLenum target, GLenum attachment, GLenum pname, GLint *params);
void (APIENTRY * qglGenerateMipmapEXT)(GLenum target);
// GL_ARB_occlusion_query
void (APIENTRY * qglGenQueriesARB)(GLsizei n, GLuint *ids);
void (APIENTRY * qglDeleteQueriesARB)(GLsizei n, const GLuint *ids);
GLboolean (APIENTRY * qglIsQueryARB)(GLuint id);
void (APIENTRY * qglBeginQueryARB)(GLenum target, GLuint id);
void (APIENTRY * qglEndQueryARB)(GLenum target);
void (APIENTRY * qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params);
void (APIENTRY * qglGetQueryObjectivARB)(GLuint id, GLenum pname, GLint *params);
void (APIENTRY * qglGetQueryObjectuivARB)(GLuint id, GLenum pname, GLuint *params);
// GL_EXT_framebuffer_blit
void (APIENTRY * qglBlitFramebufferEXT)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
// GL_EXT_framebuffer_multisample
void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples,
GLenum internalformat, GLsizei width, GLsizei height);
// GL_ARB_draw_buffers
void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs);
// GL_ARB_vertex_array_object
void (APIENTRY * qglBindVertexArrayARB)(GLuint array);
void (APIENTRY * qglDeleteVertexArraysARB)(GLsizei n, const GLuint *arrays);
void (APIENTRY * qglGenVertexArraysARB)(GLsizei n, GLuint *arrays);
GLboolean (APIENTRY * qglIsVertexArrayARB)(GLuint array);
static qboolean GLimp_HaveExtension(const char *ext)
{
const char *ptr = Q_stristr( glConfig.extensions_string, ext );
if (ptr == NULL)
return qfalse;
ptr += strlen(ext);
return ((*ptr == ' ') || (*ptr == '\0')); // verify it's complete string.
}
void GLimp_InitExtraExtensions()
{ {
char *extension; char *extension;
const char* result[3] = { "...ignoring %s\n", "...using %s\n", "...%s not found\n" }; const char* result[3] = { "...ignoring %s\n", "...using %s\n", "...%s not found\n" };
qboolean q_gl_version_at_least_3_0;
qboolean q_gl_version_at_least_3_2;
// GL_EXT_draw_range_elements q_gl_version_at_least_3_0 = QGL_VERSION_ATLEAST( 3, 0 );
extension = "GL_EXT_draw_range_elements"; q_gl_version_at_least_3_2 = QGL_VERSION_ATLEAST( 3, 2 );
glRefConfig.drawRangeElements = qfalse;
qglMultiDrawArraysEXT = NULL;
qglMultiDrawElementsEXT = NULL;
if( GLimp_HaveExtension( extension ) )
{
qglDrawRangeElementsEXT = (void *) SDL_GL_GetProcAddress("glDrawRangeElementsEXT");
if ( r_ext_draw_range_elements->integer) // Check if we need Intel graphics specific fixes.
glRefConfig.drawRangeElements = qtrue; glRefConfig.intelGraphics = qfalse;
if (strstr((char *)qglGetString(GL_RENDERER), "Intel"))
glRefConfig.intelGraphics = qtrue;
ri.Printf(PRINT_ALL, result[glRefConfig.drawRangeElements], extension); // set DSA fallbacks
} #define GLE(ret, name, ...) qgl##name = GLDSA_##name;
else QGL_EXT_direct_state_access_PROCS;
{ #undef GLE
ri.Printf(PRINT_ALL, result[2], extension);
}
// GL_EXT_multi_draw_arrays // GL function loader, based on https://gist.github.com/rygorous/16796a0c876cf8a5f542caddb55bce8a
extension = "GL_EXT_multi_draw_arrays"; #define GLE(ret, name, ...) qgl##name = (name##proc *) SDL_GL_GetProcAddress("gl" #name);
glRefConfig.multiDrawArrays = qfalse;
qglMultiDrawArraysEXT = NULL;
qglMultiDrawElementsEXT = NULL;
if( GLimp_HaveExtension( extension ) )
{
qglMultiDrawArraysEXT = (PFNGLMULTIDRAWARRAYSEXTPROC) SDL_GL_GetProcAddress("glMultiDrawArraysEXT");
qglMultiDrawElementsEXT = (PFNGLMULTIDRAWELEMENTSEXTPROC) SDL_GL_GetProcAddress("glMultiDrawElementsEXT");
if ( r_ext_multi_draw_arrays->integer ) // OpenGL 1.5 - GL_ARB_occlusion_query
glRefConfig.multiDrawArrays = qtrue; glRefConfig.occlusionQuery = qtrue;
QGL_ARB_occlusion_query_PROCS;
ri.Printf(PRINT_ALL, result[glRefConfig.multiDrawArrays], extension); // OpenGL 3.0 - GL_ARB_framebuffer_object
} extension = "GL_ARB_framebuffer_object";
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
// GL_ARB_vertex_program
//glRefConfig.vertexProgram = qfalse;
extension = "GL_ARB_vertex_program";
qglVertexAttrib4fARB = NULL;
qglVertexAttrib4fvARB = NULL;
qglVertexAttribPointerARB = NULL;
qglEnableVertexAttribArrayARB = NULL;
qglDisableVertexAttribArrayARB = NULL;
if( GLimp_HaveExtension( extension ) )
{
qglVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) SDL_GL_GetProcAddress("glVertexAttrib4fARB");
qglVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) SDL_GL_GetProcAddress("glVertexAttrib4fvARB");
qglVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) SDL_GL_GetProcAddress("glVertexAttribPointerARB");
qglEnableVertexAttribArrayARB =
(PFNGLENABLEVERTEXATTRIBARRAYARBPROC) SDL_GL_GetProcAddress("glEnableVertexAttribArrayARB");
qglDisableVertexAttribArrayARB =
(PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) SDL_GL_GetProcAddress("glDisableVertexAttribArrayARB");
ri.Printf(PRINT_ALL, result[1], extension);
//glRefConfig.vertexProgram = qtrue;
}
else
{
ri.Error(ERR_FATAL, result[2], extension);
}
// GL_ARB_vertex_buffer_object
//glRefConfig.vertexBufferObject = qfalse;
extension = "GL_ARB_vertex_buffer_object";
qglBindBufferARB = NULL;
qglDeleteBuffersARB = NULL;
qglGenBuffersARB = NULL;
qglIsBufferARB = NULL;
qglBufferDataARB = NULL;
qglBufferSubDataARB = NULL;
qglGetBufferSubDataARB = NULL;
qglGetBufferParameterivARB = NULL;
qglGetBufferPointervARB = NULL;
if( GLimp_HaveExtension( extension ) )
{
qglBindBufferARB = (PFNGLBINDBUFFERARBPROC) SDL_GL_GetProcAddress("glBindBufferARB");
qglDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) SDL_GL_GetProcAddress("glDeleteBuffersARB");
qglGenBuffersARB = (PFNGLGENBUFFERSARBPROC) SDL_GL_GetProcAddress("glGenBuffersARB");
qglIsBufferARB = (PFNGLISBUFFERARBPROC) SDL_GL_GetProcAddress("glIsBufferARB");
qglBufferDataARB = (PFNGLBUFFERDATAARBPROC) SDL_GL_GetProcAddress("glBufferDataARB");
qglBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glBufferSubDataARB");
qglGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glGetBufferSubDataARB");
qglGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetBufferParameterivARB");
qglGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC) SDL_GL_GetProcAddress("glGetBufferPointervARB");
ri.Printf(PRINT_ALL, result[1], extension);
//glRefConfig.vertexBufferObject = qtrue;
}
else
{
ri.Error(ERR_FATAL, result[2], extension);
}
// GL_ARB_shader_objects
extension = "GL_ARB_shader_objects";
//glRefConfig.shaderObjects = qfalse;
qglDeleteObjectARB = NULL;
qglGetHandleARB = NULL;
qglDetachObjectARB = NULL;
qglCreateShaderObjectARB = NULL;
qglShaderSourceARB = NULL;
qglCompileShaderARB = NULL;
qglCreateProgramObjectARB = NULL;
qglAttachObjectARB = NULL;
qglLinkProgramARB = NULL;
qglUseProgramObjectARB = NULL;
qglValidateProgramARB = NULL;
qglUniform1fARB = NULL;
qglUniform2fARB = NULL;
qglUniform3fARB = NULL;
qglUniform4fARB = NULL;
qglUniform1iARB = NULL;
qglUniform2iARB = NULL;
qglUniform3iARB = NULL;
qglUniform4iARB = NULL;
qglUniform1fvARB = NULL;
qglUniform2fvARB = NULL;
qglUniform3fvARB = NULL;
qglUniform4fvARB = NULL;
qglUniform2ivARB = NULL;
qglUniform3ivARB = NULL;
qglUniform4ivARB = NULL;
qglUniformMatrix2fvARB = NULL;
qglUniformMatrix3fvARB = NULL;
qglUniformMatrix4fvARB = NULL;
qglGetObjectParameterfvARB = NULL;
qglGetObjectParameterivARB = NULL;
qglGetInfoLogARB = NULL;
qglGetAttachedObjectsARB = NULL;
qglGetUniformLocationARB = NULL;
qglGetActiveUniformARB = NULL;
qglGetUniformfvARB = NULL;
qglGetUniformivARB = NULL;
qglGetShaderSourceARB = NULL;
if( GLimp_HaveExtension( extension ) )
{
qglDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
qglGetHandleARB = (PFNGLGETHANDLEARBPROC) SDL_GL_GetProcAddress("glGetHandleARB");
qglDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) SDL_GL_GetProcAddress("glDetachObjectARB");
qglCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
qglShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
qglCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
qglCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
qglAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
qglLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
qglUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");
qglValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) SDL_GL_GetProcAddress("glValidateProgramARB");
qglUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB");
qglUniform2fARB = (PFNGLUNIFORM2FARBPROC) SDL_GL_GetProcAddress("glUniform2fARB");
qglUniform3fARB = (PFNGLUNIFORM3FARBPROC) SDL_GL_GetProcAddress("glUniform3fARB");
qglUniform4fARB = (PFNGLUNIFORM4FARBPROC) SDL_GL_GetProcAddress("glUniform4fARB");
qglUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
qglUniform2iARB = (PFNGLUNIFORM2IARBPROC) SDL_GL_GetProcAddress("glUniform2iARB");
qglUniform3iARB = (PFNGLUNIFORM3IARBPROC) SDL_GL_GetProcAddress("glUniform3iARB");
qglUniform4iARB = (PFNGLUNIFORM4IARBPROC) SDL_GL_GetProcAddress("glUniform4iARB");
qglUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) SDL_GL_GetProcAddress("glUniform1fvARB");
qglUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) SDL_GL_GetProcAddress("glUniform2fvARB");
qglUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) SDL_GL_GetProcAddress("glUniform3fvARB");
qglUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) SDL_GL_GetProcAddress("glUniform4fvARB");
qglUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) SDL_GL_GetProcAddress("glUniform2ivARB");
qglUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) SDL_GL_GetProcAddress("glUniform3ivARB");
qglUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) SDL_GL_GetProcAddress("glUniform4ivARB");
qglUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix2fvARB");
qglUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix3fvARB");
qglUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix4fvARB");
qglGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterfvARB");
qglGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
qglGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
qglGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) SDL_GL_GetProcAddress("glGetAttachedObjectsARB");
qglGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
qglGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) SDL_GL_GetProcAddress("glGetActiveUniformARB");
qglGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) SDL_GL_GetProcAddress("glGetUniformfvARB");
qglGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) SDL_GL_GetProcAddress("glGetUniformivARB");
qglGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glGetShaderSourceARB");
ri.Printf(PRINT_ALL, result[1], extension);
//glRefConfig.shaderObjects = qtrue;
}
else
{
ri.Error(ERR_FATAL, result[2], extension);
}
// GL_ARB_vertex_shader
//glRefConfig.vertexShader = qfalse;
extension = "GL_ARB_vertex_shader";
qglBindAttribLocationARB = NULL;
qglGetActiveAttribARB = NULL;
qglGetAttribLocationARB = NULL;
if( GLimp_HaveExtension( extension ) )
{
//int reservedComponents;
//qglGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig.maxVertexUniforms);
//qglGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &glConfig.maxVaryingFloats);
//qglGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig.maxVertexAttribs);
//reservedComponents = 16 * 10; // approximation how many uniforms we have besides the bone matrices
#if 0
if(glConfig.driverType == GLDRV_MESA)
{
// HACK
// restrict to number of vertex uniforms to 512 because of:
// xreal.x86_64: nv50_program.c:4181: nv50_program_validate_data: Assertion `p->param_nr <= 512' failed
glConfig.maxVertexUniforms = Q_bound(0, glConfig.maxVertexUniforms, 512);
}
#endif
//glConfig.maxVertexSkinningBones = (int) Q_bound(0.0, (Q_max(glConfig.maxVertexUniforms - reservedComponents, 0) / 16), MAX_BONES);
//glConfig.vboVertexSkinningAvailable = r_vboVertexSkinning->integer && ((glConfig.maxVertexSkinningBones >= 12) ? qtrue : qfalse);
qglBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glBindAttribLocationARB");
qglGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) SDL_GL_GetProcAddress("glGetActiveAttribARB");
qglGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetAttribLocationARB");
ri.Printf(PRINT_ALL, result[1], extension);
//glRefConfig.vertexShader = qtrue;
}
else
{
ri.Error(ERR_FATAL, result[2], extension);
}
// GL_ARB_shading_language_100
extension = "GL_ARB_shading_language_100";
glRefConfig.textureFloat = qfalse;
if( GLimp_HaveExtension( extension ) )
{
char version[256];
Q_strncpyz( version, (char *) qglGetString (GL_SHADING_LANGUAGE_VERSION_ARB), sizeof( version ) );
sscanf(version, "%d.%d", &glRefConfig.glslMajorVersion, &glRefConfig.glslMinorVersion);
ri.Printf(PRINT_ALL, "...using GLSL version %s\n", version);
}
else
{
ri.Error(ERR_FATAL, result[2], extension);
}
glRefConfig.memInfo = MI_NONE;
if( GLimp_HaveExtension( "GL_NVX_gpu_memory_info" ) )
{
glRefConfig.memInfo = MI_NVX;
}
else if( GLimp_HaveExtension( "GL_ATI_meminfo" ) )
{
glRefConfig.memInfo = MI_ATI;
}
extension = "GL_ARB_texture_non_power_of_two";
glRefConfig.textureNonPowerOfTwo = qfalse;
if( GLimp_HaveExtension( extension ) )
{
if(1) //(r_ext_texture_non_power_of_two->integer)
{
glRefConfig.textureNonPowerOfTwo = qtrue;
}
ri.Printf(PRINT_ALL, result[glRefConfig.textureNonPowerOfTwo], extension);
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
// GL_ARB_texture_float
extension = "GL_ARB_texture_float";
glRefConfig.textureFloat = qfalse;
if( GLimp_HaveExtension( extension ) )
{
if( r_ext_texture_float->integer )
{
glRefConfig.textureFloat = qtrue;
}
ri.Printf(PRINT_ALL, result[glRefConfig.textureFloat], extension);
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
// GL_ARB_half_float_pixel
extension = "GL_ARB_half_float_pixel";
glRefConfig.halfFloatPixel = qfalse;
if( GLimp_HaveExtension( extension ) )
{
if( r_arb_half_float_pixel->integer )
glRefConfig.halfFloatPixel = qtrue;
ri.Printf(PRINT_ALL, result[glRefConfig.halfFloatPixel], extension);
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
// GL_EXT_framebuffer_object
extension = "GL_EXT_framebuffer_object";
glRefConfig.framebufferObject = qfalse; glRefConfig.framebufferObject = qfalse;
if( GLimp_HaveExtension( extension ) ) glRefConfig.framebufferBlit = qfalse;
glRefConfig.framebufferMultisample = qfalse;
if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension))
{ {
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &glRefConfig.maxRenderbufferSize); glRefConfig.framebufferObject = !!r_ext_framebuffer_object->integer;
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &glRefConfig.maxColorAttachments); glRefConfig.framebufferBlit = qtrue;
glRefConfig.framebufferMultisample = qtrue;
qglIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glIsRenderbufferEXT"); qglGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glRefConfig.maxRenderbufferSize);
qglBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glBindRenderbufferEXT"); qglGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &glRefConfig.maxColorAttachments);
qglDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) SDL_GL_GetProcAddress("glDeleteRenderbuffersEXT");
qglGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) SDL_GL_GetProcAddress("glGenRenderbuffersEXT");
qglRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) SDL_GL_GetProcAddress("glRenderbufferStorageEXT");
qglGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) SDL_GL_GetProcAddress("glGetRenderbufferParameterivEXT");
qglIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) SDL_GL_GetProcAddress("glIsFramebufferEXT");
qglBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) SDL_GL_GetProcAddress("glBindFramebufferEXT");
qglDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
qglGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) SDL_GL_GetProcAddress("glGenFramebuffersEXT");
qglCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
qglFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture1DEXT");
qglFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
qglFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture3DEXT");
qglFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glFramebufferRenderbufferEXT");
qglGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameterivEXT");
qglGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) SDL_GL_GetProcAddress("glGenerateMipmapEXT");
if(r_ext_framebuffer_object->value) QGL_ARB_framebuffer_object_PROCS;
glRefConfig.framebufferObject = qtrue;
ri.Printf(PRINT_ALL, result[glRefConfig.framebufferObject], extension); ri.Printf(PRINT_ALL, result[glRefConfig.framebufferObject], extension);
} }
@ -537,132 +80,64 @@ void GLimp_InitExtraExtensions()
ri.Printf(PRINT_ALL, result[2], extension); ri.Printf(PRINT_ALL, result[2], extension);
} }
// GL_EXT_packed_depth_stencil // OpenGL 3.0 - GL_ARB_vertex_array_object
extension = "GL_EXT_packed_depth_stencil"; extension = "GL_ARB_vertex_array_object";
glRefConfig.packedDepthStencil = qfalse; glRefConfig.vertexArrayObject = qfalse;
if( GLimp_HaveExtension(extension)) if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension))
{ {
glRefConfig.packedDepthStencil = qtrue; if (q_gl_version_at_least_3_0)
ri.Printf(PRINT_ALL, result[glRefConfig.packedDepthStencil], extension); {
// force VAO, core context requires it
glRefConfig.vertexArrayObject = qtrue;
}
else
{
glRefConfig.vertexArrayObject = !!r_arb_vertex_array_object->integer;
}
QGL_ARB_vertex_array_object_PROCS;
ri.Printf(PRINT_ALL, result[glRefConfig.vertexArrayObject], extension);
} }
else else
{ {
ri.Printf(PRINT_ALL, result[2], extension); ri.Printf(PRINT_ALL, result[2], extension);
} }
// GL_ARB_occlusion_query // OpenGL 3.0 - GL_ARB_texture_float
extension = "GL_ARB_occlusion_query"; extension = "GL_ARB_texture_float";
glRefConfig.occlusionQuery = qfalse; glRefConfig.textureFloat = qfalse;
if (GLimp_HaveExtension(extension)) if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension))
{ {
qglGenQueriesARB = (PFNGLGENQUERIESARBPROC) SDL_GL_GetProcAddress("glGenQueriesARB"); glRefConfig.textureFloat = !!r_ext_texture_float->integer;
qglDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC) SDL_GL_GetProcAddress("glDeleteQueriesARB");
qglIsQueryARB = (PFNGLISQUERYARBPROC) SDL_GL_GetProcAddress("glIsQueryARB"); ri.Printf(PRINT_ALL, result[glRefConfig.textureFloat], extension);
qglBeginQueryARB = (PFNGLBEGINQUERYARBPROC) SDL_GL_GetProcAddress("glBeginQueryARB");
qglEndQueryARB = (PFNGLENDQUERYARBPROC) SDL_GL_GetProcAddress("glEndQueryARB");
qglGetQueryivARB = (PFNGLGETQUERYIVARBPROC) SDL_GL_GetProcAddress("glGetQueryivARB");
qglGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC) SDL_GL_GetProcAddress("glGetQueryObjectivARB");
qglGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC) SDL_GL_GetProcAddress("glGetQueryObjectuivARB");
glRefConfig.occlusionQuery = qtrue;
ri.Printf(PRINT_ALL, result[glRefConfig.occlusionQuery], extension);
} }
else else
{ {
ri.Printf(PRINT_ALL, result[2], extension); ri.Printf(PRINT_ALL, result[2], extension);
} }
// GL_EXT_framebuffer_blit // OpenGL 3.2 - GL_ARB_depth_clamp
extension = "GL_EXT_framebuffer_blit";
glRefConfig.framebufferBlit = qfalse;
if (GLimp_HaveExtension(extension))
{
qglBlitFramebufferEXT = (void *)SDL_GL_GetProcAddress("glBlitFramebufferEXT");
glRefConfig.framebufferBlit = qtrue;
ri.Printf(PRINT_ALL, result[glRefConfig.framebufferBlit], extension);
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
// GL_EXT_framebuffer_multisample
extension = "GL_EXT_framebuffer_multisample";
glRefConfig.framebufferMultisample = qfalse;
if (GLimp_HaveExtension(extension))
{
qglRenderbufferStorageMultisampleEXT = (void *)SDL_GL_GetProcAddress("glRenderbufferStorageMultisampleEXT");
glRefConfig.framebufferMultisample = qtrue;
ri.Printf(PRINT_ALL, result[glRefConfig.framebufferMultisample], extension);
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
glRefConfig.textureCompression = TCR_NONE;
// GL_EXT_texture_compression_latc
extension = "GL_EXT_texture_compression_latc";
if (GLimp_HaveExtension(extension))
{
if (r_ext_compressed_textures->integer)
glRefConfig.textureCompression |= TCR_LATC;
ri.Printf(PRINT_ALL, result[r_ext_compressed_textures->integer ? 1 : 0], extension);
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
// GL_ARB_texture_compression_bptc
extension = "GL_ARB_texture_compression_bptc";
if (GLimp_HaveExtension(extension))
{
if (r_ext_compressed_textures->integer >= 2)
glRefConfig.textureCompression |= TCR_BPTC;
ri.Printf(PRINT_ALL, result[(r_ext_compressed_textures->integer >= 2) ? 1 : 0], extension);
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
// GL_ARB_draw_buffers
extension = "GL_ARB_draw_buffers";
qglDrawBuffersARB = NULL;
if( GLimp_HaveExtension( extension ) )
{
qglDrawBuffersARB = (void *) SDL_GL_GetProcAddress("glDrawBuffersARB");
ri.Printf(PRINT_ALL, result[1], extension);
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
// GL_ARB_depth_clamp
extension = "GL_ARB_depth_clamp"; extension = "GL_ARB_depth_clamp";
glRefConfig.depthClamp = qfalse; glRefConfig.depthClamp = qfalse;
if( GLimp_HaveExtension( extension ) ) if (q_gl_version_at_least_3_2 || SDL_GL_ExtensionSupported(extension))
{ {
glRefConfig.depthClamp = qtrue; glRefConfig.depthClamp = qtrue;
ri.Printf(PRINT_ALL, result[1], extension);
ri.Printf(PRINT_ALL, result[glRefConfig.depthClamp], extension);
} }
else else
{ {
ri.Printf(PRINT_ALL, result[2], extension); ri.Printf(PRINT_ALL, result[2], extension);
} }
// GL_ARB_seamless_cube_map // OpenGL 3.2 - GL_ARB_seamless_cube_map
extension = "GL_ARB_seamless_cube_map"; extension = "GL_ARB_seamless_cube_map";
glRefConfig.seamlessCubeMap = qfalse; glRefConfig.seamlessCubeMap = qfalse;
if( GLimp_HaveExtension( extension ) ) if (q_gl_version_at_least_3_2 || SDL_GL_ExtensionSupported(extension))
{ {
if (r_arb_seamless_cube_map->integer) glRefConfig.seamlessCubeMap = !!r_arb_seamless_cube_map->integer;
glRefConfig.seamlessCubeMap = qtrue;
ri.Printf(PRINT_ALL, result[glRefConfig.seamlessCubeMap], extension); ri.Printf(PRINT_ALL, result[glRefConfig.seamlessCubeMap], extension);
} }
@ -671,65 +146,108 @@ void GLimp_InitExtraExtensions()
ri.Printf(PRINT_ALL, result[2], extension); ri.Printf(PRINT_ALL, result[2], extension);
} }
// GL_ARB_vertex_type_2_10_10_10_rev // Determine GLSL version
extension = "GL_ARB_vertex_type_2_10_10_10_rev"; if (1)
glRefConfig.packedNormalDataType = GL_BYTE;
if( GLimp_HaveExtension( extension ) )
{ {
if (r_arb_vertex_type_2_10_10_10_rev->integer) char version[256];
glRefConfig.packedNormalDataType = GL_INT_2_10_10_10_REV;
ri.Printf(PRINT_ALL, result[r_arb_vertex_type_2_10_10_10_rev->integer ? 1 : 0], extension); Q_strncpyz(version, (char *)qglGetString(GL_SHADING_LANGUAGE_VERSION), sizeof(version));
sscanf(version, "%d.%d", &glRefConfig.glslMajorVersion, &glRefConfig.glslMinorVersion);
ri.Printf(PRINT_ALL, "...using GLSL version %s\n", version);
}
glRefConfig.memInfo = MI_NONE;
// GL_NVX_gpu_memory_info
extension = "GL_NVX_gpu_memory_info";
if( SDL_GL_ExtensionSupported( extension ) )
{
glRefConfig.memInfo = MI_NVX;
ri.Printf(PRINT_ALL, result[1], extension);
} }
else else
{ {
ri.Printf(PRINT_ALL, result[2], extension); ri.Printf(PRINT_ALL, result[2], extension);
} }
// use float lightmaps? // GL_ATI_meminfo
glRefConfig.floatLightmap = (glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer && r_hdr->integer); extension = "GL_ATI_meminfo";
if( SDL_GL_ExtensionSupported( extension ) )
// GL_ARB_vertex_array_object
extension = "GL_ARB_vertex_array_object";
glRefConfig.vertexArrayObject = qfalse;
if( GLimp_HaveExtension( extension ) )
{ {
qglBindVertexArrayARB = (void *) SDL_GL_GetProcAddress("glBindVertexArray"); if (glRefConfig.memInfo == MI_NONE)
qglDeleteVertexArraysARB = (void *) SDL_GL_GetProcAddress("glDeleteVertexArrays");
qglGenVertexArraysARB = (void *) SDL_GL_GetProcAddress("glGenVertexArrays");
qglIsVertexArrayARB = (void *) SDL_GL_GetProcAddress("glIsVertexArray");
if (r_arb_vertex_array_object->integer)
glRefConfig.vertexArrayObject = qtrue;
ri.Printf(PRINT_ALL, result[glRefConfig.vertexArrayObject ? 1 : 0], extension);
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
// GL_ARB_half_float_vertex
extension = "GL_ARB_half_float_vertex";
glRefConfig.packedTexcoordDataType = GL_FLOAT;
glRefConfig.packedTexcoordDataSize = sizeof(float) * 2;
glRefConfig.packedColorDataType = GL_FLOAT;
glRefConfig.packedColorDataSize = sizeof(float) * 4;
if( GLimp_HaveExtension( extension ) )
{
if (r_arb_half_float_vertex->integer)
{ {
glRefConfig.packedTexcoordDataType = GL_HALF_FLOAT; glRefConfig.memInfo = MI_ATI;
glRefConfig.packedTexcoordDataSize = sizeof(uint16_t) * 2;
glRefConfig.packedColorDataType = GL_HALF_FLOAT; ri.Printf(PRINT_ALL, result[1], extension);
glRefConfig.packedColorDataSize = sizeof(uint16_t) * 4; }
else
{
ri.Printf(PRINT_ALL, result[0], extension);
}
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
glRefConfig.textureCompression = TCR_NONE;
// GL_ARB_texture_compression_rgtc
extension = "GL_ARB_texture_compression_rgtc";
if (SDL_GL_ExtensionSupported(extension))
{
qboolean useRgtc = r_ext_compressed_textures->integer >= 1;
if (useRgtc)
glRefConfig.textureCompression |= TCR_RGTC;
ri.Printf(PRINT_ALL, result[useRgtc], extension);
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
glRefConfig.swizzleNormalmap = r_ext_compressed_textures->integer && !(glRefConfig.textureCompression & TCR_RGTC);
// GL_ARB_texture_compression_bptc
extension = "GL_ARB_texture_compression_bptc";
if (SDL_GL_ExtensionSupported(extension))
{
qboolean useBptc = r_ext_compressed_textures->integer >= 2;
if (useBptc)
glRefConfig.textureCompression |= TCR_BPTC;
ri.Printf(PRINT_ALL, result[useBptc], extension);
}
else
{
ri.Printf(PRINT_ALL, result[2], extension);
}
// GL_EXT_direct_state_access
extension = "GL_EXT_direct_state_access";
glRefConfig.directStateAccess = qfalse;
if (SDL_GL_ExtensionSupported(extension))
{
glRefConfig.directStateAccess = !!r_ext_direct_state_access->integer;
// QGL_*_PROCS becomes several functions, do not remove {}
if (glRefConfig.directStateAccess)
{
QGL_EXT_direct_state_access_PROCS;
} }
ri.Printf(PRINT_ALL, result[r_arb_half_float_vertex->integer ? 1 : 0], extension); ri.Printf(PRINT_ALL, result[glRefConfig.directStateAccess], extension);
} }
else else
{ {
ri.Printf(PRINT_ALL, result[2], extension); ri.Printf(PRINT_ALL, result[2], extension);
} }
#undef GLE
} }

View file

@ -194,7 +194,7 @@ int NextPowerOfTwo(int in)
union f32_u { union f32_u {
float f; float f;
uint32_t i; uint32_t ui;
struct { struct {
unsigned int fraction:23; unsigned int fraction:23;
unsigned int exponent:8; unsigned int exponent:8;
@ -203,7 +203,7 @@ union f32_u {
}; };
union f16_u { union f16_u {
uint16_t i; uint16_t ui;
struct { struct {
unsigned int fraction:10; unsigned int fraction:10;
unsigned int exponent:5; unsigned int exponent:5;
@ -222,5 +222,19 @@ uint16_t FloatToHalf(float in)
f16.pack.fraction = f32.pack.fraction >> 13; f16.pack.fraction = f32.pack.fraction >> 13;
f16.pack.sign = f32.pack.sign; f16.pack.sign = f32.pack.sign;
return f16.i; return f16.ui;
}
float HalfToFloat(uint16_t in)
{
union f32_u f32;
union f16_u f16;
f16.ui = in;
f32.pack.exponent = (int)(f16.pack.exponent) + 112;
f32.pack.fraction = f16.pack.fraction << 13;
f32.pack.sign = f16.pack.sign;
return f32.f;
} }

View file

@ -44,13 +44,17 @@ void Mat4SimpleInverse( const mat4_t in, mat4_t out);
#define VectorCopy2(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1]) #define VectorCopy2(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1])
#define VectorSet2(v,x,y) ((v)[0]=(x),(v)[1]=(y)); #define VectorSet2(v,x,y) ((v)[0]=(x),(v)[1]=(y));
#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
#define VectorSet4(v,x,y,z,w) ((v)[0]=(x),(v)[1]=(y),(v)[2]=(z),(v)[3]=(w))
#define VectorScale4(a,b,c) ((c)[0]=(a)[0]*(b),(c)[1]=(a)[1]*(b),(c)[2]=(a)[2]*(b),(c)[3]=(a)[3]*(b))
#define VectorCopy5(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3],(b)[4]=(a)[4])
#define OffsetByteToFloat(a) ((float)(a) * 1.0f/127.5f - 1.0f) #define OffsetByteToFloat(a) ((float)(a) * 1.0f/127.5f - 1.0f)
#define FloatToOffsetByte(a) (byte)((a) * 127.5f + 128.0f) #define FloatToOffsetByte(a) (byte)((a) * 127.5f + 128.0f)
#define ByteToFloat(a) ((float)(a) * 1.0f/255.0f) #define ByteToFloat(a) ((float)(a) * 1.0f/255.0f)
#define FloatToByte(a) (byte)((a) * 255.0f) #define FloatToByte(a) (byte)((a) * 255.0f)
void VectorLerp( const vec3_t a, const vec3_t b, float lerp, vec3_t c);
qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2); qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2);
void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3); void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3);
@ -73,5 +77,6 @@ void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, floa
int NextPowerOfTwo(int in); int NextPowerOfTwo(int in);
unsigned short FloatToHalf(float in); unsigned short FloatToHalf(float in);
float HalfToFloat(unsigned short in);
#endif #endif

View file

@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// tr_fbo.c // tr_fbo.c
#include "tr_local.h" #include "tr_local.h"
#include "tr_dsa.h"
/* /*
============= =============
R_CheckFBO R_CheckFBO
@ -30,66 +32,43 @@ R_CheckFBO
*/ */
qboolean R_CheckFBO(const FBO_t * fbo) qboolean R_CheckFBO(const FBO_t * fbo)
{ {
int code; GLenum code = qglCheckNamedFramebufferStatusEXT(fbo->frameBuffer, GL_FRAMEBUFFER);
int id;
qglGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &id); if(code == GL_FRAMEBUFFER_COMPLETE)
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer);
code = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if(code == GL_FRAMEBUFFER_COMPLETE_EXT)
{
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
return qtrue; return qtrue;
}
// an error occured // an error occurred
switch (code) switch (code)
{ {
case GL_FRAMEBUFFER_UNSUPPORTED_EXT: case GL_FRAMEBUFFER_UNSUPPORTED:
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Unsupported framebuffer format\n", fbo->name); ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Unsupported framebuffer format\n", fbo->name);
break; break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete attachment\n", fbo->name); ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete attachment\n", fbo->name);
break; break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing attachment\n", fbo->name); ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing attachment\n", fbo->name);
break; break;
//case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
// ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, duplicate attachment\n", fbo->name);
// break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, attached images must have same dimensions\n",
fbo->name);
break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, attached images must have same format\n",
fbo->name);
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing draw buffer\n", fbo->name); ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing draw buffer\n", fbo->name);
break; break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing read buffer\n", fbo->name); ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing read buffer\n", fbo->name);
break; break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete multisample\n", fbo->name);
break;
default: default:
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) unknown error 0x%X\n", fbo->name, code); ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) unknown error 0x%X\n", fbo->name, code);
//ri.Error(ERR_FATAL, "R_CheckFBO: (%s) unknown error 0x%X", fbo->name, code);
//assert(0);
break; break;
} }
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
return qfalse; return qfalse;
} }
@ -128,11 +107,16 @@ FBO_t *FBO_Create(const char *name, int width, int height)
fbo->width = width; fbo->width = width;
fbo->height = height; fbo->height = height;
qglGenFramebuffersEXT(1, &fbo->frameBuffer); qglGenFramebuffers(1, &fbo->frameBuffer);
return fbo; return fbo;
} }
/*
=================
FBO_CreateBuffer
=================
*/
void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample) void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
{ {
uint32_t *pRenderBuffer; uint32_t *pRenderBuffer;
@ -151,7 +135,7 @@ void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
case GL_RGBA32F_ARB: case GL_RGBA32F_ARB:
fbo->colorFormat = format; fbo->colorFormat = format;
pRenderBuffer = &fbo->colorBuffers[index]; pRenderBuffer = &fbo->colorBuffers[index];
attachment = GL_COLOR_ATTACHMENT0_EXT + index; attachment = GL_COLOR_ATTACHMENT0 + index;
break; break;
case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT:
@ -160,21 +144,21 @@ void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
case GL_DEPTH_COMPONENT32_ARB: case GL_DEPTH_COMPONENT32_ARB:
fbo->depthFormat = format; fbo->depthFormat = format;
pRenderBuffer = &fbo->depthBuffer; pRenderBuffer = &fbo->depthBuffer;
attachment = GL_DEPTH_ATTACHMENT_EXT; attachment = GL_DEPTH_ATTACHMENT;
break; break;
case GL_STENCIL_INDEX: case GL_STENCIL_INDEX:
case GL_STENCIL_INDEX1_EXT: case GL_STENCIL_INDEX1:
case GL_STENCIL_INDEX4_EXT: case GL_STENCIL_INDEX4:
case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX8:
case GL_STENCIL_INDEX16_EXT: case GL_STENCIL_INDEX16:
fbo->stencilFormat = format; fbo->stencilFormat = format;
pRenderBuffer = &fbo->stencilBuffer; pRenderBuffer = &fbo->stencilBuffer;
attachment = GL_STENCIL_ATTACHMENT_EXT; attachment = GL_STENCIL_ATTACHMENT;
break; break;
case GL_DEPTH_STENCIL_EXT: case GL_DEPTH_STENCIL:
case GL_DEPTH24_STENCIL8_EXT: case GL_DEPTH24_STENCIL8:
fbo->packedDepthStencilFormat = format; fbo->packedDepthStencilFormat = format;
pRenderBuffer = &fbo->packedDepthStencilBuffer; pRenderBuffer = &fbo->packedDepthStencilBuffer;
attachment = 0; // special for stencil and depth attachment = 0; // special for stencil and depth
@ -187,117 +171,47 @@ void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
absent = *pRenderBuffer == 0; absent = *pRenderBuffer == 0;
if (absent) if (absent)
qglGenRenderbuffersEXT(1, pRenderBuffer); qglGenRenderbuffers(1, pRenderBuffer);
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, *pRenderBuffer);
if (multisample && glRefConfig.framebufferMultisample) if (multisample && glRefConfig.framebufferMultisample)
{ qglNamedRenderbufferStorageMultisampleEXT(*pRenderBuffer, multisample, format, fbo->width, fbo->height);
qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, multisample, format, fbo->width, fbo->height);
}
else else
{ qglNamedRenderbufferStorageEXT(*pRenderBuffer, format, fbo->width, fbo->height);
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, fbo->width, fbo->height);
}
if(absent) if(absent)
{ {
if (attachment == 0) if (attachment == 0)
{ {
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer); qglNamedFramebufferRenderbufferEXT(fbo->frameBuffer, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, *pRenderBuffer);
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer); qglNamedFramebufferRenderbufferEXT(fbo->frameBuffer, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, *pRenderBuffer);
} }
else else
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, *pRenderBuffer); {
qglNamedFramebufferRenderbufferEXT(fbo->frameBuffer, attachment, GL_RENDERBUFFER, *pRenderBuffer);
}
} }
} }
/* /*
================= =================
R_AttachFBOTexture1D FBO_AttachImage
================= =================
*/ */
void R_AttachFBOTexture1D(int texId, int index) void FBO_AttachImage(FBO_t *fbo, image_t *image, GLenum attachment, GLuint cubemapside)
{ {
if(index < 0 || index >= glRefConfig.maxColorAttachments) GLenum target = GL_TEXTURE_2D;
{ int index;
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture1D: invalid attachment index %i\n", index);
return;
}
qglFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_1D, texId, 0); if (image->flags & IMGFLAG_CUBEMAP)
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + cubemapside;
qglNamedFramebufferTexture2DEXT(fbo->frameBuffer, attachment, target, image->texnum, 0);
index = attachment - GL_COLOR_ATTACHMENT0;
if (index >= 0 && index <= 15)
fbo->colorImage[index] = image;
} }
/*
=================
R_AttachFBOTexture2D
=================
*/
void R_AttachFBOTexture2D(int target, int texId, int index)
{
if(target != GL_TEXTURE_2D && (target < GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB || target > GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB))
{
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid target %i\n", target);
return;
}
if(index < 0 || index >= glRefConfig.maxColorAttachments)
{
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid attachment index %i\n", index);
return;
}
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, target, texId, 0);
}
/*
=================
R_AttachFBOTexture3D
=================
*/
void R_AttachFBOTexture3D(int texId, int index, int zOffset)
{
if(index < 0 || index >= glRefConfig.maxColorAttachments)
{
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture3D: invalid attachment index %i\n", index);
return;
}
qglFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_3D_EXT, texId, 0, zOffset);
}
/*
=================
R_AttachFBOTextureDepth
=================
*/
void R_AttachFBOTextureDepth(int texId)
{
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
}
/*
=================
R_AttachFBOTexturePackedDepthStencil
=================
*/
void R_AttachFBOTexturePackedDepthStencil(int texId)
{
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
}
void FBO_AttachTextureImage(image_t *img, int index)
{
if (!glState.currentFBO)
{
ri.Printf(PRINT_WARNING, "FBO: attempted to attach a texture image with no FBO bound!\n");
return;
}
R_AttachFBOTexture2D(GL_TEXTURE_2D, img->texnum, index);
glState.currentFBO->colorImage[index] = img;
}
/* /*
============ ============
@ -306,44 +220,22 @@ FBO_Bind
*/ */
void FBO_Bind(FBO_t * fbo) void FBO_Bind(FBO_t * fbo)
{ {
if (!glRefConfig.framebufferObject)
{
ri.Printf(PRINT_WARNING, "FBO_Bind() called without framebuffers enabled!\n");
return;
}
if (glState.currentFBO == fbo) if (glState.currentFBO == fbo)
return; return;
if (r_logFile->integer) if (r_logFile->integer)
{ {
// don't just call LogComment, or we will get a call to va() every frame! // don't just call LogComment, or we will get a call to va() every frame!
if (fbo) GLimp_LogComment(va("--- FBO_Bind( %s ) ---\n", fbo ? fbo->name : "NULL"));
GLimp_LogComment(va("--- FBO_Bind( %s ) ---\n", fbo->name));
else
GLimp_LogComment("--- FBO_Bind ( NULL ) ---\n");
} }
if (!fbo) GL_BindFramebuffer(GL_FRAMEBUFFER, fbo ? fbo->frameBuffer : 0);
{
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
//qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
glState.currentFBO = NULL;
return;
}
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer);
/*
if(fbo->colorBuffers[0])
{
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->colorBuffers[0]);
}
*/
/*
if(fbo->depthBuffer)
{
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->depthBuffer);
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthBuffer);
}
*/
glState.currentFBO = fbo; glState.currentFBO = fbo;
} }
@ -355,8 +247,7 @@ FBO_Init
void FBO_Init(void) void FBO_Init(void)
{ {
int i; int i;
// int width, height, hdrFormat, multisample; int hdrFormat, multisample = 0;
int hdrFormat, multisample;
ri.Printf(PRINT_ALL, "------- FBO_Init -------\n"); ri.Printf(PRINT_ALL, "------- FBO_Init -------\n");
@ -369,36 +260,22 @@ void FBO_Init(void)
R_IssuePendingRenderCommands(); R_IssuePendingRenderCommands();
/* if(glRefConfig.textureNonPowerOfTwo)
{
width = glConfig.vidWidth;
height = glConfig.vidHeight;
}
else
{
width = NextPowerOfTwo(glConfig.vidWidth);
height = NextPowerOfTwo(glConfig.vidHeight);
} */
hdrFormat = GL_RGBA8; hdrFormat = GL_RGBA8;
if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat) if (r_hdr->integer && glRefConfig.textureFloat)
{
hdrFormat = GL_RGBA16F_ARB; hdrFormat = GL_RGBA16F_ARB;
}
qglGetIntegerv(GL_MAX_SAMPLES_EXT, &multisample); if (glRefConfig.framebufferMultisample)
qglGetIntegerv(GL_MAX_SAMPLES, &multisample);
if (r_ext_framebuffer_multisample->integer < multisample) if (r_ext_framebuffer_multisample->integer < multisample)
{
multisample = r_ext_framebuffer_multisample->integer; multisample = r_ext_framebuffer_multisample->integer;
}
if (multisample < 2 || !glRefConfig.framebufferBlit) if (multisample < 2 || !glRefConfig.framebufferBlit)
multisample = 0; multisample = 0;
if (multisample != r_ext_framebuffer_multisample->integer) if (multisample != r_ext_framebuffer_multisample->integer) {
{ char buf[10];
ri.Cvar_Set( "r_ext_framebuffer_multisample", va( "%f", ( float )multisample ) ); ri.Cvar_Set("r_ext_framebuffer_multisample", itoa(multisample, buf, 10));
} }
// only create a render FBO if we need to resolve MSAA or do HDR // only create a render FBO if we need to resolve MSAA or do HDR
@ -406,36 +283,20 @@ void FBO_Init(void)
if (multisample && glRefConfig.framebufferMultisample) if (multisample && glRefConfig.framebufferMultisample)
{ {
tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
FBO_Bind(tr.renderFbo);
FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample); FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample);
FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample); FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24, 0, multisample);
R_CheckFBO(tr.renderFbo); R_CheckFBO(tr.renderFbo);
tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height); tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height);
FBO_Bind(tr.msaaResolveFbo); FBO_AttachImage(tr.msaaResolveFbo, tr.renderImage, GL_COLOR_ATTACHMENT0, 0);
FBO_AttachImage(tr.msaaResolveFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0);
//FBO_CreateBuffer(tr.msaaResolveFbo, hdrFormat, 0, 0);
FBO_AttachTextureImage(tr.renderImage, 0);
//FBO_CreateBuffer(tr.msaaResolveFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
R_CheckFBO(tr.msaaResolveFbo); R_CheckFBO(tr.msaaResolveFbo);
} }
else if (r_hdr->integer) else if (r_hdr->integer)
{ {
tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
FBO_Bind(tr.renderFbo); FBO_AttachImage(tr.renderFbo, tr.renderImage, GL_COLOR_ATTACHMENT0, 0);
FBO_AttachImage(tr.renderFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0);
//FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, 0);
FBO_AttachTextureImage(tr.renderImage, 0);
//FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
R_CheckFBO(tr.renderFbo); R_CheckFBO(tr.renderFbo);
} }
@ -443,144 +304,118 @@ void FBO_Init(void)
// this fixes the corrupt screen bug with r_hdr 1 on older hardware // this fixes the corrupt screen bug with r_hdr 1 on older hardware
if (tr.renderFbo) if (tr.renderFbo)
{ {
FBO_Bind(tr.renderFbo); GL_BindFramebuffer(GL_FRAMEBUFFER, tr.renderFbo->frameBuffer);
qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
FBO_Bind(NULL);
} }
if (r_drawSunRays->integer) if (tr.screenScratchImage)
{
tr.screenScratchFbo = FBO_Create("screenScratch", tr.screenScratchImage->width, tr.screenScratchImage->height);
FBO_AttachImage(tr.screenScratchFbo, tr.screenScratchImage, GL_COLOR_ATTACHMENT0, 0);
FBO_AttachImage(tr.screenScratchFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0);
R_CheckFBO(tr.screenScratchFbo);
}
if (tr.sunRaysImage)
{ {
tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height); tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height);
FBO_Bind(tr.sunRaysFbo); FBO_AttachImage(tr.sunRaysFbo, tr.sunRaysImage, GL_COLOR_ATTACHMENT0, 0);
FBO_AttachImage(tr.sunRaysFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0);
FBO_AttachTextureImage(tr.sunRaysImage, 0);
R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
R_CheckFBO(tr.sunRaysFbo); R_CheckFBO(tr.sunRaysFbo);
} }
// FIXME: Don't use separate color/depth buffers for a shadow buffer
if (MAX_DRAWN_PSHADOWS && tr.pshadowMaps[0]) if (MAX_DRAWN_PSHADOWS && tr.pshadowMaps[0])
{ {
for( i = 0; i < MAX_DRAWN_PSHADOWS; i++) for( i = 0; i < MAX_DRAWN_PSHADOWS; i++)
{ {
tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height); tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height);
FBO_Bind(tr.pshadowFbos[i]); // FIXME: this next line wastes 16mb with 16x512x512 sun shadow maps, skip if OpenGL 4.3+ or ARB_framebuffer_no_attachments
FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0);
//FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0); FBO_AttachImage(tr.pshadowFbos[i], tr.pshadowMaps[i], GL_DEPTH_ATTACHMENT, 0);
FBO_AttachTextureImage(tr.pshadowMaps[i], 0);
FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0);
//R_AttachFBOTextureDepth(tr.textureDepthImage->texnum);
R_CheckFBO(tr.pshadowFbos[i]); R_CheckFBO(tr.pshadowFbos[i]);
} }
} }
if (tr.sunShadowDepthImage[0]) if (tr.sunShadowDepthImage[0])
{ {
for ( i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height); tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height);
FBO_Bind(tr.sunShadowFbo[i]); // FIXME: this next line wastes 16mb with 4x1024x1024 sun shadow maps, skip if OpenGL 4.3+ or ARB_framebuffer_no_attachments
// This at least gets sun shadows working on older GPUs (Intel)
//FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0); FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0);
//FBO_AttachTextureImage(tr.sunShadowImage, 0); FBO_AttachImage(tr.sunShadowFbo[i], tr.sunShadowDepthImage[i], GL_DEPTH_ATTACHMENT, 0);
qglDrawBuffer(GL_NONE);
qglReadBuffer(GL_NONE);
//FBO_CreateBuffer(tr.sunShadowFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
R_AttachFBOTextureDepth(tr.sunShadowDepthImage[i]->texnum);
R_CheckFBO(tr.sunShadowFbo[i]); R_CheckFBO(tr.sunShadowFbo[i]);
} }
}
if (tr.screenShadowImage)
{
tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height); tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height);
FBO_Bind(tr.screenShadowFbo); FBO_AttachImage(tr.screenShadowFbo, tr.screenShadowImage, GL_COLOR_ATTACHMENT0, 0);
FBO_AttachTextureImage(tr.screenShadowImage, 0);
R_CheckFBO(tr.screenShadowFbo); R_CheckFBO(tr.screenShadowFbo);
} }
for (i = 0; i < 2; i++) if (tr.textureScratchImage[0])
{ {
tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height); for (i = 0; i < 2; i++)
FBO_Bind(tr.textureScratchFbo[i]); {
tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height);
//FBO_CreateBuffer(tr.textureScratchFbo[i], GL_RGBA8, 0, 0); FBO_AttachImage(tr.textureScratchFbo[i], tr.textureScratchImage[i], GL_COLOR_ATTACHMENT0, 0);
FBO_AttachTextureImage(tr.textureScratchImage[i], 0); R_CheckFBO(tr.textureScratchFbo[i]);
}
R_CheckFBO(tr.textureScratchFbo[i]);
} }
if (tr.calcLevelsImage)
{ {
tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height); tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height);
FBO_Bind(tr.calcLevelsFbo); FBO_AttachImage(tr.calcLevelsFbo, tr.calcLevelsImage, GL_COLOR_ATTACHMENT0, 0);
//FBO_CreateBuffer(tr.calcLevelsFbo, hdrFormat, 0, 0);
FBO_AttachTextureImage(tr.calcLevelsImage, 0);
R_CheckFBO(tr.calcLevelsFbo); R_CheckFBO(tr.calcLevelsFbo);
} }
if (tr.targetLevelsImage)
{ {
tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height); tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height);
FBO_Bind(tr.targetLevelsFbo); FBO_AttachImage(tr.targetLevelsFbo, tr.targetLevelsImage, GL_COLOR_ATTACHMENT0, 0);
//FBO_CreateBuffer(tr.targetLevelsFbo, hdrFormat, 0, 0);
FBO_AttachTextureImage(tr.targetLevelsImage, 0);
R_CheckFBO(tr.targetLevelsFbo); R_CheckFBO(tr.targetLevelsFbo);
} }
for (i = 0; i < 2; i++) if (tr.quarterImage[0])
{ {
tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height); for (i = 0; i < 2; i++)
FBO_Bind(tr.quarterFbo[i]); {
tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height);
//FBO_CreateBuffer(tr.quarterFbo[i], hdrFormat, 0, 0); FBO_AttachImage(tr.quarterFbo[i], tr.quarterImage[i], GL_COLOR_ATTACHMENT0, 0);
FBO_AttachTextureImage(tr.quarterImage[i], 0); R_CheckFBO(tr.quarterFbo[i]);
}
R_CheckFBO(tr.quarterFbo[i]);
} }
if (r_ssao->integer) if (tr.hdrDepthImage)
{ {
tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height); tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height);
FBO_Bind(tr.hdrDepthFbo); FBO_AttachImage(tr.hdrDepthFbo, tr.hdrDepthImage, GL_COLOR_ATTACHMENT0, 0);
FBO_AttachTextureImage(tr.hdrDepthImage, 0);
R_CheckFBO(tr.hdrDepthFbo); R_CheckFBO(tr.hdrDepthFbo);
}
if (tr.screenSsaoImage)
{
tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height); tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height);
FBO_Bind(tr.screenSsaoFbo); FBO_AttachImage(tr.screenSsaoFbo, tr.screenSsaoImage, GL_COLOR_ATTACHMENT0, 0);
FBO_AttachTextureImage(tr.screenSsaoImage, 0);
R_CheckFBO(tr.screenSsaoFbo); R_CheckFBO(tr.screenSsaoFbo);
} }
if (tr.renderCubeImage) if (tr.renderCubeImage)
{ {
tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height); tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height);
FBO_Bind(tr.renderCubeFbo); FBO_AttachImage(tr.renderCubeFbo, tr.renderCubeImage, GL_COLOR_ATTACHMENT0, 0);
//FBO_AttachTextureImage(tr.renderCubeImage, 0);
R_AttachFBOTexture2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, tr.renderCubeImage->texnum, 0);
glState.currentFBO->colorImage[0] = tr.renderCubeImage;
FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
R_CheckFBO(tr.renderCubeFbo); R_CheckFBO(tr.renderCubeFbo);
} }
GL_CheckErrors(); GL_CheckErrors();
FBO_Bind(NULL); GL_BindFramebuffer(GL_FRAMEBUFFER, 0);
glState.currentFBO = NULL;
} }
/* /*
@ -607,17 +442,17 @@ void FBO_Shutdown(void)
for(j = 0; j < glRefConfig.maxColorAttachments; j++) for(j = 0; j < glRefConfig.maxColorAttachments; j++)
{ {
if(fbo->colorBuffers[j]) if(fbo->colorBuffers[j])
qglDeleteRenderbuffersEXT(1, &fbo->colorBuffers[j]); qglDeleteRenderbuffers(1, &fbo->colorBuffers[j]);
} }
if(fbo->depthBuffer) if(fbo->depthBuffer)
qglDeleteRenderbuffersEXT(1, &fbo->depthBuffer); qglDeleteRenderbuffers(1, &fbo->depthBuffer);
if(fbo->stencilBuffer) if(fbo->stencilBuffer)
qglDeleteRenderbuffersEXT(1, &fbo->stencilBuffer); qglDeleteRenderbuffers(1, &fbo->stencilBuffer);
if(fbo->frameBuffer) if(fbo->frameBuffer)
qglDeleteFramebuffersEXT(1, &fbo->frameBuffer); qglDeleteFramebuffers(1, &fbo->frameBuffer);
} }
} }
@ -650,10 +485,9 @@ void R_FBOList_f(void)
ri.Printf(PRINT_ALL, " %i FBOs\n", tr.numFBOs); ri.Printf(PRINT_ALL, " %i FBOs\n", tr.numFBOs);
} }
void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexScale, FBO_t *dst, ivec4_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend) void FBO_BlitFromTexture(struct image_s *src, vec4_t inSrcTexCorners, vec2_t inSrcTexScale, FBO_t *dst, ivec4_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend)
{ {
ivec4_t dstBox, srcBox; ivec4_t dstBox;
vec2_t srcTexScale;
vec4_t color; vec4_t color;
vec4_t quadVerts[4]; vec4_t quadVerts[4];
vec2_t texCoords[4]; vec2_t texCoords[4];
@ -663,51 +497,49 @@ void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexS
int width, height; int width, height;
if (!src) if (!src)
return;
if (inSrcBox)
{ {
VectorSet4(srcBox, inSrcBox[0], inSrcBox[1], inSrcBox[0] + inSrcBox[2], inSrcBox[1] + inSrcBox[3]); ri.Printf(PRINT_WARNING, "Tried to blit from a NULL texture!\n");
return;
}
width = dst ? dst->width : glConfig.vidWidth;
height = dst ? dst->height : glConfig.vidHeight;
if (inSrcTexCorners)
{
VectorSet2(texCoords[0], inSrcTexCorners[0], inSrcTexCorners[1]);
VectorSet2(texCoords[1], inSrcTexCorners[2], inSrcTexCorners[1]);
VectorSet2(texCoords[2], inSrcTexCorners[2], inSrcTexCorners[3]);
VectorSet2(texCoords[3], inSrcTexCorners[0], inSrcTexCorners[3]);
} }
else else
{ {
VectorSet4(srcBox, 0, 0, src->width, src->height); VectorSet2(texCoords[0], 0.0f, 1.0f);
VectorSet2(texCoords[1], 1.0f, 1.0f);
VectorSet2(texCoords[2], 1.0f, 0.0f);
VectorSet2(texCoords[3], 0.0f, 0.0f);
} }
// framebuffers are 0 bottom, Y up. // framebuffers are 0 bottom, Y up.
if (inDstBox) if (inDstBox)
{ {
if (dst) dstBox[0] = inDstBox[0];
{ dstBox[1] = height - inDstBox[1] - inDstBox[3];
dstBox[0] = inDstBox[0]; dstBox[2] = inDstBox[0] + inDstBox[2];
dstBox[1] = dst->height - inDstBox[1] - inDstBox[3]; dstBox[3] = height - inDstBox[1];
dstBox[2] = inDstBox[0] + inDstBox[2];
dstBox[3] = dst->height - inDstBox[1];
}
else
{
dstBox[0] = inDstBox[0];
dstBox[1] = glConfig.vidHeight - inDstBox[1] - inDstBox[3];
dstBox[2] = inDstBox[0] + inDstBox[2];
dstBox[3] = glConfig.vidHeight - inDstBox[1];
}
}
else if (dst)
{
VectorSet4(dstBox, 0, dst->height, dst->width, 0);
} }
else else
{ {
VectorSet4(dstBox, 0, glConfig.vidHeight, glConfig.vidWidth, 0); VectorSet4(dstBox, 0, height, width, 0);
} }
if (inSrcTexScale) if (inSrcTexScale)
{ {
VectorCopy2(inSrcTexScale, srcTexScale); VectorCopy2(inSrcTexScale, invTexRes);
} }
else else
{ {
srcTexScale[0] = srcTexScale[1] = 1.0f; VectorSet2(invTexRes, 1.0f, 1.0f);
} }
if (inColor) if (inColor)
@ -726,17 +558,6 @@ void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexS
FBO_Bind(dst); FBO_Bind(dst);
if (glState.currentFBO)
{
width = glState.currentFBO->width;
height = glState.currentFBO->height;
}
else
{
width = glConfig.vidWidth;
height = glConfig.vidHeight;
}
qglViewport( 0, 0, width, height ); qglViewport( 0, 0, width, height );
qglScissor( 0, 0, width, height ); qglScissor( 0, 0, width, height );
@ -746,18 +567,13 @@ void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexS
GL_BindToTMU(src, TB_COLORMAP); GL_BindToTMU(src, TB_COLORMAP);
VectorSet4(quadVerts[0], dstBox[0], dstBox[1], 0, 1); VectorSet4(quadVerts[0], dstBox[0], dstBox[1], 0.0f, 1.0f);
VectorSet4(quadVerts[1], dstBox[2], dstBox[1], 0, 1); VectorSet4(quadVerts[1], dstBox[2], dstBox[1], 0.0f, 1.0f);
VectorSet4(quadVerts[2], dstBox[2], dstBox[3], 0, 1); VectorSet4(quadVerts[2], dstBox[2], dstBox[3], 0.0f, 1.0f);
VectorSet4(quadVerts[3], dstBox[0], dstBox[3], 0, 1); VectorSet4(quadVerts[3], dstBox[0], dstBox[3], 0.0f, 1.0f);
texCoords[0][0] = srcBox[0] / (float)src->width; texCoords[0][1] = 1.0f - srcBox[1] / (float)src->height; invTexRes[0] /= src->width;
texCoords[1][0] = srcBox[2] / (float)src->width; texCoords[1][1] = 1.0f - srcBox[1] / (float)src->height; invTexRes[1] /= src->height;
texCoords[2][0] = srcBox[2] / (float)src->width; texCoords[2][1] = 1.0f - srcBox[3] / (float)src->height;
texCoords[3][0] = srcBox[0] / (float)src->width; texCoords[3][1] = 1.0f - srcBox[3] / (float)src->height;
invTexRes[0] = 1.0f / src->width * srcTexScale[0];
invTexRes[1] = 1.0f / src->height * srcTexScale[1];
GL_State( blend ); GL_State( blend );
@ -769,14 +585,14 @@ void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexS
GLSL_SetUniformVec2(shaderProgram, UNIFORM_AUTOEXPOSUREMINMAX, tr.refdef.autoExposureMinMax); GLSL_SetUniformVec2(shaderProgram, UNIFORM_AUTOEXPOSUREMINMAX, tr.refdef.autoExposureMinMax);
GLSL_SetUniformVec3(shaderProgram, UNIFORM_TONEMINAVGMAXLINEAR, tr.refdef.toneMinAvgMaxLinear); GLSL_SetUniformVec3(shaderProgram, UNIFORM_TONEMINAVGMAXLINEAR, tr.refdef.toneMinAvgMaxLinear);
RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); RB_InstantQuad2(quadVerts, texCoords);
FBO_Bind(oldFbo); FBO_Bind(oldFbo);
} }
void FBO_Blit(FBO_t *src, ivec4_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend) void FBO_Blit(FBO_t *src, ivec4_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend)
{ {
ivec4_t srcBox; vec4_t srcTexCorners;
if (!src) if (!src)
{ {
@ -784,20 +600,19 @@ void FBO_Blit(FBO_t *src, ivec4_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, ivec
return; return;
} }
// framebuffers are 0 bottom, Y up.
if (inSrcBox) if (inSrcBox)
{ {
srcBox[0] = inSrcBox[0]; srcTexCorners[0] = inSrcBox[0] / (float)src->width;
srcBox[1] = src->height - inSrcBox[1] - inSrcBox[3]; srcTexCorners[1] = (inSrcBox[1] + inSrcBox[3]) / (float)src->height;
srcBox[2] = inSrcBox[2]; srcTexCorners[2] = (inSrcBox[0] + inSrcBox[2]) / (float)src->width;
srcBox[3] = inSrcBox[3]; srcTexCorners[3] = inSrcBox[1] / (float)src->height;
} }
else else
{ {
VectorSet4(srcBox, 0, src->height, src->width, -src->height); VectorSet4(srcTexCorners, 0.0f, 0.0f, 1.0f, 1.0f);
} }
FBO_BlitFromTexture(src->colorImage[0], srcBox, srcTexScale, dst, dstBox, shaderProgram, color, blend | GLS_DEPTHTEST_DISABLE); FBO_BlitFromTexture(src->colorImage[0], srcTexCorners, srcTexScale, dst, dstBox, shaderProgram, color, blend | GLS_DEPTHTEST_DISABLE);
} }
void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter) void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter)
@ -811,22 +626,15 @@ void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int bu
return; return;
} }
// get to a neutral state first
//FBO_Bind(NULL);
srcFb = src ? src->frameBuffer : 0; srcFb = src ? src->frameBuffer : 0;
dstFb = dst ? dst->frameBuffer : 0; dstFb = dst ? dst->frameBuffer : 0;
if (!srcBox) if (!srcBox)
{ {
if (src) int width = src ? src->width : glConfig.vidWidth;
{ int height = src ? src->height : glConfig.vidHeight;
VectorSet4(srcBoxFinal, 0, 0, src->width, src->height);
} VectorSet4(srcBoxFinal, 0, 0, width, height);
else
{
VectorSet4(srcBoxFinal, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
}
} }
else else
{ {
@ -835,26 +643,22 @@ void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int bu
if (!dstBox) if (!dstBox)
{ {
if (dst) int width = dst ? dst->width : glConfig.vidWidth;
{ int height = dst ? dst->height : glConfig.vidHeight;
VectorSet4(dstBoxFinal, 0, 0, dst->width, dst->height);
} VectorSet4(dstBoxFinal, 0, 0, width, height);
else
{
VectorSet4(dstBoxFinal, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
}
} }
else else
{ {
VectorSet4(dstBoxFinal, dstBox[0], dstBox[1], dstBox[0] + dstBox[2], dstBox[1] + dstBox[3]); VectorSet4(dstBoxFinal, dstBox[0], dstBox[1], dstBox[0] + dstBox[2], dstBox[1] + dstBox[3]);
} }
qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, srcFb); GL_BindFramebuffer(GL_READ_FRAMEBUFFER, srcFb);
qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dstFb); GL_BindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFb);
qglBlitFramebufferEXT(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3], qglBlitFramebuffer(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3],
dstBoxFinal[0], dstBoxFinal[1], dstBoxFinal[2], dstBoxFinal[3], dstBoxFinal[0], dstBoxFinal[1], dstBoxFinal[2], dstBoxFinal[3],
buffers, filter); buffers, filter);
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); GL_BindFramebuffer(GL_FRAMEBUFFER, 0);
glState.currentFBO = NULL; glState.currentFBO = NULL;
} }

View file

@ -24,10 +24,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef __TR_FBO_H__ #ifndef __TR_FBO_H__
#define __TR_FBO_H__ #define __TR_FBO_H__
#ifdef __cplusplus
extern "C" {
#endif
struct image_s; struct image_s;
struct shaderProgram_s; struct shaderProgram_s;
@ -56,16 +52,14 @@ typedef struct FBO_s
int height; int height;
} FBO_t; } FBO_t;
void FBO_AttachImage(FBO_t *fbo, image_t *image, GLenum attachment, GLuint cubemapside);
void FBO_Bind(FBO_t *fbo); void FBO_Bind(FBO_t *fbo);
void FBO_Init(void); void FBO_Init(void);
void FBO_Shutdown(void); void FBO_Shutdown(void);
void FBO_BlitFromTexture(struct image_s *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); void FBO_BlitFromTexture(struct image_s *src, vec4_t inSrcTexCorners, vec2_t inSrcTexScale, FBO_t *dst, ivec4_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend);
void FBO_Blit(FBO_t *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); void FBO_Blit(FBO_t *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend);
void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter); void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter);
#ifdef __cplusplus
}
#endif
#endif #endif

View file

@ -395,51 +395,51 @@ void RB_RenderFlare( flare_t *f ) {
return; return;
} }
iColor[0] = color[0] * fogFactors[0]; iColor[0] = color[0] * fogFactors[0] * 257;
iColor[1] = color[1] * fogFactors[1]; iColor[1] = color[1] * fogFactors[1] * 257;
iColor[2] = color[2] * fogFactors[2]; iColor[2] = color[2] * fogFactors[2] * 257;
RB_BeginSurface( tr.flareShader, f->fogNum, 0 ); RB_BeginSurface( tr.flareShader, f->fogNum, 0 );
// FIXME: use quadstamp? // FIXME: use quadstamp?
tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][0] = f->windowX - size;
tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.xyz[tess.numVertexes][1] = f->windowY - size;
tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 0; tess.texCoords[tess.numVertexes][1] = 0;
tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; tess.color[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; tess.color[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; tess.color[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 1.0f; tess.color[tess.numVertexes][3] = 65535;
tess.numVertexes++; tess.numVertexes++;
tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][0] = f->windowX - size;
tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.xyz[tess.numVertexes][1] = f->windowY + size;
tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 1; tess.texCoords[tess.numVertexes][1] = 1;
tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; tess.color[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; tess.color[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; tess.color[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 1.0f; tess.color[tess.numVertexes][3] = 65535;
tess.numVertexes++; tess.numVertexes++;
tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][0] = f->windowX + size;
tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.xyz[tess.numVertexes][1] = f->windowY + size;
tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 1; tess.texCoords[tess.numVertexes][1] = 1;
tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; tess.color[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; tess.color[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; tess.color[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 1.0f; tess.color[tess.numVertexes][3] = 65535;
tess.numVertexes++; tess.numVertexes++;
tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][0] = f->windowX + size;
tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.xyz[tess.numVertexes][1] = f->windowY - size;
tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 0; tess.texCoords[tess.numVertexes][1] = 0;
tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; tess.color[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; tess.color[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; tess.color[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 1.0f; tess.color[tess.numVertexes][3] = 65535;
tess.numVertexes++; tess.numVertexes++;
tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 0;
@ -526,10 +526,6 @@ void RB_RenderFlares (void) {
return; // none visible return; // none visible
} }
if ( backEnd.viewParms.isPortal ) {
qglDisable (GL_CLIP_PLANE0);
}
Mat4Copy(glState.projection, oldprojection); Mat4Copy(glState.projection, oldprojection);
Mat4Copy(glState.modelview, oldmodelview); Mat4Copy(glState.modelview, oldmodelview);
Mat4Identity(matrix); Mat4Identity(matrix);

View file

@ -0,0 +1,66 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_font.c -- font rendering
#include "tr_local.h"
static int s_numLoadedFonts;
static float s_fontHeightScale;
static float s_fontGeneralScale;
static float s_fontZ;
void R_SetFontHeightScale(float scale)
{
// FIXME: unimplemented
}
void R_SetFontScale(float scale)
{
// FIXME: unimplemented
}
void R_SetFontZ(float zed)
{
// FIXME: unimplemented
}
fontheader_t* R_LoadFont(const char* name)
{
// FIXME: unimplemented
return NULL;
}
void R_DrawString(const fontheader_t* font, const char* text, float x, float y, int maxlen, qboolean bVirtualScreen) {
// FIXME: unimplemented
}
float R_GetFontHeight(const fontheader_t* font)
{
// FIXME: unimplemented
return 0;
}
float R_GetFontStringWidth(const fontheader_t* font, const char* s)
{
// FIXME: unimplemented
return 0;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,498 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
2015 James Canete
This file is part of Quake III Arena source code.
Quake III Arena 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 III Arena 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 III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "../renderercommon/tr_common.h"
typedef unsigned int ui32_t;
typedef struct ddsHeader_s
{
ui32_t headerSize;
ui32_t flags;
ui32_t height;
ui32_t width;
ui32_t pitchOrFirstMipSize;
ui32_t volumeDepth;
ui32_t numMips;
ui32_t reserved1[11];
ui32_t always_0x00000020;
ui32_t pixelFormatFlags;
ui32_t fourCC;
ui32_t rgbBitCount;
ui32_t rBitMask;
ui32_t gBitMask;
ui32_t bBitMask;
ui32_t aBitMask;
ui32_t caps;
ui32_t caps2;
ui32_t caps3;
ui32_t caps4;
ui32_t reserved2;
}
ddsHeader_t;
// flags:
#define _DDSFLAGS_REQUIRED 0x001007
#define _DDSFLAGS_PITCH 0x8
#define _DDSFLAGS_MIPMAPCOUNT 0x20000
#define _DDSFLAGS_FIRSTMIPSIZE 0x80000
#define _DDSFLAGS_VOLUMEDEPTH 0x800000
// pixelFormatFlags:
#define DDSPF_ALPHAPIXELS 0x1
#define DDSPF_ALPHA 0x2
#define DDSPF_FOURCC 0x4
#define DDSPF_RGB 0x40
#define DDSPF_YUV 0x200
#define DDSPF_LUMINANCE 0x20000
// caps:
#define DDSCAPS_COMPLEX 0x8
#define DDSCAPS_MIPMAP 0x400000
#define DDSCAPS_REQUIRED 0x1000
// caps2:
#define DDSCAPS2_CUBEMAP 0xFE00
#define DDSCAPS2_VOLUME 0x200000
typedef struct ddsHeaderDxt10_s
{
ui32_t dxgiFormat;
ui32_t dimensions;
ui32_t miscFlags;
ui32_t arraySize;
ui32_t miscFlags2;
}
ddsHeaderDxt10_t;
// dxgiFormat
// from http://msdn.microsoft.com/en-us/library/windows/desktop/bb173059%28v=vs.85%29.aspx
typedef enum DXGI_FORMAT {
DXGI_FORMAT_UNKNOWN = 0,
DXGI_FORMAT_R32G32B32A32_TYPELESS = 1,
DXGI_FORMAT_R32G32B32A32_FLOAT = 2,
DXGI_FORMAT_R32G32B32A32_UINT = 3,
DXGI_FORMAT_R32G32B32A32_SINT = 4,
DXGI_FORMAT_R32G32B32_TYPELESS = 5,
DXGI_FORMAT_R32G32B32_FLOAT = 6,
DXGI_FORMAT_R32G32B32_UINT = 7,
DXGI_FORMAT_R32G32B32_SINT = 8,
DXGI_FORMAT_R16G16B16A16_TYPELESS = 9,
DXGI_FORMAT_R16G16B16A16_FLOAT = 10,
DXGI_FORMAT_R16G16B16A16_UNORM = 11,
DXGI_FORMAT_R16G16B16A16_UINT = 12,
DXGI_FORMAT_R16G16B16A16_SNORM = 13,
DXGI_FORMAT_R16G16B16A16_SINT = 14,
DXGI_FORMAT_R32G32_TYPELESS = 15,
DXGI_FORMAT_R32G32_FLOAT = 16,
DXGI_FORMAT_R32G32_UINT = 17,
DXGI_FORMAT_R32G32_SINT = 18,
DXGI_FORMAT_R32G8X24_TYPELESS = 19,
DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20,
DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21,
DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22,
DXGI_FORMAT_R10G10B10A2_TYPELESS = 23,
DXGI_FORMAT_R10G10B10A2_UNORM = 24,
DXGI_FORMAT_R10G10B10A2_UINT = 25,
DXGI_FORMAT_R11G11B10_FLOAT = 26,
DXGI_FORMAT_R8G8B8A8_TYPELESS = 27,
DXGI_FORMAT_R8G8B8A8_UNORM = 28,
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29,
DXGI_FORMAT_R8G8B8A8_UINT = 30,
DXGI_FORMAT_R8G8B8A8_SNORM = 31,
DXGI_FORMAT_R8G8B8A8_SINT = 32,
DXGI_FORMAT_R16G16_TYPELESS = 33,
DXGI_FORMAT_R16G16_FLOAT = 34,
DXGI_FORMAT_R16G16_UNORM = 35,
DXGI_FORMAT_R16G16_UINT = 36,
DXGI_FORMAT_R16G16_SNORM = 37,
DXGI_FORMAT_R16G16_SINT = 38,
DXGI_FORMAT_R32_TYPELESS = 39,
DXGI_FORMAT_D32_FLOAT = 40,
DXGI_FORMAT_R32_FLOAT = 41,
DXGI_FORMAT_R32_UINT = 42,
DXGI_FORMAT_R32_SINT = 43,
DXGI_FORMAT_R24G8_TYPELESS = 44,
DXGI_FORMAT_D24_UNORM_S8_UINT = 45,
DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46,
DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47,
DXGI_FORMAT_R8G8_TYPELESS = 48,
DXGI_FORMAT_R8G8_UNORM = 49,
DXGI_FORMAT_R8G8_UINT = 50,
DXGI_FORMAT_R8G8_SNORM = 51,
DXGI_FORMAT_R8G8_SINT = 52,
DXGI_FORMAT_R16_TYPELESS = 53,
DXGI_FORMAT_R16_FLOAT = 54,
DXGI_FORMAT_D16_UNORM = 55,
DXGI_FORMAT_R16_UNORM = 56,
DXGI_FORMAT_R16_UINT = 57,
DXGI_FORMAT_R16_SNORM = 58,
DXGI_FORMAT_R16_SINT = 59,
DXGI_FORMAT_R8_TYPELESS = 60,
DXGI_FORMAT_R8_UNORM = 61,
DXGI_FORMAT_R8_UINT = 62,
DXGI_FORMAT_R8_SNORM = 63,
DXGI_FORMAT_R8_SINT = 64,
DXGI_FORMAT_A8_UNORM = 65,
DXGI_FORMAT_R1_UNORM = 66,
DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67,
DXGI_FORMAT_R8G8_B8G8_UNORM = 68,
DXGI_FORMAT_G8R8_G8B8_UNORM = 69,
DXGI_FORMAT_BC1_TYPELESS = 70,
DXGI_FORMAT_BC1_UNORM = 71,
DXGI_FORMAT_BC1_UNORM_SRGB = 72,
DXGI_FORMAT_BC2_TYPELESS = 73,
DXGI_FORMAT_BC2_UNORM = 74,
DXGI_FORMAT_BC2_UNORM_SRGB = 75,
DXGI_FORMAT_BC3_TYPELESS = 76,
DXGI_FORMAT_BC3_UNORM = 77,
DXGI_FORMAT_BC3_UNORM_SRGB = 78,
DXGI_FORMAT_BC4_TYPELESS = 79,
DXGI_FORMAT_BC4_UNORM = 80,
DXGI_FORMAT_BC4_SNORM = 81,
DXGI_FORMAT_BC5_TYPELESS = 82,
DXGI_FORMAT_BC5_UNORM = 83,
DXGI_FORMAT_BC5_SNORM = 84,
DXGI_FORMAT_B5G6R5_UNORM = 85,
DXGI_FORMAT_B5G5R5A1_UNORM = 86,
DXGI_FORMAT_B8G8R8A8_UNORM = 87,
DXGI_FORMAT_B8G8R8X8_UNORM = 88,
DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89,
DXGI_FORMAT_B8G8R8A8_TYPELESS = 90,
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91,
DXGI_FORMAT_B8G8R8X8_TYPELESS = 92,
DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93,
DXGI_FORMAT_BC6H_TYPELESS = 94,
DXGI_FORMAT_BC6H_UF16 = 95,
DXGI_FORMAT_BC6H_SF16 = 96,
DXGI_FORMAT_BC7_TYPELESS = 97,
DXGI_FORMAT_BC7_UNORM = 98,
DXGI_FORMAT_BC7_UNORM_SRGB = 99,
DXGI_FORMAT_AYUV = 100,
DXGI_FORMAT_Y410 = 101,
DXGI_FORMAT_Y416 = 102,
DXGI_FORMAT_NV12 = 103,
DXGI_FORMAT_P010 = 104,
DXGI_FORMAT_P016 = 105,
DXGI_FORMAT_420_OPAQUE = 106,
DXGI_FORMAT_YUY2 = 107,
DXGI_FORMAT_Y210 = 108,
DXGI_FORMAT_Y216 = 109,
DXGI_FORMAT_NV11 = 110,
DXGI_FORMAT_AI44 = 111,
DXGI_FORMAT_IA44 = 112,
DXGI_FORMAT_P8 = 113,
DXGI_FORMAT_A8P8 = 114,
DXGI_FORMAT_B4G4R4A4_UNORM = 115,
DXGI_FORMAT_FORCE_UINT = 0xffffffffUL
} DXGI_FORMAT;
#define EncodeFourCC(x) ((((ui32_t)((x)[0])) ) | \
(((ui32_t)((x)[1])) << 8 ) | \
(((ui32_t)((x)[2])) << 16) | \
(((ui32_t)((x)[3])) << 24) )
void R_LoadDDS ( const char *filename, byte **pic, int *width, int *height, GLenum *picFormat, int *numMips )
{
union {
byte *b;
void *v;
} buffer;
int len;
ddsHeader_t *ddsHeader = NULL;
ddsHeaderDxt10_t *ddsHeaderDxt10 = NULL;
byte *data;
if (!picFormat)
{
ri.Printf(PRINT_ERROR, "R_LoadDDS() called without picFormat parameter!");
return;
}
if (width)
*width = 0;
if (height)
*height = 0;
if (picFormat)
*picFormat = GL_RGBA8;
if (numMips)
*numMips = 1;
*pic = NULL;
//
// load the file
//
len = ri.FS_ReadFile( ( char * ) filename, &buffer.v);
if (!buffer.b || len < 0) {
return;
}
//
// reject files that are too small to hold even a header
//
if (len < 4 + sizeof(*ddsHeader))
{
ri.Printf(PRINT_ALL, "File %s is too small to be a DDS file.\n", filename);
ri.FS_FreeFile(buffer.v);
return;
}
//
// reject files that don't start with "DDS "
//
if (*((ui32_t *)(buffer.b)) != EncodeFourCC("DDS "))
{
ri.Printf(PRINT_ALL, "File %s is not a DDS file.\n", filename);
ri.FS_FreeFile(buffer.v);
return;
}
//
// parse header and dx10 header if available
//
ddsHeader = (ddsHeader_t *)(buffer.b + 4);
if ((ddsHeader->pixelFormatFlags & DDSPF_FOURCC) && ddsHeader->fourCC == EncodeFourCC("DX10"))
{
if (len < 4 + sizeof(*ddsHeader) + sizeof(*ddsHeaderDxt10))
{
ri.Printf(PRINT_ALL, "File %s indicates a DX10 header it is too small to contain.\n", filename);
ri.FS_FreeFile(buffer.v);
return;
}
ddsHeaderDxt10 = (ddsHeaderDxt10_t *)(buffer.b + 4 + sizeof(ddsHeader_t));
data = buffer.b + 4 + sizeof(*ddsHeader) + sizeof(*ddsHeaderDxt10);
len -= 4 + sizeof(*ddsHeader) + sizeof(*ddsHeaderDxt10);
}
else
{
data = buffer.b + 4 + sizeof(*ddsHeader);
len -= 4 + sizeof(*ddsHeader);
}
if (width)
*width = ddsHeader->width;
if (height)
*height = ddsHeader->height;
if (numMips)
{
if (ddsHeader->flags & _DDSFLAGS_MIPMAPCOUNT)
*numMips = ddsHeader->numMips;
else
*numMips = 1;
}
// FIXME: handle cube map
//if ((ddsHeader->caps2 & DDSCAPS2_CUBEMAP) == DDSCAPS2_CUBEMAP)
//
// Convert DXGI format/FourCC into OpenGL format
//
if (ddsHeaderDxt10)
{
switch (ddsHeaderDxt10->dxgiFormat)
{
case DXGI_FORMAT_BC1_TYPELESS:
case DXGI_FORMAT_BC1_UNORM:
// FIXME: check for GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
*picFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
break;
case DXGI_FORMAT_BC1_UNORM_SRGB:
// FIXME: check for GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
*picFormat = GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
break;
case DXGI_FORMAT_BC2_TYPELESS:
case DXGI_FORMAT_BC2_UNORM:
*picFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
break;
case DXGI_FORMAT_BC2_UNORM_SRGB:
*picFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
break;
case DXGI_FORMAT_BC3_TYPELESS:
case DXGI_FORMAT_BC3_UNORM:
*picFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
break;
case DXGI_FORMAT_BC3_UNORM_SRGB:
*picFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
break;
case DXGI_FORMAT_BC4_TYPELESS:
case DXGI_FORMAT_BC4_UNORM:
*picFormat = GL_COMPRESSED_RED_RGTC1;
break;
case DXGI_FORMAT_BC4_SNORM:
*picFormat = GL_COMPRESSED_SIGNED_RED_RGTC1;
break;
case DXGI_FORMAT_BC5_TYPELESS:
case DXGI_FORMAT_BC5_UNORM:
*picFormat = GL_COMPRESSED_RG_RGTC2;
break;
case DXGI_FORMAT_BC5_SNORM:
*picFormat = GL_COMPRESSED_SIGNED_RG_RGTC2;
break;
case DXGI_FORMAT_BC6H_TYPELESS:
case DXGI_FORMAT_BC6H_UF16:
*picFormat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB;
break;
case DXGI_FORMAT_BC6H_SF16:
*picFormat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB;
break;
case DXGI_FORMAT_BC7_TYPELESS:
case DXGI_FORMAT_BC7_UNORM:
*picFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
break;
case DXGI_FORMAT_BC7_UNORM_SRGB:
*picFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB;
break;
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
*picFormat = GL_SRGB8_ALPHA8_EXT;
break;
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_SNORM:
*picFormat = GL_RGBA8;
break;
default:
ri.Printf(PRINT_ALL, "DDS File %s has unsupported DXGI format %d.", filename, ddsHeaderDxt10->dxgiFormat);
ri.FS_FreeFile(buffer.v);
return;
break;
}
}
else
{
if (ddsHeader->pixelFormatFlags & DDSPF_FOURCC)
{
if (ddsHeader->fourCC == EncodeFourCC("DXT1"))
*picFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
else if (ddsHeader->fourCC == EncodeFourCC("DXT2"))
*picFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
else if (ddsHeader->fourCC == EncodeFourCC("DXT3"))
*picFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
else if (ddsHeader->fourCC == EncodeFourCC("DXT4"))
*picFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
else if (ddsHeader->fourCC == EncodeFourCC("DXT5"))
*picFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
else if (ddsHeader->fourCC == EncodeFourCC("ATI1"))
*picFormat = GL_COMPRESSED_RED_RGTC1;
else if (ddsHeader->fourCC == EncodeFourCC("BC4U"))
*picFormat = GL_COMPRESSED_RED_RGTC1;
else if (ddsHeader->fourCC == EncodeFourCC("BC4S"))
*picFormat = GL_COMPRESSED_SIGNED_RED_RGTC1;
else if (ddsHeader->fourCC == EncodeFourCC("ATI2"))
*picFormat = GL_COMPRESSED_RG_RGTC2;
else if (ddsHeader->fourCC == EncodeFourCC("BC5U"))
*picFormat = GL_COMPRESSED_RG_RGTC2;
else if (ddsHeader->fourCC == EncodeFourCC("BC5S"))
*picFormat = GL_COMPRESSED_SIGNED_RG_RGTC2;
else
{
ri.Printf(PRINT_ALL, "DDS File %s has unsupported FourCC.", filename);
ri.FS_FreeFile(buffer.v);
return;
}
}
else if (ddsHeader->pixelFormatFlags == (DDSPF_RGB | DDSPF_ALPHAPIXELS)
&& ddsHeader->rgbBitCount == 32
&& ddsHeader->rBitMask == 0x000000ff
&& ddsHeader->gBitMask == 0x0000ff00
&& ddsHeader->bBitMask == 0x00ff0000
&& ddsHeader->aBitMask == 0xff000000)
{
*picFormat = GL_RGBA8;
}
else
{
ri.Printf(PRINT_ALL, "DDS File %s has unsupported RGBA format.", filename);
ri.FS_FreeFile(buffer.v);
return;
}
}
*pic = ri.Malloc(len);
Com_Memcpy(*pic, data, len);
ri.FS_FreeFile(buffer.v);
}
void R_SaveDDS(const char *filename, byte *pic, int width, int height, int depth)
{
byte *data;
ddsHeader_t *ddsHeader;
int picSize, size;
if (!depth)
depth = 1;
picSize = width * height * depth * 4;
size = 4 + sizeof(*ddsHeader) + picSize;
data = ri.Malloc(size);
data[0] = 'D';
data[1] = 'D';
data[2] = 'S';
data[3] = ' ';
ddsHeader = (ddsHeader_t *)(data + 4);
memset(ddsHeader, 0, sizeof(ddsHeader_t));
ddsHeader->headerSize = 0x7c;
ddsHeader->flags = _DDSFLAGS_REQUIRED;
ddsHeader->height = height;
ddsHeader->width = width;
ddsHeader->always_0x00000020 = 0x00000020;
ddsHeader->caps = DDSCAPS_COMPLEX | DDSCAPS_REQUIRED;
if (depth == 6)
ddsHeader->caps2 = DDSCAPS2_CUBEMAP;
ddsHeader->pixelFormatFlags = DDSPF_RGB | DDSPF_ALPHAPIXELS;
ddsHeader->rgbBitCount = 32;
ddsHeader->rBitMask = 0x000000ff;
ddsHeader->gBitMask = 0x0000ff00;
ddsHeader->bBitMask = 0x00ff0000;
ddsHeader->aBitMask = 0xff000000;
Com_Memcpy(data + 4 + sizeof(*ddsHeader), pic, picSize);
ri.FS_WriteFile(filename, data, size);
ri.Free(data);
}

View file

@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_local.h" #include "tr_local.h"
#include "tr_dsa.h"
glconfig_t glConfig; glconfig_t glConfig;
glRefConfig_t glRefConfig; glRefConfig_t glRefConfig;
qboolean textureFilterAnisotropic = qfalse; qboolean textureFilterAnisotropic = qfalse;
@ -86,10 +88,6 @@ cvar_t *r_novis;
cvar_t *r_nocull; cvar_t *r_nocull;
cvar_t *r_facePlaneCull; cvar_t *r_facePlaneCull;
cvar_t *r_showcluster; cvar_t *r_showcluster;
cvar_t *r_staticlod;
cvar_t *r_lodscale;
cvar_t *r_lodcap;
cvar_t *r_lodviewmodelcap;
cvar_t *r_nocurves; cvar_t *r_nocurves;
cvar_t *r_allowExtensions; cvar_t *r_allowExtensions;
@ -101,19 +99,12 @@ cvar_t *r_ext_texture_env_add;
cvar_t *r_ext_texture_filter_anisotropic; cvar_t *r_ext_texture_filter_anisotropic;
cvar_t *r_ext_max_anisotropy; cvar_t *r_ext_max_anisotropy;
cvar_t *r_ext_draw_range_elements;
cvar_t *r_ext_multi_draw_arrays;
cvar_t *r_ext_framebuffer_object; cvar_t *r_ext_framebuffer_object;
cvar_t *r_ext_texture_float; cvar_t *r_ext_texture_float;
cvar_t *r_arb_half_float_pixel;
cvar_t *r_arb_half_float_vertex;
cvar_t *r_ext_framebuffer_multisample; cvar_t *r_ext_framebuffer_multisample;
cvar_t *r_arb_seamless_cube_map; cvar_t *r_arb_seamless_cube_map;
cvar_t *r_arb_vertex_type_2_10_10_10_rev;
cvar_t *r_arb_vertex_array_object; cvar_t *r_arb_vertex_array_object;
cvar_t *r_ext_direct_state_access;
cvar_t *r_mergeMultidraws;
cvar_t *r_mergeLeafSurfaces;
cvar_t *r_cameraExposure; cvar_t *r_cameraExposure;
@ -134,11 +125,6 @@ cvar_t *r_forceAutoExposure;
cvar_t *r_forceAutoExposureMin; cvar_t *r_forceAutoExposureMin;
cvar_t *r_forceAutoExposureMax; cvar_t *r_forceAutoExposureMax;
cvar_t *r_materialGamma;
cvar_t *r_lightGamma;
cvar_t *r_framebufferGamma;
cvar_t *r_tonemapGamma;
cvar_t *r_depthPrepass; cvar_t *r_depthPrepass;
cvar_t *r_ssao; cvar_t *r_ssao;
@ -146,14 +132,18 @@ cvar_t *r_normalMapping;
cvar_t *r_specularMapping; cvar_t *r_specularMapping;
cvar_t *r_deluxeMapping; cvar_t *r_deluxeMapping;
cvar_t *r_parallaxMapping; cvar_t *r_parallaxMapping;
cvar_t *r_parallaxMapOffset;
cvar_t *r_parallaxMapShadows;
cvar_t *r_cubeMapping; cvar_t *r_cubeMapping;
cvar_t *r_cubemapSize;
cvar_t *r_deluxeSpecular; cvar_t *r_deluxeSpecular;
cvar_t *r_specularIsMetallic; cvar_t *r_pbr;
cvar_t *r_baseNormalX; cvar_t *r_baseNormalX;
cvar_t *r_baseNormalY; cvar_t *r_baseNormalY;
cvar_t *r_baseParallax; cvar_t *r_baseParallax;
cvar_t *r_baseSpecular; cvar_t *r_baseSpecular;
cvar_t *r_baseGloss; cvar_t *r_baseGloss;
cvar_t *r_glossType;
cvar_t *r_mergeLightmaps; cvar_t *r_mergeLightmaps;
cvar_t *r_dlightMode; cvar_t *r_dlightMode;
cvar_t *r_pshadowDist; cvar_t *r_pshadowDist;
@ -162,13 +152,13 @@ cvar_t *r_imageUpsampleMaxSize;
cvar_t *r_imageUpsampleType; cvar_t *r_imageUpsampleType;
cvar_t *r_genNormalMaps; cvar_t *r_genNormalMaps;
cvar_t *r_forceSun; cvar_t *r_forceSun;
cvar_t *r_forceSunMapLightScale;
cvar_t *r_forceSunLightScale; cvar_t *r_forceSunLightScale;
cvar_t *r_forceSunAmbientScale; cvar_t *r_forceSunAmbientScale;
cvar_t *r_sunlightMode; cvar_t *r_sunlightMode;
cvar_t *r_drawSunRays; cvar_t *r_drawSunRays;
cvar_t *r_sunShadows; cvar_t *r_sunShadows;
cvar_t *r_shadowFilter; cvar_t *r_shadowFilter;
cvar_t *r_shadowBlur;
cvar_t *r_shadowMapSize; cvar_t *r_shadowMapSize;
cvar_t *r_shadowCascadeZNear; cvar_t *r_shadowCascadeZNear;
cvar_t *r_shadowCascadeZFar; cvar_t *r_shadowCascadeZFar;
@ -246,43 +236,6 @@ int max_polys;
cvar_t *r_maxpolyverts; cvar_t *r_maxpolyverts;
int max_polyverts; int max_polyverts;
cvar_t *r_uselod;
cvar_t *lod_LOD;
cvar_t *lod_minLOD;
cvar_t *lod_maxLOD;
cvar_t *lod_LOD_slider;
cvar_t *lod_curve_0_val;
cvar_t *lod_curve_1_val;
cvar_t *lod_curve_2_val;
cvar_t *lod_curve_3_val;
cvar_t *lod_curve_4_val;
cvar_t *lod_edit_0;
cvar_t *lod_edit_1;
cvar_t *lod_edit_2;
cvar_t *lod_edit_3;
cvar_t *lod_edit_4;
cvar_t *lod_curve_0_slider;
cvar_t *lod_curve_1_slider;
cvar_t *lod_curve_2_slider;
cvar_t *lod_curve_3_slider;
cvar_t *lod_curve_4_slider;
cvar_t *lod_pitch_val;
cvar_t *lod_zee_val;
cvar_t *lod_mesh;
cvar_t *lod_meshname;
cvar_t *lod_tikiname;
cvar_t *lod_metric;
cvar_t *lod_tris;
cvar_t *lod_position;
cvar_t *lod_save;
cvar_t *lod_tool;
cvar_t *r_showSkeleton;
cvar_t *r_numdebuglines;
int r_sequencenumber = 0;
/* /*
** InitOpenGL ** InitOpenGL
** **
@ -293,8 +246,6 @@ int r_sequencenumber = 0;
*/ */
static void InitOpenGL( void ) static void InitOpenGL( void )
{ {
char renderer_buffer[1024];
// //
// initialize OS specific portions of the renderer // initialize OS specific portions of the renderer
// //
@ -310,11 +261,10 @@ static void InitOpenGL( void )
{ {
GLint temp; GLint temp;
GLimp_Init(); GLimp_Init( qfalse );
GLimp_InitExtraExtensions(); GLimp_InitExtraExtensions();
strcpy( renderer_buffer, glConfig.renderer_string ); glConfig.textureEnvAddAvailable = qtrue;
Q_strlwr( renderer_buffer );
// OpenGL driver constants // OpenGL driver constants
qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp ); qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp );
@ -325,6 +275,22 @@ static void InitOpenGL( void )
{ {
glConfig.maxTextureSize = 0; glConfig.maxTextureSize = 0;
} }
qglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS, &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;
}
}
// check for GLSL function textureCubeLod()
if ( r_cubeMapping->integer && !QGL_VERSION_ATLEAST( 3, 0 ) ) {
ri.Printf( PRINT_WARNING, "WARNING: Disabled r_cubeMapping because it requires OpenGL 3.0\n" );
ri.Cvar_Set( "r_cubeMapping", "0" );
} }
// set default state // set default state
@ -497,6 +463,7 @@ byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *pa
buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1); buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1);
bufstart = PADP((intptr_t) buffer + *offset, packAlign); bufstart = PADP((intptr_t) buffer + *offset, packAlign);
qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart); qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart);
*offset = bufstart - buffer; *offset = bufstart - buffer;
@ -874,85 +841,33 @@ void R_ScreenShotJPEG_f (void) {
/* /*
================== ==================
RB_TakeVideoFrameCmd R_ExportCubemaps
================== ==================
*/ */
const void *RB_TakeVideoFrameCmd( const void *data ) void R_ExportCubemaps(void)
{ {
const videoFrameCommand_t *cmd; exportCubemapsCommand_t *cmd;
byte *cBuf;
size_t memcount, linelen;
int padwidth, avipadwidth, padlen, avipadlen;
GLint packAlign;
// finish any 2D drawing if needed cmd = R_GetCommandBuffer(sizeof(*cmd));
if(tess.numIndexes) if (!cmd) {
RB_EndSurface(); return;
cmd = (const videoFrameCommand_t *)data;
qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);
linelen = cmd->width * 3;
// Alignment stuff for glReadPixels
padwidth = PAD(linelen, packAlign);
padlen = padwidth - linelen;
// AVI line padding
avipadwidth = PAD(linelen, AVI_LINE_PADDING);
avipadlen = avipadwidth - linelen;
cBuf = PADP(cmd->captureBuffer, packAlign);
qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB,
GL_UNSIGNED_BYTE, cBuf);
memcount = padwidth * cmd->height;
// gamma correct
if(glConfig.deviceSupportsGamma)
R_GammaCorrect(cBuf, memcount);
if(cmd->motionJpeg)
{
memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, linelen * cmd->height,
r_aviMotionJpegQuality->integer,
cmd->width, cmd->height, cBuf, padlen);
ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount);
} }
else cmd->commandId = RC_EXPORT_CUBEMAPS;
{
byte *lineend, *memend;
byte *srcptr, *destptr;
srcptr = cBuf;
destptr = cmd->encodeBuffer;
memend = srcptr + memcount;
// swap R and B and remove line paddings
while(srcptr < memend)
{
lineend = srcptr + linelen;
while(srcptr < lineend)
{
*destptr++ = srcptr[2];
*destptr++ = srcptr[1];
*destptr++ = srcptr[0];
srcptr += 3;
}
Com_Memset(destptr, '\0', avipadlen);
destptr += avipadlen;
srcptr += padlen;
}
ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, avipadwidth * cmd->height);
}
return (const void *)(cmd + 1);
} }
/*
==================
R_ExportCubemaps_f
==================
*/
void R_ExportCubemaps_f(void)
{
R_ExportCubemaps();
}
//============================================================================
//============================================================================ //============================================================================
/* /*
@ -964,21 +879,12 @@ void GL_SetDefaultState( void )
qglCullFace(GL_FRONT); qglCullFace(GL_FRONT);
qglColor4f (1,1,1,1); GL_BindNullTextures();
// initialize downstream texture unit if we're running if (glRefConfig.framebufferObject)
// in a multitexture environment GL_BindNullFramebuffers();
if ( qglActiveTextureARB ) {
GL_SelectTexture( 1 );
GL_TextureMode( r_textureMode->string );
GL_TexEnv( GL_MODULATE );
qglDisable( GL_TEXTURE_2D );
GL_SelectTexture( 0 );
}
qglEnable(GL_TEXTURE_2D);
GL_TextureMode( r_textureMode->string ); GL_TextureMode( r_textureMode->string );
GL_TexEnv( GL_MODULATE );
//qglShadeModel( GL_SMOOTH ); //qglShadeModel( GL_SMOOTH );
qglDepthFunc( GL_LEQUAL ); qglDepthFunc( GL_LEQUAL );
@ -991,14 +897,13 @@ void GL_SetDefaultState( void )
glState.faceCulling = CT_TWO_SIDED; glState.faceCulling = CT_TWO_SIDED;
glState.faceCullFront = qtrue; glState.faceCullFront = qtrue;
glState.currentProgram = 0; GL_BindNullProgram();
qglUseProgramObjectARB(0);
if (glRefConfig.vertexArrayObject) if (glRefConfig.vertexArrayObject)
qglBindVertexArrayARB(0); qglBindVertexArray(0);
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); qglBindBuffer(GL_ARRAY_BUFFER, 0);
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glState.currentVao = NULL; glState.currentVao = NULL;
glState.vertexAttribsEnabled = 0; glState.vertexAttribsEnabled = 0;
@ -1018,12 +923,6 @@ void GL_SetDefaultState( void )
qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky
} }
const char *RE_GetGraphicsInfo() {
// FIXME: stub
// this is soooo annoying that ioquake3 represents 0,5% of mohaa and 1% of ubertools
return "";
}
/* /*
================ ================
R_PrintLongString R_PrintLongString
@ -1046,6 +945,11 @@ void R_PrintLongString(const char *string) {
} }
} }
const char* RE_GetGraphicsInfo() {
// FIXME: unimplemented
return NULL;
}
/* /*
================ ================
GfxInfo_f GfxInfo_f
@ -1068,10 +972,25 @@ void GfxInfo_f( void )
ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string ); ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string );
ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string ); ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string );
ri.Printf( PRINT_ALL, "GL_EXTENSIONS: " ); ri.Printf( PRINT_ALL, "GL_EXTENSIONS: " );
R_PrintLongString( glConfig.extensions_string ); // glConfig.extensions_string is a limited length so get the full list directly
if ( qglGetStringi )
{
GLint numExtensions;
int i;
qglGetIntegerv( GL_NUM_EXTENSIONS, &numExtensions );
for ( i = 0; i < numExtensions; i++ )
{
ri.Printf( PRINT_ALL, "%s ", qglGetStringi( GL_EXTENSIONS, i ) );
}
}
else
{
R_PrintLongString( (char *) qglGetString( GL_EXTENSIONS ) );
}
ri.Printf( PRINT_ALL, "\n" ); ri.Printf( PRINT_ALL, "\n" );
ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize ); ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize );
ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_UNITS_ARB: %d\n", glConfig.numTextureUnits ); ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_IMAGE_UNITS: %d\n", glConfig.numTextureUnits );
ri.Printf( PRINT_ALL, "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits ); ri.Printf( PRINT_ALL, "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits );
ri.Printf( PRINT_ALL, "MODE: %d, %d x %d %s hz:", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] ); ri.Printf( PRINT_ALL, "MODE: %d, %d x %d %s hz:", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] );
if ( glConfig.displayFrequency ) if ( glConfig.displayFrequency )
@ -1094,7 +1013,6 @@ void GfxInfo_f( void )
ri.Printf( PRINT_ALL, "texturemode: %s\n", r_textureMode->string ); ri.Printf( PRINT_ALL, "texturemode: %s\n", r_textureMode->string );
ri.Printf( PRINT_ALL, "picmip: %d\n", r_picmip->integer ); ri.Printf( PRINT_ALL, "picmip: %d\n", r_picmip->integer );
ri.Printf( PRINT_ALL, "texture bits: %d\n", r_texturebits->integer ); ri.Printf( PRINT_ALL, "texture bits: %d\n", r_texturebits->integer );
ri.Printf( PRINT_ALL, "multitexture: %s\n", enablestrings[qglActiveTextureARB != 0] );
ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] ); ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] );
ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] ); ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] );
ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression!=TC_NONE] ); ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression!=TC_NONE] );
@ -1115,6 +1033,16 @@ void GfxInfo_f( void )
} }
} }
qboolean R_SetMode(int mode) {
// FIXME: unimplemented
return qfalse;
}
void R_SetFullscreen(qboolean fullscreen, glconfig_t* config) {
// FIXME: unimplemented
return qfalse;
}
/* /*
================ ================
GfxMemInfo_f GfxMemInfo_f
@ -1167,46 +1095,6 @@ void GfxMemInfo_f( void )
} }
} }
/*
===============
FarPlaneInfo_f
===============
*/
void FarPlaneInfo_f( void ) {
Com_Printf( "Current fog settings:\n" );
Com_Printf( "Distance: %i\n", ( signed int )tr.viewParms.farplane_distance );
Com_Printf(
"Color: %f %f %f\n",
tr.viewParms.farplane_color[ 0 ],
tr.viewParms.farplane_color[ 1 ],
tr.viewParms.farplane_color[ 2 ] );
if( tr.viewParms.farplane_cull ) {
Com_Printf( "Cull: on\n" );
} else {
Com_Printf( "Cull: off\n" );
}
}
/*
===============
R_SetMode
===============
*/
qboolean R_SetMode( int mode, glconfig_t *config ) {
// FIXME: stub..
return qfalse;
}
/*
===============
R_SetFullscreen
===============
*/
void R_SetFullscreen( qboolean fullscreen, glconfig_t *config ) {
// FIXME: stub...
}
/* /*
=============== ===============
R_Register R_Register
@ -1227,16 +1115,12 @@ void R_Register( void )
r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_ext_draw_range_elements = ri.Cvar_Get( "r_ext_draw_range_elements", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_ext_multi_draw_arrays = ri.Cvar_Get( "r_ext_multi_draw_arrays", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_ext_framebuffer_object = ri.Cvar_Get( "r_ext_framebuffer_object", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_framebuffer_object = ri.Cvar_Get( "r_ext_framebuffer_object", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_ext_texture_float = ri.Cvar_Get( "r_ext_texture_float", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_texture_float = ri.Cvar_Get( "r_ext_texture_float", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_arb_half_float_pixel = ri.Cvar_Get( "r_arb_half_float_pixel", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_arb_half_float_vertex = ri.Cvar_Get( "r_arb_half_float_vertex", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_ext_framebuffer_multisample = ri.Cvar_Get( "r_ext_framebuffer_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH); r_ext_framebuffer_multisample = ri.Cvar_Get( "r_ext_framebuffer_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH);
r_arb_seamless_cube_map = ri.Cvar_Get( "r_arb_seamless_cube_map", "0", CVAR_ARCHIVE | CVAR_LATCH); r_arb_seamless_cube_map = ri.Cvar_Get( "r_arb_seamless_cube_map", "0", CVAR_ARCHIVE | CVAR_LATCH);
r_arb_vertex_type_2_10_10_10_rev = ri.Cvar_Get( "r_arb_vertex_type_2_10_10_10_rev", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_arb_vertex_array_object = ri.Cvar_Get( "r_arb_vertex_array_object", "1", CVAR_ARCHIVE | CVAR_LATCH); r_arb_vertex_array_object = ri.Cvar_Get( "r_arb_vertex_array_object", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_ext_direct_state_access = ri.Cvar_Get("r_ext_direct_state_access", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic",
"0", CVAR_ARCHIVE | CVAR_LATCH ); "0", CVAR_ARCHIVE | CVAR_LATCH );
@ -1245,18 +1129,16 @@ void R_Register( void )
r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH ); r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH );
r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_texturebits = ri.Cvar_Get( "r_texturebits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_texturebits = ri.Cvar_Get( "r_texturebits", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH ); r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH );
r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_ext_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_ext_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH);
r_mode = ri.Cvar_Get( "r_mode", "5", CVAR_ARCHIVE | CVAR_LATCH ); r_mode = ri.Cvar_Get( "r_mode", "-2", CVAR_ARCHIVE | CVAR_LATCH );
r_fullscreen = ri.Cvar_Get( "r_fullscreen", "0", CVAR_ARCHIVE ); r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE );
r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE | CVAR_LATCH); r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE | CVAR_LATCH);
r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH ); r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH );
r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_ARCHIVE | CVAR_LATCH ); r_customheight = ri.Cvar_Get( "r_customheight", "1024", CVAR_ARCHIVE | CVAR_LATCH );
@ -1268,14 +1150,13 @@ void R_Register( void )
r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH); r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH);
r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH); r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH);
r_externalGLSL = ri.Cvar_Get( "r_externalGLSL", "0", CVAR_LATCH ); r_externalGLSL = ri.Cvar_Get( "r_externalGLSL", "0", CVAR_LATCH );
r_hdr = ri.Cvar_Get( "r_hdr", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_hdr = ri.Cvar_Get( "r_hdr", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_floatLightmap = ri.Cvar_Get( "r_floatLightmap", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_floatLightmap = ri.Cvar_Get( "r_floatLightmap", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_postProcess = ri.Cvar_Get( "r_postProcess", "1", CVAR_ARCHIVE ); r_postProcess = ri.Cvar_Get( "r_postProcess", "1", CVAR_ARCHIVE );
r_toneMap = ri.Cvar_Get( "r_toneMap", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_toneMap = ri.Cvar_Get( "r_toneMap", "1", CVAR_ARCHIVE );
r_forceToneMap = ri.Cvar_Get( "r_forceToneMap", "0", CVAR_CHEAT ); r_forceToneMap = ri.Cvar_Get( "r_forceToneMap", "0", CVAR_CHEAT );
r_forceToneMapMin = ri.Cvar_Get( "r_forceToneMapMin", "-8.0", CVAR_CHEAT ); r_forceToneMapMin = ri.Cvar_Get( "r_forceToneMapMin", "-8.0", CVAR_CHEAT );
r_forceToneMapAvg = ri.Cvar_Get( "r_forceToneMapAvg", "-2.0", CVAR_CHEAT ); r_forceToneMapAvg = ri.Cvar_Get( "r_forceToneMapAvg", "-2.0", CVAR_CHEAT );
@ -1286,12 +1167,7 @@ void R_Register( void )
r_forceAutoExposureMin = ri.Cvar_Get( "r_forceAutoExposureMin", "-2.0", CVAR_CHEAT ); r_forceAutoExposureMin = ri.Cvar_Get( "r_forceAutoExposureMin", "-2.0", CVAR_CHEAT );
r_forceAutoExposureMax = ri.Cvar_Get( "r_forceAutoExposureMax", "2.0", CVAR_CHEAT ); r_forceAutoExposureMax = ri.Cvar_Get( "r_forceAutoExposureMax", "2.0", CVAR_CHEAT );
r_cameraExposure = ri.Cvar_Get( "r_cameraExposure", "0", CVAR_CHEAT ); r_cameraExposure = ri.Cvar_Get( "r_cameraExposure", "1", CVAR_CHEAT );
r_materialGamma = ri.Cvar_Get( "r_materialGamma", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
r_lightGamma = ri.Cvar_Get( "r_lightGamma", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
r_framebufferGamma = ri.Cvar_Get( "r_framebufferGamma", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
r_tonemapGamma = ri.Cvar_Get( "r_tonemapGamma", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
r_depthPrepass = ri.Cvar_Get( "r_depthPrepass", "1", CVAR_ARCHIVE ); r_depthPrepass = ri.Cvar_Get( "r_depthPrepass", "1", CVAR_ARCHIVE );
r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE ); r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE );
@ -1300,14 +1176,18 @@ void R_Register( void )
r_specularMapping = ri.Cvar_Get( "r_specularMapping", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_specularMapping = ri.Cvar_Get( "r_specularMapping", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_deluxeMapping = ri.Cvar_Get( "r_deluxeMapping", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_deluxeMapping = ri.Cvar_Get( "r_deluxeMapping", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_parallaxMapping = ri.Cvar_Get( "r_parallaxMapping", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_parallaxMapping = ri.Cvar_Get( "r_parallaxMapping", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_parallaxMapOffset = ri.Cvar_Get( "r_parallaxMapOffset", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_parallaxMapShadows = ri.Cvar_Get( "r_parallaxMapShadows", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_cubeMapping = ri.Cvar_Get( "r_cubeMapping", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_cubeMapping = ri.Cvar_Get( "r_cubeMapping", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_deluxeSpecular = ri.Cvar_Get( "r_deluxeSpecular", "0.3", CVAR_ARCHIVE | CVAR_LATCH ); r_cubemapSize = ri.Cvar_Get( "r_cubemapSize", "128", CVAR_ARCHIVE | CVAR_LATCH );
r_specularIsMetallic = ri.Cvar_Get( "r_specularIsMetallic", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_deluxeSpecular = ri.Cvar_Get("r_deluxeSpecular", "0.3", CVAR_ARCHIVE | CVAR_LATCH);
r_pbr = ri.Cvar_Get("r_pbr", "0", CVAR_ARCHIVE | CVAR_LATCH);
r_baseNormalX = ri.Cvar_Get( "r_baseNormalX", "1.0", CVAR_ARCHIVE | CVAR_LATCH ); r_baseNormalX = ri.Cvar_Get( "r_baseNormalX", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
r_baseNormalY = ri.Cvar_Get( "r_baseNormalY", "1.0", CVAR_ARCHIVE | CVAR_LATCH ); r_baseNormalY = ri.Cvar_Get( "r_baseNormalY", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
r_baseParallax = ri.Cvar_Get( "r_baseParallax", "0.05", CVAR_ARCHIVE | CVAR_LATCH ); r_baseParallax = ri.Cvar_Get( "r_baseParallax", "0.05", CVAR_ARCHIVE | CVAR_LATCH );
r_baseSpecular = ri.Cvar_Get( "r_baseSpecular", "0.04", CVAR_ARCHIVE | CVAR_LATCH ); r_baseSpecular = ri.Cvar_Get( "r_baseSpecular", "0.04", CVAR_ARCHIVE | CVAR_LATCH );
r_baseGloss = ri.Cvar_Get( "r_baseGloss", "0.3", CVAR_ARCHIVE | CVAR_LATCH ); r_baseGloss = ri.Cvar_Get( "r_baseGloss", "0.3", CVAR_ARCHIVE | CVAR_LATCH );
r_glossType = ri.Cvar_Get("r_glossType", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_dlightMode = ri.Cvar_Get( "r_dlightMode", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_dlightMode = ri.Cvar_Get( "r_dlightMode", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_pshadowDist = ri.Cvar_Get( "r_pshadowDist", "128", CVAR_ARCHIVE ); r_pshadowDist = ri.Cvar_Get( "r_pshadowDist", "128", CVAR_ARCHIVE );
r_mergeLightmaps = ri.Cvar_Get( "r_mergeLightmaps", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_mergeLightmaps = ri.Cvar_Get( "r_mergeLightmaps", "1", CVAR_ARCHIVE | CVAR_LATCH );
@ -1317,7 +1197,6 @@ void R_Register( void )
r_genNormalMaps = ri.Cvar_Get( "r_genNormalMaps", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_genNormalMaps = ri.Cvar_Get( "r_genNormalMaps", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_forceSun = ri.Cvar_Get( "r_forceSun", "0", CVAR_CHEAT ); r_forceSun = ri.Cvar_Get( "r_forceSun", "0", CVAR_CHEAT );
r_forceSunMapLightScale = ri.Cvar_Get( "r_forceSunMapLightScale", "1.0", CVAR_CHEAT );
r_forceSunLightScale = ri.Cvar_Get( "r_forceSunLightScale", "1.0", CVAR_CHEAT ); r_forceSunLightScale = ri.Cvar_Get( "r_forceSunLightScale", "1.0", CVAR_CHEAT );
r_forceSunAmbientScale = ri.Cvar_Get( "r_forceSunAmbientScale", "0.5", CVAR_CHEAT ); r_forceSunAmbientScale = ri.Cvar_Get( "r_forceSunAmbientScale", "0.5", CVAR_CHEAT );
r_drawSunRays = ri.Cvar_Get( "r_drawSunRays", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_drawSunRays = ri.Cvar_Get( "r_drawSunRays", "0", CVAR_ARCHIVE | CVAR_LATCH );
@ -1325,7 +1204,8 @@ void R_Register( void )
r_sunShadows = ri.Cvar_Get( "r_sunShadows", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_sunShadows = ri.Cvar_Get( "r_sunShadows", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_shadowFilter = ri.Cvar_Get( "r_shadowFilter", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_shadowFilter = ri.Cvar_Get( "r_shadowFilter", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_shadowMapSize = ri.Cvar_Get( "r_shadowMapSize", "1024", CVAR_ARCHIVE | CVAR_LATCH ); r_shadowBlur = ri.Cvar_Get("r_shadowBlur", "0", CVAR_ARCHIVE | CVAR_LATCH);
r_shadowMapSize = ri.Cvar_Get("r_shadowMapSize", "1024", CVAR_ARCHIVE | CVAR_LATCH);
r_shadowCascadeZNear = ri.Cvar_Get( "r_shadowCascadeZNear", "8", CVAR_ARCHIVE | CVAR_LATCH ); r_shadowCascadeZNear = ri.Cvar_Get( "r_shadowCascadeZNear", "8", CVAR_ARCHIVE | CVAR_LATCH );
r_shadowCascadeZFar = ri.Cvar_Get( "r_shadowCascadeZFar", "1024", CVAR_ARCHIVE | CVAR_LATCH ); r_shadowCascadeZFar = ri.Cvar_Get( "r_shadowCascadeZFar", "1024", CVAR_ARCHIVE | CVAR_LATCH );
r_shadowCascadeZBias = ri.Cvar_Get( "r_shadowCascadeZBias", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_shadowCascadeZBias = ri.Cvar_Get( "r_shadowCascadeZBias", "0", CVAR_ARCHIVE | CVAR_LATCH );
@ -1335,7 +1215,6 @@ void R_Register( void )
// temporary latched variables that can only change over a restart // temporary latched variables that can only change over a restart
// //
r_displayRefresh = ri.Cvar_Get( "r_displayRefresh", "0", CVAR_LATCH ); r_displayRefresh = ri.Cvar_Get( "r_displayRefresh", "0", CVAR_LATCH );
r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT ); r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT );
r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH ); r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH );
r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH ); r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH );
@ -1348,7 +1227,6 @@ void R_Register( void )
r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE ); r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE );
r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE ); r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE );
r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT ); r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT );
r_zproj = ri.Cvar_Get( "r_zproj", "64", CVAR_ARCHIVE ); r_zproj = ri.Cvar_Get( "r_zproj", "64", CVAR_ARCHIVE );
r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "64", CVAR_ARCHIVE ); r_stereoSeparation = ri.Cvar_Get( "r_stereoSeparation", "64", CVAR_ARCHIVE );
r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE ); r_ignoreGLErrors = ri.Cvar_Get( "r_ignoreGLErrors", "1", CVAR_ARCHIVE );
@ -1358,7 +1236,7 @@ void R_Register( void )
r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE ); r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE );
r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE ); r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE );
r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE); r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE);
r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE ); r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE );
r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0", r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0",
CVAR_ARCHIVE | CVAR_LATCH ); CVAR_ARCHIVE | CVAR_LATCH );
r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE ); r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE );
@ -1372,8 +1250,6 @@ void R_Register( void )
r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT ); r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT );
r_anaglyphMode = ri.Cvar_Get("r_anaglyphMode", "0", CVAR_ARCHIVE); r_anaglyphMode = ri.Cvar_Get("r_anaglyphMode", "0", CVAR_ARCHIVE);
r_mergeMultidraws = ri.Cvar_Get("r_mergeMultidraws", "1", CVAR_ARCHIVE);
r_mergeLeafSurfaces = ri.Cvar_Get("r_mergeLeafSurfaces", "1", CVAR_ARCHIVE);
// //
// temporary variables that can change at any time // temporary variables that can change at any time
@ -1428,41 +1304,6 @@ void R_Register( void )
r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", MAX_POLYS), 0); r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", MAX_POLYS), 0);
r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", MAX_POLYVERTS), 0); r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", MAX_POLYVERTS), 0);
r_numdebuglines = ri.Cvar_Get( "r_numdebuglines", "0", 0 );
r_showSkeleton = ri.Cvar_Get( "r_showSkeleton", "0", 0 );
// lod
r_uselod = ri.Cvar_Get( "r_uselod", "1", CVAR_TEMP );
lod_LOD = ri.Cvar_Get( "lod_LOD", "0", CVAR_TEMP );
lod_minLOD = ri.Cvar_Get( "lod_minLOD", "1.0", CVAR_TEMP );
lod_maxLOD = ri.Cvar_Get( "lod_maxLOD", "0.3", CVAR_TEMP );
lod_LOD_slider = ri.Cvar_Get( "lod_LOD_slider", "0.5", CVAR_TEMP );
lod_edit_0 = ri.Cvar_Get( "lod_edit_0", "0", CVAR_TEMP );
lod_edit_1 = ri.Cvar_Get( "lod_edit_1", "0", CVAR_TEMP );
lod_edit_2 = ri.Cvar_Get( "lod_edit_2", "0", CVAR_TEMP );
lod_edit_3 = ri.Cvar_Get( "lod_edit_3", "0", CVAR_TEMP );
lod_edit_4 = ri.Cvar_Get( "lod_edit_4", "0", CVAR_TEMP );
lod_curve_0_val = ri.Cvar_Get( "lod_curve_0_val", "0", CVAR_TEMP );
lod_curve_1_val = ri.Cvar_Get( "lod_curve_1_val", "0", CVAR_TEMP );
lod_curve_2_val = ri.Cvar_Get( "lod_curve_2_val", "0", CVAR_TEMP );
lod_curve_3_val = ri.Cvar_Get( "lod_curve_3_val", "0", CVAR_TEMP );
lod_curve_4_val = ri.Cvar_Get( "lod_curve_4_val", "0", CVAR_TEMP );
lod_curve_0_slider = ri.Cvar_Get( "lod_curve_0_slider", "0", CVAR_TEMP );
lod_curve_1_slider = ri.Cvar_Get( "lod_curve_1_slider", "0", CVAR_TEMP );
lod_curve_2_slider = ri.Cvar_Get( "lod_curve_2_slider", "0", CVAR_TEMP );
lod_curve_3_slider = ri.Cvar_Get( "lod_curve_3_slider", "0", CVAR_TEMP );
lod_curve_4_slider = ri.Cvar_Get( "lod_curve_4_slider", "0", CVAR_TEMP );
lod_pitch_val = ri.Cvar_Get( "lod_pitch_val", "0", CVAR_TEMP );
lod_zee_val = ri.Cvar_Get( "lod_zee_val", "0", CVAR_TEMP );
lod_mesh = ri.Cvar_Get( "lod_mesh", "0", CVAR_TEMP );
lod_meshname = ri.Cvar_Get( "lod_meshname", "", CVAR_TEMP );
lod_tikiname = ri.Cvar_Get( "lod_tikiname", "", CVAR_TEMP );
lod_metric = ri.Cvar_Get( "lod_metric", "0.0", CVAR_TEMP );
lod_tris = ri.Cvar_Get( "lod_tris", "", CVAR_TEMP );
lod_save = ri.Cvar_Get( "lod_save", "0", CVAR_TEMP );
lod_position = ri.Cvar_Get( "lod_metric", "0 0 0", CVAR_TEMP );
lod_tool = ri.Cvar_Get( "lod_tool", "0", CVAR_TEMP );
// make sure all the commands added here are also // make sure all the commands added here are also
// removed in R_Shutdown // removed in R_Shutdown
ri.Cmd_AddCommand( "imagelist", R_ImageList_f ); ri.Cmd_AddCommand( "imagelist", R_ImageList_f );
@ -1475,6 +1316,7 @@ void R_Register( void )
ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f ); ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f );
ri.Cmd_AddCommand( "minimize", GLimp_Minimize ); ri.Cmd_AddCommand( "minimize", GLimp_Minimize );
ri.Cmd_AddCommand( "gfxmeminfo", GfxMemInfo_f ); ri.Cmd_AddCommand( "gfxmeminfo", GfxMemInfo_f );
ri.Cmd_AddCommand( "exportCubemaps", R_ExportCubemaps_f );
} }
void R_InitQueries(void) void R_InitQueries(void)
@ -1483,7 +1325,7 @@ void R_InitQueries(void)
return; return;
if (r_drawSunRays->integer) if (r_drawSunRays->integer)
qglGenQueriesARB(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); qglGenQueries(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery);
} }
void R_ShutDownQueries(void) void R_ShutDownQueries(void)
@ -1492,7 +1334,7 @@ void R_ShutDownQueries(void)
return; return;
if (r_drawSunRays->integer) if (r_drawSunRays->integer)
qglDeleteQueriesARB(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); qglDeleteQueries(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery);
} }
/* /*
@ -1512,8 +1354,8 @@ void R_Init( void ) {
Com_Memset( &backEnd, 0, sizeof( backEnd ) ); Com_Memset( &backEnd, 0, sizeof( backEnd ) );
Com_Memset( &tess, 0, sizeof( tess ) ); Com_Memset( &tess, 0, sizeof( tess ) );
//if(sizeof(glconfig_t) != 11332) if(sizeof(glconfig_t) != 11332)
// ri.Error( ERR_FATAL, "Mod ABI incompatible: sizeof(glconfig_t) == %u != 11332", (unsigned int) sizeof(glconfig_t)); ri.Error( ERR_FATAL, "Mod ABI incompatible: sizeof(glconfig_t) == %u != 11332", (unsigned int) sizeof(glconfig_t));
// Swap_Init(); // Swap_Init();
@ -1567,8 +1409,6 @@ void R_Init( void ) {
backEndData = (backEndData_t *) ptr; backEndData = (backEndData_t *) ptr;
backEndData->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData )); backEndData->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData ));
backEndData->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys); backEndData->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys);
backEndData->staticModels = NULL;
backEndData->staticModelData = NULL;
R_InitNextFrame(); R_InitNextFrame();
InitOpenGL(); InitOpenGL();
@ -1611,17 +1451,17 @@ void RE_Shutdown( qboolean destroyWindow ) {
ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow ); ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow );
ri.Cmd_RemoveCommand ("modellist"); ri.Cmd_RemoveCommand( "imagelist" );
ri.Cmd_RemoveCommand ("screenshotJPEG"); ri.Cmd_RemoveCommand( "shaderlist" );
ri.Cmd_RemoveCommand ("screenshot"); ri.Cmd_RemoveCommand( "skinlist" );
ri.Cmd_RemoveCommand ("imagelist"); ri.Cmd_RemoveCommand( "modellist" );
ri.Cmd_RemoveCommand ("shaderlist");
ri.Cmd_RemoveCommand ("skinlist");
ri.Cmd_RemoveCommand ("gfxinfo");
ri.Cmd_RemoveCommand("minimize");
ri.Cmd_RemoveCommand( "modelist" ); ri.Cmd_RemoveCommand( "modelist" );
ri.Cmd_RemoveCommand( "shaderstate" ); ri.Cmd_RemoveCommand( "screenshot" );
ri.Cmd_RemoveCommand( "screenshotJPEG" );
ri.Cmd_RemoveCommand( "gfxinfo" );
ri.Cmd_RemoveCommand( "minimize" );
ri.Cmd_RemoveCommand( "gfxmeminfo" ); ri.Cmd_RemoveCommand( "gfxmeminfo" );
ri.Cmd_RemoveCommand( "exportCubemaps" );
if ( tr.registered ) { if ( tr.registered ) {
@ -1640,43 +1480,19 @@ void RE_Shutdown( qboolean destroyWindow ) {
if ( destroyWindow ) { if ( destroyWindow ) {
GLimp_Shutdown(); GLimp_Shutdown();
Com_Memset(&glConfig, 0, sizeof(glConfig)); Com_Memset( &glConfig, 0, sizeof( glConfig ) );
textureFilterAnisotropic = qfalse; Com_Memset( &glRefConfig, 0, sizeof( glRefConfig ) );
maxAnisotropy = 0; textureFilterAnisotropic = qfalse;
displayAspect = 0.0f; maxAnisotropy = 0;
haveClampToEdge = qfalse; displayAspect = 0.0f;
haveClampToEdge = qfalse;
Com_Memset(&glState, 0, sizeof(glState)); Com_Memset( &glState, 0, sizeof( glState ) );
} }
tr.registered = qfalse; tr.registered = qfalse;
} }
/*
===============
RE_BeginRegistration
===============
*/
void RE_BeginRegistration( glconfig_t *glconfigOut ) {
ri.Hunk_Clear();
R_Init();
*glconfigOut = glConfig;
//R_SyncRenderThread();
R_IssuePendingRenderCommands();
r_sequencenumber++;
tr.viewCluster = -1; // force markleafs to regenerate
R_ClearFlares();
RE_ClearScene();
// FIXME: implement dcl...
//R_LevelMarksInit();
tr.registered = qtrue;
}
/* /*
============= =============
@ -1687,21 +1503,13 @@ Touch all images to make sure they are resident
*/ */
void RE_EndRegistration( void ) { void RE_EndRegistration( void ) {
R_IssuePendingRenderCommands(); R_IssuePendingRenderCommands();
RB_ShowImages(); if (!ri.Sys_LowPhysicalMemory()) {
RB_ShowImages();
}
} }
/* void RE_SetRenderTime(int t) {
============= // FIXME: unimplemented
RE_SetRenderTime
=============
*/
void RE_SetRenderTime( int t ) {
backEnd.refdef.floatTime = ( float )t / 1000.0;
// FIXME: update ghost textures ?
}
const char *RE_GetShaderName( qhandle_t shader ) {
return tr.shaders[ shader ]->name;
} }
/* /*
@ -1730,89 +1538,77 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) {
// the RE_ functions are Renderer Entry points // the RE_ functions are Renderer Entry points
re.Shutdown = RE_Shutdown; re.Shutdown = RE_Shutdown;
re.FreeModels = RE_FreeModels; re.FreeModels = RE_FreeModels;
re.BeginRegistration = RE_BeginRegistration; re.BeginRegistration = RE_BeginRegistration;
re.EndRegistration = RE_EndRegistration; re.EndRegistration = RE_EndRegistration;
re.RegisterModel = RE_RegisterModel; re.RegisterModel = RE_RegisterModel;
re.SpawnEffectModel = RE_SpawnEffectModel; re.SpawnEffectModel = RE_SpawnEffectModel;
re.RegisterServerModel = RE_RegisterServerModel; re.RegisterServerModel = RE_RegisterServerModel;
re.UnregisterServerModel = RE_UnregisterServerModel; re.UnregisterServerModel = RE_UnregisterServerModel;
re.RegisterShader = RE_RegisterShader; re.RegisterShader = RE_RegisterShader;
re.RegisterShaderNoMip = RE_RegisterShaderNoMip; re.RegisterShaderNoMip = RE_RegisterShaderNoMip;
re.LoadWorld = RE_LoadWorldMap; re.LoadWorld = RE_LoadWorldMap;
re.PrintBSPFileSizes = RE_PrintBSPFileSizes; re.PrintBSPFileSizes = RE_PrintBSPFileSizes;
re.MapVersion = RE_MapVersion; re.MapVersion = RE_MapVersion;
re.LoadFont = R_LoadFont; re.LoadFont = R_LoadFont;
re.SetWorldVisData = RE_SetWorldVisData; re.SetWorldVisData = RE_SetWorldVisData;
re.BeginFrame = RE_BeginFrame; re.BeginFrame = RE_BeginFrame;
re.EndFrame = RE_EndFrame; re.EndFrame = RE_EndFrame;
re.MarkFragments = R_MarkFragments; re.MarkFragments = R_MarkFragments;
re.MarkFragmentsForInlineModel = R_MarkFragmentsForInlineModel; re.MarkFragmentsForInlineModel = R_MarkFragmentsForInlineModel;
re.GetInlineModelBounds = R_GetInlineModelBounds; re.GetInlineModelBounds = R_GetInlineModelBounds;
re.GetLightingForDecal = R_GetLightingForDecal; re.GetLightingForDecal = R_GetLightingForDecal;
re.GetLightingForSmoke = R_GetLightingForSmoke; re.GetLightingForSmoke = R_GetLightingForSmoke;
re.R_GatherLightSources = R_GatherLightSources; re.R_GatherLightSources = R_GatherLightSources;
re.ModelBounds = R_ModelBounds; re.ModelBounds = R_ModelBounds;
re.ModelRadius = R_ModelRadius; re.ModelRadius = R_ModelRadius;
re.ClearScene = RE_ClearScene; re.ClearScene = RE_ClearScene;
re.AddRefEntityToScene = RE_AddRefEntityToScene; re.AddRefEntityToScene = RE_AddRefEntityToScene;
re.AddRefSpriteToScene = RE_AddRefSpriteToScene; re.AddRefSpriteToScene = RE_AddRefSpriteToScene;
re.AddPolyToScene = RE_AddPolyToScene; re.AddPolyToScene = RE_AddPolyToScene;
re.AddTerrainMarkToScene = RE_AddTerrainMarkToScene; re.AddTerrainMarkToScene = RE_AddTerrainMarkToScene;
re.AddLightToScene = RE_AddLightToScene; re.AddLightToScene = RE_AddLightToScene;
re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene; re.RenderScene = RE_RenderScene;
re.RenderScene = RE_RenderScene; re.GetRenderEntity = RE_GetRenderEntity;
re.GetRenderEntity = RE_GetRenderEntity;
re.SavePerformanceCounters = R_SavePerformanceCounters; re.SavePerformanceCounters = R_SavePerformanceCounters;
re.R_Model_GetHandle = R_Model_GetHandle; re.R_Model_GetHandle = R_Model_GetHandle;
re.SetColor = Draw_SetColor; re.SetColor = Draw_SetColor;
re.DrawStretchPic = Draw_StretchPic; re.DrawStretchPic = Draw_StretchPic;
re.DrawStretchRaw = RE_StretchRaw; re.DrawStretchRaw = RE_StretchRaw;
re.DebugLine = R_DebugLine; re.DebugLine = R_DebugLine;
re.DrawTilePic = Draw_TilePic; re.DrawTilePic = Draw_TilePic;
re.DrawTilePicOffset = Draw_TilePicOffset; re.DrawTilePicOffset = Draw_TilePicOffset;
re.DrawTrianglePic = Draw_TrianglePic; re.DrawTrianglePic = Draw_TrianglePic;
re.DrawBox = DrawBox; re.DrawBox = DrawBox;
re.AddBox = AddBox; re.AddBox = AddBox;
re.Set2DWindow = Set2DWindow; re.Set2DWindow = Set2DWindow;
re.Scissor = RE_Scissor; re.Scissor = RE_Scissor;
re.DrawLineLoop = DrawLineLoop; re.DrawLineLoop = DrawLineLoop;
re.DrawString = R_DrawString; re.DrawString = R_DrawString;
re.GetFontHeight = R_GetFontHeight; re.GetFontHeight = R_GetFontHeight;
re.GetFontStringWidth = R_GetFontStringWidth; re.GetFontStringWidth = R_GetFontStringWidth;
re.SwipeBegin = RE_SwipeBegin; re.SwipeBegin = RE_SwipeBegin;
re.SwipeEnd = RE_SwipeEnd; re.SwipeEnd = RE_SwipeEnd;
re.SetRenderTime = RE_SetRenderTime; re.SetRenderTime = RE_SetRenderTime;
re.Noise = R_NoiseGet4f; re.Noise = R_NoiseGet4f;
re.SetMode = R_SetMode; re.SetMode = R_SetMode;
re.SetFullscreen = R_SetFullscreen; re.SetFullscreen = R_SetFullscreen;
re.GetShaderHeight = RE_GetShaderHeight; re.GetShaderHeight = RE_GetShaderHeight;
re.GetShaderWidth = RE_GetShaderWidth; re.GetShaderWidth = RE_GetShaderWidth;
re.GetGraphicsInfo = RE_GetGraphicsInfo; re.GetGraphicsInfo = RE_GetGraphicsInfo;
re.ForceUpdatePose = RE_ForceUpdatePose; re.ForceUpdatePose = RE_ForceUpdatePose;
re.TIKI_Orientation = RE_TIKI_Orientation; re.TIKI_Orientation = RE_TIKI_Orientation;
re.TIKI_IsOnGround = RE_TIKI_IsOnGround; re.TIKI_IsOnGround = RE_TIKI_IsOnGround;
re.SetFrameNumber = RE_SetFrameNumber; re.SetFrameNumber = RE_SetFrameNumber;
re.RegisterFont = RE_RegisterFont;
// IneQuation
re.Text_Width = RE_Text_Width;
re.Text_Height = RE_Text_Height;
re.Text_Paint = RE_Text_Paint;
re.Text_PaintChar = RE_Text_PaintChar;
// su44
re.GetShaderName = RE_GetShaderName;
return &re; return &re;
} }

View file

@ -99,7 +99,6 @@ void R_DlightBmodel( bmodel_t *bmodel ) {
case SF_FACE: case SF_FACE:
case SF_GRID: case SF_GRID:
case SF_TRIANGLES: case SF_TRIANGLES:
case SF_VAO_MESH:
((srfBspSurface_t *)surf->data)->dlightBits = mask; ((srfBspSurface_t *)surf->data)->dlightBits = mask;
break; break;
@ -139,7 +138,7 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) {
float totalFactor; float totalFactor;
if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
// seperate lightOrigins are needed so an object that is // separate lightOrigins are needed so an object that is
// sinking into the ground can still be lit, and so // sinking into the ground can still be lit, and so
// multi-part models can be lit identically // multi-part models can be lit identically
VectorCopy( ent->e.lightingOrigin, lightOrigin ); VectorCopy( ent->e.lightingOrigin, lightOrigin );
@ -201,10 +200,10 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) {
continue; continue;
} }
if (world->hdrLightGrid) if (world->lightGrid16)
{ {
float *hdrData = world->hdrLightGrid + (int)(data - world->lightGridData) / 8 * 6; uint16_t *data16 = world->lightGrid16 + (int)(data - world->lightGridData) / 8 * 6;
if (!(hdrData[0]+hdrData[1]+hdrData[2]+hdrData[3]+hdrData[4]+hdrData[5]) ) { if (!(data16[0]+data16[1]+data16[2]+data16[3]+data16[4]+data16[5])) {
continue; // ignore samples in walls continue; // ignore samples in walls
} }
} }
@ -227,18 +226,18 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) {
ent->directedLight[1] += factor * d4; ent->directedLight[1] += factor * d4;
ent->directedLight[2] += factor * d5; ent->directedLight[2] += factor * d5;
#else #else
if (world->hdrLightGrid) if (world->lightGrid16)
{ {
// FIXME: this is hideous // FIXME: this is hideous
float *hdrData = world->hdrLightGrid + (int)(data - world->lightGridData) / 8 * 6; uint16_t *data16 = world->lightGrid16 + (int)(data - world->lightGridData) / 8 * 6;
ent->ambientLight[0] += factor * hdrData[0]; ent->ambientLight[0] += factor * data16[0] / 257.0f;
ent->ambientLight[1] += factor * hdrData[1]; ent->ambientLight[1] += factor * data16[1] / 257.0f;
ent->ambientLight[2] += factor * hdrData[2]; ent->ambientLight[2] += factor * data16[2] / 257.0f;
ent->directedLight[0] += factor * hdrData[3]; ent->directedLight[0] += factor * data16[3] / 257.0f;
ent->directedLight[1] += factor * hdrData[4]; ent->directedLight[1] += factor * data16[4] / 257.0f;
ent->directedLight[2] += factor * hdrData[5]; ent->directedLight[2] += factor * data16[5] / 257.0f;
} }
else else
{ {
@ -336,7 +335,7 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
// trace a sample point down to find ambient light // trace a sample point down to find ambient light
// //
if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
// seperate lightOrigins are needed so an object that is // separate lightOrigins are needed so an object that is
// sinking into the ground can still be lit, and so // sinking into the ground can still be lit, and so
// multi-part models can be lit identically // multi-part models can be lit identically
VectorCopy( ent->e.lightingOrigin, lightOrigin ); VectorCopy( ent->e.lightingOrigin, lightOrigin );
@ -357,7 +356,7 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
} }
// bonus items and view weapons have a fixed minimum add // bonus items and view weapons have a fixed minimum add
if ( !r_hdr->integer /* ent->e.renderfx & RF_MINLIGHT */ ) { if ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) {
// give everything a minimum light add // give everything a minimum light add
ent->ambientLight[0] += tr.identityLight * 32; ent->ambientLight[0] += tr.identityLight * 32;
ent->ambientLight[1] += tr.identityLight * 32; ent->ambientLight[1] += tr.identityLight * 32;
@ -385,16 +384,42 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
VectorMA( lightDir, d, dir, lightDir ); VectorMA( lightDir, d, dir, lightDir );
} }
// clamp ambient // clamp lights
if ( !r_hdr->integer ) // FIXME: old renderer clamps (ambient + NL * directed) per vertex
// check if that's worth implementing
{ {
for ( i = 0 ; i < 3 ; i++ ) { float r, g, b, max;
if ( ent->ambientLight[i] > tr.identityLightByte ) {
ent->ambientLight[i] = tr.identityLightByte; r = ent->ambientLight[0];
} g = ent->ambientLight[1];
b = ent->ambientLight[2];
max = MAX(MAX(r, g), b);
if (max > 255.0f)
{
max = 255.0f / max;
ent->ambientLight[0] *= max;
ent->ambientLight[1] *= max;
ent->ambientLight[2] *= max;
}
r = ent->directedLight[0];
g = ent->directedLight[1];
b = ent->directedLight[2];
max = MAX(MAX(r, g), b);
if (max > 255.0f)
{
max = 255.0f / max;
ent->directedLight[0] *= max;
ent->directedLight[1] *= max;
ent->directedLight[2] *= max;
} }
} }
if ( r_debugLight->integer ) { if ( r_debugLight->integer ) {
LogLight( ent ); LogLight( ent );
} }
@ -471,7 +496,7 @@ int R_CubemapForPoint( vec3_t point )
vec3_t diff; vec3_t diff;
vec_t length; vec_t length;
VectorSubtract(point, tr.cubemapOrigins[i], diff); VectorSubtract(point, tr.cubemaps[i].origin, diff);
length = DotProduct(diff, diff); length = DotProduct(diff, diff);
if (shortest > length) if (shortest > length)
@ -484,34 +509,3 @@ int R_CubemapForPoint( vec3_t point )
return cubemapIndex + 1; return cubemapIndex + 1;
} }
/*
=================
R_GetLightingForDecal
=================
*/
void R_GetLightingForDecal( vec3_t vLight, vec3_t vFacing, vec3_t vOrigin ) {
// FIXME: stub
}
/*
=================
R_GetLightingForSmoke
=================
*/
void R_GetLightingForSmoke( vec3_t vLight, vec3_t vOrigin ) {
// FIXME: stub
}
/*
=================
R_GatherLightSources
=================
*/
int R_GatherLightSources( const vec3_t vPos, vec3_t *pvLightPos, vec3_t *pvLightIntensity, int iMaxLights ) {
// FIXME: stub
// i don't think this is useful because renderer_gl2 handles light differently
// thus, R_GatherLightSources is mainly used to create fake shadow
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -70,230 +70,11 @@ qboolean R_CompareVert(srfVert_t * v1, srfVert_t * v2, qboolean checkST)
/* /*
============= =============
R_CalcNormalForTriangle R_CalcTexDirs
Lengyel, Eric. Computing Tangent Space Basis Vectors for an Arbitrary Mesh. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html
============= =============
*/ */
void R_CalcNormalForTriangle(vec3_t normal, const vec3_t v0, const vec3_t v1, const vec3_t v2)
{
vec3_t udir, vdir;
// compute the face normal based on vertex points
VectorSubtract(v2, v0, udir);
VectorSubtract(v1, v0, vdir);
CrossProduct(udir, vdir, normal);
VectorNormalize(normal);
}
/*
=============
R_CalcTangentsForTriangle
http://members.rogers.com/deseric/tangentspace.htm
=============
*/
void R_CalcTangentsForTriangle(vec3_t tangent, vec3_t bitangent,
const vec3_t v0, const vec3_t v1, const vec3_t v2,
const vec2_t t0, const vec2_t t1, const vec2_t t2)
{
int i;
vec3_t planes[3];
vec3_t u, v;
for(i = 0; i < 3; i++)
{
VectorSet(u, v1[i] - v0[i], t1[0] - t0[0], t1[1] - t0[1]);
VectorSet(v, v2[i] - v0[i], t2[0] - t0[0], t2[1] - t0[1]);
VectorNormalize(u);
VectorNormalize(v);
CrossProduct(u, v, planes[i]);
}
//So your tangent space will be defined by this :
//Normal = Normal of the triangle or Tangent X Bitangent (careful with the cross product,
// you have to make sure the normal points in the right direction)
//Tangent = ( dp(Fx(s,t)) / ds, dp(Fy(s,t)) / ds, dp(Fz(s,t)) / ds ) or ( -Bx/Ax, -By/Ay, - Bz/Az )
//Bitangent = ( dp(Fx(s,t)) / dt, dp(Fy(s,t)) / dt, dp(Fz(s,t)) / dt ) or ( -Cx/Ax, -Cy/Ay, -Cz/Az )
// tangent...
tangent[0] = -planes[0][1] / planes[0][0];
tangent[1] = -planes[1][1] / planes[1][0];
tangent[2] = -planes[2][1] / planes[2][0];
VectorNormalize(tangent);
// bitangent...
bitangent[0] = -planes[0][2] / planes[0][0];
bitangent[1] = -planes[1][2] / planes[1][0];
bitangent[2] = -planes[2][2] / planes[2][0];
VectorNormalize(bitangent);
}
/*
=============
R_CalcTangentSpace
=============
*/
void R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, vec3_t normal,
const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2)
{
vec3_t cp, u, v;
vec3_t faceNormal;
VectorSet(u, v1[0] - v0[0], t1[0] - t0[0], t1[1] - t0[1]);
VectorSet(v, v2[0] - v0[0], t2[0] - t0[0], t2[1] - t0[1]);
CrossProduct(u, v, cp);
if(fabs(cp[0]) > 10e-6)
{
tangent[0] = -cp[1] / cp[0];
bitangent[0] = -cp[2] / cp[0];
}
u[0] = v1[1] - v0[1];
v[0] = v2[1] - v0[1];
CrossProduct(u, v, cp);
if(fabs(cp[0]) > 10e-6)
{
tangent[1] = -cp[1] / cp[0];
bitangent[1] = -cp[2] / cp[0];
}
u[0] = v1[2] - v0[2];
v[0] = v2[2] - v0[2];
CrossProduct(u, v, cp);
if(fabs(cp[0]) > 10e-6)
{
tangent[2] = -cp[1] / cp[0];
bitangent[2] = -cp[2] / cp[0];
}
VectorNormalize(tangent);
VectorNormalize(bitangent);
// compute the face normal based on vertex points
if ( normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f )
{
VectorSubtract(v2, v0, u);
VectorSubtract(v1, v0, v);
CrossProduct(u, v, faceNormal);
}
else
{
VectorCopy(normal, faceNormal);
}
VectorNormalize(faceNormal);
#if 1
// Gram-Schmidt orthogonalize
//tangent[a] = (t - n * Dot(n, t)).Normalize();
VectorMA(tangent, -DotProduct(faceNormal, tangent), faceNormal, tangent);
VectorNormalize(tangent);
// compute the cross product B=NxT
//CrossProduct(normal, tangent, bitangent);
#else
// normal, compute the cross product N=TxB
CrossProduct(tangent, bitangent, normal);
VectorNormalize(normal);
if(DotProduct(normal, faceNormal) < 0)
{
//VectorInverse(normal);
//VectorInverse(tangent);
//VectorInverse(bitangent);
// compute the cross product T=BxN
CrossProduct(bitangent, faceNormal, tangent);
// compute the cross product B=NxT
//CrossProduct(normal, tangent, bitangent);
}
#endif
VectorCopy(faceNormal, normal);
}
void R_CalcTangentSpaceFast(vec3_t tangent, vec3_t bitangent, vec3_t normal,
const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2)
{
vec3_t cp, u, v;
vec3_t faceNormal;
VectorSet(u, v1[0] - v0[0], t1[0] - t0[0], t1[1] - t0[1]);
VectorSet(v, v2[0] - v0[0], t2[0] - t0[0], t2[1] - t0[1]);
CrossProduct(u, v, cp);
if(fabs(cp[0]) > 10e-6)
{
tangent[0] = -cp[1] / cp[0];
bitangent[0] = -cp[2] / cp[0];
}
u[0] = v1[1] - v0[1];
v[0] = v2[1] - v0[1];
CrossProduct(u, v, cp);
if(fabs(cp[0]) > 10e-6)
{
tangent[1] = -cp[1] / cp[0];
bitangent[1] = -cp[2] / cp[0];
}
u[0] = v1[2] - v0[2];
v[0] = v2[2] - v0[2];
CrossProduct(u, v, cp);
if(fabs(cp[0]) > 10e-6)
{
tangent[2] = -cp[1] / cp[0];
bitangent[2] = -cp[2] / cp[0];
}
VectorNormalizeFast(tangent);
VectorNormalizeFast(bitangent);
// compute the face normal based on vertex points
VectorSubtract(v2, v0, u);
VectorSubtract(v1, v0, v);
CrossProduct(u, v, faceNormal);
VectorNormalizeFast(faceNormal);
#if 0
// normal, compute the cross product N=TxB
CrossProduct(tangent, bitangent, normal);
VectorNormalizeFast(normal);
if(DotProduct(normal, faceNormal) < 0)
{
VectorInverse(normal);
//VectorInverse(tangent);
//VectorInverse(bitangent);
CrossProduct(normal, tangent, bitangent);
}
VectorCopy(faceNormal, normal);
#else
// Gram-Schmidt orthogonalize
//tangent[a] = (t - n * Dot(n, t)).Normalize();
VectorMA(tangent, -DotProduct(faceNormal, tangent), faceNormal, tangent);
VectorNormalizeFast(tangent);
#endif
VectorCopy(faceNormal, normal);
}
/*
http://www.terathon.com/code/tangent.html
*/
void R_CalcTexDirs(vec3_t sdir, vec3_t tdir, const vec3_t v1, const vec3_t v2, void R_CalcTexDirs(vec3_t sdir, vec3_t tdir, const vec3_t v1, const vec3_t v2,
const vec3_t v3, const vec2_t w1, const vec2_t w2, const vec2_t w3) const vec3_t v3, const vec2_t w1, const vec2_t w2, const vec2_t w3)
{ {
@ -312,13 +93,21 @@ void R_CalcTexDirs(vec3_t sdir, vec3_t tdir, const vec3_t v1, const vec3_t v2,
t1 = w2[1] - w1[1]; t1 = w2[1] - w1[1];
t2 = w3[1] - w1[1]; t2 = w3[1] - w1[1];
r = 1.0f / (s1 * t2 - s2 * t1); r = s1 * t2 - s2 * t1;
if (r) r = 1.0f / r;
VectorSet(sdir, (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); VectorSet(sdir, (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
VectorSet(tdir, (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); VectorSet(tdir, (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
} }
void R_CalcTbnFromNormalAndTexDirs(vec3_t tangent, vec3_t bitangent, vec3_t normal, vec3_t sdir, vec3_t tdir) /*
=============
R_CalcTangentSpace
Lengyel, Eric. Computing Tangent Space Basis Vectors for an Arbitrary Mesh. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html
=============
*/
vec_t R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, const vec3_t normal, const vec3_t sdir, const vec3_t tdir)
{ {
vec3_t n_cross_t; vec3_t n_cross_t;
vec_t n_dot_t, handedness; vec_t n_dot_t, handedness;
@ -332,114 +121,13 @@ void R_CalcTbnFromNormalAndTexDirs(vec3_t tangent, vec3_t bitangent, vec3_t norm
CrossProduct(normal, sdir, n_cross_t); CrossProduct(normal, sdir, n_cross_t);
handedness = (DotProduct(n_cross_t, tdir) < 0.0f) ? -1.0f : 1.0f; handedness = (DotProduct(n_cross_t, tdir) < 0.0f) ? -1.0f : 1.0f;
// Calculate bitangent // Calculate orthogonal bitangent, if necessary
CrossProduct(normal, tangent, bitangent); if (bitangent)
VectorScale(bitangent, handedness, bitangent); CrossProduct(normal, tangent, bitangent);
return handedness;
} }
void R_CalcTBN2(vec3_t tangent, vec3_t bitangent, vec3_t normal,
const vec3_t v1, const vec3_t v2, const vec3_t v3, const vec2_t t1, const vec2_t t2, const vec2_t t3)
{
vec3_t v2v1;
vec3_t v3v1;
float c2c1_T;
float c2c1_B;
float c3c1_T;
float c3c1_B;
float denominator;
float scale1, scale2;
vec3_t T, B, N, C;
// Calculate the tangent basis for each vertex of the triangle
// UPDATE: In the 3rd edition of the accompanying article, the for-loop located here has
// been removed as it was redundant (the entire TBN matrix was calculated three times
// instead of just one).
//
// Please note, that this function relies on the fact that the input geometry are triangles
// and the tangent basis for each vertex thus is identical!
//
// Calculate the vectors from the current vertex to the two other vertices in the triangle
VectorSubtract(v2, v1, v2v1);
VectorSubtract(v3, v1, v3v1);
// The equation presented in the article states that:
// c2c1_T = V2.texcoord.x - V1.texcoord.x
// c2c1_B = V2.texcoord.y - V1.texcoord.y
// c3c1_T = V3.texcoord.x - V1.texcoord.x
// c3c1_B = V3.texcoord.y - V1.texcoord.y
// Calculate c2c1_T and c2c1_B
c2c1_T = t2[0] - t1[0];
c2c1_B = t2[1] - t2[1];
// Calculate c3c1_T and c3c1_B
c3c1_T = t3[0] - t1[0];
c3c1_B = t3[1] - t1[1];
denominator = c2c1_T * c3c1_B - c3c1_T * c2c1_B;
//if(ROUNDOFF(fDenominator) == 0.0f)
if(denominator == 0.0f)
{
// We won't risk a divide by zero, so set the tangent matrix to the identity matrix
VectorSet(tangent, 1, 0, 0);
VectorSet(bitangent, 0, 1, 0);
VectorSet(normal, 0, 0, 1);
}
else
{
// Calculate the reciprocal value once and for all (to achieve speed)
scale1 = 1.0f / denominator;
// T and B are calculated just as the equation in the article states
VectorSet(T, (c3c1_B * v2v1[0] - c2c1_B * v3v1[0]) * scale1,
(c3c1_B * v2v1[1] - c2c1_B * v3v1[1]) * scale1,
(c3c1_B * v2v1[2] - c2c1_B * v3v1[2]) * scale1);
VectorSet(B, (-c3c1_T * v2v1[0] + c2c1_T * v3v1[0]) * scale1,
(-c3c1_T * v2v1[1] + c2c1_T * v3v1[1]) * scale1,
(-c3c1_T * v2v1[2] + c2c1_T * v3v1[2]) * scale1);
// The normal N is calculated as the cross product between T and B
CrossProduct(T, B, N);
#if 0
VectorCopy(T, tangent);
VectorCopy(B, bitangent);
VectorCopy(N, normal);
#else
// Calculate the reciprocal value once and for all (to achieve speed)
scale2 = 1.0f / ((T[0] * B[1] * N[2] - T[2] * B[1] * N[0]) +
(B[0] * N[1] * T[2] - B[2] * N[1] * T[0]) +
(N[0] * T[1] * B[2] - N[2] * T[1] * B[0]));
// Calculate the inverse if the TBN matrix using the formula described in the article.
// We store the basis vectors directly in the provided TBN matrix: pvTBNMatrix
CrossProduct(B, N, C); tangent[0] = C[0] * scale2;
CrossProduct(N, T, C); tangent[1] = -C[0] * scale2;
CrossProduct(T, B, C); tangent[2] = C[0] * scale2;
VectorNormalize(tangent);
CrossProduct(B, N, C); bitangent[0] = -C[1] * scale2;
CrossProduct(N, T, C); bitangent[1] = C[1] * scale2;
CrossProduct(T, B, C); bitangent[2] = -C[1] * scale2;
VectorNormalize(bitangent);
CrossProduct(B, N, C); normal[0] = C[2] * scale2;
CrossProduct(N, T, C); normal[1] = -C[2] * scale2;
CrossProduct(T, B, C); normal[2] = C[2] * scale2;
VectorNormalize(normal);
#endif
}
}
#ifdef USE_VERT_TANGENT_SPACE
qboolean R_CalcTangentVectors(srfVert_t * dv[3]) qboolean R_CalcTangentVectors(srfVert_t * dv[3])
{ {
int i; int i;
@ -455,7 +143,8 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3])
/* do each vertex */ /* do each vertex */
for(i = 0; i < 3; i++) for(i = 0; i < 3; i++)
{ {
vec3_t bitangent, nxt; vec4_t tangent;
vec3_t normal, bitangent, nxt;
// calculate s tangent vector // calculate s tangent vector
s = dv[i]->st[0] + 10.0f; s = dv[i]->st[0] + 10.0f;
@ -464,12 +153,12 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3])
bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb; bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb;
bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb; bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb;
dv[i]->tangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0]; tangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0];
dv[i]->tangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1]; tangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1];
dv[i]->tangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2]; tangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2];
VectorSubtract(dv[i]->tangent, dv[i]->xyz, dv[i]->tangent); VectorSubtract(tangent, dv[i]->xyz, tangent);
VectorNormalize(dv[i]->tangent); VectorNormalize(tangent);
// calculate t tangent vector // calculate t tangent vector
s = dv[i]->st[0]; s = dv[i]->st[0];
@ -486,8 +175,11 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3])
VectorNormalize(bitangent); VectorNormalize(bitangent);
// store bitangent handedness // store bitangent handedness
CrossProduct(dv[i]->normal, dv[i]->tangent, nxt); R_VaoUnpackNormal(normal, dv[i]->normal);
dv[i]->tangent[3] = (DotProduct(nxt, bitangent) < 0.0f) ? -1.0f : 1.0f; CrossProduct(normal, tangent, nxt);
tangent[3] = (DotProduct(nxt, bitangent) < 0.0f) ? -1.0f : 1.0f;
R_VaoPackTangent(dv[i]->tangent, tangent);
// debug code // debug code
//% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i, //% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i,
@ -496,7 +188,6 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3])
return qtrue; return qtrue;
} }
#endif
/* /*
@ -865,59 +556,6 @@ void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength; or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength;
} }
/*
=================
R_RotateForStaticModel
Generates an orientation for a static model and viewParms
=================
*/
void R_RotateForStaticModel( cStaticModelUnpacked_t *SM, const viewParms_t *viewParms,
orientationr_t *or ) {
float glMatrix[16];
vec3_t delta;
float tiki_scale;
tiki_scale = SM->tiki->load_scale * SM->scale;
VectorCopy( SM->origin, or->origin );
VectorCopy( SM->axis[0], or->axis[0] );
VectorCopy( SM->axis[1], or->axis[1] );
VectorCopy( SM->axis[2], or->axis[2] );
glMatrix[0] = or->axis[0][0] * tiki_scale;
glMatrix[4] = or->axis[1][0] * tiki_scale;
glMatrix[8] = or->axis[2][0] * tiki_scale;
glMatrix[12] = or->origin[0];
glMatrix[1] = or->axis[0][1] * tiki_scale;
glMatrix[5] = or->axis[1][1] * tiki_scale;
glMatrix[9] = or->axis[2][1] * tiki_scale;
glMatrix[13] = or->origin[1];
glMatrix[2] = or->axis[0][2] * tiki_scale;
glMatrix[6] = or->axis[1][2] * tiki_scale;
glMatrix[10] = or->axis[2][2] * tiki_scale;
glMatrix[14] = or->origin[2];
glMatrix[3] = 0;
glMatrix[7] = 0;
glMatrix[11] = 0;
glMatrix[15] = 1;
Mat4Copy(glMatrix, or->transformMatrix);
myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix );
// calculate the viewer origin in the model's space
// needed for fog, specular, and environment mapping
VectorSubtract( viewParms->or.origin, or->origin, delta );
or->viewOrigin[0] = DotProduct( delta, or->axis[0] );
or->viewOrigin[1] = DotProduct( delta, or->axis[1] );
or->viewOrigin[2] = DotProduct( delta, or->axis[2] );
}
/* /*
================= =================
R_RotateForViewer R_RotateForViewer
@ -1455,6 +1093,7 @@ qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum,
VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] ); VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] );
VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] ); VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] );
// optionally rotate
if ( e->e.skinNum ) { if ( e->e.skinNum ) {
d = e->e.skinNum; d = e->e.skinNum;
VectorCopy( camera->axis[1], transformed ); VectorCopy( camera->axis[1], transformed );
@ -1552,11 +1191,10 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128
int i; int i;
unsigned int pointOr = 0; unsigned int pointOr = 0;
unsigned int pointAnd = (unsigned int)~0; unsigned int pointAnd = (unsigned int)~0;
qboolean staticModel;
R_RotateForViewer(); R_RotateForViewer();
R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed, &staticModel ); R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed );
RB_BeginSurface( shader, fogNum, drawSurf->cubemapIndex); RB_BeginSurface( shader, fogNum, drawSurf->cubemapIndex);
rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
@ -1678,8 +1316,8 @@ qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) {
return qfalse; // bad portal, no portalentity return qfalse; // bad portal, no portalentity
} }
if (newParms.isMirror) // Never draw viewmodels in portal or mirror views.
newParms.flags |= VPF_NOVIEWMODEL; newParms.flags |= VPF_NOVIEWMODEL;
R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin ); R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin );
@ -1810,8 +1448,7 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
// compared quickly during the qsorting process // compared quickly during the qsorting process
tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT) tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT)
| tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT )
| ( ( int )pshadowMap << QSORT_PSHADOW_SHIFT ) | ( int )dlightMap | ((int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap;
| ( tr.shiftedIsStatic << QSORT_STATIC_SHIFT );
tr.refdef.drawSurfs[index].cubemapIndex = cubemap; tr.refdef.drawSurfs[index].cubemapIndex = cubemap;
tr.refdef.drawSurfs[index].surface = surface; tr.refdef.drawSurfs[index].surface = surface;
tr.refdef.numDrawSurfs++; tr.refdef.numDrawSurfs++;
@ -1823,13 +1460,12 @@ R_DecomposeSort
================= =================
*/ */
void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
int *fogNum, int *dlightMap, int *pshadowMap, qboolean *staticModel ) { int *fogNum, int *dlightMap, int *pshadowMap ) {
*fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31; *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31;
*shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ]; *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ];
*entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK; *entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK;
*pshadowMap = (sort >> QSORT_PSHADOW_SHIFT ) & 1; *pshadowMap = (sort >> QSORT_PSHADOW_SHIFT ) & 1;
*dlightMap = sort & 1; *dlightMap = sort & 1;
*staticModel = ( sort >> QSORT_STATIC_SHIFT ) & 1;
} }
/* /*
@ -1844,7 +1480,6 @@ void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
int dlighted; int dlighted;
int pshadowed; int pshadowed;
int i; int i;
qboolean staticModel;
//ri.Printf(PRINT_ALL, "firstDrawSurf %d numDrawSurfs %d\n", (int)(drawSurfs - tr.refdef.drawSurfs), numDrawSurfs); //ri.Printf(PRINT_ALL, "firstDrawSurf %d numDrawSurfs %d\n", (int)(drawSurfs - tr.refdef.drawSurfs), numDrawSurfs);
@ -1868,7 +1503,7 @@ void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
// check for any pass through drawing, which // check for any pass through drawing, which
// may cause another view to be rendered first // may cause another view to be rendered first
for ( i = 0 ; i < numDrawSurfs ; i++ ) { for ( i = 0 ; i < numDrawSurfs ; i++ ) {
R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed, &staticModel ); R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed );
if ( shader->sort > SS_PORTAL ) { if ( shader->sort > SS_PORTAL ) {
break; break;
@ -1920,8 +1555,6 @@ static void R_AddEntitySurface (int entityNum)
case RT_PORTALSURFACE: case RT_PORTALSURFACE:
break; // don't draw anything break; // don't draw anything
case RT_SPRITE: case RT_SPRITE:
ri.Error( ERR_DROP, "R_AddEntitySurfaces: Sprite being added to entities, should be added to sprite list" );
break;
case RT_BEAM: case RT_BEAM:
// self blood sprites, talk balloons, etc should not be drawn in the primary // self blood sprites, talk balloons, etc should not be drawn in the primary
// view. We can't just do this check for all entities, because md3 // view. We can't just do this check for all entities, because md3
@ -1951,22 +1584,6 @@ static void R_AddEntitySurface (int entityNum)
} }
R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 ); R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 );
break; break;
case MOD_TIKI:
if( ( ent->e.renderfx & RF_THIRD_PERSON ) && !tr.viewParms.isPortal ) {
break;
}
//if( !r_showSkeleton->integer ) {
R_AddSkelSurfaces( ent );
//} else {
// R_AddDrawSurf( ( void * )&entitySurface, tr.defaultShader, 0 /*fogNum*/, 0, 0, 0 );
//}
break;
case MOD_SPRITE:
if( ( ent->e.renderfx & RF_THIRD_PERSON ) && !tr.viewParms.isPortal ) {
break;
}
R_AddDrawSurf( &entitySurface, tr.currentModel->d.sprite->shader, 0, 0, 0, 0 );
break;
default: default:
ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" ); ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" );
break; break;
@ -1978,10 +1595,6 @@ static void R_AddEntitySurface (int entityNum)
} }
} }
static void R_AddSpriteSurface( int entityNum ) {
// FIXME: stub
}
/* /*
============= =============
R_AddEntitySurfaces R_AddEntitySurfaces
@ -1998,22 +1611,6 @@ void R_AddEntitySurfaces (void) {
R_AddEntitySurface(i); R_AddEntitySurface(i);
} }
/*
=============
R_AddSpriteSurfaces
=============
*/
void R_AddSpriteSurfaces( void ) {
int i;
if( !r_drawentities->integer ) {
return;
}
for( i = 0; i < tr.refdef.num_entities; i++ )
R_AddSpriteSurface( i );
}
/* /*
==================== ====================
@ -2037,12 +1634,10 @@ void R_GenerateDrawSurfs( void ) {
R_SetFarClip(); R_SetFarClip();
} }
R_AddTerrainMarkSurfaces();
R_AddEntitySurfaces();
R_AddSpriteSurfaces();
// we know the size of the clipping volume. Now set the rest of the projection matrix. // we know the size of the clipping volume. Now set the rest of the projection matrix.
R_SetupProjectionZ (&tr.viewParms); R_SetupProjectionZ (&tr.viewParms);
R_AddEntitySurfaces ();
} }
/* /*
@ -2087,115 +1682,20 @@ Visualization aid for movement clipping debugging
==================== ====================
*/ */
void R_DebugGraphics( void ) { void R_DebugGraphics( void ) {
if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
return;
}
if ( !r_debugSurface->integer ) { if ( !r_debugSurface->integer ) {
return; return;
} }
R_IssuePendingRenderCommands(); R_IssuePendingRenderCommands();
GL_Bind( tr.whiteImage); GL_BindToTMU(tr.whiteImage, TB_COLORMAP);
GL_Cull( CT_FRONT_SIDED ); GL_Cull( CT_FRONT_SIDED );
ri.CM_DrawDebugSurface( R_DebugPolygon ); ri.CM_DrawDebugSurface( R_DebugPolygon );
} }
#define CIRCLE_LENGTH 25
/*
================
R_DebugCircle
================
*/
void R_DebugCircle( const vec3_t org, float radius, float r, float g, float b, float alpha, qboolean horizontal ) {
int i;
float ang;
debugline_t *line;
vec3_t forward, right;
vec3_t pos, lastpos;
if( !ri.DebugLines || !ri.numDebugLines ) {
return;
}
if( horizontal )
{
VectorSet( forward, 1, 0, 0 );
VectorSet( right, 0, 1, 0 );
}
else
{
VectorCopy( tr.refdef.viewaxis[ 1 ], right );
VectorCopy( tr.refdef.viewaxis[ 2 ], forward );
}
VectorClear( pos );
VectorClear( lastpos );
for( i = 0; i < CIRCLE_LENGTH; i++ ) {
VectorCopy( pos, lastpos );
ang = ( float )i * 0.0174532925199433f;
pos[ 0 ] = ( org[ 0 ] + sin( ang ) * radius * forward[ 0 ] ) +
cos( ang ) * radius * right[ 0 ];
pos[ 1 ] = ( org[ 1 ] + sin( ang ) * radius * forward[ 1 ] ) +
cos( ang ) * radius * right[ 1 ];
pos[ 2 ] = ( org[ 2 ] + sin( ang ) * radius * forward[ 2 ] ) +
cos( ang ) * radius * right[ 2 ];
if( i > 0 )
{
if( *ri.numDebugLines >= r_numdebuglines->integer ) {
ri.Printf( PRINT_ALL, "R_DebugCircle: Exceeded MAX_DEBUG_LINES\n" );
return;
}
line = &( *ri.DebugLines )[ *ri.numDebugLines ];
( *ri.numDebugLines )++;
VectorCopy( lastpos, line->start );
VectorCopy( pos, line->end );
VectorSet( line->color, r, g, b );
line->alpha = alpha;
line->width = 1.0;
line->factor = 1;
line->pattern = -1;
}
}
}
/*
================
R_DebugLine
================
*/
void R_DebugLine( const vec3_t start, const vec3_t end, float r, float g, float b, float alpha ) {
debugline_t *line;
if( !ri.DebugLines || !ri.numDebugLines ) {
return;
}
if( *ri.numDebugLines >= r_numdebuglines->integer ) {
ri.Printf( PRINT_ALL, "R_DebugLine: Exceeded MAX_DEBUG_LINES\n" );
}
line = &( *ri.DebugLines )[ *ri.numDebugLines ];
( *ri.numDebugLines )++;
VectorCopy( start, line->start );
VectorCopy( end, line->end );
VectorSet( line->color, r, g, b );
line->alpha = alpha;
line->width = 1.0;
line->factor = 1;
line->pattern = -1;
}
/*
================
R_DrawDebugLines
================
*/
void R_DrawDebugLines( void ) {
// FIXME: stub
}
/* /*
================ ================
@ -2240,10 +1740,6 @@ void R_RenderView (viewParms_t *parms) {
R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, numDrawSurfs - firstDrawSurf ); R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, numDrawSurfs - firstDrawSurf );
if( r_showSkeleton->integer ) {
R_DebugSkeleton();
}
// draw main system development information (surface outlines, etc) // draw main system development information (surface outlines, etc)
R_DebugGraphics(); R_DebugGraphics();
} }
@ -2338,7 +1834,7 @@ void R_RenderPshadowMaps(const refdef_t *fd)
{ {
trRefEntity_t *ent = &tr.refdef.entities[i]; trRefEntity_t *ent = &tr.refdef.entities[i];
if((ent->e.renderfx & RF_FIRST_PERSON) && !(ent->e.renderfx & RF_SHADOW)) if((ent->e.renderfx & (RF_FIRST_PERSON)))
continue; continue;
//if((ent->e.renderfx & RF_THIRD_PERSON)) //if((ent->e.renderfx & RF_THIRD_PERSON))
@ -2363,14 +1859,6 @@ void R_RenderPshadowMaps(const refdef_t *fd)
switch (model->type) switch (model->type)
{ {
case MOD_TIKI:
{
dtiki_t *tiki = model->d.tiki;
radius = TIKI_GetRadiusInternal( tiki, ENTITYNUM_NONE, 1.0 );
}
break;
default: default:
break; break;
} }
@ -2504,7 +1992,7 @@ void R_RenderPshadowMaps(const refdef_t *fd)
VectorScale(lightDir, -1.0f, shadow->lightViewAxis[0]); VectorScale(lightDir, -1.0f, shadow->lightViewAxis[0]);
VectorSet(up, 0, 0, -1); VectorSet(up, 0, 0, -1);
if ( abs(DotProduct(up, shadow->lightViewAxis[0])) > 0.9f ) if ( fabsf(DotProduct(up, shadow->lightViewAxis[0])) > 0.9f )
{ {
VectorSet(up, -1, 0, 0); VectorSet(up, -1, 0, 0);
} }
@ -2549,7 +2037,7 @@ void R_RenderPshadowMaps(const refdef_t *fd)
if (glRefConfig.framebufferObject) if (glRefConfig.framebufferObject)
shadowParms.targetFbo = tr.pshadowFbos[i]; shadowParms.targetFbo = tr.pshadowFbos[i];
shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL; shadowParms.flags = VPF_DEPTHSHADOW | VPF_NOVIEWMODEL;
shadowParms.zFar = shadow->lightRadius; shadowParms.zFar = shadow->lightRadius;
VectorCopy(shadow->lightOrigin, shadowParms.or.origin); VectorCopy(shadow->lightOrigin, shadowParms.or.origin);
@ -2747,7 +2235,7 @@ void R_RenderSunShadowMaps(const refdef_t *fd, int level)
} }
// Check if too close to parallel to light direction // Check if too close to parallel to light direction
if (abs(DotProduct(lightViewAxis[2], lightViewAxis[0])) > 0.9f) if (fabsf(DotProduct(lightViewAxis[2], lightViewAxis[0])) > 0.9f)
{ {
if (level == 3 || lightViewIndependentOfCameraView) if (level == 3 || lightViewIndependentOfCameraView)
{ {
@ -3000,11 +2488,10 @@ void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene )
{ {
refdef_t refdef; refdef_t refdef;
viewParms_t parms; viewParms_t parms;
float oldColorScale = tr.refdef.colorScale;
memset( &refdef, 0, sizeof( refdef ) ); memset( &refdef, 0, sizeof( refdef ) );
refdef.rdflags = 0; refdef.rdflags = 0;
VectorCopy(tr.cubemapOrigins[cubemapIndex], refdef.vieworg); VectorCopy(tr.cubemaps[cubemapIndex].origin, refdef.vieworg);
switch(cubemapSide) switch(cubemapSide)
{ {
@ -3073,12 +2560,15 @@ void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene )
{ {
vec3_t ambient, directed, lightDir; vec3_t ambient, directed, lightDir;
float scale;
R_LightForPoint(tr.refdef.vieworg, ambient, directed, lightDir); R_LightForPoint(tr.refdef.vieworg, ambient, directed, lightDir);
tr.refdef.colorScale = 1.0f; //766.0f / (directed[0] + directed[1] + directed[2] + 1.0f); scale = directed[0] + directed[1] + directed[2] + ambient[0] + ambient[1] + ambient[2] + 1.0f;
// only print message for first side // only print message for first side
if (directed[0] + directed[1] + directed[2] == 0 && cubemapSide == 0) if (scale < 1.0001f && cubemapSide == 0)
{ {
ri.Printf(PRINT_ALL, "cubemap %d (%f, %f, %f) is outside the lightgrid!\n", cubemapIndex, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]); ri.Printf(PRINT_ALL, "cubemap %d %s (%f, %f, %f) is outside the lightgrid or inside a wall!\n", cubemapIndex, tr.cubemaps[cubemapIndex].name, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]);
} }
} }
@ -3115,12 +2605,6 @@ void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene )
R_RenderView(&parms); R_RenderView(&parms);
if (subscene) if (!subscene)
{
tr.refdef.colorScale = oldColorScale;
}
else
{
RE_EndScene(); RE_EndScene();
}
} }

View file

@ -256,7 +256,7 @@ R_MarkFragments
================= =================
*/ */
int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer, float fRadiusSquared ) { int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
int numsurfaces, numPlanes; int numsurfaces, numPlanes;
int i, j, k, m, n; int i, j, k, m, n;
surfaceType_t *surfaces[64]; surfaceType_t *surfaces[64];
@ -279,9 +279,6 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio
return 0; return 0;
} }
// FIXME: this crashes the mohaa client game dll...
return 0;
//increment view count for double check prevention //increment view count for double check prevention
tr.viewCount++; tr.viewCount++;
@ -353,17 +350,21 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio
// The offset is added in the vertex normal vector direction // The offset is added in the vertex normal vector direction
// so all triangles will still fit together. // so all triangles will still fit together.
// The 2 unit offset should avoid pretty much all LOD problems. // The 2 unit offset should avoid pretty much all LOD problems.
vec3_t fNormal;
numClipPoints = 3; numClipPoints = 3;
dv = cv->verts + m * cv->width + n; dv = cv->verts + m * cv->width + n;
VectorCopy(dv[0].xyz, clipPoints[0][0]); VectorCopy(dv[0].xyz, clipPoints[0][0]);
VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]); R_VaoUnpackNormal(fNormal, dv[0].normal);
VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
VectorCopy(dv[1].xyz, clipPoints[0][2]); VectorCopy(dv[1].xyz, clipPoints[0][2]);
VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]); R_VaoUnpackNormal(fNormal, dv[1].normal);
VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
// check the normal of this triangle // check the normal of this triangle
VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
@ -383,11 +384,14 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio
} }
VectorCopy(dv[1].xyz, clipPoints[0][0]); VectorCopy(dv[1].xyz, clipPoints[0][0]);
VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]); R_VaoUnpackNormal(fNormal, dv[1].normal);
VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]); VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);
VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]); R_VaoUnpackNormal(fNormal, dv[cv->width + 1].normal);
VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
// check the normal of this triangle // check the normal of this triangle
VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
@ -444,8 +448,10 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio
{ {
for(j = 0; j < 3; j++) for(j = 0; j < 3; j++)
{ {
vec3_t fNormal;
v = surf->verts[tri[j]].xyz; v = surf->verts[tri[j]].xyz;
VectorMA(v, MARKER_OFFSET, surf->verts[tri[j]].normal, clipPoints[0][j]); R_VaoUnpackNormal(fNormal, surf->verts[tri[j]].normal);
VectorMA(v, MARKER_OFFSET, fNormal, clipPoints[0][j]);
} }
// add the fragments of this face // add the fragments of this face
@ -463,12 +469,7 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio
return returnedFragments; return returnedFragments;
} }
int R_MarkFragmentsForInlineModel( clipHandle_t bmodel, vec3_t vAngles, vec3_t vOrigin, int numPoints, vec3_t *points, vec3_t projection,
int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer, float fRadiusSquared ) {
// FIXME: unimplemented
//return R_MarkFragments( numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer, fRadiusSquared );
return 0;
}

View file

@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// tr_models.c -- model loading and caching // tr_models.c -- model loading and caching
#include "tr_local.h" #include "tr_local.h"
#include "tiki.h"
#include <vector.h> #include <vector.h>
#define LL(x) x=LittleLong(x) #define LL(x) x=LittleLong(x)
@ -34,10 +35,10 @@ model_t *R_GetModelByHandle( qhandle_t hModel ) {
// out of range gets the default model // out of range gets the default model
if( hModel < 1 || hModel >= tr.numModels ) { if( hModel < 1 || hModel >= tr.numModels ) {
return &tr.models[0]; return tr.models[0];
} }
mod = &tr.models[hModel]; mod = tr.models[hModel];
return mod; return mod;
} }
@ -76,7 +77,7 @@ model_t *R_AllocModel( void ) {
for( i = 0; i < tr.numModels; i++ ) for( i = 0; i < tr.numModels; i++ )
{ {
if( !tr.models[ i ].name[ 0 ] ) { if( !tr.models[ i ]->name[ 0 ] ) {
break; break;
} }
} }
@ -88,9 +89,9 @@ model_t *R_AllocModel( void ) {
tr.numModels++; tr.numModels++;
} }
tr.models[ i ].index = i; tr.models[ i ]->index = i;
return &tr.models[ i ]; return tr.models[ i ];
} }
/* /*
@ -101,11 +102,11 @@ void RE_FreeModels( void ) {
for( hModel = 0; hModel < tr.numModels; hModel++ ) for( hModel = 0; hModel < tr.numModels; hModel++ )
{ {
if( !tr.models[ hModel ].name[ 0 ] ) { if( !tr.models[ hModel ]->name[ 0 ] ) {
continue; continue;
} }
R_FreeModel( &tr.models[ hModel ] ); R_FreeModel( tr.models[ hModel ] );
} }
} }
@ -145,8 +146,8 @@ void RE_UnregisterServerModel( qhandle_t hModel ) {
return; return;
} }
if( tr.models[ hModel ].serveronly ) { if( tr.models[ hModel ]->serveronly ) {
R_FreeModel( &tr.models[ hModel ] ); R_FreeModel( tr.models[ hModel ] );
} }
} }
@ -174,7 +175,7 @@ static qhandle_t R_RegisterModelInternal( const char *name, qboolean bBeginTiki,
// search the currently loaded models // search the currently loaded models
// //
for( hModel = 1; hModel < tr.numModels; hModel++ ) { for( hModel = 1; hModel < tr.numModels; hModel++ ) {
mod = &tr.models[ hModel ]; mod = tr.models[ hModel ];
if( !strcmp( mod->name, name ) ) { if( !strcmp( mod->name, name ) ) {
if( mod->type == MOD_BAD ) { if( mod->type == MOD_BAD ) {
return 0; return 0;
@ -195,7 +196,6 @@ static qhandle_t R_RegisterModelInternal( const char *name, qboolean bBeginTiki,
// make sure the render thread is stopped // make sure the render thread is stopped
//R_SyncRenderThread();
R_IssuePendingRenderCommands(); R_IssuePendingRenderCommands();
mod->serveronly = qtrue; mod->serveronly = qtrue;
@ -272,8 +272,8 @@ qhandle_t RE_SpawnEffectModel( const char *szModel, vec3_t vPos, vec3_t *axis )
if( new_entity.hModel ) if( new_entity.hModel )
{ {
tr.models[ new_entity.hModel ].serveronly = qfalse; tr.models[ new_entity.hModel ]->serveronly = qfalse;
ri.CG_ProcessInitCommands( tr.models[ new_entity.hModel ].d.tiki, &new_entity ); ri.CG_ProcessInitCommands( tr.models[ new_entity.hModel ]->d.tiki, &new_entity );
} }
return new_entity.hModel; return new_entity.hModel;
@ -288,7 +288,7 @@ qhandle_t RE_RegisterModel( const char *name ) {
handle = R_RegisterModelInternal( name, qtrue, qtrue ); handle = R_RegisterModelInternal( name, qtrue, qtrue );
if( handle ) { if( handle ) {
tr.models[ handle ].serveronly = qfalse; tr.models[ handle ]->serveronly = qfalse;
} }
return handle; return handle;
} }
@ -323,7 +323,7 @@ void R_Modellist_f( void ) {
int i; int i;
for( i = 1; i < tr.numModels; i++ ) { for( i = 1; i < tr.numModels; i++ ) {
ri.Printf( PRINT_ALL, "%s\n", tr.models[ i ].name ); ri.Printf( PRINT_ALL, "%s\n", tr.models[ i ]->name );
} }
} }
@ -773,7 +773,6 @@ void R_AddSkelSurfaces( trRefEntity_t *ent ) {
int mesh; int mesh;
int iRadiusCull = 0; int iRadiusCull = 0;
int num_tags; int num_tags;
int cubemapIndex;
tiki = ent->e.tiki; tiki = ent->e.tiki;
@ -873,8 +872,6 @@ void R_AddSkelSurfaces( trRefEntity_t *ent ) {
R_SetupEntityLighting( &tr.refdef, ent ); R_SetupEntityLighting( &tr.refdef, ent );
} }
cubemapIndex = R_CubemapForPoint( ent->e.origin );
// //
// draw all meshes // draw all meshes
// //
@ -932,16 +929,16 @@ void R_AddSkelSurfaces( trRefEntity_t *ent ) {
if( ( *bsurf & 0x40 ) && ( dsurf->numskins > 1 ) ) { if( ( *bsurf & 0x40 ) && ( dsurf->numskins > 1 ) ) {
int iShaderNum = ent->e.skinNum + ( *bsurf & 2 ); int iShaderNum = ent->e.skinNum + ( *bsurf & 2 );
R_AddDrawSurf( ( surfaceType_t * )surface, tr.shaders[ dsurf->hShader[ iShaderNum ] ], 0, qfalse, qfalse, cubemapIndex ); R_AddDrawSurf( ( surfaceType_t * )surface, tr.shaders[ dsurf->hShader[ iShaderNum ] ], 0, 0, 0, 0 );
R_AddDrawSurf( ( surfaceType_t * )surface, tr.shaders[ dsurf->hShader[ iShaderNum + 1 ] ], 0, qfalse, qfalse, cubemapIndex ); R_AddDrawSurf( ( surfaceType_t * )surface, tr.shaders[ dsurf->hShader[ iShaderNum + 1 ] ], 0, 0, 0, 0);
} else { } else {
R_AddDrawSurf( ( surfaceType_t * )surface, shader, 0, qfalse, qtrue, cubemapIndex ); R_AddDrawSurf( ( surfaceType_t * )surface, shader, 0, 0, 0, 0);
} }
} }
if( ( ent->e.customShader ) && ( ent->e.renderfx & RF_CUSTOMSHADERPASS ) ) { if( ( ent->e.customShader ) && ( ent->e.renderfx & RF_CUSTOMSHADERPASS ) ) {
shader = R_GetShaderByHandle( ent->e.customShader ); shader = R_GetShaderByHandle( ent->e.customShader );
R_AddDrawSurf( ( surfaceType_t * )surface, shader, 0, qfalse, qfalse, cubemapIndex ); R_AddDrawSurf( ( surfaceType_t * )surface, shader, 0, 0, 0, 0);
} }
} }
} }
@ -1042,7 +1039,7 @@ LerpSkelMesh
*/ */
static void LerpSkelMesh( skelSurfaceGame_t *sf ) { static void LerpSkelMesh( skelSurfaceGame_t *sf ) {
float *outXyz; float *outXyz;
uint32_t *outNormal; int16_t *outNormal;
skeletorVertex_t *newVerts; skeletorVertex_t *newVerts;
skeletorMorph_t *morph; skeletorMorph_t *morph;
skelWeight_t *weight; skelWeight_t *weight;
@ -1065,7 +1062,7 @@ static void LerpSkelMesh( skelSurfaceGame_t *sf ) {
newVerts = sf->pVerts; newVerts = sf->pVerts;
outXyz = tess.xyz[ tess.numVertexes ]; outXyz = tess.xyz[ tess.numVertexes ];
outNormal = &tess.normal[ tess.numVertexes ]; outNormal = &tess.normal[ tess.numVertexes ][0];
bones = &TIKI_Skel_Bones[ backEnd.currentEntity->e.bonestart ]; bones = &TIKI_Skel_Bones[ backEnd.currentEntity->e.bonestart ];
morphs = &skeletorMorphCache[ backEnd.currentEntity->e.morphstart ]; morphs = &skeletorMorphCache[ backEnd.currentEntity->e.morphstart ];
@ -1224,7 +1221,7 @@ static void LerpSkelMesh( skelSurfaceGame_t *sf ) {
} }
} }
R_VaoPackNormal( ( byte * )outNormal, normal ); R_VaoPackNormal(outNormal, normal);
VectorScale( out, scale, outXyz ); VectorScale( out, scale, outXyz );
@ -1246,8 +1243,6 @@ void RB_SkelMesh( skelSurfaceGame_t *sf ) {
int numVerts; int numVerts;
int numIndexes; int numIndexes;
RB_CheckVao( tess.vao );
numIndexes = sf->numTriangles * 3; numIndexes = sf->numTriangles * 3;
RB_CHECKOVERFLOW( sf->numVerts, numIndexes ); RB_CHECKOVERFLOW( sf->numVerts, numIndexes );
@ -1264,8 +1259,8 @@ void RB_SkelMesh( skelSurfaceGame_t *sf ) {
numVerts = sf->numVerts; numVerts = sf->numVerts;
vert = sf->pVerts; vert = sf->pVerts;
for( j = 0; j < numVerts; j++ ) { for( j = 0; j < numVerts; j++ ) {
tess.texCoords[ baseVertex + j ][ 0 ][ 0 ] = vert->texCoords[ 0 ]; tess.texCoords[ baseVertex + j ][ 0 ] = vert->texCoords[ 0 ];
tess.texCoords[ baseVertex + j ][ 0 ][ 1 ] = vert->texCoords[ 1 ]; tess.texCoords[ baseVertex + j ][ 1 ] = vert->texCoords[ 1 ];
vert = ( skeletorVertex_t * )( ( byte * )vert + sizeof( skeletorVertex_t ) + sizeof( skeletorMorph_t ) * vert->numMorphs + sizeof( skelWeight_t ) * vert->numWeights ); vert = ( skeletorVertex_t * )( ( byte * )vert + sizeof( skeletorVertex_t ) + sizeof( skeletorMorph_t ) * vert->numMorphs + sizeof( skelWeight_t ) * vert->numWeights );
// FIXME: fill in lightmapST for completeness? // FIXME: fill in lightmapST for completeness?
} }
@ -1426,7 +1421,7 @@ void R_DebugSkeleton( void ) {
R_IssuePendingRenderCommands(); R_IssuePendingRenderCommands();
GL_Bind( tr.whiteImage ); GL_BindToTMU(tr.whiteImage, TB_COLORMAP);
GL_State( 0x200 ); GL_State( 0x200 );
glDisableClientState( GL_COLOR_ARRAY ); glDisableClientState( GL_COLOR_ARRAY );

View file

@ -82,7 +82,7 @@ void RB_ToneMap(FBO_t *hdrFbo, ivec4_t hdrBox, FBO_t *ldrFbo, ivec4_t ldrBox, in
// tonemap // tonemap
color[0] = color[0] =
color[1] = color[1] =
color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value); color[2] = pow(2, r_cameraExposure->value - autoExposure); //exp2(r_cameraExposure->value);
color[3] = 1.0f; color[3] = 1.0f;
if (autoExposure) if (autoExposure)
@ -183,7 +183,7 @@ void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float
FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, 0); FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, 0);
} }
FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0); FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, dst, dstBox, NULL, NULL, 0);
} }
#else // higher quality blur, but slower #else // higher quality blur, but slower
else if (blur > 1.0f) else if (blur > 1.0f)
@ -217,7 +217,7 @@ void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float
FBO_Blit(tr.quarterFbo[0], NULL, blurTexScale, tr.quarterFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); FBO_Blit(tr.quarterFbo[0], NULL, blurTexScale, tr.quarterFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
} }
FBO_Blit(tr.quarterFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0); FBO_Blit(tr.quarterFbo[1], NULL, NULL, dst, dstBox, NULL, NULL, 0);
} }
#endif #endif
} }
@ -227,54 +227,40 @@ void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float
static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretch, float x, float y, float w, float h, float xcenter, float ycenter, float alpha) static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretch, float x, float y, float w, float h, float xcenter, float ycenter, float alpha)
{ {
ivec4_t srcBox, dstBox; ivec4_t srcBox, dstBox;
int srcWidth, srcHeight;
vec4_t color; vec4_t color;
const float inc = 1.f / passes; const float inc = 1.f / passes;
const float mul = powf(stretch, inc); const float mul = powf(stretch, inc);
float scale; float scale;
alpha *= inc;
VectorSet4(color, alpha, alpha, alpha, 1.0f);
srcWidth = srcFbo ? srcFbo->width : glConfig.vidWidth;
srcHeight = srcFbo ? srcFbo->height : glConfig.vidHeight;
VectorSet4(srcBox, 0, 0, srcWidth, srcHeight);
VectorSet4(dstBox, x, y, w, h);
FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, 0);
--passes;
scale = mul;
while (passes > 0)
{ {
vec2_t texScale; float iscale = 1.f / scale;
float s0 = xcenter * (1.f - iscale);
float t0 = (1.0f - ycenter) * (1.f - iscale);
texScale[0] = srcBox[0] = s0 * srcWidth;
texScale[1] = 1.0f; srcBox[1] = t0 * srcHeight;
srcBox[2] = iscale * srcWidth;
alpha *= inc; srcBox[3] = iscale * srcHeight;
VectorSet4(color, alpha, alpha, alpha, 1.0f);
VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
VectorSet4(dstBox, x, y, w, h);
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0);
--passes;
scale = mul;
while (passes > 0)
{
float iscale = 1.f / scale;
float s0 = xcenter * (1.f - iscale);
float t0 = (1.0f - ycenter) * (1.f - iscale);
float s1 = iscale + s0;
float t1 = iscale + t0;
if (srcFbo)
{
srcBox[0] = s0 * srcFbo->width;
srcBox[1] = t0 * srcFbo->height;
srcBox[2] = (s1 - s0) * srcFbo->width;
srcBox[3] = (t1 - t0) * srcFbo->height;
}
else
{
srcBox[0] = s0 * glConfig.vidWidth;
srcBox[1] = t0 * glConfig.vidHeight;
srcBox[2] = (s1 - s0) * glConfig.vidWidth;
srcBox[3] = (t1 - t0) * glConfig.vidHeight;
}
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
scale *= mul; scale *= mul;
--passes; --passes;
}
} }
} }
@ -296,7 +282,7 @@ static qboolean RB_UpdateSunFlareVis(void)
for (iter=0 ; ; ++iter) for (iter=0 ; ; ++iter)
{ {
GLint available = 0; GLint available = 0;
qglGetQueryObjectivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_AVAILABLE_ARB, &available); qglGetQueryObjectiv(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_AVAILABLE, &available);
if (available) if (available)
break; break;
} }
@ -304,7 +290,7 @@ static qboolean RB_UpdateSunFlareVis(void)
ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter); ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter);
} }
qglGetQueryObjectuivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_ARB, &sampleCount); qglGetQueryObjectuiv(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT, &sampleCount);
return sampleCount > 0; return sampleCount > 0;
} }
@ -329,7 +315,7 @@ void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox)
// From RB_DrawSun() // From RB_DrawSun()
{ {
float dist; float dist;
mat4_t trans, model, mvp; mat4_t trans, model;
Mat4Translation( backEnd.viewParms.or.origin, trans ); Mat4Translation( backEnd.viewParms.or.origin, trans );
Mat4Multiply( backEnd.viewParms.world.modelMatrix, trans, model ); Mat4Multiply( backEnd.viewParms.world.modelMatrix, trans, model );
@ -353,28 +339,16 @@ void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox)
// initialize quarter buffers // initialize quarter buffers
{ {
float mul = 1.f; float mul = 1.f;
vec2_t texScale;
ivec4_t rayBox, quarterBox; ivec4_t rayBox, quarterBox;
int srcWidth = srcFbo ? srcFbo->width : glConfig.vidWidth;
texScale[0] = int srcHeight = srcFbo ? srcFbo->height : glConfig.vidHeight;
texScale[1] = 1.0f;
VectorSet4(color, mul, mul, mul, 1); VectorSet4(color, mul, mul, mul, 1);
if (srcFbo) rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / srcWidth;
{ rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / srcHeight;
rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / srcFbo->width; rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / srcWidth;
rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / srcFbo->height; rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / srcHeight;
rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / srcFbo->width;
rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / srcFbo->height;
}
else
{
rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / glConfig.vidWidth;
rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / glConfig.vidHeight;
rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / glConfig.vidWidth;
rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / glConfig.vidHeight;
}
quarterBox[0] = 0; quarterBox[0] = 0;
quarterBox[1] = tr.quarterFbo[0]->height; quarterBox[1] = tr.quarterFbo[0]->height;
@ -408,14 +382,10 @@ void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox)
// add result back on top of the main buffer // add result back on top of the main buffer
{ {
float mul = 1.f; float mul = 1.f;
vec2_t texScale;
texScale[0] =
texScale[1] = 1.0f;
VectorSet4(color, mul, mul, mul, 1); VectorSet4(color, mul, mul, mul, 1);
FBO_Blit(tr.quarterFbo[0], NULL, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); FBO_Blit(tr.quarterFbo[0], NULL, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
} }
} }
@ -443,31 +413,27 @@ static void RB_BlurAxis(FBO_t *srcFbo, FBO_t *dstFbo, float strength, qboolean h
{ {
ivec4_t srcBox, dstBox; ivec4_t srcBox, dstBox;
vec4_t color; vec4_t color;
vec2_t texScale;
texScale[0] =
texScale[1] = 1.0f;
VectorSet4(color, weights[0], weights[0], weights[0], 1.0f); VectorSet4(color, weights[0], weights[0], weights[0], 1.0f);
VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height); VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
VectorSet4(dstBox, 0, 0, dstFbo->width, dstFbo->height); VectorSet4(dstBox, 0, 0, dstFbo->width, dstFbo->height);
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0 ); FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, 0);
VectorSet4(color, weights[1], weights[1], weights[1], 1.0f); VectorSet4(color, weights[1], weights[1], weights[1], 1.0f);
dx = offsets[1] * xmul; dx = offsets[1] * xmul;
dy = offsets[1] * ymul; dy = offsets[1] * ymul;
VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height); VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height);
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height); VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height);
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
VectorSet4(color, weights[2], weights[2], weights[2], 1.0f); VectorSet4(color, weights[2], weights[2], weights[2], 1.0f);
dx = offsets[2] * xmul; dx = offsets[2] * xmul;
dy = offsets[2] * ymul; dy = offsets[2] * ymul;
VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height); VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height);
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height); VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height);
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
} }
} }
@ -492,10 +458,6 @@ void RB_GaussianBlur(float blur)
{ {
ivec4_t srcBox, dstBox; ivec4_t srcBox, dstBox;
vec4_t color; vec4_t color;
vec2_t texScale;
texScale[0] =
texScale[1] = 1.0f;
VectorSet4(color, 1, 1, 1, 1); VectorSet4(color, 1, 1, 1, 1);
@ -504,10 +466,8 @@ void RB_GaussianBlur(float blur)
FBO_FastBlit(tr.quarterFbo[0], NULL, tr.textureScratchFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); FBO_FastBlit(tr.quarterFbo[0], NULL, tr.textureScratchFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR);
// set the alpha channel // set the alpha channel
VectorSet4(srcBox, 0, 0, tr.whiteImage->width, tr.whiteImage->height);
VectorSet4(dstBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
FBO_BlitFromTexture(tr.whiteImage, srcBox, texScale, tr.textureScratchFbo[0], dstBox, &tr.textureColorShader, color, GLS_DEPTHTEST_DISABLE); FBO_BlitFromTexture(tr.whiteImage, NULL, NULL, tr.textureScratchFbo[0], NULL, NULL, color, GLS_DEPTHTEST_DISABLE);
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// blur the tiny buffer horizontally and vertically // blur the tiny buffer horizontally and vertically
@ -518,6 +478,6 @@ void RB_GaussianBlur(float blur)
VectorSet4(srcBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height); VectorSet4(srcBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
VectorSet4(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight); VectorSet4(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
color[3] = factor; color[3] = factor;
FBO_Blit(tr.textureScratchFbo[0], srcBox, texScale, NULL, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); FBO_Blit(tr.textureScratchFbo[0], srcBox, NULL, NULL, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -30,9 +30,6 @@ int r_firstSceneDlight;
int r_numentities; int r_numentities;
int r_firstSceneEntity; int r_firstSceneEntity;
int r_numsprites;
int r_firstSceneSprite;
int r_numpolys; int r_numpolys;
int r_firstScenePoly; int r_firstScenePoly;
@ -56,9 +53,6 @@ void R_InitNextFrame( void ) {
r_numentities = 0; r_numentities = 0;
r_firstSceneEntity = 0; r_firstSceneEntity = 0;
r_numsprites = 0;
r_firstSceneSprite = 0;
r_numpolys = 0; r_numpolys = 0;
r_firstScenePoly = 0; r_firstScenePoly = 0;
@ -75,7 +69,6 @@ RE_ClearScene
void RE_ClearScene( void ) { void RE_ClearScene( void ) {
r_firstSceneDlight = r_numdlights; r_firstSceneDlight = r_numdlights;
r_firstSceneEntity = r_numentities; r_firstSceneEntity = r_numentities;
r_firstSceneSprite = r_numsprites;
r_firstScenePoly = r_numpolys; r_firstScenePoly = r_numpolys;
} }
@ -116,15 +109,15 @@ RE_AddPolyToScene
===================== =====================
*/ */
qboolean RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int renderfx ) { void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) {
srfPoly_t *poly; srfPoly_t *poly;
int i; int i, j;
int fogIndex; int fogIndex;
fog_t *fog; fog_t *fog;
vec3_t bounds[2]; vec3_t bounds[2];
if ( !tr.registered ) { if ( !tr.registered ) {
return qfalse; return;
} }
if ( !hShader ) { if ( !hShader ) {
@ -134,106 +127,72 @@ qboolean RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *v
//return; //return;
} }
if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) { for ( j = 0; j < numPolys; j++ ) {
/* if ( r_numpolyverts + numVerts > max_polyverts || r_numpolys >= max_polys ) {
NOTE TTimo this was initially a PRINT_WARNING /*
but it happens a lot with high fighting scenes and particles NOTE TTimo this was initially a PRINT_WARNING
since we don't plan on changing the const and making for room for those effects but it happens a lot with high fighting scenes and particles
simply cut this message to developer only since we don't plan on changing the const and making for room for those effects
*/ simply cut this message to developer only
ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n"); */
return qfalse; ri.Printf( PRINT_DEVELOPER, "WARNING: RE_AddPolyToScene: r_max_polys or r_max_polyverts reached\n");
} return;
poly = &backEndData->polys[r_numpolys];
poly->surfaceType = SF_POLY;
poly->hShader = hShader;
poly->numVerts = numVerts;
poly->verts = &backEndData->polyVerts[r_numpolyverts];
poly->renderfx = renderfx;
Com_Memcpy( poly->verts, verts, numVerts * sizeof( *verts ) );
if ( glConfig.hardwareType == GLHW_RAGEPRO ) {
poly->verts->modulate[0] = 255;
poly->verts->modulate[1] = 255;
poly->verts->modulate[2] = 255;
poly->verts->modulate[3] = 255;
}
// done.
r_numpolys++;
r_numpolyverts += numVerts;
// if no world is loaded
if ( tr.world == NULL ) {
fogIndex = 0;
}
// see if it is in a fog volume
else if ( tr.world->numfogs == 1 ) {
fogIndex = 0;
} else {
// find which fog volume the poly is in
VectorCopy( poly->verts[0].xyz, bounds[0] );
VectorCopy( poly->verts[0].xyz, bounds[1] );
for ( i = 1 ; i < poly->numVerts ; i++ ) {
AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
} }
for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
fog = &tr.world->fogs[fogIndex]; poly = &backEndData->polys[r_numpolys];
if ( bounds[1][0] >= fog->bounds[0][0] poly->surfaceType = SF_POLY;
&& bounds[1][1] >= fog->bounds[0][1] poly->hShader = hShader;
&& bounds[1][2] >= fog->bounds[0][2] poly->numVerts = numVerts;
&& bounds[0][0] <= fog->bounds[1][0] poly->verts = &backEndData->polyVerts[r_numpolyverts];
&& bounds[0][1] <= fog->bounds[1][1]
&& bounds[0][2] <= fog->bounds[1][2] ) { Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) );
break;
} if ( glConfig.hardwareType == GLHW_RAGEPRO ) {
poly->verts->modulate[0] = 255;
poly->verts->modulate[1] = 255;
poly->verts->modulate[2] = 255;
poly->verts->modulate[3] = 255;
} }
if ( fogIndex == tr.world->numfogs ) { // done.
r_numpolys++;
r_numpolyverts += numVerts;
// if no world is loaded
if ( tr.world == NULL ) {
fogIndex = 0; fogIndex = 0;
} }
// see if it is in a fog volume
else if ( tr.world->numfogs == 1 ) {
fogIndex = 0;
} else {
// find which fog volume the poly is in
VectorCopy( poly->verts[0].xyz, bounds[0] );
VectorCopy( poly->verts[0].xyz, bounds[1] );
for ( i = 1 ; i < poly->numVerts ; i++ ) {
AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
}
for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
fog = &tr.world->fogs[fogIndex];
if ( bounds[1][0] >= fog->bounds[0][0]
&& bounds[1][1] >= fog->bounds[0][1]
&& bounds[1][2] >= fog->bounds[0][2]
&& bounds[0][0] <= fog->bounds[1][0]
&& bounds[0][1] <= fog->bounds[1][1]
&& bounds[0][2] <= fog->bounds[1][2] ) {
break;
}
}
if ( fogIndex == tr.world->numfogs ) {
fogIndex = 0;
}
}
poly->fogIndex = fogIndex;
} }
poly->fogIndex = fogIndex;
return qtrue;
} }
/*
=====================
R_AddTerrainMarkSurfaces
=====================
*/
void R_AddTerrainMarkSurfaces( void ) {
// FIXME: stub
}
/*
=====================
RE_AddTerrainMarkToScene
=====================
*/
void RE_AddTerrainMarkToScene( int iTerrainIndex, qhandle_t hShader, int numVerts, polyVert_t *verts, int renderfx ) {
// FIXME: stub
}
//================================================================================= //=================================================================================
/*
=====================
RE_GetRenderEntity
=====================
*/
refEntity_t *RE_GetRenderEntity( int entityNumber ) {
int i;
for( i = 0; i < r_numentities; i++ ) {
if( backEndData->entities[ i ].e.entityNumber == entityNumber ) {
return &backEndData->entities[ i ].e;
}
}
return NULL;
}
/* /*
===================== =====================
@ -241,9 +200,8 @@ RE_AddRefEntityToScene
===================== =====================
*/ */
void RE_AddRefEntityToScene( const refEntity_t *ent, int parentEntityNumber ) { void RE_AddRefEntityToScene( const refEntity_t *ent ) {
vec3_t cross; vec3_t cross;
int i;
if ( !tr.registered ) { if ( !tr.registered ) {
return; return;
@ -264,18 +222,7 @@ void RE_AddRefEntityToScene( const refEntity_t *ent, int parentEntityNumber ) {
ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType ); ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
} }
backEndData->entities[ r_numentities ].e = *ent; backEndData->entities[r_numentities].e = *ent;
backEndData->entities[ r_numentities ].e.parentEntity = ENTITYNUM_NONE;
if( parentEntityNumber != ENTITYNUM_NONE ) {
for( i = r_firstSceneEntity; i < r_numentities; i++ ) {
if( backEndData->entities[ i ].e.entityNumber == parentEntityNumber ) {
backEndData->entities[ r_numentities ].e.parentEntity = parentEntityNumber;
break;
}
}
}
backEndData->entities[r_numentities].lightingCalculated = qfalse; backEndData->entities[r_numentities].lightingCalculated = qfalse;
CrossProduct(ent->axis[0], ent->axis[1], cross); CrossProduct(ent->axis[0], ent->axis[1], cross);
@ -284,48 +231,6 @@ void RE_AddRefEntityToScene( const refEntity_t *ent, int parentEntityNumber ) {
r_numentities++; r_numentities++;
} }
/*
=====================
RE_AddRefEntityToScene
=====================
*/
void RE_AddRefSpriteToScene( const refEntity_t *ent ) {
refSprite_t *spr;
int i;
if ( !tr.registered ) {
return;
}
if ( r_numsprites >= MAX_REFSPRITES ) {
ri.Printf(PRINT_DEVELOPER, "RE_AddRefSpriteToScene: Dropping refSprite, reached MAX_REFSPRITES\n");
return;
}
if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) {
static qboolean firstTime = qtrue;
if (firstTime) {
firstTime = qfalse;
ri.Printf( PRINT_WARNING, "RE_AddRefSpriteToScene passed a refEntity which has an origin with a NaN component\n");
}
return;
}
spr = &backEndData->sprites[ r_numsprites ];
VectorCopy( ent->origin, spr->origin );
spr->surftype = SF_SPRITE;
spr->hModel = ent->hModel;
spr->scale = ent->scale;
spr->renderfx = ent->renderfx;
spr->shaderTime = ent->shaderTime;
AxisCopy( ent->axis, spr->axis );
for( i = 0; i < 4; i++ ) {
spr->shaderRGBA[ i ] = ent->shaderRGBA[ i ];
}
r_numsprites++;
}
/* /*
===================== =====================
@ -364,7 +269,7 @@ RE_AddLightToScene
===================== =====================
*/ */
void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b, int type ) { void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) {
RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse ); RE_AddDynamicLightToScene( org, intensity, r, g, b, qfalse );
} }
@ -381,8 +286,6 @@ void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, flo
void RE_BeginScene(const refdef_t *fd) void RE_BeginScene(const refdef_t *fd)
{ {
//Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
tr.refdef.x = fd->x; tr.refdef.x = fd->x;
tr.refdef.y = fd->y; tr.refdef.y = fd->y;
tr.refdef.width = fd->width; tr.refdef.width = fd->width;
@ -424,37 +327,30 @@ void RE_BeginScene(const refdef_t *fd)
VectorCopy(tr.sunDirection, tr.refdef.sunDir); VectorCopy(tr.sunDirection, tr.refdef.sunDir);
if ( (tr.refdef.rdflags & RDF_NOWORLDMODEL) || !(r_depthPrepass->value) ){ if ( (tr.refdef.rdflags & RDF_NOWORLDMODEL) || !(r_depthPrepass->value) ){
tr.refdef.colorScale = 1.0f;
VectorSet(tr.refdef.sunCol, 0, 0, 0); VectorSet(tr.refdef.sunCol, 0, 0, 0);
VectorSet(tr.refdef.sunAmbCol, 0, 0, 0); VectorSet(tr.refdef.sunAmbCol, 0, 0, 0);
} }
else else
{ {
tr.refdef.colorScale = r_forceSun->integer ? r_forceSunMapLightScale->value : tr.mapLightScale; float scale = (1 << r_mapOverBrightBits->integer) / 255.0f;
if (r_forceSun->integer)
VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol);
else
VectorScale(tr.sunLight, scale, tr.refdef.sunCol);
if (r_sunlightMode->integer == 1) if (r_sunlightMode->integer == 1)
{ {
tr.refdef.sunCol[0] =
tr.refdef.sunCol[1] =
tr.refdef.sunCol[2] = 1.0f;
tr.refdef.sunAmbCol[0] = tr.refdef.sunAmbCol[0] =
tr.refdef.sunAmbCol[1] = tr.refdef.sunAmbCol[1] =
tr.refdef.sunAmbCol[2] = r_forceSun->integer ? r_forceSunAmbientScale->value : tr.sunShadowScale; tr.refdef.sunAmbCol[2] = r_forceSun->integer ? r_forceSunAmbientScale->value : tr.sunShadowScale;
} }
else else
{ {
float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8);
if (r_forceSun->integer) if (r_forceSun->integer)
{
VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol);
VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol); VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol);
}
else else
{
VectorScale(tr.sunLight, scale, tr.refdef.sunCol);
VectorScale(tr.sunLight, scale * tr.sunShadowScale, tr.refdef.sunAmbCol); VectorScale(tr.sunLight, scale * tr.sunShadowScale, tr.refdef.sunAmbCol);
}
} }
} }
@ -502,7 +398,7 @@ void RE_BeginScene(const refdef_t *fd)
// derived info // derived info
tr.refdef.floatTime = tr.refdef.time * 0.001f; tr.refdef.floatTime = tr.refdef.time * 0.001;
tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
tr.refdef.drawSurfs = backEndData->drawSurfs; tr.refdef.drawSurfs = backEndData->drawSurfs;
@ -510,9 +406,6 @@ void RE_BeginScene(const refdef_t *fd)
tr.refdef.num_entities = r_numentities - r_firstSceneEntity; tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
tr.refdef.entities = &backEndData->entities[r_firstSceneEntity]; tr.refdef.entities = &backEndData->entities[r_firstSceneEntity];
tr.refdef.num_sprites = r_numsprites - r_firstSceneSprite;
tr.refdef.sprites = &backEndData->sprites[r_firstSceneSprite];
tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight]; tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight];
@ -522,9 +415,6 @@ void RE_BeginScene(const refdef_t *fd)
tr.refdef.num_pshadows = 0; tr.refdef.num_pshadows = 0;
tr.refdef.pshadows = &backEndData->pshadows[0]; tr.refdef.pshadows = &backEndData->pshadows[0];
backEndData->staticModels = tr.refdef.staticModels;
backEndData->staticModelData = tr.refdef.staticModelData;
// turn off dynamic lighting globally by clearing all the // turn off dynamic lighting globally by clearing all the
// dlights if it needs to be disabled or if vertex lighting is enabled // dlights if it needs to be disabled or if vertex lighting is enabled
if ( r_dynamiclight->integer == 0 || if ( r_dynamiclight->integer == 0 ||
@ -543,12 +433,11 @@ void RE_BeginScene(const refdef_t *fd)
} }
void RE_EndScene() void RE_EndScene(void)
{ {
// the next scene rendered in this frame will tack on after this one // the next scene rendered in this frame will tack on after this one
r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
r_firstSceneEntity = r_numentities; r_firstSceneEntity = r_numentities;
r_firstSceneSprite = r_numsprites;
r_firstSceneDlight = r_numdlights; r_firstSceneDlight = r_numdlights;
r_firstScenePoly = r_numpolys; r_firstScenePoly = r_numpolys;
} }
@ -583,9 +472,6 @@ void RE_RenderScene( const refdef_t *fd ) {
ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
} }
//R_VisDebug();
TIKI_Reset_Caches();
RE_BeginScene(fd); RE_BeginScene(fd);
// SmileTheory: playing with shadow mapping // SmileTheory: playing with shadow mapping
@ -603,7 +489,7 @@ void RE_RenderScene( const refdef_t *fd ) {
// playing with even more shadows // playing with even more shadows
if(glRefConfig.framebufferObject && r_sunlightMode->integer && !( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows)) if(glRefConfig.framebufferObject && r_sunlightMode->integer && !( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows))
{ {
if (r_shadowCascadeZFar != 0) if (r_shadowCascadeZFar->integer != 0)
{ {
R_RenderSunShadowMaps(fd, 0); R_RenderSunShadowMaps(fd, 0);
R_RenderSunShadowMaps(fd, 1); R_RenderSunShadowMaps(fd, 1);

View file

@ -22,9 +22,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// tr_shade.c // tr_shade.c
#include "tr_local.h" #include "tr_local.h"
#if idppc_altivec && !defined(MACOS_X)
#include <altivec.h>
#endif
/* /*
@ -41,42 +38,9 @@ R_DrawElements
================== ==================
*/ */
void R_DrawElementsVao( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ) void R_DrawElements( int numIndexes, int firstIndex )
{ {
if (glRefConfig.drawRangeElements) qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t)));
qglDrawRangeElementsEXT(GL_TRIANGLES, minIndex, maxIndex, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t)));
else
qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t)));
}
static void R_DrawMultiElementsVao( int multiDrawPrimitives, glIndex_t *multiDrawMinIndex, glIndex_t *multiDrawMaxIndex,
GLsizei *multiDrawNumIndexes, glIndex_t **multiDrawFirstIndex)
{
if (glRefConfig.multiDrawArrays && multiDrawPrimitives > 1)
{
qglMultiDrawElementsEXT(GL_TRIANGLES, multiDrawNumIndexes, GL_INDEX_TYPE, (const GLvoid **)multiDrawFirstIndex, multiDrawPrimitives);
}
else
{
int i;
if (glRefConfig.drawRangeElements)
{
for (i = 0; i < multiDrawPrimitives; i++)
{
qglDrawRangeElementsEXT(GL_TRIANGLES, multiDrawMinIndex[i], multiDrawMaxIndex[i], multiDrawNumIndexes[i], GL_INDEX_TYPE, multiDrawFirstIndex[i]);
}
}
else
{
for (i = 0; i < multiDrawPrimitives; i++)
{
qglDrawElements(GL_TRIANGLES, multiDrawNumIndexes[i], GL_INDEX_TYPE, multiDrawFirstIndex[i]);
}
}
}
} }
@ -98,16 +62,7 @@ R_BindAnimatedImageToTMU
================= =================
*/ */
static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) { static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) {
int index; int64_t index;
if ( bundle->isVideoMap ) {
int oldtmu = glState.currenttmu;
GL_SelectTexture(tmu);
ri.CIN_RunCinematic(bundle->videoMapHandle);
ri.CIN_UploadCinematic(bundle->videoMapHandle);
GL_SelectTexture(oldtmu);
return;
}
if ( bundle->numImageAnimations <= 1 ) { if ( bundle->numImageAnimations <= 1 ) {
GL_BindToTMU( bundle->image[0], tmu); GL_BindToTMU( bundle->image[0], tmu);
@ -116,13 +71,18 @@ static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) {
// it is necessary to do this messy calc to make sure animations line up // it is necessary to do this messy calc to make sure animations line up
// exactly with waveforms of the same frequency // exactly with waveforms of the same frequency
index = ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE); index = tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE;
index >>= FUNCTABLE_SIZE2; index >>= FUNCTABLE_SIZE2;
if ( index < 0 ) { if ( index < 0 ) {
index = 0; // may happen with shader time offsets index = 0; // may happen with shader time offsets
} }
index %= bundle->numImageAnimations;
// Windows x86 doesn't load renderer DLL with 64 bit modulus
//index %= bundle->numImageAnimations;
while ( index >= bundle->numImageAnimations ) {
index -= bundle->numImageAnimations;
}
GL_BindToTMU( bundle->image[ index ], tmu ); GL_BindToTMU( bundle->image[ index ], tmu );
} }
@ -136,7 +96,7 @@ Draws triangle outlines for debugging
================ ================
*/ */
static void DrawTris (shaderCommands_t *input) { static void DrawTris (shaderCommands_t *input) {
GL_Bind( tr.whiteImage ); GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
qglDepthRange( 0, 0 ); qglDepthRange( 0, 0 );
@ -150,15 +110,9 @@ static void DrawTris (shaderCommands_t *input) {
GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
VectorSet4(color, 1, 1, 1, 1); VectorSet4(color, 1, 1, 1, 1);
GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color); GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color);
GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
if (input->multiDrawPrimitives) R_DrawElements(input->numIndexes, input->firstIndex);
{
R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
}
} }
qglDepthRange( 0, 1 ); qglDepthRange( 0, 1 );
@ -192,17 +146,16 @@ void RB_BeginSurface( shader_t *shader, int fogNum, int cubemapIndex ) {
tess.numIndexes = 0; tess.numIndexes = 0;
tess.firstIndex = 0; tess.firstIndex = 0;
tess.numVertexes = 0; tess.numVertexes = 0;
tess.multiDrawPrimitives = 0;
tess.shader = state; tess.shader = state;
tess.fogNum = fogNum; tess.fogNum = fogNum;
tess.cubemapIndex = cubemapIndex; tess.cubemapIndex = cubemapIndex;
tess.dlightBits = 0; // will be OR'd in by surface functions tess.dlightBits = 0; // will be OR'd in by surface functions
tess.vertexColorValid = r_vertexLight->integer != 0;
tess.pshadowBits = 0; // will be OR'd in by surface functions tess.pshadowBits = 0; // will be OR'd in by surface functions
tess.xstages = state->stages; tess.xstages = state->stages;
tess.numPasses = state->numUnfoggedPasses; tess.numPasses = state->numUnfoggedPasses;
tess.currentStageIteratorFunc = state->optimalStageIteratorFunc; tess.currentStageIteratorFunc = state->optimalStageIteratorFunc;
tess.useInternalVao = qtrue; tess.useInternalVao = qtrue;
tess.useCacheVao = qfalse;
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) { if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) {
@ -378,7 +331,7 @@ static void ProjectDlightTexture( void ) {
vec4_t vector; vec4_t vector;
if ( !( tess.dlightBits & ( 1 << l ) ) ) { if ( !( tess.dlightBits & ( 1 << l ) ) ) {
continue; // this surface definately doesn't have any of this light continue; // this surface definitely doesn't have any of this light
} }
dl = &backEnd.refdef.dlights[l]; dl = &backEnd.refdef.dlights[l];
@ -415,7 +368,7 @@ static void ProjectDlightTexture( void ) {
vector[3] = scale; vector[3] = scale;
GLSL_SetUniformVec4(sp, UNIFORM_DLIGHTINFO, vector); GLSL_SetUniformVec4(sp, UNIFORM_DLIGHTINFO, vector);
GL_Bind( tr.dlightImage ); GL_BindToTMU( tr.dlightImage, TB_COLORMAP );
// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
// where they aren't rendered // where they aren't rendered
@ -426,15 +379,9 @@ static void ProjectDlightTexture( void ) {
GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
} }
if (tess.multiDrawPrimitives) GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 1);
{
shaderCommands_t *input = &tess; R_DrawElements(tess.numIndexes, tess.firstIndex);
R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVao(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex);
}
backEnd.pc.c_totalIndexes += tess.numIndexes; backEnd.pc.c_totalIndexes += tess.numIndexes;
backEnd.pc.c_dlightIndexes += tess.numIndexes; backEnd.pc.c_dlightIndexes += tess.numIndexes;
@ -445,6 +392,17 @@ static void ProjectDlightTexture( void ) {
static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t vertColor, int blend ) static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t vertColor, int blend )
{ {
qboolean isBlend = ((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_DST_COLOR)
|| ((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_ONE_MINUS_DST_COLOR)
|| ((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_SRC_COLOR)
|| ((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR);
qboolean is2DDraw = backEnd.currentEntity == &backEnd.entity2D;
float overbright = (isBlend || is2DDraw) ? 1.0f : (float)(1 << tr.overbrightBits);
fog_t *fog;
baseColor[0] = baseColor[0] =
baseColor[1] = baseColor[1] =
baseColor[2] = baseColor[2] =
@ -455,31 +413,11 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t
vertColor[2] = vertColor[2] =
vertColor[3] = 0.0f; vertColor[3] = 0.0f;
if( tess.vertexColorValid ) {
vec4_t *in = ( vec4_t * )&tess.vertexColors;
color4ub_t *out = tess.svars.colors;
int i;
for( i = 0; i < tess.numVertexes; i++, in++, out++ )
{
( *out )[ 0 ] = ( byte )( *in )[ i ] * 255;
( *out )[ 1 ] = ( byte )( *in )[ i + 1 ] * 255;
( *out )[ 2 ] = ( byte )( *in )[ i + 2 ] * 255;
( *out )[ 3 ] = ( byte )( *in )[ i + 3 ] * 255;
}
return;
}
// //
// rgbGen // rgbGen
// //
switch ( pStage->rgbGen ) switch ( pStage->rgbGen )
{ {
case CGEN_IDENTITY_LIGHTING:
baseColor[0] =
baseColor[1] =
baseColor[2] = tr.identityLight;
break;
case CGEN_EXACT_VERTEX: case CGEN_EXACT_VERTEX:
case CGEN_EXACT_VERTEX_LIT: case CGEN_EXACT_VERTEX_LIT:
baseColor[0] = baseColor[0] =
@ -489,86 +427,49 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t
vertColor[0] = vertColor[0] =
vertColor[1] = vertColor[1] =
vertColor[2] = vertColor[2] = overbright;
vertColor[3] = 1.0f; vertColor[3] = 1.0f;
break; break;
case CGEN_LIGHTING_GRID:
baseColor[ 0 ] =
baseColor[ 1 ] =
baseColor[ 2 ] = RB_CalcLightGridColor();
break;
case CGEN_STATIC:
// FIXME: set light
break;
case CGEN_CONST: case CGEN_CONST:
baseColor[0] = pStage->constantColor[0] / 255.0f; baseColor[0] = pStage->constantColor[0] / 255.0f;
baseColor[1] = pStage->constantColor[1] / 255.0f; baseColor[1] = pStage->constantColor[1] / 255.0f;
baseColor[2] = pStage->constantColor[2] / 255.0f; baseColor[2] = pStage->constantColor[2] / 255.0f;
baseColor[3] = pStage->constantColor[3] / 255.0f; baseColor[3] = pStage->constantColor[3] / 255.0f;
break; break;
case CGEN_GLOBAL_COLOR:
baseColor[0] = backEnd.color2D[0];
baseColor[1] = backEnd.color2D[1];
baseColor[2] = backEnd.color2D[2];
baseColor[3] = backEnd.color2D[3];
break;
case CGEN_VERTEX: case CGEN_VERTEX:
baseColor[0] = case CGEN_VERTEX_LIT:
baseColor[0] =
baseColor[1] = baseColor[1] =
baseColor[2] = baseColor[2] =
baseColor[3] = 0.0f; baseColor[3] = 0.0f;
vertColor[0] = vertColor[0] =
vertColor[1] = vertColor[1] =
vertColor[2] = tr.identityLight; vertColor[2] =
vertColor[3] = 1.0f; vertColor[3] = 1.0f;
break; break;
case CGEN_VERTEX_LIT:
baseColor[0] =
baseColor[1] =
baseColor[2] =
baseColor[3] = 0.0f;
vertColor[0] =
vertColor[1] =
vertColor[2] =
vertColor[3] = tr.identityLight;
break;
case CGEN_ONE_MINUS_VERTEX: case CGEN_ONE_MINUS_VERTEX:
baseColor[0] = baseColor[0] =
baseColor[1] = baseColor[1] =
baseColor[2] = tr.identityLight; baseColor[2] = 1.0f;
vertColor[0] = vertColor[0] =
vertColor[1] = vertColor[1] =
vertColor[2] = -tr.identityLight; vertColor[2] = -1.0f;
break; break;
case CGEN_FOG: case CGEN_FOG:
{ fog = tr.world->fogs + tess.fogNum;
fog_t *fog;
fog = tr.world->fogs + tess.fogNum; baseColor[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f;
baseColor[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f;
baseColor[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f; baseColor[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f;
baseColor[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f; baseColor[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f;
baseColor[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f;
baseColor[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f;
}
break; break;
case CGEN_WAVEFORM: case CGEN_WAVEFORM:
baseColor[0] = baseColor[0] =
baseColor[1] = baseColor[1] =
baseColor[2] = RB_CalcWaveColorSingle( &pStage->rgbWave ); baseColor[2] = RB_CalcWaveColorSingle( &pStage->rgbWave );
break; break;
case CGEN_MULTIPLY_BY_WAVEFORM:
{
float color = RB_CalcWaveColorSingle( &pStage->rgbWave );
baseColor[ 0 ] = color * ( pStage->colorConst[ 0 ] / 255.0 );
baseColor[ 1 ] = color * ( pStage->colorConst[ 1 ] / 255.0 );
baseColor[ 2 ] = color * ( pStage->colorConst[ 2 ] / 255.0 );
}
break;
case CGEN_ENTITY: case CGEN_ENTITY:
if (backEnd.currentEntity) if (backEnd.currentEntity)
{ {
@ -587,29 +488,13 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t
baseColor[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f; baseColor[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f;
} }
break; break;
case CGEN_SCOORD:
baseColor[ 0 ] =
baseColor[ 1 ] =
baseColor[ 2 ] = RB_CalcRGBFromTexCoords( pStage->alphaMin, pStage->alphaMax, pStage->alphaConstMin, pStage->alphaConst, 0.0, 1.0, ( float * ) tess.svars.texcoords );
break;
case CGEN_TCOORD:
baseColor[ 0 ] =
baseColor[ 1 ] =
baseColor[ 2 ] = RB_CalcRGBFromTexCoords( pStage->alphaMin, pStage->alphaMax, pStage->alphaConstMin, pStage->alphaConst, 1.0, 0.0, ( float * )tess.svars.texcoords );
break;
case CGEN_DOT:
baseColor[ 0 ] =
baseColor[ 1 ] =
baseColor[ 2 ] = RB_CalcRGBFromDot( pStage->alphaMin, pStage->alphaMax );
break;
case CGEN_ONE_MINUS_DOT:
baseColor[ 0 ] =
baseColor[ 1 ] =
baseColor[ 2 ] = RB_CalcRGBFromOneMinusDot( pStage->alphaMin, pStage->alphaMax );
break;
case CGEN_IDENTITY: case CGEN_IDENTITY:
case CGEN_LIGHTING_SPHERICAL:
case CGEN_LIGHTING_DIFFUSE: case CGEN_LIGHTING_DIFFUSE:
baseColor[0] =
baseColor[1] =
baseColor[2] = overbright;
break;
case CGEN_IDENTITY_LIGHTING:
case CGEN_BAD: case CGEN_BAD:
break; break;
} }
@ -625,10 +510,6 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t
baseColor[3] = pStage->constantColor[3] / 255.0f; baseColor[3] = pStage->constantColor[3] / 255.0f;
vertColor[3] = 0.0f; vertColor[3] = 0.0f;
break; break;
case AGEN_GLOBAL_ALPHA:
baseColor[3] = backEnd.color2D[3];
vertColor[3] = 0.0f;
break;
case AGEN_WAVEFORM: case AGEN_WAVEFORM:
baseColor[3] = RB_CalcWaveAlphaSingle( &pStage->alphaWave ); baseColor[3] = RB_CalcWaveAlphaSingle( &pStage->alphaWave );
vertColor[3] = 0.0f; vertColor[3] = 0.0f;
@ -655,36 +536,6 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t
baseColor[3] = 1.0f; baseColor[3] = 1.0f;
vertColor[3] = -1.0f; vertColor[3] = -1.0f;
break; break;
case AGEN_DOT:
baseColor[ 3 ] = RB_CalcAlphaFromDot( pStage->alphaMin, pStage->alphaMax );
break;
case AGEN_DOT_VIEW:
baseColor[ 3 ] = RB_CalcAlphaFromDotView( pStage->alphaMin, pStage->alphaMax );
break;
case AGEN_ONE_MINUS_DOT:
baseColor[ 3 ] = RB_CalcAlphaFromOneMinusDot( pStage->alphaMin, pStage->alphaMax );
break;
case AGEN_ONE_MINUS_DOT_VIEW:
baseColor[ 3 ] = RB_CalcAlphaFromOneMinusDotView( pStage->alphaMin, pStage->alphaMax );
break;
case AGEN_SKYALPHA:
baseColor[ 3 ] = RB_CalcAlphaFromConstant( tr.refdef.sky_alpha * 255.0, pStage->alphaMax );
break;
case AGEN_ONE_MINUS_SKYALPHA:
baseColor[ 3 ] = RB_CalcAlphaFromConstant( ( 1.0 - tr.refdef.sky_alpha ) * 255.0, pStage->alphaMax );
break;
case AGEN_SCOORD:
baseColor[ 3 ] = RB_CalcAlphaFromTexCoords( pStage->alphaMin, pStage->alphaMax, pStage->alphaConstMin, pStage->alphaConst, 0.0, 1.0, ( float * )tess.svars.texcoords );
break;
case AGEN_TCOORD:
baseColor[ 3 ] = RB_CalcAlphaFromTexCoords( pStage->alphaMin, pStage->alphaMax, pStage->alphaConstMin, pStage->alphaConst, 1.0, 0.0, ( float * )tess.svars.texcoords );
break;
case AGEN_DIST_FADE:
// FIXME
break;
case AGEN_ONE_MINUS_DIST_FADE:
// FIXME
break;
case AGEN_IDENTITY: case AGEN_IDENTITY:
case AGEN_LIGHTING_SPECULAR: case AGEN_LIGHTING_SPECULAR:
case AGEN_PORTAL: case AGEN_PORTAL:
@ -694,23 +545,6 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t
break; break;
} }
// multiply color by overbrightbits if this isn't a blend
if (tr.overbrightBits
&& !((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_DST_COLOR)
&& !((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_ONE_MINUS_DST_COLOR)
&& !((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_SRC_COLOR)
&& !((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR))
{
float scale = 1 << tr.overbrightBits;
baseColor[0] *= scale;
baseColor[1] *= scale;
baseColor[2] *= scale;
vertColor[0] *= scale;
vertColor[1] *= scale;
vertColor[2] *= scale;
}
// FIXME: find some way to implement this. // FIXME: find some way to implement this.
#if 0 #if 0
// if in greyscale rendering mode turn all color values into greyscale. // if in greyscale rendering mode turn all color values into greyscale.
@ -828,7 +662,7 @@ static void ForwardDlight( void ) {
vec4_t texOffTurb; vec4_t texOffTurb;
if ( !( tess.dlightBits & ( 1 << l ) ) ) { if ( !( tess.dlightBits & ( 1 << l ) ) ) {
continue; // this surface definately doesn't have any of this light continue; // this surface definitely doesn't have any of this light
} }
dl = &backEnd.refdef.dlights[l]; dl = &backEnd.refdef.dlights[l];
@ -910,6 +744,7 @@ static void ForwardDlight( void ) {
// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
// where they aren't rendered // where they aren't rendered
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix);
@ -948,11 +783,7 @@ static void ForwardDlight( void ) {
} }
if (r_dlightMode->integer >= 2) if (r_dlightMode->integer >= 2)
{ GL_BindToTMU(tr.shadowCubemaps[l], TB_SHADOWMAP);
GL_SelectTexture(TB_SHADOWMAP);
GL_Bind(tr.shadowCubemaps[l]);
GL_SelectTexture(0);
}
ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb );
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix);
@ -964,14 +795,7 @@ static void ForwardDlight( void ) {
// draw // draw
// //
if (input->multiDrawPrimitives) R_DrawElements(input->numIndexes, input->firstIndex);
{
R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
}
backEnd.pc.c_totalIndexes += tess.numIndexes; backEnd.pc.c_totalIndexes += tess.numIndexes;
backEnd.pc.c_dlightIndexes += tess.numIndexes; backEnd.pc.c_dlightIndexes += tess.numIndexes;
@ -1002,7 +826,7 @@ static void ProjectPshadowVBOGLSL( void ) {
vec4_t vector; vec4_t vector;
if ( !( tess.pshadowBits & ( 1 << l ) ) ) { if ( !( tess.pshadowBits & ( 1 << l ) ) ) {
continue; // this surface definately doesn't have any of this shadow continue; // this surface definitely doesn't have any of this shadow
} }
ps = &backEnd.refdef.pshadows[l]; ps = &backEnd.refdef.pshadows[l];
@ -1033,6 +857,7 @@ static void ProjectPshadowVBOGLSL( void ) {
// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
// where they aren't rendered // where they aren't rendered
GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );
GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
GL_BindToTMU( tr.pshadowMaps[l], TB_DIFFUSEMAP ); GL_BindToTMU( tr.pshadowMaps[l], TB_DIFFUSEMAP );
@ -1040,14 +865,7 @@ static void ProjectPshadowVBOGLSL( void ) {
// draw // draw
// //
if (input->multiDrawPrimitives) R_DrawElements(input->numIndexes, input->firstIndex);
{
R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
}
backEnd.pc.c_totalIndexes += tess.numIndexes; backEnd.pc.c_totalIndexes += tess.numIndexes;
//backEnd.pc.c_dlightIndexes += tess.numIndexes; //backEnd.pc.c_dlightIndexes += tess.numIndexes;
@ -1083,6 +901,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];
} }
@ -1096,6 +916,11 @@ static void RB_FogPass( void ) {
GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
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)
@ -1121,16 +946,9 @@ static void RB_FogPass( void ) {
} else { } else {
GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
} }
GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
if (tess.multiDrawPrimitives) R_DrawElements(tess.numIndexes, tess.firstIndex);
{
shaderCommands_t *input = &tess;
R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVao(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex);
}
} }
@ -1144,9 +962,7 @@ static unsigned int RB_CalcShaderVertexAttribs( shaderCommands_t *input )
if (vertexAttribs & ATTR_NORMAL) if (vertexAttribs & ATTR_NORMAL)
{ {
vertexAttribs |= ATTR_NORMAL2; vertexAttribs |= ATTR_NORMAL2;
#ifdef USE_VERT_TANGENT_SPACE
vertexAttribs |= ATTR_TANGENT2; vertexAttribs |= ATTR_TANGENT2;
#endif
} }
} }
@ -1163,6 +979,8 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
int deformGen; int deformGen;
vec5_t deformParams; vec5_t deformParams;
qboolean renderToCubemap = tr.renderCubeFbo && glState.currentFBO == tr.renderCubeFbo;
ComputeDeformValues(&deformGen, deformParams); ComputeDeformValues(&deformGen, deformParams);
ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT);
@ -1187,7 +1005,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)
@ -1210,6 +1035,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)
{ {
@ -1225,7 +1054,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))
@ -1233,9 +1069,9 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
index |= LIGHTDEF_USE_SHADOWMAP; index |= LIGHTDEF_USE_SHADOWMAP;
} }
if (r_lightmap->integer && index & LIGHTDEF_USE_LIGHTMAP) if (r_lightmap->integer && ((index & LIGHTDEF_LIGHTTYPE_MASK) == LIGHTDEF_USE_LIGHTMAP))
{ {
index = LIGHTDEF_USE_LIGHTMAP; index = LIGHTDEF_USE_TCGEN_AND_TCMOD;
} }
sp = &pStage->glslShaderGroup[index]; sp = &pStage->glslShaderGroup[index];
@ -1256,6 +1092,11 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin); GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin);
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)
@ -1271,19 +1112,29 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
} }
GL_State( pStage->stateBits ); GL_State( pStage->stateBits );
if ((pStage->stateBits & GLS_ATEST_BITS) == GLS_ATEST_GT_0)
{
GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 1);
}
else if ((pStage->stateBits & GLS_ATEST_BITS) == GLS_ATEST_LT_80)
{
GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 2);
}
else if ((pStage->stateBits & GLS_ATEST_BITS) == GLS_ATEST_GE_80)
{
GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 3);
}
else
{
GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
}
{ {
vec4_t baseColor; vec4_t baseColor;
vec4_t vertColor; vec4_t vertColor;
ComputeShaderColors( pStage, baseColor, vertColor, pStage->stateBits ); ComputeShaderColors(pStage, baseColor, vertColor, pStage->stateBits);
if ((backEnd.refdef.colorScale != 1.0f) && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL))
{
// use VectorScale to only scale first three values, not alpha
VectorScale(baseColor, backEnd.refdef.colorScale, baseColor);
VectorScale(vertColor, backEnd.refdef.colorScale, vertColor);
}
GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor); GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor);
GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor); GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor);
@ -1293,20 +1144,18 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
{ {
vec4_t vec; vec4_t vec;
if( backEnd.currentEntity ) { VectorScale(backEnd.currentEntity->ambientLight, 1.0f / 255.0f, vec);
VectorScale( backEnd.currentEntity->ambientLight, 1.0f / 255.0f, vec ); GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vec);
GLSL_SetUniformVec3( sp, UNIFORM_AMBIENTLIGHT, vec );
VectorScale( backEnd.currentEntity->directedLight, 1.0f / 255.0f, vec ); VectorScale(backEnd.currentEntity->directedLight, 1.0f / 255.0f, vec);
GLSL_SetUniformVec3( sp, UNIFORM_DIRECTEDLIGHT, vec ); GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, vec);
VectorCopy(backEnd.currentEntity->lightDir, vec);
vec[3] = 0.0f;
GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vec);
GLSL_SetUniformVec3(sp, UNIFORM_MODELLIGHTDIR, backEnd.currentEntity->modelLightDir);
VectorCopy( backEnd.currentEntity->lightDir, vec ); GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, 0.0f);
vec[ 3 ] = 0.0f;
GLSL_SetUniformVec4( sp, UNIFORM_LIGHTORIGIN, vec );
GLSL_SetUniformVec3( sp, UNIFORM_MODELLIGHTDIR, backEnd.currentEntity->modelLightDir );
GLSL_SetUniformFloat( sp, UNIFORM_LIGHTRADIUS, 0.0f );
}
} }
if (pStage->alphaGen == AGEN_PORTAL) if (pStage->alphaGen == AGEN_PORTAL)
@ -1326,25 +1175,51 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask); GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask);
} }
ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); if (r_lightmap->integer)
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix);
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb);
GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen);
if (pStage->bundle[0].tcGen == TCGEN_VECTOR)
{ {
vec3_t vec; vec4_t v;
VectorSet4(v, 1.0f, 0.0f, 0.0f, 1.0f);
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, v);
VectorSet4(v, 0.0f, 0.0f, 0.0f, 0.0f);
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, v);
VectorCopy(pStage->bundle[0].tcGenVectors[0], vec); GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, TCGEN_LIGHTMAP);
GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR0, vec); }
VectorCopy(pStage->bundle[0].tcGenVectors[1], vec); else
GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR1, vec); {
ComputeTexMods(pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb);
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix);
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb);
GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen);
if (pStage->bundle[0].tcGen == TCGEN_VECTOR)
{
vec3_t vec;
VectorCopy(pStage->bundle[0].tcGenVectors[0], vec);
GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR0, vec);
VectorCopy(pStage->bundle[0].tcGenVectors[1], vec);
GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR1, vec);
}
} }
GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix);
GLSL_SetUniformVec4(sp, UNIFORM_NORMALSCALE, pStage->normalScale); GLSL_SetUniformVec4(sp, UNIFORM_NORMALSCALE, pStage->normalScale);
GLSL_SetUniformVec4(sp, UNIFORM_SPECULARSCALE, pStage->specularScale);
{
vec4_t specularScale;
Vector4Copy(pStage->specularScale, specularScale);
if (renderToCubemap)
{
// force specular to nonmetal if rendering cubemaps
if (r_pbr->integer)
specularScale[1] = 0.0f;
}
GLSL_SetUniformVec4(sp, UNIFORM_SPECULARSCALE, specularScale);
}
//GLSL_SetUniformFloat(sp, UNIFORM_MAPLIGHTSCALE, backEnd.refdef.mapLightScale); //GLSL_SetUniformFloat(sp, UNIFORM_MAPLIGHTSCALE, backEnd.refdef.mapLightScale);
@ -1354,7 +1229,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
if ( backEnd.depthFill ) if ( backEnd.depthFill )
{ {
if (!(pStage->stateBits & GLS_ATEST_BITS)) if (!(pStage->stateBits & GLS_ATEST_BITS))
GL_BindToTMU( tr.whiteImage, 0 ); GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
else if ( pStage->bundle[TB_COLORMAP].image[0] != 0 ) else if ( pStage->bundle[TB_COLORMAP].image[0] != 0 )
R_BindAnimatedImageToTMU( &pStage->bundle[TB_COLORMAP], TB_COLORMAP ); R_BindAnimatedImageToTMU( &pStage->bundle[TB_COLORMAP], TB_COLORMAP );
} }
@ -1365,9 +1240,23 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK)) if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK))
{ {
GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP); // FIXME: screenShadowImage is NULL if no framebuffers
if (tr.screenShadowImage)
GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP);
GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTAMBIENT, backEnd.refdef.sunAmbCol); GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTAMBIENT, backEnd.refdef.sunAmbCol);
GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTCOLOR, backEnd.refdef.sunCol); if (r_pbr->integer)
{
vec3_t color;
color[0] = backEnd.refdef.sunCol[0] * backEnd.refdef.sunCol[0];
color[1] = backEnd.refdef.sunCol[1] * backEnd.refdef.sunCol[1];
color[2] = backEnd.refdef.sunCol[2] * backEnd.refdef.sunCol[2];
GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTCOLOR, color);
}
else
{
GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTCOLOR, backEnd.refdef.sunCol);
}
GLSL_SetUniformVec4(sp, UNIFORM_PRIMARYLIGHTORIGIN, backEnd.refdef.sunDir); GLSL_SetUniformVec4(sp, UNIFORM_PRIMARYLIGHTORIGIN, backEnd.refdef.sunDir);
} }
@ -1376,7 +1265,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
{ {
for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
{ {
if (i == TB_LIGHTMAP) if (i == TB_COLORMAP)
R_BindAnimatedImageToTMU( &pStage->bundle[TB_LIGHTMAP], i); R_BindAnimatedImageToTMU( &pStage->bundle[TB_LIGHTMAP], i);
else else
GL_BindToTMU( tr.whiteImage, i ); GL_BindToTMU( tr.whiteImage, i );
@ -1386,7 +1275,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
{ {
for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
{ {
if (i == TB_LIGHTMAP) if (i == TB_COLORMAP)
R_BindAnimatedImageToTMU( &pStage->bundle[TB_DELUXEMAP], i); R_BindAnimatedImageToTMU( &pStage->bundle[TB_DELUXEMAP], i);
else else
GL_BindToTMU( tr.whiteImage, i ); GL_BindToTMU( tr.whiteImage, i );
@ -1463,15 +1352,16 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex && r_cubeMapping->integer) if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex && r_cubeMapping->integer)
{ {
vec4_t vec; vec4_t vec;
cubemap_t *cubemap = &tr.cubemaps[input->cubemapIndex - 1];
GL_BindToTMU( tr.cubemaps[input->cubemapIndex - 1], TB_CUBEMAP); // FIXME: cubemap image could be NULL if cubemap isn't renderer or loaded
if (cubemap->image)
GL_BindToTMU( cubemap->image, TB_CUBEMAP);
vec[0] = tr.cubemapOrigins[input->cubemapIndex - 1][0] - backEnd.viewParms.or.origin[0]; VectorSubtract(cubemap->origin, backEnd.viewParms.or.origin, vec);
vec[1] = tr.cubemapOrigins[input->cubemapIndex - 1][1] - backEnd.viewParms.or.origin[1];
vec[2] = tr.cubemapOrigins[input->cubemapIndex - 1][2] - backEnd.viewParms.or.origin[2];
vec[3] = 1.0f; vec[3] = 1.0f;
VectorScale4(vec, 1.0f / 1000.0f, vec); VectorScale4(vec, 1.0f / cubemap->parallaxRadius, vec);
GLSL_SetUniformVec4(sp, UNIFORM_CUBEMAPINFO, vec); GLSL_SetUniformVec4(sp, UNIFORM_CUBEMAPINFO, vec);
} }
@ -1479,14 +1369,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
// //
// draw // draw
// //
if (input->multiDrawPrimitives) R_DrawElements(input->numIndexes, input->firstIndex);
{
R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
}
// allow skipping out to show just lightmaps during development // allow skipping out to show just lightmaps during development
if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) ) if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) )
@ -1508,7 +1391,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;
@ -1520,6 +1412,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)
{ {
@ -1533,6 +1430,7 @@ static void RB_RenderShadowmap( shaderCommands_t *input )
GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, backEnd.viewParms.zFar); GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, backEnd.viewParms.zFar);
GL_State( 0 ); GL_State( 0 );
GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
// //
// do multitexture // do multitexture
@ -1543,14 +1441,7 @@ static void RB_RenderShadowmap( shaderCommands_t *input )
// draw // draw
// //
if (input->multiDrawPrimitives) R_DrawElements(input->numIndexes, input->firstIndex);
{
R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
}
} }
} }
} }
@ -1682,10 +1573,11 @@ void RB_StageIteratorGeneric( void )
ProjectPshadowVBOGLSL(); ProjectPshadowVBOGLSL();
} }
//
//
// now do any dynamic lighting needed // now do any dynamic lighting needed
// //
if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE && r_lightmap->integer == 0
&& !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) {
if (tess.shader->numUnfoggedPasses == 1 && tess.xstages[0]->glslShaderGroup == tr.lightallShader if (tess.shader->numUnfoggedPasses == 1 && tess.xstages[0]->glslShaderGroup == tr.lightallShader
&& (tess.xstages[0]->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && r_dlightMode->integer) && (tess.xstages[0]->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && r_dlightMode->integer)
@ -1714,7 +1606,6 @@ void RB_StageIteratorGeneric( void )
} }
} }
/* /*
** RB_EndSurface ** RB_EndSurface
*/ */
@ -1744,6 +1635,12 @@ void RB_EndSurface( void ) {
return; return;
} }
if (tess.useCacheVao)
{
// upload indexes now
VaoCache_Commit();
}
// //
// update performance counters // update performance counters
// //
@ -1770,7 +1667,6 @@ void RB_EndSurface( void ) {
tess.numIndexes = 0; tess.numIndexes = 0;
tess.numVertexes = 0; tess.numVertexes = 0;
tess.firstIndex = 0; tess.firstIndex = 0;
tess.multiDrawPrimitives = 0;
GLimp_LogComment( "----------\n" ); GLimp_LogComment( "----------\n" );
} }

View file

@ -22,12 +22,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// tr_shade_calc.c // tr_shade_calc.c
#include "tr_local.h" #include "tr_local.h"
#if idppc_altivec && !defined(MACOS_X)
#include <altivec.h>
#endif
#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ ftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude)) #define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ ( (int64_t) ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))
static float *TableForFunc( genFunc_t func ) static float *TableForFunc( genFunc_t func )
{ {
@ -116,16 +113,16 @@ void RB_CalcDeformVertexes( deformStage_t *ds )
vec3_t offset; vec3_t offset;
float scale; float scale;
float *xyz = ( float * ) tess.xyz; float *xyz = ( float * ) tess.xyz;
uint32_t *normal = tess.normal; int16_t *normal = tess.normal[0];
float *table; float *table;
if ( ds->deformationWave.frequency == 0 ) if ( ds->deformationWave.frequency == 0 )
{ {
scale = EvalWaveForm( &ds->deformationWave ); scale = EvalWaveForm( &ds->deformationWave );
for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
{ {
R_VaoUnpackNormal(offset, *normal); R_VaoUnpackNormal(offset, normal);
xyz[0] += offset[0] * scale; xyz[0] += offset[0] * scale;
xyz[1] += offset[1] * scale; xyz[1] += offset[1] * scale;
@ -136,7 +133,7 @@ void RB_CalcDeformVertexes( deformStage_t *ds )
{ {
table = TableForFunc( ds->deformationWave.func ); table = TableForFunc( ds->deformationWave.func );
for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
{ {
float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread; float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;
@ -145,7 +142,7 @@ void RB_CalcDeformVertexes( deformStage_t *ds )
ds->deformationWave.phase + off, ds->deformationWave.phase + off,
ds->deformationWave.frequency ); ds->deformationWave.frequency );
R_VaoUnpackNormal(offset, *normal); R_VaoUnpackNormal(offset, normal);
xyz[0] += offset[0] * scale; xyz[0] += offset[0] * scale;
xyz[1] += offset[1] * scale; xyz[1] += offset[1] * scale;
@ -165,12 +162,12 @@ void RB_CalcDeformNormals( deformStage_t *ds ) {
int i; int i;
float scale; float scale;
float *xyz = ( float * ) tess.xyz; float *xyz = ( float * ) tess.xyz;
uint32_t *normal = tess.normal; int16_t *normal = tess.normal[0];
for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) { for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) {
vec3_t fNormal; vec3_t fNormal;
R_VaoUnpackNormal(fNormal, *normal); R_VaoUnpackNormal(fNormal, normal);
scale = 0.98f; scale = 0.98f;
scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
@ -189,7 +186,7 @@ void RB_CalcDeformNormals( deformStage_t *ds ) {
VectorNormalizeFast( fNormal ); VectorNormalizeFast( fNormal );
R_VaoPackNormal((byte *)normal, fNormal); R_VaoPackNormal(normal, fNormal);
} }
} }
@ -203,17 +200,17 @@ void RB_CalcBulgeVertexes( deformStage_t *ds ) {
int i; int i;
const float *st = ( const float * ) tess.texCoords[0]; const float *st = ( const float * ) tess.texCoords[0];
float *xyz = ( float * ) tess.xyz; float *xyz = ( float * ) tess.xyz;
uint32_t *normal = tess.normal; int16_t *normal = tess.normal[0];
float now; double now;
now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f; now = backEnd.refdef.time * 0.001 * ds->bulgeSpeed;
for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal++ ) { for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 2, normal += 4 ) {
int off; int64_t off;
float scale; float scale;
vec3_t fNormal; vec3_t fNormal;
R_VaoUnpackNormal(fNormal, *normal); R_VaoUnpackNormal(fNormal, normal);
off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now ); off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now );
@ -350,7 +347,7 @@ static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) {
===================== =====================
AutospriteDeform AutospriteDeform
Assuming all the triangles for this shader are independant Assuming all the triangles for this shader are independent
quads, rebuild them as forward facing sprites quads, rebuild them as forward facing sprites
===================== =====================
*/ */
@ -384,6 +381,7 @@ static void AutospriteDeform( void ) {
} }
for ( i = 0 ; i < oldVerts ; i+=4 ) { for ( i = 0 ; i < oldVerts ; i+=4 ) {
vec4_t color;
// find the midpoint // find the midpoint
xyz = tess.xyz[i]; xyz = tess.xyz[i];
@ -414,7 +412,8 @@ static void AutospriteDeform( void ) {
VectorScale(up, axisLength, up); VectorScale(up, axisLength, up);
} }
RB_AddQuadStamp( mid, left, up, tess.vertexColors[i] ); VectorScale4(tess.color[i], 1.0f / 65535.0f, color);
RB_AddQuadStamp( mid, left, up, color );
} }
} }
@ -774,8 +773,8 @@ void RB_CalcScaleTexMatrix( const float scale[2], float *matrix )
*/ */
void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix ) void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix )
{ {
float timeScale = tess.shaderTime; double timeScale = tess.shaderTime;
float adjustedScrollS, adjustedScrollT; double adjustedScrollS, adjustedScrollT;
adjustedScrollS = scrollSpeed[0] * timeScale; adjustedScrollS = scrollSpeed[0] * timeScale;
adjustedScrollT = scrollSpeed[1] * timeScale; adjustedScrollT = scrollSpeed[1] * timeScale;
@ -803,9 +802,9 @@ void RB_CalcTransformTexMatrix( const texModInfo_t *tmi, float *matrix )
*/ */
void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix ) void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix )
{ {
float timeScale = tess.shaderTime; double timeScale = tess.shaderTime;
float degs; double degs;
int index; int64_t index;
float sinValue, cosValue; float sinValue, cosValue;
degs = -degsPerSecond * timeScale; degs = -degsPerSecond * timeScale;
@ -817,214 +816,3 @@ void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix )
matrix[0] = cosValue; matrix[2] = -sinValue; matrix[4] = 0.5 - 0.5 * cosValue + 0.5 * sinValue; matrix[0] = cosValue; matrix[2] = -sinValue; matrix[4] = 0.5 - 0.5 * cosValue + 0.5 * sinValue;
matrix[1] = sinValue; matrix[3] = cosValue; matrix[5] = 0.5 - 0.5 * sinValue - 0.5 * cosValue; matrix[1] = sinValue; matrix[3] = cosValue; matrix[5] = 0.5 - 0.5 * sinValue - 0.5 * cosValue;
} }
/*
** RB_CalcLightGridColor
*/
float RB_CalcLightGridColor( void )
{
if( backEnd.currentEntity )
{
if( backEnd.currentEntity == &tr.worldEntity )
{
Com_Printf( "#### shader '%s' incorrectly uses rgbGen ligthingGrid or ligthingSpherical; was rgbGen vertex intended?\n", tess.shader->name );
return -1;
}
else
{
return backEnd.currentEntity->iGridLighting;
}
}
else
{
return backEnd.currentStaticModel->iGridLighting;
}
}
/*
** RB_CalcRGBFromTexCoords
*/
float RB_CalcRGBFromTexCoords( float alphaMin, float alphaMax, int alphaMinCap, int alphaCap, float sWeight, float tWeight, float *st )
{
float f = sWeight * tess.texCoords[ 0 ][ 0 ][ 0 ] + tWeight * tess.texCoords[ 0 ][ 0 ][ 1 ];
float _ff_;
f = ( ( alphaMax - alphaMin ) * f + alphaMin ) * 255.0;
_ff_ = f - ( float )( ~( ( int )( f - ( float )( unsigned char )alphaCap ) >> 31 ) & ( int )( f - ( float )( unsigned char )alphaCap ) );
_ff_ = ( float )( ( ~( ( int )( _ff_ - ( float )( unsigned char )alphaMinCap ) >> 31 ) & ( int )( _ff_ - ( float )( unsigned char )alphaMinCap ) ) + ( unsigned char )alphaMinCap );
return _ff_ / 255.0;
}
/*
** RB_CalcRGBFromDot
*/
float RB_CalcRGBFromDot( float alphaMin, float alphaMax )
{
vec3_t viewInModel;
float f;
float _ff_;
int fl;
VectorSubtract( backEnd.or.viewOrigin, tess.xyz[ 0 ], viewInModel );
VectorNormalizeFast( viewInModel );
f = DotProduct( tess.normal, viewInModel );
f = f * f;
_ff_ = ( ( alphaMax - alphaMin ) * f + alphaMin ) * 255.0;
_ff_ = _ff_ - ( ~( ( int )( _ff_ - 255.0 ) >> 31 ) & ( int )( _ff_ - 255.0 ) );
fl = ( ~( *( int * )&_ff_ >> 31 ) & *( int * )&_ff_ );
return *( float * )fl / 255.0;
}
/*
** RB_CalcRGBFromOneMinusDot
*/
float RB_CalcRGBFromOneMinusDot( float alphaMin, float alphaMax )
{
vec3_t viewInModel;
float f;
float _ff_;
int fl;
VectorSubtract( backEnd.or.viewOrigin, tess.xyz[ 0 ], viewInModel );
VectorNormalizeFast( viewInModel );
f = DotProduct( tess.normal, viewInModel );
f = 1.0 - f * f;
_ff_ = ( ( alphaMax - alphaMin ) * f + alphaMin ) * 255.0;
_ff_ = _ff_ - ( ~( ( int )( _ff_ - 255.0 ) >> 31 ) & ( int )( _ff_ - 255.0 ) );
fl = ( ~( *( int * )&_ff_ >> 31 ) & *( int * )&_ff_ );
return *( float * )fl / 255.0;
}
/*
** RB_CalcAlphaFromDot
*/
float RB_CalcAlphaFromDot( float alphaMin, float alphaMax )
{
vec3_t viewInModel;
float f;
float _ff_;
int fl;
VectorSubtract( backEnd.or.viewOrigin, tess.xyz[ 0 ], viewInModel );
VectorNormalizeFast( viewInModel );
f = DotProduct( tess.normal, viewInModel );
f = f * f;
_ff_ = ( ( alphaMax - alphaMin ) * f + alphaMin ) * 255.0;
_ff_ = _ff_ - ( ~( ( int )( _ff_ - 255.0 ) >> 31 ) & ( int )( _ff_ - 255.0 ) );
fl = ( ~( *( int * )&_ff_ >> 31 ) & *( int * )&_ff_ );
return *( float * )fl / 255.0;
}
/*
** RB_CalcAlphaFromOneMinusDot
*/
float RB_CalcAlphaFromOneMinusDot( float alphaMin, float alphaMax )
{
vec3_t viewInModel;
float f;
float _ff_;
int fl;
VectorSubtract( backEnd.or.viewOrigin, tess.xyz[ 0 ], viewInModel );
VectorNormalizeFast( viewInModel );
f = DotProduct( tess.normal, viewInModel );
f = 1.0 - f * f;
_ff_ = ( ( alphaMax - alphaMin ) * f + alphaMin ) * 255.0;
_ff_ = _ff_ - ( ~( ( int )( _ff_ - 255.0 ) >> 31 ) & ( int )( _ff_ - 255.0 ) );
fl = ( ~( *( int * )&_ff_ >> 31 ) & *( int * )&_ff_ );
return *( float * )fl / 255.0;
}
/*
** RB_CalcAlphaFromDotView
*/
float RB_CalcAlphaFromDotView( float alphaMin, float alphaMax )
{
vec3_t viewInModel;
vec3_t normal;
float f;
float _ff_;
int fl;
VectorCopy( tr.refdef.viewaxis[ 0 ], viewInModel );
VectorNormalizeFast( viewInModel );
f = DotProduct( tess.normal, viewInModel );
f = f * f;
R_VaoUnpackNormal( normal, tess.normal[ 0 ] );
Com_Printf( "normal: %f %f %f dot: %f i %d\n", normal[ 0 ], normal[ 1 ], normal[ 2 ], f, 0 );
_ff_ = ( ( alphaMax - alphaMin ) * f + alphaMin ) * 255.0;
_ff_ = _ff_ - ( ~( ( int )( _ff_ - 255.0 ) >> 31 ) & ( int )( _ff_ - 255.0 ) );
fl = ( ~( *( int * )&_ff_ >> 31 ) & *( int * )&_ff_ );
return *( float * )fl / 255.0;
}
/*
** RB_CalcAlphaFromOneMinusDotView
*/
float RB_CalcAlphaFromOneMinusDotView( float alphaMin, float alphaMax )
{
vec3_t viewInModel;
vec3_t normal;
float f;
float _ff_;
int fl;
VectorCopy( tr.refdef.viewaxis[ 0 ], viewInModel );
VectorNormalizeFast( viewInModel );
f = DotProduct( tess.normal, viewInModel );
f = 1.0 - f * f;
R_VaoUnpackNormal( normal, tess.normal[ 0 ] );
Com_Printf( "normal: %f %f %f dot: %f i %d\n", normal[ 0 ], normal[ 1 ], normal[ 2 ], f, 0 );
_ff_ = ( ( alphaMax - alphaMin ) * f + alphaMin ) * 255.0;
_ff_ = _ff_ - ( ~( ( int )( _ff_ - 255.0 ) >> 31 ) & ( int )( _ff_ - 255.0 ) );
fl = ( ~( *( int * )&_ff_ >> 31 ) & *( int * )&_ff_ );
return *( float * )fl / 255.0;
}
/*
** RB_CalcAlphaFromConstant
*/
float RB_CalcAlphaFromConstant( float alphaMin, float alphaMax )
{
return alphaMin;
}
/*
** RB_CalcAlphaFromTexCoords
*/
float RB_CalcAlphaFromTexCoords( float alphaMin, float alphaMax, int alphaMinCap, int alphaCap, float sWeight, float tWeight, float *st )
{
float f = sWeight * tess.texCoords[ 0 ][ 0 ][ 0 ] + tWeight * tess.texCoords[ 0 ][ 0 ][ 1 ];
float _ff_;
f = ( ( alphaMax - alphaMin ) * f + alphaMin ) * 255.0;
_ff_ = f - ( float )( ~( ( int )( f - ( float )( unsigned char )alphaCap ) >> 31 ) & ( int )( f - ( float )( unsigned char )alphaCap ) );
_ff_ = ( float )( ( ~( ( int )( _ff_ - ( float )( unsigned char )alphaMinCap ) >> 31 ) & ( int )( _ff_ - ( float )( unsigned char )alphaMinCap ) ) + ( unsigned char )alphaMinCap );
return _ff_ / 255.0;
}

View file

@ -603,8 +603,6 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
char *token; char *token;
int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0; int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0;
qboolean depthMaskExplicit = qfalse; qboolean depthMaskExplicit = qfalse;
// IneQuation
int bundleNum = 0;
stage->active = qtrue; stage->active = qtrue;
@ -635,16 +633,16 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
if ( !Q_stricmp( token, "$whiteimage" ) ) if ( !Q_stricmp( token, "$whiteimage" ) )
{ {
stage->bundle[bundleNum].image[0] = tr.whiteImage; stage->bundle[0].image[0] = tr.whiteImage;
continue; continue;
} }
else if ( !Q_stricmp( token, "$lightmap" ) ) else if ( !Q_stricmp( token, "$lightmap" ) )
{ {
stage->bundle[bundleNum].isLightmap = qtrue; stage->bundle[0].isLightmap = qtrue;
if ( shader.lightmapIndex < 0 || !tr.lightmaps ) { if ( shader.lightmapIndex < 0 || !tr.lightmaps ) {
stage->bundle[bundleNum].image[0] = tr.whiteImage; stage->bundle[0].image[0] = tr.whiteImage;
} else { } else {
stage->bundle[bundleNum].image[0] = tr.lightmaps[shader.lightmapIndex]; stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
} }
continue; continue;
} }
@ -656,11 +654,11 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
return qfalse; return qfalse;
} }
stage->bundle[bundleNum].isLightmap = qtrue; stage->bundle[0].isLightmap = qtrue;
if ( shader.lightmapIndex < 0 ) { if ( shader.lightmapIndex < 0 ) {
stage->bundle[bundleNum].image[0] = tr.whiteImage; stage->bundle[0].image[0] = tr.whiteImage;
} else { } else {
stage->bundle[bundleNum].image[0] = tr.deluxemaps[shader.lightmapIndex]; stage->bundle[0].image[0] = tr.deluxemaps[shader.lightmapIndex];
} }
continue; continue;
} }
@ -689,9 +687,9 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
flags |= IMGFLAG_GENNORMALMAP; flags |= IMGFLAG_GENNORMALMAP;
} }
stage->bundle[bundleNum].image[0] = R_FindImageFile( token, type, flags ); stage->bundle[0].image[0] = R_FindImageFile( token, type, flags );
if ( !stage->bundle[bundleNum].image[0] ) if ( !stage->bundle[0].image[0] )
{ {
ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
return qfalse; return qfalse;
@ -734,8 +732,8 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
} }
stage->bundle[bundleNum].image[0] = R_FindImageFile( token, type, flags ); stage->bundle[0].image[0] = R_FindImageFile( token, type, flags );
if ( !stage->bundle[bundleNum].image[0] ) if ( !stage->bundle[0].image[0] )
{ {
ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
return qfalse; return qfalse;
@ -746,13 +744,15 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
// //
else if ( !Q_stricmp( token, "animMap" ) ) else if ( !Q_stricmp( token, "animMap" ) )
{ {
int totalImages = 0;
token = COM_ParseExt( text, qfalse ); token = COM_ParseExt( text, qfalse );
if ( !token[0] ) if ( !token[0] )
{ {
ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMap' keyword in shader '%s'\n", shader.name ); ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMap' keyword in shader '%s'\n", shader.name );
return qfalse; return qfalse;
} }
stage->bundle[bundleNum].imageAnimationSpeed = atof( token ); stage->bundle[0].imageAnimationSpeed = atof( token );
// parse up to MAX_IMAGE_ANIMATIONS animations // parse up to MAX_IMAGE_ANIMATIONS animations
while ( 1 ) { while ( 1 ) {
@ -762,7 +762,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
if ( !token[0] ) { if ( !token[0] ) {
break; break;
} }
num = stage->bundle[bundleNum].numImageAnimations; num = stage->bundle[0].numImageAnimations;
if ( num < MAX_IMAGE_ANIMATIONS ) { if ( num < MAX_IMAGE_ANIMATIONS ) {
imgFlags_t flags = IMGFLAG_NONE; imgFlags_t flags = IMGFLAG_NONE;
@ -772,28 +772,20 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
if (!shader.noPicMip) if (!shader.noPicMip)
flags |= IMGFLAG_PICMIP; flags |= IMGFLAG_PICMIP;
stage->bundle[bundleNum].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags );
if ( !stage->bundle[bundleNum].image[num] ) if ( !stage->bundle[0].image[num] )
{ {
ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
return qfalse; return qfalse;
} }
stage->bundle[bundleNum].numImageAnimations++; stage->bundle[0].numImageAnimations++;
} }
totalImages++;
} }
}
else if ( !Q_stricmp( token, "videoMap" ) ) if ( totalImages > MAX_IMAGE_ANIMATIONS ) {
{ ri.Printf( PRINT_WARNING, "WARNING: ignoring excess images for 'animMap' (found %d, max is %d) in shader '%s'\n",
token = COM_ParseExt( text, qfalse ); totalImages, MAX_IMAGE_ANIMATIONS, shader.name );
if ( !token[0] )
{
ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap' keyword in shader '%s'\n", shader.name );
return qfalse;
}
stage->bundle[bundleNum].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader));
if (stage->bundle[bundleNum].videoMapHandle != -1) {
stage->bundle[bundleNum].isVideoMap = qtrue;
stage->bundle[bundleNum].image[0] = tr.scratchImage[stage->bundle[bundleNum].videoMapHandle];
} }
} }
// //
@ -866,9 +858,6 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
} else if ( !Q_stricmp( token, "blend" ) ) { } else if ( !Q_stricmp( token, "blend" ) ) {
blendSrcBits = GLS_SRCBLEND_SRC_ALPHA; blendSrcBits = GLS_SRCBLEND_SRC_ALPHA;
blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
} else if( !Q_stricmp(token, "alphaadd" ) ) {
blendSrcBits = GLS_SRCBLEND_SRC_ALPHA;
blendDstBits = GLS_DSTBLEND_ONE;
} else { } else {
// complex double blends // complex double blends
blendSrcBits = NameToSrcBlendMode( token ); blendSrcBits = NameToSrcBlendMode( token );
@ -939,9 +928,18 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular reflectance in shader '%s'\n", shader.name ); ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular reflectance in shader '%s'\n", shader.name );
continue; continue;
} }
stage->specularScale[0] =
stage->specularScale[1] = if (r_pbr->integer)
stage->specularScale[2] = atof( token ); {
// interpret specularReflectance < 0.5 as nonmetal
stage->specularScale[1] = (atof(token) < 0.5f) ? 0.0f : 1.0f;
}
else
{
stage->specularScale[0] =
stage->specularScale[1] =
stage->specularScale[2] = atof( token );
}
} }
// //
// specularExponent <value> // specularExponent <value>
@ -959,17 +957,23 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
exponent = atof( token ); exponent = atof( token );
// Change shininess to gloss if (r_pbr->integer)
// FIXME: assumes max exponent of 8192 and min of 1, must change here if altered in lightall_fp.glsl stage->specularScale[0] = 1.0f - powf(2.0f / (exponent + 2.0), 0.25);
exponent = CLAMP(exponent, 1.0, 8192.0); else
{
stage->specularScale[3] = log(exponent) / log(8192.0); // Change shininess to gloss
// Assumes max exponent of 8190 and min of 0, must change here if altered in lightall_fp.glsl
exponent = CLAMP(exponent, 0.0f, 8190.0f);
stage->specularScale[3] = (log2f(exponent + 2.0f) - 1.0f) / 12.0f;
}
} }
// //
// gloss <value> // gloss <value>
// //
else if (!Q_stricmp(token, "gloss")) else if (!Q_stricmp(token, "gloss"))
{ {
float gloss;
token = COM_ParseExt(text, qfalse); token = COM_ParseExt(text, qfalse);
if ( token[0] == 0 ) if ( token[0] == 0 )
{ {
@ -977,7 +981,38 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
continue; continue;
} }
stage->specularScale[3] = atof( token ); gloss = atof(token);
if (r_pbr->integer)
stage->specularScale[0] = 1.0f - exp2f(-3.0f * gloss);
else
stage->specularScale[3] = gloss;
}
//
// roughness <value>
//
else if (!Q_stricmp(token, "roughness"))
{
float roughness;
token = COM_ParseExt(text, qfalse);
if (token[0] == 0)
{
ri.Printf(PRINT_WARNING, "WARNING: missing parameter for roughness in shader '%s'\n", shader.name);
continue;
}
roughness = atof(token);
if (r_pbr->integer)
stage->specularScale[0] = 1.0 - roughness;
else
{
if (roughness >= 0.125)
stage->specularScale[3] = log2f(1.0f / roughness) / 3.0f;
else
stage->specularScale[3] = 1.0f;
}
} }
// //
// parallaxDepth <value> // parallaxDepth <value>
@ -1030,6 +1065,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
} }
// //
// specularScale <rgb> <gloss> // specularScale <rgb> <gloss>
// or specularScale <metallic> <smoothness> with r_pbr 1
// or specularScale <r> <g> <b> // or specularScale <r> <g> <b>
// or specularScale <r> <g> <b> <gloss> // or specularScale <r> <g> <b> <gloss>
// //
@ -1056,10 +1092,20 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
token = COM_ParseExt(text, qfalse); token = COM_ParseExt(text, qfalse);
if ( token[0] == 0 ) if ( token[0] == 0 )
{ {
// two values, rgb then gloss if (r_pbr->integer)
stage->specularScale[3] = stage->specularScale[1]; {
stage->specularScale[1] = // two values, metallic then smoothness
stage->specularScale[2] = stage->specularScale[0]; float smoothness = stage->specularScale[1];
stage->specularScale[1] = (stage->specularScale[0] < 0.5f) ? 0.0f : 1.0f;
stage->specularScale[0] = smoothness;
}
else
{
// two values, rgb then gloss
stage->specularScale[3] = stage->specularScale[1];
stage->specularScale[1] =
stage->specularScale[2] = stage->specularScale[0];
}
continue; continue;
} }
@ -1072,7 +1118,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
continue; continue;
} }
stage->specularScale[2] = atof( token ); stage->specularScale[3] = atof( token );
} }
// //
@ -1092,18 +1138,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
ParseWaveForm( text, &stage->rgbWave ); ParseWaveForm( text, &stage->rgbWave );
stage->rgbGen = CGEN_WAVEFORM; stage->rgbGen = CGEN_WAVEFORM;
} }
else if ( !Q_stricmp( token, "colorwave" ) ) else if ( !Q_stricmp( token, "const" ) )
{
vec3_t color;
ParseVector( text, 3, color );
stage->constantColor[ 0 ] = 255 * color[ 0 ];
stage->constantColor[ 1 ] = 255 * color[ 1 ];
stage->constantColor[ 2 ] = 255 * color[ 2 ];
ParseWaveForm( text, &stage->rgbWave );
stage->rgbGen = CGEN_MULTIPLY_BY_WAVEFORM;
}
else if ( !Q_stricmp( token, "const" ) || !Q_stricmp( token, "constant" ) )
{ {
vec3_t color; vec3_t color;
@ -1124,7 +1159,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
{ {
stage->rgbGen = CGEN_IDENTITY_LIGHTING; stage->rgbGen = CGEN_IDENTITY_LIGHTING;
} }
else if ( !Q_stricmp( token, "entity" ) || !Q_stricmp( token, "fromentity" ) ) else if ( !Q_stricmp( token, "entity" ) )
{ {
stage->rgbGen = CGEN_ENTITY; stage->rgbGen = CGEN_ENTITY;
} }
@ -1132,7 +1167,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
{ {
stage->rgbGen = CGEN_ONE_MINUS_ENTITY; stage->rgbGen = CGEN_ONE_MINUS_ENTITY;
} }
else if ( !Q_stricmp( token, "vertex" ) || !Q_stricmp( token, "fromclient" ) ) else if ( !Q_stricmp( token, "vertex" ) )
{ {
stage->rgbGen = CGEN_VERTEX; stage->rgbGen = CGEN_VERTEX;
if ( stage->alphaGen == 0 ) { if ( stage->alphaGen == 0 ) {
@ -1154,15 +1189,6 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
{ {
stage->rgbGen = CGEN_EXACT_VERTEX_LIT; stage->rgbGen = CGEN_EXACT_VERTEX_LIT;
} }
else if ( !Q_stricmp( token, "lightingGrid" ) )
{
stage->rgbGen = CGEN_LIGHTING_GRID;
}
else if ( !Q_stricmp( token, "lightingSpherical" ) )
{
//stage->rgbGen = CGEN_LIGHTING_SPHERICAL;
stage->rgbGen = CGEN_LIGHTING_DIFFUSE;
}
else if ( !Q_stricmp( token, "lightingDiffuse" ) ) else if ( !Q_stricmp( token, "lightingDiffuse" ) )
{ {
stage->rgbGen = CGEN_LIGHTING_DIFFUSE; stage->rgbGen = CGEN_LIGHTING_DIFFUSE;
@ -1171,97 +1197,6 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
{ {
stage->rgbGen = CGEN_ONE_MINUS_VERTEX; stage->rgbGen = CGEN_ONE_MINUS_VERTEX;
} }
else if( !Q_stricmp( token, "global" ) )
{
stage->rgbGen = CGEN_GLOBAL_COLOR;
}
else if( !Q_stricmp( token, "static" ) )
{
stage->rgbGen = CGEN_STATIC;
if( stage->alphaGen = AGEN_IDENTITY ) {
stage->alphaGen = AGEN_VERTEX;
}
}
else if( !Q_stricmp( token, "sCoord" ) || !Q_stricmp( token, "tCoord" ) )
{
if( !Q_stricmp( token, "sCoord" ) ) {
stage->rgbGen = CGEN_SCOORD;
} else if( !Q_stricmp( token, "tCoord" ) ) {
stage->rgbGen = CGEN_TCOORD;
}
stage->alphaMin = 0.0;
stage->alphaMax = 1.0;
stage->alphaConstMin = 0;
stage->alphaConst = -1;
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMin = atof( token );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMax = atof( token );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaConstMin = ( byte )( atof( token ) * 255.0 );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaConst = ( byte )( atof( token ) * 255.0 );
}
else
{
ri.Printf( PRINT_WARNING, "WARNING: missing rgbGen sCoord or tCoord parm 'max' in shader '%s'\n", shader.name );
}
}
}
}
}
else if( !Q_stricmp( token, "dot" ) )
{
shader.needsNormal = qtrue;
stage->alphaMin = 0.0;
stage->alphaMax = 1.0;
stage->rgbGen = CGEN_DOT;
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMin = atof( token );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMax = atof( token );
}
}
}
else if( !Q_stricmp( token, "oneminusdot" ) )
{
shader.needsNormal = qtrue;
stage->alphaMin = 0.0;
stage->alphaMax = 1.0;
stage->rgbGen = CGEN_ONE_MINUS_DOT;
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMin = atof( token );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMax = atof( token );
}
}
}
else else
{ {
ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name ); ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name );
@ -1285,7 +1220,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
ParseWaveForm( text, &stage->alphaWave ); ParseWaveForm( text, &stage->alphaWave );
stage->alphaGen = AGEN_WAVEFORM; stage->alphaGen = AGEN_WAVEFORM;
} }
else if ( !Q_stricmp( token, "const" ) || !Q_stricmp( token, "constant" ) ) else if ( !Q_stricmp( token, "const" ) )
{ {
token = COM_ParseExt( text, qfalse ); token = COM_ParseExt( text, qfalse );
stage->constantColor[3] = 255 * atof( token ); stage->constantColor[3] = 255 * atof( token );
@ -1329,166 +1264,6 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
shader.portalRange = atof( token ); shader.portalRange = atof( token );
} }
} }
else if ( !Q_stricmp( token, "distFade" ) )
{
stage->alphaGen = AGEN_DIST_FADE;
shader.fDistRange = 256;
shader.fDistNear = 256;
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
shader.fDistNear = atof( token );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
shader.fDistRange = atof( token );
}
}
}
else if ( !Q_stricmp( token, "oneMinusDistFade" ) )
{
stage->alphaGen = AGEN_ONE_MINUS_DIST_FADE;
shader.fDistRange = 256;
shader.fDistNear = 256;
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
shader.fDistNear = atof( token );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
shader.fDistRange = atof( token );
}
}
}
else if ( !Q_stricmp( token, "dot" ) )
{
shader.needsNormal = qtrue;
stage->alphaMin = 0.0;
stage->alphaMax = 1.0;
stage->alphaGen = AGEN_DOT;
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMin = atof( token );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMax = atof( token );
}
}
}
else if ( !Q_stricmp( token, "dotView" ) )
{
shader.needsNormal = qtrue;
stage->alphaMin = 0.0;
stage->alphaMax = 1.0;
stage->alphaGen = AGEN_DOT_VIEW;
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMin = atof( token );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMax = atof( token );
}
}
}
else if ( !Q_stricmp( token, "oneMinusDotView" ) )
{
shader.needsNormal = qtrue;
stage->alphaMin = 0.0;
stage->alphaMax = 1.0;
stage->alphaGen = AGEN_ONE_MINUS_DOT_VIEW;
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMin = atof( token );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMax = atof( token );
}
}
}
else if ( !Q_stricmp( token, "oneMinusDot" ) )
{
shader.needsNormal = qtrue;
stage->alphaMin = 0.0;
stage->alphaMax = 1.0;
stage->alphaGen = AGEN_ONE_MINUS_DOT;
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMin = atof( token );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMax = atof( token );
}
}
}
else if ( !Q_stricmp( token, "skyAlpha" ) )
{
stage->alphaGen = AGEN_SKYALPHA;
}
else if ( !Q_stricmp( token, "oneMinusSkyAlpha" ) )
{
stage->alphaGen = AGEN_ONE_MINUS_SKYALPHA;
}else if( !Q_stricmp( token, "sCoord" ) || !Q_stricmp( token, "tCoord" ) )
{
if( !Q_stricmp( token, "sCoord" ) ) {
stage->alphaGen = AGEN_SCOORD;
} else if( !Q_stricmp( token, "tCoord" ) ) {
stage->alphaGen = AGEN_TCOORD;
}
stage->alphaMin = 0.0;
stage->alphaMax = 1.0;
stage->alphaConstMin = 0;
stage->alphaConst = -1;
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMin = atof( token );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaMax = atof( token );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaConstMin = ( byte )( atof( token ) * 255.0 );
token = COM_ParseExt( text, qfalse );
if( token[ 0 ] )
{
stage->alphaConst = ( byte )( atof( token ) * 255.0 );
}
else
{
ri.Printf( PRINT_WARNING, "WARNING: missing rgbGen sCoord or tCoord parm 'max' in shader '%s'\n", shader.name );
}
}
}
}
}
else else
{ {
ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name ); ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name );
@ -1509,33 +1284,22 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
if ( !Q_stricmp( token, "environment" ) ) if ( !Q_stricmp( token, "environment" ) )
{ {
shader.needsNormal = qtrue; stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED;
stage->bundle[bundleNum].tcGen = TCGEN_ENVIRONMENT_MAPPED;
}
else if ( !Q_stricmp( token, "environmentmodel" ) )
{
shader.needsNormal = qtrue;
stage->bundle[bundleNum].tcGen = TCGEN_ENVIRONMENT_MAPPED2;
}
else if ( !Q_stricmp( token, "sunreflection" ) )
{
shader.needsNormal = qtrue;
stage->bundle[bundleNum].tcGen = TCGEN_SUN_REFLECTION;
} }
else if ( !Q_stricmp( token, "lightmap" ) ) else if ( !Q_stricmp( token, "lightmap" ) )
{ {
stage->bundle[bundleNum].tcGen = TCGEN_LIGHTMAP; stage->bundle[0].tcGen = TCGEN_LIGHTMAP;
} }
else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) ) else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) )
{ {
stage->bundle[bundleNum].tcGen = TCGEN_TEXTURE; stage->bundle[0].tcGen = TCGEN_TEXTURE;
} }
else if ( !Q_stricmp( token, "vector" ) ) else if ( !Q_stricmp( token, "vector" ) )
{ {
ParseVector( text, 3, stage->bundle[bundleNum].tcGenVectors[0] ); ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] );
ParseVector( text, 3, stage->bundle[bundleNum].tcGenVectors[1] ); ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] );
stage->bundle[bundleNum].tcGen = TCGEN_VECTOR; stage->bundle[0].tcGen = TCGEN_VECTOR;
} }
else else
{ {
@ -1572,39 +1336,6 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
continue; continue;
} }
// IneQuation: nextbundle implementation
else if( !Q_stricmp( token, "nextbundle" ) )
{
bundleNum++;
if( bundleNum >= NUM_TEXTURE_BUNDLES ) {
ri.Printf( PRINT_WARNING, "WARNING: too many texture bundles in shader '%s'\n", shader.name );
return qfalse;
}
continue;
}
// IneQuation: this is not supposed to be here as it is a general shader param, but its absence breaks the Omaha water texture
else if( !Q_stricmp( token, "nopicmip" ) )
{
shader.noPicMip = qtrue;
continue;
}
// whether this shader param will be supported or not remains to be seen
else if( !Q_stricmp( token, "noDepthTest" ) )
{
continue;
}
else if( !Q_stricmp( token, "animMap" ) )
{
// wombat: TODO
if( !Q_stricmp( token, "animMapOnce" ) ) {
shader.flags |= 3;
}
else if( !Q_stricmp( token, "animMapPhase" ) ) {
shader.flags |= 3;
stage->bundle[bundleNum].flags |= 1;
}
continue;
}
else else
{ {
ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name ); ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name );
@ -2090,11 +1821,13 @@ static qboolean ParseShader( char **text )
if (isGL2Sun) if (isGL2Sun)
{ {
token = COM_ParseExt( text, qfalse );
tr.mapLightScale = atof(token);
token = COM_ParseExt( text, qfalse ); token = COM_ParseExt( text, qfalse );
tr.sunShadowScale = atof(token); tr.sunShadowScale = atof(token);
// parse twice, since older shaders may include mapLightScale before sunShadowScale
token = COM_ParseExt( text, qfalse );
if (token[0])
tr.sunShadowScale = atof(token);
} }
SkipRestOfLine( text ); SkipRestOfLine( text );
@ -2254,49 +1987,6 @@ static qboolean ParseShader( char **text )
ParseSort( text ); ParseSort( text );
continue; continue;
} }
// IneQuation: some general shader parms introduced in FAKK2
else if( !Q_stricmp( token, "spriteGen" ) )
{
token = COM_ParseExt( text, qfalse );
if( !token[ 0 ] ) {
ri.Printf( PRINT_WARNING, "WARNING: missing spriteGen parms in shader '%s'\n", shader.name );
continue;
}
if( !Q_stricmp( token, "parallel" ) ) {
shader.sprite.type = SPRITE_PARALLEL;
}
else if( !Q_stricmp( token, "parallel_oriented" ) ) {
shader.sprite.type = SPRITE_PARALLEL_ORIENTED;
}
else if( !Q_stricmp( token, "parallel_upright" ) ) {
shader.sprite.type = SPRITE_PARALLEL_UPRIGHT;
}
else if( !Q_stricmp( token, "oriented" ) ) {
shader.sprite.type = SPRITE_ORIENTED;
}
else
ri.Printf( PRINT_WARNING, "WARNING: invalid spriteGen parm '%s' in shader '%s'\n", token, shader.name );
continue;
}
else if( !Q_stricmp( token, "spriteScale" ) ) {
token = COM_ParseExt( text, qfalse );
if( !token[ 0 ] ) {
ri.Printf( PRINT_WARNING, "WARNING: missing spriteScale parm in shader '%s'\n", shader.name );
continue;
}
shader.sprite.scale = atof( token );
continue;
}
// force32bit, not needed anymore
else if( !Q_stricmp( token, "force32bit" ) )
{
shader.force32bit = qtrue;
continue;
}
else if( !Q_stricmp( token, "noMerge" ) ) {
shader.flags |= 1;
continue;
}
else else
{ {
ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name ); ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name );
@ -2425,12 +2115,10 @@ static void ComputeVertexAttribs(void)
{ {
shader.vertexAttribs |= ATTR_NORMAL; shader.vertexAttribs |= ATTR_NORMAL;
#ifdef USE_VERT_TANGENT_SPACE
if ((pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && !(r_normalMapping->integer == 0 && r_specularMapping->integer == 0)) if ((pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && !(r_normalMapping->integer == 0 && r_specularMapping->integer == 0))
{ {
shader.vertexAttribs |= ATTR_TANGENT; shader.vertexAttribs |= ATTR_TANGENT;
} }
#endif
switch (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) switch (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK)
{ {
@ -2529,7 +2217,7 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse,
defs |= LIGHTDEF_USE_LIGHT_VERTEX; defs |= LIGHTDEF_USE_LIGHT_VERTEX;
} }
if (r_deluxeMapping->integer && tr.worldDeluxeMapping && lightmap) if (r_deluxeMapping->integer && tr.worldDeluxeMapping && lightmap && shader.lightmapIndex >= 0)
{ {
//ri.Printf(PRINT_ALL, ", deluxemap"); //ri.Printf(PRINT_ALL, ", deluxemap");
diffuse->bundle[TB_DELUXEMAP] = lightmap->bundle[0]; diffuse->bundle[TB_DELUXEMAP] = lightmap->bundle[0];
@ -2552,12 +2240,24 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse,
{ {
char normalName[MAX_QPATH]; char normalName[MAX_QPATH];
image_t *normalImg; image_t *normalImg;
imgFlags_t normalFlags = (diffuseImg->flags & ~(IMGFLAG_GENNORMALMAP | IMGFLAG_SRGB)) | IMGFLAG_NOLIGHTSCALE; imgFlags_t normalFlags = (diffuseImg->flags & ~IMGFLAG_GENNORMALMAP) | IMGFLAG_NOLIGHTSCALE;
// try a normalheight image first
COM_StripExtension(diffuseImg->imgName, normalName, MAX_QPATH); COM_StripExtension(diffuseImg->imgName, normalName, MAX_QPATH);
Q_strcat(normalName, MAX_QPATH, "_n"); Q_strcat(normalName, MAX_QPATH, "_nh");
normalImg = R_FindImageFile(normalName, IMGTYPE_NORMAL, normalFlags); normalImg = R_FindImageFile(normalName, IMGTYPE_NORMALHEIGHT, normalFlags);
if (normalImg)
{
parallax = qtrue;
}
else
{
// try a normal image ("_n" suffix)
normalName[strlen(normalName) - 1] = '\0';
normalImg = R_FindImageFile(normalName, IMGTYPE_NORMAL, normalFlags);
}
if (normalImg) if (normalImg)
{ {
@ -2575,12 +2275,33 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse,
if (r_specularMapping->integer) if (r_specularMapping->integer)
{ {
image_t *diffuseImg;
if (specular) if (specular)
{ {
//ri.Printf(PRINT_ALL, ", specularmap %s", specular->bundle[0].image[0]->imgName); //ri.Printf(PRINT_ALL, ", specularmap %s", specular->bundle[0].image[0]->imgName);
diffuse->bundle[TB_SPECULARMAP] = specular->bundle[0]; diffuse->bundle[TB_SPECULARMAP] = specular->bundle[0];
VectorCopy4(specular->specularScale, diffuse->specularScale); VectorCopy4(specular->specularScale, diffuse->specularScale);
} }
else if ((lightmap || useLightVector || useLightVertex) && (diffuseImg = diffuse->bundle[TB_DIFFUSEMAP].image[0]))
{
char specularName[MAX_QPATH];
image_t *specularImg;
imgFlags_t specularFlags = (diffuseImg->flags & ~IMGFLAG_GENNORMALMAP) | IMGFLAG_NOLIGHTSCALE;
COM_StripExtension(diffuseImg->imgName, specularName, MAX_QPATH);
Q_strcat(specularName, MAX_QPATH, "_s");
specularImg = R_FindImageFile(specularName, IMGTYPE_COLORALPHA, specularFlags);
if (specularImg)
{
diffuse->bundle[TB_SPECULARMAP] = diffuse->bundle[0];
diffuse->bundle[TB_SPECULARMAP].numImageAnimations = 0;
diffuse->bundle[TB_SPECULARMAP].image[0] = specularImg;
VectorSet4(diffuse->specularScale, 1.0f, 1.0f, 1.0f, 1.0f);
}
}
} }
if (tcgen || diffuse->bundle[0].numTexMods) if (tcgen || diffuse->bundle[0].numTexMods)
@ -2685,6 +2406,8 @@ static int CollapseStagesToGLSL(void)
if (!skip) if (!skip)
{ {
qboolean usedLightmap = qfalse;
for (i = 0; i < MAX_SHADER_STAGES; i++) for (i = 0; i < MAX_SHADER_STAGES; i++)
{ {
shaderStage_t *pStage = &stages[i]; shaderStage_t *pStage = &stages[i];
@ -2743,7 +2466,16 @@ static int CollapseStagesToGLSL(void)
case ST_COLORMAP: case ST_COLORMAP:
if (pStage2->bundle[0].tcGen == TCGEN_LIGHTMAP) if (pStage2->bundle[0].tcGen == TCGEN_LIGHTMAP)
{ {
lightmap = pStage2; int blendBits = pStage->stateBits & ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
// Only add lightmap to blendfunc filter stage if it's the first time lightmap is used
// otherwise it will cause the shader to be darkened by the lightmap multiple times.
if (!usedLightmap || (blendBits != (GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO)
&& blendBits != (GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR)))
{
lightmap = pStage2;
usedLightmap = qtrue;
}
} }
break; break;
@ -2898,7 +2630,6 @@ sortedIndex.
*/ */
static void FixRenderCommandList( int newShader ) { static void FixRenderCommandList( int newShader ) {
renderCommandList_t *cmdList = &backEndData->commands; renderCommandList_t *cmdList = &backEndData->commands;
qboolean staticModel;
if( cmdList ) { if( cmdList ) {
const void *curCmd = cmdList->cmds; const void *curCmd = cmdList->cmds;
@ -2932,7 +2663,7 @@ static void FixRenderCommandList( int newShader ) {
const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd; const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd;
for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) { for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) {
R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap, &pshadowMap, &staticModel ); R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap, &pshadowMap );
sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1)); sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1));
if( sortedIndex >= newShader ) { if( sortedIndex >= newShader ) {
sortedIndex++; sortedIndex++;
@ -3040,11 +2771,8 @@ static shader_t *GeneratePermanentShader( void ) {
for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) { for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) {
size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t ); size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t );
newShader->stages[i]->bundle[b].texMods = ri.Hunk_Alloc( size );
if( size ) { Com_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size );
newShader->stages[ i ]->bundle[ b ].texMods = ri.Hunk_Alloc( size );
Com_Memcpy( newShader->stages[ i ]->bundle[ b ].texMods, stages[ i ].bundle[ b ].texMods, size );
}
} }
} }
@ -3062,7 +2790,7 @@ static shader_t *GeneratePermanentShader( void ) {
VertexLightingCollapse VertexLightingCollapse
If vertex lighting is enabled, only render a single If vertex lighting is enabled, only render a single
pass, trying to guess which is the correct one to best aproximate pass, trying to guess which is the correct one to best approximate
what it is supposed to look like. what it is supposed to look like.
================= =================
*/ */
@ -3166,10 +2894,17 @@ static void InitShader( const char *name, int lightmapIndex ) {
// default normal/specular // default normal/specular
VectorSet4(stages[i].normalScale, 0.0f, 0.0f, 0.0f, 0.0f); VectorSet4(stages[i].normalScale, 0.0f, 0.0f, 0.0f, 0.0f);
stages[i].specularScale[0] = if (r_pbr->integer)
stages[i].specularScale[1] = {
stages[i].specularScale[2] = r_baseSpecular->value; stages[i].specularScale[0] = r_baseGloss->value;
stages[i].specularScale[3] = r_baseGloss->value; }
else
{
stages[i].specularScale[0] =
stages[i].specularScale[1] =
stages[i].specularScale[2] = r_baseSpecular->value;
stages[i].specularScale[3] = r_baseGloss->value;
}
} }
} }
@ -3333,9 +3068,7 @@ static shader_t *FinishShader( void ) {
// //
// look for multitexture potential // look for multitexture potential
// //
if ( qglActiveTextureARB ) { stage = CollapseStagesToGLSL();
stage = CollapseStagesToGLSL();
}
if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) { if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) {
if (vertexLightmap) { if (vertexLightmap) {
@ -3418,7 +3151,7 @@ static char *FindShaderInShaderText( const char *shadername ) {
} }
else { else {
// skip the definition // skip the definition
SkipBracedSection( &p ); SkipBracedSection( &p, 0 );
} }
} }
@ -3477,18 +3210,18 @@ be defined for every single image used in the game, three default
shader behaviors can be auto-created for any image: shader behaviors can be auto-created for any image:
If lightmapIndex == LIGHTMAP_NONE, then the image will have If lightmapIndex == LIGHTMAP_NONE, then the image will have
dynamic diffuse lighting applied to it, as apropriate for most dynamic diffuse lighting applied to it, as appropriate for most
entity skin surfaces. entity skin surfaces.
If lightmapIndex == LIGHTMAP_2D, then the image will be used If lightmapIndex == LIGHTMAP_2D, then the image will be used
for 2D rendering unless an explicit shader is found for 2D rendering unless an explicit shader is found
If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use
the vertex rgba modulate values, as apropriate for misc_model the vertex rgba modulate values, as appropriate for misc_model
pre-lit surfaces. pre-lit surfaces.
Other lightmapIndex values will have a lightmap stage created Other lightmapIndex values will have a lightmap stage created
and src*dest blending applied with the texture, as apropriate for and src*dest blending applied with the texture, as appropriate for
most world construction surfaces. most world construction surfaces.
=============== ===============
@ -3987,7 +3720,7 @@ static void ScanAndLoadShaderFiles( void )
break; break;
} }
if(!SkipBracedSectionEx(&p, 1)) if(!SkipBracedSection(&p, 1))
{ {
ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing closing brace.\n", ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing closing brace.\n",
filename, shaderName, shaderLine); filename, shaderName, shaderLine);
@ -4038,7 +3771,7 @@ static void ScanAndLoadShaderFiles( void )
hash = generateHashValue(token, MAX_SHADERTEXT_HASH); hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
shaderTextHashTableSizes[hash]++; shaderTextHashTableSizes[hash]++;
size++; size++;
SkipBracedSection(&p); SkipBracedSection(&p, 0);
} }
size += MAX_SHADERTEXT_HASH; size += MAX_SHADERTEXT_HASH;
@ -4064,7 +3797,7 @@ static void ScanAndLoadShaderFiles( void )
hash = generateHashValue(token, MAX_SHADERTEXT_HASH); hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp; shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp;
SkipBracedSection(&p); SkipBracedSection(&p, 0);
} }
return; return;

View file

@ -43,8 +43,8 @@ typedef struct {
static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS]; static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS];
static int numEdgeDefs[SHADER_MAX_VERTEXES]; static int numEdgeDefs[SHADER_MAX_VERTEXES];
static int facing[SHADER_MAX_INDEXES/3]; //static int facing[SHADER_MAX_INDEXES/3];
static vec3_t shadowXyz[SHADER_MAX_VERTEXES]; //static vec3_t shadowXyz[SHADER_MAX_VERTEXES];
void R_AddEdgeDef( int i1, int i2, int facing ) { void R_AddEdgeDef( int i1, int i2, int facing ) {
int c; int c;
@ -60,6 +60,8 @@ void R_AddEdgeDef( int i1, int i2, int facing ) {
} }
void R_RenderShadowEdges( void ) { void R_RenderShadowEdges( void ) {
// FIXME: implement this
#if 0
int i; int i;
#if 0 #if 0
@ -138,6 +140,7 @@ void R_RenderShadowEdges( void ) {
} }
} }
#endif #endif
#endif
} }
/* /*
@ -153,6 +156,8 @@ triangleFromEdge[ v1 ][ v2 ]
================= =================
*/ */
void RB_ShadowTessEnd( void ) { void RB_ShadowTessEnd( void ) {
// FIXME: implement this
#if 0
int i; int i;
int numTris; int numTris;
vec3_t lightDir; vec3_t lightDir;
@ -162,7 +167,7 @@ void RB_ShadowTessEnd( void ) {
return; return;
} }
VectorCopy( backEnd.currentEntity->lightDir, lightDir ); VectorCopy( backEnd.currentEntity->modelLightDir, lightDir );
// project vertexes away from light direction // project vertexes away from light direction
for ( i = 0 ; i < tess.numVertexes ; i++ ) { for ( i = 0 ; i < tess.numVertexes ; i++ ) {
@ -206,7 +211,7 @@ void RB_ShadowTessEnd( void ) {
// draw the silhouette edges // draw the silhouette edges
GL_Bind( tr.whiteImage ); GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
qglColor3f( 0.2f, 0.2f, 0.2f ); qglColor3f( 0.2f, 0.2f, 0.2f );
@ -230,6 +235,7 @@ void RB_ShadowTessEnd( void ) {
// reenable writing to the color buffer // reenable writing to the color buffer
qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]); qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]);
#endif
} }
@ -244,6 +250,8 @@ overlap and double darken.
================= =================
*/ */
void RB_ShadowFinish( void ) { void RB_ShadowFinish( void ) {
// FIXME: implement this
#if 0
if ( r_shadows->integer != 2 ) { if ( r_shadows->integer != 2 ) {
return; return;
} }
@ -253,10 +261,9 @@ void RB_ShadowFinish( void ) {
qglEnable( GL_STENCIL_TEST ); qglEnable( GL_STENCIL_TEST );
qglStencilFunc( GL_NOTEQUAL, 0, 255 ); qglStencilFunc( GL_NOTEQUAL, 0, 255 );
qglDisable (GL_CLIP_PLANE0);
GL_Cull( CT_TWO_SIDED ); GL_Cull( CT_TWO_SIDED );
GL_Bind( tr.whiteImage ); GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
qglLoadIdentity (); qglLoadIdentity ();
@ -275,54 +282,5 @@ void RB_ShadowFinish( void ) {
qglColor4f(1,1,1,1); qglColor4f(1,1,1,1);
qglDisable( GL_STENCIL_TEST ); qglDisable( GL_STENCIL_TEST );
}
/*
=================
RB_ProjectionShadowDeform
=================
*/
void RB_ProjectionShadowDeform( void ) {
// FIXME: unimplemented
#if 0
float *xyz;
int i;
float h;
vec3_t ground;
vec3_t light;
float groundDist;
float d;
vec3_t lightDir;
xyz = ( float * ) tess.xyz;
ground[0] = backEnd.or.axis[0][2];
ground[1] = backEnd.or.axis[1][2];
ground[2] = backEnd.or.axis[2][2];
groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane;
VectorCopy( backEnd.currentEntity->lightDir, lightDir );
d = DotProduct( lightDir, ground );
// don't let the shadows get too long or go negative
if ( d < 0.5 ) {
VectorMA( lightDir, (0.5 - d), ground, lightDir );
d = DotProduct( lightDir, ground );
}
d = 1.0 / d;
light[0] = lightDir[0] * d;
light[1] = lightDir[1] * d;
light[2] = lightDir[2] * d;
for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
h = DotProduct( xyz, ground ) + groundDist;
xyz[0] -= light[0] * h;
xyz[1] -= light[1] * h;
xyz[2] -= light[2] * h;
}
#endif #endif
} }

View file

@ -366,15 +366,13 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max
int s, t; int s, t;
int firstVertex = tess.numVertexes; int firstVertex = tess.numVertexes;
//int firstIndex = tess.numIndexes; //int firstIndex = tess.numIndexes;
int minIndex = tess.minIndex;
int maxIndex = tess.maxIndex;
vec4_t color; vec4_t color;
//tess.numVertexes = 0; //tess.numVertexes = 0;
//tess.numIndexes = 0; //tess.numIndexes = 0;
tess.firstIndex = tess.numIndexes; tess.firstIndex = tess.numIndexes;
GL_Bind( image ); GL_BindToTMU( image, TB_COLORMAP );
GL_Cull( CT_TWO_SIDED ); GL_Cull( CT_TWO_SIDED );
for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
@ -386,8 +384,8 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max
tess.xyz[tess.numVertexes][2] = s_skyPoints[t][s][2]; tess.xyz[tess.numVertexes][2] = s_skyPoints[t][s][2];
tess.xyz[tess.numVertexes][3] = 1.0; tess.xyz[tess.numVertexes][3] = 1.0;
tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; tess.texCoords[tess.numVertexes][0] = s_skyTexCoords[t][s][0];
tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; tess.texCoords[tess.numVertexes][1] = s_skyTexCoords[t][s][1];
tess.numVertexes++; tess.numVertexes++;
@ -417,9 +415,6 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max
} }
} }
tess.minIndex = firstVertex;
tess.maxIndex = tess.numVertexes;
// FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function
RB_UpdateTessVao(ATTR_POSITION | ATTR_TEXCOORD); RB_UpdateTessVao(ATTR_POSITION | ATTR_TEXCOORD);
/* /*
@ -448,7 +443,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max
color[0] = color[0] =
color[1] = color[1] =
color[2] = backEnd.refdef.colorScale; color[2] =
color[3] = 1.0f; color[3] = 1.0f;
GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color); GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color);
@ -463,9 +458,11 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max
VectorSet4(vector, 0.0, 0.0, 0.0, 0.0); VectorSet4(vector, 0.0, 0.0, 0.0, 0.0);
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector); GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector);
GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
} }
R_DrawElementsVao(tess.numIndexes - tess.firstIndex, tess.firstIndex, tess.minIndex, tess.maxIndex); R_DrawElements(tess.numIndexes - tess.firstIndex, tess.firstIndex);
//qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(glIndex_t))); //qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(glIndex_t)));
@ -475,8 +472,6 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max
tess.numIndexes = tess.firstIndex; tess.numIndexes = tess.firstIndex;
tess.numVertexes = firstVertex; tess.numVertexes = firstVertex;
tess.firstIndex = 0; tess.firstIndex = 0;
tess.minIndex = minIndex;
tess.maxIndex = maxIndex;
} }
static void DrawSkyBox( shader_t *shader ) static void DrawSkyBox( shader_t *shader )
@ -563,8 +558,8 @@ static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean ad
for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
{ {
VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] ); VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; tess.texCoords[tess.numVertexes][0] = s_skyTexCoords[t][s][0];
tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; tess.texCoords[tess.numVertexes][1] = s_skyTexCoords[t][s][1];
tess.numVertexes++; tess.numVertexes++;
@ -871,6 +866,7 @@ void RB_StageIteratorSky( void ) {
mat4_t oldmodelview; mat4_t oldmodelview;
GL_State( 0 ); GL_State( 0 );
GL_Cull( CT_FRONT_SIDED );
//qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); //qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
{ {

View file

@ -1,6 +1,6 @@
/* /*
=========================================================================== ===========================================================================
Copyright (C) 2015 the OpenMoHAA team Copyright (C) 2023 the OpenMoHAA team
This file is part of OpenMoHAA source code. This file is part of OpenMoHAA source code.
@ -20,15 +20,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=========================================================================== ===========================================================================
*/ */
// tr_terrain.c : Terrain rendering // tr_sphere_shade.cpp -- sphere shade
#include "tr_local.h" #include "tr_local.h"
/* int R_GatherLightSources(const vec3_t vPos, vec3_t* pvLightPos, vec3_t* pvLightIntensity, int iMaxLights)
============= {
R_AddTerrainSurfaces // FIXME: unimplemented
============= return 0;
*/
void R_AddTerrainSurfaces( void ) {
// FIXME
} }

View file

@ -1,66 +0,0 @@
/*
===========================================================================
Copyright (C) 2010 su44
This file is part of OpenMoHAA source code.
OpenMoHAA 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.
OpenMoHAA 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 OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_sprite.c - MoHAA sprite system
#include "tr_local.h"
/*
=====================
SPR_RegisterSprite
=====================
*/
sprite_t *SPR_RegisterSprite(const char *name)
{
image_t *spriteImage;
shader_t *shader;
sprite_t *spr;
char shadername[256];
COM_StripExtension(name,shadername,sizeof(shadername));
shader = R_FindShader(shadername,-1,qfalse);
if(shader) {
spriteImage = 0;
if(shader->stages[0])
spriteImage = shader->stages[0]->bundle[0].image[0];
if ( !spriteImage ) {
ri.Printf(1, "Could not find image for sprite in shader %s\n", name);
return 0;
}
spr = ri.Hunk_Alloc(sizeof(sprite_t));
spr->height = spriteImage->height;
spr->width = spriteImage->width;
spr->origin_x = spr->width * 0.5;
spr->origin_y = spr->height * 0.5;
spr->shader = shader;
spr->scale = spr->shader->sprite.scale;
return spr;
}
return 0;
}
/*
=====================
RB_DrawSprite
=====================
*/
void RB_DrawSprite( const refSprite_t *spr ) {
// FIXME: stub
}

View file

@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// tr_staticmodels.cpp -- static model rendering // tr_staticmodels.cpp -- static model rendering
#include "tr_local.h" #include "tr_local.h"
#include "tiki.h"
#define MAX_STATIC_MODELS_SURFS 8192 #define MAX_STATIC_MODELS_SURFS 8192
@ -363,8 +364,6 @@ void R_AddStaticModelSurfaces( void ) {
} }
} }
tr.currentEntityNum = REFENTITYNUM_WORLD;
tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
tr.shiftedIsStatic = 0; tr.shiftedIsStatic = 0;
} }
/* /*
@ -385,89 +384,85 @@ void RB_StaticMesh( staticSurface_t *staticSurf ) {
int baseIndex, baseVertex; int baseIndex, baseVertex;
short collapse[ 1000 ]; short collapse[ 1000 ];
RB_CheckVao( tess.vao ); tiki = backEnd.currentStaticModel->tiki;
surf = staticSurf->surface;
tiki = backEnd.currentStaticModel->tiki; assert(surf->pStaticXyz);
surf = staticSurf->surface;
assert( surf->pStaticXyz ); meshNum = staticSurf->meshNum;
skelmodel = TIKI_GetSkel(tiki->mesh[meshNum]);
meshNum = staticSurf->meshNum; // FIXME: LOD
skelmodel = TIKI_GetSkel( tiki->mesh[ meshNum ] ); render_count = surf->numVerts;
// FIXME: LOD if (tess.numVertexes + render_count >= TIKI_MAX_VERTEXES ||
render_count = surf->numVerts; tess.numIndexes + surf->numTriangles >= TIKI_MAX_TRIANGLES * 3) {
RB_CHECKOVERFLOW(render_count, surf->numTriangles);
}
if( tess.numVertexes + render_count >= TIKI_MAX_VERTEXES || collapse_map = surf->pCollapse;
tess.numIndexes + surf->numTriangles >= TIKI_MAX_TRIANGLES * 3 ) { triangles = surf->pTriangles;
RB_CHECKOVERFLOW( render_count, surf->numTriangles ); indexes = surf->numTriangles * 3;
} baseIndex = tess.numIndexes;
baseVertex = tess.numVertexes;
tess.numVertexes += render_count;
collapse_map = surf->pCollapse; if (render_count == surf->numVerts)
triangles = surf->pTriangles; {
indexes = surf->numTriangles * 3; for (j = 0; j < indexes; j++) {
baseIndex = tess.numIndexes; tess.indexes[baseIndex + j] = baseVertex + triangles[j];
baseVertex = tess.numVertexes; }
tess.numVertexes += render_count; tess.numIndexes += indexes;
}
else
{
for (i = 0; i < render_count; i++) {
collapse[i] = i;
}
for (i = 0; i < surf->numVerts; i++) {
collapse[i] = collapse[collapse_map[i]];
}
if( render_count == surf->numVerts ) for (j = 0; j < indexes; j += 3)
{ {
for( j = 0; j < indexes; j++ ) { if (collapse[triangles[j]] == collapse[triangles[j + 1]] ||
tess.indexes[ baseIndex + j ] = baseVertex + triangles[ j ]; collapse[triangles[j + 1]] == collapse[triangles[j + 2]] ||
} collapse[triangles[j + 2]] == collapse[triangles[j]])
tess.numIndexes += indexes; {
} break;
else }
{
for( i = 0; i < render_count; i++ ) {
collapse[ i ] = i;
}
for( i = 0; i < surf->numVerts; i++ ) {
collapse[ i ] = collapse[ collapse_map[ i ] ];
}
for( j = 0; j < indexes; j += 3 ) tess.indexes[baseIndex + j] = baseVertex + collapse[triangles[j]];
{ tess.indexes[baseIndex + j + 1] = baseVertex + collapse[triangles[j + 1]];
if( collapse[ triangles[ j ] ] == collapse[ triangles[ j + 1 ] ] || tess.indexes[baseIndex + j + 2] = baseVertex + collapse[triangles[j + 2]];
collapse[ triangles[ j + 1 ] ] == collapse[ triangles[ j + 2 ] ] || }
collapse[ triangles[ j + 2 ] ] == collapse[ triangles[ j ] ] ) tess.numIndexes += j;
{ }
break;
}
tess.indexes[ baseIndex + j ] = baseVertex + collapse[ triangles[ j ] ]; for (j = 0; j < render_count; j++) {
tess.indexes[ baseIndex + j + 1 ] = baseVertex + collapse[ triangles[ j + 1 ] ]; Vector4Copy(surf->pStaticXyz[j], tess.xyz[baseVertex + j]);
tess.indexes[ baseIndex + j + 2 ] = baseVertex + collapse[ triangles[ j + 2 ] ]; Vector4Copy(surf->pStaticNormal[j], tess.normal[baseVertex + j]);
} tess.texCoords[baseVertex + j][0] = surf->pStaticTexCoords[j][0][0];
tess.numIndexes += j; tess.texCoords[baseVertex + j][1] = surf->pStaticTexCoords[j][0][1];
} }
for( j = 0; j < render_count; j++ ) { if (backEndData->staticModels) {
Vector4Copy( surf->pStaticXyz[ j ], tess.xyz[ baseVertex + j ] ); color4ub_t* in = (color4ub_t*)&backEndData->staticModelData[backEnd.currentStaticModel->firstVertexData + staticSurf->ofsStaticData];
R_VaoPackNormal( ( byte * )&tess.normal[ baseVertex + j ], surf->pStaticNormal[ j ] );
tess.texCoords[ baseVertex + j ][ 0 ][ 0 ] = surf->pStaticTexCoords[ j ][ 0 ][ 0 ];
tess.texCoords[ baseVertex + j ][ 0 ][ 1 ] = surf->pStaticTexCoords[ j ][ 0 ][ 1 ];
}
if( backEndData->staticModels ) { for (i = 0; i < render_count; i++, in++)
color4ub_t *in = ( color4ub_t * )&backEndData->staticModelData[ backEnd.currentStaticModel->firstVertexData + staticSurf->ofsStaticData ]; {
vec4_t *out = &tess.vertexColors[ baseVertex ]; tess.color[baseVertex + i][0] = (*in)[0] * 257;
tess.color[baseVertex + i][0] = (*in)[1] * 257;
for( i = 0; i < render_count; i++, in++, out++ ) tess.color[baseVertex + i][0] = (*in)[2] * 257;
{ tess.color[baseVertex + i][0] = 65535;
( *out )[ 0 ] = ( float )( *in )[ i ] / 255.0; }
( *out )[ 1 ] = ( float )( *in )[ i + 1 ] / 255.0; }
( *out )[ 2 ] = ( float )( *in )[ i + 2 ] / 255.0; else {
( *out )[ 3 ] = 1.0; for (i = 0; i < render_count; i++) {
} tess.color[baseVertex + i][0] = 65535;
} else { tess.color[baseVertex + i][1] = 65535;
for( i = 0; i < render_count; i++ ) { tess.color[baseVertex + i][2] = 65535;
tess.vertexColors[ baseVertex + i ][ 0 ] = 1.0; tess.color[baseVertex + i][3] = 65535;
tess.vertexColors[ baseVertex + i ][ 1 ] = 1.0; }
tess.vertexColors[ baseVertex + i ][ 2 ] = 1.0; }
tess.vertexColors[ baseVertex + i ][ 3 ] = 1.0;
}
}
tess.vertexColorValid = qtrue;
} }

View file

@ -23,8 +23,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_local.h" #include "tr_local.h"
#if 0
void QDECL Com_Printf( const char *msg, ... ) void QDECL Com_Printf( const char *msg, ... )
{ {
va_list argptr; va_list argptr;
@ -48,5 +46,3 @@ void QDECL Com_Error( int level, const char *error, ... )
ri.Error(level, "%s", text); ri.Error(level, "%s", text);
} }
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,43 +1,44 @@
/* /*
=========================================================================== ===========================================================================
Copyright (C) 1999-2005 Id Software, Inc. Copyright (C) 2023 the OpenMoHAA team
This file is part of Quake III Arena source code. This file is part of OpenMoHAA source code.
Quake III Arena source code is free software; you can redistribute it OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as 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, published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version. or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=========================================================================== ===========================================================================
*/ */
// tr_swipe.cpp -- renderer swipe
// tr_swipe.cpp -- swipe rendering
#include "tr_local.h" #include "tr_local.h"
void RE_SwipeBegin( float thistime, float life, qhandle_t shader ) { void RB_DrawSwipeSurface(surfaceType_t* pswipe) {
// FIXME: stub // FIXME: unimplemented
} }
void RE_SwipePoint( vec3_t point1, vec3_t point2, float time ) { void RE_SwipeBegin(float thistime, float life, qhandle_t shader)
// FIXME: stub {
// FIXME: unimplemented
} }
void RE_SwipeEnd( void ) { void RE_SwipePoint(vec3_t point1, vec3_t point2, float time)
{
// FIXME: unimplemented
} }
void R_AddSwipeSurfaces( void ) { void RE_SwipeEnd()
// FIXME: stub {
} // FIXME: unimplemented
void RB_DrawSwipeSurface( surfaceType_t *pswipe ) {
// FIXME: stub
} }

View file

@ -100,13 +100,12 @@ addTriangle
=============== ===============
*/ */
static void addTriangle( void ) { static void addTriangle( void ) {
tess.texCoords[ tess.numVertexes ][ 0 ][ 0 ] = cntSt[ 0 ]; tess.texCoords[ tess.numVertexes ][ 0 ] = cntSt[ 0 ];
tess.texCoords[ tess.numVertexes ][ 0 ][ 1 ] = cntSt[ 1 ]; tess.texCoords[ tess.numVertexes ][ 1 ] = cntSt[ 1 ];
tess.vertexColors[ tess.numVertexes ][ 0 ] = cntColor[ 0 ]; tess.color[ tess.numVertexes ][ 0 ] = cntColor[ 0 ];
tess.vertexColors[ tess.numVertexes ][ 1 ] = cntColor[ 1 ]; tess.color[ tess.numVertexes ][ 1 ] = cntColor[ 1 ];
tess.vertexColors[ tess.numVertexes ][ 2 ] = cntColor[ 2 ]; tess.color[ tess.numVertexes ][ 2 ] = cntColor[ 2 ];
tess.vertexColors[ tess.numVertexes ][ 3 ] = cntColor[ 3 ]; tess.color[ tess.numVertexes ][ 3 ] = cntColor[ 3 ];
tess.vertexColorValid = qtrue;
tess.numVertexes++; tess.numVertexes++;
} }
@ -224,27 +223,6 @@ void R_DebugRotatedBBox( const vec3_t org, vec3_t ang, vec3_t mins, vec3_t maxs,
} }
/*
===============
RB_Prepare2D
===============
*/
void RB_Prepare2D( void ) {
if( glRefConfig.framebufferObject )
{
if( !tr.renderFbo || backEnd.framePostProcessed )
{
FBO_Bind( NULL );
}
else
{
FBO_Bind( tr.renderFbo );
}
}
RB_SetGL2D();
}
/* /*
=============== ===============
RE_GetShaderWidth RE_GetShaderWidth

View file

@ -23,167 +23,45 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_local.h" #include "tr_local.h"
union pack10_u { void R_VaoPackTangent(int16_t *out, vec4_t v)
struct {
signed int x:10;
signed int y:10;
signed int z:10;
signed int w:2;
} pack;
uint32_t i;
};
union pack8_u {
struct {
signed int x:8;
signed int y:8;
signed int z:8;
signed int w:8;
} pack;
uint32_t i;
};
int R_VaoPackTangent(byte *out, vec4_t v)
{ {
if (glRefConfig.packedNormalDataType == GL_INT_2_10_10_10_REV) out[0] = v[0] * 32767.0f + (v[0] > 0.0f ? 0.5f : -0.5f);
{ out[1] = v[1] * 32767.0f + (v[1] > 0.0f ? 0.5f : -0.5f);
union pack10_u *num = (union pack10_u *)out; out[2] = v[2] * 32767.0f + (v[2] > 0.0f ? 0.5f : -0.5f);
out[3] = v[3] * 32767.0f + (v[3] > 0.0f ? 0.5f : -0.5f);
num->pack.x = v[0] * 511.0f;
num->pack.y = v[1] * 511.0f;
num->pack.z = v[2] * 511.0f;
num->pack.w = v[3];
}
else
{
union pack8_u *num = (union pack8_u *)out;
num->pack.x = v[0] * 127.0f;
num->pack.y = v[1] * 127.0f;
num->pack.z = v[2] * 127.0f;
num->pack.w = v[3] * 127.0f;
}
return 4;
} }
int R_VaoPackNormal(byte *out, vec3_t v) void R_VaoPackNormal(int16_t *out, vec3_t v)
{ {
if (glRefConfig.packedNormalDataType == GL_INT_2_10_10_10_REV) out[0] = v[0] * 32767.0f + (v[0] > 0.0f ? 0.5f : -0.5f);
{ out[1] = v[1] * 32767.0f + (v[1] > 0.0f ? 0.5f : -0.5f);
union pack10_u *num = (union pack10_u *)out; out[2] = v[2] * 32767.0f + (v[2] > 0.0f ? 0.5f : -0.5f);
out[3] = 0;
num->pack.x = v[0] * 511.0f;
num->pack.y = v[1] * 511.0f;
num->pack.z = v[2] * 511.0f;
num->pack.w = 0;
}
else
{
union pack8_u *num = (union pack8_u *)out;
num->pack.x = v[0] * 127.0f;
num->pack.y = v[1] * 127.0f;
num->pack.z = v[2] * 127.0f;
num->pack.w = 0;
}
return 4;
} }
int R_VaoPackTexCoord(byte *out, vec2_t st) void R_VaoPackColor(uint16_t *out, vec4_t c)
{ {
if (glRefConfig.packedTexcoordDataType == GL_HALF_FLOAT) out[0] = c[0] * 65535.0f + 0.5f;
{ out[1] = c[1] * 65535.0f + 0.5f;
uint16_t *num = (uint16_t *)out; out[2] = c[2] * 65535.0f + 0.5f;
out[3] = c[3] * 65535.0f + 0.5f;
*num++ = FloatToHalf(st[0]);
*num++ = FloatToHalf(st[1]);
return sizeof(*num) * 2;
}
else
{
float *num = (float *)out;
*num++ = st[0];
*num++ = st[1];
return sizeof(*num) * 2;
}
} }
int R_VaoPackColors(byte *out, vec4_t color) void R_VaoUnpackTangent(vec4_t v, int16_t *pack)
{ {
if (glRefConfig.packedTexcoordDataType == GL_HALF_FLOAT) v[0] = pack[0] / 32767.0f;
{ v[1] = pack[1] / 32767.0f;
uint16_t *num = (uint16_t *)out; v[2] = pack[2] / 32767.0f;
v[3] = pack[3] / 32767.0f;
*num++ = FloatToHalf(color[0]);
*num++ = FloatToHalf(color[1]);
*num++ = FloatToHalf(color[2]);
*num++ = FloatToHalf(color[3]);
return sizeof(*num) * 4;
}
else
{
float *num = (float *)out;
*num++ = color[0];
*num++ = color[1];
*num++ = color[2];
*num++ = color[3];
return sizeof(*num) * 4;
}
} }
void R_VaoUnpackNormal(vec3_t v, int16_t *pack)
void R_VaoUnpackTangent(vec4_t v, uint32_t b)
{ {
if (glRefConfig.packedNormalDataType == GL_INT_2_10_10_10_REV) v[0] = pack[0] / 32767.0f;
{ v[1] = pack[1] / 32767.0f;
union pack10_u *num = (union pack10_u *)&b; v[2] = pack[2] / 32767.0f;
v[0] = num->pack.x / 511.0f;
v[1] = num->pack.y / 511.0f;
v[2] = num->pack.z / 511.0f;
v[3] = num->pack.w;
}
else
{
union pack8_u *num = (union pack8_u *)&b;
v[0] = num->pack.x / 127.0f;
v[1] = num->pack.y / 127.0f;
v[2] = num->pack.z / 127.0f;
v[3] = num->pack.w / 127.0f;
}
} }
void R_VaoUnpackNormal(vec3_t v, uint32_t b)
{
if (glRefConfig.packedNormalDataType == GL_INT_2_10_10_10_REV)
{
union pack10_u *num = (union pack10_u *)&b;
v[0] = num->pack.x / 511.0f;
v[1] = num->pack.y / 511.0f;
v[2] = num->pack.z / 511.0f;
}
else
{
union pack8_u *num = (union pack8_u *)&b;
v[0] = num->pack.x / 127.0f;
v[1] = num->pack.y / 127.0f;
v[2] = num->pack.z / 127.0f;
}
}
void Vao_SetVertexPointers(vao_t *vao) void Vao_SetVertexPointers(vao_t *vao)
{ {
int attribIndex; int attribIndex;
@ -196,9 +74,9 @@ void Vao_SetVertexPointers(vao_t *vao)
if (vAtb->enabled) if (vAtb->enabled)
{ {
qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset)); qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset));
if (glRefConfig.vertexArrayObject || !(glState.vertexAttribsEnabled & attribBit)) if (glRefConfig.vertexArrayObject || !(glState.vertexAttribsEnabled & attribBit))
qglEnableVertexAttribArrayARB(attribIndex); qglEnableVertexAttribArray(attribIndex);
if (!glRefConfig.vertexArrayObject || vao == tess.vao) if (!glRefConfig.vertexArrayObject || vao == tess.vao)
glState.vertexAttribsEnabled |= attribBit; glState.vertexAttribsEnabled |= attribBit;
@ -208,7 +86,7 @@ void Vao_SetVertexPointers(vao_t *vao)
// don't disable vertex attribs when using vertex array objects // don't disable vertex attribs when using vertex array objects
// Vao_SetVertexPointers is only called during init when using VAOs, and vertex attribs start disabled anyway // Vao_SetVertexPointers is only called during init when using VAOs, and vertex attribs start disabled anyway
if (!glRefConfig.vertexArrayObject && (glState.vertexAttribsEnabled & attribBit)) if (!glRefConfig.vertexArrayObject && (glState.vertexAttribsEnabled & attribBit))
qglDisableVertexAttribArrayARB(attribIndex); qglDisableVertexAttribArray(attribIndex);
if (!glRefConfig.vertexArrayObject || vao == tess.vao) if (!glRefConfig.vertexArrayObject || vao == tess.vao)
glState.vertexAttribsEnabled &= ~attribBit; glState.vertexAttribsEnabled &= ~attribBit;
@ -229,15 +107,15 @@ vao_t *R_CreateVao(const char *name, byte *vertexes, int vertexesSize, byte *ind
switch (usage) switch (usage)
{ {
case VAO_USAGE_STATIC: case VAO_USAGE_STATIC:
glUsage = GL_STATIC_DRAW_ARB; glUsage = GL_STATIC_DRAW;
break; break;
case VAO_USAGE_DYNAMIC: case VAO_USAGE_DYNAMIC:
glUsage = GL_DYNAMIC_DRAW_ARB; glUsage = GL_DYNAMIC_DRAW;
break; break;
default: default:
Com_Error(ERR_FATAL, "bad vaoUsage_t given: %i", usage); ri.Error(ERR_FATAL, "bad vaoUsage_t given: %i", usage);
return NULL; return NULL;
} }
@ -262,25 +140,25 @@ vao_t *R_CreateVao(const char *name, byte *vertexes, int vertexesSize, byte *ind
if (glRefConfig.vertexArrayObject) if (glRefConfig.vertexArrayObject)
{ {
qglGenVertexArraysARB(1, &vao->vao); qglGenVertexArrays(1, &vao->vao);
qglBindVertexArrayARB(vao->vao); qglBindVertexArray(vao->vao);
} }
vao->vertexesSize = vertexesSize; vao->vertexesSize = vertexesSize;
qglGenBuffersARB(1, &vao->vertexesVBO); qglGenBuffers(1, &vao->vertexesVBO);
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO); qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO);
qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexesSize, vertexes, glUsage); qglBufferData(GL_ARRAY_BUFFER, vertexesSize, vertexes, glUsage);
vao->indexesSize = indexesSize; vao->indexesSize = indexesSize;
qglGenBuffersARB(1, &vao->indexesIBO); qglGenBuffers(1, &vao->indexesIBO);
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesIBO); qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO);
qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); qglBufferData(GL_ELEMENT_ARRAY_BUFFER, indexesSize, indexes, glUsage);
glState.currentVao = vao; glState.currentVao = vao;
@ -304,7 +182,7 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num
int dataSize; int dataSize;
int dataOfs; int dataOfs;
int glUsage = GL_STATIC_DRAW_ARB; int glUsage = GL_STATIC_DRAW;
if(!numVertexes || !numIndexes) if(!numVertexes || !numIndexes)
return NULL; return NULL;
@ -330,9 +208,7 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num
// since these vertex attributes are never altered, interleave them // since these vertex attributes are never altered, interleave them
vao->attribs[ATTR_INDEX_POSITION ].enabled = 1; vao->attribs[ATTR_INDEX_POSITION ].enabled = 1;
vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1; vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1;
#ifdef USE_VERT_TANGENT_SPACE
vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1; vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
#endif
vao->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1; vao->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1;
vao->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1; vao->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1;
vao->attribs[ATTR_INDEX_COLOR ].enabled = 1; vao->attribs[ATTR_INDEX_COLOR ].enabled = 1;
@ -347,30 +223,28 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num
vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4; vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4;
vao->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT; vao->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT;
vao->attribs[ATTR_INDEX_NORMAL ].type = glRefConfig.packedNormalDataType; vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT;
vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType; vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT;
vao->attribs[ATTR_INDEX_TEXCOORD ].type = glRefConfig.packedTexcoordDataType; vao->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT;
vao->attribs[ATTR_INDEX_LIGHTCOORD ].type = glRefConfig.packedTexcoordDataType; vao->attribs[ATTR_INDEX_LIGHTCOORD ].type = GL_FLOAT;
vao->attribs[ATTR_INDEX_COLOR ].type = glRefConfig.packedColorDataType; vao->attribs[ATTR_INDEX_COLOR ].type = GL_UNSIGNED_SHORT;
vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = glRefConfig.packedNormalDataType; vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT;
vao->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE; vao->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE;
vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE; vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE;
vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE; vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
vao->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE; vao->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE;
vao->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE; vao->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE;
vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_FALSE; vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_TRUE;
vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE;
vao->attribs[ATTR_INDEX_POSITION ].offset = 0; dataSize = sizeof(verts[0].xyz); vao->attribs[ATTR_INDEX_POSITION ].offset = 0; dataSize = sizeof(verts[0].xyz);
vao->attribs[ATTR_INDEX_NORMAL ].offset = dataSize; dataSize += sizeof(uint32_t); vao->attribs[ATTR_INDEX_NORMAL ].offset = dataSize; dataSize += sizeof(verts[0].normal);
#ifdef USE_VERT_TANGENT_SPACE vao->attribs[ATTR_INDEX_TANGENT ].offset = dataSize; dataSize += sizeof(verts[0].tangent);
vao->attribs[ATTR_INDEX_TANGENT ].offset = dataSize; dataSize += sizeof(uint32_t); vao->attribs[ATTR_INDEX_TEXCOORD ].offset = dataSize; dataSize += sizeof(verts[0].st);
#endif vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = dataSize; dataSize += sizeof(verts[0].lightmap);
vao->attribs[ATTR_INDEX_TEXCOORD ].offset = dataSize; dataSize += glRefConfig.packedTexcoordDataSize; vao->attribs[ATTR_INDEX_COLOR ].offset = dataSize; dataSize += sizeof(verts[0].color);
vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = dataSize; dataSize += glRefConfig.packedTexcoordDataSize; vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(verts[0].lightdir);
vao->attribs[ATTR_INDEX_COLOR ].offset = dataSize; dataSize += glRefConfig.packedColorDataSize;
vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(uint32_t);
vao->attribs[ATTR_INDEX_POSITION ].stride = dataSize; vao->attribs[ATTR_INDEX_POSITION ].stride = dataSize;
vao->attribs[ATTR_INDEX_NORMAL ].stride = dataSize; vao->attribs[ATTR_INDEX_NORMAL ].stride = dataSize;
@ -383,8 +257,8 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num
if (glRefConfig.vertexArrayObject) if (glRefConfig.vertexArrayObject)
{ {
qglGenVertexArraysARB(1, &vao->vao); qglGenVertexArrays(1, &vao->vao);
qglBindVertexArrayARB(vao->vao); qglBindVertexArray(vao->vao);
} }
@ -400,41 +274,45 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num
dataOfs += sizeof(verts[i].xyz); dataOfs += sizeof(verts[i].xyz);
// normal // normal
dataOfs += R_VaoPackNormal(data + dataOfs, verts[i].normal); memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal));
dataOfs += sizeof(verts[i].normal);
#ifdef USE_VERT_TANGENT_SPACE
// tangent // tangent
dataOfs += R_VaoPackTangent(data + dataOfs, verts[i].tangent); memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent));
#endif dataOfs += sizeof(verts[i].tangent);
// texcoords // texcoords
dataOfs += R_VaoPackTexCoord(data + dataOfs, verts[i].st); memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st));
dataOfs += sizeof(verts[i].st);
// lightmap texcoords // lightmap texcoords
dataOfs += R_VaoPackTexCoord(data + dataOfs, verts[i].lightmap); memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap));
dataOfs += sizeof(verts[i].lightmap);
// colors // colors
dataOfs += R_VaoPackColors(data + dataOfs, verts[i].vertexColors); memcpy(data + dataOfs, &verts[i].color, sizeof(verts[i].color));
dataOfs += sizeof(verts[i].color);
// light directions // light directions
dataOfs += R_VaoPackNormal(data + dataOfs, verts[i].lightdir); memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir));
dataOfs += sizeof(verts[i].lightdir);
} }
vao->vertexesSize = dataSize; vao->vertexesSize = dataSize;
qglGenBuffersARB(1, &vao->vertexesVBO); qglGenBuffers(1, &vao->vertexesVBO);
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO); qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO);
qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vao->vertexesSize, data, glUsage); qglBufferData(GL_ARRAY_BUFFER, vao->vertexesSize, data, glUsage);
// create IBO // create IBO
vao->indexesSize = numIndexes * sizeof(glIndex_t); vao->indexesSize = numIndexes * sizeof(glIndex_t);
qglGenBuffersARB(1, &vao->indexesIBO); qglGenBuffers(1, &vao->indexesIBO);
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesIBO); qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO);
qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesSize, indexes, glUsage); qglBufferData(GL_ELEMENT_ARRAY_BUFFER, vao->indexesSize, indexes, glUsage);
Vao_SetVertexPointers(vao); Vao_SetVertexPointers(vao);
@ -480,20 +358,20 @@ void R_BindVao(vao_t * vao)
if (glRefConfig.vertexArrayObject) if (glRefConfig.vertexArrayObject)
{ {
qglBindVertexArrayARB(vao->vao); qglBindVertexArray(vao->vao);
// why you no save GL_ELEMENT_ARRAY_BUFFER binding, Intel? // Intel Graphics doesn't save GL_ELEMENT_ARRAY_BUFFER binding with VAO binding.
if (1) if (glRefConfig.intelGraphics || vao == tess.vao)
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO); qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO);
// tess VAO always has buffers bound // tess VAO always has buffers bound
if (vao == tess.vao) if (vao == tess.vao)
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO); qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO);
} }
else else
{ {
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO); qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO);
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesIBO); qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO);
// tess VAO doesn't have vertex pointers set until data is uploaded // tess VAO doesn't have vertex pointers set until data is uploaded
if (vao != tess.vao) if (vao != tess.vao)
@ -515,15 +393,15 @@ void R_BindNullVao(void)
{ {
if (glRefConfig.vertexArrayObject) if (glRefConfig.vertexArrayObject)
{ {
qglBindVertexArrayARB(0); qglBindVertexArray(0);
// why you no save GL_ELEMENT_ARRAY_BUFFER binding, Intel? // why you no save GL_ELEMENT_ARRAY_BUFFER binding, Intel?
if (1) qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); if (1) qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
} }
else else
{ {
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); qglBindBuffer(GL_ARRAY_BUFFER, 0);
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
} }
glState.currentVao = NULL; glState.currentVao = NULL;
} }
@ -548,11 +426,10 @@ void R_InitVaos(void)
vertexesSize = sizeof(tess.xyz[0]); vertexesSize = sizeof(tess.xyz[0]);
vertexesSize += sizeof(tess.normal[0]); vertexesSize += sizeof(tess.normal[0]);
#ifdef USE_VERT_TANGENT_SPACE
vertexesSize += sizeof(tess.tangent[0]); vertexesSize += sizeof(tess.tangent[0]);
#endif vertexesSize += sizeof(tess.color[0]);
vertexesSize += sizeof(tess.vertexColors[0]); vertexesSize += sizeof(tess.texCoords[0]);
vertexesSize += sizeof(tess.texCoords[0][0]) * 2; vertexesSize += sizeof(tess.lightCoords[0]);
vertexesSize += sizeof(tess.lightdir[0]); vertexesSize += sizeof(tess.lightdir[0]);
vertexesSize *= SHADER_MAX_VERTEXES; vertexesSize *= SHADER_MAX_VERTEXES;
@ -564,9 +441,7 @@ void R_InitVaos(void)
tess.vao->attribs[ATTR_INDEX_POSITION ].enabled = 1; tess.vao->attribs[ATTR_INDEX_POSITION ].enabled = 1;
tess.vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1; tess.vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1;
#ifdef USE_VERT_TANGENT_SPACE
tess.vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1; tess.vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1;
#endif
tess.vao->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1; tess.vao->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1;
tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1; tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1;
tess.vao->attribs[ATTR_INDEX_COLOR ].enabled = 1; tess.vao->attribs[ATTR_INDEX_COLOR ].enabled = 1;
@ -581,57 +456,51 @@ void R_InitVaos(void)
tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4; tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4;
tess.vao->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT; tess.vao->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT;
tess.vao->attribs[ATTR_INDEX_NORMAL ].type = glRefConfig.packedNormalDataType; tess.vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT;
tess.vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType; tess.vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT;
tess.vao->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT; tess.vao->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT;
tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].type = GL_FLOAT; tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].type = GL_FLOAT;
tess.vao->attribs[ATTR_INDEX_COLOR ].type = GL_FLOAT; tess.vao->attribs[ATTR_INDEX_COLOR ].type = GL_UNSIGNED_SHORT;
tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = glRefConfig.packedNormalDataType; tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT;
tess.vao->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE; tess.vao->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE;
tess.vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE; tess.vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE;
tess.vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE; tess.vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE;
tess.vao->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE; tess.vao->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE;
tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE; tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE;
tess.vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_FALSE; tess.vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_TRUE;
tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE;
tess.vao->attribs[ATTR_INDEX_POSITION ].offset = offset; offset += sizeof(tess.xyz[0]) * SHADER_MAX_VERTEXES; tess.vao->attribs[ATTR_INDEX_POSITION ].offset = offset; offset += sizeof(tess.xyz[0]) * SHADER_MAX_VERTEXES;
tess.vao->attribs[ATTR_INDEX_NORMAL ].offset = offset; offset += sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES; tess.vao->attribs[ATTR_INDEX_NORMAL ].offset = offset; offset += sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES;
#ifdef USE_VERT_TANGENT_SPACE tess.vao->attribs[ATTR_INDEX_TANGENT ].offset = offset; offset += sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES;
tess.vao->attribs[ATTR_INDEX_TANGENT ].offset = offset; offset += sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES; tess.vao->attribs[ATTR_INDEX_TEXCOORD ].offset = offset; offset += sizeof(tess.texCoords[0]) * SHADER_MAX_VERTEXES;
#endif tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = offset; offset += sizeof(tess.lightCoords[0]) * SHADER_MAX_VERTEXES;
// these next two are actually interleaved tess.vao->attribs[ATTR_INDEX_COLOR ].offset = offset; offset += sizeof(tess.color[0]) * SHADER_MAX_VERTEXES;
tess.vao->attribs[ATTR_INDEX_TEXCOORD ].offset = offset;
tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = offset + sizeof(tess.texCoords[0][0]);
offset += sizeof(tess.texCoords[0][0]) * 2 * SHADER_MAX_VERTEXES;
tess.vao->attribs[ATTR_INDEX_COLOR ].offset = offset; offset += sizeof(tess.vertexColors[0]) * SHADER_MAX_VERTEXES;
tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = offset; tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = offset;
tess.vao->attribs[ATTR_INDEX_POSITION ].stride = sizeof(tess.xyz[0]); tess.vao->attribs[ATTR_INDEX_POSITION ].stride = sizeof(tess.xyz[0]);
tess.vao->attribs[ATTR_INDEX_NORMAL ].stride = sizeof(tess.normal[0]); tess.vao->attribs[ATTR_INDEX_NORMAL ].stride = sizeof(tess.normal[0]);
#ifdef USE_VERT_TANGENT_SPACE
tess.vao->attribs[ATTR_INDEX_TANGENT ].stride = sizeof(tess.tangent[0]); tess.vao->attribs[ATTR_INDEX_TANGENT ].stride = sizeof(tess.tangent[0]);
#endif tess.vao->attribs[ATTR_INDEX_TEXCOORD ].stride = sizeof(tess.texCoords[0]);
tess.vao->attribs[ATTR_INDEX_COLOR ].stride = sizeof(tess.vertexColors[0]); tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].stride = sizeof(tess.lightCoords[0]);
tess.vao->attribs[ATTR_INDEX_TEXCOORD ].stride = sizeof(tess.texCoords[0][0]) * 2; tess.vao->attribs[ATTR_INDEX_COLOR ].stride = sizeof(tess.color[0]);
tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].stride = sizeof(tess.texCoords[0][0]) * 2;
tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = sizeof(tess.lightdir[0]); tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = sizeof(tess.lightdir[0]);
tess.attribPointers[ATTR_INDEX_POSITION] = tess.xyz; tess.attribPointers[ATTR_INDEX_POSITION] = tess.xyz;
tess.attribPointers[ATTR_INDEX_TEXCOORD] = tess.texCoords;
tess.attribPointers[ATTR_INDEX_NORMAL] = tess.normal; tess.attribPointers[ATTR_INDEX_NORMAL] = tess.normal;
#ifdef USE_VERT_TANGENT_SPACE
tess.attribPointers[ATTR_INDEX_TANGENT] = tess.tangent; tess.attribPointers[ATTR_INDEX_TANGENT] = tess.tangent;
#endif tess.attribPointers[ATTR_INDEX_TEXCOORD] = tess.texCoords;
tess.attribPointers[ATTR_INDEX_COLOR] = tess.vertexColors; tess.attribPointers[ATTR_INDEX_LIGHTCOORD] = tess.lightCoords;
tess.attribPointers[ATTR_INDEX_COLOR] = tess.color;
tess.attribPointers[ATTR_INDEX_LIGHTDIRECTION] = tess.lightdir; tess.attribPointers[ATTR_INDEX_LIGHTDIRECTION] = tess.lightdir;
Vao_SetVertexPointers(tess.vao); Vao_SetVertexPointers(tess.vao);
R_BindNullVao(); R_BindNullVao();
VaoCache_Init();
GL_CheckErrors(); GL_CheckErrors();
} }
@ -654,16 +523,16 @@ void R_ShutdownVaos(void)
vao = tr.vaos[i]; vao = tr.vaos[i];
if(vao->vao) if(vao->vao)
qglDeleteVertexArraysARB(1, &vao->vao); qglDeleteVertexArrays(1, &vao->vao);
if(vao->vertexesVBO) if(vao->vertexesVBO)
{ {
qglDeleteBuffersARB(1, &vao->vertexesVBO); qglDeleteBuffers(1, &vao->vertexesVBO);
} }
if(vao->indexesIBO) if(vao->indexesIBO)
{ {
qglDeleteBuffersARB(1, &vao->indexesIBO); qglDeleteBuffers(1, &vao->indexesIBO);
} }
} }
@ -737,7 +606,7 @@ void RB_UpdateTessVao(unsigned int attribBits)
R_BindVao(tess.vao); R_BindVao(tess.vao);
// orphan old vertex buffer so we don't stall on it // orphan old vertex buffer so we don't stall on it
qglBufferDataARB(GL_ARRAY_BUFFER_ARB, tess.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW_ARB); qglBufferData(GL_ARRAY_BUFFER, tess.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW);
// if nothing to set, set everything // if nothing to set, set everything
if(!(attribBits & ATTR_BITS)) if(!(attribBits & ATTR_BITS))
@ -745,14 +614,6 @@ void RB_UpdateTessVao(unsigned int attribBits)
attribUpload = attribBits; attribUpload = attribBits;
if((attribUpload & ATTR_TEXCOORD) || (attribUpload & ATTR_LIGHTCOORD))
{
// these are interleaved, so we update both if either need it
// this translates to updating ATTR_TEXCOORD twice as large as it needs
attribUpload &= ~ATTR_LIGHTCOORD;
attribUpload |= ATTR_TEXCOORD;
}
for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++) for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++)
{ {
uint32_t attribBit = 1 << attribIndex; uint32_t attribBit = 1 << attribIndex;
@ -761,17 +622,17 @@ void RB_UpdateTessVao(unsigned int attribBits)
if (attribUpload & attribBit) if (attribUpload & attribBit)
{ {
// note: tess has a VBO where stride == size // note: tess has a VBO where stride == size
qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, vAtb->offset, tess.numVertexes * vAtb->stride, tess.attribPointers[attribIndex]); qglBufferSubData(GL_ARRAY_BUFFER, vAtb->offset, tess.numVertexes * vAtb->stride, tess.attribPointers[attribIndex]);
} }
if (attribBits & attribBit) if (attribBits & attribBit)
{ {
if (!glRefConfig.vertexArrayObject) if (!glRefConfig.vertexArrayObject)
qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset)); qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset));
if (!(glState.vertexAttribsEnabled & attribBit)) if (!(glState.vertexAttribsEnabled & attribBit))
{ {
qglEnableVertexAttribArrayARB(attribIndex); qglEnableVertexAttribArray(attribIndex);
glState.vertexAttribsEnabled |= attribBit; glState.vertexAttribsEnabled |= attribBit;
} }
} }
@ -779,15 +640,329 @@ void RB_UpdateTessVao(unsigned int attribBits)
{ {
if ((glState.vertexAttribsEnabled & attribBit)) if ((glState.vertexAttribsEnabled & attribBit))
{ {
qglDisableVertexAttribArrayARB(attribIndex); qglDisableVertexAttribArray(attribIndex);
glState.vertexAttribsEnabled &= ~attribBit; glState.vertexAttribsEnabled &= ~attribBit;
} }
} }
} }
// orphan old index buffer so we don't stall on it // orphan old index buffer so we don't stall on it
qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tess.vao->indexesSize, NULL, GL_DYNAMIC_DRAW_ARB); qglBufferData(GL_ELEMENT_ARRAY_BUFFER, tess.vao->indexesSize, NULL, GL_DYNAMIC_DRAW);
qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes); qglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes);
} }
} }
// FIXME: This sets a limit of 65536 verts/262144 indexes per static surface
// This is higher than the old vq3 limits but is worth noting
#define VAOCACHE_QUEUE_MAX_SURFACES (1 << 10)
#define VAOCACHE_QUEUE_MAX_VERTEXES (1 << 16)
#define VAOCACHE_QUEUE_MAX_INDEXES (VAOCACHE_QUEUE_MAX_VERTEXES * 4)
typedef struct queuedSurface_s
{
srfVert_t *vertexes;
int numVerts;
glIndex_t *indexes;
int numIndexes;
}
queuedSurface_t;
static struct
{
queuedSurface_t surfaces[VAOCACHE_QUEUE_MAX_SURFACES];
int numSurfaces;
srfVert_t vertexes[VAOCACHE_QUEUE_MAX_VERTEXES];
int vertexCommitSize;
glIndex_t indexes[VAOCACHE_QUEUE_MAX_INDEXES];
int indexCommitSize;
}
vcq;
#define VAOCACHE_MAX_SURFACES (1 << 16)
#define VAOCACHE_MAX_BATCHES (1 << 10)
// srfVert_t is 60 bytes
// assuming each vert is referenced 4 times, need 16 bytes (4 glIndex_t) per vert
// -> need about 4/15ths the space for indexes as vertexes
#if GL_INDEX_TYPE == GL_UNSIGNED_SHORT
#define VAOCACHE_VERTEX_BUFFER_SIZE (sizeof(srfVert_t) * USHRT_MAX)
#define VAOCACHE_INDEX_BUFFER_SIZE (sizeof(glIndex_t) * USHRT_MAX * 4)
#else // GL_UNSIGNED_INT
#define VAOCACHE_VERTEX_BUFFER_SIZE (16 * 1024 * 1024)
#define VAOCACHE_INDEX_BUFFER_SIZE (5 * 1024 * 1024)
#endif
typedef struct buffered_s
{
void *data;
int size;
int bufferOffset;
}
buffered_t;
static struct
{
vao_t *vao;
buffered_t surfaceIndexSets[VAOCACHE_MAX_SURFACES];
int numSurfaces;
int batchLengths[VAOCACHE_MAX_BATCHES];
int numBatches;
int vertexOffset;
int indexOffset;
}
vc;
void VaoCache_Commit(void)
{
buffered_t *indexSet;
int *batchLength;
queuedSurface_t *surf, *end = vcq.surfaces + vcq.numSurfaces;
R_BindVao(vc.vao);
// Search for a matching batch
// FIXME: Use faster search
indexSet = vc.surfaceIndexSets;
batchLength = vc.batchLengths;
for (; batchLength < vc.batchLengths + vc.numBatches; batchLength++)
{
if (*batchLength == vcq.numSurfaces)
{
buffered_t *indexSet2 = indexSet;
for (surf = vcq.surfaces; surf < end; surf++, indexSet2++)
{
if (surf->indexes != indexSet2->data || (surf->numIndexes * sizeof(glIndex_t)) != indexSet2->size)
break;
}
if (surf == end)
break;
}
indexSet += *batchLength;
}
// If found, use it
if (indexSet < vc.surfaceIndexSets + vc.numSurfaces)
{
tess.firstIndex = indexSet->bufferOffset / sizeof(glIndex_t);
//ri.Printf(PRINT_ALL, "firstIndex %d numIndexes %d as %d\n", tess.firstIndex, tess.numIndexes, (int)(batchLength - vc.batchLengths));
//ri.Printf(PRINT_ALL, "vc.numSurfaces %d vc.numBatches %d\n", vc.numSurfaces, vc.numBatches);
}
// If not, rebuffer the batch
// FIXME: keep track of the vertexes so we don't have to reupload them every time
else
{
srfVert_t *dstVertex = vcq.vertexes;
glIndex_t *dstIndex = vcq.indexes;
batchLength = vc.batchLengths + vc.numBatches;
*batchLength = vcq.numSurfaces;
vc.numBatches++;
tess.firstIndex = vc.indexOffset / sizeof(glIndex_t);
vcq.vertexCommitSize = 0;
vcq.indexCommitSize = 0;
for (surf = vcq.surfaces; surf < end; surf++)
{
glIndex_t *srcIndex = surf->indexes;
int vertexesSize = surf->numVerts * sizeof(srfVert_t);
int indexesSize = surf->numIndexes * sizeof(glIndex_t);
int i, indexOffset = (vc.vertexOffset + vcq.vertexCommitSize) / sizeof(srfVert_t);
Com_Memcpy(dstVertex, surf->vertexes, vertexesSize);
dstVertex += surf->numVerts;
vcq.vertexCommitSize += vertexesSize;
indexSet = vc.surfaceIndexSets + vc.numSurfaces;
indexSet->data = surf->indexes;
indexSet->size = indexesSize;
indexSet->bufferOffset = vc.indexOffset + vcq.indexCommitSize;
vc.numSurfaces++;
for (i = 0; i < surf->numIndexes; i++)
*dstIndex++ = *srcIndex++ + indexOffset;
vcq.indexCommitSize += indexesSize;
}
//ri.Printf(PRINT_ALL, "committing %d to %d, %d to %d as %d\n", vcq.vertexCommitSize, vc.vertexOffset, vcq.indexCommitSize, vc.indexOffset, (int)(batchLength - vc.batchLengths));
if (vcq.vertexCommitSize)
{
qglBindBuffer(GL_ARRAY_BUFFER, vc.vao->vertexesVBO);
qglBufferSubData(GL_ARRAY_BUFFER, vc.vertexOffset, vcq.vertexCommitSize, vcq.vertexes);
vc.vertexOffset += vcq.vertexCommitSize;
}
if (vcq.indexCommitSize)
{
qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vc.vao->indexesIBO);
qglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, vc.indexOffset, vcq.indexCommitSize, vcq.indexes);
vc.indexOffset += vcq.indexCommitSize;
}
}
}
void VaoCache_Init(void)
{
vc.vao = R_CreateVao("VaoCache", NULL, VAOCACHE_VERTEX_BUFFER_SIZE, NULL, VAOCACHE_INDEX_BUFFER_SIZE, VAO_USAGE_DYNAMIC);
vc.vao->attribs[ATTR_INDEX_POSITION].enabled = 1;
vc.vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1;
vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].enabled = 1;
vc.vao->attribs[ATTR_INDEX_NORMAL].enabled = 1;
vc.vao->attribs[ATTR_INDEX_TANGENT].enabled = 1;
vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].enabled = 1;
vc.vao->attribs[ATTR_INDEX_COLOR].enabled = 1;
vc.vao->attribs[ATTR_INDEX_POSITION].count = 3;
vc.vao->attribs[ATTR_INDEX_TEXCOORD].count = 2;
vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].count = 2;
vc.vao->attribs[ATTR_INDEX_NORMAL].count = 4;
vc.vao->attribs[ATTR_INDEX_TANGENT].count = 4;
vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4;
vc.vao->attribs[ATTR_INDEX_COLOR].count = 4;
vc.vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT;
vc.vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT;
vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].type = GL_FLOAT;
vc.vao->attribs[ATTR_INDEX_NORMAL].type = GL_SHORT;
vc.vao->attribs[ATTR_INDEX_TANGENT].type = GL_SHORT;
vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT;
vc.vao->attribs[ATTR_INDEX_COLOR].type = GL_UNSIGNED_SHORT;
vc.vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE;
vc.vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE;
vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].normalized = GL_FALSE;
vc.vao->attribs[ATTR_INDEX_NORMAL].normalized = GL_TRUE;
vc.vao->attribs[ATTR_INDEX_TANGENT].normalized = GL_TRUE;
vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE;
vc.vao->attribs[ATTR_INDEX_COLOR].normalized = GL_TRUE;
vc.vao->attribs[ATTR_INDEX_POSITION].offset = offsetof(srfVert_t, xyz);
vc.vao->attribs[ATTR_INDEX_TEXCOORD].offset = offsetof(srfVert_t, st);
vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].offset = offsetof(srfVert_t, lightmap);
vc.vao->attribs[ATTR_INDEX_NORMAL].offset = offsetof(srfVert_t, normal);
vc.vao->attribs[ATTR_INDEX_TANGENT].offset = offsetof(srfVert_t, tangent);
vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = offsetof(srfVert_t, lightdir);
vc.vao->attribs[ATTR_INDEX_COLOR].offset = offsetof(srfVert_t, color);
vc.vao->attribs[ATTR_INDEX_POSITION].stride = sizeof(srfVert_t);
vc.vao->attribs[ATTR_INDEX_TEXCOORD].stride = sizeof(srfVert_t);
vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].stride = sizeof(srfVert_t);
vc.vao->attribs[ATTR_INDEX_NORMAL].stride = sizeof(srfVert_t);
vc.vao->attribs[ATTR_INDEX_TANGENT].stride = sizeof(srfVert_t);
vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = sizeof(srfVert_t);
vc.vao->attribs[ATTR_INDEX_COLOR].stride = sizeof(srfVert_t);
Vao_SetVertexPointers(vc.vao);
vc.numSurfaces = 0;
vc.numBatches = 0;
vc.vertexOffset = 0;
vc.indexOffset = 0;
vcq.vertexCommitSize = 0;
vcq.indexCommitSize = 0;
vcq.numSurfaces = 0;
}
void VaoCache_BindVao(void)
{
R_BindVao(vc.vao);
}
void VaoCache_CheckAdd(qboolean *endSurface, qboolean *recycleVertexBuffer, qboolean *recycleIndexBuffer, int numVerts, int numIndexes)
{
int vertexesSize = sizeof(srfVert_t) * numVerts;
int indexesSize = sizeof(glIndex_t) * numIndexes;
if (vc.vao->vertexesSize < vc.vertexOffset + vcq.vertexCommitSize + vertexesSize)
{
//ri.Printf(PRINT_ALL, "out of space in vertex cache: %d < %d + %d + %d\n", vc.vao->vertexesSize, vc.vertexOffset, vcq.vertexCommitSize, vertexesSize);
*recycleVertexBuffer = qtrue;
*recycleIndexBuffer = qtrue;
*endSurface = qtrue;
}
if (vc.vao->indexesSize < vc.indexOffset + vcq.indexCommitSize + indexesSize)
{
//ri.Printf(PRINT_ALL, "out of space in index cache\n");
*recycleIndexBuffer = qtrue;
*endSurface = qtrue;
}
if (vc.numSurfaces + vcq.numSurfaces >= VAOCACHE_MAX_SURFACES)
{
//ri.Printf(PRINT_ALL, "out of surfaces in index cache\n");
*recycleIndexBuffer = qtrue;
*endSurface = qtrue;
}
if (vc.numBatches >= VAOCACHE_MAX_BATCHES)
{
//ri.Printf(PRINT_ALL, "out of batches in index cache\n");
*recycleIndexBuffer = qtrue;
*endSurface = qtrue;
}
if (vcq.numSurfaces >= VAOCACHE_QUEUE_MAX_SURFACES)
{
//ri.Printf(PRINT_ALL, "out of queued surfaces\n");
*endSurface = qtrue;
}
if (VAOCACHE_QUEUE_MAX_VERTEXES * sizeof(srfVert_t) < vcq.vertexCommitSize + vertexesSize)
{
//ri.Printf(PRINT_ALL, "out of queued vertexes\n");
*endSurface = qtrue;
}
if (VAOCACHE_QUEUE_MAX_INDEXES * sizeof(glIndex_t) < vcq.indexCommitSize + indexesSize)
{
//ri.Printf(PRINT_ALL, "out of queued indexes\n");
*endSurface = qtrue;
}
}
void VaoCache_RecycleVertexBuffer(void)
{
qglBindBuffer(GL_ARRAY_BUFFER, vc.vao->vertexesVBO);
qglBufferData(GL_ARRAY_BUFFER, vc.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW);
vc.vertexOffset = 0;
}
void VaoCache_RecycleIndexBuffer(void)
{
qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vc.vao->indexesIBO);
qglBufferData(GL_ELEMENT_ARRAY_BUFFER, vc.vao->indexesSize, NULL, GL_DYNAMIC_DRAW);
vc.indexOffset = 0;
vc.numSurfaces = 0;
vc.numBatches = 0;
}
void VaoCache_InitQueue(void)
{
vcq.vertexCommitSize = 0;
vcq.indexCommitSize = 0;
vcq.numSurfaces = 0;
}
void VaoCache_AddSurface(srfVert_t *verts, int numVerts, glIndex_t *indexes, int numIndexes)
{
queuedSurface_t *queueEntry = vcq.surfaces + vcq.numSurfaces;
queueEntry->vertexes = verts;
queueEntry->numVerts = numVerts;
queueEntry->indexes = indexes;
queueEntry->numIndexes = numIndexes;
vcq.numSurfaces++;
vcq.vertexCommitSize += sizeof(srfVert_t) * numVerts;
vcq.indexCommitSize += sizeof(glIndex_t) * numIndexes;
}

View file

@ -36,7 +36,7 @@ static qboolean R_CullSurface( msurface_t *surf ) {
return qfalse; return qfalse;
} }
if ( *surf->data == SF_GRID && r_nocurves->integer ) { if ( r_nocurves->integer && *surf->data == SF_GRID ) {
return qtrue; return qtrue;
} }
@ -213,7 +213,6 @@ static int R_DlightSurface( msurface_t *surf, int dlightBits ) {
case SF_FACE: case SF_FACE:
case SF_GRID: case SF_GRID:
case SF_TRIANGLES: case SF_TRIANGLES:
case SF_VAO_MESH:
((srfBspSurface_t *)surf->data)->dlightBits = dlightBits; ((srfBspSurface_t *)surf->data)->dlightBits = dlightBits;
break; break;
@ -299,7 +298,6 @@ static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) {
case SF_FACE: case SF_FACE:
case SF_GRID: case SF_GRID:
case SF_TRIANGLES: case SF_TRIANGLES:
case SF_VAO_MESH:
((srfBspSurface_t *)surf->data)->pshadowBits = pshadowBits; ((srfBspSurface_t *)surf->data)->pshadowBits = pshadowBits;
break; break;
@ -365,7 +363,7 @@ void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) {
pModel = R_GetModelByHandle( ent->e.hModel ); pModel = R_GetModelByHandle( ent->e.hModel );
bmodel = pModel->d.bmodel; bmodel = pModel->bmodel;
clip = R_CullLocalBox( bmodel->bounds ); clip = R_CullLocalBox( bmodel->bounds );
if ( clip == CULL_OUT ) { if ( clip == CULL_OUT ) {
@ -395,28 +393,17 @@ void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) {
============================================================= =============================================================
*/ */
/*
================
R_GetInlineModelBounds
================
*/
void R_GetInlineModelBounds( int iIndex, vec3_t vMins, vec3_t vMaxs ) {
bmodel_t *bmodel = &tr.world->bmodels[ iIndex ];
VectorCopy( bmodel->bounds[ 0 ], vMins );
VectorCopy( bmodel->bounds[ 1 ], vMaxs );
}
/* /*
================ ================
R_RecursiveWorldNode R_RecursiveWorldNode
================ ================
*/ */
static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits, int pshadowBits ) { static void R_RecursiveWorldNode( mnode_t *node, uint32_t planeBits, uint32_t dlightBits, uint32_t pshadowBits ) {
do { do {
int newDlights[2]; uint32_t newDlights[2];
unsigned int newPShadows[2]; uint32_t newPShadows[2];
// if the node wasn't marked as potentially visible, exit // if the node wasn't marked as potentially visible, exit
// pvs is skipped for depth shadows // pvs is skipped for depth shadows
@ -572,43 +559,23 @@ static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits,
tr.viewParms.visBounds[1][2] = node->maxs[2]; tr.viewParms.visBounds[1][2] = node->maxs[2];
} }
// add merged and unmerged surfaces // add surfaces
if (tr.world->viewSurfaces && !r_nocurves->integer) view = tr.world->marksurfaces + node->firstmarksurface;
view = tr.world->viewSurfaces + node->firstmarksurface;
else
view = tr.world->marksurfaces + node->firstmarksurface;
c = node->nummarksurfaces; c = node->nummarksurfaces;
while (c--) { while (c--) {
// just mark it as visible, so we don't jump out of the cache derefencing the surface // just mark it as visible, so we don't jump out of the cache derefencing the surface
surf = *view; surf = *view;
if (surf < 0) if (tr.world->surfacesViewCount[surf] != tr.viewCount)
{ {
if (tr.world->mergedSurfacesViewCount[-surf - 1] != tr.viewCount) tr.world->surfacesViewCount[surf] = tr.viewCount;
{ tr.world->surfacesDlightBits[surf] = dlightBits;
tr.world->mergedSurfacesViewCount[-surf - 1] = tr.viewCount; tr.world->surfacesPshadowBits[surf] = pshadowBits;
tr.world->mergedSurfacesDlightBits[-surf - 1] = dlightBits;
tr.world->mergedSurfacesPshadowBits[-surf - 1] = pshadowBits;
}
else
{
tr.world->mergedSurfacesDlightBits[-surf - 1] |= dlightBits;
tr.world->mergedSurfacesPshadowBits[-surf - 1] |= pshadowBits;
}
} }
else else
{ {
if (tr.world->surfacesViewCount[surf] != tr.viewCount) tr.world->surfacesDlightBits[surf] |= dlightBits;
{ tr.world->surfacesPshadowBits[surf] |= pshadowBits;
tr.world->surfacesViewCount[surf] = tr.viewCount;
tr.world->surfacesDlightBits[surf] = dlightBits;
tr.world->surfacesPshadowBits[surf] = pshadowBits;
}
else
{
tr.world->surfacesDlightBits[surf] |= dlightBits;
tr.world->surfacesPshadowBits[surf] |= pshadowBits;
}
} }
view++; view++;
} }
@ -661,25 +628,6 @@ static const byte *R_ClusterPVS (int cluster) {
return tr.world->vis + cluster * tr.world->clusterBytes; return tr.world->vis + cluster * tr.world->clusterBytes;
} }
/*
=================
R_inPVS
=================
*/
qboolean R_inPVS( const vec3_t p1, const vec3_t p2 ) {
mnode_t *leaf;
byte *vis;
leaf = R_PointInLeaf( p1 );
vis = ri.CM_ClusterPVS( leaf->cluster ); // why not R_ClusterPVS ??
leaf = R_PointInLeaf( p2 );
if ( !(vis[leaf->cluster>>3] & (1<<(leaf->cluster&7))) ) {
return qfalse;
}
return qtrue;
}
/* /*
=============== ===============
R_MarkLeaves R_MarkLeaves
@ -772,7 +720,7 @@ R_AddWorldSurfaces
============= =============
*/ */
void R_AddWorldSurfaces (void) { void R_AddWorldSurfaces (void) {
int planeBits, dlightBits, pshadowBits; uint32_t planeBits, dlightBits, pshadowBits;
if ( !r_drawworld->integer ) { if ( !r_drawworld->integer ) {
return; return;
@ -793,12 +741,12 @@ void R_AddWorldSurfaces (void) {
ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] ); ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] );
// perform frustum culling and flag all the potentially visible surfaces // perform frustum culling and flag all the potentially visible surfaces
if ( tr.refdef.num_dlights > 32 ) { if ( tr.refdef.num_dlights > MAX_DLIGHTS ) {
tr.refdef.num_dlights = 32 ; tr.refdef.num_dlights = MAX_DLIGHTS ;
} }
if ( tr.refdef.num_pshadows > 32 ) { if ( tr.refdef.num_pshadows > MAX_DRAWN_PSHADOWS ) {
tr.refdef.num_pshadows = 32 ; tr.refdef.num_pshadows = MAX_DRAWN_PSHADOWS;
} }
planeBits = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 31 : 15; planeBits = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 31 : 15;
@ -810,12 +758,12 @@ void R_AddWorldSurfaces (void) {
} }
else if ( !(tr.viewParms.flags & VPF_SHADOWMAP) ) else if ( !(tr.viewParms.flags & VPF_SHADOWMAP) )
{ {
dlightBits = ( 1 << tr.refdef.num_dlights ) - 1; dlightBits = ( 1ULL << tr.refdef.num_dlights ) - 1;
pshadowBits = ( 1 << tr.refdef.num_pshadows ) - 1; pshadowBits = ( 1ULL << tr.refdef.num_pshadows ) - 1;
} }
else else
{ {
dlightBits = ( 1 << tr.refdef.num_dlights ) - 1; dlightBits = ( 1ULL << tr.refdef.num_dlights ) - 1;
pshadowBits = 0; pshadowBits = 0;
} }
@ -836,18 +784,7 @@ void R_AddWorldSurfaces (void) {
R_AddWorldSurface( tr.world->surfaces + i, tr.world->surfacesDlightBits[i], tr.world->surfacesPshadowBits[i] ); R_AddWorldSurface( tr.world->surfaces + i, tr.world->surfacesDlightBits[i], tr.world->surfacesPshadowBits[i] );
tr.refdef.dlightMask |= tr.world->surfacesDlightBits[i]; tr.refdef.dlightMask |= tr.world->surfacesDlightBits[i];
} }
for (i = 0; i < tr.world->numMergedSurfaces; i++)
{
if (tr.world->mergedSurfacesViewCount[i] != tr.viewCount)
continue;
R_AddWorldSurface( tr.world->mergedSurfaces + i, tr.world->mergedSurfacesDlightBits[i], tr.world->mergedSurfacesPshadowBits[i] );
tr.refdef.dlightMask |= tr.world->mergedSurfacesDlightBits[i];
}
tr.refdef.dlightMask = ~tr.refdef.dlightMask; tr.refdef.dlightMask = ~tr.refdef.dlightMask;
} }
R_AddTerrainSurfaces();
R_AddStaticModelSurfaces();
} }