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

Author Topic: Drawing individual pixels  (Read 6170 times)

0 Members and 1 Guest are viewing this topic.

Cyragia

  • Newbie
  • *
  • Posts: 17
    • View Profile
Drawing individual pixels
« on: August 31, 2012, 01:08:38 pm »
Hello,
I'm trying to draw individual pixels to the screen.
First i tried to draw them using line of 1 pixel, it worked but was incredibly slow.
To draw every pixel on a 640x480 screen it takes about 2 seconds...
Then i searched on the forum, and i found out that writing to  a buffer, then loading it with  sf::Image::LoadFromPixels should be much faster.
So i tried that, it worked and it was indeed much faster, i got about 80-90 fps in release mode.
But the pixels i draw look antialiased or something, the pixel i wanted to draw is not fully drawn and some pixels around it are slightly drawn too...
How can i fix this ? i just want one clean pixel to be drawn.
Also, is the way i draw the fps the most efficient way ? if not, what is the most efficient way ?

My code :
#if _DEBUG
        #pragma comment(lib, "sfml-system-s-d.lib")
        #pragma comment(lib, "sfml-window-s-d.lib")
        #pragma comment(lib, "sfml-graphics-s-d.lib")
#else
        #pragma comment(lib, "sfml-system-s.lib")
        #pragma comment(lib, "sfml-graphics-s.lib")
        #pragma comment(lib, "sfml-window-s.lib")
#endif

#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
//#include <Windows.h>
using namespace std;
#include "CRenderer.h"
#include "CParticle.h"
#include "CPhysics.h"

#define WIDTH 640
#define HEIGHT 480

char textBuffer[1024];


int main()
{

        //INITIALIZATION
        sf::RenderWindow Window(sf::VideoMode(WIDTH, HEIGHT, 32), "SFML-Test");
        Window.Create(sf::VideoMode(WIDTH, HEIGHT, 32), "SFML-Test");
        CRenderer Renderer( WIDTH, HEIGHT );
        sf::Image ScreenImage;


        //MAIN LOOP
        while (Window.IsOpened())
        {
               
                // Loop through all the events and handle them
                sf::Event Event;
                while (Window.GetEvent(Event))
                {
                        // Exit when window is close or escape is pressed
                        if ( (Event.Type == sf::Event::Closed) || ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape)) )
                                Window.Close();

                        if (Event.Key.Code == sf::Key::F1)
                        {
                                sf::Image Screenshot = Window.Capture();
                                Screenshot.SaveToFile("screenshot.jpg");
                        }
                }
                // Clear the window
                Window.Clear();

                //draw some random stuff
                /*for( int x = 0 ; x < WIDTH ; x++ )
                {
                        for( int y = 0 ; y < HEIGHT ; y++ )
                        {
                                Renderer.DrawPixel( x, y, sf::Color( x % 255, y % 255, x % 255, 255 ) );
                        }
                }*/

                Renderer.DrawPixel( 50, 50, sf::Color( 255, 0, 0 ) );
                ScreenImage.LoadFromPixels( WIDTH , HEIGHT, (sf::Uint8*) Renderer._pixelArray );
                sf::Sprite ScreenSprite( ScreenImage );
                Window.Draw( ScreenSprite );

                // Calculate and draw FPS
                sf::String Text_FPS;
                Text_FPS.SetFont(sf::Font::GetDefaultFont());
                sprintf_s( textBuffer, "FPS: %i", (int)(1.0f / Window.GetFrameTime()) );
                Text_FPS.SetText(textBuffer);
                Text_FPS.SetColor(sf::Color(255, 0, 0));
                Text_FPS.Move(5, 5);
                Window.Draw(Text_FPS);


                // Display window
                Window.Display();

        }

        return EXIT_SUCCESS;
}

class CRenderer {

public:

        __int32* _pixelArray;
        int _width;
        int _height;

        CRenderer( int width, int height)
        {
                _pixelArray = new __int32[width * height];

                for( int i = 0 ; i < width * height ; i++ )
                {
                        _pixelArray[i] = 0x00000000;
                }

                _width = width;
                _height = height;
        }

        ~CRenderer()
        {
                delete[] _pixelArray;
        }

