/*
** Copyright 1991, Silicon Graphics, Inc.
** All Rights Reserved.
**
** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
** the contents of this file may not be disclosed to third parties, copied or
** duplicated in any form, in whole or in part, without the prior written
** permission of Silicon Graphics, Inc.
**
** RESTRICTED RIGHTS LEGEND:
** Use, duplication or disclosure by the Government is subject to restrictions
** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
** rights reserved under the Copyright Laws of the United States.
**
*/
#include "precomp.h"
#pragma hdrstop
#include "phong.h"

#define __TWO_31 ((__GLfloat) 2147483648.0)

/*
** Most line functions will start off by computing the information 
** computed by this routine.
**
** The excessive number of labels in this routine is partly due
** to the fact that it is used as a model for writing an assembly 
** equivalent.
*/
#ifndef NT
void FASTCALL __glInitLineData(__GLcontext *gc, __GLvertex *v0, __GLvertex *v1)
{
    GLint start, end;
    __GLfloat x0,y0,x1,y1;
    __GLfloat minorStart;
    GLint intMinorStart;
    __GLfloat dx, dy;
    __GLfloat offset;
    __GLfloat slope;
    __GLlineState *ls = &gc->state.line;
    __GLfloat halfWidth;
    __GLfloat x0frac, x1frac, y0frac, y1frac, half, totDist;

    gc->line.options.v0 = v0;
    gc->line.options.v1 = v1;
    gc->line.options.width = gc->state.line.aliasedWidth;

    x0=v0->window.x;
    y0=v0->window.y;
    x1=v1->window.x;
    y1=v1->window.y;
    dx=x1-x0;
    dy=y1-y0;

    halfWidth = (ls->aliasedWidth - 1) * __glHalf;

    /* Ugh.  This is slow.  Bummer. */
    x0frac = x0 - ((GLint) x0);
    x1frac = x1 - ((GLint) x1);
    y0frac = y0 - ((GLint) y0);
    y1frac = y1 - ((GLint) y1);
    half = __glHalf;

    if (dx > __glZero) {
	if (dy > __glZero) {
	    if (dx > dy) {	/* dx > dy > 0 */
		gc->line.options.yBig = 1;
posxmajor:			/* dx > |dy| >= 0 */
		gc->line.options.yLittle = 0;
		gc->line.options.xBig = 1;
		gc->line.options.xLittle = 1;
		slope = dy/dx;

		start = (GLint) (x0);
		end = (GLint) (x1);

		y0frac -= half;
		if (y0frac < 0) y0frac = -y0frac;

		totDist = y0frac + x0frac - half;
		if (totDist > half) start++;

		y1frac -= half;
		if (y1frac < 0) y1frac = -y1frac;

		totDist = y1frac + x1frac - half;
		if (totDist > half) end++;

		offset = start + half - x0;

		gc->line.options.length = dx;
		gc->line.options.numPixels = end - start;

xmajorfinish:
		gc->line.options.axis = __GL_X_MAJOR;
		gc->line.options.xStart = start;
		gc->line.options.offset = offset;
		minorStart = y0 + offset*slope - halfWidth;
		intMinorStart = (GLint) minorStart;
		minorStart -= intMinorStart;
		gc->line.options.yStart = intMinorStart;
		gc->line.options.dfraction = (GLint)(slope * __TWO_31);
		gc->line.options.fraction = (GLint)(minorStart * __TWO_31);
	    } else {		/* dy >= dx > 0 */
		gc->line.options.xBig = 1;
posymajor:			/* dy >= |dx| >= 0, dy != 0 */
		gc->line.options.xLittle = 0;
		gc->line.options.yBig = 1;
		gc->line.options.yLittle = 1;
		slope = dx/dy;

		start = (GLint) (y0);
		end = (GLint) (y1);

		x0frac -= half;
		if (x0frac < 0) x0frac = -x0frac;

		totDist = y0frac + x0frac - half;
		if (totDist > half) start++;

		x1frac -= half;
		if (x1frac < 0) x1frac = -x1frac;

		totDist = y1frac + x1frac - half;
		if (totDist > half) end++;

		offset = start + half - y0;

		gc->line.options.length = dy;
		gc->line.options.numPixels = end - start;

ymajorfinish:
		gc->line.options.axis = __GL_Y_MAJOR;
		gc->line.options.yStart = start;
		gc->line.options.offset = offset;
		minorStart = x0 + offset*slope - halfWidth;
		intMinorStart = (GLint) minorStart;
		minorStart -= intMinorStart;
		gc->line.options.xStart = intMinorStart;
		gc->line.options.dfraction = (GLint)(slope * __TWO_31);
		gc->line.options.fraction = (GLint)(minorStart * __TWO_31);
	    }
	} else {
	    if (dx > -dy) {	/* dx > -dy >= 0 */
		gc->line.options.yBig = -1;
		goto posxmajor;
	    } else {		/* -dy >= dx >= 0, dy != 0 */
		gc->line.options.xBig = 1;
negymajor:			/* -dy >= |dx| >= 0, dy != 0 */
		gc->line.options.xLittle = 0;
		gc->line.options.yBig = -1;
		gc->line.options.yLittle = -1;
		slope = dx/-dy;

		start = (GLint) (y0);
		end = (GLint) (y1);

		x0frac -= half;
		if (x0frac < 0) x0frac = -x0frac;

		totDist = x0frac + half - y0frac;
		if (totDist > half) start--;

		x1frac -= half;
		if (x1frac < 0) x1frac = -x1frac;

		totDist = x1frac + half - y1frac;
		if (totDist > half) end--;

		offset = y0 - (start + half);

		gc->line.options.length = -dy;
		gc->line.options.numPixels = start - end;
		goto ymajorfinish;
	    }
	}
    } else {
	if (dy > __glZero) {
	    if (-dx > dy) {	/* -dx > dy > 0 */
		gc->line.options.yBig = 1;
negxmajor:			/* -dx > |dy| >= 0 */
		gc->line.options.yLittle = 0;
		gc->line.options.xBig = -1;
		gc->line.options.xLittle = -1;
		slope = dy/-dx;

		start = (GLint) (x0);
		end = (GLint) (x1);

		y0frac -= half;
		if (y0frac < 0) y0frac = -y0frac;

		totDist = y0frac + half - x0frac;
		if (totDist > half) start--;

		y1frac -= half;
		if (y1frac < 0) y1frac = -y1frac;

		totDist = y1frac + half - x1frac;
		if (totDist > half) end--;

		offset = x0 - (start + half);

		gc->line.options.length = -dx;
		gc->line.options.numPixels = start - end;

		goto xmajorfinish;
	    } else {		/* dy >= -dx >= 0, dy != 0 */
		gc->line.options.xBig = -1;
		goto posymajor;
	    }
	} else {
	    if (dx < dy) {	/* -dx > -dy >= 0 */
		gc->line.options.yBig = -1;
		goto negxmajor;
	    } else {		/* -dy >= -dx >= 0 */
#ifdef NT 
		if (dx == dy && dy == 0) {
		    gc->line.options.numPixels = 0;
		    return;
		}
#else
		if (dx == dy && dy == 0) return;
#endif
		gc->line.options.xBig = -1;
		goto negymajor;
	    }
	}
    }
}
#endif

