/* Copyright (c) 2001, Stanford University
 * All rights reserved
 *
 * See the file LICENSE.txt for information on redistributing this software.
 */

#include <stdio.h>
#include "state.h"
#include "state/cr_statetypes.h"
#include "state_internals.h"

void crStateBufferInit (CRContext *ctx)
{
    CRBufferState *b = &ctx->buffer;
    CRStateBits *sb          = GetCurrentBits();
    CRBufferBits *bb = &(sb->buffer);
    GLcolorf zero_colorf = {0.0f, 0.0f, 0.0f, 0.0f};

    b->width = 640;
    b->height = 480;
    b->storedWidth = 0;
    b->storedHeight = 0;
    b->pFrontImg = NULL;
    b->pBackImg = NULL;

    b->depthTest = GL_FALSE;
    b->blend     = GL_FALSE;
    b->alphaTest = GL_FALSE;
    b->dither    = GL_TRUE;
    RESET(bb->enable, ctx->bitid);

    b->logicOp   = GL_FALSE;
    RESET(bb->logicOp, ctx->bitid);
    b->indexLogicOp   = GL_FALSE;
    RESET(bb->indexLogicOp, ctx->bitid);
    b->depthMask = GL_TRUE;
    RESET(bb->depthMask, ctx->bitid);

    b->alphaTestFunc = GL_ALWAYS;
    b->alphaTestRef = 0;
    RESET(bb->alphaFunc, ctx->bitid);
    b->depthFunc = GL_LESS;
    RESET(bb->depthFunc, ctx->bitid);
    b->blendSrcRGB = GL_ONE;
    b->blendDstRGB = GL_ZERO;
    RESET(bb->blendFunc, ctx->bitid);
#ifdef CR_EXT_blend_func_separate
    b->blendSrcA = GL_ONE;
    b->blendDstA = GL_ZERO;
    RESET(bb->blendFuncSeparate, ctx->bitid);
#endif
    b->logicOpMode = GL_COPY;
    b->drawBuffer = GL_BACK;
    RESET(bb->drawBuffer, ctx->bitid);
    b->readBuffer = GL_BACK;
    RESET(bb->readBuffer, ctx->bitid);
    b->indexWriteMask = 0xffffffff;
    RESET(bb->indexMask, ctx->bitid);
    b->colorWriteMask.r = GL_TRUE;
    b->colorWriteMask.g = GL_TRUE;
    b->colorWriteMask.b = GL_TRUE;
    b->colorWriteMask.a = GL_TRUE;
    RESET(bb->colorWriteMask, ctx->bitid);
    b->colorClearValue = zero_colorf;
    RESET(bb->clearColor, ctx->bitid);
    b->indexClearValue = 0;
    RESET(bb->clearIndex, ctx->bitid);
    b->depthClearValue = (GLdefault) 1.0;
    RESET(bb->clearDepth, ctx->bitid);
    b->accumClearValue = zero_colorf;
    RESET(bb->clearAccum, ctx->bitid);

#ifdef CR_EXT_blend_color
    b->blendColor = zero_colorf;
    RESET(bb->blendColor, ctx->bitid);
#endif
#if defined(CR_EXT_blend_minmax) || defined(CR_EXT_blend_subtract) || defined(CR_EXT_blend_logic_op)
    b->blendEquation = GL_FUNC_ADD_EXT;
    RESET(bb->blendEquation, ctx->bitid);
#endif

    RESET(bb->dirty, ctx->bitid);
}

void STATE_APIENTRY crStateAlphaFunc (GLenum func, GLclampf ref) 
{
    CRContext *g             = GetCurrentContext();
    CRBufferState *b         = &(g->buffer);
    CRStateBits *sb          = GetCurrentBits();
    CRBufferBits *bb = &(sb->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glAlphaFunc called in begin/end");
        return;
    }

    FLUSH();

    switch (func) 
    {
        case GL_NEVER:
        case GL_LESS:
        case GL_EQUAL:
        case GL_LEQUAL:
        case GL_GREATER:
        case GL_GEQUAL:
        case GL_NOTEQUAL:
        case GL_ALWAYS:
            break;
        default:
            crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glAlphaFunc:  Invalid func: %d", func);
            return;
    }

    if (ref < 0.0f) ref = 0.0f;
    if (ref > 1.0f) ref = 1.0f;

    b->alphaTestFunc = func;
    b->alphaTestRef = ref;
    DIRTY(bb->dirty, g->neg_bitid);
    DIRTY(bb->alphaFunc, g->neg_bitid);
}

void STATE_APIENTRY crStateDepthFunc (GLenum func) 
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sb = GetCurrentBits();
    CRBufferBits *bb = &(sb->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glDepthFunc called in begin/end");
        return;
    }

    FLUSH();

    switch (func) 
    {
        case GL_NEVER:
        case GL_LESS:
        case GL_EQUAL:
        case GL_LEQUAL:
        case GL_GREATER:
        case GL_NOTEQUAL:
        case GL_GEQUAL:
        case GL_ALWAYS:
            break;
        default:
            crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glDepthFunc:  Invalid func: %d", func);
            return;
    }


    b->depthFunc = func;
    DIRTY(bb->dirty, g->neg_bitid);
    DIRTY(bb->depthFunc, g->neg_bitid);
}

void STATE_APIENTRY crStateBlendFunc (GLenum sfactor, GLenum dfactor) 
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sb = GetCurrentBits();
    CRBufferBits *bb = &(sb->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glBlendFunc called in begin/end");
        return;
    }

    FLUSH();

    switch (sfactor) 
    {
        case GL_ZERO:
        case GL_ONE:
        case GL_DST_COLOR:
        case GL_ONE_MINUS_DST_COLOR:
        case GL_SRC_ALPHA:
        case GL_ONE_MINUS_SRC_ALPHA:
        case GL_DST_ALPHA:
        case GL_ONE_MINUS_DST_ALPHA:
        case GL_SRC_ALPHA_SATURATE:
            break; /* OK */
#ifdef CR_EXT_blend_color
        case GL_CONSTANT_COLOR_EXT:
        case GL_ONE_MINUS_CONSTANT_COLOR_EXT:
        case GL_CONSTANT_ALPHA_EXT:
        case GL_ONE_MINUS_CONSTANT_ALPHA_EXT:
            if (g->extensions.EXT_blend_color)
                break; /* OK */
#endif
        default:
            crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "Invalid sfactor passed to glBlendFunc: %d", sfactor);
            return;
    }

    switch (dfactor) 
    {
        case GL_ZERO:
        case GL_ONE:
        case GL_SRC_COLOR:
        case GL_ONE_MINUS_SRC_COLOR:
        case GL_SRC_ALPHA:
        case GL_ONE_MINUS_SRC_ALPHA:
        case GL_DST_ALPHA:
        case GL_ONE_MINUS_DST_ALPHA:
            break; /* OK */
#ifdef CR_EXT_blend_color
        case GL_CONSTANT_COLOR_EXT:
        case GL_ONE_MINUS_CONSTANT_COLOR_EXT:
        case GL_CONSTANT_ALPHA_EXT:
        case GL_ONE_MINUS_CONSTANT_ALPHA_EXT:
            if (g->extensions.EXT_blend_color)
                break; /* OK */
#endif
        default:
            crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "Invalid dfactor passed to glBlendFunc: %d", dfactor);
            return;
    }

    b->blendSrcRGB = sfactor;
    b->blendDstRGB = dfactor;
    b->blendSrcA = sfactor;
    b->blendDstA = dfactor;
    DIRTY(bb->dirty, g->neg_bitid);
    DIRTY(bb->blendFunc, g->neg_bitid);
}

