DIRECTORY Atom, G3dBasic, G3dLight, G3dVector, IO, Real, RealFns, Rope, TiogaOps, ViewerClasses, ViewerOps, ViewerTools; G3dLightImpl: CEDAR PROGRAM IMPORTS Atom, G3dVector, IO, Real, RealFns, Rope, TiogaOps, ViewerOps, ViewerTools EXPORTS G3dLight ~ BEGIN RGB: TYPE ~ G3dLight.RGB; ROPE: TYPE ~ Rope.ROPE; PropList: TYPE ~ Atom.PropList; Triple: TYPE ~ G3dBasic.Triple; Light: TYPE ~ G3dLight.Light; LightRep: TYPE ~ G3dLight.LightRep; LightSequence: TYPE ~ G3dLight.LightSequence; LightSequenceRep: TYPE ~ G3dLight.LightSequenceRep; IlluminationProc: TYPE ~ PROC [light: Light, position: Triple] RETURNS [color: RGB]; Error: PUBLIC SIGNAL [code: ATOM, reason: ROPE] = CODE; PointSource: TYPE ~ REF PointSourceRep; PointSourceRep: TYPE ~ RECORD [ radius: REAL _ 2.0 * 93000000.0 * 1609.344, -- 2x solar distance in meters (fc) exponent: REAL _ 2.0 ]; DefaultIllumination: IlluminationProc ~ { d: REAL _ G3dVector.Length[G3dVector.Sub[position, light.position]]; ps: PointSource _ NARROW[light.privateData]; strength: REAL _ RealFns.Power[(ps.radius-d)/ps.radius, ps.exponent]; RETURN[[light.color.R * strength, light.color.G * strength, light.color.B * strength]]; }; PrepareLights: PUBLIC PROC [lights: LightSequence, eyeView: Triple] RETURNS [LightSequence] ~ { IF lights = NIL THEN lights _ AddToLightSequence[NIL, NEW[LightRep _ [name: "Light1"]]]; FOR n: NAT IN [0..lights.length) DO PrepareLight[lights[n], eyeView]; ENDLOOP; RETURN[lights]; }; PrepareLight: PUBLIC PROC [light: Light, eyeView: Triple] ~ { indexOfRefraction: REAL ~ 200.0; specularCharacteristic: REAL ~ 0.35; r, rSubQ, rAddQ, qrAddQ, qrSubQ, q: REAL; light.direction _ G3dVector.Unit[light.direction]; light.highlight _ G3dVector.Unit[G3dVector.Add[eyeView, light.direction]]; q _ light.eDotH _ G3dVector.Dot[eyeView, light.direction]; r _ RealFns.SqRt[indexOfRefraction*indexOfRefraction+q*q-1.0]; rSubQ _ r-light.eDotH; rAddQ _ r+light.eDotH; qrAddQ _ light.eDotH*rAddQ-1.0; qrSubQ _ light.eDotH*rSubQ+1.0; light.f _ ((rSubQ*rSubQ)/(rAddQ*rAddQ))*(1.0+(qrAddQ*qrAddQ)/(qrSubQ*qrSubQ)); light.a _ 1.0/(specularCharacteristic*specularCharacteristic-1.0); light.b _ light.a+1.0; }; LightDots: PUBLIC PROC [light: Light, normal, eyeView: Triple] RETURNS [nDotE, nDotH, nDotL: REAL] ~ { nDotE _ -G3dVector.Dot[normal, eyeView]; -- want direction to, not from eye nDotH _ G3dVector.Dot[normal, light.highlight]; nDotL _ G3dVector.Dot[normal, light.direction]; }; SpecularFromDots: PUBLIC PROC [light: Light, nDotE, nDotH, nDotL: REAL] RETURNS [REAL] ~ { g: REAL _ IF nDotE < nDotL THEN IF 2.0*nDotE*nDotH < light.eDotH THEN 2.0*nDotH/light.eDotH ELSE 1.0/nDotE ELSE IF 2.0*nDotL*nDotH < light.eDotH THEN 2.0*nDotH*nDotL/(light.eDotH*nDotE) ELSE 1.0/nDotE; t: REAL _ light.b/(nDotH*nDotH+light.a); d: REAL _ t*t; RETURN[MAX[0.0, d*g*light.f]]; }; LengthenLightSequence: PUBLIC PROC [lights: LightSequence] RETURNS [new: LightSequence] ~ { newLength: NAT _ MAX[Real.InlineRoundI[1.3*lights.length], 3]; new _ NEW[LightSequenceRep[newLength]]; FOR i: NAT IN [0..lights.length) DO new[i] _ lights[i]; ENDLOOP; new.length _ lights.length; }; AddToLightSequence: PUBLIC PROC [ lights: LightSequence, light: Light, eyeView: Triple _ []] RETURNS [LightSequence] ~ { IF eyeView # [] THEN PrepareLight[light, eyeView]; IF lights = NIL THEN lights _ NEW[LightSequenceRep[1]]; FOR n: NAT IN [0..lights.length) DO IF NOT Rope.Equal[lights[n].name, light.name, FALSE] THEN LOOP; lights[n] _ light; EXIT; REPEAT FINISHED => { IF lights.length = lights.maxLength THEN lights _ LengthenLightSequence[lights]; lights[lights.length] _ light; lights.length _ lights.length+1; }; ENDLOOP; RETURN[lights]; }; DeleteLight: PUBLIC PROC [lights: LightSequence, name: ROPE] ~ { n: INTEGER _ -1; IF lights = NIL THEN RETURN; FOR i: NAT IN [0..lights.length) DO IF Rope.Equal[lights[i].name, name, FALSE] THEN {n _ i; EXIT}; ENDLOOP; IF n = -1 THEN RETURN; FOR nn: INT IN [n..lights.length-1) DO lights[nn] _ lights[nn+1]; ENDLOOP; lights.length _ lights.length-1; }; registeredLightTypes: PropList _ NIL; -- active lights RegisterLightType: PUBLIC PROC [light: Light, type: ATOM] ~ { registeredLightTypes _ Atom.PutPropOnList[ registeredLightTypes, type, NEW[LightRep _ light^] ]; }; InitStandardLightClasses: PUBLIC PROC ~ { -- register procedures for basic light types defaultLight: Light _ NEW[LightRep _ [ -- procs for standard lighting type: $Default, illuminationProc: DefaultIllumination ]]; defaultLight.privateData _ NEW[PointSourceRep]; RegisterLightType[defaultLight, $Default]; }; GetLightType: PUBLIC PROC [type: ATOM] RETURNS [light: Light] ~ { ref: Light _ NARROW[Atom.GetPropFromList[registeredLightTypes, type]]; IF ref # NIL THEN light _ NEW[LightRep _ ref^] ELSE Error[$Unimplemented, "Unregistered light type"]; }; RopeFromLights: PUBLIC PROC [lights: LightSequence] RETURNS [r: ROPE] ~ { r _ "Lights: \n"; IF lights # NIL THEN FOR n: NAT IN [0..lights.length) DO l: Light _ lights[n]; r _ Rope.Concat[r, IO.PutFR["\t%g: pos: [%g, %g, %g]", IO.rope[l.name], IO.real[l.position.x], IO.real[l.position.y], IO.real[l.position.z]]]; r _ Rope.Concat[r, IO.PutFR[" color: [%g, %g, %g]", IO.real[l.color.R], IO.real[l.color.G], IO.real[l.color.B]]]; r _ Rope.Concat[r, "\n"]; ENDLOOP; }; AnnotateLightsToViewer: PUBLIC PROC [lights: LightSequence, viewerName: ROPE] ~ { GetViewer: PROC RETURNS [v: ViewerClasses.Viewer] ~ { IF (v _ ViewerOps.FindViewer[viewerName]) # NIL THEN RETURN; v _ ViewerTools.MakeNewTextViewer[[name:viewerName, file:viewerName, column:right]]; ViewerOps.OpenIcon[v]; }; v: ViewerClasses.Viewer _ GetViewer[]; lastLoc: TiogaOps.Location _ TiogaOps.LastLocWithin[TiogaOps.ViewerDoc[v]]; TiogaOps.SetSelection[v, lastLoc, lastLoc]; TiogaOps.SetLooks["b"]; TiogaOps.InsertRope["Lights:"]; TiogaOps.Break[]; TiogaOps.Nest[]; IF lights # NIL THEN FOR n: NAT IN [0..lights.length) DO l: Light _ lights[n]; TiogaOps.SetLooks["b"]; TiogaOps.InsertRope[l.name]; TiogaOps.SetLooks[" "]; TiogaOps.InsertRope[IO.PutFR[": pos: (%g, %g, %g)", IO.real[l.position.x], IO.real[l.position.y], IO.real[l.position.z]]]; TiogaOps.InsertRope[IO.PutFR[" color: [%g, %g, %g]", IO.real[l.color.R], IO.real[l.color.G], IO.real[l.color.B]]]; TiogaOps.Break[]; ENDLOOP; TiogaOps.UnNest[]; }; InitStandardLightClasses[]; END. ÒG3dLightImpl.mesa Copyright c 1988 by Xerox Corporation. All rights reserved. Bloomenthal, July 21, 1989 3:13:08 pm PDT Glassner, January 23, 1989 9:34:54 am PST Crow, May 16, 1989 6:28:52 pm PDT Imported Types Errors Example Lighting Procs IlluminationProc: TYPE ~ PROC [light: Light, position: Triple] RETURNS [color: RGB]; Lighting From Blinn: Models of Light Reflection for Computer Synthesized Pictures, Siggraph '77. Registration Miscellany Start Code Êݘ™Jšœ Ïmœ1™J˜J˜J˜J˜J˜NJ˜BJ˜J˜J˜—š¡ œžœžœ(˜>Jšžœžœ˜#J˜Jšœ)¢"˜KJ˜/J˜/J˜J˜—š¡œžœžœ%žœ˜GJšžœžœ˜J˜šœžœžœ˜šžœžœ˜%Jšžœ˜Jšžœ ˜—šžœžœ˜%Jšžœ$˜(Jšžœ ˜——Jšœžœ!˜(Jšœžœ˜Jšžœžœ˜J˜J˜—š¡œžœžœ˜:Kšžœ˜ Kšœ žœžœ*˜>Jšœžœ˜'Jš žœžœžœžœžœ˜@J˜K˜K˜—š¡œžœžœ˜!Kšœ˜Kšœ ˜ Kšœ˜Kšžœ˜K˜Kšžœžœ˜2Kšžœ žœžœ žœ˜7šžœžœžœž˜#Kš žœžœ(žœžœžœ˜?K˜Kšžœ˜Kšž˜šžœ˜ Kšžœ"žœ(˜PK˜K˜ K˜—Kšžœ˜—Kšžœ ˜K˜K˜—š¡ œžœžœžœ˜@Kšœžœ˜Kšžœ žœžœžœ˜šžœžœžœž˜#Kšžœ"žœžœ žœ˜>Kšžœ˜—Jšžœžœžœ˜Jš žœžœžœžœžœ˜JJ˜ K˜——š  ™ Mšœ!žœ¢˜8M˜š¡œžœžœžœ˜=šœÏsœ£œ˜*Jšœ£œ£žœ £œ ˜2Jšœ˜—J˜—š¡œžœžœ¢,˜Vašœžœ¢˜FJ˜Jšœ%˜%J˜—Jšœžœ˜/Mšœ*˜*Mšœ˜M˜—š ¡ œžœžœžœžœ˜AMšœ žœ3˜Fšžœžœ˜ Mšžœ žœ˜"Mšžœ2˜6—M˜——š  ™ š ¡œžœžœžœžœ˜IJ˜šžœ žœž˜šžœžœžœž˜#J˜šœžœ!˜6Jšžœžœžœžœ˜W—šœžœ˜3Jšžœžœžœ˜=—Jšœ˜Jšžœ˜——K˜K˜—š¡œž œ%žœ˜Qš¡ œžœžœ˜5Jšžœ*žœžœžœ˜