-- Displacement Map Visualizer -- -- This script will create a little preview window that will test a displacement map. -- -- TODO: Handling of sizes != 127 doesn't work properly and rounds differently from the real shader. Ah well. local scale = 4 -- This script requires UI if not app.isUIAvailable then return end local getOffsetPixel = function(x, y, image, rect) local posX = x - rect.x local posY = y - rect.y if posX < 0 or posX >= image.width or posY < 0 or posY >= image.height then return image.spec.transparentColor end return image:getPixel(posX, posY) end local pixelValueToColor = function(sprite, value) return Color(value) end local applyDisplacementMap = function(width, height, size, displacement, displacementRect, target, targetRect) -- print(Color(displacement:getPixel(17, 15)).red) local image = target:clone() image:resize(width, height) image:clear() for x = 0, width - 1 do for y = 0, height - 1 do local value = getOffsetPixel(x, y, displacement, displacementRect) local color = pixelValueToColor(sprite, value) if color.alpha ~= 0 then local offset_x = (color.red - 128) / 127 * size local offset_y = (color.green - 128) / 127 * size local colorValue = getOffsetPixel(x + offset_x, y + offset_y, target, targetRect) image:drawPixel(x, y, colorValue) end end end return image end local dialog = nil local sprite = app.editor.sprite local spriteChanged = sprite.events:on("change", function(ev) dialog:repaint() end) local layers = {} for i,layer in ipairs(sprite.layers) do table.insert(layers, 1, layer.name) end local findLayer = function(sprite, name) for i, layer in ipairs(sprite.layers) do if layer.name == name then return layer end end return nil end local applyOffset = function(dx, dy) local cel = app.cel local image = cel.image:clone() local sprite = app.editor.sprite local selection = sprite.selection for x = selection.bounds.x, selection.bounds.x + selection.bounds.width - 1 do for y = selection.bounds.y, selection.bounds.y + selection.bounds.height - 1 do local xImg = x - cel.position.x local yImg = y - cel.position.y if xImg >= 0 and xImg < image.width and yImg >= 0 and yImg < image.height then local pixelValue = image:getPixel(xImg, yImg) local color = Color(pixelValue) -- Offset R and G channel color.red = math.min(255, math.max(0, color.red + dx)) color.green = math.min(255, math.max(0, color.green + dy)) image:drawPixel(xImg, yImg, app.pixelColor.rgba(color.red, color.green, color.blue, color.alpha)) end end end cel.image = image dialog:repaint() end dialog = Dialog{ title = "Displacement map preview", onclose = function(ev) sprite.events:off(spriteChanged) end} dialog:canvas{ id = "canvas", width = sprite.width * scale, height = sprite.height * scale, onpaint = function(ev) local context = ev.context local layerDisplacement = findLayer(sprite, dialog.data["displacement-select"]) local layerTarget = findLayer(sprite, dialog.data["reference-select"]) local layerBackground = findLayer(sprite, dialog.data["background-select"]) -- print(layerDisplacement.name) -- print(layerTarget.name) local celDisplacement = layerDisplacement:cel(1) local celTarget = layerTarget:cel(1) local celBackground = layerBackground:cel(1) -- Draw background context:drawImage( -- srcImage celBackground.image, -- srcPos 0, 0, -- srcSize celBackground.image.width, celBackground.image.height, -- dstPos celBackground.position.x * scale, celBackground.position.y * scale, -- dstSize celBackground.image.width * scale, celBackground.image.height * scale) -- Apply displacement map and draw local image = applyDisplacementMap( sprite.width, sprite.height, dialog.data["size"], celDisplacement.image, celDisplacement.bounds, celTarget.image, celTarget.bounds) context:drawImage( -- srcImage image, -- srcPos 0, 0, -- srcSize image.width, image.height, -- dstPos 0, 0, -- dstSize image.width * scale, image.height * scale) end } dialog:combobox{ id = "displacement-select", label = "displacement layer", options = layers, onchange = function(ev) dialog:repaint() end } dialog:combobox{ id = "reference-select", label = "reference layer", options = layers, onchange = function(ev) dialog:repaint() end } dialog:combobox{ id = "background-select", label = "background layer", options = layers, onchange = function(ev) dialog:repaint() end } dialog:slider{ id = "size", label = "displacement size", min = 127, --We dont support non 127 atm max = 127, value = 127, onchange = function(ev) dialog:repaint() end } dialog:button{ id = "moveDown", text = "Down", onclick = function(ev) applyOffset(0, -1) end } dialog:button{ id = "moveUp", text = "Up", onclick = function(ev) applyOffset(0, 1) end } dialog:button{ id = "moveLeft", text = "Left", onclick = function(ev) applyOffset(1, 0) end } dialog:button{ id = "moveRight", text = "Right", onclick = function(ev) applyOffset(-1, 0) end } dialog:show{wait = false}