@@ -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