AGI Components with Insight3D Alpha 2008 r8
Text Batch Primitive

The text batch primitive renders a group of strings with the same font. Each string can have a different position, color, horizontal origin, vertical origin, pixel offset, and eye offset. Using the text batch is similar to using the point batch, only strings are rendered instead of points.

Topic Description
Basic Example Use the text batch to render strings.
Fonts Change font properties, such as size, bold, and outline.
Per-String Color Use optional parameters to define a color per-string.
Horizontal and Vertical Origins Control the horizontal and vertical placement of a string relative to its position.
Pixel and Eye Offsets Optional offsets translate strings in pixel and/or eye space.
Dynamic Updates Set and SetPartial methods enable efficient dynamic updates.
Technical Details: The text batch uses a GPU-based rendering algorithm described in our blog.

Basic Example

The following example renders two strings with the MS Sans Serif font. An array containing the strings and a parallel array containing positions corresponding to each string are passed to the text batch's Initialize method.

CopyC#
Ellipsoid shape = CentralBodiesFacet.GetFromContext().Earth.Shape;
Cartesian p0 = shape.CartographicToCartesian(new Cartographic(Trig.DegreesToRadians(-75.25), Trig.DegreesToRadians(39.88), 0.0));
Cartesian p1 = shape.CartographicToCartesian(new Cartographic(Trig.DegreesToRadians(-77.04), Trig.DegreesToRadians(38.85), 0.0));

String[] strings = new String[]
{
    "Philadelphia",
    "Washington, D.C."
};
Array aryStrings = strings;

double[] positions = new double[]
{
    p0.X, p0.Y, p0.Z,
    p1.X, p1.Y, p1.Z
};
Array aryPositions = positions;

IAgGxFont font = new AgGxFont();
font.Initialize("MS Sans Serif", 16, false, false, false, false, false);

IAgGxPrimitiveTextBatch textBatch = new AgGxPrimitiveTextBatch();
textBatch.Initialize(earth,
    AgGxReferenceFrame.ReferenceFrameFixed,
    AgGxVertexUpdate.VertexUpdateNone,
    font,
    ref aryStrings,
    ref aryPositions,
    null);                  // Not passing in any optional parameters

sceneManager.Primitives.Add(textBatch);

Fonts

AgGxFont defines the font used to render a text batch. The Initialize method defines the font based on name, size, bold, italic, underline, strike-out, and outline. When a font is created with an outline, text is rendered with a colored outline as shown below.

CopyC#
// Bold and outline font
IAgGxFont font = new AgGxFont();
font.Initialize("MS Sans Serif", 16, true, false, false, false, true);

// ...

textBatch.OutlineColor = (uint)ColorTranslator.ToOle(Color.Red);

Per-String Color

By default, text is white. The standard color methods and properties are used to change the color of every string in the batch. For more flexibility, each string can have a unique color. This is done by creating an array of colors, where each color corresponds to one string. The array of colors is an optional parameter, so it is added to an AgGxPrimitiveTextBatchOptionalParameters object, which is then passed to Initialize as shown below.

CopyC#
Ellipsoid shape = CentralBodiesFacet.GetFromContext().Earth.Shape;
Cartesian p0 = shape.CartographicToCartesian(new Cartographic(Trig.DegreesToRadians(-75.25), Trig.DegreesToRadians(39.88), 3000.0));
Cartesian p1 = shape.CartographicToCartesian(new Cartographic(Trig.DegreesToRadians(-77.04), Trig.DegreesToRadians(38.85), 0.0));

String[] strings = new String[]
{
    "Philadelphia",
    "Washington, D.C."
};
Array aryStrings = strings;

double[] positions = new double[]
{
    p0.X, p0.Y, p0.Z,
    p1.X, p1.Y, p1.Z
};
Array aryPositions = positions;

byte[] colors = new byte[]
{
    255, 255, 0, 255,
    127, 255, 0, 255
};
Array aryColors = colors;

IAgGxPrimitiveTextBatchOptionalParameters parameters = new AgGxPrimitiveTextBatchOptionalParameters();
parameters.SetColors(ref aryColors);

IAgGxFont font = new AgGxFont();
font.Initialize("MS Sans Serif", 16, false, false, false, false, false);

IAgGxPrimitiveTextBatch textBatch = new AgGxPrimitiveTextBatch();
textBatch.Initialize(earth,
    AgGxReferenceFrame.ReferenceFrameFixed,
    AgGxVertexUpdate.VertexUpdateNone,
    font,
    ref aryStrings,
    ref aryPositions,
    parameters);

sceneManager.Primitives.Add(textBatch);

Horizontal and Vertical Origins

In many cases, text will be next to another primitive, such as a point, marker, or model. For example, the same positions array used to initialize a text batch can be used to initialize a point batch as shown below.

CopyC#
IAgGxPrimitivePointBatch pointBatch = new AgGxPrimitivePointBatch();
pointBatch.Initialize(earth,
    AgGxReferenceFrame.ReferenceFrameFixed,
    AgGxVertexUpdate.VertexUpdateNone,
    ref aryPositions);
pointBatch.PixelSize = 5;

By default, a string's position defines the bottom left corner of the text. Using AgGxPrimitiveTextBatchOptionalParameters, the position can define the horizontal origin as left, center, or right, and the vertical origin as bottom, center, or top. Use the HorizontalOrigin and VerticalOrigin properties to set the origin for every string in a batch, or use SetHorizontalOrigins and SetVerticalOrigins to define origins per-string. The following code creates a text batch with several strings to demonstrate the affects of different horizontal and vertical origins.

CopyC#
Ellipsoid shape = CentralBodiesFacet.GetFromContext().Earth.Shape;
Cartesian p0 = shape.CartographicToCartesian(new Cartographic(Trig.DegreesToRadians(-75.25), Trig.DegreesToRadians(39.88), 0.0));
Cartesian p1 = shape.CartographicToCartesian(new Cartographic(Trig.DegreesToRadians(-75.25), Trig.DegreesToRadians(39.88), 90000.0));

String[] strings = new String[]
{
    "Top Left Origin",
    "Bottom Right Origin",
    "Top Center Origin",
    "Bottom Center Origin"
};
Array aryStrings = strings;

double[] positions = new double[]
{
    p0.X, p0.Y, p0.Z,
    p0.X, p0.Y, p0.Z,
    p1.X, p1.Y, p1.Z,
    p1.X, p1.Y, p1.Z
};
Array aryPositions = positions;

AgGxHorizontalOrigin[] horizontalOrigins = new AgGxHorizontalOrigin[]
{
    AgGxHorizontalOrigin.HorizontalOriginLeft,
    AgGxHorizontalOrigin.HorizontalOriginRight,
    AgGxHorizontalOrigin.HorizontalOriginCenter,
    AgGxHorizontalOrigin.HorizontalOriginCenter
};
Array aryHorizontalOrigins = horizontalOrigins;

AgGxVerticalOrigin[] verticalOrigins = new AgGxVerticalOrigin[]
{
    AgGxVerticalOrigin.VerticalOriginTop,
    AgGxVerticalOrigin.VerticalOriginBottom,
    AgGxVerticalOrigin.VerticalOriginTop,
    AgGxVerticalOrigin.VerticalOriginBottom,
};
Array aryVerticalOrigins = verticalOrigins;

IAgGxPrimitiveTextBatchOptionalParameters parameters = new AgGxPrimitiveTextBatchOptionalParameters();
parameters.SetHorizontalOrigins(ref aryHorizontalOrigins);
parameters.SetVerticalOrigins(ref aryVerticalOrigins);

IAgGxFont font = new AgGxFont();
font.Initialize("MS Sans Serif", 16, false, false, false, false, false);

IAgGxPrimitiveTextBatch textBatch = new AgGxPrimitiveTextBatch();
textBatch.Initialize(earth,
    AgGxReferenceFrame.ReferenceFrameFixed,
    AgGxVertexUpdate.VertexUpdateNone,
    font,
    ref aryStrings,
    ref aryPositions,
    parameters);

IAgGxPrimitivePointBatch pointBatch = new AgGxPrimitivePointBatch();
pointBatch.Initialize(earth,
    AgGxReferenceFrame.ReferenceFrameFixed,
    AgGxVertexUpdate.VertexUpdateNone,
    ref aryPositions);
pointBatch.PixelSize = 8;

sceneManager.Primitives.Add(textBatch);
sceneManager.Primitives.Add(pointBatch);

Pixel and Eye Offsets

Using AgGxPrimitiveTextBatchOptionalParameters, text can be offset from its position in either pixel or eye coordinates. In pixel coordinates, increasing x moves from the left toward the right side of the window, and increasing y moves from the bottom to the top. To move "Philadelphia" to the right so the "P" and the point do not overlap, apply a pixel offset of 10.

CopyC#
int[] pixelOffsets = new int[]
{
    10, 0,
    0, 0
};
Array aryPixelOffsets = pixelOffsets;

IAgGxPrimitiveTextBatchOptionalParameters parameters = new AgGxPrimitiveTextBatchOptionalParameters();
parameters.SetPixelOffsets(ref aryPixelOffsets);

"Washington, D.C." has an offset of (0, 0) so it is not moved from its position. If every string in a batch will have the same offset, use SetPixelOffset instead of providing an array to SetPixelOffsets.

In addition to pixel offsets, an eye space offset can be applied to each string using SetEyeOffset or SetEyeOffsets. Each unit in eye space is 1 meter. Positive x points towards the viewer's right, positive y points up, and negative z points along the view vector. For example, a positive y offset may be applied to translate a string so it is always "on top" of a model primitive.

The following images demonstrate how applying an eye offset of (0, 100000, 0) affects the position of a string from different view points. Note that an eye offset is different then a pixel offset or a world translation (e.g. offset the altitude by ten meters).

From this view, the eye offset moves the strings approximately north.

From a different view, the offset moves the strings approximately along their surface normals.

Dynamic Updates

As explained in the dynamic updates overview, the text batch provides Set and SetPartial methods for efficient dynamic updates of positions, strings, and optional parameters, such as colors. Use Set to completely redefine the text batch. If this is done frequently (e.g. every few frames), initialize the text batch with VertexUpdateSet.

Use SetPartial to update a subset of strings in the text batch. Make sure to initialize the text batch with VertexUpdateSetPartial. SetPartial must modify either the string itself or its position. If optional parameters are not provided, the defaults are used. The following example updates the position of the second string in the text batch.

CopyC#
// textBatch was initialized with AgGxVertexUpdate.VertexUpdateSetPartial.

Array aryNewString = null;  // Only updating position

double[] newPosition = new double[] { p1.X, p1.Y, p1.Z };
Array aryNewPosition = newPosition;

int[] indices = new int[] { 1 };
Array aryIndices = indices;

textBatch.SetPartial(ref aryNewString, ref aryNewPosition, ref aryIndices,
    AgGxIndicesOrder.IndicesOrderSortedAscending, null);

Due to the text batch's vertex data layout, SetPartial has a few limitations:

  • If a call to SetPartial increases the length of a string (e.g. changes "0.1" to "0.12"), the new length cannot be longer then the length defined by SetPartialStringLength. It is recommended to set this property to the anticipated length of the longest string when initializing a text batch.
  • If optional parameters are passed to SetPartial, the string's text must also be passed in order to modify the string's horizontal or vertical origin.