Skip to content

refactor(w3dview): Migrate from MEMBER_ADD/MEMBER_RELEASE macros to RefCountPtr<T>#1763

Open
bobtista wants to merge 3 commits into
TheSuperHackers:mainfrom
bobtista:bobtista/refactor-w3dview-refcountptr
Open

refactor(w3dview): Migrate from MEMBER_ADD/MEMBER_RELEASE macros to RefCountPtr<T>#1763
bobtista wants to merge 3 commits into
TheSuperHackers:mainfrom
bobtista:bobtista/refactor-w3dview-refcountptr

Conversation

@bobtista

@bobtista bobtista commented Oct 31, 2025

Copy link
Copy Markdown

Replaces custom reference counting macros (MEMBER_ADD, MEMBER_RELEASE, SAFE_ADD_REF, SAFE_RELEASE_REF) with the type-safe RefCountPtr smart pointer from the core library.

Member Variables Migrated to RefCountPtr:

  • AssetInfoClass::m_pRenderObj
  • ScreenCursorClass::m_pTexture, m_pVertMaterial
  • PlaySoundDialogClass::SoundObj
  • SpherePropertySheetClass::m_RenderObj
  • RingPropertySheetClass::m_RenderObj
  • CW3DViewDoc::m_pCRenderObj, m_pCAnimation, m_pCAnimCombo, m_pCursor, m_pCursorScene
  • CGraphicView::m_pCamera, m_pLightMesh

Local Variable Usage:

  • Replaced MEMBER_ADD/MEMBER_RELEASE with REF_PTR_SET/REF_PTR_RELEASE for local raw pointers in 15 files

Removed Macros (Utils.h):

  • MEMBER_ADD
  • MEMBER_RELEASE
  • SAFE_ADD_REF
  • SAFE_RELEASE_REF

Notes:

  • Used Create_AddRef() when taking ownership of an existing pointer
  • Used Create_NoAddRef() when wrapping factory methods that return ref=1
  • Added .Peek() calls when passing to functions expecting raw pointers
  • Updated getter methods to return .Peek() instead of raw RefCountPtr
  • Preserved all original logic and formatting

@bobtista bobtista force-pushed the bobtista/refactor-w3dview-refcountptr branch 8 times, most recently from cc1d8dc to c3f8d36 Compare October 31, 2025 02:22
@Skyaero42 Skyaero42 added Refactor Edits the code with insignificant behavior changes, is never user facing Stability Concerns stability of the runtime labels Nov 1, 2025

@xezon xezon left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Before I continue review, please make another pass on this and correct all missing resource cleanups. It is important that no logic is changed, unless it fixes a bug.

Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
@@ -243,8 +241,6 @@ CW3DViewDoc::CleanupResources (void)
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The condition above is obsoleted.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

