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; contexts3d: ARRAY [0..nGlobalContext3d) OF Context3d _ ALL[NIL]; processes: ARRAY [0..nGlobalContext3d) OF Process _ ALL[NIL]; 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 RGB _ NEW[RGB _ [background.x, background.y, background.z]]; IF NOT cdState.on THEN ColorDisplay.SetColorDisplayStatus[on: TRUE]; 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]; }; 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: ROPE _ NIL, renderStyle: RenderStyle _ faceted, insideVisible: BOOL _ FALSE, matrix: Matrix _ NIL] ~ { IF vertices # NIL AND vertices.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]; }; 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] ~ { 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]; }; }; AddShape: PROC [ context3d: Context3d, shapeName: ROPE, points: TripleSequence, polygons: REF NatTable, normals: TripleSequence _ NIL, textures: TripleSequence _ NIL, position: Triple _ origin, renderStyle: RenderStyle _ smooth, insideVisible: BOOL _ FALSE] ~ { 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; }; }; ForkRender: CedarProcess.ForkableProc ~ { ThreeDMisc.MakeFrame[NARROW[data] ! ABORTED => CONTINUE]; }; Render: PUBLIC PROC [ context3d: Context3d, shapeName: ROPE, camera: Camera, fork: BOOL _ TRUE] ~ { 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.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; }; 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: BOOL _ TRUE; 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]; }; [] _ 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; }; }; #NRender3dImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Bloomenthal, February 26, 1987 11:18:04 pm PST 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 Context3d Initialization IF cdState.gray THEN backgroundRef^ _ [0.0, 0.0, 0.0]; -- sometimes a good idea Inserting Objects shades # NIL AND shades.length > 0 AND Adjusting Objects Turn texture mapping off with NIL textureAIS. Needs an argument which turns on/off summed area table. To Become Public, Next Release: Rendering ELSE ThreeDMisc.MakeFrame[context3d ! ABORTED => CONTINUE]; Miscellany Start Code The above using QuickViewers: InitThreeDViewer: PUBLIC PROC [background: Triple _ defaultBackground] ~ { context: Context; wDir: ROPE _ FileNames.CurrentWorkingDirectory[]; backgroundRef: REF RGB _ NEW[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.ROPE _ NIL] ~ { 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; }; }; ΚΘ˜šœ™Jšœ Οmœ1™J˜——Jšœ˜—š’œžœ žœ˜6IdefaultšœM˜MN˜š žœžœžœžœ£!˜YJšœžœ˜%Jšžœ žœžœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšžœ˜J˜—Jšœ+£&˜QJšœ'˜'Jšœ&˜&Jšœ˜J˜š žœžœžœžœ£˜;Jšœžœ&˜.Jšœžœ&˜.Jšœžœ&˜.Jšœžœ˜"Jšžœžœ˜DJšžœ˜ —J˜J˜>Jšœ˜——š ™š’œžœžœ˜Jšœ!žœ˜@Jšœ˜JšœžœE˜OJšœJ˜Jšžœ ž˜šœ ˜ JšœA˜AJšœ4˜4J˜—JšœM˜MJšœK˜KJšžœ˜—J˜J˜—š’œžœžœ˜Jšœ!žœžœ˜;Jšœ˜JšœžœE˜Ošžœ žœžœ˜Jšœ žœžœ˜7Jšœ$˜$šžœžœžœž˜'Jšœžœ˜)Jšžœ˜—J˜—J˜J˜—š’œžœžœ#žœ˜XJšœžœE˜Ošžœ žœžœ˜J˜Jšœžœ˜J˜—J˜J˜—š’ œžœžœ˜Jšœ˜Jšœžœ˜Jšœ%˜%Jšœ˜Jš€Πbs€ ™-J™7šœžœžœ ž˜$J˜J˜Jšžœ˜—šžœ žœžœ˜JšœžœE˜Ošœ žœžœž˜™>Jšœ0™0Jšœ/™/J™—J™J™—š’œžœžœ+™?š ’œžœ žœžœžœ™2Jšœžœ™&Jšžœžœžœ žœ ™5Jšœ™J™—šžœ žœžœ™Jšœ™Jšœ™Jšœ$žœ™)Jšœ]™]J™J™Jšœ™J™Jšžœžœžœžœ™2Jšœžœ žœ ™,Jšžœžœžœžœ™DJ™Jšžœžœ™AJšœ:™:Jšœ žœžœ™4Jšœ žœ$™2Jšœ žœžœ™4Jšœ žœ$™3JšœI™IJšœE™EJšœA™AJšœ@™@JšœN™NJšœA™AJšœA™AJšœB™BJšœN™NJšœ?™?J™šžœ™Jšžœ<™@Jšžœ$™(—šžœ™Jšžœ(™,Jšžœ+™/J™—Jšœ-™-Jšœ-™-JšœM™MJšœ9™9Jšœ:™:šœ™JšœF™F—J™J™šžœžœžœž™-Jšœžœ%™/Jšœžœ™šžœ.ž™3Jšžœžœ™!—Jšžœ™—J™—Jšœ™J™L™———…—.ng„