From 1df89e00e4b70550556eb084c90ae2f8ef9eb156 Mon Sep 17 00:00:00 2001 From: Bobby Lucero Date: Sun, 1 Jun 2025 02:00:38 -0400 Subject: [PATCH] #2 Draw an image from a byte array --- MathTypes.cs | 32 ++++++++++++++++++++++ README.md | 2 +- RenderDevice.cs | 57 +++++++++++++++++++++++++++++++++++++++ SoftwareRasterizer.cs | 47 +++++++++++++++++++++++++++----- SoftwareRasterizer.csproj | 1 + 5 files changed, 131 insertions(+), 8 deletions(-) create mode 100644 MathTypes.cs create mode 100644 RenderDevice.cs diff --git a/MathTypes.cs b/MathTypes.cs new file mode 100644 index 0000000..da06fe2 --- /dev/null +++ b/MathTypes.cs @@ -0,0 +1,32 @@ +public struct float3(float x, float y, float z) +{ + public float x = x; + public float y = y; + public float z = z; + + public float r + { + get => x; set => x = value; + } + public float g + { + get => y; set => y = value; + } + public float b + { + get => z; set => z = value; + } + + public static float3 operator -(float3 a, float3 b) => new float3(a.x - b.x, a.y - b.y, a.z - b.y); + + public static float3 cross(float3 a, float3 b) => new float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); + + public static float dot(float3 a, float3 b) => a.x * b.x + a.y * b.y + a.z * b.z; + +} + +public struct float2(float x, float y) +{ + public float x = x; + public float y = y; +} \ No newline at end of file diff --git a/README.md b/README.md index 7407e88..bfe6096 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Writing a simple 3D software renderer from scratch to understand the math behind ## 🎯 Milestones - [X] Setup Raylib C# project -- [ ] Draw an image from a byte array +- [X] Draw an image from a byte array - [ ] Draw a triangle - [ ] Render Lots of triangles - [ ] OBJ Loader diff --git a/RenderDevice.cs b/RenderDevice.cs new file mode 100644 index 0000000..ed33f2a --- /dev/null +++ b/RenderDevice.cs @@ -0,0 +1,57 @@ +using System.Numerics; +using System.Runtime.InteropServices; +using Raylib_cs; + + +public class RenderDevice +{ + public int width { get; private set; } + public int height { get; private set; } + + private int screenWidth, screenHeight; + + private Texture2D renderTarget; + private IntPtr pixelPtr; + private byte[] pixelData; + public RenderDevice(int width, int height, int screenWidth, int screenHeight) + { + this.width = width; + this.height = height; + this.screenWidth = screenWidth; + this.screenHeight = screenHeight; + + Image image = Raylib.GenImageColor(width, height, Color.Black); + renderTarget = Raylib.LoadTextureFromImage(image); + Raylib.UnloadImage(image); + + pixelData = new byte[width * height * 4]; + pixelPtr = Marshal.AllocHGlobal(pixelData.Length); + + } + + public void render() + { + Marshal.Copy(pixelData, 0, pixelPtr, pixelData.Length); + unsafe + { + Raylib.UpdateTexture(renderTarget, (void*)pixelPtr); + } + + Raylib.DrawTexturePro(renderTarget, new Rectangle(0,0, width, height), new Rectangle(0, 0, screenWidth, screenHeight), Vector2.Zero, 0f, Color.White); + } + + public void SetPixel(int x, int y, float3 color) + { + int idx = (y * width + x) * 4; + pixelData[idx] = (byte)color.r; + pixelData[idx + 1] = (byte)color.g; + pixelData[idx + 2] = (byte)color.b; + pixelData[idx + 3] = 0xFF; + } + + public void cleanup() + { + Raylib.UnloadTexture(renderTarget); + Marshal.FreeHGlobal(pixelPtr); // always free after upload + } +} \ No newline at end of file diff --git a/SoftwareRasterizer.cs b/SoftwareRasterizer.cs index 3052045..e46a0c2 100644 --- a/SoftwareRasterizer.cs +++ b/SoftwareRasterizer.cs @@ -2,22 +2,55 @@ class SoftwareRasterizer { + + const int screenWidth = 1280 * 2; + const int screenHeight = 800 * 2; + + const int scale = 8; + + private RenderDevice renderer; + static void Main() { - const int screenWidth = 800; - const int screenHeight = 600; + SoftwareRasterizer sr = new SoftwareRasterizer(); + sr.start(); + } + + public void start() + { Raylib.InitWindow(screenWidth, screenHeight, "Software Rasterizer"); - Raylib.SetTargetFPS(60); + Raylib.SetTargetFPS(0); + renderer = new RenderDevice(screenWidth / scale, screenHeight / scale, screenWidth, screenHeight); + + int frameCounter = 0; + + Random rand = new Random(); + while (!Raylib.WindowShouldClose()) { + for (int i = 0; i < renderer.height; i++) + { + for (int j = 0; j < renderer.width; j++) + { + renderer.SetPixel(j, i, new float3((j / (float)(renderer.width)) * 255, (i / (float)(renderer.height)) * 255, rand.Next(1,256))); + } + } + // Render Raylib.BeginDrawing(); - Raylib.ClearBackground(Color.LightGray); - Raylib.DrawText("Hello, Raylib-cs!", 190, 200, 50, Color.DarkGray); + Raylib.ClearBackground(Color.Black); + // + renderer.render(); + // + Raylib.DrawText($"FPS: {Raylib.GetFPS()}", 10, 10, 20, Color.White); Raylib.EndDrawing(); + frameCounter += 2; } - + + // Cleanup + renderer.cleanup(); Raylib.CloseWindow(); } -} \ No newline at end of file +} + diff --git a/SoftwareRasterizer.csproj b/SoftwareRasterizer.csproj index c99d292..5842c8b 100644 --- a/SoftwareRasterizer.csproj +++ b/SoftwareRasterizer.csproj @@ -5,6 +5,7 @@ net8.0 enable enable + true