Native ARM64 macOS port using wxWidgets#166
Open
wbreiler wants to merge 21 commits into
Open
Conversation
All 10 core library objects now build natively for arm64-apple-darwin using clang++ in Mac/. No errors; warnings only. Files changed in Win/: - stdafx.h: add #ifdef WIN32 guard so non-Windows builds get POSIX paths instead of windows.h/tchar.h/io.h; macOS PortaOpen/Create/Append redirect through _mwPorta*W() wide-char to UTF-8 helpers. - nbt.h: guard #define ZLIB_WINAPI with #ifdef WIN32 so macOS links against system zlib without __stdcall calling-convention issues. - nbt.cpp: hoist 'int inttype' before goto SectionsCode to fix clang's stricter goto-past-initialization check. - ObjFileManip.cpp: fix goto-past-init for float norm, bool subtypeGroup, bool subtypeMaterial, int noteProgress/mkGroupsObjs/prevDataVal/ prevSwatchLoc/noteFaceProgress, bool usePreviewSurface/float emission/ int nextStart/startRun; rename 'or' variable to 'ovr' (C++ keyword conflict); fix qsort_s -> qsort_r wrapper (macOS argument order differs). New Mac/: - compat.h: Win32 type shims (HANDLE=FILE*, BOOL, DWORD, HKEY/HWND/ HINSTANCE as void*), Windows CRT compat (_strdup, strcpy_s/strcat_s templates, _strlwr_s/_wcslwr_s, _stricmp/_wcsicmp, _wfopen_s, __time32_t/_time32/_localtime32_s/asctime_s, wcsncpy_s/wcscat_s), Win32 file I/O stubs (WriteFile/ReadFile/GetFileSize via FILE*), CreateDirectoryW via mkdir, MultiByteToWideChar/WideCharToMultiByte via mbstowcs/wcstombs, qsort_s->qsort_r wrapper, errno_t typedef. - stdafx.h: macOS replacement precompiled header. - zlib.h: redirect #include "zlib.h" to system <zlib.h>. - Makefile: arm64 build producing 10 .o files; GUI files excluded. Failure boundary: Mineways.cpp and MinewaysMap.cpp (the Win32 GUI) cannot be compiled on macOS because they depend on WinMain/WndProc, GDI drawing, common controls, Windows registry, and resource.h (UTF-16 LE - clang refuses to parse it). A native macOS port requires a new UI layer (Cocoa or wxWidgets/Qt) calling into the core library. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MinewaysFrame (wxFrame) + MapPanel (wxPanel) replace Win32 WndProc. DrawMap() renders into a malloc'd RGBA buffer displayed via wxImage. Mouse pan, scroll-wheel zoom, keyboard arrow nav all wired. File > Open World shows wxDirDialog and calls GetSpawn/GetFileVersionId. CullingStubs.cpp provides isBlockCulled() no-op until dialog is ported. MinewaysMap.cpp now compiles clean via POSIX FindFirstFileW/opendir shims. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- TODO.md tracking all remaining work - World saves submenu: scans ~/Library/.../saves with opendir, shows each world dir containing level.dat; Test Block World always first - Selection rectangle: right-click drag calls SetHighlightState; DrawMap renders the overlay natively, no separate draw needed - Space bar: snaps bottom depth to min solid height in active selection - Mouse hover: IDBlock status bar update on EVT_MOTION - Bottom slider wired to gTargetDepth - Pixel format fix: DrawMap writes R,G,B,0xFF (already RGB); removed incorrect BGR swap that would have inverted colors - Remove redundant MapPanel::m_bits double buffer - Add Mac/mineways binary to .gitignore Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mac/LocationDialog.cpp replaces Win/Location.cpp (122 lines → 40 lines via wxDialog). Shows X/Z text entries, validates integer input, jumps the map view on OK. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
yoff was using block->minHeight directly instead of negating it, and the grid/data/light memsets used maxHeight instead of the actual allocated heightAlloc, under/over-clearing the buffers. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- ExportDialog.cpp/h: lean wxDialog export/print dialog wired to SaveVolume(), replacing the ~1600-line Win/ExportPrint.cpp - MacCullingSchemes.cpp/h: port of Win/CullingSchemes.cpp with wxConfig persistence and a wxCheckListBox-based editor dialog, replacing the CullingStubs.cpp no-op stub - Info.plist + mineways.icns + `make app` target: bundle as Mineways.app, locating terrainExt.png relative to Resources/ - compat.h: expand leading ~/ in fopen paths (wide-char callers don't get shell tilde expansion) - TODO.md updated to reflect completed Export/Culling/Packaging work Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Correctness fixes found via code review + a live repro of "export reports success but writes nothing": - Export always applied an unwanted 270deg rotation: radioRotate0/90/180/270 were never set, so Win/ObjFileManip.cpp's rotateLocation() fell through to its 270deg branch on every export. Set radioRotate0=1. - Depth sliders didn't actually constrain exports. New selections used the world's absolute max height instead of the Depth slider (added GetCurDepth()); worse, moving either slider after a selection was already drawn never touched the selection's stored Y bounds, so the sliders looked inert once a box existed. Both sliders now re-apply SetHighlightState with the live depth, matching Win/Mineways.cpp's slider handlers. - SaveVolume's "nothing exportable in this selection" codes (MW_NO_BLOCKS_FOUND, MW_ALL_BLOCKS_DELETED) were being treated as full success because the Mac success check used the wrong threshold (MW_BEGIN_ERRORS instead of MW_BEGIN_NOTHING_TO_DO, per Win/Mineways.cpp). Confirmed via a standalone headless harness against SaveVolume before writing the fix. Now shows a distinct "Nothing exported" warning instead of a false "Export complete". - Culling scheme defaults (barrier/structure-void hidden) were never seeded at Mac startup, unlike Windows' applyCullingScheme(NULL) at launch. - Active culling scheme name was hardcoded blank in export statistics; getSelectedCullingSchemeW() was dead code. - Unterminated strncpy when saving an edited culling scheme name >=254 bytes. - No setlocale(LC_ALL, "") call, so wcstombs/mbstowcs could corrupt non-ASCII world/export paths under the default "C" locale. - ScanWorldSaves now validates worlds via GetFileVersion/GetLevelName (skips unreadable/unsupported saves, shows the real level name) instead of just checking for level.dat's existence. Cleanup: - Deleted dead Mac/CullingStubs.cpp (superseded by MacCullingSchemes.cpp, not in the Makefile, mismatched signature). - Mac/stdafx.h no longer duplicates Win/stdafx.h's !WIN32 branch (which the Mac include order silently shadowed); it now just includes it. Completed that branch with the macros it was missing (_wcsicmp, _countof, etc.) so it's an actual working single source of truth. - NUM_CULL_ENTRIES in MacCullingSchemes.cpp no longer locally redefines the constant from Win/CullingSchemes.h (drift risk); now includes that header. - MapPanel::OnPaint reuses a member RGB buffer instead of malloc/free every paint call. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Feature-parity pass following an audit against the Windows UI (see TODO.md).
View menu / navigation:
- Wire the dead OnOpenWorld handler (browse to any world folder) to a menu
item — it existed but was never reachable.
- Add the &View menu, absent on Mac until now: all 8 render-mode toggles
(show all objects, show biomes, elevation shading, lighting, cave mode,
hide obscured, transparent water, map grid), View Nether/End, Jump to
Spawn/Player, an Information dialog, Undo Selection, Select All, and Zoom
out further. These all drive gOptions.worldType bits and shared renderer
code that already existed and was already compiled in — this is menu/
handler wiring, not new rendering logic. Spawn/player coordinates are now
kept in globals instead of being discarded right after world load.
- Select All ports Win/Mineways.cpp:2108-2145's select-entire-map-or-
schematic logic, including the minimum-depth calculation.
Export dialog (the big one):
- Mac/ExportDialog.cpp now operates directly on ExportFileData — the same
struct Win/ExportPrint.cpp uses — instead of a lossy separate settings
struct that silently hardcoded most options. New 5-tab dialog (General/
Materials/Sizing/3D Print Prep/Advanced) covering rotation, all 4 model-
sizing strategies (target height/minimize-for-material/fixed block size/
target cost, with the shared physical-material and units tables), the
full 3D-print prep set (fill bubbles, seal entrances/tunnels, connect
parts/corner tips/edges, delete floaters, hollow + superhollow, melt
snow, export-all + fatten), 5 material modes, texture channels, biome/
leaves/borders/composite toggles, ZIP + keep-files, and the advanced
instancing/grouping set (separate types, USD individual blocks, material
per family, split by type, custom material, export MDL, doubled
billboards, decimate).
- Two preset buttons ("Load Rendering Defaults" / "Load 3D-Printing
Defaults") reproduce Windows' two separate export menu entries
(initializeViewExportData/initializePrintExportData) inside Mac's one
unified Export Model menu item.
- MinewaysFrame.cpp gained BuildExportFlags(), a line-for-line port of the
exportFlags bitmask translation from Win/Mineways.cpp:5296-5542, so the
dialog's choices actually reach SaveVolume() with the same effect as on
Windows.
- Verified end-to-end with a standalone headless harness (built and torn
down during development, not checked in) exercising OBJ/STL/USD exports
through real SaveVolume() calls. That caught a genuine pre-existing
cross-platform bug in Win/ObjFileManip.cpp: three call sites hardcoded
L"\\" as a path separator when building the tile-texture and USD
materials subdirectories. Backslash isn't a path separator on POSIX, so
this produced a directory literally named "tex\" on macOS instead of a
"tex/" subdirectory — invisible on Windows, silently broken on Mac, and
never exercised before since the old minimal export dialog never enabled
the tile-texture path. Fixed by using the already-present but previously
unused gSeparator (set via SetSeparatorObj, "/" on Mac and "\\" on
Windows) at all three sites; Windows output is unchanged.
Known simplification (marked with a ponytail: comment in ExportDialog.cpp):
per-file-type fields (block size, hollow thickness, physical material,
etc.) load once when the dialog opens for whatever file type was current,
rather than live-reloading when the File Type dropdown changes mid-dialog
the way Windows does. Not incorrect, just a minor UX gap.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- SaveVolume() now gets a real progress callback (was nullptr): a wxProgressDialog tracks the export, updated via ExportProgressCB which mirrors Win/Mineways.cpp's updateProgress() including its -999.0f "message only" sentinel. No wxPD_CAN_ABORT — confirmed Windows has no mid-export cancellation mechanism either (nothing in ObjFileManip.cpp polls a cancel flag), so a Cancel button would be a false promise. - SaveExportFileData/LoadExportFileData hex-encode/decode the whole ExportFileData struct into wxConfig (same idiom as MacCullingSchemes.cpp's culled[] persistence), guarded by a stored sizeof() so a struct-layout change in a future build can't corrupt-load into a live struct. Verified byte-identical round-trip via a standalone test (built and torn down during development, not checked in). - Recent Exports turned out not to be a re-export shortcut: traced Windows' IDM_RECENT_EXPORT_BASE handler and it re-imports/reopens the file via the same machinery as File > Import Settings, which doesn't exist on Mac yet. Left in the backlog blocked on that instead of building a shortcut that doesn't match Windows' actual behavior. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Small polish batch closing out several remaining backlog items: - About box now matches Win/Mineways.rc's IDD_ABOUTBOX text verbatim (version, copyright, Minecraft-version compatibility line, minutor credit, mineways.com link). - Help menu: keyboard (F1), troubleshooting, documentation, report a bug (wxLaunchDefaultBrowser to the same URLs Windows' ShellExecute calls use), and "Give more export memory!" wired to gOptions.moreExportMemory + MinimizeCacheBlocks (already-shared code). - File menu: Reload World (R), Download Terrain Files (browser link), Repeat Export (Ctrl+X) — the last required extracting a RunExport() helper out of OnExportOBJ so both the dialog path and the repeat path share the same SaveVolume-calling code instead of duplicating it. - Added Ctrl+T for Choose Terrain File, the one accelerator gap found by diffing against Win/Mineways.rc's IDC_MINEWAYS ACCELERATORS table. Also caught and fixed a stale TODO.md entry: "World Information dialog" was listed as not-yet-done but was actually already implemented in an earlier session as OnViewInformation. TODO.md updated with what's left: Jump to Model (F4), Export Map (Ctrl+M), terrain-file history submenu, Import Settings (blocking Recent Exports), and Sketchfab (needs real API credentials, flagged as likely out of scope for unattended work). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Continuing the backlog pass: - Jump to Model (F4): traced Win/Mineways.cpp:2481-2500 — despite the name, it just centers the view on the current selection's midpoint, not a tracked "last exported model". OnJumpModel matches that exactly. - Export Map (Ctrl+M): ports Win/Mineways.cpp's saveMapFile() — re-renders the selected region fresh at the current zoom via DrawMapToArray (not a screenshot of the live buffer) and writes it with writepng. Both are shared, platform-independent code already compiled into the Mac binary. Verified with a standalone headless test exercising the DrawMapToArray + writepng round-trip against a real decodable PNG. - "Choose Terrain File history" turned out to be a misreading of the Windows feature: loadTerrainList() isn't a recently-used list, it scans the app directory for terrainExt*.png files shipped alongside the executable (alternate texture packs), excluding _n/_r/_m/_e PBR-channel suffix files. Implemented as ScanTerrainFiles() (same pattern as ScanWorldSaves) populating a "Choose Terrain File" submenu with [default] + whatever's found. Also fixed a small pre-existing gap while touching this code: OnChooseTerrainFile never redrew the map after picking a new file. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Traced Win/Mineways.cpp's importSettings/importModelFile/ readAndExecuteScript/interpretImportLine before attempting it in the autonomous backlog pass: it's 1000+ lines covering both re-importing an exported file's settings header and a full batch-scripting command language, comparable in scope to the Export dialog rewrite. Not something to fold into incremental backlog work without explicit scope confirmation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ports Win/Mineways.cpp's importSettings/importModelFile/readAndExecuteScript/ interpretImportLine/interpretScriptLine into new Mac/ImportSettings.cpp: re-imports the '#'-comment header from any exported OBJ/USD/VRML/schematic file back into ExportFileData, and runs Mineways batch scripts (a superset of the same syntax plus navigation/export action commands). Preserves Windows' atomic header-commit (a mid-parse error can't half-modify the live settings) and two-pass script execution (syntax check, then a real run). Sketchfab, mouse remapping, custom printer materials, block-name translation, chunk size override, and the "Change blocks:" sub-language are deliberately not ported (documented in ImportSettings.h) — reported as clear errors rather than silently ignored. Required exposing more of MinewaysFrame's internals (LoadWorldFromDir, LoadSchematic, LoadTestBlockWorld, SetTerrainFile, SwitchToNether/TheEnd, Jump*, RunExport, RedrawMap) so the interpreter can drive the same actions the menu items do, plus SelectCullingSchemeByName in MacCullingSchemes. Found and fixed a real bug while building the verification harness: RunExport never re-derived the export bounds from the live highlight state (it relied on the caller having pre-filled gEfd from GetHighlightState()), so a script's "Selection location..." command silently had no effect on what actually got exported. Windows' saveObjFile avoids this by always re-querying GetHighlightState right before export; RunExport now does the same. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ports Win/Mineways.cpp's addToRecentExports/populateRecentExportsMenu/ IDM_RECENT_EXPORT_BASE handler: up to 5 most-recent successful model exports, newest first and deduped, in a File menu submenu placed right after Import Settings. Persisted to wxConfig immediately on every change. Clicking an entry re-opens it the same way File > Import Settings does, except schematic-like extensions reopen as a world; a since-deleted file is pruned from the list with a warning instead of erroring. This was the last item in the wx Mac port backlog besides Sketchfab, which stays explicitly deferred to the upstream maintainer (no Mac Sketchfab integration, needs real API credentials). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Author
|
Created from #165 |
Owner
|
Very cool! But, I think I need to leave it as a branch for now - I am not a Mac developer and so cannot test these changes myself. Still, I think it's worth noting this code, for sure, so I've added a link to this branch here: https://www.realtimerendering.com/erich/minecraft/public/mineways/downloads.html#macPlatformHelp |
Owner
|
(and, nice to see I'm not the only person using Claude Code on Mineways. It's pretty amazing, though occasionally goes wrong.) |
Builds the wxWidgets Mac port on every push/PR touching Mac/ or Win/, uploading a self-contained Mineways.app (Homebrew wx dylibs bundled via dylibbundler, verified to launch from a relocated copy with no Homebrew in the loop). Pushing a vX.Y tag additionally codesigns with a Developer ID cert, notarizes via notarytool (App Store Connect API key), staples, and publishes a GitHub Release with the zipped app attached. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Full sign+notarize requires a paid Apple Developer account and a fussy local cert/key export dance (hit errSecPassphraseRequired along the way). Not worth it for a hobby open-source build — ship unsigned instead. dylibbundler already ad-hoc signs the bundled app, so it launches with just a one-time "unidentified developer" right-click-Open, no further setup or secrets required. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Verified locally: an unsigned, quarantined download is rejected by Gatekeeper (spctl) whether or not it's ad-hoc signed, which macOS shows as "Mineways.app is damaged" rather than the older, clearer "unidentified developer" prompt -- easy to mistake for a broken zip. `xattr -cr` after download fixes it; confirmed the app launches clean afterward. Full-bundle ad-hoc signing is cheap insurance and doesn't hurt. Release notes now carry the one-line fix so users don't have to ask. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CLAUDE.md had no mention of Mac/ at all despite it now being a feature-complete parallel GUI with its own CI/CD and release pipeline. Add build commands, the unsigned/ad-hoc-signing distribution decision, the origin/upstream remote split, and the version-drift note. Also fix a stale pitfall claiming the memory directory is empty. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a native ARM64 macOS build of Mineways using wxWidgets (Cocoa backend), living alongside the existing Windows/MFC build under a new
Mac/directory. The Windows build and all shared core code (blockInfo,nbt,ObjFileManip,MinewaysMap, etc.) are untouched except for a couple of small cross-platform fixes described below — this is purely additive.Mac/directory:MinewaysApp,MinewaysFrame,MapPanel,LocationDialog,ExportDialog,MacCullingSchemes,ImportSettings, plusMakefile/Info.plist/app icon formake/make app.ExportFileDatafields across 5 tabs), Culling Schemes (list + editor, matches or exceeds Windows with Hide All/Show All), the View menu (all render-mode toggles, Nether/End, Jump to Spawn/Player/Model), Export Map (PNG), Repeat Export, Reload World, andwxConfig-based persistence for settings/paths/window state.#-comment blockwriteStatisticswrites into every exported file back intoExportFileData) and the batch-scripting command language, ported fromWin/Mineways.cpp'simportSettings/importModelFile/readAndExecuteScript/interpretImportLine/interpretScriptLine. Preserves the atomic header-commit and two-pass script-execution semantics. Not ported (documented inMac/ImportSettings.h, reported as a clear error rather than silently ignored): Sketchfab publish commands, Windows mouse-button remapping, "Custom printer" materials, block-nameTranslate:aliasing,Chunk size:, "Set unknown block ID:", script log-file management, and theChange blocks:sub-language.wxConfig, wired into every successful export.Two small cross-platform bug fixes found while building and testing this port, both applying to shared code:
Win/ObjFileManip.cpphardcodedL"\\"as a path separator in 3 places for texture subdirectories, producing a literaltex\directory name on macOS instead of atex/subdirectory. Fixed by using the existing-but-previously-unusedgSeparator(Windows continues to get"\\", unchanged).MinewaysFrame::RunExport(Mac-only) never re-derived export bounds from the live highlight state before exporting, so a script'sSelection location...command had no effect on what actually got exported — fixed to matchWin/Mineways.cpp'ssaveObjFile, which re-queriesGetHighlightStateunconditionally before every export.Sketchfab publish integration is explicitly not included — there's no Mac equivalent yet, and it needs a real Sketchfab account/API token to build and verify against, which wasn't available while building this. Left for whoever has Sketchfab credentials to pick up; see
Mac/ImportSettings.handTODO.mdfor the exact scope note.See
Mac/TODO.md(repo-rootTODO.md) for the full, itemized parity audit against the Windows UI, andCLAUDE.mdfor build instructions and architecture notes left for future contributors.Test plan
make -C Macbuilds cleanly (zero errors; pre-existing warnings only)SaveVolume,DrawMapToArray/writepng,wxConfiground-trips, Import Settings header re-import + scripting, and Recent Exports — all passing🤖 Generated with Claude Code