mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Merge pull request #9352 from Pokechu22/sw-line-point-width
Software: Implement line-width and point-width
This commit is contained in:
@ -331,18 +331,36 @@ void ProcessTriangle(OutputVertexData* v0, OutputVertexData* v1, OutputVertexDat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CopyVertex(OutputVertexData* dst, const OutputVertexData* src, float dx, float dy,
|
constexpr std::array<float, 8> LINE_PT_TEX_OFFSETS = {
|
||||||
unsigned int sOffset)
|
0, 1 / 16.f, 1 / 8.f, 1 / 4.f, 1 / 2.f, 1, 1, 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void CopyLineVertex(OutputVertexData* dst, const OutputVertexData* src, int px, int py,
|
||||||
|
bool apply_line_offset)
|
||||||
{
|
{
|
||||||
dst->screenPosition.x = src->screenPosition.x + dx;
|
const float line_half_width = bpmem.lineptwidth.linesize / 12.0f;
|
||||||
dst->screenPosition.y = src->screenPosition.y + dy;
|
|
||||||
|
dst->projectedPosition = src->projectedPosition;
|
||||||
|
dst->screenPosition.x = src->screenPosition.x + px * line_half_width;
|
||||||
|
dst->screenPosition.y = src->screenPosition.y + py * line_half_width;
|
||||||
dst->screenPosition.z = src->screenPosition.z;
|
dst->screenPosition.z = src->screenPosition.z;
|
||||||
|
|
||||||
dst->normal = src->normal;
|
dst->normal = src->normal;
|
||||||
dst->color = src->color;
|
dst->color = src->color;
|
||||||
|
|
||||||
// todo - s offset
|
|
||||||
dst->texCoords = src->texCoords;
|
dst->texCoords = src->texCoords;
|
||||||
|
|
||||||
|
if (apply_line_offset && LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff] != 0)
|
||||||
|
{
|
||||||
|
for (u32 coord_num = 0; coord_num < xfmem.numTexGen.numTexGens; coord_num++)
|
||||||
|
{
|
||||||
|
if (bpmem.texcoords[coord_num].s.line_offset)
|
||||||
|
{
|
||||||
|
dst->texCoords[coord_num].x += (bpmem.texcoords[coord_num].s.scale_minus_1 + 1) *
|
||||||
|
LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessLine(OutputVertexData* lineV0, OutputVertexData* lineV1)
|
void ProcessLine(OutputVertexData* lineV0, OutputVertexData* lineV1)
|
||||||
@ -365,42 +383,85 @@ void ProcessLine(OutputVertexData* lineV0, OutputVertexData* lineV1)
|
|||||||
PerspectiveDivide(v0);
|
PerspectiveDivide(v0);
|
||||||
PerspectiveDivide(v1);
|
PerspectiveDivide(v1);
|
||||||
|
|
||||||
float dx = v1->screenPosition.x - v0->screenPosition.x;
|
const float dx = v1->screenPosition.x - v0->screenPosition.x;
|
||||||
float dy = v1->screenPosition.y - v0->screenPosition.y;
|
const float dy = v1->screenPosition.y - v0->screenPosition.y;
|
||||||
|
|
||||||
float screenDx = 0;
|
int px = 0;
|
||||||
float screenDy = 0;
|
int py = 0;
|
||||||
|
|
||||||
|
// GameCube/Wii's line drawing algorithm is a little quirky. It does not
|
||||||
|
// use the correct line caps. Instead, the line caps are vertical or
|
||||||
|
// horizontal depending the slope of the line.
|
||||||
|
// FIXME: What does real hardware do when line is at a 45-degree angle?
|
||||||
|
|
||||||
|
// Note that py or px are set positive or negative to ensure that the triangles are drawn ccw.
|
||||||
if (fabsf(dx) > fabsf(dy))
|
if (fabsf(dx) > fabsf(dy))
|
||||||
{
|
py = (dx > 0) ? -1 : 1;
|
||||||
if (dx > 0)
|
|
||||||
screenDy = bpmem.lineptwidth.linesize / -12.0f;
|
|
||||||
else
|
|
||||||
screenDy = bpmem.lineptwidth.linesize / 12.0f;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
px = (dy > 0) ? 1 : -1;
|
||||||
if (dy > 0)
|
|
||||||
screenDx = bpmem.lineptwidth.linesize / 12.0f;
|
|
||||||
else
|
|
||||||
screenDx = bpmem.lineptwidth.linesize / -12.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputVertexData triangle[3];
|
OutputVertexData triangle[3];
|
||||||
|
|
||||||
CopyVertex(&triangle[0], v0, screenDx, screenDy, 0);
|
CopyLineVertex(&triangle[0], v0, px, py, false);
|
||||||
CopyVertex(&triangle[1], v1, screenDx, screenDy, 0);
|
CopyLineVertex(&triangle[1], v1, px, py, false);
|
||||||
CopyVertex(&triangle[2], v1, -screenDx, -screenDy, bpmem.lineptwidth.lineoff);
|
CopyLineVertex(&triangle[2], v1, -px, -py, true);
|
||||||
|
|
||||||
// ccw winding
|
// ccw winding
|
||||||
Rasterizer::DrawTriangleFrontFace(&triangle[2], &triangle[1], &triangle[0]);
|
Rasterizer::DrawTriangleFrontFace(&triangle[2], &triangle[1], &triangle[0]);
|
||||||
|
|
||||||
CopyVertex(&triangle[1], v0, -screenDx, -screenDy, bpmem.lineptwidth.lineoff);
|
CopyLineVertex(&triangle[1], v0, -px, -py, true);
|
||||||
|
|
||||||
Rasterizer::DrawTriangleFrontFace(&triangle[0], &triangle[1], &triangle[2]);
|
Rasterizer::DrawTriangleFrontFace(&triangle[0], &triangle[1], &triangle[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CopyPointVertex(OutputVertexData* dst, const OutputVertexData* src, bool px, bool py)
|
||||||
|
{
|
||||||
|
const float point_radius = bpmem.lineptwidth.pointsize / 12.0f;
|
||||||
|
|
||||||
|
dst->projectedPosition = src->projectedPosition;
|
||||||
|
dst->screenPosition.x = src->screenPosition.x + (px ? 1 : -1) * point_radius;
|
||||||
|
dst->screenPosition.y = src->screenPosition.y + (py ? 1 : -1) * point_radius;
|
||||||
|
dst->screenPosition.z = src->screenPosition.z;
|
||||||
|
|
||||||
|
dst->normal = src->normal;
|
||||||
|
dst->color = src->color;
|
||||||
|
|
||||||
|
dst->texCoords = src->texCoords;
|
||||||
|
|
||||||
|
const float point_offset = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff];
|
||||||
|
if (point_offset != 0)
|
||||||
|
{
|
||||||
|
for (u32 coord_num = 0; coord_num < xfmem.numTexGen.numTexGens; coord_num++)
|
||||||
|
{
|
||||||
|
const auto coord_info = bpmem.texcoords[coord_num];
|
||||||
|
if (coord_info.s.point_offset)
|
||||||
|
{
|
||||||
|
if (px)
|
||||||
|
dst->texCoords[coord_num].x += (coord_info.s.scale_minus_1 + 1) * point_offset;
|
||||||
|
if (py)
|
||||||
|
dst->texCoords[coord_num].y += (coord_info.t.scale_minus_1 + 1) * point_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessPoint(OutputVertexData* center)
|
||||||
|
{
|
||||||
|
// TODO: This isn't actually doing any clipping
|
||||||
|
PerspectiveDivide(center);
|
||||||
|
|
||||||
|
OutputVertexData ll, lr, ul, ur;
|
||||||
|
|
||||||
|
CopyPointVertex(&ll, center, false, false);
|
||||||
|
CopyPointVertex(&lr, center, true, false);
|
||||||
|
CopyPointVertex(&ur, center, true, true);
|
||||||
|
CopyPointVertex(&ul, center, false, true);
|
||||||
|
|
||||||
|
Rasterizer::DrawTriangleFrontFace(&ll, &ul, &lr);
|
||||||
|
Rasterizer::DrawTriangleFrontFace(&ur, &lr, &ul);
|
||||||
|
}
|
||||||
|
|
||||||
bool CullTest(const OutputVertexData* v0, const OutputVertexData* v1, const OutputVertexData* v2,
|
bool CullTest(const OutputVertexData* v0, const OutputVertexData* v1, const OutputVertexData* v2,
|
||||||
bool& backface)
|
bool& backface)
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,8 @@ void ProcessTriangle(OutputVertexData* v0, OutputVertexData* v1, OutputVertexDat
|
|||||||
|
|
||||||
void ProcessLine(OutputVertexData* v0, OutputVertexData* v1);
|
void ProcessLine(OutputVertexData* v0, OutputVertexData* v1);
|
||||||
|
|
||||||
|
void ProcessPoint(OutputVertexData* v);
|
||||||
|
|
||||||
bool CullTest(const OutputVertexData* v0, const OutputVertexData* v1, const OutputVertexData* v2,
|
bool CullTest(const OutputVertexData* v0, const OutputVertexData* v1, const OutputVertexData* v2,
|
||||||
bool& backface);
|
bool& backface);
|
||||||
|
|
||||||
|
@ -167,4 +167,5 @@ void SetupUnit::SetupLineStrip()
|
|||||||
|
|
||||||
void SetupUnit::SetupPoint()
|
void SetupUnit::SetupPoint()
|
||||||
{
|
{
|
||||||
|
Clipper::ProcessPoint(m_VertPointer[0]);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user