DIRECTORY BasicTime USING [ GetClockPulses, PulsesToSeconds ], Atom USING [ DottedPair, DottedPairNode, GetPropFromList, PropList, PutPropOnList, RemPropFromList ], Real USING [ Float, Fix, Round ], Rope USING [ Cat, Equal, FromChar, Index, ROPE, Substr ], IO USING [ STREAM, Close, Flush, GetAtom, GetChar, GetLineRope, GetReal, PutF, PutRope, EndOfStream, SkipWhitespace, SP, CR, real, rope, time ], FS USING [ StreamOpen, ComponentPositions, ExpandName ], Convert USING [ RopeFromAtom, RopeFromReal ], UserCredentials USING [ Get ], ViewerIO USING [ CreateViewerStreams ], ViewerClasses USING [ ViewerRec ], Imager USING [ Rectangle ], ImagerColorFns USING [ RGBFromHSL ], NamedColors USING [ RopeToHSL ], G3dMatrix USING [ Transform, TransformVec ], G3dVector USING [ Add ], G3dIO USING [ FieldRep, FieldSequenceRep, FieldType, Shape, ShapeFromFile, WriteFields ], ThreeDBasics USING [ AllOut, ClipState, Context, ContextClass, Create, Error, IntegerSequence, LoadDisplayType, LoadShadingClass, LoadSurfaceType, NatSequence, NatTable, NoneOut, OutCode, Pair, PairSequence, PtrPatch, PtrPatchSequence, Quad, RealSequence, RGB, RGBSequence, ScaleAndAddXfm, SetPosition, SetView, ShadingClass, ShadingSequence, ShadingValue, ShapeInstance, ShapeProc, ShapeSequence, SixSides, TextureMap, TextureFunction, Triple, TripleSequence, Vertex, VertexInfo, VertexInfoSequence, VertexSequence, VtxToRealSeqProc, Xfm3D, Xfm3DRep ], SceneUtilities USING [ ]; SceneUtilitiesImpl: CEDAR PROGRAM IMPORTS Atom, BasicTime, Convert, FS, G3dIO, G3dMatrix, G3dVector, ImagerColorFns, IO, NamedColors, Real, Rope, ThreeDBasics, UserCredentials, ViewerIO EXPORTS SceneUtilities ~ BEGIN RGB: TYPE ~ ThreeDBasics.RGB; RGBSequence: TYPE ~ ThreeDBasics.RGBSequence; Pair: TYPE ~ ThreeDBasics.Pair; -- RECORD [ x, y: REAL]; PairSequence: TYPE ~ ThreeDBasics.PairSequence; Triple: TYPE ~ ThreeDBasics.Triple; -- RECORD [ x, y, z: REAL]; TripleSequence: TYPE ~ ThreeDBasics.TripleSequence; Quad: TYPE ~ ThreeDBasics.Quad; -- RECORD [ x, y, z, w: REAL]; NatSequence: TYPE ~ ThreeDBasics.NatSequence; NatTable: TYPE ~ ThreeDBasics.NatTable; IntegerSequence: TYPE ~ ThreeDBasics.IntegerSequence; RealSequence: TYPE ~ ThreeDBasics.RealSequence; Xfm3D: TYPE ~ ThreeDBasics.Xfm3D; -- REF ARRAY [0..4) OF ARRAY [0..4) OF REAL; Xfm3DRep: TYPE ~ ThreeDBasics.Xfm3DRep; ScaleAndAddXfm: TYPE ~ ThreeDBasics.ScaleAndAddXfm; SixSides: TYPE ~ ThreeDBasics.SixSides; -- {Left, Right, Bottom, Top, Near, Far} ClipState: TYPE ~ ThreeDBasics.ClipState; -- {in, out, clipped} OutCode: TYPE ~ ThreeDBasics.OutCode; -- RECORD[bottom,top,left,right,near,far: BOOLEAN] NoneOut: OutCode ~ ThreeDBasics.NoneOut; -- [FALSE,FALSE,FALSE,FALSE,FALSE,FALSE] AllOut: OutCode ~ ThreeDBasics.AllOut; -- [TRUE, TRUE, TRUE, TRUE, TRUE, TRUE] Context: TYPE ~ ThreeDBasics.Context; ContextClass: TYPE ~ ThreeDBasics.ContextClass; ShadingClass: TYPE ~ ThreeDBasics.ShadingClass; ShapeInstance: TYPE ~ ThreeDBasics.ShapeInstance; ShapeSequence: TYPE ~ ThreeDBasics.ShapeSequence; ShapeProc: TYPE ~ ThreeDBasics.ShapeProc; ShadingSequence: TYPE ~ ThreeDBasics.ShadingSequence; ShadingValue: TYPE ~ ThreeDBasics.ShadingValue; Vertex: TYPE ~ ThreeDBasics.Vertex; VertexSequence: TYPE ~ ThreeDBasics.VertexSequence; VertexInfo: TYPE ~ ThreeDBasics.VertexInfo; VertexInfoSequence: TYPE ~ ThreeDBasics.VertexInfoSequence; PtrPatch: TYPE ~ ThreeDBasics.PtrPatch; PtrPatchSequence: TYPE ~ ThreeDBasics.PtrPatchSequence; TextureMap: TYPE ~ ThreeDBasics.TextureMap; TextureFunction: TYPE ~ ThreeDBasics.TextureFunction; Field: TYPE ~ G3dIO.FieldRep; FieldSequence: TYPE ~ G3dIO.FieldSequenceRep; ROPE: TYPE = Rope.ROPE; LORA: TYPE = LIST OF REF ANY; Transform: PROC[p: Triple, mat: Xfm3D] RETURNS[Triple] ~ G3dMatrix.Transform; TransformVec: PROC[vec: Triple, mat: Xfm3D] RETURNS[Triple] ~ G3dMatrix.TransformVec; GetProp: PROC [propList: Atom.PropList, prop: REF ANY] RETURNS [REF ANY] ~ Atom.GetPropFromList; PutProp: PROC [propList: Atom.PropList, prop: REF ANY, val: REF ANY] RETURNS [Atom.PropList] ~ Atom.PutPropOnList; Sqr: PROCEDURE [number: REAL] RETURNS [REAL] ~ INLINE { RETURN[number * number]; }; Ceiling: PROC[number: REAL] RETURNS[result: INTEGER] ~ { result _ INTEGER[Real.Round[number]]; IF result < number THEN result _ result + 1; }; Floor: PROC[ in: REAL ] RETURNS[ out: INTEGER ] ~ { out _ INTEGER[Real.Round[in]]; IF Real.Float[out] > in THEN out _ out - 1; }; ElapsedTime: PROC[startTime: REAL] RETURNS[ROPE] ~ { timeX100: REAL _ 100.0 * (CurrentTime[] - startTime); RETURN[ Rope.Cat[ Convert.RopeFromReal[ Real.Fix[timeX100] / 100.0 ], "s," ] ]; }; CurrentTime: PROC[] RETURNS[REAL] ~ { RETURN[ BasicTime.PulsesToSeconds[BasicTime.GetClockPulses[]] ]; }; DiffPosns: PROC[vtx1, vtx2: REF Vertex] RETURNS[Triple] ~ { RETURN[[vtx1.x - vtx2.x, vtx1.y - vtx2.y, vtx1.z - vtx2.z]] }; GetRope: PUBLIC PROC[input: IO.STREAM] RETURNS[ROPE] ~ { output: ROPE _ NIL; char: CHAR; [] _ IO.SkipWhitespace[input]; -- Strip whitespace and comments char _ IO.GetChar[input]; WHILE char # IO.SP AND char # IO.CR DO -- do until trailing space or CR output _ Rope.Cat[ output, Rope.FromChar[char] ]; char _ IO.GetChar[input]; ENDLOOP; RETURN[output]; }; CreateDefaultContext: PUBLIC PROC[] RETURNS [REF Context] ~ { context: REF Context _ ThreeDBasics.Create[]; context.preferredRenderMode _ $Pixels; NameBackgroundColor[ context, "Darkish Blue" ]; -- set background color SetLight[context, "Default", [-100., -200., 50.] ]; ThreeDBasics.SetView[ context, [2.0, -10.0, 3.0], [0.0, 0.0, 0.0] ]; RETURN[context]; }; PrependWorkingDirectory: PUBLIC PROC[context: REF 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 ]; }; 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; }; StartLog: PUBLIC PROC [context: REF 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: REF Context] ~ { log: IO.STREAM _ NARROW[GetProp[context.props, $Log]]; IF log # NIL THEN IO.Flush[log]; }; CloseLog: PUBLIC PROC [context: REF Context] ~ { log: IO.STREAM _ NARROW[GetProp[context.props, $Log]]; IF log # NIL THEN IO.Close[log]; context.props _ Atom.RemPropFromList[context.props, $Log] }; ForcePrioritySort: PUBLIC PROC[context: REF Context, on: BOOLEAN _ TRUE] ~{ IF on THEN context.props _ PutProp[context.props, $SortToPriority, $DoIt] ELSE context.props _ Atom.RemPropFromList[context.props, $SortToPriority]; }; SetWindow: PUBLIC PROC[context: REF Context, size: Imager.Rectangle] ~{ context.window _ NEW[ Imager.Rectangle _ size ]; context.viewInValid _ TRUE; }; SetViewPort: PUBLIC PROC[context: REF Context, size: Imager.Rectangle] ~{ IF size.w <= 0.0 OR size.h <= 0.0 THEN SIGNAL ThreeDBasics.Error[[$MisMatch, "Null clipper"]]; context.preferredViewPort _ size; context.viewPort _ NIL; context.window _ NIL; -- resizing viewport forces update of window context.displayInValid _ TRUE; }; SetAmbientLight: PUBLIC PROC [context: REF Context, color: ROPE] ~ { ambientColor: REF RGB _ NEW[ RGB _ ImagerColorFns.RGBFromHSL[ NamedColors.RopeToHSL[color] ] ]; context.environment _ PutProp[ context.environment, $AmbientLight, ambientColor ]; IF context.shapes # NIL THEN FOR i: NAT IN [0..context.shapes.length) DO context.shapes[i].shadingInValid _ TRUE; ENDLOOP; }; SetBackgroundColor: PUBLIC PROC [context: REF Context, color: RGB] ~ { bkgrdColor: REF RGB _ NEW[ RGB _ color ]; context.props _ PutProp[context.props, $BackGround, bkgrdColor]; -- set color }; GetBackgroundColor: PUBLIC PROC [context: REF Context] RETURNS [color: RGB] ~ { ref: REF _ GetProp[context.props, $BackGround]; -- get background color IF ref # NIL THEN color _ NARROW[ref, REF RGB]^ ELSE color _ [0., 0., 0.]; }; NameBackgroundColor: PUBLIC PROC [context: REF Context, color: ROPE] ~ { bkgrdColor: REF RGB _ NEW[ RGB _ ImagerColorFns.RGBFromHSL[ NamedColors.RopeToHSL[color] ] ]; context.props _ PutProp[context.props, $BackGround, bkgrdColor]; -- set color }; SetBackgroundImage: PUBLIC PROC [context: REF Context, aisFile: ROPE] ~ { bkGrdCtx: REF Context _ ThreeDBasics.Create[]; bkGrdCtx.depthBuffering _ context.depthBuffering; bkGrdCtx.antiAliasing _ context.antiAliasing; bkGrdCtx.class _ context.class; bkGrdCtx.props _ PutProp[bkGrdCtx.props, $BackGrdImage, aisFile]; SetBackgroundContext[context, bkGrdCtx]; }; SetBackgroundContext: PUBLIC PROC [context, bkGrdCtx: REF Context ] ~ { context.props _ PutProp[context.props, $BackGround, bkGrdCtx]; }; SetLight: PUBLIC PROC[context: REF Context, name: ROPE, position: Triple, color: RGB _ [1, 1, 1] ] ~ { light: REF ShapeInstance _ FindShape[ context, name ! ThreeDBasics.Error => IF reason.code = $MisMatch THEN RESUME ]; IF light = NIL THEN { light _ NewShape[ name, $Light ]; -- name not used before, load light class AddShape[ context, light ]; }; light.location _ position; light.boundingRadius _ 2 * 93000000.0 * 1609.344; -- twice solar distance in meters light.orientation _ [0.,0.,0.]; -- no orientation by default light.positionInValid _ TRUE; light.vtcesInValid _ TRUE; light.shadingClass.color _ color; light.props _ PutProp[light.props, $Hidden, $ok]; -- hide from display routines FOR i: NAT IN [0..context.shapes.length) DO context.shapes[i].shadingInValid _ TRUE; ENDLOOP; }; DeleteLight: PUBLIC PROC[context: REF Context, name: ROPE] ~ { DeleteShape[context, name]; IF context.shapes # NIL THEN FOR i: NAT IN [0..context.shapes.length) DO context.shapes[i].shadingInValid _ TRUE; ENDLOOP; }; SaveOnFile: PUBLIC PROC[context: REF Context, fileName: ROPE] ~ { wDir: ROPE _ PrependWorkingDirectory[context, NIL]; output: IO.STREAM _ FS.StreamOpen[fileName: fileName, accessOptions: $create, wDir: wDir]; IO.PutF[ output, " -- %g - Created by: %g at %g\n\n", IO.rope[fileName], IO.rope[UserCredentials.Get[].name], IO.time[] ]; WriteScene[context, output]; IO.Close[output]; }; RestoreFromFile: PUBLIC PROC[context: REF Context, fileName: ROPE] ~ { wDir: ROPE _ PrependWorkingDirectory[context, NIL]; input: IO.STREAM _ FS.StreamOpen[fileName: fileName, accessOptions: $read, wDir: wDir]; [] _ IO.GetLineRope[ input ]; -- ignore first line ReadScene[context, input]; IO.Close[input]; }; MakeFrameFromFile: PUBLIC PROC[context: REF Context, fileName: ROPE] ~ { wDir: ROPE _ NARROW[ GetProp[context.props, $WDir] ]; log: IO.STREAM _ NARROW[ GetProp[context.props, $Log] ]; bufferCtx: REF Context _ ThreeDBasics.Create[]; bufferCtx.pixels _ context.pixels; bufferCtx.viewer _ context.viewer; bufferCtx.terminal _ context.terminal; bufferCtx.class _ context.class; bufferCtx.antiAliasing _ context.antiAliasing; bufferCtx.props _ PutProp[bufferCtx.props, $WDir, wDir]; bufferCtx.props _ PutProp[bufferCtx.props, $Log, log]; RestoreFromFile[bufferCtx, fileName]; bufferCtx.class.render[bufferCtx]; bufferCtx _ NIL; }; ReadScene: PUBLIC PROC[context: REF Context, input: IO.STREAM] ~ { shape: REF ShapeInstance _ NIL; done: BOOLEAN _ FALSE; log: IO.STREAM _ NARROW[GetProp[context.props, $Log]]; startTime: REAL _ CurrentTime[]; WHILE NOT done DO keyWd: ROPE _ GetRope[ input ! IO.EndOfStream => EXIT ]; SELECT TRUE FROM Rope.Equal[ "View:", keyWd, FALSE] => { [] _ GetRope[input]; context.eyePoint _ [ IO.GetReal[input], IO.GetReal[input], IO.GetReal[input] ]; [] _ GetRope[input]; context.ptOfInterest _ [ IO.GetReal[input], IO.GetReal[input], IO.GetReal[input] ]; [] _ GetRope[input]; context.upDirection _ [ IO.GetReal[input], IO.GetReal[input], IO.GetReal[input] ]; [] _ GetRope[input]; context.rollAngle _ IO.GetReal[input]; [] _ GetRope[input]; context.fieldOfView _ IO.GetReal[input]; [] _ GetRope[input]; context.hitherLimit _ IO.GetReal[input]; context.yonLimit _ IO.GetReal[input]; context.viewInValid _ TRUE; }; Rope.Equal[ "ViewPort:", keyWd, FALSE] => { SetViewPort[ context, [ x: IO.GetReal[input], y: IO.GetReal[input], w: IO.GetReal[input], h: IO.GetReal[input] ] ]; }; Rope.Equal[ "Window:", keyWd, FALSE] => { -- window must be set after viewport SetWindow[ context, [ x: IO.GetReal[input], y: IO.GetReal[input], w: IO.GetReal[input], h: IO.GetReal[input] ] ]; }; Rope.Equal[ "BackgroundColor:", keyWd, FALSE] => { bkgrdColor: REF RGB _ NEW[RGB]; bkgrdColor^ _ [ IO.GetReal[input], IO.GetReal[input], IO.GetReal[input] ]; context.props _ PutProp[context.props, $BackGround, bkgrdColor]; }; Rope.Equal[ "AntiAliasing:", keyWd, FALSE] => context.antiAliasing _ TRUE; Rope.Equal[ "DepthBuffering:", keyWd, FALSE] => context.depthBuffering _ TRUE; Rope.Equal[ "DisplayType:", keyWd, FALSE] => ThreeDBasics.LoadDisplayType[context, IO.GetAtom[input] ]; Rope.Equal[ "Light:", keyWd, FALSE] => { name: ROPE _ GetRope[input]; pos: ROPE _ GetRope[input]; position: Triple _ [ IO.GetReal[input], IO.GetReal[input], IO.GetReal[input] ]; clr: ROPE _ GetRope[input]; color: RGB _ [ IO.GetReal[input], IO.GetReal[input], IO.GetReal[input] ]; [] _ SetLight[ context, name, position, color ]; }; Rope.Equal[ "ReadShape:", keyWd, FALSE] => { -- read in new shape data. name: ROPE _ GetRope[input]; fileName: ROPE _ GetRope[input]; type: ATOM _ IO.GetAtom[ input ]; insideVisible: BOOLEAN _ Rope.Equal[GetRope[input], "Open", FALSE]; AddShapeAt[context, name, fileName, [0.,0.,0.]]; shape _ FindShape[context, name]; }; Rope.Equal[ "SetShape:", keyWd, FALSE] => { -- set shape for subsequent mods. name: ROPE _ GetRope[input]; shape _ FindShape[context, name]; }; Rope.Equal[ "PlaceShape:", keyWd, FALSE] => { position: Triple _ [ IO.GetReal[input], IO.GetReal[input], IO.GetReal[input] ]; PlaceShape[ context, shape.name, position ]; }; Rope.Equal[ "MoveShape:", keyWd, FALSE] => { delta: Triple _ [ IO.GetReal[input], IO.GetReal[input], IO.GetReal[input] ]; PlaceShape[ context, shape.name, delta ]; }; Rope.Equal[ "OrientShape:", keyWd, FALSE] => { axis: Triple _ [ IO.GetReal[input], IO.GetReal[input], IO.GetReal[input] ]; OrientShape[ context, shape.name, axis ]; }; Rope.Equal[ "RotateShape:", keyWd, FALSE] => { axisBase: Triple _ [ IO.GetReal[input], IO.GetReal[input], IO.GetReal[input] ]; axisEnd: Triple _ [ IO.GetReal[input], IO.GetReal[input], IO.GetReal[input] ]; theta: REAL _ IO.GetReal[input]; RotateShape[ context, shape.name, axisBase, axisEnd, theta ]; }; Rope.Equal[ "Hide:", keyWd, FALSE] => Hide[context, GetRope[input]]; Rope.Equal[ "Reveal:", keyWd, FALSE] => Reveal[context, GetRope[input]]; Rope.Equal[ "Color:", keyWd, FALSE] => { color: RGB; color.R _ IO.GetReal[input]; color.G _ IO.GetReal[input]; color.B _ IO.GetReal[input]; SetColor[context, shape.name, color]; }; Rope.Equal[ "Shading:", keyWd, FALSE] => { SELECT IO.GetAtom[input] FROM $Faceted => SetFaceted[context, shape.name]; $Smooth => SetSmooth[context, shape.name]; $Lines => SetLines[context, shape.name]; ENDCASE => SIGNAL ThreeDBasics.Error[[$MisMatch, "Unknown shading type"]]; }; Rope.Equal[ "Shininess:", keyWd, FALSE] => { shininess: REAL _ IO.GetReal[input]; SetShiny[context, shape.name, shininess]; }; Rope.Equal[ "Transmittance:", keyWd, FALSE] => { transmittance: REAL _ IO.GetReal[input]; SetTransparent[context, shape.name, transmittance]; }; Rope.Equal[ "TextureMap:", keyWd, FALSE] => { proc: REF ShapeProc _ NARROW[ GetProp[context.props, $TextureMapFromStream] ]; IF proc # NIL THEN [] _ proc^[context, shape, input] ELSE SIGNAL ThreeDBasics.Error[[$Unloaded, "Texture procs not loaded"]]; }; Rope.Equal[ "TextureFunction:", keyWd, FALSE] => { proc: REF ShapeProc _ NARROW[ GetProp[context.props, $TextureFunctionFromStream] ]; IF proc # NIL THEN [] _ proc^[context, shape, input] ELSE SIGNAL ThreeDBasics.Error[[$Unloaded, "Texture procs not loaded"]]; }; Rope.Equal[ "Render:", keyWd, FALSE] => { IF log # NIL AND (CurrentTime[] - startTime > .01) THEN log.PutRope[ Rope.Cat[" Readin: ", ElapsedTime[startTime]] ]; context.class.render[context]; startTime _ CurrentTime[]; -- restart for modifications until next frame }; Rope.Equal[ "EndOfScene:", keyWd, FALSE] => { IF log # NIL AND (CurrentTime[] - startTime > .01) THEN log.PutRope[ Rope.Cat[" Scene input: ", ElapsedTime[startTime]] ]; done _ TRUE; }; ENDCASE => SIGNAL ThreeDBasics.Error[ [$MisMatch, Rope.Cat[keyWd, " - not understood"]] ]; ENDLOOP; }; WriteScene: PUBLIC PROC[context: REF Context, output: IO.STREAM] ~ { CatList: PROC[list: LIST OF ROPE] RETURNS[ROPE] ~ { rope: ROPE _ NIL; WHILE list # NIL DO rope _ Rope.Cat[ rope, list.first ]; list _ list.rest; ENDLOOP; RETURN[ rope ]; }; Vec3toRope: PROC[ r1, r2, r3: REAL] RETURNS[ROPE] ~ { rope: ROPE; rope _ Rope.Cat[ " ", Convert.RopeFromReal[r1], " ", Convert.RopeFromReal[r2] ]; rope _ Rope.Cat[ rope, " ", Convert.RopeFromReal[r3], " " ]; RETURN[ rope ]; }; Vec4toRope: PROC[ r1, r2, r3, r4: REAL] RETURNS[ROPE] ~ { rope: ROPE; rope _ Rope.Cat[ " ", Convert.RopeFromReal[r1], " ", Convert.RopeFromReal[r2], " " ]; rope _ Rope.Cat[ rope, Convert.RopeFromReal[r3], " ", Convert.RopeFromReal[r4], " " ]; RETURN[ rope ]; }; ref: REF; line: ROPE; IO.PutRope[ output, Rope.Cat[ "DisplayType: ", Convert.RopeFromAtom[context.class.displayType ], "\n" ] ]; IF context.antiAliasing THEN IO.PutRope[ output, "AntiAliasing: \n" ]; IF context.depthBuffering THEN IO.PutRope[ output, "DepthBuffering: \n" ]; line _ CatList[ LIST[ "View: ", "from:", Vec3toRope[context.eyePoint.x, context.eyePoint.y, context.eyePoint.z], "at:", Vec3toRope[context.ptOfInterest.x, context.ptOfInterest.y, context.ptOfInterest.z], "up:", Vec3toRope[context.upDirection.x, context.upDirection.y, context.upDirection.z], "roll: ", Convert.RopeFromReal[ context.rollAngle ], " fov: ", Convert.RopeFromReal[ context.fieldOfView ], " hithr/yon: ", Convert.RopeFromReal[ context.hitherLimit], " ", Convert.RopeFromReal[context.yonLimit], "\n" ] ]; IO.PutRope[ output, line ]; IF context.viewPort # NIL THEN IO.PutRope[ output, Rope.Cat["ViewPort: ", Vec4toRope[context.viewPort.x, context.viewPort.y, context.viewPort.w, context.viewPort.h], "\n" ] ]; IF context.window # NIL THEN IO.PutRope[ output, Rope.Cat["Window: ", Vec4toRope[context.window.x, context.window.y, context.window.w, context.window.h], "\n" ] ]; ref _ GetProp[context.props, $BackGround]; -- get background color IF ref # NIL THEN { color: RGB _ NARROW[ref, REF RGB]^; IO.PutRope[ output, Rope.Cat[ "BackgroundColor: ", Vec3toRope[color.R, color.G, color.B], "\n" ] ]; }; IF context.shapes # NIL THEN FOR i: NAT IN [0..context.shapes.length) DO IF context.shapes[i].class.type = $Light THEN { -- light source color: RGB _ context.shapes[i].shadingClass.color; IO.PutRope[ output, CatList[ LIST[ "Light: ", context.shapes[i].name, " position:", Vec3toRope[ context.shapes[i].location.x, context.shapes[i].location.y, context.shapes[i].location.z ], "color:", Vec3toRope[color.R, color.G, color.B], "\n" ] ] ]; } ELSE { -- shape shape: REF ShapeInstance _ context.shapes[i]; IF shape # NIL AND GetProp[shape.props, $Hidden] = NIL AND shape.clipState # out AND shape.surface # NIL THEN { ref: REF ANY _ NIL; xfm: Xfm3D _ shape.position; line _ Rope.Cat[ "ReadShape: ", shape.name, " ", shape.fileName, " " ]; line _ Rope.Cat[ line, Convert.RopeFromAtom[shape.class.type] ]; IF shape.insideVisible THEN line _ Rope.Cat[line, " Open \n"] ELSE line _ Rope.Cat[line, " Closed \n"]; IO.PutRope[ output, line]; IF GetProp[shape.fixedProps, $Scale] # NIL THEN { scale: REF Quad _ NARROW[GetProp[shape.fixedProps, $Scale]]; line _ Rope.Cat[" ScaleShape: ", Vec4toRope[scale.x, scale.y, scale.z, scale.w], "\n" ]; IO.PutRope[ output, line]; }; { IF shape.location # [0.,0.,0.] THEN IO.PutRope[ output, Rope.Cat[ " PlaceShape:", Vec3toRope[shape.location.x, shape.location.y, shape.location.z], "\n" ] ]; IF shape.orientation # [0.,0.,1.] THEN IO.PutRope[ output, Rope.Cat[ " OrientShape:", Vec3toRope[shape.orientation.x, shape.orientation.y, shape.orientation.z], "\n" ] ]; IF shape.rotation # 0.0 THEN IO.PutRope[ output, Rope.Cat[ " RotateShape:", Vec3toRope[shape.axisBase.x, shape.axisBase.y, shape.axisBase.z], Vec3toRope[shape.axisEnd.x, shape.axisEnd.y, shape.axisEnd.z], Convert.RopeFromReal[shape.rotation], "\n" ] ]; }; { color: RGB _ shape.shadingClass.color; shadingType: ATOM _ shape.shadingClass.shadingType; IO.PutRope[output, Rope.Cat[ " Color: ", Vec3toRope[color.R, color.G, color.B], "\n" ] ]; IO.PutRope[output, Rope.Cat[ " Shading: ", Convert.RopeFromAtom[shape.shadingClass.shadingType], "\n" ] ]; IF shape.shadingClass.shininess > 0.0 THEN IO.PutRope[ output, Rope.Cat[ " Shininess: ", Convert.RopeFromReal[shape.shadingClass.shininess], "\n" ] ]; IF shape.shadingClass.transmittance # 0.0 THEN IO.PutRope[ output, Rope.Cat[ " Transmittance: ", Convert.RopeFromReal[shape.shadingClass.transmittance], "\n" ] ]; }; IF shape.shadingClass.texture # NIL THEN { tmpTxtr: LORA _ NIL; FOR txtrList: LORA _ shape.shadingClass.texture, txtrList.rest UNTIL txtrList = NIL DO tmpTxtr _ CONS[txtrList.first, tmpTxtr]; -- reverse list to copy ENDLOOP; FOR txtrList: LORA _ tmpTxtr, txtrList.rest UNTIL txtrList = NIL DO WITH txtrList.first SELECT FROM texture: REF TextureMap => { -- mapped texture fileName: ROPE _ NARROW[ GetProp[texture.props, $FileName] ]; coordType: ATOM _ NARROW[ GetProp[texture.props, $CoordType] ]; coords: REF _ GetProp[texture.props, $Coords]; IF coordType = NIL THEN coordType _ $NoCoords; line _ Rope.Cat[ " TextureMap: ", fileName, " ", Convert.RopeFromAtom[texture.type] ]; line _ Rope.Cat[line, " ", Convert.RopeFromAtom[coordType], " " ]; SELECT coordType FROM $FromVtxNos, $FromNormals => { argList: LIST OF REAL _ NARROW[coords]; WHILE argList # NIL DO line _ Rope.Cat[line, Convert.RopeFromReal[argList.first], " " ]; argList _ argList.rest; ENDLOOP; }; ENDCASE => { SIGNAL ThreeDBasics.Error[ [$Mismatch, "Unknown texture coordType"] ]; line _ NIL; -- kill line to drop texture }; IO.PutRope[ output, Rope.Cat[line, "\n"] ]; IF GetProp[shape.fixedProps, $TextureScale] # NIL THEN { textureScale: REF Triple _ NARROW[ GetProp[shape.fixedProps, $TextureScale] ]; IO.PutRope[ output, Rope.Cat[ " Scale: ", Vec3toRope[textureScale.x, textureScale.y, textureScale.z], "\n" ] ]; } ELSE IO.PutRope[ output, Rope.Cat[ " Scale: 1.0 1.0 1.0 \n" ] ]; }; txtrFn: REF TextureFunction => { -- solid texture IO.PutRope[ output, Rope.Cat[ " TextureFunction: ", Convert.RopeFromAtom[txtrFn.name], "\n" ] ]; }; ENDCASE => SIGNAL ThreeDBasics.Error[ [$Mismatch, "Unknown texture type"] ]; ENDLOOP; }; }; }; ENDLOOP; -- end loop for all shapes }; SetTexture: PUBLIC PROC [shape: REF ShapeInstance, textures: REF PairSequence] ~ { IF shape.shadingClass.loadShapeAux = NIL -- get default if not previously specified THEN ThreeDBasics.LoadShadingClass[shape, $MappedAndSolidTexture]; [] _ shape.shadingClass.loadShapeAux[ NIL, shape, textures ]; -- now load aux array }; SetVertexProps: PUBLIC PROC [ shape: REF ShapeInstance, normals, colors, textures, transmittance: BOOL] ~ { IF normals THEN shape.fixedProps _ Atom.PutPropOnList[shape.fixedProps, $VertexNormalsInFile, $ok]; IF colors THEN shape.fixedProps _ Atom.PutPropOnList[shape.fixedProps, $VertexColorsInFile, $ok]; IF textures THEN shape.fixedProps _ Atom.PutPropOnList[shape.fixedProps, $VertexTextureInFile, $ok]; IF transmittance THEN shape.fixedProps _ Atom.PutPropOnList[shape.fixedProps, $VertexTransmittanceInFile, $ok]; }; ReadShape: PUBLIC PROC[shape: REF ShapeInstance, fileName: ROPE] ~ { s: G3dIO.Shape _ G3dIO.ShapeFromFile[fileName]; shape.insideVisible _ s.insideVisible; shape.fixedProps _ s.props; shape.vertex _ NEW[VertexSequence[s.nVertices]]; shape.shade _ NEW[ShadingSequence[s.nVertices]]; shape.vertex.length _ shape.shade.length _ s.nVertices; SetVertexProps[shape, s.vertexNormals#NIL, s.vertexColors#NIL, s.vertexTextures#NIL, s.vertexTransmits#NIL]; IF s.vertexTextures # NIL AND shape.shadingClass.loadShapeAux = NIL THEN ThreeDBasics.LoadShadingClass[shape, $MappedAndSolidTexture]; IF s.vertexTextures # NIL THEN SetTexture[shape, s.vertexTextures]; FOR n: CARDINAL IN [0..s.nVertices) DO v: REF VertexInfo _ NEW[VertexInfo]; [v.coord.x, v.coord.y, v.coord.z] _ s.vertexPositions[n]; IF s.vertexNormals # NIL THEN [v.shade.xn, v.shade.yn, v.shade.zn]_s.vertexNormals[n]; IF s.vertexColors # NIL THEN [v.shade.r, v.shade.g, v.shade.b] _ s.vertexColors[n]; IF s.vertexTransmits # NIL THEN v.shade.t _ s.vertexTransmits[n]; IF s.vertexTextures # NIL THEN v.aux _ NEW[Pair _ s.vertexTextures[n]]; shape.vertex[n] _ NEW[Vertex _ v.coord]; -- load vertex array shape.shade[n] _ NEW[ShadingValue _ v.shade]; -- load shading array ENDLOOP; { AddFixedProp: PROC [key: ATOM] ~ { shape.fixedProps _ Atom.PutPropOnList[shape.fixedProps, key, patchInfos]; }; NewPatch: PROC [nPatch, nSides: NAT] RETURNS [patch: REF PtrPatch] ~ { patch _ surfaces[nPatch] _ NEW[PtrPatch _ [ vtxPtr: NEW[NatSequence[nSides]], oneSided: NOT s.insideVisible, type: shape.class.type, nVtces: nSides]]; }; SetShadingValue: PROC [sv: REF ThreeDBasics.ShadingValue, nFace: NAT] ~ { IF s.faceTransmits # NIL THEN sv.t _ s.faceTransmits[nFace]; IF s.faceColors # NIL THEN [sv.r, sv.g, sv.b] _ s.faceColors[nFace]; IF s.faceNormals # NIL THEN [sv.xn, sv.yn, sv.zn] _ s.faceNormals[nFace]; }; surfaces: REF PtrPatchSequence _ shape.surface _ NEW[PtrPatchSequence[s.nPolygons]]; patchInfos: REF ShadingSequence _ shape.shadingClass.patchShade; ThreeDBasics.LoadSurfaceType[shape, IF s.type=poly THEN $ConvexPolygon ELSE $Bezier]; IF patchInfos = NIL OR patchInfos.maxLength < s.nPolygons THEN { shape.shadingClass.patchShade _ patchInfos _ NEW[ShadingSequence[s.nPolygons]]; FOR i: NAT IN [0..s.nPolygons) DO patchInfos[i] _ NEW[ThreeDBasics.ShadingValue]; ENDLOOP; }; patchInfos.length _ shape.numSurfaces _ surfaces.length _ s.nPolygons; IF s.faceTransmits # NIL THEN AddFixedProp[$PatchTransmittancesInFile]; IF s.faceColors # NIL THEN AddFixedProp[$PatchColorsInFile]; IF s.faceNormals # NIL THEN AddFixedProp[$PatchNormalsInFile]; FOR n: NAT IN [0..s.nPolygons) DO poly: REF NatSequence _ s.polygons[n]; patch: REF PtrPatch _ surfaces[n] _ NewPatch[n, poly.length]; SetShadingValue[patchInfos[n], n]; FOR i: NAT IN [0..poly.length) DO patch.vtxPtr[i] _ poly[i]; ENDLOOP; ENDLOOP; }; }; CloneShape: PUBLIC PROC[newshape, oldShape: REF ShapeInstance] ~ { -- copy shape data newSurface, oldSurface: REF PtrPatchSequence; newshape.class _ oldShape.class; newshape.shadingClass _ NEW[ShadingClass _ oldShape.shadingClass^]; newshape.shadingClass.texture _ NIL; -- restore default values to new shape newshape.shadingClass.color _ [R: 0.7, G: 0.7, B: 0.7]; newshape.shadingClass.shininess _ 0.0; newshape.shadingClass.transmittance _ 0.0; newshape.insideVisible _ oldShape.insideVisible; newshape.centroid _ oldShape.centroid; newshape.boundingRadius _ oldShape.boundingRadius; newshape.vertex _ NEW[ VertexSequence[oldShape.vertex.length] ]; newshape.vertex.length _ oldShape.vertex.length; newshape.shade _ NEW[ ShadingSequence[oldShape.shade.length] ]; newshape.shade.length _ oldShape.shade.length; FOR i: NAT IN [0..oldShape.vertex.length) DO -- copy vertices and shades newshape.vertex[i] _ NEW [ Vertex _ oldShape.vertex[i]^ ]; newshape.shade[i] _ NEW [ ShadingValue _ oldShape.shade[i]^ ]; ENDLOOP; newshape.numSurfaces _ oldShape.numSurfaces; newshape.surface _ NEW[ PtrPatchSequence[oldShape.numSurfaces] ]; newSurface _ NARROW[newshape.surface, REF PtrPatchSequence]; newSurface.length _ oldShape.numSurfaces; oldSurface _ NARROW[oldShape.surface, REF PtrPatchSequence]; FOR i: NAT IN [0..oldShape.numSurfaces) DO -- copy surface IF newSurface[i] = NIL THEN newSurface[i] _ NEW[PtrPatch]; newSurface[i].vtxPtr _ NEW[NatSequence[oldSurface[i].nVtces]]; newSurface[i].nVtces _ oldSurface[i].nVtces; newSurface[i].type _ oldSurface[i].type; newSurface[i].oneSided _ oldSurface[i].oneSided; FOR j: NAT IN [0..oldSurface[i].nVtces) DO newSurface[i].vtxPtr[j] _ oldSurface[i].vtxPtr[j]; ENDLOOP; ENDLOOP; newshape.fixedProps _ oldShape.fixedProps; -- copy unchanging props newshape.props _ NIL; -- copy changeable props FOR list: Atom.PropList _ oldShape.props, list.rest UNTIL list = NIL DO element: Atom.DottedPair _ NEW[Atom.DottedPairNode _ list.first^]; newshape.props _ CONS[element, newshape.props]; ENDLOOP; newshape.shadingProps _ NIL; -- copy shading props FOR list: Atom.PropList _ oldShape.shadingProps, list.rest UNTIL list = NIL DO element: Atom.DottedPair _ NEW[Atom.DottedPairNode _ list.first^]; newshape.shadingProps _ CONS[element, newshape.shadingProps]; ENDLOOP; IF newshape.shadingClass.patchShade # NIL THEN { -- copy facet info polyShades: REF ShadingSequence _ newshape.shadingClass.patchShade; newpolyShades: REF ShadingSequence _ NEW[ ShadingSequence[ polyShades.length ] ]; FOR i: NAT IN [0..polyShades.length) DO newpolyShades[i] _ NEW[ShadingValue _ polyShades[i]^ ]; ENDLOOP; newpolyShades.length _ polyShades.length; newshape.shadingClass.patchShade _ newpolyShades; }; }; AddShapeAt: PUBLIC PROC[context: REF Context, shapeName: ROPE, fileName: ROPE, position: Triple _ [0.,0.,0.] ] ~ { shape: REF ShapeInstance _ NewShape[shapeName]; cloneShape: REF ShapeInstance _ NIL; shape.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 CloneShape[ shape, cloneShape ] ELSE ReadShape[ shape, shape.fileName ]; AddShape[context, shape]; PlaceShape[context, shape.name, position]; }; WriteShape: PUBLIC PROC[ context: REF Context, shapeName: ROPE, fileName: ROPE, transformed: BOOL _ FALSE, xyz: BOOL _ TRUE, normal, color, trans, texture, polyClr: BOOL _ FALSE] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; stream: IO.STREAM _ FS.StreamOpen[Rope.Cat[fileName, ".shape"], $create]; numFields: NAT _ 0; fields: REF FieldSequence _ NEW[FieldSequence[1]]; vertices: REF VertexInfoSequence _ NEW[ VertexInfoSequence[shape.vertex.length] ]; auxData: REF _ GetProp[shape.shadingProps, $AuxiliaryVtxData ]; surfaceType: ROPE _ IF shape.class.type = $ConvexPolygon THEN "Polygons" ELSE "Patches"; insideVisible: ROPE _ IF shape.insideVisible THEN " InsideVisible" ELSE NIL; stream.PutRope[ Rope.Cat[fileName, ".shape\n\n"] ]; -- write title on first line stream.PutRope[ Rope.Cat["SurfaceType ~ ", surfaceType, insideVisible, "\n\n"] ]; -- surface IF shape.positionInValid THEN ThreeDBasics.SetPosition[shape]; -- set position matrix FOR i: NAT IN [0..shape.vertex.length) DO vertices[i] _ NEW[VertexInfo]; vertices[i].coord _ shape.vertex[i]^; IF transformed THEN { OPEN vertices[i].coord; [ [x, y, z] ] _ Transform[ [x, y, z], shape.position ]; }; vertices[i].shade _ shape.shade[i]^; IF transformed AND normal THEN { OPEN vertices[i].shade; [ [xn, yn, zn] ] _ TransformVec[ [xn, yn, zn], shape.position ]; }; IF auxData # NIL THEN { data: LORA _ LIST[ auxData, NEW[INTEGER _ i] ]; vertices[i]^ _ shape.shadingClass.loadVtxAux[ NIL, vertices[i]^, data ]; }; ENDLOOP; vertices.length _ shape.vertex.length; WriteVertexInfoSequence[ stream, "Vertices", vertices, xyz, normal, color, trans, texture ]; IF polyClr THEN { color: REF ShadingSequence _ shape.shadingClass.patchShade; tripleSeq: REF TripleSequence _ NEW[ TripleSequence[color.length] ]; tripleSeq.length _ color.length; FOR i: NAT IN [0..color.length) DO tripleSeq[i].x _ color[i].r; tripleSeq[i].y _ color[i].g; tripleSeq[i].z _ color[i].b; ENDLOOP; fields _ NEW[FieldSequence[2]]; fields[0] _ NEW[Field]; fields[0].sequence _ tripleSeq; fields[0].type _ triple; fields[0].id _ "rgbColor"; numFields _ 1; }; { surfels: REF NatTable _ NEW[NatTable[shape.numSurfaces] ]; patches: REF PtrPatchSequence _ NARROW[shape.surface, REF PtrPatchSequence]; FOR i: NAT IN [0..shape.numSurfaces) DO surfels[i] _ NEW[ NatSequence[patches[i].nVtces] ]; FOR j: NAT IN [0..patches[i].nVtces) DO surfels[i][j] _ patches[i].vtxPtr[j]; ENDLOOP; surfels[i].length _ patches[i].nVtces; ENDLOOP; surfels.length _ shape.numSurfaces; fields[numFields] _ NEW[Field]; fields[numFields].sequence _ surfels; fields[numFields].type _ nats; fields[numFields].id _ "vertices"; fields.length _ numFields + 1; }; G3dIO.WriteFields[stream, surfaceType, fields]; IO.Close[stream]; }; WriteVertexInfoSequence: PUBLIC PROC [ stream: IO.STREAM, keyword: ROPE, vertexInfo: REF VertexInfoSequence, xyz, normal, color, trans, texture: BOOL _ TRUE] ~ { IF vertexInfo # NIL THEN { vi: REF VertexInfoSequence _ vertexInfo; IO.PutF[stream, "%g~ ", IO.rope[keyword]]; IF xyz THEN IO.PutF[stream, "xyzCoords: triple"]; IF normal THEN IO.PutF[stream, ", normalVec: triple"]; IF color THEN IO.PutF[stream, ", rgbColor: triple"]; IF trans THEN IO.PutF[stream, ", transmittance: real"]; IF texture THEN IO.PutF[stream, ", textureCoords: pair"]; IO.PutF[stream, "\n\n"]; FOR n: NAT IN [0..vertexInfo.length) DO IF xyz THEN IO.PutF[stream, "%9g %9g %9g\t\t", IO.real[vi[n].coord.x], IO.real[vi[n].coord.y], IO.real[vi[n].coord.z]]; IF normal THEN IO.PutF[stream, "%9g %9g %9g\t\t", IO.real[vi[n].shade.xn], IO.real[vi[n].shade.yn], IO.real[vi[n].shade.zn]]; IF color THEN IO.PutF[stream, "%9g %9g %9g\t\t", IO.real[vi[n].shade.r], IO.real[vi[n].shade.g], IO.real[vi[n].shade.b]]; IF trans THEN IO.PutF[stream, "%9g\t\t", IO.real[vi[n].shade.t]]; IF texture THEN { txtr: REF Pair _ NARROW[ vi[n].aux ]; IO.PutF[stream, "%9g %9g %9g", IO.real[txtr.x], IO.real[txtr.y] ]; }; IO.PutF[stream, "\n"]; ENDLOOP; }; }; NewShape: PUBLIC PROC[ name: ROPE, type: ATOM _ $ConvexPolygon ] RETURNS[REF ShapeInstance] ~ { shape: REF ShapeInstance _ NEW [ShapeInstance ]; shape.name _ name; ThreeDBasics.LoadSurfaceType[shape, type]; -- load class structures RETURN [shape]; }; ShapeFromData: PUBLIC PROC[ name: Rope.ROPE _ NIL, surface: REF NatTable, vertices, normals: REF TripleSequence _ NIL, colors: REF RGBSequence _ NIL, trnsmttnce: REF RealSequence _ NIL, txtrCoord: REF PairSequence _ NIL, insideVisible, faceted: BOOL _ FALSE, type: ATOM _ $ConvexPolygon ] RETURNS[REF ShapeInstance] ~ { shape: REF ShapeInstance _ NewShape[name]; shapeSurface: REF PtrPatchSequence; IF vertices = NIL THEN ThreeDBasics.Error[[$Fatal, "Vertices needed for shape"]]; IF surface = NIL THEN ThreeDBasics.Error[[$Fatal, "Surface needed for shape"]]; shape.vertex _ NEW[VertexSequence[vertices.length]]; FOR i: NAT IN [0..vertices.length) DO OPEN shape.vertex[i]; x _ vertices[i].x; y _ vertices[i].y; z _ vertices[i].z; ENDLOOP; IF normals # NIL THEN { shape.shade _ NEW[ShadingSequence[normals.length]]; FOR i: NAT IN [0..normals.length) DO OPEN shape.shade[i]; xn _ normals[i].x; yn _ normals[i].y; zn _ normals[i].z; ENDLOOP; }; IF normals.length > vertices.length / 2 THEN shape.fixedProps _ PutProp[shape.fixedProps, $VertexNormalsInFile, $ok ]; IF faceted = FALSE AND colors # NIL THEN { FOR i: NAT IN [0..colors.length) DO OPEN shape.shade[i]; r _ colors[i].R; g _ colors[i].G; b _ colors[i].B; ENDLOOP; IF colors.length > vertices.length / 2 THEN shape.fixedProps _ PutProp[shape.fixedProps, $VertexColorsInFile, $ok]; IF trnsmttnce # NIL THEN FOR i: NAT IN [0..trnsmttnce.length) DO shape.shade[i].t _ trnsmttnce[i]; ENDLOOP; IF trnsmttnce.length > vertices.length / 2 THEN shape.fixedProps _ PutProp[ shape.fixedProps, $VertexTransmittanceInFile, $ok ]; }; shape.numSurfaces _ surface.length; shape.surface _ shapeSurface _ NEW[ PtrPatchSequence[shape.numSurfaces] ]; shape.insideVisible _ insideVisible; FOR n: NAT IN [0..shape.numSurfaces) DO nVertices: INTEGER _ surface[n].length; shapeSurface[n] _ NEW[PtrPatch _ [ vtxPtr: NEW[NatSequence[nVertices]], oneSided: NOT insideVisible, type: type, nVtces: nVertices ]]; FOR i: NAT IN [0..nVertices) DO shapeSurface[n].vtxPtr[i] _ surface[n][i]; ENDLOOP; ENDLOOP; IF txtrCoord # NIL THEN { IF shape.shadingClass.loadShapeAux = NIL THEN ThreeDBasics.LoadShadingClass[ shape, $MappedAndSolidTexture ]; [] _ shape.shadingClass.loadShapeAux[ NIL, shape, txtrCoord ]; -- load aux array }; RETURN[shape]; }; ShapeFromRope: PUBLIC PROC[ name: Rope.ROPE _ NIL, message: Rope.ROPE, color: Rope.ROPE _ NIL, size: REAL _ 0.5, font: Rope.ROPE _ NIL ] RETURNS[REF ShapeInstance] ~ { shape: REF ShapeInstance _ NewShape[name]; shapeSurface: REF PtrPatchSequence; shape.fixedProps _ Atom.PutPropOnList[shape.fixedProps, $RopeMessage, message ]; shape.fixedProps _ Atom.PutPropOnList[shape.fixedProps, $RopeFont, font ]; ThreeDBasics.LoadSurfaceType[ shape, $RopeShape ]; ThreeDBasics.LoadShadingClass[ shape, $NoShading ]; shape.shadingClass.color _ ImagerColorFns.RGBFromHSL[ NamedColors.RopeToHSL[color] ]; shape.vertex _ NEW[VertexSequence[2]]; shape.vertex[0] _ NEW[Vertex]; shape.vertex[1] _ NEW[Vertex]; shape.vertex[1].z _ size; shape.vertex.length _ 2; shape.shade _ NEW[ShadingSequence[2]]; shape.shade[0] _ NEW[ShadingValue]; shape.shade[1] _ NEW[ShadingValue]; shape.surface _ shapeSurface _ NEW[ PtrPatchSequence[1] ]; shapeSurface[0] _ NEW[PtrPatch _ [ vtxPtr: NEW[NatSequence[3]], oneSided: FALSE, type: shape.class.type, nVtces: 3 ]]; shapeSurface[0].vtxPtr[0] _ shapeSurface[0].vtxPtr[2] _ 0; shapeSurface[0].vtxPtr[1] _ 1; shape.numSurfaces _ 1; RETURN[shape]; }; ChangeRopeMessage: PUBLIC PROC[ context: REF Context, shapeName: ROPE, newMessage: Rope.ROPE ] ~ { shape: REF ShapeInstance _ FindShape[context, shapeName]; shape.fixedProps _ Atom.PutPropOnList[shape.fixedProps, $RopeMessage, newMessage ]; }; FindShape: PUBLIC PROC[ context: REF Context, shapeName: ROPE ] RETURNS[REF ShapeInstance] ~ { IF context.shapes = NIL THEN RETURN [NIL]; FOR i: NAT IN [0..context.shapes.length) DO IF Rope.Equal[ shapeName, context.shapes[i].name, FALSE ] THEN RETURN[context.shapes[i]]; ENDLOOP; SIGNAL ThreeDBasics.Error[[$MisMatch, "No such shape name"]]; RETURN [NIL]; }; AddShape: PUBLIC PROC[ context: REF Context, shape: REF ShapeInstance ] ~ { newSet: REF ShapeSequence; newPos: NAT _ 0; IF context.shapes = NIL THEN { newSet _ NEW [ShapeSequence[8]]; newPos _ 0; } ELSE { newSet _ context.shapes; newPos _ context.shapes.length; }; IF INT[newSet.maxLength] < newPos + 1 THEN { newSet _ NEW [ ShapeSequence[context.shapes.maxLength + 8] ]; FOR i: NAT IN [0..context.shapes.length) DO newSet[i] _ context.shapes[i]; ENDLOOP; }; newSet[newPos] _ shape; context.shapes _ newSet; context.shapes.length _ newPos+1; }; DeleteShape: PUBLIC PROC[ context: REF Context, shapeName: ROPE ] ~ { found: BOOLEAN _ FALSE; IF context.shapes = NIL THEN { SIGNAL ThreeDBasics.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 SIGNAL ThreeDBasics.Error[[$MisMatch, "Can't delete - not there"]]; }; CopyShape: PUBLIC PROC[ context: REF Context, shapeName, newName: ROPE _ NIL ] RETURNS[REF ShapeInstance] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; RETURN[ CopyShapeDirect[shape, newName] ]; }; CopyShapeDirect: PUBLIC PROC[ shape: REF ShapeInstance, newName: ROPE _ NIL ] RETURNS[REF ShapeInstance] ~ { newShape: REF ShapeInstance _ NEW[ShapeInstance]; newShape^ _ shape^; IF newName # NIL THEN newShape.name _ newName; IF shape.vertex # NIL THEN { newShape.vertex _ NEW[ VertexSequence[shape.vertex.length] ]; FOR i: NAT IN [0..shape.vertex.length) DO IF shape.vertex[i] # NIL THEN newShape.vertex[i] _ NEW[Vertex _ shape.vertex[i]^ ]; ENDLOOP; newShape.vertex.length _ shape.vertex.length }; IF shape.shade # NIL THEN { newShape.shade _ NEW[ ShadingSequence[shape.shade.length] ]; FOR i: NAT IN [0..shape.shade.length) DO IF shape.shade[i] # NIL THEN newShape.shade[i] _ NEW[ShadingValue _ shape.shade[i]^]; ENDLOOP; newShape.shade.length _ shape.shade.length }; newShape.props _ newShape.shadingProps _ NIL; -- copy props FOR list: Atom.PropList _ shape.props, list.rest UNTIL list = NIL DO element: Atom.DottedPair _ NEW[Atom.DottedPairNode _ list.first^]; newShape.props _ CONS[element, newShape.props]; ENDLOOP; FOR list: Atom.PropList _ shape.shadingProps, list.rest UNTIL list = NIL DO element: Atom.DottedPair _ NEW[Atom.DottedPairNode _ list.first^]; newShape.shadingProps _ CONS[element, newShape.shadingProps]; ENDLOOP; RETURN[newShape]; }; PlaceShape: PUBLIC PROC[ context: REF Context, shapeName: ROPE, location: Triple ] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; shape.location _ location; shape.positionInValid _ TRUE; shape.vtcesInValid _ TRUE; shape.shadingInValid _ TRUE; }; MoveShape: PUBLIC PROC[ context: REF Context, shapeName: ROPE, delta: Triple ] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; shape.location _ G3dVector.Add[shape.location, delta]; shape.positionInValid _ TRUE; shape.vtcesInValid _ TRUE; shape.shadingInValid _ TRUE; }; OrientShape: PUBLIC PROC[ context: REF Context, shapeName: ROPE, axis: Triple] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; shape.orientation _ axis; shape.positionInValid _ TRUE; shape.vtcesInValid _ TRUE; shape.shadingInValid _ TRUE; }; RotateShapeLocal: PUBLIC PROC[ context: REF Context, shapeName: ROPE, theta: REAL] ~{ shape: REF ShapeInstance _ FindShape[ context, shapeName ]; shape.rotation _ theta; shape.positionInValid _ TRUE; shape.vtcesInValid _ TRUE; shape.shadingInValid _ TRUE; }; RotateShape: PUBLIC PROC[ context: REF Context, shapeName: ROPE, axisBase, axisEnd: Triple, theta: REAL ] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; shape.axisBase _ axisBase; shape.axisEnd _ axisEnd; shape.rotation _ theta; shape.positionInValid _ TRUE; shape.vtcesInValid _ TRUE; shape.shadingInValid _ TRUE; }; Hide: PUBLIC PROC[context: REF Context, shapeName: ROPE] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; shape.props _ PutProp[shape.props, $Hidden, $ok]; }; Reveal: PUBLIC PROC[context: REF Context, shapeName: ROPE] ~ { -- undo Hide shape: REF ShapeInstance _ FindShape[ context, shapeName ]; shape.props _ Atom.RemPropFromList[shape.props, $Hidden]; }; SetColor: PUBLIC PROC[context: REF Context, shapeName: ROPE, color: RGB] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.shadingClass.color _ color; shape.shadingInValid _ TRUE; }; }; SetFaceted: PUBLIC PROC[context: REF Context, shapeName: ROPE] ~ { -- default style shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.shadingClass.shadingType _ $Faceted; shape.shadingInValid _ TRUE; }; }; SetSmooth: PUBLIC PROC[context: REF Context, shapeName: ROPE] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.shadingClass.shadingType _ $Smooth; shape.shadingInValid _ TRUE; }; }; SetLines: PUBLIC PROC[context: REF Context, shapeName: ROPE] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.shadingClass.shadingType _ $Lines; shape.shadingInValid _ TRUE; }; }; SetShadedLines: PUBLIC PROC[context: REF Context, shapeName: ROPE] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.shadingClass.shadingType _ $ShadedLines; shape.shadingInValid _ TRUE; }; }; SetHiddenLines: PUBLIC PROC[context: REF Context, shapeName: ROPE] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.shadingClass.shadingType _ $HiddenLines; shape.shadingInValid _ TRUE; }; }; SetNormaledLines: PUBLIC PROC[context: REF Context, shapeName: ROPE] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.shadingClass.shadingType _ $NormaledLines; shape.shadingInValid _ TRUE; }; }; SetShiny: PUBLIC PROC[context: REF Context, shapeName: ROPE, shininess: REAL _ 50.0] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.shadingClass.shininess _ shininess; shape.shadingInValid _ TRUE; }; }; SetDull: PUBLIC PROC[context: REF Context, shapeName: ROPE] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.shadingClass.shininess _ 0.0; shape.shadingInValid _ TRUE; }; }; SetTransparent: PUBLIC PROC[context: REF Context, shapeName: ROPE, t: REAL _ 0.8] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.shadingClass.transmittance _ t; IF NOT shape.insideVisible -- set prop for recovery of insideVisible if later made opaque THEN shape.fixedProps _ PutProp[shape.fixedProps, $Closed, $ok]; IncludeBackFaces[context, shapeName]; shape.shadingInValid _ TRUE; }; }; SetOpaque: PUBLIC PROC[context: REF Context, shapeName: ROPE] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.shadingClass.transmittance _ 0.0; IF GetProp[shape.fixedProps, $Closed] # NIL THEN RemoveBackFaces[context, shapeName]; shape.shadingInValid _ TRUE; }; }; IncludeBackFaces: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.insideVisible _ TRUE; WITH shape.surface SELECT FROM shapeSurface: REF PtrPatchSequence => FOR i: NAT IN [0..shapeSurface.length) DO shapeSurface[i].oneSided _ NOT shape.insideVisible; ENDLOOP; ENDCASE; }; }; RemoveBackFaces: PUBLIC PROC[context: REF Context, shapeName: Rope.ROPE] ~ { shape: REF ShapeInstance _ FindShape[ context, shapeName ]; IF shape # NIL THEN { shape.insideVisible _ FALSE; WITH shape.surface SELECT FROM shapeSurface: REF PtrPatchSequence => FOR i: NAT IN [0..shapeSurface.length) DO shapeSurface[i].oneSided _ NOT shape.insideVisible; ENDLOOP; ENDCASE; }; }; END. .. SetTexture: PUBLIC PROC [shape: REF ShapeInstance, textures: REF PairSequence] ~ { ThreeDBasics.LoadShadingClass[shape, $MappedAndSolidTexture]; -- need this line? shape.shadingProps _ Atom.PutPropOnList[shape.shadingProps, $AuxiliaryVtxData, textures]; }; ReadShape: PUBLIC PROC[shape: REF ShapeInstance, fileName: ROPE] ~ { stream: IO.STREAM _ FS.StreamOpen[ fileName: fileName ]; surfaceType: ATOM; firstVtxNo: NAT _ 0; -- some files count from 0 some from 1 surfaceInfo: ROPE; surfaceInfo _ G3dIO.ReadRope[ stream, "SurfaceType", TRUE ! G3dIO.Error => CONTINUE ]; surfaceType _ $ConvexPolygon; -- default shape.insideVisible _ FALSE; IF surfaceInfo # NIL THEN { IF Rope.Find[surfaceInfo, "Polygon", 0, FALSE] >= 0 THEN surfaceType _ $ConvexPolygon; IF Rope.Find[surfaceInfo, "Bezier", 0, FALSE] >= 0 THEN surfaceType _ $Bezier; IF Rope.Find[surfaceInfo, "InsideVisible", 0, FALSE] >= 0 THEN shape.insideVisible _ TRUE; IF Rope.Find[surfaceInfo, "CountFromOne", 0, FALSE] >= 0 THEN firstVtxNo _ 1; }; ThreeDBasics.LoadSurfaceType[ shape, surfaceType ]; { vertices: REF VertexInfoSequence; fields: REF FieldSequence; [vertices, fields] _ ReadVertexInfoSequence[stream, "Vertices"]; shape.vertex _ NEW[ VertexSequence[vertices.length] ]; shape.vertex.length _ vertices.length; shape.shade _ NEW[ ShadingSequence[vertices.length] ]; shape.shade.length _ vertices.length; FOR i: NAT IN [0..vertices.length) DO -- load vertex and shading arrays shape.vertex[i] _ NEW[ Vertex _ vertices[i].coord ]; shape.shade[i] _ NEW[ ShadingValue _ vertices[i].shade ]; ENDLOOP; FOR i: NAT IN [0..fields.length) DO SELECT TRUE FROM Rope.Equal[fields[i].id, "normalVec", FALSE] => -- vertex normals read shape.fixedProps _ PutProp[ shape.fixedProps, $VertexNormalsInFile, $ok ]; Rope.Equal[fields[i].id, "rgbColor", FALSE] => -- vertex colors read shape.fixedProps _ PutProp[ shape.fixedProps, $VertexColorsInFile, $ok ]; Rope.Equal[fields[i].id, "transmittance", FALSE] => -- vertex transmittance read shape.fixedProps _ PutProp[ shape.fixedProps, $VertexTransmittanceInFile, $ok ]; Rope.Equal[fields[i].id, "textureCoords", FALSE] => { -- texture coordinates read IF shape.shadingClass.loadShapeAux = NIL THEN ThreeDBasics.LoadShadingClass[ shape, $MappedAndSolidTexture ]; [] _ shape.shadingClass.loadShapeAux[ NIL, shape, vertices ]; -- load aux array shape.fixedProps _ PutProp[shape.fixedProps, $VertexTextureInFile, $ok ] }; ENDCASE; ENDLOOP; }; { keyWord: ROPE _ IF shape.class.type = $ConvexPolygon THEN "Polygons" ELSE "Patches"; fields: REF FieldSequence _ G3dIO.ReadFields[stream, keyWord]; GetPatchInfo: PROC[shape: REF ShapeInstance] RETURNS[p: REF ShadingSequence] ~ { p _ shape.shadingClass.patchShade; IF p = NIL THEN { p _ NEW[ShadingSequence[shape.numSurfaces] ]; p.length _ shape.numSurfaces; FOR i: NAT IN [0..shape.numSurfaces) DO p[i] _ NEW[ShadingValue]; ENDLOOP; shape.shadingClass.patchShade _ p; }; }; shape.numSurfaces _ 0; FOR n: NAT IN [0..fields.length) DO patchInfo: REF ShadingSequence; SELECT fields[n].type FROM integer => { intSeq: REF IntegerSequence _ NARROW[fields[n].sequence]; shape.numSurfaces _ intSeq.length; SELECT TRUE FROM Rope.Equal[fields[n].id, "index", FALSE] => {}; ENDCASE => { key: ATOM _ Convert.AtomFromRope[fields[n].id]; -- special, put on proplist shape.fixedProps _ PutProp[shape.fixedProps, key, intSeq ]; }; }; real => { realSeq: REF RealSequence _ NARROW[fields[n].sequence]; shape.numSurfaces _ realSeq.length; patchInfo _ GetPatchInfo[shape]; SELECT TRUE FROM Rope.Equal[fields[n].id, "transmittance", FALSE] => { FOR i: NAT IN [0..realSeq.length) DO patchInfo[i].t _ realSeq[i]; ENDLOOP; shape.fixedProps _ PutProp[ shape.fixedProps, $PatchTransmittancesInFile, patchInfo ]; }; ENDCASE => { key: ATOM _ Convert.AtomFromRope[fields[n].id]; -- special, put on proplist shape.fixedProps _ PutProp[shape.fixedProps, key, realSeq ]; }; }; triple => { tripleSeq: REF TripleSequence _ NARROW[fields[n].sequence]; shape.numSurfaces _ tripleSeq.length; patchInfo _ GetPatchInfo[shape]; SELECT TRUE FROM Rope.Equal[fields[n].id, "rgbColor", FALSE] => { FOR i: NAT IN [0..tripleSeq.length) DO patchInfo[i].r _ tripleSeq[i].x; patchInfo[i].g _ tripleSeq[i].y; patchInfo[i].b _ tripleSeq[i].z; ENDLOOP; shape.fixedProps _ PutProp[shape.fixedProps, $PatchColorsInFile, patchInfo ]; }; Rope.Equal[fields[n].id, "normalVec", FALSE] => { FOR i: NAT IN [0..tripleSeq.length) DO patchInfo[i].xn _ tripleSeq[i].x; patchInfo[i].yn _ tripleSeq[i].y; patchInfo[i].zn _ tripleSeq[i].z; ENDLOOP; shape.fixedProps _ PutProp[shape.fixedProps, $PatchNormalsInFile, patchInfo ]; }; ENDCASE => { key: ATOM _ Convert.AtomFromRope[fields[n].id]; -- special, put on proplist shape.fixedProps _ PutProp[shape.fixedProps, key, tripleSeq ]; }; }; nats => { -- get the surface elements surface: REF PtrPatchSequence; surfels: REF NatTable _ NARROW[fields[n].sequence]; shape.numSurfaces _ surfels.length; shape.surface _ NEW[ PtrPatchSequence[shape.numSurfaces] ]; surface _ NARROW[shape.surface, REF PtrPatchSequence]; surface.length _ shape.numSurfaces; FOR i: NAT IN [0..shape.numSurfaces) DO IF surface[i] = NIL THEN surface[i] _ NEW[PtrPatch]; surface[i].vtxPtr _ NEW[NatSequence[surfels[i].length]]; surface[i].nVtces _ surfels[i].length; surface[i].type _ shape.class.type; surface[i].oneSided _ NOT shape.insideVisible; FOR j: NAT IN [0..surfels[i].length) DO surface[i].vtxPtr[j] _ surfels[i][j] - firstVtxNo; -- counting from zero ENDLOOP; ENDLOOP; }; ENDCASE => { key: ATOM _ Convert.AtomFromRope[fields[n].id]; -- special, put on proplist shape.fixedProps _ PutProp[shape.fixedProps, key, fields[n].sequence ]; }; ENDLOOP; }; }; ReadVertexInfoSequence: PROC [ stream: IO.STREAM, keyword: ROPE, circularSearch: BOOL _ FALSE] RETURNS [REF VertexInfoSequence, REF FieldSequence] ~ { fields: REF FieldSequence; nElements: INTEGER; -- number of lines to convert vIS: REF VertexInfoSequence; types: ARRAY [0..5) OF G3dIO.FieldType _ [triple, triple, triple, real, pair]; ids: ARRAY [0..5) OF ROPE _ [ "xyzCoords", "normalVec", "rgbColor", "transmittance", "textureCoords" ]; line: G3dIO.Line _ G3dIO.FindKeyWord[stream, keyword, circularSearch]; IF G3dIO.NWordsInRope[line.rope] > 1 THEN fields _ G3dIO.InitializeFields[line] ELSE { fields _ NEW[FieldSequence[5]]; FOR n: NAT IN [0..5) DO fields[n].id _ ids[n]; fields[n].type _ types[n]; ENDLOOP; }; nElements _ G3dIO.NumberOfLinesToConvert[stream]; vIS _ NEW[VertexInfoSequence[nElements]]; FOR n: NAT IN [0..nElements) DO vIS[n] _ NEW[VertexInfo]; line _ G3dIO.GetDataLine[stream]; FOR i: NAT IN [0..fields.length) DO SELECT TRUE FROM Rope.Equal[fields[i].id, "xyzCoords", FALSE] => [[vIS[n].coord.x, vIS[n].coord.y, vIS[n].coord.z]] _ G3dIO.GetTriple[line]; Rope.Equal[fields[i].id, "normalVec", FALSE] => [[vIS[n].shade.xn, vIS[n].shade.yn, vIS[n].shade.zn]] _ G3dIO.GetTriple[line]; Rope.Equal[fields[i].id, "rgbColor", FALSE] => [[vIS[n].shade.r, vIS[n].shade.g, vIS[n].shade.b]] _ G3dIO.GetTriple[line]; Rope.Equal[fields[i].id, "transmittance", FALSE] => vIS[n].shade.t _ G3dIO.GetReal[line]; Rope.Equal[fields[i].id, "textureCoords", FALSE] => { txtr: REF Pair _ NEW[Pair _ G3dIO.GetPair[line]]; vIS[n].aux _ txtr; }; ENDCASE => SELECT fields[i].type FROM integer, real => [] _ G3dIO.GetWord[line]; triple => { [] _ G3dIO.GetWord[line]; [] _ G3dIO.GetWord[line]; [] _ G3dIO.GetWord[line]; }; ENDCASE => NULL; ENDLOOP; ENDLOOP; vIS.length _ nElements; RETURN[vIS, fields]; }; ŽSceneUtilitiesImpl.mesa Copyright Σ 1984, 1987 by Xerox Corporation. All rights reserved. Last Edited by: Crow, April 11, 1988 5:41:15 pm PDT Bloomenthal, September 28, 1988 3:15:31 pm PDT Basic Types RECORD[scaleX, scaleY, scaleZ, addX, addY, addZ: REAL]; Renamed Procedures Utility Procedures Gets set of characters bound by white space Procedures for Setting up and using Contexts sets up context with blue background, white light source over left shoulder, view from 12 units or so, rendering through fancy renderer copies context so temporary modifications can be made Don't copy pixels, some uses want their own Procedures for Defining and Altering Environments Computed by SurfaceRender.ValidateView or ThreeDViewer.GetViewportFromViewer View and Lighting control Get background color Scene Input/Output View, Environment, and Display Shape Manipulation Shape Shading Control Shapes and Light Sources File Name, instance name, and Surface Type Scaling Orientation and Position Color, Transmittance, Shininess Texture IO.PutRope[ output, "EndOfScene:\n"]; -- this causes stream closure when read Procedures for Reading and Writing Shape Descriptions LoadShadingClass zeros the shadingProps since they're considered ephemeral (permanent stuff goes in fixedProps), so that call must precede this: This tells ThreeDWorld eventually to fill in aux field of VertexInfo from textures. This magic happens in ShapeUtilities.ShapePatchToPatch. Changed to use G3dIO.ShapeFromFile; old code is at bottom of file (J Bloomenthal, 9/6/88). In General Set Vertices Set Polygons or Patches Header Vertices Surface Procedures for Manipulating Shapes Build dummy patch structure to pass through ShapeUtilities.ShapePatchToPatch Makes a copy of a shape newShape.surface _ ? - Can't copy this since we can't know the type here, will point to the original Maintain data but don't display Procedures for Shading Surfaces Old Code LoadShadingClass zeros the shadingProps (why?), so that call must precede this: This tells ThreeDWorld eventually to fill in aux field of VertexInfo from textures. This magic happens in ShapeUtilities.ShapePatchToPatch. Get Surface Type Get Vertices Get Surface Κ:θ˜IheadšΟb™™BJ™3Icode™.J˜šΟk ˜ Jšœ žœžœ"˜6Jšœ žœe˜sJšœ žœ˜%Jšœ žœžœžœ ˜=Jš žœžœžœvžœžœ˜§Jšžœžœ0˜=Jšœ žœ ˜0Jšœžœ ˜Jšœ žœ˜*Jšœžœ˜#Jšœ žœ˜Jšœžœ˜%Jšœžœ˜"Jšœ žœ˜.Jšœ žœ ˜JšœžœZ˜iJšœžœ‘žœρ˜¨Jšœžœ˜—J˜—head2šœžœž˜!IašžœLžœC˜˜Nšžœ˜J˜Jšœž˜—head3š ™ Jšžœžœžœ˜Jšœ žœ˜-JšœžœžœΟc˜AJšœžœ˜/JšœžœŸ˜FJšœžœ˜3JšœžœŸ˜EJšœ žœ˜-Jšœ žœ˜'Jšœžœ ˜5Jšœžœ˜/IunitšœžœŸ,˜NIdefaultšœ žœ˜'šœžœ˜3JšŸ7™7—Q˜Pšœ žœŸ(˜QQšœ žœŸ˜AQšœ žœŸ2˜ZJšœ(Ÿ)˜QJšœ'Ÿ(˜OJšœ žœ˜%Jšœžœ˜/Jšœžœ˜/Jšœžœ˜2Jšœžœ˜1Jšœ žœ˜)Jšœžœ ˜5Jšœžœ˜/Jšœžœ˜#Jšœžœ˜3Jšœ žœ˜+Jšœžœ#˜;Jšœ žœ˜'Jšœžœ"˜8Jšœ žœ˜+Jšœžœ!˜6Jšœžœ˜Jšœžœ˜.Nšžœžœžœ˜Nš žœžœžœžœžœžœ˜—š™JšΟn œžœžœ˜MJš  œžœžœ4˜gJš œžœ!žœžœžœžœžœ.˜uJš œžœ!žœžœžœžœž œ&˜x—š™Pš œž œ žœžœžœžœžœ˜Tš  œžœ žœžœ žœ˜8Jšœ žœ˜%Jšžœžœ˜,J˜—š  œžœžœžœžœ˜3Jšœžœ˜Jšžœžœ˜,J˜—š   œžœ žœžœžœ˜5Jšœ žœ'˜5JšžœI˜OJ˜—š  œžœžœžœ˜&Jšžœ:˜@J˜— š  œžœ žœ žœ ˜;Jšžœ6˜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šžœ˜—Q˜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šœžœ&˜L˜—š  œžœžœ žœžœ%žœ˜pšœžœ*˜4Jšœžœžœžœ˜?J˜—šžœ žœžœ˜Jšœ#Ÿ)˜LJ˜J˜—J˜Jšœ2Ÿ!˜SJšœ&Ÿ˜BJšœžœ˜Jšœžœ˜J˜!Nšœ1Ÿ˜Ošžœžœžœž˜+Jšœ#žœ˜(Jšžœ˜—J˜J˜—š  œžœžœ žœ˜>J˜š žœžœžœžœžœžœž˜HJšœ#žœ˜(Jšžœ˜—J˜——š™ š  œž œ žœ˜AQšœ.žœ˜3QšœžœžœžœD˜Z šžœ3˜5Qšžœ˜Qšžœ"˜$Qšžœ˜ Q˜—Q˜Qšžœ˜Q˜— š œž œ žœ˜FQšœ.žœ˜3QšœžœžœžœB˜WQšœžœŸ˜4Q˜Qšžœ˜Q˜— š œž œ žœ˜HNšœ žœ"˜5Jšœžœžœžœ!˜8Nšœ žœ!˜/N˜"N˜"N˜&N˜ N˜.N˜8N˜6Q˜%Q˜"Qšœ žœ˜Q˜—š   œžœžœ žœžœžœ˜BJšœžœžœ˜Jšœžœžœ˜Jšœžœžœžœ˜6Jšœ žœ˜ šžœžœž˜Jšœžœžœ˜8Jšžœžœž˜š™šœ œ žœ˜'J˜Jšœžœžœžœ˜OJ˜Jšœžœžœžœ˜SJ˜Jšœžœžœžœ˜RJ˜Jšœžœ˜&J˜Jšœžœ˜(J˜Jšœžœ˜(Jšœžœ˜%Jšœžœ˜J˜—šœ  œ žœ˜+Jš œžœžœ žœžœ˜‚J˜—šœ œ žœŸ$˜NJš œžœžœžœžœ˜|J˜—šœ œ žœ˜2Jš œ žœžœžœžœ˜Jšœžœžœžœ˜JJ˜@J˜—Jšœ  œ žœžœ˜JJšœ œ žœžœ˜Nšœ   œ žœ˜,Jšœ&žœ˜:—šœ œ žœ˜(Jšœžœ˜Jšœžœ˜Jšœžœžœžœ˜OJšœžœ˜Jš œžœžœžœžœ˜IJ˜0J˜——š™šœ  œ žœŸ˜HJ˜J˜ Jšœžœžœ˜!Jšœžœ&žœ˜CJ˜0J˜!J˜—šœ  œ žœŸ!˜NJ˜J˜!J˜—šœ   œ žœ˜-Jšœžœžœžœ˜OJ˜,J˜—šœ   œ žœ˜,Jšœžœžœžœ˜LJ˜)J˜—šœ   œ žœ˜.Jšœžœžœžœ˜KJ˜)J˜—šœ   œ žœ˜.Jšœžœžœžœ˜OJšœžœžœžœ˜NJšœžœžœ˜ J˜=J˜—Jšœ œ žœ#˜DJšœ œ žœ%˜H—š ™ šœ œ žœ˜(Jšœžœ˜ Jšœ žœžœžœ˜VJ˜%J˜—šœ œ žœ˜*šžœžœž˜J˜,J˜*J˜(Jšžœžœ9˜J—J˜—šœ  œ žœ˜,Jšœ žœžœ˜$J˜)J˜—šœ œ žœ˜0Jšœžœžœ˜(J˜3J˜—šœ  œ žœ˜-šœžœ žœ˜J˜-J˜—šžœžœ˜Jšžœ"˜&Jšžœžœ=˜H—J˜—šœ œ žœ˜2šœžœ žœ˜J˜2J˜—šžœžœ˜Jšžœ"˜&Jšžœžœ=˜H—J˜——š™šœ œ žœ˜)šžœžœžœ#˜3Jšžœ>˜B—J˜JšœŸ-˜JJ˜—šœ  œ žœ˜-šžœžœžœ#˜3JšžœC˜G—Jšœžœ˜ J˜—šžœžœ˜%J˜1J˜——Jšžœ˜—J˜—š  œž œ žœž œ˜Dš  œžœžœžœžœ ˜3Jšœ žœ˜Jšžœžœžœ<žœ˜WJšžœ ˜J˜—š  œžœžœžœ ˜5Jšœžœž˜ J˜QJ˜˜B—J™Jšœ&žœŸ˜SJ™SJ™7J˜J˜—š œž œ˜Jšœžœ˜Jšœ*žœ˜/J˜šžœ žœ˜"J˜@—šžœžœ˜!J˜?—šžœ žœ˜#J˜@—šžœžœ˜(J˜F—J˜J˜—š   œžœžœžœžœ˜DL™ZJšœ/˜/š ™ Q˜&Q˜—š ™ Jšœžœ˜1Qšœžœ˜0J˜7 šœ˜Qš œžœžœžœžœ˜V— šžœžœžœ#ž˜CQšžœ>˜B—Jšžœžœžœ%˜Cšžœžœžœž˜&Jšœžœžœ ˜$J˜9Jšžœžœžœ9˜VJšžœžœžœ7˜SJšžœžœžœ"˜AJšžœžœžœ žœ˜GJšœžœŸ˜?JšœžœŸ˜CJšžœ˜——š™J˜š  œžœžœ˜"J˜IJ˜—š  œžœžœžœ žœ˜Fšœžœ ˜+Jšœžœ˜!Jšœ žœ˜J˜J˜—J˜—š œžœžœ#žœ˜IJšžœžœ˜šžœžœžœž˜!Jšœžœ˜&Jšœžœ3˜=J˜"Jš žœžœžœžœžœ˜EJšžœ˜—J˜—J˜—š   œžœžœžœŸ˜UQšœžœ˜-J˜!Jšœžœ(˜CJšœ žœŸ&˜OJ˜7J˜&J˜+J˜0J˜&J˜3Jšœžœ+˜@J˜0Qšœžœ+˜?J˜.š žœžœžœžœŸ˜MJšœžœ"˜:Jšœžœ'˜>Jšžœ˜ —J˜,Qšœžœ,˜BNšœ žœžœ˜J˜,J˜(J˜0šžœžœžœž˜*J˜2Jšžœ˜—Jšžœ˜ —Jšœ.Ÿ˜FJšœžœŸ˜:šžœ1žœžœž˜GJšœžœ$˜BJšœžœ˜/Jšžœ˜—Jšœžœ Ÿ˜;šžœ8žœžœž˜NJšœžœ$˜BJšœžœ!˜=Jšžœ˜—šžœ$žœžœŸ˜CJšœ žœ4˜CJšœžœžœ)˜Qšžœžœžœž˜'Jšœžœ!˜7Jšžœ˜—J˜)J˜1J˜—J˜—š   œžœžœ žœžœ žœ0˜}Jšœžœ%˜/Jšœ žœžœ˜$J˜<š žœžœžœžœžœžœž˜Hšžœ9Ÿ˜YJšžœ ˜$—Jšžœ˜—šžœžœŸ%˜@Jšžœ ˜$Jšžœ$˜(—J˜J˜*J˜J˜—š  œžœžœ žœžœ žœžœžœžœžœ3žœžœ˜ΙJšœžœ1˜;Jšœžœžœžœ3˜IJšœ žœ˜Jšœžœžœ˜2Jšœ žœžœ,˜RJšœ žœ3˜?Jš œ žœžœ#žœ"žœ ˜oš œžœžœžœžœžœ˜LJš™—Jšœ7Ÿ˜SšœRŸ ˜\Jš™—Jšžœžœ!Ÿ˜Wšžœžœžœž˜)Jšœžœ ˜J˜%šžœ žœžœ˜.Q˜7J˜—J˜$šžœ žœžœžœ˜9Q˜@J˜—šžœ žœžœ˜Jš œžœžœ žœžœ˜/Jšœ.žœ˜HJ˜—Jšžœ˜—J˜&˜hJ˜Jš™—šžœ žœ˜Jšœžœ1˜;Jšœ žœžœ!˜DJ˜ šžœžœžœžœ˜#J˜^Jšžœ˜—Jšœ žœ˜Jšœ žœ˜J˜J˜J˜J˜J˜—šœ žœ žœ˜=Qšœ žœžœžœ˜L šžœžœžœž˜'Qšœ žœ#˜3šžœžœžœž˜'J˜%Jšžœ˜—J˜&Jšžœ˜—J˜#Jšœžœ˜J˜%J˜J˜"J˜J˜—J˜/Jšžœ˜J˜—š œžœžœ˜&Jš œžœžœ žœžœ˜EJšœ$žœžœ˜4šžœžœžœ˜Jšœžœ!˜(J˜Jšžœžœ˜*Jšžœžœžœ#˜1Jšžœžœžœ%˜6Jšžœžœžœ$˜4Jšžœžœžœ'˜7Jšžœ žœžœ'˜9Jšžœ˜J˜šžœžœžœž˜'šžœžœžœ ˜.Jšžœžœžœ˜H—šžœžœžœ ˜1Jšžœžœžœ˜K—šžœžœžœ ˜0Jšžœžœžœ˜H—Jšžœžœžœžœ˜Ašžœ žœ˜Jšœžœžœ˜%Jšžœžœžœ˜BJ˜—Jšžœ˜Jšžœ˜—J˜—J˜—J˜—š"™"š œžœžœžœžœžœžœ˜gJšœžœžœ˜0J˜Jšœ0Ÿ˜HJšžœ ˜J˜J˜—š$  œž œ žœžœ žœ(žœžœžœžœžœžœžœžœ#žœžœžœžœžœ˜ύJšœžœ ˜*Jšœžœ˜#Jšžœ žœžœ;˜QJšžœ žœžœ:˜OJšœžœ"˜4š žœžœžœžœžœ˜;J˜=Jšžœ˜ —šžœ žœžœ˜Jšœžœ"˜3š žœžœžœžœžœ˜9J˜=Jšžœ˜J˜——šžœ&˜(JšžœL˜P—š žœ žœžœ žœžœ˜*š žœžœžœžœžœ˜8J˜7Jšžœ˜—šžœ%˜'JšžœI˜M—š žœžœžœžœžœžœž˜@J˜!Jšžœ˜—šžœ)˜+Jšžœ^˜b—J˜—J˜$Qšœžœ)˜KJ˜$šžœžœžœž˜'Jšœ žœ˜'šœžœ ˜"Jšœžœ˜$Jšœ žœ˜J˜ J˜J˜—Jš žœžœžœžœ,žœ˜SJšžœ˜—šžœ žœžœ˜šžœ#žœ˜)Jšžœ@˜D—Jšœ&žœŸ˜PJ˜—Jšžœ˜J˜J˜—š  œžœžœ žœžœžœžœžœžœžœžœžœžœ˜ΒJ˜Jšœžœ ˜*Jšœžœ˜#J˜PJ˜JJ˜2J˜3˜UJ™L—Jšœžœ˜(Jšœžœ ˜Jšœžœ'˜˜[Jšžœ<˜@—J˜%Jšœžœ˜J˜—J˜—š   œžœžœ žœžœ˜AJšœžœ1˜;šžœ žœžœ˜J˜'šžœ&žœ˜,Jšžœ%˜)—Jšœžœ˜J˜—J˜—š œž œ žœžœ˜MJšœžœ1˜;šžœ žœžœ˜Jšœžœ˜šžœžœž˜š œžœžœžœžœž˜OJšœžœ˜3Jšžœ˜—Jšžœ˜—J˜—J˜—š œž œ žœžœ˜LJšœžœ1˜;šžœ žœžœ˜Jšœžœ˜šžœžœž˜š œžœžœžœžœž˜OJšœžœ˜3Jšžœ˜—Jšžœ˜—J˜—J˜—J˜—Jšžœ˜J˜š™š   œžœžœ žœžœ˜RJšœ>Ÿ˜PJ™OJ˜YJ™SJ™7J˜J˜—š   œžœžœžœžœ˜DJšœžœžœžœ"˜8Qšœ žœ˜Qšœ žœŸ&˜CQšœ žœ˜Qš™ ˜Qšœžœ˜Qšœžœ˜Q˜—Qšœ*Ÿ ˜4Qšœžœ˜Q˜ šžœ ž ˜Qšžœ&žœžœ˜VQšžœ%žœžœ˜OQšžœ,žœžœžœ˜ZQšžœ+žœžœ˜MQ˜—Q˜3J™Jš ™ šœ žœ˜$Jšœžœ˜J˜@Jšœžœ%˜7J˜&Qšœžœ%˜6J˜%š žœžœžœžœŸ!˜KJšœžœ˜4Jšœžœ%˜9Jšžœ˜—šžœžœžœž˜#šžœžœž˜šœ&žœŸ˜IJ˜J—šœ%žœŸ˜GJ˜I—šœ*žœŸ˜RJ˜P—šœ*žœŸ˜Ršžœ#žœ˜)Jšžœ@˜D—Jšœ&žœŸ˜OJ˜HJ˜—Jšžœ˜—Jšžœ˜—J˜—J˜Jš ™ š œ žœžœ#žœ!žœ ˜lJšœžœ3˜>š   œžœžœžœžœ˜PJ˜"šžœžœžœ˜Jšœžœ&˜-J˜šžœžœžœžœ˜(Jšœžœ˜Jšžœ˜—J˜"J˜—J˜—J˜šžœžœžœž˜#Jšœ žœ˜šžœž˜˜ Jšœžœžœ˜9J˜"šžœžœž˜Jšœ"žœ˜/šžœ˜ Jšœžœ(Ÿ˜LJ˜;J˜——J˜—˜ Jšœ žœžœ˜7J˜#J˜ šžœžœž˜šœ*žœ˜6Jš žœžœžœžœ žœ˜L˜J˜8J˜—J˜—šžœ˜ Jšœžœ'Ÿ˜LJ˜J˜——J˜—šœŸ˜2Qšœ žœ˜Jšœ žœ žœ˜3J˜$Qšœžœ)˜