예제 #1
0
        /// <summary>
        /// Draws a bilboard rectangle with depth. Rendering is clipped against a Y buffer.
        /// </summary>
        /// <param name="dst">Target PixelBuffer.</param>
        /// <param name="centerX">X Coordinate of the rectangle's center</param>
        /// <param name="distance">Distance from the camera to render.</param>
        /// <param name="width">Width of the rectangle at distance = 1</param>
        /// <param name="height">Height of the rectangle at distance = 1</param>
        /// <param name="y_buffer">A ray buffer to do distance clipping against.</param>
        /// <param name="color">The color to render the rectangle.</param>
        public static void rectDepth(PixelBuffer dst, int centerX, float distance, int width, int height, RayData[] y_buffer, Rgba color)
        {
            width  = (int)(width / distance);
            height = (int)(height / distance);
            int hw = (int)((width >> 1));
            int hh = (int)((height >> 1));

            clipRect.x = centerX - hw;
            clipRect.y = (dst.height >> 1) - hh;
            clipRect.w = width;
            clipRect.h = height;
            rect(dst, clipRect.x, clipRect.y, clipRect.w, clipRect.h, clippedColor);

            clipRect.left  = Math.Max(clipRect.x, 0);
            clipRect.right = Math.Min(clipRect.x + clipRect.w, dst.width - 1);
            clipRect.top   = clipRect.y;
            clipRect.bot   = clipRect.y + clipRect.h;
            // clip left
            for (int i = clipRect.left; i < clipRect.right; i++)
            {
                if (y_buffer[i].dis <= distance)
                {
                    clipRect.left = i;
                }
                else
                {
                    break;
                }
            }
            // clip right
            for (int i = clipRect.left + 1; i < clipRect.right; i++)
            {
                if (y_buffer[i].dis <= distance)
                {
                    clipRect.right = i;
                    break;
                }
            }
            rect(dst, clipRect.left, clipRect.top, clipRect.right - clipRect.left, clipRect.bot - clipRect.top, color);
        }
예제 #2
0
 /// <summary>
 /// Client Side Constructor
 /// </summary>
 /// <param name="id">Texture ID</param>
 /// <param name="pixelBuffer">PixelBuffer that is downloaded from the server.</param>
 public TextureDef(int id, PixelBuffer pixelBuffer)
 {
     this.id          = id;
     this.pixelBuffer = pixelBuffer;
 }
예제 #3
0
        public static void sprite(PixelBuffer dst, int x, float distance, RayData[] y_buffer, SpriteDef sprite)
        {
            float scale = sprite.scale;

            // No alpha blending.
            if (sprite.alpha == 0xFF)
            {
                Render.sprite(dst, x, scale, distance, y_buffer, sprite.pixelBuffer);
                return;
            }

            PixelBuffer src   = sprite.pixelBuffer;
            byte        alpha = sprite.alpha;

            int w  = (int)((src.width * scale) / distance);
            int h  = (int)((src.height * scale) / distance);
            int hw = (int)((w >> 1));
            int hh = (int)((h >> 1));

            if (w <= 0 || h <= 0)
            {
                return;
            }
            clipRect.x = x - hw;
            clipRect.y = (dst.height >> 1) - hh;
            clipRect.w = w;
            clipRect.h = h;

            clipRect.left  = Math.Max(clipRect.x, 0);
            clipRect.right = Math.Min(clipRect.x + clipRect.w, dst.width);
            clipRect.top   = Math.Max(clipRect.y, 0);
            clipRect.bot   = Math.Min(clipRect.y + clipRect.h, dst.height);

            // find the first visible column
            for (; clipRect.left < clipRect.right; clipRect.left++)
            {
                if (y_buffer[clipRect.left].dis >= distance)
                {
                    break;
                }
            }

            // Draw the sprite

            // Control vars
            int fp_src_yStep = (src.height << 8) / clipRect.h;
            int fp_src_xStep = (src.width << 8) / clipRect.w;

            // Textures are rendered at 90 degrees due to column rendering
            int fp_u     = ((clipRect.left - clipRect.x) * fp_src_xStep);
            int fp_v     = ((clipRect.top - clipRect.y) * fp_src_yStep);
            int fp_v_org = fp_v;
            //int fp_src_i = ((cRect.top - cRect.y) * fp_src_yStep) + ((cRect.left - cRect.x) * fp_src_xStep);
            int srcIdx;

            // Destination pixel index.
            int dst_i = (clipRect.left << 2) + (clipRect.top * dst.stride);
            int dstIdx;

            int  fp_sblend = alpha;
            int  fp_dblend = 0xFF - alpha;
            byte r;
            byte g;
            byte b;


            // OPTI: Implement Nearsided and Farsighted Sprite Renderer

            // Step through the rendering columns.
            for (; clipRect.left < clipRect.right; clipRect.left++)
            {
                dstIdx = dst_i;
                fp_v   = fp_v_org;
                // If the sprite is clipped here, we're done.
                if (y_buffer[clipRect.left].dis < distance)
                {
                    break;
                }
                for (int t = clipRect.top; t < clipRect.bot; t++)
                {
                    srcIdx = ((((fp_v & 0x7FFFFF00) * src.width) + fp_u) >> 8) << 2;
                    if (srcIdx >= src.pixels.Length)
                    {
                        break;
                    }
                    if (src.pixels[srcIdx + 3] == 0xFF)
                    {
                        r = (byte)(((dst.pixels[dstIdx] * fp_dblend) + (src.pixels[srcIdx] * fp_sblend)) >> 8);
                        g = (byte)(((dst.pixels[dstIdx + 1] * fp_dblend) + (src.pixels[srcIdx + 1] * fp_sblend)) >> 8);
                        b = (byte)(((dst.pixels[dstIdx + 2] * fp_dblend) + (src.pixels[srcIdx + 2] * fp_sblend)) >> 8);
                        dst.pixels[dstIdx]     = r;
                        dst.pixels[dstIdx + 1] = g;
                        dst.pixels[dstIdx + 2] = b;
                        dst.pixels[dstIdx + 3] = 255;
                    }
                    dstIdx += dst.stride;
                    fp_v   += fp_src_yStep;
                }
                fp_u  += fp_src_xStep;
                dst_i += 4;
            }
        }
예제 #4
0
 /// <summary>
 /// Render a sprite on screen, scaled by a given distance.
 /// </summary>
 /// <param name="dst">Target PixelBuffer.</param>
 /// <param name="x">X coordinate of the sprite, centered.</param>
 /// <param name="distance">Distance from the viewer to render the sprite.</param>
 /// <param name="y_buffer">A Ray buffer, used for sprite clipping.</param>
 /// <param name="sprite">The source texture to use for the sprite.</param>
 public static void sprite(PixelBuffer dst, int x, float distance, RayData[] y_buffer, PixelBuffer sprite)
 {
     Render.sprite(dst, x, 1, distance, y_buffer, sprite);
 }
예제 #5
0
        /// <summary>
        /// Draw a row of pixels using a perspective transformed texture map.
        /// </summary>
        /// <param name="dst">Target PixelBuffer</param>
        /// <param name="y">Y coordinate to render this row at</param>
        /// <param name="z">Height of the viewer from the floor</param>
        /// <param name="location_x">X coordinate of viewer, in map units.</param>
        /// <param name="location_y">Y coordinate of viewer, in map units.</param>
        /// <param name="leftAngles">The Ray that describes the far left pixel column angle.</param>
        /// <param name="rightAngles">The Ray that describes the far right pixel column angle.</param>
        /// <param name="src">Source texture to render from.</param>
        public static void floor(PixelBuffer dst, int y, float z, float location_x, float location_y, RayData leftAngles, RayData rightAngles, PixelBuffer src)
        {
            int row = (dst.height / 2) - y;

            z = 0.5f * dst.height;
            float rowDist = z / row;

            float floorStepX = rowDist * (rightAngles.ax - leftAngles.ax) / dst.width;
            float floorStepY = rowDist * (rightAngles.ay - leftAngles.ay) / dst.width;

            float floorX = location_x + rowDist * leftAngles.ax;
            float floorY = location_y + rowDist * leftAngles.ay;

            int u, v;
            int srcIdx;
            int dstIdx = y * dst.stride;

            for (int x = 0; x < dst.width; x++)
            {
                u                      = (int)(src.width * (floorX)) & (src.width - 1);
                v                      = (int)(src.height * (floorY)) & (src.height - 1);
                floorX                += floorStepX;
                floorY                += floorStepY;
                srcIdx                 = (u << 2) + (v * src.stride);
                dst.pixels[dstIdx]     = src.pixels[srcIdx];
                dst.pixels[dstIdx + 1] = src.pixels[srcIdx + 1];
                dst.pixels[dstIdx + 2] = src.pixels[srcIdx + 2];
                dst.pixels[dstIdx + 3] = 255;
                dstIdx                += 4;
            }
        }
