1local image = require 'image' 2local path = require 'path' 3 4local function newwriter() 5 return { 6 bytes = {}, 7 write8 = function( self, x ) 8 self.bytes[ #self.bytes + 1 ] = string.char( x & 255 ) 9 end, 10 write16 = function( self, x ) 11 self.bytes[ #self.bytes + 1 ] = string.char( ( x >> 8 ) & 255, x & 255 ) 12 end, 13 write32 = function( self, x ) 14 self.bytes[ #self.bytes + 1 ] = string.char( ( x >> 24 ) & 255, ( x >> 16 ) & 255, ( x >> 8 ) & 255, x & 255 ) 15 end, 16 append = function( self, rle ) 17 self.bytes[ #self.bytes + 1 ] = table.concat( rle.bytes ) 18 end, 19 size = function( self ) 20 self.bytes = { table.concat( self.bytes ) } 21 return #self.bytes[ 1 ] 22 end, 23 save = function( self, name ) 24 local file, err = io.open( name, 'wb' ) 25 if not file then error( err ) end 26 self.bytes = { table.concat( self.bytes ) } 27 file:write( self.bytes[ 1 ] ) 28 file:close() 29 end 30 } 31end 32 33local function rgbto16( r, g, b ) 34 r = r * 31 // 255 35 g = g * 63 // 255 36 b = b * 31 // 255 37 38 return ( r << 11 ) | ( g << 5 ) | b 39end 40 41local function getpixel( png, x, y ) 42 local r, g, b = image.split( png:getPixel( x, y ) ) 43 return rgbto16( r, g, b ) 44end 45 46local function mktileset( images ) 47 local writer = newwriter() 48 49 writer:write16( images[ 1 ]:getWidth() ) 50 writer:write16( images[ 1 ]:getHeight() ) 51 writer:write16( #images ) 52 53 for _, img in pairs( images ) do 54 for y = 0, img:getHeight() - 1 do 55 for x = 0, img:getWidth() - 1 do 56 writer:write16( getpixel( img, x, y ) ) 57 end 58 end 59 end 60 61 return writer 62end 63 64local function main( args ) 65 if #args == 0 then 66 io.write[[ 67rltileset.lua reads all images in the given directory and writes tileset data 68that can be directly fed to rl_tileset_create. The first image it finds in the 69given directory will dictate the width and height of all tiles in the tileset. 70Subsequent images with different dimensions won't be written to the tileset. 71 72 73Usage: luai rltileset.lua [ options ] <directory> 74 75--output <file> writes the tileset to the given file 76 (the default is <directory>.tls) 77 78]] 79 80 return 0 81 end 82 83 local dir, output 84 85 for i = 1, #args do 86 if args[ i ] == '--output' then 87 output = args[ i + 1 ] 88 i = i + 1 89 else 90 dir = args[ i ] 91 end 92 end 93 94 dir = path.realpath( dir ) 95 local files = path.scandir( dir ) 96 local width, height 97 local images = {} 98 99 for _, file in ipairs( files ) do 100 local stat = path.stat( file ) 101 102 if stat.file then 103 local ok, png = pcall( image.load, file ) 104 105 if ok then 106 if not width then 107 width, height = png:getSize() 108 images[ #images + 1 ] = png 109 io.write( string.format( '%s set the tileset dimensions to %dx%d\n', file, width, height ) ) 110 elseif width == png:getWidth() and height == png:getHeight() then 111 images[ #images + 1 ] = png 112 else 113 io.write( string.format( '%s doesn\'t have the required dimensions\n', file ) ) 114 end 115 else 116 io.write( string.format( '%s could not be read as an image\n', file ) ) 117 end 118 end 119 end 120 121 if #images ~= 0 then 122 local writer = mktileset( images ) 123 124 if not output then 125 local dir, name, ext = path.split( dir ) 126 output = dir .. path.separator .. name .. '.tls' 127 end 128 129 writer:save( output ) 130 else 131 io.write( 'no images were found\n' ) 132 end 133 134 return 0 135end 136 137return main, mktileset 138