static void crPackLockClientPointer(GLint first, GLint count, unsigned char **ppData, int index, CRClientState *c)
{
    CRClientPointer *cp;
    unsigned char *data_ptr = *ppData, *cptr;
    GLint i;

    cp = crStateGetClientPointerByIndex(index, &c->array);

    if (cp->enabled)
    {
        if (cp->buffer && cp->buffer->id)
        {
            crWarning("crPackLockClientPointer called when there's VBO enabled!");
        }

        WRITE_DATA_AI(int, index);
        cptr = cp->p + first*cp->stride;
        if (cp->bytesPerIndex==cp->stride)
        {
            crMemcpy(data_ptr, cptr, count*cp->bytesPerIndex);
            data_ptr += count*cp->bytesPerIndex;
        }
        else
        {
            for (i=0; i<count; ++i)
            {
                crMemcpy(data_ptr, cptr, cp->bytesPerIndex);
                data_ptr += cp->bytesPerIndex;
                cptr += cp->stride;
            }
        }
        *ppData = data_ptr;
    }
}
void crUnpackExtendLockArraysEXT(void)
{
    GLint first    = READ_DATA(sizeof(int) + 4, GLint);
    GLint count    = READ_DATA(sizeof(int) + 8, GLint);
    int numenabled = READ_DATA(sizeof(int) + 12, int);

    CRContext *g = crStateGetCurrent();
    CRClientState *c = &g->client;
    CRClientPointer *cp;
    int i, index, offset;
    unsigned char *data;
    
    offset = 2*sizeof(int)+12;

    /*crDebug("crUnpackExtendLockArraysEXT(%i, %i) ne=%i", first, count, numenabled);*/

    for (i=0; i<numenabled; ++i)
    {
        index = READ_DATA(offset, int);
        offset += sizeof(int);
        cp = crStateGetClientPointerByIndex(index, &c->array);
        CRASSERT(cp && cp->enabled && (!cp->buffer || !cp->buffer->id));
        data = crAlloc((first+count)*cp->bytesPerIndex);
        crMemcpy(data+first*cp->bytesPerIndex, DATA_POINTER(offset, GLvoid), count*cp->bytesPerIndex);
        offset += count*cp->bytesPerIndex;
        /*crDebug("crUnpackExtendLockArraysEXT: old cp(%i): en/l=%i(%i) p=%p size=%i type=0x%x n=%i str=%i pp=%p pstr=%i",
                index, cp->enabled, cp->locked, cp->p, cp->size, cp->type, cp->normalized, cp->stride, cp->prevPtr, cp->prevStride);*/
        crUnpackSetClientPointerByIndex(index, cp->size, cp->type, cp->normalized, 0, data, c);
        /*crDebug("crUnpackExtendLockArraysEXT: new cp(%i): en/l=%i(%i) p=%p size=%i type=0x%x n=%i str=%i pp=%p pstr=%i",
                index, cp->enabled, cp->locked, cp->p, cp->size, cp->type, cp->normalized, cp->stride, cp->prevPtr, cp->prevStride);*/
    }
    cr_unpackDispatch.LockArraysEXT(first, count);
}
void crUnpackExtendUnlockArraysEXT(void)
{
    int i;
    CRContext *g = crStateGetCurrent();
    CRClientState *c = &g->client;
    CRClientPointer *cp;

    /*crDebug("crUnpackExtendUnlockArraysEXT");*/

    cr_unpackDispatch.UnlockArraysEXT();

    for (i=0; i<CRSTATECLIENT_MAX_VERTEXARRAYS; ++i)
    {
        cp = crStateGetClientPointerByIndex(i, &c->array);
        if (cp->enabled)
        {
            /*crDebug("crUnpackExtendUnlockArraysEXT: old cp(%i): en/l=%i(%i) p=%p size=%i type=0x%x n=%i str=%i pp=%p pstr=%i",
                    i, cp->enabled, cp->locked, cp->p, cp->size, cp->type, cp->normalized, cp->stride, cp->prevPtr, cp->prevStride);*/
            crUnpackSetClientPointerByIndex(i, cp->size, cp->type, cp->normalized, cp->prevStride, cp->prevPtr, c);
            /*crDebug("crUnpackExtendUnlockArraysEXT: new cp(%i): en/l=%i(%i) p=%p size=%i type=0x%x n=%i str=%i pp=%p pstr=%i",
                    i, cp->enabled, cp->locked, cp->p, cp->size, cp->type, cp->normalized, cp->stride, cp->prevPtr, cp->prevStride);*/
        }
    }
}
static void ctStateBuffersRefsCleanup(CRContext *ctx, CRBufferObject *obj, CRbitvalue *neg_bitid)
{
    CRBufferObjectState *b = &(ctx->bufferobject);
    CRStateBits *sb = GetCurrentBits();
    CRBufferObjectBits *bb = &(sb->bufferobject);
    int j, k;

    if (obj == b->arrayBuffer)
    {
        b->arrayBuffer = b->nullBuffer;
        b->arrayBuffer->refCount++;
        DIRTY(bb->dirty, neg_bitid);
        DIRTY(bb->arrayBinding, neg_bitid);
    }
    if (obj == b->elementsBuffer)
    {
        b->elementsBuffer = b->nullBuffer;
        b->elementsBuffer->refCount++;
        DIRTY(bb->dirty, neg_bitid);
        DIRTY(bb->elementsBinding, neg_bitid);
    }
#ifdef CR_ARB_pixel_buffer_object
    if (obj == b->packBuffer)
    {
        b->packBuffer = b->nullBuffer;
        b->packBuffer->refCount++;
        DIRTY(bb->dirty, neg_bitid);
        DIRTY(bb->packBinding, neg_bitid);
    }
    if (obj == b->unpackBuffer)
    {
        b->unpackBuffer = b->nullBuffer;
        b->unpackBuffer->refCount++;
        DIRTY(bb->dirty, neg_bitid);
        DIRTY(bb->unpackBinding, neg_bitid);
    }
#endif

#ifdef CR_ARB_vertex_buffer_object
    for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
    {
        CRClientPointer *cp = crStateGetClientPointerByIndex(j, &ctx->client.array);
        if (obj == cp->buffer)
        {
            cp->buffer = b->nullBuffer;
            ++b->nullBuffer->refCount;
        }
    }

    for (k=0; k<ctx->client.vertexArrayStackDepth; ++k)
    {
        CRVertexArrays *pArray = &ctx->client.vertexArrayStack[k];
        for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
        {
            CRClientPointer *cp = crStateGetClientPointerByIndex(j, pArray);
            if (obj == cp->buffer)
            {
                cp->buffer = b->nullBuffer;
                ++b->nullBuffer->refCount;
            }
        }
    }
#endif

    CR_STATE_SHAREDOBJ_USAGE_CLEAR(obj, ctx);
}