Пример #1
0
        /// <summary>
        /// Use raycasting to determine the distance to the nearest wall at specified angle
        /// </summary>
        /// <param name="angle">angle in degrees</param>
        /// <param name="objectsGrid">the grid array in which the objects are defined</param>
        /// <returns>location of the first object found</returns>
        private WorldObject FindObject(Angle angle, int[][] objectsGrid)
        {
            // Look for the nearest intersecting wall
            Intersection intersection = FindIntersection(angle, objectsGrid);

            if (intersection == null)
            {
                return null;
            }

            WorldObject obj = new WorldObject(intersection);

            // Calculate TextureX property which determines which part of the texture to map to this object
            Point gridLocation = CoordsToGrid(obj);

            // Set texture for the object
            obj.TextureIndex = objectsGrid[gridLocation.Y][gridLocation.X];

            // Determine on which X-coordinate of the object the intersection was found
            obj.TextureX = obj.IntersectsWith == IntersectionAxe.Xaxe
                            ? (int)(obj.X % wallSize)
                            : (int)(obj.Y % wallSize);

            return obj;
        }
Пример #2
0
        /// <summary>
        /// Draw walls that are found for the current vertical scanline
        /// </summary>
        /// <param name="scanline"></param>
        /// <param name="drawingBuffer"></param>
        private void DrawObject(int scanline, WorldObject obj, Pixel[] drawingBuffer)
        {
            // Remove distortion (counter fishbowl effect)
            Angle distortionRemovalAngle = new Angle(fieldOfView / 2);
            distortionRemovalAngle.Turn(-angleBetweenRays.Value * (double)scanline);
            obj.Distance = obj.Distance * Math.Cos(distortionRemovalAngle.ToRadians());

            // Use distance to determine the size of the wall slice
            int wallHeight = (int)Math.Floor(wallSize / obj.Distance * distanceToViewPort);

            // The visible scale of a wall compared to its original size
            double wallScale = (double)wallHeight / wallSize;

            // If a wall slice is larger than the viewport height, we only need the visible section
            // skipPixels indicates how many pixels from top and bottom towards the center can be skipped during rendering
            int skipPixels = wallHeight > viewPort.Height ? (wallHeight - viewPort.Height) / 2 : 0;
            int scanlineStartY = centerOfViewPort.Y - (wallHeight - skipPixels * 2) / 2;

            // Draw wall slice (untextured)
            // GLDraw.DrawLine(new Point(scanline, centerOfViewPort.Y - (wallHeight - skipPixels * 2) / 2), new Point(scanline, centerOfViewPort.Y + (wallHeight - skipPixels * 2) / 2), wall.IntersectsWith == IntersectionAxe.Xaxe ? Color.DarkGray : Color.Gray);

            // Determine start indexes for texture read and viewport write buffers
            int drawingBufferStart = obj.TextureX * (int)wallSize;
            int viewPortBufferIndex = scanline * viewPort.Height;

            // Generate a scanline with a textured wall slice
            for (int y = 0 + skipPixels; y < wallHeight - skipPixels; y++)
            {
                // Determine index of texture pixel while taking zoom into account
                int textureCurrentPixelIndex = (int)(y / wallScale);

                // Current scanline pixel index
                int spxIndex = y - skipPixels;

                // Current viewPortBuffer index
                int drawingBufferIndex = viewPortBufferIndex + spxIndex;

                // Create a pixel in the scanline draw buffer
                Color pixelColor = textures[obj.TextureIndex][drawingBufferStart + textureCurrentPixelIndex].Color;
                if (pixelColor.ToArgb() != Color.Black.ToArgb())
                {
                    drawingBuffer[drawingBufferIndex] = new Pixel();
                    drawingBuffer[drawingBufferIndex].X = scanline;
                    drawingBuffer[drawingBufferIndex].Y = scanlineStartY + spxIndex;
                    drawingBuffer[drawingBufferIndex].Color = pixelColor;

                    // Pixels on dark sides of walls need to be half the color value
                    if (obj.IntersectsWith == IntersectionAxe.Xaxe)
                    {
                        Color color = drawingBuffer[drawingBufferIndex].Color;
                        drawingBuffer[drawingBufferIndex].Color = Color.FromArgb(color.R / 2, color.G / 2, color.B / 2);
                    }

                    // Make walls in the distance darker
                    if (obj.Distance > 250)
                    {
                        double colorDivider = obj.Distance / 250;
                        colorDivider = (colorDivider > 3) ? 3 : colorDivider;

                        Color color = drawingBuffer[drawingBufferIndex].Color;
                        drawingBuffer[drawingBufferIndex].Color = Color.FromArgb((int)(color.R / colorDivider), (int)(color.G / colorDivider), (int)(color.B / colorDivider));
                    }
                }
            }
        }