1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: usrwindow.c
6 * User interface tool: public graphics routines
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2000 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 */
31
32 #include "global.h"
33 #include "egraphics.h"
34 #include "efunction.h"
35 #include "usr.h"
36 #include "usrtrack.h"
37 #include "tecgen.h"
38 #include <math.h>
39
40 /***** REDRAW MODULES *****/
41
42 #define NOREDRAW ((REDRAW *)-1)
43
44 typedef struct Iredraw
45 {
46 BOOLEAN entryisnode; /* true of object being re-drawn is node */
47 union us_entry
48 {
49 NODEINST *ni;
50 ARCINST *ai;
51 PORTPROTO *pp;
52 void *blind;
53 } entryaddr; /* object being re-drawn */
54 struct Iredraw *nextredraw; /* next in list */
55 } REDRAW;
56
57 static REDRAW *us_redrawfree = NOREDRAW; /* free list of re-draw modules */
58 static REDRAW *us_firstredraw = NOREDRAW; /* first in list of active re-draw modules */
59 static REDRAW *us_firstopaque = NOREDRAW; /* first in list of active opaque re-draws */
60 static REDRAW *us_firstexport = NOREDRAW; /* first in list of export re-draws */
61 static REDRAW *us_lastopaque = NOREDRAW; /* last in list of active opaque re-draws */
62 static REDRAW *us_usedredraw = NOREDRAW; /* first in list of used re-draw modules */
63
64 static REDRAW *us_allocredraw(void);
65 static void us_freeredraw(REDRAW*);
66
67 /***** 3D DISPLAY *****/
68
69 #define FOVMAX 170.0f
70 #define FOVMIN 2.0f
71
72 enum {ROTATEVIEW, ZOOMVIEW, PANVIEW, TWISTVIEW};
73
74 typedef struct
75 {
76 INTBIG count;
77 INTBIG total;
78 GRAPHICS *desc;
79 float depth;
80 float *x, *y, *z;
81 } POLY3D;
82
83 static BOOLEAN us_3dgatheringpolys = 0;
84 static INTBIG us_3dpolycount;
85 static INTBIG us_3dpolytotal = 0;
86 static POLY3D **us_3dpolylist;
87 static WINDOWPART *us_3dwindowpart;
88
89 /* interaction information */
90 static INTBIG us_3dinteraction = ROTATEVIEW;
91 static INTBIG us_3dinitialbuty;
92 static INTBIG us_3dlastbutx, us_3dlastbuty;
93 static float us_3dinitialfov;
94 static float us_3dcenterx, us_3dcentery, us_3dcenterz;
95 static float us_3dlowx, us_3dhighx, us_3dlowy, us_3dhighy, us_3dlowz, us_3dhighz;
96
97 static BOOLEAN us_3deachdown(INTBIG x, INTBIG y);
98 static void us_3dbuildtransform(XFORM3D *xf3);
99 static void us_3drender(WINDOWPART *w);
100 static POLY3D *us_3dgetnextpoly(INTBIG count);
101 static int us_3dpolydepthascending(const void *e1, const void *e2);
102 static void us_3drotatepointaboutaxis(float *p, float theta, float *r, float *q);
103
104 /***** MISCELLANEOUS *****/
105
106 #define ZSHIFT 4
107 #define ZUP(x) ((x) << ZSHIFT)
108 #define ZDN(x) (((x) + 1) >> ZSHIFT)
109
110 #define CROSSSIZE 3 /* size in pixels of half a cross */
111 #define BIGCROSSSIZE 5 /* size in pixels of half a big cross */
112
113 extern GRAPHICS us_ebox;
114
115 /* prototypes for local routines */
116 static INTBIG us_showin(WINDOWPART*, GEOM*, NODEPROTO*, XARRAY, INTBIG, INTBIG);
117 static void us_queuevicinity(WINDOWPART*, GEOM*, NODEPROTO*, XARRAY, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG);
118 static void us_wanttodrawo(INTBIG, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG, WINDOWPART*, GRAPHICS*, INTBIG);
119 static void us_drawextendedpolyline(POLYGON*, WINDOWPART*);
120
121 /*
122 * Routine to free all memory associated with this module.
123 */
us_freewindowmemory(void)124 void us_freewindowmemory(void)
125 {
126 REGISTER REDRAW *r;
127 REGISTER POLY3D *p3;
128 REGISTER INTBIG i;
129
130 while (us_redrawfree != NOREDRAW)
131 {
132 r = us_redrawfree;
133 us_redrawfree = us_redrawfree->nextredraw;
134 efree((CHAR *)r);
135 }
136
137 for(i=0; i<us_3dpolytotal; i++)
138 {
139 p3 = us_3dpolylist[i];
140 if (p3->total > 0)
141 {
142 efree((CHAR *)p3->x);
143 efree((CHAR *)p3->y);
144 efree((CHAR *)p3->z);
145 }
146 efree((CHAR *)p3);
147 }
148 if (us_3dpolytotal > 0)
149 efree((CHAR *)us_3dpolylist);
150 }
151
152 /******************** WINDOW DISPLAY ********************/
153
154 /* routine to erase the cell in window "w" */
us_clearwindow(WINDOWPART * w)155 void us_clearwindow(WINDOWPART *w)
156 {
157 REGISTER INTBIG newstate;
158
159 startobjectchange((INTBIG)w, VWINDOWPART);
160 (void)setval((INTBIG)w, VWINDOWPART, x_("curnodeproto"), (INTBIG)NONODEPROTO, VNODEPROTO);
161 newstate = (w->state & ~(GRIDON|WINDOWTYPE|WINDOWMODE)) | DISPWINDOW;
162 (void)setval((INTBIG)w, VWINDOWPART, x_("state"), newstate, VINTEGER);
163 (void)setval((INTBIG)w, VWINDOWPART, x_("buttonhandler"), (INTBIG)DEFAULTBUTTONHANDLER, VADDRESS);
164 (void)setval((INTBIG)w, VWINDOWPART, x_("charhandler"), (INTBIG)DEFAULTCHARHANDLER, VADDRESS);
165 (void)setval((INTBIG)w, VWINDOWPART, x_("changehandler"), (INTBIG)DEFAULTCHANGEHANDLER, VADDRESS);
166 (void)setval((INTBIG)w, VWINDOWPART, x_("termhandler"), (INTBIG)DEFAULTTERMHANDLER, VADDRESS);
167 (void)setval((INTBIG)w, VWINDOWPART, x_("redisphandler"), (INTBIG)DEFAULTREDISPHANDLER, VADDRESS);
168 endobjectchange((INTBIG)w, VWINDOWPART);
169 }
170
171 /* routine to erase the display of window "w" */
us_erasewindow(WINDOWPART * w)172 void us_erasewindow(WINDOWPART *w)
173 {
174 static POLYGON *poly = NOPOLYGON;
175
176 /* get polygon */
177 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
178
179 maketruerectpoly(w->screenlx, w->screenhx, w->screenly, w->screenhy, poly);
180 if ((w->state&INPLACEEDIT) != 0)
181 xformpoly(poly, w->intocell);
182 poly->desc = &us_ebox;
183 poly->style = FILLEDRECT;
184 (*us_displayroutine)(poly, w);
185 }
186
187 /*
188 * routine to begin editing cell "cur" in the current window. The screen
189 * extents of the cell are "lx", "hx", "ly", and "hy". If "focusinst"
190 * is not NONODEINST, then highlight that node and port "cellinstport"
191 * (if it is not NOPORTPROTO) in the new window. If "newframe" is true,
192 * create a window for this cell, otherwise reuse the current one.
193 */
us_switchtocell(NODEPROTO * cur,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,NODEINST * focusinst,PORTPROTO * cellinstport,BOOLEAN newframe,BOOLEAN pushpop,BOOLEAN exact)194 void us_switchtocell(NODEPROTO *cur, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy,
195 NODEINST *focusinst, PORTPROTO *cellinstport, BOOLEAN newframe, BOOLEAN pushpop, BOOLEAN exact)
196 {
197 HIGHLIGHT newhigh;
198 REGISTER INTBIG i, l, resethandlers, oldmode;
199 INTBIG dummy;
200 REGISTER VARIABLE *var;
201 CHAR *one[1];
202 REGISTER INTBIG oldstate;
203 REGISTER CHAR *thisline;
204 REGISTER EDITOR *ed;
205 WINDOWPART *neww, *oldw;
206 UINTBIG descript[TEXTDESCRIPTSIZE];
207 extern GRAPHICS us_hbox;
208 REGISTER void *infstr;
209
210 us_clearhighlightcount();
211 oldw = el_curwindowpart;
212 if (oldw == NOWINDOWPART)
213 {
214 /* no former window: force a new one to be created */
215 newframe = TRUE;
216 } else
217 {
218 /* if this is an explorer window, use the other partition (if there is one) */
219 if ((oldw->state&WINDOWTYPE) == EXPLORERWINDOW)
220 {
221 for(neww = el_topwindowpart; neww != NOWINDOWPART; neww = neww->nextwindowpart)
222 if (neww != oldw && neww->frame == oldw->frame) break;
223 if (neww != NOWINDOWPART) oldw = neww;
224 }
225 }
226
227 /* start changes to the tool */
228 startobjectchange((INTBIG)us_tool, VTOOL);
229
230 if (newframe)
231 {
232 /* just create a new window for this cell */
233 neww = us_wantnewwindow(0);
234 if (neww == NOWINDOWPART)
235 {
236 us_abortcommand(_("Cannot create new window"));
237 return;
238 }
239 oldmode = oldstate = DISPWINDOW;
240 } else
241 {
242 /* reuse the window */
243 oldmode = oldw->state;
244 if (pushpop == 0 && (oldw->state&WINDOWMODE) != 0)
245 {
246 /* was in a mode: turn that off */
247 us_setwindowmode(oldw, oldw->state, oldw->state & ~WINDOWMODE);
248 }
249 oldstate = oldw->state;
250 neww = oldw;
251 }
252 el_curwindowpart = neww;
253
254 if ((cur->cellview->viewstate&TEXTVIEW) != 0)
255 {
256 /* text window: make an editor */
257 if (us_makeeditor(neww, describenodeproto(cur), &dummy, &dummy) == NOWINDOWPART)
258 return;
259
260 /* get the text that belongs here */
261 var = getvalkey((INTBIG)cur, VNODEPROTO, VSTRING|VISARRAY, el_cell_message_key);
262 if (var == NOVARIABLE)
263 {
264 one[0] = x_("");
265 var = setvalkey((INTBIG)cur, VNODEPROTO, el_cell_message_key, (INTBIG)one,
266 VSTRING|VISARRAY|(1<<VLENGTHSH));
267 if (var == NOVARIABLE) return;
268 }
269
270 ed = neww->editor;
271 ed->editobjaddr = (CHAR *)cur;
272 ed->editobjtype = VNODEPROTO;
273 ed->editobjqual = x_("FACET_message");
274 ed->editobjvar = var;
275
276 /* load the text into the window */
277 us_suspendgraphics(neww);
278 l = getlength(var);
279 for(i=0; i<l; i++)
280 {
281 thisline = ((CHAR **)var->addr)[i];
282 if (i == l-1 && *thisline == 0) continue;
283 us_addline(neww, i, thisline);
284 }
285 us_resumegraphics(neww);
286
287 /* setup for editing */
288 neww->curnodeproto = cur;
289 neww->changehandler = us_textcellchanges;
290 } else
291 {
292 neww->curnodeproto = cur;
293 neww->editor = NOEDITOR;
294
295 /* change the window type to be appropriate for editing */
296 neww->state = (oldstate & ~WINDOWTYPE) | DISPWINDOW;
297 resethandlers = 1;
298 if (pushpop != 0)
299 {
300 if ((neww->state&WINDOWMODE) != 0 &&
301 ((oldstate&WINDOWTYPE) == DISPWINDOW))
302 {
303 resethandlers = 0;
304 }
305 }
306
307 /* if editing a technology-edit cell, indicate so */
308 if ((cur->userbits&TECEDITCELL) != 0)
309 {
310 us_setwindowmode(neww, neww->state, neww->state | WINDOWTECEDMODE);
311 }
312
313 /* adjust window if it changed from display window to something else */
314 if ((neww->state&WINDOWTYPE) == DISPWINDOW && (oldstate&WINDOWTYPE) != DISPWINDOW)
315 {
316 /* became a display window: shrink the bottom and right edge */
317 neww->usehx -= DISPLAYSLIDERSIZE;
318 neww->usely += DISPLAYSLIDERSIZE;
319 }
320 if ((neww->state&WINDOWTYPE) != DISPWINDOW && (oldstate&WINDOWTYPE) == DISPWINDOW)
321 {
322 /* no longer a display window: shrink the bottom and right edge */
323 neww->usehx += DISPLAYSLIDERSIZE;
324 neww->usely -= DISPLAYSLIDERSIZE;
325 }
326
327 /* adjust window if it changed from waveform window to something else */
328 if ((neww->state&WINDOWTYPE) == WAVEFORMWINDOW && (oldstate&WINDOWTYPE) != WAVEFORMWINDOW)
329 {
330 /* became a waveform window: shrink the bottom and right edge */
331 neww->uselx += DISPLAYSLIDERSIZE;
332 neww->usely += DISPLAYSLIDERSIZE;
333 }
334 if ((neww->state&WINDOWTYPE) != WAVEFORMWINDOW && (oldstate&WINDOWTYPE) == WAVEFORMWINDOW)
335 {
336 /* no longer a waveform window: shrink the bottom and right edge */
337 neww->uselx -= DISPLAYSLIDERSIZE;
338 neww->usely -= DISPLAYSLIDERSIZE;
339 }
340
341 if (resethandlers != 0)
342 {
343 neww->buttonhandler = DEFAULTBUTTONHANDLER;
344 neww->changehandler = DEFAULTCHANGEHANDLER;
345 neww->charhandler = DEFAULTCHARHANDLER;
346 neww->termhandler = DEFAULTTERMHANDLER;
347 neww->redisphandler = DEFAULTREDISPHANDLER;
348 }
349
350 us_squarescreen(neww, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, exact);
351 neww->screenlx = lx;
352 neww->screenhx = hx;
353 neww->screenly = ly;
354 neww->screenhy = hy;
355 computewindowscale(neww);
356
357 /* window gets bigger: see if grid can be drawn */
358 us_gridset(neww, neww->state);
359
360 if (focusinst != NONODEINST)
361 {
362 newhigh.status = HIGHFROM;
363 newhigh.cell = focusinst->parent;
364 newhigh.fromgeom = focusinst->geom;
365 newhigh.fromport = cellinstport;
366 newhigh.frompoint = 0;
367 newhigh.fromvar = NOVARIABLE;
368 newhigh.fromvarnoeval = NOVARIABLE;
369 us_addhighlight(&newhigh);
370 }
371 }
372
373 (void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"), (INTBIG)cur, VNODEPROTO);
374 endobjectchange((INTBIG)us_tool, VTOOL);
375 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)neww,
376 VWINDOWPART|VDONTSAVE);
377 us_setcellname(neww);
378 us_setcellsize(neww);
379 us_setgridsize(neww);
380 if (neww->redisphandler != 0) (*neww->redisphandler)(neww);
381 if ((neww->state&WINDOWTECEDMODE) != 0 && (oldmode&WINDOWTECEDMODE) == 0)
382 {
383 TDCLEAR(descript);
384 TDSETSIZE(descript, TXTSETPOINTS(18));
385 us_hbox.col = HIGHLIT;
386 us_writetext(neww->uselx, neww->usehx, neww->usehy-30, neww->usehy, &us_hbox,
387 _("TECHNOLOGY EDIT MODE:"), descript, neww, NOTECHNOLOGY);
388 var = getval((INTBIG)us_tool, VTOOL, VSTRING, "USER_local_capg");
389 if (var != NOVARIABLE)
390 {
391 infstr = initinfstr();
392 formatinfstr(infstr, _("Use %s to make changes"), (CHAR *)var->addr);
393 us_writetext(neww->uselx, neww->usehx, neww->usehy-60, neww->usehy-30, &us_hbox,
394 returninfstr(infstr), descript, neww, NOTECHNOLOGY);
395 }
396 }
397 }
398
399 /*
400 * Routine to switch technologies. If "forcedtechnology" is nonzero, switch to that
401 * technology, otherwise determine technology from cell "cell". If "always" is false,
402 * only switch if the user has selected "auto-switching".
403 */
us_ensurepropertechnology(NODEPROTO * cell,CHAR * forcedtechnology,BOOLEAN always)404 void us_ensurepropertechnology(NODEPROTO *cell, CHAR *forcedtechnology, BOOLEAN always)
405 {
406 REGISTER USERCOM *uc;
407 REGISTER TECHNOLOGY *tech;
408 REGISTER WINDOWFRAME *curframe, *lastframe;
409 REGISTER void *infstr;
410
411 /* if not auto-switching technologies, quit */
412 if ((us_useroptions&AUTOSWITCHTECHNOLOGY) == 0) return;
413
414 /* see if cell has a technology */
415 if (cell == NONODEPROTO) return;
416 if ((cell->cellview->viewstate&TEXTVIEW) != 0) return;
417 tech = cell->tech;
418 if (tech == gen_tech) return;
419 if ((tech->userbits&NOPRIMTECHNOLOGY) != 0) return;
420
421 /* switch technologies */
422 lastframe = getwindowframe(TRUE);
423 if (us_getmacro(x_("pmtesetup")) == NOVARIABLE) return;
424 infstr = initinfstr();
425 formatinfstr(infstr, x_("pmtesetup \"%s\""), us_techname(cell));
426 uc = us_makecommand(returninfstr(infstr));
427 if (uc != NOUSERCOM)
428 {
429 us_execute(uc, FALSE, FALSE, FALSE);
430 us_freeusercom(uc);
431 }
432 curframe = getwindowframe(TRUE);
433 if (curframe != lastframe && lastframe != NOWINDOWFRAME)
434 bringwindowtofront(lastframe);
435 }
436
437 /*
438 * routine to initialize for changes to the screen
439 */
us_beginchanges(void)440 void us_beginchanges(void)
441 {
442 }
443
444 /*
445 * routine to finish making changes to the screen. If "which" is NOWINDOWPART,
446 * changes are made to all windows. Otherwise, "which" is the specific
447 * window to update.
448 */
us_endchanges(WINDOWPART * which)449 void us_endchanges(WINDOWPART *which)
450 {
451 REGISTER WINDOWPART *w;
452 XARRAY rottrans;
453 REGISTER REDRAW *r, *nextr;
454 REGISTER NODEINST *ni;
455 REGISTER ARCINST *ai;
456 REGISTER PORTPROTO *pp;
457 REGISTER INTBIG stopped;
458 REGISTER INTBIG ret;
459
460 stopped = el_pleasestop;
461 for(r = us_firstredraw; r != NOREDRAW; r = nextr)
462 {
463 /* remember the next redraw module and queue this one for deletion */
464 nextr = r->nextredraw;
465 r->nextredraw = us_usedredraw;
466 us_usedredraw = r;
467 if (stopped != 0) continue;
468
469 if (r->entryisnode)
470 {
471 ni = r->entryaddr.ni;
472 if ((ni->userbits & (REWANTN|RETDONN|DEADN)) == REWANTN)
473 {
474 if (which != NOWINDOWPART)
475 {
476 if (ni->rotation == 0 && ni->transpose == 0)
477 {
478 ret = us_showin(which, ni->geom, ni->parent, el_matid, LAYERA, 1);
479 } else
480 {
481 makerot(ni, rottrans);
482 ret = us_showin(which, ni->geom, ni->parent, rottrans, LAYERA, 1);
483 }
484 if (ret < 0) stopped = 1; else
485 if (ret & 2) us_queueopaque(ni->geom, FALSE);
486 } else
487 {
488 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
489 {
490 if ((w->state&WINDOWTYPE) != DISPWINDOW &&
491 (w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
492 if (ni->rotation == 0 && ni->transpose == 0)
493 {
494 ret = us_showin(w, ni->geom, ni->parent, el_matid, LAYERA, 1);
495 } else
496 {
497 makerot(ni, rottrans);
498 ret = us_showin(w, ni->geom, ni->parent, rottrans, LAYERA, 1);
499 }
500 if (ret < 0) { stopped = 1; break; }
501 if (ret & 2) us_queueopaque(ni->geom, FALSE);
502 }
503 }
504 ni->userbits |= RETDONN;
505 }
506 } else
507 {
508 ai = r->entryaddr.ai;
509 if ((ai->userbits & (RETDONA|DEADA)) == 0)
510 {
511 if (which != NOWINDOWPART)
512 {
513 ret = us_showin(which, ai->geom, ai->parent, el_matid, LAYERA, 1);
514 if (ret < 0) stopped = 1; else
515 if (ret & 2) us_queueopaque(ai->geom, FALSE);
516 } else
517 {
518 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
519 {
520 if ((w->state&WINDOWTYPE) != DISPWINDOW &&
521 (w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
522 ret = us_showin(w, ai->geom, ai->parent, el_matid, LAYERA, 1);
523 if (ret < 0) { stopped = 1; break; }
524 if (ret & 2) us_queueopaque(ai->geom, FALSE);
525 }
526 }
527 ai->userbits |= RETDONA;
528 }
529 }
530 }
531 us_firstredraw = NOREDRAW;
532
533 /* now re-draw the opaque objects */
534 for(r = us_firstopaque; r != NOREDRAW; r = nextr)
535 {
536 /* remember the next redraw module and queue this one for deletion */
537 nextr = r->nextredraw;
538 r->nextredraw = us_usedredraw;
539 us_usedredraw = r;
540
541 if (stopped != 0) continue;
542 if (r->entryisnode)
543 {
544 ni = r->entryaddr.ni;
545 if ((ni->userbits & (REWANTN|REODONN|DEADN)) == REWANTN)
546 {
547 if (which != NOWINDOWPART)
548 {
549 if (ni->rotation == 0 && ni->transpose == 0)
550 {
551 ret = us_showin(which, ni->geom, ni->parent, el_matid, LAYERA, 2);
552 } else
553 {
554 makerot(ni, rottrans);
555 ret = us_showin(which, ni->geom, ni->parent, rottrans, LAYERA, 2);
556 }
557 if (ret < 0) stopped = 1;
558 } else
559 {
560 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
561 {
562 if ((w->state&WINDOWTYPE) != DISPWINDOW &&
563 (w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
564 if (ni->rotation == 0 && ni->transpose == 0)
565 {
566 ret = us_showin(w, ni->geom, ni->parent, el_matid, LAYERA, 2);
567 } else
568 {
569 makerot(ni, rottrans);
570 ret = us_showin(w, ni->geom, ni->parent, rottrans, LAYERA, 2);
571 }
572 if (ret < 0) { stopped = 1; break; }
573 }
574 }
575 ni->userbits |= REODONN;
576 }
577 } else
578 {
579 ai = r->entryaddr.ai;
580 if ((ai->userbits & (REODONA|DEADA)) == 0)
581 {
582 if (which != NOWINDOWPART)
583 {
584 ret = us_showin(which, ai->geom, ai->parent, el_matid, LAYERA, 2);
585 if (ret < 0) stopped = 1;
586 } else
587 {
588 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
589 {
590 if ((w->state&WINDOWTYPE) != DISPWINDOW &&
591 (w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
592 ret = us_showin(w, ai->geom, ai->parent, el_matid, LAYERA, 2);
593 if (ret < 0) { stopped = 1; break; }
594 }
595 }
596 ai->userbits |= REODONA;
597 }
598 }
599 }
600
601 us_firstopaque = NOREDRAW;
602 us_lastopaque = NOREDRAW;
603
604 /* now free up all of the redraw modules */
605 for(r = us_usedredraw; r != NOREDRAW; r = nextr)
606 {
607 nextr = r->nextredraw;
608 if (r->entryisnode)
609 {
610 ni = r->entryaddr.ni;
611 ni->userbits &= ~(REWANTN|RELOCLN);
612 } else
613 {
614 ai = r->entryaddr.ai;
615 ai->userbits &= ~(REWANTA|RELOCLA);
616 }
617 us_freeredraw(r);
618 }
619 us_usedredraw = NOREDRAW;
620
621 /* now re-draw the exports */
622 for(r = us_firstexport; r != NOREDRAW; r = nextr)
623 {
624 /* remember the next redraw module and queue this one for deletion */
625 nextr = r->nextredraw;
626 pp = r->entryaddr.pp;
627 us_freeredraw(r);
628 if (stopped != 0) continue;
629 makerot(pp->subnodeinst, rottrans);
630
631 if (which != NOWINDOWPART)
632 {
633 us_writeprotoname(pp, LAYERA, rottrans, LAYERO, el_colcelltxt, which, 0, 0, 0, 0,
634 (us_useroptions&EXPORTLABELS)>>EXPORTLABELSSH);
635 us_drawportprotovariables(pp, LAYERA, rottrans, which, FALSE);
636 } else
637 {
638 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
639 {
640 if ((w->state&WINDOWTYPE) != DISPWINDOW &&
641 (w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
642 if (w->curnodeproto != pp->parent) continue;
643 us_writeprotoname(pp, LAYERA, rottrans, LAYERO, el_colcelltxt, w, 0, 0, 0, 0,
644 (us_useroptions&EXPORTLABELS)>>EXPORTLABELSSH);
645 us_drawportprotovariables(pp, LAYERA, rottrans, w, FALSE);
646 }
647 }
648 }
649 us_firstexport = NOREDRAW;
650
651 /* force all changes out */
652 flushscreen();
653 }
654
655 /*
656 * routine to make a change to the screen (sandwiched between a "us_beginchanges"
657 * and an "us_endchanges" call. Returns an indicator of what else needs to be
658 * drawn (negative to stop display).
659 */
us_showin(WINDOWPART * w,GEOM * object,NODEPROTO * parnt,XARRAY trans,INTBIG on,INTBIG layers)660 INTBIG us_showin(WINDOWPART *w, GEOM *object, NODEPROTO *parnt, XARRAY trans, INTBIG on,
661 INTBIG layers)
662 {
663 REGISTER NODEINST *ni;
664 XARRAY localtran, subrot, subtran;
665 REGISTER WINDOWPART *oldwin;
666 REGISTER INTBIG moretodo, res;
667 REGISTER INTBIG objlocal;
668
669 /* if the parent is the current cell in the window, draw the instance */
670 moretodo = 0;
671 oldwin = setvariablewindow(w);
672 if (parnt == w->curnodeproto)
673 {
674 if (object->entryisnode)
675 {
676 ni = object->entryaddr.ni;
677 begintraversehierarchy();
678 res = us_drawnodeinst(ni, on, trans, layers, w);
679 endtraversehierarchy();
680 if (res == -2)
681 {
682 (void)setvariablewindow(oldwin);
683 return(-1);
684 }
685 if (res < 0) res = 0;
686 moretodo |= res;
687 } else
688 {
689 res = us_drawarcinst(object->entryaddr.ai, on, trans, layers, w);
690 if (res < 0)
691 {
692 (void)setvariablewindow(oldwin);
693 return(-1);
694 }
695 moretodo |= res;
696 }
697
698 /* if drawing the opaque layer, don't look for other things to draw */
699 if (on && layers == 2)
700 {
701 (void)setvariablewindow(oldwin);
702 return(moretodo);
703 }
704
705 /* queue re-drawing of objects in vicinity of this one */
706 if (object->entryisnode)
707 us_queuevicinity(w, object, parnt, trans, 0, 0, 0, 0, on); else
708 us_queuevicinity(w, object, parnt, trans, 0, 0, 0, 0, on);
709 (void)setvariablewindow(oldwin);
710 return(moretodo);
711 }
712
713 /* look at all instances of the parent cell that are expanded */
714 if (object->entryisnode)
715 objlocal = object->entryaddr.ni->userbits & RELOCLN; else
716 objlocal = object->entryaddr.ai->userbits & RELOCLA;
717
718 /* Steve Holmlund of Factron suggested this next statement */
719 if (on == 0) objlocal = 0;
720
721 for(ni = parnt->firstinst; ni != NONODEINST; ni = ni->nextinst)
722 {
723 if ((ni->userbits & NEXPAND) == 0) continue;
724 if (objlocal != 0 && (ni->userbits&(RELOCLN|REWANTN)) == 0) continue;
725
726 /* transform nodeinst to outer instance */
727 maketrans(ni, localtran);
728 transmult(trans, localtran, subrot);
729 if (ni->rotation == 0 && ni->transpose == 0)
730 {
731 res = us_showin(w, object, ni->parent, subrot, on, layers);
732 if (res < 0)
733 {
734 (void)setvariablewindow(oldwin);
735 return(-1);
736 }
737 moretodo |= res;
738 } else
739 {
740 makerot(ni, localtran);
741 transmult(subrot, localtran, subtran);
742 res = us_showin(w, object, ni->parent, subtran, on, layers);
743 if (res < 0)
744 {
745 (void)setvariablewindow(oldwin);
746 return(-1);
747 }
748 moretodo |= res;
749 }
750 }
751 (void)setvariablewindow(oldwin);
752 return(moretodo);
753 }
754
755 /*
756 * routine to queue object "p" to be re-drawn. If "local" is true, only
757 * draw the local instance of this object, not every instance.
758 */
us_queueredraw(GEOM * p,BOOLEAN local)759 void us_queueredraw(GEOM *p, BOOLEAN local)
760 {
761 REGISTER REDRAW *r;
762 REGISTER NODEINST *ni;
763 REGISTER ARCINST *ai;
764
765 if (p->entryisnode)
766 {
767 ni = p->entryaddr.ni;
768 ni->userbits = (ni->userbits & ~(RETDONN|REODONN|RELOCLN)) | REWANTN;
769 if (local) ni->userbits |= RELOCLN;
770 } else
771 {
772 ai = p->entryaddr.ai;
773 ai->userbits = (ai->userbits & ~(RETDONA|REODONA|RELOCLA)) | REWANTA;
774 if (local) ai->userbits |= RELOCLA;
775 }
776
777 /* queue this object for being re-drawn */
778 r = us_allocredraw();
779 if (r == NOREDRAW)
780 {
781 ttyputnomemory();
782 return;
783 }
784 r->entryisnode = p->entryisnode;
785 r->entryaddr.blind = p->entryaddr.blind;
786 r->nextredraw = us_firstredraw;
787 us_firstredraw = r;
788 }
789
790 /*
791 * Routine to remove all redraw objects that are in library "lib"
792 * (because the library has been deleted)
793 */
us_unqueueredraw(LIBRARY * lib)794 void us_unqueueredraw(LIBRARY *lib)
795 {
796 REGISTER REDRAW *r, *nextr, *lastr;
797 REGISTER LIBRARY *rlib;
798
799 lastr = NOREDRAW;
800 for(r = us_firstredraw; r != NOREDRAW; r = nextr)
801 {
802 nextr = r->nextredraw;
803 if (r->entryisnode) rlib = r->entryaddr.ni->parent->lib; else
804 rlib = r->entryaddr.ai->parent->lib;
805 if (rlib == lib)
806 {
807 if (lastr == NOREDRAW) us_firstredraw = nextr; else
808 lastr->nextredraw = nextr;
809 us_freeredraw(r);
810 continue;
811 }
812 lastr = r;
813 }
814 }
815
816 /*
817 * routine to erase the display of "geom" in all windows (sandwiched between
818 * "us_beginchanges" and "us_endchanges" calls)
819 */
us_undisplayobject(GEOM * geom)820 void us_undisplayobject(GEOM *geom)
821 {
822 REGISTER NODEINST *ni;
823 REGISTER ARCINST *ai;
824 REGISTER WINDOWPART *w;
825 XARRAY rottrans;
826
827 if (geom->entryisnode)
828 {
829 ni = geom->entryaddr.ni;
830 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
831 {
832 if ((w->state&WINDOWTYPE) != DISPWINDOW &&
833 (w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
834 if (ni->rotation == 0 && ni->transpose == 0)
835 {
836 (void)us_showin(w, geom, ni->parent, el_matid, LAYERN, 3);
837 } else
838 {
839 makerot(ni, rottrans);
840 (void)us_showin(w, geom, ni->parent, rottrans, LAYERN, 3);
841 }
842 }
843 } else
844 {
845 ai = geom->entryaddr.ai;
846 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
847 {
848 if ((w->state&WINDOWTYPE) != DISPWINDOW &&
849 (w->state&WINDOWTYPE) != DISP3DWINDOW) continue;
850 (void)us_showin(w, geom, ai->parent, el_matid, LAYERN, 3);
851 }
852 }
853 }
854
855 /*
856 * routine to queue object "p" to be re-drawn.
857 */
us_queueexport(PORTPROTO * pp)858 void us_queueexport(PORTPROTO *pp)
859 {
860 REGISTER REDRAW *r;
861
862 /* queue this object for being re-drawn */
863 r = us_allocredraw();
864 if (r == NOREDRAW)
865 {
866 ttyputnomemory();
867 return;
868 }
869 r->entryaddr.pp = pp;
870 r->nextredraw = us_firstexport;
871 us_firstexport = r;
872 }
873
874 /******************** HELPER ROUTINES ******************/
875
876 /*
877 * routine to queue the opaque layers of object "p" to be re-drawn.
878 * If "local" is true, only draw the local instance of this object, not
879 * every instance.
880 */
us_queueopaque(GEOM * p,BOOLEAN local)881 void us_queueopaque(GEOM *p, BOOLEAN local)
882 {
883 REGISTER REDRAW *r;
884 REGISTER NODEINST *ni;
885 REGISTER NODEPROTO *np;
886 REGISTER ARCINST *ai;
887 REGISTER TECHNOLOGY *tech;
888 REGISTER INTBIG i;
889
890 if (p->entryisnode)
891 {
892 ni = p->entryaddr.ni;
893
894 /* count displayable variables on this node */
895 for(i = 0; i < ni->numvar; i++)
896 if ((ni->firstvar[i].type&VDISPLAY) != 0) break;
897
898 /* if this nodeinst has nothing on the opaque layer, don't queue it */
899 np = ni->proto;
900 if (np->primindex != 0 && (np->userbits&NHASOPA) == 0 &&
901 i >= ni->numvar && ni->firstportexpinst == NOPORTEXPINST) return;
902
903 /* set the nodeinst bits for opaque redraw */
904 ni->userbits = (ni->userbits & ~REODONN) | REWANTN;
905 if (local) ni->userbits |= RELOCLN;
906 tech = np->tech;
907 } else
908 {
909 ai = p->entryaddr.ai;
910
911 /* count displayable variables on this arc */
912 for(i = 0; i < ai->numvar; i++)
913 if ((ai->firstvar[i].type&VDISPLAY) != 0) break;
914
915 /* if this arcinst has nothing on the opaque layer, don't queue it */
916 if ((ai->proto->userbits&AHASOPA) == 0 && i >= ai->numvar) return;
917
918 /* set the arcinst bits for opaque redraw */
919 ai->userbits = (ai->userbits & ~REODONA) | REWANTA;
920 if (local) ai->userbits |= RELOCLA;
921 tech = ai->proto->tech;
922 }
923
924 /* queue the object for opaque redraw */
925 r = us_allocredraw();
926 if (r == NOREDRAW)
927 {
928 ttyputnomemory();
929 return;
930 }
931 r->entryisnode = p->entryisnode;
932 r->entryaddr.blind = p->entryaddr.blind;
933 if (tech == el_curtech)
934 {
935 /* in the current technology: queue redraw of this stuff first */
936 r->nextredraw = us_firstopaque;
937 us_firstopaque = r;
938 if (us_lastopaque == NOREDRAW) us_lastopaque = r;
939 } else
940 {
941 /* in some other technology: queue redraw of this stuff last */
942 if (us_lastopaque != NOREDRAW) us_lastopaque->nextredraw = r;
943 r->nextredraw = NOREDRAW;
944 us_lastopaque = r;
945 if (us_firstopaque == NOREDRAW) us_firstopaque = r;
946 }
947 }
948
949 /*
950 * routine to allocate a new redraw from the pool (if any) or memory
951 * routine returns NOREDRAW upon error
952 */
us_allocredraw(void)953 REDRAW *us_allocredraw(void)
954 {
955 REGISTER REDRAW *r;
956
957 if (us_redrawfree == NOREDRAW)
958 {
959 r = (REDRAW *)emalloc(sizeof (REDRAW), us_tool->cluster);
960 if (r == 0) return(NOREDRAW);
961 } else
962 {
963 /* take module from free list */
964 r = us_redrawfree;
965 us_redrawfree = r->nextredraw;
966 }
967 return(r);
968 }
969
970 /*
971 * routine to return redraw module "r" to the pool of free modules
972 */
us_freeredraw(REDRAW * r)973 void us_freeredraw(REDRAW *r)
974 {
975 r->nextredraw = us_redrawfree;
976 us_redrawfree = r;
977 }
978
979 /*
980 * routine to queue for local re-draw anything in cell "parnt" that is
981 * in the vicinity of "object" with bounding box (lx-hx, ly-hy). The objects
982 * are to be drawn on if "on" is nonzero. The transformation matrix
983 * between the bounding box and the cell is in "trans".
984 */
us_queuevicinity(WINDOWPART * w,GEOM * object,NODEPROTO * parnt,XARRAY trans,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,INTBIG on)985 void us_queuevicinity(WINDOWPART *w, GEOM *object, NODEPROTO *parnt, XARRAY trans, INTBIG lx,
986 INTBIG hx, INTBIG ly, INTBIG hy, INTBIG on)
987 {
988 REGISTER GEOM *look;
989 REGISTER NODEINST *ni;
990 REGISTER ARCINST *ai;
991 INTBIG bx, ux, by, uy, olx, ohx, oly, ohy;
992 REGISTER BOOLEAN local;
993 REGISTER INTBIG i, search, slop;
994
995 /* compute full extent of the object, including text */
996 if (object != NOGEOM)
997 {
998 if (object->entryisnode)
999 {
1000 us_getnodebounds(object->entryaddr.ni, &lx, &hx, &ly, &hy);
1001 } else
1002 {
1003 us_getarcbounds(object->entryaddr.ai, &lx, &hx, &ly, &hy);
1004 }
1005 }
1006
1007 xform(lx, ly, &bx, &by, trans);
1008 xform(hx, hy, &ux, &uy, trans);
1009 if (bx > ux) { i = bx; bx = ux; ux = i; }
1010 if (by > uy) { i = by; by = uy; uy = i; }
1011
1012 /* extend by 1 screen pixel */
1013 i = roundfloat(3.0f / w->scalex);
1014 if (i <= 0) i = 1;
1015 bx -= i; hx += i;
1016 by -= i; hy += i;
1017
1018 /* clip search to visible area of window */
1019 if (bx > w->screenhx || ux < w->screenlx ||
1020 by > w->screenhy || uy < w->screenly) return;
1021 if (bx < w->screenlx) bx = w->screenlx;
1022 if (ux > w->screenhx) ux = w->screenhx;
1023 if (by < w->screenly) by = w->screenly;
1024 if (uy > w->screenhy) uy = w->screenhy;
1025
1026 slop = FARTEXTLIMIT * lambdaofcell(parnt);
1027 search = initsearch(bx-slop, ux+slop, by-slop, uy+slop, parnt);
1028 if (object == NOGEOM) local = TRUE; else local = FALSE;
1029 for(;;)
1030 {
1031 if ((look = nextobject(search)) == NOGEOM) break;
1032
1033 /* don't re-draw the current object whose vicinity is being checked */
1034 if (look == object) continue;
1035
1036 /* see if the object really intersects the redraw area */
1037 if (look->entryisnode)
1038 us_getnodebounds(look->entryaddr.ni, &olx, &ohx, &oly, &ohy); else
1039 us_getarcbounds(look->entryaddr.ai, &olx, &ohx, &oly, &ohy);
1040 if (olx > ux || ohx < bx || oly > uy || ohy < by) continue;
1041
1042 /* redraw all if object is going off, redraw opaque if going on */
1043 if (on == LAYERN) us_queueredraw(look, local); else
1044 us_queueopaque(look, local);
1045 }
1046
1047 /* now queue things with "far text" */
1048 for(ni = parnt->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1049 {
1050 if ((ni->userbits&NHASFARTEXT) == 0) continue;
1051 us_getnodebounds(ni, &olx, &ohx, &oly, &ohy);
1052 if (olx >= ux || ohx <= bx || oly >= uy || ohy <= by) continue;
1053 if (on == LAYERN) us_queueredraw(ni->geom, local); else
1054 us_queueopaque(ni->geom, local);
1055 }
1056 for(ai = parnt->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1057 {
1058 if ((ai->userbits&AHASFARTEXT) == 0) continue;
1059 us_getarcbounds(ai, &olx, &ohx, &oly, &ohy);
1060 if (olx >= ux || ohx <= bx || oly >= uy || ohy <= by) continue;
1061 if (on == LAYERN) us_queueredraw(ai->geom, local); else
1062 us_queueopaque(ai->geom, local);
1063 }
1064 }
1065
1066 /*
1067 * null routine for polygon display
1068 */
us_nulldisplayroutine(POLYGON * obj,WINDOWPART * w)1069 void us_nulldisplayroutine(POLYGON *obj, WINDOWPART *w)
1070 {
1071 }
1072
1073 /*
1074 * routine to write polygon "obj" in window "w".
1075 */
us_showpoly(POLYGON * obj,WINDOWPART * w)1076 void us_showpoly(POLYGON *obj, WINDOWPART *w)
1077 {
1078 REGISTER INTBIG i, cx, cy, rad;
1079 REGISTER INTBIG pre, tx, ty;
1080 INTBIG lx, ux, ly, uy, six, siy;
1081 WINDOWPART wsc;
1082 REGISTER GRAPHICS *gra;
1083 static POLYGON *objc = NOPOLYGON;
1084 INTBIG tsx, tsy;
1085
1086 if (us_3dgatheringpolys)
1087 {
1088 us_3dshowpoly(obj, w);
1089 return;
1090 }
1091
1092 /* quit if no bits to be written */
1093 if (obj->desc->bits == LAYERN) return;
1094
1095 /* special case for grid display */
1096 if (obj->style == GRIDDOTS)
1097 {
1098 screendrawgrid(w, obj);
1099 return;
1100 }
1101
1102 /* transform to space of this window */
1103 if ((w->state&INPLACEEDIT) != 0) xformpoly(obj, w->outofcell);
1104
1105 /* now draw the polygon */
1106 gra = obj->desc;
1107 switch (obj->style)
1108 {
1109 case FILLED: /* filled polygon */
1110 case FILLEDRECT: /* filled rectangle */
1111 if (isbox(obj, &lx, &ux, &ly, &uy))
1112 {
1113 /* simple rectangular box: transform, clip, and draw */
1114 if (us_makescreen(&lx, &ly, &ux, &uy, w)) break;
1115 screendrawbox(w, lx, ux, ly, uy, gra);
1116
1117 /* for patterned and outlined rectangles, draw the box too */
1118 if ((gra->colstyle&(NATURE|OUTLINEPAT)) == (PATTERNED|OUTLINEPAT))
1119 {
1120 screendrawline(w, lx, ly, lx, uy, gra, 0);
1121 screendrawline(w, lx, uy, ux, uy, gra, 0);
1122 screendrawline(w, ux, uy, ux, ly, gra, 0);
1123 screendrawline(w, ux, ly, lx, ly, gra, 0);
1124 }
1125 break;
1126 }
1127
1128 /* code cannot be called by multiple procesors: uses globals */
1129 NOT_REENTRANT;
1130
1131 /* copy the polygon since it will be mangled when clipped */
1132 (void)needstaticpolygon(&objc, obj->count, us_tool->cluster);
1133 objc->count = obj->count;
1134 objc->style = obj->style;
1135 objc->desc = gra;
1136 for(i=0; i<obj->count; i++)
1137 {
1138 objc->xv[i] = applyxscale(w, obj->xv[i]-w->screenlx) + w->uselx;
1139 objc->yv[i] = applyyscale(w, obj->yv[i]-w->screenly) + w->usely;
1140 }
1141
1142 /* clip and draw the polygon */
1143 clippoly(objc, w->uselx, w->usehx, w->usely, w->usehy);
1144 if (objc->count <= 1) break;
1145 if (objc->count > 2)
1146 {
1147 /* always clockwise */
1148 if (areapoly(objc) < 0.0) reversepoly(objc);
1149 screendrawpolygon(w, objc->xv, objc->yv, objc->count, objc->desc);
1150
1151 /* for patterned and outlined polygons, draw the outline too */
1152 if ((gra->colstyle&(NATURE|OUTLINEPAT)) == (PATTERNED|OUTLINEPAT))
1153 {
1154 for(i=0; i<objc->count; i++)
1155 {
1156 if (i == 0) pre = objc->count-1; else pre = i-1;
1157 screendrawline(w, objc->xv[pre], objc->yv[pre], objc->xv[i], objc->yv[i],
1158 objc->desc, 0);
1159 }
1160 }
1161 } else screendrawline(w, objc->xv[0], objc->yv[0], objc->xv[1], objc->yv[1],
1162 gra, 0);
1163 break;
1164
1165 case CLOSEDRECT: /* closed rectangle outline */
1166 us_wanttodraw(obj->xv[0], obj->yv[0], obj->xv[0], obj->yv[1], w, gra, 0);
1167 us_wanttodraw(obj->xv[0], obj->yv[1], obj->xv[1], obj->yv[1], w, gra, 0);
1168 us_wanttodraw(obj->xv[1], obj->yv[1], obj->xv[1], obj->yv[0], w, gra, 0);
1169 us_wanttodraw(obj->xv[1], obj->yv[0], obj->xv[0], obj->yv[0], w, gra, 0);
1170 break;
1171
1172 case CROSSED: /* polygon outline with cross */
1173 us_wanttodraw(obj->xv[0], obj->yv[0], obj->xv[2], obj->yv[2], w, gra, 0);
1174 us_wanttodraw(obj->xv[1], obj->yv[1], obj->xv[3], obj->yv[3], w, gra, 0);
1175 /* FALLTHROUGH */
1176
1177 case CLOSED: /* closed polygon outline */
1178 for(i=0; i<obj->count; i++)
1179 {
1180 if (i == 0) pre = obj->count-1; else pre = i-1;
1181 us_wanttodraw(obj->xv[pre], obj->yv[pre], obj->xv[i], obj->yv[i], w, gra, 0);
1182 }
1183 break;
1184
1185 case OPENED: /* opened polygon outline */
1186 for(i=1; i<obj->count; i++)
1187 us_wanttodraw(obj->xv[i-1], obj->yv[i-1], obj->xv[i], obj->yv[i], w, gra, 0);
1188 break;
1189
1190 case OPENEDT1: /* opened polygon outline, dotted */
1191 for(i=1; i<obj->count; i++)
1192 us_wanttodraw(obj->xv[i-1], obj->yv[i-1], obj->xv[i], obj->yv[i], w, gra, 1);
1193 break;
1194
1195 case OPENEDT2: /* opened polygon outline, dashed */
1196 for(i=1; i<obj->count; i++)
1197 us_wanttodraw(obj->xv[i-1], obj->yv[i-1], obj->xv[i], obj->yv[i], w, gra, 2);
1198 break;
1199
1200 case OPENEDT3: /* opened polygon outline, thicker */
1201 for(i=1; i<obj->count; i++)
1202 us_wanttodraw(obj->xv[i-1], obj->yv[i-1], obj->xv[i], obj->yv[i], w, gra, 3);
1203 break;
1204
1205 case OPENEDO1: /* extended opened polygon outline */
1206 us_drawextendedpolyline(obj, w);
1207 break;
1208
1209 case VECTORS: /* many lines */
1210 if (obj->count % 2 != 0)
1211 ttyputmsg(_("Cannot display vector with %ld vertices (must be even)"),
1212 obj->count);
1213 for(i=0; i<obj->count; i += 2)
1214 us_wanttodraw(obj->xv[i], obj->yv[i], obj->xv[i+1], obj->yv[i+1], w, gra, 0);
1215 break;
1216
1217 case CROSS: /* crosses (always have one point) */
1218 case BIGCROSS:
1219 getcenter(obj, &six, &siy);
1220 if (six < w->screenlx || six > w->screenhx || siy < w->screenly || siy > w->screenhy)
1221 break;
1222 if (obj->style == CROSS) i = CROSSSIZE; else i = BIGCROSSSIZE;
1223 us_wanttodrawo(six, -i, siy, 0, six, i, siy, 0, w, gra, 0);
1224 us_wanttodrawo(six, 0, siy, -i, six, 0, siy, i, w, gra, 0);
1225 break;
1226
1227 case TEXTCENT: /* text centered in box */
1228 case TEXTTOP: /* text below top of box */
1229 case TEXTBOT: /* text above bottom of box */
1230 case TEXTLEFT: /* text right of left edge of box */
1231 case TEXTRIGHT: /* text left of right edge of box */
1232 case TEXTTOPLEFT: /* text to lower-right of upper-left corner */
1233 case TEXTBOTLEFT: /* text to upper-right of lower-left corner */
1234 case TEXTTOPRIGHT: /* text to lower-left of upper-right corner */
1235 case TEXTBOTRIGHT: /* text to upper-left of lower-right corner */
1236 getbbox(obj, &lx, &ux, &ly, &uy);
1237 lx = applyxscale(w, lx-w->screenlx) + w->uselx;
1238 ly = applyyscale(w, ly-w->screenly) + w->usely;
1239 ux = applyxscale(w, ux-w->screenlx) + w->uselx;
1240 uy = applyyscale(w, uy-w->screenly) + w->usely;
1241 screensettextinfo(w, obj->tech, obj->textdescript);
1242 screengettextsize(w, obj->string, &tsx, &tsy);
1243 switch (obj->style)
1244 {
1245 case TEXTCENT:
1246 tx = (lx+ux-tsx) / 2;
1247 ty = (ly+uy-tsy) / 2;
1248 break;
1249 case TEXTTOP:
1250 tx = (lx+ux-tsx) / 2;
1251 ty = uy-tsy;
1252 break;
1253 case TEXTBOT:
1254 tx = (lx+ux-tsx) / 2;
1255 ty = ly;
1256 break;
1257 case TEXTLEFT:
1258 tx = lx;
1259 ty = (ly+uy-tsy) / 2;
1260 break;
1261 case TEXTRIGHT:
1262 tx = ux-tsx;
1263 ty = (ly+uy-tsy) / 2;
1264 break;
1265 case TEXTTOPLEFT:
1266 tx = lx;
1267 ty = uy-tsy;
1268 break;
1269 case TEXTBOTLEFT:
1270 tx = lx;
1271 ty = ly;
1272 break;
1273 case TEXTTOPRIGHT:
1274 tx = ux-tsx;
1275 ty = uy-tsy;
1276 break;
1277 case TEXTBOTRIGHT:
1278 tx = ux-tsx;
1279 ty = ly;
1280 break;
1281 }
1282 if (tx > w->usehx || tx+tsx < w->uselx ||
1283 ty > w->usehy || ty+tsy < w->usely) break;
1284 screendrawtext(w, tx, ty, obj->string, gra);
1285 break;
1286
1287 case TEXTBOX: /* text centered and contained in box */
1288 getbbox(obj, &lx, &ux, &ly, &uy);
1289 if (us_makescreen(&lx, &ly, &ux, &uy, w)) break;
1290 us_writetext(lx, ux, ly, uy, gra, obj->string, obj->textdescript, w, obj->tech);
1291 break;
1292
1293 case CIRCLE: case THICKCIRCLE:
1294 case CIRCLEARC: case THICKCIRCLEARC:
1295 /* must scale the window for best precision when drawing curves */
1296 wsc.screenlx = w->screenlx;
1297 wsc.screenly = w->screenly;
1298 wsc.screenhx = w->screenhx;
1299 wsc.screenhy = w->screenhy;
1300 wsc.uselx = ZUP(w->uselx);
1301 wsc.usely = ZUP(w->usely);
1302 wsc.usehx = ZUP(w->usehx);
1303 wsc.usehy = ZUP(w->usehy);
1304 computewindowscale(&wsc);
1305
1306 /* code cannot be called by multiple procesors: uses globals */
1307 NOT_REENTRANT;
1308
1309 /* get copy polygon */
1310 (void)needstaticpolygon(&objc, obj->count, us_tool->cluster);
1311
1312 /* transform and copy the polygon */
1313 objc->count = obj->count;
1314 objc->style = obj->style;
1315 for(i=0; i<obj->count; i++)
1316 {
1317 objc->xv[i] = applyxscale(&wsc, obj->xv[i]-wsc.screenlx) + wsc.uselx;
1318 objc->yv[i] = applyyscale(&wsc, obj->yv[i]-wsc.screenly) + wsc.usely;
1319 }
1320
1321 /* clip the circle */
1322 cliparc(objc, wsc.uselx, wsc.usehx, wsc.usely, wsc.usehy);
1323
1324 /* circle outline at [0] radius to [1] */
1325 switch (objc->style)
1326 {
1327 case CIRCLE:
1328 if (objc->count != 2) break;
1329 six = applyxscale(w, obj->xv[1]-obj->xv[0]);
1330 siy = applyxscale(w, obj->yv[1]-obj->yv[0]);
1331 rad = computedistance(0, 0, six, siy);
1332 screendrawcircle(w, ZDN(objc->xv[0]), ZDN(objc->yv[0]), rad, gra);
1333 break;
1334 case THICKCIRCLE:
1335 if (objc->count != 2) break;
1336 six = applyxscale(w, obj->xv[1]-obj->xv[0]);
1337 siy = applyxscale(w, obj->yv[1]-obj->yv[0]);
1338 rad = computedistance(0, 0, six, siy);
1339 screendrawthickcircle(w, ZDN(objc->xv[0]), ZDN(objc->yv[0]), rad, gra);
1340 break;
1341 case CIRCLEARC:
1342 /* thin arcs at [i] points [1+i] [2+i] clockwise */
1343 if (objc->count == 0) break;
1344 if ((objc->count%3) != 0) break;
1345 for (i=0; i<objc->count; i += 3)
1346 screendrawcirclearc(w, ZDN(objc->xv[i]), ZDN(objc->yv[i]), ZDN(objc->xv[i+1]),
1347 ZDN(objc->yv[1+i]), ZDN(objc->xv[i+2]), ZDN(objc->yv[i+2]), gra);
1348 break;
1349 case THICKCIRCLEARC:
1350 /* thick arcs at [i] points [1+i] [2+i] clockwise */
1351 if (objc->count == 0) break;
1352 if ((objc->count%3) != 0) break;
1353 for (i=0; i<objc->count; i += 3)
1354 screendrawthickcirclearc(w, ZDN(objc->xv[i]), ZDN(objc->yv[i]), ZDN(objc->xv[i+1]),
1355 ZDN(objc->yv[1+i]), ZDN(objc->xv[i+2]), ZDN(objc->yv[i+2]), gra);
1356 }
1357 break;
1358
1359 case DISC:
1360 /* filled circle at [0] radius to [1] */
1361 if (obj->count != 2) break;
1362 cx = applyxscale(w, obj->xv[0]-w->screenlx) + w->uselx;
1363 cy = applyyscale(w, obj->yv[0]-w->screenly) + w->usely;
1364 six = applyxscale(w, obj->xv[1]-obj->xv[0]);
1365 siy = applyxscale(w, obj->yv[1]-obj->yv[0]);
1366 rad = computedistance(0, 0, six, siy);
1367 if (rad == 0) break;
1368
1369 /* clip if completely off screen */
1370 if (cx + rad < w->uselx || cx - rad > w->usehx ||
1371 cy + rad < w->usely || cy - rad > w->usehy)
1372 break;
1373 screendrawdisc(w, cx, cy, rad, gra);
1374 break;
1375 }
1376
1377 /* transform from space of this window */
1378 if ((w->state&INPLACEEDIT) != 0) xformpoly(obj, w->intocell);
1379 }
1380
1381 /*
1382 * routine to clip and possibly draw a line from (fx,fy) to (tx,ty) in
1383 * window "w" with description "desc", texture "texture"
1384 */
us_wanttodraw(INTBIG fx,INTBIG fy,INTBIG tx,INTBIG ty,WINDOWPART * w,GRAPHICS * desc,INTBIG texture)1385 void us_wanttodraw(INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty, WINDOWPART *w, GRAPHICS *desc,
1386 INTBIG texture)
1387 {
1388 fx = applyxscale(w, fx-w->screenlx) + w->uselx;
1389 fy = applyyscale(w, fy-w->screenly) + w->usely;
1390 tx = applyxscale(w, tx-w->screenlx) + w->uselx;
1391 ty = applyyscale(w, ty-w->screenly) + w->usely;
1392 if (clipline(&fx, &fy, &tx, &ty, w->uselx, w->usehx, w->usely, w->usehy)) return;
1393 screendrawline(w, fx, fy, tx, ty, desc, texture);
1394 }
1395
1396 /*
1397 * routine to clip and possibly draw a line from (fx,fy) to (tx,ty) in
1398 * window "w" with description "desc", texture "texture"
1399 */
us_wanttodrawo(INTBIG fx,INTBIG fxo,INTBIG fy,INTBIG fyo,INTBIG tx,INTBIG txo,INTBIG ty,INTBIG tyo,WINDOWPART * w,GRAPHICS * desc,INTBIG texture)1400 void us_wanttodrawo(INTBIG fx, INTBIG fxo, INTBIG fy, INTBIG fyo, INTBIG tx, INTBIG txo,
1401 INTBIG ty, INTBIG tyo, WINDOWPART *w, GRAPHICS *desc, INTBIG texture)
1402 {
1403 fx = applyxscale(w, fx-w->screenlx) + w->uselx + fxo;
1404 fy = applyyscale(w, fy-w->screenly) + w->usely + fyo;
1405 tx = applyxscale(w, tx-w->screenlx) + w->uselx + txo;
1406 ty = applyyscale(w, ty-w->screenly) + w->usely + tyo;
1407 if (clipline(&fx, &fy, &tx, &ty, w->uselx, w->usehx, w->usely, w->usehy)) return;
1408 screendrawline(w, fx, fy, tx, ty, desc, texture);
1409 }
1410
1411 /*
1412 * routine to draw an opened polygon full of lines, set out by 1 pixel. The polygon is in "obj".
1413 */
us_drawextendedpolyline(POLYGON * obj,WINDOWPART * w)1414 void us_drawextendedpolyline(POLYGON *obj, WINDOWPART *w)
1415 {
1416 REGISTER INTBIG i;
1417 REGISTER INTBIG x1, y1, x2, y2, x1o, y1o, x2o, y2o, centerx, centery, diff;
1418 INTBIG lx, hx, ly, hy;
1419
1420 /* if polygon is a line, extension is easy */
1421 if (isbox(obj, &lx, &hx, &ly, &hy))
1422 {
1423 if (lx == hx)
1424 {
1425 us_wanttodrawo(lx, -1, ly, 0, lx, -1, hy, 0, w, obj->desc, 0);
1426 us_wanttodrawo(lx, 1, ly, 0, lx, 1, hy, 0, w, obj->desc, 0);
1427 return;
1428 }
1429 if (ly == hy)
1430 {
1431 us_wanttodrawo(lx, -1, ly, 0, hx, -1, ly, 0, w, obj->desc, 0);
1432 us_wanttodrawo(lx, 1, ly, 0, hx, 1, ly, 0, w, obj->desc, 0);
1433 return;
1434 }
1435 }
1436
1437 if (obj->count == 3 && obj->xv[0] == obj->xv[2] && obj->yv[0] == obj->yv[2])
1438 {
1439 x1 = obj->xv[0]; y1 = obj->yv[0];
1440 x2 = obj->xv[1]; y2 = obj->yv[1];
1441 if (x1 == x2)
1442 {
1443 us_wanttodrawo(x1,-1, y1, 0, x2,-1, y2, 0, w, obj->desc, 0);
1444 us_wanttodrawo(x1, 1, y1, 0, x2, 1, y2, 0, w, obj->desc, 0);
1445 return;
1446 }
1447 if (y1 == y2)
1448 {
1449 us_wanttodrawo(x1, 0, y1,-1, x2, 0, y2,-1, w, obj->desc, 0);
1450 us_wanttodrawo(x1, 0, y1,1, x2, 0, y2, 1, w, obj->desc, 0);
1451 return;
1452 }
1453 if ((x1-x2) * (y1-y2) > 0)
1454 {
1455 us_wanttodrawo(x1,1, y1,-1, x2,1, y2,-1, w, obj->desc, 0);
1456 us_wanttodrawo(x1,-1, y1,1, x2,-1, y2,1, w, obj->desc, 0);
1457 } else
1458 {
1459 us_wanttodrawo(x1,1, y1,1, x2,1, y2,1, w, obj->desc, 0);
1460 us_wanttodrawo(x1,-1, y1,-1, x2,-1, y2,-1, w, obj->desc, 0);
1461 }
1462 return;
1463 }
1464
1465 /* do extension about polygon (and see if the polygon is a single point) */
1466 centerx = centery = diff = 0;
1467 for(i=0; i<obj->count; i++)
1468 {
1469 centerx += obj->xv[i]; centery += obj->yv[i];
1470 if (obj->xv[i] != obj->xv[0]) diff++;
1471 if (obj->yv[i] != obj->yv[0]) diff++;
1472 }
1473 centerx /= obj->count; centery /= obj->count;
1474
1475 /* special case if a single point */
1476 if (diff == 0)
1477 {
1478 us_wanttodrawo(centerx, -1, centery, -1, centerx, 1, centery, -1, w, obj->desc, 0);
1479 us_wanttodrawo(centerx, 1, centery, -1, centerx, 1, centery, 1, w, obj->desc, 0);
1480 us_wanttodrawo(centerx, 1, centery, 1, centerx, -1, centery, 1, w, obj->desc, 0);
1481 us_wanttodrawo(centerx, -1, centery, 1, centerx, -1, centery, -1, w, obj->desc, 0);
1482 return;
1483 }
1484
1485 for(i=1; i<obj->count; i++)
1486 {
1487 x1 = obj->xv[i-1]; y1 = obj->yv[i-1];
1488 x2 = obj->xv[i]; y2 = obj->yv[i];
1489 if (x1 < centerx) x1o = -1; else
1490 if (x1 > centerx) x1o = 1; else x1o = 0;
1491 if (y1 < centery) y1o = -1; else
1492 if (y1 > centery) y1o = 1; else y1o = 0;
1493 if (x2 < centerx) x2o = -1; else
1494 if (x2 > centerx) x2o = 1; else x2o = 0;
1495 if (y2 < centery) y2o = -1; else
1496 if (y2 > centery) y2o = 1; else y2o = 0;
1497 us_wanttodrawo(x1, x1o, y1, y1o, x2, x2o, y2, y2o, w, obj->desc,
1498 0);
1499 }
1500 }
1501
1502 /*
1503 * Write text in a box. The box ranges from "lx" to "ux" in X and
1504 * from "ly" to "uy" in Y. Draw in bit planes "desc->bits" with color
1505 * "desc->color". Put "txt" there (or as much as will fit). The value of
1506 * "initialfont" is the default size of text which will be reduced until it
1507 * can fit.
1508 */
us_writetext(INTBIG lx,INTBIG ux,INTBIG ly,INTBIG uy,GRAPHICS * desc,CHAR * txt,UINTBIG * initdescript,WINDOWPART * win,TECHNOLOGY * tech)1509 void us_writetext(INTBIG lx, INTBIG ux, INTBIG ly, INTBIG uy, GRAPHICS *desc, CHAR *txt,
1510 UINTBIG *initdescript, WINDOWPART *win, TECHNOLOGY *tech)
1511 {
1512 REGISTER INTBIG stop, save, xabssize, yabssize, abssize, newsize, oldsize;
1513 INTBIG six, siy;
1514 UINTBIG descript[TEXTDESCRIPTSIZE];
1515
1516 /* scan for a font that fits */
1517 TDCOPY(descript, initdescript);
1518 for(;;)
1519 {
1520 screensettextinfo(win, tech, descript);
1521 screengettextsize(win, txt, &six, &siy);
1522 if (six <= ux-lx && siy <= uy-ly) break;
1523
1524 oldsize = TDGETSIZE(descript);
1525 abssize = TXTGETPOINTS(oldsize);
1526 if (abssize != 0)
1527 {
1528 /* jump quickly to the proper font size */
1529 if (six <= ux-lx) xabssize = abssize; else
1530 xabssize = abssize * (ux-lx) / six;
1531 if (siy <= uy-ly) yabssize = abssize; else
1532 yabssize = abssize * (uy-ly) / siy;
1533 newsize = mini(xabssize, yabssize);
1534 if (newsize < 4) return;
1535 TDSETSIZE(descript, TXTSETPOINTS(newsize));
1536 } else
1537 {
1538 newsize = TXTGETQLAMBDA(TDGETSIZE(descript)) - 1;
1539 if (newsize <= 0) return;
1540 TDSETSIZE(descript, TXTSETQLAMBDA(newsize));
1541 }
1542 }
1543
1544 /* if the text doesn't fit in Y, quit */
1545 if (siy > uy-ly) return;
1546
1547 /* truncate in X if possible */
1548 if (six > ux-lx)
1549 {
1550 stop = (ux-lx) * estrlen(txt);
1551 stop /= six;
1552 if (stop == 0) return;
1553 save = txt[stop]; txt[stop] = 0;
1554 screengettextsize(win, txt, &six, &siy);
1555 } else stop = -1;
1556
1557 /* draw the text */
1558 screendrawtext(win, lx+(ux-lx-six)/2, ly+(uy-ly-siy)/2, txt, desc);
1559 if (stop >= 0) txt[stop] = (CHAR)save;
1560 }
1561
1562 /******************** WINDOW PANNING ********************/
1563
1564 /*
1565 * routine to slide the contents of the current window up by "dist" lambda
1566 * units (slides down if "dist" is negative)
1567 */
us_slideup(INTBIG dist)1568 void us_slideup(INTBIG dist)
1569 {
1570 /* save and erase highlighting */
1571 us_pushhighlight();
1572 us_clearhighlightcount();
1573
1574 /* set the new window data */
1575 startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
1576 (void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenly"), el_curwindowpart->screenly - dist, VINTEGER);
1577 (void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhy"), el_curwindowpart->screenhy - dist, VINTEGER);
1578 endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
1579
1580 /* restore highlighting */
1581 us_pophighlight(FALSE);
1582 }
1583
1584 /*
1585 * routine to slide the current window left by "dist" lambda units
1586 * (slides right if "dist" is negative)
1587 */
us_slideleft(INTBIG dist)1588 void us_slideleft(INTBIG dist)
1589 {
1590 /* save and erase highlighting */
1591 us_pushhighlight();
1592 us_clearhighlightcount();
1593
1594 startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
1595 (void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenlx"), el_curwindowpart->screenlx + dist, VINTEGER);
1596 (void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("screenhx"), el_curwindowpart->screenhx + dist, VINTEGER);
1597 endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
1598
1599 /* restore highlighting */
1600 us_pophighlight(FALSE);
1601 }
1602
1603 /******************** TRANSFORMATION TO SCREEN ********************/
1604
1605 /*
1606 * routine to convert the reference parameters (lx,ux, ly,uy)
1607 * which define a box to screen co-ordinates ready to plot.
1608 * The values are scaled to screen space of window "w" and clipped.
1609 * If the routine returns true, the box is all off the screen.
1610 */
us_makescreen(INTBIG * lx,INTBIG * ly,INTBIG * ux,INTBIG * uy,WINDOWPART * w)1611 BOOLEAN us_makescreen(INTBIG *lx, INTBIG *ly, INTBIG *ux, INTBIG *uy, WINDOWPART *w)
1612 {
1613 /* transform to screen space */
1614 if (*ux < w->screenlx || *lx > w->screenhx) return(TRUE);
1615 if (*uy < w->screenly || *ly > w->screenhy) return(TRUE);
1616 *lx = applyxscale(w, *lx-w->screenlx) + w->uselx;
1617 *ly = applyyscale(w, *ly-w->screenly) + w->usely;
1618 *ux = applyxscale(w, *ux-w->screenlx) + w->uselx;
1619 *uy = applyyscale(w, *uy-w->screenly) + w->usely;
1620
1621 /* now clip to screen bounds */
1622 if (*lx < w->uselx) *lx = w->uselx;
1623 if (*ly < w->usely) *ly = w->usely;
1624 if (*ux > w->usehx) *ux = w->usehx;
1625 if (*uy > w->usehy) *uy = w->usehy;
1626 return(FALSE);
1627 }
1628
1629 /******************** 3D DISPLAY ********************/
1630
1631 /*
1632 * Routine to setup the transformation matrix for 3D viewing.
1633 * Called once when the display is initially converted to 3D.
1634 */
us_3dsetupviewing(WINDOWPART * w)1635 void us_3dsetupviewing(WINDOWPART *w)
1636 {
1637 REGISTER TECHNOLOGY *tech;
1638 REGISTER INTBIG i, lambda;
1639 float thickness, height, lowheight, highheight, scale, cx, cy, cz, sx, sy, sz;
1640 REGISTER NODEPROTO *np;
1641 REGISTER XFORM3D *xf3;
1642
1643 /* determine height range */
1644 lowheight = 0.0; highheight = -1.0;
1645 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
1646 {
1647 for(i=0; i<tech->layercount; i++)
1648 {
1649 if (get3dfactors(tech, i, &height, &thickness)) continue;
1650 if (highheight < lowheight)
1651 {
1652 highheight = lowheight = height;
1653 } else
1654 {
1655 if (height < lowheight) lowheight = height;
1656 if (height > highheight) highheight = height;
1657 }
1658 }
1659 }
1660
1661 /* setup initial camera */
1662 np = w->curnodeproto;
1663 if (np == NONODEPROTO) return;
1664 cx = (np->lowx + np->highx) / 2.0f;
1665 cy = (np->lowy + np->highy) / 2.0f;
1666 lambda = el_curlib->lambda[el_curtech->techindex];
1667 cz = (highheight + lowheight) / 2.0f * lambda;
1668 sx = (float)(np->highx - np->lowx);
1669 sy = (float)(np->highy - np->lowy);
1670 sz = (highheight - lowheight) * lambda;
1671 scale = (sx > sy) ? sx : sy;
1672 scale = (sz > scale) ? sz : scale;
1673
1674 /* setup viewing parameters */
1675 xf3 = &w->xf3;
1676 xf3->fieldofview = 45.0f;
1677 xf3->eye[0] = -0.2f; xf3->eye[1] = 0.2f; xf3->eye[2] = 1.0f;
1678 vectornormalize3d(xf3->eye);
1679 vectormultiply3d(xf3->eye, scale, xf3->eye);
1680 xf3->eye[0] += cx; xf3->eye[1] += cy; xf3->eye[2] += cz;
1681 xf3->view[0] = cx; xf3->view[1] = cy; xf3->view[2] = cz;
1682 xf3->up[0] = 0.0; xf3->up[1] = 1.0; xf3->up[2] = 0.0;
1683 xf3->nearplane = 0.1f; xf3->farplane = scale * 60.0f;
1684 xf3->screenx = (float)(w->usehx - w->uselx) / 2.0f;
1685 xf3->screeny = (float)(w->usehy - w->usely) / 2.0f;
1686 xf3->aspect = xf3->screenx / xf3->screeny;
1687 us_3dbuildtransform(xf3);
1688 }
1689
1690 /*
1691 * Routine to fill window "win".
1692 */
us_3dfillview(WINDOWPART * win)1693 void us_3dfillview(WINDOWPART *win)
1694 {
1695 XFORM3D *xf3;
1696 float sx, sy, sz, maxs, toeye[3];
1697
1698 xf3 = &win->xf3;
1699
1700 sx = us_3dhighx - us_3dlowx;
1701 sy = us_3dhighy - us_3dlowy;
1702 sz = us_3dhighz - us_3dlowz;
1703 maxs = (sx > sy) ? sx : sy;
1704 maxs = (sz > maxs) ? sz : maxs;
1705
1706 xf3->fieldofview = 45.0f;
1707 vectorsubtract3d(xf3->eye, xf3->view, toeye);
1708 xf3->view[0] = us_3dcenterx; xf3->view[1] = us_3dcentery; xf3->view[2] = us_3dcenterz;
1709 vectoradd3d(xf3->view, toeye, xf3->eye);
1710 xf3->nearplane = 0.1f;
1711 xf3->farplane = maxs * 60.0f;
1712
1713 us_3dbuildtransform(xf3);
1714 us_3drender(win);
1715 }
1716
1717 /*
1718 * Routine to zoom window "win" by a factor of "z".
1719 */
us_3dzoomview(WINDOWPART * win,float z)1720 void us_3dzoomview(WINDOWPART *win, float z)
1721 {
1722 XFORM3D *xf3;
1723
1724 xf3 = &win->xf3;
1725 xf3->fieldofview = xf3->fieldofview * z;
1726 if (xf3->fieldofview > FOVMAX) xf3->fieldofview = FOVMAX;
1727 if (xf3->fieldofview < FOVMIN) xf3->fieldofview = FOVMIN;
1728 us_3dbuildtransform(xf3);
1729 us_3drender(win);
1730 }
1731
1732 /*
1733 * Routine to pan window "win" by a factor of "x,y".
1734 */
us_3dpanview(WINDOWPART * win,INTBIG x,INTBIG y)1735 void us_3dpanview(WINDOWPART *win, INTBIG x, INTBIG y)
1736 {
1737 XFORM3D *xf3;
1738 float d[3], side[3], up[3], view[3], scale, e[3], offset[3];
1739
1740 xf3 = &win->xf3;
1741 vectorsubtract3d(xf3->view, xf3->eye, d);
1742 vectorcross3d(d, xf3->up, side);
1743 vectorcross3d(d, side, up);
1744 vectornormalize3d(side);
1745 vectornormalize3d(up);
1746 vectorsubtract3d(xf3->view, xf3->eye, view);
1747 scale = vectormagnitude3d(view);
1748 vectormultiply3d(side, scale * 0.1f * (float)x, d);
1749 vectormultiply3d(up, scale * 0.1f * (float)y, e);
1750 vectoradd3d(d, e, offset);
1751 vectoradd3d(xf3->eye, offset, xf3->eye);
1752 vectoradd3d(xf3->view, offset, xf3->view);
1753
1754 us_3dbuildtransform(xf3);
1755 us_3drender(win);
1756 }
1757
1758 /*
1759 * Routine to build the 4x4 transformation matrix in "xf3" from
1760 * the viewing parameters there.
1761 */
us_3dbuildtransform(XFORM3D * xf3)1762 void us_3dbuildtransform(XFORM3D *xf3)
1763 {
1764 float f[3], s[3], u[3], persp[4][4], xform[4][4], trans[4][4], rot[4][4], ff;
1765
1766 /* build the perspective transform */
1767 matrixid3d(persp);
1768 if ((us_useroptions&NO3DPERSPECTIVE) == 0)
1769 {
1770 ff = 1.0f / (float)tan((xf3->fieldofview * EPI / 180.0f) / 2.0f);
1771 persp[0][0] = ff / xf3->aspect;
1772 persp[1][1] = ff;
1773 persp[2][2] = (xf3->farplane + xf3->nearplane) / (xf3->nearplane - xf3->farplane);
1774 persp[2][3] = 2.0f * xf3->farplane * xf3->nearplane / (xf3->nearplane - xf3->farplane);
1775 persp[3][2] = -1.0f;
1776 persp[3][3] = 0.0f;
1777 } else
1778 {
1779 persp[0][0] = 45.0f / xf3->fieldofview;
1780 persp[1][1] = 45.0f / xf3->fieldofview;
1781 persp[2][2] = -1.0;
1782 }
1783
1784 /* build the viewing transform */
1785 matrixid3d(trans);
1786 trans[0][3] = -xf3->eye[0];
1787 trans[1][3] = -xf3->eye[1];
1788 trans[2][3] = -xf3->eye[2];
1789
1790 vectorsubtract3d(xf3->view, xf3->eye, f);
1791 vectornormalize3d(f);
1792 vectornormalize3d(xf3->up);
1793 vectorcross3d(f, xf3->up, s);
1794 vectorcross3d(s, f, u);
1795 matrixid3d(rot);
1796 rot[0][0] = s[0]; rot[0][1] = s[1]; rot[0][2] = s[2];
1797 rot[1][0] = u[0]; rot[1][1] = u[1]; rot[1][2] = u[2];
1798 rot[2][0] = -f[0]; rot[2][1] = -f[1]; rot[2][2] = -f[2];
1799 matrixmult3d(trans, rot, xform);
1800
1801 /* build the transformation matrix */
1802 matrixmult3d(xform, persp, xf3->xform);
1803 }
1804
1805 /*
1806 * Routine called at the start of drawing.
1807 */
us_3dstartdrawing(WINDOWPART * win)1808 void us_3dstartdrawing(WINDOWPART *win)
1809 {
1810 us_3dgatheringpolys = TRUE;
1811 us_3dpolycount = 0;
1812 us_3dwindowpart = win;
1813 }
1814
1815 /*
1816 * Helper routine for "us_3denddrawing()" that makes polygon depth go in ascending order
1817 */
us_3dpolydepthascending(const void * e1,const void * e2)1818 int us_3dpolydepthascending(const void *e1, const void *e2)
1819 {
1820 REGISTER POLY3D *c1, *c2;
1821 REGISTER float diff;
1822
1823 c1 = *((POLY3D **)e1);
1824 c2 = *((POLY3D **)e2);
1825 diff = c1->depth - c2->depth;
1826 if (diff < 0.0) return(-1);
1827 if (diff > 0.0) return(1);
1828 return(0);
1829 }
1830
1831 /*
1832 * Routine called at the end of drawing.
1833 */
us_3denddrawing(void)1834 void us_3denddrawing(void)
1835 {
1836 REGISTER POLY3D *poly1;
1837 REGISTER INTBIG i, j;
1838
1839 /* flush the opaque graphics out */
1840 us_endchanges(NOWINDOWPART);
1841 us_3dgatheringpolys = FALSE;
1842
1843 /* sort the polygons */
1844 esort(us_3dpolylist, us_3dpolycount, sizeof (POLY3D *), us_3dpolydepthascending);
1845
1846 /* determine bounding volume */
1847 for(i=0; i<us_3dpolycount; i++)
1848 {
1849 poly1 = us_3dpolylist[i];
1850 for(j=0; j<poly1->count; j++)
1851 {
1852 if (i == 0 && j == 0)
1853 {
1854 us_3dlowx = us_3dhighx = poly1->x[j];
1855 us_3dlowy = us_3dhighy = poly1->y[j];
1856 us_3dlowz = us_3dhighz = poly1->z[j];
1857 } else
1858 {
1859 if (poly1->x[j] < us_3dlowx) us_3dlowx = poly1->x[j];
1860 if (poly1->x[j] > us_3dhighx) us_3dhighx = poly1->x[j];
1861 if (poly1->y[j] < us_3dlowy) us_3dlowy = poly1->y[j];
1862 if (poly1->y[j] > us_3dhighy) us_3dhighy = poly1->y[j];
1863 if (poly1->z[j] < us_3dlowz) us_3dlowz = poly1->z[j];
1864 if (poly1->z[j] > us_3dhighz) us_3dhighz = poly1->z[j];
1865 }
1866 }
1867 }
1868 us_3dcenterx = (us_3dlowx + us_3dhighx) / 2.0f;
1869 us_3dcentery = (us_3dlowy + us_3dhighy) / 2.0f;
1870 us_3dcenterz = (us_3dlowz + us_3dhighz) / 2.0f;
1871
1872 /* render it */
1873 us_3dbuildtransform(&us_3dwindowpart->xf3);
1874 us_3drender(us_3dwindowpart);
1875 }
1876
1877 /*
1878 * Routine to re-render the polygons to window "w".
1879 */
us_3drender(WINDOWPART * w)1880 void us_3drender(WINDOWPART *w)
1881 {
1882 REGISTER INTBIG i, j, k, passes, lambda;
1883 INTBIG start[2], finish[2], incr[2];
1884 REGISTER INTBIG save, isneg;
1885 POLY3D *poly3d;
1886 float vec[4], res[4], res2[4];
1887 float zplane, res3[4];
1888 static POLYGON *poly = NOPOLYGON;
1889 REGISTER XFORM3D *xf3;
1890
1891 xf3 = &w->xf3;
1892 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
1893
1894 /* clear the screen */
1895 us_erasewindow(w);
1896
1897 /* see if the view is from the back */
1898 lambda = el_curlib->lambda[el_curtech->techindex];
1899 for(zplane = us_3dhighz; zplane >= us_3dlowz; zplane -= lambda)
1900 {
1901 vec[0] = us_3dcenterx; vec[1] = us_3dcentery; vec[2] = zplane; vec[3] = 1.0;
1902 matrixxform3d(vec, xf3->xform, res);
1903 vec[0] = us_3dcenterx+1000.0f; vec[1] = us_3dcentery; vec[2] = zplane; vec[3] = 1.0;
1904 matrixxform3d(vec, xf3->xform, res2);
1905 vec[0] = us_3dcenterx; vec[1] = us_3dcentery+1000.0f; vec[2] = zplane; vec[3] = 1.0;
1906 matrixxform3d(vec, xf3->xform, res3);
1907 res[0] /= res[3]; res[1] /= res[3]; res[2] /= res[3];
1908 res2[0] /= res2[3]; res2[1] /= res2[3]; res2[2] /= res2[3];
1909 res3[0] /= res3[3]; res3[1] /= res3[3]; res3[2] /= res3[3];
1910 vectorsubtract3d(res2, res, res2);
1911 vectorsubtract3d(res3, res, res3);
1912 vectorcross3d(res2, res3, res);
1913 if (res[2] > 0) break;
1914 }
1915 if (zplane == us_3dhighz)
1916 {
1917 start[0] = 0; finish[0] = us_3dpolycount; incr[0] = 1;
1918 passes = 1;
1919 } else if (zplane < us_3dlowz)
1920 {
1921 start[0] = us_3dpolycount-1; finish[0] = -1; incr[0] = -1;
1922 passes = 1;
1923 } else
1924 {
1925 for(i=0; i<us_3dpolycount; i++)
1926 if (us_3dpolylist[i]->depth > zplane) break;
1927 start[0] = 0; finish[0] = i; incr[0] = 1;
1928 start[1] = us_3dpolycount-1; finish[1] = i-1; incr[1] = -1;
1929 passes = 2;
1930 }
1931
1932 /* now draw it all */
1933 for(k=0; k<passes; k++)
1934 {
1935 for(i=start[k]; i != finish[k]; i = i + incr[k])
1936 {
1937 poly3d = us_3dpolylist[i];
1938 if (poly->limit < poly3d->count) (void)extendpolygon(poly, poly3d->count);
1939 isneg = 0;
1940 for(j=0; j<poly3d->count; j++)
1941 {
1942 vec[0] = poly3d->x[j];
1943 vec[1] = poly3d->y[j];
1944 vec[2] = poly3d->z[j];
1945 vec[3] = 1.0;
1946 matrixxform3d(vec, xf3->xform, res);
1947 if (res[2] < 0.0)
1948 {
1949 isneg = 1;
1950 break;
1951 }
1952 poly->xv[j] = (INTBIG)(res[0] / res[3] / 2.0 * xf3->screenx + xf3->screenx);
1953 poly->yv[j] = (INTBIG)(res[1] / res[3] / 2.0 * xf3->screeny + xf3->screeny);
1954 poly->xv[j] = roundfloat((poly->xv[j] - w->uselx) / w->scalex) + w->screenlx;
1955 poly->yv[j] = roundfloat((poly->yv[j] - w->usely) / w->scaley) + w->screenly;
1956 }
1957 if (isneg != 0) continue;
1958 poly->desc = poly3d->desc;
1959 poly->count = poly3d->count;
1960 poly->style = FILLED;
1961 save = poly3d->desc->bits;
1962 poly3d->desc->bits = LAYERA;
1963 (*us_displayroutine)(poly, w);
1964 poly3d->desc->bits = save;
1965 }
1966 }
1967 }
1968
us_3dsetinteraction(INTBIG interaction)1969 void us_3dsetinteraction(INTBIG interaction)
1970 {
1971 switch (interaction)
1972 {
1973 case 0: us_3dinteraction = ROTATEVIEW; break;
1974 case 1: us_3dinteraction = ZOOMVIEW; break;
1975 case 2: us_3dinteraction = PANVIEW; break;
1976 case 3: us_3dinteraction = TWISTVIEW; break;
1977 }
1978 }
1979
1980 /*
1981 * button handler for 3D windows
1982 */
us_3dbuttonhandler(WINDOWPART * w,INTBIG but,INTBIG x,INTBIG y)1983 void us_3dbuttonhandler(WINDOWPART *w, INTBIG but, INTBIG x, INTBIG y)
1984 {
1985 REGISTER XFORM3D *xf3;
1986
1987 /* changes to the mouse-wheel are handled by the user interface */
1988 if (wheelbutton(but))
1989 {
1990 us_buttonhandler(w, but, x, y);
1991 return;
1992 }
1993 xf3 = &w->xf3;
1994 us_3dlastbutx = x;
1995 us_3dlastbuty = us_3dinitialbuty = y;
1996 switch (us_3dinteraction)
1997 {
1998 case ROTATEVIEW:
1999 break;
2000 case ZOOMVIEW:
2001 us_3dinitialfov = xf3->fieldofview;
2002 break;
2003 case PANVIEW:
2004 break;
2005 case TWISTVIEW:
2006 break;
2007 }
2008 trackcursor(FALSE, us_nullup, us_nullvoid, us_3deachdown, us_nullchar, us_nullvoid, TRACKNORMAL);
2009 }
2010
us_3deachdown(INTBIG x,INTBIG y)2011 BOOLEAN us_3deachdown(INTBIG x, INTBIG y)
2012 {
2013 float d[3], e[3], offset[3], side[3], up[3], view[3], scale;
2014 float angle, sinTheta, cosTheta, toDirection[3], tempVector1[3], tempVector2[3],
2015 tempVector3[3], rotateVector[3], toLength, newFrom[3], sinPhi, cosPhi,
2016 newToDirection[3], rightDirection[3], dot, lastangle, cx, cy;
2017 REGISTER XFORM3D *xf3;
2018
2019 xf3 = &us_3dwindowpart->xf3;
2020 switch (us_3dinteraction)
2021 {
2022 case ROTATEVIEW:
2023 if (x == us_3dlastbutx && y == us_3dlastbuty) break;
2024
2025 vectorsubtract3d(xf3->eye, xf3->view, toDirection);
2026 toLength = vectormagnitude3d(toDirection);
2027 vectornormalize3d(toDirection);
2028
2029 /* Calculate orthonormal up direction by Gram-Schmidt orthogonalization */
2030 dot = vectordot3d(xf3->up, toDirection);
2031 up[0] = xf3->up[0] - dot * toDirection[0];
2032 up[1] = xf3->up[1] - dot * toDirection[1];
2033 up[2] = xf3->up[2] - dot * toDirection[2];
2034
2035 /* orthonormal up vector vector */
2036 vectornormalize3d(up);
2037
2038 /* Calculate orthonormal right vector to make up an orthonormal view frame */
2039 vectorcross3d(up, toDirection, rightDirection);
2040
2041 angle = (float)(180.0f * ((float)(us_3dlastbuty - y) /
2042 (float)(us_3dwindowpart->usehy-us_3dwindowpart->usely)/2.0f) * EPI / 180.0f);
2043 sinTheta = (float)sin(angle);
2044 cosTheta = (float)cos(angle);
2045 vectormultiply3d(toDirection, cosTheta, tempVector1);
2046 vectormultiply3d(xf3->up, sinTheta, tempVector2);
2047 vectoradd3d(tempVector1, tempVector2, rotateVector);
2048 vectormultiply3d(rotateVector, toLength, rotateVector);
2049 vectoradd3d(xf3->view, rotateVector, newFrom);
2050
2051 /* rotate using RIGHT and new TO directions and X position of mouse */
2052 angle = (float)(180.0f * ((float)(us_3dlastbutx - x) /
2053 (float)(us_3dwindowpart->usehx-us_3dwindowpart->uselx)/2.0f) * EPI/180.0f);
2054 sinPhi = (float)sin(angle);
2055 cosPhi = (float)cos(angle);
2056 vectorsubtract3d(newFrom, xf3->view, newToDirection);
2057 vectornormalize3d(newToDirection);
2058 vectormultiply3d(newToDirection, cosPhi, tempVector1);
2059 vectormultiply3d(rightDirection, sinPhi, tempVector2);
2060 vectoradd3d(tempVector1, tempVector2, rotateVector);
2061 vectormultiply3d(rotateVector, toLength, rotateVector);
2062 vectoradd3d(xf3->view, rotateVector, xf3->eye);
2063
2064 /* calculate new UP vector */
2065 vectormultiply3d(xf3->up, cosTheta, tempVector2);
2066 vectormultiply3d(toDirection, -sinTheta*cosPhi, tempVector1);
2067 vectormultiply3d(rightDirection, sinTheta*sinPhi, tempVector3);
2068 vectoradd3d(tempVector1, tempVector2, xf3->up);
2069 vectoradd3d(xf3->up, tempVector3, xf3->up);
2070
2071 us_3dlastbutx = x;
2072 us_3dlastbuty = y;
2073 us_3dbuildtransform(xf3);
2074 us_3drender(us_3dwindowpart);
2075 break;
2076
2077 case ZOOMVIEW:
2078 xf3->fieldofview = us_3dinitialfov + 0.1f * (float)(us_3dinitialbuty - y);
2079 if (xf3->fieldofview > FOVMAX) xf3->fieldofview = FOVMAX;
2080 if (xf3->fieldofview < FOVMIN) xf3->fieldofview = FOVMIN;
2081 us_3dbuildtransform(xf3);
2082 us_3drender(us_3dwindowpart);
2083 break;
2084
2085 case PANVIEW:
2086 if (x == us_3dlastbutx && y == us_3dlastbuty) break;
2087 vectorsubtract3d(xf3->view, xf3->eye, d);
2088 vectorcross3d(d, xf3->up, side);
2089 vectorcross3d(d, side, up);
2090 vectornormalize3d(side);
2091 vectornormalize3d(up);
2092 vectorsubtract3d(xf3->view, xf3->eye, view);
2093 scale = vectormagnitude3d(view);
2094 vectormultiply3d(side, scale * 0.01f * (float)(us_3dlastbutx - x), d);
2095 vectormultiply3d(up, scale * 0.01f * (float)(y - us_3dlastbuty), e);
2096 vectoradd3d(d, e, offset);
2097 vectoradd3d(xf3->eye, offset, xf3->eye);
2098 vectoradd3d(xf3->view, offset, xf3->view);
2099
2100 us_3dbuildtransform(xf3);
2101 us_3drender(us_3dwindowpart);
2102 us_3dlastbutx = x;
2103 us_3dlastbuty = y;
2104 break;
2105
2106 case TWISTVIEW:
2107 if (x == us_3dlastbutx && y == us_3dlastbuty) break;
2108
2109 /* compute angle of twist */
2110 cx = (us_3dwindowpart->usehx+us_3dwindowpart->uselx) / 2.0f;
2111 cy = (us_3dwindowpart->usehy+us_3dwindowpart->usely) / 2.0f;
2112 lastangle = (float)atan2(us_3dlastbuty-cy, us_3dlastbutx-cx);
2113 angle = (float)atan2(y-cy, x-cx);
2114 vectorsubtract3d(xf3->eye, xf3->view, toDirection);
2115 us_3drotatepointaboutaxis(xf3->up, lastangle-angle, toDirection, tempVector1);
2116 xf3->up[0] = tempVector1[0];
2117 xf3->up[1] = tempVector1[1];
2118 xf3->up[2] = tempVector1[2];
2119 vectornormalize3d(xf3->up);
2120
2121 us_3dlastbutx = x;
2122 us_3dlastbuty = y;
2123 us_3dbuildtransform(xf3);
2124 us_3drender(us_3dwindowpart);
2125 break;
2126 }
2127 return(FALSE);
2128 }
2129
2130 /*
2131 * Rotate a point "p" by angle "theta" around an arbitrary axis "r", returning point "q".
2132 */
us_3drotatepointaboutaxis(float * p,float theta,float * r,float * q)2133 void us_3drotatepointaboutaxis(float *p, float theta, float *r, float *q)
2134 {
2135 float costheta, sintheta;
2136
2137 vectornormalize3d(r);
2138 costheta = (float)cos(theta);
2139 sintheta = (float)sin(theta);
2140
2141 q[0] = (costheta + (1.0f - costheta) * r[0] * r[0]) * p[0];
2142 q[0] += ((1.0f - costheta) * r[0] * r[1] - r[2] * sintheta) * p[1];
2143 q[0] += ((1.0f - costheta) * r[0] * r[2] + r[1] * sintheta) * p[2];
2144
2145 q[1] = ((1.0f - costheta) * r[0] * r[1] + r[2] * sintheta) * p[0];
2146 q[1] += (costheta + (1.0f - costheta) * r[1] * r[1]) * p[1];
2147 q[1] += ((1.0f - costheta) * r[1] * r[2] - r[0] * sintheta) * p[2];
2148
2149 q[2] = ((1.0f - costheta) * r[0] * r[2] - r[1] * sintheta) * p[0];
2150 q[2] += ((1.0f - costheta) * r[1] * r[2] + r[0] * sintheta) * p[1];
2151 q[2] += (costheta + (1.0f - costheta) * r[2] * r[2]) * p[2];
2152 }
2153
2154 /*
2155 * Routine to draw polygon "poly" in window "w".
2156 */
us_3dshowpoly(POLYGON * poly,WINDOWPART * w)2157 void us_3dshowpoly(POLYGON *poly, WINDOWPART *w)
2158 {
2159 REGISTER INTBIG i, previ, lambda;
2160 float topheight, botheight;
2161 INTBIG lx, hx, ly, hy;
2162 float thickness, depth, topdepth, botdepth, centerdepth;
2163 REGISTER POLY3D *poly3d;
2164
2165 /* ignore polygons with no color */
2166 if (poly->desc->col == 0) return;
2167
2168 /* special case when drawing instance boundaries */
2169 if (poly->desc->col == el_colcell)
2170 {
2171 (void)get3dfactors(el_curtech, 0, &depth, &thickness);
2172 topdepth = depth;
2173 topheight = topdepth;
2174 if (isbox(poly, &lx, &hx, &ly, &hy))
2175 {
2176 poly3d = us_3dgetnextpoly(2);
2177 if (poly3d == 0) return;
2178 poly3d->x[0] = (float)lx; poly3d->y[0] = (float)ly; poly3d->z[0] = topheight;
2179 poly3d->x[1] = (float)lx; poly3d->y[1] = (float)hy; poly3d->z[1] = topheight;
2180 poly3d->depth = topdepth;
2181 poly3d->desc = poly->desc;
2182
2183 poly3d = us_3dgetnextpoly(2);
2184 if (poly3d == 0) return;
2185 poly3d->x[0] = (float)lx; poly3d->y[0] = (float)hy; poly3d->z[0] = topheight;
2186 poly3d->x[1] = (float)hx; poly3d->y[1] = (float)hy; poly3d->z[1] = topheight;
2187 poly3d->depth = topdepth;
2188 poly3d->desc = poly->desc;
2189
2190 poly3d = us_3dgetnextpoly(2);
2191 if (poly3d == 0) return;
2192 poly3d->x[0] = (float)hx; poly3d->y[0] = (float)hy; poly3d->z[0] = topheight;
2193 poly3d->x[1] = (float)hx; poly3d->y[1] = (float)ly; poly3d->z[1] = topheight;
2194 poly3d->depth = topdepth;
2195 poly3d->desc = poly->desc;
2196
2197 poly3d = us_3dgetnextpoly(2);
2198 if (poly3d == 0) return;
2199 poly3d->x[0] = (float)hx; poly3d->y[0] = (float)ly; poly3d->z[0] = topheight;
2200 poly3d->x[1] = (float)lx; poly3d->y[1] = (float)ly; poly3d->z[1] = topheight;
2201 poly3d->depth = topdepth;
2202 poly3d->desc = poly->desc;
2203 }
2204 return;
2205 }
2206
2207 /* make sure there is a technology and a layer for this polygon */
2208 if (poly->tech == NOTECHNOLOGY) return;
2209 if (get3dfactors(poly->tech, poly->layer, &depth, &thickness)) return;
2210
2211 /* setup a 3D polygon */
2212 lambda = el_curlib->lambda[el_curtech->techindex];
2213 topdepth = (depth + thickness/2.0f) * lambda;
2214 topheight = topdepth;
2215 if (thickness != 0)
2216 {
2217 topdepth++;
2218 centerdepth = depth * lambda;
2219 botdepth = (depth - thickness/2.0f) * lambda - 1;
2220 botheight = (depth - thickness/2.0f) * lambda;
2221 }
2222
2223 /* fill the 3D polygon points */
2224 switch (poly->style)
2225 {
2226 case FILLED: /* filled polygon */
2227 case FILLEDRECT: /* filled rectangle */
2228 case CLOSEDRECT: /* closed rectangle outline */
2229 case CLOSED: /* closed polygon outline */
2230 case CROSSED: /* polygon outline with cross */
2231 if (isbox(poly, &lx, &hx, &ly, &hy))
2232 {
2233 poly3d = us_3dgetnextpoly(4);
2234 if (poly3d == 0) return;
2235 poly3d->x[0] = (float)lx; poly3d->y[0] = (float)ly; poly3d->z[0] = topheight;
2236 poly3d->x[1] = (float)lx; poly3d->y[1] = (float)hy; poly3d->z[1] = topheight;
2237 poly3d->x[2] = (float)hx; poly3d->y[2] = (float)hy; poly3d->z[2] = topheight;
2238 poly3d->x[3] = (float)hx; poly3d->y[3] = (float)ly; poly3d->z[3] = topheight;
2239 poly3d->depth = topdepth;
2240 poly3d->desc = poly->desc;
2241 if (thickness != 0)
2242 {
2243 poly3d = us_3dgetnextpoly(4);
2244 if (poly3d == 0) return;
2245 poly3d->x[0] = (float)lx; poly3d->y[0] = (float)ly; poly3d->z[0] = botheight;
2246 poly3d->x[1] = (float)lx; poly3d->y[1] = (float)hy; poly3d->z[1] = botheight;
2247 poly3d->x[2] = (float)hx; poly3d->y[2] = (float)hy; poly3d->z[2] = botheight;
2248 poly3d->x[3] = (float)hx; poly3d->y[3] = (float)ly; poly3d->z[3] = botheight;
2249 poly3d->depth = botdepth;
2250 poly3d->desc = poly->desc;
2251
2252 poly3d = us_3dgetnextpoly(4);
2253 if (poly3d == 0) return;
2254 poly3d->x[0] = (float)lx; poly3d->y[0] = (float)ly; poly3d->z[0] = topheight;
2255 poly3d->x[1] = (float)lx; poly3d->y[1] = (float)hy; poly3d->z[1] = topheight;
2256 poly3d->x[2] = (float)lx; poly3d->y[2] = (float)hy; poly3d->z[2] = botheight;
2257 poly3d->x[3] = (float)lx; poly3d->y[3] = (float)ly; poly3d->z[3] = botheight;
2258 poly3d->depth = centerdepth;
2259 poly3d->desc = poly->desc;
2260
2261 poly3d = us_3dgetnextpoly(4);
2262 if (poly3d == 0) return;
2263 poly3d->x[0] = (float)lx; poly3d->y[0] = (float)hy; poly3d->z[0] = topheight;
2264 poly3d->x[1] = (float)hx; poly3d->y[1] = (float)hy; poly3d->z[1] = topheight;
2265 poly3d->x[2] = (float)hx; poly3d->y[2] = (float)hy; poly3d->z[2] = botheight;
2266 poly3d->x[3] = (float)lx; poly3d->y[3] = (float)hy; poly3d->z[3] = botheight;
2267 poly3d->depth = centerdepth;
2268 poly3d->desc = poly->desc;
2269
2270 poly3d = us_3dgetnextpoly(4);
2271 if (poly3d == 0) return;
2272 poly3d->x[0] = (float)hx; poly3d->y[0] = (float)hy; poly3d->z[0] = topheight;
2273 poly3d->x[1] = (float)hx; poly3d->y[1] = (float)ly; poly3d->z[1] = topheight;
2274 poly3d->x[2] = (float)hx; poly3d->y[2] = (float)ly; poly3d->z[2] = botheight;
2275 poly3d->x[3] = (float)hx; poly3d->y[3] = (float)hy; poly3d->z[3] = botheight;
2276 poly3d->depth = centerdepth;
2277 poly3d->desc = poly->desc;
2278
2279 poly3d = us_3dgetnextpoly(4);
2280 if (poly3d == 0) return;
2281 poly3d->x[0] = (float)hx; poly3d->y[0] = (float)ly; poly3d->z[0] = topheight;
2282 poly3d->x[1] = (float)lx; poly3d->y[1] = (float)ly; poly3d->z[1] = topheight;
2283 poly3d->x[2] = (float)lx; poly3d->y[2] = (float)ly; poly3d->z[2] = botheight;
2284 poly3d->x[3] = (float)hx; poly3d->y[3] = (float)ly; poly3d->z[3] = botheight;
2285 poly3d->depth = centerdepth;
2286 poly3d->desc = poly->desc;
2287 }
2288 break;
2289 }
2290
2291 /* nonmanhattan polygon: handle it as points */
2292 poly3d = us_3dgetnextpoly(poly->count);
2293 if (poly3d == 0) return;
2294 for(i=0; i<poly->count; i++)
2295 {
2296 poly3d->x[i] = (float)poly->xv[i];
2297 poly3d->y[i] = (float)poly->yv[i];
2298 poly3d->z[i] = topheight;
2299 }
2300 poly3d->depth = topdepth;
2301 poly3d->desc = poly->desc;
2302 if (thickness != 0)
2303 {
2304 poly3d = us_3dgetnextpoly(poly->count);
2305 if (poly3d == 0) return;
2306 for(i=0; i<poly->count; i++)
2307 {
2308 poly3d->x[i] = (float)poly->xv[i];
2309 poly3d->y[i] = (float)poly->yv[i];
2310 poly3d->z[i] = botheight;
2311 }
2312 poly3d->depth = botdepth;
2313 poly3d->desc = poly->desc;
2314
2315 for(i=0; i<poly->count; i++)
2316 {
2317 if (i == 0) previ = poly->count-1; else previ = i-1;
2318 poly3d = us_3dgetnextpoly(4);
2319 if (poly3d == 0) return;
2320 poly3d->x[0] = (float)poly->xv[previ]; poly3d->y[0] = (float)poly->yv[previ]; poly3d->z[0] = topheight;
2321 poly3d->x[1] = (float)poly->xv[i]; poly3d->y[1] = (float)poly->yv[i]; poly3d->z[1] = topheight;
2322 poly3d->x[2] = (float)poly->xv[i]; poly3d->y[2] = (float)poly->yv[i]; poly3d->z[2] = botheight;
2323 poly3d->x[3] = (float)poly->xv[previ]; poly3d->y[3] = (float)poly->yv[previ]; poly3d->z[3] = botheight;
2324 poly3d->depth = centerdepth;
2325 poly3d->desc = poly->desc;
2326 }
2327 }
2328 break;
2329 }
2330 }
2331
us_3dgetnextpoly(INTBIG count)2332 POLY3D *us_3dgetnextpoly(INTBIG count)
2333 {
2334 REGISTER INTBIG newtotal, i;
2335 REGISTER POLY3D **newlist, *poly3d;
2336
2337 /* make sure there is room for another 3D polygon */
2338 if (us_3dpolycount >= us_3dpolytotal)
2339 {
2340 newtotal = us_3dpolytotal * 2;
2341 if (newtotal <= 0) newtotal = 50;
2342 if (us_3dpolycount > newtotal) newtotal = us_3dpolycount;
2343 newlist = (POLY3D **)emalloc(newtotal * (sizeof (POLY3D *)), us_tool->cluster);
2344 if (newlist == 0) return(0);
2345 for(i=0; i<us_3dpolytotal; i++)
2346 newlist[i] = us_3dpolylist[i];
2347 for(i=us_3dpolytotal; i<newtotal; i++)
2348 {
2349 newlist[i] = (POLY3D *)emalloc(sizeof (POLY3D), us_tool->cluster);
2350 if (newlist[i] == 0) return(0);
2351 newlist[i]->total = 0;
2352 }
2353 if (us_3dpolytotal > 0) efree((CHAR *)us_3dpolylist);
2354 us_3dpolylist = newlist;
2355 us_3dpolytotal = newtotal;
2356 }
2357 poly3d = us_3dpolylist[us_3dpolycount++];
2358 if (poly3d->total < count)
2359 {
2360 if (poly3d->total > 0)
2361 {
2362 efree((CHAR *)poly3d->x);
2363 efree((CHAR *)poly3d->y);
2364 efree((CHAR *)poly3d->z);
2365 }
2366 poly3d->total = 0;
2367 poly3d->x = (float *)emalloc(count * (sizeof (float)), us_tool->cluster);
2368 if (poly3d->x == 0) return(0);
2369 poly3d->y = (float *)emalloc(count * (sizeof (float)), us_tool->cluster);
2370 if (poly3d->y == 0) return(0);
2371 poly3d->z = (float *)emalloc(count * (sizeof (float)), us_tool->cluster);
2372 if (poly3d->z == 0) return(0);
2373 poly3d->total = count;
2374 }
2375 poly3d->count = count;
2376 return(poly3d);
2377 }
2378