Modernize and organize project to current .NET standards, make cross-platform#5
Modernize and organize project to current .NET standards, make cross-platform#5gtkramer wants to merge 45 commits into
Conversation
Modernize the project and improve cross-platform compatibility
Have the camera move more closely with the mouse
Loading previously ran the whole CCSFile read+init inside the render callback (on the UI thread), so parsing a large file froze the UI and stalled the animation. Split loading into a CPU-only parse phase that runs on a background Task and a GL-upload phase that stays on the render callback (the only place the GL context is current): - Scene.LoadCCSFile -> ReadCCSFile (parse, any thread) + InitCCSFile (GL). - EnqueueGlJob is now callable from any thread; it marshals the RequestNextFrameRendering wake-up to the UI thread. - MainWindow.LoadFiles parses on Task.Run, enqueues the GL init, then adds the tree node via the dispatcher; read failures are caught/logged. Because logging now happens off the UI thread, guard Logger's de-dup dictionaries with a lock and restructure AppendLog to marshal to the UI thread before echoing, so each message is written exactly once. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The windows were ported WinForms-style: each declared private fields
mirroring its controls, assigned them via this.FindControl<T>("name") in
the constructor, and defined a manual InitializeComponent that called
AvaloniaXamlLoader.Load. Avalonia's XAML compiler already generates
strongly-typed fields for every x:Name'd control plus InitializeComponent,
so all of that was redundant boilerplate with only runtime-checked names.
Drop the manual InitializeComponent methods and the ~36 FindControl
lookups across the four windows and reference the generated fields
directly. This also removes the AvGrid alias in MainWindow (the generated
fields are already typed, so the StudioCCS.Grid vs Avalonia.Controls.Grid
ambiguity no longer surfaces). No behavior change.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The main window populated its TreeViews by recursively constructing TreeViewItems in code (BuildTreeItem/BuildSceneAnimeItem) and drove the View-menu toggles + status bar through imperative handlers (ApplyViewMenu, IsChecked lookups, a per-frame UpdateStatus). Move this to idiomatic Avalonia: - A light MainViewModel (ViewModelBase + INotifyPropertyChanged) exposes the tree data sources (CcsRoots / SceneRoots), the render-option toggles (which write straight through to the static Scene), and the status text. It's a thin shim over Scene, not a full MVVM layer. - The TreeViews bind ItemsSource to those collections and render via a shared compiled-binding TreeDataTemplate over CcsTreeNode; per-node-type context menus move to ContextRequested handlers (CcsTreeNode lives in the portable model and shouldn't carry UI command info). - View-menu items two-way bind IsChecked to the view-model; the status bar binds its text. A timer just refreshes the camera string. - CcsTreeNode.Nodes becomes an ObservableCollection so the scene tree updates when animations are added/removed after binding. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
StudioCCS.Grid (the static OpenGL grid-renderer helper) collided with Avalonia.Controls.Grid, which had forced a 'using AvGrid = ...' alias in the window code-behind. Rename the class (and its file) to GridRenderer so the name no longer shadows the Avalonia control. Only the three call sites in Scene.cs reference it; the "Grid" shader-file name and log strings are unchanged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bring the bone editor in line with the rest of the UI and remove duplication that had accumulated across the windows: - EditBoneWindow now binds its TreeView to CcsTreeNodes (Tag = the bone) via ItemsSource instead of hand-building TreeViewItems, matching the CCS and scene trees. The BoneNodeTag wrapper is gone (the CCSObject is the Tag directly). - The CcsTreeNode TreeDataTemplate moves to App-level resources so all three trees share one definition rather than redeclaring it. - File-picker type descriptors (All / CCS / Bin) are centralized in a FileFilters helper, replacing three inline copies across the load, load-matrix, and pose dialogs. - The two ContextRequested handlers share helpers (ContextNode, Menu, OpenNodeMenu) so node extraction, menu construction (single IList cast), and pointer-placed opening are written once; pattern matching is standardized on 'is not'. No behavior change. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Preview/Scene/All toggle was three ToggleButtons whose mutual exclusion was hand-maintained with a _suppressModeEvents reentrancy guard and manual IsChecked juggling in code-behind — the one imperative holdout in an otherwise VM-bound UI. Replace them with grouped RadioButtons (mutually exclusive by design) bound to a new MainViewModel.Mode property (with Is*Mode bool wrappers for the bindings). Mode is the single source of truth and writes through to Scene.SceneDisplay. Code-behind now only mirrors mode changes into the panel layout (kept there because the column GridLength collapse doesn't bind cleanly), via the view-model's PropertyChanged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Scrolling up now zooms the camera in (toward the model) rather than out, which matches the common convention. Negated the wheel delta forwarded from the viewport to Scene.MouseWheel. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Clicking a tree item's label now expands/collapses it, so users don't have to hit the small expand/collapse chevron. A shared TreeViewExpand helper handles the TreeView's Tapped event: it ignores taps on the chevron (which already toggles) and otherwise toggles IsExpanded on the tapped row if it has children. Wired to all three trees (CCS objects, scene animations, clump bones). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The orbit camera reconstructs its orientation with Matrix4.LookAt and a fixed +Y up-vector. At exactly +/-90 deg pitch the view direction aligns with that up-vector, the camera basis (cross(forward, up)) collapses, and the model and axis gizmo flip 180 deg (gimbal lock at the pole). Clamp pitch to +/-89.9 deg so the turntable never reaches the singular orientation: rotation stays smooth and level right up to a near-top-down view. 89.9 keeps an effectively straight-down view while staying well clear of float precision issues (cos(89.9 deg) ~= 0.0017). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Shaders (data/shaders/*.{vsh,fsh,gsh}) and the vertex blobs
(data/bin/*.bin) are now compiled in as AvaloniaResource items and read
at runtime through avares:// URIs via a new EmbeddedData helper, instead
of opening FileStream/StreamReader against files copied to the output
directory. This drops the data/**/* copy-to-output rule; only
blenderDummyImport.py is still copied out.
Since the data is now immutable and assembly-resident, the disk
reload-from-file paths no longer make sense: removed the unused
AxisMarker.Reload() and demoted WireHelper.ReadBin() to private (it has
only the single internal Init() caller).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Only the GL bindings and math types are used; Avalonia provides the window and GL context. Dropping the OpenTK metapackage removes the unused GLFW windowing native redist, audio, compute, and input packages. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The old static Logger owned plumbing the framework already provides and had several design flaws: severity was encoded as a System.Drawing.Color (so the core had no log levels and couldn't filter), dedup keyed on string.GetHashCode() (collisions could silently drop distinct messages), the LogOnceCode half was dead, and caller info was captured then discarded. Adopt Microsoft.Extensions.Logging via a thin static facade (Log.Error/ Warning/Info) over a LoggerFactory configured once at startup. This matches the codebase's existing static-utility idiom (no DI container) while letting the framework own levels, filtering, formatting, and the stdout sink. What we still own is just the two things we actually care about: - PanelLoggerProvider: routes formatted output to the in-app log panel and maps LogLevel -> Color in the view layer (the only place Color now lives). - LogOnce: per-frame flood protection, keyed on the message string (fixes the GetHashCode collision risk). Replaces the old LogType machinery; the 4 render-loop call sites now pass once: true. Log.* also trims trailing newlines centrally, so each sink owns line termination (the framework console provider and the panel provider each append one) instead of every call site baking in "\n". Verified: app loads CCS files, GL context initializes, and info/warn/fail all emit through the console provider with correct level prefixes and no double-newlines (0 across 3526 log lines over a 30-file load). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The in-app log panel was a plain read-only TextBox: it ignored the colour
the provider passed and showed no severity, so it read as flat, level-less
text while stdout (via the console provider) was clearly tiered. Make the
panel a copy of stdout.
- PanelLoggerProvider now prefixes each line with the console's level
abbreviation ("info:/warn:/fail:" etc.) and emits one line per log call
(no trailing newline; the facade already trims). Severity colours are
brightened to read on a dark surface.
- The panel becomes a virtualizing ListBox of colour-coded lines (LogLine:
text + brush), keeping it responsive under heavy logging where the old
Text += concat was O(n^2). Backing collection is capped at 2000 lines,
oldest dropped first, and auto-scrolls to the newest.
- The panel background is fixed dark (not theme-dependent) so white/orange/
red stay legible regardless of the OS light/dark setting.
Verified live: loaded several CCS files and confirmed the panel renders
orange "warn:" and grey "info:" lines on the dark console, mirroring stdout.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The SimpleConsole formatter printed "info: StudioCCS[0] message" — the
category/eventId is constant and redundant in a single-app process, and it
made stdout diverge from the in-app log panel ("info: message").
Replace SimpleConsole with a small custom ConsoleFormatter that prints just
"<level>: <message>", ANSI-colouring the level tag only on a real terminal
(suppressed when stdout is redirected). The level abbreviation now comes from
a shared LogLevelTag helper used by both the console formatter and the panel
provider, so the two renderings can't drift apart.
Verified: stdout shows "info:/warn:/fail: <message>" with no "StudioCCS[0]"
and no stray ANSI escapes when redirected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The console and panel each had their own severity-colour table (console: ANSI yellow/green/red; panel: orange/grey/bright-red) and disagreed on scope (console coloured just the level tag, panel coloured the whole line). So even matching text rendered with different colours. Introduce LogPalette as the single source of truth for severity colours (RGB). The console formatter emits a 24-bit truecolor ANSI escape from it; the panel builds its brush from the same values — so the two are identical by construction. Both now colour only the severity tag: the panel template renders the tag in its colour and ": <message>" in a neutral light grey, matching the console (which resets colour before the message). Verified: panel shows an orange "warn:" tag with a neutral message, and a pty capture of stdout shows "\e[38;2;255;165;0mwarn\e[0m: ..." — same orange, tag only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The GL profile was requested only through X11PlatformOptions, so the desktop OpenGL 3.3 (#version 330 + geometry shader) context the CCS shaders require was set up on Linux alone. On Windows the app fell back to ANGLE (OpenGL ES), which cannot compile those shaders. Choose the profile by platform from one shared desktop profile list: Windows switches to native WGL (RenderingMode=Wgl + WglProfiles), Linux keeps X11 GlProfiles. macOS (AvaloniaNative) exposes no GL-version selector, so it is documented as requiring on-device verification. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Encoding.Default is platform-dependent (Windows-1252 on Windows, UTF-8 elsewhere), so any name byte >= 0x80 decoded differently per OS. CCS asset names are ASCII; using Encoding.ASCII makes parsing deterministic across platforms. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Store text files with LF in the repo while checking them out with each platform's native ending (CRLF on Windows, LF elsewhere), keeping history consistent without fighting local tooling. Mark known binary assets (.dds/.png/.bin/.ccs) so they are never normalized. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
texture2D was removed from GLSL in the 330 core profile; desktop Mesa and NVIDIA/AMD drivers accept it leniently, but Apple's strict core compiler rejects it, which would fail shader compilation on macOS. Switch the three active samplers to the overloaded texture() call. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Verify the negotiated context is desktop GL 3.2+ in OnOpenGlInit; if it is older, disable the viewport with a clear log message instead of binding shaders that never compiled and spamming GL errors into a black viewport every frame. The disabled state fills the viewport dark red and stops requesting frames rather than spinning. Also register a KHR_debug callback in debug builds (where the context is 4.3+) to surface driver warnings and errors through the existing log, making platform-specific rendering issues diagnosable instead of silent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The capability guard accepted 3.2, but the shaders are #version 330 and need GL 3.3, so a 3.2 context would pass the guard and then fail every shader compile - the same silent black viewport the guard exists to prevent. Raise the floor to 3.3 and drop the unusable 3.2 entry from the context negotiation list. 3.3 is available everywhere; macOS meets it with its 4.1 core context (it offers only 3.2 or 4.1, never 3.3). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Five shaders (CCSClump and Triangle) declared bare #version 330 while the rest used #version 330 core. The two are equivalent on a core context (330 defaults to core), so this is a consistency/intent change, not a behavioral one: every shader now explicitly states it targets the core profile and relies on no compatibility features. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A SharpDevelop/Windows-era toolchain had saved 46 source, shader, and doc files as UTF-8 with a leading BOM (EF BB BF). The marker is redundant for UTF-8, breaks naive first-line parsing (it hid shader #version lines from grep), and is out of place in a cross-platform repo. Remove the three BOM bytes from every affected file - content and LF line endings are otherwise untouched. Add a root .editorconfig pinning charset = utf-8 (no BOM) so Windows editors do not silently reintroduce it, complementing the existing .gitattributes line-ending normalization. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ask the WGL/X11 backends for OpenGL 4.6 (the highest version) first so capable Windows/Linux drivers also grant KHR_debug (core in 4.3), which lets the debug-build output callback actually engage. The list still falls back to 3.3 - the minimum the #version 330 shaders require - when a driver cannot provide anything newer. macOS is unaffected (AvaloniaNative ignores this list and caps at a 4.1 core context). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the render-info readout out of the full-width bottom strip and into the viewport column: render mode in a top bar, live camera state in a bottom bar, so the GL surface is sandwiched between them and the tree spans the full side. The mode bar gets the full viewport width since the list grows as more views are toggled on. Also reformat the camera readout with grouped axis labels, degree marks, and fixed-width fields rendered in a monospace font so it stays legible and stops jittering as it refreshes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Fluent-themed controls already tracked the OS light/dark setting, but the GL viewport (clear colour + grid lines, set in raw GL) and the Mode/ Camera status bars (hardcoded #202020) stayed dark regardless, which looked out of place against a light UI. Drive the viewport clear/grid colours from Scene.BackgroundColor/GridColor, re-applied every frame and updated on ActualThemeVariantChanged so an OS theme switch is reflected live. Move the status-bar palette into theme-keyed ResourceDictionaries (DynamicResource) so the bars re-resolve on a switch. The dark values are unchanged; only a light-mode variant is added. The log panel stays fixed-dark by design (its severity colours need a dark ground). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Convert the plain-text, tab-indented readme into proper Markdown: heading hierarchy, lists, fenced code blocks, blockquotes for asides, and tables for the CCS generations, model types, and controls. Add Requirements, Building & Running, a table of contents, and a License section for completeness, fix assorted typos, and rename Readme.md to README.md to match the conventional casing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Write per-vertex RGB color alongside each OBJ position and split the vertex/texcoord/normal output into separate passes. Open the SMD output with FileMode.Create instead of FileMode.Truncate so export no longer throws when the target file does not already exist, and re-enable the companion bind-pose (_bind.smd) dump. Ported from Casuallynoted's fork (commit 848d9a5) onto the Avalonia base.
Rework the rotation/position/scale tracks so a controller's interpolated pose threads rotation into position into scale, keyed by object name, and stop discarding duplicate keyframes (use Keys.Count and skip the Keys.Remove on equal frame numbers) so interpolation has the keys it needs. Includes the per-bone coordinate corrections for the .hack player skeleton. Add per-frame preview export of the selected animation to SMD (CCSAnime/CCSClump.DumpPreviewToSMD, Scene.DumpPreviewToSMD) wired to a debug-only 'Dump Preview to .SMD...' menu item, drop the triangle-strip winding alternation, return raw radians from ReadVec3Rotation, and add Util.toDeg. Ported from taarna23's fork onto the Avalonia base. The fork's .NET/OpenTK upgrade and whitespace reformatting are intentionally omitted; only the functional animation/export changes are carried over.
Expand .editorconfig to enforce UTF-8 (no BOM), LF line endings, final newlines, no trailing whitespace, and 4-space indentation, plus the Microsoft C# coding conventions (using placement, language keywords over BCL types, brace style, naming) as analyzer/IDE rules. Run `dotnet format` and normalize the tree to match: - reindent the legacy tab-indented files (libCCS, Scene, GL helpers) to 4 spaces; sort using directives - strip trailing whitespace and add missing final newlines everywhere - convert stray tabs to spaces in shaders, the data XML, and comments; keep the intentional display tabs in CCSAnime.Controllers.cs as \t - remove the auto-generated SharpDevelop header comment from 40 files (none contained file-specific documentation) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EditorConfig's end_of_line has no "native" value, so the previous end_of_line = lf fought .gitattributes' per-OS checkout (* text=auto): on Windows, files checked out as CRLF were rewritten to LF on save, producing mixed working trees. Resolve in favor of native-per-OS checkout: drop end_of_line from .editorconfig so editors preserve whatever Git checked out, and keep * text=auto so the repo stays LF while working trees follow the OS (CRLF on Windows when core.autocrlf is enabled, LF on Linux/macOS). Expand both files' comments to document the coupling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the TestTriangle debug renderer and its Triangle shaders, the unreferenced ScalableLine and CCSDeformModel shaders, the unused SceneInstanceObject stub and commented-out SceneClumpInstance class in Scene.cs, and the unused ArcBallCamera two-arg constructor plus its commented-out property block. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bounding box program was unfinished and unreachable: it was loaded
under the wrong name ("BBox" vs the BoundingBox.* shader files), its
fragment shader was empty and its geometry shader had no main(), the
vertex attribute/uniform names did not match the C#, and Init() both
referenced non-existent struct fields in Marshal.OffsetOf and wiped the
extents read from the file. Nothing ever drew the boxes, and the wrong
shader name would have thrown rather than failing gracefully.
- Harden Scene.LoadShader so a missing/misnamed shader logs and returns
-1 (via the existing ProgramID == -1 path) instead of throwing.
- Write a complete BoundingBox shader set: the vertex stage passes the
AABB min/max and colour through an interface block, the geometry stage
expands the point into the 12 wireframe edges via UMatrix, and the
fragment stage outputs the colour.
- Fix CCSBoundingBox: load "BoundingBox", correct the OffsetOf field
names (Minimum/Maximum), keep the read extents and set a wireframe
colour, and add a Render() that draws one point per box.
- Initialise and release BBoxList in CCSFile.Init/DeInit (previously
skipped, so boxes were never set up).
- Add a DrawBoundingBoxes scene toggle, wire it through MainViewModel,
and add a "Draw Bounding Boxes" menu item.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Regroup the catch-all root namespace and the flat 40-file libCCS library so every folder maps to an idiomatic namespace grouped by functional area: - libCCS -> StudioCCS.FileFormat, subdivided into .Geometry, .Materials, .Animation, .SceneObjects (Light/Camera/Dummy), and .Raw (opaque passthrough sections); the format/parsing core stays at the .FileFormat root. The namespace is named for the layer rather than the format's "CCS" initials, so it does not stutter against the CCS-prefixed type names (StudioCCS.FileFormat.Geometry.CCSModel). - OpenGL render code -> StudioCCS.Rendering, with the gizmo renderers under .Gizmos; EmbeddedData -> StudioCCS.Resources - Correct the Logging folder/namespace mismatch (now StudioCCS.Logging) - Keep the shared tree-model types (CcsTreeNode, TreeNodeTag) at the root so no XAML or .csproj changes are needed A single GlobalUsings.cs declares the new namespaces project-wide, which preserves the codebase's import-free ergonomics with no per-file using churn. Also align three filenames to their type names (CCSBinaryBlob, CCSFileHeader, IndexObjectEntry). Pure reorganization with no behavior change: the build is clean (0/0) and the app launches, initializes OpenGL, and renders. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Every CCS-format type uses all-caps "CCS" (CCSFile, CCSModel, ...), but a few identifiers still used the soft "Ccs" casing. Normalize them all: - CcsTreeNode / CcsTreeNodeCollection -> CCSTreeNode(Collection), with the file renamed to CCSTreeNode.cs - CcsRoots -> CCSRoots, CcsNodeTemplate -> CCSNodeTemplate, FileFilters.Ccs -> .CCS, and the OnCcsTree*/BuildCcsNodeMenu members Updates all references, including the App.axaml TreeDataTemplate x:DataType/x:Key, the CCSRoots binding, and event wiring. The lowercase `ccs` cases (xmlns prefix, the ccsTree control field, the *.ccs file pattern) are intentionally left as-is per camelCase/XML conventions. No behavior change: build is clean (0/0) and the app launches and renders. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The shaders and gizmo vertex blobs were embedded from a top-level data/ folder, but every one of them is loaded by the Rendering layer (Scene loads shaders by name; the gizmos load their own blobs). Move them -- and the loader itself -- next to that code: - data/shaders/ -> Rendering/Shaders/ (kept as one name-keyed pool that Scene.LoadProgram resolves) - data/bin/*.bin -> Rendering/Gizmos/, beside the AxisMarker/WireHelper code that reads them; WireHelpers.bin is renamed to WireHelper.bin to match its class and shaders - EmbeddedData (the avares:// loader, whose only callers are Scene and the gizmos) -> Rendering/ (StudioCCS.Rendering); the one-file Resources folder/namespace is dropped Updates the Scene shader-path prefix, the gizmo blob paths, the two AvaloniaResource globs, and GlobalUsings.cs. The avares:// URIs are assembly-relative to the source path, so they resolve under Rendering/. No behavior change: build is clean (0/0) and the app launches, loads the shaders/blobs from their new paths, and renders. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gen1_Scenes.xml (Gen1 scene reference data) and blenderDummyImport.py (a Blender import helper) were a lone orphan in data/xml/ and a script at the repo root. Collect them under Extras/, a neutral catch-all for supporting files, which fully retires the data/ folder. The Blender script is not used by this C# application, so drop its CopyToOutputDirectory entry from the csproj -- it stays in the source tree only and is no longer copied to the build output. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
More or less done with own changes
CCSFile.Read(string) opened a FileStream and BinaryReader without ever disposing them, leaking a file handle on every load. Wrap both in using declarations so the handle is released when loading finishes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The helper takes a name and a type but compared only the type, returning the first object of that type regardless of name. The bug is inherited verbatim from upstream and the method has no callers yet, but its contract is a name-and-type lookup; compare ObjectName as well, mirroring the working GetObjectByNameAndType<T> right below it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Interesting. I just recently updated to .net core 10, myself. It's allowed me to keep working on this on linux. I have a bit of a hack-jobby (pun intended?) fix for animations in my repo now, too, though the interpolation is as bad as it always was. |
|
Can you tell me more about your Linux setup? Are you maybe using WSL? I tried cloning your master branch on Arch Linux, ran I tried I checked my Windows box, and what's in this PR built and ran fine there. |
|
Oh, yes. There are a mountain of warnings. I'm running Garuda Linux, which is based on Arch. I honestly never used dotnet run. I just test from inside VSCode. |
|
Do you maybe have Mono installed on Guarda? That would explain how a Windows Forms app can run on Linux, since Mono ships with its own implementation. |
|
I don't believe so. It just launches in WINE. |
|
That makes sense now. I wanted to do away with the necessary Wine layer for the Windows Forms bits and go native on Linux so anyone can git clone and go without extra setup. Given Windows Forms is in maintenance mode, Avalonia seemed like the modern forward-looking choice. |
|
That's a great plan. Given that I'd never dragged an older app into modernity like this, that felt like a good start for me. Honestly, I was just happy not having to borrow my partner's laptop to work on the darn thing. I didn't even realize anyone else was working on this. It's good to see. |
Let me know if you want to change anything. This incorporates changes from @Casuallynoted, @taarna23, as well as my own. It fixes #4, wires up bounding box logic, gets the project to run cross-platform with modern .NET, and aligns repo artifacts and organization to current .NET standards.