Skip to content

Instantly share code, notes, and snippets.

@emilio-rst
Forked from markusfisch/README.md
Created July 28, 2014 22:05
Show Gist options
  • Select an option

  • Save emilio-rst/baae894fa62cb08bb306 to your computer and use it in GitHub Desktop.

Select an option

Save emilio-rst/baae894fa62cb08bb306 to your computer and use it in GitHub Desktop.

mkatlas

BASH script to build a texture atlas for small/medium web sites/games. Requires ImageMagick.

Usage

Basic

Just run

$ ./mkatlas img/*

which will create atlas.png and outputs the corresponding sprite regions in JSON format:

var atlas={
first:{x:298,y:0,w:35,h:22},
second:{x:254,y:0,w:44,h:33},
...
}

Advanced

Alternatively you may use just markers in your JavaScript to insert the frame data in place. This way you wouldn't have to have a extra atlas object and wouldn't need to do any additional mapping. For example:

var obj = {
	name: "Jim",
	frame: {/*first*/x:0,y:0,w:0,h:0},
	live: 100 };

This file may be patched with patchatlas like this:

$ ./mkatlas img/* | ./patchatlas index.html
#!/bin/bash
# Horizontal cut
atlas_cut_horizontal()
{
echo $(( X+$1 )) $Y $W $2 > $NODE/child0/rect
echo $X $(( Y+$2 )) $NW $H > $NODE/child1/rect
}
# Vertical cut
atlas_cut_vertical()
{
echo $X $(( Y+$2 )) $1 $H > $NODE/child0/rect
echo $(( X+$1 )) $Y $W $NH > $NODE/child1/rect
}
# Insert image, packing algorithm from
# http://www.blackpawn.com/texts/lightmaps/default.html
#
# @param 1 - image width
# @param 2 - image height
# @param 3 - image file
atlas_insert()
{
if [ -d "$NODE/child0" ]
then
local N=$NODE
NODE=$N/child0
atlas_insert $1 $2 $3 && return 0
NODE=$N/child1
atlas_insert $1 $2 $3 && return 0
return 1
fi
[ -f $NODE/rect ] || return 1
local X Y NW NH
read X Y NW NH < $NODE/rect
if (( $1 > NW )) || (( $2 > NH ))
then
return 1
fi
local W=$(( NW-$1 ))
local H=$(( NH-$2 ))
mkdir $NODE/child0 $NODE/child1
if (( H > W ))
then
if (( PREFER_SMALLER ))
then
atlas_cut_vertical $1 $2
else
atlas_cut_horizontal $1 $2
fi
else
if (( PREFER_SMALLER ))
then
atlas_cut_horizontal $1 $2
else
atlas_cut_vertical $1 $2
fi
fi
echo $X $Y $1 $2 $3 > $NODE/image
return 0
}
# Create texture atlas from a listing in the format "width height filename"
atlas_from_list()
{
local CACHE
CACHE=`mktemp -d ${0##*/}.XXXXXXXXXX` || return 1
local WIDTH=${WIDTH:-2048}
local HEIGHT=${HEIGHT:-2048}
echo 0 0 $WIDTH $HEIGHT > $CACHE/rect
# sort files and insert them into the atlas
local MAX W H FILE
while read W H FILE
do
[ "$FILE" ] || continue
if (( W > H ))
then
MAX=$W
else
MAX=$H
fi
printf '%08d %d %d %s\n' $MAX $W $H $FILE
done | sort -r | while read MAX W H FILE
do
local NODE=$CACHE
atlas_insert $W $H $FILE || {
echo 'error: canvas too small' >&2
break
}
done
# print JSON and build arguments for convert
echo "var atlas={"
find $CACHE -type f -name image | while read
do
local X Y W H FILE
read X Y W H FILE < $REPLY
echo "$FILE -geometry +$X+$Y -composite" >> $CACHE/args
local NAME=${FILE##*/}
echo "${NAME%.*}:{x:$X,y:$Y,w:$W,h:$H},"
done
echo "};"
# compose images into atlas
convert -size "${WIDTH}x${HEIGHT}" xc:transparent \
`< $CACHE/args` \
-strip -trim "${ATLAS:-atlas.png}"
rm -rf $CACHE
}
# Create texture atlas
#
# @param ... - image files
atlas_from_files()
{
local TRIMMED
TRIMMED=`mktemp -d ${0##*/}.XXXXXXXXXX` || return 1
# trim input files first
local F
for F in "$@"
do
convert "$F" -strip -trim "$TRIMMED/${F##*/}"
done
identify -format '%w %h %d/%f\n' "$TRIMMED/*" | atlas_from_list
rm -rf $TRIMMED
}
[ "$0" == "$BASH_SOURCE" ] && atlas_from_files "$@"
#!/bin/bash
# Patch given JavaScript files with JSON read from stdin
#
# @param ... - JavaScript files to patch
atlas_patch()
{
(( $# < 1 )) && {
echo "usage: ${0##*/} FILE..."
return 1
}
while read
do
case $REPLY in
*:{*)
;;
*)
continue
;;
esac
local NAME=${REPLY%%:\{*}
[ "$NAME" ] || continue
local FRAME=${REPLY#*\{}
local PATCH="s^{/\*${NAME}\*/[\"xywh:0-9,]*}^{/*${NAME}*/${FRAME%,}^g"
local TMP=".${0##*/}-$$.tmp"
local SRC
for SRC in "$@"
do
sed -e "$PATCH" < $SRC > $TMP && mv $TMP $SRC
done
done
}
[ "$0" == "$BASH_SOURCE" ] && atlas_patch "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment