What am I doing wrong? Attempt to use downloaded image as texture (player picture) fails

I’m still out on deep water, on my quest to learn this fantastic tool. Now I’m missing the final touch on this feature, before I can move along.

So far I’ve been able to connect to Facebook, download the players(me in this case) profile picture, saved it to the device file system (using io.open() (another great adventure)), and also been able to read the file from the file system. I’ve checked the values, and they are similar both at download and read, and I’ve also checked it physicaly, by checking at app bundle via xcode. The image is there, in all its glory.

Now I would like to assign that image to a texture, to use on my box node. The problem is, that it fail when i try to create the new texture, with the error:

ERROR:GUI: Invalid image buffer size. Expected 30000, got 3718
WARNING:GUI: Failed to create dynamic gui texture (-7)

I thought it was time to call for help, since I’ve spent too much time one it, trying to solve it by Google.

My function:

local function set_fb_pic()
	pprint("Setting FB avatar")
	local file =  assert(io.open(shared_data.home .. shared_data.avatar_file, "r"))
	local w, h = getsize(file)
	pprint(w)
	pprint(h)	
	local size = file:seek("end")
	file:seek("set", 0)
	local data = file:read("*a")
	data = string.gsub(data, "\r\n", "\n")
	assert(file:close())
	pprint(file)
	--local img = assert(image.load(data))
	--print(img)
	if gui.new_texture("avatar_tx", w, h, "rgb", data) then
	local n = gui.get_node("fb_pic")
	pprint(n)
	end
end

Sorry for the messy code.:blush:

1 Like

It looks as though there’s some issue with the size of the loaded data. Can’t you simply do image.load() and use the size that is returned from that call instead of manually trying to read it from the file?

Oh, I think you should do:

io.open("name of file, "rb") -- binary!

As a side note here’s a working example of getting, loading and setting an image on a box node:

local function load_and_set_texture(url, node)
	http.request(url, "GET", function(self, id, res)
		if res.status ~= 200 and res.status ~= 304 then
			print("Unable to get image", res.response)
			return
		end
		
		local img = image.load(res.response)
		if not img then
			print("Unable to load image")
			return
		end

		local texture_id = url
		if gui.new_texture(texture_id, img.width, img.height, img.type, img.buffer) then
			gui.set_texture(node, texture_id)
		else
			print("Unable to create texture")
		end
	end)
end

function init(self)
	load_and_set_texture("http://www.defold.com/static/logos/logo-text-below.png", gui.get_node("box"))
end

function final(self)
	gui.delete_texture("http://www.defold.com/static/logos/logo-text-below.png")
end
4 Likes

Hmmm… Here’s me, trying to re-invent the wheel, again. At least I learn a lot on the way. :blush: I’ll check it out, as soon as I get a chance, and report back.

Thank you for being awesome, @britzl! :+1:

Edit: And sorry for being stupid. I looked at the API reference again, and noticed that my brain hadn’t caught on to what it said about return values… http://www.defold.com/ref/image/ :neutral_face:

1 Like

Can this be done with sprites with the built in functions? It is looking like no to me…

No, not really. You can make dynamic textures end up on sprites, but that requires a bit of render script fiddling with render targets etc.

For use case I have in mind, which is loading large background images dynamically from a server, I am going to make another GUI material and then load the JPG into a GUI component that uses a material that is drawn before game objects.

Sounds good, I think that’s how it’s done in Blossom Blast Saga. Maybe @Andreas_Jirenius knows more?

Hi.
Well all the maps are actually created using meshes as we do a lot of nice “render_to_texture” and shader magic on them. But it sounds like using gui and render them in an earlier predicate would definitely be sufficient.