/* $Id: nurbssrf.c,v 1.1.1.1 1999/08/19 00:55:42 jtg Exp $ */ /* * Mesa 3-D graphics library * Version: 2.4 * Copyright (C) 1995-1997 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. */ /* * $Log: nurbssrf.c,v $ * Revision 1.1.1.1 1999/08/19 00:55:42 jtg * Imported sources * * Revision 1.7 1997/07/24 01:28:44 brianp * changed precompiled header symbol from PCH to PC_HEADER * * Revision 1.6 1997/06/23 00:22:07 brianp * include * * Revision 1.5 1997/05/28 02:29:38 brianp * added support for precompiled headers (PCH), inserted APIENTRY keyword * * Revision 1.4 1997/05/27 03:20:35 brianp * minor clean-up * * Revision 1.3 1997/05/27 03:00:16 brianp * incorporated Bogdan's new NURBS code * * Revision 1.2 1996/09/27 23:13:02 brianp * added return 0 to get_surface_dim() to silence warning * * Revision 1.1 1996/09/27 01:19:39 brianp * Initial revision * */ /* * NURBS implementation written by Bogdan Sikorski (bogdan@cira.it) * See README2 for more info. */ #ifdef PC_HEADER #include "all.h" #else #include #include #include #include "gluP.h" #include "nurbs.h" #endif static int get_surface_dim(GLenum type) { switch(type) { case GL_MAP2_VERTEX_3: return 3; case GL_MAP2_VERTEX_4: return 4; case GL_MAP2_INDEX: return 1; case GL_MAP2_COLOR_4: return 4; case GL_MAP2_NORMAL: return 3; case GL_MAP2_TEXTURE_COORD_1: return 1; case GL_MAP2_TEXTURE_COORD_2: return 2; case GL_MAP2_TEXTURE_COORD_3: return 3; case GL_MAP2_TEXTURE_COORD_4: return 4; default: abort(); /* TODO: is this OK? */ } return 0; /*never get here*/ } static GLenum test_nurbs_surface(GLUnurbsObj *nobj, surface_attribs *attrib) { GLenum err; GLint tmp_int; if(attrib->sorder < 0 || attrib->torder < 0) { call_user_error(nobj,GLU_INVALID_VALUE); return GLU_ERROR; } glGetIntegerv(GL_MAX_EVAL_ORDER,&tmp_int); if(attrib->sorder > tmp_int || attrib->sorder < 2) { call_user_error(nobj,GLU_NURBS_ERROR1); return GLU_ERROR; } if(attrib->torder > tmp_int || attrib->torder < 2) { call_user_error(nobj,GLU_NURBS_ERROR1); return GLU_ERROR; } if(attrib->sknot_count < attrib->sorder +2) { call_user_error(nobj,GLU_NURBS_ERROR2); return GLU_ERROR; } if(attrib->tknot_count < attrib->torder +2) { call_user_error(nobj,GLU_NURBS_ERROR2); return GLU_ERROR; } if(attrib->s_stride < 0 || attrib->t_stride < 0) { call_user_error(nobj,GLU_NURBS_ERROR34); return GLU_ERROR; } if(attrib->sknot==NULL || attrib->tknot==NULL || attrib->ctrlarray==NULL) { call_user_error(nobj,GLU_NURBS_ERROR36); return GLU_ERROR; } if((err=test_knot(attrib->tknot_count,attrib->tknot,attrib->torder)) !=GLU_NO_ERROR) { call_user_error(nobj,err); return GLU_ERROR; } if((err=test_knot(attrib->sknot_count,attrib->sknot,attrib->sorder)) !=GLU_NO_ERROR) { call_user_error(nobj,err); return GLU_ERROR; } return GLU_NO_ERROR; } static GLenum test_nurbs_surfaces(GLUnurbsObj *nobj) { /* test the geometric data */ if(test_nurbs_surface(nobj,&(nobj->surface.geom))!=GLU_NO_ERROR) return GLU_ERROR; /* now test the attributive data */ /* color */ if(nobj->surface.color.type!=GLU_INVALID_ENUM) if(test_nurbs_surface(nobj,&(nobj->surface.color))!=GLU_NO_ERROR) return GLU_ERROR; /* normal */ if(nobj->surface.normal.type!=GLU_INVALID_ENUM) if(test_nurbs_surface(nobj,&(nobj->surface.normal))!=GLU_NO_ERROR) return GLU_ERROR; /* texture */ if(nobj->surface.texture.type!=GLU_INVALID_ENUM) if(test_nurbs_surface(nobj,&(nobj->surface.texture))!=GLU_NO_ERROR) return GLU_ERROR; return GLU_NO_ERROR; } static GLenum convert_surf(knot_str_type *s_knot, knot_str_type *t_knot, surface_attribs *attrib, GLfloat **new_ctrl, GLint *s_n_ctrl, GLint *t_n_ctrl) { GLfloat **tmp_ctrl; GLfloat *ctrl_offset; GLint tmp_n_control; GLint i,j,t_cnt,s_cnt; GLint tmp_stride; GLint dim; GLenum err; /* valid range is empty? */ if((s_knot->unified_knot !=NULL && s_knot->unified_nknots==0) || (t_knot->unified_knot !=NULL && t_knot->unified_nknots==0)) { if(s_knot->unified_knot) { free(s_knot->unified_knot); s_knot->unified_knot=NULL; } if(t_knot->unified_knot) { free(t_knot->unified_knot); t_knot->unified_knot=NULL; } *s_n_ctrl=0; *t_n_ctrl=0; return GLU_NO_ERROR; } t_cnt=attrib->tknot_count-attrib->torder; s_cnt=attrib->sknot_count-attrib->sorder; if((tmp_ctrl=(GLfloat **)malloc(sizeof(GLfloat *)*t_cnt))==NULL) return GLU_OUT_OF_MEMORY; if((err=explode_knot(s_knot))!=GLU_NO_ERROR) { free(tmp_ctrl); if(s_knot->unified_knot) { free(s_knot->unified_knot); s_knot->unified_knot=NULL; } return err; } if(s_knot->unified_knot) { free(s_knot->unified_knot); s_knot->unified_knot=NULL; } if((err=calc_alphas(s_knot))!=GLU_NO_ERROR) { free(tmp_ctrl); free(s_knot->new_knot); return err; } free(s_knot->new_knot); ctrl_offset=attrib->ctrlarray; dim=attrib->dim; for(i=0;is_stride,s_knot, dim,&(tmp_ctrl[i]),&tmp_n_control))!=GLU_NO_ERROR) { for(--i;i<=0;i--) free(tmp_ctrl[i]); free(tmp_ctrl); free(s_knot->alpha); return err; } ctrl_offset+=attrib->t_stride; } free(s_knot->alpha); tmp_stride=dim*tmp_n_control; if((*new_ctrl=(GLfloat *)malloc(sizeof(GLfloat)*tmp_stride*t_cnt)) ==NULL) { for(i=0;iunified_knot) { free(t_knot->unified_knot); t_knot->unified_knot=NULL; } return err; } if(t_knot->unified_knot) { free(t_knot->unified_knot); t_knot->unified_knot=NULL; } if((err=calc_alphas(t_knot))!=GLU_NO_ERROR) { free(tmp_ctrl); free(t_knot->new_knot); return err; } free(t_knot->new_knot); ctrl_offset=*new_ctrl; for(i=0;i<(*s_n_ctrl);i++) { if((err=calc_new_ctrl_pts(ctrl_offset,dim,t_knot, dim,&(tmp_ctrl[i]),&tmp_n_control))!=GLU_NO_ERROR) { for(--i;i<=0;i--) free(tmp_ctrl[i]); free(tmp_ctrl); free(t_knot->alpha); return err; } ctrl_offset+=dim*t_cnt; } free(t_knot->alpha); free(*new_ctrl); tmp_stride=dim*tmp_n_control; if((*new_ctrl=(GLfloat *)malloc(sizeof(GLfloat)*tmp_stride*(*s_n_ctrl))) ==NULL) { for(i=0;i<(*s_n_ctrl);i++) free(tmp_ctrl[i]); free(tmp_ctrl); return GLU_OUT_OF_MEMORY; } for(i=0;i<(*s_n_ctrl);i++) { MEMCPY(*new_ctrl+i*tmp_stride,tmp_ctrl[i],sizeof(GLfloat)*tmp_stride); free(tmp_ctrl[i]); } free(tmp_ctrl); *t_n_ctrl=tmp_n_control; return GLU_NO_ERROR; } /* prepare the knot information structures */ static GLenum fill_knot_structures(GLUnurbsObj *nobj, knot_str_type *geom_s_knot, knot_str_type *geom_t_knot, knot_str_type *color_s_knot, knot_str_type *color_t_knot, knot_str_type *normal_s_knot, knot_str_type *normal_t_knot, knot_str_type *texture_s_knot, knot_str_type *texture_t_knot) { GLint order; GLfloat *knot; GLint nknots; GLint t_min,t_max; geom_s_knot->unified_knot=NULL; knot=geom_s_knot->knot=nobj->surface.geom.sknot; nknots=geom_s_knot->nknots=nobj->surface.geom.sknot_count; order=geom_s_knot->order=nobj->surface.geom.sorder; geom_s_knot->delta_nknots=0; t_min=geom_s_knot->t_min=order-1; t_max=geom_s_knot->t_max=nknots-order; if(fabs(knot[t_min]-knot[t_max])open_at_begin=GL_TRUE; } else geom_s_knot->open_at_begin=GL_FALSE; if(fabs(knot[t_max]-knot[nknots-1])open_at_end=GL_TRUE; } else geom_s_knot->open_at_end=GL_FALSE; geom_t_knot->unified_knot=NULL; knot=geom_t_knot->knot=nobj->surface.geom.tknot; nknots=geom_t_knot->nknots=nobj->surface.geom.tknot_count; order=geom_t_knot->order=nobj->surface.geom.torder; geom_t_knot->delta_nknots=0; t_min=geom_t_knot->t_min=order-1; t_max=geom_t_knot->t_max=nknots-order; if(fabs(knot[t_min]-knot[t_max])open_at_begin=GL_TRUE; } else geom_t_knot->open_at_begin=GL_FALSE; if(fabs(knot[t_max]-knot[nknots-1])open_at_end=GL_TRUE; } else geom_t_knot->open_at_end=GL_FALSE; if(nobj->surface.color.type!=GLU_INVALID_ENUM) { color_s_knot->unified_knot=(GLfloat *)1; knot=color_s_knot->knot=nobj->surface.color.sknot; nknots=color_s_knot->nknots=nobj->surface.color.sknot_count; order=color_s_knot->order=nobj->surface.color.sorder; color_s_knot->delta_nknots=0; t_min=color_s_knot->t_min=order-1; t_max=color_s_knot->t_max=nknots-order; if(fabs(knot[t_min]-knot[t_max])open_at_begin=GL_TRUE; } else color_s_knot->open_at_begin=GL_FALSE; if(fabs(knot[t_max]-knot[nknots-1])open_at_end=GL_TRUE; } else color_s_knot->open_at_end=GL_FALSE; color_t_knot->unified_knot=(GLfloat *)1; knot=color_t_knot->knot=nobj->surface.color.tknot; nknots=color_t_knot->nknots=nobj->surface.color.tknot_count; order=color_t_knot->order=nobj->surface.color.torder; color_t_knot->delta_nknots=0; t_min=color_t_knot->t_min=order-1; t_max=color_t_knot->t_max=nknots-order; if(fabs(knot[t_min]-knot[t_max])open_at_begin=GL_TRUE; } else color_t_knot->open_at_begin=GL_FALSE; if(fabs(knot[t_max]-knot[nknots-1])open_at_end=GL_TRUE; } else color_t_knot->open_at_end=GL_FALSE; } else { color_s_knot->unified_knot=NULL; color_t_knot->unified_knot=NULL; } if(nobj->surface.normal.type!=GLU_INVALID_ENUM) { normal_s_knot->unified_knot=(GLfloat *)1; knot=normal_s_knot->knot=nobj->surface.normal.sknot; nknots=normal_s_knot->nknots=nobj->surface.normal.sknot_count; order=normal_s_knot->order=nobj->surface.normal.sorder; normal_s_knot->delta_nknots=0; t_min=normal_s_knot->t_min=order-1; t_max=normal_s_knot->t_max=nknots-order; if(fabs(knot[t_min]-knot[t_max])open_at_begin=GL_TRUE; } else normal_s_knot->open_at_begin=GL_FALSE; if(fabs(knot[t_max]-knot[nknots-1])open_at_end=GL_TRUE; } else normal_s_knot->open_at_end=GL_FALSE; normal_t_knot->unified_knot=(GLfloat *)1; knot=normal_t_knot->knot=nobj->surface.normal.tknot; nknots=normal_t_knot->nknots=nobj->surface.normal.tknot_count; order=normal_t_knot->order=nobj->surface.normal.torder; normal_t_knot->delta_nknots=0; t_min=normal_t_knot->t_min=order-1; t_max=normal_t_knot->t_max=nknots-order; if(fabs(knot[t_min]-knot[t_max])open_at_begin=GL_TRUE; } else normal_t_knot->open_at_begin=GL_FALSE; if(fabs(knot[t_max]-knot[nknots-1])open_at_end=GL_TRUE; } else normal_t_knot->open_at_end=GL_FALSE; } else { normal_s_knot->unified_knot=NULL; normal_t_knot->unified_knot=NULL; } if(nobj->surface.texture.type!=GLU_INVALID_ENUM) { texture_s_knot->unified_knot=(GLfloat *)1; knot=texture_s_knot->knot=nobj->surface.texture.sknot; nknots=texture_s_knot->nknots=nobj->surface.texture.sknot_count; order=texture_s_knot->order=nobj->surface.texture.sorder; texture_s_knot->delta_nknots=0; t_min=texture_s_knot->t_min=order-1; t_max=texture_s_knot->t_max=nknots-order; if(fabs(knot[t_min]-knot[t_max])open_at_begin=GL_TRUE; } else texture_s_knot->open_at_begin=GL_FALSE; if(fabs(knot[t_max]-knot[nknots-1])open_at_end=GL_TRUE; } else texture_s_knot->open_at_end=GL_FALSE; texture_t_knot->unified_knot=(GLfloat *)1; knot=texture_t_knot->knot=nobj->surface.texture.tknot; nknots=texture_t_knot->nknots=nobj->surface.texture.tknot_count; order=texture_t_knot->order=nobj->surface.texture.torder; texture_t_knot->delta_nknots=0; t_min=texture_t_knot->t_min=order-1; t_max=texture_t_knot->t_max=nknots-order; if(fabs(knot[t_min]-knot[t_max])open_at_begin=GL_TRUE; } else texture_t_knot->open_at_begin=GL_FALSE; if(fabs(knot[t_max]-knot[nknots-1])open_at_end=GL_TRUE; } else texture_t_knot->open_at_end=GL_FALSE; } else { texture_s_knot->unified_knot=NULL; texture_t_knot->unified_knot=NULL; } return GLU_NO_ERROR; } void free_new_ctrl(new_ctrl_type *p) { if(p->geom_ctrl) free(p->geom_ctrl); if(p->geom_offsets) free(p->geom_offsets); if(p->color_ctrl) { free(p->color_ctrl); if(p->color_offsets) free(p->color_offsets); } if(p->normal_ctrl) { free(p->normal_ctrl); if(p->normal_offsets) free(p->normal_offsets); } if(p->texture_ctrl) { free(p->texture_ctrl); if(p->texture_offsets) free(p->texture_offsets); } } /* convert surfaces - geometry and possible attribute ones into equivalent */ /* sequence of adjacent Bezier patches */ static GLenum convert_surfs(GLUnurbsObj *nobj, new_ctrl_type *new_ctrl) { knot_str_type geom_s_knot,color_s_knot,normal_s_knot,texture_s_knot; knot_str_type geom_t_knot,color_t_knot,normal_t_knot,texture_t_knot; GLenum err; if((err=fill_knot_structures(nobj,&geom_s_knot,&geom_t_knot, &color_s_knot,&color_t_knot,&normal_s_knot,&normal_t_knot, &texture_s_knot,&texture_t_knot)) !=GLU_NO_ERROR) { return err; } /* unify knots - all knots should have the same working range */ if((err=select_knot_working_range(nobj,&geom_s_knot,&color_s_knot, &normal_s_knot,&texture_s_knot)) !=GLU_NO_ERROR) { call_user_error(nobj,err); return err; } if((err=select_knot_working_range(nobj,&geom_t_knot,&color_t_knot, &normal_t_knot,&texture_t_knot)) !=GLU_NO_ERROR) { free_unified_knots(&geom_s_knot,&color_s_knot,&normal_s_knot, &texture_s_knot); call_user_error(nobj,err); return err; } /* convert the geometry surface */ nobj->surface.geom.dim=get_surface_dim(nobj->surface.geom.type); if((err=convert_surf(&geom_s_knot,&geom_t_knot,&(nobj->surface.geom), &(new_ctrl->geom_ctrl),&(new_ctrl->geom_s_pt_cnt), &(new_ctrl->geom_t_pt_cnt)))!=GLU_NO_ERROR) { free_unified_knots(&geom_s_knot,&color_s_knot,&normal_s_knot, &texture_s_knot); free_unified_knots(&geom_t_knot,&color_t_knot,&normal_t_knot, &texture_t_knot); call_user_error(nobj,err); return err; } /* if additional attributive surfaces are given convert them as well */ if(color_s_knot.unified_knot) { nobj->surface.color.dim=get_surface_dim(nobj->surface.color.type); if((err=convert_surf(&color_s_knot,&color_t_knot,&(nobj->surface.color), &(new_ctrl->color_ctrl),&(new_ctrl->color_s_pt_cnt), &(new_ctrl->color_t_pt_cnt)))!=GLU_NO_ERROR) { free_unified_knots(&color_s_knot,&color_s_knot,&normal_s_knot, &texture_s_knot); free_unified_knots(&color_t_knot,&color_t_knot,&normal_t_knot, &texture_t_knot); free_new_ctrl(new_ctrl); call_user_error(nobj,err); return err; } } if(normal_s_knot.unified_knot) { nobj->surface.normal.dim=get_surface_dim(nobj->surface.normal.type); if((err=convert_surf(&normal_s_knot,&normal_t_knot, &(nobj->surface.normal), &(new_ctrl->normal_ctrl),&(new_ctrl->normal_s_pt_cnt), &(new_ctrl->normal_t_pt_cnt)))!=GLU_NO_ERROR) { free_unified_knots(&normal_s_knot,&normal_s_knot,&normal_s_knot, &texture_s_knot); free_unified_knots(&normal_t_knot,&normal_t_knot,&normal_t_knot, &texture_t_knot); free_new_ctrl(new_ctrl); call_user_error(nobj,err); return err; } } if(texture_s_knot.unified_knot) { nobj->surface.texture.dim=get_surface_dim(nobj->surface.texture.type); if((err=convert_surf(&texture_s_knot,&texture_t_knot, &(nobj->surface.texture), &(new_ctrl->texture_ctrl),&(new_ctrl->texture_s_pt_cnt), &(new_ctrl->texture_t_pt_cnt)))!=GLU_NO_ERROR) { free_unified_knots(&texture_s_knot,&texture_s_knot,&texture_s_knot, &texture_s_knot); free_unified_knots(&texture_t_knot,&texture_t_knot,&texture_t_knot, &texture_t_knot); free_new_ctrl(new_ctrl); call_user_error(nobj,err); return err; } } return GLU_NO_ERROR; } /* tesselate the "boundary" Bezier edge strips */ void tesselate_strip_t_line(GLint top_start,GLint top_end,GLint top_z, GLint bottom_start,GLint bottom_end,GLint bottom_z,GLint bottom_domain) { GLint top_cnt,bottom_cnt,tri_cnt,k; GLint direction; top_cnt=top_end-top_start; direction= (top_cnt>=0 ? 1: -1); bottom_cnt=bottom_end-bottom_start; glBegin(GL_LINES); while(top_cnt) { if(bottom_cnt) tri_cnt=top_cnt/bottom_cnt; else tri_cnt=abs(top_cnt); for(k=0;k<=tri_cnt;k++ , top_start+=direction) { glEvalCoord2f((GLfloat)bottom_z/bottom_domain, (GLfloat)bottom_start/bottom_domain); glEvalPoint2(top_z,top_start); } if(bottom_cnt) { glEvalCoord2f((GLfloat)bottom_z/bottom_domain, (GLfloat)bottom_start/bottom_domain); bottom_start+=direction; top_start-=direction; glEvalCoord2f((GLfloat)bottom_z/bottom_domain, (GLfloat)bottom_start/bottom_domain); glEvalCoord2f((GLfloat)bottom_z/bottom_domain, (GLfloat)bottom_start/bottom_domain); glEvalPoint2(top_z,top_start); } top_cnt-=direction*tri_cnt; bottom_cnt-=direction; } glEnd(); } void tesselate_strip_t_fill(GLint top_start,GLint top_end,GLint top_z, GLint bottom_start,GLint bottom_end,GLint bottom_z,GLint bottom_domain) { GLint top_cnt,bottom_cnt,tri_cnt,k; GLint direction; top_cnt=top_end-top_start; direction= (top_cnt>=0 ? 1: -1); bottom_cnt=bottom_end-bottom_start; while(top_cnt) { if(bottom_cnt) tri_cnt=top_cnt/bottom_cnt; else tri_cnt=abs(top_cnt); glBegin(GL_TRIANGLE_FAN); glEvalCoord2f((GLfloat)bottom_z/bottom_domain, (GLfloat)bottom_start/bottom_domain); for(k=0;k<=tri_cnt;k++ , top_start+=direction) glEvalPoint2(top_z,top_start); if(bottom_cnt) { bottom_start+=direction; top_start-=direction; glEvalCoord2f((GLfloat)bottom_z/bottom_domain, (GLfloat)bottom_start/bottom_domain); } glEnd(); top_cnt-=direction*tri_cnt; bottom_cnt-=direction; } } void tesselate_strip_t(GLenum display_mode, GLint top_start, GLint top_end, GLint top_z, GLint bottom_start, GLint bottom_end, GLint bottom_z, GLint bottom_domain) { if(display_mode==GL_FILL) tesselate_strip_t_fill(top_start,top_end,top_z,bottom_start, bottom_end,bottom_z,bottom_domain); else tesselate_strip_t_line(top_start,top_end,top_z,bottom_start, bottom_end,bottom_z,bottom_domain); } void tesselate_strip_s_fill(GLint top_start, GLint top_end, GLint top_z, GLint bottom_start, GLint bottom_end, GLint bottom_z, GLfloat bottom_domain) { GLint top_cnt,bottom_cnt,tri_cnt,k; GLint direction; top_cnt=top_end-top_start; direction= (top_cnt>=0 ? 1: -1); bottom_cnt=bottom_end-bottom_start; while(top_cnt) { if(bottom_cnt) tri_cnt=top_cnt/bottom_cnt; else tri_cnt=abs(top_cnt); glBegin(GL_TRIANGLE_FAN); glEvalCoord2f((GLfloat)bottom_start/bottom_domain, (GLfloat)bottom_z/bottom_domain); for(k=0;k<=tri_cnt;k++ , top_start+=direction) glEvalPoint2(top_start,top_z); if(bottom_cnt) { bottom_start+=direction; top_start-=direction; glEvalCoord2f((GLfloat)bottom_start/bottom_domain, (GLfloat)bottom_z/bottom_domain); } glEnd(); top_cnt-=direction*tri_cnt; bottom_cnt-=direction; } } void tesselate_strip_s_line(GLint top_start, GLint top_end, GLint top_z, GLint bottom_start, GLint bottom_end, GLint bottom_z, GLfloat bottom_domain) { GLint top_cnt,bottom_cnt,tri_cnt,k; GLint direction; top_cnt=top_end-top_start; direction= (top_cnt>=0 ? 1: -1); bottom_cnt=bottom_end-bottom_start; glBegin(GL_LINES); while(top_cnt) { if(bottom_cnt) tri_cnt=top_cnt/bottom_cnt; else tri_cnt=abs(top_cnt); for(k=0;k<=tri_cnt;k++ , top_start+=direction) { glEvalCoord2f((GLfloat)bottom_start/bottom_domain, (GLfloat)bottom_z/bottom_domain); glEvalPoint2(top_start,top_z); } if(bottom_cnt) { glEvalCoord2f((GLfloat)bottom_start/bottom_domain, (GLfloat)bottom_z/bottom_domain); bottom_start+=direction; top_start-=direction; glEvalCoord2f((GLfloat)bottom_start/bottom_domain, (GLfloat)bottom_z/bottom_domain); glEvalPoint2(top_start,top_z); glEvalCoord2f((GLfloat)bottom_start/bottom_domain, (GLfloat)bottom_z/bottom_domain); } top_cnt-=direction*tri_cnt; bottom_cnt-=direction; } glEnd(); } void tesselate_strip_s(GLenum display_mode, GLint top_start, GLint top_end, GLint top_z, GLint bottom_start, GLint bottom_end, GLint bottom_z, GLfloat bottom_domain) { if(display_mode==GL_FILL) tesselate_strip_s_fill(top_start,top_end,top_z,bottom_start, bottom_end,bottom_z,bottom_domain); else tesselate_strip_s_line(top_start,top_end,top_z,bottom_start, bottom_end,bottom_z,bottom_domain); } void tesselate_bottom_left_corner(GLenum display_mode, GLfloat s_1, GLfloat t_1) { if(display_mode==GL_FILL) { glBegin(GL_TRIANGLE_FAN); glEvalPoint2(1,1); glEvalCoord2f(s_1,0.0); glEvalCoord2f(0.0,0.0); glEvalCoord2f(0.0,t_1); } else { glBegin(GL_LINES); glEvalCoord2f(0.0,0.0); glEvalCoord2f(0.0,t_1); glEvalCoord2f(0.0,0.0); glEvalPoint2(1,1); glEvalCoord2f(0.0,0.0); glEvalCoord2f(s_1,0.0); } glEnd(); } void tesselate_bottom_right_corner(GLenum display_mode, GLint v_top,GLint v_bottom, GLfloat s_1, GLfloat t_1) { if(display_mode==GL_FILL) { glBegin(GL_TRIANGLE_FAN); glEvalPoint2(1,v_top); glEvalCoord2f(0.0,v_bottom*t_1); glEvalCoord2f(0.0,(v_bottom+1)*t_1); glEvalCoord2f(s_1,(v_bottom+1)*t_1); } else { glBegin(GL_LINES); glEvalCoord2f(0.0,(v_bottom+1)*t_1); glEvalPoint2(1,v_top); glEvalCoord2f(0.0,(v_bottom+1)*t_1); glEvalCoord2f(0.0,v_bottom*t_1); glEvalCoord2f(0.0,(v_bottom+1)*t_1); glEvalCoord2f(s_1,(v_bottom+1)*t_1); } glEnd(); } void tesselate_top_left_corner(GLenum display_mode, GLint u_right, GLint u_left, GLfloat s_1, GLfloat t_1) { if(display_mode==GL_FILL) { glBegin(GL_TRIANGLE_FAN); glEvalPoint2(u_right,1); glEvalCoord2f((u_left+1)*s_1,t_1); glEvalCoord2f((u_left+1)*s_1,0.0); glEvalCoord2f(u_left*s_1,0.0); } else { glBegin(GL_LINES); glEvalCoord2f((u_left+1)*s_1,0.0); glEvalPoint2(u_right,1); glEvalCoord2f((u_left+1)*s_1,0.0); glEvalCoord2f(u_left*s_1,0.0); glEvalCoord2f((u_left+1)*s_1,0.0); glEvalCoord2f((u_left+1)*s_1,t_1); } glEnd(); } void tesselate_top_right_corner(GLenum display_mode, GLint u_left, GLint v_bottom, GLint u_right, GLint v_top, GLfloat s_1, GLfloat t_1) { if(display_mode==GL_FILL) { glBegin(GL_TRIANGLE_FAN); glEvalPoint2(u_left,v_bottom); glEvalCoord2f((u_right-1)*s_1,v_top*t_1); glEvalCoord2f(u_right*s_1,v_top*t_1); glEvalCoord2f(u_right*s_1,(v_top-1)*t_1); } else { glBegin(GL_LINES); glEvalCoord2f(u_right*s_1,v_top*t_1); glEvalPoint2(u_left,v_bottom); glEvalCoord2f(u_right*s_1,v_top*t_1); glEvalCoord2f(u_right*s_1,(v_top-1)*t_1); glEvalCoord2f(u_right*s_1,v_top*t_1); glEvalCoord2f((u_right-1)*s_1,v_top*t_1); } glEnd(); } /* do mesh mapping of Bezier */ static void nurbs_map_bezier(GLenum display_mode,GLint *sfactors,GLint *tfactors, GLint s_bezier_cnt, GLint t_bezier_cnt, GLint s, GLint t) { GLint top,bottom,right,left; if(s==0) { top=*(tfactors+t*3); bottom=*(tfactors+t*3+1); } else if(s==s_bezier_cnt-1) { top=*(tfactors+t*3+2); bottom=*(tfactors+t*3); } else { top=bottom=*(tfactors+t*3); } if(t==0) { left=*(sfactors+s*3+1); right=*(sfactors+s*3); } else if(t==t_bezier_cnt-1) { left=*(sfactors+s*3); right=*(sfactors+s*3+2); } else { left=right=*(sfactors+s*3); } if(top>bottom) { if(leftt_bezier_cnt; s_bezier_cnt=new_ctrl->s_bezier_cnt; glEnable(nobj->surface.geom.type); if(new_ctrl->color_ctrl) { glEnable(nobj->surface.color.type); do_color=GL_TRUE; } else do_color=GL_FALSE; if(new_ctrl->normal_ctrl) { glEnable(nobj->surface.normal.type); do_normal=GL_TRUE; } else do_normal=GL_FALSE; if(new_ctrl->texture_ctrl) { glEnable(nobj->surface.texture.type); do_texture=GL_TRUE; } else do_texture=GL_FALSE; for(j=0; jgeom_offsets + offset), nobj->surface.geom.sorder,nobj->surface.geom.torder, new_ctrl->geom_s_stride,new_ctrl->geom_t_stride, nobj->surface.geom.dim)) continue; glMap2f(nobj->surface.geom.type,0.0,1.0,new_ctrl->geom_s_stride, nobj->surface.geom.sorder,0.0,1.0,new_ctrl->geom_t_stride, nobj->surface.geom.torder,*(new_ctrl->geom_offsets + offset)); if(do_color) { glMap2f(nobj->surface.color.type,0.0,1.0, new_ctrl->color_s_stride,nobj->surface.color.sorder, 0.0,1.0,new_ctrl->color_t_stride,nobj->surface.color.torder, *(new_ctrl->color_offsets + offset)); } if(do_normal) { glMap2f(nobj->surface.normal.type,0.0,1.0, new_ctrl->normal_s_stride,nobj->surface.normal.sorder, 0.0,1.0,new_ctrl->normal_t_stride, nobj->surface.normal.torder, *(new_ctrl->normal_offsets+offset)); } if(do_texture) { glMap2f(nobj->surface.texture.type,0.0,1.0, new_ctrl->texture_s_stride,nobj->surface.texture.sorder, 0.0,1.0,new_ctrl->texture_t_stride, nobj->surface.texture.torder, *(new_ctrl->texture_offsets+offset)); } /* glMapGrid2f(sfactors[j*3+0],0.0,1.0,tfactors[i*3+0],0.0,1.0); glEvalMesh2(display_mode,0,sfactors[j*3+0],0,tfactors[i*3+0]);*/ nurbs_map_bezier(display_mode,sfactors,tfactors,s_bezier_cnt, t_bezier_cnt,j,i); } } } /* draw NURBS surface in OUTLINE POLYGON mode */ #if 0 static void draw_patch_mode( GLenum display_mode, GLUnurbsObj *nobj, new_ctrl_type *new_ctrl, GLint *sfactors, GLint *tfactors ) { GLsizei offset; GLint t_bezier_cnt,s_bezier_cnt; GLboolean do_color,do_normal,do_texture; GLint i,j; t_bezier_cnt=new_ctrl->t_bezier_cnt; s_bezier_cnt=new_ctrl->s_bezier_cnt; glEnable(nobj->surface.geom.type); if(new_ctrl->color_ctrl) { glEnable(nobj->surface.color.type); do_color=GL_TRUE; } else do_color=GL_FALSE; if(new_ctrl->normal_ctrl) { glEnable(nobj->surface.normal.type); do_normal=GL_TRUE; } else do_normal=GL_FALSE; if(new_ctrl->texture_ctrl) { glEnable(nobj->surface.texture.type); do_texture=GL_TRUE; } else do_texture=GL_FALSE; for(j=0; jgeom_offsets + offset), nobj->surface.geom.sorder,nobj->surface.geom.torder, new_ctrl->geom_s_stride,new_ctrl->geom_t_stride, nobj->surface.geom.dim)) continue; glMap2f(nobj->surface.geom.type,0.0,1.0,new_ctrl->geom_s_stride, nobj->surface.geom.sorder,0.0,1.0,new_ctrl->geom_t_stride, nobj->surface.geom.torder,*(new_ctrl->geom_offsets + offset)); if(do_color) { glMap2f(nobj->surface.color.type,0.0,1.0, new_ctrl->color_s_stride,nobj->surface.color.sorder, 0.0,1.0,new_ctrl->color_t_stride,nobj->surface.color.torder, *(new_ctrl->color_offsets + offset)); } if(do_normal) { glMap2f(nobj->surface.normal.type,0.0,1.0, new_ctrl->normal_s_stride,nobj->surface.normal.sorder, 0.0,1.0,new_ctrl->normal_t_stride, nobj->surface.normal.torder, *(new_ctrl->normal_offsets+offset)); } if(do_texture) { glMap2f(nobj->surface.texture.type,0.0,1.0, new_ctrl->texture_s_stride,nobj->surface.texture.sorder, 0.0,1.0,new_ctrl->texture_t_stride, nobj->surface.texture.torder, *(new_ctrl->texture_offsets+offset)); } nurbs_map_bezier(display_mode,sfactors,tfactors,s_bezier_cnt, t_bezier_cnt,i,j); /* glMapGrid2f(sfactors[j],0.0,1.0,tfactors[i],0.0,1.0); glEvalMesh2(display_mode,0,sfactors[j],0,tfactors[i]);*/ } } } #endif void init_new_ctrl(new_ctrl_type *p) { p->geom_ctrl=p->color_ctrl=p->normal_ctrl=p->texture_ctrl=NULL; p->geom_offsets=p->color_offsets=p->normal_offsets=p->texture_offsets=NULL; p->s_bezier_cnt=p->t_bezier_cnt=0; } GLenum augment_new_ctrl(GLUnurbsObj *nobj, new_ctrl_type *p) { GLsizei offset_size; GLint i,j; p->s_bezier_cnt=(p->geom_s_pt_cnt)/(nobj->surface.geom.sorder); p->t_bezier_cnt=(p->geom_t_pt_cnt)/(nobj->surface.geom.torder); offset_size=(p->s_bezier_cnt)*(p->t_bezier_cnt); p->geom_t_stride=nobj->surface.geom.dim; p->geom_s_stride=(p->geom_t_pt_cnt)*(nobj->surface.geom.dim); p->color_t_stride=nobj->surface.color.dim; p->color_s_stride=(p->color_t_pt_cnt)*(nobj->surface.color.dim); p->normal_t_stride=nobj->surface.normal.dim; p->normal_s_stride=(p->normal_t_pt_cnt)*(nobj->surface.normal.dim); p->texture_t_stride=nobj->surface.texture.dim; p->texture_s_stride=(p->texture_t_pt_cnt)*(nobj->surface.texture.dim); if((p->geom_offsets=(GLfloat **)malloc(sizeof(GLfloat *)*offset_size))==NULL) { call_user_error(nobj,GLU_OUT_OF_MEMORY); return GLU_ERROR; } if(p->color_ctrl) if((p->color_offsets=(GLfloat **)malloc(sizeof(GLfloat *)*offset_size))==NULL) { free_new_ctrl(p); call_user_error(nobj,GLU_OUT_OF_MEMORY); return GLU_ERROR; } if(p->normal_ctrl) if((p->normal_offsets=(GLfloat **)malloc(sizeof(GLfloat *)*offset_size))==NULL) { free_new_ctrl(p); call_user_error(nobj,GLU_OUT_OF_MEMORY); return GLU_ERROR; } if(p->texture_ctrl) if((p->texture_offsets=(GLfloat **)malloc(sizeof(GLfloat *)*offset_size))==NULL) { free_new_ctrl(p); call_user_error(nobj,GLU_OUT_OF_MEMORY); return GLU_ERROR; } for(i=0;is_bezier_cnt;i++) for(j=0;jt_bezier_cnt;j++) *(p->geom_offsets + i*(p->t_bezier_cnt) + j) = p->geom_ctrl + i*(nobj->surface.geom.sorder)* (nobj->surface.geom.dim)*(p->geom_t_pt_cnt) + j*(nobj->surface.geom.dim)*(nobj->surface.geom.torder); if(p->color_ctrl) for(i=0;is_bezier_cnt;i++) for(j=0;jt_bezier_cnt;j++) *(p->color_offsets + i*(p->t_bezier_cnt) + j) = p->color_ctrl + i*(nobj->surface.color.sorder)* (nobj->surface.color.dim)*(p->color_t_pt_cnt) + j*(nobj->surface.color.dim)*(nobj->surface.color.torder); if(p->normal_ctrl) for(i=0;is_bezier_cnt;i++) for(j=0;jt_bezier_cnt;j++) *(p->normal_offsets + i*(p->t_bezier_cnt) + j) = p->normal_ctrl + i*(nobj->surface.normal.sorder)* (nobj->surface.normal.dim)*(p->normal_t_pt_cnt) + j*(nobj->surface.normal.dim)*(nobj->surface.normal.torder); if(p->texture_ctrl) for(i=0;is_bezier_cnt;i++) for(j=0;jt_bezier_cnt;j++) *(p->texture_offsets + i*(p->t_bezier_cnt) + j) = p->texture_ctrl + i*(nobj->surface.texture.sorder)* (nobj->surface.texture.dim)*(p->texture_t_pt_cnt) + j*(nobj->surface.texture.dim)*(nobj->surface.texture.torder); return GLU_NO_ERROR; } /* main NURBS surface procedure */ void do_nurbs_surface( GLUnurbsObj *nobj ) { GLint *sfactors,*tfactors; new_ctrl_type new_ctrl; /* test user supplied data */ if(test_nurbs_surfaces(nobj)!=GLU_NO_ERROR) return; init_new_ctrl(&new_ctrl); if(convert_surfs(nobj,&new_ctrl)!=GLU_NO_ERROR) return; if(augment_new_ctrl(nobj,&new_ctrl)!=GLU_NO_ERROR) return; switch(nobj->sampling_method) { case GLU_PATH_LENGTH: if(glu_do_sampling_3D(nobj,&new_ctrl,&sfactors,&tfactors)!= GLU_NO_ERROR) { free_new_ctrl(&new_ctrl); return; } break; case GLU_DOMAIN_DISTANCE: if(glu_do_sampling_uv(nobj,&new_ctrl,&sfactors,&tfactors)!= GLU_NO_ERROR) { free_new_ctrl(&new_ctrl); return; } break; case GLU_PARAMETRIC_ERROR: if(glu_do_sampling_param_3D(nobj,&new_ctrl,&sfactors,&tfactors)!= GLU_NO_ERROR) { free_new_ctrl(&new_ctrl); return; } break; default: abort(); } glFrontFace(GL_CW); switch(nobj->display_mode) { case GLU_FILL: /* if(polygon_trimming(nobj,&new_ctrl,sfactors,tfactors)==GLU_NO_ERROR)*/ draw_polygon_mode(GL_FILL,nobj,&new_ctrl,sfactors,tfactors); break; case GLU_OUTLINE_POLYGON: /* TODO - missing trimming handeling */ /* just for now - no OUTLINE_PATCH mode draw_patch_mode(GL_LINE,nobj,&new_ctrl,sfactors,tfactors); break; */ case GLU_OUTLINE_PATCH: /* if(polygon_trimming(nobj,&new_ctrl,sfactors,tfactors)==GLU_NO_ERROR)*/ draw_polygon_mode(GL_LINE,nobj,&new_ctrl,sfactors,tfactors); break; default: abort(); /* TODO: is this OK? */ } free(sfactors); free(tfactors); free_new_ctrl(&new_ctrl); }