#define MODULE_ZBF

#include "graf.h"

extern FLOAT LGT_AmbientColor[];

extern FLOAT USR_VertexInfo[VERTEX_NCOMP];
extern int USR_BackFace;

FLOAT ZBF_Oversample_Polygon_X = 2.0;
FLOAT ZBF_Oversample_Polygon_Y = 1.0;
FLOAT ZBF_Oversample_Lines     = 1.5;

ZVALUE *ZBF_Z;
int *ZBF_T,ZBF_AllIn;

CVALUE *ZBF_R, *ZBF_G, *ZBF_B;

int ZBF_Pcount, ZBF_Tcount;
int ZBF_NX, ZBF_NY, ZBF_VX_L, ZBF_VX_H, ZBF_VY_L, ZBF_VY_H;

RGBA ZBF_ColorMap[4096];

void (*ZBF_user_pixel_function)( FLOAT *, int );
void (*ZBF_user_vertex_function)( FLOAT *, int );

void zbf_set_user_functions( void (*vertex)(), void (*pixel)() )
{
    ZBF_user_vertex_function = vertex;
    ZBF_user_pixel_function  = pixel;
}

int zbf_open( int NX, int NY )
{
    int i;

    ZBF_Z = (ZVALUE *)malloc( NX*NY*sizeof( ZVALUE ) );
    ZBF_T = (int *)malloc( NX*NY*sizeof(int) );

    ZBF_R = (CVALUE *)malloc( NX*NY*sizeof( CVALUE ) );
    ZBF_G = (CVALUE *)malloc( NX*NY*sizeof( CVALUE ) );
    ZBF_B = (CVALUE *)malloc( NX*NY*sizeof( CVALUE ) );

    if ( !(ZBF_Z && ZBF_T && ZBF_R && ZBF_G && ZBF_B) )
    {
        fprintf( stderr, "zbf_init: couldn't get enough memory.\n" );
        zbf_close( );
        return FALSE;
    }

    ZBF_NX = NX;
    ZBF_NY = NY;

    ZBF_VX_L = 0;
    ZBF_VX_H = NX-1;

    ZBF_VY_L = 0;
    ZBF_VY_H = NY-1;

    zbf_clear();
    zbf_zclear();

    trs_init_transformations( );

    return TRUE;
}

int zbf_resize( int NX,int NY )
{
    float Sx,Sy;

    Sx = ZBF_NX/(float)NX;
    Sy = ZBF_NY/(float)NY;

    ZBF_Z = (ZVALUE *)realloc( ZBF_Z, NX*NY*sizeof( ZVALUE ) );
    ZBF_T = (int *)realloc( ZBF_T, NX*NY*sizeof(int) );

    ZBF_R = (CVALUE *)realloc( ZBF_R, NX*NY*sizeof( CVALUE ) );
    ZBF_G = (CVALUE *)realloc( ZBF_G, NX*NY*sizeof( CVALUE ) );
    ZBF_B = (CVALUE *)realloc( ZBF_B, NX*NY*sizeof( CVALUE ) );

    if ( !(ZBF_Z && ZBF_T && ZBF_R && ZBF_G && ZBF_B) )
    {
        fprintf( stderr, "zbf_resize: couldn't get enough memory.\n" );
        zbf_close( );
        return FALSE;
    }

    ZBF_NX = NX;
    ZBF_NY = NY;

    ZBF_VX_L /= Sx;
    ZBF_VX_H /= Sx;

    ZBF_VY_L /= Sy;
    ZBF_VY_H /= Sy;

    usr_color(usr_pack3f(0.0,0.0,0.0));
    zbf_clear();
    zbf_zclear();

    return TRUE;
}

void zbf_close( )
{
    if ( ZBF_Z ) free( ZBF_Z );
    if ( ZBF_T ) free( ZBF_T );
    if ( ZBF_R ) free( ZBF_R );
    if ( ZBF_G ) free( ZBF_G );
    if ( ZBF_B ) free( ZBF_B );
}

