Initial commit.
This commit is contained in:
775
tools/ModView/shader.cpp
Normal file
775
tools/ModView/shader.cpp
Normal file
@@ -0,0 +1,775 @@
|
||||
// Filename:- shader.cpp
|
||||
//
|
||||
// guess...
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "includes.h"
|
||||
#include "R_Common.h"
|
||||
#include "R_Image.h"
|
||||
#include "files.h"
|
||||
//
|
||||
#include "shader.h"
|
||||
|
||||
shaderCommands_t tess;
|
||||
|
||||
// stuff from lower down, may externalise.
|
||||
//
|
||||
char *COM_ParseExt( char **data_p, qboolean allowLineBreaks );
|
||||
|
||||
|
||||
|
||||
static char *s_shaderText = NULL;
|
||||
/*
|
||||
// the shader is parsed into these global variables, then copied into
|
||||
// dynamically allocated memory if it is valid.
|
||||
static shaderStage_t stages[MAX_SHADER_STAGES];
|
||||
static shader_t shader;
|
||||
static texModInfo_t texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS];
|
||||
static qboolean deferLoad;
|
||||
|
||||
#define FILE_HASH_SIZE 1024
|
||||
static shader_t* hashTable[FILE_HASH_SIZE];
|
||||
|
||||
//#define SHADERTEXTHASH
|
||||
|
||||
#define MAX_SHADERTEXT_HASH 2048
|
||||
static char **shaderTextHashTable[MAX_SHADERTEXT_HASH];
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
static char com_token[MAX_TOKEN_CHARS];
|
||||
static char com_parsename[MAX_TOKEN_CHARS];
|
||||
static int com_lines;
|
||||
|
||||
void COM_BeginParseSession( const char *name )
|
||||
{
|
||||
com_lines = 0;
|
||||
Com_sprintf(com_parsename, sizeof(com_parsename), "%s", name);
|
||||
}
|
||||
|
||||
int COM_GetCurrentParseLine( void )
|
||||
{
|
||||
return com_lines;
|
||||
}
|
||||
|
||||
char *COM_Parse( char **data_p )
|
||||
{
|
||||
return COM_ParseExt( data_p, qtrue );
|
||||
}
|
||||
|
||||
void COM_ParseError( char *format, ... )
|
||||
{
|
||||
va_list argptr;
|
||||
static char string[4096];
|
||||
|
||||
va_start (argptr, format);
|
||||
vsprintf (string, format, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, com_lines, string);
|
||||
}
|
||||
|
||||
void COM_ParseWarning( char *format, ... )
|
||||
{
|
||||
va_list argptr;
|
||||
static char string[4096];
|
||||
|
||||
va_start (argptr, format);
|
||||
vsprintf (string, format, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, com_lines, string);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
COM_Parse
|
||||
|
||||
Parse a token out of a string
|
||||
Will never return NULL, just empty strings
|
||||
|
||||
If "allowLineBreaks" is qtrue then an empty
|
||||
string will be returned if the next token is
|
||||
a newline.
|
||||
==============
|
||||
*/
|
||||
static char *SkipWhitespace( char *data, qboolean *hasNewLines ) {
|
||||
int c;
|
||||
|
||||
while( (c = *data) <= ' ') {
|
||||
if( !c ) {
|
||||
return NULL;
|
||||
}
|
||||
if( c == '\n' ) {
|
||||
com_lines++;
|
||||
*hasNewLines = qtrue;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SkipBracedSection
|
||||
|
||||
The next token should be an open brace.
|
||||
Skips until a matching close brace is found.
|
||||
Internal brace depths are properly skipped.
|
||||
=================
|
||||
*/
|
||||
void SkipBracedSection (char **program) {
|
||||
char *token;
|
||||
int depth;
|
||||
|
||||
depth = 0;
|
||||
do {
|
||||
token = COM_ParseExt( program, qtrue );
|
||||
if( token[1] == 0 ) {
|
||||
if( token[0] == '{' ) {
|
||||
depth++;
|
||||
}
|
||||
else if( token[0] == '}' ) {
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
} while( depth && *program );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SkipRestOfLine
|
||||
=================
|
||||
*/
|
||||
void SkipRestOfLine ( char **data ) {
|
||||
char *p;
|
||||
int c;
|
||||
|
||||
p = *data;
|
||||
while ( (c = *p++) != 0 ) {
|
||||
if ( c == '\n' ) {
|
||||
com_lines++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*data = p;
|
||||
}
|
||||
|
||||
|
||||
char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
|
||||
{
|
||||
int c = 0, len;
|
||||
qboolean hasNewLines = qfalse;
|
||||
char *data;
|
||||
|
||||
data = *data_p;
|
||||
len = 0;
|
||||
com_token[0] = 0;
|
||||
|
||||
// make sure incoming data is valid
|
||||
if ( !data )
|
||||
{
|
||||
*data_p = NULL;
|
||||
return com_token;
|
||||
}
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
// skip whitespace
|
||||
data = SkipWhitespace( data, &hasNewLines );
|
||||
if ( !data )
|
||||
{
|
||||
*data_p = NULL;
|
||||
return com_token;
|
||||
}
|
||||
if ( hasNewLines && !allowLineBreaks )
|
||||
{
|
||||
*data_p = data;
|
||||
return com_token;
|
||||
}
|
||||
|
||||
c = *data;
|
||||
|
||||
// skip double slash comments
|
||||
if ( c == '/' && data[1] == '/' )
|
||||
{
|
||||
data += 2;
|
||||
while (*data && *data != '\n') {
|
||||
data++;
|
||||
}
|
||||
}
|
||||
// skip /* */ comments
|
||||
else if ( c=='/' && data[1] == '*' )
|
||||
{
|
||||
data += 2;
|
||||
while ( *data && ( *data != '*' || data[1] != '/' ) )
|
||||
{
|
||||
data++;
|
||||
}
|
||||
if ( *data )
|
||||
{
|
||||
data += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// handle quoted strings
|
||||
if (c == '\"')
|
||||
{
|
||||
data++;
|
||||
while (1)
|
||||
{
|
||||
c = *data++;
|
||||
if (c=='\"' || !c)
|
||||
{
|
||||
com_token[len] = 0;
|
||||
*data_p = ( char * ) data;
|
||||
return com_token;
|
||||
}
|
||||
if (len < MAX_TOKEN_CHARS)
|
||||
{
|
||||
com_token[len] = c;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse a regular word
|
||||
do
|
||||
{
|
||||
if (len < MAX_TOKEN_CHARS)
|
||||
{
|
||||
com_token[len] = c;
|
||||
len++;
|
||||
}
|
||||
data++;
|
||||
c = *data;
|
||||
if ( c == '\n' )
|
||||
com_lines++;
|
||||
} while (c>32);
|
||||
|
||||
if (len == MAX_TOKEN_CHARS)
|
||||
{
|
||||
// Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
|
||||
len = 0;
|
||||
}
|
||||
com_token[len] = 0;
|
||||
|
||||
*data_p = ( char * ) data;
|
||||
return com_token;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
FindShaderInShaderText
|
||||
|
||||
Scans the combined text description of all the shader files for
|
||||
the given shader name.
|
||||
|
||||
return NULL if not found
|
||||
|
||||
If found, it will return a valid shader
|
||||
=====================
|
||||
*/
|
||||
static char *FindShaderInShaderText( const char *shadername ) {
|
||||
#ifdef SHADERTEXTHASH
|
||||
|
||||
char *token, *p;
|
||||
int i, hash;
|
||||
|
||||
hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH);
|
||||
|
||||
for (i = 0; shaderTextHashTable[hash][i]; i++) {
|
||||
p = shaderTextHashTable[hash][i];
|
||||
token = COM_ParseExt(&p, qtrue);
|
||||
if ( !Q_stricmp( token, shadername ) ) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
#else
|
||||
char *p = s_shaderText;
|
||||
char *token;
|
||||
|
||||
if ( !p ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// look for label
|
||||
while ( 1 ) {
|
||||
token = COM_ParseExt( &p, qtrue );
|
||||
if ( token[0] == 0 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !Q_stricmp( token, shadername ) ) {
|
||||
return p;
|
||||
}
|
||||
else {
|
||||
// skip the definition
|
||||
SkipBracedSection( &p );
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
ScanAndLoadShaderFiles
|
||||
|
||||
Finds and loads all .shader files, combining them into
|
||||
a single large text block that can be scanned for shader names
|
||||
=====================
|
||||
*/
|
||||
#define MAX_SHADER_FILES 1024
|
||||
|
||||
typedef map<string,string> ShadersFoundAndFilesPicked_t;
|
||||
ShadersFoundAndFilesPicked_t ShadersFoundAndFilesPicked;
|
||||
|
||||
void KillAllShaderFiles(void)
|
||||
{
|
||||
SAFEFREE(s_shaderText);
|
||||
ShadersFoundAndFilesPicked.clear();
|
||||
}
|
||||
|
||||
|
||||
void ScanAndLoadShaderFiles( void )
|
||||
{
|
||||
if (s_shaderText == NULL && strlen(gamedir))
|
||||
{
|
||||
char **shaderFiles;
|
||||
char *buffers[MAX_SHADER_FILES];
|
||||
#ifdef SHADERTEXTHASH
|
||||
char *p, *oldp, *token, *hashMem;
|
||||
int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size;
|
||||
#endif
|
||||
int numShaders;
|
||||
int i;
|
||||
long sum = 0;
|
||||
|
||||
#define sSHADER_DIR va("%sshaders",gamedir)
|
||||
|
||||
// scan for shader files
|
||||
shaderFiles = //ri.FS_ListFiles( "shaders", ".shader", &numShaders );
|
||||
Sys_ListFiles( sSHADER_DIR, // const char *directory,
|
||||
".shader", // const char *extension,
|
||||
NULL, // char *filter,
|
||||
&numShaders,// int *numfiles,
|
||||
qfalse // qboolean wantsubs
|
||||
);
|
||||
|
||||
if ( !shaderFiles || !numShaders )
|
||||
{
|
||||
if (!bXMenPathHack)
|
||||
{
|
||||
ri.Printf( PRINT_WARNING, "WARNING: no shader files found in '%s'\n",sSHADER_DIR );
|
||||
}
|
||||
s_shaderText = CopyString("// blank shader file to avoid re-scanning shaders\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( numShaders > MAX_SHADER_FILES ) {
|
||||
numShaders = MAX_SHADER_FILES;
|
||||
}
|
||||
|
||||
// load and parse shader files
|
||||
for ( i = 0; i < numShaders; i++ )
|
||||
{
|
||||
char filename[MAX_QPATH];
|
||||
|
||||
Com_sprintf( filename, sizeof( filename ), "shaders/%s", shaderFiles[i] );
|
||||
StatusMessage( va("Loading shader %d/%d: \"%s\"...",i+1,numShaders,filename));
|
||||
|
||||
//ri.Printf( PRINT_ALL, "...loading '%s'\n", filename );
|
||||
sum += ri.FS_ReadFile( filename, (void **)&buffers[i] );
|
||||
if ( !buffers[i] ) {
|
||||
ri.Error( ERR_DROP, "Couldn't load %s", filename );
|
||||
}
|
||||
}
|
||||
StatusMessage(NULL);
|
||||
|
||||
// build single large buffer
|
||||
s_shaderText = (char *)ri.Hunk_Alloc( sum + numShaders*2 );
|
||||
|
||||
// free in reverse order, so the temp files are all dumped
|
||||
for ( i = numShaders - 1; i >= 0 ; i-- ) {
|
||||
strcat( s_shaderText, "\n" );
|
||||
strcat( s_shaderText, buffers[i] );
|
||||
ri.FS_FreeFile( buffers[i] );
|
||||
}
|
||||
|
||||
// free up memory
|
||||
//ri.FS_FreeFileList( shaderFiles );
|
||||
Sys_FreeFileList( shaderFiles );
|
||||
|
||||
#ifdef SHADERTEXTHASH
|
||||
memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
|
||||
size = 0;
|
||||
p = s_shaderText;
|
||||
// look for label
|
||||
while ( 1 ) {
|
||||
token = COM_ParseExt( &p, qtrue );
|
||||
if ( token[0] == 0 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
|
||||
shaderTextHashTableSizes[hash]++;
|
||||
size++;
|
||||
SkipBracedSection(&p);
|
||||
}
|
||||
size += MAX_SHADERTEXT_HASH;
|
||||
|
||||
hashMem = (char *)ri.Hunk_Alloc( size * sizeof(char *) );
|
||||
|
||||
for (i = 0; i < MAX_SHADERTEXT_HASH; i++) {
|
||||
shaderTextHashTable[i] = (char **) hashMem;
|
||||
hashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *));
|
||||
}
|
||||
|
||||
memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
|
||||
p = s_shaderText;
|
||||
// look for label
|
||||
while ( 1 ) {
|
||||
oldp = p;
|
||||
token = COM_ParseExt( &p, qtrue );
|
||||
if ( token[0] == 0 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
|
||||
shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp;
|
||||
|
||||
SkipBracedSection(&p);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
textures/sfx/dclogo
|
||||
{
|
||||
qer_editorimage textures/gothic_floor/largerblock3b.tga
|
||||
nomipmaps
|
||||
|
||||
|
||||
{
|
||||
map textures/base_floor/clangdark.tga
|
||||
rgbGen identity
|
||||
tcmod scale 4 4
|
||||
}
|
||||
|
||||
{
|
||||
map $lightmap
|
||||
rgbGen identity
|
||||
blendfunc gl_dst_color gl_zero
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
clampmap textures/effects/dreamcast-logo2.tga
|
||||
blendfunc gl_one gl_one
|
||||
tcmod rotate -75
|
||||
rgbGen wave sin .75 .25 0 .5
|
||||
}
|
||||
|
||||
// END
|
||||
}
|
||||
*/
|
||||
static bool CheckForFilenameArg(LPCSTR &psSearchPos, LPCSTR psKeyword)
|
||||
{
|
||||
LPCSTR psSearchResult = strstr(psSearchPos,psKeyword);
|
||||
|
||||
if (psSearchResult && isspace(psSearchResult[strlen(psKeyword)]))
|
||||
{
|
||||
psSearchResult += strlen(psKeyword);
|
||||
while (*psSearchResult && isspace(*psSearchResult)) psSearchResult++;
|
||||
|
||||
if (strlen(psSearchResult) && *psSearchResult != '$' && ((psSearchResult>psSearchPos)?isspace(psSearchResult[-1]):1) ) // note error-check on -1 index
|
||||
{
|
||||
psSearchPos = psSearchResult;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (psSearchResult)
|
||||
{
|
||||
// skip to line end...
|
||||
//
|
||||
while (*psSearchResult++ != '\n'){}
|
||||
psSearchResult++;
|
||||
psSearchPos = psSearchResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
psSearchPos = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// have a look at the shader text pointed at by the supplied arg and try and work out
|
||||
// a suitable image name.
|
||||
//
|
||||
// First, see if there's an editorimage,
|
||||
// else check for a map with a valid texture (ie not '$lightmap' etc)
|
||||
// else check for a clampmap
|
||||
// else just return NULL, signifying that I'm stumped...
|
||||
//
|
||||
LPCSTR Shader_ExtractSuitableFilename(LPCSTR psShaderText)
|
||||
{
|
||||
char *psShaderTextEnd = (char*)psShaderText;
|
||||
SkipBracedSection (&psShaderTextEnd);
|
||||
|
||||
int iShaderChars = psShaderTextEnd - psShaderText;
|
||||
|
||||
// make a small string with just this shader in, for easier searching...
|
||||
//
|
||||
char *psThisShader = (char *) malloc(iShaderChars+1); // +1 for trailing zero
|
||||
char *psShaderSearch= psThisShader;
|
||||
strncpy(psThisShader,psShaderText,iShaderChars);
|
||||
psThisShader[iShaderChars]='\0';
|
||||
|
||||
LPCSTR psAnswer = NULL;
|
||||
|
||||
char *psShaderSearchTry = psShaderSearch;
|
||||
if (CheckForFilenameArg(psShaderSearchTry, "qer_editorimage"))
|
||||
{
|
||||
psAnswer = psShaderSearchTry;
|
||||
}
|
||||
|
||||
// these next ones I need to search for multiple times, else it hits things like "q3map_blah",
|
||||
// doesn't find a space after "map", then gives up, so it should keep trying....
|
||||
//
|
||||
psShaderSearchTry = psShaderSearch;
|
||||
while (psShaderSearchTry && !psAnswer)
|
||||
{
|
||||
if (CheckForFilenameArg(psShaderSearchTry, "map"))
|
||||
{
|
||||
psAnswer = psShaderSearchTry;
|
||||
}
|
||||
}
|
||||
|
||||
if (!psAnswer)
|
||||
{
|
||||
psShaderSearchTry = psShaderSearch;
|
||||
|
||||
while (psShaderSearchTry && !psAnswer)
|
||||
{
|
||||
if (CheckForFilenameArg(psShaderSearchTry, "clampmap"))
|
||||
{
|
||||
psAnswer = psShaderSearchTry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char sReturnName[MAX_QPATH];
|
||||
if (psAnswer)
|
||||
{
|
||||
strncpy(sReturnName,psAnswer,sizeof(sReturnName));
|
||||
sReturnName[sizeof(sReturnName)-1]='\0';
|
||||
for (int i=0; i<sizeof(sReturnName)-1; i++)
|
||||
{
|
||||
if (sReturnName[i]=='\0')
|
||||
break;
|
||||
if (isspace(sReturnName[i]))
|
||||
{
|
||||
sReturnName[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(psThisShader);
|
||||
return psAnswer?sReturnName:NULL;
|
||||
}
|
||||
|
||||
|
||||
// massively hacked-down version of original code, this simply takes an input char * local filename, then
|
||||
// modifies it to be either the name of the first MAP arg within the corresponding shader file, else leaves
|
||||
// it alone if not found
|
||||
const char *R_FindShader( const char *psLocalMaterialName)
|
||||
{
|
||||
static char sReturnString[MAX_QPATH];
|
||||
|
||||
char strippedName[MAX_QPATH];
|
||||
/* char fileName[MAX_QPATH];
|
||||
int i, hash;
|
||||
*/ char *shaderText;
|
||||
/* image_t *image;
|
||||
shader_t *sh;
|
||||
|
||||
if ( name[0] == 0 ) {
|
||||
return tr.defaultShader;
|
||||
}
|
||||
|
||||
// use (fullbright) vertex lighting if the bsp file doesn't have
|
||||
// lightmaps
|
||||
if ( lightmapIndex[0] >= 0 && lightmapIndex[0] >= tr.numLightmaps ) {
|
||||
lightmapIndex[0] = LIGHTMAP_BY_VERTEX;
|
||||
}
|
||||
*/
|
||||
COM_StripExtension( psLocalMaterialName, strippedName );
|
||||
strlwr(strippedName);
|
||||
|
||||
ShadersFoundAndFilesPicked_t::iterator it = ShadersFoundAndFilesPicked.find(strippedName);
|
||||
if (it != ShadersFoundAndFilesPicked.end())
|
||||
{
|
||||
return (*it).second.c_str();
|
||||
}
|
||||
/*
|
||||
hash = generateHashValue(strippedName, FILE_HASH_SIZE);
|
||||
|
||||
//
|
||||
// see if the shader is already loaded
|
||||
//
|
||||
for (sh = hashTable[hash]; sh; sh = sh->next) {
|
||||
// NOTE: if there was no shader or image available with the name strippedName
|
||||
// then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
|
||||
// have to check all default shaders otherwise for every call to R_FindShader
|
||||
// with that same strippedName a new default shader is created.
|
||||
if (IsShader(sh, strippedName, lightmapIndex, styles))
|
||||
{
|
||||
return sh;
|
||||
}
|
||||
}
|
||||
*/
|
||||
/* // make sure the render thread is stopped, because we are probably
|
||||
// going to have to upload an image
|
||||
R_SyncRenderThread();
|
||||
|
||||
// clear the global shader
|
||||
ClearGlobalShader();
|
||||
memset( &stages, 0, sizeof( stages ) );
|
||||
Q_strncpyz(shader.name, strippedName, sizeof(shader.name));
|
||||
memcpy(shader.lightmapIndex, lightmapIndex, sizeof(shader.lightmapIndex));
|
||||
memcpy(shader.styles, styles, sizeof(shader.styles));
|
||||
for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
|
||||
stages[i].bundle[0].texMods = texMods[i];
|
||||
}
|
||||
|
||||
// FIXME: set these "need" values apropriately
|
||||
shader.needsNormal = qtrue;
|
||||
shader.needsST1 = qtrue;
|
||||
shader.needsST2 = qtrue;
|
||||
shader.needsColor = qtrue;
|
||||
*/
|
||||
//
|
||||
// attempt to define shader from an explicit parameter file
|
||||
//
|
||||
shaderText = FindShaderInShaderText( strippedName );
|
||||
if ( shaderText )
|
||||
{
|
||||
/* // enable this when building a pak file to get a global list
|
||||
// of all explicit shaders
|
||||
if ( r_printShaders->integer ) {
|
||||
ri.Printf( PRINT_ALL, "*SHADER* %s\n", name );
|
||||
}
|
||||
|
||||
if ( !ParseShader( &shaderText ) ) {
|
||||
// had errors, so use default shader
|
||||
shader.defaultShader = qtrue;
|
||||
}
|
||||
sh = FinishShader();
|
||||
return sh;
|
||||
*/
|
||||
LPCSTR psReturnName = Shader_ExtractSuitableFilename(shaderText);
|
||||
if (psReturnName)
|
||||
{
|
||||
psLocalMaterialName = psReturnName;
|
||||
}
|
||||
}
|
||||
|
||||
ShadersFoundAndFilesPicked[strippedName] = psLocalMaterialName;
|
||||
return psLocalMaterialName; // return original name
|
||||
/*
|
||||
//
|
||||
// if not defined in the in-memory shader descriptions,
|
||||
// look for a single TGA, BMP, or PCX
|
||||
//
|
||||
Q_strncpyz( fileName, name, sizeof( fileName ) );
|
||||
image = R_FindImageFile( fileName, mipRawImage, mipRawImage, mipRawImage ? GL_REPEAT : GL_CLAMP );
|
||||
if ( !image ) {
|
||||
ri.Printf( PRINT_DEVELOPER, "Couldn't find image for shader %s\n", name );
|
||||
shader.defaultShader = qtrue;
|
||||
return FinishShader();
|
||||
}
|
||||
|
||||
//
|
||||
// create the default shading commands
|
||||
//
|
||||
if ( shader.lightmapIndex[0] == LIGHTMAP_NONE ) {
|
||||
// dynamic colors at vertexes
|
||||
stages[0].bundle[0].image[0] = image;
|
||||
stages[0].active = qtrue;
|
||||
stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
|
||||
stages[0].stateBits = GLS_DEFAULT;
|
||||
} else if ( shader.lightmapIndex[0] == LIGHTMAP_BY_VERTEX ) {
|
||||
// explicit colors at vertexes
|
||||
stages[0].bundle[0].image[0] = image;
|
||||
stages[0].active = qtrue;
|
||||
stages[0].rgbGen = CGEN_EXACT_VERTEX;
|
||||
stages[0].alphaGen = AGEN_SKIP;
|
||||
stages[0].stateBits = GLS_DEFAULT;
|
||||
} else if ( shader.lightmapIndex[0] == LIGHTMAP_2D ) {
|
||||
// GUI elements
|
||||
stages[0].bundle[0].image[0] = image;
|
||||
stages[0].active = qtrue;
|
||||
stages[0].rgbGen = CGEN_VERTEX;
|
||||
stages[0].alphaGen = AGEN_VERTEX;
|
||||
stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
|
||||
GLS_SRCBLEND_SRC_ALPHA |
|
||||
GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
|
||||
} else if ( shader.lightmapIndex[0] == LIGHTMAP_WHITEIMAGE ) {
|
||||
// fullbright level
|
||||
stages[0].bundle[0].image[0] = tr.whiteImage;
|
||||
stages[0].active = qtrue;
|
||||
stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
|
||||
stages[0].stateBits = GLS_DEFAULT;
|
||||
|
||||
stages[1].bundle[0].image[0] = image;
|
||||
stages[1].active = qtrue;
|
||||
stages[1].rgbGen = CGEN_IDENTITY;
|
||||
stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
|
||||
} else {
|
||||
// two pass lightmap
|
||||
stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex[0]];
|
||||
stages[0].bundle[0].isLightmap = qtrue;
|
||||
stages[0].active = qtrue;
|
||||
stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation
|
||||
// for identitylight
|
||||
stages[0].stateBits = GLS_DEFAULT;
|
||||
|
||||
stages[1].bundle[0].image[0] = image;
|
||||
stages[1].active = qtrue;
|
||||
stages[1].rgbGen = CGEN_IDENTITY;
|
||||
stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
|
||||
}
|
||||
|
||||
return FinishShader();
|
||||
*/
|
||||
}
|
||||
|
||||
////////////////// eof ////////////////
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user