123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794 |
- -- Copyright (c) 2011-2012 Casey Baxter
- -- See LICENSE file for details
- ---------------------------------------------------------------------------------------------------
- -- -= Loader =-
- ---------------------------------------------------------------------------------------------------
- -- Define path so lua knows where to look for files.
- local PATH = (...):gsub("[\\/]", ""):match(".+%.") or ''
- -- A cache to store tileset images so we don't load them multiple times. Filepaths are keys.
- local cache = {} --setmetatable({}, {__mode = "v"})
- -- XML parser
- local xml = require(PATH .. "xml")
- -- Get the map classes
- local Map = require(PATH .. "Map")
- local TileSet = require(PATH .. "TileSet")
- local TileLayer = require(PATH .. "TileLayer")
- local Tile = require(PATH .. "Tile")
- local Object = require(PATH .. "Object")
- local ObjectLayer = require(PATH .. "ObjectLayer")
- local Loader = {
- path = "", -- The path to tmx files.
- filterMin = "nearest", -- The default min filter for image:setFilter()
- filterMag = "nearest", -- The default mag filter for image:setFilter()
- useSpriteBatch = true, -- The default setting for map.useSpriteBatch
- drawObjects = true, -- The default setting for map.drawObjects.
- saveDirectory = "Saved Maps", -- The directory to use for Loader.save()
- }
- local filename -- The name of the tmx file
- local fullpath -- The full path to the tmx file minus the name
- local colorToBytes = love.math.colorToBytes
- local colorFromBytes = love.math.colorFromBytes
- local format = string.format
- ----------------------------------------------------------------------------------------------------
- -- Processes directory up paths
- local function directoryUp(path)
- while string.find(path, "[^/^\\]+[/\\]%.%.[/\\]") do
- path = string.gsub(path, "[^/^\\]+[/\\]%.%.[/\\]", "/", 1)
- end
- return path
- end
- local function fileexists(path)
- return love.filesystem.getInfo(path)
- end
- ----------------------------------------------------------------------------------------------------
- -- Loads a Map from a tmx file and returns it.
- function Loader.load(tofile)
-
- -- Get the raw path
- fullpath = directoryUp(Loader.path .. tofile)
-
- -- Get the file name
- filename = string.match(fullpath, "[^/^\\]+$")
-
- -- Get the path to the folder containing the file
- fullpath = string.gsub(fullpath, "[^/^\\]+$", "")
-
- -- Find out if the file is in the game or save directory
- if fileexists(fullpath .. filename) then
- elseif fileexists(fullpath .. filename .. ".tmx") then
- filename = filename .. ".tmx"
- elseif fileexists(Loader.saveDirectory.."/"..filename) then
- fullpath = Loader.saveDirectory .. "/"
- elseif fileexists(Loader.saveDirectory .. "/" .. filename .. ".tmx") then
- fullpath = Loader.saveDirectory .. "/"
- filename = filename .. ".tmx"
- else
- error("Loader.load() Could not find find the file in these locations:\n" ..
- "\nGame Directory: " .. fullpath .. filename ..
- "\nGame Directory: " .. fullpath .. filename .. ".tmx" ..
- "\nSave Directory: " .. Loader.saveDirectory.."/"..filename ..
- "\nSave Directory: " .. Loader.saveDirectory.."/"..filename .. ".tmx")
- end
-
- -- Read the file and parse it into a table
- local t = love.filesystem.read(fullpath .. filename)
- t = xml.parse(t)
-
- -- Get the map and expand it
- for _, v in pairs(t) do
- if v._name == "map" then
- return Loader._expandMap(fullpath .. filename, v)
- end
- end
-
- -- If we made this this far then there wasn't a map tag
- error("Loader.load - No map found in file " .. fullpath .. filename)
- end
- ----------------------------------------------------------------------------------------------------
- -- Saves a map to a file.
- local xmlHeader = [[<?xml version="1.0" encoding="UTF-8"?>]] .. "\n"
- function Loader.save(map, filename)
- local mapx = Loader._compactMap(map)
- if not fileexists(Loader.saveDirectory) then
- love.filesystem.createDirectory(Loader.saveDirectory)
- end
- love.filesystem.write( Loader.saveDirectory .. "/" .. filename, xmlHeader .. xml.toxml(mapx) )
- end
- ----------------------------------------------------------------------------------------------------
- -- Checks to see if a saved map exists
- function Loader.savedMapExists(filename)
- if fileexists(Loader.saveDirectory.."/"..filename) then
- return true
- elseif fileexists(Loader.saveDirectory .. "/" .. filename .. ".tmx") then
- return true
- end
- return false
- end
- ----------------------------------------------------------------------------------------------------
- -- Private
- ----------------------------------------------------------------------------------------------------
- -- Returns a new image from the filename.
- function Loader._newImage(source)
- return love.graphics.newImage(source), source:getWidth(), source:getHeight()
- end
- ----------------------------------------------------------------------------------------------------
- -- Checks to see if the table is a valid XML table
- function Loader._checkXML(t)
- assert(type(t) == "table", "Loader._checkXML - Passed value is not a table")
- assert(t ~= Loader, "Loader._checkXML - Passed table is the Loader class. " ..
- "You probably used a : instead of a .")
- assert(t._name, "Loader._checkXML - Table does not contain _name value")
- assert(t._attr, "Loader._checkXML - Table does not contain _attr table")
- end
- ----------------------------------------------------------------------------------------------------
- -- This is used to eliminate naming conflicts. It checks to see if the string is inside the table and
- -- continues to rename it until there isn't a conflict.
- function Loader._checkName(t, str)
- while t[str] do
- if string.find(str, "%(%d+%)$") == nil then str = str .. "(1)" end
- str = string.gsub(str, "%(%d+%)$", function(a) return "(" ..
- tonumber( string.sub(a, string.find(a, "%d+")) ) + 1 .. ")" end)
- end
- return str
- end
- ----------------------------------------------------------------------------------------------------
- -- Processes a properties table and returns it
- function Loader._expandProperties(t)
- -- Do some checking
- Loader._checkXML(t)
- if t._name ~= "properties" then
- error("Loader._expandProperties - Passed value is not a properties table")
- end
-
- -- Create a properties table and populate it. Will attempt to convert the property to
- -- the appropriate type.
- local prop = {}
- for _,v in pairs(t) do
- Loader._checkXML(t)
- if v._name == "property" then
- if v._attr.value == "true" then
- prop[v._attr.name] = true
- elseif v._attr.value == "false" then
- prop[v._attr.name] = false
- else
- prop[v._attr.name] = tonumber(v._attr.value) or v._attr.value
- end
- end
- end
-
- -- Return the properties
- return prop
- end
- ----------------------------------------------------------------------------------------------------
- -- Process Map data from xml table
- function Loader._expandMap(name, t)
-
- -- Do some checking
- Loader._checkXML(t)
- assert(t._name == "map", "Loader._expandMap - Passed table is not a map")
- assert(t._attr.width, t._attr.height, t._attr.tilewidth, t._attr.tileheight,
- "Loader._expandMap - Map data is corrupt")
- -- We'll use these for temporary storage
- local map, tileset, tilelayer, objectlayer, props
- local props = {}
-
- -- Get the properties
- for _, v in ipairs(t) do
- if v._name == "properties" then
- props = Loader._expandProperties(v)
- end
- end
-
- -- Create the map from the settings
- local map = Map:new(name, tonumber(t._attr.width),tonumber(t._attr.height),
- tonumber(t._attr.tilewidth), tonumber(t._attr.tileheight),
- t._attr.orientation, props.atl_directory or fullpath, props)
- -- Apply the loader settings if atl_useSpriteBatch or atl_drawObjects was not set
- map.useSpriteBatch = map.useSpriteBatch == nil and Loader.useSpriteBatch or map.useSpriteBatch
- map.drawObjects = map.drawObjects == nil and Loader.drawObjects or map.drawObjects
-
- -- Now we fill it with the content
- for _, v in ipairs(t) do
-
- -- Process TileSet
- if v._name == "tileset" then
- tileset = Loader._expandTileSet(v, map)
- map.tilesets[tileset.name] = tileset
- map:updateTiles()
- end
-
- -- Process TileLayer
- if v._name == "layer" then
- tilelayer = Loader._expandTileLayer(v, map)
- map.layers[tilelayer.name] = tilelayer
- map.layerOrder[#map.layerOrder + 1] = tilelayer
- end
-
- -- Process ObjectLayer
- if v._name == "objectgroup" then
- objectlayer = Loader._expandObjectLayer(v, map)
- map.layers[objectlayer.name] = objectlayer
- map.layerOrder[#map.layerOrder + 1] = objectlayer
- end
-
- -- Process CustomLayer
- if v._name == "customlayer" then
- map:newCustomLayer(v._attr.name)
- for _, v2 in ipairs(v) do
- if v2._name == "data" then
- map(v._attr.name).data = v2[1]
- end
- end
- end
-
- end
-
- -- Return our map
- return map
- end
- ----------------------------------------------------------------------------------------------------
- -- Process TileSet from xml table
- function Loader._expandTileSet(t, map)
- -- Do some checking
- Loader._checkXML(t)
- assert(t._name == "tileset", "Loader._expandTileSet - Passed table is not a tileset")
- -- Directory of the tileset
- local tilesetDir = map._directory
- -- If the tileset is an external one then replace it as the tileset. The firstgid is
- -- stored in the tileset tag in the original file while the rest of the tileset information
- -- is stored in the external file.
- if t._attr.source then
- local gid = t._attr.firstgid
- local path = directoryUp(tilesetDir .. t._attr.source)
- t = love.filesystem.read(path)
- tilesetDir = string.gsub(path, "[^/^\\]+$", "")
- for _,v in pairs(xml.parse(t)) do if v._name == "tileset" then t = v end end
- t._attr.firstgid = gid
- end
- -- Make sure everything loaded correctly
- if not t._attr.name or not t._attr.tilewidth or not t._attr.tileheight or not t._attr.firstgid then
- error("Loader._expandTileSet - Tileset data is corrupt")
- end
- -- Temporary storage
- local image, imagePath, imageWidth, imageHeight, path, prop, tileSetProperties, trans
- local tileProperties = {}
- local tileTypes = {}
- local offsetX, offsetY = 0, 0
- local cached
-
- -- Process elements
- for _, v in ipairs(t) do
- -- Process image
- if v._name == "image" then
- imagePath = v._attr.source
- path = directoryUp(tilesetDir .. v._attr.source)
- cached = cache[path]
- -- If the image is in the cache then load it
- if cached then
- image = cached.image
- imageWidth = cached.width
- imageHeight = cached.height
- trans = cached.trans
- -- Else load it and store in the cache
- else
- image = love.image.newImageData(path)
- -- transparent color
- trans = v._attr.trans
- if trans then
- local R, G, B = trans:match("^#?(%x%x)(%x%x)(%x%x)$")
- R, G, B = tonumber(R, 16), tonumber(G, 16), tonumber(B, 16)
- local rb, gb, bb
- image:mapPixel( function(x, y, r, g, b, a)
- rb, gb, bb = colorToBytes(r, g, b)
- if R == rb and G == gb and B == bb then return r, g, b, 0 end
- return r,g,b,a
- end)
- trans = {colorFromBytes(R, G, B)}
- end
- -- Set the image information
- image, imageWidth, imageHeight = love.graphics.newImage(image), image:getDimensions()
- image:setFilter(Loader.filterMin, Loader.filterMag)
- -- Cache the created image
- cache[path] = {image = image, width = imageWidth, height = imageHeight, trans = trans}
- end
- end
-
- -- Process tile properties
- if v._name == "tile" then
- if not v._attr.id then error(v._attr.id) end
- local tilegid = t._attr.firstgid + v._attr.id
- if v._attr.type then tileTypes[tilegid] = v._attr.type end
- for _, v2 in ipairs(v) do
- if v2._name == "properties" then
- -- Store the property.
- tileProperties[tilegid] = Loader._expandProperties(v2)
- end
- end
- end
-
- -- Process tile set properties
- if v._name == "properties" then
- tileSetProperties = Loader._expandProperties(v)
- end
-
- -- Get the tile offset if there is one.
- if v._name == "tileoffset" then
- offsetX, offsetY = tonumber(v._attr.x or 0), tonumber(v._attr.y or 0)
- end
- end
- -- Make sure that an image was loaded
- assert(image, "Loader._expandTileSet - Tileset did not contain an image")
- -- Return the TileSet
- local tileset = TileSet:new(image, imagePath, Loader._checkName(map.tilesets, t._attr.name),
- tonumber(t._attr.tilewidth), tonumber(t._attr.tileheight),
- tonumber(imageWidth), tonumber(imageHeight),
- tonumber(t._attr.firstgid), tonumber(t._attr.spacing), tonumber(t._attr.margin),
- offsetX, offsetY, trans, tileProperties, tileTypes, tileSetProperties)
- return tileset
- end
- ----------------------------------------------------------------------------------------------------
- -- Process TileLayer from xml table
- function Loader._expandTileLayer(t, map)
- -- Do some checking
- Loader._checkXML(t)
- assert(t._name == "layer", "Loader._expandTileLayer - Passed table is not a tileset")
-
- -- Process elements
- local data, properties
- for _, v in ipairs(t) do
- Loader._checkXML(t)
-
- -- Process data
- if v._name == "data" then
- data = Loader._expandTileLayerData(v)
- end
-
- -- Process TileLayer properties
- if v._name == "properties" then
- properties = Loader._expandProperties(v)
- end
- end
-
- -- Create the new layer
- local layer = TileLayer:new(map, t._attr.name, t._attr.opacity, properties)
-
- -- Set the visibility
- layer.visible = not (t._attr.visible == "0")
-
- -- Populate the tiles and return the layer
- layer:_populate(data)
- return layer
- end
- ----------------------------------------------------------------------------------------------------
- -- Process TileLayer data from xml table
- function Loader._expandTileLayerData(t)
- -- Do some checking
- Loader._checkXML(t)
- assert(t._name == "data", "Loader._expandTileLayerData - Passed table is not TileLayer data")
- local data = {}
- local encoding = t._attr.encoding
- -- If encoded by comma seperated value (csv) then cut each value out and put it into a table.
- if encoding == "csv" then
- string.gsub(t[1], "[%-%d]+", function(a) data[#data+1] = tonumber(a) or 0 end)
- end
- -- Base64 encoding. See base64.lua for more details.
- if encoding == "base64" then
- local compfmt = t._attr.compression
- local decoded = love.data.decode("string", "base64", t[1])
- -- If a compression method is used
- if compfmt == "gzip" or compfmt == "zlib" then
- decoded = love.data.decompress("string", compfmt, decoded)
- end
-
- local pos = 1
- for i = 1, math.floor(#decoded / 4) do
- data[i], pos = love.data.unpack("<I4", decoded, pos)
- end
- end
- -- If there is no encoding then the file is probably saved as XML
- if encoding == nil then
- local i = 1
- for k, v in ipairs(t) do
- if v._name == "tile" then
- data[i] = tonumber(v._attr.gid) or 0
- i = i + 1
- end
- end
- end
- -- Return the data
- return data
- end
- ----------------------------------------------------------------------------------------------------
- -- Process ObjectLayer from xml table
- function Loader._expandObjectLayer(t, map)
- -- Do some checking
- Loader._checkXML(t)
- if t._name ~= "objectgroup" then
- error("Loader._expandObjectLayer - Passed table is not ObjectLayer data")
- end
-
- -- Tiled stores colors in hexidecimal format that looks like "#FFFFFF"
- -- We need go convert them into base 10 RGB format
- local colorstr = t._attr.color
- local color, R, G, B, A
- if colorstr then
- if #colorstr == 7 then -- #RRGGBB
- A, R, G, B = "FF", colorstr:match("^#(%x%x)(%x%x)(%x%x)$")
- elseif #colorstr == 9 then -- #AARRGGBB
- A, R, G, B = colorstr:match("^#(%x%x)(%x%x)(%x%x)(%x%x)$")
- end
-
- if R then
- R, G, B, A = tonumber(R, 16), tonumber(G, 16), tonumber(B, 16), tonumber(A, 16)
- color = {colorFromBytes(R, G, B, A)}
- else
- print("unsupported objectgroup color format: " .. colorstr)
- end
- end
-
- -- Create a new layer
- local layer = ObjectLayer:new(map, Loader._checkName(map.layers, t._attr.name), color,
- t._attr.opacity)
-
- -- Process elements
- local objects = {}
- local prop, obj, poly
- for _, v in ipairs(t) do
-
- -- Process objects
- local obj
- if v._name == "object" then
- obj = Object:new(layer, v._attr.name, v._attr.type, tonumber(v._attr.x),
- tonumber(v._attr.y), tonumber(v._attr.width),
- tonumber(v._attr.height), tonumber(v._attr.gid) )
- objects[#objects+1] = obj
- for _, v2 in ipairs(v) do
-
- -- Process object properties
- if v2._name == "properties" then
- obj.properties = Loader._expandProperties(v2)
- end
-
- -- Process polyline objects
- local polylineFunct = function(a)
- obj.polyline[#obj.polyline+1] = tonumber(a) or 0
- end
- if v2._name == "polyline" then
- obj.polyline = {}
- string.gsub(v2._attr.points, "[%-%d]+", polylineFunct)
- end
-
- -- Process polyline objects
- local polygonFunct = function(a)
- obj.polygon[#obj.polygon+1] = tonumber(a) or 0
- end
- if v2._name == "polygon" then
- obj.polygon = {}
- string.gsub(v2._attr.points, "[%-%d]+", polygonFunct)
- end
-
- end
- obj:updateDrawInfo()
- end
-
- -- Process properties
- if v._name == "properties" then
- prop = Loader._expandProperties(v)
- end
-
- end
-
- -- Set the properties and object tables
- layer.properties = prop or {}
- layer.objects = objects
-
- -- Set the visibility
- layer.visible = not (t._attr.visible == "0")
-
- -- Return the layer
- return layer
- end
- ----------------------------------------------------------------------------------------------------
- -- Compact a Map
- function Loader._compactMap(map)
- --map.properties = map.properties or {}
- -- Set the ATL properties
- map.properties.atl_directory = map._directory
- map.properties.atl_useSpritebatch = map.useSpriteBatch
- map.properties.atl_viewX = map.viewX
- map.properties.atl_viewY = map.viewY
- map.properties.atl_viewW = map.viewW
- map.properties.atl_viewH = map.viewH
- map.properties.atl_viewScaling = map.viewScaling
- map.properties.atl_viewPadding = map.viewPadding
- map.properties.atl_drawObjects = map.drawObjects
- -- <map>
- local mapx = {_name = "map", _attr = {
- version = "1.0",
- orientation = map.orientation,
- width = map.width,
- height = map.height,
- tilewidth = map.tileWidth,
- tileheight = map.tileHeight,
- }}
-
- -- <tileset>
- for k,tileset in pairs(map.tilesets) do
- mapx[#mapx+1] = Loader._compactTileSet(tileset)
- end
-
- local layer, layerx
- for i = 1,#map.layerOrder do
- layer = map.layerOrder[i]
-
- -- <layer>
- if layer.class == "TileLayer" then
- mapx[#mapx+1] = Loader._compactTileLayer(layer)
-
- -- <objectgroup>
- elseif layer.class == "ObjectLayer" then
- mapx[#mapx+1] = Loader._compactObjectLayer(layer)
-
- -- <custom>
- elseif layer.encode then
- local layerx = {_name = "customlayer", _attr = {name = layer.name}}
- layerx[1] = {_name = "data", _attr = {}}
- layerx[1][1] = layer:encode()
- mapx[#mapx+1] = layerx
- end
-
- end
-
- -- <properties>
- mapx[#mapx+1] = Loader._compactProperties(map.properties)
- return mapx
- end
- ----------------------------------------------------------------------------------------------------
- -- Compact a TileSet
- function Loader._compactTileSet(tileset)
- -- <Tileset>
- local tilesetx = {_name = "tileset", _attr = {
- firstgid = tileset.firstgid,
- name = tileset.name,
- tilewidth = tileset.tileWidth,
- tileheight = tileset.tileHeight,
- spacing = tileset.spacing,
- margin = tileset.margin
- }}
-
- -- <image>
- local trans = tileset.trans
- if trans then
- trans = format("%02x%02x%02x", colorToBytes(trans[1], trans[2], trans[3]))
- end
-
- tilesetx[1] = {_name = "image", _attr = {
- source = tileset.imagePath,
- trans = trans,
- }}
-
- -- <tileoffset>
- if tileset.offsetX ~= 0 or tileset.offsetY ~= 0 then
- tilesetx[2] = {_name = "tileoffset", _attr = {x = tileset.offsetX, y = tileset.offsetY}}
- end
-
- -- <properties>
- if next(tileset.properties) then
- tilesetx[#tilesetx+1] = Loader._compactProperties(tileset.properties)
- end
-
- -- <tile>
- local hasProp = {}
- if next(tileset.tileProperties) then
- local tilex, tid
- for k, props in pairs(tileset.tileProperties) do
- tid = k - tileset.firstgid
- tilex = {_name = "tile", _attr = {id = tid}}
- tilex[1] = Loader._compactProperties(props)
- tilesetx[#tilesetx+1] = tilex
- hasProp[tid] = tilex
- end
- end
- if next(tileset.tileTypes) then
- local tilex, tid
- for k, ttype in pairs(tileset.tileTypes) do
- tid = k - tileset.firstgid
- tilex = hasProp[tid]
- if tilex then
- tilex._attr.type = ttype
- else
- tilex = {_name = "tile", _attr = {id = tid, type = ttype}}
- tilesetx[#tilesetx+1] = tilex
- end
- end
- end
-
- return tilesetx
- end
- ----------------------------------------------------------------------------------------------------
- -- Compact a TileLayer
- function Loader._compactTileLayer(layer)
- -- Set the ATL properties
- layer.properties.atl_useSpriteBatch = layer.useSpriteBatch
- layer.properties.atl_parallaxX = layer.parallaxX
- layer.properties.atl_parallaxY = layer.parallaxY
- layer.properties.atl_offsetX = layer.offsetX
- layer.properties.atl_offsetY = layer.offsetY
- -- <layer>
- local layerx = {_name = "layer", _attr = {
- name = layer.name,
- opacity = layer.opacity,
- visible = layer.visible and 1 or 0,
- width = layer.map.width,
- height = layer.map.height,
- }}
-
- -- <data>
- local tiles = {}
- local flipBits = 2^29
- local flipValue
- for x, y, tile in layer:rectangle(0, 0, layer.map.width-1, layer.map.height-1, true) do
- if tile then
- flipValue = layer._flippedTiles(x,y) and layer._flippedTiles(x,y) * flipBits or 0
- tiles[#tiles+1] = tile.id + flipValue
- else
- tiles[#tiles+1] = 0
- end
- end
- layerx[1] = {_name ="data", _attr = {encoding="csv"}, [1] = table.concat(tiles,",")}
- -- <properties>
- if next(layer.properties) then
- layerx[2] = Loader._compactProperties(layer.properties)
- end
- return layerx
- end
- ----------------------------------------------------------------------------------------------------
- -- Compact an ObjectLayer
- function Loader._compactObjectLayer(layer)
- local color = layer.color
- if color then
- color = format("#%02x%02x%02x%02x", colorToBytes(color[4] or 1, color[1], color[2], color[3]))
- end
- -- <objectgroup>
- local layerx = {_name = "objectgroup", _attr = {
- name = layer.name,
- color = color,
- opacity = layer.opacity,
- visible = layer.visible and 1 or 0,
- }}
-
- -- <object>
- --local object
- for i = 1,#layer.objects do
- --object = layer.objects[i]
- layerx[#layerx+1] = Loader._compactObject(layer.objects[i])
- end
- -- <properties>
- if next(layer.properties) then
- layerx[#layerx+1] = Loader._compactProperties(layer.properties)
- end
- return layerx
- end
- ----------------------------------------------------------------------------------------------------
- -- Compact an Object
- function Loader._compactObject(object)
- -- <object>
- local objectx = {_name = "object", _attr = {
- name = object.name,
- type = object.type,
- x = object.x,
- y = object.y,
- width = object.width,
- height = object.height,
- gid = object.gid,
- visible = object.visible,
- }}
-
- -- <polyline>
- if object.polyline then
- local polylinex = {_name = "polyline", _attr = {}}
- local points = {}
- for i = 1,#object.polyline,2 do
- points[#points+1] = object.polyline[i] .. "," .. object.polyline[i+1]
- end
- polylinex._attr.points = table.concat(points, " ")
- objectx[#objectx+1] = polylinex
- end
-
- -- <polygon>
- if object.polygon then
- local polygonx = {_name = "polygon", _attr = {}}
- local points = {}
- for i = 1,#object.polygon,2 do
- points[#points+1] = object.polygon[i] .. "," .. object.polygon[i+1]
- end
- polygonx._attr.points = table.concat(points, " ")
- objectx[#objectx+1] = polygonx
- end
- -- <properties>
- if next(object.properties) then
- objectx[#objectx+1] = Loader._compactProperties(object.properties)
- end
-
- return objectx
- end
- ----------------------------------------------------------------------------------------------------
- -- Compact Properties
- function Loader._compactProperties(prop)
-
- if not prop then return end
-
- -- <properties>
- local propx = {_name = "properties", _attr = {}}
-
- -- <property>
- for k,v in pairs(prop) do
- propx[#propx+1] = {_name = "property", _attr = {name = k, value = v}}
- end
- return propx
- end
- ----------------------------------------------------------------------------------------------------
- -- Return the loader
- return Loader
|