void zbf_clear()
{
    CVALUE R, G, B;
    int I;

    if ( LMD_Lmodel == LMD_LMODEL_CMAP )
    {
        I = USR_VertexInfo[VERTEX_COLOR_I];
        R = ZBF_ColorMap[I].r;
        G = ZBF_ColorMap[I].g;
        B = ZBF_ColorMap[I].b;
    } else
    {
        R = USR_VertexInfo[VERTEX_COLOR_R];
        G = USR_VertexInfo[VERTEX_COLOR_G];
        B = USR_VertexInfo[VERTEX_COLOR_B];
    }

    memset( ZBF_R, R, ZBF_NX * ZBF_NY ); 
    memset( ZBF_G, G, ZBF_NX * ZBF_NY ); 
    memset( ZBF_B, B, ZBF_NX * ZBF_NY ); 
}

void zbf_zclear()
{
    int i;

    for( i=0; i<ZBF_NX*ZBF_NY; i++ )
    {
        ZBF_T[i] = 0;
        ZBF_Z[i] = 1.0e20;
    }
}

#define zbf_set_pixel( r, g, b, a ) \
    if ( a < 1.0 ) { \
        ZBF_R[offset] = ZBF_R[offset]*(1.0-a) + r*a; \
        ZBF_G[offset] = ZBF_G[offset]*(1.0-a) + g*a; \
        ZBF_B[offset] = ZBF_B[offset]*(1.0-a) + b*a; \
    } else {  \
        ZBF_R[offset] = r; \
        ZBF_G[offset] = g; \
        ZBF_B[offset] = b; \
        }

#define zbf_draw_pixel_cmap( offset, z, i )          \
    if ( z <= ZBF_Z[offset] )                        \
    {                                                \
        ZBF_Z[offset] = z;                           \
        cindex = i;                                  \
        r0 = ZBF_ColorMap[cindex].r;                 \
        g0 = ZBF_ColorMap[cindex].g;                 \
        b0 = ZBF_ColorMap[cindex].b;                 \
        a0 = ZBF_ColorMap[cindex].a;                 \
        zbf_set_pixel( r0, g0, b0, a0 )              \
    }

#define zbf_draw_pixel_rgba( offset, z, r, g, b, a ) \
    if ( z <= ZBF_Z[offset] )                        \
    {                                                \
        ZBF_Z[offset] = z;                           \
        zbf_set_pixel( r, g, b, a )                  \
    }

void zbf_update_pixel( int offset, FLOAT *P )
{
    FLOAT R[VERTEX_NCOMP];
    int i, cindex;

    for( i=0; i<VERTEX_NCOMP; i++ ) R[i] = P[i];

    txr_texture_lookup( R, FALSE );

    if ( ZBF_user_pixel_function )
    {
        (*ZBF_user_pixel_function)( R, FALSE );
    }

    if ( LMD_Lmodel == LMD_LMODEL_PHONG )
    {
        lmd_evaluate_lmodel( R );

        R[VERTEX_COLOR_R] *= 255;
        R[VERTEX_COLOR_G] *= 255;
        R[VERTEX_COLOR_B] *= 255;
    }

    if ( LMD_Lmodel == LMD_LMODEL_CMAP )
    {
        cindex = R[VERTEX_COLOR_I];

        R[VERTEX_COLOR_R] = ZBF_ColorMap[cindex].r;
        R[VERTEX_COLOR_G] = ZBF_ColorMap[cindex].g;
        R[VERTEX_COLOR_B] = ZBF_ColorMap[cindex].b;
        R[VERTEX_COLOR_A] = ZBF_ColorMap[cindex].a;
    }
    else if ( LMD_Lmodel != LMD_LMODEL_USER )
        R[VERTEX_COLOR_A] = R[VERTEX_MATERIAL_ALPHA];

    txr_texture_lookup( R, TRUE );
    atm_apply_atmosphere( R );

    if ( ZBF_user_pixel_function )
    {
        (*ZBF_user_pixel_function)( R, TRUE );
    }

    zbf_set_pixel( R[VERTEX_COLOR_R], R[VERTEX_COLOR_G],
                   R[VERTEX_COLOR_B], R[VERTEX_COLOR_A] );
}

void zbf_draw_polygon( int n, ZBF_VERTEX *polygon )
{
    static FLOAT triangle[3][VERTEX_NCOMP];
    FLOAT *vertex;

    int i, j, k;

    ZBF_Pcount++;

    for( k = 0; k < n; k++ )
    {
        polygon[k].OrigCoordX = polygon[k].CoordX;
        polygon[k].OrigCoordY = polygon[k].CoordY;
        polygon[k].OrigCoordZ = polygon[k].CoordZ;
    }

    trs_viewing_transform(n,polygon);
    trs_normal_transform(n,polygon);

    if ( USR_BackFace && lmd_backfaceing(n,polygon) ) return;

    if ( ZBF_user_vertex_function )
        for( k=0; k<n; k++ )
        {
            vertex = (FLOAT *)&polygon[k];
            (*ZBF_user_vertex_function)(vertex, FALSE);
        }

    switch( LMD_Lmodel )
    {
        case LMD_LMODEL_CONSTANT:
            vertex = (FLOAT *)&polygon[0];
            lmd_evaluate_lmodel( vertex );
 
            for( k=0; k<n; k++ )
            {
                polygon[k].ColorR = 255*polygon[0].ColorR;
                polygon[k].ColorG = 255*polygon[0].ColorG;
                polygon[k].ColorB = 255*polygon[0].ColorB;
                polygon[k].ColorA =     polygon[0].ColorA;
            }
        break;

        case LMD_LMODEL_GOURAUD:
            for( k=0; k<n; k++ )
            {
                vertex = (FLOAT *)&polygon[k];
                lmd_evaluate_lmodel(vertex);

                polygon[k].ColorR = 255*polygon[k].ColorR;
                polygon[k].ColorG = 255*polygon[k].ColorG;
                polygon[k].ColorB = 255*polygon[k].ColorB;
            }
        break;
    }

    if ( ZBF_user_vertex_function )
        for( k=0; k<n; k++ )
        {
            vertex = (FLOAT *)&polygon[k];
            (*ZBF_user_vertex_function)(vertex, TRUE);
        }

    trs_projection_transform( n, polygon );
    if ( (n = clp_clip_polygon(n,polygon) ) < 3 ) return;
    trs_scale_transform( n, polygon );
  
#ifdef  JAKO
#define JAKO
    if ( n > 3 ) {
        vertex = (FLOAT *)&polygon[0];
        for( i = 0; i < VERTEX_NCOMP; i++ ) triangle[0][i] = vertex[i];

        for( k = 1; k < n; k++ ) {
            vertex = (FLOAT *)&polygon[k];
            for( i = 0; i < LMD_NtoInterpolate[LMD_Lmodel]; i++ ) {
                j = LMD_Interpolate[LMD_Lmodel][i];
                triangle[0][j] += vertex[j];
                }
            }
        for( i = 0; i < LMD_NtoInterpolate[LMD_Lmodel]; i++ ) {
            j = LMD_Interpolate[LMD_Lmodel][i];
            triangle[0][j] /= n;
            }

        triangle[0][VERTEX_COORD_X] = ((int)triangle[0][VERTEX_COORD_X])+0.5;
        triangle[0][VERTEX_COORD_Y] = ((int)triangle[0][VERTEX_COORD_Y])+0.5;

        for( k = 0; k < n - 1; k++ ) {
            vertex = (FLOAT *)&polygon[k];
            for( i = 0; i < VERTEX_NCOMP; i++ ) triangle[1][i] = vertex[i];

            vertex = (FLOAT *)&polygon[k+1];
            for( i = 0; i < VERTEX_NCOMP; i++ ) triangle[2][i] = vertex[i];

            zbf_draw_triangle( triangle );
            }

        vertex = (FLOAT *)&polygon[n-1];
        for( i = 0; i < VERTEX_NCOMP; i++ ) triangle[1][i] = vertex[i];

        vertex = (FLOAT *)&polygon[0];
        for( i = 0; i < VERTEX_NCOMP; i++ ) triangle[2][i] = vertex[i];

        zbf_draw_triangle( triangle );
    } else {
        for( k = 0; k < n; k++ ) {
            vertex = (FLOAT *)&polygon[k];
            for( i = 0; i < VERTEX_NCOMP; i++ ) triangle[k][i] = vertex[i];
            }

        zbf_draw_triangle( triangle );
        }
#else
    vertex = (FLOAT *)&polygon[0];
    for( i = 0; i < VERTEX_NCOMP; i++ ) triangle[0][i] = vertex[i];

    for( k=1; k<n-1; k++ )
    {
        vertex = (FLOAT *)&polygon[k];
        for( i = 0; i < VERTEX_NCOMP; i++ ) triangle[1][i] = vertex[i];

        vertex = (FLOAT *)&polygon[k+1];
        for( i = 0; i < VERTEX_NCOMP; i++ ) triangle[2][i] = vertex[i];

        zbf_draw_triangle( triangle );
    }
#endif
}

void zbf_draw_triangle( FLOAT triangle[3][VERTEX_NCOMP] )
{
    static FLOAT t[3][VERTEX_NCOMP];

    FLOAT y0, y1, y2;

    FLOAT *vertex0;
    FLOAT *vertex1;
    FLOAT *vertex2;

    int i0, i1, i2;
    int i, swap;

    ZBF_Tcount++;

    y0 = triangle[0][VERTEX_COORD_Y];
    y1 = triangle[1][VERTEX_COORD_Y];
    y2 = triangle[2][VERTEX_COORD_Y];

    if ( y0 < y1 ) {
        if ( y0 < y2 ) {
            i0 = 0;
            if ( y1 < y2 ) {  /* y0 < y1 < y2 */
                i1 = 1;
                i2 = 2;
            } else {          /* y0 < y2 < y1 */
                i1 = 2;
                i2 = 1;
                }
        } else {
            i0 = 2;           /* y2 < y0 < y1 */
            i1 = 0;
            i2 = 1;
            }
    } else {                  /* y1 < y0 */
        if ( y1 < y2 ) {
            i0 = 1;
            if ( y0 < y2 ) {  /* y1 < y0 < y2 */
                i1 = 0;
                i2 = 2;
            } else {          /* y1 < y2 < y0 */
                i1 = 2;
                i2 = 0;
                }
        } else {
            i0 = 2;           /* y2 < y1 < y0 */
            i1 = 1;
            i2 = 0;
            }
        }

    y0 = triangle[i0][VERTEX_COORD_Y];
    y1 = triangle[i1][VERTEX_COORD_Y];
    y2 = triangle[i2][VERTEX_COORD_Y];

    if ( ABS(y0-y1) < ABS(y2-y1) )
    {
        swap = i2;
        i2 = i0;
        i0 = swap;
    }

    vertex0 = triangle[i0];
    vertex1 = triangle[i1];
    vertex2 = triangle[i2];

    if ( vertex1[VERTEX_COORD_Y] != vertex2[VERTEX_COORD_Y] )
    {
        y0 = ( vertex1[VERTEX_COORD_Y] - vertex0[VERTEX_COORD_Y] ) /
             ( vertex2[VERTEX_COORD_Y] - vertex0[VERTEX_COORD_Y] );

        for( i = 0; i < VERTEX_NCOMP; i++ )
        {
            t[0][i] = vertex0[i];
            t[1][i] = vertex1[i];
            t[2][i] = y0 * (vertex2[i] - vertex0[i]) + vertex0[i];
        }

        t[2][VERTEX_COORD_Y] = vertex1[VERTEX_COORD_Y];

        zbf_draw_triangle_y( t );

        for( i = 0; i < VERTEX_NCOMP; i++ ) t[0][i] = vertex2[i];

        zbf_draw_triangle_y( t );
    } else
    {
        for( i = 0; i < VERTEX_NCOMP; i++ )
        {
            t[0][i] = vertex0[i]; t[1][i] = vertex1[i]; t[2][i] = vertex2[i];
        }

        zbf_draw_triangle_y( t );
    }
}

