Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/renderer/TexturedLineRData.cpp
Show First 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | void CTexturedLineRData::Render( | ||||
deviceCommandContext->SetVertexAttributeFormat( | deviceCommandContext->SetVertexAttributeFormat( | ||||
Renderer::Backend::VertexAttributeStream::POSITION, | Renderer::Backend::VertexAttributeStream::POSITION, | ||||
Renderer::Backend::Format::R32G32B32_SFLOAT, | Renderer::Backend::Format::R32G32B32_SFLOAT, | ||||
offsetof(CTexturedLineRData::SVertex, m_Position), stride, | offsetof(CTexturedLineRData::SVertex, m_Position), stride, | ||||
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); | Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); | ||||
deviceCommandContext->SetVertexAttributeFormat( | deviceCommandContext->SetVertexAttributeFormat( | ||||
Renderer::Backend::VertexAttributeStream::UV0, | Renderer::Backend::VertexAttributeStream::UV0, | ||||
Renderer::Backend::Format::R32G32_SFLOAT, | Renderer::Backend::Format::R32G32_SFLOAT, | ||||
offsetof(CTexturedLineRData::SVertex, m_UVs), stride, | offsetof(CTexturedLineRData::SVertex, m_UV), stride, | ||||
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); | Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); | ||||
deviceCommandContext->SetVertexAttributeFormat( | deviceCommandContext->SetVertexAttributeFormat( | ||||
Renderer::Backend::VertexAttributeStream::UV1, | Renderer::Backend::VertexAttributeStream::UV1, | ||||
Renderer::Backend::Format::R32G32_SFLOAT, | Renderer::Backend::Format::R32G32_SFLOAT, | ||||
offsetof(CTexturedLineRData::SVertex, m_UVs), stride, | offsetof(CTexturedLineRData::SVertex, m_UV), stride, | ||||
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); | Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); | ||||
deviceCommandContext->SetVertexBuffer(0, m_VB->m_Owner->GetBuffer()); | deviceCommandContext->SetVertexBuffer(0, m_VB->m_Owner->GetBuffer()); | ||||
deviceCommandContext->SetIndexBuffer(m_VBIndices->m_Owner->GetBuffer()); | deviceCommandContext->SetIndexBuffer(m_VBIndices->m_Owner->GetBuffer()); | ||||
deviceCommandContext->DrawIndexed(m_VBIndices->m_Index, m_VBIndices->m_Count, 0); | deviceCommandContext->DrawIndexed(m_VBIndices->m_Index, m_VBIndices->m_Count, 0); | ||||
g_Renderer.GetStats().m_DrawCalls++; | g_Renderer.GetStats().m_DrawCalls++; | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | for (size_t i = 0; i < n; ++i) | ||||
// Adjust bisector length to match the line thickness, along the line's width | // Adjust bisector length to match the line thickness, along the line's width | ||||
float l = b.Dot((p2 - p1).Normalized().Cross(norm)); | float l = b.Dot((p2 - p1).Normalized().Cross(norm)); | ||||
if (fabs(l) > 0.000001f) // avoid unlikely divide-by-zero | if (fabs(l) > 0.000001f) // avoid unlikely divide-by-zero | ||||
b *= line.m_Thickness / l; | b *= line.m_Thickness / l; | ||||
// Push vertices and indices for each quad in GL_TRIANGLES order. The two triangles of each quad are indexed using | // Push vertices and indices for each quad in GL_TRIANGLES order. The two triangles of each quad are indexed using | ||||
// the winding orders (BR, BL, TR) and (TR, BL, TL) (where BR is bottom-right of this iteration's quad, TR top-right etc). | // the winding orders (BR, BL, TR) and (TR, BL, TL) (where BR is bottom-right of this iteration's quad, TR top-right etc). | ||||
SVertex vertex1(p1 + b + norm*OverlayRenderer::OVERLAY_VOFFSET, 0.f, v); | SVertex vertex1(p1 + b + norm * OverlayRenderer::OVERLAY_VOFFSET, CVector2D(0.f, v)); | ||||
SVertex vertex2(p1 - b + norm*OverlayRenderer::OVERLAY_VOFFSET, 1.f, v); | SVertex vertex2(p1 - b + norm * OverlayRenderer::OVERLAY_VOFFSET, CVector2D(1.f, v)); | ||||
vertices.push_back(vertex1); | vertices.push_back(vertex1); | ||||
vertices.push_back(vertex2); | vertices.push_back(vertex2); | ||||
u16 vertexCount = static_cast<u16>(vertices.size()); | u16 vertexCount = static_cast<u16>(vertices.size()); | ||||
u16 index1 = vertexCount - 2; // index of vertex1 in this iteration (TR of this quad) | u16 index1 = vertexCount - 2; // index of vertex1 in this iteration (TR of this quad) | ||||
u16 index2 = vertexCount - 1; // index of the vertex2 in this iteration (TL of this quad) | u16 index2 = vertexCount - 1; // index of the vertex2 in this iteration (TL of this quad) | ||||
if (i == 0) | if (i == 0) | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | if (n % 2 == 0) | ||||
indices.push_back(0); | indices.push_back(0); | ||||
indices.push_back(vertexCount - 1); | indices.push_back(vertexCount - 1); | ||||
indices.push_back(1); | indices.push_back(1); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
// add two vertices to have the good UVs for the last quad | // add two vertices to have the good UVs for the last quad | ||||
SVertex vertex1(vertices[0].m_Position, 0.f, 1.f); | SVertex vertex1(vertices[0].m_Position, CVector2D(0.f, 1.f)); | ||||
SVertex vertex2(vertices[1].m_Position, 1.f, 1.f); | SVertex vertex2(vertices[1].m_Position, CVector2D(1.f, 1.f)); | ||||
vertices.push_back(vertex1); | vertices.push_back(vertex1); | ||||
vertices.push_back(vertex2); | vertices.push_back(vertex2); | ||||
u16 vertexCount = static_cast<u16>(vertices.size()); | u16 vertexCount = static_cast<u16>(vertices.size()); | ||||
indices.push_back(vertexCount - 4); | indices.push_back(vertexCount - 4); | ||||
indices.push_back(vertexCount - 3); | indices.push_back(vertexCount - 3); | ||||
indices.push_back(vertexCount - 2); | indices.push_back(vertexCount - 2); | ||||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | void CTexturedLineRData::CreateLineCap(const SOverlayTexturedLine& line, const CVector3D& corner1, const CVector3D& corner2, | ||||
// | / | // | / | ||||
// ----+ / | // ----+ / | ||||
// | // | ||||
int roundCapPoints = 8; // amount of points to sample along the semicircle for rounded caps (including corner points) | int roundCapPoints = 8; // amount of points to sample along the semicircle for rounded caps (including corner points) | ||||
float radius = line.m_Thickness; | float radius = line.m_Thickness; | ||||
CVector3D centerPoint = (corner1 + corner2) * 0.5f; | CVector3D centerPoint = (corner1 + corner2) * 0.5f; | ||||
SVertex centerVertex(centerPoint, 0.5f, 0.5f); | SVertex centerVertex(centerPoint, CVector2D(0.5f, 0.5f)); | ||||
u16 indexOffset = static_cast<u16>(verticesOut.size()); // index offset in verticesOut from where we start adding our vertices | u16 indexOffset = static_cast<u16>(verticesOut.size()); // index offset in verticesOut from where we start adding our vertices | ||||
switch (endCapType) | switch (endCapType) | ||||
{ | { | ||||
case SOverlayTexturedLine::LINECAP_SHARP: | case SOverlayTexturedLine::LINECAP_SHARP: | ||||
{ | { | ||||
roundCapPoints = 3; // creates only one point directly ahead | roundCapPoints = 3; // creates only one point directly ahead | ||||
radius *= 1.5f; // make it a bit sharper (note that we don't use the radius for the butt-end corner points so it should be ok) | radius *= 1.5f; // make it a bit sharper (note that we don't use the radius for the butt-end corner points so it should be ok) | ||||
centerVertex.m_UVs[0] = 0.480f; // slight visual correction to make the texture match up better at the corner points | centerVertex.m_UV.X = 0.480f; // slight visual correction to make the texture match up better at the corner points | ||||
} | } | ||||
FALLTHROUGH; | FALLTHROUGH; | ||||
case SOverlayTexturedLine::LINECAP_ROUND: | case SOverlayTexturedLine::LINECAP_ROUND: | ||||
{ | { | ||||
// Draw a rounded line cap in the 3D plane of the line specified by the two corner points and the normal vector of the | // Draw a rounded line cap in the 3D plane of the line specified by the two corner points and the normal vector of the | ||||
// line's direction. The terrain normal at the centroid between the two corner points is perpendicular to this plane. | // line's direction. The terrain normal at the centroid between the two corner points is perpendicular to this plane. | ||||
// The way this works is by taking a vector from the corner points' centroid to one of the corner points (which is then | // The way this works is by taking a vector from the corner points' centroid to one of the corner points (which is then | ||||
// of radius length), and rotate it around the terrain normal vector in that centroid. This will rotate the vector in | // of radius length), and rotate it around the terrain normal vector in that centroid. This will rotate the vector in | ||||
// the line's plane, producing the desired rounded cap. | // the line's plane, producing the desired rounded cap. | ||||
// To please OpenGL's winding order, this angle needs to be negated depending on whether we start rotating from | // To please OpenGL's winding order, this angle needs to be negated depending on whether we start rotating from | ||||
// the (center -> corner1) or (center -> corner2) vector. For the (center -> corner2) vector, we apparently need to use | // the (center -> corner1) or (center -> corner2) vector. For the (center -> corner2) vector, we apparently need to use | ||||
// the negated angle. | // the negated angle. | ||||
float stepAngle = -(float)(M_PI/(roundCapPoints-1)); | float stepAngle = -(float)(M_PI/(roundCapPoints-1)); | ||||
// Push the vertices in triangle fan order (easy to generate GL_TRIANGLES indices for afterwards) | // Push the vertices in triangle fan order (easy to generate GL_TRIANGLES indices for afterwards) | ||||
// Note that we're manually adding the corner vertices instead of having them be generated by the rotating vector. | // Note that we're manually adding the corner vertices instead of having them be generated by the rotating vector. | ||||
// This is because we want to support an overly large radius to make the sharp line ending look sharper. | // This is because we want to support an overly large radius to make the sharp line ending look sharper. | ||||
verticesOut.push_back(centerVertex); | verticesOut.push_back(centerVertex); | ||||
verticesOut.push_back(SVertex(corner2, 0.f, 0.f)); | verticesOut.push_back(SVertex(corner2, CVector2D())); | ||||
// Get the base vector that we will incrementally rotate in the cap plane to produce the radial sample points. | // Get the base vector that we will incrementally rotate in the cap plane to produce the radial sample points. | ||||
// Normally corner2 - centerPoint would suffice for this since it is of radius length, but we want to support custom | // Normally corner2 - centerPoint would suffice for this since it is of radius length, but we want to support custom | ||||
// radii to support tuning the 'sharpness' of sharp end caps (see above) | // radii to support tuning the 'sharpness' of sharp end caps (see above) | ||||
CVector3D rotationBaseVector = (corner2 - centerPoint).Normalized() * radius; | CVector3D rotationBaseVector = (corner2 - centerPoint).Normalized() * radius; | ||||
// Calculate the normal vector of the plane in which we're going to be drawing the line cap. This is the vector that | // Calculate the normal vector of the plane in which we're going to be drawing the line cap. This is the vector that | ||||
// is perpendicular to both baseVector and the 'lineDirectionNormal' vector indicating the direction of the line. | // is perpendicular to both baseVector and the 'lineDirectionNormal' vector indicating the direction of the line. | ||||
// Note that we shouldn't use terrain->CalcExactNormal() here because if the line is being rendered on top of water, | // Note that we shouldn't use terrain->CalcExactNormal() here because if the line is being rendered on top of water, | ||||
// then CalcExactNormal will return the normal vector of the terrain that's underwater (which can be quite funky). | // then CalcExactNormal will return the normal vector of the terrain that's underwater (which can be quite funky). | ||||
CVector3D capPlaneNormal = lineDirectionNormal.Cross(rotationBaseVector).Normalized(); | CVector3D capPlaneNormal = lineDirectionNormal.Cross(rotationBaseVector).Normalized(); | ||||
for (int i = 1; i < roundCapPoints - 1; ++i) | for (int i = 1; i < roundCapPoints - 1; ++i) | ||||
{ | { | ||||
// Rotate the centerPoint -> corner vector by i*stepAngle radians around the cap plane normal at the center point. | // Rotate the centerPoint -> corner vector by i*stepAngle radians around the cap plane normal at the center point. | ||||
CQuaternion quatRotation; | CQuaternion quatRotation; | ||||
quatRotation.FromAxisAngle(capPlaneNormal, i * stepAngle); | quatRotation.FromAxisAngle(capPlaneNormal, i * stepAngle); | ||||
CVector3D worldPos3D = centerPoint + quatRotation.Rotate(rotationBaseVector); | CVector3D worldPos3D = centerPoint + quatRotation.Rotate(rotationBaseVector); | ||||
// Let v range from 0 to 1 as we move along the semi-circle, keep u fixed at 0 (i.e. curve the left vertical edge | // Let v range from 0 to 1 as we move along the semi-circle, keep u fixed at 0 (i.e. curve the left vertical edge | ||||
// of the texture around the edge of the semicircle) | // of the texture around the edge of the semicircle) | ||||
float u = 0.f; | float u = 0.f; | ||||
float v = Clamp((i / static_cast<float>(roundCapPoints - 1)), 0.f, 1.f); // pos, u, v | float v = Clamp((i / static_cast<float>(roundCapPoints - 1)), 0.f, 1.f); // pos, u, v | ||||
verticesOut.push_back(SVertex(worldPos3D, u, v)); | verticesOut.push_back(SVertex(worldPos3D, CVector2D(u, v))); | ||||
} | } | ||||
// connect back to the other butt-end corner point to complete the semicircle | // connect back to the other butt-end corner point to complete the semicircle | ||||
verticesOut.push_back(SVertex(corner1, 0.f, 1.f)); | verticesOut.push_back(SVertex(corner1, CVector2D(0.f, 1.f))); | ||||
// now push indices in GL_TRIANGLES order; vertices[indexOffset] is the center vertex, vertices[indexOffset + 1] is the | // now push indices in GL_TRIANGLES order; vertices[indexOffset] is the center vertex, vertices[indexOffset + 1] is the | ||||
// first corner point, then a bunch of radial samples, and then at the end we have the other corner point again. So: | // first corner point, then a bunch of radial samples, and then at the end we have the other corner point again. So: | ||||
for (int i=1; i < roundCapPoints; ++i) | for (int i=1; i < roundCapPoints; ++i) | ||||
{ | { | ||||
indicesOut.push_back(indexOffset); // center vertex | indicesOut.push_back(indexOffset); // center vertex | ||||
indicesOut.push_back(indexOffset + i); | indicesOut.push_back(indexOffset + i); | ||||
indicesOut.push_back(indexOffset + i + 1); | indicesOut.push_back(indexOffset + i + 1); | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case SOverlayTexturedLine::LINECAP_SQUARE: | case SOverlayTexturedLine::LINECAP_SQUARE: | ||||
{ | { | ||||
// Extend the (corner1 -> corner2) vector along the direction normal and draw a square line ending consisting of | // Extend the (corner1 -> corner2) vector along the direction normal and draw a square line ending consisting of | ||||
// three triangles (sort of like a triangle fan) | // three triangles (sort of like a triangle fan) | ||||
// NOTE: The order in which the vertices are pushed out determines the visibility, as they | // NOTE: The order in which the vertices are pushed out determines the visibility, as they | ||||
// are rendered only one-sided; the wrong order of vertices will make the cap visible only from the bottom. | // are rendered only one-sided; the wrong order of vertices will make the cap visible only from the bottom. | ||||
verticesOut.push_back(centerVertex); | verticesOut.push_back(centerVertex); | ||||
verticesOut.push_back(SVertex(corner2, 0.f, 0.f)); | verticesOut.push_back(SVertex(corner2, CVector2D())); | ||||
verticesOut.push_back(SVertex(corner2 + (lineDirectionNormal * (line.m_Thickness)), 0.f, 0.33333f)); // extend butt corner point 2 along the normal vector | verticesOut.push_back(SVertex(corner2 + (lineDirectionNormal * (line.m_Thickness)), CVector2D(0.f, 0.33333f))); // extend butt corner point 2 along the normal vector | ||||
verticesOut.push_back(SVertex(corner1 + (lineDirectionNormal * (line.m_Thickness)), 0.f, 0.66666f)); // extend butt corner point 1 along the normal vector | verticesOut.push_back(SVertex(corner1 + (lineDirectionNormal * (line.m_Thickness)), CVector2D(0.f, 0.66666f))); // extend butt corner point 1 along the normal vector | ||||
verticesOut.push_back(SVertex(corner1, 0.f, 1.0f)); // push butt corner point 1 | verticesOut.push_back(SVertex(corner1, CVector2D(0.f, 1.0f))); // push butt corner point 1 | ||||
for (int i=1; i < 4; ++i) | for (int i=1; i < 4; ++i) | ||||
{ | { | ||||
indicesOut.push_back(indexOffset); // center point | indicesOut.push_back(indexOffset); // center point | ||||
indicesOut.push_back(indexOffset + i); | indicesOut.push_back(indexOffset + i); | ||||
indicesOut.push_back(indexOffset + i + 1); | indicesOut.push_back(indexOffset + i + 1); | ||||
} | } | ||||
} | } | ||||
Show All 12 Lines |
Wildfire Games · Phabricator