        bool DrawPixel( int x, int y, sf::Color color ){
                __int32 colorTotal = ( ( ( ( color.r ) & 0xff ) << 24 ) | ( ( ( color.g ) & 0xff ) << 16 ) | ( ( ( color.b ) & 0xff ) << 8 ) | ( ( color.a ) & 0xff ) );
                if( ( x >= 0 ) && ( x < _width ) && ( y >= 0 ) && ( y < _height ) )
                {
                        _pixelArray[ y * _width + x ] = colorTotal;
                        return true;
                }
                return false;
        }

};

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Drawing individual pixels
« Reply #1 on: August 31, 2012, 01:13:08 pm »
ScreenImage.SetSmooth(false);

And yes, this is the most efficient way of doing it. But you should remove this expensive test in Renderer.DrawPixel, it just slows down the whole thing. If you want to catch programer's mistakes then put an assert instead, which will be active only in debug mode and leave maximum performances in release mode.

And you should have an array of sf::Uint8, because:
- your cast from int32* to sf::Uint8* is not safe, it will produce wrong colors on big endian architectures
- you won't waste time constructing the 32 bits integers from sf::Color
« Last Edit: August 31, 2012, 01:15:25 pm by Laurent »
Laurent Gomila - SFML developer

Cyragia

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Drawing individual pixels
« Reply #2 on: August 31, 2012, 01:17:42 pm »
Thanks, that did the trick :D
Also, i tried removing the test in Renderer.DrawPixel, but the framerate stays the same...

Cyragia

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Drawing individual pixels
« Reply #3 on: August 31, 2012, 01:31:10 pm »
ok, i tried replacing this:
__int32* _pixelArray;
...
_pixelArray = new __int32[width * height * 4];
...
__int32 colorTotal = ( ( ( ( color.r ) & 0xff ) << 24 ) | ( ( ( color.g ) & 0xff ) << 16 ) | ( ( ( color.b ) & 0xff ) << 8 ) | ( ( color.a ) & 0xff ) );
_pixelArray[ y * _width + x ] = colorTotal;
 
with this:
sf::Uint8* _pixelArray;
...
_pixelArray = new sf::Uint8[width * height * 4];
...
_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;
 
but it gives different results, what did i do wrong ?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Drawing individual pixels
« Reply #4 on: August 31, 2012, 01:45:44 pm »
It looks good.

What results does it produce? Color components are swapped? Pixels are offseted? Something else?
Laurent Gomila - SFML developer

Cyragia

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Drawing individual pixels
« Reply #5 on: August 31, 2012, 01:51:55 pm »
nvm, i made a stupid mistake somewhere else.
is there a way to disable linker errors btw ? (in msvs2008)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Drawing individual pixels
« Reply #6 on: August 31, 2012, 01:53:22 pm »
Disable linker errors? You certainly mean "solve" them, right? :P
Or do you mean linker warnings? And which one?
Laurent Gomila - SFML developer

Cyragia

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Drawing individual pixels
« Reply #7 on: August 31, 2012, 01:56:37 pm »
sorry, i mean warnings, LNK4099 to be specific.
the one about the missing pdb files.

and when i compile my code in debug mode i'm getting a big grey area on my screen. (see attachment)
When i compile in release mode it's fine.


[attachment deleted by admin]

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Drawing individual pixels
« Reply #8 on: August 31, 2012, 02:00:25 pm »
Quote
sorry, i mean warnings, LNK4099 to be specific.
the one about the missing pdb files.
In the project settings, under Linker options you can disable specific warnings.
Or you can recompiler SFML in order to get these PDB files.

Quote
and when i compile my code in debug mode i'm getting a big grey area on my screen.
Do you link to debug libraries in debug mode?
Laurent Gomila - SFML developer

Cyragia

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Drawing individual pixels
« Reply #9 on: August 31, 2012, 02:04:29 pm »
i can't seem to find where to disable linker warnings...
and yes, i link with the static debug libraries in debug mode.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Drawing individual pixels
« Reply #10 on: August 31, 2012, 03:15:06 pm »
Quote
i can't seem to find where to disable linker warnings..
Sorry, I was wrong.
However searching with Google gives a lot of relevant answers ;)
Laurent Gomila - SFML developer

Cyragia

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Drawing individual pixels
« Reply #11 on: August 31, 2012, 03:47:33 pm »
i compiled sfml myself, but i don't know which pdb files i have to copy and where to copy them.
i have the "vc90.pdb" files, "Debug DLLsfml-xxx-d.pdb" and "Release DLLsfml-xxx.pdb".

i've solved the grey area problem btw. stupid mistake on my side...
« Last Edit: August 31, 2012, 03:56:17 pm by Cyragia »

 

anything