#ifdef NT
void FASTCALL __glRenderAliasLine(__GLcontext *gc, __GLvertex *v0, __GLvertex *v1, GLuint flags)
#else
void FASTCALL __glRenderAliasLine(__GLcontext *gc, __GLvertex *v0, __GLvertex *v1)
#endif
{
    __GLlineState *ls = &gc->state.line;
    __GLfloat invDelta;
    __GLfloat winv, r;
    __GLcolor *cp;
    __GLfloat offset;
    GLuint modeFlags = gc->polygon.shader.modeFlags;

#ifndef NT
    __glInitLineData(gc, v0, v1);
    if (gc->line.options.numPixels == 0) return;
#else
    GLboolean init;
    CHOP_ROUND_ON();

    init = (GLboolean)__glInitLineData(gc, v0, v1);

    CHOP_ROUND_OFF();

    if (!init)
    {
        return;
    }

    invDelta = gc->line.options.oneOverLength;
#endif

    offset = gc->line.options.offset;

    /*
    ** Set up increments for any enabled line options.
    */
#ifndef NT
    invDelta = __glOne / gc->line.options.length;
#endif
    if (modeFlags & __GL_SHADE_DEPTH_ITER) {
        __GLfloat dzdx;

        /*
        ** Calculate window z coordinate increment and starting position.
        */
        dzdx = (v1->window.z - v0->window.z) * invDelta;
#ifdef NT
        if(( gc->modes.depthBits == 16 ) &&
           ( gc->depthBuffer.scale <= (GLuint)0xffff )) {
            gc->polygon.shader.frag.z = 
              (__GLzValue)(Z16_SCALE *(v0->window.z + dzdx * offset));
            gc->polygon.shader.dzdx = (GLint)(Z16_SCALE * dzdx);
        }
        else {
            gc->polygon.shader.frag.z = 
              (__GLzValue)(v0->window.z + dzdx * offset);
            gc->polygon.shader.dzdx = (GLint)dzdx;
        }
#else
        gc->polygon.shader.frag.z = (__GLzValue)(v0->window.z + dzdx * offset);
        gc->polygon.shader.dzdx = (GLint)dzdx;
#endif
    }

    if (modeFlags & __GL_SHADE_LINE_STIPPLE) {
        if (!gc->line.notResetStipple) {
            gc->line.stipplePosition = 0;
            gc->line.repeat = 0;
            gc->line.notResetStipple = GL_TRUE;
        }
    }

    if (modeFlags & __GL_SHADE_COMPUTE_FOG)
    {
        __GLfloat f1, f0;
        __GLfloat dfdx;

        gc->line.options.f0 = f0 = v0->eyeZ;
        gc->polygon.shader.dfdx = dfdx = 
            (v1->eyeZ - v0->eyeZ) * invDelta;
        gc->polygon.shader.frag.f = f0 + dfdx * offset;
    }
    else if (modeFlags & __GL_SHADE_INTERP_FOG)
    {
        __GLfloat f1, f0;
        __GLfloat dfdx;

        f0 = v0->fog;
        f1 = v1->fog;
        gc->line.options.f0 = f0;
        gc->polygon.shader.dfdx = dfdx = (f1 - f0) * invDelta;
        gc->polygon.shader.frag.f = f0 + dfdx * offset;
    }
    
    if (modeFlags & __GL_SHADE_TEXTURE) {
        __GLfloat v0QW, v1QW;
        __GLfloat dS, dT, dQWdX;
        winv = v0->window.w;

        /*
        ** Calculate texture s and t value increments.
        */
        v0QW = v0->texture.w * winv;
        v1QW = v1->texture.w * v1->window.w;
        dS = (v1->texture.x * v1QW - v0->texture.x * v0QW) * invDelta;
        dT = (v1->texture.y * v1QW - v0->texture.y * v0QW) * invDelta;
        gc->polygon.shader.dsdx = dS;
        gc->polygon.shader.dtdx = dT;
        gc->polygon.shader.dqwdx = dQWdX = (v1QW - v0QW) * invDelta;
        gc->polygon.shader.frag.s = v0->texture.x * winv + dS * offset;
        gc->polygon.shader.frag.t = v0->texture.y * winv + dT * offset;
        gc->polygon.shader.frag.qw = v0->texture.w * winv + dQWdX * offset;
    } 
    
#ifdef GL_WIN_phong_shading
    if (modeFlags & __GL_SHADE_PHONG) 
        (*gc->procs.phong.InitLineParams) (gc, v0, v1, invDelta);
#endif //GL_WIN_phong_shading

    if ((modeFlags & __GL_SHADE_SMOOTH) 
#ifdef GL_WIN_phong_shading
        || ((modeFlags & __GL_SHADE_PHONG) &&
            (gc->polygon.shader.phong.flags & __GL_PHONG_NEED_COLOR_XPOLATE))
#endif //GL_WIN_phong_shading
        ) {
        __GLcolor *c0 = v0->color;
        __GLcolor *c1 = v1->color;
        __GLfloat drdx, dgdx, dbdx, dadx;

        /*
        ** Calculate red, green, blue and alpha value increments.
        */
        drdx = (c1->r - c0->r) * invDelta;
        if (gc->modes.rgbMode) {
            dgdx = (c1->g - c0->g) * invDelta;
            dbdx = (c1->b - c0->b) * invDelta;
            dadx = (c1->a - c0->a) * invDelta;
            gc->polygon.shader.dgdx = dgdx;
            gc->polygon.shader.dbdx = dbdx;
            gc->polygon.shader.dadx = dadx;
        }
        gc->polygon.shader.drdx = drdx;
        cp = v0->color;
    } else {
        cp = v1->color;

        // Initialize these values to zero even for the flat case
        // because there is an optimization in so_prim which will
        // turn off smooth shading without repicking, so these need
        // to be valid
        gc->polygon.shader.drdx = __glZero;
        gc->polygon.shader.dgdx = __glZero;
        gc->polygon.shader.dbdx = __glZero;
        gc->polygon.shader.dadx = __glZero;
    }

    r = cp->r;
    if (modeFlags & __GL_SHADE_RGB) {
        __GLfloat g,b,a;

        g = cp->g;
        b = cp->b;
        a = cp->a;
        gc->polygon.shader.frag.color.g = g;
        gc->polygon.shader.frag.color.b = b;
        gc->polygon.shader.frag.color.a = a;
    }
    gc->polygon.shader.frag.color.r = r;
    
    gc->polygon.shader.length = gc->line.options.numPixels;
    (*gc->procs.line.processLine)(gc);
}