So, yes the operations inside are safe to execute regardless. If I understand correctly, the conditional checks make the intent explicit (only cleanup when there's something to clean up). RefCountPtr provides operator const DummyPtrType *() specifically to enable null-checking in boolean contexts.
// From ref_ptr.h documentation (lines 92-96):
void Do_It(void)
{
if (MyObject) { // Recommended pattern
MyObject->Do_Something();
}
}

This is also the pattern we use elsewhere eg CW3DViewDoc::CleanupResources.

Happy to keep or remove them, up to you

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Assignment functions already do the tests and are safe.

const RefCountPtr<T> & operator =(DummyPtrType * dummy_ptr)
{
if (Referent) {
Referent->Release_Ref();
}
Referent = 0;
return *this;
}

Alternatively, use Clear() function. Maybe that is cleaner.

void Clear(void)
{
if (Referent) {
Referent->Release_Ref();
Referent = 0;
}
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I like Clear :) Done

Comment thread Core/Tools/W3DView/W3DViewDoc.h
@bobtista bobtista force-pushed the bobtista/refactor-w3dview-refcountptr branch 2 times, most recently from 0cbd2fc to 4c2acf0 Compare November 2, 2025 18:28

@xezon xezon left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

How about we first make a change where we just remove the duplicate Macros, without adding RefCountPtr? Then this change will be simpler? And then make small changes to introduce RefCountPtr slowly? I am afraid this will be a big review here otherwise given the implications. One mistake with ref counting and the game will crash.

Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
@bobtista

bobtista commented Nov 3, 2025

Copy link
Copy Markdown
Author

How about we first make a change where we just remove the duplicate Macros, without adding RefCountPtr? Then this change will be simpler? And then make small changes to introduce RefCountPtr slowly? I am afraid this will be a big review here otherwise given the implications. One mistake with ref counting and the game will crash.

Ok, check out 1784. Shall we continue this PR after rebasing and have it focus just on just W3DView, then additional RefCountPtr migrations can have separate PRs?

@bobtista bobtista force-pushed the bobtista/refactor-w3dview-refcountptr branch from 3c0d862 to d3cd83c Compare November 6, 2025 17:18
@xezon

xezon commented Nov 22, 2025

Copy link
Copy Markdown

This still needs work.

@bobtista bobtista force-pushed the bobtista/refactor-w3dview-refcountptr branch from 1229310 to 52e834f Compare November 22, 2025 18:17

@xezon xezon left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This refactor needs another pass. Something went wrong the indentation of code. And behavior has changed.

Comment thread Core/Tools/W3DView/AssetInfo.cpp Outdated
Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
Comment thread Core/Tools/W3DView/EmitterInstanceList.cpp Outdated
Comment thread Core/Tools/W3DView/EmitterInstanceList.cpp Outdated
Comment thread Core/Tools/W3DView/EmitterInstanceList.cpp Outdated
Comment thread Core/Tools/W3DView/PlaySoundDialog.cpp
Comment thread Core/Tools/W3DView/RingPropertySheet.cpp Outdated
if (m_pCBackObjectScene)
{
// Free the scene object
m_pCBackObjectScene->Release_Ref ();

@xezon xezon Nov 22, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

m_pCBackObjectScene.Clear() missing?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

m_pCBackObjectScene is a raw pointer (SceneClass *), not a RefCountPtr, so it uses Release_Ref() and = NULL for cleanup (lines 167-168). Want me to convert it to RefCountPtr? Or should that be in a separate PR?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Checking again - On main:
m_pCursorScene used REF_PTR_RELEASE and was migrated to RefCountPtr with .Clear().
m_pCBackObjectScene used manual Release_Ref() + = NULL (not REF_PTR_RELEASE), so it wasn’t done in this PR. Do you want me to migrate it in this PR?

Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
Comment thread Core/Tools/W3DView/W3DViewDoc.cpp
@bobtista bobtista force-pushed the bobtista/refactor-w3dview-refcountptr branch 4 times, most recently from 81a71ad to bad267f Compare December 3, 2025 16:23
Comment thread Core/Tools/W3DView/W3DViewDoc.cpp Outdated
SAFE_DELETE (m_pCAnimCombo);
REF_PTR_RELEASE (m_pCAnimation);

if (m_pCRenderObj != NULL) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This indentation seems wrong in the original code, fixed here

@bobtista

bobtista commented Dec 3, 2025

Copy link
Copy Markdown
Author

I think this is ready for another look

@bobtista bobtista force-pushed the bobtista/refactor-w3dview-refcountptr branch from bad267f to e2d2ae2 Compare December 15, 2025 20:17
DisplayObject (pCModel);

// Get an instance of the animation object
SAFE_DELETE (m_pCAnimCombo);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Here too, the indentation was weird in the original. It looks like they meant to do:
Function body level: 4 spaces
Inside the if block: 8 spaces (4 + 4)
But a few spots got 10 spaces, eg SAFE_DELETE, so I fixed those, at least here

@bobtista bobtista force-pushed the bobtista/refactor-w3dview-refcountptr branch from e2d2ae2 to 9bdab84 Compare January 14, 2026 21:32
@bobtista bobtista force-pushed the bobtista/refactor-w3dview-refcountptr branch from 9bdab84 to a3409ec Compare February 24, 2026 18:54
@greptile-apps

greptile-apps Bot commented Feb 24, 2026

Copy link
Copy Markdown

Greptile Summary

This PR replaces manual reference-counting macros (MEMBER_ADD, MEMBER_RELEASE, SAFE_ADD_REF, SAFE_RELEASE_REF, REF_PTR_SET, REF_PTR_RELEASE) across the W3DView tool with the type-safe RefCountPtr<T> smart pointer, eliminating whole classes of raw-pointer misuse while preserving all original logic.

  • Member variables across 8 classes (m_pRenderObj, m_pCamera, m_pLightMesh, m_pCursorScene, m_pCRenderObj, m_pCAnimation, m_pCursor, SoundObj, m_pTexture, m_pVertMaterial) migrated to RefCountPtr<T> with correctly chosen Create_AddRef (existing objects) vs Create_NoAddRef (factory/new returns).
  • Destructor and cleanup boilerplate removed where RefCountPtr now handles lifetime automatically; .Clear() used in CleanupResources() where an explicit early release is needed.
  • Constructor initializer-list order for SpherePropertySheetClass and RingPropertySheetClass corrected to place the base class (CPropertySheet) before member initializers, matching C++ initialization order and eliminating a latent compiler warning.

Confidence Score: 5/5

Safe to merge — a mechanical but carefully executed refactoring with no logic changes.

All Create_AddRef / Create_NoAddRef choices are consistent with each call site's ownership contract. The removed cleanup block for m_pCBackObjectScene after the dazzle-layer deletion was dead code (the earlier if-block in CleanupResources already nulled the pointer). AssetInfo::Initialize()'s manual Add_Ref / REF_PTR_RELEASE pattern on the local prender_obj is preserved and balances correctly in both the wrapped-instance and the factory-temporary paths. Constructor initializer-list reordering for the property sheets aligns with C++ initialization order without changing runtime behavior.

No files require special attention.

Important Files Changed

Filename Overview
Core/Tools/W3DView/W3DViewDoc.cpp Largest file in the PR; migrates m_pCRenderObj, m_pCAnimation, m_pCursorScene, and m_pCursor to RefCountPtr with correct Create_NoAddRef/Create_AddRef choices. The removed redundant m_pCBackObjectScene block after m_pDazzleLayer was dead code (the earlier if-block already nulled it). Cleanup, OnNewDocument, and DisplayObject paths all preserve original semantics.
Core/Tools/W3DView/W3DViewDoc.h m_pCRenderObj, m_pCAnimation, m_pCursorScene, and m_pCursor declaration types updated to RefCountPtr; accessor methods updated to return .Peek().
Core/Tools/W3DView/AssetInfo.cpp Initialize() updated to use .Peek(); the Add_Ref/REF_PTR_RELEASE pattern on the local prender_obj is preserved and correct — it balances the ref on both the wrapped-instance and the factory-created temporary paths.
Core/Tools/W3DView/AssetInfo.h m_pRenderObj migrated to RefCountPtr; Get_Render_Obj and Peek_Render_Obj updated to use .Peek() with correct manual Add_Ref semantics preserved in Get_Render_Obj.
Core/Tools/W3DView/GraphicView.cpp m_pCamera and m_pLightMesh migrated to RefCountPtr with correct Create_NoAddRef for newly allocated objects; .Peek() used consistently for raw pointer API calls.
Core/Tools/W3DView/ScreenCursor.cpp m_pTexture and m_pVertMaterial migrated to RefCountPtr. The copy constructor does not copy these fields (it calls Initialize() instead), which matches the original behavior where they were explicitly initialized to nullptr and rebuilt.
Core/Tools/W3DView/RingPropertySheet.cpp m_RenderObj migrated to RefCountPtr; constructor initializer list reordered to put base class first (matching C++ initialization order), fixing a latent warning. Create_AddRef used for existing objects, Create_NoAddRef for newly constructed RingRenderObjClass.
Core/Tools/W3DView/SpherePropertySheet.cpp Parallel refactoring to RingPropertySheet — identical pattern, identical correctness. Base class reordering and Create_AddRef/Create_NoAddRef choices are both right.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph Before["Before (Manual Macros)"]
        B1["Raw pointer member\n(e.g. RenderObjClass* m_pCRenderObj)"] --> B2["Constructor: m_pRenderObj = nullptr\nthen REF_PTR_SET adds ref"]
        B2 --> B3["Usage: pass raw pointer directly"]
        B3 --> B4["Destructor/Cleanup:\nREF_PTR_RELEASE or\nRelease_Ref + nullptr"]
    end

    subgraph After["After (RefCountPtr)"]
        A1["Smart pointer member\n(e.g. RefCountPtr&lt;RenderObjClass&gt; m_pCRenderObj)"] --> A2["Factory result → Create_NoAddRef\nExisting object → Create_AddRef"]
        A2 --> A3["Usage: .Peek() for raw pointer APIs\nbool/== works directly"]
        A3 --> A4["Destructor: automatic\nEarly release: .Clear()"]
    end

    Before --> |Refactored to| After
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph Before["Before (Manual Macros)"]
        B1["Raw pointer member\n(e.g. RenderObjClass* m_pCRenderObj)"] --> B2["Constructor: m_pRenderObj = nullptr\nthen REF_PTR_SET adds ref"]
        B2 --> B3["Usage: pass raw pointer directly"]
        B3 --> B4["Destructor/Cleanup:\nREF_PTR_RELEASE or\nRelease_Ref + nullptr"]
    end

    subgraph After["After (RefCountPtr)"]
        A1["Smart pointer member\n(e.g. RefCountPtr&lt;RenderObjClass&gt; m_pCRenderObj)"] --> A2["Factory result → Create_NoAddRef\nExisting object → Create_AddRef"]
        A2 --> A3["Usage: .Peek() for raw pointer APIs\nbool/== works directly"]
        A3 --> A4["Destructor: automatic\nEarly release: .Clear()"]
    end

    Before --> |Refactored to| After
Loading

Reviews (2): Last reviewed commit: "refactor(w3dview): Migrate W3DViewDoc an..." | Re-trigger Greptile

@bobtista bobtista force-pushed the bobtista/refactor-w3dview-refcountptr branch from a3409ec to e75954a Compare June 29, 2026 19:38
@bobtista

Copy link
Copy Markdown
Author

Ready for re-review. Rebased onto latest main and it's behavior-consistent with the original.

Note - these fixes can either be added here or to separate PRs if we want:

  1. m_pCursor.Clear() in CleanupResources - pulled this back out so the cursor is only released when the document is destroyed (as before, now via the RefCountPtr destructor). Clearing it in CleanupResources would release/recreate the cursor on every cleanup (e.g. File→New), which is a behavior change.
  2. Leak in DisplayObject (ghost-object branch) - there's a local RenderObjClass *m_pCRenderObj that shadows the member; it's Add_Ref()'d and added to the scene but never released, so the local's reference leaks. Left as-is here to keep behavior identical.
  3. GraphicView::OnDestroy - kept the explicit m_pCamera/m_pLightMesh release. With RefCountPtr these could release via the destructor instead, but that shifts release timing off WM_DESTROY, so I left the explicit clears.

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

Labels

Refactor Edits the code with insignificant behavior changes, is never user facing Stability Concerns stability of the runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants