Example #1
0
        private static void Swap(ref VertexProj v1, ref VertexProj v2)
        {
            var temp = v2;

            v2 = v1;
            v1 = temp;
        }
Example #2
0
        // drawing line between 2 points from left to right
        // papb -> pcpd
        // pa, pb, pc, pd must then be sorted before
        private static void ProcessScanLine(
            RenderState state,
            int currentY,
            ref VertexProj va,
            ref VertexProj vb,
            ref VertexProj vc,
            ref VertexProj vd,
            Texture texture)
        {
            Vector3fProj pa = va.Coordinates;
            Vector3fProj pb = vb.Coordinates;
            Vector3fProj pc = vc.Coordinates;
            Vector3fProj pd = vd.Coordinates;

            // Thanks to current Y, we can compute the gradient to compute others values like
            // the starting X (sx) and ending X (ex) to draw between
            // if pa.Y == pb.Y or pc.Y == pd.Y, gradient is forced to 1
            var gradient1 = Math.Abs(pa.Y - pb.Y) > 0.0001 ? ((currentY - pa.Y) * 1.0f / (pb.Y - pa.Y)) : 1;
            var gradient2 = Math.Abs(pc.Y - pd.Y) > 0.0001 ? ((currentY - pc.Y) * 1.0f / (pd.Y - pc.Y)) : 1;

            int sx = (int)Interpolate(pa.X, pb.X, gradient1);
            int ex = (int)Interpolate(pc.X, pd.X, gradient2);

            if (ex < sx)
            {
                return;
            }

            // starting Z & ending Z
            float z1 = Interpolate(pa.Z, pb.Z, gradient1);
            float z2 = Interpolate(pc.Z, pd.Z, gradient2);

            var sqDistA = state.Camera.Position.SqDistBetween(ref va.WorldCoordinates);
            var sqDistB = state.Camera.Position.SqDistBetween(ref vb.WorldCoordinates);
            var sqDistC = state.Camera.Position.SqDistBetween(ref vc.WorldCoordinates);
            var sqDistD = state.Camera.Position.SqDistBetween(ref vd.WorldCoordinates);

            var sSqD = Interpolate(sqDistA, sqDistB, gradient1);
            var eSqD = Interpolate(sqDistC, sqDistD, gradient2);

            // Interpolating normals on Y
            var snx = Interpolate(va.Normal.X, vb.Normal.X, gradient1);
            var enx = Interpolate(vc.Normal.X, vd.Normal.X, gradient2);
            var sny = Interpolate(va.Normal.Y, vb.Normal.Y, gradient1);
            var eny = Interpolate(vc.Normal.Y, vd.Normal.Y, gradient2);
            var snz = Interpolate(va.Normal.Z, vb.Normal.Z, gradient1);
            var enz = Interpolate(vc.Normal.Z, vd.Normal.Z, gradient2);

            float su = 0;
            float eu = 0;
            float sv = 0;
            float ev = 0;

            // Interpolating texture coordinates on Y
            if (texture != null)
            {
                su = Interpolate(va.TextureCoordinates.X, vb.TextureCoordinates.X, gradient1);
                eu = Interpolate(vc.TextureCoordinates.X, vd.TextureCoordinates.X, gradient2);
                sv = Interpolate(va.TextureCoordinates.Y, vb.TextureCoordinates.Y, gradient1);
                ev = Interpolate(vc.TextureCoordinates.Y, vd.TextureCoordinates.Y, gradient2);
            }

            // drawing a line from left (sx) to right (ex), but only for what is visible on screen.
            for (int x = Math.Max(sx, 0); x < Math.Min(ex, state.Width); x++)
            {
                float gradient = (x - sx) / (float)(ex - sx);

                // Interpolating Z, normal and texture coordinates on X
                var z  = Interpolate(z1, z2, gradient);
                var nx = Interpolate(snx, enx, gradient);
                var ny = Interpolate(sny, eny, gradient);
                var nz = Interpolate(snz, enz, gradient);
                var u  = (Interpolate(su, eu, gradient));
                var v  = (Interpolate(sv, ev, gradient));

                var sqD = Interpolate(sSqD, eSqD, gradient);

                // changing the native color value using the cosine of the angle
                // between the light vector and the normal vector
                // and the texture color
                MyColor textureColor = new MyColor();
                if (texture != null)
                {
                    texture.GetPixel(u, v, ref textureColor);
                }
                else
                {
                    textureColor = MyColor.White;
                }

                state.PutPixel(x, currentY, z, textureColor, nx, ny, nz, u, v, sqD);
            }
        }
Example #3
0
        private static void DrawTriangle(
            RenderState state,
            ref VertexProj v1,
            ref VertexProj v2,
            ref VertexProj v3,
            Texture texture,
            ref Vector3f buffv)
        {
            // Sorting the points in order to always have this order on screen p1, p2 & p3
            // with p1 always up (thus having the Y the lowest possible to be near the top screen)
            // then p2 between p1 & p3
            if (v1.Coordinates.Y > v2.Coordinates.Y)
            {
                Swap(ref v1, ref v2);
            }
            if (v2.Coordinates.Y > v3.Coordinates.Y)
            {
                Swap(ref v2, ref v3);
            }
            if (v1.Coordinates.Y > v2.Coordinates.Y)
            {
                Swap(ref v1, ref v2);
            }

            // computing lines' directions
            // http://en.wikipedia.org/wiki/Slope
            // Computing slopes
            Vector3fProj p1 = v1.Coordinates;
            Vector3fProj p2 = v2.Coordinates;
            Vector3fProj p3 = v3.Coordinates;

            // When the slope is zero, it doesn't give good
            // information. Then have to check manually
            //
            //          P1                    P1
            // First    | \       Second     / |
            // branch   |  P2     branch   P2  |
            // is for   | /       is for     \ |
            //          P3                    P3
            // However , when dP1P2 == null
            //          P1--P2            P2--P1
            // First    |   /     Second   \   |
            // branch   |  /      branch    \  |
            // is for   | /       is for     \ |
            //          P3                    P3
            // And dP1P3 cant be null without DP1P2 null first.

            bool useFirst;

            if (p1.Y == p2.Y)
            {
                useFirst = p1.X < p2.X;
            }
            else
            {
                float invSlopeP1P2 = (p2.X - p1.X) * 1.0f / (p2.Y - p1.Y);
                float invSlopeP1P3 = (p3.X - p1.X) * 1.0f / (p3.Y - p1.Y);
                useFirst = invSlopeP1P2 > invSlopeP1P3;
            }

            for (var y = Math.Max(0, p1.Y); y <= Math.Min(state.Height, p3.Y); y++)
            {
                if (useFirst)
                {
                    if (y < p2.Y)
                    {
                        ProcessScanLine(state, y, ref v1, ref v3, ref v1, ref v2, texture);
                    }
                    else
                    {
                        ProcessScanLine(state, y, ref v1, ref v3, ref v2, ref v3, texture);
                    }
                }
                else
                {
                    if (y < p2.Y)
                    {
                        ProcessScanLine(state, y, ref v1, ref v2, ref v1, ref v3, texture);
                    }
                    else
                    {
                        ProcessScanLine(state, y, ref v2, ref v3, ref v1, ref v3, texture);
                    }
                }
            }
        }