home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Homebrewer's Handbook / vr.iso / vr386 / rendcore.c < prev    next >
C/C++ Source or Header  |  1996-03-19  |  21KB  |  786 lines

  1.  
  2. /* 3D graphics renderer core: all algoritims, math and assembly */
  3. /* by Dave Stampe */
  4.  
  5. /* Completely rewritten by  Dave Stampe, December 1993 */
  6.  
  7. /* Contact:  dstampe@sunee.waterloo.edu */
  8.  
  9. /* Copyright 1992 by Dave Stampe and Bernie Roehl.
  10.    May be freely used to write software for release into the public domain;
  11.    all commercial endeavours MUST contact Bernie Roehl and Dave Stampe
  12.    for permission to incorporate any part of this software into their
  13.    products!
  14.  
  15.      ATTRIBUTION:  If you use any part of this source code or the libraries
  16.      in your projects, you must give attribution to REND386, Dave Stampe,
  17.      and Bernie Roehl in your documentation, source code, and at startup
  18.      of your program.  Let's keep the freeware ball rolling!
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include <assert.h>
  24. #include <alloc.h>
  25. #include <dos.h>
  26. #include <mem.h>
  27.  
  28. #include "3dstruct.h"        // renderer structures
  29. #include "intmath.h"        // integer math
  30. #include "rendpriv.h"        // assembler routines
  31. #include "renderer.h"
  32. #include "viewstat.h"        // DGROUP static viewport work
  33.  
  34. #include "xmem.h"
  35.  
  36.  
  37. /************* VIEWPORT CONTROL ************/
  38.  
  39.     /* compute eye point/ angle movement factors only */
  40.  
  41. void real_viewpoint(VIEW *v, long *x, long *y, long *z)
  42. {
  43.  *x = v->eye_xform[3][0] ;
  44.  *y = v->eye_xform[3][1] ;
  45.  *z = v->eye_xform[3][2] ;
  46. }
  47.  
  48.  
  49. void matrix_view_factors(VIEW *v, MATRIX m) /* set up from matrix xform */
  50. {
  51.  matrix_transpose(m, v->eye_xform);   /* copy matrix rotational inverse */
  52.  v->eye_xform[3][0] = m[3][0];        /* translation is viewpoint */
  53.  v->eye_xform[3][1] = m[3][1];
  54.  v->eye_xform[3][2] = m[3][2];
  55. }
  56.  
  57.  
  58. void view_to_matrix(VIEW *v,MATRIX m)      /* view matrix to xform matrix */
  59. {
  60.  matrix_transpose(v->eye_xform, m);   /* copy matrix rotational inverse */
  61.  m[3][0] = v->eye_xform[3][0];        /* direct inverse gaze point */
  62.  m[3][1] = v->eye_xform[3][1];
  63.  m[3][2] = v->eye_xform[3][2];
  64. }
  65.  
  66.  
  67.  
  68. /************ VERTEX AND POLY COPY MEMORY ALLOCATION ************/
  69.  
  70. #define MAXVERTICES 20
  71.  
  72. static NVERTEX *nvert[MAXVERTICES+10];  /* table of new poly vertices created */
  73. static int nvcount;                     /* table pointer/count (Z clip pass) */
  74. static int vtxcount;                /* number of vertices produced by clipper */
  75.  
  76.  
  77. static DSORT *vispolys = NULL;    /* an array of pointers to visible polygons */
  78. static DSORT *visobjs  = NULL;     /* used for object-first sort */
  79.  
  80. static DSORT *polist;        /* which array to put polys in */
  81.  
  82.  
  83. void *vtxram = NULL;       /* memory allocation area start */
  84.  
  85. static unsigned render_mem = 0;   /* size of memory */
  86. static int totpolys = 0;
  87. static int maxpolys = 1200;
  88.  
  89. static OK;              /* cleared if too many vertices */
  90.  
  91. NVERTEX *nvalloc;      /* memory alloc ptrs */
  92. NPOLY   *npalloc;      /* also used by external ASM routines */
  93.  
  94.  
  95. void reset_render()           /* free copy space */
  96. {
  97.  if (vtxram)   free(vtxram);
  98.  if (vispolys) free(vispolys);
  99.  if (visobjs)  free(visobjs);
  100.  vtxram = visobjs = vispolys = NULL;
  101. }
  102.  
  103.             /* get space for poly and vertex working copies */
  104. void *setup_render(unsigned mem, int polys)
  105. {
  106.  atexit(reset_render);
  107.  
  108.  maxpolys = polys;
  109.  render_mem = mem<<10;    /* number of K bytes */
  110.  
  111.  if (mem<16)
  112.    {
  113.      fprintf(stderr,"\nMust allocate at least 16K of memory for renderer!\n");
  114.      return NULL;
  115.    }
  116.  
  117.  if (mem>63)
  118.    {
  119.      fprintf(stderr,"\nCannot allocate more than 64K of memory for renderer!\n");
  120.      return NULL;
  121.    }
  122.  
  123.  if( (NULL==(vtxram   = (NVERTEX *)calloc(mem,1024))) ||
  124.      (NULL==(vispolys = (DSORT   *)calloc(maxpolys,sizeof(DSORT)))) ||
  125.      (NULL==(visobjs  = (DSORT   *)calloc(maxpolys,sizeof(DSORT))))  )
  126.     {
  127.      fprintf(stderr,"\nCannot allocate memory for renderer!\n");
  128.      return NULL;
  129.     }
  130.  
  131.  npalloc = (NPOLY *)vtxram;
  132.  nvalloc = (NVERTEX *)((char *)vtxram+render_mem-50);
  133.  if(init_math()) return NULL;
  134.  return vtxram;
  135. }
  136.  
  137.  
  138. static void init_render()               /* reclaim all vertex and poly space */
  139. {
  140.  npalloc = (NPOLY *)vtxram;
  141.  nvalloc = (NVERTEX *)((char *)vtxram+render_mem-50);
  142. }
  143.  
  144.  
  145.  
  146. static NVERTEX *newvertex()   /* alloc space for new vertex copy   */
  147. {                             /* nvalloc always = allocated vertex */
  148.  --nvalloc;
  149.  nvalloc->perspect = 0;                                    // initialize
  150.  if(FP_OFF(nvalloc)-FP_OFF(npalloc) < 200U) OK = 0;  // memory OK?
  151.  return nvalloc;
  152. }
  153.  
  154.  
  155. static NPOLY *newpoly()     /* alloc space for new poly copy            */
  156. {                           /* vertex array follows but allocated later */
  157.  NPOLY *p = npalloc++;
  158.  if(FP_OFF(nvalloc)-FP_OFF(npalloc) <
  159.           (200U + MAXVERTICES*sizeof(NVERTEX *)) ) OK = 0;  // memory OK?
  160.  return p;
  161. }
  162.  
  163.  
  164.  
  165. /********* Z CLIP AND VERTEX COPY *********/
  166.  
  167.  
  168. static NVERTEX *clip_z_int(VERTEX *v1, VERTEX *v2)
  169. {
  170.  NVERTEX *nv1,*nv2,*nv3;
  171.  
  172.  if ((nv1=v1->new_copy)==NULL)
  173.        nv1 = xy_transform(v1); // make sure that the
  174.  if ((nv2=v2->new_copy)==NULL)
  175.        nv2 = xy_transform(v2); // vertices are ready
  176.  
  177.  return z_hither_clip(nv1, nv2);
  178. }
  179.  
  180.  
  181. /*************** POLYGON CLIP AND PROCESS *************/
  182.  
  183. static unsigned hilite_flag = 0;
  184.  
  185. /*********** Z CLIP POLYGON, PROCESS XY IF OK *********/
  186.  
  187. static int zclip_loop(POLY *p)   // do in C as assembler can't help much (BC 3.1)
  188. {
  189.  int xy_outcode_or  = 0;
  190.  int xy_outcode_and = 15;
  191.  int j;
  192.  
  193.  char first_z_out;        /* first vertex Z outcode     */
  194.  VERTEX *first_z_vtx;     /* orig. (world) first vertex */
  195.  char last_z_out;         /* previous vertex Z outcode  */
  196.  VERTEX *last_z_vtx;      /* orig. (world) prev. vertex */
  197.  char z_ocode;
  198.  VERTEX **pv = p->points;
  199.  
  200.  first_z_vtx = last_z_vtx = *pv;
  201.  if ((first_z_out = last_z_out = z_ocode = first_z_vtx->z_outcode & HITHER)==0)
  202.    {
  203.      register int i = z_output( nvert[nvcount] = xy_transform(first_z_vtx) );
  204.      xy_outcode_or |= i;
  205.      xy_outcode_and &= i;
  206.      if(nvcount++ > MAXVERTICES) OK = 0;
  207.    }
  208.  
  209.  for (j=p->npoints;j>1;j--)
  210.    {
  211.      VERTEX *
  212.      v = *(++pv);
  213.      z_ocode = v->z_outcode & HITHER;
  214.      if (z_ocode != last_z_out)
  215.        {                                   // create clipped vertex
  216.      register int i = z_output( nvert[nvcount] = clip_z_int(last_z_vtx, v) );
  217.      xy_outcode_or |= i;
  218.      xy_outcode_and &= i;
  219.      if(nvcount++ > MAXVERTICES) OK = 0;
  220.        }
  221.       last_z_vtx = v;
  222.       if ((last_z_out = z_ocode)==0)               // convert original if OK
  223.     {
  224.       register int i = z_output( nvert[nvcount] = xy_transform(v) );
  225.       xy_outcode_or |= i;
  226.       xy_outcode_and &= i;
  227.       if(nvcount++ > MAXVERTICES) OK = 0;
  228.     }
  229.    }
  230.  
  231.  if (first_z_out != last_z_out)     // do we need to flush clipper?
  232.    {
  233.      register int i = z_output( nvert[nvcount] =
  234.                     clip_z_int(last_z_vtx, first_z_vtx) );
  235.      xy_outcode_or |= i;
  236.      xy_outcode_and &= i;              // create clipped vertex
  237.      if(nvcount++ > MAXVERTICES) OK = 0;
  238.    }
  239.  
  240.   if(xy_outcode_and) return -1;   // -1 if poly will be completely destroyed
  241.   return (xy_outcode_or);      // 0 if no XY clip required
  242. }
  243.  
  244.  
  245. /************ POLYGON PROCESSING PIPELINE *********/
  246.  
  247. static int depth_type;        /* selects depth sort style */
  248.  
  249.  
  250. static void proc_poly(POLY *p)  /* accept/reject tests on polys */
  251. {                               /* transforms vertices, clips   */
  252.  int i,j,k;                     /* and computes screen coords   */
  253.  char z_outcode_or  = 0;        /* Also copies polys and points */
  254.  char z_outcode_and = 3;        /* for minimum disruption of    */
  255.                 /* the world database           */
  256.  
  257.  NPOLY *np;             // new poly copy
  258.  NVERTEX **nvp = &nvert[0];  // pointer into vertex list
  259.  NVERTEX **vpoly;            // vertex pointer storage allocation
  260.  
  261.  
  262.  long poly_depth;
  263.  int xy_outcode_or;    // 0 if poly needs no clipping
  264.  
  265.  if(p->npoints>2 && is_poly_facing(p)>= 0) return;   // backfacing poly?
  266.  else
  267.    {
  268.      int i;
  269.      VERTEX **v = p->points;
  270.  
  271.      for(i=p->npoints;i>0;i--)     // z transform all vertices
  272.        {
  273.      int o = z_convert_vertex(*v++);
  274.      z_outcode_or |= o;
  275.      z_outcode_and &= o;
  276.        }
  277.     }
  278.  
  279.  if (z_outcode_and == HITHER ||
  280.      z_outcode_and == YON)  return;       /* all hither/yon? Reject poly */
  281.  
  282.             /* otherwise, begin Z clip and XY transforms */
  283.  
  284.  
  285.          /* Pass 2: */
  286.          /* Z-clip and XY conv. vertices   */
  287.          /* also make copies to temp array */
  288.  
  289.  nvcount = 0;    // initialize vertex buffer
  290.  
  291.  xy_outcode_or = zclip_loop(p);
  292.  
  293.  if( (nvcount<3 && p->npoints>2) ||    // poly and degenerate
  294.       xy_outcode_or == -1)              // completely outside window
  295.     {
  296.        return;   /* reject poly if degenerate */
  297.     }
  298.  
  299. // ////////////// OK, we have a set of XY vertices. ///////////
  300.  
  301.  np = newpoly();           // create polygon copy, initialize
  302.  np->parent = p;
  303.  
  304.  vpoly = (NVERTEX **)npalloc; /* used to allocate space for new poly vertex  */
  305.                   /* pointer list: vertex ptrs after poly struct */
  306.  
  307.  if(depth_type & AVERAGE)     // depth before clipping XY
  308.    {
  309.      poly_depth = average_nvertex_depth(nvp, nvcount);
  310.    }
  311.  else         /* default: use deepest Z in polygon */
  312.    {
  313.      poly_depth = deepest_nvertex_depth(nvp, nvcount);
  314.    }
  315.  
  316.  if(depth_type & ATBACK)  poly_depth |= 0x40000000; // force to back
  317.  
  318.  np->maxz = poly_depth;
  319.  
  320.  if((xy_outcode_or) == 0)    /* does poly need XY clipping? */
  321.   {
  322.     memcpy(vpoly, nvp, nvcount*sizeof(NVERTEX *) );  // no, copy to list
  323.     np->npoints = vtxcount = nvcount;
  324.   }
  325.  else                           /* yes: XY clip it to list */
  326.   {
  327.     vtxcount = XY_clip_array(nvp,vpoly,nvcount);
  328.     if(vtxcount==-1)
  329.       {
  330.        OK = 0;        // copy: out of vertex space!
  331.        return;
  332.       }
  333.  
  334.    if((vtxcount<3 && p->npoints>2) || vtxcount<2)
  335.      {
  336.        return;      /* discard degenerate poly */
  337.      }
  338.    np->npoints = vtxcount;
  339.   }
  340.  
  341.  vpoly += vtxcount;        // alloc space for vertex ptrs
  342.  npalloc = (NPOLY *)vpoly;      /* update space pointer */
  343.  
  344.  np->color = user_poly_color(p, p->color|hilite_flag, p->npoints, poly_depth); /* user poly color select */
  345.  
  346.             /* add to list of polys to render */
  347.  if (totpolys < maxpolys)
  348.   {
  349.    polist[totpolys].ptr = np;
  350.    polist[totpolys++].depth = poly_depth & 0xFFFFFFFE;
  351.   }
  352.  else OK = 0;
  353. }
  354.  
  355.  
  356.  
  357.  
  358.  
  359. /************ ALLOWS EXTERNAL (HORIZON) POLYS TO USE CLIPPER ***********/
  360.  
  361. void submit_poly(NPOLY *p, long maxz);   // fwd decl
  362.  
  363. void render_ext_poly(int npoints, int vx[20], int vy[20], unsigned color)
  364. {
  365.  NPOLY *ext_poly = NULL;
  366.  int ext_oor, ext_oand;   /* outcode and, or */
  367.  NVERTEX **ext_vlist;     /* used to store original vertexes */
  368.  NVERTEX **vpoly;         // vertex storage allocation
  369.  int i;
  370.  
  371.  if(npoints<3) return;
  372.  
  373.  init_render();
  374.  ext_poly = newpoly();
  375.  if(!ext_poly) return;
  376.  ext_vlist = &(nvert[0]);
  377.  vpoly = (NVERTEX **) npalloc;      // save memory ptr
  378.  
  379.  for(i=0; i<npoints;i++)
  380.    {
  381.     int ocode = 0;
  382.  
  383.     NVERTEX *v = newvertex();
  384.     long x = vx[i];
  385.     long y = vy[i];
  386.  
  387.     v->xs = x<<2;
  388.     v->ys = y<<2;
  389.     if((x<<2)<VS_left4)   ocode |= LEFT;
  390.     if((x<<2)>VS_right4)  ocode |= RIGHT;
  391.     if((y<<2)<VS_top4)    ocode |= TOP;
  392.     if((y<<2)>VS_bottom4) ocode |= BOTTOM;
  393.     ext_oor |= ocode;
  394.     ext_oand &= ocode;
  395.     v->outcode = ocode;
  396.     *ext_vlist++ = v;
  397.    }
  398.  
  399.  ext_poly->color = color;
  400.  ext_poly->parent = NULL;
  401.  
  402.  if(ext_oand) return;   /* reject poly if degenerate */
  403.  ext_poly->npoints = npoints;
  404.  ext_vlist = &(nvert[0]);
  405.  
  406.  if((ext_oor) == 0)    /* does poly need XY clipping? */
  407.   {
  408.    for(i=0;i<npoints;i++) *vpoly++ = *ext_vlist++;
  409.   }
  410.  else                           /* yes: XY clip it */
  411.   {
  412.    vtxcount = XY_clip_array(ext_vlist,vpoly,npoints);
  413.    if(vtxcount==-1)
  414.       {
  415.        OK = 0;
  416.        return;
  417.       }
  418.    vpoly += vtxcount;
  419.  
  420.    if(vtxcount==0) return;
  421.    ext_poly->npoints = vtxcount;
  422.   }
  423.  
  424.  npalloc = (NPOLY *)vpoly;         /* update space pointer */
  425.  
  426.  submit_poly(ext_poly, 0x7FFFFFFFL);
  427.  
  428.  init_render();
  429.  
  430. }
  431.  
  432.  
  433. /********** SCREEN-POINT MONITOR ***********/
  434.  
  435.  
  436. static OBJECT *current_object;    // needed for memory mapping of monitor
  437.  
  438. static int  monitor_test_enabled = 0;
  439.  
  440. static int  monitor_test_point_x;     // screen coords
  441. static int  monitor_test_point_y;
  442. static int  monitor_test_point_tx;    // prescaled renderer coords
  443. static int  monitor_test_point_ty;
  444.  
  445. static unsigned monitor_min_vtx_distance; // prescaled x4, city block dist
  446. static int  monitor_which_vertex;   /* npoly vertex # closest <UNTESTED YET> */
  447.                     // set to -1 when new best poly found
  448.                     // to force after-subrender rescan
  449. static POLY *monitor_which_poly;
  450.  
  451. static OBJECT *monitor_which_object;
  452.  
  453. static long monitor_poly_depth;
  454. static long monitor_min_depth = 0;
  455.  
  456.  
  457. static void monitor_vertex_scan()    // scans for vertex closest to point
  458. {                // do after end of subrender (poor speed)
  459.  int i,j,n;
  460.  VERTEX **vt;
  461.  VERTEX *v;
  462.  NVERTEX *nv;
  463.  unsigned dm, closest = monitor_min_vtx_distance;
  464.  
  465.  if(monitor_which_poly == NULL) return;    // none found
  466.  if(monitor_which_vertex != -1) return;    // no need to scan
  467.  
  468.  accessptr(monitor_which_poly); // access memory!
  469.  
  470.  vt = monitor_which_poly->points;    // we scan original poly for order
  471.  i =  monitor_which_poly->npoints;
  472.  n = -1;
  473.  
  474.  for(j=0;j<i;j++)
  475.    {
  476.      v = *vt++;
  477.      if(v->z_outcode!=0 || v->new_copy==NULL) continue; // have a renderer vtx?
  478.      nv = v->new_copy;
  479.  
  480.      if(nv->outcode) continue;    // skip if clipped
  481.  
  482.      dm = abs(nv->xs - monitor_test_point_tx) +     // is it closest?
  483.       abs(nv->ys - monitor_test_point_ty);
  484.      if (dm<closest)
  485.        {
  486.      closest = dm;
  487.      n = j;
  488.        }
  489.    }
  490.  monitor_which_vertex = n;
  491. }
  492.  
  493. void set_screen_monitor(int x, int y)
  494. {
  495.  monitor_test_enabled = 1;
  496.  monitor_test_point_x = x;
  497.  monitor_test_point_y = y;
  498.  monitor_test_point_tx = x<<2;    // prescaled
  499.  monitor_test_point_ty = y<<2;
  500.  monitor_poly_depth = 0x7FFFFFFF;
  501.  monitor_which_poly = NULL;
  502.  monitor_which_object = NULL;
  503.  monitor_which_vertex = -1;
  504.  monitor_min_depth = 0;
  505.  monitor_min_vtx_distance = 200;    // prescaled x4, city block dist
  506. }
  507.  
  508.  
  509. void clear_screen_monitor()
  510. {
  511.  monitor_test_enabled = 0;
  512. }
  513.  
  514.  
  515. OBJECT *screen_monitor_object()
  516. {
  517.  return monitor_which_object;
  518. }
  519.  
  520. POLY *screen_monitor_poly()
  521. {
  522.  return monitor_which_poly;
  523. }
  524.  
  525. int screen_monitor_vertex()
  526. {
  527.  return monitor_which_vertex;
  528. }
  529.  
  530.  
  531. /************ UNPACK NPOLY VERTICES, RENDER **********/
  532.  
  533.  
  534. static int pcoords[MAXVERTICES*2];   /* WHERE VERTICES GO TO BE DRAWN */
  535.  
  536. // routine used to draw polys
  537. extern void user_render_poly(WORD vertex_count, WORD *pcoords,
  538.                  SURFACE poly_color, COORD max_depth);
  539.  
  540.  
  541.             /* copies poly data, submits to renderer   */
  542.             /* copy in reverse order if flipped screen */
  543.             /* if monitor turned on, checks poly too   */
  544. static void submit_poly(NPOLY *p, long maxz)
  545. {
  546.  int number;
  547.  int polarity;
  548.  int vtx;
  549.  
  550.  polarity = VS_orientation & (XFLIP|YFLIP);
  551.  if(polarity==(XFLIP|YFLIP)) polarity = 0;
  552.  
  553.  number = unpack_poly_vertices(p, pcoords, polarity);
  554.  
  555.  if(monitor_test_enabled)
  556.   {
  557.    if ( number>2 && p->parent   &&
  558.     maxz<monitor_poly_depth &&
  559.     maxz>monitor_min_depth  )
  560.  
  561.     {
  562.      if(-1 != monitor_test_poly(monitor_test_point_x,
  563.                  monitor_test_point_y,
  564.                  number, &pcoords[0]) )
  565.       {
  566.        monitor_poly_depth = maxz;       // new search goal
  567.        monitor_which_vertex = -1;       // mark rescan needed
  568.        monitor_which_poly = p->parent;  // record poly
  569.        accessptr(monitor_which_poly);   // make memory accesible
  570.        monitor_which_object = monitor_which_poly->object;  // hold onto object!
  571.       }
  572.     }
  573.   }
  574.  
  575.  user_render_poly(number, &pcoords[0], p->color, maxz);
  576. }
  577.  
  578.  
  579. /*********** LIGHTING SUPPORT ***********/
  580.  
  581. // given poly, computes its cosine*127 from its first
  582. // vertex to the given point.  Used for lighting.
  583.  
  584. extern int light_cosine(long nx, long ny, long nz, // poly normal
  585.             long vx, long vy, long vz, // poly vertex
  586.             long  x, long y,  long z); // light location
  587.  
  588. int compute_poly_cosine(POLY *p, long x, long y, long z, int vect)
  589. {
  590.  accessptr(p);    // map in EMM
  591.  
  592.  if(vect==0)
  593.    return light_cosine(p->normalx, p->normaly, p->normalz,
  594.                p->points[0]->x,p->points[0]->y,p->points[0]->z,
  595.                x, y, z);
  596.  else
  597.    return light_cosine(p->normalx, p->normaly, p->normalz, 0,0,0, x, y, z);
  598. }
  599.  
  600.  
  601.  
  602. /*********** OBJECT-RENDERING CONTROL **********/
  603.  
  604. //     called before drawing obj
  605. static void (*update_obj_handler)(OBJECT *o) = NULL;
  606.  
  607.     //  sets up routine to be called when an object's
  608.     // representation is to be displayed that needs updating
  609.     // usually used to move representations to match object
  610. void *set_renderer_update_handler(void (*handler)(OBJECT *o) )
  611. {
  612.   void *h = update_obj_handler;
  613.  
  614.   update_obj_handler = handler;
  615.  
  616.   return h;
  617. }
  618.  
  619.  
  620. static int proc_obj(OBJECT *obj, long centz)
  621. {
  622.  REP *repp;
  623.  long oscreen;
  624.  
  625.  static int i;    // SCOPING BUG
  626.  static POLY *p;
  627.  
  628.  if(obj==NULL) return 1;
  629.  
  630.  if(obj->oflags&OBJ_REPLOCK)    // never change representation
  631.   {
  632.    repp = obj->current_rep;
  633.    goto use_it;
  634.   }
  635.  
  636.  if((repp = obj->replist)==NULL) return 1;   /* no representation */
  637.  if(repp->size==0) goto usethis;             /* 0 size always drawn */
  638.  if(centz<VS_hither) goto usethis;           /* bad center */
  639.  
  640.  oscreen = compute_obj_screen_size(obj, centz);  // width on screen
  641.  if(oscreen<0) goto usethis;
  642.  
  643.  while(repp!=NULL)                /* choose representation to use: */
  644.   {                             /* 0 or just smaller size always drawn */
  645.    if(oscreen>=(repp->size)) goto usethis;
  646.    if(repp->next!=NULL) repp = repp->next;
  647.    else return 1;        // too small: don't draw at all
  648.   }
  649.  
  650. usethis:            // set new representation
  651.  obj->current_rep = repp;
  652.  if(repp==NULL)                 // exit if still nothing
  653.     return 1;
  654.  
  655. use_it:
  656.  
  657.     // THIS CODE DEPENDS ON WHAT UPDATING THE REPRESENTATION
  658.     // MAY NEED.  HERE, IT MAY NEED TO BE MOVED TO MATCH THE
  659.     // CACHED OBJECT POSITION.
  660.     // THE ROUTINE SHOULD INCREMENT THE UPDATE COUNTS EACH
  661.     // TIME IT IS CALLED, OR LEAVE THEM DIFFERENT IF IT
  662.     // IS TO BE CALLED EVERY TIME
  663.  
  664.   if(obj->update_count != repp->update_count  && update_obj_handler!= NULL)
  665.     {
  666.       accessptr(repp->polys);    // used for mapping EMM
  667.  
  668.       update_obj_handler(obj);
  669.     }
  670.  
  671.   hilite_flag = (obj->oflags&OBJ_HIGHLIGHTED) ? 0x8000 : 0;  // auto-hilite object
  672.   accessptr(repp->polys);    // used for mapping EMM
  673.  
  674.   prerender_clear_object(obj);
  675.  
  676.   for(i=repp->npolys,p=repp->polys;i>0;i--)
  677.     {
  678.      proc_poly(p++);
  679.      if(!OK) break;
  680.     }
  681.  
  682.  return 0;  /* return 0, object was drawn */
  683. }
  684.  
  685.  
  686. /*************** OBJECT LIST RENDERING *************/
  687.  
  688.  
  689. #define OUT_OF_VIEW 0x80000000L    // returned if we can't see object
  690.  
  691. // EXTERNAL renderer interface
  692.  
  693. extern void user_setup_blitter();
  694. extern void user_reset_blitter();
  695.  
  696.  
  697. void subrender(OBJLIST *objlist)
  698. {
  699.  static OBJECT *obj;
  700.  static int i;      // SCOPING BUG!
  701.  static int snpoly = 0;
  702.  static int nobs = 0;
  703.  static long center_z;
  704.  static unsigned f;
  705.  
  706.  init_render();
  707.  user_setup_blitter();                /* draw the polys */
  708.  
  709.  if(objlist==NULL ||
  710.     objlist->nnext==NULL ||
  711.     objlist->nnext==objlist->prev)  return;
  712.  
  713.  totpolys = 0;               // BY_OBJ SORTING DISABLED FOR NOW
  714.  OK = 1;
  715.                 /* step 1: sort objects and polys together */
  716.  polist = visobjs;
  717.  for (obj = objlist->nnext; obj; obj = obj->nnext)
  718.   {
  719. //    if(!obj) break;
  720.     f = obj->oflags;
  721.     if (!(f&IS_VISOBJ)) continue;      // non-visible object type
  722.     if (f & OBJ_INVIS) continue;      /* invisible object */
  723.  
  724.     if ((center_z=obj_clip_by_volume(obj)) != OUT_OF_VIEW)
  725.      {
  726.       if((depth_type = obj->oflags)&BYOBJECT)
  727.     {
  728. //      obj->oflags |= IS_VISOBJ;
  729.       polist[totpolys].ptr = (NPOLY *) obj;             /* obj. depth only */
  730.       polist[totpolys++].depth = center_z | 1;
  731.     }
  732.        else
  733.     {
  734.      proc_obj(obj, center_z);                /* all polys in object */
  735.      if(OK==0) break;
  736.     }
  737.      }
  738.   }
  739.  
  740.  if(totpolys>16)
  741.     qsort_dsort( &visobjs[0], &visobjs[totpolys-1] );
  742.  else if(totpolys>1)
  743.     insertion_dsort( &visobjs[0], &visobjs[totpolys-1] );
  744.  
  745.  nobs = totpolys;
  746.  
  747.  totpolys = 0;
  748.  polist = vispolys;
  749.  
  750.  for (i=0;i<nobs;i++)                  /* now expand objects */
  751.   {
  752.    if((visobjs[i].depth & 1)==0)
  753.     {
  754.      memcpy(&vispolys[totpolys++], &visobjs[i], sizeof(DSORT));   /* just copy polys */
  755.     }
  756.    else
  757.     {
  758.      snpoly = totpolys;                   /* expand objects */
  759.      proc_obj((OBJECT *) visobjs[i].ptr, visobjs[i].depth);
  760.      if(OK==0) break;
  761.      if(totpolys-snpoly>16)
  762.        qsort_dsort( &vispolys[snpoly], &vispolys[totpolys-1] );
  763.      if(totpolys-snpoly>1)
  764.        insertion_dsort( &vispolys[snpoly], &vispolys[totpolys-1] );
  765.     }
  766.    if(totpolys >= maxpolys) break;
  767.   }
  768.  
  769.  for (i = 0; i < totpolys; i++)
  770.     submit_poly(vispolys[i].ptr,vispolys[i].depth);
  771.  user_reset_blitter();
  772.  
  773.  if (monitor_test_enabled && monitor_which_poly!=NULL);
  774.    {
  775.      accessptr(monitor_which_poly);   // make memory accesible
  776.      monitor_vertex_scan(); // if a poly found, process it
  777.    }
  778. }
  779.  
  780.  
  781. void render(OBJLIST *objlist, VIEW *view)
  782. {
  783.  render_set_view(view);
  784.  subrender(objlist);
  785. }
  786.