Реферат: I. ОСНОВНЫЕ БОГОСЛОВСКИЕ ПОЛОЖЕНИЯ

Первое: пример MainExample в окне в видеорежимах HighColor или TrueColor на всех компьютерах с видеокартами GeForce2 MX 400, где я его тестировал, почему-то работает некорректно. Наблюдается странное поведение всей операционной системы в виде общего замедления работы. Это можно было бы со злорадством отнести к ошибкам движка, НО:

  1. На видеокарте S3 Trid3D/2X движок работает нормально в любом режиме!
  2. На видеокарте GeForce всё работает нормально в режиме 256 цветов!

Вот так. Самое удивительно — примеры из MS SDK работают у меня корректно на обеих видеокартах. Вообще, когда такая ошибка обнаружилась, я был в большом недоумении и полностью растерян. Для «чистоты эксперимента» я даже написал отдельную программу (не на движке), которая также работала в оконном режиме. К сожалению, и она работала некорректно, а ведь программный код был минимален и ошибке попросту негде было спрятаться. Поразмыслив, я пришёл к выводу, что имеет место некорректное взаимодействие программ, написанных на Delphi и драйверов Detonator. Звучит дико, но других объяснений я не нахожу.

Второе: я переделал функцию сохранения изображения в файле, теперь она работает корректно для видеокарты S3. К сожалению, на GeForce в 16-битовом режиме она получается искажённой, причину я так не нашёл. Для режима 32 бита всё работает правильно.

Мысли вслух:

  1. Если планируется писать какую-то игру или мультимедийное приложение, лучше написать сначала движок для неё.
  2. Разработка более-менее крупной программы после маленьких развязывает руки, позволяет «развернуться» программисту, реализовать некоторы свои амбиции.
  3. Вместе с тем работа по ловле ошибок довольно хлопотна и иногда раздражает.
  4. Уделите некоторое внимание организации вывода сообщений об ошибках — это окупится сторицей в процессе разработки.
  5. Иногда встречаются никак, совершенно, ну абсолютно необъянимые «bugs»! Это может здорово испортить жизнь.
  6. Иногда (только иногда) такие баги пропадают сами собой, если их «заморозить» недельки на две заглушкой, а потом снять %)
  7. Собственная(!) реализация всяких эффектов вроде прозрачности и поворота радует глаз, однако слишком уж они медленны и неказисты, их качество часто желает оставлять лучшего. Вдобавок, DirectDraw API постепенно становится устаревшей технологией, её развите корпорацией Microsoft уже давно остановлено. Возможно, захотев иметь в своей программе красочные спецэффекты, следует обратить своё внимание на двумерное рисование посредством таких API, как Direct3D и OpenGL.
DirectX для начинающих

 

Sprite

 

Вернуться к разделу Hello, World! DirectX для начинающих Автор Виктор Кода, дата публикации 8 апреля 2002г.

Этот пример демонстрирует вывод изображения средствами DirectDraw. Он построен без использования VCL, но я надеюсь это не помешает вам. Вот файлы проекта:

  • sprite.dpr — отвечает за создание окна и выборку системных сообщений.
  • basedd8.pas — содержит функции для работы с DirectDraw.

После регистрации класса окна и его отображения производится инициализация DirectDraw. За это отвечает функция InitDirectDraw(). Рассмотрим её работу подробнее.

 

Первым делом необходимо создать объект DirectDraw. На сегодняшний момент его нужно создавать функцией DirectDrawCreateEx(), а не DirectDrawCreate(), как это было в прошлых версиях. Первый параметр представляет собой указатель на уникальный идентификатор драйвера видеоадаптера, но т. к. в большинстве случаев компьютеры оснащаются одним видеоадаптером, то можно передать nil. Второй параметр является указателем на интерфейс IDirectDraw7.

