DisplayList3dImplA.mesa
Last edited by Bier on July 6, 1983 3:59 pm
Author: Eric Bier in July, 1982
DIRECTORY
 CoordSys,
CSG,
 DisplayList3d,
 GraphicsColor,
 IO,
 Matrix3d,
 Rope,
 Shading,
 SV2d,
 SVArtwork,
 SVDisplayListFiling,
 SVPolygon3d,
 SVVector3d;

DisplayList3dImplA: PROGRAM
IMPORTS CoordSys, DisplayList3d, GraphicsColor, IO, Matrix3d, Rope, SVArtwork, SVDisplayListFiling
EXPORTS DisplayList3d, SVDisplayListFiling =
BEGIN
versionRope: PUBLIC Rope.ROPE ← "Solidviews Version 2.0 OF July 1, 1983 4:39 pm";
Used for version stamps and initial greeting. Exported by DisplayList3dImpl.
Introduction
Contents: The Solidviews System is involved with the creation and manipulation of three dimensional scenes. A scene is a list of lightsources, and a tree of assemblies. Intermediate nodes in this tree are cluster assemblies. The leaves of this tree are primitive assemblies. Each cluster assembly specifies a point set operation describing how its children should be combined. Each primitive assembly refers to a master object (a shape) and a triplet of scalars describing how this master object should be scaled before being displayed. All assemblies (cluster or primitive) refer to a coordinate system which describes how the object should be positioned and oriented with respect to its parent coordinate system (from which we can derive how it will be positioned in the scene's master coordinate system known as WORLD). Each master object is an instance of a class of shapes called a master object class.
Imported Types
Artwork: TYPE = REF ArtworkObj;
ArtworkObj: TYPE = SVArtwork.ArtworkObj;
Classification: TYPE = REF ClassificationObj;
ClassificationObj: TYPE = CSG.ClassificationObj;
Color: TYPE = GraphicsColor.Color;
CoordSysList: TYPE = CoordSys.CoordSysList;
CoordSysObj: TYPE = CoordSys.CoordSysObj;
CoordSystem: TYPE = REF CoordSysObj;
CSGTree: TYPE = REF CSGTreeObj;
CSGTreeObj: TYPE = CSG.CSGTreeObj;
Matrix4by4: TYPE = Matrix3d.Matrix4by4;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = Matrix3d.Point3d;
PointSetOp: TYPE = CSG.PointSetOp; -- {union, intersection, difference}
Poly3d: TYPE = SVPolygon3d.Poly3d;
Primitive: TYPE = REF PrimitiveObj;
PrimitiveObj: TYPE = CSG.PrimitiveObj;
Ray: TYPE = REF RayObj;
RayObj: TYPE = CSG.RayObj;
Vector: TYPE = SVVector3d.Vector;
DisplayList Types
Databases, Scenes, Assemblies, and Lightsources
Database: TYPE = REF DatabaseObj;
DatabaseObj: TYPE = DisplayList3d.DatabaseObj;
Scene: TYPE = REF SceneObj;
SceneObj: TYPE = DisplayList3d.SceneObj;
Assembly: TYPE = REF AssemblyObj;
AssemblyObj: TYPE = DisplayList3d.AssemblyObj;
AssemblyList: TYPE = REF AssemblyListObj;
AssemblyListObj: TYPE = DisplayList3d.AssemblyListObj;
LightSource: TYPE = REF LightSourceObj;
LightSourceObj: TYPE = Shading.LightSourceObj;
LightSourceList: TYPE = Shading.LightSourceList;
Master Object Class Types
MasterObjectClass: TYPE = REF MasterObjectClassObj;
MasterObjectClassObj: TYPE = DisplayList3d.MasterObjectClassObj;
MasterObjectClassList: TYPE = DisplayList3d.MasterObjectClassList;
FileoutProc: TYPE = DisplayList3d.FileoutProc;
FileinProc: TYPE = DisplayList3d.FileinProc;
Master Object Types
MasterObject: TYPE = REF MasterObjectRec;
MasterObjectRec: TYPE = DisplayList3d.MasterObjectRec;
MasterObjectList: TYPE = DisplayList3d.MasterObjectList;
RayCastProc: TYPE = CSG.RayCastProc;
RayCastNoBBoxesProc: TYPE = CSG.RayCastNoBBoxesProc;
BoundHedronProc: TYPE = DisplayList3d.BoundHedronProc;
PreprocessProc: TYPE = DisplayList3d.PreprocessProc;
LineDrawProc: TYPE = DisplayList3d.LineDrawProc;
NormalsDrawProc: TYPE = DisplayList3d.NormalsDrawProc;
CountPlanarSurfacesProc: TYPE = DisplayList3d.CountPlanarSurfacesProc;
GetPlanarSurfacesProc: TYPE = DisplayList3d.GetPlanarSurfacesProc;
PlanarSurface: TYPE = REF PlanarSurfaceObj;
PlanarSurfaceObj: TYPE = DisplayList3d.PlanarSurfaceObj;
PlanarSurfaceList: TYPE = DisplayList3d.PlanarSurfaceList;
DrawPlanarSurfaceProc: TYPE = DisplayList3d.DrawPlanarSurfaceProc;
DrawSubBoxesProc: TYPE = DisplayList3d.DrawSubBoxesProc;
Global Variables
globalDatabase: Database;
globalClassList: MasterObjectClassList ← NIL;
globalMOList: MasterObjectList ← NIL;
Set Up the System
RegisterMasterObjectClass: PUBLIC PROC [
name: Rope.ROPE,
filein: FileinProc,
fileout: FileoutProc,
rayCast: RayCastProc,
rayCastNoBBoxes: RayCastNoBBoxesProc,
getHedron: BoundHedronProc,
preprocess: PreprocessProc,
lineDraw: LineDrawProc,
normalsDraw: NormalsDrawProc,
countSurf: CountPlanarSurfacesProc,
getSurf: GetPlanarSurfacesProc,
drawSurf: DrawPlanarSurfaceProc,
drawSubBoxes: DrawSubBoxesProc]
RETURNS [moClass: MasterObjectClass] = {
 moClass ← NEW[MasterObjectClassObj ← [name, filein, fileout, rayCast, rayCastNoBBoxes, getHedron, preprocess, lineDraw, normalsDraw, countSurf, getSurf, drawSurf, drawSubBoxes]];
 globalClassList ← AppendClassToList[moClass, globalClassList];
 };
RegisterMasterObject: PUBLIC PROC [mo: MasterObject] = {
 globalMOList ← AppendToMasterObjects[mo, globalMOList];
 };
Create Entities
CreateScene: PUBLIC PROC [name: Rope.ROPE] RETURNS [scene: Scene] = {
Creates scene and adds scene to database.
initialCS: CoordSysList ← CoordSys.InitialCoordSysList[];
sceneAssemblyCS: CoordSystem;
sceneAssembly: Assembly ← CreateClusterAssembly["sceneAssembly", union];
defaultRedLight: LightSource ← CreateLightSource["RedLight",[200,200,400], GraphicsColor.red];
defaultGreenLight: LightSource ← CreateLightSource["GreenLight",[-200,200,400], GraphicsColor.green];
defaultWhiteLight: LightSource ← CreateLightSource["WhiteLight",[800,800,1000],GraphicsColor.white];
scene ← NEW[SceneObj ← [
name: name,
worldCS: CoordSys.FindCoordSysFromName["WORLD", initialCS],
coordSystems: initialCS,
lightSources: CONS[defaultWhiteLight, NIL],
masterObjects: CopyMasterObjectList[globalMOList], -- Copies the list structure but not the objects.
assembly: sceneAssembly,
backgroundColor: GraphicsColor.white,
shadows: FALSE,
dirty: FALSE]];
sceneAssemblyCS ← CoordSys.CreateCoordSys["sceneAssembly", Matrix3d.Identity[], scene.worldCS];
DisplayList3d.AddCoordSysToScene[sceneAssemblyCS, scene];
scene.assembly.coordSys ← sceneAssemblyCS;
globalDatabase ← AppendToDatabase[scene, globalDatabase];
};
CreateEmptyScene: PUBLIC PROC [name: Rope.ROPE] RETURNS [scene: Scene] = {
Creates scene and adds scene to database.
scene ← NEW[SceneObj ← [name: name,
worldCS: NIL,
coordSystems: NIL, lightSources: NIL,
masterObjects: NIL,
assembly: NIL,
backgroundColor: GraphicsColor.white,
shadows: FALSE,
dirty: FALSE]];
globalDatabase ← AppendToDatabase[scene, globalDatabase];
};
CreateMasterObject: PUBLIC PROC [
name: Rope.ROPE,
class: MasterObjectClass,
mainBody: REF ANY,
lineBody: REF ANY,
shadeBody: REF ANY,
rayCastBody: REF ANY] RETURNS [mo: MasterObject] = {
Adds the named object to the scene's master object list
 mo ← NEW[MasterObjectRec ←
[name, class, mainBody, lineBody, shadeBody, rayCastBody]];
};
CopyMasterObject: PUBLIC PROC [mo: MasterObject] RETURNS [copy: MasterObject] = {
copy ← NEW[MasterObjectRec];
copy.name ← mo.name;
copy.class ← mo.class;
copy.mainBody ← mo.mainBody;
copy.lineBody ← mo.lineBody;
copy.shadeBody ← mo.shadeBody;
copy.rayCastBody ← mo.rayCastBody;
};
CreatePrimitiveAssembly: PUBLIC PROC [name: Rope.ROPE, object: Rope.ROPE, size: Vector, scene: Scene, artwork: Artwork ← NIL, isTool: BOOLFALSE]
RETURNS [assembly: Assembly, masterObjectFound: BOOL] = {
masterObject: MasterObject;
masterObjectFound ← TRUE;
[masterObject, masterObjectFound] ← FindObjectFromName[object, scene];
IF NOT masterObjectFound THEN RETURN;
IF artwork = NIL THEN artwork ←
SVArtwork.CreateColorArtwork[GraphicsColor.RGBToColor[.6,.6,.8], plastic]; -- light blue
assembly ← NEW[AssemblyObj ←
[name: name, coordSys: NIL, artwork: artwork, scalars: size, visible: TRUE, isTool: isTool, object: masterObject]];
};
CreateClusterAssembly: PUBLIC PROC [name: Rope.ROPE, pointSetOp: PointSetOp ← union, isTool: BOOLFALSE] RETURNS [assembly: Assembly] = {
artwork: Artwork ← SVArtwork.CreateColorArtwork[GraphicsColor.IntensityToColor[1], plastic]; -- white
assembly ← NEW[AssemblyObj ←
[name: name, coordSys: NIL, artwork: artwork, scalars: [1,1,1],
object: NEW[AssemblyListObj ← [NIL, pointSetOp] ], isTool: isTool, visible: TRUE]];
};
CreateLightSource: PUBLIC PROC [name: Rope.ROPE, position: Point3d, color: Color] RETURNS [ls: LightSource] = {
Calculate vector from position as follows: LightSources are positioned in WORLD coordinates. Assume that objects will be placed near the origin of this coordinate system. Hence the position is also the vector from the objects to the lightsource.
vector: Vector ← position;
ls ← NEW[LightSourceObj ← [name, position, color]];
};
Build the Scene Tree
NameAlreadyPresent: PUBLIC SAFE SIGNAL = CODE;
AddMasterObjectToScene: PUBLIC PROC [mo: MasterObject, scene: Scene] = {
IF ObjectNameIsPresent[mo.name, scene] THEN SIGNAL NameAlreadyPresent;
scene.masterObjects ←
AppendToMasterObjects[mo, scene.masterObjects];
};
  
AddLightSourceToScene: PUBLIC PROC [ls: LightSource, scene: Scene] = {
IF LightSourceNameIsPresent[ls.name, scene] THEN SIGNAL NameAlreadyPresent;
scene.lightSources ← AppendToLightSourceList[ls, scene.lightSources];
};
AddCoordSysToScene: PUBLIC PROC [cs: CoordSystem, scene: Scene] = {
IF CoordSysNameIsPresent[cs.name, scene] THEN SIGNAL NameAlreadyPresent;
scene.coordSystems ← AppendToCoordSystems[cs, scene.coordSystems];
};
AddAssemblyToScene: PUBLIC PROC [assembly: Assembly, scene: Scene, mat: Matrix4by4] = {
Add assembly to the top level list of assemblies in the current scene
cs: CoordSystem ← CoordSys.CreateCoordSys[assembly.name, mat, scene.assembly.coordSys];
AddCoordSysToScene[cs, scene];
assembly.coordSys ← cs;
scene.assembly.object ← AppendToAssemblyList[assembly, NARROW[scene.assembly.object]];
};
AddSubassemblyToAssembly: PUBLIC PROC [subassembly: Assembly, assembly: Assembly, scene: Scene, mat: Matrix4by4] = {
SELECT TRUE FROM
ISTYPE[assembly.object,AssemblyList] => { -- add to old AssemblyList
alist: AssemblyList ← NARROW[assembly.object];
cs: CoordSystem ← CoordSys.CreateCoordSys[subassembly.name, mat, assembly.coordSys];
AddCoordSysToScene[cs, scene];
subassembly.coordSys ← cs;
alist ← AppendToAssemblyList[subassembly, alist]};
ENDCASE => SIGNAL AttemptToAddSubassemblyToPrimitive;
};
AttemptToAddSubassemblyToPrimitive: PUBLIC SIGNAL = CODE;
AddSubassemblyToAssemblyWithCS: PUBLIC PROC [subassembly: Assembly, assembly: Assembly, scene: Scene, coordSys: CoordSystem] = {
Automatically makes coordsys of subassembly refer to coordsys of super assembly.
SELECT TRUE FROM
ISTYPE[assembly.object,AssemblyList] => { -- add to old AssemblyList
alist: AssemblyList ← NARROW[assembly.object];
coordSys.withRespectTo ← assembly.coordSys;
AddCoordSysToScene[coordSys, scene];
subassembly.coordSys ← coordSys;
alist ← AppendToAssemblyList[subassembly, alist]};
ENDCASE => SIGNAL AttemptToAddSubassemblyToPrimitive;
};
Restructure the Tree
RenameAssembly: PUBLIC PROC [assem: Assembly, newName: Rope.ROPE, scene: Scene] = {
 -- rename this assembly and its coordinate system
 assem.name ← newName;
 assem.coordSys.name ← newName;
 };
CopyAssemblyAndSons: PUBLIC PROC [assembly: Assembly, scene: Scene, prefix: Rope.ROPE] RETURNS [copy: Assembly] = {
 moFound: BOOL;
IF NewNamesAlreadyPresent[assembly, scene, prefix] THEN SIGNAL NameAlreadyPresent;
WITH assembly.object SELECT FROM
 alist: AssemblyList => {-- assembly is a composite assembly.
  copy ← CreateClusterAssembly[Rope.Concat[prefix, assembly.name], alist.pointSetOp];
  copy.coordSys ← CoordSys.CreateCoordSys[name: copy.name, mat: Matrix3d.Identity[], withRespectTo: NIL];
  CopySubassemblies[copy, alist, scene, prefix];
  };
 mo: MasterObject => { -- assembly is a primitive assembly
  artworkCopy: Artwork ← SVArtwork.Copy[assembly.artwork];
  [copy, moFound] ← CreatePrimitiveAssembly[Rope.Concat[prefix, assembly.name], mo.name, assembly.scalars, scene, 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).
  copy.coordSys ← CoordSys.CreateCoordSys[name: copy.name, mat: Matrix3d.Identity[], withRespectTo: NIL];
  };
ENDCASE => ERROR;
 }; -- end of CopyAssemblyAndSons
CopyAssemblyAndSonsUsingNewSceneMOs: PUBLIC PROC [assembly: Assembly, newScene: Scene] RETURNS [copy: Assembly] = {
moFound: BOOL;
IF AnyNamesAlreadyPresent[assembly, newScene] THEN SIGNAL NameAlreadyPresent;
WITH assembly.object SELECT FROM
alist: AssemblyList => {-- assembly is a composite assembly.
copy ← CreateClusterAssembly[assembly.name, alist.pointSetOp];
copy.coordSys ← CoordSys.CreateCoordSys[name: copy.name, mat: Matrix3d.Identity[], withRespectTo: NIL];
CopySubassembliesUsingNewMOs[copy, alist, newScene];
};
mo: MasterObject => { -- assembly is a primitive assembly
artworkCopy: Artwork ← SVArtwork.Copy[assembly.artwork];
[copy, moFound] ← CreatePrimitiveAssembly[assembly.name, mo.name, assembly.scalars, newScene, 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).
copy.coordSys ← CoordSys.CreateCoordSys[name: copy.name, mat: Matrix3d.Identity[], withRespectTo: NIL];
};
ENDCASE => ERROR;
}; -- end of CopyAssemblyAndSonsUsingNewSceneMOs
CopySubassemblies: PRIVATE PROC [assembly: Assembly, alist: AssemblyList, scene: Scene, prefix: Rope.ROPE] = {
thisA: Assembly;
FOR list: LIST OF Assembly ← alist.list, list.rest UNTIL list = NIL DO
thisA ← CopyAssemblyAndSons[list.first, scene, prefix];
CopyAssemblyAndSons returns an assembly which has a coordinate system whose mat and withRespectTo are null. We must fill in the mat manually. AddSubassemblyToAssembly will fill in the withRespectTo automatically.
assembly.coordSys must exist at this point.
thisA.coordSys.mat ← list.first.coordSys.mat;
AddSubassemblyToAssemblyWithCS[thisA, assembly, scene, thisA.coordSys];
ENDLOOP;
};
CopySubassembliesUsingNewMOs: PRIVATE PROC [assembly: Assembly, alist: AssemblyList, newScene: Scene] = {
thisA: Assembly;
FOR list: LIST OF Assembly ← alist.list, list.rest UNTIL list = NIL DO
thisA ← CopyAssemblyAndSonsUsingNewSceneMOs[list.first, newScene];
CopySubassembliesUsingNewMOs returns an assembly which has a coordinate system whose mat and withRespectTo are null. We must fill in the mat manually. AddSubassemblyToAssembly will fill in the withRespectTo automatically.
assembly.coordSys must exist at this point.
thisA.coordSys.mat ← list.first.coordSys.mat;
AddSubassemblyToAssemblyWithCS[thisA, assembly, newScene, thisA.coordSys];
ENDLOOP;
};
MoveSubassembly: PUBLIC PROC [assem: Assembly, to: Assembly, scene: Scene] = {
Find assem's parent. Remove links from parent to assem. Create links from 'to' to assem. Likewise, assem's coordsys must now refer to the new parent's coordsys. Alter assem's coordinate system matrix so its doesn't actually move at all.
assemWithSameName, parent: Assembly;
parentList: AssemblyList;
found: BOOL;
toCS: CoordSystem ← to.coordSys;
[assemWithSameName, parent] ← FindAssemblyFromName[assem.name, scene];
IF assemWithSameName # assem THEN ERROR;
IF NOT(ISTYPE [to.object, AssemblyList] OR to.object = NIL) THEN
SIGNAL AttemptToAddSubassemblyToPrimitive;
Remove links from parent to assembly.
parentList ← NARROW[parent.object];
[parent.object, found] ← TemporaryRemoveFromAssemblyList[assem, parentList, scene];
IF NOT found THEN ERROR; -- it was found just a few lines ago. What happened?
Remove links from assem's coordsys to parent by pointing to new parent's CS. And update assem's coordsys's matrix so it doesn't actually move.
[] ← CoordSys.TPutAinTermsOfB[assem.coordSys, to.coordSys];
Create link from 'to' to assem.
to.object ← AppendToAssemblyList[assem, NARROW[to.object]]
}; -- end of MoveSubassembly
MoveToFrontOfAssembly: PUBLIC PROC [subassembly: Assembly, assembly: Assembly, scene: Scene] = {
Moves subassembly to the first position of assembly's assemblylist.
Make sure "subassembly" is a subassembly of "assembly".
aList: AssemblyList ← NARROW[assembly.object];
success: BOOLFALSE;
FOR list: LIST OF Assembly ← aList.list, list.rest UNTIL list = NIL DO
IF list.first = subassembly THEN success←TRUE;
ENDLOOP;
IF NOT success THEN ERROR SubassemblyNotFound;
[aList, success] ← TemporaryRemoveFromAssemblyList[subassembly, aList, scene];
IF NOT success THEN ERROR SubassemblyNotFound;
aList.list ← CONS[subassembly, aList.list];
};
SubassemblyNotFound: PUBLIC ERROR = CODE;
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 ← 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 ← AppendToMasterObjects[CopyMasterObject[list.first], copyList];
ENDLOOP;
};
MergeAssemblyIntoScene: PUBLIC PROC [newAssembly: Assembly, fromScene: Scene, parentAssembly: Assembly, toScene: Scene] RETURNS [copyAssembly: Assembly] = {
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. Makes a copy of the newAssembly tree (without changing names) but refering to master objects in the new scene. Wires up the new assembly to its parent.
moList: MasterObjectList ← MasterObjectsOfAssembly[newAssembly, fromScene];
toMoList: MasterObjectList ← MasterObjectsOfScene[toScene];
neededList: MasterObjectList ← MoListMinusMoList[moList, toMoList];
neededList ← CopyMOList[neededList];
AddMOsToScene[neededList, toScene];
copyAssembly ← CopyAssemblyAndSonsUsingNewSceneMOs [assembly: newAssembly, newScene: toScene];
copyAssembly.coordSys.mat ← newAssembly.coordSys.mat;
SVDisplayListFiling.AddSubassemblyToAssemblyWithCS[copyAssembly,
         parentAssembly, toScene, copyAssembly.coordSys];
};
MergeSceneIntoScene: PUBLIC PROC [fromScene: Scene, toScene: Scene] RETURNS [success: BOOL] = {
Takes all of the assemblies from fromScene which are directly under sceneAssembly and adds them to the sceneAssembly of toScene. Makes sure that all assemblies in fromScene have names unique in toScene first. This currently destroys fromScene.
fromList: AssemblyList ← NARROW[fromScene.assembly.object];
fromScene.assembly.name ← Rope.Concat[fromScene.name, "SceneAssembly"];
IF AnyNamesAlreadyPresent[fromScene.assembly, toScene] THEN RETURN[FALSE];
AddCoordSystemsInAssemblyToScene[fromScene.assembly, toScene];
FOR list: LIST OF Assembly ← fromList.list, list.rest UNTIL list = NIL DO
AddSubassemblyToAssemblyWithCS [subassembly: list.first, assembly: toScene.assembly,
scene: toScene, coordSys: list.first.coordSys];
ENDLOOP;
};
AddCoordSystemsInAssemblyToScene: PRIVATE PROC [assembly: Assembly, scene: Scene] = {
WITH assembly.object SELECT FROM
  alist: AssemblyList => {
   AddCoordSysToScene[assembly.coordSys, scene];
   AddCoordSystemsInAssemblyListToScene[alist, scene];
   };
  mo: MasterObject =>
   AddCoordSysToScene[assembly.coordSys, scene];
  ENDCASE => ERROR;
  };
  
