/* ** gldefs.cpp ** GLDEFS parser ** **--------------------------------------------------------------------------- ** Copyright 2003 Timothy Stump ** Copyright 2005-2018 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions ** are met: ** ** 1. Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** 2. Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **--------------------------------------------------------------------------- ** */ #include #include "sc_man.h" #include "filesystem.h" #include "gi.h" //#include "r_state.h" #include "stats.h" #include "v_text.h" //#include "g_levellocals.h" #include "a_dynlight.h" #include "v_video.h" #include "skyboxtexture.h" #include "hwrenderer/postprocessing/hw_postprocessshader.h" #include "hw_material.h" #include "texturemanager.h" #include "gameconfigfile.h" #include "m_argv.h" #if 0 void AddLightDefaults(FLightDefaults *defaults, double attnFactor); void AddLightAssociation(const char *actor, const char *frame, const char *light); void InitializeActorLights(TArray &LightAssociations); void ParseColorization(FScanner& sc); extern TDeletingArray LightDefaults; extern int AttenuationIsSet; #endif bool addedcvars = false; struct ExtraUniformCVARData { FString Shader; FString Uniform; double* vec4 = nullptr; ExtraUniformCVARData* Next; }; static void do_uniform_set(float value, ExtraUniformCVARData* data) { if (!(data->vec4)) { for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) { PostProcessShader& shader = PostProcessShaders[i]; if (shader.Name.Compare(data->Shader) == 0) { data->vec4 = shader.Uniforms[data->Uniform].Values; } } } double* vec4 = data->vec4; if (vec4) { vec4[0] = value; vec4[1] = 0.0; vec4[2] = 0.0; vec4[3] = 1.0; } if (data->Next) do_uniform_set(value, data->Next); } void uniform_callback_int(FIntCVar &self) { do_uniform_set ((float)self, (ExtraUniformCVARData*)self.GetExtraDataPointer()); } void uniform_callback_float(FFloatCVar &self) { do_uniform_set ((float)self, (ExtraUniformCVARData*)self.GetExtraDataPointer()); } //----------------------------------------------------------------------------- // // ParseVavoomSkybox // //----------------------------------------------------------------------------- #if 0 static void ParseVavoomSkybox() { int lump = fileSystem.CheckNumForName("SKYBOXES"); if (lump < 0) return; FScanner sc(lump); while (sc.GetString()) { int facecount=0; int maplump = -1; bool error = false; FString s = sc.String; FSkyBox * sb = new FSkyBox(sc.String); sb->fliptop = true; sc.MustGetStringName("{"); while (!sc.CheckString("}")) { if (facecount<6) { sc.MustGetStringName("{"); sc.MustGetStringName("map"); sc.MustGetString(); maplump = fileSystem.CheckNumForFullName(sc.String, true); auto tex = TexMan.FindGameTexture(sc.String, ETextureType::Wall, FTextureManager::TEXMAN_TryAny); if (tex == NULL) { sc.ScriptMessage("Texture '%s' not found in Vavoom skybox '%s'\n", sc.String, s.GetChars()); error = true; } sb->faces[facecount] = tex; sc.MustGetStringName("}"); } facecount++; } if (facecount != 6) { sc.ScriptError("%s: Skybox definition requires 6 faces", s.GetChars()); } sb->SetSize(); if (!error) { TexMan.AddGameTexture(MakeGameTexture(sb, s, ETextureType::Override)); } } } #endif //========================================================================== // // light definition keywords // //========================================================================== static const char *LightTags[]= { "color", "size", "secondarySize", "offset", "chance", "interval", "scale", "frame", "light", "{", "}", "subtractive", "additive", "halo", "dontlightself", "attenuate", "dontlightactors", "spot", "noshadowmap", nullptr }; enum { LIGHTTAG_COLOR, LIGHTTAG_SIZE, LIGHTTAG_SECSIZE, LIGHTTAG_OFFSET, LIGHTTAG_CHANCE, LIGHTTAG_INTERVAL, LIGHTTAG_SCALE, LIGHTTAG_FRAME, LIGHTTAG_LIGHT, LIGHTTAG_OPENBRACE, LIGHTTAG_CLOSEBRACE, LIGHTTAG_SUBTRACTIVE, LIGHTTAG_ADDITIVE, LIGHTTAG_HALO, LIGHTTAG_DONTLIGHTSELF, LIGHTTAG_ATTENUATE, LIGHTTAG_DONTLIGHTACTORS, LIGHTTAG_SPOT, LIGHTTAG_NOSHADOWMAP, }; //========================================================================== // // Top level keywords // //========================================================================== // these are the core types available in the *DEFS lump static const char *CoreKeywords[]= { "pointlight", "pulselight", "flickerlight", "flickerlight2", "sectorlight", "object", "clearlights", "shader", "clearshaders", "skybox", "glow", "brightmap", "disable_fullbright", "hardwareshader", "detail", "#include", "material", "lightsizefactor", "colorization", nullptr }; enum { LIGHT_POINT, LIGHT_PULSE, LIGHT_FLICKER, LIGHT_FLICKER2, LIGHT_SECTOR, LIGHT_OBJECT, LIGHT_CLEAR, TAG_SHADER, TAG_CLEARSHADERS, TAG_SKYBOX, TAG_GLOW, TAG_BRIGHTMAP, TAG_DISABLE_FB, TAG_HARDWARESHADER, TAG_DETAIL, TAG_INCLUDE, TAG_MATERIAL, TAG_LIGHTSIZEFACTOR, TAG_COLORIZATION, }; //========================================================================== // // GLDEFS parser // //========================================================================== class GLDefsParser { FScanner sc; int workingLump; int ScriptDepth = 0; TArray &LightAssociations; double lightSizeFactor = 1.; //========================================================================== // // This is only here so any shader definition for ZDoomGL can be skipped // There is no functionality for this stuff! // //========================================================================== bool ParseShader() { int ShaderDepth = 0; if (sc.GetString()) { char *tmp; tmp = strstr(sc.String, "{"); while (tmp) { ShaderDepth++; tmp++; tmp = strstr(tmp, "{"); } tmp = strstr(sc.String, "}"); while (tmp) { ShaderDepth--; tmp++; tmp = strstr(tmp, "}"); } if (ShaderDepth == 0) return true; } return false; } //========================================================================== // // Parses a GLBoom+ detail texture definition // // Syntax is this: // detail // { // (walls | flats) [default_detail_name [width [height [offset_x [offset_y]]]]] // { // texture_name [detail_name [width [height [offset_x [offset_y]]]]] // } // } // This merely parses the block and returns no error if valid. The feature // is not actually implemented, so nothing else happens. // // The semantics of this are too horrible to comprehend (default detail texture???) // so if this ever gets done, the parser will look different. //========================================================================== #if 0 void ParseDetailTexture() { while (!sc.CheckToken('}')) { sc.MustGetString(); if (sc.Compare("walls") || sc.Compare("flats")) { if (!sc.CheckToken('{')) { sc.MustGetString(); // Default detail texture if (sc.CheckFloat()) // Width if (sc.CheckFloat()) // Height if (sc.CheckFloat()) // OffsX if (sc.CheckFloat()) // OffsY { // Nothing } } else sc.UnGet(); sc.MustGetToken('{'); while (!sc.CheckToken('}')) { sc.MustGetString(); // Texture if (sc.GetString()) // Detail texture { if (sc.CheckFloat()) // Width if (sc.CheckFloat()) // Height if (sc.CheckFloat()) // OffsX if (sc.CheckFloat()) // OffsY { // Nothing } } else sc.UnGet(); } } } } #endif //========================================================================== // // // //========================================================================== float ParseFloat(FScanner &sc) { sc.MustGetFloat(); return float(sc.Float); } int ParseInt(FScanner &sc) { sc.MustGetNumber(); return sc.Number; } char *ParseString(FScanner &sc) { sc.GetString(); return sc.String; } void ParseTriple(FScanner &sc, float floatVal[3]) { for (int i = 0; i < 3; i++) { floatVal[i] = ParseFloat(sc); } } //----------------------------------------------------------------------------- // // // //----------------------------------------------------------------------------- #if 0 void AddLightAssociation(const char *actor, const char *frame, const char *light) { FLightAssociation *temp; unsigned int i; FLightAssociation assoc(actor, frame, light); for (i = 0; i < LightAssociations.Size(); i++) { temp = &LightAssociations[i]; if (temp->ActorName() == assoc.ActorName()) { if (strcmp(temp->FrameName(), assoc.FrameName()) == 0) { temp->ReplaceLightName(assoc.Light()); return; } } } LightAssociations.Push(assoc); } #endif //----------------------------------------------------------------------------- // // Note: The different light type parsers really could use some consolidation... // //----------------------------------------------------------------------------- #if 0 void ParsePointLight() { int type; float floatTriple[3]; int intVal; FLightDefaults *defaults; // get name sc.GetString(); FName name = sc.String; // check for opening brace sc.GetString(); if (sc.Compare("{")) { defaults = new FLightDefaults(name, PointLight); ScriptDepth++; while (ScriptDepth) { sc.GetString(); type = sc.MatchString(LightTags); switch (type) { case LIGHTTAG_OPENBRACE: ScriptDepth++; break; case LIGHTTAG_CLOSEBRACE: ScriptDepth--; break; case LIGHTTAG_COLOR: ParseTriple(sc, floatTriple); defaults->SetArg(LIGHT_RED, clamp((int)(floatTriple[0] * 255), 0, 255)); defaults->SetArg(LIGHT_GREEN, clamp((int)(floatTriple[1] * 255), 0, 255)); defaults->SetArg(LIGHT_BLUE, clamp((int)(floatTriple[2] * 255), 0, 255)); break; case LIGHTTAG_OFFSET: ParseTriple(sc, floatTriple); defaults->SetOffset(floatTriple); break; case LIGHTTAG_SIZE: intVal = clamp(ParseInt(sc), 1, 1024); defaults->SetArg(LIGHT_INTENSITY, intVal); break; case LIGHTTAG_SUBTRACTIVE: defaults->SetSubtractive(ParseInt(sc) != 0); break; case LIGHTTAG_ADDITIVE: defaults->SetAdditive(ParseInt(sc) != 0); break; case LIGHTTAG_HALO: // old development garbage ParseInt(sc); break; case LIGHTTAG_NOSHADOWMAP: defaults->SetNoShadowmap(ParseInt(sc) != 0); break; case LIGHTTAG_DONTLIGHTSELF: defaults->SetDontLightSelf(ParseInt(sc) != 0); break; case LIGHTTAG_ATTENUATE: defaults->SetAttenuate(ParseInt(sc) != 0); break; case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; case LIGHTTAG_SPOT: { float innerAngle = ParseFloat(sc); float outerAngle = ParseFloat(sc); defaults->SetSpot(true); defaults->SetSpotInnerAngle(innerAngle); defaults->SetSpotOuterAngle(outerAngle); } break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } } #if 0 AddLightDefaults(defaults, lightSizeFactor); #endif } else { sc.ScriptError("Expected '{'.\n"); } } #endif //----------------------------------------------------------------------------- // // // //----------------------------------------------------------------------------- #if 0 void ParsePulseLight() { int type; float floatVal, floatTriple[3]; int intVal; FLightDefaults *defaults; // get name sc.GetString(); FName name = sc.String; // check for opening brace sc.GetString(); if (sc.Compare("{")) { defaults = new FLightDefaults(name, PulseLight); ScriptDepth++; while (ScriptDepth) { sc.GetString(); type = sc.MatchString(LightTags); switch (type) { case LIGHTTAG_OPENBRACE: ScriptDepth++; break; case LIGHTTAG_CLOSEBRACE: ScriptDepth--; break; case LIGHTTAG_COLOR: ParseTriple(sc, floatTriple); defaults->SetArg(LIGHT_RED, clamp((int)(floatTriple[0] * 255), 0, 255)); defaults->SetArg(LIGHT_GREEN, clamp((int)(floatTriple[1] * 255), 0, 255)); defaults->SetArg(LIGHT_BLUE, clamp((int)(floatTriple[2] * 255), 0, 255)); break; case LIGHTTAG_OFFSET: ParseTriple(sc, floatTriple); defaults->SetOffset(floatTriple); break; case LIGHTTAG_SIZE: intVal = clamp(ParseInt(sc), 1, 1024); defaults->SetArg(LIGHT_INTENSITY, intVal); break; case LIGHTTAG_SECSIZE: intVal = clamp(ParseInt(sc), 1, 1024); defaults->SetArg(LIGHT_SECONDARY_INTENSITY, intVal); break; case LIGHTTAG_INTERVAL: floatVal = ParseFloat(sc); defaults->SetParameter(floatVal * TICRATE); break; case LIGHTTAG_SUBTRACTIVE: defaults->SetSubtractive(ParseInt(sc) != 0); break; case LIGHTTAG_HALO: // old development garbage ParseInt(sc); break; case LIGHTTAG_NOSHADOWMAP: defaults->SetNoShadowmap(ParseInt(sc) != 0); break; case LIGHTTAG_DONTLIGHTSELF: defaults->SetDontLightSelf(ParseInt(sc) != 0); break; case LIGHTTAG_ATTENUATE: defaults->SetAttenuate(ParseInt(sc) != 0); break; case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; case LIGHTTAG_SPOT: { float innerAngle = ParseFloat(sc); float outerAngle = ParseFloat(sc); defaults->SetSpot(true); defaults->SetSpotInnerAngle(innerAngle); defaults->SetSpotOuterAngle(outerAngle); } break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } } defaults->OrderIntensities(); AddLightDefaults(defaults, lightSizeFactor); } else { sc.ScriptError("Expected '{'.\n"); } } #endif //----------------------------------------------------------------------------- // // // //----------------------------------------------------------------------------- #if 0 void ParseFlickerLight() { int type; float floatVal, floatTriple[3]; int intVal; FLightDefaults *defaults; // get name sc.GetString(); FName name = sc.String; // check for opening brace sc.GetString(); if (sc.Compare("{")) { defaults = new FLightDefaults(name, FlickerLight); ScriptDepth++; while (ScriptDepth) { sc.GetString(); type = sc.MatchString(LightTags); switch (type) { case LIGHTTAG_OPENBRACE: ScriptDepth++; break; case LIGHTTAG_CLOSEBRACE: ScriptDepth--; break; case LIGHTTAG_COLOR: ParseTriple(sc, floatTriple); defaults->SetArg(LIGHT_RED, clamp((int)(floatTriple[0] * 255), 0, 255)); defaults->SetArg(LIGHT_GREEN, clamp((int)(floatTriple[1] * 255), 0, 255)); defaults->SetArg(LIGHT_BLUE, clamp((int)(floatTriple[2] * 255), 0, 255)); break; case LIGHTTAG_OFFSET: ParseTriple(sc, floatTriple); defaults->SetOffset(floatTriple); break; case LIGHTTAG_SIZE: intVal = clamp(ParseInt(sc), 1, 1024); defaults->SetArg(LIGHT_INTENSITY, intVal); break; case LIGHTTAG_SECSIZE: intVal = clamp(ParseInt(sc), 1, 1024); defaults->SetArg(LIGHT_SECONDARY_INTENSITY, intVal); break; case LIGHTTAG_CHANCE: floatVal = ParseFloat(sc); defaults->SetParameter(floatVal*360.); break; case LIGHTTAG_SUBTRACTIVE: defaults->SetSubtractive(ParseInt(sc) != 0); break; case LIGHTTAG_HALO: // old development garbage ParseInt(sc); break; case LIGHTTAG_NOSHADOWMAP: defaults->SetNoShadowmap(ParseInt(sc) != 0); break; case LIGHTTAG_DONTLIGHTSELF: defaults->SetDontLightSelf(ParseInt(sc) != 0); break; case LIGHTTAG_ATTENUATE: defaults->SetAttenuate(ParseInt(sc) != 0); break; case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; case LIGHTTAG_SPOT: { float innerAngle = ParseFloat(sc); float outerAngle = ParseFloat(sc); defaults->SetSpot(true); defaults->SetSpotInnerAngle(innerAngle); defaults->SetSpotOuterAngle(outerAngle); } break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } } defaults->OrderIntensities(); AddLightDefaults(defaults, lightSizeFactor); } else { sc.ScriptError("Expected '{'.\n"); } } #endif //----------------------------------------------------------------------------- // // // //----------------------------------------------------------------------------- #if 0 void ParseFlickerLight2() { int type; float floatVal, floatTriple[3]; int intVal; FLightDefaults *defaults; // get name sc.GetString(); FName name = sc.String; // check for opening brace sc.GetString(); if (sc.Compare("{")) { defaults = new FLightDefaults(name, RandomFlickerLight); ScriptDepth++; while (ScriptDepth) { sc.GetString(); type = sc.MatchString(LightTags); switch (type) { case LIGHTTAG_OPENBRACE: ScriptDepth++; break; case LIGHTTAG_CLOSEBRACE: ScriptDepth--; break; case LIGHTTAG_COLOR: ParseTriple(sc, floatTriple); defaults->SetArg(LIGHT_RED, clamp((int)(floatTriple[0] * 255), 0, 255)); defaults->SetArg(LIGHT_GREEN, clamp((int)(floatTriple[1] * 255), 0, 255)); defaults->SetArg(LIGHT_BLUE, clamp((int)(floatTriple[2] * 255), 0, 255)); break; case LIGHTTAG_OFFSET: ParseTriple(sc, floatTriple); defaults->SetOffset(floatTriple); break; case LIGHTTAG_SIZE: intVal = clamp(ParseInt(sc), 1, 1024); defaults->SetArg(LIGHT_INTENSITY, intVal); break; case LIGHTTAG_SECSIZE: intVal = clamp(ParseInt(sc), 1, 1024); defaults->SetArg(LIGHT_SECONDARY_INTENSITY, intVal); break; case LIGHTTAG_INTERVAL: floatVal = ParseFloat(sc); defaults->SetParameter(floatVal * 360.); break; case LIGHTTAG_SUBTRACTIVE: defaults->SetSubtractive(ParseInt(sc) != 0); break; case LIGHTTAG_HALO: // old development garbage ParseInt(sc); break; case LIGHTTAG_NOSHADOWMAP: defaults->SetNoShadowmap(ParseInt(sc) != 0); break; case LIGHTTAG_DONTLIGHTSELF: defaults->SetDontLightSelf(ParseInt(sc) != 0); break; case LIGHTTAG_ATTENUATE: defaults->SetAttenuate(ParseInt(sc) != 0); break; case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; case LIGHTTAG_SPOT: { float innerAngle = ParseFloat(sc); float outerAngle = ParseFloat(sc); defaults->SetSpot(true); defaults->SetSpotInnerAngle(innerAngle); defaults->SetSpotOuterAngle(outerAngle); } break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } } if (defaults->GetArg(LIGHT_SECONDARY_INTENSITY) < defaults->GetArg(LIGHT_INTENSITY)) { int v = defaults->GetArg(LIGHT_SECONDARY_INTENSITY); defaults->SetArg(LIGHT_SECONDARY_INTENSITY, defaults->GetArg(LIGHT_INTENSITY)); defaults->SetArg(LIGHT_INTENSITY, v); } AddLightDefaults(defaults, lightSizeFactor); } else { sc.ScriptError("Expected '{'.\n"); } } #endif //----------------------------------------------------------------------------- // // // //----------------------------------------------------------------------------- #if 0 void ParseSectorLight() { int type; float floatVal; float floatTriple[3]; FLightDefaults *defaults; // get name sc.GetString(); FName name = sc.String; // check for opening brace sc.GetString(); if (sc.Compare("{")) { defaults = new FLightDefaults(name, SectorLight); ScriptDepth++; while (ScriptDepth) { sc.GetString(); type = sc.MatchString(LightTags); switch (type) { case LIGHTTAG_OPENBRACE: ScriptDepth++; break; case LIGHTTAG_CLOSEBRACE: ScriptDepth--; break; case LIGHTTAG_COLOR: ParseTriple(sc, floatTriple); defaults->SetArg(LIGHT_RED, clamp((int)(floatTriple[0] * 255), 0, 255)); defaults->SetArg(LIGHT_GREEN, clamp((int)(floatTriple[1] * 255), 0, 255)); defaults->SetArg(LIGHT_BLUE, clamp((int)(floatTriple[2] * 255), 0, 255)); break; case LIGHTTAG_OFFSET: ParseTriple(sc, floatTriple); defaults->SetOffset(floatTriple); break; case LIGHTTAG_SCALE: floatVal = ParseFloat(sc); defaults->SetArg(LIGHT_INTENSITY, clamp((int)(floatVal * 255), 1, 1024)); break; case LIGHTTAG_SUBTRACTIVE: defaults->SetSubtractive(ParseInt(sc) != 0); break; case LIGHTTAG_HALO: // old development garbage ParseInt(sc); break; case LIGHTTAG_NOSHADOWMAP: defaults->SetNoShadowmap(ParseInt(sc) != 0); break; case LIGHTTAG_DONTLIGHTSELF: defaults->SetDontLightSelf(ParseInt(sc) != 0); break; case LIGHTTAG_ATTENUATE: defaults->SetAttenuate(ParseInt(sc) != 0); break; case LIGHTTAG_DONTLIGHTACTORS: defaults->SetDontLightActors(ParseInt(sc) != 0); break; case LIGHTTAG_SPOT: { float innerAngle = ParseFloat(sc); float outerAngle = ParseFloat(sc); defaults->SetSpot(true); defaults->SetSpotInnerAngle(innerAngle); defaults->SetSpotOuterAngle(outerAngle); } break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } } AddLightDefaults(defaults, lightSizeFactor); } else { sc.ScriptError("Expected '{'.\n"); } } #endif //----------------------------------------------------------------------------- // // // //----------------------------------------------------------------------------- #if 0 void ParseFrame(const FString &name) { int type, startDepth; FString frameName; // get name sc.GetString(); if (strlen(sc.String) > 8) { sc.ScriptError("Name longer than 8 characters: %s\n", sc.String); } frameName = sc.String; frameName.ToUpper(); startDepth = ScriptDepth; // check for opening brace sc.GetString(); if (sc.Compare("{")) { ScriptDepth++; while (ScriptDepth > startDepth) { sc.GetString(); type = sc.MatchString(LightTags); switch (type) { case LIGHTTAG_OPENBRACE: ScriptDepth++; break; case LIGHTTAG_CLOSEBRACE: ScriptDepth--; break; case LIGHTTAG_LIGHT: ParseString(sc); AddLightAssociation(name, frameName, sc.String); break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } } } else { sc.ScriptError("Expected '{'.\n"); } } #endif //----------------------------------------------------------------------------- // // // //----------------------------------------------------------------------------- #if 0 void ParseObject() { int type; FString name; // get name sc.GetString(); name = sc.String; if (!PClass::FindActor(name)) sc.ScriptMessage("Warning: dynamic lights attached to non-existent actor %s\n", name.GetChars()); // check for opening brace sc.GetString(); if (sc.Compare("{")) { ScriptDepth++; while (ScriptDepth) { sc.GetString(); type = sc.MatchString(LightTags); switch (type) { case LIGHTTAG_OPENBRACE: ScriptDepth++; break; case LIGHTTAG_CLOSEBRACE: ScriptDepth--; break; case LIGHTTAG_FRAME: ParseFrame(name); break; default: sc.ScriptError("Unknown tag: %s\n", sc.String); } } } else { sc.ScriptError("Expected '{'.\n"); } } #endif //----------------------------------------------------------------------------- // // // //----------------------------------------------------------------------------- #if 0 void ParseGldefSkybox() { int facecount=0; sc.MustGetString(); FString s = sc.String; FSkyBox * sb = new FSkyBox(s); if (sc.CheckString("fliptop")) { sb->fliptop = true; } sc.MustGetStringName("{"); while (!sc.CheckString("}")) { sc.MustGetString(); if (facecount<6) { sb->faces[facecount] = TexMan.GetGameTexture(TexMan.GetTextureID(sc.String, ETextureType::Wall, FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_Overridable)); } facecount++; } if (facecount != 3 && facecount != 6) { sc.ScriptError("%s: Skybox definition requires either 3 or 6 faces", s.GetChars()); } sb->SetSize(); TexMan.AddGameTexture(MakeGameTexture(sb, s, ETextureType::Override)); } #endif //=========================================================================== // // Reads glow definitions from GLDEFS // //=========================================================================== #if 0 void ParseGlow() { sc.MustGetStringName("{"); while (!sc.CheckString("}")) { sc.MustGetString(); if (sc.Compare("FLATS")) { sc.MustGetStringName("{"); while (!sc.CheckString("}")) { sc.MustGetString(); FTextureID flump=TexMan.CheckForTexture(sc.String, ETextureType::Flat,FTextureManager::TEXMAN_TryAny); auto tex = TexMan.GetGameTexture(flump); if (tex) tex->SetAutoGlowing(); } } else if (sc.Compare("WALLS")) { sc.MustGetStringName("{"); while (!sc.CheckString("}")) { sc.MustGetString(); FTextureID flump=TexMan.CheckForTexture(sc.String, ETextureType::Wall,FTextureManager::TEXMAN_TryAny); auto tex = TexMan.GetGameTexture(flump); if (tex) tex->SetAutoGlowing(); } } else if (sc.Compare("TEXTURE")) { sc.SetCMode(true); sc.MustGetString(); FTextureID flump=TexMan.CheckForTexture(sc.String, ETextureType::Flat,FTextureManager::TEXMAN_TryAny); auto tex = TexMan.GetGameTexture(flump); sc.MustGetStringName(","); sc.MustGetString(); PalEntry color = V_GetColor(sc.String); //sc.MustGetStringName(","); //sc.MustGetNumber(); if (sc.CheckString(",")) { if (sc.CheckNumber()) { if (tex) tex->SetGlowHeight(sc.Number); if (!sc.CheckString(",")) goto skip_fb; } sc.MustGetStringName("fullbright"); if (tex) tex->SetFullbright(); } skip_fb: sc.SetCMode(false); if (tex && color != 0) { tex->SetGlowing(color); } } } } #endif //========================================================================== // // Parses a brightmap definition // //========================================================================== #if 0 void ParseBrightmap() { ETextureType type = ETextureType::Any; bool disable_fullbright=false; bool thiswad = false; bool iwad = false; FGameTexture *bmtex = NULL; sc.MustGetString(); if (sc.Compare("texture")) type = ETextureType::Wall; else if (sc.Compare("flat")) type = ETextureType::Flat; else if (sc.Compare("sprite")) type = ETextureType::Sprite; else sc.UnGet(); sc.MustGetString(); FTextureID no = TexMan.CheckForTexture(sc.String, type, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_Overridable); auto tex = TexMan.GetGameTexture(no); sc.MustGetToken('{'); while (!sc.CheckToken('}')) { sc.MustGetString(); if (sc.Compare("disablefullbright")) { // This can also be used without a brightness map to disable // fullbright in rotations that only use brightness maps on // other angles. disable_fullbright = true; } else if (sc.Compare("thiswad")) { // only affects textures defined in the WAD containing the definition file. thiswad = true; } else if (sc.Compare ("iwad")) { // only affects textures defined in the IWAD. iwad = true; } else if (sc.Compare ("map")) { sc.MustGetString(); if (bmtex != NULL) { Printf("Multiple brightmap definitions in texture %s\n", tex? tex->GetName().GetChars() : "(null)"); } bmtex = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); if (bmtex == NULL) Printf("Brightmap '%s' not found in texture '%s'\n", sc.String, tex? tex->GetName().GetChars() : "(null)"); } } if (!tex) { return; } if (thiswad || iwad) { bool useme = false; int lumpnum = tex->GetSourceLump(); if (lumpnum != -1) { if (iwad && fileSystem.GetFileContainer(lumpnum) <= fileSystem.GetMaxIwadNum()) useme = true; if (thiswad && fileSystem.GetFileContainer(lumpnum) == fileSystem.GetFileContainer(workingLump)) useme = true; } if (!useme) return; } if (bmtex != NULL) { tex->SetBrightmap(bmtex); } tex->SetDisableFullbright(disable_fullbright); } #endif #if 0 void SetShaderIndex(FGameTexture *tex, unsigned index) { auto desc = usershaders[index - FIRST_USER_SHADER]; if (desc.disablealphatest) { tex->SetTranslucent(true); } tex->SetShaderIndex(index); } #endif //========================================================================== // // Parses a material definition // //========================================================================== #if 0 void ParseMaterial() { ETextureType type = ETextureType::Any; bool disable_fullbright = false; bool disable_fullbright_specified = false; bool thiswad = false; bool iwad = false; UserShaderDesc usershader; TArray texNameList; TArray texNameIndex; float speed = 1.f; MaterialLayers mlay = { -1000, -1000 }; FGameTexture* textures[6] = {}; const char *keywords[7] = { "brightmap", "normal", "specular", "metallic", "roughness", "ao", nullptr }; const char *notFound[6] = { "Brightmap", "Normalmap", "Specular texture", "Metallic texture", "Roughness texture", "Ambient occlusion texture" }; sc.MustGetString(); if (sc.Compare("texture")) type = ETextureType::Wall; else if (sc.Compare("flat")) type = ETextureType::Flat; else if (sc.Compare("sprite")) type = ETextureType::Sprite; else sc.UnGet(); sc.MustGetString(); FTextureID no = TexMan.CheckForTexture(sc.String, type, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_Overridable); auto tex = TexMan.GetGameTexture(no); if (tex == nullptr) { sc.ScriptMessage("Material definition refers nonexistent texture '%s'\n", sc.String); } else tex->AddAutoMaterials(); // We need these before setting up the texture. sc.MustGetToken('{'); while (!sc.CheckToken('}')) { sc.MustGetString(); if (sc.Compare("disablefullbright")) { // This can also be used without a brightness map to disable // fullbright in rotations that only use brightness maps on // other angles. disable_fullbright = true; disable_fullbright_specified = true; } else if (sc.Compare("thiswad")) { // only affects textures defined in the WAD containing the definition file. thiswad = true; } else if (sc.Compare ("iwad")) { // only affects textures defined in the IWAD. iwad = true; } else if (sc.Compare("glossiness")) { sc.MustGetFloat(); mlay.Glossiness = (float)sc.Float; } else if (sc.Compare("specularlevel")) { sc.MustGetFloat(); mlay.SpecularLevel = (float)sc.Float; } else if (sc.Compare("speed")) { sc.MustGetFloat(); speed = float(sc.Float); } else if (sc.Compare("shader")) { sc.MustGetString(); usershader.shader = sc.String; } else if (sc.Compare("texture")) { sc.MustGetString(); FString textureName = sc.String; for (FString &texName : texNameList) { if (!texName.Compare(textureName)) { sc.ScriptError("Trying to redefine custom hardware shader texture '%s' in texture '%s'\n", textureName.GetChars(), tex ? tex->GetName().GetChars() : "(null)"); } } sc.MustGetString(); if (tex) { bool okay = false; for (size_t i = 0; i < countof(mlay.CustomShaderTextures); i++) { if (!mlay.CustomShaderTextures[i]) { mlay.CustomShaderTextures[i] = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); if (!mlay.CustomShaderTextures[i]) { sc.ScriptError("Custom hardware shader texture '%s' not found in texture '%s'\n", sc.String, tex->GetName().GetChars()); } texNameList.Push(textureName); texNameIndex.Push((int)i); okay = true; break; } } if (!okay) { sc.ScriptError("Error: out of texture units in texture '%s'", tex->GetName().GetChars()); } } } else if (sc.Compare("define")) { sc.MustGetString(); FString defineName = sc.String; FString defineValue = ""; if (sc.CheckToken('=')) { sc.MustGetString(); defineValue = sc.String; } usershader.defines.AppendFormat("#define %s %s\n", defineName.GetChars(), defineValue.GetChars()); } else { for (int i = 0; keywords[i] != nullptr; i++) { if (sc.Compare (keywords[i])) { sc.MustGetString(); if (textures[i]) Printf("Multiple %s definitions in texture %s\n", keywords[i], tex? tex->GetName().GetChars() : "(null)"); textures[i] = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); if (!textures[i]) Printf("%s '%s' not found in texture '%s'\n", notFound[i], sc.String, tex? tex->GetName().GetChars() : "(null)"); break; } } } } if (!tex) { return; } if (thiswad || iwad) { bool useme = false; int lumpnum = tex->GetSourceLump(); if (lumpnum != -1) { if (iwad && fileSystem.GetFileContainer(lumpnum) <= fileSystem.GetMaxIwadNum()) useme = true; if (thiswad && fileSystem.GetFileContainer(lumpnum) == fileSystem.GetFileContainer(workingLump)) useme = true; } if (!useme) return; } FGameTexture **bindings[6] = { &mlay.Brightmap, &mlay.Normal, &mlay.Specular, &mlay.Metallic, &mlay.Roughness, &mlay.AmbientOcclusion }; for (int i = 0; keywords[i] != nullptr; i++) { if (textures[i]) { *bindings[i] = textures[i]; } } if (disable_fullbright_specified) tex->SetDisableFullbright(disable_fullbright); if (usershader.shader.IsNotEmpty()) { int firstUserTexture; if ((mlay.Normal || tex->Normal.get()) && (mlay.Specular || tex->Specular.get())) { usershader.shaderType = SHADER_Specular; firstUserTexture = 7; } else if ((mlay.Normal || tex->Normal.get()) && (mlay.Metallic || tex->Metallic.get()) && (mlay.Roughness || tex->Roughness.get()) && (mlay.AmbientOcclusion || tex->AmbientOcclusion.get())) { usershader.shaderType = SHADER_PBR; firstUserTexture = 9; } else { usershader.shaderType = SHADER_Default; firstUserTexture = 5; } for (unsigned int i = 0; i < texNameList.Size(); i++) { usershader.defines.AppendFormat("#define %s texture%d\n", texNameList[i].GetChars(), texNameIndex[i] + firstUserTexture); } if (tex->isWarped() != 0) { Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->GetName().GetChars()); return; } tex->SetShaderSpeed(speed); for (unsigned i = 0; i < usershaders.Size(); i++) { if (!usershaders[i].shader.CompareNoCase(usershader.shader) && usershaders[i].shaderType == usershader.shaderType && !usershaders[i].defines.Compare(usershader.defines)) { SetShaderIndex(tex, i + FIRST_USER_SHADER); tex->SetShaderLayers(mlay); return; } } SetShaderIndex(tex, usershaders.Push(usershader) + FIRST_USER_SHADER); } tex->SetShaderLayers(mlay); } #endif //========================================================================== // // Parses a shader definition // //========================================================================== void ParseHardwareShader() { sc.MustGetString(); if (sc.Compare("postprocess")) { sc.MustGetString(); PostProcessShader shaderdesc; shaderdesc.Target = sc.String; shaderdesc.Target.ToLower(); bool validTarget = false; if (sc.Compare("beforebloom")) validTarget = true; if (sc.Compare("scene")) validTarget = true; if (sc.Compare("screen")) validTarget = true; if (!validTarget) sc.ScriptError("Invalid target '%s' for postprocess shader",sc.String); sc.MustGetToken('{'); while (!sc.CheckToken('}')) { sc.MustGetString(); if (sc.Compare("shader")) { sc.MustGetString(); shaderdesc.ShaderLumpName = sc.String; sc.MustGetNumber(); shaderdesc.ShaderVersion = sc.Number; if (sc.Number > 450 || sc.Number < 330) sc.ScriptError("Shader version must be in range 330 to 450!"); } else if (sc.Compare("name")) { sc.MustGetString(); shaderdesc.Name = sc.String; } else if (sc.Compare("uniform") || sc.Compare("cvar_uniform")) { bool is_cvar = sc.Compare("cvar_uniform"); sc.MustGetString(); FString uniformType = sc.String; uniformType.ToLower(); sc.MustGetString(); FString uniformName = sc.String; PostProcessUniformType parsedType = PostProcessUniformType::Undefined; if (uniformType.Compare("int") == 0) parsedType = PostProcessUniformType::Int; else if (uniformType.Compare("float") == 0) parsedType = PostProcessUniformType::Float; else if (uniformType.Compare("vec2") == 0) parsedType = PostProcessUniformType::Vec2; else if (uniformType.Compare("vec3") == 0) parsedType = PostProcessUniformType::Vec3; else sc.ScriptError("Unrecognized uniform type '%s'", sc.String); auto strUniformType = sc.String; if (parsedType != PostProcessUniformType::Undefined) shaderdesc.Uniforms[uniformName].Type = parsedType; if (is_cvar) { addedcvars = true; if (!shaderdesc.Name.GetChars()) sc.ScriptError("Shader must have a name to use cvar uniforms"); ECVarType cvartype = CVAR_Dummy; int cvarflags = CVAR_MOD|CVAR_ARCHIVE|CVAR_VIRTUAL; FBaseCVar *cvar; void (*callback)(FBaseCVar&) = NULL; FString cvarname; switch (parsedType) { case PostProcessUniformType::Int: cvartype = CVAR_Int; callback = (void (*)(FBaseCVar&))uniform_callback_int; break; case PostProcessUniformType::Float: cvartype = CVAR_Float; callback = (void (*)(FBaseCVar&))uniform_callback_float; break; default: sc.ScriptError("'%s' not supported for CVAR uniforms!", strUniformType); break; } sc.MustGetString(); cvarname = sc.String; cvar = FindCVar(cvarname.GetChars(), NULL); UCVarValue oldval; UCVarValue val; ExtraUniformCVARData* oldextra = nullptr; sc.MustGetFloat(); val.Float = oldval.Float = (float)sc.Float; if (!Args->CheckParm ("-shaderuniformtest")) { // these aren't really release-ready, so lock them behind a command-line argument for now. sc.ScriptMessage("Warning - Use -shaderuniformtest to enable shader uniforms!"); } else { if (!cvar) { cvar = C_CreateCVar(cvarname.GetChars(), cvartype, cvarflags); } else if (cvar && (((cvar->GetFlags()) & CVAR_MOD) == CVAR_MOD)) { // this value may have been previously loaded oldval.Float = cvar->GetGenericRep(CVAR_Float).Float; oldextra = (ExtraUniformCVARData*)cvar->GetExtraDataPointer(); } if (!(cvar->GetFlags() & CVAR_MOD)) { if (!((cvar->GetFlags() & (CVAR_AUTO | CVAR_UNSETTABLE)) == (CVAR_AUTO | CVAR_UNSETTABLE))) sc.ScriptError("CVAR '%s' already in use!", cvarname.GetChars()); } // must've picked this up from an autoexec.cfg, handle accordingly if (cvar && ((cvar->GetFlags() & (CVAR_MOD|CVAR_AUTO|CVAR_UNSETTABLE)) == (CVAR_AUTO | CVAR_UNSETTABLE))) { oldval.Float = cvar->GetGenericRep(CVAR_Float).Float; oldextra = (ExtraUniformCVARData*)cvar->GetExtraDataPointer(); delete cvar; cvar = C_CreateCVar(cvarname.GetChars(), cvartype, cvarflags); } shaderdesc.Uniforms[uniformName].Values[0] = oldval.Float; cvar->SetGenericRepDefault(val, CVAR_Float); if (val.Float != oldval.Float) // it's not default anymore cvar->SetGenericRep(oldval.Float, CVAR_Float); if (callback) cvar->SetCallback(callback); ExtraUniformCVARData* extra = new ExtraUniformCVARData; extra->Shader = shaderdesc.Name.GetChars(); extra->Uniform = uniformName.GetChars(); extra->Next = oldextra; cvar->SetExtraDataPointer(extra); } } } else if (sc.Compare("texture")) { sc.MustGetString(); FString textureName = sc.String; sc.MustGetString(); FString textureSource = sc.String; shaderdesc.Textures[textureName] = textureSource; } else if (sc.Compare("enabled")) { shaderdesc.Enabled = true; } else { sc.ScriptError("Unknown keyword '%s'", sc.String); } } PostProcessShaders.Push(shaderdesc); } else { #if 0 // not ready for this yet ETextureType type = ETextureType::Any; if (sc.Compare("texture")) type = ETextureType::Wall; else if (sc.Compare("flat")) type = ETextureType::Flat; else if (sc.Compare("sprite")) type = ETextureType::Sprite; else sc.UnGet(); bool disable_fullbright = false; bool thiswad = false; bool iwad = false; int maplump = -1; UserShaderDesc desc; desc.shaderType = SHADER_Default; TArray texNameList; TArray texNameIndex; float speed = 1.f; sc.MustGetString(); FTextureID no = TexMan.CheckForTexture(sc.String, type); auto tex = TexMan.GetGameTexture(no); if (tex) tex->AddAutoMaterials(); MaterialLayers mlay = { -1000, -1000 }; sc.MustGetToken('{'); while (!sc.CheckToken('}')) { sc.MustGetString(); if (sc.Compare("shader")) { sc.MustGetString(); desc.shader = sc.String; } else if (sc.Compare("material")) { sc.MustGetString(); static MaterialShaderIndex typeIndex[6] = { SHADER_Default, SHADER_Default, SHADER_Specular, SHADER_Specular, SHADER_PBR, SHADER_PBR }; static bool usesBrightmap[6] = { false, true, false, true, false, true }; static const char *typeName[6] = { "normal", "brightmap", "specular", "specularbrightmap", "pbr", "pbrbrightmap" }; bool found = false; for (int i = 0; i < 6; i++) { if (sc.Compare(typeName[i])) { desc.shaderType = typeIndex[i]; if (usesBrightmap[i]) desc.shaderFlags |= SFlag_Brightmap; found = true; break; } } if (!found) sc.ScriptError("Unknown material type '%s' specified\n", sc.String); } else if (sc.Compare("speed")) { sc.MustGetFloat(); speed = float(sc.Float); } else if (sc.Compare("texture")) { sc.MustGetString(); FString textureName = sc.String; for(FString &texName : texNameList) { if(!texName.Compare(textureName)) { sc.ScriptError("Trying to redefine custom hardware shader texture '%s' in texture '%s'\n", textureName.GetChars(), tex? tex->GetName().GetChars() : "(null)"); } } sc.MustGetString(); bool okay = false; for (size_t i = 0; i < countof(mlay.CustomShaderTextures); i++) { if (!mlay.CustomShaderTextures[i]) { mlay.CustomShaderTextures[i] = TexMan.FindGameTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_TryAny); if (!mlay.CustomShaderTextures[i]) { sc.ScriptError("Custom hardware shader texture '%s' not found in texture '%s'\n", sc.String, tex? tex->GetName().GetChars() : "(null)"); } texNameList.Push(textureName); texNameIndex.Push((int)i); okay = true; break; } } if(!okay) { sc.ScriptError("Error: out of texture units in texture '%s'", tex? tex->GetName().GetChars() : "(null)"); } } else if(sc.Compare("define")) { sc.MustGetString(); FString defineName = sc.String; FString defineValue = ""; if(sc.CheckToken('=')) { sc.MustGetString(); defineValue = sc.String; } desc.defines.AppendFormat("#define %s %s\n", defineName.GetChars(), defineValue.GetChars()); } else if (sc.Compare("disablealphatest")) { desc.disablealphatest = true; } } if (!tex) { return; } int firstUserTexture; switch (desc.shaderType) { default: case SHADER_Default: firstUserTexture = 5; break; case SHADER_Specular: firstUserTexture = 7; break; case SHADER_PBR: firstUserTexture = 9; break; } for (unsigned int i = 0; i < texNameList.Size(); i++) { desc.defines.AppendFormat("#define %s texture%d\n", texNameList[i].GetChars(), texNameIndex[i] + firstUserTexture); } if (desc.shader.IsNotEmpty()) { if (tex->isWarped() != 0) { Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->GetName().GetChars()); return; } tex->SetShaderSpeed(speed); for (unsigned i = 0; i < usershaders.Size(); i++) { if (!usershaders[i].shader.CompareNoCase(desc.shader) && usershaders[i].shaderType == desc.shaderType && !usershaders[i].defines.Compare(desc.defines)) { SetShaderIndex(tex, i + FIRST_USER_SHADER); tex->SetShaderLayers(mlay); return; } } SetShaderIndex(tex, usershaders.Push(desc) + FIRST_USER_SHADER); } tex->SetShaderLayers(mlay); #endif } } #if 0 void ParseColorization(FScanner& sc) { TextureManipulation tm = {}; tm.ModulateColor = 0x01ffffff; sc.MustGetString(); FName cname = sc.String; sc.MustGetToken('{'); while (!sc.CheckToken('}')) { sc.MustGetString(); if (sc.Compare("DesaturationFactor")) { sc.MustGetFloat(); tm.DesaturationFactor = (float)sc.Float; } else if (sc.Compare("AddColor")) { sc.MustGetString(); tm.AddColor = (tm.AddColor & 0xff000000) | (V_GetColor(sc) & 0xffffff); } else if (sc.Compare("ModulateColor")) { sc.MustGetString(); tm.ModulateColor = V_GetColor(sc) & 0xffffff; if (sc.CheckToken(',')) { sc.MustGetNumber(); tm.ModulateColor.a = sc.Number; } else tm.ModulateColor.a = 1; } else if (sc.Compare("BlendColor")) { sc.MustGetString(); tm.BlendColor = V_GetColor(sc) & 0xffffff; sc.MustGetToken(','); sc.MustGetString(); static const char* opts[] = { "none", "alpha", "screen", "overlay", "hardlight", nullptr }; tm.AddColor.a = (tm.AddColor.a & ~TextureManipulation::BlendMask) | sc.MustMatchString(opts); if (sc.Compare("alpha")) { sc.MustGetToken(','); sc.MustGetFloat(); tm.BlendColor.a = (uint8_t)(clamp(sc.Float, 0., 1.) * 255); } } else if (sc.Compare("invert")) { tm.AddColor.a |= TextureManipulation::InvertBit; } else sc.ScriptError("Unknown token '%s'", sc.String); } if (tm.CheckIfEnabled()) { TexMan.InsertTextureManipulation(cname, tm); } else { TexMan.RemoveTextureManipulation(cname); } } #endif public: //========================================================================== // // // //========================================================================== void DoParseDefs() { int recursion=0; int lump, type; // Get actor class name. while (true) { sc.SavePos(); if (!sc.GetToken ()) { // *** fixme! need to load from config file //if (addedcvars) // GameConfig->DoModSetup (gameinfo.ConfigName); return; } type = sc.MatchString(CoreKeywords); switch (type) { case TAG_INCLUDE: { sc.MustGetString(); // This is not using sc.Open because it can print a more useful error message when done here lump = fileSystem.CheckNumForFullName(sc.String, true); if (lump==-1) sc.ScriptError("Lump '%s' not found", sc.String); GLDefsParser newscanner(lump, LightAssociations); newscanner.lightSizeFactor = lightSizeFactor; newscanner.DoParseDefs(); break; } #if 0 case LIGHT_POINT: ParsePointLight(); break; case LIGHT_PULSE: ParsePulseLight(); break; case LIGHT_FLICKER: ParseFlickerLight(); break; case LIGHT_FLICKER2: ParseFlickerLight2(); break; case LIGHT_SECTOR: ParseSectorLight(); break; case LIGHT_OBJECT: ParseObject(); break; case LIGHT_CLEAR: // This has been intentionally removed break; #endif case TAG_SHADER: ParseShader(); break; case TAG_CLEARSHADERS: break; #if 0 case TAG_SKYBOX: ParseGldefSkybox(); break; case TAG_GLOW: ParseGlow(); break; case TAG_BRIGHTMAP: ParseBrightmap(); break; case TAG_MATERIAL: ParseMaterial(); break; #endif case TAG_HARDWARESHADER: ParseHardwareShader(); break; #if 0 case TAG_DETAIL: ParseDetailTexture(); break; case TAG_LIGHTSIZEFACTOR: lightSizeFactor = ParseFloat(sc); break; case TAG_DISABLE_FB: { /* not implemented. sc.MustGetString(); const PClass *cls = PClass::FindClass(sc.String); if (cls) GetDefaultByType(cls)->renderflags |= RF_NEVERFULLBRIGHT; */ } break; case TAG_COLORIZATION: ParseColorization(sc); break; #endif default: sc.ScriptError("Error parsing defs. Unknown tag: %s.\n", sc.String); break; } } } GLDefsParser(int lumpnum, TArray &la) : sc(lumpnum), workingLump(lumpnum), LightAssociations(la) { } }; //========================================================================== // // // //========================================================================== void LoadGLDefs(const char *defsLump) { TArray LightAssociations; int workingLump, lastLump; static const char *gldefsnames[] = { "GLDEFS", defsLump, nullptr }; lastLump = 0; while ((workingLump = fileSystem.FindLumpMulti(gldefsnames, &lastLump)) != -1) { GLDefsParser sc(workingLump, LightAssociations); sc.DoParseDefs(); } #if 0 InitializeActorLights(LightAssociations); #endif } //========================================================================== // // // //========================================================================== void ParseGLDefs() { const char *defsLump = NULL; #if 0 LightDefaults.DeleteAndClear(); AttenuationIsSet = -1; #endif //gl_DestroyUserShaders(); function says 'todo' #if 0 // should we really use a system like this anymore with the advent of filter folders? switch (gameinfo.gametype) { case GAME_Heretic: defsLump = "HTICDEFS"; break; case GAME_Hexen: defsLump = "HEXNDEFS"; break; case GAME_Strife: defsLump = "STRFDEFS"; break; case GAME_Doom: defsLump = "DOOMDEFS"; break; case GAME_Chex: defsLump = "CHEXDEFS"; break; default: // silence GCC break; } #endif #if 0 ParseVavoomSkybox(); #endif LoadGLDefs(defsLump); }