void STATE_APIENTRY crStateBlendColorEXT( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sb = GetCurrentBits();
    CRBufferBits *bb = &(sb->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError( __LINE__, __FILE__, GL_INVALID_OPERATION, "BlendColorEXT called inside a Begin/End" );
        return;
    }

    b->blendColor.r = red;
    b->blendColor.g = green;
    b->blendColor.b = blue;
    b->blendColor.a = alpha;
    DIRTY(bb->blendColor, g->neg_bitid);
    DIRTY(bb->dirty, g->neg_bitid);
}

#ifdef CR_EXT_blend_func_separate
void STATE_APIENTRY crStateBlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorA, GLenum dfactorA )
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sb = GetCurrentBits();
    CRBufferBits *bb = &(sb->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError( __LINE__, __FILE__, GL_INVALID_OPERATION, "BlendFuncSeparateEXT called inside a Begin/End" );
        return;
    }

    FLUSH();

    switch (sfactorRGB) 
    {
        case GL_ZERO:
        case GL_ONE:
        case GL_DST_COLOR:
        case GL_ONE_MINUS_DST_COLOR:
        case GL_SRC_ALPHA:
        case GL_ONE_MINUS_SRC_ALPHA:
        case GL_DST_ALPHA:
        case GL_ONE_MINUS_DST_ALPHA:
        case GL_SRC_ALPHA_SATURATE:
            break; /* OK */
#ifdef CR_EXT_blend_color
        case GL_CONSTANT_COLOR_EXT:
        case GL_ONE_MINUS_CONSTANT_COLOR_EXT:
        case GL_CONSTANT_ALPHA_EXT:
        case GL_ONE_MINUS_CONSTANT_ALPHA_EXT:
            if (g->extensions.EXT_blend_color)
                break; /* OK */
#endif
        default:
            crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "Invalid sfactorRGB passed to glBlendFuncSeparateEXT: %d", sfactorRGB);
            return;
    }

    switch (sfactorA) 
    {
        case GL_ZERO:
        case GL_ONE:
        case GL_DST_COLOR:
        case GL_ONE_MINUS_DST_COLOR:
        case GL_SRC_ALPHA:
        case GL_ONE_MINUS_SRC_ALPHA:
        case GL_DST_ALPHA:
        case GL_ONE_MINUS_DST_ALPHA:
        case GL_SRC_ALPHA_SATURATE:
            break; /* OK */
#ifdef CR_EXT_blend_color
        case GL_CONSTANT_COLOR_EXT:
        case GL_ONE_MINUS_CONSTANT_COLOR_EXT:
        case GL_CONSTANT_ALPHA_EXT:
        case GL_ONE_MINUS_CONSTANT_ALPHA_EXT:
            if (g->extensions.EXT_blend_color)
                break; /* OK */
#endif
        default:
            crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "Invalid sfactorA passed to glBlendFuncSeparateEXT: %d", sfactorA);
            return;
    }

    switch (dfactorRGB) 
    {
        case GL_ZERO:
        case GL_ONE:
        case GL_SRC_COLOR:
        case GL_DST_COLOR:
        case GL_ONE_MINUS_DST_COLOR:
        case GL_ONE_MINUS_SRC_COLOR:
        case GL_SRC_ALPHA:
        case GL_ONE_MINUS_SRC_ALPHA:
        case GL_DST_ALPHA:
        case GL_ONE_MINUS_DST_ALPHA:
        case GL_SRC_ALPHA_SATURATE:
            break; /* OK */
#ifdef CR_EXT_blend_color
        case GL_CONSTANT_COLOR_EXT:
        case GL_ONE_MINUS_CONSTANT_COLOR_EXT:
        case GL_CONSTANT_ALPHA_EXT:
        case GL_ONE_MINUS_CONSTANT_ALPHA_EXT:
            if (g->extensions.EXT_blend_color)
                break; /* OK */
#endif
        default:
            crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "Invalid dfactorRGB passed to glBlendFuncSeparateEXT: %d", dfactorRGB);
            return;
    }

    switch (dfactorA) 
    {
        case GL_ZERO:
        case GL_ONE:
        case GL_DST_COLOR:
        case GL_SRC_COLOR:
        case GL_ONE_MINUS_SRC_COLOR:
        case GL_ONE_MINUS_DST_COLOR:
        case GL_SRC_ALPHA:
        case GL_ONE_MINUS_SRC_ALPHA:
        case GL_DST_ALPHA:
        case GL_ONE_MINUS_DST_ALPHA:
        case GL_SRC_ALPHA_SATURATE:
            break; /* OK */
#ifdef CR_EXT_blend_color
        case GL_CONSTANT_COLOR_EXT:
        case GL_ONE_MINUS_CONSTANT_COLOR_EXT:
        case GL_CONSTANT_ALPHA_EXT:
        case GL_ONE_MINUS_CONSTANT_ALPHA_EXT:
            if (g->extensions.EXT_blend_color)
                break; /* OK */
#endif
        default:
            crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "Invalid dfactorA passed to glBlendFuncSeparateEXT: %d", dfactorA);
            return;
    }

    b->blendSrcRGB = sfactorRGB;
    b->blendDstRGB = dfactorRGB;
    b->blendSrcA = sfactorA;
    b->blendDstA = dfactorA;
    DIRTY(bb->dirty, g->neg_bitid);
    DIRTY(bb->blendFuncSeparate, g->neg_bitid);
}
#endif

