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

#include "cr_mem.h"
#include "state.h"
#include "state/cr_statetypes.h"
#include "state_internals.h"
#include "cr_pixeldata.h"

void crStatePolygonInit(CRContext *ctx)
{
	CRPolygonState *p = &ctx->polygon;
        CRStateBits *sb = GetCurrentBits();
	CRPolygonBits *pb = &(sb->polygon);
	int i;

	p->polygonSmooth = GL_FALSE;
	p->polygonOffsetFill = GL_FALSE;
	p->polygonOffsetLine = GL_FALSE;
	p->polygonOffsetPoint = GL_FALSE;
	p->polygonStipple = GL_FALSE;
	p->cullFace = GL_FALSE;
	RESET(pb->enable, ctx->bitid);

	p->offsetFactor = 0;
	p->offsetUnits = 0;
	RESET(pb->offset, ctx->bitid);

	p->cullFaceMode = GL_BACK;
	p->frontFace = GL_CCW;
	p->frontMode = GL_FILL;
	p->backMode = GL_FILL;
	RESET(pb->mode, ctx->bitid);

	for (i=0; i<32; i++)
		p->stipple[i] = 0xFFFFFFFF;
	RESET(pb->stipple, ctx->bitid);

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

void STATE_APIENTRY crStateCullFace(GLenum mode) 
{
	CRContext *g = GetCurrentContext();
	CRPolygonState *p = &(g->polygon);
        CRStateBits *sb = GetCurrentBits();
	CRPolygonBits *pb = &(sb->polygon);

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

	FLUSH();

	if (mode != GL_FRONT && mode != GL_BACK && mode != GL_FRONT_AND_BACK)
	{
		crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
				"glCullFace called with bogus mode: 0x%x", mode);
		return;
	}

	p->cullFaceMode = mode;
	DIRTY(pb->mode, g->neg_bitid);
	DIRTY(pb->dirty, g->neg_bitid);
}

void STATE_APIENTRY crStateFrontFace (GLenum mode) 
{
	CRContext *g = GetCurrentContext();
	CRPolygonState *p = &(g->polygon);
        CRStateBits *sb = GetCurrentBits();
	CRPolygonBits *pb = &(sb->polygon);

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

	FLUSH();

	if (mode != GL_CW && mode != GL_CCW)
	{
		crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
				"glFrontFace called with bogus mode: 0x%x", mode);
		return;
	}

	p->frontFace = mode;
	DIRTY(pb->mode, g->neg_bitid);
	DIRTY(pb->dirty, g->neg_bitid);
}

void  STATE_APIENTRY crStatePolygonMode (GLenum face, GLenum mode) 
{
	CRContext *g = GetCurrentContext();
	CRPolygonState *p = &(g->polygon);
        CRStateBits *sb = GetCurrentBits();
	CRPolygonBits *pb = &(sb->polygon);

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

	FLUSH();

	if (mode != GL_POINT && mode != GL_LINE && mode != GL_FILL)
	{
		crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
				"glPolygonMode called with bogus mode: 0x%x", mode);
		return;
	}

	switch (face) {
		case GL_FRONT:
			p->frontMode = mode;
			break;
		case GL_FRONT_AND_BACK:
			p->frontMode = mode;
		case GL_BACK:
			p->backMode = mode;
			break;
		default:
			crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
					"glPolygonMode called with bogus face: 0x%x", face);
			return;
	}
	DIRTY(pb->mode, g->neg_bitid);
	DIRTY(pb->dirty, g->neg_bitid);
}

void STATE_APIENTRY crStatePolygonOffset (GLfloat factor, GLfloat units) 
{
	CRContext *g = GetCurrentContext();
	CRPolygonState *p = &(g->polygon);
        CRStateBits *sb = GetCurrentBits();
	CRPolygonBits *pb = &(sb->polygon);

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

	FLUSH();

	p->offsetFactor = factor;
	p->offsetUnits = units;

	DIRTY(pb->offset, g->neg_bitid);
	DIRTY(pb->dirty, g->neg_bitid);
}

void STATE_APIENTRY crStatePolygonStipple (const GLubyte *p) 
{
	CRContext *g = GetCurrentContext();
	CRPolygonState *poly = &(g->polygon);
        CRStateBits *sb = GetCurrentBits();
	CRPolygonBits *pb = &(sb->polygon);

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

	FLUSH();

	if (!p)
	{
		crStateError(__LINE__, __FILE__, GL_NO_ERROR,
				"Void pointer passed to PolygonStipple");
		return;
	}

	crMemcpy((char*)poly->stipple, (char*)p, 128);

	DIRTY(pb->dirty, g->neg_bitid);
	DIRTY(pb->stipple, g->neg_bitid);
}

void STATE_APIENTRY crStateGetPolygonStipple( GLubyte *b )
{
	CRContext *g = GetCurrentContext();
	CRPolygonState *poly = &(g->polygon);

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

	crMemcpy((char*)b, (char*)poly->stipple, 128);
}
