<> <> <> <<>> DIRECTORY Atom USING [PutPropOnList], Basics USING [Comparison], CADTypes USING [Scad, ScadSequence, VariableRec, VisibleMask, VisibleMaskSequence], Commander USING [CommandProc, Register], Convert USING [CardFromRope, Error], Geometry3dBasics USING [Triple, TripleSequence, TripleSequenceRep], Geometry3dVector USING [Add, Cross, Mul], Imager USING [Rectangle], ImagerColor USING [RGB], IO USING [BreakProc, Error, GetTokenRope, int, PutFR, RIS, STREAM], LightingModels USING [Model, PointSourceSequence], Rope USING [Compare, ROPE], SceneUtilities USING [AddShape, AddShapeAt, CreateDefaultContext, DeleteShape, Hide, NameBackgroundColor, PlaceShape, Reveal, SetColor, SetFaceted, SetLight, SetViewPort, ShapeInstance], ShadingModels USING [ShadingSequence], SurfaceRender USING [MakeFrame, SetView], SurfaceTracer, SurfaceViewer USING [], ThreeDBasics USING [Context, Create, SetView], ThreeDHacks USING [RegisterNewClasses, MakeFatPoint, MakeFatSeg, MakeTwoCell], ThreeDViewer USING [ButtonDesc, MakeViewer], ViewerClasses USING [Column, Viewer], ViewerOps USING [ChangeColumn, OpenIcon]; SurfaceViewerImpl: CEDAR PROGRAM IMPORTS Atom, Commander, Convert, IO, Rope, SurfaceRender, SurfaceTracer, ThreeDBasics, ThreeDHacks, ThreeDViewer, SceneUtilities, Geometry3dVector, ViewerOps EXPORTS SurfaceViewer ~ BEGIN <> SurfaceRec: TYPE ~ RECORD [ scad: CADTypes.Scad, id: NAT, mask: REF CADTypes.VisibleMask]; SurfaceSeq: TYPE ~ RECORD [ surfaces: SEQUENCE length: NAT OF SurfaceRec]; <> context3d: REF ThreeDBasics.Context; <> noReDraw: BOOLEAN; position: Geometry3dBasics.Triple; forward: Geometry3dBasics.Triple; up: Geometry3dBasics.Triple; viewHasChanged: BOOLEAN; surfaces: REF SurfaceSeq; numberOfSurfaces: NAT; maxNumberOfSurfaces: NAT ~ 3; nextID: NAT; Error: PUBLIC ERROR[why: ATOM] = CODE; CreateSurfaceViewer: PUBLIC PROC[] ~ BEGIN <> <<>> <> workingDirectory: Rope.ROPE; <> menuButtons: LIST OF ThreeDViewer.ButtonDesc ~ LIST [ [ proc: LoadPicture, choices: LIST[ [$Default, "Default Picture"], [NIL, NIL], [NIL, NIL], [NIL, NIL], [NIL, NIL], [NIL, NIL], [NIL, NIL], [NIL, NIL], [NIL, NIL]], label: "Load Picture", purpose: "Load a default picture" ] ]; <<>> <> noReDraw _ TRUE; <> surfaces _ NEW[SurfaceSeq[maxNumberOfSurfaces]]; numberOfSurfaces _ 0; nextID _ 0; position _ [2.0, -10.0, 3.0]; forward _ [-2, 10, -3]; up _ [0., 0., 1.]; <<>> <> context3d _ SceneUtilities.CreateDefaultContext[]; SceneUtilities.NameBackgroundColor[context3d, "Darkish Blue"]; SceneUtilities.SetLight [context3d, "Initial", position]; ThreeDBasics.SetView [ context: context3d, eyePoint: position, ptOfInterest: Geometry3dVector.Add[position, forward], upDirection: up]; <> -- ThreeDHacks.RegisterNewClasses[context3d]; <> context3d.props _ Atom.PutPropOnList[context3d.props, $WDir, workingDirectory]; <> ThreeDViewer.MakeViewer[ context: context3d, bannerName: "New and Improved Algebraic Surface Viewer", menu: menuButtons, mouseAction: NIL]; IF context3d.viewer.column # color THEN ViewerOps.ChangeColumn[context3d.viewer, color]; IF context3d.viewer.iconic THEN ViewerOps.OpenIcon[icon: context3d.viewer]; <> noReDraw _ FALSE; viewHasChanged _ TRUE; SurfaceRender.MakeFrame[context3d]; END; <<>> <> <<>> <> <<>> <> <> <> <> <<>> <> <> <<>> <> <> <> <> <> <> <> <> <> <> <> <<>> < NULL;>> <> <> <> <<>> <> <> <> <<>> ShutDown: PROC [] ~ BEGIN END; LoadPicture: PROC[context: REF ThreeDBasics.Context, key: ATOM] ~ BEGIN SceneUtilities.AddShapeAt[context, "Glass", "[Cedar]ThreeDWorld>ChampagneGlass.shape"]; SurfaceRender.MakeFrame[context]; END; MenuHit: PROC [bttn, choice: ATOM, x, y: REAL] ~ BEGIN END; LoadSurface: PUBLIC PROC[surface: CADTypes.Scad] RETURNS[id: NAT] ~ BEGIN <> index, newID: NAT; <> IF numberOfSurfaces >= maxNumberOfSurfaces THEN ERROR Error[$AllFilledUp]; index _ numberOfSurfaces; numberOfSurfaces _ numberOfSurfaces + 1; <> newID _ nextID; nextID _ nextID + 1; <> surfaces[index] _ [ scad: surface, id: newID, mask: NEW[CADTypes.VisibleMask[surface.cells.nCells]] ]; FOR i: NAT IN [0..surface.cells.nCells) DO surfaces[index].mask[i] _ TRUE; ENDLOOP; <<>> <> FOR cell: NAT IN [0..surface.cells.nCells) DO newCell: REF SceneUtilities.ShapeInstance; cellName: Rope.ROPE _ MakeShapeName[ newID, surface.cells[cell].indexX, surface.cells[cell].indexY, surface.cells[cell].indexZ]; SELECT surface.cells[cell].dimension FROM <> 0 => BEGIN newCell _ ThreeDHacks.MakeFatPoint[ name: cellName, position: surface.cells[cell].vertices[0]]; SceneUtilities.PlaceShape[context3d, cellName, [0, 0, 0]]; <> SceneUtilities.AddShape[context3d, newCell]; <> SceneUtilities.SetColor[context3d, cellName, [0.1, 0.9, 0.9]]; SceneUtilities.SetFaceted[context3d, cellName]; <> END; <> 1 => BEGIN vertexSequence: Geometry3dBasics.TripleSequence _ NEW[Geometry3dBasics.TripleSequenceRep[surface.cells[cell].vertices.nVertices]]; vertexSequence.length _ surface.cells[cell].vertices.nVertices; FOR i: NAT IN [0..surface.cells[cell].vertices.nVertices) DO vertexSequence[i] _ surface.cells[cell].vertices[i] ENDLOOP; newCell _ ThreeDHacks.MakeFatSeg[ name: cellName, points: vertexSequence]; SceneUtilities.PlaceShape[context3d, cellName, [0, 0, 0]]; <> SceneUtilities.AddShape[context3d, newCell]; <> SceneUtilities.SetColor[context3d, cellName, [0.1, 0.9, 0.9]]; SceneUtilities.SetFaceted[context3d, cellName]; <> <<9/22/86 - check for empty shape>> IF surface.cells[cell].vertices.nVertices < 2 THEN SceneUtilities.Hide[context3d, cellName]; END; <> 2 => BEGIN newCell _ ThreeDHacks.MakeTwoCell[ name: cellName, vertices: surface.cells[cell].vertices, triangles: surface.cells[cell].polygons]; SceneUtilities.PlaceShape[context3d, cellName, [0, 0, 0]]; <> SceneUtilities.AddShape[context3d, newCell]; <> SceneUtilities.SetColor[context3d, cellName, [0.1, 0.9, 0.9]]; SceneUtilities.SetFaceted[context3d, cellName]; <> <<9/22/86 - check for empty shape>> IF surface.cells[cell].polygons.nTriangles = 0 THEN SceneUtilities.Hide[context3d, cellName]; END; ENDCASE; <> ENDLOOP; viewHasChanged _ TRUE; MakeFrame[]; RETURN[newID]; END; <<>> MaskSurface: PUBLIC PROC[id: NAT, mask: REF CADTypes.VisibleMask] ~ BEGIN index: NAT _ IndexFromID[id]; --verify ID FOR i: NAT IN [0..surfaces[index].scad.cells.nCells) DO nameToMask: Rope.ROPE _ MakeShapeName[ id, surfaces[index].scad.cells[i].indexX, surfaces[index].scad.cells[i].indexY, surfaces[index].scad.cells[i].indexZ ]; IF mask[i] THEN SceneUtilities.Reveal[context3d, nameToMask] ELSE SceneUtilities.Hide[context3d, nameToMask]; ENDLOOP; surfaces[index].mask _ mask; viewHasChanged _ TRUE; MakeFrame[]; END; HideSurface: PUBLIC PROC[id: NAT] ~ BEGIN index: NAT _ IndexFromID[id]; --verify ID namesToHide: LIST OF Rope.ROPE _ ShapesMatchingID[id]; UNTIL namesToHide = NIL DO SceneUtilities.Hide[context3d, namesToHide.first]; namesToHide _ namesToHide.rest; ENDLOOP; viewHasChanged _ TRUE; MakeFrame[]; END; UnHideSurface: PUBLIC PROC[id: NAT] ~ BEGIN index: NAT _ IndexFromID[id]; --verify ID namesToHide: LIST OF Rope.ROPE _ ShapesMatchingID[id]; UNTIL namesToHide = NIL DO SceneUtilities.Reveal[context3d, namesToHide.first]; namesToHide _ namesToHide.rest; ENDLOOP; viewHasChanged _ TRUE; MakeFrame[]; END; DeleteSurface: PUBLIC PROC[id: NAT] ~ BEGIN index: NAT _ IndexFromID[id]; namesToDelete: LIST OF Rope.ROPE _ ShapesMatchingID[id]; FOR i: NAT IN [index..numberOfSurfaces - 1) DO surfaces[i] _ surfaces[i + 1]; ENDLOOP; numberOfSurfaces _ numberOfSurfaces - 1; UNTIL namesToDelete = NIL DO SceneUtilities.DeleteShape[context3d, namesToDelete.first]; <> namesToDelete _ namesToDelete.rest; ENDLOOP; viewHasChanged _ TRUE; MakeFrame[]; END; FlushSurfaces: PUBLIC PROC[] ~ BEGIN numberOfSurfaces _ 0; viewHasChanged _ TRUE; MakeFrame[]; END; IndexFromID: PROC [id: NAT] RETURNS [index: NAT] ~ BEGIN <> found: BOOLEAN _ FALSE; FOR i: NAT IN [0..numberOfSurfaces) DO IF surfaces[i].id = id THEN {index _ i; found _ TRUE}; ENDLOOP; IF ~found THEN ERROR Error[$InvalidID]; END; ShapesMatchingID: PROC [id: NAT] RETURNS [shapes: LIST OF Rope.ROPE] ~ BEGIN <> names: LIST OF Rope.ROPE _ NIL; FOR i: NAT IN [0..context3d.shapes.length) DO name: Rope.ROPE _ context3d.shapes[i].name; IF Rope.Compare[name, "Initial"] # equal AND Rope.Compare[name, "Torch"] # equal THEN BEGIN surfaceID: NAT; [id: surfaceID] _ ParseShapeName[name]; IF surfaceID = id THEN names _ CONS[name, names]; END; ENDLOOP; RETURN[names]; END; MakeShapeName: PROC [id, indexX, indexY, indexZ: NAT] RETURNS [name: Rope.ROPE] ~ BEGIN name _ IO.PutFR [ "S%gX%gY%gZ%g", IO.int[id], IO.int[indexX], IO.int[indexY], IO.int[indexZ]]; RETURN; END; ParseError: ERROR = CODE; ParseShapeName: PROC [name: Rope.ROPE] RETURNS [id, indexX, indexY, indexZ: NAT] ~ BEGIN BreakProc: IO.BreakProc ~ BEGIN RETURN [SELECT char FROM IN ['0..'9] => other, ENDCASE => break]; END; inStream: IO.STREAM _ IO.RIS[name]; token: Rope.ROPE; [token: token] _ IO.GetTokenRope[inStream, BreakProc ! IO.Error => ERROR ParseError]; IF Rope.Compare[token, "S"] # equal THEN ERROR ParseError; [token: token] _ IO.GetTokenRope[inStream, BreakProc ! IO.Error => ERROR ParseError]; id _ Convert.CardFromRope[token ! Convert.Error => ERROR ParseError]; [token: token] _ IO.GetTokenRope[inStream, BreakProc ! IO.Error => ERROR ParseError]; IF Rope.Compare[token, "X"] # equal THEN ERROR ParseError; [token: token] _ IO.GetTokenRope[inStream, BreakProc ! IO.Error => ERROR ParseError]; indexX _ Convert.CardFromRope[token ! Convert.Error => ERROR ParseError]; [token: token] _ IO.GetTokenRope[inStream, BreakProc ! IO.Error => ERROR ParseError]; IF Rope.Compare[token, "Y"] # equal THEN ERROR ParseError; [token: token] _ IO.GetTokenRope[inStream, BreakProc ! IO.Error => ERROR ParseError]; indexY _ Convert.CardFromRope[token ! Convert.Error => ERROR ParseError]; [token: token] _ IO.GetTokenRope[inStream, BreakProc ! IO.Error => ERROR ParseError]; IF Rope.Compare[token, "Z"] # equal THEN ERROR ParseError; [token: token] _ IO.GetTokenRope[inStream, BreakProc ! IO.Error => ERROR ParseError]; indexZ _ Convert.CardFromRope[token ! Convert.Error => ERROR ParseError]; END; ChangePosition: PUBLIC PROC[newPosition: Geometry3dBasics.Triple] ~ BEGIN position _ newPosition; SurfaceRender.SetView [ context: context3d, eyePoint: position, ptOfInterest: Geometry3dVector.Add[position, forward], upDirection: up]; viewHasChanged _ TRUE; END; <<>> ChangeOrientation: PUBLIC PROC[newForward, newUp: Geometry3dBasics.Triple] ~ BEGIN forward _ newForward; up _ newUp; SurfaceRender.SetView [ context: context3d, eyePoint: position, ptOfInterest: Geometry3dVector.Add[position, forward], upDirection: up]; viewHasChanged _ TRUE; END; <<>> ChangeScope: PUBLIC PROC[newScope: REAL] ~ BEGIN viewHasChanged _ TRUE; END; DrawFrame: PUBLIC PROC [] ~ BEGIN IF viewHasChanged THEN MakeFrame[]; END; InvokeRayTracer: PUBLIC PROC[variables: CADTypes.VariableRec, filename: Rope.ROPE, pixelsU, pixelsV: NAT] ~ BEGIN <<>> <> scads: REF CADTypes.ScadSequence; colors: REF ShadingModels.ShadingSequence; masks: REF CADTypes.VisibleMaskSequence; behind, right, behindAndRight, above, pointSourcePosition: Geometry3dBasics.Triple; pointSources: REF LightingModels.PointSourceSequence; lighting: LightingModels.Model; <<>> <> n: NAT _ numberOfSurfaces; scads _ NEW[CADTypes.ScadSequence[n]]; colors _ NEW[ShadingModels.ShadingSequence[n]]; masks _ NEW[CADTypes.VisibleMaskSequence[n]]; FOR i: NAT IN [0..n) DO scads[i] _ surfaces[i].scad; colors[i] _ [ surfaceColor: surfaces[i].scad.color, ambientReflectionCoefficient: 1.0, diffuseReflectionCoefficient: 0.4, specularReflectionCoefficient: 0.8]; masks[i] _ surfaces[i].mask; ENDLOOP; <> behind _ Geometry3dVector.Mul[forward, -5]; right _ Geometry3dVector.Mul[Geometry3dVector.Cross[forward, up], 2]; above _ Geometry3dVector.Mul[up, 2]; behindAndRight _ Geometry3dVector.Add[Geometry3dVector.Add[behind, right], above]; pointSourcePosition _ Geometry3dVector.Add[position, behindAndRight]; pointSources _ NEW[LightingModels.PointSourceSequence[1]]; pointSources[0] _ [position: pointSourcePosition, color: [1, 1, 1]]; lighting _ [background: [1, 1, 1], ambientSource: [0.2, 0.2, 0.2], pointSources: pointSources]; <> SurfaceTracer.TraceCells[ surfaces: scads, variables: variables, colors: colors, masks: masks, screenCenter: position, screenU: up, screenV: Geometry3dVector.Cross[up, forward], pixelsU: pixelsU, pixelsV: pixelsV, lightingModel: lighting, filename: filename]; <<>> END; <> <> <> <<>> <> <> <> <> <> <> <> <<>> <> <> <> <> <> <> <<>> <> <<>> MakeFrame: PROC [] ~ BEGIN <> SurfaceRender.SetView[ -- get new screen dimensions into transformations context: context3d, eyePoint: context3d.eyePoint, ptOfInterest: context3d.ptOfInterest, fieldOfView: context3d.fieldOfView, rollAngle: context3d.rollAngle, upDirection: context3d.upDirection, hitherLimit: context3d.hitherLimit, yonLimit: context3d.yonLimit ]; SceneUtilities.SetLight[ context: context3d, name: "Torch", position: context3d.eyePoint, color: [1, 1, 1] ]; SurfaceRender.MakeFrame[context3d]; viewHasChanged _ FALSE; END; SetViewPort: PROC [size: Imager.Rectangle] ~ BEGIN SceneUtilities.SetViewPort[context3d, size]; -- set clippers etc. FOR i: NAT IN [0..context3d.shapes.length) DO context3d.shapes[i].vtcesInValid _ TRUE; context3d.shapes[i].shadingInValid _ TRUE; ENDLOOP; SurfaceRender.SetView[ -- get new screen dimensions into transformations context: context3d, eyePoint: context3d.eyePoint, ptOfInterest: context3d.ptOfInterest, fieldOfView: context3d.fieldOfView, rollAngle: context3d.rollAngle, upDirection: context3d.upDirection, hitherLimit: context3d.hitherLimit, yonLimit: context3d.yonLimit ]; END; Foo: Commander.CommandProc ~ BEGIN CreateSurfaceViewer[]; END; Commander.Register["MakeSurfaceViewer", Foo]; END.