DisplayList3dImplB.mesa
Last edited by Bier on August 18, 1985 1:05:08 am PDT
Copyright © 1984 by Xerox Corporation. All rights reserved.
DIRECTORY
CastRays,
CoordSys,
CSGGraphics,
DisplayList3d,
DisplayList3dPrivate,
Imager,
ImagerBackdoor,
ImagerColor,
ImagerColorPrivate,
IO,
Matrix3d,
PriorityQueue,
Rope,
SV2d,
SV3d,
SVArtwork,
SVError,
SVModelTypes,
SVRayTypes,
SVSceneTypes,
SVTransforms;
DisplayList3dImplB: PROGRAM
IMPORTS CastRays, CoordSys, CSGGraphics, DisplayList3d, DisplayList3dPrivate, Imager, ImagerBackdoor, ImagerColor, ImagerColorPrivate, IO, Matrix3d, PriorityQueue, Rope, SVArtwork, SVError, SVTransforms
EXPORTS DisplayList3d, DisplayList3dPrivate =
BEGIN
Imported Types
Camera: TYPE = SVModelTypes.Camera;
Classification: TYPE = SVRayTypes.Classification;
Color: TYPE = Imager.Color;
CoordSysList: TYPE = SVModelTypes.CoordSysList;
CoordSystem: TYPE = SVModelTypes.CoordSystem;
CSGTree: TYPE = SVRayTypes.CSGTree;
DrawStyle: TYPE = SVModelTypes.DrawStyle;
FileCamera: TYPE = REF FileCameraObj;
FileCameraObj: TYPE = SVSceneTypes.FileCameraObj;
FileCameraList: TYPE = SVSceneTypes.FileCameraList;
FrameBox: TYPE = SVSceneTypes.FrameBox;
Matrix4by4: TYPE = SV3d.Matrix4by4;
Plane: TYPE = SV3d.Plane;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = SV3d.Point3d;
PointSetOp: TYPE = SVRayTypes.PointSetOp; -- {union, intersection, difference}
Poly3d: TYPE = SV3d.Poly3d;
Primitive: TYPE = SVRayTypes.Primitive;
Ray: TYPE = SVRayTypes.Ray;
Shape: TYPE = SVSceneTypes.Shape;
Vector: TYPE = SV3d.Vector;
DisplayList Types
Databases, Scenes, Assemblies, and Lightsources
Database: TYPE = REF DatabaseObj;
DatabaseObj: TYPE = SVSceneTypes.DatabaseObj;
Scene: TYPE = REF SceneObj;
SceneObj: TYPE = SVSceneTypes.SceneObj;
Artwork: TYPE = SVModelTypes.Artwork;
Assembly: TYPE = REF AssemblyObj;
AssemblyObj: TYPE = SVSceneTypes.AssemblyObj;
ToolData: TYPE = REF ToolDataObj;
ToolDataObj: TYPE = SVSceneTypes.ToolDataObj;
AssemblyList: TYPE = REF AssemblyListObj;
AssemblyListObj: TYPE = SVSceneTypes.AssemblyListObj;
LightSource: TYPE = REF LightSourceObj;
LightSourceObj: TYPE = SVModelTypes.LightSourceObj;
LightSourceList: TYPE = SVModelTypes.LightSourceList;
Master Object Class Types
MasterObjectClass: TYPE = REF MasterObjectClassObj;
MasterObjectClassObj: TYPE = SVSceneTypes.MasterObjectClassObj;
MasterObjectClassList: TYPE = SVSceneTypes.MasterObjectClassList;
FileoutProc: TYPE = SVSceneTypes.FileoutProc;
FileinProc: TYPE = SVSceneTypes.FileinProc;
Master Object Types
MasterObject: TYPE = REF MasterObjectRec;
MasterObjectRec: TYPE = SVSceneTypes.MasterObjectRec;
MasterObjectList: TYPE = SVSceneTypes.MasterObjectList;
FileoutPolyProc: TYPE = SVSceneTypes.FileoutPolyProc;
RayCastProc: TYPE = SVRayTypes.RayCastProc;
RayCastNoBBoxesProc: TYPE = SVRayTypes.RayCastNoBBoxesProc;
RayCastBoundingSpheresProc: TYPE = SVRayTypes.RayCastBoundingSpheresProc;
BoundHedronProc: TYPE = SVSceneTypes.BoundHedronProc;
PreprocessProc: TYPE = SVSceneTypes.PreprocessProc;
LineDrawProc: TYPE = SVSceneTypes.LineDrawProc;
NormalsDrawProc: TYPE = SVSceneTypes.NormalsDrawProc;
CountPlanarSurfacesProc: TYPE = SVSceneTypes.CountPlanarSurfacesProc;
GetPlanarSurfacesProc: TYPE = SVSceneTypes.GetPlanarSurfacesProc;
PlanarSurface: TYPE = REF PlanarSurfaceObj;
PlanarSurfaceObj: TYPE = SVSceneTypes.PlanarSurfaceObj;
PlanarSurfaceList: TYPE = SVSceneTypes.PlanarSurfaceList;
DrawPlanarSurfaceProc: TYPE = SVSceneTypes.DrawPlanarSurfaceProc;
DrawSubBoxesProc: TYPE = SVSceneTypes.DrawSubBoxesProc;
DrawSubSpheresProc: TYPE = SVSceneTypes.DrawSubSpheresProc;
Noop Procedures
A master object can use these entries if it doesn't implement one of these procedures
NoOpFilein: PUBLIC FileinProc = {};
NoOpFileout: PUBLIC FileoutProc = {};
NoOpFileoutPoly: PUBLIC FileoutPolyProc = {};
NoOpRayCast: PUBLIC RayCastProc = {
class ← CastRays.GetClassFromPool[];
CastRays.MakeClassAMiss[class];
};
NoOpRayCastNoBBoxes: PUBLIC RayCastNoBBoxesProc = {
class ← CastRays.GetClassFromPool[];
CastRays.MakeClassAMiss[class];
};
NoOpRayCastBoundingSpheres: PUBLIC RayCastBoundingSpheresProc = {
class ← CastRays.GetClassFromPool[];
CastRays.MakeClassAMiss[class];
};
NoOpBoundHedron: PUBLIC BoundHedronProc = {RETURN[NIL]};
NoOpPreprocess: PUBLIC PreprocessProc = {}; -- don't preprocess anything
NoOpLineDraw: PUBLIC LineDrawProc = {}; -- don't draw anything
NoOpNormalsDraw: PUBLIC NormalsDrawProc = {}; -- don't draw anything
NoOpCountPlanarSurfaces: PUBLIC CountPlanarSurfacesProc = {RETURN[0]};
Say you don't have any
NoOpGetPlanarSurfaces: PUBLIC GetPlanarSurfacesProc = {RETURN[NIL]};
Return the empty list
NoOpDrawPlanarSurface: PUBLIC DrawPlanarSurfaceProc = {}; -- don't draw anything
NoOpDrawSubBoxes: PUBLIC DrawSubBoxesProc = {};  -- don't draw anything
NoOpDrawSubSpheres: PUBLIC DrawSubSpheresProc = {};  -- don't draw anything
Delete Parts of the Scene Tree
DeleteMasterObjectNamed: PUBLIC PROC [moName: Rope.ROPE, scene: Scene] RETURNS [found: BOOL] = {
mo, beforeMo, afterMo: MasterObjectList;
[beforeMo, mo, afterMo, found] ← DisplayList3dPrivate.FindMasterObjectAndNeighborsFromName[moName, scene.masterObjects];
IF NOT found THEN RETURN;
IF beforeMo = NIL THEN scene.masterObjects ← afterMo
ELSE beforeMo.rest ← afterMo;
}; -- end of DeleteMasterObjectNamed
DeleteMasterObjectIfUnused: PUBLIC PROC [mo: MasterObject, scene: Scene] RETURNS [found: BOOL] = {
shape: Shape;
For now, we won't delete the built-in instances.
IF Rope.Equal[mo.class.name, "sphere"] OR Rope.Equal[mo.class.name, "block"] OR Rope.Equal[mo.class.name, "cylinder"] OR Rope.Equal[mo.class.name, "cone"] OR Rope.Equal[mo.class.name, "halfSpace"] THEN
RETURN[TRUE];
FOR primitiveAssemblies: LIST OF Assembly ←
DisplayList3d.ListOfPrimAssemblies[scene.assembly, scene], primitiveAssemblies.rest
UNTIL primitiveAssemblies = NIL DO
shape ← NARROW[primitiveAssemblies.first.shape];
IF shape.mo = mo THEN RETURN[TRUE];
ENDLOOP;
found ← DeleteMasterObjectNamed[mo.name, scene];
}; -- end of DeleteMasterObjectIfUnused
DeleteCoordSysAndChildren: PUBLIC PROC [cs: CoordSystem, scene: Scene] = {
CoordSys.DeleteCoordSysAndChildren[cs, scene.coordSysRoot];
}; -- end of DeleteCoordSysNamed
DeleteLightSourceNamed: PUBLIC PROC [lsName: Rope.ROPE, scene: Scene] = {
ls, beforeLS, afterLS: LightSourceList;
notFound: BOOLFALSE;
[beforeLS, ls, afterLS] ← DisplayList3dPrivate.FindLightSourceAndNeighborsFromName[lsName, scene.lightSources
!DisplayList3dPrivate.LightSourceNotFound => {notFound ← TRUE; CONTINUE}];
IF notFound THEN RETURN;
IF beforeLS = NIL THEN scene.lightSources ← afterLS
ELSE beforeLS.rest ← afterLS;
}; -- end of DeleteLightSourceNamed
ClearScene: PUBLIC PROC [scene: Scene] = {
scene.assembly.shape ← NEW[AssemblyListObj ← [NIL, union] ];
ClearCoordSystems[scene];
ClearMasterObjects[scene];
};
ClearCoordSystems: PUBLIC PROC [scene: Scene] = {
Removes all but WORLD, SCREEN and sceneAssembly.
Assumes for now that WORLD, and SCREEN are the first 2 coordsystems on the list.
world: CoordSystem ← scene.coordSysRoot;
DeleteCoordSysAndChildren[world.children.first, scene]; -- assumes this is sceneAssembly.
};
ClearMasterObjects: PUBLIC PROC [scene: Scene] = {
Removes all but "block", "sphere", "cone", and "cylinder" from current scene.
Assumes for now that "sphere","cone", and "cylinder", and "block" are the first five master objects.
z: MasterObjectList ← scene.masterObjects; -- "sphere"
z ← z.rest;-- "block"
z ← z.rest;-- "cone"
z ← z.rest;-- "cylinder"
z.rest ← NIL;-- cut off the rest
};
DeleteSubassemblyFromAssembly: PUBLIC PROC [subassembly: Assembly, assembly: Assembly, scene: Scene] RETURNS [success: BOOL] = {
IF ISTYPE[assembly.shape, AssemblyList] THEN
[assembly.shape, success] ← RemoveFromAssemblyList[subassembly,
NARROW[assembly.shape, AssemblyList], scene]
ELSE ERROR;
};
RemoveFromAssemblyList: PRIVATE PROC [a: Assembly, al: AssemblyList, scene: Scene] RETURNS [newAl: AssemblyList, success: BOOL] = {
Tree walk through the assembly deleting all of its coordinate systems. Then, cut the assembly loose and feed it to the garbage collector.
lastAssemblyList: LIST OF Assembly ← al.list;
DeleteAllAssembliesSittingOn[a, scene];
IF lastAssemblyList.first = a THEN {-- first item on the list
DeleteAssemblyAndSons[a, scene];
al.list ← lastAssemblyList.rest;
RETURN[al, TRUE];
};
FOR l: LIST OF Assembly ← lastAssemblyList.rest, l.rest UNTIL l = NIL DO
IF l.first = a THEN {
DeleteAssemblyAndSons[a, scene];
success ← TRUE;
lastAssemblyList.rest ← l.rest; -- splice out a
newAl ← al;
RETURN;
}
ELSE lastAssemblyList ← lastAssemblyList.rest;
ENDLOOP;
success ← FALSE;
};
TemporaryRemoveFromAssemblyList: PUBLIC PROC [a: Assembly, al: AssemblyList, scene: Scene] RETURNS [newAl: AssemblyList, success: BOOL] = {
A simple list remove operation. Does not break up the assembly and its sons, nor does it delete their coordinate systems. This routine is called by MoveToFrontOfAssembly to splice an assembly out of an AssemblyList.
lastAssemblyList: LIST OF Assembly ← al.list;
IF lastAssemblyList.first = a THEN {-- first item on the list
al.list ← lastAssemblyList.rest; RETURN[al, TRUE] };
FOR l: LIST OF Assembly ← lastAssemblyList.rest, l.rest UNTIL l = NIL DO
IF l.first = a THEN {
success ← TRUE;
lastAssemblyList.rest ← l.rest; -- splice out a
newAl ← al;
RETURN;
}
ELSE lastAssemblyList ← lastAssemblyList.rest;
ENDLOOP;
success ← FALSE;
};
DeleteAssemblyAndSons: PRIVATE PROC [a: Assembly, scene: Scene] = {
DeleteCoordSysAndChildren[a.coordSys, scene];
};
DeleteAllPrimitivesOfClass: PUBLIC PROC [className: Rope.ROPE, scene: Scene] = {
className must be a master object class, e.g. "sphere" or "jack". All primitive (leaf) assemblies refering to shapes of this class will be deleted in subtree rooted at root.
moClass: MasterObjectClass;
success: BOOL;
[moClass, success] ← DisplayList3d.FindClassFromName[className];
IF NOT success THEN {
SVError.Append[Rope.Cat["DeleteAllPrimitivesOfClass: Couldn't find class ", className, "."], TRUE, TRUE];
SVError.Blink[];
};
DeleteAllOfClassAux[moClass, scene.assembly, scene];
};
DeleteAllOfClassAux: PRIVATE PROC [moClass: MasterObjectClass, root: Assembly, scene: Scene] = {
WITH root.shape SELECT FROM
shape: Shape => {
child, parent: Assembly;
success: BOOL;
IF shape.mo.class = moClass THEN {
[child, parent] ← DisplayList3d.FindAssemblyFromName[root.name, scene];
IF child # root THEN ERROR;
success ← DisplayList3d.DeleteSubassemblyFromAssembly[child, parent, scene];
Removes assembly from the assemblyList of superAssembly and deletes the coordinate systems of all of its children.
IF NOT success THEN ERROR;
};
};
alist: AssemblyList => {
FOR list: LIST OF Assembly ← alist.list, list.rest UNTIL list = NIL DO
DeleteAllOfClassAux[moClass, list.first, scene];
ENDLOOP;
};
ENDCASE => ERROR;
};
DeleteAllAssembliesSittingOn: PUBLIC PROC [chair: Assembly, scene: Scene] = {
All assemblies A such that A.sittingOn = chair.name will be deleted along with their children.
DeleteAllSittingOnAux[chair.name, scene.assembly, scene];
};
DeleteAllSittingOnAux: PRIVATE PROC [chairName: Rope.ROPE, root: Assembly, scene: Scene] = {
child, parent: Assembly;
success: BOOL;
IF Rope.Equal[root.sittingOn, chairName, TRUE] THEN {
[child, parent] ← DisplayList3d.FindAssemblyFromName[root.name, scene];
IF child # root THEN ERROR;
success ← DisplayList3d.DeleteSubassemblyFromAssembly[child, parent, scene];
Removes assembly from the assemblyList of superAssembly and deletes the coordinate systems of all of its children.
IF NOT success THEN ERROR;
RETURN;
};
WITH root.shape SELECT FROM
shape: Shape => {};
alist: AssemblyList => {
FOR list: LIST OF Assembly ← alist.list, list.rest UNTIL list = NIL DO
DeleteAllSittingOnAux[chairName, list.first, scene];
ENDLOOP;
};
ENDCASE => ERROR;
};
Copy Parts of the Scene Tree
CopyAssemblyAndSonsRename: PUBLIC PROC [assembly: Assembly, scene: Scene, prefix: Rope.ROPE, parent: Assembly] RETURNS [copy: Assembly] = {
For copying assemblies within the same scene. The copies can refer to the same master object records as other objects in this scene. The prefix rope is prepended to the names of each node as it is copied to distinguish it from the original. CreateClusterAssemblyAtExistingCoordSys is used for filing in, so it doesn't do all we would like. We must wire up parents to the children manually.
moFound: BOOL;
IF NewNamesAlreadyPresent[assembly, scene, prefix] THEN SIGNAL DisplayList3d.NameAlreadyPresent;
WITH assembly.shape SELECT FROM
alist: AssemblyList => {-- assembly is a composite assembly.
copyCS: CoordSystem ← CoordSys.CreateCoordSysInTree[name: Rope.Concat[prefix, assembly.name], mat: assembly.coordSys.mat, parent: parent.coordSys, root: scene.coordSysRoot];
copy ← DisplayList3d.CreateClusterAssemblyAtExistingCoordSys[Rope.Concat[prefix, assembly.name], alist.pointSetOp, scene, copyCS];
FOR list: LIST OF Assembly ← alist.list, list.rest UNTIL list = NIL DO
[] ← CopyAssemblyAndSonsRename[list.first, scene, prefix, copy];
CopyAssemblyAndSonsRename returns an assembly which is complete and wired up to parent.
ENDLOOP;
};
shape: Shape => { -- assembly is a primitive assembly
artworkCopy: Artwork ← SVArtwork.Copy[assembly.artwork];
copyCS: CoordSystem ← CoordSys.CreateCoordSysInTree[name: Rope.Concat[prefix, assembly.name], mat: assembly.coordSys.mat, parent: parent.coordSys, root: scene.coordSysRoot];
[copy, moFound] ← DisplayList3d.CreatePrimitiveAtExistingCoordSys[Rope.Concat[prefix, assembly.name], shape.mo.name, CoordSys.GetScalars[shape.coordSys], scene, copyCS, artworkCopy, assembly.isTool];
IF NOT moFound THEN ERROR; -- for some reason the master object which assembly refers to is not registered in the scene (report this to SolidviewsSupport).
};
ENDCASE => ERROR;
DisplayList3d.ConnectAssemblyToParent[copy, parent];
}; -- end of CopyAssemblyAndSons
CopyAssemblyAndSonsNoRename: PUBLIC PROC [assembly: Assembly, newScene: Scene, parent: Assembly] RETURNS [copy: Assembly] = {
For copying an assembly from one scene to another. This presents problems since the needed masterobject may not be already present in the target scene. We assume that procedure MergeAssemblyIntoScene has already added the necessary master objects. No prefix is added. We just pray that there are no name conflicts. CreateClusterAssemblyAtExistingCoordSys is used for filing in, so it doesn't do all we would like. We must wire up parents to the children manually.
moFound: BOOL;
IF DisplayList3d.AnyNamesAlreadyPresent[assembly, newScene] THEN SIGNAL DisplayList3d.NameAlreadyPresent;
WITH assembly.shape SELECT FROM
alist: AssemblyList => {-- assembly is a composite assembly.
copyCS: CoordSystem ← CoordSys.CreateCoordSysInTree[name: assembly.name, mat: assembly.coordSys.mat, parent: parent.coordSys, root: newScene.coordSysRoot];
copy ← DisplayList3d.CreateClusterAssemblyAtExistingCoordSys[assembly.name, alist.pointSetOp, newScene, copyCS];
FOR list: LIST OF Assembly ← alist.list, list.rest UNTIL list = NIL DO
[] ← CopyAssemblyAndSonsNoRename[list.first, newScene, copy];
CopyAssemblyAndSonsNoRename returns an assembly which is complete and wired up to parent.
ENDLOOP;
};
shape: Shape => { -- assembly is a primitive assembly
artworkCopy: Artwork ← SVArtwork.Copy[assembly.artwork];
copyCS: CoordSystem ← CoordSys.CreateCoordSysInTree[name: assembly.name, mat: assembly.coordSys.mat, parent: parent.coordSys, root: newScene.coordSysRoot];
[copy, moFound] ← DisplayList3d.CreatePrimitiveAtExistingCoordSys[assembly.name, shape.mo.name, CoordSys.GetScalars[shape.coordSys], newScene, copyCS, artworkCopy, assembly.isTool];
IF NOT moFound THEN ERROR; -- for some reason the master object which assembly refers to is not registered in the scene (report this to SolidviewsSupport).
};
ENDCASE => ERROR;
DisplayList3d.ConnectAssemblyToParent[assembly, parent];
}; -- end of CopyAssemblyAndSonsNoRename
ReadAlpha: PRIVATE PROC [s: IO.STREAM] RETURNS [base: Rope.ROPE] = {
skip: INT;
[base, skip] ← IO.GetTokenRope[s, AlphaBreakProc];
};
AlphaBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = TRUSTED {
RETURN[IF char = '. THEN break ELSE other]
};
FindUniqueAssemblyNum: PRIVATE PROC [scene: Scene] RETURNS [num: NAT] = {
num ← FindUniqueAssemblyNumAux[scene.assembly];
num ← num + 1;
};
FindUniqueAssemblyNumAux: PRIVATE PROC [assembly: Assembly] RETURNS [num: NAT] = {
Finds an integer such that "<name>.<num>" is unique in the scene of assembly for all strings <name>. i.e. Find the highest .num extension in the tree rooted at assembly.
thisNum: NAT;
WITH assembly.shape SELECT FROM
alist: AssemblyList => {-- assembly is a composite assembly.
[----, num] ← CoordSys.BaseAndNumber[assembly.name];
FOR l: LIST OF Assembly ← alist.list, l.rest UNTIL l = NIL DO
thisNum ← FindUniqueAssemblyNumAux[l.first];
num ← MAX[num, thisNum];
ENDLOOP;
};
shape: Shape => { -- assembly is a primitive assembly
[----, num] ← CoordSys.BaseAndNumber[assembly.name];
};
ENDCASE => ERROR;
};
CopyAssemblyAndSonsUniqueNames: PUBLIC PROC [assembly: Assembly, oldScene: Scene, newScene: Scene, parent: Assembly] RETURNS [copy: Assembly] = {
oldScene is the scene assembly belongs to. newScene is the scene copy will belong to. parent must be an assembly in the new scene.
num: NAT;
success: BOOL;
num ← FindUniqueAssemblyNum[newScene];
IF oldScene = newScene THEN
copy ← CopyAssemblyAndSonsUniqueNamesAux[assembly, newScene, parent, num]
ELSE {
success ← CopyNeededMasterObjects[assembly, oldScene, newScene];
IF NOT success THEN {
SVError.Append[Rope.Cat["Masterobject name conflict scenes: ", oldScene.name, "/", newScene.name], TRUE, TRUE];
SVError.Blink[];
RETURN;
};
copy ← CopyAssemblyAndSonsUniqueNamesAux[assembly, newScene, parent, num];
};
};
CopyAssemblyAndSonsUniqueNamesAux: PUBLIC PROC [assembly: Assembly, newScene: Scene, parent: Assembly, num: NAT] RETURNS [copy: Assembly] = {
An attempt to do it right. For assembly and all of its successors, we find an integer a just high enough so that if name.# becomes name.a then all names will be unique. We copy the assembly and its successors and rename them this way.
thisBase, unique: Rope.ROPE;
thisNum: NAT;
moFound: BOOL;
WITH assembly.shape SELECT FROM
alist: AssemblyList => {-- assembly is a composite assembly.
copyCS: CoordSystem;
[thisBase, thisNum] ← CoordSys.BaseAndNumber[assembly.name];
uniqueIO.PutFR["%g.%g",[rope[thisBase]], [integer[num+thisNum]]];
copyCS ← CoordSys.CreateCoordSysInTree[name: unique, mat: assembly.coordSys.mat, parent: parent.coordSys, root: newScene.coordSysRoot];
copy ← DisplayList3d.CreateClusterAssemblyAtExistingCoordSys[unique, alist.pointSetOp, newScene, copyCS];
FOR list: LIST OF Assembly ← alist.list, list.rest UNTIL list = NIL DO
[] ← CopyAssemblyAndSonsUniqueNamesAux[list.first, newScene, copy, num];
CopyAssemblyAndSonsUniqueNamesAux returns an assembly which is complete and wired up to parent.
ENDLOOP;
};
shape: Shape => { -- assembly is a primitive assembly
artworkCopy: Artwork ← SVArtwork.Copy[assembly.artwork];
copyCS: CoordSystem;
[thisBase, thisNum] ← CoordSys.BaseAndNumber[assembly.name];
uniqueIO.PutFR["%g.%g",[rope[thisBase]], [integer[num+thisNum]]];
copyCS ← CoordSys.CreateCoordSysInTree[name: unique, mat: assembly.coordSys.mat, parent: parent.coordSys, root: newScene.coordSysRoot];
[copy, moFound] ← DisplayList3d.CreatePrimitiveAtExistingCoordSys[unique, shape.mo.name, CoordSys.GetScalars[shape.coordSys], newScene, copyCS, artworkCopy, assembly.isTool];
IF NOT moFound THEN ERROR; -- for some reason the master object which assembly refers to is not registered in the scene (report this to SolidviewsSupport).
};
ENDCASE => ERROR;
DisplayList3d.ConnectAssemblyToParent[copy, parent];
};
AddMOsToScene: PRIVATE PROC [moList: MasterObjectList, scene: Scene] = {
We assume that none of the mo's in moList is already in scene
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
scene.masterObjects ← DisplayList3dPrivate.AppendToMasterObjects[list.first, scene.masterObjects];
ENDLOOP;
};
CopyMOList: PRIVATE PROC [moList: MasterObjectList] RETURNS [copyList: MasterObjectList] = {
copyList ← NIL;
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
copyList ← DisplayList3dPrivate.AppendToMasterObjects[DisplayList3d.CopyMasterObject[list.first], copyList];
ENDLOOP;
};
CopyNeededMasterObjects: PUBLIC PROC [assembly: Assembly, fromScene, toScene: Scene] RETURNS [success: BOOL] = {
Makes a list of all of the masterobjects needed. Compares this list to the list of masterobjects available in the new scene, subtracting any that are available. Copies those that are still needed and adds them to the new scene. Assumes that if two master objects have the same name, they are the same.
moList: MasterObjectList;
toMoList: MasterObjectList;
neededList: MasterObjectList;
success ← TRUE;
moList ← DisplayList3d.MasterObjectsOfAssembly[assembly, fromScene];
toMoList ← DisplayList3d.MasterObjectsOfScene[toScene];
neededList ← DisplayList3dPrivate.MoListMinusMoList[moList, toMoList];
neededList ← CopyMOList[neededList];
AddMOsToScene[neededList, toScene];
};
Other List Auxiliaries
Removing Duplicates
RemoveDuplicateMOs: PUBLIC PROC [moList: MasterObjectList] RETURNS [uniqueList: MasterObjectList] = {
**** Naive algorithm for now. Go through moList. Add anything to uniqueList which it doesn't already have
thisMO: MasterObject;
uniqueList ← NIL;
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
thisMO ← list.first;
IF NOT ObjectNameInList[thisMO.name, uniqueList] THEN
uniqueList ← CONS[thisMO, uniqueList];
ENDLOOP;
};
ObjectNameInList: PRIVATE PROC [moName: Rope.ROPE, moList: MasterObjectList] RETURNS [BOOL]= {
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
IF Rope.Equal[list.first.name, moName, TRUE] THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
};
MoListMinusMoList: PUBLIC PROC [moList1, moList2: MasterObjectList] RETURNS [moList1MinusmoList2: MasterObjectList] = {
Find all elements of moList1 which are not in moList2
moList1MinusmoList2 ← NIL;
FOR list: MasterObjectList ← moList1, list.rest UNTIL list = NIL DO
IF NOT ObjectNameInList[list.first.name, moList2] THEN
moList1MinusmoList2 ← CONS[list.first, moList1MinusmoList2];
ENDLOOP;
};
CopyMasterObjectList: PUBLIC PROC [moList: MasterObjectList] RETURNS [copy: MasterObjectList] = {
Currently this has O[n2] behavior. Since moList typically has 4 elements, this is alright. Improve if moList grows.
copy ← NIL;
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
copy ← DisplayList3dPrivate.AppendToMasterObjects[list.first, copy];
ENDLOOP;
};
Find Scene Entities from their Names
NewNamesAlreadyPresent: PUBLIC PROC [assembly: Assembly, scene: Scene, prefix: Rope.ROPE] RETURNS [BOOL] = {
newName: Rope.ROPE ← Rope.Concat[prefix, assembly.name];
IF DisplayList3d.AssemblyNameIsPresent[newName, scene] THEN RETURN [TRUE];
WITH assembly.shape SELECT FROM
shape: Shape => RETURN[FALSE];
aList: AssemblyList => RETURN[NewNamesAlreadyPresentInList[aList, scene, prefix]];
ENDCASE => RETURN[FALSE];
};
NewNamesAlreadyPresentInList: PRIVATE PROC [assemblyList: AssemblyList, scene: Scene, prefix: Rope.ROPE] RETURNS [BOOL] = {
FOR list: LIST OF Assembly ← assemblyList.list, list.rest UNTIL list = NIL DO
IF NewNamesAlreadyPresent[list.first, scene, prefix] THEN RETURN [TRUE];
ENDLOOP;
RETURN [FALSE];
};
Draw Parts of the Scene Tree
DrawScene: PUBLIC PROC [dc: Imager.Context, scene: Scene, camera: Camera] = {
DrawSceneAux: SAFE PROC = TRUSTED {
CSGGraphics.Clip[dc, camera];
SELECT camera.style FROM
wire => DrawWireAssemblies[dc, scene, camera];
shaded => DrawShadedAssemblies[dc, scene, camera];
normals => DrawNormalsAssemblies[dc, scene, camera];
ENDCASE => SIGNAL NotYetImplemented;
Draw the current bounding frame if there is one.
IF NOT camera.frame.fullScreen THEN {
SetColor[dc, camera, Imager.black];
CSGGraphics.DrawFrame[dc, camera];
};
};
Imager.DoSaveAll[dc, DrawSceneAux];
};
NotYetImplemented: PUBLIC SIGNAL = CODE;
DrawWireAssemblies: PRIVATE PROC [dc: Imager.Context, scene: Scene, camera: Camera] = {
assemblyName: Rope.ROPE;
found: BOOL;
assembly: Assembly;
FOR list: LIST OF Rope.ROPE ← camera.visibleAssemblies, list.rest UNTIL list = NIL DO
assemblyName ← list.first;
found ← TRUE;
[assembly, ----] ← DisplayList3d.FindAssemblyFromName[assemblyName, scene
!DisplayList3d.AssemblyNotFound => {found ← FALSE; CONTINUE}];
IF found THEN {
SVTransforms.TellAboutCameraAndWorld[assembly.coordSys, camera, scene];
DrawWireAssembly[dc, assembly, scene, camera];
};
ENDLOOP;
};
DrawShadedAssemblies: PRIVATE PROC [dc: Imager.Context, scene: Scene, camera: Camera] = {
assemblyName: Rope.ROPE;
assembly: Assembly;
found: BOOL;
box: Imager.Rectangle;
Draw a background color.
box ← ImagerBackdoor.GetBounds[dc];
SetColor[dc, camera, scene.backgroundColor];
Imager.MaskRectangle[dc, box];
FOR list: LIST OF Rope.ROPE ← camera.visibleAssemblies, list.rest UNTIL list = NIL DO
assemblyName ← list.first;
found ← TRUE;
[assembly, ----] ← DisplayList3d.FindAssemblyFromName[assemblyName, scene
!DisplayList3d.AssemblyNotFound => {found ← FALSE; CONTINUE}];
IF found THEN {
SVTransforms.TellAboutCameraAndWorld[assembly.coordSys, camera, scene];
DrawShadedAssembly[dc, assembly, scene, camera];
};
ENDLOOP;
};
DrawNormalsAssemblies: PRIVATE PROC [dc: Imager.Context, scene: Scene, camera: Camera] = {
assemblyName: Rope.ROPE;
assembly: Assembly;
found: BOOL;
FOR list: LIST OF Rope.ROPE ← camera.visibleAssemblies, list.rest UNTIL list = NIL DO
assemblyName ← list.first;
found ← TRUE;
[assembly, ----] ← DisplayList3d.FindAssemblyFromName[assemblyName, scene
!DisplayList3d.AssemblyNotFound => {found ← FALSE; CONTINUE}];
IF found THEN {
SVTransforms.TellAboutCameraAndWorld[assembly.coordSys, camera, scene];
DrawNormalsAssembly[dc, assembly, scene, camera];
};
ENDLOOP;
};
DrawAssembly: PUBLIC PROC [dc: Imager.Context, assembly: Assembly, scene: Scene, camera: Camera] = {
SVTransforms.TellAboutCameraAndWorld[assembly.coordSys, camera, scene];
CSGGraphics.Clip[dc, camera]; -- clip picture to frame
SELECT camera.style FROM
wire => DrawWireAssembly[dc, assembly, scene, camera];
shaded => DrawShadedAssembly[dc, assembly, scene, camera];
normals => DrawNormalsAssembly[dc, assembly, scene, camera];
ENDCASE => SIGNAL NotYetImplemented;
};
SetColor: PRIVATE PROC [dc: Imager.Context, camera: Camera, color: Color] = {
currentColor: Imager.Color ← ImagerBackdoor.GetColor[dc];
IF currentColor = ImagerBackdoor.invert THEN RETURN;
IF camera.colorFilm THEN Imager.SetColor[dc, color]
ELSE {
intensity: REAL ← ImagerColorPrivate.ComponentFromColor[NARROW[color], $Intensity];
Imager.SetColor[dc, ImagerColor.ColorFromGray[1.0-intensity]]};
};
DrawWireAssembly: PRIVATE PROC [dc: Imager.Context, assembly: Assembly, scene: Scene, camera: Camera] = {
SetColor[dc, camera, Imager.black];
DrawWireAssembly2[dc, assembly, camera];
};
DrawWireAssembly2: PRIVATE PROC [dc: Imager.Context, assembly: Assembly, camera: Camera] = {
SELECT assembly.showAs FROM
tool => {
toolMasterObject: MasterObject ← assembly.toolMasterObject;
IF toolMasterObject = NIL THEN {
SVError.Append[Rope.Cat["Assembly ", assembly.name, " is a tool but has no tool data. Contact implementor."], TRUE, TRUE];
RETURN;
};
toolMasterObject.class.lineDraw[dc, toolMasterObject.lineBody, camera, assembly.coordSys];
RETURN;
};
normal => {
WITH assembly.shape SELECT FROM
assems: AssemblyList => {
FOR subassemblies: LIST OF Assembly ← assems.list, subassemblies.rest
UNTIL subassemblies = NIL DO
DrawWireAssembly2[dc: dc, assembly: subassemblies.first, camera: camera];
ENDLOOP;
};
shape: Shape => {
Imager.SetColor[dc, assembly.color];
shape.mo.class.lineDraw[dc, shape.mo.lineBody, camera, shape.coordSys];
};
ENDCASE => ERROR;
};
invisible => {};
both => ERROR SVError.NotYetImplemented;
ENDCASE => ERROR;
};
DrawShadedAssembly: PRIVATE PROC [dc: Imager.Context, assembly: Assembly, scene: Scene, camera: Camera] = {
Get a list of surfaces from each subassembly of "assembly" and draw them with the Painter's Algorithm (back to front)
Count the total number of surfaces and make a priority queue of the appropriate size.
predictedQueueSize: NATCountSurfacesInAssembly[assembly];
surfaceQueue: PriorityQueue.Ref ←
PriorityQueue.Predict[predictedQueueSize, DeeperPlanarSurface];
mo: MasterObject;
thisPlanarSurf: PlanarSurface;
DrawShadedAssemblyAux: SAFE PROC = TRUSTED {
Now put the surfaces on the queue
PutAssemblyOnQueue[assembly, surfaceQueue, camera.coordSys];
Take the surfaces off the queue in order and draw them
FOR i: INT IN[1..PriorityQueue.Size[surfaceQueue]] DO
thisPlanarSurf ← NARROW[PriorityQueue.Remove[surfaceQueue]];
mo ← thisPlanarSurf.mo;
mo.class.drawSurf[dc, thisPlanarSurf, scene.lightSources, camera];
ENDLOOP;
};
Imager.DoSaveAll[dc, DrawShadedAssemblyAux];
};
CountSurfacesInAssembly: PRIVATE PROC [assembly: Assembly] RETURNS [surfCount: NAT] = {
WITH assembly.shape SELECT FROM
assems: AssemblyList => surfCount ← CountSurfacesInAssemblyList[assems];
shape: Shape => surfCount ← shape.mo.class.countSurf[shape.mo];
ENDCASE => ERROR;
};
CountSurfacesInAssemblyList: PRIVATE PROC [asl: AssemblyList] RETURNS [surfCount: NAT] = {
surfCount ← 0;
FOR list: LIST OF Assembly ← asl.list, list.rest UNTIL list = NIL DO
surfCount ← surfCount + CountSurfacesInAssembly[list.first];
ENDLOOP;
};
PutAssemblyOnQueue: PRIVATE PROC [assembly: Assembly, q: PriorityQueue.Ref, cameraCS: CoordSystem] = {
thisSurf: PlanarSurface;
cameraNormal: Vector;
surfList: PlanarSurfaceList;
SELECT assembly.showAs FROM
tool => {
toolMasterObject: MasterObject ← assembly.toolMasterObject;
surfList ← toolMasterObject.class.getSurf[assembly, cameraCS];
FOR surfList ← surfList, surfList.rest UNTIL surfList = NIL DO
thisSurf ← surfList.first;
cameraNormal ← Matrix3d.UpdateVectorWithInverse[assembly.coordSys.cameraWRTlocal, thisSurf.normal];
thisSurf.normal ← cameraNormal;
PriorityQueue.Insert[q, thisSurf];
ENDLOOP;
};
normal => {
WITH assembly.shape SELECT FROM
assems: AssemblyList => PutAssemblyListOnQueue[assems, q, cameraCS];
shape: Shape => {
surfList ← shape.mo.class.getSurf[assembly, cameraCS];
FOR surfList ← surfList, surfList.rest UNTIL surfList = NIL DO
thisSurf ← surfList.first;
cameraNormal ← Matrix3d.UpdateVectorWithInverse[shape.coordSys.cameraWRTlocal, thisSurf.normal];
thisSurf.normal ← cameraNormal;
Eliminate most back-facing surfaces at this point by a simple test.
IF thisSurf.normal[3] >0 THEN PriorityQueue.Insert[q,thisSurf];
ENDLOOP;
};
ENDCASE => ERROR;
};
invisible => {};
both => ERROR SVError.NotYetImplemented;
ENDCASE => ERROR;
}; -- end of PutAssemblyOnQueue
PutAssemblyListOnQueue: PRIVATE PROC [asl: AssemblyList, q: PriorityQueue.Ref, cameraCS: CoordSystem] = {
FOR list: LIST OF Assembly ← asl.list, list.rest UNTIL list = NIL DO
PutAssemblyOnQueue[list.first, q, cameraCS];
ENDLOOP;
};
DeeperPlanarSurface: SAFE PROC [x,y: PriorityQueue.Item, data: REFNIL] RETURNS [BOOL] = TRUSTED {
xS: PlanarSurface ← NARROW[x];
yS: PlanarSurface ← NARROW[y];
RETURN[xS.depth < yS.depth];
};
DrawNormalsAssembly: PROC [dc: Imager.Context, assembly: Assembly, scene: Scene, camera: Camera] = {
SetColor[dc, camera, Imager.black];
DrawNormalsAssembly2[dc, assembly, scene, camera];
};
DrawNormalsAssembly2: PROC [dc: Imager.Context, assembly: Assembly, scene: Scene, camera: Camera] = {
lightSources: LightSourceList ← scene.lightSources;
WITH assembly.shape SELECT FROM
assems: AssemblyList => {
FOR subassemblies: LIST OF Assembly ← assems.list, subassemblies.rest
UNTIL subassemblies = NIL DO
DrawNormalsAssembly2[dc: dc, assembly: subassemblies.first, scene: scene, camera: camera];
ENDLOOP;
};
shape: Shape => {
Imager.SetColor[dc, assembly.color];
shape.mo.class.normalsDraw[dc, shape.mo.shadeBody, camera, shape.coordSys];
};
ENDCASE => ERROR;
};
END.