Руководство программиста в Photon (953920), страница 49
Текст из файла (страница 49)
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). В ответной реакции определите следующий образ, который будет отображён, и скопируйте его в предназначенный виджет.
Например, ответная реакция таймера может быть такой:
/* Отображение следующего образа для нашего примера мультипликации. */
/* Стандартные хеадеры */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* Инструментальные хеадеры */
#include <Ph.h>
#include <Pt.h>
#include <Ap.h>
/* Локальные хеадеры */
#include "globals.h"
#include "abimport.h"
#include "proto.h"
int display_image( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) {
/* предотвращает предупреждения (варнинги) об отсутствии ссылок */
widget = widget, apinfo = apinfo, cbinfo = cbinfo;
cur_image++;
if (cur_image >= num_images) cur_image=0;
PtSetResource (ABW_base_image, Pt_ARG_LABEL_IMAGE, images[cur_image], 0 );
PtFlush ();
return( Pt_CONTINUE );
}
ABW_base_image – это имя виджета PtLabel, в котором появляется мультипликация.
Исключение мерцания в мультипликации
Имеется два способа избежать мерцания в мультипликации:
-
Создать PtOSContainer (некий контейнер внеэкранного контекста) и сделать его родителем всех виджетов в области, где будет выполняться мультипликация
или
-
Использовать функции контекстной памяти PmMem...(), чтобы собирать образ в памяти и отображать его по завершении сборки.
PtOSContainer
Когда Вы выполняете мультипликацию в виджете, родителем которого является контейнер внеэкранного контекста, PtOSContainer формирует изображение потока прорисовки во внеэкранной видеопамяти, пользуясь преимуществами всех поддерживаемых графическим драйвером возможностей аппаратного ускорения. Графическое аппаратное обеспечение затем может блитировать (т.е. копировать большой массив памяти) образ непосредственно на экран, в результате чего получаются немерцающие виджеты и/или мультипликация с отсутствием эффекта мерцания.
Виджет типа PtRaw (так же, как любой другой виджет) может быть порождённым от PtOSContainer. Это означает, что Вы можете получить немерцающую мультипликацию даже тогда, когда используются примитивы рисования Photon'а.
Функции контекста памяти
Вы можете вызвать эти функции, чтобы использовать контекст памяти для уменьшения мерцания:
PmMemCreateMC() | Создать контекст памяти |
PmMemFlush() | Сбросить контекст памяти в его побитовый образ |
PmMemReleaseMC() | Освободить контекст памяти |
PmMemSetChunkSize() | Установить величину приращения при увеличении буфера прорисовки, принадлежащего контексту памяти |
PmMemSetMaxBufSize() | Установить максимальный размер буфера прорисовки, принадлежащего контексту памяти |
PmMemSetType() | Установить тип контекста памяти |
PmMemStart() | Сделать активным контекст памяти |
PmMemStop() | Деактивировать контекст памяти |
Начните с создания контекста памяти:
PmMemoryContext_t * PmMemCreateMC(
PhImage_t *image,
PhDim_t *dim,
PhPoint_t *translation );
В структуре image должны быть заданы по меньшей мере члены type и size. Буфер данных образа является необязательным, но если Вы хотите иметь его в памяти совместного доступа, Вы должны его обеспечить. Член type должен иметь значение Pg_IMAGE_DIRECT_888 или Pg_IMAGE_PALETTE_BYTE.
Сразу после того, как Вы создали контекст памяти:
-
Вызовите функцию PmMemStart(), чтобы установить контекст текущей прорисовки в контекст памяти
-
Вызовите функцию PmMemStop(), когда закончите Вашу прорисовку, чтобы вернуться в принимаемый по умолчанию контекст прорисовки
-
Вызовите функцию PmMemFlush(), чтобы получить результирующий образ.
Козда Вам больше не нужен контекст памяти, вызовите функцию PmMemReleaseMC().
Режим рисования с прямым доступом
В обычном (не "напрямую") режиме, приложение отсылает запросы на прорисовку в менеджер Photon'а. Графический драйвер блокируется менеджером Photon'а.
Связь в обычном (не прямого доступа) режиме
Когда приложение входит в режим прямого доступа, оно требует, чтобы графический драйвер получал поток данных прорисовки и служебные сообщения напрямую от приложения, а не от менеджера Photon'а. Драйвер блокируется на получении данных от приложения, которое теперь ответственно за то, чтобы указывать драйверу, что делать.
Связь в режиме прямого доступа
Когда приложение входит в режим рисования с прямым доступом, приложение получает полный контроль над дисплеем, так что никакие другие приложения графическим драйвером не обслуживаются. Зона графического драйвера также больше не чувствительна к событиям рисования (так что менеджер Photon'а аннулирует все запросы других приложений к службам построения изображения этого драйвера). Другим достоинством этого режима является то, что графические услуги больше не пересылаются через пространтство событий Photon'а, что улучшает производительность. Недостатком этого режима является то, что приложения, ожидающее захвата событий рисования, не могут записать визуальное представление приложения.
В целях удобства работы создан новый тип контекста PdDirectContext_t. Этот контекст, будучи активирован, становится контекстом по умолчанию для приложения, так что в этом режиме корректно работают вызовы всех остальных функций Photon'а Pg*.
В этом режиме начальной точкой отсчёта для всех операций рисования является верхний левый угол экрана, поскольку запросы больше не обрезаются и не преобразуются пространством событий Photon'а. Ваше приложение, если необходимо, по-прежнему может преобразовывать и обрезать события, вызывая функции PgSetTranslation() и PgSetClipping().
Следующие функции имеют дело с режимом рисования с прямым доступом:
PdCreateDirectContext() | Создать контекст режима рисования с прямым доступом |
PdDirectStart() | Войти в режим рисования с прямым доступом |
PdDirectStop() | Выйти из режима рисования с прямым доступом |
PdGetDevices() | Получить идентификаторы областей (region IDs) для доступных в текущий момент устройств вывода изображения |
PdReleaseDirectContext() | Выйти из режима рисования с прямым доступом и освободить контекст режима рисования с прямым доступом |
PdSetTargetDevice() | Установить целевое устройство |
PdWaitVSync() | Ожидать вертикальную синхронизацию |
Вот несколько соображений, которые надо иметь в виду:
-
Когда Вы входите или выходите из режима рисования с прямым доступом, все контексты видеопамяти (за исключением дисплея) на стороне драйвера уничтожаются (драйвер генерирует событие OSINFO, так что приложение уведомляется об этом и может реинициализировать какие-либо контексты видеопамяти). Это включает видеопамять, использовавшуюся структурами PdOffscreenContext_t и всё то, что использовалось видеоверлеем программного интерфейса приложения.
-
Когда Вы выходите из режима рисования с прямым доступом, на драйвер отсылается некое уведомительное сообщение, так что все другие приложения перерисовывают себя.
-
Когда Вы находитесь в режиме рисования с прямым доступом, область графического драйвера больше не чувствительна к событиям рисования (так что менеджер Photon'а не накапливает огромный список событий рисования, обрабатываемых из других приложений).
-
Если у Вас включено автоматическое двойное буферирование (например,
devg-banshee -B...), оно отключается, пока Вы пребываете в режиме рисования с прямым доступом (чтобы позволить приложению самому управлять двойным буферированием). [ Хотя здесь и множественное число: "applicationS", очевидно, что только одному приложению. Прим. пер]
Пример
Вот как получить адрес какого-либо контекста видео-памяти (включая дисплей, который можно также рассматривать как видеопамять). Если Вы создали контекст прямого доступа, вызвав функцию PdCreateDirectContext(), и затем вошли в режим прямого доступа, вызвав функцию PdDirectStart(), Ваше приложение "присваивает" графический драйвер (PgFlush() проходит непосредственно на видеодрайвер, минуя сервер Photon'а).