Sources/GeometrySample.c

/*
    GeometrySample.c
 
    This is a simple library illustrating trigrid geometries representing a
    Flat 5x5, Torus, Wavey Torus, Splash, Sphere, Cone, Pipe, Steps, and Spring.
 
    NewLibraryTriGrid returns a trigrid geometry when kGeometryLibraryRange_Simple
    is added to the trigrid number (0 to 8) or a trigrid with shading uv attributes
    when kGeometryLibraryRange_UVGeoAttributes or kGeometryLibraryRange_UVFaceAttributes
    is added to the trigrid number.
 
    Note: The calculation of uv's may be flipping the texture.
 
 
    Robert Dierkes - March 22, 1995
    © 1995 Apple Computer, Inc.
 
    Modification History:
 
    03/22/95    rdd     initial version
*/
 
#include <Memory.h>
#include "math.h"
 
#include "QD3D.h"
#include "QD3DGeometry.h"
#include "QD3DMath.h"
#include "AttributeSet_Lib.h"
 
#include "GeometrySample.h"
#include "MathUtilities.h"
 
 
unsigned long GetLibraryMaxSimpleTriGrid(void)
{
    return kGeometryLibrary_TriGridMaxSimple;
}
 
 
 
/*
 *  NewLibraryTriGrid
 *
 * There are two methods below for creating trigrid vertices. If the trigrid is:
 *
 *  1. planar (relatively) then the vvValue (an x-coordinate) increases from vvMin to vvMax.
 *  2. a cross section revolved about the Y axis then the vvValue (an angle) decreases from
 *      vvMax to vvMin in a counter-clockwise manner about the axis. This puts the correct
 *      side of the trigrid facing outward for texture uvs.
 *
 * In both cases, uuValue decreases from uuMax to uuMin from postive to negative Y.
 *
 *  TriGrid vertex index numbering
 *
 *     (i)
 *      8       9       10      11
 *      4       5       6       7
 *      0       1       2       3
 *
 *
 *  UVs for an upright texture continuous across the trigrid
 *
 *     (U,V)
 *     (x,y)
 *
 *      ^ +     0.0, 1.0    0.33, 1.0   0.66, 1.0   1.0, 1.0
 *      |       0.0, 0.5    0.33, 0.5   0.66, 0.5   1.0, 0.5
 *      V -     0.0, 0.0    0.33, 0.0   0.66, 0.0   1.0, 0.0
 *
 *              U -->
 *              -   +
 *
 *  UVs for an upright repeated texture
 *
 *     (U,V)
 *     (x,y)
 *
 *      ^ +     0,2     1,2     2,2     3,2
 *      |       0,1     1,1     2,1     3,1
 *      V -     0,0     1,0     2,0     3,0
 *
 *              U -->
 *              -   +
 */
