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 Volny.cz - Stránka nenalezena and
Volny.cz - Stránka nenalezena
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/