/* ** 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/bezierPatchMesh.cc,v 1.1 2001/03/17 00:25:40 brianp Exp $ */ #include "gluos.h" #include #include #include #include #include "bezierEval.h" #include "bezierPatchMesh.h" static int isDegenerate(float A[2], float B[2], float C[2]); void drawStrips(struct GLContextIFace *Self, float *vertex_array, float *normal_array, int *length_array, GLenum *type_array, int num_strips) { int i,j,k; k=0; /*k is the index of the first component of the current vertex*/ for(i=0; iGLBegin(type_array[i]); for(j=0; jGLNormal3f((normal_array+k)[0], (normal_array+k)[1], (normal_array+k)[2]); Self->GLVertex4f((vertex_array+k)[0], (vertex_array+k)[1], (vertex_array+k)[2], 1.0); k += 3; } Self->GLEnd(); } } void bezierPatchMeshListDelDeg(bezierPatchMesh* list) { bezierPatchMesh* temp; for(temp=list; temp != NULL; temp = temp->next) { bezierPatchMeshDelDeg(temp); } } void bezierPatchMeshListDelete(bezierPatchMesh *list) { if(list == NULL) return; bezierPatchMeshListDelete(list->next); bezierPatchMeshDelete(list); } bezierPatchMesh* bezierPatchMeshListReverse(bezierPatchMesh* list) { bezierPatchMesh* ret=NULL; bezierPatchMesh* temp; bezierPatchMesh* nextone; for(temp = list; temp != NULL; temp = nextone) { nextone = temp->next; ret=bezierPatchMeshListInsert(ret, temp); } return ret; } /*maptype is either GL_MAP2_VERTEX_3 or GL_MAP2_VERTEX_4 */ bezierPatchMesh *bezierPatchMeshMake(int maptype, float umin, float umax, int ustride, int uorder, float vmin, float vmax, int vstride, int vorder, float *ctlpoints, int size_UVarray, int size_length_array) { int i,j,k; int dimension; int the_ustride; int the_vstride; bezierPatchMesh *ret = (bezierPatchMesh*) malloc(sizeof(bezierPatchMesh)); assert(ret); ret->bpatch = NULL; ret->bpatch_normal = NULL; ret->bpatch_color = NULL; ret->bpatch_texcoord = NULL; if(maptype == GL_MAP2_VERTEX_3) dimension = 3; else if (maptype==GL_MAP2_VERTEX_4) dimension = 4; else { fprintf(stderr, "error in inMap2f, maptype=%i is wrong, maptype,map is invalid\n", maptype); return NULL; } ret->bpatch = bezierPatchMake(umin, vmin, umax, vmax, uorder, vorder, dimension); /*copy the control points there*/ the_ustride = vorder * dimension; the_vstride = dimension; for(i=0; ibpatch->ctlpoints[i * the_ustride + j*the_vstride+k] = ctlpoints[i*ustride+j*vstride+k]; ret->size_UVarray = size_UVarray; ret->size_length_array = size_length_array; ret->UVarray = (float*) malloc(sizeof(float) * size_UVarray); assert(ret->UVarray); ret->length_array = (int *)malloc(sizeof(int) * size_length_array); assert(ret->length_array); ret->type_array = (GLenum *)malloc(sizeof(GLenum) * size_length_array); assert(ret->type_array); ret->index_UVarray = 0; ret->index_length_array = 0; ret->vertex_array = NULL; ret->normal_array = NULL; ret->color_array = NULL; ret->texcoord_array = NULL; ret->next = NULL; return ret; } bezierPatchMesh *bezierPatchMeshMake2(int size_UVarray, int size_length_array) { bezierPatchMesh *ret = (bezierPatchMesh*) malloc(sizeof(bezierPatchMesh)); assert(ret); ret->bpatch = NULL; ret->bpatch_normal = NULL; ret->bpatch_color = NULL; ret->bpatch_texcoord = NULL; ret->size_UVarray = size_UVarray; ret->size_length_array = size_length_array; ret->UVarray = (float*) malloc(sizeof(float) * size_UVarray); assert(ret->UVarray); ret->length_array = (int *)malloc(sizeof(int) * size_length_array); assert(ret->length_array); ret->type_array = (GLenum *)malloc(sizeof(GLenum) * size_length_array); assert(ret->type_array); ret->index_UVarray = 0; ret->index_length_array = 0; ret->vertex_array = NULL; ret->normal_array = NULL; ret->color_array = NULL; ret->texcoord_array = NULL; ret->next = NULL; return ret; } void bezierPatchMeshPutPatch(bezierPatchMesh *bpm, int maptype, float umin, float umax, int ustride, int uorder, float vmin, float vmax, int vstride, int vorder, float *ctlpoints) { switch(maptype){ case GL_MAP2_VERTEX_3: bpm->bpatch = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 3, ustride, vstride, ctlpoints); break; case GL_MAP2_VERTEX_4: bpm->bpatch = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 4,ustride, vstride, ctlpoints ); break; case GL_MAP2_NORMAL: bpm->bpatch_normal = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 3, ustride, vstride, ctlpoints); break; case GL_MAP2_INDEX: bpm->bpatch_color = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 1, ustride, vstride, ctlpoints); break; case GL_MAP2_COLOR_4: bpm->bpatch_color = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 4, ustride, vstride, ctlpoints); break; case GL_MAP2_TEXTURE_COORD_1: bpm->bpatch_texcoord = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 1, ustride, vstride, ctlpoints); break; case GL_MAP2_TEXTURE_COORD_2: bpm->bpatch_texcoord = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 2, ustride, vstride, ctlpoints); break; case GL_MAP2_TEXTURE_COORD_3: bpm->bpatch_texcoord = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 3, ustride, vstride, ctlpoints); break; case GL_MAP2_TEXTURE_COORD_4: bpm->bpatch_texcoord = bezierPatchMake2(umin, vmin, umax, vmax, uorder, vorder, 4, ustride, vstride, ctlpoints); break; default: fprintf(stderr, "error in bezierPatchMeshPutPatch, maptype=%i is wrong, maptype,map is invalid\n", maptype); } } /*delete everything including the arrays. So if you want to output the *pointers of the arrays, you should not use this function to deallocate space. *you should dealocate manually */ void bezierPatchMeshDelete(bezierPatchMesh *bpm) { if(bpm->bpatch != NULL) bezierPatchDelete(bpm->bpatch); if(bpm->bpatch_normal != NULL) bezierPatchDelete(bpm->bpatch_normal); if(bpm->bpatch_color != NULL) bezierPatchDelete(bpm->bpatch_color); if(bpm->bpatch_texcoord != NULL) bezierPatchDelete(bpm->bpatch_texcoord); free(bpm->UVarray); free(bpm->length_array); free(bpm->vertex_array); free(bpm->normal_array); free(bpm->type_array); free(bpm); } /*begin a strip *type is the primitive type: */ void bezierPatchMeshBeginStrip(bezierPatchMesh *bpm, GLenum type) { bpm->counter = 0; bpm->type = type; } /*signal the end of the current strip*/ void bezierPatchMeshEndStrip(bezierPatchMesh *bpm) { int i; /*if there are no vertices in this strip, then nothing needs to be done*/ if(bpm->counter == 0) return; /*if the length_array is full, it should be expanded*/ if(bpm->index_length_array >= bpm->size_length_array) { int *temp = (int*) malloc(sizeof(int) * (bpm->size_length_array*2 + 1)); assert(temp); GLenum *temp_type = (GLenum*) malloc(sizeof(GLenum) * (bpm->size_length_array*2 + 1)); assert(temp_type); /*update the size*/ bpm->size_length_array = bpm->size_length_array*2 + 1; /*copy*/ for(i=0; iindex_length_array; i++) { temp[i] = bpm->length_array[i]; temp_type[i] = bpm->type_array[i]; } /*deallocate old array*/ free(bpm->length_array); free(bpm->type_array); /*point to the new array which is twice as bigger*/ bpm->length_array = temp; bpm->type_array = temp_type; } bpm->type_array[bpm->index_length_array] = bpm->type; bpm->length_array[bpm->index_length_array++] = bpm->counter; } /*insert (u,v) */ void bezierPatchMeshInsertUV(bezierPatchMesh *bpm, float u, float v) { int i; /*if the UVarray is full, it should be expanded*/ if(bpm->index_UVarray+1 >= bpm->size_UVarray) { float *temp = (float*) malloc(sizeof(float) * (bpm->size_UVarray * 2 + 2)); assert(temp); /*update the size*/ bpm->size_UVarray = bpm->size_UVarray*2 + 2; /*copy*/ for(i=0; iindex_UVarray; i++) { temp[i] = bpm->UVarray[i]; } /*deallocate old array*/ free(bpm->UVarray); /*pointing to the new arrays*/ bpm->UVarray = temp; } /*insert the new UV*/ bpm->UVarray[bpm->index_UVarray] = u; bpm->index_UVarray++; bpm->UVarray[bpm->index_UVarray] = v; bpm->index_UVarray++; /*update counter: one more vertex*/ bpm->counter++; } void bezierPatchMeshPrint(bezierPatchMesh *bpm) { int i; printf("the bezier patch is\n"); bezierPatchPrint(bpm->bpatch); printf("index_length_array= %i\n", bpm->index_length_array); printf("size_length_array =%i\n", bpm->size_length_array); printf("index_UVarray =%i\n", bpm->index_UVarray); printf("size_UVarray =%i\n", bpm->size_UVarray); printf("UVarray is\n"); for(i=0; iindex_UVarray; i++) printf("%f ", bpm->UVarray[i]); printf("length_array is\n"); for(i=0; iindex_length_array; i++) printf("%i ", bpm->length_array[i]); printf("\n"); } /*insert a new patch in front of the current linked list and return the new list*/ bezierPatchMesh* bezierPatchMeshListInsert(bezierPatchMesh* list, bezierPatchMesh* bpm) { bpm->next=list; return bpm; } /*print all the patches*/ void bezierPatchMeshListPrint(bezierPatchMesh* list) { bezierPatchMesh *temp; for(temp = list; temp != NULL; temp = temp->next) { bezierPatchMeshPrint(temp); } } int bezierPatchMeshListTotalStrips(bezierPatchMesh* list) { int sum=0; bezierPatchMesh *temp; for(temp=list; temp != NULL; temp = temp->next) { sum += temp->index_length_array; } return sum; } int bezierPatchMeshListTotalVert(bezierPatchMesh* list) { int sum=0; bezierPatchMesh *temp; for(temp=list; temp != NULL; temp = temp->next) { sum += temp->index_UVarray; } return sum/2; } int bezierPatchMeshListNumTriangles(bezierPatchMesh* list) { int sum=0; bezierPatchMesh* temp; for(temp=list; temp != NULL; temp = temp->next) { sum += bezierPatchMeshNumTriangles(temp); } return sum; } int bezierPatchMeshNumTriangles(bezierPatchMesh* bpm) { int i; int sum=0; for(i=0; iindex_length_array; i++) { switch(bpm->type_array[i]) { case GL_TRIANGLES: sum += bpm->length_array[i]/3; break; case GL_TRIANGLE_FAN: if(bpm->length_array[i] > 2) sum += bpm->length_array[i]-2; break; case GL_TRIANGLE_STRIP: if(bpm->length_array[i] > 2) sum += bpm->length_array[i]-2; break; case GL_QUAD_STRIP: if(bpm->length_array[i]>2) sum += (bpm->length_array[i]-2); break; default: fprintf(stderr,"error in bezierPatchMeshListNumTriangles, type invalid\n"); } } return sum; } /*delete degenerate triangles*/ void bezierPatchMeshDelDeg(bezierPatchMesh* bpm) { if(bpm == NULL) return; int i,j,k; int *new_length_array; GLenum *new_type_array; int index_new_length_array; float *new_UVarray; int index_new_UVarray; new_length_array = (int*)malloc(sizeof(int) * bpm->index_length_array); assert(new_length_array); new_type_array = (GLenum*)malloc(sizeof(GLenum) * bpm->index_length_array); assert(new_length_array); new_UVarray = (float*) malloc(sizeof(float) * bpm->index_UVarray); assert(new_UVarray); index_new_length_array = 0; index_new_UVarray=0; k=0; for(i=0; iindex_length_array; i++){ /*(if not degenerate, we have to copy*/ if( (bpm->length_array[i] != 3) || (!isDegenerate(bpm->UVarray+k, bpm->UVarray+k+2, bpm->UVarray+k+4))) { for(j=0; j<2* bpm->length_array[i]; j++) new_UVarray[index_new_UVarray++] = bpm->UVarray[k++]; new_length_array[index_new_length_array] = bpm->length_array[i]; new_type_array[index_new_length_array] = bpm->type_array[i]; index_new_length_array++; } else { k += 6; } } free(bpm->UVarray); free(bpm->length_array); free(bpm->type_array); bpm->UVarray=new_UVarray; bpm->length_array=new_length_array; bpm->type_array=new_type_array; bpm->index_UVarray = index_new_UVarray; bpm->index_length_array = index_new_length_array; } /*(u,v) to XYZ *the xyz and normals are stored in vertex_array, *and normal_array. the spaces of both are allocated here */ void bezierPatchMeshEval(bezierPatchMesh* bpm) { int i,j,k,l; float u,v; float u0 = bpm->bpatch->umin; float u1 = bpm->bpatch->umax; int uorder = bpm->bpatch->uorder; float v0 = bpm->bpatch->vmin; float v1 = bpm->bpatch->vmax; int vorder = bpm->bpatch->vorder; int dimension = bpm->bpatch->dimension; int ustride = dimension * vorder; int vstride = dimension; float *ctlpoints = bpm->bpatch->ctlpoints; bpm->vertex_array = (float*) malloc(sizeof(float)* (bpm->index_UVarray/2) * 3); assert(bpm->vertex_array); bpm->normal_array = (float*) malloc(sizeof(float)* (bpm->index_UVarray/2) * 3); assert(bpm->normal_array); k=0; l=0; for(i=0; iindex_length_array; i++) { for(j=0; jlength_array[i]; j++) { u = bpm->UVarray[k]; v = bpm->UVarray[k+1]; bezierSurfEval(u0,u1,uorder, v0, v1, vorder, dimension, ctlpoints, ustride, vstride, u,v, bpm->vertex_array+l); bezierSurfEvalNormal(u0,u1,uorder, v0, v1, vorder, dimension, ctlpoints, ustride, vstride, u,v, bpm->normal_array+l); k += 2; l += 3; } } } void bezierPatchMeshListEval(bezierPatchMesh* list) { bezierPatchMesh* temp; for(temp = list; temp != NULL; temp = temp->next) { bezierPatchMeshEval(temp); } } void bezierPatchMeshDraw(struct GLContextIFace *Self, bezierPatchMesh* bpm) { int i,j,k; k=0; /*k is the index of the first component of the current vertex*/ for(i=0; iindex_length_array; i++) { Self->GLBegin(bpm->type_array[i]); for(j=0; jlength_array[i]; j++) { Self->GLNormal3f((bpm->normal_array+k)[0], (bpm->normal_array+k)[2], (bpm->normal_array+k)[2]); Self->GLVertex4f((bpm->vertex_array+k)[0], (bpm->vertex_array+k)[1], (bpm->vertex_array+k)[2], 1.0); k+= 3; } Self->GLEnd(); } } void bezierPatchMeshListDraw(struct GLContextIFace *Self,bezierPatchMesh* list) { bezierPatchMesh* temp; for(temp = list; temp != NULL; temp = temp->next) { bezierPatchMeshDraw(Self, temp); } } void bezierPatchMeshListCollect(bezierPatchMesh* list, float **vertex_array, float **normal_array, int **length_array, GLenum **type_array, int *num_strips) { int i,j,k,l; bezierPatchMesh *temp; int total_num_vertices = bezierPatchMeshListTotalVert(list); (*vertex_array) = (float *) malloc(sizeof(float) * total_num_vertices*3); assert(*vertex_array); (*normal_array) = (float *) malloc(sizeof(float) * total_num_vertices*3); assert(*normal_array); *num_strips = bezierPatchMeshListTotalStrips(list); *length_array = (int*) malloc(sizeof(int) * (*num_strips)); assert(*length_array); *type_array = (GLenum*) malloc(sizeof(GLenum) * (*num_strips)); assert(*type_array); k=0; l=0; for(temp = list; temp != NULL; temp = temp->next) { int x=0; for(i=0; iindex_length_array; i++) { for(j=0; jlength_array[i]; j++) { (*vertex_array)[k] = temp->vertex_array[x]; (*vertex_array)[k+1] = temp->vertex_array[x+1]; (*vertex_array)[k+2] = temp->vertex_array[x+2]; (*normal_array)[k] = temp->normal_array[x]; (*normal_array)[k+1] = temp->normal_array[x+1]; (*normal_array)[k+2] = temp->normal_array[x+2]; x += 3; k += 3; } (*type_array)[l] = temp->type_array[i]; (*length_array)[l++] = temp->length_array[i]; } } } static int isDegenerate(float A[2], float B[2], float C[2]) { if( (A[0] == B[0] && A[1]==B[1]) || (A[0] == C[0] && A[1]==C[1]) || (B[0] == C[0] && B[1]==C[1]) ) return 1; else return 0; }