From 6389b6b9148947e9b856238e785c496376f17249 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Nov 2017 23:04:15 +0100 Subject: [PATCH 1/7] - UMAPINFO parser, including some convenience additions to FScanner. Not tested yet! --- .gitignore | 2 + src/CMakeLists.txt | 1 + src/g_level.h | 10 +- src/g_mapinfo.cpp | 25 +- src/intermission/intermission_parse.cpp | 21 +- src/sc_man.cpp | 70 ++++ src/sc_man.h | 9 + src/umapinfo.cpp | 431 ++++++++++++++++++++++++ 8 files changed, 556 insertions(+), 13 deletions(-) create mode 100644 src/umapinfo.cpp diff --git a/.gitignore b/.gitignore index e071ea2e8..80c2238ae 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,5 @@ /src/r_drawersasm.obj /src/r_drawersasm.o .vs +/src/gl/unused +/mapfiles_release/*.map diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7ede5128b..96910731c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -958,6 +958,7 @@ set (PCH_SOURCES stats.cpp stringtable.cpp teaminfo.cpp + umapinfo.cpp v_blend.cpp v_collection.cpp v_draw.cpp diff --git a/src/g_level.h b/src/g_level.h index 2df5af946..8b27dc68d 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -253,7 +253,7 @@ struct FSpecialAction { FName Type; // this is initialized before the actors... uint8_t Action; - int Args[5]; // must allow 16 bit tags for 666 & 667! + int Args[5]; }; class DScroller; @@ -307,6 +307,11 @@ struct FExitText FString mText; FString mMusic; FString mBackdrop; + + FExitText(int def = 0, int order = -1, const FString &text = "", const FString &backdrop = "", const FString &music = "") + : mDefined(int16_t(def)), mOrder(int16_t(order)), mText(text), mMusic(music), mBackdrop(backdrop) + { + } }; struct level_info_t @@ -619,5 +624,8 @@ struct FEpisode extern TArray AllEpisodes; +int ParseUMapInfo(int lumpnum); +void CommitUMapinfo(level_info_t *defaultinfo); + #endif //__G_LEVEL_H__ diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 5f22b25cf..cb750f4a1 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -2206,7 +2206,7 @@ void G_ParseMapInfo (FString basemapinfo) parse.ParseMapInfo(baselump, gamedefaults, defaultinfo); } - static const char *mapinfonames[] = { "MAPINFO", "ZMAPINFO", NULL }; + static const char *mapinfonames[] = { "MAPINFO", "ZMAPINFO", "UMAPINFO", NULL }; int nindex; // Parse any extra MAPINFOs. @@ -2222,9 +2222,26 @@ void G_ParseMapInfo (FString basemapinfo) if (altlump >= 0) continue; } - FMapInfoParser parse(nindex == 1? FMapInfoParser::FMT_New : FMapInfoParser::FMT_Unknown); - level_info_t defaultinfo; - parse.ParseMapInfo(lump, gamedefaults, defaultinfo); + else if (nindex == 2) + { + // MAPINFO and ZMAPINFO will override UMAPINFO if in the same WAD. + int wad = Wads.GetLumpFile(lump); + int altlump = Wads.CheckNumForName("ZMAPINFO", ns_global, wad, true); + if (altlump >= 0) continue; + altlump = Wads.CheckNumForName("MAPINFO", ns_global, wad, true); + if (altlump >= 0) continue; + } + if (nindex != 2) + { + CommitUMapinfo(&gamedefaults); // UMPAINFOs are collected until a regular MAPINFO is found so that they properly use the base settings. + FMapInfoParser parse(nindex == 1 ? FMapInfoParser::FMT_New : FMapInfoParser::FMT_Unknown); + level_info_t defaultinfo; + parse.ParseMapInfo(lump, gamedefaults, defaultinfo); + } + else + { + ParseUMapInfo(lump); + } } if (AllEpisodes.Size() == 0) diff --git a/src/intermission/intermission_parse.cpp b/src/intermission/intermission_parse.cpp index 2c3114afe..2841b70f7 100644 --- a/src/intermission/intermission_parse.cpp +++ b/src/intermission/intermission_parse.cpp @@ -724,6 +724,18 @@ FName FMapInfoParser::ParseEndGame() // //========================================================================== +FName MakeEndPic(const char *string) +{ + FString seqname; + seqname << "@EndPic_" << string; + FIntermissionDescriptor *desc = new FIntermissionDescriptor; + FIntermissionAction *action = new FIntermissionAction; + action->mBackground = string; + desc->mActions.Push(action); + ReplaceIntermission(seqname, desc); + return FName(seqname); +} + FName FMapInfoParser::CheckEndSequence() { const char *seqname = NULL; @@ -756,14 +768,7 @@ FName FMapInfoParser::CheckEndSequence() { ParseComma(); sc.MustGetString (); - FString seqname; - seqname << "@EndPic_" << sc.String; - FIntermissionDescriptor *desc = new FIntermissionDescriptor; - FIntermissionAction *action = new FIntermissionAction; - action->mBackground = sc.String; - desc->mActions.Push(action); - ReplaceIntermission(seqname, desc); - return FName(seqname); + return MakeEndPic(sc.String); } else if (sc.Compare("endbunny")) { diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 6482fbc10..2a515d91b 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -949,6 +949,76 @@ bool FScanner::Compare (const char *text) return (stricmp (text, String) == 0); } + +//========================================================================== +// +// Convenience helpers that parse an entire number including a leading minus or plus sign +// +//========================================================================== + +bool FScanner::ScanValue(bool allowfloat) +{ + bool neg = false; + if (!GetToken()) + { + return false; + } + if (TokenType == '-' || TokenType == '+') + { + neg = TokenType == '-'; + if (!GetToken()) + { + return false; + } + } + if (TokenType != TK_IntConst && (TokenType != TK_FloatConst || !allowfloat)) + { + return false; + } + if (neg) + { + Number = -Number; + Float = -Float; + } + return true; +} + +bool FScanner::CheckValue(bool allowfloat) +{ + auto savedstate = SavePos(); + bool res = ScanValue(allowfloat); + if (!res) RestorePos(savedstate); + return res; +} + +void FScanner::MustGetValue(bool allowfloat) +{ + if (!ScanValue(allowfloat)) ScriptError(allowfloat ? "Numeric constant expected" : "Integer constant expected"); +} + +bool FScanner::CheckBoolToken() +{ + if (CheckToken(TK_True)) + { + Number = 1; + Float = 1; + return true; + } + if (CheckToken(TK_False)) + { + Number = 0; + Float = 0; + return true; + } + return false; +} + +void FScanner::MustGetBoolToken() +{ + if (!CheckBoolToken()) + ScriptError("Expected true or false"); +} + //========================================================================== // // FScanner :: TokenName diff --git a/src/sc_man.h b/src/sc_man.h index 860935b8d..44dd9370a 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -57,6 +57,12 @@ public: bool GetFloat(); void MustGetFloat(); bool CheckFloat(); + + // Token based variant + bool CheckValue(bool allowfloat); + void MustGetValue(bool allowfloat); + bool CheckBoolToken(); + void MustGetBoolToken(); void UnGet(); @@ -107,6 +113,9 @@ protected: bool StateOptions; bool Escape; VersionInfo ParseVersion = { 0, 0, 0 }; // no ZScript extensions by default + + + bool ScanValue(bool allowfloat); }; enum diff --git a/src/umapinfo.cpp b/src/umapinfo.cpp new file mode 100644 index 000000000..c8d416740 --- /dev/null +++ b/src/umapinfo.cpp @@ -0,0 +1,431 @@ +//----------------------------------------------------------------------------- +// +// Copyright 2017 Christoph Oelckers +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//----------------------------------------------------------------------------- + +#include +#include +#include +#include +#include "w_wad.h" +#include "g_level.h" +#include "sc_man.h" +#include "r_defs.h" +#include "p_setup.h" +#include "gi.h" + +FName MakeEndPic(const char *string); + +struct BossAction +{ + int type; + int special; + int tag; +}; + +struct UMapEntry +{ + FString MapName; + FString LevelName; + FString InterText; + FString InterTextSecret; + TArray BossActions; + + char levelpic[9]; + char nextmap[9]; + char nextsecret[9]; + char music[9]; + char skytexture[9]; + char endpic[9]; + char exitpic[9]; + char enterpic[9]; + char interbackdrop[9] = "FLOOR4_8"; + char intermusic[9]; + int partime; + int nointermission; +}; + +static TArray Maps; + + +// ----------------------------------------------- +// +// Parses a set of string and concatenates them +// +// ----------------------------------------------- + +static FString ParseMultiString(FScanner &scanner, int error) +{ + FString build; + + if (scanner.CheckToken(TK_Identifier)) + { + if (!stricmp(scanner.String, "clear")) + { + return "-"; + } + else + { + scanner.ScriptError("Either 'clear' or string constant expected"); + } + } + + do + { + scanner.MustGetToken(TK_StringConst); + if (build.Len() > 0) build += "\n"; + build += scanner.String; + } + while (scanner.CheckToken(',')); + return build; +} + +// ----------------------------------------------- +// +// Parses a lump name. The buffer must be at least 9 characters. +// +// ----------------------------------------------- + +static int ParseLumpName(FScanner &scanner, char *buffer) +{ + scanner.MustGetToken(TK_StringConst); + if (strlen(scanner.String) > 8) + { + scanner.ScriptError("String too long. Maximum size is 8 characters."); + return 0; + } + uppercopy(buffer, scanner.String); + return 1; +} + +// ----------------------------------------------- +// +// Parses a standard property that is already known +// These do not get stored in the property list +// but in dedicated struct member variables. +// +// ----------------------------------------------- + +static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape) +{ + // find the next line with content. + // this line is no property. + + scanner.MustGetToken(TK_Identifier); + FString pname = scanner.String; + scanner.MustGetToken('='); + + if (!pname.CompareNoCase("levelname")) + { + scanner.MustGetToken(TK_StringConst); + mape->LevelName, scanner.String; + } + else if (!pname.CompareNoCase("next")) + { + ParseLumpName(scanner, mape->nextmap); + } + else if (!pname.CompareNoCase("nextsecret")) + { + ParseLumpName(scanner, mape->nextsecret); + } + else if (!pname.CompareNoCase("levelpic")) + { + ParseLumpName(scanner, mape->levelpic); + } + else if (!pname.CompareNoCase("skytexture")) + { + ParseLumpName(scanner, mape->skytexture); + } + else if (!pname.CompareNoCase("music")) + { + ParseLumpName(scanner, mape->music); + } + else if (!pname.CompareNoCase("endpic")) + { + ParseLumpName(scanner, mape->endpic); + } + else if (!pname.CompareNoCase("endcast")) + { + scanner.MustGetBoolToken(); + if (scanner.Number) strcpy(mape->endpic, "$CAST"); + else strcpy(mape->endpic, "-"); + } + else if (!pname.CompareNoCase("endbunny")) + { + scanner.MustGetBoolToken(); + if (scanner.Number) strcpy(mape->endpic, "$BUNNY"); + else strcpy(mape->endpic, "-"); + } + else if (!pname.CompareNoCase("endgame")) + { + scanner.MustGetBoolToken(); + if (scanner.Number) strcpy(mape->endpic, "!"); + else strcpy(mape->endpic, "-"); + } + else if (!pname.CompareNoCase("exitpic")) + { + ParseLumpName(scanner, mape->exitpic); + } + else if (!pname.CompareNoCase("enterpic")) + { + ParseLumpName(scanner, mape->enterpic); + } + else if (!pname.CompareNoCase("nointermission")) + { + scanner.MustGetBoolToken(); + mape->nointermission = scanner.Number; + } + else if (!pname.CompareNoCase("partime")) + { + scanner.MustGetValue(false); + mape->partime = TICRATE * scanner.Number; + } + else if (!pname.CompareNoCase("intertext")) + { + mape->InterText = ParseMultiString(scanner, 1); + if (mape->InterText.IsEmpty()) return 0; + } + else if (!pname.CompareNoCase("intertextsecret")) + { + mape->InterTextSecret = ParseMultiString(scanner, 1); + if (mape->InterTextSecret.IsEmpty()) return 0; + } + else if (!pname.CompareNoCase("interbackdrop")) + { + ParseLumpName(scanner, mape->interbackdrop); + } + else if (!pname.CompareNoCase("intermusic")) + { + ParseLumpName(scanner, mape->intermusic); + } + else if (!pname.CompareNoCase("episode")) + { + FString Episode = ParseMultiString(scanner, 1); + if (Episode.IsEmpty()) return 0; + //M_AddEpisode(mape->mapname, lname); + } + else if (!pname.CompareNoCase("bossaction")) + { + scanner.MustGetToken(TK_Identifier); + int classnum, special, tag; + if (!stricmp(scanner.String, "clear")) + { + // mark level free of boss actions + classnum = special = tag = -1; + mape->BossActions.Clear(); + } + else + { + FName type = scanner.String; + scanner.MustGetToken(','); + scanner.MustGetValue(false); + int special = scanner.Number; + scanner.MustGetToken(','); + scanner.MustGetValue(false); + int tag = scanner.Number; + // allow no 0-tag specials here, unless a level exit. + if (tag != 0 || special == 11 || special == 51 || special == 52 || special == 124) + { + FSpecialAction & bossact = mape->BossActions[mape->BossActions.Reserve(1)]; + line_t line; + maplinedef_t mld; + mld.special = special; + mld.tag = tag; + P_TranslateLineDef(&line, &mld); + bossact = { type, (uint8_t)line.special, {line.args[0], line.args[1],line.args[2],line.args[3],line.args[4]} }; + } + } + } + else + { + // Skip over all unknown properties. + do + { + if (!scanner.CheckFloat()) + { + scanner.MustGetAnyToken(); + if (scanner.TokenType != TK_Identifier && scanner.TokenType != TK_StringConst && scanner.TokenType != TK_True && scanner.TokenType != TK_False) + { + scanner.ScriptError("Identifier or value expecte3d"); + } + } + + } while (scanner.CheckToken(',')); + } + return 1; +} + +// ----------------------------------------------- +// +// Parses a complete map entry +// +// ----------------------------------------------- + +static int ParseMapEntry(FScanner &scanner, UMapEntry *val) +{ + scanner.MustGetToken(TK_Identifier); + + val->MapName, scanner.String; + scanner.MustGetToken('{'); + while(!scanner.CheckToken('}')) + { + ParseStandardProperty(scanner, val); + } + return 1; +} + +// ----------------------------------------------- +// +// Parses a complete UMAPINFO lump +// +// ----------------------------------------------- + +int ParseUMapInfo(int lumpnum) +{ + FScanner scanner(lumpnum); + unsigned int i; + + while (scanner.CheckToken(TK_Identifier)) + { + if (!scanner.Compare("map")) + { + scanner.ScriptError("'MAP' expected"); + } + UMapEntry parsed; + ParseMapEntry(scanner, &parsed); + + // Endpic overrides level exits. + if (parsed.endpic[0]) + { + parsed.nextmap[0] = parsed.nextsecret[0] = 0; + if (parsed.endpic[0] == '!') parsed.endpic[0] = 0; + } + /* + else if (!parsed.nextmap[0] && !parsed.endpic[0]) + { + if (!parsed.MapName.CompareNoCase("MAP30")) uppercopy(parsed.endpic, "$CAST"); + else if (!parsed.MapName.CompareNoCase("E1M8")) uppercopy(parsed.endpic, gameinfo.creditPages.Last()); + else if (!parsed.MapName.CompareNoCase("E2M8")) uppercopy(parsed.endpic, "VICTORY"); + else if (!parsed.MapName.CompareNoCase("E3M8")) uppercopy(parsed.endpic, "$BUNNY"); + else if (!parsed.MapName.CompareNoCase("E4M8")) uppercopy(parsed.endpic, "ENDPIC"); + else if (gameinfo.gametype == GAME_Chex && !parsed.MapName.CompareNoCase("E1M5")) uppercopy(parsed.endpic, "CREDIT"); + else + { + parsed.nextmap[0] = 0; // keep previous setting + } + } + */ + + // Does this property already exist? If yes, replace it. + for(i = 0; i < Maps.Size(); i++) + { + if (!parsed.MapName.Compare(Maps[i].MapName)) + { + Maps[i] = parsed; + return 1; + } + } + // Not found so create a new one. + Maps.Push(parsed); + + } + return 1; +} + + +// This will get called if after an UMAPINFO lump a regular (Z)MAPINFO is found or when MAPINFO parsing is complete. +void CommitUMapinfo(level_info_t *defaultinfo) +{ + for (auto &map : Maps) + { + auto levelinfo = FindLevelInfo(map.MapName); + if (levelinfo == nullptr) + { + *levelinfo = *defaultinfo; + if (map.MapName.IsNotEmpty()) levelinfo->MapName = map.MapName; + if (map.MapName.IsNotEmpty()) levelinfo->LevelName = map.LevelName; + if (map.levelpic[0]) levelinfo->PName = map.levelpic; + if (map.nextmap[0]) levelinfo->NextMap = map.nextmap; + else if (map.endpic[0]) + { + FName name; + + if (!stricmp(map.endpic, "$CAST")) + { + name = "INTER_CAST"; + } + else if (!stricmp(map.endpic, "$BUNNY")) + { + name = "INTER_BUNNY"; + } + else + { + name = MakeEndPic(map.endpic); + } + if (name != NAME_None) + { + levelinfo->NextMap.Format("enDSeQ%04x", int(name)); + } + } + + if (map.nextsecret[0]) levelinfo->NextSecretMap = map.nextsecret; + if (map.music[0]) + { + levelinfo->Music = map.music; + levelinfo->musicorder = 0; + } + if (map.skytexture[0]) + { + levelinfo->SkyPic1 = map.skytexture; + levelinfo->skyspeed1 = 0; + levelinfo->SkyPic2 = ""; + levelinfo->skyspeed2 = 0; + } + if (map.partime > 0) levelinfo->partime = map.partime; + if (map.enterpic[0]) levelinfo->EnterPic = map.enterpic; + if (map.exitpic[0]) levelinfo->ExitPic = map.exitpic; + if (map.intermusic[0]) + { + levelinfo->InterMusic = map.intermusic; + levelinfo->intermusicorder = 0; + } + if (map.BossActions.Size() > 0) levelinfo->specialactions = std::move(map.BossActions); + + const int exflags = FExitText::DEF_TEXT | FExitText::DEF_BACKDROP | FExitText::DEF_MUSIC; + if (map.InterText.IsNotEmpty()) + { + if (map.InterText.Compare("-") != 0) + levelinfo->ExitMapTexts[NAME_Normal] = { exflags, 0, map.InterText, map.interbackdrop, map.intermusic[0]? map.intermusic : gameinfo.intermissionMusic }; + else + levelinfo->ExitMapTexts[NAME_Normal] = { 0, 0 }; + } + if (map.InterTextSecret.IsNotEmpty()) + { + if (map.InterTextSecret.Compare("-") != 0) + levelinfo->ExitMapTexts[NAME_Secret] = { exflags, 0, map.InterTextSecret, map.interbackdrop, map.intermusic[0] ? map.intermusic : gameinfo.intermissionMusic }; + else + levelinfo->ExitMapTexts[NAME_Secret] = { 0, 0 }; + } + if (map.nointermission) levelinfo->flags |= LEVEL_NOINTERMISSION; + } + } + + + // All done. If we get here again, start fresh. + Maps.Clear(); + Maps.ShrinkToFit(); +} \ No newline at end of file From 0ef8105e6b6adbf7649fa599ab00d861f017e6fb Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 21 Nov 2017 18:57:44 +0100 Subject: [PATCH 2/7] - Add missing r_draw.cpp in CMakeLists.txt --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7ede5128b..f623de5a4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -702,6 +702,7 @@ set ( SWRENDER_SOURCES swrenderer/r_swrenderer.cpp swrenderer/r_memory.cpp swrenderer/r_renderthread.cpp + swrenderer/drawers/r_draw.cpp swrenderer/drawers/r_draw_pal.cpp swrenderer/drawers/r_draw_rgba.cpp swrenderer/drawers/r_thread.cpp From 4e4f94db2f431e1d384b19cdadbc143dc744b83e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 22 Nov 2017 06:32:55 +0100 Subject: [PATCH 3/7] - Implement newer scaled fuzz in softpoly's truecolor non-sse drawer --- src/polyrenderer/drawers/poly_drawer32.h | 42 +++++++++++++----------- src/polyrenderer/poly_renderer.cpp | 2 ++ src/swrenderer/drawers/r_draw.cpp | 4 +-- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/polyrenderer/drawers/poly_drawer32.h b/src/polyrenderer/drawers/poly_drawer32.h index 579488ea3..f3d05ae74 100644 --- a/src/polyrenderer/drawers/poly_drawer32.h +++ b/src/polyrenderer/drawers/poly_drawer32.h @@ -119,7 +119,7 @@ namespace TriScreenDrawerModes } template - FORCEINLINE unsigned int SampleShade32(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight, int &fuzzpos) + FORCEINLINE unsigned int SampleShade32(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight, int x, int y) { if (SamplerT::Mode == (int)Samplers::Shaded) { @@ -140,12 +140,23 @@ namespace TriScreenDrawerModes } else if (SamplerT::Mode == (int)Samplers::Fuzz) { + using namespace swrenderer; + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; unsigned int sampleshadeout = APART(texPixels[texelX * texHeight + texelY]); sampleshadeout += sampleshadeout >> 7; // 255 -> 256 - sampleshadeout = (sampleshadeout * fuzzcolormap[fuzzpos++]) >> 5; - if (fuzzpos >= FUZZTABLE) fuzzpos = 0; + + fixed_t fuzzscale = (200 << FRACBITS) / viewheight; + + int scaled_x = (x * fuzzscale) >> FRACBITS; + int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + fuzzpos; + + fixed_t fuzzcount = FUZZTABLE << FRACBITS; + fixed_t fuzz = ((fuzz_x << FRACBITS) + y * fuzzscale) % fuzzcount; + unsigned int alpha = fuzzoffset[fuzz >> FRACBITS]; + + sampleshadeout = (sampleshadeout * alpha) >> 5; return sampleshadeout; } else @@ -373,8 +384,6 @@ private: uint32_t srcalpha = args->uniforms->SrcAlpha(); uint32_t destalpha = args->uniforms->DestAlpha(); - int fuzzpos = (ScreenTriangle::FuzzStart + destX * 123 + destY) % FUZZTABLE; - auto lights = args->uniforms->Lights(); auto num_lights = args->uniforms->NumLights(); FVector3 worldnormal = args->uniforms->Normal(); @@ -505,7 +514,7 @@ private: // Sample fgcolor if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[ix]; unsigned int ifgcolor = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - unsigned int ifgshade = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + unsigned int ifgshade = SampleShade32(posU, posV, texPixels, texWidth, texHeight, destX + ix, destY + y); posU += stepU; posV += stepV; @@ -608,7 +617,7 @@ private: // Sample fgcolor if (SamplerT::Mode == (int)Samplers::FogBoundary && (mask0 & (1 << 31))) color = dest[x]; unsigned int ifgcolor = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - unsigned int ifgshade = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + unsigned int ifgshade = SampleShade32(posU, posV, texPixels, texWidth, texHeight, destX + x, destY + y); posU += stepU; posV += stepV; @@ -711,7 +720,7 @@ private: // Sample fgcolor if (SamplerT::Mode == (int)Samplers::FogBoundary && (mask1 & (1 << 31))) color = dest[x]; unsigned int ifgcolor = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - unsigned int ifgshade = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + unsigned int ifgshade = SampleShade32(posU, posV, texPixels, texWidth, texHeight, destX + x, destY + 4 + y); posU += stepU; posV += stepV; @@ -773,7 +782,11 @@ public: { using namespace TriScreenDrawerModes; - if (args->SimpleShade()) + if (SamplerT::Mode == (int)Samplers::Fuzz) + { + Loop(destOrg, destWidth, destHeight, destPitch, args, thread); + } + else if (args->SimpleShade()) { Loop(destOrg, destWidth, destHeight, destPitch, args, thread); } @@ -869,18 +882,9 @@ private: int count = x1 - x0; - int fuzzpos = (ScreenTriangle::FuzzStart + x0 * 123 + y0) % FUZZTABLE; - uint32_t posV = startV; for (int y = y0; y < y1; y++, posV += stepV) { - int coreBlock = y / 8; - if (coreBlock % thread->num_cores != thread->core) - { - fuzzpos = (fuzzpos + count) % FUZZTABLE; - continue; - } - uint32_t *dest = ((uint32_t*)destOrg) + y * destPitch + x0; uint32_t posU = startU; @@ -896,7 +900,7 @@ private: // Sample fgcolor if (SamplerT::Mode == (int)Samplers::FogBoundary) color = *dest; unsigned int ifgcolor = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - unsigned int ifgshade = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + unsigned int ifgshade = SampleShade32(posU, posV, texPixels, texWidth, texHeight, x0 + i, y); posU += stepU; // Shade and blend diff --git a/src/polyrenderer/poly_renderer.cpp b/src/polyrenderer/poly_renderer.cpp index c3389bba5..a0aa12c32 100644 --- a/src/polyrenderer/poly_renderer.cpp +++ b/src/polyrenderer/poly_renderer.cpp @@ -119,6 +119,8 @@ void PolyRenderer::RenderActorView(AActor *actor, bool dontmaplines) P_FindParticleSubsectors(); PO_LinkToSubsectors(); + swrenderer::R_UpdateFuzzPosFrameStart(); + if (APART(R_OldBlend)) NormalLight.Maps = realcolormaps.Maps; else NormalLight.Maps = realcolormaps.Maps + NUMCOLORMAPS * 256 * R_OldBlend; diff --git a/src/swrenderer/drawers/r_draw.cpp b/src/swrenderer/drawers/r_draw.cpp index 793cf2ae4..bc7eb731d 100644 --- a/src/swrenderer/drawers/r_draw.cpp +++ b/src/swrenderer/drawers/r_draw.cpp @@ -193,7 +193,7 @@ namespace swrenderer void R_UpdateFuzzPosFrameStart() { - if (r_fuzzscale) + if (r_fuzzscale || r_polyrenderer) { static int next_random = 0; @@ -207,7 +207,7 @@ namespace swrenderer void R_UpdateFuzzPos(const SpriteDrawerArgs &args) { - if (!r_fuzzscale) + if (!r_fuzzscale && !r_polyrenderer) { int yl = MAX(args.FuzzY1(), 1); int yh = MIN(args.FuzzY2(), fuzzviewheight); From f04fca75f710a2e82027911f17f6df22a424d9d8 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 22 Nov 2017 18:46:45 +0100 Subject: [PATCH 4/7] - Add scaled fuzz to softpoly sse2 drawer --- src/polyrenderer/drawers/poly_drawer32_sse2.h | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/polyrenderer/drawers/poly_drawer32_sse2.h b/src/polyrenderer/drawers/poly_drawer32_sse2.h index 8c245eec9..01c614434 100644 --- a/src/polyrenderer/drawers/poly_drawer32_sse2.h +++ b/src/polyrenderer/drawers/poly_drawer32_sse2.h @@ -107,7 +107,7 @@ namespace TriScreenDrawerModes } template - FORCEINLINE unsigned int VECTORCALL SampleShade32(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight, int &fuzzpos) + FORCEINLINE unsigned int VECTORCALL SampleShade32(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight, int x, int y) { if (SamplerT::Mode == (int)Samplers::Shaded) { @@ -128,12 +128,23 @@ namespace TriScreenDrawerModes } else if (SamplerT::Mode == (int)Samplers::Fuzz) { + using namespace swrenderer; + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; unsigned int sampleshadeout = APART(texPixels[texelX * texHeight + texelY]); sampleshadeout += sampleshadeout >> 7; // 255 -> 256 - sampleshadeout = (sampleshadeout * fuzzcolormap[fuzzpos++]) >> 5; - if (fuzzpos >= FUZZTABLE) fuzzpos = 0; + + fixed_t fuzzscale = (200 << FRACBITS) / viewheight; + + int scaled_x = (x * fuzzscale) >> FRACBITS; + int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + fuzzpos; + + fixed_t fuzzcount = FUZZTABLE << FRACBITS; + fixed_t fuzz = ((fuzz_x << FRACBITS) + y * fuzzscale) % fuzzcount; + unsigned int alpha = fuzzoffset[fuzz >> FRACBITS]; + + sampleshadeout = (sampleshadeout * alpha) >> 5; return sampleshadeout; } else @@ -392,8 +403,6 @@ private: uint32_t srcalpha = args->uniforms->SrcAlpha(); uint32_t destalpha = args->uniforms->DestAlpha(); - int fuzzpos = (ScreenTriangle::FuzzStart + destX * 123 + destY) % FUZZTABLE; - auto lights = args->uniforms->Lights(); auto num_lights = args->uniforms->NumLights(); __m128 worldnormal = _mm_setr_ps(args->uniforms->Normal().X, args->uniforms->Normal().Y, args->uniforms->Normal().Z, 0.0f); @@ -518,13 +527,13 @@ private: unsigned int ifgcolor[2], ifgshade[2]; if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[ix * 2]; ifgcolor[0] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, destX + ix * 2, destY + y); posU += stepU; posV += stepV; if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[ix * 2 + 1]; ifgcolor[1] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[1] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + ifgshade[1] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, destX + ix * 2 + 1, destY + y); posU += stepU; posV += stepV; @@ -626,13 +635,13 @@ private: unsigned int ifgcolor[2], ifgshade[2]; if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[x * 2]; ifgcolor[0] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, destX + x * 2, destY + y); posU += stepU; posV += stepV; if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[x * 2 + 1]; ifgcolor[1] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[1] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + ifgshade[1] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, destX + x * 2 + 1, destY + y); posU += stepU; posV += stepV; @@ -736,13 +745,13 @@ private: unsigned int ifgcolor[2], ifgshade[2]; if (SamplerT::Mode == (int)Samplers::FogBoundary && (mask1 & (1 << 31))) color = dest[x * 2]; ifgcolor[0] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, destX + x * 2, destY + 4 + y); posU += stepU; posV += stepV; if (SamplerT::Mode == (int)Samplers::FogBoundary && (mask1 & (1 << 30))) color = dest[x * 2 + 1]; ifgcolor[1] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[1] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + ifgshade[1] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, destX + x * 2 + 1, destY + 4 + y); posU += stepU; posV += stepV; @@ -889,18 +898,9 @@ private: int count = x1 - x0; int sseCount = count / 2; - int fuzzpos = (ScreenTriangle::FuzzStart + x0 * 123 + y0) % FUZZTABLE; - uint32_t posV = startV; for (int y = y0; y < y1; y++, posV += stepV) { - int coreBlock = y / 8; - if (coreBlock % thread->num_cores != thread->core) - { - fuzzpos = (fuzzpos + count) % FUZZTABLE; - continue; - } - uint32_t *dest = ((uint32_t*)destOrg) + y * destPitch + x0; uint32_t posU = startU; @@ -917,12 +917,12 @@ private: unsigned int ifgcolor[2], ifgshade[2]; if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[0]; ifgcolor[0] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, x0 + i * 2, y); posU += stepU; if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[1]; ifgcolor[1] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[1] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + ifgshade[1] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, x0 + i * 2 + 1, y); posU += stepU; // Shade and blend @@ -948,7 +948,7 @@ private: unsigned int ifgcolor[2], ifgshade[2]; if (SamplerT::Mode == (int)Samplers::FogBoundary) color = *dest; ifgcolor[0] = Sample32(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation); - ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + ifgshade[0] = SampleShade32(posU, posV, texPixels, texWidth, texHeight, x0 + sseCount * 2, y); ifgcolor[1] = 0; ifgshade[1] = 0; posU += stepU; From 9052ee6bc80c4ab647d5ac8c1e1f2886872f848f Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 22 Nov 2017 18:54:49 +0100 Subject: [PATCH 5/7] - Added scaled fuzz to softpoly pal drawer --- src/polyrenderer/drawers/poly_drawer8.h | 36 ++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/polyrenderer/drawers/poly_drawer8.h b/src/polyrenderer/drawers/poly_drawer8.h index f78d2a31c..d5ec5bade 100644 --- a/src/polyrenderer/drawers/poly_drawer8.h +++ b/src/polyrenderer/drawers/poly_drawer8.h @@ -79,7 +79,7 @@ namespace TriScreenDrawerModes } template - FORCEINLINE unsigned int SampleShade8(int32_t u, int32_t v, const uint8_t *texPixels, int texWidth, int texHeight, int &fuzzpos) + FORCEINLINE unsigned int SampleShade8(int32_t u, int32_t v, const uint8_t *texPixels, int texWidth, int texHeight, int x, int y) { if (SamplerT::Mode == (int)Samplers::Shaded) { @@ -97,11 +97,22 @@ namespace TriScreenDrawerModes } else if (SamplerT::Mode == (int)Samplers::Fuzz) { + using namespace swrenderer; + uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16; uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16; unsigned int sampleshadeout = (texPixels[texelX * texHeight + texelY] != 0) ? 256 : 0; - sampleshadeout = (sampleshadeout * fuzzcolormap[fuzzpos++]) >> 5; - if (fuzzpos >= FUZZTABLE) fuzzpos = 0; + + fixed_t fuzzscale = (200 << FRACBITS) / viewheight; + + int scaled_x = (x * fuzzscale) >> FRACBITS; + int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + fuzzpos; + + fixed_t fuzzcount = FUZZTABLE << FRACBITS; + fixed_t fuzz = ((fuzz_x << FRACBITS) + y * fuzzscale) % fuzzcount; + unsigned int alpha = fuzzoffset[fuzz >> FRACBITS]; + + sampleshadeout = (sampleshadeout * alpha) >> 5; return sampleshadeout; } else @@ -228,8 +239,6 @@ public: uint32_t srcalpha = args->uniforms->SrcAlpha(); uint32_t destalpha = args->uniforms->DestAlpha(); - int fuzzpos = (ScreenTriangle::FuzzStart + destX * 123 + destY) % FUZZTABLE; - // Calculate gradients const ShadedTriVertex &v1 = *args->v1; ScreenTriangleStepVariables gradientX = args->gradientX; @@ -292,7 +301,7 @@ public: uint8_t bgcolor = dest[ix]; if (SamplerT::Mode == (int)Samplers::FogBoundary) color = bgcolor; uint8_t fgcolor = Sample8(posU, posV, texPixels, texWidth, texHeight, color, translation); - uint32_t fgshade = SampleShade8(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + uint32_t fgshade = SampleShade8(posU, posV, texPixels, texWidth, texHeight, destX + ix, destY + y); if (SamplerT::Mode == (int)Samplers::Fuzz) lightshade = 256; dest[ix] = ShadeAndBlend8(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha); posU += stepU; @@ -342,7 +351,7 @@ public: uint8_t bgcolor = dest[x]; if (SamplerT::Mode == (int)Samplers::FogBoundary) color = bgcolor; uint8_t fgcolor = Sample8(posU, posV, texPixels, texWidth, texHeight, color, translation); - uint32_t fgshade = SampleShade8(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + uint32_t fgshade = SampleShade8(posU, posV, texPixels, texWidth, texHeight, destX + x, destY + y); if (SamplerT::Mode == (int)Samplers::Fuzz) lightshade = 256; dest[x] = ShadeAndBlend8(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha); } @@ -394,7 +403,7 @@ public: uint8_t bgcolor = dest[x]; if (SamplerT::Mode == (int)Samplers::FogBoundary) color = bgcolor; uint8_t fgcolor = Sample8(posU, posV, texPixels, texWidth, texHeight, color, translation); - uint32_t fgshade = SampleShade8(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + uint32_t fgshade = SampleShade8(posU, posV, texPixels, texWidth, texHeight, destX + x, destY + 4 + y); if (SamplerT::Mode == (int)Samplers::Fuzz) lightshade = 256; dest[x] = ShadeAndBlend8(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha); } @@ -458,18 +467,9 @@ public: int count = x1 - x0; - int fuzzpos = (ScreenTriangle::FuzzStart + x0 * 123 + y0) % FUZZTABLE; - uint32_t posV = startV; for (int y = y0; y < y1; y++, posV += stepV) { - int coreBlock = y / 8; - if (coreBlock % thread->num_cores != thread->core) - { - fuzzpos = (fuzzpos + count) % FUZZTABLE; - continue; - } - uint8_t *dest = ((uint8_t*)destOrg) + y * destPitch + x0; uint32_t posU = startU; @@ -478,7 +478,7 @@ public: uint8_t bgcolor = *dest; if (SamplerT::Mode == (int)Samplers::FogBoundary) color = bgcolor; uint8_t fgcolor = Sample8(posU, posV, texPixels, texWidth, texHeight, color, translation); - uint32_t fgshade = SampleShade8(posU, posV, texPixels, texWidth, texHeight, fuzzpos); + uint32_t fgshade = SampleShade8(posU, posV, texPixels, texWidth, texHeight, x0 + i, y); *dest = ShadeAndBlend8(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha); posU += stepU; From e7e9d1a94206dd8ee0edcebdc6bebffc46e2301f Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 22 Nov 2017 19:02:25 +0100 Subject: [PATCH 6/7] - Fixed bug introduced by removing a little bit too much from the rect drawers --- src/polyrenderer/drawers/poly_drawer32.h | 6 ++++++ src/polyrenderer/drawers/poly_drawer32_sse2.h | 6 ++++++ src/polyrenderer/drawers/poly_drawer8.h | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/src/polyrenderer/drawers/poly_drawer32.h b/src/polyrenderer/drawers/poly_drawer32.h index f3d05ae74..1acb3de1b 100644 --- a/src/polyrenderer/drawers/poly_drawer32.h +++ b/src/polyrenderer/drawers/poly_drawer32.h @@ -885,6 +885,12 @@ private: uint32_t posV = startV; for (int y = y0; y < y1; y++, posV += stepV) { + int coreBlock = y / 8; + if (coreBlock % thread->num_cores != thread->core) + { + continue; + } + uint32_t *dest = ((uint32_t*)destOrg) + y * destPitch + x0; uint32_t posU = startU; diff --git a/src/polyrenderer/drawers/poly_drawer32_sse2.h b/src/polyrenderer/drawers/poly_drawer32_sse2.h index 01c614434..3826d063d 100644 --- a/src/polyrenderer/drawers/poly_drawer32_sse2.h +++ b/src/polyrenderer/drawers/poly_drawer32_sse2.h @@ -901,6 +901,12 @@ private: uint32_t posV = startV; for (int y = y0; y < y1; y++, posV += stepV) { + int coreBlock = y / 8; + if (coreBlock % thread->num_cores != thread->core) + { + continue; + } + uint32_t *dest = ((uint32_t*)destOrg) + y * destPitch + x0; uint32_t posU = startU; diff --git a/src/polyrenderer/drawers/poly_drawer8.h b/src/polyrenderer/drawers/poly_drawer8.h index d5ec5bade..fb7169186 100644 --- a/src/polyrenderer/drawers/poly_drawer8.h +++ b/src/polyrenderer/drawers/poly_drawer8.h @@ -470,6 +470,12 @@ public: uint32_t posV = startV; for (int y = y0; y < y1; y++, posV += stepV) { + int coreBlock = y / 8; + if (coreBlock % thread->num_cores != thread->core) + { + continue; + } + uint8_t *dest = ((uint8_t*)destOrg) + y * destPitch + x0; uint32_t posU = startU; From 978fdfb27337d5b4130ebc317f19243648beda15 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 22 Nov 2017 21:42:48 +0100 Subject: [PATCH 7/7] - tested and fixed UMAPINFO parser. Although this looks like it's working with the test file I used it still needs some stress testing! --- src/g_mapinfo.cpp | 1 + src/umapinfo.cpp | 218 ++++++++++++++++++++++++++++------------------ 2 files changed, 133 insertions(+), 86 deletions(-) diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index cb750f4a1..0481c1784 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -2243,6 +2243,7 @@ void G_ParseMapInfo (FString basemapinfo) ParseUMapInfo(lump); } } + CommitUMapinfo(&gamedefaults); // commit remaining UMPAINFOs. if (AllEpisodes.Size() == 0) { diff --git a/src/umapinfo.cpp b/src/umapinfo.cpp index c8d416740..b6b435c40 100644 --- a/src/umapinfo.cpp +++ b/src/umapinfo.cpp @@ -45,18 +45,18 @@ struct UMapEntry FString InterTextSecret; TArray BossActions; - char levelpic[9]; - char nextmap[9]; - char nextsecret[9]; - char music[9]; - char skytexture[9]; - char endpic[9]; - char exitpic[9]; - char enterpic[9]; + char levelpic[9] = ""; + char nextmap[9] = ""; + char nextsecret[9] = ""; + char music[9] = ""; + char skytexture[9] = ""; + char endpic[9] = ""; + char exitpic[9] = ""; + char enterpic[9] = ""; char interbackdrop[9] = "FLOOR4_8"; - char intermusic[9]; - int partime; - int nointermission; + char intermusic[9] = ""; + int partime = 0; + int nointermission = 0; }; static TArray Maps; @@ -132,7 +132,7 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape) if (!pname.CompareNoCase("levelname")) { scanner.MustGetToken(TK_StringConst); - mape->LevelName, scanner.String; + mape->LevelName = scanner.String; } else if (!pname.CompareNoCase("next")) { @@ -216,7 +216,43 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape) { FString Episode = ParseMultiString(scanner, 1); if (Episode.IsEmpty()) return 0; - //M_AddEpisode(mape->mapname, lname); + if (Episode.Compare("-") == 0) + { + // clear the given episode + for (unsigned i = 0; i < AllEpisodes.Size(); i++) + { + if (AllEpisodes[i].mEpisodeMap.CompareNoCase(mape->MapName) == 0) + { + AllEpisodes.Delete(i); + break; + } + } + } + else + { + auto split = Episode.Split("\n"); + // add the given episode + FEpisode epi; + + epi.mEpisodeName = split[1]; + epi.mEpisodeMap = mape->MapName; + epi.mPicName = split[0]; + epi.mShortcut = split[2][0]; + + unsigned i; + for (i = 0; i < AllEpisodes.Size(); i++) + { + if (AllEpisodes[i].mEpisodeMap.CompareNoCase(mape->MapName) == 0) + { + AllEpisodes[i] = std::move(epi); + break; + } + } + if (i == AllEpisodes.Size()) + { + AllEpisodes.Push(epi); + } + } } else if (!pname.CompareNoCase("bossaction")) { @@ -255,12 +291,12 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape) // Skip over all unknown properties. do { - if (!scanner.CheckFloat()) + if (!scanner.CheckValue(true)) { scanner.MustGetAnyToken(); if (scanner.TokenType != TK_Identifier && scanner.TokenType != TK_StringConst && scanner.TokenType != TK_True && scanner.TokenType != TK_False) { - scanner.ScriptError("Identifier or value expecte3d"); + scanner.ScriptError("Identifier or value expected"); } } @@ -279,7 +315,7 @@ static int ParseMapEntry(FScanner &scanner, UMapEntry *val) { scanner.MustGetToken(TK_Identifier); - val->MapName, scanner.String; + val->MapName = scanner.String; scanner.MustGetToken('{'); while(!scanner.CheckToken('}')) { @@ -299,12 +335,10 @@ int ParseUMapInfo(int lumpnum) FScanner scanner(lumpnum); unsigned int i; - while (scanner.CheckToken(TK_Identifier)) + while (scanner.GetToken()) { - if (!scanner.Compare("map")) - { - scanner.ScriptError("'MAP' expected"); - } + scanner.TokenMustBe(TK_Map); + UMapEntry parsed; ParseMapEntry(scanner, &parsed); @@ -355,73 +389,85 @@ void CommitUMapinfo(level_info_t *defaultinfo) auto levelinfo = FindLevelInfo(map.MapName); if (levelinfo == nullptr) { + // Map did not exist yet. + auto levelindex = wadlevelinfos.Reserve(1); + levelinfo = &wadlevelinfos[levelindex]; *levelinfo = *defaultinfo; - if (map.MapName.IsNotEmpty()) levelinfo->MapName = map.MapName; - if (map.MapName.IsNotEmpty()) levelinfo->LevelName = map.LevelName; - if (map.levelpic[0]) levelinfo->PName = map.levelpic; - if (map.nextmap[0]) levelinfo->NextMap = map.nextmap; - else if (map.endpic[0]) - { - FName name; - - if (!stricmp(map.endpic, "$CAST")) - { - name = "INTER_CAST"; - } - else if (!stricmp(map.endpic, "$BUNNY")) - { - name = "INTER_BUNNY"; - } - else - { - name = MakeEndPic(map.endpic); - } - if (name != NAME_None) - { - levelinfo->NextMap.Format("enDSeQ%04x", int(name)); - } - } - - if (map.nextsecret[0]) levelinfo->NextSecretMap = map.nextsecret; - if (map.music[0]) - { - levelinfo->Music = map.music; - levelinfo->musicorder = 0; - } - if (map.skytexture[0]) - { - levelinfo->SkyPic1 = map.skytexture; - levelinfo->skyspeed1 = 0; - levelinfo->SkyPic2 = ""; - levelinfo->skyspeed2 = 0; - } - if (map.partime > 0) levelinfo->partime = map.partime; - if (map.enterpic[0]) levelinfo->EnterPic = map.enterpic; - if (map.exitpic[0]) levelinfo->ExitPic = map.exitpic; - if (map.intermusic[0]) - { - levelinfo->InterMusic = map.intermusic; - levelinfo->intermusicorder = 0; - } - if (map.BossActions.Size() > 0) levelinfo->specialactions = std::move(map.BossActions); - - const int exflags = FExitText::DEF_TEXT | FExitText::DEF_BACKDROP | FExitText::DEF_MUSIC; - if (map.InterText.IsNotEmpty()) - { - if (map.InterText.Compare("-") != 0) - levelinfo->ExitMapTexts[NAME_Normal] = { exflags, 0, map.InterText, map.interbackdrop, map.intermusic[0]? map.intermusic : gameinfo.intermissionMusic }; - else - levelinfo->ExitMapTexts[NAME_Normal] = { 0, 0 }; - } - if (map.InterTextSecret.IsNotEmpty()) - { - if (map.InterTextSecret.Compare("-") != 0) - levelinfo->ExitMapTexts[NAME_Secret] = { exflags, 0, map.InterTextSecret, map.interbackdrop, map.intermusic[0] ? map.intermusic : gameinfo.intermissionMusic }; - else - levelinfo->ExitMapTexts[NAME_Secret] = { 0, 0 }; - } - if (map.nointermission) levelinfo->flags |= LEVEL_NOINTERMISSION; } + if (map.MapName.IsNotEmpty()) levelinfo->MapName = map.MapName; + if (map.LevelName.IsNotEmpty()) + { + levelinfo->LevelName = map.LevelName; + levelinfo->PName = ""; // clear the map name patch to force the string version to be shown - unless explicitly overridden right next. + } + if (map.levelpic[0]) levelinfo->PName = map.levelpic; + if (map.nextmap[0]) levelinfo->NextMap = map.nextmap; + else if (map.endpic[0]) + { + FName name; + + if (!stricmp(map.endpic, "$CAST")) + { + name = "INTER_CAST"; + } + else if (!stricmp(map.endpic, "$BUNNY")) + { + name = "INTER_BUNNY"; + } + else + { + name = MakeEndPic(map.endpic); + } + if (name != NAME_None) + { + levelinfo->NextMap.Format("enDSeQ%04x", int(name)); + } + } + + if (map.nextsecret[0]) levelinfo->NextSecretMap = map.nextsecret; + if (map.music[0]) + { + levelinfo->Music = map.music; + levelinfo->musicorder = 0; + } + if (map.skytexture[0]) + { + levelinfo->SkyPic1 = map.skytexture; + levelinfo->skyspeed1 = 0; + levelinfo->SkyPic2 = ""; + levelinfo->skyspeed2 = 0; + } + if (map.partime > 0) levelinfo->partime = map.partime; + if (map.enterpic[0]) levelinfo->EnterPic = map.enterpic; + if (map.exitpic[0]) levelinfo->ExitPic = map.exitpic; + if (map.intermusic[0]) + { + levelinfo->InterMusic = map.intermusic; + levelinfo->intermusicorder = 0; + } + if (map.BossActions.Size() > 0) + { + // Setting a boss action will deactivate the flag based monster actions. + levelinfo->specialactions = std::move(map.BossActions); + levelinfo->flags &= ~(LEVEL_BRUISERSPECIAL | LEVEL_CYBORGSPECIAL | LEVEL_SPIDERSPECIAL | LEVEL_MAP07SPECIAL | LEVEL_MINOTAURSPECIAL | LEVEL_HEADSPECIAL | LEVEL_SORCERER2SPECIAL | LEVEL_SPECACTIONSMASK | LEVEL_SPECKILLMONSTERS); + } + + const int exflags = FExitText::DEF_TEXT | FExitText::DEF_BACKDROP | FExitText::DEF_MUSIC; + if (map.InterText.IsNotEmpty()) + { + if (map.InterText.Compare("-") != 0) + levelinfo->ExitMapTexts[NAME_Normal] = { exflags, 0, map.InterText, map.interbackdrop, map.intermusic[0]? map.intermusic : gameinfo.intermissionMusic }; + else + levelinfo->ExitMapTexts[NAME_Normal] = { 0, 0 }; + } + if (map.InterTextSecret.IsNotEmpty()) + { + if (map.InterTextSecret.Compare("-") != 0) + levelinfo->ExitMapTexts[NAME_Secret] = { exflags, 0, map.InterTextSecret, map.interbackdrop, map.intermusic[0] ? map.intermusic : gameinfo.intermissionMusic }; + else + levelinfo->ExitMapTexts[NAME_Secret] = { 0, 0 }; + } + if (map.nointermission) levelinfo->flags |= LEVEL_NOINTERMISSION; }