#ifdef NT
void FASTCALL __glRenderFlatFogLine(__GLcontext *gc, __GLvertex *v0,
                                    __GLvertex *v1, GLuint flags)
#else
void FASTCALL __glRenderFlatFogLine(__GLcontext *gc, __GLvertex *v0,
                                    __GLvertex *v1)
#endif
{
    __GLcolor v0col, v1col;
    __GLcolor *v0ocp, *v1ocp;

    (*gc->procs.fogColor)(gc, &v0col, v1->color, v0->fog);
    (*gc->procs.fogColor)(gc, &v1col, v1->color, v1->fog);
    v0ocp = v0->color;
    v1ocp = v1->color;
    v0->color = &v0col;
    v1->color = &v1col;

#ifdef NT
    (*gc->procs.renderLine2)(gc, v0, v1, flags);
#else
    (*gc->procs.renderLine2)(gc, v0, v1);
#endif
    
    v0->color = v0ocp;
    v1->color = v1ocp;
}


/************************************************************************/

/*
** Most line functions will start off by computing the information 
** computed by this routine.
**
** The excessive number of labels in this routine is partly due
** to the fact that it is used as a model for writing an assembly 
** equivalent.
*/
void FASTCALL __glInitAALineData(__GLcontext *gc, __GLvertex *v0, __GLvertex *v1)
{
    GLint start;
    __GLfloat width;
    __GLfloat x0,y0,x1,y1;
    __GLfloat minorStart;
    GLint intMinorStart;
    __GLfloat dx, dy;
    __GLfloat offset;
    __GLfloat slope;
    __GLlineState *ls = &gc->state.line;
    __GLfloat halfWidth;
    __GLfloat realLength, oneOverRealLength;
    __GLfloat dldx, dldy;
    __GLfloat dddx, dddy;

    gc->line.options.v0 = v0;
    gc->line.options.v1 = v1;

    x0=v0->window.x;
    y0=v0->window.y;
    x1=v1->window.x;
    y1=v1->window.y;
    dx=x1-x0;
    dy=y1-y0;
    realLength = __GL_SQRTF(dx*dx+dy*dy);
    oneOverRealLength = realLength == __glZero ? __glZero : __glOne/realLength;
    gc->line.options.realLength = realLength;
    gc->line.options.dldx = dldx = dx * oneOverRealLength;
    gc->line.options.dldy = dldy = dy * oneOverRealLength;
    gc->line.options.dddx = dddx = -dldy;
    gc->line.options.dddy = dddy = dldx;

    if (dx > __glZero) {
	if (dy > __glZero) {	/* dx > 0, dy > 0 */
	    gc->line.options.dlBig = dldx + dldy;
	    gc->line.options.ddBig = dddx + dddy;
	    if (dx > dy) {	/* dx > dy > 0 */
		gc->line.options.yBig = 1;
posxmajor:			/* dx > |dy| >= 0 */
		gc->line.options.yLittle = 0;
		gc->line.options.xBig = 1;
		gc->line.options.xLittle = 1;
		gc->line.options.dlLittle = dldx;
		gc->line.options.ddLittle = dddx;
		slope = dy/dx;
		start = (GLint) x0;
		offset = start + __glHalf - x0;

		gc->line.options.length = dx;
		gc->line.options.numPixels = (GLint)__GL_FAST_CEILF(x1 - x0) + 1;

		width = __GL_FAST_CEILF(gc->state.line.smoothWidth * 
			realLength / dx);
xmajorfinish:
		gc->line.options.width = (GLint)width + 1;
		halfWidth = width * __glHalf;

		gc->line.options.axis = __GL_X_MAJOR;
		gc->line.options.xStart = start;
		gc->line.options.offset = offset;
		minorStart = y0 + offset*slope - halfWidth;
		intMinorStart = (GLint) minorStart;
		minorStart -= intMinorStart;
		gc->line.options.yStart = intMinorStart;
		gc->line.options.dfraction = (GLint)(slope * __TWO_31);
		gc->line.options.fraction = (GLint)(minorStart * __TWO_31);
	    } else {		/* dy >= dx > 0 */
		gc->line.options.xBig = 1;
posymajor:			/* dy >= |dx| >= 0, dy != 0 */
		gc->line.options.xLittle = 0;
		gc->line.options.yBig = 1;
		gc->line.options.yLittle = 1;
		gc->line.options.dlLittle = dldy;
		gc->line.options.ddLittle = dddy;
		slope = dx/dy;
		start = (GLint) y0;
		offset = start + __glHalf - y0;

		gc->line.options.length = dy;
		gc->line.options.numPixels = (GLint)__GL_FAST_CEILF(y1 - y0) + 1;

		width = __GL_FAST_CEILF(gc->state.line.smoothWidth * 
			realLength / dy);
ymajorfinish:
		gc->line.options.width = (GLint)width + 1;
		halfWidth = width * __glHalf;

		gc->line.options.axis = __GL_Y_MAJOR;
		gc->line.options.yStart = start;
		gc->line.options.offset = offset;
		minorStart = x0 + offset*slope - halfWidth;
		intMinorStart = (GLint) minorStart;
		minorStart -= intMinorStart;
		gc->line.options.xStart = intMinorStart;
		gc->line.options.dfraction = (GLint)(slope * __TWO_31);
		gc->line.options.fraction = (GLint)(minorStart * __TWO_31);
	    }
	} else {		/* dx > 0, dy <= 0 */
	    gc->line.options.dlBig = dldx - dldy;
	    gc->line.options.ddBig = dddx - dddy;
	    if (dx > -dy) {	/* dx > -dy >= 0 */
		gc->line.options.yBig = -1;
		goto posxmajor;
	    } else {		/* -dy >= dx >= 0, dy != 0 */
		gc->line.options.xBig = 1;
negymajor:			/* -dy >= |dx| >= 0, dy != 0 */
		gc->line.options.xLittle = 0;
		gc->line.options.yBig = -1;
		gc->line.options.yLittle = -1;
		gc->line.options.dlLittle = -dldy;
		gc->line.options.ddLittle = -dddy;
		slope = dx/-dy;
		start = (GLint) y0;
		offset = y0 - (start + __glHalf);

		gc->line.options.length = -dy;
		gc->line.options.numPixels = (GLint)__GL_FAST_CEILF(y0 - y1) + 1;

		width = __GL_FAST_CEILF(-gc->state.line.smoothWidth * 
			realLength / dy);

		goto ymajorfinish;
	    }
	}
    } else {
	if (dy > __glZero) {	/* dx <= 0, dy > 0 */
	    gc->line.options.dlBig = dldy - dldx;
	    gc->line.options.ddBig = dddy - dddx;
	    if (-dx > dy) {	/* -dx > dy > 0 */
		gc->line.options.yBig = 1;
negxmajor:			/* -dx > |dy| >= 0 */
		gc->line.options.yLittle = 0;
		gc->line.options.xBig = -1;
		gc->line.options.xLittle = -1;
		gc->line.options.dlLittle = -dldx;
		gc->line.options.ddLittle = -dddx;
		slope = dy/-dx;
		start = (GLint) x0;
		offset = x0 - (start + __glHalf);

		gc->line.options.length = -dx;
		gc->line.options.numPixels = (GLint)__GL_FAST_CEILF(x0 - x1) + 1;

		width = __GL_FAST_CEILF(-gc->state.line.smoothWidth * 
			realLength / dx);

		goto xmajorfinish;
	    } else {		/* dy >= -dx >= 0, dy != 0 */
		gc->line.options.xBig = -1;
		goto posymajor;
	    }
	} else {		/* dx <= 0, dy <= 0 */
	    gc->line.options.dlBig = -dldx - dldy;
	    gc->line.options.ddBig = -dddx - dddy;
	    if (dx < dy) {	/* -dx > -dy >= 0 */
		gc->line.options.yBig = -1;
		goto negxmajor;
	    } else {		/* -dy >= -dx >= 0 */
		if (dx == dy && dy == 0) {
		    gc->line.options.length = 0;
		    return;
		}
		gc->line.options.xBig = -1;
		goto negymajor;
	    }
	}
    }
}

