Improve animations tab, fix Save as Layer, and enhance GB similarity colors
- Fix Save as Layer: convert image to sprite color mode before creating cel - Remove "Selected ->" label (brackets on buttons suffice) - Add Remove button and right-click to remove frames in strip - Add Move Animation Up/Down buttons for reordering animations - Add configurable source viewport height and auto-resize with zoom - Rename GB buttons: Analyze Duplicates, Analyze Similars, Similarity >=X% - Reorder GB buttons: Analyze -> Similars -> Similarity threshold - Use distinct colors per group for similar tile highlighting (union-find) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
534fc09da3
commit
0c1d5d9c90
198
aniphallow.lua
198
aniphallow.lua
|
|
@ -80,6 +80,8 @@ local S = {
|
||||||
gbLayerName = "auto-optimized-tiles", -- default layer name
|
gbLayerName = "auto-optimized-tiles", -- default layer name
|
||||||
gbAlwaysOverwrite = false, -- overwrite layer checkbox
|
gbAlwaysOverwrite = false, -- overwrite layer checkbox
|
||||||
gbTileSize = GB_TILE, -- current tile size used (8 for pixel, from tileset for tile)
|
gbTileSize = GB_TILE, -- current tile size used (8 for pixel, from tileset for tile)
|
||||||
|
sourceViewportH = 250, -- configurable source viewport height
|
||||||
|
sourceAutoResize = false, -- auto-resize source with zoom
|
||||||
-- Dynamic animations: each frame is {x, y, flipped, flippedV}
|
-- Dynamic animations: each frame is {x, y, flipped, flippedV}
|
||||||
animNames = {}, -- ordered list of animation names
|
animNames = {}, -- ordered list of animation names
|
||||||
anims = {}, -- name -> list of {x, y, flipped, flippedV}
|
anims = {}, -- name -> list of {x, y, flipped, flippedV}
|
||||||
|
|
@ -100,10 +102,10 @@ local S = {
|
||||||
-- Setup tab elements (static IDs, dynamic ones added at runtime)
|
-- Setup tab elements (static IDs, dynamic ones added at runtime)
|
||||||
local SETUP_IDS = {
|
local SETUP_IDS = {
|
||||||
"sepAnims", "btnNewAnim", "btnDelAnim",
|
"sepAnims", "btnNewAnim", "btnDelAnim",
|
||||||
"lblSelectedAnim",
|
"btnMoveAnimUp", "btnMoveAnimDown",
|
||||||
"sepSource", "canvasSource",
|
"sepSource", "canvasSource",
|
||||||
"sepFrames", "canvasStrips",
|
"sepFrames", "canvasStrips",
|
||||||
"sepActions", "btnFlipX", "btnFlipY", "btnMoveLeft", "btnMoveRight", "btnClearAnim",
|
"sepActions", "btnFlipX", "btnFlipY", "btnMoveLeft", "btnMoveRight", "btnRemoveFrame", "btnClearAnim",
|
||||||
"sepPreviewAnim", "canvasPreviewAnim",
|
"sepPreviewAnim", "canvasPreviewAnim",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,6 +197,8 @@ local function loadPrefs()
|
||||||
if k == "gbLastSavePath" then S.gbLastSavePath = v end
|
if k == "gbLastSavePath" then S.gbLastSavePath = v end
|
||||||
if k == "gbLayerName" then S.gbLayerName = v end
|
if k == "gbLayerName" then S.gbLayerName = v end
|
||||||
if k == "gbAlwaysOverwrite" then S.gbAlwaysOverwrite = (v == "true") end
|
if k == "gbAlwaysOverwrite" then S.gbAlwaysOverwrite = (v == "true") end
|
||||||
|
if k == "sourceViewportH" then S.sourceViewportH = tonumber(v) or 250 end
|
||||||
|
if k == "sourceAutoResize" then S.sourceAutoResize = (v == "true") end
|
||||||
-- Dynamic anim frames: anim_0, anim_1, ...
|
-- Dynamic anim frames: anim_0, anim_1, ...
|
||||||
local animIdx = k and string.match(k, "^anim_(%d+)$")
|
local animIdx = k and string.match(k, "^anim_(%d+)$")
|
||||||
if animIdx then
|
if animIdx then
|
||||||
|
|
@ -237,6 +241,8 @@ local function savePrefs()
|
||||||
f:write("gbLastSavePath=" .. S.gbLastSavePath .. "\n")
|
f:write("gbLastSavePath=" .. S.gbLastSavePath .. "\n")
|
||||||
f:write("gbLayerName=" .. S.gbLayerName .. "\n")
|
f:write("gbLayerName=" .. S.gbLayerName .. "\n")
|
||||||
f:write("gbAlwaysOverwrite=" .. tostring(S.gbAlwaysOverwrite) .. "\n")
|
f:write("gbAlwaysOverwrite=" .. tostring(S.gbAlwaysOverwrite) .. "\n")
|
||||||
|
f:write("sourceViewportH=" .. S.sourceViewportH .. "\n")
|
||||||
|
f:write("sourceAutoResize=" .. tostring(S.sourceAutoResize) .. "\n")
|
||||||
for i, name in ipairs(S.animNames) do
|
for i, name in ipairs(S.animNames) do
|
||||||
f:write("anim_" .. (i - 1) .. "=" .. serializeFrames(S.anims[name] or {}) .. "\n")
|
f:write("anim_" .. (i - 1) .. "=" .. serializeFrames(S.anims[name] or {}) .. "\n")
|
||||||
end
|
end
|
||||||
|
|
@ -310,7 +316,7 @@ end
|
||||||
local function clampScroll()
|
local function clampScroll()
|
||||||
local contentW, contentH = getSourceContentSize()
|
local contentW, contentH = getSourceContentSize()
|
||||||
local maxScrollX = math.max(0, contentW - SOURCE_VIEWPORT_W)
|
local maxScrollX = math.max(0, contentW - SOURCE_VIEWPORT_W)
|
||||||
local maxScrollY = math.max(0, contentH - SOURCE_VIEWPORT_H)
|
local maxScrollY = math.max(0, contentH - S.sourceViewportH)
|
||||||
S.scrollX = clamp(S.scrollX, 0, maxScrollX)
|
S.scrollX = clamp(S.scrollX, 0, maxScrollX)
|
||||||
S.scrollY = clamp(S.scrollY, 0, maxScrollY)
|
S.scrollY = clamp(S.scrollY, 0, maxScrollY)
|
||||||
end
|
end
|
||||||
|
|
@ -877,7 +883,7 @@ local function run()
|
||||||
|
|
||||||
local contentW, contentH = getSourceContentSize()
|
local contentW, contentH = getSourceContentSize()
|
||||||
local viewW = math.min(contentW, SOURCE_VIEWPORT_W)
|
local viewW = math.min(contentW, SOURCE_VIEWPORT_W)
|
||||||
local viewH = math.min(contentH, SOURCE_VIEWPORT_H)
|
local viewH = math.min(contentH, S.sourceViewportH)
|
||||||
|
|
||||||
local dlg = Dialog{
|
local dlg = Dialog{
|
||||||
title = "AniPhallow - Animation Builder",
|
title = "AniPhallow - Animation Builder",
|
||||||
|
|
@ -909,8 +915,6 @@ local function run()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function updateAnimLabel()
|
local function updateAnimLabel()
|
||||||
local name = currentAnimName() or "(none)"
|
|
||||||
dlg:modify{ id = "lblSelectedAnim", text = "Selected -> " .. name }
|
|
||||||
for i = 1, #S.animNames do
|
for i = 1, #S.animNames do
|
||||||
pcall(function()
|
pcall(function()
|
||||||
local label = (i == S.currentAnim) and ("[" .. S.animNames[i] .. "]") or S.animNames[i]
|
local label = (i == S.currentAnim) and ("[" .. S.animNames[i] .. "]") or S.animNames[i]
|
||||||
|
|
@ -1006,6 +1010,8 @@ local function run()
|
||||||
d:number{ id = "previewZoom", label = "Zoom:", text = tostring(S.previewZoom), decimals = 0 }
|
d:number{ id = "previewZoom", label = "Zoom:", text = tostring(S.previewZoom), decimals = 0 }
|
||||||
d:check{ id = "useBgColor", text = "Solid background", selected = S.useBgColor }
|
d:check{ id = "useBgColor", text = "Solid background", selected = S.useBgColor }
|
||||||
d:color{ id = "bgColor", label = "Bg Color:", color = S.bgColor }
|
d:color{ id = "bgColor", label = "Bg Color:", color = S.bgColor }
|
||||||
|
d:number{ id = "sourceViewportH", label = "Source Height (px):", text = tostring(S.sourceViewportH), decimals = 0 }
|
||||||
|
d:check{ id = "sourceAutoResize", text = "Auto-resize source with zoom", selected = S.sourceAutoResize }
|
||||||
d:separator{ text = "GB Options" }
|
d:separator{ text = "GB Options" }
|
||||||
-- Auto-detect darkest palette color on first open
|
-- Auto-detect darkest palette color on first open
|
||||||
local silColor = S.gbSilhouetteColor
|
local silColor = S.gbSilhouetteColor
|
||||||
|
|
@ -1032,6 +1038,10 @@ local function run()
|
||||||
S.previewZoom = pz
|
S.previewZoom = pz
|
||||||
S.useBgColor = d.data.useBgColor
|
S.useBgColor = d.data.useBgColor
|
||||||
S.bgColor = d.data.bgColor
|
S.bgColor = d.data.bgColor
|
||||||
|
local svh = d.data.sourceViewportH
|
||||||
|
if svh < 50 then svh = 50 elseif svh > 600 then svh = 600 end
|
||||||
|
S.sourceViewportH = svh
|
||||||
|
S.sourceAutoResize = d.data.sourceAutoResize
|
||||||
S.gbSilhouetteColor = d.data.silhouetteColor
|
S.gbSilhouetteColor = d.data.silhouetteColor
|
||||||
S.gbSilhouetteColorSet = true
|
S.gbSilhouetteColorSet = true
|
||||||
S.gbLayerName = d.data.layerName
|
S.gbLayerName = d.data.layerName
|
||||||
|
|
@ -1091,11 +1101,32 @@ local function run()
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
dlg:newrow()
|
dlg:button{
|
||||||
|
id = "btnMoveAnimUp",
|
||||||
|
text = "Move Up",
|
||||||
|
onclick = function()
|
||||||
|
if S.currentAnim <= 1 then return end
|
||||||
|
local i = S.currentAnim
|
||||||
|
S.animNames[i], S.animNames[i - 1] = S.animNames[i - 1], S.animNames[i]
|
||||||
|
S.currentAnim = i - 1
|
||||||
|
savePrefs()
|
||||||
|
dlg:close()
|
||||||
|
run()
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
dlg:label{
|
dlg:button{
|
||||||
id = "lblSelectedAnim",
|
id = "btnMoveAnimDown",
|
||||||
text = "Selected -> " .. (currentAnimName() or "(none)"),
|
text = "Move Down",
|
||||||
|
onclick = function()
|
||||||
|
if S.currentAnim < 1 or S.currentAnim >= #S.animNames then return end
|
||||||
|
local i = S.currentAnim
|
||||||
|
S.animNames[i], S.animNames[i + 1] = S.animNames[i + 1], S.animNames[i]
|
||||||
|
S.currentAnim = i + 1
|
||||||
|
savePrefs()
|
||||||
|
dlg:close()
|
||||||
|
run()
|
||||||
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
dlg:newrow()
|
dlg:newrow()
|
||||||
|
|
@ -1225,6 +1256,10 @@ local function run()
|
||||||
local dz = ev.deltaY < 0 and 1 or -1
|
local dz = ev.deltaY < 0 and 1 or -1
|
||||||
S.sourceZoom = math.max(1, math.min(10, S.sourceZoom + dz))
|
S.sourceZoom = math.max(1, math.min(10, S.sourceZoom + dz))
|
||||||
clampScroll()
|
clampScroll()
|
||||||
|
if S.sourceAutoResize then
|
||||||
|
local newH = math.max(60, math.floor(S.sourceViewportH / S.sourceZoom))
|
||||||
|
dlg:modify{ id = "canvasSource", height = newH }
|
||||||
|
end
|
||||||
dlg:repaint()
|
dlg:repaint()
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
@ -1232,7 +1267,7 @@ local function run()
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
-- Frame strip for current animation
|
-- Frame strip for current animation
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
dlg:separator{ id = "sepFrames", text = "Frames (click to select, drag to reorder)" }
|
dlg:separator{ id = "sepFrames", text = "Frames (left-click=select, right-click=remove, drag=reorder)" }
|
||||||
|
|
||||||
local STRIP_TOTAL_W = SOURCE_VIEWPORT_W
|
local STRIP_TOTAL_W = SOURCE_VIEWPORT_W
|
||||||
local STRIP_CELL = THUMB_SIZE + 1
|
local STRIP_CELL = THUMB_SIZE + 1
|
||||||
|
|
@ -1339,6 +1374,13 @@ local function run()
|
||||||
S.frameDragFrom = idx
|
S.frameDragFrom = idx
|
||||||
S.frameDragTo = idx
|
S.frameDragTo = idx
|
||||||
dlg:repaint()
|
dlg:repaint()
|
||||||
|
elseif ev.button == MouseButton.RIGHT then
|
||||||
|
table.remove(frames, idx)
|
||||||
|
if S.selectedFrame > #frames then
|
||||||
|
S.selectedFrame = #frames
|
||||||
|
end
|
||||||
|
if #frames == 0 then S.selectedFrame = 0 end
|
||||||
|
dlg:repaint()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
@ -1434,6 +1476,23 @@ local function run()
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dlg:button{
|
||||||
|
id = "btnRemoveFrame",
|
||||||
|
text = "Remove",
|
||||||
|
onclick = function()
|
||||||
|
local name = currentAnimName()
|
||||||
|
if not name or S.selectedFrame < 1 then return end
|
||||||
|
local frames = S.anims[name]
|
||||||
|
if not frames or S.selectedFrame > #frames then return end
|
||||||
|
table.remove(frames, S.selectedFrame)
|
||||||
|
if S.selectedFrame > #frames then
|
||||||
|
S.selectedFrame = #frames
|
||||||
|
end
|
||||||
|
if #frames == 0 then S.selectedFrame = 0 end
|
||||||
|
dlg:repaint()
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
dlg:button{
|
dlg:button{
|
||||||
id = "btnClearAnim",
|
id = "btnClearAnim",
|
||||||
text = "Clear Anim",
|
text = "Clear Anim",
|
||||||
|
|
@ -1609,10 +1668,10 @@ local function run()
|
||||||
visible = false,
|
visible = false,
|
||||||
onchange = function() S.gbAnalyzeMode = dlg.data.gbAnalyzeMode end
|
onchange = function() S.gbAnalyzeMode = dlg.data.gbAnalyzeMode end
|
||||||
}
|
}
|
||||||
-- Row: Analyze + >=threshold + Similar (all on one line)
|
-- Row: Analyze Duplicates + Analyze Similars + Similarity threshold (all on one line)
|
||||||
dlg:button{
|
dlg:button{
|
||||||
id = "btnAnalyze",
|
id = "btnAnalyze",
|
||||||
text = "Analyze",
|
text = "Analyze Duplicates",
|
||||||
visible = false,
|
visible = false,
|
||||||
onclick = function()
|
onclick = function()
|
||||||
if not S.sourceImage then return end
|
if not S.sourceImage then return end
|
||||||
|
|
@ -1633,7 +1692,7 @@ local function run()
|
||||||
S.gbScrollY = 0
|
S.gbScrollY = 0
|
||||||
local unique = #S.gbTiles
|
local unique = #S.gbTiles
|
||||||
local total = S.gbTotalTiles
|
local total = S.gbTotalTiles
|
||||||
dlg:modify{ id = "btnAnalyze", text = "Analyze (" .. unique .. "/" .. total .. ")" }
|
dlg:modify{ id = "btnAnalyze", text = "Analyze Duplicates (" .. unique .. "/" .. total .. ")" }
|
||||||
if S.gbOptImage then
|
if S.gbOptImage then
|
||||||
local z = S.gbZoomOpt
|
local z = S.gbZoomOpt
|
||||||
dlg:modify{ id = "canvasGbOpt",
|
dlg:modify{ id = "canvasGbOpt",
|
||||||
|
|
@ -1643,9 +1702,26 @@ local function run()
|
||||||
dlg:repaint()
|
dlg:repaint()
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
dlg:button{
|
||||||
|
id = "btnFindSimilar",
|
||||||
|
text = "Analyze Similars",
|
||||||
|
visible = false,
|
||||||
|
onclick = function()
|
||||||
|
if #S.gbTiles == 0 then
|
||||||
|
app.alert("Run Analyze first.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
S.gbSimilarPairs = findSimilarTiles(
|
||||||
|
S.sourceImage, S.gbTiles, S.gbSimilarThreshold,
|
||||||
|
S.gbFlipOpt, S.gbOffsetOpt)
|
||||||
|
dlg:modify{ id = "btnFindSimilar",
|
||||||
|
text = "Analyze Similars (" .. #S.gbSimilarPairs .. ")" }
|
||||||
|
dlg:repaint()
|
||||||
|
end
|
||||||
|
}
|
||||||
dlg:button{
|
dlg:button{
|
||||||
id = "gbSimilarThreshold",
|
id = "gbSimilarThreshold",
|
||||||
text = ">=" .. S.gbSimilarThreshold .. "%",
|
text = "Similarity >=" .. S.gbSimilarThreshold .. "%",
|
||||||
visible = false,
|
visible = false,
|
||||||
onclick = function()
|
onclick = function()
|
||||||
local d = Dialog{ title = "Similarity Threshold" }
|
local d = Dialog{ title = "Similarity Threshold" }
|
||||||
|
|
@ -1659,27 +1735,10 @@ local function run()
|
||||||
if v < 1 then v = 1 end
|
if v < 1 then v = 1 end
|
||||||
if v > 100 then v = 100 end
|
if v > 100 then v = 100 end
|
||||||
S.gbSimilarThreshold = v
|
S.gbSimilarThreshold = v
|
||||||
dlg:modify{ id = "gbSimilarThreshold", text = ">=" .. v .. "%" }
|
dlg:modify{ id = "gbSimilarThreshold", text = "Similarity >=" .. v .. "%" }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
dlg:button{
|
|
||||||
id = "btnFindSimilar",
|
|
||||||
text = "Similar",
|
|
||||||
visible = false,
|
|
||||||
onclick = function()
|
|
||||||
if #S.gbTiles == 0 then
|
|
||||||
app.alert("Run Analyze first.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
S.gbSimilarPairs = findSimilarTiles(
|
|
||||||
S.sourceImage, S.gbTiles, S.gbSimilarThreshold,
|
|
||||||
S.gbFlipOpt, S.gbOffsetOpt)
|
|
||||||
dlg:modify{ id = "btnFindSimilar",
|
|
||||||
text = "Similar (" .. #S.gbSimilarPairs .. ")" }
|
|
||||||
dlg:repaint()
|
|
||||||
end
|
|
||||||
}
|
|
||||||
dlg:label{ id = "lblSimilarStats", text = "", visible = false }
|
dlg:label{ id = "lblSimilarStats", text = "", visible = false }
|
||||||
|
|
||||||
-- Optimized tileset canvas
|
-- Optimized tileset canvas
|
||||||
|
|
@ -1743,22 +1802,70 @@ local function run()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Highlight tiles involved in similar pairs
|
-- Highlight tiles involved in similar pairs with distinct group colors
|
||||||
if #S.gbSimilarPairs > 0 then
|
if #S.gbSimilarPairs > 0 then
|
||||||
|
-- Build groups using union-find
|
||||||
|
local parent = {}
|
||||||
|
local function find(x)
|
||||||
|
if not parent[x] then parent[x] = x end
|
||||||
|
while parent[x] ~= x do
|
||||||
|
parent[x] = parent[parent[x]]
|
||||||
|
x = parent[x]
|
||||||
|
end
|
||||||
|
return x
|
||||||
|
end
|
||||||
|
local function union(a, b)
|
||||||
|
local ra, rb = find(a), find(b)
|
||||||
|
if ra ~= rb then parent[ra] = rb end
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, pair in ipairs(S.gbSimilarPairs) do
|
||||||
|
union(pair.i, pair.j)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Assign color index to each group root
|
||||||
|
local groupColors = {}
|
||||||
|
local colorIdx = 0
|
||||||
|
-- Predefined distinct hues
|
||||||
|
local GROUP_HUES = {
|
||||||
|
Color(255, 0, 255, 150), -- magenta
|
||||||
|
Color(0, 200, 255, 150), -- cyan
|
||||||
|
Color(255, 128, 0, 150), -- orange
|
||||||
|
Color(0, 255, 128, 150), -- spring green
|
||||||
|
Color(255, 255, 0, 150), -- yellow
|
||||||
|
Color(128, 0, 255, 150), -- purple
|
||||||
|
Color(255, 0, 128, 150), -- pink
|
||||||
|
Color(0, 255, 0, 150), -- green
|
||||||
|
Color(0, 128, 255, 150), -- blue
|
||||||
|
Color(255, 64, 64, 150), -- red
|
||||||
|
Color(128, 255, 0, 150), -- lime
|
||||||
|
Color(255, 0, 64, 150), -- crimson
|
||||||
|
Color(0, 255, 255, 150), -- aqua
|
||||||
|
Color(200, 100, 255, 150), -- lavender
|
||||||
|
Color(255, 200, 0, 150), -- gold
|
||||||
|
Color(100, 255, 200, 150), -- mint
|
||||||
|
}
|
||||||
|
|
||||||
local similarSet = {}
|
local similarSet = {}
|
||||||
for _, pair in ipairs(S.gbSimilarPairs) do
|
for _, pair in ipairs(S.gbSimilarPairs) do
|
||||||
similarSet[pair.i] = true
|
local root = find(pair.i)
|
||||||
similarSet[pair.j] = true
|
if not groupColors[root] then
|
||||||
|
colorIdx = colorIdx + 1
|
||||||
|
groupColors[root] = GROUP_HUES[((colorIdx - 1) % #GROUP_HUES) + 1]
|
||||||
end
|
end
|
||||||
|
similarSet[pair.i] = groupColors[find(pair.i)]
|
||||||
|
similarSet[pair.j] = groupColors[find(pair.j)]
|
||||||
|
end
|
||||||
|
|
||||||
local rw = ts * z
|
local rw = ts * z
|
||||||
local rh = ts * z
|
local rh = ts * z
|
||||||
for idx, _ in pairs(similarSet) do
|
for idx, c in pairs(similarSet) do
|
||||||
local tx, ty = tilePos(idx)
|
local tx, ty = tilePos(idx)
|
||||||
local srx = tx * z - S.gbScrollX
|
local srx = tx * z - S.gbScrollX
|
||||||
local sry = ty * z - S.gbScrollY
|
local sry = ty * z - S.gbScrollY
|
||||||
gc.color = Color(255, 0, 255, 40)
|
gc.color = Color(c.red, c.green, c.blue, 40)
|
||||||
gc:fillRect(Rectangle(srx, sry, rw, rh))
|
gc:fillRect(Rectangle(srx, sry, rw, rh))
|
||||||
gc.color = Color(255, 0, 255, 150)
|
gc.color = c
|
||||||
gc:fillRect(Rectangle(srx, sry, rw, 1))
|
gc:fillRect(Rectangle(srx, sry, rw, 1))
|
||||||
gc:fillRect(Rectangle(srx, sry + rh - 1, rw, 1))
|
gc:fillRect(Rectangle(srx, sry + rh - 1, rw, 1))
|
||||||
gc:fillRect(Rectangle(srx, sry, 1, rh))
|
gc:fillRect(Rectangle(srx, sry, 1, rh))
|
||||||
|
|
@ -1993,7 +2100,9 @@ local function run()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local imgCopy = S.gbOptImage:clone()
|
local imgConverted = Image(S.gbOptImage.width, S.gbOptImage.height, sp.colorMode)
|
||||||
|
imgConverted:clear()
|
||||||
|
imgConverted:drawImage(S.gbOptImage, Point(0, 0))
|
||||||
app.transaction("Save Optimized Layer", function()
|
app.transaction("Save Optimized Layer", function()
|
||||||
if existingLayer then
|
if existingLayer then
|
||||||
if S.gbAlwaysOverwrite then
|
if S.gbAlwaysOverwrite then
|
||||||
|
|
@ -2001,7 +2110,8 @@ local function run()
|
||||||
for _, cel in ipairs(existingLayer.cels) do
|
for _, cel in ipairs(existingLayer.cels) do
|
||||||
sp:deleteCel(cel)
|
sp:deleteCel(cel)
|
||||||
end
|
end
|
||||||
sp:newCel(existingLayer, app.frame, imgCopy, Point(0, 0))
|
sp:newCel(existingLayer, app.frame, imgConverted, Point(0, 0))
|
||||||
|
existingLayer.isEditable = false
|
||||||
else
|
else
|
||||||
local suffix = 2
|
local suffix = 2
|
||||||
local newName = layerName .. "-" .. suffix
|
local newName = layerName .. "-" .. suffix
|
||||||
|
|
@ -2019,12 +2129,14 @@ local function run()
|
||||||
end
|
end
|
||||||
local newLayer = sp:newLayer()
|
local newLayer = sp:newLayer()
|
||||||
newLayer.name = newName
|
newLayer.name = newName
|
||||||
sp:newCel(newLayer, app.frame, imgCopy, Point(0, 0))
|
sp:newCel(newLayer, app.frame, imgConverted, Point(0, 0))
|
||||||
|
newLayer.isEditable = false
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local newLayer = sp:newLayer()
|
local newLayer = sp:newLayer()
|
||||||
newLayer.name = layerName
|
newLayer.name = layerName
|
||||||
sp:newCel(newLayer, app.frame, imgCopy, Point(0, 0))
|
sp:newCel(newLayer, app.frame, imgConverted, Point(0, 0))
|
||||||
|
newLayer.isEditable = false
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue