Dynamically created gui box node appears black in HTML5 build

My code generated gui box node appears correctly in a desktop and Android build but displays as a black box in an HTML5 build. It should show a map of the current game level. Any ideas why this might be?

Here’s the code:

if gui.new_texture("map", w, h, "rgba", pixels) then
	mapnode = gui.new_box_node(vmath.vector3(224, 360, 0), vmath.vector3(w, h, 0))
	gui.set_scale(mapnode, vmath.vector3(MAP_SCALE, MAP_SCALE, 0))
	gui.set_texture(mapnode, "map")
	gui.set_pivot(mapnode, gui.PIVOT_CENTER)
	gui.set_color(mapnode, vmath.vector4(1, 1, 1, 0))
	gui.set_adjust_mode(mapnode, gui.ADJUST_STRETCH)
end
1 Like

Does it work if you’re not creating the box node dynamically?

Yes - just the dynamically created box node appears as a black box.

Hmm, strange. @sven, @Mathias_Westerdahl, @Andreas_Tadic: Is there any reason a run-time created box node with a run-time created texture wouldn’t work correctly on HTML5?

No, and I cannot reproduce it either. It works for me.

However, I had to change the alpha value from 0 in order to actually see the node to begin? (transparent on both desktop and html5). But after that, it worked on both desktop and html5.

Do you have a special gui shader? Or any texture profiles on HTML5?

No shaders or anything specific to HTML5.

BTW, the alpha is set to 0 in the code snippet as the texture is faded in when needed.

Hmm, ok.
How do you create the texture?
When I tested, I used the code from the example:

-- untested code (I have the tested code at home)
local w = 128
local h = 128
local orange = string.char(0xff) .. string.char(0x80) .. string.char(0x10)

-- Create the texture. Repeat the color string for each pixel.
if gui.new_texture("map", w, h, "rgb", string.rep(orange, w * h)) then
	mapnode = gui.new_box_node(vmath.vector3(224, 360, 0), vmath.vector3(w, h, 0))
	gui.set_scale(mapnode, vmath.vector3(1, 1, 0))
	gui.set_texture(mapnode, "map")
	gui.set_pivot(mapnode, gui.PIVOT_CENTER)
	gui.set_color(mapnode, vmath.vector4(1, 1, 1, 1)) -- alpha 1
	gui.set_adjust_mode(mapnode, gui.ADJUST_STRETCH)
end

Here’s the whole function - it creates a map texture of the current level.

function generate(self)
   	local sx, sy, w, h = tilemap.get_bounds(self.levelurl)
	local pixels = ""
   	
	local solid = string.char(0x00) .. string.char(0x00) .. string.char(0x00) .. string.char(0x44)
	local player = string.char(0x66) .. string.char(0x00) .. string.char(0x00) .. string.char(0xaa)
	local door = string.char(0x00) .. string.char(0x00) .. string.char(0x00) .. string.char(0x22)
	local stairs = string.char(0x00) .. string.char(0x66) .. string.char(0x00) .. string.char(0xaa)
	local floor = string.char(0x00) .. string.char(0x00) .. string.char(0x00) .. string.char(0x00)

	pos.x = math.floor(data.playerpos.x / 16) + 1
	pos.y = math.floor(data.playerpos.y / 16) + 1
	
	for y = sy + h - 1, sy, -1 do
		for x = sx, sx + w - 1 do
			local tile = tilemap.get_tile(self.levelurl, "world", x, y)
			local fog = tilemap.get_tile(self.levelurl, "fog", x, y)
			local item = tilemap.get_tile(self.levelurl, "items", x, y)
						
			if x == pos.x and y == pos.y then
				pixels = pixels .. player
			elseif fog == 0 and tile >= 289 then
				pixels = pixels .. solid
			elseif fog == 0 and tile >= 280 then
				pixels = pixels .. door
			elseif fog == 0 and (item == 267 or item == 268) then
				pixels = pixels .. stairs
			else
				pixels = pixels .. floor
			end
		end
	end

	if gui.new_texture("map", w, h, "rgba", pixels) then
		mapnode = gui.new_box_node(vmath.vector3(224, 360, 0), vmath.vector3(w, h, 0))
		gui.set_scale(mapnode, vmath.vector3(MAP_SCALE, MAP_SCALE, 0))
		gui.set_texture(mapnode, "map")
		gui.set_pivot(mapnode, gui.PIVOT_CENTER)
		gui.set_color(mapnode, vmath.vector4(1, 1, 1, 1))
		gui.set_adjust_mode(mapnode, gui.ADJUST_STRETCH)
	end
end

I’m also using the following material -

1 Like

I feel this is bug, let me explain my experience, after running the set_texture code in a dynamic script gui included in my texture_load function, the sample code for creating a box node won’t display a box.

If I try to create this box node before trying to set this textures I can see the box, I feel like there is some problem with HTML5 and setting dynamic textures, not something I need for my project, but tested it just to check.

function textures_load()
	-- Load Chapter Image
	local f = assert(io.open("assets/img.png", "rb"))
	local data = assert(f:read("*a"))
	img = image.load(data, true)
	local type = (img.type == image.TYPE_RGB) and "rgb" or "rgba"
	gui.new_texture("chapter_image", img.width, img.height, type, img.buffer, false)
	-- Load Background Image
	f = assert(io.open("assets/bk.png", "rb"))
	data = assert(f:read("*a"))
	img_bk = image.load(data, true)
	type = (img_bk.type == image.TYPE_RGB) and "rgb" or "rgba"
	gui.new_texture("back_image", img_bk.width, img_bk.height, type, img_bk.buffer, false)
end

function init(self)
-- Add initialization code here
-- Learn more: https://defold.com/manuals/script/
-- Remove this function if not needed

msg.post(".", "acquire_input_focus") -- <1>
self.state = "-"

textures_load()
	-- Create a new box node
	local new_position = vmath.vector3(400, 300, 0)
	local new_size = vmath.vector3(450, 400, 0)
	local new_boxnode = gui.new_box_node(new_position, new_size)
	gui.set_color(new_boxnode, vmath.vector4(0.2, 0.26, 0.32, 1))

You do not call gui.set_texture() on the created node.

Wasn’t my intention to call it, just saying, if I create a node, with a solid color after doing the gui.new_texture commands, this node won’t be seen, it think it will go transparent.

If I try to create the same node prior to calling textures_load(), the node can be seen ok.

This happens In HMTML5 build.

1 Like

I now realise that this won’t work on HTML5. File access in HTML5 is quite different and I don’t see how you would be able to load the files like that. You need to load the files in one of two ways:

  1. Using either bundle resources and a normal http.request()
  2. Using custom resources and sys.load_resource()

Note: Functions like io.* and sys.load()/save() works in HTML5 but instead of reading/writing from the local file system or webserver a file system is emulated using the IndexedDB API in the browser.