Replacing tile_source image with downloaded image

Is it possible at runtime to replace the image used by a tile source with one e.g. downloaded from a server? I know there have been recent improvements to runtime image loading but I’m not sure if this case is possible.

We’d be using this to recolour tilemaps seasonally, so the image would be the same dimensions as before.

Yes, I think that should be possible now.

It would look something like this:

local img = go.get("#sprite", "image")

-- get info about the atlas that is used
-- it shouldn't matter if this is a tilesource or an atlas
-- needs to be tested though...
-- https://defold.com/ref/resource/#resource.get_atlas:path
local atlas = resource.get_atlas(img)
print("texture path", atlas.texture)
pprint("animations", atlas.animations)
pprint("geometries", atlas.geometries)

-- get information about the texture that is used
-- https://defold.com/ref/resource/#resource.get_texture_info:path
local texture = resource.get_texture_info(atlas.texture)
print("texture w,h", texture.width, texture.height)

-- update the texture with new pixel data
-- https://defold.com/ref/resource/#resource.set_texture:path-table-buffer
local info = {
    type = texture.type,
    width = texture.width,
    height = texture.height,
    format = resource.TEXTURE_FORMAT_RGB, -- not sure why this isn't in the texture info table...
    x = 32, -- where to draw
    y = 64,
    compression_type = resource.COMPRESSION_TYPE_DEFAULT
}
-- create a buffer with the pixels
-- https://defold.com/ref/stable/buffer/#buffer.create:element_count-declaration
local buf = buffer.create()
resource.set_texture(atlas.texture, info, buf)

I have some questions of my own. @JCash or @jhonny.goransson should be able to answer:

  1. The result from resource.get_texture_info() provides a lot of useful info when you wish to later update the texture using resource.set_texture(), but it seems like we do not provide:
    • Compression type of the texture
    • Format of the texture
  2. The above flow works for updating a texture with new pixels. What if I want to read the existing pixels first? Do we have a way to get the pixel data? Preferably uncompressed if the data is compressed, but that is probably asking too much. Might be better to not compress a texture you wish to read from.

I think the above flow is a good candidate for a utility module that could be shared with the community.

3 Likes

Well, no not really. The data is also likely compressed in a GPU format, and you’d have to decompress it to use it.
Ofc, if the image was uncompressed, it might be useful, but we currently don’t have a way to get that data.
But also, if you’re just want to read a file, you can use sys.load_resource() to load a resource (e.g. a .png)

In short, I don’t think our .texturec mechanic is entirely appropriate to get raw pixels.

What other questions were there?

2 Likes

Sure, that makes sense. In the case of recoloring pixels like @AarrrBee is requesting it is probably best to not apply texture compression and then use sys.load_resource(path) to get the raw pixels, make the changes necessary and then set the texture.

Have you considered doing this in the shader instead?

Would it not make sense for resource.get_texture_info() to also return if the texture is compressed or not and also the format of the texture (RGB, RGBA, Luminance etc). Both of these bits of info are needed when you call resource.set_texture(). Or am I not going about it the right way?

For recolouring, I’d probably look into something using shader constants instead. Or reading colors from another texture set in the render script.

Would it not make sense for resource.get_texture_info() to also return if the texture is compressed or not and also the format of the texture (RGB, RGBA, Luminance etc)

If you want this info, sure.

However, since you need to specify the format when setting the texture, you can change format if you wish. And also note that the format specifies the format that you pass in. We don’t compress the texture for you.

I made a test image by adjusting the RGB curves in an image editor, but we might want to go further - tree tiles might lose leaves or have snow in winter - so a shader approach might be a dead end.

1 Like

If it’s no longer only colours, then yes, another approach is needed.

Thanks, I have a basic version working. Image pitch/stride was an issue but for now have just padded it to be power of 2.
Next step is to use something like TexturePacker to extrude the edges in the image to match the editor behaviour.

Issue in what way, something on our side? :thinking:

The tilesource is a 1152x1152 image , which becomes a 2k texture.Downloading a new 1152x1152 PNG gives me a buffer containing exactly those pixels, so I need to copy row by row. I’ve done that in C++ but in Lua with 1-based indexing and no pointers, it wasn’t intuitive and progress was slow (as was the code!)