| /* $Id: nurbsutl.c,v 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: nurbsutl.c,v $ |
| * Revision 1.1 1999/08/19 00:55:42 jtg |
| * Initial revision |
| * |
| * Revision 1.8 1999/06/08 00:44:51 brianp |
| * OpenStep updates (pete@ohm.york.ac.uk) |
| * |
| * Revision 1.7 1998/07/26 02:07:59 brianp |
| * updated for Windows compilation per Ted Jump |
| * |
| * Revision 1.6 1997/10/29 02:02:20 brianp |
| * various MS Windows compiler changes (David Bucciarelli, v20 3dfx driver) |
| * |
| * Revision 1.5 1997/07/24 01:28:44 brianp |
| * changed precompiled header symbol from PCH to PC_HEADER |
| * |
| * Revision 1.4 1997/05/28 02:29:38 brianp |
| * added support for precompiled headers (PCH), inserted APIENTRY keyword |
| * |
| * Revision 1.3 1997/05/27 03:19:54 brianp |
| * minor clean-up |
| * |
| * Revision 1.2 1997/05/27 03:00:16 brianp |
| * incorporated Bogdan's new NURBS code |
| * |
| * 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 <math.h> |
| #include <stdlib.h> |
| #include "gluP.h" |
| #include "nurbs.h" |
| #endif |
| |
| |
| GLenum |
| test_knot(GLint nknots, GLfloat *knot, GLint order) |
| { |
| GLsizei i; |
| GLint knot_mult; |
| GLfloat tmp_knot; |
| |
| tmp_knot=knot[0]; |
| knot_mult=1; |
| for(i=1;i<nknots;i++) |
| { |
| if(knot[i] < tmp_knot) |
| return GLU_NURBS_ERROR4; |
| if(fabs(tmp_knot-knot[i]) > EPSILON) |
| { |
| if(knot_mult>order) |
| return GLU_NURBS_ERROR5; |
| knot_mult=1; |
| tmp_knot=knot[i]; |
| } |
| else |
| ++knot_mult; |
| } |
| return GLU_NO_ERROR; |
| } |
| |
| static int |
| /* qsort function */ |
| #if defined(WIN32) && !defined(OPENSTEP) |
| __cdecl |
| #endif |
| knot_sort(const void *a, const void *b) |
| { |
| GLfloat x,y; |
| |
| x=*((GLfloat *)a); |
| y=*((GLfloat *)b); |
| if(fabs(x-y) < EPSILON) |
| return 0; |
| if(x > y) |
| return 1; |
| return -1; |
| } |
| |
| /* insert into dest knot all values within the valid range from src knot */ |
| /* that do not appear in dest */ |
| void |
| collect_unified_knot(knot_str_type *dest, knot_str_type *src, |
| GLfloat maximal_min_knot, GLfloat minimal_max_knot) |
| { |
| GLfloat *src_knot,*dest_knot; |
| GLint src_t_min,src_t_max,dest_t_min,dest_t_max; |
| GLint src_nknots,dest_nknots; |
| GLint i,j,k,new_cnt; |
| GLboolean not_found_flag; |
| |
| src_knot=src->unified_knot; |
| dest_knot=dest->unified_knot; |
| src_t_min=src->t_min; |
| src_t_max=src->t_max; |
| dest_t_min=dest->t_min; |
| dest_t_max=dest->t_max; |
| src_nknots=src->unified_nknots; |
| dest_nknots=dest->unified_nknots; |
| |
| k=new_cnt=dest_nknots; |
| for(i=src_t_min;i<=src_t_max;i++) |
| if(src_knot[i] - maximal_min_knot > -EPSILON && |
| src_knot[i] - minimal_max_knot < EPSILON) |
| { |
| not_found_flag=GL_TRUE; |
| for(j=dest_t_min;j<=dest_t_max;j++) |
| if(fabs(dest_knot[j]-src_knot[i]) < EPSILON) |
| { |
| not_found_flag=GL_FALSE; |
| break; |
| } |
| if(not_found_flag) |
| { |
| /* knot from src is not in dest - add this knot to dest */ |
| dest_knot[k++]=src_knot[i]; |
| ++new_cnt; |
| ++(dest->t_max); /* the valid range widens */ |
| ++(dest->delta_nknots); /* increment the extra knot value counter */ |
| } |
| } |
| dest->unified_nknots=new_cnt; |
| qsort((void *)dest_knot,(size_t)new_cnt,(size_t)sizeof(GLfloat), |
| &knot_sort); |
| } |
| |
| /* basing on the new common knot range for all attributes set */ |
| /* t_min and t_max values for each knot - they will be used later on */ |
| /* by explode_knot() and calc_new_ctrl_pts */ |
| static void |
| set_new_t_min_t_max(knot_str_type *geom_knot, knot_str_type *color_knot, |
| knot_str_type *normal_knot, knot_str_type *texture_knot, |
| GLfloat maximal_min_knot, GLfloat minimal_max_knot) |
| { |
| GLuint t_min,t_max,cnt; |
| |
| if(minimal_max_knot-maximal_min_knot < EPSILON) |
| { |
| /* knot common range empty */ |
| geom_knot->t_min=geom_knot->t_max=0; |
| color_knot->t_min=color_knot->t_max=0; |
| normal_knot->t_min=normal_knot->t_max=0; |
| texture_knot->t_min=texture_knot->t_max=0; |
| } |
| else |
| { |
| if(geom_knot->unified_knot!=NULL) |
| { |
| cnt=geom_knot->unified_nknots; |
| for(t_min=0;t_min<cnt;t_min++) |
| if(fabs((geom_knot->unified_knot)[t_min] - maximal_min_knot) < |
| EPSILON) |
| break; |
| for(t_max=cnt-1;t_max;t_max--) |
| if(fabs((geom_knot->unified_knot)[t_max] - minimal_max_knot) < |
| EPSILON) |
| break; |
| } |
| else |
| if(geom_knot->nknots) |
| { |
| cnt=geom_knot->nknots; |
| for(t_min=0;t_min<cnt;t_min++) |
| if(fabs((geom_knot->knot)[t_min] - maximal_min_knot) < EPSILON) |
| break; |
| for(t_max=cnt-1;t_max;t_max--) |
| if(fabs((geom_knot->knot)[t_max] - minimal_max_knot) < EPSILON) |
| break; |
| } |
| geom_knot->t_min=t_min; |
| geom_knot->t_max=t_max; |
| if(color_knot->unified_knot!=NULL) |
| { |
| cnt=color_knot->unified_nknots; |
| for(t_min=0;t_min<cnt;t_min++) |
| if(fabs((color_knot->unified_knot)[t_min] - maximal_min_knot) < |
| EPSILON) |
| break; |
| for(t_max=cnt-1;t_max;t_max--) |
| if(fabs((color_knot->unified_knot)[t_max] - minimal_max_knot) < |
| EPSILON) |
| break; |
| color_knot->t_min=t_min; |
| color_knot->t_max=t_max; |
| } |
| if(normal_knot->unified_knot!=NULL) |
| { |
| cnt=normal_knot->unified_nknots; |
| for(t_min=0;t_min<cnt;t_min++) |
| if(fabs((normal_knot->unified_knot)[t_min] - maximal_min_knot) < |
| EPSILON) |
| break; |
| for(t_max=cnt-1;t_max;t_max--) |
| if(fabs((normal_knot->unified_knot)[t_max] - minimal_max_knot) < |
| EPSILON) |
| break; |
| normal_knot->t_min=t_min; |
| normal_knot->t_max=t_max; |
| } |
| if(texture_knot->unified_knot!=NULL) |
| { |
| cnt=texture_knot->unified_nknots; |
| for(t_min=0;t_min<cnt;t_min++) |
| if(fabs((texture_knot->unified_knot)[t_min] - maximal_min_knot) |
| < EPSILON) |
| break; |
| for(t_max=cnt-1;t_max;t_max--) |
| if(fabs((texture_knot->unified_knot)[t_max] - minimal_max_knot) |
| < EPSILON) |
| break; |
| texture_knot->t_min=t_min; |
| texture_knot->t_max=t_max; |
| } |
| } |
| } |
| |
| /* modify all knot valid ranges in such a way that all have the same */ |
| /* range, common to all knots */ |
| /* do this by knot insertion */ |
| GLenum |
| select_knot_working_range(GLUnurbsObj *nobj,knot_str_type *geom_knot, |
| knot_str_type *color_knot, knot_str_type *normal_knot, |
| knot_str_type *texture_knot) |
| { |
| GLint max_nknots; |
| GLfloat maximal_min_knot,minimal_max_knot; |
| GLint i; |
| |
| /* find the maximum modified knot length */ |
| max_nknots=geom_knot->nknots; |
| if(color_knot->unified_knot) |
| max_nknots+=color_knot->nknots; |
| if(normal_knot->unified_knot) |
| max_nknots+=normal_knot->nknots; |
| if(texture_knot->unified_knot) |
| max_nknots+=texture_knot->nknots; |
| maximal_min_knot=(geom_knot->knot)[geom_knot->t_min]; |
| minimal_max_knot=(geom_knot->knot)[geom_knot->t_max]; |
| /* any attirb data ? */ |
| if(max_nknots!=geom_knot->nknots) |
| { |
| /* allocate space for the unified knots */ |
| if((geom_knot->unified_knot= |
| (GLfloat *)malloc(sizeof(GLfloat)*max_nknots))==NULL) |
| { |
| call_user_error(nobj,GLU_OUT_OF_MEMORY); |
| return GLU_ERROR; |
| } |
| /* copy the original knot to the unified one */ |
| geom_knot->unified_nknots=geom_knot->nknots; |
| for(i=0;i<geom_knot->nknots;i++) |
| (geom_knot->unified_knot)[i]=(geom_knot->knot)[i]; |
| if(color_knot->unified_knot) |
| { |
| if((color_knot->knot)[color_knot->t_min] - maximal_min_knot > |
| EPSILON) |
| maximal_min_knot=(color_knot->knot)[color_knot->t_min]; |
| if(minimal_max_knot - (color_knot->knot)[color_knot->t_max] > |
| EPSILON) |
| minimal_max_knot=(color_knot->knot)[color_knot->t_max]; |
| if((color_knot->unified_knot= |
| (GLfloat *)malloc(sizeof(GLfloat)*max_nknots))==NULL) |
| { |
| free(geom_knot->unified_knot); |
| call_user_error(nobj,GLU_OUT_OF_MEMORY); |
| return GLU_ERROR; |
| } |
| /* copy the original knot to the unified one */ |
| color_knot->unified_nknots=color_knot->nknots; |
| for(i=0;i<color_knot->nknots;i++) |
| (color_knot->unified_knot)[i]=(color_knot->knot)[i]; |
| } |
| if(normal_knot->unified_knot) |
| { |
| if((normal_knot->knot)[normal_knot->t_min] - maximal_min_knot > |
| EPSILON) |
| maximal_min_knot=(normal_knot->knot)[normal_knot->t_min]; |
| if(minimal_max_knot - (normal_knot->knot)[normal_knot->t_max] > |
| EPSILON) |
| minimal_max_knot=(normal_knot->knot)[normal_knot->t_max]; |
| if((normal_knot->unified_knot= |
| (GLfloat *)malloc(sizeof(GLfloat)*max_nknots))==NULL) |
| { |
| free(geom_knot->unified_knot); |
| free(color_knot->unified_knot); |
| call_user_error(nobj,GLU_OUT_OF_MEMORY); |
| return GLU_ERROR; |
| } |
| /* copy the original knot to the unified one */ |
| normal_knot->unified_nknots=normal_knot->nknots; |
| for(i=0;i<normal_knot->nknots;i++) |
| (normal_knot->unified_knot)[i]=(normal_knot->knot)[i]; |
| } |
| if(texture_knot->unified_knot) |
| { |
| if((texture_knot->knot)[texture_knot->t_min] - maximal_min_knot > |
| EPSILON) |
| maximal_min_knot=(texture_knot->knot)[texture_knot->t_min]; |
| if(minimal_max_knot - (texture_knot->knot)[texture_knot->t_max] > |
| EPSILON) |
| minimal_max_knot=(texture_knot->knot)[texture_knot->t_max]; |
| if((texture_knot->unified_knot= |
| (GLfloat *)malloc(sizeof(GLfloat)*max_nknots))==NULL) |
| { |
| free(geom_knot->unified_knot); |
| free(color_knot->unified_knot); |
| free(normal_knot->unified_knot); |
| call_user_error(nobj,GLU_OUT_OF_MEMORY); |
| return GLU_ERROR; |
| } |
| /* copy the original knot to the unified one */ |
| texture_knot->unified_nknots=texture_knot->nknots; |
| for(i=0;i<texture_knot->nknots;i++) |
| (texture_knot->unified_knot)[i]=(texture_knot->knot)[i]; |
| } |
| /* work on the geometry knot with all additional knot values */ |
| /* appearing in attirbutive knots */ |
| if(minimal_max_knot-maximal_min_knot < EPSILON) |
| { |
| /* empty working range */ |
| geom_knot->unified_nknots=0; |
| color_knot->unified_nknots=0; |
| normal_knot->unified_nknots=0; |
| texture_knot->unified_nknots=0; |
| } |
| else |
| { |
| if(color_knot->unified_knot) |
| collect_unified_knot(geom_knot,color_knot,maximal_min_knot, |
| minimal_max_knot); |
| if(normal_knot->unified_knot) |
| collect_unified_knot(geom_knot,normal_knot,maximal_min_knot, |
| minimal_max_knot); |
| if(texture_knot->unified_knot) |
| collect_unified_knot(geom_knot,texture_knot,maximal_min_knot, |
| minimal_max_knot); |
| /* since we have now built the "unified" geometry knot */ |
| /* add same knot values to all attributive knots */ |
| if(color_knot->unified_knot) |
| collect_unified_knot(color_knot,geom_knot,maximal_min_knot, |
| minimal_max_knot); |
| if(normal_knot->unified_knot) |
| collect_unified_knot(normal_knot,geom_knot,maximal_min_knot, |
| minimal_max_knot); |
| if(texture_knot->unified_knot) |
| collect_unified_knot(texture_knot,geom_knot,maximal_min_knot, |
| minimal_max_knot); |
| } |
| } |
| set_new_t_min_t_max(geom_knot,color_knot,normal_knot,texture_knot, |
| maximal_min_knot,minimal_max_knot); |
| return GLU_NO_ERROR; |
| } |
| |
| void |
| free_unified_knots(knot_str_type *geom_knot, knot_str_type *color_knot, |
| knot_str_type *normal_knot, knot_str_type *texture_knot) |
| { |
| if(geom_knot->unified_knot) |
| free(geom_knot->unified_knot); |
| if(color_knot->unified_knot) |
| free(color_knot->unified_knot); |
| if(normal_knot->unified_knot) |
| free(normal_knot->unified_knot); |
| if(texture_knot->unified_knot) |
| free(texture_knot->unified_knot); |
| } |
| |
| GLenum |
| explode_knot(knot_str_type *the_knot) |
| { |
| GLfloat *knot,*new_knot; |
| GLint nknots,n_new_knots=0; |
| GLint t_min,t_max; |
| GLint ord; |
| GLsizei i,j,k; |
| GLfloat tmp_float; |
| |
| if(the_knot->unified_knot) |
| { |
| knot=the_knot->unified_knot; |
| nknots=the_knot->unified_nknots; |
| } |
| else |
| { |
| knot=the_knot->knot; |
| nknots=the_knot->nknots; |
| } |
| ord=the_knot->order; |
| t_min=the_knot->t_min; |
| t_max=the_knot->t_max; |
| |
| for(i=t_min;i<=t_max;) |
| { |
| tmp_float=knot[i]; |
| for(j=0;j<ord && (i+j)<=t_max;j++) |
| if(fabs(tmp_float-knot[i+j])>EPSILON) |
| break; |
| n_new_knots+=ord-j; |
| i+=j; |
| } |
| /* alloc space for new_knot */ |
| if((new_knot=(GLfloat *)malloc(sizeof(GLfloat)*(nknots+n_new_knots)))==NULL) |
| { |
| return GLU_OUT_OF_MEMORY; |
| } |
| /* fill in new knot */ |
| for(j=0;j<t_min;j++) |
| new_knot[j]=knot[j]; |
| for(i=j;i<=t_max;i++) |
| { |
| tmp_float=knot[i]; |
| for(k=0;k<ord;k++) |
| { |
| new_knot[j++]=knot[i]; |
| if(tmp_float==knot[i+1]) |
| i++; |
| } |
| } |
| for(i=t_max+1;i<(int)nknots;i++) |
| new_knot[j++]=knot[i]; |
| /* fill in the knot structure */ |
| the_knot->new_knot=new_knot; |
| the_knot->delta_nknots+=n_new_knots; |
| the_knot->t_max+=n_new_knots; |
| return GLU_NO_ERROR; |
| } |
| |
| GLenum |
| calc_alphas(knot_str_type *the_knot) |
| { |
| GLfloat tmp_float; |
| int i,j,k,m,n; |
| int order; |
| GLfloat *alpha,*alpha_new,*tmp_alpha; |
| GLfloat denom; |
| GLfloat *knot,*new_knot; |
| |
| |
| knot=the_knot->knot; |
| order=the_knot->order; |
| new_knot=the_knot->new_knot; |
| n=the_knot->nknots-the_knot->order; |
| m=n+the_knot->delta_nknots; |
| if((alpha=(GLfloat *)malloc(sizeof(GLfloat)*n*m))==NULL) |
| { |
| return GLU_OUT_OF_MEMORY; |
| } |
| if((alpha_new=(GLfloat *)malloc(sizeof(GLfloat)*n*m))==NULL) |
| { |
| free(alpha); |
| return GLU_OUT_OF_MEMORY; |
| } |
| for(j=0;j<m;j++) |
| { |
| for(i=0;i<n;i++) |
| { |
| if((knot[i] <= new_knot[j]) && (new_knot[j] < knot[i+1])) |
| tmp_float=1.0; |
| else |
| tmp_float=0.0; |
| alpha[i+j*n]=tmp_float; |
| } |
| } |
| for(k=1;k<order;k++) |
| { |
| for(j=0;j<m;j++) |
| for(i=0;i<n;i++) |
| { |
| denom=knot[i+k]-knot[i]; |
| if(fabs(denom)<EPSILON) |
| tmp_float=0.0; |
| else |
| tmp_float=(new_knot[j+k]-knot[i])/denom* |
| alpha[i+j*n]; |
| denom=knot[i+k+1]-knot[i+1]; |
| if(fabs(denom)>EPSILON) |
| tmp_float+=(knot[i+k+1]-new_knot[j+k])/denom* |
| alpha[(i+1)+j*n]; |
| alpha_new[i+j*n]=tmp_float; |
| } |
| tmp_alpha=alpha_new; |
| alpha_new=alpha; |
| alpha=tmp_alpha; |
| } |
| the_knot->alpha=alpha; |
| free(alpha_new); |
| return GLU_NO_ERROR; |
| } |
| |
| GLenum |
| calc_new_ctrl_pts(GLfloat *ctrl,GLint stride,knot_str_type *the_knot, |
| GLint dim,GLfloat **new_ctrl,GLint *ncontrol) |
| { |
| GLsizei i,j,k,l,m,n; |
| GLsizei index1,index2; |
| GLfloat *alpha; |
| GLfloat *new_knot; |
| |
| new_knot=the_knot->new_knot; |
| n=the_knot->nknots-the_knot->order; |
| alpha=the_knot->alpha; |
| |
| m=the_knot->t_max+1-the_knot->t_min-the_knot->order; |
| k=the_knot->t_min; |
| /* allocate space for new control points */ |
| if((*new_ctrl=(GLfloat *)malloc(sizeof(GLfloat)*dim*m))==NULL) |
| { |
| return GLU_OUT_OF_MEMORY; |
| } |
| for(j=0;j<m;j++) |
| { |
| for(l=0;l<dim;l++) |
| (*new_ctrl)[j*dim+l]=0.0; |
| for(i=0;i<n;i++) |
| { |
| index1=i+(j+k)*n; |
| index2=i*stride; |
| for(l=0;l<dim;l++) |
| (*new_ctrl)[j*dim+l]+=alpha[index1]*ctrl[index2+l]; |
| } |
| } |
| *ncontrol=(GLint)m; |
| return GLU_NO_ERROR; |
| } |
| |
| static GLint |
| calc_factor(GLfloat *pts,GLint order,GLint indx,GLint stride,GLfloat tolerance, |
| GLint dim) |
| { |
| GLdouble model[16],proj[16]; |
| GLint viewport[4]; |
| GLdouble x,y,z,w,winx1,winy1,winz,winx2,winy2; |
| GLint i; |
| GLdouble len,dx,dy; |
| |
| glGetDoublev(GL_MODELVIEW_MATRIX,model); |
| glGetDoublev(GL_PROJECTION_MATRIX,proj); |
| glGetIntegerv(GL_VIEWPORT,viewport); |
| if(dim==4) |
| { |
| w=(GLdouble)pts[indx+3]; |
| x=(GLdouble)pts[indx]/w; |
| y=(GLdouble)pts[indx+1]/w; |
| z=(GLdouble)pts[indx+2]/w; |
| gluProject(x,y,z,model,proj,viewport,&winx1,&winy1,&winz); |
| len=0.0; |
| for(i=1;i<order;i++) |
| { |
| w=(GLdouble)pts[indx+i*stride+3]; |
| x=(GLdouble)pts[indx+i*stride]/w; |
| y=(GLdouble)pts[indx+i*stride+1]/w; |
| z=(GLdouble)pts[indx+i*stride+2]/w; |
| if(gluProject(x,y,z,model,proj,viewport,&winx2,&winy2,&winz)) |
| { |
| dx=winx2-winx1; |
| dy=winy2-winy1; |
| len+=sqrt(dx*dx+dy*dy); |
| } |
| winx1=winx2; winy1=winy2; |
| } |
| } |
| else |
| { |
| x=(GLdouble)pts[indx]; |
| y=(GLdouble)pts[indx+1]; |
| if(dim==2) |
| z=0.0; |
| else |
| z=(GLdouble)pts[indx+2]; |
| gluProject(x,y,z,model,proj,viewport,&winx1,&winy1,&winz); |
| len=0.0; |
| for(i=1;i<order;i++) |
| { |
| x=(GLdouble)pts[indx+i*stride]; |
| y=(GLdouble)pts[indx+i*stride+1]; |
| if(dim==2) |
| z=0.0; |
| else |
| z=(GLdouble)pts[indx+i*stride+2]; |
| if(gluProject(x,y,z,model,proj,viewport,&winx2,&winy2,&winz)) |
| { |
| dx=winx2-winx1; |
| dy=winy2-winy1; |
| len+=sqrt(dx*dx+dy*dy); |
| } |
| winx1=winx2; winy1=winy2; |
| } |
| } |
| len /= tolerance; |
| return ((GLint)len+1); |
| } |
| |
| /* we can't use the Mesa evaluators - no way to get the point coords */ |
| /* so we use our own Bezier point calculus routines */ |
| /* because I'm lazy, I reuse the ones from eval.c */ |
| |
| static void |
| bezier_curve(GLfloat *cp, GLfloat *out, GLfloat t, |
| GLuint dim, GLuint order, GLint offset) |
| { |
| GLfloat s, powert; |
| GLuint i, k, bincoeff; |
| |
| if(order >= 2) |
| { |
| bincoeff = order-1; |
| s = 1.0-t; |
| |
| for(k=0; k<dim; k++) |
| out[k] = s*cp[k] + bincoeff*t*cp[offset+k]; |
| |
| for(i=2, cp+=2*offset, powert=t*t; i<order; i++, powert*=t, cp +=offset) |
| { |
| bincoeff *= order-i; |
| bincoeff /= i; |
| |
| for(k=0; k<dim; k++) |
| out[k] = s*out[k] + bincoeff*powert*cp[k]; |
| } |
| } |
| else /* order=1 -> constant curve */ |
| { |
| for(k=0; k<dim; k++) |
| out[k] = cp[k]; |
| } |
| } |
| |
| static GLint |
| calc_parametric_factor(GLfloat *pts,GLint order,GLint indx,GLint stride, |
| GLfloat tolerance,GLint dim) |
| { |
| GLdouble model[16],proj[16]; |
| GLint viewport[4]; |
| GLdouble x,y,z,w,x1,y1,z1,x2,y2,z2,x3,y3,z3; |
| GLint i; |
| GLint P; |
| GLfloat bez_pt[4]; |
| GLdouble len=0.0,tmp,z_med; |
| |
| P = 2*(order+2); |
| glGetDoublev(GL_MODELVIEW_MATRIX,model); |
| glGetDoublev(GL_PROJECTION_MATRIX,proj); |
| glGetIntegerv(GL_VIEWPORT,viewport); |
| z_med = (viewport[2] + viewport[3]) * 0.5; |
| switch(dim) |
| { |
| case 4: |
| for(i=1;i<P;i++) |
| { |
| bezier_curve(pts+indx, bez_pt, (GLfloat)i/(GLfloat)P, 4, |
| order,stride); |
| w = (GLdouble)bez_pt[3]; |
| x = (GLdouble)bez_pt[0] / w; |
| y = (GLdouble)bez_pt[1] / w; |
| z = (GLdouble)bez_pt[2] / w; |
| gluProject(x,y,z,model,proj,viewport,&x3,&y3,&z3); |
| z3 *= z_med; |
| bezier_curve(pts+indx, bez_pt, (GLfloat)(i-1)/(GLfloat)P, 4, |
| order,stride); |
| w = (GLdouble)bez_pt[3]; |
| x = (GLdouble)bez_pt[0] / w; |
| y = (GLdouble)bez_pt[1] / w; |
| z = (GLdouble)bez_pt[2] / w; |
| gluProject(x,y,z,model,proj,viewport,&x1,&y1,&z1); |
| z1 *= z_med; |
| bezier_curve(pts+indx, bez_pt, (GLfloat)(i+1)/(GLfloat)P, 4, |
| order,stride); |
| w = (GLdouble)bez_pt[3]; |
| x = (GLdouble)bez_pt[0] / w; |
| y = (GLdouble)bez_pt[1] / w; |
| z = (GLdouble)bez_pt[2] / w; |
| gluProject(x,y,z,model,proj,viewport,&x2,&y2,&z2); |
| z2 *= z_med; |
| /* calc distance between point (x3,y3,z3) and line segment */ |
| /* <x1,y1,z1><x2,y2,z2> */ |
| x = x2-x1; |
| y = y2-y1; |
| z = z2-z1; |
| tmp = sqrt(x*x+y*y+z*z); |
| x /= tmp; |
| y /= tmp; |
| z /= tmp; |
| tmp = x3*x+y3*y+z3*z-x1*x-y1*y-z1*z; |
| x = x1+x*tmp-x3; |
| y = y1+y*tmp-y3; |
| z = z1+z*tmp-z3; |
| tmp = sqrt(x*x+y*y+z*z); |
| if(tmp > len) |
| len = tmp; |
| } |
| break; |
| case 3: |
| for(i=1;i<P;i++) |
| { |
| bezier_curve(pts+indx, bez_pt, (GLfloat)i/(GLfloat)P, 3, |
| order,stride); |
| x = (GLdouble)bez_pt[0]; |
| y = (GLdouble)bez_pt[1]; |
| z = (GLdouble)bez_pt[2]; |
| gluProject(x,y,z,model,proj,viewport,&x3,&y3,&z3); |
| z3 *= z_med; |
| bezier_curve(pts+indx, bez_pt, (GLfloat)(i-1)/(GLfloat)P, 3, |
| order,stride); |
| x = (GLdouble)bez_pt[0]; |
| y = (GLdouble)bez_pt[1]; |
| z = (GLdouble)bez_pt[2]; |
| gluProject(x,y,z,model,proj,viewport,&x1,&y1,&z1); |
| z1 *= z_med; |
| bezier_curve(pts+indx, bez_pt, (GLfloat)(i+1)/(GLfloat)P, 3, |
| order,stride); |
| x = (GLdouble)bez_pt[0]; |
| y = (GLdouble)bez_pt[1]; |
| z = (GLdouble)bez_pt[2]; |
| gluProject(x,y,z,model,proj,viewport,&x2,&y2,&z2); |
| z2 *= z_med; |
| /* calc distance between point (x3,y3,z3) and line segment */ |
| /* <x1,y1,z1><x2,y2,z2> */ |
| x = x2-x1; |
| y = y2-y1; |
| z = z2-z1; |
| tmp = sqrt(x*x+y*y+z*z); |
| x /= tmp; |
| y /= tmp; |
| z /= tmp; |
| tmp = x3*x+y3*y+z3*z-x1*x-y1*y-z1*z; |
| x = x1+x*tmp-x3; |
| y = y1+y*tmp-y3; |
| z = z1+z*tmp-z3; |
| tmp = sqrt(x*x+y*y+z*z); |
| if(tmp > len) |
| len = tmp; |
| } |
| break; |
| case 2: |
| for(i=1;i<P;i++) |
| { |
| bezier_curve(pts+indx, bez_pt, (GLfloat)i/(GLfloat)P, 2, |
| order,stride); |
| x = (GLdouble)bez_pt[0]; |
| y = (GLdouble)bez_pt[1]; |
| z = 0.0; |
| gluProject(x,y,z,model,proj,viewport,&x3,&y3,&z3); |
| z3 *= z_med; |
| bezier_curve(pts+indx, bez_pt, (GLfloat)(i-1)/(GLfloat)P, 2, |
| order,stride); |
| x = (GLdouble)bez_pt[0]; |
| y = (GLdouble)bez_pt[1]; |
| z = 0.0; |
| gluProject(x,y,z,model,proj,viewport,&x1,&y1,&z1); |
| z1 *= z_med; |
| bezier_curve(pts+indx, bez_pt, (GLfloat)(i+1)/(GLfloat)P, 2, |
| order,stride); |
| x = (GLdouble)bez_pt[0]; |
| y = (GLdouble)bez_pt[1]; |
| z = 0.0; |
| gluProject(x,y,z,model,proj,viewport,&x2,&y2,&z2); |
| z2 *= z_med; |
| /* calc distance between point (x3,y3,z3) and line segment */ |
| /* <x1,y1,z1><x2,y2,z2> */ |
| x = x2-x1; |
| y = y2-y1; |
| z = z2-z1; |
| tmp = sqrt(x*x+y*y+z*z); |
| x /= tmp; |
| y /= tmp; |
| z /= tmp; |
| tmp = x3*x+y3*y+z3*z-x1*x-y1*y-z1*z; |
| x = x1+x*tmp-x3; |
| y = y1+y*tmp-y3; |
| z = z1+z*tmp-z3; |
| tmp = sqrt(x*x+y*y+z*z); |
| if(tmp > len) |
| len = tmp; |
| } |
| break; |
| |
| } |
| if(len < tolerance) |
| return (order); |
| else |
| return (GLint)(sqrt(len/tolerance)*(order+2)+1); |
| } |
| |
| static GLenum |
| calc_sampling_3D(new_ctrl_type *new_ctrl, GLfloat tolerance, GLint dim, |
| GLint uorder, GLint vorder, GLint **ufactors, GLint **vfactors) |
| { |
| GLfloat *ctrl; |
| GLint tmp_factor1,tmp_factor2; |
| GLint ufactor_cnt,vfactor_cnt; |
| GLint offset1,offset2,offset3; |
| GLint i,j; |
| |
| ufactor_cnt=new_ctrl->s_bezier_cnt; |
| vfactor_cnt=new_ctrl->t_bezier_cnt; |
| if((*ufactors=(GLint *)malloc(sizeof(GLint)*ufactor_cnt*3)) |
| ==NULL) |
| { |
| return GLU_OUT_OF_MEMORY; |
| } |
| if((*vfactors=(GLint *)malloc(sizeof(GLint)*vfactor_cnt*3)) |
| ==NULL) |
| { |
| free(*ufactors); |
| return GLU_OUT_OF_MEMORY; |
| } |
| ctrl=new_ctrl->geom_ctrl; |
| offset1=new_ctrl->geom_t_stride*vorder; |
| offset2=new_ctrl->geom_s_stride*uorder; |
| for(j=0;j<vfactor_cnt;j++) |
| { |
| *(*vfactors+j*3+1)=tmp_factor1=calc_factor(ctrl,vorder, |
| j*offset1,dim,tolerance,dim); |
| /* loop ufactor_cnt-1 times */ |
| for(i=1;i<ufactor_cnt;i++) |
| { |
| tmp_factor2=calc_factor(ctrl,vorder, |
| j*offset1+i*offset2,dim,tolerance,dim); |
| if(tmp_factor2>tmp_factor1) |
| tmp_factor1=tmp_factor2; |
| } |
| /* last time for the opposite edge */ |
| *(*vfactors+j*3+2)=tmp_factor2=calc_factor(ctrl,vorder, |
| j*offset1+i*offset2-new_ctrl->geom_s_stride, |
| dim,tolerance,dim); |
| if(tmp_factor2>tmp_factor1) |
| *(*vfactors+j*3)=tmp_factor2; |
| else |
| *(*vfactors+j*3)=tmp_factor1; |
| } |
| offset3=new_ctrl->geom_s_stride; |
| offset2=new_ctrl->geom_s_stride*uorder; |
| for(j=0;j<ufactor_cnt;j++) |
| { |
| *(*ufactors+j*3+1)=tmp_factor1=calc_factor(ctrl,uorder, |
| j*offset2,offset3,tolerance,dim); |
| /* loop vfactor_cnt-1 times */ |
| for(i=1;i<vfactor_cnt;i++) |
| { |
| tmp_factor2=calc_factor(ctrl,uorder, |
| j*offset2+i*offset1,offset3,tolerance,dim); |
| if(tmp_factor2>tmp_factor1) |
| tmp_factor1=tmp_factor2; |
| } |
| /* last time for the opposite edge */ |
| *(*ufactors+j*3+2)=tmp_factor2=calc_factor(ctrl,uorder, |
| j*offset2+i*offset1-new_ctrl->geom_t_stride, |
| offset3,tolerance,dim); |
| if(tmp_factor2>tmp_factor1) |
| *(*ufactors+j*3)=tmp_factor2; |
| else |
| *(*ufactors+j*3)=tmp_factor1; |
| } |
| return GL_NO_ERROR; |
| } |
| |
| static GLenum |
| calc_sampling_param_3D(new_ctrl_type *new_ctrl, GLfloat tolerance, GLint dim, |
| GLint uorder, GLint vorder, GLint **ufactors, GLint **vfactors) |
| { |
| GLfloat *ctrl; |
| GLint tmp_factor1,tmp_factor2; |
| GLint ufactor_cnt,vfactor_cnt; |
| GLint offset1,offset2,offset3; |
| GLint i,j; |
| |
| ufactor_cnt=new_ctrl->s_bezier_cnt; |
| vfactor_cnt=new_ctrl->t_bezier_cnt; |
| if((*ufactors=(GLint *)malloc(sizeof(GLint)*ufactor_cnt*3)) |
| ==NULL) |
| { |
| return GLU_OUT_OF_MEMORY; |
| } |
| if((*vfactors=(GLint *)malloc(sizeof(GLint)*vfactor_cnt*3)) |
| ==NULL) |
| { |
| free(*ufactors); |
| return GLU_OUT_OF_MEMORY; |
| } |
| ctrl=new_ctrl->geom_ctrl; |
| offset1=new_ctrl->geom_t_stride*vorder; |
| offset2=new_ctrl->geom_s_stride*uorder; |
| for(j=0;j<vfactor_cnt;j++) |
| { |
| *(*vfactors+j*3+1)=tmp_factor1=calc_parametric_factor(ctrl,vorder, |
| j*offset1,dim,tolerance,dim); |
| /* loop ufactor_cnt-1 times */ |
| for(i=1;i<ufactor_cnt;i++) |
| { |
| tmp_factor2=calc_parametric_factor(ctrl,vorder, |
| j*offset1+i*offset2,dim,tolerance,dim); |
| if(tmp_factor2>tmp_factor1) |
| tmp_factor1=tmp_factor2; |
| } |
| /* last time for the opposite edge */ |
| *(*vfactors+j*3+2)=tmp_factor2=calc_parametric_factor(ctrl,vorder, |
| j*offset1+i*offset2-new_ctrl->geom_s_stride, |
| dim,tolerance,dim); |
| if(tmp_factor2>tmp_factor1) |
| *(*vfactors+j*3)=tmp_factor2; |
| else |
| *(*vfactors+j*3)=tmp_factor1; |
| } |
| offset3=new_ctrl->geom_s_stride; |
| offset2=new_ctrl->geom_s_stride*uorder; |
| for(j=0;j<ufactor_cnt;j++) |
| { |
| *(*ufactors+j*3+1)=tmp_factor1=calc_parametric_factor(ctrl,uorder, |
| j*offset2,offset3,tolerance,dim); |
| /* loop vfactor_cnt-1 times */ |
| for(i=1;i<vfactor_cnt;i++) |
| { |
| tmp_factor2=calc_parametric_factor(ctrl,uorder, |
| j*offset2+i*offset1,offset3,tolerance,dim); |
| if(tmp_factor2>tmp_factor1) |
| tmp_factor1=tmp_factor2; |
| } |
| /* last time for the opposite edge */ |
| *(*ufactors+j*3+2)=tmp_factor2=calc_parametric_factor(ctrl,uorder, |
| j*offset2+i*offset1-new_ctrl->geom_t_stride, |
| offset3,tolerance,dim); |
| if(tmp_factor2>tmp_factor1) |
| *(*ufactors+j*3)=tmp_factor2; |
| else |
| *(*ufactors+j*3)=tmp_factor1; |
| } |
| return GL_NO_ERROR; |
| } |
| |
| static GLenum |
| calc_sampling_2D(GLfloat *ctrl, GLint cnt, GLint order, |
| GLfloat tolerance, GLint dim, GLint **factors) |
| { |
| GLint factor_cnt; |
| GLint tmp_factor; |
| GLint offset; |
| GLint i; |
| |
| factor_cnt=cnt/order; |
| if((*factors=(GLint *)malloc(sizeof(GLint)*factor_cnt))==NULL) |
| { |
| return GLU_OUT_OF_MEMORY; |
| } |
| offset=order*dim; |
| for(i=0;i<factor_cnt;i++) |
| { |
| tmp_factor=calc_factor(ctrl,order,i*offset,dim,tolerance,dim); |
| if(tmp_factor == 0) |
| (*factors)[i]=1; |
| else |
| (*factors)[i]=tmp_factor; |
| } |
| return GL_NO_ERROR; |
| } |
| |
| static void |
| set_sampling_and_culling( GLUnurbsObj *nobj ) |
| { |
| if(nobj->auto_load_matrix==GL_FALSE) |
| { |
| GLint i; |
| GLfloat m[4]; |
| |
| glPushAttrib( (GLbitfield) (GL_VIEWPORT_BIT | GL_TRANSFORM_BIT)); |
| for(i=0;i<4;i++) |
| m[i]=nobj->sampling_matrices.viewport[i]; |
| glViewport(m[0],m[1],m[2],m[3]); |
| glMatrixMode(GL_PROJECTION); |
| glPushMatrix(); |
| glLoadMatrixf(nobj->sampling_matrices.proj); |
| glMatrixMode(GL_MODELVIEW); |
| glPushMatrix(); |
| glLoadMatrixf(nobj->sampling_matrices.model); |
| } |
| } |
| |
| static void |
| revert_sampling_and_culling( GLUnurbsObj *nobj ) |
| { |
| if(nobj->auto_load_matrix==GL_FALSE) |
| { |
| glMatrixMode(GL_MODELVIEW); |
| glPopMatrix(); |
| glMatrixMode(GL_PROJECTION); |
| glPopMatrix(); |
| glPopAttrib(); |
| } |
| } |
| |
| GLenum |
| glu_do_sampling_3D( GLUnurbsObj *nobj, new_ctrl_type *new_ctrl, |
| GLint **sfactors, GLint **tfactors) |
| { |
| GLint dim; |
| GLenum err; |
| |
| *sfactors=NULL; |
| *tfactors=NULL; |
| dim=nobj->surface.geom.dim; |
| set_sampling_and_culling(nobj); |
| if((err=calc_sampling_3D(new_ctrl,nobj->sampling_tolerance,dim, |
| nobj->surface.geom.sorder,nobj->surface.geom.torder, |
| sfactors,tfactors))==GLU_ERROR) |
| { |
| revert_sampling_and_culling(nobj); |
| call_user_error(nobj,err); |
| return GLU_ERROR; |
| } |
| revert_sampling_and_culling(nobj); |
| return GLU_NO_ERROR; |
| } |
| |
| GLenum |
| glu_do_sampling_uv( GLUnurbsObj *nobj, new_ctrl_type *new_ctrl, |
| GLint **sfactors, GLint **tfactors) |
| { |
| GLint s_cnt, t_cnt, i; |
| GLint u_steps, v_steps; |
| |
| s_cnt = new_ctrl->s_bezier_cnt; |
| t_cnt = new_ctrl->t_bezier_cnt; |
| *sfactors=NULL; |
| *tfactors=NULL; |
| if((*sfactors=(GLint *)malloc(sizeof(GLint)*s_cnt*3)) |
| ==NULL) |
| { |
| return GLU_OUT_OF_MEMORY; |
| } |
| if((*tfactors=(GLint *)malloc(sizeof(GLint)*t_cnt*3)) |
| ==NULL) |
| { |
| free(*sfactors); |
| return GLU_OUT_OF_MEMORY; |
| } |
| u_steps = nobj->u_step; |
| v_steps = nobj->v_step; |
| for(i=0; i<s_cnt; i++) |
| { |
| *(*sfactors+i*3) = u_steps; |
| *(*sfactors+i*3+1) = u_steps; |
| *(*sfactors+i*3+2) = u_steps; |
| } |
| for(i=0; i<t_cnt; i++) |
| { |
| *(*tfactors+i*3) = v_steps; |
| *(*tfactors+i*3+1) = v_steps; |
| *(*tfactors+i*3+2) = v_steps; |
| } |
| return GLU_NO_ERROR; |
| } |
| |
| GLenum |
| glu_do_sampling_param_3D( GLUnurbsObj *nobj, new_ctrl_type *new_ctrl, |
| GLint **sfactors, GLint **tfactors) |
| { |
| GLint dim; |
| GLenum err; |
| |
| *sfactors=NULL; |
| *tfactors=NULL; |
| dim=nobj->surface.geom.dim; |
| set_sampling_and_culling(nobj); |
| if((err=calc_sampling_param_3D(new_ctrl,nobj->parametric_tolerance,dim, |
| nobj->surface.geom.sorder,nobj->surface.geom.torder, |
| sfactors,tfactors))==GLU_ERROR) |
| { |
| revert_sampling_and_culling(nobj); |
| call_user_error(nobj,err); |
| return GLU_ERROR; |
| } |
| revert_sampling_and_culling(nobj); |
| return GLU_NO_ERROR; |
| } |
| |
| GLenum |
| glu_do_sampling_2D( GLUnurbsObj *nobj, GLfloat *ctrl, GLint cnt, GLint order, |
| GLint dim, GLint **factors) |
| { |
| GLenum err; |
| |
| set_sampling_and_culling(nobj); |
| err=calc_sampling_2D(ctrl,cnt,order,nobj->sampling_tolerance,dim, |
| factors); |
| revert_sampling_and_culling(nobj); |
| return err; |
| } |
| |
| |
| GLenum |
| glu_do_sampling_u( GLUnurbsObj *nobj, GLfloat *ctrl, GLint cnt, GLint order, |
| GLint dim, GLint **factors) |
| { |
| GLint i; |
| GLint u_steps; |
| |
| cnt /= order; |
| if((*factors=(GLint *)malloc(sizeof(GLint)*cnt)) |
| ==NULL) |
| { |
| return GLU_OUT_OF_MEMORY; |
| } |
| u_steps = nobj->u_step; |
| for(i=0; i<cnt; i++) |
| (*factors)[i] = u_steps; |
| return GLU_NO_ERROR; |
| } |
| |
| GLenum |
| glu_do_sampling_param_2D( GLUnurbsObj *nobj, GLfloat *ctrl, GLint cnt, |
| GLint order, GLint dim, GLint **factors) |
| { |
| GLint i; |
| GLint u_steps; |
| GLfloat tolerance; |
| |
| set_sampling_and_culling(nobj); |
| tolerance = nobj->parametric_tolerance; |
| cnt /= order; |
| if((*factors=(GLint *)malloc(sizeof(GLint)*cnt)) |
| ==NULL) |
| { |
| revert_sampling_and_culling(nobj); |
| return GLU_OUT_OF_MEMORY; |
| } |
| u_steps = nobj->u_step; |
| for(i=0; i<cnt; i++) |
| { |
| (*factors)[i] = calc_parametric_factor(ctrl,order,0, |
| dim,tolerance,dim); |
| |
| } |
| revert_sampling_and_culling(nobj); |
| return GLU_NO_ERROR; |
| } |
| |
| GLenum |
| glu_do_sampling_crv( GLUnurbsObj *nobj, GLfloat *ctrl, GLint cnt, GLint order, |
| GLint dim, GLint **factors) |
| { |
| GLenum err; |
| |
| *factors=NULL; |
| switch(nobj->sampling_method) |
| { |
| case GLU_PATH_LENGTH: |
| if((err=glu_do_sampling_2D(nobj,ctrl,cnt,order,dim,factors))!= |
| GLU_NO_ERROR) |
| { |
| call_user_error(nobj,err); |
| return GLU_ERROR; |
| } |
| break; |
| case GLU_DOMAIN_DISTANCE: |
| if((err=glu_do_sampling_u(nobj,ctrl,cnt,order,dim,factors))!= |
| GLU_NO_ERROR) |
| { |
| call_user_error(nobj,err); |
| return GLU_ERROR; |
| } |
| break; |
| case GLU_PARAMETRIC_ERROR: |
| if((err=glu_do_sampling_param_2D(nobj,ctrl,cnt,order,dim,factors))!= |
| GLU_NO_ERROR) |
| { |
| call_user_error(nobj,err); |
| return GLU_ERROR; |
| } |
| break; |
| default: |
| abort(); |
| } |
| |
| return GLU_NO_ERROR; |
| } |
| |
| /* TODO - i don't like this culling - this one just tests if at least one */ |
| /* ctrl point lies within the viewport . Also the point_in_viewport() */ |
| /* should be included in the fnctions for efficiency reasons */ |
| |
| static GLboolean |
| point_in_viewport(GLfloat *pt, GLint dim) |
| { |
| GLdouble model[16],proj[16]; |
| GLint viewport[4]; |
| GLdouble x,y,z,w,winx,winy,winz; |
| |
| glGetDoublev(GL_MODELVIEW_MATRIX,model); |
| glGetDoublev(GL_PROJECTION_MATRIX,proj); |
| glGetIntegerv(GL_VIEWPORT,viewport); |
| if(dim==3) |
| { |
| x=(GLdouble)pt[0]; |
| y=(GLdouble)pt[1]; |
| z=(GLdouble)pt[2]; |
| gluProject(x,y,z,model,proj,viewport,&winx,&winy,&winz); |
| } |
| else |
| { |
| w=(GLdouble)pt[3]; |
| x=(GLdouble)pt[0]/w; |
| y=(GLdouble)pt[1]/w; |
| z=(GLdouble)pt[2]/w; |
| gluProject(x,y,z,model,proj,viewport,&winx,&winy,&winz); |
| } |
| if((GLint)winx >= viewport[0] && (GLint)winx < viewport[2] && |
| (GLint)winy >= viewport[1] && (GLint)winy < viewport[3]) |
| return GL_TRUE; |
| return GL_FALSE; |
| } |
| |
| GLboolean |
| fine_culling_test_3D(GLUnurbsObj *nobj,GLfloat *pts,GLint s_cnt,GLint t_cnt, |
| GLint s_stride,GLint t_stride, GLint dim) |
| { |
| GLint i,j; |
| |
| if(nobj->culling==GL_FALSE) |
| return GL_FALSE; |
| set_sampling_and_culling(nobj); |
| |
| if(dim==3) |
| { |
| for(i=0;i<s_cnt;i++) |
| for(j=0;j<t_cnt;j++) |
| if(point_in_viewport(pts+i*s_stride+j*t_stride,dim)) |
| { |
| revert_sampling_and_culling(nobj); |
| return GL_FALSE; |
| } |
| } |
| else |
| { |
| for(i=0;i<s_cnt;i++) |
| for(j=0;j<t_cnt;j++) |
| if(point_in_viewport(pts+i*s_stride+j*t_stride,dim)) |
| { |
| revert_sampling_and_culling(nobj); |
| return GL_FALSE; |
| } |
| } |
| revert_sampling_and_culling(nobj); |
| return GL_TRUE; |
| } |
| |
| /*GLboolean |
| fine_culling_test_3D(GLUnurbsObj *nobj,GLfloat *pts,GLint s_cnt,GLint t_cnt, |
| GLint s_stride,GLint t_stride, GLint dim) |
| { |
| GLint visible_cnt; |
| GLfloat feedback_buffer[5]; |
| GLsizei buffer_size; |
| GLint i,j; |
| |
| if(nobj->culling==GL_FALSE) |
| return GL_FALSE; |
| buffer_size=5; |
| set_sampling_and_culling(nobj); |
| |
| glFeedbackBuffer(buffer_size,GL_2D,feedback_buffer); |
| glRenderMode(GL_FEEDBACK); |
| if(dim==3) |
| { |
| for(i=0;i<s_cnt;i++) |
| { |
| glBegin(GL_LINE_LOOP); |
| for(j=0;j<t_cnt;j++) |
| glVertex3fv(pts+i*s_stride+j*t_stride); |
| glEnd(); |
| } |
| for(j=0;j<t_cnt;j++) |
| { |
| glBegin(GL_LINE_LOOP); |
| for(i=0;i<s_cnt;i++) |
| glVertex3fv(pts+i*s_stride+j*t_stride); |
| glEnd(); |
| } |
| } |
| else |
| { |
| for(i=0;i<s_cnt;i++) |
| { |
| glBegin(GL_LINE_LOOP); |
| for(j=0;j<t_cnt;j++) |
| glVertex4fv(pts+i*s_stride+j*t_stride); |
| glEnd(); |
| } |
| for(j=0;j<t_cnt;j++) |
| { |
| glBegin(GL_LINE_LOOP); |
| for(i=0;i<s_cnt;i++) |
| glVertex4fv(pts+i*s_stride+j*t_stride); |
| glEnd(); |
| } |
| } |
| visible_cnt=glRenderMode(GL_RENDER); |
| |
| revert_sampling_and_culling(nobj); |
| return (GLboolean)(visible_cnt==0); |
| }*/ |
| |
| GLboolean |
| fine_culling_test_2D(GLUnurbsObj *nobj,GLfloat *pts,GLint cnt, |
| GLint stride, GLint dim) |
| { |
| GLint i; |
| |
| if(nobj->culling==GL_FALSE) |
| return GL_FALSE; |
| set_sampling_and_culling(nobj); |
| |
| if(dim==3) |
| { |
| for(i=0;i<cnt;i++) |
| if(point_in_viewport(pts+i*stride,dim)) |
| { |
| revert_sampling_and_culling(nobj); |
| return GL_FALSE; |
| } |
| } |
| else |
| { |
| for(i=0;i<cnt;i++) |
| if(point_in_viewport(pts+i*stride,dim)) |
| { |
| revert_sampling_and_culling(nobj); |
| return GL_FALSE; |
| } |
| } |
| revert_sampling_and_culling(nobj); |
| return GL_TRUE; |
| } |
| |
| /*GLboolean |
| fine_culling_test_2D(GLUnurbsObj *nobj,GLfloat *pts,GLint cnt, |
| GLint stride, GLint dim) |
| { |
| GLint visible_cnt; |
| GLfloat feedback_buffer[5]; |
| GLsizei buffer_size; |
| GLint i; |
| |
| if(nobj->culling==GL_FALSE) |
| return GL_FALSE; |
| buffer_size=5; |
| set_sampling_and_culling(nobj); |
| |
| glFeedbackBuffer(buffer_size,GL_2D,feedback_buffer); |
| glRenderMode(GL_FEEDBACK); |
| glBegin(GL_LINE_LOOP); |
| if(dim==3) |
| { |
| for(i=0;i<cnt;i++) |
| glVertex3fv(pts+i*stride); |
| } |
| else |
| { |
| for(i=0;i<cnt;i++) |
| glVertex4fv(pts+i*stride); |
| } |
| glEnd(); |
| visible_cnt=glRenderMode(GL_RENDER); |
| |
| revert_sampling_and_culling(nobj); |
| return (GLboolean)(visible_cnt==0); |
| }*/ |
| |