Add in.dt, slider warnings in --check, and two agent-written effects
Spec fixes come from a test where pi + deepseek-v4.1-flash wrote effects from EFFECTS.md alone: glitch-blocks and ghost-stamps both compiled on the first try. The agent's feedback led to in.dt (frame time), documented limits of in.prev as memory, and a --check warning for ignored slider lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
a20d3310db
commit
169c5f9b63
6 changed files with 111 additions and 9 deletions
|
|
@ -34,6 +34,7 @@ final class Renderer: NSObject, MTKViewDelegate {
|
|||
private var result: MTLTexture? // the finished frame
|
||||
private var lastSerial = -1
|
||||
private let startTime = CACurrentMediaTime()
|
||||
private var lastTime: Float?
|
||||
private var frameCount = 0
|
||||
private var pixels: [UInt8] = []
|
||||
|
||||
|
|
@ -224,6 +225,8 @@ final class Renderer: NSObject, MTKViewDelegate {
|
|||
analysis.update(commands, camera: frames.current, particles: layers.contains { $0.enabled && $0.usesParticles })
|
||||
|
||||
let time = Float(CACurrentMediaTime() - startTime)
|
||||
let dt = min(max(time - (lastTime ?? time - 1.0 / 30.0), 0.001), 0.25)
|
||||
lastTime = time
|
||||
var image = frames.current
|
||||
for layer in layers where layer.enabled {
|
||||
guard let pipeline = layer.pipeline else { continue }
|
||||
|
|
@ -231,8 +234,8 @@ final class Renderer: NSObject, MTKViewDelegate {
|
|||
layer.targets = [makeTarget(device, width: width, height: height), makeTarget(device, width: width, height: height)]
|
||||
for target in layer.targets { commands.pass(into: target, clear: true) }
|
||||
}
|
||||
// must match `struct Uniforms` in the shader: time, padding, resolution.xy, params[16]
|
||||
var uniforms: [Float] = [time, 0, Float(width), Float(height)]
|
||||
// must match `struct Uniforms` in the shader: time, dt, resolution.xy, params[16]
|
||||
var uniforms: [Float] = [time, dt, Float(width), Float(height)]
|
||||
uniforms += layer.params.map(\.value) + [Float](repeating: 0, count: maxParams - layer.params.count)
|
||||
let textures = [image, frames.current, frames.last, layer.targets[1], analysis.flow, analysis.particles]
|
||||
commands.pass(into: layer.targets[0]) { $0.fullscreen(pipeline, textures: textures, uniforms: uniforms) }
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ func effectShader(body: String, params: [EffectParam]) -> String {
|
|||
return shaderPrelude + """
|
||||
struct Uniforms {
|
||||
float time;
|
||||
float dt;
|
||||
float2 resolution;
|
||||
float params[\(maxParams)];
|
||||
};
|
||||
|
|
@ -89,6 +90,7 @@ func effectShader(body: String, params: [EffectParam]) -> String {
|
|||
texture2d<float> particles; // .r = brightness of particles that drift along with the motion
|
||||
sampler smp;
|
||||
float time; // seconds since start
|
||||
float dt; // seconds since the previous frame (about 1/30)
|
||||
float2 resolution; // output size in pixels
|
||||
Params p; // this effect's sliders
|
||||
};
|
||||
|
|
@ -106,7 +108,7 @@ func effectShader(body: String, params: [EffectParam]) -> String {
|
|||
constant Uniforms &u [[buffer(0)]]) {
|
||||
constexpr sampler smp(filter::linear, address::clamp_to_edge);
|
||||
Params p = { \(values) };
|
||||
Inputs in = { image, camera, last, prev, flow, particles, smp, u.time, u.resolution, p };
|
||||
Inputs in = { image, camera, last, prev, flow, particles, smp, u.time, u.dt, u.resolution, p };
|
||||
return effect(v.uv, in);
|
||||
}
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ if CommandLine.arguments.contains("--check") {
|
|||
_ = try makePipeline(device, source: effectShader(body: source, params: info.params),
|
||||
fragment: "effectFragment", format: .bgra8Unorm)
|
||||
print("ok \(name) sliders: \(info.params.isEmpty ? "none" : info.params.map(\.name).joined(separator: ", "))")
|
||||
let sliderLines = source.split(separator: "\n").filter { $0.hasPrefix("// slider") }.count
|
||||
if sliderLines != info.params.count {
|
||||
print(" warning: \(sliderLines - info.params.count) slider line(s) ignored (malformed, or over the limit of \(maxParams))")
|
||||
}
|
||||
} catch {
|
||||
failures += 1
|
||||
print("FAIL \(name)\n\(error.localizedDescription)")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue