public void render(object e)
        {

            //screen.floodFill(0, 0, 0x0);
            var screenData = screen.@lock();


            int y;
            DoMovement();

            foreach (var s in Sprites)
            {
                s.ScanComplete = false;
                s.ScanValid = false;

            }

            double rayDirXLeft = dirX - planeX;
            double rayDirYLeft = dirY - planeY;
            var rayDirLeft = new PointDouble { X = rayDirXLeft, Y = rayDirYLeft }.GetRotation();

            double rayDirXRight = dirX + planeX;
            double rayDirYRight = dirY + planeY;
            var rayDirRight = new PointDouble { X = rayDirXRight, Y = rayDirYRight }.GetRotation();

            var DelayDrawSprites = new List<SpriteDrawRequest>();

            var x = 0;
            while (x < w)
            {

                //calculate ray position and direction
                double cameraX = 2.0 * (double)x / (double)w - 1.0; //x-coordinate in camera space
                double rayPosX = posX;
                double rayPosY = posY;
                double rayDirX = dirX + planeX * cameraX;
                double rayDirY = dirY + planeY * cameraX;

                var rayDir = new PointDouble { X = rayDirX, Y = rayDirY }.GetRotation();

                //which box of the map we're in
                var mapX = (rayPosX).Floor();
                var mapY = (rayPosY).Floor();

                //length of ray from current position to next x or y-side
                double sideDistX;
                double sideDistY;

                //length of ray from one x or y-side to next x or y-side
                var deltaDistX = Math.Sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX));
                var deltaDistY = Math.Sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY));

                //what direction to step in x or y-direction (either +1 or -1)
                int stepX;
                int stepY;

                //calculate step and initial sideDist
                if (rayDirX < 0)
                {
                    stepX = -1;
                    sideDistX = (rayPosX - mapX) * deltaDistX;
                }
                else
                {
                    stepX = 1;
                    sideDistX = (mapX + 1.0 - rayPosX) * deltaDistX;
                }
                if (rayDirY < 0)
                {
                    stepY = -1;
                    sideDistY = (rayPosY - mapY) * deltaDistY;
                }
                else
                {
                    stepY = 1;
                    sideDistY = (mapY + 1.0 - rayPosY) * deltaDistY;
                }

                double hit = 0; //was there a wall hit?
                var side = default(int); //was a NS or a EW wall hit?

                while (hit == 0)
                { //perform DDA                 
                    //jump to next map square, OR in x-direction, OR in y-direction
                    if (sideDistX < sideDistY)
                    {
                        sideDistX += deltaDistX;
                        mapX += stepX;
                        side = 0;
                    }
                    else
                    {
                        sideDistY += deltaDistY;
                        mapY += stepY;
                        side = 1;
                    }
                    if (worldMap[mapX, mapY] > 0)
                    {
                        hit = 1; //Check if ray has hit a wall   
                    }
                }

                //Calculate distance projected on camera direction (oblique distance will give fisheye effect!)
                double perpWallDist;
                if (side == 0)
                {
                    perpWallDist = Math.Abs((mapX - rayPosX + (1 - stepX) / 2.0) / rayDirX);
                }
                else
                {
                    perpWallDist = Math.Abs((mapY - rayPosY + (1 - stepY) / 2.0) / rayDirY);
                }

                if (perpWallDist == 0)
                {
                    x++;
                    continue;
                }

                //Calculate height of line to draw on screen
                var lineHeight = Math.Abs((h / perpWallDist).Floor());

                //calculate lowest and highest pixel to fill in current stripe
                var drawStart = (-lineHeight / 2 + h / 2).Floor().Max(0);
                
              

                var drawEnd = (lineHeight / 2 + h / 2).Floor();
                if (drawEnd >= h) drawEnd = h;

                var texNum = worldMap[mapX, mapY] - 1; //1 subtracted from it so that texture 0 can be used!

                //if (texNum != 3)
                texNum = 3;

                //texNum = 0;

                //calculate value of wallX
                double wallX; //where exactly the wall was hit
                if (side == 1)
                {
                    wallX = rayPosX + ((mapY - rayPosY + (1 - stepY) / 2) / rayDirY) * rayDirX;
                }
                else
                {
                    wallX = rayPosY + ((mapX - rayPosX + (1 - stepX) / 2) / rayDirX) * rayDirY;
                }
                wallX -= Math.Floor((wallX));

                //x coordinate on the texture
                var texX = Math.Abs((wallX * texWidth).Floor());
                if (side == 0)
                    if (rayDirX > 0) texX = texWidth - texX - 1;
                if (side == 1)
                    if (rayDirY < 0) texX = texWidth - texX - 1;

                var hT = h * 128;
                var lhT = lineHeight * 128;

                y = drawStart;



                while (y < drawEnd)
                {

                    var d = y * 256 - hT + lhT;  //256 and 128 factors to avoid floats
                    var texY = Math.Abs(((d * texHeight) / lineHeight) / 256);


                    var color = textures[texNum][texX][texY];

                    //var xxx = perpWallDist;
                    #region apply fog
                    var color_r = (color >> 16) & 0xff;
                    var color_g = (color >> 8) & 0xff;
                    var color_b = color & 0xff;

                    var fog = 1 - (perpWallDist / 10).Min();

                    if (side == 0)
                        fog = (fog * 2).Min();

                    color_r = (uint)(color_r * fog);
                    color_g = (uint)(color_g * fog);
                    color_b = (uint)(color_b * fog);


                    color = (color_r << 16) + (color_g << 8) + color_b;
                    #endregion
                    //color = 0xff0000;

               
                        screen.setPixel(x, y, color);
           

                    y += 1;
                }

                //SET THE ZBUFFER FOR THE SPRITE CASTING
                ZBuffer[x] = perpWallDist; //perpendicular distance is used



                //floor casting    
                double floorXWall;
                double floorYWall; //x, y position of the floor texel at the bottom of the wall

                //4 different wall directions possible
                if (side == 0)
                {
                    if (rayDirX > 0)
                    {
                        floorXWall = mapX;
                        floorYWall = mapY + wallX;
                    }
                    else
                    {
                        floorXWall = mapX + 1.0;
                        floorYWall = mapY + wallX;
                    }
                }
                else
                {
                    if (rayDirY > 0)
                    {
                        floorXWall = mapX + wallX;
                        floorYWall = mapY;
                    }
                    else
                    {
                        floorXWall = mapX + wallX;
                        floorYWall = mapY + 1.0;
                    }
                }


                var distWall = perpWallDist;
                var distPlayer = 0.0;
                var currentDist = 0.0;

                if (drawEnd < 0) drawEnd = h; //becomes < 0 when the integer overflows

                //draw the floor from drawEnd to the bottom of the screen
                #region draw flood
                y = drawEnd;
                double weight;
                double currentFloorX;
                double currentFloorY;
                int floorTexX;
                int floorTexY;



                while (y < h)
                {

                    currentDist = (double)h / ((double)2 * (double)y - (double)h); //you could make a small lookup table for this instead
                    //currentDist = floorVals[int(y-80)];

                    weight = (currentDist - distPlayer) / (distWall - distPlayer);

                    currentFloorX = weight * floorXWall + (1.0 - weight) * posX;
                    currentFloorY = weight * floorYWall + (1.0 - weight) * posY;

                    floorTexX = Math.Abs((currentFloorX * texWidth).Floor() % texWidth);
                    floorTexY = Math.Abs((currentFloorY * texHeight).Floor() % texHeight);



                    #region floor
                    try
                    {
                        var color = textures[1][floorTexX][floorTexY];

                        #region apply fog
                        var color_r = (color >> 16) & 0xff;
                        var color_g = (color >> 8) & 0xff;
                        var color_b = color & 0xff;

                        var fog = 1 - (currentDist / 10).Min();

                        fog = (fog * 2).Min();

                        color_r = (uint)(color_r * fog);
                        color_g = (uint)(color_g * fog);
                        color_b = (uint)(color_b * fog);


                        color = (color_r << 16) + (color_g << 8) + color_b;
                        #endregion

                        screen.setPixel(x, y, color); //floor
                    }
                    catch
                    {
                        //trace("err");
                    }
                    #endregion


                    #region draw ceiling
                    try
                    {
                        var color = textures[2][floorTexX][floorTexY];

                        #region apply fog
                        var color_r = (color >> 16) & 0xff;
                        var color_g = (color >> 8) & 0xff;
                        var color_b = color & 0xff;

                        var fog = 1 - (currentDist / 10).Min();

                        fog = (fog * 2).Min();

                        color_r = (uint)(color_r * fog);
                        color_g = (uint)(color_g * fog);
                        color_b = (uint)(color_b * fog);


                        color = (color_r << 16) + (color_g << 8) + color_b;
                        #endregion

                        screen.setPixel(x, h - y - 1, color); //ceiling (symmetrical!)
                    }
                    catch
                    {
                        //trace("err");
                    }
                    #endregion

                    // draw sprites here

                    y++;
                }
                #endregion


                foreach (var s in Sprites)
                {
                    var DeltaToSprite =
                        new PointDouble
                        {
                            X = s.X - posX,
                            Y = s.Y - posY,
                        };


                    var DirectionToSprite = Math.Abs(DeltaToSprite.GetRotation() - rayDir);

                    if (!DeltaToSprite.GetRotation().IsInView(rayDirLeft, rayDirRight))
                    {
                        continue;
                    }


                    if (s.ScanComplete)
                    {
                        // painted
                    }
                    else
                    {
                        //var ScanDirDelta = DirectionToSprite - rayDir;

                        if (x == 0)
                            s.ScanDir = DirectionToSprite;
                        else
                        {
                            if (s.ScanDir < DirectionToSprite)
                            {

                                var ScanDir = s.ScanDir;

                                DelayDrawSprites.Add(
                                    new SpriteDrawRequest
                                    {
                                        Sprite = s,
                                        distance = DeltaToSprite.GetDistance(),
                                        z = (1 / DeltaToSprite.GetDistance()) * 4,
                                        x = x,
                                        Text = new
                                        {
                                            distance = DeltaToSprite.GetDistance()

                                            //dir = DeltaToSprite.GetRotation().RadiansToDegrees(), rayDirLeft = rayDirLeft.RadiansToDegrees(), rayDirRight = rayDirRight.RadiansToDegrees() 
                                        }.ToString().Replace(",", "\n")
                                    }
                                );



                                //for (int _y = 0; _y < (120 * z).ToInt32(); _y++)
                                //{

                                //    screen.setPixel(x + 8, 120 + _y, 0xffffff); //ceili
                                //    screen.setPixel(x, 120 + _y, 0xffffff); //ceili
                                //    screen.setPixel(x, 120 - _y, 0xffffff); //ceili
                                //    screen.setPixel(x + 8, 120 - _y, 0xffffff); //ceili
                                //}
                                s.ScanComplete = true;
                            }
                            else
                            {
                                s.ScanDir = DirectionToSprite;

                            }
                        }
                    }


                }

                x++;

                if (x > 4)
                    render_DebugTrace_Assign_Active = false;
            }

            // draw clipped sprites
            foreach (var r in DelayDrawSprites.Where(i => !i.Sprite.DrawAsImage).OrderBy(i => i.z))
            {
                // hardcoded for now
                var AsTextureWhichHasBits = textures[4];

                var ixstart = r.Rectangle.Left;

                for (int ix = ixstart.Max(0); ix < r.Rectangle.Right.Min(w); ix++)
                {
                    if (ZBuffer[ix] > r.distance)
                    {
                        var target_x = (ix - ixstart) * 64 / r.Rectangle.Width;

                        var iystart = r.Rectangle.Top;
                        for (int iy = iystart.Max(0); iy < r.Rectangle.Bottom.Min(h); iy++)
                        {

                            var target_y = (iy - iystart) * 64 / r.Rectangle.Height;

                            var color = AsTextureWhichHasBits[target_x][target_y];

                            #region apply fog
                            var color_a = (color >> 24) & 0xff;
                            var color_r = (color >> 16) & 0xff;
                            var color_g = (color >> 8) & 0xff;
                            var color_b = color & 0xff;

                            var fog = 1 - (r.distance / 10).Min();

                            fog = (fog * 2).Min();

                            color_r = (uint)(color_r * fog);
                            color_g = (uint)(color_g * fog);
                            color_b = (uint)(color_b * fog);


                            color = (color_r << 16) + (color_g << 8) + color_b;
                            #endregion

                            if (color_a == 0xff)
                                screen.setPixel(ix, iy, color);
                        }
                    }
                }
            }

            counter++;

            if (getTimer() - 1000 >= time)
            {
                txtMain.Text = counter.ToString();
                counter = 0;
                time = getTimer();
            }

            //screenImage.bitmapData = screen;
            screen.UnlockBits(screenData);



            using (var g = Graphics.FromImage(screen))
            using (var green = new SolidBrush(Color.FromArgb(0x7f, Color.Green)))
            using (var yellow = new SolidBrush(Color.FromArgb(0x7f, Color.Yellow)))
            using (var blue = new SolidBrush(Color.FromArgb(0x7f, Color.Blue)))
            using (var purple = new SolidBrush(Color.FromArgb(0x7f, Color.Purple)))
            using (var cyan = new SolidBrush(Color.FromArgb(0x7f, Color.Cyan)))
            {
                foreach (var r in DelayDrawSprites.OrderBy(i => i.z))
                {
                    if (r.Sprite.DrawAsImage)
                        g.DrawImage(r.Sprite.Image, r.Rectangle);
                    else
                        g.DrawRectangle(Pens.Goldenrod, r.Rectangle);

                    if (!string.IsNullOrEmpty(r.Text))
                        g.DrawString(r.Text, SystemFonts.DefaultFont, Brushes.Red, r.Rectangle.X, 120);

                }

                var colors = new[] { green, yellow, blue, purple, cyan };

                g.DrawImage(PistolImage, (w - PistolImage.Width) / 2, h - PistolImage.Height - HudImage.Height);
                g.DrawImage(HudImage, 0, h - HudImage.Height);
                g.ScaleTransform(4, 4);
                // i want a minimap!

                for (int iy = 0; iy < worldMap.YLength; iy++)
                    for (int ix = 0; ix < worldMap.XLength; ix++)
                    {
                        var cell = worldMap[ix, iy];

                        if (cell == 0)
                        {

                        }
                        else
                        {
                            g.FillRectangle(colors[cell % colors.Length], ix, iy, 1, 1);

                        }
                    }

                g.DrawLine(Pens.Red, posX, posY, posX + dirX * 2, posY + dirY * 2);


                foreach (var s in Sprites)
                {

                    g.DrawLine(Pens.Yellow, s.X, s.Y, s.X + 1, s.Y);
                }


            }

        }
Esempio n. 2
0
 public static double GetDistance(this PointDouble p)
 {
     return(Math.Sqrt(p.X * p.X + p.Y * p.Y));
 }