Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [Release] Simple Pixel Renderer  (Read 3473 times)

0 Members and 1 Guest are viewing this topic.

Cyragia

  • Newbie
  • *
  • Posts: 17
    • View Profile
[Release] Simple Pixel Renderer
« on: September 30, 2012, 01:28:56 pm »
Hello,
Recently i was making something using sfml, and i had to draw lots ( 1000 + ) of little shapes ( 1 - 5 pixels).
When i tried to do this with sprites or lines of length 1, it was super laggy.
After a bit of searching on the forums, I found out that the best way to do something like this, is to render them to a pixelarray, and then loading the complete array to the video memory at once. It was indeed much faster.
So I wrote a simple class which could render induvidual pixels to a buffer. A bit later i added lines, then circles and rectangles.
I noticed quite a lot of people need something like this, so I'm releasing my class to the public :)
I'm not claiming this is the best/fastest way of doing this, neither is this code very optimized, but nonetheless i think a lot of people will find this useful.

If you have suggestions, or found a bug, feel free to tell me !


NOTE: the buffer is meant to cover the whole screen !
If you want to draw anything else, first draw this, then draw your sprites or whatever after it.

usage example :

//initialization
sf::RenderWindow Window(sf::VideoMode(WIDTH, HEIGHT, 32), "Example");
CRenderer Renderer( WIDTH, HEIGHT );

//-------------------------------------

//inside renderer loop

//clear window
Window.Clear();
//clear buffer (optional: choose a color )
Renderer.Clear();

//draw everything you want
Renderer.DrawCircle( 100, 150, 10, sf::Color( 255 ), 0, 0 ), true );
Renderer.DrawPixel( 100, 150, sf::Color( 255 ), 0, 0 ), true );

//draw the buffer to the screen
Renderer.DrawToWindow( Window );

//draw everything else: sprites, images, text, ...

//display window
Window.Display();
       
 

full class:
class CRenderer {

public:

        sf::Uint8* pixelArray;
        int width;
        int height;
        sf::Image ScreenImage;

        CRenderer( int _width, int _height)
        {
                width = _width;
                height = _height;
                pixelArray = new sf::Uint8[ width * height * 4 ];

                for( int i = 0 ; i < width * height * 4 ; i++ )
                {
                        pixelArray[i] = 0x00;
                }

        }

        ~CRenderer()
        {
                delete[] pixelArray;
        }

        void DrawToWindow( sf::RenderWindow& Screen, bool smooth = false ){
                ScreenImage.LoadFromPixels( width , height, pixelArray );
                ScreenImage.SetSmooth( smooth );
                sf::Sprite ScreenSprite( ScreenImage );
                Screen.Draw( ScreenSprite );
        }
        void DrawPixel( int x, int y, sf::Color color ){
                if( ( x >= 0 ) && ( x < width ) && ( y >= 0 ) && ( y < height ) )
                {
                        pixelArray[ (y * width + x)*4 ] = color.r;
                        pixelArray[ (y * width + x)*4 + 1 ] = color.g;
                        pixelArray[ (y * width + x)*4 + 2 ] = color.b;
                        pixelArray[ (y * width + x)*4 + 3 ] = color.a;
                }
        }
        void DrawLine( int x0, int y0, int x1, int y1, sf::Color color ){

                int dx = abs( x1 - x0 );
                int dy = abs( y1 - y0 );
                int sx = 0;
                int sy = 0;

                if( x0 < x1 ) { sx = 1; }else{ sx = -1; }
                if( y0 < y1 ) { sy = 1; }else{ sy = -1; }

                int error = dx - dy;

                while(1)
                {
                        DrawPixel(x0,y0, color);
                        if( x0 == x1 && y0 == y1){ break; }
                        int e2 = 2*error;
                        if( e2 > -dy ){ error = error - dy; x0 = x0 + sx; }
                        if( e2 < dx){ error = error + dx; y0 = y0 + sy; }
                }
        }
        void DrawCircle( int x0, int y0, int r, sf::Color color, bool filled = true )
        {
                int f = 1 - r;
                int ddF_x = 1;
                int ddF_y = -2 * r;
                int x = 0;
                int y = r;

                DrawPixel(x0, y0 + r, color);
                DrawPixel(x0, y0 - r, color);
                if( filled )
                {
                        DrawLine(x0 - r, y0, x0 + r, y0, color);
                }
                else
                {
                        DrawPixel(x0 + r, y0, color);
                        DrawPixel(x0 - r, y0, color);
                }

                while(x < y)
                {
                        if(f >= 0)
                        {
                                y--;
                                ddF_y += 2;
                                f += ddF_y;
                        }
                        x++;
                        ddF_x += 2;
                        f += ddF_x;    
                        if( filled )
                        {
                                DrawLine(x0 + x, y0 + y, x0 - x, y0 + y, color);
                                DrawLine(x0 + y, y0 + x, x0 - y, y0 + x, color);
                                DrawLine(x0 + x, y0 - y, x0 - x, y0 - y, color);
                                DrawLine(x0 + y, y0 - x, x0 - y, y0 - x, color);
                        }
                        else
                        {
                                DrawPixel(x0 + x, y0 + y, color);
                                DrawPixel(x0 - x, y0 + y, color);
                                DrawPixel(x0 + x, y0 - y, color);
                                DrawPixel(x0 - x, y0 - y, color);
                                DrawPixel(x0 + y, y0 + x, color);
                                DrawPixel(x0 - y, y0 + x, color);
                                DrawPixel(x0 + y, y0 - x, color);
                                DrawPixel(x0 - y, y0 - x, color);
                        }
                }
        }

        void DrawRectangle( int x1, int y1, int x2, int y2, sf::Color color, bool filled = true ){
                if( x1 > x2 ){
                        int temp = x1;
                        x1 = x2;
                        x2 = temp;
                }
                if( y1 > y2 ){
                        int temp = y1;
                        y1 = y2;
                        y2 = temp;
                }
                for( int x = x1 ; x < x2 ; x++ )
                {
                        for( int y = y1 ; y < y2 ; y++ )
                        {
                                DrawPixel( x, y, color );
                        }
                }
        }
        void Clear( sf::Color color ){
                for( int i = 0 ; i < width * height ; i++ )
                {
                        pixelArray[ i * 4 ] = color.r;
                        pixelArray[ i * 4 + 1 ] = color.g;
                        pixelArray[ i * 4 + 2 ] = color.b;
                        pixelArray[ i * 4 + 3 ] = color.a;
                }
        }
};
 
« Last Edit: September 30, 2012, 01:40:03 pm by Cyragia »

Haikarainen

  • Guest
Re: [Release] Simple Pixel Renderer
« Reply #1 on: September 30, 2012, 04:13:59 pm »
How is this different from using a RenderTexture? I'd imagine a rendertexture would be a lot faster for this as well. I'm not trying to kill your whole idea here, I simply dont know how this is better, I'd love an explanation :)

EDIT: Also this isn't really hardware-accelerated is it? Except for when you render the RendererImage to the screen. How fast is this really? What kind of resolutions can it handle on mediocre hardware? 128x128? 1024x1024? 4096x4096?
« Last Edit: September 30, 2012, 04:17:10 pm by Haikarainen »

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: [Release] Simple Pixel Renderer
« Reply #2 on: September 30, 2012, 04:47:18 pm »
This is for 1.6 so don't hold your breath. Chances are vertex array and 2.0 with some algorithm to bind lines and circles down onto a grid are way faster.
Back to C++ gamedev with SFML in May 2023

Cyragia

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: [Release] Simple Pixel Renderer
« Reply #3 on: September 30, 2012, 05:19:00 pm »
@Haikarainen :
The main difference with a rendertexture is that this is made for 1.6 which doesn't have rendertexture, and the my class supports true circles, and sfml only supports polygons (which might look ok, if you have enough points).
It indeed isn't hardware accelerated, but it is much faster than any other way in sfml 1.6 :)
And for performance, i get ~25 fps wheni draw every pixel individually (if you were to draw overlapping shapes, it would be slower).
I get ~85 fps when i draw 100 random circles with a diameter between 1 and 50.
I'm using an Intel i3-2310M processor @ 2.1 GHz and an Intel hd3000 integrated gfx card, but it shouldn't matter as it's not hardware accelerated.

@FRex :
I don't really understand what you mean by "some algorithm to bind lines and circles down onto a grid" could you explain yourself a bit clearer ?