Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with Developing a Software Renderer Part 1 #3

Open
DeafMan1983 opened this issue Nov 26, 2023 · 0 comments
Open

Problem with Developing a Software Renderer Part 1 #3

DeafMan1983 opened this issue Nov 26, 2023 · 0 comments

Comments

@DeafMan1983
Copy link

DeafMan1983 commented Nov 26, 2023

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

@DeafMan1983 DeafMan1983 changed the title Problem Problem with Developing a Software Renderer Part 1 Nov 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant