SetEyeSpace:
PUBLIC
PROC[ context:
REF Context ] ~ {
in, right, up, normal: Triple;
mtx: Xfm3d;
wndw: Imager.Rectangle;
aspectRatio, viewWidth, viewHeight: REAL;
bounds: Pixels.Extent ← [
0, 0, Ceiling[context.viewPort.w], Ceiling[context.viewPort.h] ];
IF bounds.h > 0
AND bounds.w > 0
THEN aspectRatio ← Real.Float[bounds.w] / bounds.h
ELSE RETURN[];
transform from world to eye
in ← Vector3d.Normalize[Vector3d.Sub[context.ptOfInterest, context.eyePoint]];
IF Vector3d.Null[in] THEN SIGNAL Error[[$MisMatch, "Eye and Pt of Interest identical"]];
right ← Vector3d.Normalize[Vector3d.Cross[in, context.upDirection]];
IF Vector3d.Null[right] THEN right ← [1.0, 0.0, 0.0]; -- looking straight down
up ← Vector3d.Normalize[Vector3d.Cross[right, in]];
normalize not really needed (to avoid roundoff problems)
context.eyeSpaceXfm ← Matrix3d.Identity[];
context.eyeSpaceXfm[0][0] ← right.x;
context.eyeSpaceXfm[1][0] ← right.y;
context.eyeSpaceXfm[2][0] ← right.z;
context.eyeSpaceXfm[3][0] ← -Vector3d.Dot[right, context.eyePoint];
context.eyeSpaceXfm[0][1] ← up.x;
context.eyeSpaceXfm[1][1] ← up.y;
context.eyeSpaceXfm[2][1] ← up.z;
context.eyeSpaceXfm[3][1] ← -Vector3d.Dot[up, context.eyePoint];
context.eyeSpaceXfm[0][2] ← in.x;
context.eyeSpaceXfm[1][2] ← in.y;
context.eyeSpaceXfm[2][2] ← in.z;
context.eyeSpaceXfm[3][2] ← -Vector3d.Dot[in, context.eyePoint];
mtx ← Matrix3d.Identity[]; -- Roll about z-axis, clockwise
mtx[0][0] ← RealFns.CosDeg[context.rollAngle];
mtx[0][1] ← -RealFns.SinDeg[context.rollAngle];
mtx[1][0] ← RealFns.SinDeg[context.rollAngle];
mtx[1][1] ← RealFns.CosDeg[context.rollAngle];
context.eyeSpaceXfm ← Matrix3d.Mul[context.eyeSpaceXfm, mtx];
IF NOT (context.window.w > 0.0 AND context.window.h > 0.0) THEN RETURN[];
viewWidth ← 2.*RealFns.TanDeg[context.fieldOfView/2.];
wndw.x ← MIN[1.0, MAX[-1.0, context.window.x] ];
wndw.w ← MIN[1.0-wndw.x, context.window.w ];
wndw.y ← MIN[1.0, MAX[-1.0, context.window.y] ];
wndw.h ← MIN[1.0-wndw.y, context.window.h ];
context.clippingPlanes[Near] ← [0., 0., 1., -context.hitherLimit];
context.clippingPlanes[Far] ← [0., 0., -1., context.yonLimit];
normalize plane equation for true distances
normal ← Vector3d.Normalize[[1., 0., -(wndw.x * viewWidth/2.)]];
context.clippingPlanes[Left] ← [normal.x, 0., normal.z, 0.];
normal ← Vector3d.Normalize[[-1., 0., (wndw.x + wndw.w) * viewWidth/2.]];
context.clippingPlanes[Right] ← [normal.x, 0., normal.z, 0.];
normal ← Vector3d.Normalize[[0., 1., -(wndw.y * viewWidth/2.)]];
context.clippingPlanes[Bottom] ← [0., normal.y, normal.z, 0.];
normal ← Vector3d.Normalize[[0., -1., (wndw.y + wndw.h) * viewWidth/2.]];
context.clippingPlanes[Top] ← [0., normal.y, normal.z, 0.];
compute the transformation from the eye coord sys to normalized display coordinates (-1.—1.)
IF aspectRatio > 1.0
-- set angle of view on smallest viewport dimension
THEN { viewHeight ← viewWidth; viewWidth ← viewWidth * aspectRatio; }
ELSE { viewHeight ← viewWidth / aspectRatio; };
IF wndw.w / wndw.h > 1.0
THEN { viewWidth ← viewWidth * wndw.h / wndw.w; }
ELSE { viewHeight ← viewHeight * wndw.w / wndw.h; };
context.eyeToNDC.addX ← -(wndw.x / wndw.w);
context.eyeToNDC.addY ← -(wndw.y / wndw.h);
context.eyeToNDC.addZ ← 1./(1. - context.hitherLimit/context.yonLimit);
context.eyeToNDC.scaleX ← 1./(wndw.w * viewWidth / 2.0);
context.eyeToNDC.scaleY ← 1./(wndw.h * viewHeight / 2.0);
context.eyeToNDC.scaleZ ← -context.hitherLimit/(1. - context.hitherLimit/context.yonLimit);
};
SetLight:
PUBLIC PROC[context:
REF Context, name: Rope.
ROPE, position: Triple,
color:
RGB ← [1.,1.,1.] ]
RETURNS[
REF ShapeInstance] ~ {
light: REF ShapeInstance ← FindShape[ context.shapes, name ! Error =>
IF reason.code = $MisMatch THEN RESUME ];
IF light =
NIL
THEN {
light ← NewShape[ name ]; -- name not used before
context.lights ← AddShape[ context.lights, light ]; -- used just for lighting
context.shapes ← AddShape[ context.shapes, light ]; -- all shapes
};
light.type ← $Light;
light.location ← position;
light.boundingRadius ← 2 * 93000000.0 * 1609.344; -- twice solar distance in meters
light.orientation ← [0.,0.,0.]; -- no orientation by default
light.positionInValid ← TRUE;
light.vtcesInValid ← TRUE;
PutShading[ light, $Color, NEW[RGB ← color] ];
light.props ← Atom.PutPropOnList[light.props, $Hidden, $DoIt]; -- hide from display routines
FOR i:
NAT
IN [0..context.shapes.length)
DO
context.shapes[i].shadingInValid ← TRUE;
ENDLOOP;
RETURN[light];
};
WriteScene:
PUBLIC PROC[context:
REF Context, output:
IO.STREAM] ~ {
Vec3toRope:
PROC[ r1, r2, r3:
REAL]
RETURNS[Rope.
ROPE] ~ {
rope: Rope.ROPE;
rope ← Rope.Cat[ " ", Convert.RopeFromReal[r1], " ", Convert.RopeFromReal[r2] ];
rope ← Rope.Cat[ rope, " ", Convert.RopeFromReal[r3], " " ];
RETURN[ rope ];
};
Vec4toRope:
PROC[ r1, r2, r3, r4:
REAL]
RETURNS[Rope.
ROPE] ~ {
rope: Rope.ROPE;
rope ← Rope.Cat[ " ", Convert.RopeFromReal[r1], " ", Convert.RopeFromReal[r2], " " ];
rope ← Rope.Cat[ rope, Convert.RopeFromReal[r3], " ", Convert.RopeFromReal[r4], " " ];
RETURN[ rope ];
};
ref: REF;
line ← Rope.Cat["
View: ",
Vec3toRope[context.eyePoint.x, context.eyePoint.y, context.eyePoint.z],
Vec3toRope[context.ptOfInterest.x, context.ptOfInterest.y, context.ptOfInterest.z],
Vec3toRope[context.upDirection.x, context.upDirection.y, context.upDirection.z]
];
IO.PutRope[ output, Rope.Cat[line,
Vec4toRope[ context.rollAngle, context.fieldOfView, context.hitherLimit, context.yonLimit ],
"\n"
] ];
IO.PutRope[ output, Rope.Cat["
ViewPort: ",
Vec4toRope[context.viewPort.x, context.viewPort.y, context.viewPort.w, context.viewPort.h],
"\n"
] ];
IO.PutRope[ output, Rope.Cat["
Window: ",
Vec4toRope[context.window.x, context.window.y, context.window.w, context.window.h],
"\n"
] ];
ref ← Atom.GetPropFromList[context.props, $BackGround]; -- get background color
IF ref #
NIL
THEN {
color: RGB ← NARROW[ref, REF RGB]^;
IO.PutRope[ output,
Rope.Cat[ "BackgroundColor: ", Vec3toRope[color.R, color.G, color.B], "\n" ]
];
};
Light Sources
FOR i:
NAT
IN [0..context.lights.length)
DO
color: REF RGB ← NARROW[ GetShading[ context.lights[i], $Color ] ];
IO.PutRope[ output, Rope.Cat["
Light: ", context.lights[i].name,
Vec3toRope[
context.lights[i].location.x, context.lights[i].location.y, context.lights[i].location.z ],
Vec3toRope[color.R, color.G, color.B],
"\n"
] ];
ENDLOOP;
Shapes
FOR i:
NAT
IN [0..context.shapes.length)
DO
shape: REF ThreeDBasics.ShapeInstance ← context.shapes[i];
IF shape #
NIL
AND Atom.GetPropFromList[shape.props, $Hidden] =
NIL
AND shape.clipState # out
AND shape.surface #
NIL
THEN {
ref: REF ANY ← NIL;
xfm: Matrix3d.Matrix ← shape.position;
scale: REF ThreeDBasics.Quad ← NARROW[ GetShading[ shape, $Scale ] ];
color: REF RGB ← NARROW[ GetShading[ shape, $Color ] ];
shadingType: ATOM ← NARROW[GetShading[ shape, $Type ] ];
transmtnce: REF REAL ← NARROW[GetShading[ shape, $Transmittance]];
shininess: REF REAL ← NARROW[GetShading[ shape, $Shininess ] ];
texture: REF TextureMaps.TextureMap ← NARROW[ GetShading[ shape, $TextureMap ] ];
textureScale: REF ThreeDBasics.Quad ← NARROW[ GetShading[ shape, $TextureScale ] ];
File Name, instance name, and Surface Type
line ← Rope.Cat[ "Shape: ", shape.name, " ", shape.fileName, " " ];
line ← Rope.Cat[ line, Atom.GetPName[shape.type] ];
IF shape.insideVisible
THEN line ← Rope.Cat[line, " TRUE \n"]
ELSE line ← Rope.Cat[line, " FALSE \n"];
IO.PutRope[ output, line];
Scaling
IF scale #
NIL
THEN {
line ← Rope.Cat[" ScaleShape: ",
Vec4toRope[scale.x, scale.y, scale.z, scale.w],
"\n" ];
IO.PutRope[ output, line];
};
Shape Transform
IF xfm = NIL THEN { SetPosition[shape]; xfm ← shape.position; };
line ← Rope.Cat[" ShapeXfm: ",
Vec4toRope[xfm[0][0], xfm[0][1], xfm[0][2], xfm[0][3]],
Vec4toRope[xfm[1][0], xfm[1][1], xfm[1][2], xfm[1][3]] ];
line ← Rope.Cat[line,
Vec4toRope[xfm[2][0], xfm[2][1], xfm[2][2], xfm[2][3]],
Vec4toRope[xfm[3][0], xfm[3][1], xfm[3][2], xfm[3][3]], "\n" ];
IO.PutRope[ output, line];
Color, Transmittance, Shininess
IF shadingType = $Smooth
AND GetShading[ shape, $VertexColorsInFile ] = NIL
AND color # NIL THEN IO.PutRope[output,
Rope.Cat[" SmoothColor: ", Vec3toRope[color.R, color.G, color.B], "\n"] ];
IF shadingType = $Faceted
AND GetShading[ shape, $PatchColorsInFile ] = NIL
AND color # NIL THEN IO.PutRope[output,
Rope.Cat[" FacetedColor: ", Vec3toRope[color.R, color.G, color.B], "\n"] ];
IF transmtnce # NIL THEN IO.PutRope[ output,
Rope.Cat[" Transmittance: ", Convert.RopeFromReal[transmtnce^], "\n" ] ];
IF shininess #
NIL
THEN
IO.PutRope[ output,
Rope.Cat["
Shininess: ", Convert.RopeFromReal[shininess^], "\n" ] ];
Mapped Texture
IF texture #
NIL
THEN {
fileName: Rope.ROPE ← NARROW[ Atom.GetPropFromList[texture.props, $FileName] ];
coordType: ATOM ← NARROW[ Atom.GetPropFromList[texture.props, $CoordType] ];
coords: REF ← Atom.GetPropFromList[texture.props, $Coords];
IF coordType = NIL THEN coordType ← $NoCoords;
line ← Rope.Cat[" MapTexture: ", fileName, " ", Atom.GetPName[texture.type] ];
line ← Rope.Cat[line, " ", Atom.GetPName[coordType], " " ];
SELECT coordType
FROM
$FromVtxNos, $FromNormals => {
argList: LIST OF REAL ← NARROW[coords];
WHILE argList #
NIL
DO
line ← Rope.Cat[line, Convert.RopeFromReal[argList.first], " " ];
argList ← argList.rest;
ENDLOOP;
};
ENDCASE => SIGNAL Error[[$Unimplemented, "Unknown texture coordType"]];
IO.PutRope[ output, Rope.Cat[line, "\n"] ];
IF textureScale #
NIL
THEN {
line ← Rope.Cat[
" ScaleTexture: ",
Vec4toRope[textureScale.x, textureScale.y, textureScale.z, textureScale.w],
"\n" ];
IO.PutRope[ output, line];
};
};
Solid Texture
ref ← GetShading[ shape, $ShadingProcs];
IF ref #
NIL
THEN {
getVtxProc: ThreeDBasics.VtxToRealSeqProc ← NIL;
getColorProc: ScanConvert.GetColorProc ← NIL;
[getVtxProc, getColorProc] ← NARROW[ ref, REF ThreeDScenes.ShadingProcs ]^;
IF getColorProc #
NIL
THEN {
procName: Rope.ROPE ← SolidTextures.ProcToRope[getColorProc];
IO.PutRope[ output, Rope.Cat[" SolidTexture: ", procName, "\n"] ];
};
};
};
ENDLOOP;
IO.PutRope[ output, "EndOfScene:\n"];
};