示例#1
0
 private void RenderChildObjects(CRenderContext Context)
 {
     for (int i = 0; i < Children.Count; i++)
     {
         ((CObject3D)Children[i]).Render(Context);
     }
 }
示例#2
0
        // Draw a filled triangle on a given rendering context
        public static void DrawFilledTriangle(T2DTriangle Triangle, CRenderContext Context, Color FillColor, float M, float N, float K)
        {
            // Scan the list to find the top and bottom of the polygon
            int MinIndexL  = 0;
            int MaxIndex   = 0;
            int MinPoint_Y = Triangle.Corner1.Y;
            int MaxPoint_Y = MinPoint_Y;

            int CurrentIndex, PreviousIndex;

            // Create a temporary array for triangle corner points
            Point[] Points = new Point[3] {
                Triangle.Corner1, Triangle.Corner2, Triangle.Corner3
            };

            for (int i = 1; i < 3; i++)
            {
                if (Points[i].Y < MinPoint_Y)
                {
                    // new top
                    MinPoint_Y = Points[i].Y;
                    MinIndexL  = i;
                }
                else
                if (Points[i].Y > MaxPoint_Y)
                {
                    // new bottom
                    MaxPoint_Y = Points[i].Y;
                    MaxIndex   = i;
                }
            }

            if (MinPoint_Y == MaxPoint_Y)
            {
                // Triangle is 0-height
                return;
            }

            // Scan in ascending order to find the last top-edge point
            int MinIndexR = MinIndexL;

            while (Points[MinIndexR].Y == MinPoint_Y)
            {
                MinIndexR = IndexForward(MinIndexR);
            }

            // back up to last top-edge point
            MinIndexR = IndexBackward(MinIndexR);

            // Now scan in descending order to find the first top-edge point
            while (Points[MinIndexL].Y == MinPoint_Y)
            {
                MinIndexL = IndexBackward(MinIndexL);
            }

            // back up to first top-edge point
            MinIndexL = IndexForward(MinIndexL);

            // Figure out which direction through the vertex list from the top
            // vertex is the left edge and which is the right}
            int LeftEdgeDir = -1; // {assume left edge runs down thru vertex list

            int TopIsFlat;

            if (Points[MinIndexL].X != Points[MinIndexR].X)
            {
                TopIsFlat = 1;
            }
            else
            {
                TopIsFlat = 0;
            }

            // If the top is flat, just see which of the ends is leftmost
            if (TopIsFlat == 1)
            {
                if (Points[MinIndexL].X > Points[MinIndexR].X)
                {
                    LeftEdgeDir = 1;       // left edge runs up through vertex list
                    int Temp = MinIndexL;  // swap the indices so MinIndexL
                    MinIndexL = MinIndexR; //points to the start of the left
                    MinIndexR = Temp;      // edge, similarly for MinIndexR
                }
            }
            else
            {
                // Point to the downward end of the first line of each of the
                // two edges down from the top}
                int NextIndex = MinIndexR;
                NextIndex     = IndexForward(NextIndex);
                PreviousIndex = MinIndexL;
                PreviousIndex = IndexBackward(PreviousIndex);

                // Calculate X and Y lengths from the top vertex to the end of
                // the first line down each edge; use those to compare slopes
                // and see which line is leftmost
                int DeltaXN = Points[NextIndex].X - Points[MinIndexL].X;
                int DeltaYN = Points[NextIndex].Y - Points[MinIndexL].Y;
                int DeltaXP = Points[PreviousIndex].X - Points[MinIndexL].X;
                int DeltaYP = Points[PreviousIndex].Y - Points[MinIndexL].Y;

                if ((DeltaXN * DeltaYP - DeltaYN * DeltaXP) < 0)
                {
                    LeftEdgeDir = 1;       // left edge runs up through vertex list
                    int Temp = MinIndexL;  // swap the indices so MinIndexL
                    MinIndexL = MinIndexR; // points to the start of the left
                    MinIndexR = Temp;      // edge, similarly for MinIndexR
                }
            }

            // Set the # of scan lines in the polygon, skipping the bottom edge
            // and also skipping the top vertex if the top isn't flat because
            // in that case the top vertex has a right edge component, and set
            // the top scan line to draw, which is likewise the second line of
            // the polygon unless the top is flat}
            int HLineListLength = MaxPoint_Y - MinPoint_Y - 1 + TopIsFlat;

            if (HLineListLength <= 0)
            {
                // there's nothing to draw, so we're done
                return;
            }

            THLine[] HLineList = new THLine[HLineListLength];

            int HLineListYStart = MinPoint_Y + 1 - TopIsFlat;

            // Scan the left edge and store the boundary points in the list
            // Initial pointer for storing scan converted left-edge coords
            int EdgePointPtr = 0;

            // Start from the top of the left edge
            CurrentIndex  = MinIndexL;
            PreviousIndex = MinIndexL;

            // Skip the first point of the first line unless the top is flat;
            // if the top isn't flat, the top vertex is exactly on a right
            // edge and isn't drawn}
            int SkipFirst = 1 - TopIsFlat;

            // Scan convert each line in the left edge from top to bottom
            do
            {
                CurrentIndex = IndexMove(CurrentIndex, LeftEdgeDir, 3);

                ScanEdge(Points[PreviousIndex].X, Points[PreviousIndex].Y,
                         Points[CurrentIndex].X, Points[CurrentIndex].Y, 1,
                         SkipFirst, ref EdgePointPtr, HLineList, Context.HalfHeight);

                PreviousIndex = CurrentIndex;
                SkipFirst     = 0; // scan convert the first point from now on
            } while(CurrentIndex != MaxIndex);

            // Scan the right edge and store the boundary points in the list
            EdgePointPtr  = 0;
            CurrentIndex  = MinIndexR;
            PreviousIndex = MinIndexR;
            SkipFirst     = 1 - TopIsFlat;

            // Scan convert the right edge, top to bottom. X coordinates are
            // adjusted 1 to the left, effectively causing scan conversion of
            // the nearest points to the left of but not exactly on the edge}
            do
            {
                CurrentIndex = IndexMove(CurrentIndex, -LeftEdgeDir, 3);

                ScanEdge(Points[PreviousIndex].X - 1, Points[PreviousIndex].Y,
                         Points[CurrentIndex].X - 1, Points[CurrentIndex].Y, 0,
                         SkipFirst, ref EdgePointPtr, HLineList, Context.HalfHeight);

                PreviousIndex = CurrentIndex;
                SkipFirst     = 0; // scan convert the first point from now on
            } while(CurrentIndex != MaxIndex);

            // {Draw the line list representing the scan converted polygon}
            DrawHorizontalLineList(Context, HLineList, HLineListYStart, FillColor.ToArgb(), M, N, K);
        }
示例#3
0
        private static void DrawHorizontalLineList(CRenderContext Context, THLine[] HLines, int YStart, int ARGBColor, float M, float N, float K)
        {
            int HalfWidth  = Context.HalfWidth;
            int HalfHeight = Context.HalfHeight;

            for (int i = 0; i < HLines.Length; i++)
            {
                int XLineStart = HLines[i].XStart;
                int XLineEnd   = HLines[i].XEnd;
                int y          = i + YStart;
                int YLine      = HalfHeight - y;

                // Draw only lines that in the screen Y range
                if ((YLine >= 0) && (YLine < Context.Height))
                {
                    // Convert logical 2D coordinates to absolute 2D screen coordinates
                    int ScreenXStart = HalfWidth + XLineStart;
                    int ScreenXEnd   = HalfWidth + XLineEnd;

                    // Check if the line is outside the screen
                    if ((ScreenXStart >= Context.Width) || (ScreenXEnd < 0))
                    {
                        continue;
                    }

                    // Clip the horizontal line
                    if (ScreenXStart < 0)
                    {
                        XLineStart = -HalfWidth;
                    }

                    if (ScreenXEnd >= Context.Width)
                    {
                        XLineEnd = HalfWidth - 1;
                    }

                    unsafe
                    {
                        // Get pointers to the line start
                        int *PixelPtr = (int *)Context.GetLinePtr(YLine) + HalfWidth + XLineStart;

                        float[] ZBuffer    = Context.GetZBuffer();
                        int     PosInZBuff = YLine * Context.Width + HalfWidth + XLineStart;

                        for (int x = XLineStart; x <= XLineEnd; x++)
                        {
                            float OneDivZ = M * x + N * y + K;

                            if (OneDivZ > ZBuffer[PosInZBuff])
                            {
                                *PixelPtr = ARGBColor;
                                ZBuffer[PosInZBuff] = OneDivZ;
                            }

                            PixelPtr++;
                            PosInZBuff++;
                        }
                    }
                }
            }
        }
示例#4
0
        // Perform rendering on a specific context
        public void Render(CRenderContext Context)
        {
            if (!Visible)
            {
                return;
            }

            // Calculate transform matrix
            TMat4x4 Mat = GetTransformMatrix(Context);

            // Calculate the inverse matrix
            TMat4x4 InverseMat = Mat.FindInverseMat();

            // Clear translation effect
            InverseMat.ClearTranslation();

            // Calculate the viewer position in object coordinates
            TVertex ViewDirection = Context.GetViewDirection();

            TVertex ViewerPosInObjCoords = InverseMat.MulVertex(ViewDirection);

            float PerspectiveFactor = Context.GetPerspectiveFactor();

            Color IlluminatedFaceColor;

            foreach (TFace3D Face in FaceTable)
            {
                bool  FaceVisible;
                float FaceDotProd = 0;

                if (!Context.IsBackfaceCullingMode())
                {
                    // No backface culling, the face is always visible
                    FaceVisible = true;
                }
                else
                {
                    // Do backface culling
                    FaceDotProd = Math3D.DotProduct(ViewerPosInObjCoords, Face.Normal);

                    // Perspective mode
                    if (Context.IsPerspectiveMode())
                    {
                        // Remember if the face is visible
                        FaceVisible = (FaceDotProd > THRESHOLD_FOR_CULLING);
                    }
                    else
                    {
                        FaceVisible = (FaceDotProd > 0);
                    }
                }

                if (FaceVisible)
                {
                    // Get current face vertices and transform to world coordinates
                    TVertex[] FaceVertex = new TVertex[3] {
                        Mat.MulVertex(VertexTable[Face.AIndex]),
                        Mat.MulVertex(VertexTable[Face.BIndex]),
                        Mat.MulVertex(VertexTable[Face.CIndex])
                    };

                    Point[] ScreenCoords = new Point[3];

                    if (TestForBackClipping(FaceVertex[0], FaceVertex[1], FaceVertex[2]))
                    {
                        bool PreventFaceDraw = false;

                        // Perspective mode
                        if (Context.IsPerspectiveMode())
                        {
                            // Transform the from world coordinates to screen coordinates
                            for (int i = 0; i < 3; i++)
                            {
                                if (Math.Abs(FaceVertex[i].Z) < POLYGON_Z_MIN_VALUE)
                                {
                                    PreventFaceDraw = true;
                                    break;
                                }

                                ScreenCoords[i].X = (int)(FaceVertex[i].X * PerspectiveFactor / FaceVertex[i].Z);
                                ScreenCoords[i].Y = (int)(FaceVertex[i].Y * PerspectiveFactor / FaceVertex[i].Z);

                                if ((Math.Abs(ScreenCoords[i].X) > POLYGON_COORD_MAX_VALUE) || (Math.Abs(ScreenCoords[i].Y) > POLYGON_COORD_MAX_VALUE))
                                {
                                    PreventFaceDraw = true;
                                    break;
                                }
                            }
                        }
                        else
                        // Orthogonal projection
                        {
                            PreventFaceDraw = false;

                            // Transform the from world coordinates to screen coordinates
                            for (int i = 0; i < 3; i++)
                            {
                                ScreenCoords[i].X = (int)(FaceVertex[i].X / ORTHO_PROJECTION_SCALING);
                                ScreenCoords[i].Y = (int)(FaceVertex[i].Y / ORTHO_PROJECTION_SCALING);
                            }
                        }

                        if (!PreventFaceDraw)
                        {
                            T2DTriangle ScreenTriangle = new T2DTriangle(ScreenCoords[0], ScreenCoords[1], ScreenCoords[2]);

                            if (Context.IsWireFrameMode())
                            {
                                Context.DrawTriangle(ScreenTriangle);
                            }
                            else
                            // Filled triangles mode
                            {
                                float LightLevel = FaceDotProd + MIN_LIGHT_LEVEL;

                                // Clip to maximum light level
                                if (LightLevel > 1.0)
                                {
                                    LightLevel = 1.0f;
                                }

                                // Calculate face color
                                int ARGBColor = ClipColorChn(Face.Color.R, LightLevel);
                                ARGBColor |= ClipColorChn(Face.Color.G, LightLevel) << 8;
                                ARGBColor |= ClipColorChn(Face.Color.B, LightLevel) << 16;

                                // Set maximum alpha channel value
                                ARGBColor = (int)((uint)ARGBColor | 0xff000000);

                                IlluminatedFaceColor = Color.FromArgb(ARGBColor);

                                // Calculate factors for the polygon filling routine
                                TVertex FaceNormal = Math3D.CalcFaceNormal(FaceVertex[0], FaceVertex[1], FaceVertex[2]);

                                float M, N, K;
                                CalculatePolygonFactors(FaceNormal, FaceVertex[1], PerspectiveFactor, out M, out N, out K);
                                TriangleFiller.DrawFilledTriangle(ScreenTriangle, Context, IlluminatedFaceColor, M, N, K);
                            }
                        }
                    }
                }
            }

            RenderChildObjects(Context);
        }
示例#5
0
 private TMat4x4 GetTransformMatrix(CRenderContext Context)
 {
     return(CombinedMatrix.MulMat(Context.GetViewMat()));
 }