mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-05 16:54:59 +02:00
and area) so that they are consistent across commands. The default behavior remains the same, for backwards compatibility. However, a new "units" command has been added, so that "units microns" results in measurements always being displayed in microns, with choice of that or "internal", "lambda", or "grid". The units themselves may be printed (for interactive use) or not (for scripted use). The use of "units" is independent of "snap", after overriding the default behavior, so that units parsed on the command line are interpreted according to "units", not to "snap".
1893 lines
45 KiB
C
1893 lines
45 KiB
C
/*
|
|
* W3Dmain.c --
|
|
*
|
|
* Procedures to interface the 3D rendering window with the window package
|
|
* for the purposes of window creation, deletion, and modification.
|
|
*
|
|
* Copyright 2003 Open Circuit Design, Inc., for MultiGiG Ltd.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* This file is only applicable for OpenGL-enabled graphics; THREE_D is */
|
|
/* defined by the "make config" process and includes all preconditions. */
|
|
#ifdef THREE_D
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/keysym.h>
|
|
|
|
#include <GL/gl.h>
|
|
#include <GL/glx.h>
|
|
|
|
#include "tcltk/tclmagic.h"
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "windows/windows.h"
|
|
#include "tiles/tile.h"
|
|
#include "utils/hash.h"
|
|
#include "utils/undo.h"
|
|
#include "database/database.h"
|
|
#include "utils/main.h"
|
|
#include "commands/commands.h"
|
|
#include "graphics/wind3d.h"
|
|
#include "graphics/graphicsInt.h"
|
|
#include "graphics/graphics.h"
|
|
#include "grTOGLInt.h"
|
|
#include "textio/textio.h"
|
|
#include "textio/txcommands.h"
|
|
#include "utils/utils.h"
|
|
#include "utils/styles.h"
|
|
#include "dbwind/dbwtech.h"
|
|
#include "dbwind/dbwind.h"
|
|
#include "extract/extract.h"
|
|
#include "graphics/glyphs.h"
|
|
#include "utils/malloc.h"
|
|
#include "windows/windInt.h" /* for access to redisplay pointer */
|
|
#include "cif/cif.h"
|
|
#include "cif/CIFint.h" /* access to CIFPlanes, CIFCurStyle, etc. */
|
|
|
|
/* C99 compat */
|
|
#include "utils/signals.h"
|
|
|
|
extern Display *grXdpy; /* X11 display */
|
|
extern GLXContext grXcontext; /* OpenGL/X11 interface def. */
|
|
extern XVisualInfo *grVisualInfo; /* OpenGL preferred visual */
|
|
extern char *MainDisplayType; /* make sure we're using OpenGL */
|
|
extern HashTable grTOGLWindowTable;
|
|
extern int grXscrn;
|
|
extern int grCurFill;
|
|
|
|
static bool w3dNeedStyle;
|
|
static bool w3dIsLocked;
|
|
static int w3dStyle;
|
|
static MagWindow *w3dWindow;
|
|
extern bool grDriverInformed;
|
|
|
|
extern void grInformDriver();
|
|
|
|
global WindClient W3DclientID;
|
|
|
|
#define glTransYs(n) (DisplayHeight(grXdpy, grXscrn)-(n))
|
|
|
|
/* forward declarations */
|
|
|
|
void W3DCIFredisplay();
|
|
void W3Dredisplay();
|
|
void Set3DDefaults();
|
|
void w3drefreshFunc();
|
|
bool W3Ddelete();
|
|
|
|
/* ------------------------Low-Level Routines--------------------------------- */
|
|
|
|
void
|
|
w3dLock(w)
|
|
MagWindow *w;
|
|
{
|
|
grSimpleLock(w, TRUE);
|
|
w3dSetProjection(w);
|
|
}
|
|
|
|
void
|
|
w3dUnlock(w)
|
|
MagWindow *w;
|
|
{
|
|
glFlush();
|
|
glFinish();
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
glDisable(GL_COLOR_MATERIAL);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_POLYGON_SMOOTH);
|
|
|
|
grSimpleUnlock(w);
|
|
}
|
|
|
|
/* -------------------Low-Level Drawing Routines------------------------------ */
|
|
|
|
void
|
|
w3dFillEdge(bbox, r, ztop, zbot)
|
|
Rect *bbox; /* tile bounding box */
|
|
Rect *r;
|
|
float ztop;
|
|
float zbot;
|
|
{
|
|
float ztmp;
|
|
float xbot = (float)r->r_xbot;
|
|
float ybot = (float)r->r_ybot;
|
|
float xtop = (float)r->r_xtop;
|
|
float ytop = (float)r->r_ytop;
|
|
|
|
if (ytop == bbox->r_ybot || xbot == bbox->r_xtop)
|
|
{
|
|
/* reverse z top and bottom so rectangle is drawn */
|
|
/* counterclockwise as seen from the outside. */
|
|
|
|
ztmp = zbot;
|
|
zbot = ztop;
|
|
ztop = ztmp;
|
|
}
|
|
|
|
glBegin(GL_POLYGON);
|
|
glVertex3f(xbot, ybot, zbot);
|
|
glVertex3f(xbot, ybot, ztop);
|
|
glVertex3f(xtop, ytop, ztop);
|
|
glVertex3f(xtop, ytop, zbot);
|
|
glEnd();
|
|
}
|
|
|
|
void
|
|
w3dFillPolygon(p, np, zval, istop)
|
|
Point *p;
|
|
int np;
|
|
float zval;
|
|
bool istop;
|
|
{
|
|
int i;
|
|
|
|
glBegin(GL_POLYGON);
|
|
if (istop) /* counterclockwise */
|
|
for (i = 0; i < np; i++)
|
|
glVertex3f((float)(p[i].p_x), (float)(p[i].p_y), zval);
|
|
else /* clockwise */
|
|
for (i = np - 1; i >= 0; i--)
|
|
glVertex3f((float)(p[i].p_x), (float)(p[i].p_y), zval);
|
|
|
|
glEnd();
|
|
}
|
|
|
|
void
|
|
w3dFillTile(r, zval, istop)
|
|
Rect *r;
|
|
float zval;
|
|
bool istop;
|
|
{
|
|
float xbot, ybot, xtop, ytop;
|
|
|
|
ybot = (float)r->r_ybot;
|
|
ytop = (float)r->r_ytop;
|
|
|
|
if (istop)
|
|
{
|
|
xbot = (float)r->r_xbot;
|
|
xtop = (float)r->r_xtop;
|
|
}
|
|
else /* makes path counterclockwise as seen from the bottom */
|
|
{
|
|
xbot = (float)r->r_xtop;
|
|
xtop = (float)r->r_xbot;
|
|
}
|
|
|
|
glBegin(GL_POLYGON);
|
|
glVertex3f(xbot, ybot, zval);
|
|
glVertex3f(xtop, ybot, zval);
|
|
glVertex3f(xtop, ytop, zval);
|
|
glVertex3f(xbot, ytop, zval);
|
|
glEnd();
|
|
}
|
|
|
|
void
|
|
w3dFillXSide(xstart, xend, yval, ztop, zbot)
|
|
float xstart, xend, yval, ztop, zbot;
|
|
{
|
|
glBegin(GL_POLYGON);
|
|
glVertex3f(xstart, yval, zbot);
|
|
glVertex3f(xstart, yval, ztop);
|
|
glVertex3f(xend, yval, ztop);
|
|
glVertex3f(xend, yval, zbot);
|
|
glEnd();
|
|
}
|
|
|
|
void
|
|
w3dFillYSide(xval, ystart, yend, ztop, zbot)
|
|
float xval, ystart, yend, ztop, zbot;
|
|
{
|
|
glBegin(GL_POLYGON);
|
|
glVertex3f(xval, ystart, zbot);
|
|
glVertex3f(xval, ystart, ztop);
|
|
glVertex3f(xval, yend, ztop);
|
|
glVertex3f(xval, yend, zbot);
|
|
glEnd();
|
|
}
|
|
|
|
/* This routine assumes that vector (x1,y1)->(x2,y2) is in the */
|
|
/* counterclockwise direction with respect to the tile interior. */
|
|
|
|
void
|
|
w3dFillDiagonal(x1, y1, x2, y2, ztop, zbot)
|
|
float x1, y1, x2, y2, ztop, zbot;
|
|
{
|
|
glBegin(GL_POLYGON);
|
|
glVertex3f(x1, y1, zbot);
|
|
glVertex3f(x2, y2, zbot);
|
|
glVertex3f(x2, y2, ztop);
|
|
glVertex3f(x1, y1, ztop);
|
|
glEnd();
|
|
}
|
|
|
|
void
|
|
w3dFillOps(trans, tile, dinfo, cliprect, ztop, zbot)
|
|
Transform *trans;
|
|
Tile *tile;
|
|
TileType dinfo;
|
|
Rect *cliprect;
|
|
float ztop;
|
|
float zbot;
|
|
{
|
|
LinkedRect *tilesegs, *segptr;
|
|
Rect r, r2;
|
|
float xbot, ybot, xtop, ytop;
|
|
Point p[5];
|
|
int np;
|
|
|
|
r2.r_xbot = LEFT(tile);
|
|
r2.r_ybot = BOTTOM(tile);
|
|
r2.r_xtop = RIGHT(tile);
|
|
r2.r_ytop = TOP(tile);
|
|
|
|
GeoTransRect(trans, &r2, &r);
|
|
|
|
if (IsSplit(tile))
|
|
{
|
|
Rect fullr;
|
|
TileType newdinfo;
|
|
|
|
newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, trans);
|
|
|
|
fullr = r;
|
|
if (cliprect != NULL)
|
|
GeoClip(&r, cliprect);
|
|
|
|
GrClipTriangle(&fullr, &r, cliprect != NULL, newdinfo, p, &np);
|
|
|
|
if (np > 0)
|
|
{
|
|
w3dFillPolygon(p, np, ztop, TRUE);
|
|
w3dFillPolygon(p, np, zbot, FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Clip the tile area to the clipping area */
|
|
if (cliprect != NULL)
|
|
GeoClip(&r, cliprect);
|
|
|
|
/* draw tile top and bottom */
|
|
if (!GEO_RECTNULL(&r))
|
|
{
|
|
w3dFillTile(&r, ztop, TRUE);
|
|
w3dFillTile(&r, zbot, FALSE);
|
|
}
|
|
}
|
|
|
|
/* If height is zero, don't bother to draw sides */
|
|
if (ztop == zbot) return;
|
|
|
|
/* Find tile outline and render sides */
|
|
|
|
if (GrBoxOutline(tile, dinfo, &tilesegs))
|
|
{
|
|
xbot = (float)r.r_xbot;
|
|
ybot = (float)r.r_ybot;
|
|
xtop = (float)r.r_xtop;
|
|
ytop = (float)r.r_ytop;
|
|
|
|
if (r.r_xtop != r.r_xbot)
|
|
{
|
|
w3dFillXSide(xtop, xbot, ybot, ztop, zbot);
|
|
w3dFillXSide(xbot, xtop, ytop, ztop, zbot);
|
|
}
|
|
if (r.r_ytop != r.r_ybot)
|
|
{
|
|
w3dFillYSide(xbot, ybot, ytop, ztop, zbot);
|
|
w3dFillYSide(xtop, ytop, ybot, ztop, zbot);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
free_magic1_t mm1 = freeMagic1_init();
|
|
for (segptr = tilesegs; segptr != NULL; segptr = segptr->r_next)
|
|
{
|
|
GeoTransRect(trans, &segptr->r_r, &r2);
|
|
if (cliprect != NULL)
|
|
{
|
|
if (GEO_OVERLAP(cliprect, &r2))
|
|
{
|
|
GeoClip(&r2, cliprect);
|
|
w3dFillEdge(&r, &r2, ztop, zbot);
|
|
}
|
|
}
|
|
else
|
|
w3dFillEdge(&r, &r2, ztop, zbot);
|
|
freeMagic1(&mm1, segptr);
|
|
}
|
|
freeMagic1_end(&mm1);
|
|
|
|
/* For non-manhattan tiles, GrBoxOutline only returns */
|
|
/* the manhattan edges. This leaves the (possibly */
|
|
/* clipped) diagonal edge to render. */
|
|
|
|
if (IsSplit(tile))
|
|
{
|
|
int cp;
|
|
for (cp = 0; cp < np - 1; cp++)
|
|
{
|
|
if ((p[cp].p_x != p[cp + 1].p_x) && (p[cp].p_y != p[cp + 1].p_y))
|
|
{
|
|
w3dFillDiagonal((float)p[cp].p_x, (float)p[cp].p_y,
|
|
(float)p[cp + 1].p_x, (float)p[cp + 1].p_y,
|
|
ztop, zbot);
|
|
break;
|
|
}
|
|
}
|
|
if (cp == (np - 1))
|
|
if ((p[cp].p_x != p[0].p_x) && (p[cp].p_y != p[0].p_y))
|
|
w3dFillDiagonal((float)p[cp].p_x, (float)p[cp].p_y,
|
|
(float)p[0].p_x, (float)p[0].p_y,
|
|
ztop, zbot);
|
|
}
|
|
|
|
/* Render edges cut by the clipping area, if they're */
|
|
/* inside the tile, so the tile doesn't look "hollow". */
|
|
|
|
if (cliprect != NULL)
|
|
{
|
|
xbot = (float)r.r_xbot;
|
|
ybot = (float)r.r_ybot;
|
|
xtop = (float)r.r_xtop;
|
|
ytop = (float)r.r_ytop;
|
|
|
|
if (r.r_ytop > r.r_ybot)
|
|
{
|
|
if (r.r_xtop == cliprect->r_xtop)
|
|
w3dFillYSide(xtop, ytop, ybot, ztop, zbot);
|
|
if (r.r_xbot == cliprect->r_xbot)
|
|
w3dFillYSide(xbot, ybot, ytop, ztop, zbot);
|
|
}
|
|
if (r.r_xtop > r.r_xbot)
|
|
{
|
|
if (r.r_ytop == cliprect->r_ytop)
|
|
w3dFillXSide(xbot, xtop, ytop, ztop, zbot);
|
|
if (r.r_ybot == cliprect->r_ybot)
|
|
w3dFillXSide(xtop, xbot, ybot, ztop, zbot);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
w3dRenderVolume(tile, dinfo, trans, cliprect)
|
|
Tile *tile;
|
|
TileType dinfo;
|
|
Transform *trans;
|
|
Rect *cliprect;
|
|
{
|
|
float zbot, ztop;
|
|
float ftop = 0.0, fthk = 0.0;
|
|
W3DclientRec *crec;
|
|
|
|
crec = (W3DclientRec *)(w3dWindow->w_clientData);
|
|
|
|
ExtGetZAxis(tile, &ftop, &fthk);
|
|
|
|
/* Negate z-axis values for OpenGL display */
|
|
ztop = -ftop * crec->scale_z;
|
|
zbot = ztop - (fthk * crec->scale_z);
|
|
|
|
GR_CHECK_LOCK();
|
|
if (!grDriverInformed)
|
|
grInformDriver();
|
|
|
|
if ((grCurFill == GR_STSOLID) || (grCurFill == GR_STSTIPPLE))
|
|
{
|
|
w3dFillOps(trans, tile, dinfo, cliprect, ztop, zbot);
|
|
}
|
|
|
|
/* To do: Outlines and contact crosses */
|
|
/* To do: Labels */
|
|
}
|
|
|
|
void
|
|
w3dRenderCIF(tile, dinfo, layer, trans)
|
|
Tile *tile;
|
|
TileType dinfo;
|
|
CIFLayer *layer;
|
|
Transform *trans;
|
|
{
|
|
float zbot, ztop;
|
|
float ftop, fthk;
|
|
W3DclientRec *crec;
|
|
|
|
crec = (W3DclientRec *)(w3dWindow->w_clientData);
|
|
|
|
ftop = layer->cl_height;
|
|
fthk = layer->cl_thick;
|
|
|
|
/* Negate z-axis values for OpenGL display */
|
|
ztop = -ftop * crec->scale_z;
|
|
zbot = ztop - (fthk * crec->scale_z);
|
|
|
|
GR_CHECK_LOCK();
|
|
if (!grDriverInformed)
|
|
grInformDriver();
|
|
|
|
if ((grCurFill == GR_STSOLID) || (grCurFill == GR_STSTIPPLE))
|
|
{
|
|
w3dFillOps(trans, tile, dinfo, NULL, ztop, zbot);
|
|
}
|
|
|
|
/* To do: Outlines */
|
|
/* To do: Labels */
|
|
}
|
|
|
|
void
|
|
w3dClear()
|
|
{
|
|
float fr, fg, fb;
|
|
int cidx, lr, lb, lg;
|
|
|
|
/* STYLE_TRANSPARENT uses the background color definition, */
|
|
/* so we get RGB values from there. */
|
|
|
|
cidx = GrStyleTable[STYLE_TRANSPARENT].color;
|
|
GrGetColor(cidx, &lr, &lg, &lb);
|
|
|
|
fr = ((GLfloat)lr / 255);
|
|
fg = ((GLfloat)lg / 255);
|
|
fb = ((GLfloat)lb / 255);
|
|
|
|
glClearColor(fr, fg, fb, 0.0);
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
}
|
|
|
|
/* -------------------High-Level Drawing Routines------------------------------ */
|
|
|
|
void
|
|
w3dSetProjection(w)
|
|
MagWindow *w;
|
|
{
|
|
W3DclientRec *crec;
|
|
Window wind;
|
|
GLfloat light0_pos[] = { 0.0, 0.0, 0.0, 0.0 }; /* light #0 position */
|
|
GLfloat light0_amb[] = { 0.4, 0.4, 0.4, 1.0 }; /* light #0 ambient int. */
|
|
GLfloat light0_dif[] = { 0.0, 0.0, 0.0, 1.0 }; /* light #0 diffuse int. */
|
|
|
|
GLfloat light1_pos[] = { 50.0, 50.0, 50.0, 1.0 }; /* light #1 position */
|
|
GLfloat light1_amb[] = { 0.0, 0.0, 0.0, 1.0 }; /* light #1 ambient int. */
|
|
GLfloat light1_dif[] = { 1.0, 1.0, 1.0, 1.0 }; /* light #1 diffuse int. */
|
|
|
|
crec = (W3DclientRec *) w->w_clientData;
|
|
wind = Tk_WindowId((Tk_Window)w->w_grdata);
|
|
if (wind == 0) return; /* window was closed by window manager? */
|
|
|
|
/* Should not mess with surfaceArea---we want the area to be displayed */
|
|
/* in crec, in magic internal coordinates, set by the edit box (else- */
|
|
/* where). Set the viewport to maintain 1:1 x:y aspect ratio on the */
|
|
/* rendered volume. */
|
|
|
|
glXMakeCurrent(grXdpy, (GLXDrawable)wind, grXcontext);
|
|
|
|
if (crec->level > 0)
|
|
{
|
|
glEnable(GL_LINE_SMOOTH);
|
|
glEnable(GL_POLYGON_SMOOTH);
|
|
}
|
|
|
|
/* Need to look into dealing properly with double-buffered graphics */
|
|
glDrawBuffer(GL_FRONT);
|
|
/* glDrawBuffer(GL_BACK); */
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
|
|
/* Lighting */
|
|
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
glEnable(GL_LIGHTING);
|
|
glEnable(GL_LIGHT0);
|
|
glEnable(GL_LIGHT1);
|
|
|
|
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
|
|
|
|
glLightfv(GL_LIGHT0, GL_POSITION, light0_pos); /* positional */
|
|
glLightfv(GL_LIGHT0, GL_AMBIENT, light0_amb); /* ambient */
|
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_dif); /* diffuse */
|
|
|
|
glLightfv(GL_LIGHT1, GL_POSITION, light1_pos); /* directional */
|
|
glLightfv(GL_LIGHT1, GL_AMBIENT, light1_amb); /* ambient */
|
|
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_dif); /* diffuse */
|
|
|
|
/* Fill front-facing polygons only */
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
glCullFace(GL_BACK);
|
|
|
|
/* Preserve aspect ratio of 1:1 for internal units on the display */
|
|
|
|
glScalef((GLfloat)crec->height / (GLfloat)crec->width, 1.0, 1.0);
|
|
glViewport((GLsizei)0, (GLsizei)0, (GLsizei)crec->width, (GLsizei)crec->height);
|
|
|
|
/* Projection matrix manipulations */
|
|
|
|
glScalef(crec->scale_xy, crec->scale_xy, crec->prescale_z);
|
|
|
|
glRotatef(crec->view_x, 1.0, 0.0, 0.0);
|
|
glRotatef(crec->view_y, 0.0, 1.0, 0.0);
|
|
glRotatef(crec->view_z, 0.0, 0.0, 1.0);
|
|
|
|
glTranslatef(crec->trans_x, crec->trans_y, crec->trans_z);
|
|
}
|
|
|
|
/* Magic layer tile painting function */
|
|
|
|
int
|
|
w3dPaintFunc(tile, dinfo, cxp)
|
|
Tile *tile; /* Tile to be displayed */
|
|
TileType dinfo; /* Split tile information */
|
|
TreeContext *cxp; /* From DBTreeSrTiles */
|
|
{
|
|
SearchContext *scx = cxp->tc_scx;
|
|
|
|
/* Allow display interrupt a la dbwPaintFunc(). */
|
|
/* HOWEVER, note that GrEventPendingPtr looks at */
|
|
/* events in the window defined by toglCurrent, */
|
|
/* which is not the 3D window. So rendering in the */
|
|
/* 3D window can only be interrupted by events in */
|
|
/* the layout window. */
|
|
|
|
/* Honor display suspend status */
|
|
if (GrDisplayStatus == DISPLAY_SUSPEND) return 0;
|
|
|
|
if (GrDisplayStatus == DISPLAY_BREAK_PENDING)
|
|
{
|
|
GrDisplayStatus = DISPLAY_IN_PROGRESS;
|
|
if (GrEventPendingPtr)
|
|
{
|
|
if ((*GrEventPendingPtr)())
|
|
sigOnInterrupt(0);
|
|
else
|
|
SigSetTimer(0);
|
|
}
|
|
}
|
|
|
|
if (!w3dIsLocked)
|
|
{
|
|
w3dLock(w3dWindow);
|
|
w3dIsLocked = TRUE;
|
|
}
|
|
if (w3dNeedStyle)
|
|
{
|
|
GrSetStuff(w3dStyle);
|
|
w3dNeedStyle = FALSE;
|
|
}
|
|
|
|
w3dRenderVolume(tile, dinfo, &scx->scx_trans, &scx->scx_area);
|
|
return 0; /* keep the search going! */
|
|
}
|
|
|
|
/* CIF layer tile painting function */
|
|
|
|
int
|
|
w3dCIFPaintFunc(tile, dinfo, arg)
|
|
Tile *tile; /* Tile to be displayed */
|
|
TileType dinfo; /* Split tile information */
|
|
ClientData *arg; /* is NULL */
|
|
{
|
|
CIFLayer *layer = (CIFLayer *)arg;
|
|
|
|
/* Honor display suspend status */
|
|
if (GrDisplayStatus == DISPLAY_SUSPEND) return 0;
|
|
|
|
/* Allow display interrupt a la dbwPaintFunc() */
|
|
if (GrDisplayStatus == DISPLAY_BREAK_PENDING)
|
|
{
|
|
GrDisplayStatus = DISPLAY_IN_PROGRESS;
|
|
if (GrEventPendingPtr)
|
|
{
|
|
if ((*GrEventPendingPtr)())
|
|
sigOnInterrupt(0);
|
|
else
|
|
SigSetTimer(0);
|
|
}
|
|
}
|
|
|
|
if (!w3dIsLocked)
|
|
{
|
|
w3dLock(w3dWindow);
|
|
w3dIsLocked = TRUE;
|
|
}
|
|
if (w3dNeedStyle)
|
|
{
|
|
/* TxError("CIF layer 0x%x (%s) render style %d\n",
|
|
layer,
|
|
layer->cl_name,
|
|
layer->cl_renderStyle); */
|
|
GrSetStuff(layer->cl_renderStyle + TECHBEGINSTYLES);
|
|
w3dNeedStyle = FALSE;
|
|
}
|
|
|
|
w3dRenderCIF(tile, dinfo, layer, &GeoIdentityTransform);
|
|
return 0; /* keep the search going! */
|
|
}
|
|
|
|
/* -----------------------Command Procedures------------------------------ */
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dHelp --
|
|
*
|
|
* Print the list of commands available in this window.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dHelp(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
const char * const *msg;
|
|
W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
|
|
|
|
if (cmd->tx_argc == 1)
|
|
{
|
|
TxPrintf("\nWind3D command summary:\n");
|
|
for (msg = WindGetCommandTable(W3DclientID); *msg != NULL; msg++)
|
|
{
|
|
TxPrintf(" %s\n", *msg);
|
|
}
|
|
TxPrintf("\nType '?' in the window to get a key macro summary.\n");
|
|
}
|
|
else
|
|
TxError("Usage: help\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dCutBox --
|
|
*
|
|
* Set a clipping box for the 3D view
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dCutBox(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
bool hide = FALSE;
|
|
int lidx = 1, num_layers;
|
|
TileTypeBitMask mask;
|
|
W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
|
|
|
|
if (cmd->tx_argc == 1 || cmd->tx_argc == 2 || cmd->tx_argc == 5)
|
|
{
|
|
if (cmd->tx_argc == 1)
|
|
{
|
|
if (crec->clipped)
|
|
{
|
|
char *cllx, *clly, *curx, *cury;
|
|
|
|
cllx = DBWPrintValue(crec->cutbox.r_xbot, w, TRUE);
|
|
clly = DBWPrintValue(crec->cutbox.r_ybot, w, TRUE);
|
|
curx = DBWPrintValue(crec->cutbox.r_xtop, w, TRUE);
|
|
cury = DBWPrintValue(crec->cutbox.r_ytop, w, TRUE);
|
|
|
|
Tcl_Obj *rlist = Tcl_NewListObj(0, NULL);
|
|
Tcl_ListObjAppendElement(magicinterp, rlist,
|
|
Tcl_NewStringObj(cllx, -1));
|
|
Tcl_ListObjAppendElement(magicinterp, rlist,
|
|
Tcl_NewStringObj(clly, -1));
|
|
Tcl_ListObjAppendElement(magicinterp, rlist,
|
|
Tcl_NewStringObj(curx, -1));
|
|
Tcl_ListObjAppendElement(magicinterp, rlist,
|
|
Tcl_NewStringObj(cury, -1));
|
|
|
|
Tcl_SetObjResult(magicinterp, rlist);
|
|
}
|
|
else
|
|
Tcl_SetResult(magicinterp, "none", NULL);
|
|
}
|
|
else if (cmd->tx_argc == 2)
|
|
{
|
|
if (!strcmp(cmd->tx_argv[1], "none"))
|
|
crec->clipped = FALSE;
|
|
if (!strcmp(cmd->tx_argv[1], "box"))
|
|
{
|
|
Rect rootBox;
|
|
CellDef *rootBoxDef;
|
|
CellDef *cellDef = ((CellUse *)w->w_surfaceID)->cu_def;
|
|
|
|
if (ToolGetBox(&rootBoxDef, &rootBox))
|
|
{
|
|
if (rootBoxDef == cellDef)
|
|
{
|
|
crec->clipped = TRUE;
|
|
crec->cutbox = rootBox;
|
|
}
|
|
}
|
|
}
|
|
w3drefreshFunc(w);
|
|
}
|
|
else
|
|
{
|
|
if (StrIsInt(cmd->tx_argv[1]) &&
|
|
StrIsInt(cmd->tx_argv[2]) &&
|
|
StrIsInt(cmd->tx_argv[3]) &&
|
|
StrIsInt(cmd->tx_argv[4]))
|
|
{
|
|
crec->clipped = TRUE;
|
|
crec->cutbox.r_xbot = atoi(cmd->tx_argv[1]);
|
|
crec->cutbox.r_ybot = atoi(cmd->tx_argv[2]);
|
|
crec->cutbox.r_xtop = atoi(cmd->tx_argv[3]);
|
|
crec->cutbox.r_ytop = atoi(cmd->tx_argv[4]);
|
|
w3drefreshFunc(w);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
TxError("Usage: cutbox [none|box|llx lly urx ur]\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dSeeLayers --
|
|
*
|
|
* See or hide layers from the 3D view
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dSeeLayers(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
bool hide = FALSE;
|
|
int lidx = 1, num_layers;
|
|
TileTypeBitMask mask;
|
|
W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
|
|
|
|
if (cmd->tx_argc == 2 || cmd->tx_argc == 3)
|
|
{
|
|
if (cmd->tx_argc == 3)
|
|
{
|
|
lidx = 2;
|
|
if (!strcmp(cmd->tx_argv[1], "no")) hide = TRUE;
|
|
}
|
|
|
|
if (crec->cif)
|
|
{
|
|
/* If CIF layers, match the layer name (1 only) */
|
|
if (!CIFNameToMask(cmd->tx_argv[lidx], &mask, NULL))
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
/* If normal layers, pick up the name with TechType */
|
|
if (!CmdParseLayers(cmd->tx_argv[lidx], &mask))
|
|
return;
|
|
}
|
|
if (hide)
|
|
TTMaskClearMask(&crec->visible, &mask);
|
|
else
|
|
TTMaskSetMask(&crec->visible, &mask);
|
|
|
|
w3drefreshFunc(w);
|
|
}
|
|
else
|
|
TxError("Usage: see [no] layer\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dClose --
|
|
*
|
|
* Close the 3D display. This corresponds to the command-line command
|
|
* "closewindow" and overrides the default window client command of the
|
|
* same name.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dClose(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
|
|
|
|
if (cmd->tx_argc == 1)
|
|
(void) WindDelete(w);
|
|
else
|
|
TxError("Usage: closewindow\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dRescale --
|
|
*
|
|
* Change scale and translation by indicated scalefactor.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dRescale(crec, scalefactor)
|
|
W3DclientRec *crec;
|
|
float scalefactor;
|
|
{
|
|
crec->scale_xy /= scalefactor;
|
|
crec->prescale_z /= scalefactor;
|
|
|
|
crec->scale_z *= scalefactor;
|
|
crec->trans_y *= scalefactor;
|
|
crec->trans_x *= scalefactor;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dToggleCIF --
|
|
*
|
|
* Change between CIF and magic layer views
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dToggleCIF(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
|
|
|
|
if (cmd->tx_argc == 1)
|
|
{
|
|
|
|
if ((crec->cif == FALSE) && (CIFCurStyle != NULL))
|
|
{
|
|
((clientRec *)(W3DclientID))->w_redisplay = W3DCIFredisplay;
|
|
crec->cif = TRUE;
|
|
w3dRescale(crec, (float)CIFCurStyle->cs_scaleFactor);
|
|
}
|
|
else if (crec->cif == TRUE)
|
|
{
|
|
((clientRec *)(W3DclientID))->w_redisplay = W3Dredisplay;
|
|
crec->cif = FALSE;
|
|
w3dRescale(crec, 1.0 / (float)CIFCurStyle->cs_scaleFactor);
|
|
}
|
|
|
|
w3drefreshFunc(w);
|
|
}
|
|
else
|
|
TxError("Usage: cif\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dLevel --
|
|
*
|
|
* Change rendering level
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dLevel(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
|
|
|
|
if (cmd->tx_argc == 2)
|
|
{
|
|
if (StrIsInt(cmd->tx_argv[1]))
|
|
crec->level = atoi(cmd->tx_argv[1]);
|
|
else if (!strcmp(cmd->tx_argv[1], "up"))
|
|
crec->level++;
|
|
else if (!strcmp(cmd->tx_argv[1], "down"))
|
|
crec->level--;
|
|
else
|
|
{
|
|
TxError("Usage: level [<n>|up|down]\n");
|
|
return;
|
|
}
|
|
|
|
if (crec->level < 0) crec->level = 0;
|
|
w3drefreshFunc(w);
|
|
}
|
|
else if (cmd->tx_argc == 1)
|
|
{
|
|
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj((int)crec->level));
|
|
}
|
|
else
|
|
TxError("Usage: level [n]\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* Function to perform refresh on the entire 3D window
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3drefreshFunc(mw)
|
|
MagWindow *mw;
|
|
{
|
|
W3DclientRec *crec = (W3DclientRec *) mw->w_clientData;
|
|
Rect screenRect;
|
|
|
|
screenRect.r_xbot = 0;
|
|
screenRect.r_ybot = 0;
|
|
screenRect.r_xtop = crec->width;
|
|
screenRect.r_ytop = crec->height;
|
|
|
|
WindAreaChanged(mw, &screenRect);
|
|
WindUpdate();
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dDefaults --
|
|
*
|
|
* Revert to display defaults
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dDefaults(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
|
|
|
|
if (cmd->tx_argc == 1)
|
|
{
|
|
Set3DDefaults(w, crec);
|
|
w3drefreshFunc(w);
|
|
}
|
|
else
|
|
TxError("Usage: defaults\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dRefresh --
|
|
*
|
|
* Refresh the display
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dRefresh(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
|
|
|
|
if (cmd->tx_argc == 1)
|
|
w3drefreshFunc(w);
|
|
else
|
|
TxError("Usage: refresh\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dView --
|
|
*
|
|
* Set the viewing angle into the 3D display. Overrides the window
|
|
* client command of the same name.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dView(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
bool relative = FALSE;
|
|
int argc = cmd->tx_argc;
|
|
W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
|
|
|
|
if (argc == 5)
|
|
{
|
|
argc--;
|
|
if (!strncmp(cmd->tx_argv[argc], "rel", 3))
|
|
relative = TRUE;
|
|
else if (strncmp(cmd->tx_argv[argc], "abs", 3))
|
|
{
|
|
TxError("Usage: view angle_x angle_y angle_z absolute|relative\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (argc == 4)
|
|
{
|
|
/* Pick up x, y, z angles */
|
|
|
|
if (StrIsNumeric(cmd->tx_argv[1]) &&
|
|
StrIsNumeric(cmd->tx_argv[2]) &&
|
|
StrIsNumeric(cmd->tx_argv[3]))
|
|
{
|
|
if (relative)
|
|
{
|
|
crec->view_x += (float)atof(cmd->tx_argv[1]);
|
|
crec->view_y += (float)atof(cmd->tx_argv[2]);
|
|
crec->view_z += (float)atof(cmd->tx_argv[3]);
|
|
}
|
|
else
|
|
{
|
|
crec->view_x = (float)atof(cmd->tx_argv[1]);
|
|
crec->view_y = (float)atof(cmd->tx_argv[2]);
|
|
crec->view_z = (float)atof(cmd->tx_argv[3]);
|
|
}
|
|
|
|
/* Call redisplay function */
|
|
w3drefreshFunc(w);
|
|
}
|
|
}
|
|
else if (argc == 1)
|
|
{
|
|
Tcl_Obj *vlist = Tcl_NewListObj(0, NULL);
|
|
Tcl_ListObjAppendElement(magicinterp, vlist,
|
|
Tcl_NewDoubleObj((double)(crec->view_x)));
|
|
Tcl_ListObjAppendElement(magicinterp, vlist,
|
|
Tcl_NewDoubleObj((double)(crec->view_y)));
|
|
Tcl_ListObjAppendElement(magicinterp, vlist,
|
|
Tcl_NewDoubleObj((double)(crec->view_z)));
|
|
|
|
Tcl_SetObjResult(magicinterp, vlist);
|
|
}
|
|
else
|
|
TxError("Usage: view [angle_x angle_y angle_z [relative|absolute]]\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dScroll --
|
|
*
|
|
* Set the viewing position into the 3D display.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dScroll(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
bool relative = FALSE;
|
|
int argc = cmd->tx_argc;
|
|
W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
|
|
|
|
if (argc == 5)
|
|
{
|
|
argc--;
|
|
if (!strncmp(cmd->tx_argv[argc], "rel", 3))
|
|
relative = TRUE;
|
|
else if (strncmp(cmd->tx_argv[argc], "abs", 3))
|
|
{
|
|
TxError("Usage: scroll pos_x pos_y pos_z absolute|relative\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (argc == 4)
|
|
{
|
|
/* Pick up x, y, z translations */
|
|
|
|
if (StrIsNumeric(cmd->tx_argv[1]) &&
|
|
StrIsNumeric(cmd->tx_argv[2]) &&
|
|
StrIsNumeric(cmd->tx_argv[3]))
|
|
{
|
|
if (relative)
|
|
{
|
|
crec->trans_x += (float)atof(cmd->tx_argv[1]) / crec->scale_xy;
|
|
crec->trans_y += (float)atof(cmd->tx_argv[2]) / crec->scale_xy;
|
|
crec->trans_z += (float)atof(cmd->tx_argv[3]) / crec->scale_xy;
|
|
}
|
|
else
|
|
{
|
|
crec->trans_x = (float)atof(cmd->tx_argv[1]);
|
|
crec->trans_y = (float)atof(cmd->tx_argv[2]);
|
|
crec->trans_z = (float)atof(cmd->tx_argv[3]);
|
|
}
|
|
|
|
/* Call redisplay function */
|
|
w3drefreshFunc(w);
|
|
}
|
|
}
|
|
else if (argc == 1)
|
|
{
|
|
Tcl_Obj *vlist = Tcl_NewListObj(0, NULL);
|
|
Tcl_ListObjAppendElement(magicinterp, vlist,
|
|
Tcl_NewDoubleObj((double)(crec->trans_x)));
|
|
Tcl_ListObjAppendElement(magicinterp, vlist,
|
|
Tcl_NewDoubleObj((double)(crec->trans_y)));
|
|
Tcl_ListObjAppendElement(magicinterp, vlist,
|
|
Tcl_NewDoubleObj((double)(crec->trans_z)));
|
|
|
|
Tcl_SetObjResult(magicinterp, vlist);
|
|
}
|
|
else
|
|
TxError("Usage: scroll [pos_x pos_y pos_z [absolute|relative]]\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dZoom --
|
|
*
|
|
* Set the viewing scale of the 3D display. Overrides the window
|
|
* client command of the same name.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dZoom(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
bool relative = FALSE;
|
|
int argc = cmd->tx_argc;
|
|
W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
|
|
|
|
if (argc == 4)
|
|
{
|
|
argc--;
|
|
if (!strncmp(cmd->tx_argv[argc], "rel", 3))
|
|
relative = TRUE;
|
|
else if (strncmp(cmd->tx_argv[argc], "abs", 3))
|
|
{
|
|
TxError("Usage: zoom scale_xy scale_z relative|absolute\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (argc == 3)
|
|
{
|
|
/* Pick up xy and z scales */
|
|
|
|
if (StrIsNumeric(cmd->tx_argv[1]) &&
|
|
StrIsNumeric(cmd->tx_argv[2]))
|
|
{
|
|
float xy, z;
|
|
xy = (float)atof(cmd->tx_argv[1]);
|
|
z = (float)atof(cmd->tx_argv[2]);
|
|
if ((xy <= 0) || (z <= 0))
|
|
{
|
|
TxError("Error: zoom values/factors must be positive and nonzero\n");
|
|
return;
|
|
}
|
|
if (relative)
|
|
{
|
|
crec->scale_xy *= xy;
|
|
crec->scale_z *= z;
|
|
}
|
|
else
|
|
{
|
|
crec->scale_xy = xy;
|
|
crec->scale_z = z;
|
|
}
|
|
|
|
/* Call redisplay function */
|
|
w3drefreshFunc(w);
|
|
}
|
|
}
|
|
else if (cmd->tx_argc == 1)
|
|
{
|
|
Tcl_Obj *vlist = Tcl_NewListObj(0, NULL);
|
|
Tcl_ListObjAppendElement(magicinterp, vlist,
|
|
Tcl_NewDoubleObj((double)(crec->scale_xy)));
|
|
Tcl_ListObjAppendElement(magicinterp, vlist,
|
|
Tcl_NewDoubleObj((double)(crec->scale_z)));
|
|
|
|
Tcl_SetObjResult(magicinterp, vlist);
|
|
}
|
|
else
|
|
TxError("Usage: zoom [scale_xy scale_z [relative|absolute]]\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* w3dRenderValues --
|
|
*
|
|
* Set values for 3D rendering. These are independent of any
|
|
* extraction or other physical meaning, so we allow them to
|
|
* be independently controlled here.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
w3dRenderValues(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
int lidx;
|
|
CIFLayer *layer;
|
|
W3DclientRec *crec = (W3DclientRec *) w->w_clientData;
|
|
|
|
if (cmd->tx_argc > 1)
|
|
{
|
|
for (lidx = 0; lidx < CIFCurStyle->cs_nLayers; lidx++)
|
|
{
|
|
layer = CIFCurStyle->cs_layers[lidx];
|
|
if (!strcmp(layer->cl_name, cmd->tx_argv[1]))
|
|
break;
|
|
}
|
|
|
|
if (lidx == CIFCurStyle->cs_nLayers)
|
|
{
|
|
TxError("Unknown CIF layer \"%s\"\n", cmd->tx_argv[1]);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (cmd->tx_argc == 2)
|
|
{
|
|
Tcl_Obj *llist;
|
|
llist = Tcl_NewListObj(0, NULL);
|
|
Tcl_ListObjAppendElement(magicinterp, llist,
|
|
Tcl_NewDoubleObj((double)(layer->cl_height)));
|
|
Tcl_ListObjAppendElement(magicinterp, llist,
|
|
Tcl_NewDoubleObj((double)(layer->cl_thick)));
|
|
Tcl_ListObjAppendElement(magicinterp, llist,
|
|
Tcl_NewIntObj((int)(layer->cl_renderStyle)));
|
|
Tcl_SetObjResult(magicinterp, llist);
|
|
}
|
|
else if (cmd->tx_argc == 4 || cmd->tx_argc == 5)
|
|
{
|
|
int style;
|
|
float height, thick;
|
|
|
|
style = -1;
|
|
if (cmd->tx_argc == 5 && StrIsInt(cmd->tx_argv[4]))
|
|
style = atoi(cmd->tx_argv[4]);
|
|
if (!StrIsNumeric(cmd->tx_argv[3]) || !StrIsNumeric(cmd->tx_argv[2]))
|
|
goto badusage;
|
|
height = (float)atof(cmd->tx_argv[2]);
|
|
thick = (float)atof(cmd->tx_argv[3]);
|
|
|
|
/* It is necessary to update ALL layers of the same name */
|
|
for (lidx = 0; lidx < CIFCurStyle->cs_nLayers; lidx++)
|
|
{
|
|
layer = CIFCurStyle->cs_layers[lidx];
|
|
if (!strcmp(layer->cl_name, cmd->tx_argv[1]))
|
|
{
|
|
if (style >= 0) layer->cl_renderStyle = style;
|
|
layer->cl_height = height;
|
|
layer->cl_thick = thick;
|
|
}
|
|
}
|
|
|
|
/* Call redisplay function */
|
|
w3drefreshFunc(w);
|
|
}
|
|
else
|
|
|
|
badusage:
|
|
TxError("Usage: render name [height thick [style]]\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* Set3DDefaults --
|
|
*
|
|
* Set default values for the viewing parameters (scale, angle,
|
|
* and translation in 3 dimensions)
|
|
*
|
|
* Default view is top-down (layout) view scaled to fit the celldef's
|
|
* bounding box in the 3D window.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
Set3DDefaults(mw, crec)
|
|
MagWindow *mw;
|
|
W3DclientRec *crec;
|
|
{
|
|
int height, width;
|
|
int centerx, centery;
|
|
float scalex, scaley;
|
|
|
|
/* Get translation and scale from the cell bounding box */
|
|
/* (= window's bounding box, set in loadWindow proc) */
|
|
|
|
height = mw->w_bbox->r_ytop - mw->w_bbox->r_ybot;
|
|
width = mw->w_bbox->r_xtop - mw->w_bbox->r_xbot;
|
|
centerx = -(mw->w_bbox->r_xbot + (width >> 1));
|
|
centery = -(mw->w_bbox->r_ybot + (height >> 1));
|
|
|
|
scalex = 2.0 / ((float)width * 1.1); /* Add 10% margins in x and y */
|
|
scaley = 2.0 / ((float)height * 1.1);
|
|
|
|
crec->trans_x = (float)centerx;
|
|
crec->trans_y = (float)centery;
|
|
crec->trans_z = 0.0;
|
|
|
|
crec->scale_xy = (scalex > scaley) ? scaley : scalex;
|
|
crec->scale_z = 25.0; /* Height exaggerated by 25x */
|
|
|
|
/* The small z-scale value is necessary to keep large layout distances */
|
|
/* from exceeding the OpenGL (-1,1) limits of the z-axis. Distances in Z, */
|
|
/* like layer thickness, simply scale up to compensate. */
|
|
|
|
crec->prescale_z = 0.0001;
|
|
|
|
/* layout view (top down) */
|
|
|
|
crec->view_x = 0.0;
|
|
crec->view_y = 0.0;
|
|
crec->view_z = 0.0;
|
|
|
|
TTMaskZero(&crec->visible);
|
|
TTMaskSetMask(&crec->visible, &DBAllTypeBits);
|
|
|
|
/* Scale all factors appropriately for CIF display */
|
|
|
|
if (crec->cif == TRUE)
|
|
w3dRescale(crec, (float)CIFCurStyle->cs_scaleFactor);
|
|
|
|
/* Default is no clipping */
|
|
crec->clipped = FALSE; /* no clipping by default */
|
|
}
|
|
|
|
/* -----------------------Client Procedures------------------------------ */
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* W3DloadWindow --
|
|
*
|
|
* Replace the root cell of a window by the specified cell.
|
|
*
|
|
* Results:
|
|
* TRUE if successful, FALSE if not. The 3D rendering window is
|
|
* not allowed to create new cells, only to render existing ones.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
W3DloadWindow(window, name)
|
|
MagWindow *window;
|
|
char *name;
|
|
{
|
|
CellDef *newEditDef;
|
|
CellUse *newEditUse;
|
|
Rect loadBox;
|
|
|
|
newEditDef = DBCellLookDef(name);
|
|
if (newEditDef == (CellDef *)NULL)
|
|
return FALSE;
|
|
|
|
if (!DBCellRead(newEditDef, TRUE, TRUE, NULL))
|
|
return FALSE;
|
|
|
|
DBReComputeBbox(newEditDef);
|
|
loadBox = newEditDef->cd_bbox;
|
|
|
|
/* Attach cell to window */
|
|
|
|
newEditUse = DBCellNewUse(newEditDef, (char *) NULL);
|
|
(void) StrDup(&(newEditUse->cu_id), "3D rendered cell");
|
|
|
|
window->w_bbox = &(newEditUse->cu_def->cd_bbox);
|
|
return WindLoad(window, W3DclientID, (ClientData)newEditUse, &loadBox);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* W3Dcreate --
|
|
*
|
|
* A new window has been created. Create and initialize the needed
|
|
* structures.
|
|
*
|
|
* Results:
|
|
* FALSE if we have too many windows, TRUE otherwise.
|
|
*
|
|
* Side effects:
|
|
* Initialize the window to be editing the background color.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
W3Dcreate(window, argc, argv)
|
|
MagWindow *window;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
W3DclientRec *crec;
|
|
Tk_Window tkwind, tktop;
|
|
Window wind;
|
|
Colormap colormap;
|
|
HashEntry *entry;
|
|
CellDef *boxDef;
|
|
Rect box;
|
|
bool result;
|
|
char *name = NULL;
|
|
|
|
/* At least for now, there's only one 3D window allowed. */
|
|
|
|
if (w3dWindow != NULL)
|
|
{
|
|
TxError("Only one 3D window allowed.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/* The 3D rendering, of course, *only* works with OpenGL, so in an */
|
|
/* executable compiled for multiple graphics interfaces, we need */
|
|
/* to make sure that our display type is OpenGL. */
|
|
|
|
if (!GrIsDisplay(MainDisplayType, "OGL"))
|
|
{
|
|
TxError("Display type is \"%s\". OpenGL is required for the 3D display.\n",
|
|
MainDisplayType);
|
|
TxError("Please restart magic with option \"-d OGL\".\n");
|
|
return FALSE;
|
|
}
|
|
|
|
crec = (W3DclientRec *) mallocMagic(sizeof(W3DclientRec));
|
|
|
|
/* The MagWindow structure and frameArea indicates the cross-sectional */
|
|
/* area of the layout to be rendered in the 3D display window. */
|
|
|
|
/* Need to parse the argument list here. . . At least one argument */
|
|
/* should allow the Tk path name to be passed to the routine, as */
|
|
/* it is for the standard layout window in the Tk interface. */
|
|
|
|
/* Set surface area, etc. of the MagWindow. . . ? */
|
|
|
|
/* Initial window height and width (should be passed as optional */
|
|
/* arguments to the specialopen command) */
|
|
|
|
crec->width = 500;
|
|
crec->height = 500;
|
|
|
|
/* Rendering level (0 = coarse & fast, 1 = finer but slower, etc. */
|
|
/* Render cif by default. */
|
|
|
|
crec->level = 1;
|
|
crec->cif = TRUE;
|
|
|
|
window->w_clientData = (ClientData) crec;
|
|
window->w_flags &= ~(WIND_SCROLLABLE | WIND_SCROLLBARS | WIND_CAPTION |
|
|
WIND_BORDER | WIND_COMMANDS);
|
|
|
|
/* Load the current cellDef into the window */
|
|
|
|
if ((argc > 0) && (strlen(argv[0]) > 0))
|
|
result = W3DloadWindow(window, argv[0]);
|
|
else if (ToolGetBox(&boxDef, &box))
|
|
result = W3DloadWindow(window, boxDef->cd_name);
|
|
else
|
|
{
|
|
MagWindow *mw = NULL;
|
|
|
|
windCheckOnlyWindow(&mw, DBWclientID);
|
|
if (mw != NULL)
|
|
{
|
|
boxDef = ((CellUse *)mw->w_surfaceID)->cu_def;
|
|
result = W3DloadWindow(window, boxDef->cd_name);
|
|
}
|
|
else
|
|
{
|
|
TxError("Ambiguous directive: Put cursor box in one of the windows.\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (result == FALSE)
|
|
{
|
|
TxError("Cells cannot be created in the 3D window.\n");
|
|
return result;
|
|
}
|
|
|
|
/* Generate the window. */
|
|
|
|
colormap = XCreateColormap(grXdpy, RootWindow(grXdpy, DefaultScreen(grXdpy)),
|
|
grVisualInfo->visual, AllocNone);
|
|
|
|
if (!(tktop = Tk_MainWindow(magicinterp))) return FALSE;
|
|
|
|
/* Check for a Tk pathname for the window; allows window to be */
|
|
/* by a Tk GUI script. */
|
|
if (argc > 1) name = argv[1];
|
|
|
|
if (name == NULL)
|
|
tkwind = Tk_CreateWindowFromPath(magicinterp, tktop, ".magic3d", "");
|
|
else
|
|
tkwind = Tk_CreateWindowFromPath(magicinterp, tktop, name, NULL);
|
|
|
|
if (tkwind != 0)
|
|
{
|
|
window->w_grdata = (ClientData) tkwind;
|
|
entry = HashFind(&grTOGLWindowTable, (char *)tkwind);
|
|
HashSetValue(entry, window);
|
|
|
|
if (name != NULL)
|
|
{
|
|
/* Visual type must match what we chose in the graphics init proc */
|
|
Tk_SetWindowVisual(tkwind, grVisualInfo->visual, toglCurrent.depth,
|
|
colormap);
|
|
Tk_MapWindow(tkwind);
|
|
Tk_GeometryRequest(tkwind, crec->width, crec->height);
|
|
|
|
wind = Tk_WindowId(tkwind);
|
|
if (wind == 0)
|
|
glXMakeCurrent(grXdpy, (GLXDrawable)wind, grXcontext);
|
|
}
|
|
|
|
/* execute any pending Tk events */
|
|
|
|
while (Tcl_DoOneEvent(TCL_DONT_WAIT) != 0);
|
|
|
|
/* use the OpenGL Tk event handler (see grTOGL1.c) for the 3d window */
|
|
|
|
Tk_CreateEventHandler(tkwind, ExposureMask | StructureNotifyMask |
|
|
ButtonPressMask | KeyPressMask,
|
|
(Tk_EventProc *)TOGLEventProc, (ClientData)tkwind);
|
|
|
|
w3dWindow = window;
|
|
|
|
/* Use Tcl to pass commands to the window */
|
|
MakeWindowCommand((name == NULL) ? ".magic3d" : name, window);
|
|
|
|
/* Now that a cell is loaded, set default values for the */
|
|
/* client record based on the cell bounding box. */
|
|
|
|
Set3DDefaults(window, crec);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
TxError("Could not create a new Tk window\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* W3Ddelete --
|
|
*
|
|
* Clean up the data structures before deleting a window.
|
|
*
|
|
* Results:
|
|
* TRUE if we really want to delete the window, FALSE otherwise.
|
|
*
|
|
* Side effects:
|
|
* A W3DclientRec is freed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
W3Ddelete(window)
|
|
MagWindow *window;
|
|
{
|
|
W3DclientRec *cr;
|
|
Tk_Window xw;
|
|
|
|
cr = (W3DclientRec *) window->w_clientData;
|
|
xw = (Tk_Window)window->w_grdata;
|
|
w3dWindow = NULL;
|
|
|
|
freeMagic((char *)cr);
|
|
window->w_clientData = (ClientData)NULL;
|
|
xw = (Tk_Window)window->w_grdata;
|
|
/* Tk_DestroyWindow(xw); */
|
|
return (TRUE);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* W3Dredisplay --
|
|
*
|
|
* Redisplay a portion of the 3D rendered layout view
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Redisplay is done.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
W3Dredisplay(w, rootArea, clipArea)
|
|
MagWindow *w; /* The window containing the area. */
|
|
Rect *rootArea; /* Ignore this---area defined by window with box */
|
|
Rect *clipArea; /* Ignore this, too */
|
|
{
|
|
W3DclientRec *crec;
|
|
CellDef *cellDef;
|
|
SearchContext scontext;
|
|
Rect largerArea, *clipRect = &largerArea;
|
|
int i;
|
|
TileTypeBitMask *mask, layers;
|
|
|
|
w3dLock(w);
|
|
|
|
crec = (W3DclientRec *) w->w_clientData;
|
|
cellDef = ((CellUse *)w->w_surfaceID)->cu_def;
|
|
|
|
if (crec->clipped)
|
|
clipRect = &crec->cutbox;
|
|
|
|
if (rootArea != NULL)
|
|
largerArea = *rootArea;
|
|
else
|
|
largerArea = w->w_surfaceArea;
|
|
|
|
largerArea.r_xbot--;
|
|
largerArea.r_ybot--;
|
|
largerArea.r_xtop++;
|
|
largerArea.r_ytop++;
|
|
|
|
scontext.scx_area = *clipRect;
|
|
scontext.scx_use = ((CellUse *)w->w_surfaceID);
|
|
scontext.scx_x = scontext.scx_y = -1;
|
|
scontext.scx_trans = GeoIdentityTransform;
|
|
|
|
w3dClear();
|
|
|
|
/* follow the same locking procedure as DBWredisplay() */
|
|
w3dUnlock(w);
|
|
w3dIsLocked = FALSE;
|
|
for (i = 0; i < DBWNumStyles; i++)
|
|
{
|
|
/* This should probably be redesigned. . . */
|
|
mask = DBWStyleToTypes(i);
|
|
TTMaskAndMask3(&layers, mask, &crec->visible);
|
|
if (!TTMaskIsZero(&layers))
|
|
{
|
|
w3dStyle = i + TECHBEGINSTYLES;
|
|
w3dNeedStyle = TRUE;
|
|
(void) DBTreeSrTiles(&scontext, &layers, 0,
|
|
w3dPaintFunc, (ClientData) NULL);
|
|
if (w3dIsLocked)
|
|
{
|
|
w3dUnlock(w);
|
|
w3dIsLocked = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* W3DCIFredisplay --
|
|
*
|
|
* Redisplay a portion of the 3D rendered layout, in CIF layers.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Redisplay is done.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
W3DCIFredisplay(w, rootArea, clipArea)
|
|
MagWindow *w; /* The window containing the area. */
|
|
Rect *rootArea; /* Ignore this---area defined by window with box */
|
|
Rect *clipArea; /* Ignore this, too */
|
|
{
|
|
W3DclientRec *crec;
|
|
SearchContext scx;
|
|
CellDef *cellDef;
|
|
Rect clipRect;
|
|
int i;
|
|
TileTypeBitMask *mask;
|
|
|
|
w3dLock(w);
|
|
|
|
crec = (W3DclientRec *) w->w_clientData;
|
|
cellDef = ((CellUse *)w->w_surfaceID)->cu_def;
|
|
|
|
clipRect = (crec->clipped) ? crec->cutbox : cellDef->cd_bbox;
|
|
GEO_EXPAND(&clipRect, CIFCurStyle->cs_radius, &scx.scx_area);
|
|
|
|
/* The following is basically a copy of CIFSeeLayer() */
|
|
|
|
CIFErrorDef = cellDef;
|
|
CIFInitCells();
|
|
UndoDisable();
|
|
CIFDummyUse->cu_def = cellDef;
|
|
scx.scx_use = CIFDummyUse;
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
|
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
|
CIFGen(CIFComponentDef, cellDef, &clipRect, CIFPlanes, &DBAllTypeBits, TRUE,
|
|
TRUE, FALSE, (ClientData)NULL);
|
|
DBCellClearDef(CIFComponentDef);
|
|
|
|
w3dClear();
|
|
|
|
/* follow the same locking procedure as DBWredisplay() */
|
|
w3dUnlock(w);
|
|
w3dIsLocked = FALSE;
|
|
|
|
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
|
|
{
|
|
if (TTMaskHasType(&crec->visible, i))
|
|
{
|
|
w3dNeedStyle = TRUE;
|
|
DBSrPaintArea((Tile *) NULL, CIFPlanes[i], &TiPlaneRect,
|
|
&CIFSolidBits, w3dCIFPaintFunc,
|
|
(ClientData)(CIFCurStyle->cs_layers[i]));
|
|
|
|
if (w3dIsLocked)
|
|
{
|
|
w3dUnlock(w);
|
|
w3dIsLocked = FALSE;
|
|
}
|
|
}
|
|
}
|
|
UndoEnable();
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* W3Dcommand --
|
|
*
|
|
* This procedure is invoked by the window package whenever a
|
|
* command is typed while the cursor is over a 3D window.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* TBD
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
W3Dcommand(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
int cmdNum;
|
|
|
|
switch (cmd->tx_button)
|
|
{
|
|
case TX_NO_BUTTON:
|
|
WindExecute(w, W3DclientID, cmd);
|
|
break;
|
|
case TX_LEFT_BUTTON:
|
|
case TX_RIGHT_BUTTON:
|
|
case TX_MIDDLE_BUTTON:
|
|
/* No action---we shouldn't be here anyway. */
|
|
break;
|
|
default:
|
|
ASSERT(FALSE, "W3Dcommand");
|
|
}
|
|
UndoNext();
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* W3Dinit --
|
|
*
|
|
* Add the 3D rendering window client to the window module.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Add ourselves as a client to the window package.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
W3Dinit()
|
|
{
|
|
W3DclientID = WindAddClient("wind3d", W3Dcreate, W3Ddelete,
|
|
W3DCIFredisplay, W3Dcommand,
|
|
(void(*)())NULL, (bool(*)())NULL,
|
|
(void(*)())NULL, (GrGlyph *)NULL);
|
|
|
|
/* Register commands with the client */
|
|
|
|
WindAddCommand(W3DclientID,
|
|
"view [x y z] specify viewpoint angle",
|
|
w3dView, FALSE);
|
|
WindAddCommand(W3DclientID,
|
|
"scroll [x y z] specify viewpoint position",
|
|
w3dScroll, FALSE);
|
|
WindAddCommand(W3DclientID,
|
|
"zoom [xy z] specify render volume scale",
|
|
w3dZoom, FALSE);
|
|
WindAddCommand(W3DclientID,
|
|
"refresh refresh 3D display",
|
|
w3dRefresh, FALSE);
|
|
WindAddCommand(W3DclientID,
|
|
"cif switch to/from CIF layers display",
|
|
w3dToggleCIF, FALSE);
|
|
WindAddCommand(W3DclientID,
|
|
"level [<n>|up|down] set rendering level",
|
|
w3dLevel, FALSE);
|
|
WindAddCommand(W3DclientID,
|
|
"defaults revert to defaults",
|
|
w3dDefaults, FALSE);
|
|
WindAddCommand(W3DclientID,
|
|
"closewindow close the 3D display",
|
|
w3dClose, FALSE);
|
|
WindAddCommand(W3DclientID,
|
|
"render name [height thick [style]]\n"
|
|
" properties of CIF layer rendering",
|
|
w3dRenderValues, FALSE);
|
|
WindAddCommand(W3DclientID,
|
|
"see [no] layer view or hide layers from the 3D view",
|
|
w3dSeeLayers, FALSE);
|
|
WindAddCommand(W3DclientID,
|
|
"cutbox [none|box|llx lly urx ury]\n"
|
|
" set clipping rectangle for 3D view",
|
|
w3dCutBox, FALSE);
|
|
WindAddCommand(W3DclientID,
|
|
"help print this command list",
|
|
w3dHelp, FALSE);
|
|
}
|
|
|
|
#endif /* THREE_D */
|