Параметр iid может принимать только одно значение — IID_IDIRECTDRAW7. Любое другое значение приведёт к ошибке DDERR_INVALPARAMS. Последний параметр в описываемой функции на данный момент не используется и предназначен для будущих версий. Результат, возвращаемый функцией (равно как и любой другой в DirectX), имеет тип HRESULT, т.е. может иметь множество кодов завершения. В DirectDraw успешная работа функции определяется константой DD_OK, а ошибочная — множеством других, зависящих от типа ошибки. Кроме упоминавшейся константы DDERR_INVALPARAMS функция может вернуть DDERR_UNSUPPORTED, сообщив тем самым, что объект DirectDraw не инициализирован. Чтобы избежать мороки с проверкой возвращённого результата, рекомендуется применять макросы (в Delphi практически функции) FAILED() и SUCCEEDED(), определённые в windows.pas. Дело в том, что 31-й бит возвращаемого значения содержит флаг критичности, который указывает, произошла ли ошибка или нет. Если бит равен 0, то ошибки не было, а если он равен 1, то ошибка имела место. Это как раз и проверяют вышеуказанные макросы. Конечно, никто не запрещает написать так:

Но профессионалы используют исключительно макросы FAILED() и SUCCEEDED().

После создания объекта необходимо установить режим кооперации — т. е. определить, оконный или полноэкранный режим будет использовать DirectDraw. Надо сразу «брать быка за рога» и программировать полноэкранные приложения. Режим кооперации учтанавливается методом IDirectDraw7.SetCooperativeLevel(). Первым параметром передаётся идентификатор окна типа HWND. Второй представляет собой комбинацию флагов. Установим такие:

  • DDSCL_ALLOWREBOOT — указывает, что будет доступно окно снятия программы по нажатию клавиш Ctrl-Alt-Del. Полезно при отладке приложения (вдруг зависнет). Этот флаг впоследствии можно и убрать.
  • DDSCL_EXCLUSIVE — используется только в полноэкранных приложениях.
  • DDSCL_FULLSCREEN — устанавливает полноэкранный режим. При его ипользовании обязателен флаг DDSCL_EXCLUSIVE.

Следующим действием является установка видеорежима. Это делает метод
IDirectDraw7.SetDisplayMode(). Первые три параметра указывают ширину и высоту экрана, а также глубину палитры (8, 16, 24, 32). Последние два параметра используются редко. Подробности о них можно узнать из SDK.

Итак, мы создали объект DirectDraw и изменили разрешение экрана. В этот момент работы программы наше окно моментально заслоняет все объекты на Рабочем столе, включая панель задач. Если вы ещё не обратили внимание, для создания окна я использовал структуру WNDCLASSEX, а не WNDCALSS. Дело в том, что окно, построенное на базе последней, не сразу закрывает весь экран — 1-1,5 секунды продолжает красоваться Панель задач. Возможно, всё дело во флаге WS_EX_TOPMOST, который можно использовать только совместно с WNDCLASSEX.

Не стоит пренебрегать данными преимуществами — зто делает программу более «профессиональной» при минимуме усилий. Попробуйте создавать окно на базе разных классов — сами почувствуете разницу. Следующим шагом создадим первичную поверхность. Фактически это область видеопамяти, которая будет использоваться видеоадаптером для отображения картинки на экране монитора.

Поскольку поверхности могут быть разных типов (не только первичными, но и внеэкранными), а метод для их создания только один — lDirectDraw7.CreateSurface(), необходимо каким-то образом указать, что мы хотим создать именно первичную поверхность. Как это сделать?

Обратите внимание, что первый параметр метода — это указатель на структуру TDDSURFACEDESC2 (кстати, в SDK 8 для С++ этим параметром нужно передавать адрес структуры TDDSURFACEDESC, а не TDDSURFACEDESC2. Это ошибка перевода заголовочных файлов C++ на Pascal: тем не менее, всё работает корректно). Именно через эту структуру DirectDraw узнает, какой тип поверхности нужно создать.

Перед использованием структуры распространённой практикой является заполнение её нулями — на случай всякого «мусора» в RAM, который может привести к ошибке во время выполнения. Я использую функцию ZeroMemory(), но можно и FillChar(). Следующим действием является заполнение поля dwSize этой структуры размером самой структуры. Это действие обязательно!

Поле dwFlags определяет, какие другие поля структуры мы будем использовать. По-видимому, это сделано для обеспечения наивысшего быстродействия — теперь DirectDraw не будет просматривать все поля структуры (а их очень много), а «заглянет» только в те, которые мы указали. Мы будем использовать поля ddsCaps и dwBackBufferCount. Укажем это флагами DDSD_CAPS и DDSD_BACKBUFFERCOUNT. Поле ddsCaps.dwCaps как раз и определяет тип создаваемой поверхности — флаги DDSCAPS_PRIMARYSURFACE, DDSCAPS_FLIP и DDSCAPS_COMPLEX сообщат DirectDraw, что мы хотим создать первичную комплексную поверхность с возможностью переключения буферов. Поле dwBackBufferCount указывает количество задних буферов, которые мы подключим к первичной поверхности — установим 1 (хотя можно подключить и больше).

Вызываем метод lDirectDraw7.CreateSurface(), указав вторым параметром нужный интерфейс. Третий параметр заразервирован и не используется.

Теперь к первичной поверхности нужно «приаттачить» задний буфер. Этот буфер исключительно важен для самого механизма вывода изображений и необходим для избавления от мерцания спрайтов. Для создания заднего буфера используется структура TDDSCAPS. Очищаем её и задаём флаг DDSCAPS_BACKBUFFER. Методом IDirectDrawSurface.GetAttachedSurface() подсоединим задний буфер. Всё, инициализация DirectDraw закончена.

Теперь нужно создать внеэкранные поверхности и загрузить в них изображение. Внеэкранные поверхности представляют собой линейные области данных в видео- или системной памяти, которые предназначены для хранения графических данных. За всё это отвечает процедура LoadFiles(). Первым делом получаем идентификатор загруженного функцией LoadImage() растра. Я не буду её описывать, т. к. к DirectDraw она не имеет прямого отношения — за этим прошу в Help Win32 API. Скажу лишь, почему я применил именно эту функцию. Дело в том, что часто возникает необходимость загружать не только файлы формата bmp, но и файлы других форматов, например gif или JPEG. Обычно для их загрузки применяются различные библиотеки DLL (например, nViewLib.dll), результаты работы функций в этих библиотеках — величина типа HBITMAP. Её можно использовать в единообразном методе загрузки файлов различных форматов. Рекомендую использовать именно такой метод, если только вы не гуру в алгоритмах сжатия разных форматов файлов и не собираетесь самостоятельно писать функции по преобразованию сжатых файлов в растр — ведь DirectDraw подобных решений не предоставляет. К сожалению, недостаток такого способа в том, что он немного медленнен :-(. Впрочем, увеличенное время считывания должно сколь-нибудь существенно проявиться лишь при загрузке очень большого количества файлов (30-40 МБ и более).

Теперь рассмотрим процедуру CopyImage(). Первым параметром мы передаём адрес интерфейса IDirectDrawSurface — именно на на эту поверхность и будет загружен растр. Вторым — идентификатор загруженного растра. Вообще, работа функции CopyImage() базируется на GDI. После создания контекста и выбора в него растра мы получаем размеры этого растра функцией GetObject(). Теперь нужно создать поверхность DirectDraw c полученными шириной и высотой растра. За это отвечает ещё одна функцияCreateSurface(). Механизм в ней похож на тот, что использовался для создания первичной поверхности, поэтому подробно я его описывать не буду. Обратите только внимание на флаг DDSCAPS_OFFSCREENPLAIN — он указывает, что мы хотим создать именно внеэкранную поверхность. К сожалению, нельзя динамически менять размер поверхности DirectDraw — для этого нужно заново создать её и загрузить данные. После успешного создания поверхности можно загрузить на неё растр — для этого существует удобный метод IDirectDrawSurface.GetDC(). Захватив контекст устройства, осуществляем копирование растра с одного контекста на другой, захваченный (а фактически на поверхность DirectDraw). Для этого используется функция GDI BitBlt(). Достоинством метода можно считать тот факт, что теперь на поверхности DirectDraw можно рисовать любыми функциями GDI, а не только BitBlt(), не прибегая к прямому доступу к памяти, в которой расположена поверхность — например, нарисовать линию или овал. А если возникнет потребность вывести текст? Так что отказываться от GDI пока ещё рано. Да, захваченный контекст нужно освободить методом IDirectDrawSurface.ReleaseDC().

Ну вот, ещё один шаг позади. Самое время вернуться в модуль .dpr и посмотреть, что происходит дальше. Приложение начинает осуществлять выборку системных сообщений, а при отсутствии таковых вызывает функцию OnDraw(). В VCL этот алгоритм называется Application.OnIdle.

Рассмотрим OnDraw() подробнее. Это — сердце алгоритма вывода изображений на экран.
Вывод изображения в полноэкранном режиме осуществляется методом IDirectDrawSurface.BltFast(). Этот метод должен вызываться для поверхности, созданной как задний буфер — именно на нём мы и будем рисовать. Этот метод максимально быстр, но ограничен функционально, например, он не в состоянии сжать по осям выводимое изображение. Первые два параметра — координаты левого верхнего угла вывода спрайта. Третий — поверхность, содержимое которой будем выводить. Четвёртый — адрес структуры типа TRect, которая будет определять облать вывода поверхности — её инициализацию я сделал перед вызовом метода IDirectDrawSurface.BltFast(). Поэксперементируйте с функцией SetRect() и посмотрите, как параметры в ней влияют на изменение в выводе графики. Пятым параметром метода передадим константу DDBLTFAST_WAIT — она нужна для корректного вывода на экран.

Описанные действия нужно повторить для каждого выводимого спрайта. Последним делом нужно переместить содержимое заднего буфера на первичную поверхность, содержимое которой, как я уже сказал, представляет собой текущее изображение на мониторе. Сделаем это методом IDirectDrawSurface.Flip(), указав первым параметром nil — ведь у нас только один задний буфер. Константа DDFLIP_WAIT нужна для коректного вывода на экран. Этот метод следует вызывать только для первичной поверхности. Перемещение заднего буфера на экран — один из самых быстрых методов DirectDraw.
Теперь изображение появится на экране. Можете подвигать спрайт при помощи клавиатуры — так интересней.

После нажатия на клавишу Escape происходит выход из цикла. Затем программа вызывает нижестоящую функцию ReleaseDirectDraw(), которая восстанавливает начальное разрешение и удаляет созданные поверхности и объект DirectDraw. Заметьте, что вызов _Release() для соответствующего интерфейса будет корректным только в том случае, если произошёл вызов _AddRef(). Вообще, говорят что вызовы эти необязательны, но я всё же использую их для полной корректности работы программ.

Последним в цепочке действий разрушается окно — действие не обязательное, но для корректного освобождения памяти желательное.

DirectX для начинающих

 

Sound

 

Вернуться к разделу Hello, World! DirectX для начинающих Автор Виктор Кода, дата публикации 8 апреля 2002г.

Одним из достоинств компоненты DirectSound является то, что она имеет прямой (ну, почти прямой) доступ к аппаратному обеспечению звуковой карты. Среди интересных возможностей следует выделить размещение данных в памяти звуковой платы, использование аппаратного микширования звука, возможность создавать объёмный звук, используя специальные алгоритмы (это нужно для 3D-игр) — всё это мультимедиа-средства Windows обеспечить не в состоянии. Если как следует поработать с DirectSound API, можно создать очень качественный движок для вывода звука — такой, как во многих современных играх. Разумеется, желательно и соответствующее оборудование для вывода звука.

Этот пример использует только общие возможности компонента DirectSound (DirectXAudio), в частности, не используется механизм подкачки звуковых данных, не используются трёхмерные эффекты для придания «объёмности» звуку и т. д. Зато к несомненным достоинствам следует отнести универсальность алгоритма считывания звуковых данных из wav-файлов — читается любой формат. Пускай не обижаются Денис Гончаров и Тимур Салихов, по книге которых я и изучал DirectSound, но поставлять учебные примеры в стадии «обмоченные детские пелёнки» просто стыдно. Дело в том, что учебный пример по воспроизведению звуковых файлов, который поставлялся вместе в книгой, открывал только те wav-файлы, которые поставлялись на том же CD-ROM. С другими, в частности, из каталога Windows\Media, пример работать наотрез отказывался — программа просто «вылетала». Поэтому пришлось прибегнуть к SDK и воспользоваться его примерами — благо, они работают корректно со всеми wav-файлами в формате PCM (я не встретил ни одного, который бы вызвал ошибку). Всё-таки парни из Microsoft знают, что делают.

К сожалению, за универсальность приходится платить, поэтому данный пример по объёму мало смахивает на учебный. К тому же, он недописан до конца :-( — надеюсь, кто-нибудь поможет мне одолеть возникшие проблемы.

Вот файлы проекта:

  • main.pas — главное окно программы.
  • wavread.pas — реализация класса TWaveSoundRead для чтения данных из wav-файлов.
  • lowfunc.pas — функции для работы с wav-файлами на низком уровне. Используются классом TWaveSoundRead.

Итак, кликаем два раза по форме — попадаем в процедуру FormCreate(). Певой вызывается функция InitDirectSound() — обычный подход. В ней создаётся главный объект DirectSound и устанавливается уровень кооперации. Для установки эксклюзивного уровня кооперации в DirectX 7 использовался флаг DSSCL_EXCLUSIVE. В документации SDK 8 сказано, что этот флаг уже устарел и не предоставит приложению эксклюзивного режима. Для этого теперь используется флаг DSSCL_PRIORITY. Вообще, эксклюзивный режим подразумевает приглушение всех других звуков, если наше приложение активно и само воспроизводит какой-либо звук. Я пробовал устанавливать оба флага, и в обоих случаях помимо собственного вывода был слышен и вывод других программ, запускаемых параллельно, даже если окно приложения было активно. Что это, мои ошибки или ошибки в DirectSound — я не знаю. Если у вас всё работает корректно, напишите мне.

Теперь программа ничего не делает, а ждёт, когда пользователь нажмёт кнопку «Открыть...». По щелчку на ней открывается диалоговое окно выбора звукового файла. После успешного выбора вызывается функция CreateStaticBuffer(), единственный параметр которой — имя открываемого wav-файла. Эта функция создаёт специальный звуковой буфер.

Звуковой буфер — это область памяти, создаваемая в RAM или памяти звуковой карты, в которой будут размещены сэмплы — звуковы данные, считанные из wav-файла. Используя этот буфер, DirectSound сможет воспроизвести звук.

Для создания звукового буфера служит метод IDirectSound8.CreateSoundBuffer(). Первый параметр — адрес структуры типа TDSBUFFERDESC. Её поля необходимо предварительно заполнить. Второй — указатель на интерфейс IDirectSoundBuffer, третий — вездесущий параметр агрегирования — передаём nil. Теперь разберёмся со структурой TDSBUFFERSDESC.

Она указывает DirectSound, какой тип буфера мы хотим создать. Как обычно, системную память, где расположены поля структуры, необходимо заполнить нулевами значениями функцией ZeroMemory() (или FillChar()). Поле dwSize должно содержать размер самой структуры в байтах. Поле dwFlags определяет тип создаваемого звукового буфера. Вот некоторые флаги:

  • DSBCAPS_STATIC — обычный звуковой буфер. Будучи создан один раз, может проигрываться многократно. DirectSound пытается разместить такой буфер в памяти звуковой карты.
  • DSBCAPS_LOCHARDWARE — указывает, что микширование данного буфера будет выполняться аппаратно.
  • DSBCAPS_LOCSOFTWARE — указывает, что будет применяться программное микширование.
  • DSBCAPS_CTRL3D — буфер позволит управлять объёмным звучанием.
  • DSBCAPS_CTRLPAN — указывает на необходимость изменять баланс звука а колонках
  • DSBCAPS_CTRLVOLUME — буфер позволит менять громкость выводимого звука.
  • DSBCAPS_GLOBALFOCUS — воспроизведение звука не прекратится даже в том случае, если приложение потеряет активносить.

Это только половина возможных флагов. Подробнее о них можно узнать из справки SDK.
Теперь необходимо назначить требуемый размер для буфера в байтах, чтобы в нём поместились все данные из wav-файла — заполнить поле dwBufferBytes.

Вся работа по открытию wav-файлов, загрузке из них данных и завершению работы с ними возлагается на класс TWaveSoundRead — можно пользоваться им как «чёрным ящиком» — ничего увлекательного в реализации методов класса нет — сплошные операции с указателями и вызов функций из модуля lowfunc.pas. Вообще DirectSound создавался лишь для прямого доступа к звуковой карте, и в его задачу не входит чтение звуковых данных из файлов, будь то даже несжатые wav-файлы — мультимедиа-стандар Windows. Вся работа по загрузке данных в буфер ложится на программиста. К сожалению, это сильно усложняет даже простейшие проекты, т. к. функции для работы с wav-файлами довольно громоздки, а о работе с другими форматами и говорить не приходится. О классе я ещё упомяну, а сейчас лишь скажу, что при вызове метода TWaveSoundRead.Open() при успешном открытии звукового файла поле m_ckIn.cksize класса содержит размер прочитанных данных в байтах — это значение и указываем в поле dwBufferBytes структуры TDSBUFFERDESC. Также необходимо указать формат данных в звуковом файле — ведь запись может быть стерео- или монофонической, с разной частотой дискретизации и т. д. Узнать это DirectSound сможет из поля lpwfxFormat типа TWAVEFORMATEX структуры TDSBUFFERDESC. Его необходимо приравнять к полю m_pwfx класса TWaveSoundRead — оно как раз и содержит эти данные. Здесь я допустил небольшую ошибку в программотехнике — ООП требует, чтобы доступ к данным класса осуществлялся только через методы этого класса — но я просто скопировал реализацию класса из файлов SDK Microsoft.

На случай, если DirectSound не сможет создать буфер заданого размера — например, большая часть памяти звуковой карты или RAM занята — необходимо запомнить реальный размер созданного буфера — он (размер) будет помещён в поле dwBufferBytes той же струтуры, что передавалась в метод IDirectSound8.CreateSoundBuffer().

Итак, буфер создан, теперь необходимо его заполнить звуковыми данными. В этом снова поможет класс TWaveSoundRead. Заполнение буфера данными происходит в функции FillBuffer().

Сперва необходимо прочитать данные из звукового файла. Процедурой GetMem() выделяем облать памяти нужного размера и получаем на неё указатель — переменная pbWavData. Затем записываем данные в память при помощи метода TWaveSoundRead.Read(). Теперь необходимо скопировать данные в буфер DirectSound.

Порядок действий достаточно прост: необходимо заблокировать память буфера, скопировать в него звуковые данные и затем не забыть разблокировать буфер. Блокировка буфера происходит методом IDirectSoundBuffer.Lock(). Первый параметр, dwWriteCursor, показывает, с какой позиции необходимо заблокировать буфер. Позиция представляет собой простое смещение от начала буфера. Если передать 0, то блокировка будет происходить с самого начала буфера. Второй, dwWriteBytes, сообщает размер блокируемой области, он не должен превышать реальный размер буфера. Здесь я передал значение переменной bbytes — в ней хранится реальный размер созданного звукового буфера. Далее необходимо передать адреса двух пар «указатель-размер», в которые метод помещает адреса блокированных областей и их размер. Последний параметр — 0.

Данные в буфер копируются процедурой CopyMemory() — указываем, куда копировать, откуда копировать и сколько копировать :-).

Теперь разблокируем буфер методом IDirectSoundBuffer.Unlock() и удалим область, откуда копировали процедурой FreeMem().

Мы создали звуковой буфер и загрузили в него данные. Вся чёрная работа позади, теперь можно программировать «с удовольствием». Проигрывание данных в буфере осуществляется методом IDirectSoundBuffer.Play(). Первый параметр зарезервирован — нужно указать 0. Второй указывает на приоритет звукового буфера — что это за зверь, я и сам толком не знаю. Значение может меняться от 0 до $FFFFFFFF. Если при создании звукового буфера не указывался флаг DSBCAPS_LOCDEFER, то необходимо передать 0. Последний параметр — комбинация флагов, указывающих способ проигрывания буфера. Для простого проигрывания просто передаём 0, а при цикличном — флаг DSBPLAY_LOOPING. О других можно узнать из SDK.

В окне есть два регулятора TScrollBar. Левый предназначается для изменения громкости звука, второй — для изменения баланса в колонках. Изменение громкости производится методом IDirectSoundBuffer.SetVolume(), единственным параметром которого является значение в интервале от 0 до -10000 — определено константами DSBVOLUME_MAX и DSBVOLUME_MIN. Да-да, изменение громкости звука производится только в сторону приглушения, даже в восьмой версии этот недостаток не устранён :( Изменение баланса в колонках производится методом IDirectSoundBuffer.SetPan(), единственным параметром которого является значение в интервале от 10000 до -10000 — определено константами DSBPAN_LEFT и DSBPAN_RIGHT. Расставьте колонки (если они есть) пошире, запустите пример и попробуйте подвигать скроллбар — слушайте сами. Конечно, это не 3D-эффекты, но зато очень просто.

Теперь самое время заглянуть в файл wavread.pas — если у кого есть желание копаться с указателями, можете поработать с ним. Я не буду описывать его методы, т. к. всё это довольно сложно и требует несколько страниц текста. Этот класс предельно прост, но не он работает с wav-файлами — идёт вызов функций из lowfunc.pas. Эти два файла являются МОИМ переложением с DirectX SDK 7 для C++ — в SDK 8 всё существенно переделано, и как мне кажется, усложнено. Теперь о не слишком приятном. Полагаю, не очень хорошо показывать людям, как работает DirectSound, не разобравшись со всем до конца самому. Проблема в том, что одна из функций из lowfunc.pas не работает, а другая недописана до конца. Я не смог перевести некоторые сложные операции над указателями в контекст языка Object Pascal, поэтому пришлось создать динамическую библиотеку на C++ для работоспособности примера. Если кто-то сможет помочь мне перевести всё на Pascal — буду премного благодарен. Я оставил исходный код из SDK в отдельном каталоге.

I. ОСНОВНЫЕ БОГОСЛОВСКИЕ ПОЛОЖЕНИЯ

I.1. Церковь есть собрание верующих во Христа, в которое Им Самим призывается войти каждый. В ней «все небесное и земное» должно быть соединено во Христе, ибо Он — Глава «Церкви, которая есть Тело Его, полнота Наполняющего все во всем» (Еф. 1. 22-23). В Церкви действием Святого Духа совершается обожение творения, исполняется изначальный замысел Божий о мире и человеке.

Церковь являет результат искупительного подвига Сына, посланного Отцом, и освящающего действия Духа Святого, сошедшего в великий день Пятидесятницы. По выражению святого Иринея Лионского, Христос возглавил Собою человечество, стал Главою обновленного человеческого естества — Его тела, в коем обретается доступ к источнику Святого Духа. Церковь — единство «нового человека во Христе», «единство Божией благодати, живущей во множестве разумных творений, покоряющихся благодати» (А.С.Хомяков). «Мужчины, женщины, дети, глубоко разделенные в отношении расы, народа, языка, образа жизни, труда, науки, звания, богатства… — всех их Церковь воссоздает в Духе… Все получают от нее единую природу, недоступную разрушению, природу, на которую не влияют многочисленные и глубокие различия, которыми люди отличаются друг от друга… В ней никто отнюдь не отделен от общего, все как бы растворяются друг в друге простой и нераздельной силой веры» (святой Максим Исповедник).

I.2. Церковь есть богочеловеческий организм. Будучи телом Христовым, она соединяет в себе два естества – божеское и человеческое – с присущими им действованиями и волениями. Церковь связана с миром по своей человеческой, тварной природе. Однако она взаимодействует с ним не как сугубо земной организм, но во всей своей таинственной полноте. Именно богочеловеческая природа Церкви делает возможным благодатное преображение и очищение мира, совершающееся в истории в творческом соработничестве, «синергии» членов и Главы церковного тела.

Церковь — не от мира сего, так же, как ее Господь, Христос — не от мира сего. Но Он пришел в этот мир, «смирив» Себя до его условий, — в мир, который надлежало Ему спасти и восстановить. Церковь должна пройти через процесс исторического кенозиса, осуществляя свою искупительную миссию. Ее целью является не только спасение людей в этом мире, но также спасение и восстановление самого мира. Церковь призвана действовать в мире по образу Христа, свидетельствовать о Нем и Его Царстве. Члены Церкви призваны приобщаться миссии Христовой, Его служению миру, которое возможно для Церкви лишь как служение соборное, «да уверует мир» (Ин. 17. 21). Церковь призвана служить спасению мира, ибо и Сам Сын Человеческий «не для того пришел, чтобы Ему служили, но чтобы послужить и отдать душу Свою для искупления многих» (Мк. 10. 45).

Спаситель говорит о Себе: «Я посреди вас, как служащий» (Лк 22. 27). Служение во имя спасения мира и человека не может ограничиваться национальными или религиозными рамками, как ясно говорит об этом Сам Господь в притче о милосердном самарянине. Более того, члены Церкви соприкасаются со Христом, понесшим все грехи и страдания мира, встречая каждого голодного, бездомного, больного, заключенного. Помощь страждущим есть в полном смысле помощь Самому Христу, и с исполнением этой заповеди связана вечная судьба всякого человека (Мф. 25. 31-46). Христос призывает Своих учеников не гнушаться миром, но быть «солью земли» и «светом миру».

Церковь, являясь телом Богочеловека Христа, богочеловечна. Но если Христос есть совершенный Богочеловек, то Церковь еще не есть совершенное богочеловечество, ибо на земле она воинствует с грехом, и ее человечество, хотя внутренне и соединено с Божеством, далеко не во всем Его выражает и Ему соответствует.

I.3. Жизнь в Церкви, к которой призывается каждый человек, есть непрестанное служение Богу и людям. К этому служению призывается весь народ Божий. Члены тела Христова, участвуя в общем служении, выполняют и свои особые функции. Каждому дается особый дар для служения всем. «Служите друг другу, каждый тем даром, какой получил, как добрые домостроители многоразличной благодати Божией» (1 Пет. 4. 10). «Одному дается Духом слово мудрости, другому слово знания, тем же Духом; иному вера, тем же Духом; иному дары исцелений, тем же Духом; иному чудотворения, иному пророчество, иному различение духов, иному разные языки, иному истолкование языков. Все же сие производит один и тот же Дух, разделяя каждому особо, как Ему угодно» (1 Кор. 12. 8-11). Дары многоразличной благодати Божией даются каждому отдельно, но для совместного служения народа Божия (в том числе и для служения миру). И это есть общее служение Церкви, совершаемое на основе не одного, а разных даров. Различие же даров создает и различие служений, но «служения различны, а Господь один и тот же; и действия различны, а Бог один и тот же, производящий все во всех» (1 Кор. 12. 5-6).

Церковь призывает своих верных чад и к участию в общественной жизни, которое должно основываться на принципах христианской нравственности. В Первосвященнической молитве Господь Иисус просил Небесного Отца о Своих последователях: «Не молю, чтобы Ты взял их из мира, но чтобы сохранил их от зла… Как Ты послал Меня в мир, так и Я послал их в мир» (Ин. 17. 15,18). Недопустимо манихейское гнушение жизнью окружающего мира. Участие христианина в ней должно основываться на понимании того, что мир, социум, государство являются объектом любви Божией, ибо предназначены к преображению и очищению на началах богозаповеданной любви. Христианин должен видеть мир и общество в свете его конечного предназначения, в эсхатологическом свете Царства Божия. Различение даров в Церкви особым образом проявляется в области ее общественного служения. Нераздельный церковный организм участвует в жизни окружающего мира во всей полноте, однако духовенство, монашествующие и миряне могут по-разному и в разной степени осуществлять такое участие.

I.4. Исполняя миссию спасения рода человеческого, Церковь делает это не только через прямую проповедь, но и через благие дела, направленные на улучшение духовно-нравственного и материального состояния окружающего мира. Для сего она вступает во взаимодействие с государством, даже если оно не носит христианского характера, а также с различными общественными ассоциациями и отдельными людьми, даже если они не идентифицируют себя с христианской верой. Не ставя прямой задачи обращения всех в Православие в качестве условия сотрудничества, Церковь уповает, что совместное благотворение приведет ее соработников и окружающих людей к познанию Истины, поможет им сохранить или восстановить верность богоданным нравственным нормам, подвигнет их к миру, согласию и благоденствию, в условиях которых Церковь может наилучшим образом исполнять свое спасительное делание.

 

 

еще рефераты
Еще работы по истории