Create mobile apps with HTML5, JavaScript and Visual Studio

(Elle) #1

78 msdn magazine DirectX Factor


CreateWindowSizeDependentResources that converts the source


polygons to the destination polygons based on the size of the screen.


In the inner loop, you’ll see x, y and z values calculated. Th is is


a 3D coordinate but it’s not even saved. Instead, it’s immediately


collapsed back into 2D by simply ignoring the z value. To calcu-


late those 3D coordinates, the code first converts a horizontal


position on the original path geometry to an angle in radians from


0 to 2π. The sin and cos functions calculate a position on a unit


circle on the XZ plane. Th e y value is a more direct conversion from


the vertical coordinates of the original path geometry.


Th e CreateWindowSizeDependentResources method concludes


by obtaining a new ID2D1PathGeometry object from the desti-


nation Polygon collection. Th e Render method then sets a matrix


transform to put the origin in the center of the screen, and both fi lls


and outlines this path geometry, with the result shown in Figure 4.


Is the program working? It’s hard to tell! Look closely and you


can see some wide characters in the center and narrower characters


at the left and right. But the big problem is that I started out with a


path geometry with no intersecting lines, and now the geometry


is displayed back over itself, with the result that overlapping areas


are not fi lled. Th is eff ect is characteristic of geometries, and it hap-


pens whether the path geometry created by the Polygon structure


has a fi ll mode of alternate or winding.


Getting Some Perspective


Th ree-dimensional graphics programming


is not just about coordinate points. Visual


cues are necessary for the viewer to interpret


an image on a 2D screen as representing an


object in 3D space. In the real world, you


rarely view objects from a constant vantage


point. You’d get a better view of the 3D text


in Figure 4 if you could tilt it somewhat so


it looks more like the ring in Figure 1.


To get some perspective on the three-dimensional text, the


coordinates need to be rotated in space. As you know, Direct2D


supports a matrix transform structure named D2D1_MATRIX


_3x2_F that you can use to defi ne 2D transforms, which you can


apply to your 2D graphics output by fi rst calling the SetTransform


method of ID2D1RenderTarget.


Most commonly, you would use a class named Matrix3x2F from


the D2D1 namespace for this purpose. Th is class derives from


D2D1_MATRIX_3x2F_F and provides methods for defi ning var-


ious types of standards for translation, scaling, rotation and skew.


Th e Matrix3x2F class also defi nes a method named Transform-


Point that allows you to apply the transform “manually” to individual


D2D1_POINT_2F objects. Th is is useful for manipulating points


before they’re rendered.


You may think I need a 3D rotation matrix to tilt the displayed


text. I’ll certainly be exploring 3D matrix transforms in future


columns, but for now I can make do with 2D rotation. Imagine


yourself situated somewhere on the negative X axis of Figure 1,


looking toward the origin. Th e positive Z and Y axes are situated


just like the X and Y axes in a conventional 2D coordinate system,


so it seems plausible that by applying a 2D rotation matrix to the


Z and Y values, I can rotate all the coordinates around the three-


dimensional X axis.


Figure 4 The CircularText Display Figure 5 The Tilted CircularText Display


Figure 6 The Update Method of SpinningCircularText


void SpinningCircularTextRenderer::Update(DX::StepTimer const& timer)
{
// Get window size and geometry size
Windows::Foundation::Size logicalSize = m_deviceResources->GetLogicalSize();
float geometryWidth = m_geometryBounds.right - m_geometryBounds.left;
float geometryHeight = m_geometryBounds.bottom - m_geometryBounds.top;

// Calculate a few factors for converting 2D to 3D
float radius = logicalSize.Width / 2 - 50;
float circumference = 2 * 3.14159f * radius;
float scale = circumference / geometryWidth;
float height = scale * geometryHeight;

// Calculate rotation matrix
float rotateAngle = -360 * float(fmod(timer.GetTotalSeconds(), 10)) / 10;
Matrix3x2F rotateMatrix = Matrix3x2F::Rotation(rotateAngle);

// Calculate tilt matrix
Matrix3x2F tiltMatrix = Matrix3x2F::Rotation(m_tiltAngle);

for (size_t polygonIndex = 0; polygonIndex < m_srcPolygons.size(); polygonIndex++)
{
const Polygon& srcPolygon = m_srcPolygons.at(polygonIndex);
Polygon& dstPolygon = m_dstPolygons.at(polygonIndex);

for (size_t pointIndex = 0; pointIndex < srcPolygon.Points.size(); pointIndex++)
{
const D2D1_POINT_2F pt = srcPolygon.Points.at(pointIndex);
float radians = 2 * 3.14159f * (pt.x - m_geometryBounds.left) / geometryWidth;

float x = radius * sin(radians);
float z = radius * cos(radians);
float y = height * ((pt.y - m_geometryBounds.top) / geometryHeight - 0.5f);

// Apply rotation to X and Z
D2D1_POINT_2F rotatedPoint = rotateMatrix.TransformPoint(Point2F(x, z));
x = rotatedPoint.x;
z = rotatedPoint.y;

// Apply tilt to Y and Z
D2D1_POINT_2F tiltedPoint = tiltMatrix.TransformPoint(Point2F(y, z));
y = tiltedPoint.x;
z = tiltedPoint.y;

dstPolygon.Points.at(pointIndex) = Point2F(x, y);
}
}

// Create path geometry from Polygon collection
DX::ThrowIfFailed(
Polygon::CreateGeometry(m_deviceResources->GetD2DFactory(),
m_dstPolygons,
&m_pathGeometry)
);

// Update FPS display text
uint32 fps = timer.GetFramesPerSecond();

m_text = (fps > 0)? std::to_wstring(fps) + L" FPS" : L" - FPS";
}
Free download pdf