#ifdef NT
void FASTCALL __glRenderAntiAliasLine(__GLcontext *gc, __GLvertex *v0, __GLvertex *v1, GLuint flags)
#else
void FASTCALL __glRenderAntiAliasLine(__GLcontext *gc, __GLvertex *v0, __GLvertex *v1)
#endif
{
    __GLlineState *ls = &gc->state.line;
    __GLfloat invDelta;
    __GLfloat winv;
    __GLcolor *cp;
    __GLfloat offset;
    GLint lineRep;
    GLint x, y, xBig, xLittle, yBig, yLittle;
    GLint fraction, dfraction;
    __GLfloat dlLittle, dlBig;
    __GLfloat ddLittle, ddBig;
    __GLfloat length, width;
    __GLfloat lineLength;
    __GLfloat dx, dy;
    GLuint modeFlags = gc->polygon.shader.modeFlags;

    __glInitAALineData(gc, v0, v1);
    if (gc->line.options.length == 0) return;

    offset = gc->line.options.offset;

    /*
    ** Set up increments for any enabled line options.
    */
    invDelta = __glOne / gc->line.options.length;
    if (modeFlags & __GL_SHADE_DEPTH_ITER) {
        /*
        ** Calculate window z coordinate increment and starting position.
        */
#ifdef NT
        if(( gc->modes.depthBits == 16 ) &&
           ( gc->depthBuffer.scale <= (GLuint)0xffff )) {
            gc->polygon.shader.dzdx = (GLint)((v1->window.z - v0->window.z) * 
                                              invDelta * Z16_SCALE);
            gc->polygon.shader.frag.z = (GLint)(Z16_SCALE*v0->window.z + 
                                                gc->polygon.shader.dzdx * offset);
        }
        else {
            gc->polygon.shader.dzdx = (GLint)((v1->window.z - v0->window.z) * 
                                              invDelta);
            gc->polygon.shader.frag.z = (GLint)(v0->window.z + 
                                                gc->polygon.shader.dzdx * offset);
        }
#else
        gc->polygon.shader.dzdx = (GLint)((v1->window.z - v0->window.z) * 
                                          invDelta);
        gc->polygon.shader.frag.z = (GLint)(v0->window.z + 
                                            gc->polygon.shader.dzdx * offset);
#endif
    } 

    if (modeFlags & __GL_SHADE_LINE_STIPPLE) {
        if (!gc->line.notResetStipple) {
            gc->line.stipplePosition = 0;
            gc->line.repeat = 0;
            gc->line.notResetStipple = GL_TRUE;
        }
    }

    if (modeFlags & __GL_SHADE_COMPUTE_FOG)
    {
        __GLfloat f1, f0;
        __GLfloat dfdx;

        f0 = v0->eyeZ;
        f1 = v1->eyeZ;
        gc->line.options.f0 = f0;
        gc->polygon.shader.dfdx = dfdx = (f1 - f0) * invDelta;
        gc->polygon.shader.frag.f = f0 + dfdx * offset;
    }
    else if (modeFlags & __GL_SHADE_INTERP_FOG)
    {
        __GLfloat f1, f0;
        __GLfloat dfdx;

        f0 = v0->fog;
        f1 = v1->fog;
        gc->line.options.f0 = f0;
        gc->polygon.shader.dfdx = dfdx = (f1 - f0) * invDelta;
        gc->polygon.shader.frag.f = f0 + dfdx * offset;
    }

    if ((modeFlags & __GL_SHADE_SMOOTH) 
#ifdef GL_WIN_phong_shading
        || ((modeFlags & __GL_SHADE_PHONG) &&
            (gc->polygon.shader.phong.flags & __GL_PHONG_NEED_COLOR_XPOLATE))
#endif //GL_WIN_phong_shading
        ) 
    {
        __GLcolor *c0 = v0->color;
        __GLcolor *c1 = v1->color;

        /*
        ** Calculate red, green, blue and alpha value increments.
        */
        gc->polygon.shader.drdx = (c1->r - c0->r) * invDelta;
        if (gc->modes.rgbMode) {
            gc->polygon.shader.dgdx = (c1->g - c0->g) * invDelta;
            gc->polygon.shader.dbdx = (c1->b - c0->b) * invDelta;
            gc->polygon.shader.dadx = (c1->a - c0->a) * invDelta;
        }
        cp = v0->color;
    } else {
        cp = v1->color;

        // Initialize these values to zero even for the flat case
        // because there is an optimization in so_prim which will
        // turn off smooth shading without repicking, so these need
        // to be valid
        gc->polygon.shader.drdx = __glZero;
        gc->polygon.shader.dgdx = __glZero;
        gc->polygon.shader.dbdx = __glZero;
        gc->polygon.shader.dadx = __glZero;
    }

    gc->polygon.shader.frag.color.r = cp->r;
    if (gc->modes.rgbMode) {
        gc->polygon.shader.frag.color.g = cp->g;
        gc->polygon.shader.frag.color.b = cp->b;
        gc->polygon.shader.frag.color.a = cp->a;
    }

    if (gc->texture.textureEnabled) {
        __GLfloat v0QW, v1QW;
        __GLfloat dS, dT;

        /*
        ** Calculate texture s and t value increments.
        */
        v0QW = v0->texture.w * v0->window.w;
        v1QW = v1->texture.w * v1->window.w;
        dS = (v1->texture.x * v1QW - v0->texture.x * v0QW) * invDelta;
        dT = (v1->texture.y * v1QW - v0->texture.y * v0QW) * invDelta;
        gc->polygon.shader.dsdx = dS;
        gc->polygon.shader.dtdx = dT;
        gc->polygon.shader.dqwdx = (v1QW - v0QW) * invDelta;
        
        winv = v0->window.w;
        gc->polygon.shader.frag.s = v0->texture.x * winv + 
          gc->polygon.shader.dsdx * offset;
        gc->polygon.shader.frag.t = v0->texture.y * winv + 
          gc->polygon.shader.dtdx * offset;
        gc->polygon.shader.frag.qw = v0->texture.w * winv + 
          gc->polygon.shader.dqwdx * offset;
    } 

    lineRep = gc->line.options.width;
    
    fraction = gc->line.options.fraction;
    dfraction = gc->line.options.dfraction;
    
    x = gc->line.options.xStart;
    y = gc->line.options.yStart;
    xBig = gc->line.options.xBig;
    yBig = gc->line.options.yBig;
    xLittle = gc->line.options.xLittle;
    yLittle = gc->line.options.yLittle;
    
    dlLittle = gc->line.options.dlLittle;
    dlBig = gc->line.options.dlBig;
    ddLittle = gc->line.options.ddLittle;
    ddBig = gc->line.options.ddBig;
    
    dx = x + __glHalf - v0->window.x;
    dy = y + __glHalf - v0->window.y;
    length = dx * gc->line.options.dldx +
      dy * gc->line.options.dldy;
    width = dx * gc->line.options.dddx +
      dy * gc->line.options.dddy;
    lineLength = gc->line.options.realLength + __glHalf;
    
    if (modeFlags & __GL_SHADE_LINE_STIPPLE) {
        gc->line.options.stippleOffset = 
          gc->line.stipplePosition * gc->state.line.stippleRepeat +
          gc->line.repeat - __glHalf;
        
        /* XXX Move to a validation routine? */
        gc->line.options.oneOverStippleRepeat = 
          __glOne / gc->state.line.stippleRepeat;
    }
    
    while (--lineRep >= 0) {
        /* Trace the line backwards as needed */
        while (length > -__glHalf) {
            fraction -= dfraction;
            if (fraction < 0) {
                fraction &= ~0x80000000;
                length -= dlBig;
                width -= ddBig;
                x -= xBig;
                y -= yBig;
            } else {
                length -= dlLittle;
                width -= ddLittle;
                x -= xLittle;
                y -= yLittle;
            }
        }

        /* Trace line forwards to correct */
        while (length <= -__glHalf) {
            fraction += dfraction;
            if (fraction < 0) {
                fraction &= ~0x80000000;
                length += dlBig;
                width += ddBig;
                x += xBig;
                y += yBig;
            } else {
                length += dlLittle;
                width += ddLittle;
                x += xLittle;
                y += yLittle;
            }
        }
        
#ifdef GL_WIN_phong_shading
    if (modeFlags & __GL_SHADE_PHONG) 
        (*gc->procs.phong.InitLineParams) (gc, v0, v1, invDelta);
#endif //GL_WIN_phong_shading
    
        /* Save new fraction/dfraction */
        gc->line.options.plength = length;
        gc->line.options.pwidth = width;
        gc->line.options.fraction = fraction;
        gc->line.options.dfraction = dfraction;
        gc->line.options.xStart = x;
        gc->line.options.yStart = y;
        
        gc->polygon.shader.length = gc->line.options.numPixels;
        (*gc->procs.line.processLine)(gc);
        
        if (gc->line.options.axis == __GL_X_MAJOR) {
            y++;
            length += gc->line.options.dldy;
            width += gc->line.options.dddy;
        } else {
            x++;
            length += gc->line.options.dldx;
            width += gc->line.options.dddx;
        }
    }
    
    if (modeFlags & __GL_SHADE_LINE_STIPPLE) {
        /* Update stipple.  Ugh. */
        int increase;
        int posInc;

        /* Shift stipple by 'increase' bits */
        increase = (GLint)__GL_FAST_CEILF(gc->line.options.realLength);
        
        posInc = increase / gc->state.line.stippleRepeat;
        
        gc->line.stipplePosition = (gc->line.stipplePosition + posInc) & 0xf;
        gc->line.repeat = (gc->line.repeat + increase) % gc->state.line.stippleRepeat;
    }
}

#ifdef NT
void FASTCALL __glNopLineBegin(__GLcontext *gc)
{
}

void FASTCALL __glNopLineEnd(__GLcontext *gc)
{
}
#endif // NT