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