diff options
author | jtg <jtg> | 1999-08-19 00:55:39 +0000 |
---|---|---|
committer | jtg <jtg> | 1999-08-19 00:55:39 +0000 |
commit | afb833d4e89c312460a4ab9ed6a7a8ca4ebbfe1c (patch) | |
tree | 59d65b4da12fb5379224cf5f6b808fde91523c7f /src/glu/mesa | |
parent | f2544d4920ce168bec9cd94d774b7ea5103a3d74 (diff) |
Initial revision
Diffstat (limited to 'src/glu/mesa')
-rw-r--r-- | src/glu/mesa/Makefile.BeOS | 73 | ||||
-rw-r--r-- | src/glu/mesa/Makefile.BeOS-R4 | 85 | ||||
-rw-r--r-- | src/glu/mesa/Makefile.X11 | 57 | ||||
-rw-r--r-- | src/glu/mesa/MesaGLU.def | 54 | ||||
-rw-r--r-- | src/glu/mesa/README1 | 195 | ||||
-rw-r--r-- | src/glu/mesa/README2 | 43 | ||||
-rw-r--r-- | src/glu/mesa/all.h | 69 | ||||
-rw-r--r-- | src/glu/mesa/descrip.mms | 62 | ||||
-rw-r--r-- | src/glu/mesa/glu.c | 335 | ||||
-rw-r--r-- | src/glu/mesa/gluP.h | 83 | ||||
-rw-r--r-- | src/glu/mesa/mipmap.c | 790 | ||||
-rw-r--r-- | src/glu/mesa/mms_depend | 13 | ||||
-rw-r--r-- | src/glu/mesa/nurbs.c | 715 | ||||
-rw-r--r-- | src/glu/mesa/nurbs.h | 252 | ||||
-rw-r--r-- | src/glu/mesa/nurbscrv.c | 500 | ||||
-rw-r--r-- | src/glu/mesa/nurbssrf.c | 1422 | ||||
-rw-r--r-- | src/glu/mesa/nurbsutl.c | 1403 | ||||
-rw-r--r-- | src/glu/mesa/polytest.c | 1049 | ||||
-rw-r--r-- | src/glu/mesa/project.c | 318 | ||||
-rw-r--r-- | src/glu/mesa/quadric.c | 858 | ||||
-rw-r--r-- | src/glu/mesa/tess.c | 369 | ||||
-rw-r--r-- | src/glu/mesa/tess.h | 121 | ||||
-rw-r--r-- | src/glu/mesa/tesselat.c | 456 |
23 files changed, 9322 insertions, 0 deletions
diff --git a/src/glu/mesa/Makefile.BeOS b/src/glu/mesa/Makefile.BeOS new file mode 100644 index 00000000000..d1e489c1999 --- /dev/null +++ b/src/glu/mesa/Makefile.BeOS @@ -0,0 +1,73 @@ +# Makefile for GLU for BeOS contributed by +# Tinic Uro <[email protected]> + +# Mesa 3-D graphics library +# Version: 2.6 +# 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. + + + +##### MACROS ##### + +VPATH = RCS + +INCDIR = ../include +LIBDIR = ../lib + +SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \ + project.c quadric.c tess.c tesselat.c polytest.c + +OBJECTS = $(SOURCES:.c=.o) + + + +##### RULES ##### + +.c.o: + $(CC) -c -i . -i- -i $(INCDIR) $(CFLAGS) $< + + + +##### TARGETS ##### + +default: + @echo "Specify a target configuration" + +clean: + -rm *.o *~ + +targets: $(LIBDIR)/$(GLU_LIB) + +# Make the library: +$(LIBDIR)/$(GLU_LIB): $(OBJECTS) + $(MAKELIB) $(GLU_LIB) 2 6 $(OBJECTS) +# $(RANLIB) $(GLU_LIB) + mv $(GLU_LIB)* $(LIBDIR) + +include ../Make-config + +include depend + + + +# +# Run 'make depend' to update the dependencies if you change what's included +# by any source file. +# +depend: $(SOURCES) + makedepend -fdepend -Y -I../include $(SOURCES) + diff --git a/src/glu/mesa/Makefile.BeOS-R4 b/src/glu/mesa/Makefile.BeOS-R4 new file mode 100644 index 00000000000..d664534491d --- /dev/null +++ b/src/glu/mesa/Makefile.BeOS-R4 @@ -0,0 +1,85 @@ +# Makefile for GLU for BeOS R4 + +# Mesa 3-D graphics library +# Version: 3.1 +# Copyright (C) 1995-1999 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. + + +# $Id: Makefile.BeOS-R4,v 1.1 1999/08/19 00:55:42 jtg Exp $ + +# $Log: Makefile.BeOS-R4,v $ +# Revision 1.1 1999/08/19 00:55:42 jtg +# Initial revision +# +# Revision 1.2 1999/02/02 04:44:40 brianp +# fixed some problems +# +# Revision 1.1 1999/01/19 04:10:02 brianp +# Initial revision +# + + + +##### MACROS ##### + +VPATH = RCS + +INCDIR = ../include +LIBDIR = ../lib + +SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \ + project.c quadric.c tess.c tesselat.c polytest.c + +OBJECTS = $(SOURCES:.c=.o) + + + +##### TARGETS ##### + +default: + @echo "Specify a target configuration" + +clean: + -rm *.o *~ + +targets: $(LIBDIR)/$(GLU_LIB) + +# Make the library: +$(LIBDIR)/$(GLU_LIB): $(OBJECTS) + $(MAKELIB) $(GLU_LIB) $(MAJOR) $(MINOR) -L$(LIBDIR) -lMesaGL $(OBJECTS) + mv $(GLU_LIB)* $(LIBDIR) + +include ../Make-config + +include depend + + + +##### RULES ##### + +.c.o: + $(CC) -c -I. -I../ -I$(INCDIR) $(CFLAGS) $< + + + +# +# Run 'make depend' to update the dependencies if you change what's included +# by any source file. +# +depend: $(SOURCES) + makedepend -fdepend -Y -I../include $(SOURCES) + diff --git a/src/glu/mesa/Makefile.X11 b/src/glu/mesa/Makefile.X11 new file mode 100644 index 00000000000..c155aea9a55 --- /dev/null +++ b/src/glu/mesa/Makefile.X11 @@ -0,0 +1,57 @@ +# $Id: Makefile.X11,v 1.1 1999/08/19 00:55:42 jtg Exp $ + +# Mesa 3-D graphics library +# Version: 3.1 +# Copyright (C) 1995-1999 Brian Paul + +# Makefile for GLU library + + +##### MACROS ##### + +VPATH = RCS + +INCDIR = ../include +LIBDIR = ../lib + +SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \ + project.c quadric.c tess.c tesselat.c polytest.c + +OBJECTS = $(SOURCES:.c=.o) + + + +##### RULES ##### + +.c.o: + $(CC) -c -I$(INCDIR) $(CFLAGS) $< + + + +##### TARGETS ##### + +default: + @echo "Specify a target configuration" + +clean: + -rm *.o *~ + +targets: $(LIBDIR)/$(GLU_LIB) + +# Make the library: +$(LIBDIR)/$(GLU_LIB): $(OBJECTS) + $(MAKELIB) $(GLU_LIB) $(MAJOR) $(MINOR) $(OBJECTS) + mv $(GLU_LIB)* $(LIBDIR) + +include ../Make-config + +include depend + + + +# +# Run 'make depend' to update the dependencies if you change what's included +# by any source file. +# +dep: $(SOURCES) + makedepend -fdepend -Y -I../include $(SOURCES) diff --git a/src/glu/mesa/MesaGLU.def b/src/glu/mesa/MesaGLU.def new file mode 100644 index 00000000000..8b1c4449ff1 --- /dev/null +++ b/src/glu/mesa/MesaGLU.def @@ -0,0 +1,54 @@ +LIBRARY MESAGLU
+DESCRIPTION 'GLU for Windows Mesa'
+EXETYPE WINDOWS
+CODE MOVEABLE DISCARDABLE
+DATA MOVEABLE SINGLE
+HEAPSIZE 256000
+
+STACKSIZE 4096
+
+EXPORTS
+ gluLookAt
+ gluOrtho2D
+ gluPerspective
+ gluPickMatrix
+ gluProject
+ gluUnProject
+ gluErrorString
+ gluScaleImage
+ gluBuild1DMipmaps
+ gluBuild2DMipmaps
+ gluNewQuadric
+ gluDeleteQuadric
+ gluQuadricDrawStyle
+ gluQuadricOrientation
+ gluQuadricNormals
+ gluQuadricTexture
+ gluQuadricCallback
+ gluCylinder
+ gluSphere
+ gluDisk
+ gluPartialDisk
+ gluNewNurbsRenderer
+ gluDeleteNurbsRenderer
+ gluLoadSamplingMatrices
+ gluNurbsProperty
+ gluGetNurbsProperty
+ gluBeginCurve
+ gluEndCurve
+ gluNurbsCurve
+ gluBeginSurface
+ gluEndSurface
+ gluNurbsSurface
+ gluBeginTrim
+ gluEndTrim
+ gluPwlCurve
+ gluNurbsCallback
+ gluNewTess
+ gluTessCallback
+ gluDeleteTess
+ gluBeginPolygon
+ gluEndPolygon
+ gluNextContour
+ gluTessVertex
+ gluGetString
diff --git a/src/glu/mesa/README1 b/src/glu/mesa/README1 new file mode 100644 index 00000000000..75968572ff6 --- /dev/null +++ b/src/glu/mesa/README1 @@ -0,0 +1,195 @@ + +Notes on the GLU polygon tesselation facility implemented by Bogdan Sikorski... + + + +The tesselation module is provided under the same terms as the Mesa +package. + +This is the first release of polygon tesselation code for Mesa. +It was written during my very little free time, so lets name it: +"its not perfect". If someone hates pointers, don't look at the code. +I preffer dynamic allocation versus static. But _all_ ideas, suggestions, +bug reports and fixes are welcome (if You want, also flames). I am aware +that many things could have been written using better techniques, but time +that I could devote to this library was very limited. It is not well commented, +excuse me. Also I am thinking of continuing working on this code to improve, +fix and polish it. And make it as compliant as possible to the OpenGL, so +software ports from OpenGL to Mesa will work correctly. If You know of any +differences in behaviour, expected input/output between Mesa tesselation library +and OpenGL, please send me a note. I explain later on why I am not +confident with this code. + +I tried to be fully compliant with the OpenGL routines. By "tried" I mean that +up to my knowledge it behaves as OpenGL tesselation routines. Just recently +I began to experiment with OpenGL (actually only Mesa), and also have +no access to any machine providing official implementation of OpenGL, +nor access to books (particulary Addison-Wesley publications). Thus my +knowledge on how the original tesselation code works, what kind of data +it expects etc. is based _only_ on the publicly available documentation +provided by SGI. Namely: + +* "The OpenGL Graphics System Utility Library" by K.P.Smith + (Silicon Graphics, 1992) +* "The OpenGL Graphics Interface" by M.Segal and K.Akeley + (Silicon Graphics, 19??) +* "OpenGL and X, Part 1: Introduction" by M.J.Kilgard + (Silicon Graphics, 1994) +* "OpenGL and X, Part 2: Using OpenGL with Xlib" by M.J.Kilgard + (Silicon Graphics, 1994) +* "OpenGL Graphics with the X Window System" by P.Karlton + (Silicon Graphics, 1993) +* Online Docs - Appendix C of OpenGL Programming Guide, Polygon Tesselation + (partial text cut and sent by e-mail) + + +The tesselation routines use slightly different prototypes than the ones +specified in the mentioned above publications. The _only_ differences are +the enumeration types which are not GLenum, but are GLUenum. So the +implemented routines have following prototypes: + +GLUtringulatorObj *gluNewTess(void); + +void gluTessCallback(GLUtriangulatorObj *,GLUenum,void (*)()); + ^^^^^^^ +void gluBeginPolygon(GLUtriangulatorObj *); + +void gluTessVertex(GLUtriangulatorObj *,GLdouble [3],void *); + +void gluNextContour(GLUtriangulatorObj *,GLUenum); + ^^^^^^^ +void gluEndPolygon(GLUtriangulatorObj *); + +const GLubyte *gluErrorString(GLUenum); + ^^^^^^^ + prototypes for callback functions: + +void <begin>(GLUenum); + ^^^^^^^ +void <edgeFlag>(GLboolean); +void <vertex>(void *); +void <end>(void); +void <error>(GLUenum); + ^^^^^^^ + +The begin callback will be called only with GLU_TRIANGLES. No support +for traingle fans or strips yet. + +In case of errors an internal error variable is set to the appropiate +error enum values (GLU_TESS_ERROR?). Initially it is set to GLU_NO_ERROR. +The OpenGL library provides 8 error conditions, the tesselation code +of Mesa provides 9. They are: + +GLU_TESS_ERROR1: missing gluEndPolygon /* same as OpenGL */ +GLU_TESS_ERROR2: missing gluBeginPolygon /* same as OpenGL */ +GLU_TESS_ERROR3: misoriented contour /* not used in Mesa + in OpenGL is bad orientation or intersecting edges */ +GLU_TESS_ERROR4: vertex/edge intersection /* same as OpenGL */ +GLU_TESS_ERROR5: misoriented or self-intersecting loops /* same as OpenGL */ +GLU_TESS_ERROR6: coincident vertices /* same as OpenGL */ +GLU_TESS_ERROR7: colinear vertices /* OpenGL's illegal data */ +GLU_TESS_ERROR8: intersecting edges /* same as OpenGL */ +GLU_TESS_ERROR9: not coplanar contours /* new for Mesa */ + +The Mesa tesselation code ignores all data and calls after detecting an error +codition. This means that a _new_ tesselation object must be used for further +triangulations. Maybe this is too restrictive, and will be lifted in +future versions. + +The tesselation code completely ignores the type parameter passed in +gluNextContour. It also doesn't check if the passed parameter is a legal +enum value - ignores silently (maybe at least this should be checked). +The reason I chose this behaviour is based on what I read in the +beforementioned documents. I cite: + +".... +void gluNextContour(GLUtriangulatorObj *tessobj, GLenum type); + +Marks the beginning of the next contour when multiple contours make up the +boundary of the polygon to be tessellated. type can be GLU_EXTERIOR, +GLU_INTERIOR, GLU_CCW, GLU_CW, or GLU_UNKNOWN. These serve only as +to the tessellation. If you get them right, the tessellation might +go faster. If you get them wrong, they're ignored, and the tesselation still +works. +....." + +I hope You agree with me that my decision was correct. Mesa tesselation +_always_ checks by itself the interrelations between contours. Just as if +all contours were specified with the type GLU_UNKNOWN. + +One of OpenGL's policy is not to check all error conditions - rely sometimes +that the user "got things right". This is justified, since exhausting +error checking is timeconsuming, and would significantly slow down +a correct application. The Mesa tesselation code assumes only _one_ condition +when triangulating - all vertices in a contour are planar. This is _not_ +checked for correctness. Trying to tesselate such objects will lead to +unpredictable output. + +And now we arrive to the moment where I would like to list the required +(but checked for) conditions for triangulation, as well as summarize the +library: + +* all contours in a single tesselation cycle _must_ be coplanar - if not + an error is raised (and if provided a call to the error callback + is made) +* the contours can be passed in _any_ order, exteriors and holes can be + intermixed within a tesselation cycle and the correct hierarchy + will be determined by the library; thus specifying first holes then + exteriors, then holes within holes form a valid input. +* a hole within a hole is consider to be a yet another exterior contour +* multiple exterior contours (polygons) can be tesselated in one cycle; + _but_ this significantly degrades performance since many tests will be + performed for every contour pair; if You want triangulation to be fast + tesselate a single polygon (with possible holes) one at a time. +* orientation of exterior contours is arbitray, but if it has holes, + all interior holes of this particular exterior contour _must_ have an + opposite orientation. +* the output triangles have the same orientation as the exterior contour + that forms them +* each triangle is "enclosed" within the begin and end callbacks; + this is not efficent, but was made on purpose; so if triangulation + results in 2 triangles the following callbacks will be made in such + order: + <begin>(GLU_TRAINGLES) + <vertex>(...) /* 3 vertices of first triangle */ + <vertex>(...) + <vertex>(...) + <end>() + <begin>(GLU_TRAINGLES) + <vertex>(...) /* 3 vertices of second triangle */ + <vertex>(...) + <vertex>(...) + <end>() + Of course only when begin, vertex, and end callback were provided, + otherwise no output is done (actually tesselation does not take place). +* You will notice that some output traingles are very "thin"; there + exist possible several ways to traingulate a polygon, but "smart" code + avoiding such cases would require time to write, and will impact on + execution speed. +* like OpenGL, no new vertices are introduced during triangulation +* if the edgeflag callback is provided it will be called whenever + the just-about-to be output vertex begins a different type of edge + than the previous vertices; always before the first output a call + is made with GL_TRUE, to allow synchronization. +* all intermediate computations are done using GLdouble type, and comparisons + are biased with a precision value (EPSILON defined in tess.h) +* the point_in_poly function is my adaptation of code from the + comp.graphics.alg newsgroup FAQ (originally written by Mr. Wm. Randolph + Franklin, modified by Scott Anguish). +* the edge_edge_intersect test is also an adopted code from comp.graphics.alg + newsgroup FAQ +* the general idea for traingulation used in this library is described in + the book "Computational Geometry in C" by Joseph O'Rourke. + + +Excuse my English, its not my mother tongue. I should be available for some +time uner the following e-mail address. But For how long I am not certain. +Once I am settled in my new place, I'll post on the Mesa mailing list +my new address. + +(PS: today is my last day of work here, I'm changing my job). + +Bogdan. ( [email protected] ) + +Apr 28, 1995. + diff --git a/src/glu/mesa/README2 b/src/glu/mesa/README2 new file mode 100644 index 00000000000..3c9959179b0 --- /dev/null +++ b/src/glu/mesa/README2 @@ -0,0 +1,43 @@ +The current NURBS implementation has no trimming facilities yet. + +The code is not well commented. + +1) Normal calculus fails for special cases of NURBS (independent + of the NURBS modules) + Those cases arise when for u or v, some control points + for a fixed value of that parameter form the same point. + Imagine a Bezier patch degenerated into a "triangle". + + v ^ 0,1,2 order=3 + | * + | + | 3* 4* 5* + | + | 6* 7* 8* + | + | + +------------------------> u + + The calculus of du derivative at triple point (0,1 and 2) will fail. + As a result, the normal vector will be 0. + The eval2.c code has to be changed to handle the above situation. + +2) Adjacent NURBS surfaces ("sharing" the same control points along + the "joining" edge) will be sampled with the same factor. + This prevents the formation of "cracks". + When the control polygon of the "shared" edge is not the same, + cracks might appear. + +The sampling tolerance is sometimes not respected! +A NURBS object is broken into Bezier curves/surfaces. If one of such +Bezier objects has a local high curvature with other portions of it +relatively flat then the high curvature part will be sampled more dense that +its flatter regions. +The flat regions might be tesselated into quads having sides of length +greater than the current sampling tolernace setting. +I believe such behaviour is acceptable, though not along the concept of +sampling tolerance. + +February 20, 1996. + +Bogdan. diff --git a/src/glu/mesa/all.h b/src/glu/mesa/all.h new file mode 100644 index 00000000000..3712ca884ab --- /dev/null +++ b/src/glu/mesa/all.h @@ -0,0 +1,69 @@ +/* $Id: all.h,v 1.1 1999/08/19 00:55:42 jtg Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 2.3 + * 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: all.h,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.2 1997/11/20 00:28:20 brianp + * changed PCH to PC_HEADER + * + * Revision 1.1 1997/05/28 02:29:14 brianp + * Initial revision + * + */ + + +/* + * This file includes all .h files needed for the GLU source code for + * the purpose of precompiled headers. + * + * If the preprocessor symbol PCH is defined at compile time then each + * of the .c files will #include "all.h" only, instead of a bunch of + * individual .h files. + */ + + +#ifndef GLU_ALL_H +#define GLU_ALL_H + + +#ifndef PC_HEADER + This is an error. all.h should be included only if PCH is defined. +#endif + + +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "GL/gl.h" +#include "GL/glu.h" +#include "gluP.h" +#include "nurbs.h" +#include "tess.h" + + +#endif /*GLU_ALL_H*/ diff --git a/src/glu/mesa/descrip.mms b/src/glu/mesa/descrip.mms new file mode 100644 index 00000000000..b660f6914de --- /dev/null +++ b/src/glu/mesa/descrip.mms @@ -0,0 +1,62 @@ +# Makefile for GLU for VMS +# contributed by Jouk Jansen [email protected] + +.first + define gl [-.include.gl] + +.include [-]mms-config. + +##### MACROS ##### + +VPATH = RCS + +INCDIR = $disk2:[-.include] +LIBDIR = [-.lib] +CFLAGS = /include=$(INCDIR)/define=(FBIND=1) + +SOURCES = glu.c mipmap.c nurbs.c nurbscrv.c nurbssrf.c nurbsutl.c \ + project.c quadric.c tess.c tesselat.c polytest.c + +OBJECTS =glu.obj,mipmap.obj,nurbs.obj,nurbscrv.obj,nurbssrf.obj,nurbsutl.obj,\ + project.obj,quadric.obj,tess.obj,tesselat.obj,polytest.obj + + + +##### RULES ##### + +VERSION=MesaGlu V3.1 + +##### TARGETS ##### + +# Make the library: +$(LIBDIR)$(GLU_LIB) : $(OBJECTS) +.ifdef SHARE + @ WRITE_ SYS$OUTPUT " generating mesagl1.opt" + @ OPEN_/WRITE FILE mesagl1.opt + @ WRITE_ FILE "!" + @ WRITE_ FILE "! mesagl1.opt generated by DESCRIP.$(MMS_EXT)" + @ WRITE_ FILE "!" + @ WRITE_ FILE "IDENTIFICATION=""$(VERSION)""" + @ WRITE_ FILE "GSMATCH=LEQUAL,3,1 + @ WRITE_ FILE "$(OBJECTS)" + @ WRITE_ FILE "[-.lib]libmesagl.exe/SHARE" + @ WRITE_ FILE "SYS$SHARE:DECW$XEXTLIBSHR/SHARE" + @ WRITE_ FILE "SYS$SHARE:DECW$XLIBSHR/SHARE" + @ CLOSE_ FILE + @ WRITE_ SYS$OUTPUT " generating mesagl.map ..." + @ LINK_/NODEB/NOSHARE/NOEXE/MAP=mesagl.map/FULL mesagl1.opt/OPT + @ WRITE_ SYS$OUTPUT " analyzing mesagl.map ..." + @ @[-.vms]ANALYZE_MAP.COM mesagl.map mesagl.opt + @ WRITE_ SYS$OUTPUT " linking $(GLU_LIB) ..." + @ LINK_/noinform/NODEB/SHARE=$(GLU_LIB)/MAP=mesagl.map/FULL mesagl1.opt/opt,mesagl.opt/opt +.else + @ $(MAKELIB) $(GLU_LIB) $(OBJECTS) +.endif + @ rename $(GLU_LIB)* $(LIBDIR) + +clean : + delete *.obj;* + purge + +include mms_depend. + diff --git a/src/glu/mesa/glu.c b/src/glu/mesa/glu.c new file mode 100644 index 00000000000..2cceb8b743e --- /dev/null +++ b/src/glu/mesa/glu.c @@ -0,0 +1,335 @@ +/* $Id: glu.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.1 + * Copyright (C) 1995-1999 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: glu.c,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.13 1999/03/31 19:07:28 brianp + * added GL_EXT_abgr to extensions + * + * Revision 1.12 1999/02/06 06:12:41 brianp + * updated version string to 3.1 + * + * Revision 1.11 1999/01/03 03:23:15 brianp + * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump) + * + * Revision 1.10 1998/04/22 00:35:50 brianp + * changed version to 3.0 + * + * Revision 1.9 1997/12/09 03:03:32 brianp + * changed version to 2.6 + * + * Revision 1.8 1997/10/04 01:30:20 brianp + * changed version to 2.5 + * + * Revision 1.7 1997/08/13 01:25:21 brianp + * changed version string to 2.4 + * + * Revision 1.6 1997/07/24 01:28:44 brianp + * changed precompiled header symbol from PCH to PC_HEADER + * + * Revision 1.5 1997/07/13 22:59:11 brianp + * added const to viewport parameter of gluPickMatrix() + * + * Revision 1.4 1997/05/28 02:29:38 brianp + * added support for precompiled headers (PCH), inserted APIENTRY keyword + * + * Revision 1.3 1997/04/12 16:19:02 brianp + * changed version to 2.3 + * + * Revision 1.2 1997/03/11 00:58:34 brianp + * changed version to 2.2 + * + * Revision 1.1 1996/09/27 01:19:39 brianp + * Initial revision + * + */ + + +#ifdef PC_HEADER +#include "all.h" +#else +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "gluP.h" +#endif + + +/* + * Miscellaneous utility functions + */ + + +#ifndef M_PI +#define M_PI 3.1415926536 +#endif +#define EPS 0.00001 + + + + +void GLAPIENTRY gluLookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez, + GLdouble centerx, GLdouble centery, GLdouble centerz, + GLdouble upx, GLdouble upy, GLdouble upz ) +{ + GLdouble m[16]; + GLdouble x[3], y[3], z[3]; + GLdouble mag; + + /* Make rotation matrix */ + + /* Z vector */ + z[0] = eyex - centerx; + z[1] = eyey - centery; + z[2] = eyez - centerz; + mag = sqrt( z[0]*z[0] + z[1]*z[1] + z[2]*z[2] ); + if (mag) { /* mpichler, 19950515 */ + z[0] /= mag; + z[1] /= mag; + z[2] /= mag; + } + + /* Y vector */ + y[0] = upx; + y[1] = upy; + y[2] = upz; + + /* X vector = Y cross Z */ + x[0] = y[1]*z[2] - y[2]*z[1]; + x[1] = -y[0]*z[2] + y[2]*z[0]; + x[2] = y[0]*z[1] - y[1]*z[0]; + + /* Recompute Y = Z cross X */ + y[0] = z[1]*x[2] - z[2]*x[1]; + y[1] = -z[0]*x[2] + z[2]*x[0]; + y[2] = z[0]*x[1] - z[1]*x[0]; + + /* mpichler, 19950515 */ + /* cross product gives area of parallelogram, which is < 1.0 for + * non-perpendicular unit-length vectors; so normalize x, y here + */ + + mag = sqrt( x[0]*x[0] + x[1]*x[1] + x[2]*x[2] ); + if (mag) { + x[0] /= mag; + x[1] /= mag; + x[2] /= mag; + } + + mag = sqrt( y[0]*y[0] + y[1]*y[1] + y[2]*y[2] ); + if (mag) { + y[0] /= mag; + y[1] /= mag; + y[2] /= mag; + } + +#define M(row,col) m[col*4+row] + M(0,0) = x[0]; M(0,1) = x[1]; M(0,2) = x[2]; M(0,3) = 0.0; + M(1,0) = y[0]; M(1,1) = y[1]; M(1,2) = y[2]; M(1,3) = 0.0; + M(2,0) = z[0]; M(2,1) = z[1]; M(2,2) = z[2]; M(2,3) = 0.0; + M(3,0) = 0.0; M(3,1) = 0.0; M(3,2) = 0.0; M(3,3) = 1.0; +#undef M + glMultMatrixd( m ); + + /* Translate Eye to Origin */ + glTranslated( -eyex, -eyey, -eyez ); + +} + + + +void GLAPIENTRY gluOrtho2D( GLdouble left, GLdouble right, + GLdouble bottom, GLdouble top ) +{ + glOrtho( left, right, bottom, top, -1.0, 1.0 ); +} + + + +void GLAPIENTRY gluPerspective( GLdouble fovy, GLdouble aspect, + GLdouble zNear, GLdouble zFar ) +{ + GLdouble xmin, xmax, ymin, ymax; + + ymax = zNear * tan( fovy * M_PI / 360.0 ); + ymin = -ymax; + + xmin = ymin * aspect; + xmax = ymax * aspect; + + glFrustum( xmin, xmax, ymin, ymax, zNear, zFar ); +} + + + +void GLAPIENTRY gluPickMatrix( GLdouble x, GLdouble y, + GLdouble width, GLdouble height, + const GLint viewport[4] ) +{ + GLfloat m[16]; + GLfloat sx, sy; + GLfloat tx, ty; + + sx = viewport[2] / width; + sy = viewport[3] / height; + tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width; + ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height; + +#define M(row,col) m[col*4+row] + M(0,0) = sx; M(0,1) = 0.0; M(0,2) = 0.0; M(0,3) = tx; + M(1,0) = 0.0; M(1,1) = sy; M(1,2) = 0.0; M(1,3) = ty; + M(2,0) = 0.0; M(2,1) = 0.0; M(2,2) = 1.0; M(2,3) = 0.0; + M(3,0) = 0.0; M(3,1) = 0.0; M(3,2) = 0.0; M(3,3) = 1.0; +#undef M + + glMultMatrixf( m ); +} + + + +const GLubyte* GLAPIENTRY gluErrorString( GLenum errorCode ) +{ + static char *tess_error[] = { + "missing gluEndPolygon", + "missing gluBeginPolygon", + "misoriented contour", + "vertex/edge intersection", + "misoriented or self-intersecting loops", + "coincident vertices", + "colinear vertices", + "intersecting edges", + "not coplanar contours" + }; + static char *nurbs_error[] = { + "spline order un-supported", + "too few knots", + "valid knot range is empty", + "decreasing knot sequence knot", + "knot multiplicity greater than order of spline", + "endcurve() must follow bgncurve()", + "bgncurve() must precede endcurve()", + "missing or extra geometric data", + "can't draw pwlcurves", + "missing bgncurve()", + "missing bgnsurface()", + "endtrim() must precede endsurface()", + "bgnsurface() must precede endsurface()", + "curve of improper type passed as trim curve", + "bgnsurface() must precede bgntrim()", + "endtrim() must follow bgntrim()", + "bgntrim() must precede endtrim()", + "invalid or missing trim curve", + "bgntrim() must precede pwlcurve()", + "pwlcurve referenced twice", + "pwlcurve and nurbscurve mixed", + "improper usage of trim data type", + "nurbscurve referenced twice", + "nurbscurve and pwlcurve mixed", + "nurbssurface referenced twice", + "invalid property", + "endsurface() must follow bgnsurface()", + "misoriented trim curves", + "intersecting trim curves", + "UNUSED", + "unconnected trim curves", + "unknown knot error", + "negative vertex count encountered", + "negative byte-stride encounteed", + "unknown type descriptor", + "null control array or knot vector", + "duplicate point on pwlcurve" + }; + + /* GL Errors */ + if (errorCode==GL_NO_ERROR) { + return (GLubyte *) "no error"; + } + else if (errorCode==GL_INVALID_VALUE) { + return (GLubyte *) "invalid value"; + } + else if (errorCode==GL_INVALID_ENUM) { + return (GLubyte *) "invalid enum"; + } + else if (errorCode==GL_INVALID_OPERATION) { + return (GLubyte *) "invalid operation"; + } + else if (errorCode==GL_STACK_OVERFLOW) { + return (GLubyte *) "stack overflow"; + } + else if (errorCode==GL_STACK_UNDERFLOW) { + return (GLubyte *) "stack underflow"; + } + else if (errorCode==GL_OUT_OF_MEMORY) { + return (GLubyte *) "out of memory"; + } + /* GLU Errors */ + else if (errorCode==GLU_NO_ERROR) { + return (GLubyte *) "no error"; + } + else if (errorCode==GLU_INVALID_ENUM) { + return (GLubyte *) "invalid enum"; + } + else if (errorCode==GLU_INVALID_VALUE) { + return (GLubyte *) "invalid value"; + } + else if (errorCode==GLU_OUT_OF_MEMORY) { + return (GLubyte *) "out of memory"; + } + else if (errorCode==GLU_INCOMPATIBLE_GL_VERSION) { + return (GLubyte *) "incompatible GL version"; + } + else if (errorCode>=GLU_TESS_ERROR1 && errorCode<=GLU_TESS_ERROR9) { + return (GLubyte *) tess_error[errorCode-GLU_TESS_ERROR1]; + } + else if (errorCode>=GLU_NURBS_ERROR1 && errorCode<=GLU_NURBS_ERROR37) { + return (GLubyte *) nurbs_error[errorCode-GLU_NURBS_ERROR1]; + } + else { + return NULL; + } +} + + + +/* + * New in GLU 1.1 + */ + +const GLubyte* GLAPIENTRY gluGetString( GLenum name ) +{ + static char *extensions = "GL_EXT_abgr"; + static char *version = "1.1 Mesa 3.1"; + + switch (name) { + case GLU_EXTENSIONS: + return (GLubyte *) extensions; + case GLU_VERSION: + return (GLubyte *) version; + default: + return NULL; + } +} + diff --git a/src/glu/mesa/gluP.h b/src/glu/mesa/gluP.h new file mode 100644 index 00000000000..1d036eeb5ea --- /dev/null +++ b/src/glu/mesa/gluP.h @@ -0,0 +1,83 @@ +/* $Id: gluP.h,v 1.1 1999/08/19 00:55:42 jtg Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.1 + * Copyright (C) 1995-1999 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: gluP.h,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.4 1999/01/03 03:23:15 brianp + * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump) + * + * Revision 1.3 1997/08/01 22:25:27 brianp + * check for Cygnus Win32 (Stephen Rehel) + * + * Revision 1.2 1997/05/27 02:59:46 brianp + * added defines for APIENTRY and CALLBACK if not compiling on Win32 + * + * Revision 1.1 1996/09/27 01:19:39 brianp + * Initial revision + * + */ + + + +/* + * This file allows the GLU code to be compiled either with the Mesa + * headers or with the real OpenGL headers. + */ + + +#ifndef GLUP_H +#define GLUP_H + + +#include "GL/gl.h" +#include "GL/glu.h" + + +#ifndef MESA + /* If we're using the real OpenGL header files... */ +# define GLU_TESS_ERROR9 100159 +#endif + + +#define GLU_NO_ERROR GL_NO_ERROR + + +/* for Sun: */ +#ifdef SUNOS4 +#define MEMCPY( DST, SRC, BYTES) \ + memcpy( (char *) (DST), (char *) (SRC), (int) (BYTES) ) +#else +#define MEMCPY( DST, SRC, BYTES) \ + memcpy( (void *) (DST), (void *) (SRC), (size_t) (BYTES) ) +#endif + + +#ifndef NULL +# define NULL 0 +#endif + + +#endif diff --git a/src/glu/mesa/mipmap.c b/src/glu/mesa/mipmap.c new file mode 100644 index 00000000000..24af0ba33c0 --- /dev/null +++ b/src/glu/mesa/mipmap.c @@ -0,0 +1,790 @@ +/* $Id: mipmap.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.1 + * Copyright (C) 1995-1999 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: mipmap.c,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.13 1999/03/05 17:49:06 brianp + * added support for GL_EXT_abgr ([email protected]) + * + * Revision 1.12 1999/01/03 03:23:15 brianp + * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump) + * + * Revision 1.11 1998/09/18 02:44:03 brianp + * further changes to gluScaleImage() per Randy Frank + * + * Revision 1.10 1998/09/17 03:20:26 brianp + * fixed another bug in gluScaleImage() per Sven Panne + * + * Revision 1.9 1998/07/31 03:06:20 brianp + * tweaked the gluScaleImage() function per Randy Frank + * + * Revision 1.8 1998/07/08 01:02:53 brianp + * if gluBuildxDMipmaps() width or height <= 0 return GLU_INVALID_VALUE + * + * Revision 1.7 1998/07/01 00:18:02 brianp + * if gluBuildxDMipmaps() width or height <= 0 just return 0 + * + * Revision 1.6 1998/06/01 01:06:41 brianp + * small update for Next/OpenStep from Alexander Mai + * + * Revision 1.5 1997/07/24 01:28:44 brianp + * changed precompiled header symbol from PCH to PC_HEADER + * + * Revision 1.4 1997/06/23 00:22:56 brianp + * added dummy() call to work around an MSVC 4.1 bug + * + * Revision 1.3 1997/05/28 02:29:38 brianp + * added support for precompiled headers (PCH), inserted APIENTRY keyword + * + * Revision 1.2 1997/05/24 13:32:25 brianp + * undef EPSILON in case it's already defined + * + * Revision 1.1 1996/09/27 01:19:39 brianp + * Initial revision + * + */ + + +#ifdef PC_HEADER +#include "all.h" +#else +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "gluP.h" +#endif + + +/* + * Compute ceiling of integer quotient of A divided by B: + */ +#define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 ) + + + +#ifdef EPSILON +#undef EPSILON +#endif +#define EPSILON 0.001 + + +/* To work around optimizer bug in MSVC4.1 */ +#if defined(__WIN32__) && !defined(OPENSTEP) +void dummy(GLuint j, GLuint k){ +} +#else +#define dummy(J, K) +#endif + + +GLint GLAPIENTRY gluScaleImage( GLenum format, + GLint widthin, GLint heightin, + GLenum typein, const void *datain, + GLint widthout, GLint heightout, + GLenum typeout, void *dataout ) +{ + GLint components, i, j, k; + GLfloat *tempin, *tempout; + GLfloat sx, sy; + GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels; + GLint packrowlength, packalignment, packskiprows, packskippixels; + GLint sizein, sizeout; + GLint rowstride, rowlen; + + + /* Determine number of components per pixel */ + switch (format) { + case GL_COLOR_INDEX: + case GL_STENCIL_INDEX: + case GL_DEPTH_COMPONENT: + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_LUMINANCE: + components = 1; + break; + case GL_LUMINANCE_ALPHA: + components = 2; + break; + case GL_RGB: + components = 3; + break; + case GL_RGBA: +#ifdef GL_EXT_abgr + case GL_ABGR_EXT: +#endif + components = 4; + break; + default: + return GLU_INVALID_ENUM; + } + + /* Determine bytes per input datum */ + switch (typein) { + case GL_UNSIGNED_BYTE: sizein = sizeof(GLubyte); break; + case GL_BYTE: sizein = sizeof(GLbyte); break; + case GL_UNSIGNED_SHORT: sizein = sizeof(GLushort); break; + case GL_SHORT: sizein = sizeof(GLshort); break; + case GL_UNSIGNED_INT: sizein = sizeof(GLuint); break; + case GL_INT: sizein = sizeof(GLint); break; + case GL_FLOAT: sizein = sizeof(GLfloat); break; + case GL_BITMAP: + /* not implemented yet */ + default: + return GL_INVALID_ENUM; + } + + /* Determine bytes per output datum */ + switch (typeout) { + case GL_UNSIGNED_BYTE: sizeout = sizeof(GLubyte); break; + case GL_BYTE: sizeout = sizeof(GLbyte); break; + case GL_UNSIGNED_SHORT: sizeout = sizeof(GLushort); break; + case GL_SHORT: sizeout = sizeof(GLshort); break; + case GL_UNSIGNED_INT: sizeout = sizeof(GLuint); break; + case GL_INT: sizeout = sizeof(GLint); break; + case GL_FLOAT: sizeout = sizeof(GLfloat); break; + case GL_BITMAP: + /* not implemented yet */ + default: + return GL_INVALID_ENUM; + } + + /* Get glPixelStore state */ + glGetIntegerv( GL_UNPACK_ROW_LENGTH, &unpackrowlength ); + glGetIntegerv( GL_UNPACK_ALIGNMENT, &unpackalignment ); + glGetIntegerv( GL_UNPACK_SKIP_ROWS, &unpackskiprows ); + glGetIntegerv( GL_UNPACK_SKIP_PIXELS, &unpackskippixels ); + glGetIntegerv( GL_PACK_ROW_LENGTH, &packrowlength ); + glGetIntegerv( GL_PACK_ALIGNMENT, &packalignment ); + glGetIntegerv( GL_PACK_SKIP_ROWS, &packskiprows ); + glGetIntegerv( GL_PACK_SKIP_PIXELS, &packskippixels ); + + /* Allocate storage for intermediate images */ + tempin = (GLfloat *) malloc( widthin * heightin + * components * sizeof(GLfloat) ); + if (!tempin) { + return GLU_OUT_OF_MEMORY; + } + tempout = (GLfloat *) malloc( widthout * heightout + * components * sizeof(GLfloat) ); + if (!tempout) { + free( tempin ); + return GLU_OUT_OF_MEMORY; + } + + + /* + * Unpack the pixel data and convert to floating point + */ + + if (unpackrowlength>0) { + rowlen = unpackrowlength; + } + else { + rowlen = widthin; + } + if (sizein >= unpackalignment) { + rowstride = components * rowlen; + } + else { + rowstride = unpackalignment/sizein + * CEILING( components * rowlen * sizein, unpackalignment ); + } + + switch (typein) { + case GL_UNSIGNED_BYTE: + k = 0; + for (i=0;i<heightin;i++) { + GLubyte *ubptr = (GLubyte *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = (GLfloat) *ubptr++; + } + } + break; + case GL_BYTE: + k = 0; + for (i=0;i<heightin;i++) { + GLbyte *bptr = (GLbyte *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = (GLfloat) *bptr++; + } + } + break; + case GL_UNSIGNED_SHORT: + k = 0; + for (i=0;i<heightin;i++) { + GLushort *usptr = (GLushort *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = (GLfloat) *usptr++; + } + } + break; + case GL_SHORT: + k = 0; + for (i=0;i<heightin;i++) { + GLshort *sptr = (GLshort *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = (GLfloat) *sptr++; + } + } + break; + case GL_UNSIGNED_INT: + k = 0; + for (i=0;i<heightin;i++) { + GLuint *uiptr = (GLuint *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = (GLfloat) *uiptr++; + } + } + break; + case GL_INT: + k = 0; + for (i=0;i<heightin;i++) { + GLint *iptr = (GLint *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = (GLfloat) *iptr++; + } + } + break; + case GL_FLOAT: + k = 0; + for (i=0;i<heightin;i++) { + GLfloat *fptr = (GLfloat *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = *fptr++; + } + } + break; + default: + return GLU_INVALID_ENUM; + } + + + /* + * Scale the image! + */ + + if (widthout > 1) + sx = (GLfloat) (widthin-1) / (GLfloat) (widthout-1); + else + sx = (GLfloat) (widthin-1); + if (heightout > 1) + sy = (GLfloat) (heightin-1) / (GLfloat) (heightout-1); + else + sy = (GLfloat) (heightin-1); + +/*#define POINT_SAMPLE*/ +#ifdef POINT_SAMPLE + for (i=0;i<heightout;i++) { + GLint ii = i * sy; + for (j=0;j<widthout;j++) { + GLint jj = j * sx; + + GLfloat *src = tempin + (ii * widthin + jj) * components; + GLfloat *dst = tempout + (i * widthout + j) * components; + + for (k=0;k<components;k++) { + *dst++ = *src++; + } + } + } +#else + if (sx<1.0 && sy<1.0) { + /* magnify both width and height: use weighted sample of 4 pixels */ + GLint i0, i1, j0, j1; + GLfloat alpha, beta; + GLfloat *src00, *src01, *src10, *src11; + GLfloat s1, s2; + GLfloat *dst; + + for (i=0;i<heightout;i++) { + i0 = i * sy; + i1 = i0 + 1; + if (i1 >= heightin) i1 = heightin-1; +/* i1 = (i+1) * sy - EPSILON;*/ + alpha = i*sy - i0; + for (j=0;j<widthout;j++) { + j0 = j * sx; + j1 = j0 + 1; + if (j1 >= widthin) j1 = widthin-1; +/* j1 = (j+1) * sx - EPSILON; */ + beta = j*sx - j0; + + /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */ + src00 = tempin + (i0 * widthin + j0) * components; + src01 = tempin + (i0 * widthin + j1) * components; + src10 = tempin + (i1 * widthin + j0) * components; + src11 = tempin + (i1 * widthin + j1) * components; + + dst = tempout + (i * widthout + j) * components; + + for (k=0;k<components;k++) { + s1 = *src00++ * (1.0-beta) + *src01++ * beta; + s2 = *src10++ * (1.0-beta) + *src11++ * beta; + *dst++ = s1 * (1.0-alpha) + s2 * alpha; + } + } + } + } + else { + /* shrink width and/or height: use an unweighted box filter */ + GLint i0, i1; + GLint j0, j1; + GLint ii, jj; + GLfloat sum, *dst; + + for (i=0;i<heightout;i++) { + i0 = i * sy; + i1 = i0 + 1; + if (i1 >= heightin) i1 = heightin-1; +/* i1 = (i+1) * sy - EPSILON; */ + for (j=0;j<widthout;j++) { + j0 = j * sx; + j1 = j0 + 1; + if (j1 >= widthin) j1 = widthin-1; +/* j1 = (j+1) * sx - EPSILON; */ + + dst = tempout + (i * widthout + j) * components; + + /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */ + for (k=0;k<components;k++) { + sum = 0.0; + for (ii=i0;ii<=i1;ii++) { + for (jj=j0;jj<=j1;jj++) { + sum += *(tempin + (ii * widthin + jj) * components + k); + } + } + sum /= (j1-j0+1) * (i1-i0+1); + *dst++ = sum; + } + } + } + } +#endif + + + /* + * Return output image + */ + + if (packrowlength>0) { + rowlen = packrowlength; + } + else { + rowlen = widthout; + } + if (sizeout >= packalignment) { + rowstride = components * rowlen; + } + else { + rowstride = packalignment/sizeout + * CEILING( components * rowlen * sizeout, packalignment ); + } + + switch (typeout) { + case GL_UNSIGNED_BYTE: + k = 0; + for (i=0;i<heightout;i++) { + GLubyte *ubptr = (GLubyte *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *ubptr++ = (GLubyte) tempout[k++]; + } + } + break; + case GL_BYTE: + k = 0; + for (i=0;i<heightout;i++) { + GLbyte *bptr = (GLbyte *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *bptr++ = (GLbyte) tempout[k++]; + } + } + break; + case GL_UNSIGNED_SHORT: + k = 0; + for (i=0;i<heightout;i++) { + GLushort *usptr = (GLushort *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *usptr++ = (GLushort) tempout[k++]; + } + } + break; + case GL_SHORT: + k = 0; + for (i=0;i<heightout;i++) { + GLshort *sptr = (GLshort *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *sptr++ = (GLshort) tempout[k++]; + } + } + break; + case GL_UNSIGNED_INT: + k = 0; + for (i=0;i<heightout;i++) { + GLuint *uiptr = (GLuint *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *uiptr++ = (GLuint) tempout[k++]; + } + } + break; + case GL_INT: + k = 0; + for (i=0;i<heightout;i++) { + GLint *iptr = (GLint *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *iptr++ = (GLint) tempout[k++]; + } + } + break; + case GL_FLOAT: + k = 0; + for (i=0;i<heightout;i++) { + GLfloat *fptr = (GLfloat *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *fptr++ = tempout[k++]; + } + } + break; + default: + return GLU_INVALID_ENUM; + } + + + /* free temporary image storage */ + free( tempin ); + free( tempout ); + + return 0; +} + + + +/* + * Return the largest k such that 2^k <= n. + */ +static GLint ilog2( GLint n ) +{ + GLint k; + + if (n<=0) return 0; + for (k=0; n>>=1; k++) ; + return k; +} + + + +/* + * Find the value nearest to n which is also a power of two. + */ +static GLint round2( GLint n ) +{ + GLint m; + + for (m=1; m<n; m*=2) + ; + + /* m>=n */ + if (m-n <= n-m/2) { + return m; + } + else { + return m/2; + } +} + + +/* + * Given an pixel format and datatype, return the number of bytes to + * store one pixel. + */ +static GLint bytes_per_pixel( GLenum format, GLenum type ) +{ + GLint n, m; + + switch (format) { + case GL_COLOR_INDEX: + case GL_STENCIL_INDEX: + case GL_DEPTH_COMPONENT: + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_LUMINANCE: + n = 1; + break; + case GL_LUMINANCE_ALPHA: + n = 2; + break; + case GL_RGB: + n = 3; + break; + case GL_RGBA: +#ifdef GL_EXT_abgr + case GL_ABGR_EXT: +#endif + n = 4; + break; + default: + n = 0; + } + + switch (type) { + case GL_UNSIGNED_BYTE: m = sizeof(GLubyte); break; + case GL_BYTE: m = sizeof(GLbyte); break; + case GL_BITMAP: m = 1; break; + case GL_UNSIGNED_SHORT: m = sizeof(GLushort); break; + case GL_SHORT: m = sizeof(GLshort); break; + case GL_UNSIGNED_INT: m = sizeof(GLuint); break; + case GL_INT: m = sizeof(GLint); break; + case GL_FLOAT: m = sizeof(GLfloat); break; + default: m = 0; + } + + return n * m; +} + + + +/* + * WARNING: This function isn't finished and has never been tested!!!! + */ +GLint GLAPIENTRY gluBuild1DMipmaps( GLenum target, GLint components, + GLint width, GLenum format, + GLenum type, const void *data ) +{ + GLubyte *texture; + GLint levels, max_levels; + GLint new_width, max_width; + GLint i, j, k, l; + + if (width < 1) + return GLU_INVALID_VALUE; + + glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max_width ); + max_levels = ilog2( max_width ) + 1; + + /* Compute how many mipmap images to make */ + levels = ilog2( width ) + 1; + if (levels>max_levels) { + levels = max_levels; + } + + new_width = 1 << (levels-1); + + texture = (GLubyte *) malloc( new_width * components ); + if (!texture) { + return GLU_OUT_OF_MEMORY; + } + + if (width != new_width) { + /* initial rescaling */ + switch (type) { + case GL_UNSIGNED_BYTE: + { + GLubyte *ub_data = (GLubyte *) data; + for (i=0;i<new_width;i++) { + j = i * width / new_width; + for (k=0;k<components;k++) { + texture[i*components+k] = ub_data[j*components+k]; + } + } + } + break; + default: + /* Not implemented */ + return GLU_ERROR; + } + } + + /* generate and load mipmap images */ + for (l=0;l<levels;l++) { + glTexImage1D( GL_TEXTURE_1D, l, components, new_width, 0, + format, GL_UNSIGNED_BYTE, texture ); + + /* Scale image down to 1/2 size */ + new_width = new_width / 2; + for (i=0;i<new_width;i++) { + for (k=0;k<components;k++) { + GLint sample1, sample2; + sample1 = (GLint) texture[i*2*components+k]; + sample2 = (GLint) texture[(i*2+1)*components+k]; + texture[i*components+k] = (GLubyte) ((sample1 + sample2) / 2); + } + } + } + + free( texture ); + + /* make sure remaining mipmap levels are removed */ + for (l=levels;l<max_levels;l++) { + glTexImage1D( GL_TEXTURE_1D, l, components, 0, 0, + format, GL_UNSIGNED_BYTE, NULL ); + } + + return 0; +} + + + +GLint GLAPIENTRY gluBuild2DMipmaps( GLenum target, GLint components, + GLint width, GLint height, GLenum format, + GLenum type, const void *data ) +{ + GLint w, h, maxsize; + void *image, *newimage; + GLint neww, newh, level, bpp; + int error; + + if (width < 1 || height < 1) + return GLU_INVALID_VALUE; + + glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxsize ); + + w = round2( width ); + if (w>maxsize) { + w = maxsize; + } + h = round2( height ); + if (h>maxsize) { + h = maxsize; + } + + bpp = bytes_per_pixel( format, type ); + if (bpp==0) { + /* probably a bad format or type enum */ + return GLU_INVALID_ENUM; + } + + if (w!=width || h!=height) { + /* must rescale image to get "top" mipmap texture image */ + image = malloc( (w+4) * h * bpp ); + if (!image) { + return GLU_OUT_OF_MEMORY; + } + error = gluScaleImage( format, width, height, type, data, + w, h, type, image ); + if (error) { + return error; + } + } + else { + image = (void *) data; + } + + level = 0; + while (1) { + glTexImage2D( target, level, components, w, h, 0, format, type, image ); + + if (w==1 && h==1) break; + + neww = (w<2) ? 1 : w/2; + newh = (h<2) ? 1 : h/2; + newimage = malloc( (neww+4) * newh * bpp ); + if (!newimage) { + return GLU_OUT_OF_MEMORY; + } + + error = gluScaleImage( format, w, h, type, image, + neww, newh, type, newimage ); + if (error) { + return error; + } + + if (image!=data) { + free( image ); + } + image = newimage; + + w = neww; + h = newh; + level++; + } + + if (image!=data) { + free( image ); + } + + return 0; +} + diff --git a/src/glu/mesa/mms_depend b/src/glu/mesa/mms_depend new file mode 100644 index 00000000000..372e3fff1e9 --- /dev/null +++ b/src/glu/mesa/mms_depend @@ -0,0 +1,13 @@ +# DO NOT DELETE THIS LINE -- make depend depends on it. + +glu.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h +mipmap.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h +nurbs.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h nurbs.h +nurbscrv.obj : nurbs.h gluP.h [-.include.gl]gl.h [-.include.gl]glu.h +nurbssrf.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h nurbs.h +nurbsutl.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h nurbs.h +project.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h +quadric.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h +tess.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h tess.h +tesselat.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h tess.h +polytest.obj : gluP.h [-.include.gl]gl.h [-.include.gl]glu.h tess.h diff --git a/src/glu/mesa/nurbs.c b/src/glu/mesa/nurbs.c new file mode 100644 index 00000000000..65bc6f8acb7 --- /dev/null +++ b/src/glu/mesa/nurbs.c @@ -0,0 +1,715 @@ +/* $Id: nurbs.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.1 + * Copyright (C) 1995-1999 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: nurbs.c,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.14 1999/01/03 03:23:15 brianp + * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump) + * + * Revision 1.13 1998/06/01 01:07:49 brianp + * small update for Next/OpenStep from Alexander Mai + * + * Revision 1.12 1998/03/15 18:14:30 brianp + * fixed a compiler cast warning + * + * Revision 1.11 1998/02/07 14:29:11 brianp + * fixed casting problem in gluNurbsCallback, again + * + * Revision 1.10 1998/02/04 00:21:20 brianp + * fixed cygnus compilation problem (Stephane Rehel) + * + * Revision 1.9 1998/01/16 03:35:26 brianp + * fixed Windows compilation warnings (Theodore Jump) + * + * Revision 1.8 1997/09/17 01:51:48 brianp + * changed glu*Callback() functions to match prototype in glu.h + * + * Revision 1.7 1997/07/24 01:28:44 brianp + * changed precompiled header symbol from PCH to PC_HEADER + * + * Revision 1.6 1997/07/24 01:26:31 brianp + * added CALLBACK keyword to gluNurbsCallback() + * + * 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:17:22 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:11:23 brianp + * ifdef'd out unimplemented trimmed nurbs code + * + * Revision 1.1 1996/09/27 01:19:39 brianp + * Initial revision + * + */ + + +/* + * NURBS implementation written by Bogdan Sikorski ([email protected]) + * See README2 for more info. + */ + +#ifdef PC_HEADER +#include "all.h" +#else +#include <stdio.h> +#include <stdlib.h> +#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 (GLCALLBACK *fn)()) +{ +#if defined(__CYGWIN32__) || defined(OPENSTEP) + nobj->error_callback = (void(*)(GLenum))fn; +#else + nobj->error_callback = (void(GLCALLBACK*)(GLenum))fn; +#endif + + 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; +} + diff --git a/src/glu/mesa/nurbs.h b/src/glu/mesa/nurbs.h new file mode 100644 index 00000000000..fc2b4f7d557 --- /dev/null +++ b/src/glu/mesa/nurbs.h @@ -0,0 +1,252 @@ +/* $Id: nurbs.h,v 1.1 1999/08/19 00:55:42 jtg Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.1 + * Copyright (C) 1995-1999 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: nurbs.h,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.5 1999/02/27 13:55:31 brianp + * fixed BeOS-related GLU typedef problems + * + * Revision 1.4 1999/01/03 03:23:15 brianp + * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump) + * + * Revision 1.3 1997/05/27 03:18:23 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 ([email protected]) + * See README2 for more info. + */ + + +#ifndef NURBS_H +#define NURBS_H + + +#define EPSILON 1e-06 /* epsilon for double precision compares */ + +typedef enum +{ + GLU_NURBS_CURVE, GLU_NURBS_SURFACE, GLU_NURBS_TRIM, GLU_NURBS_NO_TRIM, + GLU_NURBS_TRIM_DONE, GLU_NURBS_NONE +} GLU_nurbs_enum; + +typedef enum +{ + GLU_TRIM_NURBS, GLU_TRIM_PWL +} GLU_trim_enum; + +typedef struct +{ + GLint sknot_count; + GLfloat *sknot; + GLint tknot_count; + GLfloat *tknot; + GLint s_stride; + GLint t_stride; + GLfloat *ctrlarray; + GLint sorder; + GLint torder; + GLint dim; + GLenum type; +} surface_attribs; + +typedef struct +{ + surface_attribs geom; + surface_attribs color; + surface_attribs texture; + surface_attribs normal; +} nurbs_surface; + +typedef struct +{ + GLint knot_count; + GLfloat *knot; + GLint stride; + GLfloat *ctrlarray; + GLint order; + GLint dim; + GLenum type; +} curve_attribs; + +typedef struct +{ + GLint pt_count; + GLfloat *ctrlarray; + GLint stride; + GLint dim; + GLenum type; +} pwl_curve_attribs; + +typedef struct +{ + curve_attribs geom; + curve_attribs color; + curve_attribs texture; + curve_attribs normal; +} nurbs_curve; + +typedef struct trim_list_str +{ + GLU_trim_enum trim_type; + union + { + pwl_curve_attribs pwl_curve; + curve_attribs nurbs_curve; + } curve; + struct trim_list_str *next; +} trim_list; + +typedef struct seg_trim_str +{ + GLfloat *points; + GLint pt_cnt,seg_array_len; + struct seg_trim_str *next; +} trim_segments; + +typedef struct nurbs_trim_str +{ + trim_list *trim_loop; + trim_segments *segments; + struct nurbs_trim_str *next; +} nurbs_trim; + +typedef struct +{ + GLfloat model[16],proj[16],viewport[4]; +} culling_and_sampling_str; + +struct GLUnurbs { + GLboolean culling; + GLenum error; + void (GLCALLBACK *error_callback)( GLenum err ); + GLenum display_mode; + GLU_nurbs_enum nurbs_type; + GLboolean auto_load_matrix; + culling_and_sampling_str + sampling_matrices; + GLenum sampling_method; + GLfloat sampling_tolerance; + GLfloat parametric_tolerance; + GLint u_step, v_step; + nurbs_surface surface; + nurbs_curve curve; + nurbs_trim *trim; +}; + +typedef struct +{ + GLfloat *knot; + GLint nknots; + GLfloat *unified_knot; + GLint unified_nknots; + GLint order; + GLint t_min,t_max; + GLint delta_nknots; + GLboolean open_at_begin,open_at_end; + GLfloat *new_knot; + GLfloat *alpha; +} knot_str_type; + +typedef struct +{ + GLfloat *geom_ctrl; + GLint geom_s_stride,geom_t_stride; + GLfloat **geom_offsets; + GLint geom_s_pt_cnt,geom_t_pt_cnt; + GLfloat *color_ctrl; + GLint color_s_stride,color_t_stride; + GLfloat **color_offsets; + GLint color_s_pt_cnt,color_t_pt_cnt; + GLfloat *normal_ctrl; + GLint normal_s_stride,normal_t_stride; + GLfloat **normal_offsets; + GLint normal_s_pt_cnt,normal_t_pt_cnt; + GLfloat *texture_ctrl; + GLint texture_s_stride,texture_t_stride; + GLfloat **texture_offsets; + GLint texture_s_pt_cnt,texture_t_pt_cnt; + GLint s_bezier_cnt,t_bezier_cnt; +} new_ctrl_type; + +extern void call_user_error( GLUnurbsObj *nobj, GLenum error ); + +extern GLenum test_knot(GLint nknots, GLfloat *knot, GLint order); + +extern GLenum explode_knot(knot_str_type *the_knot); + +extern GLenum calc_alphas(knot_str_type *the_knot); + +extern GLenum calc_new_ctrl_pts(GLfloat *ctrl,GLint stride,knot_str_type *the_knot, + GLint dim,GLfloat **new_ctrl,GLint *ncontrol); + +extern GLenum glu_do_sampling_crv(GLUnurbsObj *nobj, GLfloat *new_ctrl,GLint n_ctrl, + GLint order,GLint dim,GLint **factors); + +extern GLenum glu_do_sampling_3D(GLUnurbsObj *nobj, new_ctrl_type *new_ctrl, + int **sfactors, GLint **tfactors); + +extern GLenum glu_do_sampling_uv(GLUnurbsObj *nobj, new_ctrl_type *new_ctrl, + int **sfactors, GLint **tfactors); + +extern GLenum glu_do_sampling_param_3D(GLUnurbsObj *nobj, new_ctrl_type *new_ctrl, + int **sfactors, GLint **tfactors); + +extern GLboolean fine_culling_test_2D(GLUnurbsObj *nobj, GLfloat *ctrl, GLint n_ctrl, + GLint stride, GLint dim); + +extern GLboolean fine_culling_test_3D(GLUnurbsObj *nobj, GLfloat *ctrl, + GLint s_n_ctrl, GLint t_n_ctrl, GLint s_stride, GLint t_stride, GLint dim); + +extern void do_nurbs_curve( GLUnurbsObj *nobj); + +extern void do_nurbs_surface( GLUnurbsObj *nobj); + +extern GLenum patch_trimming(GLUnurbsObj *nobj,new_ctrl_type *new_ctrl, + GLint *sfactors, GLint *tfactors); + +extern void collect_unified_knot(knot_str_type *dest, knot_str_type *src, + GLfloat maximal_min_knot, GLfloat minimal_max_knot); + +extern 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); + +extern void free_unified_knots(knot_str_type *geom_knot, knot_str_type *color_knot, + knot_str_type *normal_knot, knot_str_type *texture_knot); + + + +#endif diff --git a/src/glu/mesa/nurbscrv.c b/src/glu/mesa/nurbscrv.c new file mode 100644 index 00000000000..022818b73ca --- /dev/null +++ b/src/glu/mesa/nurbscrv.c @@ -0,0 +1,500 @@ +/* $Id: nurbscrv.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: nurbscrv.c,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.6 1997/07/24 01:28:44 brianp + * changed precompiled header symbol from PCH to PC_HEADER + * + * 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:21:22 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:12:22 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 ([email protected]) + * 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 + + +static int +get_curve_dim(GLenum type) +{ + switch(type) + { + case GL_MAP1_VERTEX_3: return 3; + case GL_MAP1_VERTEX_4: return 4; + case GL_MAP1_INDEX: return 1; + case GL_MAP1_COLOR_4: return 4; + case GL_MAP1_NORMAL: return 3; + case GL_MAP1_TEXTURE_COORD_1: return 1; + case GL_MAP1_TEXTURE_COORD_2: return 2; + case GL_MAP1_TEXTURE_COORD_3: return 3; + case GL_MAP1_TEXTURE_COORD_4: return 4; + default: abort(); /* TODO: is this OK? */ + } + return 0; /*never get here*/ +} + +static GLenum +test_nurbs_curve(GLUnurbsObj *nobj, curve_attribs *attribs) +{ + GLenum err; + GLint tmp_int; + + if(attribs->order < 0) + { + call_user_error(nobj,GLU_INVALID_VALUE); + return GLU_ERROR; + } + glGetIntegerv(GL_MAX_EVAL_ORDER,&tmp_int); + if(attribs->order > tmp_int || attribs->order < 2) + { + call_user_error(nobj,GLU_NURBS_ERROR1); + return GLU_ERROR; + } + if(attribs->knot_count < attribs->order +2) + { + call_user_error(nobj,GLU_NURBS_ERROR2); + return GLU_ERROR; + } + if(attribs->stride < 0) + { + call_user_error(nobj,GLU_NURBS_ERROR34); + return GLU_ERROR; + } + if(attribs->knot==NULL || attribs->ctrlarray==NULL) + { + call_user_error(nobj,GLU_NURBS_ERROR36); + return GLU_ERROR; + } + if((err=test_knot(attribs->knot_count,attribs->knot,attribs->order)) + !=GLU_NO_ERROR) + { + call_user_error(nobj,err); + return GLU_ERROR; + } + return GLU_NO_ERROR; +} + +static GLenum +test_nurbs_curves(GLUnurbsObj *nobj) +{ + /* test the geometric data */ + if(test_nurbs_curve(nobj,&(nobj->curve.geom))!=GLU_NO_ERROR) + return GLU_ERROR; + /* now test the attributive data */ + /* color */ + if(nobj->curve.color.type!=GLU_INVALID_ENUM) + if(test_nurbs_curve(nobj,&(nobj->curve.color))!=GLU_NO_ERROR) + return GLU_ERROR; + /* normal */ + if(nobj->curve.normal.type!=GLU_INVALID_ENUM) + if(test_nurbs_curve(nobj,&(nobj->curve.normal))!=GLU_NO_ERROR) + return GLU_ERROR; + /* texture */ + if(nobj->curve.texture.type!=GLU_INVALID_ENUM) + if(test_nurbs_curve(nobj,&(nobj->curve.texture))!=GLU_NO_ERROR) + return GLU_ERROR; + return GLU_NO_ERROR; +} + +/* prepare the knot information structures */ +static GLenum +fill_knot_structures(GLUnurbsObj *nobj,knot_str_type *geom_knot, + knot_str_type *color_knot, knot_str_type *normal_knot, + knot_str_type *texture_knot) +{ + GLint order; + GLfloat *knot; + GLint nknots; + GLint t_min,t_max; + + geom_knot->unified_knot=NULL; + knot=geom_knot->knot=nobj->curve.geom.knot; + nknots=geom_knot->nknots=nobj->curve.geom.knot_count; + order=geom_knot->order=nobj->curve.geom.order; + geom_knot->delta_nknots=0; + t_min=geom_knot->t_min=order-1; + t_max=geom_knot->t_max=nknots-order; + if(fabs(knot[t_min]-knot[t_max])<EPSILON) + { + call_user_error(nobj,GLU_NURBS_ERROR3); + return GLU_ERROR; + } + if(fabs(knot[0]-knot[t_min])<EPSILON) + { + /* knot open at beggining */ + geom_knot->open_at_begin=GL_TRUE; + } + else + geom_knot->open_at_begin=GL_FALSE; + if(fabs(knot[t_max]-knot[nknots-1])<EPSILON) + { + /* knot open at end */ + geom_knot->open_at_end=GL_TRUE; + } + else + geom_knot->open_at_end=GL_FALSE; + if(nobj->curve.color.type!=GLU_INVALID_ENUM) + { + color_knot->unified_knot=(GLfloat *)1; + knot=color_knot->knot=nobj->curve.color.knot; + nknots=color_knot->nknots=nobj->curve.color.knot_count; + order=color_knot->order=nobj->curve.color.order; + color_knot->delta_nknots=0; + t_min=color_knot->t_min=order-1; + t_max=color_knot->t_max=nknots-order; + if(fabs(knot[t_min]-knot[t_max])<EPSILON) + { + call_user_error(nobj,GLU_NURBS_ERROR3); + return GLU_ERROR; + } + if(fabs(knot[0]-knot[t_min])<EPSILON) + { + /* knot open at beggining */ + color_knot->open_at_begin=GL_TRUE; + } + else + color_knot->open_at_begin=GL_FALSE; + if(fabs(knot[t_max]-knot[nknots-1])<EPSILON) + { + /* knot open at end */ + color_knot->open_at_end=GL_TRUE; + } + else + color_knot->open_at_end=GL_FALSE; + } + else + color_knot->unified_knot=NULL; + if(nobj->curve.normal.type!=GLU_INVALID_ENUM) + { + normal_knot->unified_knot=(GLfloat *)1; + knot=normal_knot->knot=nobj->curve.normal.knot; + nknots=normal_knot->nknots=nobj->curve.normal.knot_count; + order=normal_knot->order=nobj->curve.normal.order; + normal_knot->delta_nknots=0; + t_min=normal_knot->t_min=order-1; + t_max=normal_knot->t_max=nknots-order; + if(fabs(knot[t_min]-knot[t_max])<EPSILON) + { + call_user_error(nobj,GLU_NURBS_ERROR3); + return GLU_ERROR; + } + if(fabs(knot[0]-knot[t_min])<EPSILON) + { + /* knot open at beggining */ + normal_knot->open_at_begin=GL_TRUE; + } + else + normal_knot->open_at_begin=GL_FALSE; + if(fabs(knot[t_max]-knot[nknots-1])<EPSILON) + { + /* knot open at end */ + normal_knot->open_at_end=GL_TRUE; + } + else + normal_knot->open_at_end=GL_FALSE; + } + else + normal_knot->unified_knot=NULL; + if(nobj->curve.texture.type!=GLU_INVALID_ENUM) + { + texture_knot->unified_knot=(GLfloat *)1; + knot=texture_knot->knot=nobj->curve.texture.knot; + nknots=texture_knot->nknots=nobj->curve.texture.knot_count; + order=texture_knot->order=nobj->curve.texture.order; + texture_knot->delta_nknots=0; + t_min=texture_knot->t_min=order-1; + t_max=texture_knot->t_max=nknots-order; + if(fabs(knot[t_min]-knot[t_max])<EPSILON) + { + call_user_error(nobj,GLU_NURBS_ERROR3); + return GLU_ERROR; + } + if(fabs(knot[0]-knot[t_min])<EPSILON) + { + /* knot open at beggining */ + texture_knot->open_at_begin=GL_TRUE; + } + else + texture_knot->open_at_begin=GL_FALSE; + if(fabs(knot[t_max]-knot[nknots-1])<EPSILON) + { + /* knot open at end */ + texture_knot->open_at_end=GL_TRUE; + } + else + texture_knot->open_at_end=GL_FALSE; + } + else + texture_knot->unified_knot=NULL; + return GLU_NO_ERROR; +} + +/* covert the NURBS curve into a series of adjacent Bezier curves */ +static GLenum +convert_curve(knot_str_type *the_knot, curve_attribs *attrib, + GLfloat **new_ctrl,GLint *ncontrol) +{ + GLenum err; + + if((err=explode_knot(the_knot))!=GLU_NO_ERROR) + { + if(the_knot->unified_knot) + { + free(the_knot->unified_knot); + the_knot->unified_knot=NULL; + } + return err; + } + if(the_knot->unified_knot) + { + free(the_knot->unified_knot); + the_knot->unified_knot=NULL; + } + if((err=calc_alphas(the_knot))!=GLU_NO_ERROR) + { + free(the_knot->new_knot); + return err; + } + free(the_knot->new_knot); + if((err=calc_new_ctrl_pts(attrib->ctrlarray,attrib->stride,the_knot, + attrib->dim,new_ctrl,ncontrol)) + !=GLU_NO_ERROR) + { + free(the_knot->alpha); + return err; + } + free(the_knot->alpha); + return GLU_NO_ERROR; +} + +/* covert curves - geometry and possible attribute ones into equivalent */ +/* sequence of adjacent Bezier curves */ +static GLenum +convert_curves(GLUnurbsObj *nobj, GLfloat **new_geom_ctrl, + GLint *ncontrol, GLfloat **new_color_ctrl, GLfloat **new_normal_ctrl, + GLfloat **new_texture_ctrl) +{ + knot_str_type geom_knot,color_knot,normal_knot,texture_knot; + GLint junk; + GLenum err; + + *new_color_ctrl=*new_normal_ctrl=*new_texture_ctrl=NULL; + + if(fill_knot_structures(nobj,&geom_knot,&color_knot,&normal_knot, + &texture_knot)!=GLU_NO_ERROR) + return GLU_ERROR; + + /* unify knots - all knots should have the same number of working */ + /* ranges */ + if((err=select_knot_working_range(nobj,&geom_knot,&color_knot,&normal_knot, + &texture_knot))!=GLU_NO_ERROR) + { + return err; + } + /* convert the geometry curve */ + nobj->curve.geom.dim=get_curve_dim(nobj->curve.geom.type); + if((err=convert_curve(&geom_knot,&(nobj->curve.geom),new_geom_ctrl, + ncontrol))!=GLU_NO_ERROR) + { + free_unified_knots(&geom_knot,&color_knot,&normal_knot,&texture_knot); + call_user_error(nobj,err); + return err; + } + /* if additional attributive curves are given convert them as well */ + if(color_knot.unified_knot) + { + nobj->curve.color.dim=get_curve_dim(nobj->curve.color.type); + if((err=convert_curve(&color_knot,&(nobj->curve.color), + new_color_ctrl,&junk))!=GLU_NO_ERROR) + { + free_unified_knots(&geom_knot,&color_knot,&normal_knot,&texture_knot); + free(*new_geom_ctrl); + call_user_error(nobj,err); + return err; + } + } + if(normal_knot.unified_knot) + { + nobj->curve.normal.dim=get_curve_dim(nobj->curve.normal.type); + if((err=convert_curve(&normal_knot,&(nobj->curve.normal), + new_normal_ctrl,&junk))!=GLU_NO_ERROR) + { + free_unified_knots(&geom_knot,&color_knot,&normal_knot,&texture_knot); + free(*new_geom_ctrl); + if(*new_color_ctrl) + free(*new_color_ctrl); + call_user_error(nobj,err); + return err; + } + } + if(texture_knot.unified_knot) + { + nobj->curve.texture.dim=get_curve_dim(nobj->curve.texture.type); + if((err=convert_curve(&texture_knot,&(nobj->curve.texture), + new_texture_ctrl,&junk))!=GLU_NO_ERROR) + { + free_unified_knots(&geom_knot,&color_knot,&normal_knot,&texture_knot); + free(*new_geom_ctrl); + if(*new_color_ctrl) + free(*new_color_ctrl); + if(*new_normal_ctrl) + free(*new_normal_ctrl); + call_user_error(nobj,err); + return err; + } + } + return GLU_NO_ERROR; +} + +/* main NURBS curve procedure */ +void do_nurbs_curve( GLUnurbsObj *nobj) +{ + GLint geom_order,color_order=0,normal_order=0,texture_order=0; + GLenum geom_type; + GLint n_ctrl; + GLfloat *new_geom_ctrl,*new_color_ctrl,*new_normal_ctrl,*new_texture_ctrl; + GLfloat *geom_ctrl,*color_ctrl,*normal_ctrl,*texture_ctrl; + GLint *factors; + GLint i,j; + GLint geom_dim,color_dim=0,normal_dim=0,texture_dim=0; + + /* test the user supplied data */ + if(test_nurbs_curves(nobj)!=GLU_NO_ERROR) + return; + + if(convert_curves(nobj,&new_geom_ctrl,&n_ctrl,&new_color_ctrl, + &new_normal_ctrl,&new_texture_ctrl)!=GLU_NO_ERROR) + return; + + geom_order=nobj->curve.geom.order; + geom_type=nobj->curve.geom.type; + geom_dim=nobj->curve.geom.dim; + + if(glu_do_sampling_crv(nobj,new_geom_ctrl,n_ctrl,geom_order,geom_dim, + &factors) + !=GLU_NO_ERROR) + { + free(new_geom_ctrl); + if(new_color_ctrl) + free(new_color_ctrl); + if(new_normal_ctrl) + free(new_normal_ctrl); + if(new_texture_ctrl) + free(new_texture_ctrl); + return; + } + glEnable(geom_type); + if(new_color_ctrl) + { + glEnable(nobj->curve.color.type); + color_dim=nobj->curve.color.dim; + color_ctrl=new_color_ctrl; + color_order=nobj->curve.color.order; + } + if(new_normal_ctrl) + { + glEnable(nobj->curve.normal.type); + normal_dim=nobj->curve.normal.dim; + normal_ctrl=new_normal_ctrl; + normal_order=nobj->curve.normal.order; + } + if(new_texture_ctrl) + { + glEnable(nobj->curve.texture.type); + texture_dim=nobj->curve.texture.dim; + texture_ctrl=new_texture_ctrl; + texture_order=nobj->curve.texture.order; + } + for(i=0 , j=0, geom_ctrl=new_geom_ctrl; + i<n_ctrl; + i+=geom_order , j++ , geom_ctrl+=geom_order*geom_dim) + { + if(fine_culling_test_2D(nobj,geom_ctrl,geom_order,geom_dim,geom_dim)) + { + color_ctrl+=color_order*color_dim; + normal_ctrl+=normal_order*normal_dim; + texture_ctrl+=texture_order*texture_dim; + continue; + } + glMap1f(geom_type, 0.0, 1.0, geom_dim, geom_order, geom_ctrl); + if(new_color_ctrl) + { + glMap1f(nobj->curve.color.type, 0.0, 1.0, color_dim, + color_order,color_ctrl); + color_ctrl+=color_order*color_dim; + } + if(new_normal_ctrl) + { + glMap1f(nobj->curve.normal.type, 0.0, 1.0, normal_dim, + normal_order,normal_ctrl); + normal_ctrl+=normal_order*normal_dim; + } + if(new_texture_ctrl) + { + glMap1f(nobj->curve.texture.type, 0.0, 1.0, texture_dim, + texture_order,texture_ctrl); + texture_ctrl+=texture_order*texture_dim; + } + glMapGrid1f(factors[j],0.0,1.0); + glEvalMesh1(GL_LINE,0,factors[j]); + } + free(new_geom_ctrl); + free(factors); + if(new_color_ctrl) + free(new_color_ctrl); + if(new_normal_ctrl) + free(new_normal_ctrl); + if(new_texture_ctrl) + free(new_texture_ctrl); +} + + diff --git a/src/glu/mesa/nurbssrf.c b/src/glu/mesa/nurbssrf.c new file mode 100644 index 00000000000..57eb9569862 --- /dev/null +++ b/src/glu/mesa/nurbssrf.c @@ -0,0 +1,1422 @@ +/* $Id: nurbssrf.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: nurbssrf.c,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * 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 <string.h> + * + * 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 ([email protected]) + * See README2 for more info. + */ + + +#ifdef PC_HEADER +#include "all.h" +#else +#include <math.h> +#include <stdlib.h> +#include <string.h> +#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;i<t_cnt;i++) + { + if((err=calc_new_ctrl_pts(ctrl_offset,attrib->s_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;i<t_cnt;i++) + free(tmp_ctrl[i]); + free(tmp_ctrl); + return GLU_OUT_OF_MEMORY; + } + for(i=0;i<tmp_n_control;i++) + for(j=0;j<t_cnt;j++) + MEMCPY(*new_ctrl+j*dim+i*dim*t_cnt,tmp_ctrl[j]+dim*i, + sizeof(GLfloat)*dim); + for(i=0;i<t_cnt;i++) + free(tmp_ctrl[i]); + free(tmp_ctrl); + *s_n_ctrl=tmp_n_control; + + if((tmp_ctrl=(GLfloat **)malloc(sizeof(GLfloat *)*(*s_n_ctrl)))==NULL) + { + return GLU_OUT_OF_MEMORY; + } + if((err=explode_knot(t_knot))!=GLU_NO_ERROR) + { + free(tmp_ctrl); + if(t_knot->unified_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])<EPSILON) + { + call_user_error(nobj,GLU_NURBS_ERROR3); + return GLU_ERROR; + } + if(fabs(knot[0]-knot[t_min])<EPSILON) + { + /* knot open at beggining */ + geom_s_knot->open_at_begin=GL_TRUE; + } + else + geom_s_knot->open_at_begin=GL_FALSE; + if(fabs(knot[t_max]-knot[nknots-1])<EPSILON) + { + /* knot open at end */ + geom_s_knot->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])<EPSILON) + { + call_user_error(nobj,GLU_NURBS_ERROR3); + return GLU_ERROR; + } + if(fabs(knot[0]-knot[t_min])<EPSILON) + { + /* knot open at beggining */ + geom_t_knot->open_at_begin=GL_TRUE; + } + else + geom_t_knot->open_at_begin=GL_FALSE; + if(fabs(knot[t_max]-knot[nknots-1])<EPSILON) + { + /* knot open at end */ + geom_t_knot->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])<EPSILON) + { + call_user_error(nobj,GLU_NURBS_ERROR3); + return GLU_ERROR; + } + if(fabs(knot[0]-knot[t_min])<EPSILON) + { + /* knot open at beggining */ + color_s_knot->open_at_begin=GL_TRUE; + } + else + color_s_knot->open_at_begin=GL_FALSE; + if(fabs(knot[t_max]-knot[nknots-1])<EPSILON) + { + /* knot open at end */ + color_s_knot->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])<EPSILON) + { + call_user_error(nobj,GLU_NURBS_ERROR3); + return GLU_ERROR; + } + if(fabs(knot[0]-knot[t_min])<EPSILON) + { + /* knot open at beggining */ + color_t_knot->open_at_begin=GL_TRUE; + } + else + color_t_knot->open_at_begin=GL_FALSE; + if(fabs(knot[t_max]-knot[nknots-1])<EPSILON) + { + /* knot open at end */ + color_t_knot->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])<EPSILON) + { + call_user_error(nobj,GLU_NURBS_ERROR3); + return GLU_ERROR; + } + if(fabs(knot[0]-knot[t_min])<EPSILON) + { + /* knot open at beggining */ + normal_s_knot->open_at_begin=GL_TRUE; + } + else + normal_s_knot->open_at_begin=GL_FALSE; + if(fabs(knot[t_max]-knot[nknots-1])<EPSILON) + { + /* knot open at end */ + normal_s_knot->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])<EPSILON) + { + call_user_error(nobj,GLU_NURBS_ERROR3); + return GLU_ERROR; + } + if(fabs(knot[0]-knot[t_min])<EPSILON) + { + /* knot open at beggining */ + normal_t_knot->open_at_begin=GL_TRUE; + } + else + normal_t_knot->open_at_begin=GL_FALSE; + if(fabs(knot[t_max]-knot[nknots-1])<EPSILON) + { + /* knot open at end */ + normal_t_knot->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])<EPSILON) + { + call_user_error(nobj,GLU_NURBS_ERROR3); + return GLU_ERROR; + } + if(fabs(knot[0]-knot[t_min])<EPSILON) + { + /* knot open at beggining */ + texture_s_knot->open_at_begin=GL_TRUE; + } + else + texture_s_knot->open_at_begin=GL_FALSE; + if(fabs(knot[t_max]-knot[nknots-1])<EPSILON) + { + /* knot open at end */ + texture_s_knot->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])<EPSILON) + { + call_user_error(nobj,GLU_NURBS_ERROR3); + return GLU_ERROR; + } + if(fabs(knot[0]-knot[t_min])<EPSILON) + { + /* knot open at beggining */ + texture_t_knot->open_at_begin=GL_TRUE; + } + else + texture_t_knot->open_at_begin=GL_FALSE; + if(fabs(knot[t_max]-knot[nknots-1])<EPSILON) + { + /* knot open at end */ + texture_t_knot->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(left<right) + { + glMapGrid2f(right, 0.0, 1.0, top, 0.0, 1.0); + glEvalMesh2(display_mode,1,right, 1, top); + tesselate_strip_s(display_mode,1,right,1,1,left,0,(GLfloat)left); + tesselate_bottom_left_corner(display_mode,(GLfloat)(1.0/left), + (GLfloat)(1.0/bottom)); +/* tesselate_strip_t(display_mode,1,top,1,1,bottom,0,(GLfloat)bottom);*/ + tesselate_strip_t(display_mode,top,1,1,bottom,1,0,(GLfloat)bottom); + } + else + if(left==right) + { + glMapGrid2f(right, 0.0, 1.0, top, 0.0, 1.0); + glEvalMesh2(display_mode,1,right, 0, top); +/* tesselate_strip_t(display_mode,0,top,1,0,bottom,0,(GLfloat)bottom);*/ + tesselate_strip_t(display_mode,top,0,1,bottom,0,0,(GLfloat)bottom); + } + else + { + glMapGrid2f(left, 0.0, 1.0, top, 0.0, 1.0); + glEvalMesh2(display_mode,1,left, 0, top-1); +/* tesselate_strip_t(display_mode,0,top-1,1,0,bottom-1,0, + (GLfloat)bottom);*/ + tesselate_strip_t(display_mode,top-1,0,1,bottom-1,0,0, + (GLfloat)bottom); + tesselate_bottom_right_corner(display_mode,top-1,bottom-1, + (GLfloat)(1.0/right),(GLfloat)(1.0/bottom)); +/* tesselate_strip_s(display_mode,1,left,top-1,1,right,right, + (GLfloat)right);*/ + tesselate_strip_s(display_mode,left,1,top-1,right,1,right, + (GLfloat)right); + } + } + else + if(top==bottom) + { + if(left<right) + { + glMapGrid2f(right, 0.0, 1.0, top, 0.0, 1.0); + glEvalMesh2(display_mode,0,right, 1, top); + tesselate_strip_s(display_mode,0,right,1,0,left,0,(GLfloat)left); + } + else + if(left==right) + { + glMapGrid2f(right, 0.0, 1.0, top, 0.0, 1.0); + glEvalMesh2(display_mode,0,right, 0, top); + } + else + { + glMapGrid2f(left, 0.0, 1.0, top, 0.0, 1.0); + glEvalMesh2(display_mode,0,left, 0, top-1); +/* tesselate_strip_s(display_mode,0,left,top-1,0,right,right, + (GLfloat)right);*/ + tesselate_strip_s(display_mode,left,0,top-1,right,0,right, + (GLfloat)right); + } + } + else + { + if(left<right) + { + glMapGrid2f(right, 0.0, 1.0, bottom, 0.0, 1.0); + glEvalMesh2(display_mode,0,right-1, 1, bottom); + tesselate_strip_s(display_mode,0,right-1,1,0,left-1,0, + (GLfloat)left); + tesselate_top_left_corner(display_mode,right-1,left-1, + (GLfloat)(1.0/left),(GLfloat)(1.0/top)); + tesselate_strip_t(display_mode,1,bottom,right-1,1,top,top, + (GLfloat)top); + } + else + if(left==right) + { + glMapGrid2f(right, 0.0, 1.0, bottom, 0.0, 1.0); + glEvalMesh2(display_mode,0,right-1, 0, bottom); + tesselate_strip_t(display_mode,0,bottom,right-1,0,top,top, + (GLfloat)top); + } + else + { + glMapGrid2f(left, 0.0, 1.0, bottom, 0.0, 1.0); + glEvalMesh2(display_mode,0,left-1, 0, bottom-1); + tesselate_strip_t(display_mode,0,bottom-1,left-1,0,top-1,top, + (GLfloat)top); + tesselate_top_right_corner(display_mode,left-1,bottom-1,right,top, + (GLfloat)(1.0/right),(GLfloat)(1.0/top)); +/* tesselate_strip_s(display_mode,0,left-1,bottom-1,0,right-1,right, + (GLfloat)right);*/ + tesselate_strip_s(display_mode,left-1,0,bottom-1,right-1,0,right, + (GLfloat)right); + } + } +} + +/* draw NURBS surface in OUTLINE POLYGON mode */ +static void +draw_polygon_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; j<s_bezier_cnt; j++) + { + for(i=0; i<t_bezier_cnt; i++) + { + offset=j*t_bezier_cnt + i; + if(fine_culling_test_3D(nobj,*(new_ctrl->geom_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; j<s_bezier_cnt; j++) + { + for(i=0; i<t_bezier_cnt; i++) + { + offset=j*t_bezier_cnt + i; + if(fine_culling_test_3D(nobj,*(new_ctrl->geom_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;i<p->s_bezier_cnt;i++) + for(j=0;j<p->t_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;i<p->s_bezier_cnt;i++) + for(j=0;j<p->t_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;i<p->s_bezier_cnt;i++) + for(j=0;j<p->t_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;i<p->s_bezier_cnt;i++) + for(j=0;j<p->t_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); +} + diff --git a/src/glu/mesa/nurbsutl.c b/src/glu/mesa/nurbsutl.c new file mode 100644 index 00000000000..f0f166cb647 --- /dev/null +++ b/src/glu/mesa/nurbsutl.c @@ -0,0 +1,1403 @@ +/* $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 ([email protected]) + * + * 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 ([email protected]) + * 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); +}*/ + diff --git a/src/glu/mesa/polytest.c b/src/glu/mesa/polytest.c new file mode 100644 index 00000000000..9b42c63477e --- /dev/null +++ b/src/glu/mesa/polytest.c @@ -0,0 +1,1049 @@ +/* $Id: polytest.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: polytest.c,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.7 1999/06/08 00:44:51 brianp + * OpenStep updates ([email protected]) + * + * Revision 1.6 1998/07/26 02:08:52 brianp + * updated for Windows compilation per Ted Jump + * + * Revision 1.5 1997/10/29 02:02:20 brianp + * various MS Windows compiler changes (David Bucciarelli, v20 3dfx driver) + * + * Revision 1.4 1997/07/24 01:28:44 brianp + * changed precompiled header symbol from PCH to PC_HEADER + * + * Revision 1.3 1997/05/28 02:29:38 brianp + * added support for precompiled headers (PCH), inserted APIENTRY keyword + * + * Revision 1.2 1997/05/08 01:53:21 brianp + * fixed memory leak in free_current_polygon() reported by Randy Frank + * + * Revision 1.1 1996/09/27 01:19:39 brianp + * Initial revision + * + */ + + +/* + * This file is part of the polygon tesselation code contributed by + * Bogdan Sikorski + */ + + +#ifdef PC_HEADER +#include "all.h" +#else +#include <math.h> +#include <stdlib.h> +#include "gluP.h" +#include "tess.h" +#endif + + + +static GLenum store_polygon_as_contour(GLUtriangulatorObj *); +static void free_current_polygon(tess_polygon *); +static void prepare_projection_info(GLUtriangulatorObj *); +static GLdouble twice_the_polygon_area(tess_vertex *,tess_vertex *); +static GLenum verify_edge_vertex_intersections(GLUtriangulatorObj *); +void tess_find_contour_hierarchies(GLUtriangulatorObj *); +static GLenum test_for_overlapping_contours(GLUtriangulatorObj *); +static GLenum contours_overlap(tess_contour *, tess_polygon *); +static GLenum is_contour_contained_in(tess_contour *,tess_contour *); +static void add_new_exterior(GLUtriangulatorObj *,tess_contour *); +static void add_new_interior(GLUtriangulatorObj *,tess_contour *, + tess_contour *); +static void add_interior_with_hierarchy_check(GLUtriangulatorObj *, + tess_contour *,tess_contour *); +static void reverse_hierarchy_and_add_exterior(GLUtriangulatorObj *, + tess_contour *,tess_contour *); +static GLboolean point_in_polygon(tess_contour *,GLdouble,GLdouble); +static void shift_interior_to_exterior(GLUtriangulatorObj *,tess_contour *); +static void add_exterior_with_check(GLUtriangulatorObj *,tess_contour *, + tess_contour *); +static GLenum cut_out_hole(GLUtriangulatorObj *,tess_contour *, + tess_contour *); +static GLenum merge_hole_with_contour(GLUtriangulatorObj *, + tess_contour *,tess_contour *,tess_vertex *, + tess_vertex *); + +static GLenum +find_normal(GLUtriangulatorObj *tobj) +{ + tess_polygon *polygon=tobj->current_polygon; + tess_vertex *va,*vb,*vc; + GLdouble A,B,C; + GLdouble A0,A1,A2,B0,B1,B2; + + va=polygon->vertices; + vb=va->next; + A0=vb->location[0]-va->location[0]; + A1=vb->location[1]-va->location[1]; + A2=vb->location[2]-va->location[2]; + for(vc=vb->next;vc!=va;vc=vc->next) + { + B0=vc->location[0]-va->location[0]; + B1=vc->location[1]-va->location[1]; + B2=vc->location[2]-va->location[2]; + A=A1*B2-A2*B1; + B=A2*B0-A0*B2; + C=A0*B1-A1*B0; + if(fabs(A)>EPSILON || fabs(B)>EPSILON || fabs(C)>EPSILON) + { + polygon->A=A; + polygon->B=B; + polygon->C=C; + polygon->D= -A*va->location[0]-B*va->location[1]-C*va->location[2]; + return GLU_NO_ERROR; + } + } + tess_call_user_error(tobj,GLU_TESS_ERROR7); + return GLU_ERROR; +} + +void +tess_test_polygon( GLUtriangulatorObj *tobj ) +{ + tess_polygon *polygon=tobj->current_polygon; + + /* any vertices defined? */ + if(polygon->vertex_cnt<3) + { + free_current_polygon(polygon); + return; + } + /* wrap pointers */ + polygon->last_vertex->next=polygon->vertices; + polygon->vertices->previous=polygon->last_vertex; + /* determine the normal */ + if(find_normal(tobj)==GLU_ERROR) + return; + /* compare the normals of previously defined contours and this one */ + /* first contour define ? */ + if(tobj->contours==NULL) + { + tobj->A=polygon->A; + tobj->B=polygon->B; + tobj->C=polygon->C; + tobj->D=polygon->D; + /* determine the best projection to use */ + if(fabs(polygon->A) > fabs(polygon->B)) + if(fabs(polygon->A) > fabs(polygon->C)) + tobj->projection=OYZ; + else + tobj->projection=OXY; + else + if(fabs(polygon->B) > fabs(polygon->C)) + tobj->projection=OXZ; + else + tobj->projection=OXY; + } + else + { + GLdouble a[3],b[3]; + tess_vertex *vertex=polygon->vertices; + + a[0]=tobj->A; + a[1]=tobj->B; + a[2]=tobj->C; + b[0]=polygon->A; + b[1]=polygon->B; + b[2]=polygon->C; + + /* compare the normals */ + if( fabs(a[1]*b[2]-a[2]*b[1]) > EPSILON || + fabs(a[2]*b[0]-a[0]*b[2]) > EPSILON || + fabs(a[0]*b[1]-a[1]*b[0]) > EPSILON) + { + /* not coplanar */ + tess_call_user_error(tobj,GLU_TESS_ERROR9); + return; + } + /* the normals are parallel - test for plane equation */ + if(fabs(a[0]*vertex->location[0]+a[1]*vertex->location[1]+ + a[2]*vertex->location[2]+tobj->D) > EPSILON) + { + /* not the same plane */ + tess_call_user_error(tobj,GLU_TESS_ERROR9); + return; + } + } + prepare_projection_info(tobj); + if(verify_edge_vertex_intersections(tobj)==GLU_ERROR) + return; + if(test_for_overlapping_contours(tobj)==GLU_ERROR) + return; + if(store_polygon_as_contour(tobj)==GLU_ERROR) + return; +} + +static GLenum test_for_overlapping_contours(GLUtriangulatorObj *tobj) +{ + tess_contour *contour; + tess_polygon *polygon; + + polygon=tobj->current_polygon; + for(contour=tobj->contours;contour!=NULL;contour=contour->next) + if(contours_overlap(contour,polygon)!=GLU_NO_ERROR) + { + tess_call_user_error(tobj,GLU_TESS_ERROR5); + return GLU_ERROR; + } + return GLU_NO_ERROR; +} + +static GLenum store_polygon_as_contour(GLUtriangulatorObj *tobj) +{ + tess_polygon *polygon=tobj->current_polygon; + tess_contour *contour=tobj->contours; + + /* the first contour defined */ + if(contour==NULL) + { + if((contour=(tess_contour *)malloc( + sizeof(tess_contour)))==NULL) + { + tess_call_user_error(tobj,GLU_OUT_OF_MEMORY); + free_current_polygon(polygon); + return GLU_ERROR; + } + tobj->contours=tobj->last_contour=contour; + contour->next=contour->previous=NULL; + } + else + { + if((contour=(tess_contour *)malloc( + sizeof(tess_contour)))==NULL) + { + tess_call_user_error(tobj,GLU_OUT_OF_MEMORY); + free_current_polygon(polygon); + return GLU_ERROR; + } + contour->previous=tobj->last_contour; + tobj->last_contour->next=contour; + tobj->last_contour=contour; + contour->next=NULL; + } + /* mark all vertices in new contour as not special */ + /* and all are boundary edges */ + { + tess_vertex *vertex; + GLuint vertex_cnt,i; + + for(vertex=polygon->vertices , i=0 , vertex_cnt=polygon->vertex_cnt; + i<vertex_cnt; + vertex=vertex->next , i++) + { + vertex->shadow_vertex=NULL; + vertex->edge_flag=GL_TRUE; + } + } + contour->vertex_cnt=polygon->vertex_cnt; + contour->area=polygon->area; + contour->orientation=polygon->orientation; + contour->type=GLU_UNKNOWN; + contour->vertices=polygon->vertices; + contour->last_vertex=polygon->last_vertex; + polygon->vertices=polygon->last_vertex=NULL; + polygon->vertex_cnt=0; + ++(tobj->contour_cnt); + return GLU_NO_ERROR; +} + +static void free_current_polygon(tess_polygon *polygon) +{ + tess_vertex *vertex,*vertex_tmp; + GLuint i; + + /* free current_polygon structures */ + for(vertex=polygon->vertices,i=0;i<polygon->vertex_cnt;i++) + { + vertex_tmp=vertex->next; + free(vertex); + vertex=vertex_tmp; + } + polygon->vertices=polygon->last_vertex=NULL; + polygon->vertex_cnt=0; +} + +static void prepare_projection_info(GLUtriangulatorObj *tobj) +{ + tess_polygon *polygon=tobj->current_polygon; + tess_vertex *vertex,*last_vertex_ptr; + GLdouble area; + + last_vertex_ptr=polygon->last_vertex; + switch(tobj->projection) + { + case OXY: + for(vertex=polygon->vertices;vertex!=last_vertex_ptr; + vertex=vertex->next) + { + vertex->x=vertex->location[0]; + vertex->y=vertex->location[1]; + } + last_vertex_ptr->x=last_vertex_ptr->location[0]; + last_vertex_ptr->y=last_vertex_ptr->location[1]; + break; + case OXZ: + for(vertex=polygon->vertices;vertex!=last_vertex_ptr; + vertex=vertex->next) + { + vertex->x=vertex->location[0]; + vertex->y=vertex->location[2]; + } + last_vertex_ptr->x=last_vertex_ptr->location[0]; + last_vertex_ptr->y=last_vertex_ptr->location[2]; + break; + case OYZ: + for(vertex=polygon->vertices;vertex!=last_vertex_ptr; + vertex=vertex->next) + { + vertex->x=vertex->location[1]; + vertex->y=vertex->location[2]; + } + last_vertex_ptr->x=last_vertex_ptr->location[1]; + last_vertex_ptr->y=last_vertex_ptr->location[2]; + break; + } + area=twice_the_polygon_area(polygon->vertices,polygon->last_vertex); + if(area >= 0.0) + { + polygon->orientation=GLU_CCW; + polygon->area=area; + } + else + { + polygon->orientation=GLU_CW; + polygon->area= -area; + } +} + +static GLdouble twice_the_polygon_area(tess_vertex *vertex, + tess_vertex *last_vertex) +{ + tess_vertex *next; + GLdouble area,x,y; + + area=0.0; + x=vertex->x; + y=vertex->y; + vertex=vertex->next; + for(; vertex!=last_vertex; vertex=vertex->next) + { + next=vertex->next; + area+=(vertex->x - x)*(next->y - y) - (vertex->y - y)*(next->x - x); + } + return area; +} + +/* test if edges ab and cd intersect */ +/* if not return GLU_NO_ERROR, else if cross return GLU_TESS_ERROR8, */ +/* else if adjacent return GLU_TESS_ERROR4 */ +static GLenum edge_edge_intersect( + tess_vertex *a, + tess_vertex *b, + tess_vertex *c, + tess_vertex *d) +{ + GLdouble denom,r,s; + GLdouble xba,ydc,yba,xdc,yac,xac; + + xba=b->x - a->x; + yba=b->y - a->y; + xdc=d->x - c->x; + ydc=d->y - c->y; + xac=a->x - c->x; + yac=a->y - c->y; + denom= xba*ydc - yba*xdc; + r = yac*xdc - xac*ydc; + /* parallel? */ + if(fabs(denom) < EPSILON) + { + if(fabs(r) < EPSILON) + { + /* colinear */ + if(fabs(xba) < EPSILON) + { + /* compare the Y coordinate */ + if(yba > 0.0) + { + if((fabs(a->y - c->y)<EPSILON && fabs(c->y - b->y)<EPSILON) + || + (fabs(a->y - d->y)<EPSILON && fabs(d->y - b->y)<EPSILON)) + return GLU_TESS_ERROR4; + + } + else + { + if((fabs(b->y - c->y)<EPSILON && fabs(c->y - a->y)<EPSILON) + || + (fabs(b->y - d->y)<EPSILON && fabs(d->y - a->y)<EPSILON)) + return GLU_TESS_ERROR4; + } + } + else + { + /* compare the X coordinate */ + if(xba > 0.0) + { + if((fabs(a->x - c->x)<EPSILON && fabs(c->x - b->x)<EPSILON) + || + (fabs(a->x - d->x)<EPSILON && fabs(d->x - b->x)<EPSILON)) + return GLU_TESS_ERROR4; + } + else + { + if((fabs(b->x - c->x)<EPSILON && fabs(c->x - a->x)<EPSILON) + || + (fabs(b->x - d->x)<EPSILON && fabs(d->x - a->x)<EPSILON)) + return GLU_TESS_ERROR4; + } + } + } + return GLU_NO_ERROR; + } + r /= denom; + s = (yac*xba - xac*yba) / denom; + /* test if one vertex lies on other edge */ + if(((fabs(r) < EPSILON || (r < 1.0+EPSILON && r > 1.0-EPSILON)) && + s > -EPSILON && s < 1.0+EPSILON) || + ((fabs(s) < EPSILON || (s < 1.0+EPSILON && s > 1.0-EPSILON)) && + r > -EPSILON && r < 1.0+EPSILON)) + { + return GLU_TESS_ERROR4; + } + /* test for crossing */ + if(r > -EPSILON && r < 1.0+EPSILON && + s > -EPSILON && s < 1.0+EPSILON) + { + return GLU_TESS_ERROR8; + } + return GLU_NO_ERROR; +} + +static GLenum verify_edge_vertex_intersections(GLUtriangulatorObj *tobj) +{ + tess_polygon *polygon=tobj->current_polygon; + tess_vertex *vertex1,*last_vertex,*vertex2; + GLenum test; + + last_vertex=polygon->last_vertex; + vertex1=last_vertex; + for(vertex2=vertex1->next->next; + vertex2->next!=last_vertex; + vertex2=vertex2->next) + { + test=edge_edge_intersect(vertex1,vertex1->next,vertex2, + vertex2->next); + if(test!=GLU_NO_ERROR) + { + tess_call_user_error(tobj,test); + return GLU_ERROR; + } + } + for(vertex1=polygon->vertices; + vertex1->next->next!=last_vertex; + vertex1=vertex1->next) + { + for(vertex2=vertex1->next->next; + vertex2!=last_vertex; + vertex2=vertex2->next) + { + test=edge_edge_intersect(vertex1,vertex1->next,vertex2, + vertex2->next); + if(test!=GLU_NO_ERROR) + { + tess_call_user_error(tobj,test); + return GLU_ERROR; + } + } + } + return GLU_NO_ERROR; +} + +static int +#if defined(WIN32) && !defined(OPENSTEP) +__cdecl +#endif +area_compare(const void *a,const void *b) +{ + GLdouble area1,area2; + + area1=(*((tess_contour **)a))->area; + area2=(*((tess_contour **)b))->area; + if(area1 < area2) + return 1; + if(area1 > area2) + return -1; + return 0; +} + +void tess_find_contour_hierarchies(GLUtriangulatorObj *tobj) +{ + tess_contour **contours; /* dinamic array of pointers */ + tess_contour *tmp_contour_ptr=tobj->contours; + GLuint cnt,i; + GLenum result; + GLboolean hierarchy_changed; + + /* any contours? */ + if(tobj->contour_cnt < 2) + { + tobj->contours->type=GLU_EXTERIOR; + return; + } + if((contours=(tess_contour **) + malloc(sizeof(tess_contour *)*(tobj->contour_cnt)))==NULL) + { + tess_call_user_error(tobj,GLU_OUT_OF_MEMORY); + return; + } + for(tmp_contour_ptr=tobj->contours , cnt=0; + tmp_contour_ptr!=NULL; + tmp_contour_ptr=tmp_contour_ptr->next) + contours[cnt++]=tmp_contour_ptr; + /* now sort the contours in decreasing area size order */ + qsort((void *)contours,(size_t)cnt,(size_t)sizeof(tess_contour *),area_compare); + /* we leave just the first contour - remove others from list */ + tobj->contours=contours[0]; + tobj->contours->next=tobj->contours->previous=NULL; + tobj->last_contour=tobj->contours; + tobj->contour_cnt=1; + /* first contour is the one with greatest area */ + /* must be EXTERIOR */ + tobj->contours->type=GLU_EXTERIOR; + tmp_contour_ptr=tobj->contours; + /* now we play! */ + for(i=1;i<cnt;i++) + { + hierarchy_changed=GL_FALSE; + for(tmp_contour_ptr=tobj->contours; + tmp_contour_ptr!=NULL; + tmp_contour_ptr=tmp_contour_ptr->next) + { + if(tmp_contour_ptr->type==GLU_EXTERIOR) + { + /* check if contour completely contained in EXTERIOR */ + result=is_contour_contained_in(tmp_contour_ptr,contours[i]); + switch(result) + { + case GLU_INTERIOR: + /* now we have to check if contour is inside interiors */ + /* or not */ + /* any interiors? */ + if(tmp_contour_ptr->next!=NULL && + tmp_contour_ptr->next->type==GLU_INTERIOR) + { + /* for all interior, check if inside any of them */ + /* if not inside any of interiors, its another */ + /* interior */ + /* or it may contain some interiors, then change */ + /* the contained interiors to exterior ones */ + add_interior_with_hierarchy_check(tobj, + tmp_contour_ptr,contours[i]); + } + else + { + /* not in interior, add as new interior contour */ + add_new_interior(tobj,tmp_contour_ptr,contours[i]); + } + hierarchy_changed=GL_TRUE; + break; + case GLU_EXTERIOR: + /* ooops, the marked as EXTERIOR (contours[i]) is */ + /* actually an interior of tmp_contour_ptr */ + /* reverse the local hierarchy */ + reverse_hierarchy_and_add_exterior(tobj,tmp_contour_ptr, + contours[i]); + hierarchy_changed=GL_TRUE; + break; + case GLU_NO_ERROR: + break; + default: + abort(); + } + } + if(hierarchy_changed) + break; /* break from for loop */ + } + if(hierarchy_changed==GL_FALSE) + { + /* disjoint with all contours, add to contour list */ + add_new_exterior(tobj,contours[i]); + } + } + free(contours); +} + +/* returns GLU_INTERIOR if inner is completey enclosed within outer */ +/* returns GLU_EXTERIOR if outer is completely enclosed within inner */ +/* returns GLU_NO_ERROR if contours are disjoint */ +static GLenum is_contour_contained_in( + tess_contour *outer, + tess_contour *inner) +{ + GLenum relation_flag; + + /* set relation_flag to relation of containment of first inner vertex */ + /* regarding outer contour */ + if(point_in_polygon(outer,inner->vertices->x,inner->vertices->y)) + relation_flag=GLU_INTERIOR; + else + relation_flag=GLU_EXTERIOR; + if(relation_flag==GLU_INTERIOR) + return GLU_INTERIOR; + if(point_in_polygon(inner,outer->vertices->x,outer->vertices->y)) + return GLU_EXTERIOR; + return GLU_NO_ERROR; +} + +static GLboolean point_in_polygon( + tess_contour *contour, + GLdouble x, + GLdouble y) +{ + tess_vertex *v1,*v2; + GLuint i,vertex_cnt; + GLdouble xp1,yp1,xp2,yp2; + GLboolean tst; + + tst=GL_FALSE; + v1=contour->vertices; + v2=contour->vertices->previous; + for(i=0 , vertex_cnt=contour->vertex_cnt; + i < vertex_cnt; + i++) + { + xp1=v1->x; + yp1=v1->y; + xp2=v2->x; + yp2=v2->y; + if ((((yp1<=y) && (y<yp2)) || ((yp2<=y) && (y<yp1))) && + (x < (xp2 - xp1) * (y - yp1) / (yp2 - yp1) + xp1)) + tst = (tst==GL_FALSE ? GL_TRUE : GL_FALSE); + v2=v1; + v1=v1->next; + } + return tst; +} + +static GLenum contours_overlap( + tess_contour *contour, + tess_polygon *polygon) +{ + tess_vertex *vertex1,*vertex2; + GLuint vertex1_cnt,vertex2_cnt,i,j; + GLenum test; + + vertex1=contour->vertices; + vertex2=polygon->vertices; + vertex1_cnt=contour->vertex_cnt; + vertex2_cnt=polygon->vertex_cnt; + for(i=0; i<vertex1_cnt; vertex1=vertex1->next , i++) + { + for(j=0; j<vertex2_cnt; vertex2=vertex2->next , j++) + if((test=edge_edge_intersect(vertex1,vertex1->next,vertex2, + vertex2->next))!=GLU_NO_ERROR) + return test; + } + return GLU_NO_ERROR; +} + +static void add_new_exterior( + GLUtriangulatorObj *tobj, + tess_contour *contour) +{ + contour->type=GLU_EXTERIOR; + contour->next=NULL; + contour->previous=tobj->last_contour; + tobj->last_contour->next=contour; + tobj->last_contour=contour; +} + +static void add_new_interior( + GLUtriangulatorObj *tobj, + tess_contour *outer, + tess_contour *contour) +{ + contour->type=GLU_INTERIOR; + contour->next=outer->next; + contour->previous=outer; + if(outer->next!=NULL) + outer->next->previous=contour; + outer->next=contour; + if(tobj->last_contour==outer) + tobj->last_contour=contour; +} + +static void add_interior_with_hierarchy_check( + GLUtriangulatorObj *tobj, + tess_contour *outer, + tess_contour *contour) +{ + tess_contour *ptr; + + /* for all interiors of outer check if they are interior of contour */ + /* if so, change that interior to exterior and move it of of the */ + /* interior sequence */ + if(outer->next!=NULL && outer->next->type==GLU_INTERIOR) + { + GLenum test; + + for(ptr=outer->next;ptr!=NULL && ptr->type==GLU_INTERIOR;ptr=ptr->next) + { + test=is_contour_contained_in(ptr,contour); + switch(test) + { + case GLU_INTERIOR: + /* contour is contained in one of the interiors */ + /* check if possibly contained in other exteriors */ + /* move ptr to first EXTERIOR */ + for(;ptr!=NULL && ptr->type==GLU_INTERIOR;ptr=ptr->next); + if(ptr==NULL) + /* another exterior */ + add_new_exterior(tobj,contour); + else + add_exterior_with_check(tobj,ptr,contour); + return; + case GLU_EXTERIOR: + /* one of the interiors is contained in the contour */ + /* change it to EXTERIOR, and shift it away from the */ + /* interior sequence */ + shift_interior_to_exterior(tobj,ptr); + break; + case GLU_NO_ERROR: + /* disjoint */ + break; + default: + abort(); + } + } + } + /* add contour to the interior sequence */ + add_new_interior(tobj,outer,contour); +} + +static void reverse_hierarchy_and_add_exterior( + GLUtriangulatorObj *tobj, + tess_contour *outer, + tess_contour *contour) +{ + tess_contour *ptr; + + /* reverse INTERIORS to EXTERIORS */ + /* any INTERIORS? */ + if(outer->next!=NULL && outer->next->type==GLU_INTERIOR) + for(ptr=outer->next;ptr!=NULL && ptr->type==GLU_INTERIOR;ptr=ptr->next) + ptr->type=GLU_EXTERIOR; + /* the outer now becomes inner */ + outer->type=GLU_INTERIOR; + /* contour is the EXTERIOR */ + contour->next=outer; + if(tobj->contours==outer) + { + /* first contour beeing reversed */ + contour->previous=NULL; + tobj->contours=contour; + } + else + { + outer->previous->next=contour; + contour->previous=outer->previous; + } + outer->previous=contour; +} + +static void shift_interior_to_exterior( + GLUtriangulatorObj *tobj, + tess_contour *contour) +{ + contour->previous->next=contour->next; + if(contour->next!=NULL) + contour->next->previous=contour->previous; + else + tobj->last_contour=contour->previous; +} + +static void add_exterior_with_check( + GLUtriangulatorObj *tobj, + tess_contour *outer, + tess_contour *contour) +{ + GLenum test; + + /* this contour might be interior to further exteriors - check */ + /* if not, just add as a new exterior */ + for(;outer!=NULL && outer->type==GLU_EXTERIOR;outer=outer->next) + { + test=is_contour_contained_in(outer,contour); + switch(test) + { + case GLU_INTERIOR: + /* now we have to check if contour is inside interiors */ + /* or not */ + /* any interiors? */ + if(outer->next!=NULL && outer->next->type==GLU_INTERIOR) + { + /* for all interior, check if inside any of them */ + /* if not inside any of interiors, its another */ + /* interior */ + /* or it may contain some interiors, then change */ + /* the contained interiors to exterior ones */ + add_interior_with_hierarchy_check(tobj, + outer,contour); + } + else + { + /* not in interior, add as new interior contour */ + add_new_interior(tobj,outer,contour); + } + return; + case GLU_NO_ERROR: + /* disjoint */ + break; + default: + abort(); + } + } + /* add contour to the exterior sequence */ + add_new_exterior(tobj,contour); +} + +void tess_handle_holes(GLUtriangulatorObj *tobj) +{ + tess_contour *contour,*hole; + GLenum exterior_orientation; + + /* verify hole orientation */ + for(contour=tobj->contours;contour!=NULL;) + { + exterior_orientation=contour->orientation; + for(contour=contour->next; + contour!=NULL && contour->type==GLU_INTERIOR; + contour=contour->next) + { + if(contour->orientation==exterior_orientation) + { + tess_call_user_error(tobj,GLU_TESS_ERROR5); + return; + } + } + } + /* now cut-out holes */ + for(contour=tobj->contours;contour!=NULL;) + { + hole=contour->next; + while(hole!=NULL && hole->type==GLU_INTERIOR) + { + if(cut_out_hole(tobj,contour,hole)==GLU_ERROR) + return; + hole=contour->next; + } + contour=contour->next; + } +} + +static GLenum cut_out_hole( + GLUtriangulatorObj *tobj, + tess_contour *contour, + tess_contour *hole) +{ + tess_contour *tmp_hole; + tess_vertex *v1,*v2,*tmp_vertex; + GLuint vertex1_cnt,vertex2_cnt,tmp_vertex_cnt; + GLuint i,j,k; + GLenum test; + + /* find an edge connecting contour and hole not intersecting any other */ + /* edge belonging to either the contour or any of the other holes */ + for(v1=contour->vertices , vertex1_cnt=contour->vertex_cnt , i=0; + i<vertex1_cnt; + i++ , v1=v1->next) + { + for(v2=hole->vertices , vertex2_cnt=hole->vertex_cnt , j=0; + j<vertex2_cnt; + j++ , v2=v2->next) + { + /* does edge (v1,v2) intersect any edge of contour */ + for(tmp_vertex=contour->vertices , tmp_vertex_cnt=contour->vertex_cnt , + k=0; + k<tmp_vertex_cnt; + tmp_vertex=tmp_vertex->next , k++) + { + /* skip edge tests for edges directly connected */ + if(v1==tmp_vertex || v1==tmp_vertex->next) + continue; + test=edge_edge_intersect(v1,v2,tmp_vertex,tmp_vertex->next); + if(test!=GLU_NO_ERROR) + break; + } + if(test==GLU_NO_ERROR) + { + /* does edge (v1,v2) intersect any edge of hole */ + for(tmp_vertex=hole->vertices , + tmp_vertex_cnt=hole->vertex_cnt , k=0; + k<tmp_vertex_cnt; + tmp_vertex=tmp_vertex->next , k++) + { + /* skip edge tests for edges directly connected */ + if(v2==tmp_vertex || v2==tmp_vertex->next) + continue; + test=edge_edge_intersect(v1,v2,tmp_vertex,tmp_vertex->next); + if(test!=GLU_NO_ERROR) + break; + } + if(test==GLU_NO_ERROR) + { + /* does edge (v1,v2) intersect any other hole? */ + for(tmp_hole=hole->next; + tmp_hole!=NULL && tmp_hole->type==GLU_INTERIOR; + tmp_hole=tmp_hole->next) + { + /* does edge (v1,v2) intersect any edge of hole */ + for(tmp_vertex=tmp_hole->vertices , + tmp_vertex_cnt=tmp_hole->vertex_cnt , k=0; + k<tmp_vertex_cnt; + tmp_vertex=tmp_vertex->next , k++) + { + test=edge_edge_intersect(v1,v2,tmp_vertex, + tmp_vertex->next); + if(test!=GLU_NO_ERROR) + break; + } + if(test!=GLU_NO_ERROR) + break; + } + } + } + if(test==GLU_NO_ERROR) + { + /* edge (v1,v2) is good for eliminating the hole */ + if(merge_hole_with_contour(tobj,contour,hole,v1,v2) + ==GLU_NO_ERROR) + return GLU_NO_ERROR; + else + return GLU_ERROR; + } + } + } + /* other holes are blocking all possible connections of hole */ + /* with contour, we shift this hole as the last hole and retry */ + for(tmp_hole=hole; + tmp_hole!=NULL && tmp_hole->type==GLU_INTERIOR; + tmp_hole=tmp_hole->next); + contour->next=hole->next; + hole->next->previous=contour; + if(tmp_hole==NULL) + { + /* last EXTERIOR contour, shift hole as last contour */ + hole->next=NULL; + hole->previous=tobj->last_contour; + tobj->last_contour->next=hole; + tobj->last_contour=hole; + } + else + { + tmp_hole->previous->next=hole; + hole->previous=tmp_hole->previous; + tmp_hole->previous=hole; + hole->next=tmp_hole; + } + hole=contour->next; + /* try once again - recurse */ + return cut_out_hole(tobj,contour,hole); +} + +static GLenum merge_hole_with_contour( + GLUtriangulatorObj *tobj, + tess_contour *contour, + tess_contour *hole, + tess_vertex *v1, + tess_vertex *v2) +{ + tess_vertex *v1_new,*v2_new; + + /* make copies of v1 and v2, place them respectively after their originals */ + if((v1_new=(tess_vertex *)malloc(sizeof(tess_vertex)))==NULL) + { + tess_call_user_error(tobj,GLU_OUT_OF_MEMORY); + return GLU_ERROR; + } + if((v2_new=(tess_vertex *)malloc(sizeof(tess_vertex)))==NULL) + { + tess_call_user_error(tobj,GLU_OUT_OF_MEMORY); + return GLU_ERROR; + } + v1_new->edge_flag=GL_TRUE; + v1_new->data=v1->data; + v1_new->location[0]=v1->location[0]; + v1_new->location[1]=v1->location[1]; + v1_new->location[2]=v1->location[2]; + v1_new->x=v1->x; + v1_new->y=v1->y; + v1_new->shadow_vertex=v1; + v1->shadow_vertex=v1_new; + v1_new->next=v1->next; + v1_new->previous=v1; + v1->next->previous=v1_new; + v1->next=v1_new; + v2_new->edge_flag=GL_TRUE; + v2_new->data=v2->data; + v2_new->location[0]=v2->location[0]; + v2_new->location[1]=v2->location[1]; + v2_new->location[2]=v2->location[2]; + v2_new->x=v2->x; + v2_new->y=v2->y; + v2_new->shadow_vertex=v2; + v2->shadow_vertex=v2_new; + v2_new->next=v2->next; + v2_new->previous=v2; + v2->next->previous=v2_new; + v2->next=v2_new; + /* link together the two lists */ + v1->next=v2_new; + v2_new->previous=v1; + v2->next=v1_new; + v1_new->previous=v2; + /* update the vertex count of the contour */ + contour->vertex_cnt += hole->vertex_cnt+2; + /* remove the INTERIOR contour */ + contour->next=hole->next; + if(hole->next!=NULL) + hole->next->previous=contour; + free(hole); + /* update tobj structure */ + --(tobj->contour_cnt); + if(contour->last_vertex==v1) + contour->last_vertex=v1_new; + /* mark two vertices with edge_flag */ + v2->edge_flag=GL_FALSE; + v1->edge_flag=GL_FALSE; + return GLU_NO_ERROR; +} diff --git a/src/glu/mesa/project.c b/src/glu/mesa/project.c new file mode 100644 index 00000000000..32142c959e9 --- /dev/null +++ b/src/glu/mesa/project.c @@ -0,0 +1,318 @@ +/* $Id: project.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.1 + * Copyright (C) 1995-1999 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: project.c,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.7 1999/01/03 03:23:15 brianp + * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump) + * + * Revision 1.6 1998/07/08 01:43:43 brianp + * new version of invert_matrix() (also in src/matrix.c) + * + * 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/04/11 23:22:42 brianp + * added divide by zero checks to gluProject() and gluUnproject() + * + * Revision 1.2 1997/01/29 19:05:29 brianp + * faster invert_matrix() function from Stephane Rehel + * + * Revision 1.1 1996/09/27 01:19:39 brianp + * Initial revision + * + */ + + +#ifdef PC_HEADER +#include "all.h" +#else +#include <stdio.h> +#include <string.h> +#include <math.h> +#include "gluP.h" +#endif + + +/* + * This code was contributed by Marc Buffat ([email protected]). + * Thanks Marc!!! + */ + + + +/* implementation de gluProject et gluUnproject */ +/* M. Buffat 17/2/95 */ + + + +/* + * Transform a point (column vector) by a 4x4 matrix. I.e. out = m * in + * Input: m - the 4x4 matrix + * in - the 4x1 vector + * Output: out - the resulting 4x1 vector. + */ +static void transform_point( GLdouble out[4], const GLdouble m[16], + const GLdouble in[4] ) +{ +#define M(row,col) m[col*4+row] + out[0] = M(0,0) * in[0] + M(0,1) * in[1] + M(0,2) * in[2] + M(0,3) * in[3]; + out[1] = M(1,0) * in[0] + M(1,1) * in[1] + M(1,2) * in[2] + M(1,3) * in[3]; + out[2] = M(2,0) * in[0] + M(2,1) * in[1] + M(2,2) * in[2] + M(2,3) * in[3]; + out[3] = M(3,0) * in[0] + M(3,1) * in[1] + M(3,2) * in[2] + M(3,3) * in[3]; +#undef M +} + + + + +/* + * Perform a 4x4 matrix multiplication (product = a x b). + * Input: a, b - matrices to multiply + * Output: product - product of a and b + */ +static void matmul( GLdouble *product, const GLdouble *a, const GLdouble *b ) +{ + /* This matmul was contributed by Thomas Malik */ + GLdouble temp[16]; + GLint i; + +#define A(row,col) a[(col<<2)+row] +#define B(row,col) b[(col<<2)+row] +#define T(row,col) temp[(col<<2)+row] + + /* i-te Zeile */ + for (i = 0; i < 4; i++) + { + T(i, 0) = A(i, 0) * B(0, 0) + A(i, 1) * B(1, 0) + A(i, 2) * B(2, 0) + A(i, 3) * B(3, 0); + T(i, 1) = A(i, 0) * B(0, 1) + A(i, 1) * B(1, 1) + A(i, 2) * B(2, 1) + A(i, 3) * B(3, 1); + T(i, 2) = A(i, 0) * B(0, 2) + A(i, 1) * B(1, 2) + A(i, 2) * B(2, 2) + A(i, 3) * B(3, 2); + T(i, 3) = A(i, 0) * B(0, 3) + A(i, 1) * B(1, 3) + A(i, 2) * B(2, 3) + A(i, 3) * B(3, 3); + } + +#undef A +#undef B +#undef T + MEMCPY( product, temp, 16*sizeof(GLdouble) ); +} + + +static GLdouble Identity[16] = { + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 +}; + + + +/* + * Compute inverse of 4x4 transformation matrix. + * Code contributed by Jacques Leroy [email protected] + * Return GL_TRUE for success, GL_FALSE for failure (singular matrix) + */ +static GLboolean invert_matrix( const GLdouble *m, GLdouble *out ) +{ +/* NB. OpenGL Matrices are COLUMN major. */ +#define SWAP_ROWS(a, b) { GLdouble *_tmp = a; (a)=(b); (b)=_tmp; } +#define MAT(m,r,c) (m)[(c)*4+(r)] + + GLdouble wtmp[4][8]; + GLdouble m0, m1, m2, m3, s; + GLdouble *r0, *r1, *r2, *r3; + + r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3]; + + r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1), + r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3), + r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0, + + r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1), + r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3), + r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0, + + r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1), + r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3), + r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0, + + r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1), + r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3), + r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0; + + /* choose pivot - or die */ + if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2); + if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1); + if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0); + if (0.0 == r0[0]) return GL_FALSE; + + /* eliminate first variable */ + m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0]; + s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s; + s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s; + s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s; + s = r0[4]; + if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; } + s = r0[5]; + if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; } + s = r0[6]; + if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; } + s = r0[7]; + if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; } + + /* choose pivot - or die */ + if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2); + if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1); + if (0.0 == r1[1]) return GL_FALSE; + + /* eliminate second variable */ + m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1]; + r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2]; + r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3]; + s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; } + s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; } + s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; } + s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; } + + /* choose pivot - or die */ + if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2); + if (0.0 == r2[2]) return GL_FALSE; + + /* eliminate third variable */ + m3 = r3[2]/r2[2]; + r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4], + r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], + r3[7] -= m3 * r2[7]; + + /* last check */ + if (0.0 == r3[3]) return GL_FALSE; + + s = 1.0/r3[3]; /* now back substitute row 3 */ + r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s; + + m2 = r2[3]; /* now back substitute row 2 */ + s = 1.0/r2[2]; + r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2), + r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2); + m1 = r1[3]; + r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1, + r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1; + m0 = r0[3]; + r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0, + r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0; + + m1 = r1[2]; /* now back substitute row 1 */ + s = 1.0/r1[1]; + r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1), + r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1); + m0 = r0[2]; + r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0, + r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0; + + m0 = r0[1]; /* now back substitute row 0 */ + s = 1.0/r0[0]; + r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0), + r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0); + + MAT(out,0,0) = r0[4]; MAT(out,0,1) = r0[5], + MAT(out,0,2) = r0[6]; MAT(out,0,3) = r0[7], + MAT(out,1,0) = r1[4]; MAT(out,1,1) = r1[5], + MAT(out,1,2) = r1[6]; MAT(out,1,3) = r1[7], + MAT(out,2,0) = r2[4]; MAT(out,2,1) = r2[5], + MAT(out,2,2) = r2[6]; MAT(out,2,3) = r2[7], + MAT(out,3,0) = r3[4]; MAT(out,3,1) = r3[5], + MAT(out,3,2) = r3[6]; MAT(out,3,3) = r3[7]; + + return GL_TRUE; + +#undef MAT +#undef SWAP_ROWS +} + + + +/* projection du point (objx,objy,obz) sur l'ecran (winx,winy,winz) */ +GLint GLAPIENTRY gluProject(GLdouble objx,GLdouble objy,GLdouble objz, + const GLdouble model[16],const GLdouble proj[16], + const GLint viewport[4], + GLdouble *winx,GLdouble *winy,GLdouble *winz) +{ + /* matrice de transformation */ + GLdouble in[4],out[4]; + + /* initilise la matrice et le vecteur a transformer */ + in[0]=objx; in[1]=objy; in[2]=objz; in[3]=1.0; + transform_point(out,model,in); + transform_point(in,proj,out); + + /* d'ou le resultat normalise entre -1 et 1*/ + if (in[3]==0.0) + return GL_FALSE; + + in[0]/=in[3]; in[1]/=in[3]; in[2]/=in[3]; + + /* en coordonnees ecran */ + *winx = viewport[0]+(1+in[0])*viewport[2]/2; + *winy = viewport[1]+(1+in[1])*viewport[3]/2; + /* entre 0 et 1 suivant z */ + *winz = (1+in[2])/2; + return GL_TRUE; +} + + + +/* transformation du point ecran (winx,winy,winz) en point objet */ +GLint GLAPIENTRY gluUnProject(GLdouble winx,GLdouble winy,GLdouble winz, + const GLdouble model[16],const GLdouble proj[16], + const GLint viewport[4], + GLdouble *objx,GLdouble *objy,GLdouble *objz) +{ + /* matrice de transformation */ + GLdouble m[16], A[16]; + GLdouble in[4],out[4]; + + /* transformation coordonnees normalisees entre -1 et 1 */ + in[0]=(winx-viewport[0])*2/viewport[2] - 1.0; + in[1]=(winy-viewport[1])*2/viewport[3] - 1.0; + in[2]=2*winz - 1.0; + in[3]=1.0; + + /* calcul transformation inverse */ + matmul(A,proj,model); + invert_matrix(A,m); + + /* d'ou les coordonnees objets */ + transform_point(out,m,in); + if (out[3]==0.0) + return GL_FALSE; + *objx=out[0]/out[3]; + *objy=out[1]/out[3]; + *objz=out[2]/out[3]; + return GL_TRUE; +} + diff --git a/src/glu/mesa/quadric.c b/src/glu/mesa/quadric.c new file mode 100644 index 00000000000..4698e795b15 --- /dev/null +++ b/src/glu/mesa/quadric.c @@ -0,0 +1,858 @@ +/* $Id: quadric.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.1 + * Copyright (C) 1995-1999 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: quadric.c,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.19 1999/02/27 13:55:31 brianp + * fixed BeOS-related GLU typedef problems + * + * Revision 1.18 1999/01/03 03:23:15 brianp + * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump) + * + * Revision 1.17 1999/01/03 03:19:15 brianp + * rewrote some of gluCylinder + * + * Revision 1.16 1998/06/01 01:08:36 brianp + * small update for Next/OpenStep from Alexander Mai + * + * Revision 1.15 1998/03/15 18:28:54 brianp + * reimplemented gluDisk() point and line mode + * + * Revision 1.14 1998/03/15 18:14:17 brianp + * fixed a compiler cast warning + * + * Revision 1.13 1998/02/07 14:28:34 brianp + * another change to gluQuadricCallback(), this time for StormC compiler + * + * Revision 1.12 1998/02/05 00:43:19 brianp + * Yes, still another change to gluQuadricCallback()! + * + * Revision 1.11 1998/02/04 00:27:43 brianp + * yet another change to gluQuadricCallback()! + * + * Revision 1.10 1998/02/04 00:23:23 brianp + * fixed CALLBACK problem in gluQuadricCallback() (Stephane Rehel) + * + * Revision 1.9 1998/02/04 00:20:09 brianp + * added missing (int) in ErrorFunc cast + * + * Revision 1.8 1998/01/16 03:37:51 brianp + * fixed another assignment warning in gluQuadricCallback() + * + * Revision 1.7 1998/01/16 03:35:26 brianp + * fixed Windows compilation warnings (Theodore 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/09/17 01:51:48 brianp + * changed glu*Callback() functions to match prototype in glu.h + * + * Revision 1.4 1997/07/24 01:28:44 brianp + * changed precompiled header symbol from PCH to PC_HEADER + * + * Revision 1.3 1997/05/28 02:29:38 brianp + * added support for precompiled headers (PCH), inserted APIENTRY keyword + * + * Revision 1.2 1997/03/12 02:15:38 brianp + * fixed problem in gluPartialDisk() reported by Kenneth H. Carpenter + * + * Revision 1.1 1996/09/27 01:19:39 brianp + * Initial revision + * + */ + + +/* TODO: + * texture coordinate support + * flip normals according to orientation + * there's still some inside/outside orientation bugs in possibly all + * but the sphere function + */ + + +#ifdef PC_HEADER +#include "all.h" +#else +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "gluP.h" +#endif + + + +#ifndef M_PI +# define M_PI (3.1415926) +#endif + + +/* + * Convert degrees to radians: + */ +#define DEG_TO_RAD(A) ((A)*(M_PI/180.0)) + + +/* + * Sin and Cos for degree angles: + */ +#define SIND( A ) sin( (A)*(M_PI/180.0) ) +#define COSD( A) cos( (A)*(M_PI/180.0) ) + + +/* + * Texture coordinates if texture flag is set + */ +#define TXTR_COORD(x,y) if (qobj->TextureFlag) glTexCoord2f(x,y); + + + +struct GLUquadric { + GLenum DrawStyle; /* GLU_FILL, LINE, SILHOUETTE, or POINT */ + GLenum Orientation; /* GLU_INSIDE or GLU_OUTSIDE */ + GLboolean TextureFlag; /* Generate texture coords? */ + GLenum Normals; /* GLU_NONE, GLU_FLAT, or GLU_SMOOTH */ + void (GLCALLBACK *ErrorFunc)(GLenum err); /* Error handler callback function */ +}; + + + +/* + * Process a GLU error. + */ +static void quadric_error( GLUquadricObj *qobj, GLenum error, const char *msg ) +{ + /* Call the error call back function if any */ + if (qobj->ErrorFunc) { + (*qobj->ErrorFunc)( error ); + } + /* Print a message to stdout if MESA_DEBUG variable is defined */ + if (getenv("MESA_DEBUG")) { + fprintf(stderr,"GLUError: %s: %s\n", (char*) gluErrorString(error), msg); + } +} + + + + +GLUquadricObj * GLAPIENTRY gluNewQuadric( void ) +{ + GLUquadricObj *q; + + q = (GLUquadricObj *) malloc( sizeof(struct GLUquadric) ); + if (q) { + q->DrawStyle = GLU_FILL; + q->Orientation = GLU_OUTSIDE; + q->TextureFlag = GL_FALSE; + q->Normals = GLU_SMOOTH; + q->ErrorFunc = NULL; + } + return q; +} + + + +void GLAPIENTRY gluDeleteQuadric( GLUquadricObj *state ) +{ + if (state) { + free( (void *) state ); + } +} + + + +/* + * Set the drawing style to be GLU_FILL, GLU_LINE, GLU_SILHOUETTE, + * or GLU_POINT. + */ +void GLAPIENTRY gluQuadricDrawStyle( GLUquadricObj *quadObject, GLenum drawStyle ) +{ + if (quadObject && (drawStyle==GLU_FILL || drawStyle==GLU_LINE + || drawStyle==GLU_SILHOUETTE || drawStyle==GLU_POINT)) { + quadObject->DrawStyle = drawStyle; + } + else { + quadric_error( quadObject, GLU_INVALID_ENUM, "qluQuadricDrawStyle" ); + } +} + + + +/* + * Set the orientation to GLU_INSIDE or GLU_OUTSIDE. + */ +void GLAPIENTRY gluQuadricOrientation( GLUquadricObj *quadObject, + GLenum orientation ) +{ + if (quadObject && (orientation==GLU_INSIDE || orientation==GLU_OUTSIDE)) { + quadObject->Orientation = orientation; + } + else { + quadric_error( quadObject, GLU_INVALID_ENUM, "qluQuadricOrientation" ); + } +} + + + +/* + * Set the error handler callback function. + */ +void GLAPIENTRY gluQuadricCallback( GLUquadricObj *qobj, + GLenum which, void (GLCALLBACK *fn)() ) +{ + /* + * UGH, this is a mess! I thought ANSI was a standard. + */ + if (qobj && which==GLU_ERROR) { +#ifdef __CYGWIN32__ + qobj->ErrorFunc = (void(*)(int))fn; +#elif defined(OPENSTEP) + qobj->ErrorFunc = (void(*)(GLenum))fn; +#elif defined(_WIN32) + qobj->ErrorFunc = (void(GLCALLBACK*)(int))fn; +#elif defined(__STORM__) + qobj->ErrorFunc = (void(GLCALLBACK*)(GLenum))fn; +#elif defined(__BEOS__) + qobj->ErrorFunc = (void(*)(GLenum))fn; +#else + qobj->ErrorFunc = (void(GLCALLBACK*)())fn; +#endif + } +} + + +void GLAPIENTRY gluQuadricNormals( GLUquadricObj *quadObject, GLenum normals ) +{ + if (quadObject + && (normals==GLU_NONE || normals==GLU_FLAT || normals==GLU_SMOOTH)) { + quadObject->Normals = normals; + } +} + + +void GLAPIENTRY gluQuadricTexture( GLUquadricObj *quadObject, + GLboolean textureCoords ) +{ + if (quadObject) { + quadObject->TextureFlag = textureCoords; + } +} + + + + +/* + * Call glNormal3f after scaling normal to unit length. + */ +static void normal3f( GLfloat x, GLfloat y, GLfloat z ) +{ + GLdouble mag; + + mag = sqrt( x*x + y*y + z*z ); + if (mag>0.00001F) { + x /= mag; + y /= mag; + z /= mag; + } + glNormal3f( x, y, z ); +} + + + +void GLAPIENTRY gluCylinder( GLUquadricObj *qobj, + GLdouble baseRadius, GLdouble topRadius, + GLdouble height, GLint slices, GLint stacks ) +{ + GLdouble da, r, dr, dz; + GLfloat x, y, z, nz, nsign; + GLint i, j; + + if (qobj->Orientation==GLU_INSIDE) { + nsign = -1.0; + } + else { + nsign = 1.0; + } + + da = 2.0*M_PI / slices; + dr = (topRadius-baseRadius) / stacks; + dz = height / stacks; + nz = (baseRadius-topRadius) / height; /* Z component of normal vectors */ + + if (qobj->DrawStyle==GLU_POINT) { + glBegin( GL_POINTS ); + for (i=0;i<slices;i++) { + x = cos(i*da); + y = sin(i*da); + normal3f( x*nsign, y*nsign, nz*nsign ); + + z = 0.0; + r = baseRadius; + for (j=0;j<=stacks;j++) { + glVertex3f( x*r, y*r, z ); + z += dz; + r += dr; + } + } + glEnd(); + } + else if (qobj->DrawStyle==GLU_LINE || qobj->DrawStyle==GLU_SILHOUETTE) { + /* Draw rings */ + if (qobj->DrawStyle==GLU_LINE) { + z = 0.0; + r = baseRadius; + for (j=0;j<=stacks;j++) { + glBegin( GL_LINE_LOOP ); + for (i=0;i<slices;i++) { + x = cos(i*da); + y = sin(i*da); + normal3f( x*nsign, y*nsign, nz*nsign ); + glVertex3f( x*r, y*r, z ); + } + glEnd(); + z += dz; + r += dr; + } + } + else { + /* draw one ring at each end */ + if (baseRadius!=0.0) { + glBegin( GL_LINE_LOOP ); + for (i=0;i<slices;i++) { + x = cos(i*da); + y = sin(i*da); + normal3f( x*nsign, y*nsign, nz*nsign ); + glVertex3f( x*baseRadius, y*baseRadius, 0.0 ); + } + glEnd(); + glBegin( GL_LINE_LOOP ); + for (i=0;i<slices;i++) { + x = cos(i*da); + y = sin(i*da); + normal3f( x*nsign, y*nsign, nz*nsign ); + glVertex3f( x*topRadius, y*topRadius, height ); + } + glEnd(); + } + } + /* draw length lines */ + glBegin( GL_LINES ); + for (i=0;i<slices;i++) { + x = cos(i*da); + y = sin(i*da); + normal3f( x*nsign, y*nsign, nz*nsign ); + glVertex3f( x*baseRadius, y*baseRadius, 0.0 ); + glVertex3f( x*topRadius, y*topRadius, height ); + } + glEnd(); + } + else if (qobj->DrawStyle==GLU_FILL) { + GLfloat ds = 1.0 / slices; + GLfloat dt = 1.0 / stacks; + GLfloat t = 0.0; + z = 0.0; + r = baseRadius; + for (j=0;j<stacks;j++) { + GLfloat s = 0.0; + glBegin( GL_QUAD_STRIP ); + for (i=0;i<=slices;i++) { + GLfloat x, y; + if (i == slices) { + x = sin(0); + y = cos(0); + } + else { + x = sin(i * da); + y = cos(i * da); + } + if (nsign==1.0) { + normal3f( x*nsign, y*nsign, nz*nsign ); + TXTR_COORD(s, t); + glVertex3f( x * r, y * r, z ); + normal3f( x*nsign, y*nsign, nz*nsign ); + TXTR_COORD(s, t + dt); + glVertex3f( x * (r + dr), y * (r + dr), z + dz); + } + else { + normal3f( x*nsign, y*nsign, nz*nsign ); + TXTR_COORD(s, t); + glVertex3f( x * r, y * r, z ); + normal3f( x*nsign, y*nsign, nz*nsign ); + TXTR_COORD(s, t + dt); + glVertex3f( x * (r + dr), y * (r + dr), z + dz); + } + s += ds; + } /* for slices */ + glEnd(); + r += dr; + t += dt; + z += dz; + } /* for stacks */ + } +} + + + + + +void GLAPIENTRY gluSphere( GLUquadricObj *qobj, + GLdouble radius, GLint slices, GLint stacks ) +{ + GLfloat rho, drho, theta, dtheta; + GLfloat x, y, z; + GLfloat s, t, ds, dt; + GLint i, j, imin, imax; + GLboolean normals; + GLfloat nsign; + + if (qobj->Normals==GLU_NONE) { + normals = GL_FALSE; + } + else { + normals = GL_TRUE; + } + if (qobj->Orientation==GLU_INSIDE) { + nsign = -1.0; + } + else { + nsign = 1.0; + } + + drho = M_PI / (GLfloat) stacks; + dtheta = 2.0 * M_PI / (GLfloat) slices; + + /* texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis */ + /* t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes) */ + /* cannot use triangle fan on texturing (s coord. at top/bottom tip varies) */ + + if (qobj->DrawStyle==GLU_FILL) { + if (!qobj->TextureFlag) { + /* draw +Z end as a triangle fan */ + glBegin( GL_TRIANGLE_FAN ); + glNormal3f( 0.0, 0.0, 1.0 ); + TXTR_COORD(0.5,1.0); + glVertex3f( 0.0, 0.0, nsign * radius ); + for (j=0;j<=slices;j++) { + theta = (j==slices) ? 0.0 : j * dtheta; + x = -sin(theta) * sin(drho); + y = cos(theta) * sin(drho); + z = nsign * cos(drho); + if (normals) glNormal3f( x*nsign, y*nsign, z*nsign ); + glVertex3f( x*radius, y*radius, z*radius ); + } + glEnd(); + } + + ds = 1.0 / slices; + dt = 1.0 / stacks; + t = 1.0; /* because loop now runs from 0 */ + if (qobj->TextureFlag) { + imin = 0; + imax = stacks; + } + else { + imin = 1; + imax = stacks-1; + } + + /* draw intermediate stacks as quad strips */ + for (i=imin;i<imax;i++) { + rho = i * drho; + glBegin( GL_QUAD_STRIP ); + s = 0.0; + for (j=0;j<=slices;j++) { + theta = (j==slices) ? 0.0 : j * dtheta; + x = -sin(theta) * sin(rho); + y = cos(theta) * sin(rho); + z = nsign * cos(rho); + if (normals) glNormal3f( x*nsign, y*nsign, z*nsign ); + TXTR_COORD(s,t); + glVertex3f( x*radius, y*radius, z*radius ); + x = -sin(theta) * sin(rho+drho); + y = cos(theta) * sin(rho+drho); + z = nsign * cos(rho+drho); + if (normals) glNormal3f( x*nsign, y*nsign, z*nsign ); + TXTR_COORD(s,t-dt); + s += ds; + glVertex3f( x*radius, y*radius, z*radius ); + } + glEnd(); + t -= dt; + } + + if (!qobj->TextureFlag) { + /* draw -Z end as a triangle fan */ + glBegin( GL_TRIANGLE_FAN ); + glNormal3f( 0.0, 0.0, -1.0 ); + TXTR_COORD(0.5,0.0); + glVertex3f( 0.0, 0.0, -radius*nsign ); + rho = M_PI - drho; + s = 1.0; + t = dt; + for (j=slices;j>=0;j--) { + theta = (j==slices) ? 0.0 : j * dtheta; + x = -sin(theta) * sin(rho); + y = cos(theta) * sin(rho); + z = nsign * cos(rho); + if (normals) glNormal3f( x*nsign, y*nsign, z*nsign ); + TXTR_COORD(s,t); + s -= ds; + glVertex3f( x*radius, y*radius, z*radius ); + } + glEnd(); + } + } + else if (qobj->DrawStyle==GLU_LINE || qobj->DrawStyle==GLU_SILHOUETTE) { + /* draw stack lines */ + for (i=1;i<stacks;i++) { /* stack line at i==stacks-1 was missing here */ + rho = i * drho; + glBegin( GL_LINE_LOOP ); + for (j=0;j<slices;j++) { + theta = j * dtheta; + x = cos(theta) * sin(rho); + y = sin(theta) * sin(rho); + z = cos(rho); + if (normals) glNormal3f( x*nsign, y*nsign, z*nsign ); + glVertex3f( x*radius, y*radius, z*radius ); + } + glEnd(); + } + /* draw slice lines */ + for (j=0;j<slices;j++) { + theta = j * dtheta; + glBegin( GL_LINE_STRIP ); + for (i=0;i<=stacks;i++) { + rho = i * drho; + x = cos(theta) * sin(rho); + y = sin(theta) * sin(rho); + z = cos(rho); + if (normals) glNormal3f( x*nsign, y*nsign, z*nsign ); + glVertex3f( x*radius, y*radius, z*radius ); + } + glEnd(); + } + } + else if (qobj->DrawStyle==GLU_POINT) { + /* top and bottom-most points */ + glBegin( GL_POINTS ); + if (normals) glNormal3f( 0.0, 0.0, nsign ); + glVertex3d( 0.0, 0.0, radius ); + if (normals) glNormal3f( 0.0, 0.0, -nsign ); + glVertex3d( 0.0, 0.0, -radius ); + + /* loop over stacks */ + for (i=1;i<stacks-1;i++) { + rho = i * drho; + for (j=0;j<slices;j++) { + theta = j * dtheta; + x = cos(theta) * sin(rho); + y = sin(theta) * sin(rho); + z = cos(rho); + if (normals) glNormal3f( x*nsign, y*nsign, z*nsign ); + glVertex3f( x*radius, y*radius, z*radius ); + } + } + glEnd(); + } + +} + + + +void GLAPIENTRY gluDisk( GLUquadricObj *qobj, + GLdouble innerRadius, GLdouble outerRadius, + GLint slices, GLint loops ) +{ + GLfloat da, dr; +#if 0 + GLdouble a, da; + GLfloat r, dr; + GLfloat x, y; + GLfloat r1, r2, dtc; + GLint s, l; +#endif + + /* Normal vectors */ + if (qobj->Normals!=GLU_NONE) { + if (qobj->Orientation==GLU_OUTSIDE) { + glNormal3f( 0.0, 0.0, +1.0 ); + } + else { + glNormal3f( 0.0, 0.0, -1.0 ); + } + } + + da = 2.0*M_PI / slices; + dr = (outerRadius-innerRadius) / (GLfloat) loops; + + switch (qobj->DrawStyle) { + case GLU_FILL: + { + /* texture of a gluDisk is a cut out of the texture unit square + * x, y in [-outerRadius, +outerRadius]; s, t in [0, 1] + * (linear mapping) + */ + GLfloat dtc = 2.0f * outerRadius; + GLfloat sa,ca; + GLfloat r1 = innerRadius; + GLint l; + for (l=0; l<loops; l++) { + GLfloat r2 = r1 + dr; + if (qobj->Orientation==GLU_OUTSIDE) { + GLint s; + glBegin( GL_QUAD_STRIP ); + for (s=0;s<=slices;s++) { + GLfloat a; + if (s==slices) a = 0.0; + else a = s * da; + sa = sin(a); ca = cos(a); + TXTR_COORD(0.5+sa*r2/dtc,0.5+ca*r2/dtc); + glVertex2f( r2*sa, r2*ca ); + TXTR_COORD(0.5+sa*r1/dtc,0.5+ca*r1/dtc); + glVertex2f( r1*sa, r1*ca ); + } + glEnd(); + } + else { + GLint s; + glBegin( GL_QUAD_STRIP ); + for (s=slices;s>=0;s--) { + GLfloat a; + if (s==slices) a = 0.0; + else a = s * da; + sa = sin(a); ca = cos(a); + TXTR_COORD(0.5-sa*r2/dtc,0.5+ca*r2/dtc); + glVertex2f( r2*sa, r2*ca ); + TXTR_COORD(0.5-sa*r1/dtc,0.5+ca*r1/dtc); + glVertex2f( r1*sa, r1*ca ); + } + glEnd(); + } + r1 = r2; + } + break; + } + case GLU_LINE: + { + GLint l, s; + /* draw loops */ + for (l=0; l<=loops; l++) { + GLfloat r = innerRadius + l * dr; + glBegin( GL_LINE_LOOP ); + for (s=0; s<slices; s++) { + GLfloat a = s * da; + glVertex2f( r*sin(a), r*cos(a) ); + } + glEnd(); + } + /* draw spokes */ + for (s=0; s<slices; s++) { + GLfloat a = s * da; + GLfloat x = sin(a); + GLfloat y = cos(a); + glBegin( GL_LINE_STRIP ); + for (l=0; l<=loops; l++) { + GLfloat r = innerRadius + l * dr; + glVertex2f( r*x, r*y ); + } + glEnd(); + } + break; + } + case GLU_POINT: + { + GLint s; + glBegin( GL_POINTS ); + for (s=0; s<slices; s++) { + GLfloat a = s * da; + GLfloat x = sin(a); + GLfloat y = cos(a); + GLint l; + for (l=0; l<=loops; l++) { + GLfloat r = innerRadius * l * dr; + glVertex2f( r*x, r*y ); + } + } + glEnd(); + break; + } + case GLU_SILHOUETTE: + { + if (innerRadius!=0.0) { + GLfloat a; + glBegin( GL_LINE_LOOP ); + for (a=0.0; a<2.0*M_PI; a+=da) { + GLfloat x = innerRadius * sin(a); + GLfloat y = innerRadius * cos(a); + glVertex2f( x, y ); + } + glEnd(); + } + { + GLfloat a; + glBegin( GL_LINE_LOOP ); + for (a=0; a<2.0*M_PI; a+=da) { + GLfloat x = outerRadius * sin(a); + GLfloat y = outerRadius * cos(a); + glVertex2f( x, y ); + } + glEnd(); + } + break; + } + default: + abort(); + } +} + + + +void GLAPIENTRY gluPartialDisk( GLUquadricObj *qobj, GLdouble innerRadius, + GLdouble outerRadius, GLint slices, GLint loops, + GLdouble startAngle, GLdouble sweepAngle ) +{ + if (qobj->Normals!=GLU_NONE) { + if (qobj->Orientation==GLU_OUTSIDE) { + glNormal3f( 0.0, 0.0, +1.0 ); + } + else { + glNormal3f( 0.0, 0.0, -1.0 ); + } + } + + if (qobj->DrawStyle==GLU_POINT) { + GLint loop, slice; + GLdouble radius, delta_radius; + GLdouble angle, delta_angle; + delta_radius = (outerRadius - innerRadius) / (loops-1); + delta_angle = DEG_TO_RAD((sweepAngle) / (slices-1)); + glBegin( GL_POINTS ); + radius = innerRadius; + for (loop=0; loop<loops; loop++) { + angle = DEG_TO_RAD(startAngle); + for (slice=0; slice<slices; slice++) { + glVertex2d( radius * sin(angle), radius * cos(angle) ); + angle += delta_angle; + } + radius += delta_radius; + } + glEnd(); + } + else if (qobj->DrawStyle==GLU_LINE) { + GLint loop, slice; + GLdouble radius, delta_radius; + GLdouble angle, delta_angle; + delta_radius = (outerRadius - innerRadius) / loops; + delta_angle = DEG_TO_RAD(sweepAngle / slices); + /* draw rings */ + radius = innerRadius; + for (loop=0; loop<loops; loop++) { + angle = DEG_TO_RAD(startAngle); + glBegin( GL_LINE_STRIP ); + for (slice=0; slice<slices; slice++) { + glVertex2d( radius * sin(angle), radius * cos(angle) ); + angle += delta_angle; + } + glEnd(); + radius += delta_radius; + } + /* draw spokes */ + angle = DEG_TO_RAD(startAngle); + for (slice=0; slice<slices; slice++) { + radius = innerRadius; + glBegin( GL_LINE_STRIP ); + for (loop=0; loop<loops; loop++) { + glVertex2d( radius * sin(angle), radius * cos(angle) ); + radius += delta_radius; + } + glEnd(); + angle += delta_angle; + } + } + else if (qobj->DrawStyle==GLU_SILHOUETTE) { + GLint slice; + GLdouble angle, delta_angle; + delta_angle = DEG_TO_RAD(sweepAngle / slices); + /* draw outer ring */ + glBegin( GL_LINE_STRIP ); + angle = DEG_TO_RAD(startAngle); + for (slice=0; slice<=slices; slice++) { + glVertex2d( outerRadius * sin(angle), outerRadius * cos(angle) ); + angle += delta_angle; + } + glEnd(); + /* draw inner ring */ + if (innerRadius>0.0) { + glBegin( GL_LINE_STRIP ); + angle = DEG_TO_RAD(startAngle); + for (slice=0; slice<slices; slice++) { + glVertex2d( innerRadius * sin(angle), innerRadius * cos(angle) ); + angle += delta_angle; + } + glEnd(); + } + /* draw spokes */ + if (sweepAngle<360.0) { + GLdouble stopAngle = startAngle + sweepAngle; + glBegin( GL_LINES ); + glVertex2d( innerRadius*SIND(startAngle), innerRadius*COSD(startAngle) ); + glVertex2d( outerRadius*SIND(startAngle), outerRadius*COSD(startAngle) ); + glVertex2d( innerRadius*SIND(stopAngle), innerRadius*COSD(stopAngle) ); + glVertex2d( outerRadius*SIND(stopAngle), outerRadius*COSD(stopAngle) ); + glEnd(); + } + } + else if (qobj->DrawStyle==GLU_FILL) { + GLint loop, slice; + GLdouble radius, delta_radius; + GLdouble angle, delta_angle; + delta_radius = (outerRadius - innerRadius) / loops; + delta_angle = DEG_TO_RAD(sweepAngle / slices); + radius = innerRadius; + for (loop=0; loop<loops; loop++) { + glBegin( GL_QUAD_STRIP ); + angle = DEG_TO_RAD(startAngle); + for (slice=0; slice<slices; slice++) { + if (qobj->Orientation==GLU_OUTSIDE) { + glVertex2d( (radius+delta_radius)*sin(angle), + (radius+delta_radius)*cos(angle) ); + glVertex2d( radius * sin(angle), radius * cos(angle) ); + } + else { + glVertex2d( radius * sin(angle), radius * cos(angle) ); + glVertex2d( (radius+delta_radius)*sin(angle), + (radius+delta_radius)*cos(angle) ); + } + angle += delta_angle; + } + glEnd(); + radius += delta_radius; + } + } +} + + + diff --git a/src/glu/mesa/tess.c b/src/glu/mesa/tess.c new file mode 100644 index 00000000000..c773fbaae4b --- /dev/null +++ b/src/glu/mesa/tess.c @@ -0,0 +1,369 @@ +/* $Id: tess.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.1 + * Copyright (C) 1995-1999 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: tess.c,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.11 1999/02/27 13:55:31 brianp + * fixed BeOS-related GLU typedef problems + * + * Revision 1.10 1999/01/03 03:23:15 brianp + * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump) + * + * Revision 1.9 1998/06/01 01:10:29 brianp + * small update for Next/OpenStep from Alexander Mai + * + * Revision 1.8 1998/02/04 00:27:58 brianp + * cygnus changes from Stephane Rehel + * + * Revision 1.7 1998/01/16 03:35:26 brianp + * fixed Windows compilation warnings (Theodore Jump) + * + * Revision 1.6 1997/09/17 01:51:48 brianp + * changed glu*Callback() functions to match prototype in glu.h + * + * 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 1996/11/12 01:23:02 brianp + * added test to prevent free(vertex) when vertex==NULL in delete_contours() + * + * Revision 1.2 1996/10/22 22:57:19 brianp + * better error handling in gluBegin/EndPolygon() from Erich Eder + * + * Revision 1.1 1996/09/27 01:19:39 brianp + * Initial revision + * + */ + + +/* + * This file is part of the polygon tesselation code contributed by + * Bogdan Sikorski + */ + + +#ifdef PC_HEADER +#include "all.h" +#else +#include <math.h> +#include <stdlib.h> +#include "tess.h" +#endif + + +/* + * This is ugly, but seems the easiest way to do things to make the + * code work under YellowBox for Windows + */ +#if defined(OPENSTEP) && defined(GLCALLBACK) +#undef GLCALLBACK +#define GLCALLBACK +#endif + + +extern void tess_test_polygon(GLUtriangulatorObj *); +extern void tess_find_contour_hierarchies(GLUtriangulatorObj *); +extern void tess_handle_holes(GLUtriangulatorObj *); +extern void tess_tesselate(GLUtriangulatorObj *); +extern void tess_tesselate_with_edge_flag(GLUtriangulatorObj *); +static void delete_contours(GLUtriangulatorObj *); + +#ifdef __CYGWIN32__ +#define _CALLBACK +#else +#define _CALLBACK GLCALLBACK +#endif + +void init_callbacks(tess_callbacks *callbacks) +{ + callbacks->begin = ( void (_CALLBACK*)(GLenum) ) 0; + callbacks->edgeFlag = ( void (_CALLBACK*)(GLboolean) ) 0; + callbacks->vertex = ( void (_CALLBACK*)(void*) ) 0; + callbacks->end = ( void (_CALLBACK*)(void) ) 0; + callbacks->error = ( void (_CALLBACK*)(GLenum) ) 0; +} + +void tess_call_user_error(GLUtriangulatorObj *tobj, GLenum gluerr) +{ + if(tobj->error==GLU_NO_ERROR) + tobj->error=gluerr; + if(tobj->callbacks.error!=NULL) + (tobj->callbacks.error)(gluerr); +} + +GLUtriangulatorObj* GLAPIENTRY gluNewTess( void ) +{ + GLUtriangulatorObj *tobj; + tobj = (GLUtriangulatorObj *) malloc(sizeof(struct GLUtesselator)); + if (!tobj) + return NULL; + tobj->contours=tobj->last_contour=NULL; + init_callbacks(&tobj->callbacks); + tobj->error=GLU_NO_ERROR; + tobj->current_polygon=NULL; + tobj->contour_cnt=0; + return tobj; +} + + +void GLAPIENTRY gluTessCallback( GLUtriangulatorObj *tobj, GLenum which, + void (GLCALLBACK *fn)() ) +{ + switch(which) + { + case GLU_BEGIN: + tobj->callbacks.begin = (void (_CALLBACK*)(GLenum)) fn; + break; + case GLU_EDGE_FLAG: + tobj->callbacks.edgeFlag = (void (_CALLBACK*)(GLboolean)) fn; + break; + case GLU_VERTEX: + tobj->callbacks.vertex = (void (_CALLBACK*)(void *)) fn; + break; + case GLU_END: + tobj->callbacks.end = (void (_CALLBACK*)(void)) fn; + break; + case GLU_ERROR: + tobj->callbacks.error = (void (_CALLBACK*)(GLenum)) fn; + break; + default: + tobj->error=GLU_INVALID_ENUM; + break; + } +} + + + +void GLAPIENTRY gluDeleteTess( GLUtriangulatorObj *tobj ) +{ + if(tobj->error==GLU_NO_ERROR && tobj->contour_cnt) + /* was gluEndPolygon called? */ + tess_call_user_error(tobj,GLU_TESS_ERROR1); + /* delete all internal structures */ + delete_contours(tobj); + free(tobj); +} + + +void GLAPIENTRY gluBeginPolygon( GLUtriangulatorObj *tobj ) +{ +/* + if(tobj->error!=GLU_NO_ERROR) + return; +*/ + tobj->error = GLU_NO_ERROR; + if(tobj->current_polygon!=NULL) + { + /* gluEndPolygon was not called */ + tess_call_user_error(tobj,GLU_TESS_ERROR1); + /* delete all internal structures */ + delete_contours(tobj); + } + else + { + if((tobj->current_polygon= + (tess_polygon *)malloc(sizeof(tess_polygon)))==NULL) + { + tess_call_user_error(tobj,GLU_OUT_OF_MEMORY); + return; + } + tobj->current_polygon->vertex_cnt=0; + tobj->current_polygon->vertices= + tobj->current_polygon->last_vertex=NULL; + } +} + + +void GLAPIENTRY gluEndPolygon( GLUtriangulatorObj *tobj ) +{ + /*tess_contour *contour_ptr;*/ + + /* there was an error */ + if(tobj->error!=GLU_NO_ERROR) goto end; + + /* check if gluBeginPolygon was called */ + if(tobj->current_polygon==NULL) + { + tess_call_user_error(tobj,GLU_TESS_ERROR2); + return; + } + tess_test_polygon(tobj); + /* there was an error */ + if(tobj->error!=GLU_NO_ERROR) goto end; + + /* any real contours? */ + if(tobj->contour_cnt==0) + { + /* delete all internal structures */ + delete_contours(tobj); + return; + } + tess_find_contour_hierarchies(tobj); + /* there was an error */ + if(tobj->error!=GLU_NO_ERROR) goto end; + + tess_handle_holes(tobj); + /* there was an error */ + if(tobj->error!=GLU_NO_ERROR) goto end; + + /* if no callbacks, nothing to do */ + if(tobj->callbacks.begin!=NULL && tobj->callbacks.vertex!=NULL && + tobj->callbacks.end!=NULL) + { + if(tobj->callbacks.edgeFlag==NULL) + tess_tesselate(tobj); + else + tess_tesselate_with_edge_flag(tobj); + } + +end: + /* delete all internal structures */ + delete_contours(tobj); +} + + +void GLAPIENTRY gluNextContour( GLUtriangulatorObj *tobj, GLenum type ) +{ + if(tobj->error!=GLU_NO_ERROR) + return; + if(tobj->current_polygon==NULL) + { + tess_call_user_error(tobj,GLU_TESS_ERROR2); + return; + } + /* first contour? */ + if(tobj->current_polygon->vertex_cnt) + tess_test_polygon(tobj); +} + + +void GLAPIENTRY gluTessVertex( GLUtriangulatorObj *tobj, GLdouble v[3], void *data ) +{ + tess_polygon *polygon=tobj->current_polygon; + tess_vertex *last_vertex_ptr; + + if(tobj->error!=GLU_NO_ERROR) + return; + if(polygon==NULL) + { + tess_call_user_error(tobj,GLU_TESS_ERROR2); + return; + } + last_vertex_ptr=polygon->last_vertex; + if(last_vertex_ptr==NULL) + { + if((last_vertex_ptr=(tess_vertex *) + malloc(sizeof(tess_vertex)))==NULL) + { + tess_call_user_error(tobj,GLU_OUT_OF_MEMORY); + return; + } + polygon->vertices=last_vertex_ptr; + polygon->last_vertex=last_vertex_ptr; + last_vertex_ptr->data=data; + last_vertex_ptr->location[0]=v[0]; + last_vertex_ptr->location[1]=v[1]; + last_vertex_ptr->location[2]=v[2]; + last_vertex_ptr->next=NULL; + last_vertex_ptr->previous=NULL; + ++(polygon->vertex_cnt); + } + else + { + tess_vertex *vertex_ptr; + + /* same point twice? */ + if(fabs(last_vertex_ptr->location[0]-v[0]) < EPSILON && + fabs(last_vertex_ptr->location[1]-v[1]) < EPSILON && + fabs(last_vertex_ptr->location[2]-v[2]) < EPSILON) + { + tess_call_user_error(tobj,GLU_TESS_ERROR6); + return; + } + if((vertex_ptr=(tess_vertex *) + malloc(sizeof(tess_vertex)))==NULL) + { + tess_call_user_error(tobj,GLU_OUT_OF_MEMORY); + return; + } + vertex_ptr->data=data; + vertex_ptr->location[0]=v[0]; + vertex_ptr->location[1]=v[1]; + vertex_ptr->location[2]=v[2]; + vertex_ptr->next=NULL; + vertex_ptr->previous=last_vertex_ptr; + ++(polygon->vertex_cnt); + last_vertex_ptr->next=vertex_ptr; + polygon->last_vertex=vertex_ptr; + } +} + + +static void delete_contours(GLUtriangulatorObj *tobj) +{ + tess_polygon *polygon=tobj->current_polygon; + tess_contour *contour,*contour_tmp; + tess_vertex *vertex,*vertex_tmp; + + /* remove current_polygon list - if exists due to detected error */ + if(polygon!=NULL) + { + if (polygon->vertices) + { + for(vertex=polygon->vertices;vertex!=polygon->last_vertex;) + { + vertex_tmp=vertex->next; + free(vertex); + vertex=vertex_tmp; + } + free(vertex); + } + free(polygon); + tobj->current_polygon=NULL; + } + /* remove all contour data */ + for(contour=tobj->contours;contour!=NULL;) + { + for(vertex=contour->vertices;vertex!=contour->last_vertex;) + { + vertex_tmp=vertex->next; + free(vertex); + vertex=vertex_tmp; + } + free(vertex); + contour_tmp=contour->next; + free(contour); + contour=contour_tmp; + } + tobj->contours=tobj->last_contour=NULL; + tobj->contour_cnt=0; +} + + + diff --git a/src/glu/mesa/tess.h b/src/glu/mesa/tess.h new file mode 100644 index 00000000000..53d673ccbea --- /dev/null +++ b/src/glu/mesa/tess.h @@ -0,0 +1,121 @@ +/* $Id: tess.h,v 1.1 1999/08/19 00:55:42 jtg Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.1 + * Copyright (C) 1995-1998 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: tess.h,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.5 1999/02/27 13:55:31 brianp + * fixed BeOS-related GLU typedef problems + * + * Revision 1.4 1999/01/03 03:23:15 brianp + * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump) + * + * Revision 1.3 1997/10/29 02:02:20 brianp + * various MS Windows compiler changes (David Bucciarelli, v20 3dfx driver) + * + * Revision 1.2 1997/05/24 13:30:58 brianp + * added TESS_H multi-inclusion prevention test + * + * Revision 1.1 1996/09/27 01:19:39 brianp + * Initial revision + * + */ + + +/* + * This file is part of the polygon tesselation code contributed by + * Bogdan Sikorski + */ + + +#ifndef TESS_H +#define TESS_H + + +#include "gluP.h" + +#define EPSILON 1e-06 /* epsilon for double precision compares */ + +typedef enum +{ + OXY, + OYZ, + OXZ +} projection_type; + +typedef struct callbacks_str +{ + void (GLCALLBACK *begin)( GLenum mode ); + void (GLCALLBACK *edgeFlag)( GLboolean flag ); + void (GLCALLBACK *vertex)( GLvoid *v ); + void (GLCALLBACK *end)( void ); + void (GLCALLBACK *error)( GLenum err ); +} tess_callbacks; + +typedef struct vertex_str +{ + void *data; + GLdouble location[3]; + GLdouble x,y; + GLboolean edge_flag; + struct vertex_str *shadow_vertex; + struct vertex_str *next,*previous; +} tess_vertex; + +typedef struct contour_str +{ + GLenum type; + GLuint vertex_cnt; + GLdouble area; + GLenum orientation; + struct vertex_str *vertices,*last_vertex; + struct contour_str *next,*previous; +} tess_contour; + +typedef struct polygon_str +{ + GLuint vertex_cnt; + GLdouble A,B,C,D; + GLdouble area; + GLenum orientation; + struct vertex_str *vertices,*last_vertex; +} tess_polygon; + +struct GLUtesselator +{ + tess_contour *contours,*last_contour; + GLuint contour_cnt; + tess_callbacks callbacks; + tess_polygon *current_polygon; + GLenum error; + GLdouble A,B,C,D; + projection_type projection; +}; + + +extern void tess_call_user_error(GLUtriangulatorObj *,GLenum); + + +#endif diff --git a/src/glu/mesa/tesselat.c b/src/glu/mesa/tesselat.c new file mode 100644 index 00000000000..1e424c17ca7 --- /dev/null +++ b/src/glu/mesa/tesselat.c @@ -0,0 +1,456 @@ +/* $Id: tesselat.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: tesselat.c,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * 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/02/17 17:24:58 brianp + * more tesselation changes (Randy Frank) + * + * Revision 1.2 1997/02/13 18:31:57 brianp + * fixed some numerical precision problems (Randy Frank) + * + * Revision 1.1 1996/09/27 01:19:39 brianp + * Initial revision + * + */ + + +/* + * This file is part of the polygon tesselation code contributed by + * Bogdan Sikorski + */ + + +#ifdef PC_HEADER +#include "all.h" +#else +#include <stdlib.h> +#include <math.h> +#include "tess.h" +#endif + + + +static GLboolean edge_flag; + +static void emit_triangle(GLUtriangulatorObj *, tess_vertex *, + tess_vertex *,tess_vertex *); + +static void emit_triangle_with_edge_flag(GLUtriangulatorObj *, + tess_vertex *,GLboolean,tess_vertex *,GLboolean, + tess_vertex *,GLboolean); + +static GLdouble twice_the_triangle_area( + tess_vertex *va, + tess_vertex *vb, + tess_vertex *vc) +{ + return (vb->x - va->x)*(vc->y - va->y) - (vb->y - va->y)*(vc->x - va->x); +} + +static GLboolean left( + GLdouble A, + GLdouble B, + GLdouble C, + GLdouble x, + GLdouble y) +{ + if(A*x+B*y+C > -EPSILON) + return GL_TRUE; + else + return GL_FALSE; +} + +static GLboolean right( + GLdouble A, + GLdouble B, + GLdouble C, + GLdouble x, + GLdouble y) +{ + if(A*x+B*y+C < EPSILON) + return GL_TRUE; + else + return GL_FALSE; +} + +static GLint convex_ccw( + tess_vertex *va, + tess_vertex *vb, + tess_vertex *vc, + GLUtriangulatorObj *tobj) +{ + GLdouble d; + + d = twice_the_triangle_area(va,vb,vc); + + if (d > EPSILON ) { + return 1; + } else if (d < -EPSILON ) { + return 0; + } else { + return -1; + } +} + +static GLint convex_cw( + tess_vertex *va, + tess_vertex *vb, + tess_vertex *vc, + GLUtriangulatorObj *tobj) +{ + GLdouble d; + + d = twice_the_triangle_area(va,vb,vc); + + if (d < -EPSILON ) { + return 1; + } else if (d > EPSILON ) { + return 0; + } else { + return -1; + } +} + +static GLboolean diagonal_ccw( + tess_vertex *va, + tess_vertex *vb, + GLUtriangulatorObj *tobj, + tess_contour *contour) +{ + tess_vertex *vc=va->next , *vertex , *shadow_vertex; + struct + { + GLdouble A,B,C; + } ac,cb,ba; + GLdouble x,y; + + GLint res = convex_ccw(va,vc,vb,tobj); + if (res == 0) return GL_FALSE; + if (res == -1) return GL_TRUE; + + ba.A=vb->y - va->y; + ba.B=va->x - vb->x; + ba.C= -ba.A*va->x - ba.B*va->y; + ac.A=va->y - vc->y; + ac.B=vc->x - va->x; + ac.C= -ac.A*vc->x - ac.B*vc->y; + cb.A=vc->y - vb->y; + cb.B=vb->x - vc->x; + cb.C= -cb.A*vb->x - cb.B*vb->y; + for(vertex=vb->next;vertex!=va;vertex=vertex->next) + { + shadow_vertex=vertex->shadow_vertex; + if(shadow_vertex!=NULL && + (shadow_vertex==va || shadow_vertex==vb || shadow_vertex==vc)) + continue; + x=vertex->x; + y=vertex->y; + if(left(ba.A,ba.B,ba.C,x,y) && + left(ac.A,ac.B,ac.C,x,y) && + left(cb.A,cb.B,cb.C,x,y)) + return GL_FALSE; + } + return GL_TRUE; +} + +static GLboolean diagonal_cw( + tess_vertex *va, + tess_vertex *vb, + GLUtriangulatorObj *tobj, + tess_contour *contour) +{ + tess_vertex *vc=va->next , *vertex , *shadow_vertex; + struct + { + GLdouble A,B,C; + } ac,cb,ba; + GLdouble x,y; + + GLint res = convex_cw(va,vc,vb,tobj); + if (res == 0) return GL_FALSE; + if (res == -1) return GL_TRUE; + + ba.A=vb->y - va->y; + ba.B=va->x - vb->x; + ba.C= -ba.A*va->x - ba.B*va->y; + ac.A=va->y - vc->y; + ac.B=vc->x - va->x; + ac.C= -ac.A*vc->x - ac.B*vc->y; + cb.A=vc->y - vb->y; + cb.B=vb->x - vc->x; + cb.C= -cb.A*vb->x - cb.B*vb->y; + for(vertex=vb->next;vertex!=va;vertex=vertex->next) + { + shadow_vertex=vertex->shadow_vertex; + if(shadow_vertex!=NULL && + (shadow_vertex==va || shadow_vertex==vb || shadow_vertex==vc)) + continue; + x=vertex->x; + y=vertex->y; + if(right(ba.A,ba.B,ba.C,x,y) && + right(ac.A,ac.B,ac.C,x,y) && + right(cb.A,cb.B,cb.C,x,y)) + return GL_FALSE; + } + return GL_TRUE; +} + +static void clip_ear( + GLUtriangulatorObj *tobj, + tess_vertex *v, + tess_contour *contour) +{ + emit_triangle(tobj,v->previous,v,v->next); + /* the first in the list */ + if(contour->vertices==v) + { + contour->vertices=v->next; + contour->last_vertex->next=v->next; + v->next->previous=contour->last_vertex; + } + else + /* the last ? */ + if(contour->last_vertex==v) + { + contour->vertices->previous=v->previous; + v->previous->next=v->next; + contour->last_vertex=v->previous; + } + else + { + v->next->previous=v->previous; + v->previous->next=v->next; + } + free(v); + --(contour->vertex_cnt); +} + +static void clip_ear_with_edge_flag( + GLUtriangulatorObj *tobj, + tess_vertex *v, + tess_contour *contour) +{ + emit_triangle_with_edge_flag(tobj,v->previous,v->previous->edge_flag, + v,v->edge_flag,v->next,GL_FALSE); + v->previous->edge_flag=GL_FALSE; + /* the first in the list */ + if(contour->vertices==v) + { + contour->vertices=v->next; + contour->last_vertex->next=v->next; + v->next->previous=contour->last_vertex; + } + else + /* the last ? */ + if(contour->last_vertex==v) + { + contour->vertices->previous=v->previous; + v->previous->next=v->next; + contour->last_vertex=v->previous; + } + else + { + v->next->previous=v->previous; + v->previous->next=v->next; + } + free(v); + --(contour->vertex_cnt); +} + +static void triangulate_ccw( + GLUtriangulatorObj *tobj, + tess_contour *contour) +{ + tess_vertex *vertex; + GLuint vertex_cnt=contour->vertex_cnt; + + while(vertex_cnt > 3) + { + vertex=contour->vertices; + while(diagonal_ccw(vertex,vertex->next->next,tobj,contour)==GL_FALSE && + tobj->error==GLU_NO_ERROR) + vertex=vertex->next; + if(tobj->error!=GLU_NO_ERROR) + return; + clip_ear(tobj,vertex->next,contour); + --vertex_cnt; + } +} + +static void triangulate_cw( + GLUtriangulatorObj *tobj, + tess_contour *contour) +{ + tess_vertex *vertex; + GLuint vertex_cnt=contour->vertex_cnt; + + while(vertex_cnt > 3) + { + vertex=contour->vertices; + while(diagonal_cw(vertex,vertex->next->next,tobj,contour)==GL_FALSE && + tobj->error==GLU_NO_ERROR) + vertex=vertex->next; + if(tobj->error!=GLU_NO_ERROR) + return; + clip_ear(tobj,vertex->next,contour); + --vertex_cnt; + } +} + +static void triangulate_ccw_with_edge_flag( + GLUtriangulatorObj *tobj, + tess_contour *contour) +{ + tess_vertex *vertex; + GLuint vertex_cnt=contour->vertex_cnt; + + while(vertex_cnt > 3) + { + vertex=contour->vertices; + while(diagonal_ccw(vertex,vertex->next->next,tobj,contour)==GL_FALSE && + tobj->error==GLU_NO_ERROR) + vertex=vertex->next; + if(tobj->error!=GLU_NO_ERROR) + return; + clip_ear_with_edge_flag(tobj,vertex->next,contour); + --vertex_cnt; + } +} + +static void triangulate_cw_with_edge_flag( + GLUtriangulatorObj *tobj, + tess_contour *contour) +{ + tess_vertex *vertex; + GLuint vertex_cnt=contour->vertex_cnt; + + while(vertex_cnt > 3) + { + vertex=contour->vertices; + while(diagonal_cw(vertex,vertex->next->next,tobj,contour)==GL_FALSE && + tobj->error==GLU_NO_ERROR) + vertex=vertex->next; + if(tobj->error!=GLU_NO_ERROR) + return; + clip_ear_with_edge_flag(tobj,vertex->next,contour); + --vertex_cnt; + } +} + +void tess_tesselate(GLUtriangulatorObj *tobj) +{ + tess_contour *contour; + + for(contour=tobj->contours;contour!=NULL;contour=contour->next) + { + if(contour->orientation==GLU_CCW) { + triangulate_ccw(tobj,contour); + } else { + triangulate_cw(tobj,contour); + } + if(tobj->error!=GLU_NO_ERROR) + return; + + /* emit the last triangle */ + emit_triangle(tobj,contour->vertices,contour->vertices->next, + contour->vertices->next->next); + } +} + +void tess_tesselate_with_edge_flag(GLUtriangulatorObj *tobj) +{ + tess_contour *contour; + + edge_flag=GL_TRUE; + /* first callback with edgeFlag set to GL_TRUE */ + (tobj->callbacks.edgeFlag)(GL_TRUE); + + for(contour=tobj->contours;contour!=NULL;contour=contour->next) + { + if(contour->orientation==GLU_CCW) + triangulate_ccw_with_edge_flag(tobj,contour); + else + triangulate_cw_with_edge_flag(tobj,contour); + if(tobj->error!=GLU_NO_ERROR) + return; + /* emit the last triangle */ + emit_triangle_with_edge_flag(tobj,contour->vertices, + contour->vertices->edge_flag,contour->vertices->next, + contour->vertices->next->edge_flag,contour->vertices->next->next, + contour->vertices->next->next->edge_flag); + } +} + +static void emit_triangle( + GLUtriangulatorObj *tobj, + tess_vertex *v1, + tess_vertex *v2, + tess_vertex *v3) +{ + (tobj->callbacks.begin)(GL_TRIANGLES); + (tobj->callbacks.vertex)(v1->data); + (tobj->callbacks.vertex)(v2->data); + (tobj->callbacks.vertex)(v3->data); + (tobj->callbacks.end)(); +} + +static void emit_triangle_with_edge_flag( + GLUtriangulatorObj *tobj, + tess_vertex *v1, + GLboolean edge_flag1, + tess_vertex *v2, + GLboolean edge_flag2, + tess_vertex *v3, + GLboolean edge_flag3) +{ + (tobj->callbacks.begin)(GL_TRIANGLES); + if(edge_flag1!=edge_flag) + { + edge_flag = (edge_flag==GL_TRUE ? GL_FALSE : GL_TRUE); + (tobj->callbacks.edgeFlag)(edge_flag); + } + (tobj->callbacks.vertex)(v1->data); + if(edge_flag2!=edge_flag) + { + edge_flag = (edge_flag==GL_TRUE ? GL_FALSE : GL_TRUE); + (tobj->callbacks.edgeFlag)(edge_flag); + } + (tobj->callbacks.vertex)(v2->data); + if(edge_flag3!=edge_flag) + { + edge_flag = (edge_flag==GL_TRUE ? GL_FALSE : GL_TRUE); + (tobj->callbacks.edgeFlag)(edge_flag); + } + (tobj->callbacks.vertex)(v3->data); + (tobj->callbacks.end)(); +} |