Merge remote-tracking branch 'gzdoom/master' into newmaster

This commit is contained in:
Major Cooke 2019-11-14 14:04:44 -06:00
commit 4c8f87627e
42 changed files with 1493 additions and 1277 deletions

View file

@ -1003,6 +1003,7 @@ set (PCH_SOURCES
maploader/polyobjects.cpp maploader/polyobjects.cpp
maploader/renderinfo.cpp maploader/renderinfo.cpp
maploader/compatibility.cpp maploader/compatibility.cpp
maploader/postprocessor.cpp
menu/joystickmenu.cpp menu/joystickmenu.cpp
menu/loadsavemenu.cpp menu/loadsavemenu.cpp
menu/menu.cpp menu/menu.cpp

View file

@ -128,6 +128,10 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize,
sc.MustGetString(); sc.MustGetString();
iwad->MapInfo = sc.String; iwad->MapInfo = sc.String;
} }
else if (sc.Compare("NoKeyboardCheats"))
{
iwad->nokeyboardcheats = true;
}
else if (sc.Compare("Compatibility")) else if (sc.Compare("Compatibility"))
{ {
sc.MustGetStringName("="); sc.MustGetStringName("=");

View file

@ -2480,6 +2480,7 @@ static int D_DoomMain_Internal (void)
if (!iwad_info) return 0; // user exited the selection popup via cancel button. if (!iwad_info) return 0; // user exited the selection popup via cancel button.
gameinfo.gametype = iwad_info->gametype; gameinfo.gametype = iwad_info->gametype;
gameinfo.flags = iwad_info->flags; gameinfo.flags = iwad_info->flags;
gameinfo.nokeyboardcheats = iwad_info->nokeyboardcheats;
gameinfo.ConfigName = iwad_info->Configname; gameinfo.ConfigName = iwad_info->Configname;
lastIWAD = iwad; lastIWAD = iwad;

View file

@ -107,6 +107,7 @@ struct FIWADInfo
EGameType gametype = GAME_Doom; // which game are we playing? EGameType gametype = GAME_Doom; // which game are we playing?
int StartupType = FStartupInfo::DefaultStartup; // alternate startup type int StartupType = FStartupInfo::DefaultStartup; // alternate startup type
FString MapInfo; // Base mapinfo to load FString MapInfo; // Base mapinfo to load
bool nokeyboardcheats = false; // disable keyboard cheats
TArray<FString> Load; // Wads to be loaded with this one. TArray<FString> Load; // Wads to be loaded with this one.
TArray<FString> Lumps; // Lump names for identification TArray<FString> Lumps; // Lump names for identification
TArray<FString> DeleteLumps; // Lumps which must be deleted from the directory. TArray<FString> DeleteLumps; // Lumps which must be deleted from the directory.

View file

@ -111,6 +111,7 @@ struct gameinfo_t
FString ConfigName; FString ConfigName;
FString TitlePage; FString TitlePage;
bool nokeyboardcheats;
bool drawreadthis; bool drawreadthis;
bool noloopfinalemusic; bool noloopfinalemusic;
bool intermissioncounter; bool intermissioncounter;

View file

@ -50,7 +50,6 @@
#include "w_wad.h" #include "w_wad.h"
#include "textures.h" #include "textures.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#include "vm.h"
#include "actor.h" #include "actor.h"
#include "p_setup.h" #include "p_setup.h"
#include "maploader/maploader.h" #include "maploader/maploader.h"
@ -340,209 +339,3 @@ FName MapLoader::CheckCompatibility(MapData *map)
} }
return FName(hash, true); // if this returns NAME_None it means there is no scripted compatibility handler. return FName(hash, true); // if this returns NAME_None it means there is no scripted compatibility handler.
} }
//==========================================================================
//
// SetCompatibilityParams
//
//==========================================================================
class DLevelCompatibility : public DObject
{
DECLARE_ABSTRACT_CLASS(DLevelCompatibility, DObject)
public:
MapLoader *loader;
FLevelLocals *Level;
};
IMPLEMENT_CLASS(DLevelCompatibility, true, false);
void MapLoader::SetCompatibilityParams(FName checksum)
{
auto lc = Create<DLevelCompatibility>();
lc->loader = this;
lc->Level = Level;
for(auto cls : PClass::AllClasses)
{
if (cls->IsDescendantOf(RUNTIME_CLASS(DLevelCompatibility)))
{
PFunction *const func = dyn_cast<PFunction>(cls->FindSymbol("Apply", false));
if (func == nullptr)
{
Printf("Missing 'Apply' method in class '%s', level compatibility object ignored\n", cls->TypeName.GetChars());
continue;
}
auto argTypes = func->Variants[0].Proto->ArgumentTypes;
if (argTypes.Size() != 3 || argTypes[1] != TypeName || argTypes[2] != TypeString)
{
Printf("Wrong signature of 'Apply' method in class '%s', level compatibility object ignored\n", cls->TypeName.GetChars());
continue;
}
VMValue param[] = { lc, checksum.GetIndex(), &Level->MapName };
VMCall(func->Variants[0].Implementation, param, 3, nullptr, 0);
}
}
}
DEFINE_ACTION_FUNCTION(DLevelCompatibility, OffsetSectorPlane)
{
PARAM_SELF_PROLOGUE(DLevelCompatibility);
PARAM_INT(sector);
PARAM_INT(planeval);
PARAM_FLOAT(delta);
if ((unsigned)sector < self->Level->sectors.Size())
{
sector_t *sec = &self->Level->sectors[sector];
secplane_t& plane = sector_t::floor == planeval? sec->floorplane : sec->ceilingplane;
plane.ChangeHeight(delta);
sec->ChangePlaneTexZ(planeval, delta);
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelCompatibility, ClearSectorTags)
{
PARAM_SELF_PROLOGUE(DLevelCompatibility);
PARAM_INT(sector);
self->Level->tagManager.RemoveSectorTags(sector);
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelCompatibility, AddSectorTag)
{
PARAM_SELF_PROLOGUE(DLevelCompatibility);
PARAM_INT(sector);
PARAM_INT(tag);
if ((unsigned)sector < self->Level->sectors.Size())
{
self->Level->tagManager.AddSectorTag(sector, tag);
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelCompatibility, ClearLineIDs)
{
PARAM_SELF_PROLOGUE(DLevelCompatibility);
PARAM_INT(line);
self->Level->tagManager.RemoveLineIDs(line);
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelCompatibility, AddLineID)
{
PARAM_SELF_PROLOGUE(DLevelCompatibility);
PARAM_INT(line);
PARAM_INT(tag);
if ((unsigned)line < self->Level->lines.Size())
{
self->Level->tagManager.AddLineID(line, tag);
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelCompatibility, SetThingSkills)
{
PARAM_SELF_PROLOGUE(DLevelCompatibility);
PARAM_INT(thing);
PARAM_INT(skillmask);
if ((unsigned)thing < self->loader->MapThingsConverted.Size())
{
self->loader->MapThingsConverted[thing].SkillFilter = skillmask;
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelCompatibility, SetThingXY)
{
PARAM_SELF_PROLOGUE(DLevelCompatibility);
PARAM_INT(thing);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
if ((unsigned)thing < self->loader->MapThingsConverted.Size())
{
auto& pos = self->loader->MapThingsConverted[thing].pos;
pos.X = x;
pos.Y = y;
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelCompatibility, SetThingZ)
{
PARAM_SELF_PROLOGUE(DLevelCompatibility);
PARAM_INT(thing);
PARAM_FLOAT(z);
if ((unsigned)thing < self->loader->MapThingsConverted.Size())
{
self->loader->MapThingsConverted[thing].pos.Z = z;
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelCompatibility, SetThingFlags)
{
PARAM_SELF_PROLOGUE(DLevelCompatibility);
PARAM_INT(thing);
PARAM_INT(flags);
if ((unsigned)thing < self->loader->MapThingsConverted.Size())
{
self->loader->MapThingsConverted[thing].flags = flags;
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelCompatibility, SetVertex)
{
PARAM_SELF_PROLOGUE(DLevelCompatibility);
PARAM_UINT(vertex);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
if (vertex < self->Level->vertexes.Size())
{
self->Level->vertexes[vertex].p = DVector2(x, y);
}
self->loader->ForceNodeBuild = true;
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelCompatibility, SetLineSectorRef)
{
PARAM_SELF_PROLOGUE(DLevelCompatibility);
PARAM_UINT(lineidx);
PARAM_UINT(sideidx);
PARAM_UINT(sectoridx);
if ( sideidx < 2
&& lineidx < self->Level->lines.Size()
&& sectoridx < self->Level->sectors.Size())
{
line_t *line = &self->Level->lines[lineidx];
side_t *side = line->sidedef[sideidx];
side->sector = &self->Level->sectors[sectoridx];
if (sideidx == 0) line->frontsector = side->sector;
else line->backsector = side->sector;
}
self->loader->ForceNodeBuild = true;
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelCompatibility, GetDefaultActor)
{
PARAM_SELF_PROLOGUE(DLevelCompatibility);
PARAM_NAME(actorclass);
ACTION_RETURN_OBJECT(GetDefaultByName(actorclass));
}
DEFINE_FIELD(DLevelCompatibility, Level);

View file

@ -79,6 +79,7 @@
#include "swrenderer/r_swrenderer.h" #include "swrenderer/r_swrenderer.h"
#include "hwrenderer/data/flatvertices.h" #include "hwrenderer/data/flatvertices.h"
#include "xlat/xlat.h" #include "xlat/xlat.h"
#include "vm.h"
enum enum
{ {
@ -3053,7 +3054,8 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
ParseTextMap(map, missingtex); ParseTextMap(map, missingtex);
} }
SetCompatibilityParams(checksum); CalcIndices();
PostProcessLevel(checksum);
LoopSidedefs(true); LoopSidedefs(true);
@ -3269,3 +3271,4 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
if (!Level->IsReentering()) if (!Level->IsReentering())
Level->FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them. Level->FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them.
} }

View file

@ -131,7 +131,7 @@ private:
TArray<int32_t> KnownPolySides; TArray<int32_t> KnownPolySides;
FName CheckCompatibility(MapData *map); FName CheckCompatibility(MapData *map);
void SetCompatibilityParams(FName checksum); void PostProcessLevel(FName checksum);
// Slopes // Slopes
void SlopeLineToPoint(int lineid, const DVector3 &pos, bool slopeCeil); void SlopeLineToPoint(int lineid, const DVector3 &pos, bool slopeCeil);

View file

@ -0,0 +1,516 @@
/*
** postprocessor.cpp
** Level postprocessing
**
**---------------------------------------------------------------------------
** Copyright 2009 Randy Heit
** Copyright 2009-2018 Christoph Oelckers
** Copyright 2019 Alexey Lysiuk
** 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 "doomstat.h"
#include "c_dispatch.h"
#include "gi.h"
#include "g_level.h"
#include "p_lnspec.h"
#include "p_tags.h"
#include "w_wad.h"
#include "textures.h"
#include "g_levellocals.h"
#include "actor.h"
#include "p_setup.h"
#include "maploader/maploader.h"
#include "types.h"
#include "vm.h"
//==========================================================================
//
// PostProcessLevel
//
//==========================================================================
class DLevelPostProcessor : public DObject
{
DECLARE_ABSTRACT_CLASS(DLevelPostProcessor, DObject)
public:
MapLoader *loader;
FLevelLocals *Level;
};
IMPLEMENT_CLASS(DLevelPostProcessor, true, false);
void MapLoader::PostProcessLevel(FName checksum)
{
auto lc = Create<DLevelPostProcessor>();
lc->loader = this;
lc->Level = Level;
for(auto cls : PClass::AllClasses)
{
if (cls->IsDescendantOf(RUNTIME_CLASS(DLevelPostProcessor)))
{
PFunction *const func = dyn_cast<PFunction>(cls->FindSymbol("Apply", false));
if (func == nullptr)
{
Printf("Missing 'Apply' method in class '%s', level compatibility object ignored\n", cls->TypeName.GetChars());
continue;
}
auto argTypes = func->Variants[0].Proto->ArgumentTypes;
if (argTypes.Size() != 3 || argTypes[1] != TypeName || argTypes[2] != TypeString)
{
Printf("Wrong signature of 'Apply' method in class '%s', level compatibility object ignored\n", cls->TypeName.GetChars());
continue;
}
VMValue param[] = { lc, checksum.GetIndex(), &Level->MapName };
VMCall(func->Variants[0].Implementation, param, 3, nullptr, 0);
}
}
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, OffsetSectorPlane)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_INT(sector);
PARAM_INT(planeval);
PARAM_FLOAT(delta);
if ((unsigned)sector < self->Level->sectors.Size())
{
sector_t *sec = &self->Level->sectors[sector];
secplane_t& plane = sector_t::floor == planeval? sec->floorplane : sec->ceilingplane;
plane.ChangeHeight(delta);
sec->ChangePlaneTexZ(planeval, delta);
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, ClearSectorTags)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_INT(sector);
self->Level->tagManager.RemoveSectorTags(sector);
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, AddSectorTag)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_INT(sector);
PARAM_INT(tag);
if ((unsigned)sector < self->Level->sectors.Size())
{
self->Level->tagManager.AddSectorTag(sector, tag);
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, ClearLineIDs)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_INT(line);
self->Level->tagManager.RemoveLineIDs(line);
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, AddLineID)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_INT(line);
PARAM_INT(tag);
if ((unsigned)line < self->Level->lines.Size())
{
self->Level->tagManager.AddLineID(line, tag);
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetThingCount)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
ACTION_RETURN_INT(self->loader->MapThingsConverted.Size());
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, AddThing)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(ednum);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(z);
PARAM_INT(angle);
PARAM_UINT(skills);
PARAM_UINT(flags);
auto &things = self->loader->MapThingsConverted;
const unsigned newindex = things.Size();
things.Resize(newindex + 1);
auto &newthing = things.Last();
memset(&newthing, 0, sizeof newthing);
newthing.Gravity = 1;
newthing.SkillFilter = skills;
newthing.ClassFilter = 0xFFFF;
newthing.RenderStyle = STYLE_Count;
newthing.Alpha = -1;
newthing.Health = 1;
newthing.FloatbobPhase = -1;
newthing.pos.X = x;
newthing.pos.Y = y;
newthing.pos.Z = z;
newthing.angle = angle;
newthing.EdNum = ednum;
newthing.info = DoomEdMap.CheckKey(ednum);
newthing.flags = flags;
ACTION_RETURN_INT(newindex);
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetThingEdNum)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
const int ednum = thing < self->loader->MapThingsConverted.Size()
? self->loader->MapThingsConverted[thing].EdNum : 0;
ACTION_RETURN_INT(ednum);
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetThingEdNum)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
PARAM_UINT(ednum);
if (thing < self->loader->MapThingsConverted.Size())
{
auto &mti = self->loader->MapThingsConverted[thing];
mti.EdNum = ednum;
mti.info = DoomEdMap.CheckKey(ednum);
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetThingPos)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
const DVector3 pos = thing < self->loader->MapThingsConverted.Size()
? self->loader->MapThingsConverted[thing].pos
: DVector3(0, 0, 0);
ACTION_RETURN_VEC3(pos);
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetThingXY)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
if (thing < self->loader->MapThingsConverted.Size())
{
auto& pos = self->loader->MapThingsConverted[thing].pos;
pos.X = x;
pos.Y = y;
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetThingZ)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
PARAM_FLOAT(z);
if (thing < self->loader->MapThingsConverted.Size())
{
self->loader->MapThingsConverted[thing].pos.Z = z;
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetThingAngle)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
const int angle = thing < self->loader->MapThingsConverted.Size()
? self->loader->MapThingsConverted[thing].angle : 0;
ACTION_RETURN_INT(angle);
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetThingAngle)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
PARAM_INT(angle);
if (thing < self->loader->MapThingsConverted.Size())
{
self->loader->MapThingsConverted[thing].angle = angle;
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetThingSkills)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
const int skills = thing < self->loader->MapThingsConverted.Size()
? self->loader->MapThingsConverted[thing].SkillFilter : 0;
ACTION_RETURN_INT(skills);
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetThingSkills)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
PARAM_UINT(skillmask);
if (thing < self->loader->MapThingsConverted.Size())
{
self->loader->MapThingsConverted[thing].SkillFilter = skillmask;
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetThingFlags)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
const unsigned flags = thing < self->loader->MapThingsConverted.Size()
? self->loader->MapThingsConverted[thing].flags : 0;
ACTION_RETURN_INT(flags);
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetThingFlags)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
PARAM_UINT(flags);
if (thing < self->loader->MapThingsConverted.Size())
{
self->loader->MapThingsConverted[thing].flags = flags;
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetThingSpecial)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
const int special = thing < self->loader->MapThingsConverted.Size()
? self->loader->MapThingsConverted[thing].special : 0;
ACTION_RETURN_INT(special);
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetThingSpecial)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
PARAM_INT(special);
if (thing < self->loader->MapThingsConverted.Size())
{
self->loader->MapThingsConverted[thing].special = special;
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetThingArgument)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
PARAM_UINT(index);
const int argument = index < 5 && thing < self->loader->MapThingsConverted.Size()
? self->loader->MapThingsConverted[thing].args[index] : 0;
ACTION_RETURN_INT(argument);
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetThingStringArgument)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
const FName argument = thing < self->loader->MapThingsConverted.Size()
? self->loader->MapThingsConverted[thing].arg0str : NAME_None;
ACTION_RETURN_INT(argument);
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetThingArgument)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
PARAM_UINT(index);
PARAM_INT(value);
if (index < 5 && thing < self->loader->MapThingsConverted.Size())
{
self->loader->MapThingsConverted[thing].args[index] = value;
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetThingStringArgument)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
PARAM_INT(value);
if (thing < self->loader->MapThingsConverted.Size())
{
self->loader->MapThingsConverted[thing].arg0str = ENamedName(value);
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetThingID)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
const int id = thing < self->loader->MapThingsConverted.Size()
? self->loader->MapThingsConverted[thing].thingid : 0;
ACTION_RETURN_INT(id);
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetThingID)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(thing);
PARAM_INT(id);
if (thing < self->loader->MapThingsConverted.Size())
{
self->loader->MapThingsConverted[thing].thingid = id;
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetVertex)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(vertex);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
if (vertex < self->Level->vertexes.Size())
{
self->Level->vertexes[vertex].p = DVector2(x, y);
}
self->loader->ForceNodeBuild = true;
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetLineVertexes)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(lineidx);
PARAM_UINT(vertexidx1);
PARAM_UINT(vertexidx2);
if (lineidx < self->Level->lines.Size() &&
vertexidx1 < self->Level->vertexes.Size() &&
vertexidx2 < self->Level->vertexes.Size())
{
line_t *line = &self->Level->lines[lineidx];
vertex_t *vertex1 = &self->Level->vertexes[vertexidx1];
vertex_t *vertex2 = &self->Level->vertexes[vertexidx2];
line->v1 = vertex1;
line->v2 = vertex2;
}
self->loader->ForceNodeBuild = true;
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, FlipLineSideRefs)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(lineidx);
if (lineidx < self->Level->lines.Size())
{
line_t *line = &self->Level->lines[lineidx];
side_t *side1 = line->sidedef[1];
side_t *side2 = line->sidedef[0];
if (!!side1 && !!side2) // don't flip single-sided lines
{
sector_t *frontsector = line->sidedef[1]->sector;
sector_t *backsector = line->sidedef[0]->sector;
line->sidedef[0] = side1;
line->sidedef[1] = side2;
line->frontsector = frontsector;
line->backsector = backsector;
}
}
self->loader->ForceNodeBuild = true;
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetLineSectorRef)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(lineidx);
PARAM_UINT(sideidx);
PARAM_UINT(sectoridx);
if ( sideidx < 2
&& lineidx < self->Level->lines.Size()
&& sectoridx < self->Level->sectors.Size())
{
line_t *line = &self->Level->lines[lineidx];
side_t *side = line->sidedef[sideidx];
side->sector = &self->Level->sectors[sectoridx];
if (sideidx == 0) line->frontsector = side->sector;
else line->backsector = side->sector;
}
self->loader->ForceNodeBuild = true;
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, GetDefaultActor)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_NAME(actorclass);
ACTION_RETURN_OBJECT(GetDefaultByName(actorclass));
}
DEFINE_FIELD(DLevelPostProcessor, Level);

View file

@ -592,12 +592,10 @@ void P_GiveSecret(FLevelLocals *Level, AActor *actor, bool printmessage, bool pl
{ {
if (printmessage) if (printmessage)
{ {
if (!showsecretsector || sectornum < 0) C_MidPrint(nullptr, GStrings["SECRETMESSAGE"]); C_MidPrint(nullptr, GStrings["SECRETMESSAGE"]);
else if (showsecretsector && sectornum >= 0)
{ {
FString s = GStrings["SECRETMESSAGE"]; Printf(PRINT_NONOTIFY, "Secret found in sector %d\n", sectornum);
s.AppendFormat(" (Sector %d)", sectornum);
C_MidPrint(nullptr, s);
} }
} }
if (playsound) S_Sound (CHAN_AUTO | CHAN_UI, "misc/secret", 1, ATTN_NORM); if (playsound) S_Sound (CHAN_AUTO | CHAN_UI, "misc/secret", 1, ATTN_NORM);

View file

@ -54,12 +54,15 @@
namespace swrenderer namespace swrenderer
{ {
void RenderFogBoundary::Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, const ProjectedWallLight &wallLight) void RenderFogBoundary::Render(RenderThread *thread, int x1, int x2, const DrawSegmentClipInfo& clip, const ProjectedWallLight &wallLight)
{ {
// This is essentially the same as R_MapVisPlane but with an extra step // This is essentially the same as R_MapVisPlane but with an extra step
// to create new horizontal spans whenever the light changes enough that // to create new horizontal spans whenever the light changes enough that
// we need to use a new colormap. // we need to use a new colormap.
const short* uclip = clip.sprtopclip;
const short* dclip = clip.sprbottomclip;
int wallshade = LightVisibility::LightLevelToShade(wallLight.GetLightLevel(), wallLight.GetFoggy(), thread->Viewport.get()); int wallshade = LightVisibility::LightLevelToShade(wallLight.GetLightLevel(), wallLight.GetFoggy(), thread->Viewport.get());
int x = x2 - 1; int x = x2 - 1;
int t2 = uclip[x]; int t2 = uclip[x];

View file

@ -31,7 +31,7 @@ namespace swrenderer
class RenderFogBoundary class RenderFogBoundary
{ {
public: public:
void Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, const ProjectedWallLight &wallLight); void Render(RenderThread *thread, int x1, int x2, const DrawSegmentClipInfo &clip, const ProjectedWallLight &wallLight);
private: private:
void RenderSection(RenderThread *thread, int y, int y2, int x1); void RenderSection(RenderThread *thread, int y, int y2, int x1);

View file

@ -109,21 +109,7 @@ namespace swrenderer
if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && P_ClipLineToPortal(line->linedef, renderportal->CurrentPortal->dst, Thread->Viewport->viewpoint.Pos)) if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && P_ClipLineToPortal(line->linedef, renderportal->CurrentPortal->dst, Thread->Viewport->viewpoint.Pos))
return; return;
vertex_t *v1 = line->linedef->v1; WallT.InitFromLine(Thread, line);
vertex_t *v2 = line->linedef->v2;
if ((v1 == line->v1 && v2 == line->v2) || (v2 == line->v1 && v1 == line->v2))
{ // The seg is the entire wall.
WallT.InitFromWallCoords(Thread, &WallC);
}
else
{ // The seg is only part of the wall.
if (line->linedef->sidedef[0] != line->sidedef)
{
swapvalues(v1, v2);
}
WallT.InitFromLine(Thread, v1->fPos() - Thread->Viewport->viewpoint.Pos, v2->fPos() - Thread->Viewport->viewpoint.Pos);
}
mFrontCeilingZ1 = mFrontSector->ceilingplane.ZatPoint(line->v1); mFrontCeilingZ1 = mFrontSector->ceilingplane.ZatPoint(line->v1);
mFrontFloorZ1 = mFrontSector->floorplane.ZatPoint(line->v1); mFrontFloorZ1 = mFrontSector->floorplane.ZatPoint(line->v1);
@ -301,14 +287,6 @@ namespace swrenderer
// A wall segment will be drawn between start and stop pixels (inclusive). // A wall segment will be drawn between start and stop pixels (inclusive).
bool SWRenderLine::RenderWallSegment(int start, int stop) bool SWRenderLine::RenderWallSegment(int start, int stop)
{ {
int i;
bool maskedtexture = false;
#ifdef RANGECHECK
if (start >= viewwidth || start >= stop)
I_Error("Bad R_StoreWallRange: %i to %i", start, stop);
#endif
if (!rw_prepped) if (!rw_prepped)
{ {
rw_prepped = true; rw_prepped = true;
@ -327,41 +305,39 @@ namespace swrenderer
if (m3DFloor.type == Fake3DOpaque::Normal) if (m3DFloor.type == Fake3DOpaque::Normal)
Thread->DrawSegments->Push(draw_segment); Thread->DrawSegments->Push(draw_segment);
draw_segment->CurrentPortalUniq = renderportal->CurrentPortalUniq; draw_segment->drawsegclip.CurrentPortalUniq = renderportal->CurrentPortalUniq;
draw_segment->WallC = WallC; draw_segment->WallC = WallC;
draw_segment->tmapvals = WallT; draw_segment->tmapvals = WallT;
draw_segment->x1 = start; draw_segment->x1 = start;
draw_segment->x2 = stop; draw_segment->x2 = stop;
draw_segment->curline = mLineSegment; draw_segment->curline = mLineSegment;
draw_segment->SubsectorDepth = Thread->OpaquePass->GetSubsectorDepth(mSubsector->Index()); draw_segment->drawsegclip.SubsectorDepth = Thread->OpaquePass->GetSubsectorDepth(mSubsector->Index());
bool markportal = ShouldMarkPortal(); bool markportal = ShouldMarkPortal();
if (markportal) if (markportal)
{ {
draw_segment->silhouette = SIL_BOTH; draw_segment->drawsegclip.SetTopClip(Thread, start, stop, Thread->OpaquePass->ceilingclip);
draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, Thread->OpaquePass->floorclip);
draw_segment->drawsegclip.silhouette = SIL_BOTH;
} }
else if (mBackSector == NULL) else if (!mBackSector)
{ {
draw_segment->sprtopclip = Thread->FrameMemory->AllocMemory<short>(stop - start); draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight);
draw_segment->sprbottomclip = Thread->FrameMemory->AllocMemory<short>(stop - start); draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, -1);
fillshort(draw_segment->sprtopclip, stop - start, viewheight); draw_segment->drawsegclip.silhouette = SIL_BOTH;
memset(draw_segment->sprbottomclip, -1, (stop - start) * sizeof(short));
draw_segment->silhouette = SIL_BOTH;
} }
else else
{ {
// two sided line // two sided line
if (mFrontFloorZ1 > mBackFloorZ1 || mFrontFloorZ2 > mBackFloorZ2 || if (mFrontFloorZ1 > mBackFloorZ1 || mFrontFloorZ2 > mBackFloorZ2 || mBackSector->floorplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0)
mBackSector->floorplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0)
{ {
draw_segment->silhouette = SIL_BOTTOM; draw_segment->drawsegclip.silhouette = SIL_BOTTOM;
} }
if (mFrontCeilingZ1 < mBackCeilingZ1 || mFrontCeilingZ2 < mBackCeilingZ2 || if (mFrontCeilingZ1 < mBackCeilingZ1 || mFrontCeilingZ2 < mBackCeilingZ2 || mBackSector->ceilingplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0)
mBackSector->ceilingplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0)
{ {
draw_segment->silhouette |= SIL_TOP; draw_segment->drawsegclip.silhouette |= SIL_TOP;
} }
// killough 1/17/98: this test is required if the fix // killough 1/17/98: this test is required if the fix
@ -372,27 +348,27 @@ namespace swrenderer
// //
// killough 4/7/98: make doorclosed external variable // killough 4/7/98: make doorclosed external variable
{
if (mDoorClosed || (mBackCeilingZ1 <= mFrontFloorZ1 && mBackCeilingZ2 <= mFrontFloorZ2)) if (mDoorClosed || (mBackCeilingZ1 <= mFrontFloorZ1 && mBackCeilingZ2 <= mFrontFloorZ2))
{ {
draw_segment->sprbottomclip = Thread->FrameMemory->AllocMemory<short>(stop - start); draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, -1);
memset(draw_segment->sprbottomclip, -1, (stop - start) * sizeof(short)); draw_segment->drawsegclip.silhouette |= SIL_BOTTOM;
draw_segment->silhouette |= SIL_BOTTOM;
} }
if (mDoorClosed || (mBackFloorZ1 >= mFrontCeilingZ1 && mBackFloorZ2 >= mFrontCeilingZ2)) if (mDoorClosed || (mBackFloorZ1 >= mFrontCeilingZ1 && mBackFloorZ2 >= mFrontCeilingZ2))
{ // killough 1/17/98, 2/8/98 {
draw_segment->sprtopclip = Thread->FrameMemory->AllocMemory<short>(stop - start); draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight);
fillshort(draw_segment->sprtopclip, stop - start, viewheight); draw_segment->drawsegclip.silhouette |= SIL_TOP;
draw_segment->silhouette |= SIL_TOP;
}
} }
if (m3DFloor.type == Fake3DOpaque::Normal) if (m3DFloor.type == Fake3DOpaque::Normal)
{
if ((mCeilingClipped != ProjectedWallCull::OutsideBelow || !sidedef->GetTexture(side_t::top).isValid()) &&
(mFloorClipped != ProjectedWallCull::OutsideAbove || !sidedef->GetTexture(side_t::bottom).isValid()) &&
(WallC.sz1 >= TOO_CLOSE_Z && WallC.sz2 >= TOO_CLOSE_Z))
{ {
if (r_3dfloors) if (r_3dfloors)
{ {
if (mBackSector->e && mBackSector->e->XFloor.ffloors.Size()) { if (mBackSector->e && mBackSector->e->XFloor.ffloors.Size()) {
for (i = 0; i < (int)mBackSector->e->XFloor.ffloors.Size(); i++) { for (int i = 0; i < (int)mBackSector->e->XFloor.ffloors.Size(); i++) {
F3DFloor* rover = mBackSector->e->XFloor.ffloors[i]; F3DFloor* rover = mBackSector->e->XFloor.ffloors[i];
if (rover->flags & FF_RENDERSIDES && (!(rover->flags & FF_INVERTSIDES) || rover->flags & FF_ALLSIDES)) { if (rover->flags & FF_RENDERSIDES && (!(rover->flags & FF_INVERTSIDES) || rover->flags & FF_ALLSIDES)) {
draw_segment->SetHas3DFloorBackSectorWalls(); draw_segment->SetHas3DFloorBackSectorWalls();
@ -401,7 +377,7 @@ namespace swrenderer
} }
} }
if (mFrontSector->e && mFrontSector->e->XFloor.ffloors.Size()) { if (mFrontSector->e && mFrontSector->e->XFloor.ffloors.Size()) {
for (i = 0; i < (int)mFrontSector->e->XFloor.ffloors.Size(); i++) { for (int i = 0; i < (int)mFrontSector->e->XFloor.ffloors.Size(); i++) {
F3DFloor* rover = mFrontSector->e->XFloor.ffloors[i]; F3DFloor* rover = mFrontSector->e->XFloor.ffloors[i];
if (rover->flags & FF_RENDERSIDES && (rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) { if (rover->flags & FF_RENDERSIDES && (rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) {
draw_segment->SetHas3DFloorFrontSectorWalls(); draw_segment->SetHas3DFloorFrontSectorWalls();
@ -411,44 +387,26 @@ namespace swrenderer
} }
} }
// allocate space for masked texture tables, if needed if (IsFogBoundary(mFrontSector, mBackSector))
// [RH] Don't just allocate the space; fill it in too. draw_segment->SetHasFogBoundary();
if ((sidedef->GetTexture(side_t::mid).isValid() || draw_segment->Has3DFloorWalls() || IsFogBoundary(mFrontSector, mBackSector)) &&
(mCeilingClipped != ProjectedWallCull::OutsideBelow || !sidedef->GetTexture(side_t::top).isValid()) && if (mLineSegment->linedef->alpha > 0.0f && sidedef->GetTexture(side_t::mid).isValid())
(mFloorClipped != ProjectedWallCull::OutsideAbove || !sidedef->GetTexture(side_t::bottom).isValid()) &&
(WallC.sz1 >= TOO_CLOSE_Z && WallC.sz2 >= TOO_CLOSE_Z))
{ {
maskedtexture = true;
// kg3D - backup for mid and fake walls
draw_segment->bkup = Thread->FrameMemory->AllocMemory<short>(stop - start);
memcpy(draw_segment->bkup, &Thread->OpaquePass->ceilingclip[start], sizeof(short)*(stop - start));
draw_segment->bFogBoundary = IsFogBoundary(mFrontSector, mBackSector);
bool is_translucent = sidedef->GetTexture(side_t::mid).isValid() || draw_segment->Has3DFloorWalls();
if (is_translucent)
{
if (sidedef->GetTexture(side_t::mid).isValid())
draw_segment->SetHas3DFloorMidTexture();
FTexture* tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true); FTexture* tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true);
FSoftwareTexture* pic = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr; FSoftwareTexture* pic = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr;
double yscale = (pic ? pic->GetScale().Y : 1.0) * sidedef->GetTextureYScale(side_t::mid); if (pic)
fixed_t xoffset = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::mid));
if (pic && pic->useWorldPanning(sidedef->GetLevel()))
{ {
xoffset = xs_RoundToInt(xoffset * lwallscale); draw_segment->SetHasTranslucentMidTexture();
} draw_segment->texcoords.ProjectTranslucent(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, pic);
draw_segment->drawsegclip.silhouette |= SIL_TOP | SIL_BOTTOM;
draw_segment->texcoords.Set(Thread, walltexcoords, start, stop, xoffset, yscale); }
} }
if (draw_segment->HasFogBoundary() || draw_segment->HasTranslucentMidTexture() || draw_segment->Has3DFloorWalls())
{
draw_segment->drawsegclip.SetBackupClip(Thread, start, stop, Thread->OpaquePass->ceilingclip);
draw_segment->light = mLight.GetLightPos(start); draw_segment->light = mLight.GetLightPos(start);
draw_segment->lightstep = mLight.GetLightStep(); draw_segment->lightstep = mLight.GetLightStep();
if (draw_segment->bFogBoundary || is_translucent)
{
Thread->DrawSegments->PushTranslucent(draw_segment); Thread->DrawSegments->PushTranslucent(draw_segment);
} }
} }
@ -468,22 +426,16 @@ namespace swrenderer
MarkOpaquePassClip(start, stop); MarkOpaquePassClip(start, stop);
// save sprite clipping info bool needcliplists = draw_segment->HasFogBoundary() || draw_segment->HasTranslucentMidTexture() || draw_segment->Has3DFloorWalls();
if (((draw_segment->silhouette & SIL_TOP) || maskedtexture) && draw_segment->sprtopclip == nullptr)
if (((draw_segment->drawsegclip.silhouette & SIL_TOP) || needcliplists) && !draw_segment->drawsegclip.sprtopclip)
{ {
draw_segment->sprtopclip = Thread->FrameMemory->AllocMemory<short>(stop - start); draw_segment->drawsegclip.SetTopClip(Thread, start, stop, Thread->OpaquePass->ceilingclip);
memcpy(draw_segment->sprtopclip, &Thread->OpaquePass->ceilingclip[start], sizeof(short)*(stop - start));
} }
if (((draw_segment->silhouette & SIL_BOTTOM) || maskedtexture) && draw_segment->sprbottomclip == nullptr) if (((draw_segment->drawsegclip.silhouette & SIL_BOTTOM) || needcliplists) && !draw_segment->drawsegclip.sprbottomclip)
{ {
draw_segment->sprbottomclip = Thread->FrameMemory->AllocMemory<short>(stop - start); draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, Thread->OpaquePass->floorclip);
memcpy(draw_segment->sprbottomclip, &Thread->OpaquePass->floorclip[start], sizeof(short)*(stop - start));
}
if (maskedtexture && mLineSegment->sidedef->GetTexture(side_t::mid).isValid())
{
draw_segment->silhouette |= SIL_TOP | SIL_BOTTOM;
} }
RenderMiddleTexture(start, stop); RenderMiddleTexture(start, stop);
@ -499,7 +451,7 @@ namespace swrenderer
if (markportal) if (markportal)
{ {
Thread->Portal->AddLinePortal(mLineSegment->linedef, draw_segment->x1, draw_segment->x2, draw_segment->sprtopclip, draw_segment->sprbottomclip); Thread->Portal->AddLinePortal(mLineSegment->linedef, draw_segment->x1, draw_segment->x2, draw_segment->drawsegclip.sprtopclip, draw_segment->drawsegclip.sprbottomclip);
} }
return true; return true;
@ -685,9 +637,7 @@ namespace swrenderer
markfloor = ShouldMarkFloor(); markfloor = ShouldMarkFloor();
markceiling = ShouldMarkCeiling(); markceiling = ShouldMarkCeiling();
SetTopTexture(); SetTextures();
SetMiddleTexture();
SetBottomTexture();
if (mBackSector && !(sidedef == linedef->sidedef[0] && (linedef->special == Line_Mirror && r_drawmirrors))) if (mBackSector && !(sidedef == linedef->sidedef[0] && (linedef->special == Line_Mirror && r_drawmirrors)))
{ {
@ -715,7 +665,7 @@ namespace swrenderer
FTexture *ftex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true); FTexture *ftex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true);
FSoftwareTexture *midtex = ftex && ftex->isValid() ? ftex->GetSoftwareTexture() : nullptr; FSoftwareTexture *midtex = ftex && ftex->isValid() ? ftex->GetSoftwareTexture() : nullptr;
bool segtextured = ftex != NULL || mTopPart.Texture != NULL || mBottomPart.Texture != NULL; bool segtextured = ftex != NULL || mTopTexture != NULL || mBottomTexture != NULL;
if (m3DFloor.type == Fake3DOpaque::Normal) if (m3DFloor.type == Fake3DOpaque::Normal)
{ {
@ -725,201 +675,69 @@ namespace swrenderer
// calculate light table // calculate light table
if (segtextured || (mBackSector && IsFogBoundary(mFrontSector, mBackSector))) if (segtextured || (mBackSector && IsFogBoundary(mFrontSector, mBackSector)))
{ {
lwallscale =
ftex ? ((midtex? midtex->GetScale().X : 1.0) * sidedef->GetTextureXScale(side_t::mid)) :
mTopPart.Texture ? (mTopPart.Texture->GetScale().X * sidedef->GetTextureXScale(side_t::top)) :
mBottomPart.Texture ? (mBottomPart.Texture->GetScale().X * sidedef->GetTextureXScale(side_t::bottom)) :
1.;
walltexcoords.Project(Thread->Viewport.get(), sidedef->TexelLength * lwallscale, WallC.sx1, WallC.sx2, WallT);
mLight.SetLightLeft(Thread, WallC); mLight.SetLightLeft(Thread, WallC);
} }
} }
void SWRenderLine::SetTextures()
{
mTopTexture = nullptr;
mMiddleTexture = nullptr;
mBottomTexture = nullptr;
side_t* sidedef = mLineSegment->sidedef;
line_t* linedef = mLineSegment->linedef;
if (sidedef == linedef->sidedef[0] && (linedef->special == Line_Mirror && r_drawmirrors)) return;
if (!mBackSector)
{
SetMiddleTexture();
}
else
{
if (mFrontCeilingZ1 > mBackCeilingZ1 || mFrontCeilingZ2 > mBackCeilingZ2) SetTopTexture();
if (mFrontFloorZ1 < mBackFloorZ1 || mFrontFloorZ2 < mBackFloorZ2) SetBottomTexture();
}
}
void SWRenderLine::SetTopTexture() void SWRenderLine::SetTopTexture()
{ {
mTopPart.Texture = nullptr;
if (!(mFrontCeilingZ1 > mBackCeilingZ1 || mFrontCeilingZ2 > mBackCeilingZ2)) return;
side_t *sidedef = mLineSegment->sidedef; side_t *sidedef = mLineSegment->sidedef;
line_t *linedef = mLineSegment->linedef; line_t *linedef = mLineSegment->linedef;
if (sidedef == linedef->sidedef[0] && (linedef->special == Line_Mirror && r_drawmirrors)) return;
if (!mBackSector) return;
// No top texture for skyhack lines // No top texture for skyhack lines
if (mFrontSector->GetTexture(sector_t::ceiling) == skyflatnum && mBackSector->GetTexture(sector_t::ceiling) == skyflatnum) return; if (mFrontSector->GetTexture(sector_t::ceiling) == skyflatnum && mBackSector->GetTexture(sector_t::ceiling) == skyflatnum) return;
FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::top), true); FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::top), true);
mTopPart.Texture = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr; if (!tex || !tex->isValid()) return;
if (mTopPart.Texture == nullptr) return;
mTopPart.TextureOffsetU = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::top)); mTopTexture = tex->GetSoftwareTexture();
double rowoffset = sidedef->GetTextureYOffset(side_t::top);
mTopPart.TextureScaleU = sidedef->GetTextureXScale(side_t::top);
mTopPart.TextureScaleV = sidedef->GetTextureYScale(side_t::top);
double yrepeat = mTopPart.Texture->GetScale().Y * mTopPart.TextureScaleV;
if (yrepeat >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGTOP)
{ // top of texture at top
mTopPart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
if (rowoffset < 0 && mTopPart.Texture != NULL)
{
rowoffset += mTopPart.Texture->GetHeight();
}
}
else
{ // bottom of texture at bottom
mTopPart.TextureMid = (mBackSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + mTopPart.Texture->GetHeight();
}
}
else
{ // upside down
rowoffset = -rowoffset;
if (linedef->flags & ML_DONTPEGTOP)
{ // bottom of texture at top
mTopPart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + mTopPart.Texture->GetHeight();
}
else
{ // top of texture at bottom
mTopPart.TextureMid = (mBackSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
}
}
if (mTopPart.Texture->useWorldPanning(mLineSegment->GetLevel()))
{
mTopPart.TextureMid += rowoffset * yrepeat;
}
else
{
mTopPart.TextureMid += rowoffset;
}
} }
void SWRenderLine::SetMiddleTexture() void SWRenderLine::SetMiddleTexture()
{ {
mMiddlePart.Texture = nullptr;
side_t *sidedef = mLineSegment->sidedef; side_t *sidedef = mLineSegment->sidedef;
line_t *linedef = mLineSegment->linedef; line_t *linedef = mLineSegment->linedef;
if (sidedef == linedef->sidedef[0] && (linedef->special == Line_Mirror && r_drawmirrors)) return;
if (mBackSector) return;
// [RH] Horizon lines do not need to be textured // [RH] Horizon lines do not need to be textured
if (linedef->isVisualPortal()) return; if (linedef->isVisualPortal()) return;
if (linedef->special == Line_Horizon) return; if (linedef->special == Line_Horizon) return;
auto tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true); auto tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true);
mMiddlePart.Texture = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr; if (!tex || !tex->isValid()) return;
if (mMiddlePart.Texture == nullptr) return;
mMiddlePart.TextureOffsetU = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::mid)); mMiddleTexture = tex->GetSoftwareTexture();
double rowoffset = sidedef->GetTextureYOffset(side_t::mid);
mMiddlePart.TextureScaleU = sidedef->GetTextureXScale(side_t::mid);
mMiddlePart.TextureScaleV = sidedef->GetTextureYScale(side_t::mid);
double yrepeat = mMiddlePart.Texture->GetScale().Y * mMiddlePart.TextureScaleV;
if (yrepeat >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // bottom of texture at bottom
mMiddlePart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::floor) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + mMiddlePart.Texture->GetHeight();
}
else
{ // top of texture at top
mMiddlePart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
if (rowoffset < 0 && mMiddlePart.Texture != NULL)
{
rowoffset += mMiddlePart.Texture->GetHeight();
}
}
}
else
{ // upside down
rowoffset = -rowoffset;
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // top of texture at bottom
mMiddlePart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::floor) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
}
else
{ // bottom of texture at top
mMiddlePart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + mMiddlePart.Texture->GetHeight();
}
}
if (mMiddlePart.Texture->useWorldPanning(mLineSegment->GetLevel()))
{
mMiddlePart.TextureMid += rowoffset * yrepeat;
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
mMiddlePart.TextureMid += rowoffset;
}
} }
void SWRenderLine::SetBottomTexture() void SWRenderLine::SetBottomTexture()
{ {
mBottomPart.Texture = nullptr;
if (!(mFrontFloorZ1 < mBackFloorZ1 || mFrontFloorZ2 < mBackFloorZ2)) return;
side_t *sidedef = mLineSegment->sidedef; side_t *sidedef = mLineSegment->sidedef;
line_t *linedef = mLineSegment->linedef; line_t *linedef = mLineSegment->linedef;
if (sidedef == linedef->sidedef[0] && (linedef->special == Line_Mirror && r_drawmirrors)) return;
if (!mBackSector) return;
double frontlowertop = mFrontSector->GetPlaneTexZ(sector_t::ceiling);
if (mFrontSector->GetTexture(sector_t::ceiling) == skyflatnum && mBackSector->GetTexture(sector_t::ceiling) == skyflatnum)
{
// Putting sky ceilings on the front and back of a line alters the way unpegged
// positioning works.
frontlowertop = mBackSector->GetPlaneTexZ(sector_t::ceiling);
}
FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::bottom), true); FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::bottom), true);
mBottomPart.Texture = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr; if (!tex || !tex->isValid()) return;
if (!mBottomPart.Texture) return;
mBottomPart.TextureOffsetU = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::bottom)); mBottomTexture = tex->GetSoftwareTexture();
double rowoffset = sidedef->GetTextureYOffset(side_t::bottom);
mBottomPart.TextureScaleU = sidedef->GetTextureXScale(side_t::bottom);
mBottomPart.TextureScaleV = sidedef->GetTextureYScale(side_t::bottom);
double yrepeat = mBottomPart.Texture->GetScale().Y * mBottomPart.TextureScaleV;
if (yrepeat >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // bottom of texture at bottom
mBottomPart.TextureMid = (frontlowertop - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
}
else
{ // top of texture at top
mBottomPart.TextureMid = (mBackSector->GetPlaneTexZ(sector_t::floor) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
if (rowoffset < 0 && mBottomPart.Texture != NULL)
{
rowoffset += mBottomPart.Texture->GetHeight();
}
}
}
else
{ // upside down
rowoffset = -rowoffset;
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // top of texture at bottom
mBottomPart.TextureMid = (frontlowertop - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
}
else
{ // bottom of texture at top
mBottomPart.TextureMid = (mBackSector->GetPlaneTexZ(sector_t::floor) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + mBottomPart.Texture->GetHeight();
}
}
if (mBottomPart.Texture->useWorldPanning(mLineSegment->GetLevel()))
{
mBottomPart.TextureMid += rowoffset * yrepeat;
}
else
{
mBottomPart.TextureMid += rowoffset;
}
} }
bool SWRenderLine::IsFogBoundary(sector_t *front, sector_t *back) const bool SWRenderLine::IsFogBoundary(sector_t *front, sector_t *back) const
@ -1037,14 +855,14 @@ namespace swrenderer
auto ceilingclip = Thread->OpaquePass->ceilingclip; auto ceilingclip = Thread->OpaquePass->ceilingclip;
auto floorclip = Thread->OpaquePass->floorclip; auto floorclip = Thread->OpaquePass->floorclip;
if (mMiddlePart.Texture) // one sided line if (mMiddleTexture) // one sided line
{ {
fillshort(ceilingclip + x1, x2 - x1, viewheight); fillshort(ceilingclip + x1, x2 - x1, viewheight);
fillshort(floorclip + x1, x2 - x1, 0xffff); fillshort(floorclip + x1, x2 - x1, 0xffff);
} }
else else
{ // two sided line { // two sided line
if (mTopPart.Texture != nullptr) if (mTopTexture != nullptr)
{ // top wall { // top wall
for (int x = x1; x < x2; ++x) for (int x = x1; x < x2; ++x)
{ {
@ -1057,7 +875,7 @@ namespace swrenderer
memcpy(ceilingclip + x1, walltop.ScreenY + x1, (x2 - x1) * sizeof(short)); memcpy(ceilingclip + x1, walltop.ScreenY + x1, (x2 - x1) * sizeof(short));
} }
if (mBottomPart.Texture != nullptr) if (mBottomTexture != nullptr)
{ // bottom wall { // bottom wall
for (int x = x1; x < x2; ++x) for (int x = x1; x < x2; ++x)
{ {
@ -1074,97 +892,40 @@ namespace swrenderer
void SWRenderLine::RenderTopTexture(int x1, int x2) void SWRenderLine::RenderTopTexture(int x1, int x2)
{ {
if (mMiddlePart.Texture) return; if (mMiddleTexture) return;
if (!mTopPart.Texture) return; if (!mTopTexture) return;
if (!viewactive) return; if (!viewactive) return;
auto rw_pic = mTopPart.Texture; ProjectedWallTexcoords texcoords;
double xscale = rw_pic->GetScale().X * mTopPart.TextureScaleU; texcoords.ProjectTop(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, mTopTexture);
double yscale = rw_pic->GetScale().Y * mTopPart.TextureScaleV;
if (xscale != lwallscale)
{
walltexcoords.Project(Thread->Viewport.get(), mLineSegment->sidedef->TexelLength*xscale, WallC.sx1, WallC.sx2, WallT);
lwallscale = xscale;
}
fixed_t offset;
if (mTopPart.Texture->useWorldPanning(mLineSegment->GetLevel()))
{
offset = xs_RoundToInt(mTopPart.TextureOffsetU * xscale);
}
else
{
offset = mTopPart.TextureOffsetU;
}
if (xscale < 0)
{
offset = -offset;
}
RenderWallPart renderWallpart(Thread); RenderWallPart renderWallpart(Thread);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walltop.ScreenY, wallupper.ScreenY, mTopPart.TextureMid, walltexcoords, yscale, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mBackCeilingZ1, mBackCeilingZ2), false, false, OPAQUE, offset, mLight, GetLightList()); renderWallpart.Render(mFrontSector, mLineSegment, WallC, mTopTexture, x1, x2, walltop.ScreenY, wallupper.ScreenY, texcoords, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mBackCeilingZ1, mBackCeilingZ2), false, false, OPAQUE, mLight, GetLightList());
} }
void SWRenderLine::RenderMiddleTexture(int x1, int x2) void SWRenderLine::RenderMiddleTexture(int x1, int x2)
{ {
if (!mMiddlePart.Texture) return; if (!mMiddleTexture) return;
if (!viewactive) return; if (!viewactive) return;
auto rw_pic = mMiddlePart.Texture; ProjectedWallTexcoords texcoords;
double xscale = rw_pic->GetScale().X * mMiddlePart.TextureScaleU; texcoords.ProjectMid(Thread->Viewport.get(), mFrontSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, mMiddleTexture);
double yscale = rw_pic->GetScale().Y * mMiddlePart.TextureScaleV;
if (xscale != lwallscale)
{
walltexcoords.Project(Thread->Viewport.get(), mLineSegment->sidedef->TexelLength*xscale, WallC.sx1, WallC.sx2, WallT);
lwallscale = xscale;
}
fixed_t offset;
if (mMiddlePart.Texture->useWorldPanning(mLineSegment->GetLevel()))
{
offset = xs_RoundToInt(mMiddlePart.TextureOffsetU * xscale);
}
else
{
offset = mMiddlePart.TextureOffsetU;
}
if (xscale < 0)
{
offset = -offset;
}
RenderWallPart renderWallpart(Thread); RenderWallPart renderWallpart(Thread);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walltop.ScreenY, wallbottom.ScreenY, mMiddlePart.TextureMid, walltexcoords, yscale, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, false, OPAQUE, offset, mLight, GetLightList()); renderWallpart.Render(mFrontSector, mLineSegment, WallC, mMiddleTexture, x1, x2, walltop.ScreenY, wallbottom.ScreenY, texcoords, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, false, OPAQUE, mLight, GetLightList());
} }
void SWRenderLine::RenderBottomTexture(int x1, int x2) void SWRenderLine::RenderBottomTexture(int x1, int x2)
{ {
if (mMiddlePart.Texture) return; if (mMiddleTexture) return;
if (!mBottomPart.Texture) return; if (!mBottomTexture) return;
if (!viewactive) return; if (!viewactive) return;
auto rw_pic = mBottomPart.Texture; ProjectedWallTexcoords texcoords;
double xscale = rw_pic->GetScale().X * mBottomPart.TextureScaleU; texcoords.ProjectBottom(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC.sx1, WallC.sx2, WallT, mBottomTexture);
double yscale = rw_pic->GetScale().Y * mBottomPart.TextureScaleV;
if (xscale != lwallscale)
{
walltexcoords.Project(Thread->Viewport.get(), mLineSegment->sidedef->TexelLength*xscale, WallC.sx1, WallC.sx2, WallT);
lwallscale = xscale;
}
fixed_t offset;
if (mBottomPart.Texture->useWorldPanning(mLineSegment->GetLevel()))
{
offset = xs_RoundToInt(mBottomPart.TextureOffsetU * xscale);
}
else
{
offset = mBottomPart.TextureOffsetU;
}
if (xscale < 0)
{
offset = -offset;
}
RenderWallPart renderWallpart(Thread); RenderWallPart renderWallpart(Thread);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walllower.ScreenY, wallbottom.ScreenY, mBottomPart.TextureMid, walltexcoords, yscale, MAX(mBackFloorZ1, mBackFloorZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, false, OPAQUE, offset, mLight, GetLightList()); renderWallpart.Render(mFrontSector, mLineSegment, WallC, mBottomTexture, x1, x2, walllower.ScreenY, wallbottom.ScreenY, texcoords, MAX(mBackFloorZ1, mBackFloorZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, false, OPAQUE, mLight, GetLightList());
} }
FLightNode *SWRenderLine::GetLightList() FLightNode *SWRenderLine::GetLightList()
@ -1253,48 +1014,4 @@ namespace swrenderer
return sx2 <= sx1; return sx2 <= sx1;
} }
/////////////////////////////////////////////////////////////////////////
void FWallTmapVals::InitFromWallCoords(RenderThread *thread, const FWallCoords *wallc)
{
const FVector2 *left = &wallc->tleft;
const FVector2 *right = &wallc->tright;
RenderPortal *renderportal = thread->Portal.get();
if (renderportal->MirrorFlags & RF_XFLIP)
{
swapvalues(left, right);
}
UoverZorg = left->X * thread->Viewport->CenterX;
UoverZstep = -left->Y;
InvZorg = (left->X - right->X) * thread->Viewport->CenterX;
InvZstep = right->Y - left->Y;
}
void FWallTmapVals::InitFromLine(RenderThread *thread, const DVector2 &left, const DVector2 &right)
{
// Coordinates should have already had viewx,viewy subtracted
auto viewport = thread->Viewport.get();
double fullx1 = left.X * viewport->viewpoint.Sin - left.Y * viewport->viewpoint.Cos;
double fullx2 = right.X * viewport->viewpoint.Sin - right.Y * viewport->viewpoint.Cos;
double fully1 = left.X * viewport->viewpoint.TanCos + left.Y * viewport->viewpoint.TanSin;
double fully2 = right.X * viewport->viewpoint.TanCos + right.Y * viewport->viewpoint.TanSin;
RenderPortal *renderportal = thread->Portal.get();
if (renderportal->MirrorFlags & RF_XFLIP)
{
fullx1 = -fullx1;
fullx2 = -fullx2;
}
UoverZorg = float(fullx1 * viewport->CenterX);
UoverZstep = float(-fully1);
InvZorg = float((fullx1 - fullx2) * viewport->CenterX);
InvZstep = float(fully2 - fully1);
}
} }

View file

@ -50,24 +50,6 @@ namespace swrenderer
bool Init(RenderThread *thread, const DVector2 &pt1, const DVector2 &pt2, double too_close); bool Init(RenderThread *thread, const DVector2 &pt1, const DVector2 &pt2, double too_close);
}; };
struct FWallTmapVals
{
float UoverZorg, UoverZstep;
float InvZorg, InvZstep;
void InitFromWallCoords(RenderThread *thread, const FWallCoords *wallc);
void InitFromLine(RenderThread *thread, const DVector2 &left, const DVector2 &right);
};
struct WallPartTexture
{
fixed_t TextureOffsetU;
double TextureMid;
double TextureScaleU;
double TextureScaleV;
FSoftwareTexture *Texture;
};
class SWRenderLine : VisibleSegmentRenderer class SWRenderLine : VisibleSegmentRenderer
{ {
public: public:
@ -79,6 +61,7 @@ namespace swrenderer
private: private:
bool RenderWallSegment(int x1, int x2) override; bool RenderWallSegment(int x1, int x2) override;
void SetWallVariables(); void SetWallVariables();
void SetTextures();
void SetTopTexture(); void SetTopTexture();
void SetMiddleTexture(); void SetMiddleTexture();
void SetBottomTexture(); void SetBottomTexture();
@ -134,14 +117,12 @@ namespace swrenderer
ProjectedWallLight mLight; ProjectedWallLight mLight;
double lwallscale;
bool markfloor; // False if the back side is the same plane. bool markfloor; // False if the back side is the same plane.
bool markceiling; bool markceiling;
WallPartTexture mTopPart; FSoftwareTexture* mTopTexture;
WallPartTexture mMiddlePart; FSoftwareTexture* mMiddleTexture;
WallPartTexture mBottomPart; FSoftwareTexture* mBottomTexture;
ProjectedWallCull mCeilingClipped; ProjectedWallCull mCeilingClipped;
ProjectedWallCull mFloorClipped; ProjectedWallCull mFloorClipped;
@ -150,7 +131,6 @@ namespace swrenderer
ProjectedWallLine wallbottom; ProjectedWallLine wallbottom;
ProjectedWallLine wallupper; ProjectedWallLine wallupper;
ProjectedWallLine walllower; ProjectedWallLine walllower;
ProjectedWallTexcoords walltexcoords;
sector_t tempsec; // killough 3/8/98: ceiling/water hack sector_t tempsec; // killough 3/8/98: ceiling/water hack
}; };

View file

@ -54,8 +54,6 @@
#include "swrenderer/viewport/r_viewport.h" #include "swrenderer/viewport/r_viewport.h"
#include "swrenderer/viewport/r_spritedrawer.h" #include "swrenderer/viewport/r_spritedrawer.h"
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
namespace swrenderer namespace swrenderer
{ {
RenderDrawSegment::RenderDrawSegment(RenderThread *thread) RenderDrawSegment::RenderDrawSegment(RenderThread *thread)
@ -92,52 +90,33 @@ namespace swrenderer
} }
} }
float alpha = (float)MIN(curline->linedef->alpha, 1.); if (!ds->HasTranslucentMidTexture() && !ds->HasFogBoundary() && !ds->Has3DFloorWalls())
bool additive = (curline->linedef->flags & ML_ADDTRANS) != 0;
SpriteDrawerArgs columndrawerargs;
ColormapLight cmlight;
cmlight.SetColormap(Thread, MINZ, mLight.GetLightLevel(), mLight.GetFoggy(), mLight.GetBaseColormap(), false, false, false, false, false);
bool visible = columndrawerargs.SetStyle(viewport, LegacyRenderStyles[additive ? STYLE_Add : STYLE_Translucent], alpha, 0, 0, cmlight);
if (!visible && !ds->bFogBoundary && !ds->Has3DFloorWalls())
{ {
return; return;
} }
// [RH] Draw fog partition if (ds->HasFogBoundary())
bool renderwall = true;
bool notrelevant = false;
if (ds->bFogBoundary)
{ {
const short *mfloorclip = ds->sprbottomclip - ds->x1;
const short *mceilingclip = ds->sprtopclip - ds->x1;
RenderFogBoundary renderfog; RenderFogBoundary renderfog;
renderfog.Render(Thread, x1, x2, mceilingclip, mfloorclip, mLight); renderfog.Render(Thread, x1, x2, ds->drawsegclip, mLight);
if (!ds->texcoords)
renderwall = false;
} }
else if ((ds->Has3DFloorWalls() && !ds->Has3DFloorMidTexture()) || !visible)
bool notrelevant = false;
if (ds->HasTranslucentMidTexture())
notrelevant = RenderWall(ds, x1, x2);
if (ds->Has3DFloorWalls())
{ {
renderwall = false; Render3DFloorWallRange(ds, x1, x2);
} }
if (renderwall)
notrelevant = RenderWall(ds, x1, x2, columndrawerargs, visible);
if (ds->Has3DFloorFrontSectorWalls() || ds->Has3DFloorBackSectorWalls())
{
RenderFakeWallRange(ds, x1, x2);
}
if (!notrelevant) if (!notrelevant)
{ {
ds->sprclipped = true; ds->drawsegclip.SetRangeDrawn(x1, x2);
fillshort(ds->sprtopclip - ds->x1 + x1, x2 - x1, viewheight);
} }
} }
bool RenderDrawSegment::RenderWall(DrawSegment *ds, int x1, int x2, SpriteDrawerArgs &columndrawerargs, bool visible) bool RenderDrawSegment::RenderWall(DrawSegment *ds, int x1, int x2)
{ {
auto renderstyle = DefaultRenderStyle(); auto renderstyle = DefaultRenderStyle();
auto viewport = Thread->Viewport.get(); auto viewport = Thread->Viewport.get();
@ -153,63 +132,24 @@ namespace swrenderer
} }
FSoftwareTexture *tex = ttex->GetSoftwareTexture(); FSoftwareTexture *tex = ttex->GetSoftwareTexture();
const short *mfloorclip = ds->sprbottomclip - ds->x1; const short *mfloorclip = ds->drawsegclip.sprbottomclip;
const short *mceilingclip = ds->sprtopclip - ds->x1; const short *mceilingclip = ds->drawsegclip.sprtopclip;
float MaskedScaleY = ds->texcoords.yscale;
// find positioning
double texheight = tex->GetScaledHeightDouble();
double texheightscale = fabs(curline->sidedef->GetTextureYScale(side_t::mid));
if (texheightscale != 1)
{
texheight = texheight / texheightscale;
}
double texturemid;
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
{
texturemid = MAX(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor)) + texheight;
}
else
{
texturemid = MIN(frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling));
}
double rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid);
bool wrap = (curline->linedef->flags & ML_WRAP_MIDTEX) || (curline->sidedef->Flags & WALLF_WRAP_MIDTEX); bool wrap = (curline->linedef->flags & ML_WRAP_MIDTEX) || (curline->sidedef->Flags & WALLF_WRAP_MIDTEX);
if (!wrap) if (!wrap)
{ // Texture does not wrap vertically. { // Texture does not wrap vertically.
double textop;
bool sprflipvert = false; // find positioning
double texheight = tex->GetScaledHeightDouble() / fabs(curline->sidedef->GetTextureYScale(side_t::mid));
if (MaskedScaleY < 0) double texturemid;
{ if (curline->linedef->flags & ML_DONTPEGBOTTOM)
MaskedScaleY = -MaskedScaleY; texturemid = MAX(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor)) + texheight;
sprflipvert = true;
}
if (tex->useWorldPanning(curline->GetLevel()))
{
// rowoffset is added before the multiply so that the masked texture will
// still be positioned in world units rather than texels.
texturemid += rowoffset - Thread->Viewport->viewpoint.Pos.Z;
textop = texturemid;
texturemid *= MaskedScaleY;
}
else else
{ texturemid = MIN(frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling));
// rowoffset is added outside the multiply so that it positions the texture double rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid);
// by texels instead of world units. if (tex->useWorldPanning(curline->GetLevel()))
textop = texturemid + rowoffset / MaskedScaleY - Thread->Viewport->viewpoint.Pos.Z; rowoffset /= fabs(tex->GetScale().Y * curline->sidedef->GetTextureYScale(side_t::mid));
texturemid = (texturemid - Thread->Viewport->viewpoint.Pos.Z) * MaskedScaleY + rowoffset; double textop = texturemid + rowoffset - Thread->Viewport->viewpoint.Pos.Z;
}
if (sprflipvert)
{
MaskedScaleY = -MaskedScaleY;
texturemid -= tex->GetHeight() << FRACBITS;
}
// [RH] Don't bother drawing segs that are completely offscreen // [RH] Don't bother drawing segs that are completely offscreen
if (viewport->globaldclip * ds->WallC.sz1 < -textop && viewport->globaldclip * ds->WallC.sz2 < -textop) if (viewport->globaldclip * ds->WallC.sz1 < -textop && viewport->globaldclip * ds->WallC.sz2 < -textop)
@ -231,11 +171,6 @@ namespace swrenderer
return true; return true;
} }
WallC.sz1 = ds->WallC.sz1;
WallC.sz2 = ds->WallC.sz2;
WallC.sx1 = ds->WallC.sx1;
WallC.sx2 = ds->WallC.sx2;
// Unclipped vanilla Doom range for the wall. Relies on ceiling/floor clip to clamp the wall in range. // Unclipped vanilla Doom range for the wall. Relies on ceiling/floor clip to clamp the wall in range.
double ceilZ = textop; double ceilZ = textop;
double floorZ = textop - texheight; double floorZ = textop - texheight;
@ -267,19 +202,11 @@ namespace swrenderer
floorZ = MAX(floorZ, clipZ); floorZ = MAX(floorZ, clipZ);
} }
wallupper.Project(Thread->Viewport.get(), ceilZ, &WallC); wallupper.Project(Thread->Viewport.get(), ceilZ, &ds->WallC);
walllower.Project(Thread->Viewport.get(), floorZ, &WallC); walllower.Project(Thread->Viewport.get(), floorZ, &ds->WallC);
for (int i = x1; i < x2; i++) wallupper.ClipTop(x1, x2, ds->drawsegclip);
{ walllower.ClipBottom(x1, x2, ds->drawsegclip);
if (wallupper.ScreenY[i] < mceilingclip[i])
wallupper.ScreenY[i] = mceilingclip[i];
}
for (int i = x1; i < x2; i++)
{
if (walllower.ScreenY[i] > mfloorclip[i])
walllower.ScreenY[i] = mfloorclip[i];
}
if (clip3d->CurrentSkybox) if (clip3d->CurrentSkybox)
{ // Midtex clipping doesn't work properly with skyboxes, since you're normally below the floor { // Midtex clipping doesn't work properly with skyboxes, since you're normally below the floor
@ -289,52 +216,15 @@ namespace swrenderer
(curline->sidedef->Flags & WALLF_CLIP_MIDTEX) || (curline->sidedef->Flags & WALLF_CLIP_MIDTEX) ||
(curline->GetLevel()->ib_compatflags & BCOMPATF_CLIPMIDTEX)) (curline->GetLevel()->ib_compatflags & BCOMPATF_CLIPMIDTEX))
{ {
ClipMidtex(x1, x2); ClipMidtex(ds, x1, x2);
} }
} }
mfloorclip = walllower.ScreenY; mfloorclip = walllower.ScreenY;
mceilingclip = wallupper.ScreenY; mceilingclip = wallupper.ScreenY;
auto cameraLight = CameraLight::Instance();
bool needslight = (cameraLight->FixedColormap() == nullptr && cameraLight->FixedLightLevel() < 0);
// draw the columns one at a time
if (visible)
{
Thread->PrepareTexture(tex, renderstyle);
float lightpos = mLight.GetLightPos(x1);
for (int x = x1; x < x2; ++x)
{
if (needslight)
{
columndrawerargs.SetLight(lightpos, mLight.GetLightLevel(), mLight.GetFoggy(), Thread->Viewport.get());
lightpos += mLight.GetLightStep();
}
columndrawerargs.DrawMaskedColumn(Thread, x, tex, ds->texcoords, texturemid, MaskedScaleY, sprflipvert, mfloorclip, mceilingclip, renderstyle);
}
}
} }
else else
{ // Texture does wrap vertically. { // Texture does wrap vertically.
if (tex->useWorldPanning(curline->GetLevel()))
{
// rowoffset is added before the multiply so that the masked texture will
// still be positioned in world units rather than texels.
texturemid = (texturemid - Thread->Viewport->viewpoint.Pos.Z + rowoffset) * MaskedScaleY;
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
texturemid = (texturemid - Thread->Viewport->viewpoint.Pos.Z) * MaskedScaleY + rowoffset;
}
WallC.sz1 = ds->WallC.sz1;
WallC.sz2 = ds->WallC.sz2;
WallC.sx1 = ds->WallC.sx1;
WallC.sx2 = ds->WallC.sx2;
if (clip3d->CurrentSkybox) if (clip3d->CurrentSkybox)
{ // Midtex clipping doesn't work properly with skyboxes, since you're normally below the floor { // Midtex clipping doesn't work properly with skyboxes, since you're normally below the floor
@ -344,13 +234,13 @@ namespace swrenderer
(curline->sidedef->Flags & WALLF_CLIP_MIDTEX) || (curline->sidedef->Flags & WALLF_CLIP_MIDTEX) ||
(curline->GetLevel()->ib_compatflags & BCOMPATF_CLIPMIDTEX)) (curline->GetLevel()->ib_compatflags & BCOMPATF_CLIPMIDTEX))
{ {
ClipMidtex(x1, x2); ClipMidtex(ds, x1, x2);
} }
} }
if (m3DFloor.clipTop) if (m3DFloor.clipTop)
{ {
wallupper.Project(Thread->Viewport.get(), m3DFloor.sclipTop - Thread->Viewport->viewpoint.Pos.Z, &WallC); wallupper.Project(Thread->Viewport.get(), m3DFloor.sclipTop - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
for (int i = x1; i < x2; i++) for (int i = x1; i < x2; i++)
{ {
if (wallupper.ScreenY[i] < mceilingclip[i]) if (wallupper.ScreenY[i] < mceilingclip[i])
@ -360,7 +250,7 @@ namespace swrenderer
} }
if (m3DFloor.clipBottom) if (m3DFloor.clipBottom)
{ {
walllower.Project(Thread->Viewport.get(), m3DFloor.sclipBottom - Thread->Viewport->viewpoint.Pos.Z, &WallC); walllower.Project(Thread->Viewport.get(), m3DFloor.sclipBottom - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
for (int i = x1; i < x2; i++) for (int i = x1; i < x2; i++)
{ {
if (walllower.ScreenY[i] > mfloorclip[i]) if (walllower.ScreenY[i] > mfloorclip[i])
@ -368,9 +258,7 @@ namespace swrenderer
} }
mfloorclip = walllower.ScreenY; mfloorclip = walllower.ScreenY;
} }
}
rw_offset = 0;
FSoftwareTexture *rw_pic = tex;
double top, bot; double top, bot;
GetMaskedWallTopBottom(ds, top, bot); GetMaskedWallTopBottom(ds, top, bot);
@ -379,104 +267,39 @@ namespace swrenderer
bool additive = (curline->linedef->flags & ML_ADDTRANS) != 0; bool additive = (curline->linedef->flags & ML_ADDTRANS) != 0;
RenderWallPart renderWallpart(Thread); RenderWallPart renderWallpart(Thread);
renderWallpart.Render(frontsector, curline, WallC, rw_pic, x1, x2, mceilingclip, mfloorclip, texturemid, ds->texcoords, ds->texcoords.yscale, top, bot, true, additive, alpha, rw_offset, mLight, nullptr); renderWallpart.Render(frontsector, curline, ds->WallC, tex, x1, x2, mceilingclip, mfloorclip, ds->texcoords, top, bot, true, additive, alpha, mLight, nullptr);
}
return false; return false;
} }
// kg3D - render one fake wall void RenderDrawSegment::Render3DFloorWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, double clipTop, double clipBottom, FSoftwareTexture *rw_pic)
void RenderDrawSegment::RenderFakeWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, double clipTop, double clipBottom, FSoftwareTexture *rw_pic)
{ {
int i;
double xscale;
double yscale;
fixed_t Alpha = Scale(rover->alpha, OPAQUE, 255); fixed_t Alpha = Scale(rover->alpha, OPAQUE, 255);
if (Alpha <= 0) if (Alpha <= 0)
return; return;
mLight.SetLightLeft(ds->light, ds->lightstep, ds->x1); mLight.SetLightLeft(ds->light, ds->lightstep, ds->x1);
const short *mfloorclip = ds->sprbottomclip - ds->x1;
const short *mceilingclip = ds->sprtopclip - ds->x1;
// find positioning
side_t *scaledside;
side_t::ETexpart scaledpart;
if (rover->flags & FF_UPPERTEXTURE)
{
scaledside = curline->sidedef;
scaledpart = side_t::top;
}
else if (rover->flags & FF_LOWERTEXTURE)
{
scaledside = curline->sidedef;
scaledpart = side_t::bottom;
}
else
{
scaledside = rover->master->sidedef[0];
scaledpart = side_t::mid;
}
xscale = rw_pic->GetScale().X * scaledside->GetTextureXScale(scaledpart);
yscale = rw_pic->GetScale().Y * scaledside->GetTextureYScale(scaledpart);
double rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureYOffset(side_t::mid);
double planez = rover->model->GetPlaneTexZ(sector_t::ceiling);
rw_offset = FLOAT2FIXED(curline->sidedef->GetTextureXOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureXOffset(side_t::mid));
if (rowoffset < 0)
{
rowoffset += rw_pic->GetHeight();
}
double texturemid = (planez - Thread->Viewport->viewpoint.Pos.Z) * yscale;
if (rw_pic->useWorldPanning(curline->GetLevel()))
{
// rowoffset is added before the multiply so that the masked texture will
// still be positioned in world units rather than texels.
texturemid = texturemid + rowoffset * yscale;
rw_offset = xs_RoundToInt(rw_offset * xscale);
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
texturemid += rowoffset;
}
WallC = ds->WallC;
WallT = ds->tmapvals;
Clip3DFloors *clip3d = Thread->Clip3D.get(); Clip3DFloors *clip3d = Thread->Clip3D.get();
wallupper.Project(Thread->Viewport.get(), clipTop - Thread->Viewport->viewpoint.Pos.Z, &WallC); wallupper.Project(Thread->Viewport.get(), clipTop - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
walllower.Project(Thread->Viewport.get(), clipBottom - Thread->Viewport->viewpoint.Pos.Z, &WallC); walllower.Project(Thread->Viewport.get(), clipBottom - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
for (i = x1; i < x2; i++) wallupper.ClipTop(x1, x2, ds->drawsegclip);
{ walllower.ClipBottom(x1, x2, ds->drawsegclip);
if (wallupper.ScreenY[i] < mceilingclip[i])
wallupper.ScreenY[i] = mceilingclip[i];
}
for (i = x1; i < x2; i++)
{
if (walllower.ScreenY[i] > mfloorclip[i])
walllower.ScreenY[i] = mfloorclip[i];
}
ProjectedWallTexcoords walltexcoords; ProjectedWallTexcoords walltexcoords;
walltexcoords.Project(Thread->Viewport.get(), curline->sidedef->TexelLength*xscale, ds->WallC.sx1, ds->WallC.sx2, WallT); walltexcoords.Project3DFloor(Thread->Viewport.get(), rover, curline, ds->WallC.sx1, ds->WallC.sx2, ds->tmapvals, rw_pic);
double top, bot; double top, bot;
GetMaskedWallTopBottom(ds, top, bot); GetMaskedWallTopBottom(ds, top, bot);
RenderWallPart renderWallpart(Thread); RenderWallPart renderWallpart(Thread);
renderWallpart.Render(frontsector, curline, WallC, rw_pic, x1, x2, wallupper.ScreenY, walllower.ScreenY, texturemid, walltexcoords, yscale, top, bot, true, (rover->flags & FF_ADDITIVETRANS) != 0, Alpha, rw_offset, mLight, nullptr); renderWallpart.Render(frontsector, curline, ds->WallC, rw_pic, x1, x2, wallupper.ScreenY, walllower.ScreenY, walltexcoords, top, bot, true, (rover->flags & FF_ADDITIVETRANS) != 0, Alpha, mLight, nullptr);
RenderDecal::RenderDecals(Thread, curline->sidedef, ds, curline, mLight, wallupper.ScreenY, walllower.ScreenY, true); RenderDecal::RenderDecals(Thread, curline->sidedef, ds, curline, mLight, wallupper.ScreenY, walllower.ScreenY, true);
} }
// kg3D - walls of fake floors void RenderDrawSegment::Render3DFloorWallRange(DrawSegment *ds, int x1, int x2)
void RenderDrawSegment::RenderFakeWallRange(DrawSegment *ds, int x1, int x2)
{ {
int i, j; int i, j;
F3DFloor *rover, *fover = nullptr; F3DFloor *rover, *fover = nullptr;
@ -699,7 +522,7 @@ namespace swrenderer
//mLight.lightlevel = ds->lightlevel; //mLight.lightlevel = ds->lightlevel;
mLight.SetColormap(frontsector, curline, lit); mLight.SetColormap(frontsector, curline, lit);
RenderFakeWall(ds, x1, x2, fover ? fover : rover, clipTop, clipBottom, rw_pic); Render3DFloorWall(ds, x1, x2, fover ? fover : rover, clipTop, clipBottom, rw_pic);
} }
break; break;
} }
@ -881,7 +704,7 @@ namespace swrenderer
//mLight.lightlevel = ds->lightlevel; //mLight.lightlevel = ds->lightlevel;
mLight.SetColormap(frontsector, curline, lit); mLight.SetColormap(frontsector, curline, lit);
RenderFakeWall(ds, x1, x2, fover ? fover : rover, clipTop, clipBottom, rw_pic); Render3DFloorWall(ds, x1, x2, fover ? fover : rover, clipTop, clipBottom, rw_pic);
} }
break; break;
} }
@ -889,19 +712,19 @@ namespace swrenderer
} }
// Clip a midtexture to the floor and ceiling of the sector in front of it. // Clip a midtexture to the floor and ceiling of the sector in front of it.
void RenderDrawSegment::ClipMidtex(int x1, int x2) void RenderDrawSegment::ClipMidtex(DrawSegment* ds, int x1, int x2)
{ {
ProjectedWallLine most; ProjectedWallLine most;
RenderPortal *renderportal = Thread->Portal.get(); RenderPortal *renderportal = Thread->Portal.get();
most.Project(Thread->Viewport.get(), curline->frontsector->ceilingplane, &WallC, curline, renderportal->MirrorFlags & RF_XFLIP); most.Project(Thread->Viewport.get(), curline->frontsector->ceilingplane, &ds->WallC, curline, renderportal->MirrorFlags & RF_XFLIP);
for (int i = x1; i < x2; ++i) for (int i = x1; i < x2; ++i)
{ {
if (wallupper.ScreenY[i] < most.ScreenY[i]) if (wallupper.ScreenY[i] < most.ScreenY[i])
wallupper.ScreenY[i] = most.ScreenY[i]; wallupper.ScreenY[i] = most.ScreenY[i];
} }
most.Project(Thread->Viewport.get(), curline->frontsector->floorplane, &WallC, curline, renderportal->MirrorFlags & RF_XFLIP); most.Project(Thread->Viewport.get(), curline->frontsector->floorplane, &ds->WallC, curline, renderportal->MirrorFlags & RF_XFLIP);
for (int i = x1; i < x2; ++i) for (int i = x1; i < x2; ++i)
{ {
if (walllower.ScreenY[i] > most.ScreenY[i]) if (walllower.ScreenY[i] > most.ScreenY[i])

View file

@ -37,10 +37,10 @@ namespace swrenderer
RenderThread *Thread = nullptr; RenderThread *Thread = nullptr;
private: private:
bool RenderWall(DrawSegment *ds, int x1, int x2, SpriteDrawerArgs &columndrawerargs, bool visible); bool RenderWall(DrawSegment *ds, int x1, int x2);
void ClipMidtex(int x1, int x2); void ClipMidtex(DrawSegment* ds, int x1, int x2);
void RenderFakeWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, double clipTop, double clipBottom, FSoftwareTexture *rw_pic); void Render3DFloorWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, double clipTop, double clipBottom, FSoftwareTexture *rw_pic);
void RenderFakeWallRange(DrawSegment *ds, int x1, int x2); void Render3DFloorWallRange(DrawSegment *ds, int x1, int x2);
void GetMaskedWallTopBottom(DrawSegment *ds, double &top, double &bot); void GetMaskedWallTopBottom(DrawSegment *ds, double &top, double &bot);
sector_t *frontsector = nullptr; sector_t *frontsector = nullptr;
@ -49,13 +49,8 @@ namespace swrenderer
seg_t *curline = nullptr; seg_t *curline = nullptr;
Fake3DTranslucent m3DFloor; Fake3DTranslucent m3DFloor;
FWallCoords WallC;
FWallTmapVals WallT;
ProjectedWallLight mLight; ProjectedWallLight mLight;
fixed_t rw_offset = 0;
ProjectedWallLine wallupper; ProjectedWallLine wallupper;
ProjectedWallLine walllower; ProjectedWallLine walllower;
}; };

View file

@ -54,7 +54,7 @@
namespace swrenderer namespace swrenderer
{ {
void RenderWallPart::ProcessNormalWall(const short *uwal, const short *dwal, double texturemid, const float *swal, const fixed_t *lwal) void RenderWallPart::ProcessNormalWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords)
{ {
if (rw_pic == nullptr) if (rw_pic == nullptr)
return; return;
@ -63,8 +63,6 @@ namespace swrenderer
if (fracbits == 32) if (fracbits == 32)
{ // Hack for one pixel tall textures { // Hack for one pixel tall textures
fracbits = 0; fracbits = 0;
yrepeat = 0;
texturemid = 0;
} }
WallDrawerArgs drawerargs; WallDrawerArgs drawerargs;
@ -114,13 +112,13 @@ namespace swrenderer
if (!fixed) if (!fixed)
drawerargs.SetLight(curlight, mLight.GetLightLevel(), mLight.GetFoggy(), viewport); drawerargs.SetLight(curlight, mLight.GetLightLevel(), mLight.GetFoggy(), viewport);
if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(lwal[x + 1]) - FIXED2DBL(lwal[x])); if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(texcoords.UPos(x + 1)) - FIXED2DBL(texcoords.UPos(x)));
fixed_t xxoffset = (lwal[x] + xoffset + FLOAT2FIXED(xmagnitude * 0.5)) * rw_pic->GetPhysicalScale(); fixed_t xxoffset = (texcoords.UPos(x) + FLOAT2FIXED(xmagnitude * 0.5)) * rw_pic->GetPhysicalScale();
// Normalize to 0-1 range: // Normalize to 0-1 range:
double uv_stepd = swal[x] * yrepeat; double uv_stepd = texcoords.VStep(x) * texcoords.yscale;
double v = (texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / rw_pic->GetHeight(); double v = (texcoords.texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / rw_pic->GetHeight();
v = v - floor(v); v = v - floor(v);
double v_step = uv_stepd / rw_pic->GetHeight(); double v_step = uv_stepd / rw_pic->GetHeight();
@ -227,19 +225,19 @@ namespace swrenderer
if (!fixed) if (!fixed)
drawerargs.SetLight(curlight, mLight.GetLightLevel(), mLight.GetFoggy(), viewport); drawerargs.SetLight(curlight, mLight.GetLightLevel(), mLight.GetFoggy(), viewport);
if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(lwal[x + 1]) - FIXED2DBL(lwal[x])); if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(texcoords.UPos(x + 1)) - FIXED2DBL(texcoords.UPos(x)));
uint32_t uv_pos; uint32_t uv_pos;
uint32_t uv_step; uint32_t uv_step;
fixed_t xxoffset = (lwal[x] + xoffset + FLOAT2FIXED(xmagnitude * 0.5)) * rw_pic->GetPhysicalScale(); fixed_t xxoffset = (texcoords.UPos(x) + FLOAT2FIXED(xmagnitude * 0.5)) * rw_pic->GetPhysicalScale();
if (uv_fracbits != 32) if (uv_fracbits != 32)
{ {
// Find start uv in [0-base_height[ range. // Find start uv in [0-base_height[ range.
// Not using xs_ToFixed because it rounds the result and we need something that always rounds down to stay within the range. // Not using xs_ToFixed because it rounds the result and we need something that always rounds down to stay within the range.
double uv_stepd = swal[x] * yrepeat; double uv_stepd = texcoords.VStep(x) * texcoords.yscale;
double v = (texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / rw_pic->GetHeight(); double v = (texcoords.texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / rw_pic->GetHeight();
v = v - floor(v); v = v - floor(v);
v *= height; v *= height;
v *= (1 << uv_fracbits); v *= (1 << uv_fracbits);
@ -410,7 +408,7 @@ namespace swrenderer
} }
} }
void RenderWallPart::ProcessStripedWall(const short *uwal, const short *dwal, double texturemid, const float *swal, const fixed_t *lwal) void RenderWallPart::ProcessStripedWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords)
{ {
ProjectedWallLine most1, most2, most3; ProjectedWallLine most1, most2, most3;
const short *up; const short *up;
@ -434,7 +432,7 @@ namespace swrenderer
{ {
down[j] = clamp(most3.ScreenY[j], up[j], dwal[j]); down[j] = clamp(most3.ScreenY[j], up[j], dwal[j]);
} }
ProcessNormalWall(up, down, texturemid, swal, lwal); ProcessNormalWall(up, down, texcoords);
up = down; up = down;
down = (down == most1.ScreenY) ? most2.ScreenY : most1.ScreenY; down = (down == most1.ScreenY) ? most2.ScreenY : most1.ScreenY;
} }
@ -442,19 +440,19 @@ namespace swrenderer
mLight.SetColormap(frontsector, curline, &frontsector->e->XFloor.lightlist[i]); mLight.SetColormap(frontsector, curline, &frontsector->e->XFloor.lightlist[i]);
} }
ProcessNormalWall(up, dwal, texturemid, swal, lwal); ProcessNormalWall(up, dwal, texcoords);
} }
void RenderWallPart::ProcessWall(const short *uwal, const short *dwal, double texturemid, const float *swal, const fixed_t *lwal) void RenderWallPart::ProcessWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords)
{ {
CameraLight *cameraLight = CameraLight::Instance(); CameraLight *cameraLight = CameraLight::Instance();
if (cameraLight->FixedColormap() != NULL || cameraLight->FixedLightLevel() >= 0 || !(frontsector->e && frontsector->e->XFloor.lightlist.Size())) if (cameraLight->FixedColormap() != NULL || cameraLight->FixedLightLevel() >= 0 || !(frontsector->e && frontsector->e->XFloor.lightlist.Size()))
{ {
ProcessNormalWall(uwal, dwal, texturemid, swal, lwal); ProcessNormalWall(uwal, dwal, texcoords);
} }
else else
{ {
ProcessStripedWall(uwal, dwal, texturemid, swal, lwal); ProcessStripedWall(uwal, dwal, texcoords);
} }
} }
@ -469,23 +467,23 @@ namespace swrenderer
// //
//============================================================================= //=============================================================================
void RenderWallPart::ProcessWallNP2(const short *uwal, const short *dwal, double texturemid, const float *swal, const fixed_t *lwal, double top, double bot) void RenderWallPart::ProcessWallNP2(const short *uwal, const short *dwal, ProjectedWallTexcoords texcoords, double top, double bot)
{ {
ProjectedWallLine most1, most2, most3; ProjectedWallLine most1, most2, most3;
double texheight = rw_pic->GetHeight(); double texheight = rw_pic->GetHeight();
double partition; double partition;
double scaledtexheight = texheight / yrepeat; double scaledtexheight = texheight / texcoords.yscale;
if (yrepeat >= 0) if (texcoords.yscale >= 0)
{ // normal orientation: draw strips from top to bottom { // normal orientation: draw strips from top to bottom
partition = top - fmod(top - texturemid / yrepeat - Thread->Viewport->viewpoint.Pos.Z, scaledtexheight); partition = top - fmod(top - texcoords.texturemid / texcoords.yscale - Thread->Viewport->viewpoint.Pos.Z, scaledtexheight);
if (partition == top) if (partition == top)
{ {
partition -= scaledtexheight; partition -= scaledtexheight;
} }
const short *up = uwal; const short *up = uwal;
short *down = most1.ScreenY; short *down = most1.ScreenY;
texturemid = (partition - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + texheight; texcoords.texturemid = (partition - Thread->Viewport->viewpoint.Pos.Z) * texcoords.yscale + texheight;
while (partition > bot) while (partition > bot)
{ {
ProjectedWallCull j = most3.Project(Thread->Viewport.get(), partition - Thread->Viewport->viewpoint.Pos.Z, &WallC); ProjectedWallCull j = most3.Project(Thread->Viewport.get(), partition - Thread->Viewport->viewpoint.Pos.Z, &WallC);
@ -495,21 +493,21 @@ namespace swrenderer
{ {
down[j] = clamp(most3.ScreenY[j], up[j], dwal[j]); down[j] = clamp(most3.ScreenY[j], up[j], dwal[j]);
} }
ProcessWall(up, down, texturemid, swal, lwal); ProcessWall(up, down, texcoords);
up = down; up = down;
down = (down == most1.ScreenY) ? most2.ScreenY : most1.ScreenY; down = (down == most1.ScreenY) ? most2.ScreenY : most1.ScreenY;
} }
partition -= scaledtexheight; partition -= scaledtexheight;
texturemid -= texheight; texcoords.texturemid -= texheight;
} }
ProcessWall(up, dwal, texturemid, swal, lwal); ProcessWall(up, dwal, texcoords);
} }
else else
{ // upside down: draw strips from bottom to top { // upside down: draw strips from bottom to top
partition = bot - fmod(bot - texturemid / yrepeat - Thread->Viewport->viewpoint.Pos.Z, scaledtexheight); partition = bot - fmod(bot - texcoords.texturemid / texcoords.yscale - Thread->Viewport->viewpoint.Pos.Z, scaledtexheight);
short *up = most1.ScreenY; short *up = most1.ScreenY;
const short *down = dwal; const short *down = dwal;
texturemid = (partition - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + texheight; texcoords.texturemid = (partition - Thread->Viewport->viewpoint.Pos.Z) * texcoords.yscale + texheight;
while (partition < top) while (partition < top)
{ {
ProjectedWallCull j = most3.Project(Thread->Viewport.get(), partition - Thread->Viewport->viewpoint.Pos.Z, &WallC); ProjectedWallCull j = most3.Project(Thread->Viewport.get(), partition - Thread->Viewport->viewpoint.Pos.Z, &WallC);
@ -519,27 +517,25 @@ namespace swrenderer
{ {
up[j] = clamp(most3.ScreenY[j], uwal[j], down[j]); up[j] = clamp(most3.ScreenY[j], uwal[j], down[j]);
} }
ProcessWall(up, down, texturemid, swal, lwal); ProcessWall(up, down, texcoords);
down = up; down = up;
up = (up == most1.ScreenY) ? most2.ScreenY : most1.ScreenY; up = (up == most1.ScreenY) ? most2.ScreenY : most1.ScreenY;
} }
partition -= scaledtexheight; partition -= scaledtexheight;
texturemid -= texheight; texcoords.texturemid -= texheight;
} }
ProcessWall(uwal, down, texturemid, swal, lwal); ProcessWall(uwal, down, texcoords);
} }
} }
void RenderWallPart::Render(sector_t *frontsector, seg_t *curline, const FWallCoords &WallC, FSoftwareTexture *pic, int x1, int x2, const short *walltop, const short *wallbottom, double texturemid, const ProjectedWallTexcoords& texcoords, double yscale, double top, double bottom, bool mask, bool additive, fixed_t alpha, fixed_t xoffset, const ProjectedWallLight &light, FLightNode *light_list) void RenderWallPart::Render(sector_t *frontsector, seg_t *curline, const FWallCoords &WallC, FSoftwareTexture *pic, int x1, int x2, const short *walltop, const short *wallbottom, const ProjectedWallTexcoords& texcoords, double top, double bottom, bool mask, bool additive, fixed_t alpha, const ProjectedWallLight &light, FLightNode *light_list)
{ {
this->x1 = x1; this->x1 = x1;
this->x2 = x2; this->x2 = x2;
this->frontsector = frontsector; this->frontsector = frontsector;
this->curline = curline; this->curline = curline;
this->WallC = WallC; this->WallC = WallC;
this->yrepeat = yscale;
this->mLight = light; this->mLight = light;
this->xoffset = xoffset;
this->light_list = light_list; this->light_list = light_list;
this->rw_pic = pic; this->rw_pic = pic;
this->mask = mask; this->mask = mask;
@ -548,41 +544,13 @@ namespace swrenderer
Thread->PrepareTexture(pic, DefaultRenderStyle()); // Get correct render style? Shaded won't get here. Thread->PrepareTexture(pic, DefaultRenderStyle()); // Get correct render style? Shaded won't get here.
if (rw_pic->GetHeight() != 1 << rw_pic->GetHeightBits()) if (rw_pic->GetHeight() != (1 << rw_pic->GetHeightBits()))
{ {
ProcessWallNP2(walltop, wallbottom, texturemid, texcoords.VStep, texcoords.UPos, top, bottom); ProcessWallNP2(walltop, wallbottom, texcoords, top, bottom);
} }
else else
{ {
ProcessWall(walltop, wallbottom, texturemid, texcoords.VStep, texcoords.UPos); ProcessWall(walltop, wallbottom, texcoords);
}
}
void RenderWallPart::Render(sector_t* frontsector, seg_t* curline, const FWallCoords& WallC, FSoftwareTexture* pic, int x1, int x2, const short* walltop, const short* wallbottom, double texturemid, const DrawSegmentWallTexcoords& texcoords, double yscale, double top, double bottom, bool mask, bool additive, fixed_t alpha, fixed_t xoffset, const ProjectedWallLight& light, FLightNode* light_list)
{
this->x1 = x1;
this->x2 = x2;
this->frontsector = frontsector;
this->curline = curline;
this->WallC = WallC;
this->yrepeat = yscale;
this->mLight = light;
this->xoffset = xoffset;
this->light_list = light_list;
this->rw_pic = pic;
this->mask = mask;
this->additive = additive;
this->alpha = alpha;
Thread->PrepareTexture(pic, DefaultRenderStyle()); // Get correct render style? Shaded won't get here.
if (rw_pic->GetHeight() != 1 << rw_pic->GetHeightBits())
{
ProcessWallNP2(walltop, wallbottom, texturemid, texcoords.VStep, texcoords.UPos, top, bottom);
}
else
{
ProcessWall(walltop, wallbottom, texturemid, texcoords.VStep, texcoords.UPos);
} }
} }

View file

@ -54,46 +54,22 @@ namespace swrenderer
int x2, int x2,
const short *walltop, const short *walltop,
const short *wallbottom, const short *wallbottom,
double texturemid,
const ProjectedWallTexcoords &texcoords, const ProjectedWallTexcoords &texcoords,
double yscale,
double top, double top,
double bottom, double bottom,
bool mask, bool mask,
bool additive, bool additive,
fixed_t alpha, fixed_t alpha,
fixed_t xoffset,
const ProjectedWallLight &light,
FLightNode *light_list);
void Render(
sector_t* frontsector,
seg_t* curline,
const FWallCoords& WallC,
FSoftwareTexture* rw_pic,
int x1,
int x2,
const short* walltop,
const short* wallbottom,
double texturemid,
const DrawSegmentWallTexcoords& texcoords,
double yscale,
double top,
double bottom,
bool mask,
bool additive,
fixed_t alpha,
fixed_t xoffset,
const ProjectedWallLight &light, const ProjectedWallLight &light,
FLightNode *light_list); FLightNode *light_list);
RenderThread *Thread = nullptr; RenderThread *Thread = nullptr;
private: private:
void ProcessWallNP2(const short *uwal, const short *dwal, double texturemid, const float *swal, const fixed_t *lwal, double top, double bot); void ProcessWallNP2(const short *uwal, const short *dwal, ProjectedWallTexcoords texcoords, double top, double bot);
void ProcessWall(const short *uwal, const short *dwal, double texturemid, const float *swal, const fixed_t *lwal); void ProcessWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords);
void ProcessStripedWall(const short *uwal, const short *dwal, double texturemid, const float *swal, const fixed_t *lwal); void ProcessStripedWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords);
void ProcessNormalWall(const short *uwal, const short *dwal, double texturemid, const float *swal, const fixed_t *lwal); void ProcessNormalWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords);
void SetLights(WallDrawerArgs &drawerargs, int x, int y1); void SetLights(WallDrawerArgs &drawerargs, int x, int y1);
int x1 = 0; int x1 = 0;
@ -105,8 +81,6 @@ namespace swrenderer
ProjectedWallLight mLight; ProjectedWallLight mLight;
double yrepeat = 0.0;
fixed_t xoffset = 0;
FLightNode *light_list = nullptr; FLightNode *light_list = nullptr;
bool mask = false; bool mask = false;
bool additive = false; bool additive = false;

View file

@ -168,84 +168,416 @@ namespace swrenderer
} }
} }
void ProjectedWallLine::ClipTop(int x1, int x2, const DrawSegmentClipInfo& clip)
{
for (int i = x1; i < x2; i++)
{
ScreenY[i] = std::max(ScreenY[i], clip.sprtopclip[i]);
}
}
void ProjectedWallLine::ClipBottom(int x1, int x2, const DrawSegmentClipInfo& clip)
{
for (int i = x1; i < x2; i++)
{
ScreenY[i] = std::min(ScreenY[i], clip.sprbottomclip[i]);
}
}
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
void ProjectedWallTexcoords::Project(RenderViewport *viewport, double walxrepeat, int x1, int x2, const FWallTmapVals &WallT, bool flipx) void FWallTmapVals::InitFromWallCoords(RenderThread* thread, const FWallCoords* wallc)
{ {
float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - viewport->CenterX); const FVector2* left = &wallc->tleft;
float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - viewport->CenterX); const FVector2* right = &wallc->tright;
float uGradient = WallT.UoverZstep;
float zGradient = WallT.InvZstep;
float xrepeat = (float)fabs(walxrepeat);
float depthScale = (float)(WallT.InvZstep * viewport->WallTMapScale2);
float depthOrg = (float)(-WallT.UoverZstep * viewport->WallTMapScale2);
if (walxrepeat < 0.0) if (thread->Portal->MirrorFlags & RF_XFLIP)
{ {
for (int x = x1; x < x2; x++) swapvalues(left, right);
}
UoverZorg = left->X * thread->Viewport->CenterX;
UoverZstep = -left->Y;
InvZorg = (left->X - right->X) * thread->Viewport->CenterX;
InvZstep = right->Y - left->Y;
}
void FWallTmapVals::InitFromLine(RenderThread* thread, seg_t* line)
{ {
float u = uOverZ / invZ; auto viewport = thread->Viewport.get();
auto renderportal = thread->Portal.get();
UPos[x] = (fixed_t)((xrepeat - u * xrepeat) * FRACUNIT); vertex_t* v1 = line->linedef->v1;
VStep[x] = depthOrg + u * depthScale; vertex_t* v2 = line->linedef->v2;
uOverZ += uGradient; if (line->linedef->sidedef[0] != line->sidedef)
invZ += zGradient; {
swapvalues(v1, v2);
}
DVector2 left = v1->fPos() - viewport->viewpoint.Pos;
DVector2 right = v2->fPos() - viewport->viewpoint.Pos;
double viewspaceX1 = left.X * viewport->viewpoint.Sin - left.Y * viewport->viewpoint.Cos;
double viewspaceX2 = right.X * viewport->viewpoint.Sin - right.Y * viewport->viewpoint.Cos;
double viewspaceY1 = left.X * viewport->viewpoint.TanCos + left.Y * viewport->viewpoint.TanSin;
double viewspaceY2 = right.X * viewport->viewpoint.TanCos + right.Y * viewport->viewpoint.TanSin;
if (renderportal->MirrorFlags & RF_XFLIP)
{
viewspaceX1 = -viewspaceX1;
viewspaceX2 = -viewspaceX2;
}
UoverZorg = float(viewspaceX1 * viewport->CenterX);
UoverZstep = float(-viewspaceY1);
InvZorg = float((viewspaceX1 - viewspaceX2) * viewport->CenterX);
InvZstep = float(viewspaceY2 - viewspaceY1);
}
/////////////////////////////////////////////////////////////////////////
void ProjectedWallTexcoords::ProjectTop(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic)
{
side_t* sidedef = lineseg->sidedef;
line_t* linedef = lineseg->linedef;
yscale = GetYScale(sidedef, pic, side_t::top);
double cameraZ = viewport->viewpoint.Pos.Z;
if (yscale >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGTOP)
{ // top of texture at top
texturemid = (frontsector->GetPlaneTexZ(sector_t::ceiling) - cameraZ) * yscale;
}
else
{ // bottom of texture at bottom
texturemid = (backsector->GetPlaneTexZ(sector_t::ceiling) - cameraZ) * yscale + pic->GetHeight();
} }
} }
else else
{ { // upside down
for (int x = x1; x < x2; x++) if (linedef->flags & ML_DONTPEGTOP)
{ { // bottom of texture at top
float u = uOverZ / invZ; texturemid = (frontsector->GetPlaneTexZ(sector_t::ceiling) - cameraZ) * yscale + pic->GetHeight();
UPos[x] = (fixed_t)(u * xrepeat * FRACUNIT);
VStep[x] = depthOrg + u * depthScale;
uOverZ += uGradient;
invZ += zGradient;
} }
else
{ // top of texture at bottom
texturemid = (backsector->GetPlaneTexZ(sector_t::ceiling) - cameraZ) * yscale;
}
}
texturemid += GetRowOffset(lineseg, pic, side_t::top);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::top), x1, x2, WallT);
xoffset = GetXOffset(lineseg, pic, side_t::top);
}
void ProjectedWallTexcoords::ProjectMid(RenderViewport* viewport, sector_t* frontsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic)
{
side_t* sidedef = lineseg->sidedef;
line_t* linedef = lineseg->linedef;
yscale = GetYScale(sidedef, pic, side_t::mid);
double cameraZ = viewport->viewpoint.Pos.Z;
if (yscale >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // bottom of texture at bottom
texturemid = (frontsector->GetPlaneTexZ(sector_t::floor) - cameraZ) * yscale + pic->GetHeight();
}
else
{ // top of texture at top
texturemid = (frontsector->GetPlaneTexZ(sector_t::ceiling) - cameraZ) * yscale;
}
}
else
{ // upside down
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // top of texture at bottom
texturemid = (frontsector->GetPlaneTexZ(sector_t::floor) - cameraZ) * yscale;
}
else
{ // bottom of texture at top
texturemid = (frontsector->GetPlaneTexZ(sector_t::ceiling) - cameraZ) * yscale + pic->GetHeight();
}
}
texturemid += GetRowOffset(lineseg, pic, side_t::mid);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::mid), x1, x2, WallT);
xoffset = GetXOffset(lineseg, pic, side_t::mid);
}
void ProjectedWallTexcoords::ProjectBottom(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic)
{
side_t* sidedef = lineseg->sidedef;
line_t* linedef = lineseg->linedef;
double frontlowertop = frontsector->GetPlaneTexZ(sector_t::ceiling);
if (frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum)
{
// Putting sky ceilings on the front and back of a line alters the way unpegged
// positioning works.
frontlowertop = backsector->GetPlaneTexZ(sector_t::ceiling);
}
yscale = GetYScale(sidedef, pic, side_t::bottom);
double cameraZ = viewport->viewpoint.Pos.Z;
if (yscale >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // bottom of texture at bottom
texturemid = (frontlowertop - cameraZ) * yscale;
}
else
{ // top of texture at top
texturemid = (backsector->GetPlaneTexZ(sector_t::floor) - cameraZ) * yscale;
}
}
else
{ // upside down
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // top of texture at bottom
texturemid = (frontlowertop - cameraZ) * yscale;
}
else
{ // bottom of texture at top
texturemid = (backsector->GetPlaneTexZ(sector_t::floor) - cameraZ) * yscale + pic->GetHeight();
}
}
texturemid += GetRowOffset(lineseg, pic, side_t::bottom);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::bottom), x1, x2, WallT);
xoffset = GetXOffset(lineseg, pic, side_t::bottom);
}
void ProjectedWallTexcoords::ProjectTranslucent(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic)
{
line_t* linedef = lineseg->linedef;
side_t* sidedef = lineseg->sidedef;
yscale = GetYScale(sidedef, pic, side_t::mid);
double cameraZ = viewport->viewpoint.Pos.Z;
double texZFloor = MAX(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor));
double texZCeiling = MIN(frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling));
if (yscale >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // bottom of texture at bottom
texturemid = (texZFloor - cameraZ) * yscale + pic->GetHeight();
}
else
{ // top of texture at top
texturemid = (texZCeiling - cameraZ) * yscale;
}
}
else
{ // upside down
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // top of texture at bottom
texturemid = (texZFloor - cameraZ) * yscale;
}
else
{ // bottom of texture at top
texturemid = (texZCeiling - cameraZ) * yscale + pic->GetHeight();
}
}
texturemid += GetRowOffset(lineseg, pic, side_t::mid);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::mid), x1, x2, WallT);
xoffset = GetXOffset(lineseg, pic, side_t::mid);
}
void ProjectedWallTexcoords::Project3DFloor(RenderViewport* viewport, F3DFloor* rover, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic)
{
// find positioning
side_t* scaledside;
side_t::ETexpart scaledpart;
if (rover->flags & FF_UPPERTEXTURE)
{
scaledside = lineseg->sidedef;
scaledpart = side_t::top;
}
else if (rover->flags & FF_LOWERTEXTURE)
{
scaledside = lineseg->sidedef;
scaledpart = side_t::bottom;
}
else
{
scaledside = rover->master->sidedef[0];
scaledpart = side_t::mid;
}
double xscale = pic->GetScale().X * scaledside->GetTextureXScale(scaledpart);
yscale = pic->GetScale().Y * scaledside->GetTextureYScale(scaledpart);
double rowoffset = lineseg->sidedef->GetTextureYOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureYOffset(side_t::mid);
double planez = rover->model->GetPlaneTexZ(sector_t::ceiling);
xoffset = FLOAT2FIXED(lineseg->sidedef->GetTextureXOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureXOffset(side_t::mid));
if (rowoffset < 0)
{
rowoffset += pic->GetHeight();
}
texturemid = (planez - viewport->viewpoint.Pos.Z) * yscale;
if (pic->useWorldPanning(lineseg->GetLevel()))
{
// rowoffset is added before the multiply so that the masked texture will
// still be positioned in world units rather than texels.
texturemid = texturemid + rowoffset * yscale;
xoffset = xs_RoundToInt(xoffset * xscale);
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
texturemid += rowoffset;
}
Project(viewport, lineseg->sidedef->TexelLength * xscale, x1, x2, WallT);
}
void ProjectedWallTexcoords::ProjectSprite(RenderViewport* viewport, double topZ, double scale, bool flipX, bool flipY, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic)
{
yscale = 1.0 / scale;
texturemid = pic->GetTopOffset(0) + (topZ - viewport->viewpoint.Pos.Z) * yscale;
if (flipY)
{
yscale = -yscale;
texturemid -= pic->GetHeight();
}
Project(viewport, pic->GetWidth(), x1, x2, WallT, flipX);
}
void ProjectedWallTexcoords::Project(RenderViewport *viewport, double walxrepeat, int x1, int x2, const FWallTmapVals &WallT, bool flipx)
{
this->walxrepeat = walxrepeat;
this->x1 = x1;
this->x2 = x2;
this->WallT = WallT;
this->flipx = flipx;
CenterX = viewport->CenterX;
WallTMapScale2 = viewport->WallTMapScale2;
}
float ProjectedWallTexcoords::VStep(int x) const
{
float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - CenterX);
float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - CenterX);
float uGradient = WallT.UoverZstep;
float zGradient = WallT.InvZstep;
float depthScale = (float)(WallT.InvZstep * WallTMapScale2);
float depthOrg = (float)(-WallT.UoverZstep * WallTMapScale2);
float u = (uOverZ + uGradient * (x - x1)) / (invZ + zGradient * (x - x1));
return depthOrg + u * depthScale;
}
fixed_t ProjectedWallTexcoords::UPos(int x) const
{
float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - CenterX);
float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - CenterX);
float uGradient = WallT.UoverZstep;
float zGradient = WallT.InvZstep;
float u = (uOverZ + uGradient * (x - x1)) / (invZ + zGradient * (x - x1));
fixed_t value;
if (walxrepeat < 0.0)
{
float xrepeat = -walxrepeat;
value = (fixed_t)((xrepeat - u * xrepeat) * FRACUNIT);
}
else
{
value = (fixed_t)(u * walxrepeat * FRACUNIT);
} }
if (flipx) if (flipx)
{ {
int right = (int)walxrepeat - 1; value = (int)walxrepeat - 1 - value;
for (int i = x1; i < x2; i++)
{
UPos[i] = right - UPos[i];
}
}
} }
///////////////////////////////////////////////////////////////////////// return value + xoffset;
void DrawSegmentWallTexcoords::Set(RenderThread* thread, const ProjectedWallTexcoords& texcoords, int x1, int x2, fixed_t xoffset, double yscale)
{
UPos = thread->FrameMemory->AllocMemory<fixed_t>(x2 - x1) - x1;
VStep = thread->FrameMemory->AllocMemory<float>(x2 - x1) - x1;
for (int i = x1; i < x2; i++)
{
UPos[i] = texcoords.UPos[i] + xoffset;
VStep[i] = texcoords.VStep[i];
} }
double istart = VStep[x1] * yscale; double ProjectedWallTexcoords::GetRowOffset(seg_t* lineseg, FSoftwareTexture* tex, side_t::ETexpart texpart)
double iend = VStep[x2 - 1] * yscale;
istart = 1 / istart;
iend = 1 / iend;
this->yscale = (float)yscale;
iscale = (float)istart;
if (x2 - x1 > 1)
{ {
iscalestep = float((iend - istart) / (x2 - x1 - 1)); double yrepeat = GetYScale(lineseg->sidedef, tex, texpart);
double rowoffset = lineseg->sidedef->GetTextureYOffset(texpart);
if (yrepeat >= 0)
{
// check if top of texture at top:
bool top_at_top =
(texpart == side_t::top && (lineseg->linedef->flags & ML_DONTPEGTOP)) ||
(texpart != side_t::top && !(lineseg->linedef->flags & ML_DONTPEGBOTTOM));
if (rowoffset < 0 && top_at_top)
{
rowoffset += tex->GetHeight();
}
} }
else else
{ {
iscalestep = 0; rowoffset = -rowoffset;
} }
if (tex->useWorldPanning(lineseg->GetLevel()))
{
return rowoffset * yrepeat;
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
return rowoffset;
}
}
fixed_t ProjectedWallTexcoords::GetXOffset(seg_t* lineseg, FSoftwareTexture* tex, side_t::ETexpart texpart)
{
fixed_t TextureOffsetU = FLOAT2FIXED(lineseg->sidedef->GetTextureXOffset(texpart));
double xscale = GetXScale(lineseg->sidedef, tex, texpart);
fixed_t xoffset;
if (tex->useWorldPanning(lineseg->GetLevel()))
{
xoffset = xs_RoundToInt(TextureOffsetU * xscale);
}
else
{
xoffset = TextureOffsetU;
}
if (xscale < 0)
{
xoffset = -xoffset;
}
return xoffset;
}
double ProjectedWallTexcoords::GetXScale(side_t* sidedef, FSoftwareTexture* tex, side_t::ETexpart texpart)
{
double TextureScaleU = sidedef->GetTextureXScale(texpart);
return tex->GetScale().X * TextureScaleU;
}
double ProjectedWallTexcoords::GetYScale(side_t* sidedef, FSoftwareTexture* tex, side_t::ETexpart texpart)
{
double TextureScaleV = sidedef->GetTextureYScale(texpart);
return tex->GetScale().Y * TextureScaleV;
} }
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////

View file

@ -28,7 +28,7 @@
namespace swrenderer namespace swrenderer
{ {
struct FWallCoords; struct FWallCoords;
struct FWallTmapVals; struct DrawSegmentClipInfo;
enum class ProjectedWallCull enum class ProjectedWallCull
{ {
@ -45,35 +45,55 @@ namespace swrenderer
ProjectedWallCull Project(RenderViewport *viewport, double z1, double z2, const FWallCoords *wallc); ProjectedWallCull Project(RenderViewport *viewport, double z1, double z2, const FWallCoords *wallc);
ProjectedWallCull Project(RenderViewport *viewport, const secplane_t &plane, const FWallCoords *wallc, seg_t *line, bool xflip); ProjectedWallCull Project(RenderViewport *viewport, const secplane_t &plane, const FWallCoords *wallc, seg_t *line, bool xflip);
ProjectedWallCull Project(RenderViewport *viewport, double z, const FWallCoords *wallc); ProjectedWallCull Project(RenderViewport *viewport, double z, const FWallCoords *wallc);
void ClipTop(int x1, int x2, const DrawSegmentClipInfo& clip);
void ClipBottom(int x1, int x2, const DrawSegmentClipInfo& clip);
};
struct FWallTmapVals
{
void InitFromWallCoords(RenderThread* thread, const FWallCoords* wallc);
void InitFromLine(RenderThread* thread, seg_t* line);
private:
float UoverZorg, UoverZstep;
float InvZorg, InvZstep;
friend class ProjectedWallTexcoords;
}; };
class ProjectedWallTexcoords class ProjectedWallTexcoords
{ {
public: public:
void ProjectTop(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic);
void ProjectMid(RenderViewport* viewport, sector_t* frontsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic);
void ProjectBottom(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic);
void ProjectTranslucent(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic);
void Project3DFloor(RenderViewport* viewport, F3DFloor* rover, seg_t* lineseg, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic);
void ProjectSprite(RenderViewport* viewport, double topZ, double scale, bool flipX, bool flipY, int x1, int x2, const FWallTmapVals& WallT, FSoftwareTexture* pic);
float VStep(int x) const;
fixed_t UPos(int x) const;
private:
void Project(RenderViewport* viewport, double walxrepeat, int x1, int x2, const FWallTmapVals& WallT, bool flipx = false); void Project(RenderViewport* viewport, double walxrepeat, int x1, int x2, const FWallTmapVals& WallT, bool flipx = false);
private: static fixed_t GetXOffset(seg_t* lineseg, FSoftwareTexture* tex, side_t::ETexpart texpart);
float VStep[MAXWIDTH]; // swall static double GetRowOffset(seg_t* lineseg, FSoftwareTexture* tex, side_t::ETexpart texpart);
fixed_t UPos[MAXWIDTH]; // lwall static double GetXScale(side_t* sidedef, FSoftwareTexture* tex, side_t::ETexpart texpart);
static double GetYScale(side_t* sidedef, FSoftwareTexture* tex, side_t::ETexpart texpart);
friend class DrawSegmentWallTexcoords; double CenterX;
friend class RenderWallPart; double WallTMapScale2;
friend class SpriteDrawerArgs; double walxrepeat;
}; int x1;
int x2;
FWallTmapVals WallT;
bool flipx;
class DrawSegmentWallTexcoords float yscale = 1.0f;
{ fixed_t xoffset = 0;
public: double texturemid = 0.0f;
void Set(RenderThread *thread, const ProjectedWallTexcoords& texcoords, int x1, int x2, fixed_t xoffset, double yscale);
float yscale;
float iscale, iscalestep;
explicit operator bool() const { return UPos; }
private:
float* VStep = nullptr; // swall
fixed_t* UPos = nullptr; // maskedtexturecol
friend class RenderWallPart; friend class RenderWallPart;
friend class SpriteDrawerArgs; friend class SpriteDrawerArgs;

View file

@ -206,18 +206,15 @@ namespace swrenderer
// Create a drawseg to clip sprites to the sky plane // Create a drawseg to clip sprites to the sky plane
DrawSegment *draw_segment = Thread->FrameMemory->NewObject<DrawSegment>(); DrawSegment *draw_segment = Thread->FrameMemory->NewObject<DrawSegment>();
draw_segment->CurrentPortalUniq = CurrentPortalUniq; draw_segment->drawsegclip.CurrentPortalUniq = CurrentPortalUniq;
draw_segment->WallC.sz1 = 0; draw_segment->WallC.sz1 = 0;
draw_segment->WallC.sz2 = 0; draw_segment->WallC.sz2 = 0;
draw_segment->x1 = pl->left; draw_segment->x1 = pl->left;
draw_segment->x2 = pl->right; draw_segment->x2 = pl->right;
draw_segment->silhouette = SIL_BOTH; draw_segment->drawsegclip.silhouette = SIL_BOTH;
draw_segment->sprbottomclip = Thread->FrameMemory->AllocMemory<short>(pl->right - pl->left); draw_segment->drawsegclip.SetTopClip(Thread, pl->left, pl->right, ceilingclip);
draw_segment->sprtopclip = Thread->FrameMemory->AllocMemory<short>(pl->right - pl->left); draw_segment->drawsegclip.SetBottomClip(Thread, pl->left, pl->right, floorclip);
draw_segment->bFogBoundary = false;
draw_segment->curline = nullptr; draw_segment->curline = nullptr;
memcpy(draw_segment->sprbottomclip, floorclip + pl->left, (pl->right - pl->left) * sizeof(short));
memcpy(draw_segment->sprtopclip, ceilingclip + pl->left, (pl->right - pl->left) * sizeof(short));
drawseglist->Push(draw_segment); drawseglist->Push(draw_segment);
Thread->OpaquePass->RenderScene(Thread->Viewport->Level()); Thread->OpaquePass->RenderScene(Thread->Viewport->Level());

View file

@ -114,7 +114,7 @@ namespace swrenderer
for (DrawSegment *seg : portaldrawsegs) for (DrawSegment *seg : portaldrawsegs)
{ {
// ignore segs from other portals // ignore segs from other portals
if (seg->CurrentPortalUniq != renderportal->CurrentPortalUniq) if (seg->drawsegclip.CurrentPortalUniq != renderportal->CurrentPortalUniq)
continue; continue;
// (all checks that are already done in R_CollectPortals have been removed for performance reasons.) // (all checks that are already done in R_CollectPortals have been removed for performance reasons.)
@ -154,19 +154,17 @@ namespace swrenderer
DrawSegment *ds = drawseglist->Segment(index); DrawSegment *ds = drawseglist->Segment(index);
// [ZZ] the same as above // [ZZ] the same as above
if (ds->CurrentPortalUniq != renderportal->CurrentPortalUniq) if (ds->drawsegclip.CurrentPortalUniq != renderportal->CurrentPortalUniq)
continue; continue;
if (ds->texcoords || ds->bFogBoundary)
if (ds->HasTranslucentMidTexture() || ds->Has3DFloorWalls() || ds->HasFogBoundary())
{ {
RenderDrawSegment renderer(Thread); RenderDrawSegment renderer(Thread);
renderer.Render(ds, ds->x1, ds->x2, clip3DFloor); renderer.Render(ds, ds->x1, ds->x2, clip3DFloor);
if (renew && ds->bFogBoundary) // don't draw fogboundary again if (renew)
ds->bFogBoundary = false;
if (renew && ds->sprclipped)
{ {
memcpy(ds->sprtopclip, ds->bkup, (ds->x2 - ds->x1) * sizeof(short)); ds->ClearFogBoundary(); // don't draw fogboundary again
ds->sprclipped = false; ds->drawsegclip.SetRangeUndrawn(ds->x1, ds->x2);
} }
} }
} }

View file

@ -131,10 +131,10 @@ namespace swrenderer
{ {
ds = Segment(groupIndex); ds = Segment(groupIndex);
if (ds->silhouette & SIL_BOTTOM) if (ds->drawsegclip.silhouette & SIL_BOTTOM)
{ {
short *clip1 = clipbottom + ds->x1; short *clip1 = clipbottom + ds->x1;
const short *clip2 = ds->sprbottomclip; const short *clip2 = ds->drawsegclip.sprbottomclip + ds->x1;
int i = ds->x2 - ds->x1; int i = ds->x2 - ds->x1;
do do
{ {
@ -145,10 +145,10 @@ namespace swrenderer
} while (--i); } while (--i);
} }
if (ds->silhouette & SIL_TOP) if (ds->drawsegclip.silhouette & SIL_TOP)
{ {
short *clip1 = cliptop + ds->x1; short *clip1 = cliptop + ds->x1;
const short *clip2 = ds->sprtopclip; const short *clip2 = ds->drawsegclip.sprtopclip + ds->x1;
int i = ds->x2 - ds->x1; int i = ds->x2 - ds->x1;
do do
{ {
@ -168,4 +168,58 @@ namespace swrenderer
SegmentGroups.Push(group); SegmentGroups.Push(group);
} }
} }
/////////////////////////////////////////////////////////////////////////
void DrawSegmentClipInfo::SetTopClip(RenderThread* thread, int x1, int x2, const short* ceilingclip)
{
short* clip = thread->FrameMemory->AllocMemory<short>(x2 - x1);
memcpy(clip, ceilingclip + x1, (x2 - x1) * sizeof(short));
sprtopclip = clip - x1;
}
void DrawSegmentClipInfo::SetTopClip(RenderThread* thread, int x1, int x2, short value)
{
short* clip = thread->FrameMemory->AllocMemory<short>(x2 - x1);
for (int i = 0; i < x2 - x1; i++)
clip[i] = value;
sprtopclip = clip - x1;
}
void DrawSegmentClipInfo::SetBottomClip(RenderThread* thread, int x1, int x2, const short* floorclip)
{
short* clip = thread->FrameMemory->AllocMemory<short>(x2 - x1);
memcpy(clip, floorclip + x1, (x2 - x1) * sizeof(short));
sprbottomclip = clip - x1;
}
void DrawSegmentClipInfo::SetBottomClip(RenderThread* thread, int x1, int x2, short value)
{
short* clip = thread->FrameMemory->AllocMemory<short>(x2 - x1);
for (int i = 0; i < x2 - x1; i++)
clip[i] = value;
sprbottomclip = clip - x1;
}
void DrawSegmentClipInfo::SetBackupClip(RenderThread* thread, int x1, int x2, const short* ceilingclip)
{
short* clip = thread->FrameMemory->AllocMemory<short>(x2 - x1);
memcpy(clip, ceilingclip + x1, (x2 - x1) * sizeof(short));
bkup = clip - x1;
}
void DrawSegmentClipInfo::SetRangeDrawn(int x1, int x2)
{
sprclipped = true;
fillshort(const_cast<short*>(sprtopclip) + x1, x2 - x1, viewheight);
}
void DrawSegmentClipInfo::SetRangeUndrawn(int x1, int x2)
{
if (sprclipped)
{
sprclipped = false;
memcpy(const_cast<short*>(sprtopclip) + x1, bkup + x1, (x2 - x1) * sizeof(short));
}
}
} }

View file

@ -25,40 +25,56 @@
namespace swrenderer namespace swrenderer
{ {
struct DrawSegmentClipInfo
{
void SetTopClip(RenderThread* thread, int x1, int x2, const short* ceilingclip);
void SetTopClip(RenderThread* thread, int x1, int x2, short value);
void SetBottomClip(RenderThread* thread, int x1, int x2, const short* floorclip);
void SetBottomClip(RenderThread* thread, int x1, int x2, short value);
void SetBackupClip(RenderThread* thread, int x1, int x2, const short* ceilingclip);
void SetRangeDrawn(int x1, int x2);
void SetRangeUndrawn(int x1, int x2);
uint8_t silhouette = 0; // 0=none, 1=bottom, 2=top, 3=both
int CurrentPortalUniq = 0; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping.
int SubsectorDepth;
// Pointers to lists for sprite clipping, all three adjusted so [x1] is first value.
const short* sprtopclip = nullptr;
const short* sprbottomclip = nullptr;
private:
bool sprclipped = false; // True if draw segment was used for clipping sprites
const short* bkup = nullptr;
};
struct DrawSegment struct DrawSegment
{ {
seg_t *curline; seg_t *curline;
float light, lightstep; float light, lightstep;
short x1, x2; // Same as sx1 and sx2, but clipped to the drawseg short x1, x2; // Same as sx1 and sx2, but clipped to the drawseg
FWallCoords WallC; FWallCoords WallC;
uint8_t silhouette = 0; // 0=none, 1=bottom, 2=top, 3=both
bool bFogBoundary = false;
DrawSegmentWallTexcoords texcoords;
// Pointers to lists for sprite clipping, all three adjusted so [x1] is first value.
short *sprtopclip = nullptr;
short *sprbottomclip = nullptr;
short *bkup = nullptr; // sprtopclip backup, for mid and fake textures
bool sprclipped = false; // True if draw segment was used for clipping sprites
FWallTmapVals tmapvals; FWallTmapVals tmapvals;
ProjectedWallTexcoords texcoords;
int CurrentPortalUniq = 0; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping. DrawSegmentClipInfo drawsegclip;
int SubsectorDepth; bool HasFogBoundary() const { return (flags & 8) != 0; }
bool Has3DFloorWalls() const { return (flags & 3) != 0; }
bool Has3DFloorFrontSectorWalls() const { return (flags & 2) != 0; }
bool Has3DFloorBackSectorWalls() const { return (flags & 1) != 0; }
bool HasTranslucentMidTexture() const { return (flags & 4) != 0; }
bool Has3DFloorWalls() const { return b3DFloorBoundary != 0; } void SetHasFogBoundary() { flags |= 8; }
bool Has3DFloorFrontSectorWalls() const { return (b3DFloorBoundary & 2) == 2; } void SetHas3DFloorFrontSectorWalls() { flags |= 2; }
bool Has3DFloorBackSectorWalls() const { return (b3DFloorBoundary & 1) == 1; } void SetHas3DFloorBackSectorWalls() { flags |= 1; }
bool Has3DFloorMidTexture() const { return (b3DFloorBoundary & 4) == 4; } void SetHasTranslucentMidTexture() { flags |= 4; }
void SetHas3DFloorFrontSectorWalls() { b3DFloorBoundary |= 2; } void ClearFogBoundary() { flags &= ~8; } // Note: this shouldn't be needed as fog boundaries should be able to clip same way as 3dfloor walls
void SetHas3DFloorBackSectorWalls() { b3DFloorBoundary |= 1; }
void SetHas3DFloorMidTexture() { b3DFloorBoundary |= 4; }
private: private:
uint8_t b3DFloorBoundary = 0; // 1=backsector, 2=frontsector, 4=midtexture int flags = 0; // 1=backsector, 2=frontsector, 4=midtexture, 8=fogboundary
}; };
struct DrawSegmentGroup struct DrawSegmentGroup

View file

@ -52,8 +52,8 @@ namespace swrenderer
ceilingclip = thread->FrameMemory->AllocMemory<short>(len); ceilingclip = thread->FrameMemory->AllocMemory<short>(len);
floorclip = thread->FrameMemory->AllocMemory<short>(len); floorclip = thread->FrameMemory->AllocMemory<short>(len);
memcpy(ceilingclip, topclip, len * sizeof(short)); memcpy(ceilingclip, topclip + x1, len * sizeof(short));
memcpy(floorclip, bottomclip, len * sizeof(short)); memcpy(floorclip, bottomclip + x1, len * sizeof(short));
for (int i = 0; i < x2 - x1; i++) for (int i = 0; i < x2 - x1; i++)
{ {

View file

@ -69,8 +69,6 @@ namespace swrenderer
{ {
DVector2 decal_left, decal_right, decal_pos; DVector2 decal_left, decal_right, decal_pos;
int x1, x2; int x1, x2;
double yscale;
uint8_t flipx;
double zpos; double zpos;
int needrepeat = 0; int needrepeat = 0;
sector_t *back; sector_t *back;
@ -127,7 +125,6 @@ namespace swrenderer
} }
FTexture *tex = TexMan.GetPalettedTexture(decal->PicNum, true); FTexture *tex = TexMan.GetPalettedTexture(decal->PicNum, true);
flipx = (uint8_t)(decal->RenderFlags & RF_XFLIP);
if (tex == NULL || !tex->isValid()) if (tex == NULL || !tex->isValid())
{ {
@ -149,13 +146,11 @@ namespace swrenderer
decal_pos = { dcx, dcy }; decal_pos = { dcx, dcy };
DVector2 angvec = (curline->v2->fPos() - curline->v1->fPos()).Unit(); DVector2 angvec = (curline->v2->fPos() - curline->v1->fPos()).Unit();
float maskedScaleY;
decal_left = decal_pos - edge_left * angvec - thread->Viewport->viewpoint.Pos; decal_left = decal_pos - edge_left * angvec - thread->Viewport->viewpoint.Pos;
decal_right = decal_pos + edge_right * angvec - thread->Viewport->viewpoint.Pos; decal_right = decal_pos + edge_right * angvec - thread->Viewport->viewpoint.Pos;
CameraLight *cameraLight; CameraLight *cameraLight;
double texturemid;
FWallCoords WallC; FWallCoords WallC;
if (WallC.Init(thread, decal_left, decal_right, TOO_CLOSE_Z)) if (WallC.Init(thread, decal_left, decal_right, TOO_CLOSE_Z))
@ -167,9 +162,6 @@ namespace swrenderer
if (x1 >= clipper->x2 || x2 <= clipper->x1) if (x1 >= clipper->x2 || x2 <= clipper->x1)
return; return;
FWallTmapVals WallT;
WallT.InitFromWallCoords(thread, &WallC);
if (drawsegPass) if (drawsegPass)
{ {
uint32_t clipMode = decal->RenderFlags & RF_CLIPMASK; uint32_t clipMode = decal->RenderFlags & RF_CLIPMASK;
@ -230,9 +222,6 @@ namespace swrenderer
} }
} }
yscale = decal->ScaleY;
texturemid = WallSpriteTile->GetTopOffset(0) + (zpos - thread->Viewport->viewpoint.Pos.Z) / yscale;
// Clip sprite to drawseg // Clip sprite to drawseg
x1 = MAX<int>(clipper->x1, x1); x1 = MAX<int>(clipper->x1, x1);
x2 = MIN<int>(clipper->x2, x2); x2 = MIN<int>(clipper->x2, x2);
@ -241,9 +230,6 @@ namespace swrenderer
return; return;
} }
ProjectedWallTexcoords walltexcoords;
walltexcoords.Project(thread->Viewport.get(), WallSpriteTile->GetWidth(), x1, x2, WallT, flipx);
// Prepare lighting // Prepare lighting
usecolormap = light.GetBaseColormap(); usecolormap = light.GetBaseColormap();
@ -258,19 +244,13 @@ namespace swrenderer
cameraLight = CameraLight::Instance(); cameraLight = CameraLight::Instance();
// Draw it // Draw it
bool sprflipvert;
if (decal->RenderFlags & RF_YFLIP)
{
sprflipvert = true;
yscale = -yscale;
texturemid -= WallSpriteTile->GetHeight();
}
else
{
sprflipvert = false;
}
maskedScaleY = float(1 / yscale); FWallTmapVals WallT;
WallT.InitFromWallCoords(thread, &WallC);
ProjectedWallTexcoords walltexcoords;
walltexcoords.ProjectSprite(thread->Viewport.get(), zpos, decal->ScaleY, decal->RenderFlags & RF_XFLIP, decal->RenderFlags & RF_YFLIP, x1, x2, WallT, WallSpriteTile);
do do
{ {
int x = x1; int x = x1;
@ -285,13 +265,14 @@ namespace swrenderer
if (visible) if (visible)
{ {
thread->PrepareTexture(WallSpriteTile, decal->RenderStyle); thread->PrepareTexture(WallSpriteTile, decal->RenderStyle);
bool sprflipvert = (decal->RenderFlags & RF_YFLIP);
while (x < x2) while (x < x2)
{ {
if (calclighting) if (calclighting)
{ // calculate lighting { // calculate lighting
drawerargs.SetLight(lightpos, light.GetLightLevel(), light.GetFoggy(), thread->Viewport.get()); drawerargs.SetLight(lightpos, light.GetLightLevel(), light.GetFoggy(), thread->Viewport.get());
} }
drawerargs.DrawMaskedColumn(thread, x, WallSpriteTile, walltexcoords, texturemid, maskedScaleY, sprflipvert, mfloorclip, mceilingclip, decal->RenderStyle); drawerargs.DrawMaskedColumn(thread, x, WallSpriteTile, walltexcoords, sprflipvert, mfloorclip, mceilingclip, decal->RenderStyle);
lightpos += light.GetLightStep(); lightpos += light.GetLightStep();
x++; x++;
} }

View file

@ -298,7 +298,7 @@ namespace swrenderer
if ((siz2 - siz1) * ((x2 + x1) / 2 - ds->WallC.sx1) / (ds->WallC.sx2 - ds->WallC.sx1) + siz1 < idepth) if ((siz2 - siz1) * ((x2 + x1) / 2 - ds->WallC.sx1) / (ds->WallC.sx2 - ds->WallC.sx1) + siz1 < idepth)
{ {
// [ZZ] only draw stuff that's inside the same portal as the particle, other portals will care for themselves // [ZZ] only draw stuff that's inside the same portal as the particle, other portals will care for themselves
if (ds->CurrentPortalUniq == CurrentPortalUniq) if (ds->drawsegclip.CurrentPortalUniq == CurrentPortalUniq)
{ {
RenderDrawSegment renderer(thread); RenderDrawSegment renderer(thread);
renderer.Render(ds, MAX<int>(ds->x1, x1), MIN<int>(ds->x2, x2), clip3DFloor); renderer.Render(ds, MAX<int>(ds->x1, x1), MIN<int>(ds->x2, x2), clip3DFloor);

View file

@ -59,7 +59,7 @@ namespace swrenderer
for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++) for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++)
{ {
DrawSegment *ds = segmentlist->TranslucentSegment(index); DrawSegment *ds = segmentlist->TranslucentSegment(index);
if (ds->SubsectorDepth >= SubsectorDepth && ds->CurrentPortalUniq == renderportal->CurrentPortalUniq) if (ds->drawsegclip.SubsectorDepth >= SubsectorDepth && ds->drawsegclip.CurrentPortalUniq == renderportal->CurrentPortalUniq)
{ {
int r1 = MAX<int>(ds->x1, 0); int r1 = MAX<int>(ds->x1, 0);
int r2 = MIN<int>(ds->x2, viewwidth - 1); int r2 = MIN<int>(ds->x2, viewwidth - 1);
@ -321,7 +321,7 @@ namespace swrenderer
for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++) for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++)
{ {
DrawSegment *ds = segmentlist->TranslucentSegment(index); DrawSegment *ds = segmentlist->TranslucentSegment(index);
if (ds->SubsectorDepth >= subsectordepth && ds->CurrentPortalUniq == renderportal->CurrentPortalUniq) if (ds->drawsegclip.SubsectorDepth >= subsectordepth && ds->drawsegclip.CurrentPortalUniq == renderportal->CurrentPortalUniq)
{ {
int r1 = MAX<int>(ds->x1, 0); int r1 = MAX<int>(ds->x1, 0);
int r2 = MIN<int>(ds->x2, viewwidth - 1); int r2 = MIN<int>(ds->x2, viewwidth - 1);
@ -350,7 +350,7 @@ namespace swrenderer
(spr->gpos.Y - ds->curline->v1->fY()) * (ds->curline->v2->fX() - ds->curline->v1->fX()) - (spr->gpos.Y - ds->curline->v1->fY()) * (ds->curline->v2->fX() - ds->curline->v1->fX()) -
(spr->gpos.X - ds->curline->v1->fX()) * (ds->curline->v2->fY() - ds->curline->v1->fY()) <= 0)) (spr->gpos.X - ds->curline->v1->fX()) * (ds->curline->v2->fY() - ds->curline->v1->fY()) <= 0))
{ {
if (ds->CurrentPortalUniq == renderportal->CurrentPortalUniq) if (ds->drawsegclip.CurrentPortalUniq == renderportal->CurrentPortalUniq)
{ {
int r1 = MAX<int>(ds->x1, x1); int r1 = MAX<int>(ds->x1, x1);
int r2 = MIN<int>(ds->x2, x2); int r2 = MIN<int>(ds->x2, x2);
@ -405,7 +405,7 @@ namespace swrenderer
DrawSegment *ds = segmentlist->Segment(index); DrawSegment *ds = segmentlist->Segment(index);
// determine if the drawseg obscures the sprite // determine if the drawseg obscures the sprite
if (ds->x1 >= x2 || ds->x2 <= x1 || (!(ds->silhouette & SIL_BOTH) && !ds->texcoords && !ds->bFogBoundary)) if (ds->x1 >= x2 || ds->x2 <= x1 || (!(ds->drawsegclip.silhouette & SIL_BOTH) && !ds->Has3DFloorWalls() && !ds->HasTranslucentMidTexture() && !ds->HasFogBoundary()))
{ {
// does not cover sprite // does not cover sprite
continue; continue;
@ -431,10 +431,10 @@ namespace swrenderer
// [RH] Optimized further (at least for VC++; // [RH] Optimized further (at least for VC++;
// other compilers should be at least as good as before) // other compilers should be at least as good as before)
if (ds->silhouette & SIL_BOTTOM) //bottom sil if (ds->drawsegclip.silhouette & SIL_BOTTOM) //bottom sil
{ {
short *clip1 = clipbot + r1; short *clip1 = clipbot + r1;
const short *clip2 = ds->sprbottomclip + r1 - ds->x1; const short *clip2 = ds->drawsegclip.sprbottomclip + r1;
int i = r2 - r1; int i = r2 - r1;
do do
{ {
@ -445,10 +445,10 @@ namespace swrenderer
} while (--i); } while (--i);
} }
if (ds->silhouette & SIL_TOP) // top sil if (ds->drawsegclip.silhouette & SIL_TOP) // top sil
{ {
short *clip1 = cliptop + r1; short *clip1 = cliptop + r1;
const short *clip2 = ds->sprtopclip + r1 - ds->x1; const short *clip2 = ds->drawsegclip.sprtopclip + r1;
int i = r2 - r1; int i = r2 - r1;
do do
{ {

View file

@ -67,8 +67,6 @@
#include "swrenderer/r_memory.h" #include "swrenderer/r_memory.h"
#include "swrenderer/r_renderthread.h" #include "swrenderer/r_renderthread.h"
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
namespace swrenderer namespace swrenderer
{ {
void RenderWallSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *ppic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap) void RenderWallSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *ppic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap)
@ -162,24 +160,11 @@ namespace swrenderer
{ {
auto spr = this; auto spr = this;
int x1, x2; int x1 = MAX<int>(spr->x1, spr->wallc.sx1);
double iyscale; int x2 = MIN<int>(spr->x2, spr->wallc.sx2);
bool sprflipvert;
x1 = MAX<int>(spr->x1, spr->wallc.sx1);
x2 = MIN<int>(spr->x2, spr->wallc.sx2);
if (x1 >= x2) if (x1 >= x2)
return; return;
FWallTmapVals WallT;
WallT.InitFromWallCoords(thread, &spr->wallc);
ProjectedWallTexcoords walltexcoords;
walltexcoords.Project(thread->Viewport.get(), spr->pic->GetWidth(), x1, x2, WallT, spr->renderflags & RF_XFLIP);
iyscale = 1 / spr->yscale;
double texturemid = (spr->gzt - thread->Viewport->viewpoint.Pos.Z) * iyscale;
// Prepare lighting // Prepare lighting
// Decals that are added to the scene must fade to black. // Decals that are added to the scene must fade to black.
@ -203,25 +188,18 @@ namespace swrenderer
// Draw it // Draw it
auto WallSpriteTile = spr->pic; auto WallSpriteTile = spr->pic;
if (spr->renderflags & RF_YFLIP)
{
sprflipvert = true;
iyscale = -iyscale;
texturemid -= spr->pic->GetHeight();
}
else
{
sprflipvert = false;
}
float maskedScaleY = (float)iyscale; FWallTmapVals WallT;
WallT.InitFromWallCoords(thread, &spr->wallc);
int x = x1; ProjectedWallTexcoords walltexcoords;
walltexcoords.ProjectSprite(thread->Viewport.get(), spr->gzt, spr->yscale, spr->renderflags & RF_XFLIP, spr->renderflags & RF_YFLIP, x1, x2, WallT, WallSpriteTile);
RenderTranslucentPass *translucentPass = thread->TranslucentPass.get(); RenderTranslucentPass *translucentPass = thread->TranslucentPass.get();
thread->PrepareTexture(WallSpriteTile, spr->RenderStyle); thread->PrepareTexture(WallSpriteTile, spr->RenderStyle);
while (x < x2) bool sprflipvert = (spr->renderflags & RF_YFLIP);
for (int x = x1; x < x2; x++)
{ {
if (calclighting) if (calclighting)
{ {
@ -229,9 +207,8 @@ namespace swrenderer
drawerargs.SetLight(light, spr->sector->lightlevel, spr->foggy, thread->Viewport.get()); drawerargs.SetLight(light, spr->sector->lightlevel, spr->foggy, thread->Viewport.get());
} }
if (!translucentPass->ClipSpriteColumnWithPortals(x, spr)) if (!translucentPass->ClipSpriteColumnWithPortals(x, spr))
drawerargs.DrawMaskedColumn(thread, x, WallSpriteTile, walltexcoords, texturemid, maskedScaleY, sprflipvert, mfloorclip, mceilingclip, spr->RenderStyle); drawerargs.DrawMaskedColumn(thread, x, WallSpriteTile, walltexcoords, sprflipvert, mfloorclip, mceilingclip, spr->RenderStyle);
light += lightstep; light += lightstep;
x++;
} }
} }
} }

View file

@ -43,34 +43,19 @@ namespace swrenderer
colfunc = &SWPixelFormatDrawers::DrawColumn; colfunc = &SWPixelFormatDrawers::DrawColumn;
} }
void SpriteDrawerArgs::DrawMaskedColumn(RenderThread* thread, int x, FSoftwareTexture* WallSpriteTile, const ProjectedWallTexcoords& walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short* mfloorclip, const short* mceilingclip, FRenderStyle style) void SpriteDrawerArgs::DrawMaskedColumn(RenderThread* thread, int x, FSoftwareTexture* WallSpriteTile, const ProjectedWallTexcoords& walltexcoords, bool sprflipvert, const short* mfloorclip, const short* mceilingclip, FRenderStyle style)
{ {
auto viewport = thread->Viewport.get(); auto viewport = thread->Viewport.get();
float iscale = walltexcoords.VStep[x] * maskedScaleY; float iscale = walltexcoords.VStep(x) * walltexcoords.yscale;
double spryscale = 1 / iscale; double spryscale = 1 / iscale;
double sprtopscreen; double sprtopscreen;
if (sprflipvert) if (sprflipvert)
sprtopscreen = viewport->CenterY + texturemid * spryscale; sprtopscreen = viewport->CenterY + walltexcoords.texturemid * spryscale;
else else
sprtopscreen = viewport->CenterY - texturemid * spryscale; sprtopscreen = viewport->CenterY - walltexcoords.texturemid * spryscale;
DrawMaskedColumn(thread, x, FLOAT2FIXED(iscale), WallSpriteTile, walltexcoords.UPos[x], spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, style); DrawMaskedColumn(thread, x, FLOAT2FIXED(iscale), WallSpriteTile, walltexcoords.UPos(x), spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, style);
}
void SpriteDrawerArgs::DrawMaskedColumn(RenderThread* thread, int x, FSoftwareTexture* WallSpriteTile, const DrawSegmentWallTexcoords& walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short* mfloorclip, const short* mceilingclip, FRenderStyle style)
{
auto viewport = thread->Viewport.get();
float iscale = walltexcoords.VStep[x] * maskedScaleY;
double spryscale = 1 / iscale;
double sprtopscreen;
if (sprflipvert)
sprtopscreen = viewport->CenterY + texturemid * spryscale;
else
sprtopscreen = viewport->CenterY - texturemid * spryscale;
DrawMaskedColumn(thread, x, FLOAT2FIXED(iscale), WallSpriteTile, walltexcoords.UPos[x], spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, style);
} }
void SpriteDrawerArgs::DrawMaskedColumn(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *tex, fixed_t col, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style, bool unmasked) void SpriteDrawerArgs::DrawMaskedColumn(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *tex, fixed_t col, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style, bool unmasked)

View file

@ -10,7 +10,6 @@ namespace swrenderer
{ {
class RenderThread; class RenderThread;
class ProjectedWallTexcoords; class ProjectedWallTexcoords;
class DrawSegmentWallTexcoords;
class VoxelBlock class VoxelBlock
{ {
@ -35,8 +34,7 @@ namespace swrenderer
void SetSolidColor(int color) { dc_color = color; dc_color_bgra = GPalette.BaseColors[color]; } void SetSolidColor(int color) { dc_color = color; dc_color_bgra = GPalette.BaseColors[color]; }
void SetDynamicLight(uint32_t color) { dynlightcolor = color; } void SetDynamicLight(uint32_t color) { dynlightcolor = color; }
void DrawMaskedColumn(RenderThread* thread, int x, FSoftwareTexture* WallSpriteTile, const ProjectedWallTexcoords& walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short* mfloorclip, const short* mceilingclip, FRenderStyle style); void DrawMaskedColumn(RenderThread* thread, int x, FSoftwareTexture* WallSpriteTile, const ProjectedWallTexcoords& walltexcoords, bool sprflipvert, const short* mfloorclip, const short* mceilingclip, FRenderStyle style);
void DrawMaskedColumn(RenderThread* thread, int x, FSoftwareTexture* WallSpriteTile, const DrawSegmentWallTexcoords& walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short* mfloorclip, const short* mceilingclip, FRenderStyle style);
void DrawMaskedColumn(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *texture, fixed_t column, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style, bool unmasked = false); void DrawMaskedColumn(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *texture, fixed_t column, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style, bool unmasked = false);
void FillColumn(RenderThread *thread); void FillColumn(RenderThread *thread);
void DrawVoxelBlocks(RenderThread *thread, const VoxelBlock *blocks, int blockcount); void DrawVoxelBlocks(RenderThread *thread, const VoxelBlock *blocks, int blockcount);

View file

@ -86,6 +86,7 @@ static const FLOP FxFlops[] =
{ NAME_Round, FLOP_ROUND, [](double v) { return round(v); } }, { NAME_Round, FLOP_ROUND, [](double v) { return round(v); } },
}; };
static bool AreCompatiblePointerTypes(PType* dest, PType* source, bool forcompare = false);
//========================================================================== //==========================================================================
// //
@ -143,9 +144,12 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos)
// A prototype that defines fewer return types can be compatible with // A prototype that defines fewer return types can be compatible with
// one that defines more if the shorter one matches the initial types // one that defines more if the shorter one matches the initial types
// for the longer one. // for the longer one.
bool swapped = false;
if (ReturnProto->ReturnTypes.Size() < proto->ReturnTypes.Size()) if (ReturnProto->ReturnTypes.Size() < proto->ReturnTypes.Size())
{ // Make proto the shorter one to avoid code duplication below. { // Make proto the shorter one to avoid code duplication below.
swapvalues(proto, ReturnProto); swapvalues(proto, ReturnProto);
swapped = true;
} }
// If one prototype returns nothing, they both must. // If one prototype returns nothing, they both must.
if (proto->ReturnTypes.Size() == 0) if (proto->ReturnTypes.Size() == 0)
@ -159,9 +163,13 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos)
{ {
for (unsigned i = 0; i < proto->ReturnTypes.Size(); i++) for (unsigned i = 0; i < proto->ReturnTypes.Size(); i++)
{ {
if (ReturnProto->ReturnTypes[i] != proto->ReturnTypes[i]) PType* expected = ReturnProto->ReturnTypes[i];
PType* actual = proto->ReturnTypes[i];
if (swapped) swapvalues(expected, actual);
if (expected != actual && !AreCompatiblePointerTypes(expected, actual))
{ // Incompatible { // Incompatible
Printf("Return type %s mismatch with %s\n", ReturnProto->ReturnTypes[i]->DescriptiveName(), proto->ReturnTypes[i]->DescriptiveName()); Printf("Return type %s mismatch with %s\n", expected->DescriptiveName(), actual->DescriptiveName());
fail = true; fail = true;
break; break;
} }
@ -274,7 +282,7 @@ static PFunction *FindBuiltinFunction(FName funcname)
// //
//========================================================================== //==========================================================================
static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare = false) static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare)
{ {
if (dest->isPointer() && source->isPointer()) if (dest->isPointer() && source->isPointer())
{ {
@ -10708,27 +10716,44 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx)
PPrototype *retproto; PPrototype *retproto;
if (ctx.ReturnProto != nullptr && ctx.ReturnProto->ReturnTypes.Size() == 0 && ctx.ReturnProto->ReturnTypes.Size() != Args.Size()) const bool hasProto = ctx.ReturnProto != nullptr;
const unsigned protoRetCount = hasProto ? ctx.ReturnProto->ReturnTypes.Size() : 0;
const unsigned retCount = Args.Size();
int mismatchSeverity = -1;
if (hasProto)
{ {
int severity = ctx.Version >= MakeVersion(3, 7) ? MSG_ERROR : MSG_WARNING; if (protoRetCount == 0 && retCount == 1)
ScriptPosition.Message(severity, "Incorrect number of return values. Got %u, but expected %u", Args.Size(), ctx.ReturnProto->ReturnTypes.Size()); {
if (severity == MSG_ERROR) // Handle the case with void function returning something, but only for one value
// It was accepted in previous versions, do not abort with fatal error when compiling old scripts
mismatchSeverity = ctx.Version >= MakeVersion(3, 7) ? MSG_ERROR : MSG_WARNING;
}
else if (protoRetCount < retCount)
{
mismatchSeverity = MSG_ERROR;
}
}
if (mismatchSeverity != -1)
{
ScriptPosition.Message(mismatchSeverity, "Incorrect number of return values. Got %u, but expected %u", Args.Size(), ctx.ReturnProto->ReturnTypes.Size());
if (mismatchSeverity == MSG_ERROR)
{ {
delete this; delete this;
return nullptr; return nullptr;
} }
// For older script versions this must fall through.
} }
if (Args.Size() == 0) if (retCount == 0)
{ {
TArray<PType *> none(0); TArray<PType *> none(0);
retproto = NewPrototype(none, none); retproto = NewPrototype(none, none);
} }
else if (Args.Size() == 1) else if (retCount == 1)
{ {
// If we already know the real return type we need at least try to cast the value to its proper type (unless in an anonymous function.) // If we already know the real return type we need at least try to cast the value to its proper type (unless in an anonymous function.)
if (ctx.ReturnProto != nullptr && ctx.ReturnProto->ReturnTypes.Size() > 0 && ctx.Function->SymbolName != NAME_None) if (hasProto && protoRetCount > 0 && ctx.Function->SymbolName != NAME_None)
{ {
Args[0] = new FxTypeCast(Args[0], ctx.ReturnProto->ReturnTypes[0], false, false); Args[0] = new FxTypeCast(Args[0], ctx.ReturnProto->ReturnTypes[0], false, false);
Args[0] = Args[0]->Resolve(ctx); Args[0] = Args[0]->Resolve(ctx);
@ -10738,7 +10763,7 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx)
} }
else else
{ {
for (unsigned i = 0; i < Args.Size(); i++) for (unsigned i = 0; i < retCount; i++)
{ {
Args[i] = new FxTypeCast(Args[i], ctx.ReturnProto->ReturnTypes[i], false, false); Args[i] = new FxTypeCast(Args[i], ctx.ReturnProto->ReturnTypes[i], false, false);
Args[i] = Args[i]->Resolve(ctx); Args[i] = Args[i]->Resolve(ctx);

View file

@ -39,6 +39,7 @@
EXTERN_CVAR (Bool, ticker); EXTERN_CVAR (Bool, ticker);
EXTERN_CVAR (Bool, noisedebug); EXTERN_CVAR (Bool, noisedebug);
EXTERN_CVAR (Int, am_cheat); EXTERN_CVAR (Int, am_cheat);
EXTERN_CVAR (Int, cl_blockcheats);
struct cheatseq_t struct cheatseq_t
{ {
@ -300,6 +301,7 @@ static cheatseq_t SpecialCheats[] =
CVAR(Bool, allcheats, false, CVAR_ARCHIVE) CVAR(Bool, allcheats, false, CVAR_ARCHIVE)
CVAR(Bool, nocheats, false, CVAR_ARCHIVE)
// Respond to keyboard input events, intercept cheats. // Respond to keyboard input events, intercept cheats.
// [RH] Cheats eat the last keypress used to trigger them // [RH] Cheats eat the last keypress used to trigger them
@ -307,7 +309,11 @@ bool ST_Responder (event_t *ev)
{ {
bool eat = false; bool eat = false;
if (!allcheats) if (nocheats || !!cl_blockcheats || (gameinfo.nokeyboardcheats && !allcheats))
{
return false;
}
else if (!allcheats)
{ {
cheatseq_t *cheats; cheatseq_t *cheats;
int numcheats; int numcheats;

View file

@ -1187,6 +1187,7 @@ OptionMenu "MiscOptions" protected
} }
Option "$MISCMNU_QUERYIWAD", "queryiwad", "OnOff" Option "$MISCMNU_QUERYIWAD", "queryiwad", "OnOff"
StaticText " " StaticText " "
Option "$MISCMNU_NOCHEATS", "nocheats", "OnOff"
Option "$MISCMNU_ALLCHEATS", "allcheats", "OnOff" Option "$MISCMNU_ALLCHEATS", "allcheats", "OnOff"
Option "$MISCMNU_ENABLEAUTOSAVES", "disableautosave", "Autosave" Option "$MISCMNU_ENABLEAUTOSAVES", "disableautosave", "Autosave"
Option "$MISCMNU_SAVELOADCONFIRMATION", "saveloadconfirmation", "OnOff" Option "$MISCMNU_SAVELOADCONFIRMATION", "saveloadconfirmation", "OnOff"

View file

@ -6,6 +6,7 @@ version "4.2"
#include "zscript/constants.zs" #include "zscript/constants.zs"
#include "zscript/events.zs" #include "zscript/events.zs"
#include "zscript/destructible.zs" #include "zscript/destructible.zs"
#include "zscript/level_postprocessor.zs"
#include "zscript/level_compatibility.zs" #include "zscript/level_compatibility.zs"
#include "zscript/actors/actor.zs" #include "zscript/actors/actor.zs"

View file

@ -1,8 +1,6 @@
class LevelCompatibility native play class LevelCompatibility : LevelPostProcessor
{ {
native LevelLocals level;
protected void Apply(Name checksum, String mapname) protected void Apply(Name checksum, String mapname)
{ {
switch (checksum) switch (checksum)
@ -1461,77 +1459,4 @@ class LevelCompatibility native play
} }
} }
} }
protected native void ClearSectorTags(int sector);
protected native void AddSectorTag(int sector, int tag);
protected native void ClearLineIDs(int line);
protected native void AddLineID(int line, int tag);
protected native void OffsetSectorPlane(int sector, int plane, double offset);
protected native void SetThingSkills(int thing, int skills);
protected native void SetThingXY(int thing, double x, double y);
protected native void SetThingZ(int thing, double z);
protected native void SetThingFlags(int thing, int flags);
protected native void SetVertex(uint vertex, double x, double y);
protected native void SetLineSectorRef(uint line, uint side, uint sector);
protected native Actor GetDefaultActor(Name actorclass);
protected void SetWallTexture(int line, int side, int texpart, String texture)
{
SetWallTextureID(line, side, texpart, TexMan.CheckForTexture(texture, TexMan.Type_Wall));
}
protected void SetWallTextureID(int line, int side, int texpart, TextureID texture)
{
level.Lines[line].sidedef[side].SetTexture(texpart, texture);
}
protected void SetLineFlags(int line, int setflags, int clearflags = 0)
{
level.Lines[line].flags = (level.Lines[line].flags & ~clearflags) | setflags;
}
protected void SetLineActivation(int line, int acttype)
{
level.Lines[line].activation = acttype;
}
protected void ClearLineSpecial(int line)
{
level.Lines[line].special = 0;
}
protected void SetLineSpecial(int line, int special, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0, int arg5 = 0)
{
level.Lines[line].special = special;
level.Lines[line].args[0] = arg1;
level.Lines[line].args[1] = arg2;
level.Lines[line].args[2] = arg3;
level.Lines[line].args[3] = arg4;
level.Lines[line].args[4] = arg5;
}
protected void SetSectorSpecial(int sectornum, int special)
{
level.sectors[sectornum].special = special;
}
protected void SetSectorTextureID(int sectornum, int plane, TextureID texture)
{
level.sectors[sectornum].SetTexture(plane, texture);
}
protected void SetSectorTexture(int sectornum, int plane, String texture)
{
SetSectorTextureID(sectornum, plane, TexMan.CheckForTexture(texture, TexMan.Type_Flat));
}
protected void SetSectorLight(int sectornum, int newval)
{
level.sectors[sectornum].SetLightLevel(newval);
}
protected void SetWallYScale(int line, int side, int texpart, double scale)
{
level.lines[line].sidedef[side].SetTextureYScale(texpart, scale);
}
} }

View file

@ -0,0 +1,121 @@
class LevelPostProcessor native play
{
protected native LevelLocals level;
protected void Apply(Name checksum, String mapname)
{
}
protected native void ClearSectorTags(int sector);
protected native void AddSectorTag(int sector, int tag);
protected native void ClearLineIDs(int line);
protected native void AddLineID(int line, int tag);
protected native void OffsetSectorPlane(int sector, int plane, double offset);
const SKILLS_ALL = 31;
const MODES_ALL = MTF_SINGLE | MTF_COOPERATIVE | MTF_DEATHMATCH;
protected native uint GetThingCount();
protected native uint AddThing(int ednum, Vector3 pos, int angle = 0, uint skills = SKILLS_ALL, uint flags = MODES_ALL);
protected native int GetThingEdNum(uint thing);
protected native void SetThingEdNum(uint thing, int ednum);
protected native vector3 GetThingPos(uint thing);
protected native void SetThingXY(uint thing, double x, double y);
protected native void SetThingZ(uint thing, double z);
protected native int GetThingAngle(uint thing);
protected native void SetThingAngle(uint thing, int angle);
protected native uint GetThingSkills(uint thing);
protected native void SetThingSkills(uint thing, uint skills);
protected native uint GetThingFlags(uint thing);
protected native void SetThingFlags(uint thing, uint flags);
protected native int GetThingID(uint thing);
protected native void SetThingID(uint thing, int id);
protected native int GetThingSpecial(uint thing);
protected native void SetThingSpecial(uint thing, int special);
protected native int GetThingArgument(uint thing, uint index);
protected native Name GetThingStringArgument(uint thing);
protected native void SetThingArgument(uint thing, uint index, int value);
protected native void SetThingStringArgument(uint thing, Name value);
protected native void SetVertex(uint vertex, double x, double y);
protected native void SetLineVertexes(uint Line, uint v1, uint v2);
protected native void FlipLineSideRefs(uint Line);
protected native void SetLineSectorRef(uint line, uint side, uint sector);
protected native Actor GetDefaultActor(Name actorclass);
protected void FlipLine(uint Line)
{
uint v1 = level.lines[Line].v1.Index();
uint v2 = level.lines[Line].v2.Index();
SetLineVertexes(Line, v2, v1);
}
protected void SetWallTexture(int line, int side, int texpart, String texture)
{
SetWallTextureID(line, side, texpart, TexMan.CheckForTexture(texture, TexMan.Type_Wall));
}
protected void SetWallTextureID(int line, int side, int texpart, TextureID texture)
{
level.Lines[line].sidedef[side].SetTexture(texpart, texture);
}
protected void SetLineFlags(int line, int setflags, int clearflags = 0)
{
level.Lines[line].flags = (level.Lines[line].flags & ~clearflags) | setflags;
}
protected void SetLineActivation(int line, int acttype)
{
level.Lines[line].activation = acttype;
}
protected void ClearLineSpecial(int line)
{
level.Lines[line].special = 0;
}
protected void SetLineSpecial(int line, int special, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0, int arg5 = 0)
{
level.Lines[line].special = special;
level.Lines[line].args[0] = arg1;
level.Lines[line].args[1] = arg2;
level.Lines[line].args[2] = arg3;
level.Lines[line].args[3] = arg4;
level.Lines[line].args[4] = arg5;
}
protected void SetSectorSpecial(int sectornum, int special)
{
level.sectors[sectornum].special = special;
}
protected void SetSectorTextureID(int sectornum, int plane, TextureID texture)
{
level.sectors[sectornum].SetTexture(plane, texture);
}
protected void SetSectorTexture(int sectornum, int plane, String texture)
{
SetSectorTextureID(sectornum, plane, TexMan.CheckForTexture(texture, TexMan.Type_Flat));
}
protected void SetSectorLight(int sectornum, int newval)
{
level.sectors[sectornum].SetLightLevel(newval);
}
protected void SetWallYScale(int line, int side, int texpart, double scale)
{
level.lines[line].sidedef[side].SetTextureYScale(texpart, scale);
}
}

View file

@ -862,10 +862,10 @@ class StatusScreen abstract play version("2.5")
enteringPatch = TexMan.CheckForTexture("WIENTER", TexMan.Type_MiscPatch); // "entering" enteringPatch = TexMan.CheckForTexture("WIENTER", TexMan.Type_MiscPatch); // "entering"
finishedPatch = TexMan.CheckForTexture("WIF", TexMan.Type_MiscPatch); // "finished" finishedPatch = TexMan.CheckForTexture("WIF", TexMan.Type_MiscPatch); // "finished"
lnametexts[0] = wbstartstruct.thisname; lnametexts[0] = StringTable.Localize(wbstartstruct.thisname);
lnametexts[1] = wbstartstruct.nextname; lnametexts[1] = StringTable.Localize(wbstartstruct.nextname);
authortexts[0] = wbstartstruct.thisauthor; authortexts[0] = StringTable.Localize(wbstartstruct.thisauthor);
authortexts[1] = wbstartstruct.nextauthor; authortexts[1] = StringTable.Localize(wbstartstruct.nextauthor);
bg = InterBackground.Create(wbs); bg = InterBackground.Create(wbs);
noautostartmap = bg.LoadBackground(false); noautostartmap = bg.LoadBackground(false);

View file

@ -320,6 +320,7 @@ class BaseStatusBar native ui
virtual void Init() virtual void Init()
{ {
SetSize(0, 320, 200);
} }
native virtual void Tick (); native virtual void Tick ();