void zbf_draw_triangle_y( FLOAT triangle[3][VERTEX_NCOMP] )
{
    static FLOAT dP0[VERTEX_NCOMP];
    static FLOAT dP1[VERTEX_NCOMP];

    static FLOAT P0[VERTEX_NCOMP];
    static FLOAT P1[VERTEX_NCOMP];

    FLOAT y;
    FLOAT y1;

    FLOAT ds;

    FLOAT *vertex0;
    FLOAT *vertex1;
    FLOAT *vertex2;

    int i, j, k, n;

    vertex0 = triangle[0];
    vertex1 = triangle[1];
    vertex2 = triangle[2];

    y  = vertex0[VERTEX_COORD_Y];
    y1 = vertex1[VERTEX_COORD_Y];

    n = ABS( y1 - y ) + 1;

    for( i = 0; i < VERTEX_NCOMP; i++ ) P0[i] = P1[i] = vertex0[i];

    if ( n > 1 )
    {
        ds = 1.0/(n-1.0);
        for( i = 0; i < LMD_NtoInterpolate[LMD_Lmodel]; i++ )
        {
            j = LMD_Interpolate[LMD_Lmodel][i];
            dP0[j] = ds*(vertex1[j] - vertex0[j]);
            dP1[j] = ds*(vertex2[j] - vertex0[j]);
        }
    }

    if ( y1 <= y )
    {
        zbf_draw_triangle_x( y, P0, P1 );
        n -= 1;
    }
        
    for( k = 1;  k < n; k++ )
    { 
        for( i = 0; i < LMD_NtoInterpolate[LMD_Lmodel]; i++ )
        {
            j = LMD_Interpolate[LMD_Lmodel][i];
            P0[j] = k*dP0[j] + vertex0[j];
            P1[j] = k*dP1[j] + vertex0[j];
        }
        y = P0[VERTEX_COORD_Y];
        zbf_draw_triangle_x( y, P0, P1 );
    }
}

void zbf_draw_triangle_x( FLOAT y, FLOAT *P0, FLOAT *P1 )
{
    FLOAT dP[VERTEX_NCOMP];
    FLOAT  P[VERTEX_NCOMP];

    FLOAT x, x1, z;

    FLOAT ds;

    FLOAT *swap;

    ZVALUE Z;

    int offset;
    int i, j, k, n;

    if ( P0[VERTEX_COORD_X] > P1[VERTEX_COORD_X] )
    {
        swap = P0; P0 = P1; P1 = swap;
    }

    x  = P0[VERTEX_COORD_X] = ((int)P0[VERTEX_COORD_X])+0.5;
    x1 = P1[VERTEX_COORD_X] = ((int)P1[VERTEX_COORD_X])+0.5;

    for( i = 0; i < VERTEX_NCOMP; i++ ) P[i] = P0[i];

    n = x1 - x + 1;
    n *= ZBF_Oversample_Polygon_X;

    if (  n > 1 )
    {
        ds = 1.0/(n-1.0);
        for( i = 0; i < LMD_NtoInterpolate[LMD_Lmodel]; i++ )
        {
            j = LMD_Interpolate[LMD_Lmodel][i];
            dP[j] = ds * (P1[j] - P0[j]);
        }
    }

    for( k = 1; k < n; k++ )
    {
        for( i = 0; i < LMD_NtoInterpolate[LMD_Lmodel]; i++ )
        {
            j = LMD_Interpolate[LMD_Lmodel][i];
            P[j] = k*dP[j] + P0[j];
        }
        x = P[VERTEX_COORD_X];
        z = P[VERTEX_COORD_Z];

        if ( (int)x == (int)P0[VERTEX_COORD_X] ) continue;

        offset = ((int)y) * ZBF_NX + x;
        if ( z <= ZBF_Z[offset] && ZBF_T[offset] != ZBF_Pcount )
        {
            ZBF_Z[offset] = z;
            ZBF_T[offset] = ZBF_Pcount;
            if ( LMD_Lmodel != LMD_LMODEL_SHADOW_PASS ) zbf_update_pixel( offset, P );
        }
    }
}

