<<>> <> <> <> DIRECTORY BasicTime, CedarProcess, Commander, CommandTool, Convert, G3dAnimate, IO, Process, Rope, ThisMachine; G3dAnimateImpl: CEDAR MONITOR IMPORTS BasicTime, CedarProcess, Commander, CommandTool, Convert, IO, Process, Rope, ThisMachine EXPORTS G3dAnimate ~ BEGIN <> ROPE: TYPE ~ Rope.ROPE; Status: TYPE ~ RECORD [ start, finish: BasicTime.GMT ¬ BasicTime.nullGMT, done: BOOL ¬ FALSE]; StatusSequence: TYPE ~ REF StatusSequenceRep; StatusSequenceRep: TYPE ~ RECORD [element: SEQUENCE length: CARDINAL OF Status]; Registration: TYPE ~ REF RegistrationRep; RegistrationRep: TYPE ~ RECORD [ name: ROPE ¬ NIL, estMinutesPerFrame: NAT ¬ 60, status: StatusSequence ¬ NIL]; <> Error: PUBLIC SIGNAL [code: ATOM, reason: ROPE] = CODE; <> GetRegistration: PROC [animationName: ROPE] RETURNS [r: Registration ¬ NIL] ~ { FOR l: LIST OF Registration ¬ registry, l.rest WHILE l # NIL DO IF Rope.Equal[l.first.name, animationName, FALSE] THEN RETURN[l.first]; ENDLOOP; }; GetFrameNumber: PUBLIC ENTRY PROC [masterMachineName, animationName: ROPE] RETURNS [INTEGER] ~ { IF Rope.Equal[ThisMachine.Name[], masterMachineName] THEN { r: Registration ¬ GetRegistration[animationName]; IF r = NIL THEN Error[$NoSuchAnimation, Rope.Cat[animationName, " isn't registered"]]; FOR n: NAT IN [0..r.status.length) DO IF r.status[n].start # BasicTime.nullGMT THEN LOOP; r.status[n].start ¬ BasicTime.Now[]; RETURN[n]; ENDLOOP; RETURN[-1]; } ELSE { <> RETURN[-1]; }; }; FrameDone: PUBLIC ENTRY PROC [masterMachineName, animationName: ROPE, frame: NAT] ~ { IF Rope.Equal[ThisMachine.Name[], masterMachineName] THEN { r: Registration ¬ GetRegistration[animationName]; IF r = NIL THEN Error[$NoSuchAnimation, Rope.Cat[animationName, " isn't registered"]]; IF frame >= r.status.length THEN Error[$BadFrame, IO.PutFR["%g is too large; %g has only %g frames", IO.int[frame], IO.rope[animationName], IO.int[r.status.length]]]; r.status[frame].done ¬ TRUE; r.status[frame].finish ¬ BasicTime.Now[]; RETURN; } ELSE { <> }; }; RegisterAnimation: PUBLIC ENTRY PROC [name: ROPE, nFrames, estMinutesPerFrame: NAT] ~ { r: Registration ¬ NEW[RegistrationRep ¬ [name, estMinutesPerFrame]]; r.status ¬ NEW[StatusSequenceRep[nFrames]]; FOR l: LIST OF Registration ¬ registry, l.rest WHILE l # NIL DO IF Rope.Equal[l.first.name, name, FALSE] THEN {l.first ¬ r; RETURN}; IF l.rest = NIL THEN {l.rest ¬ LIST[r]; RETURN}; ENDLOOP; }; UnRegisterAnimation: PUBLIC ENTRY PROC [name: ROPE] ~ { previous: LIST OF Registration ¬ NIL; FOR l: LIST OF Registration ¬ registry, l.rest WHILE l # NIL DO IF NOT Rope.Equal[l.first.name, name, FALSE] THEN {previous ¬ l; LOOP}; IF previous = NIL THEN registry ¬ l.rest ELSE previous.rest ¬ l.rest; RETURN; ENDLOOP; }; Watch: CedarProcess.ForkableProc ~ { -- reset status to unstarted if computation takes too long DO now: BasicTime.GMT ¬ BasicTime.Now[]; Process.Pause[Process.SecondsToTicks[300]]; FOR l: LIST OF Registration ¬ registry, l.rest WHILE l # NIL DO FOR n: NAT IN [0..l.first.status.length) DO s: Status ¬ l.first.status[n]; IF s.done OR s.start = BasicTime.nullGMT THEN LOOP; IF BasicTime.Period[s.start, now] > 2.0*l.first.estMinutesPerFrame THEN l.first.status[n].start ¬ BasicTime.nullGMT; ENDLOOP; ENDLOOP; ENDLOOP; }; <> registry: LIST OF Registration ¬ NIL; AnimateMasterCmd: Commander.CommandProc ~ { ENABLE Convert.Error => {msg ¬ "Bad conversion"; GOTO Bad}; a: CommandTool.ArgumentVector ¬ CommandTool.Parse[cmd]; IF a.argc # 3 THEN RETURN[$Failure, usage] ELSE RegisterAnimation[a[1], Convert.IntFromRope[a[2]], Convert.IntFromRope[a[3]]]; EXITS Bad => RETURN [$Failure, msg]; }; <> usage: ROPE ~ "Usage: 3dAnimateMaster <# frames> If initializing, just specify number of frames for this animation"; G3dTool.Register["3dAnimateMaster", AnimateMasterCmd, usage]; [] ¬ CedarProcess.Fork[Watch]; END.