Logo Search packages:      
Sourcecode: magic version File versions  Download package

W3Dmain.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. */

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();
}

#ifdef NONMANHATTAN
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();
}
#endif

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();
}

#ifdef NONMANHATTAN

/* 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();
}

#endif

void
w3dFillOps(trans, tile, cliprect, ztop, zbot)
    Transform *trans;
    Tile *tile;
    Rect *cliprect;
    float ztop;
    float zbot;
{
    LinkedRect *tilesegs, *segptr;
    Rect r, r2;
    float xbot, ybot, xtop, ytop;

#ifdef NONMANHATTAN
    Point p[5];
    int np;
#endif

    r2.r_xbot = LEFT(tile);
    r2.r_ybot = BOTTOM(tile);
    r2.r_xtop = RIGHT(tile);
    r2.r_ytop = TOP(tile);

    GeoTransRect(trans, &r2, &r);

#ifdef NONMANHATTAN
    if (IsSplit(tile))
    {
      Rect fullr;
      TileType dinfo;

      dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans);

      fullr = r;
      if (cliprect != NULL)
          GeoClip(&r, cliprect);

      GrClipTriangle(&fullr, &r, cliprect != NULL, dinfo, p, &np);
      
      if (np > 0)
      {
          w3dFillPolygon(p, np, ztop, TRUE);
          w3dFillPolygon(p, np, zbot, FALSE);
      }
    }
    else
    {
#endif

    /* 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);
    }

#ifdef NONMANHATTAN
    }
#endif

    /* If height is zero, don't bother to draw sides */
    if (ztop == zbot) return;

    /* Find tile outline and render sides */

    if (GrBoxOutline(tile, &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
    {
      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);
          freeMagic(segptr);
      }

#ifdef NONMANHATTAN
      /* 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);
      }
#endif

      /* 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, trans, cliprect)
    Tile *tile;
    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, cliprect, ztop, zbot);
    }

    /* To do:  Outlines and contact crosses */
    /* To do:  Labels                   */
}

void
w3dRenderCIF(tile, layer, trans)
    Tile *tile;
    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, 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, cxp)
    Tile *tile;               /* Tile to be displayed */
    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, &scx->scx_trans, &scx->scx_area);
    return 0;                 /* keep the search going! */
}

/* CIF layer tile painting function */

int
w3dCIFPaintFunc(tile, arg)
    Tile *tile;               /* Tile to be displayed */
    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, 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;
{
    char **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)
          {
            Tcl_Obj *rlist = Tcl_NewListObj(0, NULL);
            Tcl_ListObjAppendElement(magicinterp, rlist,
                  Tcl_NewIntObj((int)(crec->cutbox.r_xbot)));
            Tcl_ListObjAppendElement(magicinterp, rlist,
                  Tcl_NewIntObj((int)(crec->cutbox.r_ybot)));
            Tcl_ListObjAppendElement(magicinterp, rlist,
                  Tcl_NewIntObj((int)(crec->cutbox.r_xtop)));
            Tcl_ListObjAppendElement(magicinterp, rlist,
                  Tcl_NewIntObj((int)(crec->cutbox.r_ytop)));

            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))
            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, (char *)NULL, TRUE))
      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, 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, &clipRect, CIFPlanes, &DBAllTypeBits, TRUE, TRUE);
    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 */

Generated by  Doxygen 1.6.0   Back to index