Урок 7. Курсоры мыши средствами X

      Комментарии к записи Урок 7. Курсоры мыши средствами X отключены

Главная Форумы Программирование Программирование на С++ Библиотека SDL Урок 7. Курсоры мыши средствами X

Помечено: , , ,

В этой теме 0 ответов, 1 участник, последнее обновление  Васильев Владимир Сергеевич 4 мес., 2 нед. назад.

  • Автор
    Сообщения
  • #3564
    Урок 6Содержание

    В играх часто требуется заменить стандартный курсор мыши на свой, вид которого более соответствует духу игры. Один из вариантов – рисовать поверх кадра маленькую 2д текстурку. Это очень простой и стабильный способ, однако тут не обходится без недостатков; самый очевидный – при снижении частоты кадров курсор также начнёт замирать.

    Предлагаемый метод использует стандартные средства X для отображения курсора вне зависимости от того, что рисуется в окне вашей программы (то, что называется “hardware cursor” в некоторых играх).

    Что уже есть в SDL?

    В SDL имеется API для подмены курсора, однако поддерживаются только двухцветные изображения (foreground color, background color и прозрачный). Реально же уже довольно давно поддерживаются цветные курсоры с полупрозрачностью. К сожалению, такой API появится только в SDL 1.3 (уже есть в mercurial, но пока только для windows).

    Подготовка к работе

    Сразу оговорюсь, что для дальнейших примеров я буду использовать библиотеку libXcursor. Если посмотреть в исходный код этой библиотеки, то можно заметить, что все необходимые действия можно проводить и без неё напрямую через Xlib, однако libXcursor довольно стандартна и присутствует в любом современном дистрибутиве, в котором есть X-сервер.

    Для работы с Xlib потребуются такие дескрипторы, как Display и Window. Если вы используется Xlib напрямую, то они у вас уже есть. Если окно создаётся средствами SDL, то необходимые данные можно очень легко запросить:

    SDL_SysWMinfo wminfo;
    SDL_VERSION(&wminfo.version);
    SDL_GetWMInfo(&wminfo);
    Display display = wminfo.info.x11.display;
    Window window = wminfo.info.x11.window;

    В простейшем случае – статичном курсоре – нам потребуется одно изображение, которым требуется заменить стандартный курсор. Предположим, оно загружается средствами SDL_image:

    SDL_Surface *s = IMG_Load(“sample_cursor.png”);

    Перед тем, как данные будут отданы Xlib, их необходимо привести к нужному формату:

    if(s->format->BytesPerPixel != 4) {
      SDL_Surface *tmp = SDL_CreateRGBSurface(0, s->w, s->h, 32, 0xff, 0xff00, 0xff0000, 0xff000000);
      assert(tmp);
      SDL_BlitSurface(s, NULL, tmp, NULL);
      SDL_FreeSurface(s);
      s = tmp;
    }

    Xcursor & Xlib

    Итак, по указателю “s” у нас уже имеется SDL_Surface, в которой каждый цветовой канал закодирован одним байтом. Дальнейшие действия должны быть понятны из комментариев:

    XcursorImage *ci = XcursorImageCreate(s->w, s->h);	// создаём изображение
    memcpy(ci->pixels, s->pixels, s->w * s->h * s->format->BytesPerPixel);	// копируем данные
    ci->xhot = ci->yhot = 0;	// координаты “горячей точки” (см. ниже)
    Cursor cursor = XcursorImageLoadCursor(display, ci);

    После этого SDL_Surface и XcursorImage можно удалить (SDL_FreeSurface и XcursorImageDestroy соответственно).

    Относительно “горячей точки” курсора (hot point) – это координаты точки, которой изображение курсора будет привязано к реальному положению указателя мыши (то, каким местом изображения нужно “кликнуть”, если угодно). Точка должна быть в интервале [0 .. w) и [0 .. h), причём Xlib не производит такую проверку.

    Далее нужно задать курсор для нашего окна:

    XDefineCursor(display, window, cursor);

    После чего курсор можно удалить вызовом XFreeCursor.

    Курсор задаётся только в пределах окна и будет автоматически изменён на стандартный, если указатель выйдет за его пределы (и автоматически восстановится при возвращении в окно).

    Анимированные курсоры

    libXcursor определяет структуры XcursorCursors для хранения массива курсоров, и XcursorAnimate для их циклической итерации. Использование XcursorAnimate не даёт реальных преимуществ, поэтому в примере я её не использую. Автоматического переключения курсоров нет, поэтому придётся по таймеру просто задавать новый курсор всё тем же XDefineCursor.

    Предлагается загрузить пример, основанный на шестом уроке учебника по SDL, реализующий анимированный курсор: xcursor_sample.tar. Изображения курсоров, использованные в примере – (c) Старкрафт, Близзард энтертейнмент.

Для ответа в этой теме необходимо авторизоваться.