The Wayback Machine - https://web.archive.org/web/20130104200822/http://mamedev.org/source/src/mame/video/model2.c.html

Viewing File: <root>/src/mame/video/model2.c

    1  /*********************************************************************************************************************************
    2  
    3      Sega Model 2 Geometry Engine and 3D Rasterizer Emulation
    4  
    5      General Notes:
    6  
    7      - The 3D rendering system has 3 main parts:
    8          1) The Geometry Engine: Model 2B and 2C hardware upload the geometry code to a DSP. The original and 2A hardware
    9          have the geometry code in an internal ROM inside the DSP itself. The simulation written here for the geometry engine
   10          is based off the disassembly of the code uploaded to a 2B game.
   11          2) The Z-Sort and Clip Hardware: Not much information about this hardware. There are a couple of variables that
   12          can be passed to this stage, like a master Z-Clip enable register, and a Z-Sort mode variable.
   13          3) The Hardware Renderer: Not much information about the inner workings of this hardware. Based on the available
   14          tidbits from the 2B manual, it is a double-buffered device (can be toggled between page flipping and single
   15          buffer mode), and can also be switched to generate output at 60Hz or 30Hz.
   16  
   17      - Most of the information used to write this code come from 3 main sources:
   18          1) The Geometry Engine code disassembly from a 2B game.
   19          2) The Model 2B-CRX Manual.
   20          3) ElSemi's Direct3D implementation of the geometrizer engine.
   21  
   22      - The emulation strategy used here is to decouple the geometrizer code from the Z-Sort/Clip/Renderer code, so that for
   23      original and 2A games, the HLE version of the geometrizer can be used, while for 2B and 2C games, the original geometrizer
   24      DSP can be emulated, and data can be pushed to the Z-Sort/Clip/Renderer code.
   25  
   26  
   27  
   28      Geometry Engine Notes and Known Bugs:
   29  
   30      - Top Skater seem to use a slightly different geometry code that has a secondary transformation matrix. Once we implement
   31      the real DSP code upload and emulation for 2B and 2C games, this should not be an issue.
   32  
   33  
   34  
   35      Z-Sort Notes and Known Bugs:
   36  
   37      - The Z-Sort algorithm is not entirely understood. The manual states that the Z-Sort works internally in 1.4.8 bit format,
   38      but then it states that the Z-Sort Mode register value is added to the floating point z value, and converted to a 16 bit
   39      format (most likely 4.12).
   40      - The system allows for Z-Sort override, by means of specifying whether a polygon will use the same Z value ordinal as the
   41      previous polygon, or the calculated minimum or maximum from it's points. This allows for a full object to be in front of
   42      another, even though the first object might have some z coordinates that are bigger than the second object's z coordinates.
   43      - The current implementation takes the effective computed z value for the polygon and converts it into a 4.12 fixed point
   44      representation, used as an index into an array of linked polygons. Every polygon with the same z value is linked with any
   45      previous polygon that had that same z value:
   46  
   47          z-value index   linked list of polygons
   48              0000        triangle3->triangle2->triangle1
   49              0001        triangle22->triangle8->triangle7
   50              ....
   51              FFFF        triangle33->triangle11->triangle9
   52  
   53      As we add polygons to the array, we also keep track of the minimum and maximum z-value indexes seen this frame.
   54      When it's time to render, we start and the max z-value seen, and iterate through the array going down to the minimum
   55      z-value seen, clipping and rendering the linked polygons as we go.
   56      Unfortunately, it seems there's something not quite right, as there are some visible Z-Sort problems in various games.
   57      Perhaps the linked list of polygons need to be presorted by a unknown factor before rendering.
   58  
   59  
   60  
   61      Clip Notes and Known Bugs:
   62  
   63      - The Z-Clip happens at z=0. Since dividing by 0 during projection would give bogus values, we scale by a distance of
   64      1, thus our projection equation turns into vd.x = (d*vs.x) / (d+vs.z) where d = 1, since we know we won't have polygons
   65      with a z < 0. This, however, poses the problem that for objects originally between 0.0 and 1.0 are not going to be
   66      scaled properly. We still need to find a solution for this.
   67      - A small offset need to be added horizontally and vertically to the viewport and center variables for certain games (like
   68      the original Model 2 games). The coordinate system has been worked out from the 2B specifications, but the older games
   69      need a slight adjustment.
   70  
   71  
   72  
   73      Hardware Renderer Notes and Known Bugs:
   74  
   75      - Texturing code could use a real good speed optimization.
   76      - The U and V coordinates provided by the game are in 13.3 fixed point format.
   77      - The luma/texel combination algorithm is not known. There are currently some small color glitches here and
   78      there, and this might be the culprit.
   79      - The log tables and distance coefficients are used to calculate the number of texels per world unit that need to
   80      be used to render a texture. Textures can also be provided with smaller levels of details and a LOD bit selector
   81      in the texture header tells the rasterizer which texture map to use. The rasterizer then can average two texture
   82      maps to do mip mapping. More information can be found on the 2B manual, on the 'Texturing' and 'Data Format' chapters.
   83      This is currently unemulated. We always use the texture data from the bigger texture map.
   84      - The rasterizer supports up to 128x128 'microtex' textures, which are supposed to be higher resolution textures used
   85      to display more detail when a texture is real close to the viewer. This is currently unemulated.
   86  
   87  *********************************************************************************************************************************/
   88  #include "emu.h"
   89  #include "video/segaic24.h"
   90  #include "video/poly.h"
   91  #include "includes/model2.h"
   92  
   93  #define DEBUG 0
   94  
   95  
   96  #define pz      p[0]
   97  #define pu      p[1]
   98  #define pv      p[2]
   99  
  100  
  101  /*******************************************
  102   *
  103   *  Basic Data Types
  104   *
  105   *******************************************/
  106  
  107  struct plane
  108  {
  109      poly_vertex normal;
  110      float       distance;
  111  };
  112  
  113  struct texture_parameter
  114  {
  115      float   diffuse;
  116      float   ambient;
  117      UINT32  specular_control;
  118      float   specular_scale;
  119  };
  120  
  121  struct triangle
  122  {
  123      void *              next;
  124      poly_vertex         v[3];
  125      UINT16              z;
  126      UINT16              texheader[4];
  127      UINT8               luma;
  128      INT16               viewport[4];
  129      INT16               center[2];
  130  };
  131  
  132  struct quad_m2
  133  {
  134      poly_vertex         v[4];
  135      UINT16              z;
  136      UINT16              texheader[4];
  137      UINT8               luma;
  138  };
  139  
  140  struct poly_extra_data
  141  {
  142      model2_state *  state;
  143      UINT32      lumabase;
  144      UINT32      colorbase;
  145      UINT32 *    texsheet;
  146      UINT32      texwidth;
  147      UINT32      texheight;
  148      UINT32      texx, texy;
  149      UINT8       texmirrorx;
  150      UINT8       texmirrory;
  151  };
  152  
  153  
  154  /*******************************************
  155   *
  156   *  Generic 3D Math Functions
  157   *
  158   *******************************************/
  159  
  160  INLINE void transform_point( poly_vertex *point, float *matrix )
  161  {
  162      float tx = (point->x * matrix[0]) + (point->y * matrix[3]) + (point->pz * matrix[6]) + (matrix[9]);
  163      float ty = (point->x * matrix[1]) + (point->y * matrix[4]) + (point->pz * matrix[7]) + (matrix[10]);
  164      float tz = (point->x * matrix[2]) + (point->y * matrix[5]) + (point->pz * matrix[8]) + (matrix[11]);
  165  
  166      point->x = tx;
  167      point->y = ty;
  168      point->pz = tz;
  169  }
  170  
  171  INLINE void transform_vector( poly_vertex *vector, float *matrix )
  172  {
  173      float tx = (vector->x * matrix[0]) + (vector->y * matrix[3]) + (vector->pz * matrix[6]);
  174      float ty = (vector->x * matrix[1]) + (vector->y * matrix[4]) + (vector->pz * matrix[7]);
  175      float tz = (vector->x * matrix[2]) + (vector->y * matrix[5]) + (vector->pz * matrix[8]);
  176  
  177      vector->x = tx;
  178      vector->y = ty;
  179      vector->pz = tz;
  180  }
  181  
  182  INLINE void normalize_vector( poly_vertex *vector )
  183  {
  184      float n = sqrt( (vector->x * vector->x) + (vector->y * vector->y) + (vector->pz * vector->pz) );
  185  
  186      if ( n )
  187      {
  188          float oon = 1.0f / n;
  189          vector->x *= oon;
  190          vector->y *= oon;
  191          vector->pz *= oon;
  192      }
  193  }
  194  
  195  INLINE float dot_product( poly_vertex *v1, poly_vertex *v2 )
  196  {
  197      return (v1->x * v2->x) + (v1->y * v2->y) + (v1->pz * v2->pz);
  198  }
  199  
  200  INLINE void vector_cross3( poly_vertex *dst, poly_vertex *v0, poly_vertex *v1, poly_vertex *v2 )
  201  {
  202      poly_vertex p1, p2;
  203  
  204      p1.x = v1->x - v0->x;   p1.y = v1->y - v0->y;   p1.pz = v1->pz - v0->pz;
  205      p2.x = v2->x - v0->x;   p2.y = v2->y - v0->y;   p2.pz = v2->pz - v0->pz;
  206  
  207      dst->x = (p1.y * p2.pz) - (p1.pz * p2.y);
  208      dst->y = (p1.pz * p2.x) - (p1.x * p2.pz);
  209      dst->pz = (p1.x * p2.y) - (p1.y * p2.x);
  210  }
  211  
  212  /* 1.8.23 float to 4.12 float converter, courtesy of Aaron Giles */
  213  static UINT16 float_to_zval( float floatval )
  214  {
  215      INT32 fpint = f2u(floatval);
  216      INT32 exponent = ((fpint >> 23) & 0xff) - 127;
  217      UINT32 mantissa = fpint & 0x7fffff;
  218  
  219      /* round the low bits and reduce to 12 */
  220      mantissa += 0x400;
  221      if (mantissa > 0x7fffff) { exponent++; mantissa = (mantissa & 0x7fffff) >> 1; }
  222      mantissa >>= 11;
  223  
  224      /* if negative, clamp to 0 */
  225      if (fpint < 0)
  226          return 0x0000;
  227  
  228      /* the rest depends on the exponent */
  229      /* less than -12 is too small, return 0 */
  230      if ( exponent < -12 )
  231          return 0x0000;
  232  
  233      /* between -12 and 0 create a denormal with exponent of 0 */
  234      else if ( exponent < 0 )
  235          return (mantissa | 0x1000) >> -exponent;
  236  
  237      /* between 0 and 14 create a FP value with exponent + 1 */
  238      else if ( exponent < 15 )
  239          return (( exponent + 1 ) << 12) | mantissa;
  240  
  241      /* above 14 is too large */
  242      return 0xffff;
  243  }
  244  
  245  static INT32 clip_polygon(poly_vertex *v, INT32 num_vertices, plane *cp, poly_vertex *vout)
  246  {
  247      poly_vertex *cur, *out;
  248      float   curdot, nextdot, scale;
  249      INT32   i, curin, nextin, nextvert, outcount;
  250  
  251      outcount = 0;
  252  
  253      cur = v;
  254      out = vout;
  255  
  256      curdot = dot_product( cur, &cp->normal );
  257      curin = (curdot >= cp->distance) ? 1 : 0;
  258  
  259      for( i = 0; i < num_vertices; i++ )
  260      {
  261          nextvert = (i + 1) % num_vertices;
  262  
  263          /* if the current point is inside the plane, add it */
  264          if ( curin ) memcpy( &out[outcount++], cur, sizeof( poly_vertex ) );
  265  
  266          nextdot = dot_product( &v[nextvert], &cp->normal );
  267          nextin = (nextdot >= cp->distance) ? 1 : 0;
  268  
  269          /* Add a clipped vertex if one end of the current edge is inside the plane and the other is outside */
  270          if ( curin != nextin )
  271          {
  272              scale = (cp->distance - curdot) / (nextdot - curdot);
  273  
  274              out[outcount].x = cur->x + ((v[nextvert].x - cur->x) * scale);
  275              out[outcount].y = cur->y + ((v[nextvert].y - cur->y) * scale);
  276              out[outcount].pz = cur->pz + ((v[nextvert].pz - cur->pz) * scale);
  277              out[outcount].pu = (UINT16)((float)cur->pu + (((float)v[nextvert].pu - (float)cur->pu) * scale));
  278              out[outcount].pv = (UINT16)((float)cur->pv + (((float)v[nextvert].pv - (float)cur->pv) * scale));
  279              outcount++;
  280          }
  281  
  282          curdot = nextdot;
  283          curin = nextin;
  284          cur++;
  285      }
  286  
  287      return outcount;
  288  }
  289  
  290  /***********************************************************************************************/
  291  
  292  /*******************************************
  293   *
  294   *  Hardware 3D Rasterizer Internal State
  295   *
  296   *******************************************/
  297  
  298  #define MAX_TRIANGLES       32768
  299  
  300  struct raster_state
  301  {
  302      UINT32              mode;               /* bit 0 = Test Mode, bit 2 = Switch 60Hz(1)/30Hz(0) operation */
  303      UINT16 *            texture_rom;        /* Texture ROM pointer */
  304      INT16               viewport[4];        /* View port (startx,starty,endx,endy) */
  305      INT16               center[4][2];       /* Centers (eye 0[x,y],1[x,y],2[x,y],3[x,y]) */
  306      UINT16              center_sel;         /* Selected center */
  307      UINT32              reverse;            /* Left/Right Reverse */
  308      float               z_adjust;           /* ZSort Mode */
  309      float               triangle_z;         /* Current Triangle z value */
  310      UINT8               master_z_clip;      /* Master Z-Clip value */
  311      UINT32              cur_command;        /* Current command */
  312      UINT32              command_buffer[32]; /* Command buffer */
  313      UINT32              command_index;      /* Command buffer index */
  314      triangle            tri_list[MAX_TRIANGLES];            /* Triangle list */
  315      UINT32              tri_list_index;     /* Triangle list index */
  316      triangle *          tri_sorted_list[0x10000];   /* Sorted Triangle list */
  317      UINT16              min_z;              /* Minimum sortable Z value */
  318      UINT16              max_z;              /* Maximum sortable Z value */
  319      UINT16          texture_ram[0x10000];       /* Texture RAM pointer */
  320      UINT8               log_ram[0x40000];           /* Log RAM pointer */
  321  };
  322  
  323  
  324  /*******************************************
  325   *
  326   *  Hardware 3D Rasterizer Initialization
  327   *
  328   *******************************************/
  329  
  330  static void model2_3d_init( running_machine &machine, UINT16 *texture_rom )
  331  {
  332      model2_state *state = machine.driver_data<model2_state>();
  333  
  334      state->m_raster = auto_alloc_clear( machine, raster_state );
  335  
  336      state->m_raster->texture_rom = texture_rom;
  337  }
  338  
  339  /*******************************************
  340   *
  341   *  Hardware 3D Rasterizer Z-Clip selection
  342   *
  343   *******************************************/
  344  
  345  void model2_3d_set_zclip( running_machine &machine, UINT8 clip )
  346  {
  347      model2_state *state = machine.driver_data<model2_state>();
  348      state->m_raster->master_z_clip = clip;
  349  }
  350  
  351  /*******************************************
  352   *
  353   *  Hardware 3D Rasterizer Processing
  354   *
  355   *******************************************/
  356  
  357  static void model2_3d_process_quad( raster_state *raster, UINT32 attr )
  358  {
  359      quad_m2     object;
  360      UINT16      *th, *tp;
  361      INT32       tho;
  362      UINT32      cull, i;
  363      float       zvalue;
  364      float       min_z, max_z;
  365  
  366      /* extract P0(n-1) */
  367      object.v[1].x = u2f( raster->command_buffer[2] << 8 );
  368      object.v[1].y = u2f( raster->command_buffer[3] << 8 );
  369      object.v[1].pz = u2f( raster->command_buffer[4] << 8 );
  370  
  371      /* extract P1(n-1) */
  372      object.v[0].x = u2f( raster->command_buffer[5] << 8 );
  373      object.v[0].y = u2f( raster->command_buffer[6] << 8 );
  374      object.v[0].pz = u2f( raster->command_buffer[7] << 8 );
  375  
  376      /* extract P0(n) */
  377      object.v[2].x = u2f( raster->command_buffer[11] << 8 );
  378      object.v[2].y = u2f( raster->command_buffer[12] << 8 );
  379      object.v[2].pz = u2f( raster->command_buffer[13] << 8 );
  380  
  381      /* extract P1(n) */
  382      object.v[3].x = u2f( raster->command_buffer[14] << 8 );
  383      object.v[3].y = u2f( raster->command_buffer[15] << 8 );
  384      object.v[3].pz = u2f( raster->command_buffer[16] << 8 );
  385  
  386      /* always calculate the min z and max z value */
  387      min_z = object.v[0].pz;
  388      if ( object.v[1].pz < min_z ) min_z = object.v[1].pz;
  389      if ( object.v[2].pz < min_z ) min_z = object.v[2].pz;
  390      if ( object.v[3].pz < min_z ) min_z = object.v[3].pz;
  391  
  392      max_z = object.v[0].pz;
  393      if ( object.v[1].pz > max_z ) max_z = object.v[1].pz;
  394      if ( object.v[2].pz > max_z ) max_z = object.v[2].pz;
  395      if ( object.v[3].pz > max_z ) max_z = object.v[3].pz;
  396  
  397      /* read in the texture information */
  398  
  399      /* texture point data */
  400      if ( raster->command_buffer[0] & 0x800000 )
  401          tp = &raster->texture_ram[raster->command_buffer[0] & 0xFFFF];
  402      else
  403          tp = &raster->texture_rom[raster->command_buffer[0] & 0x7FFFFF];
  404  
  405      object.v[0].pv = *tp++;
  406      object.v[0].pu = *tp++;
  407      object.v[1].pv = *tp++;
  408      object.v[1].pu = *tp++;
  409      object.v[2].pv = *tp++;
  410      object.v[2].pu = *tp++;
  411      object.v[3].pv = *tp++;
  412      object.v[3].pu = *tp++;
  413  
  414      /* update the address */
  415      raster->command_buffer[0] += 8;
  416  
  417      /* texture header data */
  418      if ( raster->command_buffer[1] & 0x800000 )
  419          th = &raster->texture_ram[raster->command_buffer[1] & 0xFFFF];
  420      else
  421          th = &raster->texture_rom[raster->command_buffer[1] & 0x7FFFFF];
  422  
  423      object.texheader[0] = *th++;
  424      object.texheader[1] = *th++;
  425      object.texheader[2] = *th++;
  426      object.texheader[3] = *th++;
  427  
  428      /* extract the texture header offset */
  429      tho = (attr >> 12) & 0x1F;
  430  
  431      /* adjust for sign */
  432      if ( tho & 0x10 )
  433          tho |= -16;
  434  
  435      /* update the address */
  436      raster->command_buffer[1] += tho * 4;
  437  
  438      /* set the luma value of this quad */
  439      object.luma = (raster->command_buffer[9] >> 15) & 0xFF;
  440  
  441      /* determine whether we can cull this quad */
  442      cull = 0;
  443  
  444      /* if doubleside is disabled */
  445      if ( ((attr >> 17) & 1) == 0 )
  446      {
  447          /* if it's the backface, cull it */
  448          if ( raster->command_buffer[9] & 0x00800000 )
  449              cull = 1;
  450      }
  451  
  452      /* if the linktype is 0, then we can also cull it */
  453      if ( ((attr >> 8) & 3) == 0 )
  454          cull = 1;
  455  
  456      /* if the minimum z value is bigger than the master z clip value, don't render */
  457      if ( (INT32)(1.0/min_z) > raster->master_z_clip )
  458          cull = 1;
  459  
  460      /* if the maximum z value is < 0 then we can safely clip the entire polygon */
  461      if ( max_z < 0 )
  462          cull = 1;
  463  
  464      /* set the object's z value */
  465      zvalue = raster->triangle_z;
  466  
  467      /* see if we need to recompute min/max z */
  468      if ( (attr >> 10) & 3 )
  469      {
  470          if ( (attr >> 10) & 1 ) /* min value */
  471          {
  472              zvalue = min_z;
  473          }
  474          else if ( (attr >> 10) & 2 ) /* max value */
  475          {
  476              zvalue = max_z;
  477          }
  478  
  479          raster->triangle_z = zvalue;
  480      }
  481  
  482      if ( cull == 0 )
  483      {
  484          INT32       clipped_verts;
  485          poly_vertex verts[10];
  486          plane       clip_plane;
  487  
  488          clip_plane.normal.x = 0;
  489          clip_plane.normal.y = 0;
  490          clip_plane.normal.pz = 1;
  491          clip_plane.distance = 0;
  492  
  493          /* do near z clipping */
  494          clipped_verts = clip_polygon( object.v, 4, &clip_plane, verts);
  495  
  496          if ( clipped_verts > 2 )
  497          {
  498              triangle *ztri;
  499  
  500              /* adjust and set the object z-sort value */
  501              object.z = float_to_zval( zvalue + raster->z_adjust );
  502  
  503              /* get our list read to add the triangles */
  504              ztri = raster->tri_sorted_list[object.z];
  505  
  506              if ( ztri != NULL )
  507              {
  508                  while( ztri->next != NULL )
  509                      ztri = (triangle *)ztri->next;
  510              }
  511  
  512              /* go through the clipped vertex list, adding triangles */
  513              for( i = 2; i < clipped_verts; i++ )
  514              {
  515                  triangle    *tri;
  516  
  517                  tri = &raster->tri_list[raster->tri_list_index++];
  518  
  519                  if ( raster->tri_list_index >= MAX_TRIANGLES )
  520                  {
  521                      fatalerror( "SEGA 3D: Max triangle limit exceeded\n" );
  522                  }
  523  
  524                  /* copy the object information */
  525                  tri->z = object.z;
  526                  tri->texheader[0] = object.texheader[0];
  527                  tri->texheader[1] = object.texheader[1];
  528                  tri->texheader[2] = object.texheader[2];
  529                  tri->texheader[3] = object.texheader[3];
  530                  tri->luma = object.luma;
  531  
  532                  /* set the viewport */
  533                  tri->viewport[0] = raster->viewport[0];
  534                  tri->viewport[1] = raster->viewport[1];
  535                  tri->viewport[2] = raster->viewport[2];
  536                  tri->viewport[3] = raster->viewport[3];
  537  
  538                  /* set the center */
  539                  tri->center[0] = raster->center[raster->center_sel][0];
  540                  tri->center[1] = raster->center[raster->center_sel][1];
  541  
  542                  memcpy( &tri->v[0], &verts[0], sizeof( poly_vertex ) );
  543                  memcpy( &tri->v[1], &verts[i-1], sizeof( poly_vertex ) );
  544                  memcpy( &tri->v[2], &verts[i], sizeof( poly_vertex ) );
  545  
  546                  /* add to our sorted list */
  547                  tri->next = NULL;
  548  
  549                  if ( ztri == NULL )
  550                  {
  551                      raster->tri_sorted_list[object.z] = tri;
  552                  }
  553                  else
  554                  {
  555                      ztri->next = tri;
  556                  }
  557  
  558                  ztri = tri;
  559              }
  560  
  561              /* keep around the min and max z values for this frame */
  562              if ( object.z < raster->min_z ) raster->min_z = object.z;
  563              if ( object.z > raster->max_z ) raster->max_z = object.z;
  564          }
  565      }
  566  
  567      /* update linking */
  568      switch( ((attr >> 8) & 3) )
  569      {
  570          case 0:
  571          case 2:
  572          {
  573              /* reuse P0(n) and P1(n) */
  574              for( i = 0; i < 6; i++ )                                        /* P0(n) -> P0(n-1) */
  575                  raster->command_buffer[2+i] = raster->command_buffer[11+i]; /* P1(n) -> P1(n-1) */
  576          }
  577          break;
  578  
  579          case 1:
  580          {
  581              /* reuse P0(n-1) and P0(n) */
  582              for( i = 0; i < 3; i++ )
  583                  raster->command_buffer[5+i] = raster->command_buffer[11+i]; /* P0(n) -> P1(n-1) */
  584          }
  585          break;
  586  
  587          case 3:
  588          {
  589              /* reuse P1(n-1) and P1(n) */
  590              for( i = 0; i < 3; i++ )
  591                  raster->command_buffer[2+i] = raster->command_buffer[14+i]; /* P1(n) -> P1(n-1) */
  592          }
  593          break;
  594      }
  595  }
  596  
  597  static void model2_3d_process_triangle( raster_state *raster, UINT32 attr )
  598  {
  599      triangle    object;
  600      UINT16      *th, *tp;
  601      INT32       tho;
  602      UINT32      cull, i;
  603      float       zvalue;
  604      float       min_z, max_z;
  605  
  606      /* extract P0(n-1) */
  607      object.v[1].x = u2f( raster->command_buffer[2] << 8 );
  608      object.v[1].y = u2f( raster->command_buffer[3] << 8 );
  609      object.v[1].pz = u2f( raster->command_buffer[4] << 8 );
  610  
  611      /* extract P1(n-1) */
  612      object.v[0].x = u2f( raster->command_buffer[5] << 8 );
  613      object.v[0].y = u2f( raster->command_buffer[6] << 8 );
  614      object.v[0].pz = u2f( raster->command_buffer[7] << 8 );
  615  
  616      /* extract P0(n) */
  617      object.v[2].x = u2f( raster->command_buffer[11] << 8 );
  618      object.v[2].y = u2f( raster->command_buffer[12] << 8 );
  619      object.v[2].pz = u2f( raster->command_buffer[13] << 8 );
  620  
  621      /* for triangles, the rope of P1(n) is achieved by P0(n-1) (linktype 3) */
  622      raster->command_buffer[14] = raster->command_buffer[11];
  623      raster->command_buffer[15] = raster->command_buffer[12];
  624      raster->command_buffer[16] = raster->command_buffer[13];
  625  
  626      /* always calculate the min z and max z values */
  627      min_z = object.v[0].pz;
  628      if ( object.v[1].pz < min_z ) min_z = object.v[1].pz;
  629      if ( object.v[2].pz < min_z ) min_z = object.v[2].pz;
  630  
  631      max_z = object.v[0].pz;
  632      if ( object.v[1].pz > max_z ) max_z = object.v[1].pz;
  633      if ( object.v[2].pz > max_z ) max_z = object.v[2].pz;
  634  
  635      /* read in the texture information */
  636  
  637      /* texture point data */
  638      if ( raster->command_buffer[0] & 0x800000 )
  639          tp = &raster->texture_ram[raster->command_buffer[0] & 0xFFFF];
  640      else
  641          tp = &raster->texture_rom[raster->command_buffer[0] & 0x7FFFFF];
  642  
  643      object.v[0].pv = *tp++;
  644      object.v[0].pu = *tp++;
  645      object.v[1].pv = *tp++;
  646      object.v[1].pu = *tp++;
  647      object.v[2].pv = *tp++;
  648      object.v[2].pu = *tp++;
  649  
  650      /* update the address */
  651      raster->command_buffer[0] += 6;
  652  
  653      /* texture header data */
  654      if ( raster->command_buffer[1] & 0x800000 )
  655          th = &raster->texture_ram[raster->command_buffer[1] & 0xFFFF];
  656      else
  657          th = &raster->texture_rom[raster->command_buffer[1] & 0x7FFFFF];
  658  
  659      object.texheader[0] = *th++;
  660      object.texheader[1] = *th++;
  661      object.texheader[2] = *th++;
  662      object.texheader[3] = *th++;
  663  
  664      /* extract the texture header offset */
  665      tho = (attr >> 12) & 0x1F;
  666  
  667      /* adjust for sign */
  668      if ( tho & 0x10 )
  669          tho |= -16;
  670  
  671      /* update the address */
  672      raster->command_buffer[1] += tho * 4;
  673  
  674      /* set the luma value of this quad */
  675      object.luma = (raster->command_buffer[9] >> 15) & 0xFF;
  676  
  677      /* determine whether we can cull this quad */
  678      cull = 0;
  679  
  680      /* if doubleside is disabled */
  681      if ( ((attr >> 17) & 1) == 0 )
  682      {
  683          /* if it's the backface, cull it */
  684          if ( raster->command_buffer[9] & 0x00800000 )
  685              cull = 1;
  686      }
  687  
  688      /* if the linktype is 0, then we can also cull it */
  689      if ( ((attr >> 8) & 3) == 0 )
  690          cull = 1;
  691  
  692      /* if the minimum z value is bigger than the master z clip value, don't render */
  693      if ( (INT32)(1.0/min_z) > raster->master_z_clip )
  694          cull = 1;
  695  
  696      /* if the maximum z value is < 0 then we can safely clip the entire polygon */
  697      if ( max_z < 0 )
  698          cull = 1;
  699  
  700      /* set the object's z value */
  701      zvalue = raster->triangle_z;
  702  
  703      /* see if we need to recompute min/max z */
  704      if ( (attr >> 10) & 3 )
  705      {
  706          if ( (attr >> 10) & 1 ) /* min value */
  707          {
  708              zvalue = min_z;
  709          }
  710          else if ( (attr >> 10) & 2 ) /* max value */
  711          {
  712              zvalue = max_z;
  713          }
  714  
  715          raster->triangle_z = zvalue;
  716      }
  717  
  718      /* if we're not culling, do z-clip and add to out triangle list */
  719      if ( cull == 0 )
  720      {
  721          INT32       clipped_verts;
  722          poly_vertex verts[10];
  723          plane       clip_plane;
  724  
  725          clip_plane.normal.x = 0;
  726          clip_plane.normal.y = 0;
  727          clip_plane.normal.pz = 1;
  728          clip_plane.distance = 0;
  729  
  730          /* do near z clipping */
  731          clipped_verts = clip_polygon( object.v, 3, &clip_plane, verts);
  732  
  733          if ( clipped_verts > 2 )
  734          {
  735              triangle *ztri;
  736  
  737              /* adjust and set the object z-sort value */
  738              object.z = float_to_zval( zvalue + raster->z_adjust );
  739  
  740              /* get our list read to add the triangles */
  741              ztri = raster->tri_sorted_list[object.z];
  742  
  743              if ( ztri != NULL )
  744              {
  745                  while( ztri->next != NULL )
  746                      ztri = (triangle *)ztri->next;
  747              }
  748  
  749              /* go through the clipped vertex list, adding triangles */
  750              for( i = 2; i < clipped_verts; i++ )
  751              {
  752                  triangle    *tri;
  753  
  754                  tri = &raster->tri_list[raster->tri_list_index++];
  755  
  756                  if ( raster->tri_list_index >= MAX_TRIANGLES )
  757                  {
  758                      fatalerror( "SEGA 3D: Max triangle limit exceeded\n" );
  759                  }
  760  
  761                  /* copy the object information */
  762                  tri->z = object.z;
  763                  tri->texheader[0] = object.texheader[0];
  764                  tri->texheader[1] = object.texheader[1];
  765                  tri->texheader[2] = object.texheader[2];
  766                  tri->texheader[3] = object.texheader[3];
  767                  tri->luma = object.luma;
  768  
  769                  /* set the viewport */
  770                  tri->viewport[0] = raster->viewport[0];
  771                  tri->viewport[1] = raster->viewport[1];
  772                  tri->viewport[2] = raster->viewport[2];
  773                  tri->viewport[3] = raster->viewport[3];
  774  
  775                  /* set the center */
  776                  tri->center[0] = raster->center[raster->center_sel][0];
  777                  tri->center[1] = raster->center[raster->center_sel][1];
  778  
  779                  memcpy( &tri->v[0], &verts[0], sizeof( poly_vertex ) );
  780                  memcpy( &tri->v[1], &verts[i-1], sizeof( poly_vertex ) );
  781                  memcpy( &tri->v[2], &verts[i], sizeof( poly_vertex ) );
  782  
  783                  /* add to our sorted list */
  784                  tri->next = NULL;
  785  
  786                  if ( ztri == NULL )
  787                  {
  788                      raster->tri_sorted_list[object.z] = tri;
  789                  }
  790                  else
  791                  {
  792                      ztri->next = tri;
  793                  }
  794  
  795                  ztri = tri;
  796              }
  797  
  798              /* keep around the min and max z values for this frame */
  799              if ( object.z < raster->min_z ) raster->min_z = object.z;
  800              if ( object.z > raster->max_z ) raster->max_z = object.z;
  801          }
  802      }
  803  
  804      /* update linking */
  805      switch( ((attr >> 8) & 3) )
  806      {
  807          case 0:
  808          case 2:
  809          {
  810              /* reuse P0(n) and P1(n) */
  811              for( i = 0; i < 6; i++ )                                        /* P0(n) -> P0(n-1) */
  812                  raster->command_buffer[2+i] = raster->command_buffer[11+i]; /* P1(n) -> P1(n-1) */
  813          }
  814          break;
  815  
  816          case 1:
  817          {
  818              /* reuse P0(n-1) and P0(n) */
  819              for( i = 0; i < 3; i++ )
  820                  raster->command_buffer[5+i] = raster->command_buffer[11+i]; /* P0(n) -> P1(n-1) */
  821          }
  822          break;
  823  
  824          case 3:
  825          {
  826              /* reuse P1(n-1) and P1(n) */
  827              for( i = 0; i < 3; i++ )
  828                  raster->command_buffer[2+i] = raster->command_buffer[14+i]; /* P1(n) -> P1(n-1) */
  829          }
  830          break;
  831      }
  832  }
  833  
  834  /***********************************************************************************************/
  835  
  836  INLINE UINT16 get_texel( UINT32 base_x, UINT32 base_y, int x, int y, UINT32 *sheet )
  837  {
  838      UINT32  baseoffs = ((base_y/2)*512)+(base_x/2);
  839      UINT32  texeloffs = ((y/2)*512)+(x/2);
  840      UINT32  offset = baseoffs + texeloffs;
  841      UINT32  texel = sheet[offset>>1];
  842  
  843      if ( offset & 1 )
  844          texel >>= 16;
  845  
  846      if ( (y & 1) == 0 )
  847          texel >>= 8;
  848  
  849      if ( (x & 1) == 0 )
  850          texel >>= 4;
  851  
  852      return (texel & 0x0f);
  853  }
  854  
  855  /* checker = 0, textured = 0, transparent = 0 */
  856  #define MODEL2_FUNC 0
  857  #define MODEL2_FUNC_NAME    model2_3d_render_0
  858  #include "model2rd.c"
  859  #undef MODEL2_FUNC
  860  #undef MODEL2_FUNC_NAME
  861  
  862  /* checker = 0, textured = 0, translucent = 1 */
  863  #define MODEL2_FUNC 1
  864  #define MODEL2_FUNC_NAME    model2_3d_render_1
  865  #include "model2rd.c"
  866  #undef MODEL2_FUNC
  867  #undef MODEL2_FUNC_NAME
  868  
  869  /* checker = 0, textured = 1, translucent = 0 */
  870  #define MODEL2_FUNC 2
  871  #define MODEL2_FUNC_NAME    model2_3d_render_2
  872  #include "model2rd.c"
  873  #undef MODEL2_FUNC
  874  #undef MODEL2_FUNC_NAME
  875  
  876  /* checker = 0, textured = 1, translucent = 1 */
  877  #define MODEL2_FUNC 3
  878  #define MODEL2_FUNC_NAME    model2_3d_render_3
  879  #include "model2rd.c"
  880  #undef MODEL2_FUNC
  881  #undef MODEL2_FUNC_NAME
  882  
  883  /* checker = 1, textured = 0, translucent = 0 */
  884  #define MODEL2_FUNC 4
  885  #define MODEL2_FUNC_NAME    model2_3d_render_4
  886  #include "model2rd.c"
  887  #undef MODEL2_FUNC
  888  #undef MODEL2_FUNC_NAME
  889  
  890  /* checker = 1, textured = 0, translucent = 1 */
  891  #define MODEL2_FUNC 5
  892  #define MODEL2_FUNC_NAME    model2_3d_render_5
  893  #include "model2rd.c"
  894  #undef MODEL2_FUNC
  895  #undef MODEL2_FUNC_NAME
  896  
  897  /* checker = 1, textured = 1, translucent = 0 */
  898  #define MODEL2_FUNC 6
  899  #define MODEL2_FUNC_NAME    model2_3d_render_6
  900  #include "model2rd.c"
  901  #undef MODEL2_FUNC
  902  #undef MODEL2_FUNC_NAME
  903  
  904  /* checker = 1, textured = 1, translucent = 1 */
  905  #define MODEL2_FUNC 7
  906  #define MODEL2_FUNC_NAME    model2_3d_render_7
  907  #include "model2rd.c"
  908  #undef MODEL2_FUNC
  909  #undef MODEL2_FUNC_NAME
  910  
  911  /***********************************************************************************************/
  912  
  913  static const poly_draw_scanline_func render_funcs[8] =
  914  {
  915      model2_3d_render_0, /* checker = 0, textured = 0, translucent = 0 */
  916      model2_3d_render_1, /* checker = 0, textured = 0, translucent = 1 */
  917      model2_3d_render_2, /* checker = 0, textured = 1, translucent = 0 */
  918      model2_3d_render_3, /* checker = 0, textured = 1, translucent = 1 */
  919      model2_3d_render_4, /* checker = 1, textured = 0, translucent = 0 */
  920      model2_3d_render_5, /* checker = 1, textured = 0, translucent = 1 */
  921      model2_3d_render_6, /* checker = 1, textured = 1, translucent = 0 */
  922      model2_3d_render_7  /* checker = 1, textured = 1, translucent = 1 */
  923  };
  924  
  925  static void model2_3d_render( model2_state *state, bitmap_rgb32 &bitmap, triangle *tri, const rectangle &cliprect )
  926  {
  927      poly_manager *poly = state->m_poly;
  928      poly_extra_data *extra = (poly_extra_data *)poly_get_extra_data(poly);
  929      UINT8       renderer;
  930  
  931      /* select renderer based on attributes (bit15 = checker, bit14 = textured, bit13 = transparent */
  932      renderer = (tri->texheader[0] >> 13) & 7;
  933  
  934      /* calculate and clip to viewport */
  935      rectangle vp(tri->viewport[0] - 8, tri->viewport[2] - 8, (384-tri->viewport[3])+90, (384-tri->viewport[1])+90);
  936      vp &= cliprect;
  937  
  938      extra->state = state;
  939      extra->lumabase = ((tri->texheader[1] & 0xFF) << 7) + ((tri->luma >> 5) ^ 0x7);
  940      extra->colorbase = (tri->texheader[3] >> 6) & 0x3FF;
  941  
  942      if (renderer & 2)
  943      {
  944          extra->texwidth = 32 << ((tri->texheader[0] >> 0) & 0x7);
  945          extra->texheight = 32 << ((tri->texheader[0] >> 3) & 0x7);
  946          extra->texx = 32 * ((tri->texheader[2] >> 0) & 0x1f);
  947          extra->texy = 32 * (((tri->texheader[2] >> 6) & 0x1f) + ( tri->texheader[2] & 0x20 ));
  948          extra->texmirrorx = (tri->texheader[0] >> 9) & 1;
  949          extra->texmirrory = (tri->texheader[0] >> 8) & 1;
  950          extra->texsheet = (tri->texheader[2] & 0x1000) ? state->m_textureram1 : state->m_textureram0;
  951  
  952          tri->v[0].pz = 1.0f / (1.0f + tri->v[0].pz);
  953          tri->v[0].pu = tri->v[0].pu * tri->v[0].pz * (1.0f / 8.0f);
  954          tri->v[0].pv = tri->v[0].pv * tri->v[0].pz * (1.0f / 8.0f);
  955          tri->v[1].pz = 1.0f / (1.0f + tri->v[1].pz);
  956          tri->v[1].pu = tri->v[1].pu * tri->v[1].pz * (1.0f / 8.0f);
  957          tri->v[1].pv = tri->v[1].pv * tri->v[1].pz * (1.0f / 8.0f);
  958          tri->v[2].pz = 1.0f / (1.0f + tri->v[2].pz);
  959          tri->v[2].pu = tri->v[2].pu * tri->v[2].pz * (1.0f / 8.0f);
  960          tri->v[2].pv = tri->v[2].pv * tri->v[2].pz * (1.0f / 8.0f);
  961  
  962          poly_render_triangle(poly, &bitmap, vp, render_funcs[renderer], 3, &tri->v[0], &tri->v[1], &tri->v[2]);
  963      }
  964      else
  965          poly_render_triangle(poly, &bitmap, vp, render_funcs[renderer], 0, &tri->v[0], &tri->v[1], &tri->v[2]);
  966  }
  967  
  968  /*
  969      Projection:
  970  
  971      According to the 2B Manual the screen coordinates are:
  972  
  973      (8,474)                         (504,474)
  974         +--------------------------------+
  975         |                                |
  976         |                                |
  977         |                                |
  978         |                                |
  979         |                                |
  980         |                                |
  981         |                                |
  982         |                                |
  983         +--------------------------------+
  984      (8,90)                          (504,90)
  985  */
  986  
  987  /* 3D Rasterizer projection: projects a triangle into screen coordinates */
  988  static void model2_3d_project( triangle *tri )
  989  {
  990      UINT16  i;
  991  
  992      for( i = 0; i < 3; i++ )
  993      {
  994          /* project the vertices */
  995          tri->v[i].x = -8 + tri->center[0] + (tri->v[i].x / (1.0f+tri->v[i].pz));
  996          tri->v[i].y = ((384 - tri->center[1])+90) - (tri->v[i].y / (1.0f+tri->v[i].pz));
  997      }
  998  }
  999  
 1000  /* 3D Rasterizer frame start: Resets frame variables */
 1001  static void model2_3d_frame_start( model2_state *state )
 1002  {
 1003      raster_state *raster = state->m_raster;
 1004  
 1005      /* reset the triangle list index */
 1006      raster->tri_list_index = 0;
 1007  
 1008      /* reset the sorted z list */
 1009      memset( raster->tri_sorted_list, 0, 0x10000 * sizeof( triangle * ) );
 1010  
 1011      /* reset the min-max sortable Z values */
 1012      raster->min_z = 0xFFFF;
 1013      raster->max_z = 0;
 1014  }
 1015  
 1016  static void model2_3d_frame_end( model2_state *state, bitmap_rgb32 &bitmap, const rectangle &cliprect )
 1017  {
 1018      raster_state *raster = state->m_raster;
 1019      INT32       z;
 1020  
 1021      /* if we have nothing to render, bail */
 1022      if ( raster->tri_list_index == 0 )
 1023          return;
 1024  
 1025  #if DEBUG
 1026      if (machine.input().code_pressed(KEYCODE_Q))
 1027      {
 1028          UINT32  i;
 1029  
 1030          FILE *f = fopen( "triangles.txt", "w" );
 1031  
 1032          if ( f )
 1033          {
 1034              for( i = 0; i < raster->tri_list_index; i++ )
 1035              {
 1036  
 1037                  fprintf( f, "index: %d\n", i );
 1038                  fprintf( f, "v0.x = %f, v0.y = %f, v0.z = %f\n", raster->tri_list[i].v[0].x, raster->tri_list[i].v[0].y, raster->tri_list[i].v[0].pz );
 1039                  fprintf( f, "v1.x = %f, v1.y = %f, v1.z = %f\n", raster->tri_list[i].v[1].x, raster->tri_list[i].v[1].y, raster->tri_list[i].v[1].pz );
 1040                  fprintf( f, "v2.x = %f, v2.y = %f, v2.z = %f\n", raster->tri_list[i].v[2].x, raster->tri_list[i].v[2].y, raster->tri_list[i].v[2].pz );
 1041  
 1042                  fprintf( f, "tri z: %04x\n", raster->tri_list[i].pz );
 1043                  fprintf( f, "texheader - 0: %04x\n", raster->tri_list[i].texheader[0] );
 1044                  fprintf( f, "texheader - 1: %04x\n", raster->tri_list[i].texheader[1] );
 1045                  fprintf( f, "texheader - 2: %04x\n", raster->tri_list[i].texheader[2] );
 1046                  fprintf( f, "texheader - 3: %04x\n", raster->tri_list[i].texheader[3] );
 1047                  fprintf( f, "luma: %02x\n", raster->tri_list[i].luma );
 1048                  fprintf( f, "vp.sx: %04x\n", raster->tri_list[i].viewport[0] );
 1049                  fprintf( f, "vp.sy: %04x\n", raster->tri_list[i].viewport[1] );
 1050                  fprintf( f, "vp.ex: %04x\n", raster->tri_list[i].viewport[2] );
 1051                  fprintf( f, "vp.ey: %04x\n", raster->tri_list[i].viewport[3] );
 1052                  fprintf( f, "vp.swx: %04x\n", raster->tri_list[i].center[0] );
 1053                  fprintf( f, "vp.swy: %04x\n", raster->tri_list[i].center[1] );
 1054                  fprintf( f, "\n---\n\n" );
 1055              }
 1056  
 1057              fprintf( f, "min_z = %04x, max_z = %04x\n", raster->min_z, raster->max_z );
 1058  
 1059              fclose( f );
 1060          }
 1061      }
 1062  #endif
 1063  
 1064      /* go through the Z levels, and render each bucket */
 1065      for( z = raster->max_z; z >= raster->min_z; z-- )
 1066      {
 1067          /* see if we have items at this z level */
 1068          if ( raster->tri_sorted_list[z] != NULL )
 1069          {
 1070              /* get a pointer to the first triangle */
 1071              triangle *tri = raster->tri_sorted_list[z];
 1072  
 1073              /* and loop clipping and rendering each triangle */
 1074              while( tri != NULL )
 1075              {
 1076                  /* project and render */
 1077                  model2_3d_project( tri );
 1078                  model2_3d_render( state, bitmap, tri, cliprect );
 1079  
 1080                  tri = (triangle *)tri->next;
 1081              }
 1082          }
 1083      }
 1084      poly_wait(state->m_poly, "End of frame");
 1085  }
 1086  
 1087  /* 3D Rasterizer main data input port */
 1088  static void model2_3d_push( raster_state *raster, UINT32 input )
 1089  {
 1090      /* see if we have a command in progress */
 1091      if ( raster->cur_command != 0 )
 1092      {
 1093          raster->command_buffer[raster->command_index++] = input;
 1094  
 1095          switch( raster->cur_command )
 1096          {
 1097              case 0x00:  /* NOP */
 1098              break;
 1099  
 1100              case 0x01:  /* Polygon Data */
 1101              {
 1102                  UINT32  attr;
 1103  
 1104                  /* start by looking if we have the basic input data */
 1105                  if ( raster->command_index < 9 )
 1106                      return;
 1107  
 1108                  /* get the attributes */
 1109                  attr = raster->command_buffer[8];
 1110  
 1111                  /* see if we're done */
 1112                  if ( (attr & 3) == 0 )
 1113                  {
 1114                      raster->cur_command = 0;
 1115                      return;
 1116                  }
 1117  
 1118                  /* see if it's a quad or a triangle */
 1119                  if ( attr & 1 )
 1120                  {
 1121                      /* it's a quad, wait for the rest of the points */
 1122                      if ( raster->command_index < 17 )
 1123                          return;
 1124  
 1125                      /* we have a full quad info, fill up our quad structure */
 1126                      model2_3d_process_quad( raster, attr );
 1127  
 1128                      /* back up and wait for more data */
 1129                      raster->command_index = 8;
 1130                  }
 1131                  else
 1132                  {
 1133                      /* it's a triangle, wait for the rest of the point */
 1134                      if ( raster->command_index < 14 )
 1135                          return;
 1136  
 1137                      /* we have a full quad info, fill up our quad structure */
 1138                      model2_3d_process_triangle( raster, attr );
 1139  
 1140                      /* back up and wait for more data */
 1141                      raster->command_index = 8;
 1142                  }
 1143              }
 1144              break;
 1145  
 1146              case 0x03:  /* Window Data */
 1147              {
 1148                  UINT32  i;
 1149  
 1150                  /* make sure we have all the data */
 1151                  if ( raster->command_index < 6 )
 1152                      return;
 1153  
 1154                  /* coordinates are 12 bit signed */
 1155  
 1156                  /* extract the viewport start x */
 1157                  raster->viewport[0] = (raster->command_buffer[0] >> 12) & 0xFFF;
 1158  
 1159                  if ( raster->viewport[0] & 0x800 )
 1160                      raster->viewport[0] = -( 0x800 - (raster->viewport[0] & 0x7FF) );
 1161  
 1162                  /* extract the viewport start y */
 1163                  raster->viewport[1] = raster->command_buffer[0] & 0xFFF;
 1164  
 1165                  if ( raster->viewport[1] & 0x800 )
 1166                      raster->viewport[1] = -( 0x800 - (raster->viewport[1] & 0x7FF) );
 1167  
 1168                  /* extract the viewport end x */
 1169                  raster->viewport[2] = (raster->command_buffer[1] >> 12) & 0xFFF;
 1170  
 1171                  if ( raster->viewport[2] & 0x800 )
 1172                      raster->viewport[2] = -( 0x800 - (raster->viewport[2] & 0x7FF) );
 1173  
 1174                  /* extract the viewport end y */
 1175                  raster->viewport[3] = raster->command_buffer[1] & 0xFFF;
 1176  
 1177                  if ( raster->viewport[3] & 0x800 )
 1178                      raster->viewport[3] = -( 0x800 - (raster->viewport[3] & 0x7FF) );
 1179  
 1180                  /* extract the centers */
 1181                  for( i = 0; i < 4; i++ )
 1182                  {
 1183                      /* center x */
 1184                      raster->center[i][0] = (raster->command_buffer[2+i] >> 12) & 0xFFF;
 1185  
 1186                      if ( raster->center[i][0] & 0x800 )
 1187                          raster->center[i][0] = -( 0x800 - (raster->center[i][0] & 0x7FF) );
 1188  
 1189                      /* center y */
 1190                      raster->center[i][1] = raster->command_buffer[2+i] & 0xFFF;
 1191  
 1192                      if ( raster->center[i][1] & 0x800 )
 1193                          raster->center[i][1] = -( 0x800 - (raster->center[i][1] & 0x7FF) );
 1194                  }
 1195  
 1196                  /* done with this command */
 1197                  raster->cur_command = 0;
 1198              }
 1199              break;
 1200  
 1201              case 0x04:  /* Texture/Log Data write */
 1202              {
 1203                  /* make sure we have enough data */
 1204                  if ( raster->command_index < 2 )
 1205                      return;
 1206  
 1207                  /* see if the count is non-zero */
 1208                  if ( raster->command_buffer[1] > 0 )
 1209                  {
 1210                      /* see if we have data available */
 1211                      if ( raster->command_index >= 3 )
 1212                      {
 1213                          /* get the address */
 1214                          UINT32  address = raster->command_buffer[0];
 1215  
 1216                          /* do the write */
 1217                          if ( address & 0x800000 )
 1218                              raster->texture_ram[address&0xFFFF] = raster->command_buffer[2];
 1219                          else
 1220                              raster->log_ram[address&0xFFFF] = raster->command_buffer[2];
 1221  
 1222                          /* increment the address and decrease the count */
 1223                          raster->command_buffer[0]++;
 1224                          raster->command_buffer[1]--;
 1225  
 1226                          /* decrease the index, so we keep placing data in the same slot */
 1227                          raster->command_index--;
 1228                      }
 1229                  }
 1230  
 1231                  /* see if we're done with this command */
 1232                  if ( raster->command_buffer[1] == 0 )
 1233                      raster->cur_command = 0;
 1234              }
 1235              break;
 1236  
 1237              case 0x08:  /* ZSort mode */
 1238              {
 1239                  /* save the zsort mode value */
 1240                  raster->z_adjust = u2f( raster->command_buffer[0] << 8 );
 1241  
 1242                  /* done with this command */
 1243                  raster->cur_command = 0;
 1244              }
 1245              break;
 1246  
 1247              default:
 1248              {
 1249                  fatalerror( "SEGA 3D: Unknown rasterizer command %08x\n", raster->cur_command );
 1250              }
 1251              break;
 1252          }
 1253      }
 1254      else
 1255      {
 1256          /* new command */
 1257          raster->cur_command = input & 0x0F;
 1258          raster->command_index = 0;
 1259  
 1260          /* see if it's object data */
 1261          if ( raster->cur_command == 1 )
 1262          {
 1263              /* extract reverse bit */
 1264              raster->reverse = (input >> 4) & 1;
 1265  
 1266              /* extract center select */
 1267              raster->center_sel = ( input >> 6 ) & 3;
 1268  
 1269              /* reset the triangle z value */
 1270              raster->triangle_z = 0;
 1271          }
 1272      }
 1273  }
 1274  
 1275  /***********************************************************************************************/
 1276  
 1277  
 1278  
 1279  /*******************************************
 1280   *
 1281   *  Geometry Engine Internal State
 1282   *
 1283   *******************************************/
 1284  
 1285  struct geo_state
 1286  {
 1287      raster_state *          raster;
 1288      UINT32              mode;                   /* bit 0 = Enable Specular, bit 1 = Calculate Normals */
 1289      UINT32 *            polygon_rom;            /* Polygon ROM pointer */
 1290      float               matrix[12];             /* Current Transformation Matrix */
 1291      poly_vertex         focus;                  /* Focus (x,y) */
 1292      poly_vertex         light;                  /* Light Vector */
 1293      float               lod;                    /* LOD */
 1294      float               coef_table[32];         /* Distane Coefficient table */
 1295      texture_parameter   texture_parameters[32]; /* Texture parameters */
 1296      UINT32          polygon_ram0[0x8000];           /* Fast Polygon RAM pointer */
 1297      UINT32          polygon_ram1[0x8000];           /* Slow Polygon RAM pointer */
 1298  };
 1299  
 1300  
 1301  /*******************************************
 1302   *
 1303   *  Geometry Engine Initialization
 1304   *
 1305   *******************************************/
 1306  
 1307  static void geo_init( running_machine &machine, UINT32 *polygon_rom )
 1308  {
 1309      model2_state *state = machine.driver_data<model2_state>();
 1310      state->m_geo = auto_alloc_clear(machine, geo_state);
 1311  
 1312      state->m_geo->raster = state->m_raster;
 1313      state->m_geo->polygon_rom = polygon_rom;
 1314  }
 1315  
 1316  /*******************************************
 1317   *
 1318   *  Geometry Engine Polygon Parsers
 1319   *
 1320   *******************************************/
 1321  
 1322  /* Parse Polygons: Normals Present, No Specular case */
 1323  static void geo_parse_np_ns( geo_state *geo, UINT32 *input, UINT32 count )
 1324  {
 1325      raster_state *raster = geo->raster;
 1326      poly_vertex point, normal;
 1327      UINT32  attr, i;
 1328  
 1329      /* read the 1st point */
 1330      point.x = u2f( *input++ );
 1331      point.y = u2f( *input++ );
 1332      point.pz = u2f( *input++ );
 1333  
 1334      /* transform with the current matrix */
 1335      transform_point( &point, geo->matrix );
 1336  
 1337      /* apply focus */
 1338      point.x *= geo->focus.x;
 1339      point.y *= geo->focus.y;
 1340  
 1341      /* push it to the 3d rasterizer */
 1342      model2_3d_push( raster, f2u(point.x) >> 8 );
 1343      model2_3d_push( raster, f2u(point.y) >> 8 );
 1344      model2_3d_push( raster, f2u(point.pz) >> 8 );
 1345  
 1346      /* read the 2nd point */
 1347      point.x = u2f( *input++ );
 1348      point.y = u2f( *input++ );
 1349      point.pz = u2f( *input++ );
 1350  
 1351      /* transform with the current matrix */
 1352      transform_point( &point, geo->matrix );
 1353  
 1354      /* apply focus */
 1355      point.x *= geo->focus.x;
 1356      point.y *= geo->focus.y;
 1357  
 1358      /* push it to the 3d rasterizer */
 1359      model2_3d_push( raster, f2u(point.x) >> 8 );
 1360      model2_3d_push( raster, f2u(point.y) >> 8 );
 1361      model2_3d_push( raster, f2u(point.pz) >> 8 );
 1362  
 1363      /* loop through the following links */
 1364      for( i = 0; i < count; i++ )
 1365      {
 1366          /* read in the attributes */
 1367          attr = *input++;
 1368  
 1369          /* push to the 3d rasterizer */
 1370          model2_3d_push( raster, attr & 0x0003FFFF );
 1371  
 1372          /* read in the normal */
 1373          normal.x = u2f(*input++);
 1374          normal.y = u2f(*input++);
 1375          normal.pz = u2f(*input++);
 1376  
 1377          /* transform with the current matrix */
 1378          transform_vector( &normal, geo->matrix );
 1379  
 1380          if ( (attr & 3) != 0 ) /* quad or triangle */
 1381          {
 1382              float               dotl, dotp, luminance, distance;
 1383              float               coef, face;
 1384              INT32               luma;
 1385              texture_parameter * texparam;
 1386  
 1387              /* read in the next point */
 1388              point.x = u2f( *input++ );
 1389              point.y = u2f( *input++ );
 1390              point.pz = u2f( *input++ );
 1391  
 1392              /* transform with the current matrix */
 1393              transform_point( &point, geo->matrix );
 1394  
 1395              /* calculate the dot product of the normal and the light vector */
 1396              dotl = dot_product( &normal, &geo->light );
 1397  
 1398              /* calculate the dot product of the normal and the point */
 1399              dotp = dot_product( &normal, &point );
 1400  
 1401              /* apply focus */
 1402              point.x *= geo->focus.x;
 1403              point.y *= geo->focus.y;
 1404  
 1405              /* determine whether this is the front or the back of the polygon */
 1406              face = 0x100; /* rear */
 1407              if ( dotp >= 0 ) face = 0; /* front */
 1408  
 1409              /* get the texture parameters */
 1410              texparam = &geo->texture_parameters[(attr>>18) & 0x1f];
 1411  
 1412              /* calculate luminance */
 1413              if ( (dotl * dotp) < 0 ) luminance = 0;
 1414              else luminance = fabs( dotl );
 1415  
 1416              luminance = (luminance * texparam->diffuse) + texparam->ambient;
 1417              luma = (INT32)luminance;
 1418  
 1419              if ( luma > 255 ) luma = 255;
 1420              if ( luma < 0 ) luma = 0;
 1421  
 1422              /* add the face bit to the luma */
 1423              luma += face;
 1424  
 1425              /* extract distance coefficient */
 1426              coef = geo->coef_table[attr>>27];
 1427  
 1428              /* calculate texture level of detail */
 1429              distance = coef * fabs( dotp ) * geo->lod;
 1430  
 1431              /* push to the 3d rasterizer */
 1432              model2_3d_push( raster, luma << 15 );
 1433              model2_3d_push( raster, f2u(distance) >> 8 );
 1434              model2_3d_push( raster, f2u(point.x) >> 8 );
 1435              model2_3d_push( raster, f2u(point.y) >> 8 );
 1436              model2_3d_push( raster, f2u(point.pz) >> 8 );
 1437  
 1438              /* if it's a quad, push one more point */
 1439              if ( attr & 1 )
 1440              {
 1441                  /* read in the next point */
 1442                  point.x = u2f( *input++ );
 1443                  point.y = u2f( *input++ );
 1444                  point.pz = u2f( *input++ );
 1445  
 1446                  /* transform with the current matrix */
 1447                  transform_point( &point, geo->matrix );
 1448  
 1449                  /* apply focus */
 1450                  point.x *= geo->focus.x;
 1451                  point.y *= geo->focus.y;
 1452  
 1453                  /* push to the 3d rasterizer */
 1454                  model2_3d_push( raster, f2u(point.x) >> 8 );
 1455                  model2_3d_push( raster, f2u(point.y) >> 8 );
 1456                  model2_3d_push( raster, f2u(point.pz) >> 8 );
 1457              }
 1458              else /* triangle */
 1459              {
 1460                  /* skip the next 3 points */
 1461                  input += 3;
 1462              }
 1463          }
 1464          else /* we're done */
 1465          {
 1466              break;
 1467          }
 1468      }
 1469  
 1470      /* notify the 3d rasterizer we're done */
 1471      model2_3d_push( raster, 0 );
 1472  }
 1473  
 1474  /* Parse Polygons: Normals Present, Specular case */
 1475  static void geo_parse_np_s( geo_state *geo, UINT32 *input, UINT32 count )
 1476  {
 1477      raster_state *raster = geo->raster;
 1478      poly_vertex point, normal;
 1479      UINT32  attr, i;
 1480  
 1481      /* read the 1st point */
 1482      point.x = u2f( *input++ );
 1483      point.y = u2f( *input++ );
 1484      point.pz = u2f( *input++ );
 1485  
 1486      /* transform with the current matrix */
 1487      transform_point( &point, geo->matrix );
 1488  
 1489      /* apply focus */
 1490      point.x *= geo->focus.x;
 1491      point.y *= geo->focus.y;
 1492  
 1493      /* push it to the 3d rasterizer */
 1494      model2_3d_push( raster, f2u(point.x) >> 8 );
 1495      model2_3d_push( raster, f2u(point.y) >> 8 );
 1496      model2_3d_push( raster, f2u(point.pz) >> 8 );
 1497  
 1498      /* read the 2nd point */
 1499      point.x = u2f( *input++ );
 1500      point.y = u2f( *input++ );
 1501      point.pz = u2f( *input++ );
 1502  
 1503      /* transform with the current matrix */
 1504      transform_point( &point, geo->matrix );
 1505  
 1506      /* apply focus */
 1507      point.x *= geo->focus.x;
 1508      point.y *= geo->focus.y;
 1509  
 1510      /* push it to the 3d rasterizer */
 1511      model2_3d_push( raster, f2u(point.x) >> 8 );
 1512      model2_3d_push( raster, f2u(point.y) >> 8 );
 1513      model2_3d_push( raster, f2u(point.pz) >> 8 );
 1514  
 1515      /* loop through the following links */
 1516      for( i = 0; i < count; i++ )
 1517      {
 1518          /* read in the attributes */
 1519          attr = *input++;
 1520  
 1521          /* push to the 3d rasterizer */
 1522          model2_3d_push( raster, attr & 0x0003FFFF );
 1523  
 1524          /* read in the normal */
 1525          normal.x = u2f(*input++);
 1526          normal.y = u2f(*input++);
 1527          normal.pz = u2f(*input++);
 1528  
 1529          /* transform with the current matrix */
 1530          transform_vector( &normal, geo->matrix );
 1531  
 1532          if ( (attr & 3) != 0 ) /* quad or triangle */
 1533          {
 1534              float               dotl, dotp, luminance, distance, specular;
 1535              float               coef, face;
 1536              INT32               luma;
 1537              texture_parameter * texparam;
 1538  
 1539              /* read in the next point */
 1540              point.x = u2f( *input++ );
 1541              point.y = u2f( *input++ );
 1542              point.pz = u2f( *input++ );
 1543  
 1544              /* transform with the current matrix */
 1545              transform_point( &point, geo->matrix );
 1546  
 1547              /* calculate the dot product of the normal and the light vector */
 1548              dotl = dot_product( &normal, &geo->light );
 1549  
 1550              /* calculate the dot product of the normal and the point */
 1551              dotp = dot_product( &normal, &point );
 1552  
 1553              /* apply focus */
 1554              point.x *= geo->focus.x;
 1555              point.y *= geo->focus.y;
 1556  
 1557              /* determine whether this is the front or the back of the polygon */
 1558              face = 0x100; /* rear */
 1559              if ( dotp >= 0 ) face = 0; /* front */
 1560  
 1561              /* get the texture parameters */
 1562              texparam = &geo->texture_parameters[(attr>>18) & 0x1f];
 1563  
 1564              /* calculate luminance and specular */
 1565              if ( (dotl * dotp) < 0 ) luminance = 0;
 1566              else luminance = fabs( dotl );
 1567  
 1568              specular = ((2*dotl) * normal.pz) - geo->light.pz;
 1569              if ( specular < 0 ) specular = 0;
 1570              if ( texparam->specular_control == 0 ) specular = 0;
 1571              if ( (texparam->specular_control >> 1) != 0 ) specular *= specular;
 1572              if ( (texparam->specular_control >> 2) != 0 ) specular *= specular;
 1573              if ( ((texparam->specular_control+1) >> 3) != 0 ) specular *= specular;
 1574  
 1575              specular *= texparam->specular_scale;
 1576  
 1577              luminance = (luminance * texparam->diffuse) + texparam->ambient + specular;
 1578              luma = (INT32)luminance;
 1579  
 1580              if ( luma > 255 ) luma = 255;
 1581              if ( luma < 0 ) luma = 0;
 1582  
 1583              /* add the face bit to the luma */
 1584              luma += face;
 1585  
 1586              /* extract distance coefficient */
 1587              coef = geo->coef_table[attr>>27];
 1588  
 1589              /* calculate texture level of detail */
 1590              distance = coef * fabs( dotp ) * geo->lod;
 1591  
 1592              /* push to the 3d rasterizer */
 1593              model2_3d_push( raster, luma << 15 );
 1594              model2_3d_push( raster, f2u(distance) >> 8 );
 1595              model2_3d_push( raster, f2u(point.x) >> 8 );
 1596              model2_3d_push( raster, f2u(point.y) >> 8 );
 1597              model2_3d_push( raster, f2u(point.pz) >> 8 );
 1598  
 1599              /* if it's a quad, push one more point */
 1600              if ( attr & 1 )
 1601              {
 1602                  /* read in the next point */
 1603                  point.x = u2f( *input++ );
 1604                  point.y = u2f( *input++ );
 1605                  point.pz = u2f( *input++ );
 1606  
 1607                  /* transform with the current matrix */
 1608                  transform_point( &point, geo->matrix );
 1609  
 1610                  /* apply focus */
 1611                  point.x *= geo->focus.x;
 1612                  point.y *= geo->focus.y;
 1613  
 1614                  /* push to the 3d rasterizer */
 1615                  model2_3d_push( raster, f2u(point.x) >> 8 );
 1616                  model2_3d_push( raster, f2u(point.y) >> 8 );
 1617                  model2_3d_push( raster, f2u(point.pz) >> 8 );
 1618              }
 1619              else /* triangle */
 1620              {
 1621                  /* skip the next 3 points */
 1622                  input += 3;
 1623              }
 1624          }
 1625          else /* we're done */
 1626          {
 1627              break;
 1628          }
 1629      }
 1630  
 1631      /* notify the 3d rasterizer we're done */
 1632      model2_3d_push( raster, 0 );
 1633  }
 1634  
 1635  /* Parse Polygons: No Normals, No Specular case */
 1636  static void geo_parse_nn_ns( geo_state *geo, UINT32 *input, UINT32 count )
 1637  {
 1638      raster_state *raster = geo->raster;
 1639      poly_vertex point, normal, p0, p1, p2, p3;
 1640      UINT32  attr, i;
 1641  
 1642      /* read the 1st point */
 1643      point.x = u2f( *input++ );
 1644      point.y = u2f( *input++ );
 1645      point.pz = u2f( *input++ );
 1646  
 1647      /* transform with the current matrix */
 1648      transform_point( &point, geo->matrix );
 1649  
 1650      /* save for normal calculation */
 1651      p0.x = point.x; p0.y = point.y; p0.pz = point.pz;
 1652  
 1653      /* apply focus */
 1654      point.x *= geo->focus.x;
 1655      point.y *= geo->focus.y;
 1656  
 1657      /* push it to the 3d rasterizer */
 1658      model2_3d_push( raster, f2u(point.x) >> 8 );
 1659      model2_3d_push( raster, f2u(point.y) >> 8 );
 1660      model2_3d_push( raster, f2u(point.pz) >> 8 );
 1661  
 1662      /* read the 2nd point */
 1663      point.x = u2f( *input++ );
 1664      point.y = u2f( *input++ );
 1665      point.pz = u2f( *input++ );
 1666  
 1667      /* transform with the current matrix */
 1668      transform_point( &point, geo->matrix );
 1669  
 1670      /* save for normal calculation */
 1671      p1.x = point.x; p1.y = point.y; p1.pz = point.pz;
 1672  
 1673      /* apply focus */
 1674      point.x *= geo->focus.x;
 1675      point.y *= geo->focus.y;
 1676  
 1677      /* push it to the 3d rasterizer */
 1678      model2_3d_push( raster, f2u(point.x) >> 8 );
 1679      model2_3d_push( raster, f2u(point.y) >> 8 );
 1680      model2_3d_push( raster, f2u(point.pz) >> 8 );
 1681  
 1682      /* skip 4 */
 1683      input += 4;
 1684  
 1685      /* loop through the following links */
 1686      for( i = 0; i < count; i++ )
 1687      {
 1688          /* read in the attributes */
 1689          attr = *input++;
 1690  
 1691          /* push to the 3d rasterizer */
 1692          model2_3d_push( raster, attr & 0x0003FFFF );
 1693  
 1694          if ( (attr & 3) != 0 ) /* quad or triangle */
 1695          {
 1696              float               dotl, dotp, luminance, distance;
 1697              float               coef, face;
 1698              INT32               luma;
 1699              texture_parameter * texparam;
 1700  
 1701              /* read in the next point */
 1702              point.x = u2f( *input++ );
 1703              point.y = u2f( *input++ );
 1704              point.pz = u2f( *input++ );
 1705  
 1706              /* transform with the current matrix */
 1707              transform_point( &point, geo->matrix );
 1708  
 1709              /* save for normal calculation */
 1710              p2.x = point.x; p2.y = point.y; p2.pz = point.pz;
 1711  
 1712              /* compute the normal */
 1713              vector_cross3( &normal, &p0, &p1, &p2 );
 1714  
 1715              /* normalize it */
 1716              normalize_vector( &normal );
 1717  
 1718              /* calculate the dot product of the normal and the light vector */
 1719              dotl = dot_product( &normal, &geo->light );
 1720  
 1721              /* calculate the dot product of the normal and the point */
 1722              dotp = dot_product( &normal, &point );
 1723  
 1724              /* apply focus */
 1725              point.x *= geo->focus.x;
 1726              point.y *= geo->focus.y;
 1727  
 1728              /* determine whether this is the front or the back of the polygon */
 1729              face = 0x100; /* rear */
 1730              if ( dotp >= 0 ) face = 0; /* front */
 1731  
 1732              /* get the texture parameters */
 1733              texparam = &geo->texture_parameters[(attr>>18) & 0x1f];
 1734  
 1735              /* calculate luminance */
 1736              if ( (dotl * dotp) < 0 ) luminance = 0;
 1737              else luminance = fabs( dotl );
 1738  
 1739              luminance = (luminance * texparam->diffuse) + texparam->ambient;
 1740              luma = (INT32)luminance;
 1741  
 1742              if ( luma > 255 ) luma = 255;
 1743              if ( luma < 0 ) luma = 0;
 1744  
 1745              /* add the face bit to the luma */
 1746              luma += face;
 1747  
 1748              /* extract distance coefficient */
 1749              coef = geo->coef_table[attr>>27];
 1750  
 1751              /* calculate texture level of detail */
 1752              distance = coef * fabs( dotp ) * geo->lod;
 1753  
 1754              /* push to the 3d rasterizer */
 1755              model2_3d_push( raster, luma << 15 );
 1756              model2_3d_push( raster, f2u(distance) >> 8 );
 1757              model2_3d_push( raster, f2u(point.x) >> 8 );
 1758              model2_3d_push( raster, f2u(point.y) >> 8 );
 1759              model2_3d_push( raster, f2u(point.pz) >> 8 );
 1760  
 1761              /* if it's a quad, push one more point */
 1762              if ( attr & 1 )
 1763              {
 1764                  /* read in the next point */
 1765                  point.x = u2f( *input++ );
 1766                  point.y = u2f( *input++ );
 1767                  point.pz = u2f( *input++ );
 1768  
 1769                  /* transform with the current matrix */
 1770                  transform_point( &point, geo->matrix );
 1771  
 1772                  /* save for normal calculation */
 1773                  p3.x = point.x; p3.y = point.y; p3.pz = point.pz;
 1774  
 1775                  /* apply focus */
 1776                  point.x *= geo->focus.x;
 1777                  point.y *= geo->focus.y;
 1778  
 1779                  /* push to the 3d rasterizer */
 1780                  model2_3d_push( raster, f2u(point.x) >> 8 );
 1781                  model2_3d_push( raster, f2u(point.y) >> 8 );
 1782                  model2_3d_push( raster, f2u(point.pz) >> 8 );
 1783              }
 1784              else
 1785              {
 1786                  /* skip the next 3 points */
 1787                  input += 3;
 1788  
 1789                  /* for triangles, the rope of P1(n) is achieved by P0(n-1) (linktype 3) */
 1790                  p3.x = p2.x; p3.y = p2.y; p3.pz = p2.pz;
 1791              }
 1792          }
 1793          else /* we're done */
 1794          {
 1795              break;
 1796          }
 1797  
 1798          /* link type */
 1799          switch( (attr>>8) & 3 )
 1800          {
 1801              case 0:
 1802              case 2:
 1803              {
 1804                  /* reuse P0(n) and P1(n) */
 1805                  p0.x = p2.x; p0.y = p2.y; p0.pz = p2.pz;
 1806                  p1.x = p3.x; p1.y = p3.y; p1.pz = p3.pz;
 1807              }
 1808              break;
 1809  
 1810              case 1:
 1811              {
 1812                  /* reuse P0(n-1) and P0(n) */
 1813                  p1.x = p2.x; p1.y = p2.y; p1.pz = p2.pz;
 1814              }
 1815              break;
 1816  
 1817              case 3:
 1818              {
 1819                  /* reuse P1(n-1) and P1(n) */
 1820                  p0.x = p3.x; p0.y = p3.y; p0.pz = p3.pz;
 1821              }
 1822              break;
 1823          }
 1824      }
 1825  
 1826      /* notify the 3d rasterizer we're done */
 1827      model2_3d_push( raster, 0 );
 1828  }
 1829  
 1830  /* Parse Polygons: No Normals, Specular case */
 1831  static void geo_parse_nn_s( geo_state *geo, UINT32 *input, UINT32 count )
 1832  {
 1833      raster_state *raster = geo->raster;
 1834      poly_vertex point, normal, p0, p1, p2, p3;
 1835      UINT32  attr, i;
 1836  
 1837      /* read the 1st point */
 1838      point.x = u2f( *input++ );
 1839      point.y = u2f( *input++ );
 1840      point.pz = u2f( *input++ );
 1841  
 1842      /* transform with the current matrix */
 1843      transform_point( &point, geo->matrix );
 1844  
 1845      /* save for normal calculation */
 1846      p0.x = point.x; p0.y = point.y; p0.pz = point.pz;
 1847  
 1848      /* apply focus */
 1849      point.x *= geo->focus.x;
 1850      point.y *= geo->focus.y;
 1851  
 1852      /* push it to the 3d rasterizer */
 1853      model2_3d_push( raster, f2u(point.x) >> 8 );
 1854      model2_3d_push( raster, f2u(point.y) >> 8 );
 1855      model2_3d_push( raster, f2u(point.pz) >> 8 );
 1856  
 1857      /* read the 2nd point */
 1858      point.x = u2f( *input++ );
 1859      point.y = u2f( *input++ );
 1860      point.pz = u2f( *input++ );
 1861  
 1862      /* transform with the current matrix */
 1863      transform_point( &point, geo->matrix );
 1864  
 1865      /* save for normal calculation */
 1866      p1.x = point.x; p1.y = point.y; p1.pz = point.pz;
 1867  
 1868      /* apply focus */
 1869      point.x *= geo->focus.x;
 1870      point.y *= geo->focus.y;
 1871  
 1872      /* push it to the 3d rasterizer */
 1873      model2_3d_push( raster, f2u(point.x) >> 8 );
 1874      model2_3d_push( raster, f2u(point.y) >> 8 );
 1875      model2_3d_push( raster, f2u(point.pz) >> 8 );
 1876  
 1877      /* skip 4 */
 1878      input += 4;
 1879  
 1880      /* loop through the following links */
 1881      for( i = 0; i < count; i++ )
 1882      {
 1883          /* read in the attributes */
 1884          attr = *input++;
 1885  
 1886          /* push to the 3d rasterizer */
 1887          model2_3d_push( raster, attr & 0x0003FFFF );
 1888  
 1889          if ( (attr & 3) != 0 ) /* quad or triangle */
 1890          {
 1891              float               dotl, dotp, luminance, distance, specular;
 1892              float               coef, face;
 1893              INT32               luma;
 1894              texture_parameter * texparam;
 1895  
 1896              /* read in the next point */
 1897              point.x = u2f( *input++ );
 1898              point.y = u2f( *input++ );
 1899              point.pz = u2f( *input++ );
 1900  
 1901              /* transform with the current matrix */
 1902              transform_point( &point, geo->matrix );
 1903  
 1904              /* save for normal calculation */
 1905              p2.x = point.x; p2.y = point.y; p2.pz = point.pz;
 1906  
 1907              /* compute the normal */
 1908              vector_cross3( &normal, &p0, &p1, &p2 );
 1909  
 1910              /* normalize it */
 1911              normalize_vector( &normal );
 1912  
 1913              /* calculate the dot product of the normal and the light vector */
 1914              dotl = dot_product( &normal, &geo->light );
 1915  
 1916              /* calculate the dot product of the normal and the point */
 1917              dotp = dot_product( &normal, &point );
 1918  
 1919              /* apply focus */
 1920              point.x *= geo->focus.x;
 1921              point.y *= geo->focus.y;
 1922  
 1923              /* determine whether this is the front or the back of the polygon */
 1924              face = 0x100; /* rear */
 1925              if ( dotp >= 0 ) face = 0; /* front */
 1926  
 1927              /* get the texture parameters */
 1928              texparam = &geo->texture_parameters[(attr>>18) & 0x1f];
 1929  
 1930              /* calculate luminance and specular */
 1931              if ( (dotl * dotp) < 0 ) luminance = 0;
 1932              else luminance = fabs( dotl );
 1933  
 1934              specular = ((2*dotl) * normal.pz) - geo->light.pz;
 1935              if ( specular < 0 ) specular = 0;
 1936              if ( texparam->specular_control == 0 ) specular = 0;
 1937              if ( (texparam->specular_control >> 1) != 0 ) specular *= specular;
 1938              if ( (texparam->specular_control >> 2) != 0 ) specular *= specular;
 1939              if ( ((texparam->specular_control+1) >> 3) != 0 ) specular *= specular;
 1940  
 1941              specular *= texparam->specular_scale;
 1942  
 1943              luminance = (luminance * texparam->diffuse) + texparam->ambient + specular;
 1944              luma = (INT32)luminance;
 1945  
 1946              if ( luma > 255 ) luma = 255;
 1947              if ( luma < 0 ) luma = 0;
 1948  
 1949              /* add the face bit to the luma */
 1950              luma += face;
 1951  
 1952              /* extract distance coefficient */
 1953              coef = geo->coef_table[attr>>27];
 1954  
 1955              /* calculate texture level of detail */
 1956              distance = coef * fabs( dotp ) * geo->lod;
 1957  
 1958              /* push to the 3d rasterizer */
 1959              model2_3d_push( raster, luma << 15 );
 1960              model2_3d_push( raster, f2u(distance) >> 8 );
 1961              model2_3d_push( raster, f2u(point.x) >> 8 );
 1962              model2_3d_push( raster, f2u(point.y) >> 8 );
 1963              model2_3d_push( raster, f2u(point.pz) >> 8 );
 1964  
 1965              /* if it's a quad, push one more point */
 1966              if ( attr & 1 )
 1967              {
 1968                  /* read in the next point */
 1969                  point.x = u2f( *input++ );
 1970                  point.y = u2f( *input++ );
 1971                  point.pz = u2f( *input++ );
 1972  
 1973                  /* transform with the current matrix */
 1974                  transform_point( &point, geo->matrix );
 1975  
 1976                  /* save for normal calculation */
 1977                  p3.x = point.x; p3.y = point.y; p3.pz = point.pz;
 1978  
 1979                  /* apply focus */
 1980                  point.x *= geo->focus.x;
 1981                  point.y *= geo->focus.y;
 1982  
 1983                  /* push to the 3d rasterizer */
 1984                  model2_3d_push( raster, f2u(point.x) >> 8 );
 1985                  model2_3d_push( raster, f2u(point.y) >> 8 );
 1986                  model2_3d_push( raster, f2u(point.pz) >> 8 );
 1987              }
 1988              else
 1989              {
 1990                  /* skip the next 3 points */
 1991                  input += 3;
 1992  
 1993                  /* for triangles, the rope of P1(n) is achieved by P0(n-1) (linktype 3) */
 1994                  p3.x = p2.x; p3.y = p2.y; p3.pz = p2.pz;
 1995              }
 1996          }
 1997          else /* we're done */
 1998          {
 1999              break;
 2000          }
 2001  
 2002          /* link type */
 2003          switch( (attr>>8) & 3 )
 2004          {
 2005              case 0:
 2006              case 2:
 2007              {
 2008                  /* reuse P0(n) and P1(n) */
 2009                  p0.x = p2.x; p0.y = p2.y; p0.pz = p2.pz;
 2010                  p1.x = p3.x; p1.y = p3.y; p1.pz = p3.pz;
 2011              }
 2012              break;
 2013  
 2014              case 1:
 2015              {
 2016                  /* reuse P0(n-1) and P0(n) */
 2017                  p1.x = p2.x; p1.y = p2.y; p1.pz = p2.pz;
 2018              }
 2019              break;
 2020  
 2021              case 3:
 2022              {
 2023                  /* reuse P1(n-1) and P1(n) */
 2024                  p0.x = p3.x; p0.y = p3.y; p0.pz = p3.pz;
 2025              }
 2026              break;
 2027          }
 2028      }
 2029  
 2030      /* notify the 3d rasterizer we're done */
 2031      model2_3d_push( raster, 0 );
 2032  }
 2033  
 2034  /*******************************************
 2035   *
 2036   *  Geometry Engine Commands
 2037   *
 2038   *******************************************/
 2039  
 2040  /* Command 00: NOP */
 2041  static UINT32 * geo_nop( geo_state *geo, UINT32 opcode, UINT32 *input )
 2042  {
 2043      raster_state *raster = geo->raster;
 2044  
 2045      /* push the opcode to the 3d rasterizer */
 2046      model2_3d_push( raster, opcode >> 23 );
 2047  
 2048      return input;
 2049  }
 2050  
 2051  /* Command 01: Object Data */
 2052  static UINT32 * geo_object_data( geo_state *geo, UINT32 opcode, UINT32 *input )
 2053  {
 2054      raster_state *raster = geo->raster;
 2055      UINT32  tpa = *input++;     /* Texture Point Address */
 2056      UINT32  tha = *input++;     /* Texture Header Address */
 2057      UINT32  oba = *input++;     /* Object Address */
 2058      UINT32  obc = *input++;     /* Object Count */
 2059  
 2060      UINT32 *obp;                /* Object Pointer */
 2061  
 2062      /* push the initial set of data to the 3d rasterizer */
 2063      model2_3d_push( raster, opcode >> 23 );
 2064      model2_3d_push( raster, tpa );
 2065      model2_3d_push( raster, tha );
 2066  
 2067      /* select where we're reading polygon information from */
 2068      if ( oba & 0x01000000 )
 2069      {
 2070          /* Fast polygon RAM */
 2071          obp = &geo->polygon_ram0[oba & 0x7FFF];
 2072      }
 2073      else if ( oba & 0x00800000 )
 2074      {
 2075          /* Polygon ROM */
 2076          obp = &geo->polygon_rom[oba & 0x7FFFFF];
 2077      }
 2078      else
 2079      {
 2080          /* Slow Polygon RAM */
 2081          obp = &geo->polygon_ram1[oba & 0x7FFF];
 2082      }
 2083  
 2084      switch( geo->mode & 3 )
 2085      {
 2086          /* Normals present, No Specular */
 2087          case 0: geo_parse_np_ns( geo, obp, obc ); break;
 2088  
 2089          /* Normals present, Specular */
 2090          case 1: geo_parse_np_s( geo, obp, obc ); break;
 2091  
 2092          /* No Normals present, No Specular */
 2093          case 2: geo_parse_nn_ns( geo, obp, obc ); break;
 2094  
 2095          /* No Normals present, Specular */
 2096          case 3: geo_parse_nn_s( geo, obp, obc ); break;
 2097      }
 2098  
 2099      /* move by 4 parameters */
 2100      return input;
 2101  }
 2102  
 2103  /* Command 02: Direct Data */
 2104  static UINT32 * geo_direct_data( geo_state *geo, UINT32 opcode, UINT32 *input )
 2105  {
 2106      raster_state *raster = geo->raster;
 2107      UINT32  tpa = *input++;     /* Texture Point Address */
 2108      UINT32  tha = *input++;     /* Texture Header Address */
 2109      UINT32  attr;
 2110  
 2111      /* push the initial set of data to the 3d rasterizer */
 2112      model2_3d_push( raster, (opcode >> 23) - 1 );
 2113      model2_3d_push( raster, tpa );
 2114      model2_3d_push( raster, tha );
 2115  
 2116      /* push the initial points */
 2117      model2_3d_push( raster, (*input++) >> 8 ); /* x */
 2118      model2_3d_push( raster, (*input++) >> 8 ); /* y */
 2119      model2_3d_push( raster, (*input++) >> 8 ); /* z */
 2120  
 2121      model2_3d_push( raster, (*input++) >> 8 ); /* x */
 2122      model2_3d_push( raster, (*input++) >> 8 ); /* y */
 2123      model2_3d_push( raster, (*input++) >> 8 ); /* z */
 2124  
 2125      do
 2126      {
 2127          /* read in the attributes */
 2128          attr = *input++;
 2129  
 2130          if ( (attr & 3) == 0 )
 2131              break;
 2132  
 2133          /* push attributes */
 2134          model2_3d_push( raster, attr & 0x00FFFFFF );
 2135  
 2136          /* push luma */
 2137          model2_3d_push( raster, (*input++) >> 8 );
 2138  
 2139          /* push distance */
 2140          model2_3d_push( raster, (*input++) >> 8 );
 2141  
 2142          /* push the next point */
 2143          model2_3d_push( raster, (*input++) >> 8 ); /* x */
 2144          model2_3d_push( raster, (*input++) >> 8 ); /* y */
 2145          model2_3d_push( raster, (*input++) >> 8 ); /* z */
 2146  
 2147          /* if it's a quad, output another point */
 2148          if ( attr & 1 )
 2149          {
 2150              model2_3d_push( raster, (*input++) >> 8 ); /* x */
 2151              model2_3d_push( raster, (*input++) >> 8 ); /* y */
 2152              model2_3d_push( raster, (*input++) >> 8 ); /* z */
 2153          }
 2154      } while( 1 );
 2155  
 2156      /* we're done */
 2157      model2_3d_push( raster, 0 );
 2158  
 2159      return input;
 2160  }
 2161  
 2162  /* Command 03: Window Data */
 2163  static UINT32 * geo_window_data( geo_state *geo, UINT32 opcode, UINT32 *input )
 2164  {
 2165      raster_state *raster = geo->raster;
 2166      UINT32  x, y, i;
 2167  
 2168      /* start by pushing the opcode */
 2169      model2_3d_push( raster, opcode >> 23 );
 2170  
 2171      /*
 2172          we're going to move 6 coordinates to the 3d rasterizer:
 2173          - starting coordinate
 2174          - completion coordinate
 2175          - vanishing point 0 (eye mode 0)
 2176          - vanishing point 1 (eye mode 1)
 2177          - vanishing point 2 (eye mode 2)
 2178          - vanishing point 3 (eye mode 3)
 2179      */
 2180  
 2181      for( i = 0; i < 6; i++ )
 2182      {
 2183          /* read in the coordinate */
 2184          y = *input++;
 2185  
 2186          /* convert to the 3d rasterizer format (00XXXYYY) */
 2187          x = ( y & 0x0FFF0000 ) >> 4 ;
 2188          y &= 0xFFF;
 2189  
 2190          /* push it */
 2191          model2_3d_push( raster, x | y );
 2192      }
 2193  
 2194      return input;
 2195  }
 2196  
 2197  /* Command 04: Texture Data Write */
 2198  static UINT32 * geo_texture_data( geo_state *geo, UINT32 opcode, UINT32 *input )
 2199  {
 2200      raster_state *raster = geo->raster;
 2201      UINT32  i, count;
 2202  
 2203      /* start by pushing the opcode */
 2204      model2_3d_push( raster, opcode >> 23 );
 2205  
 2206      /* push the starting address/dsp id */
 2207      model2_3d_push( raster, *input++ );
 2208  
 2209      /* get the count */
 2210      count = *input++;
 2211  
 2212      /* push the count */
 2213      model2_3d_push( raster, count );
 2214  
 2215      /* loop and send the data */
 2216      for( i = 0; i < count; i++ )
 2217          model2_3d_push( raster, *input++ );
 2218  
 2219      return input;
 2220  }
 2221  
 2222  /* Command 05: Polygon Data */
 2223  static UINT32 * geo_polygon_data( geo_state *geo, UINT32 opcode, UINT32 *input )
 2224  {
 2225      UINT32  address, count, i;
 2226      UINT32 *p;
 2227  
 2228      (void)opcode;
 2229  
 2230      /* read in the address */
 2231      address = *input++;
 2232  
 2233      /* prepare the pointer */
 2234      if ( address & 0x01000000 )
 2235      {
 2236          /* Fast polygon RAM */
 2237          p = &geo->polygon_ram0[address & 0x7FFF];
 2238      }
 2239      else
 2240      {
 2241          /* Slow Polygon RAM */
 2242          p = &geo->polygon_ram1[address & 0x7FFF];
 2243      }
 2244  
 2245      /* read the count */
 2246      count = *input++;
 2247  
 2248      /* move the data */
 2249      for( i = 0; i < count; i++ )
 2250          *p++ = *input++;
 2251  
 2252      return input;
 2253  }
 2254  
 2255  /* Command 06: Texture Parameters */
 2256  static UINT32 * geo_texture_parameters( geo_state *geo, UINT32 opcode, UINT32 *input )
 2257  {
 2258      UINT32  index, count, i, param;
 2259  
 2260      (void)opcode;
 2261  
 2262      /* read in the index */
 2263      index = *input++;
 2264  
 2265      /* read in the conut */
 2266      count = *input++;
 2267  
 2268      for( i = 0; i < count; i++ )
 2269      {
 2270          /* read in the texture parameters */
 2271          param = *input++;
 2272  
 2273          geo->texture_parameters[index].diffuse = (float)( param & 0xFF );
 2274          geo->texture_parameters[index].ambient = (float)( (param >> 8) & 0xFF );
 2275          geo->texture_parameters[index].specular_control = (param >> 24) & 0xFF;
 2276          geo->texture_parameters[index].specular_scale = (float)( (param >> 16) & 0xFF );
 2277  
 2278          /* read in the distance coefficient */
 2279          geo->coef_table[index] = u2f(*input++);
 2280  
 2281          index = (index + 1) & 0x1F;
 2282      }
 2283  
 2284      return input;
 2285  }
 2286  
 2287  /* Command 07: Geo Mode */
 2288  static UINT32 * geo_mode( geo_state *geo, UINT32 opcode, UINT32 *input )
 2289  {
 2290      (void)opcode;
 2291  
 2292      /* read in the mode */
 2293      geo->mode = *input++;
 2294  
 2295      return input;
 2296  }
 2297  
 2298  /* Command 08: ZSort Mode */
 2299  static UINT32 * geo_zsort_mode( geo_state *geo, UINT32 opcode, UINT32 *input )
 2300  {
 2301      raster_state *raster = geo->raster;
 2302  
 2303      /* push the opcode */
 2304      model2_3d_push( raster, opcode >> 23 );
 2305  
 2306      /* push the mode */
 2307      model2_3d_push( raster, (*input++) >> 8 );
 2308  
 2309      return input;
 2310  }
 2311  
 2312  /* Command 09: Focal Distance */
 2313  static UINT32 * geo_focal_distance( geo_state *geo, UINT32 opcode, UINT32 *input )
 2314  {
 2315      (void)opcode;
 2316  
 2317      /* read the x focus value */
 2318      geo->focus.x = u2f( *input++ );
 2319  
 2320      /* read the y focus value */
 2321      geo->focus.y = u2f( *input++ );
 2322  
 2323      return input;
 2324  }
 2325  
 2326  /* Command 0A: Light Source Vector Write */
 2327  static UINT32 * geo_light_source( geo_state *geo, UINT32 opcode, UINT32 *input )
 2328  {
 2329      (void)opcode;
 2330  
 2331      /* read the x light value */
 2332      geo->light.x = u2f( *input++ );
 2333  
 2334      /* read the y light value */
 2335      geo->light.y = u2f( *input++ );
 2336  
 2337      /* read the z light value */
 2338      geo->light.pz = u2f( *input++ );
 2339  
 2340      return input;
 2341  }
 2342  
 2343  /* Command 0B: Transformation Matrix Write */
 2344  static UINT32 * geo_matrix_write( geo_state *geo, UINT32 opcode, UINT32 *input )
 2345  {
 2346      UINT32  i;
 2347  
 2348      (void)opcode;
 2349  
 2350      /* read in the transformation matrix */
 2351      for( i = 0; i < 12; i++ )
 2352          geo->matrix[i] = u2f( *input++ );
 2353  
 2354      return input;
 2355  }
 2356  
 2357  /* Command 0C: Parallel Transfer Vector Write */
 2358  static UINT32 * geo_translate_write( geo_state *geo, UINT32 opcode, UINT32 *input )
 2359  {
 2360      UINT32  i;
 2361  
 2362      (void)opcode;
 2363  
 2364      /* read in the translation vector */
 2365      for( i = 0; i < 3; i++ )
 2366          geo->matrix[i+9] = u2f( *input++ );
 2367  
 2368      return input;
 2369  }
 2370  
 2371  /* Command 0D: Geo Data Memory Push (undocumented, unsupported) */
 2372  static UINT32 * geo_data_mem_push( geo_state *geo, UINT32 opcode, UINT32 *input )
 2373  {
 2374      UINT32  address, count, i;
 2375  
 2376      /*
 2377          This command pushes data stored in the Geometry DSP's RAM
 2378          to the hardware 3D rasterizer. Since we don't emulate the
 2379          DSP, we don't know what the RAM contents are.
 2380  
 2381          Eventually, we could check for the address, and if it
 2382          happens to point to a polygon ROM, we could potentially
 2383          emulate it partially.
 2384  
 2385          No games are known to use this command yet.
 2386      */
 2387  
 2388  
 2389      (void)opcode;
 2390  
 2391      /* read in the address */
 2392      address = *input++;
 2393  
 2394      /* read in the count */
 2395      count = *input++;
 2396  
 2397      logerror( "SEGA GEO: Executing unsupported geo_data_mem_push (address = %08x, count = %08x)\n", address, count );
 2398  
 2399      (void)i;
 2400  /*
 2401      for( i = 0; i < count; i++ )
 2402          model2_3d_push( 0 );
 2403  */
 2404  
 2405      return input;
 2406  }
 2407  
 2408  /* Command 0E: Geo Test */
 2409  static UINT32 * geo_test( geo_state *geo, UINT32 opcode, UINT32 *input )
 2410  {
 2411      UINT32      data, blocks, address, count, checksum, i;
 2412  
 2413      (void)opcode;
 2414  
 2415      /* fifo test */
 2416      data = 1;
 2417  
 2418      for( i = 0; i < 32; i++ )
 2419      {
 2420          if ( *input++ != data )
 2421          {
 2422              /* TODO: Set Red LED on */
 2423              logerror( "SEGA GEO: FIFO Test failed\n" );
 2424          }
 2425  
 2426          data <<= 1;
 2427      }
 2428  
 2429      /* get the number of checksums we have to run */
 2430      blocks = *input++;
 2431  
 2432      for( i = 0; i < blocks; i++ )
 2433      {
 2434          UINT32  sum_even, sum_odd, j;
 2435  
 2436          /* read in the address */
 2437          address = (*input++) & 0x7FFFFF;
 2438  
 2439          /* read in the count */
 2440          count = *input++;
 2441  
 2442          /* read in the checksum */
 2443          checksum = *input++;
 2444  
 2445          /* reset the checksum counters */
 2446          sum_even = 0;
 2447          sum_odd = 0;
 2448  
 2449          for( j = 0; j < count; j++ )
 2450          {
 2451              data = geo->polygon_rom[address++];
 2452  
 2453              address &= 0x7FFFFF;
 2454  
 2455              sum_even += data >> 16;
 2456              sum_even &= 0xFFFF;
 2457  
 2458              sum_odd += data & 0xFFFF;
 2459              sum_odd &= 0xFFFF;
 2460          }
 2461  
 2462          sum_even += checksum >> 16;
 2463          sum_even &= 0xFFFF;
 2464  
 2465          sum_odd += checksum & 0xFFFF;
 2466          sum_odd &= 0xFFFF;
 2467  
 2468          if ( sum_even != 0 || sum_odd != 0 )
 2469          {
 2470              /* TODO: Set Green LED on */
 2471              logerror( "SEGA GEO: Polygon ROM Test failed\n" );
 2472          }
 2473      }
 2474  
 2475      return input;
 2476  }
 2477  
 2478  /* Command 0F: End */
 2479  static UINT32 * geo_end( geo_state *geo, UINT32 opcode, UINT32 *input )
 2480  {
 2481      raster_state *raster = geo->raster;
 2482  
 2483      (void)opcode;
 2484  
 2485      /* signal the end of this data block the rasterizer */
 2486      model2_3d_push( raster, 0xFF000000 );
 2487  
 2488      /* signal end by returning NULL */
 2489      return NULL;
 2490  }
 2491  
 2492  /* Command 10: Dummy */
 2493  static UINT32 * geo_dummy( geo_state *geo, UINT32 opcode, UINT32 *input )
 2494  {
 2495  //  UINT32  data;
 2496      (void)opcode;
 2497  
 2498      /* do the dummy read cycle */
 2499  //  data = *input++;
 2500      input++;
 2501  
 2502      return input;
 2503  }
 2504  
 2505  /* Command 14: Log Data Write */
 2506  static UINT32 * geo_log_data( geo_state *geo, UINT32 opcode, UINT32 *input )
 2507  {
 2508      raster_state *raster = geo->raster;
 2509      UINT32  i, count;
 2510  
 2511      /* start by pushing the opcode */
 2512      model2_3d_push( raster, opcode >> 23 );
 2513  
 2514      /* push the starting address/dsp id */
 2515      model2_3d_push( raster, *input++ );
 2516  
 2517      /* get the count */
 2518      count = *input++;
 2519  
 2520      /* push the count */
 2521      model2_3d_push( raster, count << 2 );
 2522  
 2523      /* loop and send the data */
 2524      for( i = 0; i < count; i++ )
 2525      {
 2526          UINT32  data = *input++;
 2527  
 2528          model2_3d_push( raster, data & 0xff );
 2529          model2_3d_push( raster, (data >> 8) & 0xff );
 2530          model2_3d_push( raster, (data >> 16) & 0xff );
 2531          model2_3d_push( raster, (data >> 24) & 0xff );
 2532      }
 2533  
 2534      return input;
 2535  }
 2536  
 2537  /* Command 16: LOD */
 2538  static UINT32 * geo_lod( geo_state *geo, UINT32 opcode, UINT32 *input )
 2539  {
 2540      (void)opcode;
 2541  
 2542      /* read in the LOD */
 2543      geo->lod = u2f(*input++);
 2544  
 2545      return input;
 2546  }
 2547  
 2548  /* Command 1D: Code Upload  (undocumented, unsupported) */
 2549  static UINT32 * geo_code_upload( geo_state *geo, UINT32 opcode, UINT32 *input )
 2550  {
 2551      UINT32  count, i;
 2552  
 2553      /*
 2554          This command uploads code to program memory and
 2555          optionally runs it. Probably used for debugging.
 2556  
 2557          No games are known to use this command yet.
 2558      */
 2559  
 2560      logerror( "SEGA GEO: Uploading debug code (unimplemented)\n" );
 2561  
 2562      (void)opcode;
 2563  
 2564      /* read in the flags */
 2565  //  flags = *input++;
 2566      input++;
 2567  
 2568      /* read in the count */
 2569      count = *input++;
 2570  
 2571      for( i = 0; i < count; i++ )
 2572      {
 2573          UINT64  code;
 2574  
 2575          /* read the top part of the opcode */
 2576          code = *input++;
 2577  
 2578          code <<= 32;
 2579  
 2580          /* the bottom part comes in two pieces */
 2581          code |= *input++;
 2582          code |= (*input++) << 16;
 2583      }
 2584  
 2585      /*
 2586          Bit 10 of flags indicate whether to run iummediately after upload
 2587      */
 2588  
 2589  /*
 2590      if ( flags & 0x400 )
 2591          code_jump();
 2592  */
 2593  
 2594      return input;
 2595  }
 2596  
 2597  /* Command 1E: Code Jump (undocumented, unsupported) */
 2598  static UINT32 * geo_code_jump( geo_state *geo, UINT32 opcode, UINT32 *input )
 2599  {
 2600  //  UINT32  address;
 2601  
 2602      /*
 2603          This command jumps to a specified address in program
 2604          memory. Code can be uploaded with function 1D.
 2605          Probably used for debugging.
 2606  
 2607          No games are known to use this command yet.
 2608      */
 2609  
 2610      logerror( "SEGA GEO: Jumping to debug code (unimplemented)\n" );
 2611  
 2612      (void)opcode;
 2613  
 2614  //  address = *input++ & 0x3FF;
 2615      input++;
 2616  
 2617  /*
 2618      code_jump( address )
 2619  */
 2620      return input;
 2621  }
 2622  
 2623  static UINT32 * geo_process_command( geo_state *geo, UINT32 opcode, UINT32 *input )
 2624  {
 2625      switch( opcode >> 23 )
 2626      {
 2627          case 0x00: input = geo_nop( geo, opcode, input );               break;
 2628          case 0x01: input = geo_object_data( geo, opcode, input );       break;
 2629          case 0x02: input = geo_direct_data( geo, opcode, input );       break;
 2630          case 0x03: input = geo_window_data( geo, opcode, input );       break;
 2631          case 0x04: input = geo_texture_data( geo, opcode, input );      break;
 2632          case 0x05: input = geo_polygon_data( geo, opcode, input );      break;
 2633          case 0x06: input = geo_texture_parameters( geo, opcode, input );    break;
 2634          case 0x07: input = geo_mode( geo, opcode, input );              break;
 2635          case 0x08: input = geo_zsort_mode( geo, opcode, input );            break;
 2636          case 0x09: input = geo_focal_distance( geo, opcode, input );        break;
 2637          case 0x0A: input = geo_light_source( geo, opcode, input );      break;
 2638          case 0x0B: input = geo_matrix_write( geo, opcode, input );      break;
 2639          case 0x0C: input = geo_translate_write( geo, opcode, input );   break;
 2640          case 0x0D: input = geo_data_mem_push( geo, opcode, input );     break;
 2641          case 0x0E: input = geo_test( geo, opcode, input );              break;
 2642          case 0x0F: input = geo_end( geo, opcode, input );               break;
 2643          case 0x10: input = geo_dummy( geo, opcode, input );             break;
 2644          case 0x11: input = geo_object_data( geo, opcode, input );       break;
 2645          case 0x12: input = geo_direct_data( geo, opcode, input );       break;
 2646          case 0x13: input = geo_window_data( geo, opcode, input );       break;
 2647          case 0x14: input = geo_log_data( geo, opcode, input );          break;
 2648          case 0x15: input = geo_polygon_data( geo, opcode, input );      break;
 2649          case 0x16: input = geo_lod( geo, opcode, input );               break;
 2650          case 0x17: input = geo_mode( geo, opcode, input );              break;
 2651          case 0x18: input = geo_zsort_mode( geo, opcode, input );            break;
 2652          case 0x19: input = geo_focal_distance( geo, opcode, input );        break;
 2653          case 0x1A: input = geo_light_source( geo, opcode, input );      break;
 2654          case 0x1B: input = geo_matrix_write( geo, opcode, input );      break;
 2655          case 0x1C: input = geo_translate_write( geo, opcode, input );   break;
 2656          case 0x1D: input = geo_code_upload( geo, opcode, input );       break;
 2657          case 0x1E: input = geo_code_jump( geo, opcode, input );         break;
 2658          case 0x1F: input = geo_end( geo, opcode, input );               break;
 2659      }
 2660  
 2661      return input;
 2662  }
 2663  
 2664  static void geo_parse( model2_state *state )
 2665  {
 2666      UINT32  address = (state->m_geo_read_start_address/4);
 2667      UINT32 *input = &state->m_bufferram[address];
 2668      UINT32  opcode;
 2669  
 2670      while( input != NULL && (input - state->m_bufferram) < 0x20000  )
 2671      {
 2672          /* read in the opcode */
 2673          opcode = *input++;
 2674  
 2675          /* if it's a jump opcode, do the jump */
 2676          if ( opcode & 0x80000000 )
 2677          {
 2678              /* get the address */
 2679              address = (opcode & 0x7FFFF) / 4;
 2680  
 2681              /* update our pointer */
 2682              input = &state->m_bufferram[address];
 2683  
 2684              /* go again */
 2685              continue;
 2686          }
 2687  
 2688          /* process it */
 2689          input = geo_process_command( state->m_geo, opcode, input );
 2690      }
 2691  }
 2692  
 2693  /***********************************************************************************************/
 2694  
 2695  
 2696  static void model2_exit(running_machine &machine)
 2697  {
 2698      model2_state *state = machine.driver_data<model2_state>();
 2699      poly_free(state->m_poly);
 2700  }
 2701  
 2702  VIDEO_START_MEMBER(model2_state,model2)
 2703  {
 2704      const rectangle &visarea = machine().primary_screen->visible_area();
 2705      int width = visarea.width();
 2706      int height = visarea.height();
 2707  
 2708      m_sys24_bitmap.allocate(width, height+4);
 2709  
 2710      m_poly = poly_alloc(machine(), 4000, sizeof(poly_extra_data), 0);
 2711      machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(model2_exit), &machine()));
 2712  
 2713      /* initialize the hardware rasterizer */
 2714      model2_3d_init( machine(), (UINT16*)memregion("user3")->base() );
 2715  
 2716      /* initialize the geometry engine */
 2717      geo_init( machine(), (UINT32*)memregion("user2")->base() );
 2718  }
 2719  
 2720  UINT32 model2_state::screen_update_model2(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
 2721  {
 2722      logerror("--- frame ---\n");
 2723  
 2724      bitmap.fill(machine().pens[0], cliprect);
 2725      m_sys24_bitmap.fill(0, cliprect);
 2726  
 2727      segas24_tile *tile = machine().device<segas24_tile>("tile");
 2728      tile->draw(m_sys24_bitmap, cliprect, 7, 0, 0);
 2729      tile->draw(m_sys24_bitmap, cliprect, 6, 0, 0);
 2730      tile->draw(m_sys24_bitmap, cliprect, 5, 0, 0);
 2731      tile->draw(m_sys24_bitmap, cliprect, 4, 0, 0);
 2732  
 2733      copybitmap_trans(bitmap, m_sys24_bitmap, 0, 0, 0, 0, cliprect, 0);
 2734  
 2735      /* tell the rasterizer we're starting a frame */
 2736      model2_3d_frame_start(this);
 2737  
 2738      /* let the geometry engine do it's thing */
 2739      geo_parse(this);
 2740  
 2741      /* have the rasterizer output the frame */
 2742      model2_3d_frame_end( this, bitmap, cliprect );
 2743  
 2744      m_sys24_bitmap.fill(0, cliprect);
 2745      tile->draw(m_sys24_bitmap, cliprect, 3, 0, 0);
 2746      tile->draw(m_sys24_bitmap, cliprect, 2, 0, 0);
 2747      tile->draw(m_sys24_bitmap, cliprect, 1, 0, 0);
 2748      tile->draw(m_sys24_bitmap, cliprect, 0, 0, 0);
 2749  
 2750      copybitmap_trans(bitmap, m_sys24_bitmap, 0, 0, 0, 0, cliprect, 0);
 2751  
 2752      return 0;
 2753  }
 2754