From: Ryan C. Gordon Date: Thu, 13 May 2010 01:26:22 +0000 (-0400) Subject: Moving GLU sources into a Dependencies directory. X-Git-Url: https://git.jsancho.org/?a=commitdiff_plain;h=e83d733ee595d57bbac80ee1604dbad423d52444;p=lugaru.git Moving GLU sources into a Dependencies directory. --- diff --git a/Dependencies/GLU/dict-list.h b/Dependencies/GLU/dict-list.h new file mode 100644 index 0000000..11331a7 --- /dev/null +++ b/Dependencies/GLU/dict-list.h @@ -0,0 +1,100 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __dict_list_h_ +#define __dict_list_h_ + +/* Use #define's so that another heap implementation can use this one */ + +#define DictKey DictListKey +#define Dict DictList +#define DictNode DictListNode + +#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq) +#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict) + +#define dictSearch(dict,key) __gl_dictListSearch(dict,key) +#define dictInsert(dict,key) __gl_dictListInsert(dict,key) +#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key) +#define dictDelete(dict,node) __gl_dictListDelete(dict,node) + +#define dictKey(n) __gl_dictListKey(n) +#define dictSucc(n) __gl_dictListSucc(n) +#define dictPred(n) __gl_dictListPred(n) +#define dictMin(d) __gl_dictListMin(d) +#define dictMax(d) __gl_dictListMax(d) + + + +typedef void *DictKey; +typedef struct Dict Dict; +typedef struct DictNode DictNode; + +Dict *dictNewDict( + void *frame, + int (*leq)(void *frame, DictKey key1, DictKey key2) ); + +void dictDeleteDict( Dict *dict ); + +/* Search returns the node with the smallest key greater than or equal + * to the given key. If there is no such key, returns a node whose + * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc. + */ +DictNode *dictSearch( Dict *dict, DictKey key ); +DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ); +void dictDelete( Dict *dict, DictNode *node ); + +#define __gl_dictListKey(n) ((n)->key) +#define __gl_dictListSucc(n) ((n)->next) +#define __gl_dictListPred(n) ((n)->prev) +#define __gl_dictListMin(d) ((d)->head.next) +#define __gl_dictListMax(d) ((d)->head.prev) +#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k))) + + +/*** Private data structures ***/ + +struct DictNode { + DictKey key; + DictNode *next; + DictNode *prev; +}; + +struct Dict { + DictNode head; + void *frame; + int (*leq)(void *frame, DictKey key1, DictKey key2); +}; + +#endif diff --git a/Dependencies/GLU/dict.c b/Dependencies/GLU/dict.c new file mode 100644 index 0000000..49d4f75 --- /dev/null +++ b/Dependencies/GLU/dict.c @@ -0,0 +1,111 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include +#include "dict-list.h" +#include "memalloc.h" + +/* really __gl_dictListNewDict */ +Dict *dictNewDict( void *frame, + int (*leq)(void *frame, DictKey key1, DictKey key2) ) +{ + Dict *dict = (Dict *) memAlloc( sizeof( Dict )); + DictNode *head; + + if (dict == NULL) return NULL; + + head = &dict->head; + + head->key = NULL; + head->next = head; + head->prev = head; + + dict->frame = frame; + dict->leq = leq; + + return dict; +} + +/* really __gl_dictListDeleteDict */ +void dictDeleteDict( Dict *dict ) +{ + DictNode *node, *next; + + for( node = dict->head.next; node != &dict->head; node = next ) { + next = node->next; + memFree( node ); + } + memFree( dict ); +} + +/* really __gl_dictListInsertBefore */ +DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ) +{ + DictNode *newNode; + + do { + node = node->prev; + } while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key)); + + newNode = (DictNode *) memAlloc( sizeof( DictNode )); + if (newNode == NULL) return NULL; + + newNode->key = key; + newNode->next = node->next; + node->next->prev = newNode; + newNode->prev = node; + node->next = newNode; + + return newNode; +} + +/* really __gl_dictListDelete */ +void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/ +{ + node->next->prev = node->prev; + node->prev->next = node->next; + memFree( node ); +} + +/* really __gl_dictListSearch */ +DictNode *dictSearch( Dict *dict, DictKey key ) +{ + DictNode *node = &dict->head; + + do { + node = node->next; + } while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key)); + + return node; +} diff --git a/Dependencies/GLU/dict.h b/Dependencies/GLU/dict.h new file mode 100644 index 0000000..11331a7 --- /dev/null +++ b/Dependencies/GLU/dict.h @@ -0,0 +1,100 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __dict_list_h_ +#define __dict_list_h_ + +/* Use #define's so that another heap implementation can use this one */ + +#define DictKey DictListKey +#define Dict DictList +#define DictNode DictListNode + +#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq) +#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict) + +#define dictSearch(dict,key) __gl_dictListSearch(dict,key) +#define dictInsert(dict,key) __gl_dictListInsert(dict,key) +#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key) +#define dictDelete(dict,node) __gl_dictListDelete(dict,node) + +#define dictKey(n) __gl_dictListKey(n) +#define dictSucc(n) __gl_dictListSucc(n) +#define dictPred(n) __gl_dictListPred(n) +#define dictMin(d) __gl_dictListMin(d) +#define dictMax(d) __gl_dictListMax(d) + + + +typedef void *DictKey; +typedef struct Dict Dict; +typedef struct DictNode DictNode; + +Dict *dictNewDict( + void *frame, + int (*leq)(void *frame, DictKey key1, DictKey key2) ); + +void dictDeleteDict( Dict *dict ); + +/* Search returns the node with the smallest key greater than or equal + * to the given key. If there is no such key, returns a node whose + * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc. + */ +DictNode *dictSearch( Dict *dict, DictKey key ); +DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ); +void dictDelete( Dict *dict, DictNode *node ); + +#define __gl_dictListKey(n) ((n)->key) +#define __gl_dictListSucc(n) ((n)->next) +#define __gl_dictListPred(n) ((n)->prev) +#define __gl_dictListMin(d) ((d)->head.next) +#define __gl_dictListMax(d) ((d)->head.prev) +#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k))) + + +/*** Private data structures ***/ + +struct DictNode { + DictKey key; + DictNode *next; + DictNode *prev; +}; + +struct Dict { + DictNode head; + void *frame; + int (*leq)(void *frame, DictKey key1, DictKey key2); +}; + +#endif diff --git a/Dependencies/GLU/geom.c b/Dependencies/GLU/geom.c new file mode 100644 index 0000000..7d3b8d8 --- /dev/null +++ b/Dependencies/GLU/geom.c @@ -0,0 +1,264 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "gluos.h" +#include +#include "mesh.h" +#include "geom.h" + +int __gl_vertLeq( GLUvertex *u, GLUvertex *v ) +{ + /* Returns TRUE if u is lexicographically <= v. */ + + return VertLeq( u, v ); +} + +GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ) +{ + /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w), + * evaluates the t-coord of the edge uw at the s-coord of the vertex v. + * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v. + * If uw is vertical (and thus passes thru v), the result is zero. + * + * The calculation is extremely accurate and stable, even when v + * is very close to u or w. In particular if we set v->t = 0 and + * let r be the negated result (this evaluates (uw)(v->s)), then + * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t). + */ + GLdouble gapL, gapR; + + assert( VertLeq( u, v ) && VertLeq( v, w )); + + gapL = v->s - u->s; + gapR = w->s - v->s; + + if( gapL + gapR > 0 ) { + if( gapL < gapR ) { + return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR)); + } else { + return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR)); + } + } + /* vertical line */ + return 0; +} + +GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ) +{ + /* Returns a number whose sign matches EdgeEval(u,v,w) but which + * is cheaper to evaluate. Returns > 0, == 0 , or < 0 + * as v is above, on, or below the edge uw. + */ + GLdouble gapL, gapR; + + assert( VertLeq( u, v ) && VertLeq( v, w )); + + gapL = v->s - u->s; + gapR = w->s - v->s; + + if( gapL + gapR > 0 ) { + return (v->t - w->t) * gapL + (v->t - u->t) * gapR; + } + /* vertical line */ + return 0; +} + + +/*********************************************************************** + * Define versions of EdgeSign, EdgeEval with s and t transposed. + */ + +GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ) +{ + /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w), + * evaluates the t-coord of the edge uw at the s-coord of the vertex v. + * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v. + * If uw is vertical (and thus passes thru v), the result is zero. + * + * The calculation is extremely accurate and stable, even when v + * is very close to u or w. In particular if we set v->s = 0 and + * let r be the negated result (this evaluates (uw)(v->t)), then + * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s). + */ + GLdouble gapL, gapR; + + assert( TransLeq( u, v ) && TransLeq( v, w )); + + gapL = v->t - u->t; + gapR = w->t - v->t; + + if( gapL + gapR > 0 ) { + if( gapL < gapR ) { + return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR)); + } else { + return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR)); + } + } + /* vertical line */ + return 0; +} + +GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ) +{ + /* Returns a number whose sign matches TransEval(u,v,w) but which + * is cheaper to evaluate. Returns > 0, == 0 , or < 0 + * as v is above, on, or below the edge uw. + */ + GLdouble gapL, gapR; + + assert( TransLeq( u, v ) && TransLeq( v, w )); + + gapL = v->t - u->t; + gapR = w->t - v->t; + + if( gapL + gapR > 0 ) { + return (v->s - w->s) * gapL + (v->s - u->s) * gapR; + } + /* vertical line */ + return 0; +} + + +int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w ) +{ + /* For almost-degenerate situations, the results are not reliable. + * Unless the floating-point arithmetic can be performed without + * rounding errors, *any* implementation will give incorrect results + * on some degenerate inputs, so the client must have some way to + * handle this situation. + */ + return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0; +} + +/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b), + * or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces + * this in the rare case that one argument is slightly negative. + * The implementation is extremely stable numerically. + * In particular it guarantees that the result r satisfies + * MIN(x,y) <= r <= MAX(x,y), and the results are very accurate + * even when a and b differ greatly in magnitude. + */ +#define RealInterpolate(a,x,b,y) \ + (a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \ + ((a <= b) ? ((b == 0) ? ((x+y) / 2) \ + : (x + (y-x) * (a/(a+b)))) \ + : (y + (x-y) * (b/(a+b))))) + +#ifndef FOR_TRITE_TEST_PROGRAM +#define Interpolate(a,x,b,y) RealInterpolate(a,x,b,y) +#else + +/* Claim: the ONLY property the sweep algorithm relies on is that + * MIN(x,y) <= r <= MAX(x,y). This is a nasty way to test that. + */ +#include +extern int RandomInterpolate; + +GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y) +{ +printf("*********************%d\n",RandomInterpolate); + if( RandomInterpolate ) { + a = 1.2 * drand48() - 0.1; + a = (a < 0) ? 0 : ((a > 1) ? 1 : a); + b = 1.0 - a; + } + return RealInterpolate(a,x,b,y); +} + +#endif + +#define Swap(a,b) if (1) { GLUvertex *t = a; a = b; b = t; } else + +void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1, + GLUvertex *o2, GLUvertex *d2, + GLUvertex *v ) +/* Given edges (o1,d1) and (o2,d2), compute their point of intersection. + * The computed point is guaranteed to lie in the intersection of the + * bounding rectangles defined by each edge. + */ +{ + GLdouble z1, z2; + + /* This is certainly not the most efficient way to find the intersection + * of two line segments, but it is very numerically stable. + * + * Strategy: find the two middle vertices in the VertLeq ordering, + * and interpolate the intersection s-value from these. Then repeat + * using the TransLeq ordering to find the intersection t-value. + */ + + if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); } + if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); } + if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); } + + if( ! VertLeq( o2, d1 )) { + /* Technically, no intersection -- do our best */ + v->s = (o2->s + d1->s) / 2; + } else if( VertLeq( d1, d2 )) { + /* Interpolate between o2 and d1 */ + z1 = EdgeEval( o1, o2, d1 ); + z2 = EdgeEval( o2, d1, d2 ); + if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } + v->s = Interpolate( z1, o2->s, z2, d1->s ); + } else { + /* Interpolate between o2 and d2 */ + z1 = EdgeSign( o1, o2, d1 ); + z2 = -EdgeSign( o1, d2, d1 ); + if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } + v->s = Interpolate( z1, o2->s, z2, d2->s ); + } + + /* Now repeat the process for t */ + + if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); } + if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); } + if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); } + + if( ! TransLeq( o2, d1 )) { + /* Technically, no intersection -- do our best */ + v->t = (o2->t + d1->t) / 2; + } else if( TransLeq( d1, d2 )) { + /* Interpolate between o2 and d1 */ + z1 = TransEval( o1, o2, d1 ); + z2 = TransEval( o2, d1, d2 ); + if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } + v->t = Interpolate( z1, o2->t, z2, d1->t ); + } else { + /* Interpolate between o2 and d2 */ + z1 = TransSign( o1, o2, d1 ); + z2 = -TransSign( o1, d2, d1 ); + if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } + v->t = Interpolate( z1, o2->t, z2, d2->t ); + } +} diff --git a/Dependencies/GLU/geom.h b/Dependencies/GLU/geom.h new file mode 100644 index 0000000..5cb76c7 --- /dev/null +++ b/Dependencies/GLU/geom.h @@ -0,0 +1,84 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __geom_h_ +#define __geom_h_ + +#include "mesh.h" + +#ifdef NO_BRANCH_CONDITIONS +/* MIPS architecture has special instructions to evaluate boolean + * conditions -- more efficient than branching, IF you can get the + * compiler to generate the right instructions (SGI compiler doesn't) + */ +#define VertEq(u,v) (((u)->s == (v)->s) & ((u)->t == (v)->t)) +#define VertLeq(u,v) (((u)->s < (v)->s) | \ + ((u)->s == (v)->s & (u)->t <= (v)->t)) +#else +#define VertEq(u,v) ((u)->s == (v)->s && (u)->t == (v)->t) +#define VertLeq(u,v) (((u)->s < (v)->s) || \ + ((u)->s == (v)->s && (u)->t <= (v)->t)) +#endif + +#define EdgeEval(u,v,w) __gl_edgeEval(u,v,w) +#define EdgeSign(u,v,w) __gl_edgeSign(u,v,w) + +/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */ + +#define TransLeq(u,v) (((u)->t < (v)->t) || \ + ((u)->t == (v)->t && (u)->s <= (v)->s)) +#define TransEval(u,v,w) __gl_transEval(u,v,w) +#define TransSign(u,v,w) __gl_transSign(u,v,w) + + +#define EdgeGoesLeft(e) VertLeq( (e)->Dst, (e)->Org ) +#define EdgeGoesRight(e) VertLeq( (e)->Org, (e)->Dst ) + +#undef ABS +#define ABS(x) ((x) < 0 ? -(x) : (x)) +#define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t)) + +#define VertCCW(u,v,w) __gl_vertCCW(u,v,w) + +int __gl_vertLeq( GLUvertex *u, GLUvertex *v ); +GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ); +GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ); +GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ); +GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ); +int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w ); +void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1, + GLUvertex *o2, GLUvertex *d2, + GLUvertex *v ); + +#endif diff --git a/Dependencies/GLU/gluos.h b/Dependencies/GLU/gluos.h new file mode 100644 index 0000000..8eaa7a1 --- /dev/null +++ b/Dependencies/GLU/gluos.h @@ -0,0 +1,72 @@ +/* +** gluos.h - operating system dependencies for GLU +** +*/ +#ifdef __VMS +#ifdef __cplusplus +#pragma message disable nocordel +#pragma message disable codeunreachable +#pragma message disable codcauunr +#endif +#endif + +#ifdef __WATCOMC__ +/* Disable *lots* of warnings to get a clean build. I can't be bothered fixing the + * code at the moment, as it is pretty ugly. + */ +#pragma warning 7 10 +#pragma warning 13 10 +#pragma warning 14 10 +#pragma warning 367 10 +#pragma warning 379 10 +#pragma warning 726 10 +#pragma warning 836 10 +#endif + +#ifdef BUILD_FOR_SNAP + +#include +#include +#include + +#elif defined(_WIN32) + +#include /* For _MAX_PATH definition */ +#include +#include + +#define WIN32_LEAN_AND_MEAN +#define NOGDI +#define NOIME +#define NOMINMAX + +#define _WIN32_WINNT 0x0400 +#ifndef STRICT + #define STRICT 1 +#endif + +#include + +/* Disable warnings */ +#pragma warning(disable : 4101) +#pragma warning(disable : 4244) +#pragma warning(disable : 4761) + +#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1300 +#pragma comment(linker, "/OPT:NOWIN98") +#endif + +#elif defined(__OS2__) + +#include +#include +#include +#define WINGDIAPI + +#else + +/* Disable Microsoft-specific keywords */ +#define GLAPIENTRY +#define WINGDIAPI + +#endif diff --git a/Dependencies/GLU/memalloc.c b/Dependencies/GLU/memalloc.c new file mode 100644 index 0000000..81879ef --- /dev/null +++ b/Dependencies/GLU/memalloc.c @@ -0,0 +1,55 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "memalloc.h" +#include "string.h" + +int __gl_memInit( size_t maxFast ) +{ +#ifndef NO_MALLOPT +/* mallopt( M_MXFAST, maxFast );*/ +#ifdef MEMORY_DEBUG + mallopt( M_DEBUG, 1 ); +#endif +#endif + return 1; +} + +#ifdef MEMORY_DEBUG +void *__gl_memAlloc( size_t n ) +{ + return memset( malloc( n ), 0xa5, n ); +} +#endif + diff --git a/Dependencies/GLU/memalloc.h b/Dependencies/GLU/memalloc.h new file mode 100644 index 0000000..c2f969b --- /dev/null +++ b/Dependencies/GLU/memalloc.h @@ -0,0 +1,54 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __memalloc_simple_h_ +#define __memalloc_simple_h_ + +#include + +#define memRealloc realloc +#define memFree free + +#define memInit __gl_memInit +/*extern void __gl_memInit( size_t );*/ +extern int __gl_memInit( size_t ); + +#ifndef MEMORY_DEBUG +#define memAlloc malloc +#else +#define memAlloc __gl_memAlloc +extern void * __gl_memAlloc( size_t ); +#endif + +#endif diff --git a/Dependencies/GLU/mesh.c b/Dependencies/GLU/mesh.c new file mode 100644 index 0000000..ae861f8 --- /dev/null +++ b/Dependencies/GLU/mesh.c @@ -0,0 +1,789 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "gluos.h" +#include +#include +#include "mesh.h" +#include "memalloc.h" + +#define TRUE 1 +#define FALSE 0 + +static GLUvertex *allocVertex() +{ + return (GLUvertex *)memAlloc( sizeof( GLUvertex )); +} + +static GLUface *allocFace() +{ + return (GLUface *)memAlloc( sizeof( GLUface )); +} + +/************************ Utility Routines ************************/ + +/* Allocate and free half-edges in pairs for efficiency. + * The *only* place that should use this fact is allocation/free. + */ +typedef struct { GLUhalfEdge e, eSym; } EdgePair; + +/* MakeEdge creates a new pair of half-edges which form their own loop. + * No vertex or face structures are allocated, but these must be assigned + * before the current edge operation is completed. + */ +static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext ) +{ + GLUhalfEdge *e; + GLUhalfEdge *eSym; + GLUhalfEdge *ePrev; + EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair )); + if (pair == NULL) return NULL; + + e = &pair->e; + eSym = &pair->eSym; + + /* Make sure eNext points to the first edge of the edge pair */ + if( eNext->Sym < eNext ) { eNext = eNext->Sym; } + + /* Insert in circular doubly-linked list before eNext. + * Note that the prev pointer is stored in Sym->next. + */ + ePrev = eNext->Sym->next; + eSym->next = ePrev; + ePrev->Sym->next = e; + e->next = eNext; + eNext->Sym->next = eSym; + + e->Sym = eSym; + e->Onext = e; + e->Lnext = eSym; + e->Org = NULL; + e->Lface = NULL; + e->winding = 0; + e->activeRegion = NULL; + + eSym->Sym = e; + eSym->Onext = eSym; + eSym->Lnext = e; + eSym->Org = NULL; + eSym->Lface = NULL; + eSym->winding = 0; + eSym->activeRegion = NULL; + + return e; +} + +/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the + * CS348a notes (see mesh.h). Basically it modifies the mesh so that + * a->Onext and b->Onext are exchanged. This can have various effects + * depending on whether a and b belong to different face or vertex rings. + * For more explanation see __gl_meshSplice() below. + */ +static void Splice( GLUhalfEdge *a, GLUhalfEdge *b ) +{ + GLUhalfEdge *aOnext = a->Onext; + GLUhalfEdge *bOnext = b->Onext; + + aOnext->Sym->Lnext = b; + bOnext->Sym->Lnext = a; + a->Onext = bOnext; + b->Onext = aOnext; +} + +/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the + * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives + * a place to insert the new vertex in the global vertex list. We insert + * the new vertex *before* vNext so that algorithms which walk the vertex + * list will not see the newly created vertices. + */ +static void MakeVertex( GLUvertex *newVertex, + GLUhalfEdge *eOrig, GLUvertex *vNext ) +{ + GLUhalfEdge *e; + GLUvertex *vPrev; + GLUvertex *vNew = newVertex; + + assert(vNew != NULL); + + /* insert in circular doubly-linked list before vNext */ + vPrev = vNext->prev; + vNew->prev = vPrev; + vPrev->next = vNew; + vNew->next = vNext; + vNext->prev = vNew; + + vNew->anEdge = eOrig; + vNew->data = NULL; + /* leave coords, s, t undefined */ + + /* fix other edges on this vertex loop */ + e = eOrig; + do { + e->Org = vNew; + e = e->Onext; + } while( e != eOrig ); +} + +/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left + * face of all edges in the face loop to which eOrig belongs. "fNext" gives + * a place to insert the new face in the global face list. We insert + * the new face *before* fNext so that algorithms which walk the face + * list will not see the newly created faces. + */ +static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext ) +{ + GLUhalfEdge *e; + GLUface *fPrev; + GLUface *fNew = newFace; + + assert(fNew != NULL); + + /* insert in circular doubly-linked list before fNext */ + fPrev = fNext->prev; + fNew->prev = fPrev; + fPrev->next = fNew; + fNew->next = fNext; + fNext->prev = fNew; + + fNew->anEdge = eOrig; + fNew->data = NULL; + fNew->trail = NULL; + fNew->marked = FALSE; + + /* The new face is marked "inside" if the old one was. This is a + * convenience for the common case where a face has been split in two. + */ + fNew->inside = fNext->inside; + + /* fix other edges on this face loop */ + e = eOrig; + do { + e->Lface = fNew; + e = e->Lnext; + } while( e != eOrig ); +} + +/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym), + * and removes from the global edge list. + */ +static void KillEdge( GLUhalfEdge *eDel ) +{ + GLUhalfEdge *ePrev, *eNext; + + /* Half-edges are allocated in pairs, see EdgePair above */ + if( eDel->Sym < eDel ) { eDel = eDel->Sym; } + + /* delete from circular doubly-linked list */ + eNext = eDel->next; + ePrev = eDel->Sym->next; + eNext->Sym->next = ePrev; + ePrev->Sym->next = eNext; + + memFree( eDel ); +} + + +/* KillVertex( vDel ) destroys a vertex and removes it from the global + * vertex list. It updates the vertex loop to point to a given new vertex. + */ +static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg ) +{ + GLUhalfEdge *e, *eStart = vDel->anEdge; + GLUvertex *vPrev, *vNext; + + /* change the origin of all affected edges */ + e = eStart; + do { + e->Org = newOrg; + e = e->Onext; + } while( e != eStart ); + + /* delete from circular doubly-linked list */ + vPrev = vDel->prev; + vNext = vDel->next; + vNext->prev = vPrev; + vPrev->next = vNext; + + memFree( vDel ); +} + +/* KillFace( fDel ) destroys a face and removes it from the global face + * list. It updates the face loop to point to a given new face. + */ +static void KillFace( GLUface *fDel, GLUface *newLface ) +{ + GLUhalfEdge *e, *eStart = fDel->anEdge; + GLUface *fPrev, *fNext; + + /* change the left face of all affected edges */ + e = eStart; + do { + e->Lface = newLface; + e = e->Lnext; + } while( e != eStart ); + + /* delete from circular doubly-linked list */ + fPrev = fDel->prev; + fNext = fDel->next; + fNext->prev = fPrev; + fPrev->next = fNext; + + memFree( fDel ); +} + + +/****************** Basic Edge Operations **********************/ + +/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face). + * The loop consists of the two new half-edges. + */ +GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh ) +{ + GLUvertex *newVertex1= allocVertex(); + GLUvertex *newVertex2= allocVertex(); + GLUface *newFace= allocFace(); + GLUhalfEdge *e; + + /* if any one is null then all get freed */ + if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) { + if (newVertex1 != NULL) memFree(newVertex1); + if (newVertex2 != NULL) memFree(newVertex2); + if (newFace != NULL) memFree(newFace); + return NULL; + } + + e = MakeEdge( &mesh->eHead ); + if (e == NULL) return NULL; + + MakeVertex( newVertex1, e, &mesh->vHead ); + MakeVertex( newVertex2, e->Sym, &mesh->vHead ); + MakeFace( newFace, e, &mesh->fHead ); + return e; +} + + +/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the + * mesh connectivity and topology. It changes the mesh so that + * eOrg->Onext <- OLD( eDst->Onext ) + * eDst->Onext <- OLD( eOrg->Onext ) + * where OLD(...) means the value before the meshSplice operation. + * + * This can have two effects on the vertex structure: + * - if eOrg->Org != eDst->Org, the two vertices are merged together + * - if eOrg->Org == eDst->Org, the origin is split into two vertices + * In both cases, eDst->Org is changed and eOrg->Org is untouched. + * + * Similarly (and independently) for the face structure, + * - if eOrg->Lface == eDst->Lface, one loop is split into two + * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one + * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. + * + * Some special cases: + * If eDst == eOrg, the operation has no effect. + * If eDst == eOrg->Lnext, the new face will have a single edge. + * If eDst == eOrg->Lprev, the old face will have a single edge. + * If eDst == eOrg->Onext, the new vertex will have a single edge. + * If eDst == eOrg->Oprev, the old vertex will have a single edge. + */ +int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ) +{ + int joiningLoops = FALSE; + int joiningVertices = FALSE; + + if( eOrg == eDst ) return 1; + + if( eDst->Org != eOrg->Org ) { + /* We are merging two disjoint vertices -- destroy eDst->Org */ + joiningVertices = TRUE; + KillVertex( eDst->Org, eOrg->Org ); + } + if( eDst->Lface != eOrg->Lface ) { + /* We are connecting two disjoint loops -- destroy eDst->Lface */ + joiningLoops = TRUE; + KillFace( eDst->Lface, eOrg->Lface ); + } + + /* Change the edge structure */ + Splice( eDst, eOrg ); + + if( ! joiningVertices ) { + GLUvertex *newVertex= allocVertex(); + if (newVertex == NULL) return 0; + + /* We split one vertex into two -- the new vertex is eDst->Org. + * Make sure the old vertex points to a valid half-edge. + */ + MakeVertex( newVertex, eDst, eOrg->Org ); + eOrg->Org->anEdge = eOrg; + } + if( ! joiningLoops ) { + GLUface *newFace= allocFace(); + if (newFace == NULL) return 0; + + /* We split one loop into two -- the new loop is eDst->Lface. + * Make sure the old face points to a valid half-edge. + */ + MakeFace( newFace, eDst, eOrg->Lface ); + eOrg->Lface->anEdge = eOrg; + } + + return 1; +} + + +/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases: + * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop + * eDel->Lface is deleted. Otherwise, we are splitting one loop into two; + * the newly created loop will contain eDel->Dst. If the deletion of eDel + * would create isolated vertices, those are deleted as well. + * + * This function could be implemented as two calls to __gl_meshSplice + * plus a few calls to memFree, but this would allocate and delete + * unnecessary vertices and faces. + */ +int __gl_meshDelete( GLUhalfEdge *eDel ) +{ + GLUhalfEdge *eDelSym = eDel->Sym; + int joiningLoops = FALSE; + + /* First step: disconnect the origin vertex eDel->Org. We make all + * changes to get a consistent mesh in this "intermediate" state. + */ + if( eDel->Lface != eDel->Rface ) { + /* We are joining two loops into one -- remove the left face */ + joiningLoops = TRUE; + KillFace( eDel->Lface, eDel->Rface ); + } + + if( eDel->Onext == eDel ) { + KillVertex( eDel->Org, NULL ); + } else { + /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */ + eDel->Rface->anEdge = eDel->Oprev; + eDel->Org->anEdge = eDel->Onext; + + Splice( eDel, eDel->Oprev ); + if( ! joiningLoops ) { + GLUface *newFace= allocFace(); + if (newFace == NULL) return 0; + + /* We are splitting one loop into two -- create a new loop for eDel. */ + MakeFace( newFace, eDel, eDel->Lface ); + } + } + + /* Claim: the mesh is now in a consistent state, except that eDel->Org + * may have been deleted. Now we disconnect eDel->Dst. + */ + if( eDelSym->Onext == eDelSym ) { + KillVertex( eDelSym->Org, NULL ); + KillFace( eDelSym->Lface, NULL ); + } else { + /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */ + eDel->Lface->anEdge = eDelSym->Oprev; + eDelSym->Org->anEdge = eDelSym->Onext; + Splice( eDelSym, eDelSym->Oprev ); + } + + /* Any isolated vertices or faces have already been freed. */ + KillEdge( eDel ); + + return 1; +} + + +/******************** Other Edge Operations **********************/ + +/* All these routines can be implemented with the basic edge + * operations above. They are provided for convenience and efficiency. + */ + + +/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that + * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. + * eOrg and eNew will have the same left face. + */ +GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg ) +{ + GLUhalfEdge *eNewSym; + GLUhalfEdge *eNew = MakeEdge( eOrg ); + if (eNew == NULL) return NULL; + + eNewSym = eNew->Sym; + + /* Connect the new edge appropriately */ + Splice( eNew, eOrg->Lnext ); + + /* Set the vertex and face information */ + eNew->Org = eOrg->Dst; + { + GLUvertex *newVertex= allocVertex(); + if (newVertex == NULL) return NULL; + + MakeVertex( newVertex, eNewSym, eNew->Org ); + } + eNew->Lface = eNewSym->Lface = eOrg->Lface; + + return eNew; +} + + +/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew, + * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org. + * eOrg and eNew will have the same left face. + */ +GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg ) +{ + GLUhalfEdge *eNew; + GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg ); + if (tempHalfEdge == NULL) return NULL; + + eNew = tempHalfEdge->Sym; + + /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */ + Splice( eOrg->Sym, eOrg->Sym->Oprev ); + Splice( eOrg->Sym, eNew ); + + /* Set the vertex and face information */ + eOrg->Dst = eNew->Org; + eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */ + eNew->Rface = eOrg->Rface; + eNew->winding = eOrg->winding; /* copy old winding information */ + eNew->Sym->winding = eOrg->Sym->winding; + + return eNew; +} + + +/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst + * to eDst->Org, and returns the corresponding half-edge eNew. + * If eOrg->Lface == eDst->Lface, this splits one loop into two, + * and the newly created loop is eNew->Lface. Otherwise, two disjoint + * loops are merged into one, and the loop eDst->Lface is destroyed. + * + * If (eOrg == eDst), the new face will have only two edges. + * If (eOrg->Lnext == eDst), the old face is reduced to a single edge. + * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges. + */ +GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ) +{ + GLUhalfEdge *eNewSym; + int joiningLoops = FALSE; + GLUhalfEdge *eNew = MakeEdge( eOrg ); + if (eNew == NULL) return NULL; + + eNewSym = eNew->Sym; + + if( eDst->Lface != eOrg->Lface ) { + /* We are connecting two disjoint loops -- destroy eDst->Lface */ + joiningLoops = TRUE; + KillFace( eDst->Lface, eOrg->Lface ); + } + + /* Connect the new edge appropriately */ + Splice( eNew, eOrg->Lnext ); + Splice( eNewSym, eDst ); + + /* Set the vertex and face information */ + eNew->Org = eOrg->Dst; + eNewSym->Org = eDst->Org; + eNew->Lface = eNewSym->Lface = eOrg->Lface; + + /* Make sure the old face points to a valid half-edge */ + eOrg->Lface->anEdge = eNewSym; + + if( ! joiningLoops ) { + GLUface *newFace= allocFace(); + if (newFace == NULL) return NULL; + + /* We split one loop into two -- the new loop is eNew->Lface */ + MakeFace( newFace, eNew, eOrg->Lface ); + } + return eNew; +} + + +/******************** Other Operations **********************/ + +/* __gl_meshZapFace( fZap ) destroys a face and removes it from the + * global face list. All edges of fZap will have a NULL pointer as their + * left face. Any edges which also have a NULL pointer as their right face + * are deleted entirely (along with any isolated vertices this produces). + * An entire mesh can be deleted by zapping its faces, one at a time, + * in any order. Zapped faces cannot be used in further mesh operations! + */ +void __gl_meshZapFace( GLUface *fZap ) +{ + GLUhalfEdge *eStart = fZap->anEdge; + GLUhalfEdge *e, *eNext, *eSym; + GLUface *fPrev, *fNext; + + /* walk around face, deleting edges whose right face is also NULL */ + eNext = eStart->Lnext; + do { + e = eNext; + eNext = e->Lnext; + + e->Lface = NULL; + if( e->Rface == NULL ) { + /* delete the edge -- see __gl_MeshDelete above */ + + if( e->Onext == e ) { + KillVertex( e->Org, NULL ); + } else { + /* Make sure that e->Org points to a valid half-edge */ + e->Org->anEdge = e->Onext; + Splice( e, e->Oprev ); + } + eSym = e->Sym; + if( eSym->Onext == eSym ) { + KillVertex( eSym->Org, NULL ); + } else { + /* Make sure that eSym->Org points to a valid half-edge */ + eSym->Org->anEdge = eSym->Onext; + Splice( eSym, eSym->Oprev ); + } + KillEdge( e ); + } + } while( e != eStart ); + + /* delete from circular doubly-linked list */ + fPrev = fZap->prev; + fNext = fZap->next; + fNext->prev = fPrev; + fPrev->next = fNext; + + memFree( fZap ); +} + + +/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices, + * and no loops (what we usually call a "face"). + */ +GLUmesh *__gl_meshNewMesh( void ) +{ + GLUvertex *v; + GLUface *f; + GLUhalfEdge *e; + GLUhalfEdge *eSym; + GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh )); + if (mesh == NULL) { + return NULL; + } + + v = &mesh->vHead; + f = &mesh->fHead; + e = &mesh->eHead; + eSym = &mesh->eHeadSym; + + v->next = v->prev = v; + v->anEdge = NULL; + v->data = NULL; + + f->next = f->prev = f; + f->anEdge = NULL; + f->data = NULL; + f->trail = NULL; + f->marked = FALSE; + f->inside = FALSE; + + e->next = e; + e->Sym = eSym; + e->Onext = NULL; + e->Lnext = NULL; + e->Org = NULL; + e->Lface = NULL; + e->winding = 0; + e->activeRegion = NULL; + + eSym->next = eSym; + eSym->Sym = e; + eSym->Onext = NULL; + eSym->Lnext = NULL; + eSym->Org = NULL; + eSym->Lface = NULL; + eSym->winding = 0; + eSym->activeRegion = NULL; + + return mesh; +} + + +/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in + * both meshes, and returns the new mesh (the old meshes are destroyed). + */ +GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 ) +{ + GLUface *f1 = &mesh1->fHead; + GLUvertex *v1 = &mesh1->vHead; + GLUhalfEdge *e1 = &mesh1->eHead; + GLUface *f2 = &mesh2->fHead; + GLUvertex *v2 = &mesh2->vHead; + GLUhalfEdge *e2 = &mesh2->eHead; + + /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */ + if( f2->next != f2 ) { + f1->prev->next = f2->next; + f2->next->prev = f1->prev; + f2->prev->next = f1; + f1->prev = f2->prev; + } + + if( v2->next != v2 ) { + v1->prev->next = v2->next; + v2->next->prev = v1->prev; + v2->prev->next = v1; + v1->prev = v2->prev; + } + + if( e2->next != e2 ) { + e1->Sym->next->Sym->next = e2->next; + e2->next->Sym->next = e1->Sym->next; + e2->Sym->next->Sym->next = e1; + e1->Sym->next = e2->Sym->next; + } + + memFree( mesh2 ); + return mesh1; +} + + +#ifdef DELETE_BY_ZAPPING + +/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. + */ +void __gl_meshDeleteMesh( GLUmesh *mesh ) +{ + GLUface *fHead = &mesh->fHead; + + while( fHead->next != fHead ) { + __gl_meshZapFace( fHead->next ); + } + assert( mesh->vHead.next == &mesh->vHead ); + + memFree( mesh ); +} + +#else + +/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. + */ +void __gl_meshDeleteMesh( GLUmesh *mesh ) +{ + GLUface *f, *fNext; + GLUvertex *v, *vNext; + GLUhalfEdge *e, *eNext; + + for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) { + fNext = f->next; + memFree( f ); + } + + for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) { + vNext = v->next; + memFree( v ); + } + + for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) { + /* One call frees both e and e->Sym (see EdgePair above) */ + eNext = e->next; + memFree( e ); + } + + memFree( mesh ); +} + +#endif + +#ifndef NDEBUG + +/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency. + */ +void __gl_meshCheckMesh( GLUmesh *mesh ) +{ + GLUface *fHead = &mesh->fHead; + GLUvertex *vHead = &mesh->vHead; + GLUhalfEdge *eHead = &mesh->eHead; + GLUface *f, *fPrev; + GLUvertex *v, *vPrev; + GLUhalfEdge *e, *ePrev; + + fPrev = fHead; + for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) { + assert( f->prev == fPrev ); + e = f->anEdge; + do { + assert( e->Sym != e ); + assert( e->Sym->Sym == e ); + assert( e->Lnext->Onext->Sym == e ); + assert( e->Onext->Sym->Lnext == e ); + assert( e->Lface == f ); + e = e->Lnext; + } while( e != f->anEdge ); + } + assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL ); + + vPrev = vHead; + for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) { + assert( v->prev == vPrev ); + e = v->anEdge; + do { + assert( e->Sym != e ); + assert( e->Sym->Sym == e ); + assert( e->Lnext->Onext->Sym == e ); + assert( e->Onext->Sym->Lnext == e ); + assert( e->Org == v ); + e = e->Onext; + } while( e != v->anEdge ); + } + assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL ); + + ePrev = eHead; + for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) { + assert( e->Sym->next == ePrev->Sym ); + assert( e->Sym != e ); + assert( e->Sym->Sym == e ); + assert( e->Org != NULL ); + assert( e->Dst != NULL ); + assert( e->Lnext->Onext->Sym == e ); + assert( e->Onext->Sym->Lnext == e ); + } + assert( e->Sym->next == ePrev->Sym + && e->Sym == &mesh->eHeadSym + && e->Sym->Sym == e + && e->Org == NULL && e->Dst == NULL + && e->Lface == NULL && e->Rface == NULL ); +} + +#endif diff --git a/Dependencies/GLU/mesh.h b/Dependencies/GLU/mesh.h new file mode 100644 index 0000000..690c5f2 --- /dev/null +++ b/Dependencies/GLU/mesh.h @@ -0,0 +1,266 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __mesh_h_ +#define __mesh_h_ + +#include + +typedef struct GLUmesh GLUmesh; + +typedef struct GLUvertex GLUvertex; +typedef struct GLUface GLUface; +typedef struct GLUhalfEdge GLUhalfEdge; + +typedef struct ActiveRegion ActiveRegion; /* Internal data */ + +/* The mesh structure is similar in spirit, notation, and operations + * to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives + * for the manipulation of general subdivisions and the computation of + * Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985). + * For a simplified description, see the course notes for CS348a, + * "Mathematical Foundations of Computer Graphics", available at the + * Stanford bookstore (and taught during the fall quarter). + * The implementation also borrows a tiny subset of the graph-based approach + * use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction + * to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988). + * + * The fundamental data structure is the "half-edge". Two half-edges + * go together to make an edge, but they point in opposite directions. + * Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym), + * its origin vertex (Org), the face on its left side (Lface), and the + * adjacent half-edges in the CCW direction around the origin vertex + * (Onext) and around the left face (Lnext). There is also a "next" + * pointer for the global edge list (see below). + * + * The notation used for mesh navigation: + * Sym = the mate of a half-edge (same edge, but opposite direction) + * Onext = edge CCW around origin vertex (keep same origin) + * Dnext = edge CCW around destination vertex (keep same dest) + * Lnext = edge CCW around left face (dest becomes new origin) + * Rnext = edge CCW around right face (origin becomes new dest) + * + * "prev" means to substitute CW for CCW in the definitions above. + * + * The mesh keeps global lists of all vertices, faces, and edges, + * stored as doubly-linked circular lists with a dummy header node. + * The mesh stores pointers to these dummy headers (vHead, fHead, eHead). + * + * The circular edge list is special; since half-edges always occur + * in pairs (e and e->Sym), each half-edge stores a pointer in only + * one direction. Starting at eHead and following the e->next pointers + * will visit each *edge* once (ie. e or e->Sym, but not both). + * e->Sym stores a pointer in the opposite direction, thus it is + * always true that e->Sym->next->Sym->next == e. + * + * Each vertex has a pointer to next and previous vertices in the + * circular list, and a pointer to a half-edge with this vertex as + * the origin (NULL if this is the dummy header). There is also a + * field "data" for client data. + * + * Each face has a pointer to the next and previous faces in the + * circular list, and a pointer to a half-edge with this face as + * the left face (NULL if this is the dummy header). There is also + * a field "data" for client data. + * + * Note that what we call a "face" is really a loop; faces may consist + * of more than one loop (ie. not simply connected), but there is no + * record of this in the data structure. The mesh may consist of + * several disconnected regions, so it may not be possible to visit + * the entire mesh by starting at a half-edge and traversing the edge + * structure. + * + * The mesh does NOT support isolated vertices; a vertex is deleted along + * with its last edge. Similarly when two faces are merged, one of the + * faces is deleted (see __gl_meshDelete below). For mesh operations, + * all face (loop) and vertex pointers must not be NULL. However, once + * mesh manipulation is finished, __gl_MeshZapFace can be used to delete + * faces of the mesh, one at a time. All external faces can be "zapped" + * before the mesh is returned to the client; then a NULL face indicates + * a region which is not part of the output polygon. + */ + +struct GLUvertex { + GLUvertex *next; /* next vertex (never NULL) */ + GLUvertex *prev; /* previous vertex (never NULL) */ + GLUhalfEdge *anEdge; /* a half-edge with this origin */ + void *data; /* client's data */ + + /* Internal data (keep hidden) */ + GLdouble coords[3]; /* vertex location in 3D */ + GLdouble s, t; /* projection onto the sweep plane */ + long pqHandle; /* to allow deletion from priority queue */ +}; + +struct GLUface { + GLUface *next; /* next face (never NULL) */ + GLUface *prev; /* previous face (never NULL) */ + GLUhalfEdge *anEdge; /* a half edge with this left face */ + void *data; /* room for client's data */ + + /* Internal data (keep hidden) */ + GLUface *trail; /* "stack" for conversion to strips */ + GLboolean marked; /* flag for conversion to strips */ + GLboolean inside; /* this face is in the polygon interior */ +}; + +struct GLUhalfEdge { + GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */ + GLUhalfEdge *Sym; /* same edge, opposite direction */ + GLUhalfEdge *Onext; /* next edge CCW around origin */ + GLUhalfEdge *Lnext; /* next edge CCW around left face */ + GLUvertex *Org; /* origin vertex (Overtex too long) */ + GLUface *Lface; /* left face */ + + /* Internal data (keep hidden) */ + ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */ + int winding; /* change in winding number when crossing + from the right face to the left face */ +}; + +#define Rface Sym->Lface +#define Dst Sym->Org + +#define Oprev Sym->Lnext +#define Lprev Onext->Sym +#define Dprev Lnext->Sym +#define Rprev Sym->Onext +#define Dnext Rprev->Sym /* 3 pointers */ +#define Rnext Oprev->Sym /* 3 pointers */ + + +struct GLUmesh { + GLUvertex vHead; /* dummy header for vertex list */ + GLUface fHead; /* dummy header for face list */ + GLUhalfEdge eHead; /* dummy header for edge list */ + GLUhalfEdge eHeadSym; /* and its symmetric counterpart */ +}; + +/* The mesh operations below have three motivations: completeness, + * convenience, and efficiency. The basic mesh operations are MakeEdge, + * Splice, and Delete. All the other edge operations can be implemented + * in terms of these. The other operations are provided for convenience + * and/or efficiency. + * + * When a face is split or a vertex is added, they are inserted into the + * global list *before* the existing vertex or face (ie. e->Org or e->Lface). + * This makes it easier to process all vertices or faces in the global lists + * without worrying about processing the same data twice. As a convenience, + * when a face is split, the "inside" flag is copied from the old face. + * Other internal data (v->data, v->activeRegion, f->data, f->marked, + * f->trail, e->winding) is set to zero. + * + * ********************** Basic Edge Operations ************************** + * + * __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop. + * The loop (face) consists of the two new half-edges. + * + * __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the + * mesh connectivity and topology. It changes the mesh so that + * eOrg->Onext <- OLD( eDst->Onext ) + * eDst->Onext <- OLD( eOrg->Onext ) + * where OLD(...) means the value before the meshSplice operation. + * + * This can have two effects on the vertex structure: + * - if eOrg->Org != eDst->Org, the two vertices are merged together + * - if eOrg->Org == eDst->Org, the origin is split into two vertices + * In both cases, eDst->Org is changed and eOrg->Org is untouched. + * + * Similarly (and independently) for the face structure, + * - if eOrg->Lface == eDst->Lface, one loop is split into two + * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one + * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. + * + * __gl_meshDelete( eDel ) removes the edge eDel. There are several cases: + * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop + * eDel->Lface is deleted. Otherwise, we are splitting one loop into two; + * the newly created loop will contain eDel->Dst. If the deletion of eDel + * would create isolated vertices, those are deleted as well. + * + * ********************** Other Edge Operations ************************** + * + * __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that + * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. + * eOrg and eNew will have the same left face. + * + * __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew, + * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org. + * eOrg and eNew will have the same left face. + * + * __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst + * to eDst->Org, and returns the corresponding half-edge eNew. + * If eOrg->Lface == eDst->Lface, this splits one loop into two, + * and the newly created loop is eNew->Lface. Otherwise, two disjoint + * loops are merged into one, and the loop eDst->Lface is destroyed. + * + * ************************ Other Operations ***************************** + * + * __gl_meshNewMesh() creates a new mesh with no edges, no vertices, + * and no loops (what we usually call a "face"). + * + * __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in + * both meshes, and returns the new mesh (the old meshes are destroyed). + * + * __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. + * + * __gl_meshZapFace( fZap ) destroys a face and removes it from the + * global face list. All edges of fZap will have a NULL pointer as their + * left face. Any edges which also have a NULL pointer as their right face + * are deleted entirely (along with any isolated vertices this produces). + * An entire mesh can be deleted by zapping its faces, one at a time, + * in any order. Zapped faces cannot be used in further mesh operations! + * + * __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency. + */ + +GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh ); +int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ); +int __gl_meshDelete( GLUhalfEdge *eDel ); + +GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg ); +GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg ); +GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ); + +GLUmesh *__gl_meshNewMesh( void ); +GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 ); +void __gl_meshDeleteMesh( GLUmesh *mesh ); +void __gl_meshZapFace( GLUface *fZap ); + +#ifdef NDEBUG +#define __gl_meshCheckMesh( mesh ) +#else +void __gl_meshCheckMesh( GLUmesh *mesh ); +#endif + +#endif diff --git a/Dependencies/GLU/mipmap.c b/Dependencies/GLU/mipmap.c new file mode 100644 index 0000000..ba84237 --- /dev/null +++ b/Dependencies/GLU/mipmap.c @@ -0,0 +1,8930 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#include "gluos.h" +#include +#include +#include +#include +#include +#include /* UINT_MAX */ +#include + +typedef union { + unsigned char ub[4]; + unsigned short us[2]; + unsigned int ui; + char b[4]; + short s[2]; + int i; + float f; +} Type_Widget; + +/* Pixel storage modes */ +typedef struct { + GLint pack_alignment; + GLint pack_row_length; + GLint pack_skip_rows; + GLint pack_skip_pixels; + GLint pack_lsb_first; + GLint pack_swap_bytes; + GLint pack_skip_images; + GLint pack_image_height; + + GLint unpack_alignment; + GLint unpack_row_length; + GLint unpack_skip_rows; + GLint unpack_skip_pixels; + GLint unpack_lsb_first; + GLint unpack_swap_bytes; + GLint unpack_skip_images; + GLint unpack_image_height; +} PixelStorageModes; + +static int gluBuild1DMipmapLevelsCore(GLenum, GLint, + GLsizei, + GLsizei, + GLenum, GLenum, GLint, GLint, GLint, + const void *); +static int gluBuild2DMipmapLevelsCore(GLenum, GLint, + GLsizei, GLsizei, + GLsizei, GLsizei, + GLenum, GLenum, GLint, GLint, GLint, + const void *); +static int gluBuild3DMipmapLevelsCore(GLenum, GLint, + GLsizei, GLsizei, GLsizei, + GLsizei, GLsizei, GLsizei, + GLenum, GLenum, GLint, GLint, GLint, + const void *); + +/* + * internal function declarations + */ +static GLfloat bytes_per_element(GLenum type); +static GLint elements_per_group(GLenum format, GLenum type); +static GLint is_index(GLenum format); +static GLint image_size(GLint width, GLint height, GLenum format, GLenum type); +static void fill_image(const PixelStorageModes *, + GLint width, GLint height, GLenum format, + GLenum type, GLboolean index_format, + const void *userdata, GLushort *newimage); +static void empty_image(const PixelStorageModes *, + GLint width, GLint height, GLenum format, + GLenum type, GLboolean index_format, + const GLushort *oldimage, void *userdata); +static void scale_internal(GLint components, GLint widthin, GLint heightin, + const GLushort *datain, + GLint widthout, GLint heightout, + GLushort *dataout); + +static void scale_internal_ubyte(GLint components, GLint widthin, + GLint heightin, const GLubyte *datain, + GLint widthout, GLint heightout, + GLubyte *dataout, GLint element_size, + GLint ysize, GLint group_size); +static void scale_internal_byte(GLint components, GLint widthin, + GLint heightin, const GLbyte *datain, + GLint widthout, GLint heightout, + GLbyte *dataout, GLint element_size, + GLint ysize, GLint group_size); +static void scale_internal_ushort(GLint components, GLint widthin, + GLint heightin, const GLushort *datain, + GLint widthout, GLint heightout, + GLushort *dataout, GLint element_size, + GLint ysize, GLint group_size, + GLint myswap_bytes); +static void scale_internal_short(GLint components, GLint widthin, + GLint heightin, const GLshort *datain, + GLint widthout, GLint heightout, + GLshort *dataout, GLint element_size, + GLint ysize, GLint group_size, + GLint myswap_bytes); +static void scale_internal_uint(GLint components, GLint widthin, + GLint heightin, const GLuint *datain, + GLint widthout, GLint heightout, + GLuint *dataout, GLint element_size, + GLint ysize, GLint group_size, + GLint myswap_bytes); +static void scale_internal_int(GLint components, GLint widthin, + GLint heightin, const GLint *datain, + GLint widthout, GLint heightout, + GLint *dataout, GLint element_size, + GLint ysize, GLint group_size, + GLint myswap_bytes); +static void scale_internal_float(GLint components, GLint widthin, + GLint heightin, const GLfloat *datain, + GLint widthout, GLint heightout, + GLfloat *dataout, GLint element_size, + GLint ysize, GLint group_size, + GLint myswap_bytes); + +static int checkMipmapArgs(GLenum, GLenum, GLenum); +static GLboolean legalFormat(GLenum); +static GLboolean legalType(GLenum); +static GLboolean isTypePackedPixel(GLenum); +static GLboolean isLegalFormatForPackedPixelType(GLenum, GLenum); +static GLboolean isLegalLevels(GLint, GLint, GLint, GLint); +static void closestFit(GLenum, GLint, GLint, GLint, GLenum, GLenum, + GLint *, GLint *); + +/* all extract/shove routines must return double to handle unsigned ints */ +static GLdouble extractUbyte(int, const void *); +static void shoveUbyte(GLdouble, int, void *); +static GLdouble extractSbyte(int, const void *); +static void shoveSbyte(GLdouble, int, void *); +static GLdouble extractUshort(int, const void *); +static void shoveUshort(GLdouble, int, void *); +static GLdouble extractSshort(int, const void *); +static void shoveSshort(GLdouble, int, void *); +static GLdouble extractUint(int, const void *); +static void shoveUint(GLdouble, int, void *); +static GLdouble extractSint(int, const void *); +static void shoveSint(GLdouble, int, void *); +static GLdouble extractFloat(int, const void *); +static void shoveFloat(GLdouble, int, void *); +static void halveImageSlice(int, GLdouble (*)(int, const void *), + void (*)(GLdouble, int, void *), + GLint, GLint, GLint, + const void *, void *, + GLint, GLint, GLint, GLint, GLint); +static void halveImage3D(int, GLdouble (*)(int, const void *), + void (*)(GLdouble, int, void *), + GLint, GLint, GLint, + const void *, void *, + GLint, GLint, GLint, GLint, GLint); + +/* packedpixel type scale routines */ +static void extract332(int,const void *, GLfloat []); +static void shove332(const GLfloat [],int ,void *); +static void extract233rev(int,const void *, GLfloat []); +static void shove233rev(const GLfloat [],int ,void *); +static void extract565(int,const void *, GLfloat []); +static void shove565(const GLfloat [],int ,void *); +static void extract565rev(int,const void *, GLfloat []); +static void shove565rev(const GLfloat [],int ,void *); +static void extract4444(int,const void *, GLfloat []); +static void shove4444(const GLfloat [],int ,void *); +static void extract4444rev(int,const void *, GLfloat []); +static void shove4444rev(const GLfloat [],int ,void *); +static void extract5551(int,const void *, GLfloat []); +static void shove5551(const GLfloat [],int ,void *); +static void extract1555rev(int,const void *, GLfloat []); +static void shove1555rev(const GLfloat [],int ,void *); +static void extract8888(int,const void *, GLfloat []); +static void shove8888(const GLfloat [],int ,void *); +static void extract8888rev(int,const void *, GLfloat []); +static void shove8888rev(const GLfloat [],int ,void *); +static void extract1010102(int,const void *, GLfloat []); +static void shove1010102(const GLfloat [],int ,void *); +static void extract2101010rev(int,const void *, GLfloat []); +static void shove2101010rev(const GLfloat [],int ,void *); +static void scaleInternalPackedPixel(int, + void (*)(int, const void *,GLfloat []), + void (*)(const GLfloat [],int, void *), + GLint,GLint, const void *, + GLint,GLint,void *,GLint,GLint,GLint); +static void halveImagePackedPixel(int, + void (*)(int, const void *,GLfloat []), + void (*)(const GLfloat [],int, void *), + GLint, GLint, const void *, + void *, GLint, GLint, GLint); +static void halve1DimagePackedPixel(int, + void (*)(int, const void *,GLfloat []), + void (*)(const GLfloat [],int, void *), + GLint, GLint, const void *, + void *, GLint, GLint, GLint); + +static void halve1Dimage_ubyte(GLint, GLuint, GLuint,const GLubyte *, + GLubyte *, GLint, GLint, GLint); +static void halve1Dimage_byte(GLint, GLuint, GLuint,const GLbyte *, GLbyte *, + GLint, GLint, GLint); +static void halve1Dimage_ushort(GLint, GLuint, GLuint, const GLushort *, + GLushort *, GLint, GLint, GLint, GLint); +static void halve1Dimage_short(GLint, GLuint, GLuint,const GLshort *, GLshort *, + GLint, GLint, GLint, GLint); +static void halve1Dimage_uint(GLint, GLuint, GLuint, const GLuint *, GLuint *, + GLint, GLint, GLint, GLint); +static void halve1Dimage_int(GLint, GLuint, GLuint, const GLint *, GLint *, + GLint, GLint, GLint, GLint); +static void halve1Dimage_float(GLint, GLuint, GLuint, const GLfloat *, GLfloat *, + GLint, GLint, GLint, GLint); + +static GLint imageSize3D(GLint, GLint, GLint, GLenum,GLenum); +static void fillImage3D(const PixelStorageModes *, GLint, GLint, GLint,GLenum, + GLenum, GLboolean, const void *, GLushort *); +static void emptyImage3D(const PixelStorageModes *, + GLint, GLint, GLint, GLenum, + GLenum, GLboolean, + const GLushort *, void *); +static void scaleInternal3D(GLint, GLint, GLint, GLint, const GLushort *, + GLint, GLint, GLint, GLushort *); + +static void retrieveStoreModes(PixelStorageModes *psm) +{ + glGetIntegerv(GL_UNPACK_ALIGNMENT, &psm->unpack_alignment); + glGetIntegerv(GL_UNPACK_ROW_LENGTH, &psm->unpack_row_length); + glGetIntegerv(GL_UNPACK_SKIP_ROWS, &psm->unpack_skip_rows); + glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &psm->unpack_skip_pixels); + glGetIntegerv(GL_UNPACK_LSB_FIRST, &psm->unpack_lsb_first); + glGetIntegerv(GL_UNPACK_SWAP_BYTES, &psm->unpack_swap_bytes); + + glGetIntegerv(GL_PACK_ALIGNMENT, &psm->pack_alignment); + glGetIntegerv(GL_PACK_ROW_LENGTH, &psm->pack_row_length); + glGetIntegerv(GL_PACK_SKIP_ROWS, &psm->pack_skip_rows); + glGetIntegerv(GL_PACK_SKIP_PIXELS, &psm->pack_skip_pixels); + glGetIntegerv(GL_PACK_LSB_FIRST, &psm->pack_lsb_first); + glGetIntegerv(GL_PACK_SWAP_BYTES, &psm->pack_swap_bytes); +} + +static void retrieveStoreModes3D(PixelStorageModes *psm) +{ + glGetIntegerv(GL_UNPACK_ALIGNMENT, &psm->unpack_alignment); + glGetIntegerv(GL_UNPACK_ROW_LENGTH, &psm->unpack_row_length); + glGetIntegerv(GL_UNPACK_SKIP_ROWS, &psm->unpack_skip_rows); + glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &psm->unpack_skip_pixels); + glGetIntegerv(GL_UNPACK_LSB_FIRST, &psm->unpack_lsb_first); + glGetIntegerv(GL_UNPACK_SWAP_BYTES, &psm->unpack_swap_bytes); + glGetIntegerv(GL_UNPACK_SKIP_IMAGES, &psm->unpack_skip_images); + glGetIntegerv(GL_UNPACK_IMAGE_HEIGHT, &psm->unpack_image_height); + + glGetIntegerv(GL_PACK_ALIGNMENT, &psm->pack_alignment); + glGetIntegerv(GL_PACK_ROW_LENGTH, &psm->pack_row_length); + glGetIntegerv(GL_PACK_SKIP_ROWS, &psm->pack_skip_rows); + glGetIntegerv(GL_PACK_SKIP_PIXELS, &psm->pack_skip_pixels); + glGetIntegerv(GL_PACK_LSB_FIRST, &psm->pack_lsb_first); + glGetIntegerv(GL_PACK_SWAP_BYTES, &psm->pack_swap_bytes); + glGetIntegerv(GL_PACK_SKIP_IMAGES, &psm->pack_skip_images); + glGetIntegerv(GL_PACK_IMAGE_HEIGHT, &psm->pack_image_height); +} + +static int computeLog(GLuint value) +{ + int i; + + i = 0; + + /* Error! */ + if (value == 0) return -1; + + for (;;) { + if (value & 1) { + /* Error ! */ + if (value != 1) return -1; + return i; + } + value = value >> 1; + i++; + } +} + +/* +** Compute the nearest power of 2 number. This algorithm is a little +** strange, but it works quite well. +*/ +static int nearestPower(GLuint value) +{ + int i; + + i = 1; + + /* Error! */ + if (value == 0) return -1; + + for (;;) { + if (value == 1) { + return i; + } else if (value == 3) { + return i*4; + } + value = value >> 1; + i *= 2; + } +} + +#define __GLU_SWAP_2_BYTES(s)\ +(GLushort)(((GLushort)((const GLubyte*)(s))[1])<<8 | ((const GLubyte*)(s))[0]) + +#define __GLU_SWAP_4_BYTES(s)\ +(GLuint)(((GLuint)((const GLubyte*)(s))[3])<<24 | \ + ((GLuint)((const GLubyte*)(s))[2])<<16 | \ + ((GLuint)((const GLubyte*)(s))[1])<<8 | ((const GLubyte*)(s))[0]) + +static void halveImage(GLint components, GLuint width, GLuint height, + const GLushort *datain, GLushort *dataout) +{ + int i, j, k; + int newwidth, newheight; + int delta; + GLushort *s; + const GLushort *t; + + newwidth = width / 2; + newheight = height / 2; + delta = width * components; + s = dataout; + t = datain; + + /* Piece o' cake! */ + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + s[0] = (t[0] + t[components] + t[delta] + + t[delta+components] + 2) / 4; + s++; t++; + } + t += components; + } + t += delta; + } +} + +static void halveImage_ubyte(GLint components, GLuint width, GLuint height, + const GLubyte *datain, GLubyte *dataout, + GLint element_size, GLint ysize, GLint group_size) +{ + int i, j, k; + int newwidth, newheight; + int padBytes; + GLubyte *s; + const char *t; + + /* handle case where there is only 1 column/row */ + if (width == 1 || height == 1) { + assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ + halve1Dimage_ubyte(components,width,height,datain,dataout, + element_size,ysize,group_size); + return; + } + + newwidth = width / 2; + newheight = height / 2; + padBytes = ysize - (width*group_size); + s = dataout; + t = (const char *)datain; + + /* Piece o' cake! */ + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + s[0] = (*(const GLubyte*)t + + *(const GLubyte*)(t+group_size) + + *(const GLubyte*)(t+ysize) + + *(const GLubyte*)(t+ysize+group_size) + 2) / 4; + s++; t += element_size; + } + t += group_size; + } + t += padBytes; + t += ysize; + } +} + +/* */ +static void halve1Dimage_ubyte(GLint components, GLuint width, GLuint height, + const GLubyte *dataIn, GLubyte *dataOut, + GLint element_size, GLint ysize, + GLint group_size) +{ + GLint halfWidth= width / 2; + GLint halfHeight= height / 2; + const char *src= (const char *) dataIn; + GLubyte *dest= dataOut; + int jj; + + assert(width == 1 || height == 1); /* must be 1D */ + assert(width != height); /* can't be square */ + + if (height == 1) { /* 1 row */ + assert(width != 1); /* widthxheight can't be 1x1 */ + halfHeight= 1; + + for (jj= 0; jj< halfWidth; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { + *dest= (*(const GLubyte*)src + + *(const GLubyte*)(src+group_size)) / 2; + + src+= element_size; + dest++; + } + src+= group_size; /* skip to next 2 */ + } + { + int padBytes= ysize - (width*group_size); + src+= padBytes; /* for assertion only */ + } + } + else if (width == 1) { /* 1 column */ + int padBytes= ysize - (width * group_size); + assert(height != 1); /* widthxheight can't be 1x1 */ + halfWidth= 1; + /* one vertical column with possible pad bytes per row */ + /* average two at a time */ + + for (jj= 0; jj< halfHeight; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { + *dest= (*(const GLubyte*)src + *(const GLubyte*)(src+ysize)) / 2; + + src+= element_size; + dest++; + } + src+= padBytes; /* add pad bytes, if any, to get to end to row */ + src+= ysize; + } + } + + assert(src == &((const char *)dataIn)[ysize*height]); + assert((char *)dest == &((char *)dataOut) + [components * element_size * halfWidth * halfHeight]); +} /* halve1Dimage_ubyte() */ + +static void halveImage_byte(GLint components, GLuint width, GLuint height, + const GLbyte *datain, GLbyte *dataout, + GLint element_size, + GLint ysize, GLint group_size) +{ + int i, j, k; + int newwidth, newheight; + int padBytes; + GLbyte *s; + const char *t; + + /* handle case where there is only 1 column/row */ + if (width == 1 || height == 1) { + assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ + halve1Dimage_byte(components,width,height,datain,dataout, + element_size,ysize,group_size); + return; + } + + newwidth = width / 2; + newheight = height / 2; + padBytes = ysize - (width*group_size); + s = dataout; + t = (const char *)datain; + + /* Piece o' cake! */ + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + s[0] = (*(const GLbyte*)t + + *(const GLbyte*)(t+group_size) + + *(const GLbyte*)(t+ysize) + + *(const GLbyte*)(t+ysize+group_size) + 2) / 4; + s++; t += element_size; + } + t += group_size; + } + t += padBytes; + t += ysize; + } +} + +static void halve1Dimage_byte(GLint components, GLuint width, GLuint height, + const GLbyte *dataIn, GLbyte *dataOut, + GLint element_size,GLint ysize, GLint group_size) +{ + GLint halfWidth= width / 2; + GLint halfHeight= height / 2; + const char *src= (const char *) dataIn; + GLbyte *dest= dataOut; + int jj; + + assert(width == 1 || height == 1); /* must be 1D */ + assert(width != height); /* can't be square */ + + if (height == 1) { /* 1 row */ + assert(width != 1); /* widthxheight can't be 1x1 */ + halfHeight= 1; + + for (jj= 0; jj< halfWidth; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { + *dest= (*(const GLbyte*)src + *(const GLbyte*)(src+group_size)) / 2; + + src+= element_size; + dest++; + } + src+= group_size; /* skip to next 2 */ + } + { + int padBytes= ysize - (width*group_size); + src+= padBytes; /* for assertion only */ + } + } + else if (width == 1) { /* 1 column */ + int padBytes= ysize - (width * group_size); + assert(height != 1); /* widthxheight can't be 1x1 */ + halfWidth= 1; + /* one vertical column with possible pad bytes per row */ + /* average two at a time */ + + for (jj= 0; jj< halfHeight; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { + *dest= (*(const GLbyte*)src + *(const GLbyte*)(src+ysize)) / 2; + + src+= element_size; + dest++; + } + src+= padBytes; /* add pad bytes, if any, to get to end to row */ + src+= ysize; + } + + assert(src == &((const char *)dataIn)[ysize*height]); + } + + assert((char *)dest == &((char *)dataOut) + [components * element_size * halfWidth * halfHeight]); +} /* halve1Dimage_byte() */ + +static void halveImage_ushort(GLint components, GLuint width, GLuint height, + const GLushort *datain, GLushort *dataout, + GLint element_size, GLint ysize, GLint group_size, + GLint myswap_bytes) +{ + int i, j, k; + int newwidth, newheight; + int padBytes; + GLushort *s; + const char *t; + + /* handle case where there is only 1 column/row */ + if (width == 1 || height == 1) { + assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ + halve1Dimage_ushort(components,width,height,datain,dataout, + element_size,ysize,group_size, myswap_bytes); + return; + } + + newwidth = width / 2; + newheight = height / 2; + padBytes = ysize - (width*group_size); + s = dataout; + t = (const char *)datain; + + /* Piece o' cake! */ + if (!myswap_bytes) + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + s[0] = (*(const GLushort*)t + + *(const GLushort*)(t+group_size) + + *(const GLushort*)(t+ysize) + + *(const GLushort*)(t+ysize+group_size) + 2) / 4; + s++; t += element_size; + } + t += group_size; + } + t += padBytes; + t += ysize; + } + else + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + s[0] = (__GLU_SWAP_2_BYTES(t) + + __GLU_SWAP_2_BYTES(t+group_size) + + __GLU_SWAP_2_BYTES(t+ysize) + + __GLU_SWAP_2_BYTES(t+ysize+group_size)+ 2)/4; + s++; t += element_size; + } + t += group_size; + } + t += padBytes; + t += ysize; + } +} + +static void halve1Dimage_ushort(GLint components, GLuint width, GLuint height, + const GLushort *dataIn, GLushort *dataOut, + GLint element_size, GLint ysize, + GLint group_size, GLint myswap_bytes) +{ + GLint halfWidth= width / 2; + GLint halfHeight= height / 2; + const char *src= (const char *) dataIn; + GLushort *dest= dataOut; + int jj; + + assert(width == 1 || height == 1); /* must be 1D */ + assert(width != height); /* can't be square */ + + if (height == 1) { /* 1 row */ + assert(width != 1); /* widthxheight can't be 1x1 */ + halfHeight= 1; + + for (jj= 0; jj< halfWidth; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { +#define BOX2 2 + GLushort ushort[BOX2]; + if (myswap_bytes) { + ushort[0]= __GLU_SWAP_2_BYTES(src); + ushort[1]= __GLU_SWAP_2_BYTES(src+group_size); + } + else { + ushort[0]= *(const GLushort*)src; + ushort[1]= *(const GLushort*)(src+group_size); + } + + *dest= (ushort[0] + ushort[1]) / 2; + src+= element_size; + dest++; + } + src+= group_size; /* skip to next 2 */ + } + { + int padBytes= ysize - (width*group_size); + src+= padBytes; /* for assertion only */ + } + } + else if (width == 1) { /* 1 column */ + int padBytes= ysize - (width * group_size); + assert(height != 1); /* widthxheight can't be 1x1 */ + halfWidth= 1; + /* one vertical column with possible pad bytes per row */ + /* average two at a time */ + + for (jj= 0; jj< halfHeight; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { +#define BOX2 2 + GLushort ushort[BOX2]; + if (myswap_bytes) { + ushort[0]= __GLU_SWAP_2_BYTES(src); + ushort[1]= __GLU_SWAP_2_BYTES(src+ysize); + } + else { + ushort[0]= *(const GLushort*)src; + ushort[1]= *(const GLushort*)(src+ysize); + } + *dest= (ushort[0] + ushort[1]) / 2; + + src+= element_size; + dest++; + } + src+= padBytes; /* add pad bytes, if any, to get to end to row */ + src+= ysize; + } + + assert(src == &((const char *)dataIn)[ysize*height]); + } + + assert((char *)dest == &((char *)dataOut) + [components * element_size * halfWidth * halfHeight]); + +} /* halve1Dimage_ushort() */ + + +static void halveImage_short(GLint components, GLuint width, GLuint height, + const GLshort *datain, GLshort *dataout, + GLint element_size, GLint ysize, GLint group_size, + GLint myswap_bytes) +{ + int i, j, k; + int newwidth, newheight; + int padBytes; + GLshort *s; + const char *t; + + /* handle case where there is only 1 column/row */ + if (width == 1 || height == 1) { + assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ + halve1Dimage_short(components,width,height,datain,dataout, + element_size,ysize,group_size, myswap_bytes); + return; + } + + newwidth = width / 2; + newheight = height / 2; + padBytes = ysize - (width*group_size); + s = dataout; + t = (const char *)datain; + + /* Piece o' cake! */ + if (!myswap_bytes) + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + s[0] = (*(const GLshort*)t + + *(const GLshort*)(t+group_size) + + *(const GLshort*)(t+ysize) + + *(const GLshort*)(t+ysize+group_size) + 2) / 4; + s++; t += element_size; + } + t += group_size; + } + t += padBytes; + t += ysize; + } + else + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + GLushort b; + GLint buf; + b = __GLU_SWAP_2_BYTES(t); + buf = *(const GLshort*)&b; + b = __GLU_SWAP_2_BYTES(t+group_size); + buf += *(const GLshort*)&b; + b = __GLU_SWAP_2_BYTES(t+ysize); + buf += *(const GLshort*)&b; + b = __GLU_SWAP_2_BYTES(t+ysize+group_size); + buf += *(const GLshort*)&b; + s[0] = (GLshort)((buf+2)/4); + s++; t += element_size; + } + t += group_size; + } + t += padBytes; + t += ysize; + } +} + +static void halve1Dimage_short(GLint components, GLuint width, GLuint height, + const GLshort *dataIn, GLshort *dataOut, + GLint element_size, GLint ysize, + GLint group_size, GLint myswap_bytes) +{ + GLint halfWidth= width / 2; + GLint halfHeight= height / 2; + const char *src= (const char *) dataIn; + GLshort *dest= dataOut; + int jj; + + assert(width == 1 || height == 1); /* must be 1D */ + assert(width != height); /* can't be square */ + + if (height == 1) { /* 1 row */ + assert(width != 1); /* widthxheight can't be 1x1 */ + halfHeight= 1; + + for (jj= 0; jj< halfWidth; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { +#define BOX2 2 + GLshort sshort[BOX2]; + if (myswap_bytes) { + sshort[0]= __GLU_SWAP_2_BYTES(src); + sshort[1]= __GLU_SWAP_2_BYTES(src+group_size); + } + else { + sshort[0]= *(const GLshort*)src; + sshort[1]= *(const GLshort*)(src+group_size); + } + + *dest= (sshort[0] + sshort[1]) / 2; + src+= element_size; + dest++; + } + src+= group_size; /* skip to next 2 */ + } + { + int padBytes= ysize - (width*group_size); + src+= padBytes; /* for assertion only */ + } + } + else if (width == 1) { /* 1 column */ + int padBytes= ysize - (width * group_size); + assert(height != 1); /* widthxheight can't be 1x1 */ + halfWidth= 1; + /* one vertical column with possible pad bytes per row */ + /* average two at a time */ + + for (jj= 0; jj< halfHeight; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { +#define BOX2 2 + GLshort sshort[BOX2]; + if (myswap_bytes) { + sshort[0]= __GLU_SWAP_2_BYTES(src); + sshort[1]= __GLU_SWAP_2_BYTES(src+ysize); + } + else { + sshort[0]= *(const GLshort*)src; + sshort[1]= *(const GLshort*)(src+ysize); + } + *dest= (sshort[0] + sshort[1]) / 2; + + src+= element_size; + dest++; + } + src+= padBytes; /* add pad bytes, if any, to get to end to row */ + src+= ysize; + } + + assert(src == &((const char *)dataIn)[ysize*height]); + } + + assert((char *)dest == &((char *)dataOut) + [components * element_size * halfWidth * halfHeight]); + +} /* halve1Dimage_short() */ + + +static void halveImage_uint(GLint components, GLuint width, GLuint height, + const GLuint *datain, GLuint *dataout, + GLint element_size, GLint ysize, GLint group_size, + GLint myswap_bytes) +{ + int i, j, k; + int newwidth, newheight; + int padBytes; + GLuint *s; + const char *t; + + /* handle case where there is only 1 column/row */ + if (width == 1 || height == 1) { + assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ + halve1Dimage_uint(components,width,height,datain,dataout, + element_size,ysize,group_size, myswap_bytes); + return; + } + + newwidth = width / 2; + newheight = height / 2; + padBytes = ysize - (width*group_size); + s = dataout; + t = (const char *)datain; + + /* Piece o' cake! */ + if (!myswap_bytes) + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + /* need to cast to double to hold large unsigned ints */ + s[0] = ((double)*(const GLuint*)t + + (double)*(const GLuint*)(t+group_size) + + (double)*(const GLuint*)(t+ysize) + + (double)*(const GLuint*)(t+ysize+group_size))/4 + 0.5; + s++; t += element_size; + + } + t += group_size; + } + t += padBytes; + t += ysize; + } + else + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + /* need to cast to double to hold large unsigned ints */ + GLdouble buf; + buf = (GLdouble)__GLU_SWAP_4_BYTES(t) + + (GLdouble)__GLU_SWAP_4_BYTES(t+group_size) + + (GLdouble)__GLU_SWAP_4_BYTES(t+ysize) + + (GLdouble)__GLU_SWAP_4_BYTES(t+ysize+group_size); + s[0] = (GLuint)(buf/4 + 0.5); + + s++; t += element_size; + } + t += group_size; + } + t += padBytes; + t += ysize; + } +} + +/* */ +static void halve1Dimage_uint(GLint components, GLuint width, GLuint height, + const GLuint *dataIn, GLuint *dataOut, + GLint element_size, GLint ysize, + GLint group_size, GLint myswap_bytes) +{ + GLint halfWidth= width / 2; + GLint halfHeight= height / 2; + const char *src= (const char *) dataIn; + GLuint *dest= dataOut; + int jj; + + assert(width == 1 || height == 1); /* must be 1D */ + assert(width != height); /* can't be square */ + + if (height == 1) { /* 1 row */ + assert(width != 1); /* widthxheight can't be 1x1 */ + halfHeight= 1; + + for (jj= 0; jj< halfWidth; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { +#define BOX2 2 + GLuint uint[BOX2]; + if (myswap_bytes) { + uint[0]= __GLU_SWAP_4_BYTES(src); + uint[1]= __GLU_SWAP_4_BYTES(src+group_size); + } + else { + uint[0]= *(const GLuint*)src; + uint[1]= *(const GLuint*)(src+group_size); + } + *dest= ((double)uint[0]+(double)uint[1])/2.0; + + src+= element_size; + dest++; + } + src+= group_size; /* skip to next 2 */ + } + { + int padBytes= ysize - (width*group_size); + src+= padBytes; /* for assertion only */ + } + } + else if (width == 1) { /* 1 column */ + int padBytes= ysize - (width * group_size); + assert(height != 1); /* widthxheight can't be 1x1 */ + halfWidth= 1; + /* one vertical column with possible pad bytes per row */ + /* average two at a time */ + + for (jj= 0; jj< halfHeight; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { +#define BOX2 2 + GLuint uint[BOX2]; + if (myswap_bytes) { + uint[0]= __GLU_SWAP_4_BYTES(src); + uint[1]= __GLU_SWAP_4_BYTES(src+ysize); + } + else { + uint[0]= *(const GLuint*)src; + uint[1]= *(const GLuint*)(src+ysize); + } + *dest= ((double)uint[0]+(double)uint[1])/2.0; + + src+= element_size; + dest++; + } + src+= padBytes; /* add pad bytes, if any, to get to end to row */ + src+= ysize; + } + + assert(src == &((const char *)dataIn)[ysize*height]); + } + + assert((char *)dest == &((char *)dataOut) + [components * element_size * halfWidth * halfHeight]); + +} /* halve1Dimage_uint() */ + +static void halveImage_int(GLint components, GLuint width, GLuint height, + const GLint *datain, GLint *dataout, GLint element_size, + GLint ysize, GLint group_size, GLint myswap_bytes) +{ + int i, j, k; + int newwidth, newheight; + int padBytes; + GLint *s; + const char *t; + + /* handle case where there is only 1 column/row */ + if (width == 1 || height == 1) { + assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ + halve1Dimage_int(components,width,height,datain,dataout, + element_size,ysize,group_size, myswap_bytes); + return; + } + + newwidth = width / 2; + newheight = height / 2; + padBytes = ysize - (width*group_size); + s = dataout; + t = (const char *)datain; + + /* Piece o' cake! */ + if (!myswap_bytes) + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + s[0] = ((float)*(const GLint*)t + + (float)*(const GLint*)(t+group_size) + + (float)*(const GLint*)(t+ysize) + + (float)*(const GLint*)(t+ysize+group_size))/4 + 0.5; + s++; t += element_size; + } + t += group_size; + } + t += padBytes; + t += ysize; + } + else + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + GLuint b; + GLfloat buf; + b = __GLU_SWAP_4_BYTES(t); + buf = *(GLint*)&b; + b = __GLU_SWAP_4_BYTES(t+group_size); + buf += *(GLint*)&b; + b = __GLU_SWAP_4_BYTES(t+ysize); + buf += *(GLint*)&b; + b = __GLU_SWAP_4_BYTES(t+ysize+group_size); + buf += *(GLint*)&b; + s[0] = (GLint)(buf/4 + 0.5); + + s++; t += element_size; + } + t += group_size; + } + t += padBytes; + t += ysize; + } +} + +/* */ +static void halve1Dimage_int(GLint components, GLuint width, GLuint height, + const GLint *dataIn, GLint *dataOut, + GLint element_size, GLint ysize, + GLint group_size, GLint myswap_bytes) +{ + GLint halfWidth= width / 2; + GLint halfHeight= height / 2; + const char *src= (const char *) dataIn; + GLint *dest= dataOut; + int jj; + + assert(width == 1 || height == 1); /* must be 1D */ + assert(width != height); /* can't be square */ + + if (height == 1) { /* 1 row */ + assert(width != 1); /* widthxheight can't be 1x1 */ + halfHeight= 1; + + for (jj= 0; jj< halfWidth; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { +#define BOX2 2 + GLuint uint[BOX2]; + if (myswap_bytes) { + uint[0]= __GLU_SWAP_4_BYTES(src); + uint[1]= __GLU_SWAP_4_BYTES(src+group_size); + } + else { + uint[0]= *(const GLuint*)src; + uint[1]= *(const GLuint*)(src+group_size); + } + *dest= ((float)uint[0]+(float)uint[1])/2.0; + + src+= element_size; + dest++; + } + src+= group_size; /* skip to next 2 */ + } + { + int padBytes= ysize - (width*group_size); + src+= padBytes; /* for assertion only */ + } + } + else if (width == 1) { /* 1 column */ + int padBytes= ysize - (width * group_size); + assert(height != 1); /* widthxheight can't be 1x1 */ + halfWidth= 1; + /* one vertical column with possible pad bytes per row */ + /* average two at a time */ + + for (jj= 0; jj< halfHeight; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { +#define BOX2 2 + GLuint uint[BOX2]; + if (myswap_bytes) { + uint[0]= __GLU_SWAP_4_BYTES(src); + uint[1]= __GLU_SWAP_4_BYTES(src+ysize); + } + else { + uint[0]= *(const GLuint*)src; + uint[1]= *(const GLuint*)(src+ysize); + } + *dest= ((float)uint[0]+(float)uint[1])/2.0; + + src+= element_size; + dest++; + } + src+= padBytes; /* add pad bytes, if any, to get to end to row */ + src+= ysize; + } + + assert(src == &((const char *)dataIn)[ysize*height]); + } + + assert((char *)dest == &((char *)dataOut) + [components * element_size * halfWidth * halfHeight]); + +} /* halve1Dimage_int() */ + + +static void halveImage_float(GLint components, GLuint width, GLuint height, + const GLfloat *datain, GLfloat *dataout, + GLint element_size, GLint ysize, GLint group_size, + GLint myswap_bytes) +{ + int i, j, k; + int newwidth, newheight; + int padBytes; + GLfloat *s; + const char *t; + + /* handle case where there is only 1 column/row */ + if (width == 1 || height == 1) { + assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ + halve1Dimage_float(components,width,height,datain,dataout, + element_size,ysize,group_size, myswap_bytes); + return; + } + + newwidth = width / 2; + newheight = height / 2; + padBytes = ysize - (width*group_size); + s = dataout; + t = (const char *)datain; + + /* Piece o' cake! */ + if (!myswap_bytes) + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + s[0] = (*(const GLfloat*)t + + *(const GLfloat*)(t+group_size) + + *(const GLfloat*)(t+ysize) + + *(const GLfloat*)(t+ysize+group_size)) / 4; + s++; t += element_size; + } + t += group_size; + } + t += padBytes; + t += ysize; + } + else + for (i = 0; i < newheight; i++) { + for (j = 0; j < newwidth; j++) { + for (k = 0; k < components; k++) { + union { GLuint b; GLfloat f; } swapbuf; + swapbuf.b = __GLU_SWAP_4_BYTES(t); + s[0] = swapbuf.f; + swapbuf.b = __GLU_SWAP_4_BYTES(t+group_size); + s[0] += swapbuf.f; + swapbuf.b = __GLU_SWAP_4_BYTES(t+ysize); + s[0] += swapbuf.f; + swapbuf.b = __GLU_SWAP_4_BYTES(t+ysize+group_size); + s[0] += swapbuf.f; + s[0] /= 4; + s++; t += element_size; + } + t += group_size; + } + t += padBytes; + t += ysize; + } +} + +/* */ +static void halve1Dimage_float(GLint components, GLuint width, GLuint height, + const GLfloat *dataIn, GLfloat *dataOut, + GLint element_size, GLint ysize, + GLint group_size, GLint myswap_bytes) +{ + GLint halfWidth= width / 2; + GLint halfHeight= height / 2; + const char *src= (const char *) dataIn; + GLfloat *dest= dataOut; + int jj; + + assert(width == 1 || height == 1); /* must be 1D */ + assert(width != height); /* can't be square */ + + if (height == 1) { /* 1 row */ + assert(width != 1); /* widthxheight can't be 1x1 */ + halfHeight= 1; + + for (jj= 0; jj< halfWidth; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { +#define BOX2 2 + GLfloat sfloat[BOX2]; + if (myswap_bytes) { + sfloat[0]= __GLU_SWAP_4_BYTES(src); + sfloat[1]= __GLU_SWAP_4_BYTES(src+group_size); + } + else { + sfloat[0]= *(const GLfloat*)src; + sfloat[1]= *(const GLfloat*)(src+group_size); + } + + *dest= (sfloat[0] + sfloat[1]) / 2.0; + src+= element_size; + dest++; + } + src+= group_size; /* skip to next 2 */ + } + { + int padBytes= ysize - (width*group_size); + src+= padBytes; /* for assertion only */ + } + } + else if (width == 1) { /* 1 column */ + int padBytes= ysize - (width * group_size); + assert(height != 1); /* widthxheight can't be 1x1 */ + halfWidth= 1; + /* one vertical column with possible pad bytes per row */ + /* average two at a time */ + + for (jj= 0; jj< halfHeight; jj++) { + int kk; + for (kk= 0; kk< components; kk++) { +#define BOX2 2 + GLfloat sfloat[BOX2]; + if (myswap_bytes) { + sfloat[0]= __GLU_SWAP_4_BYTES(src); + sfloat[1]= __GLU_SWAP_4_BYTES(src+ysize); + } + else { + sfloat[0]= *(const GLfloat*)src; + sfloat[1]= *(const GLfloat*)(src+ysize); + } + *dest= (sfloat[0] + sfloat[1]) / 2.0; + + src+= element_size; + dest++; + } + src+= padBytes; /* add pad bytes, if any, to get to end to row */ + src+= ysize; /* skip to odd row */ + } + } + + assert(src == &((const char *)dataIn)[ysize*height]); + assert((char *)dest == &((char *)dataOut) + [components * element_size * halfWidth * halfHeight]); +} /* halve1Dimage_float() */ + +static void scale_internal(GLint components, GLint widthin, GLint heightin, + const GLushort *datain, + GLint widthout, GLint heightout, + GLushort *dataout) +{ + float x, lowx, highx, convx, halfconvx; + float y, lowy, highy, convy, halfconvy; + float xpercent,ypercent; + float percent; + /* Max components in a format is 4, so... */ + float totals[4]; + float area; + int i,j,k,yint,xint,xindex,yindex; + int temp; + + if (widthin == widthout*2 && heightin == heightout*2) { + halveImage(components, widthin, heightin, datain, dataout); + return; + } + convy = (float) heightin/heightout; + convx = (float) widthin/widthout; + halfconvx = convx/2; + halfconvy = convy/2; + for (i = 0; i < heightout; i++) { + y = convy * (i+0.5); + if (heightin > heightout) { + highy = y + halfconvy; + lowy = y - halfconvy; + } else { + highy = y + 0.5; + lowy = y - 0.5; + } + for (j = 0; j < widthout; j++) { + x = convx * (j+0.5); + if (widthin > widthout) { + highx = x + halfconvx; + lowx = x - halfconvx; + } else { + highx = x + 0.5; + lowx = x - 0.5; + } + + /* + ** Ok, now apply box filter to box that goes from (lowx, lowy) + ** to (highx, highy) on input data into this pixel on output + ** data. + */ + totals[0] = totals[1] = totals[2] = totals[3] = 0.0; + area = 0.0; + + y = lowy; + yint = floor(y); + while (y < highy) { + yindex = (yint + heightin) % heightin; + if (highy < yint+1) { + ypercent = highy - y; + } else { + ypercent = yint+1 - y; + } + + x = lowx; + xint = floor(x); + + while (x < highx) { + xindex = (xint + widthin) % widthin; + if (highx < xint+1) { + xpercent = highx - x; + } else { + xpercent = xint+1 - x; + } + + percent = xpercent * ypercent; + area += percent; + temp = (xindex + (yindex * widthin)) * components; + for (k = 0; k < components; k++) { + totals[k] += datain[temp + k] * percent; + } + + xint++; + x = xint; + } + yint++; + y = yint; + } + + temp = (j + (i * widthout)) * components; + for (k = 0; k < components; k++) { + /* totals[] should be rounded in the case of enlarging an RGB + * ramp when the type is 332 or 4444 + */ + dataout[temp + k] = (totals[k]+0.5)/area; + } + } + } +} + +static void scale_internal_ubyte(GLint components, GLint widthin, + GLint heightin, const GLubyte *datain, + GLint widthout, GLint heightout, + GLubyte *dataout, GLint element_size, + GLint ysize, GLint group_size) +{ + float convx; + float convy; + float percent; + /* Max components in a format is 4, so... */ + float totals[4]; + float area; + int i,j,k,xindex; + + const char *temp, *temp0; + const char *temp_index; + int outindex; + + int lowx_int, highx_int, lowy_int, highy_int; + float x_percent, y_percent; + float lowx_float, highx_float, lowy_float, highy_float; + float convy_float, convx_float; + int convy_int, convx_int; + int l, m; + const char *left, *right; + + if (widthin == widthout*2 && heightin == heightout*2) { + halveImage_ubyte(components, widthin, heightin, + (const GLubyte *)datain, (GLubyte *)dataout, + element_size, ysize, group_size); + return; + } + convy = (float) heightin/heightout; + convx = (float) widthin/widthout; + convy_int = floor(convy); + convy_float = convy - convy_int; + convx_int = floor(convx); + convx_float = convx - convx_int; + + area = convx * convy; + + lowy_int = 0; + lowy_float = 0; + highy_int = convy_int; + highy_float = convy_float; + + for (i = 0; i < heightout; i++) { + /* Clamp here to be sure we don't read beyond input buffer. */ + if (highy_int >= heightin) + highy_int = heightin - 1; + lowx_int = 0; + lowx_float = 0; + highx_int = convx_int; + highx_float = convx_float; + + for (j = 0; j < widthout; j++) { + + /* + ** Ok, now apply box filter to box that goes from (lowx, lowy) + ** to (highx, highy) on input data into this pixel on output + ** data. + */ + totals[0] = totals[1] = totals[2] = totals[3] = 0.0; + + /* calculate the value for pixels in the 1st row */ + xindex = lowx_int*group_size; + if((highy_int>lowy_int) && (highx_int>lowx_int)) { + + y_percent = 1-lowy_float; + temp = (const char *)datain + xindex + lowy_int * ysize; + percent = y_percent * (1-lowx_float); + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * percent; + } + left = temp; + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * y_percent; + } + } + temp += group_size; + right = temp; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * percent; + } + + /* calculate the value for pixels in the last row */ + y_percent = highy_float; + percent = y_percent * (1-lowx_float); + temp = (const char *)datain + xindex + highy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * percent; + } + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * y_percent; + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * percent; + } + + + /* calculate the value for pixels in the 1st and last column */ + for(m = lowy_int+1; m < highy_int; m++) { + left += ysize; + right += ysize; + for (k = 0; k < components; + k++, left += element_size, right += element_size) { + totals[k] += (GLubyte)(*(left))*(1-lowx_float) + +(GLubyte)(*(right))*highx_float; + } + } + } else if (highy_int > lowy_int) { + x_percent = highx_float - lowx_float; + percent = (1-lowy_float)*x_percent; + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * percent; + } + for(m = lowy_int+1; m < highy_int; m++) { + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * x_percent; + } + } + percent = x_percent * highy_float; + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * percent; + } + } else if (highx_int > lowx_int) { + y_percent = highy_float - lowy_float; + percent = (1-lowx_float)*y_percent; + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * percent; + } + for (l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * y_percent; + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * percent; + } + } else { + percent = (highy_float-lowy_float)*(highx_float-lowx_float); + temp = (const char *)datain + xindex + lowy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)) * percent; + } + } + + + + /* this is for the pixels in the body */ + temp0 = (const char *)datain + xindex + group_size + + (lowy_int+1)*ysize; + for (m = lowy_int+1; m < highy_int; m++) { + temp = temp0; + for(l = lowx_int+1; l < highx_int; l++) { + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLubyte)(*(temp_index)); + } + temp += group_size; + } + temp0 += ysize; + } + + outindex = (j + (i * widthout)) * components; + for (k = 0; k < components; k++) { + dataout[outindex + k] = totals[k]/area; + /*printf("totals[%d] = %f\n", k, totals[k]);*/ + } + lowx_int = highx_int; + lowx_float = highx_float; + highx_int += convx_int; + highx_float += convx_float; + if(highx_float > 1) { + highx_float -= 1.0; + highx_int++; + } + } + lowy_int = highy_int; + lowy_float = highy_float; + highy_int += convy_int; + highy_float += convy_float; + if(highy_float > 1) { + highy_float -= 1.0; + highy_int++; + } + } +} + +static void scale_internal_byte(GLint components, GLint widthin, + GLint heightin, const GLbyte *datain, + GLint widthout, GLint heightout, + GLbyte *dataout, GLint element_size, + GLint ysize, GLint group_size) +{ + float convx; + float convy; + float percent; + /* Max components in a format is 4, so... */ + float totals[4]; + float area; + int i,j,k,xindex; + + const char *temp, *temp0; + const char *temp_index; + int outindex; + + int lowx_int, highx_int, lowy_int, highy_int; + float x_percent, y_percent; + float lowx_float, highx_float, lowy_float, highy_float; + float convy_float, convx_float; + int convy_int, convx_int; + int l, m; + const char *left, *right; + + if (widthin == widthout*2 && heightin == heightout*2) { + halveImage_byte(components, widthin, heightin, + (const GLbyte *)datain, (GLbyte *)dataout, + element_size, ysize, group_size); + return; + } + convy = (float) heightin/heightout; + convx = (float) widthin/widthout; + convy_int = floor(convy); + convy_float = convy - convy_int; + convx_int = floor(convx); + convx_float = convx - convx_int; + + area = convx * convy; + + lowy_int = 0; + lowy_float = 0; + highy_int = convy_int; + highy_float = convy_float; + + for (i = 0; i < heightout; i++) { + /* Clamp here to be sure we don't read beyond input buffer. */ + if (highy_int >= heightin) + highy_int = heightin - 1; + lowx_int = 0; + lowx_float = 0; + highx_int = convx_int; + highx_float = convx_float; + + for (j = 0; j < widthout; j++) { + + /* + ** Ok, now apply box filter to box that goes from (lowx, lowy) + ** to (highx, highy) on input data into this pixel on output + ** data. + */ + totals[0] = totals[1] = totals[2] = totals[3] = 0.0; + + /* calculate the value for pixels in the 1st row */ + xindex = lowx_int*group_size; + if((highy_int>lowy_int) && (highx_int>lowx_int)) { + + y_percent = 1-lowy_float; + temp = (const char *)datain + xindex + lowy_int * ysize; + percent = y_percent * (1-lowx_float); + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * percent; + } + left = temp; + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * y_percent; + } + } + temp += group_size; + right = temp; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * percent; + } + + /* calculate the value for pixels in the last row */ + y_percent = highy_float; + percent = y_percent * (1-lowx_float); + temp = (const char *)datain + xindex + highy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * percent; + } + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * y_percent; + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * percent; + } + + + /* calculate the value for pixels in the 1st and last column */ + for(m = lowy_int+1; m < highy_int; m++) { + left += ysize; + right += ysize; + for (k = 0; k < components; + k++, left += element_size, right += element_size) { + totals[k] += (GLbyte)(*(left))*(1-lowx_float) + +(GLbyte)(*(right))*highx_float; + } + } + } else if (highy_int > lowy_int) { + x_percent = highx_float - lowx_float; + percent = (1-lowy_float)*x_percent; + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * percent; + } + for(m = lowy_int+1; m < highy_int; m++) { + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * x_percent; + } + } + percent = x_percent * highy_float; + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * percent; + } + } else if (highx_int > lowx_int) { + y_percent = highy_float - lowy_float; + percent = (1-lowx_float)*y_percent; + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * percent; + } + for (l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * y_percent; + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * percent; + } + } else { + percent = (highy_float-lowy_float)*(highx_float-lowx_float); + temp = (const char *)datain + xindex + lowy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)) * percent; + } + } + + + + /* this is for the pixels in the body */ + temp0 = (const char *)datain + xindex + group_size + + (lowy_int+1)*ysize; + for (m = lowy_int+1; m < highy_int; m++) { + temp = temp0; + for(l = lowx_int+1; l < highx_int; l++) { + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + totals[k] += (GLbyte)(*(temp_index)); + } + temp += group_size; + } + temp0 += ysize; + } + + outindex = (j + (i * widthout)) * components; + for (k = 0; k < components; k++) { + dataout[outindex + k] = totals[k]/area; + /*printf("totals[%d] = %f\n", k, totals[k]);*/ + } + lowx_int = highx_int; + lowx_float = highx_float; + highx_int += convx_int; + highx_float += convx_float; + if(highx_float > 1) { + highx_float -= 1.0; + highx_int++; + } + } + lowy_int = highy_int; + lowy_float = highy_float; + highy_int += convy_int; + highy_float += convy_float; + if(highy_float > 1) { + highy_float -= 1.0; + highy_int++; + } + } +} + +static void scale_internal_ushort(GLint components, GLint widthin, + GLint heightin, const GLushort *datain, + GLint widthout, GLint heightout, + GLushort *dataout, GLint element_size, + GLint ysize, GLint group_size, + GLint myswap_bytes) +{ + float convx; + float convy; + float percent; + /* Max components in a format is 4, so... */ + float totals[4]; + float area; + int i,j,k,xindex; + + const char *temp, *temp0; + const char *temp_index; + int outindex; + + int lowx_int, highx_int, lowy_int, highy_int; + float x_percent, y_percent; + float lowx_float, highx_float, lowy_float, highy_float; + float convy_float, convx_float; + int convy_int, convx_int; + int l, m; + const char *left, *right; + + if (widthin == widthout*2 && heightin == heightout*2) { + halveImage_ushort(components, widthin, heightin, + (const GLushort *)datain, (GLushort *)dataout, + element_size, ysize, group_size, myswap_bytes); + return; + } + convy = (float) heightin/heightout; + convx = (float) widthin/widthout; + convy_int = floor(convy); + convy_float = convy - convy_int; + convx_int = floor(convx); + convx_float = convx - convx_int; + + area = convx * convy; + + lowy_int = 0; + lowy_float = 0; + highy_int = convy_int; + highy_float = convy_float; + + for (i = 0; i < heightout; i++) { + /* Clamp here to be sure we don't read beyond input buffer. */ + if (highy_int >= heightin) + highy_int = heightin - 1; + lowx_int = 0; + lowx_float = 0; + highx_int = convx_int; + highx_float = convx_float; + + for (j = 0; j < widthout; j++) { + /* + ** Ok, now apply box filter to box that goes from (lowx, lowy) + ** to (highx, highy) on input data into this pixel on output + ** data. + */ + totals[0] = totals[1] = totals[2] = totals[3] = 0.0; + + /* calculate the value for pixels in the 1st row */ + xindex = lowx_int*group_size; + if((highy_int>lowy_int) && (highx_int>lowx_int)) { + + y_percent = 1-lowy_float; + temp = (const char *)datain + xindex + lowy_int * ysize; + percent = y_percent * (1-lowx_float); + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } + left = temp; + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_2_BYTES(temp_index) * y_percent; + } else { + totals[k] += *(const GLushort*)temp_index * y_percent; + } + } + } + temp += group_size; + right = temp; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } + + /* calculate the value for pixels in the last row */ + y_percent = highy_float; + percent = y_percent * (1-lowx_float); + temp = (const char *)datain + xindex + highy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_2_BYTES(temp_index) * y_percent; + } else { + totals[k] += *(const GLushort*)temp_index * y_percent; + } + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } + + /* calculate the value for pixels in the 1st and last column */ + for(m = lowy_int+1; m < highy_int; m++) { + left += ysize; + right += ysize; + for (k = 0; k < components; + k++, left += element_size, right += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_2_BYTES(left) * (1-lowx_float) + + __GLU_SWAP_2_BYTES(right) * highx_float; + } else { + totals[k] += *(const GLushort*)left * (1-lowx_float) + + *(const GLushort*)right * highx_float; + } + } + } + } else if (highy_int > lowy_int) { + x_percent = highx_float - lowx_float; + percent = (1-lowy_float)*x_percent; + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } + for(m = lowy_int+1; m < highy_int; m++) { + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_2_BYTES(temp_index) * x_percent; + } else { + totals[k] += *(const GLushort*)temp_index * x_percent; + } + } + } + percent = x_percent * highy_float; + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } + } else if (highx_int > lowx_int) { + y_percent = highy_float - lowy_float; + percent = (1-lowx_float)*y_percent; + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } + for (l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_2_BYTES(temp_index) * y_percent; + } else { + totals[k] += *(const GLushort*)temp_index * y_percent; + } + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } + } else { + percent = (highy_float-lowy_float)*(highx_float-lowx_float); + temp = (const char *)datain + xindex + lowy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } + } + + /* this is for the pixels in the body */ + temp0 = (const char *)datain + xindex + group_size + + (lowy_int+1)*ysize; + for (m = lowy_int+1; m < highy_int; m++) { + temp = temp0; + for(l = lowx_int+1; l < highx_int; l++) { + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index); + } else { + totals[k] += *(const GLushort*)temp_index; + } + } + temp += group_size; + } + temp0 += ysize; + } + + outindex = (j + (i * widthout)) * components; + for (k = 0; k < components; k++) { + dataout[outindex + k] = totals[k]/area; + /*printf("totals[%d] = %f\n", k, totals[k]);*/ + } + lowx_int = highx_int; + lowx_float = highx_float; + highx_int += convx_int; + highx_float += convx_float; + if(highx_float > 1) { + highx_float -= 1.0; + highx_int++; + } + } + lowy_int = highy_int; + lowy_float = highy_float; + highy_int += convy_int; + highy_float += convy_float; + if(highy_float > 1) { + highy_float -= 1.0; + highy_int++; + } + } +} + +static void scale_internal_short(GLint components, GLint widthin, + GLint heightin, const GLshort *datain, + GLint widthout, GLint heightout, + GLshort *dataout, GLint element_size, + GLint ysize, GLint group_size, + GLint myswap_bytes) +{ + float convx; + float convy; + float percent; + /* Max components in a format is 4, so... */ + float totals[4]; + float area; + int i,j,k,xindex; + + const char *temp, *temp0; + const char *temp_index; + int outindex; + + int lowx_int, highx_int, lowy_int, highy_int; + float x_percent, y_percent; + float lowx_float, highx_float, lowy_float, highy_float; + float convy_float, convx_float; + int convy_int, convx_int; + int l, m; + const char *left, *right; + + GLushort swapbuf; /* unsigned buffer */ + + if (widthin == widthout*2 && heightin == heightout*2) { + halveImage_short(components, widthin, heightin, + (const GLshort *)datain, (GLshort *)dataout, + element_size, ysize, group_size, myswap_bytes); + return; + } + convy = (float) heightin/heightout; + convx = (float) widthin/widthout; + convy_int = floor(convy); + convy_float = convy - convy_int; + convx_int = floor(convx); + convx_float = convx - convx_int; + + area = convx * convy; + + lowy_int = 0; + lowy_float = 0; + highy_int = convy_int; + highy_float = convy_float; + + for (i = 0; i < heightout; i++) { + /* Clamp here to be sure we don't read beyond input buffer. */ + if (highy_int >= heightin) + highy_int = heightin - 1; + lowx_int = 0; + lowx_float = 0; + highx_int = convx_int; + highx_float = convx_float; + + for (j = 0; j < widthout; j++) { + /* + ** Ok, now apply box filter to box that goes from (lowx, lowy) + ** to (highx, highy) on input data into this pixel on output + ** data. + */ + totals[0] = totals[1] = totals[2] = totals[3] = 0.0; + + /* calculate the value for pixels in the 1st row */ + xindex = lowx_int*group_size; + if((highy_int>lowy_int) && (highx_int>lowx_int)) { + + y_percent = 1-lowy_float; + temp = (const char *)datain + xindex + lowy_int * ysize; + percent = y_percent * (1-lowx_float); + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * percent; + } else { + totals[k] += *(const GLshort*)temp_index * percent; + } + } + left = temp; + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * y_percent; + } else { + totals[k] += *(const GLshort*)temp_index * y_percent; + } + } + } + temp += group_size; + right = temp; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * percent; + } else { + totals[k] += *(const GLshort*)temp_index * percent; + } + } + + /* calculate the value for pixels in the last row */ + y_percent = highy_float; + percent = y_percent * (1-lowx_float); + temp = (const char *)datain + xindex + highy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * percent; + } else { + totals[k] += *(const GLshort*)temp_index * percent; + } + } + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * y_percent; + } else { + totals[k] += *(const GLshort*)temp_index * y_percent; + } + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * percent; + } else { + totals[k] += *(const GLshort*)temp_index * percent; + } + } + + /* calculate the value for pixels in the 1st and last column */ + for(m = lowy_int+1; m < highy_int; m++) { + left += ysize; + right += ysize; + for (k = 0; k < components; + k++, left += element_size, right += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(left); + totals[k] += *(const GLshort*)&swapbuf * (1-lowx_float); + swapbuf = __GLU_SWAP_2_BYTES(right); + totals[k] += *(const GLshort*)&swapbuf * highx_float; + } else { + totals[k] += *(const GLshort*)left * (1-lowx_float) + + *(const GLshort*)right * highx_float; + } + } + } + } else if (highy_int > lowy_int) { + x_percent = highx_float - lowx_float; + percent = (1-lowy_float)*x_percent; + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * percent; + } else { + totals[k] += *(const GLshort*)temp_index * percent; + } + } + for(m = lowy_int+1; m < highy_int; m++) { + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * x_percent; + } else { + totals[k] += *(const GLshort*)temp_index * x_percent; + } + } + } + percent = x_percent * highy_float; + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * percent; + } else { + totals[k] += *(const GLshort*)temp_index * percent; + } + } + } else if (highx_int > lowx_int) { + y_percent = highy_float - lowy_float; + percent = (1-lowx_float)*y_percent; + + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * percent; + } else { + totals[k] += *(const GLshort*)temp_index * percent; + } + } + for (l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * y_percent; + } else { + totals[k] += *(const GLshort*)temp_index * y_percent; + } + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * percent; + } else { + totals[k] += *(const GLshort*)temp_index * percent; + } + } + } else { + percent = (highy_float-lowy_float)*(highx_float-lowx_float); + temp = (const char *)datain + xindex + lowy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf * percent; + } else { + totals[k] += *(const GLshort*)temp_index * percent; + } + } + } + + /* this is for the pixels in the body */ + temp0 = (const char *)datain + xindex + group_size + + (lowy_int+1)*ysize; + for (m = lowy_int+1; m < highy_int; m++) { + temp = temp0; + for(l = lowx_int+1; l < highx_int; l++) { + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_2_BYTES(temp_index); + totals[k] += *(const GLshort*)&swapbuf; + } else { + totals[k] += *(const GLshort*)temp_index; + } + } + temp += group_size; + } + temp0 += ysize; + } + + outindex = (j + (i * widthout)) * components; + for (k = 0; k < components; k++) { + dataout[outindex + k] = totals[k]/area; + /*printf("totals[%d] = %f\n", k, totals[k]);*/ + } + lowx_int = highx_int; + lowx_float = highx_float; + highx_int += convx_int; + highx_float += convx_float; + if(highx_float > 1) { + highx_float -= 1.0; + highx_int++; + } + } + lowy_int = highy_int; + lowy_float = highy_float; + highy_int += convy_int; + highy_float += convy_float; + if(highy_float > 1) { + highy_float -= 1.0; + highy_int++; + } + } +} + +static void scale_internal_uint(GLint components, GLint widthin, + GLint heightin, const GLuint *datain, + GLint widthout, GLint heightout, + GLuint *dataout, GLint element_size, + GLint ysize, GLint group_size, + GLint myswap_bytes) +{ + float convx; + float convy; + float percent; + /* Max components in a format is 4, so... */ + float totals[4]; + float area; + int i,j,k,xindex; + + const char *temp, *temp0; + const char *temp_index; + int outindex; + + int lowx_int, highx_int, lowy_int, highy_int; + float x_percent, y_percent; + float lowx_float, highx_float, lowy_float, highy_float; + float convy_float, convx_float; + int convy_int, convx_int; + int l, m; + const char *left, *right; + + if (widthin == widthout*2 && heightin == heightout*2) { + halveImage_uint(components, widthin, heightin, + (const GLuint *)datain, (GLuint *)dataout, + element_size, ysize, group_size, myswap_bytes); + return; + } + convy = (float) heightin/heightout; + convx = (float) widthin/widthout; + convy_int = floor(convy); + convy_float = convy - convy_int; + convx_int = floor(convx); + convx_float = convx - convx_int; + + area = convx * convy; + + lowy_int = 0; + lowy_float = 0; + highy_int = convy_int; + highy_float = convy_float; + + for (i = 0; i < heightout; i++) { + /* Clamp here to be sure we don't read beyond input buffer. */ + if (highy_int >= heightin) + highy_int = heightin - 1; + lowx_int = 0; + lowx_float = 0; + highx_int = convx_int; + highx_float = convx_float; + + for (j = 0; j < widthout; j++) { + /* + ** Ok, now apply box filter to box that goes from (lowx, lowy) + ** to (highx, highy) on input data into this pixel on output + ** data. + */ + totals[0] = totals[1] = totals[2] = totals[3] = 0.0; + + /* calculate the value for pixels in the 1st row */ + xindex = lowx_int*group_size; + if((highy_int>lowy_int) && (highx_int>lowx_int)) { + + y_percent = 1-lowy_float; + temp = (const char *)datain + xindex + lowy_int * ysize; + percent = y_percent * (1-lowx_float); + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLuint*)temp_index * percent; + } + } + left = temp; + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_4_BYTES(temp_index) * y_percent; + } else { + totals[k] += *(const GLuint*)temp_index * y_percent; + } + } + } + temp += group_size; + right = temp; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLuint*)temp_index * percent; + } + } + + /* calculate the value for pixels in the last row */ + y_percent = highy_float; + percent = y_percent * (1-lowx_float); + temp = (const char *)datain + xindex + highy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLuint*)temp_index * percent; + } + } + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_4_BYTES(temp_index) * y_percent; + } else { + totals[k] += *(const GLuint*)temp_index * y_percent; + } + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLuint*)temp_index * percent; + } + } + + /* calculate the value for pixels in the 1st and last column */ + for(m = lowy_int+1; m < highy_int; m++) { + left += ysize; + right += ysize; + for (k = 0; k < components; + k++, left += element_size, right += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_4_BYTES(left) * (1-lowx_float) + + __GLU_SWAP_4_BYTES(right) * highx_float; + } else { + totals[k] += *(const GLuint*)left * (1-lowx_float) + + *(const GLuint*)right * highx_float; + } + } + } + } else if (highy_int > lowy_int) { + x_percent = highx_float - lowx_float; + percent = (1-lowy_float)*x_percent; + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLuint*)temp_index * percent; + } + } + for(m = lowy_int+1; m < highy_int; m++) { + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_4_BYTES(temp_index) * x_percent; + } else { + totals[k] += *(const GLuint*)temp_index * x_percent; + } + } + } + percent = x_percent * highy_float; + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLuint*)temp_index * percent; + } + } + } else if (highx_int > lowx_int) { + y_percent = highy_float - lowy_float; + percent = (1-lowx_float)*y_percent; + + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLuint*)temp_index * percent; + } + } + for (l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_4_BYTES(temp_index) * y_percent; + } else { + totals[k] += *(const GLuint*)temp_index * y_percent; + } + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLuint*)temp_index * percent; + } + } + } else { + percent = (highy_float-lowy_float)*(highx_float-lowx_float); + temp = (const char *)datain + xindex + lowy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLuint*)temp_index * percent; + } + } + } + + /* this is for the pixels in the body */ + temp0 = (const char *)datain + xindex + group_size + + (lowy_int+1)*ysize; + for (m = lowy_int+1; m < highy_int; m++) { + temp = temp0; + for(l = lowx_int+1; l < highx_int; l++) { + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_4_BYTES(temp_index); + } else { + totals[k] += *(const GLuint*)temp_index; + } + } + temp += group_size; + } + temp0 += ysize; + } + + outindex = (j + (i * widthout)) * components; + for (k = 0; k < components; k++) { + /* clamp at UINT_MAX */ + float value= totals[k]/area; + if (value >= (float) UINT_MAX) { /* need '=' */ + dataout[outindex + k] = UINT_MAX; + } + else dataout[outindex + k] = value; + } + lowx_int = highx_int; + lowx_float = highx_float; + highx_int += convx_int; + highx_float += convx_float; + if(highx_float > 1) { + highx_float -= 1.0; + highx_int++; + } + } + lowy_int = highy_int; + lowy_float = highy_float; + highy_int += convy_int; + highy_float += convy_float; + if(highy_float > 1) { + highy_float -= 1.0; + highy_int++; + } + } +} + + + +static void scale_internal_int(GLint components, GLint widthin, + GLint heightin, const GLint *datain, + GLint widthout, GLint heightout, + GLint *dataout, GLint element_size, + GLint ysize, GLint group_size, + GLint myswap_bytes) +{ + float convx; + float convy; + float percent; + /* Max components in a format is 4, so... */ + float totals[4]; + float area; + int i,j,k,xindex; + + const char *temp, *temp0; + const char *temp_index; + int outindex; + + int lowx_int, highx_int, lowy_int, highy_int; + float x_percent, y_percent; + float lowx_float, highx_float, lowy_float, highy_float; + float convy_float, convx_float; + int convy_int, convx_int; + int l, m; + const char *left, *right; + + GLuint swapbuf; /* unsigned buffer */ + + if (widthin == widthout*2 && heightin == heightout*2) { + halveImage_int(components, widthin, heightin, + (const GLint *)datain, (GLint *)dataout, + element_size, ysize, group_size, myswap_bytes); + return; + } + convy = (float) heightin/heightout; + convx = (float) widthin/widthout; + convy_int = floor(convy); + convy_float = convy - convy_int; + convx_int = floor(convx); + convx_float = convx - convx_int; + + area = convx * convy; + + lowy_int = 0; + lowy_float = 0; + highy_int = convy_int; + highy_float = convy_float; + + for (i = 0; i < heightout; i++) { + /* Clamp here to be sure we don't read beyond input buffer. */ + if (highy_int >= heightin) + highy_int = heightin - 1; + lowx_int = 0; + lowx_float = 0; + highx_int = convx_int; + highx_float = convx_float; + + for (j = 0; j < widthout; j++) { + /* + ** Ok, now apply box filter to box that goes from (lowx, lowy) + ** to (highx, highy) on input data into this pixel on output + ** data. + */ + totals[0] = totals[1] = totals[2] = totals[3] = 0.0; + + /* calculate the value for pixels in the 1st row */ + xindex = lowx_int*group_size; + if((highy_int>lowy_int) && (highx_int>lowx_int)) { + + y_percent = 1-lowy_float; + temp = (const char *)datain + xindex + lowy_int * ysize; + percent = y_percent * (1-lowx_float); + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * percent; + } else { + totals[k] += *(const GLint*)temp_index * percent; + } + } + left = temp; + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * y_percent; + } else { + totals[k] += *(const GLint*)temp_index * y_percent; + } + } + } + temp += group_size; + right = temp; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * percent; + } else { + totals[k] += *(const GLint*)temp_index * percent; + } + } + + /* calculate the value for pixels in the last row */ + y_percent = highy_float; + percent = y_percent * (1-lowx_float); + temp = (const char *)datain + xindex + highy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * percent; + } else { + totals[k] += *(const GLint*)temp_index * percent; + } + } + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * y_percent; + } else { + totals[k] += *(const GLint*)temp_index * y_percent; + } + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * percent; + } else { + totals[k] += *(const GLint*)temp_index * percent; + } + } + + /* calculate the value for pixels in the 1st and last column */ + for(m = lowy_int+1; m < highy_int; m++) { + left += ysize; + right += ysize; + for (k = 0; k < components; + k++, left += element_size, right += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(left); + totals[k] += *(const GLint*)&swapbuf * (1-lowx_float); + swapbuf = __GLU_SWAP_4_BYTES(right); + totals[k] += *(const GLint*)&swapbuf * highx_float; + } else { + totals[k] += *(const GLint*)left * (1-lowx_float) + + *(const GLint*)right * highx_float; + } + } + } + } else if (highy_int > lowy_int) { + x_percent = highx_float - lowx_float; + percent = (1-lowy_float)*x_percent; + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * percent; + } else { + totals[k] += *(const GLint*)temp_index * percent; + } + } + for(m = lowy_int+1; m < highy_int; m++) { + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * x_percent; + } else { + totals[k] += *(const GLint*)temp_index * x_percent; + } + } + } + percent = x_percent * highy_float; + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * percent; + } else { + totals[k] += *(const GLint*)temp_index * percent; + } + } + } else if (highx_int > lowx_int) { + y_percent = highy_float - lowy_float; + percent = (1-lowx_float)*y_percent; + + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * percent; + } else { + totals[k] += *(const GLint*)temp_index * percent; + } + } + for (l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * y_percent; + } else { + totals[k] += *(const GLint*)temp_index * y_percent; + } + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * percent; + } else { + totals[k] += *(const GLint*)temp_index * percent; + } + } + } else { + percent = (highy_float-lowy_float)*(highx_float-lowx_float); + temp = (const char *)datain + xindex + lowy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf * percent; + } else { + totals[k] += *(const GLint*)temp_index * percent; + } + } + } + + /* this is for the pixels in the body */ + temp0 = (const char *)datain + xindex + group_size + + (lowy_int+1)*ysize; + for (m = lowy_int+1; m < highy_int; m++) { + temp = temp0; + for(l = lowx_int+1; l < highx_int; l++) { + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += *(const GLint*)&swapbuf; + } else { + totals[k] += *(const GLint*)temp_index; + } + } + temp += group_size; + } + temp0 += ysize; + } + + outindex = (j + (i * widthout)) * components; + for (k = 0; k < components; k++) { + dataout[outindex + k] = totals[k]/area; + /*printf("totals[%d] = %f\n", k, totals[k]);*/ + } + lowx_int = highx_int; + lowx_float = highx_float; + highx_int += convx_int; + highx_float += convx_float; + if(highx_float > 1) { + highx_float -= 1.0; + highx_int++; + } + } + lowy_int = highy_int; + lowy_float = highy_float; + highy_int += convy_int; + highy_float += convy_float; + if(highy_float > 1) { + highy_float -= 1.0; + highy_int++; + } + } +} + + + +static void scale_internal_float(GLint components, GLint widthin, + GLint heightin, const GLfloat *datain, + GLint widthout, GLint heightout, + GLfloat *dataout, GLint element_size, + GLint ysize, GLint group_size, + GLint myswap_bytes) +{ + float convx; + float convy; + float percent; + /* Max components in a format is 4, so... */ + float totals[4]; + float area; + int i,j,k,xindex; + + const char *temp, *temp0; + const char *temp_index; + int outindex; + + int lowx_int, highx_int, lowy_int, highy_int; + float x_percent, y_percent; + float lowx_float, highx_float, lowy_float, highy_float; + float convy_float, convx_float; + int convy_int, convx_int; + int l, m; + const char *left, *right; + + union { GLuint b; GLfloat f; } swapbuf; + + if (widthin == widthout*2 && heightin == heightout*2) { + halveImage_float(components, widthin, heightin, + (const GLfloat *)datain, (GLfloat *)dataout, + element_size, ysize, group_size, myswap_bytes); + return; + } + convy = (float) heightin/heightout; + convx = (float) widthin/widthout; + convy_int = floor(convy); + convy_float = convy - convy_int; + convx_int = floor(convx); + convx_float = convx - convx_int; + + area = convx * convy; + + lowy_int = 0; + lowy_float = 0; + highy_int = convy_int; + highy_float = convy_float; + + for (i = 0; i < heightout; i++) { + /* Clamp here to be sure we don't read beyond input buffer. */ + if (highy_int >= heightin) + highy_int = heightin - 1; + lowx_int = 0; + lowx_float = 0; + highx_int = convx_int; + highx_float = convx_float; + + for (j = 0; j < widthout; j++) { + /* + ** Ok, now apply box filter to box that goes from (lowx, lowy) + ** to (highx, highy) on input data into this pixel on output + ** data. + */ + totals[0] = totals[1] = totals[2] = totals[3] = 0.0; + + /* calculate the value for pixels in the 1st row */ + xindex = lowx_int*group_size; + if((highy_int>lowy_int) && (highx_int>lowx_int)) { + + y_percent = 1-lowy_float; + temp = (const char *)datain + xindex + lowy_int * ysize; + percent = y_percent * (1-lowx_float); + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * percent; + } else { + totals[k] += *(const GLfloat*)temp_index * percent; + } + } + left = temp; + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * y_percent; + } else { + totals[k] += *(const GLfloat*)temp_index * y_percent; + } + } + } + temp += group_size; + right = temp; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * percent; + } else { + totals[k] += *(const GLfloat*)temp_index * percent; + } + } + + /* calculate the value for pixels in the last row */ + y_percent = highy_float; + percent = y_percent * (1-lowx_float); + temp = (const char *)datain + xindex + highy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * percent; + } else { + totals[k] += *(const GLfloat*)temp_index * percent; + } + } + for(l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * y_percent; + } else { + totals[k] += *(const GLfloat*)temp_index * y_percent; + } + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * percent; + } else { + totals[k] += *(const GLfloat*)temp_index * percent; + } + } + + /* calculate the value for pixels in the 1st and last column */ + for(m = lowy_int+1; m < highy_int; m++) { + left += ysize; + right += ysize; + for (k = 0; k < components; + k++, left += element_size, right += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(left); + totals[k] += swapbuf.f * (1-lowx_float); + swapbuf.b = __GLU_SWAP_4_BYTES(right); + totals[k] += swapbuf.f * highx_float; + } else { + totals[k] += *(const GLfloat*)left * (1-lowx_float) + + *(const GLfloat*)right * highx_float; + } + } + } + } else if (highy_int > lowy_int) { + x_percent = highx_float - lowx_float; + percent = (1-lowy_float)*x_percent; + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * percent; + } else { + totals[k] += *(const GLfloat*)temp_index * percent; + } + } + for(m = lowy_int+1; m < highy_int; m++) { + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * x_percent; + } else { + totals[k] += *(const GLfloat*)temp_index * x_percent; + } + } + } + percent = x_percent * highy_float; + temp += ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * percent; + } else { + totals[k] += *(const GLfloat*)temp_index * percent; + } + } + } else if (highx_int > lowx_int) { + y_percent = highy_float - lowy_float; + percent = (1-lowx_float)*y_percent; + + temp = (const char *)datain + xindex + lowy_int*ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * percent; + } else { + totals[k] += *(const GLfloat*)temp_index * percent; + } + } + for (l = lowx_int+1; l < highx_int; l++) { + temp += group_size; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * y_percent; + } else { + totals[k] += *(const GLfloat*)temp_index * y_percent; + } + } + } + temp += group_size; + percent = y_percent * highx_float; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * percent; + } else { + totals[k] += *(const GLfloat*)temp_index * percent; + } + } + } else { + percent = (highy_float-lowy_float)*(highx_float-lowx_float); + temp = (const char *)datain + xindex + lowy_int * ysize; + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f * percent; + } else { + totals[k] += *(const GLfloat*)temp_index * percent; + } + } + } + + /* this is for the pixels in the body */ + temp0 = (const char *)datain + xindex + group_size + + (lowy_int+1)*ysize; + for (m = lowy_int+1; m < highy_int; m++) { + temp = temp0; + for(l = lowx_int+1; l < highx_int; l++) { + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); + totals[k] += swapbuf.f; + } else { + totals[k] += *(const GLfloat*)temp_index; + } + } + temp += group_size; + } + temp0 += ysize; + } + + outindex = (j + (i * widthout)) * components; + for (k = 0; k < components; k++) { + dataout[outindex + k] = totals[k]/area; + /*printf("totals[%d] = %f\n", k, totals[k]);*/ + } + lowx_int = highx_int; + lowx_float = highx_float; + highx_int += convx_int; + highx_float += convx_float; + if(highx_float > 1) { + highx_float -= 1.0; + highx_int++; + } + } + lowy_int = highy_int; + lowy_float = highy_float; + highy_int += convy_int; + highy_float += convy_float; + if(highy_float > 1) { + highy_float -= 1.0; + highy_int++; + } + } +} + +static int checkMipmapArgs(GLenum internalFormat, GLenum format, GLenum type) +{ + if (!legalFormat(format) || !legalType(type)) { + return GLU_INVALID_ENUM; + } + if (format == GL_STENCIL_INDEX) { + return GLU_INVALID_ENUM; + } + + if (!isLegalFormatForPackedPixelType(format, type)) { + return GLU_INVALID_OPERATION; + } + + return 0; +} /* checkMipmapArgs() */ + +static GLboolean legalFormat(GLenum format) +{ + 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_RGB: + case GL_RGBA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_BGR: + case GL_BGRA: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +static GLboolean legalType(GLenum type) +{ + switch(type) { + case GL_BITMAP: + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + return GL_TRUE; + default: + return GL_FALSE; + } +} + +/* */ +static GLboolean isTypePackedPixel(GLenum type) +{ + assert(legalType(type)); + + if (type == GL_UNSIGNED_BYTE_3_3_2 || + type == GL_UNSIGNED_BYTE_2_3_3_REV || + type == GL_UNSIGNED_SHORT_5_6_5 || + type == GL_UNSIGNED_SHORT_5_6_5_REV || + type == GL_UNSIGNED_SHORT_4_4_4_4 || + type == GL_UNSIGNED_SHORT_4_4_4_4_REV || + type == GL_UNSIGNED_SHORT_5_5_5_1 || + type == GL_UNSIGNED_SHORT_1_5_5_5_REV || + type == GL_UNSIGNED_INT_8_8_8_8 || + type == GL_UNSIGNED_INT_8_8_8_8_REV || + type == GL_UNSIGNED_INT_10_10_10_2 || + type == GL_UNSIGNED_INT_2_10_10_10_REV) { + return 1; + } + else return 0; +} /* isTypePackedPixel() */ + +/* Determines if the packed pixel type is compatible with the format */ +static GLboolean isLegalFormatForPackedPixelType(GLenum format, GLenum type) +{ + /* if not a packed pixel type then return true */ + if (!isTypePackedPixel(type)) { + return GL_TRUE; + } + + /* 3_3_2/2_3_3_REV & 5_6_5/5_6_5_REV are only compatible with RGB */ + if ((type == GL_UNSIGNED_BYTE_3_3_2 || type == GL_UNSIGNED_BYTE_2_3_3_REV|| + type == GL_UNSIGNED_SHORT_5_6_5|| type == GL_UNSIGNED_SHORT_5_6_5_REV) + && format != GL_RGB) + return GL_FALSE; + + /* 4_4_4_4/4_4_4_4_REV & 5_5_5_1/1_5_5_5_REV & 8_8_8_8/8_8_8_8_REV & + * 10_10_10_2/2_10_10_10_REV are only compatible with RGBA, BGRA & ABGR_EXT. + */ + if ((type == GL_UNSIGNED_SHORT_4_4_4_4 || + type == GL_UNSIGNED_SHORT_4_4_4_4_REV || + type == GL_UNSIGNED_SHORT_5_5_5_1 || + type == GL_UNSIGNED_SHORT_1_5_5_5_REV || + type == GL_UNSIGNED_INT_8_8_8_8 || + type == GL_UNSIGNED_INT_8_8_8_8_REV || + type == GL_UNSIGNED_INT_10_10_10_2 || + type == GL_UNSIGNED_INT_2_10_10_10_REV) && + (format != GL_RGBA && + format != GL_BGRA)) { + return GL_FALSE; + } + + return GL_TRUE; +} /* isLegalFormatForPackedPixelType() */ + +static GLboolean isLegalLevels(GLint userLevel,GLint baseLevel,GLint maxLevel, + GLint totalLevels) +{ + if (baseLevel < 0 || baseLevel < userLevel || maxLevel < baseLevel || + totalLevels < maxLevel) + return GL_FALSE; + else return GL_TRUE; +} /* isLegalLevels() */ + +/* Given user requested texture size, determine if it fits. If it + * doesn't then halve both sides and make the determination again + * until it does fit (for IR only). + * Note that proxy textures are not implemented in RE* even though + * they advertise the texture extension. + * Note that proxy textures are implemented but not according to spec in + * IMPACT*. + */ +static void closestFit(GLenum target, GLint width, GLint height, + GLint internalFormat, GLenum format, GLenum type, + GLint *newWidth, GLint *newHeight) +{ + /* Use proxy textures if OpenGL version is >= 1.1 */ + if ( (strtod((const char *)glGetString(GL_VERSION),NULL) >= 1.1) + ) { + GLint widthPowerOf2= nearestPower(width); + GLint heightPowerOf2= nearestPower(height); + GLint proxyWidth; + + do { + /* compute level 1 width & height, clamping each at 1 */ + GLint widthAtLevelOne= (widthPowerOf2 > 1) ? + widthPowerOf2 >> 1 : + widthPowerOf2; + GLint heightAtLevelOne= (heightPowerOf2 > 1) ? + heightPowerOf2 >> 1 : + heightPowerOf2; + GLenum proxyTarget; + assert(widthAtLevelOne > 0); assert(heightAtLevelOne > 0); + + /* does width x height at level 1 & all their mipmaps fit? */ + if (target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D) { + proxyTarget = GL_PROXY_TEXTURE_2D; + glTexImage2D(proxyTarget, 1, /* must be non-zero */ + internalFormat, + widthAtLevelOne,heightAtLevelOne,0,format,type,NULL); + } else +#if defined(GL_ARB_texture_cube_map) + if ((target == GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB) || + (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB) || + (target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB) || + (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB) || + (target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB) || + (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) { + proxyTarget = GL_PROXY_TEXTURE_CUBE_MAP_ARB; + glTexImage2D(proxyTarget, 1, /* must be non-zero */ + internalFormat, + widthAtLevelOne,heightAtLevelOne,0,format,type,NULL); + } else +#endif /* GL_ARB_texture_cube_map */ + { + assert(target == GL_TEXTURE_1D || target == GL_PROXY_TEXTURE_1D); + proxyTarget = GL_PROXY_TEXTURE_1D; + glTexImage1D(proxyTarget, 1, /* must be non-zero */ + internalFormat,widthAtLevelOne,0,format,type,NULL); + } + glGetTexLevelParameteriv(proxyTarget, 1,GL_TEXTURE_WIDTH,&proxyWidth); + /* does it fit??? */ + if (proxyWidth == 0) { /* nope, so try again with these sizes */ + if (widthPowerOf2 == 1 && heightPowerOf2 == 1) { + /* An 1x1 texture couldn't fit for some reason, so + * break out. This should never happen. But things + * happen. The disadvantage with this if-statement is + * that we will never be aware of when this happens + * since it will silently branch out. + */ + goto noProxyTextures; + } + widthPowerOf2= widthAtLevelOne; + heightPowerOf2= heightAtLevelOne; + } + /* else it does fit */ + } while (proxyWidth == 0); + /* loop must terminate! */ + + /* return the width & height at level 0 that fits */ + *newWidth= widthPowerOf2; + *newHeight= heightPowerOf2; +/*printf("Proxy Textures\n");*/ + } /* if gluCheckExtension() */ + else { /* no texture extension, so do this instead */ + GLint maxsize; + +noProxyTextures: + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); + /* clamp user's texture sizes to maximum sizes, if necessary */ + *newWidth = nearestPower(width); + if (*newWidth > maxsize) *newWidth = maxsize; + *newHeight = nearestPower(height); + if (*newHeight > maxsize) *newHeight = maxsize; +/*printf("NO proxy textures\n");*/ + } +} /* closestFit() */ + +GLint GLAPIENTRY +gluScaleImage(GLenum format, GLsizei widthin, GLsizei heightin, + GLenum typein, const void *datain, + GLsizei widthout, GLsizei heightout, GLenum typeout, + void *dataout) +{ + int components; + GLushort *beforeImage; + GLushort *afterImage; + PixelStorageModes psm; + + if (widthin == 0 || heightin == 0 || widthout == 0 || heightout == 0) { + return 0; + } + if (widthin < 0 || heightin < 0 || widthout < 0 || heightout < 0) { + return GLU_INVALID_VALUE; + } + if (!legalFormat(format) || !legalType(typein) || !legalType(typeout)) { + return GLU_INVALID_ENUM; + } + if (!isLegalFormatForPackedPixelType(format, typein)) { + return GLU_INVALID_OPERATION; + } + if (!isLegalFormatForPackedPixelType(format, typeout)) { + return GLU_INVALID_OPERATION; + } + beforeImage = + malloc(image_size(widthin, heightin, format, GL_UNSIGNED_SHORT)); + afterImage = + malloc(image_size(widthout, heightout, format, GL_UNSIGNED_SHORT)); + if (beforeImage == NULL || afterImage == NULL) { + return GLU_OUT_OF_MEMORY; + } + + retrieveStoreModes(&psm); + fill_image(&psm,widthin, heightin, format, typein, is_index(format), + datain, beforeImage); + components = elements_per_group(format, 0); + scale_internal(components, widthin, heightin, beforeImage, + widthout, heightout, afterImage); + empty_image(&psm,widthout, heightout, format, typeout, + is_index(format), afterImage, dataout); + free((GLbyte *) beforeImage); + free((GLbyte *) afterImage); + + return 0; +} + +int gluBuild1DMipmapLevelsCore(GLenum target, GLint internalFormat, + GLsizei width, + GLsizei widthPowerOf2, + GLenum format, GLenum type, + GLint userLevel, GLint baseLevel,GLint maxLevel, + const void *data) +{ + GLint newwidth; + GLint level, levels; + GLushort *newImage; + GLint newImage_width; + GLushort *otherImage; + GLushort *imageTemp; + GLint memreq; + GLint cmpts; + PixelStorageModes psm; + + assert(checkMipmapArgs(internalFormat,format,type) == 0); + assert(width >= 1); + + otherImage = NULL; + + newwidth= widthPowerOf2; + levels = computeLog(newwidth); + + levels+= userLevel; + + retrieveStoreModes(&psm); + newImage = (GLushort *) + malloc(image_size(width, 1, format, GL_UNSIGNED_SHORT)); + newImage_width = width; + if (newImage == NULL) { + return GLU_OUT_OF_MEMORY; + } + fill_image(&psm,width, 1, format, type, is_index(format), + data, newImage); + cmpts = elements_per_group(format,type); + glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + /* + ** If swap_bytes was set, swapping occurred in fill_image. + */ + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + + for (level = userLevel; level <= levels; level++) { + if (newImage_width == newwidth) { + /* Use newImage for this level */ + if (baseLevel <= level && level <= maxLevel) { + glTexImage1D(target, level, internalFormat, newImage_width, + 0, format, GL_UNSIGNED_SHORT, (void *) newImage); + } + } else { + if (otherImage == NULL) { + memreq = image_size(newwidth, 1, format, GL_UNSIGNED_SHORT); + otherImage = (GLushort *) malloc(memreq); + if (otherImage == NULL) { + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS,psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + return GLU_OUT_OF_MEMORY; + } + } + scale_internal(cmpts, newImage_width, 1, newImage, + newwidth, 1, otherImage); + /* Swap newImage and otherImage */ + imageTemp = otherImage; + otherImage = newImage; + newImage = imageTemp; + + newImage_width = newwidth; + if (baseLevel <= level && level <= maxLevel) { + glTexImage1D(target, level, internalFormat, newImage_width, + 0, format, GL_UNSIGNED_SHORT, (void *) newImage); + } + } + if (newwidth > 1) newwidth /= 2; + } + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + + free((GLbyte *) newImage); + if (otherImage) { + free((GLbyte *) otherImage); + } + return 0; +} + +GLint GLAPIENTRY +gluBuild1DMipmapLevels(GLenum target, GLint internalFormat, + GLsizei width, + GLenum format, GLenum type, + GLint userLevel, GLint baseLevel, GLint maxLevel, + const void *data) +{ + int levels; + + int rc= checkMipmapArgs(internalFormat,format,type); + if (rc != 0) return rc; + + if (width < 1) { + return GLU_INVALID_VALUE; + } + + levels = computeLog(width); + + levels+= userLevel; + if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels)) + return GLU_INVALID_VALUE; + + return gluBuild1DMipmapLevelsCore(target, internalFormat, + width, + width,format, type, + userLevel, baseLevel, maxLevel, + data); +} /* gluBuild1DMipmapLevels() */ + +GLint GLAPIENTRY +gluBuild1DMipmaps(GLenum target, GLint internalFormat, GLsizei width, + GLenum format, GLenum type, + const void *data) +{ + GLint widthPowerOf2; + int levels; + GLint dummy; + + int rc= checkMipmapArgs(internalFormat,format,type); + if (rc != 0) return rc; + + if (width < 1) { + return GLU_INVALID_VALUE; + } + + closestFit(target,width,1,internalFormat,format,type,&widthPowerOf2,&dummy); + levels = computeLog(widthPowerOf2); + + return gluBuild1DMipmapLevelsCore(target,internalFormat, + width, + widthPowerOf2, + format,type,0,0,levels,data); +} + +static int bitmapBuild2DMipmaps(GLenum target, GLint internalFormat, + GLint width, GLint height, GLenum format, + GLenum type, const void *data) +{ + GLint newwidth, newheight; + GLint level, levels; + GLushort *newImage; + GLint newImage_width; + GLint newImage_height; + GLushort *otherImage; + GLushort *imageTemp; + GLint memreq; + GLint cmpts; + PixelStorageModes psm; + + retrieveStoreModes(&psm); + +#if 0 + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); + newwidth = nearestPower(width); + if (newwidth > maxsize) newwidth = maxsize; + newheight = nearestPower(height); + if (newheight > maxsize) newheight = maxsize; +#else + closestFit(target,width,height,internalFormat,format,type, + &newwidth,&newheight); +#endif + levels = computeLog(newwidth); + level = computeLog(newheight); + if (level > levels) levels=level; + + otherImage = NULL; + newImage = (GLushort *) + malloc(image_size(width, height, format, GL_UNSIGNED_SHORT)); + newImage_width = width; + newImage_height = height; + if (newImage == NULL) { + return GLU_OUT_OF_MEMORY; + } + + fill_image(&psm,width, height, format, type, is_index(format), + data, newImage); + + cmpts = elements_per_group(format,type); + glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + /* + ** If swap_bytes was set, swapping occurred in fill_image. + */ + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + + for (level = 0; level <= levels; level++) { + if (newImage_width == newwidth && newImage_height == newheight) { /* Use newImage for this level */ + glTexImage2D(target, level, internalFormat, newImage_width, + newImage_height, 0, format, GL_UNSIGNED_SHORT, + (void *) newImage); + } else { + if (otherImage == NULL) { + memreq = + image_size(newwidth, newheight, format, GL_UNSIGNED_SHORT); + otherImage = (GLushort *) malloc(memreq); + if (otherImage == NULL) { + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS,psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + return GLU_OUT_OF_MEMORY; + } + } + scale_internal(cmpts, newImage_width, newImage_height, newImage, + newwidth, newheight, otherImage); + /* Swap newImage and otherImage */ + imageTemp = otherImage; + otherImage = newImage; + newImage = imageTemp; + + newImage_width = newwidth; + newImage_height = newheight; + glTexImage2D(target, level, internalFormat, newImage_width, + newImage_height, 0, format, GL_UNSIGNED_SHORT, + (void *) newImage); + } + if (newwidth > 1) newwidth /= 2; + if (newheight > 1) newheight /= 2; + } + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + + free((GLbyte *) newImage); + if (otherImage) { + free((GLbyte *) otherImage); + } + return 0; +} + +/* To make swapping images less error prone */ +#define __GLU_INIT_SWAP_IMAGE void *tmpImage +#define __GLU_SWAP_IMAGE(a,b) tmpImage = a; a = b; b = tmpImage; + +static int gluBuild2DMipmapLevelsCore(GLenum target, GLint internalFormat, + GLsizei width, GLsizei height, + GLsizei widthPowerOf2, + GLsizei heightPowerOf2, + GLenum format, GLenum type, + GLint userLevel, + GLint baseLevel,GLint maxLevel, + const void *data) +{ + GLint newwidth, newheight; + GLint level, levels; + const void *usersImage; /* passed from user. Don't touch! */ + void *srcImage, *dstImage; /* scratch area to build mipmapped images */ + __GLU_INIT_SWAP_IMAGE; + GLint memreq; + GLint cmpts; + + GLint myswap_bytes, groups_per_line, element_size, group_size; + GLint rowsize, padding; + PixelStorageModes psm; + + assert(checkMipmapArgs(internalFormat,format,type) == 0); + assert(width >= 1 && height >= 1); + + if(type == GL_BITMAP) { + return bitmapBuild2DMipmaps(target, internalFormat, width, height, + format, type, data); + } + + srcImage = dstImage = NULL; + + newwidth= widthPowerOf2; + newheight= heightPowerOf2; + levels = computeLog(newwidth); + level = computeLog(newheight); + if (level > levels) levels=level; + + levels+= userLevel; + + retrieveStoreModes(&psm); + myswap_bytes = psm.unpack_swap_bytes; + cmpts = elements_per_group(format,type); + if (psm.unpack_row_length > 0) { + groups_per_line = psm.unpack_row_length; + } else { + groups_per_line = width; + } + + element_size = bytes_per_element(type); + group_size = element_size * cmpts; + if (element_size == 1) myswap_bytes = 0; + + rowsize = groups_per_line * group_size; + padding = (rowsize % psm.unpack_alignment); + if (padding) { + rowsize += psm.unpack_alignment - padding; + } + usersImage = (const GLubyte *) data + psm.unpack_skip_rows * rowsize + + psm.unpack_skip_pixels * group_size; + + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + level = userLevel; + + /* already power-of-two square */ + if (width == newwidth && height == newheight) { + /* Use usersImage for level userLevel */ + if (baseLevel <= level && level <= maxLevel) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glTexImage2D(target, level, internalFormat, width, + height, 0, format, type, + usersImage); + } + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + if(levels == 0) { /* we're done. clean up and return */ + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + return 0; + } + { + int nextWidth= newwidth/2; + int nextHeight= newheight/2; + + /* clamp to 1 */ + if (nextWidth < 1) nextWidth= 1; + if (nextHeight < 1) nextHeight= 1; + memreq = image_size(nextWidth, nextHeight, format, type); + } + + switch(type) { + case GL_UNSIGNED_BYTE: + dstImage = (GLubyte *)malloc(memreq); + break; + case GL_BYTE: + dstImage = (GLbyte *)malloc(memreq); + break; + case GL_UNSIGNED_SHORT: + dstImage = (GLushort *)malloc(memreq); + break; + case GL_SHORT: + dstImage = (GLshort *)malloc(memreq); + break; + case GL_UNSIGNED_INT: + dstImage = (GLuint *)malloc(memreq); + break; + case GL_INT: + dstImage = (GLint *)malloc(memreq); + break; + case GL_FLOAT: + dstImage = (GLfloat *)malloc(memreq); + break; + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + dstImage = (GLubyte *)malloc(memreq); + break; + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + dstImage = (GLushort *)malloc(memreq); + break; + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + dstImage = (GLuint *)malloc(memreq); + break; + default: + return GLU_INVALID_ENUM; + } + if (dstImage == NULL) { + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + return GLU_OUT_OF_MEMORY; + } + else + switch(type) { + case GL_UNSIGNED_BYTE: + halveImage_ubyte(cmpts, width, height, + (const GLubyte *)usersImage, (GLubyte *)dstImage, + element_size, rowsize, group_size); + break; + case GL_BYTE: + halveImage_byte(cmpts, width, height, + (const GLbyte *)usersImage, (GLbyte *)dstImage, + element_size, rowsize, group_size); + break; + case GL_UNSIGNED_SHORT: + halveImage_ushort(cmpts, width, height, + (const GLushort *)usersImage, (GLushort *)dstImage, + element_size, rowsize, group_size, myswap_bytes); + break; + case GL_SHORT: + halveImage_short(cmpts, width, height, + (const GLshort *)usersImage, (GLshort *)dstImage, + element_size, rowsize, group_size, myswap_bytes); + break; + case GL_UNSIGNED_INT: + halveImage_uint(cmpts, width, height, + (const GLuint *)usersImage, (GLuint *)dstImage, + element_size, rowsize, group_size, myswap_bytes); + break; + case GL_INT: + halveImage_int(cmpts, width, height, + (const GLint *)usersImage, (GLint *)dstImage, + element_size, rowsize, group_size, myswap_bytes); + break; + case GL_FLOAT: + halveImage_float(cmpts, width, height, + (const GLfloat *)usersImage, (GLfloat *)dstImage, + element_size, rowsize, group_size, myswap_bytes); + break; + case GL_UNSIGNED_BYTE_3_3_2: + assert(format == GL_RGB); + halveImagePackedPixel(3,extract332,shove332, + width,height,usersImage,dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_BYTE_2_3_3_REV: + assert(format == GL_RGB); + halveImagePackedPixel(3,extract233rev,shove233rev, + width,height,usersImage,dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_SHORT_5_6_5: + halveImagePackedPixel(3,extract565,shove565, + width,height,usersImage,dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_SHORT_5_6_5_REV: + halveImagePackedPixel(3,extract565rev,shove565rev, + width,height,usersImage,dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + halveImagePackedPixel(4,extract4444,shove4444, + width,height,usersImage,dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + halveImagePackedPixel(4,extract4444rev,shove4444rev, + width,height,usersImage,dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_SHORT_5_5_5_1: + halveImagePackedPixel(4,extract5551,shove5551, + width,height,usersImage,dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + halveImagePackedPixel(4,extract1555rev,shove1555rev, + width,height,usersImage,dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_INT_8_8_8_8: + halveImagePackedPixel(4,extract8888,shove8888, + width,height,usersImage,dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + halveImagePackedPixel(4,extract8888rev,shove8888rev, + width,height,usersImage,dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_INT_10_10_10_2: + halveImagePackedPixel(4,extract1010102,shove1010102, + width,height,usersImage,dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + halveImagePackedPixel(4,extract2101010rev,shove2101010rev, + width,height,usersImage,dstImage, + element_size,rowsize,myswap_bytes); + break; + default: + assert(0); + break; + } + newwidth = width/2; + newheight = height/2; + /* clamp to 1 */ + if (newwidth < 1) newwidth= 1; + if (newheight < 1) newheight= 1; + + myswap_bytes = 0; + rowsize = newwidth * group_size; + memreq = image_size(newwidth, newheight, format, type); + /* Swap srcImage and dstImage */ + __GLU_SWAP_IMAGE(srcImage,dstImage); + switch(type) { + case GL_UNSIGNED_BYTE: + dstImage = (GLubyte *)malloc(memreq); + break; + case GL_BYTE: + dstImage = (GLbyte *)malloc(memreq); + break; + case GL_UNSIGNED_SHORT: + dstImage = (GLushort *)malloc(memreq); + break; + case GL_SHORT: + dstImage = (GLshort *)malloc(memreq); + break; + case GL_UNSIGNED_INT: + dstImage = (GLuint *)malloc(memreq); + break; + case GL_INT: + dstImage = (GLint *)malloc(memreq); + break; + case GL_FLOAT: + dstImage = (GLfloat *)malloc(memreq); + break; + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + dstImage = (GLubyte *)malloc(memreq); + break; + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + dstImage = (GLushort *)malloc(memreq); + break; + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + dstImage = (GLuint *)malloc(memreq); + break; + default: + return GLU_INVALID_ENUM; + } + if (dstImage == NULL) { + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + return GLU_OUT_OF_MEMORY; + } + /* level userLevel+1 is in srcImage; level userLevel already saved */ + level = userLevel+1; + } else { /* user's image is *not* nice power-of-2 sized square */ + memreq = image_size(newwidth, newheight, format, type); + switch(type) { + case GL_UNSIGNED_BYTE: + dstImage = (GLubyte *)malloc(memreq); + break; + case GL_BYTE: + dstImage = (GLbyte *)malloc(memreq); + break; + case GL_UNSIGNED_SHORT: + dstImage = (GLushort *)malloc(memreq); + break; + case GL_SHORT: + dstImage = (GLshort *)malloc(memreq); + break; + case GL_UNSIGNED_INT: + dstImage = (GLuint *)malloc(memreq); + break; + case GL_INT: + dstImage = (GLint *)malloc(memreq); + break; + case GL_FLOAT: + dstImage = (GLfloat *)malloc(memreq); + break; + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + dstImage = (GLubyte *)malloc(memreq); + break; + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + dstImage = (GLushort *)malloc(memreq); + break; + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + dstImage = (GLuint *)malloc(memreq); + break; + default: + return GLU_INVALID_ENUM; + } + + if (dstImage == NULL) { + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + return GLU_OUT_OF_MEMORY; + } + + switch(type) { + case GL_UNSIGNED_BYTE: + scale_internal_ubyte(cmpts, width, height, + (const GLubyte *)usersImage, newwidth, newheight, + (GLubyte *)dstImage, element_size, + rowsize, group_size); + break; + case GL_BYTE: + scale_internal_byte(cmpts, width, height, + (const GLbyte *)usersImage, newwidth, newheight, + (GLbyte *)dstImage, element_size, + rowsize, group_size); + break; + case GL_UNSIGNED_SHORT: + scale_internal_ushort(cmpts, width, height, + (const GLushort *)usersImage, newwidth, newheight, + (GLushort *)dstImage, element_size, + rowsize, group_size, myswap_bytes); + break; + case GL_SHORT: + scale_internal_short(cmpts, width, height, + (const GLshort *)usersImage, newwidth, newheight, + (GLshort *)dstImage, element_size, + rowsize, group_size, myswap_bytes); + break; + case GL_UNSIGNED_INT: + scale_internal_uint(cmpts, width, height, + (const GLuint *)usersImage, newwidth, newheight, + (GLuint *)dstImage, element_size, + rowsize, group_size, myswap_bytes); + break; + case GL_INT: + scale_internal_int(cmpts, width, height, + (const GLint *)usersImage, newwidth, newheight, + (GLint *)dstImage, element_size, + rowsize, group_size, myswap_bytes); + break; + case GL_FLOAT: + scale_internal_float(cmpts, width, height, + (const GLfloat *)usersImage, newwidth, newheight, + (GLfloat *)dstImage, element_size, + rowsize, group_size, myswap_bytes); + break; + case GL_UNSIGNED_BYTE_3_3_2: + scaleInternalPackedPixel(3,extract332,shove332, + width, height,usersImage, + newwidth,newheight,(void *)dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_BYTE_2_3_3_REV: + scaleInternalPackedPixel(3,extract233rev,shove233rev, + width, height,usersImage, + newwidth,newheight,(void *)dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_SHORT_5_6_5: + scaleInternalPackedPixel(3,extract565,shove565, + width, height,usersImage, + newwidth,newheight,(void *)dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_SHORT_5_6_5_REV: + scaleInternalPackedPixel(3,extract565rev,shove565rev, + width, height,usersImage, + newwidth,newheight,(void *)dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + scaleInternalPackedPixel(4,extract4444,shove4444, + width, height,usersImage, + newwidth,newheight,(void *)dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + scaleInternalPackedPixel(4,extract4444rev,shove4444rev, + width, height,usersImage, + newwidth,newheight,(void *)dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_SHORT_5_5_5_1: + scaleInternalPackedPixel(4,extract5551,shove5551, + width, height,usersImage, + newwidth,newheight,(void *)dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + scaleInternalPackedPixel(4,extract1555rev,shove1555rev, + width, height,usersImage, + newwidth,newheight,(void *)dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_INT_8_8_8_8: + scaleInternalPackedPixel(4,extract8888,shove8888, + width, height,usersImage, + newwidth,newheight,(void *)dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + scaleInternalPackedPixel(4,extract8888rev,shove8888rev, + width, height,usersImage, + newwidth,newheight,(void *)dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_INT_10_10_10_2: + scaleInternalPackedPixel(4,extract1010102,shove1010102, + width, height,usersImage, + newwidth,newheight,(void *)dstImage, + element_size,rowsize,myswap_bytes); + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + scaleInternalPackedPixel(4,extract2101010rev,shove2101010rev, + width, height,usersImage, + newwidth,newheight,(void *)dstImage, + element_size,rowsize,myswap_bytes); + break; + default: + assert(0); + break; + } + myswap_bytes = 0; + rowsize = newwidth * group_size; + /* Swap dstImage and srcImage */ + __GLU_SWAP_IMAGE(srcImage,dstImage); + + if(levels != 0) { /* use as little memory as possible */ + { + int nextWidth= newwidth/2; + int nextHeight= newheight/2; + if (nextWidth < 1) nextWidth= 1; + if (nextHeight < 1) nextHeight= 1; + + memreq = image_size(nextWidth, nextHeight, format, type); + } + + switch(type) { + case GL_UNSIGNED_BYTE: + dstImage = (GLubyte *)malloc(memreq); + break; + case GL_BYTE: + dstImage = (GLbyte *)malloc(memreq); + break; + case GL_UNSIGNED_SHORT: + dstImage = (GLushort *)malloc(memreq); + break; + case GL_SHORT: + dstImage = (GLshort *)malloc(memreq); + break; + case GL_UNSIGNED_INT: + dstImage = (GLuint *)malloc(memreq); + break; + case GL_INT: + dstImage = (GLint *)malloc(memreq); + break; + case GL_FLOAT: + dstImage = (GLfloat *)malloc(memreq); + break; + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + dstImage = (GLubyte *)malloc(memreq); + break; + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + dstImage = (GLushort *)malloc(memreq); + break; + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + dstImage = (GLuint *)malloc(memreq); + break; + default: + return GLU_INVALID_ENUM; + } + if (dstImage == NULL) { + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + return GLU_OUT_OF_MEMORY; + } + } + /* level userLevel is in srcImage; nothing saved yet */ + level = userLevel; + } + + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + if (baseLevel <= level && level <= maxLevel) { + glTexImage2D(target, level, internalFormat, newwidth, newheight, 0, + format, type, (void *)srcImage); + } + + level++; /* update current level for the loop */ + for (; level <= levels; level++) { + switch(type) { + case GL_UNSIGNED_BYTE: + halveImage_ubyte(cmpts, newwidth, newheight, + (GLubyte *)srcImage, (GLubyte *)dstImage, element_size, + rowsize, group_size); + break; + case GL_BYTE: + halveImage_byte(cmpts, newwidth, newheight, + (GLbyte *)srcImage, (GLbyte *)dstImage, element_size, + rowsize, group_size); + break; + case GL_UNSIGNED_SHORT: + halveImage_ushort(cmpts, newwidth, newheight, + (GLushort *)srcImage, (GLushort *)dstImage, element_size, + rowsize, group_size, myswap_bytes); + break; + case GL_SHORT: + halveImage_short(cmpts, newwidth, newheight, + (GLshort *)srcImage, (GLshort *)dstImage, element_size, + rowsize, group_size, myswap_bytes); + break; + case GL_UNSIGNED_INT: + halveImage_uint(cmpts, newwidth, newheight, + (GLuint *)srcImage, (GLuint *)dstImage, element_size, + rowsize, group_size, myswap_bytes); + break; + case GL_INT: + halveImage_int(cmpts, newwidth, newheight, + (GLint *)srcImage, (GLint *)dstImage, element_size, + rowsize, group_size, myswap_bytes); + break; + case GL_FLOAT: + halveImage_float(cmpts, newwidth, newheight, + (GLfloat *)srcImage, (GLfloat *)dstImage, element_size, + rowsize, group_size, myswap_bytes); + break; + case GL_UNSIGNED_BYTE_3_3_2: + halveImagePackedPixel(3,extract332,shove332, + newwidth,newheight, + srcImage,dstImage,element_size,rowsize, + myswap_bytes); + break; + case GL_UNSIGNED_BYTE_2_3_3_REV: + halveImagePackedPixel(3,extract233rev,shove233rev, + newwidth,newheight, + srcImage,dstImage,element_size,rowsize, + myswap_bytes); + break; + case GL_UNSIGNED_SHORT_5_6_5: + halveImagePackedPixel(3,extract565,shove565, + newwidth,newheight, + srcImage,dstImage,element_size,rowsize, + myswap_bytes); + break; + case GL_UNSIGNED_SHORT_5_6_5_REV: + halveImagePackedPixel(3,extract565rev,shove565rev, + newwidth,newheight, + srcImage,dstImage,element_size,rowsize, + myswap_bytes); + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + halveImagePackedPixel(4,extract4444,shove4444, + newwidth,newheight, + srcImage,dstImage,element_size,rowsize, + myswap_bytes); + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + halveImagePackedPixel(4,extract4444rev,shove4444rev, + newwidth,newheight, + srcImage,dstImage,element_size,rowsize, + myswap_bytes); + break; + case GL_UNSIGNED_SHORT_5_5_5_1: + halveImagePackedPixel(4,extract5551,shove5551, + newwidth,newheight, + srcImage,dstImage,element_size,rowsize, + myswap_bytes); + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + halveImagePackedPixel(4,extract1555rev,shove1555rev, + newwidth,newheight, + srcImage,dstImage,element_size,rowsize, + myswap_bytes); + break; + case GL_UNSIGNED_INT_8_8_8_8: + halveImagePackedPixel(4,extract8888,shove8888, + newwidth,newheight, + srcImage,dstImage,element_size,rowsize, + myswap_bytes); + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + halveImagePackedPixel(4,extract8888rev,shove8888rev, + newwidth,newheight, + srcImage,dstImage,element_size,rowsize, + myswap_bytes); + break; + case GL_UNSIGNED_INT_10_10_10_2: + halveImagePackedPixel(4,extract1010102,shove1010102, + newwidth,newheight, + srcImage,dstImage,element_size,rowsize, + myswap_bytes); + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + halveImagePackedPixel(4,extract2101010rev,shove2101010rev, + newwidth,newheight, + srcImage,dstImage,element_size,rowsize, + myswap_bytes); + break; + default: + assert(0); + break; + } + + __GLU_SWAP_IMAGE(srcImage,dstImage); + + if (newwidth > 1) { newwidth /= 2; rowsize /= 2;} + if (newheight > 1) newheight /= 2; + { + /* compute amount to pad per row, if any */ + int rowPad= rowsize % psm.unpack_alignment; + + /* should row be padded? */ + if (rowPad == 0) { /* nope, row should not be padded */ + /* call tex image with srcImage untouched since it's not padded */ + if (baseLevel <= level && level <= maxLevel) { + glTexImage2D(target, level, internalFormat, newwidth, newheight, 0, + format, type, (void *) srcImage); + } + } + else { /* yes, row should be padded */ + /* compute length of new row in bytes, including padding */ + int newRowLength= rowsize + psm.unpack_alignment - rowPad; + int ii; unsigned char *dstTrav, *srcTrav; /* indices for copying */ + + /* allocate new image for mipmap of size newRowLength x newheight */ + void *newMipmapImage= malloc((size_t) (newRowLength*newheight)); + if (newMipmapImage == NULL) { + /* out of memory so return */ + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + return GLU_OUT_OF_MEMORY; + } + + /* copy image from srcImage into newMipmapImage by rows */ + for (ii= 0, + dstTrav= (unsigned char *) newMipmapImage, + srcTrav= (unsigned char *) srcImage; + ii< newheight; + ii++, + dstTrav+= newRowLength, /* make sure the correct distance... */ + srcTrav+= rowsize) { /* ...is skipped */ + memcpy(dstTrav,srcTrav,rowsize); + /* note that the pad bytes are not visited and will contain + * garbage, which is ok. + */ + } + + /* ...and use this new image for mipmapping instead */ + if (baseLevel <= level && level <= maxLevel) { + glTexImage2D(target, level, internalFormat, newwidth, newheight, 0, + format, type, newMipmapImage); + } + free(newMipmapImage); /* don't forget to free it! */ + } /* else */ + } + } /* for level */ + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + + free(srcImage); /*if you get to here, a srcImage has always been malloc'ed*/ + if (dstImage) { /* if it's non-rectangular and only 1 level */ + free(dstImage); + } + return 0; +} /* gluBuild2DMipmapLevelsCore() */ + +GLint GLAPIENTRY +gluBuild2DMipmapLevels(GLenum target, GLint internalFormat, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLint userLevel, GLint baseLevel, GLint maxLevel, + const void *data) +{ + int level, levels; + + int rc= checkMipmapArgs(internalFormat,format,type); + if (rc != 0) return rc; + + if (width < 1 || height < 1) { + return GLU_INVALID_VALUE; + } + + levels = computeLog(width); + level = computeLog(height); + if (level > levels) levels=level; + + levels+= userLevel; + if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels)) + return GLU_INVALID_VALUE; + + return gluBuild2DMipmapLevelsCore(target, internalFormat, + width, height, + width, height, + format, type, + userLevel, baseLevel, maxLevel, + data); +} /* gluBuild2DMipmapLevels() */ + +GLint GLAPIENTRY +gluBuild2DMipmaps(GLenum target, GLint internalFormat, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const void *data) +{ + GLint widthPowerOf2, heightPowerOf2; + int level, levels; + + int rc= checkMipmapArgs(internalFormat,format,type); + if (rc != 0) return rc; + + if (width < 1 || height < 1) { + return GLU_INVALID_VALUE; + } + + closestFit(target,width,height,internalFormat,format,type, + &widthPowerOf2,&heightPowerOf2); + + levels = computeLog(widthPowerOf2); + level = computeLog(heightPowerOf2); + if (level > levels) levels=level; + + return gluBuild2DMipmapLevelsCore(target,internalFormat, + width, height, + widthPowerOf2,heightPowerOf2, + format,type, + 0,0,levels,data); +} /* gluBuild2DMipmaps() */ + +#if 0 +/* +** This routine is for the limited case in which +** type == GL_UNSIGNED_BYTE && format != index && +** unpack_alignment = 1 && unpack_swap_bytes == false +** +** so all of the work data can be kept as ubytes instead of shorts. +*/ +static int fastBuild2DMipmaps(const PixelStorageModes *psm, + GLenum target, GLint components, GLint width, + GLint height, GLenum format, + GLenum type, void *data) +{ + GLint newwidth, newheight; + GLint level, levels; + GLubyte *newImage; + GLint newImage_width; + GLint newImage_height; + GLubyte *otherImage; + GLubyte *imageTemp; + GLint memreq; + GLint cmpts; + + +#if 0 + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); + newwidth = nearestPower(width); + if (newwidth > maxsize) newwidth = maxsize; + newheight = nearestPower(height); + if (newheight > maxsize) newheight = maxsize; +#else + closestFit(target,width,height,components,format,type, + &newwidth,&newheight); +#endif + levels = computeLog(newwidth); + level = computeLog(newheight); + if (level > levels) levels=level; + + cmpts = elements_per_group(format,type); + + otherImage = NULL; + /** + ** No need to copy the user data if its in the packed correctly. + ** Make sure that later routines don't change that data. + */ + if (psm->unpack_skip_rows == 0 && psm->unpack_skip_pixels == 0) { + newImage = (GLubyte *)data; + newImage_width = width; + newImage_height = height; + } else { + GLint rowsize; + GLint groups_per_line; + GLint elements_per_line; + const GLubyte *start; + const GLubyte *iter; + GLubyte *iter2; + GLint i, j; + + newImage = (GLubyte *) + malloc(image_size(width, height, format, GL_UNSIGNED_BYTE)); + newImage_width = width; + newImage_height = height; + if (newImage == NULL) { + return GLU_OUT_OF_MEMORY; + } + + /* + ** Abbreviated version of fill_image for this restricted case. + */ + if (psm->unpack_row_length > 0) { + groups_per_line = psm->unpack_row_length; + } else { + groups_per_line = width; + } + rowsize = groups_per_line * cmpts; + elements_per_line = width * cmpts; + start = (const GLubyte *) data + psm->unpack_skip_rows * rowsize + + psm->unpack_skip_pixels * cmpts; + iter2 = newImage; + + for (i = 0; i < height; i++) { + iter = start; + for (j = 0; j < elements_per_line; j++) { + *iter2 = *iter; + iter++; + iter2++; + } + start += rowsize; + } + } + + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + + for (level = 0; level <= levels; level++) { + if (newImage_width == newwidth && newImage_height == newheight) { + /* Use newImage for this level */ + glTexImage2D(target, level, components, newImage_width, + newImage_height, 0, format, GL_UNSIGNED_BYTE, + (void *) newImage); + } else { + if (otherImage == NULL) { + memreq = + image_size(newwidth, newheight, format, GL_UNSIGNED_BYTE); + otherImage = (GLubyte *) malloc(memreq); + if (otherImage == NULL) { + glPixelStorei(GL_UNPACK_ALIGNMENT, psm->unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm->unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm->unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH,psm->unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES,psm->unpack_swap_bytes); + return GLU_OUT_OF_MEMORY; + } + } +/* + scale_internal_ubyte(cmpts, newImage_width, newImage_height, + newImage, newwidth, newheight, otherImage); +*/ + /* Swap newImage and otherImage */ + imageTemp = otherImage; + otherImage = newImage; + newImage = imageTemp; + + newImage_width = newwidth; + newImage_height = newheight; + glTexImage2D(target, level, components, newImage_width, + newImage_height, 0, format, GL_UNSIGNED_BYTE, + (void *) newImage); + } + if (newwidth > 1) newwidth /= 2; + if (newheight > 1) newheight /= 2; + } + glPixelStorei(GL_UNPACK_ALIGNMENT, psm->unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm->unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm->unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm->unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm->unpack_swap_bytes); + + if (newImage != (const GLubyte *)data) { + free((GLbyte *) newImage); + } + if (otherImage && otherImage != (const GLubyte *)data) { + free((GLbyte *) otherImage); + } + return 0; +} +#endif + +/* + * Utility Routines + */ +static GLint elements_per_group(GLenum format, GLenum type) +{ + /* + * Return the number of elements per group of a specified format + */ + + /* If the type is packedpixels then answer is 1 (ignore format) */ + if (type == GL_UNSIGNED_BYTE_3_3_2 || + type == GL_UNSIGNED_BYTE_2_3_3_REV || + type == GL_UNSIGNED_SHORT_5_6_5 || + type == GL_UNSIGNED_SHORT_5_6_5_REV || + type == GL_UNSIGNED_SHORT_4_4_4_4 || + type == GL_UNSIGNED_SHORT_4_4_4_4_REV || + type == GL_UNSIGNED_SHORT_5_5_5_1 || + type == GL_UNSIGNED_SHORT_1_5_5_5_REV || + type == GL_UNSIGNED_INT_8_8_8_8 || + type == GL_UNSIGNED_INT_8_8_8_8_REV || + type == GL_UNSIGNED_INT_10_10_10_2 || + type == GL_UNSIGNED_INT_2_10_10_10_REV) { + return 1; + } + + /* Types are not packed pixels, so get elements per group */ + switch(format) { + case GL_RGB: + case GL_BGR: + return 3; + case GL_LUMINANCE_ALPHA: + return 2; + case GL_RGBA: + case GL_BGRA: + return 4; + default: + return 1; + } +} + +static GLfloat bytes_per_element(GLenum type) +{ + /* + * Return the number of bytes per element, based on the element type + */ + switch(type) { + case GL_BITMAP: + return 1.0 / 8.0; + case GL_UNSIGNED_SHORT: + return(sizeof(GLushort)); + case GL_SHORT: + return(sizeof(GLshort)); + case GL_UNSIGNED_BYTE: + return(sizeof(GLubyte)); + case GL_BYTE: + return(sizeof(GLbyte)); + case GL_INT: + return(sizeof(GLint)); + case GL_UNSIGNED_INT: + return(sizeof(GLuint)); + case GL_FLOAT: + return(sizeof(GLfloat)); + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + return(sizeof(GLubyte)); + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + return(sizeof(GLushort)); + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + return(sizeof(GLuint)); + default: + return 4; + } +} + +static GLint is_index(GLenum format) +{ + return format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX; +} + +/* +** Compute memory required for internal packed array of data of given type +** and format. +*/ +static GLint image_size(GLint width, GLint height, GLenum format, GLenum type) +{ + int bytes_per_row; + int components; + +assert(width > 0); +assert(height > 0); + components = elements_per_group(format,type); + if (type == GL_BITMAP) { + bytes_per_row = (width + 7) / 8; + } else { + bytes_per_row = bytes_per_element(type) * width; + } + return bytes_per_row * height * components; +} + +/* +** Extract array from user's data applying all pixel store modes. +** The internal format used is an array of unsigned shorts. +*/ +static void fill_image(const PixelStorageModes *psm, + GLint width, GLint height, GLenum format, + GLenum type, GLboolean index_format, + const void *userdata, GLushort *newimage) +{ + GLint components; + GLint element_size; + GLint rowsize; + GLint padding; + GLint groups_per_line; + GLint group_size; + GLint elements_per_line; + const GLubyte *start; + const GLubyte *iter; + GLushort *iter2; + GLint i, j, k; + GLint myswap_bytes; + + myswap_bytes = psm->unpack_swap_bytes; + components = elements_per_group(format,type); + if (psm->unpack_row_length > 0) { + groups_per_line = psm->unpack_row_length; + } else { + groups_per_line = width; + } + + /* All formats except GL_BITMAP fall out trivially */ + if (type == GL_BITMAP) { + GLint bit_offset; + GLint current_bit; + + rowsize = (groups_per_line * components + 7) / 8; + padding = (rowsize % psm->unpack_alignment); + if (padding) { + rowsize += psm->unpack_alignment - padding; + } + start = (const GLubyte *) userdata + psm->unpack_skip_rows * rowsize + + (psm->unpack_skip_pixels * components / 8); + elements_per_line = width * components; + iter2 = newimage; + for (i = 0; i < height; i++) { + iter = start; + bit_offset = (psm->unpack_skip_pixels * components) % 8; + for (j = 0; j < elements_per_line; j++) { + /* Retrieve bit */ + if (psm->unpack_lsb_first) { + current_bit = iter[0] & (1 << bit_offset); + } else { + current_bit = iter[0] & (1 << (7 - bit_offset)); + } + if (current_bit) { + if (index_format) { + *iter2 = 1; + } else { + *iter2 = 65535; + } + } else { + *iter2 = 0; + } + bit_offset++; + if (bit_offset == 8) { + bit_offset = 0; + iter++; + } + iter2++; + } + start += rowsize; + } + } else { + element_size = bytes_per_element(type); + group_size = element_size * components; + if (element_size == 1) myswap_bytes = 0; + + rowsize = groups_per_line * group_size; + padding = (rowsize % psm->unpack_alignment); + if (padding) { + rowsize += psm->unpack_alignment - padding; + } + start = (const GLubyte *) userdata + psm->unpack_skip_rows * rowsize + + psm->unpack_skip_pixels * group_size; + elements_per_line = width * components; + + iter2 = newimage; + for (i = 0; i < height; i++) { + iter = start; + for (j = 0; j < elements_per_line; j++) { + Type_Widget widget; + float extractComponents[4]; + + switch(type) { + case GL_UNSIGNED_BYTE_3_3_2: + extract332(0,iter,extractComponents); + for (k = 0; k < 3; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_BYTE_2_3_3_REV: + extract233rev(0,iter,extractComponents); + for (k = 0; k < 3; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_BYTE: + if (index_format) { + *iter2++ = *iter; + } else { + *iter2++ = (*iter) * 257; + } + break; + case GL_BYTE: + if (index_format) { + *iter2++ = *((const GLbyte *) iter); + } else { + /* rough approx */ + *iter2++ = (*((const GLbyte *) iter)) * 516; + } + break; + case GL_UNSIGNED_SHORT_5_6_5: + extract565(myswap_bytes,iter,extractComponents); + for (k = 0; k < 3; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT_5_6_5_REV: + extract565rev(myswap_bytes,iter,extractComponents); + for (k = 0; k < 3; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + extract4444(myswap_bytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + extract4444rev(myswap_bytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT_5_5_5_1: + extract5551(myswap_bytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + extract1555rev(myswap_bytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT: + case GL_SHORT: + if (myswap_bytes) { + widget.ub[0] = iter[1]; + widget.ub[1] = iter[0]; + } else { + widget.ub[0] = iter[0]; + widget.ub[1] = iter[1]; + } + if (type == GL_SHORT) { + if (index_format) { + *iter2++ = widget.s[0]; + } else { + /* rough approx */ + *iter2++ = widget.s[0]*2; + } + } else { + *iter2++ = widget.us[0]; + } + break; + case GL_UNSIGNED_INT_8_8_8_8: + extract8888(myswap_bytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + extract8888rev(myswap_bytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_INT_10_10_10_2: + extract1010102(myswap_bytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + extract2101010rev(myswap_bytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + if (myswap_bytes) { + widget.ub[0] = iter[3]; + widget.ub[1] = iter[2]; + widget.ub[2] = iter[1]; + widget.ub[3] = iter[0]; + } else { + widget.ub[0] = iter[0]; + widget.ub[1] = iter[1]; + widget.ub[2] = iter[2]; + widget.ub[3] = iter[3]; + } + if (type == GL_FLOAT) { + if (index_format) { + *iter2++ = widget.f; + } else { + *iter2++ = 65535 * widget.f; + } + } else if (type == GL_UNSIGNED_INT) { + if (index_format) { + *iter2++ = widget.ui; + } else { + *iter2++ = widget.ui >> 16; + } + } else { + if (index_format) { + *iter2++ = widget.i; + } else { + *iter2++ = widget.i >> 15; + } + } + break; + } + iter += element_size; + } /* for j */ + start += rowsize; +#if 1 + /* want 'iter' pointing at start, not within, row for assertion + * purposes + */ + iter= start; +#endif + } /* for i */ + + /* iterators should be one byte past end */ + if (!isTypePackedPixel(type)) { + assert(iter2 == &newimage[width*height*components]); + } + else { + assert(iter2 == &newimage[width*height* + elements_per_group(format,0)]); + } + assert( iter == &((const GLubyte *)userdata)[rowsize*height + + psm->unpack_skip_rows * rowsize + + psm->unpack_skip_pixels * group_size] ); + + } /* else */ +} /* fill_image() */ + +/* +** Insert array into user's data applying all pixel store modes. +** The internal format is an array of unsigned shorts. +** empty_image() because it is the opposite of fill_image(). +*/ +static void empty_image(const PixelStorageModes *psm, + GLint width, GLint height, GLenum format, + GLenum type, GLboolean index_format, + const GLushort *oldimage, void *userdata) +{ + GLint components; + GLint element_size; + GLint rowsize; + GLint padding; + GLint groups_per_line; + GLint group_size; + GLint elements_per_line; + GLubyte *start; + GLubyte *iter; + const GLushort *iter2; + GLint i, j, k; + GLint myswap_bytes; + + myswap_bytes = psm->pack_swap_bytes; + components = elements_per_group(format,type); + if (psm->pack_row_length > 0) { + groups_per_line = psm->pack_row_length; + } else { + groups_per_line = width; + } + + /* All formats except GL_BITMAP fall out trivially */ + if (type == GL_BITMAP) { + GLint bit_offset; + GLint current_bit; + + rowsize = (groups_per_line * components + 7) / 8; + padding = (rowsize % psm->pack_alignment); + if (padding) { + rowsize += psm->pack_alignment - padding; + } + start = (GLubyte *) userdata + psm->pack_skip_rows * rowsize + + (psm->pack_skip_pixels * components / 8); + elements_per_line = width * components; + iter2 = oldimage; + for (i = 0; i < height; i++) { + iter = start; + bit_offset = (psm->pack_skip_pixels * components) % 8; + for (j = 0; j < elements_per_line; j++) { + if (index_format) { + current_bit = iter2[0] & 1; + } else { + if (iter2[0] > 32767) { + current_bit = 1; + } else { + current_bit = 0; + } + } + + if (current_bit) { + if (psm->pack_lsb_first) { + *iter |= (1 << bit_offset); + } else { + *iter |= (1 << (7 - bit_offset)); + } + } else { + if (psm->pack_lsb_first) { + *iter &= ~(1 << bit_offset); + } else { + *iter &= ~(1 << (7 - bit_offset)); + } + } + + bit_offset++; + if (bit_offset == 8) { + bit_offset = 0; + iter++; + } + iter2++; + } + start += rowsize; + } + } else { + float shoveComponents[4]; + + element_size = bytes_per_element(type); + group_size = element_size * components; + if (element_size == 1) myswap_bytes = 0; + + rowsize = groups_per_line * group_size; + padding = (rowsize % psm->pack_alignment); + if (padding) { + rowsize += psm->pack_alignment - padding; + } + start = (GLubyte *) userdata + psm->pack_skip_rows * rowsize + + psm->pack_skip_pixels * group_size; + elements_per_line = width * components; + + iter2 = oldimage; + for (i = 0; i < height; i++) { + iter = start; + for (j = 0; j < elements_per_line; j++) { + Type_Widget widget; + + switch(type) { + case GL_UNSIGNED_BYTE_3_3_2: + for (k = 0; k < 3; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove332(shoveComponents,0,(void *)iter); + break; + case GL_UNSIGNED_BYTE_2_3_3_REV: + for (k = 0; k < 3; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove233rev(shoveComponents,0,(void *)iter); + break; + case GL_UNSIGNED_BYTE: + if (index_format) { + *iter = *iter2++; + } else { + *iter = *iter2++ >> 8; + } + break; + case GL_BYTE: + if (index_format) { + *((GLbyte *) iter) = *iter2++; + } else { + *((GLbyte *) iter) = *iter2++ >> 9; + } + break; + case GL_UNSIGNED_SHORT_5_6_5: + for (k = 0; k < 3; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove565(shoveComponents,0,(void *)&widget.us[0]); + if (myswap_bytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } + else { + *(GLushort *)iter = widget.us[0]; + } + break; + case GL_UNSIGNED_SHORT_5_6_5_REV: + for (k = 0; k < 3; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove565rev(shoveComponents,0,(void *)&widget.us[0]); + if (myswap_bytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } + else { + *(GLushort *)iter = widget.us[0]; + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove4444(shoveComponents,0,(void *)&widget.us[0]); + if (myswap_bytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } else { + *(GLushort *)iter = widget.us[0]; + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove4444rev(shoveComponents,0,(void *)&widget.us[0]); + if (myswap_bytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } else { + *(GLushort *)iter = widget.us[0]; + } + break; + case GL_UNSIGNED_SHORT_5_5_5_1: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove5551(shoveComponents,0,(void *)&widget.us[0]); + if (myswap_bytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } else { + *(GLushort *)iter = widget.us[0]; + } + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove1555rev(shoveComponents,0,(void *)&widget.us[0]); + if (myswap_bytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } else { + *(GLushort *)iter = widget.us[0]; + } + break; + case GL_UNSIGNED_SHORT: + case GL_SHORT: + if (type == GL_SHORT) { + if (index_format) { + widget.s[0] = *iter2++; + } else { + widget.s[0] = *iter2++ >> 1; + } + } else { + widget.us[0] = *iter2++; + } + if (myswap_bytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } else { + iter[0] = widget.ub[0]; + iter[1] = widget.ub[1]; + } + break; + case GL_UNSIGNED_INT_8_8_8_8: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove8888(shoveComponents,0,(void *)&widget.ui); + if (myswap_bytes) { + iter[3] = widget.ub[0]; + iter[2] = widget.ub[1]; + iter[1] = widget.ub[2]; + iter[0] = widget.ub[3]; + } else { + *(GLuint *)iter= widget.ui; + } + + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove8888rev(shoveComponents,0,(void *)&widget.ui); + if (myswap_bytes) { + iter[3] = widget.ub[0]; + iter[2] = widget.ub[1]; + iter[1] = widget.ub[2]; + iter[0] = widget.ub[3]; + } else { + *(GLuint *)iter= widget.ui; + } + break; + case GL_UNSIGNED_INT_10_10_10_2: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove1010102(shoveComponents,0,(void *)&widget.ui); + if (myswap_bytes) { + iter[3] = widget.ub[0]; + iter[2] = widget.ub[1]; + iter[1] = widget.ub[2]; + iter[0] = widget.ub[3]; + } else { + *(GLuint *)iter= widget.ui; + } + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove2101010rev(shoveComponents,0,(void *)&widget.ui); + if (myswap_bytes) { + iter[3] = widget.ub[0]; + iter[2] = widget.ub[1]; + iter[1] = widget.ub[2]; + iter[0] = widget.ub[3]; + } else { + *(GLuint *)iter= widget.ui; + } + break; + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + if (type == GL_FLOAT) { + if (index_format) { + widget.f = *iter2++; + } else { + widget.f = *iter2++ / (float) 65535.0; + } + } else if (type == GL_UNSIGNED_INT) { + if (index_format) { + widget.ui = *iter2++; + } else { + widget.ui = (unsigned int) *iter2++ * 65537; + } + } else { + if (index_format) { + widget.i = *iter2++; + } else { + widget.i = ((unsigned int) *iter2++ * 65537)/2; + } + } + if (myswap_bytes) { + iter[3] = widget.ub[0]; + iter[2] = widget.ub[1]; + iter[1] = widget.ub[2]; + iter[0] = widget.ub[3]; + } else { + iter[0] = widget.ub[0]; + iter[1] = widget.ub[1]; + iter[2] = widget.ub[2]; + iter[3] = widget.ub[3]; + } + break; + } + iter += element_size; + } /* for j */ + start += rowsize; +#if 1 + /* want 'iter' pointing at start, not within, row for assertion + * purposes + */ + iter= start; +#endif + } /* for i */ + + /* iterators should be one byte past end */ + if (!isTypePackedPixel(type)) { + assert(iter2 == &oldimage[width*height*components]); + } + else { + assert(iter2 == &oldimage[width*height* + elements_per_group(format,0)]); + } + assert( iter == &((GLubyte *)userdata)[rowsize*height + + psm->pack_skip_rows * rowsize + + psm->pack_skip_pixels * group_size] ); + + } /* else */ +} /* empty_image() */ + +/*-------------------------------------------------------------------------- + * Decimation of packed pixel types + *-------------------------------------------------------------------------- + */ +static void extract332(int isSwap, + const void *packedPixel, GLfloat extractComponents[]) +{ + GLubyte ubyte= *(const GLubyte *)packedPixel; + + isSwap= isSwap; /* turn off warnings */ + + /* 11100000 == 0xe0 */ + /* 00011100 == 0x1c */ + /* 00000011 == 0x03 */ + + extractComponents[0]= (float)((ubyte & 0xe0) >> 5) / 7.0; + extractComponents[1]= (float)((ubyte & 0x1c) >> 2) / 7.0; /* 7 = 2^3-1 */ + extractComponents[2]= (float)((ubyte & 0x03) ) / 3.0; /* 3 = 2^2-1 */ +} /* extract332() */ + +static void shove332(const GLfloat shoveComponents[], + int index, void *packedPixel) +{ + /* 11100000 == 0xe0 */ + /* 00011100 == 0x1c */ + /* 00000011 == 0x03 */ + + assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); + assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); + assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); + + /* due to limited precision, need to round before shoving */ + ((GLubyte *)packedPixel)[index] = + ((GLubyte)((shoveComponents[0] * 7)+0.5) << 5) & 0xe0; + ((GLubyte *)packedPixel)[index] |= + ((GLubyte)((shoveComponents[1] * 7)+0.5) << 2) & 0x1c; + ((GLubyte *)packedPixel)[index] |= + ((GLubyte)((shoveComponents[2] * 3)+0.5) ) & 0x03; +} /* shove332() */ + +static void extract233rev(int isSwap, + const void *packedPixel, GLfloat extractComponents[]) +{ + GLubyte ubyte= *(const GLubyte *)packedPixel; + + isSwap= isSwap; /* turn off warnings */ + + /* 0000,0111 == 0x07 */ + /* 0011,1000 == 0x38 */ + /* 1100,0000 == 0xC0 */ + + extractComponents[0]= (float)((ubyte & 0x07) ) / 7.0; + extractComponents[1]= (float)((ubyte & 0x38) >> 3) / 7.0; + extractComponents[2]= (float)((ubyte & 0xC0) >> 6) / 3.0; +} /* extract233rev() */ + +static void shove233rev(const GLfloat shoveComponents[], + int index, void *packedPixel) +{ + /* 0000,0111 == 0x07 */ + /* 0011,1000 == 0x38 */ + /* 1100,0000 == 0xC0 */ + + assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); + assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); + assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); + + /* due to limited precision, need to round before shoving */ + ((GLubyte *)packedPixel)[index] = + ((GLubyte)((shoveComponents[0] * 7.0)+0.5) ) & 0x07; + ((GLubyte *)packedPixel)[index]|= + ((GLubyte)((shoveComponents[1] * 7.0)+0.5) << 3) & 0x38; + ((GLubyte *)packedPixel)[index]|= + ((GLubyte)((shoveComponents[2] * 3.0)+0.5) << 6) & 0xC0; +} /* shove233rev() */ + +static void extract565(int isSwap, + const void *packedPixel, GLfloat extractComponents[]) +{ + GLushort ushort= *(const GLushort *)packedPixel; + + if (isSwap) { + ushort= __GLU_SWAP_2_BYTES(packedPixel); + } + else { + ushort= *(const GLushort *)packedPixel; + } + + /* 11111000,00000000 == 0xf800 */ + /* 00000111,11100000 == 0x07e0 */ + /* 00000000,00011111 == 0x001f */ + + extractComponents[0]=(float)((ushort & 0xf800) >> 11) / 31.0;/* 31 = 2^5-1*/ + extractComponents[1]=(float)((ushort & 0x07e0) >> 5) / 63.0;/* 63 = 2^6-1*/ + extractComponents[2]=(float)((ushort & 0x001f) ) / 31.0; +} /* extract565() */ + +static void shove565(const GLfloat shoveComponents[], + int index,void *packedPixel) +{ + /* 11111000,00000000 == 0xf800 */ + /* 00000111,11100000 == 0x07e0 */ + /* 00000000,00011111 == 0x001f */ + + assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); + assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); + assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); + + /* due to limited precision, need to round before shoving */ + ((GLushort *)packedPixel)[index] = + ((GLushort)((shoveComponents[0] * 31)+0.5) << 11) & 0xf800; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[1] * 63)+0.5) << 5) & 0x07e0; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[2] * 31)+0.5) ) & 0x001f; +} /* shove565() */ + +static void extract565rev(int isSwap, + const void *packedPixel, GLfloat extractComponents[]) +{ + GLushort ushort= *(const GLushort *)packedPixel; + + if (isSwap) { + ushort= __GLU_SWAP_2_BYTES(packedPixel); + } + else { + ushort= *(const GLushort *)packedPixel; + } + + /* 00000000,00011111 == 0x001f */ + /* 00000111,11100000 == 0x07e0 */ + /* 11111000,00000000 == 0xf800 */ + + extractComponents[0]= (float)((ushort & 0x001F) ) / 31.0; + extractComponents[1]= (float)((ushort & 0x07E0) >> 5) / 63.0; + extractComponents[2]= (float)((ushort & 0xF800) >> 11) / 31.0; +} /* extract565rev() */ + +static void shove565rev(const GLfloat shoveComponents[], + int index,void *packedPixel) +{ + /* 00000000,00011111 == 0x001f */ + /* 00000111,11100000 == 0x07e0 */ + /* 11111000,00000000 == 0xf800 */ + + assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); + assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); + assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); + + /* due to limited precision, need to round before shoving */ + ((GLushort *)packedPixel)[index] = + ((GLushort)((shoveComponents[0] * 31.0)+0.5) ) & 0x001F; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[1] * 63.0)+0.5) << 5) & 0x07E0; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[2] * 31.0)+0.5) << 11) & 0xF800; +} /* shove565rev() */ + +static void extract4444(int isSwap,const void *packedPixel, + GLfloat extractComponents[]) +{ + GLushort ushort; + + if (isSwap) { + ushort= __GLU_SWAP_2_BYTES(packedPixel); + } + else { + ushort= *(const GLushort *)packedPixel; + } + + /* 11110000,00000000 == 0xf000 */ + /* 00001111,00000000 == 0x0f00 */ + /* 00000000,11110000 == 0x00f0 */ + /* 00000000,00001111 == 0x000f */ + + extractComponents[0]= (float)((ushort & 0xf000) >> 12) / 15.0;/* 15=2^4-1 */ + extractComponents[1]= (float)((ushort & 0x0f00) >> 8) / 15.0; + extractComponents[2]= (float)((ushort & 0x00f0) >> 4) / 15.0; + extractComponents[3]= (float)((ushort & 0x000f) ) / 15.0; +} /* extract4444() */ + +static void shove4444(const GLfloat shoveComponents[], + int index,void *packedPixel) +{ + assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); + assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); + assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); + assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); + + /* due to limited precision, need to round before shoving */ + ((GLushort *)packedPixel)[index] = + ((GLushort)((shoveComponents[0] * 15)+0.5) << 12) & 0xf000; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[1] * 15)+0.5) << 8) & 0x0f00; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[2] * 15)+0.5) << 4) & 0x00f0; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[3] * 15)+0.5) ) & 0x000f; +} /* shove4444() */ + +static void extract4444rev(int isSwap,const void *packedPixel, + GLfloat extractComponents[]) +{ + GLushort ushort; + + if (isSwap) { + ushort= __GLU_SWAP_2_BYTES(packedPixel); + } + else { + ushort= *(const GLushort *)packedPixel; + } + + /* 00000000,00001111 == 0x000f */ + /* 00000000,11110000 == 0x00f0 */ + /* 00001111,00000000 == 0x0f00 */ + /* 11110000,00000000 == 0xf000 */ + + /* 15 = 2^4-1 */ + extractComponents[0]= (float)((ushort & 0x000F) ) / 15.0; + extractComponents[1]= (float)((ushort & 0x00F0) >> 4) / 15.0; + extractComponents[2]= (float)((ushort & 0x0F00) >> 8) / 15.0; + extractComponents[3]= (float)((ushort & 0xF000) >> 12) / 15.0; +} /* extract4444rev() */ + +static void shove4444rev(const GLfloat shoveComponents[], + int index,void *packedPixel) +{ + /* 00000000,00001111 == 0x000f */ + /* 00000000,11110000 == 0x00f0 */ + /* 00001111,00000000 == 0x0f00 */ + /* 11110000,00000000 == 0xf000 */ + + assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); + assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); + assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); + assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); + + /* due to limited precision, need to round before shoving */ + ((GLushort *)packedPixel)[index] = + ((GLushort)((shoveComponents[0] * 15)+0.5) ) & 0x000F; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[1] * 15)+0.5) << 4) & 0x00F0; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[2] * 15)+0.5) << 8) & 0x0F00; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[3] * 15)+0.5) << 12) & 0xF000; +} /* shove4444rev() */ + +static void extract5551(int isSwap,const void *packedPixel, + GLfloat extractComponents[]) +{ + GLushort ushort; + + if (isSwap) { + ushort= __GLU_SWAP_2_BYTES(packedPixel); + } + else { + ushort= *(const GLushort *)packedPixel; + } + + /* 11111000,00000000 == 0xf800 */ + /* 00000111,11000000 == 0x07c0 */ + /* 00000000,00111110 == 0x003e */ + /* 00000000,00000001 == 0x0001 */ + + extractComponents[0]=(float)((ushort & 0xf800) >> 11) / 31.0;/* 31 = 2^5-1*/ + extractComponents[1]=(float)((ushort & 0x07c0) >> 6) / 31.0; + extractComponents[2]=(float)((ushort & 0x003e) >> 1) / 31.0; + extractComponents[3]=(float)((ushort & 0x0001) ); +} /* extract5551() */ + +static void shove5551(const GLfloat shoveComponents[], + int index,void *packedPixel) +{ + /* 11111000,00000000 == 0xf800 */ + /* 00000111,11000000 == 0x07c0 */ + /* 00000000,00111110 == 0x003e */ + /* 00000000,00000001 == 0x0001 */ + + assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); + assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); + assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); + assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); + + /* due to limited precision, need to round before shoving */ + ((GLushort *)packedPixel)[index] = + ((GLushort)((shoveComponents[0] * 31)+0.5) << 11) & 0xf800; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[1] * 31)+0.5) << 6) & 0x07c0; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[2] * 31)+0.5) << 1) & 0x003e; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[3])+0.5) ) & 0x0001; +} /* shove5551() */ + +static void extract1555rev(int isSwap,const void *packedPixel, + GLfloat extractComponents[]) +{ + GLushort ushort; + + if (isSwap) { + ushort= __GLU_SWAP_2_BYTES(packedPixel); + } + else { + ushort= *(const GLushort *)packedPixel; + } + + /* 00000000,00011111 == 0x001F */ + /* 00000011,11100000 == 0x03E0 */ + /* 01111100,00000000 == 0x7C00 */ + /* 10000000,00000000 == 0x8000 */ + + /* 31 = 2^5-1 */ + extractComponents[0]= (float)((ushort & 0x001F) ) / 31.0; + extractComponents[1]= (float)((ushort & 0x03E0) >> 5) / 31.0; + extractComponents[2]= (float)((ushort & 0x7C00) >> 10) / 31.0; + extractComponents[3]= (float)((ushort & 0x8000) >> 15); +} /* extract1555rev() */ + +static void shove1555rev(const GLfloat shoveComponents[], + int index,void *packedPixel) +{ + /* 00000000,00011111 == 0x001F */ + /* 00000011,11100000 == 0x03E0 */ + /* 01111100,00000000 == 0x7C00 */ + /* 10000000,00000000 == 0x8000 */ + + assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); + assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); + assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); + assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); + + /* due to limited precision, need to round before shoving */ + ((GLushort *)packedPixel)[index] = + ((GLushort)((shoveComponents[0] * 31)+0.5) ) & 0x001F; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[1] * 31)+0.5) << 5) & 0x03E0; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[2] * 31)+0.5) << 10) & 0x7C00; + ((GLushort *)packedPixel)[index]|= + ((GLushort)((shoveComponents[3])+0.5) << 15) & 0x8000; +} /* shove1555rev() */ + +static void extract8888(int isSwap, + const void *packedPixel, GLfloat extractComponents[]) +{ + GLuint uint; + + if (isSwap) { + uint= __GLU_SWAP_4_BYTES(packedPixel); + } + else { + uint= *(const GLuint *)packedPixel; + } + + /* 11111111,00000000,00000000,00000000 == 0xff000000 */ + /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */ + /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */ + /* 00000000,00000000,00000000,11111111 == 0x000000ff */ + + /* 255 = 2^8-1 */ + extractComponents[0]= (float)((uint & 0xff000000) >> 24) / 255.0; + extractComponents[1]= (float)((uint & 0x00ff0000) >> 16) / 255.0; + extractComponents[2]= (float)((uint & 0x0000ff00) >> 8) / 255.0; + extractComponents[3]= (float)((uint & 0x000000ff) ) / 255.0; +} /* extract8888() */ + +static void shove8888(const GLfloat shoveComponents[], + int index,void *packedPixel) +{ + /* 11111111,00000000,00000000,00000000 == 0xff000000 */ + /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */ + /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */ + /* 00000000,00000000,00000000,11111111 == 0x000000ff */ + + assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); + assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); + assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); + assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); + + /* due to limited precision, need to round before shoving */ + ((GLuint *)packedPixel)[index] = + ((GLuint)((shoveComponents[0] * 255)+0.5) << 24) & 0xff000000; + ((GLuint *)packedPixel)[index]|= + ((GLuint)((shoveComponents[1] * 255)+0.5) << 16) & 0x00ff0000; + ((GLuint *)packedPixel)[index]|= + ((GLuint)((shoveComponents[2] * 255)+0.5) << 8) & 0x0000ff00; + ((GLuint *)packedPixel)[index]|= + ((GLuint)((shoveComponents[3] * 255)+0.5) ) & 0x000000ff; +} /* shove8888() */ + +static void extract8888rev(int isSwap, + const void *packedPixel,GLfloat extractComponents[]) +{ + GLuint uint; + + if (isSwap) { + uint= __GLU_SWAP_4_BYTES(packedPixel); + } + else { + uint= *(const GLuint *)packedPixel; + } + + /* 00000000,00000000,00000000,11111111 == 0x000000ff */ + /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */ + /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */ + /* 11111111,00000000,00000000,00000000 == 0xff000000 */ + + /* 255 = 2^8-1 */ + extractComponents[0]= (float)((uint & 0x000000FF) ) / 255.0; + extractComponents[1]= (float)((uint & 0x0000FF00) >> 8) / 255.0; + extractComponents[2]= (float)((uint & 0x00FF0000) >> 16) / 255.0; + extractComponents[3]= (float)((uint & 0xFF000000) >> 24) / 255.0; +} /* extract8888rev() */ + +static void shove8888rev(const GLfloat shoveComponents[], + int index,void *packedPixel) +{ + /* 00000000,00000000,00000000,11111111 == 0x000000ff */ + /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */ + /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */ + /* 11111111,00000000,00000000,00000000 == 0xff000000 */ + + assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); + assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); + assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); + assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); + + /* due to limited precision, need to round before shoving */ + ((GLuint *)packedPixel)[index] = + ((GLuint)((shoveComponents[0] * 255)+0.5) ) & 0x000000FF; + ((GLuint *)packedPixel)[index]|= + ((GLuint)((shoveComponents[1] * 255)+0.5) << 8) & 0x0000FF00; + ((GLuint *)packedPixel)[index]|= + ((GLuint)((shoveComponents[2] * 255)+0.5) << 16) & 0x00FF0000; + ((GLuint *)packedPixel)[index]|= + ((GLuint)((shoveComponents[3] * 255)+0.5) << 24) & 0xFF000000; +} /* shove8888rev() */ + +static void extract1010102(int isSwap, + const void *packedPixel,GLfloat extractComponents[]) +{ + GLuint uint; + + if (isSwap) { + uint= __GLU_SWAP_4_BYTES(packedPixel); + } + else { + uint= *(const GLuint *)packedPixel; + } + + /* 11111111,11000000,00000000,00000000 == 0xffc00000 */ + /* 00000000,00111111,11110000,00000000 == 0x003ff000 */ + /* 00000000,00000000,00001111,11111100 == 0x00000ffc */ + /* 00000000,00000000,00000000,00000011 == 0x00000003 */ + + /* 1023 = 2^10-1 */ + extractComponents[0]= (float)((uint & 0xffc00000) >> 22) / 1023.0; + extractComponents[1]= (float)((uint & 0x003ff000) >> 12) / 1023.0; + extractComponents[2]= (float)((uint & 0x00000ffc) >> 2) / 1023.0; + extractComponents[3]= (float)((uint & 0x00000003) ) / 3.0; +} /* extract1010102() */ + +static void shove1010102(const GLfloat shoveComponents[], + int index,void *packedPixel) +{ + /* 11111111,11000000,00000000,00000000 == 0xffc00000 */ + /* 00000000,00111111,11110000,00000000 == 0x003ff000 */ + /* 00000000,00000000,00001111,11111100 == 0x00000ffc */ + /* 00000000,00000000,00000000,00000011 == 0x00000003 */ + + assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); + assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); + assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); + assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); + + /* due to limited precision, need to round before shoving */ + ((GLuint *)packedPixel)[index] = + ((GLuint)((shoveComponents[0] * 1023)+0.5) << 22) & 0xffc00000; + ((GLuint *)packedPixel)[index]|= + ((GLuint)((shoveComponents[1] * 1023)+0.5) << 12) & 0x003ff000; + ((GLuint *)packedPixel)[index]|= + ((GLuint)((shoveComponents[2] * 1023)+0.5) << 2) & 0x00000ffc; + ((GLuint *)packedPixel)[index]|= + ((GLuint)((shoveComponents[3] * 3)+0.5) ) & 0x00000003; +} /* shove1010102() */ + +static void extract2101010rev(int isSwap, + const void *packedPixel, + GLfloat extractComponents[]) +{ + GLuint uint; + + if (isSwap) { + uint= __GLU_SWAP_4_BYTES(packedPixel); + } + else { + uint= *(const GLuint *)packedPixel; + } + + /* 00000000,00000000,00000011,11111111 == 0x000003FF */ + /* 00000000,00001111,11111100,00000000 == 0x000FFC00 */ + /* 00111111,11110000,00000000,00000000 == 0x3FF00000 */ + /* 11000000,00000000,00000000,00000000 == 0xC0000000 */ + + /* 1023 = 2^10-1 */ + extractComponents[0]= (float)((uint & 0x000003FF) ) / 1023.0; + extractComponents[1]= (float)((uint & 0x000FFC00) >> 10) / 1023.0; + extractComponents[2]= (float)((uint & 0x3FF00000) >> 20) / 1023.0; + extractComponents[3]= (float)((uint & 0xC0000000) >> 30) / 3.0; + /* 3 = 2^2-1 */ +} /* extract2101010rev() */ + +static void shove2101010rev(const GLfloat shoveComponents[], + int index,void *packedPixel) +{ + /* 00000000,00000000,00000011,11111111 == 0x000003FF */ + /* 00000000,00001111,11111100,00000000 == 0x000FFC00 */ + /* 00111111,11110000,00000000,00000000 == 0x3FF00000 */ + /* 11000000,00000000,00000000,00000000 == 0xC0000000 */ + + assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); + assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); + assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); + assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); + + /* due to limited precision, need to round before shoving */ + ((GLuint *)packedPixel)[index] = + ((GLuint)((shoveComponents[0] * 1023)+0.5) ) & 0x000003FF; + ((GLuint *)packedPixel)[index]|= + ((GLuint)((shoveComponents[1] * 1023)+0.5) << 10) & 0x000FFC00; + ((GLuint *)packedPixel)[index]|= + ((GLuint)((shoveComponents[2] * 1023)+0.5) << 20) & 0x3FF00000; + ((GLuint *)packedPixel)[index]|= + ((GLuint)((shoveComponents[3] * 3)+0.5) << 30) & 0xC0000000; +} /* shove2101010rev() */ + +static void scaleInternalPackedPixel(int components, + void (*extractPackedPixel) + (int, const void *,GLfloat []), + void (*shovePackedPixel) + (const GLfloat [], int, void *), + GLint widthIn,GLint heightIn, + const void *dataIn, + GLint widthOut,GLint heightOut, + void *dataOut, + GLint pixelSizeInBytes, + GLint rowSizeInBytes,GLint isSwap) +{ + float convx; + float convy; + float percent; + + /* Max components in a format is 4, so... */ + float totals[4]; + float extractTotals[4], extractMoreTotals[4], shoveTotals[4]; + + float area; + int i,j,k,xindex; + + const char *temp, *temp0; + int outindex; + + int lowx_int, highx_int, lowy_int, highy_int; + float x_percent, y_percent; + float lowx_float, highx_float, lowy_float, highy_float; + float convy_float, convx_float; + int convy_int, convx_int; + int l, m; + const char *left, *right; + + if (widthIn == widthOut*2 && heightIn == heightOut*2) { + halveImagePackedPixel(components,extractPackedPixel,shovePackedPixel, + widthIn, heightIn, dataIn, dataOut, + pixelSizeInBytes,rowSizeInBytes,isSwap); + return; + } + convy = (float) heightIn/heightOut; + convx = (float) widthIn/widthOut; + convy_int = floor(convy); + convy_float = convy - convy_int; + convx_int = floor(convx); + convx_float = convx - convx_int; + + area = convx * convy; + + lowy_int = 0; + lowy_float = 0; + highy_int = convy_int; + highy_float = convy_float; + + for (i = 0; i < heightOut; i++) { + lowx_int = 0; + lowx_float = 0; + highx_int = convx_int; + highx_float = convx_float; + + for (j = 0; j < widthOut; j++) { + /* + ** Ok, now apply box filter to box that goes from (lowx, lowy) + ** to (highx, highy) on input data into this pixel on output + ** data. + */ + totals[0] = totals[1] = totals[2] = totals[3] = 0.0; + + /* calculate the value for pixels in the 1st row */ + xindex = lowx_int*pixelSizeInBytes; + if((highy_int>lowy_int) && (highx_int>lowx_int)) { + + y_percent = 1-lowy_float; + temp = (const char *)dataIn + xindex + lowy_int * rowSizeInBytes; + percent = y_percent * (1-lowx_float); +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * percent; + } +#endif + left = temp; + for(l = lowx_int+1; l < highx_int; l++) { + temp += pixelSizeInBytes; +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_2_BYTES(temp_index) * y_percent; + } else { + totals[k] += *(const GLushort*)temp_index * y_percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * y_percent; + } +#endif + } + temp += pixelSizeInBytes; + right = temp; + percent = y_percent * highx_float; +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * percent; + } +#endif + + /* calculate the value for pixels in the last row */ + + y_percent = highy_float; + percent = y_percent * (1-lowx_float); + temp = (const char *)dataIn + xindex + highy_int * rowSizeInBytes; +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * percent; + } +#endif + for(l = lowx_int+1; l < highx_int; l++) { + temp += pixelSizeInBytes; +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_2_BYTES(temp_index) * y_percent; + } else { + totals[k] += *(const GLushort*)temp_index * y_percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * y_percent; + } +#endif + + } + temp += pixelSizeInBytes; + percent = y_percent * highx_float; +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * percent; + } +#endif + + /* calculate the value for pixels in the 1st and last column */ + for(m = lowy_int+1; m < highy_int; m++) { + left += rowSizeInBytes; + right += rowSizeInBytes; +#if 0 + for (k = 0; k < components; + k++, left += element_size, right += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_2_BYTES(left) * (1-lowx_float) + + __GLU_SWAP_2_BYTES(right) * highx_float; + } else { + totals[k] += *(const GLushort*)left * (1-lowx_float) + + *(const GLushort*)right * highx_float; + } + } +#else + (*extractPackedPixel)(isSwap,left,extractTotals); + (*extractPackedPixel)(isSwap,right,extractMoreTotals); + for (k = 0; k < components; k++) { + totals[k]+= (extractTotals[k]*(1-lowx_float) + + extractMoreTotals[k]*highx_float); + } +#endif + } + } else if (highy_int > lowy_int) { + x_percent = highx_float - lowx_float; + percent = (1-lowy_float)*x_percent; + temp = (const char *)dataIn + xindex + lowy_int*rowSizeInBytes; +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * percent; + } +#endif + for(m = lowy_int+1; m < highy_int; m++) { + temp += rowSizeInBytes; +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_2_BYTES(temp_index) * x_percent; + } else { + totals[k] += *(const GLushort*)temp_index * x_percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * x_percent; + } +#endif + } + percent = x_percent * highy_float; + temp += rowSizeInBytes; +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * percent; + } +#endif + } else if (highx_int > lowx_int) { + y_percent = highy_float - lowy_float; + percent = (1-lowx_float)*y_percent; + temp = (const char *)dataIn + xindex + lowy_int*rowSizeInBytes; +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * percent; + } +#endif + for (l = lowx_int+1; l < highx_int; l++) { + temp += pixelSizeInBytes; +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += + __GLU_SWAP_2_BYTES(temp_index) * y_percent; + } else { + totals[k] += *(const GLushort*)temp_index * y_percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * y_percent; + } +#endif + } + temp += pixelSizeInBytes; + percent = y_percent * highx_float; +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * percent; + } +#endif + } else { + percent = (highy_float-lowy_float)*(highx_float-lowx_float); + temp = (const char *)dataIn + xindex + lowy_int * rowSizeInBytes; +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; + } else { + totals[k] += *(const GLushort*)temp_index * percent; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k] * percent; + } +#endif + } + + /* this is for the pixels in the body */ + temp0 = (const char *)dataIn + xindex + pixelSizeInBytes + (lowy_int+1)*rowSizeInBytes; + for (m = lowy_int+1; m < highy_int; m++) { + temp = temp0; + for(l = lowx_int+1; l < highx_int; l++) { +#if 0 + for (k = 0, temp_index = temp; k < components; + k++, temp_index += element_size) { + if (myswap_bytes) { + totals[k] += __GLU_SWAP_2_BYTES(temp_index); + } else { + totals[k] += *(const GLushort*)temp_index; + } + } +#else + (*extractPackedPixel)(isSwap,temp,extractTotals); + for (k = 0; k < components; k++) { + totals[k]+= extractTotals[k]; + } +#endif + temp += pixelSizeInBytes; + } + temp0 += rowSizeInBytes; + } + + outindex = (j + (i * widthOut)); /* * (components == 1) */ +#if 0 + for (k = 0; k < components; k++) { + dataout[outindex + k] = totals[k]/area; + /*printf("totals[%d] = %f\n", k, totals[k]);*/ + } +#else + for (k = 0; k < components; k++) { + shoveTotals[k]= totals[k]/area; + } + (*shovePackedPixel)(shoveTotals,outindex,(void *)dataOut); +#endif + lowx_int = highx_int; + lowx_float = highx_float; + highx_int += convx_int; + highx_float += convx_float; + if(highx_float > 1) { + highx_float -= 1.0; + highx_int++; + } + } + lowy_int = highy_int; + lowy_float = highy_float; + highy_int += convy_int; + highy_float += convy_float; + if(highy_float > 1) { + highy_float -= 1.0; + highy_int++; + } + } + + assert(outindex == (widthOut*heightOut - 1)); +} /* scaleInternalPackedPixel() */ + +/* rowSizeInBytes is at least the width (in bytes) due to padding on + * inputs; not always equal. Output NEVER has row padding. + */ +static void halveImagePackedPixel(int components, + void (*extractPackedPixel) + (int, const void *,GLfloat []), + void (*shovePackedPixel) + (const GLfloat [],int, void *), + GLint width, GLint height, + const void *dataIn, void *dataOut, + GLint pixelSizeInBytes, + GLint rowSizeInBytes, GLint isSwap) +{ + /* handle case where there is only 1 column/row */ + if (width == 1 || height == 1) { + assert(!(width == 1 && height == 1)); /* can't be 1x1 */ + halve1DimagePackedPixel(components,extractPackedPixel,shovePackedPixel, + width,height,dataIn,dataOut,pixelSizeInBytes, + rowSizeInBytes,isSwap); + return; + } + + { + int ii, jj; + + int halfWidth= width / 2; + int halfHeight= height / 2; + const char *src= (const char *) dataIn; + int padBytes= rowSizeInBytes - (width*pixelSizeInBytes); + int outIndex= 0; + + for (ii= 0; ii< halfHeight; ii++) { + for (jj= 0; jj< halfWidth; jj++) { +#define BOX4 4 + float totals[4]; /* 4 is maximum components */ + float extractTotals[BOX4][4]; /* 4 is maximum components */ + int cc; + + (*extractPackedPixel)(isSwap,src, + &extractTotals[0][0]); + (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes), + &extractTotals[1][0]); + (*extractPackedPixel)(isSwap,(src+rowSizeInBytes), + &extractTotals[2][0]); + (*extractPackedPixel)(isSwap, + (src+rowSizeInBytes+pixelSizeInBytes), + &extractTotals[3][0]); + for (cc = 0; cc < components; cc++) { + int kk; + + /* grab 4 pixels to average */ + totals[cc]= 0.0; + /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ + * extractTotals[2][RED]+extractTotals[3][RED]; + * totals[RED]/= 4.0; + */ + for (kk = 0; kk < BOX4; kk++) { + totals[cc]+= extractTotals[kk][cc]; + } + totals[cc]/= (float)BOX4; + } + (*shovePackedPixel)(totals,outIndex,dataOut); + + outIndex++; + /* skip over to next square of 4 */ + src+= pixelSizeInBytes + pixelSizeInBytes; + } + /* skip past pad bytes, if any, to get to next row */ + src+= padBytes; + + /* src is at beginning of a row here, but it's the second row of + * the square block of 4 pixels that we just worked on so we + * need to go one more row. + * i.e., + * OO... + * here -->OO... + * but want -->OO... + * OO... + * ... + */ + src+= rowSizeInBytes; + } + + /* both pointers must reach one byte after the end */ + assert(src == &((const char *)dataIn)[rowSizeInBytes*height]); + assert(outIndex == halfWidth * halfHeight); + } +} /* halveImagePackedPixel() */ + +static void halve1DimagePackedPixel(int components, + void (*extractPackedPixel) + (int, const void *,GLfloat []), + void (*shovePackedPixel) + (const GLfloat [],int, void *), + GLint width, GLint height, + const void *dataIn, void *dataOut, + GLint pixelSizeInBytes, + GLint rowSizeInBytes, GLint isSwap) +{ + int halfWidth= width / 2; + int halfHeight= height / 2; + const char *src= (const char *) dataIn; + int jj; + + assert(width == 1 || height == 1); /* must be 1D */ + assert(width != height); /* can't be square */ + + if (height == 1) { /* 1 row */ + int outIndex= 0; + + assert(width != 1); /* widthxheight can't be 1x1 */ + halfHeight= 1; + + /* one horizontal row with possible pad bytes */ + + for (jj= 0; jj< halfWidth; jj++) { +#define BOX2 2 + float totals[4]; /* 4 is maximum components */ + float extractTotals[BOX2][4]; /* 4 is maximum components */ + int cc; + + /* average two at a time, instead of four */ + (*extractPackedPixel)(isSwap,src, + &extractTotals[0][0]); + (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes), + &extractTotals[1][0]); + for (cc = 0; cc < components; cc++) { + int kk; + + /* grab 2 pixels to average */ + totals[cc]= 0.0; + /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]; + * totals[RED]/= 2.0; + */ + for (kk = 0; kk < BOX2; kk++) { + totals[cc]+= extractTotals[kk][cc]; + } + totals[cc]/= (float)BOX2; + } + (*shovePackedPixel)(totals,outIndex,dataOut); + + outIndex++; + /* skip over to next group of 2 */ + src+= pixelSizeInBytes + pixelSizeInBytes; + } + + { + int padBytes= rowSizeInBytes - (width*pixelSizeInBytes); + src+= padBytes; /* for assertion only */ + } + assert(src == &((const char *)dataIn)[rowSizeInBytes]); + assert(outIndex == halfWidth * halfHeight); + } + else if (width == 1) { /* 1 column */ + int outIndex= 0; + + assert(height != 1); /* widthxheight can't be 1x1 */ + halfWidth= 1; + /* one vertical column with possible pad bytes per row */ + /* average two at a time */ + + for (jj= 0; jj< halfHeight; jj++) { +#define BOX2 2 + float totals[4]; /* 4 is maximum components */ + float extractTotals[BOX2][4]; /* 4 is maximum components */ + int cc; + + /* average two at a time, instead of four */ + (*extractPackedPixel)(isSwap,src, + &extractTotals[0][0]); + (*extractPackedPixel)(isSwap,(src+rowSizeInBytes), + &extractTotals[1][0]); + for (cc = 0; cc < components; cc++) { + int kk; + + /* grab 2 pixels to average */ + totals[cc]= 0.0; + /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]; + * totals[RED]/= 2.0; + */ + for (kk = 0; kk < BOX2; kk++) { + totals[cc]+= extractTotals[kk][cc]; + } + totals[cc]/= (float)BOX2; + } + (*shovePackedPixel)(totals,outIndex,dataOut); + + outIndex++; + src+= rowSizeInBytes + rowSizeInBytes; /* go to row after next */ + } + + assert(src == &((const char *)dataIn)[rowSizeInBytes*height]); + assert(outIndex == halfWidth * halfHeight); + } +} /* halve1DimagePackedPixel() */ + +/*===========================================================================*/ + +#ifdef RESOLVE_3D_TEXTURE_SUPPORT +/* + * This section ensures that GLU 1.3 will load and run on + * a GL 1.1 implementation. It dynamically resolves the + * call to glTexImage3D() which might not be available. + * Or is it might be supported as an extension. + * Contributed by Gerk Huisma . + */ + +typedef void (GLAPIENTRY *TexImage3Dproc)( GLenum target, GLint level, + GLenum internalFormat, + GLsizei width, GLsizei height, + GLsizei depth, GLint border, + GLenum format, GLenum type, + const GLvoid *pixels ); + +static TexImage3Dproc pTexImage3D = 0; + +#if !defined(_WIN32) && !defined(__WIN32__) +# include +# include +#else + WINGDIAPI PROC WINAPI wglGetProcAddress(LPCSTR); +#endif + +static void gluTexImage3D( GLenum target, GLint level, + GLenum internalFormat, + GLsizei width, GLsizei height, + GLsizei depth, GLint border, + GLenum format, GLenum type, + const GLvoid *pixels ) +{ + if (!pTexImage3D) { +#if defined(_WIN32) || defined(__WIN32__) + pTexImage3D = (TexImage3Dproc) wglGetProcAddress("glTexImage3D"); + if (!pTexImage3D) + pTexImage3D = (TexImage3Dproc) wglGetProcAddress("glTexImage3DEXT"); +#else + void *libHandle = dlopen("libgl.so", RTLD_LAZY); + pTexImage3D = TexImage3Dproc) dlsym(libHandle, "glTexImage3D" ); + if (!pTexImage3D) + pTexImage3D = (TexImage3Dproc) dlsym(libHandle,"glTexImage3DEXT"); + dlclose(libHandle); +#endif + } + + /* Now call glTexImage3D */ + if (pTexImage3D) + pTexImage3D(target, level, internalFormat, width, height, + depth, border, format, type, pixels); +} + +#else + +/* Only bind to a GL 1.2 implementation: */ +#define gluTexImage3D glTexImage3D + +#endif + +static GLint imageSize3D(GLint width, GLint height, GLint depth, + GLenum format, GLenum type) +{ + int components= elements_per_group(format,type); + int bytes_per_row= bytes_per_element(type) * width; + +assert(width > 0 && height > 0 && depth > 0); +assert(type != GL_BITMAP); + + return bytes_per_row * height * depth * components; +} /* imageSize3D() */ + +static void fillImage3D(const PixelStorageModes *psm, + GLint width, GLint height, GLint depth, GLenum format, + GLenum type, GLboolean indexFormat, + const void *userImage, GLushort *newImage) +{ + int myswapBytes; + int components; + int groupsPerLine; + int elementSize; + int groupSize; + int rowSize; + int padding; + int elementsPerLine; + int rowsPerImage; + int imageSize; + const GLubyte *start, *rowStart, *iter; + GLushort *iter2; + int ww, hh, dd, k; + + myswapBytes= psm->unpack_swap_bytes; + components= elements_per_group(format,type); + if (psm->unpack_row_length > 0) { + groupsPerLine= psm->unpack_row_length; + } + else { + groupsPerLine= width; + } + elementSize= bytes_per_element(type); + groupSize= elementSize * components; + if (elementSize == 1) myswapBytes= 0; + + /* 3dstuff begin */ + if (psm->unpack_image_height > 0) { + rowsPerImage= psm->unpack_image_height; + } + else { + rowsPerImage= height; + } + /* 3dstuff end */ + + rowSize= groupsPerLine * groupSize; + padding= rowSize % psm->unpack_alignment; + if (padding) { + rowSize+= psm->unpack_alignment - padding; + } + + imageSize= rowsPerImage * rowSize; /* 3dstuff */ + + start= (const GLubyte *)userImage + psm->unpack_skip_rows * rowSize + + psm->unpack_skip_pixels * groupSize + + /*3dstuff*/ + psm->unpack_skip_images * imageSize; + elementsPerLine = width * components; + + iter2= newImage; + for (dd= 0; dd < depth; dd++) { + rowStart= start; + + for (hh= 0; hh < height; hh++) { + iter= rowStart; + + for (ww= 0; ww < elementsPerLine; ww++) { + Type_Widget widget; + float extractComponents[4]; + + switch(type) { + case GL_UNSIGNED_BYTE: + if (indexFormat) { + *iter2++ = *iter; + } else { + *iter2++ = (*iter) * 257; + } + break; + case GL_BYTE: + if (indexFormat) { + *iter2++ = *((const GLbyte *) iter); + } else { + /* rough approx */ + *iter2++ = (*((const GLbyte *) iter)) * 516; + } + break; + case GL_UNSIGNED_BYTE_3_3_2: + extract332(0,iter,extractComponents); + for (k = 0; k < 3; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_BYTE_2_3_3_REV: + extract233rev(0,iter,extractComponents); + for (k = 0; k < 3; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT_5_6_5: + extract565(myswapBytes,iter,extractComponents); + for (k = 0; k < 3; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT_5_6_5_REV: + extract565rev(myswapBytes,iter,extractComponents); + for (k = 0; k < 3; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + extract4444(myswapBytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + extract4444rev(myswapBytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT_5_5_5_1: + extract5551(myswapBytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + extract1555rev(myswapBytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_SHORT: + case GL_SHORT: + if (myswapBytes) { + widget.ub[0] = iter[1]; + widget.ub[1] = iter[0]; + } else { + widget.ub[0] = iter[0]; + widget.ub[1] = iter[1]; + } + if (type == GL_SHORT) { + if (indexFormat) { + *iter2++ = widget.s[0]; + } else { + /* rough approx */ + *iter2++ = widget.s[0]*2; + } + } else { + *iter2++ = widget.us[0]; + } + break; + case GL_UNSIGNED_INT_8_8_8_8: + extract8888(myswapBytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + extract8888rev(myswapBytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_INT_10_10_10_2: + extract1010102(myswapBytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + extract2101010rev(myswapBytes,iter,extractComponents); + for (k = 0; k < 4; k++) { + *iter2++ = (GLushort)(extractComponents[k]*65535); + } + break; + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + if (myswapBytes) { + widget.ub[0] = iter[3]; + widget.ub[1] = iter[2]; + widget.ub[2] = iter[1]; + widget.ub[3] = iter[0]; + } else { + widget.ub[0] = iter[0]; + widget.ub[1] = iter[1]; + widget.ub[2] = iter[2]; + widget.ub[3] = iter[3]; + } + if (type == GL_FLOAT) { + if (indexFormat) { + *iter2++ = widget.f; + } else { + *iter2++ = 65535 * widget.f; + } + } else if (type == GL_UNSIGNED_INT) { + if (indexFormat) { + *iter2++ = widget.ui; + } else { + *iter2++ = widget.ui >> 16; + } + } else { + if (indexFormat) { + *iter2++ = widget.i; + } else { + *iter2++ = widget.i >> 15; + } + } + break; + default: + assert(0); + } + + iter+= elementSize; + } /* for ww */ + rowStart+= rowSize; + + iter= rowStart; /* for assertion purposes */ + } /* for hh */ + + start+= imageSize; + } /* for dd */ + + /* iterators should be one byte past end */ + if (!isTypePackedPixel(type)) { + assert(iter2 == &newImage[width*height*depth*components]); + } + else { + assert(iter2 == &newImage[width*height*depth* + elements_per_group(format,0)]); + } + assert( iter == &((const GLubyte *)userImage)[rowSize*height*depth + + psm->unpack_skip_rows * rowSize + + psm->unpack_skip_pixels * groupSize + + /*3dstuff*/ + psm->unpack_skip_images * imageSize] ); +} /* fillImage3D () */ + +static void scaleInternal3D(GLint components, + GLint widthIn, GLint heightIn, GLint depthIn, + const GLushort *dataIn, + GLint widthOut, GLint heightOut, GLint depthOut, + GLushort *dataOut) +{ + float x, lowx, highx, convx, halfconvx; + float y, lowy, highy, convy, halfconvy; + float z, lowz, highz, convz, halfconvz; + float xpercent,ypercent,zpercent; + float percent; + /* Max components in a format is 4, so... */ + float totals[4]; + float volume; + int i,j,d,k,zint,yint,xint,xindex,yindex,zindex; + int temp; + + convz = (float) depthIn/depthOut; + convy = (float) heightIn/heightOut; + convx = (float) widthIn/widthOut; + halfconvx = convx/2; + halfconvy = convy/2; + halfconvz = convz/2; + for (d = 0; d < depthOut; d++) { + z = convz * (d+0.5); + if (depthIn > depthOut) { + highz = z + halfconvz; + lowz = z - halfconvz; + } else { + highz = z + 0.5; + lowz = z - 0.5; + } + for (i = 0; i < heightOut; i++) { + y = convy * (i+0.5); + if (heightIn > heightOut) { + highy = y + halfconvy; + lowy = y - halfconvy; + } else { + highy = y + 0.5; + lowy = y - 0.5; + } + for (j = 0; j < widthOut; j++) { + x = convx * (j+0.5); + if (widthIn > widthOut) { + highx = x + halfconvx; + lowx = x - halfconvx; + } else { + highx = x + 0.5; + lowx = x - 0.5; + } + + /* + ** Ok, now apply box filter to box that goes from (lowx, lowy, + ** lowz) to (highx, highy, highz) on input data into this pixel + ** on output data. + */ + totals[0] = totals[1] = totals[2] = totals[3] = 0.0; + volume = 0.0; + + z = lowz; + zint = floor(z); + while (z < highz) { + zindex = (zint + depthIn) % depthIn; + if (highz < zint+1) { + zpercent = highz - z; + } else { + zpercent = zint+1 - z; + } + + y = lowy; + yint = floor(y); + while (y < highy) { + yindex = (yint + heightIn) % heightIn; + if (highy < yint+1) { + ypercent = highy - y; + } else { + ypercent = yint+1 - y; + } + + x = lowx; + xint = floor(x); + + while (x < highx) { + xindex = (xint + widthIn) % widthIn; + if (highx < xint+1) { + xpercent = highx - x; + } else { + xpercent = xint+1 - x; + } + + percent = xpercent * ypercent * zpercent; + volume += percent; + + temp = (xindex + (yindex*widthIn) + + (zindex*widthIn*heightIn)) * components; + for (k = 0; k < components; k++) { + assert(0 <= (temp+k) && + (temp+k) < + (widthIn*heightIn*depthIn*components)); + totals[k] += dataIn[temp + k] * percent; + } + + xint++; + x = xint; + } /* while x */ + + yint++; + y = yint; + } /* while y */ + + zint++; + z = zint; + } /* while z */ + + temp = (j + (i * widthOut) + + (d*widthOut*heightOut)) * components; + for (k = 0; k < components; k++) { + /* totals[] should be rounded in the case of enlarging an + * RGB ramp when the type is 332 or 4444 + */ + assert(0 <= (temp+k) && + (temp+k) < (widthOut*heightOut*depthOut*components)); + dataOut[temp + k] = (totals[k]+0.5)/volume; + } + } /* for j */ + } /* for i */ + } /* for d */ +} /* scaleInternal3D() */ + +static void emptyImage3D(const PixelStorageModes *psm, + GLint width, GLint height, GLint depth, + GLenum format, GLenum type, GLboolean indexFormat, + const GLushort *oldImage, void *userImage) +{ + int myswapBytes; + int components; + int groupsPerLine; + int elementSize; + int groupSize; + int rowSize; + int padding; + GLubyte *start, *rowStart, *iter; + int elementsPerLine; + const GLushort *iter2; + int ii, jj, dd, k; + int rowsPerImage; + int imageSize; + + myswapBytes= psm->pack_swap_bytes; + components = elements_per_group(format,type); + if (psm->pack_row_length > 0) { + groupsPerLine = psm->pack_row_length; + } + else { + groupsPerLine = width; + } + + elementSize= bytes_per_element(type); + groupSize= elementSize * components; + if (elementSize == 1) myswapBytes= 0; + + /* 3dstuff begin */ + if (psm->pack_image_height > 0) { + rowsPerImage= psm->pack_image_height; + } + else { + rowsPerImage= height; + } + + /* 3dstuff end */ + + rowSize = groupsPerLine * groupSize; + padding = rowSize % psm->pack_alignment; + if (padding) { + rowSize+= psm->pack_alignment - padding; + } + + imageSize= rowsPerImage * rowSize; /* 3dstuff */ + + start = (GLubyte *)userImage + psm->pack_skip_rows * rowSize + + psm->pack_skip_pixels * groupSize + + /*3dstuff*/ + psm->pack_skip_images * imageSize; + elementsPerLine= width * components; + + iter2 = oldImage; + for (dd= 0; dd < depth; dd++) { + rowStart= start; + + for (ii= 0; ii< height; ii++) { + iter = rowStart; + + for (jj = 0; jj < elementsPerLine; jj++) { + Type_Widget widget; + float shoveComponents[4]; + + switch(type){ + case GL_UNSIGNED_BYTE: + if (indexFormat) { + *iter = *iter2++; + } else { + *iter = *iter2++ >> 8; + } + break; + case GL_BYTE: + if (indexFormat) { + *((GLbyte *) iter) = *iter2++; + } else { + *((GLbyte *) iter) = *iter2++ >> 9; + } + break; + case GL_UNSIGNED_BYTE_3_3_2: + for (k = 0; k < 3; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove332(shoveComponents,0,(void *)iter); + break; + case GL_UNSIGNED_BYTE_2_3_3_REV: + for (k = 0; k < 3; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove233rev(shoveComponents,0,(void *)iter); + break; + case GL_UNSIGNED_SHORT_5_6_5: + for (k = 0; k < 3; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove565(shoveComponents,0,(void *)&widget.us[0]); + if (myswapBytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } + else { + *(GLushort *)iter = widget.us[0]; + } + break; + case GL_UNSIGNED_SHORT_5_6_5_REV: + for (k = 0; k < 3; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove565rev(shoveComponents,0,(void *)&widget.us[0]); + if (myswapBytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } + else { + *(GLushort *)iter = widget.us[0]; + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove4444(shoveComponents,0,(void *)&widget.us[0]); + if (myswapBytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } else { + *(GLushort *)iter = widget.us[0]; + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove4444rev(shoveComponents,0,(void *)&widget.us[0]); + if (myswapBytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } else { + *(GLushort *)iter = widget.us[0]; + } + break; + case GL_UNSIGNED_SHORT_5_5_5_1: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove5551(shoveComponents,0,(void *)&widget.us[0]); + if (myswapBytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } else { + *(GLushort *)iter = widget.us[0]; + } + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove1555rev(shoveComponents,0,(void *)&widget.us[0]); + if (myswapBytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } else { + *(GLushort *)iter = widget.us[0]; + } + break; + case GL_UNSIGNED_SHORT: + case GL_SHORT: + if (type == GL_SHORT) { + if (indexFormat) { + widget.s[0] = *iter2++; + } else { + widget.s[0] = *iter2++ >> 1; + } + } else { + widget.us[0] = *iter2++; + } + if (myswapBytes) { + iter[0] = widget.ub[1]; + iter[1] = widget.ub[0]; + } else { + iter[0] = widget.ub[0]; + iter[1] = widget.ub[1]; + } + break; + case GL_UNSIGNED_INT_8_8_8_8: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove8888(shoveComponents,0,(void *)&widget.ui); + if (myswapBytes) { + iter[3] = widget.ub[0]; + iter[2] = widget.ub[1]; + iter[1] = widget.ub[2]; + iter[0] = widget.ub[3]; + } else { + *(GLuint *)iter= widget.ui; + } + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove8888rev(shoveComponents,0,(void *)&widget.ui); + if (myswapBytes) { + iter[3] = widget.ub[0]; + iter[2] = widget.ub[1]; + iter[1] = widget.ub[2]; + iter[0] = widget.ub[3]; + } else { + *(GLuint *)iter= widget.ui; + } + break; + case GL_UNSIGNED_INT_10_10_10_2: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove1010102(shoveComponents,0,(void *)&widget.ui); + if (myswapBytes) { + iter[3] = widget.ub[0]; + iter[2] = widget.ub[1]; + iter[1] = widget.ub[2]; + iter[0] = widget.ub[3]; + } else { + *(GLuint *)iter= widget.ui; + } + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + for (k = 0; k < 4; k++) { + shoveComponents[k]= *iter2++ / 65535.0; + } + shove2101010rev(shoveComponents,0,(void *)&widget.ui); + if (myswapBytes) { + iter[3] = widget.ub[0]; + iter[2] = widget.ub[1]; + iter[1] = widget.ub[2]; + iter[0] = widget.ub[3]; + } else { + *(GLuint *)iter= widget.ui; + } + break; + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + if (type == GL_FLOAT) { + if (indexFormat) { + widget.f = *iter2++; + } else { + widget.f = *iter2++ / (float) 65535.0; + } + } else if (type == GL_UNSIGNED_INT) { + if (indexFormat) { + widget.ui = *iter2++; + } else { + widget.ui = (unsigned int) *iter2++ * 65537; + } + } else { + if (indexFormat) { + widget.i = *iter2++; + } else { + widget.i = ((unsigned int) *iter2++ * 65537)/2; + } + } + if (myswapBytes) { + iter[3] = widget.ub[0]; + iter[2] = widget.ub[1]; + iter[1] = widget.ub[2]; + iter[0] = widget.ub[3]; + } else { + iter[0] = widget.ub[0]; + iter[1] = widget.ub[1]; + iter[2] = widget.ub[2]; + iter[3] = widget.ub[3]; + } + break; + default: + assert(0); + } + + iter+= elementSize; + } /* for jj */ + + rowStart+= rowSize; + } /* for ii */ + + start+= imageSize; + } /* for dd */ + + /* iterators should be one byte past end */ + if (!isTypePackedPixel(type)) { + assert(iter2 == &oldImage[width*height*depth*components]); + } + else { + assert(iter2 == &oldImage[width*height*depth* + elements_per_group(format,0)]); + } + assert( iter == &((GLubyte *)userImage)[rowSize*height*depth + + psm->unpack_skip_rows * rowSize + + psm->unpack_skip_pixels * groupSize + + /*3dstuff*/ + psm->unpack_skip_images * imageSize] ); +} /* emptyImage3D() */ + +static +int gluScaleImage3D(GLenum format, + GLint widthIn, GLint heightIn, GLint depthIn, + GLenum typeIn, const void *dataIn, + GLint widthOut, GLint heightOut, GLint depthOut, + GLenum typeOut, void *dataOut) +{ + int components; + GLushort *beforeImage, *afterImage; + PixelStorageModes psm; + + if (widthIn == 0 || heightIn == 0 || depthIn == 0 || + widthOut == 0 || heightOut == 0 || depthOut == 0) { + return 0; + } + + if (widthIn < 0 || heightIn < 0 || depthIn < 0 || + widthOut < 0 || heightOut < 0 || depthOut < 0) { + return GLU_INVALID_VALUE; + } + + if (!legalFormat(format) || !legalType(typeIn) || !legalType(typeOut) || + typeIn == GL_BITMAP || typeOut == GL_BITMAP) { + return GLU_INVALID_ENUM; + } + if (!isLegalFormatForPackedPixelType(format, typeIn)) { + return GLU_INVALID_OPERATION; + } + if (!isLegalFormatForPackedPixelType(format, typeOut)) { + return GLU_INVALID_OPERATION; + } + + beforeImage = malloc(imageSize3D(widthIn, heightIn, depthIn, format, + GL_UNSIGNED_SHORT)); + afterImage = malloc(imageSize3D(widthOut, heightOut, depthOut, format, + GL_UNSIGNED_SHORT)); + if (beforeImage == NULL || afterImage == NULL) { + return GLU_OUT_OF_MEMORY; + } + retrieveStoreModes3D(&psm); + + fillImage3D(&psm,widthIn,heightIn,depthIn,format,typeIn, is_index(format), + dataIn, beforeImage); + components = elements_per_group(format,0); + scaleInternal3D(components,widthIn,heightIn,depthIn,beforeImage, + widthOut,heightOut,depthOut,afterImage); + emptyImage3D(&psm,widthOut,heightOut,depthOut,format,typeOut, + is_index(format),afterImage, dataOut); + free((void *) beforeImage); + free((void *) afterImage); + + return 0; +} /* gluScaleImage3D() */ + + +static void closestFit3D(GLenum target, GLint width, GLint height, GLint depth, + GLint internalFormat, GLenum format, GLenum type, + GLint *newWidth, GLint *newHeight, GLint *newDepth) +{ + GLint widthPowerOf2= nearestPower(width); + GLint heightPowerOf2= nearestPower(height); + GLint depthPowerOf2= nearestPower(depth); + GLint proxyWidth; + + do { + /* compute level 1 width & height & depth, clamping each at 1 */ + GLint widthAtLevelOne= (widthPowerOf2 > 1) ? + widthPowerOf2 >> 1 : + widthPowerOf2; + GLint heightAtLevelOne= (heightPowerOf2 > 1) ? + heightPowerOf2 >> 1 : + heightPowerOf2; + GLint depthAtLevelOne= (depthPowerOf2 > 1) ? + depthPowerOf2 >> 1 : + depthPowerOf2; + GLenum proxyTarget = GL_PROXY_TEXTURE_3D; + assert(widthAtLevelOne > 0); + assert(heightAtLevelOne > 0); + assert(depthAtLevelOne > 0); + + /* does width x height x depth at level 1 & all their mipmaps fit? */ + assert(target == GL_TEXTURE_3D || target == GL_PROXY_TEXTURE_3D); + gluTexImage3D(proxyTarget, 1, /* must be non-zero */ + internalFormat, + widthAtLevelOne,heightAtLevelOne,depthAtLevelOne, + 0,format,type,NULL); + glGetTexLevelParameteriv(proxyTarget, 1,GL_TEXTURE_WIDTH,&proxyWidth); + /* does it fit??? */ + if (proxyWidth == 0) { /* nope, so try again with these sizes */ + if (widthPowerOf2 == 1 && heightPowerOf2 == 1 && + depthPowerOf2 == 1) { + *newWidth= *newHeight= *newDepth= 1; /* must fit 1x1x1 texture */ + return; + } + widthPowerOf2= widthAtLevelOne; + heightPowerOf2= heightAtLevelOne; + depthPowerOf2= depthAtLevelOne; + } + /* else it does fit */ + } while (proxyWidth == 0); + /* loop must terminate! */ + + /* return the width & height at level 0 that fits */ + *newWidth= widthPowerOf2; + *newHeight= heightPowerOf2; + *newDepth= depthPowerOf2; +/*printf("Proxy Textures\n");*/ +} /* closestFit3D() */ + +static void halveImagePackedPixelSlice(int components, + void (*extractPackedPixel) + (int, const void *,GLfloat []), + void (*shovePackedPixel) + (const GLfloat [],int, void *), + GLint width, GLint height, GLint depth, + const void *dataIn, void *dataOut, + GLint pixelSizeInBytes, + GLint rowSizeInBytes, + GLint imageSizeInBytes, + GLint isSwap) +{ + int ii, jj; + int halfWidth= width / 2; + int halfHeight= height / 2; + int halfDepth= depth / 2; + const char *src= (const char *)dataIn; + int outIndex= 0; + + assert((width == 1 || height == 1) && depth >= 2); + + if (width == height) { /* a 1-pixel column viewed from top */ + assert(width == 1 && height == 1); + assert(depth >= 2); + + for (ii= 0; ii< halfDepth; ii++) { + float totals[4]; + float extractTotals[BOX2][4]; + int cc; + + (*extractPackedPixel)(isSwap,src,&extractTotals[0][0]); + (*extractPackedPixel)(isSwap,(src+imageSizeInBytes), + &extractTotals[1][0]); + for (cc = 0; cc < components; cc++) { + int kk; + + /* average 2 pixels since only a column */ + totals[cc]= 0.0; + /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]; + * totals[RED]/= 2.0; + */ + for (kk = 0; kk < BOX2; kk++) { + totals[cc]+= extractTotals[kk][cc]; + } + totals[cc]/= (float)BOX2; + } /* for cc */ + + (*shovePackedPixel)(totals,outIndex,dataOut); + outIndex++; + /* skip over to next group of 2 */ + src+= imageSizeInBytes + imageSizeInBytes; + } /* for ii */ + } + else if (height == 1) { /* horizontal slice viewed from top */ + assert(width != 1); + + for (ii= 0; ii< halfDepth; ii++) { + for (jj= 0; jj< halfWidth; jj++) { + float totals[4]; + float extractTotals[BOX4][4]; + int cc; + + (*extractPackedPixel)(isSwap,src, + &extractTotals[0][0]); + (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes), + &extractTotals[1][0]); + (*extractPackedPixel)(isSwap,(src+imageSizeInBytes), + &extractTotals[2][0]); + (*extractPackedPixel)(isSwap, + (src+imageSizeInBytes+pixelSizeInBytes), + &extractTotals[3][0]); + for (cc = 0; cc < components; cc++) { + int kk; + + /* grab 4 pixels to average */ + totals[cc]= 0.0; + /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ + * extractTotals[2][RED]+extractTotals[3][RED]; + * totals[RED]/= 4.0; + */ + for (kk = 0; kk < BOX4; kk++) { + totals[cc]+= extractTotals[kk][cc]; + } + totals[cc]/= (float)BOX4; + } + (*shovePackedPixel)(totals,outIndex,dataOut); + + outIndex++; + /* skip over to next horizontal square of 4 */ + src+= imageSizeInBytes + imageSizeInBytes; + } + } + + /* assert() */ + } + else if (width == 1) { /* vertical slice viewed from top */ + assert(height != 1); + + for (ii= 0; ii< halfDepth; ii++) { + for (jj= 0; jj< halfHeight; jj++) { + float totals[4]; + float extractTotals[BOX4][4]; + int cc; + + (*extractPackedPixel)(isSwap,src, + &extractTotals[0][0]); + (*extractPackedPixel)(isSwap,(src+rowSizeInBytes), + &extractTotals[1][0]); + (*extractPackedPixel)(isSwap,(src+imageSizeInBytes), + &extractTotals[2][0]); + (*extractPackedPixel)(isSwap, + (src+imageSizeInBytes+rowSizeInBytes), + &extractTotals[3][0]); + for (cc = 0; cc < components; cc++) { + int kk; + + /* grab 4 pixels to average */ + totals[cc]= 0.0; + /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ + * extractTotals[2][RED]+extractTotals[3][RED]; + * totals[RED]/= 4.0; + */ + for (kk = 0; kk < BOX4; kk++) { + totals[cc]+= extractTotals[kk][cc]; + } + totals[cc]/= (float)BOX4; + } + (*shovePackedPixel)(totals,outIndex,dataOut); + + outIndex++; + + /* skip over to next vertical square of 4 */ + src+= imageSizeInBytes + imageSizeInBytes; + } + } + /* assert() */ + } + +} /* halveImagePackedPixelSlice() */ + +static void halveImagePackedPixel3D(int components, + void (*extractPackedPixel) + (int, const void *,GLfloat []), + void (*shovePackedPixel) + (const GLfloat [],int, void *), + GLint width, GLint height, GLint depth, + const void *dataIn, void *dataOut, + GLint pixelSizeInBytes, + GLint rowSizeInBytes, + GLint imageSizeInBytes, + GLint isSwap) +{ + if (depth == 1) { + assert(1 <= width && 1 <= height); + + halveImagePackedPixel(components,extractPackedPixel,shovePackedPixel, + width,height,dataIn,dataOut,pixelSizeInBytes, + rowSizeInBytes,isSwap); + return; + } + /* a horizontal or vertical slice viewed from top */ + else if (width == 1 || height == 1) { + assert(1 <= depth); + + halveImagePackedPixelSlice(components, + extractPackedPixel,shovePackedPixel, + width, height, depth, dataIn, dataOut, + pixelSizeInBytes, rowSizeInBytes, + imageSizeInBytes, isSwap); + return; + } + { + int ii, jj, dd; + + int halfWidth= width / 2; + int halfHeight= height / 2; + int halfDepth= depth / 2; + const char *src= (const char *) dataIn; + int padBytes= rowSizeInBytes - (width*pixelSizeInBytes); + int outIndex= 0; + + for (dd= 0; dd < halfDepth; dd++) { + for (ii= 0; ii< halfHeight; ii++) { + for (jj= 0; jj< halfWidth; jj++) { +#define BOX8 8 + float totals[4]; /* 4 is maximum components */ + float extractTotals[BOX8][4]; /* 4 is maximum components */ + int cc; + + (*extractPackedPixel)(isSwap,src, + &extractTotals[0][0]); + (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes), + &extractTotals[1][0]); + (*extractPackedPixel)(isSwap,(src+rowSizeInBytes), + &extractTotals[2][0]); + (*extractPackedPixel)(isSwap, + (src+rowSizeInBytes+pixelSizeInBytes), + &extractTotals[3][0]); + + (*extractPackedPixel)(isSwap,(src+imageSizeInBytes), + &extractTotals[4][0]); + (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes+imageSizeInBytes), + &extractTotals[5][0]); + (*extractPackedPixel)(isSwap,(src+rowSizeInBytes+imageSizeInBytes), + &extractTotals[6][0]); + (*extractPackedPixel)(isSwap, + (src+rowSizeInBytes+pixelSizeInBytes+imageSizeInBytes), + &extractTotals[7][0]); + for (cc = 0; cc < components; cc++) { + int kk; + + /* grab 8 pixels to average */ + totals[cc]= 0.0; + /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ + * extractTotals[2][RED]+extractTotals[3][RED]+ + * extractTotals[4][RED]+extractTotals[5][RED]+ + * extractTotals[6][RED]+extractTotals[7][RED]; + * totals[RED]/= 8.0; + */ + for (kk = 0; kk < BOX8; kk++) { + totals[cc]+= extractTotals[kk][cc]; + } + totals[cc]/= (float)BOX8; + } + (*shovePackedPixel)(totals,outIndex,dataOut); + + outIndex++; + /* skip over to next square of 4 */ + src+= pixelSizeInBytes + pixelSizeInBytes; + } + /* skip past pad bytes, if any, to get to next row */ + src+= padBytes; + + /* src is at beginning of a row here, but it's the second row of + * the square block of 4 pixels that we just worked on so we + * need to go one more row. + * i.e., + * OO... + * here -->OO... + * but want -->OO... + * OO... + * ... + */ + src+= rowSizeInBytes; + } + + src+= imageSizeInBytes; + } /* for dd */ + + /* both pointers must reach one byte after the end */ + assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]); + assert(outIndex == halfWidth * halfHeight * halfDepth); + } /* for dd */ + +} /* halveImagePackedPixel3D() */ + +static int gluBuild3DMipmapLevelsCore(GLenum target, GLint internalFormat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLsizei widthPowerOf2, + GLsizei heightPowerOf2, + GLsizei depthPowerOf2, + GLenum format, GLenum type, + GLint userLevel, + GLint baseLevel,GLint maxLevel, + const void *data) +{ + GLint newWidth, newHeight, newDepth; + GLint level, levels; + const void *usersImage; + void *srcImage, *dstImage; + __GLU_INIT_SWAP_IMAGE; + GLint memReq; + GLint cmpts; + + GLint myswapBytes, groupsPerLine, elementSize, groupSize; + GLint rowsPerImage, imageSize; + GLint rowSize, padding; + PixelStorageModes psm; + + assert(checkMipmapArgs(internalFormat,format,type) == 0); + assert(width >= 1 && height >= 1 && depth >= 1); + assert(type != GL_BITMAP); + + srcImage = dstImage = NULL; + + newWidth= widthPowerOf2; + newHeight= heightPowerOf2; + newDepth= depthPowerOf2; + levels = computeLog(newWidth); + level = computeLog(newHeight); + if (level > levels) levels=level; + level = computeLog(newDepth); + if (level > levels) levels=level; + + levels+= userLevel; + + retrieveStoreModes3D(&psm); + myswapBytes = psm.unpack_swap_bytes; + cmpts = elements_per_group(format,type); + if (psm.unpack_row_length > 0) { + groupsPerLine = psm.unpack_row_length; + } else { + groupsPerLine = width; + } + + elementSize = bytes_per_element(type); + groupSize = elementSize * cmpts; + if (elementSize == 1) myswapBytes = 0; + + /* 3dstuff begin */ + if (psm.unpack_image_height > 0) { + rowsPerImage= psm.unpack_image_height; + } + else { + rowsPerImage= height; + } + + /* 3dstuff end */ + rowSize = groupsPerLine * groupSize; + padding = (rowSize % psm.unpack_alignment); + if (padding) { + rowSize += psm.unpack_alignment - padding; + } + + imageSize= rowsPerImage * rowSize; /* 3dstuff */ + + usersImage = (const GLubyte *)data + psm.unpack_skip_rows * rowSize + + psm.unpack_skip_pixels * groupSize + + /* 3dstuff */ + psm.unpack_skip_images * imageSize; + + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); + + level = userLevel; + + if (width == newWidth && height == newHeight && depth == newDepth) { + /* Use usersImage for level userLevel */ + if (baseLevel <= level && level <= maxLevel) { + gluTexImage3D(target, level, internalFormat, width, + height, depth, 0, format, type, + usersImage); + } + if(levels == 0) { /* we're done. clean up and return */ + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height); + return 0; + } + { + int nextWidth= newWidth/2; + int nextHeight= newHeight/2; + int nextDepth= newDepth/2; + + /* clamp to 1 */ + if (nextWidth < 1) nextWidth= 1; + if (nextHeight < 1) nextHeight= 1; + if (nextDepth < 1) nextDepth= 1; + memReq = imageSize3D(nextWidth, nextHeight, nextDepth, format, type); + } + switch(type) { + case GL_UNSIGNED_BYTE: + dstImage = (GLubyte *)malloc(memReq); + break; + case GL_BYTE: + dstImage = (GLbyte *)malloc(memReq); + break; + case GL_UNSIGNED_SHORT: + dstImage = (GLushort *)malloc(memReq); + break; + case GL_SHORT: + dstImage = (GLshort *)malloc(memReq); + break; + case GL_UNSIGNED_INT: + dstImage = (GLuint *)malloc(memReq); + break; + case GL_INT: + dstImage = (GLint *)malloc(memReq); + break; + case GL_FLOAT: + dstImage = (GLfloat *)malloc(memReq); + break; + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + dstImage = (GLubyte *)malloc(memReq); + break; + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + dstImage = (GLushort *)malloc(memReq); + break; + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + dstImage = (GLuint *)malloc(memReq); + break; + default: + return GLU_INVALID_ENUM; /* assertion */ + } + if (dstImage == NULL) { + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height); + return GLU_OUT_OF_MEMORY; + } + else + switch(type) { + case GL_UNSIGNED_BYTE: + if (depth > 1) { + halveImage3D(cmpts,extractUbyte,shoveUbyte, + width,height,depth, + usersImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_ubyte(cmpts,width,height,usersImage,dstImage, + elementSize,rowSize,groupSize); + } + break; + case GL_BYTE: + if (depth > 1) { + halveImage3D(cmpts,extractSbyte,shoveSbyte, + width,height,depth, + usersImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_byte(cmpts,width,height,usersImage,dstImage, + elementSize,rowSize,groupSize); + } + break; + case GL_UNSIGNED_SHORT: + if (depth > 1) { + halveImage3D(cmpts,extractUshort,shoveUshort, + width,height,depth, + usersImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_ushort(cmpts,width,height,usersImage,dstImage, + elementSize,rowSize,groupSize,myswapBytes); + } + break; + case GL_SHORT: + if (depth > 1) { + halveImage3D(cmpts,extractSshort,shoveSshort, + width,height,depth, + usersImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_short(cmpts,width,height,usersImage,dstImage, + elementSize,rowSize,groupSize,myswapBytes); + } + break; + case GL_UNSIGNED_INT: + if (depth > 1) { + halveImage3D(cmpts,extractUint,shoveUint, + width,height,depth, + usersImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_uint(cmpts,width,height,usersImage,dstImage, + elementSize,rowSize,groupSize,myswapBytes); + } + break; + case GL_INT: + if (depth > 1) { + halveImage3D(cmpts,extractSint,shoveSint, + width,height,depth, + usersImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_int(cmpts,width,height,usersImage,dstImage, + elementSize,rowSize,groupSize,myswapBytes); + } + break; + case GL_FLOAT: + if (depth > 1 ) { + halveImage3D(cmpts,extractFloat,shoveFloat, + width,height,depth, + usersImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_float(cmpts,width,height,usersImage,dstImage, + elementSize,rowSize,groupSize,myswapBytes); + } + break; + case GL_UNSIGNED_BYTE_3_3_2: + assert(format == GL_RGB); + halveImagePackedPixel3D(3,extract332,shove332, + width,height,depth,usersImage,dstImage, + elementSize,rowSize,imageSize,myswapBytes); + break; + case GL_UNSIGNED_BYTE_2_3_3_REV: + assert(format == GL_RGB); + halveImagePackedPixel3D(3,extract233rev,shove233rev, + width,height,depth,usersImage,dstImage, + elementSize,rowSize,imageSize,myswapBytes); + break; + case GL_UNSIGNED_SHORT_5_6_5: + halveImagePackedPixel3D(3,extract565,shove565, + width,height,depth,usersImage,dstImage, + elementSize,rowSize,imageSize,myswapBytes); + break; + case GL_UNSIGNED_SHORT_5_6_5_REV: + halveImagePackedPixel3D(3,extract565rev,shove565rev, + width,height,depth,usersImage,dstImage, + elementSize,rowSize,imageSize,myswapBytes); + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + halveImagePackedPixel3D(4,extract4444,shove4444, + width,height,depth,usersImage,dstImage, + elementSize,rowSize,imageSize,myswapBytes); + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + halveImagePackedPixel3D(4,extract4444rev,shove4444rev, + width,height,depth,usersImage,dstImage, + elementSize,rowSize,imageSize,myswapBytes); + break; + case GL_UNSIGNED_SHORT_5_5_5_1: + halveImagePackedPixel3D(4,extract5551,shove5551, + width,height,depth,usersImage,dstImage, + elementSize,rowSize,imageSize,myswapBytes); + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + halveImagePackedPixel3D(4,extract1555rev,shove1555rev, + width,height,depth,usersImage,dstImage, + elementSize,rowSize,imageSize,myswapBytes); + break; + case GL_UNSIGNED_INT_8_8_8_8: + halveImagePackedPixel3D(4,extract8888,shove8888, + width,height,depth,usersImage,dstImage, + elementSize,rowSize,imageSize,myswapBytes); + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + halveImagePackedPixel3D(4,extract8888rev,shove8888rev, + width,height,depth,usersImage,dstImage, + elementSize,rowSize,imageSize,myswapBytes); + break; + case GL_UNSIGNED_INT_10_10_10_2: + halveImagePackedPixel3D(4,extract1010102,shove1010102, + width,height,depth,usersImage,dstImage, + elementSize,rowSize,imageSize,myswapBytes); + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + halveImagePackedPixel3D(4,extract2101010rev,shove2101010rev, + width,height,depth,usersImage,dstImage, + elementSize,rowSize,imageSize,myswapBytes); + break; + default: + assert(0); + break; + } + newWidth = width/2; + newHeight = height/2; + newDepth = depth/2; + /* clamp to 1 */ + if (newWidth < 1) newWidth= 1; + if (newHeight < 1) newHeight= 1; + if (newDepth < 1) newDepth= 1; + + myswapBytes = 0; + rowSize = newWidth * groupSize; + imageSize= rowSize * newHeight; /* 3dstuff */ + memReq = imageSize3D(newWidth, newHeight, newDepth, format, type); + /* Swap srcImage and dstImage */ + __GLU_SWAP_IMAGE(srcImage,dstImage); + switch(type) { + case GL_UNSIGNED_BYTE: + dstImage = (GLubyte *)malloc(memReq); + break; + case GL_BYTE: + dstImage = (GLbyte *)malloc(memReq); + break; + case GL_UNSIGNED_SHORT: + dstImage = (GLushort *)malloc(memReq); + break; + case GL_SHORT: + dstImage = (GLshort *)malloc(memReq); + break; + case GL_UNSIGNED_INT: + dstImage = (GLuint *)malloc(memReq); + break; + case GL_INT: + dstImage = (GLint *)malloc(memReq); + break; + case GL_FLOAT: + dstImage = (GLfloat *)malloc(memReq); + break; + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + dstImage = (GLubyte *)malloc(memReq); + break; + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + dstImage = (GLushort *)malloc(memReq); + break; + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + dstImage = (GLuint *)malloc(memReq); + break; + default: + return GLU_INVALID_ENUM; /* assertion */ + } + if (dstImage == NULL) { + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height); + return GLU_OUT_OF_MEMORY; + } + /* level userLevel+1 is in srcImage; level userLevel already saved */ + level = userLevel+1; + } else {/* user's image is *not* nice power-of-2 sized square */ + memReq = imageSize3D(newWidth, newHeight, newDepth, format, type); + switch(type) { + case GL_UNSIGNED_BYTE: + dstImage = (GLubyte *)malloc(memReq); + break; + case GL_BYTE: + dstImage = (GLbyte *)malloc(memReq); + break; + case GL_UNSIGNED_SHORT: + dstImage = (GLushort *)malloc(memReq); + break; + case GL_SHORT: + dstImage = (GLshort *)malloc(memReq); + break; + case GL_UNSIGNED_INT: + dstImage = (GLuint *)malloc(memReq); + break; + case GL_INT: + dstImage = (GLint *)malloc(memReq); + break; + case GL_FLOAT: + dstImage = (GLfloat *)malloc(memReq); + break; + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + dstImage = (GLubyte *)malloc(memReq); + break; + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + dstImage = (GLushort *)malloc(memReq); + break; + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + dstImage = (GLuint *)malloc(memReq); + break; + default: + return GLU_INVALID_ENUM; /* assertion */ + } + + if (dstImage == NULL) { + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height); + return GLU_OUT_OF_MEMORY; + } + /*printf("Build3DMipmaps(): ScaleImage3D %d %d %d->%d %d %d\n", + width,height,depth,newWidth,newHeight,newDepth);*/ + + gluScaleImage3D(format, width, height, depth, type, usersImage, + newWidth, newHeight, newDepth, type, dstImage); + + myswapBytes = 0; + rowSize = newWidth * groupSize; + imageSize = rowSize * newHeight; /* 3dstuff */ + /* Swap dstImage and srcImage */ + __GLU_SWAP_IMAGE(srcImage,dstImage); + + if(levels != 0) { /* use as little memory as possible */ + { + int nextWidth= newWidth/2; + int nextHeight= newHeight/2; + int nextDepth= newDepth/2; + if (nextWidth < 1) nextWidth= 1; + if (nextHeight < 1) nextHeight= 1; + if (nextDepth < 1) nextDepth= 1; + + memReq = imageSize3D(nextWidth, nextHeight, nextDepth, format, type); + } + switch(type) { + case GL_UNSIGNED_BYTE: + dstImage = (GLubyte *)malloc(memReq); + break; + case GL_BYTE: + dstImage = (GLbyte *)malloc(memReq); + break; + case GL_UNSIGNED_SHORT: + dstImage = (GLushort *)malloc(memReq); + break; + case GL_SHORT: + dstImage = (GLshort *)malloc(memReq); + break; + case GL_UNSIGNED_INT: + dstImage = (GLuint *)malloc(memReq); + break; + case GL_INT: + dstImage = (GLint *)malloc(memReq); + break; + case GL_FLOAT: + dstImage = (GLfloat *)malloc(memReq); + break; + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + dstImage = (GLubyte *)malloc(memReq); + break; + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + dstImage = (GLushort *)malloc(memReq); + break; + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + dstImage = (GLuint *)malloc(memReq); + break; + default: + return GLU_INVALID_ENUM; /* assertion */ + } + if (dstImage == NULL) { + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height); + return GLU_OUT_OF_MEMORY; + } + } + /* level userLevel is in srcImage; nothing saved yet */ + level = userLevel; + } + + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + if (baseLevel <= level && level <= maxLevel) { + gluTexImage3D(target, level, internalFormat, newWidth, newHeight, newDepth, + 0,format, type, (void *)srcImage); + } + level++; /* update current level for the loop */ + for (; level <= levels; level++) { + switch(type) { + case GL_UNSIGNED_BYTE: + if (newDepth > 1) { + halveImage3D(cmpts,extractUbyte,shoveUbyte, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_ubyte(cmpts,newWidth,newHeight,srcImage,dstImage, + elementSize,rowSize,groupSize); + } + break; + case GL_BYTE: + if (newDepth > 1) { + halveImage3D(cmpts,extractSbyte,shoveSbyte, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_byte(cmpts,newWidth,newHeight,srcImage,dstImage, + elementSize,rowSize,groupSize); + } + break; + case GL_UNSIGNED_SHORT: + if (newDepth > 1) { + halveImage3D(cmpts,extractUshort,shoveUshort, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_ushort(cmpts,newWidth,newHeight,srcImage,dstImage, + elementSize,rowSize,groupSize,myswapBytes); + } + break; + case GL_SHORT: + if (newDepth > 1) { + halveImage3D(cmpts,extractSshort,shoveSshort, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_short(cmpts,newWidth,newHeight,srcImage,dstImage, + elementSize,rowSize,groupSize,myswapBytes); + } + break; + case GL_UNSIGNED_INT: + if (newDepth > 1) { + halveImage3D(cmpts,extractUint,shoveUint, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_uint(cmpts,newWidth,newHeight,srcImage,dstImage, + elementSize,rowSize,groupSize,myswapBytes); + } + break; + case GL_INT: + if (newDepth > 1) { + halveImage3D(cmpts,extractSint,shoveSint, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_int(cmpts,newWidth,newHeight,srcImage,dstImage, + elementSize,rowSize,groupSize,myswapBytes); + } + break; + case GL_FLOAT: + if (newDepth > 1) { + halveImage3D(cmpts,extractFloat,shoveFloat, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,groupSize,rowSize, + imageSize,myswapBytes); + } + else { + halveImage_float(cmpts,newWidth,newHeight,srcImage,dstImage, + elementSize,rowSize,groupSize,myswapBytes); + } + break; + case GL_UNSIGNED_BYTE_3_3_2: + halveImagePackedPixel3D(3,extract332,shove332, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,rowSize, + imageSize,myswapBytes); + break; + case GL_UNSIGNED_BYTE_2_3_3_REV: + halveImagePackedPixel3D(3,extract233rev,shove233rev, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,rowSize, + imageSize,myswapBytes); + break; + case GL_UNSIGNED_SHORT_5_6_5: + halveImagePackedPixel3D(3,extract565,shove565, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,rowSize, + imageSize,myswapBytes); + break; + case GL_UNSIGNED_SHORT_5_6_5_REV: + halveImagePackedPixel3D(3,extract565rev,shove565rev, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,rowSize, + imageSize,myswapBytes); + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + halveImagePackedPixel3D(4,extract4444,shove4444, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,rowSize, + imageSize,myswapBytes); + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + halveImagePackedPixel3D(4,extract4444rev,shove4444rev, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,rowSize, + imageSize,myswapBytes); + break; + case GL_UNSIGNED_SHORT_5_5_5_1: + halveImagePackedPixel3D(4,extract5551,shove5551, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,rowSize, + imageSize,myswapBytes); + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + halveImagePackedPixel3D(4,extract1555rev,shove1555rev, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,rowSize, + imageSize,myswapBytes); + break; + case GL_UNSIGNED_INT_8_8_8_8: + halveImagePackedPixel3D(4,extract8888,shove8888, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,rowSize, + imageSize,myswapBytes); + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + halveImagePackedPixel3D(4,extract8888rev,shove8888rev, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,rowSize, + imageSize,myswapBytes); + break; + case GL_UNSIGNED_INT_10_10_10_2: + halveImagePackedPixel3D(4,extract1010102,shove1010102, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,rowSize, + imageSize,myswapBytes); + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + halveImagePackedPixel3D(4,extract2101010rev,shove2101010rev, + newWidth,newHeight,newDepth, + srcImage,dstImage,elementSize,rowSize, + imageSize,myswapBytes); + break; + default: + assert(0); + break; + } + + __GLU_SWAP_IMAGE(srcImage,dstImage); + + if (newWidth > 1) { newWidth /= 2; rowSize /= 2;} + if (newHeight > 1) { newHeight /= 2; imageSize = rowSize * newHeight; } + if (newDepth > 1) newDepth /= 2; + { + /* call tex image with srcImage untouched since it's not padded */ + if (baseLevel <= level && level <= maxLevel) { + gluTexImage3D(target, level, internalFormat, newWidth, newHeight, + newDepth,0, format, type, (void *) srcImage); + } + } + } /* for level */ + glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); + glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); + glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); + glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); + glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height); + + free(srcImage); /*if you get to here, a srcImage has always been malloc'ed*/ + if (dstImage) { /* if it's non-rectangular and only 1 level */ + free(dstImage); + } + return 0; +} /* gluBuild3DMipmapLevelsCore() */ + +GLint GLAPIENTRY +gluBuild3DMipmapLevels(GLenum target, GLint internalFormat, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + GLint userLevel, GLint baseLevel, GLint maxLevel, + const void *data) +{ + int level, levels; + + int rc= checkMipmapArgs(internalFormat,format,type); + if (rc != 0) return rc; + + if (width < 1 || height < 1 || depth < 1) { + return GLU_INVALID_VALUE; + } + + if(type == GL_BITMAP) { + return GLU_INVALID_ENUM; + } + + levels = computeLog(width); + level = computeLog(height); + if (level > levels) levels=level; + level = computeLog(depth); + if (level > levels) levels=level; + + levels+= userLevel; + if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels)) + return GLU_INVALID_VALUE; + + return gluBuild3DMipmapLevelsCore(target, internalFormat, + width, height, depth, + width, height, depth, + format, type, + userLevel, baseLevel, maxLevel, + data); +} /* gluBuild3DMipmapLevels() */ + +GLint GLAPIENTRY +gluBuild3DMipmaps(GLenum target, GLint internalFormat, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const void *data) +{ + GLint widthPowerOf2, heightPowerOf2, depthPowerOf2; + int level, levels; + + int rc= checkMipmapArgs(internalFormat,format,type); + if (rc != 0) return rc; + + if (width < 1 || height < 1 || depth < 1) { + return GLU_INVALID_VALUE; + } + + if(type == GL_BITMAP) { + return GLU_INVALID_ENUM; + } + + closestFit3D(target,width,height,depth,internalFormat,format,type, + &widthPowerOf2,&heightPowerOf2,&depthPowerOf2); + + levels = computeLog(widthPowerOf2); + level = computeLog(heightPowerOf2); + if (level > levels) levels=level; + level = computeLog(depthPowerOf2); + if (level > levels) levels=level; + + return gluBuild3DMipmapLevelsCore(target, internalFormat, + width, height, depth, + widthPowerOf2, heightPowerOf2, + depthPowerOf2, + format, type, 0, 0, levels, + data); +} /* gluBuild3DMipmaps() */ + +static GLdouble extractUbyte(int isSwap, const void *ubyte) +{ + isSwap= isSwap; /* turn off warnings */ + + assert(*((const GLubyte *)ubyte) <= 255); + + return (GLdouble)(*((const GLubyte *)ubyte)); +} /* extractUbyte() */ + +static void shoveUbyte(GLdouble value, int index, void *data) +{ + assert(0.0 <= value && value < 256.0); + + ((GLubyte *)data)[index]= (GLubyte)value; +} /* shoveUbyte() */ + +static GLdouble extractSbyte(int isSwap, const void *sbyte) +{ + isSwap= isSwap; /* turn off warnings */ + + assert(*((const GLbyte *)sbyte) <= 127); + + return (GLdouble)(*((const GLbyte *)sbyte)); +} /* extractSbyte() */ + +static void shoveSbyte(GLdouble value, int index, void *data) +{ + ((GLbyte *)data)[index]= (GLbyte)value; +} /* shoveSbyte() */ + +static GLdouble extractUshort(int isSwap, const void *uitem) +{ + GLushort ushort; + + if (isSwap) { + ushort= __GLU_SWAP_2_BYTES(uitem); + } + else { + ushort= *(const GLushort *)uitem; + } + + assert(ushort <= 65535); + + return (GLdouble)ushort; +} /* extractUshort() */ + +static void shoveUshort(GLdouble value, int index, void *data) +{ + assert(0.0 <= value && value < 65536.0); + + ((GLushort *)data)[index]= (GLushort)value; +} /* shoveUshort() */ + +static GLdouble extractSshort(int isSwap, const void *sitem) +{ + GLshort sshort; + + if (isSwap) { + sshort= __GLU_SWAP_2_BYTES(sitem); + } + else { + sshort= *(const GLshort *)sitem; + } + + assert(sshort <= 32767); + + return (GLdouble)sshort; +} /* extractSshort() */ + +static void shoveSshort(GLdouble value, int index, void *data) +{ + assert(0.0 <= value && value < 32768.0); + + ((GLshort *)data)[index]= (GLshort)value; +} /* shoveSshort() */ + +static GLdouble extractUint(int isSwap, const void *uitem) +{ + GLuint uint; + + if (isSwap) { + uint= __GLU_SWAP_4_BYTES(uitem); + } + else { + uint= *(const GLuint *)uitem; + } + + assert(uint <= 0xffffffff); + + return (GLdouble)uint; +} /* extractUint() */ + +static void shoveUint(GLdouble value, int index, void *data) +{ + assert(0.0 <= value && value <= (GLdouble) UINT_MAX); + + ((GLuint *)data)[index]= (GLuint)value; +} /* shoveUint() */ + +static GLdouble extractSint(int isSwap, const void *sitem) +{ + GLint sint; + + if (isSwap) { + sint= __GLU_SWAP_4_BYTES(sitem); + } + else { + sint= *(const GLint *)sitem; + } + + assert(sint <= 0x7fffffff); + + return (GLdouble)sint; +} /* extractSint() */ + +static void shoveSint(GLdouble value, int index, void *data) +{ + assert(0.0 <= value && value <= (GLdouble) INT_MAX); + + ((GLint *)data)[index]= (GLint)value; +} /* shoveSint() */ + +static GLdouble extractFloat(int isSwap, const void *item) +{ + GLfloat ffloat; + + if (isSwap) { + ffloat= __GLU_SWAP_4_BYTES(item); + } + else { + ffloat= *(const GLfloat *)item; + } + + assert(ffloat <= 1.0); + + return (GLdouble)ffloat; +} /* extractFloat() */ + +static void shoveFloat(GLdouble value, int index, void *data) +{ + assert(0.0 <= value && value <= 1.0); + + ((GLfloat *)data)[index]= value; +} /* shoveFloat() */ + +static void halveImageSlice(int components, + GLdouble (*extract)(int, const void *), + void (*shove)(GLdouble, int, void *), + GLint width, GLint height, GLint depth, + const void *dataIn, void *dataOut, + GLint elementSizeInBytes, + GLint groupSizeInBytes, + GLint rowSizeInBytes, + GLint imageSizeInBytes, + GLint isSwap) +{ + int ii, jj; + int halfWidth= width / 2; + int halfHeight= height / 2; + int halfDepth= depth / 2; + const char *src= (const char *)dataIn; + int rowPadBytes= rowSizeInBytes - (width * groupSizeInBytes); + int imagePadBytes= imageSizeInBytes - (width*height*groupSizeInBytes); + int outIndex= 0; + + assert((width == 1 || height == 1) && depth >= 2); + + if (width == height) { /* a 1-pixel column viewed from top */ + /* printf("1-column\n");*/ + assert(width == 1 && height == 1); + assert(depth >= 2); + + for (ii= 0; ii< halfDepth; ii++) { + int cc; + + for (cc = 0; cc < components; cc++) { + double totals[4]; + double extractTotals[BOX2][4]; + int kk; + + extractTotals[0][cc]= (*extract)(isSwap,src); + extractTotals[1][cc]= (*extract)(isSwap,(src+imageSizeInBytes)); + + /* average 2 pixels since only a column */ + totals[cc]= 0.0; + /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]; + * totals[RED]/= 2.0; + */ + for (kk = 0; kk < BOX2; kk++) { + totals[cc]+= extractTotals[kk][cc]; + } + totals[cc]/= (double)BOX2; + + (*shove)(totals[cc],outIndex,dataOut); + outIndex++; + src+= elementSizeInBytes; + } /* for cc */ + + /* skip over to next group of 2 */ + src+= rowSizeInBytes; + } /* for ii */ + + assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]); + assert(outIndex == halfDepth * components); + } + else if (height == 1) { /* horizontal slice viewed from top */ + /* printf("horizontal slice\n"); */ + assert(width != 1); + + for (ii= 0; ii< halfDepth; ii++) { + for (jj= 0; jj< halfWidth; jj++) { + int cc; + + for (cc = 0; cc < components; cc++) { + int kk; + double totals[4]; + double extractTotals[BOX4][4]; + + extractTotals[0][cc]=(*extract)(isSwap,src); + extractTotals[1][cc]=(*extract)(isSwap, + (src+groupSizeInBytes)); + extractTotals[2][cc]=(*extract)(isSwap, + (src+imageSizeInBytes)); + extractTotals[3][cc]=(*extract)(isSwap, + (src+imageSizeInBytes+groupSizeInBytes)); + + /* grab 4 pixels to average */ + totals[cc]= 0.0; + /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ + * extractTotals[2][RED]+extractTotals[3][RED]; + * totals[RED]/= 4.0; + */ + for (kk = 0; kk < BOX4; kk++) { + totals[cc]+= extractTotals[kk][cc]; + } + totals[cc]/= (double)BOX4; + + (*shove)(totals[cc],outIndex,dataOut); + outIndex++; + + src+= elementSizeInBytes; + } /* for cc */ + + /* skip over to next horizontal square of 4 */ + src+= groupSizeInBytes; + } /* for jj */ + src+= rowPadBytes; + + src+= rowSizeInBytes; + } /* for ii */ + + assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]); + assert(outIndex == halfWidth * halfDepth * components); + } + else if (width == 1) { /* vertical slice viewed from top */ + /* printf("vertical slice\n"); */ + assert(height != 1); + + for (ii= 0; ii< halfDepth; ii++) { + for (jj= 0; jj< halfHeight; jj++) { + int cc; + + for (cc = 0; cc < components; cc++) { + int kk; + double totals[4]; + double extractTotals[BOX4][4]; + + extractTotals[0][cc]=(*extract)(isSwap,src); + extractTotals[1][cc]=(*extract)(isSwap, + (src+rowSizeInBytes)); + extractTotals[2][cc]=(*extract)(isSwap, + (src+imageSizeInBytes)); + extractTotals[3][cc]=(*extract)(isSwap, + (src+imageSizeInBytes+rowSizeInBytes)); + + /* grab 4 pixels to average */ + totals[cc]= 0.0; + /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ + * extractTotals[2][RED]+extractTotals[3][RED]; + * totals[RED]/= 4.0; + */ + for (kk = 0; kk < BOX4; kk++) { + totals[cc]+= extractTotals[kk][cc]; + } + totals[cc]/= (double)BOX4; + + (*shove)(totals[cc],outIndex,dataOut); + outIndex++; + + src+= elementSizeInBytes; + } /* for cc */ + src+= rowPadBytes; + + /* skip over to next vertical square of 4 */ + src+= rowSizeInBytes; + } /* for jj */ + src+= imagePadBytes; + + src+= imageSizeInBytes; + } /* for ii */ + + assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]); + assert(outIndex == halfHeight * halfDepth * components); + } + +} /* halveImageSlice() */ + +static void halveImage3D(int components, + GLdouble (*extract)(int, const void *), + void (*shove)(GLdouble, int, void *), + GLint width, GLint height, GLint depth, + const void *dataIn, void *dataOut, + GLint elementSizeInBytes, + GLint groupSizeInBytes, + GLint rowSizeInBytes, + GLint imageSizeInBytes, + GLint isSwap) +{ + assert(depth > 1); + + /* a horizontal/vertical/one-column slice viewed from top */ + if (width == 1 || height == 1) { + assert(1 <= depth); + + halveImageSlice(components,extract,shove, width, height, depth, + dataIn, dataOut, elementSizeInBytes, groupSizeInBytes, + rowSizeInBytes, imageSizeInBytes, isSwap); + return; + } + { + int ii, jj, dd; + + int halfWidth= width / 2; + int halfHeight= height / 2; + int halfDepth= depth / 2; + const char *src= (const char *) dataIn; + int rowPadBytes= rowSizeInBytes - (width*groupSizeInBytes); + int imagePadBytes= imageSizeInBytes - (width*height*groupSizeInBytes); + int outIndex= 0; + + for (dd= 0; dd < halfDepth; dd++) { + for (ii= 0; ii< halfHeight; ii++) { + for (jj= 0; jj< halfWidth; jj++) { + int cc; + + for (cc= 0; cc < components; cc++) { + int kk; +#define BOX8 8 + double totals[4]; /* 4 is maximum components */ + double extractTotals[BOX8][4]; /* 4 is maximum components */ + + extractTotals[0][cc]= (*extract)(isSwap,src); + extractTotals[1][cc]= (*extract)(isSwap, + (src+groupSizeInBytes)); + extractTotals[2][cc]= (*extract)(isSwap, + (src+rowSizeInBytes)); + extractTotals[3][cc]= (*extract)(isSwap, + (src+rowSizeInBytes+groupSizeInBytes)); + + extractTotals[4][cc]= (*extract)(isSwap, + (src+imageSizeInBytes)); + + extractTotals[5][cc]= (*extract)(isSwap, + (src+groupSizeInBytes+imageSizeInBytes)); + extractTotals[6][cc]= (*extract)(isSwap, + (src+rowSizeInBytes+imageSizeInBytes)); + extractTotals[7][cc]= (*extract)(isSwap, + (src+rowSizeInBytes+groupSizeInBytes+imageSizeInBytes)); + + totals[cc]= 0.0; + + /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ + * extractTotals[2][RED]+extractTotals[3][RED]+ + * extractTotals[4][RED]+extractTotals[5][RED]+ + * extractTotals[6][RED]+extractTotals[7][RED]; + * totals[RED]/= 8.0; + */ + for (kk = 0; kk < BOX8; kk++) { + totals[cc]+= extractTotals[kk][cc]; + } + totals[cc]/= (double)BOX8; + + (*shove)(totals[cc],outIndex,dataOut); + + outIndex++; + + src+= elementSizeInBytes; /* go to next component */ + } /* for cc */ + + /* skip over to next square of 4 */ + src+= groupSizeInBytes; + } /* for jj */ + /* skip past pad bytes, if any, to get to next row */ + src+= rowPadBytes; + + /* src is at beginning of a row here, but it's the second row of + * the square block of 4 pixels that we just worked on so we + * need to go one more row. + * i.e., + * OO... + * here -->OO... + * but want -->OO... + * OO... + * ... + */ + src+= rowSizeInBytes; + } /* for ii */ + + /* skip past pad bytes, if any, to get to next image */ + src+= imagePadBytes; + + src+= imageSizeInBytes; + } /* for dd */ + + /* both pointers must reach one byte after the end */ + assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]); + assert(outIndex == halfWidth * halfHeight * halfDepth * components); + } +} /* halveImage3D() */ + + + +/*** mipmap.c ***/ + diff --git a/Dependencies/GLU/normal.c b/Dependencies/GLU/normal.c new file mode 100644 index 0000000..0a2494b --- /dev/null +++ b/Dependencies/GLU/normal.c @@ -0,0 +1,253 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "gluos.h" +#include "mesh.h" +#include "tess.h" +#include "normal.h" +#include +#include + +#define TRUE 1 +#define FALSE 0 + +#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2]) + +#if 0 +static void Normalize( GLdouble v[3] ) +{ + GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + + assert( len > 0 ); + len = sqrt( len ); + v[0] /= len; + v[1] /= len; + v[2] /= len; +} +#endif + +#undef ABS +#define ABS(x) ((x) < 0 ? -(x) : (x)) + +static int LongAxis( GLdouble v[3] ) +{ + int i = 0; + + if( ABS(v[1]) > ABS(v[0]) ) { i = 1; } + if( ABS(v[2]) > ABS(v[i]) ) { i = 2; } + return i; +} + +static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] ) +{ + GLUvertex *v, *v1, *v2; + GLdouble c, tLen2, maxLen2; + GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3]; + GLUvertex *maxVert[3], *minVert[3]; + GLUvertex *vHead = &tess->mesh->vHead; + int i; + + maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD; + minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD; + + for( v = vHead->next; v != vHead; v = v->next ) { + for( i = 0; i < 3; ++i ) { + c = v->coords[i]; + if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; } + if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; } + } + } + + /* Find two vertices separated by at least 1/sqrt(3) of the maximum + * distance between any two vertices + */ + i = 0; + if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; } + if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; } + if( minVal[i] >= maxVal[i] ) { + /* All vertices are the same -- normal doesn't matter */ + norm[0] = 0; norm[1] = 0; norm[2] = 1; + return; + } + + /* Look for a third vertex which forms the triangle with maximum area + * (Length of normal == twice the triangle area) + */ + maxLen2 = 0; + v1 = minVert[i]; + v2 = maxVert[i]; + d1[0] = v1->coords[0] - v2->coords[0]; + d1[1] = v1->coords[1] - v2->coords[1]; + d1[2] = v1->coords[2] - v2->coords[2]; + for( v = vHead->next; v != vHead; v = v->next ) { + d2[0] = v->coords[0] - v2->coords[0]; + d2[1] = v->coords[1] - v2->coords[1]; + d2[2] = v->coords[2] - v2->coords[2]; + tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1]; + tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2]; + tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0]; + tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2]; + if( tLen2 > maxLen2 ) { + maxLen2 = tLen2; + norm[0] = tNorm[0]; + norm[1] = tNorm[1]; + norm[2] = tNorm[2]; + } + } + + if( maxLen2 <= 0 ) { + /* All points lie on a single line -- any decent normal will do */ + norm[0] = norm[1] = norm[2] = 0; + norm[LongAxis(d1)] = 1; + } +} + + +static void CheckOrientation( GLUtesselator *tess ) +{ + GLdouble area; + GLUface *f, *fHead = &tess->mesh->fHead; + GLUvertex *v, *vHead = &tess->mesh->vHead; + GLUhalfEdge *e; + + /* When we compute the normal automatically, we choose the orientation + * so that the the sum of the signed areas of all contours is non-negative. + */ + area = 0; + for( f = fHead->next; f != fHead; f = f->next ) { + e = f->anEdge; + if( e->winding <= 0 ) continue; + do { + area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t); + e = e->Lnext; + } while( e != f->anEdge ); + } + if( area < 0 ) { + /* Reverse the orientation by flipping all the t-coordinates */ + for( v = vHead->next; v != vHead; v = v->next ) { + v->t = - v->t; + } + tess->tUnit[0] = - tess->tUnit[0]; + tess->tUnit[1] = - tess->tUnit[1]; + tess->tUnit[2] = - tess->tUnit[2]; + } +} + +#ifdef FOR_TRITE_TEST_PROGRAM +#include +extern int RandomSweep; +#define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0) +#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0) +#else +#if defined(SLANTED_SWEEP) +/* The "feature merging" is not intended to be complete. There are + * special cases where edges are nearly parallel to the sweep line + * which are not implemented. The algorithm should still behave + * robustly (ie. produce a reasonable tesselation) in the presence + * of such edges, however it may miss features which could have been + * merged. We could minimize this effect by choosing the sweep line + * direction to be something unusual (ie. not parallel to one of the + * coordinate axes). + */ +#define S_UNIT_X 0.50941539564955385 /* Pre-normalized */ +#define S_UNIT_Y 0.86052074622010633 +#else +#define S_UNIT_X 1.0 +#define S_UNIT_Y 0.0 +#endif +#endif + +/* Determine the polygon normal and project vertices onto the plane + * of the polygon. + */ +void __gl_projectPolygon( GLUtesselator *tess ) +{ + GLUvertex *v, *vHead = &tess->mesh->vHead; + GLdouble norm[3]; + GLdouble *sUnit, *tUnit; + int i, computedNormal = FALSE; + + norm[0] = tess->normal[0]; + norm[1] = tess->normal[1]; + norm[2] = tess->normal[2]; + if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { + ComputeNormal( tess, norm ); + computedNormal = TRUE; + } + sUnit = tess->sUnit; + tUnit = tess->tUnit; + i = LongAxis( norm ); + +#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT) + /* Choose the initial sUnit vector to be approximately perpendicular + * to the normal. + */ + Normalize( norm ); + + sUnit[i] = 0; + sUnit[(i+1)%3] = S_UNIT_X; + sUnit[(i+2)%3] = S_UNIT_Y; + + /* Now make it exactly perpendicular */ + w = Dot( sUnit, norm ); + sUnit[0] -= w * norm[0]; + sUnit[1] -= w * norm[1]; + sUnit[2] -= w * norm[2]; + Normalize( sUnit ); + + /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */ + tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1]; + tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2]; + tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0]; + Normalize( tUnit ); +#else + /* Project perpendicular to a coordinate axis -- better numerically */ + sUnit[i] = 0; + sUnit[(i+1)%3] = S_UNIT_X; + sUnit[(i+2)%3] = S_UNIT_Y; + + tUnit[i] = 0; + tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y; + tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X; +#endif + + /* Project the vertices onto the sweep plane */ + for( v = vHead->next; v != vHead; v = v->next ) { + v->s = Dot( v->coords, sUnit ); + v->t = Dot( v->coords, tUnit ); + } + if( computedNormal ) { + CheckOrientation( tess ); + } +} diff --git a/Dependencies/GLU/normal.h b/Dependencies/GLU/normal.h new file mode 100644 index 0000000..c376ca4 --- /dev/null +++ b/Dependencies/GLU/normal.h @@ -0,0 +1,45 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __normal_h_ +#define __normal_h_ + +#include "tess.h" + +/* __gl_projectPolygon( tess ) determines the polygon normal + * and project vertices onto the plane of the polygon. + */ +void __gl_projectPolygon( GLUtesselator *tess ); + +#endif diff --git a/Dependencies/GLU/priorityq-heap.c b/Dependencies/GLU/priorityq-heap.c new file mode 100644 index 0000000..2d7d164 --- /dev/null +++ b/Dependencies/GLU/priorityq-heap.c @@ -0,0 +1,253 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include +#include +#include +#include "priorityq-heap.h" +#include "memalloc.h" + +#define INIT_SIZE 32 + +#define TRUE 1 +#define FALSE 0 + +#ifdef FOR_TRITE_TEST_PROGRAM +#define LEQ(x,y) (*pq->leq)(x,y) +#else +/* Violates modularity, but a little faster */ +#include "geom.h" +#define LEQ(x,y) VertLeq((GLUvertex *)x, (GLUvertex *)y) +#endif + +/* really __gl_pqHeapNewPriorityQ */ +PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ) +{ + PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ )); + if (pq == NULL) return NULL; + + pq->size = 0; + pq->max = INIT_SIZE; + pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) ); + if (pq->nodes == NULL) { + memFree(pq); + return NULL; + } + + pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) ); + if (pq->handles == NULL) { + memFree(pq->nodes); + memFree(pq); + return NULL; + } + + pq->initialized = FALSE; + pq->freeList = 0; + pq->leq = leq; + + pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */ + pq->handles[1].key = NULL; + return pq; +} + +/* really __gl_pqHeapDeletePriorityQ */ +void pqDeletePriorityQ( PriorityQ *pq ) +{ + memFree( pq->handles ); + memFree( pq->nodes ); + memFree( pq ); +} + + +static void FloatDown( PriorityQ *pq, long curr ) +{ + PQnode *n = pq->nodes; + PQhandleElem *h = pq->handles; + PQhandle hCurr, hChild; + long child; + + hCurr = n[curr].handle; + for( ;; ) { + child = curr << 1; + if( child < pq->size && LEQ( h[n[child+1].handle].key, + h[n[child].handle].key )) { + ++child; + } + + assert(child <= pq->max); + + hChild = n[child].handle; + if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) { + n[curr].handle = hCurr; + h[hCurr].node = curr; + break; + } + n[curr].handle = hChild; + h[hChild].node = curr; + curr = child; + } +} + + +static void FloatUp( PriorityQ *pq, long curr ) +{ + PQnode *n = pq->nodes; + PQhandleElem *h = pq->handles; + PQhandle hCurr, hParent; + long parent; + + hCurr = n[curr].handle; + for( ;; ) { + parent = curr >> 1; + hParent = n[parent].handle; + if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) { + n[curr].handle = hCurr; + h[hCurr].node = curr; + break; + } + n[curr].handle = hParent; + h[hParent].node = curr; + curr = parent; + } +} + +/* really __gl_pqHeapInit */ +void pqInit( PriorityQ *pq ) +{ + long i; + + /* This method of building a heap is O(n), rather than O(n lg n). */ + + for( i = pq->size; i >= 1; --i ) { + FloatDown( pq, i ); + } + pq->initialized = TRUE; +} + +/* really __gl_pqHeapInsert */ +/* returns LONG_MAX iff out of memory */ +PQhandle pqInsert( PriorityQ *pq, PQkey keyNew ) +{ + long curr; + PQhandle free; + + curr = ++ pq->size; + if( (curr*2) > pq->max ) { + PQnode *saveNodes= pq->nodes; + PQhandleElem *saveHandles= pq->handles; + + /* If the heap overflows, double its size. */ + pq->max <<= 1; + pq->nodes = (PQnode *)memRealloc( pq->nodes, + (size_t) + ((pq->max + 1) * sizeof( pq->nodes[0] ))); + if (pq->nodes == NULL) { + pq->nodes = saveNodes; /* restore ptr to free upon return */ + return LONG_MAX; + } + pq->handles = (PQhandleElem *)memRealloc( pq->handles, + (size_t) + ((pq->max + 1) * + sizeof( pq->handles[0] ))); + if (pq->handles == NULL) { + pq->handles = saveHandles; /* restore ptr to free upon return */ + return LONG_MAX; + } + } + + if( pq->freeList == 0 ) { + free = curr; + } else { + free = pq->freeList; + pq->freeList = pq->handles[free].node; + } + + pq->nodes[curr].handle = free; + pq->handles[free].node = curr; + pq->handles[free].key = keyNew; + + if( pq->initialized ) { + FloatUp( pq, curr ); + } + assert(free != LONG_MAX); + return free; +} + +/* really __gl_pqHeapExtractMin */ +PQkey pqExtractMin( PriorityQ *pq ) +{ + PQnode *n = pq->nodes; + PQhandleElem *h = pq->handles; + PQhandle hMin = n[1].handle; + PQkey min = h[hMin].key; + + if( pq->size > 0 ) { + n[1].handle = n[pq->size].handle; + h[n[1].handle].node = 1; + + h[hMin].key = NULL; + h[hMin].node = pq->freeList; + pq->freeList = hMin; + + if( -- pq->size > 0 ) { + FloatDown( pq, 1 ); + } + } + return min; +} + +/* really __gl_pqHeapDelete */ +void pqDelete( PriorityQ *pq, PQhandle hCurr ) +{ + PQnode *n = pq->nodes; + PQhandleElem *h = pq->handles; + long curr; + + assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL ); + + curr = h[hCurr].node; + n[curr].handle = n[pq->size].handle; + h[n[curr].handle].node = curr; + + if( curr <= -- pq->size ) { + if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) { + FloatDown( pq, curr ); + } else { + FloatUp( pq, curr ); + } + } + h[hCurr].key = NULL; + h[hCurr].node = pq->freeList; + pq->freeList = hCurr; +} diff --git a/Dependencies/GLU/priorityq-heap.h b/Dependencies/GLU/priorityq-heap.h new file mode 100644 index 0000000..dc9aaef --- /dev/null +++ b/Dependencies/GLU/priorityq-heap.h @@ -0,0 +1,107 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __priorityq_heap_h_ +#define __priorityq_heap_h_ + +/* Use #define's so that another heap implementation can use this one */ + +#define PQkey PQHeapKey +#define PQhandle PQHeapHandle +#define PriorityQ PriorityQHeap + +#define pqNewPriorityQ(leq) __gl_pqHeapNewPriorityQ(leq) +#define pqDeletePriorityQ(pq) __gl_pqHeapDeletePriorityQ(pq) + +/* The basic operations are insertion of a new key (pqInsert), + * and examination/extraction of a key whose value is minimum + * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); + * for this purpose pqInsert returns a "handle" which is supplied + * as the argument. + * + * An initial heap may be created efficiently by calling pqInsert + * repeatedly, then calling pqInit. In any case pqInit must be called + * before any operations other than pqInsert are used. + * + * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. + * This may also be tested with pqIsEmpty. + */ +#define pqInit(pq) __gl_pqHeapInit(pq) +#define pqInsert(pq,key) __gl_pqHeapInsert(pq,key) +#define pqMinimum(pq) __gl_pqHeapMinimum(pq) +#define pqExtractMin(pq) __gl_pqHeapExtractMin(pq) +#define pqDelete(pq,handle) __gl_pqHeapDelete(pq,handle) +#define pqIsEmpty(pq) __gl_pqHeapIsEmpty(pq) + + +/* Since we support deletion the data structure is a little more + * complicated than an ordinary heap. "nodes" is the heap itself; + * active nodes are stored in the range 1..pq->size. When the + * heap exceeds its allocated size (pq->max), its size doubles. + * The children of node i are nodes 2i and 2i+1. + * + * Each node stores an index into an array "handles". Each handle + * stores a key, plus a pointer back to the node which currently + * represents that key (ie. nodes[handles[i].node].handle == i). + */ + +typedef void *PQkey; +typedef long PQhandle; +typedef struct PriorityQ PriorityQ; + +typedef struct { PQhandle handle; } PQnode; +typedef struct { PQkey key; PQhandle node; } PQhandleElem; + +struct PriorityQ { + PQnode *nodes; + PQhandleElem *handles; + long size, max; + PQhandle freeList; + int initialized; + int (*leq)(PQkey key1, PQkey key2); +}; + +PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); +void pqDeletePriorityQ( PriorityQ *pq ); + +void pqInit( PriorityQ *pq ); +PQhandle pqInsert( PriorityQ *pq, PQkey key ); +PQkey pqExtractMin( PriorityQ *pq ); +void pqDelete( PriorityQ *pq, PQhandle handle ); + + +#define __gl_pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key) +#define __gl_pqHeapIsEmpty(pq) ((pq)->size == 0) + +#endif diff --git a/Dependencies/GLU/priorityq-sort.h b/Dependencies/GLU/priorityq-sort.h new file mode 100644 index 0000000..746cf5f --- /dev/null +++ b/Dependencies/GLU/priorityq-sort.h @@ -0,0 +1,117 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __priorityq_sort_h_ +#define __priorityq_sort_h_ + +#include "priorityq-heap.h" + +#undef PQkey +#undef PQhandle +#undef PriorityQ +#undef pqNewPriorityQ +#undef pqDeletePriorityQ +#undef pqInit +#undef pqInsert +#undef pqMinimum +#undef pqExtractMin +#undef pqDelete +#undef pqIsEmpty + +/* Use #define's so that another heap implementation can use this one */ + +#define PQkey PQSortKey +#define PQhandle PQSortHandle +#define PriorityQ PriorityQSort + +#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq) +#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq) + +/* The basic operations are insertion of a new key (pqInsert), + * and examination/extraction of a key whose value is minimum + * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); + * for this purpose pqInsert returns a "handle" which is supplied + * as the argument. + * + * An initial heap may be created efficiently by calling pqInsert + * repeatedly, then calling pqInit. In any case pqInit must be called + * before any operations other than pqInsert are used. + * + * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. + * This may also be tested with pqIsEmpty. + */ +#define pqInit(pq) __gl_pqSortInit(pq) +#define pqInsert(pq,key) __gl_pqSortInsert(pq,key) +#define pqMinimum(pq) __gl_pqSortMinimum(pq) +#define pqExtractMin(pq) __gl_pqSortExtractMin(pq) +#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle) +#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq) + + +/* Since we support deletion the data structure is a little more + * complicated than an ordinary heap. "nodes" is the heap itself; + * active nodes are stored in the range 1..pq->size. When the + * heap exceeds its allocated size (pq->max), its size doubles. + * The children of node i are nodes 2i and 2i+1. + * + * Each node stores an index into an array "handles". Each handle + * stores a key, plus a pointer back to the node which currently + * represents that key (ie. nodes[handles[i].node].handle == i). + */ + +typedef PQHeapKey PQkey; +typedef PQHeapHandle PQhandle; +typedef struct PriorityQ PriorityQ; + +struct PriorityQ { + PriorityQHeap *heap; + PQkey *keys; + PQkey **order; + PQhandle size, max; + int initialized; + int (*leq)(PQkey key1, PQkey key2); +}; + +PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); +void pqDeletePriorityQ( PriorityQ *pq ); + +int pqInit( PriorityQ *pq ); +PQhandle pqInsert( PriorityQ *pq, PQkey key ); +PQkey pqExtractMin( PriorityQ *pq ); +void pqDelete( PriorityQ *pq, PQhandle handle ); + +PQkey pqMinimum( PriorityQ *pq ); +int pqIsEmpty( PriorityQ *pq ); + +#endif diff --git a/Dependencies/GLU/priorityq.c b/Dependencies/GLU/priorityq.c new file mode 100644 index 0000000..11f0263 --- /dev/null +++ b/Dependencies/GLU/priorityq.c @@ -0,0 +1,260 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "gluos.h" +#include +#include +#include /* LONG_MAX */ +#include "memalloc.h" + +/* Include all the code for the regular heap-based queue here. */ + +#include "priorityq-heap.c" + +/* Now redefine all the function names to map to their "Sort" versions. */ + +#include "priorityq-sort.h" + +/* really __gl_pqSortNewPriorityQ */ +PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ) +{ + PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ )); + if (pq == NULL) return NULL; + + pq->heap = __gl_pqHeapNewPriorityQ( leq ); + if (pq->heap == NULL) { + memFree(pq); + return NULL; + } + + pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) ); + if (pq->keys == NULL) { + __gl_pqHeapDeletePriorityQ(pq->heap); + memFree(pq); + return NULL; + } + + pq->size = 0; + pq->max = INIT_SIZE; + pq->initialized = FALSE; + pq->leq = leq; + return pq; +} + +/* really __gl_pqSortDeletePriorityQ */ +void pqDeletePriorityQ( PriorityQ *pq ) +{ + assert(pq != NULL); + if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap ); + if (pq->order != NULL) memFree( pq->order ); + if (pq->keys != NULL) memFree( pq->keys ); + memFree( pq ); +} + + +#define LT(x,y) (! LEQ(y,x)) +#define GT(x,y) (! LEQ(x,y)) +#define Swap(a,b) if(1){PQkey *tmp = *a; *a = *b; *b = tmp;}else + +/* really __gl_pqSortInit */ +int pqInit( PriorityQ *pq ) +{ + PQkey **p, **r, **i, **j, *piv; + struct { PQkey **p, **r; } Stack[50], *top = Stack; + unsigned long seed = 2016473283; + + /* Create an array of indirect pointers to the keys, so that we + * the handles we have returned are still valid. + */ +/* + pq->order = (PQHeapKey **)memAlloc( (size_t) + (pq->size * sizeof(pq->order[0])) ); +*/ + pq->order = (PQHeapKey **)memAlloc( (size_t) + ((pq->size+1) * sizeof(pq->order[0])) ); +/* the previous line is a patch to compensate for the fact that IBM */ +/* machines return a null on a malloc of zero bytes (unlike SGI), */ +/* so we have to put in this defense to guard against a memory */ +/* fault four lines down. from fossum@austin.ibm.com. */ + if (pq->order == NULL) return 0; + + p = pq->order; + r = p + pq->size - 1; + for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) { + *i = piv; + } + + /* Sort the indirect pointers in descending order, + * using randomized Quicksort + */ + top->p = p; top->r = r; ++top; + while( --top >= Stack ) { + p = top->p; + r = top->r; + while( r > p + 10 ) { + seed = seed * 1539415821 + 1; + i = p + seed % (r - p + 1); + piv = *i; + *i = *p; + *p = piv; + i = p - 1; + j = r + 1; + do { + do { ++i; } while( GT( **i, *piv )); + do { --j; } while( LT( **j, *piv )); + Swap( i, j ); + } while( i < j ); + Swap( i, j ); /* Undo last swap */ + if( i - p < r - j ) { + top->p = j+1; top->r = r; ++top; + r = i-1; + } else { + top->p = p; top->r = i-1; ++top; + p = j+1; + } + } + /* Insertion sort small lists */ + for( i = p+1; i <= r; ++i ) { + piv = *i; + for( j = i; j > p && LT( **(j-1), *piv ); --j ) { + *j = *(j-1); + } + *j = piv; + } + } + pq->max = pq->size; + pq->initialized = TRUE; + __gl_pqHeapInit( pq->heap ); /* always succeeds */ + +#ifndef NDEBUG + p = pq->order; + r = p + pq->size - 1; + for( i = p; i < r; ++i ) { + assert( LEQ( **(i+1), **i )); + } +#endif + + return 1; +} + +/* really __gl_pqSortInsert */ +/* returns LONG_MAX iff out of memory */ +PQhandle pqInsert( PriorityQ *pq, PQkey keyNew ) +{ + long curr; + + if( pq->initialized ) { + return __gl_pqHeapInsert( pq->heap, keyNew ); + } + curr = pq->size; + if( ++ pq->size >= pq->max ) { + PQkey *saveKey= pq->keys; + + /* If the heap overflows, double its size. */ + pq->max <<= 1; + pq->keys = (PQHeapKey *)memRealloc( pq->keys, + (size_t) + (pq->max * sizeof( pq->keys[0] ))); + if (pq->keys == NULL) { + pq->keys = saveKey; /* restore ptr to free upon return */ + return LONG_MAX; + } + } + assert(curr != LONG_MAX); + pq->keys[curr] = keyNew; + + /* Negative handles index the sorted array. */ + return -(curr+1); +} + +/* really __gl_pqSortExtractMin */ +PQkey pqExtractMin( PriorityQ *pq ) +{ + PQkey sortMin, heapMin; + + if( pq->size == 0 ) { + return __gl_pqHeapExtractMin( pq->heap ); + } + sortMin = *(pq->order[pq->size-1]); + if( ! __gl_pqHeapIsEmpty( pq->heap )) { + heapMin = __gl_pqHeapMinimum( pq->heap ); + if( LEQ( heapMin, sortMin )) { + return __gl_pqHeapExtractMin( pq->heap ); + } + } + do { + -- pq->size; + } while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ); + return sortMin; +} + +/* really __gl_pqSortMinimum */ +PQkey pqMinimum( PriorityQ *pq ) +{ + PQkey sortMin, heapMin; + + if( pq->size == 0 ) { + return __gl_pqHeapMinimum( pq->heap ); + } + sortMin = *(pq->order[pq->size-1]); + if( ! __gl_pqHeapIsEmpty( pq->heap )) { + heapMin = __gl_pqHeapMinimum( pq->heap ); + if( LEQ( heapMin, sortMin )) { + return heapMin; + } + } + return sortMin; +} + +/* really __gl_pqSortIsEmpty */ +int pqIsEmpty( PriorityQ *pq ) +{ + return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap ); +} + +/* really __gl_pqSortDelete */ +void pqDelete( PriorityQ *pq, PQhandle curr ) +{ + if( curr >= 0 ) { + __gl_pqHeapDelete( pq->heap, curr ); + return; + } + curr = -(curr+1); + assert( curr < pq->max && pq->keys[curr] != NULL ); + + pq->keys[curr] = NULL; + while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) { + -- pq->size; + } +} diff --git a/Dependencies/GLU/priorityq.h b/Dependencies/GLU/priorityq.h new file mode 100644 index 0000000..746cf5f --- /dev/null +++ b/Dependencies/GLU/priorityq.h @@ -0,0 +1,117 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __priorityq_sort_h_ +#define __priorityq_sort_h_ + +#include "priorityq-heap.h" + +#undef PQkey +#undef PQhandle +#undef PriorityQ +#undef pqNewPriorityQ +#undef pqDeletePriorityQ +#undef pqInit +#undef pqInsert +#undef pqMinimum +#undef pqExtractMin +#undef pqDelete +#undef pqIsEmpty + +/* Use #define's so that another heap implementation can use this one */ + +#define PQkey PQSortKey +#define PQhandle PQSortHandle +#define PriorityQ PriorityQSort + +#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq) +#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq) + +/* The basic operations are insertion of a new key (pqInsert), + * and examination/extraction of a key whose value is minimum + * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); + * for this purpose pqInsert returns a "handle" which is supplied + * as the argument. + * + * An initial heap may be created efficiently by calling pqInsert + * repeatedly, then calling pqInit. In any case pqInit must be called + * before any operations other than pqInsert are used. + * + * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. + * This may also be tested with pqIsEmpty. + */ +#define pqInit(pq) __gl_pqSortInit(pq) +#define pqInsert(pq,key) __gl_pqSortInsert(pq,key) +#define pqMinimum(pq) __gl_pqSortMinimum(pq) +#define pqExtractMin(pq) __gl_pqSortExtractMin(pq) +#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle) +#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq) + + +/* Since we support deletion the data structure is a little more + * complicated than an ordinary heap. "nodes" is the heap itself; + * active nodes are stored in the range 1..pq->size. When the + * heap exceeds its allocated size (pq->max), its size doubles. + * The children of node i are nodes 2i and 2i+1. + * + * Each node stores an index into an array "handles". Each handle + * stores a key, plus a pointer back to the node which currently + * represents that key (ie. nodes[handles[i].node].handle == i). + */ + +typedef PQHeapKey PQkey; +typedef PQHeapHandle PQhandle; +typedef struct PriorityQ PriorityQ; + +struct PriorityQ { + PriorityQHeap *heap; + PQkey *keys; + PQkey **order; + PQhandle size, max; + int initialized; + int (*leq)(PQkey key1, PQkey key2); +}; + +PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); +void pqDeletePriorityQ( PriorityQ *pq ); + +int pqInit( PriorityQ *pq ); +PQhandle pqInsert( PriorityQ *pq, PQkey key ); +PQkey pqExtractMin( PriorityQ *pq ); +void pqDelete( PriorityQ *pq, PQhandle handle ); + +PQkey pqMinimum( PriorityQ *pq ); +int pqIsEmpty( PriorityQ *pq ); + +#endif diff --git a/Dependencies/GLU/render.c b/Dependencies/GLU/render.c new file mode 100644 index 0000000..4f376f7 --- /dev/null +++ b/Dependencies/GLU/render.c @@ -0,0 +1,498 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "gluos.h" +#include +#include +#include "mesh.h" +#include "tess.h" +#include "render.h" + +#define TRUE 1 +#define FALSE 0 + +/* This structure remembers the information we need about a primitive + * to be able to render it later, once we have determined which + * primitive is able to use the most triangles. + */ +struct FaceCount { + long size; /* number of triangles used */ + GLUhalfEdge *eStart; /* edge where this primitive starts */ + void (*render)(GLUtesselator *, GLUhalfEdge *, long); + /* routine to render this primitive */ +}; + +static struct FaceCount MaximumFan( GLUhalfEdge *eOrig ); +static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig ); + +static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size ); +static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size ); +static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart, + long size ); + +static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig ); +static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head ); + + + +/************************ Strips and Fans decomposition ******************/ + +/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle + * fans, strips, and separate triangles. A substantial effort is made + * to use as few rendering primitives as possible (ie. to make the fans + * and strips as large as possible). + * + * The rendering output is provided as callbacks (see the api). + */ +void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh ) +{ + GLUface *f; + + /* Make a list of separate triangles so we can render them all at once */ + tess->lonelyTriList = NULL; + + for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { + f->marked = FALSE; + } + for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { + + /* We examine all faces in an arbitrary order. Whenever we find + * an unprocessed face F, we output a group of faces including F + * whose size is maximum. + */ + if( f->inside && ! f->marked ) { + RenderMaximumFaceGroup( tess, f ); + assert( f->marked ); + } + } + if( tess->lonelyTriList != NULL ) { + RenderLonelyTriangles( tess, tess->lonelyTriList ); + tess->lonelyTriList = NULL; + } +} + + +static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig ) +{ + /* We want to find the largest triangle fan or strip of unmarked faces + * which includes the given face fOrig. There are 3 possible fans + * passing through fOrig (one centered at each vertex), and 3 possible + * strips (one for each CCW permutation of the vertices). Our strategy + * is to try all of these, and take the primitive which uses the most + * triangles (a greedy approach). + */ + GLUhalfEdge *e = fOrig->anEdge; + struct FaceCount max, newFace; + + max.size = 1; + max.eStart = e; + max.render = &RenderTriangle; + + if( ! tess->flagBoundary ) { + newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; } + newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; } + newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; } + + newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; } + newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; } + newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; } + } + (*(max.render))( tess, max.eStart, max.size ); +} + + +/* Macros which keep track of faces we have marked temporarily, and allow + * us to backtrack when necessary. With triangle fans, this is not + * really necessary, since the only awkward case is a loop of triangles + * around a single origin vertex. However with strips the situation is + * more complicated, and we need a general tracking method like the + * one here. + */ +#define Marked(f) (! (f)->inside || (f)->marked) + +#define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE) + +#define FreeTrail(t) if( 1 ) { \ + while( (t) != NULL ) { \ + (t)->marked = FALSE; t = (t)->trail; \ + } \ + } else /* absorb trailing semicolon */ + + + +static struct FaceCount MaximumFan( GLUhalfEdge *eOrig ) +{ + /* eOrig->Lface is the face we want to render. We want to find the size + * of a maximal fan around eOrig->Org. To do this we just walk around + * the origin vertex as far as possible in both directions. + */ + struct FaceCount newFace = { 0, NULL, &RenderFan }; + GLUface *trail = NULL; + GLUhalfEdge *e; + + for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) { + AddToTrail( e->Lface, trail ); + ++newFace.size; + } + for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) { + AddToTrail( e->Rface, trail ); + ++newFace.size; + } + newFace.eStart = e; + /*LINTED*/ + FreeTrail( trail ); + return newFace; +} + + +#define IsEven(n) (((n) & 1) == 0) + +static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig ) +{ + /* Here we are looking for a maximal strip that contains the vertices + * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the + * reverse, such that all triangles are oriented CCW). + * + * Again we walk forward and backward as far as possible. However for + * strips there is a twist: to get CCW orientations, there must be + * an *even* number of triangles in the strip on one side of eOrig. + * We walk the strip starting on a side with an even number of triangles; + * if both side have an odd number, we are forced to shorten one side. + */ + struct FaceCount newFace = { 0, NULL, &RenderStrip }; + long headSize = 0, tailSize = 0; + GLUface *trail = NULL; + GLUhalfEdge *e, *eTail, *eHead; + + for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) { + AddToTrail( e->Lface, trail ); + ++tailSize; + e = e->Dprev; + if( Marked( e->Lface )) break; + AddToTrail( e->Lface, trail ); + } + eTail = e; + + for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) { + AddToTrail( e->Rface, trail ); + ++headSize; + e = e->Oprev; + if( Marked( e->Rface )) break; + AddToTrail( e->Rface, trail ); + } + eHead = e; + + newFace.size = tailSize + headSize; + if( IsEven( tailSize )) { + newFace.eStart = eTail->Sym; + } else if( IsEven( headSize )) { + newFace.eStart = eHead; + } else { + /* Both sides have odd length, we must shorten one of them. In fact, + * we must start from eHead to guarantee inclusion of eOrig->Lface. + */ + --newFace.size; + newFace.eStart = eHead->Onext; + } + /*LINTED*/ + FreeTrail( trail ); + return newFace; +} + + +static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size ) +{ + /* Just add the triangle to a triangle list, so we can render all + * the separate triangles at once. + */ + assert( size == 1 ); + AddToTrail( e->Lface, tess->lonelyTriList ); +} + + +static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f ) +{ + /* Now we render all the separate triangles which could not be + * grouped into a triangle fan or strip. + */ + GLUhalfEdge *e; + int newState; + int edgeState = -1; /* force edge state output for first vertex */ + + CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES ); + + for( ; f != NULL; f = f->trail ) { + /* Loop once for each edge (there will always be 3 edges) */ + + e = f->anEdge; + do { + if( tess->flagBoundary ) { + /* Set the "edge state" to TRUE just before we output the + * first vertex of each edge on the polygon boundary. + */ + newState = ! e->Rface->inside; + if( edgeState != newState ) { + edgeState = newState; + CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState ); + } + } + CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); + + e = e->Lnext; + } while( e != f->anEdge ); + } + CALL_END_OR_END_DATA(); +} + + +static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size ) +{ + /* Render as many CCW triangles as possible in a fan starting from + * edge "e". The fan *should* contain exactly "size" triangles + * (otherwise we've goofed up somewhere). + */ + CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN ); + CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); + CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); + + while( ! Marked( e->Lface )) { + e->Lface->marked = TRUE; + --size; + e = e->Onext; + CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); + } + + assert( size == 0 ); + CALL_END_OR_END_DATA(); +} + + +static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size ) +{ + /* Render as many CCW triangles as possible in a strip starting from + * edge "e". The strip *should* contain exactly "size" triangles + * (otherwise we've goofed up somewhere). + */ + CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP ); + CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); + CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); + + while( ! Marked( e->Lface )) { + e->Lface->marked = TRUE; + --size; + e = e->Dprev; + CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); + if( Marked( e->Lface )) break; + + e->Lface->marked = TRUE; + --size; + e = e->Onext; + CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); + } + + assert( size == 0 ); + CALL_END_OR_END_DATA(); +} + + +/************************ Boundary contour decomposition ******************/ + +/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one + * contour for each face marked "inside". The rendering output is + * provided as callbacks (see the api). + */ +void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh ) +{ + GLUface *f; + GLUhalfEdge *e; + + for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { + if( f->inside ) { + CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP ); + e = f->anEdge; + do { + CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); + e = e->Lnext; + } while( e != f->anEdge ); + CALL_END_OR_END_DATA(); + } + } +} + + +/************************ Quick-and-dirty decomposition ******************/ + +#define SIGN_INCONSISTENT 2 + +static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check ) +/* + * If check==FALSE, we compute the polygon normal and place it in norm[]. + * If check==TRUE, we check that each triangle in the fan from v0 has a + * consistent orientation with respect to norm[]. If triangles are + * consistently oriented CCW, return 1; if CW, return -1; if all triangles + * are degenerate return 0; otherwise (no consistent orientation) return + * SIGN_INCONSISTENT. + */ +{ + CachedVertex *v0 = tess->cache; + CachedVertex *vn = v0 + tess->cacheCount; + CachedVertex *vc; + GLdouble dot, xc, yc, zc, xp, yp, zp, n[3]; + int sign = 0; + + /* Find the polygon normal. It is important to get a reasonable + * normal even when the polygon is self-intersecting (eg. a bowtie). + * Otherwise, the computed normal could be very tiny, but perpendicular + * to the true plane of the polygon due to numerical noise. Then all + * the triangles would appear to be degenerate and we would incorrectly + * decompose the polygon as a fan (or simply not render it at all). + * + * We use a sum-of-triangles normal algorithm rather than the more + * efficient sum-of-trapezoids method (used in CheckOrientation() + * in normal.c). This lets us explicitly reverse the signed area + * of some triangles to get a reasonable normal in the self-intersecting + * case. + */ + if( ! check ) { + norm[0] = norm[1] = norm[2] = 0.0; + } + + vc = v0 + 1; + xc = vc->coords[0] - v0->coords[0]; + yc = vc->coords[1] - v0->coords[1]; + zc = vc->coords[2] - v0->coords[2]; + while( ++vc < vn ) { + xp = xc; yp = yc; zp = zc; + xc = vc->coords[0] - v0->coords[0]; + yc = vc->coords[1] - v0->coords[1]; + zc = vc->coords[2] - v0->coords[2]; + + /* Compute (vp - v0) cross (vc - v0) */ + n[0] = yp*zc - zp*yc; + n[1] = zp*xc - xp*zc; + n[2] = xp*yc - yp*xc; + + dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2]; + if( ! check ) { + /* Reverse the contribution of back-facing triangles to get + * a reasonable normal for self-intersecting polygons (see above) + */ + if( dot >= 0 ) { + norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2]; + } else { + norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2]; + } + } else if( dot != 0 ) { + /* Check the new orientation for consistency with previous triangles */ + if( dot > 0 ) { + if( sign < 0 ) return SIGN_INCONSISTENT; + sign = 1; + } else { + if( sign > 0 ) return SIGN_INCONSISTENT; + sign = -1; + } + } + } + return sign; +} + +/* __gl_renderCache( tess ) takes a single contour and tries to render it + * as a triangle fan. This handles convex polygons, as well as some + * non-convex polygons if we get lucky. + * + * Returns TRUE if the polygon was successfully rendered. The rendering + * output is provided as callbacks (see the api). + */ +GLboolean __gl_renderCache( GLUtesselator *tess ) +{ + CachedVertex *v0 = tess->cache; + CachedVertex *vn = v0 + tess->cacheCount; + CachedVertex *vc; + GLdouble norm[3]; + int sign; + + if( tess->cacheCount < 3 ) { + /* Degenerate contour -- no output */ + return TRUE; + } + + norm[0] = tess->normal[0]; + norm[1] = tess->normal[1]; + norm[2] = tess->normal[2]; + if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { + ComputeNormal( tess, norm, FALSE ); + } + + sign = ComputeNormal( tess, norm, TRUE ); + if( sign == SIGN_INCONSISTENT ) { + /* Fan triangles did not have a consistent orientation */ + return FALSE; + } + if( sign == 0 ) { + /* All triangles were degenerate */ + return TRUE; + } + + /* Make sure we do the right thing for each winding rule */ + switch( tess->windingRule ) { + case GLU_TESS_WINDING_ODD: + case GLU_TESS_WINDING_NONZERO: + break; + case GLU_TESS_WINDING_POSITIVE: + if( sign < 0 ) return TRUE; + break; + case GLU_TESS_WINDING_NEGATIVE: + if( sign > 0 ) return TRUE; + break; + case GLU_TESS_WINDING_ABS_GEQ_TWO: + return TRUE; + } + + CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP + : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN + : GL_TRIANGLES ); + + CALL_VERTEX_OR_VERTEX_DATA( v0->data ); + if( sign > 0 ) { + for( vc = v0+1; vc < vn; ++vc ) { + CALL_VERTEX_OR_VERTEX_DATA( vc->data ); + } + } else { + for( vc = vn-1; vc > v0; --vc ) { + CALL_VERTEX_OR_VERTEX_DATA( vc->data ); + } + } + CALL_END_OR_END_DATA(); + return TRUE; +} diff --git a/Dependencies/GLU/render.h b/Dependencies/GLU/render.h new file mode 100644 index 0000000..a298c9a --- /dev/null +++ b/Dependencies/GLU/render.h @@ -0,0 +1,52 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __render_h_ +#define __render_h_ + +#include "mesh.h" + +/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle + * fans, strips, and separate triangles. A substantial effort is made + * to use as few rendering primitives as possible (ie. to make the fans + * and strips as large as possible). + * + * The rendering output is provided as callbacks (see the api). + */ +void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh ); +void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh ); + +GLboolean __gl_renderCache( GLUtesselator *tess ); + +#endif diff --git a/Dependencies/GLU/sweep.c b/Dependencies/GLU/sweep.c new file mode 100644 index 0000000..744be6b --- /dev/null +++ b/Dependencies/GLU/sweep.c @@ -0,0 +1,1357 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "gluos.h" +#include +#include +#include /* longjmp */ +#include /* LONG_MAX */ + +#include "mesh.h" +#include "geom.h" +#include "tess.h" +#include "dict.h" +#include "priorityq.h" +#include "memalloc.h" +#include "sweep.h" + +#define TRUE 1 +#define FALSE 0 + +#ifdef FOR_TRITE_TEST_PROGRAM +extern void DebugEvent( GLUtesselator *tess ); +#else +#define DebugEvent( tess ) +#endif + +/* + * Invariants for the Edge Dictionary. + * - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2) + * at any valid location of the sweep event + * - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2 + * share a common endpoint + * - for each e, e->Dst has been processed, but not e->Org + * - each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org) + * where "event" is the current sweep line event. + * - no edge e has zero length + * + * Invariants for the Mesh (the processed portion). + * - the portion of the mesh left of the sweep line is a planar graph, + * ie. there is *some* way to embed it in the plane + * - no processed edge has zero length + * - no two processed vertices have identical coordinates + * - each "inside" region is monotone, ie. can be broken into two chains + * of monotonically increasing vertices according to VertLeq(v1,v2) + * - a non-invariant: these chains may intersect (very slightly) + * + * Invariants for the Sweep. + * - if none of the edges incident to the event vertex have an activeRegion + * (ie. none of these edges are in the edge dictionary), then the vertex + * has only right-going edges. + * - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced + * by ConnectRightVertex), then it is the only right-going edge from + * its associated vertex. (This says that these edges exist only + * when it is necessary.) + */ + +#undef MAX +#undef MIN +#define MAX(x,y) ((x) >= (y) ? (x) : (y)) +#define MIN(x,y) ((x) <= (y) ? (x) : (y)) + +/* When we merge two edges into one, we need to compute the combined + * winding of the new edge. + */ +#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \ + eDst->Sym->winding += eSrc->Sym->winding) + +static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent ); +static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp ); +static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp ); + +static int EdgeLeq( GLUtesselator *tess, ActiveRegion *reg1, + ActiveRegion *reg2 ) +/* + * Both edges must be directed from right to left (this is the canonical + * direction for the upper edge of each region). + * + * The strategy is to evaluate a "t" value for each edge at the + * current sweep line position, given by tess->event. The calculations + * are designed to be very stable, but of course they are not perfect. + * + * Special case: if both edge destinations are at the sweep event, + * we sort the edges by slope (they would otherwise compare equally). + */ +{ + GLUvertex *event = tess->event; + GLUhalfEdge *e1, *e2; + GLdouble t1, t2; + + e1 = reg1->eUp; + e2 = reg2->eUp; + + if( e1->Dst == event ) { + if( e2->Dst == event ) { + /* Two edges right of the sweep line which meet at the sweep event. + * Sort them by slope. + */ + if( VertLeq( e1->Org, e2->Org )) { + return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0; + } + return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0; + } + return EdgeSign( e2->Dst, event, e2->Org ) <= 0; + } + if( e2->Dst == event ) { + return EdgeSign( e1->Dst, event, e1->Org ) >= 0; + } + + /* General case - compute signed distance *from* e1, e2 to event */ + t1 = EdgeEval( e1->Dst, event, e1->Org ); + t2 = EdgeEval( e2->Dst, event, e2->Org ); + return (t1 >= t2); +} + + +static void DeleteRegion( GLUtesselator *tess, ActiveRegion *reg ) +{ + if( reg->fixUpperEdge ) { + /* It was created with zero winding number, so it better be + * deleted with zero winding number (ie. it better not get merged + * with a real edge). + */ + assert( reg->eUp->winding == 0 ); + } + reg->eUp->activeRegion = NULL; + dictDelete( tess->dict, reg->nodeUp ); /* __gl_dictListDelete */ + memFree( reg ); +} + + +static int FixUpperEdge( ActiveRegion *reg, GLUhalfEdge *newEdge ) +/* + * Replace an upper edge which needs fixing (see ConnectRightVertex). + */ +{ + assert( reg->fixUpperEdge ); + if ( !__gl_meshDelete( reg->eUp ) ) return 0; + reg->fixUpperEdge = FALSE; + reg->eUp = newEdge; + newEdge->activeRegion = reg; + + return 1; +} + +static ActiveRegion *TopLeftRegion( ActiveRegion *reg ) +{ + GLUvertex *org = reg->eUp->Org; + GLUhalfEdge *e; + + /* Find the region above the uppermost edge with the same origin */ + do { + reg = RegionAbove( reg ); + } while( reg->eUp->Org == org ); + + /* If the edge above was a temporary edge introduced by ConnectRightVertex, + * now is the time to fix it. + */ + if( reg->fixUpperEdge ) { + e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext ); + if (e == NULL) return NULL; + if ( !FixUpperEdge( reg, e ) ) return NULL; + reg = RegionAbove( reg ); + } + return reg; +} + +static ActiveRegion *TopRightRegion( ActiveRegion *reg ) +{ + GLUvertex *dst = reg->eUp->Dst; + + /* Find the region above the uppermost edge with the same destination */ + do { + reg = RegionAbove( reg ); + } while( reg->eUp->Dst == dst ); + return reg; +} + +static ActiveRegion *AddRegionBelow( GLUtesselator *tess, + ActiveRegion *regAbove, + GLUhalfEdge *eNewUp ) +/* + * Add a new active region to the sweep line, *somewhere* below "regAbove" + * (according to where the new edge belongs in the sweep-line dictionary). + * The upper edge of the new region will be "eNewUp". + * Winding number and "inside" flag are not updated. + */ +{ + ActiveRegion *regNew = (ActiveRegion *)memAlloc( sizeof( ActiveRegion )); + if (regNew == NULL) longjmp(tess->env,1); + + regNew->eUp = eNewUp; + /* __gl_dictListInsertBefore */ + regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew ); + if (regNew->nodeUp == NULL) longjmp(tess->env,1); + regNew->fixUpperEdge = FALSE; + regNew->sentinel = FALSE; + regNew->dirty = FALSE; + + eNewUp->activeRegion = regNew; + return regNew; +} + +static GLboolean IsWindingInside( GLUtesselator *tess, int n ) +{ + switch( tess->windingRule ) { + case GLU_TESS_WINDING_ODD: + return (n & 1); + case GLU_TESS_WINDING_NONZERO: + return (n != 0); + case GLU_TESS_WINDING_POSITIVE: + return (n > 0); + case GLU_TESS_WINDING_NEGATIVE: + return (n < 0); + case GLU_TESS_WINDING_ABS_GEQ_TWO: + return (n >= 2) || (n <= -2); + } + /*LINTED*/ + assert( FALSE ); + /*NOTREACHED*/ + return GL_FALSE; /* avoid compiler complaints */ +} + + +static void ComputeWinding( GLUtesselator *tess, ActiveRegion *reg ) +{ + reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding; + reg->inside = IsWindingInside( tess, reg->windingNumber ); +} + + +static void FinishRegion( GLUtesselator *tess, ActiveRegion *reg ) +/* + * Delete a region from the sweep line. This happens when the upper + * and lower chains of a region meet (at a vertex on the sweep line). + * The "inside" flag is copied to the appropriate mesh face (we could + * not do this before -- since the structure of the mesh is always + * changing, this face may not have even existed until now). + */ +{ + GLUhalfEdge *e = reg->eUp; + GLUface *f = e->Lface; + + f->inside = reg->inside; + f->anEdge = e; /* optimization for __gl_meshTessellateMonoRegion() */ + DeleteRegion( tess, reg ); +} + + +static GLUhalfEdge *FinishLeftRegions( GLUtesselator *tess, + ActiveRegion *regFirst, ActiveRegion *regLast ) +/* + * We are given a vertex with one or more left-going edges. All affected + * edges should be in the edge dictionary. Starting at regFirst->eUp, + * we walk down deleting all regions where both edges have the same + * origin vOrg. At the same time we copy the "inside" flag from the + * active region to the face, since at this point each face will belong + * to at most one region (this was not necessarily true until this point + * in the sweep). The walk stops at the region above regLast; if regLast + * is NULL we walk as far as possible. At the same time we relink the + * mesh if necessary, so that the ordering of edges around vOrg is the + * same as in the dictionary. + */ +{ + ActiveRegion *reg, *regPrev; + GLUhalfEdge *e, *ePrev; + + regPrev = regFirst; + ePrev = regFirst->eUp; + while( regPrev != regLast ) { + regPrev->fixUpperEdge = FALSE; /* placement was OK */ + reg = RegionBelow( regPrev ); + e = reg->eUp; + if( e->Org != ePrev->Org ) { + if( ! reg->fixUpperEdge ) { + /* Remove the last left-going edge. Even though there are no further + * edges in the dictionary with this origin, there may be further + * such edges in the mesh (if we are adding left edges to a vertex + * that has already been processed). Thus it is important to call + * FinishRegion rather than just DeleteRegion. + */ + FinishRegion( tess, regPrev ); + break; + } + /* If the edge below was a temporary edge introduced by + * ConnectRightVertex, now is the time to fix it. + */ + e = __gl_meshConnect( ePrev->Lprev, e->Sym ); + if (e == NULL) longjmp(tess->env,1); + if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1); + } + + /* Relink edges so that ePrev->Onext == e */ + if( ePrev->Onext != e ) { + if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1); + if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1); + } + FinishRegion( tess, regPrev ); /* may change reg->eUp */ + ePrev = reg->eUp; + regPrev = reg; + } + return ePrev; +} + + +static void AddRightEdges( GLUtesselator *tess, ActiveRegion *regUp, + GLUhalfEdge *eFirst, GLUhalfEdge *eLast, GLUhalfEdge *eTopLeft, + GLboolean cleanUp ) +/* + * Purpose: insert right-going edges into the edge dictionary, and update + * winding numbers and mesh connectivity appropriately. All right-going + * edges share a common origin vOrg. Edges are inserted CCW starting at + * eFirst; the last edge inserted is eLast->Oprev. If vOrg has any + * left-going edges already processed, then eTopLeft must be the edge + * such that an imaginary upward vertical segment from vOrg would be + * contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft + * should be NULL. + */ +{ + ActiveRegion *reg, *regPrev; + GLUhalfEdge *e, *ePrev; + int firstTime = TRUE; + + /* Insert the new right-going edges in the dictionary */ + e = eFirst; + do { + assert( VertLeq( e->Org, e->Dst )); + AddRegionBelow( tess, regUp, e->Sym ); + e = e->Onext; + } while ( e != eLast ); + + /* Walk *all* right-going edges from e->Org, in the dictionary order, + * updating the winding numbers of each region, and re-linking the mesh + * edges to match the dictionary ordering (if necessary). + */ + if( eTopLeft == NULL ) { + eTopLeft = RegionBelow( regUp )->eUp->Rprev; + } + regPrev = regUp; + ePrev = eTopLeft; + for( ;; ) { + reg = RegionBelow( regPrev ); + e = reg->eUp->Sym; + if( e->Org != ePrev->Org ) break; + + if( e->Onext != ePrev ) { + /* Unlink e from its current position, and relink below ePrev */ + if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1); + if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1); + } + /* Compute the winding number and "inside" flag for the new regions */ + reg->windingNumber = regPrev->windingNumber - e->winding; + reg->inside = IsWindingInside( tess, reg->windingNumber ); + + /* Check for two outgoing edges with same slope -- process these + * before any intersection tests (see example in __gl_computeInterior). + */ + regPrev->dirty = TRUE; + if( ! firstTime && CheckForRightSplice( tess, regPrev )) { + AddWinding( e, ePrev ); + DeleteRegion( tess, regPrev ); + if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1); + } + firstTime = FALSE; + regPrev = reg; + ePrev = e; + } + regPrev->dirty = TRUE; + assert( regPrev->windingNumber - e->winding == reg->windingNumber ); + + if( cleanUp ) { + /* Check for intersections between newly adjacent edges. */ + WalkDirtyRegions( tess, regPrev ); + } +} + + +static void CallCombine( GLUtesselator *tess, GLUvertex *isect, + void *data[4], GLfloat weights[4], int needed ) +{ + GLdouble coords[3]; + + /* Copy coord data in case the callback changes it. */ + coords[0] = isect->coords[0]; + coords[1] = isect->coords[1]; + coords[2] = isect->coords[2]; + + isect->data = NULL; + CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data ); + if( isect->data == NULL ) { + if( ! needed ) { + isect->data = data[0]; + } else if( ! tess->fatalError ) { + /* The only way fatal error is when two edges are found to intersect, + * but the user has not provided the callback necessary to handle + * generated intersection points. + */ + CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK ); + tess->fatalError = TRUE; + } + } +} + +static void SpliceMergeVertices( GLUtesselator *tess, GLUhalfEdge *e1, + GLUhalfEdge *e2 ) +/* + * Two vertices with idential coordinates are combined into one. + * e1->Org is kept, while e2->Org is discarded. + */ +{ + void *data[4] = { NULL, NULL, NULL, NULL }; + GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 }; + + data[0] = e1->Org->data; + data[1] = e2->Org->data; + CallCombine( tess, e1->Org, data, weights, FALSE ); + if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1); +} + +static void VertexWeights( GLUvertex *isect, GLUvertex *org, GLUvertex *dst, + GLfloat *weights ) +/* + * Find some weights which describe how the intersection vertex is + * a linear combination of "org" and "dest". Each of the two edges + * which generated "isect" is allocated 50% of the weight; each edge + * splits the weight between its org and dst according to the + * relative distance to "isect". + */ +{ + GLdouble t1 = VertL1dist( org, isect ); + GLdouble t2 = VertL1dist( dst, isect ); + + weights[0] = 0.5 * t2 / (t1 + t2); + weights[1] = 0.5 * t1 / (t1 + t2); + isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0]; + isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1]; + isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2]; +} + + +static void GetIntersectData( GLUtesselator *tess, GLUvertex *isect, + GLUvertex *orgUp, GLUvertex *dstUp, + GLUvertex *orgLo, GLUvertex *dstLo ) +/* + * We've computed a new intersection point, now we need a "data" pointer + * from the user so that we can refer to this new vertex in the + * rendering callbacks. + */ +{ + void *data[4]; + GLfloat weights[4]; + + data[0] = orgUp->data; + data[1] = dstUp->data; + data[2] = orgLo->data; + data[3] = dstLo->data; + + isect->coords[0] = isect->coords[1] = isect->coords[2] = 0; + VertexWeights( isect, orgUp, dstUp, &weights[0] ); + VertexWeights( isect, orgLo, dstLo, &weights[2] ); + + CallCombine( tess, isect, data, weights, TRUE ); +} + +static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp ) +/* + * Check the upper and lower edge of "regUp", to make sure that the + * eUp->Org is above eLo, or eLo->Org is below eUp (depending on which + * origin is leftmost). + * + * The main purpose is to splice right-going edges with the same + * dest vertex and nearly identical slopes (ie. we can't distinguish + * the slopes numerically). However the splicing can also help us + * to recover from numerical errors. For example, suppose at one + * point we checked eUp and eLo, and decided that eUp->Org is barely + * above eLo. Then later, we split eLo into two edges (eg. from + * a splice operation like this one). This can change the result of + * our test so that now eUp->Org is incident to eLo, or barely below it. + * We must correct this condition to maintain the dictionary invariants. + * + * One possibility is to check these edges for intersection again + * (ie. CheckForIntersect). This is what we do if possible. However + * CheckForIntersect requires that tess->event lies between eUp and eLo, + * so that it has something to fall back on when the intersection + * calculation gives us an unusable answer. So, for those cases where + * we can't check for intersection, this routine fixes the problem + * by just splicing the offending vertex into the other edge. + * This is a guaranteed solution, no matter how degenerate things get. + * Basically this is a combinatorial solution to a numerical problem. + */ +{ + ActiveRegion *regLo = RegionBelow(regUp); + GLUhalfEdge *eUp = regUp->eUp; + GLUhalfEdge *eLo = regLo->eUp; + + if( VertLeq( eUp->Org, eLo->Org )) { + if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) return FALSE; + + /* eUp->Org appears to be below eLo */ + if( ! VertEq( eUp->Org, eLo->Org )) { + /* Splice eUp->Org into eLo */ + if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1); + regUp->dirty = regLo->dirty = TRUE; + + } else if( eUp->Org != eLo->Org ) { + /* merge the two vertices, discarding eUp->Org */ + pqDelete( tess->pq, eUp->Org->pqHandle ); /* __gl_pqSortDelete */ + SpliceMergeVertices( tess, eLo->Oprev, eUp ); + } + } else { + if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE; + + /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */ + RegionAbove(regUp)->dirty = regUp->dirty = TRUE; + if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1); + } + return TRUE; +} + +static int CheckForLeftSplice( GLUtesselator *tess, ActiveRegion *regUp ) +/* + * Check the upper and lower edge of "regUp", to make sure that the + * eUp->Dst is above eLo, or eLo->Dst is below eUp (depending on which + * destination is rightmost). + * + * Theoretically, this should always be true. However, splitting an edge + * into two pieces can change the results of previous tests. For example, + * suppose at one point we checked eUp and eLo, and decided that eUp->Dst + * is barely above eLo. Then later, we split eLo into two edges (eg. from + * a splice operation like this one). This can change the result of + * the test so that now eUp->Dst is incident to eLo, or barely below it. + * We must correct this condition to maintain the dictionary invariants + * (otherwise new edges might get inserted in the wrong place in the + * dictionary, and bad stuff will happen). + * + * We fix the problem by just splicing the offending vertex into the + * other edge. + */ +{ + ActiveRegion *regLo = RegionBelow(regUp); + GLUhalfEdge *eUp = regUp->eUp; + GLUhalfEdge *eLo = regLo->eUp; + GLUhalfEdge *e; + + assert( ! VertEq( eUp->Dst, eLo->Dst )); + + if( VertLeq( eUp->Dst, eLo->Dst )) { + if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) return FALSE; + + /* eLo->Dst is above eUp, so splice eLo->Dst into eUp */ + RegionAbove(regUp)->dirty = regUp->dirty = TRUE; + e = __gl_meshSplitEdge( eUp ); + if (e == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1); + e->Lface->inside = regUp->inside; + } else { + if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) return FALSE; + + /* eUp->Dst is below eLo, so splice eUp->Dst into eLo */ + regUp->dirty = regLo->dirty = TRUE; + e = __gl_meshSplitEdge( eLo ); + if (e == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1); + e->Rface->inside = regUp->inside; + } + return TRUE; +} + + +static int CheckForIntersect( GLUtesselator *tess, ActiveRegion *regUp ) +/* + * Check the upper and lower edges of the given region to see if + * they intersect. If so, create the intersection and add it + * to the data structures. + * + * Returns TRUE if adding the new intersection resulted in a recursive + * call to AddRightEdges(); in this case all "dirty" regions have been + * checked for intersections, and possibly regUp has been deleted. + */ +{ + ActiveRegion *regLo = RegionBelow(regUp); + GLUhalfEdge *eUp = regUp->eUp; + GLUhalfEdge *eLo = regLo->eUp; + GLUvertex *orgUp = eUp->Org; + GLUvertex *orgLo = eLo->Org; + GLUvertex *dstUp = eUp->Dst; + GLUvertex *dstLo = eLo->Dst; + GLdouble tMinUp, tMaxLo; + GLUvertex isect, *orgMin; + GLUhalfEdge *e; + + assert( ! VertEq( dstLo, dstUp )); + assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 ); + assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 ); + assert( orgUp != tess->event && orgLo != tess->event ); + assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge ); + + if( orgUp == orgLo ) return FALSE; /* right endpoints are the same */ + + tMinUp = MIN( orgUp->t, dstUp->t ); + tMaxLo = MAX( orgLo->t, dstLo->t ); + if( tMinUp > tMaxLo ) return FALSE; /* t ranges do not overlap */ + + if( VertLeq( orgUp, orgLo )) { + if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) return FALSE; + } else { + if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) return FALSE; + } + + /* At this point the edges intersect, at least marginally */ + DebugEvent( tess ); + + __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect ); + /* The following properties are guaranteed: */ + assert( MIN( orgUp->t, dstUp->t ) <= isect.t ); + assert( isect.t <= MAX( orgLo->t, dstLo->t )); + assert( MIN( dstLo->s, dstUp->s ) <= isect.s ); + assert( isect.s <= MAX( orgLo->s, orgUp->s )); + + if( VertLeq( &isect, tess->event )) { + /* The intersection point lies slightly to the left of the sweep line, + * so move it until it''s slightly to the right of the sweep line. + * (If we had perfect numerical precision, this would never happen + * in the first place). The easiest and safest thing to do is + * replace the intersection by tess->event. + */ + isect.s = tess->event->s; + isect.t = tess->event->t; + } + /* Similarly, if the computed intersection lies to the right of the + * rightmost origin (which should rarely happen), it can cause + * unbelievable inefficiency on sufficiently degenerate inputs. + * (If you have the test program, try running test54.d with the + * "X zoom" option turned on). + */ + orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo; + if( VertLeq( orgMin, &isect )) { + isect.s = orgMin->s; + isect.t = orgMin->t; + } + + if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) { + /* Easy case -- intersection at one of the right endpoints */ + (void) CheckForRightSplice( tess, regUp ); + return FALSE; + } + + if( (! VertEq( dstUp, tess->event ) + && EdgeSign( dstUp, tess->event, &isect ) >= 0) + || (! VertEq( dstLo, tess->event ) + && EdgeSign( dstLo, tess->event, &isect ) <= 0 )) + { + /* Very unusual -- the new upper or lower edge would pass on the + * wrong side of the sweep event, or through it. This can happen + * due to very small numerical errors in the intersection calculation. + */ + if( dstLo == tess->event ) { + /* Splice dstLo into eUp, and process the new region(s) */ + if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eLo->Sym, eUp ) ) longjmp(tess->env,1); + regUp = TopLeftRegion( regUp ); + if (regUp == NULL) longjmp(tess->env,1); + eUp = RegionBelow(regUp)->eUp; + FinishLeftRegions( tess, RegionBelow(regUp), regLo ); + AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE ); + return TRUE; + } + if( dstUp == tess->event ) { + /* Splice dstUp into eLo, and process the new region(s) */ + if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1); + regLo = regUp; + regUp = TopRightRegion( regUp ); + e = RegionBelow(regUp)->eUp->Rprev; + regLo->eUp = eLo->Oprev; + eLo = FinishLeftRegions( tess, regLo, NULL ); + AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE ); + return TRUE; + } + /* Special case: called from ConnectRightVertex. If either + * edge passes on the wrong side of tess->event, split it + * (and wait for ConnectRightVertex to splice it appropriately). + */ + if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) { + RegionAbove(regUp)->dirty = regUp->dirty = TRUE; + if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); + eUp->Org->s = tess->event->s; + eUp->Org->t = tess->event->t; + } + if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) { + regUp->dirty = regLo->dirty = TRUE; + if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); + eLo->Org->s = tess->event->s; + eLo->Org->t = tess->event->t; + } + /* leave the rest for ConnectRightVertex */ + return FALSE; + } + + /* General case -- split both edges, splice into new vertex. + * When we do the splice operation, the order of the arguments is + * arbitrary as far as correctness goes. However, when the operation + * creates a new face, the work done is proportional to the size of + * the new face. We expect the faces in the processed part of + * the mesh (ie. eUp->Lface) to be smaller than the faces in the + * unprocessed original contours (which will be eLo->Oprev->Lface). + */ + if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); + if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); + if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1); + eUp->Org->s = isect.s; + eUp->Org->t = isect.t; + eUp->Org->pqHandle = pqInsert( tess->pq, eUp->Org ); /* __gl_pqSortInsert */ + if (eUp->Org->pqHandle == LONG_MAX) { + pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */ + tess->pq = NULL; + longjmp(tess->env,1); + } + GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo ); + RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE; + return FALSE; +} + +static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp ) +/* + * When the upper or lower edge of any region changes, the region is + * marked "dirty". This routine walks through all the dirty regions + * and makes sure that the dictionary invariants are satisfied + * (see the comments at the beginning of this file). Of course + * new dirty regions can be created as we make changes to restore + * the invariants. + */ +{ + ActiveRegion *regLo = RegionBelow(regUp); + GLUhalfEdge *eUp, *eLo; + + for( ;; ) { + /* Find the lowest dirty region (we walk from the bottom up). */ + while( regLo->dirty ) { + regUp = regLo; + regLo = RegionBelow(regLo); + } + if( ! regUp->dirty ) { + regLo = regUp; + regUp = RegionAbove( regUp ); + if( regUp == NULL || ! regUp->dirty ) { + /* We've walked all the dirty regions */ + return; + } + } + regUp->dirty = FALSE; + eUp = regUp->eUp; + eLo = regLo->eUp; + + if( eUp->Dst != eLo->Dst ) { + /* Check that the edge ordering is obeyed at the Dst vertices. */ + if( CheckForLeftSplice( tess, regUp )) { + + /* If the upper or lower edge was marked fixUpperEdge, then + * we no longer need it (since these edges are needed only for + * vertices which otherwise have no right-going edges). + */ + if( regLo->fixUpperEdge ) { + DeleteRegion( tess, regLo ); + if ( !__gl_meshDelete( eLo ) ) longjmp(tess->env,1); + regLo = RegionBelow( regUp ); + eLo = regLo->eUp; + } else if( regUp->fixUpperEdge ) { + DeleteRegion( tess, regUp ); + if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1); + regUp = RegionAbove( regLo ); + eUp = regUp->eUp; + } + } + } + if( eUp->Org != eLo->Org ) { + if( eUp->Dst != eLo->Dst + && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge + && (eUp->Dst == tess->event || eLo->Dst == tess->event) ) + { + /* When all else fails in CheckForIntersect(), it uses tess->event + * as the intersection location. To make this possible, it requires + * that tess->event lie between the upper and lower edges, and also + * that neither of these is marked fixUpperEdge (since in the worst + * case it might splice one of these edges into tess->event, and + * violate the invariant that fixable edges are the only right-going + * edge from their associated vertex). + */ + if( CheckForIntersect( tess, regUp )) { + /* WalkDirtyRegions() was called recursively; we're done */ + return; + } + } else { + /* Even though we can't use CheckForIntersect(), the Org vertices + * may violate the dictionary edge ordering. Check and correct this. + */ + (void) CheckForRightSplice( tess, regUp ); + } + } + if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) { + /* A degenerate loop consisting of only two edges -- delete it. */ + AddWinding( eLo, eUp ); + DeleteRegion( tess, regUp ); + if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1); + regUp = RegionAbove( regLo ); + } + } +} + + +static void ConnectRightVertex( GLUtesselator *tess, ActiveRegion *regUp, + GLUhalfEdge *eBottomLeft ) +/* + * Purpose: connect a "right" vertex vEvent (one where all edges go left) + * to the unprocessed portion of the mesh. Since there are no right-going + * edges, two regions (one above vEvent and one below) are being merged + * into one. "regUp" is the upper of these two regions. + * + * There are two reasons for doing this (adding a right-going edge): + * - if the two regions being merged are "inside", we must add an edge + * to keep them separated (the combined region would not be monotone). + * - in any case, we must leave some record of vEvent in the dictionary, + * so that we can merge vEvent with features that we have not seen yet. + * For example, maybe there is a vertical edge which passes just to + * the right of vEvent; we would like to splice vEvent into this edge. + * + * However, we don't want to connect vEvent to just any vertex. We don''t + * want the new edge to cross any other edges; otherwise we will create + * intersection vertices even when the input data had no self-intersections. + * (This is a bad thing; if the user's input data has no intersections, + * we don't want to generate any false intersections ourselves.) + * + * Our eventual goal is to connect vEvent to the leftmost unprocessed + * vertex of the combined region (the union of regUp and regLo). + * But because of unseen vertices with all right-going edges, and also + * new vertices which may be created by edge intersections, we don''t + * know where that leftmost unprocessed vertex is. In the meantime, we + * connect vEvent to the closest vertex of either chain, and mark the region + * as "fixUpperEdge". This flag says to delete and reconnect this edge + * to the next processed vertex on the boundary of the combined region. + * Quite possibly the vertex we connected to will turn out to be the + * closest one, in which case we won''t need to make any changes. + */ +{ + GLUhalfEdge *eNew; + GLUhalfEdge *eTopLeft = eBottomLeft->Onext; + ActiveRegion *regLo = RegionBelow(regUp); + GLUhalfEdge *eUp = regUp->eUp; + GLUhalfEdge *eLo = regLo->eUp; + int degenerate = FALSE; + + if( eUp->Dst != eLo->Dst ) { + (void) CheckForIntersect( tess, regUp ); + } + + /* Possible new degeneracies: upper or lower edge of regUp may pass + * through vEvent, or may coincide with new intersection vertex + */ + if( VertEq( eUp->Org, tess->event )) { + if ( !__gl_meshSplice( eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1); + regUp = TopLeftRegion( regUp ); + if (regUp == NULL) longjmp(tess->env,1); + eTopLeft = RegionBelow( regUp )->eUp; + FinishLeftRegions( tess, RegionBelow(regUp), regLo ); + degenerate = TRUE; + } + if( VertEq( eLo->Org, tess->event )) { + if ( !__gl_meshSplice( eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1); + eBottomLeft = FinishLeftRegions( tess, regLo, NULL ); + degenerate = TRUE; + } + if( degenerate ) { + AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE ); + return; + } + + /* Non-degenerate situation -- need to add a temporary, fixable edge. + * Connect to the closer of eLo->Org, eUp->Org. + */ + if( VertLeq( eLo->Org, eUp->Org )) { + eNew = eLo->Oprev; + } else { + eNew = eUp; + } + eNew = __gl_meshConnect( eBottomLeft->Lprev, eNew ); + if (eNew == NULL) longjmp(tess->env,1); + + /* Prevent cleanup, otherwise eNew might disappear before we've even + * had a chance to mark it as a temporary edge. + */ + AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE ); + eNew->Sym->activeRegion->fixUpperEdge = TRUE; + WalkDirtyRegions( tess, regUp ); +} + +/* Because vertices at exactly the same location are merged together + * before we process the sweep event, some degenerate cases can't occur. + * However if someone eventually makes the modifications required to + * merge features which are close together, the cases below marked + * TOLERANCE_NONZERO will be useful. They were debugged before the + * code to merge identical vertices in the main loop was added. + */ +#define TOLERANCE_NONZERO FALSE + +static void ConnectLeftDegenerate( GLUtesselator *tess, + ActiveRegion *regUp, GLUvertex *vEvent ) +/* + * The event vertex lies exacty on an already-processed edge or vertex. + * Adding the new vertex involves splicing it into the already-processed + * part of the mesh. + */ +{ + GLUhalfEdge *e, *eTopLeft, *eTopRight, *eLast; + ActiveRegion *reg; + + e = regUp->eUp; + if( VertEq( e->Org, vEvent )) { + /* e->Org is an unprocessed vertex - just combine them, and wait + * for e->Org to be pulled from the queue + */ + assert( TOLERANCE_NONZERO ); + SpliceMergeVertices( tess, e, vEvent->anEdge ); + return; + } + + if( ! VertEq( e->Dst, vEvent )) { + /* General case -- splice vEvent into edge e which passes through it */ + if (__gl_meshSplitEdge( e->Sym ) == NULL) longjmp(tess->env,1); + if( regUp->fixUpperEdge ) { + /* This edge was fixable -- delete unused portion of original edge */ + if ( !__gl_meshDelete( e->Onext ) ) longjmp(tess->env,1); + regUp->fixUpperEdge = FALSE; + } + if ( !__gl_meshSplice( vEvent->anEdge, e ) ) longjmp(tess->env,1); + SweepEvent( tess, vEvent ); /* recurse */ + return; + } + + /* vEvent coincides with e->Dst, which has already been processed. + * Splice in the additional right-going edges. + */ + assert( TOLERANCE_NONZERO ); + regUp = TopRightRegion( regUp ); + reg = RegionBelow( regUp ); + eTopRight = reg->eUp->Sym; + eTopLeft = eLast = eTopRight->Onext; + if( reg->fixUpperEdge ) { + /* Here e->Dst has only a single fixable edge going right. + * We can delete it since now we have some real right-going edges. + */ + assert( eTopLeft != eTopRight ); /* there are some left edges too */ + DeleteRegion( tess, reg ); + if ( !__gl_meshDelete( eTopRight ) ) longjmp(tess->env,1); + eTopRight = eTopLeft->Oprev; + } + if ( !__gl_meshSplice( vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1); + if( ! EdgeGoesLeft( eTopLeft )) { + /* e->Dst had no left-going edges -- indicate this to AddRightEdges() */ + eTopLeft = NULL; + } + AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE ); +} + + +static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent ) +/* + * Purpose: connect a "left" vertex (one where both edges go right) + * to the processed portion of the mesh. Let R be the active region + * containing vEvent, and let U and L be the upper and lower edge + * chains of R. There are two possibilities: + * + * - the normal case: split R into two regions, by connecting vEvent to + * the rightmost vertex of U or L lying to the left of the sweep line + * + * - the degenerate case: if vEvent is close enough to U or L, we + * merge vEvent into that edge chain. The subcases are: + * - merging with the rightmost vertex of U or L + * - merging with the active edge of U or L + * - merging with an already-processed portion of U or L + */ +{ + ActiveRegion *regUp, *regLo, *reg; + GLUhalfEdge *eUp, *eLo, *eNew; + ActiveRegion tmp; + + /* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */ + + /* Get a pointer to the active region containing vEvent */ + tmp.eUp = vEvent->anEdge->Sym; + /* __GL_DICTLISTKEY */ /* __gl_dictListSearch */ + regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp )); + regLo = RegionBelow( regUp ); + eUp = regUp->eUp; + eLo = regLo->eUp; + + /* Try merging with U or L first */ + if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) { + ConnectLeftDegenerate( tess, regUp, vEvent ); + return; + } + + /* Connect vEvent to rightmost processed vertex of either chain. + * e->Dst is the vertex that we will connect to vEvent. + */ + reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo; + + if( regUp->inside || reg->fixUpperEdge) { + if( reg == regUp ) { + eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext ); + if (eNew == NULL) longjmp(tess->env,1); + } else { + GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge); + if (tempHalfEdge == NULL) longjmp(tess->env,1); + + eNew = tempHalfEdge->Sym; + } + if( reg->fixUpperEdge ) { + if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1); + } else { + ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew )); + } + SweepEvent( tess, vEvent ); + } else { + /* The new vertex is in a region which does not belong to the polygon. + * We don''t need to connect this vertex to the rest of the mesh. + */ + AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE ); + } +} + + +static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent ) +/* + * Does everything necessary when the sweep line crosses a vertex. + * Updates the mesh and the edge dictionary. + */ +{ + ActiveRegion *regUp, *reg; + GLUhalfEdge *e, *eTopLeft, *eBottomLeft; + + tess->event = vEvent; /* for access in EdgeLeq() */ + DebugEvent( tess ); + + /* Check if this vertex is the right endpoint of an edge that is + * already in the dictionary. In this case we don't need to waste + * time searching for the location to insert new edges. + */ + e = vEvent->anEdge; + while( e->activeRegion == NULL ) { + e = e->Onext; + if( e == vEvent->anEdge ) { + /* All edges go right -- not incident to any processed edges */ + ConnectLeftVertex( tess, vEvent ); + return; + } + } + + /* Processing consists of two phases: first we "finish" all the + * active regions where both the upper and lower edges terminate + * at vEvent (ie. vEvent is closing off these regions). + * We mark these faces "inside" or "outside" the polygon according + * to their winding number, and delete the edges from the dictionary. + * This takes care of all the left-going edges from vEvent. + */ + regUp = TopLeftRegion( e->activeRegion ); + if (regUp == NULL) longjmp(tess->env,1); + reg = RegionBelow( regUp ); + eTopLeft = reg->eUp; + eBottomLeft = FinishLeftRegions( tess, reg, NULL ); + + /* Next we process all the right-going edges from vEvent. This + * involves adding the edges to the dictionary, and creating the + * associated "active regions" which record information about the + * regions between adjacent dictionary edges. + */ + if( eBottomLeft->Onext == eTopLeft ) { + /* No right-going edges -- add a temporary "fixable" edge */ + ConnectRightVertex( tess, regUp, eBottomLeft ); + } else { + AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE ); + } +} + + +/* Make the sentinel coordinates big enough that they will never be + * merged with real input features. (Even with the largest possible + * input contour and the maximum tolerance of 1.0, no merging will be + * done with coordinates larger than 3 * GLU_TESS_MAX_COORD). + */ +#define SENTINEL_COORD (4 * GLU_TESS_MAX_COORD) + +static void AddSentinel( GLUtesselator *tess, GLdouble t ) +/* + * We add two sentinel edges above and below all other edges, + * to avoid special cases at the top and bottom. + */ +{ + GLUhalfEdge *e; + ActiveRegion *reg = (ActiveRegion *)memAlloc( sizeof( ActiveRegion )); + if (reg == NULL) longjmp(tess->env,1); + + e = __gl_meshMakeEdge( tess->mesh ); + if (e == NULL) longjmp(tess->env,1); + + e->Org->s = SENTINEL_COORD; + e->Org->t = t; + e->Dst->s = -SENTINEL_COORD; + e->Dst->t = t; + tess->event = e->Dst; /* initialize it */ + + reg->eUp = e; + reg->windingNumber = 0; + reg->inside = FALSE; + reg->fixUpperEdge = FALSE; + reg->sentinel = TRUE; + reg->dirty = FALSE; + reg->nodeUp = dictInsert( tess->dict, reg ); /* __gl_dictListInsertBefore */ + if (reg->nodeUp == NULL) longjmp(tess->env,1); +} + + +static void InitEdgeDict( GLUtesselator *tess ) +/* + * We maintain an ordering of edge intersections with the sweep line. + * This order is maintained in a dynamic dictionary. + */ +{ + /* __gl_dictListNewDict */ + tess->dict = dictNewDict( tess, (int (*)(void *, DictKey, DictKey)) EdgeLeq ); + if (tess->dict == NULL) longjmp(tess->env,1); + + AddSentinel( tess, -SENTINEL_COORD ); + AddSentinel( tess, SENTINEL_COORD ); +} + + +static void DoneEdgeDict( GLUtesselator *tess ) +{ + ActiveRegion *reg; +#ifndef NDEBUG + int fixedEdges = 0; +#endif + + /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */ + while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) { + /* + * At the end of all processing, the dictionary should contain + * only the two sentinel edges, plus at most one "fixable" edge + * created by ConnectRightVertex(). + */ + if( ! reg->sentinel ) { + assert( reg->fixUpperEdge ); + assert( ++fixedEdges == 1 ); + } + assert( reg->windingNumber == 0 ); + DeleteRegion( tess, reg ); +/* __gl_meshDelete( reg->eUp );*/ + } + dictDeleteDict( tess->dict ); /* __gl_dictListDeleteDict */ +} + + +static void RemoveDegenerateEdges( GLUtesselator *tess ) +/* + * Remove zero-length edges, and contours with fewer than 3 vertices. + */ +{ + GLUhalfEdge *e, *eNext, *eLnext; + GLUhalfEdge *eHead = &tess->mesh->eHead; + + /*LINTED*/ + for( e = eHead->next; e != eHead; e = eNext ) { + eNext = e->next; + eLnext = e->Lnext; + + if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) { + /* Zero-length edge, contour has at least 3 edges */ + + SpliceMergeVertices( tess, eLnext, e ); /* deletes e->Org */ + if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); /* e is a self-loop */ + e = eLnext; + eLnext = e->Lnext; + } + if( eLnext->Lnext == e ) { + /* Degenerate contour (one or two edges) */ + + if( eLnext != e ) { + if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; } + if ( !__gl_meshDelete( eLnext ) ) longjmp(tess->env,1); + } + if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; } + if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); + } + } +} + +static int InitPriorityQ( GLUtesselator *tess ) +/* + * Insert all vertices into the priority queue which determines the + * order in which vertices cross the sweep line. + */ +{ + PriorityQ *pq; + GLUvertex *v, *vHead; + + /* __gl_pqSortNewPriorityQ */ + pq = tess->pq = pqNewPriorityQ( (int (*)(PQkey, PQkey)) __gl_vertLeq ); + if (pq == NULL) return 0; + + vHead = &tess->mesh->vHead; + for( v = vHead->next; v != vHead; v = v->next ) { + v->pqHandle = pqInsert( pq, v ); /* __gl_pqSortInsert */ + if (v->pqHandle == LONG_MAX) break; + } + if (v != vHead || !pqInit( pq ) ) { /* __gl_pqSortInit */ + pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */ + tess->pq = NULL; + return 0; + } + + return 1; +} + + +static void DonePriorityQ( GLUtesselator *tess ) +{ + pqDeletePriorityQ( tess->pq ); /* __gl_pqSortDeletePriorityQ */ +} + + +static int RemoveDegenerateFaces( GLUmesh *mesh ) +/* + * Delete any degenerate faces with only two edges. WalkDirtyRegions() + * will catch almost all of these, but it won't catch degenerate faces + * produced by splice operations on already-processed edges. + * The two places this can happen are in FinishLeftRegions(), when + * we splice in a "temporary" edge produced by ConnectRightVertex(), + * and in CheckForLeftSplice(), where we splice already-processed + * edges to ensure that our dictionary invariants are not violated + * by numerical errors. + * + * In both these cases it is *very* dangerous to delete the offending + * edge at the time, since one of the routines further up the stack + * will sometimes be keeping a pointer to that edge. + */ +{ + GLUface *f, *fNext; + GLUhalfEdge *e; + + /*LINTED*/ + for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) { + fNext = f->next; + e = f->anEdge; + assert( e->Lnext != e ); + + if( e->Lnext->Lnext == e ) { + /* A face with only two edges */ + AddWinding( e->Onext, e ); + if ( !__gl_meshDelete( e ) ) return 0; + } + } + return 1; +} + +int __gl_computeInterior( GLUtesselator *tess ) +/* + * __gl_computeInterior( tess ) computes the planar arrangement specified + * by the given contours, and further subdivides this arrangement + * into regions. Each region is marked "inside" if it belongs + * to the polygon, according to the rule given by tess->windingRule. + * Each interior region is guaranteed be monotone. + */ +{ + GLUvertex *v, *vNext; + + tess->fatalError = FALSE; + + /* Each vertex defines an event for our sweep line. Start by inserting + * all the vertices in a priority queue. Events are processed in + * lexicographic order, ie. + * + * e1 < e2 iff e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y) + */ + RemoveDegenerateEdges( tess ); + if ( !InitPriorityQ( tess ) ) return 0; /* if error */ + InitEdgeDict( tess ); + + /* __gl_pqSortExtractMin */ + while( (v = (GLUvertex *)pqExtractMin( tess->pq )) != NULL ) { + for( ;; ) { + vNext = (GLUvertex *)pqMinimum( tess->pq ); /* __gl_pqSortMinimum */ + if( vNext == NULL || ! VertEq( vNext, v )) break; + + /* Merge together all vertices at exactly the same location. + * This is more efficient than processing them one at a time, + * simplifies the code (see ConnectLeftDegenerate), and is also + * important for correct handling of certain degenerate cases. + * For example, suppose there are two identical edges A and B + * that belong to different contours (so without this code they would + * be processed by separate sweep events). Suppose another edge C + * crosses A and B from above. When A is processed, we split it + * at its intersection point with C. However this also splits C, + * so when we insert B we may compute a slightly different + * intersection point. This might leave two edges with a small + * gap between them. This kind of error is especially obvious + * when using boundary extraction (GLU_TESS_BOUNDARY_ONLY). + */ + vNext = (GLUvertex *)pqExtractMin( tess->pq ); /* __gl_pqSortExtractMin*/ + SpliceMergeVertices( tess, v->anEdge, vNext->anEdge ); + } + SweepEvent( tess, v ); + } + + /* Set tess->event for debugging purposes */ + /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */ + tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org; + DebugEvent( tess ); + DoneEdgeDict( tess ); + DonePriorityQ( tess ); + + if ( !RemoveDegenerateFaces( tess->mesh ) ) return 0; + __gl_meshCheckMesh( tess->mesh ); + + return 1; +} diff --git a/Dependencies/GLU/sweep.h b/Dependencies/GLU/sweep.h new file mode 100644 index 0000000..feb68b0 --- /dev/null +++ b/Dependencies/GLU/sweep.h @@ -0,0 +1,77 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __sweep_h_ +#define __sweep_h_ + +#include "mesh.h" + +/* __gl_computeInterior( tess ) computes the planar arrangement specified + * by the given contours, and further subdivides this arrangement + * into regions. Each region is marked "inside" if it belongs + * to the polygon, according to the rule given by tess->windingRule. + * Each interior region is guaranteed be monotone. + */ +int __gl_computeInterior( GLUtesselator *tess ); + + +/* The following is here *only* for access by debugging routines */ + +#include "dict.h" + +/* For each pair of adjacent edges crossing the sweep line, there is + * an ActiveRegion to represent the region between them. The active + * regions are kept in sorted order in a dynamic dictionary. As the + * sweep line crosses each vertex, we update the affected regions. + */ + +struct ActiveRegion { + GLUhalfEdge *eUp; /* upper edge, directed right to left */ + DictNode *nodeUp; /* dictionary node corresponding to eUp */ + int windingNumber; /* used to determine which regions are + * inside the polygon */ + GLboolean inside; /* is this region inside the polygon? */ + GLboolean sentinel; /* marks fake edges at t = +/-infinity */ + GLboolean dirty; /* marks regions where the upper or lower + * edge has changed, but we haven't checked + * whether they intersect yet */ + GLboolean fixUpperEdge; /* marks temporary edges introduced when + * we process a "right vertex" (one without + * any edges leaving to the right) */ +}; + +#define RegionBelow(r) ((ActiveRegion *) dictKey(dictPred((r)->nodeUp))) +#define RegionAbove(r) ((ActiveRegion *) dictKey(dictSucc((r)->nodeUp))) + +#endif diff --git a/Dependencies/GLU/tess.c b/Dependencies/GLU/tess.c new file mode 100644 index 0000000..029a02c --- /dev/null +++ b/Dependencies/GLU/tess.c @@ -0,0 +1,628 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "gluos.h" +#include +#include +#include +#include "memalloc.h" +#include "tess.h" +#include "mesh.h" +#include "normal.h" +#include "sweep.h" +#include "tessmono.h" +#include "render.h" + +#define GLU_TESS_DEFAULT_TOLERANCE 0.0 +#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */ + +#define TRUE 1 +#define FALSE 0 + +/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {} +/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {} +/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {} +/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {} +/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {} +/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4], + GLfloat weight[4], void **dataOut ) {} +/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {} + + +/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type, + void *polygonData ) {} +/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, + void *polygonData ) {} +/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data, + void *polygonData ) {} +/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {} +/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum, + void *polygonData ) {} +/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], + void *data[4], + GLfloat weight[4], + void **outData, + void *polygonData ) {} + +/* Half-edges are allocated in pairs (see mesh.c) */ +typedef struct { GLUhalfEdge e, eSym; } EdgePair; + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \ + MAX(sizeof(GLUvertex),sizeof(GLUface)))) + + +GLUtesselator * GLAPIENTRY +gluNewTess( void ) +{ + GLUtesselator *tess; + + /* Only initialize fields which can be changed by the api. Other fields + * are initialized where they are used. + */ + + if (memInit( MAX_FAST_ALLOC ) == 0) { + return 0; /* out of memory */ + } + tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator )); + if (tess == NULL) { + return 0; /* out of memory */ + } + + tess->state = T_DORMANT; + + tess->normal[0] = 0; + tess->normal[1] = 0; + tess->normal[2] = 0; + + tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE; + tess->windingRule = GLU_TESS_WINDING_ODD; + tess->flagBoundary = FALSE; + tess->boundaryOnly = FALSE; + + tess->callBegin = &noBegin; + tess->callEdgeFlag = &noEdgeFlag; + tess->callVertex = &noVertex; + tess->callEnd = &noEnd; + + tess->callError = &noError; + tess->callCombine = &noCombine; + tess->callMesh = &noMesh; + + tess->callBeginData= &__gl_noBeginData; + tess->callEdgeFlagData= &__gl_noEdgeFlagData; + tess->callVertexData= &__gl_noVertexData; + tess->callEndData= &__gl_noEndData; + tess->callErrorData= &__gl_noErrorData; + tess->callCombineData= &__gl_noCombineData; + + tess->polygonData= NULL; + + return tess; +} + +static void MakeDormant( GLUtesselator *tess ) +{ + /* Return the tessellator to its original dormant state. */ + + if( tess->mesh != NULL ) { + __gl_meshDeleteMesh( tess->mesh ); + } + tess->state = T_DORMANT; + tess->lastEdge = NULL; + tess->mesh = NULL; +} + +#define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s) + +static void GotoState( GLUtesselator *tess, enum TessState newState ) +{ + while( tess->state != newState ) { + /* We change the current state one level at a time, to get to + * the desired state. + */ + if( tess->state < newState ) { + switch( tess->state ) { + case T_DORMANT: + CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON ); + gluTessBeginPolygon( tess, NULL ); + break; + case T_IN_POLYGON: + CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR ); + gluTessBeginContour( tess ); + break; + default: + ; + } + } else { + switch( tess->state ) { + case T_IN_CONTOUR: + CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR ); + gluTessEndContour( tess ); + break; + case T_IN_POLYGON: + CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON ); + /* gluTessEndPolygon( tess ) is too much work! */ + MakeDormant( tess ); + break; + default: + ; + } + } + } +} + + +void GLAPIENTRY +gluDeleteTess( GLUtesselator *tess ) +{ + RequireState( tess, T_DORMANT ); + memFree( tess ); +} + + +void GLAPIENTRY +gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value ) +{ + GLenum windingRule; + + switch( which ) { + case GLU_TESS_TOLERANCE: + if( value < 0.0 || value > 1.0 ) break; + tess->relTolerance = value; + return; + + case GLU_TESS_WINDING_RULE: + windingRule = (GLenum) value; + if( windingRule != value ) break; /* not an integer */ + + switch( windingRule ) { + case GLU_TESS_WINDING_ODD: + case GLU_TESS_WINDING_NONZERO: + case GLU_TESS_WINDING_POSITIVE: + case GLU_TESS_WINDING_NEGATIVE: + case GLU_TESS_WINDING_ABS_GEQ_TWO: + tess->windingRule = windingRule; + return; + default: + break; + } + + case GLU_TESS_BOUNDARY_ONLY: + tess->boundaryOnly = (value != 0); + return; + + default: + CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); + return; + } + CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE ); +} + +/* Returns tessellator property */ +void GLAPIENTRY +gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value ) +{ + switch (which) { + case GLU_TESS_TOLERANCE: + /* tolerance should be in range [0..1] */ + assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0); + *value= tess->relTolerance; + break; + case GLU_TESS_WINDING_RULE: + assert(tess->windingRule == GLU_TESS_WINDING_ODD || + tess->windingRule == GLU_TESS_WINDING_NONZERO || + tess->windingRule == GLU_TESS_WINDING_POSITIVE || + tess->windingRule == GLU_TESS_WINDING_NEGATIVE || + tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO); + *value= tess->windingRule; + break; + case GLU_TESS_BOUNDARY_ONLY: + assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE); + *value= tess->boundaryOnly; + break; + default: + *value= 0.0; + CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); + break; + } +} /* gluGetTessProperty() */ + +void GLAPIENTRY +gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z ) +{ + tess->normal[0] = x; + tess->normal[1] = y; + tess->normal[2] = z; +} + +void GLAPIENTRY +gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn) +{ + switch( which ) { + case GLU_TESS_BEGIN: + tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn; + return; + case GLU_TESS_BEGIN_DATA: + tess->callBeginData = (fn == NULL) ? + &__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn; + return; + case GLU_TESS_EDGE_FLAG: + tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag : + (void (GLAPIENTRY *)(GLboolean)) fn; + /* If the client wants boundary edges to be flagged, + * we render everything as separate triangles (no strips or fans). + */ + tess->flagBoundary = (fn != NULL); + return; + case GLU_TESS_EDGE_FLAG_DATA: + tess->callEdgeFlagData= (fn == NULL) ? + &__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn; + /* If the client wants boundary edges to be flagged, + * we render everything as separate triangles (no strips or fans). + */ + tess->flagBoundary = (fn != NULL); + return; + case GLU_TESS_VERTEX: + tess->callVertex = (fn == NULL) ? &noVertex : + (void (GLAPIENTRY *)(void *)) fn; + return; + case GLU_TESS_VERTEX_DATA: + tess->callVertexData = (fn == NULL) ? + &__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn; + return; + case GLU_TESS_END: + tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn; + return; + case GLU_TESS_END_DATA: + tess->callEndData = (fn == NULL) ? &__gl_noEndData : + (void (GLAPIENTRY *)(void *)) fn; + return; + case GLU_TESS_ERROR: + tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn; + return; + case GLU_TESS_ERROR_DATA: + tess->callErrorData = (fn == NULL) ? + &__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn; + return; + case GLU_TESS_COMBINE: + tess->callCombine = (fn == NULL) ? &noCombine : + (void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn; + return; + case GLU_TESS_COMBINE_DATA: + tess->callCombineData = (fn == NULL) ? &__gl_noCombineData : + (void (GLAPIENTRY *)(GLdouble [3], + void *[4], + GLfloat [4], + void **, + void *)) fn; + return; + case GLU_TESS_MESH: + tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn; + return; + default: + CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); + return; + } +} + +static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) +{ + GLUhalfEdge *e; + + e = tess->lastEdge; + if( e == NULL ) { + /* Make a self-loop (one vertex, one edge). */ + + e = __gl_meshMakeEdge( tess->mesh ); + if (e == NULL) return 0; + if ( !__gl_meshSplice( e, e->Sym ) ) return 0; + } else { + /* Create a new vertex and edge which immediately follow e + * in the ordering around the left face. + */ + if (__gl_meshSplitEdge( e ) == NULL) return 0; + e = e->Lnext; + } + + /* The new vertex is now e->Org. */ + e->Org->data = data; + e->Org->coords[0] = coords[0]; + e->Org->coords[1] = coords[1]; + e->Org->coords[2] = coords[2]; + + /* The winding of an edge says how the winding number changes as we + * cross from the edge''s right face to its left face. We add the + * vertices in such an order that a CCW contour will add +1 to + * the winding number of the region inside the contour. + */ + e->winding = 1; + e->Sym->winding = -1; + + tess->lastEdge = e; + + return 1; +} + + +static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) +{ + CachedVertex *v = &tess->cache[tess->cacheCount]; + + v->data = data; + v->coords[0] = coords[0]; + v->coords[1] = coords[1]; + v->coords[2] = coords[2]; + ++tess->cacheCount; +} + + +static int EmptyCache( GLUtesselator *tess ) +{ + CachedVertex *v = tess->cache; + CachedVertex *vLast; + + tess->mesh = __gl_meshNewMesh(); + if (tess->mesh == NULL) return 0; + + for( vLast = v + tess->cacheCount; v < vLast; ++v ) { + if ( !AddVertex( tess, v->coords, v->data ) ) return 0; + } + tess->cacheCount = 0; + tess->emptyCache = FALSE; + + return 1; +} + + +void GLAPIENTRY +gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) +{ + int i, tooLarge = FALSE; + GLdouble x, clamped[3]; + + RequireState( tess, T_IN_CONTOUR ); + + if( tess->emptyCache ) { + if ( !EmptyCache( tess ) ) { + CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); + return; + } + tess->lastEdge = NULL; + } + for( i = 0; i < 3; ++i ) { + x = coords[i]; + if( x < - GLU_TESS_MAX_COORD ) { + x = - GLU_TESS_MAX_COORD; + tooLarge = TRUE; + } + if( x > GLU_TESS_MAX_COORD ) { + x = GLU_TESS_MAX_COORD; + tooLarge = TRUE; + } + clamped[i] = x; + } + if( tooLarge ) { + CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE ); + } + + if( tess->mesh == NULL ) { + if( tess->cacheCount < TESS_MAX_CACHE ) { + CacheVertex( tess, clamped, data ); + return; + } + if ( !EmptyCache( tess ) ) { + CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); + return; + } + } + if ( !AddVertex( tess, clamped, data ) ) { + CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); + } +} + + +void GLAPIENTRY +gluTessBeginPolygon( GLUtesselator *tess, void *data ) +{ + RequireState( tess, T_DORMANT ); + + tess->state = T_IN_POLYGON; + tess->cacheCount = 0; + tess->emptyCache = FALSE; + tess->mesh = NULL; + + tess->polygonData= data; +} + + +void GLAPIENTRY +gluTessBeginContour( GLUtesselator *tess ) +{ + RequireState( tess, T_IN_POLYGON ); + + tess->state = T_IN_CONTOUR; + tess->lastEdge = NULL; + if( tess->cacheCount > 0 ) { + /* Just set a flag so we don't get confused by empty contours + * -- these can be generated accidentally with the obsolete + * NextContour() interface. + */ + tess->emptyCache = TRUE; + } +} + + +void GLAPIENTRY +gluTessEndContour( GLUtesselator *tess ) +{ + RequireState( tess, T_IN_CONTOUR ); + tess->state = T_IN_POLYGON; +} + +void GLAPIENTRY +gluTessEndPolygon( GLUtesselator *tess ) +{ + GLUmesh *mesh; + + if (setjmp(tess->env) != 0) { + /* come back here if out of memory */ + CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); + return; + } + + RequireState( tess, T_IN_POLYGON ); + tess->state = T_DORMANT; + + if( tess->mesh == NULL ) { + if( ! tess->flagBoundary && tess->callMesh == &noMesh ) { + + /* Try some special code to make the easy cases go quickly + * (eg. convex polygons). This code does NOT handle multiple contours, + * intersections, edge flags, and of course it does not generate + * an explicit mesh either. + */ + if( __gl_renderCache( tess )) { + tess->polygonData= NULL; + return; + } + } + if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/ + } + + /* Determine the polygon normal and project vertices onto the plane + * of the polygon. + */ + __gl_projectPolygon( tess ); + + /* __gl_computeInterior( tess ) computes the planar arrangement specified + * by the given contours, and further subdivides this arrangement + * into regions. Each region is marked "inside" if it belongs + * to the polygon, according to the rule given by tess->windingRule. + * Each interior region is guaranteed be monotone. + */ + if ( !__gl_computeInterior( tess ) ) { + longjmp(tess->env,1); /* could've used a label */ + } + + mesh = tess->mesh; + if( ! tess->fatalError ) { + int rc = 1; + + /* If the user wants only the boundary contours, we throw away all edges + * except those which separate the interior from the exterior. + * Otherwise we tessellate all the regions marked "inside". + */ + if( tess->boundaryOnly ) { + rc = __gl_meshSetWindingNumber( mesh, 1, TRUE ); + } else { + rc = __gl_meshTessellateInterior( mesh ); + } + if (rc == 0) longjmp(tess->env,1); /* could've used a label */ + + __gl_meshCheckMesh( mesh ); + + if( tess->callBegin != &noBegin || tess->callEnd != &noEnd + || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag + || tess->callBeginData != &__gl_noBeginData + || tess->callEndData != &__gl_noEndData + || tess->callVertexData != &__gl_noVertexData + || tess->callEdgeFlagData != &__gl_noEdgeFlagData ) + { + if( tess->boundaryOnly ) { + __gl_renderBoundary( tess, mesh ); /* output boundary contours */ + } else { + __gl_renderMesh( tess, mesh ); /* output strips and fans */ + } + } + if( tess->callMesh != &noMesh ) { + + /* Throw away the exterior faces, so that all faces are interior. + * This way the user doesn't have to check the "inside" flag, + * and we don't need to even reveal its existence. It also leaves + * the freedom for an implementation to not generate the exterior + * faces in the first place. + */ + __gl_meshDiscardExterior( mesh ); + (*tess->callMesh)( mesh ); /* user wants the mesh itself */ + tess->mesh = NULL; + tess->polygonData= NULL; + return; + } + } + __gl_meshDeleteMesh( mesh ); + tess->polygonData= NULL; + tess->mesh = NULL; +} + + +/*XXXblythe unused function*/ +#if 0 +void GLAPIENTRY +gluDeleteMesh( GLUmesh *mesh ) +{ + __gl_meshDeleteMesh( mesh ); +} +#endif + + + +/*******************************************************/ + +/* Obsolete calls -- for backward compatibility */ + +void GLAPIENTRY +gluBeginPolygon( GLUtesselator *tess ) +{ + gluTessBeginPolygon( tess, NULL ); + gluTessBeginContour( tess ); +} + + +/*ARGSUSED*/ +void GLAPIENTRY +gluNextContour( GLUtesselator *tess, GLenum type ) +{ + gluTessEndContour( tess ); + gluTessBeginContour( tess ); +} + + +void GLAPIENTRY +gluEndPolygon( GLUtesselator *tess ) +{ + gluTessEndContour( tess ); + gluTessEndPolygon( tess ); +} diff --git a/Dependencies/GLU/tess.h b/Dependencies/GLU/tess.h new file mode 100644 index 0000000..064477d --- /dev/null +++ b/Dependencies/GLU/tess.h @@ -0,0 +1,165 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __tess_h_ +#define __tess_h_ + +#include "GL/glu.h" +#include +#include "mesh.h" +#include "dict.h" +#include "priorityq.h" + +/* The begin/end calls must be properly nested. We keep track of + * the current state to enforce the ordering. + */ +enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR }; + +/* We cache vertex data for single-contour polygons so that we can + * try a quick-and-dirty decomposition first. + */ +#define TESS_MAX_CACHE 100 + +typedef struct CachedVertex { + GLdouble coords[3]; + void *data; +} CachedVertex; + +struct GLUtesselator { + + /*** state needed for collecting the input data ***/ + + enum TessState state; /* what begin/end calls have we seen? */ + + GLUhalfEdge *lastEdge; /* lastEdge->Org is the most recent vertex */ + GLUmesh *mesh; /* stores the input contours, and eventually + the tessellation itself */ + + void (GLAPIENTRY *callError)( GLenum errnum ); + + /*** state needed for projecting onto the sweep plane ***/ + + GLdouble normal[3]; /* user-specified normal (if provided) */ + GLdouble sUnit[3]; /* unit vector in s-direction (debugging) */ + GLdouble tUnit[3]; /* unit vector in t-direction (debugging) */ + + /*** state needed for the line sweep ***/ + + GLdouble relTolerance; /* tolerance for merging features */ + GLenum windingRule; /* rule for determining polygon interior */ + GLboolean fatalError; /* fatal error: needed combine callback */ + + Dict *dict; /* edge dictionary for sweep line */ + PriorityQ *pq; /* priority queue of vertex events */ + GLUvertex *event; /* current sweep event being processed */ + + void (GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4], + GLfloat weight[4], void **outData ); + + /*** state needed for rendering callbacks (see render.c) ***/ + + GLboolean flagBoundary; /* mark boundary edges (use EdgeFlag) */ + GLboolean boundaryOnly; /* Extract contours, not triangles */ + GLUface *lonelyTriList; + /* list of triangles which could not be rendered as strips or fans */ + + void (GLAPIENTRY *callBegin)( GLenum type ); + void (GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge ); + void (GLAPIENTRY *callVertex)( void *data ); + void (GLAPIENTRY *callEnd)( void ); + void (GLAPIENTRY *callMesh)( GLUmesh *mesh ); + + + /*** state needed to cache single-contour polygons for renderCache() */ + + GLboolean emptyCache; /* empty cache on next vertex() call */ + int cacheCount; /* number of cached vertices */ + CachedVertex cache[TESS_MAX_CACHE]; /* the vertex data */ + + /*** rendering callbacks that also pass polygon data ***/ + void (GLAPIENTRY *callBeginData)( GLenum type, void *polygonData ); + void (GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge, + void *polygonData ); + void (GLAPIENTRY *callVertexData)( void *data, void *polygonData ); + void (GLAPIENTRY *callEndData)( void *polygonData ); + void (GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData ); + void (GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4], + GLfloat weight[4], void **outData, + void *polygonData ); + + jmp_buf env; /* place to jump to when memAllocs fail */ + + void *polygonData; /* client data for current polygon */ +}; + +void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData ); +void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData ); +void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData ); +void GLAPIENTRY __gl_noEndData( void *polygonData ); +void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData ); +void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4], + GLfloat weight[4], void **outData, + void *polygonData ); + +#define CALL_BEGIN_OR_BEGIN_DATA(a) \ + if (tess->callBeginData != &__gl_noBeginData) \ + (*tess->callBeginData)((a),tess->polygonData); \ + else (*tess->callBegin)((a)); + +#define CALL_VERTEX_OR_VERTEX_DATA(a) \ + if (tess->callVertexData != &__gl_noVertexData) \ + (*tess->callVertexData)((a),tess->polygonData); \ + else (*tess->callVertex)((a)); + +#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \ + if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \ + (*tess->callEdgeFlagData)((a),tess->polygonData); \ + else (*tess->callEdgeFlag)((a)); + +#define CALL_END_OR_END_DATA() \ + if (tess->callEndData != &__gl_noEndData) \ + (*tess->callEndData)(tess->polygonData); \ + else (*tess->callEnd)(); + +#define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \ + if (tess->callCombineData != &__gl_noCombineData) \ + (*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \ + else (*tess->callCombine)((a),(b),(c),(d)); + +#define CALL_ERROR_OR_ERROR_DATA(a) \ + if (tess->callErrorData != &__gl_noErrorData) \ + (*tess->callErrorData)((a),tess->polygonData); \ + else (*tess->callError)((a)); + +#endif diff --git a/Dependencies/GLU/tessmono.c b/Dependencies/GLU/tessmono.c new file mode 100644 index 0000000..4d08440 --- /dev/null +++ b/Dependencies/GLU/tessmono.c @@ -0,0 +1,201 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#include "gluos.h" +#include +#include "geom.h" +#include "mesh.h" +#include "tessmono.h" +#include + +#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \ + eDst->Sym->winding += eSrc->Sym->winding) + +/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region + * (what else would it do??) The region must consist of a single + * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this + * case means that any vertical line intersects the interior of the + * region in a single interval. + * + * Tessellation consists of adding interior edges (actually pairs of + * half-edges), to split the region into non-overlapping triangles. + * + * The basic idea is explained in Preparata and Shamos (which I don''t + * have handy right now), although their implementation is more + * complicated than this one. The are two edge chains, an upper chain + * and a lower chain. We process all vertices from both chains in order, + * from right to left. + * + * The algorithm ensures that the following invariant holds after each + * vertex is processed: the untessellated region consists of two + * chains, where one chain (say the upper) is a single edge, and + * the other chain is concave. The left vertex of the single edge + * is always to the left of all vertices in the concave chain. + * + * Each step consists of adding the rightmost unprocessed vertex to one + * of the two chains, and forming a fan of triangles from the rightmost + * of two chain endpoints. Determining whether we can add each triangle + * to the fan is a simple orientation test. By making the fan as large + * as possible, we restore the invariant (check it yourself). + */ +int __gl_meshTessellateMonoRegion( GLUface *face ) +{ + GLUhalfEdge *up, *lo; + + /* All edges are oriented CCW around the boundary of the region. + * First, find the half-edge whose origin vertex is rightmost. + * Since the sweep goes from left to right, face->anEdge should + * be close to the edge we want. + */ + up = face->anEdge; + assert( up->Lnext != up && up->Lnext->Lnext != up ); + + for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev ) + ; + for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext ) + ; + lo = up->Lprev; + + while( up->Lnext != lo ) { + if( VertLeq( up->Dst, lo->Org )) { + /* up->Dst is on the left. It is safe to form triangles from lo->Org. + * The EdgeGoesLeft test guarantees progress even when some triangles + * are CW, given that the upper and lower chains are truly monotone. + */ + while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext ) + || EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) { + GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo ); + if (tempHalfEdge == NULL) return 0; + lo = tempHalfEdge->Sym; + } + lo = lo->Lprev; + } else { + /* lo->Org is on the left. We can make CCW triangles from up->Dst. */ + while( lo->Lnext != up && (EdgeGoesRight( up->Lprev ) + || EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) { + GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev ); + if (tempHalfEdge == NULL) return 0; + up = tempHalfEdge->Sym; + } + up = up->Lnext; + } + } + + /* Now lo->Org == up->Dst == the leftmost vertex. The remaining region + * can be tessellated in a fan from this leftmost vertex. + */ + assert( lo->Lnext != up ); + while( lo->Lnext->Lnext != up ) { + GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo ); + if (tempHalfEdge == NULL) return 0; + lo = tempHalfEdge->Sym; + } + + return 1; +} + + +/* __gl_meshTessellateInterior( mesh ) tessellates each region of + * the mesh which is marked "inside" the polygon. Each such region + * must be monotone. + */ +int __gl_meshTessellateInterior( GLUmesh *mesh ) +{ + GLUface *f, *next; + + /*LINTED*/ + for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) { + /* Make sure we don''t try to tessellate the new triangles. */ + next = f->next; + if( f->inside ) { + if ( !__gl_meshTessellateMonoRegion( f ) ) return 0; + } + } + + return 1; +} + + +/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces + * which are not marked "inside" the polygon. Since further mesh operations + * on NULL faces are not allowed, the main purpose is to clean up the + * mesh so that exterior loops are not represented in the data structure. + */ +void __gl_meshDiscardExterior( GLUmesh *mesh ) +{ + GLUface *f, *next; + + /*LINTED*/ + for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) { + /* Since f will be destroyed, save its next pointer. */ + next = f->next; + if( ! f->inside ) { + __gl_meshZapFace( f ); + } + } +} + +#define MARKED_FOR_DELETION 0x7fffffff + +/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the + * winding numbers on all edges so that regions marked "inside" the + * polygon have a winding number of "value", and regions outside + * have a winding number of 0. + * + * If keepOnlyBoundary is TRUE, it also deletes all edges which do not + * separate an interior region from an exterior one. + */ +int __gl_meshSetWindingNumber( GLUmesh *mesh, int value, + GLboolean keepOnlyBoundary ) +{ + GLUhalfEdge *e, *eNext; + + for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) { + eNext = e->next; + if( e->Rface->inside != e->Lface->inside ) { + + /* This is a boundary edge (one side is interior, one is exterior). */ + e->winding = (e->Lface->inside) ? value : -value; + } else { + + /* Both regions are interior, or both are exterior. */ + if( ! keepOnlyBoundary ) { + e->winding = 0; + } else { + if ( !__gl_meshDelete( e ) ) return 0; + } + } + } + return 1; +} diff --git a/Dependencies/GLU/tessmono.h b/Dependencies/GLU/tessmono.h new file mode 100644 index 0000000..8ee1b2f --- /dev/null +++ b/Dependencies/GLU/tessmono.h @@ -0,0 +1,71 @@ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ +/* +** Author: Eric Veach, July 1994. +** +*/ + +#ifndef __tessmono_h_ +#define __tessmono_h_ + +/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region + * (what else would it do??) The region must consist of a single + * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this + * case means that any vertical line intersects the interior of the + * region in a single interval. + * + * Tessellation consists of adding interior edges (actually pairs of + * half-edges), to split the region into non-overlapping triangles. + * + * __gl_meshTessellateInterior( mesh ) tessellates each region of + * the mesh which is marked "inside" the polygon. Each such region + * must be monotone. + * + * __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces + * which are not marked "inside" the polygon. Since further mesh operations + * on NULL faces are not allowed, the main purpose is to clean up the + * mesh so that exterior loops are not represented in the data structure. + * + * __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the + * winding numbers on all edges so that regions marked "inside" the + * polygon have a winding number of "value", and regions outside + * have a winding number of 0. + * + * If keepOnlyBoundary is TRUE, it also deletes all edges which do not + * separate an interior region from an exterior one. + */ + +int __gl_meshTessellateMonoRegion( GLUface *face ); +int __gl_meshTessellateInterior( GLUmesh *mesh ); +void __gl_meshDiscardExterior( GLUmesh *mesh ); +int __gl_meshSetWindingNumber( GLUmesh *mesh, int value, + GLboolean keepOnlyBoundary ); + +#endif diff --git a/Dependencies/GLU/util.c b/Dependencies/GLU/util.c new file mode 100644 index 0000000..90d58f3 --- /dev/null +++ b/Dependencies/GLU/util.c @@ -0,0 +1,90 @@ +// These are just the bits of GLU we use so we can ditch the external +// dependency (since it turns out to be complicated, as it depends on libGL, +// which we load dynamically, etc). This is from SGI's open source version. + +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#include +#include +#include "GL/gl.h" +#include "GL/glu.h" + +/* +** Make m an identity matrix +*/ +static void __gluMakeIdentityd(GLdouble m[16]) +{ + m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0; + m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0; + m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0; + m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1; +} + +static void __gluMakeIdentityf(GLfloat m[16]) +{ + m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0; + m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0; + m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0; + m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1; +} + +void GLAPIENTRY +gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top) +{ + glOrtho(left, right, bottom, top, -1, 1); +} + +#define __glPi 3.14159265358979323846 + +void GLAPIENTRY +gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) +{ + GLdouble m[4][4]; + double sine, cotangent, deltaZ; + double radians = fovy / 2 * __glPi / 180; + + deltaZ = zFar - zNear; + sine = sin(radians); + if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) { + return; + } + cotangent = cos(radians) / sine; + + __gluMakeIdentityd(&m[0][0]); + m[0][0] = cotangent / aspect; + m[1][1] = cotangent; + m[2][2] = -(zFar + zNear) / deltaZ; + m[2][3] = -1; + m[3][2] = -2 * zNear * zFar / deltaZ; + m[3][3] = 0; + glMultMatrixd(&m[0][0]); +} + diff --git a/GLU/dict-list.h b/GLU/dict-list.h deleted file mode 100644 index 11331a7..0000000 --- a/GLU/dict-list.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __dict_list_h_ -#define __dict_list_h_ - -/* Use #define's so that another heap implementation can use this one */ - -#define DictKey DictListKey -#define Dict DictList -#define DictNode DictListNode - -#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq) -#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict) - -#define dictSearch(dict,key) __gl_dictListSearch(dict,key) -#define dictInsert(dict,key) __gl_dictListInsert(dict,key) -#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key) -#define dictDelete(dict,node) __gl_dictListDelete(dict,node) - -#define dictKey(n) __gl_dictListKey(n) -#define dictSucc(n) __gl_dictListSucc(n) -#define dictPred(n) __gl_dictListPred(n) -#define dictMin(d) __gl_dictListMin(d) -#define dictMax(d) __gl_dictListMax(d) - - - -typedef void *DictKey; -typedef struct Dict Dict; -typedef struct DictNode DictNode; - -Dict *dictNewDict( - void *frame, - int (*leq)(void *frame, DictKey key1, DictKey key2) ); - -void dictDeleteDict( Dict *dict ); - -/* Search returns the node with the smallest key greater than or equal - * to the given key. If there is no such key, returns a node whose - * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc. - */ -DictNode *dictSearch( Dict *dict, DictKey key ); -DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ); -void dictDelete( Dict *dict, DictNode *node ); - -#define __gl_dictListKey(n) ((n)->key) -#define __gl_dictListSucc(n) ((n)->next) -#define __gl_dictListPred(n) ((n)->prev) -#define __gl_dictListMin(d) ((d)->head.next) -#define __gl_dictListMax(d) ((d)->head.prev) -#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k))) - - -/*** Private data structures ***/ - -struct DictNode { - DictKey key; - DictNode *next; - DictNode *prev; -}; - -struct Dict { - DictNode head; - void *frame; - int (*leq)(void *frame, DictKey key1, DictKey key2); -}; - -#endif diff --git a/GLU/dict.c b/GLU/dict.c deleted file mode 100644 index 49d4f75..0000000 --- a/GLU/dict.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#include -#include "dict-list.h" -#include "memalloc.h" - -/* really __gl_dictListNewDict */ -Dict *dictNewDict( void *frame, - int (*leq)(void *frame, DictKey key1, DictKey key2) ) -{ - Dict *dict = (Dict *) memAlloc( sizeof( Dict )); - DictNode *head; - - if (dict == NULL) return NULL; - - head = &dict->head; - - head->key = NULL; - head->next = head; - head->prev = head; - - dict->frame = frame; - dict->leq = leq; - - return dict; -} - -/* really __gl_dictListDeleteDict */ -void dictDeleteDict( Dict *dict ) -{ - DictNode *node, *next; - - for( node = dict->head.next; node != &dict->head; node = next ) { - next = node->next; - memFree( node ); - } - memFree( dict ); -} - -/* really __gl_dictListInsertBefore */ -DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ) -{ - DictNode *newNode; - - do { - node = node->prev; - } while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key)); - - newNode = (DictNode *) memAlloc( sizeof( DictNode )); - if (newNode == NULL) return NULL; - - newNode->key = key; - newNode->next = node->next; - node->next->prev = newNode; - newNode->prev = node; - node->next = newNode; - - return newNode; -} - -/* really __gl_dictListDelete */ -void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/ -{ - node->next->prev = node->prev; - node->prev->next = node->next; - memFree( node ); -} - -/* really __gl_dictListSearch */ -DictNode *dictSearch( Dict *dict, DictKey key ) -{ - DictNode *node = &dict->head; - - do { - node = node->next; - } while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key)); - - return node; -} diff --git a/GLU/dict.h b/GLU/dict.h deleted file mode 100644 index 11331a7..0000000 --- a/GLU/dict.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __dict_list_h_ -#define __dict_list_h_ - -/* Use #define's so that another heap implementation can use this one */ - -#define DictKey DictListKey -#define Dict DictList -#define DictNode DictListNode - -#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq) -#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict) - -#define dictSearch(dict,key) __gl_dictListSearch(dict,key) -#define dictInsert(dict,key) __gl_dictListInsert(dict,key) -#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key) -#define dictDelete(dict,node) __gl_dictListDelete(dict,node) - -#define dictKey(n) __gl_dictListKey(n) -#define dictSucc(n) __gl_dictListSucc(n) -#define dictPred(n) __gl_dictListPred(n) -#define dictMin(d) __gl_dictListMin(d) -#define dictMax(d) __gl_dictListMax(d) - - - -typedef void *DictKey; -typedef struct Dict Dict; -typedef struct DictNode DictNode; - -Dict *dictNewDict( - void *frame, - int (*leq)(void *frame, DictKey key1, DictKey key2) ); - -void dictDeleteDict( Dict *dict ); - -/* Search returns the node with the smallest key greater than or equal - * to the given key. If there is no such key, returns a node whose - * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc. - */ -DictNode *dictSearch( Dict *dict, DictKey key ); -DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key ); -void dictDelete( Dict *dict, DictNode *node ); - -#define __gl_dictListKey(n) ((n)->key) -#define __gl_dictListSucc(n) ((n)->next) -#define __gl_dictListPred(n) ((n)->prev) -#define __gl_dictListMin(d) ((d)->head.next) -#define __gl_dictListMax(d) ((d)->head.prev) -#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k))) - - -/*** Private data structures ***/ - -struct DictNode { - DictKey key; - DictNode *next; - DictNode *prev; -}; - -struct Dict { - DictNode head; - void *frame; - int (*leq)(void *frame, DictKey key1, DictKey key2); -}; - -#endif diff --git a/GLU/geom.c b/GLU/geom.c deleted file mode 100644 index 7d3b8d8..0000000 --- a/GLU/geom.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#include "gluos.h" -#include -#include "mesh.h" -#include "geom.h" - -int __gl_vertLeq( GLUvertex *u, GLUvertex *v ) -{ - /* Returns TRUE if u is lexicographically <= v. */ - - return VertLeq( u, v ); -} - -GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ) -{ - /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w), - * evaluates the t-coord of the edge uw at the s-coord of the vertex v. - * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v. - * If uw is vertical (and thus passes thru v), the result is zero. - * - * The calculation is extremely accurate and stable, even when v - * is very close to u or w. In particular if we set v->t = 0 and - * let r be the negated result (this evaluates (uw)(v->s)), then - * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t). - */ - GLdouble gapL, gapR; - - assert( VertLeq( u, v ) && VertLeq( v, w )); - - gapL = v->s - u->s; - gapR = w->s - v->s; - - if( gapL + gapR > 0 ) { - if( gapL < gapR ) { - return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR)); - } else { - return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR)); - } - } - /* vertical line */ - return 0; -} - -GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ) -{ - /* Returns a number whose sign matches EdgeEval(u,v,w) but which - * is cheaper to evaluate. Returns > 0, == 0 , or < 0 - * as v is above, on, or below the edge uw. - */ - GLdouble gapL, gapR; - - assert( VertLeq( u, v ) && VertLeq( v, w )); - - gapL = v->s - u->s; - gapR = w->s - v->s; - - if( gapL + gapR > 0 ) { - return (v->t - w->t) * gapL + (v->t - u->t) * gapR; - } - /* vertical line */ - return 0; -} - - -/*********************************************************************** - * Define versions of EdgeSign, EdgeEval with s and t transposed. - */ - -GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ) -{ - /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w), - * evaluates the t-coord of the edge uw at the s-coord of the vertex v. - * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v. - * If uw is vertical (and thus passes thru v), the result is zero. - * - * The calculation is extremely accurate and stable, even when v - * is very close to u or w. In particular if we set v->s = 0 and - * let r be the negated result (this evaluates (uw)(v->t)), then - * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s). - */ - GLdouble gapL, gapR; - - assert( TransLeq( u, v ) && TransLeq( v, w )); - - gapL = v->t - u->t; - gapR = w->t - v->t; - - if( gapL + gapR > 0 ) { - if( gapL < gapR ) { - return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR)); - } else { - return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR)); - } - } - /* vertical line */ - return 0; -} - -GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ) -{ - /* Returns a number whose sign matches TransEval(u,v,w) but which - * is cheaper to evaluate. Returns > 0, == 0 , or < 0 - * as v is above, on, or below the edge uw. - */ - GLdouble gapL, gapR; - - assert( TransLeq( u, v ) && TransLeq( v, w )); - - gapL = v->t - u->t; - gapR = w->t - v->t; - - if( gapL + gapR > 0 ) { - return (v->s - w->s) * gapL + (v->s - u->s) * gapR; - } - /* vertical line */ - return 0; -} - - -int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w ) -{ - /* For almost-degenerate situations, the results are not reliable. - * Unless the floating-point arithmetic can be performed without - * rounding errors, *any* implementation will give incorrect results - * on some degenerate inputs, so the client must have some way to - * handle this situation. - */ - return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0; -} - -/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b), - * or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces - * this in the rare case that one argument is slightly negative. - * The implementation is extremely stable numerically. - * In particular it guarantees that the result r satisfies - * MIN(x,y) <= r <= MAX(x,y), and the results are very accurate - * even when a and b differ greatly in magnitude. - */ -#define RealInterpolate(a,x,b,y) \ - (a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \ - ((a <= b) ? ((b == 0) ? ((x+y) / 2) \ - : (x + (y-x) * (a/(a+b)))) \ - : (y + (x-y) * (b/(a+b))))) - -#ifndef FOR_TRITE_TEST_PROGRAM -#define Interpolate(a,x,b,y) RealInterpolate(a,x,b,y) -#else - -/* Claim: the ONLY property the sweep algorithm relies on is that - * MIN(x,y) <= r <= MAX(x,y). This is a nasty way to test that. - */ -#include -extern int RandomInterpolate; - -GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y) -{ -printf("*********************%d\n",RandomInterpolate); - if( RandomInterpolate ) { - a = 1.2 * drand48() - 0.1; - a = (a < 0) ? 0 : ((a > 1) ? 1 : a); - b = 1.0 - a; - } - return RealInterpolate(a,x,b,y); -} - -#endif - -#define Swap(a,b) if (1) { GLUvertex *t = a; a = b; b = t; } else - -void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1, - GLUvertex *o2, GLUvertex *d2, - GLUvertex *v ) -/* Given edges (o1,d1) and (o2,d2), compute their point of intersection. - * The computed point is guaranteed to lie in the intersection of the - * bounding rectangles defined by each edge. - */ -{ - GLdouble z1, z2; - - /* This is certainly not the most efficient way to find the intersection - * of two line segments, but it is very numerically stable. - * - * Strategy: find the two middle vertices in the VertLeq ordering, - * and interpolate the intersection s-value from these. Then repeat - * using the TransLeq ordering to find the intersection t-value. - */ - - if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); } - if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); } - if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); } - - if( ! VertLeq( o2, d1 )) { - /* Technically, no intersection -- do our best */ - v->s = (o2->s + d1->s) / 2; - } else if( VertLeq( d1, d2 )) { - /* Interpolate between o2 and d1 */ - z1 = EdgeEval( o1, o2, d1 ); - z2 = EdgeEval( o2, d1, d2 ); - if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } - v->s = Interpolate( z1, o2->s, z2, d1->s ); - } else { - /* Interpolate between o2 and d2 */ - z1 = EdgeSign( o1, o2, d1 ); - z2 = -EdgeSign( o1, d2, d1 ); - if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } - v->s = Interpolate( z1, o2->s, z2, d2->s ); - } - - /* Now repeat the process for t */ - - if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); } - if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); } - if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); } - - if( ! TransLeq( o2, d1 )) { - /* Technically, no intersection -- do our best */ - v->t = (o2->t + d1->t) / 2; - } else if( TransLeq( d1, d2 )) { - /* Interpolate between o2 and d1 */ - z1 = TransEval( o1, o2, d1 ); - z2 = TransEval( o2, d1, d2 ); - if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } - v->t = Interpolate( z1, o2->t, z2, d1->t ); - } else { - /* Interpolate between o2 and d2 */ - z1 = TransSign( o1, o2, d1 ); - z2 = -TransSign( o1, d2, d1 ); - if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; } - v->t = Interpolate( z1, o2->t, z2, d2->t ); - } -} diff --git a/GLU/geom.h b/GLU/geom.h deleted file mode 100644 index 5cb76c7..0000000 --- a/GLU/geom.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __geom_h_ -#define __geom_h_ - -#include "mesh.h" - -#ifdef NO_BRANCH_CONDITIONS -/* MIPS architecture has special instructions to evaluate boolean - * conditions -- more efficient than branching, IF you can get the - * compiler to generate the right instructions (SGI compiler doesn't) - */ -#define VertEq(u,v) (((u)->s == (v)->s) & ((u)->t == (v)->t)) -#define VertLeq(u,v) (((u)->s < (v)->s) | \ - ((u)->s == (v)->s & (u)->t <= (v)->t)) -#else -#define VertEq(u,v) ((u)->s == (v)->s && (u)->t == (v)->t) -#define VertLeq(u,v) (((u)->s < (v)->s) || \ - ((u)->s == (v)->s && (u)->t <= (v)->t)) -#endif - -#define EdgeEval(u,v,w) __gl_edgeEval(u,v,w) -#define EdgeSign(u,v,w) __gl_edgeSign(u,v,w) - -/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */ - -#define TransLeq(u,v) (((u)->t < (v)->t) || \ - ((u)->t == (v)->t && (u)->s <= (v)->s)) -#define TransEval(u,v,w) __gl_transEval(u,v,w) -#define TransSign(u,v,w) __gl_transSign(u,v,w) - - -#define EdgeGoesLeft(e) VertLeq( (e)->Dst, (e)->Org ) -#define EdgeGoesRight(e) VertLeq( (e)->Org, (e)->Dst ) - -#undef ABS -#define ABS(x) ((x) < 0 ? -(x) : (x)) -#define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t)) - -#define VertCCW(u,v,w) __gl_vertCCW(u,v,w) - -int __gl_vertLeq( GLUvertex *u, GLUvertex *v ); -GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ); -GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ); -GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w ); -GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w ); -int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w ); -void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1, - GLUvertex *o2, GLUvertex *d2, - GLUvertex *v ); - -#endif diff --git a/GLU/gluos.h b/GLU/gluos.h deleted file mode 100644 index 8eaa7a1..0000000 --- a/GLU/gluos.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -** gluos.h - operating system dependencies for GLU -** -*/ -#ifdef __VMS -#ifdef __cplusplus -#pragma message disable nocordel -#pragma message disable codeunreachable -#pragma message disable codcauunr -#endif -#endif - -#ifdef __WATCOMC__ -/* Disable *lots* of warnings to get a clean build. I can't be bothered fixing the - * code at the moment, as it is pretty ugly. - */ -#pragma warning 7 10 -#pragma warning 13 10 -#pragma warning 14 10 -#pragma warning 367 10 -#pragma warning 379 10 -#pragma warning 726 10 -#pragma warning 836 10 -#endif - -#ifdef BUILD_FOR_SNAP - -#include -#include -#include - -#elif defined(_WIN32) - -#include /* For _MAX_PATH definition */ -#include -#include - -#define WIN32_LEAN_AND_MEAN -#define NOGDI -#define NOIME -#define NOMINMAX - -#define _WIN32_WINNT 0x0400 -#ifndef STRICT - #define STRICT 1 -#endif - -#include - -/* Disable warnings */ -#pragma warning(disable : 4101) -#pragma warning(disable : 4244) -#pragma warning(disable : 4761) - -#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1300 -#pragma comment(linker, "/OPT:NOWIN98") -#endif - -#elif defined(__OS2__) - -#include -#include -#include -#define WINGDIAPI - -#else - -/* Disable Microsoft-specific keywords */ -#define GLAPIENTRY -#define WINGDIAPI - -#endif diff --git a/GLU/memalloc.c b/GLU/memalloc.c deleted file mode 100644 index 81879ef..0000000 --- a/GLU/memalloc.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#include "memalloc.h" -#include "string.h" - -int __gl_memInit( size_t maxFast ) -{ -#ifndef NO_MALLOPT -/* mallopt( M_MXFAST, maxFast );*/ -#ifdef MEMORY_DEBUG - mallopt( M_DEBUG, 1 ); -#endif -#endif - return 1; -} - -#ifdef MEMORY_DEBUG -void *__gl_memAlloc( size_t n ) -{ - return memset( malloc( n ), 0xa5, n ); -} -#endif - diff --git a/GLU/memalloc.h b/GLU/memalloc.h deleted file mode 100644 index c2f969b..0000000 --- a/GLU/memalloc.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __memalloc_simple_h_ -#define __memalloc_simple_h_ - -#include - -#define memRealloc realloc -#define memFree free - -#define memInit __gl_memInit -/*extern void __gl_memInit( size_t );*/ -extern int __gl_memInit( size_t ); - -#ifndef MEMORY_DEBUG -#define memAlloc malloc -#else -#define memAlloc __gl_memAlloc -extern void * __gl_memAlloc( size_t ); -#endif - -#endif diff --git a/GLU/mesh.c b/GLU/mesh.c deleted file mode 100644 index ae861f8..0000000 --- a/GLU/mesh.c +++ /dev/null @@ -1,789 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#include "gluos.h" -#include -#include -#include "mesh.h" -#include "memalloc.h" - -#define TRUE 1 -#define FALSE 0 - -static GLUvertex *allocVertex() -{ - return (GLUvertex *)memAlloc( sizeof( GLUvertex )); -} - -static GLUface *allocFace() -{ - return (GLUface *)memAlloc( sizeof( GLUface )); -} - -/************************ Utility Routines ************************/ - -/* Allocate and free half-edges in pairs for efficiency. - * The *only* place that should use this fact is allocation/free. - */ -typedef struct { GLUhalfEdge e, eSym; } EdgePair; - -/* MakeEdge creates a new pair of half-edges which form their own loop. - * No vertex or face structures are allocated, but these must be assigned - * before the current edge operation is completed. - */ -static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext ) -{ - GLUhalfEdge *e; - GLUhalfEdge *eSym; - GLUhalfEdge *ePrev; - EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair )); - if (pair == NULL) return NULL; - - e = &pair->e; - eSym = &pair->eSym; - - /* Make sure eNext points to the first edge of the edge pair */ - if( eNext->Sym < eNext ) { eNext = eNext->Sym; } - - /* Insert in circular doubly-linked list before eNext. - * Note that the prev pointer is stored in Sym->next. - */ - ePrev = eNext->Sym->next; - eSym->next = ePrev; - ePrev->Sym->next = e; - e->next = eNext; - eNext->Sym->next = eSym; - - e->Sym = eSym; - e->Onext = e; - e->Lnext = eSym; - e->Org = NULL; - e->Lface = NULL; - e->winding = 0; - e->activeRegion = NULL; - - eSym->Sym = e; - eSym->Onext = eSym; - eSym->Lnext = e; - eSym->Org = NULL; - eSym->Lface = NULL; - eSym->winding = 0; - eSym->activeRegion = NULL; - - return e; -} - -/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the - * CS348a notes (see mesh.h). Basically it modifies the mesh so that - * a->Onext and b->Onext are exchanged. This can have various effects - * depending on whether a and b belong to different face or vertex rings. - * For more explanation see __gl_meshSplice() below. - */ -static void Splice( GLUhalfEdge *a, GLUhalfEdge *b ) -{ - GLUhalfEdge *aOnext = a->Onext; - GLUhalfEdge *bOnext = b->Onext; - - aOnext->Sym->Lnext = b; - bOnext->Sym->Lnext = a; - a->Onext = bOnext; - b->Onext = aOnext; -} - -/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the - * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives - * a place to insert the new vertex in the global vertex list. We insert - * the new vertex *before* vNext so that algorithms which walk the vertex - * list will not see the newly created vertices. - */ -static void MakeVertex( GLUvertex *newVertex, - GLUhalfEdge *eOrig, GLUvertex *vNext ) -{ - GLUhalfEdge *e; - GLUvertex *vPrev; - GLUvertex *vNew = newVertex; - - assert(vNew != NULL); - - /* insert in circular doubly-linked list before vNext */ - vPrev = vNext->prev; - vNew->prev = vPrev; - vPrev->next = vNew; - vNew->next = vNext; - vNext->prev = vNew; - - vNew->anEdge = eOrig; - vNew->data = NULL; - /* leave coords, s, t undefined */ - - /* fix other edges on this vertex loop */ - e = eOrig; - do { - e->Org = vNew; - e = e->Onext; - } while( e != eOrig ); -} - -/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left - * face of all edges in the face loop to which eOrig belongs. "fNext" gives - * a place to insert the new face in the global face list. We insert - * the new face *before* fNext so that algorithms which walk the face - * list will not see the newly created faces. - */ -static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext ) -{ - GLUhalfEdge *e; - GLUface *fPrev; - GLUface *fNew = newFace; - - assert(fNew != NULL); - - /* insert in circular doubly-linked list before fNext */ - fPrev = fNext->prev; - fNew->prev = fPrev; - fPrev->next = fNew; - fNew->next = fNext; - fNext->prev = fNew; - - fNew->anEdge = eOrig; - fNew->data = NULL; - fNew->trail = NULL; - fNew->marked = FALSE; - - /* The new face is marked "inside" if the old one was. This is a - * convenience for the common case where a face has been split in two. - */ - fNew->inside = fNext->inside; - - /* fix other edges on this face loop */ - e = eOrig; - do { - e->Lface = fNew; - e = e->Lnext; - } while( e != eOrig ); -} - -/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym), - * and removes from the global edge list. - */ -static void KillEdge( GLUhalfEdge *eDel ) -{ - GLUhalfEdge *ePrev, *eNext; - - /* Half-edges are allocated in pairs, see EdgePair above */ - if( eDel->Sym < eDel ) { eDel = eDel->Sym; } - - /* delete from circular doubly-linked list */ - eNext = eDel->next; - ePrev = eDel->Sym->next; - eNext->Sym->next = ePrev; - ePrev->Sym->next = eNext; - - memFree( eDel ); -} - - -/* KillVertex( vDel ) destroys a vertex and removes it from the global - * vertex list. It updates the vertex loop to point to a given new vertex. - */ -static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg ) -{ - GLUhalfEdge *e, *eStart = vDel->anEdge; - GLUvertex *vPrev, *vNext; - - /* change the origin of all affected edges */ - e = eStart; - do { - e->Org = newOrg; - e = e->Onext; - } while( e != eStart ); - - /* delete from circular doubly-linked list */ - vPrev = vDel->prev; - vNext = vDel->next; - vNext->prev = vPrev; - vPrev->next = vNext; - - memFree( vDel ); -} - -/* KillFace( fDel ) destroys a face and removes it from the global face - * list. It updates the face loop to point to a given new face. - */ -static void KillFace( GLUface *fDel, GLUface *newLface ) -{ - GLUhalfEdge *e, *eStart = fDel->anEdge; - GLUface *fPrev, *fNext; - - /* change the left face of all affected edges */ - e = eStart; - do { - e->Lface = newLface; - e = e->Lnext; - } while( e != eStart ); - - /* delete from circular doubly-linked list */ - fPrev = fDel->prev; - fNext = fDel->next; - fNext->prev = fPrev; - fPrev->next = fNext; - - memFree( fDel ); -} - - -/****************** Basic Edge Operations **********************/ - -/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face). - * The loop consists of the two new half-edges. - */ -GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh ) -{ - GLUvertex *newVertex1= allocVertex(); - GLUvertex *newVertex2= allocVertex(); - GLUface *newFace= allocFace(); - GLUhalfEdge *e; - - /* if any one is null then all get freed */ - if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) { - if (newVertex1 != NULL) memFree(newVertex1); - if (newVertex2 != NULL) memFree(newVertex2); - if (newFace != NULL) memFree(newFace); - return NULL; - } - - e = MakeEdge( &mesh->eHead ); - if (e == NULL) return NULL; - - MakeVertex( newVertex1, e, &mesh->vHead ); - MakeVertex( newVertex2, e->Sym, &mesh->vHead ); - MakeFace( newFace, e, &mesh->fHead ); - return e; -} - - -/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the - * mesh connectivity and topology. It changes the mesh so that - * eOrg->Onext <- OLD( eDst->Onext ) - * eDst->Onext <- OLD( eOrg->Onext ) - * where OLD(...) means the value before the meshSplice operation. - * - * This can have two effects on the vertex structure: - * - if eOrg->Org != eDst->Org, the two vertices are merged together - * - if eOrg->Org == eDst->Org, the origin is split into two vertices - * In both cases, eDst->Org is changed and eOrg->Org is untouched. - * - * Similarly (and independently) for the face structure, - * - if eOrg->Lface == eDst->Lface, one loop is split into two - * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one - * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. - * - * Some special cases: - * If eDst == eOrg, the operation has no effect. - * If eDst == eOrg->Lnext, the new face will have a single edge. - * If eDst == eOrg->Lprev, the old face will have a single edge. - * If eDst == eOrg->Onext, the new vertex will have a single edge. - * If eDst == eOrg->Oprev, the old vertex will have a single edge. - */ -int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ) -{ - int joiningLoops = FALSE; - int joiningVertices = FALSE; - - if( eOrg == eDst ) return 1; - - if( eDst->Org != eOrg->Org ) { - /* We are merging two disjoint vertices -- destroy eDst->Org */ - joiningVertices = TRUE; - KillVertex( eDst->Org, eOrg->Org ); - } - if( eDst->Lface != eOrg->Lface ) { - /* We are connecting two disjoint loops -- destroy eDst->Lface */ - joiningLoops = TRUE; - KillFace( eDst->Lface, eOrg->Lface ); - } - - /* Change the edge structure */ - Splice( eDst, eOrg ); - - if( ! joiningVertices ) { - GLUvertex *newVertex= allocVertex(); - if (newVertex == NULL) return 0; - - /* We split one vertex into two -- the new vertex is eDst->Org. - * Make sure the old vertex points to a valid half-edge. - */ - MakeVertex( newVertex, eDst, eOrg->Org ); - eOrg->Org->anEdge = eOrg; - } - if( ! joiningLoops ) { - GLUface *newFace= allocFace(); - if (newFace == NULL) return 0; - - /* We split one loop into two -- the new loop is eDst->Lface. - * Make sure the old face points to a valid half-edge. - */ - MakeFace( newFace, eDst, eOrg->Lface ); - eOrg->Lface->anEdge = eOrg; - } - - return 1; -} - - -/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases: - * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop - * eDel->Lface is deleted. Otherwise, we are splitting one loop into two; - * the newly created loop will contain eDel->Dst. If the deletion of eDel - * would create isolated vertices, those are deleted as well. - * - * This function could be implemented as two calls to __gl_meshSplice - * plus a few calls to memFree, but this would allocate and delete - * unnecessary vertices and faces. - */ -int __gl_meshDelete( GLUhalfEdge *eDel ) -{ - GLUhalfEdge *eDelSym = eDel->Sym; - int joiningLoops = FALSE; - - /* First step: disconnect the origin vertex eDel->Org. We make all - * changes to get a consistent mesh in this "intermediate" state. - */ - if( eDel->Lface != eDel->Rface ) { - /* We are joining two loops into one -- remove the left face */ - joiningLoops = TRUE; - KillFace( eDel->Lface, eDel->Rface ); - } - - if( eDel->Onext == eDel ) { - KillVertex( eDel->Org, NULL ); - } else { - /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */ - eDel->Rface->anEdge = eDel->Oprev; - eDel->Org->anEdge = eDel->Onext; - - Splice( eDel, eDel->Oprev ); - if( ! joiningLoops ) { - GLUface *newFace= allocFace(); - if (newFace == NULL) return 0; - - /* We are splitting one loop into two -- create a new loop for eDel. */ - MakeFace( newFace, eDel, eDel->Lface ); - } - } - - /* Claim: the mesh is now in a consistent state, except that eDel->Org - * may have been deleted. Now we disconnect eDel->Dst. - */ - if( eDelSym->Onext == eDelSym ) { - KillVertex( eDelSym->Org, NULL ); - KillFace( eDelSym->Lface, NULL ); - } else { - /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */ - eDel->Lface->anEdge = eDelSym->Oprev; - eDelSym->Org->anEdge = eDelSym->Onext; - Splice( eDelSym, eDelSym->Oprev ); - } - - /* Any isolated vertices or faces have already been freed. */ - KillEdge( eDel ); - - return 1; -} - - -/******************** Other Edge Operations **********************/ - -/* All these routines can be implemented with the basic edge - * operations above. They are provided for convenience and efficiency. - */ - - -/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that - * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. - * eOrg and eNew will have the same left face. - */ -GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg ) -{ - GLUhalfEdge *eNewSym; - GLUhalfEdge *eNew = MakeEdge( eOrg ); - if (eNew == NULL) return NULL; - - eNewSym = eNew->Sym; - - /* Connect the new edge appropriately */ - Splice( eNew, eOrg->Lnext ); - - /* Set the vertex and face information */ - eNew->Org = eOrg->Dst; - { - GLUvertex *newVertex= allocVertex(); - if (newVertex == NULL) return NULL; - - MakeVertex( newVertex, eNewSym, eNew->Org ); - } - eNew->Lface = eNewSym->Lface = eOrg->Lface; - - return eNew; -} - - -/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew, - * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org. - * eOrg and eNew will have the same left face. - */ -GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg ) -{ - GLUhalfEdge *eNew; - GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg ); - if (tempHalfEdge == NULL) return NULL; - - eNew = tempHalfEdge->Sym; - - /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */ - Splice( eOrg->Sym, eOrg->Sym->Oprev ); - Splice( eOrg->Sym, eNew ); - - /* Set the vertex and face information */ - eOrg->Dst = eNew->Org; - eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */ - eNew->Rface = eOrg->Rface; - eNew->winding = eOrg->winding; /* copy old winding information */ - eNew->Sym->winding = eOrg->Sym->winding; - - return eNew; -} - - -/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst - * to eDst->Org, and returns the corresponding half-edge eNew. - * If eOrg->Lface == eDst->Lface, this splits one loop into two, - * and the newly created loop is eNew->Lface. Otherwise, two disjoint - * loops are merged into one, and the loop eDst->Lface is destroyed. - * - * If (eOrg == eDst), the new face will have only two edges. - * If (eOrg->Lnext == eDst), the old face is reduced to a single edge. - * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges. - */ -GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ) -{ - GLUhalfEdge *eNewSym; - int joiningLoops = FALSE; - GLUhalfEdge *eNew = MakeEdge( eOrg ); - if (eNew == NULL) return NULL; - - eNewSym = eNew->Sym; - - if( eDst->Lface != eOrg->Lface ) { - /* We are connecting two disjoint loops -- destroy eDst->Lface */ - joiningLoops = TRUE; - KillFace( eDst->Lface, eOrg->Lface ); - } - - /* Connect the new edge appropriately */ - Splice( eNew, eOrg->Lnext ); - Splice( eNewSym, eDst ); - - /* Set the vertex and face information */ - eNew->Org = eOrg->Dst; - eNewSym->Org = eDst->Org; - eNew->Lface = eNewSym->Lface = eOrg->Lface; - - /* Make sure the old face points to a valid half-edge */ - eOrg->Lface->anEdge = eNewSym; - - if( ! joiningLoops ) { - GLUface *newFace= allocFace(); - if (newFace == NULL) return NULL; - - /* We split one loop into two -- the new loop is eNew->Lface */ - MakeFace( newFace, eNew, eOrg->Lface ); - } - return eNew; -} - - -/******************** Other Operations **********************/ - -/* __gl_meshZapFace( fZap ) destroys a face and removes it from the - * global face list. All edges of fZap will have a NULL pointer as their - * left face. Any edges which also have a NULL pointer as their right face - * are deleted entirely (along with any isolated vertices this produces). - * An entire mesh can be deleted by zapping its faces, one at a time, - * in any order. Zapped faces cannot be used in further mesh operations! - */ -void __gl_meshZapFace( GLUface *fZap ) -{ - GLUhalfEdge *eStart = fZap->anEdge; - GLUhalfEdge *e, *eNext, *eSym; - GLUface *fPrev, *fNext; - - /* walk around face, deleting edges whose right face is also NULL */ - eNext = eStart->Lnext; - do { - e = eNext; - eNext = e->Lnext; - - e->Lface = NULL; - if( e->Rface == NULL ) { - /* delete the edge -- see __gl_MeshDelete above */ - - if( e->Onext == e ) { - KillVertex( e->Org, NULL ); - } else { - /* Make sure that e->Org points to a valid half-edge */ - e->Org->anEdge = e->Onext; - Splice( e, e->Oprev ); - } - eSym = e->Sym; - if( eSym->Onext == eSym ) { - KillVertex( eSym->Org, NULL ); - } else { - /* Make sure that eSym->Org points to a valid half-edge */ - eSym->Org->anEdge = eSym->Onext; - Splice( eSym, eSym->Oprev ); - } - KillEdge( e ); - } - } while( e != eStart ); - - /* delete from circular doubly-linked list */ - fPrev = fZap->prev; - fNext = fZap->next; - fNext->prev = fPrev; - fPrev->next = fNext; - - memFree( fZap ); -} - - -/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices, - * and no loops (what we usually call a "face"). - */ -GLUmesh *__gl_meshNewMesh( void ) -{ - GLUvertex *v; - GLUface *f; - GLUhalfEdge *e; - GLUhalfEdge *eSym; - GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh )); - if (mesh == NULL) { - return NULL; - } - - v = &mesh->vHead; - f = &mesh->fHead; - e = &mesh->eHead; - eSym = &mesh->eHeadSym; - - v->next = v->prev = v; - v->anEdge = NULL; - v->data = NULL; - - f->next = f->prev = f; - f->anEdge = NULL; - f->data = NULL; - f->trail = NULL; - f->marked = FALSE; - f->inside = FALSE; - - e->next = e; - e->Sym = eSym; - e->Onext = NULL; - e->Lnext = NULL; - e->Org = NULL; - e->Lface = NULL; - e->winding = 0; - e->activeRegion = NULL; - - eSym->next = eSym; - eSym->Sym = e; - eSym->Onext = NULL; - eSym->Lnext = NULL; - eSym->Org = NULL; - eSym->Lface = NULL; - eSym->winding = 0; - eSym->activeRegion = NULL; - - return mesh; -} - - -/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in - * both meshes, and returns the new mesh (the old meshes are destroyed). - */ -GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 ) -{ - GLUface *f1 = &mesh1->fHead; - GLUvertex *v1 = &mesh1->vHead; - GLUhalfEdge *e1 = &mesh1->eHead; - GLUface *f2 = &mesh2->fHead; - GLUvertex *v2 = &mesh2->vHead; - GLUhalfEdge *e2 = &mesh2->eHead; - - /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */ - if( f2->next != f2 ) { - f1->prev->next = f2->next; - f2->next->prev = f1->prev; - f2->prev->next = f1; - f1->prev = f2->prev; - } - - if( v2->next != v2 ) { - v1->prev->next = v2->next; - v2->next->prev = v1->prev; - v2->prev->next = v1; - v1->prev = v2->prev; - } - - if( e2->next != e2 ) { - e1->Sym->next->Sym->next = e2->next; - e2->next->Sym->next = e1->Sym->next; - e2->Sym->next->Sym->next = e1; - e1->Sym->next = e2->Sym->next; - } - - memFree( mesh2 ); - return mesh1; -} - - -#ifdef DELETE_BY_ZAPPING - -/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. - */ -void __gl_meshDeleteMesh( GLUmesh *mesh ) -{ - GLUface *fHead = &mesh->fHead; - - while( fHead->next != fHead ) { - __gl_meshZapFace( fHead->next ); - } - assert( mesh->vHead.next == &mesh->vHead ); - - memFree( mesh ); -} - -#else - -/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. - */ -void __gl_meshDeleteMesh( GLUmesh *mesh ) -{ - GLUface *f, *fNext; - GLUvertex *v, *vNext; - GLUhalfEdge *e, *eNext; - - for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) { - fNext = f->next; - memFree( f ); - } - - for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) { - vNext = v->next; - memFree( v ); - } - - for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) { - /* One call frees both e and e->Sym (see EdgePair above) */ - eNext = e->next; - memFree( e ); - } - - memFree( mesh ); -} - -#endif - -#ifndef NDEBUG - -/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency. - */ -void __gl_meshCheckMesh( GLUmesh *mesh ) -{ - GLUface *fHead = &mesh->fHead; - GLUvertex *vHead = &mesh->vHead; - GLUhalfEdge *eHead = &mesh->eHead; - GLUface *f, *fPrev; - GLUvertex *v, *vPrev; - GLUhalfEdge *e, *ePrev; - - fPrev = fHead; - for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) { - assert( f->prev == fPrev ); - e = f->anEdge; - do { - assert( e->Sym != e ); - assert( e->Sym->Sym == e ); - assert( e->Lnext->Onext->Sym == e ); - assert( e->Onext->Sym->Lnext == e ); - assert( e->Lface == f ); - e = e->Lnext; - } while( e != f->anEdge ); - } - assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL ); - - vPrev = vHead; - for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) { - assert( v->prev == vPrev ); - e = v->anEdge; - do { - assert( e->Sym != e ); - assert( e->Sym->Sym == e ); - assert( e->Lnext->Onext->Sym == e ); - assert( e->Onext->Sym->Lnext == e ); - assert( e->Org == v ); - e = e->Onext; - } while( e != v->anEdge ); - } - assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL ); - - ePrev = eHead; - for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) { - assert( e->Sym->next == ePrev->Sym ); - assert( e->Sym != e ); - assert( e->Sym->Sym == e ); - assert( e->Org != NULL ); - assert( e->Dst != NULL ); - assert( e->Lnext->Onext->Sym == e ); - assert( e->Onext->Sym->Lnext == e ); - } - assert( e->Sym->next == ePrev->Sym - && e->Sym == &mesh->eHeadSym - && e->Sym->Sym == e - && e->Org == NULL && e->Dst == NULL - && e->Lface == NULL && e->Rface == NULL ); -} - -#endif diff --git a/GLU/mesh.h b/GLU/mesh.h deleted file mode 100644 index 690c5f2..0000000 --- a/GLU/mesh.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __mesh_h_ -#define __mesh_h_ - -#include - -typedef struct GLUmesh GLUmesh; - -typedef struct GLUvertex GLUvertex; -typedef struct GLUface GLUface; -typedef struct GLUhalfEdge GLUhalfEdge; - -typedef struct ActiveRegion ActiveRegion; /* Internal data */ - -/* The mesh structure is similar in spirit, notation, and operations - * to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives - * for the manipulation of general subdivisions and the computation of - * Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985). - * For a simplified description, see the course notes for CS348a, - * "Mathematical Foundations of Computer Graphics", available at the - * Stanford bookstore (and taught during the fall quarter). - * The implementation also borrows a tiny subset of the graph-based approach - * use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction - * to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988). - * - * The fundamental data structure is the "half-edge". Two half-edges - * go together to make an edge, but they point in opposite directions. - * Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym), - * its origin vertex (Org), the face on its left side (Lface), and the - * adjacent half-edges in the CCW direction around the origin vertex - * (Onext) and around the left face (Lnext). There is also a "next" - * pointer for the global edge list (see below). - * - * The notation used for mesh navigation: - * Sym = the mate of a half-edge (same edge, but opposite direction) - * Onext = edge CCW around origin vertex (keep same origin) - * Dnext = edge CCW around destination vertex (keep same dest) - * Lnext = edge CCW around left face (dest becomes new origin) - * Rnext = edge CCW around right face (origin becomes new dest) - * - * "prev" means to substitute CW for CCW in the definitions above. - * - * The mesh keeps global lists of all vertices, faces, and edges, - * stored as doubly-linked circular lists with a dummy header node. - * The mesh stores pointers to these dummy headers (vHead, fHead, eHead). - * - * The circular edge list is special; since half-edges always occur - * in pairs (e and e->Sym), each half-edge stores a pointer in only - * one direction. Starting at eHead and following the e->next pointers - * will visit each *edge* once (ie. e or e->Sym, but not both). - * e->Sym stores a pointer in the opposite direction, thus it is - * always true that e->Sym->next->Sym->next == e. - * - * Each vertex has a pointer to next and previous vertices in the - * circular list, and a pointer to a half-edge with this vertex as - * the origin (NULL if this is the dummy header). There is also a - * field "data" for client data. - * - * Each face has a pointer to the next and previous faces in the - * circular list, and a pointer to a half-edge with this face as - * the left face (NULL if this is the dummy header). There is also - * a field "data" for client data. - * - * Note that what we call a "face" is really a loop; faces may consist - * of more than one loop (ie. not simply connected), but there is no - * record of this in the data structure. The mesh may consist of - * several disconnected regions, so it may not be possible to visit - * the entire mesh by starting at a half-edge and traversing the edge - * structure. - * - * The mesh does NOT support isolated vertices; a vertex is deleted along - * with its last edge. Similarly when two faces are merged, one of the - * faces is deleted (see __gl_meshDelete below). For mesh operations, - * all face (loop) and vertex pointers must not be NULL. However, once - * mesh manipulation is finished, __gl_MeshZapFace can be used to delete - * faces of the mesh, one at a time. All external faces can be "zapped" - * before the mesh is returned to the client; then a NULL face indicates - * a region which is not part of the output polygon. - */ - -struct GLUvertex { - GLUvertex *next; /* next vertex (never NULL) */ - GLUvertex *prev; /* previous vertex (never NULL) */ - GLUhalfEdge *anEdge; /* a half-edge with this origin */ - void *data; /* client's data */ - - /* Internal data (keep hidden) */ - GLdouble coords[3]; /* vertex location in 3D */ - GLdouble s, t; /* projection onto the sweep plane */ - long pqHandle; /* to allow deletion from priority queue */ -}; - -struct GLUface { - GLUface *next; /* next face (never NULL) */ - GLUface *prev; /* previous face (never NULL) */ - GLUhalfEdge *anEdge; /* a half edge with this left face */ - void *data; /* room for client's data */ - - /* Internal data (keep hidden) */ - GLUface *trail; /* "stack" for conversion to strips */ - GLboolean marked; /* flag for conversion to strips */ - GLboolean inside; /* this face is in the polygon interior */ -}; - -struct GLUhalfEdge { - GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */ - GLUhalfEdge *Sym; /* same edge, opposite direction */ - GLUhalfEdge *Onext; /* next edge CCW around origin */ - GLUhalfEdge *Lnext; /* next edge CCW around left face */ - GLUvertex *Org; /* origin vertex (Overtex too long) */ - GLUface *Lface; /* left face */ - - /* Internal data (keep hidden) */ - ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */ - int winding; /* change in winding number when crossing - from the right face to the left face */ -}; - -#define Rface Sym->Lface -#define Dst Sym->Org - -#define Oprev Sym->Lnext -#define Lprev Onext->Sym -#define Dprev Lnext->Sym -#define Rprev Sym->Onext -#define Dnext Rprev->Sym /* 3 pointers */ -#define Rnext Oprev->Sym /* 3 pointers */ - - -struct GLUmesh { - GLUvertex vHead; /* dummy header for vertex list */ - GLUface fHead; /* dummy header for face list */ - GLUhalfEdge eHead; /* dummy header for edge list */ - GLUhalfEdge eHeadSym; /* and its symmetric counterpart */ -}; - -/* The mesh operations below have three motivations: completeness, - * convenience, and efficiency. The basic mesh operations are MakeEdge, - * Splice, and Delete. All the other edge operations can be implemented - * in terms of these. The other operations are provided for convenience - * and/or efficiency. - * - * When a face is split or a vertex is added, they are inserted into the - * global list *before* the existing vertex or face (ie. e->Org or e->Lface). - * This makes it easier to process all vertices or faces in the global lists - * without worrying about processing the same data twice. As a convenience, - * when a face is split, the "inside" flag is copied from the old face. - * Other internal data (v->data, v->activeRegion, f->data, f->marked, - * f->trail, e->winding) is set to zero. - * - * ********************** Basic Edge Operations ************************** - * - * __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop. - * The loop (face) consists of the two new half-edges. - * - * __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the - * mesh connectivity and topology. It changes the mesh so that - * eOrg->Onext <- OLD( eDst->Onext ) - * eDst->Onext <- OLD( eOrg->Onext ) - * where OLD(...) means the value before the meshSplice operation. - * - * This can have two effects on the vertex structure: - * - if eOrg->Org != eDst->Org, the two vertices are merged together - * - if eOrg->Org == eDst->Org, the origin is split into two vertices - * In both cases, eDst->Org is changed and eOrg->Org is untouched. - * - * Similarly (and independently) for the face structure, - * - if eOrg->Lface == eDst->Lface, one loop is split into two - * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one - * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected. - * - * __gl_meshDelete( eDel ) removes the edge eDel. There are several cases: - * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop - * eDel->Lface is deleted. Otherwise, we are splitting one loop into two; - * the newly created loop will contain eDel->Dst. If the deletion of eDel - * would create isolated vertices, those are deleted as well. - * - * ********************** Other Edge Operations ************************** - * - * __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that - * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex. - * eOrg and eNew will have the same left face. - * - * __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew, - * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org. - * eOrg and eNew will have the same left face. - * - * __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst - * to eDst->Org, and returns the corresponding half-edge eNew. - * If eOrg->Lface == eDst->Lface, this splits one loop into two, - * and the newly created loop is eNew->Lface. Otherwise, two disjoint - * loops are merged into one, and the loop eDst->Lface is destroyed. - * - * ************************ Other Operations ***************************** - * - * __gl_meshNewMesh() creates a new mesh with no edges, no vertices, - * and no loops (what we usually call a "face"). - * - * __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in - * both meshes, and returns the new mesh (the old meshes are destroyed). - * - * __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. - * - * __gl_meshZapFace( fZap ) destroys a face and removes it from the - * global face list. All edges of fZap will have a NULL pointer as their - * left face. Any edges which also have a NULL pointer as their right face - * are deleted entirely (along with any isolated vertices this produces). - * An entire mesh can be deleted by zapping its faces, one at a time, - * in any order. Zapped faces cannot be used in further mesh operations! - * - * __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency. - */ - -GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh ); -int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ); -int __gl_meshDelete( GLUhalfEdge *eDel ); - -GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg ); -GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg ); -GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst ); - -GLUmesh *__gl_meshNewMesh( void ); -GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 ); -void __gl_meshDeleteMesh( GLUmesh *mesh ); -void __gl_meshZapFace( GLUface *fZap ); - -#ifdef NDEBUG -#define __gl_meshCheckMesh( mesh ) -#else -void __gl_meshCheckMesh( GLUmesh *mesh ); -#endif - -#endif diff --git a/GLU/mipmap.c b/GLU/mipmap.c deleted file mode 100644 index ba84237..0000000 --- a/GLU/mipmap.c +++ /dev/null @@ -1,8930 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#include "gluos.h" -#include -#include -#include -#include -#include -#include /* UINT_MAX */ -#include - -typedef union { - unsigned char ub[4]; - unsigned short us[2]; - unsigned int ui; - char b[4]; - short s[2]; - int i; - float f; -} Type_Widget; - -/* Pixel storage modes */ -typedef struct { - GLint pack_alignment; - GLint pack_row_length; - GLint pack_skip_rows; - GLint pack_skip_pixels; - GLint pack_lsb_first; - GLint pack_swap_bytes; - GLint pack_skip_images; - GLint pack_image_height; - - GLint unpack_alignment; - GLint unpack_row_length; - GLint unpack_skip_rows; - GLint unpack_skip_pixels; - GLint unpack_lsb_first; - GLint unpack_swap_bytes; - GLint unpack_skip_images; - GLint unpack_image_height; -} PixelStorageModes; - -static int gluBuild1DMipmapLevelsCore(GLenum, GLint, - GLsizei, - GLsizei, - GLenum, GLenum, GLint, GLint, GLint, - const void *); -static int gluBuild2DMipmapLevelsCore(GLenum, GLint, - GLsizei, GLsizei, - GLsizei, GLsizei, - GLenum, GLenum, GLint, GLint, GLint, - const void *); -static int gluBuild3DMipmapLevelsCore(GLenum, GLint, - GLsizei, GLsizei, GLsizei, - GLsizei, GLsizei, GLsizei, - GLenum, GLenum, GLint, GLint, GLint, - const void *); - -/* - * internal function declarations - */ -static GLfloat bytes_per_element(GLenum type); -static GLint elements_per_group(GLenum format, GLenum type); -static GLint is_index(GLenum format); -static GLint image_size(GLint width, GLint height, GLenum format, GLenum type); -static void fill_image(const PixelStorageModes *, - GLint width, GLint height, GLenum format, - GLenum type, GLboolean index_format, - const void *userdata, GLushort *newimage); -static void empty_image(const PixelStorageModes *, - GLint width, GLint height, GLenum format, - GLenum type, GLboolean index_format, - const GLushort *oldimage, void *userdata); -static void scale_internal(GLint components, GLint widthin, GLint heightin, - const GLushort *datain, - GLint widthout, GLint heightout, - GLushort *dataout); - -static void scale_internal_ubyte(GLint components, GLint widthin, - GLint heightin, const GLubyte *datain, - GLint widthout, GLint heightout, - GLubyte *dataout, GLint element_size, - GLint ysize, GLint group_size); -static void scale_internal_byte(GLint components, GLint widthin, - GLint heightin, const GLbyte *datain, - GLint widthout, GLint heightout, - GLbyte *dataout, GLint element_size, - GLint ysize, GLint group_size); -static void scale_internal_ushort(GLint components, GLint widthin, - GLint heightin, const GLushort *datain, - GLint widthout, GLint heightout, - GLushort *dataout, GLint element_size, - GLint ysize, GLint group_size, - GLint myswap_bytes); -static void scale_internal_short(GLint components, GLint widthin, - GLint heightin, const GLshort *datain, - GLint widthout, GLint heightout, - GLshort *dataout, GLint element_size, - GLint ysize, GLint group_size, - GLint myswap_bytes); -static void scale_internal_uint(GLint components, GLint widthin, - GLint heightin, const GLuint *datain, - GLint widthout, GLint heightout, - GLuint *dataout, GLint element_size, - GLint ysize, GLint group_size, - GLint myswap_bytes); -static void scale_internal_int(GLint components, GLint widthin, - GLint heightin, const GLint *datain, - GLint widthout, GLint heightout, - GLint *dataout, GLint element_size, - GLint ysize, GLint group_size, - GLint myswap_bytes); -static void scale_internal_float(GLint components, GLint widthin, - GLint heightin, const GLfloat *datain, - GLint widthout, GLint heightout, - GLfloat *dataout, GLint element_size, - GLint ysize, GLint group_size, - GLint myswap_bytes); - -static int checkMipmapArgs(GLenum, GLenum, GLenum); -static GLboolean legalFormat(GLenum); -static GLboolean legalType(GLenum); -static GLboolean isTypePackedPixel(GLenum); -static GLboolean isLegalFormatForPackedPixelType(GLenum, GLenum); -static GLboolean isLegalLevels(GLint, GLint, GLint, GLint); -static void closestFit(GLenum, GLint, GLint, GLint, GLenum, GLenum, - GLint *, GLint *); - -/* all extract/shove routines must return double to handle unsigned ints */ -static GLdouble extractUbyte(int, const void *); -static void shoveUbyte(GLdouble, int, void *); -static GLdouble extractSbyte(int, const void *); -static void shoveSbyte(GLdouble, int, void *); -static GLdouble extractUshort(int, const void *); -static void shoveUshort(GLdouble, int, void *); -static GLdouble extractSshort(int, const void *); -static void shoveSshort(GLdouble, int, void *); -static GLdouble extractUint(int, const void *); -static void shoveUint(GLdouble, int, void *); -static GLdouble extractSint(int, const void *); -static void shoveSint(GLdouble, int, void *); -static GLdouble extractFloat(int, const void *); -static void shoveFloat(GLdouble, int, void *); -static void halveImageSlice(int, GLdouble (*)(int, const void *), - void (*)(GLdouble, int, void *), - GLint, GLint, GLint, - const void *, void *, - GLint, GLint, GLint, GLint, GLint); -static void halveImage3D(int, GLdouble (*)(int, const void *), - void (*)(GLdouble, int, void *), - GLint, GLint, GLint, - const void *, void *, - GLint, GLint, GLint, GLint, GLint); - -/* packedpixel type scale routines */ -static void extract332(int,const void *, GLfloat []); -static void shove332(const GLfloat [],int ,void *); -static void extract233rev(int,const void *, GLfloat []); -static void shove233rev(const GLfloat [],int ,void *); -static void extract565(int,const void *, GLfloat []); -static void shove565(const GLfloat [],int ,void *); -static void extract565rev(int,const void *, GLfloat []); -static void shove565rev(const GLfloat [],int ,void *); -static void extract4444(int,const void *, GLfloat []); -static void shove4444(const GLfloat [],int ,void *); -static void extract4444rev(int,const void *, GLfloat []); -static void shove4444rev(const GLfloat [],int ,void *); -static void extract5551(int,const void *, GLfloat []); -static void shove5551(const GLfloat [],int ,void *); -static void extract1555rev(int,const void *, GLfloat []); -static void shove1555rev(const GLfloat [],int ,void *); -static void extract8888(int,const void *, GLfloat []); -static void shove8888(const GLfloat [],int ,void *); -static void extract8888rev(int,const void *, GLfloat []); -static void shove8888rev(const GLfloat [],int ,void *); -static void extract1010102(int,const void *, GLfloat []); -static void shove1010102(const GLfloat [],int ,void *); -static void extract2101010rev(int,const void *, GLfloat []); -static void shove2101010rev(const GLfloat [],int ,void *); -static void scaleInternalPackedPixel(int, - void (*)(int, const void *,GLfloat []), - void (*)(const GLfloat [],int, void *), - GLint,GLint, const void *, - GLint,GLint,void *,GLint,GLint,GLint); -static void halveImagePackedPixel(int, - void (*)(int, const void *,GLfloat []), - void (*)(const GLfloat [],int, void *), - GLint, GLint, const void *, - void *, GLint, GLint, GLint); -static void halve1DimagePackedPixel(int, - void (*)(int, const void *,GLfloat []), - void (*)(const GLfloat [],int, void *), - GLint, GLint, const void *, - void *, GLint, GLint, GLint); - -static void halve1Dimage_ubyte(GLint, GLuint, GLuint,const GLubyte *, - GLubyte *, GLint, GLint, GLint); -static void halve1Dimage_byte(GLint, GLuint, GLuint,const GLbyte *, GLbyte *, - GLint, GLint, GLint); -static void halve1Dimage_ushort(GLint, GLuint, GLuint, const GLushort *, - GLushort *, GLint, GLint, GLint, GLint); -static void halve1Dimage_short(GLint, GLuint, GLuint,const GLshort *, GLshort *, - GLint, GLint, GLint, GLint); -static void halve1Dimage_uint(GLint, GLuint, GLuint, const GLuint *, GLuint *, - GLint, GLint, GLint, GLint); -static void halve1Dimage_int(GLint, GLuint, GLuint, const GLint *, GLint *, - GLint, GLint, GLint, GLint); -static void halve1Dimage_float(GLint, GLuint, GLuint, const GLfloat *, GLfloat *, - GLint, GLint, GLint, GLint); - -static GLint imageSize3D(GLint, GLint, GLint, GLenum,GLenum); -static void fillImage3D(const PixelStorageModes *, GLint, GLint, GLint,GLenum, - GLenum, GLboolean, const void *, GLushort *); -static void emptyImage3D(const PixelStorageModes *, - GLint, GLint, GLint, GLenum, - GLenum, GLboolean, - const GLushort *, void *); -static void scaleInternal3D(GLint, GLint, GLint, GLint, const GLushort *, - GLint, GLint, GLint, GLushort *); - -static void retrieveStoreModes(PixelStorageModes *psm) -{ - glGetIntegerv(GL_UNPACK_ALIGNMENT, &psm->unpack_alignment); - glGetIntegerv(GL_UNPACK_ROW_LENGTH, &psm->unpack_row_length); - glGetIntegerv(GL_UNPACK_SKIP_ROWS, &psm->unpack_skip_rows); - glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &psm->unpack_skip_pixels); - glGetIntegerv(GL_UNPACK_LSB_FIRST, &psm->unpack_lsb_first); - glGetIntegerv(GL_UNPACK_SWAP_BYTES, &psm->unpack_swap_bytes); - - glGetIntegerv(GL_PACK_ALIGNMENT, &psm->pack_alignment); - glGetIntegerv(GL_PACK_ROW_LENGTH, &psm->pack_row_length); - glGetIntegerv(GL_PACK_SKIP_ROWS, &psm->pack_skip_rows); - glGetIntegerv(GL_PACK_SKIP_PIXELS, &psm->pack_skip_pixels); - glGetIntegerv(GL_PACK_LSB_FIRST, &psm->pack_lsb_first); - glGetIntegerv(GL_PACK_SWAP_BYTES, &psm->pack_swap_bytes); -} - -static void retrieveStoreModes3D(PixelStorageModes *psm) -{ - glGetIntegerv(GL_UNPACK_ALIGNMENT, &psm->unpack_alignment); - glGetIntegerv(GL_UNPACK_ROW_LENGTH, &psm->unpack_row_length); - glGetIntegerv(GL_UNPACK_SKIP_ROWS, &psm->unpack_skip_rows); - glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &psm->unpack_skip_pixels); - glGetIntegerv(GL_UNPACK_LSB_FIRST, &psm->unpack_lsb_first); - glGetIntegerv(GL_UNPACK_SWAP_BYTES, &psm->unpack_swap_bytes); - glGetIntegerv(GL_UNPACK_SKIP_IMAGES, &psm->unpack_skip_images); - glGetIntegerv(GL_UNPACK_IMAGE_HEIGHT, &psm->unpack_image_height); - - glGetIntegerv(GL_PACK_ALIGNMENT, &psm->pack_alignment); - glGetIntegerv(GL_PACK_ROW_LENGTH, &psm->pack_row_length); - glGetIntegerv(GL_PACK_SKIP_ROWS, &psm->pack_skip_rows); - glGetIntegerv(GL_PACK_SKIP_PIXELS, &psm->pack_skip_pixels); - glGetIntegerv(GL_PACK_LSB_FIRST, &psm->pack_lsb_first); - glGetIntegerv(GL_PACK_SWAP_BYTES, &psm->pack_swap_bytes); - glGetIntegerv(GL_PACK_SKIP_IMAGES, &psm->pack_skip_images); - glGetIntegerv(GL_PACK_IMAGE_HEIGHT, &psm->pack_image_height); -} - -static int computeLog(GLuint value) -{ - int i; - - i = 0; - - /* Error! */ - if (value == 0) return -1; - - for (;;) { - if (value & 1) { - /* Error ! */ - if (value != 1) return -1; - return i; - } - value = value >> 1; - i++; - } -} - -/* -** Compute the nearest power of 2 number. This algorithm is a little -** strange, but it works quite well. -*/ -static int nearestPower(GLuint value) -{ - int i; - - i = 1; - - /* Error! */ - if (value == 0) return -1; - - for (;;) { - if (value == 1) { - return i; - } else if (value == 3) { - return i*4; - } - value = value >> 1; - i *= 2; - } -} - -#define __GLU_SWAP_2_BYTES(s)\ -(GLushort)(((GLushort)((const GLubyte*)(s))[1])<<8 | ((const GLubyte*)(s))[0]) - -#define __GLU_SWAP_4_BYTES(s)\ -(GLuint)(((GLuint)((const GLubyte*)(s))[3])<<24 | \ - ((GLuint)((const GLubyte*)(s))[2])<<16 | \ - ((GLuint)((const GLubyte*)(s))[1])<<8 | ((const GLubyte*)(s))[0]) - -static void halveImage(GLint components, GLuint width, GLuint height, - const GLushort *datain, GLushort *dataout) -{ - int i, j, k; - int newwidth, newheight; - int delta; - GLushort *s; - const GLushort *t; - - newwidth = width / 2; - newheight = height / 2; - delta = width * components; - s = dataout; - t = datain; - - /* Piece o' cake! */ - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - s[0] = (t[0] + t[components] + t[delta] + - t[delta+components] + 2) / 4; - s++; t++; - } - t += components; - } - t += delta; - } -} - -static void halveImage_ubyte(GLint components, GLuint width, GLuint height, - const GLubyte *datain, GLubyte *dataout, - GLint element_size, GLint ysize, GLint group_size) -{ - int i, j, k; - int newwidth, newheight; - int padBytes; - GLubyte *s; - const char *t; - - /* handle case where there is only 1 column/row */ - if (width == 1 || height == 1) { - assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ - halve1Dimage_ubyte(components,width,height,datain,dataout, - element_size,ysize,group_size); - return; - } - - newwidth = width / 2; - newheight = height / 2; - padBytes = ysize - (width*group_size); - s = dataout; - t = (const char *)datain; - - /* Piece o' cake! */ - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - s[0] = (*(const GLubyte*)t + - *(const GLubyte*)(t+group_size) + - *(const GLubyte*)(t+ysize) + - *(const GLubyte*)(t+ysize+group_size) + 2) / 4; - s++; t += element_size; - } - t += group_size; - } - t += padBytes; - t += ysize; - } -} - -/* */ -static void halve1Dimage_ubyte(GLint components, GLuint width, GLuint height, - const GLubyte *dataIn, GLubyte *dataOut, - GLint element_size, GLint ysize, - GLint group_size) -{ - GLint halfWidth= width / 2; - GLint halfHeight= height / 2; - const char *src= (const char *) dataIn; - GLubyte *dest= dataOut; - int jj; - - assert(width == 1 || height == 1); /* must be 1D */ - assert(width != height); /* can't be square */ - - if (height == 1) { /* 1 row */ - assert(width != 1); /* widthxheight can't be 1x1 */ - halfHeight= 1; - - for (jj= 0; jj< halfWidth; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { - *dest= (*(const GLubyte*)src + - *(const GLubyte*)(src+group_size)) / 2; - - src+= element_size; - dest++; - } - src+= group_size; /* skip to next 2 */ - } - { - int padBytes= ysize - (width*group_size); - src+= padBytes; /* for assertion only */ - } - } - else if (width == 1) { /* 1 column */ - int padBytes= ysize - (width * group_size); - assert(height != 1); /* widthxheight can't be 1x1 */ - halfWidth= 1; - /* one vertical column with possible pad bytes per row */ - /* average two at a time */ - - for (jj= 0; jj< halfHeight; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { - *dest= (*(const GLubyte*)src + *(const GLubyte*)(src+ysize)) / 2; - - src+= element_size; - dest++; - } - src+= padBytes; /* add pad bytes, if any, to get to end to row */ - src+= ysize; - } - } - - assert(src == &((const char *)dataIn)[ysize*height]); - assert((char *)dest == &((char *)dataOut) - [components * element_size * halfWidth * halfHeight]); -} /* halve1Dimage_ubyte() */ - -static void halveImage_byte(GLint components, GLuint width, GLuint height, - const GLbyte *datain, GLbyte *dataout, - GLint element_size, - GLint ysize, GLint group_size) -{ - int i, j, k; - int newwidth, newheight; - int padBytes; - GLbyte *s; - const char *t; - - /* handle case where there is only 1 column/row */ - if (width == 1 || height == 1) { - assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ - halve1Dimage_byte(components,width,height,datain,dataout, - element_size,ysize,group_size); - return; - } - - newwidth = width / 2; - newheight = height / 2; - padBytes = ysize - (width*group_size); - s = dataout; - t = (const char *)datain; - - /* Piece o' cake! */ - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - s[0] = (*(const GLbyte*)t + - *(const GLbyte*)(t+group_size) + - *(const GLbyte*)(t+ysize) + - *(const GLbyte*)(t+ysize+group_size) + 2) / 4; - s++; t += element_size; - } - t += group_size; - } - t += padBytes; - t += ysize; - } -} - -static void halve1Dimage_byte(GLint components, GLuint width, GLuint height, - const GLbyte *dataIn, GLbyte *dataOut, - GLint element_size,GLint ysize, GLint group_size) -{ - GLint halfWidth= width / 2; - GLint halfHeight= height / 2; - const char *src= (const char *) dataIn; - GLbyte *dest= dataOut; - int jj; - - assert(width == 1 || height == 1); /* must be 1D */ - assert(width != height); /* can't be square */ - - if (height == 1) { /* 1 row */ - assert(width != 1); /* widthxheight can't be 1x1 */ - halfHeight= 1; - - for (jj= 0; jj< halfWidth; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { - *dest= (*(const GLbyte*)src + *(const GLbyte*)(src+group_size)) / 2; - - src+= element_size; - dest++; - } - src+= group_size; /* skip to next 2 */ - } - { - int padBytes= ysize - (width*group_size); - src+= padBytes; /* for assertion only */ - } - } - else if (width == 1) { /* 1 column */ - int padBytes= ysize - (width * group_size); - assert(height != 1); /* widthxheight can't be 1x1 */ - halfWidth= 1; - /* one vertical column with possible pad bytes per row */ - /* average two at a time */ - - for (jj= 0; jj< halfHeight; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { - *dest= (*(const GLbyte*)src + *(const GLbyte*)(src+ysize)) / 2; - - src+= element_size; - dest++; - } - src+= padBytes; /* add pad bytes, if any, to get to end to row */ - src+= ysize; - } - - assert(src == &((const char *)dataIn)[ysize*height]); - } - - assert((char *)dest == &((char *)dataOut) - [components * element_size * halfWidth * halfHeight]); -} /* halve1Dimage_byte() */ - -static void halveImage_ushort(GLint components, GLuint width, GLuint height, - const GLushort *datain, GLushort *dataout, - GLint element_size, GLint ysize, GLint group_size, - GLint myswap_bytes) -{ - int i, j, k; - int newwidth, newheight; - int padBytes; - GLushort *s; - const char *t; - - /* handle case where there is only 1 column/row */ - if (width == 1 || height == 1) { - assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ - halve1Dimage_ushort(components,width,height,datain,dataout, - element_size,ysize,group_size, myswap_bytes); - return; - } - - newwidth = width / 2; - newheight = height / 2; - padBytes = ysize - (width*group_size); - s = dataout; - t = (const char *)datain; - - /* Piece o' cake! */ - if (!myswap_bytes) - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - s[0] = (*(const GLushort*)t + - *(const GLushort*)(t+group_size) + - *(const GLushort*)(t+ysize) + - *(const GLushort*)(t+ysize+group_size) + 2) / 4; - s++; t += element_size; - } - t += group_size; - } - t += padBytes; - t += ysize; - } - else - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - s[0] = (__GLU_SWAP_2_BYTES(t) + - __GLU_SWAP_2_BYTES(t+group_size) + - __GLU_SWAP_2_BYTES(t+ysize) + - __GLU_SWAP_2_BYTES(t+ysize+group_size)+ 2)/4; - s++; t += element_size; - } - t += group_size; - } - t += padBytes; - t += ysize; - } -} - -static void halve1Dimage_ushort(GLint components, GLuint width, GLuint height, - const GLushort *dataIn, GLushort *dataOut, - GLint element_size, GLint ysize, - GLint group_size, GLint myswap_bytes) -{ - GLint halfWidth= width / 2; - GLint halfHeight= height / 2; - const char *src= (const char *) dataIn; - GLushort *dest= dataOut; - int jj; - - assert(width == 1 || height == 1); /* must be 1D */ - assert(width != height); /* can't be square */ - - if (height == 1) { /* 1 row */ - assert(width != 1); /* widthxheight can't be 1x1 */ - halfHeight= 1; - - for (jj= 0; jj< halfWidth; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { -#define BOX2 2 - GLushort ushort[BOX2]; - if (myswap_bytes) { - ushort[0]= __GLU_SWAP_2_BYTES(src); - ushort[1]= __GLU_SWAP_2_BYTES(src+group_size); - } - else { - ushort[0]= *(const GLushort*)src; - ushort[1]= *(const GLushort*)(src+group_size); - } - - *dest= (ushort[0] + ushort[1]) / 2; - src+= element_size; - dest++; - } - src+= group_size; /* skip to next 2 */ - } - { - int padBytes= ysize - (width*group_size); - src+= padBytes; /* for assertion only */ - } - } - else if (width == 1) { /* 1 column */ - int padBytes= ysize - (width * group_size); - assert(height != 1); /* widthxheight can't be 1x1 */ - halfWidth= 1; - /* one vertical column with possible pad bytes per row */ - /* average two at a time */ - - for (jj= 0; jj< halfHeight; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { -#define BOX2 2 - GLushort ushort[BOX2]; - if (myswap_bytes) { - ushort[0]= __GLU_SWAP_2_BYTES(src); - ushort[1]= __GLU_SWAP_2_BYTES(src+ysize); - } - else { - ushort[0]= *(const GLushort*)src; - ushort[1]= *(const GLushort*)(src+ysize); - } - *dest= (ushort[0] + ushort[1]) / 2; - - src+= element_size; - dest++; - } - src+= padBytes; /* add pad bytes, if any, to get to end to row */ - src+= ysize; - } - - assert(src == &((const char *)dataIn)[ysize*height]); - } - - assert((char *)dest == &((char *)dataOut) - [components * element_size * halfWidth * halfHeight]); - -} /* halve1Dimage_ushort() */ - - -static void halveImage_short(GLint components, GLuint width, GLuint height, - const GLshort *datain, GLshort *dataout, - GLint element_size, GLint ysize, GLint group_size, - GLint myswap_bytes) -{ - int i, j, k; - int newwidth, newheight; - int padBytes; - GLshort *s; - const char *t; - - /* handle case where there is only 1 column/row */ - if (width == 1 || height == 1) { - assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ - halve1Dimage_short(components,width,height,datain,dataout, - element_size,ysize,group_size, myswap_bytes); - return; - } - - newwidth = width / 2; - newheight = height / 2; - padBytes = ysize - (width*group_size); - s = dataout; - t = (const char *)datain; - - /* Piece o' cake! */ - if (!myswap_bytes) - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - s[0] = (*(const GLshort*)t + - *(const GLshort*)(t+group_size) + - *(const GLshort*)(t+ysize) + - *(const GLshort*)(t+ysize+group_size) + 2) / 4; - s++; t += element_size; - } - t += group_size; - } - t += padBytes; - t += ysize; - } - else - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - GLushort b; - GLint buf; - b = __GLU_SWAP_2_BYTES(t); - buf = *(const GLshort*)&b; - b = __GLU_SWAP_2_BYTES(t+group_size); - buf += *(const GLshort*)&b; - b = __GLU_SWAP_2_BYTES(t+ysize); - buf += *(const GLshort*)&b; - b = __GLU_SWAP_2_BYTES(t+ysize+group_size); - buf += *(const GLshort*)&b; - s[0] = (GLshort)((buf+2)/4); - s++; t += element_size; - } - t += group_size; - } - t += padBytes; - t += ysize; - } -} - -static void halve1Dimage_short(GLint components, GLuint width, GLuint height, - const GLshort *dataIn, GLshort *dataOut, - GLint element_size, GLint ysize, - GLint group_size, GLint myswap_bytes) -{ - GLint halfWidth= width / 2; - GLint halfHeight= height / 2; - const char *src= (const char *) dataIn; - GLshort *dest= dataOut; - int jj; - - assert(width == 1 || height == 1); /* must be 1D */ - assert(width != height); /* can't be square */ - - if (height == 1) { /* 1 row */ - assert(width != 1); /* widthxheight can't be 1x1 */ - halfHeight= 1; - - for (jj= 0; jj< halfWidth; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { -#define BOX2 2 - GLshort sshort[BOX2]; - if (myswap_bytes) { - sshort[0]= __GLU_SWAP_2_BYTES(src); - sshort[1]= __GLU_SWAP_2_BYTES(src+group_size); - } - else { - sshort[0]= *(const GLshort*)src; - sshort[1]= *(const GLshort*)(src+group_size); - } - - *dest= (sshort[0] + sshort[1]) / 2; - src+= element_size; - dest++; - } - src+= group_size; /* skip to next 2 */ - } - { - int padBytes= ysize - (width*group_size); - src+= padBytes; /* for assertion only */ - } - } - else if (width == 1) { /* 1 column */ - int padBytes= ysize - (width * group_size); - assert(height != 1); /* widthxheight can't be 1x1 */ - halfWidth= 1; - /* one vertical column with possible pad bytes per row */ - /* average two at a time */ - - for (jj= 0; jj< halfHeight; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { -#define BOX2 2 - GLshort sshort[BOX2]; - if (myswap_bytes) { - sshort[0]= __GLU_SWAP_2_BYTES(src); - sshort[1]= __GLU_SWAP_2_BYTES(src+ysize); - } - else { - sshort[0]= *(const GLshort*)src; - sshort[1]= *(const GLshort*)(src+ysize); - } - *dest= (sshort[0] + sshort[1]) / 2; - - src+= element_size; - dest++; - } - src+= padBytes; /* add pad bytes, if any, to get to end to row */ - src+= ysize; - } - - assert(src == &((const char *)dataIn)[ysize*height]); - } - - assert((char *)dest == &((char *)dataOut) - [components * element_size * halfWidth * halfHeight]); - -} /* halve1Dimage_short() */ - - -static void halveImage_uint(GLint components, GLuint width, GLuint height, - const GLuint *datain, GLuint *dataout, - GLint element_size, GLint ysize, GLint group_size, - GLint myswap_bytes) -{ - int i, j, k; - int newwidth, newheight; - int padBytes; - GLuint *s; - const char *t; - - /* handle case where there is only 1 column/row */ - if (width == 1 || height == 1) { - assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ - halve1Dimage_uint(components,width,height,datain,dataout, - element_size,ysize,group_size, myswap_bytes); - return; - } - - newwidth = width / 2; - newheight = height / 2; - padBytes = ysize - (width*group_size); - s = dataout; - t = (const char *)datain; - - /* Piece o' cake! */ - if (!myswap_bytes) - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - /* need to cast to double to hold large unsigned ints */ - s[0] = ((double)*(const GLuint*)t + - (double)*(const GLuint*)(t+group_size) + - (double)*(const GLuint*)(t+ysize) + - (double)*(const GLuint*)(t+ysize+group_size))/4 + 0.5; - s++; t += element_size; - - } - t += group_size; - } - t += padBytes; - t += ysize; - } - else - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - /* need to cast to double to hold large unsigned ints */ - GLdouble buf; - buf = (GLdouble)__GLU_SWAP_4_BYTES(t) + - (GLdouble)__GLU_SWAP_4_BYTES(t+group_size) + - (GLdouble)__GLU_SWAP_4_BYTES(t+ysize) + - (GLdouble)__GLU_SWAP_4_BYTES(t+ysize+group_size); - s[0] = (GLuint)(buf/4 + 0.5); - - s++; t += element_size; - } - t += group_size; - } - t += padBytes; - t += ysize; - } -} - -/* */ -static void halve1Dimage_uint(GLint components, GLuint width, GLuint height, - const GLuint *dataIn, GLuint *dataOut, - GLint element_size, GLint ysize, - GLint group_size, GLint myswap_bytes) -{ - GLint halfWidth= width / 2; - GLint halfHeight= height / 2; - const char *src= (const char *) dataIn; - GLuint *dest= dataOut; - int jj; - - assert(width == 1 || height == 1); /* must be 1D */ - assert(width != height); /* can't be square */ - - if (height == 1) { /* 1 row */ - assert(width != 1); /* widthxheight can't be 1x1 */ - halfHeight= 1; - - for (jj= 0; jj< halfWidth; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { -#define BOX2 2 - GLuint uint[BOX2]; - if (myswap_bytes) { - uint[0]= __GLU_SWAP_4_BYTES(src); - uint[1]= __GLU_SWAP_4_BYTES(src+group_size); - } - else { - uint[0]= *(const GLuint*)src; - uint[1]= *(const GLuint*)(src+group_size); - } - *dest= ((double)uint[0]+(double)uint[1])/2.0; - - src+= element_size; - dest++; - } - src+= group_size; /* skip to next 2 */ - } - { - int padBytes= ysize - (width*group_size); - src+= padBytes; /* for assertion only */ - } - } - else if (width == 1) { /* 1 column */ - int padBytes= ysize - (width * group_size); - assert(height != 1); /* widthxheight can't be 1x1 */ - halfWidth= 1; - /* one vertical column with possible pad bytes per row */ - /* average two at a time */ - - for (jj= 0; jj< halfHeight; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { -#define BOX2 2 - GLuint uint[BOX2]; - if (myswap_bytes) { - uint[0]= __GLU_SWAP_4_BYTES(src); - uint[1]= __GLU_SWAP_4_BYTES(src+ysize); - } - else { - uint[0]= *(const GLuint*)src; - uint[1]= *(const GLuint*)(src+ysize); - } - *dest= ((double)uint[0]+(double)uint[1])/2.0; - - src+= element_size; - dest++; - } - src+= padBytes; /* add pad bytes, if any, to get to end to row */ - src+= ysize; - } - - assert(src == &((const char *)dataIn)[ysize*height]); - } - - assert((char *)dest == &((char *)dataOut) - [components * element_size * halfWidth * halfHeight]); - -} /* halve1Dimage_uint() */ - -static void halveImage_int(GLint components, GLuint width, GLuint height, - const GLint *datain, GLint *dataout, GLint element_size, - GLint ysize, GLint group_size, GLint myswap_bytes) -{ - int i, j, k; - int newwidth, newheight; - int padBytes; - GLint *s; - const char *t; - - /* handle case where there is only 1 column/row */ - if (width == 1 || height == 1) { - assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ - halve1Dimage_int(components,width,height,datain,dataout, - element_size,ysize,group_size, myswap_bytes); - return; - } - - newwidth = width / 2; - newheight = height / 2; - padBytes = ysize - (width*group_size); - s = dataout; - t = (const char *)datain; - - /* Piece o' cake! */ - if (!myswap_bytes) - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - s[0] = ((float)*(const GLint*)t + - (float)*(const GLint*)(t+group_size) + - (float)*(const GLint*)(t+ysize) + - (float)*(const GLint*)(t+ysize+group_size))/4 + 0.5; - s++; t += element_size; - } - t += group_size; - } - t += padBytes; - t += ysize; - } - else - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - GLuint b; - GLfloat buf; - b = __GLU_SWAP_4_BYTES(t); - buf = *(GLint*)&b; - b = __GLU_SWAP_4_BYTES(t+group_size); - buf += *(GLint*)&b; - b = __GLU_SWAP_4_BYTES(t+ysize); - buf += *(GLint*)&b; - b = __GLU_SWAP_4_BYTES(t+ysize+group_size); - buf += *(GLint*)&b; - s[0] = (GLint)(buf/4 + 0.5); - - s++; t += element_size; - } - t += group_size; - } - t += padBytes; - t += ysize; - } -} - -/* */ -static void halve1Dimage_int(GLint components, GLuint width, GLuint height, - const GLint *dataIn, GLint *dataOut, - GLint element_size, GLint ysize, - GLint group_size, GLint myswap_bytes) -{ - GLint halfWidth= width / 2; - GLint halfHeight= height / 2; - const char *src= (const char *) dataIn; - GLint *dest= dataOut; - int jj; - - assert(width == 1 || height == 1); /* must be 1D */ - assert(width != height); /* can't be square */ - - if (height == 1) { /* 1 row */ - assert(width != 1); /* widthxheight can't be 1x1 */ - halfHeight= 1; - - for (jj= 0; jj< halfWidth; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { -#define BOX2 2 - GLuint uint[BOX2]; - if (myswap_bytes) { - uint[0]= __GLU_SWAP_4_BYTES(src); - uint[1]= __GLU_SWAP_4_BYTES(src+group_size); - } - else { - uint[0]= *(const GLuint*)src; - uint[1]= *(const GLuint*)(src+group_size); - } - *dest= ((float)uint[0]+(float)uint[1])/2.0; - - src+= element_size; - dest++; - } - src+= group_size; /* skip to next 2 */ - } - { - int padBytes= ysize - (width*group_size); - src+= padBytes; /* for assertion only */ - } - } - else if (width == 1) { /* 1 column */ - int padBytes= ysize - (width * group_size); - assert(height != 1); /* widthxheight can't be 1x1 */ - halfWidth= 1; - /* one vertical column with possible pad bytes per row */ - /* average two at a time */ - - for (jj= 0; jj< halfHeight; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { -#define BOX2 2 - GLuint uint[BOX2]; - if (myswap_bytes) { - uint[0]= __GLU_SWAP_4_BYTES(src); - uint[1]= __GLU_SWAP_4_BYTES(src+ysize); - } - else { - uint[0]= *(const GLuint*)src; - uint[1]= *(const GLuint*)(src+ysize); - } - *dest= ((float)uint[0]+(float)uint[1])/2.0; - - src+= element_size; - dest++; - } - src+= padBytes; /* add pad bytes, if any, to get to end to row */ - src+= ysize; - } - - assert(src == &((const char *)dataIn)[ysize*height]); - } - - assert((char *)dest == &((char *)dataOut) - [components * element_size * halfWidth * halfHeight]); - -} /* halve1Dimage_int() */ - - -static void halveImage_float(GLint components, GLuint width, GLuint height, - const GLfloat *datain, GLfloat *dataout, - GLint element_size, GLint ysize, GLint group_size, - GLint myswap_bytes) -{ - int i, j, k; - int newwidth, newheight; - int padBytes; - GLfloat *s; - const char *t; - - /* handle case where there is only 1 column/row */ - if (width == 1 || height == 1) { - assert( !(width == 1 && height == 1) ); /* can't be 1x1 */ - halve1Dimage_float(components,width,height,datain,dataout, - element_size,ysize,group_size, myswap_bytes); - return; - } - - newwidth = width / 2; - newheight = height / 2; - padBytes = ysize - (width*group_size); - s = dataout; - t = (const char *)datain; - - /* Piece o' cake! */ - if (!myswap_bytes) - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - s[0] = (*(const GLfloat*)t + - *(const GLfloat*)(t+group_size) + - *(const GLfloat*)(t+ysize) + - *(const GLfloat*)(t+ysize+group_size)) / 4; - s++; t += element_size; - } - t += group_size; - } - t += padBytes; - t += ysize; - } - else - for (i = 0; i < newheight; i++) { - for (j = 0; j < newwidth; j++) { - for (k = 0; k < components; k++) { - union { GLuint b; GLfloat f; } swapbuf; - swapbuf.b = __GLU_SWAP_4_BYTES(t); - s[0] = swapbuf.f; - swapbuf.b = __GLU_SWAP_4_BYTES(t+group_size); - s[0] += swapbuf.f; - swapbuf.b = __GLU_SWAP_4_BYTES(t+ysize); - s[0] += swapbuf.f; - swapbuf.b = __GLU_SWAP_4_BYTES(t+ysize+group_size); - s[0] += swapbuf.f; - s[0] /= 4; - s++; t += element_size; - } - t += group_size; - } - t += padBytes; - t += ysize; - } -} - -/* */ -static void halve1Dimage_float(GLint components, GLuint width, GLuint height, - const GLfloat *dataIn, GLfloat *dataOut, - GLint element_size, GLint ysize, - GLint group_size, GLint myswap_bytes) -{ - GLint halfWidth= width / 2; - GLint halfHeight= height / 2; - const char *src= (const char *) dataIn; - GLfloat *dest= dataOut; - int jj; - - assert(width == 1 || height == 1); /* must be 1D */ - assert(width != height); /* can't be square */ - - if (height == 1) { /* 1 row */ - assert(width != 1); /* widthxheight can't be 1x1 */ - halfHeight= 1; - - for (jj= 0; jj< halfWidth; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { -#define BOX2 2 - GLfloat sfloat[BOX2]; - if (myswap_bytes) { - sfloat[0]= __GLU_SWAP_4_BYTES(src); - sfloat[1]= __GLU_SWAP_4_BYTES(src+group_size); - } - else { - sfloat[0]= *(const GLfloat*)src; - sfloat[1]= *(const GLfloat*)(src+group_size); - } - - *dest= (sfloat[0] + sfloat[1]) / 2.0; - src+= element_size; - dest++; - } - src+= group_size; /* skip to next 2 */ - } - { - int padBytes= ysize - (width*group_size); - src+= padBytes; /* for assertion only */ - } - } - else if (width == 1) { /* 1 column */ - int padBytes= ysize - (width * group_size); - assert(height != 1); /* widthxheight can't be 1x1 */ - halfWidth= 1; - /* one vertical column with possible pad bytes per row */ - /* average two at a time */ - - for (jj= 0; jj< halfHeight; jj++) { - int kk; - for (kk= 0; kk< components; kk++) { -#define BOX2 2 - GLfloat sfloat[BOX2]; - if (myswap_bytes) { - sfloat[0]= __GLU_SWAP_4_BYTES(src); - sfloat[1]= __GLU_SWAP_4_BYTES(src+ysize); - } - else { - sfloat[0]= *(const GLfloat*)src; - sfloat[1]= *(const GLfloat*)(src+ysize); - } - *dest= (sfloat[0] + sfloat[1]) / 2.0; - - src+= element_size; - dest++; - } - src+= padBytes; /* add pad bytes, if any, to get to end to row */ - src+= ysize; /* skip to odd row */ - } - } - - assert(src == &((const char *)dataIn)[ysize*height]); - assert((char *)dest == &((char *)dataOut) - [components * element_size * halfWidth * halfHeight]); -} /* halve1Dimage_float() */ - -static void scale_internal(GLint components, GLint widthin, GLint heightin, - const GLushort *datain, - GLint widthout, GLint heightout, - GLushort *dataout) -{ - float x, lowx, highx, convx, halfconvx; - float y, lowy, highy, convy, halfconvy; - float xpercent,ypercent; - float percent; - /* Max components in a format is 4, so... */ - float totals[4]; - float area; - int i,j,k,yint,xint,xindex,yindex; - int temp; - - if (widthin == widthout*2 && heightin == heightout*2) { - halveImage(components, widthin, heightin, datain, dataout); - return; - } - convy = (float) heightin/heightout; - convx = (float) widthin/widthout; - halfconvx = convx/2; - halfconvy = convy/2; - for (i = 0; i < heightout; i++) { - y = convy * (i+0.5); - if (heightin > heightout) { - highy = y + halfconvy; - lowy = y - halfconvy; - } else { - highy = y + 0.5; - lowy = y - 0.5; - } - for (j = 0; j < widthout; j++) { - x = convx * (j+0.5); - if (widthin > widthout) { - highx = x + halfconvx; - lowx = x - halfconvx; - } else { - highx = x + 0.5; - lowx = x - 0.5; - } - - /* - ** Ok, now apply box filter to box that goes from (lowx, lowy) - ** to (highx, highy) on input data into this pixel on output - ** data. - */ - totals[0] = totals[1] = totals[2] = totals[3] = 0.0; - area = 0.0; - - y = lowy; - yint = floor(y); - while (y < highy) { - yindex = (yint + heightin) % heightin; - if (highy < yint+1) { - ypercent = highy - y; - } else { - ypercent = yint+1 - y; - } - - x = lowx; - xint = floor(x); - - while (x < highx) { - xindex = (xint + widthin) % widthin; - if (highx < xint+1) { - xpercent = highx - x; - } else { - xpercent = xint+1 - x; - } - - percent = xpercent * ypercent; - area += percent; - temp = (xindex + (yindex * widthin)) * components; - for (k = 0; k < components; k++) { - totals[k] += datain[temp + k] * percent; - } - - xint++; - x = xint; - } - yint++; - y = yint; - } - - temp = (j + (i * widthout)) * components; - for (k = 0; k < components; k++) { - /* totals[] should be rounded in the case of enlarging an RGB - * ramp when the type is 332 or 4444 - */ - dataout[temp + k] = (totals[k]+0.5)/area; - } - } - } -} - -static void scale_internal_ubyte(GLint components, GLint widthin, - GLint heightin, const GLubyte *datain, - GLint widthout, GLint heightout, - GLubyte *dataout, GLint element_size, - GLint ysize, GLint group_size) -{ - float convx; - float convy; - float percent; - /* Max components in a format is 4, so... */ - float totals[4]; - float area; - int i,j,k,xindex; - - const char *temp, *temp0; - const char *temp_index; - int outindex; - - int lowx_int, highx_int, lowy_int, highy_int; - float x_percent, y_percent; - float lowx_float, highx_float, lowy_float, highy_float; - float convy_float, convx_float; - int convy_int, convx_int; - int l, m; - const char *left, *right; - - if (widthin == widthout*2 && heightin == heightout*2) { - halveImage_ubyte(components, widthin, heightin, - (const GLubyte *)datain, (GLubyte *)dataout, - element_size, ysize, group_size); - return; - } - convy = (float) heightin/heightout; - convx = (float) widthin/widthout; - convy_int = floor(convy); - convy_float = convy - convy_int; - convx_int = floor(convx); - convx_float = convx - convx_int; - - area = convx * convy; - - lowy_int = 0; - lowy_float = 0; - highy_int = convy_int; - highy_float = convy_float; - - for (i = 0; i < heightout; i++) { - /* Clamp here to be sure we don't read beyond input buffer. */ - if (highy_int >= heightin) - highy_int = heightin - 1; - lowx_int = 0; - lowx_float = 0; - highx_int = convx_int; - highx_float = convx_float; - - for (j = 0; j < widthout; j++) { - - /* - ** Ok, now apply box filter to box that goes from (lowx, lowy) - ** to (highx, highy) on input data into this pixel on output - ** data. - */ - totals[0] = totals[1] = totals[2] = totals[3] = 0.0; - - /* calculate the value for pixels in the 1st row */ - xindex = lowx_int*group_size; - if((highy_int>lowy_int) && (highx_int>lowx_int)) { - - y_percent = 1-lowy_float; - temp = (const char *)datain + xindex + lowy_int * ysize; - percent = y_percent * (1-lowx_float); - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * percent; - } - left = temp; - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * y_percent; - } - } - temp += group_size; - right = temp; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * percent; - } - - /* calculate the value for pixels in the last row */ - y_percent = highy_float; - percent = y_percent * (1-lowx_float); - temp = (const char *)datain + xindex + highy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * percent; - } - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * y_percent; - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * percent; - } - - - /* calculate the value for pixels in the 1st and last column */ - for(m = lowy_int+1; m < highy_int; m++) { - left += ysize; - right += ysize; - for (k = 0; k < components; - k++, left += element_size, right += element_size) { - totals[k] += (GLubyte)(*(left))*(1-lowx_float) - +(GLubyte)(*(right))*highx_float; - } - } - } else if (highy_int > lowy_int) { - x_percent = highx_float - lowx_float; - percent = (1-lowy_float)*x_percent; - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * percent; - } - for(m = lowy_int+1; m < highy_int; m++) { - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * x_percent; - } - } - percent = x_percent * highy_float; - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * percent; - } - } else if (highx_int > lowx_int) { - y_percent = highy_float - lowy_float; - percent = (1-lowx_float)*y_percent; - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * percent; - } - for (l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * y_percent; - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * percent; - } - } else { - percent = (highy_float-lowy_float)*(highx_float-lowx_float); - temp = (const char *)datain + xindex + lowy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)) * percent; - } - } - - - - /* this is for the pixels in the body */ - temp0 = (const char *)datain + xindex + group_size + - (lowy_int+1)*ysize; - for (m = lowy_int+1; m < highy_int; m++) { - temp = temp0; - for(l = lowx_int+1; l < highx_int; l++) { - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLubyte)(*(temp_index)); - } - temp += group_size; - } - temp0 += ysize; - } - - outindex = (j + (i * widthout)) * components; - for (k = 0; k < components; k++) { - dataout[outindex + k] = totals[k]/area; - /*printf("totals[%d] = %f\n", k, totals[k]);*/ - } - lowx_int = highx_int; - lowx_float = highx_float; - highx_int += convx_int; - highx_float += convx_float; - if(highx_float > 1) { - highx_float -= 1.0; - highx_int++; - } - } - lowy_int = highy_int; - lowy_float = highy_float; - highy_int += convy_int; - highy_float += convy_float; - if(highy_float > 1) { - highy_float -= 1.0; - highy_int++; - } - } -} - -static void scale_internal_byte(GLint components, GLint widthin, - GLint heightin, const GLbyte *datain, - GLint widthout, GLint heightout, - GLbyte *dataout, GLint element_size, - GLint ysize, GLint group_size) -{ - float convx; - float convy; - float percent; - /* Max components in a format is 4, so... */ - float totals[4]; - float area; - int i,j,k,xindex; - - const char *temp, *temp0; - const char *temp_index; - int outindex; - - int lowx_int, highx_int, lowy_int, highy_int; - float x_percent, y_percent; - float lowx_float, highx_float, lowy_float, highy_float; - float convy_float, convx_float; - int convy_int, convx_int; - int l, m; - const char *left, *right; - - if (widthin == widthout*2 && heightin == heightout*2) { - halveImage_byte(components, widthin, heightin, - (const GLbyte *)datain, (GLbyte *)dataout, - element_size, ysize, group_size); - return; - } - convy = (float) heightin/heightout; - convx = (float) widthin/widthout; - convy_int = floor(convy); - convy_float = convy - convy_int; - convx_int = floor(convx); - convx_float = convx - convx_int; - - area = convx * convy; - - lowy_int = 0; - lowy_float = 0; - highy_int = convy_int; - highy_float = convy_float; - - for (i = 0; i < heightout; i++) { - /* Clamp here to be sure we don't read beyond input buffer. */ - if (highy_int >= heightin) - highy_int = heightin - 1; - lowx_int = 0; - lowx_float = 0; - highx_int = convx_int; - highx_float = convx_float; - - for (j = 0; j < widthout; j++) { - - /* - ** Ok, now apply box filter to box that goes from (lowx, lowy) - ** to (highx, highy) on input data into this pixel on output - ** data. - */ - totals[0] = totals[1] = totals[2] = totals[3] = 0.0; - - /* calculate the value for pixels in the 1st row */ - xindex = lowx_int*group_size; - if((highy_int>lowy_int) && (highx_int>lowx_int)) { - - y_percent = 1-lowy_float; - temp = (const char *)datain + xindex + lowy_int * ysize; - percent = y_percent * (1-lowx_float); - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * percent; - } - left = temp; - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * y_percent; - } - } - temp += group_size; - right = temp; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * percent; - } - - /* calculate the value for pixels in the last row */ - y_percent = highy_float; - percent = y_percent * (1-lowx_float); - temp = (const char *)datain + xindex + highy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * percent; - } - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * y_percent; - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * percent; - } - - - /* calculate the value for pixels in the 1st and last column */ - for(m = lowy_int+1; m < highy_int; m++) { - left += ysize; - right += ysize; - for (k = 0; k < components; - k++, left += element_size, right += element_size) { - totals[k] += (GLbyte)(*(left))*(1-lowx_float) - +(GLbyte)(*(right))*highx_float; - } - } - } else if (highy_int > lowy_int) { - x_percent = highx_float - lowx_float; - percent = (1-lowy_float)*x_percent; - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * percent; - } - for(m = lowy_int+1; m < highy_int; m++) { - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * x_percent; - } - } - percent = x_percent * highy_float; - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * percent; - } - } else if (highx_int > lowx_int) { - y_percent = highy_float - lowy_float; - percent = (1-lowx_float)*y_percent; - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * percent; - } - for (l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * y_percent; - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * percent; - } - } else { - percent = (highy_float-lowy_float)*(highx_float-lowx_float); - temp = (const char *)datain + xindex + lowy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)) * percent; - } - } - - - - /* this is for the pixels in the body */ - temp0 = (const char *)datain + xindex + group_size + - (lowy_int+1)*ysize; - for (m = lowy_int+1; m < highy_int; m++) { - temp = temp0; - for(l = lowx_int+1; l < highx_int; l++) { - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - totals[k] += (GLbyte)(*(temp_index)); - } - temp += group_size; - } - temp0 += ysize; - } - - outindex = (j + (i * widthout)) * components; - for (k = 0; k < components; k++) { - dataout[outindex + k] = totals[k]/area; - /*printf("totals[%d] = %f\n", k, totals[k]);*/ - } - lowx_int = highx_int; - lowx_float = highx_float; - highx_int += convx_int; - highx_float += convx_float; - if(highx_float > 1) { - highx_float -= 1.0; - highx_int++; - } - } - lowy_int = highy_int; - lowy_float = highy_float; - highy_int += convy_int; - highy_float += convy_float; - if(highy_float > 1) { - highy_float -= 1.0; - highy_int++; - } - } -} - -static void scale_internal_ushort(GLint components, GLint widthin, - GLint heightin, const GLushort *datain, - GLint widthout, GLint heightout, - GLushort *dataout, GLint element_size, - GLint ysize, GLint group_size, - GLint myswap_bytes) -{ - float convx; - float convy; - float percent; - /* Max components in a format is 4, so... */ - float totals[4]; - float area; - int i,j,k,xindex; - - const char *temp, *temp0; - const char *temp_index; - int outindex; - - int lowx_int, highx_int, lowy_int, highy_int; - float x_percent, y_percent; - float lowx_float, highx_float, lowy_float, highy_float; - float convy_float, convx_float; - int convy_int, convx_int; - int l, m; - const char *left, *right; - - if (widthin == widthout*2 && heightin == heightout*2) { - halveImage_ushort(components, widthin, heightin, - (const GLushort *)datain, (GLushort *)dataout, - element_size, ysize, group_size, myswap_bytes); - return; - } - convy = (float) heightin/heightout; - convx = (float) widthin/widthout; - convy_int = floor(convy); - convy_float = convy - convy_int; - convx_int = floor(convx); - convx_float = convx - convx_int; - - area = convx * convy; - - lowy_int = 0; - lowy_float = 0; - highy_int = convy_int; - highy_float = convy_float; - - for (i = 0; i < heightout; i++) { - /* Clamp here to be sure we don't read beyond input buffer. */ - if (highy_int >= heightin) - highy_int = heightin - 1; - lowx_int = 0; - lowx_float = 0; - highx_int = convx_int; - highx_float = convx_float; - - for (j = 0; j < widthout; j++) { - /* - ** Ok, now apply box filter to box that goes from (lowx, lowy) - ** to (highx, highy) on input data into this pixel on output - ** data. - */ - totals[0] = totals[1] = totals[2] = totals[3] = 0.0; - - /* calculate the value for pixels in the 1st row */ - xindex = lowx_int*group_size; - if((highy_int>lowy_int) && (highx_int>lowx_int)) { - - y_percent = 1-lowy_float; - temp = (const char *)datain + xindex + lowy_int * ysize; - percent = y_percent * (1-lowx_float); - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } - left = temp; - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_2_BYTES(temp_index) * y_percent; - } else { - totals[k] += *(const GLushort*)temp_index * y_percent; - } - } - } - temp += group_size; - right = temp; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } - - /* calculate the value for pixels in the last row */ - y_percent = highy_float; - percent = y_percent * (1-lowx_float); - temp = (const char *)datain + xindex + highy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_2_BYTES(temp_index) * y_percent; - } else { - totals[k] += *(const GLushort*)temp_index * y_percent; - } - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } - - /* calculate the value for pixels in the 1st and last column */ - for(m = lowy_int+1; m < highy_int; m++) { - left += ysize; - right += ysize; - for (k = 0; k < components; - k++, left += element_size, right += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_2_BYTES(left) * (1-lowx_float) + - __GLU_SWAP_2_BYTES(right) * highx_float; - } else { - totals[k] += *(const GLushort*)left * (1-lowx_float) - + *(const GLushort*)right * highx_float; - } - } - } - } else if (highy_int > lowy_int) { - x_percent = highx_float - lowx_float; - percent = (1-lowy_float)*x_percent; - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } - for(m = lowy_int+1; m < highy_int; m++) { - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_2_BYTES(temp_index) * x_percent; - } else { - totals[k] += *(const GLushort*)temp_index * x_percent; - } - } - } - percent = x_percent * highy_float; - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } - } else if (highx_int > lowx_int) { - y_percent = highy_float - lowy_float; - percent = (1-lowx_float)*y_percent; - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } - for (l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_2_BYTES(temp_index) * y_percent; - } else { - totals[k] += *(const GLushort*)temp_index * y_percent; - } - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } - } else { - percent = (highy_float-lowy_float)*(highx_float-lowx_float); - temp = (const char *)datain + xindex + lowy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } - } - - /* this is for the pixels in the body */ - temp0 = (const char *)datain + xindex + group_size + - (lowy_int+1)*ysize; - for (m = lowy_int+1; m < highy_int; m++) { - temp = temp0; - for(l = lowx_int+1; l < highx_int; l++) { - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index); - } else { - totals[k] += *(const GLushort*)temp_index; - } - } - temp += group_size; - } - temp0 += ysize; - } - - outindex = (j + (i * widthout)) * components; - for (k = 0; k < components; k++) { - dataout[outindex + k] = totals[k]/area; - /*printf("totals[%d] = %f\n", k, totals[k]);*/ - } - lowx_int = highx_int; - lowx_float = highx_float; - highx_int += convx_int; - highx_float += convx_float; - if(highx_float > 1) { - highx_float -= 1.0; - highx_int++; - } - } - lowy_int = highy_int; - lowy_float = highy_float; - highy_int += convy_int; - highy_float += convy_float; - if(highy_float > 1) { - highy_float -= 1.0; - highy_int++; - } - } -} - -static void scale_internal_short(GLint components, GLint widthin, - GLint heightin, const GLshort *datain, - GLint widthout, GLint heightout, - GLshort *dataout, GLint element_size, - GLint ysize, GLint group_size, - GLint myswap_bytes) -{ - float convx; - float convy; - float percent; - /* Max components in a format is 4, so... */ - float totals[4]; - float area; - int i,j,k,xindex; - - const char *temp, *temp0; - const char *temp_index; - int outindex; - - int lowx_int, highx_int, lowy_int, highy_int; - float x_percent, y_percent; - float lowx_float, highx_float, lowy_float, highy_float; - float convy_float, convx_float; - int convy_int, convx_int; - int l, m; - const char *left, *right; - - GLushort swapbuf; /* unsigned buffer */ - - if (widthin == widthout*2 && heightin == heightout*2) { - halveImage_short(components, widthin, heightin, - (const GLshort *)datain, (GLshort *)dataout, - element_size, ysize, group_size, myswap_bytes); - return; - } - convy = (float) heightin/heightout; - convx = (float) widthin/widthout; - convy_int = floor(convy); - convy_float = convy - convy_int; - convx_int = floor(convx); - convx_float = convx - convx_int; - - area = convx * convy; - - lowy_int = 0; - lowy_float = 0; - highy_int = convy_int; - highy_float = convy_float; - - for (i = 0; i < heightout; i++) { - /* Clamp here to be sure we don't read beyond input buffer. */ - if (highy_int >= heightin) - highy_int = heightin - 1; - lowx_int = 0; - lowx_float = 0; - highx_int = convx_int; - highx_float = convx_float; - - for (j = 0; j < widthout; j++) { - /* - ** Ok, now apply box filter to box that goes from (lowx, lowy) - ** to (highx, highy) on input data into this pixel on output - ** data. - */ - totals[0] = totals[1] = totals[2] = totals[3] = 0.0; - - /* calculate the value for pixels in the 1st row */ - xindex = lowx_int*group_size; - if((highy_int>lowy_int) && (highx_int>lowx_int)) { - - y_percent = 1-lowy_float; - temp = (const char *)datain + xindex + lowy_int * ysize; - percent = y_percent * (1-lowx_float); - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * percent; - } else { - totals[k] += *(const GLshort*)temp_index * percent; - } - } - left = temp; - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * y_percent; - } else { - totals[k] += *(const GLshort*)temp_index * y_percent; - } - } - } - temp += group_size; - right = temp; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * percent; - } else { - totals[k] += *(const GLshort*)temp_index * percent; - } - } - - /* calculate the value for pixels in the last row */ - y_percent = highy_float; - percent = y_percent * (1-lowx_float); - temp = (const char *)datain + xindex + highy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * percent; - } else { - totals[k] += *(const GLshort*)temp_index * percent; - } - } - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * y_percent; - } else { - totals[k] += *(const GLshort*)temp_index * y_percent; - } - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * percent; - } else { - totals[k] += *(const GLshort*)temp_index * percent; - } - } - - /* calculate the value for pixels in the 1st and last column */ - for(m = lowy_int+1; m < highy_int; m++) { - left += ysize; - right += ysize; - for (k = 0; k < components; - k++, left += element_size, right += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(left); - totals[k] += *(const GLshort*)&swapbuf * (1-lowx_float); - swapbuf = __GLU_SWAP_2_BYTES(right); - totals[k] += *(const GLshort*)&swapbuf * highx_float; - } else { - totals[k] += *(const GLshort*)left * (1-lowx_float) - + *(const GLshort*)right * highx_float; - } - } - } - } else if (highy_int > lowy_int) { - x_percent = highx_float - lowx_float; - percent = (1-lowy_float)*x_percent; - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * percent; - } else { - totals[k] += *(const GLshort*)temp_index * percent; - } - } - for(m = lowy_int+1; m < highy_int; m++) { - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * x_percent; - } else { - totals[k] += *(const GLshort*)temp_index * x_percent; - } - } - } - percent = x_percent * highy_float; - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * percent; - } else { - totals[k] += *(const GLshort*)temp_index * percent; - } - } - } else if (highx_int > lowx_int) { - y_percent = highy_float - lowy_float; - percent = (1-lowx_float)*y_percent; - - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * percent; - } else { - totals[k] += *(const GLshort*)temp_index * percent; - } - } - for (l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * y_percent; - } else { - totals[k] += *(const GLshort*)temp_index * y_percent; - } - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * percent; - } else { - totals[k] += *(const GLshort*)temp_index * percent; - } - } - } else { - percent = (highy_float-lowy_float)*(highx_float-lowx_float); - temp = (const char *)datain + xindex + lowy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf * percent; - } else { - totals[k] += *(const GLshort*)temp_index * percent; - } - } - } - - /* this is for the pixels in the body */ - temp0 = (const char *)datain + xindex + group_size + - (lowy_int+1)*ysize; - for (m = lowy_int+1; m < highy_int; m++) { - temp = temp0; - for(l = lowx_int+1; l < highx_int; l++) { - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_2_BYTES(temp_index); - totals[k] += *(const GLshort*)&swapbuf; - } else { - totals[k] += *(const GLshort*)temp_index; - } - } - temp += group_size; - } - temp0 += ysize; - } - - outindex = (j + (i * widthout)) * components; - for (k = 0; k < components; k++) { - dataout[outindex + k] = totals[k]/area; - /*printf("totals[%d] = %f\n", k, totals[k]);*/ - } - lowx_int = highx_int; - lowx_float = highx_float; - highx_int += convx_int; - highx_float += convx_float; - if(highx_float > 1) { - highx_float -= 1.0; - highx_int++; - } - } - lowy_int = highy_int; - lowy_float = highy_float; - highy_int += convy_int; - highy_float += convy_float; - if(highy_float > 1) { - highy_float -= 1.0; - highy_int++; - } - } -} - -static void scale_internal_uint(GLint components, GLint widthin, - GLint heightin, const GLuint *datain, - GLint widthout, GLint heightout, - GLuint *dataout, GLint element_size, - GLint ysize, GLint group_size, - GLint myswap_bytes) -{ - float convx; - float convy; - float percent; - /* Max components in a format is 4, so... */ - float totals[4]; - float area; - int i,j,k,xindex; - - const char *temp, *temp0; - const char *temp_index; - int outindex; - - int lowx_int, highx_int, lowy_int, highy_int; - float x_percent, y_percent; - float lowx_float, highx_float, lowy_float, highy_float; - float convy_float, convx_float; - int convy_int, convx_int; - int l, m; - const char *left, *right; - - if (widthin == widthout*2 && heightin == heightout*2) { - halveImage_uint(components, widthin, heightin, - (const GLuint *)datain, (GLuint *)dataout, - element_size, ysize, group_size, myswap_bytes); - return; - } - convy = (float) heightin/heightout; - convx = (float) widthin/widthout; - convy_int = floor(convy); - convy_float = convy - convy_int; - convx_int = floor(convx); - convx_float = convx - convx_int; - - area = convx * convy; - - lowy_int = 0; - lowy_float = 0; - highy_int = convy_int; - highy_float = convy_float; - - for (i = 0; i < heightout; i++) { - /* Clamp here to be sure we don't read beyond input buffer. */ - if (highy_int >= heightin) - highy_int = heightin - 1; - lowx_int = 0; - lowx_float = 0; - highx_int = convx_int; - highx_float = convx_float; - - for (j = 0; j < widthout; j++) { - /* - ** Ok, now apply box filter to box that goes from (lowx, lowy) - ** to (highx, highy) on input data into this pixel on output - ** data. - */ - totals[0] = totals[1] = totals[2] = totals[3] = 0.0; - - /* calculate the value for pixels in the 1st row */ - xindex = lowx_int*group_size; - if((highy_int>lowy_int) && (highx_int>lowx_int)) { - - y_percent = 1-lowy_float; - temp = (const char *)datain + xindex + lowy_int * ysize; - percent = y_percent * (1-lowx_float); - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLuint*)temp_index * percent; - } - } - left = temp; - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_4_BYTES(temp_index) * y_percent; - } else { - totals[k] += *(const GLuint*)temp_index * y_percent; - } - } - } - temp += group_size; - right = temp; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLuint*)temp_index * percent; - } - } - - /* calculate the value for pixels in the last row */ - y_percent = highy_float; - percent = y_percent * (1-lowx_float); - temp = (const char *)datain + xindex + highy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLuint*)temp_index * percent; - } - } - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_4_BYTES(temp_index) * y_percent; - } else { - totals[k] += *(const GLuint*)temp_index * y_percent; - } - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLuint*)temp_index * percent; - } - } - - /* calculate the value for pixels in the 1st and last column */ - for(m = lowy_int+1; m < highy_int; m++) { - left += ysize; - right += ysize; - for (k = 0; k < components; - k++, left += element_size, right += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_4_BYTES(left) * (1-lowx_float) - + __GLU_SWAP_4_BYTES(right) * highx_float; - } else { - totals[k] += *(const GLuint*)left * (1-lowx_float) - + *(const GLuint*)right * highx_float; - } - } - } - } else if (highy_int > lowy_int) { - x_percent = highx_float - lowx_float; - percent = (1-lowy_float)*x_percent; - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLuint*)temp_index * percent; - } - } - for(m = lowy_int+1; m < highy_int; m++) { - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_4_BYTES(temp_index) * x_percent; - } else { - totals[k] += *(const GLuint*)temp_index * x_percent; - } - } - } - percent = x_percent * highy_float; - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLuint*)temp_index * percent; - } - } - } else if (highx_int > lowx_int) { - y_percent = highy_float - lowy_float; - percent = (1-lowx_float)*y_percent; - - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLuint*)temp_index * percent; - } - } - for (l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_4_BYTES(temp_index) * y_percent; - } else { - totals[k] += *(const GLuint*)temp_index * y_percent; - } - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLuint*)temp_index * percent; - } - } - } else { - percent = (highy_float-lowy_float)*(highx_float-lowx_float); - temp = (const char *)datain + xindex + lowy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_4_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLuint*)temp_index * percent; - } - } - } - - /* this is for the pixels in the body */ - temp0 = (const char *)datain + xindex + group_size + - (lowy_int+1)*ysize; - for (m = lowy_int+1; m < highy_int; m++) { - temp = temp0; - for(l = lowx_int+1; l < highx_int; l++) { - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_4_BYTES(temp_index); - } else { - totals[k] += *(const GLuint*)temp_index; - } - } - temp += group_size; - } - temp0 += ysize; - } - - outindex = (j + (i * widthout)) * components; - for (k = 0; k < components; k++) { - /* clamp at UINT_MAX */ - float value= totals[k]/area; - if (value >= (float) UINT_MAX) { /* need '=' */ - dataout[outindex + k] = UINT_MAX; - } - else dataout[outindex + k] = value; - } - lowx_int = highx_int; - lowx_float = highx_float; - highx_int += convx_int; - highx_float += convx_float; - if(highx_float > 1) { - highx_float -= 1.0; - highx_int++; - } - } - lowy_int = highy_int; - lowy_float = highy_float; - highy_int += convy_int; - highy_float += convy_float; - if(highy_float > 1) { - highy_float -= 1.0; - highy_int++; - } - } -} - - - -static void scale_internal_int(GLint components, GLint widthin, - GLint heightin, const GLint *datain, - GLint widthout, GLint heightout, - GLint *dataout, GLint element_size, - GLint ysize, GLint group_size, - GLint myswap_bytes) -{ - float convx; - float convy; - float percent; - /* Max components in a format is 4, so... */ - float totals[4]; - float area; - int i,j,k,xindex; - - const char *temp, *temp0; - const char *temp_index; - int outindex; - - int lowx_int, highx_int, lowy_int, highy_int; - float x_percent, y_percent; - float lowx_float, highx_float, lowy_float, highy_float; - float convy_float, convx_float; - int convy_int, convx_int; - int l, m; - const char *left, *right; - - GLuint swapbuf; /* unsigned buffer */ - - if (widthin == widthout*2 && heightin == heightout*2) { - halveImage_int(components, widthin, heightin, - (const GLint *)datain, (GLint *)dataout, - element_size, ysize, group_size, myswap_bytes); - return; - } - convy = (float) heightin/heightout; - convx = (float) widthin/widthout; - convy_int = floor(convy); - convy_float = convy - convy_int; - convx_int = floor(convx); - convx_float = convx - convx_int; - - area = convx * convy; - - lowy_int = 0; - lowy_float = 0; - highy_int = convy_int; - highy_float = convy_float; - - for (i = 0; i < heightout; i++) { - /* Clamp here to be sure we don't read beyond input buffer. */ - if (highy_int >= heightin) - highy_int = heightin - 1; - lowx_int = 0; - lowx_float = 0; - highx_int = convx_int; - highx_float = convx_float; - - for (j = 0; j < widthout; j++) { - /* - ** Ok, now apply box filter to box that goes from (lowx, lowy) - ** to (highx, highy) on input data into this pixel on output - ** data. - */ - totals[0] = totals[1] = totals[2] = totals[3] = 0.0; - - /* calculate the value for pixels in the 1st row */ - xindex = lowx_int*group_size; - if((highy_int>lowy_int) && (highx_int>lowx_int)) { - - y_percent = 1-lowy_float; - temp = (const char *)datain + xindex + lowy_int * ysize; - percent = y_percent * (1-lowx_float); - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * percent; - } else { - totals[k] += *(const GLint*)temp_index * percent; - } - } - left = temp; - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * y_percent; - } else { - totals[k] += *(const GLint*)temp_index * y_percent; - } - } - } - temp += group_size; - right = temp; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * percent; - } else { - totals[k] += *(const GLint*)temp_index * percent; - } - } - - /* calculate the value for pixels in the last row */ - y_percent = highy_float; - percent = y_percent * (1-lowx_float); - temp = (const char *)datain + xindex + highy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * percent; - } else { - totals[k] += *(const GLint*)temp_index * percent; - } - } - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * y_percent; - } else { - totals[k] += *(const GLint*)temp_index * y_percent; - } - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * percent; - } else { - totals[k] += *(const GLint*)temp_index * percent; - } - } - - /* calculate the value for pixels in the 1st and last column */ - for(m = lowy_int+1; m < highy_int; m++) { - left += ysize; - right += ysize; - for (k = 0; k < components; - k++, left += element_size, right += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(left); - totals[k] += *(const GLint*)&swapbuf * (1-lowx_float); - swapbuf = __GLU_SWAP_4_BYTES(right); - totals[k] += *(const GLint*)&swapbuf * highx_float; - } else { - totals[k] += *(const GLint*)left * (1-lowx_float) - + *(const GLint*)right * highx_float; - } - } - } - } else if (highy_int > lowy_int) { - x_percent = highx_float - lowx_float; - percent = (1-lowy_float)*x_percent; - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * percent; - } else { - totals[k] += *(const GLint*)temp_index * percent; - } - } - for(m = lowy_int+1; m < highy_int; m++) { - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * x_percent; - } else { - totals[k] += *(const GLint*)temp_index * x_percent; - } - } - } - percent = x_percent * highy_float; - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * percent; - } else { - totals[k] += *(const GLint*)temp_index * percent; - } - } - } else if (highx_int > lowx_int) { - y_percent = highy_float - lowy_float; - percent = (1-lowx_float)*y_percent; - - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * percent; - } else { - totals[k] += *(const GLint*)temp_index * percent; - } - } - for (l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * y_percent; - } else { - totals[k] += *(const GLint*)temp_index * y_percent; - } - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * percent; - } else { - totals[k] += *(const GLint*)temp_index * percent; - } - } - } else { - percent = (highy_float-lowy_float)*(highx_float-lowx_float); - temp = (const char *)datain + xindex + lowy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf * percent; - } else { - totals[k] += *(const GLint*)temp_index * percent; - } - } - } - - /* this is for the pixels in the body */ - temp0 = (const char *)datain + xindex + group_size + - (lowy_int+1)*ysize; - for (m = lowy_int+1; m < highy_int; m++) { - temp = temp0; - for(l = lowx_int+1; l < highx_int; l++) { - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += *(const GLint*)&swapbuf; - } else { - totals[k] += *(const GLint*)temp_index; - } - } - temp += group_size; - } - temp0 += ysize; - } - - outindex = (j + (i * widthout)) * components; - for (k = 0; k < components; k++) { - dataout[outindex + k] = totals[k]/area; - /*printf("totals[%d] = %f\n", k, totals[k]);*/ - } - lowx_int = highx_int; - lowx_float = highx_float; - highx_int += convx_int; - highx_float += convx_float; - if(highx_float > 1) { - highx_float -= 1.0; - highx_int++; - } - } - lowy_int = highy_int; - lowy_float = highy_float; - highy_int += convy_int; - highy_float += convy_float; - if(highy_float > 1) { - highy_float -= 1.0; - highy_int++; - } - } -} - - - -static void scale_internal_float(GLint components, GLint widthin, - GLint heightin, const GLfloat *datain, - GLint widthout, GLint heightout, - GLfloat *dataout, GLint element_size, - GLint ysize, GLint group_size, - GLint myswap_bytes) -{ - float convx; - float convy; - float percent; - /* Max components in a format is 4, so... */ - float totals[4]; - float area; - int i,j,k,xindex; - - const char *temp, *temp0; - const char *temp_index; - int outindex; - - int lowx_int, highx_int, lowy_int, highy_int; - float x_percent, y_percent; - float lowx_float, highx_float, lowy_float, highy_float; - float convy_float, convx_float; - int convy_int, convx_int; - int l, m; - const char *left, *right; - - union { GLuint b; GLfloat f; } swapbuf; - - if (widthin == widthout*2 && heightin == heightout*2) { - halveImage_float(components, widthin, heightin, - (const GLfloat *)datain, (GLfloat *)dataout, - element_size, ysize, group_size, myswap_bytes); - return; - } - convy = (float) heightin/heightout; - convx = (float) widthin/widthout; - convy_int = floor(convy); - convy_float = convy - convy_int; - convx_int = floor(convx); - convx_float = convx - convx_int; - - area = convx * convy; - - lowy_int = 0; - lowy_float = 0; - highy_int = convy_int; - highy_float = convy_float; - - for (i = 0; i < heightout; i++) { - /* Clamp here to be sure we don't read beyond input buffer. */ - if (highy_int >= heightin) - highy_int = heightin - 1; - lowx_int = 0; - lowx_float = 0; - highx_int = convx_int; - highx_float = convx_float; - - for (j = 0; j < widthout; j++) { - /* - ** Ok, now apply box filter to box that goes from (lowx, lowy) - ** to (highx, highy) on input data into this pixel on output - ** data. - */ - totals[0] = totals[1] = totals[2] = totals[3] = 0.0; - - /* calculate the value for pixels in the 1st row */ - xindex = lowx_int*group_size; - if((highy_int>lowy_int) && (highx_int>lowx_int)) { - - y_percent = 1-lowy_float; - temp = (const char *)datain + xindex + lowy_int * ysize; - percent = y_percent * (1-lowx_float); - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * percent; - } else { - totals[k] += *(const GLfloat*)temp_index * percent; - } - } - left = temp; - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * y_percent; - } else { - totals[k] += *(const GLfloat*)temp_index * y_percent; - } - } - } - temp += group_size; - right = temp; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * percent; - } else { - totals[k] += *(const GLfloat*)temp_index * percent; - } - } - - /* calculate the value for pixels in the last row */ - y_percent = highy_float; - percent = y_percent * (1-lowx_float); - temp = (const char *)datain + xindex + highy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * percent; - } else { - totals[k] += *(const GLfloat*)temp_index * percent; - } - } - for(l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * y_percent; - } else { - totals[k] += *(const GLfloat*)temp_index * y_percent; - } - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * percent; - } else { - totals[k] += *(const GLfloat*)temp_index * percent; - } - } - - /* calculate the value for pixels in the 1st and last column */ - for(m = lowy_int+1; m < highy_int; m++) { - left += ysize; - right += ysize; - for (k = 0; k < components; - k++, left += element_size, right += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(left); - totals[k] += swapbuf.f * (1-lowx_float); - swapbuf.b = __GLU_SWAP_4_BYTES(right); - totals[k] += swapbuf.f * highx_float; - } else { - totals[k] += *(const GLfloat*)left * (1-lowx_float) - + *(const GLfloat*)right * highx_float; - } - } - } - } else if (highy_int > lowy_int) { - x_percent = highx_float - lowx_float; - percent = (1-lowy_float)*x_percent; - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * percent; - } else { - totals[k] += *(const GLfloat*)temp_index * percent; - } - } - for(m = lowy_int+1; m < highy_int; m++) { - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * x_percent; - } else { - totals[k] += *(const GLfloat*)temp_index * x_percent; - } - } - } - percent = x_percent * highy_float; - temp += ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * percent; - } else { - totals[k] += *(const GLfloat*)temp_index * percent; - } - } - } else if (highx_int > lowx_int) { - y_percent = highy_float - lowy_float; - percent = (1-lowx_float)*y_percent; - - temp = (const char *)datain + xindex + lowy_int*ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * percent; - } else { - totals[k] += *(const GLfloat*)temp_index * percent; - } - } - for (l = lowx_int+1; l < highx_int; l++) { - temp += group_size; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * y_percent; - } else { - totals[k] += *(const GLfloat*)temp_index * y_percent; - } - } - } - temp += group_size; - percent = y_percent * highx_float; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * percent; - } else { - totals[k] += *(const GLfloat*)temp_index * percent; - } - } - } else { - percent = (highy_float-lowy_float)*(highx_float-lowx_float); - temp = (const char *)datain + xindex + lowy_int * ysize; - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f * percent; - } else { - totals[k] += *(const GLfloat*)temp_index * percent; - } - } - } - - /* this is for the pixels in the body */ - temp0 = (const char *)datain + xindex + group_size + - (lowy_int+1)*ysize; - for (m = lowy_int+1; m < highy_int; m++) { - temp = temp0; - for(l = lowx_int+1; l < highx_int; l++) { - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - swapbuf.b = __GLU_SWAP_4_BYTES(temp_index); - totals[k] += swapbuf.f; - } else { - totals[k] += *(const GLfloat*)temp_index; - } - } - temp += group_size; - } - temp0 += ysize; - } - - outindex = (j + (i * widthout)) * components; - for (k = 0; k < components; k++) { - dataout[outindex + k] = totals[k]/area; - /*printf("totals[%d] = %f\n", k, totals[k]);*/ - } - lowx_int = highx_int; - lowx_float = highx_float; - highx_int += convx_int; - highx_float += convx_float; - if(highx_float > 1) { - highx_float -= 1.0; - highx_int++; - } - } - lowy_int = highy_int; - lowy_float = highy_float; - highy_int += convy_int; - highy_float += convy_float; - if(highy_float > 1) { - highy_float -= 1.0; - highy_int++; - } - } -} - -static int checkMipmapArgs(GLenum internalFormat, GLenum format, GLenum type) -{ - if (!legalFormat(format) || !legalType(type)) { - return GLU_INVALID_ENUM; - } - if (format == GL_STENCIL_INDEX) { - return GLU_INVALID_ENUM; - } - - if (!isLegalFormatForPackedPixelType(format, type)) { - return GLU_INVALID_OPERATION; - } - - return 0; -} /* checkMipmapArgs() */ - -static GLboolean legalFormat(GLenum format) -{ - 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_RGB: - case GL_RGBA: - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - case GL_BGR: - case GL_BGRA: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -static GLboolean legalType(GLenum type) -{ - switch(type) { - case GL_BITMAP: - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - return GL_TRUE; - default: - return GL_FALSE; - } -} - -/* */ -static GLboolean isTypePackedPixel(GLenum type) -{ - assert(legalType(type)); - - if (type == GL_UNSIGNED_BYTE_3_3_2 || - type == GL_UNSIGNED_BYTE_2_3_3_REV || - type == GL_UNSIGNED_SHORT_5_6_5 || - type == GL_UNSIGNED_SHORT_5_6_5_REV || - type == GL_UNSIGNED_SHORT_4_4_4_4 || - type == GL_UNSIGNED_SHORT_4_4_4_4_REV || - type == GL_UNSIGNED_SHORT_5_5_5_1 || - type == GL_UNSIGNED_SHORT_1_5_5_5_REV || - type == GL_UNSIGNED_INT_8_8_8_8 || - type == GL_UNSIGNED_INT_8_8_8_8_REV || - type == GL_UNSIGNED_INT_10_10_10_2 || - type == GL_UNSIGNED_INT_2_10_10_10_REV) { - return 1; - } - else return 0; -} /* isTypePackedPixel() */ - -/* Determines if the packed pixel type is compatible with the format */ -static GLboolean isLegalFormatForPackedPixelType(GLenum format, GLenum type) -{ - /* if not a packed pixel type then return true */ - if (!isTypePackedPixel(type)) { - return GL_TRUE; - } - - /* 3_3_2/2_3_3_REV & 5_6_5/5_6_5_REV are only compatible with RGB */ - if ((type == GL_UNSIGNED_BYTE_3_3_2 || type == GL_UNSIGNED_BYTE_2_3_3_REV|| - type == GL_UNSIGNED_SHORT_5_6_5|| type == GL_UNSIGNED_SHORT_5_6_5_REV) - && format != GL_RGB) - return GL_FALSE; - - /* 4_4_4_4/4_4_4_4_REV & 5_5_5_1/1_5_5_5_REV & 8_8_8_8/8_8_8_8_REV & - * 10_10_10_2/2_10_10_10_REV are only compatible with RGBA, BGRA & ABGR_EXT. - */ - if ((type == GL_UNSIGNED_SHORT_4_4_4_4 || - type == GL_UNSIGNED_SHORT_4_4_4_4_REV || - type == GL_UNSIGNED_SHORT_5_5_5_1 || - type == GL_UNSIGNED_SHORT_1_5_5_5_REV || - type == GL_UNSIGNED_INT_8_8_8_8 || - type == GL_UNSIGNED_INT_8_8_8_8_REV || - type == GL_UNSIGNED_INT_10_10_10_2 || - type == GL_UNSIGNED_INT_2_10_10_10_REV) && - (format != GL_RGBA && - format != GL_BGRA)) { - return GL_FALSE; - } - - return GL_TRUE; -} /* isLegalFormatForPackedPixelType() */ - -static GLboolean isLegalLevels(GLint userLevel,GLint baseLevel,GLint maxLevel, - GLint totalLevels) -{ - if (baseLevel < 0 || baseLevel < userLevel || maxLevel < baseLevel || - totalLevels < maxLevel) - return GL_FALSE; - else return GL_TRUE; -} /* isLegalLevels() */ - -/* Given user requested texture size, determine if it fits. If it - * doesn't then halve both sides and make the determination again - * until it does fit (for IR only). - * Note that proxy textures are not implemented in RE* even though - * they advertise the texture extension. - * Note that proxy textures are implemented but not according to spec in - * IMPACT*. - */ -static void closestFit(GLenum target, GLint width, GLint height, - GLint internalFormat, GLenum format, GLenum type, - GLint *newWidth, GLint *newHeight) -{ - /* Use proxy textures if OpenGL version is >= 1.1 */ - if ( (strtod((const char *)glGetString(GL_VERSION),NULL) >= 1.1) - ) { - GLint widthPowerOf2= nearestPower(width); - GLint heightPowerOf2= nearestPower(height); - GLint proxyWidth; - - do { - /* compute level 1 width & height, clamping each at 1 */ - GLint widthAtLevelOne= (widthPowerOf2 > 1) ? - widthPowerOf2 >> 1 : - widthPowerOf2; - GLint heightAtLevelOne= (heightPowerOf2 > 1) ? - heightPowerOf2 >> 1 : - heightPowerOf2; - GLenum proxyTarget; - assert(widthAtLevelOne > 0); assert(heightAtLevelOne > 0); - - /* does width x height at level 1 & all their mipmaps fit? */ - if (target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D) { - proxyTarget = GL_PROXY_TEXTURE_2D; - glTexImage2D(proxyTarget, 1, /* must be non-zero */ - internalFormat, - widthAtLevelOne,heightAtLevelOne,0,format,type,NULL); - } else -#if defined(GL_ARB_texture_cube_map) - if ((target == GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB) || - (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB) || - (target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB) || - (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB) || - (target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB) || - (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) { - proxyTarget = GL_PROXY_TEXTURE_CUBE_MAP_ARB; - glTexImage2D(proxyTarget, 1, /* must be non-zero */ - internalFormat, - widthAtLevelOne,heightAtLevelOne,0,format,type,NULL); - } else -#endif /* GL_ARB_texture_cube_map */ - { - assert(target == GL_TEXTURE_1D || target == GL_PROXY_TEXTURE_1D); - proxyTarget = GL_PROXY_TEXTURE_1D; - glTexImage1D(proxyTarget, 1, /* must be non-zero */ - internalFormat,widthAtLevelOne,0,format,type,NULL); - } - glGetTexLevelParameteriv(proxyTarget, 1,GL_TEXTURE_WIDTH,&proxyWidth); - /* does it fit??? */ - if (proxyWidth == 0) { /* nope, so try again with these sizes */ - if (widthPowerOf2 == 1 && heightPowerOf2 == 1) { - /* An 1x1 texture couldn't fit for some reason, so - * break out. This should never happen. But things - * happen. The disadvantage with this if-statement is - * that we will never be aware of when this happens - * since it will silently branch out. - */ - goto noProxyTextures; - } - widthPowerOf2= widthAtLevelOne; - heightPowerOf2= heightAtLevelOne; - } - /* else it does fit */ - } while (proxyWidth == 0); - /* loop must terminate! */ - - /* return the width & height at level 0 that fits */ - *newWidth= widthPowerOf2; - *newHeight= heightPowerOf2; -/*printf("Proxy Textures\n");*/ - } /* if gluCheckExtension() */ - else { /* no texture extension, so do this instead */ - GLint maxsize; - -noProxyTextures: - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); - /* clamp user's texture sizes to maximum sizes, if necessary */ - *newWidth = nearestPower(width); - if (*newWidth > maxsize) *newWidth = maxsize; - *newHeight = nearestPower(height); - if (*newHeight > maxsize) *newHeight = maxsize; -/*printf("NO proxy textures\n");*/ - } -} /* closestFit() */ - -GLint GLAPIENTRY -gluScaleImage(GLenum format, GLsizei widthin, GLsizei heightin, - GLenum typein, const void *datain, - GLsizei widthout, GLsizei heightout, GLenum typeout, - void *dataout) -{ - int components; - GLushort *beforeImage; - GLushort *afterImage; - PixelStorageModes psm; - - if (widthin == 0 || heightin == 0 || widthout == 0 || heightout == 0) { - return 0; - } - if (widthin < 0 || heightin < 0 || widthout < 0 || heightout < 0) { - return GLU_INVALID_VALUE; - } - if (!legalFormat(format) || !legalType(typein) || !legalType(typeout)) { - return GLU_INVALID_ENUM; - } - if (!isLegalFormatForPackedPixelType(format, typein)) { - return GLU_INVALID_OPERATION; - } - if (!isLegalFormatForPackedPixelType(format, typeout)) { - return GLU_INVALID_OPERATION; - } - beforeImage = - malloc(image_size(widthin, heightin, format, GL_UNSIGNED_SHORT)); - afterImage = - malloc(image_size(widthout, heightout, format, GL_UNSIGNED_SHORT)); - if (beforeImage == NULL || afterImage == NULL) { - return GLU_OUT_OF_MEMORY; - } - - retrieveStoreModes(&psm); - fill_image(&psm,widthin, heightin, format, typein, is_index(format), - datain, beforeImage); - components = elements_per_group(format, 0); - scale_internal(components, widthin, heightin, beforeImage, - widthout, heightout, afterImage); - empty_image(&psm,widthout, heightout, format, typeout, - is_index(format), afterImage, dataout); - free((GLbyte *) beforeImage); - free((GLbyte *) afterImage); - - return 0; -} - -int gluBuild1DMipmapLevelsCore(GLenum target, GLint internalFormat, - GLsizei width, - GLsizei widthPowerOf2, - GLenum format, GLenum type, - GLint userLevel, GLint baseLevel,GLint maxLevel, - const void *data) -{ - GLint newwidth; - GLint level, levels; - GLushort *newImage; - GLint newImage_width; - GLushort *otherImage; - GLushort *imageTemp; - GLint memreq; - GLint cmpts; - PixelStorageModes psm; - - assert(checkMipmapArgs(internalFormat,format,type) == 0); - assert(width >= 1); - - otherImage = NULL; - - newwidth= widthPowerOf2; - levels = computeLog(newwidth); - - levels+= userLevel; - - retrieveStoreModes(&psm); - newImage = (GLushort *) - malloc(image_size(width, 1, format, GL_UNSIGNED_SHORT)); - newImage_width = width; - if (newImage == NULL) { - return GLU_OUT_OF_MEMORY; - } - fill_image(&psm,width, 1, format, type, is_index(format), - data, newImage); - cmpts = elements_per_group(format,type); - glPixelStorei(GL_UNPACK_ALIGNMENT, 2); - glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - /* - ** If swap_bytes was set, swapping occurred in fill_image. - */ - glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); - - for (level = userLevel; level <= levels; level++) { - if (newImage_width == newwidth) { - /* Use newImage for this level */ - if (baseLevel <= level && level <= maxLevel) { - glTexImage1D(target, level, internalFormat, newImage_width, - 0, format, GL_UNSIGNED_SHORT, (void *) newImage); - } - } else { - if (otherImage == NULL) { - memreq = image_size(newwidth, 1, format, GL_UNSIGNED_SHORT); - otherImage = (GLushort *) malloc(memreq); - if (otherImage == NULL) { - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS,psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - return GLU_OUT_OF_MEMORY; - } - } - scale_internal(cmpts, newImage_width, 1, newImage, - newwidth, 1, otherImage); - /* Swap newImage and otherImage */ - imageTemp = otherImage; - otherImage = newImage; - newImage = imageTemp; - - newImage_width = newwidth; - if (baseLevel <= level && level <= maxLevel) { - glTexImage1D(target, level, internalFormat, newImage_width, - 0, format, GL_UNSIGNED_SHORT, (void *) newImage); - } - } - if (newwidth > 1) newwidth /= 2; - } - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - - free((GLbyte *) newImage); - if (otherImage) { - free((GLbyte *) otherImage); - } - return 0; -} - -GLint GLAPIENTRY -gluBuild1DMipmapLevels(GLenum target, GLint internalFormat, - GLsizei width, - GLenum format, GLenum type, - GLint userLevel, GLint baseLevel, GLint maxLevel, - const void *data) -{ - int levels; - - int rc= checkMipmapArgs(internalFormat,format,type); - if (rc != 0) return rc; - - if (width < 1) { - return GLU_INVALID_VALUE; - } - - levels = computeLog(width); - - levels+= userLevel; - if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels)) - return GLU_INVALID_VALUE; - - return gluBuild1DMipmapLevelsCore(target, internalFormat, - width, - width,format, type, - userLevel, baseLevel, maxLevel, - data); -} /* gluBuild1DMipmapLevels() */ - -GLint GLAPIENTRY -gluBuild1DMipmaps(GLenum target, GLint internalFormat, GLsizei width, - GLenum format, GLenum type, - const void *data) -{ - GLint widthPowerOf2; - int levels; - GLint dummy; - - int rc= checkMipmapArgs(internalFormat,format,type); - if (rc != 0) return rc; - - if (width < 1) { - return GLU_INVALID_VALUE; - } - - closestFit(target,width,1,internalFormat,format,type,&widthPowerOf2,&dummy); - levels = computeLog(widthPowerOf2); - - return gluBuild1DMipmapLevelsCore(target,internalFormat, - width, - widthPowerOf2, - format,type,0,0,levels,data); -} - -static int bitmapBuild2DMipmaps(GLenum target, GLint internalFormat, - GLint width, GLint height, GLenum format, - GLenum type, const void *data) -{ - GLint newwidth, newheight; - GLint level, levels; - GLushort *newImage; - GLint newImage_width; - GLint newImage_height; - GLushort *otherImage; - GLushort *imageTemp; - GLint memreq; - GLint cmpts; - PixelStorageModes psm; - - retrieveStoreModes(&psm); - -#if 0 - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); - newwidth = nearestPower(width); - if (newwidth > maxsize) newwidth = maxsize; - newheight = nearestPower(height); - if (newheight > maxsize) newheight = maxsize; -#else - closestFit(target,width,height,internalFormat,format,type, - &newwidth,&newheight); -#endif - levels = computeLog(newwidth); - level = computeLog(newheight); - if (level > levels) levels=level; - - otherImage = NULL; - newImage = (GLushort *) - malloc(image_size(width, height, format, GL_UNSIGNED_SHORT)); - newImage_width = width; - newImage_height = height; - if (newImage == NULL) { - return GLU_OUT_OF_MEMORY; - } - - fill_image(&psm,width, height, format, type, is_index(format), - data, newImage); - - cmpts = elements_per_group(format,type); - glPixelStorei(GL_UNPACK_ALIGNMENT, 2); - glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - /* - ** If swap_bytes was set, swapping occurred in fill_image. - */ - glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); - - for (level = 0; level <= levels; level++) { - if (newImage_width == newwidth && newImage_height == newheight) { /* Use newImage for this level */ - glTexImage2D(target, level, internalFormat, newImage_width, - newImage_height, 0, format, GL_UNSIGNED_SHORT, - (void *) newImage); - } else { - if (otherImage == NULL) { - memreq = - image_size(newwidth, newheight, format, GL_UNSIGNED_SHORT); - otherImage = (GLushort *) malloc(memreq); - if (otherImage == NULL) { - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS,psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - return GLU_OUT_OF_MEMORY; - } - } - scale_internal(cmpts, newImage_width, newImage_height, newImage, - newwidth, newheight, otherImage); - /* Swap newImage and otherImage */ - imageTemp = otherImage; - otherImage = newImage; - newImage = imageTemp; - - newImage_width = newwidth; - newImage_height = newheight; - glTexImage2D(target, level, internalFormat, newImage_width, - newImage_height, 0, format, GL_UNSIGNED_SHORT, - (void *) newImage); - } - if (newwidth > 1) newwidth /= 2; - if (newheight > 1) newheight /= 2; - } - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - - free((GLbyte *) newImage); - if (otherImage) { - free((GLbyte *) otherImage); - } - return 0; -} - -/* To make swapping images less error prone */ -#define __GLU_INIT_SWAP_IMAGE void *tmpImage -#define __GLU_SWAP_IMAGE(a,b) tmpImage = a; a = b; b = tmpImage; - -static int gluBuild2DMipmapLevelsCore(GLenum target, GLint internalFormat, - GLsizei width, GLsizei height, - GLsizei widthPowerOf2, - GLsizei heightPowerOf2, - GLenum format, GLenum type, - GLint userLevel, - GLint baseLevel,GLint maxLevel, - const void *data) -{ - GLint newwidth, newheight; - GLint level, levels; - const void *usersImage; /* passed from user. Don't touch! */ - void *srcImage, *dstImage; /* scratch area to build mipmapped images */ - __GLU_INIT_SWAP_IMAGE; - GLint memreq; - GLint cmpts; - - GLint myswap_bytes, groups_per_line, element_size, group_size; - GLint rowsize, padding; - PixelStorageModes psm; - - assert(checkMipmapArgs(internalFormat,format,type) == 0); - assert(width >= 1 && height >= 1); - - if(type == GL_BITMAP) { - return bitmapBuild2DMipmaps(target, internalFormat, width, height, - format, type, data); - } - - srcImage = dstImage = NULL; - - newwidth= widthPowerOf2; - newheight= heightPowerOf2; - levels = computeLog(newwidth); - level = computeLog(newheight); - if (level > levels) levels=level; - - levels+= userLevel; - - retrieveStoreModes(&psm); - myswap_bytes = psm.unpack_swap_bytes; - cmpts = elements_per_group(format,type); - if (psm.unpack_row_length > 0) { - groups_per_line = psm.unpack_row_length; - } else { - groups_per_line = width; - } - - element_size = bytes_per_element(type); - group_size = element_size * cmpts; - if (element_size == 1) myswap_bytes = 0; - - rowsize = groups_per_line * group_size; - padding = (rowsize % psm.unpack_alignment); - if (padding) { - rowsize += psm.unpack_alignment - padding; - } - usersImage = (const GLubyte *) data + psm.unpack_skip_rows * rowsize + - psm.unpack_skip_pixels * group_size; - - glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - level = userLevel; - - /* already power-of-two square */ - if (width == newwidth && height == newheight) { - /* Use usersImage for level userLevel */ - if (baseLevel <= level && level <= maxLevel) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glTexImage2D(target, level, internalFormat, width, - height, 0, format, type, - usersImage); - } - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - if(levels == 0) { /* we're done. clean up and return */ - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - return 0; - } - { - int nextWidth= newwidth/2; - int nextHeight= newheight/2; - - /* clamp to 1 */ - if (nextWidth < 1) nextWidth= 1; - if (nextHeight < 1) nextHeight= 1; - memreq = image_size(nextWidth, nextHeight, format, type); - } - - switch(type) { - case GL_UNSIGNED_BYTE: - dstImage = (GLubyte *)malloc(memreq); - break; - case GL_BYTE: - dstImage = (GLbyte *)malloc(memreq); - break; - case GL_UNSIGNED_SHORT: - dstImage = (GLushort *)malloc(memreq); - break; - case GL_SHORT: - dstImage = (GLshort *)malloc(memreq); - break; - case GL_UNSIGNED_INT: - dstImage = (GLuint *)malloc(memreq); - break; - case GL_INT: - dstImage = (GLint *)malloc(memreq); - break; - case GL_FLOAT: - dstImage = (GLfloat *)malloc(memreq); - break; - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - dstImage = (GLubyte *)malloc(memreq); - break; - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - dstImage = (GLushort *)malloc(memreq); - break; - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - dstImage = (GLuint *)malloc(memreq); - break; - default: - return GLU_INVALID_ENUM; - } - if (dstImage == NULL) { - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - return GLU_OUT_OF_MEMORY; - } - else - switch(type) { - case GL_UNSIGNED_BYTE: - halveImage_ubyte(cmpts, width, height, - (const GLubyte *)usersImage, (GLubyte *)dstImage, - element_size, rowsize, group_size); - break; - case GL_BYTE: - halveImage_byte(cmpts, width, height, - (const GLbyte *)usersImage, (GLbyte *)dstImage, - element_size, rowsize, group_size); - break; - case GL_UNSIGNED_SHORT: - halveImage_ushort(cmpts, width, height, - (const GLushort *)usersImage, (GLushort *)dstImage, - element_size, rowsize, group_size, myswap_bytes); - break; - case GL_SHORT: - halveImage_short(cmpts, width, height, - (const GLshort *)usersImage, (GLshort *)dstImage, - element_size, rowsize, group_size, myswap_bytes); - break; - case GL_UNSIGNED_INT: - halveImage_uint(cmpts, width, height, - (const GLuint *)usersImage, (GLuint *)dstImage, - element_size, rowsize, group_size, myswap_bytes); - break; - case GL_INT: - halveImage_int(cmpts, width, height, - (const GLint *)usersImage, (GLint *)dstImage, - element_size, rowsize, group_size, myswap_bytes); - break; - case GL_FLOAT: - halveImage_float(cmpts, width, height, - (const GLfloat *)usersImage, (GLfloat *)dstImage, - element_size, rowsize, group_size, myswap_bytes); - break; - case GL_UNSIGNED_BYTE_3_3_2: - assert(format == GL_RGB); - halveImagePackedPixel(3,extract332,shove332, - width,height,usersImage,dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_BYTE_2_3_3_REV: - assert(format == GL_RGB); - halveImagePackedPixel(3,extract233rev,shove233rev, - width,height,usersImage,dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_SHORT_5_6_5: - halveImagePackedPixel(3,extract565,shove565, - width,height,usersImage,dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_SHORT_5_6_5_REV: - halveImagePackedPixel(3,extract565rev,shove565rev, - width,height,usersImage,dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - halveImagePackedPixel(4,extract4444,shove4444, - width,height,usersImage,dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - halveImagePackedPixel(4,extract4444rev,shove4444rev, - width,height,usersImage,dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_SHORT_5_5_5_1: - halveImagePackedPixel(4,extract5551,shove5551, - width,height,usersImage,dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - halveImagePackedPixel(4,extract1555rev,shove1555rev, - width,height,usersImage,dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_INT_8_8_8_8: - halveImagePackedPixel(4,extract8888,shove8888, - width,height,usersImage,dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_INT_8_8_8_8_REV: - halveImagePackedPixel(4,extract8888rev,shove8888rev, - width,height,usersImage,dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_INT_10_10_10_2: - halveImagePackedPixel(4,extract1010102,shove1010102, - width,height,usersImage,dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - halveImagePackedPixel(4,extract2101010rev,shove2101010rev, - width,height,usersImage,dstImage, - element_size,rowsize,myswap_bytes); - break; - default: - assert(0); - break; - } - newwidth = width/2; - newheight = height/2; - /* clamp to 1 */ - if (newwidth < 1) newwidth= 1; - if (newheight < 1) newheight= 1; - - myswap_bytes = 0; - rowsize = newwidth * group_size; - memreq = image_size(newwidth, newheight, format, type); - /* Swap srcImage and dstImage */ - __GLU_SWAP_IMAGE(srcImage,dstImage); - switch(type) { - case GL_UNSIGNED_BYTE: - dstImage = (GLubyte *)malloc(memreq); - break; - case GL_BYTE: - dstImage = (GLbyte *)malloc(memreq); - break; - case GL_UNSIGNED_SHORT: - dstImage = (GLushort *)malloc(memreq); - break; - case GL_SHORT: - dstImage = (GLshort *)malloc(memreq); - break; - case GL_UNSIGNED_INT: - dstImage = (GLuint *)malloc(memreq); - break; - case GL_INT: - dstImage = (GLint *)malloc(memreq); - break; - case GL_FLOAT: - dstImage = (GLfloat *)malloc(memreq); - break; - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - dstImage = (GLubyte *)malloc(memreq); - break; - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - dstImage = (GLushort *)malloc(memreq); - break; - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - dstImage = (GLuint *)malloc(memreq); - break; - default: - return GLU_INVALID_ENUM; - } - if (dstImage == NULL) { - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - return GLU_OUT_OF_MEMORY; - } - /* level userLevel+1 is in srcImage; level userLevel already saved */ - level = userLevel+1; - } else { /* user's image is *not* nice power-of-2 sized square */ - memreq = image_size(newwidth, newheight, format, type); - switch(type) { - case GL_UNSIGNED_BYTE: - dstImage = (GLubyte *)malloc(memreq); - break; - case GL_BYTE: - dstImage = (GLbyte *)malloc(memreq); - break; - case GL_UNSIGNED_SHORT: - dstImage = (GLushort *)malloc(memreq); - break; - case GL_SHORT: - dstImage = (GLshort *)malloc(memreq); - break; - case GL_UNSIGNED_INT: - dstImage = (GLuint *)malloc(memreq); - break; - case GL_INT: - dstImage = (GLint *)malloc(memreq); - break; - case GL_FLOAT: - dstImage = (GLfloat *)malloc(memreq); - break; - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - dstImage = (GLubyte *)malloc(memreq); - break; - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - dstImage = (GLushort *)malloc(memreq); - break; - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - dstImage = (GLuint *)malloc(memreq); - break; - default: - return GLU_INVALID_ENUM; - } - - if (dstImage == NULL) { - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - return GLU_OUT_OF_MEMORY; - } - - switch(type) { - case GL_UNSIGNED_BYTE: - scale_internal_ubyte(cmpts, width, height, - (const GLubyte *)usersImage, newwidth, newheight, - (GLubyte *)dstImage, element_size, - rowsize, group_size); - break; - case GL_BYTE: - scale_internal_byte(cmpts, width, height, - (const GLbyte *)usersImage, newwidth, newheight, - (GLbyte *)dstImage, element_size, - rowsize, group_size); - break; - case GL_UNSIGNED_SHORT: - scale_internal_ushort(cmpts, width, height, - (const GLushort *)usersImage, newwidth, newheight, - (GLushort *)dstImage, element_size, - rowsize, group_size, myswap_bytes); - break; - case GL_SHORT: - scale_internal_short(cmpts, width, height, - (const GLshort *)usersImage, newwidth, newheight, - (GLshort *)dstImage, element_size, - rowsize, group_size, myswap_bytes); - break; - case GL_UNSIGNED_INT: - scale_internal_uint(cmpts, width, height, - (const GLuint *)usersImage, newwidth, newheight, - (GLuint *)dstImage, element_size, - rowsize, group_size, myswap_bytes); - break; - case GL_INT: - scale_internal_int(cmpts, width, height, - (const GLint *)usersImage, newwidth, newheight, - (GLint *)dstImage, element_size, - rowsize, group_size, myswap_bytes); - break; - case GL_FLOAT: - scale_internal_float(cmpts, width, height, - (const GLfloat *)usersImage, newwidth, newheight, - (GLfloat *)dstImage, element_size, - rowsize, group_size, myswap_bytes); - break; - case GL_UNSIGNED_BYTE_3_3_2: - scaleInternalPackedPixel(3,extract332,shove332, - width, height,usersImage, - newwidth,newheight,(void *)dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_BYTE_2_3_3_REV: - scaleInternalPackedPixel(3,extract233rev,shove233rev, - width, height,usersImage, - newwidth,newheight,(void *)dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_SHORT_5_6_5: - scaleInternalPackedPixel(3,extract565,shove565, - width, height,usersImage, - newwidth,newheight,(void *)dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_SHORT_5_6_5_REV: - scaleInternalPackedPixel(3,extract565rev,shove565rev, - width, height,usersImage, - newwidth,newheight,(void *)dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - scaleInternalPackedPixel(4,extract4444,shove4444, - width, height,usersImage, - newwidth,newheight,(void *)dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - scaleInternalPackedPixel(4,extract4444rev,shove4444rev, - width, height,usersImage, - newwidth,newheight,(void *)dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_SHORT_5_5_5_1: - scaleInternalPackedPixel(4,extract5551,shove5551, - width, height,usersImage, - newwidth,newheight,(void *)dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - scaleInternalPackedPixel(4,extract1555rev,shove1555rev, - width, height,usersImage, - newwidth,newheight,(void *)dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_INT_8_8_8_8: - scaleInternalPackedPixel(4,extract8888,shove8888, - width, height,usersImage, - newwidth,newheight,(void *)dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_INT_8_8_8_8_REV: - scaleInternalPackedPixel(4,extract8888rev,shove8888rev, - width, height,usersImage, - newwidth,newheight,(void *)dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_INT_10_10_10_2: - scaleInternalPackedPixel(4,extract1010102,shove1010102, - width, height,usersImage, - newwidth,newheight,(void *)dstImage, - element_size,rowsize,myswap_bytes); - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - scaleInternalPackedPixel(4,extract2101010rev,shove2101010rev, - width, height,usersImage, - newwidth,newheight,(void *)dstImage, - element_size,rowsize,myswap_bytes); - break; - default: - assert(0); - break; - } - myswap_bytes = 0; - rowsize = newwidth * group_size; - /* Swap dstImage and srcImage */ - __GLU_SWAP_IMAGE(srcImage,dstImage); - - if(levels != 0) { /* use as little memory as possible */ - { - int nextWidth= newwidth/2; - int nextHeight= newheight/2; - if (nextWidth < 1) nextWidth= 1; - if (nextHeight < 1) nextHeight= 1; - - memreq = image_size(nextWidth, nextHeight, format, type); - } - - switch(type) { - case GL_UNSIGNED_BYTE: - dstImage = (GLubyte *)malloc(memreq); - break; - case GL_BYTE: - dstImage = (GLbyte *)malloc(memreq); - break; - case GL_UNSIGNED_SHORT: - dstImage = (GLushort *)malloc(memreq); - break; - case GL_SHORT: - dstImage = (GLshort *)malloc(memreq); - break; - case GL_UNSIGNED_INT: - dstImage = (GLuint *)malloc(memreq); - break; - case GL_INT: - dstImage = (GLint *)malloc(memreq); - break; - case GL_FLOAT: - dstImage = (GLfloat *)malloc(memreq); - break; - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - dstImage = (GLubyte *)malloc(memreq); - break; - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - dstImage = (GLushort *)malloc(memreq); - break; - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - dstImage = (GLuint *)malloc(memreq); - break; - default: - return GLU_INVALID_ENUM; - } - if (dstImage == NULL) { - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - return GLU_OUT_OF_MEMORY; - } - } - /* level userLevel is in srcImage; nothing saved yet */ - level = userLevel; - } - - glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); - if (baseLevel <= level && level <= maxLevel) { - glTexImage2D(target, level, internalFormat, newwidth, newheight, 0, - format, type, (void *)srcImage); - } - - level++; /* update current level for the loop */ - for (; level <= levels; level++) { - switch(type) { - case GL_UNSIGNED_BYTE: - halveImage_ubyte(cmpts, newwidth, newheight, - (GLubyte *)srcImage, (GLubyte *)dstImage, element_size, - rowsize, group_size); - break; - case GL_BYTE: - halveImage_byte(cmpts, newwidth, newheight, - (GLbyte *)srcImage, (GLbyte *)dstImage, element_size, - rowsize, group_size); - break; - case GL_UNSIGNED_SHORT: - halveImage_ushort(cmpts, newwidth, newheight, - (GLushort *)srcImage, (GLushort *)dstImage, element_size, - rowsize, group_size, myswap_bytes); - break; - case GL_SHORT: - halveImage_short(cmpts, newwidth, newheight, - (GLshort *)srcImage, (GLshort *)dstImage, element_size, - rowsize, group_size, myswap_bytes); - break; - case GL_UNSIGNED_INT: - halveImage_uint(cmpts, newwidth, newheight, - (GLuint *)srcImage, (GLuint *)dstImage, element_size, - rowsize, group_size, myswap_bytes); - break; - case GL_INT: - halveImage_int(cmpts, newwidth, newheight, - (GLint *)srcImage, (GLint *)dstImage, element_size, - rowsize, group_size, myswap_bytes); - break; - case GL_FLOAT: - halveImage_float(cmpts, newwidth, newheight, - (GLfloat *)srcImage, (GLfloat *)dstImage, element_size, - rowsize, group_size, myswap_bytes); - break; - case GL_UNSIGNED_BYTE_3_3_2: - halveImagePackedPixel(3,extract332,shove332, - newwidth,newheight, - srcImage,dstImage,element_size,rowsize, - myswap_bytes); - break; - case GL_UNSIGNED_BYTE_2_3_3_REV: - halveImagePackedPixel(3,extract233rev,shove233rev, - newwidth,newheight, - srcImage,dstImage,element_size,rowsize, - myswap_bytes); - break; - case GL_UNSIGNED_SHORT_5_6_5: - halveImagePackedPixel(3,extract565,shove565, - newwidth,newheight, - srcImage,dstImage,element_size,rowsize, - myswap_bytes); - break; - case GL_UNSIGNED_SHORT_5_6_5_REV: - halveImagePackedPixel(3,extract565rev,shove565rev, - newwidth,newheight, - srcImage,dstImage,element_size,rowsize, - myswap_bytes); - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - halveImagePackedPixel(4,extract4444,shove4444, - newwidth,newheight, - srcImage,dstImage,element_size,rowsize, - myswap_bytes); - break; - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - halveImagePackedPixel(4,extract4444rev,shove4444rev, - newwidth,newheight, - srcImage,dstImage,element_size,rowsize, - myswap_bytes); - break; - case GL_UNSIGNED_SHORT_5_5_5_1: - halveImagePackedPixel(4,extract5551,shove5551, - newwidth,newheight, - srcImage,dstImage,element_size,rowsize, - myswap_bytes); - break; - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - halveImagePackedPixel(4,extract1555rev,shove1555rev, - newwidth,newheight, - srcImage,dstImage,element_size,rowsize, - myswap_bytes); - break; - case GL_UNSIGNED_INT_8_8_8_8: - halveImagePackedPixel(4,extract8888,shove8888, - newwidth,newheight, - srcImage,dstImage,element_size,rowsize, - myswap_bytes); - break; - case GL_UNSIGNED_INT_8_8_8_8_REV: - halveImagePackedPixel(4,extract8888rev,shove8888rev, - newwidth,newheight, - srcImage,dstImage,element_size,rowsize, - myswap_bytes); - break; - case GL_UNSIGNED_INT_10_10_10_2: - halveImagePackedPixel(4,extract1010102,shove1010102, - newwidth,newheight, - srcImage,dstImage,element_size,rowsize, - myswap_bytes); - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - halveImagePackedPixel(4,extract2101010rev,shove2101010rev, - newwidth,newheight, - srcImage,dstImage,element_size,rowsize, - myswap_bytes); - break; - default: - assert(0); - break; - } - - __GLU_SWAP_IMAGE(srcImage,dstImage); - - if (newwidth > 1) { newwidth /= 2; rowsize /= 2;} - if (newheight > 1) newheight /= 2; - { - /* compute amount to pad per row, if any */ - int rowPad= rowsize % psm.unpack_alignment; - - /* should row be padded? */ - if (rowPad == 0) { /* nope, row should not be padded */ - /* call tex image with srcImage untouched since it's not padded */ - if (baseLevel <= level && level <= maxLevel) { - glTexImage2D(target, level, internalFormat, newwidth, newheight, 0, - format, type, (void *) srcImage); - } - } - else { /* yes, row should be padded */ - /* compute length of new row in bytes, including padding */ - int newRowLength= rowsize + psm.unpack_alignment - rowPad; - int ii; unsigned char *dstTrav, *srcTrav; /* indices for copying */ - - /* allocate new image for mipmap of size newRowLength x newheight */ - void *newMipmapImage= malloc((size_t) (newRowLength*newheight)); - if (newMipmapImage == NULL) { - /* out of memory so return */ - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - return GLU_OUT_OF_MEMORY; - } - - /* copy image from srcImage into newMipmapImage by rows */ - for (ii= 0, - dstTrav= (unsigned char *) newMipmapImage, - srcTrav= (unsigned char *) srcImage; - ii< newheight; - ii++, - dstTrav+= newRowLength, /* make sure the correct distance... */ - srcTrav+= rowsize) { /* ...is skipped */ - memcpy(dstTrav,srcTrav,rowsize); - /* note that the pad bytes are not visited and will contain - * garbage, which is ok. - */ - } - - /* ...and use this new image for mipmapping instead */ - if (baseLevel <= level && level <= maxLevel) { - glTexImage2D(target, level, internalFormat, newwidth, newheight, 0, - format, type, newMipmapImage); - } - free(newMipmapImage); /* don't forget to free it! */ - } /* else */ - } - } /* for level */ - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - - free(srcImage); /*if you get to here, a srcImage has always been malloc'ed*/ - if (dstImage) { /* if it's non-rectangular and only 1 level */ - free(dstImage); - } - return 0; -} /* gluBuild2DMipmapLevelsCore() */ - -GLint GLAPIENTRY -gluBuild2DMipmapLevels(GLenum target, GLint internalFormat, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - GLint userLevel, GLint baseLevel, GLint maxLevel, - const void *data) -{ - int level, levels; - - int rc= checkMipmapArgs(internalFormat,format,type); - if (rc != 0) return rc; - - if (width < 1 || height < 1) { - return GLU_INVALID_VALUE; - } - - levels = computeLog(width); - level = computeLog(height); - if (level > levels) levels=level; - - levels+= userLevel; - if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels)) - return GLU_INVALID_VALUE; - - return gluBuild2DMipmapLevelsCore(target, internalFormat, - width, height, - width, height, - format, type, - userLevel, baseLevel, maxLevel, - data); -} /* gluBuild2DMipmapLevels() */ - -GLint GLAPIENTRY -gluBuild2DMipmaps(GLenum target, GLint internalFormat, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - const void *data) -{ - GLint widthPowerOf2, heightPowerOf2; - int level, levels; - - int rc= checkMipmapArgs(internalFormat,format,type); - if (rc != 0) return rc; - - if (width < 1 || height < 1) { - return GLU_INVALID_VALUE; - } - - closestFit(target,width,height,internalFormat,format,type, - &widthPowerOf2,&heightPowerOf2); - - levels = computeLog(widthPowerOf2); - level = computeLog(heightPowerOf2); - if (level > levels) levels=level; - - return gluBuild2DMipmapLevelsCore(target,internalFormat, - width, height, - widthPowerOf2,heightPowerOf2, - format,type, - 0,0,levels,data); -} /* gluBuild2DMipmaps() */ - -#if 0 -/* -** This routine is for the limited case in which -** type == GL_UNSIGNED_BYTE && format != index && -** unpack_alignment = 1 && unpack_swap_bytes == false -** -** so all of the work data can be kept as ubytes instead of shorts. -*/ -static int fastBuild2DMipmaps(const PixelStorageModes *psm, - GLenum target, GLint components, GLint width, - GLint height, GLenum format, - GLenum type, void *data) -{ - GLint newwidth, newheight; - GLint level, levels; - GLubyte *newImage; - GLint newImage_width; - GLint newImage_height; - GLubyte *otherImage; - GLubyte *imageTemp; - GLint memreq; - GLint cmpts; - - -#if 0 - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); - newwidth = nearestPower(width); - if (newwidth > maxsize) newwidth = maxsize; - newheight = nearestPower(height); - if (newheight > maxsize) newheight = maxsize; -#else - closestFit(target,width,height,components,format,type, - &newwidth,&newheight); -#endif - levels = computeLog(newwidth); - level = computeLog(newheight); - if (level > levels) levels=level; - - cmpts = elements_per_group(format,type); - - otherImage = NULL; - /** - ** No need to copy the user data if its in the packed correctly. - ** Make sure that later routines don't change that data. - */ - if (psm->unpack_skip_rows == 0 && psm->unpack_skip_pixels == 0) { - newImage = (GLubyte *)data; - newImage_width = width; - newImage_height = height; - } else { - GLint rowsize; - GLint groups_per_line; - GLint elements_per_line; - const GLubyte *start; - const GLubyte *iter; - GLubyte *iter2; - GLint i, j; - - newImage = (GLubyte *) - malloc(image_size(width, height, format, GL_UNSIGNED_BYTE)); - newImage_width = width; - newImage_height = height; - if (newImage == NULL) { - return GLU_OUT_OF_MEMORY; - } - - /* - ** Abbreviated version of fill_image for this restricted case. - */ - if (psm->unpack_row_length > 0) { - groups_per_line = psm->unpack_row_length; - } else { - groups_per_line = width; - } - rowsize = groups_per_line * cmpts; - elements_per_line = width * cmpts; - start = (const GLubyte *) data + psm->unpack_skip_rows * rowsize + - psm->unpack_skip_pixels * cmpts; - iter2 = newImage; - - for (i = 0; i < height; i++) { - iter = start; - for (j = 0; j < elements_per_line; j++) { - *iter2 = *iter; - iter++; - iter2++; - } - start += rowsize; - } - } - - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); - - for (level = 0; level <= levels; level++) { - if (newImage_width == newwidth && newImage_height == newheight) { - /* Use newImage for this level */ - glTexImage2D(target, level, components, newImage_width, - newImage_height, 0, format, GL_UNSIGNED_BYTE, - (void *) newImage); - } else { - if (otherImage == NULL) { - memreq = - image_size(newwidth, newheight, format, GL_UNSIGNED_BYTE); - otherImage = (GLubyte *) malloc(memreq); - if (otherImage == NULL) { - glPixelStorei(GL_UNPACK_ALIGNMENT, psm->unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm->unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm->unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH,psm->unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES,psm->unpack_swap_bytes); - return GLU_OUT_OF_MEMORY; - } - } -/* - scale_internal_ubyte(cmpts, newImage_width, newImage_height, - newImage, newwidth, newheight, otherImage); -*/ - /* Swap newImage and otherImage */ - imageTemp = otherImage; - otherImage = newImage; - newImage = imageTemp; - - newImage_width = newwidth; - newImage_height = newheight; - glTexImage2D(target, level, components, newImage_width, - newImage_height, 0, format, GL_UNSIGNED_BYTE, - (void *) newImage); - } - if (newwidth > 1) newwidth /= 2; - if (newheight > 1) newheight /= 2; - } - glPixelStorei(GL_UNPACK_ALIGNMENT, psm->unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm->unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm->unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm->unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm->unpack_swap_bytes); - - if (newImage != (const GLubyte *)data) { - free((GLbyte *) newImage); - } - if (otherImage && otherImage != (const GLubyte *)data) { - free((GLbyte *) otherImage); - } - return 0; -} -#endif - -/* - * Utility Routines - */ -static GLint elements_per_group(GLenum format, GLenum type) -{ - /* - * Return the number of elements per group of a specified format - */ - - /* If the type is packedpixels then answer is 1 (ignore format) */ - if (type == GL_UNSIGNED_BYTE_3_3_2 || - type == GL_UNSIGNED_BYTE_2_3_3_REV || - type == GL_UNSIGNED_SHORT_5_6_5 || - type == GL_UNSIGNED_SHORT_5_6_5_REV || - type == GL_UNSIGNED_SHORT_4_4_4_4 || - type == GL_UNSIGNED_SHORT_4_4_4_4_REV || - type == GL_UNSIGNED_SHORT_5_5_5_1 || - type == GL_UNSIGNED_SHORT_1_5_5_5_REV || - type == GL_UNSIGNED_INT_8_8_8_8 || - type == GL_UNSIGNED_INT_8_8_8_8_REV || - type == GL_UNSIGNED_INT_10_10_10_2 || - type == GL_UNSIGNED_INT_2_10_10_10_REV) { - return 1; - } - - /* Types are not packed pixels, so get elements per group */ - switch(format) { - case GL_RGB: - case GL_BGR: - return 3; - case GL_LUMINANCE_ALPHA: - return 2; - case GL_RGBA: - case GL_BGRA: - return 4; - default: - return 1; - } -} - -static GLfloat bytes_per_element(GLenum type) -{ - /* - * Return the number of bytes per element, based on the element type - */ - switch(type) { - case GL_BITMAP: - return 1.0 / 8.0; - case GL_UNSIGNED_SHORT: - return(sizeof(GLushort)); - case GL_SHORT: - return(sizeof(GLshort)); - case GL_UNSIGNED_BYTE: - return(sizeof(GLubyte)); - case GL_BYTE: - return(sizeof(GLbyte)); - case GL_INT: - return(sizeof(GLint)); - case GL_UNSIGNED_INT: - return(sizeof(GLuint)); - case GL_FLOAT: - return(sizeof(GLfloat)); - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - return(sizeof(GLubyte)); - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - return(sizeof(GLushort)); - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - return(sizeof(GLuint)); - default: - return 4; - } -} - -static GLint is_index(GLenum format) -{ - return format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX; -} - -/* -** Compute memory required for internal packed array of data of given type -** and format. -*/ -static GLint image_size(GLint width, GLint height, GLenum format, GLenum type) -{ - int bytes_per_row; - int components; - -assert(width > 0); -assert(height > 0); - components = elements_per_group(format,type); - if (type == GL_BITMAP) { - bytes_per_row = (width + 7) / 8; - } else { - bytes_per_row = bytes_per_element(type) * width; - } - return bytes_per_row * height * components; -} - -/* -** Extract array from user's data applying all pixel store modes. -** The internal format used is an array of unsigned shorts. -*/ -static void fill_image(const PixelStorageModes *psm, - GLint width, GLint height, GLenum format, - GLenum type, GLboolean index_format, - const void *userdata, GLushort *newimage) -{ - GLint components; - GLint element_size; - GLint rowsize; - GLint padding; - GLint groups_per_line; - GLint group_size; - GLint elements_per_line; - const GLubyte *start; - const GLubyte *iter; - GLushort *iter2; - GLint i, j, k; - GLint myswap_bytes; - - myswap_bytes = psm->unpack_swap_bytes; - components = elements_per_group(format,type); - if (psm->unpack_row_length > 0) { - groups_per_line = psm->unpack_row_length; - } else { - groups_per_line = width; - } - - /* All formats except GL_BITMAP fall out trivially */ - if (type == GL_BITMAP) { - GLint bit_offset; - GLint current_bit; - - rowsize = (groups_per_line * components + 7) / 8; - padding = (rowsize % psm->unpack_alignment); - if (padding) { - rowsize += psm->unpack_alignment - padding; - } - start = (const GLubyte *) userdata + psm->unpack_skip_rows * rowsize + - (psm->unpack_skip_pixels * components / 8); - elements_per_line = width * components; - iter2 = newimage; - for (i = 0; i < height; i++) { - iter = start; - bit_offset = (psm->unpack_skip_pixels * components) % 8; - for (j = 0; j < elements_per_line; j++) { - /* Retrieve bit */ - if (psm->unpack_lsb_first) { - current_bit = iter[0] & (1 << bit_offset); - } else { - current_bit = iter[0] & (1 << (7 - bit_offset)); - } - if (current_bit) { - if (index_format) { - *iter2 = 1; - } else { - *iter2 = 65535; - } - } else { - *iter2 = 0; - } - bit_offset++; - if (bit_offset == 8) { - bit_offset = 0; - iter++; - } - iter2++; - } - start += rowsize; - } - } else { - element_size = bytes_per_element(type); - group_size = element_size * components; - if (element_size == 1) myswap_bytes = 0; - - rowsize = groups_per_line * group_size; - padding = (rowsize % psm->unpack_alignment); - if (padding) { - rowsize += psm->unpack_alignment - padding; - } - start = (const GLubyte *) userdata + psm->unpack_skip_rows * rowsize + - psm->unpack_skip_pixels * group_size; - elements_per_line = width * components; - - iter2 = newimage; - for (i = 0; i < height; i++) { - iter = start; - for (j = 0; j < elements_per_line; j++) { - Type_Widget widget; - float extractComponents[4]; - - switch(type) { - case GL_UNSIGNED_BYTE_3_3_2: - extract332(0,iter,extractComponents); - for (k = 0; k < 3; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_BYTE_2_3_3_REV: - extract233rev(0,iter,extractComponents); - for (k = 0; k < 3; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_BYTE: - if (index_format) { - *iter2++ = *iter; - } else { - *iter2++ = (*iter) * 257; - } - break; - case GL_BYTE: - if (index_format) { - *iter2++ = *((const GLbyte *) iter); - } else { - /* rough approx */ - *iter2++ = (*((const GLbyte *) iter)) * 516; - } - break; - case GL_UNSIGNED_SHORT_5_6_5: - extract565(myswap_bytes,iter,extractComponents); - for (k = 0; k < 3; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT_5_6_5_REV: - extract565rev(myswap_bytes,iter,extractComponents); - for (k = 0; k < 3; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - extract4444(myswap_bytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - extract4444rev(myswap_bytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT_5_5_5_1: - extract5551(myswap_bytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - extract1555rev(myswap_bytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT: - case GL_SHORT: - if (myswap_bytes) { - widget.ub[0] = iter[1]; - widget.ub[1] = iter[0]; - } else { - widget.ub[0] = iter[0]; - widget.ub[1] = iter[1]; - } - if (type == GL_SHORT) { - if (index_format) { - *iter2++ = widget.s[0]; - } else { - /* rough approx */ - *iter2++ = widget.s[0]*2; - } - } else { - *iter2++ = widget.us[0]; - } - break; - case GL_UNSIGNED_INT_8_8_8_8: - extract8888(myswap_bytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_INT_8_8_8_8_REV: - extract8888rev(myswap_bytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_INT_10_10_10_2: - extract1010102(myswap_bytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - extract2101010rev(myswap_bytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - if (myswap_bytes) { - widget.ub[0] = iter[3]; - widget.ub[1] = iter[2]; - widget.ub[2] = iter[1]; - widget.ub[3] = iter[0]; - } else { - widget.ub[0] = iter[0]; - widget.ub[1] = iter[1]; - widget.ub[2] = iter[2]; - widget.ub[3] = iter[3]; - } - if (type == GL_FLOAT) { - if (index_format) { - *iter2++ = widget.f; - } else { - *iter2++ = 65535 * widget.f; - } - } else if (type == GL_UNSIGNED_INT) { - if (index_format) { - *iter2++ = widget.ui; - } else { - *iter2++ = widget.ui >> 16; - } - } else { - if (index_format) { - *iter2++ = widget.i; - } else { - *iter2++ = widget.i >> 15; - } - } - break; - } - iter += element_size; - } /* for j */ - start += rowsize; -#if 1 - /* want 'iter' pointing at start, not within, row for assertion - * purposes - */ - iter= start; -#endif - } /* for i */ - - /* iterators should be one byte past end */ - if (!isTypePackedPixel(type)) { - assert(iter2 == &newimage[width*height*components]); - } - else { - assert(iter2 == &newimage[width*height* - elements_per_group(format,0)]); - } - assert( iter == &((const GLubyte *)userdata)[rowsize*height + - psm->unpack_skip_rows * rowsize + - psm->unpack_skip_pixels * group_size] ); - - } /* else */ -} /* fill_image() */ - -/* -** Insert array into user's data applying all pixel store modes. -** The internal format is an array of unsigned shorts. -** empty_image() because it is the opposite of fill_image(). -*/ -static void empty_image(const PixelStorageModes *psm, - GLint width, GLint height, GLenum format, - GLenum type, GLboolean index_format, - const GLushort *oldimage, void *userdata) -{ - GLint components; - GLint element_size; - GLint rowsize; - GLint padding; - GLint groups_per_line; - GLint group_size; - GLint elements_per_line; - GLubyte *start; - GLubyte *iter; - const GLushort *iter2; - GLint i, j, k; - GLint myswap_bytes; - - myswap_bytes = psm->pack_swap_bytes; - components = elements_per_group(format,type); - if (psm->pack_row_length > 0) { - groups_per_line = psm->pack_row_length; - } else { - groups_per_line = width; - } - - /* All formats except GL_BITMAP fall out trivially */ - if (type == GL_BITMAP) { - GLint bit_offset; - GLint current_bit; - - rowsize = (groups_per_line * components + 7) / 8; - padding = (rowsize % psm->pack_alignment); - if (padding) { - rowsize += psm->pack_alignment - padding; - } - start = (GLubyte *) userdata + psm->pack_skip_rows * rowsize + - (psm->pack_skip_pixels * components / 8); - elements_per_line = width * components; - iter2 = oldimage; - for (i = 0; i < height; i++) { - iter = start; - bit_offset = (psm->pack_skip_pixels * components) % 8; - for (j = 0; j < elements_per_line; j++) { - if (index_format) { - current_bit = iter2[0] & 1; - } else { - if (iter2[0] > 32767) { - current_bit = 1; - } else { - current_bit = 0; - } - } - - if (current_bit) { - if (psm->pack_lsb_first) { - *iter |= (1 << bit_offset); - } else { - *iter |= (1 << (7 - bit_offset)); - } - } else { - if (psm->pack_lsb_first) { - *iter &= ~(1 << bit_offset); - } else { - *iter &= ~(1 << (7 - bit_offset)); - } - } - - bit_offset++; - if (bit_offset == 8) { - bit_offset = 0; - iter++; - } - iter2++; - } - start += rowsize; - } - } else { - float shoveComponents[4]; - - element_size = bytes_per_element(type); - group_size = element_size * components; - if (element_size == 1) myswap_bytes = 0; - - rowsize = groups_per_line * group_size; - padding = (rowsize % psm->pack_alignment); - if (padding) { - rowsize += psm->pack_alignment - padding; - } - start = (GLubyte *) userdata + psm->pack_skip_rows * rowsize + - psm->pack_skip_pixels * group_size; - elements_per_line = width * components; - - iter2 = oldimage; - for (i = 0; i < height; i++) { - iter = start; - for (j = 0; j < elements_per_line; j++) { - Type_Widget widget; - - switch(type) { - case GL_UNSIGNED_BYTE_3_3_2: - for (k = 0; k < 3; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove332(shoveComponents,0,(void *)iter); - break; - case GL_UNSIGNED_BYTE_2_3_3_REV: - for (k = 0; k < 3; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove233rev(shoveComponents,0,(void *)iter); - break; - case GL_UNSIGNED_BYTE: - if (index_format) { - *iter = *iter2++; - } else { - *iter = *iter2++ >> 8; - } - break; - case GL_BYTE: - if (index_format) { - *((GLbyte *) iter) = *iter2++; - } else { - *((GLbyte *) iter) = *iter2++ >> 9; - } - break; - case GL_UNSIGNED_SHORT_5_6_5: - for (k = 0; k < 3; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove565(shoveComponents,0,(void *)&widget.us[0]); - if (myswap_bytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } - else { - *(GLushort *)iter = widget.us[0]; - } - break; - case GL_UNSIGNED_SHORT_5_6_5_REV: - for (k = 0; k < 3; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove565rev(shoveComponents,0,(void *)&widget.us[0]); - if (myswap_bytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } - else { - *(GLushort *)iter = widget.us[0]; - } - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove4444(shoveComponents,0,(void *)&widget.us[0]); - if (myswap_bytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } else { - *(GLushort *)iter = widget.us[0]; - } - break; - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove4444rev(shoveComponents,0,(void *)&widget.us[0]); - if (myswap_bytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } else { - *(GLushort *)iter = widget.us[0]; - } - break; - case GL_UNSIGNED_SHORT_5_5_5_1: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove5551(shoveComponents,0,(void *)&widget.us[0]); - if (myswap_bytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } else { - *(GLushort *)iter = widget.us[0]; - } - break; - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove1555rev(shoveComponents,0,(void *)&widget.us[0]); - if (myswap_bytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } else { - *(GLushort *)iter = widget.us[0]; - } - break; - case GL_UNSIGNED_SHORT: - case GL_SHORT: - if (type == GL_SHORT) { - if (index_format) { - widget.s[0] = *iter2++; - } else { - widget.s[0] = *iter2++ >> 1; - } - } else { - widget.us[0] = *iter2++; - } - if (myswap_bytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } else { - iter[0] = widget.ub[0]; - iter[1] = widget.ub[1]; - } - break; - case GL_UNSIGNED_INT_8_8_8_8: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove8888(shoveComponents,0,(void *)&widget.ui); - if (myswap_bytes) { - iter[3] = widget.ub[0]; - iter[2] = widget.ub[1]; - iter[1] = widget.ub[2]; - iter[0] = widget.ub[3]; - } else { - *(GLuint *)iter= widget.ui; - } - - break; - case GL_UNSIGNED_INT_8_8_8_8_REV: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove8888rev(shoveComponents,0,(void *)&widget.ui); - if (myswap_bytes) { - iter[3] = widget.ub[0]; - iter[2] = widget.ub[1]; - iter[1] = widget.ub[2]; - iter[0] = widget.ub[3]; - } else { - *(GLuint *)iter= widget.ui; - } - break; - case GL_UNSIGNED_INT_10_10_10_2: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove1010102(shoveComponents,0,(void *)&widget.ui); - if (myswap_bytes) { - iter[3] = widget.ub[0]; - iter[2] = widget.ub[1]; - iter[1] = widget.ub[2]; - iter[0] = widget.ub[3]; - } else { - *(GLuint *)iter= widget.ui; - } - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove2101010rev(shoveComponents,0,(void *)&widget.ui); - if (myswap_bytes) { - iter[3] = widget.ub[0]; - iter[2] = widget.ub[1]; - iter[1] = widget.ub[2]; - iter[0] = widget.ub[3]; - } else { - *(GLuint *)iter= widget.ui; - } - break; - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - if (type == GL_FLOAT) { - if (index_format) { - widget.f = *iter2++; - } else { - widget.f = *iter2++ / (float) 65535.0; - } - } else if (type == GL_UNSIGNED_INT) { - if (index_format) { - widget.ui = *iter2++; - } else { - widget.ui = (unsigned int) *iter2++ * 65537; - } - } else { - if (index_format) { - widget.i = *iter2++; - } else { - widget.i = ((unsigned int) *iter2++ * 65537)/2; - } - } - if (myswap_bytes) { - iter[3] = widget.ub[0]; - iter[2] = widget.ub[1]; - iter[1] = widget.ub[2]; - iter[0] = widget.ub[3]; - } else { - iter[0] = widget.ub[0]; - iter[1] = widget.ub[1]; - iter[2] = widget.ub[2]; - iter[3] = widget.ub[3]; - } - break; - } - iter += element_size; - } /* for j */ - start += rowsize; -#if 1 - /* want 'iter' pointing at start, not within, row for assertion - * purposes - */ - iter= start; -#endif - } /* for i */ - - /* iterators should be one byte past end */ - if (!isTypePackedPixel(type)) { - assert(iter2 == &oldimage[width*height*components]); - } - else { - assert(iter2 == &oldimage[width*height* - elements_per_group(format,0)]); - } - assert( iter == &((GLubyte *)userdata)[rowsize*height + - psm->pack_skip_rows * rowsize + - psm->pack_skip_pixels * group_size] ); - - } /* else */ -} /* empty_image() */ - -/*-------------------------------------------------------------------------- - * Decimation of packed pixel types - *-------------------------------------------------------------------------- - */ -static void extract332(int isSwap, - const void *packedPixel, GLfloat extractComponents[]) -{ - GLubyte ubyte= *(const GLubyte *)packedPixel; - - isSwap= isSwap; /* turn off warnings */ - - /* 11100000 == 0xe0 */ - /* 00011100 == 0x1c */ - /* 00000011 == 0x03 */ - - extractComponents[0]= (float)((ubyte & 0xe0) >> 5) / 7.0; - extractComponents[1]= (float)((ubyte & 0x1c) >> 2) / 7.0; /* 7 = 2^3-1 */ - extractComponents[2]= (float)((ubyte & 0x03) ) / 3.0; /* 3 = 2^2-1 */ -} /* extract332() */ - -static void shove332(const GLfloat shoveComponents[], - int index, void *packedPixel) -{ - /* 11100000 == 0xe0 */ - /* 00011100 == 0x1c */ - /* 00000011 == 0x03 */ - - assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); - assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); - assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); - - /* due to limited precision, need to round before shoving */ - ((GLubyte *)packedPixel)[index] = - ((GLubyte)((shoveComponents[0] * 7)+0.5) << 5) & 0xe0; - ((GLubyte *)packedPixel)[index] |= - ((GLubyte)((shoveComponents[1] * 7)+0.5) << 2) & 0x1c; - ((GLubyte *)packedPixel)[index] |= - ((GLubyte)((shoveComponents[2] * 3)+0.5) ) & 0x03; -} /* shove332() */ - -static void extract233rev(int isSwap, - const void *packedPixel, GLfloat extractComponents[]) -{ - GLubyte ubyte= *(const GLubyte *)packedPixel; - - isSwap= isSwap; /* turn off warnings */ - - /* 0000,0111 == 0x07 */ - /* 0011,1000 == 0x38 */ - /* 1100,0000 == 0xC0 */ - - extractComponents[0]= (float)((ubyte & 0x07) ) / 7.0; - extractComponents[1]= (float)((ubyte & 0x38) >> 3) / 7.0; - extractComponents[2]= (float)((ubyte & 0xC0) >> 6) / 3.0; -} /* extract233rev() */ - -static void shove233rev(const GLfloat shoveComponents[], - int index, void *packedPixel) -{ - /* 0000,0111 == 0x07 */ - /* 0011,1000 == 0x38 */ - /* 1100,0000 == 0xC0 */ - - assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); - assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); - assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); - - /* due to limited precision, need to round before shoving */ - ((GLubyte *)packedPixel)[index] = - ((GLubyte)((shoveComponents[0] * 7.0)+0.5) ) & 0x07; - ((GLubyte *)packedPixel)[index]|= - ((GLubyte)((shoveComponents[1] * 7.0)+0.5) << 3) & 0x38; - ((GLubyte *)packedPixel)[index]|= - ((GLubyte)((shoveComponents[2] * 3.0)+0.5) << 6) & 0xC0; -} /* shove233rev() */ - -static void extract565(int isSwap, - const void *packedPixel, GLfloat extractComponents[]) -{ - GLushort ushort= *(const GLushort *)packedPixel; - - if (isSwap) { - ushort= __GLU_SWAP_2_BYTES(packedPixel); - } - else { - ushort= *(const GLushort *)packedPixel; - } - - /* 11111000,00000000 == 0xf800 */ - /* 00000111,11100000 == 0x07e0 */ - /* 00000000,00011111 == 0x001f */ - - extractComponents[0]=(float)((ushort & 0xf800) >> 11) / 31.0;/* 31 = 2^5-1*/ - extractComponents[1]=(float)((ushort & 0x07e0) >> 5) / 63.0;/* 63 = 2^6-1*/ - extractComponents[2]=(float)((ushort & 0x001f) ) / 31.0; -} /* extract565() */ - -static void shove565(const GLfloat shoveComponents[], - int index,void *packedPixel) -{ - /* 11111000,00000000 == 0xf800 */ - /* 00000111,11100000 == 0x07e0 */ - /* 00000000,00011111 == 0x001f */ - - assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); - assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); - assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); - - /* due to limited precision, need to round before shoving */ - ((GLushort *)packedPixel)[index] = - ((GLushort)((shoveComponents[0] * 31)+0.5) << 11) & 0xf800; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[1] * 63)+0.5) << 5) & 0x07e0; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[2] * 31)+0.5) ) & 0x001f; -} /* shove565() */ - -static void extract565rev(int isSwap, - const void *packedPixel, GLfloat extractComponents[]) -{ - GLushort ushort= *(const GLushort *)packedPixel; - - if (isSwap) { - ushort= __GLU_SWAP_2_BYTES(packedPixel); - } - else { - ushort= *(const GLushort *)packedPixel; - } - - /* 00000000,00011111 == 0x001f */ - /* 00000111,11100000 == 0x07e0 */ - /* 11111000,00000000 == 0xf800 */ - - extractComponents[0]= (float)((ushort & 0x001F) ) / 31.0; - extractComponents[1]= (float)((ushort & 0x07E0) >> 5) / 63.0; - extractComponents[2]= (float)((ushort & 0xF800) >> 11) / 31.0; -} /* extract565rev() */ - -static void shove565rev(const GLfloat shoveComponents[], - int index,void *packedPixel) -{ - /* 00000000,00011111 == 0x001f */ - /* 00000111,11100000 == 0x07e0 */ - /* 11111000,00000000 == 0xf800 */ - - assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); - assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); - assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); - - /* due to limited precision, need to round before shoving */ - ((GLushort *)packedPixel)[index] = - ((GLushort)((shoveComponents[0] * 31.0)+0.5) ) & 0x001F; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[1] * 63.0)+0.5) << 5) & 0x07E0; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[2] * 31.0)+0.5) << 11) & 0xF800; -} /* shove565rev() */ - -static void extract4444(int isSwap,const void *packedPixel, - GLfloat extractComponents[]) -{ - GLushort ushort; - - if (isSwap) { - ushort= __GLU_SWAP_2_BYTES(packedPixel); - } - else { - ushort= *(const GLushort *)packedPixel; - } - - /* 11110000,00000000 == 0xf000 */ - /* 00001111,00000000 == 0x0f00 */ - /* 00000000,11110000 == 0x00f0 */ - /* 00000000,00001111 == 0x000f */ - - extractComponents[0]= (float)((ushort & 0xf000) >> 12) / 15.0;/* 15=2^4-1 */ - extractComponents[1]= (float)((ushort & 0x0f00) >> 8) / 15.0; - extractComponents[2]= (float)((ushort & 0x00f0) >> 4) / 15.0; - extractComponents[3]= (float)((ushort & 0x000f) ) / 15.0; -} /* extract4444() */ - -static void shove4444(const GLfloat shoveComponents[], - int index,void *packedPixel) -{ - assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); - assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); - assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); - assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); - - /* due to limited precision, need to round before shoving */ - ((GLushort *)packedPixel)[index] = - ((GLushort)((shoveComponents[0] * 15)+0.5) << 12) & 0xf000; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[1] * 15)+0.5) << 8) & 0x0f00; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[2] * 15)+0.5) << 4) & 0x00f0; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[3] * 15)+0.5) ) & 0x000f; -} /* shove4444() */ - -static void extract4444rev(int isSwap,const void *packedPixel, - GLfloat extractComponents[]) -{ - GLushort ushort; - - if (isSwap) { - ushort= __GLU_SWAP_2_BYTES(packedPixel); - } - else { - ushort= *(const GLushort *)packedPixel; - } - - /* 00000000,00001111 == 0x000f */ - /* 00000000,11110000 == 0x00f0 */ - /* 00001111,00000000 == 0x0f00 */ - /* 11110000,00000000 == 0xf000 */ - - /* 15 = 2^4-1 */ - extractComponents[0]= (float)((ushort & 0x000F) ) / 15.0; - extractComponents[1]= (float)((ushort & 0x00F0) >> 4) / 15.0; - extractComponents[2]= (float)((ushort & 0x0F00) >> 8) / 15.0; - extractComponents[3]= (float)((ushort & 0xF000) >> 12) / 15.0; -} /* extract4444rev() */ - -static void shove4444rev(const GLfloat shoveComponents[], - int index,void *packedPixel) -{ - /* 00000000,00001111 == 0x000f */ - /* 00000000,11110000 == 0x00f0 */ - /* 00001111,00000000 == 0x0f00 */ - /* 11110000,00000000 == 0xf000 */ - - assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); - assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); - assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); - assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); - - /* due to limited precision, need to round before shoving */ - ((GLushort *)packedPixel)[index] = - ((GLushort)((shoveComponents[0] * 15)+0.5) ) & 0x000F; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[1] * 15)+0.5) << 4) & 0x00F0; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[2] * 15)+0.5) << 8) & 0x0F00; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[3] * 15)+0.5) << 12) & 0xF000; -} /* shove4444rev() */ - -static void extract5551(int isSwap,const void *packedPixel, - GLfloat extractComponents[]) -{ - GLushort ushort; - - if (isSwap) { - ushort= __GLU_SWAP_2_BYTES(packedPixel); - } - else { - ushort= *(const GLushort *)packedPixel; - } - - /* 11111000,00000000 == 0xf800 */ - /* 00000111,11000000 == 0x07c0 */ - /* 00000000,00111110 == 0x003e */ - /* 00000000,00000001 == 0x0001 */ - - extractComponents[0]=(float)((ushort & 0xf800) >> 11) / 31.0;/* 31 = 2^5-1*/ - extractComponents[1]=(float)((ushort & 0x07c0) >> 6) / 31.0; - extractComponents[2]=(float)((ushort & 0x003e) >> 1) / 31.0; - extractComponents[3]=(float)((ushort & 0x0001) ); -} /* extract5551() */ - -static void shove5551(const GLfloat shoveComponents[], - int index,void *packedPixel) -{ - /* 11111000,00000000 == 0xf800 */ - /* 00000111,11000000 == 0x07c0 */ - /* 00000000,00111110 == 0x003e */ - /* 00000000,00000001 == 0x0001 */ - - assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); - assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); - assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); - assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); - - /* due to limited precision, need to round before shoving */ - ((GLushort *)packedPixel)[index] = - ((GLushort)((shoveComponents[0] * 31)+0.5) << 11) & 0xf800; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[1] * 31)+0.5) << 6) & 0x07c0; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[2] * 31)+0.5) << 1) & 0x003e; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[3])+0.5) ) & 0x0001; -} /* shove5551() */ - -static void extract1555rev(int isSwap,const void *packedPixel, - GLfloat extractComponents[]) -{ - GLushort ushort; - - if (isSwap) { - ushort= __GLU_SWAP_2_BYTES(packedPixel); - } - else { - ushort= *(const GLushort *)packedPixel; - } - - /* 00000000,00011111 == 0x001F */ - /* 00000011,11100000 == 0x03E0 */ - /* 01111100,00000000 == 0x7C00 */ - /* 10000000,00000000 == 0x8000 */ - - /* 31 = 2^5-1 */ - extractComponents[0]= (float)((ushort & 0x001F) ) / 31.0; - extractComponents[1]= (float)((ushort & 0x03E0) >> 5) / 31.0; - extractComponents[2]= (float)((ushort & 0x7C00) >> 10) / 31.0; - extractComponents[3]= (float)((ushort & 0x8000) >> 15); -} /* extract1555rev() */ - -static void shove1555rev(const GLfloat shoveComponents[], - int index,void *packedPixel) -{ - /* 00000000,00011111 == 0x001F */ - /* 00000011,11100000 == 0x03E0 */ - /* 01111100,00000000 == 0x7C00 */ - /* 10000000,00000000 == 0x8000 */ - - assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); - assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); - assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); - assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); - - /* due to limited precision, need to round before shoving */ - ((GLushort *)packedPixel)[index] = - ((GLushort)((shoveComponents[0] * 31)+0.5) ) & 0x001F; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[1] * 31)+0.5) << 5) & 0x03E0; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[2] * 31)+0.5) << 10) & 0x7C00; - ((GLushort *)packedPixel)[index]|= - ((GLushort)((shoveComponents[3])+0.5) << 15) & 0x8000; -} /* shove1555rev() */ - -static void extract8888(int isSwap, - const void *packedPixel, GLfloat extractComponents[]) -{ - GLuint uint; - - if (isSwap) { - uint= __GLU_SWAP_4_BYTES(packedPixel); - } - else { - uint= *(const GLuint *)packedPixel; - } - - /* 11111111,00000000,00000000,00000000 == 0xff000000 */ - /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */ - /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */ - /* 00000000,00000000,00000000,11111111 == 0x000000ff */ - - /* 255 = 2^8-1 */ - extractComponents[0]= (float)((uint & 0xff000000) >> 24) / 255.0; - extractComponents[1]= (float)((uint & 0x00ff0000) >> 16) / 255.0; - extractComponents[2]= (float)((uint & 0x0000ff00) >> 8) / 255.0; - extractComponents[3]= (float)((uint & 0x000000ff) ) / 255.0; -} /* extract8888() */ - -static void shove8888(const GLfloat shoveComponents[], - int index,void *packedPixel) -{ - /* 11111111,00000000,00000000,00000000 == 0xff000000 */ - /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */ - /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */ - /* 00000000,00000000,00000000,11111111 == 0x000000ff */ - - assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); - assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); - assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); - assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); - - /* due to limited precision, need to round before shoving */ - ((GLuint *)packedPixel)[index] = - ((GLuint)((shoveComponents[0] * 255)+0.5) << 24) & 0xff000000; - ((GLuint *)packedPixel)[index]|= - ((GLuint)((shoveComponents[1] * 255)+0.5) << 16) & 0x00ff0000; - ((GLuint *)packedPixel)[index]|= - ((GLuint)((shoveComponents[2] * 255)+0.5) << 8) & 0x0000ff00; - ((GLuint *)packedPixel)[index]|= - ((GLuint)((shoveComponents[3] * 255)+0.5) ) & 0x000000ff; -} /* shove8888() */ - -static void extract8888rev(int isSwap, - const void *packedPixel,GLfloat extractComponents[]) -{ - GLuint uint; - - if (isSwap) { - uint= __GLU_SWAP_4_BYTES(packedPixel); - } - else { - uint= *(const GLuint *)packedPixel; - } - - /* 00000000,00000000,00000000,11111111 == 0x000000ff */ - /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */ - /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */ - /* 11111111,00000000,00000000,00000000 == 0xff000000 */ - - /* 255 = 2^8-1 */ - extractComponents[0]= (float)((uint & 0x000000FF) ) / 255.0; - extractComponents[1]= (float)((uint & 0x0000FF00) >> 8) / 255.0; - extractComponents[2]= (float)((uint & 0x00FF0000) >> 16) / 255.0; - extractComponents[3]= (float)((uint & 0xFF000000) >> 24) / 255.0; -} /* extract8888rev() */ - -static void shove8888rev(const GLfloat shoveComponents[], - int index,void *packedPixel) -{ - /* 00000000,00000000,00000000,11111111 == 0x000000ff */ - /* 00000000,00000000,11111111,00000000 == 0x0000ff00 */ - /* 00000000,11111111,00000000,00000000 == 0x00ff0000 */ - /* 11111111,00000000,00000000,00000000 == 0xff000000 */ - - assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); - assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); - assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); - assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); - - /* due to limited precision, need to round before shoving */ - ((GLuint *)packedPixel)[index] = - ((GLuint)((shoveComponents[0] * 255)+0.5) ) & 0x000000FF; - ((GLuint *)packedPixel)[index]|= - ((GLuint)((shoveComponents[1] * 255)+0.5) << 8) & 0x0000FF00; - ((GLuint *)packedPixel)[index]|= - ((GLuint)((shoveComponents[2] * 255)+0.5) << 16) & 0x00FF0000; - ((GLuint *)packedPixel)[index]|= - ((GLuint)((shoveComponents[3] * 255)+0.5) << 24) & 0xFF000000; -} /* shove8888rev() */ - -static void extract1010102(int isSwap, - const void *packedPixel,GLfloat extractComponents[]) -{ - GLuint uint; - - if (isSwap) { - uint= __GLU_SWAP_4_BYTES(packedPixel); - } - else { - uint= *(const GLuint *)packedPixel; - } - - /* 11111111,11000000,00000000,00000000 == 0xffc00000 */ - /* 00000000,00111111,11110000,00000000 == 0x003ff000 */ - /* 00000000,00000000,00001111,11111100 == 0x00000ffc */ - /* 00000000,00000000,00000000,00000011 == 0x00000003 */ - - /* 1023 = 2^10-1 */ - extractComponents[0]= (float)((uint & 0xffc00000) >> 22) / 1023.0; - extractComponents[1]= (float)((uint & 0x003ff000) >> 12) / 1023.0; - extractComponents[2]= (float)((uint & 0x00000ffc) >> 2) / 1023.0; - extractComponents[3]= (float)((uint & 0x00000003) ) / 3.0; -} /* extract1010102() */ - -static void shove1010102(const GLfloat shoveComponents[], - int index,void *packedPixel) -{ - /* 11111111,11000000,00000000,00000000 == 0xffc00000 */ - /* 00000000,00111111,11110000,00000000 == 0x003ff000 */ - /* 00000000,00000000,00001111,11111100 == 0x00000ffc */ - /* 00000000,00000000,00000000,00000011 == 0x00000003 */ - - assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); - assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); - assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); - assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); - - /* due to limited precision, need to round before shoving */ - ((GLuint *)packedPixel)[index] = - ((GLuint)((shoveComponents[0] * 1023)+0.5) << 22) & 0xffc00000; - ((GLuint *)packedPixel)[index]|= - ((GLuint)((shoveComponents[1] * 1023)+0.5) << 12) & 0x003ff000; - ((GLuint *)packedPixel)[index]|= - ((GLuint)((shoveComponents[2] * 1023)+0.5) << 2) & 0x00000ffc; - ((GLuint *)packedPixel)[index]|= - ((GLuint)((shoveComponents[3] * 3)+0.5) ) & 0x00000003; -} /* shove1010102() */ - -static void extract2101010rev(int isSwap, - const void *packedPixel, - GLfloat extractComponents[]) -{ - GLuint uint; - - if (isSwap) { - uint= __GLU_SWAP_4_BYTES(packedPixel); - } - else { - uint= *(const GLuint *)packedPixel; - } - - /* 00000000,00000000,00000011,11111111 == 0x000003FF */ - /* 00000000,00001111,11111100,00000000 == 0x000FFC00 */ - /* 00111111,11110000,00000000,00000000 == 0x3FF00000 */ - /* 11000000,00000000,00000000,00000000 == 0xC0000000 */ - - /* 1023 = 2^10-1 */ - extractComponents[0]= (float)((uint & 0x000003FF) ) / 1023.0; - extractComponents[1]= (float)((uint & 0x000FFC00) >> 10) / 1023.0; - extractComponents[2]= (float)((uint & 0x3FF00000) >> 20) / 1023.0; - extractComponents[3]= (float)((uint & 0xC0000000) >> 30) / 3.0; - /* 3 = 2^2-1 */ -} /* extract2101010rev() */ - -static void shove2101010rev(const GLfloat shoveComponents[], - int index,void *packedPixel) -{ - /* 00000000,00000000,00000011,11111111 == 0x000003FF */ - /* 00000000,00001111,11111100,00000000 == 0x000FFC00 */ - /* 00111111,11110000,00000000,00000000 == 0x3FF00000 */ - /* 11000000,00000000,00000000,00000000 == 0xC0000000 */ - - assert(0.0 <= shoveComponents[0] && shoveComponents[0] <= 1.0); - assert(0.0 <= shoveComponents[1] && shoveComponents[1] <= 1.0); - assert(0.0 <= shoveComponents[2] && shoveComponents[2] <= 1.0); - assert(0.0 <= shoveComponents[3] && shoveComponents[3] <= 1.0); - - /* due to limited precision, need to round before shoving */ - ((GLuint *)packedPixel)[index] = - ((GLuint)((shoveComponents[0] * 1023)+0.5) ) & 0x000003FF; - ((GLuint *)packedPixel)[index]|= - ((GLuint)((shoveComponents[1] * 1023)+0.5) << 10) & 0x000FFC00; - ((GLuint *)packedPixel)[index]|= - ((GLuint)((shoveComponents[2] * 1023)+0.5) << 20) & 0x3FF00000; - ((GLuint *)packedPixel)[index]|= - ((GLuint)((shoveComponents[3] * 3)+0.5) << 30) & 0xC0000000; -} /* shove2101010rev() */ - -static void scaleInternalPackedPixel(int components, - void (*extractPackedPixel) - (int, const void *,GLfloat []), - void (*shovePackedPixel) - (const GLfloat [], int, void *), - GLint widthIn,GLint heightIn, - const void *dataIn, - GLint widthOut,GLint heightOut, - void *dataOut, - GLint pixelSizeInBytes, - GLint rowSizeInBytes,GLint isSwap) -{ - float convx; - float convy; - float percent; - - /* Max components in a format is 4, so... */ - float totals[4]; - float extractTotals[4], extractMoreTotals[4], shoveTotals[4]; - - float area; - int i,j,k,xindex; - - const char *temp, *temp0; - int outindex; - - int lowx_int, highx_int, lowy_int, highy_int; - float x_percent, y_percent; - float lowx_float, highx_float, lowy_float, highy_float; - float convy_float, convx_float; - int convy_int, convx_int; - int l, m; - const char *left, *right; - - if (widthIn == widthOut*2 && heightIn == heightOut*2) { - halveImagePackedPixel(components,extractPackedPixel,shovePackedPixel, - widthIn, heightIn, dataIn, dataOut, - pixelSizeInBytes,rowSizeInBytes,isSwap); - return; - } - convy = (float) heightIn/heightOut; - convx = (float) widthIn/widthOut; - convy_int = floor(convy); - convy_float = convy - convy_int; - convx_int = floor(convx); - convx_float = convx - convx_int; - - area = convx * convy; - - lowy_int = 0; - lowy_float = 0; - highy_int = convy_int; - highy_float = convy_float; - - for (i = 0; i < heightOut; i++) { - lowx_int = 0; - lowx_float = 0; - highx_int = convx_int; - highx_float = convx_float; - - for (j = 0; j < widthOut; j++) { - /* - ** Ok, now apply box filter to box that goes from (lowx, lowy) - ** to (highx, highy) on input data into this pixel on output - ** data. - */ - totals[0] = totals[1] = totals[2] = totals[3] = 0.0; - - /* calculate the value for pixels in the 1st row */ - xindex = lowx_int*pixelSizeInBytes; - if((highy_int>lowy_int) && (highx_int>lowx_int)) { - - y_percent = 1-lowy_float; - temp = (const char *)dataIn + xindex + lowy_int * rowSizeInBytes; - percent = y_percent * (1-lowx_float); -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * percent; - } -#endif - left = temp; - for(l = lowx_int+1; l < highx_int; l++) { - temp += pixelSizeInBytes; -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_2_BYTES(temp_index) * y_percent; - } else { - totals[k] += *(const GLushort*)temp_index * y_percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * y_percent; - } -#endif - } - temp += pixelSizeInBytes; - right = temp; - percent = y_percent * highx_float; -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * percent; - } -#endif - - /* calculate the value for pixels in the last row */ - - y_percent = highy_float; - percent = y_percent * (1-lowx_float); - temp = (const char *)dataIn + xindex + highy_int * rowSizeInBytes; -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * percent; - } -#endif - for(l = lowx_int+1; l < highx_int; l++) { - temp += pixelSizeInBytes; -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_2_BYTES(temp_index) * y_percent; - } else { - totals[k] += *(const GLushort*)temp_index * y_percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * y_percent; - } -#endif - - } - temp += pixelSizeInBytes; - percent = y_percent * highx_float; -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * percent; - } -#endif - - /* calculate the value for pixels in the 1st and last column */ - for(m = lowy_int+1; m < highy_int; m++) { - left += rowSizeInBytes; - right += rowSizeInBytes; -#if 0 - for (k = 0; k < components; - k++, left += element_size, right += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_2_BYTES(left) * (1-lowx_float) + - __GLU_SWAP_2_BYTES(right) * highx_float; - } else { - totals[k] += *(const GLushort*)left * (1-lowx_float) - + *(const GLushort*)right * highx_float; - } - } -#else - (*extractPackedPixel)(isSwap,left,extractTotals); - (*extractPackedPixel)(isSwap,right,extractMoreTotals); - for (k = 0; k < components; k++) { - totals[k]+= (extractTotals[k]*(1-lowx_float) + - extractMoreTotals[k]*highx_float); - } -#endif - } - } else if (highy_int > lowy_int) { - x_percent = highx_float - lowx_float; - percent = (1-lowy_float)*x_percent; - temp = (const char *)dataIn + xindex + lowy_int*rowSizeInBytes; -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * percent; - } -#endif - for(m = lowy_int+1; m < highy_int; m++) { - temp += rowSizeInBytes; -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_2_BYTES(temp_index) * x_percent; - } else { - totals[k] += *(const GLushort*)temp_index * x_percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * x_percent; - } -#endif - } - percent = x_percent * highy_float; - temp += rowSizeInBytes; -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * percent; - } -#endif - } else if (highx_int > lowx_int) { - y_percent = highy_float - lowy_float; - percent = (1-lowx_float)*y_percent; - temp = (const char *)dataIn + xindex + lowy_int*rowSizeInBytes; -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * percent; - } -#endif - for (l = lowx_int+1; l < highx_int; l++) { - temp += pixelSizeInBytes; -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += - __GLU_SWAP_2_BYTES(temp_index) * y_percent; - } else { - totals[k] += *(const GLushort*)temp_index * y_percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * y_percent; - } -#endif - } - temp += pixelSizeInBytes; - percent = y_percent * highx_float; -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * percent; - } -#endif - } else { - percent = (highy_float-lowy_float)*(highx_float-lowx_float); - temp = (const char *)dataIn + xindex + lowy_int * rowSizeInBytes; -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index) * percent; - } else { - totals[k] += *(const GLushort*)temp_index * percent; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k] * percent; - } -#endif - } - - /* this is for the pixels in the body */ - temp0 = (const char *)dataIn + xindex + pixelSizeInBytes + (lowy_int+1)*rowSizeInBytes; - for (m = lowy_int+1; m < highy_int; m++) { - temp = temp0; - for(l = lowx_int+1; l < highx_int; l++) { -#if 0 - for (k = 0, temp_index = temp; k < components; - k++, temp_index += element_size) { - if (myswap_bytes) { - totals[k] += __GLU_SWAP_2_BYTES(temp_index); - } else { - totals[k] += *(const GLushort*)temp_index; - } - } -#else - (*extractPackedPixel)(isSwap,temp,extractTotals); - for (k = 0; k < components; k++) { - totals[k]+= extractTotals[k]; - } -#endif - temp += pixelSizeInBytes; - } - temp0 += rowSizeInBytes; - } - - outindex = (j + (i * widthOut)); /* * (components == 1) */ -#if 0 - for (k = 0; k < components; k++) { - dataout[outindex + k] = totals[k]/area; - /*printf("totals[%d] = %f\n", k, totals[k]);*/ - } -#else - for (k = 0; k < components; k++) { - shoveTotals[k]= totals[k]/area; - } - (*shovePackedPixel)(shoveTotals,outindex,(void *)dataOut); -#endif - lowx_int = highx_int; - lowx_float = highx_float; - highx_int += convx_int; - highx_float += convx_float; - if(highx_float > 1) { - highx_float -= 1.0; - highx_int++; - } - } - lowy_int = highy_int; - lowy_float = highy_float; - highy_int += convy_int; - highy_float += convy_float; - if(highy_float > 1) { - highy_float -= 1.0; - highy_int++; - } - } - - assert(outindex == (widthOut*heightOut - 1)); -} /* scaleInternalPackedPixel() */ - -/* rowSizeInBytes is at least the width (in bytes) due to padding on - * inputs; not always equal. Output NEVER has row padding. - */ -static void halveImagePackedPixel(int components, - void (*extractPackedPixel) - (int, const void *,GLfloat []), - void (*shovePackedPixel) - (const GLfloat [],int, void *), - GLint width, GLint height, - const void *dataIn, void *dataOut, - GLint pixelSizeInBytes, - GLint rowSizeInBytes, GLint isSwap) -{ - /* handle case where there is only 1 column/row */ - if (width == 1 || height == 1) { - assert(!(width == 1 && height == 1)); /* can't be 1x1 */ - halve1DimagePackedPixel(components,extractPackedPixel,shovePackedPixel, - width,height,dataIn,dataOut,pixelSizeInBytes, - rowSizeInBytes,isSwap); - return; - } - - { - int ii, jj; - - int halfWidth= width / 2; - int halfHeight= height / 2; - const char *src= (const char *) dataIn; - int padBytes= rowSizeInBytes - (width*pixelSizeInBytes); - int outIndex= 0; - - for (ii= 0; ii< halfHeight; ii++) { - for (jj= 0; jj< halfWidth; jj++) { -#define BOX4 4 - float totals[4]; /* 4 is maximum components */ - float extractTotals[BOX4][4]; /* 4 is maximum components */ - int cc; - - (*extractPackedPixel)(isSwap,src, - &extractTotals[0][0]); - (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes), - &extractTotals[1][0]); - (*extractPackedPixel)(isSwap,(src+rowSizeInBytes), - &extractTotals[2][0]); - (*extractPackedPixel)(isSwap, - (src+rowSizeInBytes+pixelSizeInBytes), - &extractTotals[3][0]); - for (cc = 0; cc < components; cc++) { - int kk; - - /* grab 4 pixels to average */ - totals[cc]= 0.0; - /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ - * extractTotals[2][RED]+extractTotals[3][RED]; - * totals[RED]/= 4.0; - */ - for (kk = 0; kk < BOX4; kk++) { - totals[cc]+= extractTotals[kk][cc]; - } - totals[cc]/= (float)BOX4; - } - (*shovePackedPixel)(totals,outIndex,dataOut); - - outIndex++; - /* skip over to next square of 4 */ - src+= pixelSizeInBytes + pixelSizeInBytes; - } - /* skip past pad bytes, if any, to get to next row */ - src+= padBytes; - - /* src is at beginning of a row here, but it's the second row of - * the square block of 4 pixels that we just worked on so we - * need to go one more row. - * i.e., - * OO... - * here -->OO... - * but want -->OO... - * OO... - * ... - */ - src+= rowSizeInBytes; - } - - /* both pointers must reach one byte after the end */ - assert(src == &((const char *)dataIn)[rowSizeInBytes*height]); - assert(outIndex == halfWidth * halfHeight); - } -} /* halveImagePackedPixel() */ - -static void halve1DimagePackedPixel(int components, - void (*extractPackedPixel) - (int, const void *,GLfloat []), - void (*shovePackedPixel) - (const GLfloat [],int, void *), - GLint width, GLint height, - const void *dataIn, void *dataOut, - GLint pixelSizeInBytes, - GLint rowSizeInBytes, GLint isSwap) -{ - int halfWidth= width / 2; - int halfHeight= height / 2; - const char *src= (const char *) dataIn; - int jj; - - assert(width == 1 || height == 1); /* must be 1D */ - assert(width != height); /* can't be square */ - - if (height == 1) { /* 1 row */ - int outIndex= 0; - - assert(width != 1); /* widthxheight can't be 1x1 */ - halfHeight= 1; - - /* one horizontal row with possible pad bytes */ - - for (jj= 0; jj< halfWidth; jj++) { -#define BOX2 2 - float totals[4]; /* 4 is maximum components */ - float extractTotals[BOX2][4]; /* 4 is maximum components */ - int cc; - - /* average two at a time, instead of four */ - (*extractPackedPixel)(isSwap,src, - &extractTotals[0][0]); - (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes), - &extractTotals[1][0]); - for (cc = 0; cc < components; cc++) { - int kk; - - /* grab 2 pixels to average */ - totals[cc]= 0.0; - /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]; - * totals[RED]/= 2.0; - */ - for (kk = 0; kk < BOX2; kk++) { - totals[cc]+= extractTotals[kk][cc]; - } - totals[cc]/= (float)BOX2; - } - (*shovePackedPixel)(totals,outIndex,dataOut); - - outIndex++; - /* skip over to next group of 2 */ - src+= pixelSizeInBytes + pixelSizeInBytes; - } - - { - int padBytes= rowSizeInBytes - (width*pixelSizeInBytes); - src+= padBytes; /* for assertion only */ - } - assert(src == &((const char *)dataIn)[rowSizeInBytes]); - assert(outIndex == halfWidth * halfHeight); - } - else if (width == 1) { /* 1 column */ - int outIndex= 0; - - assert(height != 1); /* widthxheight can't be 1x1 */ - halfWidth= 1; - /* one vertical column with possible pad bytes per row */ - /* average two at a time */ - - for (jj= 0; jj< halfHeight; jj++) { -#define BOX2 2 - float totals[4]; /* 4 is maximum components */ - float extractTotals[BOX2][4]; /* 4 is maximum components */ - int cc; - - /* average two at a time, instead of four */ - (*extractPackedPixel)(isSwap,src, - &extractTotals[0][0]); - (*extractPackedPixel)(isSwap,(src+rowSizeInBytes), - &extractTotals[1][0]); - for (cc = 0; cc < components; cc++) { - int kk; - - /* grab 2 pixels to average */ - totals[cc]= 0.0; - /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]; - * totals[RED]/= 2.0; - */ - for (kk = 0; kk < BOX2; kk++) { - totals[cc]+= extractTotals[kk][cc]; - } - totals[cc]/= (float)BOX2; - } - (*shovePackedPixel)(totals,outIndex,dataOut); - - outIndex++; - src+= rowSizeInBytes + rowSizeInBytes; /* go to row after next */ - } - - assert(src == &((const char *)dataIn)[rowSizeInBytes*height]); - assert(outIndex == halfWidth * halfHeight); - } -} /* halve1DimagePackedPixel() */ - -/*===========================================================================*/ - -#ifdef RESOLVE_3D_TEXTURE_SUPPORT -/* - * This section ensures that GLU 1.3 will load and run on - * a GL 1.1 implementation. It dynamically resolves the - * call to glTexImage3D() which might not be available. - * Or is it might be supported as an extension. - * Contributed by Gerk Huisma . - */ - -typedef void (GLAPIENTRY *TexImage3Dproc)( GLenum target, GLint level, - GLenum internalFormat, - GLsizei width, GLsizei height, - GLsizei depth, GLint border, - GLenum format, GLenum type, - const GLvoid *pixels ); - -static TexImage3Dproc pTexImage3D = 0; - -#if !defined(_WIN32) && !defined(__WIN32__) -# include -# include -#else - WINGDIAPI PROC WINAPI wglGetProcAddress(LPCSTR); -#endif - -static void gluTexImage3D( GLenum target, GLint level, - GLenum internalFormat, - GLsizei width, GLsizei height, - GLsizei depth, GLint border, - GLenum format, GLenum type, - const GLvoid *pixels ) -{ - if (!pTexImage3D) { -#if defined(_WIN32) || defined(__WIN32__) - pTexImage3D = (TexImage3Dproc) wglGetProcAddress("glTexImage3D"); - if (!pTexImage3D) - pTexImage3D = (TexImage3Dproc) wglGetProcAddress("glTexImage3DEXT"); -#else - void *libHandle = dlopen("libgl.so", RTLD_LAZY); - pTexImage3D = TexImage3Dproc) dlsym(libHandle, "glTexImage3D" ); - if (!pTexImage3D) - pTexImage3D = (TexImage3Dproc) dlsym(libHandle,"glTexImage3DEXT"); - dlclose(libHandle); -#endif - } - - /* Now call glTexImage3D */ - if (pTexImage3D) - pTexImage3D(target, level, internalFormat, width, height, - depth, border, format, type, pixels); -} - -#else - -/* Only bind to a GL 1.2 implementation: */ -#define gluTexImage3D glTexImage3D - -#endif - -static GLint imageSize3D(GLint width, GLint height, GLint depth, - GLenum format, GLenum type) -{ - int components= elements_per_group(format,type); - int bytes_per_row= bytes_per_element(type) * width; - -assert(width > 0 && height > 0 && depth > 0); -assert(type != GL_BITMAP); - - return bytes_per_row * height * depth * components; -} /* imageSize3D() */ - -static void fillImage3D(const PixelStorageModes *psm, - GLint width, GLint height, GLint depth, GLenum format, - GLenum type, GLboolean indexFormat, - const void *userImage, GLushort *newImage) -{ - int myswapBytes; - int components; - int groupsPerLine; - int elementSize; - int groupSize; - int rowSize; - int padding; - int elementsPerLine; - int rowsPerImage; - int imageSize; - const GLubyte *start, *rowStart, *iter; - GLushort *iter2; - int ww, hh, dd, k; - - myswapBytes= psm->unpack_swap_bytes; - components= elements_per_group(format,type); - if (psm->unpack_row_length > 0) { - groupsPerLine= psm->unpack_row_length; - } - else { - groupsPerLine= width; - } - elementSize= bytes_per_element(type); - groupSize= elementSize * components; - if (elementSize == 1) myswapBytes= 0; - - /* 3dstuff begin */ - if (psm->unpack_image_height > 0) { - rowsPerImage= psm->unpack_image_height; - } - else { - rowsPerImage= height; - } - /* 3dstuff end */ - - rowSize= groupsPerLine * groupSize; - padding= rowSize % psm->unpack_alignment; - if (padding) { - rowSize+= psm->unpack_alignment - padding; - } - - imageSize= rowsPerImage * rowSize; /* 3dstuff */ - - start= (const GLubyte *)userImage + psm->unpack_skip_rows * rowSize + - psm->unpack_skip_pixels * groupSize + - /*3dstuff*/ - psm->unpack_skip_images * imageSize; - elementsPerLine = width * components; - - iter2= newImage; - for (dd= 0; dd < depth; dd++) { - rowStart= start; - - for (hh= 0; hh < height; hh++) { - iter= rowStart; - - for (ww= 0; ww < elementsPerLine; ww++) { - Type_Widget widget; - float extractComponents[4]; - - switch(type) { - case GL_UNSIGNED_BYTE: - if (indexFormat) { - *iter2++ = *iter; - } else { - *iter2++ = (*iter) * 257; - } - break; - case GL_BYTE: - if (indexFormat) { - *iter2++ = *((const GLbyte *) iter); - } else { - /* rough approx */ - *iter2++ = (*((const GLbyte *) iter)) * 516; - } - break; - case GL_UNSIGNED_BYTE_3_3_2: - extract332(0,iter,extractComponents); - for (k = 0; k < 3; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_BYTE_2_3_3_REV: - extract233rev(0,iter,extractComponents); - for (k = 0; k < 3; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT_5_6_5: - extract565(myswapBytes,iter,extractComponents); - for (k = 0; k < 3; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT_5_6_5_REV: - extract565rev(myswapBytes,iter,extractComponents); - for (k = 0; k < 3; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - extract4444(myswapBytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - extract4444rev(myswapBytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT_5_5_5_1: - extract5551(myswapBytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - extract1555rev(myswapBytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_SHORT: - case GL_SHORT: - if (myswapBytes) { - widget.ub[0] = iter[1]; - widget.ub[1] = iter[0]; - } else { - widget.ub[0] = iter[0]; - widget.ub[1] = iter[1]; - } - if (type == GL_SHORT) { - if (indexFormat) { - *iter2++ = widget.s[0]; - } else { - /* rough approx */ - *iter2++ = widget.s[0]*2; - } - } else { - *iter2++ = widget.us[0]; - } - break; - case GL_UNSIGNED_INT_8_8_8_8: - extract8888(myswapBytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_INT_8_8_8_8_REV: - extract8888rev(myswapBytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_INT_10_10_10_2: - extract1010102(myswapBytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - extract2101010rev(myswapBytes,iter,extractComponents); - for (k = 0; k < 4; k++) { - *iter2++ = (GLushort)(extractComponents[k]*65535); - } - break; - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - if (myswapBytes) { - widget.ub[0] = iter[3]; - widget.ub[1] = iter[2]; - widget.ub[2] = iter[1]; - widget.ub[3] = iter[0]; - } else { - widget.ub[0] = iter[0]; - widget.ub[1] = iter[1]; - widget.ub[2] = iter[2]; - widget.ub[3] = iter[3]; - } - if (type == GL_FLOAT) { - if (indexFormat) { - *iter2++ = widget.f; - } else { - *iter2++ = 65535 * widget.f; - } - } else if (type == GL_UNSIGNED_INT) { - if (indexFormat) { - *iter2++ = widget.ui; - } else { - *iter2++ = widget.ui >> 16; - } - } else { - if (indexFormat) { - *iter2++ = widget.i; - } else { - *iter2++ = widget.i >> 15; - } - } - break; - default: - assert(0); - } - - iter+= elementSize; - } /* for ww */ - rowStart+= rowSize; - - iter= rowStart; /* for assertion purposes */ - } /* for hh */ - - start+= imageSize; - } /* for dd */ - - /* iterators should be one byte past end */ - if (!isTypePackedPixel(type)) { - assert(iter2 == &newImage[width*height*depth*components]); - } - else { - assert(iter2 == &newImage[width*height*depth* - elements_per_group(format,0)]); - } - assert( iter == &((const GLubyte *)userImage)[rowSize*height*depth + - psm->unpack_skip_rows * rowSize + - psm->unpack_skip_pixels * groupSize + - /*3dstuff*/ - psm->unpack_skip_images * imageSize] ); -} /* fillImage3D () */ - -static void scaleInternal3D(GLint components, - GLint widthIn, GLint heightIn, GLint depthIn, - const GLushort *dataIn, - GLint widthOut, GLint heightOut, GLint depthOut, - GLushort *dataOut) -{ - float x, lowx, highx, convx, halfconvx; - float y, lowy, highy, convy, halfconvy; - float z, lowz, highz, convz, halfconvz; - float xpercent,ypercent,zpercent; - float percent; - /* Max components in a format is 4, so... */ - float totals[4]; - float volume; - int i,j,d,k,zint,yint,xint,xindex,yindex,zindex; - int temp; - - convz = (float) depthIn/depthOut; - convy = (float) heightIn/heightOut; - convx = (float) widthIn/widthOut; - halfconvx = convx/2; - halfconvy = convy/2; - halfconvz = convz/2; - for (d = 0; d < depthOut; d++) { - z = convz * (d+0.5); - if (depthIn > depthOut) { - highz = z + halfconvz; - lowz = z - halfconvz; - } else { - highz = z + 0.5; - lowz = z - 0.5; - } - for (i = 0; i < heightOut; i++) { - y = convy * (i+0.5); - if (heightIn > heightOut) { - highy = y + halfconvy; - lowy = y - halfconvy; - } else { - highy = y + 0.5; - lowy = y - 0.5; - } - for (j = 0; j < widthOut; j++) { - x = convx * (j+0.5); - if (widthIn > widthOut) { - highx = x + halfconvx; - lowx = x - halfconvx; - } else { - highx = x + 0.5; - lowx = x - 0.5; - } - - /* - ** Ok, now apply box filter to box that goes from (lowx, lowy, - ** lowz) to (highx, highy, highz) on input data into this pixel - ** on output data. - */ - totals[0] = totals[1] = totals[2] = totals[3] = 0.0; - volume = 0.0; - - z = lowz; - zint = floor(z); - while (z < highz) { - zindex = (zint + depthIn) % depthIn; - if (highz < zint+1) { - zpercent = highz - z; - } else { - zpercent = zint+1 - z; - } - - y = lowy; - yint = floor(y); - while (y < highy) { - yindex = (yint + heightIn) % heightIn; - if (highy < yint+1) { - ypercent = highy - y; - } else { - ypercent = yint+1 - y; - } - - x = lowx; - xint = floor(x); - - while (x < highx) { - xindex = (xint + widthIn) % widthIn; - if (highx < xint+1) { - xpercent = highx - x; - } else { - xpercent = xint+1 - x; - } - - percent = xpercent * ypercent * zpercent; - volume += percent; - - temp = (xindex + (yindex*widthIn) + - (zindex*widthIn*heightIn)) * components; - for (k = 0; k < components; k++) { - assert(0 <= (temp+k) && - (temp+k) < - (widthIn*heightIn*depthIn*components)); - totals[k] += dataIn[temp + k] * percent; - } - - xint++; - x = xint; - } /* while x */ - - yint++; - y = yint; - } /* while y */ - - zint++; - z = zint; - } /* while z */ - - temp = (j + (i * widthOut) + - (d*widthOut*heightOut)) * components; - for (k = 0; k < components; k++) { - /* totals[] should be rounded in the case of enlarging an - * RGB ramp when the type is 332 or 4444 - */ - assert(0 <= (temp+k) && - (temp+k) < (widthOut*heightOut*depthOut*components)); - dataOut[temp + k] = (totals[k]+0.5)/volume; - } - } /* for j */ - } /* for i */ - } /* for d */ -} /* scaleInternal3D() */ - -static void emptyImage3D(const PixelStorageModes *psm, - GLint width, GLint height, GLint depth, - GLenum format, GLenum type, GLboolean indexFormat, - const GLushort *oldImage, void *userImage) -{ - int myswapBytes; - int components; - int groupsPerLine; - int elementSize; - int groupSize; - int rowSize; - int padding; - GLubyte *start, *rowStart, *iter; - int elementsPerLine; - const GLushort *iter2; - int ii, jj, dd, k; - int rowsPerImage; - int imageSize; - - myswapBytes= psm->pack_swap_bytes; - components = elements_per_group(format,type); - if (psm->pack_row_length > 0) { - groupsPerLine = psm->pack_row_length; - } - else { - groupsPerLine = width; - } - - elementSize= bytes_per_element(type); - groupSize= elementSize * components; - if (elementSize == 1) myswapBytes= 0; - - /* 3dstuff begin */ - if (psm->pack_image_height > 0) { - rowsPerImage= psm->pack_image_height; - } - else { - rowsPerImage= height; - } - - /* 3dstuff end */ - - rowSize = groupsPerLine * groupSize; - padding = rowSize % psm->pack_alignment; - if (padding) { - rowSize+= psm->pack_alignment - padding; - } - - imageSize= rowsPerImage * rowSize; /* 3dstuff */ - - start = (GLubyte *)userImage + psm->pack_skip_rows * rowSize + - psm->pack_skip_pixels * groupSize + - /*3dstuff*/ - psm->pack_skip_images * imageSize; - elementsPerLine= width * components; - - iter2 = oldImage; - for (dd= 0; dd < depth; dd++) { - rowStart= start; - - for (ii= 0; ii< height; ii++) { - iter = rowStart; - - for (jj = 0; jj < elementsPerLine; jj++) { - Type_Widget widget; - float shoveComponents[4]; - - switch(type){ - case GL_UNSIGNED_BYTE: - if (indexFormat) { - *iter = *iter2++; - } else { - *iter = *iter2++ >> 8; - } - break; - case GL_BYTE: - if (indexFormat) { - *((GLbyte *) iter) = *iter2++; - } else { - *((GLbyte *) iter) = *iter2++ >> 9; - } - break; - case GL_UNSIGNED_BYTE_3_3_2: - for (k = 0; k < 3; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove332(shoveComponents,0,(void *)iter); - break; - case GL_UNSIGNED_BYTE_2_3_3_REV: - for (k = 0; k < 3; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove233rev(shoveComponents,0,(void *)iter); - break; - case GL_UNSIGNED_SHORT_5_6_5: - for (k = 0; k < 3; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove565(shoveComponents,0,(void *)&widget.us[0]); - if (myswapBytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } - else { - *(GLushort *)iter = widget.us[0]; - } - break; - case GL_UNSIGNED_SHORT_5_6_5_REV: - for (k = 0; k < 3; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove565rev(shoveComponents,0,(void *)&widget.us[0]); - if (myswapBytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } - else { - *(GLushort *)iter = widget.us[0]; - } - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove4444(shoveComponents,0,(void *)&widget.us[0]); - if (myswapBytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } else { - *(GLushort *)iter = widget.us[0]; - } - break; - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove4444rev(shoveComponents,0,(void *)&widget.us[0]); - if (myswapBytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } else { - *(GLushort *)iter = widget.us[0]; - } - break; - case GL_UNSIGNED_SHORT_5_5_5_1: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove5551(shoveComponents,0,(void *)&widget.us[0]); - if (myswapBytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } else { - *(GLushort *)iter = widget.us[0]; - } - break; - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove1555rev(shoveComponents,0,(void *)&widget.us[0]); - if (myswapBytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } else { - *(GLushort *)iter = widget.us[0]; - } - break; - case GL_UNSIGNED_SHORT: - case GL_SHORT: - if (type == GL_SHORT) { - if (indexFormat) { - widget.s[0] = *iter2++; - } else { - widget.s[0] = *iter2++ >> 1; - } - } else { - widget.us[0] = *iter2++; - } - if (myswapBytes) { - iter[0] = widget.ub[1]; - iter[1] = widget.ub[0]; - } else { - iter[0] = widget.ub[0]; - iter[1] = widget.ub[1]; - } - break; - case GL_UNSIGNED_INT_8_8_8_8: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove8888(shoveComponents,0,(void *)&widget.ui); - if (myswapBytes) { - iter[3] = widget.ub[0]; - iter[2] = widget.ub[1]; - iter[1] = widget.ub[2]; - iter[0] = widget.ub[3]; - } else { - *(GLuint *)iter= widget.ui; - } - break; - case GL_UNSIGNED_INT_8_8_8_8_REV: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove8888rev(shoveComponents,0,(void *)&widget.ui); - if (myswapBytes) { - iter[3] = widget.ub[0]; - iter[2] = widget.ub[1]; - iter[1] = widget.ub[2]; - iter[0] = widget.ub[3]; - } else { - *(GLuint *)iter= widget.ui; - } - break; - case GL_UNSIGNED_INT_10_10_10_2: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove1010102(shoveComponents,0,(void *)&widget.ui); - if (myswapBytes) { - iter[3] = widget.ub[0]; - iter[2] = widget.ub[1]; - iter[1] = widget.ub[2]; - iter[0] = widget.ub[3]; - } else { - *(GLuint *)iter= widget.ui; - } - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - for (k = 0; k < 4; k++) { - shoveComponents[k]= *iter2++ / 65535.0; - } - shove2101010rev(shoveComponents,0,(void *)&widget.ui); - if (myswapBytes) { - iter[3] = widget.ub[0]; - iter[2] = widget.ub[1]; - iter[1] = widget.ub[2]; - iter[0] = widget.ub[3]; - } else { - *(GLuint *)iter= widget.ui; - } - break; - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - if (type == GL_FLOAT) { - if (indexFormat) { - widget.f = *iter2++; - } else { - widget.f = *iter2++ / (float) 65535.0; - } - } else if (type == GL_UNSIGNED_INT) { - if (indexFormat) { - widget.ui = *iter2++; - } else { - widget.ui = (unsigned int) *iter2++ * 65537; - } - } else { - if (indexFormat) { - widget.i = *iter2++; - } else { - widget.i = ((unsigned int) *iter2++ * 65537)/2; - } - } - if (myswapBytes) { - iter[3] = widget.ub[0]; - iter[2] = widget.ub[1]; - iter[1] = widget.ub[2]; - iter[0] = widget.ub[3]; - } else { - iter[0] = widget.ub[0]; - iter[1] = widget.ub[1]; - iter[2] = widget.ub[2]; - iter[3] = widget.ub[3]; - } - break; - default: - assert(0); - } - - iter+= elementSize; - } /* for jj */ - - rowStart+= rowSize; - } /* for ii */ - - start+= imageSize; - } /* for dd */ - - /* iterators should be one byte past end */ - if (!isTypePackedPixel(type)) { - assert(iter2 == &oldImage[width*height*depth*components]); - } - else { - assert(iter2 == &oldImage[width*height*depth* - elements_per_group(format,0)]); - } - assert( iter == &((GLubyte *)userImage)[rowSize*height*depth + - psm->unpack_skip_rows * rowSize + - psm->unpack_skip_pixels * groupSize + - /*3dstuff*/ - psm->unpack_skip_images * imageSize] ); -} /* emptyImage3D() */ - -static -int gluScaleImage3D(GLenum format, - GLint widthIn, GLint heightIn, GLint depthIn, - GLenum typeIn, const void *dataIn, - GLint widthOut, GLint heightOut, GLint depthOut, - GLenum typeOut, void *dataOut) -{ - int components; - GLushort *beforeImage, *afterImage; - PixelStorageModes psm; - - if (widthIn == 0 || heightIn == 0 || depthIn == 0 || - widthOut == 0 || heightOut == 0 || depthOut == 0) { - return 0; - } - - if (widthIn < 0 || heightIn < 0 || depthIn < 0 || - widthOut < 0 || heightOut < 0 || depthOut < 0) { - return GLU_INVALID_VALUE; - } - - if (!legalFormat(format) || !legalType(typeIn) || !legalType(typeOut) || - typeIn == GL_BITMAP || typeOut == GL_BITMAP) { - return GLU_INVALID_ENUM; - } - if (!isLegalFormatForPackedPixelType(format, typeIn)) { - return GLU_INVALID_OPERATION; - } - if (!isLegalFormatForPackedPixelType(format, typeOut)) { - return GLU_INVALID_OPERATION; - } - - beforeImage = malloc(imageSize3D(widthIn, heightIn, depthIn, format, - GL_UNSIGNED_SHORT)); - afterImage = malloc(imageSize3D(widthOut, heightOut, depthOut, format, - GL_UNSIGNED_SHORT)); - if (beforeImage == NULL || afterImage == NULL) { - return GLU_OUT_OF_MEMORY; - } - retrieveStoreModes3D(&psm); - - fillImage3D(&psm,widthIn,heightIn,depthIn,format,typeIn, is_index(format), - dataIn, beforeImage); - components = elements_per_group(format,0); - scaleInternal3D(components,widthIn,heightIn,depthIn,beforeImage, - widthOut,heightOut,depthOut,afterImage); - emptyImage3D(&psm,widthOut,heightOut,depthOut,format,typeOut, - is_index(format),afterImage, dataOut); - free((void *) beforeImage); - free((void *) afterImage); - - return 0; -} /* gluScaleImage3D() */ - - -static void closestFit3D(GLenum target, GLint width, GLint height, GLint depth, - GLint internalFormat, GLenum format, GLenum type, - GLint *newWidth, GLint *newHeight, GLint *newDepth) -{ - GLint widthPowerOf2= nearestPower(width); - GLint heightPowerOf2= nearestPower(height); - GLint depthPowerOf2= nearestPower(depth); - GLint proxyWidth; - - do { - /* compute level 1 width & height & depth, clamping each at 1 */ - GLint widthAtLevelOne= (widthPowerOf2 > 1) ? - widthPowerOf2 >> 1 : - widthPowerOf2; - GLint heightAtLevelOne= (heightPowerOf2 > 1) ? - heightPowerOf2 >> 1 : - heightPowerOf2; - GLint depthAtLevelOne= (depthPowerOf2 > 1) ? - depthPowerOf2 >> 1 : - depthPowerOf2; - GLenum proxyTarget = GL_PROXY_TEXTURE_3D; - assert(widthAtLevelOne > 0); - assert(heightAtLevelOne > 0); - assert(depthAtLevelOne > 0); - - /* does width x height x depth at level 1 & all their mipmaps fit? */ - assert(target == GL_TEXTURE_3D || target == GL_PROXY_TEXTURE_3D); - gluTexImage3D(proxyTarget, 1, /* must be non-zero */ - internalFormat, - widthAtLevelOne,heightAtLevelOne,depthAtLevelOne, - 0,format,type,NULL); - glGetTexLevelParameteriv(proxyTarget, 1,GL_TEXTURE_WIDTH,&proxyWidth); - /* does it fit??? */ - if (proxyWidth == 0) { /* nope, so try again with these sizes */ - if (widthPowerOf2 == 1 && heightPowerOf2 == 1 && - depthPowerOf2 == 1) { - *newWidth= *newHeight= *newDepth= 1; /* must fit 1x1x1 texture */ - return; - } - widthPowerOf2= widthAtLevelOne; - heightPowerOf2= heightAtLevelOne; - depthPowerOf2= depthAtLevelOne; - } - /* else it does fit */ - } while (proxyWidth == 0); - /* loop must terminate! */ - - /* return the width & height at level 0 that fits */ - *newWidth= widthPowerOf2; - *newHeight= heightPowerOf2; - *newDepth= depthPowerOf2; -/*printf("Proxy Textures\n");*/ -} /* closestFit3D() */ - -static void halveImagePackedPixelSlice(int components, - void (*extractPackedPixel) - (int, const void *,GLfloat []), - void (*shovePackedPixel) - (const GLfloat [],int, void *), - GLint width, GLint height, GLint depth, - const void *dataIn, void *dataOut, - GLint pixelSizeInBytes, - GLint rowSizeInBytes, - GLint imageSizeInBytes, - GLint isSwap) -{ - int ii, jj; - int halfWidth= width / 2; - int halfHeight= height / 2; - int halfDepth= depth / 2; - const char *src= (const char *)dataIn; - int outIndex= 0; - - assert((width == 1 || height == 1) && depth >= 2); - - if (width == height) { /* a 1-pixel column viewed from top */ - assert(width == 1 && height == 1); - assert(depth >= 2); - - for (ii= 0; ii< halfDepth; ii++) { - float totals[4]; - float extractTotals[BOX2][4]; - int cc; - - (*extractPackedPixel)(isSwap,src,&extractTotals[0][0]); - (*extractPackedPixel)(isSwap,(src+imageSizeInBytes), - &extractTotals[1][0]); - for (cc = 0; cc < components; cc++) { - int kk; - - /* average 2 pixels since only a column */ - totals[cc]= 0.0; - /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]; - * totals[RED]/= 2.0; - */ - for (kk = 0; kk < BOX2; kk++) { - totals[cc]+= extractTotals[kk][cc]; - } - totals[cc]/= (float)BOX2; - } /* for cc */ - - (*shovePackedPixel)(totals,outIndex,dataOut); - outIndex++; - /* skip over to next group of 2 */ - src+= imageSizeInBytes + imageSizeInBytes; - } /* for ii */ - } - else if (height == 1) { /* horizontal slice viewed from top */ - assert(width != 1); - - for (ii= 0; ii< halfDepth; ii++) { - for (jj= 0; jj< halfWidth; jj++) { - float totals[4]; - float extractTotals[BOX4][4]; - int cc; - - (*extractPackedPixel)(isSwap,src, - &extractTotals[0][0]); - (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes), - &extractTotals[1][0]); - (*extractPackedPixel)(isSwap,(src+imageSizeInBytes), - &extractTotals[2][0]); - (*extractPackedPixel)(isSwap, - (src+imageSizeInBytes+pixelSizeInBytes), - &extractTotals[3][0]); - for (cc = 0; cc < components; cc++) { - int kk; - - /* grab 4 pixels to average */ - totals[cc]= 0.0; - /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ - * extractTotals[2][RED]+extractTotals[3][RED]; - * totals[RED]/= 4.0; - */ - for (kk = 0; kk < BOX4; kk++) { - totals[cc]+= extractTotals[kk][cc]; - } - totals[cc]/= (float)BOX4; - } - (*shovePackedPixel)(totals,outIndex,dataOut); - - outIndex++; - /* skip over to next horizontal square of 4 */ - src+= imageSizeInBytes + imageSizeInBytes; - } - } - - /* assert() */ - } - else if (width == 1) { /* vertical slice viewed from top */ - assert(height != 1); - - for (ii= 0; ii< halfDepth; ii++) { - for (jj= 0; jj< halfHeight; jj++) { - float totals[4]; - float extractTotals[BOX4][4]; - int cc; - - (*extractPackedPixel)(isSwap,src, - &extractTotals[0][0]); - (*extractPackedPixel)(isSwap,(src+rowSizeInBytes), - &extractTotals[1][0]); - (*extractPackedPixel)(isSwap,(src+imageSizeInBytes), - &extractTotals[2][0]); - (*extractPackedPixel)(isSwap, - (src+imageSizeInBytes+rowSizeInBytes), - &extractTotals[3][0]); - for (cc = 0; cc < components; cc++) { - int kk; - - /* grab 4 pixels to average */ - totals[cc]= 0.0; - /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ - * extractTotals[2][RED]+extractTotals[3][RED]; - * totals[RED]/= 4.0; - */ - for (kk = 0; kk < BOX4; kk++) { - totals[cc]+= extractTotals[kk][cc]; - } - totals[cc]/= (float)BOX4; - } - (*shovePackedPixel)(totals,outIndex,dataOut); - - outIndex++; - - /* skip over to next vertical square of 4 */ - src+= imageSizeInBytes + imageSizeInBytes; - } - } - /* assert() */ - } - -} /* halveImagePackedPixelSlice() */ - -static void halveImagePackedPixel3D(int components, - void (*extractPackedPixel) - (int, const void *,GLfloat []), - void (*shovePackedPixel) - (const GLfloat [],int, void *), - GLint width, GLint height, GLint depth, - const void *dataIn, void *dataOut, - GLint pixelSizeInBytes, - GLint rowSizeInBytes, - GLint imageSizeInBytes, - GLint isSwap) -{ - if (depth == 1) { - assert(1 <= width && 1 <= height); - - halveImagePackedPixel(components,extractPackedPixel,shovePackedPixel, - width,height,dataIn,dataOut,pixelSizeInBytes, - rowSizeInBytes,isSwap); - return; - } - /* a horizontal or vertical slice viewed from top */ - else if (width == 1 || height == 1) { - assert(1 <= depth); - - halveImagePackedPixelSlice(components, - extractPackedPixel,shovePackedPixel, - width, height, depth, dataIn, dataOut, - pixelSizeInBytes, rowSizeInBytes, - imageSizeInBytes, isSwap); - return; - } - { - int ii, jj, dd; - - int halfWidth= width / 2; - int halfHeight= height / 2; - int halfDepth= depth / 2; - const char *src= (const char *) dataIn; - int padBytes= rowSizeInBytes - (width*pixelSizeInBytes); - int outIndex= 0; - - for (dd= 0; dd < halfDepth; dd++) { - for (ii= 0; ii< halfHeight; ii++) { - for (jj= 0; jj< halfWidth; jj++) { -#define BOX8 8 - float totals[4]; /* 4 is maximum components */ - float extractTotals[BOX8][4]; /* 4 is maximum components */ - int cc; - - (*extractPackedPixel)(isSwap,src, - &extractTotals[0][0]); - (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes), - &extractTotals[1][0]); - (*extractPackedPixel)(isSwap,(src+rowSizeInBytes), - &extractTotals[2][0]); - (*extractPackedPixel)(isSwap, - (src+rowSizeInBytes+pixelSizeInBytes), - &extractTotals[3][0]); - - (*extractPackedPixel)(isSwap,(src+imageSizeInBytes), - &extractTotals[4][0]); - (*extractPackedPixel)(isSwap,(src+pixelSizeInBytes+imageSizeInBytes), - &extractTotals[5][0]); - (*extractPackedPixel)(isSwap,(src+rowSizeInBytes+imageSizeInBytes), - &extractTotals[6][0]); - (*extractPackedPixel)(isSwap, - (src+rowSizeInBytes+pixelSizeInBytes+imageSizeInBytes), - &extractTotals[7][0]); - for (cc = 0; cc < components; cc++) { - int kk; - - /* grab 8 pixels to average */ - totals[cc]= 0.0; - /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ - * extractTotals[2][RED]+extractTotals[3][RED]+ - * extractTotals[4][RED]+extractTotals[5][RED]+ - * extractTotals[6][RED]+extractTotals[7][RED]; - * totals[RED]/= 8.0; - */ - for (kk = 0; kk < BOX8; kk++) { - totals[cc]+= extractTotals[kk][cc]; - } - totals[cc]/= (float)BOX8; - } - (*shovePackedPixel)(totals,outIndex,dataOut); - - outIndex++; - /* skip over to next square of 4 */ - src+= pixelSizeInBytes + pixelSizeInBytes; - } - /* skip past pad bytes, if any, to get to next row */ - src+= padBytes; - - /* src is at beginning of a row here, but it's the second row of - * the square block of 4 pixels that we just worked on so we - * need to go one more row. - * i.e., - * OO... - * here -->OO... - * but want -->OO... - * OO... - * ... - */ - src+= rowSizeInBytes; - } - - src+= imageSizeInBytes; - } /* for dd */ - - /* both pointers must reach one byte after the end */ - assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]); - assert(outIndex == halfWidth * halfHeight * halfDepth); - } /* for dd */ - -} /* halveImagePackedPixel3D() */ - -static int gluBuild3DMipmapLevelsCore(GLenum target, GLint internalFormat, - GLsizei width, - GLsizei height, - GLsizei depth, - GLsizei widthPowerOf2, - GLsizei heightPowerOf2, - GLsizei depthPowerOf2, - GLenum format, GLenum type, - GLint userLevel, - GLint baseLevel,GLint maxLevel, - const void *data) -{ - GLint newWidth, newHeight, newDepth; - GLint level, levels; - const void *usersImage; - void *srcImage, *dstImage; - __GLU_INIT_SWAP_IMAGE; - GLint memReq; - GLint cmpts; - - GLint myswapBytes, groupsPerLine, elementSize, groupSize; - GLint rowsPerImage, imageSize; - GLint rowSize, padding; - PixelStorageModes psm; - - assert(checkMipmapArgs(internalFormat,format,type) == 0); - assert(width >= 1 && height >= 1 && depth >= 1); - assert(type != GL_BITMAP); - - srcImage = dstImage = NULL; - - newWidth= widthPowerOf2; - newHeight= heightPowerOf2; - newDepth= depthPowerOf2; - levels = computeLog(newWidth); - level = computeLog(newHeight); - if (level > levels) levels=level; - level = computeLog(newDepth); - if (level > levels) levels=level; - - levels+= userLevel; - - retrieveStoreModes3D(&psm); - myswapBytes = psm.unpack_swap_bytes; - cmpts = elements_per_group(format,type); - if (psm.unpack_row_length > 0) { - groupsPerLine = psm.unpack_row_length; - } else { - groupsPerLine = width; - } - - elementSize = bytes_per_element(type); - groupSize = elementSize * cmpts; - if (elementSize == 1) myswapBytes = 0; - - /* 3dstuff begin */ - if (psm.unpack_image_height > 0) { - rowsPerImage= psm.unpack_image_height; - } - else { - rowsPerImage= height; - } - - /* 3dstuff end */ - rowSize = groupsPerLine * groupSize; - padding = (rowSize % psm.unpack_alignment); - if (padding) { - rowSize += psm.unpack_alignment - padding; - } - - imageSize= rowsPerImage * rowSize; /* 3dstuff */ - - usersImage = (const GLubyte *)data + psm.unpack_skip_rows * rowSize + - psm.unpack_skip_pixels * groupSize + - /* 3dstuff */ - psm.unpack_skip_images * imageSize; - - glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0); - glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); - - level = userLevel; - - if (width == newWidth && height == newHeight && depth == newDepth) { - /* Use usersImage for level userLevel */ - if (baseLevel <= level && level <= maxLevel) { - gluTexImage3D(target, level, internalFormat, width, - height, depth, 0, format, type, - usersImage); - } - if(levels == 0) { /* we're done. clean up and return */ - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images); - glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height); - return 0; - } - { - int nextWidth= newWidth/2; - int nextHeight= newHeight/2; - int nextDepth= newDepth/2; - - /* clamp to 1 */ - if (nextWidth < 1) nextWidth= 1; - if (nextHeight < 1) nextHeight= 1; - if (nextDepth < 1) nextDepth= 1; - memReq = imageSize3D(nextWidth, nextHeight, nextDepth, format, type); - } - switch(type) { - case GL_UNSIGNED_BYTE: - dstImage = (GLubyte *)malloc(memReq); - break; - case GL_BYTE: - dstImage = (GLbyte *)malloc(memReq); - break; - case GL_UNSIGNED_SHORT: - dstImage = (GLushort *)malloc(memReq); - break; - case GL_SHORT: - dstImage = (GLshort *)malloc(memReq); - break; - case GL_UNSIGNED_INT: - dstImage = (GLuint *)malloc(memReq); - break; - case GL_INT: - dstImage = (GLint *)malloc(memReq); - break; - case GL_FLOAT: - dstImage = (GLfloat *)malloc(memReq); - break; - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - dstImage = (GLubyte *)malloc(memReq); - break; - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - dstImage = (GLushort *)malloc(memReq); - break; - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - dstImage = (GLuint *)malloc(memReq); - break; - default: - return GLU_INVALID_ENUM; /* assertion */ - } - if (dstImage == NULL) { - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images); - glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height); - return GLU_OUT_OF_MEMORY; - } - else - switch(type) { - case GL_UNSIGNED_BYTE: - if (depth > 1) { - halveImage3D(cmpts,extractUbyte,shoveUbyte, - width,height,depth, - usersImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_ubyte(cmpts,width,height,usersImage,dstImage, - elementSize,rowSize,groupSize); - } - break; - case GL_BYTE: - if (depth > 1) { - halveImage3D(cmpts,extractSbyte,shoveSbyte, - width,height,depth, - usersImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_byte(cmpts,width,height,usersImage,dstImage, - elementSize,rowSize,groupSize); - } - break; - case GL_UNSIGNED_SHORT: - if (depth > 1) { - halveImage3D(cmpts,extractUshort,shoveUshort, - width,height,depth, - usersImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_ushort(cmpts,width,height,usersImage,dstImage, - elementSize,rowSize,groupSize,myswapBytes); - } - break; - case GL_SHORT: - if (depth > 1) { - halveImage3D(cmpts,extractSshort,shoveSshort, - width,height,depth, - usersImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_short(cmpts,width,height,usersImage,dstImage, - elementSize,rowSize,groupSize,myswapBytes); - } - break; - case GL_UNSIGNED_INT: - if (depth > 1) { - halveImage3D(cmpts,extractUint,shoveUint, - width,height,depth, - usersImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_uint(cmpts,width,height,usersImage,dstImage, - elementSize,rowSize,groupSize,myswapBytes); - } - break; - case GL_INT: - if (depth > 1) { - halveImage3D(cmpts,extractSint,shoveSint, - width,height,depth, - usersImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_int(cmpts,width,height,usersImage,dstImage, - elementSize,rowSize,groupSize,myswapBytes); - } - break; - case GL_FLOAT: - if (depth > 1 ) { - halveImage3D(cmpts,extractFloat,shoveFloat, - width,height,depth, - usersImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_float(cmpts,width,height,usersImage,dstImage, - elementSize,rowSize,groupSize,myswapBytes); - } - break; - case GL_UNSIGNED_BYTE_3_3_2: - assert(format == GL_RGB); - halveImagePackedPixel3D(3,extract332,shove332, - width,height,depth,usersImage,dstImage, - elementSize,rowSize,imageSize,myswapBytes); - break; - case GL_UNSIGNED_BYTE_2_3_3_REV: - assert(format == GL_RGB); - halveImagePackedPixel3D(3,extract233rev,shove233rev, - width,height,depth,usersImage,dstImage, - elementSize,rowSize,imageSize,myswapBytes); - break; - case GL_UNSIGNED_SHORT_5_6_5: - halveImagePackedPixel3D(3,extract565,shove565, - width,height,depth,usersImage,dstImage, - elementSize,rowSize,imageSize,myswapBytes); - break; - case GL_UNSIGNED_SHORT_5_6_5_REV: - halveImagePackedPixel3D(3,extract565rev,shove565rev, - width,height,depth,usersImage,dstImage, - elementSize,rowSize,imageSize,myswapBytes); - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - halveImagePackedPixel3D(4,extract4444,shove4444, - width,height,depth,usersImage,dstImage, - elementSize,rowSize,imageSize,myswapBytes); - break; - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - halveImagePackedPixel3D(4,extract4444rev,shove4444rev, - width,height,depth,usersImage,dstImage, - elementSize,rowSize,imageSize,myswapBytes); - break; - case GL_UNSIGNED_SHORT_5_5_5_1: - halveImagePackedPixel3D(4,extract5551,shove5551, - width,height,depth,usersImage,dstImage, - elementSize,rowSize,imageSize,myswapBytes); - break; - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - halveImagePackedPixel3D(4,extract1555rev,shove1555rev, - width,height,depth,usersImage,dstImage, - elementSize,rowSize,imageSize,myswapBytes); - break; - case GL_UNSIGNED_INT_8_8_8_8: - halveImagePackedPixel3D(4,extract8888,shove8888, - width,height,depth,usersImage,dstImage, - elementSize,rowSize,imageSize,myswapBytes); - break; - case GL_UNSIGNED_INT_8_8_8_8_REV: - halveImagePackedPixel3D(4,extract8888rev,shove8888rev, - width,height,depth,usersImage,dstImage, - elementSize,rowSize,imageSize,myswapBytes); - break; - case GL_UNSIGNED_INT_10_10_10_2: - halveImagePackedPixel3D(4,extract1010102,shove1010102, - width,height,depth,usersImage,dstImage, - elementSize,rowSize,imageSize,myswapBytes); - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - halveImagePackedPixel3D(4,extract2101010rev,shove2101010rev, - width,height,depth,usersImage,dstImage, - elementSize,rowSize,imageSize,myswapBytes); - break; - default: - assert(0); - break; - } - newWidth = width/2; - newHeight = height/2; - newDepth = depth/2; - /* clamp to 1 */ - if (newWidth < 1) newWidth= 1; - if (newHeight < 1) newHeight= 1; - if (newDepth < 1) newDepth= 1; - - myswapBytes = 0; - rowSize = newWidth * groupSize; - imageSize= rowSize * newHeight; /* 3dstuff */ - memReq = imageSize3D(newWidth, newHeight, newDepth, format, type); - /* Swap srcImage and dstImage */ - __GLU_SWAP_IMAGE(srcImage,dstImage); - switch(type) { - case GL_UNSIGNED_BYTE: - dstImage = (GLubyte *)malloc(memReq); - break; - case GL_BYTE: - dstImage = (GLbyte *)malloc(memReq); - break; - case GL_UNSIGNED_SHORT: - dstImage = (GLushort *)malloc(memReq); - break; - case GL_SHORT: - dstImage = (GLshort *)malloc(memReq); - break; - case GL_UNSIGNED_INT: - dstImage = (GLuint *)malloc(memReq); - break; - case GL_INT: - dstImage = (GLint *)malloc(memReq); - break; - case GL_FLOAT: - dstImage = (GLfloat *)malloc(memReq); - break; - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - dstImage = (GLubyte *)malloc(memReq); - break; - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - dstImage = (GLushort *)malloc(memReq); - break; - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - dstImage = (GLuint *)malloc(memReq); - break; - default: - return GLU_INVALID_ENUM; /* assertion */ - } - if (dstImage == NULL) { - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images); - glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height); - return GLU_OUT_OF_MEMORY; - } - /* level userLevel+1 is in srcImage; level userLevel already saved */ - level = userLevel+1; - } else {/* user's image is *not* nice power-of-2 sized square */ - memReq = imageSize3D(newWidth, newHeight, newDepth, format, type); - switch(type) { - case GL_UNSIGNED_BYTE: - dstImage = (GLubyte *)malloc(memReq); - break; - case GL_BYTE: - dstImage = (GLbyte *)malloc(memReq); - break; - case GL_UNSIGNED_SHORT: - dstImage = (GLushort *)malloc(memReq); - break; - case GL_SHORT: - dstImage = (GLshort *)malloc(memReq); - break; - case GL_UNSIGNED_INT: - dstImage = (GLuint *)malloc(memReq); - break; - case GL_INT: - dstImage = (GLint *)malloc(memReq); - break; - case GL_FLOAT: - dstImage = (GLfloat *)malloc(memReq); - break; - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - dstImage = (GLubyte *)malloc(memReq); - break; - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - dstImage = (GLushort *)malloc(memReq); - break; - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - dstImage = (GLuint *)malloc(memReq); - break; - default: - return GLU_INVALID_ENUM; /* assertion */ - } - - if (dstImage == NULL) { - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images); - glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height); - return GLU_OUT_OF_MEMORY; - } - /*printf("Build3DMipmaps(): ScaleImage3D %d %d %d->%d %d %d\n", - width,height,depth,newWidth,newHeight,newDepth);*/ - - gluScaleImage3D(format, width, height, depth, type, usersImage, - newWidth, newHeight, newDepth, type, dstImage); - - myswapBytes = 0; - rowSize = newWidth * groupSize; - imageSize = rowSize * newHeight; /* 3dstuff */ - /* Swap dstImage and srcImage */ - __GLU_SWAP_IMAGE(srcImage,dstImage); - - if(levels != 0) { /* use as little memory as possible */ - { - int nextWidth= newWidth/2; - int nextHeight= newHeight/2; - int nextDepth= newDepth/2; - if (nextWidth < 1) nextWidth= 1; - if (nextHeight < 1) nextHeight= 1; - if (nextDepth < 1) nextDepth= 1; - - memReq = imageSize3D(nextWidth, nextHeight, nextDepth, format, type); - } - switch(type) { - case GL_UNSIGNED_BYTE: - dstImage = (GLubyte *)malloc(memReq); - break; - case GL_BYTE: - dstImage = (GLbyte *)malloc(memReq); - break; - case GL_UNSIGNED_SHORT: - dstImage = (GLushort *)malloc(memReq); - break; - case GL_SHORT: - dstImage = (GLshort *)malloc(memReq); - break; - case GL_UNSIGNED_INT: - dstImage = (GLuint *)malloc(memReq); - break; - case GL_INT: - dstImage = (GLint *)malloc(memReq); - break; - case GL_FLOAT: - dstImage = (GLfloat *)malloc(memReq); - break; - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - dstImage = (GLubyte *)malloc(memReq); - break; - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - dstImage = (GLushort *)malloc(memReq); - break; - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - dstImage = (GLuint *)malloc(memReq); - break; - default: - return GLU_INVALID_ENUM; /* assertion */ - } - if (dstImage == NULL) { - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images); - glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height); - return GLU_OUT_OF_MEMORY; - } - } - /* level userLevel is in srcImage; nothing saved yet */ - level = userLevel; - } - - glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); - if (baseLevel <= level && level <= maxLevel) { - gluTexImage3D(target, level, internalFormat, newWidth, newHeight, newDepth, - 0,format, type, (void *)srcImage); - } - level++; /* update current level for the loop */ - for (; level <= levels; level++) { - switch(type) { - case GL_UNSIGNED_BYTE: - if (newDepth > 1) { - halveImage3D(cmpts,extractUbyte,shoveUbyte, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_ubyte(cmpts,newWidth,newHeight,srcImage,dstImage, - elementSize,rowSize,groupSize); - } - break; - case GL_BYTE: - if (newDepth > 1) { - halveImage3D(cmpts,extractSbyte,shoveSbyte, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_byte(cmpts,newWidth,newHeight,srcImage,dstImage, - elementSize,rowSize,groupSize); - } - break; - case GL_UNSIGNED_SHORT: - if (newDepth > 1) { - halveImage3D(cmpts,extractUshort,shoveUshort, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_ushort(cmpts,newWidth,newHeight,srcImage,dstImage, - elementSize,rowSize,groupSize,myswapBytes); - } - break; - case GL_SHORT: - if (newDepth > 1) { - halveImage3D(cmpts,extractSshort,shoveSshort, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_short(cmpts,newWidth,newHeight,srcImage,dstImage, - elementSize,rowSize,groupSize,myswapBytes); - } - break; - case GL_UNSIGNED_INT: - if (newDepth > 1) { - halveImage3D(cmpts,extractUint,shoveUint, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_uint(cmpts,newWidth,newHeight,srcImage,dstImage, - elementSize,rowSize,groupSize,myswapBytes); - } - break; - case GL_INT: - if (newDepth > 1) { - halveImage3D(cmpts,extractSint,shoveSint, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_int(cmpts,newWidth,newHeight,srcImage,dstImage, - elementSize,rowSize,groupSize,myswapBytes); - } - break; - case GL_FLOAT: - if (newDepth > 1) { - halveImage3D(cmpts,extractFloat,shoveFloat, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,groupSize,rowSize, - imageSize,myswapBytes); - } - else { - halveImage_float(cmpts,newWidth,newHeight,srcImage,dstImage, - elementSize,rowSize,groupSize,myswapBytes); - } - break; - case GL_UNSIGNED_BYTE_3_3_2: - halveImagePackedPixel3D(3,extract332,shove332, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,rowSize, - imageSize,myswapBytes); - break; - case GL_UNSIGNED_BYTE_2_3_3_REV: - halveImagePackedPixel3D(3,extract233rev,shove233rev, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,rowSize, - imageSize,myswapBytes); - break; - case GL_UNSIGNED_SHORT_5_6_5: - halveImagePackedPixel3D(3,extract565,shove565, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,rowSize, - imageSize,myswapBytes); - break; - case GL_UNSIGNED_SHORT_5_6_5_REV: - halveImagePackedPixel3D(3,extract565rev,shove565rev, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,rowSize, - imageSize,myswapBytes); - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - halveImagePackedPixel3D(4,extract4444,shove4444, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,rowSize, - imageSize,myswapBytes); - break; - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - halveImagePackedPixel3D(4,extract4444rev,shove4444rev, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,rowSize, - imageSize,myswapBytes); - break; - case GL_UNSIGNED_SHORT_5_5_5_1: - halveImagePackedPixel3D(4,extract5551,shove5551, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,rowSize, - imageSize,myswapBytes); - break; - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - halveImagePackedPixel3D(4,extract1555rev,shove1555rev, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,rowSize, - imageSize,myswapBytes); - break; - case GL_UNSIGNED_INT_8_8_8_8: - halveImagePackedPixel3D(4,extract8888,shove8888, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,rowSize, - imageSize,myswapBytes); - break; - case GL_UNSIGNED_INT_8_8_8_8_REV: - halveImagePackedPixel3D(4,extract8888rev,shove8888rev, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,rowSize, - imageSize,myswapBytes); - break; - case GL_UNSIGNED_INT_10_10_10_2: - halveImagePackedPixel3D(4,extract1010102,shove1010102, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,rowSize, - imageSize,myswapBytes); - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - halveImagePackedPixel3D(4,extract2101010rev,shove2101010rev, - newWidth,newHeight,newDepth, - srcImage,dstImage,elementSize,rowSize, - imageSize,myswapBytes); - break; - default: - assert(0); - break; - } - - __GLU_SWAP_IMAGE(srcImage,dstImage); - - if (newWidth > 1) { newWidth /= 2; rowSize /= 2;} - if (newHeight > 1) { newHeight /= 2; imageSize = rowSize * newHeight; } - if (newDepth > 1) newDepth /= 2; - { - /* call tex image with srcImage untouched since it's not padded */ - if (baseLevel <= level && level <= maxLevel) { - gluTexImage3D(target, level, internalFormat, newWidth, newHeight, - newDepth,0, format, type, (void *) srcImage); - } - } - } /* for level */ - glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); - glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); - glPixelStorei(GL_UNPACK_SKIP_IMAGES, psm.unpack_skip_images); - glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, psm.unpack_image_height); - - free(srcImage); /*if you get to here, a srcImage has always been malloc'ed*/ - if (dstImage) { /* if it's non-rectangular and only 1 level */ - free(dstImage); - } - return 0; -} /* gluBuild3DMipmapLevelsCore() */ - -GLint GLAPIENTRY -gluBuild3DMipmapLevels(GLenum target, GLint internalFormat, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, - GLint userLevel, GLint baseLevel, GLint maxLevel, - const void *data) -{ - int level, levels; - - int rc= checkMipmapArgs(internalFormat,format,type); - if (rc != 0) return rc; - - if (width < 1 || height < 1 || depth < 1) { - return GLU_INVALID_VALUE; - } - - if(type == GL_BITMAP) { - return GLU_INVALID_ENUM; - } - - levels = computeLog(width); - level = computeLog(height); - if (level > levels) levels=level; - level = computeLog(depth); - if (level > levels) levels=level; - - levels+= userLevel; - if (!isLegalLevels(userLevel,baseLevel,maxLevel,levels)) - return GLU_INVALID_VALUE; - - return gluBuild3DMipmapLevelsCore(target, internalFormat, - width, height, depth, - width, height, depth, - format, type, - userLevel, baseLevel, maxLevel, - data); -} /* gluBuild3DMipmapLevels() */ - -GLint GLAPIENTRY -gluBuild3DMipmaps(GLenum target, GLint internalFormat, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const void *data) -{ - GLint widthPowerOf2, heightPowerOf2, depthPowerOf2; - int level, levels; - - int rc= checkMipmapArgs(internalFormat,format,type); - if (rc != 0) return rc; - - if (width < 1 || height < 1 || depth < 1) { - return GLU_INVALID_VALUE; - } - - if(type == GL_BITMAP) { - return GLU_INVALID_ENUM; - } - - closestFit3D(target,width,height,depth,internalFormat,format,type, - &widthPowerOf2,&heightPowerOf2,&depthPowerOf2); - - levels = computeLog(widthPowerOf2); - level = computeLog(heightPowerOf2); - if (level > levels) levels=level; - level = computeLog(depthPowerOf2); - if (level > levels) levels=level; - - return gluBuild3DMipmapLevelsCore(target, internalFormat, - width, height, depth, - widthPowerOf2, heightPowerOf2, - depthPowerOf2, - format, type, 0, 0, levels, - data); -} /* gluBuild3DMipmaps() */ - -static GLdouble extractUbyte(int isSwap, const void *ubyte) -{ - isSwap= isSwap; /* turn off warnings */ - - assert(*((const GLubyte *)ubyte) <= 255); - - return (GLdouble)(*((const GLubyte *)ubyte)); -} /* extractUbyte() */ - -static void shoveUbyte(GLdouble value, int index, void *data) -{ - assert(0.0 <= value && value < 256.0); - - ((GLubyte *)data)[index]= (GLubyte)value; -} /* shoveUbyte() */ - -static GLdouble extractSbyte(int isSwap, const void *sbyte) -{ - isSwap= isSwap; /* turn off warnings */ - - assert(*((const GLbyte *)sbyte) <= 127); - - return (GLdouble)(*((const GLbyte *)sbyte)); -} /* extractSbyte() */ - -static void shoveSbyte(GLdouble value, int index, void *data) -{ - ((GLbyte *)data)[index]= (GLbyte)value; -} /* shoveSbyte() */ - -static GLdouble extractUshort(int isSwap, const void *uitem) -{ - GLushort ushort; - - if (isSwap) { - ushort= __GLU_SWAP_2_BYTES(uitem); - } - else { - ushort= *(const GLushort *)uitem; - } - - assert(ushort <= 65535); - - return (GLdouble)ushort; -} /* extractUshort() */ - -static void shoveUshort(GLdouble value, int index, void *data) -{ - assert(0.0 <= value && value < 65536.0); - - ((GLushort *)data)[index]= (GLushort)value; -} /* shoveUshort() */ - -static GLdouble extractSshort(int isSwap, const void *sitem) -{ - GLshort sshort; - - if (isSwap) { - sshort= __GLU_SWAP_2_BYTES(sitem); - } - else { - sshort= *(const GLshort *)sitem; - } - - assert(sshort <= 32767); - - return (GLdouble)sshort; -} /* extractSshort() */ - -static void shoveSshort(GLdouble value, int index, void *data) -{ - assert(0.0 <= value && value < 32768.0); - - ((GLshort *)data)[index]= (GLshort)value; -} /* shoveSshort() */ - -static GLdouble extractUint(int isSwap, const void *uitem) -{ - GLuint uint; - - if (isSwap) { - uint= __GLU_SWAP_4_BYTES(uitem); - } - else { - uint= *(const GLuint *)uitem; - } - - assert(uint <= 0xffffffff); - - return (GLdouble)uint; -} /* extractUint() */ - -static void shoveUint(GLdouble value, int index, void *data) -{ - assert(0.0 <= value && value <= (GLdouble) UINT_MAX); - - ((GLuint *)data)[index]= (GLuint)value; -} /* shoveUint() */ - -static GLdouble extractSint(int isSwap, const void *sitem) -{ - GLint sint; - - if (isSwap) { - sint= __GLU_SWAP_4_BYTES(sitem); - } - else { - sint= *(const GLint *)sitem; - } - - assert(sint <= 0x7fffffff); - - return (GLdouble)sint; -} /* extractSint() */ - -static void shoveSint(GLdouble value, int index, void *data) -{ - assert(0.0 <= value && value <= (GLdouble) INT_MAX); - - ((GLint *)data)[index]= (GLint)value; -} /* shoveSint() */ - -static GLdouble extractFloat(int isSwap, const void *item) -{ - GLfloat ffloat; - - if (isSwap) { - ffloat= __GLU_SWAP_4_BYTES(item); - } - else { - ffloat= *(const GLfloat *)item; - } - - assert(ffloat <= 1.0); - - return (GLdouble)ffloat; -} /* extractFloat() */ - -static void shoveFloat(GLdouble value, int index, void *data) -{ - assert(0.0 <= value && value <= 1.0); - - ((GLfloat *)data)[index]= value; -} /* shoveFloat() */ - -static void halveImageSlice(int components, - GLdouble (*extract)(int, const void *), - void (*shove)(GLdouble, int, void *), - GLint width, GLint height, GLint depth, - const void *dataIn, void *dataOut, - GLint elementSizeInBytes, - GLint groupSizeInBytes, - GLint rowSizeInBytes, - GLint imageSizeInBytes, - GLint isSwap) -{ - int ii, jj; - int halfWidth= width / 2; - int halfHeight= height / 2; - int halfDepth= depth / 2; - const char *src= (const char *)dataIn; - int rowPadBytes= rowSizeInBytes - (width * groupSizeInBytes); - int imagePadBytes= imageSizeInBytes - (width*height*groupSizeInBytes); - int outIndex= 0; - - assert((width == 1 || height == 1) && depth >= 2); - - if (width == height) { /* a 1-pixel column viewed from top */ - /* printf("1-column\n");*/ - assert(width == 1 && height == 1); - assert(depth >= 2); - - for (ii= 0; ii< halfDepth; ii++) { - int cc; - - for (cc = 0; cc < components; cc++) { - double totals[4]; - double extractTotals[BOX2][4]; - int kk; - - extractTotals[0][cc]= (*extract)(isSwap,src); - extractTotals[1][cc]= (*extract)(isSwap,(src+imageSizeInBytes)); - - /* average 2 pixels since only a column */ - totals[cc]= 0.0; - /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]; - * totals[RED]/= 2.0; - */ - for (kk = 0; kk < BOX2; kk++) { - totals[cc]+= extractTotals[kk][cc]; - } - totals[cc]/= (double)BOX2; - - (*shove)(totals[cc],outIndex,dataOut); - outIndex++; - src+= elementSizeInBytes; - } /* for cc */ - - /* skip over to next group of 2 */ - src+= rowSizeInBytes; - } /* for ii */ - - assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]); - assert(outIndex == halfDepth * components); - } - else if (height == 1) { /* horizontal slice viewed from top */ - /* printf("horizontal slice\n"); */ - assert(width != 1); - - for (ii= 0; ii< halfDepth; ii++) { - for (jj= 0; jj< halfWidth; jj++) { - int cc; - - for (cc = 0; cc < components; cc++) { - int kk; - double totals[4]; - double extractTotals[BOX4][4]; - - extractTotals[0][cc]=(*extract)(isSwap,src); - extractTotals[1][cc]=(*extract)(isSwap, - (src+groupSizeInBytes)); - extractTotals[2][cc]=(*extract)(isSwap, - (src+imageSizeInBytes)); - extractTotals[3][cc]=(*extract)(isSwap, - (src+imageSizeInBytes+groupSizeInBytes)); - - /* grab 4 pixels to average */ - totals[cc]= 0.0; - /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ - * extractTotals[2][RED]+extractTotals[3][RED]; - * totals[RED]/= 4.0; - */ - for (kk = 0; kk < BOX4; kk++) { - totals[cc]+= extractTotals[kk][cc]; - } - totals[cc]/= (double)BOX4; - - (*shove)(totals[cc],outIndex,dataOut); - outIndex++; - - src+= elementSizeInBytes; - } /* for cc */ - - /* skip over to next horizontal square of 4 */ - src+= groupSizeInBytes; - } /* for jj */ - src+= rowPadBytes; - - src+= rowSizeInBytes; - } /* for ii */ - - assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]); - assert(outIndex == halfWidth * halfDepth * components); - } - else if (width == 1) { /* vertical slice viewed from top */ - /* printf("vertical slice\n"); */ - assert(height != 1); - - for (ii= 0; ii< halfDepth; ii++) { - for (jj= 0; jj< halfHeight; jj++) { - int cc; - - for (cc = 0; cc < components; cc++) { - int kk; - double totals[4]; - double extractTotals[BOX4][4]; - - extractTotals[0][cc]=(*extract)(isSwap,src); - extractTotals[1][cc]=(*extract)(isSwap, - (src+rowSizeInBytes)); - extractTotals[2][cc]=(*extract)(isSwap, - (src+imageSizeInBytes)); - extractTotals[3][cc]=(*extract)(isSwap, - (src+imageSizeInBytes+rowSizeInBytes)); - - /* grab 4 pixels to average */ - totals[cc]= 0.0; - /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ - * extractTotals[2][RED]+extractTotals[3][RED]; - * totals[RED]/= 4.0; - */ - for (kk = 0; kk < BOX4; kk++) { - totals[cc]+= extractTotals[kk][cc]; - } - totals[cc]/= (double)BOX4; - - (*shove)(totals[cc],outIndex,dataOut); - outIndex++; - - src+= elementSizeInBytes; - } /* for cc */ - src+= rowPadBytes; - - /* skip over to next vertical square of 4 */ - src+= rowSizeInBytes; - } /* for jj */ - src+= imagePadBytes; - - src+= imageSizeInBytes; - } /* for ii */ - - assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]); - assert(outIndex == halfHeight * halfDepth * components); - } - -} /* halveImageSlice() */ - -static void halveImage3D(int components, - GLdouble (*extract)(int, const void *), - void (*shove)(GLdouble, int, void *), - GLint width, GLint height, GLint depth, - const void *dataIn, void *dataOut, - GLint elementSizeInBytes, - GLint groupSizeInBytes, - GLint rowSizeInBytes, - GLint imageSizeInBytes, - GLint isSwap) -{ - assert(depth > 1); - - /* a horizontal/vertical/one-column slice viewed from top */ - if (width == 1 || height == 1) { - assert(1 <= depth); - - halveImageSlice(components,extract,shove, width, height, depth, - dataIn, dataOut, elementSizeInBytes, groupSizeInBytes, - rowSizeInBytes, imageSizeInBytes, isSwap); - return; - } - { - int ii, jj, dd; - - int halfWidth= width / 2; - int halfHeight= height / 2; - int halfDepth= depth / 2; - const char *src= (const char *) dataIn; - int rowPadBytes= rowSizeInBytes - (width*groupSizeInBytes); - int imagePadBytes= imageSizeInBytes - (width*height*groupSizeInBytes); - int outIndex= 0; - - for (dd= 0; dd < halfDepth; dd++) { - for (ii= 0; ii< halfHeight; ii++) { - for (jj= 0; jj< halfWidth; jj++) { - int cc; - - for (cc= 0; cc < components; cc++) { - int kk; -#define BOX8 8 - double totals[4]; /* 4 is maximum components */ - double extractTotals[BOX8][4]; /* 4 is maximum components */ - - extractTotals[0][cc]= (*extract)(isSwap,src); - extractTotals[1][cc]= (*extract)(isSwap, - (src+groupSizeInBytes)); - extractTotals[2][cc]= (*extract)(isSwap, - (src+rowSizeInBytes)); - extractTotals[3][cc]= (*extract)(isSwap, - (src+rowSizeInBytes+groupSizeInBytes)); - - extractTotals[4][cc]= (*extract)(isSwap, - (src+imageSizeInBytes)); - - extractTotals[5][cc]= (*extract)(isSwap, - (src+groupSizeInBytes+imageSizeInBytes)); - extractTotals[6][cc]= (*extract)(isSwap, - (src+rowSizeInBytes+imageSizeInBytes)); - extractTotals[7][cc]= (*extract)(isSwap, - (src+rowSizeInBytes+groupSizeInBytes+imageSizeInBytes)); - - totals[cc]= 0.0; - - /* totals[RED]= extractTotals[0][RED]+extractTotals[1][RED]+ - * extractTotals[2][RED]+extractTotals[3][RED]+ - * extractTotals[4][RED]+extractTotals[5][RED]+ - * extractTotals[6][RED]+extractTotals[7][RED]; - * totals[RED]/= 8.0; - */ - for (kk = 0; kk < BOX8; kk++) { - totals[cc]+= extractTotals[kk][cc]; - } - totals[cc]/= (double)BOX8; - - (*shove)(totals[cc],outIndex,dataOut); - - outIndex++; - - src+= elementSizeInBytes; /* go to next component */ - } /* for cc */ - - /* skip over to next square of 4 */ - src+= groupSizeInBytes; - } /* for jj */ - /* skip past pad bytes, if any, to get to next row */ - src+= rowPadBytes; - - /* src is at beginning of a row here, but it's the second row of - * the square block of 4 pixels that we just worked on so we - * need to go one more row. - * i.e., - * OO... - * here -->OO... - * but want -->OO... - * OO... - * ... - */ - src+= rowSizeInBytes; - } /* for ii */ - - /* skip past pad bytes, if any, to get to next image */ - src+= imagePadBytes; - - src+= imageSizeInBytes; - } /* for dd */ - - /* both pointers must reach one byte after the end */ - assert(src == &((const char *)dataIn)[rowSizeInBytes*height*depth]); - assert(outIndex == halfWidth * halfHeight * halfDepth * components); - } -} /* halveImage3D() */ - - - -/*** mipmap.c ***/ - diff --git a/GLU/normal.c b/GLU/normal.c deleted file mode 100644 index 0a2494b..0000000 --- a/GLU/normal.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#include "gluos.h" -#include "mesh.h" -#include "tess.h" -#include "normal.h" -#include -#include - -#define TRUE 1 -#define FALSE 0 - -#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2]) - -#if 0 -static void Normalize( GLdouble v[3] ) -{ - GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; - - assert( len > 0 ); - len = sqrt( len ); - v[0] /= len; - v[1] /= len; - v[2] /= len; -} -#endif - -#undef ABS -#define ABS(x) ((x) < 0 ? -(x) : (x)) - -static int LongAxis( GLdouble v[3] ) -{ - int i = 0; - - if( ABS(v[1]) > ABS(v[0]) ) { i = 1; } - if( ABS(v[2]) > ABS(v[i]) ) { i = 2; } - return i; -} - -static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] ) -{ - GLUvertex *v, *v1, *v2; - GLdouble c, tLen2, maxLen2; - GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3]; - GLUvertex *maxVert[3], *minVert[3]; - GLUvertex *vHead = &tess->mesh->vHead; - int i; - - maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD; - minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD; - - for( v = vHead->next; v != vHead; v = v->next ) { - for( i = 0; i < 3; ++i ) { - c = v->coords[i]; - if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; } - if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; } - } - } - - /* Find two vertices separated by at least 1/sqrt(3) of the maximum - * distance between any two vertices - */ - i = 0; - if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; } - if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; } - if( minVal[i] >= maxVal[i] ) { - /* All vertices are the same -- normal doesn't matter */ - norm[0] = 0; norm[1] = 0; norm[2] = 1; - return; - } - - /* Look for a third vertex which forms the triangle with maximum area - * (Length of normal == twice the triangle area) - */ - maxLen2 = 0; - v1 = minVert[i]; - v2 = maxVert[i]; - d1[0] = v1->coords[0] - v2->coords[0]; - d1[1] = v1->coords[1] - v2->coords[1]; - d1[2] = v1->coords[2] - v2->coords[2]; - for( v = vHead->next; v != vHead; v = v->next ) { - d2[0] = v->coords[0] - v2->coords[0]; - d2[1] = v->coords[1] - v2->coords[1]; - d2[2] = v->coords[2] - v2->coords[2]; - tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1]; - tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2]; - tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0]; - tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2]; - if( tLen2 > maxLen2 ) { - maxLen2 = tLen2; - norm[0] = tNorm[0]; - norm[1] = tNorm[1]; - norm[2] = tNorm[2]; - } - } - - if( maxLen2 <= 0 ) { - /* All points lie on a single line -- any decent normal will do */ - norm[0] = norm[1] = norm[2] = 0; - norm[LongAxis(d1)] = 1; - } -} - - -static void CheckOrientation( GLUtesselator *tess ) -{ - GLdouble area; - GLUface *f, *fHead = &tess->mesh->fHead; - GLUvertex *v, *vHead = &tess->mesh->vHead; - GLUhalfEdge *e; - - /* When we compute the normal automatically, we choose the orientation - * so that the the sum of the signed areas of all contours is non-negative. - */ - area = 0; - for( f = fHead->next; f != fHead; f = f->next ) { - e = f->anEdge; - if( e->winding <= 0 ) continue; - do { - area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t); - e = e->Lnext; - } while( e != f->anEdge ); - } - if( area < 0 ) { - /* Reverse the orientation by flipping all the t-coordinates */ - for( v = vHead->next; v != vHead; v = v->next ) { - v->t = - v->t; - } - tess->tUnit[0] = - tess->tUnit[0]; - tess->tUnit[1] = - tess->tUnit[1]; - tess->tUnit[2] = - tess->tUnit[2]; - } -} - -#ifdef FOR_TRITE_TEST_PROGRAM -#include -extern int RandomSweep; -#define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0) -#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0) -#else -#if defined(SLANTED_SWEEP) -/* The "feature merging" is not intended to be complete. There are - * special cases where edges are nearly parallel to the sweep line - * which are not implemented. The algorithm should still behave - * robustly (ie. produce a reasonable tesselation) in the presence - * of such edges, however it may miss features which could have been - * merged. We could minimize this effect by choosing the sweep line - * direction to be something unusual (ie. not parallel to one of the - * coordinate axes). - */ -#define S_UNIT_X 0.50941539564955385 /* Pre-normalized */ -#define S_UNIT_Y 0.86052074622010633 -#else -#define S_UNIT_X 1.0 -#define S_UNIT_Y 0.0 -#endif -#endif - -/* Determine the polygon normal and project vertices onto the plane - * of the polygon. - */ -void __gl_projectPolygon( GLUtesselator *tess ) -{ - GLUvertex *v, *vHead = &tess->mesh->vHead; - GLdouble norm[3]; - GLdouble *sUnit, *tUnit; - int i, computedNormal = FALSE; - - norm[0] = tess->normal[0]; - norm[1] = tess->normal[1]; - norm[2] = tess->normal[2]; - if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { - ComputeNormal( tess, norm ); - computedNormal = TRUE; - } - sUnit = tess->sUnit; - tUnit = tess->tUnit; - i = LongAxis( norm ); - -#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT) - /* Choose the initial sUnit vector to be approximately perpendicular - * to the normal. - */ - Normalize( norm ); - - sUnit[i] = 0; - sUnit[(i+1)%3] = S_UNIT_X; - sUnit[(i+2)%3] = S_UNIT_Y; - - /* Now make it exactly perpendicular */ - w = Dot( sUnit, norm ); - sUnit[0] -= w * norm[0]; - sUnit[1] -= w * norm[1]; - sUnit[2] -= w * norm[2]; - Normalize( sUnit ); - - /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */ - tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1]; - tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2]; - tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0]; - Normalize( tUnit ); -#else - /* Project perpendicular to a coordinate axis -- better numerically */ - sUnit[i] = 0; - sUnit[(i+1)%3] = S_UNIT_X; - sUnit[(i+2)%3] = S_UNIT_Y; - - tUnit[i] = 0; - tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y; - tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X; -#endif - - /* Project the vertices onto the sweep plane */ - for( v = vHead->next; v != vHead; v = v->next ) { - v->s = Dot( v->coords, sUnit ); - v->t = Dot( v->coords, tUnit ); - } - if( computedNormal ) { - CheckOrientation( tess ); - } -} diff --git a/GLU/normal.h b/GLU/normal.h deleted file mode 100644 index c376ca4..0000000 --- a/GLU/normal.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __normal_h_ -#define __normal_h_ - -#include "tess.h" - -/* __gl_projectPolygon( tess ) determines the polygon normal - * and project vertices onto the plane of the polygon. - */ -void __gl_projectPolygon( GLUtesselator *tess ); - -#endif diff --git a/GLU/priorityq-heap.c b/GLU/priorityq-heap.c deleted file mode 100644 index 2d7d164..0000000 --- a/GLU/priorityq-heap.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#include -#include -#include -#include "priorityq-heap.h" -#include "memalloc.h" - -#define INIT_SIZE 32 - -#define TRUE 1 -#define FALSE 0 - -#ifdef FOR_TRITE_TEST_PROGRAM -#define LEQ(x,y) (*pq->leq)(x,y) -#else -/* Violates modularity, but a little faster */ -#include "geom.h" -#define LEQ(x,y) VertLeq((GLUvertex *)x, (GLUvertex *)y) -#endif - -/* really __gl_pqHeapNewPriorityQ */ -PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ) -{ - PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ )); - if (pq == NULL) return NULL; - - pq->size = 0; - pq->max = INIT_SIZE; - pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) ); - if (pq->nodes == NULL) { - memFree(pq); - return NULL; - } - - pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) ); - if (pq->handles == NULL) { - memFree(pq->nodes); - memFree(pq); - return NULL; - } - - pq->initialized = FALSE; - pq->freeList = 0; - pq->leq = leq; - - pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */ - pq->handles[1].key = NULL; - return pq; -} - -/* really __gl_pqHeapDeletePriorityQ */ -void pqDeletePriorityQ( PriorityQ *pq ) -{ - memFree( pq->handles ); - memFree( pq->nodes ); - memFree( pq ); -} - - -static void FloatDown( PriorityQ *pq, long curr ) -{ - PQnode *n = pq->nodes; - PQhandleElem *h = pq->handles; - PQhandle hCurr, hChild; - long child; - - hCurr = n[curr].handle; - for( ;; ) { - child = curr << 1; - if( child < pq->size && LEQ( h[n[child+1].handle].key, - h[n[child].handle].key )) { - ++child; - } - - assert(child <= pq->max); - - hChild = n[child].handle; - if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) { - n[curr].handle = hCurr; - h[hCurr].node = curr; - break; - } - n[curr].handle = hChild; - h[hChild].node = curr; - curr = child; - } -} - - -static void FloatUp( PriorityQ *pq, long curr ) -{ - PQnode *n = pq->nodes; - PQhandleElem *h = pq->handles; - PQhandle hCurr, hParent; - long parent; - - hCurr = n[curr].handle; - for( ;; ) { - parent = curr >> 1; - hParent = n[parent].handle; - if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) { - n[curr].handle = hCurr; - h[hCurr].node = curr; - break; - } - n[curr].handle = hParent; - h[hParent].node = curr; - curr = parent; - } -} - -/* really __gl_pqHeapInit */ -void pqInit( PriorityQ *pq ) -{ - long i; - - /* This method of building a heap is O(n), rather than O(n lg n). */ - - for( i = pq->size; i >= 1; --i ) { - FloatDown( pq, i ); - } - pq->initialized = TRUE; -} - -/* really __gl_pqHeapInsert */ -/* returns LONG_MAX iff out of memory */ -PQhandle pqInsert( PriorityQ *pq, PQkey keyNew ) -{ - long curr; - PQhandle free; - - curr = ++ pq->size; - if( (curr*2) > pq->max ) { - PQnode *saveNodes= pq->nodes; - PQhandleElem *saveHandles= pq->handles; - - /* If the heap overflows, double its size. */ - pq->max <<= 1; - pq->nodes = (PQnode *)memRealloc( pq->nodes, - (size_t) - ((pq->max + 1) * sizeof( pq->nodes[0] ))); - if (pq->nodes == NULL) { - pq->nodes = saveNodes; /* restore ptr to free upon return */ - return LONG_MAX; - } - pq->handles = (PQhandleElem *)memRealloc( pq->handles, - (size_t) - ((pq->max + 1) * - sizeof( pq->handles[0] ))); - if (pq->handles == NULL) { - pq->handles = saveHandles; /* restore ptr to free upon return */ - return LONG_MAX; - } - } - - if( pq->freeList == 0 ) { - free = curr; - } else { - free = pq->freeList; - pq->freeList = pq->handles[free].node; - } - - pq->nodes[curr].handle = free; - pq->handles[free].node = curr; - pq->handles[free].key = keyNew; - - if( pq->initialized ) { - FloatUp( pq, curr ); - } - assert(free != LONG_MAX); - return free; -} - -/* really __gl_pqHeapExtractMin */ -PQkey pqExtractMin( PriorityQ *pq ) -{ - PQnode *n = pq->nodes; - PQhandleElem *h = pq->handles; - PQhandle hMin = n[1].handle; - PQkey min = h[hMin].key; - - if( pq->size > 0 ) { - n[1].handle = n[pq->size].handle; - h[n[1].handle].node = 1; - - h[hMin].key = NULL; - h[hMin].node = pq->freeList; - pq->freeList = hMin; - - if( -- pq->size > 0 ) { - FloatDown( pq, 1 ); - } - } - return min; -} - -/* really __gl_pqHeapDelete */ -void pqDelete( PriorityQ *pq, PQhandle hCurr ) -{ - PQnode *n = pq->nodes; - PQhandleElem *h = pq->handles; - long curr; - - assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL ); - - curr = h[hCurr].node; - n[curr].handle = n[pq->size].handle; - h[n[curr].handle].node = curr; - - if( curr <= -- pq->size ) { - if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) { - FloatDown( pq, curr ); - } else { - FloatUp( pq, curr ); - } - } - h[hCurr].key = NULL; - h[hCurr].node = pq->freeList; - pq->freeList = hCurr; -} diff --git a/GLU/priorityq-heap.h b/GLU/priorityq-heap.h deleted file mode 100644 index dc9aaef..0000000 --- a/GLU/priorityq-heap.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __priorityq_heap_h_ -#define __priorityq_heap_h_ - -/* Use #define's so that another heap implementation can use this one */ - -#define PQkey PQHeapKey -#define PQhandle PQHeapHandle -#define PriorityQ PriorityQHeap - -#define pqNewPriorityQ(leq) __gl_pqHeapNewPriorityQ(leq) -#define pqDeletePriorityQ(pq) __gl_pqHeapDeletePriorityQ(pq) - -/* The basic operations are insertion of a new key (pqInsert), - * and examination/extraction of a key whose value is minimum - * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); - * for this purpose pqInsert returns a "handle" which is supplied - * as the argument. - * - * An initial heap may be created efficiently by calling pqInsert - * repeatedly, then calling pqInit. In any case pqInit must be called - * before any operations other than pqInsert are used. - * - * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. - * This may also be tested with pqIsEmpty. - */ -#define pqInit(pq) __gl_pqHeapInit(pq) -#define pqInsert(pq,key) __gl_pqHeapInsert(pq,key) -#define pqMinimum(pq) __gl_pqHeapMinimum(pq) -#define pqExtractMin(pq) __gl_pqHeapExtractMin(pq) -#define pqDelete(pq,handle) __gl_pqHeapDelete(pq,handle) -#define pqIsEmpty(pq) __gl_pqHeapIsEmpty(pq) - - -/* Since we support deletion the data structure is a little more - * complicated than an ordinary heap. "nodes" is the heap itself; - * active nodes are stored in the range 1..pq->size. When the - * heap exceeds its allocated size (pq->max), its size doubles. - * The children of node i are nodes 2i and 2i+1. - * - * Each node stores an index into an array "handles". Each handle - * stores a key, plus a pointer back to the node which currently - * represents that key (ie. nodes[handles[i].node].handle == i). - */ - -typedef void *PQkey; -typedef long PQhandle; -typedef struct PriorityQ PriorityQ; - -typedef struct { PQhandle handle; } PQnode; -typedef struct { PQkey key; PQhandle node; } PQhandleElem; - -struct PriorityQ { - PQnode *nodes; - PQhandleElem *handles; - long size, max; - PQhandle freeList; - int initialized; - int (*leq)(PQkey key1, PQkey key2); -}; - -PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); -void pqDeletePriorityQ( PriorityQ *pq ); - -void pqInit( PriorityQ *pq ); -PQhandle pqInsert( PriorityQ *pq, PQkey key ); -PQkey pqExtractMin( PriorityQ *pq ); -void pqDelete( PriorityQ *pq, PQhandle handle ); - - -#define __gl_pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key) -#define __gl_pqHeapIsEmpty(pq) ((pq)->size == 0) - -#endif diff --git a/GLU/priorityq-sort.h b/GLU/priorityq-sort.h deleted file mode 100644 index 746cf5f..0000000 --- a/GLU/priorityq-sort.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __priorityq_sort_h_ -#define __priorityq_sort_h_ - -#include "priorityq-heap.h" - -#undef PQkey -#undef PQhandle -#undef PriorityQ -#undef pqNewPriorityQ -#undef pqDeletePriorityQ -#undef pqInit -#undef pqInsert -#undef pqMinimum -#undef pqExtractMin -#undef pqDelete -#undef pqIsEmpty - -/* Use #define's so that another heap implementation can use this one */ - -#define PQkey PQSortKey -#define PQhandle PQSortHandle -#define PriorityQ PriorityQSort - -#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq) -#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq) - -/* The basic operations are insertion of a new key (pqInsert), - * and examination/extraction of a key whose value is minimum - * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); - * for this purpose pqInsert returns a "handle" which is supplied - * as the argument. - * - * An initial heap may be created efficiently by calling pqInsert - * repeatedly, then calling pqInit. In any case pqInit must be called - * before any operations other than pqInsert are used. - * - * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. - * This may also be tested with pqIsEmpty. - */ -#define pqInit(pq) __gl_pqSortInit(pq) -#define pqInsert(pq,key) __gl_pqSortInsert(pq,key) -#define pqMinimum(pq) __gl_pqSortMinimum(pq) -#define pqExtractMin(pq) __gl_pqSortExtractMin(pq) -#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle) -#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq) - - -/* Since we support deletion the data structure is a little more - * complicated than an ordinary heap. "nodes" is the heap itself; - * active nodes are stored in the range 1..pq->size. When the - * heap exceeds its allocated size (pq->max), its size doubles. - * The children of node i are nodes 2i and 2i+1. - * - * Each node stores an index into an array "handles". Each handle - * stores a key, plus a pointer back to the node which currently - * represents that key (ie. nodes[handles[i].node].handle == i). - */ - -typedef PQHeapKey PQkey; -typedef PQHeapHandle PQhandle; -typedef struct PriorityQ PriorityQ; - -struct PriorityQ { - PriorityQHeap *heap; - PQkey *keys; - PQkey **order; - PQhandle size, max; - int initialized; - int (*leq)(PQkey key1, PQkey key2); -}; - -PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); -void pqDeletePriorityQ( PriorityQ *pq ); - -int pqInit( PriorityQ *pq ); -PQhandle pqInsert( PriorityQ *pq, PQkey key ); -PQkey pqExtractMin( PriorityQ *pq ); -void pqDelete( PriorityQ *pq, PQhandle handle ); - -PQkey pqMinimum( PriorityQ *pq ); -int pqIsEmpty( PriorityQ *pq ); - -#endif diff --git a/GLU/priorityq.c b/GLU/priorityq.c deleted file mode 100644 index 11f0263..0000000 --- a/GLU/priorityq.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#include "gluos.h" -#include -#include -#include /* LONG_MAX */ -#include "memalloc.h" - -/* Include all the code for the regular heap-based queue here. */ - -#include "priorityq-heap.c" - -/* Now redefine all the function names to map to their "Sort" versions. */ - -#include "priorityq-sort.h" - -/* really __gl_pqSortNewPriorityQ */ -PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ) -{ - PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ )); - if (pq == NULL) return NULL; - - pq->heap = __gl_pqHeapNewPriorityQ( leq ); - if (pq->heap == NULL) { - memFree(pq); - return NULL; - } - - pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) ); - if (pq->keys == NULL) { - __gl_pqHeapDeletePriorityQ(pq->heap); - memFree(pq); - return NULL; - } - - pq->size = 0; - pq->max = INIT_SIZE; - pq->initialized = FALSE; - pq->leq = leq; - return pq; -} - -/* really __gl_pqSortDeletePriorityQ */ -void pqDeletePriorityQ( PriorityQ *pq ) -{ - assert(pq != NULL); - if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap ); - if (pq->order != NULL) memFree( pq->order ); - if (pq->keys != NULL) memFree( pq->keys ); - memFree( pq ); -} - - -#define LT(x,y) (! LEQ(y,x)) -#define GT(x,y) (! LEQ(x,y)) -#define Swap(a,b) if(1){PQkey *tmp = *a; *a = *b; *b = tmp;}else - -/* really __gl_pqSortInit */ -int pqInit( PriorityQ *pq ) -{ - PQkey **p, **r, **i, **j, *piv; - struct { PQkey **p, **r; } Stack[50], *top = Stack; - unsigned long seed = 2016473283; - - /* Create an array of indirect pointers to the keys, so that we - * the handles we have returned are still valid. - */ -/* - pq->order = (PQHeapKey **)memAlloc( (size_t) - (pq->size * sizeof(pq->order[0])) ); -*/ - pq->order = (PQHeapKey **)memAlloc( (size_t) - ((pq->size+1) * sizeof(pq->order[0])) ); -/* the previous line is a patch to compensate for the fact that IBM */ -/* machines return a null on a malloc of zero bytes (unlike SGI), */ -/* so we have to put in this defense to guard against a memory */ -/* fault four lines down. from fossum@austin.ibm.com. */ - if (pq->order == NULL) return 0; - - p = pq->order; - r = p + pq->size - 1; - for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) { - *i = piv; - } - - /* Sort the indirect pointers in descending order, - * using randomized Quicksort - */ - top->p = p; top->r = r; ++top; - while( --top >= Stack ) { - p = top->p; - r = top->r; - while( r > p + 10 ) { - seed = seed * 1539415821 + 1; - i = p + seed % (r - p + 1); - piv = *i; - *i = *p; - *p = piv; - i = p - 1; - j = r + 1; - do { - do { ++i; } while( GT( **i, *piv )); - do { --j; } while( LT( **j, *piv )); - Swap( i, j ); - } while( i < j ); - Swap( i, j ); /* Undo last swap */ - if( i - p < r - j ) { - top->p = j+1; top->r = r; ++top; - r = i-1; - } else { - top->p = p; top->r = i-1; ++top; - p = j+1; - } - } - /* Insertion sort small lists */ - for( i = p+1; i <= r; ++i ) { - piv = *i; - for( j = i; j > p && LT( **(j-1), *piv ); --j ) { - *j = *(j-1); - } - *j = piv; - } - } - pq->max = pq->size; - pq->initialized = TRUE; - __gl_pqHeapInit( pq->heap ); /* always succeeds */ - -#ifndef NDEBUG - p = pq->order; - r = p + pq->size - 1; - for( i = p; i < r; ++i ) { - assert( LEQ( **(i+1), **i )); - } -#endif - - return 1; -} - -/* really __gl_pqSortInsert */ -/* returns LONG_MAX iff out of memory */ -PQhandle pqInsert( PriorityQ *pq, PQkey keyNew ) -{ - long curr; - - if( pq->initialized ) { - return __gl_pqHeapInsert( pq->heap, keyNew ); - } - curr = pq->size; - if( ++ pq->size >= pq->max ) { - PQkey *saveKey= pq->keys; - - /* If the heap overflows, double its size. */ - pq->max <<= 1; - pq->keys = (PQHeapKey *)memRealloc( pq->keys, - (size_t) - (pq->max * sizeof( pq->keys[0] ))); - if (pq->keys == NULL) { - pq->keys = saveKey; /* restore ptr to free upon return */ - return LONG_MAX; - } - } - assert(curr != LONG_MAX); - pq->keys[curr] = keyNew; - - /* Negative handles index the sorted array. */ - return -(curr+1); -} - -/* really __gl_pqSortExtractMin */ -PQkey pqExtractMin( PriorityQ *pq ) -{ - PQkey sortMin, heapMin; - - if( pq->size == 0 ) { - return __gl_pqHeapExtractMin( pq->heap ); - } - sortMin = *(pq->order[pq->size-1]); - if( ! __gl_pqHeapIsEmpty( pq->heap )) { - heapMin = __gl_pqHeapMinimum( pq->heap ); - if( LEQ( heapMin, sortMin )) { - return __gl_pqHeapExtractMin( pq->heap ); - } - } - do { - -- pq->size; - } while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ); - return sortMin; -} - -/* really __gl_pqSortMinimum */ -PQkey pqMinimum( PriorityQ *pq ) -{ - PQkey sortMin, heapMin; - - if( pq->size == 0 ) { - return __gl_pqHeapMinimum( pq->heap ); - } - sortMin = *(pq->order[pq->size-1]); - if( ! __gl_pqHeapIsEmpty( pq->heap )) { - heapMin = __gl_pqHeapMinimum( pq->heap ); - if( LEQ( heapMin, sortMin )) { - return heapMin; - } - } - return sortMin; -} - -/* really __gl_pqSortIsEmpty */ -int pqIsEmpty( PriorityQ *pq ) -{ - return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap ); -} - -/* really __gl_pqSortDelete */ -void pqDelete( PriorityQ *pq, PQhandle curr ) -{ - if( curr >= 0 ) { - __gl_pqHeapDelete( pq->heap, curr ); - return; - } - curr = -(curr+1); - assert( curr < pq->max && pq->keys[curr] != NULL ); - - pq->keys[curr] = NULL; - while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) { - -- pq->size; - } -} diff --git a/GLU/priorityq.h b/GLU/priorityq.h deleted file mode 100644 index 746cf5f..0000000 --- a/GLU/priorityq.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __priorityq_sort_h_ -#define __priorityq_sort_h_ - -#include "priorityq-heap.h" - -#undef PQkey -#undef PQhandle -#undef PriorityQ -#undef pqNewPriorityQ -#undef pqDeletePriorityQ -#undef pqInit -#undef pqInsert -#undef pqMinimum -#undef pqExtractMin -#undef pqDelete -#undef pqIsEmpty - -/* Use #define's so that another heap implementation can use this one */ - -#define PQkey PQSortKey -#define PQhandle PQSortHandle -#define PriorityQ PriorityQSort - -#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq) -#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq) - -/* The basic operations are insertion of a new key (pqInsert), - * and examination/extraction of a key whose value is minimum - * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete); - * for this purpose pqInsert returns a "handle" which is supplied - * as the argument. - * - * An initial heap may be created efficiently by calling pqInsert - * repeatedly, then calling pqInit. In any case pqInit must be called - * before any operations other than pqInsert are used. - * - * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key. - * This may also be tested with pqIsEmpty. - */ -#define pqInit(pq) __gl_pqSortInit(pq) -#define pqInsert(pq,key) __gl_pqSortInsert(pq,key) -#define pqMinimum(pq) __gl_pqSortMinimum(pq) -#define pqExtractMin(pq) __gl_pqSortExtractMin(pq) -#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle) -#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq) - - -/* Since we support deletion the data structure is a little more - * complicated than an ordinary heap. "nodes" is the heap itself; - * active nodes are stored in the range 1..pq->size. When the - * heap exceeds its allocated size (pq->max), its size doubles. - * The children of node i are nodes 2i and 2i+1. - * - * Each node stores an index into an array "handles". Each handle - * stores a key, plus a pointer back to the node which currently - * represents that key (ie. nodes[handles[i].node].handle == i). - */ - -typedef PQHeapKey PQkey; -typedef PQHeapHandle PQhandle; -typedef struct PriorityQ PriorityQ; - -struct PriorityQ { - PriorityQHeap *heap; - PQkey *keys; - PQkey **order; - PQhandle size, max; - int initialized; - int (*leq)(PQkey key1, PQkey key2); -}; - -PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) ); -void pqDeletePriorityQ( PriorityQ *pq ); - -int pqInit( PriorityQ *pq ); -PQhandle pqInsert( PriorityQ *pq, PQkey key ); -PQkey pqExtractMin( PriorityQ *pq ); -void pqDelete( PriorityQ *pq, PQhandle handle ); - -PQkey pqMinimum( PriorityQ *pq ); -int pqIsEmpty( PriorityQ *pq ); - -#endif diff --git a/GLU/render.c b/GLU/render.c deleted file mode 100644 index 4f376f7..0000000 --- a/GLU/render.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#include "gluos.h" -#include -#include -#include "mesh.h" -#include "tess.h" -#include "render.h" - -#define TRUE 1 -#define FALSE 0 - -/* This structure remembers the information we need about a primitive - * to be able to render it later, once we have determined which - * primitive is able to use the most triangles. - */ -struct FaceCount { - long size; /* number of triangles used */ - GLUhalfEdge *eStart; /* edge where this primitive starts */ - void (*render)(GLUtesselator *, GLUhalfEdge *, long); - /* routine to render this primitive */ -}; - -static struct FaceCount MaximumFan( GLUhalfEdge *eOrig ); -static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig ); - -static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size ); -static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size ); -static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart, - long size ); - -static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig ); -static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head ); - - - -/************************ Strips and Fans decomposition ******************/ - -/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle - * fans, strips, and separate triangles. A substantial effort is made - * to use as few rendering primitives as possible (ie. to make the fans - * and strips as large as possible). - * - * The rendering output is provided as callbacks (see the api). - */ -void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh ) -{ - GLUface *f; - - /* Make a list of separate triangles so we can render them all at once */ - tess->lonelyTriList = NULL; - - for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { - f->marked = FALSE; - } - for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { - - /* We examine all faces in an arbitrary order. Whenever we find - * an unprocessed face F, we output a group of faces including F - * whose size is maximum. - */ - if( f->inside && ! f->marked ) { - RenderMaximumFaceGroup( tess, f ); - assert( f->marked ); - } - } - if( tess->lonelyTriList != NULL ) { - RenderLonelyTriangles( tess, tess->lonelyTriList ); - tess->lonelyTriList = NULL; - } -} - - -static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig ) -{ - /* We want to find the largest triangle fan or strip of unmarked faces - * which includes the given face fOrig. There are 3 possible fans - * passing through fOrig (one centered at each vertex), and 3 possible - * strips (one for each CCW permutation of the vertices). Our strategy - * is to try all of these, and take the primitive which uses the most - * triangles (a greedy approach). - */ - GLUhalfEdge *e = fOrig->anEdge; - struct FaceCount max, newFace; - - max.size = 1; - max.eStart = e; - max.render = &RenderTriangle; - - if( ! tess->flagBoundary ) { - newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; } - newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; } - newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; } - - newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; } - newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; } - newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; } - } - (*(max.render))( tess, max.eStart, max.size ); -} - - -/* Macros which keep track of faces we have marked temporarily, and allow - * us to backtrack when necessary. With triangle fans, this is not - * really necessary, since the only awkward case is a loop of triangles - * around a single origin vertex. However with strips the situation is - * more complicated, and we need a general tracking method like the - * one here. - */ -#define Marked(f) (! (f)->inside || (f)->marked) - -#define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE) - -#define FreeTrail(t) if( 1 ) { \ - while( (t) != NULL ) { \ - (t)->marked = FALSE; t = (t)->trail; \ - } \ - } else /* absorb trailing semicolon */ - - - -static struct FaceCount MaximumFan( GLUhalfEdge *eOrig ) -{ - /* eOrig->Lface is the face we want to render. We want to find the size - * of a maximal fan around eOrig->Org. To do this we just walk around - * the origin vertex as far as possible in both directions. - */ - struct FaceCount newFace = { 0, NULL, &RenderFan }; - GLUface *trail = NULL; - GLUhalfEdge *e; - - for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) { - AddToTrail( e->Lface, trail ); - ++newFace.size; - } - for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) { - AddToTrail( e->Rface, trail ); - ++newFace.size; - } - newFace.eStart = e; - /*LINTED*/ - FreeTrail( trail ); - return newFace; -} - - -#define IsEven(n) (((n) & 1) == 0) - -static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig ) -{ - /* Here we are looking for a maximal strip that contains the vertices - * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the - * reverse, such that all triangles are oriented CCW). - * - * Again we walk forward and backward as far as possible. However for - * strips there is a twist: to get CCW orientations, there must be - * an *even* number of triangles in the strip on one side of eOrig. - * We walk the strip starting on a side with an even number of triangles; - * if both side have an odd number, we are forced to shorten one side. - */ - struct FaceCount newFace = { 0, NULL, &RenderStrip }; - long headSize = 0, tailSize = 0; - GLUface *trail = NULL; - GLUhalfEdge *e, *eTail, *eHead; - - for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) { - AddToTrail( e->Lface, trail ); - ++tailSize; - e = e->Dprev; - if( Marked( e->Lface )) break; - AddToTrail( e->Lface, trail ); - } - eTail = e; - - for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) { - AddToTrail( e->Rface, trail ); - ++headSize; - e = e->Oprev; - if( Marked( e->Rface )) break; - AddToTrail( e->Rface, trail ); - } - eHead = e; - - newFace.size = tailSize + headSize; - if( IsEven( tailSize )) { - newFace.eStart = eTail->Sym; - } else if( IsEven( headSize )) { - newFace.eStart = eHead; - } else { - /* Both sides have odd length, we must shorten one of them. In fact, - * we must start from eHead to guarantee inclusion of eOrig->Lface. - */ - --newFace.size; - newFace.eStart = eHead->Onext; - } - /*LINTED*/ - FreeTrail( trail ); - return newFace; -} - - -static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size ) -{ - /* Just add the triangle to a triangle list, so we can render all - * the separate triangles at once. - */ - assert( size == 1 ); - AddToTrail( e->Lface, tess->lonelyTriList ); -} - - -static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f ) -{ - /* Now we render all the separate triangles which could not be - * grouped into a triangle fan or strip. - */ - GLUhalfEdge *e; - int newState; - int edgeState = -1; /* force edge state output for first vertex */ - - CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES ); - - for( ; f != NULL; f = f->trail ) { - /* Loop once for each edge (there will always be 3 edges) */ - - e = f->anEdge; - do { - if( tess->flagBoundary ) { - /* Set the "edge state" to TRUE just before we output the - * first vertex of each edge on the polygon boundary. - */ - newState = ! e->Rface->inside; - if( edgeState != newState ) { - edgeState = newState; - CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState ); - } - } - CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); - - e = e->Lnext; - } while( e != f->anEdge ); - } - CALL_END_OR_END_DATA(); -} - - -static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size ) -{ - /* Render as many CCW triangles as possible in a fan starting from - * edge "e". The fan *should* contain exactly "size" triangles - * (otherwise we've goofed up somewhere). - */ - CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN ); - CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); - CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); - - while( ! Marked( e->Lface )) { - e->Lface->marked = TRUE; - --size; - e = e->Onext; - CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); - } - - assert( size == 0 ); - CALL_END_OR_END_DATA(); -} - - -static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size ) -{ - /* Render as many CCW triangles as possible in a strip starting from - * edge "e". The strip *should* contain exactly "size" triangles - * (otherwise we've goofed up somewhere). - */ - CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP ); - CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); - CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); - - while( ! Marked( e->Lface )) { - e->Lface->marked = TRUE; - --size; - e = e->Dprev; - CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); - if( Marked( e->Lface )) break; - - e->Lface->marked = TRUE; - --size; - e = e->Onext; - CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data ); - } - - assert( size == 0 ); - CALL_END_OR_END_DATA(); -} - - -/************************ Boundary contour decomposition ******************/ - -/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one - * contour for each face marked "inside". The rendering output is - * provided as callbacks (see the api). - */ -void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh ) -{ - GLUface *f; - GLUhalfEdge *e; - - for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) { - if( f->inside ) { - CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP ); - e = f->anEdge; - do { - CALL_VERTEX_OR_VERTEX_DATA( e->Org->data ); - e = e->Lnext; - } while( e != f->anEdge ); - CALL_END_OR_END_DATA(); - } - } -} - - -/************************ Quick-and-dirty decomposition ******************/ - -#define SIGN_INCONSISTENT 2 - -static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check ) -/* - * If check==FALSE, we compute the polygon normal and place it in norm[]. - * If check==TRUE, we check that each triangle in the fan from v0 has a - * consistent orientation with respect to norm[]. If triangles are - * consistently oriented CCW, return 1; if CW, return -1; if all triangles - * are degenerate return 0; otherwise (no consistent orientation) return - * SIGN_INCONSISTENT. - */ -{ - CachedVertex *v0 = tess->cache; - CachedVertex *vn = v0 + tess->cacheCount; - CachedVertex *vc; - GLdouble dot, xc, yc, zc, xp, yp, zp, n[3]; - int sign = 0; - - /* Find the polygon normal. It is important to get a reasonable - * normal even when the polygon is self-intersecting (eg. a bowtie). - * Otherwise, the computed normal could be very tiny, but perpendicular - * to the true plane of the polygon due to numerical noise. Then all - * the triangles would appear to be degenerate and we would incorrectly - * decompose the polygon as a fan (or simply not render it at all). - * - * We use a sum-of-triangles normal algorithm rather than the more - * efficient sum-of-trapezoids method (used in CheckOrientation() - * in normal.c). This lets us explicitly reverse the signed area - * of some triangles to get a reasonable normal in the self-intersecting - * case. - */ - if( ! check ) { - norm[0] = norm[1] = norm[2] = 0.0; - } - - vc = v0 + 1; - xc = vc->coords[0] - v0->coords[0]; - yc = vc->coords[1] - v0->coords[1]; - zc = vc->coords[2] - v0->coords[2]; - while( ++vc < vn ) { - xp = xc; yp = yc; zp = zc; - xc = vc->coords[0] - v0->coords[0]; - yc = vc->coords[1] - v0->coords[1]; - zc = vc->coords[2] - v0->coords[2]; - - /* Compute (vp - v0) cross (vc - v0) */ - n[0] = yp*zc - zp*yc; - n[1] = zp*xc - xp*zc; - n[2] = xp*yc - yp*xc; - - dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2]; - if( ! check ) { - /* Reverse the contribution of back-facing triangles to get - * a reasonable normal for self-intersecting polygons (see above) - */ - if( dot >= 0 ) { - norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2]; - } else { - norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2]; - } - } else if( dot != 0 ) { - /* Check the new orientation for consistency with previous triangles */ - if( dot > 0 ) { - if( sign < 0 ) return SIGN_INCONSISTENT; - sign = 1; - } else { - if( sign > 0 ) return SIGN_INCONSISTENT; - sign = -1; - } - } - } - return sign; -} - -/* __gl_renderCache( tess ) takes a single contour and tries to render it - * as a triangle fan. This handles convex polygons, as well as some - * non-convex polygons if we get lucky. - * - * Returns TRUE if the polygon was successfully rendered. The rendering - * output is provided as callbacks (see the api). - */ -GLboolean __gl_renderCache( GLUtesselator *tess ) -{ - CachedVertex *v0 = tess->cache; - CachedVertex *vn = v0 + tess->cacheCount; - CachedVertex *vc; - GLdouble norm[3]; - int sign; - - if( tess->cacheCount < 3 ) { - /* Degenerate contour -- no output */ - return TRUE; - } - - norm[0] = tess->normal[0]; - norm[1] = tess->normal[1]; - norm[2] = tess->normal[2]; - if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) { - ComputeNormal( tess, norm, FALSE ); - } - - sign = ComputeNormal( tess, norm, TRUE ); - if( sign == SIGN_INCONSISTENT ) { - /* Fan triangles did not have a consistent orientation */ - return FALSE; - } - if( sign == 0 ) { - /* All triangles were degenerate */ - return TRUE; - } - - /* Make sure we do the right thing for each winding rule */ - switch( tess->windingRule ) { - case GLU_TESS_WINDING_ODD: - case GLU_TESS_WINDING_NONZERO: - break; - case GLU_TESS_WINDING_POSITIVE: - if( sign < 0 ) return TRUE; - break; - case GLU_TESS_WINDING_NEGATIVE: - if( sign > 0 ) return TRUE; - break; - case GLU_TESS_WINDING_ABS_GEQ_TWO: - return TRUE; - } - - CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP - : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN - : GL_TRIANGLES ); - - CALL_VERTEX_OR_VERTEX_DATA( v0->data ); - if( sign > 0 ) { - for( vc = v0+1; vc < vn; ++vc ) { - CALL_VERTEX_OR_VERTEX_DATA( vc->data ); - } - } else { - for( vc = vn-1; vc > v0; --vc ) { - CALL_VERTEX_OR_VERTEX_DATA( vc->data ); - } - } - CALL_END_OR_END_DATA(); - return TRUE; -} diff --git a/GLU/render.h b/GLU/render.h deleted file mode 100644 index a298c9a..0000000 --- a/GLU/render.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __render_h_ -#define __render_h_ - -#include "mesh.h" - -/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle - * fans, strips, and separate triangles. A substantial effort is made - * to use as few rendering primitives as possible (ie. to make the fans - * and strips as large as possible). - * - * The rendering output is provided as callbacks (see the api). - */ -void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh ); -void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh ); - -GLboolean __gl_renderCache( GLUtesselator *tess ); - -#endif diff --git a/GLU/sweep.c b/GLU/sweep.c deleted file mode 100644 index 744be6b..0000000 --- a/GLU/sweep.c +++ /dev/null @@ -1,1357 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#include "gluos.h" -#include -#include -#include /* longjmp */ -#include /* LONG_MAX */ - -#include "mesh.h" -#include "geom.h" -#include "tess.h" -#include "dict.h" -#include "priorityq.h" -#include "memalloc.h" -#include "sweep.h" - -#define TRUE 1 -#define FALSE 0 - -#ifdef FOR_TRITE_TEST_PROGRAM -extern void DebugEvent( GLUtesselator *tess ); -#else -#define DebugEvent( tess ) -#endif - -/* - * Invariants for the Edge Dictionary. - * - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2) - * at any valid location of the sweep event - * - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2 - * share a common endpoint - * - for each e, e->Dst has been processed, but not e->Org - * - each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org) - * where "event" is the current sweep line event. - * - no edge e has zero length - * - * Invariants for the Mesh (the processed portion). - * - the portion of the mesh left of the sweep line is a planar graph, - * ie. there is *some* way to embed it in the plane - * - no processed edge has zero length - * - no two processed vertices have identical coordinates - * - each "inside" region is monotone, ie. can be broken into two chains - * of monotonically increasing vertices according to VertLeq(v1,v2) - * - a non-invariant: these chains may intersect (very slightly) - * - * Invariants for the Sweep. - * - if none of the edges incident to the event vertex have an activeRegion - * (ie. none of these edges are in the edge dictionary), then the vertex - * has only right-going edges. - * - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced - * by ConnectRightVertex), then it is the only right-going edge from - * its associated vertex. (This says that these edges exist only - * when it is necessary.) - */ - -#undef MAX -#undef MIN -#define MAX(x,y) ((x) >= (y) ? (x) : (y)) -#define MIN(x,y) ((x) <= (y) ? (x) : (y)) - -/* When we merge two edges into one, we need to compute the combined - * winding of the new edge. - */ -#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \ - eDst->Sym->winding += eSrc->Sym->winding) - -static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent ); -static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp ); -static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp ); - -static int EdgeLeq( GLUtesselator *tess, ActiveRegion *reg1, - ActiveRegion *reg2 ) -/* - * Both edges must be directed from right to left (this is the canonical - * direction for the upper edge of each region). - * - * The strategy is to evaluate a "t" value for each edge at the - * current sweep line position, given by tess->event. The calculations - * are designed to be very stable, but of course they are not perfect. - * - * Special case: if both edge destinations are at the sweep event, - * we sort the edges by slope (they would otherwise compare equally). - */ -{ - GLUvertex *event = tess->event; - GLUhalfEdge *e1, *e2; - GLdouble t1, t2; - - e1 = reg1->eUp; - e2 = reg2->eUp; - - if( e1->Dst == event ) { - if( e2->Dst == event ) { - /* Two edges right of the sweep line which meet at the sweep event. - * Sort them by slope. - */ - if( VertLeq( e1->Org, e2->Org )) { - return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0; - } - return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0; - } - return EdgeSign( e2->Dst, event, e2->Org ) <= 0; - } - if( e2->Dst == event ) { - return EdgeSign( e1->Dst, event, e1->Org ) >= 0; - } - - /* General case - compute signed distance *from* e1, e2 to event */ - t1 = EdgeEval( e1->Dst, event, e1->Org ); - t2 = EdgeEval( e2->Dst, event, e2->Org ); - return (t1 >= t2); -} - - -static void DeleteRegion( GLUtesselator *tess, ActiveRegion *reg ) -{ - if( reg->fixUpperEdge ) { - /* It was created with zero winding number, so it better be - * deleted with zero winding number (ie. it better not get merged - * with a real edge). - */ - assert( reg->eUp->winding == 0 ); - } - reg->eUp->activeRegion = NULL; - dictDelete( tess->dict, reg->nodeUp ); /* __gl_dictListDelete */ - memFree( reg ); -} - - -static int FixUpperEdge( ActiveRegion *reg, GLUhalfEdge *newEdge ) -/* - * Replace an upper edge which needs fixing (see ConnectRightVertex). - */ -{ - assert( reg->fixUpperEdge ); - if ( !__gl_meshDelete( reg->eUp ) ) return 0; - reg->fixUpperEdge = FALSE; - reg->eUp = newEdge; - newEdge->activeRegion = reg; - - return 1; -} - -static ActiveRegion *TopLeftRegion( ActiveRegion *reg ) -{ - GLUvertex *org = reg->eUp->Org; - GLUhalfEdge *e; - - /* Find the region above the uppermost edge with the same origin */ - do { - reg = RegionAbove( reg ); - } while( reg->eUp->Org == org ); - - /* If the edge above was a temporary edge introduced by ConnectRightVertex, - * now is the time to fix it. - */ - if( reg->fixUpperEdge ) { - e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext ); - if (e == NULL) return NULL; - if ( !FixUpperEdge( reg, e ) ) return NULL; - reg = RegionAbove( reg ); - } - return reg; -} - -static ActiveRegion *TopRightRegion( ActiveRegion *reg ) -{ - GLUvertex *dst = reg->eUp->Dst; - - /* Find the region above the uppermost edge with the same destination */ - do { - reg = RegionAbove( reg ); - } while( reg->eUp->Dst == dst ); - return reg; -} - -static ActiveRegion *AddRegionBelow( GLUtesselator *tess, - ActiveRegion *regAbove, - GLUhalfEdge *eNewUp ) -/* - * Add a new active region to the sweep line, *somewhere* below "regAbove" - * (according to where the new edge belongs in the sweep-line dictionary). - * The upper edge of the new region will be "eNewUp". - * Winding number and "inside" flag are not updated. - */ -{ - ActiveRegion *regNew = (ActiveRegion *)memAlloc( sizeof( ActiveRegion )); - if (regNew == NULL) longjmp(tess->env,1); - - regNew->eUp = eNewUp; - /* __gl_dictListInsertBefore */ - regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew ); - if (regNew->nodeUp == NULL) longjmp(tess->env,1); - regNew->fixUpperEdge = FALSE; - regNew->sentinel = FALSE; - regNew->dirty = FALSE; - - eNewUp->activeRegion = regNew; - return regNew; -} - -static GLboolean IsWindingInside( GLUtesselator *tess, int n ) -{ - switch( tess->windingRule ) { - case GLU_TESS_WINDING_ODD: - return (n & 1); - case GLU_TESS_WINDING_NONZERO: - return (n != 0); - case GLU_TESS_WINDING_POSITIVE: - return (n > 0); - case GLU_TESS_WINDING_NEGATIVE: - return (n < 0); - case GLU_TESS_WINDING_ABS_GEQ_TWO: - return (n >= 2) || (n <= -2); - } - /*LINTED*/ - assert( FALSE ); - /*NOTREACHED*/ - return GL_FALSE; /* avoid compiler complaints */ -} - - -static void ComputeWinding( GLUtesselator *tess, ActiveRegion *reg ) -{ - reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding; - reg->inside = IsWindingInside( tess, reg->windingNumber ); -} - - -static void FinishRegion( GLUtesselator *tess, ActiveRegion *reg ) -/* - * Delete a region from the sweep line. This happens when the upper - * and lower chains of a region meet (at a vertex on the sweep line). - * The "inside" flag is copied to the appropriate mesh face (we could - * not do this before -- since the structure of the mesh is always - * changing, this face may not have even existed until now). - */ -{ - GLUhalfEdge *e = reg->eUp; - GLUface *f = e->Lface; - - f->inside = reg->inside; - f->anEdge = e; /* optimization for __gl_meshTessellateMonoRegion() */ - DeleteRegion( tess, reg ); -} - - -static GLUhalfEdge *FinishLeftRegions( GLUtesselator *tess, - ActiveRegion *regFirst, ActiveRegion *regLast ) -/* - * We are given a vertex with one or more left-going edges. All affected - * edges should be in the edge dictionary. Starting at regFirst->eUp, - * we walk down deleting all regions where both edges have the same - * origin vOrg. At the same time we copy the "inside" flag from the - * active region to the face, since at this point each face will belong - * to at most one region (this was not necessarily true until this point - * in the sweep). The walk stops at the region above regLast; if regLast - * is NULL we walk as far as possible. At the same time we relink the - * mesh if necessary, so that the ordering of edges around vOrg is the - * same as in the dictionary. - */ -{ - ActiveRegion *reg, *regPrev; - GLUhalfEdge *e, *ePrev; - - regPrev = regFirst; - ePrev = regFirst->eUp; - while( regPrev != regLast ) { - regPrev->fixUpperEdge = FALSE; /* placement was OK */ - reg = RegionBelow( regPrev ); - e = reg->eUp; - if( e->Org != ePrev->Org ) { - if( ! reg->fixUpperEdge ) { - /* Remove the last left-going edge. Even though there are no further - * edges in the dictionary with this origin, there may be further - * such edges in the mesh (if we are adding left edges to a vertex - * that has already been processed). Thus it is important to call - * FinishRegion rather than just DeleteRegion. - */ - FinishRegion( tess, regPrev ); - break; - } - /* If the edge below was a temporary edge introduced by - * ConnectRightVertex, now is the time to fix it. - */ - e = __gl_meshConnect( ePrev->Lprev, e->Sym ); - if (e == NULL) longjmp(tess->env,1); - if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1); - } - - /* Relink edges so that ePrev->Onext == e */ - if( ePrev->Onext != e ) { - if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1); - if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1); - } - FinishRegion( tess, regPrev ); /* may change reg->eUp */ - ePrev = reg->eUp; - regPrev = reg; - } - return ePrev; -} - - -static void AddRightEdges( GLUtesselator *tess, ActiveRegion *regUp, - GLUhalfEdge *eFirst, GLUhalfEdge *eLast, GLUhalfEdge *eTopLeft, - GLboolean cleanUp ) -/* - * Purpose: insert right-going edges into the edge dictionary, and update - * winding numbers and mesh connectivity appropriately. All right-going - * edges share a common origin vOrg. Edges are inserted CCW starting at - * eFirst; the last edge inserted is eLast->Oprev. If vOrg has any - * left-going edges already processed, then eTopLeft must be the edge - * such that an imaginary upward vertical segment from vOrg would be - * contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft - * should be NULL. - */ -{ - ActiveRegion *reg, *regPrev; - GLUhalfEdge *e, *ePrev; - int firstTime = TRUE; - - /* Insert the new right-going edges in the dictionary */ - e = eFirst; - do { - assert( VertLeq( e->Org, e->Dst )); - AddRegionBelow( tess, regUp, e->Sym ); - e = e->Onext; - } while ( e != eLast ); - - /* Walk *all* right-going edges from e->Org, in the dictionary order, - * updating the winding numbers of each region, and re-linking the mesh - * edges to match the dictionary ordering (if necessary). - */ - if( eTopLeft == NULL ) { - eTopLeft = RegionBelow( regUp )->eUp->Rprev; - } - regPrev = regUp; - ePrev = eTopLeft; - for( ;; ) { - reg = RegionBelow( regPrev ); - e = reg->eUp->Sym; - if( e->Org != ePrev->Org ) break; - - if( e->Onext != ePrev ) { - /* Unlink e from its current position, and relink below ePrev */ - if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1); - if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1); - } - /* Compute the winding number and "inside" flag for the new regions */ - reg->windingNumber = regPrev->windingNumber - e->winding; - reg->inside = IsWindingInside( tess, reg->windingNumber ); - - /* Check for two outgoing edges with same slope -- process these - * before any intersection tests (see example in __gl_computeInterior). - */ - regPrev->dirty = TRUE; - if( ! firstTime && CheckForRightSplice( tess, regPrev )) { - AddWinding( e, ePrev ); - DeleteRegion( tess, regPrev ); - if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1); - } - firstTime = FALSE; - regPrev = reg; - ePrev = e; - } - regPrev->dirty = TRUE; - assert( regPrev->windingNumber - e->winding == reg->windingNumber ); - - if( cleanUp ) { - /* Check for intersections between newly adjacent edges. */ - WalkDirtyRegions( tess, regPrev ); - } -} - - -static void CallCombine( GLUtesselator *tess, GLUvertex *isect, - void *data[4], GLfloat weights[4], int needed ) -{ - GLdouble coords[3]; - - /* Copy coord data in case the callback changes it. */ - coords[0] = isect->coords[0]; - coords[1] = isect->coords[1]; - coords[2] = isect->coords[2]; - - isect->data = NULL; - CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data ); - if( isect->data == NULL ) { - if( ! needed ) { - isect->data = data[0]; - } else if( ! tess->fatalError ) { - /* The only way fatal error is when two edges are found to intersect, - * but the user has not provided the callback necessary to handle - * generated intersection points. - */ - CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK ); - tess->fatalError = TRUE; - } - } -} - -static void SpliceMergeVertices( GLUtesselator *tess, GLUhalfEdge *e1, - GLUhalfEdge *e2 ) -/* - * Two vertices with idential coordinates are combined into one. - * e1->Org is kept, while e2->Org is discarded. - */ -{ - void *data[4] = { NULL, NULL, NULL, NULL }; - GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 }; - - data[0] = e1->Org->data; - data[1] = e2->Org->data; - CallCombine( tess, e1->Org, data, weights, FALSE ); - if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1); -} - -static void VertexWeights( GLUvertex *isect, GLUvertex *org, GLUvertex *dst, - GLfloat *weights ) -/* - * Find some weights which describe how the intersection vertex is - * a linear combination of "org" and "dest". Each of the two edges - * which generated "isect" is allocated 50% of the weight; each edge - * splits the weight between its org and dst according to the - * relative distance to "isect". - */ -{ - GLdouble t1 = VertL1dist( org, isect ); - GLdouble t2 = VertL1dist( dst, isect ); - - weights[0] = 0.5 * t2 / (t1 + t2); - weights[1] = 0.5 * t1 / (t1 + t2); - isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0]; - isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1]; - isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2]; -} - - -static void GetIntersectData( GLUtesselator *tess, GLUvertex *isect, - GLUvertex *orgUp, GLUvertex *dstUp, - GLUvertex *orgLo, GLUvertex *dstLo ) -/* - * We've computed a new intersection point, now we need a "data" pointer - * from the user so that we can refer to this new vertex in the - * rendering callbacks. - */ -{ - void *data[4]; - GLfloat weights[4]; - - data[0] = orgUp->data; - data[1] = dstUp->data; - data[2] = orgLo->data; - data[3] = dstLo->data; - - isect->coords[0] = isect->coords[1] = isect->coords[2] = 0; - VertexWeights( isect, orgUp, dstUp, &weights[0] ); - VertexWeights( isect, orgLo, dstLo, &weights[2] ); - - CallCombine( tess, isect, data, weights, TRUE ); -} - -static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp ) -/* - * Check the upper and lower edge of "regUp", to make sure that the - * eUp->Org is above eLo, or eLo->Org is below eUp (depending on which - * origin is leftmost). - * - * The main purpose is to splice right-going edges with the same - * dest vertex and nearly identical slopes (ie. we can't distinguish - * the slopes numerically). However the splicing can also help us - * to recover from numerical errors. For example, suppose at one - * point we checked eUp and eLo, and decided that eUp->Org is barely - * above eLo. Then later, we split eLo into two edges (eg. from - * a splice operation like this one). This can change the result of - * our test so that now eUp->Org is incident to eLo, or barely below it. - * We must correct this condition to maintain the dictionary invariants. - * - * One possibility is to check these edges for intersection again - * (ie. CheckForIntersect). This is what we do if possible. However - * CheckForIntersect requires that tess->event lies between eUp and eLo, - * so that it has something to fall back on when the intersection - * calculation gives us an unusable answer. So, for those cases where - * we can't check for intersection, this routine fixes the problem - * by just splicing the offending vertex into the other edge. - * This is a guaranteed solution, no matter how degenerate things get. - * Basically this is a combinatorial solution to a numerical problem. - */ -{ - ActiveRegion *regLo = RegionBelow(regUp); - GLUhalfEdge *eUp = regUp->eUp; - GLUhalfEdge *eLo = regLo->eUp; - - if( VertLeq( eUp->Org, eLo->Org )) { - if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) return FALSE; - - /* eUp->Org appears to be below eLo */ - if( ! VertEq( eUp->Org, eLo->Org )) { - /* Splice eUp->Org into eLo */ - if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); - if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1); - regUp->dirty = regLo->dirty = TRUE; - - } else if( eUp->Org != eLo->Org ) { - /* merge the two vertices, discarding eUp->Org */ - pqDelete( tess->pq, eUp->Org->pqHandle ); /* __gl_pqSortDelete */ - SpliceMergeVertices( tess, eLo->Oprev, eUp ); - } - } else { - if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE; - - /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */ - RegionAbove(regUp)->dirty = regUp->dirty = TRUE; - if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); - if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1); - } - return TRUE; -} - -static int CheckForLeftSplice( GLUtesselator *tess, ActiveRegion *regUp ) -/* - * Check the upper and lower edge of "regUp", to make sure that the - * eUp->Dst is above eLo, or eLo->Dst is below eUp (depending on which - * destination is rightmost). - * - * Theoretically, this should always be true. However, splitting an edge - * into two pieces can change the results of previous tests. For example, - * suppose at one point we checked eUp and eLo, and decided that eUp->Dst - * is barely above eLo. Then later, we split eLo into two edges (eg. from - * a splice operation like this one). This can change the result of - * the test so that now eUp->Dst is incident to eLo, or barely below it. - * We must correct this condition to maintain the dictionary invariants - * (otherwise new edges might get inserted in the wrong place in the - * dictionary, and bad stuff will happen). - * - * We fix the problem by just splicing the offending vertex into the - * other edge. - */ -{ - ActiveRegion *regLo = RegionBelow(regUp); - GLUhalfEdge *eUp = regUp->eUp; - GLUhalfEdge *eLo = regLo->eUp; - GLUhalfEdge *e; - - assert( ! VertEq( eUp->Dst, eLo->Dst )); - - if( VertLeq( eUp->Dst, eLo->Dst )) { - if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) return FALSE; - - /* eLo->Dst is above eUp, so splice eLo->Dst into eUp */ - RegionAbove(regUp)->dirty = regUp->dirty = TRUE; - e = __gl_meshSplitEdge( eUp ); - if (e == NULL) longjmp(tess->env,1); - if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1); - e->Lface->inside = regUp->inside; - } else { - if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) return FALSE; - - /* eUp->Dst is below eLo, so splice eUp->Dst into eLo */ - regUp->dirty = regLo->dirty = TRUE; - e = __gl_meshSplitEdge( eLo ); - if (e == NULL) longjmp(tess->env,1); - if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1); - e->Rface->inside = regUp->inside; - } - return TRUE; -} - - -static int CheckForIntersect( GLUtesselator *tess, ActiveRegion *regUp ) -/* - * Check the upper and lower edges of the given region to see if - * they intersect. If so, create the intersection and add it - * to the data structures. - * - * Returns TRUE if adding the new intersection resulted in a recursive - * call to AddRightEdges(); in this case all "dirty" regions have been - * checked for intersections, and possibly regUp has been deleted. - */ -{ - ActiveRegion *regLo = RegionBelow(regUp); - GLUhalfEdge *eUp = regUp->eUp; - GLUhalfEdge *eLo = regLo->eUp; - GLUvertex *orgUp = eUp->Org; - GLUvertex *orgLo = eLo->Org; - GLUvertex *dstUp = eUp->Dst; - GLUvertex *dstLo = eLo->Dst; - GLdouble tMinUp, tMaxLo; - GLUvertex isect, *orgMin; - GLUhalfEdge *e; - - assert( ! VertEq( dstLo, dstUp )); - assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 ); - assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 ); - assert( orgUp != tess->event && orgLo != tess->event ); - assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge ); - - if( orgUp == orgLo ) return FALSE; /* right endpoints are the same */ - - tMinUp = MIN( orgUp->t, dstUp->t ); - tMaxLo = MAX( orgLo->t, dstLo->t ); - if( tMinUp > tMaxLo ) return FALSE; /* t ranges do not overlap */ - - if( VertLeq( orgUp, orgLo )) { - if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) return FALSE; - } else { - if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) return FALSE; - } - - /* At this point the edges intersect, at least marginally */ - DebugEvent( tess ); - - __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect ); - /* The following properties are guaranteed: */ - assert( MIN( orgUp->t, dstUp->t ) <= isect.t ); - assert( isect.t <= MAX( orgLo->t, dstLo->t )); - assert( MIN( dstLo->s, dstUp->s ) <= isect.s ); - assert( isect.s <= MAX( orgLo->s, orgUp->s )); - - if( VertLeq( &isect, tess->event )) { - /* The intersection point lies slightly to the left of the sweep line, - * so move it until it''s slightly to the right of the sweep line. - * (If we had perfect numerical precision, this would never happen - * in the first place). The easiest and safest thing to do is - * replace the intersection by tess->event. - */ - isect.s = tess->event->s; - isect.t = tess->event->t; - } - /* Similarly, if the computed intersection lies to the right of the - * rightmost origin (which should rarely happen), it can cause - * unbelievable inefficiency on sufficiently degenerate inputs. - * (If you have the test program, try running test54.d with the - * "X zoom" option turned on). - */ - orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo; - if( VertLeq( orgMin, &isect )) { - isect.s = orgMin->s; - isect.t = orgMin->t; - } - - if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) { - /* Easy case -- intersection at one of the right endpoints */ - (void) CheckForRightSplice( tess, regUp ); - return FALSE; - } - - if( (! VertEq( dstUp, tess->event ) - && EdgeSign( dstUp, tess->event, &isect ) >= 0) - || (! VertEq( dstLo, tess->event ) - && EdgeSign( dstLo, tess->event, &isect ) <= 0 )) - { - /* Very unusual -- the new upper or lower edge would pass on the - * wrong side of the sweep event, or through it. This can happen - * due to very small numerical errors in the intersection calculation. - */ - if( dstLo == tess->event ) { - /* Splice dstLo into eUp, and process the new region(s) */ - if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); - if ( !__gl_meshSplice( eLo->Sym, eUp ) ) longjmp(tess->env,1); - regUp = TopLeftRegion( regUp ); - if (regUp == NULL) longjmp(tess->env,1); - eUp = RegionBelow(regUp)->eUp; - FinishLeftRegions( tess, RegionBelow(regUp), regLo ); - AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE ); - return TRUE; - } - if( dstUp == tess->event ) { - /* Splice dstUp into eLo, and process the new region(s) */ - if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); - if ( !__gl_meshSplice( eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1); - regLo = regUp; - regUp = TopRightRegion( regUp ); - e = RegionBelow(regUp)->eUp->Rprev; - regLo->eUp = eLo->Oprev; - eLo = FinishLeftRegions( tess, regLo, NULL ); - AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE ); - return TRUE; - } - /* Special case: called from ConnectRightVertex. If either - * edge passes on the wrong side of tess->event, split it - * (and wait for ConnectRightVertex to splice it appropriately). - */ - if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) { - RegionAbove(regUp)->dirty = regUp->dirty = TRUE; - if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); - eUp->Org->s = tess->event->s; - eUp->Org->t = tess->event->t; - } - if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) { - regUp->dirty = regLo->dirty = TRUE; - if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); - eLo->Org->s = tess->event->s; - eLo->Org->t = tess->event->t; - } - /* leave the rest for ConnectRightVertex */ - return FALSE; - } - - /* General case -- split both edges, splice into new vertex. - * When we do the splice operation, the order of the arguments is - * arbitrary as far as correctness goes. However, when the operation - * creates a new face, the work done is proportional to the size of - * the new face. We expect the faces in the processed part of - * the mesh (ie. eUp->Lface) to be smaller than the faces in the - * unprocessed original contours (which will be eLo->Oprev->Lface). - */ - if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1); - if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1); - if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1); - eUp->Org->s = isect.s; - eUp->Org->t = isect.t; - eUp->Org->pqHandle = pqInsert( tess->pq, eUp->Org ); /* __gl_pqSortInsert */ - if (eUp->Org->pqHandle == LONG_MAX) { - pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */ - tess->pq = NULL; - longjmp(tess->env,1); - } - GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo ); - RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE; - return FALSE; -} - -static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp ) -/* - * When the upper or lower edge of any region changes, the region is - * marked "dirty". This routine walks through all the dirty regions - * and makes sure that the dictionary invariants are satisfied - * (see the comments at the beginning of this file). Of course - * new dirty regions can be created as we make changes to restore - * the invariants. - */ -{ - ActiveRegion *regLo = RegionBelow(regUp); - GLUhalfEdge *eUp, *eLo; - - for( ;; ) { - /* Find the lowest dirty region (we walk from the bottom up). */ - while( regLo->dirty ) { - regUp = regLo; - regLo = RegionBelow(regLo); - } - if( ! regUp->dirty ) { - regLo = regUp; - regUp = RegionAbove( regUp ); - if( regUp == NULL || ! regUp->dirty ) { - /* We've walked all the dirty regions */ - return; - } - } - regUp->dirty = FALSE; - eUp = regUp->eUp; - eLo = regLo->eUp; - - if( eUp->Dst != eLo->Dst ) { - /* Check that the edge ordering is obeyed at the Dst vertices. */ - if( CheckForLeftSplice( tess, regUp )) { - - /* If the upper or lower edge was marked fixUpperEdge, then - * we no longer need it (since these edges are needed only for - * vertices which otherwise have no right-going edges). - */ - if( regLo->fixUpperEdge ) { - DeleteRegion( tess, regLo ); - if ( !__gl_meshDelete( eLo ) ) longjmp(tess->env,1); - regLo = RegionBelow( regUp ); - eLo = regLo->eUp; - } else if( regUp->fixUpperEdge ) { - DeleteRegion( tess, regUp ); - if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1); - regUp = RegionAbove( regLo ); - eUp = regUp->eUp; - } - } - } - if( eUp->Org != eLo->Org ) { - if( eUp->Dst != eLo->Dst - && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge - && (eUp->Dst == tess->event || eLo->Dst == tess->event) ) - { - /* When all else fails in CheckForIntersect(), it uses tess->event - * as the intersection location. To make this possible, it requires - * that tess->event lie between the upper and lower edges, and also - * that neither of these is marked fixUpperEdge (since in the worst - * case it might splice one of these edges into tess->event, and - * violate the invariant that fixable edges are the only right-going - * edge from their associated vertex). - */ - if( CheckForIntersect( tess, regUp )) { - /* WalkDirtyRegions() was called recursively; we're done */ - return; - } - } else { - /* Even though we can't use CheckForIntersect(), the Org vertices - * may violate the dictionary edge ordering. Check and correct this. - */ - (void) CheckForRightSplice( tess, regUp ); - } - } - if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) { - /* A degenerate loop consisting of only two edges -- delete it. */ - AddWinding( eLo, eUp ); - DeleteRegion( tess, regUp ); - if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1); - regUp = RegionAbove( regLo ); - } - } -} - - -static void ConnectRightVertex( GLUtesselator *tess, ActiveRegion *regUp, - GLUhalfEdge *eBottomLeft ) -/* - * Purpose: connect a "right" vertex vEvent (one where all edges go left) - * to the unprocessed portion of the mesh. Since there are no right-going - * edges, two regions (one above vEvent and one below) are being merged - * into one. "regUp" is the upper of these two regions. - * - * There are two reasons for doing this (adding a right-going edge): - * - if the two regions being merged are "inside", we must add an edge - * to keep them separated (the combined region would not be monotone). - * - in any case, we must leave some record of vEvent in the dictionary, - * so that we can merge vEvent with features that we have not seen yet. - * For example, maybe there is a vertical edge which passes just to - * the right of vEvent; we would like to splice vEvent into this edge. - * - * However, we don't want to connect vEvent to just any vertex. We don''t - * want the new edge to cross any other edges; otherwise we will create - * intersection vertices even when the input data had no self-intersections. - * (This is a bad thing; if the user's input data has no intersections, - * we don't want to generate any false intersections ourselves.) - * - * Our eventual goal is to connect vEvent to the leftmost unprocessed - * vertex of the combined region (the union of regUp and regLo). - * But because of unseen vertices with all right-going edges, and also - * new vertices which may be created by edge intersections, we don''t - * know where that leftmost unprocessed vertex is. In the meantime, we - * connect vEvent to the closest vertex of either chain, and mark the region - * as "fixUpperEdge". This flag says to delete and reconnect this edge - * to the next processed vertex on the boundary of the combined region. - * Quite possibly the vertex we connected to will turn out to be the - * closest one, in which case we won''t need to make any changes. - */ -{ - GLUhalfEdge *eNew; - GLUhalfEdge *eTopLeft = eBottomLeft->Onext; - ActiveRegion *regLo = RegionBelow(regUp); - GLUhalfEdge *eUp = regUp->eUp; - GLUhalfEdge *eLo = regLo->eUp; - int degenerate = FALSE; - - if( eUp->Dst != eLo->Dst ) { - (void) CheckForIntersect( tess, regUp ); - } - - /* Possible new degeneracies: upper or lower edge of regUp may pass - * through vEvent, or may coincide with new intersection vertex - */ - if( VertEq( eUp->Org, tess->event )) { - if ( !__gl_meshSplice( eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1); - regUp = TopLeftRegion( regUp ); - if (regUp == NULL) longjmp(tess->env,1); - eTopLeft = RegionBelow( regUp )->eUp; - FinishLeftRegions( tess, RegionBelow(regUp), regLo ); - degenerate = TRUE; - } - if( VertEq( eLo->Org, tess->event )) { - if ( !__gl_meshSplice( eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1); - eBottomLeft = FinishLeftRegions( tess, regLo, NULL ); - degenerate = TRUE; - } - if( degenerate ) { - AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE ); - return; - } - - /* Non-degenerate situation -- need to add a temporary, fixable edge. - * Connect to the closer of eLo->Org, eUp->Org. - */ - if( VertLeq( eLo->Org, eUp->Org )) { - eNew = eLo->Oprev; - } else { - eNew = eUp; - } - eNew = __gl_meshConnect( eBottomLeft->Lprev, eNew ); - if (eNew == NULL) longjmp(tess->env,1); - - /* Prevent cleanup, otherwise eNew might disappear before we've even - * had a chance to mark it as a temporary edge. - */ - AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE ); - eNew->Sym->activeRegion->fixUpperEdge = TRUE; - WalkDirtyRegions( tess, regUp ); -} - -/* Because vertices at exactly the same location are merged together - * before we process the sweep event, some degenerate cases can't occur. - * However if someone eventually makes the modifications required to - * merge features which are close together, the cases below marked - * TOLERANCE_NONZERO will be useful. They were debugged before the - * code to merge identical vertices in the main loop was added. - */ -#define TOLERANCE_NONZERO FALSE - -static void ConnectLeftDegenerate( GLUtesselator *tess, - ActiveRegion *regUp, GLUvertex *vEvent ) -/* - * The event vertex lies exacty on an already-processed edge or vertex. - * Adding the new vertex involves splicing it into the already-processed - * part of the mesh. - */ -{ - GLUhalfEdge *e, *eTopLeft, *eTopRight, *eLast; - ActiveRegion *reg; - - e = regUp->eUp; - if( VertEq( e->Org, vEvent )) { - /* e->Org is an unprocessed vertex - just combine them, and wait - * for e->Org to be pulled from the queue - */ - assert( TOLERANCE_NONZERO ); - SpliceMergeVertices( tess, e, vEvent->anEdge ); - return; - } - - if( ! VertEq( e->Dst, vEvent )) { - /* General case -- splice vEvent into edge e which passes through it */ - if (__gl_meshSplitEdge( e->Sym ) == NULL) longjmp(tess->env,1); - if( regUp->fixUpperEdge ) { - /* This edge was fixable -- delete unused portion of original edge */ - if ( !__gl_meshDelete( e->Onext ) ) longjmp(tess->env,1); - regUp->fixUpperEdge = FALSE; - } - if ( !__gl_meshSplice( vEvent->anEdge, e ) ) longjmp(tess->env,1); - SweepEvent( tess, vEvent ); /* recurse */ - return; - } - - /* vEvent coincides with e->Dst, which has already been processed. - * Splice in the additional right-going edges. - */ - assert( TOLERANCE_NONZERO ); - regUp = TopRightRegion( regUp ); - reg = RegionBelow( regUp ); - eTopRight = reg->eUp->Sym; - eTopLeft = eLast = eTopRight->Onext; - if( reg->fixUpperEdge ) { - /* Here e->Dst has only a single fixable edge going right. - * We can delete it since now we have some real right-going edges. - */ - assert( eTopLeft != eTopRight ); /* there are some left edges too */ - DeleteRegion( tess, reg ); - if ( !__gl_meshDelete( eTopRight ) ) longjmp(tess->env,1); - eTopRight = eTopLeft->Oprev; - } - if ( !__gl_meshSplice( vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1); - if( ! EdgeGoesLeft( eTopLeft )) { - /* e->Dst had no left-going edges -- indicate this to AddRightEdges() */ - eTopLeft = NULL; - } - AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE ); -} - - -static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent ) -/* - * Purpose: connect a "left" vertex (one where both edges go right) - * to the processed portion of the mesh. Let R be the active region - * containing vEvent, and let U and L be the upper and lower edge - * chains of R. There are two possibilities: - * - * - the normal case: split R into two regions, by connecting vEvent to - * the rightmost vertex of U or L lying to the left of the sweep line - * - * - the degenerate case: if vEvent is close enough to U or L, we - * merge vEvent into that edge chain. The subcases are: - * - merging with the rightmost vertex of U or L - * - merging with the active edge of U or L - * - merging with an already-processed portion of U or L - */ -{ - ActiveRegion *regUp, *regLo, *reg; - GLUhalfEdge *eUp, *eLo, *eNew; - ActiveRegion tmp; - - /* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */ - - /* Get a pointer to the active region containing vEvent */ - tmp.eUp = vEvent->anEdge->Sym; - /* __GL_DICTLISTKEY */ /* __gl_dictListSearch */ - regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp )); - regLo = RegionBelow( regUp ); - eUp = regUp->eUp; - eLo = regLo->eUp; - - /* Try merging with U or L first */ - if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) { - ConnectLeftDegenerate( tess, regUp, vEvent ); - return; - } - - /* Connect vEvent to rightmost processed vertex of either chain. - * e->Dst is the vertex that we will connect to vEvent. - */ - reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo; - - if( regUp->inside || reg->fixUpperEdge) { - if( reg == regUp ) { - eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext ); - if (eNew == NULL) longjmp(tess->env,1); - } else { - GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge); - if (tempHalfEdge == NULL) longjmp(tess->env,1); - - eNew = tempHalfEdge->Sym; - } - if( reg->fixUpperEdge ) { - if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1); - } else { - ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew )); - } - SweepEvent( tess, vEvent ); - } else { - /* The new vertex is in a region which does not belong to the polygon. - * We don''t need to connect this vertex to the rest of the mesh. - */ - AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE ); - } -} - - -static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent ) -/* - * Does everything necessary when the sweep line crosses a vertex. - * Updates the mesh and the edge dictionary. - */ -{ - ActiveRegion *regUp, *reg; - GLUhalfEdge *e, *eTopLeft, *eBottomLeft; - - tess->event = vEvent; /* for access in EdgeLeq() */ - DebugEvent( tess ); - - /* Check if this vertex is the right endpoint of an edge that is - * already in the dictionary. In this case we don't need to waste - * time searching for the location to insert new edges. - */ - e = vEvent->anEdge; - while( e->activeRegion == NULL ) { - e = e->Onext; - if( e == vEvent->anEdge ) { - /* All edges go right -- not incident to any processed edges */ - ConnectLeftVertex( tess, vEvent ); - return; - } - } - - /* Processing consists of two phases: first we "finish" all the - * active regions where both the upper and lower edges terminate - * at vEvent (ie. vEvent is closing off these regions). - * We mark these faces "inside" or "outside" the polygon according - * to their winding number, and delete the edges from the dictionary. - * This takes care of all the left-going edges from vEvent. - */ - regUp = TopLeftRegion( e->activeRegion ); - if (regUp == NULL) longjmp(tess->env,1); - reg = RegionBelow( regUp ); - eTopLeft = reg->eUp; - eBottomLeft = FinishLeftRegions( tess, reg, NULL ); - - /* Next we process all the right-going edges from vEvent. This - * involves adding the edges to the dictionary, and creating the - * associated "active regions" which record information about the - * regions between adjacent dictionary edges. - */ - if( eBottomLeft->Onext == eTopLeft ) { - /* No right-going edges -- add a temporary "fixable" edge */ - ConnectRightVertex( tess, regUp, eBottomLeft ); - } else { - AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE ); - } -} - - -/* Make the sentinel coordinates big enough that they will never be - * merged with real input features. (Even with the largest possible - * input contour and the maximum tolerance of 1.0, no merging will be - * done with coordinates larger than 3 * GLU_TESS_MAX_COORD). - */ -#define SENTINEL_COORD (4 * GLU_TESS_MAX_COORD) - -static void AddSentinel( GLUtesselator *tess, GLdouble t ) -/* - * We add two sentinel edges above and below all other edges, - * to avoid special cases at the top and bottom. - */ -{ - GLUhalfEdge *e; - ActiveRegion *reg = (ActiveRegion *)memAlloc( sizeof( ActiveRegion )); - if (reg == NULL) longjmp(tess->env,1); - - e = __gl_meshMakeEdge( tess->mesh ); - if (e == NULL) longjmp(tess->env,1); - - e->Org->s = SENTINEL_COORD; - e->Org->t = t; - e->Dst->s = -SENTINEL_COORD; - e->Dst->t = t; - tess->event = e->Dst; /* initialize it */ - - reg->eUp = e; - reg->windingNumber = 0; - reg->inside = FALSE; - reg->fixUpperEdge = FALSE; - reg->sentinel = TRUE; - reg->dirty = FALSE; - reg->nodeUp = dictInsert( tess->dict, reg ); /* __gl_dictListInsertBefore */ - if (reg->nodeUp == NULL) longjmp(tess->env,1); -} - - -static void InitEdgeDict( GLUtesselator *tess ) -/* - * We maintain an ordering of edge intersections with the sweep line. - * This order is maintained in a dynamic dictionary. - */ -{ - /* __gl_dictListNewDict */ - tess->dict = dictNewDict( tess, (int (*)(void *, DictKey, DictKey)) EdgeLeq ); - if (tess->dict == NULL) longjmp(tess->env,1); - - AddSentinel( tess, -SENTINEL_COORD ); - AddSentinel( tess, SENTINEL_COORD ); -} - - -static void DoneEdgeDict( GLUtesselator *tess ) -{ - ActiveRegion *reg; -#ifndef NDEBUG - int fixedEdges = 0; -#endif - - /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */ - while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) { - /* - * At the end of all processing, the dictionary should contain - * only the two sentinel edges, plus at most one "fixable" edge - * created by ConnectRightVertex(). - */ - if( ! reg->sentinel ) { - assert( reg->fixUpperEdge ); - assert( ++fixedEdges == 1 ); - } - assert( reg->windingNumber == 0 ); - DeleteRegion( tess, reg ); -/* __gl_meshDelete( reg->eUp );*/ - } - dictDeleteDict( tess->dict ); /* __gl_dictListDeleteDict */ -} - - -static void RemoveDegenerateEdges( GLUtesselator *tess ) -/* - * Remove zero-length edges, and contours with fewer than 3 vertices. - */ -{ - GLUhalfEdge *e, *eNext, *eLnext; - GLUhalfEdge *eHead = &tess->mesh->eHead; - - /*LINTED*/ - for( e = eHead->next; e != eHead; e = eNext ) { - eNext = e->next; - eLnext = e->Lnext; - - if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) { - /* Zero-length edge, contour has at least 3 edges */ - - SpliceMergeVertices( tess, eLnext, e ); /* deletes e->Org */ - if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); /* e is a self-loop */ - e = eLnext; - eLnext = e->Lnext; - } - if( eLnext->Lnext == e ) { - /* Degenerate contour (one or two edges) */ - - if( eLnext != e ) { - if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; } - if ( !__gl_meshDelete( eLnext ) ) longjmp(tess->env,1); - } - if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; } - if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); - } - } -} - -static int InitPriorityQ( GLUtesselator *tess ) -/* - * Insert all vertices into the priority queue which determines the - * order in which vertices cross the sweep line. - */ -{ - PriorityQ *pq; - GLUvertex *v, *vHead; - - /* __gl_pqSortNewPriorityQ */ - pq = tess->pq = pqNewPriorityQ( (int (*)(PQkey, PQkey)) __gl_vertLeq ); - if (pq == NULL) return 0; - - vHead = &tess->mesh->vHead; - for( v = vHead->next; v != vHead; v = v->next ) { - v->pqHandle = pqInsert( pq, v ); /* __gl_pqSortInsert */ - if (v->pqHandle == LONG_MAX) break; - } - if (v != vHead || !pqInit( pq ) ) { /* __gl_pqSortInit */ - pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */ - tess->pq = NULL; - return 0; - } - - return 1; -} - - -static void DonePriorityQ( GLUtesselator *tess ) -{ - pqDeletePriorityQ( tess->pq ); /* __gl_pqSortDeletePriorityQ */ -} - - -static int RemoveDegenerateFaces( GLUmesh *mesh ) -/* - * Delete any degenerate faces with only two edges. WalkDirtyRegions() - * will catch almost all of these, but it won't catch degenerate faces - * produced by splice operations on already-processed edges. - * The two places this can happen are in FinishLeftRegions(), when - * we splice in a "temporary" edge produced by ConnectRightVertex(), - * and in CheckForLeftSplice(), where we splice already-processed - * edges to ensure that our dictionary invariants are not violated - * by numerical errors. - * - * In both these cases it is *very* dangerous to delete the offending - * edge at the time, since one of the routines further up the stack - * will sometimes be keeping a pointer to that edge. - */ -{ - GLUface *f, *fNext; - GLUhalfEdge *e; - - /*LINTED*/ - for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) { - fNext = f->next; - e = f->anEdge; - assert( e->Lnext != e ); - - if( e->Lnext->Lnext == e ) { - /* A face with only two edges */ - AddWinding( e->Onext, e ); - if ( !__gl_meshDelete( e ) ) return 0; - } - } - return 1; -} - -int __gl_computeInterior( GLUtesselator *tess ) -/* - * __gl_computeInterior( tess ) computes the planar arrangement specified - * by the given contours, and further subdivides this arrangement - * into regions. Each region is marked "inside" if it belongs - * to the polygon, according to the rule given by tess->windingRule. - * Each interior region is guaranteed be monotone. - */ -{ - GLUvertex *v, *vNext; - - tess->fatalError = FALSE; - - /* Each vertex defines an event for our sweep line. Start by inserting - * all the vertices in a priority queue. Events are processed in - * lexicographic order, ie. - * - * e1 < e2 iff e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y) - */ - RemoveDegenerateEdges( tess ); - if ( !InitPriorityQ( tess ) ) return 0; /* if error */ - InitEdgeDict( tess ); - - /* __gl_pqSortExtractMin */ - while( (v = (GLUvertex *)pqExtractMin( tess->pq )) != NULL ) { - for( ;; ) { - vNext = (GLUvertex *)pqMinimum( tess->pq ); /* __gl_pqSortMinimum */ - if( vNext == NULL || ! VertEq( vNext, v )) break; - - /* Merge together all vertices at exactly the same location. - * This is more efficient than processing them one at a time, - * simplifies the code (see ConnectLeftDegenerate), and is also - * important for correct handling of certain degenerate cases. - * For example, suppose there are two identical edges A and B - * that belong to different contours (so without this code they would - * be processed by separate sweep events). Suppose another edge C - * crosses A and B from above. When A is processed, we split it - * at its intersection point with C. However this also splits C, - * so when we insert B we may compute a slightly different - * intersection point. This might leave two edges with a small - * gap between them. This kind of error is especially obvious - * when using boundary extraction (GLU_TESS_BOUNDARY_ONLY). - */ - vNext = (GLUvertex *)pqExtractMin( tess->pq ); /* __gl_pqSortExtractMin*/ - SpliceMergeVertices( tess, v->anEdge, vNext->anEdge ); - } - SweepEvent( tess, v ); - } - - /* Set tess->event for debugging purposes */ - /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */ - tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org; - DebugEvent( tess ); - DoneEdgeDict( tess ); - DonePriorityQ( tess ); - - if ( !RemoveDegenerateFaces( tess->mesh ) ) return 0; - __gl_meshCheckMesh( tess->mesh ); - - return 1; -} diff --git a/GLU/sweep.h b/GLU/sweep.h deleted file mode 100644 index feb68b0..0000000 --- a/GLU/sweep.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __sweep_h_ -#define __sweep_h_ - -#include "mesh.h" - -/* __gl_computeInterior( tess ) computes the planar arrangement specified - * by the given contours, and further subdivides this arrangement - * into regions. Each region is marked "inside" if it belongs - * to the polygon, according to the rule given by tess->windingRule. - * Each interior region is guaranteed be monotone. - */ -int __gl_computeInterior( GLUtesselator *tess ); - - -/* The following is here *only* for access by debugging routines */ - -#include "dict.h" - -/* For each pair of adjacent edges crossing the sweep line, there is - * an ActiveRegion to represent the region between them. The active - * regions are kept in sorted order in a dynamic dictionary. As the - * sweep line crosses each vertex, we update the affected regions. - */ - -struct ActiveRegion { - GLUhalfEdge *eUp; /* upper edge, directed right to left */ - DictNode *nodeUp; /* dictionary node corresponding to eUp */ - int windingNumber; /* used to determine which regions are - * inside the polygon */ - GLboolean inside; /* is this region inside the polygon? */ - GLboolean sentinel; /* marks fake edges at t = +/-infinity */ - GLboolean dirty; /* marks regions where the upper or lower - * edge has changed, but we haven't checked - * whether they intersect yet */ - GLboolean fixUpperEdge; /* marks temporary edges introduced when - * we process a "right vertex" (one without - * any edges leaving to the right) */ -}; - -#define RegionBelow(r) ((ActiveRegion *) dictKey(dictPred((r)->nodeUp))) -#define RegionAbove(r) ((ActiveRegion *) dictKey(dictSucc((r)->nodeUp))) - -#endif diff --git a/GLU/tess.c b/GLU/tess.c deleted file mode 100644 index 029a02c..0000000 --- a/GLU/tess.c +++ /dev/null @@ -1,628 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#include "gluos.h" -#include -#include -#include -#include "memalloc.h" -#include "tess.h" -#include "mesh.h" -#include "normal.h" -#include "sweep.h" -#include "tessmono.h" -#include "render.h" - -#define GLU_TESS_DEFAULT_TOLERANCE 0.0 -#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */ - -#define TRUE 1 -#define FALSE 0 - -/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {} -/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {} -/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {} -/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {} -/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {} -/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4], - GLfloat weight[4], void **dataOut ) {} -/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {} - - -/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type, - void *polygonData ) {} -/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, - void *polygonData ) {} -/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data, - void *polygonData ) {} -/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {} -/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum, - void *polygonData ) {} -/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], - void *data[4], - GLfloat weight[4], - void **outData, - void *polygonData ) {} - -/* Half-edges are allocated in pairs (see mesh.c) */ -typedef struct { GLUhalfEdge e, eSym; } EdgePair; - -#undef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \ - MAX(sizeof(GLUvertex),sizeof(GLUface)))) - - -GLUtesselator * GLAPIENTRY -gluNewTess( void ) -{ - GLUtesselator *tess; - - /* Only initialize fields which can be changed by the api. Other fields - * are initialized where they are used. - */ - - if (memInit( MAX_FAST_ALLOC ) == 0) { - return 0; /* out of memory */ - } - tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator )); - if (tess == NULL) { - return 0; /* out of memory */ - } - - tess->state = T_DORMANT; - - tess->normal[0] = 0; - tess->normal[1] = 0; - tess->normal[2] = 0; - - tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE; - tess->windingRule = GLU_TESS_WINDING_ODD; - tess->flagBoundary = FALSE; - tess->boundaryOnly = FALSE; - - tess->callBegin = &noBegin; - tess->callEdgeFlag = &noEdgeFlag; - tess->callVertex = &noVertex; - tess->callEnd = &noEnd; - - tess->callError = &noError; - tess->callCombine = &noCombine; - tess->callMesh = &noMesh; - - tess->callBeginData= &__gl_noBeginData; - tess->callEdgeFlagData= &__gl_noEdgeFlagData; - tess->callVertexData= &__gl_noVertexData; - tess->callEndData= &__gl_noEndData; - tess->callErrorData= &__gl_noErrorData; - tess->callCombineData= &__gl_noCombineData; - - tess->polygonData= NULL; - - return tess; -} - -static void MakeDormant( GLUtesselator *tess ) -{ - /* Return the tessellator to its original dormant state. */ - - if( tess->mesh != NULL ) { - __gl_meshDeleteMesh( tess->mesh ); - } - tess->state = T_DORMANT; - tess->lastEdge = NULL; - tess->mesh = NULL; -} - -#define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s) - -static void GotoState( GLUtesselator *tess, enum TessState newState ) -{ - while( tess->state != newState ) { - /* We change the current state one level at a time, to get to - * the desired state. - */ - if( tess->state < newState ) { - switch( tess->state ) { - case T_DORMANT: - CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON ); - gluTessBeginPolygon( tess, NULL ); - break; - case T_IN_POLYGON: - CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR ); - gluTessBeginContour( tess ); - break; - default: - ; - } - } else { - switch( tess->state ) { - case T_IN_CONTOUR: - CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR ); - gluTessEndContour( tess ); - break; - case T_IN_POLYGON: - CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON ); - /* gluTessEndPolygon( tess ) is too much work! */ - MakeDormant( tess ); - break; - default: - ; - } - } - } -} - - -void GLAPIENTRY -gluDeleteTess( GLUtesselator *tess ) -{ - RequireState( tess, T_DORMANT ); - memFree( tess ); -} - - -void GLAPIENTRY -gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value ) -{ - GLenum windingRule; - - switch( which ) { - case GLU_TESS_TOLERANCE: - if( value < 0.0 || value > 1.0 ) break; - tess->relTolerance = value; - return; - - case GLU_TESS_WINDING_RULE: - windingRule = (GLenum) value; - if( windingRule != value ) break; /* not an integer */ - - switch( windingRule ) { - case GLU_TESS_WINDING_ODD: - case GLU_TESS_WINDING_NONZERO: - case GLU_TESS_WINDING_POSITIVE: - case GLU_TESS_WINDING_NEGATIVE: - case GLU_TESS_WINDING_ABS_GEQ_TWO: - tess->windingRule = windingRule; - return; - default: - break; - } - - case GLU_TESS_BOUNDARY_ONLY: - tess->boundaryOnly = (value != 0); - return; - - default: - CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); - return; - } - CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE ); -} - -/* Returns tessellator property */ -void GLAPIENTRY -gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value ) -{ - switch (which) { - case GLU_TESS_TOLERANCE: - /* tolerance should be in range [0..1] */ - assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0); - *value= tess->relTolerance; - break; - case GLU_TESS_WINDING_RULE: - assert(tess->windingRule == GLU_TESS_WINDING_ODD || - tess->windingRule == GLU_TESS_WINDING_NONZERO || - tess->windingRule == GLU_TESS_WINDING_POSITIVE || - tess->windingRule == GLU_TESS_WINDING_NEGATIVE || - tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO); - *value= tess->windingRule; - break; - case GLU_TESS_BOUNDARY_ONLY: - assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE); - *value= tess->boundaryOnly; - break; - default: - *value= 0.0; - CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); - break; - } -} /* gluGetTessProperty() */ - -void GLAPIENTRY -gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z ) -{ - tess->normal[0] = x; - tess->normal[1] = y; - tess->normal[2] = z; -} - -void GLAPIENTRY -gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn) -{ - switch( which ) { - case GLU_TESS_BEGIN: - tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn; - return; - case GLU_TESS_BEGIN_DATA: - tess->callBeginData = (fn == NULL) ? - &__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn; - return; - case GLU_TESS_EDGE_FLAG: - tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag : - (void (GLAPIENTRY *)(GLboolean)) fn; - /* If the client wants boundary edges to be flagged, - * we render everything as separate triangles (no strips or fans). - */ - tess->flagBoundary = (fn != NULL); - return; - case GLU_TESS_EDGE_FLAG_DATA: - tess->callEdgeFlagData= (fn == NULL) ? - &__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn; - /* If the client wants boundary edges to be flagged, - * we render everything as separate triangles (no strips or fans). - */ - tess->flagBoundary = (fn != NULL); - return; - case GLU_TESS_VERTEX: - tess->callVertex = (fn == NULL) ? &noVertex : - (void (GLAPIENTRY *)(void *)) fn; - return; - case GLU_TESS_VERTEX_DATA: - tess->callVertexData = (fn == NULL) ? - &__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn; - return; - case GLU_TESS_END: - tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn; - return; - case GLU_TESS_END_DATA: - tess->callEndData = (fn == NULL) ? &__gl_noEndData : - (void (GLAPIENTRY *)(void *)) fn; - return; - case GLU_TESS_ERROR: - tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn; - return; - case GLU_TESS_ERROR_DATA: - tess->callErrorData = (fn == NULL) ? - &__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn; - return; - case GLU_TESS_COMBINE: - tess->callCombine = (fn == NULL) ? &noCombine : - (void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn; - return; - case GLU_TESS_COMBINE_DATA: - tess->callCombineData = (fn == NULL) ? &__gl_noCombineData : - (void (GLAPIENTRY *)(GLdouble [3], - void *[4], - GLfloat [4], - void **, - void *)) fn; - return; - case GLU_TESS_MESH: - tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn; - return; - default: - CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM ); - return; - } -} - -static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) -{ - GLUhalfEdge *e; - - e = tess->lastEdge; - if( e == NULL ) { - /* Make a self-loop (one vertex, one edge). */ - - e = __gl_meshMakeEdge( tess->mesh ); - if (e == NULL) return 0; - if ( !__gl_meshSplice( e, e->Sym ) ) return 0; - } else { - /* Create a new vertex and edge which immediately follow e - * in the ordering around the left face. - */ - if (__gl_meshSplitEdge( e ) == NULL) return 0; - e = e->Lnext; - } - - /* The new vertex is now e->Org. */ - e->Org->data = data; - e->Org->coords[0] = coords[0]; - e->Org->coords[1] = coords[1]; - e->Org->coords[2] = coords[2]; - - /* The winding of an edge says how the winding number changes as we - * cross from the edge''s right face to its left face. We add the - * vertices in such an order that a CCW contour will add +1 to - * the winding number of the region inside the contour. - */ - e->winding = 1; - e->Sym->winding = -1; - - tess->lastEdge = e; - - return 1; -} - - -static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) -{ - CachedVertex *v = &tess->cache[tess->cacheCount]; - - v->data = data; - v->coords[0] = coords[0]; - v->coords[1] = coords[1]; - v->coords[2] = coords[2]; - ++tess->cacheCount; -} - - -static int EmptyCache( GLUtesselator *tess ) -{ - CachedVertex *v = tess->cache; - CachedVertex *vLast; - - tess->mesh = __gl_meshNewMesh(); - if (tess->mesh == NULL) return 0; - - for( vLast = v + tess->cacheCount; v < vLast; ++v ) { - if ( !AddVertex( tess, v->coords, v->data ) ) return 0; - } - tess->cacheCount = 0; - tess->emptyCache = FALSE; - - return 1; -} - - -void GLAPIENTRY -gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data ) -{ - int i, tooLarge = FALSE; - GLdouble x, clamped[3]; - - RequireState( tess, T_IN_CONTOUR ); - - if( tess->emptyCache ) { - if ( !EmptyCache( tess ) ) { - CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); - return; - } - tess->lastEdge = NULL; - } - for( i = 0; i < 3; ++i ) { - x = coords[i]; - if( x < - GLU_TESS_MAX_COORD ) { - x = - GLU_TESS_MAX_COORD; - tooLarge = TRUE; - } - if( x > GLU_TESS_MAX_COORD ) { - x = GLU_TESS_MAX_COORD; - tooLarge = TRUE; - } - clamped[i] = x; - } - if( tooLarge ) { - CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE ); - } - - if( tess->mesh == NULL ) { - if( tess->cacheCount < TESS_MAX_CACHE ) { - CacheVertex( tess, clamped, data ); - return; - } - if ( !EmptyCache( tess ) ) { - CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); - return; - } - } - if ( !AddVertex( tess, clamped, data ) ) { - CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); - } -} - - -void GLAPIENTRY -gluTessBeginPolygon( GLUtesselator *tess, void *data ) -{ - RequireState( tess, T_DORMANT ); - - tess->state = T_IN_POLYGON; - tess->cacheCount = 0; - tess->emptyCache = FALSE; - tess->mesh = NULL; - - tess->polygonData= data; -} - - -void GLAPIENTRY -gluTessBeginContour( GLUtesselator *tess ) -{ - RequireState( tess, T_IN_POLYGON ); - - tess->state = T_IN_CONTOUR; - tess->lastEdge = NULL; - if( tess->cacheCount > 0 ) { - /* Just set a flag so we don't get confused by empty contours - * -- these can be generated accidentally with the obsolete - * NextContour() interface. - */ - tess->emptyCache = TRUE; - } -} - - -void GLAPIENTRY -gluTessEndContour( GLUtesselator *tess ) -{ - RequireState( tess, T_IN_CONTOUR ); - tess->state = T_IN_POLYGON; -} - -void GLAPIENTRY -gluTessEndPolygon( GLUtesselator *tess ) -{ - GLUmesh *mesh; - - if (setjmp(tess->env) != 0) { - /* come back here if out of memory */ - CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY ); - return; - } - - RequireState( tess, T_IN_POLYGON ); - tess->state = T_DORMANT; - - if( tess->mesh == NULL ) { - if( ! tess->flagBoundary && tess->callMesh == &noMesh ) { - - /* Try some special code to make the easy cases go quickly - * (eg. convex polygons). This code does NOT handle multiple contours, - * intersections, edge flags, and of course it does not generate - * an explicit mesh either. - */ - if( __gl_renderCache( tess )) { - tess->polygonData= NULL; - return; - } - } - if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/ - } - - /* Determine the polygon normal and project vertices onto the plane - * of the polygon. - */ - __gl_projectPolygon( tess ); - - /* __gl_computeInterior( tess ) computes the planar arrangement specified - * by the given contours, and further subdivides this arrangement - * into regions. Each region is marked "inside" if it belongs - * to the polygon, according to the rule given by tess->windingRule. - * Each interior region is guaranteed be monotone. - */ - if ( !__gl_computeInterior( tess ) ) { - longjmp(tess->env,1); /* could've used a label */ - } - - mesh = tess->mesh; - if( ! tess->fatalError ) { - int rc = 1; - - /* If the user wants only the boundary contours, we throw away all edges - * except those which separate the interior from the exterior. - * Otherwise we tessellate all the regions marked "inside". - */ - if( tess->boundaryOnly ) { - rc = __gl_meshSetWindingNumber( mesh, 1, TRUE ); - } else { - rc = __gl_meshTessellateInterior( mesh ); - } - if (rc == 0) longjmp(tess->env,1); /* could've used a label */ - - __gl_meshCheckMesh( mesh ); - - if( tess->callBegin != &noBegin || tess->callEnd != &noEnd - || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag - || tess->callBeginData != &__gl_noBeginData - || tess->callEndData != &__gl_noEndData - || tess->callVertexData != &__gl_noVertexData - || tess->callEdgeFlagData != &__gl_noEdgeFlagData ) - { - if( tess->boundaryOnly ) { - __gl_renderBoundary( tess, mesh ); /* output boundary contours */ - } else { - __gl_renderMesh( tess, mesh ); /* output strips and fans */ - } - } - if( tess->callMesh != &noMesh ) { - - /* Throw away the exterior faces, so that all faces are interior. - * This way the user doesn't have to check the "inside" flag, - * and we don't need to even reveal its existence. It also leaves - * the freedom for an implementation to not generate the exterior - * faces in the first place. - */ - __gl_meshDiscardExterior( mesh ); - (*tess->callMesh)( mesh ); /* user wants the mesh itself */ - tess->mesh = NULL; - tess->polygonData= NULL; - return; - } - } - __gl_meshDeleteMesh( mesh ); - tess->polygonData= NULL; - tess->mesh = NULL; -} - - -/*XXXblythe unused function*/ -#if 0 -void GLAPIENTRY -gluDeleteMesh( GLUmesh *mesh ) -{ - __gl_meshDeleteMesh( mesh ); -} -#endif - - - -/*******************************************************/ - -/* Obsolete calls -- for backward compatibility */ - -void GLAPIENTRY -gluBeginPolygon( GLUtesselator *tess ) -{ - gluTessBeginPolygon( tess, NULL ); - gluTessBeginContour( tess ); -} - - -/*ARGSUSED*/ -void GLAPIENTRY -gluNextContour( GLUtesselator *tess, GLenum type ) -{ - gluTessEndContour( tess ); - gluTessBeginContour( tess ); -} - - -void GLAPIENTRY -gluEndPolygon( GLUtesselator *tess ) -{ - gluTessEndContour( tess ); - gluTessEndPolygon( tess ); -} diff --git a/GLU/tess.h b/GLU/tess.h deleted file mode 100644 index 064477d..0000000 --- a/GLU/tess.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __tess_h_ -#define __tess_h_ - -#include "GL/glu.h" -#include -#include "mesh.h" -#include "dict.h" -#include "priorityq.h" - -/* The begin/end calls must be properly nested. We keep track of - * the current state to enforce the ordering. - */ -enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR }; - -/* We cache vertex data for single-contour polygons so that we can - * try a quick-and-dirty decomposition first. - */ -#define TESS_MAX_CACHE 100 - -typedef struct CachedVertex { - GLdouble coords[3]; - void *data; -} CachedVertex; - -struct GLUtesselator { - - /*** state needed for collecting the input data ***/ - - enum TessState state; /* what begin/end calls have we seen? */ - - GLUhalfEdge *lastEdge; /* lastEdge->Org is the most recent vertex */ - GLUmesh *mesh; /* stores the input contours, and eventually - the tessellation itself */ - - void (GLAPIENTRY *callError)( GLenum errnum ); - - /*** state needed for projecting onto the sweep plane ***/ - - GLdouble normal[3]; /* user-specified normal (if provided) */ - GLdouble sUnit[3]; /* unit vector in s-direction (debugging) */ - GLdouble tUnit[3]; /* unit vector in t-direction (debugging) */ - - /*** state needed for the line sweep ***/ - - GLdouble relTolerance; /* tolerance for merging features */ - GLenum windingRule; /* rule for determining polygon interior */ - GLboolean fatalError; /* fatal error: needed combine callback */ - - Dict *dict; /* edge dictionary for sweep line */ - PriorityQ *pq; /* priority queue of vertex events */ - GLUvertex *event; /* current sweep event being processed */ - - void (GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4], - GLfloat weight[4], void **outData ); - - /*** state needed for rendering callbacks (see render.c) ***/ - - GLboolean flagBoundary; /* mark boundary edges (use EdgeFlag) */ - GLboolean boundaryOnly; /* Extract contours, not triangles */ - GLUface *lonelyTriList; - /* list of triangles which could not be rendered as strips or fans */ - - void (GLAPIENTRY *callBegin)( GLenum type ); - void (GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge ); - void (GLAPIENTRY *callVertex)( void *data ); - void (GLAPIENTRY *callEnd)( void ); - void (GLAPIENTRY *callMesh)( GLUmesh *mesh ); - - - /*** state needed to cache single-contour polygons for renderCache() */ - - GLboolean emptyCache; /* empty cache on next vertex() call */ - int cacheCount; /* number of cached vertices */ - CachedVertex cache[TESS_MAX_CACHE]; /* the vertex data */ - - /*** rendering callbacks that also pass polygon data ***/ - void (GLAPIENTRY *callBeginData)( GLenum type, void *polygonData ); - void (GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge, - void *polygonData ); - void (GLAPIENTRY *callVertexData)( void *data, void *polygonData ); - void (GLAPIENTRY *callEndData)( void *polygonData ); - void (GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData ); - void (GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4], - GLfloat weight[4], void **outData, - void *polygonData ); - - jmp_buf env; /* place to jump to when memAllocs fail */ - - void *polygonData; /* client data for current polygon */ -}; - -void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData ); -void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData ); -void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData ); -void GLAPIENTRY __gl_noEndData( void *polygonData ); -void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData ); -void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4], - GLfloat weight[4], void **outData, - void *polygonData ); - -#define CALL_BEGIN_OR_BEGIN_DATA(a) \ - if (tess->callBeginData != &__gl_noBeginData) \ - (*tess->callBeginData)((a),tess->polygonData); \ - else (*tess->callBegin)((a)); - -#define CALL_VERTEX_OR_VERTEX_DATA(a) \ - if (tess->callVertexData != &__gl_noVertexData) \ - (*tess->callVertexData)((a),tess->polygonData); \ - else (*tess->callVertex)((a)); - -#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \ - if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \ - (*tess->callEdgeFlagData)((a),tess->polygonData); \ - else (*tess->callEdgeFlag)((a)); - -#define CALL_END_OR_END_DATA() \ - if (tess->callEndData != &__gl_noEndData) \ - (*tess->callEndData)(tess->polygonData); \ - else (*tess->callEnd)(); - -#define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \ - if (tess->callCombineData != &__gl_noCombineData) \ - (*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \ - else (*tess->callCombine)((a),(b),(c),(d)); - -#define CALL_ERROR_OR_ERROR_DATA(a) \ - if (tess->callErrorData != &__gl_noErrorData) \ - (*tess->callErrorData)((a),tess->polygonData); \ - else (*tess->callError)((a)); - -#endif diff --git a/GLU/tessmono.c b/GLU/tessmono.c deleted file mode 100644 index 4d08440..0000000 --- a/GLU/tessmono.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#include "gluos.h" -#include -#include "geom.h" -#include "mesh.h" -#include "tessmono.h" -#include - -#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \ - eDst->Sym->winding += eSrc->Sym->winding) - -/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region - * (what else would it do??) The region must consist of a single - * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this - * case means that any vertical line intersects the interior of the - * region in a single interval. - * - * Tessellation consists of adding interior edges (actually pairs of - * half-edges), to split the region into non-overlapping triangles. - * - * The basic idea is explained in Preparata and Shamos (which I don''t - * have handy right now), although their implementation is more - * complicated than this one. The are two edge chains, an upper chain - * and a lower chain. We process all vertices from both chains in order, - * from right to left. - * - * The algorithm ensures that the following invariant holds after each - * vertex is processed: the untessellated region consists of two - * chains, where one chain (say the upper) is a single edge, and - * the other chain is concave. The left vertex of the single edge - * is always to the left of all vertices in the concave chain. - * - * Each step consists of adding the rightmost unprocessed vertex to one - * of the two chains, and forming a fan of triangles from the rightmost - * of two chain endpoints. Determining whether we can add each triangle - * to the fan is a simple orientation test. By making the fan as large - * as possible, we restore the invariant (check it yourself). - */ -int __gl_meshTessellateMonoRegion( GLUface *face ) -{ - GLUhalfEdge *up, *lo; - - /* All edges are oriented CCW around the boundary of the region. - * First, find the half-edge whose origin vertex is rightmost. - * Since the sweep goes from left to right, face->anEdge should - * be close to the edge we want. - */ - up = face->anEdge; - assert( up->Lnext != up && up->Lnext->Lnext != up ); - - for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev ) - ; - for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext ) - ; - lo = up->Lprev; - - while( up->Lnext != lo ) { - if( VertLeq( up->Dst, lo->Org )) { - /* up->Dst is on the left. It is safe to form triangles from lo->Org. - * The EdgeGoesLeft test guarantees progress even when some triangles - * are CW, given that the upper and lower chains are truly monotone. - */ - while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext ) - || EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) { - GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo ); - if (tempHalfEdge == NULL) return 0; - lo = tempHalfEdge->Sym; - } - lo = lo->Lprev; - } else { - /* lo->Org is on the left. We can make CCW triangles from up->Dst. */ - while( lo->Lnext != up && (EdgeGoesRight( up->Lprev ) - || EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) { - GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev ); - if (tempHalfEdge == NULL) return 0; - up = tempHalfEdge->Sym; - } - up = up->Lnext; - } - } - - /* Now lo->Org == up->Dst == the leftmost vertex. The remaining region - * can be tessellated in a fan from this leftmost vertex. - */ - assert( lo->Lnext != up ); - while( lo->Lnext->Lnext != up ) { - GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo ); - if (tempHalfEdge == NULL) return 0; - lo = tempHalfEdge->Sym; - } - - return 1; -} - - -/* __gl_meshTessellateInterior( mesh ) tessellates each region of - * the mesh which is marked "inside" the polygon. Each such region - * must be monotone. - */ -int __gl_meshTessellateInterior( GLUmesh *mesh ) -{ - GLUface *f, *next; - - /*LINTED*/ - for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) { - /* Make sure we don''t try to tessellate the new triangles. */ - next = f->next; - if( f->inside ) { - if ( !__gl_meshTessellateMonoRegion( f ) ) return 0; - } - } - - return 1; -} - - -/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces - * which are not marked "inside" the polygon. Since further mesh operations - * on NULL faces are not allowed, the main purpose is to clean up the - * mesh so that exterior loops are not represented in the data structure. - */ -void __gl_meshDiscardExterior( GLUmesh *mesh ) -{ - GLUface *f, *next; - - /*LINTED*/ - for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) { - /* Since f will be destroyed, save its next pointer. */ - next = f->next; - if( ! f->inside ) { - __gl_meshZapFace( f ); - } - } -} - -#define MARKED_FOR_DELETION 0x7fffffff - -/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the - * winding numbers on all edges so that regions marked "inside" the - * polygon have a winding number of "value", and regions outside - * have a winding number of 0. - * - * If keepOnlyBoundary is TRUE, it also deletes all edges which do not - * separate an interior region from an exterior one. - */ -int __gl_meshSetWindingNumber( GLUmesh *mesh, int value, - GLboolean keepOnlyBoundary ) -{ - GLUhalfEdge *e, *eNext; - - for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) { - eNext = e->next; - if( e->Rface->inside != e->Lface->inside ) { - - /* This is a boundary edge (one side is interior, one is exterior). */ - e->winding = (e->Lface->inside) ? value : -value; - } else { - - /* Both regions are interior, or both are exterior. */ - if( ! keepOnlyBoundary ) { - e->winding = 0; - } else { - if ( !__gl_meshDelete( e ) ) return 0; - } - } - } - return 1; -} diff --git a/GLU/tessmono.h b/GLU/tessmono.h deleted file mode 100644 index 8ee1b2f..0000000 --- a/GLU/tessmono.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ -/* -** Author: Eric Veach, July 1994. -** -*/ - -#ifndef __tessmono_h_ -#define __tessmono_h_ - -/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region - * (what else would it do??) The region must consist of a single - * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this - * case means that any vertical line intersects the interior of the - * region in a single interval. - * - * Tessellation consists of adding interior edges (actually pairs of - * half-edges), to split the region into non-overlapping triangles. - * - * __gl_meshTessellateInterior( mesh ) tessellates each region of - * the mesh which is marked "inside" the polygon. Each such region - * must be monotone. - * - * __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces - * which are not marked "inside" the polygon. Since further mesh operations - * on NULL faces are not allowed, the main purpose is to clean up the - * mesh so that exterior loops are not represented in the data structure. - * - * __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the - * winding numbers on all edges so that regions marked "inside" the - * polygon have a winding number of "value", and regions outside - * have a winding number of 0. - * - * If keepOnlyBoundary is TRUE, it also deletes all edges which do not - * separate an interior region from an exterior one. - */ - -int __gl_meshTessellateMonoRegion( GLUface *face ); -int __gl_meshTessellateInterior( GLUmesh *mesh ); -void __gl_meshDiscardExterior( GLUmesh *mesh ); -int __gl_meshSetWindingNumber( GLUmesh *mesh, int value, - GLboolean keepOnlyBoundary ); - -#endif diff --git a/GLU/util.c b/GLU/util.c deleted file mode 100644 index 90d58f3..0000000 --- a/GLU/util.c +++ /dev/null @@ -1,90 +0,0 @@ -// These are just the bits of GLU we use so we can ditch the external -// dependency (since it turns out to be complicated, as it depends on libGL, -// which we load dynamically, etc). This is from SGI's open source version. - -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Except as contained in this notice, the name of Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#include -#include -#include "GL/gl.h" -#include "GL/glu.h" - -/* -** Make m an identity matrix -*/ -static void __gluMakeIdentityd(GLdouble m[16]) -{ - m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0; - m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0; - m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0; - m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1; -} - -static void __gluMakeIdentityf(GLfloat m[16]) -{ - m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0; - m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0; - m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0; - m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1; -} - -void GLAPIENTRY -gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top) -{ - glOrtho(left, right, bottom, top, -1, 1); -} - -#define __glPi 3.14159265358979323846 - -void GLAPIENTRY -gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) -{ - GLdouble m[4][4]; - double sine, cotangent, deltaZ; - double radians = fovy / 2 * __glPi / 180; - - deltaZ = zFar - zNear; - sine = sin(radians); - if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) { - return; - } - cotangent = cos(radians) / sine; - - __gluMakeIdentityd(&m[0][0]); - m[0][0] = cotangent / aspect; - m[1][1] = cotangent; - m[2][2] = -(zFar + zNear) / deltaZ; - m[2][3] = -1; - m[3][2] = -2 * zNear * zFar / deltaZ; - m[3][3] = 0; - glMultMatrixd(&m[0][0]); -} -