Releases: jamesknopp/JamEditor
v1.2.0 - Move tool, high-DPI support, batch convert, canvas packing and more
JamEditor v1.2.0
First major update since the initial v001 release in December 2025. This release covers approximately four months of active development across the editor core, canvas interaction, file handling, texture management, and display. Every area of the application has seen work.
Canvas interaction
Move and resize tool
A dedicated move/resize tool has been added alongside the existing selection mode. Textures can be dragged to reposition them and resized by dragging any of the eight handles around the selection (corners, edges). Corners preserve the aspect ratio when resizing. The cursor updates to indicate the active handle zone. A dirty-rect optimised drag preview redraws only the changed screen region each frame, keeping performance high even at large canvas sizes.
Texture snapping
An optional snap system aligns textures to the edges and centres of neighbouring textures and to the canvas boundary. Snap guides are drawn as coloured overlay lines when a snap is active. The toggle is available from the toolbar and the View menu, and the state is persisted across sessions.
Smooth zoom animation
Zoom now animates with an easing curve rather than snapping immediately. The toolbar +/- buttons and Alt+Scroll Wheel all use the animated path. A scroll anchor ensures the point under the cursor (or the viewport centre for toolbar buttons) stays pinned throughout the animation, eliminating the position jump that previously occurred as the ScrollBox took over.
Space-bar canvas pan
Holding Space and dragging pans the canvas viewport, consistent with the convention used in most image editors.
High-DPI display support
A new View - Scale for High-DPI Display toggle multiplies the canvas zoom by the monitor physical DPI factor, making texture atlases render at a useful size on 4K and other high-PPI displays without affecting the logical zoom setting. The physical DPI is read via GetDpiForMonitor(MDT_RAW_DPI) from shcore.dll, which returns the true hardware PPI regardless of Windows display scaling settings or application DPI-awareness mode.
Moving the window between monitors refreshes the DPI factor and redraws automatically, with no restart required. The monitor refresh rate is also re-queried on each screen crossing and used to set the drag frame cap.
The zoom label shows the active factor when scaling is on, for example Zoom: 100% [DPI x1.7]. The toggle state is saved to the registry alongside other preferences.
Drag and rendering performance
Drag-frame throttling previously used GetTickCount, which has a 15 ms resolution and produces irregular intervals that show up as jitter during texture move and resize operations. This has been replaced with QueryPerformanceCounter (sub-microsecond resolution). The frame interval is derived from the monitor actual refresh rate via GetDeviceCaps(VREFRESH), falling back to 100 Hz if the query returns an implausible value.
Texture auto-pack
The auto-pack algorithm has been rewritten. The original implementation placed textures in simple left-to-right rows, leaving large gaps when texture heights varied within a row. The replacement uses a gap-fitting approach: after each placement, the remaining space in the row and below the placed texture are recorded as candidate gaps, and subsequent textures are placed into the best-fitting gap. Textures are sorted tallest-first before placement so the most constraining items are packed first.
Canvas height changes are now propagated through a proper ChangeJamCanvasHeight method on both the SW and HW JAM types, which updates the header, resizes the internal bitmap, and keeps the canvas height spin-edit in sync.
Batch convert
The batch converter has been substantially reworked:
- A path-index dictionary replaces the previous linear scan for duplicate detection, so adding hundreds of files to the queue is fast
- Item creation is centralised with automatic input-type detection and smart output-type and output-path defaults (SW to HW, HW to SW, GP2 to GP3 SW; Gp3Jams / Gp3JamsH folder pairs are toggled automatically)
- Conversion is decoupled from the UI thread so the interface remains responsive during long operations
- Per-item progress and status are written back to the list view as each file completes
- Output path now receives the full file path rather than just the directory, fixing a bug that caused saves to fail silently
- The batch form UI has been overhauled with a cleaner layout, better progress reporting and improved error display
Undo system
The undo and redo stacks have been reworked. State is now pushed through a consistent path gated by a flag that prevents duplicate captures when a single user action triggers multiple property-change notifications. Undo and redo menu items are kept consistent across all code paths that modify JAM data.
RCR JAM handling
RCR texture deinterlacing now accepts the JAM canvas height as a parameter, allowing correct handling of RCR files whose dimensions differ from the default. The two interleaved colour channels are stored as separate bitmaps per entry and composited for display. Canvas width is correctly selected between 512 (RCR) and 256 (standard SW) depending on file type. GP2/GP3 palettes are applied to RCR textures at load time.
JIP mipmap drawing
JIP files now have a dedicated mipmap drawing procedure on the HW JAM type. RCR-specific texture drawing has been separated from the general single-texture path so that each rendering path is clean and does not branch on file type mid-render.
JAM Browser
The background thumbnail loader has been stabilised:
- A generation counter and current-path guard prevent stale results from a previous folder appearing when the user navigates quickly
- List-view updates now use TThread.Synchronize, eliminating a class of race conditions where the UI could be updated after the browser had already moved on
- All JAM state globals (loaded file, type flags, selected texture, palette ID, etc.) are saved before a preview load and fully restored afterwards, preventing the browser from corrupting the main editor state
- Thumbnail background colour is taken from the list view rather than a hardcoded value
UI layout
- Canvas info bar added above the ScrollBox showing the current canvas dimensions, a height spin-edit, a Fit-to-Textures button, and the zoom level indicator
- Toolbar extended with buttons for: Transparency (checkerboard background toggle), Batch Convert, Auto Pack, and JAM Analysis
- Texture Properties panel collapsed to a compact single-row horizontal strip, recovering vertical space in the sidebar
- Texture Flags panel: the six unlabelled flags (Flag 11-16) are hidden by default; a Show unknown flags (advanced) checkbox reveals them when needed
- Sidebar panel order revised to: Texture Properties, Texture Flags, Scaling Parameters, GP2/GP3 SW Palette Creation
- JAM Canvas accordion panel removed; its controls are now in the canvas info bar
- About dialog added
JAM loading
Opening a JAM file no longer sets the modified flag. Previously the act of loading triggered the same code path as an edit, causing a spurious save prompt on first close.
Conversion menu
The three JAM conversion menu items (Convert to GP2, GP3 SW, GP3 HW) are now correctly enabled and disabled depending on the type of the currently loaded file.
Stability and correctness
- Fixed a crash on startup caused by WM_MOVE firing during window construction before FormCreate had run
- Custom path-delimiter helpers removed in favour of Delphi RTL equivalents
- Release build configuration corrected: debug-symbol overrides that were inadvertently left in the Release property group have been removed, so release builds no longer embed debug tables
- Binary version resource updated to 1.2.0.0
Jam Editor v01
Initial release of JamEditor, probably buggy. Set myself a task of rebuilding Jam Editor as a personal project.
Main efforts for this release was to allow conversion to/from HW Jams and rebuilding of palette support. Batch conversion broadly works.
Releasing source code - messy and not my best coding. Trying to remember old methods/decrypting HW Jams!
Support for RCR jam viewing... Could be of some interest.
Credits:
Trevor Kellaway, Paul Hoad, Mal Ross, John Verheijen