Skip to content

Conversation

@xezon
Copy link

@xezon xezon commented Jan 6, 2026

Merge with Rebase

This optimization is needed to make HeightMapRenderObjClass::oversizeTerrain faster, which is relevant later for terrain size extension on low camera pitch.

The first commit consolidates some duplicated code.

The second commit implements the performance optimization.

Cost was measured and reduced by 96%.

TODO

  • Replicate in Generals

@xezon xezon added Minor Severity: Minor < Major < Critical < Blocker Performance Is a performance concern Gen Relates to Generals ZH Relates to Zero Hour Rendering Is Rendering related labels Jan 6, 2026
@xezon
Copy link
Author

xezon commented Jan 7, 2026

Generals fails to compile until replicated.

Comment on lines +222 to +226
RECT rect;
rect.left = min.I;
rect.top = min.J;
rect.right = max.I;
rect.bottom = max.J;
Copy link

Choose a reason for hiding this comment

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

Suggested change
RECT rect;
rect.left = min.I;
rect.top = min.J;
rect.right = max.I;
rect.bottom = max.J;
RECT rect = { min.I, min.J, max.I, max.J };

Copy link
Author

Choose a reason for hiding this comment

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

I doubt this works in C++98

Copy link

Choose a reason for hiding this comment

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

Did you try it? VC6 seems to compile for me.


const Int playerIndex = rts::getObservedOrLocalPlayer()->getPlayerIndex();
for (int i = 0; i < m_totalCellCount; ++i)
if (m_totalCellCount != 0)
Copy link

Choose a reason for hiding this comment

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

Maybe invert to reduce nesting?

if (m_totalCellCount == 0)
	return;

Copy link
Author

Choose a reason for hiding this comment

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

Prefer not, because it is not at the top of the function.

Copy link

Choose a reason for hiding this comment

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

Why? A few lines down is still at the top of the function.

Copy link
Author

Choose a reason for hiding this comment

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

I am not so much a fan of returns unless they are at the start of the function or the function has a single purpose and will never change (e.g. findSomethingInContainer)


Int psize;
psize=PixelSize(desc);
psize=Get_Bytes_Per_Pixel(desc.Format);
Copy link

Choose a reason for hiding this comment

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

Combine declaration and assignment?

const Int psize=Get_Bytes_Per_Pixel(desc.Format);

Copy link
Author

Choose a reason for hiding this comment

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

Could do, but for simplicity sake the refactor is enough as is.

Copy link

Choose a reason for hiding this comment

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

Okay. I had assumed minor refactors were on the table due to the changes to Core/Libraries/Source/WWVegas/WW3D2/ww3dformat.cpp.

Copy link
Author

Choose a reason for hiding this comment

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

Yes sure but can be separate refactor then. Keeping it extra simple :)

m_shroudSurface = m_shroudTexture->Get_Surface_Level();
DEBUG_ASSERTCRASH( m_shroudSurface != NULL, ("W3DRadar::beginSetShroudLevel: Can't get surface for Shroud texture") );

if (surfaceRegion != NULL)

Choose a reason for hiding this comment

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

In what situation is surfaceRegion not NULL? The only invocation I found was TheRadar->beginSetShroudLevel()

Copy link
Author

Choose a reason for hiding this comment

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

I provided the option to lock a subregion only. But it is unused, because refreshShroudForLocalPlayer needs the full region locked to touch every pixel.

switch (m_shroudSurfacePixelSize)
{
case 1: *column = (UnsignedByte)color; break;
case 2: *reinterpret_cast<UnsignedShort*>(column) = (UnsignedShort)color; break;

Choose a reason for hiding this comment

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

Is it valid to cast Color like this? Color is AARRGGBB and casting to 2 bytes would give you GGBB and casting to 1 byte gives BB which are both zero in this case

Copy link
Author

Choose a reason for hiding this comment

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

Indeed it looks strange. I copied this style from SurfaceClass::DrawPixel, so if this is wrong then it is original game bug (out the scope of this change).

@xezon
Copy link
Author

xezon commented Jan 9, 2026

Perhaps we can combine this fix with jmarshall2323@9b1c399, which makes a lot of sense too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker Performance Is a performance concern Rendering Is Rendering related ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants