void SERVER_DISPATCH_APIENTRY
crServerDispatchBindProgramNV(GLenum target, GLuint id)
{
    if (target == GL_VERTEX_PROGRAM_NV) {
        CRServerProgram *prog = LookupProgram(id);
        (void) prog;
        cr_server.currentProgram = id;
    }
    /* pass through */
    crStateBindProgramNV(&cr_server.StateTracker, target, id);
    cr_server.head_spu->dispatch_table.BindProgramNV(target, id);
}
void SERVER_DISPATCH_APIENTRY
crServerDispatchBindProgramARB(GLenum target, GLuint id)
{
    id = crServerTranslateProgramID(id);

    if (target == GL_VERTEX_PROGRAM_ARB) {
        CRServerProgram *prog = LookupProgram(id);
        (void) prog;
        cr_server.currentProgram = id;
    }

    /* pass through */
    crStateBindProgramARB(target, id);
    cr_server.head_spu->dispatch_table.BindProgramARB(target, id);
}
void SERVER_DISPATCH_APIENTRY
crServerDispatchProgramParameter4fNV(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
#if 0
    if (target == GL_VERTEX_PROGRAM_NV) {
        CRServerProgram *prog = LookupProgram(cr_server.currentProgram);

        if (prog && prog->projParamStart != -1) {
            if (index >= (GLuint) prog->projParamStart && index <= (GLuint) prog->projParamStart + 3) {
                /* save the parameters as rows in the matrix */
                const int i = index - prog->projParamStart;
                prog->projMat[4*0+i] = x;
                prog->projMat[4*1+i] = y;
                prog->projMat[4*2+i] = z;
                prog->projMat[4*3+i] = w;
            }

            /* When we get the 4th row (row==3) of the projection matrix we can
             * then pre-multiply it by the base matrix and update the program
             * parameters with the new matrix.
             */
            if (index == (GLuint) (prog->projParamStart + 3)) {
                const CRMuralInfo *mural = cr_server.curClient->currentMural;
                const GLfloat *baseMat = (const GLfloat *) &(mural->extents[mural->curExtent].baseProjection);
                int i;
                GLfloat mat[16];

                /* pre-mult the projection matrix by the base projection */
                matmul(mat, baseMat, prog->projMat);
                /* update the program parameters with the new matrix */
                for (i = 0; i < 4; i++) {
                    cr_server.head_spu->dispatch_table.ProgramParameter4fNV(target, index + i - 3, mat[4*0+i], mat[4*1+i], mat[4*2+i], mat[4*3+i]);
                }
                return; /* done */
            }
        }
    }
#endif

    /* if we get here, pass the call through unchanged */
    cr_server.head_spu->dispatch_table.ProgramParameter4fNV(target, index, x, y, z, w);
}
void SERVER_DISPATCH_APIENTRY
crServerDispatchLoadProgramNV(GLenum target, GLuint id, GLsizei len, const GLubyte *string)
{
    if (target == GL_VERTEX_PROGRAM_NV &&
            cr_server.vpProjectionMatrixVariable != NULL) {
        /* scan the program string looking for 'vertprog_projection'
         * If the program was generated by Cg, the info we want will look
         * something like this:
         * #var float4x4 ModelViewProj :  : c[0], 4 : 1 : 1
         */
        CRServerProgram *prog = LookupProgram(id);
        CRASSERT(prog);
        if (prog) {
            const char *varPos, *paramPos;
            varPos = crStrstr((const char *) string, cr_server.vpProjectionMatrixVariable);
            if (varPos) {
                 paramPos = crStrstr(varPos, "c[");
                 if (paramPos) {
                        char number[10];
                        int i = 0;
                        paramPos += 2;  /* skip "c[" */
                        while (crIsDigit(paramPos[i])) {
                             number[i] = paramPos[i];
                             i++;
                        }
                        number[i] = 0;
                        prog->projParamStart = crStrToInt(number);
                 }
            }
            else {
                 crWarning("Didn't find %s parameter in vertex program string",
                                     cr_server.vpProjectionMatrixVariable);
            }
        }
    }

    /* pass through */
    crStateLoadProgramNV(&cr_server.StateTracker, target, id, len, string);
    cr_server.head_spu->dispatch_table.LoadProgramNV(target, id, len, string);
}