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

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