void zbf_draw_polyline( int n, ZBF_VERTEX *polyline )
{
    int i;

    trs_viewing_transform( n, polyline );
    trs_projection_transform( n, polyline );

    for( i=0; i<n-1; i++ )
    {
        zbf_draw_line( (FLOAT *)&polyline[i],(FLOAT *)&polyline[i+1] );
    }
}

void zbf_draw_line( FLOAT *v0,FLOAT *v1 )
{
    FLOAT x, y, z, dx, dy, dz, ds;

    FLOAT r0, g0, b0, a0;
    FLOAT r, g, b, a;

    FLOAT c,dc, dr, dg, db, da;

    ZBF_VERTEX line[2];

    int cindex;
    int offset;

    int n;
    int i;

    memcpy(&line[0],v0,sizeof(ZBF_VERTEX));
    memcpy(&line[1],v1,sizeof(ZBF_VERTEX));

    if ( !clp_clip_line( line ) ) return;
    v0 = (FLOAT *)&line[0];
    v1 = (FLOAT *)&line[1];

    trs_scale_transform( 2, line );

    if ( v0[VERTEX_COORD_X] < ZBF_VX_L ) v0[VERTEX_COORD_X] = ZBF_VX_L;
    if ( v0[VERTEX_COORD_X] > ZBF_VX_H ) v0[VERTEX_COORD_X] = ZBF_VX_H;
    if ( v0[VERTEX_COORD_Y] < ZBF_VY_L ) v0[VERTEX_COORD_Y] = ZBF_VY_L;
    if ( v0[VERTEX_COORD_Y] > ZBF_VY_H ) v0[VERTEX_COORD_Y] = ZBF_VY_H;

    if ( v1[VERTEX_COORD_X] < ZBF_VX_L ) v1[VERTEX_COORD_X] = ZBF_VX_L;
    if ( v1[VERTEX_COORD_X] > ZBF_VX_H ) v1[VERTEX_COORD_X] = ZBF_VX_H;
    if ( v1[VERTEX_COORD_Y] < ZBF_VY_L ) v1[VERTEX_COORD_Y] = ZBF_VY_L;
    if ( v1[VERTEX_COORD_Y] > ZBF_VY_H ) v1[VERTEX_COORD_Y] = ZBF_VY_H;

    x = v0[VERTEX_COORD_X];
    y = v0[VERTEX_COORD_Y];
    z = v0[VERTEX_COORD_Z] - 1.0e-3;

    c = v0[VERTEX_COLOR_I];

    r = v0[VERTEX_COLOR_R];
    g = v0[VERTEX_COLOR_G];
    b = v0[VERTEX_COLOR_B];
    a = v0[VERTEX_MATERIAL_ALPHA];

    dx = ( v1[VERTEX_COORD_X] - x );
    dy = ( v1[VERTEX_COORD_Y] - y );
    dz = ( v1[VERTEX_COORD_Z] - 1.0e-3 - z );

    if ( LMD_Lmodel == LMD_LMODEL_CMAP )
    {
        dc = ( v1[VERTEX_COLOR_I] - c );
    } else
    {
        dr = ( v1[VERTEX_COLOR_R] - r );
        dg = ( v1[VERTEX_COLOR_G] - g );
        db = ( v1[VERTEX_COLOR_B] - b );
        da = 0.0;
    }

    if ( ABS( dx ) >  ABS( dy ) )
    {
        ds = ABS( dx );
    } else
    {
        ds = ABS( dy );
    }

    if ( ds < 1.0 )
    {
        n   =   1;
        ds  = 1.0;
    } else
    {
        ds *= ZBF_Oversample_Lines; 
        n   = ds + 1;
        ds  = 1.0 / ds;

        dx *= ds; dy *= ds; dz *= ds;
        if ( LMD_Lmodel == LMD_LMODEL_CMAP )
        {
            dc *= ds;
        } else
        {
            dr *= ds; dg *= ds; db *= ds; da *= ds;
        }
    }

    if ( LMD_Lmodel != LMD_LMODEL_CMAP )
    { 
         for( i = 0; i < n; i++ )
         {
            offset = ((int)y) * ZBF_NX + (int)x;
            zbf_draw_pixel_rgba( offset, z, r, g, b, a );

            x += dx;
            y += dy;
            z += dz;
            r += dr;
            g += dg;
            b += db;
            a += da;
        }
    } else
    {
        for( i = 0; i < n; i++ )
        {
            offset = ((int)y) * ZBF_NX + (int)x;
            cindex = c;
            zbf_draw_pixel_cmap( offset, z, c );

            x += dx;
            y += dy;
            z += dz;
            c += dc;
        }
    }
}

