<> <> <> DIRECTORY Atom USING [ GetPropFromList, PropList, PutPropOnList ], Real USING [ LargestNumber ], RealFns USING [ Power, SqRt ], IO USING [ PutRope, STREAM ], Convert USING [ RopeFromReal ], Rope USING [ Cat ], G3dVector USING [ Add, Length, Sub ], G3dMatrix USING [ Transform ], ThreeDBasics USING [ Context, SetPosition, ShapeInstance, ShapeProc, Triple ], SceneUtilities USING [ FindShape ]; AnimationProcs: CEDAR PROGRAM IMPORTS Atom, Convert, G3dVector, G3dMatrix, IO, RealFns, Rope, SceneUtilities, ThreeDBasics ~ BEGIN <> Context: TYPE ~ ThreeDBasics.Context; Triple: TYPE ~ ThreeDBasics.Triple; -- RECORD [ x, y, z: REAL]; ShapeInstance: TYPE ~ ThreeDBasics.ShapeInstance; LORA: TYPE ~ LIST OF REF ANY; <> GetProp: PROC [propList: Atom.PropList, prop: REF ANY] RETURNS [REF ANY] ~ Atom.GetPropFromList; PutProp: PROC [propList: Atom.PropList, prop: REF ANY, val: REF ANY] RETURNS [Atom.PropList] ~ Atom.PutPropOnList; <> radiansToDegrees: REAL ~ 180.0 / 3.1416; force: REAL _ 2.0; -- force of gravity (for twiddling) <> Sqr: PROCEDURE [number: REAL] RETURNS [REAL] ~ INLINE { RETURN[number * number]; }; <> RollShape: ThreeDBasics.ShapeProc ~ { <> <> GetBase: PROC [shape: REF ShapeInstance] RETURNS[base: Triple] ~ { base.z _ Real.LargestNumber; FOR i: NAT IN [0..shape.vertex.length) DO newVtx: Triple _ G3dMatrix.Transform[ [shape.vertex[i].x, shape.vertex[i].y, shape.vertex[i].z], shape.position ]; IF newVtx.z < base.z THEN base _ newVtx; ENDLOOP; }; shadowShape: REF ShapeInstance; frameNumber: NAT _ context.frameNumber; log: IO.STREAM _ NARROW[Atom.GetPropFromList[context.props, $Log]]; list: LORA _ NARROW[GetProp[shape.shadingProps, $RollShape] ]; rotationRate: REAL _ NARROW[ list.first, REF REAL ]^; timePerFrame: REAL _ NARROW[ list.rest.first, REF REAL ]^; endTime: REAL _ NARROW[ list.rest.rest.first, REF REAL ]^; ctrOfMass: REF Triple _ IF list.rest.rest.rest # NIL THEN NARROW[ list.rest.rest.rest.first ] ELSE NIL; xfmdCtr, lastBase: Triple; armLength, massLength, dRot, newMassLength: REAL; IF ctrOfMass = NIL THEN { <> ctrOfMass _ NEW[ Triple _ [0.0,0.0,0.0] ]; FOR i: NAT IN [0..shape.vertex.length) DO weight: REAL _ 4.0 * RealFns.Power[0.5 * (1.0 - shape.vertex[i].z), 3.0] * RealFns.SqRt[Sqr[shape.vertex[i].x] + Sqr[shape.vertex[i].y]]; ctrOfMass.x _ ctrOfMass.x + shape.vertex[i].x*weight; ctrOfMass.y _ ctrOfMass.y + shape.vertex[i].y*weight; ctrOfMass.z _ ctrOfMass.z + shape.vertex[i].z*weight; ENDLOOP; ctrOfMass.x _ ctrOfMass.x / shape.vertex.length; ctrOfMass.y _ ctrOfMass.y / shape.vertex.length; ctrOfMass.z _ ctrOfMass.z / shape.vertex.length; }; xfmdCtr _ G3dMatrix.Transform[ ctrOfMass^, shape.position ]; -- Evaluate new center of mass armLength _ G3dVector.Length[ G3dVector.Sub[ xfmdCtr, [shape.axisBase.x, shape.axisBase.y, xfmdCtr.z] ] ]; massLength _ G3dVector.Length[ G3dVector.Sub[xfmdCtr, shape.axisBase] ]; <> dRot _ (force / massLength) * armLength / massLength; IF (((shape.axisEnd.x - shape.axisBase.x) * (xfmdCtr.y - shape.axisBase.y)) -- which way? - ((shape.axisEnd.y - shape.axisBase.y) * (xfmdCtr.x - shape.axisBase.x))) < 0 THEN dRot _ -dRot; rotationRate _ rotationRate + dRot * radiansToDegrees; -- Adjust rotation rate IF log # NIL THEN log.PutRope[ Rope.Cat[ " Rate - ", Convert.RopeFromReal[rotationRate], ", delta - ", Convert.RopeFromReal[dRot], " " ] ]; shape.rotation _ rotationRate * timePerFrame; -- Rotate shape incrementally lastBase _ shape.axisBase; lastBase.z _ shape.axisBase.z + shape.location.z; shape.axisBase _ GetBase[shape]; -- get new base for axis shape.axisEnd _ G3dVector.Add[ shape.axisEnd, G3dVector.Sub[shape.axisBase, lastBase] ]; shape.location.z _ lastBase.z - shape.axisBase.z; -- keep above surface ThreeDBasics.SetPosition[shape: shape, concat: TRUE]; -- concatenate new rotation shape.vtcesInValid _ TRUE; <> xfmdCtr _ G3dMatrix.Transform[ ctrOfMass^, shape.position ]; -- Evaluate new center of mass newMassLength _ G3dVector.Length[ G3dVector.Sub[xfmdCtr, shape.axisBase] ]; rotationRate _ rotationRate * Sqr[massLength / newMassLength]; <> rotationRate _ rotationRate * RealFns.Power[(endTime - frameNumber * timePerFrame) / endTime, 1.0]; <<>> shape.shadingProps _ PutProp[ -- Update parameters on property list shape.shadingProps, $RollShape, LIST[ NEW[REAL _ rotationRate], NEW[REAL _ timePerFrame], NEW[REAL _ endTime], ctrOfMass ] ]; shadowShape _ SceneUtilities.FindShape[context, "EggShadow"]; shadowShape.location _ G3dVector.Add[ shape.axisBase, [0.0, 0.1, -0.1] ]; ThreeDBasics.SetPosition[shape: shadowShape]; -- set new location under rolling egg shadowShape.vtcesInValid _ TRUE; RETURN[shape]; }; END.