DIRECTORY Atom, CedarProcess, Commander, G3dBasic, G3dMappedAndSolidTexture, G3dMatrix, G3dRender, G3dRenderWithPixels, G3dShadeClipXfm, G3dShape, G3dSortandDisplay, G3dView, ImagerColorFns, ImagerColorMap, IO, NamedColors, Real, Rope, RuntimeError, SafeStorage, ViewerOps; G3dRenderImpl: CEDAR MONITOR IMPORTS Atom, CedarProcess, Commander, G3dMappedAndSolidTexture, G3dMatrix, G3dRender, G3dRenderWithPixels, G3dShadeClipXfm, G3dShape, G3dSortandDisplay, G3dView, ImagerColorFns, ImagerColorMap, NamedColors, Rope, RuntimeError, SafeStorage, ViewerOps EXPORTS G3dRender ~ BEGIN Error: PUBLIC SIGNAL [code: ATOM, reason: ROPE] = CODE; PropList: TYPE ~ Atom.PropList; STREAM: TYPE ~ IO.STREAM; ROPE: TYPE ~ Rope.ROPE; Process: TYPE ~ CedarProcess.Process; NatSequence: TYPE ~ G3dBasic.NatSequence; NatSequenceRep: TYPE ~ G3dBasic.NatSequenceRep; PairSequence: TYPE ~ G3dBasic.PairSequence; TripleSequence: TYPE ~ G3dBasic.TripleSequence; RGB: TYPE ~ G3dRender.RGB; Pair: TYPE ~ G3dBasic.Pair; Triple: TYPE ~ G3dBasic.Triple; Quad: TYPE ~ G3dBasic.Quad; -- RECORD [x, y, z, w: REAL]; Matrix: TYPE ~ G3dMatrix.Matrix; -- REF 4 by 4 ARRAY OF REAL SampleMap: TYPE ~ G3dRender.SampleMap; PixelMap: TYPE ~ G3dRender.PixelMap; Box: TYPE ~ G3dRender.Box; -- [min, max: Pair] Rectangle: TYPE ~ G3dRender.Rectangle; -- RECORD [x, y, w, h: REAL] NatTable: TYPE ~ G3dBasic.NatTable; NatTableRep: TYPE ~ G3dBasic.NatTableRep; TextureFunction: TYPE ~ G3dRender.TextureFunction; TextureMap: TYPE ~ G3dRender.TextureMap; SummedTexture: TYPE ~ G3dRender.SummedTexture; TextureStyle: TYPE ~ G3dRender.TextureStyle; TextureInfo: TYPE ~ G3dRender.TextureInfo; CtlPoint: TYPE ~ G3dRender.CtlPoint; Shape: TYPE ~ G3dShape.Shape; ShapeRep: TYPE ~ G3dShape.ShapeRep; ShapeSequence: TYPE ~ G3dShape.ShapeSequence; ShapeSequenceRep: TYPE ~ G3dShape.ShapeSequenceRep; Vertex: TYPE ~ G3dShape.Vertex; VertexRep: TYPE ~ G3dShape.VertexRep; VertexSequenceRep: TYPE ~ G3dShape.VertexSequenceRep; PatchSequence: TYPE ~ G3dRender.PatchSequence; ShapeClass: TYPE ~ G3dRender.ShapeClass; ShadingClass: TYPE ~ G3dRender.ShadingClass; ShapeProc: TYPE ~ G3dRender.ShapeProc; RenderStyle: TYPE ~ G3dRender.RenderStyle; Context: TYPE ~ G3dRender.Context; ContextRep: TYPE ~ G3dRender.ContextRep; ContextClass: TYPE ~ G3dRender.ContextClass; RenderData: TYPE ~ G3dRender.RenderData; DisplayMode: TYPE ~ G3dRender.DisplayMode; Transform: PROC [p: Triple, mat: Matrix] RETURNS [Triple] ~ G3dMatrix.Transform; TransformVec: PROC [vec: Triple, mat: Matrix] RETURNS [Triple] ~ G3dMatrix.TransformVec; GetProp: PROC [propList: PropList, prop: REF ANY] RETURNS [REF ANY] ~ Atom.GetPropFromList; PutProp: PROC [propList: PropList, prop: REF ANY, val: REF ANY] RETURNS [PropList] ~ Atom.PutPropOnList; registeredDisplayTypes: PropList _ NIL; -- keeps active display types registeredSurfaceTypes: PropList _ NIL; -- keeps active surface types registeredShadingClasses: PropList _ NIL; -- keeps active shading classes RegisterDisplayClass: PUBLIC PROC [class: ContextClass, type: ATOM] ~ { registeredDisplayTypes _ PutProp[registeredDisplayTypes, type, NEW[ContextClass _ class]]; }; GetDisplayClass: PUBLIC PROC [type: ATOM] RETURNS [class: ContextClass] ~ { refClass: REF ContextClass _ NARROW[GetProp[registeredDisplayTypes, type]]; IF refClass # NIL THEN class _ refClass^ ELSE G3dRender.Error[$Unimplemented, "Unregistered display type"] }; LoadDisplayClass: PUBLIC PROC [context: Context, type: ATOM] ~ { class: REF ContextClass _ NARROW[GetProp[registeredDisplayTypes, type]]; IF class = NIL THEN G3dRender.Error[$Unimplemented, "Unregistered display type"]; context.class _ NEW[ContextClass _ class^]; context.pixels _ NIL; --this and next line for saving VM context.displayProps _ Atom.RemPropFromList[context.displayProps, $FullDisplayMemory]; context.class.setUpDisplayType[context]; -- maps in pixels, sets up color map IF GetProp[context.props, $BufferContext] # NIL THEN { G3dRender.Error[$Warning, "Dropping Buffer context"]; -- insufficient info to update context.props _ Atom.RemPropFromList[context.props, $BufferContext]; }; WITH GetProp[context.props, $BackGround] SELECT FROM backGrdCtx: Context => { G3dRender.Error[$Warning, "Dropping BackGround context"]; -- no info for update context.props _ Atom.RemPropFromList[context.props, $BackGround]; }; ENDCASE; }; RegisterShapeClass: PUBLIC PROC [class: ShapeClass, type: ATOM] ~ { registeredSurfaceTypes _ PutProp[registeredSurfaceTypes, type, NEW[ShapeClass _ class]]; }; GetShapeClass: PUBLIC PROC [type: ATOM] RETURNS [class: ShapeClass] ~ { refClass: REF ShapeClass _ NARROW[GetProp[registeredSurfaceTypes, type]]; IF refClass # NIL THEN class _ refClass^ ELSE G3dRender.Error[$Unimplemented, "Unregistered surface type"]; }; LoadShapeClass: PUBLIC PROC [shape: Shape, type: ATOM _ $ConvexPolygon] ~{ shapeClass: REF ShapeClass; class: REF ShapeClass _ NARROW[GetProp[registeredSurfaceTypes, type]]; IF class = NIL THEN G3dRender.Error[$Unimplemented, "Unregistered surface type"]; shapeClass _ ShapeClassFrom[shape]; IF shapeClass = NIL THEN shapeClass _ NEW[ShapeClass _ class^] ELSE { -- inherit previous procedures if no replacements new: REF ShapeClass _ NEW[ShapeClass _ class^]; IF new.validate = NIL THEN new.validate _ shapeClass.validate; IF new.display = NIL THEN new.display _ shapeClass.display; IF new.displayPatch = NIL THEN new.displayPatch _ shapeClass.displayPatch; IF new.doBeforeFrame = NIL THEN new.doBeforeFrame _ shapeClass.doBeforeFrame; shapeClass _ new; }; IF ShadingClassFrom[shape] = NIL THEN LoadShadingClass[shape]; -- load default class shape.renderValid _ FALSE; -- in case we're changing the type on an existing shape shape.screenValid _ FALSE; shape.props _ Atom.RemPropFromList[shape.props, $LinesList]; -- list may not be valid }; RegisterShadingClass: PUBLIC PROC [class: ShadingClass, type: ATOM] ~ { registeredShadingClasses _ PutProp[registeredShadingClasses, type, NEW[ShadingClass _class]]; }; GetShadingClass: PUBLIC PROC [type: ATOM] RETURNS [class: ShadingClass] ~ { ref: REF ShadingClass _ NARROW[GetProp[registeredShadingClasses, type]]; IF ref # NIL THEN class _ ref^ ELSE G3dRender.Error[$Unimplemented, "Unregistered shading class"]; }; LoadShadingClass: PUBLIC PROC [shape: Shape, type: ATOM _ $Default ] ~ { shadingClass: REF ShadingClass; class: REF ShadingClass _ NARROW[GetProp[registeredShadingClasses, type]]; IF class = NIL THEN G3dRender.Error[$Unimplemented, "Unregistered shading class"]; shadingClass _ ShadingClassFrom[shape]; IF shadingClass = NIL THEN shadingClass _ NEW[ShadingClass _ class^] ELSE { new: REF ShadingClass _ NEW[ShadingClass _ class^]; IF new.renderMethod = NIL THEN new.renderMethod _ shadingClass.renderMethod; new.color _ shadingClass.color; new.shininess _ shadingClass.shininess; new.transmittance _ shadingClass.transmittance; IF new.texture = NIL THEN new.texture _ shadingClass.texture; new.textureScale _ shadingClass.textureScale; new.bumpScale _ shadingClass.bumpScale; IF new.cnvrtVtx = NIL THEN new.cnvrtVtx _ shadingClass.cnvrtVtx; IF new.getColor = NIL THEN new.getColor _ shadingClass.getColor; IF new.shadeVtx = NIL THEN new.shadeVtx _ shadingClass.shadeVtx; shadingClass _ new; }; NARROW[shape.renderData, REF RenderData].shadingProps _ NIL; -- WHY??? }; InitStandardShapeClasses: PROC[] ~ { -- register procedures for basic surface types standardClass: ShapeClass _ [ type: $Light, display: NIL, displayPatch: NIL ]; defaultShadingClass: ShadingClass _ [ -- procs for standard shading (no texture) type: $Default, renderMethod: $Faceted, shadeVtx: G3dShadeClipXfm.ShadeVtx ]; G3dRender.RegisterShapeClass[standardClass, $Light]; -- placeholder class for light source standardClass.type _ $ConvexPolygon; standardClass.validate _ G3dSortandDisplay.ValidatePolyhedron; standardClass.displayPatch _ G3dSortandDisplay.OutputPolygon; G3dRender.RegisterShapeClass[standardClass, $ConvexPolygon]; -- ConvexPolygon procs standardClass.type _ $RopeShape; standardClass.validate _ G3dSortandDisplay.ValidateRopeShape; standardClass.displayPatch _ G3dSortandDisplay.RopeDisplay; G3dRender.RegisterShapeClass[standardClass, $RopeShape]; -- RopeShape procs G3dRender.RegisterShadingClass[defaultShadingClass, $Default]; defaultShadingClass.type _ $NoShading; defaultShadingClass.renderMethod _ $Faceted; defaultShadingClass.shadeVtx _ G3dShadeClipXfm.NoShadeVtx; G3dRender.RegisterShadingClass[defaultShadingClass, $NoShading]; }; Create: PUBLIC PROC [] RETURNS [Context] ~ { context: Context _ NEW[ContextRep]; wDir: ROPE _ Commander.PrependWorkingDir[" "]; -- add needed space (wierdness) wDir _ Rope.Substr[base: wDir, len: Rope.Length[wDir] - 1]; -- drop space context.props _ PutProp[context.props, $WDir, wDir]; -- keep directory context.eyeSpaceXfm _ G3dMatrix.Identity[]; -- can't do this in initialization, so do it here context.stopMe _ NEW[BOOLEAN _ FALSE]; RETURN[context]; }; InitializeRawColorDisplayContext: PUBLIC PROC [ antiAliasing: BOOL _ TRUE, background: RGB _ [0.2, 0.2, 0.7], displayMode: DisplayMode _ gray] RETURNS [context: Context] ~ { context _ Create[]; context.preferredRenderMode _ $Pixels; LoadDisplayClass[context, AtomFromDisplayMode[displayMode]]; G3dRenderWithPixels.BufferRendering[context, FALSE]; -- , displayType = $FullColor]; SetAntiAliasing[context, antiAliasing]; SetBackgroundColor[context, background]; AddLight[context, "Light0", [-100.0, -200.0, 20.0]]; SetView[context, [3.0, -10.0, 3.0], []]; }; CloseDisplay: PUBLIC PROC [context: Context] ~ { context.pixels _ NIL; -- throw away buffer bits context.displayProps _ Atom.RemPropFromList[context.displayProps, $FullDisplayMemory]; ImagerColorMap.SetStandardColorMap[context.terminal -- restore standard color map ! RuntimeError.BoundsFault => CONTINUE]; }; CloseColorViewers: PUBLIC PROC ~ { EnumProc: ViewerOps.EnumProc ~ { IF v.column = color THEN { ViewerOps.CloseViewer[v]; ViewerOps.ChangeColumn[v, left]; }; }; ViewerOps.EnumerateViewers[EnumProc]; }; KillUntitledColorViewers: PUBLIC PROC ~ { EnumProc: ViewerOps.EnumProc ~ { IF v.column = color AND v.name = NIL THEN ViewerOps.DestroyViewer[v]; }; ViewerOps.EnumerateViewers[EnumProc]; }; GetTmpContext: PUBLIC PROC [srcCtx: REF Context] RETURNS[dstCtx: REF Context] ~ { dstCtx _ ThreeDBasics.Create[]; CopyContextData[dstCtx, srcCtx]; dstCtx.pixels _ srcCtx.pixels; }; CopyContextData: PUBLIC PROC [dstCtx, srcCtx: REF Context] ~ { dstCtx.class _ IF srcCtx.class # NIL THEN NEW[ ContextClass _ srcCtx.class^ ] ELSE NIL; dstCtx.stopMe _ srcCtx.stopMe; -- inheriting REF so Stop signals will propagate dstCtx.frameNumber _ srcCtx.frameNumber; dstCtx.shapes _ srcCtx.shapes; dstCtx.visibleShapes _ srcCtx.visibleShapes; dstCtx.lightSources _ srcCtx.lightSources; dstCtx.environment _ srcCtx.environment; dstCtx.viewInValid _ srcCtx.viewInValid; dstCtx.eyePoint _ srcCtx.eyePoint; dstCtx.ptOfInterest _ srcCtx.ptOfInterest; dstCtx.rollAngle _ srcCtx.rollAngle; dstCtx.upDirection _ srcCtx.upDirection; dstCtx.fieldOfView _ srcCtx.fieldOfView; dstCtx.window _ srcCtx.window; dstCtx.hitherLimit _ srcCtx.hitherLimit; dstCtx.yonLimit _ srcCtx.yonLimit; dstCtx.clippingPlanes _ srcCtx.clippingPlanes; dstCtx.eyeSpaceXfm _ srcCtx.eyeSpaceXfm; dstCtx.eyeToNdc _ srcCtx.eyeToNdc; dstCtx.ndcToPixels _ srcCtx.ndcToPixels; IF srcCtx.viewer # NIL THEN { dstCtx.viewer _ NEW[ViewerClasses.ViewerRec _ srcCtx.viewer^]; FOR list: Atom.PropList _ srcCtx.viewer.props, list.rest UNTIL list = NIL DO -- new proplist element: Atom.DottedPair _ NEW[Atom.DottedPairNode _ list.first^]; dstCtx.viewer.props _ CONS[element, dstCtx.viewer.props]; ENDLOOP; dstCtx.viewer.props _ PutProp[ dstCtx.viewer.props, $Context3D, dstCtx ]; }; dstCtx.terminal _ srcCtx.terminal; dstCtx.displayInValid _ srcCtx.displayInValid; dstCtx.viewPort _ IF srcCtx.viewPort # NIL THEN NEW[ Imager.Rectangle _ srcCtx.viewPort^] ELSE NIL; dstCtx.preferredViewPort _ srcCtx.preferredViewPort; dstCtx.extentCovered _ srcCtx.extentCovered; dstCtx.preferredRenderMode _ srcCtx.preferredRenderMode; dstCtx.displayProps _ NIL; FOR list: Atom.PropList _ srcCtx.displayProps, list.rest UNTIL list = NIL DO -- new proplist element: Atom.DottedPair _ NEW[Atom.DottedPairNode _ list.first^]; dstCtx.displayProps _ CONS[element, dstCtx.displayProps]; ENDLOOP; dstCtx.autoRedraw _ srcCtx.autoRedraw; dstCtx.delayClear _ srcCtx.delayClear; dstCtx.doVisibly _ srcCtx.doVisibly; dstCtx.antiAliasing _ srcCtx.antiAliasing; dstCtx.depthBuffering _ srcCtx.depthBuffering; dstCtx.depthResolution _ srcCtx.depthResolution; dstCtx.sortSequence _ srcCtx.sortSequence; dstCtx.props _ NIL; FOR list: Atom.PropList _ srcCtx.props, list.rest UNTIL list = NIL DO -- make new proplist element: Atom.DottedPair _ NEW[Atom.DottedPairNode _ list.first^]; dstCtx.props _ CONS[element, dstCtx.props]; ENDLOOP; }; CopyContextShapes: PUBLIC PROC [dstCtx, srcCtx: REF Context] ~ { dstCtx.shapes _ NEW[ ShapeSequence[srcCtx.shapes.length] ]; FOR i: NAT IN [0..srcCtx.shapes.length) DO dstCtx.shapes[i] _ NEW[ ShapeInstance _ srcCtx.shapes[i]^ ]; dstCtx.shapes[i].shadingClass _ NEW[ ShadingClass _ srcCtx.shapes[i].shadingClass^ ]; ENDLOOP; dstCtx.shapes.length _ srcCtx.shapes.length; }; SetViewFromParameters: PUBLIC PROC [ context: Context, fieldOfView: REAL _ 40.0, scale: REAL _ 1.0, moves, rotates: Triple _ []] ~ { fov: REAL _ IF fieldOfView = 0.0 THEN 40.0 ELSE fieldOfView; eyePoint, lookAt, upDirection: Triple; [eyePoint, lookAt, upDirection] _ G3dView.FromScaleMovesRots[scale, moves, rotates]; SetView[context, eyePoint, lookAt, fov, 0.0, upDirection]; }; SetView: PUBLIC PROC [ context: Context, eyePoint: Triple, lookAt: Triple, fieldOfView: REAL _ 40.0, rollAngle: REAL _ 0.0, upDirection: Triple _ [0., 0., 1.], hitherLimit: REAL _ .01, yonLimit: REAL _ 1000.0] ~ { context.eyePoint _ eyePoint; context.lookAt _ lookAt; context.fieldOfView _ fieldOfView; context.rollAngle _ rollAngle; context.upDirection _ upDirection; context.hitherLimit _ hitherLimit; context.yonLimit _ yonLimit; context.changed _ TRUE; }; SetViewPort: PUBLIC PROC [context: Context, size: Rectangle] ~{ IF size.w <= 0.0 OR size.h <= 0.0 THEN SIGNAL Error[$MisMatch, "Null rectangle"]; context.preferredViewPort _ size; context.viewPort _ NIL; -- computed by ValidateView GetViewportFromViewer context.window _ NIL; -- resizing viewport forces update of window context.displayInValid _ TRUE; }; SetAmbientLight: PUBLIC PROC [context: Context, rgb: RGB] ~ { IF context # NIL THEN { ref: REF RGB _ NEW[RGB _ rgb]; context.environment _ PutProp[context.environment, $AmbientLight, ref]; context.changed _ TRUE; }; }; NameAmbientLight: PUBLIC PROC [context: Context, color: ROPE] ~ { clr: RGB _ ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[color]]; SetAmbientLight[context, clr]; }; GetAmbientLight: PUBLIC PROC [context: Context] RETURNS [rgb: RGB] ~ { IF context # NIL THEN { refAny: REF ANY _ GetProp[context.environment, $AmbientLight]; rgb _ IF refAny = NIL THEN [0.0, 0.0, 0.0] ELSE NARROW[refAny, REF RGB]^; }; }; AddLight: PUBLIC PROC [context: Context, name: ROPE, position: Triple, color: RGB _ [1,1,1]] ~ { light: Shape _ FindShape[context, name]; IF light = NIL THEN { light _ NEW [ShapeRep]; -- name not used before, make new light light.name _ name; LoadShapeClass[light, $Light]; -- load light class structures AddShape[context, light]; }; light.position _ position; light.sphereExtent _ [ center: [0.0, 0.0, 0.0], radius: 2 * 93000000.0 * 1609.344 -- twice solar distance in meters ]; ShadingClassFrom[light].color _ color; light.props _ PutProp[light.props, $Hidden, $ok]; -- hide from display routines G3dShape.ComputeMatrix[light]; -- make sure matrix is valid context.changed _ TRUE; }; DeleteLight: PUBLIC PROC [context: Context, name: ROPE] ~ { DeleteShape[context, name]; context.changed _ TRUE; }; NameBackgroundColor: PUBLIC PROC [context: Context, color: ROPE] ~ { bkgrdColor: RGB _ ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[color]]; SetBackgroundColor[context, bkgrdColor]; -- set color }; SetBackgroundColor: PUBLIC PROC [context: Context, color: RGB] ~ { context.props _ PutProp[context.props, $BackGround, NEW[RGB _ color]]; }; GetBackgroundColor: PUBLIC PROC [context: Context] RETURNS [rgb: RGB] ~ { WITH GetProp[context.props, $BackGround] SELECT FROM x: REF RGB => rgb _ x^; ENDCASE; }; SetBackgroundImage: PUBLIC PROC [context: Context, aisFile: ROPE] ~ { bkGrdCtx: Context _ Create[]; bkGrdCtx.depthBuffering _ context.depthBuffering; bkGrdCtx.antiAliasing _ context.antiAliasing; bkGrdCtx.class _ context.class; bkGrdCtx.props _ PutProp[bkGrdCtx.props, $BackGrdImage, aisFile]; SetBackgroundContext[context, bkGrdCtx]; }; GetBackgroundImage: PUBLIC PROC [context: Context] RETURNS [r: ROPE _ NIL] ~ { WITH GetProp[context.props, $BackGround] SELECT FROM bkGrdCtx: Context => { name: REF ANY _ GetProp[bkGrdCtx.props, $BackGrdImage]; IF name # NIL THEN r _ NARROW[name]; }; ENDCASE; }; SetBackgroundContext: PUBLIC PROC [context, bkGrdCtx: Context] ~ { context.props _ PutProp[context.props, $BackGround, bkGrdCtx]; }; KillBackground: PUBLIC PROC [context: Context] ~ { context.props _ Atom.RemPropFromList[context.props, $BackGround]; }; AddShape: PUBLIC PROC [context: Context, shape: Shape] ~ { IF shape = NIL THEN RETURN; DeleteShape[context, shape.name ! G3dRender.Error => CONTINUE]; context.shapes _ G3dShape.AddToShapeSequence[context.shapes, shape]; }; AddShapeFromFile: PUBLIC PROC [ context: Context, shapeName: ROPE, fileName: ROPE, position: Triple _ [0., 0., 0.]] ~ { shape, cloneShape: Shape _ NIL; fileName _ PrependWorkingDirectory[context, fileName]; IF context.shapes # NIL THEN FOR i: NAT IN [0..context.shapes.length) DO IF Rope.Equal[shape.fileName, context.shapes[i].fileName] -- same data as another shape? THEN cloneShape _ context.shapes[i]; ENDLOOP; IF cloneShape # NIL -- save data reads if previously read THEN G3dShape.CloneShape[shape, cloneShape] ELSE shape _ G3dShape.ShapeFromFile[fileName]; shape.name _ shapeName; shape.fileName _ fileName; AddShape[context, shape]; G3dShape.TransformShape[shape: shape, translate: position]; }; FindShape: PUBLIC PROC [context: Context, shapeName: ROPE] RETURNS [shape: Shape _ NIL] ~ { IF context # NIL THEN shape _ G3dShape.FindShape[context.shapes, shapeName ! G3dShape.Error => CONTINUE]; }; ShapeFromRope: PUBLIC PROC [ name: ROPE _ NIL, message: ROPE, color: ROPE _ NIL, size: REAL _ 0.5, font: ROPE _ NIL] RETURNS [Shape] ~ { shape: Shape _ NEW[ShapeRep]; renderData: REF RenderData _ NEW[RenderData]; renderData.fixedProps _ PutProp[renderData.fixedProps, $RopeMessage, message]; renderData.fixedProps _ PutProp[renderData.fixedProps, $RopeFont, font]; shape.renderData _ renderData; LoadShapeClass[shape, $RopeShape]; LoadShadingClass[shape, $NoShading]; renderData.shadingClass.color _ ImagerColorFns.RGBFromHSL[NamedColors.RopeToHSL[color]]; shape.vertices _ NEW[VertexSequenceRep[2]]; shape.vertices[0] _ NEW[VertexRep]; shape.vertices[1] _ NEW[VertexRep]; shape.vertices[1].point.z _ size; shape.vertices.length _ 2; shape.surfaces _ NEW[NatTableRep[1]]; shape.surfaces[0] _ NEW[NatSequenceRep[3]]; shape.surfaces[0][0] _ shape.surfaces[0][2] _ 0; shape.surfaces[0][1] _ 1; shape.surfaces.length _ 1; RETURN[shape]; }; ChangeRopeMessage: PUBLIC PROC [context: Context, shapeName: ROPE, newMessage: ROPE] ~ { shape: Shape _ FindShape[context, shapeName]; NARROW[shape.renderData, REF RenderData].fixedProps _ PutProp[ NARROW[shape.renderData, REF RenderData].fixedProps, $RopeMessage, newMessage ]; }; DeleteShape: PUBLIC PROC [context: Context, shapeName: ROPE] ~ { found: BOOL _ FALSE; IF context.shapes = NIL THEN { SIGNAL G3dRender.Error[$MisMatch, "No shapes to delete from"]; RETURN[]; }; FOR i: NAT IN [0..context.shapes.length) DO IF found THEN context.shapes[i] _ context.shapes[i+1] ELSE { found _ Rope.Equal[shapeName, context.shapes[i].name, FALSE]; IF found THEN { context.shapes[i] _ context.shapes[i+1]; context.shapes.length _ context.shapes.length - 1; }; }; ENDLOOP; IF NOT found THEN G3dRender.Error[ $MisMatch, Rope.Cat["Can't delete", shapeName, "- not there"] ]; }; DeleteAllShapes: PUBLIC PROC [context: Context] ~ { IF context # NIL THEN FOR n: NAT IN [0..context.shapes.length) DO IF NARROW[context.shapes[n].renderData, REF RenderData].class.type # $Light THEN DeleteShape[context, context.shapes[n].name ! G3dRender.Error => CONTINUE]; ENDLOOP; }; SetRenderStyle: PUBLIC PROC [shape: Shape, renderStyle: RenderStyle] ~ { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade # NIL THEN shade.renderMethod _ NEW[RenderStyle _ renderStyle]; }; SetColor: PUBLIC PROC [shape: Shape, color: RGB] ~ { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade # NIL THEN shade.color _ color; }; SetShininess: PUBLIC PROC [shape: Shape, shininess: REAL] ~ { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade # NIL THEN shade.shininess _ shininess; }; SetTransmittance: PUBLIC PROC [shape: Shape, transmittance: REAL] ~ { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade # NIL THEN shade.transmittance _ transmittance; }; SetInvisible: PUBLIC PROC [shape: Shape] ~ { NARROW[shape.renderData, REF RenderData].props _ PutProp[ NARROW[shape.renderData, REF RenderData].props, $Hidden, $ok ]; }; SetVisible: PUBLIC PROC [shape: Shape] ~ { NARROW[shape.renderData, REF RenderData].props _ Atom.RemPropFromList[ NARROW[shape.renderData, REF RenderData].props, $Hidden ]; }; ShowBackfaces: PUBLIC PROC [shape: Shape] ~ { IF shape # NIL THEN shape.showBackfaces _ TRUE; }; HideBackfaces: PUBLIC PROC [shape: Shape] ~ { IF shape # NIL THEN shape.showBackfaces _ FALSE; }; RenderDataFrom: PUBLIC PROC [shape: Shape] RETURNS [REF RenderData] ~ { data: REF RenderData; IF shape.renderData = NIL THEN shape.renderData _ NEW[RenderData]; data _ NARROW[shape.renderData]; RETURN[data]; }; ShapeClassFrom: PUBLIC PROC [shape: Shape] RETURNS [REF ShapeClass] ~ { data: REF RenderData _ RenderDataFrom[shape]; IF data.class = NIL THEN data.class _ NEW[ShapeClass]; RETURN[data.class]; }; ShadingClassFrom: PUBLIC PROC [shape: Shape] RETURNS [REF ShadingClass] ~ { data: REF RenderData _ RenderDataFrom[shape]; IF data.shadingClass = NIL THEN data.shadingClass _ NEW[ShadingClass]; RETURN[data.shadingClass]; }; PatchesFrom: PUBLIC PROC [shape: Shape] RETURNS [PatchSequence] ~ { data: REF RenderData _ RenderDataFrom[shape]; RETURN[data.patch]; }; SetTextureMap: PUBLIC PROC [ context: Context, shapeName: ROPE, aisName: ROPE, textureStyle: TextureStyle _ intensity, textureFiltering: BOOL _ FALSE] RETURNS [error: ROPE] ~ { a: ATOM ~ AtomFromTextureStyle[textureStyle]; IF shapeName = NIL THEN RETURN; IF textureStyle = none THEN G3dMappedAndSolidTexture.RemoveAllTexture[context, shapeName] ELSE IF aisName # NIL THEN { ENABLE G3dRender.Error => {error _ reason; CONTINUE}; m: REF TextureMap _ G3dMappedAndSolidTexture.TextureFromAIS[context, aisName, a]; shape: Shape _ FindShape[context, shapeName]; IF shape # NIL THEN SetTextureRange[shape, [1000., 1000.]]; G3dMappedAndSolidTexture.AddMappedTexture[context, shapeName, m]; IF textureFiltering THEN G3dMappedAndSolidTexture.SumAllMappedTextures[context, shapeName]; }; }; OffsetTextureCoords: PUBLIC PROC [shape: Shape, offset: Pair] ~ { ps: PairSequence _ NARROW[GetProp[ NARROW[shape.renderData, REF RenderData].shadingProps, $AuxiliaryVtxData ]]; FOR i: NAT IN [0..ps.length) DO p: Pair _ ps[i]; ps[i] _ [p.x+offset.x, p.y+offset.y]; ENDLOOP; }; GetTexture: PUBLIC PROC [shape: Shape] RETURNS [PairSequence] ~ { RETURN[NARROW[GetProp[ NARROW[shape.renderData, REF RenderData].shadingProps, $AuxiliaryVtxData ]]]; }; GetTextureInfo: PUBLIC PROC [s: Shape] RETURNS [textureInfo: LIST OF TextureInfo] ~ { filtered: BOOL _ FALSE; IF s = NIL OR ShadingClassFrom[s] = NIL THEN RETURN; FOR l: LIST OF REF ANY _ ShadingClassFrom[s].texture, l.rest WHILE l # NIL DO WITH l.first SELECT FROM texture: REF G3dRender.TextureMap => { ref: REF ANY _ GetProp[texture.props, $FileName]; name: ROPE _ IF ref # NIL THEN NARROW[ref] ELSE NIL; type: TextureStyle _ SELECT texture.type FROM $Intensity => intensity, $Color => color, $Bump => bump, ENDCASE => none; WITH texture.pixels SELECT FROM x: PixelMap => filtered _ FALSE; x: REF G3dRender.SummedTexture => filtered _ TRUE; ENDCASE; textureInfo _ CONS[[name, type, filtered], textureInfo]; }; txtrFn: REF TextureFunction => -- solid or other function-based texture textureInfo _ CONS[[NIL, function, FALSE], textureInfo]; ENDCASE; ENDLOOP; }; ScaleTexture: PUBLIC PROC [context: Context, shape: Shape, scale: Pair] ~ { G3dMappedAndSolidTexture.ScaleTxtrCoords[context, shape.name, 1.0, scale.x, scale.y]; }; GetTextureScale: PUBLIC PROC [shape: Shape] RETURNS [scale: Pair _ [1.0, 1.0]] ~ { IF shape # NIL THEN { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade # NIL THEN scale _ shade.textureScale; }; }; SetTextureScale: PUBLIC PROC [shape: Shape, scale: Pair _ [1.0, 1.0]] ~ { IF shape # NIL THEN { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade # NIL THEN shade.textureScale _ scale; }; }; SetTextureRange: PUBLIC PROC [shape: Shape, textureRange: Pair] ~ { IF shape # NIL THEN NARROW[shape.renderData, REF RenderData].shadingProps _ PutProp[ NARROW[shape.renderData, REF RenderData].shadingProps, $TxtrCoordRange, NEW[Pair _ textureRange] ]; }; SetTextureFiltering: PUBLIC PROC [context: Context, shape: Shape, on: BOOL] ~ { IF shape # NIL THEN { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade.texture = NIL THEN RETURN; IF on THEN G3dMappedAndSolidTexture.SumAllMappedTextures[context, shape.name] ELSE FOR l: LIST OF TextureInfo _ GetTextureInfo[shape], l.rest WHILE l # NIL DO [] _ SetTextureMap[context, shape.name, l.first.name, l.first.type]; ENDLOOP; }; }; GetBumpScale: PUBLIC PROC [shape: Shape] RETURNS [scale: REAL _ 1.0] ~ { IF shape # NIL THEN { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade # NIL THEN scale _ shade.bumpScale; }; }; SetBumpScale: PUBLIC PROC [shape: Shape, scale: REAL _ 1.0] ~ { IF shape # NIL THEN { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade # NIL THEN shade.bumpScale _ scale; }; }; renderDone: CONDITION; Render: PUBLIC PROC [context: Context, fork: BOOL _ TRUE] ~ { IF fork THEN { process: Process _ CedarProcess.Fork[ReallyRender, context, [background, TRUE]]; context.props _ PutProp[context.props, $Process, process]; } ELSE [] _ ReallyRender[context]; }; WaitTilRenderDone: PUBLIC ENTRY PROC ~ { ENABLE UNWIND => NULL; WAIT renderDone; }; NotRendering: PUBLIC PROC [context: Context] RETURNS [b: BOOL] ~ { process: Process _ NARROW[GetProp[context.props, $Process]]; RETURN[process = NIL OR CedarProcess.GetStatus[process] # busy]; }; BroadcastRenderDone: ENTRY PROC ~ { BROADCAST renderDone; }; ReallyRender: CedarProcess.ForkableProc ~ { context: Context _ NARROW[data]; context.class.render[context ! ABORTED => CONTINUE]; BroadcastRenderDone[]; }; AbortRender: PUBLIC PROC [context: Context] ~ { IF context # NIL THEN context.stopMe^ _ TRUE; }; GetDisplayMode: PUBLIC PROC [context: Context] RETURNS [DisplayMode] ~ { RETURN[SELECT context.class.displayType FROM $PseudoColor => dither, $Gray => gray, ENDCASE => fullColor]; }; SetAntiAliasing: PUBLIC PROC [context: Context, on: BOOL _ TRUE] ~ { G3dRenderWithPixels.AntiAliasing[context, on]; }; AntiAliasingNeeded: PUBLIC PROC [context: Context] RETURNS [BOOL] ~ { FOR n: NAT IN [0..context.shapes.length) DO FOR l: LIST OF TextureInfo _ GetTextureInfo[context.shapes[n]], l.rest WHILE l #NIL DO IF l.first.type = bump OR l.first.type = function THEN RETURN[TRUE]; ENDLOOP; IF ShadingClassFrom[context.shapes[n]].transmittance > 0.0 THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; GetBuffer: PUBLIC PROC [context: Context, type: ATOM] RETURNS [sm: SampleMap _ NIL] ~ { r: REF _ GetProp[context.displayProps, type]; IF r # NIL AND context.pixels # NIL THEN sm _ context.pixels[NARROW[r, REF NAT]^] }; GetAlphaBuffer: PUBLIC PROC [context: Context] RETURNS [SampleMap] ~ { RETURN[GetBuffer[context, $Alpha]]; }; GetDepthBuffer: PUBLIC PROC [context: Context] RETURNS [SampleMap] ~ { RETURN[GetBuffer[context, $Depth]]; }; Sqr: PROCEDURE [number: REAL] RETURNS [REAL] ~ INLINE {RETURN[number*number]; }; GetRenderData: PROCEDURE [context: Context, shapeName: ROPE] RETURNS [REF RenderData] ~ { data: REF RenderData _ NIL; IF context # NIL THEN { shape: Shape _ FindShape[context, shapeName]; IF shape # NIL THEN IF shape.renderData # NIL THEN data _ NARROW[ shape.renderData ! SafeStorage.NarrowRefFault => CONTINUE ]; }; RETURN[data]; }; PrependWorkingDirectory: PUBLIC PROC [context: Context, file: ROPE] RETURNS [ROPE]~{ wDir: ROPE _ NARROW[GetProp[context.props, $WDir]]; IF wDir = NIL THEN RETURN[file] ELSE IF file = NIL OR (Rope.Index[s1: file, s2: "/"] > 0 AND Rope.Index[s1: file, s2: "["] > 0) THEN file _ Rope.Cat[wDir, file]; -- if first char not / or [then prepend wDir RETURN[file]; }; TackOnExtension: PUBLIC PROC[file, extension: ROPE] RETURNS[ROPE] ~ { cp: FS.ComponentPositions; fullFName, fName: ROPE; [fullFName, cp, ] _ FS.ExpandName[file]; IF cp.ext.length = 0 THEN { fName _ Rope.Substr[ fullFName, 0, cp.ext.start]; RETURN[ Rope.Cat[fName, ".", extension] ]; } ELSE RETURN[ file ]; }; IntersectRectangles: PUBLIC PROC [rect1, rect2: Rectangle] RETURNS [Rectangle] ~ { intersection: Rectangle; intersection.x _ MAX[rect1.x, rect2.x]; intersection.y _ MAX[rect1.y, rect2.y]; intersection.w _ MIN[rect1.w - (intersection.x - rect1.x), rect2.w - (intersection.x - rect2.x)]; intersection.h _ MIN[rect1.h - (intersection.y - rect1.y), rect2.h - (intersection.y - rect2.y)]; RETURN [intersection]; }; AtomFromTextureStyle: PUBLIC PROC [textureStyle: TextureStyle] RETURNS [a: ATOM] ~ { a _ SELECT textureStyle FROM bump => $Bump, color => $Color, ENDCASE => $Intensity; }; AtomFromDisplayMode: PUBLIC PROC [displayMode: DisplayMode] RETURNS [a: ATOM] ~ { a _ SELECT displayMode FROM fullColor=>$FullColor, dither=>$PseudoColor, ENDCASE=>$Gray; }; RopeFromDisplayMode: PUBLIC PROC [displayMode: DisplayMode] RETURNS [ROPE] ~ { RETURN[SELECT displayMode FROM gray => "Gray", dither => "Dither", fullColor => "FullColor", ENDCASE => NIL]; }; RopeFromRenderStyle: PUBLIC PROC [renderStyle: RenderStyle] RETURNS [ROPE] ~ { RETURN[SELECT renderStyle FROM faceted => "Faceted", smooth => "Smooth", lines => "Lines", shadedLines => "ShadedLines", hiddenLines => "HiddenLines", ENDCASE => NIL]; }; RopeFromTextureStyle: PUBLIC PROC [textureStyle: TextureStyle] RETURNS [ROPE] ~ { RETURN[SELECT textureStyle FROM intensity => "Intensity", color => "Color", bump => "Bump", ENDCASE => "None"]; }; InitStandardShapeClasses[]; END. G3dRenderImpl.mesa Copyright Σ 1985, 1989 by Xerox Corporation. All rights reserved. Bloomenthal, April 15, 1989 4:50:32 pm PDT Heckbert, August 9, 1988 4:50:32 pm PDT Crow, April 20, 1989 11:17:53 pm PDT Errors Types Miscellaneous Types Imported Sequences Pixel Definitions Geometric Definitions Image Definitions Polygon Definitions Texture Definitions Control Point Definitions Shape Definitions Context Definition Renamed Procedures Global Variables Class Registration and Installation Context copies context so temporary modifications can be made Don't copy pixels, some uses want their own View Lighting Background Set background color using color naming scheme Set background color Return the background for context. Use named AIS file as background image for scene instead of solid color Return the name of the background image (NIL if none). Use named 3d context as background image for scene (contexts may be stacked arbitrarily). Remove the background, images will be rendered with no background. Use for images to be matted over others using alpha channel Shapes Build dummy patch structure to pass through ShapeUtilities.ShapePatchToPatch Return the shapeClass for this shape. Return the shadingClass for this shape. Get shape.renderData.patch, the patch-by-patch description, of the surface, conveniently. Textures Kill current texture map (if any) before adding new one, so only one texture at a time. G3dMappedAndSolidTexture.RemoveAllTexture[context, shapeName]; Disable the bizarre uv wraparound code in G3dMappedAndSolidTexture.AdjustTexture: ScaleTexture: PUBLIC PROC [shape: Shape, scale: Pair] ~ { textures: PairSequence _ GetTexture[shape]; IF textures # NIL THEN { FOR n: NAT IN [0..textures.length) DO texture: Pair _ textures[n]; textures[n] _ [texture.x*scale.x, texture.y*scale.y]; ENDLOOP; SceneUtilities.SetTexture[shape, textures]; }; }; Rendering Control If providing management alpha and depth buffers for three-d compositing: SurfaceRender.ShowShapes[context ! ABORTED => CONTINUE]; This will draw images using the alpha buffer; all texture and transparency are enabled. Determine if anti-aliasing is needed to render the shapes in their respective shading modes. For example, anti-aliasing is necessary for bump-mapping, transparency, solid texture. Local Utilities and Miscellany Κ#Ϊ˜™JšœB™BJšœ'Οk™*Icodešœ$™'Kšœ$™$J˜Jš œΖœ@˜‘J˜—šΡbln œœ˜Jšœσ˜ϊJšœ ˜J˜—Jšœ˜headšΟl™Jš œ œœœ œœ˜;—šŸ™šŸ™Jšœ œ˜"Jšœœœœ˜Jšœœœ˜Jšœ œ˜(—šŸ™Jšœœ˜+Jšœœ˜0Jšœœ˜,Jšœœ˜0—šŸ™Jšœœ œ˜—šŸ™Jšœ œ˜Jšœ œ˜"Jšœ œΟcΠcs ‘ ˜AJšœ œ ‘˜D—šŸ™Jšœ œ˜(Jšœ œ˜'JšΟtœœ ’ Πct ˜5Jš œœ ’œ ’£‘ ‘ ˜G—šŸ™Jšœ œ˜&Jšœœ˜+—šΠblŸ ™Jšœœ˜2Jšœœ˜*Jšœœ˜/Jšœœ˜.Jšœœ˜,—š€™Jšœ œ˜'—š€™Jšœ œ˜!Jšœ œ˜&Jšœœ˜.Jšœœ˜3Jšœ œ˜"Jšœ œ˜'Jšœœ˜5Jšœœ˜/Jšœœ˜*Jšœœ˜2Jšœ œ˜(Jšœœ˜,—š€™Jšœ œ˜%Jšœœ˜*Jšœœ˜.Jšœœ˜*Jšœœ˜+——š€™šΟn œœœ ˜PJ˜—š₯ œœœ#˜XJ˜—š₯œΟsœ ¦œ ¦œ¦¦œ¦¦œ¦œ˜CJšœ˜J˜—š₯œœœœœœœ ˜RJšœ˜——š€™Idefaultšœ$œ ˜HMšœ$œ ˜HMšœ%œ ˜K—šŸ#™#š₯œœœœ˜GJšœ?œ˜[M˜—š ₯œœœœœ˜KMšœ œœ(˜Kšœ œ˜Mšœ˜Mšœ=˜A—M˜—š₯œœœœ˜@Mšœœœ(˜HMšœ œœ>˜QJšœœ˜+Jšœœ  "˜AJ˜WJšœ+ $˜Ošœ*œœ˜6Mšœ7 ˜UM˜DM˜—šœ%œ˜4šœ˜Mšœ: ˜OM˜AM˜—Mšœ˜—M˜—š₯œœœœ˜CJšœ?œ˜YM˜—š ₯ œœœœœ˜GMšœ œœ(˜Išœ œ˜Mšœ˜Mšœ>˜B—M˜—š₯œœœœ˜JMšœ œ ˜Mšœœœ(˜FMšœ œœ>˜QJšœ#˜#šœœ˜Jšœœ˜*šœ 1˜Jšœœœ"˜;Jšœœœ,˜JJšœœœ.˜MJšœ˜J˜——Jšœœœ ˜TMšœœ 7˜SJšœœ˜Jšœ> ˜VM˜—š₯œœœœ˜GJš œ¦œ¦œ!¦œ¦œ ¦œ ˜]J˜—š ₯œœœœœ˜KMšœœœ*˜Hšœœ˜ Mšœ˜Mšœ?˜C—M˜—š₯œœœœ˜HMšœœ˜Mšœœœ*˜JMšœ œœ?˜RJšœ'˜'šœœ˜Jšœœ˜.šœ˜Jšœœœ˜3Jšœœœ.˜LJšœ˜Jšœ'˜'Jšœ/˜/Jšœœœ$˜=Jšœ-˜-Jšœ'˜'Jšœœœ&˜@Jšœœœ&˜@Jšœœœ&˜@Jšœ˜J˜——Mšœœœ  ˜GM˜—š₯œœ .˜T˜J˜Jšœ œ˜ Jšœ˜J˜—ašœ' *˜QJ˜J˜J˜"J˜—Jšœ5 %˜ZJ˜$J˜>J˜=Jšœ= ˜TJ˜ J˜=J˜;Jšœ9 œ˜LM˜>J˜&J˜,Jšœ:˜:M˜@J˜——šŸ™š₯œœœœ˜,Jšœœ˜$Jšœœ& ˜OJšœ?  ˜LJšœ5 ˜FMšœ, 1˜]Mšœœœœ˜&Mšœ ˜M˜—š₯ œœœ˜/Jšœœœ˜Jšœ œ˜"J˜ Jšœ˜J˜J˜N˜&Jšœ<˜Nš œœœœœ!œœ˜XNšœ! 0œ˜RN˜(N˜N˜,N˜*N˜)N˜(N˜"N˜*N˜$N˜(N˜(N˜N˜(N˜"N˜.N˜(N˜"N˜)šœœœ˜Nšœœ+˜>š œ6œœœ ˜\Jšœœ$˜BJšœœ˜9Jšœ˜—M˜IJ˜—N˜"N˜.N™+Nš œœœœœ5œœ˜rN˜4N˜,N˜8Jšœœ˜š œ6œœœ ˜\Jšœœ$˜BJšœœ˜9Jšœ˜ —N˜&N˜&N˜$N˜*N˜.N˜0N˜+Jšœœ˜š œ/œœœ ˜ZJšœœ$˜BJšœœ˜+Jšœ˜—N˜—š₯œœœœ ˜@Jšœœ)˜<šœœœœ˜+Jšœœ&˜šœœ ˜Kšœ˜Kšœœ œœ˜—K˜—K˜—š₯œ¦¦¦œ ¦œ¦œ¦œ¦œ ¦œ¦œ¦¦œ¦œ ˜`Jšœ(˜(šœ œœ˜Jšœœ '˜BJšœ˜Jšœ$ ˜BJ˜J˜—J˜šœ˜Jšœ˜Jšœ" !˜CJ˜—J˜&Nšœ2 ˜OJšœ$ ˜@Jšœœ˜J˜J˜—š₯ œœœœ˜;J˜Jšœœ˜J˜——šŸ ™ š₯œ œœ˜DJ™.Jšœ œ<˜KJšœ)  ˜5J˜—š₯œœœœ˜BJ™Jšœ4œœ ˜FJ˜J˜—š ₯œœœœœ˜IJ™"šœ%œ˜4Kšœœœ ˜Kšœ˜—J˜J˜—š₯œœœœ˜EJšœ œ:™GJšœ˜J˜1J˜-J˜J˜AK˜(K˜—š ₯œœœœœœ˜NJšœ)¦œ ™6šœ%œ˜4šœ˜Jšœœœ*˜7Jšœœœœ˜$J˜—Jšœ˜—J˜J˜—š₯œ œ!˜BJ™YJ˜>K˜—š₯œœœ˜2J™J˜AK˜J™——šŸ™š₯œœœ%˜:Jšœ œœœ˜Jšœ5œ˜?J˜DJšœ₯˜—š₯œ œ˜Jšœ˜Jšœ œ˜Jšœ œ˜Jšœ ˜ J˜Jšœœ˜Jšœ6˜6š œœœœœœ˜Hšœ9 ˜YJšœ ˜$—Jšœ˜—šœœ %˜@Jšœ'˜+Jšœ*˜.—Jšœ˜J˜J˜Jšœ;˜;J˜J˜—š₯ œœœœ˜:Jšœœ˜J˜šœ œ˜JšœIœ˜S—J˜J˜—š₯ œ œ˜Jšœœœ˜Jšœ œ˜Jšœœœ˜Jšœœ˜Jšœœœ˜Jšœ ˜Jšœœ ˜Jšœ œœ ˜-J˜NJ˜HJšœ˜Jšœ"˜"J˜$šœX˜XJ™L—Jšœœ˜-Jšœœ ˜$Jšœœ1˜HJšœ˜Mšœœ˜&Jšœœ˜+JšœK˜KJšœ˜Jšœ˜J˜—š₯œ¦¦¦œ ¦œ¦œ ¦œ¦œ ¦œ˜TJšœ¦œ˜Jšœ-˜-šœœ"˜>Jšœœ2˜NJ˜—J˜—š₯ œœœœ˜@Jšœœœ˜šœœœ˜Jšœ8˜>Jšœ˜ J˜—š œœœœœ˜5Jšœ(˜,šœ˜Jšœ6œ˜=šœœ˜J˜(J˜2J˜—J˜—Jšœ˜—šœœœ˜"Jšœ=˜=Jšœ˜—J˜J˜—š₯œœœ˜3šœ œ˜šœœœœ˜-šœœœ ˜KJšœBœ˜P—Jšœ˜——J˜J˜—š₯œœœ-˜HJšœœ(˜2Jšœ œœœ˜HJ˜J˜—š₯œœœœ˜4Jšœœ(˜2Jšœ œœ˜(J˜J™—š § œ¦¦œœ˜=Jšœœ(˜2Jšœ œœ˜0˜J˜——š₯œœœœ˜EJšœœ(˜2Jšœ œœ%˜8J˜J˜—š₯ œœœ˜,šœœ˜9Nšœœ ˜™>šœ˜Jšœ>˜Bšœœ œœ˜Jšœ%œ˜5JšœœK˜QJšœ-˜-JšœQ™QJšœ œœ(˜;JšœA˜Ašœ˜JšœC˜G—J˜——J˜J˜—š₯œœœ!˜Ašœœ ˜"Mšœœ˜7Mšœ˜Mšœ˜—šœœœœ˜ M˜M˜%Mšœ˜—M˜M˜—š₯ œœœœ˜Ašœœ ˜Jšœœ˜7Jšœ˜Jšœ˜—J˜J˜—š ₯œœœ œœœ˜UJšœ œœ˜Jš œœœœœœ˜4šœœœœœ'œœ˜Mšœ œ˜šœ œ˜&Jšœœœ%˜1Jšœœœœœœœœ˜4šœœ˜-J˜J˜J˜Jšœ ˜—šœœ˜Jšœœ˜ Jšœœ'œ˜2Jšœ˜—Jšœœ&˜8J˜—šœœ (˜KJšœœœ œ˜8—Jšœ˜ —Jšœ˜—J˜J˜—š₯ œœœ2˜KJšœU˜UJ˜J˜—š₯ œœœ ™9J™+šœ œœ™šœœœ™%J™J™5Jšœ™—J™+J™—J™J™—š₯œœœœ˜Ršœ œœ˜Jšœœ(˜2Jšœ œœ˜/J˜—J˜J˜—š₯œœœ-˜Išœ œœ˜Jšœœ(˜2Jšœ œœ˜/J˜—J˜J˜—š₯œœœ'˜Cš œ œœœœ$˜TJšœœ˜7Jšœœ˜)Jšœ˜—J˜J˜—š₯œœœ&œ˜Ošœ œœ˜Jšœœ(˜2Jšœœœœ˜#šœ˜JšœC˜Gš œœœœ-œœ˜PJšœD˜DJšœ˜——J˜—J˜J˜—š ₯ œœœœ œ ˜Hšœ œœ˜Jšœœ(˜2Jšœ œœ˜,J˜—J˜J˜—š₯ œœœœ ˜?šœ œœ˜Jšœœ(˜2Jšœ œœ˜,J˜—J˜——šŸ™šœ  œ˜J˜—š ₯œœœœœ˜=šœ˜šœ˜JšœIœ˜PJšœ:˜:J˜—Jšœ˜ —J˜J˜—š₯œœœœ˜(Jšœœœ˜Jšœ ˜J˜J˜—š ₯ œœœœœ˜BJšœœ#˜