1 /*
2 * W3Dmain.c --
3 *
4 * Procedures to interface the 3D rendering window with the window package
5 * for the purposes of window creation, deletion, and modification.
6 *
7 * Copyright 2003 Open Circuit Design, Inc., for MultiGiG Ltd.
8 *
9 */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 /* This file is only applicable for OpenGL-enabled graphics; THREE_D is */
16 /* defined by the "make config" process and includes all preconditions. */
17 #ifdef THREE_D
18
19 #include <X11/Xlib.h>
20 #include <X11/Xutil.h>
21 #include <X11/keysym.h>
22
23 #include <GL/gl.h>
24 #include <GL/glx.h>
25
26 #include "tcltk/tclmagic.h"
27 #include "utils/magic.h"
28 #include "utils/geometry.h"
29 #include "windows/windows.h"
30 #include "tiles/tile.h"
31 #include "utils/hash.h"
32 #include "utils/undo.h"
33 #include "database/database.h"
34 #include "utils/main.h"
35 #include "commands/commands.h"
36 #include "graphics/wind3d.h"
37 #include "graphics/graphicsInt.h"
38 #include "graphics/graphics.h"
39 #include "grTOGLInt.h"
40 #include "textio/textio.h"
41 #include "textio/txcommands.h"
42 #include "utils/utils.h"
43 #include "utils/styles.h"
44 #include "dbwind/dbwtech.h"
45 #include "dbwind/dbwind.h"
46 #include "extract/extract.h"
47 #include "graphics/glyphs.h"
48 #include "utils/malloc.h"
49 #include "windows/windInt.h" /* for access to redisplay pointer */
50 #include "cif/cif.h"
51 #include "cif/CIFint.h" /* access to CIFPlanes, CIFCurStyle, etc. */
52
53 extern Display *grXdpy; /* X11 display */
54 extern GLXContext grXcontext; /* OpenGL/X11 interface def. */
55 extern XVisualInfo *grVisualInfo; /* OpenGL preferred visual */
56 extern char *MainDisplayType; /* make sure we're using OpenGL */
57 extern HashTable grTOGLWindowTable;
58 extern int grXscrn;
59 extern int grCurFill;
60
61 static bool w3dNeedStyle;
62 static bool w3dIsLocked;
63 static int w3dStyle;
64 static MagWindow *w3dWindow;
65 extern bool grDriverInformed;
66
67 extern void grInformDriver();
68
69 global WindClient W3DclientID;
70
71 #define glTransYs(n) (DisplayHeight(grXdpy, grXscrn)-(n))
72
73 /* forward declarations */
74
75 void W3DCIFredisplay();
76 void W3Dredisplay();
77 void Set3DDefaults();
78 void w3drefreshFunc();
79 bool W3Ddelete();
80
81 /* ------------------------Low-Level Routines--------------------------------- */
82
83 void
w3dLock(w)84 w3dLock(w)
85 MagWindow *w;
86 {
87 grSimpleLock(w, TRUE);
88 w3dSetProjection(w);
89 }
90
91 void
w3dUnlock(w)92 w3dUnlock(w)
93 MagWindow *w;
94 {
95 glFlush();
96 glFinish();
97
98 glDisable(GL_CULL_FACE);
99
100 glDisable(GL_COLOR_MATERIAL);
101 glDisable(GL_LIGHTING);
102 glDisable(GL_DEPTH_TEST);
103 glDisable(GL_POLYGON_SMOOTH);
104
105 grSimpleUnlock(w);
106 }
107
108 /* -------------------Low-Level Drawing Routines------------------------------ */
109
110 void
w3dFillEdge(bbox,r,ztop,zbot)111 w3dFillEdge(bbox, r, ztop, zbot)
112 Rect *bbox; /* tile bounding box */
113 Rect *r;
114 float ztop;
115 float zbot;
116 {
117 float ztmp;
118 float xbot = (float)r->r_xbot;
119 float ybot = (float)r->r_ybot;
120 float xtop = (float)r->r_xtop;
121 float ytop = (float)r->r_ytop;
122
123 if (ytop == bbox->r_ybot || xbot == bbox->r_xtop)
124 {
125 /* reverse z top and bottom so rectangle is drawn */
126 /* counterclockwise as seen from the outside. */
127
128 ztmp = zbot;
129 zbot = ztop;
130 ztop = ztmp;
131 }
132
133 glBegin(GL_POLYGON);
134 glVertex3f(xbot, ybot, zbot);
135 glVertex3f(xbot, ybot, ztop);
136 glVertex3f(xtop, ytop, ztop);
137 glVertex3f(xtop, ytop, zbot);
138 glEnd();
139 }
140
141 void
w3dFillPolygon(p,np,zval,istop)142 w3dFillPolygon(p, np, zval, istop)
143 Point *p;
144 int np;
145 float zval;
146 bool istop;
147 {
148 int i;
149
150 glBegin(GL_POLYGON);
151 if (istop) /* counterclockwise */
152 for (i = 0; i < np; i++)
153 glVertex3f((float)(p[i].p_x), (float)(p[i].p_y), zval);
154 else /* clockwise */
155 for (i = np - 1; i >= 0; i--)
156 glVertex3f((float)(p[i].p_x), (float)(p[i].p_y), zval);
157
158 glEnd();
159 }
160
161 void
w3dFillTile(r,zval,istop)162 w3dFillTile(r, zval, istop)
163 Rect *r;
164 float zval;
165 bool istop;
166 {
167 float xbot, ybot, xtop, ytop;
168
169 ybot = (float)r->r_ybot;
170 ytop = (float)r->r_ytop;
171
172 if (istop)
173 {
174 xbot = (float)r->r_xbot;
175 xtop = (float)r->r_xtop;
176 }
177 else /* makes path counterclockwise as seen from the bottom */
178 {
179 xbot = (float)r->r_xtop;
180 xtop = (float)r->r_xbot;
181 }
182
183 glBegin(GL_POLYGON);
184 glVertex3f(xbot, ybot, zval);
185 glVertex3f(xtop, ybot, zval);
186 glVertex3f(xtop, ytop, zval);
187 glVertex3f(xbot, ytop, zval);
188 glEnd();
189 }
190
191 void
w3dFillXSide(xstart,xend,yval,ztop,zbot)192 w3dFillXSide(xstart, xend, yval, ztop, zbot)
193 float xstart, xend, yval, ztop, zbot;
194 {
195 glBegin(GL_POLYGON);
196 glVertex3f(xstart, yval, zbot);
197 glVertex3f(xstart, yval, ztop);
198 glVertex3f(xend, yval, ztop);
199 glVertex3f(xend, yval, zbot);
200 glEnd();
201 }
202
203 void
w3dFillYSide(xval,ystart,yend,ztop,zbot)204 w3dFillYSide(xval, ystart, yend, ztop, zbot)
205 float xval, ystart, yend, ztop, zbot;
206 {
207 glBegin(GL_POLYGON);
208 glVertex3f(xval, ystart, zbot);
209 glVertex3f(xval, ystart, ztop);
210 glVertex3f(xval, yend, ztop);
211 glVertex3f(xval, yend, zbot);
212 glEnd();
213 }
214
215 /* This routine assumes that vector (x1,y1)->(x2,y2) is in the */
216 /* counterclockwise direction with respect to the tile interior. */
217
218 void
w3dFillDiagonal(x1,y1,x2,y2,ztop,zbot)219 w3dFillDiagonal(x1, y1, x2, y2, ztop, zbot)
220 float x1, y1, x2, y2, ztop, zbot;
221 {
222 glBegin(GL_POLYGON);
223 glVertex3f(x1, y1, zbot);
224 glVertex3f(x2, y2, zbot);
225 glVertex3f(x2, y2, ztop);
226 glVertex3f(x1, y1, ztop);
227 glEnd();
228 }
229
230 void
w3dFillOps(trans,tile,cliprect,ztop,zbot)231 w3dFillOps(trans, tile, cliprect, ztop, zbot)
232 Transform *trans;
233 Tile *tile;
234 Rect *cliprect;
235 float ztop;
236 float zbot;
237 {
238 LinkedRect *tilesegs, *segptr;
239 Rect r, r2;
240 float xbot, ybot, xtop, ytop;
241 Point p[5];
242 int np;
243
244 r2.r_xbot = LEFT(tile);
245 r2.r_ybot = BOTTOM(tile);
246 r2.r_xtop = RIGHT(tile);
247 r2.r_ytop = TOP(tile);
248
249 GeoTransRect(trans, &r2, &r);
250
251 if (IsSplit(tile))
252 {
253 Rect fullr;
254 TileType dinfo;
255
256 dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans);
257
258 fullr = r;
259 if (cliprect != NULL)
260 GeoClip(&r, cliprect);
261
262 GrClipTriangle(&fullr, &r, cliprect != NULL, dinfo, p, &np);
263
264 if (np > 0)
265 {
266 w3dFillPolygon(p, np, ztop, TRUE);
267 w3dFillPolygon(p, np, zbot, FALSE);
268 }
269 }
270 else
271 {
272 /* Clip the tile area to the clipping area */
273 if (cliprect != NULL)
274 GeoClip(&r, cliprect);
275
276 /* draw tile top and bottom */
277 if (!GEO_RECTNULL(&r))
278 {
279 w3dFillTile(&r, ztop, TRUE);
280 w3dFillTile(&r, zbot, FALSE);
281 }
282 }
283
284 /* If height is zero, don't bother to draw sides */
285 if (ztop == zbot) return;
286
287 /* Find tile outline and render sides */
288
289 if (GrBoxOutline(tile, &tilesegs))
290 {
291 xbot = (float)r.r_xbot;
292 ybot = (float)r.r_ybot;
293 xtop = (float)r.r_xtop;
294 ytop = (float)r.r_ytop;
295
296 if (r.r_xtop != r.r_xbot)
297 {
298 w3dFillXSide(xtop, xbot, ybot, ztop, zbot);
299 w3dFillXSide(xbot, xtop, ytop, ztop, zbot);
300 }
301 if (r.r_ytop != r.r_ybot)
302 {
303 w3dFillYSide(xbot, ybot, ytop, ztop, zbot);
304 w3dFillYSide(xtop, ytop, ybot, ztop, zbot);
305 }
306 }
307 else
308 {
309 for (segptr = tilesegs; segptr != NULL; segptr = segptr->r_next)
310 {
311 GeoTransRect(trans, &segptr->r_r, &r2);
312 if (cliprect != NULL)
313 {
314 if (GEO_OVERLAP(cliprect, &r2))
315 {
316 GeoClip(&r2, cliprect);
317 w3dFillEdge(&r, &r2, ztop, zbot);
318 }
319 }
320 else
321 w3dFillEdge(&r, &r2, ztop, zbot);
322 freeMagic(segptr);
323 }
324
325 /* For non-manhattan tiles, GrBoxOutline only returns */
326 /* the manhattan edges. This leaves the (possibly */
327 /* clipped) diagonal edge to render. */
328
329 if (IsSplit(tile))
330 {
331 int cp;
332 for (cp = 0; cp < np - 1; cp++)
333 {
334 if ((p[cp].p_x != p[cp + 1].p_x) && (p[cp].p_y != p[cp + 1].p_y))
335 {
336 w3dFillDiagonal((float)p[cp].p_x, (float)p[cp].p_y,
337 (float)p[cp + 1].p_x, (float)p[cp + 1].p_y,
338 ztop, zbot);
339 break;
340 }
341 }
342 if (cp == (np - 1))
343 if ((p[cp].p_x != p[0].p_x) && (p[cp].p_y != p[0].p_y))
344 w3dFillDiagonal((float)p[cp].p_x, (float)p[cp].p_y,
345 (float)p[0].p_x, (float)p[0].p_y,
346 ztop, zbot);
347 }
348
349 /* Render edges cut by the clipping area, if they're */
350 /* inside the tile, so the tile doesn't look "hollow". */
351
352 if (cliprect != NULL)
353 {
354 xbot = (float)r.r_xbot;
355 ybot = (float)r.r_ybot;
356 xtop = (float)r.r_xtop;
357 ytop = (float)r.r_ytop;
358
359 if (r.r_ytop > r.r_ybot)
360 {
361 if (r.r_xtop == cliprect->r_xtop)
362 w3dFillYSide(xtop, ytop, ybot, ztop, zbot);
363 if (r.r_xbot == cliprect->r_xbot)
364 w3dFillYSide(xbot, ybot, ytop, ztop, zbot);
365 }
366 if (r.r_xtop > r.r_xbot)
367 {
368 if (r.r_ytop == cliprect->r_ytop)
369 w3dFillXSide(xbot, xtop, ytop, ztop, zbot);
370 if (r.r_ybot == cliprect->r_ybot)
371 w3dFillXSide(xtop, xbot, ybot, ztop, zbot);
372 }
373 }
374 }
375 }
376
377 void
w3dRenderVolume(tile,trans,cliprect)378 w3dRenderVolume(tile, trans, cliprect)
379 Tile *tile;
380 Transform *trans;
381 Rect *cliprect;
382 {
383 float zbot, ztop;
384 float ftop = 0.0, fthk = 0.0;
385 W3DclientRec *crec;
386
387 crec = (W3DclientRec *)(w3dWindow->w_clientData);
388
389 ExtGetZAxis(tile, &ftop, &fthk);
390
391 /* Negate z-axis values for OpenGL display */
392 ztop = -ftop * crec->scale_z;
393 zbot = ztop - (fthk * crec->scale_z);
394
395 GR_CHECK_LOCK();
396 if (!grDriverInformed)
397 grInformDriver();
398
399 if ((grCurFill == GR_STSOLID) || (grCurFill == GR_STSTIPPLE))
400 {
401 w3dFillOps(trans, tile, cliprect, ztop, zbot);
402 }
403
404 /* To do: Outlines and contact crosses */
405 /* To do: Labels */
406 }
407
408 void
w3dRenderCIF(tile,layer,trans)409 w3dRenderCIF(tile, layer, trans)
410 Tile *tile;
411 CIFLayer *layer;
412 Transform *trans;
413 {
414 float zbot, ztop;
415 float ftop, fthk;
416 W3DclientRec *crec;
417
418 crec = (W3DclientRec *)(w3dWindow->w_clientData);
419
420 ftop = layer->cl_height;
421 fthk = layer->cl_thick;
422
423 /* Negate z-axis values for OpenGL display */
424 ztop = -ftop * crec->scale_z;
425 zbot = ztop - (fthk * crec->scale_z);
426
427 GR_CHECK_LOCK();
428 if (!grDriverInformed)
429 grInformDriver();
430
431 if ((grCurFill == GR_STSOLID) || (grCurFill == GR_STSTIPPLE))
432 {
433 w3dFillOps(trans, tile, NULL, ztop, zbot);
434 }
435
436 /* To do: Outlines */
437 /* To do: Labels */
438 }
439
440 void
w3dClear()441 w3dClear()
442 {
443 float fr, fg, fb;
444 int cidx, lr, lb, lg;
445
446 /* STYLE_TRANSPARENT uses the background color definition, */
447 /* so we get RGB values from there. */
448
449 cidx = GrStyleTable[STYLE_TRANSPARENT].color;
450 GrGetColor(cidx, &lr, &lg, &lb);
451
452 fr = ((GLfloat)lr / 255);
453 fg = ((GLfloat)lg / 255);
454 fb = ((GLfloat)lb / 255);
455
456 glClearColor(fr, fg, fb, 0.0);
457 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
458 }
459
460 /* -------------------High-Level Drawing Routines------------------------------ */
461
462 void
w3dSetProjection(w)463 w3dSetProjection(w)
464 MagWindow *w;
465 {
466 W3DclientRec *crec;
467 Window wind;
468 GLfloat light0_pos[] = { 0.0, 0.0, 0.0, 0.0 }; /* light #0 position */
469 GLfloat light0_amb[] = { 0.4, 0.4, 0.4, 1.0 }; /* light #0 ambient int. */
470 GLfloat light0_dif[] = { 0.0, 0.0, 0.0, 1.0 }; /* light #0 diffuse int. */
471
472 GLfloat light1_pos[] = { 50.0, 50.0, 50.0, 1.0 }; /* light #1 position */
473 GLfloat light1_amb[] = { 0.0, 0.0, 0.0, 1.0 }; /* light #1 ambient int. */
474 GLfloat light1_dif[] = { 1.0, 1.0, 1.0, 1.0 }; /* light #1 diffuse int. */
475
476 crec = (W3DclientRec *) w->w_clientData;
477 wind = Tk_WindowId((Tk_Window)w->w_grdata);
478 if (wind == 0) return; /* window was closed by window manager? */
479
480 /* Should not mess with surfaceArea---we want the area to be displayed */
481 /* in crec, in magic internal coordinates, set by the edit box (else- */
482 /* where). Set the viewport to maintain 1:1 x:y aspect ratio on the */
483 /* rendered volume. */
484
485 glXMakeCurrent(grXdpy, (GLXDrawable)wind, grXcontext);
486
487 if (crec->level > 0)
488 {
489 glEnable(GL_LINE_SMOOTH);
490 glEnable(GL_POLYGON_SMOOTH);
491 }
492
493 /* Need to look into dealing properly with double-buffered graphics */
494 glDrawBuffer(GL_FRONT);
495 /* glDrawBuffer(GL_BACK); */
496
497 glMatrixMode(GL_PROJECTION);
498 glLoadIdentity();
499
500 /* Lighting */
501
502 glEnable(GL_COLOR_MATERIAL);
503 glEnable(GL_LIGHTING);
504 glEnable(GL_LIGHT0);
505 glEnable(GL_LIGHT1);
506
507 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
508
509 glLightfv(GL_LIGHT0, GL_POSITION, light0_pos); /* positional */
510 glLightfv(GL_LIGHT0, GL_AMBIENT, light0_amb); /* ambient */
511 glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_dif); /* diffuse */
512
513 glLightfv(GL_LIGHT1, GL_POSITION, light1_pos); /* directional */
514 glLightfv(GL_LIGHT1, GL_AMBIENT, light1_amb); /* ambient */
515 glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_dif); /* diffuse */
516
517 /* Fill front-facing polygons only */
518
519 glEnable(GL_CULL_FACE);
520 glCullFace(GL_BACK);
521
522 /* Preserve aspect ratio of 1:1 for internal units on the display */
523
524 glScalef((GLfloat)crec->height / (GLfloat)crec->width, 1.0, 1.0);
525 glViewport((GLsizei)0, (GLsizei)0, (GLsizei)crec->width, (GLsizei)crec->height);
526
527 /* Projection matrix manipulations */
528
529 glScalef(crec->scale_xy, crec->scale_xy, crec->prescale_z);
530
531 glRotatef(crec->view_x, 1.0, 0.0, 0.0);
532 glRotatef(crec->view_y, 0.0, 1.0, 0.0);
533 glRotatef(crec->view_z, 0.0, 0.0, 1.0);
534
535 glTranslatef(crec->trans_x, crec->trans_y, crec->trans_z);
536 }
537
538 /* Magic layer tile painting function */
539
540 int
w3dPaintFunc(tile,cxp)541 w3dPaintFunc(tile, cxp)
542 Tile *tile; /* Tile to be displayed */
543 TreeContext *cxp; /* From DBTreeSrTiles */
544 {
545 SearchContext *scx = cxp->tc_scx;
546
547 /* Allow display interrupt a la dbwPaintFunc(). */
548 /* HOWEVER, note that GrEventPendingPtr looks at */
549 /* events in the window defined by toglCurrent, */
550 /* which is not the 3D window. So rendering in the */
551 /* 3D window can only be interrupted by events in */
552 /* the layout window. */
553
554 /* Honor display suspend status */
555 if (GrDisplayStatus == DISPLAY_SUSPEND) return 0;
556
557 if (GrDisplayStatus == DISPLAY_BREAK_PENDING)
558 {
559 GrDisplayStatus = DISPLAY_IN_PROGRESS;
560 if (GrEventPendingPtr)
561 {
562 if ((*GrEventPendingPtr)())
563 sigOnInterrupt(0);
564 else
565 SigSetTimer(0);
566 }
567 }
568
569 if (!w3dIsLocked)
570 {
571 w3dLock(w3dWindow);
572 w3dIsLocked = TRUE;
573 }
574 if (w3dNeedStyle)
575 {
576 GrSetStuff(w3dStyle);
577 w3dNeedStyle = FALSE;
578 }
579
580 w3dRenderVolume(tile, &scx->scx_trans, &scx->scx_area);
581 return 0; /* keep the search going! */
582 }
583
584 /* CIF layer tile painting function */
585
586 int
w3dCIFPaintFunc(tile,arg)587 w3dCIFPaintFunc(tile, arg)
588 Tile *tile; /* Tile to be displayed */
589 ClientData *arg; /* is NULL */
590 {
591 CIFLayer *layer = (CIFLayer *)arg;
592
593 /* Honor display suspend status */
594 if (GrDisplayStatus == DISPLAY_SUSPEND) return 0;
595
596 /* Allow display interrupt a la dbwPaintFunc() */
597 if (GrDisplayStatus == DISPLAY_BREAK_PENDING)
598 {
599 GrDisplayStatus = DISPLAY_IN_PROGRESS;
600 if (GrEventPendingPtr)
601 {
602 if ((*GrEventPendingPtr)())
603 sigOnInterrupt(0);
604 else
605 SigSetTimer(0);
606 }
607 }
608
609 if (!w3dIsLocked)
610 {
611 w3dLock(w3dWindow);
612 w3dIsLocked = TRUE;
613 }
614 if (w3dNeedStyle)
615 {
616 /* TxError("CIF layer 0x%x (%s) render style %d\n",
617 layer,
618 layer->cl_name,
619 layer->cl_renderStyle); */
620 GrSetStuff(layer->cl_renderStyle + TECHBEGINSTYLES);
621 w3dNeedStyle = FALSE;
622 }
623
624 w3dRenderCIF(tile, layer, &GeoIdentityTransform);
625 return 0; /* keep the search going! */
626 }
627
628 /* -----------------------Command Procedures------------------------------ */
629
630 /*
631 * ----------------------------------------------------------------------------
632 *
633 * w3dHelp --
634 *
635 * Print the list of commands available in this window.
636 *
637 * ----------------------------------------------------------------------------
638 */
639
640 void
w3dHelp(w,cmd)641 w3dHelp(w, cmd)
642 MagWindow *w;
643 TxCommand *cmd;
644 {
645 char **msg;
646 W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
647
648 if (cmd->tx_argc == 1)
649 {
650 TxPrintf("\nWind3D command summary:\n");
651 for (msg = WindGetCommandTable(W3DclientID); *msg != NULL; msg++)
652 {
653 TxPrintf(" %s\n", *msg);
654 }
655 TxPrintf("\nType '?' in the window to get a key macro summary.\n");
656 }
657 else
658 TxError("Usage: help\n");
659 }
660
661 /*
662 * ----------------------------------------------------------------------------
663 *
664 * w3dCutBox --
665 *
666 * Set a clipping box for the 3D view
667 *
668 * ----------------------------------------------------------------------------
669 */
670
671 void
w3dCutBox(w,cmd)672 w3dCutBox(w, cmd)
673 MagWindow *w;
674 TxCommand *cmd;
675 {
676 bool hide = FALSE;
677 int lidx = 1, num_layers;
678 TileTypeBitMask mask;
679 W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
680
681 if (cmd->tx_argc == 1 || cmd->tx_argc == 2 || cmd->tx_argc == 5)
682 {
683 if (cmd->tx_argc == 1)
684 {
685 if (crec->clipped)
686 {
687 Tcl_Obj *rlist = Tcl_NewListObj(0, NULL);
688 Tcl_ListObjAppendElement(magicinterp, rlist,
689 Tcl_NewIntObj((int)(crec->cutbox.r_xbot)));
690 Tcl_ListObjAppendElement(magicinterp, rlist,
691 Tcl_NewIntObj((int)(crec->cutbox.r_ybot)));
692 Tcl_ListObjAppendElement(magicinterp, rlist,
693 Tcl_NewIntObj((int)(crec->cutbox.r_xtop)));
694 Tcl_ListObjAppendElement(magicinterp, rlist,
695 Tcl_NewIntObj((int)(crec->cutbox.r_ytop)));
696
697 Tcl_SetObjResult(magicinterp, rlist);
698 }
699 else
700 Tcl_SetResult(magicinterp, "none", NULL);
701 }
702 else if (cmd->tx_argc == 2)
703 {
704 if (!strcmp(cmd->tx_argv[1], "none"))
705 crec->clipped = FALSE;
706 if (!strcmp(cmd->tx_argv[1], "box"))
707 {
708 Rect rootBox;
709 CellDef *rootBoxDef;
710 CellDef *cellDef = ((CellUse *)w->w_surfaceID)->cu_def;
711
712 if (ToolGetBox(&rootBoxDef, &rootBox))
713 {
714 if (rootBoxDef == cellDef)
715 {
716 crec->clipped = TRUE;
717 crec->cutbox = rootBox;
718 }
719 }
720 }
721 w3drefreshFunc(w);
722 }
723 else
724 {
725 if (StrIsInt(cmd->tx_argv[1]) &&
726 StrIsInt(cmd->tx_argv[2]) &&
727 StrIsInt(cmd->tx_argv[3]) &&
728 StrIsInt(cmd->tx_argv[4]))
729 {
730 crec->clipped = TRUE;
731 crec->cutbox.r_xbot = atoi(cmd->tx_argv[1]);
732 crec->cutbox.r_ybot = atoi(cmd->tx_argv[2]);
733 crec->cutbox.r_xtop = atoi(cmd->tx_argv[3]);
734 crec->cutbox.r_ytop = atoi(cmd->tx_argv[4]);
735 w3drefreshFunc(w);
736 }
737 }
738 }
739 else
740 TxError("Usage: cutbox [none|box|llx lly urx ur]\n");
741 }
742
743 /*
744 * ----------------------------------------------------------------------------
745 *
746 * w3dSeeLayers --
747 *
748 * See or hide layers from the 3D view
749 *
750 * ----------------------------------------------------------------------------
751 */
752
753 void
w3dSeeLayers(w,cmd)754 w3dSeeLayers(w, cmd)
755 MagWindow *w;
756 TxCommand *cmd;
757 {
758 bool hide = FALSE;
759 int lidx = 1, num_layers;
760 TileTypeBitMask mask;
761 W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
762
763 if (cmd->tx_argc == 2 || cmd->tx_argc == 3)
764 {
765 if (cmd->tx_argc == 3)
766 {
767 lidx = 2;
768 if (!strcmp(cmd->tx_argv[1], "no")) hide = TRUE;
769 }
770
771 if (crec->cif)
772 {
773 /* If CIF layers, match the layer name (1 only) */
774 if (!CIFNameToMask(cmd->tx_argv[lidx], &mask))
775 return;
776 }
777 else
778 {
779 /* If normal layers, pick up the name with TechType */
780 if (!CmdParseLayers(cmd->tx_argv[lidx], &mask))
781 return;
782 }
783 if (hide)
784 TTMaskClearMask(&crec->visible, &mask);
785 else
786 TTMaskSetMask(&crec->visible, &mask);
787
788 w3drefreshFunc(w);
789 }
790 else
791 TxError("Usage: see [no] layer\n");
792 }
793
794 /*
795 * ----------------------------------------------------------------------------
796 *
797 * w3dClose --
798 *
799 * Close the 3D display. This corresponds to the command-line command
800 * "closewindow" and overrides the default window client command of the
801 * same name.
802 *
803 * ----------------------------------------------------------------------------
804 */
805
806 void
w3dClose(w,cmd)807 w3dClose(w, cmd)
808 MagWindow *w;
809 TxCommand *cmd;
810 {
811 W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
812
813 if (cmd->tx_argc == 1)
814 (void) WindDelete(w);
815 else
816 TxError("Usage: closewindow\n");
817 }
818
819 /*
820 * ----------------------------------------------------------------------------
821 *
822 * w3dRescale --
823 *
824 * Change scale and translation by indicated scalefactor.
825 *
826 * ----------------------------------------------------------------------------
827 */
828
829 void
w3dRescale(crec,scalefactor)830 w3dRescale(crec, scalefactor)
831 W3DclientRec *crec;
832 float scalefactor;
833 {
834 crec->scale_xy /= scalefactor;
835 crec->prescale_z /= scalefactor;
836
837 crec->scale_z *= scalefactor;
838 crec->trans_y *= scalefactor;
839 crec->trans_x *= scalefactor;
840 }
841
842 /*
843 * ----------------------------------------------------------------------------
844 *
845 * w3dToggleCIF --
846 *
847 * Change between CIF and magic layer views
848 *
849 * ----------------------------------------------------------------------------
850 */
851
852 void
w3dToggleCIF(w,cmd)853 w3dToggleCIF(w, cmd)
854 MagWindow *w;
855 TxCommand *cmd;
856 {
857 W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
858
859 if (cmd->tx_argc == 1)
860 {
861
862 if ((crec->cif == FALSE) && (CIFCurStyle != NULL))
863 {
864 ((clientRec *)(W3DclientID))->w_redisplay = W3DCIFredisplay;
865 crec->cif = TRUE;
866 w3dRescale(crec, (float)CIFCurStyle->cs_scaleFactor);
867 }
868 else if (crec->cif == TRUE)
869 {
870 ((clientRec *)(W3DclientID))->w_redisplay = W3Dredisplay;
871 crec->cif = FALSE;
872 w3dRescale(crec, 1.0 / (float)CIFCurStyle->cs_scaleFactor);
873 }
874
875 w3drefreshFunc(w);
876 }
877 else
878 TxError("Usage: cif\n");
879 }
880
881 /*
882 * ----------------------------------------------------------------------------
883 *
884 * w3dLevel --
885 *
886 * Change rendering level
887 *
888 * ----------------------------------------------------------------------------
889 */
890
891 void
w3dLevel(w,cmd)892 w3dLevel(w, cmd)
893 MagWindow *w;
894 TxCommand *cmd;
895 {
896 W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
897
898 if (cmd->tx_argc == 2)
899 {
900 if (StrIsInt(cmd->tx_argv[1]))
901 crec->level = atoi(cmd->tx_argv[1]);
902 else if (!strcmp(cmd->tx_argv[1], "up"))
903 crec->level++;
904 else if (!strcmp(cmd->tx_argv[1], "down"))
905 crec->level--;
906 else
907 {
908 TxError("Usage: level [<n>|up|down]\n");
909 return;
910 }
911
912 if (crec->level < 0) crec->level = 0;
913 w3drefreshFunc(w);
914 }
915 else if (cmd->tx_argc == 1)
916 {
917 Tcl_SetObjResult(magicinterp, Tcl_NewIntObj((int)crec->level));
918 }
919 else
920 TxError("Usage: level [n]\n");
921 }
922
923 /*
924 * ----------------------------------------------------------------------------
925 *
926 * Function to perform refresh on the entire 3D window
927 *
928 * ----------------------------------------------------------------------------
929 */
930
931 void
w3drefreshFunc(mw)932 w3drefreshFunc(mw)
933 MagWindow *mw;
934 {
935 W3DclientRec *crec = (W3DclientRec *) mw->w_clientData;
936 Rect screenRect;
937
938 screenRect.r_xbot = 0;
939 screenRect.r_ybot = 0;
940 screenRect.r_xtop = crec->width;
941 screenRect.r_ytop = crec->height;
942
943 WindAreaChanged(mw, &screenRect);
944 WindUpdate();
945 }
946
947 /*
948 * ----------------------------------------------------------------------------
949 *
950 * w3dDefaults --
951 *
952 * Revert to display defaults
953 *
954 * ----------------------------------------------------------------------------
955 */
956
957 void
w3dDefaults(w,cmd)958 w3dDefaults(w, cmd)
959 MagWindow *w;
960 TxCommand *cmd;
961 {
962 W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
963
964 if (cmd->tx_argc == 1)
965 {
966 Set3DDefaults(w, crec);
967 w3drefreshFunc(w);
968 }
969 else
970 TxError("Usage: defaults\n");
971 }
972
973 /*
974 * ----------------------------------------------------------------------------
975 *
976 * w3dRefresh --
977 *
978 * Refresh the display
979 *
980 * ----------------------------------------------------------------------------
981 */
982
983 void
w3dRefresh(w,cmd)984 w3dRefresh(w, cmd)
985 MagWindow *w;
986 TxCommand *cmd;
987 {
988 W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
989
990 if (cmd->tx_argc == 1)
991 w3drefreshFunc(w);
992 else
993 TxError("Usage: refresh\n");
994 }
995
996 /*
997 * ----------------------------------------------------------------------------
998 *
999 * w3dView --
1000 *
1001 * Set the viewing angle into the 3D display. Overrides the window
1002 * client command of the same name.
1003 *
1004 * ----------------------------------------------------------------------------
1005 */
1006
1007 void
w3dView(w,cmd)1008 w3dView(w, cmd)
1009 MagWindow *w;
1010 TxCommand *cmd;
1011 {
1012 bool relative = FALSE;
1013 int argc = cmd->tx_argc;
1014 W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
1015
1016 if (argc == 5)
1017 {
1018 argc--;
1019 if (!strncmp(cmd->tx_argv[argc], "rel", 3))
1020 relative = TRUE;
1021 else if (strncmp(cmd->tx_argv[argc], "abs", 3))
1022 {
1023 TxError("Usage: view angle_x angle_y angle_z absolute|relative\n");
1024 return;
1025 }
1026 }
1027
1028 if (argc == 4)
1029 {
1030 /* Pick up x, y, z angles */
1031
1032 if (StrIsNumeric(cmd->tx_argv[1]) &&
1033 StrIsNumeric(cmd->tx_argv[2]) &&
1034 StrIsNumeric(cmd->tx_argv[3]))
1035 {
1036 if (relative)
1037 {
1038 crec->view_x += (float)atof(cmd->tx_argv[1]);
1039 crec->view_y += (float)atof(cmd->tx_argv[2]);
1040 crec->view_z += (float)atof(cmd->tx_argv[3]);
1041 }
1042 else
1043 {
1044 crec->view_x = (float)atof(cmd->tx_argv[1]);
1045 crec->view_y = (float)atof(cmd->tx_argv[2]);
1046 crec->view_z = (float)atof(cmd->tx_argv[3]);
1047 }
1048
1049 /* Call redisplay function */
1050 w3drefreshFunc(w);
1051 }
1052 }
1053 else if (argc == 1)
1054 {
1055 Tcl_Obj *vlist = Tcl_NewListObj(0, NULL);
1056 Tcl_ListObjAppendElement(magicinterp, vlist,
1057 Tcl_NewDoubleObj((double)(crec->view_x)));
1058 Tcl_ListObjAppendElement(magicinterp, vlist,
1059 Tcl_NewDoubleObj((double)(crec->view_y)));
1060 Tcl_ListObjAppendElement(magicinterp, vlist,
1061 Tcl_NewDoubleObj((double)(crec->view_z)));
1062
1063 Tcl_SetObjResult(magicinterp, vlist);
1064 }
1065 else
1066 TxError("Usage: view [angle_x angle_y angle_z [relative|absolute]]\n");
1067 }
1068
1069 /*
1070 * ----------------------------------------------------------------------------
1071 *
1072 * w3dScroll --
1073 *
1074 * Set the viewing position into the 3D display.
1075 *
1076 * ----------------------------------------------------------------------------
1077 */
1078
1079 void
w3dScroll(w,cmd)1080 w3dScroll(w, cmd)
1081 MagWindow *w;
1082 TxCommand *cmd;
1083 {
1084 bool relative = FALSE;
1085 int argc = cmd->tx_argc;
1086 W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
1087
1088 if (argc == 5)
1089 {
1090 argc--;
1091 if (!strncmp(cmd->tx_argv[argc], "rel", 3))
1092 relative = TRUE;
1093 else if (strncmp(cmd->tx_argv[argc], "abs", 3))
1094 {
1095 TxError("Usage: scroll pos_x pos_y pos_z absolute|relative\n");
1096 return;
1097 }
1098 }
1099
1100 if (argc == 4)
1101 {
1102 /* Pick up x, y, z translations */
1103
1104 if (StrIsNumeric(cmd->tx_argv[1]) &&
1105 StrIsNumeric(cmd->tx_argv[2]) &&
1106 StrIsNumeric(cmd->tx_argv[3]))
1107 {
1108 if (relative)
1109 {
1110 crec->trans_x += (float)atof(cmd->tx_argv[1]) / crec->scale_xy;
1111 crec->trans_y += (float)atof(cmd->tx_argv[2]) / crec->scale_xy;
1112 crec->trans_z += (float)atof(cmd->tx_argv[3]) / crec->scale_xy;
1113 }
1114 else
1115 {
1116 crec->trans_x = (float)atof(cmd->tx_argv[1]);
1117 crec->trans_y = (float)atof(cmd->tx_argv[2]);
1118 crec->trans_z = (float)atof(cmd->tx_argv[3]);
1119 }
1120
1121 /* Call redisplay function */
1122 w3drefreshFunc(w);
1123 }
1124 }
1125 else if (argc == 1)
1126 {
1127 Tcl_Obj *vlist = Tcl_NewListObj(0, NULL);
1128 Tcl_ListObjAppendElement(magicinterp, vlist,
1129 Tcl_NewDoubleObj((double)(crec->trans_x)));
1130 Tcl_ListObjAppendElement(magicinterp, vlist,
1131 Tcl_NewDoubleObj((double)(crec->trans_y)));
1132 Tcl_ListObjAppendElement(magicinterp, vlist,
1133 Tcl_NewDoubleObj((double)(crec->trans_z)));
1134
1135 Tcl_SetObjResult(magicinterp, vlist);
1136 }
1137 else
1138 TxError("Usage: scroll [pos_x pos_y pos_z [absolute|relative]]\n");
1139 }
1140
1141 /*
1142 * ----------------------------------------------------------------------------
1143 *
1144 * w3dZoom --
1145 *
1146 * Set the viewing scale of the 3D display. Overrides the window
1147 * client command of the same name.
1148 *
1149 * ----------------------------------------------------------------------------
1150 */
1151
1152 void
w3dZoom(w,cmd)1153 w3dZoom(w, cmd)
1154 MagWindow *w;
1155 TxCommand *cmd;
1156 {
1157 bool relative = FALSE;
1158 int argc = cmd->tx_argc;
1159 W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
1160
1161 if (argc == 4)
1162 {
1163 argc--;
1164 if (!strncmp(cmd->tx_argv[argc], "rel", 3))
1165 relative = TRUE;
1166 else if (strncmp(cmd->tx_argv[argc], "abs", 3))
1167 {
1168 TxError("Usage: zoom scale_xy scale_z relative|absolute\n");
1169 return;
1170 }
1171 }
1172
1173 if (argc == 3)
1174 {
1175 /* Pick up xy and z scales */
1176
1177 if (StrIsNumeric(cmd->tx_argv[1]) &&
1178 StrIsNumeric(cmd->tx_argv[2]))
1179 {
1180 float xy, z;
1181 xy = (float)atof(cmd->tx_argv[1]);
1182 z = (float)atof(cmd->tx_argv[2]);
1183 if ((xy <= 0) || (z <= 0))
1184 {
1185 TxError("Error: zoom values/factors must be positive and nonzero\n");
1186 return;
1187 }
1188 if (relative)
1189 {
1190 crec->scale_xy *= xy;
1191 crec->scale_z *= z;
1192 }
1193 else
1194 {
1195 crec->scale_xy = xy;
1196 crec->scale_z = z;
1197 }
1198
1199 /* Call redisplay function */
1200 w3drefreshFunc(w);
1201 }
1202 }
1203 else if (cmd->tx_argc == 1)
1204 {
1205 Tcl_Obj *vlist = Tcl_NewListObj(0, NULL);
1206 Tcl_ListObjAppendElement(magicinterp, vlist,
1207 Tcl_NewDoubleObj((double)(crec->scale_xy)));
1208 Tcl_ListObjAppendElement(magicinterp, vlist,
1209 Tcl_NewDoubleObj((double)(crec->scale_z)));
1210
1211 Tcl_SetObjResult(magicinterp, vlist);
1212 }
1213 else
1214 TxError("Usage: zoom [scale_xy scale_z [relative|absolute]]\n");
1215 }
1216
1217 /*
1218 * ----------------------------------------------------------------------------
1219 *
1220 * w3dRenderValues --
1221 *
1222 * Set values for 3D rendering. These are independent of any
1223 * extraction or other physical meaning, so we allow them to
1224 * be independently controlled here.
1225 *
1226 * ----------------------------------------------------------------------------
1227 */
1228
1229 void
w3dRenderValues(w,cmd)1230 w3dRenderValues(w, cmd)
1231 MagWindow *w;
1232 TxCommand *cmd;
1233 {
1234 int lidx;
1235 CIFLayer *layer;
1236 W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
1237
1238 if (cmd->tx_argc > 1)
1239 {
1240 for (lidx = 0; lidx < CIFCurStyle->cs_nLayers; lidx++)
1241 {
1242 layer = CIFCurStyle->cs_layers[lidx];
1243 if (!strcmp(layer->cl_name, cmd->tx_argv[1]))
1244 break;
1245 }
1246
1247 if (lidx == CIFCurStyle->cs_nLayers)
1248 {
1249 TxError("Unknown CIF layer \"%s\"\n", cmd->tx_argv[1]);
1250 return;
1251 }
1252 }
1253
1254 if (cmd->tx_argc == 2)
1255 {
1256 Tcl_Obj *llist;
1257 llist = Tcl_NewListObj(0, NULL);
1258 Tcl_ListObjAppendElement(magicinterp, llist,
1259 Tcl_NewDoubleObj((double)(layer->cl_height)));
1260 Tcl_ListObjAppendElement(magicinterp, llist,
1261 Tcl_NewDoubleObj((double)(layer->cl_thick)));
1262 Tcl_ListObjAppendElement(magicinterp, llist,
1263 Tcl_NewIntObj((int)(layer->cl_renderStyle)));
1264 Tcl_SetObjResult(magicinterp, llist);
1265 }
1266 else if (cmd->tx_argc == 4 || cmd->tx_argc == 5)
1267 {
1268 int style;
1269 float height, thick;
1270
1271 style = -1;
1272 if (cmd->tx_argc == 5 && StrIsInt(cmd->tx_argv[4]))
1273 style = atoi(cmd->tx_argv[4]);
1274 if (!StrIsNumeric(cmd->tx_argv[3]) || !StrIsNumeric(cmd->tx_argv[2]))
1275 goto badusage;
1276 height = (float)atof(cmd->tx_argv[2]);
1277 thick = (float)atof(cmd->tx_argv[3]);
1278
1279 /* It is necessary to update ALL layers of the same name */
1280 for (lidx = 0; lidx < CIFCurStyle->cs_nLayers; lidx++)
1281 {
1282 layer = CIFCurStyle->cs_layers[lidx];
1283 if (!strcmp(layer->cl_name, cmd->tx_argv[1]))
1284 {
1285 if (style >= 0) layer->cl_renderStyle = style;
1286 layer->cl_height = height;
1287 layer->cl_thick = thick;
1288 }
1289 }
1290
1291 /* Call redisplay function */
1292 w3drefreshFunc(w);
1293 }
1294 else
1295
1296 badusage:
1297 TxError("Usage: render name [height thick [style]]\n");
1298 }
1299
1300 /*
1301 * ----------------------------------------------------------------------------
1302 *
1303 * Set3DDefaults --
1304 *
1305 * Set default values for the viewing parameters (scale, angle,
1306 * and translation in 3 dimensions)
1307 *
1308 * Default view is top-down (layout) view scaled to fit the celldef's
1309 * bounding box in the 3D window.
1310 *
1311 * ----------------------------------------------------------------------------
1312 */
1313
1314 void
Set3DDefaults(mw,crec)1315 Set3DDefaults(mw, crec)
1316 MagWindow *mw;
1317 W3DclientRec *crec;
1318 {
1319 int height, width;
1320 int centerx, centery;
1321 float scalex, scaley;
1322
1323 /* Get translation and scale from the cell bounding box */
1324 /* (= window's bounding box, set in loadWindow proc) */
1325
1326 height = mw->w_bbox->r_ytop - mw->w_bbox->r_ybot;
1327 width = mw->w_bbox->r_xtop - mw->w_bbox->r_xbot;
1328 centerx = -(mw->w_bbox->r_xbot + (width >> 1));
1329 centery = -(mw->w_bbox->r_ybot + (height >> 1));
1330
1331 scalex = 2.0 / ((float)width * 1.1); /* Add 10% margins in x and y */
1332 scaley = 2.0 / ((float)height * 1.1);
1333
1334 crec->trans_x = (float)centerx;
1335 crec->trans_y = (float)centery;
1336 crec->trans_z = 0.0;
1337
1338 crec->scale_xy = (scalex > scaley) ? scaley : scalex;
1339 crec->scale_z = 25.0; /* Height exaggerated by 25x */
1340
1341 /* The small z-scale value is necessary to keep large layout distances */
1342 /* from exceeding the OpenGL (-1,1) limits of the z-axis. Distances in Z, */
1343 /* like layer thickness, simply scale up to compensate. */
1344
1345 crec->prescale_z = 0.0001;
1346
1347 /* layout view (top down) */
1348
1349 crec->view_x = 0.0;
1350 crec->view_y = 0.0;
1351 crec->view_z = 0.0;
1352
1353 TTMaskZero(&crec->visible);
1354 TTMaskSetMask(&crec->visible, &DBAllTypeBits);
1355
1356 /* Scale all factors appropriately for CIF display */
1357
1358 if (crec->cif == TRUE)
1359 w3dRescale(crec, (float)CIFCurStyle->cs_scaleFactor);
1360
1361 /* Default is no clipping */
1362 crec->clipped = FALSE; /* no clipping by default */
1363 }
1364
1365 /* -----------------------Client Procedures------------------------------ */
1366
1367 /*
1368 * ----------------------------------------------------------------------------
1369 *
1370 * W3DloadWindow --
1371 *
1372 * Replace the root cell of a window by the specified cell.
1373 *
1374 * Results:
1375 * TRUE if successful, FALSE if not. The 3D rendering window is
1376 * not allowed to create new cells, only to render existing ones.
1377 *
1378 * Side effects:
1379 * None.
1380 *
1381 * ----------------------------------------------------------------------------
1382 */
1383
1384 bool
W3DloadWindow(window,name)1385 W3DloadWindow(window, name)
1386 MagWindow *window;
1387 char *name;
1388 {
1389 CellDef *newEditDef;
1390 CellUse *newEditUse;
1391 Rect loadBox;
1392 bool dereference;
1393
1394 newEditDef = DBCellLookDef(name);
1395 if (newEditDef == (CellDef *)NULL)
1396 return FALSE;
1397
1398 dereference = (newEditDef->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
1399 if (!DBCellRead(newEditDef, (char *)NULL, TRUE, dereference, NULL))
1400 return FALSE;
1401
1402 DBReComputeBbox(newEditDef);
1403 loadBox = newEditDef->cd_bbox;
1404
1405 /* Attach cell to window */
1406
1407 newEditUse = DBCellNewUse(newEditDef, (char *) NULL);
1408 (void) StrDup(&(newEditUse->cu_id), "3D rendered cell");
1409
1410 window->w_bbox = &(newEditUse->cu_def->cd_bbox);
1411 return WindLoad(window, W3DclientID, (ClientData)newEditUse, &loadBox);
1412 }
1413
1414 /*
1415 * ----------------------------------------------------------------------------
1416 *
1417 * W3Dcreate --
1418 *
1419 * A new window has been created. Create and initialize the needed
1420 * structures.
1421 *
1422 * Results:
1423 * FALSE if we have too many windows, TRUE otherwise.
1424 *
1425 * Side effects:
1426 * Initialize the window to be editing the background color.
1427 *
1428 * ----------------------------------------------------------------------------
1429 */
1430
1431 bool
W3Dcreate(window,argc,argv)1432 W3Dcreate(window, argc, argv)
1433 MagWindow *window;
1434 int argc;
1435 char *argv[];
1436 {
1437 W3DclientRec *crec;
1438 Tk_Window tkwind, tktop;
1439 Window wind;
1440 Colormap colormap;
1441 HashEntry *entry;
1442 CellDef *boxDef;
1443 Rect box;
1444 bool result;
1445 char *name = NULL;
1446
1447 /* At least for now, there's only one 3D window allowed. */
1448
1449 if (w3dWindow != NULL)
1450 {
1451 TxError("Only one 3D window allowed.\n");
1452 return FALSE;
1453 }
1454
1455 /* The 3D rendering, of course, *only* works with OpenGL, so in an */
1456 /* executable compiled for multiple graphics interfaces, we need */
1457 /* to make sure that our display type is OpenGL. */
1458
1459 if (!GrIsDisplay(MainDisplayType, "OGL"))
1460 {
1461 TxError("Display type is \"%s\". OpenGL is required for the 3D display.\n",
1462 MainDisplayType);
1463 TxError("Please restart magic with option \"-d OGL\".\n");
1464 return FALSE;
1465 }
1466
1467 crec = (W3DclientRec *) mallocMagic(sizeof(W3DclientRec));
1468
1469 /* The MagWindow structure and frameArea indicates the cross-sectional */
1470 /* area of the layout to be rendered in the 3D display window. */
1471
1472 /* Need to parse the argument list here. . . At least one argument */
1473 /* should allow the Tk path name to be passed to the routine, as */
1474 /* it is for the standard layout window in the Tk interface. */
1475
1476 /* Set surface area, etc. of the MagWindow. . . ? */
1477
1478 /* Initial window height and width (should be passed as optional */
1479 /* arguments to the specialopen command) */
1480
1481 crec->width = 500;
1482 crec->height = 500;
1483
1484 /* Rendering level (0 = coarse & fast, 1 = finer but slower, etc. */
1485 /* Render cif by default. */
1486
1487 crec->level = 1;
1488 crec->cif = TRUE;
1489
1490 window->w_clientData = (ClientData) crec;
1491 window->w_flags &= ~(WIND_SCROLLABLE | WIND_SCROLLBARS | WIND_CAPTION |
1492 WIND_BORDER | WIND_COMMANDS);
1493
1494 /* Load the current cellDef into the window */
1495
1496 if ((argc > 0) && (strlen(argv[0]) > 0))
1497 result = W3DloadWindow(window, argv[0]);
1498 else if (ToolGetBox(&boxDef, &box))
1499 result = W3DloadWindow(window, boxDef->cd_name);
1500 else
1501 {
1502 MagWindow *mw = NULL;
1503
1504 windCheckOnlyWindow(&mw, DBWclientID);
1505 if (mw != NULL)
1506 {
1507 boxDef = ((CellUse *)mw->w_surfaceID)->cu_def;
1508 result = W3DloadWindow(window, boxDef->cd_name);
1509 }
1510 else
1511 {
1512 TxError("Ambiguous directive: Put cursor box in one of the windows.\n");
1513 return FALSE;
1514 }
1515 }
1516
1517 if (result == FALSE)
1518 {
1519 TxError("Cells cannot be created in the 3D window.\n");
1520 return result;
1521 }
1522
1523 /* Generate the window. */
1524
1525 colormap = XCreateColormap(grXdpy, RootWindow(grXdpy, DefaultScreen(grXdpy)),
1526 grVisualInfo->visual, AllocNone);
1527
1528 if (!(tktop = Tk_MainWindow(magicinterp))) return FALSE;
1529
1530 /* Check for a Tk pathname for the window; allows window to be */
1531 /* by a Tk GUI script. */
1532 if (argc > 1) name = argv[1];
1533
1534 if (name == NULL)
1535 tkwind = Tk_CreateWindowFromPath(magicinterp, tktop, ".magic3d", "");
1536 else
1537 tkwind = Tk_CreateWindowFromPath(magicinterp, tktop, name, NULL);
1538
1539 if (tkwind != 0)
1540 {
1541 window->w_grdata = (ClientData) tkwind;
1542 entry = HashFind(&grTOGLWindowTable, (char *)tkwind);
1543 HashSetValue(entry, window);
1544
1545 if (name != NULL)
1546 {
1547 /* Visual type must match what we chose in the graphics init proc */
1548 Tk_SetWindowVisual(tkwind, grVisualInfo->visual, toglCurrent.depth,
1549 colormap);
1550 Tk_MapWindow(tkwind);
1551 Tk_GeometryRequest(tkwind, crec->width, crec->height);
1552
1553 wind = Tk_WindowId(tkwind);
1554 if (wind == 0)
1555 glXMakeCurrent(grXdpy, (GLXDrawable)wind, grXcontext);
1556 }
1557
1558 /* execute any pending Tk events */
1559
1560 while (Tcl_DoOneEvent(TCL_DONT_WAIT) != 0);
1561
1562 /* use the OpenGL Tk event handler (see grTOGL1.c) for the 3d window */
1563
1564 Tk_CreateEventHandler(tkwind, ExposureMask | StructureNotifyMask |
1565 ButtonPressMask | KeyPressMask,
1566 (Tk_EventProc *)TOGLEventProc, (ClientData)tkwind);
1567
1568 w3dWindow = window;
1569
1570 /* Use Tcl to pass commands to the window */
1571 MakeWindowCommand((name == NULL) ? ".magic3d" : name, window);
1572
1573 /* Now that a cell is loaded, set default values for the */
1574 /* client record based on the cell bounding box. */
1575
1576 Set3DDefaults(window, crec);
1577
1578 return TRUE;
1579 }
1580
1581 TxError("Could not create a new Tk window\n");
1582 return FALSE;
1583 }
1584
1585 /*
1586 * ----------------------------------------------------------------------------
1587 *
1588 * W3Ddelete --
1589 *
1590 * Clean up the data structures before deleting a window.
1591 *
1592 * Results:
1593 * TRUE if we really want to delete the window, FALSE otherwise.
1594 *
1595 * Side effects:
1596 * A W3DclientRec is freed.
1597 *
1598 * ----------------------------------------------------------------------------
1599 */
1600
1601 bool
W3Ddelete(window)1602 W3Ddelete(window)
1603 MagWindow *window;
1604 {
1605 W3DclientRec *cr;
1606 Tk_Window xw;
1607
1608 cr = (W3DclientRec *) window->w_clientData;
1609 xw = (Tk_Window)window->w_grdata;
1610 w3dWindow = NULL;
1611
1612 freeMagic((char *)cr);
1613 window->w_clientData = (ClientData)NULL;
1614 xw = (Tk_Window)window->w_grdata;
1615 /* Tk_DestroyWindow(xw); */
1616 return (TRUE);
1617 }
1618
1619 /*
1620 * ----------------------------------------------------------------------------
1621 *
1622 * W3Dredisplay --
1623 *
1624 * Redisplay a portion of the 3D rendered layout view
1625 *
1626 * Results:
1627 * None.
1628 *
1629 * Side effects:
1630 * Redisplay is done.
1631 * ----------------------------------------------------------------------------
1632 */
1633
1634 void
W3Dredisplay(w,rootArea,clipArea)1635 W3Dredisplay(w, rootArea, clipArea)
1636 MagWindow *w; /* The window containing the area. */
1637 Rect *rootArea; /* Ignore this---area defined by window with box */
1638 Rect *clipArea; /* Ignore this, too */
1639 {
1640 W3DclientRec *crec;
1641 CellDef *cellDef;
1642 SearchContext scontext;
1643 Rect largerArea, *clipRect = &largerArea;
1644 int i;
1645 TileTypeBitMask *mask, layers;
1646
1647 w3dLock(w);
1648
1649 crec = (W3DclientRec *) w->w_clientData;
1650 cellDef = ((CellUse *)w->w_surfaceID)->cu_def;
1651
1652 if (crec->clipped)
1653 clipRect = &crec->cutbox;
1654
1655 if (rootArea != NULL)
1656 largerArea = *rootArea;
1657 else
1658 largerArea = w->w_surfaceArea;
1659
1660 largerArea.r_xbot--;
1661 largerArea.r_ybot--;
1662 largerArea.r_xtop++;
1663 largerArea.r_ytop++;
1664
1665 scontext.scx_area = *clipRect;
1666 scontext.scx_use = ((CellUse *)w->w_surfaceID);
1667 scontext.scx_x = scontext.scx_y = -1;
1668 scontext.scx_trans = GeoIdentityTransform;
1669
1670 w3dClear();
1671
1672 /* follow the same locking procedure as DBWredisplay() */
1673 w3dUnlock(w);
1674 w3dIsLocked = FALSE;
1675 for (i = 0; i < DBWNumStyles; i++)
1676 {
1677 /* This should probably be redesigned. . . */
1678 mask = DBWStyleToTypes(i);
1679 TTMaskAndMask3(&layers, mask, &crec->visible);
1680 if (!TTMaskIsZero(&layers))
1681 {
1682 w3dStyle = i + TECHBEGINSTYLES;
1683 w3dNeedStyle = TRUE;
1684 (void) DBTreeSrTiles(&scontext, &layers, 0,
1685 w3dPaintFunc, (ClientData) NULL);
1686 if (w3dIsLocked)
1687 {
1688 w3dUnlock(w);
1689 w3dIsLocked = FALSE;
1690 }
1691 }
1692 }
1693 }
1694
1695
1696 /*
1697 * ----------------------------------------------------------------------------
1698 *
1699 * W3DCIFredisplay --
1700 *
1701 * Redisplay a portion of the 3D rendered layout, in CIF layers.
1702 *
1703 * Results:
1704 * None.
1705 *
1706 * Side effects:
1707 * Redisplay is done.
1708 * ----------------------------------------------------------------------------
1709 */
1710
1711 void
W3DCIFredisplay(w,rootArea,clipArea)1712 W3DCIFredisplay(w, rootArea, clipArea)
1713 MagWindow *w; /* The window containing the area. */
1714 Rect *rootArea; /* Ignore this---area defined by window with box */
1715 Rect *clipArea; /* Ignore this, too */
1716 {
1717 W3DclientRec *crec;
1718 SearchContext scx;
1719 CellDef *cellDef;
1720 Rect clipRect;
1721 int i;
1722 TileTypeBitMask *mask;
1723
1724 w3dLock(w);
1725
1726 crec = (W3DclientRec *) w->w_clientData;
1727 cellDef = ((CellUse *)w->w_surfaceID)->cu_def;
1728
1729 clipRect = (crec->clipped) ? crec->cutbox : cellDef->cd_bbox;
1730 GEO_EXPAND(&clipRect, CIFCurStyle->cs_radius, &scx.scx_area);
1731
1732 /* The following is basically a copy of CIFSeeLayer() */
1733
1734 CIFErrorDef = cellDef;
1735 CIFInitCells();
1736 UndoDisable();
1737 CIFDummyUse->cu_def = cellDef;
1738 scx.scx_use = CIFDummyUse;
1739 scx.scx_trans = GeoIdentityTransform;
1740 (void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
1741 cifHierCopyFunc, (ClientData) CIFComponentDef);
1742 CIFGen(CIFComponentDef, cellDef, &clipRect, CIFPlanes, &DBAllTypeBits, TRUE,
1743 TRUE, FALSE, (ClientData)NULL);
1744 DBCellClearDef(CIFComponentDef);
1745
1746 w3dClear();
1747
1748 /* follow the same locking procedure as DBWredisplay() */
1749 w3dUnlock(w);
1750 w3dIsLocked = FALSE;
1751
1752 for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
1753 {
1754 if (TTMaskHasType(&crec->visible, i))
1755 {
1756 w3dNeedStyle = TRUE;
1757 DBSrPaintArea((Tile *) NULL, CIFPlanes[i], &TiPlaneRect,
1758 &CIFSolidBits, w3dCIFPaintFunc,
1759 (ClientData)(CIFCurStyle->cs_layers[i]));
1760
1761 if (w3dIsLocked)
1762 {
1763 w3dUnlock(w);
1764 w3dIsLocked = FALSE;
1765 }
1766 }
1767 }
1768 UndoEnable();
1769 }
1770
1771 /*
1772 * ----------------------------------------------------------------------------
1773 *
1774 * W3Dcommand --
1775 *
1776 * This procedure is invoked by the window package whenever a
1777 * command is typed while the cursor is over a 3D window.
1778 *
1779 * Results:
1780 * None.
1781 *
1782 * Side effects:
1783 * TBD
1784 *
1785 * ----------------------------------------------------------------------------
1786 */
1787
1788 void
W3Dcommand(w,cmd)1789 W3Dcommand(w, cmd)
1790 MagWindow *w;
1791 TxCommand *cmd;
1792 {
1793 int cmdNum;
1794
1795 switch (cmd->tx_button)
1796 {
1797 case TX_NO_BUTTON:
1798 WindExecute(w, W3DclientID, cmd);
1799 break;
1800 case TX_LEFT_BUTTON:
1801 case TX_RIGHT_BUTTON:
1802 case TX_MIDDLE_BUTTON:
1803 /* No action---we shouldn't be here anyway. */
1804 break;
1805 default:
1806 ASSERT(FALSE, "W3Dcommand");
1807 }
1808 UndoNext();
1809 }
1810
1811 /*
1812 * ----------------------------------------------------------------------------
1813 *
1814 * W3Dinit --
1815 *
1816 * Add the 3D rendering window client to the window module.
1817 *
1818 * Results:
1819 * None.
1820 *
1821 * Side effects:
1822 * Add ourselves as a client to the window package.
1823 *
1824 * ----------------------------------------------------------------------------
1825 */
1826
1827 void
W3Dinit()1828 W3Dinit()
1829 {
1830 W3DclientID = WindAddClient("wind3d", W3Dcreate, W3Ddelete,
1831 W3DCIFredisplay, W3Dcommand,
1832 (void(*)())NULL, (bool(*)())NULL,
1833 (void(*)())NULL, (GrGlyph *)NULL);
1834
1835 /* Register commands with the client */
1836
1837 WindAddCommand(W3DclientID,
1838 "view [x y z] specify viewpoint angle",
1839 w3dView, FALSE);
1840 WindAddCommand(W3DclientID,
1841 "scroll [x y z] specify viewpoint position",
1842 w3dScroll, FALSE);
1843 WindAddCommand(W3DclientID,
1844 "zoom [xy z] specify render volume scale",
1845 w3dZoom, FALSE);
1846 WindAddCommand(W3DclientID,
1847 "refresh refresh 3D display",
1848 w3dRefresh, FALSE);
1849 WindAddCommand(W3DclientID,
1850 "cif switch to/from CIF layers display",
1851 w3dToggleCIF, FALSE);
1852 WindAddCommand(W3DclientID,
1853 "level [<n>|up|down] set rendering level",
1854 w3dLevel, FALSE);
1855 WindAddCommand(W3DclientID,
1856 "defaults revert to defaults",
1857 w3dDefaults, FALSE);
1858 WindAddCommand(W3DclientID,
1859 "closewindow close the 3D display",
1860 w3dClose, FALSE);
1861 WindAddCommand(W3DclientID,
1862 "render name [height thick [style]]\n"
1863 " properties of CIF layer rendering",
1864 w3dRenderValues, FALSE);
1865 WindAddCommand(W3DclientID,
1866 "see [no] layer view or hide layers from the 3D view",
1867 w3dSeeLayers, FALSE);
1868 WindAddCommand(W3DclientID,
1869 "cutbox [none|box|llx lly urx ury]\n"
1870 " set clipping rectangle for 3D view",
1871 w3dCutBox, FALSE);
1872 WindAddCommand(W3DclientID,
1873 "help print this command list",
1874 w3dHelp, FALSE);
1875 }
1876
1877 #endif /* THREE_D */
1878