84 lines
3.3 KiB
GDScript
84 lines
3.3 KiB
GDScript
extends SceneTree
|
|
const Materials = preload("res://fx/particle_color_material.gd")
|
|
const EffectPlayer = preload("res://fx/effect_player.gd")
|
|
var failures := 0
|
|
func check(ok: bool, label: String) -> void:
|
|
if not ok:
|
|
failures += 1
|
|
printerr("FAIL: " + label)
|
|
func _init() -> void:
|
|
call_deferred("run")
|
|
func run() -> void:
|
|
var fx := EffectPlayer.new()
|
|
var textures: Array[Texture2D] = []
|
|
for color in [Color.RED, Color.GREEN, Color.BLUE]:
|
|
var img := Image.create(4, 4, false, Image.FORMAT_RGBA8)
|
|
img.fill(color)
|
|
textures.append(ImageTexture.create_from_image(img))
|
|
var frames := fx._texture_array(textures)
|
|
check(frames != null and frames.get_layers() == 3, "independent texture-array slices")
|
|
var base := StandardMaterial3D.new()
|
|
base.blend_mode = BaseMaterial3D.BLEND_MODE_MIX
|
|
base.albedo_texture = textures[0]
|
|
var mat := Materials.build(base, 4, frames, {"TexAniType": 1, "TexAniDelay": 0.1}, 1.0)
|
|
check(mat is ShaderMaterial, "ordinary modulation supports per-particle frames")
|
|
if DisplayServer.get_name() != "headless":
|
|
await pixels(mat)
|
|
else:
|
|
print("SKIP: texture animation pixels require a renderer")
|
|
fx.free()
|
|
print("effect_texture_animation_test: failures=%d" % failures)
|
|
quit(1 if failures else 0)
|
|
func pixels(material: ShaderMaterial) -> void:
|
|
var viewport := SubViewport.new()
|
|
viewport.size = Vector2i(96, 96)
|
|
viewport.own_world_3d = true
|
|
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
|
root.add_child(viewport)
|
|
var environment := WorldEnvironment.new()
|
|
environment.environment = Environment.new()
|
|
environment.environment.background_mode = Environment.BG_COLOR
|
|
environment.environment.background_color = Color.BLACK
|
|
viewport.add_child(environment)
|
|
var camera := Camera3D.new()
|
|
camera.projection = Camera3D.PROJECTION_ORTHOGONAL
|
|
camera.size = 3.0
|
|
camera.position.z = 3.0
|
|
viewport.add_child(camera)
|
|
var instance := MultiMeshInstance3D.new()
|
|
var mesh := QuadMesh.new()
|
|
mesh.size = Vector2(0.8, 0.8)
|
|
var multi := MultiMesh.new()
|
|
multi.transform_format = MultiMesh.TRANSFORM_3D
|
|
multi.use_custom_data = true
|
|
multi.use_colors = true
|
|
multi.mesh = mesh
|
|
multi.instance_count = 2
|
|
for i in 2:
|
|
multi.set_instance_transform(i, Transform3D(Basis.IDENTITY, Vector3(-0.6 + i * 1.2, 0, 0)))
|
|
multi.set_instance_color(i, Color.WHITE)
|
|
instance.multimesh = multi
|
|
instance.material_override = material
|
|
viewport.add_child(instance)
|
|
# Same material, different ages: old shared AnimatedTexture fails this.
|
|
for type in [0, 1, 2, 3, 4]:
|
|
material.set_shader_parameter("animation_type", type)
|
|
for age in [0.15, 0.25, 0.35]:
|
|
multi.set_instance_custom_data(0, Color(0, 0, 0.2, 0))
|
|
multi.set_instance_custom_data(1, Color(0, age, 0.2, 0))
|
|
await process_frame
|
|
await RenderingServer.frame_post_draw
|
|
var img := viewport.get_texture().get_image()
|
|
var newborn := img.get_pixel(29, 48)
|
|
check(newborn.r > 0.9 and newborn.g < 0.05, "newborn always starts at frame zero type=%d" % type)
|
|
var aged := img.get_pixel(67, 48)
|
|
if type in [0, 1, 2, 4]:
|
|
var step := int(floor(age / 0.1))
|
|
var index := 0 if type == 0 else posmod(-step if type == 2 else step, 3)
|
|
var channels := [aged.r, aged.g, aged.b]
|
|
check(channels[index] > 0.9, "age selects expected frame type=%d age=%s" % [type, age])
|
|
else:
|
|
check(maxf(aged.r, maxf(aged.g, aged.b)) > 0.9, "random frame selects one valid texture")
|
|
viewport.free()
|
|
await process_frame
|