void zbf_draw_points(int n, ZBF_VERTEX *points)
{
    FLOAT *p,x,y,z,c,r,g,b,a;
    FLOAT r0,g0,b0,a0;

    int i,offset,cindex;

    trs_viewing_transform( n, points );
    trs_projection_transform( n, points );
    trs_scale_transform( n, points );

    p = (FLOAT *)points; 
    for( i=0; i<n; i++, p++ )
    {
        x = p[VERTEX_COORD_X];
        y = p[VERTEX_COORD_Y];
        z = p[VERTEX_COORD_Z];

        c = p[VERTEX_COLOR_I];

        r = p[VERTEX_COLOR_R];
        g = p[VERTEX_COLOR_G];
        b = p[VERTEX_COLOR_B];
        a = p[VERTEX_MATERIAL_ALPHA];

        if ( z >= -1 && z <= 1.0 && x >= 0 && x < ZBF_NX && y >= 0 && y < ZBF_NY )
        {
            offset = ((int)y) * ZBF_NX + (int)x;
            if ( LMD_Lmodel == LMD_LMODEL_CMAP )
            {
                cindex = c;
                zbf_draw_pixel_cmap( offset, z, c );
            } else
            {
                zbf_draw_pixel_rgba( offset, z, r, g, b, a );
            }
        }
    }
}

#ifdef  NOTDEF
#define NOTDEF

void zbf_show( )
{
    static unsigned long *Image;
    static int first_time = 1;
    int i;

    int dev;
    short val;

    if ( first_time )
    {
        Image = (unsigned long *)malloc( ZBF_NX*ZBF_NY*sizeof(int) );

        foreground( );
        prefsize( ZBF_NX, ZBF_NY );

        winopen( "zbf" );

        qdevice( REDRAW );

        RGBmode( );
        gconfig( );

        RGBcolor( 0, 0, 0 );
        clear( );
    }

    for( i = 0; i < ZBF_NY*ZBF_NX; i++ ) {
        Image[i]  = 255 << 24;
        Image[i] |= ((int)ZBF_B[i]) << 16;
        Image[i] |= ((int)ZBF_G[i]) <<  8;
        Image[i] |= ((int)ZBF_R[i]);
        }

    lrectwrite( 0, 0, ZBF_NX-1, ZBF_NY-1, Image );

    for( ;; ) {
        dev = qread( &val );
        if ( dev == REDRAW ) {
            reshapeviewport( );
            lrectwrite( 0, 0, ZBF_NX - 1, ZBF_NY - 1, Image );
            } 
        }

    first_time = 0;
}

#else

void zbf_show( )
{
    static int n = 0;
    char name[256];
    FILE *fp;

    sprintf( name, "zbf.%04d", n++ );
    fp = fopen( name, "w" );
    fprintf( fp, "%d %d %d\n", ZBF_NX,ZBF_NY,3*sizeof(CVALUE) );
    fwrite( ZBF_R, ZBF_NX*ZBF_NY, sizeof(CVALUE), fp ); 
    fwrite( ZBF_G, ZBF_NX*ZBF_NY, sizeof(CVALUE), fp ); 
    fwrite( ZBF_B, ZBF_NX*ZBF_NY, sizeof(CVALUE), fp ); 
    fclose(fp );
}

#endif
