G3dToolDrawImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, April 9, 1993 4:04 pm PDT
Heckbert, August 9, 1988 5:51:51 pm PDT
3d Tool: Line Drawing
DIRECTORY Args, CedarProcess, Commander, Controls, Draw2d, G3dBasic, G3dControl, G3dDraw, G3dLight, G3dMatrix, G3dModel, G3dRender, G3dShape, G3dTool, G3dVector, Imager, ImagerArtwork, ImagerBackdoor, ImagerColor, ImagerFont, ImagerSample, IO, PFS, Rope, ViewerAbort, ViewerOps;
G3dToolDrawImpl: CEDAR PROGRAM
IMPORTS Args, Controls, Draw2d, G3dControl, G3dDraw, G3dMatrix, G3dModel, G3dRender, G3dShape, G3dTool, G3dVector, Imager, ImagerArtwork, ImagerBackdoor, ImagerFont, ImagerSample, IO, PFS, Rope, ViewerAbort, ViewerOps
EXPORTS G3dTool
~ BEGIN
Types
ClickProc:   TYPE ~ Controls.ClickProc;
Viewer:    TYPE ~ Controls.Viewer;
Triple:    TYPE ~ G3dBasic.Triple;
Matrix:    TYPE ~ G3dMatrix.Matrix;
Shape:    TYPE ~ G3dShape.Shape;
Buffering:   TYPE ~ G3dTool.Buffering;
Client:    TYPE ~ G3dTool.Client;
DrawProc:   TYPE ~ G3dTool.DrawProc;
NamedBuffer:  TYPE ~ G3dTool.NamedBuffer;
Tool:     TYPE ~ G3dTool.Tool;
View:    TYPE ~ G3dTool.View;
ViewProc:   TYPE ~ G3dTool.ViewProc;
Context:    TYPE ~ Imager.Context;
Rectangle:   TYPE ~ Imager.Rectangle;
ROPE:    TYPE ~ Rope.ROPE;
Line Drawing Display
maxDisplayTime: REAL ¬ 0.1; -- in seconds
useCG6:    BOOL ¬ TRUE; -- to debug, don't use CG6!
Repaint: PUBLIC PROC [tool: Tool, whatChanged: REF ¬ $Client, buffering: Buffering ¬ default]
~ {
Paint: ViewProc ~ {ViewerOps.PaintViewer[view.viewer, client, FALSE, whatChanged]};
IF tool.views = NIL OR tool.views.length = 0 THEN RETURN;
tool.buffering ¬ buffering;
IF whatChanged = $Camera AND tool.camera.mouse.state = up
THEN RETURN; -- whatChanged ¬ $Store;
G3dTool.DoWithViews[tool, Paint, whatChanged = $Camera];
IF tool.timing THEN G3dTool.PrintElapsedTime[tool, tool.previousDisplayTime, "Draw"];
tool.previousWhatChanged ¬ whatChanged;
};
SetMinFPS: PUBLIC PROC [fps: NAT ¬ 4] ~ {maxDisplayTime ¬ 1.0/REAL[fps]};
Print: PROC [context: Context, x, y: INTEGER, rope: ROPE] ~ {
font: Imager.Font ¬ ImagerFont.Find["xerox/tiogafonts/helvetica18"];
Imager.SetFont[context, font];
IF x # -1 AND y # -1 THEN Imager.SetXY[context, [x, y]];
Imager.ShowRope[context, rope];
};
Store: PUBLIC PROC [context: Context, view: View, id: ATOM ¬ $Frame] ~ {
Buffer[context, view, store, id];
};
Restore: PUBLIC PROC [context: Context, view: View, id: ATOM ¬ $Frame] ~ {
Buffer[context, view, restore, id];
};
Buffer: PROC [context: Context, view: View, op: {store, restore}, id: ATOM] ~ {
r: Rectangle;
r ¬ view.tool.bounds ¬ ImagerBackdoor.GetBounds[context ! Imager.Error => GOTO Quit];
IF view # NIL THEN SELECT op FROM
store => {
Store: PROC [pm: Imager.PixelMap] ~ {
nb: NamedBuffer ¬ [id, ImagerSample.Copy[pm[0]]];
FOR l: LIST OF NamedBuffer ¬ view.idBuffer, l.rest WHILE l # NIL DO
IF l.first.id = id THEN {
ImagerSample.ReleaseScratchMap[l.first.map];
l.first ¬ nb;
RETURN;
};
ENDLOOP;
view.idBuffer ¬ CONS[nb, view.idBuffer];
};
ImagerBackdoor.AccessBufferRectangle[context, Store, r];
};
ENDCASE =>
FOR l: LIST OF NamedBuffer ¬ view.idBuffer, l.rest WHILE l # NIL DO
Restore: PROC [pm: Imager.PixelMap] ~ {ImagerSample.Transfer[pm[0], l.first.map]};
IF l.first.id # id THEN LOOP;
IF l.first.map # NIL THEN ImagerBackdoor.AccessBufferRectangle[context, Restore, r];
EXIT;
ENDLOOP;
EXITS Quit => NULL; -- ImagerBackdoor operations not defined for Interpress masters
};
Draw: PUBLIC G3dTool.DrawProc ~ {
IF v # NIL AND (whatChanged = $IPOut OR v.viewer = viewer) THEN
WITH whatChanged SELECT FROM
proc: REF CedarProcess.ForkableProc => [] ¬ proc[tool.context3d];
ENDCASE => SELECT whatChanged FROM
$Store => Store[context, v];
$Restore => Restore[context, v];
ENDCASE => {
double buffering method, which, however, does not work with the CG6
hardware because the CG6 only functions with the actual SparcStation frame
buffer and cannot write into other memory, such as the scratch sample map
ViewerAbortAction: PROC ~ {
Action: PROC [map: ImagerSample.RasterSampleMap] ~ {
Restore: PROC [pm: Imager.PixelMap] ~ {
ImagerSample.Transfer[pm[0], map, ImagerSample.GetBox[pm[0]].min];
};
maps: CtBasic.SampleMaps ¬ CtBasic.SampleMapsFromMaps[map, NIL, NIL];
temp: Context ¬ CtBasic.ContextFromSampleMaps[maps];
DoDraw[temp, tool, whatChanged, viewer, v];
ImagerBackdoor.AccessBufferRectangle[context, Restore, bounds];
};
bounds: Imager.Rectangle ¬ ImagerBackdoor.GetBounds[context];
box: ImagerSample.Box ¬ [
[Real.Round[bounds.y], Real.Round[bounds.x]],
[Real.Round[bounds.h], Real.Round[bounds.w]]];
ImagerSample.DoWithScratchMap[box, 8, Action];
};
ViewerAbortAction: PROC ~ {DoDraw[context, tool, whatChanged, viewer, v]};
IF tool.camera.use = view THEN {
v.camera.matrix ¬ G3dMatrix.CopyMatrix[tool.camera.matrix, v.camera.matrix];
G3dControl.SaveState[tool.camera, v.camera];
};
SELECT whatChanged FROM
NIL, $Camera, $DrawOps, $ShapeOps, $Scene =>
InvalidateVertexScreens[tool, all];
ENDCASE;
IF tool.shapes # NIL THEN FOR n: NAT IN [0..tool.shapes.length) DO
IF GetRenderStyle[tool.shapes[n]] # lines THEN {
G3dTool.Render[tool, FALSE];
RETURN;
};
ENDLOOP;
ViewerAbort.CallWithAbortEnabled[viewer, ViewerAbortAction];
};
G3dRender.SetView[
tool.context3d, tool.camera.eyePoint, tool.camera.lookAt,
tool.camera.fieldOfView.value, 0, tool.camera.up];
};
GetRenderStyle: PROC [s: Shape] RETURNS [rs: G3dRender.RenderStyle ¬ lines] ~ {
d: G3dRender.RenderData ¬ G3dRender.RenderDataFrom[s];
IF d # NIL THEN rs ¬ d.renderStyle;
};
DoDraw: PROC [context: Context, clientData, whatChanged: REF, viewer: Viewer, v: View] ~ {
It appears (see G3dDraw.Vector, eg) that Draw2d calls can be wrapped within CG6.
DrawSprite: PROC ~ {G3dDraw.Mark[context, t.sprite, x, vp,, asterisk]};
DrawAxes: PROC ~ {
Vec: PROC [v: Triple, r: ROPE] ~ {G3dDraw.Vector[context, [], v, x, vp, r]};
Vec[[1, 0, 0], "x"]; Vec[[0, 1, 0], "y"]; Vec[[0, 0, 1], "z"];
};
LabelVertex: PROC ~ {
vtx: G3dShape.Vertex ¬ t.shapes[t.selectedShape].vertices[t.selectedVertex];
r: ROPE ¬ IO.PutFLR[" #%g (%g, %g, %g)", LIST[
IO.int[t.selectedVertex], IO.real[vtx.point.x], IO.real[vtx.point.y], IO.real[vtx.point.z]]];
IF t.shapes.length#1 THEN r ¬IO.PutFR["%g (shape %g)", [rope[r]], IO.int[t.selectedVertex]];
Imager.SetFont[context, ImagerFont.Find["xerox/tiogafonts/helvetica12"]];
G3dDraw.Vector[context, vtx.point, vtx.normal, x, vp, r,, 30.0, asterisk];
};
IdentifyView: PROC ~ {
NViews: PROC RETURNS [i: INT ¬ 0] ~ {
FOR l: LIST OF NAT ¬ t.activeViews ,l.rest WHILE l#NIL DO i ¬ i+1; ENDLOOP;
};
active: BOOL ¬ FALSE;
IF whatChanged = $IPOut THEN RETURN;
IF t.shapes = NIL AND NViews[] = 1 THEN RETURN;
IF t.camera.use = view THEN FOR l: LIST OF NAT ¬ t.activeViews, l.rest WHILE l # NIL DO
IF v.index = l.first THEN {active ¬ TRUE; EXIT};
ENDLOOP;
G3dDraw.SetColor[context, [0.0, 0.0, 0.0]];
IF active
THEN {
G3dDraw.Quadrangle[context, 0, 0, 0, 20, 20, 20, 20, 0, cg6];
G3dDraw.SetColor[context, [1.0, 1.0, 1.0]];
}
ELSE {
G3dDraw.Line2d[context, [0, 20], [20, 20], solid, cg6];
G3dDraw.Line2d[context, [20, 0], [20, 20], solid, cg6];
G3dDraw.SetColor[context, [0.0, 0.0, 0.0]];
};
Draw2d.Label[context, [5, 5], IO.PutFR1["%g", IO.int[v.index]]];
};
ClientsDraw: PROC [whatChanged: REF ANY] ~ {
IF NOT t.drawClient THEN RETURN;
IF t.client.draw # NIL
THEN t.client.draw[context, viewer, whatChanged, x, vp, v, t, t.client.data];
IF t = G3dTool.GetActiveTool[] THEN
FOR c: LIST OF Client ¬ G3dTool.GetActiveClients[], c.rest WHILE c # NIL DO
IF c.first.draw # NIL
THEN c.first.draw[context, viewer, whatChanged, x, vp, v, t, c.first.data];
ENDLOOP;
};
DrawShapesLights: PROC ~ {
DrawCertainShapes: PROC [which: {selected, unselected, all}, type: Draw2d.DrawType]~{
lv: Triple ¬ IF t.lights#NIL AND t.lights.length>0 THEN t.lights[0].direction ELSE [.7,.7,.0];
IF t.shapes # NIL THEN
FOR n: NAT IN [0..t.shapes.length) DO
s: Shape ¬ t.shapes[n];
IF s # NIL AND s.visible AND (which = all OR s.selected = (which=selected)) THEN {
sv: G3dDraw.Options ¬ t.drawOptions;
t.drawOptions.lineType ¬ type;
IF NOT G3dShape.FaceValid[s, normal] THEN G3dShape.SetFaceNormals[s];
IF NOT s.showBackfaces AND sv.backFaces = on
THEN t.drawOptions.backFaces ¬ off;
v.screens[n] ¬
G3dDraw.Shape[context, s, x,, vp, lv, v.screens[n],, t.drawOptions];
t.drawOptions ¬ sv;
};
ENDLOOP;
};
-- IF t.ops.shape THEN -- DrawCertainShapes[unselected, dashed];
-- IF t.ops.shape THEN -- DrawCertainShapes[selected, solid];
IF t.shapes # NIL AND t.ops.light AND t.lights # NIL THEN {
DrawSun: PROC [x, y: INTEGER, fill: BOOL] ~ {
DrawQuad: PROC [x1, y1, x2, y2, x3, y3, x4, y4: INTEGER] ~ {
IF fill
THEN G3dDraw.Quadrangle[context, x1, y1, x2, y2, x3, y3, x4, y4, cg6]
ELSE {
G3dDraw.Line2d[context, [x1, y1], [x2, y2], solid, cg6];
G3dDraw.Line2d[context, [x2, y2], [x3, y3], solid, cg6];
G3dDraw.Line2d[context, [x3, y3], [x4, y4], solid, cg6];
};
};
x1, x2, x3, x4, y1, y2, y3, y4: INTEGER;
x1 ¬ x-7; x2 ¬ x-3; x3 ¬ x+3; x4 ¬ x+7; y1 ¬ y-5; y2 ¬ y+5; y3 ¬ y1-7; y4 ¬ y2+7;
DrawQuad[x1, y, x2, y1, x3, y1, x4, y];
DrawQuad[x1, y, x2, y2, x3, y2, x4, y];
G3dDraw.Line2d[context, [x1, y], [x-14, y], solid, cg6];
G3dDraw.Line2d[context, [x4, y], [x+14, y], solid, cg6];
G3dDraw.Line2d[context, [x2, y1], [x1, y3], solid, cg6];
G3dDraw.Line2d[context, [x3, y1], [x4, y3], solid, cg6];
G3dDraw.Line2d[context, [x2, y2], [x1, y4], solid, cg6];
G3dDraw.Line2d[context, [x3, y2], [x4, y4], solid, cg6];
};
hasPersp: BOOL ¬ G3dMatrix.HasPerspective[x];
IF t.drawLights THEN FOR i: INTEGER IN [0..t.lights.length) DO
l: G3dLight.Light ¬ t.lights[i];
screen: G3dBasic.Screen ¬ G3dMatrix.GetScreen[l.position, x, hasPersp, vp];
r: Triple ¬ IF G3dVector.FrontFacing[l.direction, l.position, x] THEN [1,0,0] ELSE [0,0,1];
G3dDraw.SetColor[context, r];
l.screen ¬ screen.pos;
DrawSun[screen.intPos.x, screen.intPos.y, i = t.selectedLight];
G3dDraw.Vector[context, l.position, l.direction, x, vp];
ENDLOOP;
G3dDraw.SetColor[context, [0.0, 0.0, 0.0]];
};
};
Clear: PROC ~ {
color: ImagerColor.RGB ¬ t.context3d.backgroundColor;
IF whatChanged # $IPOut THEN G3dDraw.Clear[context, t.background];
};
Action: PROC ~ {
SELECT whatChanged FROM
$Clear => Clear[];
$Vertex => {Restore[context, v, $Pose]; IF vertex THEN LabelVertex[]};
$Sprite => IF t.drawSprite THEN {Restore[context, v, $Pose]; DrawSprite[]};
NIL, $Camera, $DrawOps, $IPOut, $ShapeOps, $Scene, $Stuff, $Client,
$SelectShape, $SelectLight, $Pose => {
context.propList ¬ Prop.Rem[context.propList, $CG6]; -- disable CG6 in other procs
Clear[];
IdentifyView[];
Imager.SetStrokeWidth[context, IF whatChanged=$IPOut THEN t.ipStrokeWidth ELSE 0];
Imager.SetStrokeWidth[context, t.ipStrokeWidth];
G3dDraw.SetColor[context, [0.0, 0.0, 0.0]];
ClientsDraw[whatChanged];
DrawShapesLights[];
IF t.drawAxes THEN DrawAxes[];
IF t.drawPendant THEN G3dDraw.Pendant[context, x, .07, .7, .7, ["x", "y", "z",,,]];
IF vertex THEN LabelVertex[];
IF t.drawSprite THEN DrawSprite[];
IF whatChanged = NIL OR whatChanged = $Pose THEN Store[context, v];
};
$View => IdentifyView[];
ENDCASE => {
ClientsDraw[whatChanged];
RETURN;
};
ClientsDraw[$Overlay];
};
t: Tool ¬ NARROW[clientData];
x: Matrix ¬ v.camera.matrix;
vp: G3dMatrix.Viewport ¬ v.viewport;
vertex: BOOL ¬ t.queryVertices AND t.selectedShape # -1 AND t.selectedVertex # -1;
cg6: G3dDraw.UseCG6 ¬
IF useCG6 AND whatChanged # $IPOut AND
NOT t.drawOptions.tapered AND NOT t.drawOptions.dimFurtherLines
AND G3dDraw.CG6Available[]
THEN y ELSE n;
IF cg6 = y
THEN G3dDraw.WrapInCG6[context, Action]
ELSE Action[];
};
InvalidateVertexScreens: PUBLIC PROC [t: Tool, which: G3dTool.WhichVertices] ~ {
IF t.shapes # NIL THEN
FOR n: NAT IN [0..t.shapes.length) DO
s: Shape ¬ t.shapes[n];
IF s # NIL AND (which = all OR s.selected) THEN {
renderData: G3dRender.RenderData ¬ G3dRender.RenderDataFrom[s];
IF t.views # NIL THEN FOR i: NAT IN [0..t.views.length) DO
screens: G3dTool.ScreenSequence ¬ t.views[i].screens[n];
screens.screensValid ¬ screens.extentValid ¬ FALSE;
ENDLOOP;
};
ENDLOOP;
};
Line/Flat-Shade Drawing Ops
DrawOpsButton: PUBLIC ClickProc ~ {
save: BOOL ¬ FALSE;
t: Tool ¬ NARROW[clientData];
choice: INT ¬ Controls.PopUpRequest[["Draw Ops"], LIST[
-- 1 -- Controls.BoolRequest[t.drawOptions.flatShade,    "Flat Shade"],
-- 2 -- Controls.BoolRequest[t.drawOptions.hiddenLineElim,  "Hidden Line Elimination"],
-- 3 -- Controls.BoolRequest[t.drawOptions.vertexNormals,  "Vertex Normals"],
-- 4 -- Controls.BoolRequest[t.drawOptions.faceNormals,  "Face Normals"],
-- 5 -- Controls.BoolRequest[t.drawOptions.verticesOnly,  "Vertices Only"],
-- 6 -- Controls.BoolRequest[t.drawOptions.labelVertices,  "Label Vertices"],
-- 7 -- Controls.BoolRequest[t.drawOptions.labelPolygons,  "Label Polygons"],
-- 8 -- Controls.BoolRequest[t.drawSprite,      "Sprite"],
-- 9 -- Controls.BoolRequest[t.drawPendant,     "Pendant"],
-- 10 -- Controls.BoolRequest[t.drawClient,      "Client Display"],
-- 11 -- Controls.BoolRequest[t.timing,       "Timing"],
-- 12 -- Controls.BoolRequest[t.drawOptions.silhouettesOnly, "Silhouettes"],
-- 13 -- Controls.BoolRequest[t.drawOptions.backFaces=dashed, "Dashed Backfaces"],
-- 14 -- Controls.BoolRequest[t.drawCurves,      "Curves"],
-- 15 -- Controls.BoolRequest[t.queryVertices,     "Vertex Querying"],
-- 16 -- Controls.BoolRequest[t.drawOptions.tapered,   "Tapered lines"],
-- 17 -- Controls.BoolRequest[t.drawOptions.dimFurtherLines, "Dim far lines"],
-- 18 -- ["SetDrawMode", "Line Drawing Mode (will prompt)"],
-- 19 -- ["Stuff", "Stuff to Tioga selection"],
-- 20 -- ["Write Vectors", "Write 2d vectors to a file"]]];
SELECT choice FROM
1 => t.drawOptions.flatShade   ¬ NOT t.drawOptions.flatShade;
2 => t.drawOptions.hiddenLineElim ¬ NOT t.drawOptions.hiddenLineElim;
3 => t.drawOptions.vertexNormals ¬ NOT t.drawOptions.vertexNormals;
4 => t.drawOptions.faceNormals  ¬ NOT t.drawOptions.faceNormals;
5 => t.drawOptions.verticesOnly  ¬ NOT t.drawOptions.verticesOnly;
6 => t.drawOptions.labelVertices  ¬ NOT t.drawOptions.labelVertices;
7 => t.drawOptions.labelPolygons ¬ NOT t.drawOptions.labelPolygons;
8 => IF (t.drawSprite ¬ NOT t.drawSprite) THEN save ¬ TRUE;
9 => t.drawPendant     ¬ NOT t.drawPendant;
10 => t.drawClient      ¬ NOT t.drawClient;
11 => t.timing       ¬ NOT t.timing;
12 => t.drawOptions.silhouettesOnly ¬ NOT t.drawOptions.silhouettesOnly;
13 => t.drawOptions.backFaces ¬ IF t.drawOptions.backFaces = dashed THEN on ELSE dashed;
14 => {
t.drawCurves ¬ NOT t.drawCurves;
IF t.drawCurves AND t.shapes # NIL THEN
FOR n: NAT IN [0..t.shapes.length) DO
m: G3dModel.Model ¬ G3dModel.GetModel[t.shapes[n]];
IF m.curves = NIL THEN G3dModel.SetCurves[t.shapes[n]];
ENDLOOP;
};
15 => IF (t.queryVertices ¬ NOT t.queryVertices) THEN save ¬ TRUE;
16 => t.drawOptions.tapered ¬ NOT t.drawOptions.tapered;
17 => t.drawOptions.dimFurtherLines ¬ NOT t.drawOptions.dimFurtherLines;
18 => {
choice: INT ¬ Controls.MultiRequest["Line Drawing Mode is ", LIST[
["Solid", t.drawOptions.lineType = solid AND NOT t.drawOptions.verticesOnly],
["Dashed", t.drawOptions.lineType = dashed AND NOT t.drawOptions.verticesOnly],
["Dotted", t.drawOptions.lineType = dotted AND NOT t.drawOptions.verticesOnly]]];
t.drawOptions.lineType ¬ SELECT choice FROM 2 => dashed, 3 => dotted, ENDCASE => solid;
};
19 => {
DoStuff: PROC [context: Context] ~ {
Inner: PROC ~ {G3dTool.Draw[context, NIL, $Stuff, NIL, [], NIL, t, t]};
Imager.TranslateT[context, [-t.bounds.x, -t.bounds.y]];
Imager.DoSaveAll[context, Inner];
};
ImagerArtwork.PasteArtwork[DoStuff, t.bounds, ImagerArtwork.Points[],,, FALSE];
};
20 => {
fileName: ROPE ¬ Controls.TypescriptReadFileName[t.typescript];
IF fileName # NIL AND t.shapes # NIL THEN {
out: IO.STREAM ¬ PFS.StreamOpen[PFS.PathFromRope[fileName], create];
v: View ¬ G3dTool.GetView[NIL, t];
IO.PutF1[t.cmd.out, "Writing %g\n", IO.rope[fileName]];
FOR n: NAT IN [0..v.screens.length) DO
s: Shape ¬ t.shapes[n];
screens: G3dTool.ScreenSequence ¬ v.screens[n];
FOR i: NAT IN [0..s.edges.length) DO
e: G3dShape.Edge ¬ s.edges[i];
p0: G3dBasic.Pair ¬ screens[e.v0].pos;
p1: G3dBasic.Pair ¬ screens[e.v1].pos;
IO.PutFL[out, "%6.5f\t%6.5f\t%6.5f\t%6.5f\n",
LIST[IO.real[p0.x], IO.real[p0.y], IO.real[p1.x], IO.real[p1.y]]];
ENDLOOP;
ENDLOOP;
IO.Close[out];
};
};
ENDCASE;
IF save THEN G3dTool.Repaint[t, $Save];
IF Controls.GetPopUpButton[] = right AND choice > 0 AND choice # 10
THEN Repaint[t, $DrawOps];
};
Initialization
UseCG6: Commander.CommandProc ~ {
SELECT TRUE FROM
Rope.Equal[Args.GetRope[cmd], "yes"] => useCG6 ¬ TRUE;
Rope.Equal[Args.GetRope[cmd], "no"] => useCG6 ¬ FALSE;
Rope.Equal[Args.GetRope[cmd], "?"] =>
IO.PutF1[cmd.out, "useCG6 = %g\n", IO.rope[IF useCG6 THEN "yes" ELSE "no"]];
ENDCASE => IO.PutRope[cmd.out, "specify yes, no, or ?\n"];
};
G3dTool.Register["UseCG6", UseCG6, "enable or disable CG6"];
END.
..
IF (toggle ¬ NOT toggle) THEN {
TerminalIO.PutF["eye = (%6.4f %6.4f %6.4f), ",
IO.real[t.camera.eyePoint.x], IO.real[t.camera.eyePoint.y], IO.real[t.camera.eyePoint.z]];
TerminalIO.PutF["look = (%6.4f %6.4f %6.4f)\n",
IO.real[t.camera.lookAt.x], IO.real[t.camera.lookAt.y], IO.real[t.camera.lookAt.z]];
WriteCamera[v.context3d];
};
toggle: BOOL ¬ TRUE;
WriteCamera: PROC [c: Context3d] ~ {
pi: REAL ¬ 3.14159265359;
AimZ: PROC [direction: Triple] ~ {
xzlen, yzlen, yrot, xrot: REAL;
TerminalIO.PutF["direction %7.5f %7.5f %7.5f\n",
IO.real[direction.x], IO.real[direction.y], IO.real[direction.z]];
IF G3dVector.Null[direction] THEN {TerminalIO.PutF["NULL!\n"]; RETURN};
xzlen ¬ RealFns.SqRt[direction.x*direction.x+direction.z*direction.z];
TerminalIO.PutF["xzlen = %g\n", IO.real[xzlen]];
yrot ¬ IF xzlen = 0.0
THEN (IF direction.y < 0.0 THEN 180.0 ELSE 0.0)
ELSE 180.0*G2dBasic.ArcCos[direction.z/xzlen]/pi;
yzlen ¬ RealFns.SqRt[direction.y*direction.y+xzlen*xzlen];
xrot ¬ 180.0*G2dBasic.ArcCos[xzlen/yzlen]/pi;
TerminalIO.PutF["Rotate %7.5f 1.0 0.0 0.0\n",
IO.real[IF direction.y > 0.0 THEN xrot ELSE -xrot]];
TerminalIO.PutF["Rotate %7.5f 0.0 1.0 0.0\n",
IO.real[IF direction.x > 0.0 THEN -yrot ELSE yrot]];
};
eye: Triple ¬ [c.eyePoint.x, c.eyePoint.y, -c.eyePoint.z]; -- negate z
look: Triple ¬ [c.lookAt.x, c.lookAt.y, -c.lookAt.z]; -- negate z
TerminalIO.PutF["up %7.5f %7.5f %7.5f\n", IO.real[c.upDirection.x], IO.real[c.upDirection.y], IO.real[c.upDirection.z]];
TerminalIO.PutF["Rotate %7.5f 0.0 0.0 1.0\n", IO.real[c.rollAngle]];
AimZ[G3dVector.Sub[look, eye]];
TerminalIO.PutF["Translate %7.5f %7.5f %7.5f\n\n",
IO.real[-eye.x], IO.real[-eye.y], IO.real[-eye.z]];
};
doubleBuffer: BOOL ¬ FALSE;
doubleBuffer ¬ t.buffering = double OR (t.buffering = default AND
(t.previousDisplayTime < maxDisplayTime OR t.drawOptions.silhouettesOnly));
IF NOT doubleBuffer THEN {
w: INTEGER ¬ v.previousExtent.max.f-v.previousExtent.min.f+1;
h: INTEGER ¬ v.previousExtent.max.s-v.previousExtent.min.s+1;
Imager.SetColor[context, Imager.white];
Imager.MaskRectang[context,v.previousExtent.min.f,v.previousExtent.min.s,w,h];
Imager.SetColor[context, Imager.black];
};
v.previousExtent ¬ v.extent;
v.extent ¬ SetScreensGetExtent[t, v, context, whatChanged];
IF doubleBuffer
THEN {
mn: SF.Vec ¬ SF.Min[v.extent.min, v.previousExtent.min];
mx: SF.Vec ¬ SF.Max[v.extent.max, v.previousExtent.max];
Imager.DoWithBuffer[context, A, mn.f, mn.s, mx.f-mn.f, mx.s-mn.s, Imager.white];
}
ELSE ViewerAbort.CallWithAbortEnabled[viewer, A];
G3dTool.StartTimer[t];
t.previousDisplayTime ¬ G3dTool.ElapsedTime[t];
noneSelected: BOOL ¬ t.selectedShape = -1 AND t.focusNode = NIL;
$SelectShape, $Pose => {
IF t.previousWhatChanged = whatChanged OR noneSelected
THEN Restore[context, v, $Unselected]
ELSE {
Draw2d.Clear[context];
IdentifyView[];
DrawCertainShapes[IF whatChanged = $Pose THEN unselected ELSE all, dashed];
Store[context, v, $Unselected];
};
DrawCertainShapes[selected, solid];
Store[context, v, $Frame];
};
SetScreensGetExtent: PROC [t: Tool, v: View, context: Context, whatChanged: REF ANY]
RETURNS [b: SF.Box]
~ {
clientDraw: BOOL ¬ t.client.draw # NIL;
fullBox: SF.Box ¬ [[0, 0], [10000, 10000]];
IF NOT clientDraw AND t = G3dTool.GetActiveTool[] THEN
FOR c: LIST OF Client ¬ G3dTool.GetActiveClients[], c.rest WHILE c # NIL DO
IF c.first.draw # NIL THEN {clientDraw ¬ TRUE; EXIT};
ENDLOOP;
SELECT whatChanged FROM
$Camera, $DrawOps, $ShapeOps, $Scene, $Pose, NIL => {
rb: G2dBasic.Box ¬ [[10000, 10000], [-10000, -10000]];
IF v.context3d.shapes = NIL THEN RETURN[[[0, 0], [0, 0]]];
FOR n: NAT IN [0..t.shapes.length) DO
s: Shape ¬ t.shapes[n];
IF s.visible THEN {
scr: G3dShape.ScreenSequence ¬ v.screens[n];
IF scr = NIL OR NOT scr.screensValid THEN v.screens[n] ¬ scr ¬
G3dShape.SetScreenCoords[context, s, v.camera.matrix, scr, TRUE];
rb.min ¬ [MIN[rb.min.x, scr.extent.min.x], MIN[rb.min.y, scr.extent.min.y]];
rb.max ¬ [MAX[rb.max.x, scr.extent.max.x], MAX[rb.max.y, scr.extent.max.y]];
};
ENDLOOP;
b.min ¬ [Real.Round[rb.min.y], Real.Round[rb.min.x]];
b.max ¬ [Real.Round[rb.max.y], Real.Round[rb.max.x]];
};
$IPOut, $Stuff, $SelectShape, $View => RETURN[v.extent];
ENDCASE => RETURN[fullBox];
IF clientDraw THEN RETURN[fullBox];
IF t.queryVertices AND t.selectedShape # -1 AND t.selectedVertex # -1
THEN b ¬ [SF.Sub[b.min, [5, 5]], SF.Add[b.max, [10, 10]]];
};