G3dRenderImpl.mesa
Copyright Ó 1985, 1989, 1992 by Xerox Corporation. All rights reserved.
Bloomenthal, July 15, 1992 10:54 pm PDT
Heckbert, August 9, 1988 4:50:32 pm PDT
Crow, November 16, 1990 11:15 am PST
Glassner, March 2, 1990 1:03:22 pm PST
DIRECTORY CedarProcess, ColorFns, G3dBasic, G3dLight, G3dMatrix, G3dRender, G3dShape, G3dVector, G3dView, Imager, ImagerColor, ImagerSample, NamedColors, Rope;
G3dRenderImpl: CEDAR MONITOR
IMPORTS ColorFns, G3dMatrix, G3dView, NamedColors, Rope
EXPORTS G3dRender
~ BEGIN
Errors
Error:    PUBLIC SIGNAL [code: ATOM, reason: ROPE] = CODE;
Types
Process:    TYPE ~ CedarProcess.Process;
Pair:     TYPE ~ G3dBasic.Pair;
Triple:    TYPE ~ G3dBasic.Triple;
Light:     TYPE ~ G3dLight.Light;
LightSequence:  TYPE ~ G3dLight.LightSequence;
Matrix:    TYPE ~ G3dMatrix.Matrix;
Context3d:   TYPE ~ G3dRender.Context3d;
Context3dRep:  TYPE ~ G3dRender.Context3dRep;
DisplayMode:  TYPE ~ G3dRender.DisplayMode;
RenderData:   TYPE ~ G3dRender.RenderData;
RenderStyle:   TYPE ~ G3dRender.RenderStyle;
TextureMap:   TYPE ~ G3dRender.TextureMap;
TextureStyle:   TYPE ~ G3dRender.TextureStyle;
Shape:     TYPE ~ G3dShape.Shape;
ShapeRep:    TYPE ~ G3dShape.ShapeRep;
ShapeSequence:  TYPE ~ G3dShape.ShapeSequence;
Vertex:    TYPE ~ G3dShape.Vertex;
VertexRep:   TYPE ~ G3dShape.VertexRep;
VertexSequenceRep: TYPE ~ G3dShape.VertexSequenceRep;
Rectangle:    TYPE ~ Imager.Rectangle;
RGB:      TYPE ~ ImagerColor.RGB;
SampleMap:   TYPE ~ ImagerSample.SampleMap;
ROPE:     TYPE ~ Rope.ROPE;
Context3d
Create: PUBLIC PROC RETURNS [c: Context3d] ~ {
c ¬ NEW[Context3dRep ¬ [view: G3dMatrix.Identity[]]];
SetBackgroundColor[c, [0.2, 0.2, 0.7]];
};
View
SetViewFromParameters: PUBLIC PROC [
context3d: Context3d,
fieldOfView: REAL ¬ 40.0,
scale: REAL ¬ 1.0,
moves, rotates: Triple ¬ []]
~ {
fov: REAL ¬ IF fieldOfView = 0.0 THEN 40.0 ELSE fieldOfView;
eyePoint, lookAt, upDirection: Triple;
[eyePoint, lookAt, upDirection] ¬ G3dView.FromScaleMovesRots[scale, moves, rotates];
SetView[context3d, eyePoint, lookAt, fov, 0.0, upDirection];
};
SetView: PUBLIC PROC [
context3d: Context3d,
eyePoint: Triple,
lookAt: Triple,
fieldOfView: REAL ¬ 40.0,
rollAngle: REAL ¬ 0.0,
upDirection: Triple ¬ [0., 0., 1.],
hitherLimit: REAL ¬ .01,
yonLimit: REAL ¬ 1000.0]
~ {
context3d.eyePoint ¬ eyePoint;
context3d.lookAt ¬ lookAt;
context3d.fieldOfView ¬ fieldOfView;
context3d.rollAngle ¬ rollAngle;
context3d.upDirection ¬ upDirection;
context3d.hitherLimit ¬ hitherLimit;
context3d.yonLimit ¬ yonLimit;
};
SetViewport: PUBLIC PROC [context3d: Context3d, size: Rectangle] ~{
IF size.w <= 0.0 OR size.h <= 0.0 THEN SIGNAL Error[$MisMatch, "Null rectangle"];
context3d.viewport ¬ size;
};
SetWindow: PUBLIC PROC [context3d: Context3d, size: Rectangle] ~ {
context3d.window ← NEW[Rectangle ← size];
};
Background
NameBackgroundColor: PUBLIC PROC [context3d: Context3d, color: ROPE] ~ {
Set background color using color naming scheme
bkgrdColor: RGB ¬ ColorFns.RGBFromHSL[NamedColors.RopeToHSL[color]];
SetBackgroundColor[context3d, bkgrdColor]; -- set color
};
SetBackgroundColor: PUBLIC PROC [context3d: Context3d, color: RGB] ~ {
IF context3d # NIL THEN context3d.backgroundColor ¬ color;
};
SetBackgroundImage: PUBLIC PROC [context3d: Context3d, name: ROPE] ~ {
GetImage: PROC [name: ROPE] RETURNS [map: SampleMap] ~ {};
context3d.backgroundImage ¬ GetImage[context3d.backgroundName ¬ name];
};
EnableClear: PUBLIC PROC [context3d: Context3d, on: BOOL] ~ {
IF context3d # NIL THEN context3d.clear ¬ on;
};
MatteBackground: PUBLIC PROC [context3d: Context3d, matte: BOOL] ~ {
IF context3d # NIL THEN context3d.matteBackground ¬ matte;
};
Shapes
RenderDataFrom: PUBLIC PROC [shape: Shape] RETURNS [data: RenderData] ~ {
IF shape = NIL THEN RETURN[NIL];
IF shape.renderData = NIL THEN shape.renderData ¬ NEW[G3dRender.RenderDataRep];
data ¬ NARROW[shape.renderData];
};
SetRenderStyle: PUBLIC PROC [shape: Shape, renderStyle: RenderStyle] ~ {
RenderDataFrom[shape].renderStyle ¬ renderStyle;
};
SetColor: PUBLIC PROC [shape: Shape, color: RGB] ~ {
RenderDataFrom[shape].color ¬ color;
};
SetDiffuse: PUBLIC PROC [shape: Shape, diffuseReflectivity: REAL] ~ {
RenderDataFrom[shape].diffuseReflectivity¬ diffuseReflectivity;
};
SetSpecular: PUBLIC PROC [shape: Shape, specularReflectivity: REAL] ~ {
RenderDataFrom[shape].specularReflectivity¬ specularReflectivity;
};
SetMetallicity: PUBLIC PROC [shape: Shape, metallicity: REAL] ~ {
RenderDataFrom[shape].metallicity¬ metallicity;
};
SetShininess: PUBLIC PROC [shape: Shape, shininess: REAL] ~ {
RenderDataFrom[shape].shininess¬ shininess;
};
SetTransmittance: PUBLIC PROC [shape: Shape, transmittance: REAL] ~ {
RenderDataFrom[shape].transmittance ¬ transmittance;
};
SetInvisible: PUBLIC PROC [shape: Shape] ~ {IF shape # NIL THEN shape.visible ¬ FALSE};
SetVisible: PUBLIC PROC [shape: Shape] ~ {IF shape # NIL THEN shape.visible ¬ TRUE};
ShowBackfaces: PUBLIC PROC [shape: Shape] ~ {
IF shape # NIL THEN shape.showBackfaces ¬ TRUE;
};
HideBackfaces: PUBLIC PROC [shape: Shape] ~ {
IF shape # NIL THEN shape.showBackfaces ¬ FALSE;
};
AddAxes: PUBLIC PROC [
context3d: Context3d,
origin: Triple ¬ [0, 0, 0],
size: REAL ¬ 1.0,
scale: Triple ¬ [1, 1, 1],
nReticles: NAT ¬ 20]
~ {};
Don't create shapes, just transform axes endpoints and draw smooth lines to Imager context3d?
AddAxis: PROC [name: ROPE, p, v0, v1: Triple] ~ {
AddName: PROC [name: ROPE, position: Triple] ~ {
s: Shape ← ShapeFromRope[name, name, "white"];
s.position ← position;
AddShape[context3d, s];
};
SetRect: PROC [id, n0, n1, n2, n3: NAT] ~ {
poly: G3dBasic.Surface ← s.surfaces[id] ← [NIL, NEW[G3dBasic.NatSequenceRep[4]]];
poly.vertices.length ← 4;
poly.vertices[0] ← n0;
poly.vertices[1] ← n1;
poly.vertices[2] ← n2;
poly.vertices[3] ← n3;
};
SetVertex: PROC [id: NAT, p: Triple] ~ {s.vertices[id] ← NEW[VertexRep ← [point: p]]};
s: Shape ← NEW[ShapeRep ← [name: Rope.Cat[name, "-axis"], matrix: G3dMatrix.Identity[]]];
SetRenderStyle[s, lines];
s.surfaces ← NEW[G3dBasic.SurfaceSequenceRep[4]]; s.surfaces.length ← 4;
s.vertices ← NEW[VertexSequenceRep[8]]; s.vertices.length ← 8;
SetVertex[0, origin];
SetVertex[1, G3dVector.Add[origin, v0]];
SetVertex[2, G3dVector.Add[G3dVector.Add[origin, v0], v1]];
SetVertex[3, G3dVector.Add[origin, v1]];
SetVertex[4, p];
SetVertex[5, G3dVector.Add[p, v0]];
SetVertex[6, G3dVector.Add[G3dVector.Add[p, v0], v1]];
SetVertex[7, G3dVector.Add[p, v1]];
SetRect[0, 0, 1, 5, 4];
SetRect[1, 1, 2, 6, 5];
SetRect[2, 2, 3, 7, 6];
SetRect[3, 3, 0, 4, 7];
FOR n: NAT IN [0..nReticles) DO
p1: Triple ← G3dVector.Interp[REAL[n]/REAL[nReticles], origin, direction];
p2: Triple ← G3dVector.Add[p1, offset];
s.vertices[2*n] ← NEW[VertexRep ← [point: p1]];
s.vertices[2*n+1] ← NEW[VertexRep ← [point: p2]];
s.surfaces[n].vertices ← NewPoly[2*n, 2*n+1];
ENDLOOP;
SetRenderStyle[s, lines];
AddShape[context3d, s];
AddName[name, direction];
};
AddAxis["X", [origin.x+size, origin.y, origin.z], [0.0, 0.01, 0.0], [0.0, 0.0, 0.01]];
AddAxis["Y", [origin.x, origin.y+size, origin.z], [0.0, 0.0, 0.01], [0.01, 0.0, 0.0]];
AddAxis["Z", [origin.x, origin.y, origin.z+size], [0.01, 0.0, 0.0], [0.0, 0.01, 0.0]];
};
Textures
SetTextureMap: PUBLIC PROC [
shape: Shape,
fileName: ROPE,
textureStyle: TextureStyle ¬ intensity,
textureFiltering: BOOL ¬ FALSE]
RETURNS [error: ROPE]
~ {
};
GetTextureMap: PUBLIC PROC [shape: Shape, textureName: ROPE] RETURNS [t: TextureMap] ~ {
FOR l: LIST OF TextureMap ¬ RenderDataFrom[shape].textures, l.rest WHILE l # NIL DO
IF Rope.Equal[l.first.name, textureName, FALSE] THEN RETURN[l.first];
ENDLOOP;
};
OffsetTextureCoords: PUBLIC PROC [shape: Shape, offset: Pair] ~ {
FOR n: NAT IN [0..shape.vertices.length) DO
v: Vertex ¬ shape.vertices[n];
v.texture ¬ [v.texture.x+offset.x, v.texture.y+offset.y];
ENDLOOP;
};
SetTextureScale: PUBLIC PROC [shape: Shape, textureName: ROPE, scale: Pair ¬ [1.0, 1.0]] ~ {
map: TextureMap ¬ GetTextureMap[shape, textureName];
IF map # NIL THEN map.scale ¬ scale;
};
SetTextureRange: PUBLIC PROC [shape: Shape, textureName: ROPE, range: Pair] ~ {
map: TextureMap ¬ GetTextureMap[shape, textureName];
IF map # NIL THEN map.range ¬ range;
};
SetTextureFiltering: PUBLIC PROC [shape: Shape, textureName: ROPE, on: BOOL] ~ {
map: TextureMap ¬ GetTextureMap[shape, textureName];
IF map # NIL THEN map.filter ¬ on;
};
SetBumpHeight: PUBLIC PROC [shape: Shape, textureName: ROPE, height: REAL ¬ 1.0] ~ {
map: TextureMap ¬ GetTextureMap[shape, textureName];
IF map # NIL THEN map.bumpHeight ¬ height;
};
Rendering Control
renderDone: CONDITION;
ReallyRenderData: TYPE ~ RECORD [context3d: Context3d, image: REF ANY, error: ROPE ¬ NIL];
Render: PUBLIC PROC [context3d: Context3d, image: REF ANY, fork: BOOL ¬ TRUE]
RETURNS [error: ROPE]
~ {
reallyRenderData: REF ReallyRenderData ← NEW[ReallyRenderData ← [context3d, image]];
IF fork
THEN [] ← CedarProcess.Fork[ReallyRender, reallyRenderData, [background, TRUE]]
ELSE [] ← ReallyRender[reallyRenderData];
RETURN[reallyRenderData.error];
};
RenderToFile: PUBLIC PROC [
context3d: Context3d,
fileName: ROPE,
fork: BOOL ¬ TRUE,
abekas: BOOL ¬ FALSE]
~ {
IF fork
THEN context3d.process ← CedarProcess.Fork[ReallyRender, context3d, [background, TRUE]]
ELSE [] ← ReallyRender[context3d];
StoreImage[context3d, name ];       -- store resulting image
};
WaitTilRenderDone: PUBLIC ENTRY PROC ~ {
ENABLE UNWIND => NULL;
WAIT renderDone;
};
IsRendering: PUBLIC PROC [context3d: Context3d] RETURNS [b: BOOL ¬ TRUE] ~ {
RETURN[context3d.process = NIL OR CedarProcess.GetStatus[context3d.process] # busy];
};
BroadcastRenderDone: ENTRY PROC ~ {
BROADCAST renderDone;
};
ReallyRender: CedarProcess.ForkableProc ~ {
reallyRenderData: REF ReallyRenderData ← NARROW[data];
imagerCtx: Imager.Context ← NARROW[reallyRenderData.image];
context3d: Context3d ← reallyRenderData.context3d;
IF context3d.shapes # NIL THEN {
reallyRenderData.error ← "not really rendered";
};
BroadcastRenderDone[];
};
AbortRender: PUBLIC PROC [context3d: Context3d] ~ {
IF context3d # NIL THEN context3d.stop^ ← TRUE;
};
SetAntiAliasing: PUBLIC PROC [context3d: Context3d, on: BOOL ¬ TRUE] ~ {
This will draw images using the alpha buffer; all texture and transparency are enabled.
G3dRenderWithPixels.AntiAliasing[context3d, on];
};
AntiAliasingNeeded: PUBLIC PROC [context3d: Context3d] RETURNS [b: BOOL ¬ FALSE] ~ {
Determine if anti-aliasing is needed to render the shapes in their respective shading modes.
For example, anti-aliasing is necessary for bump-mapping, transparency, solid texture.
IF context3d # NIL AND context3d.shapes # NIL THEN {
FOR n: NAT IN [0..context3d.shapes.length) DO
r: RenderData ← RenderDataFrom[context3d.shapes[n]];
FOR l: LIST OF TextureMap r.textures, l.rest WHILE l # NIL DO
IF l.first.style = bump --OR l.first.type = function-- THEN RETURN[TRUE];
ENDLOOP;
IF r.transmittance > 0.0 THEN RETURN[TRUE];
ENDLOOP;
};
};
GetBuffer: PUBLIC PROC [context3d: Context3d, type: ATOM] RETURNS [s: SampleMap] ~ {
};
Local Utilities and Miscellany
AtomFromTextureStyle: PUBLIC PROC [textureStyle: TextureStyle] RETURNS [a: ATOM] ~ {
a ¬ SELECT textureStyle FROM bump => $Bump, color => $Color, ENDCASE => $Intensity;
};
AtomFromDisplayMode: PUBLIC PROC [displayMode: DisplayMode] RETURNS [a: ATOM] ~ {
a ¬ SELECT displayMode FROM fullColor=>$FullColor, dither=>$PseudoColor, ENDCASE=>$Gray;
};
RopeFromDisplayMode: PUBLIC PROC [displayMode: DisplayMode] RETURNS [ROPE] ~ {
RETURN[SELECT displayMode FROM
gray => "Gray",
dither => "Dither",
fullColor => "FullColor",
ENDCASE => NIL];
};
RopeFromRenderStyle: PUBLIC PROC [renderStyle: RenderStyle] RETURNS [ROPE] ~ {
RETURN[SELECT renderStyle FROM
faceted => "constant",
ENDCASE => "smooth"];
lines => "Lines",
shadedLines => "ShadedLines",
hiddenLines => "HiddenLines",
ENDCASE => NIL];
};
RopeFromTextureStyle: PUBLIC PROC [textureStyle: TextureStyle] RETURNS [ROPE] ~ {
RETURN[SELECT textureStyle FROM
intensity => "Intensity",
color => "Color",
bump => "Bump",
ENDCASE => "None"];
};
END.