AddCoordSystemsInAssemblyListToScene: PRIVATE PROC [assemblyList: AssemblyList, scene: Scene] = {
FOR list: LIST OF Assembly ← assemblyList.list, list.rest UNTIL list = NIL DO
  AddCoordSystemsInAssemblyToScene[list.first, scene];
ENDLOOP;
 };
SetArtworkAssembly: PUBLIC PROC [assembly: Assembly, artwork: Artwork, scene: Scene] = {
FOR list: LIST OF Assembly ← ListOfPrimAssemblies[assembly, scene], list.rest
UNTIL list = NIL DO
  list.first.artwork ← artwork;
ENDLOOP;
 };
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] ← 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] = {
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"] THEN RETURN[TRUE];
For now, we won't delete the built-in instances
FOR primitiveAssemblies: LIST OF Assembly ← ListOfPrimAssemblies[scene.assembly, scene], primitiveAssemblies.rest UNTIL primitiveAssemblies = NIL DO
IF primitiveAssemblies.first.object = mo THEN RETURN[TRUE];
ENDLOOP;
found ← DeleteMasterObjectNamed[mo.name, scene];
}; -- end of DeleteMasterObjectIfUnused
DeleteCoordSysNamed: PUBLIC PROC [csName: Rope.ROPE, scene: Scene] = {
 cs, beforeCS, afterCS: CoordSysList;
 notFound: BOOLFALSE;
 [beforeCS, cs, afterCS] ← CoordSys.FindCoordSysAndNeighborsFromName[csName, scene.coordSystems
  !CoordSys.CoordSysNotFound => {notFound ← TRUE; CONTINUE}];
IF notFound THEN RETURN;
IF beforeCS = NIL THEN scene.coordSystems ← afterCS
  ELSE beforeCS.rest ← afterCS;
 }; -- end of DeleteCoordSysNamed
