[BACK]Return to hidden3d.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gnuplot

Annotation of OpenXM_contrib/gnuplot/hidden3d.c, Revision 1.1.1.3

1.1       maekawa     1: #ifndef lint
1.1.1.3 ! ohara       2: static char *RCSid = "$Id: hidden3d.c,v 1.13.2.6 2002/03/11 12:27:57 broeker Exp $";
1.1       maekawa     3: #endif
                      4:
                      5: /* GNUPLOT - hidden3d.c */
                      6:
                      7: /*[
                      8:  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
                      9:  *
                     10:  * Permission to use, copy, and distribute this software and its
                     11:  * documentation for any purpose with or without fee is hereby granted,
                     12:  * provided that the above copyright notice appear in all copies and
                     13:  * that both that copyright notice and this permission notice appear
                     14:  * in supporting documentation.
                     15:  *
                     16:  * Permission to modify the software is granted, but not the right to
                     17:  * distribute the complete modified source code.  Modifications are to
                     18:  * be distributed as patches to the released version.  Permission to
                     19:  * distribute binaries produced by compiling modified sources is granted,
                     20:  * provided you
                     21:  *   1. distribute the corresponding source modifications from the
                     22:  *    released version in the form of a patch file along with the binaries,
                     23:  *   2. add special version identification to distinguish your version
                     24:  *    in addition to the base release version number,
                     25:  *   3. provide your name and address as the primary contact for the
                     26:  *    support of your modified version, and
                     27:  *   4. retain our contact information in regard to use of the base
                     28:  *    software.
                     29:  * Permission to distribute the released version of the source code along
                     30:  * with corresponding source modifications in the form of a patch file is
                     31:  * granted with same provisions 2 through 4 for binary distributions.
                     32:  *
                     33:  * This software is provided "as is" without express or implied warranty
                     34:  * to the extent permitted by applicable law.
                     35: ]*/
                     36:
                     37:
                     38: /*
                     39:  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
                     40:  * Added user-specified bases for log scaling.
                     41:  *
                     42:  * 'someone'  contributed a complete rewrite of the hidden line
                     43:  * stuff, for about beta 173 or so, called 'newhide.tgz'
                     44:  *
                     45:  * 1995-1997 Hans-Bernhard Br"oker (Broeker@physik.rwth-aachen.de)
                     46:  *   Speedup, cleanup and several modification to integrate
                     47:  *   'newhide' with 3.6 betas ~188 (start of work) up to 273.
                     48:  *   As of beta 290, this is 'officially' in gnuplot.
                     49:  *
                     50:  */
                     51:
                     52: #include "plot.h"
                     53: #include "setshow.h"
                     54:
                     55: /* TODO (HBB's notes, just in case you're interested):
                     56:  * + fix all the problems I annotated by a 'FIXME' comment
                     57:  * + Find out which value EPSILON should have, and why
                     58:  * + Ask gnuplot-beta for a suitable way of concentrating
                     59:  *   all those 'VERYSMALL', 'EPSILON', and other numbers
                     60:  *   into one, consistent scheme, possibly based on
                     61:  *   <float.h>. E.g., I'd say that for most applications,
                     62:  *   the best 'epsilon' is either DBL_EPS or its square root.
                     63:  * + redo all the profiling, esp. to find out if TEST_GRIDCHECK = 1
                     64:  *   actually gains some speed, and if it is worth the memory
                     65:  *   spent to store the bit masks
                     66:  *   -> seems not improve speed at all, at least for my standard
                     67:  *   test case (mandd.gpl) it even slows it down by ~ 10%
                     68:  * + Evaluate the speed/memory comparison for storing vertex
                     69:  *   indices instead of (double) floating point constants
                     70:  *   to store {x|y}{min|max}
                     71:  * + remove those of my comments that are now pointless
                     72:  * + indent all that code
                     73:  * + try to really understand that 'hl_buffer' stuff...
                     74:  * + get rid of hardcoded things like sizeof(short) == 4,
                     75:  *   those 0x7fff terms and all that.
                     76:  * + restructure the hl_buffer storing method to make it more efficient
                     77:  * + Try to cut the speed decrease of this code rel. to the old hidden
                     78:  *   hidden line removal. (For 'mandd.gpl', it costs an overall
                     79:  *   factor of 9 compared with my older versions of gnuplot!)
                     80:  */
                     81:
                     82: /*************************/
                     83: /* Configuration section */
                     84: /*************************/
                     85:
                     86: /* HBB: if this module is compiled with TEST_GRIDCHECK = 1 defined,
                     87:  * it will store the information about {x|y}{min|max} in an
                     88:  * other (additional!) form: a bit mask, with each bit representing
                     89:  * one horizontal or vertical strip of the screen. The bits
                     90:  * for  strips a polygon spans are set to one. This allows to
                     91:  * test for xy_overlap simply by comparing bit patterns.
                     92:  */
                     93: #ifndef TEST_GRIDCHECK
                     94: #define TEST_GRIDCHECK 0
                     95: #endif
                     96:
                     97: /* HBB 961124; If you don't want the color-distinction between the
                     98:  * 'top' and 'bottom' sides of the surface, like I do, then just compile
                     99:  * with -DBACKSIDE_LINETYPE_OFFSET = 0. */
                    100: #ifndef BACKSIDE_LINETYPE_OFFSET
                    101: #define BACKSIDE_LINETYPE_OFFSET 1
                    102: #endif
                    103:
                    104: /* HBB 961127: defining FOUR_TRIANGLES = 1 will separate each quadrangle
                    105:  * of data points into *four* triangles, by introducing an additional
                    106:  * point at the mean of the four corners. Status: experimental
                    107:  */
                    108: #ifndef FOUR_TRIANGLES
                    109: #define FOUR_TRIANGLES 0
                    110: #endif
                    111:
                    112: /* HBB 970322: I removed the SENTINEL flag and its implementation
                    113:  * completely.  Its speed improvement wasn't that great, and it never
                    114:  * fully worked anyway, so that shouldn't make much of a difference at
                    115:  * all. */
                    116:
                    117: /* HBB 961212: this #define lets you choose if the diagonals that
                    118:  * divide each original quadrangle in two triangles will be drawn
                    119:  * visible or not: do draw them, define it to be 7L, otherwise let be
                    120:  * 3L (for the FOUR_TRIANGLES method, the values are 7L and 1L) */
                    121: /* drd : default to 3, for back-compatibility with 3.5 */
                    122: #ifndef TRIANGLE_LINESDRAWN_PATTERN
                    123: #define TRIANGLE_LINESDRAWN_PATTERN 3L
                    124: #endif
                    125:
                    126: /* HBB 970131: with HANDLE_UNDEFINED_POINTS = 1, let's try to handle
                    127:  * UNDEFINED data points in the input we're given by the rest of
                    128:  * gnuplot. We do that by marking these points by giving them z = -2
                    129:  * (which normally never happens), and then refusing to build any
                    130:  * polygon if one of its vertices has this mark. Thus, there's now a
                    131:  * hole in the generated surface. */
                    132: /* HBB 970322: some of this code is now hardwired (in
                    133:  * PREPARE_POLYGON), so HANDLE_UNDEFINED_POINTS = 0 might have stopped
                    134:  * to be a useful setting. I doubt anyone will miss it, anyway. */
                    135: /* drd : 2 means undefined only. 1 means outrange treated as undefined */
                    136: #ifndef HANDLE_UNDEFINED_POINTS
                    137: #define HANDLE_UNDEFINED_POINTS 1
                    138: #endif
                    139: /* Symbolic value for 'do not handle Undefined Points specially' */
                    140: #define UNHANDLED (UNDEFINED+1)
                    141:
                    142: /* HBB 970322: If both subtriangles of a quad were cancelled, try if
                    143:  * using the other diagonal is better. This only makes a difference if
                    144:  * exactly one vertex of the quad is unusable, and that one is on the
                    145:  * first tried diagonal. In such a case, the border of the hole in the
                    146:  * surface will be less rough than with the previous method. To
                    147:  * disable this, #define SHOW_ALTERNATIVE_DIAGONAL as 0 */
                    148: #ifndef SHOW_ALTERNATIVE_DIAGONAL
                    149: #define SHOW_ALTERNATIVE_DIAGONAL 1
                    150: #endif
                    151:
                    152: /* HBB 9790522: If the two triangles in a quad are both drawn, and
                    153:  * they show different sides to the user (the quad is 'bent over'),
                    154:  * then it often looks more sensible to draw the diagonal visibly to
                    155:  * avoid other parts of the scene being obscured by what the user
                    156:  * can't see. To disable, #define HANDLE_BENTOVER_QUADRANGLES 0 */
                    157: #ifndef HANDLE_BENTOVER_QUADRANGLES
                    158: #define HANDLE_BENTOVER_QUADRANGLES 1
                    159: #endif
                    160:
                    161: /* HBB 970618: The code of split_polygon_by_plane used to make a
                    162:  * separate decision about what should happen to points that are 'in'
                    163:  * the splitting plane (within EPSILON accuracy, i.e.), based on the
                    164:  * orientation of the splitting plane. I had disabled that code for I
                    165:  * assumed it might be the cause of some of the buggyness. I'm not yet
                    166:  * fully convinced on wether that assumption holds or not, so it's now
                    167:  * choosable.  OLD_SPLIT_PLANE == 1 will enable it. Some older comments
                    168:  * from the source:*/
                    169: /* HBB 970325: re-inserted this from older versions. Finally, someone
                    170:  * came up with a test case where it is actually needed :-( */
                    171: /* HBB 970427: seems to have been an incorrect analysis of that error.
                    172:  * the problematic plot works without this as well. */
                    173: #ifndef OLD_SPLIT_INPLANE
                    174: #define OLD_SPLIT_INPLANE 1
                    175: #endif
                    176:
                    177: /* HBB 970618: this way, new edges introduced by splitting a polygon
                    178:  * by the plane of another one will be made visible. Not too useful on
                    179:  * production output, but can help in debugging. */
                    180: #ifndef SHOW_SPLITTING_EDGES
                    181: #define SHOW_SPLITTING_EDGES 0
                    182: #endif
                    183:
                    184: /********************************/
                    185: /* END of configuration section */
                    186: /********************************/
                    187:
                    188:
                    189:
                    190: /* Variables to hold configurable values. This is meant to prepare for
                    191:  * making these settable by the user via 'set hidden [option]...' */
                    192:
                    193: int hiddenBacksideLinetypeOffset = BACKSIDE_LINETYPE_OFFSET;
                    194: long hiddenTriangleLinesdrawnPattern = TRIANGLE_LINESDRAWN_PATTERN;
                    195: int hiddenHandleUndefinedPoints = HANDLE_UNDEFINED_POINTS;
                    196: int hiddenShowAlternativeDiagonal = SHOW_ALTERNATIVE_DIAGONAL;
                    197: int hiddenHandleBentoverQuadrangles = HANDLE_BENTOVER_QUADRANGLES;
                    198:
                    199: /* The functions to map from user 3D space into normalized -1..1 */
                    200: #define map_x3d(x) ((x-min_array[FIRST_X_AXIS])*xscale3d-1.0)
                    201: #define map_y3d(y) ((y-min_array[FIRST_Y_AXIS])*yscale3d-1.0)
1.1.1.2   maekawa   202: #define map_z3d(z) ((z-floor_z)*zscale3d-1.0)
1.1       maekawa   203:
                    204: extern int suppressMove;
                    205: extern int xright, xleft, ybot, ytop;
                    206: extern int xmiddle, ymiddle, xscaler, yscaler;
                    207: extern double min_array[], max_array[];
                    208: extern int auto_array[], log_array[];
                    209: extern double base_array[], log_base_array[];
                    210: extern double xscale3d, yscale3d, zscale3d;
1.1.1.2   maekawa   211: extern double floor_z;
1.1       maekawa   212:
                    213: extern int hidden_no_update, hidden_active;
                    214: extern int hidden_line_type_above, hidden_line_type_below;
                    215:
                    216: extern double trans_mat[4][4];
                    217:
                    218:
                    219: #ifdef HAVE_STRINGIZE
                    220: /* ANSI preprocessor concatenation */
                    221: # define CONCAT(x,y) x##y
                    222: # define CONCAT3(x,y,z) x##y##z
                    223: #else
                    224: /* K&R preprocessor concatenation */
                    225: # define CONCAT(x,y) x/**/y
                    226: # define CONCAT3(x,y,z) x/**/y/**/z
                    227: #endif
                    228:
                    229: /* Bitmap of the screen.  The array for each x value is malloc-ed as needed */
                    230: /* HBB 961111: started parametrisation of type t_pnt, to prepare change from
                    231:  * short to normal ints in **pnt. The other changes aren't always annotated,
                    232:  * so watch out! */
                    233: typedef unsigned short int t_pnt;
                    234: #define PNT_BITS (CHAR_BIT*sizeof(t_pnt))
                    235: /* caution! ANSI-dependant ! ? */
                    236: #define PNT_MAX USHRT_MAX
                    237: typedef t_pnt *tp_pnt;
                    238: static tp_pnt *pnt;
                    239:
                    240: /* Testroutine for the bitmap */
                    241: /* HBB 961110: fixed slight problem indicated by lclint:
                    242:  * calling IS_UNSET with pnt == 0 (possible?) */
                    243: /* HBB 961111: changed for new t_pnt, let compiler take care of optimisation
                    244:  * `%' -> `&' */
                    245: /* HBB 961124: switched semantics: as this was *always* called as !IS_SET(),
                    246:  * it's better to check for *unset* bits right away: */
                    247: #define IS_UNSET(X,Y) ((!pnt || pnt[X] == 0) ? 1 : !(((pnt[X])[(Y)/PNT_BITS] >> ((Y)%PNT_BITS)) & 0x01))
                    248:
                    249: /* Amount of space we need for one vertical row of bitmap,
                    250:    and byte offset of first used element */
                    251: static unsigned long y_malloc;
                    252:
                    253: /* These numbers are chosen as dividers into the bitmap. */
                    254: static int xfact, yfact;
                    255: #define XREDUCE(X) ((X)/xfact)
                    256: #define YREDUCE(Y) ((Y)/yfact)
                    257:
                    258: /* These variables are only used for drawing the individual polygons
                    259:    that make up the 3d figure.  After each polygon is drawn, the
                    260:    information is copied to the bitmap: xmin_hl, ymin_hl are used to
                    261:    keep track of the range of x values.  The arrays ymin_hl[],
                    262:    ymax_hl[] are used to keep track of the minimum and maximum y
                    263:    values used for each X value. */
                    264:
                    265: /* HBB 961124: new macro, to avoid a wordsize-depence */
                    266: #define HL_EXTENT_X_MAX UINT_MAX       /* caution! ANSI-only !? */
                    267: static unsigned int xmin_hl, xmax_hl;
                    268:
                    269: /* HBB: parametrized type of hl_buffer elements, to allow easier
                    270:    changing later on: */
                    271: #define HL_EXTENT_Y_MAX SHRT_MAX       /* caution! ANSI-only !? */
                    272: typedef short int t_hl_extent_y;
                    273: static t_hl_extent_y *ymin_hl, *ymax_hl;
                    274:
                    275:
                    276: /* hl_buffer is a buffer which is needed to draw polygons with very small
                    277:    angles correct:
                    278:
                    279:    One polygon may be split during the sorting algorithmus into
                    280:    several polygons. Before drawing a part of a polygon, I save in
                    281:    this buffer all lines of the polygon, which will not yet be drawn.
                    282:    If then the actual part draws a virtual line (a invisible line,
                    283:    which splits the polygon into 2 parts), it draws the line visible
                    284:    in those points, which are set in the buffer.
                    285:
                    286:    The layout of the buffer:
                    287:    hl_buffer[i] stands for the i'th column of the bitmap.
                    288:    Each column is splitted into pairs of points (a,b).
                    289:    Each pair describes a cross of one line with the column. */
                    290:
1.1.1.3 ! ohara     291: /* HBB 20000608: finally, someone found a serious bug in this code :-(
        !           292:  * whenever the Cross_store array has to be reallocated, all the
        !           293:  * pointers in hl_buffer, and the next pointers in struct Cross become
        !           294:  * invalid. Use indices instead of pointers. */
        !           295:
1.1       maekawa   296: struct Cross {
                    297:     int a, b;
1.1.1.3 ! ohara     298:     unsigned int next;         /* (unsigned int) -1 means: no next */
        !           299:     /* HBB 20000608: was struct Cross GPHUGE *next;*/
1.1       maekawa   300: };
                    301:
1.1.1.3 ! ohara     302: #if 0 /* HBB 20000608 */
1.1       maekawa   303: static struct Cross GPHUGE *GPHUGE * hl_buffer;
1.1.1.3 ! ohara     304: #else
        !           305: static unsigned int GPHUGE * hl_buffer;
        !           306: #endif
1.1       maekawa   307:
                    308: /* HBB 980303: added a global array of Cross structures, to save lots
                    309:  * of gp_alloc() calls (3 millions in a run through all.dem!)  */
                    310:
                    311: #define CROSS_STORE_INCREASE 500       /* number of Cross'es to alloc at a time */
                    312: static struct Cross *Cross_store = 0;
1.1.1.3 ! ohara     313: static unsigned int last_Cross_store = 0, free_Cross_store = 0;
1.1       maekawa   314:
                    315: struct Vertex {
                    316:     coordval x, y, z;
                    317:     int style;
                    318: };
                    319:
                    320: /* HBB 971114: two new macros, to properly hide the machinery that
                    321:  *implements flagging of vertices as 'undefined' (or 'out of range',
                    322:  *handled equally). Thanks to Lars Hecking for pointing this out */
                    323: #define FLAG_VERTEX_AS_UNDEFINED(v) \
                    324:   do { (v).z = -2.0; } while (0)
                    325: #define VERTEX_IS_UNDEFINED(v) ((v).z == -2.0)
                    326:
                    327: /* These values serve as flags to detect loops of polygons obscuring
                    328:  * each other in in_front() */
                    329: typedef enum {
                    330:     is_untested = 0, is_tested, is_in_loop, is_moved_or_split
                    331: } t_poly_tested;
                    332:
                    333: /* Strings for printing out values of type t_poly_tested: */
                    334: static const char *string_poly_tested[] =
                    335: {
                    336:     "is_untested",
                    337:     "is_tested",
                    338:     "is_in_loop",
                    339:     "is_moved_or_split"
                    340: };
                    341:
                    342: struct Polygon {
                    343:     int n;                     /* amount of vertices */
                    344:     long *vertex;              /* The vertices (indices on vlist) */
                    345:     long line;                 /* i'th bit shows, if the i'th line should be drawn */
                    346:     coordval xmin, xmax, ymin, ymax, zmin, zmax;
                    347:     /* min/max in all three directions */
                    348:     struct lp_style_type *lp;  /* pointer to l/p properties */
                    349:     int style;                 /* The style of the lines */
                    350:     long next;                 /* index of next polygon in z-sorted list */
                    351:     long next_frag;            /* next fragment of same polygon... */
                    352:     int id;                    /* Which polygons belong together? */
                    353:     t_poly_tested tested;      /* To determine a loop during the sorting algorithm */
                    354:     /* HBB 980317: on the 16 bit PC platforms, the struct size must
                    355:      * be a power of two, so it exactly fits into a 64KB segment. First
                    356:      * we'll add the TEST_GRIDCHECK fields, regardless wether that
                    357:      * feature was activated or not. */
                    358: #if TEST_GRIDCHECK || defined(DOS16) || defined(WIN16)
                    359:     unsigned int xextent, yextent;
                    360: #endif
                    361:     /* HBB 980317: the remaining bit of padding. */
                    362: #if defined(DOS16) || defined(WIN16) || defined(WIN32)
                    363:     char dummies[8];
                    364: #endif
                    365: };
                    366:
                    367: typedef enum {                 /* result type for polygon_plane_intersection() */
                    368:     infront, inside, behind, intersects
                    369: } t_poly_plane_intersect;
                    370:
                    371: static struct Vertex GPHUGE *vlist;    /* The vertices */
                    372: static struct Polygon GPHUGE *plist;   /* The polygons */
                    373: static long nvert, npoly;      /* amount of vertices and polygons */
                    374: static long pfree, vert_free;  /* index on the first free entries */
                    375:
                    376: static long pfirst;            /* Index on the first polygon */
                    377:
                    378: /* macros for (somewhat) safer handling of the dynamic array of
                    379:  * polygons, 'plist[]' */
                    380: #define EXTEND_PLIST() \
                    381:     plist = (struct Polygon GPHUGE *) gp_realloc(plist, \
                    382:       (unsigned long)sizeof(struct Polygon)*(npoly += 10L), "hidden plist")
                    383:
                    384: #define CHECK_PLIST() if (pfree >= npoly) EXTEND_PLIST()
                    385: #define CHECK_PLIST_2() if (pfree+1 >= npoly) EXTEND_PLIST()
                    386: #define CHECK_PLIST_EXTRA(extra) if (pfree >= npoly) { EXTEND_PLIST() ; extra; }
                    387:
                    388:
                    389: /* precision of calculations in normalized space: */
                    390: #define EPSILON 1e-5           /* HBB: was 1.0E-5 */
                    391: #define SIGNOF(X)  ( ((X)<-EPSILON) ? -1: ((X)>EPSILON) )
                    392:
                    393: /* Some inexact relations: == , > , >= */
                    394: #define EQ(X,Y)  (fabs( (X) - (Y) ) < EPSILON) /* X == Y */
                    395: #define GR(X,Y)  ((X) >  (Y) + EPSILON)                /* X >  Y */
                    396: #define GE(X,Y)  ((X) >= (Y) - EPSILON)                /* X >= Y */
                    397:
                    398: /* Test, if two vertices are near each other */
                    399: #define V_EQUAL(a,b) ( GE(0.0, fabs((a)->x - (b)->x) + \
                    400:    fabs((a)->y - (b)->y) + fabs((a)->z - (b)->z)) )
                    401:
                    402: #define SETBIT(a,i,set) a= (set) ?  (a) | (1L<<(i)) : (a) & ~(1L<<(i))
                    403: #define GETBIT(a,i) (((a)>>(i))&1L)
                    404:
                    405: #define UINT_BITS (CHAR_BIT*sizeof(unsigned int))
                    406: #define USHRT_BITS (CHAR_BIT*sizeof(unsigned short))
                    407:
                    408:
                    409: static void print_polygon __PROTO((struct Polygon GPHUGE * p, const char *pname));
                    410:
                    411: /* HBB: new routine, to help debug 'Logic errors', mainly */
                    412: static void print_polygon(p, pname)
                    413: struct Polygon GPHUGE *p;
                    414: const char *pname;
                    415: {
                    416:     struct Vertex GPHUGE *v;
                    417:     int i;
                    418:
                    419:     fprintf(stderr, "#%s:(ind %d) n:%d, id:%d, next:%ld, tested:%s\n",
                    420:            pname, (int) (p - plist), p->n, p->id, p->next,
                    421:            string_poly_tested[(int) (p->tested)]);
                    422:     fprintf(stderr, "#zmin:%g, zmax:%g\n", p->zmin, p->zmax);
                    423:     for (i = 0; i < p->n; i++, v++) {
                    424:        v = vlist + p->vertex[i];
                    425:        fprintf(stderr, "%g %g %g \t%ld\n", v->x, v->y, v->z, p->vertex[i]);
                    426:     }
                    427:     /*repeat first vertex, so the line gets closed: */
                    428:     v = vlist + p->vertex[0];
                    429:     fprintf(stderr, "%g %g %g \t%ld\n", v->x, v->y, v->z, p->vertex[0]);
                    430:     /*two blank lines, as a multimesh separator: */
                    431:     fputs("\n\n", stderr);
                    432: }
                    433:
                    434: /* Gets Minimum 'C' value of polygon, C is x, y, or z: */
                    435: #define GET_MIN(p, C, min) do { \
                    436:   int i; \
                    437:   long *v = p->vertex; \
                    438:                        \
                    439:   min = vlist[*v++].C; \
                    440:   for (i = 1; i< p->n; i++, v++) \
                    441:     if (vlist[*v].C < min) \
                    442:       min = vlist[*v].C; \
                    443: } while (0)
                    444:
                    445: /* Gets Maximum 'C' value of polygon, C is x, y, or z: */
                    446: #define GET_MAX(p, C, max) do { \
                    447:   int i; \
                    448:   long *v = p->vertex; \
                    449:                       \
                    450:   max = vlist[*v++].C; \
                    451:   for (i = 1; i< p->n; i++, v++) \
                    452:     if (vlist[*v].C > max) \
                    453:       max = vlist[*v].C; \
                    454: } while (0)
                    455:
                    456: /* Prototypes for internal functions of this module. */
                    457: static void map3d_xyz __PROTO((double x, double y, double z,
                    458:                               struct Vertex GPHUGE * v));
                    459: static int reduce_polygon __PROTO((int *n, long **v, long *line, int nmin));
                    460: static void build_polygon __PROTO((struct Polygon GPHUGE * p, int n,
                    461:                long *v, long line, int style, struct lp_style_type * lp,
                    462:               long next, long next_frag, int id, t_poly_tested tested));
                    463: static GP_INLINE int maybe_build_polygon __PROTO((struct Polygon GPHUGE * p,
                    464:         int n, long *v, long line, int style, struct lp_style_type * lp,
                    465:               long next, long next_frag, int id, t_poly_tested tested));
                    466: static void init_polygons __PROTO((struct surface_points * plots, int pcount));
1.1.1.3 ! ohara     467: int compare_by_zmax __PROTO((SORTFUNC_ARGS p1, SORTFUNC_ARGS p2));
1.1       maekawa   468: static void sort_by_zmax __PROTO((void));
                    469: static int obscured __PROTO((struct Polygon GPHUGE * p));
                    470: static GP_INLINE int xy_overlap __PROTO((struct Polygon GPHUGE * a, struct Polygon GPHUGE * b));
                    471: static void get_plane __PROTO((struct Polygon GPHUGE * p, double *a, double *b,
                    472:                               double *c, double *d));
                    473: static t_poly_plane_intersect polygon_plane_intersection __PROTO((struct Polygon GPHUGE * p, double a, double b, double c, double d));
                    474: static int intersect __PROTO((struct Vertex GPHUGE * v1,
                    475:                              struct Vertex GPHUGE * v2, struct Vertex GPHUGE * v3, struct Vertex GPHUGE * v4));
                    476: static int v_intersect __PROTO((struct Vertex GPHUGE * v1,
                    477:                                struct Vertex GPHUGE * v2, struct Vertex GPHUGE * v3, struct Vertex GPHUGE * v4));
                    478: static int intersect_polygon __PROTO((struct Vertex GPHUGE * v1, struct Vertex GPHUGE * v2, struct Polygon GPHUGE * p));
                    479: static int full_xy_overlap __PROTO((struct Polygon GPHUGE * a, struct Polygon GPHUGE * b));
                    480: static long build_new_vertex __PROTO((long V1, long V2, double w));
                    481: static long split_polygon_by_plane __PROTO((long P, double a, double b,
                    482:                                        double c, double d, TBOOLEAN f));
                    483: static int in_front __PROTO((long Last, long Test));
                    484:
                    485: /* HBB 980303: new, for the new back-buffer for *Cross structures: */
1.1.1.3 ! ohara     486: static GP_INLINE unsigned int get_Cross_from_store __PROTO((void));
1.1       maekawa   487: static GP_INLINE void init_Cross_store __PROTO((void));
                    488:
                    489: static GP_INLINE TBOOLEAN hl_buffer_set __PROTO((int xv, int yv));
                    490: static GP_INLINE void update_hl_buffer_column __PROTO((int xv, int ya, int yv));
                    491: static void draw_clip_line_buffer __PROTO((int x1, int y1, int x2, int y2));
                    492: static void draw_clip_line_update __PROTO((int x1, int y1, int x2, int y2,
                    493:                                           int virtual));
                    494: static GP_INLINE void clip_vector_h __PROTO((int x, int y));
                    495: static GP_INLINE void clip_vector_virtual __PROTO((int x, int y));
                    496: static GP_INLINE void clip_vector_buffer __PROTO((int x, int y));
                    497: static void draw __PROTO((struct Polygon GPHUGE * p));
                    498:
                    499:
                    500: /* Set the options for hidden3d. To be called from set.c, when the
                    501:  * user has begun a command with 'set hidden3d', to parse the rest of
                    502:  * that command */
                    503: void set_hidden3doptions()
                    504: {
                    505:     struct value t;
                    506:
                    507:     c_token++;
                    508:
                    509:     if (END_OF_COMMAND) {
                    510:        return;
                    511:     }
                    512:     if (almost_equals(c_token, "def$aults")) {
                    513:        /* reset all parameters to defaults */
                    514:        hiddenBacksideLinetypeOffset = BACKSIDE_LINETYPE_OFFSET;
                    515:        hiddenTriangleLinesdrawnPattern = TRIANGLE_LINESDRAWN_PATTERN;
                    516:        hiddenHandleUndefinedPoints = HANDLE_UNDEFINED_POINTS;
                    517:        hiddenShowAlternativeDiagonal = SHOW_ALTERNATIVE_DIAGONAL;
                    518:        hiddenHandleBentoverQuadrangles = HANDLE_BENTOVER_QUADRANGLES;
                    519:        c_token++;
                    520:        if (!END_OF_COMMAND)
                    521:            int_error("No further options allowed after 'defaults'", c_token);
                    522:        return;
                    523:     }
                    524:     if (almost_equals(c_token, "off$set")) {
                    525:        c_token++;
                    526:        hiddenBacksideLinetypeOffset = (int) real(const_express(&t));
                    527:     } else if (almost_equals(c_token, "nooff$set")) {
                    528:        c_token++;
                    529:        hiddenBacksideLinetypeOffset = 0;
                    530:     }
                    531:     if (END_OF_COMMAND) {
                    532:        return;
                    533:     }
                    534:     if (almost_equals(c_token, "tri$anglepattern")) {
                    535:        c_token++;
                    536:        hiddenTriangleLinesdrawnPattern = (int) real(const_express(&t));
                    537:     }
                    538:     if (END_OF_COMMAND) {
                    539:        return;
                    540:     }
                    541:     if (almost_equals(c_token, "undef$ined")) {
                    542:        int tmp;
                    543:
                    544:        c_token++;
                    545:        tmp = (int) real(const_express(&t));
                    546:        if (tmp <= 0 || tmp > UNHANDLED)
                    547:            tmp = UNHANDLED;
                    548:        hiddenHandleUndefinedPoints = tmp;
                    549:     } else if (almost_equals(c_token, "nound$efined")) {
                    550:        c_token++;
                    551:        hiddenHandleUndefinedPoints = UNHANDLED;
                    552:     }
                    553:     if (END_OF_COMMAND) {
                    554:        return;
                    555:     }
                    556:     if (almost_equals(c_token, "alt$diagonal")) {
                    557:        c_token++;
                    558:        hiddenShowAlternativeDiagonal = 1;
                    559:     } else if (almost_equals(c_token, "noalt$diagonal")) {
                    560:        c_token++;
                    561:        hiddenShowAlternativeDiagonal = 0;
                    562:     }
                    563:     if (END_OF_COMMAND) {
                    564:        return;
                    565:     }
                    566:     if (almost_equals(c_token, "bent$over")) {
                    567:        c_token++;
                    568:        hiddenHandleBentoverQuadrangles = 1;
                    569:     } else if (almost_equals(c_token, "nobent$over")) {
                    570:        c_token++;
                    571:        hiddenHandleBentoverQuadrangles = 0;
                    572:     }
                    573:     if (!END_OF_COMMAND) {
                    574:        int_error("No such option to hidden3d (or wrong order)", c_token);
                    575:     }
                    576: }
                    577:
                    578: /* HBB 970619: new routine for displaying the option settings */
                    579: void show_hidden3doptions()
                    580: {
                    581:     fprintf(stderr,"\
                    582: \t  Back side of surfaces has linestyle offset of %d\n\
                    583: \t  Bit-Mask of Lines to draw in each triangle is %ld\n\
                    584: \t  %d: ",
                    585:            hiddenBacksideLinetypeOffset, hiddenTriangleLinesdrawnPattern,
                    586:            hiddenHandleUndefinedPoints);
                    587:
                    588:     switch (hiddenHandleUndefinedPoints) {
                    589:     case OUTRANGE:
                    590:        fputs("Outranged and undefined datapoints are omitted from the surface.\n", stderr);
                    591:        break;
                    592:     case UNDEFINED:
                    593:        fputs("Only undefined datapoints are omitted from the surface.\n", stderr);
                    594:        break;
                    595:     case UNHANDLED:
                    596:        fputs("Will not check for undefined datapoints (may cause crashes).\n", stderr);
                    597:        break;
                    598:     default:
                    599:        fputs("This value is illegal!!!\n", stderr);
                    600:        break;
                    601:     }
                    602:     fprintf(stderr,"\
                    603: \t  Will %suse other diagonal if it gives a less jaggy outline\n\
                    604: \t  Will %sdraw diagonal visibly if quadrangle is 'bent over'\n",
                    605:            hiddenShowAlternativeDiagonal ? "" : "not ",
                    606:            hiddenHandleBentoverQuadrangles ? "" : "not ");
                    607: }
                    608:
                    609: /* HBB 971117: new function. */
                    610: /* Implements proper 'save'ing of the new hidden3d options... */
                    611: void save_hidden3doptions(fp)
                    612: FILE *fp;
                    613: {
                    614:     if (!hidden3d) {
                    615:        fputs("set nohidden3d\n", fp);
                    616:        return;
                    617:     }
                    618:     fprintf(fp, "set hidden3d offset %d trianglepattern %ld undefined %d %saltdiagonal %sbentover\n",
                    619:            hiddenBacksideLinetypeOffset,
                    620:            hiddenTriangleLinesdrawnPattern,
                    621:            hiddenHandleUndefinedPoints,
                    622:            hiddenShowAlternativeDiagonal ? "" : "no",
                    623:            hiddenHandleBentoverQuadrangles ? "" : "no");
                    624: }
                    625:
                    626: /* Initialize the necessary steps for hidden line removal and
                    627:    initialize global variables. */
                    628: void init_hidden_line_removal()
                    629: {
                    630:     int i;
                    631:
                    632:     /* Check for some necessary conditions to be set elsewhere: */
                    633:     /* HandleUndefinedPoints mechanism depends on these: */
                    634:     assert(OUTRANGE == 1);
                    635:     assert(UNDEFINED == 2);
                    636:     /* '3' makes the test easier in the critical section */
                    637:     if (hiddenHandleUndefinedPoints < OUTRANGE)
                    638:        hiddenHandleUndefinedPoints = UNHANDLED;
                    639:
                    640:     /*  We want to keep the bitmap size less than 2048x2048, so we choose
                    641:      *  integer dividers for the x and y coordinates to keep the x and y
                    642:      *  ranges less than 2048.  In practice, the x and y sizes for the bitmap
                    643:      *  will be somewhere between 1024 and 2048, except in cases where the
                    644:      *  coordinates ranges for the device are already less than 1024.
                    645:      *  We do this mainly to control the size of the bitmap, but it also
                    646:      *  speeds up the computation.  We maintain separate dividers for
                    647:      *  x and y.
                    648:      */
                    649:     xfact = (xright - xleft) / 1024;
                    650:     yfact = (ytop - ybot) / 1024;
                    651:     if (xfact == 0)
                    652:        xfact = 1;
                    653:     if (yfact == 0)
                    654:        yfact = 1;
                    655:     if (pnt == 0) {
                    656:        i = XREDUCE(xright) - XREDUCE(xleft) + 1;
1.1.1.3 ! ohara     657:        pnt = (tp_pnt *) gp_alloc(i * sizeof(tp_pnt), "hidden pnt");
1.1       maekawa   658:        while (--i >= 0)
                    659:            pnt[i] = (tp_pnt) 0;
                    660:     }
                    661: }
                    662:
                    663: /* Reset the hidden line data to a fresh start.                              */
                    664: void reset_hidden_line_removal()
                    665: {
                    666:     int i;
                    667:     if (pnt) {
                    668:        for (i = 0; i <= XREDUCE(xright) - XREDUCE(xleft); i++) {
                    669:            if (pnt[i]) {
                    670:                free(pnt[i]);
                    671:                pnt[i] = 0;
                    672:            };
                    673:        };
                    674:     };
                    675: }
                    676:
                    677:
                    678: /* Terminates the hidden line removal process.                  */
                    679: /* Free any memory allocated by init_hidden_line_removal above. */
                    680: void term_hidden_line_removal()
                    681: {
                    682:     if (pnt) {
                    683:        int j;
                    684:        for (j = 0; j <= XREDUCE(xright) - XREDUCE(xleft); j++) {
                    685:            if (pnt[j]) {
                    686:                free(pnt[j]);
                    687:                pnt[j] = 0;
                    688:            };
                    689:        };
                    690:        free(pnt);
                    691:        pnt = 0;
                    692:     };
                    693:     if (ymin_hl)
                    694:        free(ymin_hl), ymin_hl = 0;
                    695:     if (ymax_hl)
                    696:        free(ymax_hl), ymax_hl = 0;
                    697: }
                    698:
                    699:
                    700: /* Maps from normalized space to terminal coordinates */
                    701: #define TERMCOORD(v,x,y) x = ((int)((v)->x * xscaler)) + xmiddle, \
                    702:                         y = ((int)((v)->y * yscaler)) + ymiddle;
                    703:
                    704:
                    705: static void map3d_xyz(x, y, z, v)
                    706: double x, y, z;                        /* user coordinates */
                    707: struct Vertex GPHUGE *v;       /* the point in normalized space */
                    708: {
                    709:     int i, j;
                    710:     double V[4], Res[4],       /* Homogeneous coords. vectors. */
                    711:      w = trans_mat[3][3];
                    712:     /* Normalize object space to -1..1 */
                    713:     V[0] = map_x3d(x);
                    714:     V[1] = map_y3d(y);
                    715:     V[2] = map_z3d(z);
                    716:     V[3] = 1.0;
                    717:     Res[0] = 0;                        /*HBB 961110: lclint wanted this... Why? */
                    718:     for (i = 0; i < 3; i++) {
                    719:        Res[i] = trans_mat[3][i];       /* Initiate it with the weight factor. */
                    720:        for (j = 0; j < 3; j++)
                    721:            Res[i] += V[j] * trans_mat[j][i];
                    722:     }
                    723:     for (i = 0; i < 3; i++)
                    724:        w += V[i] * trans_mat[i][3];
                    725:     if (w == 0)
                    726:        w = 1.0e-5;
                    727:     v->x = Res[0] / w;
                    728:     v->y = Res[1] / w;
                    729:     v->z = Res[2] / w;
                    730: }
                    731:
                    732:
                    733: /* remove unnecessary Vertices from a polygon: */
                    734: static int reduce_polygon(n, v, line, nmin)
                    735: int *n;                                /* number of vertices */
                    736: long **v;                      /* the vertices */
                    737: long *line;                    /* information which line should be drawn */
                    738: int nmin;                      /* if the number reduces under nmin, forget polygon */
                    739:      /* Return value 1: the reduced polygon has still more or equal
                    740:         vertices than nmin.
                    741:         Return value 0: the polygon was trivial; memory is given free */
                    742: {
                    743:     int less, i;
                    744:     long *w = *v;
                    745:     for (less = 0, i = 0; i < *n - 1; i++) {
                    746:        if (V_EQUAL(vlist + w[i], vlist + w[i + 1])
                    747:        /* HBB 970321: try to remove an endless loop bug (part1/2) */
                    748:            && ((w[i] == w[i + 1])
                    749:                || !GETBIT(*line, i)
                    750:                || GETBIT(*line, i + 1)
                    751:            || ((i > 0) ? GETBIT(*line, i - 1) : GETBIT(*line, *n - 1))))
                    752:            less++;
                    753:        else if (less) {
                    754:            w[i - less] = w[i];
                    755:            SETBIT(*line, i - less, GETBIT(*line, i));
                    756:        }
                    757:     }
                    758:     if (i - less > 0
                    759:        && V_EQUAL(vlist + w[i], vlist + w[0])
                    760:     /* HBB 970321: try to remove an endless loop bug (part2/2) */
                    761:        && (w[i] == w[0]
                    762:            || !GETBIT(*line, i)
                    763:            || GETBIT(*line, i - 1)
                    764:            || GETBIT(*line, 0)))
                    765:        less++;
                    766:     else if (less) {
                    767:        w[i - less] = w[i];
                    768:        SETBIT(*line, i - less, GETBIT(*line, i));
                    769:     }
                    770:     *n -= less;
                    771:     if (*n < nmin) {
                    772:        free(w);
                    773:        *v = 0;                 /* HBB 980213: signal that v(==w) is free()d */
                    774:        return 0;
                    775:     }
                    776:     if (less) {
                    777:        w = (long *) gp_realloc(w, (unsigned long) sizeof(long) * (*n),
                    778:                                "hidden red_poly");
                    779:        *v = w;
                    780:        for (; less > 0; less--)
                    781:            SETBIT(*line, *n + less - 1, 0);
                    782:     }
                    783:     return 1;
                    784: }
                    785:
                    786: /* Write polygon in plist */
                    787: /*
                    788:  * HBB: changed this to precalculate {x|y}{min|max}
                    789:  */
                    790: static void build_polygon(p, n, v, line, style, lp, next, next_frag, id, tested)
                    791: struct Polygon GPHUGE *p;      /* this should point at a free entry in plist */
                    792: int n;                         /* number of vertices */
                    793: long *v;                       /* array of indices on the vertices (in vlist) */
                    794: long line;                     /* information, which line should be drawn */
                    795: int style;                     /* color of the lines */
                    796: struct lp_style_type *lp;      /* pointer to line/point properties */
                    797: long next;                     /* next polygon in the list */
                    798: long next_frag;                        /* next fragment of same polygon */
                    799: int id;                                /* Which polygons belong together? */
                    800: t_poly_tested tested;          /* Is polygon already on the right place of list? */
                    801: {
                    802:     int i;
                    803:     struct Vertex vert;
                    804:
                    805:     if (p >= plist + npoly)
                    806:        fputs("uh oh !\n", stderr);
                    807:
                    808:     CHECK_POINTER(plist, p);
                    809:
                    810:     p->n = n;
                    811:     p->vertex = v;
                    812:     p->line = line;
                    813:     p->lp = lp;                        /* line and point properties */
                    814:     p->style = style;
                    815:     CHECK_POINTER(vlist, (vlist + v[0]));
                    816:     vert = vlist[v[0]];
                    817:     p->xmin = p->xmax = vert.x;
                    818:     p->ymin = p->ymax = vert.y;
                    819:     p->zmin = p->zmax = vert.z;
                    820:     for (i = 1; i < n; i++) {
                    821:        CHECK_POINTER(vlist, (vlist + v[i]));
                    822:        vert = vlist[v[i]];
                    823:        if (vert.x < p->xmin)
                    824:            p->xmin = vert.x;
                    825:        else if (vert.x > p->xmax)
                    826:            p->xmax = vert.x;
                    827:        if (vert.y < p->ymin)
                    828:            p->ymin = vert.y;
                    829:        else if (vert.y > p->ymax)
                    830:            p->ymax = vert.y;
                    831:        if (vert.z < p->zmin)
                    832:            p->zmin = vert.z;
                    833:        else if (vert.z > p->zmax)
                    834:            p->zmax = vert.z;
                    835:     }
                    836:
                    837: #if TEST_GRIDCHECK
                    838: /* FIXME: this should probably use a table of bit-patterns instead... */
                    839:     p->xextent = (~(~0U << (unsigned int) ((p->xmax + 1.0) / 2.0 * UINT_BITS + 1.0)))
                    840:        & (~0U << (unsigned int) ((p->xmin + 1.0) / 2.0 * UINT_BITS));
                    841:     p->yextent = (~(~0U << (unsigned int) ((p->ymax + 1.0) / 2.0 * UINT_BITS + 1.0)))
                    842:        & (~0U << (unsigned int) ((p->ymin + 1.0) / 2.0 * UINT_BITS));
                    843: #endif
                    844:
                    845:     p->next = next;
                    846:     p->next_frag = next_frag;  /* HBB 961201: link fragments, to speed up draw() q-loop */
                    847:     p->id = id;
                    848:     p->tested = tested;
                    849: }
                    850:
                    851:
                    852: /* get the amount of curves in a plot */
                    853: #define GETNCRV(NCRV) do {\
                    854:    if(this_plot->plot_type == FUNC3D)        \
                    855:      for(icrvs = this_plot->iso_crvs,NCRV = 0; \
                    856:         icrvs;icrvs = icrvs->next,NCRV++);  \
                    857:    else if(this_plot->plot_type == DATA3D) \
                    858:         NCRV = this_plot->num_iso_read;    \
                    859:     else {                                 \
                    860:        graph_error("Plot type is neither function nor data"); \
                    861:        return; /* stops a gcc -Wunitialised warning */        \
                    862:     } \
                    863: } while (0)
                    864:
                    865: /* Do we see the top or bottom of the polygon, or is it 'on edge'? */
                    866: #define GET_SIDE(vlst,csign) do { \
                    867:   double c = vlist[vlst[0]].x * (vlist[vlst[1]].y - vlist[vlst[2]].y) + \
                    868:     vlist[vlst[1]].x * (vlist[vlst[2]].y - vlist[vlst[0]].y) + \
                    869:     vlist[vlst[2]].x * (vlist[vlst[0]].y - vlist[vlst[1]].y); \
                    870:   csign = SIGNOF (c); \
                    871: } while (0)
                    872:
                    873: /* HBB 970131: new function, to allow handling of undefined datapoints
                    874:  * by leaving out the corresponding polygons from the list.
                    875:  * Return Value: 1 if polygon was built, 0 otherwise */
                    876: static GP_INLINE int maybe_build_polygon(p, n, v, line, style, lp,
                    877:                                         next, next_frag, id, tested)
                    878: struct Polygon GPHUGE *p;
                    879: struct lp_style_type *lp;
                    880: int n, style, id;
                    881: t_poly_tested tested;
                    882: long *v, line, next, next_frag;
                    883: {
                    884:     int i;
                    885:
                    886:     assert(v);
                    887:
                    888:     if (hiddenHandleUndefinedPoints != UNHANDLED)
                    889:        for (i = 0; i < n; i++)
                    890:            if (VERTEX_IS_UNDEFINED(vlist[v[i]])) {
                    891:                free(v);        /* HBB 980213: free mem... */
                    892:                v = 0;
                    893:                return 0;       /* *don't* build the polygon! */
                    894:            }
                    895:     build_polygon(p, n, v, line, style, lp, next, next_frag, id, tested);
                    896:     return 1;
                    897: }
                    898:
                    899: /* HBB 970322: new macro, invented because code like this occured several
                    900:  * times inside init_polygons, esp. after I added the option to choose the
                    901:  * other diagonal to divide a quad when necessary */
                    902: /* HBB 980213: Here and below in init_polygons, added code to properly
                    903:  * free any allocated vertex lists ('v' here), or avoid allocating
                    904:  * them in the first place. Thanks to Stefan Schroepfer for reporting
                    905:  * the leak.  */
                    906: #define PREPARE_POLYGON(n,v,i0,i1,i2,line,c,border,i_chk,ncrv_chk,style) do {\
                    907:   (n) = 3; \
                    908:   if (VERTEX_IS_UNDEFINED(vlist[vert_free + (i0)])\
                    909:       || VERTEX_IS_UNDEFINED(vlist[vert_free + (i1)]) \
                    910:       || VERTEX_IS_UNDEFINED(vlist[vert_free + (i2)])) { \
                    911:     /* These values avoid any further action on this polygon */\
                    912:     (v) = 0; /* flag this as undefined */ \
                    913:     (c) = (border) = 0; \
                    914:   } else {\
1.1.1.3 ! ohara     915:   (v) = (long *) gp_alloc (sizeof (long) * (n), "hidden PREPARE_POLYGON"); \
1.1       maekawa   916:   (v)[0] = vert_free + (i0);\
                    917:   (v)[1] = vert_free + (i1);\
                    918:   (v)[2] = vert_free + (i2);\
                    919:   (line) = hiddenTriangleLinesdrawnPattern;\
                    920:     GET_SIDE((v),(c));\
                    921:     /* Is this polygon at the border of the surface? */\
                    922:     (border) = (i == (i_chk) || ncrv == (ncrv_chk));\
                    923:   }\
                    924:   (style) = ((c) >= 0) ? above : below;\
                    925: } while (0)
                    926:
                    927: static void init_polygons(plots, pcount)
                    928: struct surface_points *plots;
                    929: int pcount;
                    930:      /* Initialize vlist, plist */
                    931: {
                    932:     long int i;
                    933:     struct surface_points *this_plot;
                    934:     int surface;
                    935:     long int ncrv, ncrv1;
                    936:     struct iso_curve *icrvs;
                    937:     int row_offset;
                    938:     int id;
                    939:     int n1, n2;                        /* number of vertices of a Polygon */
                    940:     long *v1, *v2;             /* the Vertices */
                    941:     long line1, line2;         /* which  lines should be drawn */
                    942:     int above = -1, below, style1, style2;     /* the line color */
                    943:     struct lp_style_type *lp;  /* pointer to line and point properties */
                    944:     int c1, c2;                        /* do we see the front or the back */
                    945:     TBOOLEAN border1, border2; /* is it at the border of the surface */
                    946:
                    947:     /* allocate memory for polylist and nodelist */
                    948:     nvert = npoly = 0;
                    949:     for (this_plot = plots, surface = 0;
                    950:         surface < pcount;
                    951:         this_plot = this_plot->next_sp, surface++) {
                    952:        GETNCRV(ncrv);
                    953:        switch (this_plot->plot_style) {
                    954:        case LINESPOINTS:
                    955:        case STEPS:             /* handle as LINES */
                    956:        case FSTEPS:
                    957:        case HISTEPS:
                    958:        case LINES:
                    959: #if FOUR_TRIANGLES
                    960:            nvert += ncrv * (2 * this_plot->iso_crvs->p_count - 1);
                    961: #else
                    962:            nvert += ncrv * (this_plot->iso_crvs->p_count);
                    963: #endif
                    964:            npoly += 2 * (ncrv - 1) * (this_plot->iso_crvs->p_count - 1);
                    965:            break;
                    966:        case DOTS:
                    967:        case XERRORBARS:        /* handle as POINTSTYLE */
                    968:        case YERRORBARS:
                    969:        case XYERRORBARS:
                    970:        case BOXXYERROR:
                    971:        case BOXERROR:
                    972:        case CANDLESTICKS:      /* HBB: these as well */
                    973:        case FINANCEBARS:
                    974:        case VECTOR:
                    975:        case POINTSTYLE:
                    976:            nvert += ncrv * (this_plot->iso_crvs->p_count);
                    977:            npoly += (ncrv - 1) * (this_plot->iso_crvs->p_count - 1);
                    978:            break;
                    979:        case BOXES:             /* handle as IMPULSES */
                    980:        case IMPULSES:
                    981:            nvert += 2 * ncrv * (this_plot->iso_crvs->p_count);
                    982:            npoly += (ncrv - 1) * (this_plot->iso_crvs->p_count - 1);
                    983:            break;
                    984:        }
                    985:     }
                    986:     vlist = (struct Vertex GPHUGE *)
1.1.1.3 ! ohara     987:        gp_alloc(sizeof(struct Vertex) * nvert, "hidden vlist");
1.1       maekawa   988:     plist = (struct Polygon GPHUGE *)
1.1.1.3 ! ohara     989:        gp_alloc(sizeof(struct Polygon) * npoly, "hidden plist");
1.1       maekawa   990:
                    991:     /* initialize vlist: */
                    992:     for (vert_free = 0, this_plot = plots, surface = 0;
                    993:         surface < pcount;
                    994:         this_plot = this_plot->next_sp, surface++) {
                    995:        switch (this_plot->plot_style) {
                    996:        case LINESPOINTS:
                    997:        case BOXERROR:          /* handle as POINTSTYLE */
                    998:        case BOXXYERROR:
                    999:        case XERRORBARS:
                   1000:        case YERRORBARS:
                   1001:        case XYERRORBARS:
                   1002:        case CANDLESTICKS:      /* HBB: these as well */
                   1003:        case FINANCEBARS:
                   1004:        case VECTOR:
                   1005:        case POINTSTYLE:
                   1006:            above = this_plot->lp_properties.p_type;
                   1007:            break;
                   1008:        case STEPS:             /* handle as LINES */
                   1009:        case FSTEPS:
                   1010:        case HISTEPS:
                   1011:        case LINES:
                   1012:        case DOTS:
                   1013:        case BOXES:             /* handle as IMPULSES */
                   1014:        case IMPULSES:
                   1015:            above = -1;
                   1016:            break;
                   1017:        }
                   1018:        GETNCRV(ncrv1);
                   1019:        for (ncrv = 0, icrvs = this_plot->iso_crvs;
                   1020:             ncrv < ncrv1 && icrvs;
                   1021:             ncrv++, icrvs = icrvs->next) {
                   1022:            struct coordinate GPHUGE *points = icrvs->points;
                   1023:
                   1024:            for (i = 0; i < icrvs->p_count; i++) {
                   1025:                /* As long as the point types keep OUTRANGE == 1 and
                   1026:                 * UNDEFINED == 2, we can just compare
                   1027:                 * hiddenHandleUndefinedPoints to the type of the point. To
                   1028:                 * simplify this, let UNHANDLED := UNDEFINED+1 mean 'do not
                   1029:                 * handle undefined or outranged points at all' (dangerous
                   1030:                 * option, that is...) */
                   1031:                if (points[i].type >= hiddenHandleUndefinedPoints) {
                   1032:                    /* mark this vertex as a bad one */
                   1033:                    FLAG_VERTEX_AS_UNDEFINED(vlist[vert_free++]);
                   1034:                    continue;
                   1035:                }
                   1036:                map3d_xyz(points[i].x, points[i].y, points[i].z, vlist + vert_free);
                   1037:                vlist[vert_free++].style = above;
                   1038:                if (this_plot->plot_style == IMPULSES
                   1039:                    || this_plot->plot_style == BOXES) {
                   1040:                    map3d_xyz(points[i].x, points[i].y, min_array[FIRST_Z_AXIS], vlist + vert_free);
                   1041:                    vlist[vert_free++].style = above;
                   1042:                }
                   1043: #if FOUR_TRIANGLES
                   1044:                /* FIXME: handle other styles as well! */
                   1045:                if (this_plot->plot_style == LINES &&
                   1046:                    i < icrvs->p_count - 1)
                   1047:                    vert_free++;        /* keep one entry free for quad-center */
                   1048: #endif
                   1049:            }
                   1050:        }
                   1051:     }
                   1052:
                   1053:     /* initialize plist: */
                   1054:     id = 0;
                   1055:     for (pfree = vert_free = 0, this_plot = plots, surface = 0;
                   1056:         surface < pcount;
                   1057:         this_plot = this_plot->next_sp, surface++) {
                   1058:        row_offset = this_plot->iso_crvs->p_count;
                   1059:        lp = &(this_plot->lp_properties);
                   1060:        above = this_plot->lp_properties.l_type;
                   1061:        below = this_plot->lp_properties.l_type + hiddenBacksideLinetypeOffset;
                   1062:        GETNCRV(ncrv1);
                   1063:        for (ncrv = 0, icrvs = this_plot->iso_crvs;
                   1064:             ncrv < ncrv1 && icrvs;
                   1065:             ncrv++, icrvs = icrvs->next)
                   1066:            for (i = 0; i < icrvs->p_count; i++)
                   1067:                switch (this_plot->plot_style) {
                   1068:                case LINESPOINTS:
                   1069:                case STEPS:     /* handle as LINES */
                   1070:                case FSTEPS:
                   1071:                case HISTEPS:
                   1072:                case LINES:
                   1073:                    if (i < icrvs->p_count - 1 && ncrv < ncrv1 - 1) {
                   1074: #if FOUR_TRIANGLES
                   1075:                        long *v3, *v4;
                   1076:                        int n3, n4;
                   1077:                        long line3, line4;
                   1078:                        int c3, c4, style3, style4;
                   1079:                        TBOOLEAN border3, border4, inc_id = FALSE;
                   1080:
                   1081:                        /* Build medium vertex: */
                   1082:                        vlist[vert_free + 1].x =
                   1083:                            (vlist[vert_free].x + vlist[vert_free + 2 * row_offset - 1].x +
                   1084:                             vlist[vert_free + 2].x + vlist[vert_free + 2 * row_offset + 1].x
                   1085:                            ) / 4;
                   1086:                        vlist[vert_free + 1].y =
                   1087:                            (vlist[vert_free].y + vlist[vert_free + 2 * row_offset - 1].y +
                   1088:                             vlist[vert_free + 2].y + vlist[vert_free + 2 * row_offset + 1].y
                   1089:                            ) / 4;
                   1090:                        vlist[vert_free + 1].z =
                   1091:                            (vlist[vert_free].z + vlist[vert_free + 2 * row_offset - 1].z +
                   1092:                             vlist[vert_free + 2].z + vlist[vert_free + 2 * row_offset + 1].z
                   1093:                            ) / 4;
                   1094:                        vlist[vert_free + 1].style = above;
                   1095:
                   1096:                        PREPARE_POLYGON(n1, v1, 2, 0, 1, line1, c1,
                   1097:                                        border1, 0, -1, style1);
                   1098:                        /* !!FIXME!! special casing (see the older code) still needs to be
                   1099:                         * implemented! */
                   1100:                        if ((c1 || border1)
                   1101:                            && reduce_polygon(&n1, &v1, &line1, 3)) {
                   1102:                            CHECK_PLIST();
                   1103:                            pfree += maybe_build_polygon(plist + pfree, n1, v1, line1,
                   1104:                                              style1, lp, -1L, -1L, id++,
                   1105:                                                         is_untested);
                   1106:                            inc_id = TRUE;
                   1107:                        }
                   1108:                        PREPARE_POLYGON(n2, v2, 0, 2 * row_offset - 1, 1, line2, c2,
                   1109:                                        border2, -1, 0, style2);
                   1110:                        if ((c2 || border2)
                   1111:                            && reduce_polygon(&n2, &v2, &line2, 3)) {
                   1112:                            CHECK_PLIST();
                   1113:                            pfree += maybe_build_polygon(plist + pfree, n2, v2, line2,
                   1114:                                              style2, lp, -1L, -1L, id++,
                   1115:                                                         is_untested);
                   1116:                            inc_id = TRUE;
                   1117:                        }
                   1118:                        PREPARE_POLYGON(n3, v3, 2 * row_offset - 1, 2 * row_offset + 1, 1,
                   1119:                              line3, c3, border3, icrvs->p_count - 2, -1,
                   1120:                                        style3);
                   1121:                        if ((c3 || border3)
                   1122:                            && reduce_polygon(&n3, &v3, &line3, 3)) {
                   1123:                            CHECK_PLIST();
                   1124:                            pfree += maybe_build_polygon(plist + pfree, n3, v3, line3,
                   1125:                                              style3, lp, -1L, -1L, id++,
                   1126:                                                         is_untested);
                   1127:                            inc_id = TRUE;
                   1128:                        }
                   1129:                        PREPARE_POLYGON(n4, v4, 2 * row_offset + 1, 0, 1, line4, c4,
                   1130:                                        border4, -1, ncrv1 - 2, style4);
                   1131:                        if ((c4 || border4)
                   1132:                            && reduce_polygon(&n4, &v4, &line4, 3)) {
                   1133:                            CHECK_PLIST();
                   1134:                            pfree += maybe_build_polygon(plist + pfree, n4, v4, line4,
                   1135:                                              style4, lp, -1L, -1L, id++,
                   1136:                                                         is_untested);
                   1137:                            inc_id = TRUE;
                   1138:                        }
                   1139:                        /*if (inc_id)
                   1140:                           id++; */
                   1141:                        vert_free++;
                   1142:
                   1143: #else /* FOUR_TRIANGLES */
                   1144:
                   1145:                        PREPARE_POLYGON(n1, v1, row_offset, 0, 1, line1, c1,
                   1146:                                        border1, 0, 0, style1);
                   1147:                        PREPARE_POLYGON(n2, v2, 1, row_offset + 1, row_offset, line2,
                   1148:                              c2, border2, icrvs->p_count - 2, ncrv1 - 2,
                   1149:                                        style2);
                   1150:
                   1151:                        /* if this makes at least one of the two triangles
                   1152:                         * visible, use the other diagonal here */
                   1153:                        if (hiddenShowAlternativeDiagonal
                   1154:                            && !(v1)    /* HBB 980213: only try this in the case of */
                   1155:                            &&!(v2)     /* undefined vertices -> *missing* trigs */
                   1156:                            ) {
                   1157:                            if (VERTEX_IS_UNDEFINED(vlist[vert_free + 1])) {
                   1158:                                PREPARE_POLYGON(n1, v1, row_offset + 1, row_offset, 0,
                   1159:                                        line1, c1, border1, 0, ncrv1 - 2,
                   1160:                                                style1);
                   1161:                            } else if (VERTEX_IS_UNDEFINED(vlist[vert_free + row_offset])) {
                   1162:                                PREPARE_POLYGON(n1, v1, 0, 1, row_offset + 1, line1,
                   1163:                                      c1, border1, icrvs->p_count - 2, 0,
                   1164:                                                style1);
                   1165:                            }
                   1166:                        }
                   1167:                        /* HBB 970323: if visible sides of the two triangles
                   1168:                         * differs, make diagonal visible! */
                   1169:                        /* HBB 970428: FIXME: should this be changed to only
                   1170:                         * activate *one* of the triangles' diagonals? If so, how
                   1171:                         * to find out the right one? Maybe the one with its
                   1172:                         * normal closer to the z direction? */
                   1173:                        if (hiddenHandleBentoverQuadrangles
                   1174:                            && (c1 * c2) < 0
                   1175:                            ) {
                   1176:                            SETBIT(line1, n1 - 1, 1);
                   1177:                            SETBIT(line2, n2 - 1, 1);
                   1178:                        }
                   1179:                        if ((c1 || border1)
                   1180:                            && reduce_polygon(&n1, &v1, &line1, 3)) {
                   1181:                            if ((c2 || border2)
                   1182:                                && reduce_polygon(&n2, &v2, &line2, 3)) {
                   1183:                                /* These two will need special handling, to
                   1184:                                 * ensure the links from one to the other
                   1185:                                 * are only set up when *both* polygons are
                   1186:                                 * valid */
                   1187:                                int r1, r2;     /* temp. results */
                   1188:
                   1189:                                CHECK_PLIST_2();
                   1190:                                r1 = maybe_build_polygon(plist + pfree, n1, v1,
                   1191:                                                  line1, style1, lp, -1L,
                   1192:                                                   -1L, id, is_untested);
                   1193:                                r2 = maybe_build_polygon(plist + pfree + r1, n2, v2,
                   1194:                                                  line2, style2, lp, -1L,
                   1195:                                                 -1L, id++, is_untested);
                   1196:                                if (r1 && r2) {
                   1197:                                    plist[pfree].next_frag = pfree + 1;
                   1198:                                    plist[pfree + 1].next_frag = pfree;
                   1199:                                }
                   1200:                                pfree += r1 + r2;
                   1201:                            } else {    /* P1 was ok, but P2 wasn't */
                   1202: /* HBB 980213: P2 is invisible, so free its vertex list: */
                   1203:                                if (v2) {
                   1204:                                    free(v2);
                   1205:                                    v2 = 0;
                   1206:                                }
                   1207: /* HBB 970323: if other polygon wasn't drawn, draw this polygon's
                   1208:  * diagonal visibly (not only if it was 'on edge'). */
                   1209:                                /*if (c2 || border2) */
                   1210:                                SETBIT(line1, n1 - 1, 1);
                   1211:                                CHECK_PLIST();
                   1212:                                pfree += maybe_build_polygon(plist + pfree, n1, v1, line1,
                   1213:                                              style1, lp, -1L, -1L, id++,
                   1214:                                                             is_untested);
                   1215:                            }
                   1216:                        } else {        /* P1 was not ok */
                   1217: /* HBB 980213: P1 is invisible, so free its vertex list: */
                   1218:                            if (v1) {
                   1219:                                free(v1);
                   1220:                                v1 = 0;
                   1221:                            }
                   1222: /* HBB 970323: if other polygon wasn't drawn, draw this polygon's
                   1223:  * diagonal visibly (not only if it was 'on edge'). */
                   1224:                            /*if (c1 || border1) */
                   1225:                            SETBIT(line2, n2 - 1, 1);
                   1226: /* HBB 970522: yet another problem triggered by the handling of
                   1227:  * undefined points: if !(c2||border2), we mustn't try to reduce
                   1228:  * triangle 2. */
                   1229:                            if (0
                   1230:                                || (1
                   1231:                                    && (c2 || border2)
                   1232:                                  && reduce_polygon(&n2, &v2, &line2, 2))
                   1233:                                || (1
                   1234: /* HBB 980213: reduce_... above might have zeroed v... */
                   1235:                                    && (v2)
                   1236:                                    && (c1 || border1))) {
                   1237:                                CHECK_PLIST();
                   1238:                                pfree += maybe_build_polygon(plist + pfree, n2, v2, line2,
                   1239:                                              style2, lp, -1L, -1L, id++,
                   1240:                                                             is_untested);
                   1241:                            } else {
                   1242:                                /* HBB 980213: sigh... both P1 and P2 were invisible, but
                   1243:                                 * at least one of them was a not undefined.. */
                   1244:                                if (v1)
                   1245:                                    free(v1);
                   1246:                                if (v2)
                   1247:                                    free(v2);
                   1248:                            }
                   1249:                        }
                   1250: #endif /* else: FOUR_TRIANGLES */
                   1251:                    }
                   1252:                    vert_free++;
                   1253:                    break;
                   1254:                case DOTS:
1.1.1.3 ! ohara    1255:                    v1 = (long *) gp_alloc(sizeof(long) * 1,
1.1       maekawa  1256:                                           "hidden v1 for dots");
                   1257:                    v1[0] = vert_free++;
                   1258:                    CHECK_PLIST();
                   1259:                    pfree += maybe_build_polygon(plist + pfree, 1, v1, 1L, above,
                   1260:                                        lp, -1L, -1L, id++, is_untested);
                   1261:                    break;
                   1262:                case BOXERROR:  /* handle as POINTSTYLE */
                   1263:                case BOXXYERROR:
                   1264:                case XERRORBARS:        /* handle as POINTSTYLE */
                   1265:                case YERRORBARS:
                   1266:                case XYERRORBARS:
                   1267:                case CANDLESTICKS:      /* HBB: these as well */
                   1268:                case FINANCEBARS:
                   1269:                case POINTSTYLE:
                   1270:                case VECTOR:
1.1.1.3 ! ohara    1271:                    v1 = (long *) gp_alloc(sizeof(long) * 1,
1.1       maekawa  1272:                                           "hidden v1 for point");
                   1273:                    v1[0] = vert_free++;
                   1274:                    CHECK_PLIST();
                   1275:                    pfree += maybe_build_polygon(plist + pfree, 1, v1, 0L, above,
                   1276:                                        lp, -1L, -1L, id++, is_untested);
                   1277:                    break;
                   1278:                case BOXES:     /* handle as IMPULSES */
                   1279:                case IMPULSES:
                   1280:                    n1 = 2;
1.1.1.3 ! ohara    1281:                    v1 = (long *) gp_alloc(sizeof(long) * n1,
1.1       maekawa  1282:                                           "hidden v1 for impulse");
                   1283:                    v1[0] = vert_free++;
                   1284:                    v1[1] = vert_free++;
                   1285:                    line1 = 2L;
                   1286:                    (void) reduce_polygon(&n1, &v1, &line1, 1);
                   1287:                    CHECK_PLIST();
                   1288:                    pfree += maybe_build_polygon(plist + pfree, n1, v1, line1, above,
                   1289:                                        lp, -1L, -1L, id++, is_untested);
                   1290:                    break;
                   1291:                }
                   1292:     }
                   1293: }
                   1294:
1.1.1.3 ! ohara    1295: int compare_by_zmax(p1, p2)
        !          1296:     SORTFUNC_ARGS p1;
        !          1297:     SORTFUNC_ARGS p2;
1.1       maekawa  1298: {
1.1.1.3 ! ohara    1299:     return (SIGNOF(plist[*(const long *) p2].zmax
        !          1300:                   - plist[*(const long *) p1].zmax));
1.1       maekawa  1301: }
                   1302:
                   1303: static void sort_by_zmax()
                   1304:      /* and build the list (return_value = start of list) */
                   1305: {
                   1306:     long *sortarray, i;
                   1307:     struct Polygon GPHUGE *this;
1.1.1.3 ! ohara    1308:     sortarray = (long *) gp_alloc(sizeof(long) * pfree, "hidden sortarray");
1.1       maekawa  1309:     for (i = 0; i < pfree; i++)
                   1310:        sortarray[i] = i;
                   1311:     qsort(sortarray, (size_t) pfree, sizeof(long), compare_by_zmax);
                   1312:     this = plist + sortarray[0];
                   1313:     for (i = 1; i < pfree; i++) {
                   1314:        this->next = sortarray[i];
                   1315:        this = plist + sortarray[i];
                   1316:     }
                   1317:     this->next = -1L;
                   1318:     pfirst = sortarray[0];
                   1319:     free(sortarray);
                   1320: }
                   1321:
                   1322:
                   1323: /* HBB: try if converting this code to unsigned int (from signed shorts)
                   1324:  *  fixes any of the remaining bugs. In the same motion, remove
                   1325:  *  hardcoded sizeof(short) = 2 (09.10.1996) */
                   1326:
                   1327: #define LASTBITS (USHRT_BITS -1)       /* ????? */
                   1328: static int obscured(p)
                   1329:      /* is p obscured by already drawn polygons? (only a simple minimax-test) */
                   1330: struct Polygon GPHUGE *p;
                   1331: {
                   1332:     int l_xmin, l_xmax, l_ymin, l_ymax;                /* HBB 961110: avoid shadowing external names */
                   1333:     t_pnt mask1, mask2;
                   1334:     long indx1, indx2, k, m;
                   1335:     tp_pnt cpnt;
                   1336:     /* build the minimax-box */
                   1337:     l_xmin = (p->xmin * xscaler) + xmiddle;
                   1338:     l_xmax = (p->xmax * xscaler) + xmiddle;
                   1339:     l_ymin = (p->ymin * yscaler) + ymiddle;
                   1340:     l_ymax = (p->ymax * yscaler) + ymiddle;
                   1341:     if (l_xmin < xleft)
                   1342:        l_xmin = xleft;
                   1343:     if (l_xmax > xright)
                   1344:        l_xmax = xright;
                   1345:     if (l_ymin < ybot)
                   1346:        l_ymin = ybot;
                   1347:     if (l_ymax > ytop)
                   1348:        l_ymax = ytop;
                   1349:     if (l_xmin > l_xmax || l_ymin > l_ymax)
                   1350:        return 1;               /* not viewable */
                   1351:     l_ymin = YREDUCE(l_ymin) - YREDUCE(ybot);
                   1352:     l_ymax = YREDUCE(l_ymax) - YREDUCE(ybot);
                   1353:     l_xmin = XREDUCE(l_xmin) - XREDUCE(xleft);
                   1354:     l_xmax = XREDUCE(l_xmax) - XREDUCE(xleft);
                   1355:     /* Now check bitmap */
                   1356:     indx1 = l_ymin / PNT_BITS;
                   1357:     indx2 = l_ymax / PNT_BITS;
                   1358:     mask1 = PNT_MAX << (((unsigned) l_ymin) % PNT_BITS);
                   1359:     mask2 = PNT_MAX >> ((~((unsigned) l_ymax)) % PNT_BITS);
                   1360:     /* HBB: lclint wanted this: */
                   1361:     assert(pnt != 0);
                   1362:     for (m = l_xmin; m <= l_xmax; m++) {
                   1363:        if (pnt[m] == 0)
                   1364:            return 0;           /* not obscured */
                   1365:        cpnt = pnt[m] + indx1;
                   1366:        if (indx1 == indx2) {
                   1367:            if (~(*cpnt) & mask1 & mask2)
                   1368:                return 0;
                   1369:        } else {
                   1370:            if (~(*cpnt++) & mask1)
                   1371:                return 0;
                   1372:            for (k = indx1 + 1; k < indx2; k++)
                   1373:                if ((*cpnt++) != PNT_MAX)
                   1374:                    return 0;
                   1375:            if (~(*cpnt++) & mask2)
                   1376:                return 0;
                   1377:        }
                   1378:     }
                   1379:     return 1;
                   1380: }
                   1381:
                   1382:
                   1383: void draw_line_hidden(x1, y1, x2, y2)
                   1384: unsigned int x1, y1, x2, y2;
                   1385: {
                   1386:     register struct termentry *t = term;
                   1387:     TBOOLEAN flag;
                   1388:     register int xv, yv, errx, erry, err;
                   1389:     register unsigned int xvr, yvr;
                   1390:     int unsigned xve, yve;
                   1391:     register int dy, nstep = 0, dyr;
                   1392:     int i;
                   1393:
                   1394:     if (x1 > x2) {
                   1395:        xvr = x2;
                   1396:        yvr = y2;
                   1397:        xve = x1;
                   1398:        yve = y1;
                   1399:     } else {
                   1400:        xvr = x1;
                   1401:        yvr = y1;
                   1402:        xve = x2;
                   1403:        yve = y2;
                   1404:     };
                   1405:     errx = XREDUCE(xve) - XREDUCE(xvr);
                   1406:     erry = YREDUCE(yve) - YREDUCE(yvr);
                   1407:     dy = (erry > 0 ? 1 : -1);
                   1408:     dyr = dy * yfact;
                   1409:     switch (dy) {
                   1410:     case 1:
                   1411:        nstep = errx + erry;
                   1412:        errx = -errx;
                   1413:        break;
                   1414:     case -1:
                   1415:        nstep = errx - erry;
                   1416:        errx = -errx;
                   1417:        erry = -erry;
                   1418:        break;
                   1419:     };
                   1420:     err = errx + erry;
                   1421:     errx <<= 1;
                   1422:     erry <<= 1;
                   1423:     xv = XREDUCE(xvr) - XREDUCE(xleft);
                   1424:     yv = YREDUCE(yvr) - YREDUCE(ybot);
                   1425:     (*t->move) (xvr, yvr);
                   1426:     flag = !IS_UNSET(xv, yv);
                   1427:     if (!hidden_no_update) {   /* Check first point */
                   1428:        assert(ymax_hl != 0);
                   1429:        assert(ymin_hl != 0);
                   1430:        if (xv < xmin_hl)
                   1431:            xmin_hl = xv;
                   1432:        if (xv > xmax_hl)
                   1433:            xmax_hl = xv;
                   1434:        if (yv > ymax_hl[xv])
                   1435:            ymax_hl[xv] = yv;
                   1436:        if (yv < ymin_hl[xv])
                   1437:            ymin_hl[xv] = yv;
                   1438:     };
                   1439:     for (i = 0; i < nstep; i++) {
                   1440:        if (err < 0) {
                   1441:            xv++;
                   1442:            xvr += xfact;
                   1443:            err += erry;
                   1444:        } else {
                   1445:            yv += dy;
                   1446:            yvr += dyr;
                   1447:            err += errx;
                   1448:        };
                   1449:        if (IS_UNSET(xv, yv)) {
                   1450:            if (flag) {
                   1451:                (*t->move) (xvr, yvr);
                   1452:                flag = FALSE;
                   1453:            };
                   1454:        } else {
                   1455:            if (!flag) {
                   1456:                (*t->vector) (xvr, yvr);
                   1457:                flag = TRUE;
                   1458:            };
                   1459:        };
                   1460:        if (!hidden_no_update) {
                   1461:            /* HBB 961110: lclint wanted these: */
                   1462:            assert(ymax_hl != 0);
                   1463:            assert(ymin_hl != 0);
                   1464:            if (xv < xmin_hl)
                   1465:                xmin_hl = xv;
                   1466:            if (xv > xmax_hl)
                   1467:                xmax_hl = xv;
                   1468:            if (yv > ymax_hl[xv])
                   1469:                ymax_hl[xv] = yv;
                   1470:            if (yv < ymin_hl[xv])
                   1471:                ymin_hl[xv] = yv;
                   1472:        };
                   1473:     };
                   1474:     if (!flag)
                   1475:        (*t->vector) (xve, yve);
                   1476:     return;
                   1477: }
                   1478:
                   1479:
                   1480: static GP_INLINE int xy_overlap(a, b)
                   1481:      /* Do a and b overlap in x or y (minimax test) */
                   1482: struct Polygon GPHUGE *a, GPHUGE * b;
                   1483: {
                   1484: #if TEST_GRIDCHECK
                   1485:     /* First, check by comparing the extent bit patterns: */
                   1486:     if (!((a->xextent & b->xextent) && (a->yextent & b->yextent)))
                   1487:        return 0;
                   1488: #endif
                   1489:     return ((int) (GE(b->xmax, a->xmin) && GE(a->xmax, b->xmin)
                   1490:                   && GE(b->ymax, a->ymin) && GE(a->ymax, b->ymin)));
                   1491: }
                   1492:
                   1493:
                   1494: static void get_plane(p, a, b, c, d)
                   1495: struct Polygon GPHUGE *p;
                   1496: double *a, *b, *c, *d;
                   1497: {
                   1498:     int i;
                   1499:     struct Vertex GPHUGE *v1, GPHUGE * v2;
                   1500:     double x, y, z, s;
                   1501:     if (p->n == 1) {
                   1502:        *a = 0.0;
                   1503:        *b = 0.0;
                   1504:        *c = 1.0;
                   1505:        *d = -vlist[p->vertex[0]].z;
                   1506:        return;
                   1507:     }
                   1508:     v1 = vlist + p->vertex[p->n - 1];
                   1509:     v2 = vlist + p->vertex[0];
                   1510:     *a = (v1->y - v2->y) * (v1->z + v2->z);
                   1511:     *b = (v1->z - v2->z) * (v1->x + v2->x);
                   1512:     *c = (v1->x - v2->x) * (v1->y + v2->y);
                   1513:     for (i = 0; i < p->n - 1; i++) {
                   1514:        v1 = vlist + p->vertex[i];
                   1515:        v2 = vlist + p->vertex[i + 1];
                   1516:        *a += (v1->y - v2->y) * (v1->z + v2->z);
                   1517:        *b += (v1->z - v2->z) * (v1->x + v2->x);
                   1518:        *c += (v1->x - v2->x) * (v1->y + v2->y);
                   1519:     }
                   1520:     s = sqrt(*a * *a + *b * *b + *c * *c);
                   1521:     if (GE(0.0, s)) {          /* => s==0 => the vertices are in one line */
                   1522:        v1 = vlist + p->vertex[0];
                   1523:        for (i = 1; i < p->n; i++) {
                   1524:            v2 = vlist + p->vertex[i];
                   1525:            if (!V_EQUAL(v1, v2))
                   1526:                break;
                   1527:        }
                   1528:        /* (x,y,z) is l.u. from <v1, v2> */
                   1529:        x = v1->x;
                   1530:        y = v1->y;
                   1531:        z = v1->z;
                   1532:        if (EQ(y, v2->y))
                   1533:            y += 1.0;
                   1534:        else
                   1535:            x += 1.0;
                   1536:        /* build a vector that is orthogonal to the line of the polygon */
                   1537:        *a = v1->y * (v2->z - z) + v2->y * (z - v1->z) + y * (v1->z - v2->z);
                   1538:        *b = v1->z * (v2->x - x) + v2->z * (x - v1->x) + z * (v1->x - v2->x);
                   1539:        *c = v1->x * (v2->y - y) + v2->x * (y - v1->y) + x * (v1->y - v2->y);
                   1540:        s = sqrt(*a * *a + *b * *b + *c * *c);
                   1541:     }
                   1542:     if (*c < 0.0)              /* ensure that normalized c is > 0 */
                   1543:        s *= -1.0;              /* The exact relation, because c can be very small */
                   1544:     *a /= s;
                   1545:     *b /= s;
                   1546:     *c /= s;
                   1547:     *d = -*a * v1->x - *b * v1->y - *c * v1->z;
                   1548:     return;
                   1549: }
                   1550:
                   1551:
                   1552: static t_poly_plane_intersect
                   1553:  polygon_plane_intersection(p, a, b, c, d)
                   1554: struct Polygon GPHUGE *p;
                   1555: double a, b, c, d;
                   1556: {
                   1557:     int i, sign, max_sign, min_sign;
                   1558:     struct Vertex GPHUGE *v;
                   1559:
                   1560:     CHECK_POINTER(plist, p);
                   1561:
                   1562:     v = vlist + p->vertex[0];
                   1563:     max_sign = min_sign = SIGNOF(a * v->x + b * v->y + c * v->z + d);
                   1564:     for (i = 1; i < p->n; i++) {
                   1565:        v = vlist + p->vertex[i];
                   1566:        sign = SIGNOF(a * v->x + b * v->y + c * v->z + d);
                   1567:        if (sign > max_sign)
                   1568:            max_sign = sign;
                   1569:        else if (sign < min_sign)
                   1570:            min_sign = sign;
                   1571:     }
                   1572:
                   1573:     /* Yes, this is a bit tricky, but it's simpler for the computer... */
                   1574:     if (min_sign == -1) {
                   1575:        if (max_sign == 1)
                   1576:            return (intersects);
                   1577:        else
                   1578:            return behind;
                   1579:     } else {
                   1580:        if ((max_sign == 0) && (min_sign == 0))
                   1581:            return (inside);
                   1582:        else
                   1583:            return infront;
                   1584:     }
                   1585: }
                   1586:
                   1587:
                   1588: /* full xy-overlap test (support routines first) */
                   1589:
                   1590: /* What do negative return values mean?
                   1591:    It is allowed, that the 2 polygons touch themselves in one point.
                   1592:    There are 2 possibilities of this case:
                   1593:    (A) A vertex of the one polygon is on an edge of the other
                   1594:    (B) The two polygons have a vertex together.
                   1595:    In case (A) the algorithm finds 2 edges, wich touches an edge of the
                   1596:    other polygon. In case (B) the algorithm finds four pairs of edges.
                   1597:    I handle both cases with negative return values:
                   1598:    Case (A) returns -2, and case (B) returns -1.
                   1599:    So I can say, if the sum of negative return values goes greater than 4
                   1600:    (absolutly), there must be more than one touch point. So the
                   1601:    polygons must overlap. */
                   1602:
                   1603: /* some variables, for keeping track of minima and maxima across
                   1604:  * all these routines */
                   1605:
                   1606: static double m1x, M1x, m1y, M1y, m2x, M2x, m2y, M2y;
                   1607:
                   1608: #define MINIMAX  (GE(M2x,m1x) && GE(M1x,m2x) && GE(M2y,m1y) && GE(M1y,m2y))
                   1609:
                   1610:
                   1611: /* Does the edge [v1,v2] intersect edge [v3, v4] ?
                   1612:  * This is for non-vertical [v1,v2]
                   1613:  */
                   1614: static int intersect(v1, v2, v3, v4)
                   1615: struct Vertex GPHUGE *v1, GPHUGE * v2, GPHUGE * v3, GPHUGE * v4;
                   1616: {
                   1617:     double m1, m2, t1, t2, x, y, minx, maxx;
                   1618:
                   1619:     m1 = (v2->y - v1->y) / (v2->x - v1->x);
                   1620:     t1 = v1->y - m1 * v1->x;
                   1621:
                   1622:     /* if [v3,v4] vertical: */
                   1623:     if (EQ(v3->x, v4->x)) {
                   1624:        y = v3->x * m1 + t1;
                   1625:        if (GR(m2x, m1x) && GR(M1x, m2x)) {
                   1626:            if (GR(y, m2y) && GR(M2y, y))
                   1627:                return 1;
                   1628:            if (EQ(y, m2y) || EQ(y, M2y))
                   1629:                return -2;
                   1630:            return 0;
                   1631:        }
                   1632:        /* m2x == m1x || m2x == M1x */
                   1633:        if (GR(y, m2y) && GR(M2y, y))
                   1634:            return -2;
                   1635:        if (EQ(y, m2y) || EQ(y, M2y))
                   1636:            return -1;
                   1637:        return 0;
                   1638:     }
                   1639:     /* [v3,v4] not vertical */
                   1640:     m2 = (v4->y - v3->y) / (v4->x - v3->x);
                   1641:     t2 = v3->y - m2 * v3->x;
                   1642:     if (!SIGNOF(m1 - m2)) {    /* if edges are parallel: */
                   1643:        x = m1 * v3->x + t1 - v3->y;
                   1644:        if (!EQ(m1 * v3->x + t1 - v3->y, 0.0))
                   1645:            return 0;
                   1646:        if (GR(M2x, m1x) && GR(M1x, m2x))
                   1647:            return 1;
                   1648:        return -1;              /* the edges have a common vertex */
                   1649:     }
                   1650:     x = (t2 - t1) / (m1 - m2);
                   1651:     minx = GPMAX(m1x, m2x);
                   1652:     maxx = GPMIN(M1x, M2x);
                   1653:     if (GR(x, minx) && GR(maxx, x))
                   1654:        return 1;
                   1655:     if (GR(minx, x) || GR(x, maxx))
                   1656:        return 0;
                   1657:     if ((EQ(x, m1x) || EQ(x, M1x)) && (EQ(x, m1x) || EQ(x, M1x)))
                   1658:        return -1;
                   1659:     return -2;
                   1660: }
                   1661:
                   1662: /* Does the edge [v1,v2] intersect edge [v3, v4] ?
                   1663:  * This is for vertical [v1,v2]
                   1664:  */
                   1665: static int v_intersect(v1, v2, v3, v4)
                   1666: struct Vertex GPHUGE *v1, GPHUGE * v2, GPHUGE * v3, GPHUGE * v4;
                   1667: {
                   1668:     double y;
                   1669:
                   1670:     /* HBB 971115: to silence picky compilers, use v2 at least once, in
                   1671:      * a dummy expression (caution, may be ANSI-C specific because of
                   1672:      * the use of 'void'...) */
                   1673:     (void) v2;
                   1674:
                   1675:     /* if [v3,v4] is vertical, too: */
                   1676:     /* already known: rectangles do overlap, because MINIMAX was true */
                   1677:     if (EQ(v3->x, v4->x))
                   1678:        return (GR(M2y, m1y) && GR(M1y, m2y)) ? 1 : -1;
                   1679:
                   1680:     /*  [v3,v4] not vertical */
                   1681:     y = v3->y + (v1->x - v3->x) * (v4->y - v3->y) / (v4->x - v3->x);
                   1682:     if (GR(m1x, m2x) && GR(M2x, m1x)) {
                   1683:        if (GR(y, m1y) && GR(M1y, y))
                   1684:            return 1;
                   1685:        if (EQ(y, m1y) || EQ(y, M1y))
                   1686:            return -2;
                   1687:        return 0;
                   1688:     }
                   1689:     /* m1x == m2x || m1x == M2x */
                   1690:     if (GR(y, m1y) && GR(M1y, y))
                   1691:        return -2;
                   1692:     if (EQ(y, m1y) || EQ(y, M1y))
                   1693:        return -1;
                   1694:     return 0;
                   1695: }
                   1696:
                   1697: #define UPD_MINMAX(v1,v2,npar) do {    \
                   1698:   if (v1->x< v2->x)                 \
                   1699:     CONCAT3(m,npar,x) = v1->x, CONCAT3(M,npar,x) = v2->x;   \
                   1700:   else                              \
                   1701:     CONCAT3(m,npar,x) = v2->x, CONCAT3(M,npar,x) = v1->x;   \
                   1702:   if (v1->y< v2->y)                 \
                   1703:     CONCAT3(m,npar,y) = v1->y, CONCAT3(M,npar,y) = v2->y;   \
                   1704:   else                              \
                   1705:     CONCAT3(m,npar,y) = v2->y, CONCAT3(M,npar,y) = v1->y;   \
                   1706: } while (0)
                   1707:
                   1708: /* does the edge [v1,v2] intersect polygon p? */
                   1709: static int intersect_polygon(v1, v2, p)
                   1710: struct Vertex GPHUGE *v1, GPHUGE * v2;
                   1711: struct Polygon GPHUGE *p;
                   1712: {
                   1713:     struct Vertex GPHUGE *v3, GPHUGE * v4;
                   1714:     int i, s, t = 0;
                   1715:     int (*which_intersect) __PROTO((struct Vertex GPHUGE * v1,
                   1716:                                    struct Vertex GPHUGE * v2,
                   1717:                                    struct Vertex GPHUGE * v3,
                   1718:                                    struct Vertex GPHUGE * v4))
                   1719:     = intersect;
                   1720:
                   1721:     /* Is [v1,v2] vertical? If, use v_intersect() */
                   1722:     if (EQ(v1->x, v2->x))
                   1723:        which_intersect = v_intersect;
                   1724:
                   1725:     UPD_MINMAX(v1,v2,1);
                   1726:
                   1727:     /* test first edge of polygon p */
                   1728:     v3 = vlist + p->vertex[p->n - 1];
                   1729:     v4 = vlist + p->vertex[0];
                   1730:     UPD_MINMAX(v3,v4,2);
                   1731:
                   1732:
                   1733:     if (MINIMAX) {
                   1734:        s = (*which_intersect) (v1, v2, v3, v4);
                   1735:        if (s == 1 || (s < 0 && (t += s) < -4))
                   1736:            return 1;
                   1737:     }
                   1738:     /* and the other edges... */
                   1739:     for (i = 0; i < p->n - 1; i++) {
                   1740:        v3 = vlist + p->vertex[i];
                   1741:        v4 = vlist + p->vertex[i + 1];
                   1742:        UPD_MINMAX(v3,v4,2);
                   1743:        if (!MINIMAX)
                   1744:            continue;
                   1745:        s = (*which_intersect) (v1, v2, v3, v4);
                   1746:        if (s == 1 || (s < 0 && (t += s) < -4))
                   1747:            return 1;
                   1748:     }
                   1749:     return t;
                   1750: }
                   1751:
                   1752: /* OK, now here comes the 'real' polygon intersection routine:
                   1753:  * Do a and b overlap in x or y (full test):
                   1754:  * Do edges intersect, do the polygons touch in two points,
                   1755:  * or is a vertex of one polygon inside the other polygon? */
                   1756:
                   1757: static int full_xy_overlap(a, b)
                   1758: struct Polygon GPHUGE *a, GPHUGE * b;
                   1759: {
                   1760:     struct Vertex GPHUGE *v1, GPHUGE * v2, v;
                   1761:     int i, s, t = 0;
                   1762:
                   1763:     if (a->n < 2 || b->n < 2)
                   1764:        return 0;
                   1765:     v1 = vlist + a->vertex[a->n - 1];
                   1766:     v2 = vlist + a->vertex[0];
                   1767:     s = intersect_polygon(v1, v2, b);
                   1768:     if (s == 1 || (s < 0 && (t += s) < -4))
                   1769:        return 1;
                   1770:     for (i = 0; i < a->n - 1; i++) {
                   1771:        v1 = vlist + a->vertex[i];
                   1772:        v2 = vlist + a->vertex[i + 1];
                   1773:        s = intersect_polygon(v1, v2, b);
                   1774:        if (s == 1 || (s < 0 && (t += s) < -4))
                   1775:            return 1;
                   1776:     }
                   1777:     /* No edges intersect. Is one polygon inside the other? */
                   1778:     /* The  inner polygon has the greater minx */
                   1779:     if (a->xmin < b->xmin) {
                   1780:        struct Polygon GPHUGE *temp = a;
                   1781:        a = b;
                   1782:        b = temp;
                   1783:     }
                   1784:     /* Now, a is the inner polygon */
                   1785:     for (i = 0; i < a->n; i++) {
                   1786:        v1 = vlist + a->vertex[i];
                   1787:        /* HBB: lclint seems to have found a problem here: v wasn't
                   1788:         * fully defined when passed to intersect_polygon() */
                   1789:        v = *v1;
                   1790:        v.x = -1.1;
                   1791:        s = intersect_polygon(v1, &v, b);
                   1792:        if (s == 0)
                   1793:            return 0;           /* a is outside polygon b */
                   1794:        v.x = 1.1;
                   1795:        if (s == 1) {
                   1796:            s = intersect_polygon(v1, &v, b);
                   1797:            if (s == 0)
                   1798:                return 0;
                   1799:            if (s == 1)
                   1800:                return 1;
                   1801:        } else if (intersect_polygon(v1, &v, b) == 0)
                   1802:            return 0;
                   1803:     }
                   1804: #if 1
                   1805:     /* 970614: don't bother, just presume that they do overlap: */
                   1806:     return 1;
                   1807: #else /* !1 */
                   1808:     print_polygon(a, "a");
                   1809:     print_polygon(b, "b");
                   1810:     graph_error("Logic Error in full_xy_overlap");
                   1811:     return -1;                 /* HBB: shut up gcc -Wall */
                   1812: #endif /* !1 */
                   1813: }
                   1814:
                   1815:
                   1816: /* Helper routine for split_polygon_by_plane */
                   1817: static long build_new_vertex(V1, V2, w)
                   1818: long V1, V2;   /* the vertices, between which a new vertex is demanded */
                   1819: double w;      /* information about where between V1 and V2 it should be */
                   1820: {
                   1821:     long V;
                   1822:     struct Vertex GPHUGE *v, GPHUGE * v1, GPHUGE * v2;
                   1823:
                   1824:     if (EQ(w, 0.0))
                   1825:        return V1;
                   1826:     if (EQ(w, 1.0))
                   1827:        return V2;
                   1828:
                   1829:     /* We need a new Vertex */
                   1830:     if (vert_free == nvert)    /* Extend vlist, if necessary */
                   1831:        vlist = (struct Vertex GPHUGE *)
                   1832:            gp_realloc(vlist, (unsigned long) sizeof(struct Vertex) * (nvert += 10L), "hidden vlist");
                   1833:     V = vert_free++;
                   1834:     v = vlist + V;
                   1835:     v1 = vlist + V1;
                   1836:     v2 = vlist + V2;
                   1837:
                   1838:     v->x = (v2->x - v1->x) * w + v1->x;
                   1839:     v->y = (v2->y - v1->y) * w + v1->y;
                   1840:     v->z = (v2->z - v1->z) * w + v1->z;
                   1841:     v->style = -1;
                   1842:
                   1843:     /* 970610: additional checks, to prevent adding unnecessary vertices */
                   1844:     if (V_EQUAL(v, v1)) {
                   1845:        vert_free--;
                   1846:        return V1;
                   1847:     }
                   1848:     if (V_EQUAL(v, v2)) {
                   1849:        vert_free--;
                   1850:        return V2;
                   1851:     }
                   1852:     return V;
                   1853: }
                   1854:
                   1855:
                   1856: /* Splits polygon p by the plane represented by its equation
                   1857:  * coeffecients a to d.
                   1858:  * return-value: part of the polygon, that is in front/back of plane
                   1859:  * (Distinction necessary to ensure the ordering of polygons in
                   1860:  * the plist stays intact)
                   1861:  * Caution: plist and vlist can change their location!!!
                   1862:  * If a point is in plane, it comes to the behind - part
                   1863:  * (HBB: that may well have changed, as I cut at the 'in plane'
                   1864:  * mechanisms heavily)
                   1865:  */
                   1866:
                   1867: static long split_polygon_by_plane(P, a, b, c, d, f)
                   1868: long P;                                /* Polygon as index on plist */
                   1869: double a, b, c, d;
                   1870: TBOOLEAN f;                    /* return value = Front(1) or Back(0) */
                   1871: {
                   1872:     int i, j;
                   1873:     struct Polygon GPHUGE *p = plist + P;
                   1874:     struct Vertex GPHUGE *v;
                   1875:     int snew, stest;
                   1876:     int in_plane;              /* what is about points in plane? */
                   1877:     int cross1, cross2;                /* first vertices, after p crossed the plane */
                   1878:     double a1 = 0.0, b1, a2 = 0.0, b2; /* parameters of the crosses */
                   1879:     long Front;                        /* the new Polygon */
                   1880:     int n1, n2;
                   1881:     long *v1, *v2;
                   1882:     long line1, line2;
                   1883:     long next_frag_temp;
                   1884:
                   1885:
                   1886:     CHECK_POINTER(plist, p);
                   1887:
                   1888:     in_plane = (EQ(c, 0.0) && f) ? 1 : -1;
                   1889:     /* first vertex */
                   1890:     v = vlist + p->vertex[0];
                   1891:
                   1892:     CHECK_POINTER(vlist, v);
                   1893:
                   1894:     b1 = a * v->x + b * v->y + c * v->z + d;
                   1895:     stest = SIGNOF(b1);
                   1896: #if OLD_SPLIT_INPLANE
                   1897:     if (!stest)
                   1898:        stest = in_plane;
                   1899: #endif
                   1900:
                   1901:     /* find first vertex that is on the other side of the plane */
                   1902:     for (cross1 = 1, snew = stest; snew == stest && cross1 < p->n; cross1++) {
                   1903:        a1 = b1;
                   1904:        v = vlist + p->vertex[cross1];
                   1905:        CHECK_POINTER(vlist, v);
                   1906:        b1 = a * v->x + b * v->y + c * v->z + d;
                   1907:        snew = SIGNOF(b1);
                   1908: #if OLD_SPLIT_INPLANE
                   1909:        if (!snew)
                   1910:            snew = in_plane;
                   1911: #endif
                   1912:     }
                   1913:
                   1914:     if (snew == stest) {
                   1915:        /*HBB: this is possibly not an error in split_polygon, it's just
                   1916:         * not possible to split this polygon by this plane. I.e., the
                   1917:         * error is in the caller!  */
                   1918:        fprintf(stderr, "split_poly failed, polygon nr. %ld\n", P);
                   1919:        return (-1);            /* return 'unsplittable' */
                   1920:     }
                   1921:     cross1--;                  /* now, it's the last one on 'this' side */
                   1922:
                   1923:     /* first vertex that is on the first side again */
                   1924:     for (b2 = b1, cross2 = cross1 + 1;
                   1925:         snew != stest && cross2 < p->n; cross2++) {
                   1926:        a2 = b2;
                   1927:        v = vlist + p->vertex[cross2];
                   1928:        CHECK_POINTER(vlist, v);
                   1929:        b2 = a * v->x + b * v->y + c * v->z + d;
                   1930:        snew = SIGNOF(b2);
                   1931: #if OLD_SPLIT_INPLANE
                   1932:        if (!snew)
                   1933:            snew = -in_plane;
                   1934: #endif
                   1935:     }
                   1936:
                   1937:     if (snew != stest) {
                   1938:        /* only p->vertex[0] is on 'this' side */
                   1939:        a2 = b2;
                   1940:        v = vlist + p->vertex[0];
                   1941:        CHECK_POINTER(vlist, v);
                   1942:        b2 = a * v->x + b * v->y + c * v->z + d;
                   1943:     } else
                   1944:        cross2--;               /* now it's the last one on 'the other' side */
                   1945:
                   1946:     /* We need two new polygons instead of the old one: */
                   1947:     n1 = p->n - cross2 + cross1 + 2;
                   1948:     n2 = cross2 - cross1 + 2;
1.1.1.3 ! ohara    1949:     v1 = (long *) gp_alloc(sizeof(long) * n1, "hidden v1 for two new poly");
        !          1950:     v2 = (long *) gp_alloc(sizeof(long) * n2, "hidden v2 for two new poly");
1.1       maekawa  1951: #if SHOW_SPLITTING_EDGES
                   1952:     line1 = 1L << (n1 - 1);
                   1953:     line2 = 1L << (n2 - 1);
                   1954: #else
                   1955:     line1 = line2 = 0L;
                   1956: #endif
                   1957:     v1[0] = v2[n2 - 1] =
                   1958:        build_new_vertex(p->vertex[cross2 - 1],
                   1959:                p->vertex[(cross2 < p->n) ? cross2 : 0], a2 / (a2 - b2));
                   1960:     v2[0] = v1[n1 - 1] =
                   1961:        build_new_vertex(p->vertex[cross1 - 1],
                   1962:                         p->vertex[cross1], a1 / (a1 - b1));
                   1963:
                   1964:     /* Copy visibility from split edges to their fragments: */
                   1965:     if (p->line & (1 << (cross1 - 1))) {
                   1966:        line1 |= 1L << (n1 - 2);
                   1967:        line2 |= 1L;
                   1968:     }
                   1969:     if (p->line & (1L << (cross2 - 1))) {
                   1970:        line1 |= 1L;
                   1971:        line2 |= 1L << (n2 - 2);
                   1972:     }
                   1973:     /* Copy the old line patterns and vertex listings into new places */
                   1974:     /* p->vertex[cross2...p->n-1] --> v1[1...] */
                   1975:     for (i = cross2, j = 1; i < p->n;) {
                   1976:        if (p->line & (1L << i))
                   1977:            line1 |= 1L << j;
                   1978:        v1[j++] = p->vertex[i++];
                   1979:     }
                   1980:     /* p->vertex[0...cross1-1] --> v1[...n1-2] */
                   1981:     for (i = 0; i < cross1 - 1;) {
                   1982:        if (p->line & (1L << i))
                   1983:            line1 |= 1L << j;
                   1984:        v1[j++] = p->vertex[i++];
                   1985:     }
                   1986:     v1[j++] = p->vertex[i++];
                   1987:
                   1988:     /* p->vertex[cross1...cross2-1] -> v2[1...n2-2] */
                   1989:     for (j = 1; i < cross2 - 1;) {
                   1990:        if (p->line & (1L << i))
                   1991:            line2 |= 1L << j;
                   1992:        v2[j++] = p->vertex[i++];
                   1993:     }
                   1994:     v2[j++] = p->vertex[i];
                   1995:
                   1996:     /* old vertex list isn't needed any more: */
                   1997:     free(p->vertex);
                   1998:     p->vertex = 0;
                   1999:
                   2000:     if (!reduce_polygon(&n1, &v1, &line1, 1) ||
                   2001:        !reduce_polygon(&n2, &v2, &line2, 1))
                   2002:        graph_error("Logic Error 2 in split_polygon");
                   2003:
                   2004:     /* Build the 2 new polygons : we are reusing one + making one new */
                   2005:     CHECK_PLIST_EXTRA(p = plist + P);
                   2006:     Front = pfree++;
                   2007:
                   2008:     if ((next_frag_temp = p->next_frag) < 0)
                   2009:        next_frag_temp = P;     /* First split of this polygon at all */
                   2010:
                   2011:     /* HBB 961110: lclint said == shouldn't be used on Boolean's */
                   2012:     if ((f && (stest < 0)) || ((!f) && !(stest < 0))) {
                   2013:        build_polygon(plist + P, n1, v1, line1, p->style, p->lp,
                   2014:                      p->next, Front, p->id, p->tested);
                   2015:        build_polygon(plist + Front, n2, v2, line2, p->style, p->lp,
                   2016:                      -1, next_frag_temp, p->id, is_moved_or_split);
                   2017:     } else {
                   2018:        build_polygon(plist + P, n2, v2, line2, p->style, p->lp,
                   2019:                      p->next, Front, p->id, p->tested);
                   2020:        build_polygon(plist + Front, n1, v1, line1, p->style, p->lp,
                   2021:                      -1, next_frag_temp, p->id, is_moved_or_split);
                   2022:     }
                   2023:     return Front;
                   2024: }
                   2025:
                   2026: /* HBB: these pieces of code are found repeatedly in in_front(), so
                   2027:  * I put them into macros
                   2028:  * Note: can't use the 'do {...} while (0)' method for
                   2029:  * these: 'continue' wouldn't work any more.
                   2030:  */
                   2031: #define PUT_P_IN_FRONT_TEST(new_tested) {\
                   2032:   plist[Plast].next = p->next; \
                   2033:   p->next = Test; \
                   2034:   p->tested = new_tested; \
                   2035:   if (Insert >= 0) \
                   2036:     plist[Insert].next = P; \
                   2037:   else \
                   2038:     pfirst = P; \
                   2039:   Insert = P; \
                   2040:   P = Plast; \
                   2041:   p = plist + P; \
                   2042:   continue; \
                   2043: }
                   2044:
                   2045: #define SPLIT_TEST_BY_P {\
                   2046:   long Back = split_polygon_by_plane (Test, pa, pb, pc, pd, 0); \
                   2047:   if (Back >0) { \
                   2048:     p = plist + P; \
                   2049:     test = plist + Test;  /* plist can change */ \
                   2050:     plist[Back].next = p->next; \
                   2051:     p->next = Back; \
                   2052:     P = Back; \
                   2053:     p = plist + P; \
                   2054:     zmin = test->zmin;  /* the new z-value */ \
                   2055:   } else { \
                   2056:     fprintf(stderr, "Failed to split test (%ld) by p (%ld)\n", Test, P); \
                   2057:     graph_error("Error in hidden line removal: couldn't split..."); \
                   2058:   } \
                   2059:   continue; \
                   2060: }
                   2061:
                   2062: #define SPLIT_P_BY_TEST {\
                   2063:   long Front = split_polygon_by_plane (P, ta, tb, tc, td, 1);\
                   2064:   if (Front >0) {\
                   2065:     p = plist + P;\
                   2066:     test = plist + Test;       /* plist can change */\
                   2067:     plist[Front].next = Test;\
                   2068:     if (Insert >= 0)\
                   2069:       plist[Insert].next = Front;\
                   2070:     else\
                   2071:       pfirst = Front;\
                   2072:     Insert = Front;\
                   2073:   } else {\
                   2074:     fprintf(stderr, "Failed to split p (%ld) by test(%ld), relations are %d, %d\n", P, Test, p_rel_tplane, t_rel_pplane);\
                   2075:     print_polygon(test, "test");\
                   2076:     print_polygon(p, "p");\
                   2077:     fputc('\n', stderr);\
                   2078:   }\
                   2079:   continue; /* FIXME: should we continue nevertheless? */\
                   2080: }
                   2081:
                   2082:
                   2083: /* Is Test in front of the other polygons?
                   2084:  * If not, polygons which are in front of test come between
                   2085:  * Last and Test (I.e. to the 'front' of the plist)
                   2086:  */
                   2087: static int in_front(Last, Test)
                   2088: long Last, Test;
                   2089: {
                   2090:     struct Polygon GPHUGE *test = plist + Test, GPHUGE * p;
                   2091:     long Insert, P, Plast;
                   2092:     double zmin,               /* minimum z-value of Test */
                   2093:      ta, tb, tc, td,           /* the plane of Test      */
                   2094:      pa, pb, pc, pd;           /* the plane of a polygon */
                   2095:     t_poly_plane_intersect p_rel_tplane, t_rel_pplane;
                   2096:     int loop = (test->tested == is_in_loop);
                   2097:
                   2098:     CHECK_POINTER(plist, test);
                   2099:
                   2100:     /* Maybe this should only done at the end of this routine... */
                   2101:     /* test->tested = is_tested; */
                   2102:
                   2103:     Insert = Last;
                   2104:
                   2105:     /* minimal z-value of Test */
                   2106:     zmin = test->zmin;
                   2107:
                   2108:     /* The plane of the polygon Test */
                   2109:     get_plane(test, &ta, &tb, &tc, &td);
                   2110:
                   2111:     /* Compare Test with the following polygons, which overlap in z value */
                   2112:     for (Plast = Test, p = test;
                   2113:         ((P = p->next) >= 0) && (((p = plist + P)->zmax > zmin) || (p->tested != 0));
                   2114:         Plast = P) {
                   2115:        CHECK_POINTER(plist, p);
                   2116:
                   2117:        if (!xy_overlap(test, p))
                   2118:            continue;
                   2119:
                   2120:        if (p->zmax <= zmin)
                   2121:            continue;
                   2122:
                   2123:        p_rel_tplane = polygon_plane_intersection(p, ta, tb, tc, td);
                   2124:        if ((p_rel_tplane == behind) || (p_rel_tplane == inside))
                   2125:            continue;
                   2126:
                   2127:        get_plane(p, &pa, &pb, &pc, &pd);
                   2128:        t_rel_pplane = polygon_plane_intersection(test, pa, pb, pc, pd);
                   2129:        if ((t_rel_pplane == infront) || (t_rel_pplane == inside))
                   2130:            continue;
                   2131:
                   2132:        if (!full_xy_overlap(test, p))
                   2133:            continue;
                   2134:
                   2135: #if 1
                   2136:        /* HBB 971115: try new approach developed directly from Foley et
                   2137:         * al.'s original description */
                   2138:        /* OK, at this point, a total of 16 cases is left to be handled,
                   2139:         * as 4 variables are important, each with two possible values:
                   2140:         * t_rel_pplane may be 'behind' or 'intersects', p_rel_tplane may
                   2141:         * be 'infront' or 'intersects', 'test' may be (seem to be) part
                   2142:         * of a loop or not ('loop'), and p may have been considered
                   2143:         * already or not (p->tested =?= is_tested). */
                   2144:        /* See if splitting wherever possible is a good idea: */
                   2145:        if (p_rel_tplane == intersects) {
                   2146:            p->tested = is_moved_or_split;
                   2147:            SPLIT_P_BY_TEST;
                   2148:        } else if (t_rel_pplane == intersects) {
                   2149:            test->tested = is_moved_or_split;
                   2150:            SPLIT_TEST_BY_P;
                   2151:        } else {
1.1.1.3 ! ohara    2152:            if (loop && (p->tested == is_in_loop)) {
        !          2153:                /* Ouch, seems like we're in trouble, really: no way to
        !          2154:                 * split one of them, and we're in a loop, so we can't
        !          2155:                 * move p to the front of the list, without risking an
        !          2156:                 * endless loop. Well, let's just output the darn thing,
        !          2157:                 * then, no matter what. :-( */
        !          2158: #if DEBUG /* normally off */
1.1       maekawa  2159:                fprintf(stderr, "\
                   2160: #Failed: In loop, without intersections.\n\
                   2161: #Relations are %d, %d\n",
                   2162:                        p_rel_tplane, t_rel_pplane);
                   2163:                print_polygon(test, "test");
                   2164:                print_polygon(p, "p");
1.1.1.3 ! ohara    2165: #endif
1.1       maekawa  2166:                continue;       /* Keep quiet, maybe no-one will notice (;-) */
                   2167:            } else {
                   2168:                PUT_P_IN_FRONT_TEST(is_in_loop);
                   2169:            }
                   2170:        }
                   2171: #else
                   2172:        /* p obscures test (at least, this *might* be happening */
                   2173:        if (loop) {
                   2174:            /* if P isn't interesting for the loop, put P in front of Test */
                   2175:            if ((p->tested != is_tested)
                   2176:                || (p_rel_tplane == infront)
                   2177:                || (t_rel_pplane == behind))    /* HBB 970325: was infront (!?) */
                   2178:                PUT_P_IN_FRONT_TEST(is_moved_or_split);
                   2179:
                   2180:            /* else, split either test or p */
                   2181:            if (t_rel_pplane == intersects)
                   2182:                SPLIT_TEST_BY_P;
                   2183:            if (p_rel_tplane == intersects)
                   2184:                SPLIT_P_BY_TEST;
                   2185:
                   2186:            /* HBB: if we ever come through here, something went severely wrong */
                   2187:            fprintf(stderr, "Failed: polygon %ld vs. %ld, relations are %d, %d\n", P, Test, p_rel_tplane, t_rel_pplane);
                   2188:            print_polygon(test, "test");
                   2189:            print_polygon(p, "p");
                   2190:            fputc('\n', stderr);
                   2191:            graph_error("Couldn't resolve a polygon overlapping pb. Go tell HBB...");
                   2192:        }
                   2193:        /* No loop: if it makes sense, put P in front of Test */
                   2194:        if ((p->tested != is_tested)
                   2195:            && ((t_rel_pplane == behind)
                   2196:                || (p_rel_tplane == infront)))
                   2197:            PUT_P_IN_FRONT_TEST(is_moved_or_split);
                   2198:
                   2199:        /* If possible, split P */
                   2200:        if ((p->tested != is_tested) || (p_rel_tplane == intersects))
                   2201:            SPLIT_P_BY_TEST;
                   2202:
                   2203:        /* if possible, split Test */
                   2204:        if (t_rel_pplane == intersects)
                   2205:            SPLIT_TEST_BY_P;
                   2206:
                   2207:        /* else, we have a loop: mark P as loop and put it in front of Test */
                   2208:        PUT_P_IN_FRONT_TEST(is_in_loop);        /* -2: p is in a loop */
                   2209: #endif
                   2210:     }
                   2211:     if (Insert == Last)
                   2212:        test->tested = is_tested;
                   2213:     return (int) (Insert == Last);
                   2214: }
                   2215:
                   2216:
                   2217: /* Drawing the polygons */
                   2218:
                   2219: /* HBB 980303: new functions to handle Cross back-buffer (saves
                   2220:  * gp_alloc()'s) */
                   2221:
                   2222: static GP_INLINE void init_Cross_store()
                   2223: {
                   2224:     assert(!Cross_store && !last_Cross_store);
                   2225:     last_Cross_store = CROSS_STORE_INCREASE;
                   2226:     free_Cross_store = 0;
                   2227:     Cross_store = (struct Cross *)
1.1.1.3 ! ohara    2228:        gp_alloc(last_Cross_store * sizeof(struct Cross), "hidden cross store");
1.1       maekawa  2229: }
                   2230:
1.1.1.3 ! ohara    2231: static GP_INLINE unsigned int
        !          2232: get_Cross_from_store()
1.1       maekawa  2233: {
                   2234:     while (last_Cross_store <= free_Cross_store) {
                   2235:        last_Cross_store += CROSS_STORE_INCREASE;
                   2236:        Cross_store = (struct Cross *)
                   2237:            gp_realloc(Cross_store,
                   2238:                 (unsigned long) last_Cross_store * sizeof(struct Cross),
                   2239:                       "hidden cross store");
                   2240:     }
1.1.1.3 ! ohara    2241:     return free_Cross_store++;
1.1       maekawa  2242: }
                   2243:
                   2244: static GP_INLINE TBOOLEAN
                   2245:  hl_buffer_set(xv, yv)
                   2246: int xv, yv;
                   2247: {
1.1.1.3 ! ohara    2248:     unsigned int c;
        !          2249:
1.1       maekawa  2250:     /*HBB 961110: lclint wanted this: */
                   2251:     assert(hl_buffer != 0);
1.1.1.3 ! ohara    2252:     for (c = hl_buffer[xv];
        !          2253:         c < last_Cross_store;
        !          2254:         c = Cross_store[c].next)
        !          2255:        if (Cross_store[c].a <= yv && Cross_store[c].b >= yv) {
1.1       maekawa  2256:            return TRUE;
                   2257:        }
                   2258:     return FALSE;
                   2259: }
                   2260:
                   2261: /* HBB 961201: new var's, to speed up free()ing hl_buffer later */
                   2262: static int hl_buff_xmin, hl_buff_xmax;
                   2263:
                   2264: /* HBB 961124: new routine. All this occured twice in
                   2265:  * draw_clip_line_buffer */
                   2266: /* Store a line crossing the x interval around xv between y = ya and
                   2267:  * y = yb in the hl_buffer */
                   2268: static GP_INLINE void update_hl_buffer_column(xv, ya, yb)
