diff --git a/spritesheet.lua b/spritesheet.lua index 53b4ef4..eea094b 100644 --- a/spritesheet.lua +++ b/spritesheet.lua @@ -1,5 +1,14 @@ -local error = require 'errors' 'SpriteSheet2' +local error_orig = error +local error, error_internal do + error, error_internal = error_orig, error_orig + error_orig = nil + local success, errorlib = pcall(require,'errors') + if success then + error = errorlib 'spritesheet' + error_internal = error.internal + end +end -------------------------------------------------------------------------------- -- Util @@ -102,7 +111,7 @@ function Animation:generateImage () if self.wrap then t = t % self.duration end local quad = get_quad_based_on_time(self, t) - if not quad then error.internal('Could not determine quad when drawing animation. Time was %f.', t) end + if not quad then error_internal('Could not determine quad when drawing animation. Time was %f.', t) end love.graphics.draw(self.imagesheet.image, quad, x, y, 0, 1, 1, self.imagesheet.origin_x, self.imagesheet.origin_y) end end @@ -165,8 +174,8 @@ local function load_quads (image, quad_data, imagesheet) local image_width, image_height = image:getDimensions() local tile_width, tile_height = quad_data.tile_width, quad_data.tile_height - local tiles_pr_row = image_width/tile_width - local max_quad_id = tiles_pr_row * (image_height/tile_height) - 1 + local tiles_per_row = image_width/tile_width + local max_quad_id = tiles_per_row * (image_height/tile_height) - 1 local quad_cache = {} local function quad_from_id (id) @@ -177,7 +186,7 @@ local function load_quads (image, quad_data, imagesheet) -- Calculate if not quad_cache[id] then - quad_cache[id] = love.graphics.newQuad((id%tiles_pr_row)*tile_width, math.floor(id/tiles_pr_row)*tile_height, tile_width, tile_height, image_width, image_height) + quad_cache[id] = love.graphics.newQuad((id%tiles_per_row)*tile_width, math.floor(id/tiles_per_row)*tile_height, tile_width, tile_height, image_width, image_height) end return quad_cache[id] end @@ -226,15 +235,40 @@ local function load_quad_data (filename) local chunk, error_msg = love.filesystem.load(filename..'.lua') if chunk then local data = setfenv(chunk, SPRITESHEET_ENV)() + -- Error check - if type(data) ~= 'table' then error('Bad spritesheet "%s". Must return a table, but returned %s (%s)', filename, data, type(data)) end - if type(data.tile_width) ~= 'number' then error('Bad spritesheet "%s". The root table must contain key "tile_width", with integer value, but it was %s (%s)', filename, data.tile_width, type(data.tile_width)) end - if data.tile_width ~= math.floor(data.tile_width) then error('Bad spritesheet "%s". The root table must contain key "tile_width", with integer value, but it was %f (float)', filename, data.tile_width) end - if type(data.tile_height) ~= 'number' then error('Bad spritesheet "%s". The root table must contain key "tile_height", with integer value, but it was %s (%s)', filename, data.tile_height, type(data.tile_height)) end - if data.tile_height ~= math.floor(data.tile_height) then error('Bad spritesheet "%s". The root table must contain key "tile_height", with integer value, but it was %f (float)', filename, data.tile_height) end - if not (type(data.tile_names) == 'table' or type(data.tile_names) == 'number') then error('Bad spritesheet "%s". The root table must contain key "tile_names", with either a table or a number value, but it was %s (%s)', filename, data.tile_names, type(data.tile_names)) end - if data.tile_origin and type(data.tile_origin) ~= 'table' then error('Bad spritesheet "%s". If the root table contains key "tile_origin", it must be a table value, but it was %s (%s)', filename, data.tile_origin, type(data.tile_origin)) end - -- + if type(data) ~= 'table' then + error('Bad spritesheet "%s". Must return a table, but returned %s (%s)', filename, data, type(data)) + end + local l = {'Bad spritesheet "'.. filename.. '"'} + if data.tiles_per_row ~= nil and data.tile_width ~= nil then + l[#l+1] = 'Root table must not contain both keys "tiles_per_row" and "tile_width"' + elseif data.tiles_per_row == nil and data.tile_width == nil then + l[#l+1] = 'Root table must contain either keys "tiles_per_row" or "tile_width"' + end + if data.tiles_per_column ~= nil and data.tile_height ~= nil then + l[#l+1] = 'Root table must not contain both keys "tiles_per_column" and "tile_height"' + elseif data.tiles_per_column == nil and data.tile_height == nil then + l[#l+1] = 'Root table must contain either keys "tiles_per_column" or "tile_height"' + end + local INTEGER_TILESET_KEYS = {'tile_width', 'tile_height', 'tiles_per_row', 'tiles_per_column'} + for _, integer_key in ipairs(INTEGER_TILESET_KEYS) do + local v = data[integer_key] + if v and (type(v) ~= 'number' or v % 1 ~= 0) then + l[#l+1] = string.format('Key "%s" in root table must map to integer value, but it was %s (%s)', integer_key, v, type(v)) + end + end + if not (type(data.tile_names) == 'table' or type(data.tile_names) == 'number') then + l[#l+1] = string.format('Root table must contain key "tile_names", with either a table or a number value, but it was %s (%s)', data.tile_names, type(data.tile_names)) + end + if data.tile_origin and type(data.tile_origin) ~= 'table' then + l[#l+1] = string.format('Key "%s" in root table must map to a table value, but it was %s (%s)', 'tile_origin', data.tile_origin, type(data.tile_origin)) + end + + -- Throw error or return + if #l > 1 then + error(table.concat(l, '\n ')) + end return data end print(error_msg) @@ -253,18 +287,38 @@ local SpriteSheet = {} function SpriteSheet.new (filename) local quad_data = load_quad_data(filename) + -- NOTE: `force_uneven_tile_size` in quad_data can be used to + -- ignore the image size-tile size divisibility check. Edit the + -- spriteimage itself if you can, as it will silently ignore + -- several errors. + -- Set info local self = setmetatable({}, SpriteSheet) self.filename = filename self.image = love.graphics.newImage(filename..'.png') self.origin_x = 0 self.origin_y = 0 - self.tile_width = quad_data.tile_width - self.tile_height = quad_data.tile_height + + -- TODO: Give warning/error due to rounding down. + quad_data.tile_width = quad_data.tile_width or math.floor(self.image:getWidth() / quad_data.tiles_per_row) + quad_data.tile_height = quad_data.tile_height or math.floor(self.image:getHeight() / quad_data.tiles_per_column) + print(self.tile_width, self.tile_height) + + self.tile_width = quad_data.tile_width + self.tile_height = quad_data.tile_height -- Error checking - if self.image:getWidth() % self.tile_width ~= 0 then error('Bad spritesheet "%s". Image size (%i, %i) must be dividable by tile size (%i, %i), but width leaves a remainder of %i.', filename, self.image:getWidth(), self.image:getHeight(), self.tile_width, self.tile_height, self.image:getWidth() % self.tile_width) end - if self.image:getHeight() % self.tile_height ~= 0 then error('Bad spritesheet "%s". Image size (%i, %i) must be dividable by tile size (%i, %i), but height leaves a remainder of %i.', filename, self.image:getWidth(), self.image:getHeight(), self.tile_width, self.tile_height, self.image:getHeight() % self.tile_height) end + do + local rem_width = self.image:getWidth() % self.tile_width + local rem_height = self.image:getHeight() % self.tile_height + if not quad_data.force_uneven_tile_size and (rem_width ~= 0 or rem_height ~= 0) then + local s = ('Bad spritesheet "%s". Image size (%i, %i) must be dividable by tile size (%i, %i)') + :format(filename, self.image:getWidth(), self.image:getHeight(), self.tile_width, self.tile_height) + if rem_width ~= 0 then s = s..('\n Width leaves a remainder of %i.'):format(rem_width) end + if rem_height ~= 0 then s = s..('\n Height leaves a remainder of %i.'):format(rem_height) end + error(s) + end + end -- Set origin if quad_data.tile_origin then