Рассылка закрыта
При закрытии подписчики были переданы в рассылку "Delphi - проблемы и решения" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Delphi для профессионалов - Введение в DirectX
Информационный Канал Subscribe.Ru |
Рассылка: Delphi для профессионалов
Количество подписчиков: 6405

Здравствуйте, мои дороги подписчики!
Сразу раскажу новости.
- Мою написан программный продукт NoSPAM
- программа предназначена, в первую очередь, рядовому пользователю для фильтрования
входящей почты от СПАМА. Проста в настройке. Настройки сохраняются в INI-файлы,
что позволяет один раз настроить программу, а потом настройки установить
на другой компьютер. Работает по протоколу POP3 с возможностью APOP.
Если кто-то заинтересовался - скачивайте с сайта программы: http://igp.org.ua/products/nospam/. - Вводятся следующие правила по отправке вопросов в рассылку:
- Вопрос может быть подан либо только в рассылку, либо только на форум.
- Автору вопроса в ответ присылается ссылка на его отвеченый вопрос на форуме - как следствие должен быть указан реальный почтовый адрес.
- Вопросы которые были отвечены на форуме в рассылку не попадают.
Теперь приступим:
По просьбе одного из подписчиков рассылки высылаю материалы
относительно работы с DirectX.
Я посмею повториться, но также дам ссылку на описание DelphiX на сайте RXLib:
http://www.rxlib.ru/faqs/dx/dx.html:
|
Итак возьмемся за DirectX.... Описание у меня есть по DirectX 5. Я приведу вырезки и описания по версиям 2/3 и 5. Все описать я не смогу - не влезу в рассылку, хотя у меня на полочке стоит книжечка на последнему... DirectX 9..... Ну не набирать же ж мне ее? ;) Жаль сканера нет :(
Что такое DirectDraw
Правильнее всего было бы сказать, что DirectDraw - аппаратно-независимый механизм блиттинга, наделенный некоторыми возможностями программной эмуляции. Главная задача DirectDraw как раз и заключается в том, чтобы по возможности быстро и надежно копировать графические изображения в память видеоустройств (блиттинг).
DirectDraw можно рассматривать и с другой точки зрения - как менеджер видеопамяти. DirectDraw распределяет блоки памяти и следит за состоянием каждого блока. Программы могут по своему усмотрению создавать, копировать, изменять и уничтожать такие блоки, причем конкретные подробности этих операций остаются скрытыми от программиста. Такое описание тоже оказывается излишне упрощенным. Во-первых, DirectDraw может использовать не только видеопамять, но и обычную память (RAM). Кроме того, при проектировании менеджеров памяти основное внимание обычно уделяется надежности, а не быстродействию. При проектировании же DirectDraw главной целью было именно быстродействие.
С технической точки зрения DirectDraw представляет собой переносимый API в сочетании с набором драйверов устройств. В своей работе DirectDraw полностью обходит традиционный графический механизм Windows (интерфейс графических устройств, GDI). GDI завоевал дурную славу своим низким быстродействием, поэтому независимость от него крайне важна для достижения оптимальной скорости.
Структуры DirectDraw
После рассмотрения всех интерфейсов и функций DirectDraw мы переходим к структурам данных. Всего в DirectDraw определено восемь структур:
DDBLTFX DDCAPS DDOVERLAYFX DDPIXELFORMAT DDSURFACEDESC DDSCAPS DDBLTBATCH DDCOLORKEY
Мы не станем детально рассматривать каждую структуру, а вместо этого разберемся с одной особенностью DirectDraw, которая способна причинить немало бед, если о ней забыть.
Пять (точнее, первые пять) из восьми перечисленных структур содержат поле с именем dwSize, в котором хранится размер структуры. Присвоение значения этому полю лежит на вашей ответственности. Более того, все функции DirectDraw, получающие эти структуры в качестве аргументов, не смогут работать, если полю dwSize не будет присвоено правильное значение.
Например, фрагмент для работы со структурой DDSURFACEDESC может выглядеть так:
var surfdesc : TDDSURFACEDESC ; begin surfdesc. dwSize := sizeof (surfdesc); surf.GetSurfaceDesc( &surfdesc ); {...........} end;
Сначала мы объявляем структуру, затем присваиваем полю dwSize значение, используя функцию sizeof(). После этого структура передается функции GetSurfaceDesc интерфейса DIrectDrawSurface. Если забыть присвоить значение полю dwSize, вызов функции закончится неудачей.
На первый взгляд это выглядит глупо. С какой радости DirectDraw настаивает на передаче размера структуры, в ней же и определенной? Причина, по которой эти пять структур содержат поле dwSize, состоит в том, что в будущем они могут измениться. DirectDraw будет проверять размер структуры и по нему определять ее версию. Сейчас DirectDraw требует передачи правильного размера, чтобы приучить к этому разработчиков. Позднее это окупится, поскольку дальнейшие версии DirectDraw смогут корректно работать со старыми программами DirectDraw.
Раз уж речь зашла о структурах, следует упомянуть, что перед использованием структур желательно заполнять их нулями. В этом случае предыдущий фрагмент будет выглядеть так:
var surfdesc : TDDSURFACEDESC ; begin {..............} ZeroMemory( &surfdesc, sizeof(surfdesc) ); surfdesc. dwSize = sizeof(surfdesc); surf.GetSurfaceDesc( &surfdesc ); end;
Функция Win32 ZeroMemory() заполняет нулями область памяти, начало которой передается в качестве первого аргумента. Второй аргумент функции определяет размер инициализируемой области. Преимущество такого подхода состоит в том, что теперь можно выяснить, какие поля структуры изменились в результате вызова функции GetSurfaceDesc(). Если не инициализировать структуру, случайные значения в ее полях можно принять за величины, занесенные в нее DirectDraw.
Видеорежимы
Видеорежимом называется набор параметров, поддерживаемый аппаратурой видеокарты (видеоадаптера) и позволяющий организовать вывод графического изображения. Самым известным атрибутом видеорежима является разрешение экрана. По умолчанию, сегодня, в Windows используется видеорежим с разрешением 800х600. Это означает, что на экране выводится 800 пикселей по горизонтали и 600 пикселей по вертикали. Также часто встречаются видеорежимы с разрешением 1024х768 и выше. Некоторые видеокарты поддерживают так называемые режимы ModeX. Типичный режим ModeX имеет разрешение 320х200 и выше.
Видеорежимы также различаются по глубине пикселей (pixel depth). Этот параметр определяет количество различных значений, принимаемых отдельным пикселем, и, следовательно, количество отображаемых цветов. Например, в видеорежиме с глубиной пикселей в 8 бит каждый пиксель может иметь один из 256 различных цветов. В режимах с 16-битной глубиной пикселей поддерживается отображение до 65 536 цветов. Глубина пикселей обычно равна 8, 16, 24 или 32 битам.
Видеорежимы реализуются специальным устройством, установленным на компьютере, - видеокартой. На видеокарте устанавливается отдельная память, не входящая в основную память компьютера. Память, установленную на видеокарте, мы будем называть видеопамятью, а обычную память (RAM) - системной памятью.
Объем памяти, необходимой для поддержки определенного видеорежима, определяется разрешением и глубиной пикселей в этом режиме. Например, для видеорежима 640х480х8 (640х480 пикселей, каждый из которых имеет глубину в 8 бит) требуется 307 300 байт. Видеорежим 1024х768х16 требует 1 572 864 байт. Для поддержки видеорежимов используется видеопамять. Следовательно, режимы, поддерживаемые конкретной видеокартой, ограничиваются объемом установленной видеопамяти. Скажем, режим 1024х768х16 не поддерживается видеокартами с 1 Мбайт памяти, потому что для него такой объем памяти недостаточен.
Одна из ключевых возможностей DirectDraw - переключение видеорежимов. Она позволяет приложению DirectDraw обнаружить и активизировать любой режим, поддерживаемый установленной видеокартой. Переключение режимов подробно рассматривается в главе 4.
Аппаратное ускорение
Основная причина, по которой DirectDraw обеспечивает оптимальное быстродействие, состоит в том, что во всех возможных случаях применяется аппаратное ускорение. Это означает, что видеокарта выполняет некоторые операции с помощью встроенных в нее аппаратных средств. Аппаратное ускорение обладает двумя основными преимуществами. Во-первых, в нем используются средства, спроектированные специально для ускорения графических операций. Тем самым обеспечивается максимальная скорость выполнения всех действий. Во-вторых, аппаратное ускорение освобождает процессор компьютера от необходимости выполнения этих операций, благодаря чему процессор может заняться другими задачами.
Поверхности
Поверхностью (surface) в DirectDraw называется прямоугольная область памяти, обычно содержащая графические данные. Блок памяти, изображающий поверхность, может находиться как в системной, так и в видеопамяти. Хранение поверхностей в видеопамяти обычно повышает скорость работы программы, поскольку большинство видеокарт не может обращаться к системной памяти напрямую.
Поверхности делятся на несколько типов. Простейшими являются внеэкранные (off-screen) поверхности. Внеэкранная поверхность может находиться как в видеопамяти, так и в системной памяти, но не отображается на экране. Такие поверхности обычно используются для хранения спрайтов и фоновых изображений.
Первичная (primary) поверхность, напротив, представляет собой участок видеопамяти, отображаемой на экране. Любая программа DirectDraw, обеспечивающая графический вывод, имеет первичные поверхности. Первичная поверхность должна находиться в видеопамяти.
Первичные поверхности часто бывают составными (complex), или, что то же самое, переключаемыми (flippable). Переключаемая поверхность может участвовать в переключении страниц - операции, при которой содержимое всей поверхности мгновенно отображается на экране с помощью специальных аппаратных средств. Переключение страниц используется во многих графических программах как с поддержкой DirectDraw, так и без, поскольку оно обеспечивает очень гладкую анимацию и устраняет мерцание. Переключаемая первичная поверхность на самом деле состоит из двух поверхностей, одна из которых отображается на экране, а другая - нет. Невидимая поверхность называется вторичным буфером (back buffer). При переключении страниц поверхности меняются местами: та, которая была вторичным буфером, отображается на экране, а та, что ранее отображалась, превращается во вторичный буфер.
Как внеэкранные, так и первичные поверхности делятся на две разновидности: палитровые (palettized) и беспалитровые (non-palettized). Палитровая поверхность вместо конкретных значений цветов содержит индексы в цветовой таблице, которая называется палитрой. В DirectDraw палитровыми являются только 8-битные поверхности. Поверхности с глубиной пикселей, равной 16, 24 и 32 битам, являются бес-палитровыми. Вместо индексов в них хранятся фактические значения цветов.
Поскольку в каждом пикселе беспалитровой поверхности находятся реальные цветовые данные, необходимо знать, в каком формате хранятся отдельные пиксели поверхностей. Формат пикселя описывает способ хранения красной, зеленой и синей (RGB) составляющих. Он зависит от глубины пикселей, видеорежима и аппаратной архитектуры. Форматы пикселей подробно рассматриваются в главе 5.
На жаргоне, принятом в компьютерной графике, "блиттингом" называется операция копирования. Примером типичного блиттинга служит копирование внеэкранной поверхности во вторичный буфер. Если аппаратное ускорение невозможно, DirectDraw эмулирует блиттинг на программном уровне. Такая эмуляция справляется со своей задачей, однако выполняется намного медленнее аппаратного блиттинга. Обычно аппаратные средства видеокарты допускают блиттинг лишь для поверхностей, находящихся в видеопамяти.
В блиттинге обычно участвуют две поверхности: источник (source) и приемник (destination). Содержимое поверхности-источника копируется в поверхность-приемник. В результате операции содержимое поверхности-источника остается неизменным; блиттинг влияет лишь на поверхность-приемник. Кроме того, блиттинг не всегда изменяет все содержимое приемника; любой прямоугольный фрагмент источника можно скопировать в любое место приемника.
При блиттинге непрямоугольных областей (например, спрайтов) применяется эффект прозрачности. Для этого некоторые пиксели поверхности помечаются так, чтобы они не копировались в ходе блиттинга. Такая пометка осуществляется с помощью цветовых ключей (color key).
Цветовые ключи можно назначить как источнику, так и приемнику. Чаще применяются цветовые ключи источника. В этом случае прозрачность обеспечивается за счет того, что пиксели источника, имеющие определенные цветовые значения, не копируются в приемник. При использовании цветовых ключей приемника содержимое источника в ходе операции изменяет только те пиксели приемника, которые помечены цветовым ключом.
Кроме того, DirectDraw поддерживает ряд специализированных операций блиттинга, в ходе которых выполняется растяжение, сжатие, повороты, зеркальные отображения и наложение. Наличие этих возможностей часто зависит от видеокарты. Некоторые из операций могут при необходимости эмулироваться DirectDraw, однако за это нередко приходится расплачиваться заметным снижением быстродействия.
К сожалению, некоторые возможности вообще не эмулируются DirectDraw (например, цветовые ключи приемника). Их использование оказывается рискованным, потому что без поддержки со стороны видеокарты такие операции могут закончиться неудачей. У разработчика остаются два варианта: отказаться от данной возможности или включить в приложение собственную программную эмуляцию.
Палитры
Приложение, работающее в 8-битном видеорежиме, должно иметь палитру. Палитрой называется таблица цветов, к которой можно обратиться в любой момент. Если бы 8-битные видеорежимы обходились без палитры, то приложениям пришлось бы работать с фиксированным набором из 256 цветов. Палитра же позволяет указать, какие именно 256 цветов будут использоваться в приложении.
При использовании палитровых видеорежимов необходимо позаботиться о том, чтобы во всех графических объектах вашего приложения использовалась одна и та же палитра. В противном случае некоторые объекты будут отображаться в искаженных цветах. Палитры могут причинить немало хлопот, особенно когда вам придется выбирать единую палитру для отображения большого количества графических объектов. Тем не менее они обладают некоторыми преимуществами. Как упоминалось выше, палитры позволяют представить в ограниченном наборе максимальное количество цветов. Кроме того, с помощью палитр можно организовать палитро-вую анимацию (palette animation).
Палитровой анимацией называется методика, при которой анимация выполняется за счет изменения элементов палитры, а не самих пикселей. Это позволяет мгновенно изменить цвета многих пикселей изображения. В некоторых ситуациях (например, для повторяющихся анимаций) она оказывается полезной.
Отсечение
В идеальном случае блиттинг сводится к копированию всей поверхности на другую поверхность. Однако на практике источник довольно часто копируется на край приемника, или же приемник частично перекрыт другой поверхностью или окном. В таких случаях применяется отсечение (clipping). Оно позволяет скопировать лишь отдельную часть (или несколько частей) поверхности.
Отсечение чаще всего оказывается необходимым при написании оконных приложений DirectDraw, поскольку эти приложения должны подчиняться ?правилам поведения? для рабочего стола Windows. Мы поговорим об оконных приложениях позднее в этой главе.
DirectDraw обеспечивает полноценную поддержку прямоугольного отсечения. Тем не менее в некоторых ситуациях бывает полезно написать свою собственную процедуру отсечения. Нестандартное отсечение рассматривается в главе 3.
Другие типы поверхностей
Внеэкранные и первичные поверхности (со вторичными буферами) образуют основу всех приложений DirectDraw. Тем не менее существуют и другие разновидности поверхностей. В их число входят оверлейные поверхности, альфа-поверхности, Z-буферы и поверхности 3D-устройств.
Оверлеи (overlay) представляют собой аппаратные спрайты; следовательно, они доступны лишь на видеокартах, поддерживающих работу с оверлеями. В отличие от программного спрайта при перемещении оверлея нет необходимости восстанавливать фоновое изображение.
Альфа-поверхности (alpha channel surface) используются для выполнения альфа-наложения (alpha blending). Альфа-наложение является более сложной формой прозрачности и позволяет осуществлять ?полупрозрачное? копирование поверхностей. Альфа-поверхность может использоваться для управления прозрачностью отдельных пикселей. Такие поверхности имеют глубину в 1, 2, 4 или 8 бит. Альфа-поверхность с глубиной 1 бит поддерживает лишь два уровня прозрачности: нулевой (непрозрачный пиксель) и стопроцентный (полностью прозрачный пиксель). С другой стороны, 8-битные альфа-поверхности позволяют задавать до 256 различных степеней прозрачности. Альфа-наложение относится к числу возможностей, не эмулируемых в DirectDraw. Следовательно, для использования альфа-наложения необходимо иметь видеокарту, обладающую соответствующими аппаратными средствами, или же написать собственную функцию для программной эмуляции альфа-наложения.
Z-буферы и поверхности 3D-устройств используются в трехмерных приложениях. Эти типы поверхностей были включены в DirectDraw специально для поддержки Direct3D. Z-буферы используются при визуализации трехмерных сцен; они определяют, какие объекты сцены находятся ближе к зрителю и, следовательно, отображаются перед другими объектами. Поверхности 3D-устройств могут использоваться для синтеза трехмерных изображений в DirectDraw. Z-буферы и поверхности 3D-устройств в в этот вiпуск расслки уж точно не влезет. Но вы можете найти доку в нете. Я думаю что у Вас таки голова на плечах есть! :)
Спецификация СОМ+
Библиотека DirectDraw реализована в соответствии со спецификацией СОМ (многокомпонентная модель объекта, Component Object Model) фирмы Microsoft. Спецификация СОМ предназначена для создания стопроцентно переносимых программных компонентов, наделенных возможностью безопасного обновления. Мы рассмотрим СОМ лишь в объеме, необходимом для использования DirectDraw.
В СОМ используется объектно-ориентированная модель, более жесткая, чем модели, принятые в языках типа C++. Так, доступ к СОМ-объектам всегда осуществляется с помощью функций. СОМ-объекты не могут иметь открытых переменных. Кроме того, наследование в СОМ выглядит ограниченным по сравнению с C++.
Объекты и интерфейсы
В СОМ четко разграничены понятия объектов и интерфейсов. СОМ-объекты обеспечивают настоящую функциональность, тогда как СОМ-интерфейсы предоставляют способы для работы с ней. Обращения к СОМ-объектам никогда не осуществляются напрямую, а только через интерфейсы. Это правило соблюдается так строго, что мы даже не знаем имен СОМ-объектов. Известны лишь имена интерфейсов, используемых для работы с объектами. Поскольку прямое обращение к СОМ-объектам невозможно, в дальнейшем речь пойдет в основном об интерфейсах.
СОМ-объект может поддерживать сразу несколько интерфейсов. На первый взгляд это может показаться странным, но все объясняется тем, что в соответствии со спецификацией СОМ-интерфейс после своего определения не может быть изменен или дополнен. Это было сделано для того, чтобы не нарушать работу старых программ при обновлении СОМ-объекта. Исходный интерфейс остается неизменным, а для работы с новыми функциональными возможностями объекта добавляется новый альтернативный интерфейс.
Интерфейс IUnknown
Все СОМ-интерфейсы являются производными от интерфейса IUnknown. Префикс I (от слова interface, то есть интерфейс) является стандартным для имен СОМ-интерфейсов. Имена всех интерфейсов DirectDraw начинаются с I, однако в документации обычно приводятся без префикса. У нас при упоминании СОМ-интерфейсов префикс I также будет опускаться.
Интерфейс lUnknown содержит три функции, наследуемые всеми СОМ-интерфейсами.
AddRef() Release() Querylnterface
Функции AddRef и Release обеспечивают поддержку такого средства СОМ, как инкапсуляция времени существования (lifetime encapsulation). Она представляет собой протокол, согласно которому каждый объект сам отвечает за свое уничтожение.
Инкапсуляция времени существования реализована с помощью счетчика ссылок. Каждый объект содержит внутреннюю переменную, в которой отслеживается количество указателей или ссылок на него. В момент создания объекта счетчик равен 1. При создании дополнительных интерфейсов или указателей на интерфейсы значение счетчика увеличивается, а при уничтожении указателей на интерфейсы - уменьшается. Когда счетчик ссылок падает до нуля, объект уничтожает себя.
Функция AddRef служит для увеличения внутреннего счетчика ссылок объекта. В подавляющем большинстве случаев она вызывается самими функциями Direct Draw API. Например, при создании нового интерфейса функцией DirectDraw API создающая функция автоматически вызывает AddRef.
Функция Release уменьшает значение внутреннего счетчика ссылок. Ее следует применять при завершении работы с указателем или его выходе из области видимости. Обе функции, AddRef и Release, возвращают значение, равное новому состоянию счетчика ссылок объекта.
Функция QueryInterface() позволяет обратиться к СОМ-объекту с запросом о том, поддерживает ли он тот или иной интерфейс. Вспомните, например, что обновленные СОМ-объекты предоставляют дополнительные интерфейсы, не изменяя существующих. Если данный интерфейс не поддерживается запрашиваемым объектом, возвращается указатель на альтернативный интерфейс.
GUID
Чтобы обратиться к объекту с запросом о поддержке некоторого интерфейса, используя функцию QueryInterface, необходимо как-то идентифицировать этот интерфейс. Для этого используется значение GUID (глобально-уникального идентификатора, Globally Unique IDentifier) данного интерфейса. GUID представляет собой 128-битное значение, уникальное для всех практических целей. Значения GUID всех интерфейсов DirectDraw включены в заголовочные файлы DirectX.
Такого краткого введения в СОМ вполне достаточно для эффективной работы с DirectDraw API. Далее, по мере обсуждения DirectDraw API, вы поймете, насколько важна эта информация.
DirectDraw API
Один из способов оценить API - посмотреть на его размер. Большой, сложный API может быть результатом неудачного планирования. С другой стороны, большой API иногда свидетельствует и о том, что разработчики учли все возможные ситуации и позаботились о вас. Маленькие API нередко характерны для новых пакетов с ограничейными возможностями. С другой стороны, это может говорить и о том, что API делает только самое необходимое и ничего больше.
DirectDraw API невелик. В сущности, он настолько мал, что все его функции можно рассмотреть в одной главе (так мы и поступим), не превращая ее в справочное руководство. DirectDraw обладает некоторыми удобными средствами и подчиняется нескольким ограничениям.
Библиотека DirectDraw оформлена в виде четырех СОМ-объектов. Доступ к каждому объекту осуществляется через один или несколько интерфейсов. Вот их неполный список:
DirectDraw DirectDraw2 DirectDrawSurface DirectDrawSurface2 DirectDrawSurface3 DilrectDrawPatette DirectDrawClipper
Мы рассмотрим все интерфейсы вместе с входящими в них функциями. Тем не менее этот раздел не претендует на то, чтобы заменить собой справочное руководство. Help-файл, входящий в состав DirectX SDK, несмотря на все ограничения, содержит достаточно справочной информации, так что мы не станем подробно рассматривать все функции, а поговорим вместо этого о том, что делает каждая функция, для чего и с какой вероятностью она вам может понадобиться.
Интерфейсы DirectDraw и DirectDraw2
В первоначальном варианте библиотеки DirectX (еще в те времена, когда она называлась Game SDK) вся основная функциональность DirectDraw была сосредоточена в интерфейсе DirectDraw. Позднее, с выходом DirectX 2, рабочий интерфейс был усовершенствован. В соответствии со спецификацией СОМ интерфейс DirectDraw не изменился, а для работы с новыми возможностями использовался новый интерфейс DirectDraw2.
Следует заметить, что интерфейс DirectDraw2 представляет собой расширение DirectDraw. Он предоставляет все возможности интерфейса DirectDraw, а также ряд дополнительных. При работе с DirectX версий 2 и выше можно выбирать между интерфейсом DirectDraw и DirectDraw2. Поскольку DirectDraw2 делает все то же, что и DirectDraw, а также многое другое, вряд ли можно найти какие-то доводы в пользу работы с DirectDraw. Кроме того, Microsoft выступает против хаотичного, непоследовательного использования этих интерфейсов. По этим причинам во всех приведенных программах будет использован интерфейс DirectDraw2.
Ниже перечислены все функции интерфейсов DirectDraw и DirectDraw2 (в алфавитном порядке):
Compact () CreateCIpper() CreatePalette() CreateSurface() DuplicateSurface() EnumDisplayModes() EnumSurfaces() FlipToGDISurface() GetAvailableVidMem() GetCaps() GetDisplayMode() GetFourCCCodes() GetGDISurface() GetMonitorFrequency() GetScanLine() GetVerticalBlankStatus() RestoreDisplayMode() SetCooperativeLevel() SetDisplayMode() WaitForVerticalBlank()
Далее рассмотрены функции интерфейса DirectDraw. Обратите внимание на то, что в оставшейся части этой главы термин интерфейс DirectDraw относится как к интерфейсу DirectDraw, так и к DirectDraw2. Уточнения будут приведены лишь в тех случаях, когда функция отличается в двух интерфейсах.
Функции создания интерфейсов
Интерфейс DirectDraw представляет саму библиотеку DirectDraw. Этот интерфейс является главным в том отношении, что в нем создаются экземпляры всех остальных интерфейсов DirectDraw. Интерфейс DirectDraw содержит три функции, предназначенные для создания экземпляров интерфейсов:
CreateClipper() CreatePalette() CreateSurface()
Функция CreateClipper создает экземпляры интерфейса DirectDrawClipper. Объекты отсечения (clipper) используются не всеми приложениями DirectDraw, так что в некоторых программах эта функция может отсутствовать. Вскоре мы рассмотрим интерфейс DirectDrawClipper подробнее.
Функция CreatePalette создает экземпляры интерфейса DirectDrawPalette. Палитры, как и интерфейс DirectDrawClipper, используются не всеми приложениями DirectDraw. Например, приложению, работающему только с 16-битными видеорежимами, палитра не понадобится. Тем не менее приложение, работающее в 8-битном видеорежиме, должно создать хотя бы один экземпляр DirectDrawPalette.
Экземпляры интерфейса DirectDrawSurface создаются функцией CreateSurface. Поверхности обязательно присутствуют в любом приложении DirectDraw, работающем с графическими данными, поэтому данная функция используется очень часто.
Экземпляры самого интерфейса DirectDraw создаются функцией DirectDraw Create(), DirectDrawCreate() - одна из немногих самостоятельных функций DirectDraw, не принадлежащих никакому СОМ-интерфейсу.
Функция GetCaps()
Интерфейс DirectDraw позволяет точно узнать, какие возможности поддерживаются как на программном, так и на аппаратном уровне. Функция GetCaps() инициализирует два экземпляра структуры DDCAPS. Первая структура показывает, какие возможности поддерживаются непосредственно видеокартой, а вторая - что доступно посредством программной эмуляции. Функция GetCaps() помогает определить, поддерживаются ли нужные возможности.
DirectDraw автоматически использует аппаратную поддержку, если она имеется, и по умолчанию в случае необходимости переключается на программную эмуляцию. Неудачей заканчиваются вызовы лишь тех функций, которые не поддерживаются ни на аппаратном, ни на программном уровне.
Функция SetCooperativeLevel()
Функция SetCooperativeLevelО определяет уровень кооперации - степень контроля над видеокартой, необходимую для данного приложения. Например, нормальный (normal) уровень кооперации означает, что приложение не сможет изменить текущий видеорежим или задать содержимое всей системной палитры. Монопольный (exclusive) уровень допускает переключение видеорежимов и предоставляет приложению полный контроль над палитрой. Независимо от выбранного уровня вам необходимо вызвать SetCooperativeLevel().
Функции для работы с видеорежимами
Интерфейс DirectDraw содержит четыре функции для работы с видеорежимами:
EnumDisplayModes() GetDisplayMode() RestoreDisplayMode() SetDisplayMode()
С помощью функции EnumDisplayModes() можно получить от DirectDraw список доступных видеорежимов. По умолчанию EnumDisplayModes() перечисляет все видеорежимы, но по описаниям можно исключить из списка режимы, не представляющие для вас интереса. Функция EnumDisplayModes() не обязана присутствовать в программе, однако это желательно, если вы собираетесь организовать переключение видеорежимов. На рынке существует огромное количество видеоустройств, каждое из которых обладает своими возможностями и ограничениями. Не стоит полагаться на автоматическую поддержку любого конкретного видеорежима, за исключением принятого по умолчанию в Windows режима 640х480х8.
Функция GetDisplayMode() получает сведения о текущем видеорежиме. Она заполняет структуру DDSURFACEDESC информацией о горизонтальном и вертикальном разрешениях, глубине и формате пикселей текущего видеорежима. Ту же информацию можно получить и другими способами (например, по описанию первичной поверхности), поэтому эта функция встречается не во всех программах.
Функция SetDisplayMode() активизирует заданный видеорежим. Версия SetDisplay Mode() из интерфейса DirectDraw2 позволяет дополнительно задать частоту смены кадров. Этим она отличается от функции из интерфейса DirectDraw, в которой можно задать только горизонтальное и вертикальное разрешения и глубину пикселей. Функция SetDisp1ayMode() присутствует в любой программе, осуществляющей переключение видеорежимов.
Функция RestoreDisplayMode() восстанавливает видеорежим, действовавший до вызова SetDisplayMode(). Перед вызовом функций SetDisplayMode() и RestoreDisplayMode() необходимо предварительно установить монопольный уровень кооперации вызовом функции SetCooperativeLevel ().
Функции для работы с поверхностями
Помимо функции CreateSurface() интерфейс DirectDraw содержит следующие функции для работы с поверхностями:
DuplicateSurface() EnumSurfaces() FlipToGDISurface() GetGDISurface() GetAvailableVidMem() Compact()
Функция DuplicateSurface() создает копию существующей поверхности. Она копирует только интерфейс поверхности, но не ее содержимое. Копия поверхности использует ту же область памяти, поэтому модификация содержимого памяти приведет к изменению изображения, представленного обеими поверхностями.
Функция EnumSurfaces() используется для перебора всех поверхностей, удовлетворяющих заданному критерию. Если критерий не указан, составляется список всех существующих поверхностей.
Функция FlipToGDISurface() используется перед завершением приложения, осуществляющего переключение страниц, чтобы обеспечить правильное восстановление первичной поверхности. Вспомните о том, что при переключении страниц происходит попеременное отображение двух поверхностей. Это означает, что приложение может завершиться, не восстановив исходной поверхности, отображаемой на экране. Если это произойдет, Windows будет осуществлять вывод на невидимую поверхность. Такой ситуации можно легко избежать с помощью функции FlipToGDISurface().
Функция GetGDISurface возвращает указатель на единственную поверхность, с которой работает GDI. Весь графический вывод Windows осуществляется именно на поверхность GDI. Примером ситуации, когда эта функция может оказаться полезной, является программа копирования экрана, в которой DirectDraw используется для копирования произвольной части рабочего стола.
Функция GetAvailableVidMem() возвращает объем текущей доступной видеопамяти. Эта функция присутствует в интерфейсе DirectDraw2, но отсутствует в DirectDraw. С ее помощью приложение может определить, сколько поверхностей ваше приложение сможет создать в видеопамяти.
Функция Compact() не реализована в DirectX, однако в будущем она обеспечит механизм дефрагментации видеопамяти. Если ваше приложение постоянно создает и уничтожает поверхности, находящиеся в видеопамяти, дефрагментация может высвободить немало места.
Функции для работы с частотой смены кадров
Интерфейс DirectDraw содержит четыре функции, относящихся не к видеокарте, а к устройству отображения (монитору):
GetMonitorFrequency() GetScanLine() GetVerticalBlankStatus() WaitForVerticalBlank()
Говоря конкретно, эти функции относятся к механизму смены кадров на мониторе. С их помощью можно реализовать анимации с минимальным мерцанием и задержками. Тем не менее следует учесть, что эти функции поддерживаются не всеми комбинациями видеокарт и мониторов.
Функция GetMonitorFrequency() возвращает текущую частоту смены кадров монитора. Эта частота обычно измеряется в герцах (Гц). Например, частота в 60 Гц означает, что состояние экрана обновляется 60 раз в секунду.
Функция GetScanLine() возвращает номер строки развертки (горизонтального ряда пикселей), обновляемой в данный момент. Она не поддерживается некоторыми комбинациями видеокарт и мониторов. Если данная способность не поддерживается, функция возвращает код ошибки DDERR_UNSUPPORTED.
В высокопроизводительных графических приложениях обновление экрана обычно синхронизируется с процессом вертикальной развертки. Другими словами, первичную поверхность желательно обновлять в тот момент, когда монитор закончил очередное обновление экрана. В противном случае в одной части экрана будут отображаться новые данные, а в другой - старые. Подобный эффект называется расхождением (tearing). По умолчанию DirectDraw автоматически синхронизирует обновление экрана с завершением вертикальной развертки. В нестандартных ситуациях можно добиться синхронизации с помощью функций GetVerticalBlankStatus() и WaitForVerticalBlank().
Функция GetFourCCCodes()
Наш обзор интерфейса DirectDraw завершается функцией GetFourCCCodes(). Она возвращает коды FourCC, поддерживаемые видеокартой. Коды FourCC используются для описания YUV-поверхностей, не относящихся к стандарту RGB. Мы не будем рассматривать такие поверхности.
Интерфейсы DirectDrawSurface
Множественные интерфейсы DirectDrawSurface, как и интерфейсы DirectDraw, возникли из-за особенностей спецификации СОМ. В исходном варианте работа с поверхностями осуществлялась через интерфейс DirectDrawSurface. В DirectX 2 появились новые функциональные возможности, представленные интерфейсом DirectDrawSurface2, а в DirectX 5 возник интерфейс DirectDrawSurface3.
Хотя мы рассматриваем вместо DirectDraw интерфейс DirectDraw2, для работы с поверхностями мы будем придерживаться исходного интерфейса DirectDrawSurface, потому что нововведения интерфейсов DirectDrawSurface2 и DirectDrawSurface3 не слишком важны. В оставшейся части рассылки термин интерфейс DirectDrawSurface будет обозначать все три интерфейса, если при этом не возникает двусмысленности.
Самый большой из всех интерфейсов DirectDraw, DirectDrawSurface, позволяет копировать и стирать содержимое поверхности, а также напрямую работать с ним из программы. В общей сложности он поддерживает 36 функций, перечисленных ниже (в алфавитном порядке):
AddAttachedSurface() AddOverIayDirtyRect() BIt() BItBatch() BItFast() DeleteAttachedSurface() EnumAttachedSurfaces() EnumOverIayZOrdersFlip GetAttachedSurface() GetBltStatus() GetCaps() GetClipper() GetColorKey() GetDC() GetDDInterface() GetFlipStatus() GetOverlayPosition() GetPalette() GetPixelFormat() GetSurfaceDesc() IsLost() Lock() PageLock() PageUnlock() ReleaseDC() Restore() SetClipper() SetColorKey() SetOverIayPosition() SetPalette() SetSurfaceDesc() Unlock() UpdateOverIay() UpdateOverIayDisplay() UpdateOverIayZOrder()
Функции описания поверхностей
Мы начнем с четырех функций, с помощью которых можно получить информацию о самой поверхности:
GetCaps() GetPixelFormat () GetSurfaceDesc() SetSurfaceDesc()
Функция GetCaps() по аналогии с одноименной функцией интерфейса DirectDraw заполняет структуру информацией о том, какие возможности поддерживаются данной поверхностью. В частности, в нее заносятся сведения о том, является ли данная поверхность первичной или внеэкранной, и где она находится - в системной или видеопамяти.
Функция GetPixelFormat особенно важна при работе с поверхностями форматов High и True Color, поскольку формат пикселей может зависеть от видеокарты. Функция возвращает маски, которые определяют способ хранения отдельных цветовых составляющих.
Функция GetSurfaceDesc() возвращает описание поверхности. Сведения включают ширину и высоту поверхности, а также глубину пикселей. В описание поверхности также входит формат ее пикселей (в том же виде, что и получаемый с помощью функции GetPixelFormat()).
Функция SetSurfaceDesc() (появилась только в DirectX 5 и поддерживается только интерфейсом DirectDrawSurface3) позволяет задать значения некоторых атрибутов поверхности. Например, с ее помощью можно выбрать тип памяти, в которой должна находиться поверхность. Данная функция помогает реализовать нестандартную схему управления поверхностями.
Функции блиттинга
Интерфейс DirectDrawSurface поддерживает три функции, предназначенные для выполнения блиттинга:
BIt() BItBatch() BItFast()
Функция Blt() выполняет всю основную работу. Она осуществляет классический блиттинг (простое копирование данных между поверхностями без применения специальных эффектов), а также поддерживает растяжение, повороты, зеркальные отображения и цветовые заливки. В случае применения Blt() для поверхностей, связанных с объектом отсечения, выполняется блиттинг с отсечением.
Функция BltBatch() не реализована в DirectX 5 (ее можно вызвать, но при этом ничего не произойдет). После реализации эта функция будет выполнять сразу несколько операций блиттинга, по возможности одновременно.
Функция BltFast() является оптимизированным вариантом функции Blt(). Повышение эффективности достигается за счет сокращения возможностей, поэтому BltFast() не умеет выполнять специальные операции блиттинга, поддерживаемые функцией Blt(). Кроме того, BltFast() не выполняет отсечения. Тем не менее функция BltFastO поддерживает блиттинг с использованием цветовых ключей источника и приемника. В сочетании с нестандартными алгоритмами отсечения функция BltFast() обеспечивает выполнение самого быстрого и универсального блиттинга, которого можно добиться от DirectDraw. Нестандартный алгоритм отсечения будет реализован в главе 3.
Все три блит-функции в качестве аргументов получают две поверхности - источник и приемник. Также передаются дополнительные данные, более детально описывающие операцию блиттинга (например, положение копируемого участка на поверхности-приемнике). Там, где это возможно, функция выполняет блиттинг с аппаратным ускорением.
Функция Flip()
Функция Flip() выполняет переключение страниц. При вызове F11p() поверхность, ранее отображавшаяся на экране, становится невидимой, а вместо нее отображается вторичный буфер. Функция Flip() действует лишь для поверхностей, созданных как переключаемые.
Необходимо учитывать, что настоящее (аппаратное) переключение страниц возможно не всегда. Для переключения страниц требуется видеопамять в объеме, достаточном для хранения двух полных экранов с данными. Если это требование не выполняется, вторичный буфер создается в системной памяти. В этом случае при вызове Flip() вместо переключения страниц выполняется блиттинг - содержимое вторичного буфера из видеопамяти копируется на первичную поверхность. Это ведет к заметному снижению быстродействия, но в тех случаях, когда видеопамяти не хватает для настоящего переключения страниц, ничего другого не остается (не считая аварийного завершения программы). Если ваше приложение требует максимального быстродействия, можно запретить активизацию видеорежимов, в которых не удается организовать настоящее переключение страниц.
Функции определения состояния поверхностей
Две следующие функции предназначены для получения информации о ходе операций блиттинга и переключения:
GetBltStatus() GetFIipStatus()
С помощью функции GetBltStatusO можно определить, выполняется ли блиттинг в данный момент. Это может быть важно, поскольку копируемые поверхности не могут участвовать в других операциях. Функция показывает, занята ли данная поверхность в качестве источника или приемника блиттинга.
Аналогично, функция GetFlipStatus() показывает, происходит ли в данный момент переключение страниц. Для получения информации о переключении страниц, вызванном функцией Flip(), вместо GetBltStatus() следует пользоваться именно этой функцией даже в том случае, если DirectDraw имитирует переключение страниц посредством блиттинга.
Функции для работы с цветовыми ключами
Интерфейс DirectDraw содержит две функции для назначения и просмотра цветового ключа (или интервала цветовых ключей) поверхности:
GetColorKey() SetColorKey()
По умолчанию поверхность не имеет цветового ключа. Чаще всего цветовой ключ представляет собой один цвет, однако на некоторых видеокартах возможна работа с интервалами цветовых ключей. Цветовые ключи и их интервалы описываются структурой DDCOLORKEY. Указатели на эту структуру передаются функциям GetColorKeyO и SetColorKeyO в качестве аргументов. Функции GetColorKeyO и SetColorKeyO используются при частичном копировании поверхностей, а также при выполнении операций с цветовыми ключами приемника.
Функции Lock() и Unlock()
Одна из важнейших особенностей DirectDraw - возможность прямого доступа к графическим данным. Прямой доступ обеспечивает максимум быстродействия и гибкости, поскольку он не замедляется использованием промежуточных API, a разработчик может делать с графическими данными все, что считает нужным. Для прямого доступа к памяти поверхности существуют две функции:
Unlock() Lock()
Функция Lock() возвращает указатель на область памяти, занятую поверхностью, независимо от того, где поверхность находится - в системной памяти или в видеопамяти. Память поверхности всегда организована линейно, что позволяет максимально упростить обращение к графическим данным. Функция Unlock() сообщает DirectDraw о том, что прямой доступ к памяти поверхности завершен.
Впрочем, за эту мощную возможность приходится расплачиваться. Чтобы обеспечить прямой доступ, DirectDraw приходится на время блокировки поверхности отключать некоторые фундаментальные механизмы Windows. Если вы забудете разблокировать поверхность в Windows 95, компьютер наверняка "зависнет".
По этой причине блокировка поверхностей должна применяться в течение как можно меньшего промежутка времени. Перед тем как приступать к тестированию, необходимо тщательно проверить фрагмент программы между вызовами функций Lock() и Unlock(), потому что его невозможно отладить традиционными средствами.
Для заблокированных поверхностей не выполняются операции блиттинга и переключения, так что хранение поверхности в заблокированном состоянии не даст вам никаких преимуществ. Указатель, полученный функцией Lock(), после разблокирования поверхности становится недействительным.
Заблокированную поверхность невозможно заблокировать снова. Попытка вызова функции Lock() для уже заблокированной поверхности закончится неудачей.
Функции GetDC() и ReleaseDC()
Прямой доступ к памяти поверхности - замечательная возможность, но иногда бывает удобнее рассматривать поверхность как обычное графическое устройство Windows. Для этой цели в интерфейсе DirectDrawSurface предусмотрены две функции:
GetDC() ReleaseDC()
Функция GetDC() предоставляет в ваше распоряжение DC (контекст устройства, Device Context), через который можно осуществлять вывод на поверхность стандартными функциями Win32. Например, передавая его функции Win32 TextOut(), можно вывести на поверхность текст. Функция ReleaseDC() должна быть вызвана сразу же после завершения работы с DC.
Как и в случае с Lock() и Unlock(), функцию ReleaseDC() необходимо вызывать после GetDCO как можно быстрее. Это связано с тем, что внутри функции GetDC() вызывается Lock(), а внутри ReleaseDC () - Unlock().
Функции PageLock() и PageUnlock()
Перейдем к двум функциям, внешне похожим на Lock() и Unlock():
PageLock() PageUnlock()
Вероятно, имена этих функций были выбраны неудачно, потому что они предназначены совсем для других целей. С помощью PageLock() и PageUnlock() можно управлять тем, как Windows обходится с поверхностями в системной памяти. Для работы с ними используется интерфейс DirectDrawSurface2, в DirectDrawSurface они отсутствуют.
Обычно система Windows переносит содержимое памяти на диск, когда по ее мнению другое приложение или процесс в данный момент смогут лучше распорядиться памятью. Это относится ко всей системной памяти, поэтому поверхности DirectDraw, хранящиеся в ней, также могут переноситься на диск. Когда в такой поверхности возникнет необходимость, получение данных с диска будет сопровождаться ощутимой паузой.
Функция PageLock сообщает Windows о том, что данную поверхность нельзя переносить на диск. В этом случае поверхность всегда остается доступной и не требует долгих обращений к жесткому диску. Функция PageUnlock разрешает Windows переносить поверхность на диск.
Следует помнить, что частое использование PageLock приведет к замедлению работы Windows из-за сокращения общего объема переносимой памяти. Когда именно это произойдет, зависит от объема памяти, для которой запрещен перенос на диск, и общего объема системной памяти.
Функции PageLock и PageUnlock используются в первую очередь самой библиотекой DirectDraw, а не приложениями. Например, DirectDraw автоматически вызывает PageLock и PageUnlock, чтобы поверхности, находящиеся в системной памяти, не переносились на диск в ходе блиттинга.
Функцию PageLock можно вызывать для одной поверхности многократно. DirectDraw следит за количеством вызовов PageLock, используя механизм подсчета ссылок, поэтому для отмены многократных вызовов PageLock потребуется несколько вызовов PageUnlock.
Функции PageLock и PageUnlock не влияют на поверхности, находящиеся в видеопамяти.
Функции IsLost() и Restore()
Две следующие функции предназначены для работы с поверхностями в видеопамяти:
IsLost() Restore()
Рассмотрим следующую ситуацию: ваше приложение начинает работу. Вы размещаете как можно больше поверхностей в видеопамяти, а все остальные - в системной памяти. В течение некоторого времени приложение работает, но затем пользователь запускает другое приложение или переключается на него. Другое приложение может быть чем угодно - скажем, стандартной Windows-программой (например, Windows Explorer или Notepad). Оно также может оказаться другим приложением, которое тоже работает с DirectDraw и стремится разместить как можно больше поверхностей в видеопамяти. Если DirectDraw откажется выделить новому приложению видеопамять, оно будет работать плохо (а то и вообще не будет). Возможна и обратная ситуация - видеопамять окажется недоступной для вашего приложения.
По этой причине DirectDraw может забрать у неактивного приложения видеопамять, занятую некоторыми (или всеми) поверхностями. Такие поверхности называются потерянными (lost). Вообще говоря, такие поверхности остаются у вашей программы, но они перестают быть связанными с какой-либо областью памяти. Любая попытка использовать потерянную поверхность приводит к ошибке DDERR_SURFACELOST. Функция IsLost позволяет узнать, была ли потеряна память данной поверхности.
Потерянную поверхность можно восстановить функцией Restore, но только после повторной активизации вашего приложения. Тем самым предотвращается восстановление поверхностей для приложений, находящихся в свернутом виде на панели задач.
При этом существует одна загвоздка. Функция Restore восстанавливает лишь память, закрепленную за поверхностью, но не ее содержимое. Следовательно, после восстановления поверхности ваше приложение само должно восстановить ее содержимое.
Обратите внимание: сказанное не относится к поверхностям, находящимся в системной памяти. Если память, занятая такими поверхностями, потребуется для других целей, Windows перенесет их на диск. Все эти действия Windows выполняет автоматически, включая восстановление содержимого поверхностей.
Функция GetDDInterface()
Функция GetDDInterface() возвращает указатель на интерфейс DirectDraw, использованный для создания заданной поверхности. Эта функция используется очень редко, поскольку ваши программы, вероятно, будут обходиться одним экземпляром интерфейса DirectDraw. Тем не менее в одном приложении разрешено иметь несколько интерфейсов DirectDraw. В этом случае функция GetDDInterface() может оказаться полезной.
Функции присоединения поверхностей
Интерфейс DirectDrawSurface содержит четыре функции для управления взаимосвязанными поверхностями:
AddAttachedSurface() DeleteAttachedSurface() EnumAttachedSurface() GetAttachedSurface()
В DirectDraw возможно несколько ситуаций, при которых поверхности могут присоединяться к другим поверхностям. Самая распространенная из них - переключение страниц. Чтобы переключение страниц стало возможным, необходимо циклически соединить две или несколько поверхностей. При каждом вызове Flip() на экране будет отображаться следующая поверхность из цепочки.
Перечисленные выше функции используются для создания, просмотра и уничтожения связей между поверхностями, однако в программах они встречаются довольно редко. Обычно DirectDraw создает за вас нужные поверхности вместе с взаимными связями. Например, при создании первичной переключаемой поверхности вы указываете количество присоединенных к ней вторичных буферов. DirectDraw создает все необходимые поверхности и должным образом присоединяет их друг к другу.
Оверлейные функции
Поддержка оверлеев в DirectDrawSurface представлена следующими функциями:
AddOverlayDirtyRect() EnumOverIayZOrder() GetOverIayPosition() SetOverIayPosition() UpdateOverIay() UpdateOverIayDisplay() UpdateOverIayZOrder()
Функции GetOverlayPosition и SetOverlayPosition управляют положением оверлеев. Функция UpdateOverlay() изменяет параметры оверлея; в частности, она определяет, должен ли оверлей отображаться на экране и следует ли применять для него альфа-наложение или копирование с цветовым ключом.
Функция UpdateOverlayDisplay обновляет изображение с учетом новых значений параметров. Данная функция может обновить все изображение оверлея или ограничиться его прямоугольными областями, заданными функцией AddOverlayDirtyRect. Наконец, функция EnumOverlayZOrders используется для перебора оверлеев в порядке их Z-координаты (Z-координата определяет, какие оверлеи выводятся поверх других). Возможен перебор как в прямом порядке (от передних оверлеев к задним), так и в обратном (от задних - к передним).
Функции для работы с объектами отсечения
DirectDraw позволяет присоединить к поверхности экземпляр интерфейса DIrectDrawClipper (который мы еще не рассматривали). После того как такое присоединение состоится, операция блиттинга на данную поверхность будет регулироваться объектом отсечения. Для работы с объектами отсечения в интерфейсе DirectDrawSurface имеются две функции:
GetClipper() SetClipper()
Функция SetClipper присоединяет объект отсечения к поверхности. Функция GetClipper возвращает указатель на присоединенный ранее объект отсечения. С помощью функции SetClipper можно разорвать связь между поверхностью и объектом отсечения, для этого в качестве указателя на интерфейс DirectDrawClipper следует задать NULL.
Функции палитры
Палитры, как и объекты отсечения, можно присоединять к поверхностям. Для этой цели в интерфейсе DirectDrawSurface предусмотрены две функции:
SetPalette()
Функция SetPalette присоединяет к поверхности экземпляр интерфейса DirectDrawPalette (о нем речь пойдет ниже). Функция GetPaletteO применяется для получения указателя на палитру, присоединенную ранее.
Палитру можно присоединить к любой поверхности, однако действовать она будет лишь в том случае, если поверхность является первичной. Палитра, присоединенная к первичной поверхности, управляет палитрой видеокарты.
Интерфейс DirectDrawPalette
Интерфейс DirectDrawPalette предназначен для работы с палитровыми видеорежимами и поверхностями. Несмотря на то что в Windows поддерживается ряд видеорежимов с глубиной пикселей менее 8 бит, DirectDraw поддерживает лишь 8-битные палитровые режимы.
Экземпляры интерфейса DirectDrawPalette создаются функцией CreatePalette интерфейса DirectDraw. Функция CreatePalette получает набор флагов, определяющих тип палитры.
Интерфейс DirectDrawPalette содержит всего три функции:
GetCaps() GetEntries() SetEntries()
Функция GetCaps определяет возможности палитры. В числе получаемых сведений - количество элементов палитры, поддержка палитрой вертикальной синхронизации и (в случае 8-битной палитры) возможность заполнения всех 256 элементов.
Для заполнения палитры используется функция SetEntries. Содержимое палитры чаще всего берется из файла. Тем не менее значения элементов палитры можно рассчитать и занести в палитру во время выполнения программы. Функция GetEntMes возвращает значения элементов, ранее занесенных в палитру.
Экземпляры интерфейса DirectDrawPalette присоединяются к поверхности функцией SetPalette интерфейса DirectDrawSurface. Палитровая анимация выполняется либо присоединением разных палитр к первичной поверхности, либо изменением содержимого палитры функцией SetEntries.
Интерфейс DirectDrawClipper
Интерфейс DirectDrawClipper предназначен для поддержки отсечения. Чтобы выполнить отсечение, следует присоединить объект отсечения к поверхности и использовать ее в качестве приемника блиттинга. Экземпляры интерфейса DirectDrawClipper создаются функцией CreateClipper интерфейса DirectDraw. Интерфейс DirectDrawClipper содержит следующие функции:
SetHWnd() GetHWnd() IsClipListChanged() SetClipList() GetClipList()
Объекты отсечения обычно используются для ограничения вывода, необходимого при работе приложений DirectDraw в окне. Объект отсечения гарантирует, что при выполнении блиттинга будет учитываться присутствие на рабочем столе других окон. Например, если окно приложения будет полностью или частично закрыто другим окном, объект отсечения позаботится о том, чтобы содержимое верхнего окна не было испорчено приложением DirectDraw.
Отсечение для рабочего стола активизируется функцией SetHWnd. Функция SetHWnd присоединяет объект отсечения к логическому номеру (handle) окна. В результате инициируется взаимодействие Windows с объектом отсечения. Объект отсечения получает уведомления обо всех изменениях окон на рабочем столе и действует соответствующим образом. Функция GetHWnd определяет, к какому логическому номеру окна присоединен заданный объект отсечения (и присоединен ли он вообще). Функция IsClipListChanged определяет, был ли внутренний список отсечений изменен вследствие изменений на рабочем столе.
Функции SetClipList и GetClipList упрощают нестандартное использование интерфейса DirectDrawClipper. Функция SetClipList определяет набор прямоугольных областей, для которых разрешено выполнение блиттинга. Функция GetClipList извлекает внутренние данные объекта отсечения.
После того как экземпляр DirectDrawClipper будет присоединен к поверхности, происходит автоматическое отсечение операций блиттинга, выполняемых функциями B1t(), BltBatch() и UpdateOverlay(). Обратите внимание на то, что в список не входит функция BltFast(). Для нее отсечение не поддерживается.
Дополнительные интерфейсы DirectDraw
Строго говоря, DirectDraw содержит еще три интерфейса, не рассмотренных нами:
DDVideoPortContainer DirectDrawColorControl DirectDrawVideoPort
Эти интерфейсы, появившиеся в DirectX 5, предназначены для низкоуровневого управления видеопортами. Точнее, они предоставляют средства для потоковой пересылки "живого видео" на поверхности DirectDraw. Хотя с их помощью можно организовать в приложениях DirectDraw поддержку работы с видео, это не рекомендуется, за исключением случаев, когда высокоуровневые видео-АРI не отвечают вашим потребностям.
Пример реализации (на Visual C++)
Относительно языка - думаю это не проблема для Вас перевести код С на Delphi.
Для начала необходимо подключить к проекту библиотеку ddraw.lib и заголовочный файл ddraw.h. Для использования DirectDraw необходимо создать ссылку на объект библиотеки DirectDraw (одновременно могут работать несколько приложений использующих эту библиотеку, поэтому прямое создание и удаление объектов DirectX недопустимо).
DirectDraw работает с так называемыми поверхностями. Давайте
разберемся, что понимают под этим термином разработчики из Майкрософт. Поверхность
это некий кусочек виртуальной памяти операционной системы, обычно содержащий
изображение. Поверхность обычно не привязана к конкретному адресному пространству
и может как бы плавать в нем, в том числе поверхности могут находиться на диске
в файле подкачки и даже фрагментироваться. Но драйвер делает так, что для программиста
поверхность всегда представляет линейное пространство. Поверхности бывают нескольких
типов. Первая и самая важная: первичная поверхность, за ней закреплена видеопамять
или участок видеопамяти (доступ к которой мы и пытаемся получить). Второй тип
внеэкранная поверхность она может находиться, как в видеопамяти (если размер
оной позволяет, не будем забывать, что многие современные видеоадаптеры имеют
размер памяти значительно больший, чем необходимо для представления типичного
рабочего разрешения), так и в системной памяти. Как внеэкранные так и первичные
поверхности могут быть палитровыми и беспалитровыми. Так как моя демка изначально
нацелена на работу в беспалитровых режимах Hicolor, палитровые поверхности мы
рассматривать не будем. За любой поверхностью могут быть закреплены вторичные
буферы. Которые можно переключать, делая активным любой из подключенных буферов,
таким образом можно, например, переключать страницы видеоадаптера.
Самое главное достоинство работы с первичной поверхностью заключается в ее линейности,
специальный виртуальный драйвер берет всю работу по переключению банков памяти
видеоадаптера на себя, предоставляя нам всю видеопамять как единый кусок памяти.
В демке я использовал только первичную поверхность, все остальные, в том числе видео-буфер я выделял "в ручную" фунцией new(). Это связанно с несколькими обстоятельствами. Во-первых у многих пользователей размер видеопамяти компьютера не привышает 1 мегабайта, и не справедливо было бы лешить их возможности, увидеть проектируемую игру. Во-вторых мои эксперименты с поверхностями показали, что на таком рядовом видеоадаптере как S3trio64V+ аппаратное ускорение практически отсутствует и необходимость в работе с поверхностями практически отпала. На мой взгляд, всегда лучше полностью контролировать работу программы самому, нежели отдовать часть работы другим разработчикам, т.к. намного легче чего-то изменить.Впрочем, в следующих своих поделках (имется ввиду движок игрухи) я буду использовать вторичный буфер прикрепленный к первичной поверхности, проще говоря странички всеже быстрее будут :) (поправка от 6.10.99 скорее все же буфер)
// Итак мы описываем два объекта: LPDIRECTDRAW lpDD=NULL; // DirectDraw объект LPDIRECTDRAWSURFACE lpFront=NULL; //DDraw первичная поверхность
Типы LPDIRECTDRAW и LPDIRECTDRAWSURFACE описаны в подключенном
заголовочном файле ddraw.h Далее нам необходимо написать функцию, которая создаст
объект DirectDraw и установит нужный режим работы. До вызова этой функции мы
должны проделать такие необходимые, при программировании под Windows, вещи как
регистрация класса окна и создание главного окна приложения, после чего в нашем
распоряжении будет необходимая переменная- дескриптор окна HWND. Так как мы
не собираемся создавать вторичные поверхности, функция будет очень простой.
Необходимо заметить, что обмен параметрами с функциями DirectX часто идет через
заполнение структур, которых в DirectX просто ужасающее количество.
// Создает главный объект DD , устанавливает режим работы BOOL ddInit(HWND hwnd, HINSTANCE hInst) { HRESULT result; // возвращаемое значение DDSURFACEDESC ddsd; //структура, описывающая поверхность
Создаем объект DirectDraw, используя специально предназначенную для этого функцию, в качестве одного из параметров передадим указатель на объект DirectDraw.
result = DirectDrawCreate( NULL, &lpDD, NULL ); if( result!=DD_OK ) goto dderror;
Если все нормально то... Получим эксклюзивные права доступа к экрану и полноэкранный режим. Обращение к этой функции уже идет не непосредственно, а через указатель на объект DirectDraw (очевидно в этом и проявляется объектная модель DirectX). Параметры функции - дескриптор окна, и флаги привилегий.
result = lpDD->SetCooperativeLevel( hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ); if( result!=DD_OK ) goto dderror;
Если все нормально то продолжим работу. И установим нужный нам видео режим. У меня его задают соответствующие константы ширина, высота, глубина цвета. Вызов функции опять же через объект DirectDraw. Замечание: здесь приводится описание интерфейса DirectDraw, а существует еще DirectDraw2, и т.д. DirectDraw2, например позволяет переключать не только разрешение, но и частоту вертикального развертки монитора.
result = lpDD->SetDisplayMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH); if( result!=DD_OK ) goto dderror;
Если все пока нормально то: Создадим первичную поверхность с одним буфером. Для этого заполним структуру работы с поверхностью. Вначале всегда необходимо обнулить содержимое структуры. Кстати размер структур в windows вообще не постоянен, поэтому рекомендуется использовать метод sizeof для определения занимаемого структурой места.
memset(&ddsd,0,sizeof( ddsd )); ddsd.dwSize = sizeof( ddsd ); ddsd.dwFlags = DDSD_CAPS; // в структуре используются другие структуры, // об изменении которых необходимо проинформировать вызываемую // функцию. ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; // указали, что это первичная поверхность // И теперь вызываем функцию для создания поверхности. result = lpDD->CreateSurface( &ddsd, &lpFront, NULL ); if( result!=DD_OK ) goto dderror; //Теперь все необходимое проделали и можно выходить из функции. return TRUE; //Если произошла ошибка, проинформируем об этом пользователя // и выйдем. dderror: MessageBox( hwnd, "Direct Draw Init Failed", "ERROR", MB_OK); ddRelease(); return FALSE; }
Нужно еще описать функцию освобождения всех созданных объектов, для корректного выхода из программы. Эта функция обычно вызывается при уничтожении главного окна приложения.
// освобождает объекты DirectDraw1 и DirectSurface void ddRelease() { if( lpDD != NULL ) { if( lpFront != NULL ) { lpFront>Release(); lpFront = NULL; } lpDD>Release(); lpDD = NULL; } }
Удаление функцией delete не допустимо, т.к. нельзя забывать,
что мы работаем в многозадачной среде, и возможно, что другое приложение тоже
использует DirectX. Функция Release просто уменьшает счетчик созданных объектов
и при достижении им нуля, объект сам удаляется из памяти.
Все это хорошо, но пока совсем не понятно как работать с поверхностью, которая
может плавать по памяти и вообще находиться непонятно где. Для решения этой
проблемы придумали специальный метод объекта поверхность, который назвали блокировкой
поверхности. Вмести с ним, используется обратный метод- разблокировка, позволяющий
поверхности свободно плавать. Можно заблокировать отдельную часть поверхности,
указав ее в качестве одного из параметров как прямоугольную область. В литературе
метод блокировки используется в основном во время вызова внутренних функций
DirectDraw для работы с поверхностью. Я же его использую с единственной целью
получить адрес битовой карты поверхности (собстенно мы подошли к тому моменту
из-за чего все затевалось).
В качестве примера приведу исходник функции, копирующей картинку в формате .spr
или .pct (мои собственные форматы, созданные для удобства) на первичную поверхность
или любую другую поверхность.
Функция принимает следующие параметры: lps-указатель на поверхность, rect-рамка
по которой необходимо обрезать выводимую картинку, psrc -объект картинка, X,Y-координаты
вывода картинки относительно верхнего - левого угла поверхности, dark и light
- коэффициенты затемнения и осветления картинки.
void picPutS(LPDIRECTDRAWSURFACE lps, RECT& rect, PIC& psrc, long X, long Y, long dark, long light) { if(psrc.data==NULL) return; // обычная проверка DDSURFACEDESC ddsd; // структура для работы с поверхностью HRESULT result; // возвращаемый результат memset(&ddsd,0,sizeof(ddsd)); // обнулим и заполним структуру ddsd.dwSize=sizeof(ddsd);
Заблокируем поверхность в памяти, заметим, что Lock является методом объекта поверхность, в качестве флага показывающего как реагировать в случаи невозможности блокировки, укажем, что нужно ждать, пока поверхность не заблокируется. Любая поверхность- это общий ресурс операционной системы и может быть она уже используется другим потоком или например была утеряна приложением, но об этом позже.
result=lps->Lock(NULL, &ddsd, DDLOCK_WAIT,NULL);
Если все нормально, то функция Lock помимо блокировки поверхностти заполнила структуру ddsd конкретными характеристиками поверхности.
if(result==DD_OK) {
Далее я создаю структуру, которая повторяет заголовок картинок в моем формате. Я как будто подменяю поверхность на картинку.
// ddsd.dwWidth -ширина поверхности // ddsd.dwHeight- высота поверхности // ddsd.lpSurface- адрес битового массива поверхности PIC desc; desc.type=PIC_pct | PIC_16; desc.width=ddsd.dwWidth; desc.height=ddsd.dwHeight; desc.data=(char*)ddsd.lpSurface;
Далее просто вызывается обычная функция для копирования изображения, которая ничего не подозревает о существовании DirectX вообще и DirectDraw в частности.
picPut(desc,rect,psrc,X,Y,dark,light); // Остается только разблокировать поверхность. lps->Unlock(0); } }
Критическое замечание:
Разблокировать поверхность необходимо всегда, иначе это может
привести к непредсказуемым последствиям, вплоть до останова работы Windows.
Вообще в документации к DirectX говорится, что при блокировке поверхности операционная
система приостанавливает свою работу. Теперь о потере поверхности. Потерять
поверхность, находящеюся в видеопамяти, DirectDraw может в случаи переключения
разрешения экрана другим приложением. При этом необходимо будет восстановить
поверхность, но, к сожалению, все содержимое поверхности будет утеряно. Пример
потери внеэкранной поверхности, находящейся в системной памяти привести сложнее,
этот случай может произойти только при какой-нибудь нештатной ситуации.
Пример проверки на потерю поверхности:
double2: result=lpFront->IsLost(); if(result==DDERR_SURFACELOST) { lpFront->Restore(); goto double2; }
Все ответы присылайте по адресу: delphi-reply@igp.org.ua
Все подсказки присылайте по адресу: delphi-hint@igp.org.ua
Со всем списком советов можно познакомиться по адресу: http://igp.org.ua/delphine/.
Наш проект Delphine можно найти по следующей ссылке: http://igp.org.ua/products/delphine/.
Заходите в наш форум: Форум Delphi-профессионалов. Адрес: http://forum.igp.org.ua/.
Здесь Вы найдете ответы на все Ваши вопросы!
http://subscribe.ru/
E-mail: ask@subscribe.ru |
Отписаться
Убрать рекламу |
В избранное | ||