예제 #6
0
        /// <summary>
        /// Draw a wall column using a texture for pixel colors and use fog calculations.
        /// </summary>
        /// <param name="dst">Target PixelBuffer</param>
        /// <param name="x">X coordinate to render the wall on.</param>
        /// <param name="z">View height (but does nothing at the moment) </param>
        /// <param name="distance">Distance of the wall from the camera</param>
        /// <param name="textureOffset">Offset of the source texture to render from</param>
        /// <param name="src">Source texture to render from</param>
        public static void wallColumn(PixelBuffer dst, int x, float z, float distance, float textureOffset, PixelBuffer src, Rgba fogColor)
        {
            // Calculate initial source texture position.
            int fp_Src = (int)(src.height * textureOffset);

            fp_Src = fp_Src * src.width;
            fp_Src = fp_Src << 8;

            // Calculate the height of the column render.
            int colHeight = dst.height;

            if (distance != 0)
            {
                colHeight = (int)(dst.height / distance);
            }

            // Calculate view offset
            int viewOfs = (int)(colHeight * (z - 1));

            // Calculate base step ratio for source texture read.
            int fp_srcStep = (src.width << 8) / colHeight;

            // Handle columns too tall for the screen.
            if (colHeight > dst.height || distance == 0)
            {
                // Adjust the source texture data offset.
                fp_Src += fp_srcStep * ((colHeight - dst.height) >> 1);
                // Clip the column height to screen height.
                colHeight = dst.height;
            }
            // Calculate the destination data offset for the write.
            int dstIdx = (x * BPP) + ((((dst.height + viewOfs) - colHeight) >> 1) * dst.stride);

            // Calcualte shading values
            // Fixed point rgba maths
            int fp_r;
            int fp_g;
            int fp_b;
            int fp_fogCol = (int)(distance * 16f);

            fp_fogCol += fogColor.a;
            if (fp_fogCol > 0x0100)
            {
                fp_fogCol = 0x0100;
            }

            //Console.WriteLine(fp_fogCol.ToString("X8"));
            int fog_r = fp_fogCol * (fogColor.r);
            int fog_g = fp_fogCol * (fogColor.g);
            int fog_b = fp_fogCol * (fogColor.b);

            int fp_srcCol = 0x0100 - fp_fogCol;

            int srcIdx;

            if (fp_srcStep >= 0x10000)
            {
                // Draw the column.
                for (int i = 0; i < colHeight; i++)
                {
                    srcIdx = (fp_Src >> 8) << 2;
                    if (dstIdx < 0 || dstIdx >= dst.height)
                    {
                        break;
                    }

                    fp_r = (src.pixels[srcIdx] * fp_srcCol) + fog_r;
                    fp_g = (src.pixels[srcIdx + 1] * fp_srcCol) + fog_g;
                    fp_b = (src.pixels[srcIdx + 2] * fp_srcCol) + fog_b;

                    dst.pixels[dstIdx]     = (byte)(fp_r >> 8);
                    dst.pixels[dstIdx + 1] = (byte)(fp_g >> 8);
                    dst.pixels[dstIdx + 2] = (byte)(fp_b >> 8);
                    dst.pixels[dstIdx + 3] = 255;
                    fp_Src += fp_srcStep;
                    dstIdx += dst.stride;
                }
            }
            else
            {
                // Compressed Column Drawing
                int  fp_nextSrc;
                byte r, g, b;
                // Draw the column.
                for (int i = 0; i < colHeight;)
                {
                    fp_nextSrc = (fp_Src + 0x100) & 0xFFFFF00;
                    srcIdx     = (fp_Src >> 8) << 2;
                    fp_r       = ((src.pixels[srcIdx] * fp_srcCol) + fog_r) >> 8;
                    fp_g       = ((src.pixels[srcIdx + 1] * fp_srcCol) + fog_g) >> 8;
                    fp_b       = ((src.pixels[srcIdx + 2] * fp_srcCol) + fog_b) >> 8;
                    r          = (byte)fp_r;
                    g          = (byte)fp_g;
                    b          = (byte)fp_b;
                    while (fp_Src < fp_nextSrc && i < colHeight)
                    {
                        // HACK: Nearsided renderer should really not have to do this.
                        if (dstIdx >= 0 && dstIdx < dst.pixels.Length)
                        {
                            dst.pixels[dstIdx]     = r;
                            dst.pixels[dstIdx + 1] = g;
                            dst.pixels[dstIdx + 2] = b;
                            dst.pixels[dstIdx + 3] = 255;
                        }
                        fp_Src += fp_srcStep;
                        dstIdx += dst.stride;
                        i++;
                    }
                }
            }
        }
