DIRECTORY Atom, BasicTime, CedarProcess, Commander, Convert, FS, G3dBasic, G3dColorDisplaySupport, G3dMappedAndSolidTexture, G3dMatrix, G3dLight, G3dRender, G3dRenderWithPixels, G3dShade, G3dShape, G3dSortandDisplay, G3dVector, G3dView, ImagerColorFns, ImagerColorMap, IO, NamedColors, Real, Rope, RuntimeError, SafeStorage, ViewerClasses, ViewerIO, ViewerOps; G3dRenderImpl: CEDAR MONITOR IMPORTS Atom, BasicTime, CedarProcess, Commander, Convert, FS, G3dColorDisplaySupport, G3dMappedAndSolidTexture, G3dLight, G3dMatrix, G3dRenderWithPixels, G3dShade, G3dShape, G3dSortandDisplay, G3dVector, G3dView, ImagerColorFns, ImagerColorMap, IO, NamedColors, Real, Rope, RuntimeError, SafeStorage, ViewerIO, 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; Light: TYPE ~ G3dLight.Light; LightRep: TYPE ~ G3dLight.LightRep; NatSequence: TYPE ~ G3dBasic.NatSequence; NatSequenceRep: TYPE ~ G3dBasic.NatSequenceRep; PairSequence: TYPE ~ G3dBasic.PairSequence; TripleSequence: TYPE ~ G3dBasic.TripleSequence; LightSequence: TYPE ~ G3dLight.LightSequence; 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] SurfaceSequence: TYPE ~ G3dBasic.SurfaceSequence; SurfaceSequenceRep: TYPE ~ G3dBasic.SurfaceSequenceRep; 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 Error[$Unimplemented, "Unregistered display type"] }; LoadDisplayClass: PUBLIC PROC [context: Context, type: ATOM] ~ { class: REF ContextClass _ NARROW[GetProp[registeredDisplayTypes, type]]; IF class = NIL THEN 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 { 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 => { 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 Error[$Unimplemented, "Unregistered surface type"]; }; LoadShapeClass: PUBLIC PROC [shape: Shape, type: ATOM] ~{ renderData: REF RenderData; class: REF ShapeClass _ NARROW[GetProp[registeredSurfaceTypes, type]]; IF class = NIL THEN Error[$Unimplemented, "Unregistered surface type"]; renderData _ RenderDataFrom[shape]; IF renderData.class = NIL THEN renderData.class _ NEW[ShapeClass _ class^] ELSE { -- inherit previous procedures if no replacements new: REF ShapeClass _ NEW[ShapeClass _ class^]; IF new.validate = NIL THEN new.validate _ renderData.class.validate; IF new.display = NIL THEN new.display _ renderData.class.display; IF new.displayPatch = NIL THEN new.displayPatch _ renderData.class.displayPatch; IF new.doBeforeFrame = NIL THEN new.doBeforeFrame _ renderData.class.doBeforeFrame; renderData.class _ new; }; IF ShadingClassFrom[shape] = NIL THEN G3dShade.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 shape.type _ type; }; InitStandardShapeClasses: PROC[] ~ { -- register procedures for basic surface types standardClass: ShapeClass _ [ type: $Light, validate: G3dSortandDisplay.DummyValidate, display: NIL, displayPatch: NIL ]; RegisterShapeClass[standardClass, $Light]; -- placeholder class for light source standardClass.type _ $ConvexPolygon; standardClass.validate _ G3dSortandDisplay.ValidatePolyhedron; standardClass.displayPatch _ G3dSortandDisplay.OutputPolygon; RegisterShapeClass[standardClass, $ConvexPolygon]; -- ConvexPolygon procs standardClass.type _ $RopeShape; standardClass.displayPatch _ G3dSortandDisplay.RopeDisplay; RegisterShapeClass[standardClass, $RopeShape]; -- RopeShape procs }; 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]; }; CreateUndisplayedContext: PUBLIC PROC [ oldContext: Context _ NIL, width: NAT _ 1024, height: NAT _ 768, displayMode: DisplayMode _ fullColor, keepLog: BOOLEAN _ FALSE ] RETURNS [context: Context] ~ { context _ Create[]; context.preferredRenderMode _ $Pixels; IF oldContext # NIL THEN CopyContextData[context, oldContext]; context.viewer _ NIL; context.viewPort _ NEW[ -- set viewport directly to define pixelMap size Rectangle _ [ x: 0.0, y: 0.0, w: Real.Float[width], h: Real.Float[height] ] ]; context.preferredViewPort _ context.viewPort^; SELECT displayMode FROM gray => LoadDisplayClass[context, $GrayInVM]; dither => LoadDisplayClass[context, $PseudoColorInVM]; fullColor => LoadDisplayClass[context, $FullColorInVM]; ENDCASE; -- can't get here without type error IF keepLog THEN [] _ StartLog[context]; context.changed _ TRUE; -- ensure screen coordinates get updated IF oldContext = NIL THEN SetBackgroundColor[context, [0.2, 0.2, 0.7]]; }; 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]]; -- Jules' desired defaults SetView[context, [0.0, -10.0, 0.0], []]; }; StoreImage: PUBLIC PROC [ context: Context, fileName: ROPE, sequenceNo: NAT _ LAST[NAT], log: BOOL _ FALSE, abekasFormat: BOOL _ FALSE] ~ { cp: FS.ComponentPositions; fullFName: ROPE; IF log OR sequenceNo # LAST[NAT] THEN { out: STREAM _ FS.StreamOpen[ fileName: GetLogFileName[PrependWorkingDirectory[context, fileName]], accessOptions: $append, wDir: NARROW[GetProp[context.props, $WDir] ] ]; IO.PutRope[out, Rope.Cat[ " Frame no. ", Convert.RopeFromInt[sequenceNo], " written at ", Convert.RopeFromTime[from: BasicTime.Now[], start: months, end: seconds], "\n"]]; IO.Close[out]; }; [fullFName, cp] _ FS.ExpandName[fileName]; IF abekasFormat THEN fullFName _ Rope.Replace[fullFName, cp.ext.start, cp.ext.length, "rgb"] ELSE IF Rope.Equal[Rope.Substr[fullFName, cp.ext.start, cp.ext.length], "rgb", FALSE] THEN abekasFormat _ TRUE; fileName _ PrependWorkingDirectory[context, fileName]; IF sequenceNo # LAST[NAT] THEN fileName _ PasteInSequenceNo[fileName, sequenceNo]; IF abekasFormat THEN G3dColorDisplaySupport.PutRGB[context, fileName] ELSE G3dColorDisplaySupport.PutAIS[context, fileName]; }; 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: Context] RETURNS[dstCtx: Context] ~ { dstCtx _ Create[]; CopyContextData[dstCtx, srcCtx]; dstCtx.pixels _ srcCtx.pixels; }; CopyContextData: PUBLIC PROC [dstCtx, srcCtx: 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.changed _ srcCtx.changed; dstCtx.eyePoint _ srcCtx.eyePoint; dstCtx.lookAt _ srcCtx.lookAt; 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[ Rectangle _ srcCtx.viewPort^] ELSE NIL; dstCtx.preferredViewPort _ srcCtx.preferredViewPort; dstCtx.screenExtent _ srcCtx.screenExtent; 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: Context] ~ { dstCtx.shapes _ NEW[ ShapeSequenceRep[srcCtx.shapes.length] ]; FOR i: NAT IN [0..srcCtx.shapes.length) DO dstCtx.shapes[i] _ NEW[ ShapeRep _ srcCtx.shapes[i]^ ]; RenderDataFrom[dstCtx.shapes[i]].shadingClass _ NEW[ ShadingClass _ RenderDataFrom[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; }; SetWindow: PUBLIC PROC[context: Context, size: Rectangle] ~{ context.window _ NEW[ Rectangle _ size ]; context.changed _ 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], type: ATOM _ $Default] ~ { light: Light; light _ G3dLight.GetLightType[type]; -- make new light of given type light.name _ name; light.position _ position; light.color _ color; context.lightSources _ G3dLight.AddToLightSequence[context.lightSources, light]; context.changed _ TRUE; }; DeleteLight: PUBLIC PROC [context: Context, name: ROPE] ~ { G3dLight.DeleteLight[context.lightSources, name]; context.changed _ TRUE; }; DeleteAllLights: PUBLIC PROC [context: Context] ~ { context.lightSources.length _ 0; }; LightsFromContext: PUBLIC PROC [context: Context] RETURNS [l: LightSequence] ~ { RETURN[context.lightSources]; }; LightsToContext: PUBLIC PROC [lights: LightSequence, context: Context] ~ { context.lightSources _ lights; }; 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]; }; EnableClear: PUBLIC PROC [context: Context, on: BOOL] ~ { IF on THEN context.props _ Atom.RemPropFromList[context.props, $DisableClear] ELSE context.props _ Atom.PutPropOnList[context.props, $DisableClear, $DoIt]; }; DontMatteBackground: PUBLIC PROC [context: Context] ~ { context.props _ Atom.RemPropFromList[context.props, $BackGround]; }; AddShape: PUBLIC PROC [context: Context, shape: Shape] ~ { IF shape = NIL THEN RETURN; IF shape.renderData = NIL THEN shape.renderData _ NEW[RenderData]; -- JB DeleteShape[context, shape.name ! Error => CONTINUE]; context.shapes _ G3dShape.AddToShapeSequence[context.shapes, shape]; }; AddShapeFromFile: PUBLIC PROC [ context: Context, shapeName: ROPE, fileName: ROPE, position: Triple _ [0., 0., 0.]] ~ { shape, copyShape: Shape _ NIL; fileName _ PrependWorkingDirectory[context, fileName]; IF context.shapes # NIL THEN FOR i: NAT IN [0..context.shapes.length) DO IF Rope.Equal[fileName, context.shapes[i].fileName] -- same data as another shape? THEN copyShape _ context.shapes[i]; ENDLOOP; IF copyShape # NIL -- save data reads if previously read THEN shape _ G3dShape.CopyShape[copyShape] 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]; IF shape = NIL THEN SIGNAL Error[$MisMatch, Rope.Cat[shapeName, " - not found"]]; }; ShapeFromRope: PUBLIC PROC [ name: ROPE _ NIL, message: ROPE, color: ROPE _ NIL, size: REAL _ 0.5, font: ROPE _ NIL] RETURNS [Shape] ~ { shape: Shape _ NEW[ShapeRep _ [name: name, matrix: G3dMatrix.Identity[]]]; renderData: REF RenderData _ NEW[RenderData]; renderData.props _ PutProp[renderData.props, $RopeMessage, message]; renderData.props _ PutProp[renderData.props, $RopeFont, font]; shape.renderData _ renderData; LoadShapeClass[shape, $RopeShape]; G3dShade.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[SurfaceSequenceRep[1]]; shape.surfaces[0].vertices _ NEW[NatSequenceRep[3]]; shape.surfaces[0].vertices[0] _ shape.surfaces[0].vertices[2] _ 0; shape.surfaces[0].vertices[1] _ 1; shape.surfaces[0].vertices.length _ 3; 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].props _ PutProp[ NARROW[shape.renderData, REF RenderData].props, $RopeMessage, newMessage ]; }; DeleteShape: PUBLIC PROC [context: Context, shapeName: ROPE] ~ { found: BOOL _ FALSE; IF context.shapes = NIL THEN { SIGNAL Error[$MisMatch, "No shapes to delete from"]; RETURN[]; }; FOR i: CARDINAL IN [0..context.shapes.length) DO IF NOT found THEN found _ Rope.Equal[shapeName, context.shapes[i].name, FALSE] ELSE context.shapes[i-1] _ context.shapes[i]; ENDLOOP; IF found THEN { context.shapes.length _ context.shapes.length - 1; context.shapes[context.shapes.length] _ NIL; } ELSE SIGNAL 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 context.shapes[n] _ NIL; ENDLOOP; context.shapes _ NIL; }; }; SetRenderStyle: PUBLIC PROC [shape: Shape, renderStyle: RenderStyle] ~ { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade = NIL THEN RETURN; shade.renderMethod _ NEW[RenderStyle _ renderStyle]; shape.renderValid _ FALSE; }; SetColor: PUBLIC PROC [shape: Shape, color: RGB] ~ { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade = NIL THEN RETURN; shade.color _ color; shape.renderValid _ FALSE; }; SetDiffuse: PUBLIC PROC [shape: Shape, diffuseReflectivity: REAL] ~ { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade = NIL THEN RETURN; shade.diffuseReflectivity _ diffuseReflectivity; shape.renderValid _ FALSE; }; SetSpecular: PUBLIC PROC [shape: Shape, specularReflectivity: REAL] ~ { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade = NIL THEN RETURN; shade.specularReflectivity _ specularReflectivity; shape.renderValid _ FALSE; }; SetMetallicity: PUBLIC PROC [shape: Shape, metallicity: REAL] ~ { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade = NIL THEN RETURN; shade.metallicity _ metallicity; shape.renderValid _ FALSE; }; SetShininess: PUBLIC PROC [shape: Shape, shininess: REAL] ~ { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade = NIL THEN RETURN; shade.shininess _ shininess; shape.renderValid _ FALSE; }; SetTransmittance: PUBLIC PROC [shape: Shape, transmittance: REAL] ~ { shade: REF ShadingClass _ ShadingClassFrom[shape]; IF shade = NIL THEN RETURN; shade.transmittance _ transmittance; shape.renderValid _ FALSE; }; SetInvisible: PUBLIC PROC [shape: Shape] ~ {IF shape # NIL THEN shape.visible _ FALSE}; SetVisible: PUBLIC PROC [shape: Shape] ~ {IF shape # NIL THEN shape.visible _ TRUE}; ShowBackfaces: PUBLIC PROC [shape: Shape] ~ { IF shape = NIL THEN RETURN; shape.showBackfaces _ TRUE; RenderDataFrom[shape].patch _ NIL; }; HideBackfaces: PUBLIC PROC [shape: Shape] ~ { IF shape = NIL THEN RETURN; shape.showBackfaces _ FALSE; RenderDataFrom[shape].patch _ NIL; }; RenderDataFrom: PUBLIC PROC [shape: Shape] RETURNS [data: REF RenderData] ~ { IF shape = NIL THEN RETURN[NIL]; IF shape.renderData = NIL THEN shape.renderData _ NEW[RenderData]; data _ NARROW[shape.renderData]; }; ShapeClassFrom: PUBLIC PROC [shape: Shape] RETURNS [REF ShapeClass] ~ { data: REF RenderData; IF shape = NIL THEN RETURN[NIL]; data _ RenderDataFrom[shape]; IF data.class = NIL THEN LoadShapeClass[shape, shape.type]; RETURN[data.class]; }; ShadingClassFrom: PUBLIC PROC [shape: Shape] RETURNS [REF ShadingClass] ~ { data: REF RenderData; IF shape = NIL THEN RETURN[NIL]; data _ RenderDataFrom[shape]; IF data.shadingClass = NIL THEN G3dShade.LoadShadingClass[shape]; RETURN[data.shadingClass]; }; PatchesFrom: PUBLIC PROC [shape: Shape] RETURNS [PatchSequence] ~ { data: REF RenderData _ RenderDataFrom[shape]; RETURN[IF data # NIL THEN data.patch ELSE NIL]; }; AddAxes: PUBLIC PROC [ context: Context, origin: Triple _ [0, 0, 0], size: REAL _ 1.0, scale: Triple _ [1, 1, 1], nReticles: NAT _ 20] ~ { AddAxis: PROC [name: ROPE, p, v0, v1: Triple] ~ { SetRect: PROC [id, n0, n1, n2, n3: NAT] ~ { poly: G3dShape.Surface _ s.surfaces[id] _ [NIL, NEW[NatSequenceRep[4]]]; poly.vertices.length _ 4; poly.vertices[0] _ n0; poly.vertices[1] _ n1; poly.vertices[2] _ n2; poly.vertices[3] _ n3; }; SetVertex: PROC [id: NAT, p: Triple] ~ {s.vertices[id] _ NEW[VertexRep _ [point: p]]}; s: Shape _ NEW[ShapeRep _ [name: Rope.Cat[name, "-axis"], matrix: G3dMatrix.Identity[]]]; SetRenderStyle[s, lines]; s.surfaces _ NEW[SurfaceSequenceRep[4]]; s.surfaces.length _ 4; s.vertices _ NEW[VertexSequenceRep[8]]; s.vertices.length _ 8; SetVertex[0, origin]; SetVertex[1, G3dVector.Add[origin, v0]]; SetVertex[2, G3dVector.Add[G3dVector.Add[origin, v0], v1]]; SetVertex[3, G3dVector.Add[origin, v1]]; SetVertex[4, p]; SetVertex[5, G3dVector.Add[p, v0]]; SetVertex[6, G3dVector.Add[G3dVector.Add[p, v0], v1]]; SetVertex[7, G3dVector.Add[p, v1]]; SetRect[0, 0, 1, 5, 4]; SetRect[1, 1, 2, 6, 5]; SetRect[2, 2, 3, 7, 6]; SetRect[3, 3, 0, 4, 7]; AddShape[context, s]; }; AddAxis["X", [origin.x+size, origin.y, origin.z], [0.0, 0.01, 0.0], [0.0, 0.0, 0.01]]; AddAxis["Y", [origin.x, origin.y+size, origin.z], [0.0, 0.0, 0.01], [0.01, 0.0, 0.0]]; AddAxis["Z", [origin.x, origin.y, origin.z+size], [0.01, 0.0, 0.0], [0.0, 0.01, 0.0]]; }; 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 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] ~ { FOR n: NAT IN [0..shape.vertices.length) DO v: Vertex _ shape.vertices[n]; v.texture _ [v.texture.x+offset.x, v.texture.y+offset.y]; ENDLOOP; }; 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 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 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; StartLog: PUBLIC PROC [context: Context] RETURNS[IO.STREAM] ~ { log: IO.STREAM _ NARROW[GetProp[context.props, $Log]]; IF log = NIL THEN { [out: log] _ ViewerIO.CreateViewerStreams[ name: "ThreeDWorld.log", backingFile: PrependWorkingDirectory[context, "ThreeDWorld.log"] ]; context.props _ PutProp[context.props, $Log, log]; }; RETURN[ log ]; }; FlushLog: PUBLIC PROC [context: Context] ~ { log: IO.STREAM _ NARROW[GetProp[context.props, $Log]]; IF log # NIL THEN IO.Flush[log]; }; CloseLog: PUBLIC PROC [context: Context] ~ { log: IO.STREAM _ NARROW[GetProp[context.props, $Log]]; IF log # NIL THEN IO.Close[log]; context.props _ Atom.RemPropFromList[context.props, $Log] }; 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]; }; RendertoAISFile: PUBLIC PROC [context: Context, name: ROPE, fork: BOOL _ TRUE] ~ { IF fork THEN { process: Process _ CedarProcess.Fork[ReallyRender, context, [background, TRUE]]; context.props _ PutProp[context.props, $Process, process]; } ELSE [] _ ReallyRender[context]; StoreImage[context, name ]; -- store resulting image }; 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]; IF context.shapes # NIL THEN 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] ~ { IF context.shapes # NIL THEN 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 ]; }; GetLogFileName: PUBLIC PROC[fileRoot: ROPE] RETURNS[ROPE] ~ { cp: FS.ComponentPositions; fullFName, fName: ROPE; [fullFName, cp] _ FS.ExpandName[fileRoot]; fName _ Rope.Substr[fullFName, 0, IF cp.ext.length = 0 THEN cp.ext.start ELSE cp.ext.start-1]; RETURN[Rope.Cat[fName, ".", "log"]]; }; PasteInSequenceNo: PUBLIC PROC[fileRoot: ROPE, number: NAT] RETURNS[ROPE] ~ { num: ROPE _ Convert.RopeFromInt[number, 10, FALSE]; SELECT Rope.Length[num] FROM 1 => num _ Rope.Cat["00", num]; 2 => num _ Rope.Cat["0", num]; 3 => {}; ENDCASE => SIGNAL Error[$MisMatch, "Sequence # out of range"]; RETURN[ PasteInLabel[fileRoot, num ] ]; }; PasteInLabel: PUBLIC PROC[fileRoot: ROPE, label: ROPE] RETURNS[ROPE] ~ { cp: FS.ComponentPositions; fullFName, fName, ext: ROPE; [fullFName, cp, ] _ FS.ExpandName[fileRoot]; IF cp.ext.length = 0 THEN { fName _ Rope.Substr[ fullFName, 0, cp.ext.start]; -- name for filling in numbers ext _ "ais"; } ELSE { fName _ Rope.Substr[ fullFName, 0, cp.ext.start-1]; -- drop "." before ext ext _ Rope.Substr[ fullFName, cp.ext.start, cp.ext.length]; }; RETURN[ Rope.Cat[fName, label, ".", ext] ]; }; 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, September 10, 1989 1:48:21 pm PDT Heckbert, August 9, 1988 4:50:32 pm PDT Crow, September 21, 1989 4:19:55 pm PDT Glassner, July 19, 1989 12:03:35 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 Non-convex polygon type, $Poly, registered from G3dStandardPatchProcs.mesa Context Return a Context with memory allocated for the indicated number of pixels. If oldContext is not NIL then copy existing scene, background, lights, etc. from it, otherwise initialize context to standard defaults and set RGB background to [0.2, 0.2, 0.7]. copies context so temporary modifications can be made (don't change shapes however) copies REFed data to dstCtx to insulate srcCtx from changes (except for shapes) Don't copy pixels, some uses want their own copies shape data to dstCtx to insulate srcCtx shapes from changes View Lighting Was: IF context # NIL AND context.shapes # NIL THEN FOR n: NAT IN [0..context.shapes.length) DO s: Shape _ context.shapes[n]; IF ShapeClassFrom[s].type = $Light THEN { rgb: RGB _ ShadingClassFrom[s].color; i: Light _ NEW[G3dLight.LightRep _ [s.name, s.position, G3dVector.Normalize[s.position], rgb]]; l _ G3dLight.AddToLightSequence[l, i]; }; ENDLOOP; Was: IF context # NIL AND lights # NIL THEN FOR n: NAT IN [0..lights.length) DO l: Light _ lights[n]; AddLight[context, l.name, l.position, l.color]; ENDLOOP; 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. Don't create shapes, just transform axes endpoints and draw smooth lines to Imager context? AddName: PROC [name: ROPE, position: Triple] ~ { s: Shape _ ShapeFromRope[name, name, "white"]; s.position _ position; AddShape[context, s]; }; FOR n: NAT IN [0..nReticles) DO p1: Triple _ G3dVector.Interp[REAL[n]/REAL[nReticles], origin, direction]; p2: Triple _ G3dVector.Add[p1, offset]; s.vertices[2*n] _ NEW[VertexRep _ [point: p1]]; s.vertices[2*n+1] _ NEW[VertexRep _ [point: p2]]; s.surfaces[n].vertices _ NewPoly[2*n, 2*n+1]; ENDLOOP; SetRenderStyle[s, lines]; AddName[name, direction]; 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: 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 gets name of log file for updating animation status adds sequence number before file name extension for animations puts arbitrary label before file name extension, for adding "-red, -grn, -blu" etc. Κ*&˜™J™BJšœ.™.Icodešœ$Οk™'Kšœ'™'Kšœ$™'J˜Jš œ4œΞœY˜θJ˜—šΡbln œœ˜Jšœ4œΉœI˜ΑJšœ ˜J˜—Jšœ˜headšΟl™Jš Οnœœœœ œœ˜;—šŸ™šŸ™Jšœ œ˜"Jšœœœœ˜Jšœœœ˜Jšœ œ˜(Jšœ œ˜!Jšœ œ˜&—šŸ™Jšœœ˜+Jšœœ˜0Jšœœ˜,Jšœœ˜0Jšœœ˜.—šŸ™Jšœœ œ˜—šŸ™Jšœ œ˜Jšœ œ˜"Jšœ œΟcΠcs‘’‘˜AJšœ œ‘’˜D—šŸ™Jšœ œ˜(Jšœ œ˜'JšΟtœœ £ Πct‘˜5Jš œœ £œ £€’‘’‘˜G—šŸ™Jšœœ˜1JšœΟsœ˜7—šΠblŸ ™Jšœœ˜2Jšœœ˜*Jšœœ˜/Jšœœ˜.Jšœœ˜,—š¦™Jšœ œ˜'—š¦™Jšœ œ˜!Jšœ œ˜&Jšœœ˜.Jšœœ˜3Jšœ œ˜"Jšœ œ˜'Jšœœ˜5Jšœœ˜/Jšœœ˜*Jšœœ˜2Jšœ œ˜(Jšœœ˜,—š¦™Jšœ œ˜%Jšœœ˜*Jšœœ˜.Jšœœ˜*Jšœœ˜+——š¦™š  œœœ ˜PJ˜—š  œœœ#˜XJ˜—š œ₯œ ₯œ ₯œ₯₯œ₯₯œ₯œ˜CJ˜J˜—š œœœœœœœ ˜RJ˜——š¦™Idefaultšœ$œ‘˜HMšœ$œ‘˜HMšœ%œ‘˜K—šŸ#™#š œœœœ˜GJšœ?œ˜[M˜—š  œœœœœ˜KMšœ œœ(˜Kšœ œ˜Mšœ˜Mšœ3˜7—M˜—š œœœœ˜@Mšœœœ(˜HMšœ œœ4˜GJšœœ˜+Jšœœ ‘"˜AJ˜WJšœ+‘$˜Ošœ*œœ˜6Mšœ-‘˜KM˜DM˜—šœ%œ˜4˜Mšœ0‘˜EM˜AM˜—Mšœ˜—M˜—š œœœœ˜CJšœ?œ˜YM˜—š   œœœœœ˜GMšœ œœ(˜Išœ œ˜Mšœ˜Mšœ4˜8—M˜—š œœœœ˜9Mšœ œ ˜Mšœœœ(˜FMšœ œœ4˜GJ˜#šœœ˜Jšœœ˜0šœ‘1˜‘˜VMšœ˜M˜—š œœ‘.˜T˜J˜J˜*Jšœ œ˜ Jšœ˜J˜—Jšœ+‘%œ˜QJ˜$J˜>J˜=Jšœ3‘œ˜JJ™KJ˜ J˜;Jšœ/‘˜AJ˜——šŸ™š œœœœ˜,Jšœœ˜$Jšœœ&‘˜OJšœ?‘ ˜LJšœ5‘˜FMšœ,‘1˜]Mšœœœœ˜&Mšœ ˜M˜—š œœœ˜'Jšœœ˜Jšœœ ˜Jšœœ˜Jšœ%˜%Jšœ œœ˜Jšœ˜Jšœaœwœ™ύIašœ˜N˜&Nšœœœ&˜>Nšœœ˜šœœ‘0˜MN˜LN˜—Nšœ.˜.šœ ˜Nšœ.˜.Nšœ7˜7Nšœ7˜7Nšœ ‘$˜4—Jšœ œ˜'Jšœœ‘(˜FJšœœœ.˜FJ˜—š  œœœ˜/Jšœœœ˜Jšœ œ˜"J˜ Jšœ˜J˜J˜N˜&J˜š œ6œœœ‘˜\Jšœœ$˜BJšœœ˜9Jšœ˜—M˜IJ˜—N˜"N˜.N™+Nš œœœœœ.œœ˜kN˜4N˜*N˜8Jšœœ˜š œ6œœœ‘˜\Jšœœ$˜BJšœœ˜9Jšœ˜ —N˜&N˜&N˜$N˜*N˜.N˜0N˜+Jšœœ˜š œ/œœœ‘˜ZJšœœ$˜BJšœœ˜+Jšœ˜—N˜—š œœœ˜J˜—Jšœ˜—J˜,N˜——šŸ™š œœœ˜$J˜Jšœ œ˜Jšœœ˜J˜J˜Jš œœœœœ ˜šœœ ˜Kšœ˜Kšœœ œœ˜—K˜—K˜—š œ₯₯₯œ ₯œ₯œ₯œ₯œ ₯œ₯œ₯₯œ₯œœ˜J˜ Jšœ'‘˜FJ˜J˜J˜J˜PJšœœ˜J˜J˜—š  œœœœ˜;J˜1Jšœœ˜J˜J˜—š œ œ˜3J˜ J˜J™—š œœœœ˜P™š œ œœœ™.šœœœ™+J™šœ!œ™)Jšœœ™%šœ œ™"J™<—J™&J™—Jšœ™———Kšœ˜K˜K™—š œœœ.˜J™š œ œœ œ™&šœœœ™#K™K™/Kšœ™———K˜K˜——šŸ ™ š œœœœ˜DJ™.Jšœ œ<˜KJšœ)‘ ˜5J˜—š œœœœ˜BJ™Jšœ4œœ ˜FJ˜J˜—š  œœœœœ˜IJ™"šœ%œ˜4Kšœœœ ˜Kšœ˜—J˜J˜—š œœœœ˜EJšœ œ:™GJ˜J˜1J˜-J˜J˜AK˜(K˜—š  œœœœœœ˜NJšœ)Πksœ ™6šœ%œ˜4˜Jšœœœ*˜7Jšœœœœ˜$J˜—Jšœ˜—J˜J˜—š œœœ!˜BJ™YJ˜>K˜—š  œœœœ˜9šœ˜JšœC˜GJšœJ˜N—J˜J˜—š œœœ˜7J™J˜AK˜J™——šŸ™š œœœ%˜:Jšœ œœœ˜Jš œœœœ‘˜HJšœ+œ˜5J˜DJšœ˜—š œœœ˜J˜Jšœ œ˜Jšœ œ˜J˜ J˜Jšœœ˜J˜6š œœœœœœ˜Hšœ3‘˜SJšœ˜#—Jšœ˜—šœ œ‘%˜?Jšœ&˜*Jšœ*˜.—J˜J˜J˜J˜;J˜J˜—š  œœœœ˜:Jšœœ˜J˜šœ œ˜JšœIœ˜S—Jšœ œœœ7˜QJ˜J˜—š  œœœ˜Jšœœœ˜Jšœ œ˜Jšœœœ˜Jšœœ˜Jšœœœ˜Jšœ ˜Jšœœ8˜JJšœ œœ ˜-J˜DJ˜>J˜J˜"J˜-˜XJ™L—Jšœœ˜-Jšœœ ˜$Jšœœ1˜HJ˜Mšœœ˜-Jšœœ˜4J˜BJ˜"J˜&J˜Jšœ˜J˜—š œ₯₯₯œ ₯œ₯œ ₯œ₯œ ₯œ˜TJšœ₯œ˜J˜-šœœ˜9Jšœœ-˜IJ˜—J˜—š  œœœœ˜@Jšœœœ˜šœœœ˜Jšœ. œ˜AJ˜—šœœœœ˜1šœœ˜ Jšœ7œ˜AJšœ*˜.—Jšœ˜—šœ˜ šœ˜Jšœ5˜5Jšœ(œ˜-Jšœ˜—JšœœF˜Q—J˜J˜—š œœœ˜3šœ œœ˜Jš œœœœœœ˜OJšœœ˜J˜—J˜J˜—š œœœ-˜HJšœœ(˜2Jšœ œœœ˜Jšœœ˜4Jšœœ˜J˜J˜—š œœœœ˜4Jšœœ(˜2Jšœ œœœ˜Jšœ˜Jšœœ˜J˜J™—š § œ₯œœ%œ˜EJšœœ(˜2Jšœ œœœ˜Jšœ0˜0Jšœœ˜˜J˜——š § œ₯œœ&œ˜GJšœœ(˜2Jšœ œœœ˜Jšœ2˜2Jšœœ˜˜J˜——š §œ₯œœœ˜AJšœœ(˜2Jšœ œœœ˜Jšœ ˜ Jšœœ˜˜J˜——š § œ₯₯œœ˜=Jšœœ(˜2Jšœ œœœ˜Jšœ˜Jšœœ˜˜J˜——š œœœœ˜EJšœœ(˜2Jšœ œœœ˜Jšœ$˜$Jšœœ˜J˜J˜—š  œœœœ œœœ˜WN˜—š  œœœœ œœœ˜TN˜—š  œœœ˜-Jšœ œœœ˜Jšœœ˜Jšœœ˜"J˜—š  œœœ˜-Jšœ œœœ˜Jšœœ˜Jšœœ˜"J˜J˜—š  œœœœœ˜MMš œ œœœœ˜ Mšœœœœ ˜BMšœœ˜ M˜—š  œœœœœ˜GM™%Mšœœ ˜Mš œ œœœœ˜ M˜Mšœœœ#˜;Mšœ ˜M˜—š  œœœœœ˜KM™'Mšœœ ˜Mš œ œœœœ˜ M˜Mšœœœ"˜AMšœ˜Mšœ˜—š§ œœœœ˜CJ™YMšœœ$˜-Mš œœœœ œœ˜/M˜M˜—š œœœ˜Jšœ˜Jšœ˜Jšœœ˜Jšœ₯œ ˜Jšœ œ˜J˜J™[š œœœ˜1š œœœ™0Jšœ.™.J™Jšœ™Jšœ™—š œœœ˜+Jšœ+œœ˜HJšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜—Jš  œœœ!œ˜VJšœ œK˜YJ˜Jšœ œ/˜?Jšœ œ.˜>J˜J˜(J˜;J˜(J˜J˜#J˜6J˜#J˜J˜J˜J˜šœœœ™Jšœœœ ™JJ™'Jšœœ™/Jšœœ™1J™-Jšœ™—J™Jšœ˜Jšœ™Jšœ˜—JšœV˜VJšœV˜VJšœV˜VJ˜——šŸ™š  œœœ˜J˜Jšœ œ˜Jšœ œ˜J˜'Jšœœœ˜Jšœ œ˜J˜Jšœœ&˜-Jšœ œœœ˜Jšœ9Οbœ™WJ™>šœ˜Jšœ>˜Bšœœ œœ˜Jšœœ˜+JšœœK˜QJ˜-J™QJšœ œœ(˜;J˜Ašœ˜JšœC˜G—J˜——J˜J˜—š œœœ!˜Ašœœœœ˜,M˜M˜9Mšœ˜—M˜M˜—š  œœœ œœœ˜UJšœ œœ˜Jš œœœœœœ˜4šœœœœœ'œœ˜Mšœ œ˜šœ œ˜Jšœœœ%˜1Jšœœœœœœœœ˜4šœœ˜-J˜J˜J˜Jšœ ˜—šœœ˜Jšœœ˜ Jšœœœ˜(Jšœ˜—Jšœœ&˜8J˜—šœœ‘(˜KJšœœœ œ˜8—Jšœ˜ —Jšœ˜—J˜J˜—š  œœœ2˜KJ˜UJ˜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˜DJšœ˜——J˜—J˜J˜—š   œœœœ œ ˜Hšœ œœ˜Jšœœ(˜2Jšœ œœ˜,J˜—J˜J˜—š  œœœœ ˜?šœ œœ˜Jšœœ(˜2Jšœ œœ˜,J˜—J˜——šŸ™šœ  œ˜J˜—š  œœœœœœ˜?Jšœœœœ˜6šœœœ˜˜*J˜J˜@J˜—J˜2J˜—Nšœ˜N˜—š œœœ˜,Jšœœœœ˜6Nšœœœœ ˜ N˜—š œœœ˜,Jšœœœœ˜6Nšœœœœ ˜ N˜9N˜—š  œœœœœ˜=šœ˜šœ˜JšœIœ˜PJ˜:J˜—Jšœ˜ —J˜J˜—š  œœœœœœ˜Ršœ˜šœ˜JšœIœ˜PJ˜:J˜—Jšœ˜ —Jšœ"‘˜:Jšœ˜—š œœœœ˜(Jšœœœ˜Jšœ ˜J˜J˜—š   œœœœœ˜BJšœœ#˜Nšœœ#œ˜3šœ˜N˜N˜N˜Nšœœ-˜>—Nšœ!˜'N˜N˜—š  œœœ œ œœœ˜HN™SNšœœ-œ˜8Jšœœ˜,šœ˜šœ˜Nšœ3‘˜QN˜ N˜—šœ˜Nšœ5‘˜KN˜;N˜——Nšœ%˜+N˜N˜—š œœœœ˜RM˜Mšœœ˜(Mšœœ˜(MšœœM˜aMšœœM˜aMšœ˜M˜—š  œœœ₯œ₯œ˜TJšœœœ!œ˜SJ˜J˜—š  œœœ₯œ₯œ˜QJš œ₯œ₯₯œ ₯œ.œ˜XJ˜J˜—š  œœœœœ˜Nšœœ ˜J˜J˜J˜Jšœœ˜—J˜J˜—š  œœœœœ˜Nšœœ ˜J˜J˜J˜J˜J˜Jšœœ˜—J˜J˜—š  œœœœœ˜Qšœœ˜J˜J˜J˜Jšœ ˜—J˜——˜J˜—Jšœ˜—…—ΖP