- Clean up PolyTriangleDrawer API so that it can better support both softpoly and the swrenderer
- Slightly improve how softpoly processes portals - Pass the vertex transform matrix via a command rather than being part of the drawer args - Improve zbuffer drawers in the software renderer - Misc model rendering fixes
This commit is contained in:
parent
cb3650ed9e
commit
2d51fa5b43
54 changed files with 1210 additions and 843 deletions
|
|
@ -39,52 +39,69 @@
|
|||
#include "screen_triangle.h"
|
||||
#include "x86.h"
|
||||
|
||||
int PolyTriangleDrawer::viewport_x;
|
||||
int PolyTriangleDrawer::viewport_y;
|
||||
int PolyTriangleDrawer::viewport_width;
|
||||
int PolyTriangleDrawer::viewport_height;
|
||||
int PolyTriangleDrawer::dest_pitch;
|
||||
int PolyTriangleDrawer::dest_width;
|
||||
int PolyTriangleDrawer::dest_height;
|
||||
uint8_t *PolyTriangleDrawer::dest;
|
||||
bool PolyTriangleDrawer::dest_bgra;
|
||||
bool PolyTriangleDrawer::mirror;
|
||||
|
||||
void PolyTriangleDrawer::set_viewport(int x, int y, int width, int height, DCanvas *canvas)
|
||||
void PolyTriangleDrawer::ClearBuffers(DCanvas *canvas)
|
||||
{
|
||||
dest = (uint8_t*)canvas->GetBuffer();
|
||||
dest_width = canvas->GetWidth();
|
||||
dest_height = canvas->GetHeight();
|
||||
dest_pitch = canvas->GetPitch();
|
||||
dest_bgra = canvas->IsBgra();
|
||||
PolyStencilBuffer::Instance()->Clear(canvas->GetWidth(), canvas->GetHeight(), 0);
|
||||
PolyZBuffer::Instance()->Resize(canvas->GetPitch(), canvas->GetHeight());
|
||||
}
|
||||
|
||||
void PolyTriangleDrawer::SetViewport(const DrawerCommandQueuePtr &queue, int x, int y, int width, int height, DCanvas *canvas, bool span_drawers)
|
||||
{
|
||||
uint8_t *dest = (uint8_t*)canvas->GetBuffer();
|
||||
int dest_width = canvas->GetWidth();
|
||||
int dest_height = canvas->GetHeight();
|
||||
int dest_pitch = canvas->GetPitch();
|
||||
bool dest_bgra = canvas->IsBgra();
|
||||
|
||||
int offsetx = clamp(x, 0, dest_width);
|
||||
int offsety = clamp(y, 0, dest_height);
|
||||
int pixelsize = dest_bgra ? 4 : 1;
|
||||
|
||||
viewport_x = x - offsetx;
|
||||
viewport_y = y - offsety;
|
||||
viewport_width = width;
|
||||
viewport_height = height;
|
||||
int viewport_x = x - offsetx;
|
||||
int viewport_y = y - offsety;
|
||||
int viewport_width = width;
|
||||
int viewport_height = height;
|
||||
|
||||
dest += (offsetx + offsety * dest_pitch) * pixelsize;
|
||||
dest_width = clamp(viewport_x + viewport_width, 0, dest_width - offsetx);
|
||||
dest_height = clamp(viewport_y + viewport_height, 0, dest_height - offsety);
|
||||
|
||||
queue->Push<PolySetViewportCommand>(viewport_x, viewport_y, viewport_width, viewport_height, dest, dest_width, dest_height, dest_pitch, dest_bgra, span_drawers);
|
||||
}
|
||||
|
||||
void PolyTriangleDrawer::SetTransform(const DrawerCommandQueuePtr &queue, const Mat4f *objectToClip)
|
||||
{
|
||||
queue->Push<PolySetTransformCommand>(objectToClip);
|
||||
}
|
||||
|
||||
void PolyTriangleDrawer::ToggleMirror(const DrawerCommandQueuePtr &queue)
|
||||
{
|
||||
queue->Push<PolyToggleMirrorCommand>();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyTriangleThreadData::SetViewport(int x, int y, int width, int height, uint8_t *new_dest, int new_dest_width, int new_dest_height, int new_dest_pitch, bool new_dest_bgra, bool new_span_drawers)
|
||||
{
|
||||
viewport_x = x;
|
||||
viewport_y = y;
|
||||
viewport_width = width;
|
||||
viewport_height = height;
|
||||
dest = new_dest;
|
||||
dest_width = new_dest_width;
|
||||
dest_height = new_dest_height;
|
||||
dest_pitch = new_dest_pitch;
|
||||
dest_bgra = new_dest_bgra;
|
||||
span_drawers = new_span_drawers;
|
||||
mirror = false;
|
||||
}
|
||||
|
||||
void PolyTriangleDrawer::toggle_mirror()
|
||||
void PolyTriangleThreadData::SetTransform(const Mat4f *newObjectToClip)
|
||||
{
|
||||
mirror = !mirror;
|
||||
objectToClip = newObjectToClip;
|
||||
}
|
||||
|
||||
bool PolyTriangleDrawer::is_mirror()
|
||||
{
|
||||
return mirror;
|
||||
}
|
||||
|
||||
void PolyTriangleDrawer::draw_elements(const PolyDrawArgs &drawargs, WorkerThreadData *thread)
|
||||
void PolyTriangleThreadData::DrawElements(const PolyDrawArgs &drawargs)
|
||||
{
|
||||
if (drawargs.VertexCount() < 3)
|
||||
return;
|
||||
|
|
@ -101,7 +118,7 @@ void PolyTriangleDrawer::draw_elements(const PolyDrawArgs &drawargs, WorkerThrea
|
|||
args.stencilMasks = PolyStencilBuffer::Instance()->Masks();
|
||||
args.zbuffer = PolyZBuffer::Instance()->Values();
|
||||
|
||||
bool ccw = drawargs.FaceCullCCW();
|
||||
bool ccw = !mirror;
|
||||
const TriVertex *vinput = drawargs.Vertices();
|
||||
const unsigned int *elements = drawargs.Elements();
|
||||
int vcount = drawargs.VertexCount();
|
||||
|
|
@ -112,29 +129,29 @@ void PolyTriangleDrawer::draw_elements(const PolyDrawArgs &drawargs, WorkerThrea
|
|||
for (int i = 0; i < vcount / 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
vert[j] = shade_vertex(drawargs, vinput[*(elements++)]);
|
||||
draw_shaded_triangle(vert, ccw, &args, thread);
|
||||
vert[j] = ShadeVertex(drawargs, vinput[*(elements++)]);
|
||||
DrawShadedTriangle(vert, ccw, &args);
|
||||
}
|
||||
}
|
||||
else if (drawargs.DrawMode() == PolyDrawMode::TriangleFan)
|
||||
{
|
||||
vert[0] = shade_vertex(drawargs, vinput[*(elements++)]);
|
||||
vert[1] = shade_vertex(drawargs, vinput[*(elements++)]);
|
||||
vert[0] = ShadeVertex(drawargs, vinput[*(elements++)]);
|
||||
vert[1] = ShadeVertex(drawargs, vinput[*(elements++)]);
|
||||
for (int i = 2; i < vcount; i++)
|
||||
{
|
||||
vert[2] = shade_vertex(drawargs, vinput[*(elements++)]);
|
||||
draw_shaded_triangle(vert, ccw, &args, thread);
|
||||
vert[2] = ShadeVertex(drawargs, vinput[*(elements++)]);
|
||||
DrawShadedTriangle(vert, ccw, &args);
|
||||
vert[1] = vert[2];
|
||||
}
|
||||
}
|
||||
else // TriangleDrawMode::TriangleStrip
|
||||
{
|
||||
vert[0] = shade_vertex(drawargs, vinput[*(elements++)]);
|
||||
vert[1] = shade_vertex(drawargs, vinput[*(elements++)]);
|
||||
vert[0] = ShadeVertex(drawargs, vinput[*(elements++)]);
|
||||
vert[1] = ShadeVertex(drawargs, vinput[*(elements++)]);
|
||||
for (int i = 2; i < vcount; i++)
|
||||
{
|
||||
vert[2] = shade_vertex(drawargs, vinput[*(elements++)]);
|
||||
draw_shaded_triangle(vert, ccw, &args, thread);
|
||||
vert[2] = ShadeVertex(drawargs, vinput[*(elements++)]);
|
||||
DrawShadedTriangle(vert, ccw, &args);
|
||||
vert[0] = vert[1];
|
||||
vert[1] = vert[2];
|
||||
ccw = !ccw;
|
||||
|
|
@ -142,7 +159,7 @@ void PolyTriangleDrawer::draw_elements(const PolyDrawArgs &drawargs, WorkerThrea
|
|||
}
|
||||
}
|
||||
|
||||
void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, WorkerThreadData *thread)
|
||||
void PolyTriangleThreadData::DrawArrays(const PolyDrawArgs &drawargs)
|
||||
{
|
||||
if (drawargs.VertexCount() < 3)
|
||||
return;
|
||||
|
|
@ -159,7 +176,7 @@ void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, WorkerThreadD
|
|||
args.stencilMasks = PolyStencilBuffer::Instance()->Masks();
|
||||
args.zbuffer = PolyZBuffer::Instance()->Values();
|
||||
|
||||
bool ccw = drawargs.FaceCullCCW();
|
||||
bool ccw = !mirror;
|
||||
const TriVertex *vinput = drawargs.Vertices();
|
||||
int vcount = drawargs.VertexCount();
|
||||
|
||||
|
|
@ -169,29 +186,29 @@ void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, WorkerThreadD
|
|||
for (int i = 0; i < vcount / 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
vert[j] = shade_vertex(drawargs, *(vinput++));
|
||||
draw_shaded_triangle(vert, ccw, &args, thread);
|
||||
vert[j] = ShadeVertex(drawargs, *(vinput++));
|
||||
DrawShadedTriangle(vert, ccw, &args);
|
||||
}
|
||||
}
|
||||
else if (drawargs.DrawMode() == PolyDrawMode::TriangleFan)
|
||||
{
|
||||
vert[0] = shade_vertex(drawargs, *(vinput++));
|
||||
vert[1] = shade_vertex(drawargs, *(vinput++));
|
||||
vert[0] = ShadeVertex(drawargs, *(vinput++));
|
||||
vert[1] = ShadeVertex(drawargs, *(vinput++));
|
||||
for (int i = 2; i < vcount; i++)
|
||||
{
|
||||
vert[2] = shade_vertex(drawargs, *(vinput++));
|
||||
draw_shaded_triangle(vert, ccw, &args, thread);
|
||||
vert[2] = ShadeVertex(drawargs, *(vinput++));
|
||||
DrawShadedTriangle(vert, ccw, &args);
|
||||
vert[1] = vert[2];
|
||||
}
|
||||
}
|
||||
else // TriangleDrawMode::TriangleStrip
|
||||
{
|
||||
vert[0] = shade_vertex(drawargs, *(vinput++));
|
||||
vert[1] = shade_vertex(drawargs, *(vinput++));
|
||||
vert[0] = ShadeVertex(drawargs, *(vinput++));
|
||||
vert[1] = ShadeVertex(drawargs, *(vinput++));
|
||||
for (int i = 2; i < vcount; i++)
|
||||
{
|
||||
vert[2] = shade_vertex(drawargs, *(vinput++));
|
||||
draw_shaded_triangle(vert, ccw, &args, thread);
|
||||
vert[2] = ShadeVertex(drawargs, *(vinput++));
|
||||
DrawShadedTriangle(vert, ccw, &args);
|
||||
vert[0] = vert[1];
|
||||
vert[1] = vert[2];
|
||||
ccw = !ccw;
|
||||
|
|
@ -199,12 +216,10 @@ void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, WorkerThreadD
|
|||
}
|
||||
}
|
||||
|
||||
ShadedTriVertex PolyTriangleDrawer::shade_vertex(const PolyDrawArgs &drawargs, const TriVertex &v)
|
||||
ShadedTriVertex PolyTriangleThreadData::ShadeVertex(const PolyDrawArgs &drawargs, const TriVertex &v)
|
||||
{
|
||||
const TriMatrix &objectToClip = *drawargs.ObjectToClip();
|
||||
|
||||
// Apply transform to get clip coordinates:
|
||||
FVector4 position = objectToClip * FVector4(v.x, v.y, v.z, v.w);
|
||||
Vec4f position = (*objectToClip) * Vec4f(v.x, v.y, v.z, v.w);
|
||||
|
||||
ShadedTriVertex sv;
|
||||
sv.x = position.X;
|
||||
|
|
@ -227,7 +242,7 @@ ShadedTriVertex PolyTriangleDrawer::shade_vertex(const PolyDrawArgs &drawargs, c
|
|||
return sv;
|
||||
}
|
||||
|
||||
bool PolyTriangleDrawer::is_degenerate(const ShadedTriVertex *vert)
|
||||
bool PolyTriangleThreadData::IsDegenerate(const ShadedTriVertex *vert)
|
||||
{
|
||||
// A degenerate triangle has a zero cross product for two of its sides.
|
||||
float ax = vert[1].x - vert[0].x;
|
||||
|
|
@ -243,7 +258,7 @@ bool PolyTriangleDrawer::is_degenerate(const ShadedTriVertex *vert)
|
|||
return crosslengthsqr <= 1.e-6f;
|
||||
}
|
||||
|
||||
bool PolyTriangleDrawer::is_frontfacing(TriDrawTriangleArgs *args)
|
||||
bool PolyTriangleThreadData::IsFrontfacing(TriDrawTriangleArgs *args)
|
||||
{
|
||||
float a =
|
||||
args->v1->x * args->v2->y - args->v2->x * args->v1->y +
|
||||
|
|
@ -252,15 +267,15 @@ bool PolyTriangleDrawer::is_frontfacing(TriDrawTriangleArgs *args)
|
|||
return a <= 0.0f;
|
||||
}
|
||||
|
||||
void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread)
|
||||
void PolyTriangleThreadData::DrawShadedTriangle(const ShadedTriVertex *vert, bool ccw, TriDrawTriangleArgs *args)
|
||||
{
|
||||
// Reject triangle if degenerate
|
||||
if (is_degenerate(vert))
|
||||
if (IsDegenerate(vert))
|
||||
return;
|
||||
|
||||
// Cull, clip and generate additional vertices as needed
|
||||
ShadedTriVertex clippedvert[max_additional_vertices];
|
||||
int numclipvert = clipedge(vert, clippedvert);
|
||||
int numclipvert = ClipEdge(vert, clippedvert);
|
||||
|
||||
#ifdef NO_SSE
|
||||
// Map to 2D viewport:
|
||||
|
|
@ -333,8 +348,13 @@ void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool
|
|||
args->v1 = &clippedvert[numclipvert - 1];
|
||||
args->v2 = &clippedvert[i - 1];
|
||||
args->v3 = &clippedvert[i - 2];
|
||||
if (is_frontfacing(args) == ccw && args->CalculateGradients())
|
||||
ScreenTriangle::Draw(args, thread);
|
||||
if (IsFrontfacing(args) == ccw && args->CalculateGradients())
|
||||
{
|
||||
if (!span_drawers)
|
||||
ScreenTriangle::Draw(args, this);
|
||||
else
|
||||
ScreenTriangle::DrawSWRender(args, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -344,13 +364,18 @@ void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool
|
|||
args->v1 = &clippedvert[0];
|
||||
args->v2 = &clippedvert[i - 1];
|
||||
args->v3 = &clippedvert[i];
|
||||
if (is_frontfacing(args) != ccw && args->CalculateGradients())
|
||||
ScreenTriangle::Draw(args, thread);
|
||||
if (IsFrontfacing(args) != ccw && args->CalculateGradients())
|
||||
{
|
||||
if (!span_drawers)
|
||||
ScreenTriangle::Draw(args, this);
|
||||
else
|
||||
ScreenTriangle::DrawSWRender(args, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, ShadedTriVertex *clippedvert)
|
||||
int PolyTriangleThreadData::ClipEdge(const ShadedTriVertex *verts, ShadedTriVertex *clippedvert)
|
||||
{
|
||||
// Clip and cull so that the following is true for all vertices:
|
||||
// -v.w <= v.x <= v.w
|
||||
|
|
@ -524,35 +549,61 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, ShadedTriVertex *
|
|||
return inputverts;
|
||||
}
|
||||
|
||||
PolyTriangleThreadData *PolyTriangleThreadData::Get(DrawerThread *thread)
|
||||
{
|
||||
if (!thread->poly)
|
||||
thread->poly = std::make_shared<PolyTriangleThreadData>(thread->core, thread->num_cores);
|
||||
return thread->poly.get();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DrawPolyTrianglesCommand::DrawPolyTrianglesCommand(const PolyDrawArgs &args, bool mirror)
|
||||
: args(args)
|
||||
PolySetTransformCommand::PolySetTransformCommand(const Mat4f *objectToClip) : objectToClip(objectToClip)
|
||||
{
|
||||
}
|
||||
|
||||
void PolySetTransformCommand::Execute(DrawerThread *thread)
|
||||
{
|
||||
PolyTriangleThreadData::Get(thread)->SetTransform(objectToClip);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyToggleMirrorCommand::Execute(DrawerThread *thread)
|
||||
{
|
||||
PolyTriangleThreadData::Get(thread)->ToggleMirror();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolySetViewportCommand::PolySetViewportCommand(int x, int y, int width, int height, uint8_t *dest, int dest_width, int dest_height, int dest_pitch, bool dest_bgra, bool span_drawers)
|
||||
: x(x), y(y), width(width), height(height), dest(dest), dest_width(dest_width), dest_height(dest_height), dest_pitch(dest_pitch), dest_bgra(dest_bgra), span_drawers(span_drawers)
|
||||
{
|
||||
}
|
||||
|
||||
void PolySetViewportCommand::Execute(DrawerThread *thread)
|
||||
{
|
||||
PolyTriangleThreadData::Get(thread)->SetViewport(x, y, width, height, dest, dest_width, dest_height, dest_pitch, dest_bgra, span_drawers);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DrawPolyTrianglesCommand::DrawPolyTrianglesCommand(const PolyDrawArgs &args) : args(args)
|
||||
{
|
||||
if (mirror)
|
||||
this->args.SetFaceCullCCW(!this->args.FaceCullCCW());
|
||||
}
|
||||
|
||||
void DrawPolyTrianglesCommand::Execute(DrawerThread *thread)
|
||||
{
|
||||
WorkerThreadData thread_data;
|
||||
thread_data.core = thread->core;
|
||||
thread_data.num_cores = thread->num_cores;
|
||||
|
||||
if (!args.Elements())
|
||||
PolyTriangleDrawer::draw_arrays(args, &thread_data);
|
||||
PolyTriangleThreadData::Get(thread)->DrawArrays(args);
|
||||
else
|
||||
PolyTriangleDrawer::draw_elements(args, &thread_data);
|
||||
PolyTriangleThreadData::Get(thread)->DrawElements(args);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DrawRectCommand::Execute(DrawerThread *thread)
|
||||
{
|
||||
WorkerThreadData thread_data;
|
||||
thread_data.core = thread->core;
|
||||
thread_data.num_cores = thread->num_cores;
|
||||
|
||||
auto renderTarget = PolyRenderer::Instance()->RenderTarget;
|
||||
const void *destOrg = renderTarget->GetBuffer();
|
||||
int destWidth = renderTarget->GetWidth();
|
||||
|
|
@ -560,7 +611,7 @@ void DrawRectCommand::Execute(DrawerThread *thread)
|
|||
int destPitch = renderTarget->GetPitch();
|
||||
int blendmode = (int)args.BlendMode();
|
||||
if (renderTarget->IsBgra())
|
||||
ScreenTriangle::RectDrawers32[blendmode](destOrg, destWidth, destHeight, destPitch, &args, &thread_data);
|
||||
ScreenTriangle::RectDrawers32[blendmode](destOrg, destWidth, destHeight, destPitch, &args, PolyTriangleThreadData::Get(thread));
|
||||
else
|
||||
ScreenTriangle::RectDrawers8[blendmode](destOrg, destWidth, destHeight, destPitch, &args, &thread_data);
|
||||
ScreenTriangle::RectDrawers8[blendmode](destOrg, destWidth, destHeight, destPitch, &args, PolyTriangleThreadData::Get(thread));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue