Log In  


I wanted a tool to help me import a large folder of asset .pngs (such as one you might get from https://kenney.nl/) into .gfx files. I know there are tools such as @pancelor 's helpful importpng.p64 (or just click-n-dragging onto the gfx editor), but I didn't want to do that for hundreds of files.

Using importpng.p64 as a foundation, I create a command-line utility for Picotron that will import entire folders of assets into .gfx files! Below is the snippet that you'll put in /appdata/system/utils/simport.lua

-- a tool to import all pngs in a folder into a single .gfx file
-- tool by  @fletch_pico
-- version 1.1
-- 
-- makes use of:
-- importpng.p64 code by     @pancelor
-- https://www.lexaloffle.com/bbs/?tid=141149

cd(env().path)
local argv = env().argv

if (argv[1] == "--help") then
	print("Usage: simport [FOLDER]")
	print("Populate the .gfx file using a folder of PNGs.")
	print("")
	print("OPTIONS")
	print("  -e")
	print("  --empty-sprite-0")
	print("  keep sprite 0 empty on every .gfx file")
	print("  (default is to write data to sprite 0)")
	exit(0)
end

-- check if argv[1] is a folder
local path = fullpath(env().argv[1])
if (not path) then
	print("could not resolve path")
	exit(1)
end

-- loop through items in this folder looking for pngs
local dir_items = ls(path)
local pngs = {}
for i=1,#dir_items do
	local item = dir_items[i]
	if (#item > 4 and sub(item,-4) == ".png") then
		add(pngs,item)
	end
end

if (#pngs < 1) then
	print("no PNGs found, exiting early...")
	exit(1)
end

if (argv[2] == "-e" or argv[2] == "--empty-sprite-0") then
	local i = 0
	while i < #pngs do
		add(pngs, "empty", i+1) -- gotta add 1 because pngs is not 0-indexed here
		i += 256
	end
end
-- ------------------------------------------
--     @pancelor's importpng.p64 code starts here
-- ------------------------------------------
function sprite_from_image(png_path)
	local img_i32 = fetch(png_path)
	if not img_i32 then return nil end

	local rgb = {}
	for i=0,31 do
		rgb[i] = rgb_from_int(peek4(0x5000+i*4))
	end

	local w,h = img_i32:attribs()
	local img_u8 = userdata("u8",w,h)
	for i=0,w*h-1 do
		img_u8[i] = best_match(rgb,img_i32[i])
	end

	return {
		bmp=img_u8,
		flags=0x0,
		pan_x=0,
		pan_y=0,
		zoom=8
	}
end

local _memo={}
function best_match(rgb,now_i32)
	local res=_memo[now_i32]
	if res then return res end

	local now = rgb_from_int(now_i32)
	local v,k = minby0(rgb,function(cvec)
		cvec -= now
		return cvec:dot(cvec) --distance squared to now
	end)

	_memo[now_i32]=k
	return k
end

-- rgb: vec(r,g,b), each in [0,1] range
-- returns: 0xRRGGBB
function int_from_rgb(rgb)
	return (rgb.x*255\1<<16)+(rgb.y*255\1<<8)+(rgb.z*255\1)
end

-- int: 0xRRGGBB
-- returns: vec(r,g,b), each in [0,1] range
function rgb_from_int(int)
	return vec((int>>16&0xff)/255,(int>>8&0xff)/255,(int&0xff)/255)
end

function minby0(arr, fn)
  fn = fn or function(x) return x end
  local best,besti = fn(arr[0]),0
  for i=1,#arr do
    local now = fn(arr[i])
    if now<best then
      best,besti = now,i
    end
  end
  return best,besti
end
-- ------------------------------------------
--     @pancelor's importpng.p64 code stops here
-- ------------------------------------------

-- loop through pngs table and start copying their userdata
local total_files = #pngs
local idx = 0

-- core loop - get a png userdata, copy to .gfx, go next
local gfx_data = {}
for i=0,flr(#pngs/256) do
	-- create a new gfx "page"
	gfx_data[i] = {}

	-- calculate how many sprites are in this page
	local num_sprites = #pngs-(i*256)

	-- loop through each sprite and populate the current page
	for j=0,num_sprites-1	 do
		-- check if this is the "empty" sprite
		if (pngs[i*256+j+1] == "empty") then
			gfx_data[i][j] = {
				bmp=userdata("u8", 16, 16), -- empty 16x16 userdata
				flags=0x0,
				pan_x=0,
				pan_y=0,
				zoom=8
			}
		-- this is a real file to attempt to import
		else
			local data = sprite_from_image(path.."/"..pngs[i*256+j+1])
			if (data ~= nil) then
				gfx_data[i][j] = data
				print("imported "..pngs[i*256+j+1].." ("..(i*256+j+1).."/"..total_files..")")
			else
				print("failed to import "..pngs[i].."; continuing")
			end
		end
	end
end

-- write to gfx file(s)
for i=0,flr(#pngs/256) do
	print("storing "..i..".gfx")
	store(path.."/"..i..".gfx", gfx_data[i])
end
2


Usage:

simport [FOLDER]
Populate .gfx file(s) using a folder of PNGs.

OPTIONS
  -e
  --empty-sprite-0
  keep sprite 0 empty on every .gfx file
  (default is to write data to sprite 0)


[Please log in to post a comment]