diff --git a/src/rendering/polyrenderer/backend/poly_buffers.cpp b/src/rendering/polyrenderer/backend/poly_buffers.cpp index fd0ead6ea..e186b7a71 100644 --- a/src/rendering/polyrenderer/backend/poly_buffers.cpp +++ b/src/rendering/polyrenderer/backend/poly_buffers.cpp @@ -83,29 +83,14 @@ void PolyVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t mStride = stride; } -ShadedTriVertex PolyVertexBuffer::Shade(PolyTriangleThreadData *thread, const PolyDrawArgs &drawargs, const void *vertices, int index) +void PolyVertexBuffer::Load(PolyTriangleThreadData *thread, const void *vertices, int index) { const uint8_t *vertex = static_cast(vertices) + mStride * index; const float *attrVertex = reinterpret_cast(vertex + mOffsets[VATTR_VERTEX]); const float *attrTexcoord = reinterpret_cast(vertex + mOffsets[VATTR_TEXCOORD]); - Vec4f objpos = Vec4f(attrVertex[0], attrVertex[1], attrVertex[2], 1.0f); - Vec4f clippos = (*thread->objectToClip) * objpos; - - ShadedTriVertex sv; - sv.u = attrTexcoord[1]; - sv.v = attrTexcoord[0]; - sv.x = clippos.X; - sv.y = clippos.Y; - sv.z = clippos.Z; - sv.w = clippos.W; - sv.worldX = objpos.X; - sv.worldY = objpos.Y; - sv.worldZ = objpos.Z; - sv.clipDistance[0] = 1.0f; - sv.clipDistance[1] = 1.0f; - sv.clipDistance[2] = 1.0f; - return sv; + thread->mainVertexShader.aPosition = { attrVertex[0], attrVertex[1], attrVertex[2], 1.0f }; + thread->mainVertexShader.aTexCoord = { attrTexcoord[0], attrTexcoord[1] }; } ///////////////////////////////////////////////////////////////////////////// diff --git a/src/rendering/polyrenderer/backend/poly_buffers.h b/src/rendering/polyrenderer/backend/poly_buffers.h index 2ad9e11f9..b4e183194 100644 --- a/src/rendering/polyrenderer/backend/poly_buffers.h +++ b/src/rendering/polyrenderer/backend/poly_buffers.h @@ -39,13 +39,13 @@ private: std::vector mData; }; -class PolyVertexBuffer : public IVertexBuffer, public PolyBuffer, public PolyVertexShader +class PolyVertexBuffer : public IVertexBuffer, public PolyBuffer, public PolyInputAssembly { public: PolyVertexBuffer() { } void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) override; - ShadedTriVertex Shade(PolyTriangleThreadData *thread, const PolyDrawArgs &drawargs, const void *vertices, int index) override; + void Load(PolyTriangleThreadData *thread, const void *vertices, int index) override; private: size_t mOffsets[VATTR_MAX] = {}; diff --git a/src/rendering/polyrenderer/backend/poly_renderstate.cpp b/src/rendering/polyrenderer/backend/poly_renderstate.cpp index ea1148d1a..6b99db945 100644 --- a/src/rendering/polyrenderer/backend/poly_renderstate.cpp +++ b/src/rendering/polyrenderer/backend/poly_renderstate.cpp @@ -26,6 +26,7 @@ static PolyDrawMode dtToDrawMode[] = PolyRenderState::PolyRenderState() { + mIdentityMatrix.loadIdentity(); Reset(); } @@ -175,23 +176,71 @@ void PolyRenderState::Apply() auto fb = GetPolyFrameBuffer(); if (mVertexBuffer) PolyTriangleDrawer::SetVertexBuffer(fb->GetDrawCommands(), mVertexBuffer->Memory()); if (mIndexBuffer) PolyTriangleDrawer::SetIndexBuffer(fb->GetDrawCommands(), mIndexBuffer->Memory()); - PolyTriangleDrawer::SetVertexShader(fb->GetDrawCommands(), static_cast(mVertexBuffer)); + PolyTriangleDrawer::SetInputAssembly(fb->GetDrawCommands(), static_cast(mVertexBuffer)); + + ApplyMatrices(); + + PolyTriangleDrawer::PushStreamData(fb->GetDrawCommands(), mStreamData, { mClipSplit[0], mClipSplit[1] }); + PolyTriangleDrawer::SetTwoSided(fb->GetDrawCommands(), true); PolyTriangleDrawer::PushConstants(fb->GetDrawCommands(), args); drawcalls.Unclock(); } +template +static void BufferedSet(bool &modified, T &dst, const T &src) +{ + if (dst == src) + return; + dst = src; + modified = true; +} + +static void BufferedSet(bool &modified, VSMatrix &dst, const VSMatrix &src) +{ + if (memcmp(dst.get(), src.get(), sizeof(FLOATTYPE) * 16) == 0) + return; + dst = src; + modified = true; +} + +void PolyRenderState::ApplyMatrices() +{ + bool modified = mFirstMatrixApply; + if (mTextureMatrixEnabled) + { + BufferedSet(modified, mMatrices.TextureMatrix, mTextureMatrix); + } + else + { + BufferedSet(modified, mMatrices.TextureMatrix, mIdentityMatrix); + } + + if (mModelMatrixEnabled) + { + BufferedSet(modified, mMatrices.ModelMatrix, mModelMatrix); + if (modified) + mMatrices.NormalModelMatrix.computeNormalMatrix(mModelMatrix); + } + else + { + BufferedSet(modified, mMatrices.ModelMatrix, mIdentityMatrix); + BufferedSet(modified, mMatrices.NormalModelMatrix, mIdentityMatrix); + } + + if (modified) + { + mFirstMatrixApply = false; + PolyTriangleDrawer::PushMatrices(GetPolyFrameBuffer()->GetDrawCommands(), mMatrices.ModelMatrix, mMatrices.NormalModelMatrix, mMatrices.TextureMatrix); + } +} + void PolyRenderState::Bind(PolyDataBuffer *buffer, uint32_t offset, uint32_t length) { if (buffer->bindingpoint == VIEWPOINT_BINDINGPOINT) { mViewpointUniforms = reinterpret_cast(static_cast(buffer->Memory()) + offset); - - Mat4f viewToProj = Mat4f::FromValues(mViewpointUniforms->mProjectionMatrix.get()); - Mat4f worldToView = Mat4f::FromValues(mViewpointUniforms->mViewMatrix.get()); - - auto fb = GetPolyFrameBuffer(); - PolyTriangleDrawer::SetTransform(fb->GetDrawCommands(), fb->GetFrameMemory()->NewObject(viewToProj * worldToView), nullptr); + PolyTriangleDrawer::SetViewpointUniforms(GetPolyFrameBuffer()->GetDrawCommands(), mViewpointUniforms); } } diff --git a/src/rendering/polyrenderer/backend/poly_renderstate.h b/src/rendering/polyrenderer/backend/poly_renderstate.h index 7e3676615..ab3637783 100644 --- a/src/rendering/polyrenderer/backend/poly_renderstate.h +++ b/src/rendering/polyrenderer/backend/poly_renderstate.h @@ -44,6 +44,16 @@ public: private: void Apply(); + void ApplyMatrices(); + + struct Matrices + { + VSMatrix ModelMatrix; + VSMatrix NormalModelMatrix; + VSMatrix TextureMatrix; + } mMatrices; + VSMatrix mIdentityMatrix; + bool mFirstMatrixApply = true; HWViewpointUniforms *mViewpointUniforms = nullptr; diff --git a/src/rendering/polyrenderer/drawers/poly_triangle.cpp b/src/rendering/polyrenderer/drawers/poly_triangle.cpp index 14d3972e1..dbde652d9 100644 --- a/src/rendering/polyrenderer/drawers/poly_triangle.cpp +++ b/src/rendering/polyrenderer/drawers/poly_triangle.cpp @@ -86,9 +86,9 @@ void PolyTriangleDrawer::SetViewport(const DrawerCommandQueuePtr &queue, int x, queue->Push(viewport_x, viewport_y, viewport_width, viewport_height, dest, dest_width, dest_height, dest_pitch, dest_bgra); } -void PolyTriangleDrawer::SetVertexShader(const DrawerCommandQueuePtr &queue, PolyVertexShader *shader) +void PolyTriangleDrawer::SetInputAssembly(const DrawerCommandQueuePtr &queue, PolyInputAssembly *input) { - queue->Push(shader); + queue->Push(input); } void PolyTriangleDrawer::SetTransform(const DrawerCommandQueuePtr &queue, const Mat4f *objectToClip, const Mat4f *objectToWorld) @@ -131,6 +131,21 @@ void PolyTriangleDrawer::PushConstants(const DrawerCommandQueuePtr &queue, const queue->Push(args); } +void PolyTriangleDrawer::PushStreamData(const DrawerCommandQueuePtr &queue, const StreamData &data, const Vec2f &uClipSplit) +{ + queue->Push(data, uClipSplit); +} + +void PolyTriangleDrawer::PushMatrices(const DrawerCommandQueuePtr &queue, const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix) +{ + queue->Push(modelMatrix, normalModelMatrix, textureMatrix); +} + +void PolyTriangleDrawer::SetViewpointUniforms(const DrawerCommandQueuePtr &queue, const HWViewpointUniforms *uniforms) +{ + queue->Push(uniforms); +} + void PolyTriangleDrawer::Draw(const DrawerCommandQueuePtr &queue, int index, int vcount, PolyDrawMode mode) { queue->Push(index, vcount, mode); @@ -197,8 +212,8 @@ void PolyTriangleThreadData::SetViewport(int x, int y, int width, int height, ui void PolyTriangleThreadData::SetTransform(const Mat4f *newObjectToClip, const Mat4f *newObjectToWorld) { - objectToClip = newObjectToClip; - objectToWorld = newObjectToWorld; + swVertexShader.objectToClip = newObjectToClip; + swVertexShader.objectToWorld = newObjectToWorld; } void PolyTriangleThreadData::PushConstants(const PolyDrawArgs &args) @@ -206,6 +221,24 @@ void PolyTriangleThreadData::PushConstants(const PolyDrawArgs &args) drawargs = args; } +void PolyTriangleThreadData::PushStreamData(const StreamData &data, const Vec2f &uClipSplit) +{ + mainVertexShader.Data = data; + mainVertexShader.uClipSplit = uClipSplit; +} + +void PolyTriangleThreadData::PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix) +{ + mainVertexShader.ModelMatrix = modelMatrix; + mainVertexShader.NormalModelMatrix = normalModelMatrix; + mainVertexShader.TextureMatrix = textureMatrix; +} + +void PolyTriangleThreadData::SetViewpointUniforms(const HWViewpointUniforms *uniforms) +{ + mainVertexShader.Viewpoint = uniforms; +} + void PolyTriangleThreadData::DrawIndexed(int index, int vcount, PolyDrawMode drawmode) { if (vcount < 3) @@ -216,38 +249,41 @@ void PolyTriangleThreadData::DrawIndexed(int index, int vcount, PolyDrawMode dra TriDrawTriangleArgs args; args.uniforms = &drawargs; - ShadedTriVertex vert[3]; + ShadedTriVertex vertbuffer[3]; + ShadedTriVertex *vert[3] = { &vertbuffer[0], &vertbuffer[1], &vertbuffer[2] }; if (drawmode == PolyDrawMode::Triangles) { for (int i = 0; i < vcount / 3; i++) { for (int j = 0; j < 3; j++) - vert[j] = vertexShader->Shade(this, drawargs, vertices, *(elements++)); + *vert[j] = ShadeVertex(*(elements++)); DrawShadedTriangle(vert, ccw, &args); } } else if (drawmode == PolyDrawMode::TriangleFan) { - vert[0] = vertexShader->Shade(this, drawargs, vertices, *(elements++)); - vert[1] = vertexShader->Shade(this, drawargs, vertices, *(elements++)); + *vert[0] = ShadeVertex(*(elements++)); + *vert[1] = ShadeVertex(*(elements++)); for (int i = 2; i < vcount; i++) { - vert[2] = vertexShader->Shade(this, drawargs, vertices, *(elements++)); + *vert[2] = ShadeVertex(*(elements++)); DrawShadedTriangle(vert, ccw, &args); - vert[1] = vert[2]; + std::swap(vert[1], vert[2]); } } else // TriangleDrawMode::TriangleStrip { bool toggleccw = ccw; - vert[0] = vertexShader->Shade(this, drawargs, vertices, *(elements++)); - vert[1] = vertexShader->Shade(this, drawargs, vertices, *(elements++)); + *vert[0] = ShadeVertex(*(elements++)); + *vert[1] = ShadeVertex(*(elements++)); for (int i = 2; i < vcount; i++) { - vert[2] = vertexShader->Shade(this, drawargs, vertices, *(elements++)); + *vert[2] = ShadeVertex(*(elements++)); DrawShadedTriangle(vert, toggleccw, &args); + ShadedTriVertex *vtmp = vert[0]; vert[0] = vert[1]; vert[1] = vert[2]; + vert[2] = vtmp; toggleccw = !toggleccw; } } @@ -263,116 +299,89 @@ void PolyTriangleThreadData::Draw(int index, int vcount, PolyDrawMode drawmode) int vinput = index; - ShadedTriVertex vert[3]; + ShadedTriVertex vertbuffer[3]; + ShadedTriVertex *vert[3] = { &vertbuffer[0], &vertbuffer[1], &vertbuffer[2] }; if (drawmode == PolyDrawMode::Triangles) { for (int i = 0; i < vcount / 3; i++) { for (int j = 0; j < 3; j++) - vert[j] = vertexShader->Shade(this, drawargs, vertices, vinput++); + *vert[j] = ShadeVertex(vinput++); DrawShadedTriangle(vert, ccw, &args); } } else if (drawmode == PolyDrawMode::TriangleFan) { - vert[0] = vertexShader->Shade(this, drawargs, vertices, vinput++); - vert[1] = vertexShader->Shade(this, drawargs, vertices, vinput++); + *vert[0] = ShadeVertex(vinput++); + *vert[1] = ShadeVertex(vinput++); for (int i = 2; i < vcount; i++) { - vert[2] = vertexShader->Shade(this, drawargs, vertices, vinput++); + *vert[2] = ShadeVertex(vinput++); DrawShadedTriangle(vert, ccw, &args); - vert[1] = vert[2]; + std::swap(vert[1], vert[2]); } } else // TriangleDrawMode::TriangleStrip { bool toggleccw = ccw; - vert[0] = vertexShader->Shade(this, drawargs, vertices, vinput++); - vert[1] = vertexShader->Shade(this, drawargs, vertices, vinput++); + *vert[0] = ShadeVertex(vinput++); + *vert[1] = ShadeVertex(vinput++); for (int i = 2; i < vcount; i++) { - vert[2] = vertexShader->Shade(this, drawargs, vertices, vinput++); + *vert[2] = ShadeVertex(vinput++); DrawShadedTriangle(vert, toggleccw, &args); + ShadedTriVertex *vtmp = vert[0]; vert[0] = vert[1]; vert[1] = vert[2]; + vert[2] = vtmp; toggleccw = !toggleccw; } } } -ShadedTriVertex PolyTriVertexShader::Shade(PolyTriangleThreadData *thread, const PolyDrawArgs &drawargs, const void *vertices, int index) +ShadedTriVertex PolyTriangleThreadData::ShadeVertex(int index) { - ShadedTriVertex sv; - Vec4f objpos; + inputAssembly->Load(this, vertices, index); + mainVertexShader.main(); + return mainVertexShader; +} +void PolySWInputAssembly::Load(PolyTriangleThreadData *thread, const void *vertices, int index) +{ if (thread->modelFrame1 == -1) { - const TriVertex &v = static_cast(vertices)[index]; - objpos = Vec4f(v.x, v.y, v.z, v.w); - sv.u = v.u; - sv.v = v.v; - } - else if (thread->modelFrame1 == thread->modelFrame2 || thread->modelInterpolationFactor == 0.f) - { - const FModelVertex &v = static_cast(vertices)[thread->modelFrame1 + index]; - objpos = Vec4f(v.x, v.y, v.z, 1.0f); - sv.u = v.u; - sv.v = v.v; + thread->swVertexShader.v1 = static_cast(vertices)[index]; } else { const FModelVertex &v1 = static_cast(vertices)[thread->modelFrame1 + index]; const FModelVertex &v2 = static_cast(vertices)[thread->modelFrame2 + index]; - float frac = thread->modelInterpolationFactor; - float inv_frac = 1.0f - frac; + thread->swVertexShader.v1.x = v1.x; + thread->swVertexShader.v1.y = v1.y; + thread->swVertexShader.v1.z = v1.z; + thread->swVertexShader.v1.w = 1.0f; + thread->swVertexShader.v1.u = v1.u; + thread->swVertexShader.v1.v = v1.v; - objpos = Vec4f(v1.x * inv_frac + v2.x * frac, v1.y * inv_frac + v2.y * frac, v1.z * inv_frac + v2.z * frac, 1.0f); - sv.u = v1.u; - sv.v = v1.v; + thread->swVertexShader.v2.x = v2.x; + thread->swVertexShader.v2.y = v2.y; + thread->swVertexShader.v2.z = v2.z; + thread->swVertexShader.v2.w = 1.0f; + thread->swVertexShader.v2.u = v2.u; + thread->swVertexShader.v2.v = v2.v; } - - // Apply transform to get clip coordinates: - Vec4f clippos = (*thread->objectToClip) * objpos; - - sv.x = clippos.X; - sv.y = clippos.Y; - sv.z = clippos.Z; - sv.w = clippos.W; - - if (!thread->objectToWorld) // Identity matrix - { - sv.worldX = objpos.X; - sv.worldY = objpos.Y; - sv.worldZ = objpos.Z; - } - else - { - Vec4f worldpos = (*thread->objectToWorld) * objpos; - sv.worldX = worldpos.X; - sv.worldY = worldpos.Y; - sv.worldZ = worldpos.Z; - } - - // Calculate gl_ClipDistance[i] - for (int i = 0; i < 3; i++) - { - const auto &clipPlane = drawargs.ClipPlane(i); - sv.clipDistance[i] = objpos.X * clipPlane.A + objpos.Y * clipPlane.B + objpos.Z * clipPlane.C + objpos.W * clipPlane.D; - } - - return sv; } -bool PolyTriangleThreadData::IsDegenerate(const ShadedTriVertex *vert) +bool PolyTriangleThreadData::IsDegenerate(const ShadedTriVertex *const* vert) { // A degenerate triangle has a zero cross product for two of its sides. - float ax = vert[1].x - vert[0].x; - float ay = vert[1].y - vert[0].y; - float az = vert[1].w - vert[0].w; - float bx = vert[2].x - vert[0].x; - float by = vert[2].y - vert[0].y; - float bz = vert[2].w - vert[0].w; + float ax = vert[1]->gl_Position.X - vert[0]->gl_Position.X; + float ay = vert[1]->gl_Position.Y - vert[0]->gl_Position.Y; + float az = vert[1]->gl_Position.W - vert[0]->gl_Position.W; + float bx = vert[2]->gl_Position.X - vert[0]->gl_Position.X; + float by = vert[2]->gl_Position.Y - vert[0]->gl_Position.Y; + float bz = vert[2]->gl_Position.W - vert[0]->gl_Position.W; float crossx = ay * bz - az * by; float crossy = az * bx - ax * bz; float crossz = ax * by - ay * bx; @@ -389,15 +398,35 @@ bool PolyTriangleThreadData::IsFrontfacing(TriDrawTriangleArgs *args) return a <= 0.0f; } -void PolyTriangleThreadData::DrawShadedTriangle(const ShadedTriVertex *vert, bool ccw, TriDrawTriangleArgs *args) +void PolyTriangleThreadData::DrawShadedTriangle(const ShadedTriVertex *const* vert, bool ccw, TriDrawTriangleArgs *args) { // Reject triangle if degenerate if (IsDegenerate(vert)) return; // Cull, clip and generate additional vertices as needed - ShadedTriVertex clippedvert[max_additional_vertices]; - int numclipvert = ClipEdge(vert, clippedvert); + ScreenTriVertex clippedvert[max_additional_vertices]; + int numclipvert = ClipEdge(vert); + + // Convert barycentric weights to actual vertices + for (int i = 0; i < numclipvert; i++) + { + auto &v = clippedvert[i]; + memset(&v, 0, sizeof(ScreenTriVertex)); + for (int w = 0; w < 3; w++) + { + float weight = weights[i * 3 + w]; + v.x += vert[w]->gl_Position.X * weight; + v.y += vert[w]->gl_Position.Y * weight; + v.z += vert[w]->gl_Position.Z * weight; + v.w += vert[w]->gl_Position.W * weight; + v.u += vert[w]->vTexCoord.X * weight; + v.v += vert[w]->vTexCoord.Y * weight; + v.worldX += vert[w]->pixelpos.X * weight; + v.worldY += vert[w]->pixelpos.Y * weight; + v.worldZ += vert[w]->pixelpos.Z * weight; + } + } #ifdef NO_SSE // Map to 2D viewport: @@ -499,8 +528,18 @@ void PolyTriangleThreadData::DrawShadedTriangle(const ShadedTriVertex *vert, boo } } -int PolyTriangleThreadData::ClipEdge(const ShadedTriVertex *verts, ShadedTriVertex *clippedvert) +int PolyTriangleThreadData::ClipEdge(const ShadedTriVertex *const* verts) { + // use barycentric weights for clipped vertices + weights = weightsbuffer; + for (int i = 0; i < 3; i++) + { + weights[i * 3 + 0] = 0.0f; + weights[i * 3 + 1] = 0.0f; + weights[i * 3 + 2] = 0.0f; + weights[i * 3 + i] = 1.0f; + } + // Clip and cull so that the following is true for all vertices: // -v.w <= v.x <= v.w // -v.w <= v.y <= v.w @@ -514,16 +553,16 @@ int PolyTriangleThreadData::ClipEdge(const ShadedTriVertex *verts, ShadedTriVert float *clipd = clipdistance; for (int i = 0; i < 3; i++) { - const auto &v = verts[i]; - clipd[0] = v.x + v.w; - clipd[1] = v.w - v.x; - clipd[2] = v.y + v.w; - clipd[3] = v.w - v.y; - clipd[4] = v.z + v.w; - clipd[5] = v.w - v.z; - clipd[6] = v.clipDistance[0]; - clipd[7] = v.clipDistance[1]; - clipd[8] = v.clipDistance[2]; + const auto &v = *verts[i]; + clipd[0] = v.gl_Position.X + v.gl_Position.W; + clipd[1] = v.gl_Position.W - v.gl_Position.X; + clipd[2] = v.gl_Position.Y + v.gl_Position.W; + clipd[3] = v.gl_Position.W - v.gl_Position.Y; + clipd[4] = v.gl_Position.Z + v.gl_Position.W; + clipd[5] = v.gl_Position.W - v.gl_Position.Z; + clipd[6] = v.gl_ClipDistance[0]; + clipd[7] = v.gl_ClipDistance[1]; + clipd[8] = v.gl_ClipDistance[2]; for (int j = 0; j < 9; j++) needsclipping = needsclipping || clipd[i]; clipd += numclipdistances; @@ -532,16 +571,12 @@ int PolyTriangleThreadData::ClipEdge(const ShadedTriVertex *verts, ShadedTriVert // If all halfspace clip distances are positive then the entire triangle is visible. Skip the expensive clipping step. if (!needsclipping) { - for (int i = 0; i < 3; i++) - { - memcpy(clippedvert + i, &verts[i], sizeof(ShadedTriVertex)); - } return 3; } #else - __m128 mx = _mm_loadu_ps(&verts[0].x); - __m128 my = _mm_loadu_ps(&verts[1].x); - __m128 mz = _mm_loadu_ps(&verts[2].x); + __m128 mx = _mm_loadu_ps(&verts[0]->gl_Position.X); + __m128 my = _mm_loadu_ps(&verts[1]->gl_Position.X); + __m128 mz = _mm_loadu_ps(&verts[2]->gl_Position.X); __m128 mw = _mm_setzero_ps(); _MM_TRANSPOSE4_PS(mx, my, mz, mw); __m128 clipd0 = _mm_add_ps(mx, mw); @@ -550,9 +585,9 @@ int PolyTriangleThreadData::ClipEdge(const ShadedTriVertex *verts, ShadedTriVert __m128 clipd3 = _mm_sub_ps(mw, my); __m128 clipd4 = _mm_add_ps(mz, mw); __m128 clipd5 = _mm_sub_ps(mw, mz); - __m128 clipd6 = _mm_setr_ps(verts[0].clipDistance[0], verts[1].clipDistance[0], verts[2].clipDistance[0], 0.0f); - __m128 clipd7 = _mm_setr_ps(verts[0].clipDistance[1], verts[1].clipDistance[1], verts[2].clipDistance[1], 0.0f); - __m128 clipd8 = _mm_setr_ps(verts[0].clipDistance[2], verts[1].clipDistance[2], verts[2].clipDistance[2], 0.0f); + __m128 clipd6 = _mm_setr_ps(verts[0]->gl_ClipDistance[0], verts[1]->gl_ClipDistance[0], verts[2]->gl_ClipDistance[0], 0.0f); + __m128 clipd7 = _mm_setr_ps(verts[0]->gl_ClipDistance[1], verts[1]->gl_ClipDistance[1], verts[2]->gl_ClipDistance[1], 0.0f); + __m128 clipd8 = _mm_setr_ps(verts[0]->gl_ClipDistance[2], verts[1]->gl_ClipDistance[2], verts[2]->gl_ClipDistance[2], 0.0f); __m128 mneedsclipping = _mm_cmplt_ps(clipd0, _mm_setzero_ps()); mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd1, _mm_setzero_ps())); mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd2, _mm_setzero_ps())); @@ -564,10 +599,6 @@ int PolyTriangleThreadData::ClipEdge(const ShadedTriVertex *verts, ShadedTriVert mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd8, _mm_setzero_ps())); if (_mm_movemask_ps(mneedsclipping) == 0) { - for (int i = 0; i < 3; i++) - { - memcpy(clippedvert + i, &verts[i], sizeof(ShadedTriVertex)); - } return 3; } float clipdistance[numclipdistances * 4]; @@ -582,16 +613,6 @@ int PolyTriangleThreadData::ClipEdge(const ShadedTriVertex *verts, ShadedTriVert _mm_storeu_ps(clipdistance + 32, clipd8); #endif - // use barycentric weights while clipping vertices - float weights[max_additional_vertices * 3 * 2]; - for (int i = 0; i < 3; i++) - { - weights[i * 3 + 0] = 0.0f; - weights[i * 3 + 1] = 0.0f; - weights[i * 3 + 2] = 0.0f; - weights[i * 3 + i] = 1.0f; - } - // Clip against each halfspace float *input = weights; float *output = weights + max_additional_vertices * 3; @@ -650,26 +671,8 @@ int PolyTriangleThreadData::ClipEdge(const ShadedTriVertex *verts, ShadedTriVert if (inputverts == 0) break; } - - // Convert barycentric weights to actual vertices - for (int i = 0; i < inputverts; i++) - { - auto &v = clippedvert[i]; - memset(&v, 0, sizeof(ShadedTriVertex)); - for (int w = 0; w < 3; w++) - { - float weight = input[i * 3 + w]; - v.x += verts[w].x * weight; - v.y += verts[w].y * weight; - v.z += verts[w].z * weight; - v.w += verts[w].w * weight; - v.u += verts[w].u * weight; - v.v += verts[w].v * weight; - v.worldX += verts[w].worldX * weight; - v.worldY += verts[w].worldY * weight; - v.worldZ += verts[w].worldZ * weight; - } - } + + weights = input; return inputverts; } @@ -704,13 +707,13 @@ void PolySetIndexBufferCommand::Execute(DrawerThread *thread) ///////////////////////////////////////////////////////////////////////////// -PolySetVertexShaderCommand::PolySetVertexShaderCommand(PolyVertexShader *shader) : shader(shader) +PolySetInputAssemblyCommand::PolySetInputAssemblyCommand(PolyInputAssembly *input) : input(input) { } -void PolySetVertexShaderCommand::Execute(DrawerThread *thread) +void PolySetInputAssemblyCommand::Execute(DrawerThread *thread) { - PolyTriangleThreadData::Get(thread)->SetVertexShader(shader); + PolyTriangleThreadData::Get(thread)->SetInputAssembly(input); } ///////////////////////////////////////////////////////////////////////////// @@ -804,6 +807,40 @@ void PolySetViewportCommand::Execute(DrawerThread *thread) ///////////////////////////////////////////////////////////////////////////// +PolySetViewpointUniformsCommand::PolySetViewpointUniformsCommand(const HWViewpointUniforms *uniforms) : uniforms(uniforms) +{ +} + +void PolySetViewpointUniformsCommand::Execute(DrawerThread *thread) +{ + PolyTriangleThreadData::Get(thread)->SetViewpointUniforms(uniforms); +} + +///////////////////////////////////////////////////////////////////////////// + +PolyPushMatricesCommand::PolyPushMatricesCommand(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix) + : modelMatrix(modelMatrix), normalModelMatrix(normalModelMatrix), textureMatrix(textureMatrix) +{ +} + +void PolyPushMatricesCommand::Execute(DrawerThread *thread) +{ + PolyTriangleThreadData::Get(thread)->PushMatrices(modelMatrix, normalModelMatrix, textureMatrix); +} + +///////////////////////////////////////////////////////////////////////////// + +PolyPushStreamDataCommand::PolyPushStreamDataCommand(const StreamData &data, const Vec2f &uClipSplit) : data(data), uClipSplit(uClipSplit) +{ +} + +void PolyPushStreamDataCommand::Execute(DrawerThread *thread) +{ + PolyTriangleThreadData::Get(thread)->PushStreamData(data, uClipSplit); +} + +///////////////////////////////////////////////////////////////////////////// + PolyPushConstantsCommand::PolyPushConstantsCommand(const PolyDrawArgs &args) : args(args) { } diff --git a/src/rendering/polyrenderer/drawers/poly_triangle.h b/src/rendering/polyrenderer/drawers/poly_triangle.h index 10287b696..d3f1fa6dc 100644 --- a/src/rendering/polyrenderer/drawers/poly_triangle.h +++ b/src/rendering/polyrenderer/drawers/poly_triangle.h @@ -32,7 +32,7 @@ class DCanvas; class PolyDrawerCommand; -class PolyVertexShader; +class PolyInputAssembly; class PolyTriangleDrawer { @@ -41,7 +41,7 @@ public: static void ClearDepth(const DrawerCommandQueuePtr &queue, float value); static void ClearStencil(const DrawerCommandQueuePtr &queue, uint8_t value); static void SetViewport(const DrawerCommandQueuePtr &queue, int x, int y, int width, int height, DCanvas *canvas); - static void SetVertexShader(const DrawerCommandQueuePtr &queue, PolyVertexShader *shader); + static void SetInputAssembly(const DrawerCommandQueuePtr &queue, PolyInputAssembly *input); static void SetCullCCW(const DrawerCommandQueuePtr &queue, bool ccw); static void SetTwoSided(const DrawerCommandQueuePtr &queue, bool twosided); static void SetWeaponScene(const DrawerCommandQueuePtr &queue, bool enable); @@ -49,42 +49,55 @@ public: static void SetTransform(const DrawerCommandQueuePtr &queue, const Mat4f *objectToClip, const Mat4f *objectToWorld); static void SetVertexBuffer(const DrawerCommandQueuePtr &queue, const void *vertices); static void SetIndexBuffer(const DrawerCommandQueuePtr &queue, const void *elements); + static void SetViewpointUniforms(const DrawerCommandQueuePtr &queue, const HWViewpointUniforms *uniforms); static void PushConstants(const DrawerCommandQueuePtr &queue, const PolyDrawArgs &args); + static void PushStreamData(const DrawerCommandQueuePtr &queue, const StreamData &data, const Vec2f &uClipSplit); + static void PushMatrices(const DrawerCommandQueuePtr &queue, const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix); static void Draw(const DrawerCommandQueuePtr &queue, int index, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles); static void DrawIndexed(const DrawerCommandQueuePtr &queue, int index, int count, PolyDrawMode mode = PolyDrawMode::Triangles); static bool IsBgra(); }; -class PolyVertexShader +class PolyInputAssembly { public: - virtual ShadedTriVertex Shade(PolyTriangleThreadData *thread, const PolyDrawArgs &drawargs, const void *vertices, int index) = 0; + virtual void Load(PolyTriangleThreadData *thread, const void *vertices, int index) = 0; }; -class PolyTriVertexShader : public PolyVertexShader +class PolySWInputAssembly : public PolyInputAssembly { public: - ShadedTriVertex Shade(PolyTriangleThreadData *thread, const PolyDrawArgs &drawargs, const void *vertices, int index) override; + void Load(PolyTriangleThreadData *thread, const void *vertices, int index) override; }; class PolyTriangleThreadData { public: - PolyTriangleThreadData(int32_t core, int32_t num_cores, int32_t numa_node, int32_t num_numa_nodes, int numa_start_y, int numa_end_y) : core(core), num_cores(num_cores), numa_node(numa_node), num_numa_nodes(num_numa_nodes), numa_start_y(numa_start_y), numa_end_y(numa_end_y) { } + PolyTriangleThreadData(int32_t core, int32_t num_cores, int32_t numa_node, int32_t num_numa_nodes, int numa_start_y, int numa_end_y) + : core(core), num_cores(num_cores), numa_node(numa_node), num_numa_nodes(num_numa_nodes), numa_start_y(numa_start_y), numa_end_y(numa_end_y) + { + swVertexShader.drawargs = &drawargs; + } void ClearDepth(float value); void ClearStencil(uint8_t value); void SetViewport(int x, int y, int width, int height, uint8_t *dest, int dest_width, int dest_height, int dest_pitch, bool dest_bgra); + void SetTransform(const Mat4f *objectToClip, const Mat4f *objectToWorld); void SetCullCCW(bool value) { ccw = value; } void SetTwoSided(bool value) { twosided = value; } void SetWeaponScene(bool value) { weaponScene = value; } - void SetModelVertexShader(int frame1, int frame2, float interpolationFactor) { modelFrame1 = frame1; modelFrame2 = frame2; modelInterpolationFactor = interpolationFactor; } - void SetVertexShader(PolyVertexShader *shader) { vertexShader = shader; } + void SetModelVertexShader(int frame1, int frame2, float interpolationFactor) { modelFrame1 = frame1; modelFrame2 = frame2; swVertexShader.modelInterpolationFactor = interpolationFactor; } + + void SetInputAssembly(PolyInputAssembly *input) { inputAssembly = input; } void SetVertexBuffer(const void *data) { vertices = data; } void SetIndexBuffer(const void *data) { elements = (const unsigned int *)data; } + void SetViewpointUniforms(const HWViewpointUniforms *uniforms); void PushConstants(const PolyDrawArgs &args); + void PushStreamData(const StreamData &data, const Vec2f &uClipSplit); + void PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix); + void DrawIndexed(int index, int count, PolyDrawMode mode); void Draw(int index, int vcount, PolyDrawMode mode); @@ -140,30 +153,30 @@ public: const void *vertices = nullptr; const unsigned int *elements = nullptr; + PolyMainVertexShader mainVertexShader; + + int modelFrame1 = -1; + int modelFrame2 = -1; + PolySWVertexShader swVertexShader; + private: - void DrawShadedTriangle(const ShadedTriVertex *vertices, bool ccw, TriDrawTriangleArgs *args); - static bool IsDegenerate(const ShadedTriVertex *vertices); + ShadedTriVertex ShadeVertex(int index); + void DrawShadedTriangle(const ShadedTriVertex *const* vertices, bool ccw, TriDrawTriangleArgs *args); + static bool IsDegenerate(const ShadedTriVertex *const* vertices); static bool IsFrontfacing(TriDrawTriangleArgs *args); - static int ClipEdge(const ShadedTriVertex *verts, ShadedTriVertex *clippedvert); + + int ClipEdge(const ShadedTriVertex *const* verts); int viewport_x = 0; int viewport_width = 0; int viewport_height = 0; bool ccw = true; bool twosided = false; -public: - const Mat4f *objectToClip = nullptr; - const Mat4f *objectToWorld = nullptr; -private: - int modelFrame1 = -1; - int modelFrame2 = -1; - float modelInterpolationFactor = 0.0f; - PolyVertexShader *vertexShader = nullptr; - PolyMainVertexShader mainVertexShader; + PolyInputAssembly *inputAssembly = nullptr; enum { max_additional_vertices = 16 }; - - friend class PolyTriVertexShader; + float weightsbuffer[max_additional_vertices * 3 * 2]; + float *weights = nullptr; }; class PolyDrawerCommand : public DrawerCommand @@ -191,14 +204,14 @@ private: const void *indices; }; -class PolySetVertexShaderCommand : public PolyDrawerCommand +class PolySetInputAssemblyCommand : public PolyDrawerCommand { public: - PolySetVertexShaderCommand(PolyVertexShader *shader); + PolySetInputAssemblyCommand(PolyInputAssembly *input); void Execute(DrawerThread *thread) override; private: - PolyVertexShader *shader; + PolyInputAssembly *input; }; class PolySetTransformCommand : public PolyDrawerCommand @@ -300,6 +313,39 @@ private: bool dest_bgra; }; +class PolySetViewpointUniformsCommand : public PolyDrawerCommand +{ +public: + PolySetViewpointUniformsCommand(const HWViewpointUniforms *uniforms); + void Execute(DrawerThread *thread) override; + +private: + const HWViewpointUniforms *uniforms; +}; + +class PolyPushMatricesCommand : public PolyDrawerCommand +{ +public: + PolyPushMatricesCommand(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix); + void Execute(DrawerThread *thread) override; + +private: + VSMatrix modelMatrix; + VSMatrix normalModelMatrix; + VSMatrix textureMatrix; +}; + +class PolyPushStreamDataCommand : public PolyDrawerCommand +{ +public: + PolyPushStreamDataCommand(const StreamData &data, const Vec2f &uClipSplit); + void Execute(DrawerThread *thread) override; + +private: + StreamData data; + Vec2f uClipSplit; +}; + class PolyPushConstantsCommand : public PolyDrawerCommand { public: diff --git a/src/rendering/polyrenderer/drawers/poly_vertex_shader.h b/src/rendering/polyrenderer/drawers/poly_vertex_shader.h index 758b0387c..56486d047 100644 --- a/src/rendering/polyrenderer/drawers/poly_vertex_shader.h +++ b/src/rendering/polyrenderer/drawers/poly_vertex_shader.h @@ -9,7 +9,16 @@ #include #endif -class PolyMainVertexShader +class ShadedTriVertex +{ +public: + Vec4f gl_Position; + float gl_ClipDistance[5]; + Vec4f vTexCoord; + Vec4f pixelpos; +}; + +class PolyMainVertexShader : public ShadedTriVertex { public: // Input @@ -21,11 +30,7 @@ public: Vec4f aNormal2; // Output - Vec4f gl_Position; - float gl_ClipDistance[5]; - Vec4f vTexCoord; Vec4f vColor; - Vec4f pixelpos; Vec3f glowdist; Vec3f gradientdist; Vec4f vWorldNormal; @@ -41,12 +46,10 @@ public: VSMatrix TextureMatrix; StreamData Data; Vec2f uClipSplit; - HWViewpointUniforms Viewpoint; + const HWViewpointUniforms *Viewpoint = nullptr; void main() { - float ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3, ClipDistance4; - Vec2f parmTexCoord = aTexCoord; Vec4f parmPosition = aPosition; @@ -56,7 +59,7 @@ public: else worldcoord = mul(ModelMatrix, parmPosition); - Vec4f eyeCoordPos = mul(Viewpoint.mViewMatrix, worldcoord); + Vec4f eyeCoordPos = mul(Viewpoint->mViewMatrix, worldcoord); vColor = aColor; @@ -87,12 +90,12 @@ public: if (Data.uSplitBottomPlane.Z != 0.0f) { - ClipDistance3 = ((Data.uSplitTopPlane.W + Data.uSplitTopPlane.X * worldcoord.X + Data.uSplitTopPlane.Y * worldcoord.Z) * Data.uSplitTopPlane.Z) - worldcoord.Y; - ClipDistance4 = worldcoord.Y - ((Data.uSplitBottomPlane.W + Data.uSplitBottomPlane.X * worldcoord.X + Data.uSplitBottomPlane.Y * worldcoord.Z) * Data.uSplitBottomPlane.Z); + gl_ClipDistance[3] = ((Data.uSplitTopPlane.W + Data.uSplitTopPlane.X * worldcoord.X + Data.uSplitTopPlane.Y * worldcoord.Z) * Data.uSplitTopPlane.Z) - worldcoord.Y; + gl_ClipDistance[4] = worldcoord.Y - ((Data.uSplitBottomPlane.W + Data.uSplitBottomPlane.X * worldcoord.X + Data.uSplitBottomPlane.Y * worldcoord.Z) * Data.uSplitBottomPlane.Z); } vWorldNormal = mul(NormalModelMatrix, Vec4f(normalize(mix3(aNormal, aNormal2, Data.uInterpolationFactor)), 1.0f)); - vEyeNormal = mul(Viewpoint.mNormalViewMatrix, vWorldNormal); + vEyeNormal = mul(Viewpoint->mNormalViewMatrix, vWorldNormal); } if (!SPHEREMAP) @@ -102,43 +105,39 @@ public: else { Vec3f u = normalize3(eyeCoordPos); - Vec3f n = normalize3(mul(Viewpoint.mNormalViewMatrix, Vec4f(parmTexCoord.X, 0.0f, parmTexCoord.Y, 0.0f))); + Vec3f n = normalize3(mul(Viewpoint->mNormalViewMatrix, Vec4f(parmTexCoord.X, 0.0f, parmTexCoord.Y, 0.0f))); Vec3f r = reflect(u, n); float m = 2.0f * sqrt(r.X*r.X + r.Y*r.Y + (r.Z + 1.0f)*(r.Z + 1.0f)); vTexCoord.X = r.X / m + 0.5f; vTexCoord.Y = r.Y / m + 0.5f; } - gl_Position = mul(Viewpoint.mProjectionMatrix, eyeCoordPos); + gl_Position = mul(Viewpoint->mProjectionMatrix, eyeCoordPos); - if (Viewpoint.mClipHeightDirection != 0.0f) // clip planes used for reflective flats + if (Viewpoint->mClipHeightDirection != 0.0f) // clip planes used for reflective flats { - ClipDistance0 = (worldcoord.Y - Viewpoint.mClipHeight) * Viewpoint.mClipHeightDirection; + gl_ClipDistance[0] = (worldcoord.Y - Viewpoint->mClipHeight) * Viewpoint->mClipHeightDirection; } - else if (Viewpoint.mClipLine.X > -1000000.0f) // and for line portals - this will never be active at the same time as the reflective planes clipping so it can use the same hardware clip plane. + else if (Viewpoint->mClipLine.X > -1000000.0f) // and for line portals - this will never be active at the same time as the reflective planes clipping so it can use the same hardware clip plane. { - ClipDistance0 = -((worldcoord.Z - Viewpoint.mClipLine.Y) * Viewpoint.mClipLine.Z + (Viewpoint.mClipLine.X - worldcoord.X) * Viewpoint.mClipLine.W) + 1.0f / 32768.0f; // allow a tiny bit of imprecisions for colinear linedefs. + gl_ClipDistance[0] = -((worldcoord.Z - Viewpoint->mClipLine.Y) * Viewpoint->mClipLine.Z + (Viewpoint->mClipLine.X - worldcoord.X) * Viewpoint->mClipLine.W) + 1.0f / 32768.0f; // allow a tiny bit of imprecisions for colinear linedefs. } else { - ClipDistance0 = 1.0f; + gl_ClipDistance[0] = 1.0f; } // clip planes used for translucency splitting - ClipDistance1 = worldcoord.Y - uClipSplit.X; - ClipDistance2 = uClipSplit.Y - worldcoord.Y; + gl_ClipDistance[1] = worldcoord.Y - uClipSplit.X; + gl_ClipDistance[2] = uClipSplit.Y - worldcoord.Y; if (Data.uSplitTopPlane == FVector4(0.0f, 0.0f, 0.0f, 0.0f)) { - ClipDistance3 = 1.0f; - ClipDistance4 = 1.0f; + gl_ClipDistance[3] = 1.0f; + gl_ClipDistance[4] = 1.0f; } - gl_ClipDistance[0] = ClipDistance0; - gl_ClipDistance[1] = ClipDistance1; - gl_ClipDistance[2] = ClipDistance2; - gl_ClipDistance[3] = ClipDistance3; - gl_ClipDistance[4] = ClipDistance4; + std::swap(vTexCoord.X, vTexCoord.Y); // textures are transposed because the software renderer did them this way } private: @@ -198,3 +197,59 @@ private: return result; } }; + +class PolySWVertexShader : public ShadedTriVertex +{ +public: + // Input + TriVertex v1; + TriVertex v2; + + // Uniforms + float modelInterpolationFactor = 0.0f; + const Mat4f *objectToClip = nullptr; + const Mat4f *objectToWorld = nullptr; + PolyDrawArgs *drawargs = nullptr; + + void main() + { + Vec4f objpos; + + if (modelInterpolationFactor == 0.f) + { + objpos = Vec4f(v1.x, v1.y, v1.z, v1.w); + vTexCoord.X = v1.u; + vTexCoord.Y = v1.v; + } + else + { + float frac = modelInterpolationFactor; + float inv_frac = 1.0f - frac; + + objpos = Vec4f(v1.x * inv_frac + v2.x * frac, v1.y * inv_frac + v2.y * frac, v1.z * inv_frac + v2.z * frac, 1.0f); + vTexCoord.X = v1.u; + vTexCoord.Y = v1.v; + } + + // Apply transform to get clip coordinates: + gl_Position = (*objectToClip) * objpos; + + if (!objectToWorld) // Identity matrix + { + pixelpos = objpos; + } + else + { + pixelpos = (*objectToWorld) * objpos; + } + + // Calculate gl_ClipDistance[i] + for (int i = 0; i < 3; i++) + { + const auto &clipPlane = drawargs->ClipPlane(i); + gl_ClipDistance[i] = objpos.X * clipPlane.A + objpos.Y * clipPlane.B + objpos.Z * clipPlane.C + objpos.W * clipPlane.D; + } + gl_ClipDistance[3] = 1.0f; + gl_ClipDistance[4] = 1.0f; + } +}; diff --git a/src/rendering/polyrenderer/drawers/screen_triangle.cpp b/src/rendering/polyrenderer/drawers/screen_triangle.cpp index 82b652532..413b63d3d 100644 --- a/src/rendering/polyrenderer/drawers/screen_triangle.cpp +++ b/src/rendering/polyrenderer/drawers/screen_triangle.cpp @@ -38,7 +38,7 @@ #include "screen_triangle.h" #include "x86.h" -static void SortVertices(const TriDrawTriangleArgs *args, ShadedTriVertex **sortedVertices) +static void SortVertices(const TriDrawTriangleArgs *args, ScreenTriVertex **sortedVertices) { sortedVertices[0] = args->v1; sortedVertices[1] = args->v2; @@ -57,7 +57,7 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat using namespace TriScreenDrawerModes; // Sort vertices by Y position - ShadedTriVertex *sortedVertices[3]; + ScreenTriVertex *sortedVertices[3]; SortVertices(args, sortedVertices); int clipleft = 0; diff --git a/src/rendering/polyrenderer/drawers/screen_triangle.h b/src/rendering/polyrenderer/drawers/screen_triangle.h index 613466593..92d346376 100644 --- a/src/rendering/polyrenderer/drawers/screen_triangle.h +++ b/src/rendering/polyrenderer/drawers/screen_triangle.h @@ -31,11 +31,10 @@ class FString; class PolyDrawArgs; class PolyTriangleThreadData; -struct ShadedTriVertex +struct ScreenTriVertex { float x, y, z, w; float u, v; - float clipDistance[3]; float worldX, worldY, worldZ; }; @@ -47,9 +46,9 @@ struct ScreenTriangleStepVariables struct TriDrawTriangleArgs { - ShadedTriVertex *v1; - ShadedTriVertex *v2; - ShadedTriVertex *v3; + ScreenTriVertex *v1; + ScreenTriVertex *v2; + ScreenTriVertex *v3; const PolyDrawArgs *uniforms; ScreenTriangleStepVariables gradientX; ScreenTriangleStepVariables gradientY; diff --git a/src/rendering/swrenderer/things/r_model.cpp b/src/rendering/swrenderer/things/r_model.cpp index b59170128..1d666fdf4 100644 --- a/src/rendering/swrenderer/things/r_model.cpp +++ b/src/rendering/swrenderer/things/r_model.cpp @@ -148,8 +148,8 @@ namespace swrenderer SWModelRenderer::SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor, Mat4f *worldToClip, bool mirrorWorldToClip) : Thread(thread), Clip3DFloor(clip3DFloor), WorldToClip(worldToClip), MirrorWorldToClip(mirrorWorldToClip) { - static PolyTriVertexShader shader; - PolyTriangleDrawer::SetVertexShader(thread->DrawQueue, &shader); + static PolySWInputAssembly input; + PolyTriangleDrawer::SetInputAssembly(thread->DrawQueue, &input); } void SWModelRenderer::AddLights(AActor *actor)