Initial test with software rasterizer on C# and SDL2 Wrapper

Posted 1 month ago2023-11-02 11:11:36 UTC
DeafMan1983 DeafMan1983C# Developer and Linux Creator
I have updated porting from Linedrawing
I tested with my SDL2 Wrapper = OK It is very fast like Quake 2's or Old Half-Life's Software Rasterizer :)
namespace RasterizerTest;

using DeafMan1983.Interop.SDL2;
using static DeafMan1983.Interop.SDL2.SDL;

unsafe class Program
{
    class Rasterizer
    {
        private uint* m_pixels;
        private int m_w, m_h;

        public void SetFrameBuffer(uint* pixels, int w, int h)
        {
            m_pixels = pixels;
            m_w = w;
            m_h = h;
        }

        // Without SDL_Surface and try to convert from SDL_Color to pixel (uint32)
        private uint ToPixel(SDL_Color color)
        {
            return ((uint)color.b << 16) | ((uint)color.g << 8) | (color.r);
        }

        public void SetPixel(int x, int y, SDL_Color color)
        {
            if (x >= m_w || y >= m_h)
                return;

            m_pixels[y * m_w + x] = ToPixel(color);
        }

        public void SetPixel(float x, float y, SDL_Color color)
        {
            SetPixel((int)x, (int)y, color);
        }

        public void Clear(SDL_Window* window)
        {
            SDL_FreeSurface(SDL_GetWindowSurface(window));
        }

        public void DrawLine(SDL_Color color1, float x1, float y1,
                            SDL_Color color2, float x2, float y2)
        {
            float xdiff = x2 - x1;
            float ydiff = y2 - y1;

            if (xdiff == 0 && ydiff == 0)
            {
                SetPixel(x1, y1, color1);
                return;
            }

            if (MathF.Abs(xdiff) > MathF.Abs(ydiff))
            {
                float xmin, xmax;

                if (x1 < x2)
                {
                    xmin = x1;
                    xmax = x2;
                }
                else
                {
                    xmin = x2;
                    xmax = x1;
                }

                float slope = ydiff / xdiff;
                for (float x = xmin; x <= xmax; x += 1)
                {
                    float y = y1 + ((x - x1) * slope);
                    byte color_r = (byte)(color2.r + (color2.r - color1.r) * ((x - x1) / xdiff));
                    byte color_g = (byte)(color2.g + (color2.g - color1.g) * ((x - x1) / xdiff));
                    byte color_b = (byte)(color2.b + (color2.b - color1.b) * ((x - x1) / xdiff));
                    SDL_Color color = new SDL_Color{r = color_r, g = color_g, b = color_b};
                    SetPixel(x, y, color);
                }
            }
            else
            {
                float ymin, ymax;

                if (y1 < y2)
                {
                    ymin = y1;
                    ymax = y2;
                }
                else
                {
                    ymin = y2;
                    ymax = y1;
                }

                float slope = xdiff / ydiff;
                for (float y = ymin; y <= ymax; y += 1)
                {
                    float x = x1 + ((y - y1) * slope);
                    byte color_r = (byte)(color2.r + (color2.r - color1.r) * ((y - y1) / ydiff));
                    byte color_g = (byte)(color2.g + (color2.g - color1.g) * ((y - y1) / ydiff));
                    byte color_b = (byte)(color2.b + (color2.b - color1.b) * ((y - y1) / ydiff));
                    SDL_Color color = new SDL_Color{r = color_r, g = color_g, b = color_b};
                    SetPixel(x, y, color);
                }
            }
        }
    }

    const int width = 640;
    const int height = 480;

    static int Main(string[] args)
    {
        SDL_Init(SDL_INIT_VIDEO);

        SDL_Window* window = SDL_CreateWindow(null, (int)SDL_WINDOWPOS_CENTERED, (int)SDL_WINDOWPOS_CENTERED, width, height, (uint)SDL_WindowFlags.SDL_WINDOW_SHOWN);
        SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, (uint)SDL_RendererFlags.SDL_RENDERER_SOFTWARE);
        SDL_Texture* texture = SDL_CreateTexture(renderer, (uint)SDL_PixelFormatEnum.SDL_PIXELFORMAT_RGBA32, (int)SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, width, height);

        Rasterizer rast = new();
        float r = 0.0f;

        while(true)
        {
            SDL_Event evt;
            SDL_PollEvent(&evt);
            if (evt.type == (uint)SDL_EventType.SDL_QUIT)
            {
                break;
            }

            if (evt.type == (uint)SDL_EventType.SDL_KEYDOWN)
            {
                if (evt.key.keysym.sym == SDL_KeyCode.SDLK_ESCAPE)
                {
                    break;
                }
            }

            uint* pixels;
            int pitch;

            if (SDL_LockTexture(texture, null, (void**)&pixels, &pitch) != 0)
                return -1;

            rast.SetFrameBuffer(pixels, width, height);
            rast.Clear(window);

            float size = 120;
            float x1 = (float)((width / 2) + MathF.Cos(r - MathF.PI / 6.0f) * size);
            float y1 = (float)((height / 2) + MathF.Sin(r - MathF.PI / 6.0f) * size);
            float x2 = (float)((width / 2) + MathF.Cos(r + MathF.PI / 2.0f) * size);
            float y2 = (float)((height / 2) + MathF.Sin(r + MathF.PI / 2.0f) * size);
            float x3 = (float)((width / 2) + MathF.Cos(r + MathF.PI + MathF.PI / 6.0f) * size);
            float y3 = (float)((height / 2) + MathF.Sin(r + MathF.PI + MathF.PI / 6.0f) * size);

            SDL_Color color1 = new SDL_Color { r = 255, g = 0, b = 0};
            SDL_Color color2 = new SDL_Color { r = 0, g = 255, b = 0};
            SDL_Color color3 = new SDL_Color { r = 0, g = 0, b = 255};

            rast.DrawLine(color1, x1, y1, color2, x2, y2);
            rast.DrawLine(color2, x2, y2, color3, x3, y3);
            rast.DrawLine(color3, x3, y3, color1, x1, y1);

            SDL_UnlockTexture(texture);
            if (SDL_RenderClear(renderer) != 0)
                return -1;

            if (SDL_RenderCopy(renderer, texture, null, null) != 0)
                return -1;

            SDL_RenderPresent(renderer);
        }

        SDL_DestroyTexture(texture);
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
        SDL_Quit();

        return 0;
    }
}
Result:
User posted image
Enjoy and happy coding on C#!

Comments

You must log in to post a comment. You can login or register a new account.