The code bellow just polling mouse events and draw lines between the previous and last mouse coordinates in case of left mouse button pressed down, nothing special and its using only fast integer operations.
The code is fast enough on PC but compiling and running it on a pi3 the rendering speed gets extremely slow when i enable the experimental openGL driver. Tried to call SDL_CreateRenderer()
with flag SDL_RENDERER_ACCELERATED
but it did not help a lot.
The rendering speed is much faster when i disable the openGL driver and calling SDL_CreateRenderer()
with flag SDL_RENDERER_SOFTWARE
(yet not fast enough). I think i can get much better results with somehow utilizing hw accelerated rendering the right way, but how? What can be the problem?
#include <SDL.h>
//Screen dimension constants
const int SCREEN_WIDTH = 1024; //640;
const int SCREEN_HEIGHT = 768; //480;
Uint32* pixels;
struct _mCoords
{
int xprev;
int yprev;
int x;
int y;
};
_mCoords mCoords;
SDL_Window * window;
SDL_Renderer * renderer;
SDL_Texture * texture;
void clean();
void drawpixel( int mX, int mY );
void bhm_line(int x1,int y1,int x2,int y2);
int isClose(int x1, int y1, int x2, int y2);
int main( int argc, char* args[] )
{
bool quit = false;
bool leftMouseButtonDown = false;
pixels = new Uint32[SCREEN_WIDTH * SCREEN_HEIGHT];
memset(pixels, 255, SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(Uint32)); //background to white
SDL_Event event;
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("Pixel drawing", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED );
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, SCREEN_WIDTH, SCREEN_HEIGHT);
while (!quit)
{
while (SDL_PollEvent(&event) != 0 )
{
switch (event.type)
{
case SDL_QUIT:
quit = true;
break;
case SDL_MOUSEBUTTONUP:
if (event.button.button == SDL_BUTTON_LEFT)
leftMouseButtonDown = false;
break;
case SDL_MOUSEBUTTONDOWN:
if (event.button.button == SDL_BUTTON_LEFT)
leftMouseButtonDown = true;
mCoords.xprev = event.motion.x;
mCoords.yprev = event.motion.y;
case SDL_MOUSEMOTION:
if (leftMouseButtonDown)
{
mCoords.x = event.motion.x;
mCoords.y = event.motion.y;
if (isClose(mCoords.x, mCoords.y, mCoords.xprev, mCoords.yprev) == 0)
bhm_line(mCoords.xprev, mCoords.yprev, mCoords.x, mCoords.y);
else
drawpixel( mCoords.x, mCoords.y );
mCoords.xprev = mCoords.x;
mCoords.yprev = mCoords.y;
//SDL_RenderClear(renderer);
SDL_UpdateTexture(texture, NULL, pixels, SCREEN_WIDTH * sizeof(Uint32)); //pixel array to texture
SDL_RenderCopy(renderer, texture, NULL, NULL); //to backbuffer
SDL_RenderPresent(renderer); //to frontbuffer
}
break;
}
}
}
clean();
SDL_Quit();
return 0;
}
void clean()
{
delete[] pixels;
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
}
void bhm_line(int x1,int y1,int x2,int y2)
//Breshenian's line algorithm
{
int x,y,dx,dy,dx1,dy1,px,py,xe,ye,i;
dx=x2-x1;
dy=y2-y1;
dx1=fabs(dx);
dy1=fabs(dy);
px=2*dy1-dx1;
py=2*dx1-dy1;
if(dy1<=dx1)
{
if(dx>=0)
{
x=x1;
y=y1;
xe=x2;
}
else
{
x=x2;
y=y2;
xe=x1;
}
drawpixel(x,y);
for(i=0;x<xe;i++)
{
x=x+1;
if(px<0)
{
px=px+2*dy1;
}
else
{
if((dx<0 && dy<0) || (dx>0 && dy>0))
{
y=y+1;
}
else
{
y=y-1;
}
px=px+2*(dy1-dx1);
}
drawpixel(x,y);
}
}
else
{
if(dy>=0)
{
x=x1;
y=y1;
ye=y2;
}
else
{
x=x2;
y=y2;
ye=y1;
}
drawpixel(x,y);
for(i=0;y<ye;i++)
{
y=y+1;
if(py<=0)
{
py=py+2*dx1;
}
else
{
if((dx<0 && dy<0) || (dx>0 && dy>0))
{
x=x+1;
}
else
{
x=x-1;
}
py=py+2*(dx1-dy1);
}
drawpixel(x,y);
}
}
}
int isClose(int x1, int y1, int x2, int y2)
{
if ((abs(x2-x1) > 1) || (abs(y2-y1) > 1))
return 0;
else
return 1;
}
void drawpixel(int mX, int mY)
{
int pixelidx = mY * SCREEN_WIDTH + mX;
pixels[pixelidx] = pixels[pixelidx] & 0x0;
}