예제 #7
0
        /// <summary>
        /// Draw a wall column using a texture for pixel colors.
        /// </summary>
        /// <param name="dst">Target PixelBuffer.</param>
        /// <param name="x">X coordinate to render the wall on.</param>
        /// <param name="z">View height (but does nothing at the moment) </param>
        /// <param name="distance">Distance of the wall from the camera.</param>
        /// <param name="textureOffset">Offset of the source texture to render from</param>
        /// <param name="src">Source texture to render from</param>
        public static void wallColumn(PixelBuffer dst, int x, float z, float distance, float textureOffset, PixelBuffer src)
        {
            // Calculate initial source texture position.
            int fp_Src = (int)((float)src.height * textureOffset);

            fp_Src = fp_Src * src.width;
            fp_Src = fp_Src << 8;

            // Calculate the height of the column render.
            int colHeight = dst.height;

            if (distance != 0)
            {
                colHeight = (int)(dst.height / distance);
            }

            // Calculate view offset
            int viewOfs = (int)(colHeight * (z - 1));

            // Calculate base step ratio for source texture read.
            int fpSrcStep = (src.width << 8) / colHeight;

            // Handle columns too tall for the screen.
            if (colHeight > dst.height || distance == 0)
            {
                // Adjust the source texture data offset.
                fp_Src += fpSrcStep * ((colHeight - dst.height) >> 1);
                // Clip the column height to screen height.
                colHeight = dst.height;
            }
            // Calculate the destination data offset for the write.
            int dstIdx = (x * BPP) + ((((dst.height + viewOfs) - colHeight) >> 1) * dst.stride);
            int srcIdx;

            // Draw the column.
            for (int i = 0; i < colHeight; i++)
            {
                srcIdx                 = (fp_Src >> 8) << 2;
                dst.pixels[dstIdx]     = (byte)(src.pixels[srcIdx]);
                dst.pixels[dstIdx + 1] = (byte)(src.pixels[srcIdx + 1]);
                dst.pixels[dstIdx + 2] = (byte)(src.pixels[srcIdx + 2]);
                dst.pixels[dstIdx + 3] = (byte)(src.pixels[srcIdx + 3]);
                fp_Src                += fpSrcStep;
                dstIdx                += dst.stride;
            }
        }
