Jump to content
  • Advertisement
Sign in to follow this  

C# SFML and fast pixel drawing in C#

Recommended Posts

Hi. It's been a while since I posted here, and my last posts are almost about this exact same subject. Just saying to demonstrate how annoying this is to me.

Here is the problem : I'm trying to make a decent raycaster in C#. The main issue is that for this to happen, I need pixel by pixel drawing. My previous raycaster used VS GDI+, and trough several tricks involving pointers and filling a bitmap byte by byte, I was able to obtain half decent results, and make an online server-client style 3d engine complete with a map builder and several really cool features. I unfortunately wasn't able to expand the project further due to poorly written code (I am an hobbyist, I study Business Administration at Uni) and the fact that my quick hack for performance was barely able to carry the bare minimum of what I needed to make a very bare bone raycaster possible. This came with very real sadness, the realization that the project I spent almost 2 years on was essentially useless, bloated and impossible to expand on. 

Enough background. Now, starting anew, my main concern is to find a way to gain fast pixel by pixel control over the screen. I'm using SFML and C#. My current testbench is pretty simple, I'm using a method I found on the internet written for C++. I Adapted it for C#. I'm filling a Color[,] array (each color is a pixel) and then I copy the RGB values inside a byte[] array before moving them inside the texture buffer. I then display the texture on the screen. I'm not sure what the bottleneck is, the application is faster than my previous one, but it's still too slow for my liking. Raycasters work by redrawing stuff ontop of other stuff, and I fear that adding more stuff would creep it to an halt. I'm posting what I have as a testbench right now, any help would be greatly appreciated. Keep in mind I am not a professional programmer by any mean, I am pretty uncomfortable with pointers and true 3d stuff, but I will use them if I must. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SFML.Audio;
using SFML.Graphics;
using SFML.System;
using SFML.Window;

namespace RayCastFF
{
    class Program
    {
        public static int TestCounter = 0;
        public static Color[,] ScreenBuffer = new Color[640, 360]; //an array containing the color of all the pixel, this is intended to be the main target of all manipulation and draw call
        public static Texture MainViewPort = new Texture(640, 360);//main screen texture

        unsafe static void Main(string[] args)
        {
            //MAINWINDOW SETUP
            RenderWindow window = new RenderWindow(new VideoMode(640, 360), "RayCaster");

            while (window.IsOpen)//MAIN GAME LOOP
            {
                //CALL FOR UPDATE
                Update();

                //DRAW
                window.Clear();
                window.DispatchEvents();

                Sprite mainviewport = new Sprite(MainViewPort);
                window.Draw(mainviewport);//draw the texture over the screen

                window.Display();



                //TAKE INPUT


            }
        }
        static void Update()
        {
            TestCounter++;
            if (TestCounter > 639) { TestCounter = 0; }
            //RESET THE BUFFER (COULD BE REMOVED LATER I GUESS)
            for (int x = 0; x < 640; x++)
            {
                for (int y = 0; y < 360; y++)
                {
                    ScreenBuffer[x, y] = Color.Black;
                }
            }

            //DO STUFF
            DrawLine(Color.Red, TestCounter, 200, 100); //(for this test, i simply draw a moving line)

            //WRITING THE BUFFER INTO THE IMAGE
            //THIS SHOULD ALWAYS BE THE LAST STEP OF THE UPDATE METHOD
            byte[] pixels = new byte[640 * 360 * 4]; //640 x 360 pixels x 4 bytes per pixel
            Color[] cpixels = new Color[640 * 360];//intermediary step to keep everything clear
            for (int x = 0; x < 640; x++)
            {
                for (int y = 0; y < 360; y++)
                {
                    cpixels[x+(640*y)] = ScreenBuffer[x, y];//make an intermediary array the correct dimention and arrange the pixels in the correct position to be drawn (separate step to keep everything clean, I find this operation incredibly confusing mainly because I had no idea how the pixels are supposed to be arrenged in the first place(still kind of dont))
                }
            }
            for (int i = 0; i < 640 * 360 * 4; i += 4)//fill the byte array
            {
                
                pixels[i + 0] = cpixels[i / 4].R;
                pixels[i + 1] = cpixels[i / 4].G;
                pixels[i + 2] = cpixels[i / 4].B;
                pixels[i + 3] = cpixels[i / 4].A;
            }

            MainViewPort.Update(pixels);//update the texture with the array
        }

        //[X , Y]
        static void DrawLine(Color color, int Wpos, int Ytop, int Ybottom)//simple draw method making a vertical line
        {

            for (int y = Ybottom; y < Ytop; y++)
            {
                ScreenBuffer[Wpos, y] = color;
            }
        }
    }
}

What I'd like to end up with is a very fast way to draw the pixels on the window by the abstraction of a single 2d array of 640x360 unit that I could easily and simply manipulate. However, while being simple, it's also somewhat slow. It's also using 30% GPU load for some reason on a 1070GTX 8GB. Again, any help would be greatly appreciated.

Thanks in advance.

Share this post


Link to post
Share on other sites
Advertisement

See those massive 'new <huge array>' operations in the middle of your Update loop?  Remove those.  Those allocations are going to be causing GC collections too frequently.  They're also going to be automatically filling the entire array with zeroes which you don't need since you immediately fill them yourself.

The part where you clear ScreenBuffer to black is eating a bunch of time.  In old programs, instead of clearing the screen and redrawing everything, we would update only the parts of the image that were changing.  Your line moves, so the old-school technique would be to 'erase' ONLY the pixels where the line was last time only, instead of setting the entire screen black first.  For mouse cursors in old apps, what I would do was save a backup copy of all of the pixels underneath where I was about to render the mouse cursor, then render the cursor, then on the next frame render the backup pixels to 'undo' rendering the mouse.

You have two full-array copy loops (ScreenBuffer -> cpixels, cpixels -> pixels), but you only need one ScreenBuffer -> pixels).  Get rid of the cpixels array as well.

In fact you should probably get rid of ScreenBuffer and only use pixels.  Just write to pixels and nothing else.  You will have to know which bytes are red/green/blue/etc but you want high performance so you've gotta remove as many "worthless" operations as possible to get it fast.

If SFML allows you to use uint[] instead of byte[], one assignment to a uint will be faster than four assignments to bytes.  This can be useful as one uint will be one pixel anyway.

C# *should* know how to optimize the constant subexpressions within inner loops such as (y*640) but you can try hand optimizing them yourself to see if it makes any difference.

Make sure you are allowing JIT to fully optimize your code.  If you're using Visual Studio this means using the Release configuration (or enabling optimization on the debug configuration) as well as {launching without the debugger attached or disabling Tools -> Options -> Debugging -> Suppress JIT optimization on module load}.

Edited by Nypyren

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Popular Now

  • Advertisement
  • Similar Content

    • By LuigiLuigi
      I've been working on my own Metroidvania via GameMaker Studio for the past few years. You play as a bat named Ralph as he goes on an adventure to obtain 7 Crystal Medallions hidden in dungeons with the help of a cult known as the Crimson Fog. Along the way, there will be quests unlocked in Cedrus Village as you progress through the game. I've managed to complete a demo of the game up to the first dungeon and boss fight.
      I have only a PC build available, and the only gamepads I managed to install were Logitech Precision and Xbox PC gamepads. I had some trouble on gamepad detection though, so they may have connection issues. The desktop controls are similar to Terarria's control scheme if it's too much trouble. I don't have any music at this point, I'll need to get someone else to compose it later on. The music I make isn't bad, but it doesn't fit the aesthetic that well.
      I'm really hoping I can get feedback regarding the general content.
      Crimson Fog.0.2.zip
    • By ethancodes
      I've got a bug with my brick breaker style game. The bricks move down one line at a time ever 1.5 seconds. What appears to be happening is occasionally the ball will be just about to hit the brick when the brick moves down a line, and now the ball is behind it. I'm not sure how to fix this. I have two ideas but I'm not sure of implementation. 1 solution would be to check where they were and where they are going to be before rendering the frame. Then if they crossed paths, then register the brick as hit. Solution 2 would be change how the bricks move. I could maybe slide them down line by line, instead of a jump down. I'm not sure of this will fix the issue or not. Any ideas?
    • By Scouting Ninja
      Once again Unity is frustrating me to the point of insanity.
      What I am looking for is a way to find a ray intersect with the edges of the mesh, using Unity's already made collision system. I want to point out that I know how to do a line intersect, what I want to know is if Unity supports this already.

      The image above shows how I sweep a ray,intersecting the mesh. The top green image shows what I want and the red shows what Unity is giving me.
      I want to know if there is some way, to find the edges in Unity without creating a custom line intersection tool.
      Most engines I know don't use rays for this but instead use a plane like this:

      I checked the Unity "Plane intersection" but it is just a ray cast. It will still need me to find the vertices on the collision mesh to cast the ray from; if I am doing that then making my own line intersection tool is better.
       
      I looked online and can find anything on this. Also I don't want to cut the mesh, so I don't need a way to know what side is what.
      Does Unity even have collisions that support edge only detection?
    • By Alexander Winter
      Jumpaï is a game about creating platformer levels and playing them online with everyone. Will you become the most popular level maker or will you be a speedrunner holding world records on everyone's levels? More into casual play? No problem! You can happily play through the giant level database or chill at people's hub. Meet new people, make new friends, learn to master the game by asking pros or ask for people's favorite tricks on level making. Download here: https://jumpai.itch.io/jumpai Discord: https://discord.gg/dwRTNCG   Trailer:      (The following screenshots are older but still a bit representative)  





      Unlike other games of its genre, Jumpaï is about playing levels with everyone in real time. You have the fun to see how other people are playing and get to realize you are not the only one failing that jump!

      The game is currently into development and still have lots to do. I am looking for people willing to help how they can. Developer? Graphist? Play tester? Sound designer? Game designer? I'm welcoming any talent. The project is so big I have a lot of work to do in all areas. Server backend, UI/UX, Game networking, Gameplay and even the website some day. As you can see from the default buttons, the game has been made with LibGDX. This project is a perfect opportunity for you to get better in various fields as well as showing off your skills.

      If you plan to take an important role into the development of the game, we will discuss how you will get paid once the game generates money. Note that I'm not working on the game full-time. I'm studying full-time and working on it is a hobby. The project has started in november 2016 and experiences heavy progress.

      So, are you interested? If so join me on my discord https://discord.gg/dwRTNCG and I'll answer all your questions.

      Additionnal screenshots:
       



       
    • By Adrian Bigaj
      Hello!

      The game: https://www.combo-clicks.com/
      DEV blog (so everyone can read the journey and some history):
      http://www.combo-clicks-dev.com/
      TL;DR
      Feedback for Combo Clicks and also IDEAS for future games will be super appreciated (Hyper Casuals done in 3-4 weeks, each game with React Native).
      I will try to post on my blog atleast on weekly basis (both for gamers and developers) 
      Thank you!




  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!