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. „AnimationProcs.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Last Edited by: Crow, February 8, 1988 5:03:07 pm PST Basic Types Renamed Procedures Globals Utility Procedures Procedures for EggRolling Animation PROC[context: REF Context, shape: REF ShapeInstance, data: REF ANY _ NIL] RETURNS[REF ShapeInstance] Rotates and finds minimum height, returns as new base to rotate on compute center of mass based on vertex locations (crude approximation) Get acceleration due to center of mass and base position Get acceleration due to change in length of moment arm Damp rotation rate just to get things to stop eventually Κ£˜Ihead™šœ Οmœ1™Jš œžœžœžœžœ˜5Jš œžœžœžœžœ˜:Jš œ žœžœžœžœ˜:šœ žœ žœžœ˜5Jšžœžœžœžœ˜2—J˜Jšœ,žœ˜1šžœ žœžœ˜J™FJšœ žœ˜*šžœžœžœž˜)Jšœžœ…˜‘J˜5J˜5J˜5Jšžœ˜—J˜0J˜0J˜0J˜—J˜Jšœ= ˜[˜J˜JJ˜—J˜HJ˜Jš 8™8J˜6šžœJ œQ˜«Jšžœ˜—Jšœ9 ˜Pšžœžœžœ˜)M˜2J˜0Jšœ ˜—Jšœ0 ˜MJšœ œ˜Jšœ œ$˜1Jšœ) ˜DJ˜XJšœ5 ˜JJšœ/žœ ˜SJšœžœ˜J™6Jšœ= ˜[J˜KJ˜?J™8J˜kJ™šœ% %˜JJ˜ Jšžœžœžœžœžœžœžœ˜]J˜—J˜J˜=J˜IJšœ0 %˜UJšœžœ˜ J˜Jšžœ˜Jšœ‘˜——Jšžœ˜—…—‚©