/*
 ** License Applicability. Except to the extent portions of this file are
 ** made subject to an alternative license as permitted in the SGI Free
 ** Software License B, Version 1.1 (the "License"), the contents of this
 ** file are subject only to the provisions of the License. You may not use
 ** this file except in compliance with the License. You may obtain a copy
 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
 ** 
 ** http://oss.sgi.com/projects/FreeB
 ** 
 ** Note that, as provided in the License, the Software is distributed on an
 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
 ** 
 ** Original Code. The Original Code is: OpenGL Sample Implementation,
 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
 ** Copyright in any portions created by third parties is as indicated
 ** elsewhere herein. All Rights Reserved.
 ** 
 ** Additional Notice Provisions: The application programming interfaces
 ** established by SGI in conjunction with the Original Code are The
 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
 ** Window System(R) (Version 1.3), released October 19, 1998. This software
 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
 ** published by SGI, but has not been independently verified as being
 ** compliant with the OpenGL(R) version 1.2.1 Specification.
 **
 ** $Date: 2001/03/17 00:25:40 $ $Revision: 1.1 $
 */
/*
 ** $Header: /home/krh/git/sync/mesa-cvs-repo/Mesa/src/glu/sgi/libnurbs/interface/bezierPatch.cc,v 1.1 2001/03/17 00:25:40 brianp Exp $
 */

#include "gluos.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <GL/glu.h> /*for drawing bzier patch*/
#include "bezierPatch.h"
#include "bezierEval.h"

/*
 *allocate an instance of bezierPatch. The control points are unknown. But
 *the space of this array is allocated with size of 
 *   uorder*vorder*dimension
 *
 */
bezierPatch* bezierPatchMake(float umin, float vmin, float umax, float vmax, int uorder, int vorder, int dimension)
{
	bezierPatch* ret = (bezierPatch*) malloc(sizeof(bezierPatch));
	assert(ret);
	ret->umin = umin;
	ret->vmin = vmin;
	ret->umax = umax;
	ret->vmax = vmax;
	ret->uorder = uorder;
	ret->vorder = vorder;
	ret->dimension = dimension;
	ret->ctlpoints = (float*) malloc(sizeof(float) * dimension * uorder * vorder);
	assert(ret->ctlpoints);

	ret->next = NULL;

	return ret;
}

bezierPatch* bezierPatchMake2(float umin, float vmin, float umax, float vmax, int uorder, int vorder, int dimension, int ustride, int vstride,  float* ctlpoints)
{
	bezierPatch* ret = (bezierPatch*) malloc(sizeof(bezierPatch));
	assert(ret);
	ret->umin = umin;
	ret->vmin = vmin;
	ret->umax = umax;
	ret->vmax = vmax;
	ret->uorder = uorder;
	ret->vorder = vorder;
	ret->dimension = dimension;
	ret->ctlpoints = (float*) malloc(sizeof(float) * dimension * uorder * vorder);
	assert(ret->ctlpoints);

	/*copy the control points there*/
	int the_ustride = vorder * dimension;
	int the_vstride = dimension;
	for(int i=0; i<uorder; i++)
		for(int j=0; j<vorder; j++)
			for(int k=0; k<dimension; k++)
				ret->ctlpoints[i * the_ustride + j*the_vstride+k] = ctlpoints[i*ustride+j*vstride+k];

	ret->next = NULL;

	return ret;
}

/*
 *deallocate the space as allocated by Make
 */
void bezierPatchDelete(bezierPatch *b)
{
	free(b->ctlpoints);
	free(b);
}

/*delete the whole linked list
 */
void bezierPatchDeleteList(bezierPatch *b)
{
	bezierPatch *temp;
	for(temp = b; temp != NULL; temp = temp->next)
		bezierPatchDelete(temp);
}

bezierPatch* bezierPatchInsert(bezierPatch *list, bezierPatch *b)
{
	b->next = list;
	return b;
}