void STATE_APIENTRY crStateBlendEquationEXT( GLenum mode )
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sb = GetCurrentBits();
    CRBufferBits *bb = &(sb->buffer);

    if( g->current.inBeginEnd )
    {
        crStateError( __LINE__, __FILE__, GL_INVALID_OPERATION, "BlendEquationEXT called inside a Begin/End" );
        return;
    }
    switch( mode )
    {
#if defined(CR_EXT_blend_minmax) || defined(CR_EXT_blend_subtract) || defined(CR_EXT_blend_logic_op)
        case GL_FUNC_ADD_EXT:
#ifdef CR_EXT_blend_subtract
        case GL_FUNC_SUBTRACT_EXT:
        case GL_FUNC_REVERSE_SUBTRACT_EXT:
#endif /* CR_EXT_blend_subtract */
#ifdef CR_EXT_blend_minmax
        case GL_MIN_EXT:
        case GL_MAX_EXT:
#endif /* CR_EXT_blend_minmax */
#ifdef CR_EXT_blend_logic_op
        case GL_LOGIC_OP:
#endif /* CR_EXT_blend_logic_op */
            b->blendEquation = mode;
            break;
#endif /* defined(CR_EXT_blend_minmax) || defined(CR_EXT_blend_subtract) || defined(CR_EXT_blend_logic_op) */
        default:
            crStateError( __LINE__, __FILE__, GL_INVALID_ENUM,
                "BlendEquationEXT: mode called with illegal parameter: 0x%x", (GLenum) mode );
            return;
    }
    DIRTY(bb->blendEquation, g->neg_bitid);
    DIRTY(bb->dirty, g->neg_bitid);
}

void STATE_APIENTRY crStateLogicOp (GLenum opcode) 
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sb = GetCurrentBits();
    CRBufferBits *bb = &(sb->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glLogicOp called in begin/end");
        return;
    }

    FLUSH();

    switch (opcode) 
    {
        case GL_CLEAR:
        case GL_SET:
        case GL_COPY:
        case GL_COPY_INVERTED:
        case GL_NOOP:
        case GL_INVERT:
        case GL_AND:
        case GL_NAND:
        case GL_OR:
        case GL_NOR:
        case GL_XOR:
        case GL_EQUIV:
        case GL_AND_REVERSE:
        case GL_AND_INVERTED:
        case GL_OR_REVERSE:
        case GL_OR_INVERTED:
            break;
        default:
            crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glLogicOp called with bogus opcode: %d", opcode);
            return;
    }

    b->logicOpMode = opcode;
    DIRTY(bb->dirty, g->neg_bitid);
    DIRTY(bb->logicOp, g->neg_bitid);
    DIRTY(bb->indexLogicOp, g->neg_bitid);
}

