This does an alpha-based mask in about 20ms for a set of 64x64 images, so about 0.32 seconds for your example.
func _ready():
# var final_image = Image.new()
var final_image = load('res://test_sheet.png')
# final_image.create(64,64,true,Image.FORMAT_RGBA8)
# var mask = load("res://icon2.png")
var source = load("res://icon.png")
# final_image.blit_rect_mask(source,mask,Rect2(0,0,64,64),Vector2(0,0))
var bl = Blender.new()
var mask = bl.gradient()
var t = OS.get_ticks_msec()
var comb = bl.blend(source, mask, final_image, Rect2(64,32,64,64), Vector2(64,32))
print('completed blend in %0.2fms' % [OS.get_ticks_msec() - t])
var t1 = ImageTexture.new()
var t2 = ImageTexture.new()
var t3 = ImageTexture.new()
t1.create_from_image(source)
t2.create_from_image(mask)
t3.create_from_image(comb)
var tr1 = TextureRect.new()
var tr2 = TextureRect.new()
var tr3 = TextureRect.new()
tr1.texture = t1
tr2.texture = t2
tr3.texture = t3
tr2.rect_position = Vector2(80, 0)
tr3.rect_position = Vector2(160, 0)
add_child(tr1)
add_child(tr2)
add_child(tr3)
# blender.gd -- a simple, blend with an alpha mask
extends Reference
class_name Blender
func gradient() -> Image:
# I can't get gimp to spit out a real alpha
# gradient, so I'm making one here.
var grad := Image.new()
grad.create(64,64,true,Image.FORMAT_RGBA8)
var dat:PoolByteArray = []
for i in range(0, 64*64*4, 4):
var x = int(i / 4.0) % 64
dat.append(0)
dat.append(0)
dat.append(0)
dat.append(int(255 * x / 64.0))
grad.create_from_data(grad.get_width(), grad.get_height(),
false, grad.get_format(), dat)
return grad
func blend(source:Image, mask:Image, final:Image, rect:Rect2, pos:Vector2) -> Image:
# This takes the source image according to the
# alpha of the mask, and combines it with the
# final image, creating and returning a new image.
# The source and mask must be the same size.
# *ALL* images must be in RGBA8 format.
var combine := Image.new()
var finalc := Image.new()
var out := Image.new()
var source_dat:PoolByteArray
var mask_dat:PoolByteArray
var final_dat:PoolByteArray
var combine_dat:PoolByteArray = []
var height = source.get_height()
var width = source.get_width()
finalc.create(width, height, true, Image.FORMAT_RGBA8)
finalc.blit_rect(final, Rect2(rect.position, Vector2(width, height)), Vector2.ZERO)
source_dat = source.get_data()
mask_dat = mask.get_data()
final_dat = finalc.get_data()
# print(source.get_format())
for i in range(0, len(source_dat), 4):
var alpha:float = mask_dat[i+3] * source_dat[i+3] / 255.0 / 255.0
var ialpha:float = 1.0 - alpha
combine_dat.append(int(source_dat[i+0] * alpha + final_dat[i+0] * ialpha))
combine_dat.append(int(source_dat[i+1] * alpha + final_dat[i+1] * ialpha))
combine_dat.append(int(source_dat[i+2] * alpha + final_dat[i+2] * ialpha))
combine_dat.append(int(alpha * 255.0 + final_dat[i+3] * ialpha))
if false and alpha > 0:
print('%0.2f, %0.2f' % [alpha, ialpha])
print('%d, %d, %d, %d' % [mask_dat[i+0], mask_dat[i+1], mask_dat[i+2], mask_dat[i+3]])
print('%d, %d, %d, %d' % [source_dat[i+0], source_dat[i+1], source_dat[i+2], source_dat[i+3]])
print('%d, %d, %d, %d' % [final_dat[i+0], final_dat[i+1], final_dat[i+2], final_dat[i+3]])
print('%d, %d, %d, %d' % [combine_dat[i+0], combine_dat[i+1], combine_dat[i+2], combine_dat[i+3]])
combine.create_from_data(width, height,
false, source.get_format(), combine_dat)
out.copy_from(final)
out.blit_rect(combine, Rect2(Vector2.ZERO, rect.size), pos)
return out
Edit: Now it takes the correct piece of the final image, instead of assuming it will be at (0,0).
