Render3dImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, February 26, 1987 11:18:04 pm PST
DIRECTORY Atom, CedarProcess, ColorDisplay, Controls3d, FileNames, Imager, ImagerColor, ImagerColorMap, Matrix3d, Pixels, RealFns, Render3d, Rope, RuntimeError, Terminal, TextureMaps, ThreeDBasics, ThreeDMisc, ThreeDScenes, Vector3d, ViewerClasses, ViewerOps;
Render3dImpl: CEDAR PROGRAM
IMPORTS Atom, CedarProcess, ColorDisplay, Controls3d, FileNames, ImagerColorMap, RealFns, Rope, RuntimeError, Terminal, TextureMaps, ThreeDMisc, ThreeDScenes, Vector3d, ViewerOps
EXPORTS Render3d
~ BEGIN
OPEN Render3d;
Recommendations for ThreeDWorld
Problems
What to do if fov = 0?
Why need shape name to set bounding sphere in Render?
Why is it so difficult to change rendering style? Why doesn't shadingType default to something reasonable; why isn't the NARROW in ThreeDSurfaces properly error guarded?
Definitions
Shape.surface shouldn't be a REF ANY -- unsafe! (even if it is general); why not shape.polys, shape.patches, etc.?
Shading type should be a separate field in the ShapeInstance and default to smooth, rather than be a part of the property list.
Type ThreeDBasics.Context should be renamed ThreeDBasics.Context3d.
General
ThreeDWorld is incredibly top-heavy; a client oriented package should be created that would allow simple rendering functions without all the other baggage.
Certain procedures shouldn't use atoms as parameters (e.g., PutShading shouldn't take an atom, but an enumerated type).
There seems to be a serious problem in ThreeDSurfaces.LoadSortSequence; buckets run out of range if the object is placed off-screen.
Is there a way to blit in the new pix, rather than clearing the screen first?
Globals
contexts3d:   ARRAY [0..nGlobalContext3d) OF Context3d ← ALL[NIL];
processes:    ARRAY [0..nGlobalContext3d) OF Process ← ALL[NIL];
Context3d Initialization
CDNotifier: ColorDisplay.CDNotifyProc ~ {
IF new.on AND (old.bpp # new.bpp OR old.gray # new.gray
OR NOT Rope.Equal[old.monitorType, new.monitorType]) THEN
FOR n: NAT IN [0..nGlobalContext3d) DO
IF contexts3d[n] # NIL THEN {
SetContext3dDisplay[contexts3d[n], new];
ThreeDMisc.MakeFrame[contexts3d[n]];
};
ENDLOOP;
};
InitContext3d: PUBLIC PROC [background: Triple ← defaultBackground] RETURNS [Context3d]
~ {
cdState: CDState ← GetColorDisplayStatus[];
context3d: Context3d ← ThreeDScenes.Create[];
backgroundRef: REF RGBNEW[RGB ← [background.x, background.y, background.z]];
IF NOT cdState.on THEN ColorDisplay.SetColorDisplayStatus[on: TRUE];
IF cdState.gray THEN backgroundRef^ ← [0.0, 0.0, 0.0];   -- sometimes a good idea
FOR n: NAT IN [0..nGlobalContext3d) DO
IF contexts3d[n] = NIL THEN {
contexts3d[n] ← context3d;
EXIT;
};
ENDLOOP;
SetContext3dDisplay[context3d, cdState];
context3d.props ← Atom.PutPropOnList[
context3d.props, $WDir, FileNames.CurrentWorkingDirectory[]];
context3d.props ← Atom.PutPropOnList[context3d.props, $BackGround, backgroundRef];
[] ← ThreeDScenes.SetLight[context3d, "Light1", [-100.0, -200.0, 50.0]];
ThreeDScenes.SetView[context3d, [2.0, -10.0, 3.0], origin];
RETURN[context3d];
};
Context3dIndex: PROC [context3d: Context3d] RETURNS [INTEGER] ~ {
FOR n: NAT IN [0..nGlobalContext3d) DO
IF contexts3d[n] = context3d THEN RETURN[n];
ENDLOOP;
RETURN[-1];
};
NullifyThreeDContext: PUBLIC PROC [context3d: Context3d] ~ {
index: INTEGER ← Context3dIndex[context3d];
IF index # -1 THEN contexts3d[index] ← NIL;
};
GetColorDisplayStatus: PROC RETURNS [CDState] ~ {
on, onLeft, gray: BOOL;
bpp, bppB: CARDINAL;
monitorType: ROPE;
[on, onLeft, gray, bpp, bppB, monitorType] ← ColorDisplay.GetColorDisplayStatus[];
RETURN[[on, onLeft, gray, bpp, bppB, monitorType]];
};
ChangeRenderMode: PROC [context3d: Context3d, mode: ATOM] ~ {
SELECT mode FROM
$Dithered => ImagerColorMap.SetStandardColorMap[Terminal.Current[]];
$PseudoColor => ThreeDMisc.LoadStd8BitClrMap[Terminal.Current[]];
$Grey => ThreeDMisc.LoadColorRamp[Terminal.Current[], [0.,0.,0.], [1.,1.,1.], [.43,.43,.43]];
ENDCASE;
context3d.renderMode ← context3d.preferredRenderMode ← mode;
context3d.display.props ← Atom.PutPropOnList[context3d.display.props, $RenderMode, mode];
};
SetContext3dDisplay: PROC [context3d: Context3d, cdState: CDState] ~ {
CloseColorViewers[];
ThreeDScenes.DisplayFromTerminal[context3d, Terminal.Current[]];
IF cdState.gray AND context3d.renderMode = $PseudoColor
THEN ChangeRenderMode[context3d, $Grey];
};
CloseColorViewers: PROC ~ {
EnumProc: ViewerOps.EnumProc ~ {
IF v.column = color THEN {
ViewerOps.CloseViewer[v];
ViewerOps.ChangeColumn[v, left];
};
};
ViewerOps.EnumerateViewers[EnumProc];
};
Inserting Objects
AddFileShape: PUBLIC PROC [
context3d: Context3d,
shapeName: ROPE,
fileName: ROPE,
position: Triple ← origin,
color: RGB ← [0.7, 0.7, 0.7],
renderStyle: RenderStyle ← none]
~ {
ThreeDMisc.AddShapeAt[context3d, shapeName, fileName, position];
SELECT renderStyle FROM
faceted => ThreeDMisc.SetFacetedColor[context3d, shapeName, color];
smooth =>ThreeDMisc.SetSmoothColor[context3d, shapeName, color];
ENDCASE;
};
AddObject: PUBLIC PROC [
context3d: Context3d,
polygons: REF NatTable,
vertices: REF VertexSequence,
shades: REF ShadingSequence,
textures: TripleSequence ← NIL,
position: Triple ← origin,
name: ROPENIL,
renderStyle: RenderStyle ← faceted,
insideVisible: BOOLFALSE,
matrix: Matrix ← NIL]
~ {
IF
vertices # NIL AND vertices.length > 0 AND
shades # NIL AND shades.length > 0 AND
polygons # NIL AND polygons.length > 0 THEN {
shape: REF ShapeInstance ← ThreeDScenes.NewShape[name];
surfaces: REF PtrPatchSequence ← NEW[PtrPatchSequence[polygons.length]];
shape.surface ← surfaces;
shape.auxInfo ← textures;
shape.type ← $ConvexPolygon;
shape.insideVisible ← insideVisible;
shape.vertex ← vertices;
shape.shade ← shades;
shape.numSurfaces ← polygons.length;
FOR n: NAT IN [0..polygons.length) DO
nVtces: INTEGER ← polygons[n].length;
surfaces[n] ← NEW[PtrPatch ← [
vtxPtr: NEW[NatSequence[nVtces]],
type: shape.type,
oneSided: NOT insideVisible,
nVtces: nVtces
]];
FOR i: NAT IN [0..nVtces) DO surfaces[n].vtxPtr[i] ← polygons[n][i]; ENDLOOP;
ENDLOOP;
context3d.shapes ← ThreeDScenes.DeleteShape[context3d.shapes, name !
ThreeDScenes.Error => CONTINUE];
context3d.shapes ← ThreeDScenes.AddShape[context3d.shapes, shape];
ThreeDScenes.PlaceShape[shape, position];
SetRenderStyle[context3d, name, renderStyle];
ThreeDMisc.SetFacetedColor[context3d, name, [0.7, 0.7, 0.7]];
ThreeDMisc.SetSmoothColor[context3d, name, [0.7, 0.7, 0.7]];
IF matrix # NIL THEN SetObjectMatrix[context3d, name, matrix];
};
};
SetBoundingSphere: PROC [shape: REF ShapeInstance] ~ {
min, max: Triple ← [shape.vertex[0].x, shape.vertex[0].y, shape.vertex[0].z];
FOR n: NAT IN (1..shape.vertex.length) DO -- get min and max in x, y, and z
vertex: REF Vertex ← shape.vertex[n];
IF vertex = NIL THEN LOOP;
min.x ← MIN[min.x, vertex.x];
max.x ← MAX[max.x, vertex.x];
min.y ← MIN[min.y, vertex.y];
max.y ← MAX[max.y, vertex.y];
min.z ← MIN[min.z, vertex.z];
max.z ← MAX[max.z, vertex.z];
ENDLOOP;
shape.centroid.x ← 0.5*(min.x+max.x);      -- get middle point in each coordinate
shape.centroid.y ← 0.5*(min.y+max.y);
shape.centroid.z ← 0.5*(min.z+max.z);
shape.boundingRadius ← 0.0;
FOR n: NAT IN [0..shape.vertex.length) DO    -- find radius
dx: REAL ← shape.vertex[n].x-shape.centroid.x;
dy: REAL ← shape.vertex[n].y-shape.centroid.y;
dz: REAL ← shape.vertex[n].z-shape.centroid.z;
radius: REAL ← dx*dx+dy*dy+dz*dz;
IF radius > shape.boundingRadius THEN shape.boundingRadius ← radius;
ENDLOOP;
shape.boundingRadius ← 2.0*RealFns.SqRt[shape.boundingRadius];
};
Adjusting Objects
SetRenderStyle: PUBLIC PROC [
context3d: Context3d, shapeName: ROPE, renderStyle: RenderStyle]
~ {
shape: REF ShapeInstance ← ThreeDScenes.FindShape[context3d.shapes, shapeName];
shape.shadingProps ← Atom.RemPropFromList[shape.shadingProps, $Shininess];
SELECT renderStyle FROM
shiny => {
ThreeDMisc.SetSmoothColor[context3d, shapeName, [1.0, 1.0, 1.0]];
ThreeDMisc.SetShininess[context3d, shapeName, 50.0];
};
faceted => ThreeDMisc.SetFacetedColor[context3d, shapeName, [1.0, 1.0, 1.0]];
smooth => ThreeDMisc.SetSmoothColor[context3d, shapeName, [1.0, 1.0, 1.0]];
ENDCASE;
};
SetInsideVisible: PUBLIC PROC [
context3d: Context3d, shapeName: ROPE, insideVisible: BOOL]
~ {
shape: REF ShapeInstance ← ThreeDScenes.FindShape[context3d.shapes, shapeName];
IF shape # NIL THEN {
surfaces: REF PtrPatchSequence ← NARROW[shape.surface];
shape.insideVisible ← insideVisible;
FOR n: NAT IN [0..shape.numSurfaces) DO
surfaces[n].oneSided ← NOT insideVisible;
ENDLOOP;
};
};
SetObjectMatrix: PUBLIC PROC [context3d: Context3d, shapeName: ROPE, matrix: Matrix] ~ {
shape: REF ShapeInstance ← ThreeDScenes.FindShape[context3d.shapes, shapeName];
IF shape # NIL THEN {
shape.position ← matrix;
shape.positionInValid ← FALSE;
};
};
SetTextureMap: PUBLIC PROC [
context3d: Context3d,
shapeName, textureAIS: ROPE,
textureType: TextureType ← intensity]
~ {
Turn texture mapping off with NIL textureAIS.
Needs an argument which turns on/off summed area table.
atom: ATOM ~ SELECT textureType FROM
bump => $Bump,
color => $Color,
ENDCASE => $Intensity;
IF shapeName # NIL THEN {
shape: REF ShapeInstance ~ ThreeDScenes.FindShape[context3d.shapes, shapeName];
textureMap: REF TextureMaps.TextureMap ← IF textureAIS # NIL
THEN TextureMaps.TextureFromAIS[context3d, textureAIS, atom]
ELSE NIL;
TextureMaps.SetTexture[shape, textureMap];
TextureMaps.SumTexture[shape];
};
};
To Become Public, Next Release:
AddShape: PROC [
context3d: Context3d,
shapeName: ROPE,
points: TripleSequence,
polygons: REF NatTable,
normals: TripleSequence ← NIL,
textures: TripleSequence ← NIL,
position: Triple ← origin,
renderStyle: RenderStyle ← smooth,
insideVisible: BOOLFALSE]
~ {
vertices: REF ThreeDBasics.VertexSequence ~ NEW[ThreeDBasics.VertexSequence[points.length]];
shades: REF ThreeDBasics.ShadingSequence ~
NEW[ThreeDBasics.ShadingSequence[points.length]];
FOR n: NAT IN [0..points.length) DO
vertices[n] ← NEW[ThreeDBasics.Vertex];
shades[n] ← NEW[ThreeDBasics.ShadingValue];
[vertices[n].x, vertices[n].y, vertices[n].z] ← points[n];
IF normals # NIL AND n < normals.length
THEN [shades[n].xn, shades[n].yn, shades[n].zn] ← normals[n];
ENDLOOP;
AddObject[context3d, polygons, vertices, shades, textures, position, shapeName, renderStyle, insideVisible];
};
ScaleTexture: PROC [shape: REF ThreeDBasics.ShapeInstance, scale: Triple] ~ {
IF shape.auxInfo # NIL THEN {
textures: TripleSequence ← NARROW[shape.auxInfo];
FOR n: NAT IN [0..textures.length) DO
textures[n] ← Vector3d.MulVectors[textures[n], scale];
ENDLOOP;
};
};
Rendering
ForkRender: CedarProcess.ForkableProc ~ {
ThreeDMisc.MakeFrame[NARROW[data] ! ABORTED => CONTINUE];
};
Render: PUBLIC PROC [
context3d: Context3d,
shapeName: ROPE,
camera: Camera,
fork: BOOLTRUE]
~ {
index: INTEGER ← Context3dIndex[context3d];
Controls3d.SetContext3dView[context3d, camera];
SetBoundingSphere[ThreeDScenes.FindShape[context3d.shapes, shapeName]];
IF index # -1
THEN {
IF processes[index] = NIL OR CedarProcess.GetStatus[processes[index]] # busy
THEN processes[index] ← CedarProcess.Fork[ForkRender, context3d];
}
ELSE ThreeDMisc.MakeFrame[context3d ! ABORTED => CONTINUE];
ELSE ThreeDMisc.ShowShapes[context3d ! ABORTED => CONTINUE];
};
TurnOnAntiAliasing: PUBLIC PROC [context3d: Context3d] ~ {
IF context3d # NIL AND context3d.alphaBuffer # TRUE
THEN ThreeDScenes.AddAlphaBuffer[context3d];
};
TurnOffAntiAliasing: PUBLIC PROC [context3d: Context3d] ~ {
save: ATOM ~ context3d.renderMode;
IF context3d = NIL OR context3d.alphaBuffer = FALSE THEN RETURN;
ThreeDScenes.DisplayFromTerminal[context3d, Terminal.Current[]];
IF save = $Grey AND context3d.renderMode = $PseudoColor
THEN ChangeRenderMode[context3d, $Grey];
IF context3d.depthBuffer THEN ThreeDScenes.AddDepthBuffer[context3d];
context3d.alphaBuffer ← FALSE;
};
Miscellany
PolygonsFromShape: PUBLIC PROC [shape: REF ShapeInstance] RETURNS [REF NatTable] ~ {
surface: REF PtrPatchSequence ← NARROW[shape.surface];
polygons: REF NatTable ← NEW[NatTable[shape.numSurfaces]];
polygons.length ← shape.numSurfaces;
FOR n: NAT IN [0..polygons.length) DO
polygons[n] ← NEW[NatSequence[surface[n].nVtces]];
polygons[n].length ← surface[n].nVtces;
FOR i: NAT IN [0..polygons[n].length) DO
polygons[n][i] ← surface[n].vtxPtr[i];
ENDLOOP;
ENDLOOP;
RETURN[polygons];
};
PointsFromShape: PUBLIC PROC [
shape: REF ShapeInstance,
triples: TripleSequence ← NIL]
RETURNS [TripleSequence]
~ {
Allocate: PROC RETURNS [TripleSequence] ~ {
RETURN[NEW[TripleSequenceRep[shape.vertex.length]]];
};
ok: BOOLTRUE;
IF triples = NIL OR triples.maxLength < shape.vertex.length
THEN triples ← Allocate[! RuntimeError.BoundsFault => {ok ← FALSE; CONTINUE}];
IF NOT ok THEN RETURN[NIL];
triples.length ← shape.vertex.length;
FOR n: NAT IN [0..triples.length) DO
vertex: REF Vertex ← shape.vertex[n];
triples[n] ← [vertex.x, vertex.y, vertex.z];
ENDLOOP;
RETURN[triples];
};
Start Code
[] ← ColorDisplay.RegisterCDNotifyProc [CDNotifier, NIL];
END.
..
SetRenderStyle: PUBLIC PROC [
context3d: Context3d, shapeName: ROPE, renderStyle: RenderStyle]
~ {
IF renderStyle = shiny
THEN ThreeDMisc.SetShininess[context3d, shapeName, 50.0]
ELSE {
shape: REF ShapeInstance ← ThreeDScenes.FindShape[context3d.shapes, shapeName];
IF shape # NIL THEN SELECT renderStyle FROM
faceted => ThreeDScenes.PutShading[shape, $Type, $Faceted];
smooth => ThreeDScenes.PutShading[shape, $Type, $Smooth];
ENDCASE => NULL;
};
};
The above using QuickViewers:
InitThreeDViewer: PUBLIC PROC [background: Triple ← defaultBackground] ~ {
context: Context;
wDir: ROPE ← FileNames.CurrentWorkingDirectory[];
backgroundRef: REF RGBNEW[RGB ← [background.x, background.y, background.z]];
IF NOT ColorDisplay.GetColorDisplayStatus[].on
THEN ColorDisplay.SetColorDisplayStatus[on: TRUE];
IF context3d # NIL THEN ViewerOps.DestroyViewer[viewer, FALSE];
context ← QuickViewer.BuildViewer[NIL, ReDraw, QuitProc, NIL, "Tube Render", TRUE];
viewer ← NARROW[context.data, QuickViewer.QuickView].viewer.parent;
IF viewer.column # color THEN ViewerOps.ChangeColumn[viewer, color];
noReDraw ← TRUE;            -- stop recursion via ReDraw
context3d ← ThreeDScenes.GetFromImagerContext[context];
context3d.props ← Atom.PutPropOnList[context3d.props, $WDir, wDir];
context3d.props ← Atom.PutPropOnList[context3d.props, $BackGround, backgroundRef];
[] ← ThreeDScenes.SetLight[context3d, "Light1", [-100.0, -200.0, 50.0]];
ThreeDScenes.SetView[context3d, [2.0, -10.0, 3.0], origin];
noReDraw ← FALSE;
};
ReDraw: PROC [context: Imager.Context] ~ { 
newContext3d: Context3d;
IF noReDraw THEN RETURN;         -- do nothing during init
noReDraw ← TRUE;            -- stop recursion from viewers
IF context3d # NIL THEN {
oldContext: Context ← ThreeDMisc.GetImagerContext[context3d];
IF oldContext # NIL THEN context ← oldContext;  -- use original context
};
newContext3d ← ThreeDScenes.GetFromImagerContext[
context, context3d.alphaBuffer, context3d.depthBuffer];
context3d.display ← newContext3d.display;
context3d.alphaBuffer ← newContext3d.alphaBuffer;
context3d.depthBuffer ← newContext3d.depthBuffer;
context3d.renderMode ← newContext3d.renderMode;
context3d.viewPort ← newContext3d.viewPort;
SetViewPort[context3d.viewPort];
noReDraw ← FALSE;
};
QuitProc: PROC ~ {context3d ← NIL};
SetView: PUBLIC PROC [camera: Camera] ~ {
IF context3d = NIL THEN InitThreeDViewer[];
context3d.eyePoint ← [0.0, -2.0, 0.0];
context3d.ptOfInterest ← origin;
context3d.fieldOfView ← IF camera.fov.value # 0.0 THEN camera.fov.value ELSE 40.0;
context3d.rollAngle ← camera.tilt.value;
ThreeDScenes.SetEyeSpace[context3d];
FOR n: NAT IN [0..context3d.shapes.length) DO
context3d.shapes[n].vtcesInValid ← TRUE;
IF ThreeDScenes.GetShading[context3d.shapes[n], $Shininess] # NIL
THEN context3d.shapes[n].shadingInValid ← TRUE;
ENDLOOP;
};
SetViewPort: PROC [size: Imager.Rectangle] ~ {
IF context3d = NIL THEN InitThreeDViewer[];
ThreeDScenes.SetViewPort[context3d, size];
FOR n: NAT IN [0..context3d.shapes.length) DO
context3d.shapes[n].vtcesInValid ← TRUE;
context3d.shapes[n].shadingInValid ← TRUE;
ENDLOOP;
ThreeDScenes.SetView[
context:  context3d,
eyePoint:  context3d.eyePoint,
ptOfInterest: context3d.ptOfInterest,
fieldOfView: context3d.fieldOfView,
rollAngle: context3d.rollAngle,
upDirection: context3d.upDirection,
hitherLimit: context3d.hitherLimit,
yonLimit:  context3d.yonLimit
];
};
AddPointsPolygonsToThreeDContext: PROC [
context: ThreeDBasics.Context,
points: ThreeDBasics.TripleSequence,
polygons: ThreeDBasics.NatTable,
name: Rope.ROPENIL]
~ {
IF points.length # 0 AND polygons.length # 0 THEN {
shape: REF ThreeDBasics.ShapeInstance ←
ThreeDScenes.NewShape[objectName];
vertices: REF ThreeDBasics.VertexSequence ←
NEW[ThreeDBasics.VertexSequence[points.length]];
shades: REF ThreeDBasics.ShadingSequence ←
NEW[ThreeDBasics.ShadingSequence[polygons.length]];
shape: REF ThreeDBasics.ShapeInstance ←
ThreeDScenes.NewShape[name];
surfaces: REF ThreeDBasics.PtrPatchSequence ←
NEW[ThreeDBasics.PtrPatchSequence[polygons.length]];
shape.type ← $ConvexPolygon;
shape.insideVisible ← TRUE;
vertices.length ← points.length;
shades.length ← polygons.length;
surfaces.length ← polygons.length;
FOR n: NAT IN [0..vertices.length) DO
p: Triple ~ points[n];
vertices[n] ← NEW[ThreeDBasics.Vertex ← [x: p.x, y: p.y, z: p.y]];
ENDLOOP;
shape.surface ← surfaces;
shape.type ← $ConvexPolygon;
shape.insideVisible ← TRUE;
shape.vertex ← vertices;
shape.shade ← shades;
shape.numSurfaces ← polygons.length;
FOR n: NAT IN [0..polygons.length) DO
nVertices: INTEGER ← polygons[n].length;
shades[n] ← NEW[ThreeDBasics.ShadingValue ← [r: ?, b: ?, b: ?]];
ThreeDScenes.PutShading[ shape, $PatchColors, patchInfo ];
ThreeDScenes.PutShading[shape, $Type, $Faceted ];
surfaces[n] ← NEW[ThreeDBasics.PtrPatch ← [
vtxPtr: NEW[NatSequence[nVertices]],
type: shape.type,
oneSided: FALSE,
nVtces: nVertices
]];
FOR i: NAT IN [0..nVertices) DO surfaces[n].vtxPtr[i] ← polygons[n][i]; ENDLOOP;
ENDLOOP;
context.shapes ← ThreeDScenes.DeleteShape[context.shapes, name !
ThreeDScenes.Error => CONTINUE];
context.shapes ← ThreeDScenes.AddShape[context.shapes, shape];
ThreeDScenes.PlaceShape[shape, [0.0, 0.0, 0.0]];
ThreeDScenes.PutShading[shape, $Type, $Smooth];
};
};
SetView: PUBLIC PROC [context3d: Context3d, matrix: Matrix] ~ {
Ceiling: PROC [number: REAL] RETURNS [INTEGER] ~ {
result: INTEGER ← Real.RoundI[number];
RETURN[IF result < number THEN result+1 ELSE result];
};
IF context3d # NIL THEN {
normal: Triple;
window: Imager.Rectangle;
aspectRatio, viewWidth, viewHeight: REAL;
bounds: Pixels.Extent ← [0, 0, Ceiling[context3d.viewPort.w], Ceiling[context3d.viewPort.h]];
From ThreeDScenes.SetEyeSpace:
context3d.eyeSpaceXfm ← matrix;
IF bounds.h <= 0.0 OR bounds.w <= 0.0 THEN RETURN;
aspectRatio ← REAL[bounds.w]/REAL[bounds.h];
IF context3d.window.w < 0.0 OR context3d.window.h < 0.0 THEN RETURN;
IF context3d.fieldOfView = 0.0 THEN context3d.fieldOfView ← 40.0;
viewWidth ← 2.0*RealFns.TanDeg[0.5*context3d.fieldOfView];
window.x ← MIN[1.0, MAX[-1.0, context3d.window.x] ];
window.w ← MIN[1.0-window.x, context3d.window.w ];
window.y ← MIN[1.0, MAX[-1.0, context3d.window.y] ];
window.h ← MIN[1.0-window.y, context3d.window.h ];
context3d.clippingPlanes[Near] ← [0.0, 0.0, 1.0, -context3d.hitherLimit];
context3d.clippingPlanes[Far] ← [0.0, 0.0, -1.0, context3d.yonLimit];
normal ← Vector3d.Normalize[[1.0, 0.0, -0.5*window.x*viewWidth]];
context3d.clippingPlanes[Left] ← [normal.x, 0.0, normal.z, 0.0];
normal ← Vector3d.Normalize[[-1.0, 0.0, 0.5*(window.x + window.w)*viewWidth]];
context3d.clippingPlanes[Right] ← [normal.x, 0.0, normal.z, 0.0];
normal ← Vector3d.Normalize[[0.0, 1.0, -0.5*window.y*viewWidth]];
context3d.clippingPlanes[Bottom] ← [0.0, normal.y, normal.z, 0.0];
normal ← Vector3d.Normalize[[0.0, -1.0, 0.5*(window.y + window.h)*viewWidth]];
context3d.clippingPlanes[Top] ← [0.0, normal.y, normal.z, 0.0];
IF aspectRatio > 1.0
THEN {viewHeight ← viewWidth; viewWidth ← viewWidth*aspectRatio}
ELSE viewHeight ← viewWidth/aspectRatio;
IF window.w > window.h
THEN viewWidth ← viewWidth*window.h/window.w
ELSE viewHeight ← viewHeight*window.w/window.h;
context3d.eyeToNDC.addX ← -window.x/window.w;
context3d.eyeToNDC.addY ← -window.y/window.h;
context3d.eyeToNDC.addZ ← 1.0/(1.0-context3d.hitherLimit/context3d.yonLimit);
context3d.eyeToNDC.scaleX ← 1.0/(0.5*window.w*viewWidth);
context3d.eyeToNDC.scaleY ← 1.0/(0.5*window.h*viewHeight);
context3d.eyeToNDC.scaleZ ←
-context3d.hitherLimit/(1.0-context3d.hitherLimit/context3d.yonLimit);
From ThreeDScenesImpl.SetView:
FOR n: NAT IN [0..context3d.shapes.length) DO
shape: REF ShapeInstance ← context3d.shapes[n];
shape.vtcesInValid ← TRUE;
IF ThreeDScenes.GetShading[shape, $Shininess] # NIL
THEN shape.shadingInValid ← TRUE;
ENDLOOP;
};
};