Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
sprite sheet generator
#1
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:

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


Attached Files
.txt   atlasgen.txt (Size: 5.81 KB / Downloads: 3)
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)