Skip to content

Commit a9947ee

Browse files
committed
Implement missed Placemark label functionality.
1 parent 49080c0 commit a9947ee

File tree

4 files changed

+159
-89
lines changed

4 files changed

+159
-89
lines changed

worldwind-examples/src/main/java/gov/nasa/worldwindx/PlacemarksDemoActivity.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import gov.nasa.worldwind.BasicWorldWindowController;
3131
import gov.nasa.worldwind.PickedObject;
3232
import gov.nasa.worldwind.PickedObjectList;
33+
import gov.nasa.worldwind.WorldWind;
34+
import gov.nasa.worldwind.geom.Offset;
3335
import gov.nasa.worldwind.geom.Position;
3436
import gov.nasa.worldwind.layer.RenderableLayer;
3537
import gov.nasa.worldwind.render.ImageSource;
@@ -273,6 +275,7 @@ protected static PlacemarkAttributes createPlacemarkAttributes(Resources resourc
273275
//IconBitmapFactory factory = new IconBitmapFactory(resources, resourceId);
274276
//placemarkAttributes.setImageSource(ImageSource.fromBitmapFactory(factory)).setImageScale(scale);
275277
placemarkAttributes.setImageSource(ImageSource.fromResource(resourceId)).setImageScale(scale).setMinimumImageScale(0.5);
278+
placemarkAttributes.getLabelAttributes().setTextOffset(new Offset(WorldWind.OFFSET_PIXELS, -24, WorldWind.OFFSET_FRACTION, 0.0));
276279
return placemarkAttributes;
277280
}
278281
}
@@ -560,6 +563,8 @@ private void createPlaceIcons() {
560563
placemark.setLevelOfDetailSelector(new PlaceLevelOfDetailSelector(getResources(), place));
561564
placemark.setEyeDistanceScaling(true);
562565
placemark.setEyeDistanceScalingThreshold(PlaceLevelOfDetailSelector.LEVEL_1_DISTANCE);
566+
placemark.setLabel(place.name);
567+
placemark.setAltitudeMode(WorldWind.CLAMP_TO_GROUND);
563568

564569
// On a background thread, we can add Placemarks to a RenderableLayer that is
565570
// NOT attached to the WorldWindow. If the layer was attached to the WorldWindow

worldwind/src/main/java/gov/nasa/worldwind/render/RenderContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ public Texture getText(String text, TextAttributes attributes) {
432432
}
433433

434434
public Texture renderText(String text, TextAttributes attributes) {
435-
TextCacheKey key = new TextCacheKey().set(text, attributes);
435+
TextCacheKey key = this.scratchTextCacheKey.set(text, attributes);
436436
Texture texture = null;
437437

438438
if (text != null && attributes != null) {

worldwind/src/main/java/gov/nasa/worldwind/shape/Placemark.java

Lines changed: 152 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,21 @@ public interface LevelOfDetailSelector {
6262

6363
protected static final double DEFAULT_DEPTH_OFFSET = -0.03;
6464

65-
private static Vec3 placePoint = new Vec3();
65+
private static final Vec3 placePoint = new Vec3();
6666

67-
private static Vec3 screenPlacePoint = new Vec3();
67+
private static final Vec3 screenPlacePoint = new Vec3();
6868

69-
private static Vec3 groundPoint = new Vec3();
69+
private static final Vec3 groundPoint = new Vec3();
7070

71-
private static Vec2 offset = new Vec2();
71+
private static final Vec2 offset = new Vec2();
7272

73-
private static Matrix4 unitSquareTransform = new Matrix4();
73+
private static final Matrix4 imageTransform = new Matrix4();
7474

75-
private static Viewport screenBounds = new Viewport();
75+
private static final Matrix4 labelTransform = new Matrix4();
76+
77+
private static final Viewport imageBounds = new Viewport();
78+
79+
private static final Viewport labelBounds = new Viewport();
7680

7781
/**
7882
* The placemark's geographic position.
@@ -105,6 +109,11 @@ public interface LevelOfDetailSelector {
105109
*/
106110
protected Texture activeTexture;
107111

112+
/**
113+
* The texture associated with the label attributes, or null if the attributes specify no image.
114+
*/
115+
protected Texture labelTexture;
116+
108117
/**
109118
* The picked object ID associated with the placemark during the current render pass.
110119
*/
@@ -115,8 +124,7 @@ public interface LevelOfDetailSelector {
115124
/**
116125
* The label text to draw near the placemark.
117126
*/
118-
// TODO: implement label property
119-
// protected String label;
127+
protected String label;
120128

121129
/**
122130
* Determines whether the normal or highlighted attibutes should be used.
@@ -210,7 +218,7 @@ public Placemark(Position position, PlacemarkAttributes attributes, String name)
210218
this.setPosition(position);
211219
this.setAltitudeMode(WorldWind.ABSOLUTE);
212220
this.setDisplayName(name == null || name.isEmpty() ? "Placemark" : name);
213-
// this.setLabel(name); // TODO: call setLabel(name)
221+
//this.setLabel(name);
214222
this.attributes = attributes;
215223
this.eyeDistanceScaling = false;
216224
this.eyeDistanceScalingThreshold = DEFAULT_EYE_DISTANCE_SCALING_THRESHOLD;
@@ -257,10 +265,9 @@ public static Placemark createWithImage(Position position, ImageSource imageSour
257265
*
258266
* @return A new Placemark with a PlacemarkAttributes bundle containing TextAttributes.
259267
*/
260-
// TODO: implement createWithImageAndLabel factory method
261-
// public static Placemark createWithImageAndLabel(Position position, ImageSource imageSource, String label) {
262-
// return new Placemark(position, PlacemarkAttributes.createWithImage(imageSource), label);
263-
// }
268+
public static Placemark createWithImageAndLabel(Position position, ImageSource imageSource, String label) {
269+
return new Placemark(position, PlacemarkAttributes.createWithImage(imageSource), label);
270+
}
264271

265272
/**
266273
* Gets this placemark's geographic position.
@@ -385,15 +392,15 @@ public Placemark setLevelOfDetailSelector(LevelOfDetailSelector levelOfDetailSel
385392
this.levelOfDetailSelector = levelOfDetailSelector;
386393
return this;
387394
}
388-
/**
395+
396+
/*
389397
* Gets the text used to label this placemark on the globe.
390398
*
391399
* @return The text used to label a placemark on the globe when labels are enabled
392400
*/
393-
// TODO: implement getLabel()
394-
// public String getLabel() {
395-
// return label;
396-
// }
401+
public String getLabel() {
402+
return label;
403+
}
397404

398405
/**
399406
* Sets the text used for this placemark's label on the globe.
@@ -402,11 +409,10 @@ public Placemark setLevelOfDetailSelector(LevelOfDetailSelector levelOfDetailSel
402409
*
403410
* @return This placemark
404411
*/
405-
// TODO: implement setLabel()
406-
// public Placemark setLabel(String label) {
407-
// this.label = label;
408-
// return this;
409-
// }
412+
public Placemark setLabel(String label) {
413+
this.label = label;
414+
return this;
415+
}
410416

411417
/**
412418
* Indicates whether this placemark's size is reduced at higher eye distances. If true, this placemark's size is
@@ -749,61 +755,13 @@ protected void doRender(RenderContext rc) {
749755
// Compute the placemark icon's active texture.
750756
this.determineActiveTexture(rc);
751757

752-
// If the placemark's icon is visible, enqueue a drawable icon for processing on the OpenGL thread.
753-
WWMath.boundingRectForUnitSquare(unitSquareTransform, screenBounds);
754-
if (rc.frustum.intersectsViewport(screenBounds)) {
755-
Pool<DrawableScreenTexture> pool = rc.getDrawablePool(DrawableScreenTexture.class);
756-
DrawableScreenTexture drawable = DrawableScreenTexture.obtain(pool);
757-
this.prepareDrawableIcon(rc, drawable);
758-
rc.offerShapeDrawable(drawable, this.cameraDistance);
759-
}
760-
761-
// Release references to objects stored in the render resource cache.
762-
this.activeTexture = null;
763-
764-
// Enqueue a picked object that associates the placemark's icon and leader with its picked object ID.
765-
if (rc.pickMode && rc.drawableCount() != drawableCount) {
766-
rc.offerPickedObject(PickedObject.fromRenderable(this.pickedObjectId, this, rc.currentLayer));
767-
}
768-
}
769-
770-
/**
771-
* Determines the placemark attributes to use for the current render pass.
772-
*
773-
* @param rc the current render context
774-
*/
775-
protected void determineActiveAttributes(RenderContext rc) {
776-
if (this.highlighted && this.highlightAttributes != null) {
777-
this.activeAttributes = this.highlightAttributes;
778-
} else {
779-
this.activeAttributes = this.attributes;
780-
}
781-
}
782-
783-
/**
784-
* Determines the image texture and unit square transform to use for the current render pass.
785-
*
786-
* @param rc the current render context
787-
*/
788-
protected void determineActiveTexture(RenderContext rc) {
789-
// TODO: Refactor!
790-
if (this.activeAttributes.imageSource != null) {
791-
// Earlier in doRender(), an attempt was made to 'get' the activeTexture from the cache.
792-
// If was not found in the cache we need to retrieve a texture from the image source.
793-
if (this.activeTexture == null) {
794-
this.activeTexture = rc.retrieveTexture(this.activeAttributes.imageSource, null); // puts retrieved textures in the cache
795-
}
796-
} else {
797-
this.activeTexture = null; // there is no imageSource; draw a simple colored square
798-
}
799-
800758
// Compute an camera-position proximity scaling factor, so that distant placemarks can be scaled smaller than
801759
// nearer placemarks.
802760
double visibilityScale = this.isEyeDistanceScaling() ?
803761
Math.max(this.activeAttributes.minimumImageScale, Math.min(1, this.getEyeDistanceScalingThreshold() / this.cameraDistance)) : 1;
804762

805763
// Initialize the unit square transform to the identity matrix.
806-
unitSquareTransform.setToIdentity();
764+
imageTransform.setToIdentity();
807765

808766
// Apply the icon's translation and scale according to the image size, image offset and image scale. The image
809767
// offset is defined with its origin at the image's bottom-left corner and axes that extend up and to the right
@@ -831,34 +789,113 @@ protected void determineActiveTexture(RenderContext rc) {
831789
}
832790

833791
// Position image on screen
834-
unitSquareTransform.multiplyByTranslation(
792+
imageTransform.multiplyByTranslation(
835793
screenPlacePoint.x,
836794
screenPlacePoint.y,
837795
screenPlacePoint.z);
838796

839797
// Divide Z by 2^24 to prevent texture clipping when tilting (where 24 is depth buffer bit size).
840798
// Doing so will limit depth range to (diagonal length)/2^24 and make its value within 0..1 range.
841-
unitSquareTransform.multiplyByScale(1, 1, 1d / (1 << 24) );
799+
imageTransform.multiplyByScale(1, 1, 1d / (1 << 24) );
842800

843801
// Perform the tilt so that the image tilts back from its base into the view volume
844802
if (this.imageTilt != 0) {
845-
double tilt = this.imageTiltReference == WorldWind.RELATIVE_TO_GLOBE ?
803+
double actualTilt = this.imageTiltReference == WorldWind.RELATIVE_TO_GLOBE ?
846804
rc.camera.tilt + this.imageTilt : this.imageTilt;
847-
unitSquareTransform.multiplyByRotation(-1, 0, 0, tilt);
805+
imageTransform.multiplyByRotation(-1, 0, 0, actualTilt);
848806
}
849807

850808
// Perform image rotation
851809
if (this.imageRotation != 0) {
852-
double rotation = this.imageRotationReference == WorldWind.RELATIVE_TO_GLOBE ?
810+
double actualRotation = this.imageRotationReference == WorldWind.RELATIVE_TO_GLOBE ?
853811
rc.camera.heading - this.imageRotation : -this.imageRotation;
854-
unitSquareTransform.multiplyByRotation(0, 0, 1, rotation);
812+
imageTransform.multiplyByRotation(0, 0, 1, actualRotation);
855813
}
856814

857815
// Apply pivot translation
858-
unitSquareTransform.multiplyByTranslation(-offsetX, -offsetY, 0);
816+
imageTransform.multiplyByTranslation(-offsetX, -offsetY, 0);
859817

860818
// Apply scale
861-
unitSquareTransform.multiplyByScale(scaleX, scaleY, 1);
819+
imageTransform.multiplyByScale(scaleX, scaleY, 1);
820+
821+
// If the placemark's icon is visible, enqueue a drawable icon for processing on the OpenGL thread.
822+
WWMath.boundingRectForUnitSquare(imageTransform, imageBounds);
823+
if (rc.frustum.intersectsViewport(imageBounds)) {
824+
Pool<DrawableScreenTexture> pool = rc.getDrawablePool(DrawableScreenTexture.class);
825+
DrawableScreenTexture drawable = DrawableScreenTexture.obtain(pool);
826+
this.prepareDrawableIcon(rc, drawable);
827+
rc.offerShapeDrawable(drawable, this.cameraDistance);
828+
}
829+
830+
// If there's a label, perform these same operations for the label texture.
831+
if (this.mustDrawLabel(rc)) {
832+
// Render the label's texture when the label's position is in the frustum. If the label's position is outside
833+
// the frustum we don't do anything. This ensures that label textures are rendered only as necessary.
834+
this.labelTexture = rc.getText(this.label, this.activeAttributes.labelAttributes);
835+
if (this.labelTexture == null && rc.frustum.containsPoint(placePoint)) {
836+
this.labelTexture = rc.renderText(this.label, this.activeAttributes.labelAttributes);
837+
}
838+
839+
if (this.labelTexture != null) {
840+
int w = this.labelTexture.getWidth();
841+
int h = this.labelTexture.getHeight();
842+
this.activeAttributes.labelAttributes.textOffset.offsetForSize(w, h, offset);
843+
844+
labelTransform.setTranslation(
845+
screenPlacePoint.x - offset.x,
846+
screenPlacePoint.y - offset.y,
847+
screenPlacePoint.z);
848+
849+
labelTransform.setScale(w, h, 1);
850+
851+
WWMath.boundingRectForUnitSquare(labelTransform, labelBounds);
852+
if (rc.frustum.intersectsViewport(labelBounds)) {
853+
Pool<DrawableScreenTexture> pool = rc.getDrawablePool(DrawableScreenTexture.class);
854+
DrawableScreenTexture drawable = DrawableScreenTexture.obtain(pool);
855+
this.prepareDrawableLabel(rc, drawable);
856+
rc.offerShapeDrawable(drawable, this.cameraDistance);
857+
}
858+
}
859+
}
860+
861+
// Release references to objects stored in the render resource cache.
862+
this.activeTexture = null;
863+
this.labelTexture = null;
864+
865+
// Enqueue a picked object that associates the placemark's icon and leader with its picked object ID.
866+
if (rc.pickMode && rc.drawableCount() != drawableCount) {
867+
rc.offerPickedObject(PickedObject.fromRenderable(this.pickedObjectId, this, rc.currentLayer));
868+
}
869+
}
870+
871+
/**
872+
* Determines the placemark attributes to use for the current render pass.
873+
*
874+
* @param rc the current render context
875+
*/
876+
protected void determineActiveAttributes(RenderContext rc) {
877+
if (this.highlighted && this.highlightAttributes != null) {
878+
this.activeAttributes = this.highlightAttributes;
879+
} else {
880+
this.activeAttributes = this.attributes;
881+
}
882+
}
883+
884+
/**
885+
* Determines the image texture and unit square transform to use for the current render pass.
886+
*
887+
* @param rc the current render context
888+
*/
889+
protected void determineActiveTexture(RenderContext rc) {
890+
if (this.activeAttributes.imageSource != null) {
891+
// Earlier in doRender(), an attempt was made to 'get' the activeTexture from the cache.
892+
// If was not found in the cache we need to retrieve a texture from the image source.
893+
if (this.activeTexture == null) {
894+
this.activeTexture = rc.retrieveTexture(this.activeAttributes.imageSource, null); // puts retrieved textures in the cache
895+
}
896+
} else {
897+
this.activeTexture = null; // there is no imageSource; draw a simple colored square
898+
}
862899
}
863900

864901
/**
@@ -876,7 +913,7 @@ protected void prepareDrawableIcon(RenderContext rc, DrawableScreenTexture drawa
876913
}
877914

878915
// Use the plaemark's unit square transform matrix.
879-
drawable.unitSquareTransform.set(unitSquareTransform);
916+
drawable.unitSquareTransform.set(imageTransform);
880917

881918
// Configure the drawable according to the placemark's active attributes. Use a color appropriate for the pick
882919
// mode. When picking use a unique color associated with the picked object ID. Use the texture associated with
@@ -887,6 +924,37 @@ protected void prepareDrawableIcon(RenderContext rc, DrawableScreenTexture drawa
887924
drawable.enableDepthTest = this.activeAttributes.depthTest;
888925
}
889926

927+
/**
928+
* Prepares this placemark's label for processing in a subsequent drawing pass. Implementations must be
929+
* careful not to leak resources from Placemark into the Drawable.
930+
*
931+
* @param rc the current render context
932+
* @param drawable the Drawable to be prepared
933+
*/
934+
protected void prepareDrawableLabel(RenderContext rc, DrawableScreenTexture drawable) {
935+
// Use the basic GLSL program to draw the placemark's label.
936+
drawable.program = (BasicShaderProgram) rc.getShaderProgram(BasicShaderProgram.KEY);
937+
if (drawable.program == null) {
938+
drawable.program = (BasicShaderProgram) rc.putShaderProgram(BasicShaderProgram.KEY, new BasicShaderProgram(rc.resources));
939+
}
940+
941+
// Use the label's unit square transform matrix.
942+
drawable.unitSquareTransform.set(labelTransform);
943+
944+
// Configure the drawable according to the active label attributes. Use a color appropriate for the pick mode. When
945+
// picking use a unique color associated with the picked object ID. Use the texture associated with the active
946+
// attributes' text image and its associated tex coord transform. The text texture includes the appropriate
947+
// color for drawing, specifying white for normal drawing ensures the color multiplication in the shader results
948+
// in the texture's color.
949+
if (rc.pickMode) {
950+
drawable.color.set(this.pickColor);
951+
} else {
952+
drawable.color.set(1, 1, 1, 1);
953+
}
954+
drawable.texture = this.labelTexture;
955+
drawable.enableDepthTest = this.activeAttributes.labelAttributes.isEnableDepthTest();
956+
}
957+
890958
/**
891959
* Prepares this placemark's leader for drawing in a subsequent drawing pass. Implementations must be careful not to
892960
* leak resources from Placemark into the Drawable.
@@ -925,13 +993,10 @@ protected void prepareDrawableLeader(RenderContext rc, DrawableLines drawable) {
925993
*
926994
* @return True if there is a valid label and label attributes.
927995
*/
928-
929996
protected boolean mustDrawLabel(RenderContext rc) {
930-
return false;
931-
// TODO: implement mustDrawLabel()
932-
// return this.label != null
933-
// && !this.label.isEmpty()
934-
// && this.activeAttributes.labelAttributes != null;
997+
return this.label != null
998+
&& !this.label.isEmpty()
999+
&& this.activeAttributes.labelAttributes != null;
9351000
}
9361001

9371002
/**

0 commit comments

Comments
 (0)