Implement playable Mac client and rendering validation
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
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 effective(pm: ParticleProcessMaterial, age: float) -> Color:
|
||||
return pm.color * pm.color_ramp.gradient.sample(age) if pm.color_ramp else pm.color
|
||||
|
||||
func _init() -> void:
|
||||
var fx := EffectPlayer.new()
|
||||
fx.build({"particles": [{"particle": {
|
||||
"TimeEventColorRed": [[0.0, 0.2], [0.5, 0.8], [1.0, 0.4]],
|
||||
"TimeEventColorGreen": [[0.25, 0.4], [0.75, 0.8]],
|
||||
"TimeEventColorBlue": [[0.0, 0.5]],
|
||||
"TimeEventAlpha": [[0.0, 1.0], [1.0, 0.0]]}},
|
||||
{"particle": {"TimeEventColorRed": [[0.0, 0.5]], "TimeEventAlpha": [[0.0, 1.0]]}},
|
||||
{"particle": {"TimeEventColorBlue": [[0.0, 0.2], [1.0, 0.8]]}},
|
||||
{"particle": {}}]})
|
||||
var pm: ParticleProcessMaterial = fx._emitters[0].process_material
|
||||
check(pm.color == Color.WHITE, "neutral base prevents double tint")
|
||||
check(effective(pm, 0.0).is_equal_approx(Color(0.2, 0.4, 0.5, 1.0)), "birth RGBA")
|
||||
check(effective(pm, 0.25).is_equal_approx(Color(0.5, 0.4, 0.5, 0.75)), "independent green knot")
|
||||
check(effective(pm, 0.5).is_equal_approx(Color(0.8, 0.6, 0.5, 0.5)), "middle RGBA")
|
||||
check(effective(pm, 0.75).is_equal_approx(Color(0.6, 0.8, 0.5, 0.25)), "late RGBA")
|
||||
check(effective(pm, 1.0).is_equal_approx(Color(0.4, 0.8, 0.5, 0.0)), "end RGBA")
|
||||
check(effective(fx._emitters[1].process_material, 0.5).is_equal_approx(Color(0.5, 1.0, 1.0)),
|
||||
"constant 0.5 tint remains 0.5, not 0.25")
|
||||
check(effective(fx._emitters[2].process_material, 0.5).is_equal_approx(Color(1.0, 1.0, 0.5)),
|
||||
"RGB animates without alpha track")
|
||||
check(effective(fx._emitters[3].process_material, 0.5) == Color.WHITE, "missing tracks default white")
|
||||
fx.free()
|
||||
var malformed := EffectPlayer.new()
|
||||
var cleaned: GradientTexture1D = malformed._color_ramp({"TimeEventColorRed": [
|
||||
[1.0, 0.8], [], [0.0, 0.1], [0.0, 0.2], [NAN, 0.5], [0.5, INF], ["bad", 0.4]]})
|
||||
check(cleaned.gradient.sample(0.5).is_equal_approx(Color(0.5, 1, 1)),
|
||||
"unordered/duplicate keys normalized and invalid values ignored")
|
||||
malformed.free()
|
||||
real_resources()
|
||||
print("effect_color_test: failures=%d" % failures)
|
||||
quit(1 if failures else 0)
|
||||
|
||||
# Independent scalar interpolation oracle for the sorted, valid asset tracks.
|
||||
func reference(rows: Array, age: float) -> float:
|
||||
if rows.is_empty():
|
||||
return 1.0
|
||||
if age <= float(rows[0][0]):
|
||||
return float(rows[0][1])
|
||||
for i in range(1, rows.size()):
|
||||
if age <= float(rows[i][0]):
|
||||
var fraction := (age - float(rows[i - 1][0])) / (float(rows[i][0]) - float(rows[i - 1][0]))
|
||||
return float(rows[i - 1][1]) * (1.0 - fraction) + float(rows[i][1]) * fraction
|
||||
return float(rows[-1][1])
|
||||
|
||||
func real_resources() -> void:
|
||||
var count := 0
|
||||
for name in ["warrior/effect/palbang_4_sword.mse", "assassin/effect/beam_blow.mse",
|
||||
"sura/effect/pabeopsul_4_blow.mse", "shaman/effect/noejeon_making_1.mse"]:
|
||||
var path := AssetRoot.path().path_join("PC/ymir work/pc/" + name)
|
||||
var parsed: Dictionary = preload("res://fx/mse.gd").new().parse_file(path)
|
||||
check(not parsed.get("particles", []).is_empty(), "real resource loaded: " + name)
|
||||
for particle in parsed.get("particles", []):
|
||||
# Exercise real RGBA through material construction; texture loading and
|
||||
# emission geometry are deliberately outside this color-only regression.
|
||||
var prop: Dictionary = {}
|
||||
for key in ["TimeEventColorRed", "TimeEventColorGreen", "TimeEventColorBlue", "TimeEventAlpha"]:
|
||||
prop[key] = particle.particle.get(key, [])
|
||||
var fx := EffectPlayer.new()
|
||||
fx.build({"particles": [{"particle": prop}]})
|
||||
var pm: ParticleProcessMaterial = fx._emitters[0].process_material
|
||||
for step in range(41):
|
||||
var age := float(step) / 40.0
|
||||
var expected := Color(reference(prop.TimeEventColorRed, age),
|
||||
reference(prop.TimeEventColorGreen, age), reference(prop.TimeEventColorBlue, age),
|
||||
reference(prop.TimeEventAlpha, age))
|
||||
check(effective(pm, age).is_equal_approx(expected), "real RGBA %s particle %d t=%f" % [name, count, age])
|
||||
count += 1
|
||||
fx.free()
|
||||
print("real color tracks: particles=%d samples=%d" % [count, count * 41])
|
||||
Reference in New Issue
Block a user