Compare commits

...

4 Commits

Author SHA1 Message Date
e1cfcc8b5f [nostalgia] Update release notes
All checks were successful
Build / build (push) Successful in 1m13s
2025-05-30 23:37:58 -05:00
514cb97835 [nostalgia/gfx/studio/tilesheet] Fix draw command to work on same pixel after switching subsheets 2025-05-30 23:32:51 -05:00
4b5218c4f1 [nostalgia/gfx] Cleanup 2025-05-30 23:32:27 -05:00
2ca77173d3 [keel] Add isUuidUrl function 2025-05-30 23:29:42 -05:00
6 changed files with 51 additions and 40 deletions

View File

@ -3,6 +3,11 @@
* Add ability to remember recent projects in config * Add ability to remember recent projects in config
* PaletteEditor: Add RGB key shortcuts for focusing color channels * PaletteEditor: Add RGB key shortcuts for focusing color channels
# d2025.05.2
* TileSheetEditor: Fix manual redo of draw actions, fix drawing to pixel 0, 0 as first action (cce5f52f96511694afd98f0b9b6b1f19c06ecd20)
* TileSheetEditor: Fix draw command to work on same pixel after switching subsheets (514cb978351ee4b0a5335c22a506a6d9f608f0a7)
# d2025.05.1 # d2025.05.1
* TileSheetEditor: Fix overrun errors when switching subsheets, clear selection * TileSheetEditor: Fix overrun errors when switching subsheets, clear selection

View File

@ -350,7 +350,7 @@ void panic(const char *file, int line, const char *panicMsg, ox::Error const&err
const auto heapEnd = reinterpret_cast<char*>(MEM_EWRAM_BEGIN + heapSz); const auto heapEnd = reinterpret_cast<char*>(MEM_EWRAM_BEGIN + heapSz);
ox::heapmgr::initHeap(heapBegin, heapEnd); ox::heapmgr::initHeap(heapBegin, heapEnd);
OX_ALLOW_UNSAFE_BUFFERS_END OX_ALLOW_UNSAFE_BUFFERS_END
auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap(); auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap();
auto ctx = init(*tctx).unwrap(); auto ctx = init(*tctx).unwrap();
std::ignore = initGfx(); std::ignore = initGfx();
std::ignore = initConsole(*ctx); std::ignore = initConsole(*ctx);

View File

@ -126,7 +126,7 @@ void TileSheetEditorModel::paste() {
auto const pt1 = m_selection->a; auto const pt1 = m_selection->a;
auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight}; auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
if (auto const cmd = ox::makeCatch<CutPasteCommand>( if (auto const cmd = ox::makeCatch<CutPasteCommand>(
CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb); cmd.ok()) { CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb); cmd.value) {
std::ignore = pushCommand(cmd.value); std::ignore = pushCommand(cmd.value);
} }
} }
@ -202,38 +202,39 @@ void TileSheetEditorModel::endDrawCommand() noexcept {
} }
} }
void TileSheetEditorModel::addSubsheet(TileSheet::SubSheetIdx const&parentIdx) noexcept { void TileSheetEditorModel::addSubsheet(TileSheet::SubSheetIdx const &parentIdx) noexcept {
std::ignore = pushCommand(ox::make<AddSubSheetCommand>(m_img, parentIdx)); std::ignore = pushCommand(ox::make<AddSubSheetCommand>(m_img, parentIdx));
} }
void TileSheetEditorModel::rmSubsheet(TileSheet::SubSheetIdx const&idx) noexcept { void TileSheetEditorModel::rmSubsheet(TileSheet::SubSheetIdx const &idx) noexcept {
std::ignore = pushCommand(ox::make<RmSubSheetCommand>(m_img, idx)); std::ignore = pushCommand(ox::make<RmSubSheetCommand>(m_img, idx));
} }
void TileSheetEditorModel::insertTiles( void TileSheetEditorModel::insertTiles(
TileSheet::SubSheetIdx const&idx, std::size_t const tileIdx, std::size_t const tileCnt) noexcept { TileSheet::SubSheetIdx const &idx, std::size_t const tileIdx, std::size_t const tileCnt) noexcept {
std::ignore = pushCommand(ox::make<InsertTilesCommand>(m_img, idx, tileIdx, tileCnt)); std::ignore = pushCommand(ox::make<InsertTilesCommand>(m_img, idx, tileIdx, tileCnt));
} }
void TileSheetEditorModel::deleteTiles( void TileSheetEditorModel::deleteTiles(
TileSheet::SubSheetIdx const&idx, std::size_t const tileIdx, std::size_t const tileCnt) noexcept { TileSheet::SubSheetIdx const &idx, std::size_t const tileIdx, std::size_t const tileCnt) noexcept {
std::ignore = pushCommand(ox::make<DeleteTilesCommand>(m_img, idx, tileIdx, tileCnt)); std::ignore = pushCommand(ox::make<DeleteTilesCommand>(m_img, idx, tileIdx, tileCnt));
} }
ox::Error TileSheetEditorModel::updateSubsheet( ox::Error TileSheetEditorModel::updateSubsheet(
TileSheet::SubSheetIdx const&idx, ox::StringViewCR name, int const cols, int const rows) noexcept { TileSheet::SubSheetIdx const &idx, ox::StringViewCR name, int const cols, int const rows) noexcept {
OX_REQUIRE(cmd, ox::makeCatch<UpdateSubSheetCommand>(m_img, idx, name, cols, rows)); OX_REQUIRE(cmd, ox::makeCatch<UpdateSubSheetCommand>(m_img, idx, name, cols, rows));
std::ignore = pushCommand(cmd); std::ignore = pushCommand(cmd);
return {}; return {};
} }
void TileSheetEditorModel::setActiveSubsheet(TileSheet::SubSheetIdx const&idx) noexcept { void TileSheetEditorModel::setActiveSubsheet(TileSheet::SubSheetIdx const &idx) noexcept {
m_activeSubsSheetIdx = idx; m_activeSubsSheetIdx = idx;
this->activeSubsheetChanged.emit(m_activeSubsSheetIdx); this->activeSubsheetChanged.emit(m_activeSubsSheetIdx);
clearSelection(); clearSelection();
m_lastDrawUpdatePt = {-1, -1};
} }
void TileSheetEditorModel::fill(ox::Point const&pt, int const palIdx) noexcept { void TileSheetEditorModel::fill(ox::Point const &pt, uint8_t const palIdx) noexcept {
auto const&activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx); auto const&activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx);
// build idx list // build idx list
if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) { if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) {
@ -280,7 +281,7 @@ ox::Error TileSheetEditorModel::rotateRight() noexcept {
m_img, m_activeSubsSheetIdx, pt1, pt2, RotateCommand::Direction::Right)); m_img, m_activeSubsSheetIdx, pt1, pt2, RotateCommand::Direction::Right));
} }
void TileSheetEditorModel::setSelection(studio::Selection const&sel) noexcept { void TileSheetEditorModel::setSelection(studio::Selection const &sel) noexcept {
auto const &ss = activeSubSheet(); auto const &ss = activeSubSheet();
if (sel.a.x < ss.columns * TileWidth && sel.a.y < ss.rows * TileHeight) { if (sel.a.x < ss.columns * TileWidth && sel.a.y < ss.rows * TileHeight) {
m_selection.emplace(sel); m_selection.emplace(sel);
@ -291,7 +292,7 @@ void TileSheetEditorModel::setSelection(studio::Selection const&sel) noexcept {
m_updated = true; m_updated = true;
} }
void TileSheetEditorModel::select(ox::Point const&pt) noexcept { void TileSheetEditorModel::select(ox::Point const &pt) noexcept {
if (m_selTracker.updateCursorPoint(pt)) { if (m_selTracker.updateCursorPoint(pt)) {
setSelection(m_selTracker.selection()); setSelection(m_selTracker.selection());
} }
@ -318,7 +319,7 @@ bool TileSheetEditorModel::updated() const noexcept {
return m_updated; return m_updated;
} }
ox::Error TileSheetEditorModel::markUpdatedCmdId(studio::UndoCommand const*cmd) noexcept { ox::Error TileSheetEditorModel::markUpdatedCmdId(studio::UndoCommand const *cmd) noexcept {
m_updated = true; m_updated = true;
auto const cmdId = cmd->commandId(); auto const cmdId = cmd->commandId();
if (static_cast<CommandId>(cmdId) == CommandId::PaletteChange) { if (static_cast<CommandId>(cmdId) == CommandId::PaletteChange) {
@ -394,9 +395,9 @@ ox::Error TileSheetEditorModel::moveSubSheet(TileSheet::SubSheetIdx src, TileShe
void TileSheetEditorModel::getFillPixels( void TileSheetEditorModel::getFillPixels(
TileSheet::SubSheet const&activeSubSheet, TileSheet::SubSheet const&activeSubSheet,
ox::Span<bool> pixels, ox::Span<bool> const pixels,
ox::Point const&pt, ox::Point const &pt,
int const oldColor) const noexcept { uint8_t const oldColor) noexcept {
auto const idx = ptToIdx(pt, activeSubSheet.columns); auto const idx = ptToIdx(pt, activeSubSheet.columns);
auto const relIdx = idx % PixelsPerTile; auto const relIdx = idx % PixelsPerTile;
if (pixels[relIdx] || activeSubSheet.pixels[idx] != oldColor) { if (pixels[relIdx] || activeSubSheet.pixels[idx] != oldColor) {

View File

@ -14,7 +14,7 @@
namespace nostalgia::gfx { namespace nostalgia::gfx {
class TileSheetEditorModel: public ox::SignalHandler { class TileSheetEditorModel final: public ox::SignalHandler {
public: public:
ox::Signal<ox::Error(const TileSheet::SubSheetIdx&)> activeSubsheetChanged; ox::Signal<ox::Error(const TileSheet::SubSheetIdx&)> activeSubsheetChanged;
@ -53,13 +53,13 @@ class TileSheetEditorModel: public ox::SignalHandler {
bool acceptsClipboardPayload() const noexcept; bool acceptsClipboardPayload() const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr TileSheet const&img() const noexcept; constexpr TileSheet const &img() const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr TileSheet &img() noexcept; constexpr TileSheet &img() noexcept;
[[nodiscard]] [[nodiscard]]
constexpr Palette const&pal() const noexcept; constexpr Palette const &pal() const noexcept;
[[nodiscard]] [[nodiscard]]
ox::String const &palPath() const & noexcept; ox::String const &palPath() const & noexcept;
@ -71,26 +71,26 @@ class TileSheetEditorModel: public ox::SignalHandler {
[[nodiscard]] [[nodiscard]]
size_t palettePage() const noexcept; size_t palettePage() const noexcept;
void drawCommand(ox::Point const&pt, std::size_t palIdx) noexcept; void drawCommand(ox::Point const &pt, std::size_t palIdx) noexcept;
void drawLineCommand(ox::Point const&pt, std::size_t palIdx) noexcept; void drawLineCommand(ox::Point const &pt, std::size_t palIdx) noexcept;
void endDrawCommand() noexcept; void endDrawCommand() noexcept;
void addSubsheet(TileSheet::SubSheetIdx const&parentIdx) noexcept; void addSubsheet(TileSheet::SubSheetIdx const &parentIdx) noexcept;
void rmSubsheet(TileSheet::SubSheetIdx const&idx) noexcept; void rmSubsheet(TileSheet::SubSheetIdx const &idx) noexcept;
void insertTiles(TileSheet::SubSheetIdx const&idx, std::size_t tileIdx, std::size_t tileCnt) noexcept; void insertTiles(TileSheet::SubSheetIdx const &idx, std::size_t tileIdx, std::size_t tileCnt) noexcept;
void deleteTiles(TileSheet::SubSheetIdx const&idx, std::size_t tileIdx, std::size_t tileCnt) noexcept; void deleteTiles(TileSheet::SubSheetIdx const &idx, std::size_t tileIdx, std::size_t tileCnt) noexcept;
ox::Error updateSubsheet(TileSheet::SubSheetIdx const&idx, ox::StringView const&name, int cols, int rows) noexcept; ox::Error updateSubsheet(TileSheet::SubSheetIdx const &idx, ox::StringView const &name, int cols, int rows) noexcept;
void setActiveSubsheet(TileSheet::SubSheetIdx const&) noexcept; void setActiveSubsheet(TileSheet::SubSheetIdx const &) noexcept;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheet const&activeSubSheet() const noexcept { TileSheet::SubSheet const &activeSubSheet() const noexcept {
return getSubSheet(m_img, m_activeSubsSheetIdx); return getSubSheet(m_img, m_activeSubsSheetIdx);
} }
@ -100,19 +100,19 @@ class TileSheetEditorModel: public ox::SignalHandler {
} }
[[nodiscard]] [[nodiscard]]
constexpr TileSheet::SubSheetIdx const&activeSubSheetIdx() const noexcept { constexpr TileSheet::SubSheetIdx const &activeSubSheetIdx() const noexcept {
return m_activeSubsSheetIdx; return m_activeSubsSheetIdx;
} }
void fill(ox::Point const&pt, int palIdx) noexcept; void fill(ox::Point const &pt, uint8_t palIdx) noexcept;
ox::Error rotateLeft() noexcept; ox::Error rotateLeft() noexcept;
ox::Error rotateRight() noexcept; ox::Error rotateRight() noexcept;
void setSelection(studio::Selection const&sel) noexcept; void setSelection(studio::Selection const &sel) noexcept;
void select(ox::Point const&pt) noexcept; void select(ox::Point const &pt) noexcept;
void completeSelection() noexcept; void completeSelection() noexcept;
@ -121,7 +121,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
[[nodiscard]] [[nodiscard]]
bool updated() const noexcept; bool updated() const noexcept;
ox::Error markUpdatedCmdId(studio::UndoCommand const*cmd) noexcept; ox::Error markUpdatedCmdId(studio::UndoCommand const *cmd) noexcept;
ox::Error markUpdated() noexcept; ox::Error markUpdated() noexcept;
@ -144,21 +144,21 @@ class TileSheetEditorModel: public ox::SignalHandler {
ox::Error moveSubSheet(TileSheet::SubSheetIdx src, TileSheet::SubSheetIdx dst) noexcept; ox::Error moveSubSheet(TileSheet::SubSheetIdx src, TileSheet::SubSheetIdx dst) noexcept;
private: private:
void getFillPixels( static void getFillPixels(
TileSheet::SubSheet const&activeSubSheet, TileSheet::SubSheet const &activeSubSheet,
ox::Span<bool> pixels, ox::Span<bool> pixels,
ox::Point const&pt, ox::Point const &pt,
int oldColor) const noexcept; uint8_t oldColor) noexcept;
void setPalPath() noexcept; void setPalPath() noexcept;
ox::Error pushCommand(studio::UndoCommand *cmd) noexcept; ox::Error pushCommand(studio::UndoCommand *cmd) noexcept;
ox::Error handleFileRename(ox::StringViewCR, ox::StringViewCR newPath, ox::UUID const&id) noexcept; ox::Error handleFileRename(ox::StringViewCR, ox::StringViewCR newPath, ox::UUID const &id) noexcept;
}; };
constexpr TileSheet const&TileSheetEditorModel::img() const noexcept { constexpr TileSheet const &TileSheetEditorModel::img() const noexcept {
return m_img; return m_img;
} }
@ -166,7 +166,7 @@ constexpr TileSheet &TileSheetEditorModel::img() noexcept {
return m_img; return m_img;
} }
constexpr Palette const&TileSheetEditorModel::pal() const noexcept { constexpr Palette const &TileSheetEditorModel::pal() const noexcept {
if (m_pal) { if (m_pal) {
return *m_pal; return *m_pal;
} }

View File

@ -89,7 +89,7 @@ void TileSheetEditorView::clickSelect(ox::Vec2 const&paneSize, ox::Vec2 const&cl
void TileSheetEditorView::clickFill(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept { void TileSheetEditorView::clickFill(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept {
auto const pt = clickPoint(paneSize, clickPos); auto const pt = clickPoint(paneSize, clickPos);
m_model.fill(pt, static_cast<int>(m_palIdx)); m_model.fill(pt, static_cast<uint8_t>(m_palIdx));
} }
void TileSheetEditorView::releaseMouseButton(TileSheetTool tool) noexcept { void TileSheetEditorView::releaseMouseButton(TileSheetTool tool) noexcept {

View File

@ -60,6 +60,11 @@ ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::StringViewCR uuid) noex
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept; ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept;
[[nodiscard]]
constexpr bool isUuidUrl(ox::StringViewCR path) noexcept {
return ox::beginsWith(path, "uuid://");
}
#ifndef OX_BARE_METAL #ifndef OX_BARE_METAL
namespace detail { namespace detail {