The struggle with raycasting in C# intensifies, need help

Started by
6 comments, last by jeskeca 9 years, 4 months ago

Fellow up with my last post, i'm currently trying to implement 2s sprites in my raycaster written in C# following Lodev tutorial. Unfortunately, i'm out of luck. I'm using native csharp class to keep it simple and the set pixel class is so slow it's unusable. I tried an alternative way drawing sprites and masking out part that should be obstructed by walls without any good results. Either it's completely unusable or way to slow. I want to be able to draw few dozens of sprites at the same time. Can anyone please help me ?

Advertisement

Are you setting one pixel at a time, or setting multiple pixels at time?

From your previous post, it looks like you're using a WinForms project. If that's still true, and you're using standard WinForms drawing, use Bitmap.LockBits to update the entire bitmap at once instead of using multiple SetPixel calls (see link).

http://msdn.microsoft.com/en-us/library/5ey6h79d(v=vs.110).aspx

NOTE: You don't have to do both a read and a write. You can raytrace to an array and then copy your array into the bitmap without copying the bitmap into your array first.

Alright so far so good. Found this page explaining how to use LockBits pretty well http://bobpowell.net/lockingbits.aspx . Got the code to work and fill my bitmap with blue pixel but i am unfamiliar with pointers and bytes. How would i write a simple function analogous to the SetPixel method ? I am looking at something like this :

public unsafe void SetPixelByte(BitmapData Data, int R, int G, int B, int A, int x, int y)
{
}
Where RGBA would be the color channel and x and y would be the location to write on. Thanks in advance and sorry for my lack of knowledge, never played around with pointers and bytes.
Rather than having a function to set one pixel at a time, here is what I would do: I'd make a 2D array of uints to store the colors until I'm ready to put them all in the bitmap, then copy them over all at once.

(Let's say you started with a default WinForms example - use the following code in the Form1.cs file. Also make sure to enable "Allow unsafe code" in the Project properties' Build section)


using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

namespace BitmapSetExample
{
    public partial class Form1 : Form
    {
        Bitmap bmp;

        public Form1()
        {
            InitializeComponent();

            bmp = new Bitmap(256, 256, PixelFormat.Format32bppArgb);
            uint[,] pixels = new uint[256,256];

            for (uint y=0; y<256; ++y)
            for (uint x=0; x<256; ++x)
                pixels[x,y] = 0xFF000000 + (x ^ y);

            pixels[0,0] = 0xFFFF0000; // Use a red pixel to indicate where the 0,0 coordinate is (currently this example has 0,0 at the upper left)

            SetBitmap32bppArgb(bmp, pixels);
        }

        public static unsafe void SetBitmap32bppArgb(Bitmap bmp, uint[,] pixels)
        {
            int width  = Math.Min(bmp.Width, pixels.GetLength(0));
            int height = Math.Min(bmp.Height, pixels.GetLength(1));

            var bitmapData = bmp.LockBits(new Rectangle(0,0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

            for (int y=0; y < height; ++y)
            {
                uint *row = (uint*)(bitmapData.Scan0.ToInt64() + y * bitmapData.Stride);
                    
                for (int x=0; x<width; ++x)
                    row[x] = pixels[x,y];
            }

            bmp.UnlockBits(bitmapData);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.DrawImageUnscaled(bmp, 0, 0);
        }
    }
}
Where pixels is a 2D array of uints, where each uint represents one pixel and has the hexadecimal layout: 0xAARRGGBB.
To combine separate red, green, blue, and alpha values into your uint, you could do something like this (this is specific to the layout that Format32bppArgb uses):


uint alpha = valueBetween0and255;
uint red   = valueBetween0and255;
uint green = valueBetween0and255;
uint blue  = valueBetween0and255;

uint pixelValue = (alpha << 24) | (red << 16) | (green << 8) | blue;

Thank you alot for your help. While your solution looks appealing, i find it way easier for me to use function analogous to the native ones. Problem solved and thanks again you made my day, project was on hold last week because of this issue.

Why write pixels with winforms?

You can do insanely fast 2d sprite drawing with OpenTK/OpenGL, and get cheap zooming, rotations, and cross-platform as well.

This topic is closed to new replies.

Advertisement