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;
}
};
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
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 ?