home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 10
/
aminetcdnumber101996.iso
/
Aminet
/
gfx
/
x11
/
Mesa_Amiwin.lha
/
Mesa-Amiwin
/
src-glu
/
nurbsutl.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-17
|
14KB
|
665 lines
/* nurbsutl.c */
/*
* Mesa 3-D graphics library
* Version: 1.2
* Copyright (C) 1995 Brian Paul (brianp@ssec.wisc.edu)
*
* 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.
*/
/*
$Id: nurbsutl.c,v 1.5 1995/11/03 14:15:13 brianp Exp $
$Log: nurbsutl.c,v $
* Revision 1.5 1995/11/03 14:15:13 brianp
* Bogdan's November 3, 1995 updates
*
* Revision 1.4 1995/09/20 18:25:57 brianp
* removed Bogdan's old email address
*
* Revision 1.3 1995/08/04 13:09:59 brianp
* include gluP.h to define NULL, just in case
*
* Revision 1.2 1995/07/28 21:37:30 brianp
* updates from Bogdan on July 28
*
* Revision 1.1 1995/07/28 14:45:10 brianp
* Initial revision
*
*/
/*
* NURBS implementation written by Bogdan Sikorski (bogdan@cira.it)
* See README-nurbs for more info.
*/
#include <math.h>
#include <stdlib.h>
#include "nurbs.h"
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;
}
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;
GLboolean knot_open_at_begin=GL_FALSE,knot_open_at_end=GL_FALSE;
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;
if(the_knot->open_at_begin)
{
/* knot open at beggining */
knot_open_at_begin=GL_TRUE;
++t_min;
}
if(the_knot->open_at_end)
{
/* knot open at end */
knot_open_at_end=GL_TRUE;
--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;
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;
m=n+the_knot->delta_nknots;
alpha=the_knot->alpha;
if(the_knot->open_at_begin==GL_TRUE)
{
k=0;
}
else
{
k=the_knot->order-1;
m-=k;
}
/* is knot open at end? */
if(the_knot->open_at_end==GL_FALSE)
m-=the_knot->order-1;
/* 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==3)
{
x=(GLdouble)pts[indx];
y=(GLdouble)pts[indx+1];
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];
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;
}
}
else
{
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;
}
}
len /= tolerance;
return (GLint)len;
}
static GLenum
calc_sampling_3D(GLfloat *ctrl, GLint ucnt, GLint vcnt, GLint uorder, GLint vorder,
GLfloat tolerance, GLint dim, GLint **ufactors, GLint **vfactors)
{
GLint ufactor_cnt,vfactor_cnt;
GLint tmp_factor,max_factor;
GLint offset1,offset2;
GLint i,j;
ufactor_cnt=ucnt/uorder;
vfactor_cnt=vcnt/vorder;
if((*ufactors=(GLint *)malloc(sizeof(GLint)*ufactor_cnt))==NULL)
{
return GLU_OUT_OF_MEMORY;
}
if((*vfactors=(GLint *)malloc(sizeof(GLint)*vfactor_cnt))==NULL)
{
free(ufactors);
return GLU_OUT_OF_MEMORY;
}
offset1=vorder*dim;
offset2=vcnt*dim;
for(j=0;j<vfactor_cnt;j++)
{
for(i=0 , max_factor=1;i<ucnt;i++)
{
tmp_factor=calc_factor(ctrl,vorder,j*offset1+i*offset2,
dim,tolerance,dim);
if(tmp_factor>max_factor)
max_factor=tmp_factor;
}
(*vfactors)[j]=max_factor;
}
offset1=offset2;
offset2*=uorder;
for(j=0;j<ufactor_cnt;j++)
{
for(i=0 , max_factor=1;i<vcnt;i++)
{
tmp_factor=calc_factor(ctrl,uorder,j*offset2+i*dim,
offset1,tolerance,dim);
if(tmp_factor>max_factor)
max_factor=tmp_factor;
}
(*ufactors)[j]=max_factor;
}
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(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, GLfloat *ctrl, GLint scnt, GLint tcnt,
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(ctrl,scnt,tcnt,nobj->surface.geom.sorder,
nobj->surface.geom.torder,nobj->sampling_tolerance,dim,
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;
*factors=NULL;
set_sampling_and_culling(nobj);
if((err=calc_sampling_2D(ctrl,cnt,order,nobj->sampling_tolerance,dim,
factors))==GLU_ERROR)
{
revert_sampling_and_culling(nobj);
call_user_error(nobj,err);
return GLU_ERROR;
}
revert_sampling_and_culling(nobj);
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);
}*/