예제 #8
0
        /// <summary>
        /// Draw a rectangle.
        /// </summary>
        /// <param name="x">Left edge coordinate of the rectangle</param>
        /// <param name="y">Top edge coordinate of teh rectangle</param>
        /// <param name="width">Width in pixels</param>
        /// <param name="height">Height in pixels</param>
        /// <param name="color">The desired RGBA color</param>
        public static void rect(PixelBuffer dst, int x, int y, int width, int height, Rgba color)
        {
            // Find clipping rectangle.
            int left  = Math.Max(x, 0);
            int right = Math.Min(x + width, dst.width - 1);
            int top   = Math.Max(y, 0);
            int bot   = Math.Min(y + height, dst.height - 1);
            int clipH = bot - top;
            int clipW = right - left;

            if (clipH <= 0 || clipW <= 0)
            {
                return;
            }

            int dy   = top * dst.stride;
            int dstA = dy + (left << 2);
            int dstB = dy + (right << 2);
            // Draw pixel with alpha blending.
            int fp8_dstBlend = 0xFF - color.a;
            int ar           = color.r * color.a;
            int ag           = color.g * color.a;
            int ab           = color.b * color.a;

            // Draw cols.
            for (int i = 0; i < clipH; i++)
            {
                if (left == x)
                {
                    dst.pixels[dstA + 0] = (byte)(((dst.pixels[dstA + 0] * fp8_dstBlend) + ar) >> 8);
                    dst.pixels[dstA + 1] = (byte)(((dst.pixels[dstA + 1] * fp8_dstBlend) + ag) >> 8);
                    dst.pixels[dstA + 2] = (byte)(((dst.pixels[dstA + 2] * fp8_dstBlend) + ab) >> 8);
                    dst.pixels[dstA + 3] = 255;
                }
                if (right == x + width)
                {
                    dst.pixels[dstB + 0] = (byte)(((dst.pixels[dstB + 0] * fp8_dstBlend) + ar) >> 8);
                    dst.pixels[dstB + 1] = (byte)(((dst.pixels[dstB + 1] * fp8_dstBlend) + ag) >> 8);
                    dst.pixels[dstB + 2] = (byte)(((dst.pixels[dstB + 2] * fp8_dstBlend) + ab) >> 8);
                    dst.pixels[dstB + 3] = 255;
                }
                dstA += dst.stride;
                dstB += dst.stride;
            }

            dstB = dy + (left << 2);
            // Draw rows
            for (int i = 0; i < clipW; i++)
            {
                if (bot == (y + height))
                {
                    dst.pixels[dstA + 0] = (byte)(((dst.pixels[dstA + 0] * fp8_dstBlend) + ar) >> 8);
                    dst.pixels[dstA + 1] = (byte)(((dst.pixels[dstA + 1] * fp8_dstBlend) + ag) >> 8);
                    dst.pixels[dstA + 2] = (byte)(((dst.pixels[dstA + 2] * fp8_dstBlend) + ab) >> 8);
                    dst.pixels[dstA + 3] = 255;
                }
                if (top == y)
                {
                    dst.pixels[dstB + 0] = (byte)(((dst.pixels[dstB + 0] * fp8_dstBlend) + ar) >> 8);
                    dst.pixels[dstB + 1] = (byte)(((dst.pixels[dstB + 1] * fp8_dstBlend) + ag) >> 8);
                    dst.pixels[dstB + 2] = (byte)(((dst.pixels[dstB + 2] * fp8_dstBlend) + ab) >> 8);
                    dst.pixels[dstB + 3] = 255;
                }
                dstA += BPP;
                dstB += BPP;
            }
        }
예제 #9
0
 /// <summary>
 /// Create a sprite defention with alpha parameter set.
 /// </summary>
 /// <param name="texture_id">ID number of this sprite.</param>
 /// <param name="alpha">Overall alpha value for this sprite.</param>
 public SpriteDef(int id, byte alpha)
 {
     this.id     = id;
     this.alpha  = alpha;
     pixelBuffer = null;
 }
예제 #10
0
 /// <summary>
 /// Creates a sprite defenition that references a given texture.
 /// </summary>
 /// <param name="sprite_id">ID number of this sprite.</param>
 public SpriteDef(int id)
 {
     this.id     = id;
     alpha       = 0xFF;
     pixelBuffer = null;
 }
예제 #11
0
 /// <summary>
 /// Default Constructor
 /// </summary>
 public SpriteDef()
 {
     id          = 0;
     alpha       = 0xFF;
     pixelBuffer = null;
 }