<<>> <> <> <> <> <> 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; LightProc: TYPE ~ G3dLight.LightProc; LightRep: TYPE ~ G3dLight.LightRep; LightSequence: TYPE ~ G3dLight.LightSequence; LightSequenceRep: TYPE ~ G3dLight.LightSequenceRep; <> Error: PUBLIC SIGNAL [code: ATOM, reason: ROPE] = CODE; <> <> <<>> DefaultIllumination: LightProc ~ { d: REAL ¬ G3dVector.Length[G3dVector.Sub[position, light.position]]; strength: REAL ¬ RealFns.Power[(light.radius-d)/light.radius, light.exponent]; RETURN[[light.color.R*strength, light.color.G*strength, light.color.B*strength]]; }; <> <<>> 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]]; }; <> AddLight: PUBLIC PROC [ lights: LightSequence, name: ROPE, position, direction: Triple, color: RGB ¬ [1,1,1], eyeView: Triple ¬ []] RETURNS [LightSequence] ~ { light: Light ¬ NEW[LightRep]; -- make new light of given type light.name ¬ name; light.position ¬ position; light.color ¬ color; light.direction ¬ direction; 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]; }; LengthenLightSequence: PUBLIC PROC [lights: LightSequence] RETURNS [new: LightSequence] ~ { newLength: NAT ¬ MAX[Real.Round[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; }; 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; }; <> PrepareLight: PUBLIC PROC [light: Light, eyeView: Triple] ~ { <> indexOfRefraction: REAL ~ 200.0; specularCharacteristic: REAL ~ 0.35; r, rSubQ, rAddQ, qrAddQ, qrSubQ, q: REAL; light.position ¬ G3dVector.Unit[light.position]; -- keep to unit sphere, for user interaction 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; IF light.lightProc = NIL THEN light.lightProc ¬ DefaultIllumination; }; PrepareLights: PUBLIC PROC [lights: LightSequence, eyeView: Triple] RETURNS [LightSequence] ~ { IF lights = NIL THEN lights ¬ AddLight[NIL, "Light1", [200.0, 100.0, 100.0], [1.0, 0.0, 0.0]]; FOR n: NAT IN [0..lights.length) DO PrepareLight[lights[n], eyeView]; ENDLOOP; RETURN[lights]; }; <> registeredLights: PropList ¬ NIL; -- registered lights RegisterLight: PUBLIC PROC [light: Light, type: ATOM] ~ { registeredLights ¬ Atom.PutPropOnList[registeredLights, type, NEW[LightRep ¬ light­]]; }; GetRegisteredLight: PUBLIC PROC [type: ATOM] RETURNS [light: Light] ~ { ref: Light ¬ NARROW[Atom.GetPropFromList[registeredLights, type]]; IF ref # NIL THEN light ¬ NEW[LightRep ¬ ref­] ELSE Error[$Unimplemented, "Unregistered light type"]; }; InitDefaultLightClasses: PUBLIC PROC ~ { defaultLight: Light ¬ NEW[LightRep]; defaultLight.lightProc ¬ DefaultIllumination; RegisterLight[defaultLight, $Default]; }; <> 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.PutFLR["\t%g: pos: [%g, %g, %g]", LIST[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[]; }; <> InitDefaultLightClasses[]; <<>> END.