66package gov .nasa .worldwind .shape ;
77
88import android .opengl .GLES20 ;
9+ import android .util .SparseArray ;
910
1011import java .nio .ByteBuffer ;
1112import java .nio .ByteOrder ;
1516import gov .nasa .worldwind .draw .DrawShapeState ;
1617import gov .nasa .worldwind .draw .DrawableSurfaceShape ;
1718import gov .nasa .worldwind .geom .Position ;
19+ import gov .nasa .worldwind .geom .Range ;
1820import gov .nasa .worldwind .geom .Vec3 ;
1921import gov .nasa .worldwind .render .BasicShaderProgram ;
2022import gov .nasa .worldwind .render .BufferObject ;
@@ -102,13 +104,9 @@ public class Ellipse extends AbstractShape {
102104
103105 protected FloatArray vertexArray = new FloatArray ();
104106
105- protected ShortArray interiorElements = new ShortArray ();
106-
107- protected ShortArray outlineElements = new ShortArray ();
108-
109107 protected Object vertexBufferKey = nextCacheKey ();
110108
111- protected Object elementBufferKey = nextCacheKey ();
109+ protected static SparseArray < ElementBufferAttributes > ELEMENT_BUFFER_ATTRIBUTES = new SparseArray <> ();
112110
113111 protected Vec3 vertexOrigin = new Vec3 ();
114112
@@ -383,9 +381,7 @@ protected void makeDrawable(RenderContext rc) {
383381
384382 if (this .mustAssembleGeometry (rc )) {
385383 this .assembleGeometry (rc );
386- this .assembleElements (rc );
387384 this .vertexBufferKey = nextCacheKey ();
388- this .elementBufferKey = nextCacheKey ();
389385 }
390386
391387 // Obtain a drawable form the render context pool.
@@ -412,19 +408,16 @@ protected void makeDrawable(RenderContext rc) {
412408 rc .putBufferObject (this .vertexBufferKey , drawState .vertexBuffer );
413409 }
414410
415- // Assemble the drawable's OpenGL element buffer object.
416- drawState .elementBuffer = rc .getBufferObject (this .elementBufferKey );
411+ // Get the attributes of the element buffer
412+ ElementBufferAttributes elementBufferAttributes = ELEMENT_BUFFER_ATTRIBUTES .get (this .intervals );
413+ drawState .elementBuffer = rc .getBufferObject (elementBufferAttributes );
417414 if (drawState .elementBuffer == null ) {
418- int size = (this .interiorElements .size () * 2 ) + (this .outlineElements .size () * 2 );
419- ShortBuffer buffer = ByteBuffer .allocateDirect (size ).order (ByteOrder .nativeOrder ()).asShortBuffer ();
420- buffer .put (this .interiorElements .array (), 0 , this .interiorElements .size ());
421- buffer .put (this .outlineElements .array (), 0 , this .outlineElements .size ());
422- drawState .elementBuffer = new BufferObject (GLES20 .GL_ELEMENT_ARRAY_BUFFER , size , buffer .rewind ());
423- rc .putBufferObject (this .elementBufferKey , drawState .elementBuffer );
415+ elementBufferAttributes = assembleElementsToCache (rc , this .intervals );
416+ drawState .elementBuffer = rc .getBufferObject (elementBufferAttributes );
424417 }
425418
426- this .drawInterior (rc , drawState );
427- this .drawOutline (rc , drawState );
419+ this .drawInterior (rc , drawState , elementBufferAttributes );
420+ this .drawOutline (rc , drawState , elementBufferAttributes );
428421
429422 // Configure the drawable according to the shape's attributes.
430423 drawState .vertexOrigin .set (this .vertexOrigin );
@@ -436,7 +429,7 @@ protected void makeDrawable(RenderContext rc) {
436429 rc .offerSurfaceDrawable (drawable , 0 /*zOrder*/ );
437430 }
438431
439- protected void drawInterior (RenderContext rc , DrawShapeState drawState ) {
432+ protected void drawInterior (RenderContext rc , DrawShapeState drawState , ElementBufferAttributes elementBufferAttrs ) {
440433 if (!this .activeAttributes .drawInterior ) {
441434 return ;
442435 }
@@ -446,11 +439,11 @@ protected void drawInterior(RenderContext rc, DrawShapeState drawState) {
446439 // Configure the drawable to display the shape's interior.
447440 drawState .color (rc .pickMode ? this .pickColor : this .activeAttributes .interiorColor );
448441 drawState .texCoordAttrib (2 /*size*/ , 12 /*offset in bytes*/ );
449- drawState .drawElements (GLES20 .GL_TRIANGLE_STRIP , this .interiorElements .size (),
450- GLES20 .GL_UNSIGNED_SHORT , 0 /*offset*/ );
442+ drawState .drawElements (GLES20 .GL_TRIANGLE_STRIP , elementBufferAttrs .interiorElements .length (),
443+ GLES20 .GL_UNSIGNED_SHORT , elementBufferAttrs . interiorElements . lower * 2 /*offset*/ );
451444 }
452445
453- protected void drawOutline (RenderContext rc , DrawShapeState drawState ) {
446+ protected void drawOutline (RenderContext rc , DrawShapeState drawState , ElementBufferAttributes elementBufferAttrs ) {
454447 if (!this .activeAttributes .drawOutline ) {
455448 return ;
456449 }
@@ -461,8 +454,8 @@ protected void drawOutline(RenderContext rc, DrawShapeState drawState) {
461454 drawState .color (rc .pickMode ? this .pickColor : this .activeAttributes .outlineColor );
462455 drawState .lineWidth (this .activeAttributes .outlineWidth );
463456 drawState .texCoordAttrib (1 /*size*/ , 20 /*offset in bytes*/ );
464- drawState .drawElements (GLES20 .GL_LINE_LOOP , this .outlineElements .size (),
465- GLES20 .GL_UNSIGNED_SHORT , this . interiorElements . size () * 2 /*offset*/ );
457+ drawState .drawElements (GLES20 .GL_LINE_LOOP , elementBufferAttrs .outlineElements .length (),
458+ GLES20 .GL_UNSIGNED_SHORT , elementBufferAttrs . outlineElements . lower * 2 /*offset*/ );
466459 }
467460
468461 protected boolean mustAssembleGeometry (RenderContext rc ) {
@@ -477,11 +470,8 @@ protected boolean mustAssembleGeometry(RenderContext rc) {
477470 }
478471
479472 protected void assembleGeometry (RenderContext rc ) {
480- // Clear the shape's vertex array and element arrays. These arrays will accumulate values as the shapes's
481- // geometry is assembled.
473+ // Clear the shape's vertex array. The array will accumulate values as the shapes's geometry is assembled.
482474 this .vertexArray .clear ();
483- this .interiorElements .clear ();
484- this .outlineElements .clear ();
485475
486476 // Use the ellipse's center position as the local origin for vertex positions.
487477 this .vertexOrigin .set (this .center .longitude , this .center .latitude , this .center .altitude );
@@ -537,39 +527,61 @@ protected void assembleGeometry(RenderContext rc) {
537527 this .boundingBox .setToUnitBox (); // Surface/geographic shape bounding box is unused
538528 }
539529
540- protected void assembleElements (RenderContext rc ) {
530+ protected static ElementBufferAttributes assembleElementsToCache (RenderContext rc , int intervals ) {
531+ // Create temporary storage for elements
532+ ShortArray interiorElements = new ShortArray ();
533+ ShortArray outlineElements = new ShortArray ();
534+
541535 // Generate the interior element buffer with spine
542- int interiorIdx = this . intervals ;
536+ int interiorIdx = intervals ;
543537 // Add the anchor leg
544- this . interiorElements .add ((short ) 0 );
545- this . interiorElements .add ((short ) 1 );
538+ interiorElements .add ((short ) 0 );
539+ interiorElements .add ((short ) 1 );
546540 // Tessellate the interior
547- for (int i = 2 ; i < this . intervals ; i ++) {
541+ for (int i = 2 ; i < intervals ; i ++) {
548542 // Add the corresponding interior spine point if this isn't the vertex following the last vertex for the
549543 // negative major axis
550- if (i != (this . intervals / 2 + 1 )) {
551- if (i > this . intervals / 2 ) {
552- this . interiorElements .add ((short ) --interiorIdx );
544+ if (i != (intervals / 2 + 1 )) {
545+ if (i > intervals / 2 ) {
546+ interiorElements .add ((short ) --interiorIdx );
553547 } else {
554- this . interiorElements .add ((short ) interiorIdx ++);
548+ interiorElements .add ((short ) interiorIdx ++);
555549 }
556550 }
557551 // Add the degenerate triangle at the negative major axis in order to flip the triangle strip back towards
558552 // the positive axis
559- if (i == this . intervals / 2 ) {
560- this . interiorElements .add ((short ) i );
553+ if (i == intervals / 2 ) {
554+ interiorElements .add ((short ) i );
561555 }
562556 // Add the exterior vertex
563- this . interiorElements .add ((short ) i );
557+ interiorElements .add ((short ) i );
564558 }
565559 // Complete the strip
566- this . interiorElements .add ((short ) --interiorIdx );
567- this . interiorElements .add ((short ) 0 );
560+ interiorElements .add ((short ) --interiorIdx );
561+ interiorElements .add ((short ) 0 );
568562
569563 // Generate the outline element buffer
570- for (int i = 0 ; i < this . intervals ; i ++) {
571- this . outlineElements .add ((short ) i );
564+ for (int i = 0 ; i < intervals ; i ++) {
565+ outlineElements .add ((short ) i );
572566 }
567+
568+ // Generate an attribute bundle for this element buffer
569+ ElementBufferAttributes elementBufferAttributes = new ElementBufferAttributes ();
570+ elementBufferAttributes .interiorElements .set (0 , interiorElements .size ());
571+ elementBufferAttributes .outlineElements .set (interiorElements .size (), interiorElements .size () + outlineElements .size ());
572+
573+ // Generate a buffer for the element
574+ int size = (interiorElements .size () * 2 ) + (outlineElements .size () * 2 );
575+ ShortBuffer buffer = ByteBuffer .allocateDirect (size ).order (ByteOrder .nativeOrder ()).asShortBuffer ();
576+ buffer .put (interiorElements .array (), 0 , interiorElements .size ());
577+ buffer .put (outlineElements .array (), 0 , outlineElements .size ());
578+ BufferObject elementBuffer = new BufferObject (GLES20 .GL_ELEMENT_ARRAY_BUFFER , size , buffer .rewind ());
579+
580+ // Cache the buffer object and attributes in the render resource cache and attribute map respectively
581+ rc .putBufferObject (elementBufferAttributes , elementBuffer );
582+ ELEMENT_BUFFER_ATTRIBUTES .put (intervals , elementBufferAttributes );
583+
584+ return elementBufferAttributes ;
573585 }
574586
575587 protected void addVertex (RenderContext rc , double latitude , double longitude , double altitude ) {
@@ -625,7 +637,30 @@ protected double computeCircumference() {
625637 @ Override
626638 protected void reset () {
627639 this .vertexArray .clear ();
628- this .interiorElements .clear ();
629- this .outlineElements .clear ();
640+ }
641+
642+ protected static class ElementBufferAttributes {
643+
644+ protected Range interiorElements = new Range ();
645+
646+ protected Range outlineElements = new Range ();
647+
648+ @ Override
649+ public boolean equals (Object o ) {
650+ if (this == o ) return true ;
651+ if (o == null || getClass () != o .getClass ()) return false ;
652+
653+ ElementBufferAttributes that = (ElementBufferAttributes ) o ;
654+
655+ if (!interiorElements .equals (that .interiorElements )) return false ;
656+ return outlineElements .equals (that .outlineElements );
657+ }
658+
659+ @ Override
660+ public int hashCode () {
661+ int result = interiorElements .hashCode ();
662+ result = 31 * result + outlineElements .hashCode ();
663+ return result ;
664+ }
630665 }
631666}
0 commit comments