void STATE_APIENTRY crStateDrawBuffer (GLenum mode) 
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sb = GetCurrentBits();
    CRBufferBits *bb = &(sb->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glDrawBuffer called in begin/end");
        return;
    }

    FLUSH();

    switch (mode) 
    {
        case GL_NONE:
            break;
        case GL_FRONT_LEFT:
        case GL_FRONT_RIGHT:
        case GL_BACK_LEFT:
        case GL_BACK_RIGHT:
        case GL_FRONT:
        case GL_BACK:
        case GL_LEFT:
        case GL_RIGHT:
        case GL_FRONT_AND_BACK:
        case GL_AUX0:
        case GL_AUX1:
        case GL_AUX2:
        case GL_AUX3:
            if (g->framebufferobject.drawFB)
            {
                crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glDrawBuffer invalid mode while fbo is active");
                return;
            }
            break;
        default:
            if (mode>=GL_COLOR_ATTACHMENT0_EXT && mode<=GL_COLOR_ATTACHMENT15_EXT)
            {
                if (!g->framebufferobject.drawFB)
                {
                    crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glDrawBuffer invalid mode while fbo is inactive");
                    return;
                }
            }
            else
            {
                crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glDrawBuffer called with bogus mode: %d", mode);
                return;
            }
    }

    if (g->framebufferobject.drawFB)
    {
        g->framebufferobject.drawFB->drawbuffer[0] = mode;
    }
    else
    {
        b->drawBuffer = mode;
        DIRTY(bb->dirty, g->neg_bitid);
        DIRTY(bb->drawBuffer, g->neg_bitid);
    }
}

void STATE_APIENTRY crStateReadBuffer (GLenum mode) 
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sb = GetCurrentBits();
    CRBufferBits *bb = &(sb->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glReadBuffer called in begin/end");
        return;
    }

    FLUSH();

    switch (mode) 
    {
        case GL_NONE:
            break;
        case GL_FRONT_LEFT:
        case GL_FRONT_RIGHT:
        case GL_BACK_LEFT:
        case GL_BACK_RIGHT:
        case GL_FRONT:
        case GL_BACK:
        case GL_LEFT:
        case GL_RIGHT:
        case GL_FRONT_AND_BACK:
        case GL_AUX0:
        case GL_AUX1:
        case GL_AUX2:
        case GL_AUX3:
            if (g->framebufferobject.readFB)
            {
                crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glReadBuffer invalid mode while fbo is active");
                return;
            }
            break;
        default:
            if (mode>=GL_COLOR_ATTACHMENT0_EXT && mode<=GL_COLOR_ATTACHMENT15_EXT)
            {
                if (!g->framebufferobject.readFB)
                {
                    crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glReadBuffer invalid mode while fbo is inactive");
                    return;
                }
                else
                {
                    /*@todo, check if fbo binding is complete*/
                }
            }
            else
            {
                crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glReadBuffer called with bogus mode: %d", mode);
                return;
            }
    }

    if (g->framebufferobject.readFB)
    {
        g->framebufferobject.readFB->readbuffer = mode;
    }
    else
    {
        b->readBuffer = mode;
        DIRTY(bb->dirty, g->neg_bitid);
        DIRTY(bb->readBuffer, g->neg_bitid);
    }
}

void STATE_APIENTRY crStateIndexMask (GLuint mask) 
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sp = GetCurrentBits();
    CRBufferBits *bb = &(sp->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glReadBuffer called in begin/end");
        return;
    }

    FLUSH();

    b->indexWriteMask = mask;
    DIRTY(bb->dirty, g->neg_bitid);
    DIRTY(bb->indexMask, g->neg_bitid);
}

