<> <> <> DIRECTORY CoordSys, CSG, CSGGraphics, Imager, Matrix3d, Rope, SV2d, SV3d, SVBasicTypes, SVBoundBox, SVBoundSphere, SVModelTypes, SVRayTypes, SVVector3d; CSGImpl: CEDAR PROGRAM IMPORTS CoordSys, Matrix3d, Rope, SVBoundBox, SVBoundSphere, SVVector3d EXPORTS CSG, SVRayTypes = BEGIN BoundBox: TYPE = SVBasicTypes.BoundBox; BoundSphere: TYPE = SVBasicTypes.BoundSphere; Camera: TYPE = SVModelTypes.Camera; Classification: TYPE = REF ClassificationObj; ClassificationObj: TYPE = SVRayTypes.ClassificationObj; Color: TYPE = Imager.Color; CoordSystem: TYPE = SVModelTypes.CoordSystem; Matrix4by4: TYPE = SV3d.Matrix4by4; Point2d: TYPE = SV2d.Point2d; Point3d: TYPE = SV3d.Point3d; Primitive: TYPE = REF PrimitiveObj; PrimitiveObj: TYPE = SVRayTypes.PrimitiveObj; Vector3d: TYPE = SV3d.Vector3d; PointSetOp: TYPE = SVRayTypes.PointSetOp; -- {union, intersection, difference}; Composite: TYPE = REF CompositeObj; CompositeObj: TYPE = SVRayTypes.CompositeObj; CSGTree: TYPE = REF CSGTreeObj; CSGTreeObj: TYPE = SVRayTypes.CSGTreeObj; Ray: TYPE = SVRayTypes.Ray; RayObj: PUBLIC TYPE = RECORD [ basePt: Point3d, direction: Vector3d, cameraBasePt: Point3d, cameraDirection: Vector3d, worldBasePt: Point3d, worldDirection: Point3d, cameraValid: BOOL _ FALSE, worldValid: BOOL _ FALSE]; globalRayPoolCount: NAT = 15; globalRayPoolPointer: NAT; RayPool: TYPE = REF RayPoolObj; RayPoolObj: TYPE = ARRAY[1..globalRayPoolCount] OF Ray; globalRayPool: RayPool; <> <> StuffCameraRay: PUBLIC PROC [ray: Ray, screenPoint: Point2d, camera: Camera] = { <> realRay: REF RayObj _ NARROW[ray]; realRay.basePt _ realRay.cameraBasePt _ [screenPoint[1], screenPoint[2], 0]; realRay.cameraValid _ TRUE; realRay.worldValid _ FALSE; IF camera.projection = perspective THEN { realRay.direction _ realRay.cameraDirection _ [screenPoint[1], screenPoint[2], -camera.focalLength]; } ELSE { -- orthographic projection realRay.direction _ realRay.cameraDirection _ [0, 0, -camera.focalLength]; }; }; StuffWorldRayFromCamera: PUBLIC PROC [ray: Ray, screenPoint: Point2d, camera: Camera] = { <> realRay: REF RayObj _ NARROW[ray]; cameraWorld: Matrix4by4; realRay.cameraBasePt _ [screenPoint[1], screenPoint[2], 0]; IF camera.projection = perspective THEN { realRay.cameraDirection _ [screenPoint[1], screenPoint[2], -camera.focalLength]; } ELSE { -- orthographic projection realRay.cameraDirection _ [0, 0, -camera.focalLength]; }; realRay.cameraValid _ TRUE; cameraWorld _ CoordSys.FindInTermsOfWorld[camera.coordSys]; realRay.basePt _ realRay.worldBasePt _ Matrix3d.Update[realRay.cameraBasePt, cameraWorld]; realRay.direction _ realRay.worldDirection _ Matrix3d.UpdateVectorEvenScaling[realRay.cameraDirection, cameraWorld]; realRay.worldValid _ TRUE; }; StuffCameraRayLiterally: PUBLIC PROC [ray: Ray, base: Point3d, direction: Vector3d] = { realRay: REF RayObj _ NARROW[ray]; realRay.basePt _ realRay.cameraBasePt _ base; realRay.direction _ realRay.cameraDirection _ direction; realRay.cameraValid _ TRUE; realRay.worldValid _ FALSE; }; StuffWorldRay: PUBLIC PROC [ray: Ray, basePt: Point3d, direction: Vector3d, camera: Camera] = { <> worldCAMERA: Matrix4by4; realRay: REF RayObj _ NARROW[ray]; realRay.basePt _ realRay.worldBasePt _ basePt; realRay.direction _ realRay.worldDirection _ direction; <> worldCAMERA _ CoordSys.FindAInTermsOfB[camera.coordSys.parent, camera.coordSys]; realRay.cameraBasePt _ Matrix3d.Update[basePt, worldCAMERA]; realRay.cameraDirection _ Matrix3d.UpdateVectorEvenScaling[direction, worldCAMERA]; realRay.cameraValid _ TRUE; realRay.worldValid _ TRUE; }; StuffWorldOnlyRay: PUBLIC PROC [ray: Ray, basePt: Point3d, direction: Vector3d] = { <> realRay: REF RayObj _ NARROW[ray]; realRay.basePt _ realRay.worldBasePt _ basePt; realRay.direction _ realRay.worldDirection _ direction; realRay.cameraValid _ FALSE; realRay.worldValid _ TRUE; }; StuffWorldRayFromPoints: PUBLIC PROC [ray: Ray, basePt: Point3d, directionPt: Point3d] = { <> realRay: REF RayObj _ NARROW[ray]; direction: Vector3d _ SVVector3d.Sub[directionPt, basePt]; realRay.basePt _ realRay.worldBasePt _ basePt; realRay.direction _ realRay.worldDirection _ direction; realRay.cameraValid _ FALSE; realRay.worldValid _ TRUE; }; StuffLocalRay: PUBLIC PROC [ray: Ray, basePt: Point3d, direction: Vector3d, camera: Camera, localCS: CoordSystem] = { <> realRay: REF RayObj _ NARROW[ray]; realRay.basePt _ basePt; realRay.direction _ direction; realRay.cameraValid _ FALSE; realRay.worldValid _ FALSE; }; EvaluateWorldRay: PUBLIC PROC [ray: Ray, t: REAL] RETURNS [pt: Point3d] = { realRay: REF RayObj _ NARROW[ray]; p: Point3d; d: Vector3d; IF NOT realRay.worldValid THEN ERROR; p _ realRay.worldBasePt; d _ realRay.worldDirection; pt[1] _ p[1] + t*d[1]; pt[2] _ p[2] + t*d[2]; pt[3] _ p[3] + t*d[3]; }; EvaluateCameraRay: PUBLIC PROC [ray: Ray, t: REAL] RETURNS [pt: Point3d] = { realRay: REF RayObj _ NARROW[ray]; p: Point3d; d: Vector3d; IF NOT realRay.cameraValid THEN ERROR; p _ realRay.cameraBasePt; d _ realRay.cameraDirection; pt[1] _ p[1] + t*d[1]; pt[2] _ p[2] + t*d[2]; pt[3] _ p[3] + t*d[3]; }; EvaluateLocalRay: PUBLIC PROC [ray: Ray, t: REAL] RETURNS [pt: Point3d] = { realRay: REF RayObj _ NARROW[ray]; p: Point3d; d: Vector3d; p _ realRay.basePt; d _ realRay.direction; pt[1] _ p[1] + t*d[1]; pt[2] _ p[2] + t*d[2]; pt[3] _ p[3] + t*d[3]; }; EvaluateLocalRay2: PUBLIC PROC [ray: Ray, t: REAL] RETURNS [x, y, z: REAL] = { realRay: REF RayObj _ NARROW[ray]; p: Point3d; d: Vector3d; p _ realRay.basePt; d _ realRay.direction; x _ p[1] + t*d[1]; y _ p[2] + t*d[2]; z _ p[3] + t*d[3]; }; GetCameraRay: PUBLIC PROC [ray: Ray] RETURNS [basePt: Point3d, direction: Vector3d] = { realRay: REF RayObj _ NARROW[ray]; IF NOT realRay.cameraValid THEN ERROR; basePt _ realRay.cameraBasePt; direction _ realRay.cameraDirection; }; GetWorldRay: PUBLIC PROC [ray: Ray] RETURNS [basePt: Point3d, direction: Vector3d] = { realRay: REF RayObj _ NARROW[ray]; IF NOT realRay.worldValid THEN ERROR; basePt _ realRay.worldBasePt; direction _ realRay.worldDirection; }; GetLocalRay: PUBLIC PROC [ray: Ray] RETURNS [basePt: Point3d, direction: Vector3d] = { realRay: REF RayObj _ NARROW[ray]; basePt _ realRay.basePt; direction _ realRay.direction; }; << >> CreateRay: PUBLIC PROC RETURNS [ray: Ray] = { ray _ NEW[RayObj]; }; GetRayFromPool: PUBLIC PROC RETURNS [ray: Ray] = { IF globalRayPoolPointer = 0 THEN SIGNAL RayPoolEmpty; ray _ globalRayPool[globalRayPoolPointer]; globalRayPoolPointer _ globalRayPoolPointer -1; }; RayPoolEmpty: SIGNAL = CODE; ReturnRayToPool: PUBLIC PROC [ray: Ray] = { IF globalRayPoolPointer = globalRayPoolCount THEN SIGNAL RayPoolFull; globalRayPoolPointer _ globalRayPoolPointer + 1; globalRayPool[globalRayPoolPointer] _ ray; }; RayPoolFull: SIGNAL = CODE; TransformRay: PUBLIC PROC [ray: Ray, mat: Matrix4by4] RETURNS [newRay: Ray] = { realRay, realNewRay: REF RayObj; newRay _ GetRayFromPool[]; realNewRay _ NARROW[newRay]; realRay _ NARROW[ray]; realNewRay.basePt _ Matrix3d.Update[realRay.basePt, mat]; realNewRay.direction _ Matrix3d.UpdateVectorEvenScaling[realRay.direction, mat]; <> IF realRay.cameraValid THEN { realNewRay.cameraBasePt _ realRay.cameraBasePt; realNewRay.cameraDirection _ realRay.cameraDirection; }; IF realRay.worldValid THEN { realNewRay.worldBasePt _ realRay.worldBasePt; realNewRay.worldDirection _ realRay.worldDirection; }; realNewRay.cameraValid _ realRay.cameraValid; realNewRay.worldValid _ realRay.worldValid; }; -- end of TransformRay TransformRayToWorld: PUBLIC PROC [ray: Ray, cameraWORLD: Matrix4by4] RETURNS [newRay: Ray] = { <> realRay, realNewRay: REF RayObj; newRay _ GetRayFromPool[]; realNewRay _ NARROW[newRay]; realRay _ NARROW[ray]; realNewRay.basePt _ Matrix3d.Update[realRay.basePt, cameraWORLD]; realNewRay.direction _ Matrix3d.UpdateVectorEvenScaling[realRay.direction, cameraWORLD]; <> IF realRay.cameraValid THEN { realNewRay.cameraBasePt _ realRay.cameraBasePt; realNewRay.cameraDirection _ realRay.cameraDirection; }; realNewRay.worldValid _ TRUE; realNewRay.worldBasePt _ realNewRay.basePt; realNewRay.worldDirection _ realNewRay.direction; realNewRay.cameraValid _ realRay.cameraValid; }; -- end of TransformRayToWorld <<>> TransformNewRay: PUBLIC PROC [ray: Ray, mat: Matrix4by4] RETURNS [newRay: Ray] = { realRay, realNewRay: REF RayObj; newRay _ CreateRay[]; realNewRay _ NARROW[newRay]; realRay _ NARROW[ray]; realNewRay.basePt _ Matrix3d.Update[realRay.basePt, mat]; realNewRay.direction _ Matrix3d.UpdateVectorEvenScaling[realRay.direction, mat]; <> IF realRay.cameraValid THEN { realNewRay.cameraBasePt _ realRay.cameraBasePt; realNewRay.cameraDirection _ realRay.cameraDirection; }; IF realRay.worldValid THEN { realNewRay.worldBasePt _ realRay.worldBasePt; realNewRay.worldDirection _ realRay.worldDirection; }; realNewRay.cameraValid _ realRay.cameraValid; realNewRay.worldValid _ realRay.worldValid; }; -- end of TransformNewRay AddRay: PUBLIC PROC [ray1, ray2: Ray] = { -- puts sum in ray2 real1, real2: REF RayObj; real1 _ NARROW[ray1]; real2 _ NARROW[ray2]; real2.basePt _ SVVector3d.Add[real1.basePt, real2.basePt]; real2.direction _ SVVector3d.Add[real1.direction, real2.direction]; real2.cameraValid _ FALSE; -- for now IF real1.worldValid AND real2.worldValid THEN { real2.worldBasePt _ SVVector3d.Add[real1.worldBasePt, real2.worldBasePt]; real2.worldDirection _ SVVector3d.Add[real1.worldDirection, real2.worldDirection]; } ELSE real2.worldValid _ FALSE; }; -- end of AddRay SubtractRays: PUBLIC PROC [ray1, ray2: Ray] RETURNS [ray1MinusRay2: Ray] = { -- allocates a new ray. realRay, real1, real2: REF RayObj; ray1MinusRay2 _ CreateRay[]; realRay _ NARROW[ray1MinusRay2]; real1 _ NARROW[ray1]; real2 _ NARROW[ray2]; realRay.basePt _ SVVector3d.Sub[real1.basePt, real2.basePt]; realRay.direction _ SVVector3d.Sub[real1.direction, real2.direction]; realRay.cameraValid _ FALSE; -- for now IF real1.worldValid AND real2.worldValid THEN { realRay.worldBasePt _ SVVector3d.Sub[real1.worldBasePt, real2.worldBasePt]; realRay.worldDirection _ SVVector3d.Sub[real1.worldDirection, real2.worldDirection]; realRay.worldValid _ TRUE; } ELSE realRay.worldValid _ FALSE; }; -- end of SubtractRays CopyClass: PUBLIC PROC [class: Classification] RETURNS [copy: Classification] = { copy _ NEW[ClassificationObj]; copy.count _ class.count; copy.params _ class.params; copy.surfaces _ class.surfaces; copy.primitives _ class.primitives; copy.classifs _ class.classifs; copy.normals _ class.normals; }; MakeCompositeCell: PUBLIC PROC [name: Rope.ROPE, operation: PointSetOp, LeftSolidPtr: REF ANY, RightSolidPtr: REF ANY] RETURNS [c: Composite] = { c _ NEW[CompositeObj _ [name, operation, LeftSolidPtr, RightSolidPtr, NIL, NIL]]; }; MakeCSGTree: PUBLIC PROC [son: REF ANY, backgroundColor: Color, shadows: BOOL] RETURNS [tree: CSGTree] = { name: Rope.ROPE; IF son = NIL THEN name _ "Empty Scene" ELSE { WITH son SELECT FROM prim: Primitive => name _ prim.name; comp: Composite => name _ comp.name; ENDCASE => ERROR; }; tree _ NEW[CSGTreeObj _ [name, TRUE, son, backgroundColor, shadows]]; }; CombineBoundBoxes: PUBLIC PROC [bb1, bb2: BoundBox, op: PointSetOp] RETURNS [newBB: BoundBox] = { <> SELECT op FROM union => newBB _ SVBoundBox.UnionCombineBoundBoxes[bb1, bb2]; intersection => newBB _ SVBoundBox.IntersectionCombineBoundBoxes[bb1, bb2]; difference => newBB _ SVBoundBox.DifferenceCombineBoundBoxes[bb1, bb2]; ENDCASE => ERROR; }; CombineBoundSpheres: PUBLIC PROC [bs1, bs2: BoundSphere, op: PointSetOp] RETURNS [newBS: BoundSphere] = { <> SELECT op FROM union => newBS _ SVBoundSphere.UnionCombineBoundSpheres[bs1, bs2]; intersection => newBS _ SVBoundSphere.IntersectionCombineBoundSpheres[bs1, bs2]; difference => newBS _ SVBoundSphere.DifferenceCombineBoundSpheres[bs1, bs2]; ENDCASE => ERROR; }; RayHitsBoundSphere: PUBLIC PROC [worldRay: Ray, boundSphere: BoundSphere] RETURNS [BOOL] = { <> magRaySquared, dotProd, dotProdSquared, rCosThetaSquared, dSquared, rSquared: REAL; vecToCenter: Vector3d; basePtWORLD: Point3d; directionWORLD: Vector3d; IF boundSphere = NIL THEN RETURN[TRUE]; -- NIL is used to represent an infinite bounding sphere [basePtWORLD, directionWORLD] _ GetWorldRay[worldRay]; magRaySquared _ SVVector3d.MagnitudeSquared[directionWORLD]; vecToCenter _ SVVector3d.Sub[boundSphere.center, basePtWORLD]; rSquared _ SVVector3d.MagnitudeSquared[vecToCenter]; dotProd _ SVVector3d.DotProduct[directionWORLD, vecToCenter]; dotProdSquared _ dotProd*dotProd; rCosThetaSquared _ dotProdSquared/magRaySquared; dSquared _ rSquared - rCosThetaSquared; -- Pythagorean Theorem RETURN[dSquared <= boundSphere.radiusSquared]; }; PointSetOpToRope: PUBLIC PROC [pointSetOp: PointSetOp] RETURNS [opRope: Rope.ROPE] = { SELECT pointSetOp FROM union => opRope _ "union"; intersection => opRope _ "intersection"; difference => opRope _ "difference"; ENDCASE => ERROR; }; RopeToPointSetOp: PUBLIC PROC [opRope: Rope.ROPE] RETURNS [pointSetOp: PointSetOp] = { SELECT TRUE FROM Rope.Equal[opRope, "union", TRUE] => pointSetOp _ union; Rope.Equal[opRope, "intersection", TRUE] => pointSetOp _ intersection; Rope.Equal[opRope, "difference", TRUE] => pointSetOp _ difference; ENDCASE => ERROR; }; <> <<>> Init: PROC = { <> <<>> globalRayPool _ NEW[RayPoolObj]; FOR i: NAT IN[1..globalRayPoolCount] DO globalRayPool[i] _ NEW[RayObj]; ENDLOOP; globalRayPoolPointer _ globalRayPoolCount; }; Init[]; END.