public static void DrawTriangle2(Model m, int i)
        {
            var centerX = SoftwareRasterizer3D.CenterX;
            var centerY = SoftwareRasterizer3D.CenterY;

            var j  = 0;
            var a  = m.TriangleViewspaceA[i];
            var b  = m.TriangleViewspaceB[i];
            var c  = m.TriangleViewspaceC[i];
            var aZ = TmpTexturedZ[a];
            var bZ = TmpTexturedZ[b];
            var cZ = TmpTexturedZ[c];

            if (aZ >= 50)
            {
                TmpScreenX[j] = TriangleX[a];
                TmpScreenY[j] = TriangleY[a];
                TmpHsl[j++]   = m.TriHsl1[i];
            }
            else
            {
                int x   = TmpTexturedX[a];
                int y   = TmpTexturedY[a];
                int hsl = m.TriHsl1[i];

                if (cZ >= 50)
                {
                    int decay = (50 - aZ) * SoftwareRasterizer3D.ShadowDecay[cZ - aZ];
                    TmpScreenX[j] = centerX + (x + ((TmpTexturedX[c] - x) * decay >> 16) << 9) / 50;
                    TmpScreenY[j] = centerY + (y + ((TmpTexturedY[c] - y) * decay >> 16) << 9) / 50;
                    TmpHsl[j++]   = hsl + ((m.TriHsl3[i] - hsl) * decay >> 16);
                }

                if (bZ >= 50)
                {
                    int decay = (50 - aZ) * SoftwareRasterizer3D.ShadowDecay[bZ - aZ];
                    TmpScreenX[j] = centerX + (x + ((TmpTexturedX[b] - x) * decay >> 16) << 9) / 50;
                    TmpScreenY[j] = centerY + (y + ((TmpTexturedY[b] - y) * decay >> 16) << 9) / 50;
                    TmpHsl[j++]   = hsl + ((m.TriHsl2[i] - hsl) * decay >> 16);
                }
            }

            if (bZ >= 50)
            {
                TmpScreenX[j] = TriangleX[b];
                TmpScreenY[j] = TriangleY[b];
                TmpHsl[j++]   = m.TriHsl2[i];
            }
            else
            {
                int x   = TmpTexturedX[b];
                int y   = TmpTexturedY[b];
                int hsl = m.TriHsl2[i];

                if (aZ >= 50)
                {
                    int i6 = (50 - bZ) * SoftwareRasterizer3D.ShadowDecay[aZ - bZ];
                    TmpScreenX[j] = centerX + (x + ((TmpTexturedX[a] - x) * i6 >> 16) << 9) / 50;
                    TmpScreenY[j] = centerY + (y + ((TmpTexturedY[a] - y) * i6 >> 16) << 9) / 50;
                    TmpHsl[j++]   = hsl + ((m.TriHsl1[i] - hsl) * i6 >> 16);
                }

                if (cZ >= 50)
                {
                    int j6 = (50 - bZ) * SoftwareRasterizer3D.ShadowDecay[cZ - bZ];
                    TmpScreenX[j] = centerX + (x + ((TmpTexturedX[c] - x) * j6 >> 16) << 9) / 50;
                    TmpScreenY[j] = centerY + (y + ((TmpTexturedY[c] - y) * j6 >> 16) << 9) / 50;
                    TmpHsl[j++]   = hsl + ((m.TriHsl3[i] - hsl) * j6 >> 16);
                }
            }

            if (cZ >= 50)
            {
                TmpScreenX[j] = TriangleX[c];
                TmpScreenY[j] = TriangleY[c];
                TmpHsl[j++]   = m.TriHsl3[i];
            }
            else
            {
                var x   = TmpTexturedX[c];
                var y   = TmpTexturedY[c];
                var hsl = m.TriHsl3[i];
                if (bZ >= 50)
                {
                    var k6 = (50 - cZ) * SoftwareRasterizer3D.ShadowDecay[bZ - cZ];
                    TmpScreenX[j] = centerX + (x + ((TmpTexturedX[b] - x) * k6 >> 16) << 9) / 50;
                    TmpScreenY[j] = centerY + (y + ((TmpTexturedY[b] - y) * k6 >> 16) << 9) / 50;
                    TmpHsl[j++]   = hsl + ((m.TriHsl2[i] - hsl) * k6 >> 16);
                }
                if (aZ >= 50)
                {
                    var l6 = (50 - cZ) * SoftwareRasterizer3D.ShadowDecay[aZ - cZ];
                    TmpScreenX[j] = centerX + (x + ((TmpTexturedX[a] - x) * l6 >> 16) << 9) / 50;
                    TmpScreenY[j] = centerY + (y + ((TmpTexturedY[a] - y) * l6 >> 16) << 9) / 50;
                    TmpHsl[j++]   = hsl + ((m.TriHsl2[i] - hsl) * l6 >> 16);
                }
            }

            var x0 = TmpScreenX[0];
            var x1 = TmpScreenX[1];
            var x2 = TmpScreenX[2];
            var y0 = TmpScreenY[0];
            var y1 = TmpScreenY[1];
            var y2 = TmpScreenY[2];

            if ((x0 - x1) * (y2 - y1) - (y0 - y1) * (x2 - x1) > 0)
            {
                SoftwareRasterizer3D.CheckBounds = false;
                if (j == 3)
                {
                    if (x0 < 0 || x1 < 0 || x2 < 0 || x0 > SoftwareRasterizer2D.Bound || x1 > SoftwareRasterizer2D.Bound || x2 > SoftwareRasterizer2D.Bound)
                    {
                        SoftwareRasterizer3D.CheckBounds = true;
                    }

                    var type = 0;
                    if (m.TriangleInfo != null)
                    {
                        type = m.TriangleInfo[i] & 3;
                    }

                    if (type == TypeShadedTri)
                    {
                        SoftwareRasterizer3D.DrawShadedTriangle(x0, y0, x1, y1, x2, y2, TmpHsl[0], TmpHsl[1], TmpHsl[2]);
                    }
                    else if (type == TypeFlatTri)
                    {
                        SoftwareRasterizer3D.DrawFlatTriangle(x0, y0, x1, y1, x2, y2, ColorUtils.HSLToRGBMap[m.TriHsl1[i]]);
                    }
                    else if (type == TypeShadedTexTri)
                    {
                        var k = m.TriangleInfo[i] >> 2;
                        var x = m.TextureMapX[k];
                        var y = m.TextureMapY[k];
                        var z = m.TextureMapZ[k];
                        SoftwareRasterizer3D.DrawShadedTriangle(x0, y0, x1, y1, x2, y2, TmpHsl[0], TmpHsl[1], TmpHsl[2]);
                    }
                    else if (type == TypeFlatTexTri)
                    {
                        var k = m.TriangleInfo[i] >> 2;
                        var x = m.TextureMapX[k];
                        var y = m.TextureMapY[k];
                        var z = m.TextureMapZ[k];
                        SoftwareRasterizer3D.DrawShadedTriangle(x0, y0, x1, y1, x2, y2, TmpHsl[0], TmpHsl[1], TmpHsl[2]);
                    }
                }
                else if (j == 4)
                {
                    if (x0 < 0 || x1 < 0 || x2 < 0 || x0 > SoftwareRasterizer2D.Bound || x1 > SoftwareRasterizer2D.Bound || x2 > SoftwareRasterizer2D.Bound || TmpScreenX[3] < 0 || TmpScreenX[3] > SoftwareRasterizer2D.Bound)
                    {
                        SoftwareRasterizer3D.CheckBounds = true;
                    }

                    var type = 0;
                    if (m.TriangleInfo != null)
                    {
                        type = m.TriangleInfo[i] & 3;
                    }

                    if (type == TypeShadedTri)
                    {
                        SoftwareRasterizer3D.DrawShadedTriangle(x0, y0, x1, y1, x2, y2, TmpHsl[0], TmpHsl[1], TmpHsl[2]);
                        SoftwareRasterizer3D.DrawShadedTriangle(x0, y0, x2, y2, TmpScreenX[3], TmpScreenY[3], TmpHsl[0], TmpHsl[2], TmpHsl[3]);
                    }
                    else if (type == TypeFlatTri)
                    {
                        var rgb = ColorUtils.HSLToRGBMap[m.TriHsl1[i]];
                        SoftwareRasterizer3D.DrawFlatTriangle(x0, y0, x1, y1, x2, y2, rgb);
                        SoftwareRasterizer3D.DrawFlatTriangle(x0, y0, x2, y2, TmpScreenX[3], TmpScreenY[3], rgb);
                    }
                    else if (type == TypeShadedTexTri)
                    {
                        var k = m.TriangleInfo[i] >> 2;
                        var x = m.TextureMapX[k];
                        var y = m.TextureMapY[k];
                        var z = m.TextureMapZ[k];
                        SoftwareRasterizer3D.DrawShadedTriangle(x0, y0, x1, y1, x2, y2, TmpHsl[0], TmpHsl[1], TmpHsl[2]);
                        SoftwareRasterizer3D.DrawShadedTriangle(x0, y0, x2, y2, TmpScreenX[3], TmpScreenY[3], TmpHsl[0], TmpHsl[2], TmpHsl[3]);
                    }
                    else if (type == TypeFlatTexTri)
                    {
                        var k = m.TriangleInfo[i] >> 2;
                        var x = m.TextureMapX[k];
                        var y = m.TextureMapY[k];
                        var z = m.TextureMapZ[k];
                        SoftwareRasterizer3D.DrawShadedTriangle(x0, y0, x1, y1, x2, y2, TmpHsl[0], TmpHsl[1], TmpHsl[2]);
                        SoftwareRasterizer3D.DrawShadedTriangle(x0, y0, x2, y2, TmpScreenX[3], TmpScreenY[3], TmpHsl[0], TmpHsl[2], TmpHsl[3]);
                    }
                }
            }
        }
        public static void DrawTriangle(Model m, int idx)
        {
            if (TriangleProject[idx])
            {
                DrawTriangle2(m, idx);
                return;
            }

            var firstTriVertex  = m.TriangleViewspaceA[idx];
            var secondTriVertex = m.TriangleViewspaceB[idx];
            var thirdTriVertex  = m.TriangleViewspaceC[idx];

            SoftwareRasterizer3D.CheckBounds = TriangleCheckBounds[idx];
            if (m.TriangleAlpha == null)
            {
                SoftwareRasterizer3D.Opacity = 0;
            }
            else
            {
                SoftwareRasterizer3D.Opacity = m.TriangleAlpha[idx];
            }

            var type = 0;

            if (m.TriangleInfo != null)
            {
                type = m.TriangleInfo[idx] & 3;
            }

            switch (type)
            {
            case TypeShadedTri:
            {
                SoftwareRasterizer3D.DrawShadedTriangle(TriangleX[firstTriVertex], TriangleY[firstTriVertex], TriangleX[secondTriVertex], TriangleY[secondTriVertex], TriangleX[thirdTriVertex], TriangleY[thirdTriVertex], m.TriHsl1[idx], m.TriHsl2[idx], m.TriHsl3[idx]);
                return;
            }

            case TypeFlatTri:
            {
                SoftwareRasterizer3D.DrawFlatTriangle(TriangleX[firstTriVertex], TriangleY[firstTriVertex], TriangleX[secondTriVertex], TriangleY[secondTriVertex], TriangleX[thirdTriVertex], TriangleY[thirdTriVertex], ColorUtils.HSLToRGBMap[m.TriHsl1[idx]]);
                return;
            }

            case TypeShadedTexTri:
            {
                var j = m.TriangleInfo[idx] >> 2;
                var x = m.TextureMapX[j];
                var y = m.TextureMapY[j];
                var z = m.TextureMapZ[j];
                SoftwareRasterizer3D.DrawShadedTriangle(TriangleX[firstTriVertex], TriangleY[firstTriVertex], TriangleX[secondTriVertex], TriangleY[secondTriVertex], TriangleX[thirdTriVertex], TriangleY[thirdTriVertex], m.TriHsl1[idx], m.TriHsl2[idx], m.TriHsl3[idx]);
                return;
            }

            case TypeFlatTexTri:
            {
                var j = m.TriangleInfo[idx] >> 2;
                var x = m.TextureMapX[j];
                var y = m.TextureMapY[j];
                var z = m.TextureMapZ[j];
                SoftwareRasterizer3D.DrawShadedTriangle(TriangleX[firstTriVertex], TriangleY[firstTriVertex], TriangleX[secondTriVertex], TriangleY[secondTriVertex], TriangleX[thirdTriVertex], TriangleY[thirdTriVertex], m.TriHsl1[idx], m.TriHsl2[idx], m.TriHsl3[idx]);
                return;
            }
            }
        }