Руководство программиста в Photon (953920), страница 51
Текст из файла (страница 51)
PhRect_t rsrc,rdst;
/* Инициализация внеэкранной области и формирование данных по изображению,
которое мы хотим в ней иметь */
...
/* Копирование образа, хранящегося во внеэкранном контексте, на экран,
применение орерации OR к данным источника и шаблона вместе */
rsrc.ul.x = rdst.ul.x = rsrc.ul.y = rdst.ul.y = 0;
rsrc.lr.x = rdst.lr.x = rsrc.lr.y = rdst.lr.y = 100;
PgSetDrawMode(Pg_DrawModePSo);
PgSetFillDither(Pg_BLUE,Pg_BLACK,Pg_PAT_CHECKB8);
PgContextBlit(context1, &rsrc, NULL, &rdst);
/* Применение операции OR к шаблону в виде синией и чёрной шахматки –
и к данным источника; копирование результата на экран */
PgFlush();
Видеорежимы
Видеорежим определяет, как выглядит экран (что Вы видите на мониторе). Описание режима включает:
Width | Ширина экрана в пикселях |
Heigth | Высота экрана в пикселях |
Pixel depth | "Глубина" пикселя – число бит представляющих пиксель. определяет, как много уникальных цветов Вы можете видеть на экране одновременно. |
Refresh rate | Частота обновления кадров – число, указывающее, с какой частотой обновляется люминофор на ЭЛТ Вашего монитора (представлен в Hz). |
Метод перечисления видеорежимов, применяемый в микроGUI Photon'а, схож со спецификацией VESA, где имеются "номера режимов" – численные представления ширины, высоты и пиксельной глубины видеорежима. Частота регенерации зависит от номера режима (это является отдельным членом в PgDisplaySettings_t). Номера режимов определяет драйвер, так что для одной видеокарты режим 640х480х8 может быть режимом 2, тогда как для другой – режимом 3022. Чтобы определить свойства какого-либо данного номера режима, используйте функцию PgGetVideoModeInfo(). Чтобы получить список номеров режимов, поддерживаемых конкретным графическим драйвером, используйте функцию PgGetVideoModeList().
Функциями для работы с видеорежимами являются:
PdSetTargetDevice() | Установить целевое устройство |
PgGetGraphicsHWCaps() | Определить характеристики аппаратного обеспечения |
PgGetVideoMode() | Получить текущий видеорежим |
PgGetVideoModeInfo() | Получить информацию о видеорежиме |
PgGetVideoModeList() | Запросить у графического драйвера список поддерживаемых им видеорежимов |
PgSetVideoMode() | Установить текущий видеорежим |
Вот некий простой код:
PgVideoModes_t ModeList;
PgVideoModeInfo_t ModeInfo;
PgDisplaySettings_t ModeSetting;
int I = 0, done = 0;
if (PgGetVideoModeList(&ModeList)) {
/* Ошибка – драйвер этого не поддерживает */
}
/* Использовать для этого режима принятую по умолчанию частоту обновления */
ModeSetting.refresh = 0;
while (!done) {
if (PgGetVideoModeInfo(ModeList.modes[i], &ModeInfo)) {
/* Код ошибки */
}
if ((ModeInfo.width = = 640) && (ModeInfo.height = = 480) && (ModeInfo.bits_per_pixel = = 16))
{
/* Мы нашли режим, который искали */
done = 1;
ModeSetting.mode = ModeList.modes[i];
}
i++;
if (i >= ModeList.num_modes) {
/* Ошибка – режим не найден */
done=1;
}
}
PgSetVideoMode (&ModeSetting);
Градиенты
Градиент – это постепенный переход одного цвета в другой. Библиотека Photon'а поддерживает:
-
Градиенты уровня драйвера – быстрые, но не изощрённые. Точность жертвуется ради скорости.
-
Градиенты уровня приложения – более медлительные, но более точные.
Градиенты уровня драйвера
Хотя библиотека Photon'а поддерживает большое многообразие градиентов (см. PhImage_t), бывают моменты, когда Вам понадобится простой градиент, формируемый без хранения его в PhImage_t. Поэтому к графическому драйверу добавлены несколько базовых операций формирования градиента:
PgDrawGradient() Потребовать от графического драйвера сформировать градиент
Градиенты уровня приложения
Эти функции позволяют ВАм создать Ваши собственные градиенты:
PgBevelBox() | Рисовать прямоугольник с фасками, имеющий градиенты |
PgCalcColorContrast() | Вычислить светлый и тёмный цвета для использования в градиенте |
PgContrastBevelBox() | Рисовать прямоугольник с фасками, имеющий градиенты и заданный уровень контрастности |
PgDrawGradientBevelBox() | Рисовать прямоугольник с фасками, имеющий градиенты и два плоских цвета |
Видеоверлей
Видеоверлейная пересчётная схема (video overlay scaler) – это аппаратная возможность, позволяющая на прямоугольной области видимого экрана менять масштабированные версии отличающегося рисунка. Предварительно отмасштабированные видеокадры обычно размещены во внеэкранной памяти, и они выбираются из памяти и накладываются сверху на экранный образ рабочего стола в реальном времени с помощью видеоверлейной пересчётной схемы.
Для контроля за тем, какая часть видеокадра видима, используется хромоключ. Обычно приложение отбирает цвет, являющийся цветом хроматического ключа, и рисует прямоугольник этого цвета там, где появляется видеосодержание. Когда другое окно приложения размещается сверху на приложении, воспроизводящем видео, окрашенный в хроматический цвет прямоугольник затеняется. Поскольку видеоаппаратное обеспечение запрограммировано на отображение видеосодержания экрана только тогда, когда рисуется цвет хромоключа, видео не демонстрируется, пока прямоугольник цвета хромоключа затемнён.
Следующие функции и типы данных имеют дело с видеоверлеем:
PgConfigScalerChannel() | Конфигурирование канала пересчётной схемы видеоверлея |
PgCreateVideoChannel() | Создание канала для видеопотока |
PgDestroyVideoChannel() | Освобождение ресурса, связанного с видеоканалом |
PgGetOverlayChromaColor() | Возвращает цвет, используемый для оверлейных операций хромоключа |
PgGetScalerCapabilities() | Получает характеристики пересчётной схемы видеоверлея |
PgNextVideoFrame() | Получает индекс следующего видеобуфера для заполнения |
PgScalerCaps_t() | Структура данных, описывающая характеристики пересчётной схемы видеоверлея |
PgScalerProps_t() | Структура данных, описывающая свойства персчётной схемы видеоверлея |
PgVideoChannel_t() | Структура данных, описывающая канал видеоверлея |
Пример
#include <stdio.h>
#include <Ph.h>
#define SRC_WIDTH 100
#define SRC_HEIGHT 100
#define DATA_FORMAT Pg_VIDEO_FORMAT_YV12
unsigned char *ybuf0, *ybuf1;
unsigned char *ubuf0, *ubuf1;
unsigned char *vbuf0, *vbuf1;
void grab_ptrs(PgVideoChannel_t *channel) {
/* Буферы перемещались, получить указатели снова */
ybuf0 = PdGetOffscreenContextPtr(channel->yplane1);
ybuf1 = PdGetOffscreenContextPtr(channel->yplane2);
ubuf0 = PdGetOffscreenContextPtr(channel->uplane1);
ubuf1 = PdGetOffscreenContextPtr(channel->uplane2);
vbuf0 = PdGetOffscreenContextPtr(channel->vplane1);
vbuf1 = PdGetOffscreenContextPtr(channel->vplane2);
if (channel->yplane1) fprintf(stderr, "ybuf0: %x, stride %d\n", ybuf0, channel->yplane1->pitch);
if (channel->uplane1) fprintf(stderr, "ubuf0: %x, stride %d\n", ubuf0, channel->uplane1->pitch);
if (channel->vplane1) fprintf(stderr, "vbuf0: %x, stride %d\n", vbuf0, channel->vplane1->pitch);
if (channel->yplane2) fprintf(stderr, "ybuf1: %x, stride %d\n", ybuf1, channel->yplane2->pitch);
if (channel->uplane2) fprintf(stderr, "ubuf1: %x, stride %d\n", ubuf1, channel->uplane2->pitch);
if (channel->vplane2) fprintf(stderr, "vbuf1: %x, stride %d\n", vbuf1, channel->vplane2->pitch);
}
void overlay_example() {
PgVideoChannel_t *channel;
PgScalerCaps_t vcaps;
PgScalerProps_t props;
unsigned char *ptr;
unsigned short *ptr16;
int i = 0, j, k, index;
int color;
PhDrawContext_t *old;
int rc;
if ((channel = PgCreateVideoChannel(Pg_VIDEO_CHANNEL_SCALER, 0)) = = NULL) {
perror("PgCreateVideoChannel");
exit(1);
}
/* Проход по доступным форматом в поисках интересующего */
vcaps.size = sizeof (vcaps);
while (PgGetScalerCapabilities(channel, i++, &vcaps) == 0) {
if (vcaps.format == DATA_FORMAT) break;
vcaps.size = sizeof (vcaps);
}
if (vcaps.format != DATA_FORMAT) {
fprintf(stderr, "Формат не поддерживается?\n");
exit(1);
}
props.size = sizeof (props);
props.format = DATA_FORMAT;
props.viewport.ul.x = 20;
props.viewport.ul.y = 20;
props.viewport.lr.x = 600;
props.viewport.lr.y = 440;
props.src_dim.w = SRC_WIDTH;
props.src_dim.h = SRC_HEIGHT;
props.flags =
Pg_SCALER_PROP_SCALER_ENABLE |
Pg_SCALER_PROP_DOUBLE_BUFFER |
Pg_SCALER_PROP_DISABLE_FILTERING;
if (PgConfigScalerChannel(channel, &props) == -1) {
fprintf(stderr, "Не удалось сконфигурировать канал\n");
exit(1);
}
grab_ptrs(channel);
for (i = 0; i < 100; i++) {
index = PgNextVideoFrame(channel);
delay(50);
ptr = (void *)(index ? ybuf1 : ybuf0);
color = rand() & 0xff;
for (k = 0; k < props.src_dim.h; k++) {
memset(ptr, color, channel->yplane1->pitch);
ptr += channel->yplane1->pitch;
}
}
props.flags &= ~Pg_SCALER_PROP_DISABLE_FILTERING;
switch (PgConfigScalerChannel(channel, &props)) {
case -1:
fprintf(stderr, " Не удалось сконфигурировать канал \n");
exit(1);
break;
case 1:
grab_ptrs(channel);
break;
case 0:
default:
break;
}
fprintf(stderr, "\"TV показ\" эффект\n");
for (i = 0; i < 1000; i++) {
index = PgNextVideoFrame(channel);
ptr = (void *)(index ? ybuf1 : ybuf0);
for (k = 0; k < props.src_dim.h; k++) {
for (j = 0; j < channel->yplane1->pitch; j++) *(ptr + j) = rand() & 0xff;
ptr = (void *)((char *)ptr + channel->yplane1->pitch);
}
/* Установка хроматичности для монохромности в нейтральное */
ptr = ubuf0;
for (i = 0; i < props.src_dim.h; i++) {
memset(ptr, 128, props.src_dim.w / 2);
ptr += channel->uplane1->pitch;
}
ptr = vbuf0;
for (i = 0; i < props.src_dim.h; i++) {
memset(ptr, 128, props.src_dim.w / 2);
ptr += channel->vplane1->pitch;
}
if (rand() % 200 == 23) {
props.viewport.ul.x = rand() % 400;
props.viewport.ul.y = rand() % 300;
props.viewport.lr.x = props.viewport.ul.x + SRC_WIDTH + rand() % 200;
props.viewport.lr.y = props.viewport.ul.y + SRC_HEIGHT + rand() % 200;
if (PgConfigScalerChannel(channel, &props) == 1) grab_ptrs(channel);
}
}
/*
* В действительности это не нужно, поскольку видеоресурсы будут освобождены
* автоматически при завершении приложения
*/
PgDestroyVideoChannel(channel);
}
int main(int argc, char *argv[]) {