1.1.1.3 ! ohara    2269:     int xv, ya, yb;
1.1       maekawa  2270: {
1.1.1.3 ! ohara    2271:     unsigned int cross, cross2;
        !          2272:     TBOOLEAN still_in_hl_buffer = TRUE;
1.1       maekawa  2273:
                   2274:     /* First, ensure that ya <= yb */
                   2275:     if (ya > yb) {
                   2276:        int y_temp = yb;
                   2277:        yb = ya;
                   2278:        ya = y_temp;
                   2279:     }
                   2280:     /* loop over all previous crossings at this x-value */
1.1.1.3 ! ohara    2281:     for (cross = hl_buffer[xv], still_in_hl_buffer = TRUE;
        !          2282:         1;
        !          2283:         cross = Cross_store[cross].next, still_in_hl_buffer = FALSE
        !          2284:         ) {
        !          2285:        if (cross > last_Cross_store) {
1.1       maekawa  2286:            /* first or new highest crossing at this x-value */
                   2287:
                   2288:            /* HBB 980303: new method to allocate Cross structures */
1.1.1.3 ! ohara    2289:            cross = get_Cross_from_store();
        !          2290:            if (still_in_hl_buffer)
        !          2291:                hl_buffer[xv] = cross;
        !          2292:            Cross_store[cross].a = ya;
        !          2293:            Cross_store[cross].b = yb;
        !          2294:            Cross_store[cross].next = (unsigned int) -1;
1.1       maekawa  2295:            /* HBB 961201: keep track of x-range of hl_buffer, to
                   2296:             * speedup free()ing it */
                   2297:            if (xv < hl_buff_xmin)
                   2298:                hl_buff_xmin = xv;
                   2299:            if (xv > hl_buff_xmax)
                   2300:                hl_buff_xmax = xv;
                   2301:            break;
                   2302:        }
1.1.1.3 ! ohara    2303:        if (yb < Cross_store[cross].a - 1) {
1.1       maekawa  2304:            /* crossing below 'cross', create new entry before 'cross' */
1.1.1.3 ! ohara    2305:            cross2 = cross;
1.1       maekawa  2306:            /* HBB 980303: new method to allocate Cross structures */
1.1.1.3 ! ohara    2307:            cross = get_Cross_from_store();
        !          2308:            if (still_in_hl_buffer)
        !          2309:                hl_buffer[xv] = cross;
        !          2310:            Cross_store[cross].a = ya;
        !          2311:            Cross_store[cross].b = yb;
        !          2312:            Cross_store[cross].next = cross2;
1.1       maekawa  2313:            break;
1.1.1.3 ! ohara    2314:        } else if (ya <= Cross_store[cross].b + 1) {
1.1       maekawa  2315:            /* crossing overlaps or covers 'cross' */
1.1.1.3 ! ohara    2316:            if (ya < Cross_store[cross].a)
        !          2317:                Cross_store[cross].a = ya;
        !          2318:            if (yb > Cross_store[cross].b) {
        !          2319:                if (Cross_store[cross].next < last_Cross_store
        !          2320:                    && Cross_store[Cross_store[cross].next].a <= yb
        !          2321:                    ) {
1.1       maekawa  2322:                    /* crossing spans all the way up to 'cross->next' so
                   2323:                     * unite them */
1.1.1.3 ! ohara    2324:                    cross2 = Cross_store[cross].next;
        !          2325:                    Cross_store[cross].b = Cross_store[cross2].b;
        !          2326:                    Cross_store[cross].next = Cross_store[cross2].next;
1.1       maekawa  2327:                } else
1.1.1.3 ! ohara    2328:                    Cross_store[cross].b = yb;
1.1       maekawa  2329:            }
                   2330:            break;
                   2331:        }
                   2332:     }
                   2333:     return;
                   2334: }
                   2335:
                   2336:
                   2337: static void draw_clip_line_buffer(x1, y1, x2, y2)
                   2338: int x1, y1, x2, y2;
                   2339:      /* Draw a line in the hl_buffer */
                   2340: {
                   2341:     register int xv, yv, errx, erry, err;
                   2342:     register int dy, nstep;
                   2343:     register int ya;
                   2344:     int i;
                   2345:
                   2346:     if (!clip_line(&x1, &y1, &x2, &y2)) {
                   2347:        /*printf("dcl_buffer: clipped away!\n"); */
                   2348:        return;
                   2349:     }
                   2350:     if (x1 > x2) {
                   2351:        errx = XREDUCE(x1) - XREDUCE(x2);
                   2352:        erry = YREDUCE(y1) - YREDUCE(y2);
                   2353:        xv = XREDUCE(x2) - XREDUCE(xleft);
                   2354:        yv = YREDUCE(y2) - YREDUCE(ybot);
                   2355:     } else {
                   2356:        errx = XREDUCE(x2) - XREDUCE(x1);
                   2357:        erry = YREDUCE(y2) - YREDUCE(y1);
                   2358:        xv = XREDUCE(x1) - XREDUCE(xleft);
                   2359:        yv = YREDUCE(y1) - YREDUCE(ybot);
                   2360:     }
                   2361:     if (erry > 0)
                   2362:        dy = 1;
                   2363:     else {
                   2364:        dy = -1;
                   2365:        erry = -erry;
                   2366:     }
                   2367:     nstep = errx + erry;
                   2368:     err = -errx + erry;
                   2369:     errx <<= 1;
                   2370:     erry <<= 1;
                   2371:     ya = yv;
                   2372:
                   2373:     for (i = 0; i < nstep; i++) {
                   2374:        if (err < 0) {
                   2375:            update_hl_buffer_column(xv, ya, yv);
                   2376:            xv++;
                   2377:            ya = yv;
                   2378:            err += erry;
                   2379:        } else {
                   2380:            yv += dy;
                   2381:            err -= errx;
                   2382:        }
                   2383:     }
                   2384:     (void) update_hl_buffer_column(xv, ya, yv);
                   2385:     return;
                   2386: }
                   2387:
                   2388:
                   2389: /* HBB 961124: improve similarity of this routine with
                   2390:  * draw_clip_line_buffer ()
                   2391:  *
                   2392:  * HBB 961124: changed from 'virtual' to 'do_draw', for clarity (this
                   2393:  * also affects the routines calling this one, so beware!
                   2394:  *
                   2395:  * HBB 961124: introduced checking code, to search for the 'holes in
                   2396:  * the surface' bug
                   2397:  *
                   2398:  * Draw a line into the bitmap (**cpnt), and optionally also to the
                   2399:  * terminal
                   2400:  */
                   2401: static void draw_clip_line_update(x1, y1, x2, y2, do_draw)
                   2402: int x1, y1, x2, y2;
                   2403: TBOOLEAN do_draw;
                   2404: {
                   2405:     /* HBB 961110: made 'flag' a boolean variable, which needs some
                   2406:      *  other changes below as well
                   2407:      *
                   2408:      * HBB 970508: renamed 'flag' to 'is_drawn' (reverting its meaning).
                   2409:      * Should be clearer now
                   2410:      */
                   2411:     TBOOLEAN is_drawn;
                   2412:     register struct termentry *t = term;
                   2413:     register int xv, yv, errx, erry, err;
                   2414:     register int xvr, yvr;
                   2415:     int xve, yve;
                   2416:     register int dy, nstep = 0, dyr;
                   2417:     int i;
                   2418:     if (!clip_line(&x1, &y1, &x2, &y2)) {
                   2419:        /*printf("dcl_update: clipped away!\n"); */
                   2420:        return;
                   2421:     }
                   2422:     if (x1 > x2) {
                   2423:        xvr = x2;
                   2424:        yvr = y2;
                   2425:        xve = x1;
                   2426:        yve = y1;
                   2427:     } else {
                   2428:        xvr = x1;
                   2429:        yvr = y1;
                   2430:        xve = x2;
                   2431:        yve = y2;
                   2432:     }
                   2433:     errx = XREDUCE(xve) - XREDUCE(xvr);
                   2434:     erry = YREDUCE(yve) - YREDUCE(yvr);
                   2435:     if (erry > 0)
                   2436:        dy = 1;
                   2437:     else {
                   2438:        dy = -1;
                   2439:        erry = -erry;
                   2440:     }
                   2441:     dyr = dy * yfact;
                   2442:     nstep = errx + erry;
                   2443:     err = -errx + erry;
                   2444:     errx <<= 1;
                   2445:     erry <<= 1;
                   2446:     xv = XREDUCE(xvr) - XREDUCE(xleft);
                   2447:     yv = YREDUCE(yvr) - YREDUCE(ybot);
                   2448:     (*t->move) ((unsigned int) xvr, (unsigned int) yvr);
                   2449:
                   2450:     is_drawn = (IS_UNSET(xv, yv) && (do_draw || hl_buffer_set(xv, yv)));
                   2451:
                   2452:     /* HBB 961110: lclint wanted these: */
                   2453:     assert(ymin_hl != 0);
                   2454:     assert(ymax_hl != 0);
                   2455:     /* Check first point in hl-buffer */
                   2456:     if (xv < xmin_hl)
                   2457:        xmin_hl = xv;
                   2458:     if (xv > xmax_hl)
                   2459:        xmax_hl = xv;
                   2460:     if (yv < ymin_hl[xv])
                   2461:        ymin_hl[xv] = yv;
                   2462:     if (yv > ymax_hl[xv])
                   2463:        ymax_hl[xv] = yv;
                   2464:     for (i = 0; i < nstep; i++) {
                   2465:        /* 970722: new variables */
                   2466:        unsigned int xvr_temp = xvr, yvr_temp = yvr;
                   2467:        if (err < 0) {
                   2468:            xv++;
                   2469:            xvr += xfact;
                   2470:            err += erry;
                   2471:        } else {
                   2472:            yv += dy;
                   2473:            yvr += dyr;
                   2474:            err -= errx;
                   2475:        }
                   2476:        if (IS_UNSET(xv, yv) && (do_draw || hl_buffer_set(xv, yv))) {
                   2477:            if (!is_drawn) {
                   2478:                /* 970722: If this line was meant to be drawn, originally,
                   2479:                 * and it was just the bitmap that stopped it, then draw
                   2480:                 * it a bit longer (i.e.: start one pixel earlier
                   2481:                 */
                   2482:                if (do_draw)
                   2483:                    (*t->move) ((unsigned int) xvr_temp, (unsigned int) yvr_temp);
                   2484:                else
                   2485:                    (*t->move) ((unsigned int) xvr, (unsigned int) yvr);
                   2486:                is_drawn = TRUE;
                   2487:            }
                   2488:        } else {
                   2489:            if (is_drawn) {
                   2490:                /* 970722: If this line is only drawn because hl_buffer_set()
                   2491:                 * was true, then don't extend to the new position (where it
                   2492:                 * isn't true any more). Draw the line one pixel shorter,
                   2493:                 * instead:
                   2494:                 */
                   2495:                if (do_draw)
                   2496:                    (*t->vector) ((unsigned int) xvr, (unsigned int) yvr);
                   2497:                else {
                   2498:                    (*t->vector) ((unsigned int) xvr_temp, (unsigned int) yvr_temp);
                   2499:                    (*t->move) ((unsigned int) xvr, (unsigned int) yvr);
                   2500:                }
                   2501:                is_drawn = FALSE;
                   2502:            }
                   2503:        }
                   2504:        if (xv < xmin_hl)
                   2505:            xmin_hl = xv;
                   2506:        if (xv > xmax_hl)
                   2507:            xmax_hl = xv;
                   2508:        if (yv < ymin_hl[xv])
                   2509:            ymin_hl[xv] = yv;
                   2510:        if (yv > ymax_hl[xv])
                   2511:            ymax_hl[xv] = yv;
                   2512:     }
                   2513:     if (is_drawn)
                   2514:        (*t->vector) ((unsigned int) xvr, (unsigned int) yvr);
                   2515:     return;
                   2516: }
                   2517:
                   2518: #define DRAW_VERTEX(v, x, y) do { \
                   2519:    if ((v)->style >= 0 &&                                            \
                   2520:        !clip_point(x,y)  &&                                        \
                   2521:        IS_UNSET(XREDUCE(x)-XREDUCE(xleft),YREDUCE(y)-YREDUCE(ybot))) \
                   2522:      (*t->point)(x,y, v->style);                                   \
                   2523:    (v)->style = -1;                                                  \
                   2524: } while (0)
                   2525:
                   2526: /* Two routines to emulate move/vector sequence using line drawing routine. */
                   2527: static unsigned int move_pos_x, move_pos_y;
                   2528:
                   2529: void clip_move(x, y)
                   2530: unsigned int x, y;
                   2531: {
                   2532:     move_pos_x = x;
                   2533:     move_pos_y = y;
                   2534: }
                   2535:
                   2536: void clip_vector(x, y)
                   2537: unsigned int x, y;
                   2538: {
                   2539:     draw_clip_line(move_pos_x, move_pos_y, x, y);
                   2540:     move_pos_x = x;
                   2541:     move_pos_y = y;
                   2542: }
                   2543:
                   2544: static GP_INLINE void clip_vector_h(x, y)
                   2545: int x, y;
                   2546:      /* Draw a line on terminal and update bitmap */
                   2547: {
                   2548:     draw_clip_line_update(move_pos_x, move_pos_y, x, y, TRUE);
                   2549:     move_pos_x = x;
                   2550:     move_pos_y = y;
                   2551: }
                   2552:
                   2553:
                   2554: static GP_INLINE void clip_vector_virtual(x, y)
                   2555: int x, y;
                   2556:      /* update bitmap, do not really draw the line */
                   2557: {
                   2558:     draw_clip_line_update(move_pos_x, move_pos_y, x, y, FALSE);
                   2559:     move_pos_x = x;
                   2560:     move_pos_y = y;
                   2561: }
                   2562:
                   2563: static GP_INLINE void clip_vector_buffer(x, y)
                   2564:      /* draw a line in the hl_buffer */
                   2565: int x, y;
                   2566: {
                   2567:     draw_clip_line_buffer(move_pos_x, move_pos_y, x, y);
                   2568:     move_pos_x = x;
                   2569:     move_pos_y = y;
                   2570: }
                   2571:
                   2572: static void draw(p)
                   2573: struct Polygon GPHUGE *p;
                   2574: {
                   2575:     struct Vertex GPHUGE *v;
                   2576:     struct Polygon GPHUGE *q;
                   2577:     long Q;
                   2578:     int i;
                   2579:     int x, y;                  /* point in terminal coordinates */
                   2580:     register struct termentry *t = term;
                   2581:     t_pnt mask1, mask2;
                   2582:     long int indx1, indx2, k;
                   2583:     tp_pnt cpnt;
                   2584:
                   2585:     xmin_hl = HL_EXTENT_X_MAX; /* HBB 961124: parametrized this value */
                   2586:     xmax_hl = 0;
                   2587:
                   2588:     /* HBB 961201: store initial values for range of hl_buffer: */
                   2589:     hl_buff_xmin = XREDUCE(xright) - XREDUCE(xleft);
                   2590:     hl_buff_xmax = 0;
                   2591:
                   2592:     /* Write the lines of all polygons with the same id as p in the hl_buffer */
                   2593:     /* HBB 961201: use next_frag pointers to loop over fragments: */
                   2594:     for (q = p; (Q = q->next_frag) >= 0 && (q = plist + Q) != p;) {
                   2595:        if (q->id != p->id)
                   2596:            continue;
                   2597:
                   2598:        /* draw the lines of q into hl_buffer: */
                   2599:        v = vlist + q->vertex[0];
                   2600:        TERMCOORD(v, x, y);
                   2601:        clip_move(x, y);
                   2602:        for (i = 1; i < q->n; i++) {
                   2603:            v = vlist + q->vertex[i];
                   2604:            TERMCOORD(v, x, y);
                   2605:            if (q->line & (1L << (i - 1)))
                   2606:                clip_vector_buffer(x, y);
                   2607:            else
                   2608:                clip_move(x, y);
                   2609:        }
                   2610:        if (q->line & (1L << (i - 1))) {
                   2611:            v = vlist + q->vertex[0];
                   2612:            TERMCOORD(v, x, y);
                   2613:            clip_vector_buffer(x, y);
                   2614:        }
                   2615:     }
                   2616:
                   2617:
                   2618:     /* first, set the line and point styles: */
                   2619:     {
                   2620:        struct lp_style_type lp;
                   2621:
                   2622:        lp = *(p->lp);
                   2623:        lp.l_type = p->style;
                   2624:        term_apply_lp_properties(&(lp));
                   2625:     }
                   2626:
                   2627:     /*print_polygon (p, "drawing"); */
                   2628:
                   2629:     /* draw the lines of p */
                   2630:     v = vlist + p->vertex[0];
                   2631:     TERMCOORD(v, x, y);
                   2632:     clip_move(x, y);
                   2633:     DRAW_VERTEX(v, x, y);
                   2634:     for (i = 1; i < p->n; i++) {
                   2635:        v = vlist + p->vertex[i];
                   2636:        TERMCOORD(v, x, y);
                   2637:        if (p->line & (1L << (i - 1)))
                   2638:            clip_vector_h(x, y);
                   2639:        else
                   2640:            clip_vector_virtual(x, y);
                   2641:        DRAW_VERTEX(v, x, y);
                   2642:     }
                   2643:     TERMCOORD(vlist + p->vertex[0], x, y);
                   2644:     if (p->line & (1L << (i - 1)))
                   2645:        clip_vector_h(x, y);
                   2646:     else
                   2647:        clip_vector_virtual(x, y);
                   2648:
                   2649:
                   2650:     /* reset the hl_buffer */
                   2651:     /*HBB 961110: lclint wanted this: */
                   2652:     assert(hl_buffer);
                   2653:     for (i = hl_buff_xmin; i <= hl_buff_xmax; i++) {
                   2654:        /* HBB 980303: one part was removed here. It isn't needed any more,
                   2655:         * with the global store for Cross structs. */
1.1.1.3 ! ohara    2656:        hl_buffer[i] = (unsigned int) -1;
1.1       maekawa  2657:     }
                   2658:     /* HBB 980303: instead, set back the free pointer of the Cross store: */
                   2659:     free_Cross_store = 0;
                   2660:
                   2661:     /* now mark the area as being filled in the bitmap. */
                   2662:     /* HBB 971115: Yes, I do know that xmin_hl is unsigned, and the
                   2663:      * first test is thus useless. But I'd like to keep it anyway ;-) */
                   2664:     if (xmin_hl < 0 || xmax_hl > XREDUCE(xright) - XREDUCE(xleft))
                   2665:        graph_error("Logic error #3 in hidden line");
                   2666:     /* HBB 961110: lclint wanted these: */
                   2667:     assert(ymin_hl != 0);
                   2668:     assert(ymax_hl != 0);
                   2669:     assert(pnt != 0);
                   2670:     if (xmin_hl < xmax_hl)
                   2671:        for (i = xmin_hl; i <= xmax_hl; i++) {
                   2672:            if (ymin_hl[i] == HL_EXTENT_Y_MAX)
                   2673:                graph_error("Logic error #2 in hidden line");
                   2674:            if (pnt[i] == 0) {
1.1.1.3 ! ohara    2675:                pnt[i] = (t_pnt *) gp_alloc(y_malloc, "hidden ymalloc");
1.1       maekawa  2676:                memset(pnt[i], 0, (size_t) y_malloc);
                   2677:            }
                   2678:            if (ymin_hl[i] < 0 || ymax_hl[i] > YREDUCE(ytop) - YREDUCE(ybot))
                   2679:                graph_error("Logic error #1 in hidden line");
                   2680:            /* HBB 970508: this shift was wordsize dependent
                   2681:             * I think I fixed that
                   2682:             */
                   2683:            indx1 = ymin_hl[i] / PNT_BITS;
                   2684:            indx2 = ymax_hl[i] / PNT_BITS;
                   2685:            mask1 = PNT_MAX << (((unsigned) ymin_hl[i]) % PNT_BITS);
                   2686:            mask2 = PNT_MAX >> ((~((unsigned) ymax_hl[i])) % PNT_BITS);
                   2687:            cpnt = pnt[i] + indx1;
                   2688:            if (indx1 == indx2)
                   2689:                *cpnt |= (mask1 & mask2);
                   2690:            else {
                   2691:                *cpnt++ |= mask1;
                   2692:                for (k = indx1 + 1; k < indx2; k++)
                   2693:                    *cpnt++ = PNT_MAX;
                   2694:                *cpnt |= mask2;
                   2695:            }
                   2696:            ymin_hl[i] = HL_EXTENT_Y_MAX;
                   2697:            ymax_hl[i] = 0;
                   2698:        }
                   2699: }
                   2700:
                   2701:
                   2702: void plot3d_hidden(plots, pcount)
                   2703: struct surface_points *plots;
                   2704: int pcount;
                   2705: {
                   2706:     long Last, This;
                   2707:     long i;
                   2708:
                   2709: #if defined(DOS16) || defined(WIN16)
                   2710:     /* HBB 980309: Ensure that Polygon Structs exactly fit a 64K segment. The
                   2711:      * problem this prevents is that even with 'huge pointers', a single
                   2712:      * struct may not cross a 64K boundary: it will wrap around to the
                   2713:      * beginning of that 64K segment. Someone ought to complain about
                   2714:      * this nuisance, somewhere... :-( */
                   2715:     assert(0 == (0x1 << 16) % (sizeof(struct Polygon)));
                   2716: #endif
                   2717:
                   2718:     /* Initialize global variables */
                   2719:     y_malloc = (2 + (YREDUCE(ytop) >> 4) - (YREDUCE(ybot) >> 4)) * sizeof(t_pnt);
                   2720:     /* ymin_hl, ymax_hl: */
                   2721:     i = sizeof(t_hl_extent_y) * (XREDUCE(xright) - XREDUCE(xleft) + 1);
1.1.1.3 ! ohara    2722:     ymin_hl = (t_hl_extent_y *) gp_alloc(i, "hidden ymin_hl");
        !          2723:     ymax_hl = (t_hl_extent_y *) gp_alloc(i, "hidden ymax_hl");
1.1       maekawa  2724:     for (i = (XREDUCE(xright) - XREDUCE(xleft)); i >= 0; i--) {
                   2725:        ymin_hl[i] = HL_EXTENT_Y_MAX;
                   2726:        ymax_hl[i] = 0;
                   2727:     }
                   2728:     /* hl_buffer: */
                   2729:     /* HBB 980303 new: initialize the global store for Cross structs: */
                   2730:     init_Cross_store();
                   2731:     i = XREDUCE(xright) - XREDUCE(xleft) + 1;
1.1.1.3 ! ohara    2732:     hl_buffer = (unsigned int GPHUGE *)
        !          2733:        gp_alloc(i * sizeof(unsigned int), "hidden hl_buffer");
1.1       maekawa  2734:     while (--i >= 0)
1.1.1.3 ! ohara    2735:        hl_buffer[i] = (unsigned int) -1;
1.1       maekawa  2736:
                   2737:     init_polygons(plots, pcount);
                   2738:
                   2739:     /* HBB 970326: if no polygons survived the cutting away of undefined
                   2740:      * and/or outranged vertices, bail out with a warning message.
                   2741:      * Without this, sort_by_zmax gets a SegFault */
                   2742:     if (!pfree) {
                   2743:        /* HBB 980701: new code to deallocate all the structures allocated up
                   2744:         * to this point. Should fix the core dump reported by
                   2745:         * Stefan A. Deutscher today  */
                   2746:        if (ymin_hl) {
                   2747:            free(ymin_hl);
                   2748:            ymin_hl = 0;
                   2749:        }
                   2750:        if (ymax_hl) {
                   2751:            free(ymax_hl);
                   2752:            ymax_hl = 0;
                   2753:        }
                   2754:        if (hl_buffer) {
                   2755:            free(hl_buffer);
                   2756:            hl_buffer = 0;
                   2757:        }
                   2758:        if (Cross_store) {
                   2759:            free(Cross_store);
                   2760:            Cross_store = 0;
                   2761:            last_Cross_store = 0;
                   2762:        }
                   2763:        graph_error("*All* polygons undefined or out of range, thus no plot.");
                   2764:     }
                   2765:     sort_by_zmax();
                   2766:
                   2767:     /* sort the polygons and draw them in one loop */
                   2768:     Last = -1L;
                   2769:     This = pfirst;
                   2770:     /* Search first polygon, that can be drawn */
                   2771:     while (Last == -1L && This >= 0L) {
                   2772:        This = pfirst;
                   2773:        if (obscured(plist + This)) {
                   2774:            Last = This;
                   2775:            continue;
                   2776:        }
                   2777:        if (plist[This].tested != is_tested && !in_front(Last, This))
                   2778:            continue;
                   2779:        draw(plist + This);
                   2780:        Last = This;
                   2781:     }
                   2782:     /* Draw the other polygons */
                   2783:     for (This = plist[Last].next; This >= 0L; This = plist[Last].next) {
                   2784:        if (obscured(plist + This)) {
                   2785:            Last = This;
                   2786:            continue;
                   2787:        }
                   2788:        if (plist[This].tested != is_tested && !in_front(Last, This))
                   2789:            continue;
                   2790:        draw(plist + This);
                   2791:        Last = This;
                   2792:     }
                   2793:
                   2794:     /* Free memory */
                   2795:     if (plist) {
                   2796:        for (This = 0L; This < pfree; This++)
                   2797:            free(plist[This].vertex);
                   2798:        free(plist);
                   2799:        plist = 0;
                   2800:     }
                   2801:     if (vlist) {
                   2802:        free(vlist);
                   2803:        vlist = 0;
                   2804:     }
                   2805:     if (ymin_hl) {
                   2806:        free(ymin_hl);
                   2807:        ymin_hl = 0;
                   2808:     }
                   2809:     if (ymax_hl) {
                   2810:        free(ymax_hl);
                   2811:        ymax_hl = 0;
                   2812:     }
                   2813:     if (hl_buffer) {
                   2814:        free(hl_buffer);
                   2815:        hl_buffer = 0;
                   2816:     }
                   2817:     if (Cross_store) {
                   2818:        free(Cross_store);
                   2819:        Cross_store = 0;
                   2820:        last_Cross_store = 0;
                   2821:     }
                   2822: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>