-
Notifications
You must be signed in to change notification settings - Fork 25
/
Pack Similar Tiles.lua
133 lines (120 loc) · 4.33 KB
/
Pack Similar Tiles.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
----------------------------------------------------------------------
-- Takes similar tiles from the given current sprite and convert it into
-- two sprites:
-- 1) One sprite will be the tilemap, an indexed sprite where each
-- pixel is a reference to the tileset
-- 2) Other sprite will be the tileset, where each tile grid is a
-- portion of the original sprite
----------------------------------------------------------------------
local spr = app.activeSprite
if not spr then
app.alert("There is no sprite to export")
return
end
local d = Dialog("Pack Similar Tiles")
d:number{ id="tile_w", label="Tile Width:", text="16", focus=true }
:number{ id="tile_h", label="Tile Height:", text="16" }
:number{ id="sheet_w", label="Sprite Sheet Width:", text="256" }
:button{ id="ok", text="&OK", focus=true }
:button{ text="&Cancel" }
:show()
local data = d.data
if not data.ok then return end
local tile_w = data.tile_w
local tile_h = data.tile_h
local sheet_w = data.sheet_w
-- We will extract tiles from the active frame of the active sprite
local img = Image(spr.spec)
img:clear()
img:drawSprite(spr, app.activeFrame)
local tiles_w = img.width / tile_w
local tiles_h = img.height / tile_h
-- "images" will be an array with unique tiles, we use the addTile()
-- function to add a new tile if it doesn't matches any of the
-- existent tiles in the array.
local images = { }
local function addTile(newTileImg)
for i,v in ipairs(images) do
if v:isEqual(newTileImg) then
return i -- Return the existent tile index that matches the "newTileImg"
end
end
-- In this case this "newTileImg" is really a new unknown tile, so
-- we add it and return the index of it.
table.insert(images, newTileImg)
return #images
end
-- Returns a possible color that could represent the given "img" tile
-- in the tilemap. It calculates the average RGB values from the four
-- corners of the tile.
local function getAvgTileColor(img)
local pc = app.pixelColor
local corners = { img:getPixel(0, 0),
img:getPixel(img.width-1, 0),
img:getPixel(0, img.height-1),
img:getPixel(img.width-1, img.height-1) }
if img.colorMode == ColorMode.INDEXED then
for i = 1,4 do
local c = spr.palettes[1]:getColor(corners[i])
corners[i] = pc.rgba(c.red, c.green, c.blue)
end
elseif img.colorMode == ColorMode.GRAY then
for i = 1,4 do
local v = pc.grayaV(corners[i])
corners[i] = pc.rgba(v, v, v)
end
end
local avg = { r=0, g=0, b=0 }
for i,c in ipairs(corners) do
avg.r = avg.r + pc.rgbaR(c)
avg.g = avg.g + pc.rgbaG(c)
avg.b = avg.b + pc.rgbaB(c)
end
return Color { r=avg.r/4, g=avg.g/4, b=avg.b/4 }
end
-- "newSprTilemap" will be the tilemap where each pixel is a reference
-- to the tileset.
local newSprTilemap = Sprite(tiles_w, tiles_h, ColorMode.INDEXED)
app.command.BackgroundFromLayer()
local newSprTilemapImage = newSprTilemap.cels[1].image
for j = 0,tiles_h-1 do
for i = 0,tiles_w-1 do
local tileImg = Image(tile_w, tile_h, img.colorMode)
tileImg:putImage(img, -i*tile_w, -j*tile_h)
local index = addTile(tileImg)
newSprTilemapImage:putPixel(i, j, index)
end
end
-- Here we create a pseudo-palette for the tilemap (it's only a
-- palette useful to identify different tiles in the tilemap, but it's
-- not useful for the user)
local pal = newSprTilemap.palettes[1]
if #images >= 1 and #images < 256 then
pal:resize(#images+1)
end
for i,v in ipairs(images) do
if i >= #pal then break end
pal:setColor(i, getAvgTileColor(v))
end
-- Here we create the new sprite sheet with the tiles in "images" array
local sheet_tiles_w = math.floor(sheet_w / tile_w)
local sheet_tiles_h = math.floor(#images / sheet_tiles_w)
if #images / (sheet_tiles_w*sheet_tiles_h) > 0 then
sheet_tiles_h = sheet_tiles_h+1
end
local sheet_h = sheet_tiles_h * tile_h
local newSprTileset = Sprite(sheet_w, sheet_h, spr.colorMode)
app.command.BackgroundFromLayer()
local sheetImg = Image(newSprTileset.spec)
for i,v in ipairs(images) do
sheetImg:putImage(v,
math.floor((i-1) % sheet_tiles_w) * tile_w,
math.floor((i-1) / sheet_tiles_w) * tile_h)
end
newSprTileset:setPalette(spr.palettes[1])
newSprTileset.cels[1].image = sheetImg
if app.apiVersion >= 3 then
newSprTilemap.filename = "tilemap"
newSprTileset.filename = "tileset"
end
app.refresh()