Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
kb1

Texture offset fix for non-ZDoom software rendering of segs with bad offsets

Recommended Posts

Upon working on my home source port (details pending), I loaded DV map 5, and noticed some screwed-up texture offset rendering. Sorry, no screenshots, but it can be seen also in PrBoom-Plus, and, perhaps others by navigating to coordinates (400, -12345), and looking west. The wall is actually two textures, MARB_1A on the top, and MARB_1B on the bottom. The top is where the trouble occurs.

It appears that the trouble is caused by the node builder (I'm assuming ZDBSP?) applying offsets to the wrong segs.

This code, placed at the bottom of P_LoadSegs, inside the for loop fixes it, by recalculating all seg offsets:

// [kb] recalculate seg offsets that are sometimes incorrect
// with certain nodebuilders. Fixes among others, line 20365
// of DV.wad, map 5
{
vertex_t *start_vertex;

start_vertex = side ? ldef->v2 : ldef->v1;

if (start_vertex == li->v1)
li->offset = 0;

else
{
int dx = (start_vertex->x - li->v1->x) >> FRACBITS;
int dy = (start_vertex->y - li->v1->y) >> FRACBITS;

if (dx)
{
if (dy)
li->offset = ((int)(sqrt(dx * dx + dy * dy) + 0.5)) << FRACBITS;
else
li->offset = abs(dx) << FRACBITS;
}

else
li->offset = abs(dy) << FRACBITS;
}
}

Apparently, ZDoom doesn't use the SEGS offsets, so maps created with ZDBSP for ZDoom don't exhibit the problem.

Honestly, I haven't tested it too thoroughly to see if it causes any trouble elsewhere, but, it seems correct on the maps I've tried so far, and I wanted to share it.

Share this post


Link to post

The ZDBSP bug has long been fixed but I still don't understand why all other ports still exclusively rely on this information from the segs.

Share this post


Link to post

Yeah, it takes time to work on Doom, man! Completely rewriting the renderer is quite an undertaking. I currently have 3 typed pages of to-dos in my port, even before releasing it, and I've been working on it for longer than I care to admit. You know what I mean.

Share this post


Link to post
Graf Zahl said:

The ZDBSP bug has long been fixed but I still don't understand why all other ports still exclusively rely on this information from the segs.

Doomsday hasn't used the seg offsets since it got its own nodebuilder.

Share this post


Link to post
Graf Zahl said:

but I still don't understand why all other ports still exclusively rely on this information from the segs.

EDGE has had the following code for a long time:

float sx = seg->side ? seg->linedef->v2->x : seg->linedef->v1->x;
float sy = seg->side ? seg->linedef->v2->y : seg->linedef->v1->y;

seg->offset = R_PointToDist(sx, sy, seg->v1->x, seg->v1->y);

Share this post


Link to post

Is code from the first post correct?

I have applied it to prboom-plus. Makes sense for software renderer, because glboom+ does not use seg offsets at all.

Share this post


Link to post

This is the code that EE uses for calculating the seg offsets for dynamic segs:

//
// R_DynaSegOffset
//
// Computes the offset value of the seg relative to its parent linedef.
// Not terribly fast.
// Derived from BSP 5.2 SplitDist routine.
//
static void R_DynaSegOffset(seg_t *seg, line_t *line)
{
   double t;
   double dx = line->v1->fx - seg->v1->fx;
   double dy = line->v1->fy - seg->v1->fy;
 
   if(dx == 0.0 && dy == 0.0)
      t = 0;
   else
      t = sqrt((dx * dx) + (dy * dy));

   seg->offset = (float)t;
}
I don't see why the same approach wouldn't work on normal static segs; I just haven't gotten around to it.

Share this post


Link to post
Graf Zahl said:

but I still don't understand why all other ports still exclusively rely on this information from the segs.


...it is, after all, the job of the source port to compensate for poorly written node builders...

Share this post


Link to post
SoM said:

...it is, after all, the job of the source port to compensate for poorly written node builders...

I think it is an established fact that poorly-made levels are an integral part of the Doom experience. Even the IWADs have their share of bogus levels, that happen to work just because the original software is rather tolerant towards glitches.

Share this post


Link to post
SoM said:

...it is, after all, the job of the source port to compensate for poorly written node builders...



I think that any software that relies on all data being correct, despite knowing that this isn't always the case, is also poorly written...

Yes, the ZDBSP bug has been fixed for years but I know of at least one other node builder that had problems with this offset value (WARM.)

Share this post


Link to post

Yknow, the segs offset could be used to create offsets per line on wall (i.e. single line) w/ texture with multiple offsets. Kinda like the BLOCKMAP trick...

Share this post


Link to post
GhostlyDeath said:

Yknow, the segs offset could be used to create offsets per line on wall (i.e. single line) w/ texture with multiple offsets. Kinda like the BLOCKMAP trick...

Er...I'm not sure I see how this would be capable of doing anything that isn't far easier and cleaner to do by just putting a vertex in the middle of the line and aligning it that way.

Share this post


Link to post

How should that even work, considering that the mapper has no influence whatsoever over the nodebuilder's decision where to split lines...?

Share this post


Link to post

The 'BSP' nodebuilder (by Colin Reed and Lee Killough) had the following feature:

Furthermore, just for grins, if the linedef's tag is 999, then the sidedefs' x-offsets set an angle adjustment in degrees to be applied -- you can look straight at a wall, but it might come right at you on both sides and "stretch".

I wonder if anyone ever used it... :)

The angle is another field that ports tend to compute themselves nowadays.

Share this post


Link to post
andrewj said:

The 'BSP' nodebuilder (by Colin Reed and Lee Killough) had the following feature:

I wonder if anyone ever used it... :)

The angle is another field that ports tend to compute themselves nowadays.

EE already doesn't support that trick, due to changes made in Cardboard (seg->angle no longer exists as it is not used for anything, ever).

Share this post


Link to post
Graf Zahl said:

I think that any software that relies on all data being correct, despite knowing that this isn't always the case, is also poorly written...


Adherence to specifications != poorly written, sorry. Also, versions of several node builders have had this bug. I'm not attacking ZDBSP or anything. If I take a random pattern of 0-F's and throw it into a map lump and it crashes Zdoom, that doesn't mean Zdoom is poorly written, it means Garbage in->Garbage out kthx.

Share this post


Link to post
SoM said:

Adherence to specifications != poorly written, sorry. Also, versions of several node builders have had this bug. I'm not attacking ZDBSP or anything. If I take a random pattern of 0-F's and throw it into a map lump and it crashes Zdoom, that doesn't mean Zdoom is poorly written, it means Garbage in->Garbage out kthx.



... but if the garbage can be detected to avoid the crash it will be done.

Ignoring a problem that is well known and easy to circumvent, however, is just stupid.

PrBoom+ has added a fix for this recently, btw.

Share this post


Link to post
Graf Zahl said:

... but if the garbage can be detected to avoid the crash it will be done.

SoM is kidding you! :)

Look at the few latest revisions of EE.

1. Scan forward for a MUS\x1a header signature at the beginning of a MUS lump, which apparently DMX was capable of doing vis-a-vis DIESCUM.WAD. Thanks to TheGreenHerring.

2. So this should finally squash the stupid rendering bugs with the stupid wad at stupid low-res.

3. Eternity can now play one of the worst wads ever made without rendering errors. Thanks CSonicGo! :D

4. Added P_VerifyBlockMap in order to let Eternity play what is possibly one of the worst levels ever made.

Do not sure about 2 and 3, but 1 and 4 are "garbage in"

Share this post


Link to post
Graf Zahl said:

... but if the garbage can be detected to avoid the crash it will be done.

Ignoring a problem that is well known and easy to circumvent, however, is just stupid.

PrBoom+ has added a fix for this recently, btw.


Avoiding a crash and seg offsets are SLLLOIIIIIIGGGGHHHHHHTTTTLLLLLLYYYYYY different. But my point still stands. If there is some wad with shitty nodes or some other problem due to shitty construction, I don't lose sleep over it. I absolutely hate having to hack up a perfectly valid design because some people can't figure out how to generate valid data.

Share this post


Link to post

Don't get me wrong, EE will probably add the 'fix' but I just think while we're at it we might as well add code to auto-generate map data because people might be too stupid to make this correctly as well. Eventually you reach a point where it becomes retarded to try and fix everyone's invalid wads within the source port.

Share this post


Link to post
SoM said:

Don't get me wrong, EE will probably add the 'fix' but I just think while we're at it we might as well add code to auto-generate map data because people might be too stupid to make this correctly as well. Eventually you reach a point where it becomes retarded to try and fix everyone's invalid wads within the source port.

There *is* a point where you can cross the line; I'm just not sure where it is myself :) My own standards have softened up considerably over the years - I was initially a hardliner. Broken data == no play. But now I realize it's more convenient to the user if you can gloss over the simpler problems that exist out there in the wild.

Share this post


Link to post
SoM said:

I absolutely hate having to hack up a perfectly valid design.



So having some perfectly redundant data around is 'valid design'?

I always wondered what the point was of keeping such useless nonsense like the offsets and angles which can be trivially calculated at map load in the seg data while at the same time shaving valuable bytes off fields that really needed more than they got (Like the line id issue in Hexen map format, for example.)

BTW, if you ever are going to support compressed nodes you'll have to do something anyway because they rightfully dump all this redundant stuff because it'd only inflate the stored data.


because some people can't figure out how to generate valid data.


That's life. You'll have to accept it.

Share this post


Link to post
Graf Zahl said:

That's life. You'll have to accept it.

So you probably want to avoid crashing on map30 with some DEHs

gzdoom 32innail.wad -warp 30

You need something like

  if (!newmobj || !newmobj->state || newmobj->momy == 0 || newmobj->state->tics == 0)
    I_Error("A_BrainSpit: can't spawn brain missile (incorrect DEH)");
in A_BrainSpit()

Share this post


Link to post

No need to. That situation cannot happen in ZDoom because the cube timing is done differently (so that it doesn't have to assume that all travelling states have the same duration) and the assumption that momy is not 0 has been taken care of long ago.

Share this post


Link to post

Why would anyone want to play MAP30 of 32-inch nails when it only has MAP01 to MAP07?

Anyway, it does crash, but because somehow the AActor * self pointer manages to be null...

Share this post


Link to post

<u>Entryway said:</u>
<quote>Is code from the first post correct?</quote>
It appears to be. I've been using it without issues for a while now. Not so sure about the + 0.5 stuff, I put that in to try to make it more precise, but it may not be necessary.

<u>On 'Garbage in/garbage out':</u>
I can't completely agree that engines that cannot handle all manners of crap data are poorly written. And, technically, the fix I posted actually causes Doom to bypass the 'standard'. I guess the point I'm trying to make is that 'looking correct' is sometimes better than 'being correct', especially when that was the effect the author intended.

Both sides have some merit, but, my view is this:
I write code, and can generally debug the occsaional problem with a given wad I may be trying to play, but, when I want to play the game, I don't care about the code - I just want it work. If a launch the game with some half-assed wad, and it crashes, I have to stop and dick with it to get it to work, and that sucks. I sure others would agree. Sure, it sucks when the wad is broken, but, if the port lets me play it, I can then decide if I want to fix the wad, or forget about it.

By the way, I'm a newbie at posting, but I've been lurking forever. Hello all!

Share this post


Link to post

Gee, that last post is crappy. Was I supposed to use brackets instead of < > ?

Share this post


Link to post
kb1 said:

Gee, that last post is crappy. Was I supposed to use brackets instead of < > ?

Yes. Square brackets []. Also, you have "Quote" links below each post.

Share this post


Link to post
Graf Zahl said:

So having some perfectly redundant data around is 'valid design'?


No, FOLLOWING SPECIFICATIONS is good design. PLZ TO RTFM KTHX

If you have a nodebuilder that is going to generate DOOM FORMAT NODES that format includes SEG OFFSETS. If you don't want to worry about 'redundant' data (which, I don't get HOW you can call it that, it's pre-calculated and cached data) then don't write a node builder that claims to output DOOM FORMAT NODES. KTHX

That's life. You'll have to accept it.


You mean like 'some people are going to flame you, that's life, you'll have to accept it'... oh wait... never mind.

Share this post


Link to post
SoM said:

'redundant' data (which, I don't get HOW you can call it that, it's pre-calculated and cached data)

It's trivially recomputable, hence redundant.

By your logic, segs could have a length field and it wouldn't be redundant, even though it is trivially computable from the start/end coordinates.

Share this post


Link to post
Guest
This topic is now closed to further replies.
×