TQ3GeometryObject   NewLibraryTriGrid(unsigned long num)
{
    TQ3GeometryObject   geometryObject = NULL;
    TQ3TriGridData      data;
    TQ3Vertex3D         *vertices;
    unsigned long       i;
    float               uuValue, vvValue,
                        uuMin, uuMax, uuStep,
                        vvMin, vvMax, vvStep,
                        radius;
    TQ3Boolean          hasUVAttributes;
    TQ3Param2D          param2D;
 
    hasUVAttributes = (TQ3Boolean) (mHasUVGeoAttributes(num)  ||  mHasUVFaceAttributes(num));
 
    switch (num)
    {
        case kGeometryLibraryRange_Simple+0:        //  Flat 5x5
        case kGeometryLibraryRange_UVGeoAttributes+0:
        case kGeometryLibraryRange_UVFaceAttributes+0:
        case kGeometryLibraryRange_Simple+3:        //  Splash
        case kGeometryLibraryRange_UVGeoAttributes+3:
        case kGeometryLibraryRange_UVFaceAttributes+3:
        case kGeometryLibraryRange_Simple+7:        //  Steps
        case kGeometryLibraryRange_UVGeoAttributes+7:
        case kGeometryLibraryRange_UVFaceAttributes+7:
        {
            /* Setup min, max and step values trigrid vertex u & v values */
            switch (num)
            {
            /**
             ** Flat 5x5
             **/
            case kGeometryLibraryRange_Simple+0:
            case kGeometryLibraryRange_UVGeoAttributes+0:
            case kGeometryLibraryRange_UVFaceAttributes+0:
 
                /*
                 * uuValue is an x-coordinate
                 * vvValue is a  y-coordinate
                 */
                uuMin = -0.5;
                uuMax =  0.5;
                uuStep = 0.25;
 
                vvMin = -0.5;
                vvMax =  0.5;
                vvStep = 0.25;
            break;
 
            /**
             ** Splash
             **/
            case kGeometryLibraryRange_Simple+3:
            case kGeometryLibraryRange_UVGeoAttributes+3:
            case kGeometryLibraryRange_UVFaceAttributes+3:
 
                /*
                 * uuValue is an x-coordinate
                 * vvValue is a  y-coordinate
                 */
                uuMin = -3.5;
                uuMax =  3.5;
                vvMin = -3.5;
                vvMax =  3.5;
                if (hasUVAttributes) {
                    uuStep = 0.35;
                    vvStep = 0.35;
                } else {
                    uuStep = 0.25;
                    vvStep = 0.25;
                }
                break;
 
            /**
             ** Steps
             **/
            case kGeometryLibraryRange_Simple+7:
            case kGeometryLibraryRange_UVGeoAttributes+7:
            case kGeometryLibraryRange_UVFaceAttributes+7:
 
                /*
                 * uuValue is an x-coordinate
                 * vvValue is a  y-coordinate
                 */
                #define kStepScale   0.2
 
                uuMin = -4.5;
                uuMax =  4.5;
                uuStep = 0.5;
 
                vvMin = -4.5;
                vvMax =  4.5;
                vvStep = 0.5;
                break;
 
            default:
                DebugStr("\pWarning:  NewLibraryTriGrid ; unknown flat trigrid index");
                return NULL;
                break;
            }
 
 
            /* Setup TQ3TriGridData */
            data.numRows        = (unsigned long) ((vvMax - vvMin) / vvStep) + 1;
            data.numColumns     = (unsigned long) ((uuMax - uuMin) / uuStep) + 1;
            data.facetAttributeSet  = NULL;
            data.triGridAttributeSet= NULL;
 
            data.vertices = (TQ3Vertex3D *) NewPtr (data.numRows * data.numColumns * sizeof(TQ3Vertex3D));
            if (data.vertices == NULL)
            {
                DebugStr("\pError:  NewLibraryTriGrid ; Out of memory for triGrid vertices, geometry library number");
                return NULL;
            }
 
            /* Set trigrid vertices and shading UVs, if it hasUVAttributes */
            vertices = data.vertices;
            i = 0;
            for (vvValue = vvMin; vvValue <= vvMax; vvValue += vvStep)
            {
                for (uuValue = uuMin; uuValue <= uuMax; uuValue += uuStep)
                {
                    switch (num)
                    {
                        /* Flat 5x5 */
                        case kGeometryLibraryRange_Simple+0:
                        case kGeometryLibraryRange_UVGeoAttributes+0:
                        case kGeometryLibraryRange_UVFaceAttributes+0:
                            vertices[i].point.x = uuValue;
                            vertices[i].point.y = vvValue;
                            vertices[i].point.z = 0;
                        break;
 
                        /* Splash */
                        case kGeometryLibraryRange_Simple+3:
                        case kGeometryLibraryRange_UVGeoAttributes+3:
                        case kGeometryLibraryRange_UVFaceAttributes+3:
                            vertices[i].point.x = uuValue;
                            vertices[i].point.y = vvValue;
                            vertices[i].point.z = 1.5 * uMath_Sin_Deg(48.0 * uuValue * vvValue) *
                                                        uMath_Cos_Deg(48.0 * uuValue * vvValue);
                        break;
 
                        /* Steps */
                        case kGeometryLibraryRange_Simple+7:
                        case kGeometryLibraryRange_UVGeoAttributes+7:
                        case kGeometryLibraryRange_UVFaceAttributes+7:
                            vertices[i].point.x = uuValue;
                            vertices[i].point.y = vvValue;
                            vertices[i].point.z = kStepScale * (((long) uuValue) % ((data.numRows-1)/2)) *
                                                               (((long) vvValue) % ((data.numColumns-1)/2));
                        break;
                    }
 
                    if (hasUVAttributes)
                    {
                        if (mHasUVGeoAttributes(num))
                        {
                            param2D.u = (uuValue - uuMin) / (uuMax - uuMin);
                            param2D.v = (vvValue - vvMin) / (vvMax - vvMin);
                        }
                        else /* mHasUVFaceAttributes */
                        {
                            param2D.u = i % data.numColumns;
                            param2D.v = i / data.numColumns;
                        }
 
                        vertices[i].attributeSet = Q3AttributeSet_New();
                        Q3AttributeSet_Add(vertices[i].attributeSet, kQ3AttributeTypeShadingUV, &param2D);
                    }
                    else
                        vertices[i].attributeSet = NULL;
 
                    i++;
                }
            }
 
            geometryObject = Q3TriGrid_New (&data);
 
            if (hasUVAttributes)
            {
                for (i = 0; i < data.numRows * data.numColumns; i++)
                    Q3Object_Dispose(vertices[i].attributeSet);
            }
            DisposePtr ((void *) vertices);
        }
        break;
 
        case kGeometryLibraryRange_Simple+1:        //  Torus
        case kGeometryLibraryRange_UVGeoAttributes+1:
        case kGeometryLibraryRange_UVFaceAttributes+1:
        case kGeometryLibraryRange_Simple+2:        //  Wavey Torus
        case kGeometryLibraryRange_UVGeoAttributes+2:
        case kGeometryLibraryRange_UVFaceAttributes+2:
        case kGeometryLibraryRange_Simple+4:        //  Sphere
        case kGeometryLibraryRange_UVGeoAttributes+4:
        case kGeometryLibraryRange_UVFaceAttributes+4:
        case kGeometryLibraryRange_Simple+5:        //  Cone
        case kGeometryLibraryRange_UVGeoAttributes+5:
        case kGeometryLibraryRange_UVFaceAttributes+5:
        case kGeometryLibraryRange_Simple+6:        //  Pipe
        case kGeometryLibraryRange_UVGeoAttributes+6:
        case kGeometryLibraryRange_UVFaceAttributes+6:
        case kGeometryLibraryRange_Simple+8:        //  Spring
        case kGeometryLibraryRange_UVGeoAttributes+8:
        case kGeometryLibraryRange_UVFaceAttributes+8:
        {
            /* Setup min, max and step values trigrid vertex u & v values */
            switch (num)
            {
            /**
             ** Torus
             **/
            case kGeometryLibraryRange_Simple+1:
            case kGeometryLibraryRange_UVGeoAttributes+1:
            case kGeometryLibraryRange_UVFaceAttributes+1:
            /**
             ** Wavey Torus
             **/
            case kGeometryLibraryRange_Simple+2:
            case kGeometryLibraryRange_UVGeoAttributes+2:
            case kGeometryLibraryRange_UVFaceAttributes+2:
 
                /*
                 * uuValue is used to generate each circular cross section about the y axis
                 * vvValue is used to revolve the circular cross section about the torus' center
                 */
                #define kTorusCrossRadius    0.5
                #define kTorusInnerRadius    1.0
                #define kTorusWaveyAmpRadius 5.0
 
                uuMin =    0.0;
                uuMax =  360.0;
                vvMin = -180.0;
                vvMax =  180.0;
                if (hasUVAttributes) {
                    uuStep = 12.0;
                    vvStep = 12.0;
                } else {
                    uuStep = 10.0;
                    vvStep = 10.0;
                }
                break;
 
            /**
             ** Sphere
             **/
            case kGeometryLibraryRange_Simple+4:
            case kGeometryLibraryRange_UVGeoAttributes+4:
            case kGeometryLibraryRange_UVFaceAttributes+4:
 
                /*
                 * uuValue is an angle used to revolve the cross section about the y axis
                 * vvValue is an angle used to generate each half circular cross section
                 */
                uuMin =    0.0;
                uuMax =  360.0;
                vvMin = - 90.0;
                vvMax =   90.0;
                if (hasUVAttributes) {
                    uuStep =  12.0;
                    vvStep =  12.0;
                } else {
                    uuStep =   9.0;
                    vvStep =   9.0;
                }
                radius = 1.0;
                break;
 
            /**
             ** Cone
             **/
            case kGeometryLibraryRange_Simple+5:
            case kGeometryLibraryRange_UVGeoAttributes+5:
            case kGeometryLibraryRange_UVFaceAttributes+5:
 
                /*
                 * vvValue is the length of the cone side from point to the edge
                 * uuValue is an angle used to revolve the cross section about the y axis
                 */
                if (hasUVAttributes) {
                    uuStep = 24.0;
                    vvStep =  0.25;
                } else {
                    uuStep = 10.0;
                    vvStep =  0.25;
                }
                uuMin =   0.0;
                uuMax = 360.0;
                vvMin = -vvStep;
                vvMax =   2.0;
 
                radius =  0.5;
                break;
 
            /**
             ** Pipe
             **/
            case kGeometryLibraryRange_Simple+6:
            case kGeometryLibraryRange_UVGeoAttributes+6:
            case kGeometryLibraryRange_UVFaceAttributes+6:
 
                /*
                 * uuValue is used to revolve the line cross section about the y axis
                 * vvValue is used to generate the length of the pipe
                 */
                if (hasUVAttributes) {
                    uuStep = 20.0;
                    vvStep =  0.5;
                } else {
                    uuStep = 15.0;
                    vvStep =  0.3;
                }
                uuMin =   0.0;
                uuMax = 360.0;
                vvMin = - 1.5;
                vvMax =   1.5;
#ifdef  FINISH_THIS
                vvMin = - 1.5 - vvStep;
                vvMax =   1.5 + vvStep;
#else   /* FINISH_THIS */
                vvMin = - 1.5;
                vvMax =   1.5;
#endif  /* FINISH_THIS */
                radius =  1.0;
                break;
 
            /**
             ** Spring
             **/
            case kGeometryLibraryRange_Simple+8:
            case kGeometryLibraryRange_UVGeoAttributes+8:
            case kGeometryLibraryRange_UVFaceAttributes+8:
 
                /*
                 * uuValue is used to revolve the circular cross section about the springs' axis
                 * vvValue is used to generate each circular cross section
                 */
                #define kSpringCrossRadius   0.25
                #define kSpringInnerRadius   1.0
                #define kSpringSpacing       3.5*kSpringCrossRadius
 
                uuMin = - 90.0;
                uuMax =  810.0;
                vvMin = -180.0;
                vvMax =  180.0;
                if (hasUVAttributes) {
                    uuStep = 30.0;
                    vvStep = 30.0;
                } else {
                    uuStep = 20.0;
                    vvStep = 15.0;
                }
                break;
 
            default:
                DebugStr("\pWarning:  NewLibraryTriGrid ; unknown revolved trigrid index");
                return NULL;
                break;
            }
 
 
            /* Setup TQ3TriGridData */
            data.numRows        = (unsigned long) ((vvMax - vvMin) / vvStep) + 1;
            data.numColumns     = (unsigned long) ((uuMax - uuMin) / uuStep) + 1;
            data.facetAttributeSet  = NULL;
            data.triGridAttributeSet= NULL;
 
            data.vertices = (TQ3Vertex3D *) NewPtr (data.numRows * data.numColumns * sizeof(TQ3Vertex3D));
            if (data.vertices == NULL)
            {
                DebugStr("\pError:  NewLibraryTriGrid ; Out of memory for triGrid vertices.");
                return NULL;
            }
 
            /* Set trigrid vertices and shading UVs, if it hasUVAttributes */
            vertices = data.vertices;
            i = 0;
            for (vvValue = vvMin; vvValue <= vvMax; vvValue += vvStep)
            {
                for (uuValue = uuMax; uuValue >= uuMin; uuValue -= uuStep)
                {
                    switch (num)
                    {
                        /* Torus */
                        case kGeometryLibraryRange_Simple+1:
                        case kGeometryLibraryRange_UVGeoAttributes+1:
                        case kGeometryLibraryRange_UVFaceAttributes+1:
                            vertices[i].point.x = (uMath_Cos_Deg(vvValue) * kTorusCrossRadius + kTorusInnerRadius) * uMath_Cos_Deg(uuValue);
                            vertices[i].point.y =  uMath_Sin_Deg(vvValue) * kTorusCrossRadius;
                            vertices[i].point.z = (uMath_Cos_Deg(vvValue) * kTorusCrossRadius + kTorusInnerRadius) * uMath_Sin_Deg(uuValue);
                        break;
 
                        /* Wavey Torus */
                        case kGeometryLibraryRange_Simple+2:
                        case kGeometryLibraryRange_UVGeoAttributes+2:
                        case kGeometryLibraryRange_UVFaceAttributes+2:
                            radius = kTorusCrossRadius / kTorusWaveyAmpRadius * uMath_Sin_Deg(kTorusWaveyAmpRadius * uuValue) + kTorusCrossRadius;
                            vertices[i].point.x = (uMath_Cos_Deg(vvValue) * radius + kTorusInnerRadius) * uMath_Cos_Deg(uuValue);
                            vertices[i].point.y =  uMath_Sin_Deg(vvValue) * radius;
                            vertices[i].point.z = (uMath_Cos_Deg(vvValue) * radius + kTorusInnerRadius) * uMath_Sin_Deg(uuValue);
                        break;
 
                        /* Sphere */
                        case kGeometryLibraryRange_Simple+4:
                        case kGeometryLibraryRange_UVGeoAttributes+4:
                        case kGeometryLibraryRange_UVFaceAttributes+4:
                            vertices[i].point.x = uMath_Cos_Deg(vvValue) * uMath_Cos_Deg(uuValue) * radius;
                            vertices[i].point.y = uMath_Sin_Deg(vvValue) * radius;
                            vertices[i].point.z = uMath_Cos_Deg(vvValue) * uMath_Sin_Deg(uuValue) * radius;
                        break;
 
                        /* Cone */
                        case kGeometryLibraryRange_Simple+5:
                        case kGeometryLibraryRange_UVGeoAttributes+5:
                        case kGeometryLibraryRange_UVFaceAttributes+5:
                            if (vvValue < (vvMin + vvStep))
                            {
                                vertices[i].point.x = 0.0;
                                vertices[i].point.y = vvMin + vvStep;
                                vertices[i].point.z = 0.0;
                            }
                            else
                            {
                                vertices[i].point.x = (vvMax - vvValue) * uMath_Cos_Deg(uuValue) * radius;
                                vertices[i].point.y =  vvValue;
                                vertices[i].point.z = (vvMax - vvValue) * uMath_Sin_Deg(uuValue) * radius;
                            }
                        break;
 
                        /* Pipe */
                        case kGeometryLibraryRange_Simple+6:
                        case kGeometryLibraryRange_UVGeoAttributes+6:
                        case kGeometryLibraryRange_UVFaceAttributes+6:
#ifdef  FINISH_THIS
                            if (vvValue < (vvMin + vvStep))
                            {
                                vertices[i].point.x = 0.0;
                                vertices[i].point.y = vvMin + vvStep;
                                vertices[i].point.z = 0.0;
                            }
                            else
                            if (vvValue > (vvMax - vvStep))
                            {
                                vertices[i].point.x = 0.0;
                                vertices[i].point.y = vvMax - vvStep;
                                vertices[i].point.z = 0.0;
                            }
                            else
                            {
                                vertices[i].point.x = uMath_Cos_Deg(uuValue) * radius;
                                vertices[i].point.y = vvValue;
                                vertices[i].point.z = uMath_Sin_Deg(uuValue) * radius;
                            }
#else   /* FINISH_THIS */
                            vertices[i].point.x = radius * uMath_Cos_Deg(uuValue);
                            vertices[i].point.y = vvValue;
                            vertices[i].point.z = radius * uMath_Sin_Deg(uuValue);
#endif  /* FINISH_THIS */
                        break;
 
                        /* Spring */
                        case kGeometryLibraryRange_Simple+8:
                        case kGeometryLibraryRange_UVGeoAttributes+8:
                        case kGeometryLibraryRange_UVFaceAttributes+8:
                            vertices[i].point.x = (uMath_Cos_Deg(vvValue) * kSpringCrossRadius + kSpringInnerRadius) * uMath_Cos_Deg(uuValue);
                            vertices[i].point.y =  uMath_Sin_Deg(vvValue) * kSpringCrossRadius + kSpringSpacing * uuValue/360.0;
                            vertices[i].point.z = (uMath_Cos_Deg(vvValue) * kSpringCrossRadius + kSpringInnerRadius) * uMath_Sin_Deg(uuValue);
                        break;
                    }
 
                    if (hasUVAttributes)
                    {
                        if (mHasUVGeoAttributes(num))
                        {
                            param2D.u = 1.0 - ((uuValue - uuMin) / (uuMax - uuMin));
                            param2D.v = (vvValue - vvMin) / (vvMax - vvMin);
                        }
                        else /* mHasUVFaceAttributes */
                        {
                            param2D.u = i % data.numColumns;
                            param2D.v = i / data.numColumns;
                        }
 
                        vertices[i].attributeSet = Q3AttributeSet_New();
                        Q3AttributeSet_Add(vertices[i].attributeSet, kQ3AttributeTypeShadingUV, &param2D);
                    }
                    else
                        vertices[i].attributeSet = NULL;
 
                    i++;
                }
            }
 
            geometryObject = Q3TriGrid_New (&data);
 
            if (hasUVAttributes)
            {
                for (i = 0; i < data.numRows * data.numColumns; i++)
                    Q3Object_Dispose(vertices[i].attributeSet);
            }
            DisposePtr ((void *) vertices);
        }
        break;
 
        default:
            DebugStr("\pWarning:  NewLibraryTriGrid ; index unimplemented ");
            break;
    }
    return  geometryObject;
}