/*print the data stored in this patch*/
void bezierPatchPrint(bezierPatch *b)
{
	printf("bezierPatch:\n");
	printf("umin,umax=(%f,%f), (vmin, vmax)=(%f,%f)\n", b->umin, b->umax, b->vmin, b->vmax);
	printf("uorder=%i, vorder=%i\n", b->uorder, b->vorder);
	printf("idmension = %i\n", b->dimension);
}

/*print the whole list*/
void bezierPatchPrintList(bezierPatch *list)
{
	bezierPatch* temp;
	for(temp=list; temp != NULL; temp = temp->next)
		bezierPatchPrint(temp);
}

void bezierPatchEval(bezierPatch *b, float u, float v, float ret[])
{
	if(   u >= b->umin && u<= b->umax
			&& v >= b->vmin && v<= b->vmax)
	{

		bezierSurfEval(b->umin, b->umax, b->uorder, b->vmin, b->vmax, b->vorder, b->dimension, b->ctlpoints, b->dimension * b->vorder, b->dimension, u, v, ret);

	}
	else if(b->next != NULL)
		bezierPatchEval(b->next, u,v, ret);
	else 
		bezierSurfEval(b->umin, b->umax, b->uorder, b->vmin, b->vmax, b->vorder, b->dimension, b->ctlpoints, b->dimension * b->vorder, b->dimension, u, v, ret);    
}

/*the returned normal is normlized
 */
void bezierPatchEvalNormal(bezierPatch *b, float u, float v, float ret[])
{
	bezierSurfEvalNormal(b->umin, b->umax, b->uorder, b->vmin, b->vmax, b->vorder, b->dimension, b->ctlpoints, b->dimension * b->vorder, b->dimension, u, v, ret);  

	if(   u >= b->umin && u<= b->umax
			&& v >= b->vmin && v<= b->vmax)
	{
		bezierSurfEvalNormal(b->umin, b->umax, b->uorder, b->vmin, b->vmax, b->vorder, b->dimension, b->ctlpoints, b->dimension * b->vorder, b->dimension, u, v, ret);
	}
	else if(b->next != NULL)
		bezierPatchEvalNormal(b->next, u,v, ret);
	else 
		bezierSurfEvalNormal(b->umin, b->umax, b->uorder, b->vmin, b->vmax, b->vorder, b->dimension, b->ctlpoints, b->dimension * b->vorder, b->dimension, u, v, ret);    

}

void bezierPatchDraw(struct GLContextIFace *Self, bezierPatch *bpatch, int u_reso, int v_reso)
{
	if(bpatch->dimension == 3)
		Self->GLMap2f(GL_MAP2_VERTEX_3, bpatch->umin, bpatch->umax, 3*bpatch->vorder, bpatch->uorder, bpatch->vmin, bpatch->vmax,3, bpatch->vorder, (GLfloat*) bpatch->ctlpoints);
	else
		Self->GLMap2f(GL_MAP2_VERTEX_4, bpatch->umin, bpatch->umax, 4*bpatch->vorder, bpatch->uorder, bpatch->vmin, bpatch->vmax,3, bpatch->vorder, (GLfloat*) bpatch->ctlpoints);    

	Self->GLMapGrid2f(u_reso, bpatch->umin, bpatch->umax, 
			v_reso, bpatch->vmin, bpatch->vmax);
	Self->GLEvalMesh2(GL_LINE, 0, u_reso, 0, v_reso);
}

void bezierPatchListDraw(struct GLContextIFace *Self, bezierPatch *list, int u_reso, int v_reso)
{
	bezierPatch *temp;
	Self->SetState(GL_LIGHTING, GL_TRUE);
	Self->SetState(GL_LIGHT0, GL_TRUE);
	Self->SetState(GL_MAP2_VERTEX_3, GL_TRUE);
	Self->SetState(GL_AUTO_NORMAL, GL_TRUE);
	Self->SetState(GL_NORMALIZE, GL_TRUE);
	Self->GLColor4f(1,0,0,1);
#ifdef DEBUG
	printf("mapmap\n");
#endif


	for(temp = list; temp != NULL; temp = temp->next)
		bezierPatchDraw(Self, temp, u_reso, v_reso);
}