void STATE_APIENTRY crStateColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) 
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sp = GetCurrentBits();
    CRBufferBits *bb = &(sp->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glReadBuffer called in begin/end");
        return;
    }

    FLUSH();

    b->colorWriteMask.r = red;
    b->colorWriteMask.g = green;
    b->colorWriteMask.b = blue;
    b->colorWriteMask.a = alpha;
    DIRTY(bb->dirty, g->neg_bitid);
    DIRTY(bb->colorWriteMask, g->neg_bitid);
}

void STATE_APIENTRY crStateClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) 
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sp = GetCurrentBits();
    CRBufferBits *bb = &(sp->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glClearColor called in begin/end");
        return;
    }

    FLUSH();

    if (red < 0.0f) red = 0.0f;
    if (red > 1.0f) red = 1.0f;
    if (green < 0.0f) green = 0.0f;
    if (green > 1.0f) green = 1.0f;
    if (blue < 0.0f) blue = 0.0f;
    if (blue > 1.0f) blue = 1.0f;
    if (alpha < 0.0f) alpha = 0.0f;
    if (alpha > 1.0f) alpha = 1.0f;

    b->colorClearValue.r = red;
    b->colorClearValue.g = green;
    b->colorClearValue.b = blue;
    b->colorClearValue.a = alpha;
    DIRTY(bb->dirty, g->neg_bitid);
    DIRTY(bb->clearColor, g->neg_bitid);
}

void STATE_APIENTRY crStateClearIndex (GLfloat c) 
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sp = GetCurrentBits();
    CRBufferBits *bb = &(sp->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glClearIndex called in begin/end");
        return;
    }

    b->indexClearValue = c;
    DIRTY(bb->dirty, g->neg_bitid);
    DIRTY(bb->clearIndex, g->neg_bitid);
}

void STATE_APIENTRY crStateClearDepth (GLclampd depth) 
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sp = GetCurrentBits();
    CRBufferBits *bb = &(sp->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glClearDepth called in begin/end");
        return;
    }

    FLUSH();

    if (depth < 0.0) depth = 0.0;
    if (depth > 1.0) depth = 1.0;

    b->depthClearValue = (GLdefault) depth;
    DIRTY(bb->dirty, g->neg_bitid);
    DIRTY(bb->clearDepth, g->neg_bitid);
}

void STATE_APIENTRY crStateClearAccum (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) 
{
    CRContext *g = GetCurrentContext();
    CRBufferState *b = &(g->buffer);
    CRStateBits *sp = GetCurrentBits();
    CRBufferBits *bb = &(sp->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glClearAccum called in begin/end");
        return;
    }
    
    FLUSH();

    if (red < -1.0f) red = 0.0f;
    if (red > 1.0f) red = 1.0f;
    if (green < -1.0f) green = 0.0f;
    if (green > 1.0f) green = 1.0f;
    if (blue < -1.0f) blue = 0.0f;
    if (blue > 1.0f) blue = 1.0f;
    if (alpha < -1.0f) alpha = 0.0f;
    if (alpha > 1.0f) alpha = 1.0f;

    b->accumClearValue.r = red;
    b->accumClearValue.g = green;
    b->accumClearValue.b = blue;
    b->accumClearValue.a = alpha;
    DIRTY(bb->dirty, g->neg_bitid);
    DIRTY(bb->clearAccum, g->neg_bitid);
}

void STATE_APIENTRY crStateDepthMask (GLboolean b) 
{
    CRContext *g = GetCurrentContext();
    CRBufferState *bs = &(g->buffer);
    CRStateBits *sp = GetCurrentBits();
    CRBufferBits *bb = &(sp->buffer);

    if (g->current.inBeginEnd)
    {
        crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "DepthMask called in begin/end");
        return;
    }

    FLUSH();

    bs->depthMask = b;
    DIRTY(bb->dirty, g->neg_bitid);
    DIRTY(bb->depthMask, g->neg_bitid);
}
