Руководство программиста в Photon (1037671), страница 49
Текст из файла (страница 49)
PgSetPalette( ImagePalette, 0, 0, 256, Pg_PALSET_SOFT );
PgDrawImage( ImageData, Pg_IMAGE_PALETTE_BYTE, pos, ImageSize, ImageBPL, 0 );
}
Образы в непосредственных цветах
В образах в непосредственных цветах каждый пиксель может быть любого цвета. Но в сравнении с образами на основе палитры, данные образа имеют больший объём и образ, возможно, будет дольше прорисовываться. Вы можете выбирать между несколькими типами образов в непосредственных цветах, перечисленных в описании к PhImage_t в "Справочнике библиотечных функций Photon'а"; они отличаются размером пикселя образа и точностью цвета.
Образы в градиентных цветах
В образах в градиентных цветах цвета алгоритмически сгенерированы как градиент между двумя заданными цветами.
Создание образов
Чтобы создать структуру PhImage_t:
-
Вызовите функцию PhCreateImage()
или
-
Вызовите функцию PxLoadImage(), чтобы загрузить образ с диска
или
-
Вызовите функцию ApGetImageRes(), чтобы загрузить образ из базы данных виджетов PhAB'а
или
-
Получите значение ресурса Pt_ARG_LABEL_IMAGE виджета типа PtLabel или PtButton (поддерживаемые виджетовским Pt_ARG_LABEL_TYPE являются Pt_IMAGE или Pt_TEXT_IMAGE)
или
-
Выделите для него место в памяти и заполните члены образа вручную.
Лучше вызвать функцию PhCreateImage(), чем выделять память под структуру и заполнять её вручную. Функция PhCreateImage() не только предоставляет удобный способ настройки пустого образа, но также соблюдает ограничения, накладываемые графическими драйверами на выравнивание образа, и прочие вещи.
Кэширование образов
Члены image_tag и palette_tag структуры PhImage_t используются для кэширования образов при работе с удалёнными процессами через phrelay (см. "Справочник утилит QNX 6"), например, при использовании phindows.
Эти тэги являются контрольной суммой (CRS – т.е. полученной циклическим избыточным кодом) данных образа и палитры, и могут быть вычислены с помощью функций PtCRC() или PtCRCValue(). Если эти тэги являются ненулевыми, phindows и phditto кэшируют образы. Перед отсылкой образа phrelay отсылает его тэг. Если phindows обнаруживает тот же тэг в своём кэше, то использует образ из кэша. Эта схема уменьшает объём передаваемых данных.
-
Вам нет нужды заполнять тэги, если не надо сохранять образы в кэше. Например, установите тэги в 0, если Вы отображаете мультипликацию, отображая образы, и образы никогда не повторятся.
Функции PxLoadImage и ApGetImageRes() устанавливают тэги автоматически. PhAB генерирует тэги для всех образов, сгенерированных через него (например, в побитовом редакторе).
Прозрачность в образах
Если Вы хотите, чтобы часть какого-то обрааз была прозрачной, Вы можете:
-
использовать хроматический ключ
или
-
создать маску прозрачности для образа.
Хромоключ поддерживается в большей части аппаратного обеспечения, тогда как маски прозрачности всегда обеспечиваются в программном обеспечении.
Использование хромоключа
Чтобы сделать заданный цвет прозрачным в образе, используя, если это возможно, хромоключ, вызовите функцию PhMakeTransparent(), передав ей образ и RGB-цвет, который Вы хотите сделать прозрачным.
Использование маски прозрачности
Маска прозрачности хранится в члене mask_bm структуры PhImage_t. Она представляет из себя побитовый образ, соответствующий данным образа; каждый бит этого побитового образа представляет пиксель рисуемого образа:
Если бит равен: | Сответствующий пиксель является: |
0 | Прозрачным |
1 | Каким-то цветом, заданным в данных образа |
Член mask_bpl структуры PhImage_t задаёт число байтов на линию для маски прозрачности. Вы можете создать маску прозрачности, вызвав функцию PhMakeTransBitmap().
Если Вы используете функцию PxLoadImage() для загрузки прозрачного образа, установите флаг Px_TRANSPARENT в члене flags структуры PxMethods_t. Если Вы делаете это, функция автоматически делает образ прозрачным; Вам нет необходимости создавать маску прозрачности.
Отображение образов
Существуют различные пути отображения образов:
-
Если образ хранится в структуре PhImage_t, вызовите функцию PgDrawPhImage() или PgDrawPhImagemx(). Эти функции автоматически обрабатывают хромоключ, альфа-операции, появление ореола на изображении, прозрачность и всё такое прочее.
Чтобы прорисовывать образ периодически, вызовите функцию PgDrawRepPhImage() или PgDrawRepPhImagemx().
Чтобы прорисовать прямоугольный фрагмент образа, вызовите функцию PgDrawPhImageRectmx().
-
Если образ не хранится в структуре данных PhImage_t, вызовите функцию PgDrawImage() или PgDrawImagemx().
Чтобы прорисовать образ периодически, вызовите функцию PgDrawRepImage() или PgDrawRepImagemx().
-
Если образ не хранится в структуре PhImage_t и имеет маску прозрачности, вызовите функцию PgDrawTImage() или PgDrawTImagemx().
-
Установите ресурс Pt_ARG_LABEL_IMAGE для виджета PtLabel или PtButton (которые используют функцию PgDrawPhImagemx() внутренне). Ресурс Pt_ARG_LABEL_TYPE виджета должен быть установлен в Pt_IMAGE или в Pt_TEXT_IMAGE.
Версии mx этих функций размещают адрес образа в буфере рисования пространства данных Вашего приложения. Когда буфер рисования сбрасывается, весь образ копируется в графический драйвер. Не-mx'овские версии копируют сам образ в буфер рисования:
my_image–> image = PgShmenCreate (size, NULL);
Если Вы это делаете, данные образа не копируются в графический драйвер.
Образы, созданные и возвращённые функциями ApGetImageRes() и PxLoadImage(), не размещаются в памяти совместного доступа.
Управление образами
Следующие функции позволяют Вам управлять образами:
PiCropImage() | Обрезает образ по заданной границе |
PiDuppplicateImage() | Дублирует образ |
PiFlipImage() | Зеркально отображает весь образ или его часть |
PiGetPixel() | Получает значение пикселя внутри образа |
PiGetPixelFromData() | Получает значение из диапазона пикселей |
PiGetPixelRGB() | Получает RGB-значение пикселя внутри образа |
PiSetPixel() | Изменяет значение пикселя внутри образа |
PiSetPixelInData() | Устанавливает значение пикселя в диапазоне пикселей |
Освобождение образов
Структура PhImage_t включает член flags, который упрощает освобождение памяти, используемой образом. Эти флаги указывают, какие члены Вы хотите освободить:
-
Ph_RELEASE_IMAGE
-
Ph_RELEASE_PALETTE
-
Ph_RELEASE_TRANSPARENCY_MASK
-
Ph_RELEASE_GHOST_BITMAP
Вызов функции PhReleaseImage() с каким-то образом в качестве аргумента освобождает какие-либо ресурсы, соответствующие биту, установленному во флагах образа.
|
|
|
Член flags для образов, созданных функциями ApGetImageres() и PxLoadImage(), не установлен. Если Вы хотите вызвать функцию PhReleaseImage(), чтобы освободить размещённые в памяти члены, Вы должны установить флаг самостоятельно:
my_image->flags = Ph_RELEASE_IMAGE |
Ph_RELEASE_PALETTE |
Ph_RELEASE_TRANSPARENCY_MASK |
Ph_RELEASE_GHOST_BITMAP;
Если образ хранится в виджете, размещённые в памяти члены автоматически освобождаются, когда задаётся новый образ или виджет удаляется, обеспечивая, что соответствующие биты в члене flags структуры PhImage_t устанавливаются перед тем, как образ добавляется к виджету.
Мультипликация
В этом разделе описано, как Вы можете создавать простую мультипликацию. Здесь есть два основных шага:
-
создание серии "кадров" объекта в движении
-
циклический проход по кадрам
Для мультипликации лучше использовать образы, а не побитовые образы, поскольку образы не являются прозрачными (при условии, что Вы не создали маску прозрачности). Это означает, что нет необходимости перерисовывать задний фон при замене одного образа на другой. В результате, когда Вы используете образы, отсутствует мерцание. Относительно других методов борьбы с мерцанием см. раздел "Мультипликация без мерцания" ниже.
Также возможно создание мультипликации использованием виджета PtRaw и Photon'овских примитивов рисования. См. раздел "Виджет PtRaw" выше в этой главе.
Создание серии кадров
Чтобы анимировать образ, Вам потребуется серия кадров его в движении. Например, Вы можете использовать виджет PtLabel (с ресурсом Pt_ARG_LABEL_TYPE, установленным в значение Pt_IMAGE или Pt_TEXT_IMAGE) для мультипликации. Создайте один виджет PtLabel там, где Вы хотите, чтобы мультипликация появилась, и создайте другой виджет PtLabel для каждого кадра. Вы можете разместить эти кадры в базе данных виджетов или в файле.
Использование базы данных виджетов
Как описано в разделе "Базы данных виджетов" главы "Доступ к модулям PhAB из программного кода", Вы можете использовать модуль картинки в качестве базы данных виджетов. Чтобы использовать его для мультипликации, выполните в PhAB следующее:
-
Создайте модуль картинки для его использования в качестве базы данных
-
Создайте внутреннюю связь к модулю картинки
-
Создайте кадры объекта в движении. Используйте тот же тип виджета, который Вы применяете, когда появляется анимация. Присвойте каждому кадру уникальное имя экземпляра.
В Вашей функции инициализации откройте базу данных, вызвав функцию ApOpenDBase(). Затем загрузите образы функций ApGetImageRes(). Например:
/* global данные */
PhImage_t *images[4];
ApDBase_t *database;
int cur_image = -1,
num_images = 4;
int app_init( int argc, char *argv[]) {
int i;
char image_name[15];
/* предотвращает предупреждения (варнинги) об отсутствии ссылок */
argc = argc, argv = argv;
database = ApOpenDBase (ABM_image_db);
for (i = 0; i < num_images; i++) {
sprintf (image_name, "image%d", i);
images[i] = ApGetImageRes (database, image_name);
}
return (PT_CONTINUE);
}
Функция ApGetImageRes() возвращает указатель в базе данных виджетов. Не закрывайте базу данных до тех пор, пока Вы используете образы из неё.
Использование файла
Вы также можете загрузить кадры из файла – из структуры PhImage_t – функцией PxLoadImage(). Эта функция поддерживает множество форматов, включая gif, pcx, jpg, bmp, и png. Полный список см. в /usr/photon/dll/pi_io_*.
Циклическая прокрутка кадров
Вне зависимости от того, как Вы получили кадры, мультипликация выполняется одинаково:
-
Создайте в Вашем приложении виджет PtTimer. PhAB отображает его как чёрный прямоугольник, он не появится, когда Вы запустите своё приложение.
-
Задайте для таймера начальный (Pt_ARG_TIMER_INITIAL) интервал и интервалы повтора (Pt_ARG_TIMER_REPEAT).
-
Создайте для таймера ответную реакцию активизации (Pt_CB_TIMER_ACTIVATE). В ответной реакции определите следующий образ, который будет отображён, и скопируйте его в предназначенный виджет.
Например, ответная реакция таймера может быть такой:
/* Отображение следующего образа для нашего примера мультипликации. */