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��