Here's a little tool that is not of much use when you're making games with naalaa.
When you make games that use opengl/opengles you know that texture binding can be costy. Therefor you want to squeeze as many images as possible into every texture. There are already nice tools out there that do this for you, such as Texture Packer (costs Money though). But I prefer writing my own tools, so here's a naalaa program that grabs every png image in a directory and packs them in a single image. It also generates a json file (in the same format as Texture Packer and most other programs) that specifies the locations of all sub images in the resulting image.
This program should be run from the command line. The syntax is:
atlasgen <path to images> <texture width> <texture height> [<output filename>]
So if you have a bunch of png files in a folder, c:\hello\images, and you want to generate a texture and json named my_texture.png and my_texture.json, you'd write:
When you make games that use opengl/opengles you know that texture binding can be costy. Therefor you want to squeeze as many images as possible into every texture. There are already nice tools out there that do this for you, such as Texture Packer (costs Money though). But I prefer writing my own tools, so here's a naalaa program that grabs every png image in a directory and packs them in a single image. It also generates a json file (in the same format as Texture Packer and most other programs) that specifies the locations of all sub images in the resulting image.
This program should be run from the command line. The syntax is:
atlasgen <path to images> <texture width> <texture height> [<output filename>]
So if you have a bunch of png files in a folder, c:\hello\images, and you want to generate a texture and json named my_texture.png and my_texture.json, you'd write:
Code:
atlasgen c:\hello\images 1024 1024 my_texture
Code:
' ==============================================================================
' image atlas generator, by marcus.
' ==============================================================================
import "QuickSort.lib"
LENGTH = 1
AREA = 2
if sizeof(args) < 4
_Error "atlasgen <path to images> <atlas width> <atlas height> [(name)]"
endif
path$ = args[1]
WIDTH = int(args[2])
HEIGHT = int(args[3])
if sizeof(args) > 4
name$ = args[4]
else
name$ = "assets"
endif
if not (mid(path, len(path) - 1) = "/" or mid(path, len(path) - 1) = "\")
path = path + "/"
endif
files$[] = ListFiles(path)
count = 0
for i = 0 to sizeof(files) - 1
if len(files[i])
load image count, path + files[i]
if image(count) then count = count + 1
endif
next
if count = 0 then end
' area seems to work better
sort = AREA
uns?[count]
org?[count]
rects?[1000]
tmp[count][2]
for i = 0 to sizeof(org) - 1
' Add spacing.
uns[i].w = width(i) + 2
uns[i].h = height(i) + 2
uns[i].img = i
uns[i].fn$ = files[i]
tmp[i][0] = i
' sort based on area
if sort = AREA
' This one wins in all cases.
tmp[i][1] = uns[i].w*uns[i].h
tmp[i][1] = tmp[i][1]*min(uns[i].w, uns[i].h)/max(uns[i].w, uns[i].h)
' sort based on max of width and height
elseif sort = LENGTH
tmp[i][1] = max(uns[i].w, uns[i].h)
endif
next
' sort by area
_QuickSort2D tmp, 1
for i = 0 to sizeof(uns) - 1
org[sizeof(org) - 1 - i] = uns[tmp[i][0]]
next
rectCount = 1
rects[0].x = 0
rects[0].y = 0
rects[0].w = WIDTH
rects[0].h = HEIGHT
for i = 0 to sizeof(org) - 1
smallestIndex = rectCount
smallestArea = WIDTH*HEIGHT*2
for j = 0 to rectCount - 1
if rects[j].w >= org[i].w and rects[j].h >= org[i].h and rects[j].w*rects[j].h < smallestArea
smallestIndex = j
smallestArea = rects[j].w*rects[j].h
endif
next
if smallestIndex = rectCount
set color 0, 0, 0
draw rect 0, 0, 208, 24, true
set color 255, 255, 255
_Error "Images did not fit"
endif
j = smallestIndex
org[i].x = rects[j].x
org[i].y = rects[j].y
orgX = rects[j].x
orgY = rects[j].y
orgW = rects[j].w
orgH = rects[j].h
rects[rectCount].x = orgX + org[i].w
rects[rectCount].y = orgY
rects[rectCount].w = orgW - org[i].w
rects[rectCount].h = orgH
a1 = rects[rectCount].w*rects[rectCount].h
rects[rectCount].x = orgX
rects[rectCount].y = orgY + org[i].h
rects[rectCount].w = orgW
rects[rectCount].h = orgH - org[i].h
a2 = rects[rectCount].w*rects[rectCount].h
' This is not right. Checking which split yields one largest rectangle.
' It would be better to check which one yields the two 'most square' rectangles.
if a1 > a2
rects[j].x = orgX
rects[j].y = orgY + org[i].h
rects[j].w = org[i].w
rects[j].h = orgH - org[i].h
rects[rectCount].x = orgX + org[i].w
rects[rectCount].y = orgY
rects[rectCount].w = orgW - org[i].w
rects[rectCount].h = orgH
else
rects[j].x = orgX + org[i].w
rects[j].y = orgY
rects[j].w = orgW - org[i].w
rects[j].h = org[i].h
rects[rectCount].x = orgX
rects[rectCount].y = orgY + org[i].h
rects[rectCount].w = orgW
rects[rectCount].h = orgH - org[i].h
endif
rectCount = rectCount + 1
next
create image -1, WIDTH, HEIGHT
set image -1
set color 0, 0, 0, 0
for y = 0 to HEIGHT - 1
for x = 0 to WIDTH - 1
set pixel x, y
next
next
for i = 0 to sizeof(org) - 1
for y = 0 to height(org[i].img) - 1
for x = 0 to width(org[i].img) - 1
set image org[i].img
c[] = pixel(x, y)
set image -1
set color c[0], c[1], c[2], c[3]
set pixel org[i].x + 1 + x, org[i].y + 1 + y
next
next
next
save image - 1, name + ".png"
tab$ = chr(9)
create file 0, name + ".json"
wln file 0, "{", quoted("frames"), ": ["
for i = 0 to sizeof(org) - 1
wln file 0, "{"
wln file 0, tab, quoted("filename"), ": ", quoted(org[i].fn$), ","
write file 0, tab, quoted("frame"), ": {"
write file 0, quoted("x"), ": ", org[i].x + 1, ", "
write file 0, quoted("y"), ": ", org[i].y + 1, ", "
write file 0, quoted("w"), ": ", width(org[i].img), ", "
wln file 0, quoted("h"), ": ", height(org[i].img), "},"
wln file 0, tab, quoted("rotated"), ": false,"
wln file 0, tab, quoted("trimmed"), ": false,"
write file 0, tab, quoted("spriteSourceSize"), ": {"
write file 0, quoted("x"), ": 0, "
write file 0, quoted("y"), ": 0, "
write file 0, quoted("w"), ": ", width(org[i].img), ", "
wln file 0, quoted("h"), ": ", height(org[i].img), "},"
write file 0, tab, quoted("sourceSize"), ": {"
write file 0, quoted("w"), ": ", width(org[i].img), ", "
wln file 0, quoted("h"), ": ", height(org[i].img), "}"
if i < sizeof(org) - 1
wln file 0, "},"
else
wln file 0, "}"
endif
next
wln file 0, "]}"
free file 0
function quoted$(txt$)
return chr(34) + txt + chr(34)
endfunc
procedure Error(txt$)
set color 0, 0, 0
cls
set color 255, 255, 255
set caret 0, 0
wln txt
t = time()
while time() < t + 2000
redraw
wait 10
wend
end
endproc
procedure ListFiles$[](dir$)
shellexecute "open", "cmd", "", "/c cd " + chr(34) + dir + chr(34) + " & dir /b *.png > png_list.txt", true
open file 0, dir + "png_list.txt"
if file(0)
tmp$ = ""
while not eof(0)
tmp = tmp + read$(0) + chr(10)
wend
free file 0
return split(tmp, chr(10))
else
bad$[]
return bad
endif
endproc