DeleteLightSourceNamed: PUBLIC PROC [lsName: Rope.ROPE, scene: Scene] = {
 ls, beforeLS, afterLS: LightSourceList;
 notFound: BOOLFALSE;
 [beforeLS, ls, afterLS] ← FindLightSourceAndNeighborsFromName[lsName, scene.lightSources
  !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.object ← 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
 z: CoordSysList ← scene.coordSystems; -- WORLD
 z ← z.rest; -- SCREEN
 z ← z.rest; -- sceneAssembly
 z.rest ← NIL; -- cut off the rest
 };
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.object,AssemblyList] THEN
   [assembly.object, success] ← RemoveFromAssemblyList[subassembly,
           NARROW[assembly.object,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;
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: PRIVATE PROC [a: Assembly, al: AssemblyList, scene: Scene] RETURNS [newAl: AssemblyList, success: BOOL] = {
A simple list remove operation. 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] = {
DeleteCoordSysNamed[a.coordSys.name, scene];
WITH a.object SELECT FROM
alist: AssemblyList => DeleteAssemblyListAndSons[alist, scene];
mo: MasterObject => RETURN;
ENDCASE => ERROR;
};
DeleteAssemblyListAndSons: PRIVATE PROC [alist: AssemblyList, scene: Scene] = {
FOR list: LIST OF Assembly ← alist.list, list.rest UNTIL list = NIL DO
 DeleteAssemblyAndSons[list.first, scene];
ENDLOOP;
};
Find Scene Entities from their Names
FindSceneFromName: PUBLIC PROC [name: Rope.ROPE] RETURNS [scene: Scene] = {
 l: LIST OF Scene ← globalDatabase.scenes;
IF l = NIL THEN ERROR DatabaseEmpty;
UNTIL l = NIL DO
  IF Rope.Equal[l.first.name, name, FALSE] THEN BEGIN scene ← l.first; RETURN END;
  l ← l.rest;
ENDLOOP;
SIGNAL SceneNotFound;
 };
DatabaseEmpty: PUBLIC SIGNAL = CODE;
SceneNotFound: PUBLIC SIGNAL = CODE;
FindAssemblyFromName: PUBLIC PROC [name: Rope.ROPE, scene: Scene] RETURNS [assembly: Assembly, superAssembly: Assembly] = {
Finds the named assembly and its immediate superior. superAssembly is NIL if assembly is top level.
t: Assembly ← scene.assembly;
success: BOOL;
[assembly, superAssembly, success] ← FindAssemblyInTree[name, t, NIL];
IF success = FALSE THEN SIGNAL AssemblyNotFound;
};
AssemblyNotFound: PUBLIC SIGNAL = CODE;
AssemblyNameIsPresent: PUBLIC PROC [name: Rope.ROPE, scene: Scene] RETURNS [BOOL] = {
 dummy1, dummy2: Assembly;
 isPresent: BOOL;
 [dummy1, dummy2, isPresent] ← FindAssemblyInTree[name, scene.assembly, NIL];
RETURN[isPresent];
 };
FindAssemblyInTree: PRIVATE PROC [name: Rope.ROPE, t: Assembly, super: Assembly] RETURNS [assembly: Assembly, superAssembly: Assembly, success: BOOL] = {
IF t = NIL THEN RETURN[NIL,NIL,FALSE];
IF Rope.Equal[t.name, name] THEN RETURN[t, super, TRUE];
WITH t.object SELECT FROM
  as: AssemblyList => {
    FOR l: LIST OF Assembly ← as.list, l.rest UNTIL l = NIL DO
     [assembly,superAssembly,success] ← FindAssemblyInTree[name, l.first, t];
    IF success THEN RETURN;
    ENDLOOP;
    RETURN [NIL, NIL, FALSE];
    };
  ENDCASE => -- t is a primitive assembly with the wrong name
   RETURN[NIL,NIL,FALSE];
 };
AnyNamesAlreadyPresent: PUBLIC PROC [assembly: Assembly, scene: Scene] RETURNS [BOOL] = {
IF AssemblyNameIsPresent[assembly.name, scene] THEN RETURN [TRUE];
WITH assembly.object SELECT FROM
  mo: MasterObject => RETURN[FALSE];
  aList: AssemblyList => RETURN[AnyNamesAlreadyPresentInList[aList, scene]];
  ENDCASE => RETURN[FALSE];
 };
AnyNamesAlreadyPresentInList: PRIVATE PROC [assemblyList: AssemblyList, scene: Scene] RETURNS [BOOL] = {
FOR list: LIST OF Assembly ← assemblyList.list, list.rest UNTIL list = NIL DO
  IF AnyNamesAlreadyPresent[list.first, scene] THEN RETURN [TRUE];
ENDLOOP;
RETURN [FALSE];
 };
NewNamesAlreadyPresent: PUBLIC PROC [assembly: Assembly, scene: Scene, prefix: Rope.ROPE] RETURNS [BOOL] = {
 newName: Rope.ROPE ← Rope.Concat[prefix, assembly.name];
IF AssemblyNameIsPresent[newName, scene] THEN RETURN [TRUE];
WITH assembly.object SELECT FROM
  mo: MasterObject => 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];
 };
FindClassFromName: PUBLIC PROC [name: Rope.ROPE] RETURNS [moClass: MasterObjectClass, success: BOOL] = {
FOR moClassList: MasterObjectClassList ← globalClassList, moClassList.rest
UNTIL moClassList = NIL DO
  IF Rope.Equal[moClassList.first.name, name, TRUE] THEN RETURN [moClassList.first, TRUE];
ENDLOOP;
RETURN[NIL, FALSE];
 };
FindObjectFromName: PUBLIC PROC [name: Rope.ROPE, scene: Scene] RETURNS [object: MasterObject, success: BOOL] = {
FOR ol: MasterObjectList ← scene.masterObjects, ol.rest UNTIL ol = NIL DO
  IF Rope.Equal[ol.first.name, name, TRUE] THEN RETURN [ol.first, TRUE];
ENDLOOP;
RETURN[NIL, FALSE];
 };
ObjectNameIsPresent: PUBLIC PROC [name: Rope.ROPE, scene: Scene] RETURNS [BOOL] = {
FOR ol: MasterObjectList ← scene.masterObjects, ol.rest UNTIL ol = NIL DO
  IF Rope.Equal[ol.first.name, name, TRUE] THEN RETURN [TRUE];
ENDLOOP;
RETURN[FALSE];
 };
CoordSysNameIsPresent: PUBLIC PROC [name: Rope.ROPE, scene: Scene] RETURNS [BOOL] = {
FOR cl: CoordSysList ← scene.coordSystems, cl.rest UNTIL cl = NIL DO
  IF Rope.Equal[cl.first.name, name, TRUE] THEN RETURN [TRUE];
ENDLOOP;
RETURN[FALSE];
 };
FindLightFromName: PUBLIC PROC [name: Rope.ROPE, scene: Scene] RETURNS [light: LightSource, success: BOOL] = {
FOR list: LightSourceList ← scene.lightSources, list.rest UNTIL list = NIL DO
  IF Rope.Equal[list.first.name, name, TRUE] THEN RETURN [list.first, TRUE];
ENDLOOP;
RETURN [NIL, FALSE];
 };
LightSourceNameIsPresent: PUBLIC PROC [name: Rope.ROPE, scene: Scene] RETURNS [BOOL] = {
FOR ll: LightSourceList ← scene.lightSources, ll.rest UNTIL ll = NIL DO
  IF Rope.Equal[ll.first.name, name, TRUE] THEN RETURN [TRUE];
ENDLOOP;
RETURN[FALSE];
 };

UniqueNameFrom: PUBLIC PROC [name: Rope.ROPE, scene: Scene] RETURNS [unique: Rope.ROPE] = {
 -- Finds any digits on the end of the name. Looks through the scene extracting a digit and base name from each name. Finds the maximum number, adds one, reconcatenates and returns.
 maxNum: NAT ← 0;
 uniqueStream: IO.STREAM;
 targetBase, base: Rope.ROPE;
 targetNum, num: NAT;
 [targetBase, targetNum] ← BaseAndNumber[name];
FOR ol: MasterObjectList ← scene.masterObjects, ol.rest UNTIL ol = NIL DO
  [base, num] ← BaseAndNumber[ol.first.name];
  IF Rope.Equal[base, targetBase, TRUE] THEN maxNum ← Max[num, maxNum];
ENDLOOP;
 uniqueStream ← IO.CreateOutputStreamToRope[];
 uniqueStream.PutF["%g.%g",[rope[targetBase]], [integer[maxNum+1]]];
 unique ← IO.GetOutputStreamRope[uniqueStream];
 };

Max: PRIVATE PROC [a, b: NAT] RETURNS [NAT] = {
RETURN[IF a > b THEN a ELSE b];
 };

BaseAndNumber: PRIVATE PROC [name: Rope.ROPE] RETURNS [base: Rope.ROPE, number: NAT] = {
 noNumber: BOOL ← FALSE;
 nameStream: IO.STREAM;
 next: CHAR;
 nameStream ← IO.CreateInputStreamFromRope[name];
 base ← ReadAlpha[nameStream];
 next ← nameStream.GetChar[
  !IO.EndOfStream => {noNumber ← TRUE; CONTINUE}];
IF noNumber THEN number ← 0 ELSE
  IF next = '. THEN number ← IO.GetInt[nameStream]
  ELSE number ← 0;
 };

ReadAlpha: PRIVATE PROC [s: IO.STREAM] RETURNS [base: Rope.ROPE] = {
 base ← IO.GetToken[s, AlphaBreakProc];
 };

AlphaBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = TRUSTED {
RETURN[IF char = '. THEN break ELSE other]
 };
FindMasterObjectAndNeighborsFromName: PRIVATE PROC [moName: Rope.ROPE, moList: MasterObjectList] RETURNS [beforeMo, mo, afterMo: MasterObjectList, found: BOOL] = {
 -- returns found = FALSE if that is the case.
 lastL: MasterObjectList ← NIL;
 l: MasterObjectList ← moList;
 found ← TRUE;
IF l = NIL THEN RETURN[NIL, NIL, NIL, FALSE];
UNTIL l = NIL DO
  IF Rope.Equal[l.first.name, moName] THEN {
    beforeMo ← lastL; mo ← l; afterMo ← l.rest; RETURN};
  lastL ← l;
  l ← l.rest;
ENDLOOP;
RETURN[NIL, NIL, NIL, FALSE];
 };
FindLightSourceAndNeighborsFromName: PRIVATE PROC [lsName: Rope.ROPE, lsList: LightSourceList] RETURNS [beforeLS, ls, afterLS: LightSourceList] = {
 -- signals LightSourceNotFound if that is the case.
 lastL: LightSourceList ← NIL;
 l: LightSourceList ← lsList;
IF l = NIL THEN ERROR LightSourceNotFound;
UNTIL l = NIL DO
  IF Rope.Equal[l.first.name, lsName] THEN {
    beforeLS ← lastL; ls ← l; afterLS ← l.rest; RETURN};
  lastL ← l;
  l ← l.rest;
ENDLOOP;
SIGNAL LightSourceNotFound;
 };
LightSourceNotFound: SIGNAL = CODE;
List Append Auxiliaries For the Add Procedures
AppendToDatabase: PROC [scene: Scene, database: Database] RETURNS [Database] = {
 -- a copy of List.Nconc1 for LIST OF Scene instead of LIST OF REF ANY
 z: LIST OF Scene ← database.scenes;
IF z = NIL THEN {database.scenes ← CONS[scene,NIL]; RETURN[database]};
UNTIL z.rest = NIL DO z ← z.rest; ENDLOOP;
 z.rest ← CONS[scene,NIL];
RETURN[database];
 };

AppendToAssemblyList: PROC [assembly: Assembly, list: AssemblyList] RETURNS [AssemblyList] = {
 -- a copy of List.Nconc1 for LIST OF Assembly instead of LIST OF REF ANY
 z: LIST OF Assembly ← list.list;
IF z = NIL THEN {list.list ← CONS[assembly, NIL]; RETURN[list]};
UNTIL z.rest = NIL DO z ← z.rest; ENDLOOP;
 z.rest ← CONS[assembly,NIL];
RETURN[list];
 };

AppendToLightSourceList: PROC [ls: LightSource, list: LightSourceList] RETURNS [LightSourceList] = {
 -- a copy of List.Nconc1 for LightSourceList instead of LIST OF REF ANY
 z: LightSourceList ← list;
IF z = NIL THEN RETURN[CONS[ls,NIL]];
UNTIL z.rest = NIL DO z ← z.rest; ENDLOOP;
 z.rest ← CONS[ls,NIL];
RETURN[list];
 };

AppendToCoordSystems: PROC [cs: CoordSystem, list: CoordSysList] RETURNS [CoordSysList] = {
 -- a copy of List.Nconc1 for CoordSysList instead of LIST OF REF ANY
 z: CoordSysList ← list;
IF z = NIL THEN RETURN[CONS[cs,NIL]];
UNTIL z.rest = NIL DO z ← z.rest; ENDLOOP;
 z.rest ← CONS[cs,NIL];
RETURN[list];
 };

AppendToMasterObjects: PROC [mo: MasterObject, list: MasterObjectList] RETURNS [MasterObjectList] = {
 -- a copy of List.Nconc1 for MasterObjectList instead of LIST OF REF ANY
 z: MasterObjectList ← list;
IF z = NIL THEN RETURN[CONS[mo,NIL]];
UNTIL z.rest = NIL DO z ← z.rest; ENDLOOP;
 z.rest ← CONS[mo,NIL];
RETURN[list];
 };

AppendClassToList: PROC [moc: MasterObjectClass, list: MasterObjectClassList] RETURNS [MasterObjectClassList] = {
 -- a copy of List.Nconc1 for MasterObjectClassList instead of LIST OF REF ANY
 z: MasterObjectClassList ← list;
IF z = NIL THEN RETURN[CONS[moc,NIL]];
UNTIL z.rest = NIL DO z ← z.rest; ENDLOOP;
 z.rest ← CONS[moc,NIL];
RETURN[list];
 };
Get Generators of Scene Entities
Scene Generator
GetSceneGenerator: PUBLIC PROC RETURNS [g: SceneGenerator] = {
 g ← NEW[SceneGeneratorObj ← [currentPtr: globalDatabase.scenes]];
 };
SceneGenerator: TYPE = REF SceneGeneratorObj;
SceneGeneratorObj: TYPE = DisplayList3d.SceneGeneratorObj;
NextScene: PUBLIC PROC [g: SceneGenerator] RETURNS [scene: Scene] = {
IF g.currentPtr = NIL THEN RETURN[NIL];
 scene ← g.currentPtr.first;
 g.currentPtr ← g.currentPtr.rest;
 };
CoordSystem Generator
GetCoordSysGenerator: PUBLIC PROC [scene: Scene] RETURNS [g: CoordSysGenerator] = {
 g ← NEW[CoordSysGeneratorObj ← [currentPtr: scene.coordSystems]];
 };
CoordSysGenerator: TYPE = REF CoordSysGeneratorObj;
CoordSysGeneratorObj: TYPE = DisplayList3d.CoordSysGeneratorObj;
NextCoordSys: PUBLIC PROC [g: CoordSysGenerator] RETURNS [cs: CoordSystem] = {
IF g.currentPtr = NIL THEN RETURN[NIL];
 cs ← g.currentPtr.first;
 g.currentPtr ← g.currentPtr.rest;
 };
Assembly Generator
GetListOfAssembliesFromScene: PRIVATE PROC [scene: Scene] RETURNS [aList: LIST OF Assembly] = {
 aList ← GetListOfAssembliesFromAssembly[scene.assembly];
 };

GetListOfAssembliesFromAssembly: PRIVATE PROC [assem: Assembly] RETURNS [aList: LIST OF Assembly] = {
 aList ← NIL;
WITH assem.object SELECT FROM
  al: AssemblyList => aList ← CONS[assem, GetListOfAssembliesFromAssemblyList[al]];
  ENDCASE => aList ← CONS[assem, NIL];
 };

GetListOfAssembliesFromAssemblyList: PRIVATE PROC [al: AssemblyList] RETURNS [aList: LIST OF Assembly] = {
 aList ← NIL;
FOR list: LIST OF Assembly ← al.list, list.rest UNTIL list = NIL DO
  aList ← AppendDestructiveAssemblies[aList, GetListOfAssembliesFromAssembly[list.first]];
ENDLOOP;
 };

AppendDestructiveAssemblies: PRIVATE PROC [list1, list2: LIST OF Assembly] RETURNS [LIST OF Assembly] = {
 list: LIST OF Assembly;
IF list1 = NIL THEN RETURN [list2];
 list ← list1;
UNTIL list.rest = NIL DO
  list ← list.rest;
ENDLOOP;
 list.rest ← list2;
RETURN[list1];
 }; -- end of AppendDestructiveAssemblies


GetAssemblyGenerator: PUBLIC PROC [scene: Scene] RETURNS [g: AssemblyGenerator] = {
 -- a pretty dumb generator. Walks the tree, makes the whole list and then feeds it to you one item at a time.
 aList: LIST OF Assembly ← GetListOfAssembliesFromScene[scene];
 g ← NEW[AssemblyGeneratorObj ← [currentPtr: aList]];
 };

AssemblyGenerator: TYPE = REF AssemblyGeneratorObj;
AssemblyGeneratorObj: TYPE = DisplayList3d.AssemblyGeneratorObj;

NextAssembly: PUBLIC PROC [g: AssemblyGenerator] RETURNS [a: Assembly] = {
IF g.currentPtr = NIL THEN RETURN[NIL];
 a ← g.currentPtr.first;
 g.currentPtr ← g.currentPtr.rest;
 };
LightSource Generator
GetLightSourceGenerator: PUBLIC PROC [scene: Scene] RETURNS [g: LightSourceGenerator] = {
 g ← NEW[LightSourceGeneratorObj ← [currentPtr: scene.lightSources]];
 };
LightSourceGenerator: TYPE = REF LightSourceGeneratorObj;
LightSourceGeneratorObj: TYPE = DisplayList3d.LightSourceGeneratorObj;
NextLight: PUBLIC PROC [g: LightSourceGenerator] RETURNS [ls: LightSource] = {
IF g.currentPtr = NIL THEN RETURN[NIL];
 ls ← g.currentPtr.first;
 g.currentPtr ← g.currentPtr.rest;
 };
MasterObject Generator
MasterObjectsOfScene: PUBLIC PROC [scene: Scene] RETURNS [l: MasterObjectList] = {
l ← scene.masterObjects;
};
MasterObjectsOfAssembly: PUBLIC PROC [assembly: Assembly, scene: Scene] RETURNS [l: MasterObjectList] = {
Get a list of the leaves of the tree and extract a master object from each. Remove duplicates.
primList: LIST OF Assembly ← ListOfPrimAssemblies[assembly, scene];
thisMO: MasterObject;
l ← NIL;
FOR list: LIST OF Assembly ← primList, list.rest UNTIL list = NIL DO
thisMO ← NARROW[list.first.object];
l ← CONS[thisMO, l];
ENDLOOP;
l ← RemoveDuplicateMOs[l];
};
List of Primitive Assemblies
ListOfPrimAssemblies: PUBLIC PROC [assembly: Assembly, scene: Scene] RETURNS [primList: LIST OF Assembly] = {
IF assembly = NIL THEN RETURN[NIL];
WITH assembly.object SELECT FROM
  aList: AssemblyList => primList ← ListOfPrimAssembliesFromAssemblyList[aList.list, scene];
  mo: MasterObject => primList ← CONS[assembly, NIL];
  ENDCASE => ERROR;
  };
  
ListOfPrimAssembliesFromAssemblyList: PRIVATE PROC [aList: LIST OF Assembly, scene: Scene] RETURNS [primList: LIST OF Assembly] = {
 thisList: LIST OF Assembly;
IF aList = NIL THEN RETURN[NIL];
 thisList ← ListOfPrimAssemblies[aList.first, scene];
IF thisList = NIL THEN primList ← ListOfPrimAssembliesFromAssemblyList[aList.rest, scene]
ELSE primList ← AppendDestructiveAssemblies[thisList,
  ListOfPrimAssembliesFromAssemblyList[aList.rest, scene]];
 };
Other List Auxiliaries
Removing Duplicates
RemoveDuplicateMOs: PRIVATE 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: PRIVATE 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: PRIVATE 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 ← AppendToMasterObjects[list.first, copy];
ENDLOOP;
};
Initialization
Init: PROC = {
 Create a database.
globalDatabase ← NEW[DatabaseObj ← [scenes: NIL]];
};

Init[];
END.