//***************************************************************************************
// GeometryGenerator.cpp by Frank Luna (C) 2011 All Rights Reserved.
//***************************************************************************************
#include "GeometryGenerator.h"
#include <algorithm>
using namespace DirectX;
GeometryGenerator::MeshData GeometryGenerator::CreateBox(float width, float height, float depth, uint32 numSubdivisions)
{
MeshData meshData;
//
// Create the vertices.
//
Vertex v[24];
float w2 = 0.5f*width;
float h2 = 0.5f*height;
float d2 = 0.5f*depth;
// Fill in the front face vertex data.
v[0] = Vertex(-w2, -h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
v[1] = Vertex(-w2, +h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
v[2] = Vertex(+w2, +h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
v[3] = Vertex(+w2, -h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
// Fill in the back face vertex data.
v[4] = Vertex(-w2, -h2, +d2, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
v[5] = Vertex(+w2, -h2, +d2, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
v[6] = Vertex(+w2, +h2, +d2, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
v[7] = Vertex(-w2, +h2, +d2, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
// Fill in the top face vertex data.
v[8] = Vertex(-w2, +h2, -d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
v[9] = Vertex(-w2, +h2, +d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
v[10] = Vertex(+w2, +h2, +d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
v[11] = Vertex(+w2, +h2, -d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
// Fill in the bottom face vertex data.
v[12] = Vertex(-w2, -h2, -d2, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
v[13] = Vertex(+w2, -h2, -d2, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
v[14] = Vertex(+w2, -h2, +d2, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
v[15] = Vertex(-w2, -h2, +d2, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
// Fill in the left face vertex data.
v[16] = Vertex(-w2, -h2, +d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[17] = Vertex(-w2, +h2, +d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
v[18] = Vertex(-w2, +h2, -d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[19] = Vertex(-w2, -h2, -d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
// Fill in the right face vertex data.
v[20] = Vertex(+w2, -h2, -d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f);
v[21] = Vertex(+w2, +h2, -d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
v[22] = Vertex(+w2, +h2, +d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f);
v[23] = Vertex(+w2, -h2, +d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f);
meshData.Vertices.assign(&v[0], &v[24]);
//
// Create the indices.
//
uint32 i[36];
// Fill in the front face index data
i[0] = 0; i[1] = 1; i[2] = 2;
i[3] = 0; i[4] = 2; i[5] = 3;
// Fill in the back face index data
i[6] = 4; i[7] = 5; i[8] = 6;
i[9] = 4; i[10] = 6; i[11] = 7;
// Fill in the top face index data
i[12] = 8; i[13] = 9; i[14] = 10;
i[15] = 8; i[16] = 10; i[17] = 11;
// Fill in the bottom face index data
i[18] = 12; i[19] = 13; i[20] = 14;
i[21] = 12; i[22] = 14; i[23] = 15;
// Fill in the left face index data
i[24] = 16; i[25] = 17; i[26] = 18;
i[27] = 16; i[28] = 18; i[29] = 19;
// Fill in the right face index data
i[30] = 20; i[31] = 21; i[32] = 22;
i[33] = 20; i[34] = 22; i[35] = 23;
meshData.Indices32.assign(&i[0], &i[36]);
// Put a cap on the number of subdivisions.
numSubdivisions = std::min<uint32>(numSubdivisions, 6u);
for(uint32 i = 0; i < numSubdivisions; ++i)
Subdivide(meshData);
return meshData;
}
GeometryGenerator::MeshData GeometryGenerator::CreateSphere(float radius, uint32 sliceCount, uint32 stackCount)
{
MeshData meshData;
//
// Compute the vertices stating at the top pole and moving down the stacks.
//
// Poles: note that there will be texture coordinate distortion as there is
// not a unique point on the texture map to assign to the pole when mapping
// a rectangular texture onto a sphere.
Vertex topVertex(0.0f, +radius, 0.0f, 0.0f, +1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
Vertex bottomVertex(0.0f, -radius, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
meshData.Vertices.push_back( topVertex );
float phiStep = XM_PI/stackCount;
float thetaStep = 2.0f*XM_PI/sliceCount;
// Compute vertices for each stack ring (do not count the poles as rings).
for(uint32 i = 1; i <= stackCount-1; ++i)
{
float phi = i*phiStep;
// Vertices of ring.
for(uint32 j = 0; j <= sliceCount; ++j)
{
float theta = j*thetaStep;
Vertex v;
// spherical to cartesian
v.Position.x = radius*sinf(phi)*cosf(theta);
v.Position.y = radius*cosf(phi);
v.Position.z = radius*sinf(phi)*sinf(theta);
// Partial derivative of P with respect to theta
v.TangentU.x = -radius*sinf(phi)*sinf(theta);
v.TangentU.y = 0.0f;
v.TangentU.z = +radius*sinf(phi)*cosf(theta);
XMVECTOR T = XMLoadFloat3(&v.TangentU);
XMStoreFloat3(&v.TangentU, XMVector3Normalize(T));
XMVECTOR p = XMLoadFloat3(&v.Position);
XMStoreFloat3(&v.Normal, XMVector3Normalize(p));
v.TexC.x = theta / XM_2PI;
v.TexC.y = phi / XM_PI;
meshData.Vertices.push_back( v );
}
}
meshData.Vertices.push_back( bottomVertex );
//
// Compute indices for top stack. The top stack was written first to the vertex buffer
// and connects the top pole to the first ring.
//
for(uint32 i = 1; i <= sliceCount; ++i)
{
meshData.Indices32.push_back(0);
meshData.Indices32.push_back(i+1);
meshData.Indices32.push_back(i);
}
//
// Compute indices for inner stacks (not connected to poles).
//
// Offset the indices to the index of the first vertex in the first ring.
// This is just skipping the top pole vertex.
uint32 baseIndex = 1;
uint32 ringVertexCount = sliceCount + 1;
for(uint32 i = 0; i < stackCount-2; ++i)
{
for(uint32 j = 0; j < sliceCount; ++j)
{
meshData.Indices32.push_back(baseIndex + i*ringVertexCount + j);
meshData.Indices32.push_back(baseIndex + i*ringVertexCount + j+1);
meshData.Indices32.push_back(baseIndex + (i+1)*ringVertexCount + j);
meshData.Indices32.push_back(baseIndex + (i+1)*ringVertexCount + j);
meshData.Indices32.push_back(baseIndex + i*ringVertexCount + j+1);
meshData.Indices32.push_back(baseIndex + (i+1)*ringVertexCount + j+1);
}
}
//
// Compute indices for bottom stack. The bottom stack was written last to the vertex buffer
// and connects the bottom pole to the bottom ring.
//
// South pole vertex was added last.
uint32 southPoleIndex = (uint32)meshData.Vertices.size()-1;
// Offset the indices to the index of the first vertex in the last ring.
baseIndex = southPoleIndex - ringVertexCount;
for(uint32 i = 0; i < sliceCount; ++i)
{
meshData.Indices32.push_back(southPoleIndex);
meshData.Indices32.push_back(baseIndex+i);
meshData.Indices32.push_back(baseIndex+i+1);
}
return meshData;
}
void GeometryGenerator::Subdivide(MeshData& meshData)
{
// Save a copy of the input geometry.
MeshData inputCopy = meshData;
meshData.Vertices.resize(0);
meshData.Indices32.resize(0);
// v1
// *
// / \
// / \
// m0*-----*m1
// / \ / \
// / \ / \
// *-----*-----*
// v0 m2 v2
uint32 numTris = (uint32)inputCopy.Indices32.size()/3;
for(uint32 i = 0; i < numTris; ++i)
{
Vertex v0 = inputCopy.Vertices[ inputCopy.Indices32[i*3+0] ];
Vertex v1 = inputCopy.Vertices[ inputCopy.Indices32[i*3+1] ];
Vertex v2 = inputCopy.Vertices[ inputCopy.Indices32[i*3+2] ];
//
// Generate the midpoints.
//
Vertex m0 = MidPoint(v0, v1);
Vertex m1 = MidPoint(v1, v2);
Vertex m2 = MidPoint(v0, v2);
//
// Add new geometry.
//
meshData.Vertices.push_back(v0); // 0
meshData.Vertices.push_back(v1); // 1
meshData.Vertices.push_back(v2); // 2
meshData.Vertices.push_back(m0); // 3
meshData.Vertices.push_back(m1); // 4
meshData.Vertices.push_back(m2); // 5
meshData.Indices32.push_back(i*6+0);
meshData.Indices32.push_back(i*6+3);
meshData.Indices32.push_back(i*6+5);
meshData.Indices32.push_back(i*6+3);
meshData.Indices32.push_back(i*6+4);
meshData.Indices32.push_back(i*6+5);
meshData.Indices32.push_back(i*6+5);
meshData.Indices32.push_back(i*6+4);
meshData.Indices32.push_back(i*6+2);
meshData.Indices32.push_back(i*6+3);
meshData.Indices32.push_back(i*6+1);
meshData.Indices32.push_back(i*6+4);
}
}
GeometryGenerator::Vertex GeometryGenerator::MidPoint(const Vertex& v0, const Vertex& v1)
{
XMVECTOR p0 = XMLoadFloat3(&v0.Position);
XMVECTOR p1 = XMLoadFloat3(&v1.Position);
XMVECTOR n0 = XMLoadFloat3(&v0.Normal);
XMVECTOR n1 = XMLoadFloat3(&v1.Normal);
XMVECTOR tan0 = XMLoadFloat3(&v0.TangentU);
XMVECTOR tan1 = XMLoadFloat3(&v1.TangentU);
XMVECTOR tex0 = XMLoadFloat2(&v0.TexC);
XMVECTOR tex1 = XMLoadFloat2(&v1.TexC);
// Compute the midpoints of all the attributes. Vectors need to be normalized
// since linear interpolating can make them not unit length.
XMVECTOR pos = 0.5f*(p0 + p1);
XMVECTOR normal = XMVector3Normalize(0.5f*(n0 + n1));
XMVECTOR tangent = XMVector3Normalize(0.5f*(tan0+tan1));
XMVECTOR tex = 0.5f*(tex0 + tex1);
Vertex v;
XMStoreFloat3(&v.Position, pos);
XMStoreFloat3(&v.Normal, normal);
XMStoreFloat3(&v.TangentU, tangent);
XMStoreFloat2(&v.TexC, tex);
return v;
}
GeometryGenerator::MeshData GeometryGenerator::CreateGeosphere(float radius, uint32 numSubdivisions)
{
MeshData meshData;
// Put a cap on the number of subdivisions.
numSubdivisions = std::min<uint32>(numSubdivisions, 6u);
// Approximate a sphere by tessellating an icosahedron.
const float X = 0.525731f;
const float Z = 0.850651f;
XMFLOAT3 pos[12] =
{
XMFLOAT3(-X, 0.0f, Z), XMFLOAT3(X, 0.0f, Z),
XMFLOAT3(-X, 0.0f, -Z), XMFLOAT3(X, 0.0f, -Z),
XMFLOAT3(0.0f, Z, X), XMFLOAT3(0.0f, Z, -X),
XMFLOAT3(0.0f, -Z, X), XMFLOAT3(0.0f, -Z, -X),
XMFLOAT3(Z, X, 0.0f), XMFLOAT3(-Z, X, 0.0f),
XMFLOAT3(Z, -X, 0.0f), XMFLOAT3(-Z, -X, 0.0f)
};
uint32 k[60] =
{
1,4,0, 4,9,0, 4,5,9, 8,5,4, 1,8,4,
1,10,8, 10,3,8, 8,3,5, 3,2,5, 3,7,2,
3,10,7, 10,6,7, 6,11,7, 6,0,11, 6,1,0,
10,1,6, 11,0,9, 2,11,9, 5,2,9, 11,2,7
};
meshData.Vertices.resize(12);
meshData.Indices32.assign(&k[0], &k[60]);
for(uint32 i = 0; i < 12; ++i)
meshData.Vertices[i].Position = pos[i];
for(uint32 i = 0; i < numSubdivisions; ++i)
Subdivide(meshData);
// Project vertices onto sphere and scale.
for(uint32 i = 0; i < meshData.Vertices.size(); ++i)
{
// Project onto unit sphere.
XMVECTOR n = XMVector3Normalize(XMLoadFloat3(&meshData.Vertices[i].Position));
// Project onto sphere.
XMVECTOR p = radius*n;
XMStoreFloat3(&meshData.Vertices[i].Position, p);
XMStoreFloat3(&meshData.Vertices[i].Normal, n);
// Derive texture coordinates from spherical coordinates.
float theta = atan2f(meshData.Vertices[i].Position.z, meshData.Vertices[i].Position.x);
// Put in [0, 2pi].
if(theta < 0.0f)
theta += XM_2PI;
float phi = acosf(meshData.Vertices[i].Position.y / radius);
meshData.Vertices[i].TexC.x = theta/XM_2PI;
meshData.Vertices[i].TexC.y = phi/XM_PI;
// Partial derivative of P with respect to theta
meshData.Vertices[i].TangentU.x = -radius*sinf(phi)*sinf(theta);
meshData.Vertices[i].TangentU.y = 0.0f;
meshData.Vertices[i].TangentU.z = +radius*sinf(phi)*cosf(theta);
XMVECTOR T = XMLoadFloat3(&meshData.Vertices[i].TangentU);
XMStoreFloat3(&meshData.Vertices[i].TangentU, XMVector3Normalize(T));
}
return meshData;
}
GeometryGenerator::MeshData GeometryGenerator::CreateCylinder(float bottomRadius, float topRadius, float height, uint32 sliceCount, uint32 stackCount)
{
MeshData meshData;
//
// Build Stacks.
//
float stackHeight = height / stackCount;
// Amount to increment radius as we move up each stack level from bottom to top.
float radiusStep = (topRadius - bottomRadius) / stackCount;
uint32 ringCount = stackCount+1;
// Compute vertices for each stack ring starting at the bottom and moving up.
for(uint32 i = 0; i < ringCount; ++i)
{
float y = -0.5f*height + i*stackHeight;
float r = bottomRadius + i*radiusStep;
// vertices of ring
float dTheta = 2.0f*XM_PI/sliceCount;
for(uint32 j = 0; j <= sliceCount; ++j)
{
Vertex vertex;
float c = cosf(j*dTheta);
float s = sinf(j*dTheta);
vertex.Position = XMFLOAT3(r*c, y, r*s);
vertex.TexC.x = (float)j/sliceCount;
vertex.TexC.y = 1.0f - (float)i/stackCount;
// Cylinder can be parameterized as follows, where we introduce v
// parameter that goes in the same direction as the v tex-coord
// so that the bitangent goes in the same direction as the v tex-coord.
// Let r0 be the bottom radius and let r1 be the top radius.
// y(v) = h - hv for v in [0,1].
// r(v) = r1 + (r0-r1)v
//
// x(t, v) = r(v)*cos(t)
// y(t, v) = h - hv
// z(t, v) = r(v)*sin(t)
//
// dx/dt = -r(v)*sin(t)
// dy/dt = 0
// dz/dt = +r(v)*cos(t)
//
// dx/dv = (r0-r1)*cos(t)
// dy/dv = -h
// dz/dv = (r0-r1)*sin(t)
// This is unit length.
vertex.TangentU = XMFLOAT3(-s, 0.0f, c);
float dr = bottomRadius-topRadius;
XMFLOAT3 bitangent(dr*c, -height, dr*s);
XMVECTOR T = XMLoadFloat3(&vertex.TangentU);
XMVECTOR B = XMLoadFloat3(&bitangent);
XMVECTOR N = XMVector3Normalize(XMVector3Cross(T, B));
XMStoreFloat3(&vertex.Normal, N);
meshData.Vertices.push_back(vertex);
}
}
// Add one because we duplicate the first and last vertex per ring
// since the texture coordinates are different.
uint32 ringVertexCount = sliceCount+1;
// Compute indices for each stack.
for(uint32 i = 0; i < stackCount; ++i)
{
for(uint32 j = 0; j < sliceCount; ++j)
{
meshData.Indices32.push_back(i*ringVertexCount + j);
meshData.Indices32.push_back((i+1)*ringVertexCount + j);
meshData.Indices32.push_back((i+1)*ringVertexCount + j+1);
meshData.Indices32.push_back(i*ringVertexCount + j);
meshData.Indices32.push_back((i+1)*ringVertexCount + j+1);
meshData.Indices32.push_back(i*ringVertexCount + j+1);
}
}
BuildCylinderTopCap(bottomRadius, topRadius, height, sliceCount, stackCount, meshData);
BuildCylinderBottomCap(bottomRadius, topRadius, height, sliceCount, stackCount, meshData);
return meshData;
}
void GeometryGenerator::BuildCylinderTopCap(float bottomRadius, float topRadius, float height,
uint32 sliceCount, uint32 stackCount, MeshData& meshData)
{
uint32 baseIndex = (uint32)meshData.Vertices.size();
float y = 0.5f*height;
float dTheta = 2.0f*XM_PI/sliceCount;
// Duplicate cap ring vertices because the texture coordinates and normals differ.
for(uint32 i = 0; i <= sliceCount; ++i)
{
float x = topRadius*cosf(i*dTheta);
float z = topRadius*sinf(i*dTheta);
// Scale down by the height to try and make top cap texture coord area
// proportional to base.
float u = x/height + 0.5f;
float v = z/height + 0.5f;
meshData.Vertices.push_back( Vertex(x, y, z, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, u, v) );
}
// Cap center vertex.
meshData.Vertices.push_back( Vertex(0.0f, y, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f) );
// Index of center vertex.
uint32 centerIndex = (uint32)meshData.Vertices.size()-1;
for(uint32 i = 0; i < sliceCount; ++i)
{
meshData.Indices32.push_back(centerIndex);
meshData.Indices32.push_back(baseIndex + i+1);
meshData.Indices32.push_back(baseIndex + i);
}
}
void GeometryGenerator::BuildCylinderBottomCap(float bottomRadius, float topRadius, float height,
uint32 sliceCount, uint32 stackCount, MeshData& meshData)
{
//
// Build bottom cap.
//
uint32 baseIndex = (uint32)meshData.Vertices.size();
float y = -0.5f*height;
// vertices of ring
float dTheta = 2.0f*XM_PI/sliceCount;
for(uint32 i = 0; i <= sliceCount; ++i)
{
float x = bottomRadius*cosf(i*dTheta);
float z = bottomRadius*sinf(i*dTheta);
// Scale down by the height to try and make top cap texture coord area
// proportional to base.
float u = x/height + 0.5f;
float v = z/height + 0.5f;
meshData.Vertices.push_back( Vertex(x, y, z, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, u, v) );
}
// Cap center vertex.
meshData.Vertices.push_back( Vertex(0.0f, y, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f) );
// Cache the index of center vertex.
uint32 centerIndex = (uint32)meshData.Vertices.size()-1;
for(uint32 i = 0; i < sliceCount; ++i)
{
meshData.Indices32.push_back(centerIndex);
meshData.Indices32.push_back(baseIndex + i);
meshData.Indices32.push_back(baseIndex + i+1);
}
}
GeometryGenerator::MeshData GeometryGenerator::CreateGrid(float width, float depth, uint32 m, uint32 n)
{
MeshData meshData;
uint32 vertexCount = m*n;
uint32 faceCount = (m-1)*(n-1)*2;
//
// Create the vertices.
//
float halfWidth = 0.5f*width;
float halfDepth = 0.5f*depth;
float dx = width / (n-1);
float dz = depth / (m-1);
float du = 1.0f / (n-1);
float dv = 1.0f / (m-1);
meshData.Vertices.resize(vertexCount);
for(uint32 i = 0; i < m; ++i)
{
float z = halfDepth - i*dz;
for(uint32 j = 0; j < n; ++j)
{
float x = -halfWidth + j*dx;
meshData.Vertices[i*n+j].Position = XMFLOAT3(x, 0.0f, z);
meshData.Vertices[i*n+j].Normal = XMFLOAT3(0.0f, 1.0f, 0.0f);
meshData.Vertices[i*n+j].TangentU = XMFLOAT3(1.0f, 0.0f, 0.0f);
// Stretch texture over grid.
meshData.Vertices[i*n+j].TexC.x = j*du;
meshData.Vertices[i*n+j].TexC.y = i*dv;
}
}
//
// Create the indices.
//
meshData.Indices32.resize(faceCount*3); // 3 indices per face
// Iterate over each quad and compute indices.
uint32 k = 0;
for(uint32 i = 0; i < m-1; ++i)
{
for(uint32 j = 0; j < n-1; ++j)
{
meshData.Indices32[k] = i*n+j;
meshData.Indices32[k+1] = i*n+j+1;
meshData.Indices32[k+2] = (i+1)*n+j;
meshData.Indices32[k+3] = (i+1)*n+j;
meshData.Indices32[k+4] = i*n+j+1;
meshData.Indices32[k+5] = (i+1)*n+j+1;
k += 6; // next quad
}
}
return meshData;
}
GeometryGenerator::MeshData GeometryGenerator::CreateQuad(float x, float y, float w, float h, float depth)
{
MeshData meshData;
meshData.Vertices.resize(4);
meshData.Indices32.resize(6);
// Position coordinates specified in NDC space.
meshData.Vertices[0] = Vertex(
x, y - h, depth,
0.0f, 0.0f, -1.0f,
1.0f, 0.0f, 0.0f,
0.0f, 1.0f);
meshData.Vertices[1] = Vertex(
x, y, depth,
0.0f, 0.0f, -1.0f,
1.0f, 0.0f, 0.0f,
0.0f, 0.0f);
meshData.Vertices[2] = Vertex(
x+w, y, depth,
0.0f, 0.0f, -1.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f);
meshData.Vertices[3] = Vertex(
x+w, y-h, depth,
0.0f, 0.0f, -1.0f,
1.0f, 0.0f, 0.0f,
1.0f, 1.0f);
meshData.Indices32[0] = 0;
meshData.Indices32[1] = 1;
meshData.Indices32[2] = 2;
meshData.Indices32[3] = 0;
meshData.Indices32[4] = 2;
meshData.Indices32[5] = 3;
return meshData;
}