1919import gov .nasa .worldwind .draw .DrawableShape ;
2020import gov .nasa .worldwind .draw .DrawableSurfaceShape ;
2121import gov .nasa .worldwind .geom .Location ;
22+ import gov .nasa .worldwind .geom .Matrix3 ;
23+ import gov .nasa .worldwind .geom .Matrix4 ;
2224import gov .nasa .worldwind .geom .Position ;
2325import gov .nasa .worldwind .geom .Range ;
2426import gov .nasa .worldwind .geom .Vec3 ;
2527import gov .nasa .worldwind .render .BasicShaderProgram ;
2628import gov .nasa .worldwind .render .BufferObject ;
29+ import gov .nasa .worldwind .render .ImageOptions ;
2730import gov .nasa .worldwind .render .RenderContext ;
31+ import gov .nasa .worldwind .render .Texture ;
2832import gov .nasa .worldwind .util .Logger ;
2933import gov .nasa .worldwind .util .Pool ;
3034import gov .nasa .worldwind .util .ShortArray ;
@@ -81,6 +85,10 @@ public class Ellipse extends AbstractShape {
8185 */
8286 protected static final int SIDE_RANGE = 2 ;
8387
88+ protected static final ImageOptions defaultInteriorImageOptions = new ImageOptions ();
89+
90+ protected static final ImageOptions defaultOutlineImageOptions = new ImageOptions ();
91+
8492 /**
8593 * Simple interval count based cache of the keys for element buffers. Element buffers are dependent only on the
8694 * number of intervals so the keys are cached here. The element buffer object itself is in the
@@ -145,12 +153,28 @@ public class Ellipse extends AbstractShape {
145153
146154 protected boolean isSurfaceShape ;
147155
156+ protected double texCoord1d ;
157+
158+ protected Vec3 texCoord2d = new Vec3 ();
159+
160+ protected Matrix3 texCoordMatrix = new Matrix3 ();
161+
162+ protected Matrix4 modelToTexCoord = new Matrix4 ();
163+
148164 protected double cameraDistance ;
149165
166+ protected Vec3 prevPoint = new Vec3 ();
167+
150168 private static Position scratchPosition = new Position ();
151169
152170 private static Vec3 scratchPoint = new Vec3 ();
153171
172+ static {
173+ defaultInteriorImageOptions .wrapMode = WorldWind .REPEAT ;
174+ defaultOutlineImageOptions .resamplingMode = WorldWind .NEAREST_NEIGHBOR ;
175+ defaultOutlineImageOptions .wrapMode = WorldWind .REPEAT ;
176+ }
177+
154178 /**
155179 * Constructs an ellipse with a null center position, and with major- and minor-radius both 0.0. This ellipse does
156180 * not display until the center position is defined and the radii are both greater than 0.0.
@@ -378,7 +402,7 @@ public Ellipse setFollowTerrain(boolean followTerrain) {
378402 * Indicates the maximum number of angular intervals that may be used to approximate this ellipse's geometry on
379403 * screen.
380404 *
381- * @return the maximum number of angular intervals
405+ * @return the number of angular intervals
382406 */
383407 public int getMaximumIntervals () {
384408 return this .maximumIntervals ;
@@ -435,6 +459,7 @@ protected void makeDrawable(RenderContext rc) {
435459 drawable = DrawableSurfaceShape .obtain (pool );
436460 drawState = ((DrawableSurfaceShape ) drawable ).drawState ;
437461 ((DrawableSurfaceShape ) drawable ).sector .set (this .boundingSector );
462+ this .cameraDistance = this .cameraDistanceGeographic (rc , this .boundingSector );
438463 } else {
439464 Pool <DrawableShape > pool = rc .getDrawablePool (DrawableShape .class );
440465 drawable = DrawableShape .obtain (pool );
@@ -498,7 +523,21 @@ protected void drawInterior(RenderContext rc, DrawShapeState drawState) {
498523 return ;
499524 }
500525
501- drawState .texture (null );
526+ // Configure the drawable to use the interior texture when drawing the interior.
527+ if (this .activeAttributes .interiorImageSource != null ) {
528+ Texture texture = rc .getTexture (this .activeAttributes .interiorImageSource );
529+ if (texture == null ) {
530+ texture = rc .retrieveTexture (this .activeAttributes .interiorImageSource , defaultInteriorImageOptions );
531+ }
532+ if (texture != null ) {
533+ double metersPerPixel = rc .pixelSizeAtDistance (this .cameraDistance );
534+ this .computeRepeatingTexCoordTransform (texture , metersPerPixel , this .texCoordMatrix );
535+ drawState .texture (texture );
536+ drawState .texCoordMatrix (this .texCoordMatrix );
537+ }
538+ } else {
539+ drawState .texture (null );
540+ }
502541
503542 // Configure the drawable to display the shape's interior.
504543 drawState .color (rc .pickMode ? this .pickColor : this .activeAttributes .interiorColor );
@@ -509,6 +548,7 @@ protected void drawInterior(RenderContext rc, DrawShapeState drawState) {
509548
510549 if (this .extrude ) {
511550 Range side = drawState .elementBuffer .ranges .get (SIDE_RANGE );
551+ drawState .texture (null );
512552 drawState .drawElements (GLES20 .GL_TRIANGLE_STRIP , side .length (),
513553 GLES20 .GL_UNSIGNED_SHORT , side .lower * 2 );
514554 }
@@ -519,7 +559,21 @@ protected void drawOutline(RenderContext rc, DrawShapeState drawState) {
519559 return ;
520560 }
521561
522- drawState .texture (null );
562+ // Configure the drawable to use the outline texture when drawing the outline.
563+ if (this .activeAttributes .outlineImageSource != null ) {
564+ Texture texture = rc .getTexture (this .activeAttributes .outlineImageSource );
565+ if (texture == null ) {
566+ texture = rc .retrieveTexture (this .activeAttributes .outlineImageSource , defaultOutlineImageOptions );
567+ }
568+ if (texture != null ) {
569+ double metersPerPixel = rc .pixelSizeAtDistance (this .cameraDistance );
570+ this .computeRepeatingTexCoordTransform (texture , metersPerPixel , this .texCoordMatrix );
571+ drawState .texture (texture );
572+ drawState .texCoordMatrix (this .texCoordMatrix );
573+ }
574+ } else {
575+ drawState .texture (null );
576+ }
523577
524578 // Configure the drawable to display the shape's outline.
525579 drawState .color (rc .pickMode ? this .pickColor : this .activeAttributes .outlineColor );
@@ -531,6 +585,9 @@ protected void drawOutline(RenderContext rc, DrawShapeState drawState) {
531585
532586 if (this .activeAttributes .drawVerticals && this .extrude ) {
533587 Range side = drawState .elementBuffer .ranges .get (SIDE_RANGE );
588+ drawState .color (rc .pickMode ? this .pickColor : this .activeAttributes .outlineColor );
589+ drawState .lineWidth (this .activeAttributes .outlineWidth );
590+ drawState .texture (null );
534591 drawState .drawElements (GLES20 .GL_LINES , side .length (),
535592 GLES20 .GL_UNSIGNED_SHORT , side .lower * 2 );
536593 }
@@ -551,6 +608,9 @@ protected void assembleGeometry(RenderContext rc) {
551608 // Determine whether the shape geometry must be assembled as Cartesian geometry or as goegraphic geometry.
552609 this .isSurfaceShape = (this .altitudeMode == WorldWind .CLAMP_TO_GROUND ) && this .followTerrain ;
553610
611+ // Compute a matrix that transforms from Cartesian coordinates to shape texture coordinates.
612+ this .determineModelToTexCoord (rc );
613+
554614 // Use the ellipse's center position as the local origin for vertex positions.
555615 if (this .isSurfaceShape ) {
556616 this .vertexOrigin .set (this .center .longitude , this .center .latitude , this .center .altitude );
@@ -563,9 +623,7 @@ protected void assembleGeometry(RenderContext rc) {
563623 int spineCount = computeNumberSpinePoints (this .activeIntervals ); // activeIntervals must be even
564624
565625 // Clear the shape's vertex array. The array will accumulate values as the shapes's geometry is assembled.
566- // Determine the offset from the top and extruded vertices
567626 this .vertexIndex = 0 ;
568- int arrayOffset = computeIndexOffset (this .activeIntervals ) * VERTEX_STRIDE ;
569627 if (this .extrude && !this .isSurfaceShape ) {
570628 this .vertexArray = new float [(this .activeIntervals * 2 + spineCount ) * VERTEX_STRIDE ];
571629 } else {
@@ -589,6 +647,8 @@ protected void assembleGeometry(RenderContext rc) {
589647 minorArcRadians = this .majorRadius / globeRadius ;
590648 }
591649
650+ // Determine the offset from the top and extruded vertices
651+ int arrayOffset = computeIndexOffset (this .activeIntervals ) * VERTEX_STRIDE ;
592652 // Setup spine radius values
593653 int spineIdx = 0 ;
594654 double [] spineRadius = new double [spineCount ];
@@ -637,7 +697,6 @@ protected static BufferObject assembleElements(int intervals) {
637697
638698 // Generate the top element buffer with spine
639699 int interiorIdx = intervals ;
640- int spinePoints = computeNumberSpinePoints (intervals );
641700 int offset = computeIndexOffset (intervals );
642701
643702 // Add the anchor leg
@@ -697,23 +756,32 @@ protected static BufferObject assembleElements(int intervals) {
697756 protected void addVertex (RenderContext rc , double latitude , double longitude , double altitude , int offset , boolean isExtrudedSkirt ) {
698757 int offsetVertexIndex = this .vertexIndex + offset ;
699758
759+ Vec3 point = rc .geographicToCartesian (latitude , longitude , altitude , this .altitudeMode , scratchPoint );
760+ Vec3 texCoord2d = this .texCoord2d .set (point ).multiplyByMatrix (this .modelToTexCoord );
761+
762+ if (this .vertexIndex == 0 ) {
763+ this .texCoord1d = 0 ;
764+ this .prevPoint .set (point );
765+ } else {
766+ this .texCoord1d += point .distanceTo (this .prevPoint );
767+ this .prevPoint .set (point );
768+ }
769+
700770 if (this .isSurfaceShape ) {
701771 this .vertexArray [this .vertexIndex ++] = (float ) (longitude - this .vertexOrigin .x );
702772 this .vertexArray [this .vertexIndex ++] = (float ) (latitude - this .vertexOrigin .y );
703773 this .vertexArray [this .vertexIndex ++] = (float ) (altitude - this .vertexOrigin .z );
704774 // reserved for future texture coordinate use
705- this .vertexArray [this .vertexIndex ++] = 0 ;
706- this .vertexArray [this .vertexIndex ++] = 0 ;
707- this .vertexArray [this .vertexIndex ++] = 0 ;
775+ this .vertexArray [this .vertexIndex ++] = ( float ) texCoord2d . x ;
776+ this .vertexArray [this .vertexIndex ++] = ( float ) texCoord2d . y ;
777+ this .vertexArray [this .vertexIndex ++] = ( float ) this . texCoord1d ;
708778 } else {
709- Vec3 point = rc .geographicToCartesian (latitude , longitude , altitude , this .altitudeMode , scratchPoint );
710779 this .vertexArray [this .vertexIndex ++] = (float ) (point .x - this .vertexOrigin .x );
711780 this .vertexArray [this .vertexIndex ++] = (float ) (point .y - this .vertexOrigin .y );
712781 this .vertexArray [this .vertexIndex ++] = (float ) (point .z - this .vertexOrigin .z );
713- // reserved for future texture coordinate use
714- this .vertexArray [this .vertexIndex ++] = 0 ;
715- this .vertexArray [this .vertexIndex ++] = 0 ;
716- this .vertexArray [this .vertexIndex ++] = 0 ;
782+ this .vertexArray [this .vertexIndex ++] = (float ) texCoord2d .x ;
783+ this .vertexArray [this .vertexIndex ++] = (float ) texCoord2d .y ;
784+ this .vertexArray [this .vertexIndex ++] = (float ) this .texCoord1d ;
717785
718786 if (isExtrudedSkirt ) {
719787 point = rc .geographicToCartesian (latitude , longitude , 0 , WorldWind .CLAMP_TO_GROUND , scratchPoint );
@@ -727,6 +795,12 @@ protected void addVertex(RenderContext rc, double latitude, double longitude, do
727795 }
728796 }
729797
798+ protected void determineModelToTexCoord (RenderContext rc ) {
799+ Vec3 point = rc .geographicToCartesian (this .center .latitude , this .center .longitude , this .center .altitude , this .altitudeMode , scratchPoint );
800+ this .modelToTexCoord = rc .globe .cartesianToLocalTransform (point .x , point .y , point .z , this .modelToTexCoord );
801+ this .modelToTexCoord .invertOrthonormal ();
802+ }
803+
730804 /**
731805 * Calculate the number of times to split the edges of the shape for geometry assembly.
732806 *
0 commit comments