Skip to content

Conversation

@xezon
Copy link

@xezon xezon commented Oct 18, 2025

Merge with Rebase

This change fixes translucent objects drawn without translucency when no occluders are in the scene.

Additionally the second commit cleans up code in W3DScene a bit to be more readable.

TODO

  • Add pull numbers to commits
  • Replicate in Generals

@xezon xezon added Bug Something is not working right, typically is user facing Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Rendering Is Rendering related labels Oct 18, 2025
{
//object which could occlude other objects that need to be visible.
//Make sure this object is not translucent so it's not rendered twice (from m_potentialOccluders and m_translucentObjectsBuffer)
if (drawInfo->m_flags ^ DrawableInfo::ERF_IS_TRANSLUCENT)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this from xor to and because that should have been the intent here.

@xezon xezon added the Approved Pull Request was approved label Oct 21, 2025
@xezon xezon removed the Gen Relates to Generals label Oct 22, 2025
@xezon
Copy link
Author

xezon commented Oct 22, 2025

This fix is Zero Hour specific. Generals does not have this code because translucent objects are not retained as ocludees, so translucent objects can not be seen through occluders. This change will get to Generals when merging the original code.

@xezon xezon force-pushed the xezon/fix-translucent-render branch from e6a020b to 34acc85 Compare October 22, 2025 17:16
@xezon
Copy link
Author

xezon commented Oct 22, 2025

But the refactor commit was replicable in Generals, with several conflicts.

$ git diff 2a54e1dedeb1fc5629e67191aac552d7316863db..b9dd8dbfad735530562ba61c9212b8c5d6e408bf > changes.patch

$ git apply -p2 --directory=Generals --reject --whitespace=fix changes.patch
changes.patch:267: space before tab in indent.
                                return; //this object was removed by the getShroudedStatus() call.
changes.patch:457: space before tab in indent.
                it.Next();      //advance to next object in case this one gets deleted during renderOneObject().
Checking patch Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DScene.h...
Hunk #5 succeeded at 148 (offset -1 lines).
Hunk #6 succeeded at 162 (offset -1 lines).
Hunk #7 succeeded at 173 (offset -1 lines).
Hunk #8 succeeded at 181 (offset -1 lines).
Checking patch Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp...
Hunk #1 succeeded at 94 (offset -1 lines).
error: while searching for:
//      m_frenzyMaterialPass->Set_Shader(frenzyShader);


        //Allocate memory to hold queue of visible renderobjects that need to be drawn last
        //because they are forced translucent.
        m_translucentObjectsCount = 0;
        if (TheGlobalData->m_maxVisibleTranslucentObjects > 0)

error: patch failed: Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp:146
error: while searching for:

#ifdef USE_NON_STENCIL_OCCLUSION
        for (i=0; i<MAX_PLAYER_COUNT; i++)
        {       m_occludedMaterialPass[i]=NEW_REF(MaterialPassClass,());
                VertexMaterialClass * vmtl = NEW_REF(VertexMaterialClass,());
                vmtl->Set_Lighting(true);
                vmtl->Set_Ambient(0,0,0);       //we're only using emissive so kill all other lights.

error: patch failed: Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp:181
Hunk #4 succeeded at 212 (offset -17 lines).
Hunk #5 succeeded at 279 (offset -17 lines).
Hunk #6 succeeded at 396 (offset -17 lines).
Hunk #7 succeeded at 421 (offset -17 lines).
Hunk #8 succeeded at 449 (offset -17 lines).
error: while searching for:
              continue;

                                                if (draw->getEffectiveOpacity() != 1.0f && m_translucentObjectsCount < TheGlobalData->m_maxVisibleTranslucentObjects)
                                                {       drawInfo->m_flags |= DrawableInfo::ERF_IS_TRANSLUCENT;  //object is translucent
                                                        m_translucentObjectsBuffer[m_translucentObjectsCount++] = robj;
                                                }
                                                if (TheGlobalData->m_enableBehindBuildingMarkers && TheGameLogic && TheGameLogic->getShowBehindBuildingMarkers())
                                                {
                                                        //visible drawable. Check if it's either an occluder or occludee
                                                        if (draw->isKindOf(KINDOF_STRUCTURE) && m_numPotentialOccluders < TheGlobalData->m_maxVisibleOccluderObjects)
                                                        {       //object which could occlude other objects that need to be visible.
                                                                //Make sure this object is not translucent so it's not rendered twice (from m_potentialOccluders and m_translucentObjectsBuffer)
                                                                if (drawInfo->m_flags ^ DrawableInfo::ERF_IS_TRANSLUCENT)
                                                                        m_potentialOccluders[m_numPotentialOccluders++]=robj;
                                                                drawInfo->m_flags |= DrawableInfo::ERF_POTENTIAL_OCCLUDER;
                                                        }
                                                        else
                                                        if (draw->getObject() &&
                                                                        (draw->isKindOf(KINDOF_SCORE) || draw->isKindOf(KINDOF_SCORE_CREATE) || draw->isKindOf(KINDOF_SCORE_DESTROY) || draw->isKindOf(KINDOF_MP_COUNT_FOR_VICTORY)) &&
                                                                        (draw->getObject()->getSafeOcclusionFrame()) <= currentFrame && m_numPotentialOccludees < TheGlobalData->m_maxVisibleOccludeeObjects)
                                                        {       //object which could be occluded but still needs to be visible.
                                                                //We process transucent units twice (also in m_translucentObjectsBuffer) because we need to see them when occluded.
                                                                m_potentialOccludees[m_numPotentialOccludees++]=robj;
                                                                drawInfo->m_flags |= DrawableInfo::ERF_POTENTIAL_OCCLUDEE;
                                                        }
                                                        else
                                                        if (drawInfo->m_flags == DrawableInfo::ERF_IS_NORMAL && m_numNonOccluderOrOccludee < TheGlobalData->m_maxVisibleNonOccluderOrOccludeeObjects)
                                                        {       //regular object with no custom effects but still needs to be delayed to get the occlusion feature to work correctly.
                                                                //Make sure this object is not translucent so it's not rendered twice (from m_potentialOccluders and m_translucentObjectsBuffer)
                                                                if (drawInfo->m_flags ^ DrawableInfo::ERF_IS_TRANSLUCENT)  //make sure not translucent
                                                                        m_nonOccludersOrOccludees[m_numNonOccluderOrOccludee++]=robj;
                                                                drawInfo->m_flags |= DrawableInfo::ERF_IS_NON_OCCLUDER_OR_OCCLUDEE;
                                                        }

error: patch failed: Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp:477
Hunk #10 succeeded at 554 (offset -28 lines).
error: while searching for:
        Bool doExtraFlagsPop=FALSE;
        LightClass **sceneLights=m_globalLight;



        if (robj->Class_ID() == RenderObjClass::CLASSID_IMAGE3D )
        {       robj->Render(rinfo);    //notify decals system that this track is visible
                return; //decals are not lit by this system yet so skip rest of lighting
        }


error: patch failed: Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp:583
Hunk #12 succeeded at 572 (offset -29 lines).
error: while searching for:
                                return; //this object was removed by the getShroudedStatus() call.
                }
                else
                {       //drawable with no object so no way to know if it's shrouded.
                        ss = OBJECTSHROUD_CLEAR;        //assume not shrouded/fogged.
                        //Check to see if there is another unrelated object which controls the shroud status
                        //(Hack for prison camps which contain enemy prisoner drawables)
                        if (drawInfo->m_shroudStatusObjectID != INVALID_ID)
                        {       Object *shroudObject=TheGameLogic->findObjectByID(drawInfo->m_shroudStatusObjectID);
                                if (shroudObject && shroudObject->getShroudedStatus(localPlayerIndex) >= OBJECTSHROUD_FOGGED)
                                        ss = OBJECTSHROUD_SHROUDED;     //we will assume that drawables without objects are 'particle' like and therefore don't need drawing if fogged/shrouded.
                        }
                }

                if (draw->isKindOf(KINDOF_INFANTRY))
                {       //ambient = m_infantryAmbient;  //has no effect - see comment on m_infantryAmbient
                        sceneLights = m_infantryLight;
                }


error: patch failed: Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp:635
Hunk #14 succeeded at 699 (offset -41 lines).
Hunk #15 succeeded at 715 (offset -41 lines).
Hunk #16 succeeded at 764 (offset -44 lines).
error: while searching for:
        }

        rinfo.light_environment = NULL;
        if (doExtraMaterialPop) //check if there is an extra material on the stack from the add'l material effect.
                rinfo.Pop_Material_Pass();
        if (doExtraFlagsPop)
                rinfo.Pop_Override_Flags();     //flags used to disable base pass and only render custom heat vision pass.

error: patch failed: Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp:818
Hunk #18 succeeded at 808 (offset -44 lines).
Hunk #19 succeeded at 824 (offset -48 lines).
Hunk #20 succeeded at 837 (offset -48 lines).
error: while searching for:

        Vector3 oldDiffuse, oldAmbient;
        for (Int globalLightIndex = 0; globalLightIndex < m_numGlobalLights; globalLightIndex++)
        {       m_defaultLightEnv.Add_Light(*m_globalLight[globalLightIndex]);
                //copy default lighting for infantry so we can tweak it.
                *m_infantryLight[globalLightIndex]=*m_globalLight[globalLightIndex];
                m_infantryLight[globalLightIndex]->Set_Transform(m_globalLight[globalLightIndex]->Get_Transform());

error: patch failed: Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp:890
Hunk #22 succeeded at 925 (offset -55 lines).
Hunk #23 succeeded at 956 (offset -55 lines).
Hunk #24 succeeded at 1002 (offset -55 lines).
Hunk #25 succeeded at 1095 (offset -55 lines).
Hunk #26 succeeded at 1117 (offset -55 lines).
Hunk #27 succeeded at 1142 (offset -55 lines).
Hunk #28 succeeded at 1171 (offset -55 lines).
Hunk #29 succeeded at 1212 (offset -55 lines).
Hunk #30 succeeded at 1228 (offset -55 lines).
Hunk #31 succeeded at 1242 (offset -55 lines).
error: while searching for:
        //We do this so that all objects are sorted by color which reduces the number of
        //state changes needed when drawing them.
        for (Int i=0; i<MAX_PLAYER_COUNT; i++)
        {       lastPlayerObject[i]=&playerObjects[i][0];
                playerColorIndex[i]=-1;
        }


error: patch failed: Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp:1332
Hunk #33 succeeded at 1358 (offset -55 lines).
error: while searching for:
                                                DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILFUNC,  D3DCMP_ALWAYS );
                                        }
                                        else
                                                renderOneObject(rinfo, (*renderList), localPlayerIndex);
                                        renderList++;   //advance to next object
                                }


