64 lines
2.8 KiB
GDScript
64 lines
2.8 KiB
GDScript
extends SceneTree
|
|
|
|
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:
|
|
var fx := EffectPlayer.new()
|
|
# D3D8: SRCALPHA=5, INVSRCALPHA=6; both mesh and particle use this helper.
|
|
check(fx._blend(5, 6) == BaseMaterial3D.BLEND_MODE_MIX, "source-alpha transparency")
|
|
check(fx._blend(5, 2) == BaseMaterial3D.BLEND_MODE_ADD, "additive glow preserved")
|
|
fx.build({"particles": [{"start_time": 0.5,
|
|
"emitter": {"CycleLength": 1.0, "CycleLoopEnable": 1, "LoopCount": 2},
|
|
"particle": {"SrcBlendType": 5, "DestBlendType": 6}}]})
|
|
var state: Dictionary = fx._particle_states[0]
|
|
var emitter: GPUParticles3D = state.node
|
|
check(emitter.material_override.blend_mode == BaseMaterial3D.BLEND_MODE_MIX,
|
|
"built particle uses alpha material")
|
|
fx._advance_particle(state, 0.25)
|
|
check(is_equal_approx(state.clock, 0.25) and not emitter.emitting,
|
|
"stationary emitter advances clock and respects start delay")
|
|
# Simulate the play timer starting emission; isolate cycle gating from timers.
|
|
emitter.emitting = true
|
|
fx._advance_particle(state, 2.0)
|
|
check(emitter.emitting and not state.emission_stopped, "finite loop before end")
|
|
fx._advance_particle(state, 0.25)
|
|
check(not emitter.emitting and state.emission_stopped, "stationary finite loop ends")
|
|
state.clock = 0.0
|
|
state.start_time = 0.0
|
|
state.cycle_loop = false
|
|
state.emission_stopped = false
|
|
emitter.emitting = true
|
|
fx._advance_particle(state, 1.0)
|
|
check(not emitter.emitting and state.emission_stopped, "stationary non-loop ends")
|
|
state.clock = 0.0
|
|
state.cycle_loop = true
|
|
state.loop_count = 0
|
|
state.emission_stopped = false
|
|
emitter.emitting = true
|
|
fx._advance_particle(state, 10.0)
|
|
check(emitter.emitting and not state.emission_stopped, "unlimited loop preserved")
|
|
check(emitter.position == Vector3.ZERO, "missing position stays at origin")
|
|
fx.free()
|
|
var path := AssetRoot.path().path_join("PC/ymir work/pc/shaman/effect/7budongbakbu_throw.mse")
|
|
var parsed: Dictionary = preload("res://fx/mse.gd").new().parse_file(path)
|
|
check(not parsed.get("particles", []).is_empty(), "real shaman effect loaded")
|
|
var real_fx := EffectPlayer.new()
|
|
real_fx.build(parsed, AssetRoot.path())
|
|
var alpha_count := 0
|
|
for i in parsed.get("particles", []).size():
|
|
var prop: Dictionary = parsed.particles[i].particle
|
|
if int(prop.get("SrcBlendType", 0)) == 5 and int(prop.get("DestBlendType", 0)) == 6:
|
|
alpha_count += 1
|
|
check(real_fx._emitters[i].material_override.blend_mode == BaseMaterial3D.BLEND_MODE_MIX,
|
|
"real shaman alpha particle %d" % i)
|
|
check(alpha_count > 0, "real fixture exercises alpha blending")
|
|
real_fx.free()
|
|
print("effect_render_regression_test: failures=%d" % failures)
|
|
quit(1 if failures else 0)
|