Skip to content

Problem with Developing a Software Renderer Part 1 #3

@DeafMan1983

Description

@DeafMan1983

Hello dear,
FIXED NOW!
I have tried to port to C#
Is it correct or wrongly?
My code is completely with Clear and ClearColor in class Rasterizer

namespace SurfaceRasterizer;

using static DeafMan1983.ConvFunctions;

using DeafMan1983.Interop.SDL2;
using static DeafMan1983.Interop.SDL2.SDL;
using System.Runtime.InteropServices;

unsafe class Program
{
    const int WIDTH = 1024;
    const int HEIGHT = 728;
    const int POS = (int)SDL_WINDOWPOS_CENTERED;
    static sbyte* TITLE = SBytePointerFromString("Draw Filled Triangle!");
    const uint FLAGS = (uint)SDL_WindowFlags.SDL_WINDOW_SHOWN;

    // Structure Color
    struct Color
    {
        public float R, G, B;

        public Color(float r, float g, float b)
        {
            R = r;
            G = g;
            B = b;
        }

        public uint ToPixel()
        {
            byte red = (byte)(R * 255.0f);
            byte green = (byte)(G * 255.0f);
            byte blue = (byte)(B * 255.0f);

            return (uint)((red << 16) | (green << 8) | blue);
        }

        public static Color operator +(Color left, Color right)
        {
            return new Color(left.R + right.R, left.G + right.G, left.B + right.B);
        }

        public static Color operator -(Color left, Color right)
        {
            return new Color(left.R - right.R, left.G - right.G, left.B - right.B);
        }

        public static Color operator *(Color color, float f)
        {
            return new Color(color.R * f, color.G * f, color.B * f);
        }
    }

    // Structure Vertex
    public struct Vertex
    {
        public float x, y;
        public float r, g, b;

        public Vertex(float x, float y, float r, float g, float b)
        {
            this.x = x;
            this.y = y;
            this.r = r;
            this.g = g;
            this.b = b;
        }

        public static Vertex operator -(Vertex left, Vertex right)
        {
            return new Vertex(left.x - right.x, left.y - right.y, left.r - right.r, left.g - right.g, left.b - right.b);
        }

        public static Vertex operator +(Vertex left, Vertex right)
        {
            return new Vertex(left.x + right.x, left.y + right.y, left.r + right.r, left.g + right.g, left.b + right.b);
        }
    }

    // Structure EdgeEquation
    struct EdgeEquation
    {   
        public float a, b, c;
        public bool tie;

        public EdgeEquation(Vertex v0, Vertex v1)
        {
            a = v0.y - v1.y;
            b = v1.x - v0.x;
            c = - (a * (v0.x + v1.x) + b * (v0.y + v1.y)) / 2;
            tie = a != 0 ? a > 0 : b > 0;
        }

        public float evaluate(float x, float y)
        {
            return a * x + b * y + c;
        }

        public bool test(float x, float y)
        {
            return test(evaluate(x, y));
        }

        public bool test(float v)
        {
            return (v > 0 || v == 0 && tie);
        }
    }

    // Structure ParameterEquation
    struct ParameterEquation
    {
        public float a, b, c;

        public ParameterEquation(float p0, float p1, float p2, EdgeEquation e0, EdgeEquation e1, EdgeEquation e2, float area)
        {
            float factor = 1.0f / (2.0f * area);
            a = factor * (p0 * e0.a + p1 * e1.a + p2 * e2.a);
            b = factor * (p0 * e0.b + p1 * e1.b + p2 * e2.b);
            c = factor * (p0 * e0.c + p1 * e1.c + p2 * e2.c);
        }

        public float evaluate(float x, float y)
        {
            return a * x + b * y + c;
        }
    }

    // Raszerizer
    class Raszerizer
    {
        [DllImport("c")]
        public static extern void* memset(void* str, int c, nuint n);

        private SDL_Surface* m_surf;
        private uint* m_pixels;
        private int m_width;
        private int m_height;

        private int m_minX, m_minY, m_maxX, m_maxY;

        public Raszerizer()
        {
            Viewport(0, 0, 0, 0);
        }

        public void SetFrameBuffer(SDL_Surface* surf, int width, int height)
        {
            m_surf = surf;
            m_pixels = (uint*)surf->pixels;
            m_width = width;
            m_height = height;
        }

