diff --git a/src/rendering/polyrenderer/backend/poly_buffers.cpp b/src/rendering/polyrenderer/backend/poly_buffers.cpp index 5aa713d84..75f3c99dc 100644 --- a/src/rendering/polyrenderer/backend/poly_buffers.cpp +++ b/src/rendering/polyrenderer/backend/poly_buffers.cpp @@ -98,20 +98,17 @@ void PolyVertexInputAssembly::Load(PolyTriangleThreadData *thread, const void *v if ((UseVertexData & 1) == 0) { const auto &c = thread->mainVertexShader.Data.uVertexColor; - thread->mainVertexShader.aColor = MAKEARGB( - static_cast(c.W * 255.0f + 0.5f), - static_cast(c.X * 255.0f + 0.5f), - static_cast(c.Y * 255.0f + 0.5f), - static_cast(c.Z * 255.0f + 0.5f) - ); + thread->mainVertexShader.aColor.X = c.X; + thread->mainVertexShader.aColor.Y = c.Y; + thread->mainVertexShader.aColor.Z = c.Z; + thread->mainVertexShader.aColor.W = c.W; } else { - uint32_t r = attrColor[0]; - uint32_t g = attrColor[1]; - uint32_t b = attrColor[2]; - uint32_t a = attrColor[3]; - thread->mainVertexShader.aColor = MAKEARGB(a, r, g, b); + thread->mainVertexShader.aColor.X = attrColor[0] * (1.0f / 255.0f); + thread->mainVertexShader.aColor.Y = attrColor[1] * (1.0f / 255.0f); + thread->mainVertexShader.aColor.Z = attrColor[2] * (1.0f / 255.0f); + thread->mainVertexShader.aColor.W = attrColor[3] * (1.0f / 255.0f); } if ((UseVertexData & 2) == 0) diff --git a/src/rendering/polyrenderer/drawers/poly_triangle.cpp b/src/rendering/polyrenderer/drawers/poly_triangle.cpp index 694e7a404..19db47fab 100644 --- a/src/rendering/polyrenderer/drawers/poly_triangle.cpp +++ b/src/rendering/polyrenderer/drawers/poly_triangle.cpp @@ -414,8 +414,6 @@ void PolyTriangleThreadData::DrawIndexed(int index, int vcount, PolyDrawMode dra elements += index; - TriDrawTriangleArgs args; - ShadedTriVertex vertbuffer[3]; ShadedTriVertex *vert[3] = { &vertbuffer[0], &vertbuffer[1], &vertbuffer[2] }; if (drawmode == PolyDrawMode::Triangles) @@ -424,7 +422,7 @@ void PolyTriangleThreadData::DrawIndexed(int index, int vcount, PolyDrawMode dra { for (int j = 0; j < 3; j++) *vert[j] = ShadeVertex(*(elements++)); - DrawShadedTriangle(vert, ccw, &args); + DrawShadedTriangle(vert, ccw); } } else if (drawmode == PolyDrawMode::TriangleFan) @@ -434,7 +432,7 @@ void PolyTriangleThreadData::DrawIndexed(int index, int vcount, PolyDrawMode dra for (int i = 2; i < vcount; i++) { *vert[2] = ShadeVertex(*(elements++)); - DrawShadedTriangle(vert, ccw, &args); + DrawShadedTriangle(vert, ccw); std::swap(vert[1], vert[2]); } } @@ -446,7 +444,7 @@ void PolyTriangleThreadData::DrawIndexed(int index, int vcount, PolyDrawMode dra for (int i = 2; i < vcount; i++) { *vert[2] = ShadeVertex(*(elements++)); - DrawShadedTriangle(vert, toggleccw, &args); + DrawShadedTriangle(vert, toggleccw); ShadedTriVertex *vtmp = vert[0]; vert[0] = vert[1]; vert[1] = vert[2]; @@ -478,8 +476,6 @@ void PolyTriangleThreadData::Draw(int index, int vcount, PolyDrawMode drawmode) if (vcount < 3) return; - TriDrawTriangleArgs args; - int vinput = index; ShadedTriVertex vertbuffer[3]; @@ -490,7 +486,7 @@ void PolyTriangleThreadData::Draw(int index, int vcount, PolyDrawMode drawmode) { for (int j = 0; j < 3; j++) *vert[j] = ShadeVertex(vinput++); - DrawShadedTriangle(vert, ccw, &args); + DrawShadedTriangle(vert, ccw); } } else if (drawmode == PolyDrawMode::TriangleFan) @@ -500,7 +496,7 @@ void PolyTriangleThreadData::Draw(int index, int vcount, PolyDrawMode drawmode) for (int i = 2; i < vcount; i++) { *vert[2] = ShadeVertex(vinput++); - DrawShadedTriangle(vert, ccw, &args); + DrawShadedTriangle(vert, ccw); std::swap(vert[1], vert[2]); } } @@ -512,7 +508,7 @@ void PolyTriangleThreadData::Draw(int index, int vcount, PolyDrawMode drawmode) for (int i = 2; i < vcount; i++) { *vert[2] = ShadeVertex(vinput++); - DrawShadedTriangle(vert, toggleccw, &args); + DrawShadedTriangle(vert, toggleccw); ShadedTriVertex *vtmp = vert[0]; vert[0] = vert[1]; vert[1] = vert[2]; @@ -623,11 +619,6 @@ void PolyTriangleThreadData::DrawShadedLine(const ShadedTriVertex *const* vert) 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; } // Calculate normalized device coordinates: @@ -641,7 +632,11 @@ void PolyTriangleThreadData::DrawShadedLine(const ShadedTriVertex *const* vert) v.y = viewport_y + viewport_height * (1.0f - v.y) * 0.5f; } - uint32_t color = vert[0]->vColor; + uint32_t vColorA = (int)(vert[0]->vColor.W * 255.0f + 0.5f); + uint32_t vColorR = (int)(vert[0]->vColor.X * 255.0f + 0.5f); + uint32_t vColorG = (int)(vert[0]->vColor.Y * 255.0f + 0.5f); + uint32_t vColorB = (int)(vert[0]->vColor.Z * 255.0f + 0.5f); + uint32_t color = MAKEARGB(vColorA, vColorR, vColorG, vColorB); // Slow and naive implementation. Hopefully fast enough.. @@ -679,7 +674,7 @@ void PolyTriangleThreadData::DrawShadedLine(const ShadedTriVertex *const* vert) } } -void PolyTriangleThreadData::DrawShadedTriangle(const ShadedTriVertex *const* vert, bool ccw, TriDrawTriangleArgs *args) +void PolyTriangleThreadData::DrawShadedTriangle(const ShadedTriVertex *const* vert, bool ccw) { // Reject triangle if degenerate if (IsDegenerate(vert)) @@ -706,6 +701,11 @@ void PolyTriangleThreadData::DrawShadedTriangle(const ShadedTriVertex *const* ve v.worldX += vert[w]->pixelpos.X * weight; v.worldY += vert[w]->pixelpos.Y * weight; v.worldZ += vert[w]->pixelpos.Z * weight; + v.a += vert[w]->vColor.W * weight; + v.r += vert[w]->vColor.X * weight; + v.g += vert[w]->vColor.Y * weight; + v.b += vert[w]->vColor.Z * weight; + v.gradientdistZ += vert[w]->gradientdist.Z * weight; } } @@ -759,27 +759,14 @@ void PolyTriangleThreadData::DrawShadedTriangle(const ShadedTriVertex *const* ve } #endif -#if 0 - // Keep varyings in -128 to 128 range if possible - // But don't do this for the skycap mode since the V texture coordinate is used for blending - if (numclipvert > 0 && drawargs.BlendMode() != TriBlendMode::Skycap) - { - float newOriginU = floorf(clippedvert[0].u * 0.1f) * 10.0f; - float newOriginV = floorf(clippedvert[0].v * 0.1f) * 10.0f; - for (int i = 0; i < numclipvert; i++) - { - clippedvert[i].u -= newOriginU; - clippedvert[i].v -= newOriginV; - } - } -#endif + TriDrawTriangleArgs args; if (twosided && numclipvert > 2) { - args->v1 = &clippedvert[0]; - args->v2 = &clippedvert[1]; - args->v3 = &clippedvert[2]; - ccw = !IsFrontfacing(args); + args.v1 = &clippedvert[0]; + args.v2 = &clippedvert[1]; + args.v3 = &clippedvert[2]; + ccw = !IsFrontfacing(&args); } // Draw screen triangles @@ -787,12 +774,12 @@ void PolyTriangleThreadData::DrawShadedTriangle(const ShadedTriVertex *const* ve { for (int i = numclipvert - 1; i > 1; i--) { - args->v1 = &clippedvert[numclipvert - 1]; - args->v2 = &clippedvert[i - 1]; - args->v3 = &clippedvert[i - 2]; - if (IsFrontfacing(args) == ccw && args->CalculateGradients()) + args.v1 = &clippedvert[numclipvert - 1]; + args.v2 = &clippedvert[i - 1]; + args.v3 = &clippedvert[i - 2]; + if (IsFrontfacing(&args) == ccw && args.CalculateGradients()) { - ScreenTriangle::Draw(args, this); + ScreenTriangle::Draw(&args, this); } } } @@ -800,12 +787,12 @@ void PolyTriangleThreadData::DrawShadedTriangle(const ShadedTriVertex *const* ve { for (int i = 2; i < numclipvert; i++) { - args->v1 = &clippedvert[0]; - args->v2 = &clippedvert[i - 1]; - args->v3 = &clippedvert[i]; - if (IsFrontfacing(args) != ccw && args->CalculateGradients()) + args.v1 = &clippedvert[0]; + args.v2 = &clippedvert[i - 1]; + args.v3 = &clippedvert[i]; + if (IsFrontfacing(&args) != ccw && args.CalculateGradients()) { - ScreenTriangle::Draw(args, this); + ScreenTriangle::Draw(&args, this); } } } diff --git a/src/rendering/polyrenderer/drawers/poly_triangle.h b/src/rendering/polyrenderer/drawers/poly_triangle.h index 3355f2971..8b7402943 100644 --- a/src/rendering/polyrenderer/drawers/poly_triangle.h +++ b/src/rendering/polyrenderer/drawers/poly_triangle.h @@ -196,11 +196,18 @@ public: struct Scanline { float W[MAXWIDTH]; + float WeightV1[MAXWIDTH]; + float WeightV2[MAXWIDTH]; uint16_t U[MAXWIDTH]; uint16_t V[MAXWIDTH]; float WorldX[MAXWIDTH]; float WorldY[MAXWIDTH]; float WorldZ[MAXWIDTH]; + uint8_t vColorA[MAXWIDTH]; + uint8_t vColorR[MAXWIDTH]; + uint8_t vColorG[MAXWIDTH]; + uint8_t vColorB[MAXWIDTH]; + float GradientdistZ[MAXWIDTH]; uint32_t FragColor[MAXWIDTH]; uint16_t lightarray[MAXWIDTH]; uint32_t dynlights[MAXWIDTH]; @@ -263,7 +270,7 @@ private: ShadedTriVertex ShadeVertex(int index); void DrawShadedPoint(const ShadedTriVertex *const* vertex); void DrawShadedLine(const ShadedTriVertex *const* vertices); - void DrawShadedTriangle(const ShadedTriVertex *const* vertices, bool ccw, TriDrawTriangleArgs *args); + void DrawShadedTriangle(const ShadedTriVertex *const* vertices, bool ccw); static bool IsDegenerate(const ShadedTriVertex *const* vertices); static bool IsFrontfacing(TriDrawTriangleArgs *args); diff --git a/src/rendering/polyrenderer/drawers/poly_vertex_shader.h b/src/rendering/polyrenderer/drawers/poly_vertex_shader.h index a3797ee7f..45af2e4e1 100644 --- a/src/rendering/polyrenderer/drawers/poly_vertex_shader.h +++ b/src/rendering/polyrenderer/drawers/poly_vertex_shader.h @@ -15,8 +15,11 @@ public: Vec4f gl_Position; float gl_ClipDistance[5]; Vec4f vTexCoord; - uint32_t vColor; + Vec4f vColor; Vec4f pixelpos; + //Vec3f glowdist; + Vec3f gradientdist; + //Vec4f vEyeNormal; Vec4f vWorldNormal; }; @@ -26,16 +29,11 @@ public: // Input Vec4f aPosition; Vec2f aTexCoord; - uint32_t aColor; + Vec4f aColor; Vec4f aVertex2; Vec4f aNormal; Vec4f aNormal2; - // Output - Vec3f glowdist; - Vec3f gradientdist; - Vec4f vEyeNormal; - // Defines bool SIMPLE = false; bool SPHEREMAP = false; @@ -70,14 +68,14 @@ public: pixelpos.Z = worldcoord.Z; pixelpos.W = -eyeCoordPos.Z / eyeCoordPos.W; - if (Data.uGlowTopColor.W > 0 || Data.uGlowBottomColor.W > 0) + /*if (Data.uGlowTopColor.W > 0 || Data.uGlowBottomColor.W > 0) { float topatpoint = (Data.uGlowTopPlane.W + Data.uGlowTopPlane.X * worldcoord.X + Data.uGlowTopPlane.Y * worldcoord.Z) * Data.uGlowTopPlane.Z; float bottomatpoint = (Data.uGlowBottomPlane.W + Data.uGlowBottomPlane.X * worldcoord.X + Data.uGlowBottomPlane.Y * worldcoord.Z) * Data.uGlowBottomPlane.Z; glowdist.X = topatpoint - worldcoord.Y; glowdist.Y = worldcoord.Y - bottomatpoint; glowdist.Z = clamp(glowdist.X / (topatpoint - bottomatpoint), 0.0f, 1.0f); - } + }*/ if (Data.uObjectColor2.a != 0) { @@ -95,7 +93,7 @@ public: } vWorldNormal = mul(NormalModelMatrix, Vec4f(normalize(mix3(aNormal, aNormal2, Data.uInterpolationFactor)), 1.0f)); - vEyeNormal = mul(Viewpoint->mNormalViewMatrix, vWorldNormal); + //vEyeNormal = mul(Viewpoint->mNormalViewMatrix, vWorldNormal); } if (!SPHEREMAP) diff --git a/src/rendering/polyrenderer/drawers/screen_triangle.cpp b/src/rendering/polyrenderer/drawers/screen_triangle.cpp index 2965b6b6f..1bd948aec 100644 --- a/src/rendering/polyrenderer/drawers/screen_triangle.cpp +++ b/src/rendering/polyrenderer/drawers/screen_triangle.cpp @@ -371,6 +371,42 @@ static void WriteVaryingWrap(float pos, float step, int x0, int x1, const float* } #endif +#ifdef NO_SSE +static void WriteVaryingColor(float pos, float step, int x0, int x1, const float* w, uint8_t* varying) +{ + for (int x = x0; x < x1; x++) + { + varying[x] = (int)(pos * w[x] * 255.0f); + pos += step; + } +} +#else +static void WriteVaryingColor(float pos, float step, int x0, int x1, const float* w, uint8_t* varying) +{ + int ssecount = ((x1 - x0) & ~3); + int sseend = x0 + ssecount; + + __m128 mstep = _mm_set1_ps(step * 4.0f); + __m128 mpos = _mm_setr_ps(pos, pos + step, pos + step + step, pos + step + step + step); + + for (int x = x0; x < sseend; x += 4) + { + __m128i value = _mm_cvttps_epi32(_mm_mul_ps(_mm_mul_ps(mpos, _mm_loadu_ps(w + x)), _mm_set1_ps(255.0f))); + value = _mm_packs_epi32(value, value); + value = _mm_packus_epi16(value, value); + *(uint32_t*)(varying + x) = _mm_cvtsi128_si32(value); + mpos = _mm_add_ps(mpos, mstep); + } + + pos += ssecount * step; + for (int x = sseend; x < x1; x++) + { + varying[x] = (int)(pos * w[x] * 255.0f); + pos += step; + } +} +#endif + static void WriteVaryings(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) { float startX = x0 + (0.5f - args->v1->x); @@ -381,6 +417,11 @@ static void WriteVaryings(int y, int x0, int x1, const TriDrawTriangleArgs* args WriteVarying(args->v1->worldX * args->v1->w + args->gradientX.WorldX * startX + args->gradientY.WorldX * startY, args->gradientX.WorldX, x0, x1, thread->scanline.W, thread->scanline.WorldX); WriteVarying(args->v1->worldY * args->v1->w + args->gradientX.WorldY * startX + args->gradientY.WorldY * startY, args->gradientX.WorldY, x0, x1, thread->scanline.W, thread->scanline.WorldY); WriteVarying(args->v1->worldZ * args->v1->w + args->gradientX.WorldZ * startX + args->gradientY.WorldZ * startY, args->gradientX.WorldZ, x0, x1, thread->scanline.W, thread->scanline.WorldZ); + WriteVarying(args->v1->gradientdistZ * args->v1->w + args->gradientX.GradientdistZ * startX + args->gradientY.GradientdistZ * startY, args->gradientX.GradientdistZ, x0, x1, thread->scanline.W, thread->scanline.GradientdistZ); + WriteVaryingColor(args->v1->a * args->v1->w + args->gradientX.A * startX + args->gradientY.A * startY, args->gradientX.A, x0, x1, thread->scanline.W, thread->scanline.vColorA); + WriteVaryingColor(args->v1->r * args->v1->w + args->gradientX.R * startX + args->gradientY.R * startY, args->gradientX.R, x0, x1, thread->scanline.W, thread->scanline.vColorR); + WriteVaryingColor(args->v1->g * args->v1->w + args->gradientX.G * startX + args->gradientY.G * startY, args->gradientX.G, x0, x1, thread->scanline.W, thread->scanline.vColorG); + WriteVaryingColor(args->v1->b * args->v1->w + args->gradientX.B * startX + args->gradientY.B * startY, args->gradientX.B, x0, x1, thread->scanline.W, thread->scanline.vColorB); } static const int shiftTable[] = { @@ -621,17 +662,17 @@ static void RunShader(int x0, int x1, PolyTriangleThreadData* thread) const void* tex2Pixels = thread->textures[1].pixels; bool tex2Bgra = thread->textures[1].bgra; - uint32_t frag = thread->mainVertexShader.vColor; - uint32_t frag_r = RPART(frag); - uint32_t frag_g = GPART(frag); - uint32_t frag_b = BPART(frag); - uint32_t frag_a = APART(frag); - frag_r += frag_r >> 7; // 255 -> 256 - frag_g += frag_g >> 7; // 255 -> 256 - frag_b += frag_b >> 7; // 255 -> 256 - frag_a += frag_a >> 7; // 255 -> 256 for (int x = x0; x < x1; x++) { + uint32_t frag_r = thread->scanline.vColorR[x]; + uint32_t frag_g = thread->scanline.vColorG[x]; + uint32_t frag_b = thread->scanline.vColorB[x]; + uint32_t frag_a = thread->scanline.vColorA[x]; + frag_r += frag_r >> 7; // 255 -> 256 + frag_g += frag_g >> 7; // 255 -> 256 + frag_b += frag_b >> 7; // 255 -> 256 + frag_a += frag_a >> 7; // 255 -> 256 + uint32_t t1 = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra); uint32_t t2 = SampleTexture(u[x], 0xffff - v[x], tex2Pixels, tex2Width, tex2Height, tex2Bgra); @@ -797,13 +838,15 @@ static void RunShader(int x0, int x1, PolyTriangleThreadData* thread) } else { - float t = thread->mainVertexShader.gradientdist.Z; - float inv_t = 1.0f - t; - uint32_t r = (int)((streamdata.uObjectColor.r * inv_t + streamdata.uObjectColor2.r * t) * 256.0f); - uint32_t g = (int)((streamdata.uObjectColor.g * inv_t + streamdata.uObjectColor2.g * t) * 256.0f); - uint32_t b = (int)((streamdata.uObjectColor.b * inv_t + streamdata.uObjectColor2.b * t) * 256.0f); + float* gradientdistZ = thread->scanline.GradientdistZ; for (int x = x0; x < x1; x++) { + float t = gradientdistZ[x]; + float inv_t = 1.0f - t; + uint32_t r = (int)((streamdata.uObjectColor.r * inv_t + streamdata.uObjectColor2.r * t) * 256.0f); + uint32_t g = (int)((streamdata.uObjectColor.g * inv_t + streamdata.uObjectColor2.g * t) * 256.0f); + uint32_t b = (int)((streamdata.uObjectColor.b * inv_t + streamdata.uObjectColor2.b * t) * 256.0f); + uint32_t texel = fragcolor[x]; fragcolor[x] = MAKEARGB( APART(texel), @@ -831,25 +874,24 @@ static void RunShader(int x0, int x1, PolyTriangleThreadData* thread) } } - if (thread->mainVertexShader.vColor != 0xffffffff) + for (int x = x0; x < x1; x++) { - uint32_t a = APART(thread->mainVertexShader.vColor); - uint32_t r = RPART(thread->mainVertexShader.vColor); - uint32_t g = GPART(thread->mainVertexShader.vColor); - uint32_t b = BPART(thread->mainVertexShader.vColor); + uint32_t r = thread->scanline.vColorR[x]; + uint32_t g = thread->scanline.vColorG[x]; + uint32_t b = thread->scanline.vColorB[x]; + uint32_t a = thread->scanline.vColorA[x]; + a += a >> 7; r += r >> 7; g += g >> 7; b += b >> 7; - for (int x = x0; x < x1; x++) - { - uint32_t texel = fragcolor[x]; - fragcolor[x] = MAKEARGB( - (APART(texel) * a + 127) >> 8, - (RPART(texel) * r + 127) >> 8, - (GPART(texel) * g + 127) >> 8, - (BPART(texel) * b + 127) >> 8); - } + + uint32_t texel = fragcolor[x]; + fragcolor[x] = MAKEARGB( + (APART(texel) * a + 127) >> 8, + (RPART(texel) * r + 127) >> 8, + (GPART(texel) * g + 127) >> 8, + (BPART(texel) * b + 127) >> 8); } if (constants->uLightLevel >= 0.0f && thread->numPolyLights > 0) diff --git a/src/rendering/polyrenderer/drawers/screen_triangle.h b/src/rendering/polyrenderer/drawers/screen_triangle.h index ccf4818c1..e73edb969 100644 --- a/src/rendering/polyrenderer/drawers/screen_triangle.h +++ b/src/rendering/polyrenderer/drawers/screen_triangle.h @@ -35,12 +35,16 @@ struct ScreenTriVertex float x, y, z, w; float u, v; float worldX, worldY, worldZ; + float a, r, g, b; + float gradientdistZ; }; struct ScreenTriangleStepVariables { float W, U, V; - float WorldX, WorldY, WorldZ, Padding; // Padding so it can be loaded directly into a XMM register + float WorldX, WorldY, WorldZ; + float A, R, G, B; + float GradientdistZ; }; struct TriDrawTriangleArgs @@ -64,6 +68,11 @@ struct TriDrawTriangleArgs gradientX.WorldX = FindGradientX(bottomX, v1->worldX, v2->worldX, v3->worldX); gradientX.WorldY = FindGradientX(bottomX, v1->worldY, v2->worldY, v3->worldY); gradientX.WorldZ = FindGradientX(bottomX, v1->worldZ, v2->worldZ, v3->worldZ); + gradientX.A = FindGradientX(bottomX, v1->a, v2->a, v3->a); + gradientX.R = FindGradientX(bottomX, v1->r, v2->r, v3->r); + gradientX.G = FindGradientX(bottomX, v1->g, v2->g, v3->g); + gradientX.B = FindGradientX(bottomX, v1->b, v2->b, v3->b); + gradientX.GradientdistZ = FindGradientX(bottomX, v1->gradientdistZ, v2->gradientdistZ, v3->gradientdistZ); gradientY.W = FindGradientY(bottomY, 1.0f, 1.0f, 1.0f); gradientY.U = FindGradientY(bottomY, v1->u, v2->u, v3->u); @@ -71,6 +80,11 @@ struct TriDrawTriangleArgs gradientY.WorldX = FindGradientY(bottomY, v1->worldX, v2->worldX, v3->worldX); gradientY.WorldY = FindGradientY(bottomY, v1->worldY, v2->worldY, v3->worldY); gradientY.WorldZ = FindGradientY(bottomY, v1->worldZ, v2->worldZ, v3->worldZ); + gradientY.A = FindGradientY(bottomY, v1->a, v2->a, v3->a); + gradientY.R = FindGradientY(bottomY, v1->r, v2->r, v3->r); + gradientY.G = FindGradientY(bottomY, v1->g, v2->g, v3->g); + gradientY.B = FindGradientY(bottomY, v1->b, v2->b, v3->b); + gradientY.GradientdistZ = FindGradientY(bottomY, v1->gradientdistZ, v2->gradientdistZ, v3->gradientdistZ); return true; }