diff --git a/code/client/cl_imgui.cpp b/code/client/cl_imgui.cpp
index a0120c8..b2a8409 100644
--- a/code/client/cl_imgui.cpp
+++ b/code/client/cl_imgui.cpp
@@ -286,6 +286,16 @@ static const cmdTableItem_t imgui_cmds[] =
{ "toggleguiinput", &ToggleGuiInput_f, NULL, "toggles CNQ3 GUI input capture" }
};
+static const char* GetClipboardText(void*)
+{
+ return Sys_GetClipboardData();
+}
+
+static void SetClipboardText(void*, const char* text)
+{
+ Sys_SetClipboardData(text);
+}
+
void CL_IMGUI_Init()
{
Cmd_RegisterArray(imgui_cmds, MODULE_CLIENT);
@@ -297,6 +307,8 @@ void CL_IMGUI_Init()
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
io.IniFilename = "cnq3/imgui.ini";
+ io.GetClipboardTextFn = &GetClipboardText;
+ io.SetClipboardTextFn = &SetClipboardText;
//io.MouseDrawCursor = true; // just use the operating system's
ImFontConfig fontConfig;
diff --git a/code/renderer/grp_world.cpp b/code/renderer/grp_world.cpp
index 544e2d2..9358b95 100644
--- a/code/renderer/grp_world.cpp
+++ b/code/renderer/grp_world.cpp
@@ -75,9 +75,15 @@ static bool drawClouds = true;
static bool forceDynamic = false;
-static bool HasStaticGeo(const drawSurf_t* drawSurf)
+static bool HasStaticGeo(const drawSurf_t* drawSurf, const shader_t* shader)
{
- return drawSurf->staticGeoChunk > 0 && drawSurf->staticGeoChunk < ARRAY_LEN(grp.world.statChunks);
+ // @NOTE: the shader->isDynamic check is needed because of the shader editing feature
+ // without it, an edited shader that changes vertex attributes won't display correctly
+ // because the original "baked" vertex attributes would be used instead
+ return
+ !shader->isDynamic &&
+ drawSurf->staticGeoChunk > 0 &&
+ drawSurf->staticGeoChunk < ARRAY_LEN(grp.world.statChunks);
}
static void UpdateEntityData(bool& depthHack, int entityNum, double originalTime)
@@ -919,7 +925,7 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
}
}
- const bool hasStaticGeo = forceDynamic ? false : HasStaticGeo(drawSurf);
+ const bool hasStaticGeo = forceDynamic ? false : HasStaticGeo(drawSurf, shader);
const bool staticChanged = hasStaticGeo != oldHasStaticGeo;
const bool shaderChanged = shader != oldShader;
bool entityChanged = entityNum != oldEntityNum;
diff --git a/code/renderer/tr_gui.cpp b/code/renderer/tr_gui.cpp
index b72717d..bbd023c 100644
--- a/code/renderer/tr_gui.cpp
+++ b/code/renderer/tr_gui.cpp
@@ -27,6 +27,7 @@ along with Challenge Quake 3. If not, see .
#define IMAGE_WINDOW_NAME "Image Details"
#define SHADER_WINDOW_NAME "Shader Details"
+#define EDIT_WINDOW_NAME "Shader Editor"
struct ImageWindow
@@ -67,10 +68,19 @@ struct ImageReplacements
int count;
};
+struct ShaderEditWindow
+{
+ char code[4096];
+ shader_t originalShader;
+ shader_t* shader;
+ bool active;
+};
+
static ImageWindow imageWindow;
static ShaderWindow shaderWindow;
static ShaderReplacements shaderReplacements;
static ImageReplacements imageReplacements;
+static ShaderEditWindow shaderEditWindow;
static const char* mipNames[16] =
{
@@ -109,30 +119,25 @@ static const ImageFlag imageFlags[] =
};
-static void TitleText(const char* text)
+#if 0
+static void SelectableText(const char* text)
{
- ImGui::TextColored(ImVec4(1.0f, 0.25f, 0.0f, 1.0f), text);
+ char buffer[256];
+ Q_strncpyz(buffer, text, sizeof(buffer));
+
+ ImGui::PushID(text);
+ ImGui::PushItemWidth(ImGui::GetWindowSize().x);
+ ImGui::InputText("", buffer, sizeof(buffer), ImGuiInputTextFlags_ReadOnly);
+ ImGui::PopItemWidth();
+ ImGui::PopID();
}
+#endif
-static void OpenImageDetails(const image_t* image)
+static void FormatShaderCode(char* dest, int destSize, const shader_t* shader)
{
- ImGui::SetWindowFocus(IMAGE_WINDOW_NAME);
+#define Append(Text) Q_strcat(dest, destSize, Text)
- imageWindow.active = true;
- imageWindow.image = image;
- imageWindow.mip = 0;
-}
-
-static void OpenShaderDetails(shader_t* shader)
-{
-#define Append(Text) Q_strcat(shaderWindow.formattedCode, sizeof(shaderWindow.formattedCode), Text)
-
- ImGui::SetWindowFocus(SHADER_WINDOW_NAME);
-
- shaderWindow.active = true;
- shaderWindow.shader = shader;
-
- shaderWindow.formattedCode[0] = '\0';
+ dest[0] = '\0';
if(shader->text == NULL)
{
return;
@@ -176,11 +181,69 @@ static void OpenShaderDetails(shader_t* shader)
#undef Append
}
-static bool AreCheatsEnabled()
+static void TitleText(const char* text)
+{
+ ImGui::TextColored(ImVec4(1.0f, 0.25f, 0.0f, 1.0f), text);
+}
+
+static void OpenImageDetails(const image_t* image)
+{
+ ImGui::SetWindowFocus(IMAGE_WINDOW_NAME);
+
+ imageWindow.active = true;
+ imageWindow.image = image;
+ imageWindow.mip = 0;
+}
+
+static void OpenShaderDetails(shader_t* shader)
+{
+ ImGui::SetWindowFocus(SHADER_WINDOW_NAME);
+
+ shaderWindow.active = true;
+ shaderWindow.shader = shader;
+ FormatShaderCode(shaderWindow.formattedCode, sizeof(shaderWindow.formattedCode), shader);
+}
+
+static void OpenShaderEdit(shader_t* shader)
+{
+ ImGui::SetWindowFocus(EDIT_WINDOW_NAME);
+
+ if(shaderEditWindow.active)
+ {
+ R_SetShaderData(shaderEditWindow.shader, &shaderEditWindow.originalShader);
+ }
+
+ shaderEditWindow.active = true;
+ shaderEditWindow.shader = shader;
+ shaderEditWindow.originalShader = *shader;
+ FormatShaderCode(shaderEditWindow.code, sizeof(shaderEditWindow.code), shader);
+ tr.shaderParseFailed = qfalse;
+ tr.shaderParseNumWarnings = 0;
+}
+
+static bool IsCheating()
{
return ri.Cvar_Get("sv_cheats", "0", 0)->integer != 0;
}
+static void RemoveShaderReplacement(int shaderIndex)
+{
+ for(int i = 0; i < shaderReplacements.count; ++i)
+ {
+ const ShaderReplacement& repl = shaderReplacements.shaders[i];
+ if(shaderIndex == repl.index && shaderIndex >= 0 && shaderIndex < tr.numShaders)
+ {
+ *tr.shaders[repl.index] = repl.original;
+ if(i < shaderReplacements.count - 1)
+ {
+ shaderReplacements.shaders[i] = shaderReplacements.shaders[shaderReplacements.count - 1];
+ }
+ shaderReplacements.count--;
+ break;
+ }
+ }
+}
+
static void AddShaderReplacement(int shaderIndex)
{
if(shaderReplacements.count >= ARRAY_LEN(shaderReplacements.shaders))
@@ -201,6 +264,13 @@ static void AddShaderReplacement(int shaderIndex)
}
}
+ ShaderEditWindow& edit = shaderEditWindow;
+ if(edit.active && edit.shader->index == shaderIndex)
+ {
+ RemoveShaderReplacement(shaderIndex);
+ edit.active = false;
+ }
+
ShaderReplacement& repl = shaderReplacements.shaders[shaderReplacements.count++];
repl.index = shaderIndex;
repl.original = *tr.shaders[shaderIndex];
@@ -210,24 +280,6 @@ static void AddShaderReplacement(int shaderIndex)
tr.shaders[shaderIndex]->sortedIndex = repl.original.sortedIndex;
}
-static void RemoveShaderReplacement(int shaderIndex)
-{
- for(int i = 0; i < shaderReplacements.count; ++i)
- {
- const ShaderReplacement& repl = shaderReplacements.shaders[i];
- if(shaderIndex == repl.index && shaderIndex >= 0 && shaderIndex < tr.numShaders)
- {
- *tr.shaders[repl.index] = repl.original;
- if(i < shaderReplacements.count - 1)
- {
- shaderReplacements.shaders[i] = shaderReplacements.shaders[shaderReplacements.count - 1];
- }
- shaderReplacements.count--;
- break;
- }
- }
-}
-
static bool IsReplacedShader(int shaderIndex)
{
for(int i = 0; i < shaderReplacements.count; ++i)
@@ -437,7 +489,7 @@ static void DrawImageWindow()
}
}
- if(AreCheatsEnabled())
+ if(IsCheating())
{
if(IsReplacedImage(image->index))
{
@@ -591,9 +643,12 @@ static void DrawShaderWindow()
ImGui::Text(shaderPath);
}
- if(AreCheatsEnabled())
+ const bool isReplaced = IsReplacedShader(shader->index);
+ const bool isCheating = IsCheating();
+
+ if(isCheating)
{
- if(IsReplacedShader(shader->index))
+ if(isReplaced)
{
if(ImGui::Button("Restore Shader"))
{
@@ -631,6 +686,9 @@ static void DrawShaderWindow()
}
}
}
+
+ const image_t* displayImages[MAX_IMAGE_ANIMATIONS * MAX_SHADER_STAGES];
+ int displayImageCount = 0;
for(int s = 0; s < shader->numStages; ++s)
{
const textureBundle_t& bundle = shader->stages[s]->bundle;
@@ -638,6 +696,25 @@ static void DrawShaderWindow()
for(int i = 0; i < imageCount; ++i)
{
const image_t* image = bundle.image[i];
+
+ bool found = false;
+ for(int di = 0; di < displayImageCount; ++di)
+ {
+ if(displayImages[di] == image)
+ {
+ found = true;
+ break;
+ }
+ }
+ if(found)
+ {
+ continue;
+ }
+ if(displayImageCount < ARRAY_LEN(displayImages))
+ {
+ displayImages[displayImageCount++] = image;
+ }
+
if(ImGui::Selectable(va("%s##%d_%d", image->name, s, i), false))
{
OpenImageDetails(image);
@@ -650,26 +727,131 @@ static void DrawShaderWindow()
}
ImGui::NewLine();
- if(window.formattedCode[0] != '\0')
+ if(isReplaced)
+ {
+ ImGui::Text("No code available (using default shader)");
+ }
+ else if(shaderEditWindow.active && window.shader == shaderEditWindow.shader)
+ {
+ ImGui::Text("Shader code is being edited");
+ if(shaderEditWindow.code[0] != '\0')
+ {
+ ImGui::Text("This is the current edited code, not the last successful compile");
+ ImGui::TextUnformatted(shaderEditWindow.code);
+ }
+ }
+ else if(window.formattedCode[0] != '\0')
{
ImGui::TextUnformatted(window.formattedCode);
+ ImGui::NewLine();
+ if(ImGui::Button("Copy Code"))
+ {
+ ImGui::SetClipboardText(window.formattedCode);
+ }
}
else
{
ImGui::Text("No code available");
}
+
+ if(isCheating)
+ {
+ if(!shaderEditWindow.active || window.shader != shaderEditWindow.shader)
+ {
+ ImGui::NewLine();
+ if(ImGui::Button("Edit Shader"))
+ {
+ if(isReplaced)
+ {
+ RemoveShaderReplacement(shader->index);
+ }
+ OpenShaderEdit(shader);
+ }
+ }
+ }
}
ImGui::End();
}
}
+static int ShaderEditCallback(ImGuiInputTextCallbackData* data)
+{
+ data->InsertChars(data->CursorPos, " ");
+ return 1;
+}
+
+static void DrawShaderEdit()
+{
+ ShaderEditWindow& window = shaderEditWindow;
+ const bool wasActive = window.active;
+ if(window.active)
+ {
+ if(ImGui::Begin(EDIT_WINDOW_NAME, &window.active, ImGuiWindowFlags_AlwaysAutoResize))
+ {
+ shader_t* shader = window.shader;
+ TitleText(shader->name);
+
+ if(IsCheating())
+ {
+ ImGui::NewLine();
+
+ if(ImGui::IsWindowAppearing())
+ {
+ ImGui::SetKeyboardFocusHere();
+ }
+ const ImVec2 xSize = ImGui::CalcTextSize("X");
+ const ImVec2 inputSize = ImVec2(xSize.x * 60.0f, xSize.y * 30.0f);
+ ImGui::InputTextMultiline(
+ "##Shader Code", window.code, sizeof(window.code), inputSize,
+ ImGuiInputTextFlags_CallbackCompletion, &ShaderEditCallback);
+
+ ImGui::NewLine();
+ if(ImGui::Button("Apply Code"))
+ {
+ R_EditShader(window.shader, &window.originalShader, window.code);
+ }
+ ImGui::SameLine(inputSize.x - ImGui::CalcTextSize("Close and Discard").x);
+ if(ImGui::Button("Close and Discard"))
+ {
+ window.active = false;
+ }
+
+ if(tr.shaderParseFailed || tr.shaderParseNumWarnings > 0)
+ {
+ ImGui::NewLine();
+ }
+ if(tr.shaderParseFailed)
+ {
+ ImGui::TextColored(ImVec4(1.0f, 0.25f, 0.0f, 1.0f), "Error: %s", tr.shaderParseError);
+ }
+ for(int i = 0; i < tr.shaderParseNumWarnings; ++i)
+ {
+ ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f), "Warning: %s", tr.shaderParseWarnings[i]);
+ }
+ }
+ else
+ {
+ ImGui::Text("Enable cheats to use");
+ }
+ }
+
+ ImGui::End();
+ }
+
+ if(wasActive && !window.active)
+ {
+ R_SetShaderData(window.shader, &window.originalShader);
+ }
+}
+
void R_DrawGUI()
{
DrawImageList();
DrawImageWindow();
DrawShaderList();
DrawShaderWindow();
+ DrawShaderEdit();
}
void R_ShutDownGUI()
@@ -677,10 +859,13 @@ void R_ShutDownGUI()
// this is necessary to avoid crashes in the detail windows
// following a map change or video restart:
// the renderer is shut down and the pointers become stale
- imageWindow.active = false;
- imageWindow.image = NULL;
- shaderWindow.active = false;
- shaderWindow.shader = NULL;
+ if(shaderEditWindow.active)
+ {
+ R_SetShaderData(shaderEditWindow.shader, &shaderEditWindow.originalShader);
+ }
+ memset(&imageWindow, 0, sizeof(imageWindow));
+ memset(&shaderWindow, 0, sizeof(shaderWindow));
+ memset(&shaderEditWindow, 0, sizeof(shaderEditWindow));
ClearShaderReplacements();
ClearImageReplacements();
}
diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h
index ac75885..dbc22f2 100644
--- a/code/renderer/tr_local.h
+++ b/code/renderer/tr_local.h
@@ -866,14 +866,18 @@ typedef struct {
#define FOG_TABLE_SIZE 256
-enum renderMode_t
-{
+enum renderMode_t {
RM_NONE,
RM_UI,
RM_3D
};
+struct shaderParseMessage_t {
+ char message[256];
+};
+
+
/*
** trGlobals_t
**
@@ -964,6 +968,16 @@ typedef struct {
qbool worldSurface; // is the currently added draw surface a world surface?
renderMode_t renderMode;
+
+ // the following are only to be used after calling R_UpdateShader()
+ // the save state boolean is needed because otherwise, a delayed shader load
+ // could change the error and warning messages of the edited shader
+ shaderParseMessage_t shaderParseError;
+ shaderParseMessage_t shaderParseWarnings[16];
+ qbool shaderParseSaveState;
+ qbool shaderParseFailed;
+ int shaderParseNumWarnings;
+
} trGlobals_t;
extern backEndState_t backEnd;
@@ -1236,7 +1250,9 @@ void R_ShaderList_f( void );
void R_ShaderInfo_f();
void R_ShaderMixedUse_f();
void R_CompleteShaderName_f( int startArg, int compArg );
-const char* R_GetShaderPath( const shader_t* shader );
+const char* R_GetShaderPath( const shader_t* shader );
+qbool R_EditShader( shader_t* sh, const shader_t* original, const char* shaderText );
+void R_SetShaderData( shader_t* sh, const shader_t* original );
/*
====================================================================
diff --git a/code/renderer/tr_shader.cpp b/code/renderer/tr_shader.cpp
index ca9f13e..00763ab 100644
--- a/code/renderer/tr_shader.cpp
+++ b/code/renderer/tr_shader.cpp
@@ -62,6 +62,39 @@ static shader_t* hashTable[FILE_HASH_SIZE];
#define MAX_SHADERTEXT_HASH 2048
static char** shaderTextHashTable[MAX_SHADERTEXT_HASH];
+static char parseMessage[1024];
+
+
+static void ParserWarning( PRINTF_FORMAT_STRING const char* format, ... )
+{
+ va_list ap;
+ va_start( ap, format );
+ Q_vsnprintf( parseMessage, sizeof( parseMessage ) - 1, format, ap );
+ va_end( ap );
+
+ ri.Printf( PRINT_WARNING, "WARNING: %s in shader '%s'\n", parseMessage, shader.name );
+
+ if ( tr.shaderParseSaveState ) {
+ if ( tr.shaderParseNumWarnings < ARRAY_LEN( tr.shaderParseWarnings ) ) {
+ Q_strncpyz( tr.shaderParseWarnings[tr.shaderParseNumWarnings++].message, parseMessage, sizeof( tr.shaderParseWarnings[0] ) );
+ }
+ }
+}
+
+static void ParserError( PRINTF_FORMAT_STRING const char* format, ... )
+{
+ va_list ap;
+ va_start( ap, format );
+ Q_vsnprintf( parseMessage, sizeof( parseMessage ) - 1, format, ap );
+ va_end( ap );
+
+ ri.Printf( PRINT_WARNING, "ERROR: %s in shader '%s'\n", parseMessage, shader.name );
+
+ if ( tr.shaderParseSaveState ) {
+ Q_strncpyz( tr.shaderParseError.message, parseMessage, sizeof( tr.shaderParseError.message ) );
+ }
+}
+
static qbool ParseVector( const char** text, int count, float *v )
{
@@ -70,14 +103,14 @@ static qbool ParseVector( const char** text, int count, float *v )
// FIXME: spaces are currently required after parens, should change parseext...
const char* token = COM_ParseExt( text, qfalse );
if ( strcmp( token, "(" ) ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
+ ParserWarning( "missing parenthesis" );
return qfalse;
}
for ( i = 0 ; i < count ; i++ ) {
token = COM_ParseExt( text, qfalse );
if ( !token[0] ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing vector element in shader '%s'\n", shader.name );
+ ParserWarning( "missing vector element" );
return qfalse;
}
v[i] = atof( token );
@@ -85,7 +118,7 @@ static qbool ParseVector( const char** text, int count, float *v )
token = COM_ParseExt( text, qfalse );
if ( strcmp( token, ")" ) ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
+ ParserWarning( "missing parenthesis" );
return qfalse;
}
@@ -113,7 +146,7 @@ static unsigned NameToAFunc( const char *funcname )
return GLS_ATEST_GE_80;
}
- ri.Printf( PRINT_WARNING, "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name );
+ ParserWarning( "invalid alphaFunc name '%s'", funcname );
return 0;
}
@@ -162,7 +195,7 @@ static int NameToSrcBlendMode( const char *name )
return GLS_SRCBLEND_ALPHA_SATURATE;
}
- ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
+ ParserWarning( "unknown blend mode '%s', using GL_ONE instead", name );
return GLS_SRCBLEND_ONE;
}
@@ -206,7 +239,7 @@ static int NameToDstBlendMode( const char *name )
return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR;
}
- ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
+ ParserWarning( "unknown blend mode '%s', using GL_ONE instead", name );
return GLS_DSTBLEND_ONE;
}
@@ -242,7 +275,7 @@ static genFunc_t NameToGenFunc( const char *funcname )
return GF_NOISE;
}
- ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name );
+ ParserWarning( "invalid genfunc name '%s'", funcname );
return GF_SIN;
}
@@ -252,7 +285,7 @@ static void ParseWaveForm( const char** text, waveForm_t* wave )
const char* token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing waveform parm" );
return;
}
wave->func = NameToGenFunc( token );
@@ -261,7 +294,7 @@ static void ParseWaveForm( const char** text, waveForm_t* wave )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing waveform parm" );
return;
}
wave->base = atof( token );
@@ -269,7 +302,7 @@ static void ParseWaveForm( const char** text, waveForm_t* wave )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing waveform parm" );
return;
}
wave->amplitude = atof( token );
@@ -277,7 +310,7 @@ static void ParseWaveForm( const char** text, waveForm_t* wave )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing waveform parm" );
return;
}
wave->phase = atof( token );
@@ -285,7 +318,7 @@ static void ParseWaveForm( const char** text, waveForm_t* wave )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing waveform parm" );
return;
}
wave->frequency = atof( token );
@@ -298,7 +331,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
texModInfo_t *tmi;
if ( stage->numTexMods == TR_MAX_TEXMODS ) {
- ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'\n", shader.name );
+ ParserError( "too many tcMod stages" );
return;
}
@@ -315,28 +348,28 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing tcMod turb parms" );
return;
}
tmi->wave.base = atof( token );
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
+ ParserWarning( "missing tcMod turb parms" );
return;
}
tmi->wave.amplitude = atof( token );
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
+ ParserWarning( "missing tcMod turb parms" );
return;
}
tmi->wave.phase = atof( token );
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
+ ParserWarning( "missing tcMod turb parms" );
return;
}
tmi->wave.frequency = atof( token );
@@ -351,7 +384,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing scale parms" );
return;
}
tmi->scale[0] = atof( token );
@@ -359,7 +392,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing scale parms" );
return;
}
tmi->scale[1] = atof( token );
@@ -373,14 +406,14 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing scale scroll parms" );
return;
}
tmi->scroll[0] = atof( token );
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing scale scroll parms" );
return;
}
tmi->scroll[1] = atof( token );
@@ -394,7 +427,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing stretch parms" );
return;
}
tmi->wave.func = NameToGenFunc( token );
@@ -402,7 +435,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing stretch parms" );
return;
}
tmi->wave.base = atof( token );
@@ -410,7 +443,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing stretch parms" );
return;
}
tmi->wave.amplitude = atof( token );
@@ -418,7 +451,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing stretch parms" );
return;
}
tmi->wave.phase = atof( token );
@@ -426,7 +459,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing stretch parms" );
return;
}
tmi->wave.frequency = atof( token );
@@ -441,7 +474,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing transform parms" );
return;
}
tmi->matrix[0][0] = atof( token );
@@ -449,7 +482,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing transform parms" );
return;
}
tmi->matrix[0][1] = atof( token );
@@ -457,7 +490,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing transform parms" );
return;
}
tmi->matrix[1][0] = atof( token );
@@ -465,7 +498,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing transform parms" );
return;
}
tmi->matrix[1][1] = atof( token );
@@ -473,7 +506,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing transform parms" );
return;
}
tmi->translate[0] = atof( token );
@@ -481,7 +514,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing transform parms" );
return;
}
tmi->translate[1] = atof( token );
@@ -496,7 +529,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing tcMod rotate parms" );
return;
}
tmi->rotateSpeed = atof( token );
@@ -511,7 +544,7 @@ static void ParseTexMod( const char** text, shaderStage_t *stage )
}
else
{
- ri.Printf( PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name );
+ ParserWarning( "unknown tcMod '%s'", token );
}
}
@@ -529,7 +562,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
token = COM_ParseExt( text, qtrue );
if ( !token[0] )
{
- ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" );
+ ParserError( "no matching '}' found" );
return qfalse;
}
@@ -545,7 +578,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
token = COM_ParseExt( text, qfalse );
if ( !token[0] )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name );
+ ParserError( "missing parameter for 'map' keyword" );
return qfalse;
}
@@ -578,7 +611,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
stage->bundle.image[0] = R_FindImageFile( token, shader.imgflags, TW_REPEAT );
if ( !stage->bundle.image[0] )
{
- ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
+ ParserError( "R_FindImageFile could not find '%s'", token );
return qfalse;
}
}
@@ -591,14 +624,14 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
token = COM_ParseExt( text, qfalse );
if ( !token[0] )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name );
+ ParserError( "missing parameter for 'clampmap' keyword" );
return qfalse;
}
stage->bundle.image[0] = R_FindImageFile( token, shader.imgflags, TW_CLAMP_TO_EDGE );
if ( !stage->bundle.image[0] )
{
- ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
+ ParserError( "R_FindImageFile could not find '%s'", token );
return qfalse;
}
}
@@ -610,7 +643,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
token = COM_ParseExt( text, qfalse );
if ( !token[0] )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMmap' keyword in shader '%s'\n", shader.name );
+ ParserError( "missing parameter for 'animMmap' keyword" );
return qfalse;
}
stage->bundle.imageAnimationSpeed = atof( token );
@@ -626,7 +659,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
stage->bundle.image[num] = R_FindImageFile( token, shader.imgflags, TW_REPEAT );
if ( !stage->bundle.image[num] )
{
- ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
+ ParserError( "R_FindImageFile could not find '%s'", token );
return qfalse;
}
stage->bundle.numImageAnimations++;
@@ -638,7 +671,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
token = COM_ParseExt( text, qfalse );
if ( !token[0] )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap' keyword in shader '%s'\n", shader.name );
+ ParserError( "missing parameter for 'videoMap' keyword" );
return qfalse;
}
stage->bundle.videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader));
@@ -655,7 +688,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
token = COM_ParseExt( text, qfalse );
if ( !token[0] )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name );
+ ParserError( "missing parameter for 'alphaFunc' keyword" );
return qfalse;
}
@@ -670,7 +703,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
if ( !token[0] )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name );
+ ParserError( "missing parameter for 'depthFunc' keyword" );
return qfalse;
}
@@ -684,7 +717,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
}
else
{
- ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name );
+ ParserWarning( "unknown depthFunc '%s'", token );
continue;
}
}
@@ -704,7 +737,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
+ ParserWarning( "missing parm for blendFunc" );
continue;
}
// check for "simple" blends first
@@ -724,7 +757,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
+ ParserWarning( "missing parm for blendFunc" );
continue;
}
blendDstBits = NameToDstBlendMode( token );
@@ -744,7 +777,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name );
+ ParserWarning( "missing parameters for rgbGen" );
continue;
}
@@ -799,7 +832,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
}
else
{
- ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name );
+ ParserWarning( "unknown rgbGen parameter '%s'", token );
continue;
}
}
@@ -811,7 +844,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name );
+ ParserWarning( "missing parameters for alphaGen" );
continue;
}
@@ -857,7 +890,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
if ( token[0] == 0 )
{
shader.portalRange = 256;
- ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name );
+ ParserWarning( "missing range parameter for alphaGen portal, defaulting to 256" );
}
else
{
@@ -866,7 +899,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
}
else
{
- ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name );
+ ParserWarning( "unknown alphaGen parameter '%s'", token );
continue;
}
}
@@ -878,7 +911,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing tcGen parm" );
continue;
}
@@ -902,7 +935,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
}
else
{
- ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name );
+ ParserWarning( "unknown tcGen parm '%s'", token );
}
}
//
@@ -924,7 +957,7 @@ static qbool ParseStage( const char** text, shaderStage_t* stage )
}
else
{
- ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name );
+ ParserError( "unknown parameter '%s'", token );
return qfalse;
}
}
@@ -992,12 +1025,12 @@ static void ParseDeform( const char** text )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing deform parm" );
return;
}
if ( shader.numDeforms == MAX_SHADER_DEFORMS ) {
- ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name );
+ ParserWarning( "too many deforms" );
return;
}
@@ -1029,7 +1062,7 @@ static void ParseDeform( const char** text )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing deformVertexes bulge parm" );
return;
}
ds->bulgeWidth = atof( token );
@@ -1037,7 +1070,7 @@ static void ParseDeform( const char** text )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing deformVertexes bulge parm" );
return;
}
ds->bulgeHeight = atof( token );
@@ -1045,7 +1078,7 @@ static void ParseDeform( const char** text )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing deformVertexes bulge parm" );
return;
}
ds->bulgeSpeed = atof( token );
@@ -1059,7 +1092,7 @@ static void ParseDeform( const char** text )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing deformVertexes parm" );
return;
}
@@ -1070,7 +1103,7 @@ static void ParseDeform( const char** text )
else
{
ds->deformationSpread = 100.0f;
- ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name );
+ ParserWarning( "illegal div value of 0 in deformVertexes" );
}
ParseWaveForm( text, &ds->deformationWave );
@@ -1083,7 +1116,7 @@ static void ParseDeform( const char** text )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing deformVertexes parm" );
return;
}
ds->deformationWave.amplitude = atof( token );
@@ -1091,7 +1124,7 @@ static void ParseDeform( const char** text )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing deformVertexes parm" );
return;
}
ds->deformationWave.frequency = atof( token );
@@ -1106,7 +1139,7 @@ static void ParseDeform( const char** text )
for ( i = 0 ; i < 3 ; i++ ) {
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
+ ParserWarning( "missing deformVertexes parm" );
return;
}
ds->moveVector[i] = atof( token );
@@ -1117,8 +1150,8 @@ static void ParseDeform( const char** text )
return;
}
- //ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name );
- ri.Error( ERR_FATAL, "unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name );
+ ParserWarning( "unknown deformVertexes subtype '%s'", token );
+ shader.numDeforms--;
}
@@ -1134,7 +1167,7 @@ static void ParseSkyParms( const char** text )
// outerbox
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
+ ParserWarning( "'skyParms' missing parameter" );
return;
}
if ( strcmp( token, "-" ) ) {
@@ -1150,7 +1183,7 @@ static void ParseSkyParms( const char** text )
// cloudheight
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
+ ParserWarning( "'skyParms' missing parameter" );
return;
}
shader.sky.cloudHeight = atof( token );
@@ -1162,7 +1195,7 @@ static void ParseSkyParms( const char** text )
// innerbox
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
+ ParserWarning( "'skyParms' missing parameter" );
return;
}
if ( strcmp( token, "-" ) ) {
@@ -1186,7 +1219,7 @@ static void ParseSort( const char** text )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 ) {
- ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name );
+ ParserWarning( "missing sort parameter" );
return;
}
@@ -1297,20 +1330,14 @@ static void ParseDepthFade( const char** text )
const char* token = COM_ParseExt( text, qfalse );
float scale;
if ( token[0] == '\0' || sscanf( token, "%f", &scale ) != 1 || scale <= 0.0f ) {
- ri.Printf( PRINT_WARNING,
- "WARNING: invalid/missing depth fade scale argument '%s' in shader '%s'! "
- "Ignoring the directive completely.\n",
- token, shader.name );
+ ParserWarning( "invalid/missing depth fade scale argument '%s'", token );
return;
}
token = COM_ParseExt( text, qfalse );
float bias;
if ( token[0] == '\0' || sscanf( token, "%f", &bias ) != 1 ) {
- ri.Printf( PRINT_WARNING,
- "WARNING: invalid/missing depth fade bias argument '%s' in shader '%s'! "
- "Ignoring the directive completely.\n",
- token, shader.name );
+ ParserWarning( "invalid/missing depth fade bias argument '%s'", token );
return;
}
@@ -1331,7 +1358,7 @@ static qbool ParseShader( const char** text )
token = COM_ParseExt( text, qtrue );
if ( token[0] != '{' )
{
- ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name );
+ ParserError( "expecting '{', found '%s' instead", token );
return qfalse;
}
@@ -1340,7 +1367,7 @@ static qbool ParseShader( const char** text )
token = COM_ParseExt( text, qtrue );
if ( !token[0] )
{
- ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name );
+ ParserError( "no concluding '}'" );
return qfalse;
}
@@ -1353,7 +1380,7 @@ static qbool ParseShader( const char** text )
else if ( token[0] == '{' )
{
if ( s >= MAX_SHADER_STAGES ) {
- ri.Error( ERR_DROP, "too many stages in shader %s\n", shader.name );
+ ParserError( "too many stages" );
return qfalse;
}
@@ -1430,13 +1457,14 @@ static qbool ParseShader( const char** text )
else if ( !Q_stricmp( token, "fogParms" ) )
{
if ( !ParseVector( text, 3, shader.fogParms.color ) ) {
+ ParserError( "invalid fogParms vector" );
return qfalse;
}
token = COM_ParseExt( text, qfalse );
if ( !token[0] )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name );
+ ParserWarning( "missing parm for 'fogParms' keyword" );
continue;
}
shader.fogParms.depthForOpaque = atof( token );
@@ -1469,7 +1497,7 @@ static qbool ParseShader( const char** text )
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
- ri.Printf( PRINT_WARNING, "WARNING: missing cull parms in shader '%s'\n", shader.name );
+ ParserWarning( "missing cull parms" );
continue;
}
@@ -1483,7 +1511,7 @@ static qbool ParseShader( const char** text )
}
else
{
- ri.Printf( PRINT_WARNING, "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name );
+ ParserWarning( "invalid cull parm '%s'", token );
}
continue;
}
@@ -1495,7 +1523,7 @@ static qbool ParseShader( const char** text )
}
else
{
- ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name );
+ ParserError( "unknown general shader parameter '%s'", token );
return qfalse;
}
}
@@ -1504,6 +1532,7 @@ static qbool ParseShader( const char** text )
// ignore shaders that don't have any stages, unless it is a sky or fog
//
if ( s == 0 && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG ) ) {
+ ParserError( "non-sky/fog shaders must have at least 1 stage" );
return qfalse;
}
@@ -1513,7 +1542,7 @@ static qbool ParseShader( const char** text )
}
-static int R_CompareShaders( const void* aPtr, const void* bPtr )
+static int CompareShaders( const void* aPtr, const void* bPtr )
{
const shader_t* const a = *(const shader_t**)aPtr;
const shader_t* const b = *(const shader_t**)bPtr;
@@ -1529,6 +1558,15 @@ static int R_CompareShaders( const void* aPtr, const void* bPtr )
}
+static void SortShaders()
+{
+ qsort( tr.sortedShaders, tr.numShaders, sizeof(shader_t*), &CompareShaders );
+ for ( int i = 0; i < tr.numShaders; ++i ) {
+ tr.sortedShaders[i]->sortedIndex = i;
+ }
+}
+
+
static qbool IsColorGenDynamic(colorGen_t cGen)
{
switch(cGen)
@@ -1746,10 +1784,7 @@ static void SortNewShader()
tr.sortedShaders[i+1] = newShader;
// sort it more aggressively for better performance
- qsort( tr.sortedShaders, tr.numShaders, sizeof(shader_t*), &R_CompareShaders );
- for ( i = 0; i < tr.numShaders; ++i ) {
- tr.sortedShaders[i]->sortedIndex = i;
- }
+ SortShaders();
//
// If we register a new shader when surfaces are already added,
@@ -1780,15 +1815,33 @@ static void SortNewShader()
}
-static shader_t* GeneratePermanentShader()
+static shader_t* GeneratePermanentShader( shader_t* sh )
{
if ( tr.numShaders == MAX_SHADERS ) {
- ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n");
+ ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n" );
return tr.defaultShader;
}
- shader_t* newShader = RI_New();
- *newShader = shader;
+ shader_t* newShader;
+ if ( sh != NULL ) {
+ newShader = sh;
+ *newShader = shader;
+ } else {
+ newShader = RI_New();
+ *newShader = shader;
+
+ tr.shaders[tr.numShaders] = newShader;
+ newShader->index = tr.numShaders;
+
+ tr.sortedShaders[tr.numShaders] = newShader;
+ newShader->sortedIndex = tr.numShaders;
+
+ tr.numShaders++;
+
+ const int hash = Q_FileHash( newShader->name, FILE_HASH_SIZE );
+ newShader->next = hashTable[hash];
+ hashTable[hash] = newShader;
+ }
if ( shader.sort <= SS_OPAQUE ) {
newShader->fogPass = FP_EQUAL;
@@ -1796,14 +1849,6 @@ static shader_t* GeneratePermanentShader()
newShader->fogPass = FP_LE;
}
- tr.shaders[ tr.numShaders ] = newShader;
- newShader->index = tr.numShaders;
-
- tr.sortedShaders[ tr.numShaders ] = newShader;
- newShader->sortedIndex = tr.numShaders;
-
- tr.numShaders++;
-
for ( int i = 0; i < newShader->numStages; ++i ) {
if ( !stages[i].active ) {
newShader->numStages = i;
@@ -1819,14 +1864,14 @@ static shader_t* GeneratePermanentShader()
ClassifyShader( newShader );
- SortNewShader();
+ if ( sh != NULL ) {
+ SortShaders();
+ } else {
+ SortNewShader();
+ }
renderPipeline->ProcessShader( *newShader );
- int hash = Q_FileHash(newShader->name, FILE_HASH_SIZE);
- newShader->next = hashTable[hash];
- hashTable[hash] = newShader;
-
return newShader;
}
@@ -2347,7 +2392,7 @@ static void BuildPerImageShaderList( shader_t* newShader )
// returns a freshly allocated shader with info
// copied from the current global working shader
-static shader_t* FinishShader()
+static shader_t* FinishShader( shader_t* sh = NULL )
{
int stage;
@@ -2370,7 +2415,7 @@ static shader_t* FinishShader()
// check for a missing texture
if ( !pStage->bundle.image[0] ) {
- ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name );
+ ParserWarning( "found a stage with no image" );
pStage->active = qfalse;
continue;
}
@@ -2540,7 +2585,7 @@ static shader_t* FinishShader()
FixUnusedBlendModes();
- shader_t* const newShader = GeneratePermanentShader();
+ shader_t* const newShader = GeneratePermanentShader( sh );
BuildPerImageShaderList( newShader );
@@ -2573,6 +2618,46 @@ static const char* FindShaderInShaderText( const char* shadername )
}
+qbool R_EditShader( shader_t* sh, const shader_t* original, const char* shaderText )
+{
+ Com_Memset( &shader, 0, sizeof( shader ) );
+ Q_strncpyz( shader.name, original->name, sizeof( shader.name ) ); // for console messages
+ Com_Memset( &stages, 0, sizeof( stages ) );
+ for ( int i = 0; i < MAX_SHADER_STAGES; i++ ) {
+ stages[i].texMods = texMods[i];
+ }
+
+ tr.shaderParseSaveState = qtrue;
+ tr.shaderParseNumWarnings = 0;
+ tr.shaderParseFailed = !ParseShader( &shaderText );
+ tr.shaderParseSaveState = qfalse;
+ if ( tr.shaderParseFailed ) {
+ *sh = *original;
+ SortShaders();
+
+ return qfalse;
+ }
+
+ FinishShader( sh );
+
+ Q_strncpyz( sh->name, original->name, sizeof( sh->name ) );
+ sh->index = original->index;
+ sh->lightmapIndex = original->lightmapIndex;
+ sh->text = original->text;
+ sh->next = original->next;
+ sh->isDynamic = true;
+
+ return qtrue;
+}
+
+
+void R_SetShaderData( shader_t* sh, const shader_t* original )
+{
+ *sh = *original;
+ SortShaders();
+}
+
+
/*
===============
R_FindShader
@@ -2780,7 +2865,7 @@ qhandle_t RE_RegisterShaderFromImage( const char* name, image_t* image )
static qhandle_t RE_RegisterShaderInternal( const char* name, int lightmapIndex, qbool mip )
{
if ( strlen( name ) >= MAX_QPATH ) {
- ri.Printf( PRINT_WARNING, "RE_RegisterShader: name exceeds MAX_QPATH\n" );
+ ri.Printf( PRINT_WARNING, "WARNING: shader name is too long: '%s'\n", name );
return 0;
}
@@ -2822,7 +2907,7 @@ qhandle_t RE_RegisterShaderNoMip( const char* name )
const shader_t* R_GetShaderByHandle( qhandle_t hShader )
{
if ((hShader < 0) || (hShader >= tr.numShaders)) {
- ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
+ ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: shader handle out of range: %d\n", hShader );
return tr.defaultShader;
}
return tr.shaders[hShader];
diff --git a/code/win32/win_main.cpp b/code/win32/win_main.cpp
index 54c46a8..e88a168 100644
--- a/code/win32/win_main.cpp
+++ b/code/win32/win_main.cpp
@@ -329,7 +329,7 @@ char *Sys_GetClipboardData( void )
data = (char*)Z_Malloc( GlobalSize( hClipboardData ) + 1 );
Q_strncpyz( data, cliptext, GlobalSize( hClipboardData ) );
GlobalUnlock( hClipboardData );
- strtok( data, "\n\r\b" );
+ //strtok( data, "\n\r\b" ); // keep all the lines...
}
}