001/*****************************************************************************
002 *                        J3D.org Copyright (c) 2000
003 *                               Java Source
004 *
005 * This source is licensed under the GNU LGPL v2.1
006 * Please read http://www.gnu.org/copyleft/lgpl.html for more information
007 *
008 ****************************************************************************/
009
010package jahuwaldt.j3d.geom;
011
012// Standard imports
013import org.jogamp.vecmath.Vector3f;
014
015// Application specific imports
016
017/**
018 * A simple cylinder that can be configured to have end caps.
019 * <p>
020 *
021 * The generator is used to create cylinder shaped geometry for the code.
022 * Internally we use a triangle array to generate the information as a
023 * collection of single triangles. A triangle strip would be more efficient
024 * for rendering, but that's too hard for this first cut :)
025 *
026 * The height of the cone is along the Y axis with the point in the positive
027 * Y direction. The radius is around the X-Z plane. The whole object is
028 * centered on the origin.
029 *
030 * @author Justin Couch
031 * @version $Revision: 1.11-JAH1 $
032 */
033public class CylinderGenerator extends GeometryGenerator
034{
035    /** The default height of the object */
036    private static final float DEFAULT_HEIGHT = 2;
037
038    /** The default radius of the cylinder */
039    private static final float DEFAULT_RADIUS = 1;
040
041    /** Default number of segments used in the cone */
042    private static final int DEFAULT_FACETS = 16;
043
044    /** The height of the code */
045    private float cylinderHeight;
046
047    /** The radius of the bottom of the cone */
048    private float radius;
049
050    /** Flag to indicate if the geometry should create the top */
051    private boolean useTop;
052
053    /** Flag to indicate if the geometry should create the side */
054    private boolean useSide;
055
056    /** Flag to indicate if the geometry should create the bottom */
057    private boolean useBottom;
058
059    /** The number of sections used around the cone */
060    private int facetCount;
061
062    /** The points on the base of the cone for each facet in [x, z] */
063    private float[] baseCoordinates;
064
065    /** The number of values used in the base coordinate array */
066    private int numBaseValues;
067
068    /**
069     * The 2D texture coordinates for the sphere. These match the order of
070     * vertex declaration in the quadCoordinates field thus making life
071     * easy for dealing with half spheres
072     */
073    private float[] texCoordinates2D;
074
075    /** The number of values used in the 2D tex coord array */
076    private int numTexCoords2D;
077
078    /**
079     * The 3D texture coordinates for the sphere. These match the order of
080     * vertex declaration in the quadCoordinates field thus making life
081     * easy for dealing with half spheres
082     */
083    private float[] texCoordinates3D;
084
085    /** The number of values used in the 2D tex coord array */
086    private int numTexCoords3D;
087
088    /** Flag indicating base values have changed */
089    private boolean baseChanged;
090
091    /** Flag to indicate the facet count or half settings have changed */
092    private boolean facetsChanged;
093
094    /** Working values for the normal generation */
095    private Vector3f normal;
096
097    /**
098     * Construct a default cylinder with end caps. The default height is 2
099     * and radius 1. There are 16 faces on around the radius.
100     */
101    public CylinderGenerator()
102    {
103        this(DEFAULT_HEIGHT, DEFAULT_RADIUS, DEFAULT_FACETS, true, true, true);
104    }
105
106    /**
107     * Construct a default cylinder with the option of having end caps.
108     * The default height is 2 and radius 1. There are 16 faces on around the
109     * radius.
110     *
111     * @param ends true to use end caps
112     */
113    public CylinderGenerator(boolean ends)
114    {
115        this(DEFAULT_HEIGHT, DEFAULT_RADIUS, DEFAULT_FACETS, ends, ends, true);
116    }
117
118    /**
119     * Construct a default cylinder with end caps and selectable number of
120     * faces around the radius. The default height is 2 and radius 1. The
121     * minimum number of facets is 3.
122     *
123     * @param facets The number of faces to use around the radius
124     * @throws IllegalArgumentException The number of facets is less than 3
125     */
126    public CylinderGenerator(int facets)
127    {
128        this(DEFAULT_HEIGHT, DEFAULT_RADIUS, facets, true, true, true);
129    }
130
131    /**
132     * Construct a default cylinder with the option of having end caps and
133     * selectable number of faces around the radius. The default height is 2
134     * and radius 1.The minimum number of facets is 3.
135     *
136     * @param facets The number of faces to use around the radius
137     * @param ends true to use end caps
138     * @throws IllegalArgumentException The number of facets is less than 3
139     */
140    public CylinderGenerator(int facets, boolean ends)
141    {
142        this(DEFAULT_HEIGHT, DEFAULT_RADIUS, facets, ends, ends, true);
143    }
144
145    /**
146     * Construct a cylinder of a given height and radius with ends. There are
147     * 16 faces around the radius.
148     *
149     * @param height The height of the cylinder to generate
150     * @param radius The radis of the cylinder to generate
151     */
152    public CylinderGenerator(float height, float radius)
153    {
154        this(height, radius, DEFAULT_FACETS, true, true, true);
155    }
156
157    /**
158     * Construct a cylinder of a given height and radius with ends and
159     * selectable number of faces around the radius. The minimum
160     * number of facets is 3.
161     *
162     * @param height The height of the cylinder to generate
163     * @param radius The radis of the cylinder to generate
164     * @param facets The number of faces to use around the radius
165     * @throws IllegalArgumentException The number of facets is less than 3
166     */
167    public CylinderGenerator(float height, float radius, int facets)
168    {
169        this(height, radius, facets, true, true, true);
170    }
171
172    /**
173     * Construct a cylinder of a given height and radius with the option of
174     * ends. There are 16 faces around the radius.
175     *
176     * @param height The height of the cylinder to generate
177     * @param radius The radis of the cylinder to generate
178     * @param ends true to use end caps
179     * @param side true to display the sides
180     */
181    public CylinderGenerator(float height, float radius, boolean ends, boolean side)
182    {
183        this(height, radius, DEFAULT_FACETS, ends, ends, side);
184    }
185
186    /**
187     * Construct a cylinder of a given height and radius with the option of
188     * ends. There are 16 faces around the radius.
189     *
190     * @param height The height of the cylinder to generate
191     * @param radius The radis of the cylinder to generate
192     * @param top Whether to generate the top of the cylinder
193     * @param bottom Whether to generate the bottom of the cylinder
194     * @param side Whether to generate the side of the cylinder
195     */
196    public CylinderGenerator(float height, float radius, boolean top, boolean bottom,
197        boolean side)
198    {
199        this(height, radius, DEFAULT_FACETS, top, bottom, side);
200    }
201
202    /**
203     * Construct a cylinder of a given height and radius with the option of
204     * ends and selectable number of faces around the radius. The minimum
205     * number of facets is 3.
206     *
207     * @param height The height of the cylinder to generate
208     * @param radius The radis of the cylinder to generate
209     * @param facets The number of faces to use around the radius
210     * @param ends true to use end caps
211     * @param side true to display the side
212     * @throws IllegalArgumentException The number of facets is less than 3
213     */
214    public CylinderGenerator(float height,
215                             float radius,
216                             int facets,
217                             boolean ends,
218                             boolean side)
219    {
220        this(height, radius, facets, true, true, side);
221    }
222
223    /**
224     * Construct a cylinder of a given height and radius with the option of
225     * ends and selectable number of faces around the radius. The minimum
226     * number of facets is 3.
227     *
228     * @param height The height of the cylinder to generate
229     * @param radius The radis of the cylinder to generate
230     * @param facets The number of faces to use around the radius
231     * @param top Whether to generate the top of the cylinder
232     * @param bottom Whether to generate the bottom of the cylinder
233     * @param side Whether to generate the side of the cylinder
234     * @throws IllegalArgumentException The number of facets is less than 3
235     */
236    public CylinderGenerator(float height,
237                             float radius,
238                             int facets,
239                             boolean top,
240                             boolean bottom,
241                             boolean side) {
242
243        if(facets < 3)
244            throw new IllegalArgumentException("Number of facets is < 3");
245
246        facetCount = facets;
247        cylinderHeight = height;
248        this.radius = radius;
249
250        useTop = top;
251        useBottom = bottom;
252        useSide = side;
253        baseChanged = true;
254        facetsChanged = true;
255        normal = new Vector3f();
256    }
257
258    /**
259     * Check to see that this cylinder has ends in use or not
260     *
261     * @return true if there is are end caps in use
262     */
263    public boolean hasEnds()
264    {
265        if (useTop && useBottom)
266            return true;
267        else
268            return false;
269    }
270
271    /**
272     * Get the dimensions of the cylinder. These are returned as 2 values of
273     * height and radius respectively for the array. A new array is
274     * created each time so you can do what you like with it.
275     *
276     * @return The current size of the cone
277     */
278    public float[] getDimensions()
279    {
280        return new float[] { cylinderHeight, radius };
281    }
282
283    /**
284     * Change the dimensions of the cone to be generated. Calling this will
285     * make the points be re-calculated next time you ask for geometry or
286     * normals.
287     *
288     * @param height The height of the cone to generate
289     * @param radius The radius of the bottom of the cone
290     * @param ends True if to generate faces for the ends
291     * @param side true if to generate faces for the sides
292     */
293    public void setDimensions(float height, float radius, boolean ends,
294        boolean side)
295    {
296        if((cylinderHeight != height) || (this.radius != radius))
297        {
298            baseChanged = true;
299            cylinderHeight = height;
300            this.radius = radius;
301        }
302
303        if(ends != useTop != useBottom)
304            facetsChanged = true;
305
306        if (side != useSide)
307            facetsChanged = true;
308
309        useTop = ends;
310        useBottom = ends;
311        useSide = side;
312    }
313
314    /**
315     * Change the number of facets used to create this cone. This will cause
316     * the geometry to be regenerated next time they are asked for.
317     * The minimum number of facets is 3.
318     *
319     * @param facets The number of facets on the side of the cone
320     * @throws IllegalArgumentException The number of facets is less than 3
321     */
322    public void setFacetCount(int facets)
323    {
324        if(facets < 3)
325            throw new IllegalArgumentException("Number of facets is < 3");
326
327        facetCount = facets;
328        baseChanged = true;
329        facetsChanged = true;
330    }
331
332    /**
333     * Get the number of vertices that this generator will create for the
334     * shape given in the definition.
335     *
336     * @param data The data to base the calculations on
337     * @return The vertex count for the object
338     * @throws UnsupportedTypeException The generator cannot handle the type
339     *   of geometry you have requested.
340     */
341    public int getVertexCount(GeometryData data)
342        throws UnsupportedTypeException
343    {
344        int ret_val = 0;
345
346        switch(data.geometryType)
347        {
348            case GeometryData.TRIANGLES:
349                if (useSide)
350                    ret_val = facetCount * 6;
351                if(useTop)
352                    ret_val += facetCount * 3;
353                if(useBottom)
354                    ret_val += facetCount * 3;
355                break;
356
357            case GeometryData.QUADS:
358                if (useSide)
359                    ret_val = facetCount * 4;
360                if(useTop)
361                    ret_val += facetCount * 4;
362                if(useBottom)
363                    ret_val += facetCount * 4;
364                break;
365
366            // These all have the same vertex count
367            case GeometryData.TRIANGLE_STRIPS:
368                if (useSide)
369                    ret_val = (facetCount + 1) * 2;
370                if(useTop)
371                    ret_val += (facetCount + 1) * 2;
372                if(useBottom)
373                    ret_val += (facetCount + 1) * 2;
374                break;
375
376            case GeometryData.TRIANGLE_FANS:
377                if (useSide)
378                    ret_val = facetCount * 4;
379                if(useTop)
380                    ret_val += (facetCount + 2);
381                if(useBottom)
382                    ret_val += (facetCount + 2);
383
384            case GeometryData.INDEXED_TRIANGLES:
385            case GeometryData.INDEXED_QUADS:
386            case GeometryData.INDEXED_TRIANGLE_STRIPS:
387            case GeometryData.INDEXED_TRIANGLE_FANS:
388                if (useSide)
389                    ret_val = facetCount * 2;
390                if(useTop)
391                    ret_val += 1 + facetCount;
392                if(useBottom)
393                    ret_val += 1 + facetCount;
394                break;
395
396            default:
397                throw new UnsupportedTypeException("Unknown geometry type: " +
398                                                   data.geometryType);
399        }
400
401        return ret_val;
402    }
403
404    /**
405     * Generate a new set of geometry items based on the passed data. If the
406     * data does not contain the right minimum array lengths an exception will
407     * be generated. If the array reference is null, this will create arrays
408     * of the correct length and assign them to the return value.
409     *
410     * @param data The data to base the calculations on
411     * @throws InvalidArraySizeException The array is not big enough to contain
412     *   the requested geometry
413     * @throws UnsupportedTypeException The generator cannot handle the type
414     *   of geometry you have requested
415     */
416    public void generate(GeometryData data)
417        throws UnsupportedTypeException, InvalidArraySizeException
418    {
419        switch(data.geometryType)
420        {
421            case GeometryData.TRIANGLES:
422                unindexedTriangles(data);
423                break;
424            case GeometryData.QUADS:
425                unindexedQuads(data);
426                break;
427            case GeometryData.TRIANGLE_STRIPS:
428                triangleStrips(data);
429                break;
430            case GeometryData.TRIANGLE_FANS:
431                triangleFans(data);
432                break;
433            case GeometryData.INDEXED_QUADS:
434                indexedQuads(data);
435                break;
436            case GeometryData.INDEXED_TRIANGLES:
437                indexedTriangles(data);
438                break;
439            case GeometryData.INDEXED_TRIANGLE_STRIPS:
440                indexedTriangleStrips(data);
441                break;
442            case GeometryData.INDEXED_TRIANGLE_FANS:
443                indexedTriangleFans(data);
444                break;
445
446            default:
447                throw new UnsupportedTypeException("Unknown geometry type: " +
448                                                   data.geometryType);
449        }
450    }
451
452    /**
453     * Generate a new set of points for an unindexed quad array
454     *
455     * @param data The data to base the calculations on
456     * @throws InvalidArraySizeException The array is not big enough to contain
457     *   the requested geometry
458     */
459    private void unindexedTriangles(GeometryData data)
460        throws InvalidArraySizeException
461    {
462        generateUnindexedTriCoordinates(data);
463
464        if((data.geometryComponents & GeometryData.NORMAL_DATA) != 0)
465            generateUnindexedTriNormals(data);
466
467        if((data.geometryComponents & GeometryData.TEXTURE_2D_DATA) != 0)
468            generateTriTexture2D(data);
469        else if((data.geometryComponents & GeometryData.TEXTURE_3D_DATA) != 0)
470            generateTriTexture3D(data);
471    }
472
473    /**
474     * Generate a new set of points for an unindexed quad array
475     *
476     * @param data The data to base the calculations on
477     * @throws InvalidArraySizeException The array is not big enough to contain
478     *   the requested geometry
479     */
480    private void unindexedQuads(GeometryData data)
481        throws InvalidArraySizeException
482    {
483        generateUnindexedQuadCoordinates(data);
484
485        if((data.geometryComponents & GeometryData.NORMAL_DATA) != 0)
486            generateUnindexedQuadNormals(data);
487
488        if((data.geometryComponents & GeometryData.TEXTURE_2D_DATA) != 0)
489            generateTriTexture2D(data);
490        else if((data.geometryComponents & GeometryData.TEXTURE_3D_DATA) != 0)
491            generateTriTexture3D(data);
492    }
493
494    /**
495     * Generate a new set of points for an indexed quad array. Uses the same
496     * points as an indexed triangle, but repeats the top coordinate index.
497     *
498     * @param data The data to base the calculations on
499     * @throws InvalidArraySizeException The array is not big enough to contain
500     *   the requested geometry
501     */
502    private void indexedQuads(GeometryData data)
503        throws InvalidArraySizeException
504    {
505        generateIndexedCoordinates(data);
506
507        if((data.geometryComponents & GeometryData.NORMAL_DATA) != 0)
508            generateIndexedNormals(data);
509
510        if((data.geometryComponents & GeometryData.TEXTURE_2D_DATA) != 0)
511            generateTriTexture2D(data);
512        else if((data.geometryComponents & GeometryData.TEXTURE_3D_DATA) != 0)
513            generateTriTexture3D(data);
514
515        // now let's do the index list
516        int index_size = data.vertexCount * 4;
517
518        if(data.indexes == null)
519            data.indexes = new int[index_size];
520        else if(data.indexes.length < index_size)
521            throw new InvalidArraySizeException("Coordinates",
522                                                data.indexes.length,
523                                                index_size);
524
525        int[] indexes = data.indexes;
526        data.indexesCount = index_size;
527        int idx = 0;
528        int vtx = 0;
529
530        if (useSide)
531        {
532            // each face consists of an anti-clockwise
533            for(int i = facetCount; --i > 0; vtx += 2)
534            {
535                indexes[idx++] = vtx;
536                indexes[idx++] = vtx + 1;
537                indexes[idx++] = vtx + 3;
538                indexes[idx++] = vtx + 2;
539            }
540
541            indexes[idx++] = vtx++;
542            indexes[idx++] = vtx++;
543            indexes[idx++] = 0;
544            indexes[idx++] = 1;
545        }
546
547        int middle;
548        if(useTop)
549        {
550            middle = vtx++;
551
552            // top face.
553            for(int i = facetCount; --i > 0; )
554            {
555                indexes[idx++] = middle;
556                indexes[idx++] = vtx++;
557                indexes[idx++] = vtx;
558                indexes[idx++] = middle;
559            }
560
561            indexes[idx++] = middle;
562            indexes[idx++] = vtx++;
563            indexes[idx++] = middle + 1;
564            indexes[idx++] = middle;
565        }
566
567        if (useBottom)
568        {
569            middle = vtx++;
570
571            // bottom face is same as top.
572            for(int i = facetCount; --i > 0; )
573            {
574                indexes[idx++] = middle;
575                indexes[idx++] = vtx + 1;
576                indexes[idx++] = vtx++;
577                indexes[idx++] = middle;
578            }
579
580            indexes[idx++] = middle;
581            indexes[idx++] = middle + 1;
582            indexes[idx++] = vtx;
583            indexes[idx++] = middle;
584        }
585    }
586
587    /**
588     * Generate a new set of points for an indexed triangle array
589     *
590     * @param data The data to base the calculations on
591     * @throws InvalidArraySizeException The array is not big enough to contain
592     *   the requested geometry
593     */
594    private void indexedTriangles(GeometryData data)
595        throws InvalidArraySizeException
596    {
597        generateIndexedCoordinates(data);
598
599        if((data.geometryComponents & GeometryData.NORMAL_DATA) != 0)
600            generateIndexedNormals(data);
601
602        if((data.geometryComponents & GeometryData.TEXTURE_2D_DATA) != 0)
603            generateTriTexture2D(data);
604        else if((data.geometryComponents & GeometryData.TEXTURE_3D_DATA) != 0)
605            generateTriTexture3D(data);
606
607        // now let's do the index list
608        int index_size = data.vertexCount * 3;
609
610        if(data.indexes == null)
611            data.indexes = new int[index_size];
612        else if(data.indexes.length < index_size)
613            throw new InvalidArraySizeException("Coordinates",
614                                                data.indexes.length,
615                                                index_size);
616
617        int[] indexes = data.indexes;
618        data.indexesCount = index_size;
619        int idx = 0;
620        int vtx = 0;
621
622        if (useSide)
623        {
624            // each face consists of an anti-clockwise
625            for(int i = facetCount; --i > 0; vtx += 2)
626            {
627                // triangle 1
628                indexes[idx++] = vtx;
629                indexes[idx++] = vtx + 1;
630                indexes[idx++] = vtx + 3;
631
632                // triangle 2
633                indexes[idx++] = vtx + 3;
634                indexes[idx++] = vtx + 2;
635                indexes[idx++] = vtx;
636            }
637
638            // triangle 1
639            indexes[idx++] = vtx;
640            indexes[idx++] = vtx + 1;
641            indexes[idx++] = 1;
642
643            // triangle 2
644            indexes[idx++] = 1;
645            indexes[idx++] = 0;
646            indexes[idx++] = vtx;
647
648            vtx += 2;
649        }
650
651        int middle;
652
653        if(useTop)
654        {
655            middle = vtx++;
656
657            for(int i = facetCount; --i > 0; )
658            {
659                indexes[idx++] = middle;
660                indexes[idx++] = vtx + 1;
661                indexes[idx++] = vtx++;
662            }
663
664            indexes[idx++] = middle;
665            indexes[idx++] = middle + 1;
666            indexes[idx++] = vtx;
667
668        }
669        if (useBottom)
670        {
671            middle = vtx++;
672
673            for(int i = facetCount; --i > 0; )
674            {
675                indexes[idx++] = middle;
676                indexes[idx++] = vtx + 1;
677                indexes[idx++] = vtx++;
678            }
679
680            indexes[idx++] = middle;
681            indexes[idx++] = middle + 1;
682            indexes[idx++] = vtx;
683        }
684    }
685
686    /**
687     * Generate a new set of points for a triangle strip array. There is one
688     * strip for the side and one strip each for the ends.
689     *
690     * @param data The data to base the calculations on
691     * @throws InvalidArraySizeException The array is not big enough to contain
692     *   the requested geometry
693     */
694    private void triangleStrips(GeometryData data)
695        throws InvalidArraySizeException
696    {
697        generateUnindexedTriStripCoordinates(data);
698
699        if((data.geometryComponents & GeometryData.NORMAL_DATA) != 0)
700            generateUnindexedTriStripNormals(data);
701
702        if((data.geometryComponents & GeometryData.TEXTURE_2D_DATA) != 0)
703            generateTriTexture2D(data);
704        else if((data.geometryComponents & GeometryData.TEXTURE_3D_DATA) != 0)
705            generateTriTexture3D(data);
706
707        int num_strips = 0;
708
709        if (useSide)
710            num_strips++;
711
712        if (useTop)
713            num_strips++;
714
715        if (useBottom)
716            num_strips++;
717
718        if(data.stripCounts == null)
719            data.stripCounts = new int[num_strips];
720        else if(data.stripCounts.length < num_strips)
721            throw new InvalidArraySizeException("Strip counts",
722                                                data.stripCounts.length,
723                                                num_strips);
724
725        int scnt=0;
726        int basecount = (1 + facetCount) * 2;
727
728        data.numStrips = num_strips;
729
730        if (useSide)
731            data.stripCounts[scnt++] = basecount;
732
733        if (useTop)
734            data.stripCounts[scnt++] = basecount;
735        if (useBottom)
736            data.stripCounts[scnt++] = basecount;
737    }
738
739    /**
740     * Generate a new set of points for a triangle fan array. Each facet on the
741     * side of the cylinder is a single fan, but the ends are one big fan each.
742     *
743     * @param data The data to base the calculations on
744     * @throws InvalidArraySizeException The array is not big enough to contain
745     *   the requested geometry
746     */
747    private void triangleFans(GeometryData data)
748        throws InvalidArraySizeException
749    {
750        generateUnindexedTriFanCoordinates(data);
751
752        if((data.geometryComponents & GeometryData.NORMAL_DATA) != 0)
753            generateUnindexedTriFanNormals(data);
754
755        if((data.geometryComponents & GeometryData.TEXTURE_2D_DATA) != 0)
756            generateTriTexture2D(data);
757        else if((data.geometryComponents & GeometryData.TEXTURE_3D_DATA) != 0)
758            generateTriTexture3D(data);
759
760        int num_strips = facetCount + 2;
761
762        if(data.stripCounts == null)
763            data.stripCounts = new int[num_strips];
764        else if(data.stripCounts.length < num_strips)
765            throw new InvalidArraySizeException("Strip counts",
766                                                data.stripCounts.length,
767                                                num_strips);
768
769        for(int i = facetCount; --i >= 0; )
770            data.stripCounts[i] = 4;
771
772        data.stripCounts[num_strips - 2] = facetCount + 2;
773        data.stripCounts[num_strips - 1] = facetCount + 2;
774        data.numStrips = num_strips;
775    }
776
777    /**
778     * Generate a new set of points for an indexed triangle strip array. We
779     * build the strip from the existing points starting by working around the
780     * side and then doing the top and bottom. To create the ends we start at
781     * on radius point and then always refer to the center for each second
782     * item. This wastes every second triangle as a degenerate triangle, but
783     * the gain is less strips needing to be transmitted - ie less memory
784     * usage.
785     *
786     * @param data The data to base the calculations on
787     * @throws InvalidArraySizeException The array is not big enough to contain
788     *   the requested geometry
789     */
790    private void indexedTriangleStrips(GeometryData data)
791        throws InvalidArraySizeException
792    {
793        generateIndexedCoordinates(data);
794
795        if((data.geometryComponents & GeometryData.NORMAL_DATA) != 0)
796            generateIndexedNormals(data);
797
798        if((data.geometryComponents & GeometryData.TEXTURE_2D_DATA) != 0)
799            generateTriTexture2D(data);
800        else if((data.geometryComponents & GeometryData.TEXTURE_3D_DATA) != 0)
801            generateTriTexture3D(data);
802
803        int index_size = 0;
804        int num_strips = 0;
805
806        if (useSide)
807        {
808            // now let's do the index list
809            index_size = (facetCount + 1) * 2;
810            num_strips = 1;
811        }
812
813        if (useTop)
814        {
815            index_size += (facetCount + 1) * 2;
816            num_strips += 1;
817        }
818        if (useBottom)
819        {
820            index_size += (facetCount + 1) * 2;
821            num_strips += 1;
822        }
823
824        if(data.indexes == null)
825            data.indexes = new int[index_size];
826        else if(data.indexes.length < index_size)
827            throw new InvalidArraySizeException("Indexes",
828                                                data.indexes.length,
829                                                index_size);
830
831        if(data.stripCounts == null)
832            data.stripCounts = new int[num_strips];
833        else if(data.stripCounts.length < num_strips)
834            throw new InvalidArraySizeException("Strip counts",
835                                                data.stripCounts.length,
836                                                num_strips);
837
838        int[] indexes = data.indexes;
839        int[] stripCounts = data.stripCounts;
840        data.indexesCount = index_size;
841        data.numStrips = num_strips;
842        int idx = 0;
843        int vtx = 0;
844        int s_idx = 0;
845
846        if (useSide)
847        {
848            stripCounts[s_idx++] = (facetCount + 1) * 2;
849
850            // The side is one big strip
851            for(int i = facetCount; --i >= 0; )
852            {
853                indexes[idx++] = vtx++;
854                indexes[idx++] = vtx++;
855            }
856
857            indexes[idx++] = 0;
858            indexes[idx++] = facetCount;
859        }
860
861        int middle;
862        if(useTop)
863        {
864            stripCounts[s_idx++] = (facetCount + 1) * 2;
865
866            // Do the top face as one strip
867            middle = vtx++;
868
869            for(int i = facetCount; --i >= 0; )
870            {
871                indexes[idx++] = middle;
872                indexes[idx++] = vtx++;
873            }
874
875            indexes[idx++] = middle + 1;
876            indexes[idx++] = middle;
877
878        }
879        if(useBottom)
880        {
881            // Now the bottom face as one strip. Must wind it backwards compared
882            // to the top.
883            stripCounts[s_idx] = (facetCount + 1) * 2;
884
885            middle = vtx++;
886
887            for(int i = facetCount; --i >= 0; )
888            {
889                indexes[idx++] = vtx++;
890                indexes[idx++] = middle;
891            }
892
893            indexes[idx++] = middle + 1;
894            indexes[idx++] = middle;
895        }
896    }
897
898    /**
899     * Generate a new set of points for an indexed triangle fan array. We
900     * build the strip from the existing points, and there's no need to
901     * re-order the points for the indexes this time. As for the simple fan,
902     * we use the first index, the lower-right corner as the apex for the fan.
903     *
904     * @param data The data to base the calculations on
905     * @throws InvalidArraySizeException The array is not big enough to contain
906     *   the requested geometry
907     */
908    private void indexedTriangleFans(GeometryData data)
909        throws InvalidArraySizeException
910    {
911        generateIndexedCoordinates(data);
912
913        if((data.geometryComponents & GeometryData.NORMAL_DATA) != 0)
914            generateIndexedNormals(data);
915
916        if((data.geometryComponents & GeometryData.TEXTURE_2D_DATA) != 0)
917            generateTriTexture2D(data);
918        else if((data.geometryComponents & GeometryData.TEXTURE_3D_DATA) != 0)
919            generateTriTexture3D(data);
920
921        int index_size = 0;
922        int num_strips = 0;
923
924        if (useSide)
925        {
926            index_size = facetCount * 4;
927            num_strips = facetCount;
928        }
929
930        if (useTop)
931        {
932            index_size += 2 * (facetCount + 2);
933            num_strips++;
934        }
935
936        if (useBottom)
937        {
938            index_size += 2 * (facetCount + 2);
939            num_strips++;
940        }
941
942        if(data.indexes == null)
943            data.indexes = new int[index_size];
944        else if(data.indexes.length < index_size)
945            throw new InvalidArraySizeException("Indexes",
946                                                data.indexes.length,
947                                                index_size);
948
949        if(data.stripCounts == null)
950            data.stripCounts = new int[num_strips];
951        else if(data.stripCounts.length < num_strips)
952            throw new InvalidArraySizeException("Strip counts",
953                                                data.stripCounts.length,
954                                                num_strips);
955
956        int[] indexes = data.indexes;
957        int[] stripCounts = data.stripCounts;
958        data.indexesCount = index_size;
959        data.numStrips = num_strips;
960        int idx = 0;
961        int vtx = 0;
962        int scnt = 0;
963
964        if (useSide)
965        {
966            // each face consists of an anti-clockwise
967            for(int i = facetCount; --i > 0; )
968            {
969                indexes[idx++] = vtx;
970                indexes[idx++] = vtx + 1;
971                indexes[idx++] = vtx + 3;
972                indexes[idx++] = vtx + 2;
973                stripCounts[i] = 4;
974
975                vtx += 2;
976            }
977
978            indexes[idx++] = vtx;
979            indexes[idx++] = vtx + 1;
980            indexes[idx++] = 1;
981            indexes[idx++] = 0;
982            vtx += 2;
983
984            stripCounts[scnt++] = 4;
985        }
986
987        int middle;
988
989        if(useTop)
990        {
991            // Do the top face as one fan
992            middle = vtx++;
993            indexes[idx++] = middle;
994            stripCounts[scnt++] = facetCount + 2;
995
996            for(int i = facetCount; --i >= 0; )
997                indexes[idx++] = vtx++;
998
999            indexes[idx++] = middle + 1;
1000
1001        }
1002        if (useBottom)
1003        {
1004            // Now the bottom face as one fan. Must wind it backwards compared
1005            // to the top.
1006            middle = vtx++;
1007            indexes[idx++] = middle;
1008            stripCounts[scnt++] = facetCount + 2;
1009
1010            vtx = data.vertexCount - 1;
1011            for(int i = facetCount; --i >= 0; )
1012                indexes[idx++] = vtx--;
1013
1014            indexes[idx++] = data.vertexCount - 1;
1015        }
1016    }
1017
1018    //------------------------------------------------------------------------
1019    // Coordinate generation routines
1020    //------------------------------------------------------------------------
1021
1022    /**
1023     * Generates new set of unindexed points for triangles. The array consists
1024     * of the side coordinates, followed by the top and bottom.
1025     *
1026     * @param data The data to base the calculations on
1027     * @throws InvalidArraySizeException The array is not big enough to contain
1028     *   the requested geometry
1029     */
1030    private void generateUnindexedTriCoordinates(GeometryData data)
1031        throws InvalidArraySizeException
1032    {
1033        int vtx_cnt = 0;
1034
1035        if (useSide)
1036            vtx_cnt = facetCount * 6;
1037        if(useTop)
1038            vtx_cnt += facetCount * 3;
1039        if(useBottom)
1040            vtx_cnt += facetCount * 3;
1041
1042        if(data.coordinates == null)
1043            data.coordinates = new float[vtx_cnt * 3];
1044        else if(data.coordinates.length < vtx_cnt * 3)
1045            throw new InvalidArraySizeException("Coordinates",
1046                                                data.coordinates.length,
1047                                                vtx_cnt * 3);
1048
1049        float[] coords = data.coordinates;
1050        data.vertexCount = vtx_cnt;
1051
1052        regenerateBase();
1053
1054        int count = 0;
1055        int i = 0;
1056        int base_count = 0;
1057        float half_height = cylinderHeight / 2;
1058
1059        if (useSide)
1060        {
1061            for(i = facetCount; --i > 0; )
1062            {
1063                //side coords triangle 1
1064                coords[count++] = baseCoordinates[base_count];
1065                coords[count++] = -half_height;
1066                coords[count++] = baseCoordinates[base_count + 1];
1067
1068                coords[count++] = baseCoordinates[base_count + 2];
1069                coords[count++] = -half_height;
1070                coords[count++] = baseCoordinates[base_count + 3];
1071
1072                coords[count++] = baseCoordinates[base_count + 2];
1073                coords[count++] = half_height;
1074                coords[count++] = baseCoordinates[base_count + 3];
1075
1076                //side coords triangle 2
1077                coords[count++] = baseCoordinates[base_count + 2];
1078                coords[count++] = half_height;
1079                coords[count++] = baseCoordinates[base_count + 3];
1080
1081                coords[count++] = baseCoordinates[base_count];
1082                coords[count++] = half_height;
1083                coords[count++] = baseCoordinates[base_count + 1];
1084
1085                coords[count++] = baseCoordinates[base_count];
1086                coords[count++] = -half_height;
1087                coords[count++] = baseCoordinates[base_count + 1];
1088
1089                base_count += 2;
1090            }
1091
1092            //side coords triangle 1
1093            coords[count++] = baseCoordinates[base_count];
1094            coords[count++] = -half_height;
1095            coords[count++] = baseCoordinates[base_count + 1];
1096
1097            coords[count++] = baseCoordinates[0];
1098            coords[count++] = -half_height;
1099            coords[count++] = baseCoordinates[1];
1100
1101            coords[count++] = baseCoordinates[0];
1102            coords[count++] = half_height;
1103            coords[count++] = baseCoordinates[1];
1104
1105            //side coords triangle 2
1106            coords[count++] = baseCoordinates[0];
1107            coords[count++] = half_height;
1108            coords[count++] = baseCoordinates[1];
1109
1110            coords[count++] = baseCoordinates[base_count];
1111            coords[count++] = half_height;
1112            coords[count++] = baseCoordinates[base_count + 1];
1113
1114            coords[count++] = baseCoordinates[base_count];
1115            coords[count++] = -half_height;
1116            coords[count++] = baseCoordinates[base_count + 1];
1117        }
1118
1119        if(useTop)
1120        {
1121            base_count = 0;
1122
1123            // Top coordinates
1124            for(i = facetCount; --i > 0; )
1125            {
1126                coords[count++] = baseCoordinates[base_count + 2];
1127                coords[count++] = half_height;
1128                coords[count++] = baseCoordinates[base_count + 3];
1129
1130                coords[count++] = 0;
1131                coords[count++] = half_height;
1132                coords[count++] = 0;
1133
1134                coords[count++] = baseCoordinates[base_count];
1135                coords[count++] = half_height;
1136                coords[count++] = baseCoordinates[base_count + 1];
1137
1138                base_count += 2;
1139            }
1140
1141            coords[count++] = baseCoordinates[0];
1142            coords[count++] = half_height;
1143            coords[count++] = baseCoordinates[1];
1144
1145            coords[count++] = 0;
1146            coords[count++] = half_height;
1147            coords[count++] = 0;
1148
1149            coords[count++] = baseCoordinates[base_count];
1150            coords[count++] = half_height;
1151            coords[count++] = baseCoordinates[base_count + 1];
1152
1153        }
1154
1155        if (useBottom) {
1156            // Bottom coordinates
1157
1158            base_count = 0;
1159
1160            for(i = facetCount; --i > 0; )
1161            {
1162                coords[count++] = baseCoordinates[base_count];
1163                coords[count++] = -half_height;
1164                coords[count++] = baseCoordinates[base_count + 1];
1165
1166                coords[count++] = 0;
1167                coords[count++] = -half_height;
1168                coords[count++] = 0;
1169
1170                coords[count++] = baseCoordinates[base_count + 2];
1171                coords[count++] = -half_height;
1172                coords[count++] = baseCoordinates[base_count + 3];
1173
1174                base_count += 2;
1175            }
1176
1177            // bottom coords
1178            coords[count++] = baseCoordinates[base_count];
1179            coords[count++] = -half_height;
1180            coords[count++] = baseCoordinates[base_count + 1];
1181
1182            coords[count++] = 0;
1183            coords[count++] = -half_height;
1184            coords[count++] = 0;
1185
1186            coords[count++] = baseCoordinates[0];
1187            coords[count++] = -half_height;
1188            coords[count++] = baseCoordinates[1];
1189        }
1190    }
1191
1192    /**
1193     * Generates new set of unindexed points for triangles strips. The array
1194     * consists of the side coordinates as one strip with the top and bottom
1195     * as separate strips.
1196     *
1197     * @param data The data to base the calculations on
1198     * @throws InvalidArraySizeException The array is not big enough to contain
1199     *   the requested geometry
1200     */
1201    private void generateUnindexedTriStripCoordinates(GeometryData data)
1202        throws InvalidArraySizeException
1203    {
1204        int vtx_cnt = 0;
1205
1206        if (useSide)
1207            vtx_cnt = (facetCount + 1) * 2;
1208
1209        if(useTop)
1210            vtx_cnt += (facetCount + 1) * 2;
1211
1212        if(useBottom)
1213            vtx_cnt += (facetCount + 1) * 2;
1214
1215        if(data.coordinates == null)
1216            data.coordinates = new float[vtx_cnt * 3];
1217        else if(data.coordinates.length < vtx_cnt * 3)
1218            throw new InvalidArraySizeException("Coordinates",
1219                                                data.coordinates.length,
1220                                                vtx_cnt * 3);
1221
1222        float[] coords = data.coordinates;
1223        data.vertexCount = vtx_cnt;
1224        float half_height = cylinderHeight / 2;
1225
1226        regenerateBase();
1227
1228        int i;
1229        int count = 0;
1230        int base_count = 0;
1231
1232        if (useSide)
1233        {
1234            // The side is one big strip
1235            for(i = facetCount; --i >= 0; )
1236            {
1237                coords[count++] = baseCoordinates[base_count];
1238                coords[count++] = half_height;
1239                coords[count++] = baseCoordinates[base_count + 1];
1240
1241                coords[count++] = baseCoordinates[base_count];
1242                coords[count++] = -half_height;
1243                coords[count++] = baseCoordinates[base_count + 1];
1244
1245                base_count += 2;
1246            }
1247
1248            coords[count++] = baseCoordinates[0];
1249            coords[count++] = half_height;
1250            coords[count++] = baseCoordinates[1];
1251
1252            coords[count++] = baseCoordinates[0];
1253            coords[count++] = -half_height;
1254            coords[count++] = baseCoordinates[1];
1255        }
1256
1257        if(useTop)
1258        {
1259            // Do the top face as one strip
1260            base_count = 0;
1261            for(i = facetCount; --i >= 0; )
1262            {
1263                coords[count++] = 0;
1264                coords[count++] = half_height;
1265                coords[count++] = 0;
1266
1267                coords[count++] = baseCoordinates[base_count++];
1268                coords[count++] = half_height;
1269                coords[count++] = baseCoordinates[base_count++];
1270            }
1271
1272            coords[count++] = 0;
1273            coords[count++] = half_height;
1274            coords[count++] = 0;
1275
1276            coords[count++] = baseCoordinates[0];
1277            coords[count++] = half_height;
1278            coords[count++] = baseCoordinates[1];
1279        }
1280
1281        if (useBottom)
1282        {
1283            // Now the bottom face as one fan. Must wind it backwards compared
1284            // to the top.
1285            base_count = 0;
1286            for(i = facetCount; --i >= 0; )
1287            {
1288                coords[count++] = baseCoordinates[base_count++];
1289                coords[count++] = -half_height;
1290                coords[count++] = baseCoordinates[base_count++];
1291
1292                coords[count++] = 0;
1293                coords[count++] = -half_height;
1294                coords[count++] = 0;
1295            }
1296
1297            coords[count++] = baseCoordinates[0];
1298            coords[count++] = -half_height;
1299            coords[count++] = baseCoordinates[1];
1300
1301            coords[count++] = 0;
1302            coords[count++] = -half_height;
1303            coords[count++] = 0;
1304        }
1305    }
1306
1307    /**
1308     * Generates new set of unindexed points for triangle fans. For each
1309     * facet on the side we have one fan. For each end there is a single
1310     * fan.
1311     *
1312     * @param data The data to base the calculations on
1313     * @throws InvalidArraySizeException The array is not big enough to contain
1314     *   the requested geometry
1315     */
1316    private void generateUnindexedTriFanCoordinates(GeometryData data)
1317        throws InvalidArraySizeException
1318    {
1319        int vtx_cnt = 0;
1320
1321        if (useSide)
1322            vtx_cnt = facetCount * 4;
1323
1324        if(useTop)
1325            vtx_cnt += (facetCount + 2);
1326
1327        if(useBottom)
1328            vtx_cnt += (facetCount + 2);
1329
1330        if(data.coordinates == null)
1331            data.coordinates = new float[vtx_cnt * 3];
1332        else if(data.coordinates.length < vtx_cnt * 3)
1333            throw new InvalidArraySizeException("Coordinates",
1334                                                data.coordinates.length,
1335                                                vtx_cnt * 3);
1336
1337        float[] coords = data.coordinates;
1338        data.vertexCount = vtx_cnt;
1339
1340        regenerateBase();
1341
1342        int count = 0;
1343        int i = 0;
1344        int base_count = 0;
1345        float half_height = cylinderHeight / 2;
1346
1347        if (useSide)
1348        {
1349            for(i = facetCount; --i > 0; )
1350            {
1351                //side coords triangle 1
1352                coords[count++] = baseCoordinates[base_count];
1353                coords[count++] = half_height;
1354                coords[count++] = baseCoordinates[base_count + 1];
1355
1356                coords[count++] = baseCoordinates[base_count];
1357                coords[count++] = -half_height;
1358                coords[count++] = baseCoordinates[base_count + 1];
1359
1360                coords[count++] = baseCoordinates[base_count + 2];
1361                coords[count++] = -half_height;
1362                coords[count++] = baseCoordinates[base_count + 3];
1363
1364                coords[count++] = baseCoordinates[base_count + 2];
1365                coords[count++] = half_height;
1366                coords[count++] = baseCoordinates[base_count + 3];
1367
1368                base_count += 2;
1369            }
1370
1371            coords[count++] = baseCoordinates[base_count];
1372            coords[count++] = half_height;
1373            coords[count++] = baseCoordinates[base_count + 1];
1374
1375            coords[count++] = baseCoordinates[base_count];
1376            coords[count++] = -half_height;
1377            coords[count++] = baseCoordinates[base_count + 1];
1378
1379            coords[count++] = baseCoordinates[0];
1380            coords[count++] = -half_height;
1381            coords[count++] = baseCoordinates[1];
1382
1383            coords[count++] = baseCoordinates[0];
1384            coords[count++] = half_height;
1385            coords[count++] = baseCoordinates[1];
1386        }
1387
1388        if(useTop)
1389        {
1390            base_count = 0;
1391
1392            coords[count++] = 0;
1393            coords[count++] = half_height;
1394            coords[count++] = 0;
1395
1396            // Top coordinates
1397            for(i = facetCount; --i >= 0; )
1398            {
1399                coords[count++] = baseCoordinates[base_count++];
1400                coords[count++] = half_height;
1401                coords[count++] = baseCoordinates[base_count++];
1402            }
1403
1404            coords[count++] = baseCoordinates[0];
1405            coords[count++] = half_height;
1406            coords[count++] = baseCoordinates[1];
1407
1408        }
1409        if (useBottom)
1410        {
1411            // Bottom coordinates wound in reverse order
1412            base_count = numBaseValues - 1;
1413
1414            coords[count++] = 0;
1415            coords[count++] = -half_height;
1416            coords[count++] = 0;
1417
1418            for(i = facetCount; --i >= 0; )
1419            {
1420                coords[count++] = baseCoordinates[base_count - 1];
1421                coords[count++] = -half_height;
1422                coords[count++] = baseCoordinates[base_count];
1423
1424                base_count -= 2;
1425            }
1426
1427            // bottom coords
1428            coords[count++] = baseCoordinates[numBaseValues - 2];
1429            coords[count++] = -half_height;
1430            coords[count++] = baseCoordinates[numBaseValues - 1];
1431        }
1432    }
1433
1434    /**
1435     * Generates new set of unindexed points for quads. The array consists
1436     * of the side coordinates, followed by the top and bottom.
1437     *
1438     * @param data The data to base the calculations on
1439     * @throws InvalidArraySizeException The array is not big enough to contain
1440     *   the requested geometry
1441     */
1442    private void generateUnindexedQuadCoordinates(GeometryData data)
1443        throws InvalidArraySizeException
1444    {
1445        int vtx_cnt = 0;
1446
1447        if (useSide)
1448             vtx_cnt = facetCount * 4;
1449
1450        if(useTop)
1451            vtx_cnt += facetCount * 4;
1452
1453        if(useBottom)
1454            vtx_cnt += facetCount * 4;
1455
1456        if(data.coordinates == null)
1457            data.coordinates = new float[vtx_cnt * 3];
1458        else if(data.coordinates.length < vtx_cnt * 3)
1459            throw new InvalidArraySizeException("Coordinates",
1460                                                data.coordinates.length,
1461                                                vtx_cnt * 3);
1462
1463        float[] coords = data.coordinates;
1464        data.vertexCount = vtx_cnt;
1465
1466        regenerateBase();
1467
1468        int count = 0;
1469        int i = 0;
1470        int base_count = 0;
1471        float half_height = cylinderHeight / 2;
1472
1473        if (useSide)
1474        {
1475            for(i = facetCount; --i > 0; )
1476            {
1477                //side coords triangle 1
1478                coords[count++] = baseCoordinates[base_count];
1479                coords[count++] = -half_height;
1480                coords[count++] = baseCoordinates[base_count + 1];
1481
1482                coords[count++] = baseCoordinates[base_count + 2];
1483                coords[count++] = -half_height;
1484                coords[count++] = baseCoordinates[base_count + 3];
1485
1486                coords[count++] = baseCoordinates[base_count + 2];
1487                coords[count++] = half_height;
1488                coords[count++] = baseCoordinates[base_count + 3];
1489
1490                coords[count++] = baseCoordinates[base_count];
1491                coords[count++] = half_height;
1492                coords[count++] = baseCoordinates[base_count + 1];
1493
1494                base_count += 2;
1495            }
1496
1497            coords[count++] = baseCoordinates[base_count];
1498            coords[count++] = -half_height;
1499            coords[count++] = baseCoordinates[base_count + 1];
1500
1501            coords[count++] = baseCoordinates[0];
1502            coords[count++] = -half_height;
1503            coords[count++] = baseCoordinates[1];
1504
1505            coords[count++] = baseCoordinates[0];
1506            coords[count++] = half_height;
1507            coords[count++] = baseCoordinates[1];
1508
1509            coords[count++] = baseCoordinates[base_count];
1510            coords[count++] = half_height;
1511            coords[count++] = baseCoordinates[base_count + 1];
1512        }
1513
1514        if(useTop)
1515        {
1516            base_count = 0;
1517
1518            // Top coordinates
1519            for(i = facetCount; --i > 0; )
1520            {
1521                coords[count++] = baseCoordinates[base_count + 2];
1522                coords[count++] = half_height;
1523                coords[count++] = baseCoordinates[base_count + 3];
1524
1525                coords[count++] = 0;
1526                coords[count++] = half_height;
1527                coords[count++] = 0;
1528
1529                coords[count++] = 0;
1530                coords[count++] = half_height;
1531                coords[count++] = 0;
1532
1533                coords[count++] = baseCoordinates[base_count];
1534                coords[count++] = half_height;
1535                coords[count++] = baseCoordinates[base_count + 1];
1536
1537                base_count += 2;
1538            }
1539
1540            coords[count++] = baseCoordinates[0];
1541            coords[count++] = half_height;
1542            coords[count++] = baseCoordinates[1];
1543
1544            coords[count++] = 0;
1545            coords[count++] = half_height;
1546            coords[count++] = 0;
1547
1548            coords[count++] = 0;
1549            coords[count++] = half_height;
1550            coords[count++] = 0;
1551
1552            coords[count++] = baseCoordinates[base_count];
1553            coords[count++] = half_height;
1554            coords[count++] = baseCoordinates[base_count + 1];
1555
1556        }
1557        if (useBottom)
1558        {
1559            // Bottom coordinates
1560
1561            base_count = 0;
1562
1563            for(i = facetCount; --i > 0; )
1564            {
1565                coords[count++] = baseCoordinates[base_count];
1566                coords[count++] = -half_height;
1567                coords[count++] = baseCoordinates[base_count + 1];
1568
1569                coords[count++] = 0;
1570                coords[count++] = -half_height;
1571                coords[count++] = 0;
1572
1573                coords[count++] = 0;
1574                coords[count++] = -half_height;
1575                coords[count++] = 0;
1576
1577                coords[count++] = baseCoordinates[base_count + 2];
1578                coords[count++] = -half_height;
1579                coords[count++] = baseCoordinates[base_count + 3];
1580
1581                base_count += 2;
1582            }
1583
1584            // bottom coords
1585            coords[count++] = baseCoordinates[base_count];
1586            coords[count++] = -half_height;
1587            coords[count++] = baseCoordinates[base_count + 1];
1588
1589            coords[count++] = 0;
1590            coords[count++] = -half_height;
1591            coords[count++] = 0;
1592
1593            coords[count++] = 0;
1594            coords[count++] = -half_height;
1595            coords[count++] = 0;
1596
1597            coords[count++] = baseCoordinates[0];
1598            coords[count++] = -half_height;
1599            coords[count++] = baseCoordinates[1];
1600        }
1601    }
1602
1603    /**
1604     * Generates new set of indexed points for triangles or quads. The array
1605     * consists of the side coordinates, followed by the center for top, then
1606     * its points then the bottom center and its points. We do this as they
1607     * use a completely different set of normals. The side
1608     * coordinates are interleved as top and then bottom values.
1609     *
1610     * @param data The data to base the calculations on
1611     * @throws InvalidArraySizeException The array is not big enough to contain
1612     *   the requested geometry
1613     */
1614    private void generateIndexedCoordinates(GeometryData data)
1615        throws InvalidArraySizeException
1616    {
1617        int vtx_cnt = 0;
1618
1619        if (useSide)
1620            vtx_cnt = facetCount * 2;
1621
1622        if(useTop)
1623            vtx_cnt += 1 + facetCount;
1624
1625        if(useBottom)
1626            vtx_cnt += 1 + facetCount;
1627
1628        if(data.coordinates == null)
1629            data.coordinates = new float[vtx_cnt * 3];
1630        else if(data.coordinates.length < vtx_cnt * 3)
1631            throw new InvalidArraySizeException("Coordinates",
1632                                                data.coordinates.length,
1633                                                vtx_cnt * 3);
1634
1635        float[] coords = data.coordinates;
1636        data.vertexCount = vtx_cnt;
1637
1638        regenerateBase();
1639
1640        int count = 0;
1641        int i = 0;
1642        int base_count = 0;
1643        float half_height = cylinderHeight / 2;
1644
1645        if (useSide)
1646        {
1647            for(i = facetCount; --i >=0; )
1648            {
1649                coords[count++] = baseCoordinates[base_count];
1650                coords[count++] = half_height;
1651                coords[count++] = baseCoordinates[base_count + 1];
1652
1653                coords[count++] = baseCoordinates[base_count];
1654                coords[count++] = -half_height;
1655                coords[count++] = baseCoordinates[base_count + 1];
1656
1657                base_count += 2;
1658            }
1659        }
1660
1661        if(useTop)
1662        {
1663            coords[count++] = 0;
1664            coords[count++] = half_height;
1665            coords[count++] = 0;
1666
1667            base_count = 0;
1668
1669            for(i = facetCount; --i >= 0; )
1670            {
1671                coords[count++] = baseCoordinates[base_count++];
1672                coords[count++] = half_height;
1673                coords[count++] = baseCoordinates[base_count++];
1674            }
1675
1676        }
1677
1678        if (useBottom)
1679        {
1680            base_count = 0;
1681
1682            coords[count++] = 0;
1683            coords[count++] = -half_height;
1684            coords[count++] = 0;
1685
1686            for(i = facetCount; --i >= 0; )
1687            {
1688                coords[count++] = baseCoordinates[base_count++];
1689                coords[count++] = -half_height;
1690                coords[count++] = baseCoordinates[base_count++];
1691            }
1692        }
1693    }
1694
1695    //------------------------------------------------------------------------
1696    // Normal generation routines
1697    //------------------------------------------------------------------------
1698
1699    /**
1700     * Generate a new set of normals for a normal set of unindexed points.
1701     * Smooth normals are used for the sides at the average between the faces.
1702     * Bottom normals always point down.
1703     * <p>
1704     * This must always be called after the coordinate generation.
1705     *
1706     * @param data The data to base the calculations on
1707     * @throws InvalidArraySizeException The array is not big enough to contain
1708     *   the requested geometry
1709     */
1710    private void generateUnindexedTriNormals(GeometryData data)
1711        throws InvalidArraySizeException
1712    {
1713        int vtx_cnt = data.vertexCount * 3;
1714
1715        if(data.normals == null)
1716            data.normals = new float[vtx_cnt];
1717        else if(data.normals.length < vtx_cnt)
1718            throw new InvalidArraySizeException("Normals",
1719                                                data.normals.length,
1720                                                vtx_cnt);
1721
1722        int i;
1723        float[] normals = data.normals;
1724        int count = 0;
1725        int vtx = 0;
1726
1727        if (useSide)
1728        {
1729            createRadialFlatNormal(vtx++);
1730
1731            for(i = facetCount; --i > 0; )
1732            {
1733                normals[count++] = normal.x;
1734                normals[count++] = normal.y;
1735                normals[count++] = normal.z;
1736
1737                normals[count + 9] = normal.x;
1738                normals[count + 10] = normal.y;
1739                normals[count + 11] = normal.z;
1740
1741                normals[count + 12] = normal.x;
1742                normals[count + 13] = normal.y;
1743                normals[count + 14] = normal.z;
1744
1745                createRadialFlatNormal(vtx++);
1746
1747                normals[count++] = normal.x;
1748                normals[count++] = normal.y;
1749                normals[count++] = normal.z;
1750
1751                normals[count++] = normal.x;
1752                normals[count++] = normal.y;
1753                normals[count++] = normal.z;
1754
1755                normals[count++] = normal.x;
1756                normals[count++] = normal.y;
1757                normals[count++] = normal.z;
1758
1759                count += 6;
1760            }
1761
1762            normals[count++] = normal.x;
1763            normals[count++] = normal.y;
1764            normals[count++] = normal.z;
1765
1766            normals[count + 9] = normal.x;
1767            normals[count + 10] = normal.y;
1768            normals[count + 11] = normal.z;
1769
1770            normals[count + 12] = normal.x;
1771            normals[count + 13] = normal.y;
1772            normals[count + 14] = normal.z;
1773
1774            createRadialFlatNormal(0);
1775
1776            normals[count++] = normal.x;
1777            normals[count++] = normal.y;
1778            normals[count++] = normal.z;
1779
1780            normals[count++] = normal.x;
1781            normals[count++] = normal.y;
1782            normals[count++] = normal.z;
1783
1784            normals[count++] = normal.x;
1785            normals[count++] = normal.y;
1786            normals[count++] = normal.z;
1787
1788            count += 6;
1789        }
1790
1791        // Now generate the top if we need it.
1792        if(useTop)
1793        {
1794            // The three vertices of the top in an unrolled loop
1795            for(i = facetCount; --i >= 0; )
1796            {
1797                normals[count++] = 0;
1798                normals[count++] = 1;
1799                normals[count++] = 0;
1800
1801                normals[count++] = 0;
1802                normals[count++] = 1;
1803                normals[count++] = 0;
1804
1805                normals[count++] = 0;
1806                normals[count++] = 1;
1807                normals[count++] = 0;
1808            }
1809
1810        }
1811
1812        if (useBottom)
1813        {
1814            // The three vertices of the bottom in an unrolled loop
1815            for(i = facetCount; --i >= 0; )
1816            {
1817                normals[count++] = 0;
1818                normals[count++] = -1;
1819                normals[count++] = 0;
1820
1821                normals[count++] = 0;
1822                normals[count++] = -1;
1823                normals[count++] = 0;
1824
1825                normals[count++] = 0;
1826                normals[count++] = -1;
1827                normals[count++] = 0;
1828            }
1829        }
1830    }
1831
1832    /**
1833     * Generate a new set of normals for a normal set of unindexed points.
1834     * Smooth normals are used for the sides at the average between the faces.
1835     * Bottom normals always point down.
1836     * <p>
1837     * This must always be called after the coordinate generation.
1838     *
1839     * @param data The data to base the calculations on
1840     * @throws InvalidArraySizeException The array is not big enough to contain
1841     *   the requested geometry
1842     */
1843    private void generateUnindexedTriStripNormals(GeometryData data)
1844        throws InvalidArraySizeException
1845    {
1846        int vtx_cnt = data.vertexCount * 3;
1847
1848        if(data.normals == null)
1849            data.normals = new float[vtx_cnt];
1850        else if(data.normals.length < vtx_cnt)
1851            throw new InvalidArraySizeException("Normals",
1852                                                data.normals.length,
1853                                                vtx_cnt);
1854
1855        int i;
1856        float[] normals = data.normals;
1857        int count = 0;
1858        int vtx = 0;
1859
1860        if (useSide)
1861        {
1862            for(i = facetCount; --i >= 0; )
1863            {
1864                createRadialFlatNormal(vtx++);
1865
1866                normals[count++] = normal.x;
1867                normals[count++] = normal.y;
1868                normals[count++] = normal.z;
1869
1870                normals[count++] = normal.x;
1871                normals[count++] = normal.y;
1872                normals[count++] = normal.z;
1873            }
1874
1875            // Last row of the facets is the same as the first items
1876            normals[count++] = normals[0];
1877            normals[count++] = normals[1];
1878            normals[count++] = normals[2];
1879
1880            normals[count++] = normals[3];
1881            normals[count++] = normals[4];
1882            normals[count++] = normals[5];
1883        }
1884
1885        // Now generate the top if we need it.
1886        if(useTop)
1887        {
1888            // The vertices of the top
1889            for(i = facetCount + 1; --i >= 0; )
1890            {
1891                normals[count++] = 0;
1892                normals[count++] = 1;
1893                normals[count++] = 0;
1894
1895                normals[count++] = 0;
1896                normals[count++] = 1;
1897                normals[count++] = 0;
1898            }
1899
1900        }
1901
1902        if (useBottom)
1903        {
1904            // The vertices of the bottom
1905            for(i = facetCount + 1; --i >= 0; )
1906            {
1907                normals[count++] = 0;
1908                normals[count++] = -1;
1909                normals[count++] = 0;
1910
1911                normals[count++] = 0;
1912                normals[count++] = -1;
1913                normals[count++] = 0;
1914            }
1915        }
1916    }
1917
1918    /**
1919     * Generate a new set of normals for a normal set of unindexed triangle
1920     * fan points. Smooth normals are used for the sides at the average
1921     * between the faces. Bottom normals always point down.
1922     * <p>
1923     * This must always be called after the coordinate generation.
1924     *
1925     * @param data The data to base the calculations on
1926     * @throws InvalidArraySizeException The array is not big enough to contain
1927     *   the requested geometry
1928     */
1929    private void generateUnindexedTriFanNormals(GeometryData data)
1930        throws InvalidArraySizeException
1931    {
1932        int vtx_cnt = data.vertexCount * 3;
1933
1934        if(data.normals == null)
1935            data.normals = new float[vtx_cnt];
1936        else if(data.normals.length < vtx_cnt)
1937            throw new InvalidArraySizeException("Normals",
1938                                                data.normals.length,
1939                                                vtx_cnt);
1940
1941        int i;
1942        float[] normals = data.normals;
1943        int count = 0;
1944        int vtx = 0;
1945
1946        if (useSide) {
1947            createRadialFlatNormal(vtx++);
1948
1949            for(i = facetCount; --i > 0; )
1950            {
1951                normals[count++] = normal.x;
1952                normals[count++] = normal.y;
1953                normals[count++] = normal.z;
1954
1955                normals[count++] = normal.x;
1956                normals[count++] = normal.y;
1957                normals[count++] = normal.z;
1958
1959                createRadialFlatNormal(vtx++);
1960
1961                normals[count++] = normal.x;
1962                normals[count++] = normal.y;
1963                normals[count++] = normal.z;
1964
1965                normals[count++] = normal.x;
1966                normals[count++] = normal.y;
1967                normals[count++] = normal.z;
1968            }
1969
1970            normals[count++] = normal.x;
1971            normals[count++] = normal.y;
1972            normals[count++] = normal.z;
1973
1974            normals[count++] = normal.x;
1975            normals[count++] = normal.y;
1976            normals[count++] = normal.z;
1977
1978            normals[count++] = normals[0];
1979            normals[count++] = normals[1];
1980            normals[count++] = normals[2];
1981
1982            normals[count++] = normals[3];
1983            normals[count++] = normals[4];
1984            normals[count++] = normals[5];
1985        }
1986
1987        // Now generate the bottom if we need it.
1988        if(useTop)
1989        {
1990            // The three vertices of the top in an unrolled loop
1991            for(i = facetCount + 2; --i >= 0; )
1992            {
1993                normals[count++] = 0;
1994                normals[count++] = 1;
1995                normals[count++] = 0;
1996            }
1997
1998        }
1999        if (useBottom)
2000        {
2001            // The three vertices of the bottom in an unrolled loop
2002            for(i = facetCount + 2; --i >= 0; )
2003            {
2004                normals[count++] = 0;
2005                normals[count++] = -1;
2006                normals[count++] = 0;
2007            }
2008        }
2009    }
2010
2011    /**
2012     * Generate a new set of normals for a normal set of unindexed points.
2013     * Smooth normals are used for the sides at the average between the faces.
2014     * Bottom normals always point down.
2015     * <p>
2016     * This must always be called after the coordinate generation.
2017     *
2018     * @param data The data to base the calculations on
2019     * @throws InvalidArraySizeException The array is not big enough to contain
2020     *   the requested geometry
2021     */
2022    private void generateUnindexedQuadNormals(GeometryData data)
2023        throws InvalidArraySizeException
2024    {
2025        int vtx_cnt = data.vertexCount * 3;
2026
2027        if(data.normals == null)
2028            data.normals = new float[vtx_cnt];
2029        else if(data.normals.length < vtx_cnt)
2030            throw new InvalidArraySizeException("Normals",
2031                                                data.normals.length,
2032                                                vtx_cnt);
2033
2034        int i;
2035        float[] normals = data.normals;
2036        int count = 0;
2037        int vtx = 0;
2038
2039        if (useSide)
2040        {
2041            createRadialFlatNormal(vtx++);
2042
2043            for(i = facetCount; --i > 0; )
2044            {
2045                normals[count++] = normal.x;
2046                normals[count++] = normal.y;
2047                normals[count++] = normal.z;
2048
2049                normals[count + 6] = normal.x;
2050                normals[count + 7] = normal.y;
2051                normals[count + 8] = normal.z;
2052
2053                createRadialFlatNormal(vtx++);
2054
2055                normals[count++] = normal.x;
2056                normals[count++] = normal.y;
2057                normals[count++] = normal.z;
2058
2059                normals[count++] = normal.x;
2060                normals[count++] = normal.y;
2061                normals[count++] = normal.z;
2062
2063                count += 3;
2064            }
2065
2066            normals[count++] = normal.x;
2067            normals[count++] = normal.y;
2068            normals[count++] = normal.z;
2069
2070            normals[count + 6] = normal.x;
2071            normals[count + 7] = normal.y;
2072            normals[count + 8] = normal.z;
2073
2074            createRadialFlatNormal(0);
2075
2076            normals[count++] = normal.x;
2077            normals[count++] = normal.y;
2078            normals[count++] = normal.z;
2079
2080            normals[count++] = normal.x;
2081            normals[count++] = normal.y;
2082            normals[count++] = normal.z;
2083
2084            count += 3;
2085        }
2086
2087        // Now generate the top if we need it.
2088        if(useTop)
2089        {
2090            // The three vertices of the top in an unrolled loop
2091            for(i = facetCount; --i >= 0; )
2092            {
2093                normals[count++] = 0;
2094                normals[count++] = 1;
2095                normals[count++] = 0;
2096
2097                normals[count++] = 0;
2098                normals[count++] = 1;
2099                normals[count++] = 0;
2100
2101                normals[count++] = 0;
2102                normals[count++] = 1;
2103                normals[count++] = 0;
2104
2105                normals[count++] = 0;
2106                normals[count++] = 1;
2107                normals[count++] = 0;
2108            }
2109
2110        }
2111        if (useBottom)
2112        {
2113            // The three vertices of the bottom in an unrolled loop
2114            for(i = facetCount; --i >= 0; )
2115            {
2116                normals[count++] = 0;
2117                normals[count++] = -1;
2118                normals[count++] = 0;
2119
2120                normals[count++] = 0;
2121                normals[count++] = -1;
2122                normals[count++] = 0;
2123
2124                normals[count++] = 0;
2125                normals[count++] = -1;
2126                normals[count++] = 0;
2127
2128                normals[count++] = 0;
2129                normals[count++] = -1;
2130                normals[count++] = 0;
2131            }
2132        }
2133    }
2134
2135    /**
2136     * Generate a new set of normals for a normal set of indexed points.
2137     * Smooth normals are used for the sides at the average between the faces.
2138     * Bottom normals always point down.
2139     * <p>
2140     * This must always be called after the coordinate generation.
2141     *
2142     * @param data The data to base the calculations on
2143     * @throws InvalidArraySizeException The array is not big enough to contain
2144     *   the requested geometry
2145     */
2146    private void generateIndexedNormals(GeometryData data)
2147        throws InvalidArraySizeException
2148    {
2149        int vtx_cnt = data.vertexCount * 3;
2150
2151        if(data.normals == null)
2152            data.normals = new float[vtx_cnt];
2153        else if(data.normals.length < vtx_cnt)
2154            throw new InvalidArraySizeException("Normals",
2155                                                data.normals.length,
2156                                                vtx_cnt);
2157
2158        int i;
2159        float[] normals = data.normals;
2160        int count = 0;
2161        int vtx = 0;
2162
2163        if (useSide)
2164        {
2165            for(i = facetCount; --i >= 0; )
2166            {
2167                createRadialFlatNormal(vtx++);
2168
2169                normals[count++] = normal.x;
2170                normals[count++] = normal.y;
2171                normals[count++] = normal.z;
2172
2173                normals[count++] = normal.x;
2174                normals[count++] = normal.y;
2175                normals[count++] = normal.z;
2176            }
2177        }
2178
2179        // Now generate the top if we need it.
2180        if(useTop)
2181        {
2182            // top
2183            for(i = facetCount + 1; --i >= 0; )
2184            {
2185                normals[count++] = 0;
2186                normals[count++] = 1;
2187                normals[count++] = 0;
2188            }
2189
2190        }
2191        if (useBottom)
2192        {
2193            // bottom
2194            for(i = facetCount + 1; --i >= 0; )
2195            {
2196                normals[count++] = 0;
2197                normals[count++] = -1;
2198                normals[count++] = 0;
2199            }
2200        }
2201    }
2202
2203    //------------------------------------------------------------------------
2204    // Texture coordinate generation routines
2205    //------------------------------------------------------------------------
2206
2207    /**
2208     * Generate a new set of texCoords for a normal set of unindexed points. Each
2209     * normal faces directly perpendicular for each point. This makes each face
2210     * seem flat.
2211     * <p>
2212     * This must always be called after the coordinate generation.
2213     *
2214     * @param data The data to base the calculations on
2215     * @throws InvalidArraySizeException The array is not big enough to contain
2216     *   the requested geometry
2217     */
2218    private void generateTriTexture2D(GeometryData data)
2219        throws InvalidArraySizeException
2220    {
2221        int vtx_cnt = data.vertexCount * 2;
2222
2223        if(data.textureCoordinates == null)
2224            data.textureCoordinates = new float[vtx_cnt];
2225        else if(data.textureCoordinates.length < vtx_cnt)
2226            throw new InvalidArraySizeException("2D Texture coordinates",
2227                                                data.textureCoordinates.length,
2228                                                vtx_cnt);
2229
2230        recalc2DTexture();
2231
2232        System.arraycopy(texCoordinates2D, 0, data.textureCoordinates, 0, vtx_cnt);
2233        float[] texCoords = data.textureCoordinates;
2234    }
2235
2236    /**
2237     * Generate a new set of texCoords for a normal set of unindexed points. Each
2238     * normal faces directly perpendicular for each point. This makes each face
2239     * seem flat.
2240     * <p>
2241     * This must always be called after the coordinate generation.
2242     *
2243     * @param data The data to base the calculations on
2244     * @throws InvalidArraySizeException The array is not big enough to contain
2245     *   the requested geometry
2246     */
2247    private void generateTriTexture3D(GeometryData data)
2248        throws InvalidArraySizeException
2249    {
2250        int vtx_cnt = data.vertexCount * 2;
2251
2252        if(data.textureCoordinates == null)
2253            data.textureCoordinates = new float[vtx_cnt];
2254        else if(data.textureCoordinates.length < vtx_cnt)
2255            throw new InvalidArraySizeException("3D Texture coordinates",
2256                                                data.textureCoordinates.length,
2257                                                vtx_cnt);
2258
2259        float[] texCoords = data.textureCoordinates;
2260    }
2261
2262    /**
2263     * Regenerate the base coordinate points. These are the flat circle that
2264     * makes up the base of the code. The coordinates are generated based on
2265     * the 2 PI divided by the number of facets to generate.
2266     */
2267    private final void regenerateBase()
2268    {
2269        if(!baseChanged)
2270            return;
2271
2272        baseChanged = false;
2273
2274        if((baseCoordinates == null) ||
2275           (facetCount * 2 > baseCoordinates.length))
2276        {
2277            baseCoordinates = new float[facetCount * 2];
2278        }
2279
2280        numBaseValues = facetCount * 2;
2281
2282         // local constant to make math calcs faster
2283        double segment_angle = 2.0 * Math.PI / facetCount;
2284        int count = 0;
2285        float x, z;
2286        double angle;
2287        int i;
2288        double halfCount = (Math.PI / 2 - Math.PI / (facetCount / 2));
2289
2290        // Reverse loop count because it is *much* faster than the forward
2291        // version.
2292        for(i = facetCount; --i >= 0; )
2293        {
2294            angle = segment_angle * i;
2295
2296            x = (float)(radius * Math.cos(angle - halfCount));
2297            z = (float)(radius * Math.sin(angle - halfCount));
2298
2299            baseCoordinates[count++] = x;
2300            baseCoordinates[count++] = z;
2301        }
2302    }
2303
2304    /**
2305     * Recalculate the 2D texture coordinates IAW the coordinate values. This
2306     * starts by using the circumference as a T value of 0.5 to indicate it is
2307     * halfway through the texture (we are starting at the middle of the
2308     * sphere!). Then, if we have a bottom, we calculate the T from 0 to 0.5.
2309     * thus the coordinates are for the top half of the sphere, followed by
2310     * the bottom half.
2311     */
2312    private void recalc2DTexture()
2313    {
2314        if(!facetsChanged)
2315            return;
2316
2317        // not a good idea because we should also leave this set to recalc
2318        // the 3D coordinates.
2319        facetsChanged = false;
2320        int vtx_count = 0;
2321
2322        if (useSide)
2323            vtx_count = (facetCount + 1) * 2;
2324
2325        if (useTop)
2326            vtx_count += (facetCount + 1) * 2;
2327
2328        if (useBottom)
2329            vtx_count += (facetCount + 1) * 2;
2330
2331        if((texCoordinates2D == null) ||
2332           (vtx_count * 2 > texCoordinates2D.length))
2333        {
2334            texCoordinates2D = new float[vtx_count * 2];
2335        }
2336
2337        // local constant to make math calcs faster
2338        float segment_angle = 1 / (float)facetCount;
2339        float angle = (float)(2.0 * Math.PI / facetCount);
2340
2341        int count = 0;
2342        int i, k;
2343        float s, a;
2344        float[] bottom_s = new float[facetCount + 1];
2345        float[] bottom_t = new float[facetCount + 1];
2346
2347        if (useSide)
2348        {
2349            for(i = 0; i < facetCount; i++)
2350            {
2351                s = i * segment_angle;
2352
2353                texCoordinates2D[count++] = s;
2354                texCoordinates2D[count++] = 1;
2355
2356                texCoordinates2D[count++] = s;
2357                texCoordinates2D[count++] = 0;
2358
2359                a = i * angle;
2360                bottom_s[i] = (float)(0.5f - radius * Math.cos(a) / 2);
2361                bottom_t[i] = (float)(0.5f - radius * Math.sin(a) / 2);
2362            }
2363
2364            texCoordinates2D[count++] = 1;
2365            texCoordinates2D[count++] = 1;
2366
2367            texCoordinates2D[count++] = 1;
2368            texCoordinates2D[count++] = 0;
2369        }
2370
2371        if (useTop)
2372        {
2373            bottom_s[facetCount] = bottom_s[0];
2374            bottom_t[facetCount] = bottom_t[0];
2375
2376            // top is a flat square that is based with the centre at
2377            // the centre of the cone. Start with the centre point first
2378
2379            for(i = facetCount; --i >= 0; ) {
2380                texCoordinates2D[count++] = 0.5f;
2381                texCoordinates2D[count++] = 0.5f;
2382
2383                texCoordinates2D[count++] = bottom_s[i];
2384                texCoordinates2D[count++] = bottom_t[i];
2385            }
2386
2387            texCoordinates2D[count++] = 0.5f;
2388            texCoordinates2D[count++] = 0.5f;
2389            texCoordinates2D[count++] = bottom_s[0];
2390            texCoordinates2D[count++] = bottom_t[1];
2391        }
2392
2393        if (useBottom)
2394        {
2395            // Bottom is a flat square that is based with the centre at
2396            // the centre of the cone. Start with the centre point first
2397
2398            for(i = facetCount; --i >= 0; ) {
2399                texCoordinates2D[count++] = bottom_s[i];
2400                texCoordinates2D[count++] = bottom_t[i];
2401
2402                texCoordinates2D[count++] = 0.5f;
2403                texCoordinates2D[count++] = 0.5f;
2404            }
2405
2406            texCoordinates2D[count++] = bottom_s[0];
2407            texCoordinates2D[count++] = bottom_t[1];
2408            texCoordinates2D[count++] = 0.5f;
2409            texCoordinates2D[count++] = 0.5f;
2410        }
2411
2412        numTexCoords2D = count;
2413    }
2414
2415    /**
2416     * Create a normal based on the given vertex position, assuming that it is
2417     * a point in space, relative to the origin but also ignores the Y
2418     * component. This will create a normal that points directly along the
2419     * vector from the origin to the point along the X-Z plane. Useful for
2420     * doing cones and cylinders.
2421     *
2422     * @param p The facet index of the point to calculate
2423     * @param A temporary value containing the normal value
2424     */
2425    private void createRadialFlatNormal(int p)
2426    {
2427        float x = baseCoordinates[p * 2];
2428        float z = baseCoordinates[p * 2 + 1];
2429
2430        float mag = x * x + z * z;
2431
2432        if(mag != 0.0)
2433        {
2434            mag = 1.0f / ((float) Math.sqrt(mag));
2435            normal.x = x * mag;
2436            normal.y = 0;
2437            normal.z = z * mag;
2438        }
2439        else
2440        {
2441            normal.x = 0;
2442            normal.y = 0;
2443            normal.z = 0;
2444        }
2445    }
2446}