/* $Id: nurbs.c,v 1.3 2000/02/10 17:45:52 brianp Exp $ */ /* * Mesa 3-D graphics library * Version: 3.3 * Copyright (C) 1995-2000 Brian Paul * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * NURBS implementation written by Bogdan Sikorski (bogdan@cira.it) * See README2 for more info. */ #ifdef PC_HEADER #include "all.h" #else #include #include #include "gluP.h" #include "nurbs.h" #endif void call_user_error( GLUnurbsObj *nobj, GLenum error ) { nobj->error=error; if(nobj->error_callback != NULL) { (*(nobj->error_callback))(error); } else { printf("NURBS error %d %s\n", error, (char *) gluErrorString(error) ); } } GLUnurbsObj * GLAPIENTRY gluNewNurbsRenderer( void ) { GLUnurbsObj *n; GLfloat tmp_viewport[4]; GLint i,j; n = (GLUnurbsObj *) malloc( sizeof(GLUnurbsObj) ); if (n) { /* init */ n->culling=GL_FALSE; n->nurbs_type=GLU_NURBS_NONE; n->error=GLU_NO_ERROR; n->error_callback=NULL; n->auto_load_matrix=GL_TRUE; n->sampling_tolerance=50.0; n->parametric_tolerance=0.5; n->u_step = n->v_step = 100; n->sampling_method = GLU_PATH_LENGTH; n->display_mode=GLU_FILL; /* in case the user doesn't supply the sampling matrices */ /* set projection and modelview to identity */ for(i=0;i<4;i++) for(j=0;j<4;j++) if(i==j) { n->sampling_matrices.model[i*4+j]=1.0; n->sampling_matrices.proj[i*4+j]=1.0; } else { n->sampling_matrices.model[i*4+j]=0.0; n->sampling_matrices.proj[i*4+j]=0.0; } /* and set the viewport sampling matrix to current ciewport */ glGetFloatv(GL_VIEWPORT,tmp_viewport); for(i=0;i<4;i++) n->sampling_matrices.viewport[i]=tmp_viewport[i]; n->trim=NULL; } return n; } void GLAPIENTRY gluDeleteNurbsRenderer( GLUnurbsObj *nobj ) { if (nobj) { free( nobj ); } } void GLAPIENTRY gluLoadSamplingMatrices( GLUnurbsObj *nobj, const GLfloat modelMatrix[16], const GLfloat projMatrix[16], const GLint viewport[4] ) { GLint i; for(i=0;i<16;i++) { nobj->sampling_matrices.model[i]=modelMatrix[i]; nobj->sampling_matrices.proj[i]=projMatrix[i]; } for(i=0;i<4;i++) nobj->sampling_matrices.viewport[i]=viewport[i]; } void GLAPIENTRY gluNurbsProperty( GLUnurbsObj *nobj, GLenum property, GLfloat value ) { GLenum val; switch (property) { case GLU_SAMPLING_TOLERANCE: if(value <= 0.0) { call_user_error(nobj,GLU_INVALID_VALUE); return; } nobj->sampling_tolerance=value; break; case GLU_PARAMETRIC_TOLERANCE: if(value <= 0.0) { call_user_error(nobj,GLU_INVALID_VALUE); return; } nobj->parametric_tolerance=value; break; case GLU_U_STEP: if(value <= 0.0) { call_user_error(nobj,GLU_INVALID_VALUE); return; } nobj->u_step=(GLint)value; break; case GLU_V_STEP: if(value <= 0.0) { call_user_error(nobj,GLU_INVALID_VALUE); return; } nobj->v_step=(GLint)value; break; case GLU_SAMPLING_METHOD: val = (GLenum)value; if(val!=GLU_PATH_LENGTH && val!=GLU_PARAMETRIC_ERROR && val!=GLU_DOMAIN_DISTANCE) { call_user_error(nobj,GLU_INVALID_ENUM); return; } nobj->sampling_method=val; break; case GLU_DISPLAY_MODE: val=(GLenum)value; if(val!=GLU_FILL && val!=GLU_OUTLINE_POLYGON && val!=GLU_OUTLINE_PATCH) { call_user_error(nobj,GLU_INVALID_ENUM); return; } if(nobj->nurbs_type==GLU_NURBS_CURVE) { call_user_error(nobj,GLU_NURBS_ERROR26); return; } nobj->display_mode=val; if(val==GLU_OUTLINE_PATCH) fprintf(stderr,"NURBS, for the moment, can display only in POLYGON mode\n"); break; case GLU_CULLING: val=(GLenum)value; if(val!=GL_TRUE && val!=GL_FALSE) { call_user_error(nobj,GLU_INVALID_ENUM); return; } nobj->culling = (GLboolean) value; break; case GLU_AUTO_LOAD_MATRIX: val=(GLenum)value; if(val!=GL_TRUE && val!=GL_FALSE) { call_user_error(nobj,GLU_INVALID_ENUM); return; } nobj->auto_load_matrix = (GLboolean) value; break; default: call_user_error(nobj,GLU_NURBS_ERROR26); } } void GLAPIENTRY gluGetNurbsProperty( GLUnurbsObj *nobj, GLenum property, GLfloat *value ) { switch (property) { case GLU_SAMPLING_TOLERANCE: *value = nobj->sampling_tolerance; break; case GLU_DISPLAY_MODE: *value = (GLfloat) (GLint) nobj->display_mode; break; case GLU_CULLING: *value = nobj->culling ? 1.0 : 0.0; break; case GLU_AUTO_LOAD_MATRIX: *value = nobj->auto_load_matrix ? 1.0 : 0.0; break; default: call_user_error(nobj,GLU_INVALID_ENUM); } } void GLAPIENTRY gluBeginCurve( GLUnurbsObj *nobj ) { if(nobj->nurbs_type==GLU_NURBS_CURVE) { call_user_error(nobj,GLU_NURBS_ERROR6); return; } nobj->nurbs_type=GLU_NURBS_CURVE; nobj->curve.geom.type=GLU_INVALID_ENUM; nobj->curve.color.type=GLU_INVALID_ENUM; nobj->curve.texture.type=GLU_INVALID_ENUM; nobj->curve.normal.type=GLU_INVALID_ENUM; } void GLAPIENTRY gluEndCurve( GLUnurbsObj * nobj ) { if(nobj->nurbs_type==GLU_NURBS_NONE) { call_user_error(nobj,GLU_NURBS_ERROR7); return; } if(nobj->curve.geom.type==GLU_INVALID_ENUM) { call_user_error(nobj,GLU_NURBS_ERROR8); nobj->nurbs_type=GLU_NURBS_NONE; return; } glPushAttrib( (GLbitfield) (GL_EVAL_BIT | GL_ENABLE_BIT) ); glDisable(GL_MAP1_VERTEX_3); glDisable(GL_MAP1_VERTEX_4); glDisable(GL_MAP1_INDEX); glDisable(GL_MAP1_COLOR_4); glDisable(GL_MAP1_NORMAL); glDisable(GL_MAP1_TEXTURE_COORD_1); glDisable(GL_MAP1_TEXTURE_COORD_2); glDisable(GL_MAP1_TEXTURE_COORD_3); glDisable(GL_MAP1_TEXTURE_COORD_4); glDisable(GL_MAP2_VERTEX_3); glDisable(GL_MAP2_VERTEX_4); glDisable(GL_MAP2_INDEX); glDisable(GL_MAP2_COLOR_4); glDisable(GL_MAP2_NORMAL); glDisable(GL_MAP2_TEXTURE_COORD_1); glDisable(GL_MAP2_TEXTURE_COORD_2); glDisable(GL_MAP2_TEXTURE_COORD_3); glDisable(GL_MAP2_TEXTURE_COORD_4); do_nurbs_curve(nobj); glPopAttrib(); nobj->nurbs_type=GLU_NURBS_NONE; } void GLAPIENTRY gluNurbsCurve( GLUnurbsObj *nobj, GLint nknots, GLfloat *knot, GLint stride, GLfloat *ctlarray, GLint order, GLenum type ) { if(nobj->nurbs_type==GLU_NURBS_TRIM) { #if 0 /* TODO: NOT IMPLEMENTED YET */ nurbs_trim *ptr1; trim_list *ptr2; if(type!=GLU_MAP1_TRIM_2 && type!=GLU_MAP1_TRIM_3) { call_user_error(nobj,GLU_NURBS_ERROR14); return; } for(ptr1=nobj->trim;ptr1->next;ptr1=ptr1->next); if(ptr1->trim_loop) { for(ptr2=ptr1->trim_loop;ptr2->next;ptr2=ptr2->next); if((ptr2->next=(trim_list *)malloc(sizeof(trim_list)))==NULL) { call_user_error(nobj,GLU_OUT_OF_MEMORY); return; } ptr2=ptr2->next; } else { if((ptr2=(trim_list *)malloc(sizeof(trim_list)))==NULL) { call_user_error(nobj,GLU_OUT_OF_MEMORY); return; } ptr1->trim_loop=ptr2; } ptr2->trim_type=GLU_TRIM_NURBS; ptr2->curve.nurbs_curve.knot_count=nknots; ptr2->curve.nurbs_curve.knot=knot; ptr2->curve.nurbs_curve.stride=stride; ptr2->curve.nurbs_curve.ctrlarray=ctlarray; ptr2->curve.nurbs_curve.order=order; ptr2->curve.nurbs_curve.dim= (type==GLU_MAP1_TRIM_2 ? 2 : 3 ); ptr2->curve.nurbs_curve.type=type; ptr2->next=NULL; #endif } else { if(type==GLU_MAP1_TRIM_2 || type==GLU_MAP1_TRIM_3) { call_user_error(nobj,GLU_NURBS_ERROR22); return; } if(nobj->nurbs_type!=GLU_NURBS_CURVE) { call_user_error(nobj,GLU_NURBS_ERROR10); return; } switch(type) { case GL_MAP1_VERTEX_3: case GL_MAP1_VERTEX_4: if(nobj->curve.geom.type!=GLU_INVALID_ENUM) { call_user_error(nobj,GLU_NURBS_ERROR8); return; } nobj->curve.geom.type=type; nobj->curve.geom.knot_count=nknots; nobj->curve.geom.knot=knot; nobj->curve.geom.stride=stride; nobj->curve.geom.ctrlarray=ctlarray; nobj->curve.geom.order=order; break; case GL_MAP1_INDEX: case GL_MAP1_COLOR_4: nobj->curve.color.type=type; nobj->curve.color.knot_count=nknots; nobj->curve.color.knot=knot; nobj->curve.color.stride=stride; nobj->curve.color.ctrlarray=ctlarray; nobj->curve.color.order=order; break; case GL_MAP1_NORMAL: nobj->curve.normal.type=type; nobj->curve.normal.knot_count=nknots; nobj->curve.normal.knot=knot; nobj->curve.normal.stride=stride; nobj->curve.normal.ctrlarray=ctlarray; nobj->curve.normal.order=order; break; case GL_MAP1_TEXTURE_COORD_1: case GL_MAP1_TEXTURE_COORD_2: case GL_MAP1_TEXTURE_COORD_3: case GL_MAP1_TEXTURE_COORD_4: nobj->curve.texture.type=type; nobj->curve.texture.knot_count=nknots; nobj->curve.texture.knot=knot; nobj->curve.texture.stride=stride; nobj->curve.texture.ctrlarray=ctlarray; nobj->curve.texture.order=order; break; default: call_user_error(nobj,GLU_INVALID_ENUM); } } } void GLAPIENTRY gluBeginSurface( GLUnurbsObj *nobj ) { switch(nobj->nurbs_type) { case GLU_NURBS_NONE: nobj->nurbs_type=GLU_NURBS_SURFACE; nobj->surface.geom.type=GLU_INVALID_ENUM; nobj->surface.color.type=GLU_INVALID_ENUM; nobj->surface.texture.type=GLU_INVALID_ENUM; nobj->surface.normal.type=GLU_INVALID_ENUM; break; case GLU_NURBS_TRIM: call_user_error(nobj,GLU_NURBS_ERROR16); break; case GLU_NURBS_SURFACE: case GLU_NURBS_NO_TRIM: case GLU_NURBS_TRIM_DONE: call_user_error(nobj,GLU_NURBS_ERROR27); break; case GLU_NURBS_CURVE: call_user_error(nobj,GLU_NURBS_ERROR6); break; } } void GLAPIENTRY gluEndSurface( GLUnurbsObj * nobj ) { switch(nobj->nurbs_type) { case GLU_NURBS_NONE: call_user_error(nobj,GLU_NURBS_ERROR13); break; case GLU_NURBS_TRIM: call_user_error(nobj,GLU_NURBS_ERROR12); break; case GLU_NURBS_TRIM_DONE: /* if(nobj->trim->trim_loop==NULL) { call_user_error(nobj,GLU_NURBS_ERROR18); return; }*/ /* no break - fallthrough */ case GLU_NURBS_NO_TRIM: glPushAttrib( (GLbitfield) (GL_EVAL_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT) ); glDisable(GL_MAP2_VERTEX_3); glDisable(GL_MAP2_VERTEX_4); glDisable(GL_MAP2_INDEX); glDisable(GL_MAP2_COLOR_4); glDisable(GL_MAP2_NORMAL); glDisable(GL_MAP2_TEXTURE_COORD_1); glDisable(GL_MAP2_TEXTURE_COORD_2); glDisable(GL_MAP2_TEXTURE_COORD_3); glDisable(GL_MAP2_TEXTURE_COORD_4); /* glDisable(GL_MAP1_VERTEX_3); glDisable(GL_MAP1_VERTEX_4); glDisable(GL_MAP1_INDEX); glDisable(GL_MAP1_COLOR_4); glDisable(GL_MAP1_NORMAL); glDisable(GL_MAP1_TEXTURE_COORD_1); glDisable(GL_MAP1_TEXTURE_COORD_2); glDisable(GL_MAP1_TEXTURE_COORD_3); glDisable(GL_MAP1_TEXTURE_COORD_4);*/ do_nurbs_surface(nobj); glPopAttrib(); break; default: call_user_error(nobj,GLU_NURBS_ERROR8); } nobj->nurbs_type=GLU_NURBS_NONE; } void GLAPIENTRY gluNurbsSurface( GLUnurbsObj *nobj, GLint sknot_count, GLfloat *sknot, GLint tknot_count, GLfloat *tknot, GLint s_stride, GLint t_stride, GLfloat *ctrlarray, GLint sorder, GLint torder, GLenum type ) { if(nobj->nurbs_type==GLU_NURBS_NO_TRIM || nobj->nurbs_type==GLU_NURBS_TRIM || nobj->nurbs_type==GLU_NURBS_TRIM_DONE) { if(type==GL_MAP2_VERTEX_3 || type==GL_MAP2_VERTEX_4) { call_user_error(nobj,GLU_NURBS_ERROR8); return; } } else if(nobj->nurbs_type!=GLU_NURBS_SURFACE) { call_user_error(nobj,GLU_NURBS_ERROR11); return; } switch(type) { case GL_MAP2_VERTEX_3: case GL_MAP2_VERTEX_4: nobj->surface.geom.sknot_count=sknot_count; nobj->surface.geom.sknot=sknot; nobj->surface.geom.tknot_count=tknot_count; nobj->surface.geom.tknot=tknot; nobj->surface.geom.s_stride=s_stride; nobj->surface.geom.t_stride=t_stride; nobj->surface.geom.ctrlarray=ctrlarray; nobj->surface.geom.sorder=sorder; nobj->surface.geom.torder=torder; nobj->surface.geom.type=type; nobj->nurbs_type=GLU_NURBS_NO_TRIM; break; case GL_MAP2_INDEX: case GL_MAP2_COLOR_4: nobj->surface.color.sknot_count=sknot_count; nobj->surface.color.sknot=sknot; nobj->surface.color.tknot_count=tknot_count; nobj->surface.color.tknot=tknot; nobj->surface.color.s_stride=s_stride; nobj->surface.color.t_stride=t_stride; nobj->surface.color.ctrlarray=ctrlarray; nobj->surface.color.sorder=sorder; nobj->surface.color.torder=torder; nobj->surface.color.type=type; break; case GL_MAP2_NORMAL: nobj->surface.normal.sknot_count=sknot_count; nobj->surface.normal.sknot=sknot; nobj->surface.normal.tknot_count=tknot_count; nobj->surface.normal.tknot=tknot; nobj->surface.normal.s_stride=s_stride; nobj->surface.normal.t_stride=t_stride; nobj->surface.normal.ctrlarray=ctrlarray; nobj->surface.normal.sorder=sorder; nobj->surface.normal.torder=torder; nobj->surface.normal.type=type; break; case GL_MAP2_TEXTURE_COORD_1: case GL_MAP2_TEXTURE_COORD_2: case GL_MAP2_TEXTURE_COORD_3: case GL_MAP2_TEXTURE_COORD_4: nobj->surface.texture.sknot_count=sknot_count; nobj->surface.texture.sknot=sknot; nobj->surface.texture.tknot_count=tknot_count; nobj->surface.texture.tknot=tknot; nobj->surface.texture.s_stride=s_stride; nobj->surface.texture.t_stride=t_stride; nobj->surface.texture.ctrlarray=ctrlarray; nobj->surface.texture.sorder=sorder; nobj->surface.texture.torder=torder; nobj->surface.texture.type=type; break; default: call_user_error(nobj,GLU_INVALID_ENUM); } } void GLAPIENTRY gluNurbsCallback( GLUnurbsObj *nobj, GLenum which, void (GLCALLBACKP fn)()) { nobj->error_callback = (void(GLCALLBACKPCAST)(GLenum))fn; if(which!=GLU_ERROR) call_user_error(nobj,GLU_INVALID_ENUM); } void GLAPIENTRY gluBeginTrim( GLUnurbsObj *nobj ) { #if 0 nurbs_trim *ptr; #endif if(nobj->nurbs_type!=GLU_NURBS_TRIM_DONE) if(nobj->nurbs_type!=GLU_NURBS_NO_TRIM) { call_user_error(nobj,GLU_NURBS_ERROR15); return; } nobj->nurbs_type=GLU_NURBS_TRIM; fprintf(stderr,"NURBS - trimming not supported yet\n"); #if 0 if((ptr=(nurbs_trim *)malloc(sizeof(nurbs_trim)))==NULL) { call_user_error(nobj,GLU_OUT_OF_MEMORY); return; } if(nobj->trim) { nurbs_trim *tmp_ptr; for(tmp_ptr=nobj->trim;tmp_ptr->next;tmp_ptr=tmp_ptr->next); tmp_ptr->next=ptr; } else nobj->trim=ptr; ptr->trim_loop=NULL; ptr->segments=NULL; ptr->next=NULL; #endif } void GLAPIENTRY gluPwlCurve( GLUnurbsObj *nobj, GLint count, GLfloat *array, GLint stride, GLenum type) { #if 0 nurbs_trim *ptr1; trim_list *ptr2; #endif if(nobj->nurbs_type==GLU_NURBS_CURVE) { call_user_error(nobj,GLU_NURBS_ERROR9); return; } if(nobj->nurbs_type==GLU_NURBS_NONE) { call_user_error(nobj,GLU_NURBS_ERROR19); return; } if(type!=GLU_MAP1_TRIM_2 && type!=GLU_MAP1_TRIM_3) { call_user_error(nobj,GLU_NURBS_ERROR14); return; } #if 0 for(ptr1=nobj->trim;ptr1->next;ptr1=ptr1->next); if(ptr1->trim_loop) { for(ptr2=ptr1->trim_loop;ptr2->next;ptr2=ptr2->next); if((ptr2->next=(trim_list *)malloc(sizeof(trim_list)))==NULL) { call_user_error(nobj,GLU_OUT_OF_MEMORY); return; } ptr2=ptr2->next; } else { if((ptr2=(trim_list *)malloc(sizeof(trim_list)))==NULL) { call_user_error(nobj,GLU_OUT_OF_MEMORY); return; } ptr1->trim_loop=ptr2; } ptr2->trim_type=GLU_TRIM_PWL; ptr2->curve.pwl_curve.pt_count=count; ptr2->curve.pwl_curve.ctrlarray=array; ptr2->curve.pwl_curve.stride=stride; ptr2->curve.pwl_curve.dim= (type==GLU_MAP1_TRIM_2 ? 2 : 3 ); ptr2->curve.pwl_curve.type=type; ptr2->next=NULL; #endif } void GLAPIENTRY gluEndTrim( GLUnurbsObj *nobj ) { if(nobj->nurbs_type!=GLU_NURBS_TRIM) { call_user_error(nobj,GLU_NURBS_ERROR17); return; } nobj->nurbs_type=GLU_NURBS_TRIM_DONE; }