error: patch failed: Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp:1424
Hunk #35 succeeded at 1437 (offset -73 lines).
Hunk #36 succeeded at 1450 (offset -73 lines).
Hunk #37 succeeded at 1629 (offset -80 lines).
Hunk #38 succeeded at 1676 (offset -80 lines).
Hunk #39 succeeded at 1718 (offset -80 lines).
Hunk #40 succeeded at 1729 (offset -80 lines).
Hunk #41 succeeded at 1741 (offset -80 lines).
Hunk #42 succeeded at 1779 (offset -80 lines).
Applied patch Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DScene.h cleanly.
Applying patch Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DScene.cpp with 9 rejects...
Hunk #1 applied cleanly.
Rejected hunk #2.
Rejected hunk #3.
Hunk #4 applied cleanly.
Hunk #5 applied cleanly.
Hunk #6 applied cleanly.
Hunk #7 applied cleanly.
Hunk #8 applied cleanly.
Rejected hunk #9.
Hunk #10 applied cleanly.
Rejected hunk #11.
Hunk #12 applied cleanly.
Rejected hunk #13.
Hunk #14 applied cleanly.
Hunk #15 applied cleanly.
Hunk #16 applied cleanly.
Rejected hunk #17.
Hunk #18 applied cleanly.
Hunk #19 applied cleanly.
Hunk #20 applied cleanly.
Rejected hunk #21.
Hunk #22 applied cleanly.
Hunk #23 applied cleanly.
Hunk #24 applied cleanly.
Hunk #25 applied cleanly.
Hunk #26 applied cleanly.
Hunk #27 applied cleanly.
Hunk #28 applied cleanly.
Hunk #29 applied cleanly.
Hunk #30 applied cleanly.
Hunk #31 applied cleanly.
Rejected hunk #32.
Hunk #33 applied cleanly.
Rejected hunk #34.
Hunk #35 applied cleanly.
Hunk #36 applied cleanly.
Hunk #37 applied cleanly.
Hunk #38 applied cleanly.
Hunk #39 applied cleanly.
Hunk #40 applied cleanly.
Hunk #41 applied cleanly.
Hunk #42 applied cleanly.

@xezon xezon merged commit a20744f into TheSuperHackers:main Oct 23, 2025
18 checks passed
xezon added a commit that referenced this pull request Oct 23, 2025
@xezon xezon deleted the xezon/fix-translucent-render branch October 23, 2025 16:43
fbraz3 pushed a commit to fbraz3/GeneralsX that referenced this pull request Nov 10, 2025
fbraz3 pushed a commit to fbraz3/GeneralsX that referenced this pull request Nov 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Approved Pull Request was approved Bug Something is not working right, typically is user facing Minor Severity: Minor < Major < Critical < Blocker Rendering Is Rendering related ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stealthed unit is see through from narrow angle only when zoomed close

2 participants