        private void SetPixel(int x, int y, Color color)
        {
            if (x >= m_width || y >= m_height)
                return;

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

        private void SetPixel(int x, int y, uint color_pixel)
        {
            if (x >= m_width || y >= m_height)
                return;

            m_pixels[y * m_width + x] = color_pixel;
        }

        public void Clear()
        {
            memset(m_pixels, 0, (nuint)(sizeof(uint) * m_width * m_height));
        }

        public void ClearColor(Color color)
        {
            for (int x = 0; x < m_width; x++)
            {
                for (int y = 0; y < m_height; y++)
                {
                    SetPixel(x, y, color);
                }
            }
        }

        public void Viewport(int x, int y, int width, int height)
        {
            m_minX = x;
            m_minY = y;
            m_maxX = x + width;
            m_maxY = y + m_height;
        }

        public void DrawTriangle(Vertex v0, Vertex v1, Vertex v2)
        {
            // Compute triangle bounding box.
            int minX = (int)Math.Min(Math.Min(v0.x, v1.x), v2.x);
            int maxX = (int)Math.Max(Math.Max(v0.x, v1.x), v2.x);
            int minY = (int)Math.Min(Math.Min(v0.y, v1.y), v2.y);
            int maxY = (int)Math.Max(Math.Max(v0.y, v1.y), v2.y);

            // Clip to scissor rect.
            minX = Math.Max(minX, m_minX);
            maxX = Math.Min(maxX, m_maxX);
            minY = Math.Max(minY, m_minY);
            maxY = Math.Min(maxY, m_maxY);

            // Compute edge equations.
            EdgeEquation e0 = new(v1, v2);
            EdgeEquation e1 = new(v2, v0);
            EdgeEquation e2 = new(v0, v1);

            float area = (float)(0.5 * (e0.c + e1.c + e2.c));
            
            // Check if triangle is backfacing.
            if (area < 0)
                return;

            ParameterEquation r = new(v0.r, v1.r, v2.r, e0, e1, e2, area);
            ParameterEquation g = new(v0.g, v1.g, v2.g, e0, e1, e2, area);
            ParameterEquation b = new(v0.b, v1.b, v2.b, e0, e1, e2, area);

            // Add 0.5 to sample at pixel centers.
            for (float x = minX + 0.5f, xm = maxX + 0.5f; x <= xm; x += 1.0f)
            for (float y = minY + 0.5f, ym = maxY + 0.5f; y <= ym; y += 1.0f)
            {
                if (e0.test(x, y) && e1.test(x, y) && e2.test(x, y))
                {
                    byte rint = (byte)(r.evaluate(x, y) * 255);
                    byte gint = (byte)(g.evaluate(x, y) * 255);
                    byte bint = (byte)(b.evaluate(x, y) * 255);
                    uint color = SDL_MapRGB(m_surf->format, rint, gint, bint);
                    SetPixel((int)x, (int)y, color);
                }
            }
        }

    }


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

        SDL_Window* window = SDL_CreateWindow(TITLE, POS, POS, WIDTH, HEIGHT, FLAGS);
        SDL_Surface* surface = SDL_GetWindowSurface(window);

        Raszerizer rast = new();

        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;
                }
            }

            if (evt.type == (uint)SDL_EventType.SDL_WINDOWEVENT)
            {
                if (evt.window.eventID == (byte)SDL_WindowEventID.SDL_WINDOWEVENT_EXPOSED)
                {
                    SDL_SetWindowSize(SDL_GetWindowFromID(evt.window.windowID), evt.window.data1, evt.window.data2);
                }

                if (evt.window.eventID == (byte)SDL_WindowEventID.SDL_WINDOWEVENT_MAXIMIZED)
                {
                    SDL_SetWindowSize(SDL_GetWindowFromID(evt.window.windowID), evt.window.data1, evt.window.data2);
                    SDL_SetWindowMaximumSize(SDL_GetWindowFromID(evt.window.windowID), evt.window.data1, evt.window.data2);
                }

                if (evt.window.eventID == (byte)SDL_WindowEventID.SDL_WINDOWEVENT_MAXIMIZED)
                {
                    SDL_SetWindowSize(SDL_GetWindowFromID(evt.window.windowID), evt.window.data1, evt.window.data2);
                }
            }

            // Lock Surface
            if (SDL_LockSurface(surface) != 0)
                return -1;

            // Set Rasterizing FrameBuffer
            rast.SetFrameBuffer(surface, WIDTH, HEIGHT);
            rast.Clear();
            rast.Viewport(0, 0, WIDTH, HEIGHT);

            // Clear color
            Color backcolor = new Color { R = 1.0f, G = 1.0f / 4, B = 0f };
            rast.ClearColor(backcolor);

            // Draw Filled Traingle
            Vertex v1 = new Vertex { x = 256, y = 540, r = 1f, g = 0f, b = 0f };
            Vertex v2 = new Vertex { x = WIDTH / 2, y = 180, r = 0f, g = 1f, b = 0f };
            Vertex v3 = new Vertex { x = 768, y = 540, r = 0f, g = 0f, b = 1f };
            rast.DrawTriangle(v1, v2, v3);

            // Unlock and Update Surface
            SDL_UnlockSurface(surface);
            SDL_UpdateWindowSurface(window);
        }
        
        SDL_FreeSurface(surface);
        SDL_DestroyWindow(window);
        SDL_Quit();
        return 0;
    }
}

Update: I don't expect that float means 1.0f = WIDTH like in OpenGL or Vulkan.
float 1 : int 1 ....
Now it works fine :D
image

Thanks

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions