<> <> <> <> <> <> 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] ~ { <> <> <> <> <> <> <> <<[s.name, s.position, G3dVector.Normalize[s.position], rgb]];>> <> <<};>> <> 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[]; <> < CONTINUE];>> }; 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.