swwmgz_m/zscript/handler/swwm_handler_debugrender.zsc
Marisa the Magician e5e6ce619c Fix severe performance issues in large maps.
So... Remember that one decision I made about avoiding BlockThingsIterator as
much as possible? Turns out that was a stupid idea. There ARE situations where
it's better to iterate sector thinglists, yes, especially for things that are
NOT part of the blockmap, but in other cases, the excess allocations of new
iterators are a reasonable price to pay for the lower perf impact in extreme
cases, such as maps that have a gazillion sectors with gazillions of things in
them (I'm looking at you, UDMF mappers).
As a compromise, at least, in situations where the thinglists are needed, I did
add a sort of micro-optimization by implementing code to check if a bounding
box is inside a sector (would be nice if this was part of GZDoom itself, tho).
2023-12-19 11:46:29 +01:00

122 lines
5.2 KiB
Text

// ported and optimized from old debug test mod
extend Class SWWMHandler
{
ui SWWMProjectionData projdata;
private ui void DrawWorldLine( RenderEvent e, Vector3 apos, Vector3 bpos, Color col )
{
Vector3 a = SWWMUtility.ProjectPoint(projdata,e.viewpos+level.Vec3Diff(e.viewpos,apos)),
b = SWWMUtility.ProjectPoint(projdata,e.viewpos+level.Vec3Diff(e.viewpos,bpos));
if ( (a.z > 1.) && (b.z > 1.) ) return;
if ( (a.z == -double.infinity) || (b.z == -double.infinity) ) return; // how???
double da, db, s;
Vector3 p;
da = a dot (0.,0.,-1.)-1.;
db = b dot (0.,0.,-1.)-1.;
if ( da-db != 0. )
{
s = da/(da-db);
p = (a.x+s*(b.x-a.x),a.y+s*(b.y-a.y),a.z+s*(b.z-a.z));
if ( a.z > 1. ) a = p;
if ( b.z > 1. ) b = p;
}
Vector2 va = SWWMUtility.NDCToViewport(projdata,a);
Vector2 vb = SWWMUtility.NDCToViewport(projdata,b);
Screen.DrawLine(int(va.x),int(va.y),int(vb.x),int(vb.y),col);
}
private ui void DrawWorldCircle( RenderEvent e, Vector3 pos, double radius, Color col )
{
let [x, y, z] = SWWMUtility.GetAxes(e.viewangle,e.viewpitch,e.viewroll);
Vector3 ndc[64];
for ( int i=0; i<64; i++ )
{
Vector3 wpos = e.viewpos+level.Vec3Diff(e.viewpos,level.Vec3Offset(pos,SWWMUtility.CircleOffset(y,z,i*5.625,radius)));
ndc[i] = SWWMUtility.ProjectPoint(projdata,wpos);
}
for ( int i=0; i<64; i++ )
{
Vector3 a = ndc[i], b = ndc[(i+1)%64];
if ( (a.z > 1.) && (b.z > 1.) ) continue;
if ( (a.z == -double.infinity) || (b.z == -double.infinity) ) continue; // how???
double da, db, s;
Vector3 p;
da = a dot (0.,0.,-1.)-1.;
db = b dot (0.,0.,-1.)-1.;
if ( da-db != 0. )
{
s = da/(da-db);
p = (a.x+s*(b.x-a.x),a.y+s*(b.y-a.y),a.z+s*(b.z-a.z));
if ( a.z > 1. ) a = p;
if ( b.z > 1. ) b = p;
}
Vector2 va = SWWMUtility.NDCToViewport(projdata,a);
Vector2 vb = SWWMUtility.NDCToViewport(projdata,b);
Screen.DrawLine(int(va.x),int(va.y),int(vb.x),int(vb.y),col);
}
}
private ui void DrawActor( RenderEvent e, Actor a )
{
Vector3 pos = SWWMUtility.LerpVector3(a.prev,a.pos,e.FracTic);
if ( a is 'DynamicLight' ) DrawWorldCircle(e,pos,a.args[3]*2,Color(a.args[0],a.args[1],a.args[2]));
if ( (a.radius > 0.) && (a.height > 0.) )
{
Vector3 b1, b2;
b1 = pos-(a.radius,a.radius,0);
b2 = pos+(a.radius,a.radius,a.height);
DrawWorldLine(e,(b1.x,b1.y,b1.z),(b1.x,b2.y,b1.z),"White");
DrawWorldLine(e,(b1.x,b2.y,b1.z),(b2.x,b2.y,b1.z),"White");
DrawWorldLine(e,(b2.x,b2.y,b1.z),(b2.x,b1.y,b1.z),"White");
DrawWorldLine(e,(b2.x,b1.y,b1.z),(b1.x,b1.y,b1.z),"White");
DrawWorldLine(e,(b1.x,b1.y,b2.z),(b1.x,b2.y,b2.z),"White");
DrawWorldLine(e,(b1.x,b2.y,b2.z),(b2.x,b2.y,b2.z),"White");
DrawWorldLine(e,(b2.x,b2.y,b2.z),(b2.x,b1.y,b2.z),"White");
DrawWorldLine(e,(b2.x,b1.y,b2.z),(b1.x,b1.y,b2.z),"White");
DrawWorldLine(e,(b1.x,b1.y,b1.z),(b1.x,b1.y,b2.z),"White");
DrawWorldLine(e,(b2.x,b1.y,b1.z),(b2.x,b1.y,b2.z),"White");
DrawWorldLine(e,(b1.x,b2.y,b1.z),(b1.x,b2.y,b2.z),"White");
DrawWorldLine(e,(b2.x,b2.y,b1.z),(b2.x,b2.y,b2.z),"White");
}
let [x, y, z] = SWWMUtility.GetAxes(a.angle,a.pitch,a.roll);
DrawWorldLine(e,pos,pos+x*16,"Red");
DrawWorldLine(e,pos,pos+y*16,"Green");
DrawWorldLine(e,pos,pos+z*16,"Blue");
if ( a.vel != (0,0,0) ) DrawWorldLine(e,pos,pos+a.vel*GameTicRate,"Yellow");
if ( a.target ) DrawWorldLine(e,pos,SWWMUtility.LerpVector3(a.target.prev,a.target.pos,e.FracTic),"Gold");
if ( a.tracer ) DrawWorldLine(e,pos,SWWMUtility.LerpVector3(a.tracer.prev,a.tracer.pos,e.FracTic),"Orange");
if ( a.master ) DrawWorldLine(e,pos,SWWMUtility.LerpVector3(a.master.prev,a.master.pos,e.FracTic),"Purple");
double hdiff = a.Height/2;
if ( a.bFLOATBOB ) hdiff += a.GetBobOffset();
Vector3 ndc = SWWMUtility.ProjectPoint(projdata,e.viewpos+level.Vec3Diff(e.viewpos,pos+(0,0,hdiff)));
if ( ndc.z > 1. ) return;
Vector2 vpos = SWWMUtility.NDCToViewport(projdata,ndc);
String tag = a.player?a.player.GetUserName():a.GetTag();
if ( tag == a.GetClassName() ) SWWMUtility.BeautifyClassName(tag);
Screen.DrawText(NewSmallFont,a.bDROPPED?Font.CR_DARKRED:Font.CR_RED,vpos.x-NewSmallFont.StringWidth(tag)/2,vpos.y-NewSmallFont.GetHeight()/2,tag);
}
private ui void DrawDebug( RenderEvent e )
{
if ( !swwm_debugview ) return;
// prepare projection data, we're going to need this
SWWMUtility.PrepareProjData(projdata,e.ViewPos,e.ViewAngle,e.ViewPitch,e.ViewRoll,players[consoleplayer].fov);
foreach ( s:level.Sectors )
{
// don't check sectors that aren't within bounds, saves some time
if ( !BoxInSectorBounds(s,players[consoleplayer].Camera.pos.xy,1000,players[consoleplayer].Camera.CurSector.PortalGroup) )
continue;
for ( Actor a=s.thinglist; a; a=a.snext )
{
if ( (a == players[consoleplayer].Camera) && !(players[consoleplayer].cheats&CF_CHASECAM) ) continue;
if ( a.bINVISIBLE && !(a is 'DynamicLight') ) continue;
if ( (a is 'Inventory') && Inventory(a).Owner ) continue;
if ( (a is 'SWWMPickupFlash') && (a.CurState == a.FindState('Pickup')) ) continue;
if ( (a is 'SWWMShadow') || (a is 'SWWMItemOverlay') || (a is 'HeadpatTracker') || (a is 'SWWMTeleportLine') || (a is 'SWWMTeleportDest') ) continue;
if ( a.Distance3DSquared(e.Camera) > 1000000 ) continue;
DrawActor(e,a);
}
}
}
}