Mouse cursor from png

good morning,
please tell me what is the most elegant way of setting my own custom
mouse cursor saved in a small RGBA PNG file.
now im doing it by disabling system cursor and blitting that png on
screen each time mouse moves (the event coords change) on that coodrs.
but i believe this is very ugly and slow. is there another, qucker way?
btw i need the cursor to be quickly interchangeble whit other one
depending on the area where it is located at the moment. I tried to
understand the SDL_CreateCursor() but no luck. has anybody a piece of
code i can learn from?
thank you
515

good morning,
please tell me what is the most elegant way of setting my own custom
mouse cursor saved in a small RGBA PNG file.
now im doing it by disabling system cursor and blitting that png on
screen each time mouse moves (the event coords change) on that coodrs.
but i believe this is very ugly and slow. is there another, qucker way?
btw i need the cursor to be quickly interchangeble whit other one
depending on the area where it is located at the moment. I tried to
understand the SDL_CreateCursor() but no luck. has anybody a piece of
code i can learn from?
thank you
515

If you want/need color cursors then you have to load and blit them yourself,
SDL cursors are black and white. If you can go with B&W cursors, here’s a
function that will convert a SDL_Surface to a SDL_Cursor (the colors will be
converted to black and white depending on their gray intensity, any pixel
that is equal to image->format->colorkey will be made transparent, hx and hy
are the local coordinates of the hot pixel of the cursor):

--------------------8<--------------------8<--------------------
SDL_Cursor *SurfaceToCursor(SDL_Surface *image, int hx, int hy) {
int w, x, y;
Uint8 *data, *mask, *d, *m, r, g, b;
Uint32 color;
SDL_Cursor *cursor;

    w = (image->w + 7) / 8;
    data = (Uint8 *)alloca(w * image->h * 2);
    if (data == NULL)
            return NULL;
    memset(data, 0, w * image->h * 2);
    mask = data + w * image->h;
    if (SDL_MUSTLOCK(image))
            SDL_LockSurface(image);
    for (y = 0; y < image->h; y++) {
            d = data + y * w;
            m = mask + y * w;
            for (x = 0; x < image->w; x++) {
                    color = getpixel(image, x, y);
                    if ((image->flags & SDL_SRCCOLORKEY) == 0 || color

!= image->format->colorkey) {
SDL_GetRGB(color, image->format, &r, &g,
&b);
color = (r + g + b) / 3;
m[x / 8] |= 128 >> (x & 7);
if (color < 128)
d[x / 8] |= 128 >> (x & 7);
}
}
}
if (SDL_MUSTLOCK(image))
SDL_UnlockSurface(image);
cursor = SDL_CreateCursor(data, mask, w, image->h, hx, hy);
return cursor;
}
--------------------8<--------------------8<--------------------

This function call a function getpixel that you must define, there is a
sample one in SDL docs.

Regards,

Andre de Leiradella

If you want/need color cursors then you have to load and blit them yourself,
SDL cursors are black and white. If you can go with B&W cursors, here’s a
function that will convert a SDL_Surface to a SDL_Cursor (the colors will be
converted to black and white depending on their gray intensity, any pixel
that is equal to image->format->colorkey will be made transparent, hx and hy
are the local coordinates of the hot pixel of the cursor):

i have tried this but I get scambled cursor - it doesn’t look like the
image from
which it’s made. it’s much narrower and I can’t recognize the picture I
wanted there.
when I keep the cursor image width at 8px, everything is ok. but other
sizes such as 16,24,32 are bad.
i tried several images and none of them worked fine.
here is the code. the files (if somebody is willing to try to compile
it) are at http://www.volny.cz/rootshell/SDL_bare.c and
http://www.volny.cz/rootshell/cursor1_noalpha.png

RedHat8.0, X11, Nvidia GFti300
thanks a lot
515

Uint32 getpixel(SDL_Surface surface, int x, int y)
{
int bpp = surface->format->BytesPerPixel;
/
Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

 switch(bpp) {
 case 1:
     return *p;

 case 2:
     return *(Uint16 *)p;

 case 3:
     if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
         return p[0] << 16 | p[1] << 8 | p[2];
     else
         return p[0] | p[1] << 8 | p[2] << 16;

 case 4:
     return *(Uint32 *)p;

 default:
     return 0;       /* shouldn't happen, but avoids warnings */
 }

}
//this is the function andre has sent me
SDL_Cursor *SurfaceToCursor(SDL_Surface *image, int hx, int hy) {
int w, x, y;
Uint8 *data, *mask, *d, *m, r, g, b;
Uint32 color;
SDL_Cursor *cursor;

     w = (image->w + 7) / 8;
     data = (Uint8 *)alloca(w * image->h * 2);
     if (data == NULL)
             return NULL;
     memset(data, 0, w * image->h * 2);
     mask = data + w * image->h;
     if (SDL_MUSTLOCK(image))
             SDL_LockSurface(image);
     for (y = 0; y < image->h; y++) {
             d = data + y * w;
             m = mask + y * w;
             for (x = 0; x < image->w; x++) {
                     color = getpixel(image, x, y);
                     if ((image->flags & SDL_SRCCOLORKEY) == 0 || color

!= image->format->colorkey) {
SDL_GetRGB(color, image->format, &r, &g,
&b);
color = (r + g + b) / 3;
m[x / 8] |= 128 >> (x & 7);
if (color < 128)
d[x / 8] |= 128 >> (x & 7);
}
}
}
if (SDL_MUSTLOCK(image))
SDL_UnlockSurface(image);
cursor = SDL_CreateCursor(data, mask, w, image->h, hx, hy);
return cursor;
}

main(int argc, char *argv[]) {

Uint32 colorkey;
SDL_Surface *screen, *cursor1_noalpha, *tmp;
SDL_Cursor *bw;

if (SDL_Init(SDL_INIT_VIDEO) != 0) {
printf(“Unable to initialize SDL: %s\n”, SDL_GetError());
return 1;
}

atexit(SDL_Quit);

screen = SDL_SetVideoMode(1024, 768, 32, SDL_HWSURFACE | SDL_DOUBLEBUF
| SDL_HWPALETTE ); //| SDL_FULLSCREEN | SDL_NOFRAME
if (screen == NULL) {
printf(“Unable to set video mode: %s\n”, SDL_GetError());
return 1;
}

cursor1_noalpha = IMG_Load("./cursor1_noalpha.png");
if (cursor1_noalpha == NULL) {
printf(“Unable to load cursor.\n”);
return 1;
}
cursor1_noalpha = SDL_DisplayFormat(cursor1_noalpha);
//i know about the mem leak

//colorkey = SDL_MapRGB(cursor1_noalpha->format, 255, 255, 255);
//SDL_SetColorKey(cursor1_noalpha, SDL_SRCCOLORKEY, colorkey);

bw=SurfaceToCursor(cursor1_noalpha, 0, 0);
SDL_SetCursor(bw);

SDL_Delay(20000);
SDL_FreeCursor(bw);

}/main end/