In R_DrawBEntity, near the end, BSP models that aren't in a single leaf are sent to R_DrawSolidClippedSubmodelPolygons, to be clipped against the world.

In R_DrawSolidClippedSubmodelPolygons, the medge_t data from the model is copied to a bedge_t struct, and then the bedge_t data is passed to R_RecursiveClipBPoly along with the model's surfaces and nodes.

R_RecursiveClipBPoly clips the edges from the medge_t data, and apparently it stores the resulting edges into the local psideedges array. Since this function is recursive, it means that every time it's called, a new copy of psideedges is allocated, so the code can allocate exactly the required amount of RAM for the clipped edges, without ever knowing how many edges will be generated. This is why I couldn't find any data set for clipped edges before. After each finalized polygon is generated, it's sent to R_RenderBmodelFace.

R_RenderBmodelFace calls R_ClipEdge to clip the edges of the polygon against the screen, and stores the resulting data in the surf_t *surfaces list through the surface_p pointer. The surfaces list is allocated in R_NewMap through the line surfaces = Hunk_AllocName (r_cnumsurfs * sizeof (surf_t), "surfaces");

Why such a generic name was used for a global variable so important? I've had to search for surfaces[, *surfaces and surfaces = to be able to track the parts of the code that uses it.

Anyway, R_RenderBmodelFace doesn't do anything afterwards. The surfaces data is rendered through D_DrawSurfaces, which is called by R_ScanEdges, which is called by R_EdgeDrawing after all R_DrawSolidClippedSubmodelPolygons calls have been issued by R_DrawBEntitiesOnList, which R_EdgeDrawing had also called before.

Then it draws them last with R_DrawAlphaSurfaces in R_RenderView. There's no special sorting step. Unwinding the chain draws back to front in correct order. It seems that it would even work if fence textures were in the chain.

It looks like the whole r_ poly.c file from Quake 2 is needed. I'll try to port it.

And I've found a perfect example of how bad the Z-fighting of BSP entities can be. Open the start map of the Contract Revoked mod, and look at the floor of the Normal difficulty room. Both the lava and the bricks on the floor are BSP entities, and there's lots of Z-fighting between them - even though their planes are perpendicular to each other, which surprised me. This happens in all software-rendered Quake engines.

I was thinking about this again... QuakeSpasm's solution of including hacked .ent files for id1 maps is not the greatest.

First train of thought was, -add the face plane (float3 normal, float dist) for each vertex to the VBO for BSP models. -maybe render the world into a float4 FBO color buffer, writing the float4 plane for each fragment.-read from this texture later and use it as sort of a "extact" depth buffer when drawing the bmodels.

Then I saw this on the GL wiki:

On some SGI OpenGL platforms, an application can use the SGIX_reference_plane extension. With this extension, the user specifies a plane equation in object coordinates corresponding to a set of coplanar primitives. You can enable or disable the plane. When the plane is enabled, all fragment Z values will derive from the specified plane equation. Thus, for any given fragment XY location, the depth value is guaranteed to be identical regardless of which primitive rendered it.

SGIX_reference_plane is a 1996 thing, but it should be easy to implement in GLSL, I think? Just calculate gl_FragDepth using only 1) the plane normal+dist, which you'd add as vertex attributes, 2) gl_FragCoord. This would ensure that a door bmodel that's coplanar with a world face would both generate exactly the same depth values, so they wouldn't Z-fight. You'd also need to pass in the bmodel's offset from the origin, and offset the planes stored in the vertex attributes by that much.

ericw wrote:I was thinking about this again... QuakeSpasm's solution of including hacked .ent files for id1 maps is not the greatest.

Easily beats the choice of either having people complain about E1M1 quad area or having evil gl_ztrick 1 enabled by default.

E1M1 is the main source of complaints.

... since most custom single player don't have z-fighting in their maps.

Not ideal, but keeps an engine author from getting the "z-fighting", "z-fighting", "z-fighting" topic coming up again and again and again, since the external .ents make it relatively scarce for an average user.

The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..

Yeah - I mean the .ent's aren't the worst, but if this "emulate SGIX_reference_plane with GLSL" idea actually works, it seems like it would be better, and wouldn't have the issues of adding cracks around secret doors that gl_ztrick does.

If it works, what I was thinking was:- new "gl_zfightingfix" cvar deafults to "auto" which means "enabled on whitelisted original game levels only". You could manually set it to "1" when playing late 90s maps with z-fighting, to get software-renderer-like behaviour, but otherwise it would default to being off.

Last time I played the original levels I noticed several spots where the QS .ent's missed correcting z-fighting, and it is kind of distracting / takes you out of the game.