Информация о програмировании может быть полезна.

Наша фирма дружит с такими сайтами как Яндекс , Лимит и сайт под названием GamesKrutomer.ru.

1.6. Встроенные функции самоконтроля (self-test) Практически с момента появления стандарта S.M.A.R.T. II, в большинстве накопителей появилась новая функция - внутренняя диагностика и самоконтроль, для углубленного контроля состояния механики накопителя, поверхности дисков и т.п. Для запуска этой функции, в набор команд S.M.A.R.T. была введена новая команда - SMART EXECUTE OFF-LINE IMMEDIATE. Результат работы сохраняется либо в специализированных атрибутах, либо отдельным параметром среди других данных в атрибутах. Если накопитель поддерживает журналы S.M.A.R.T., то результат выполнения тестов сохраняется также в журнале Self-test Log. После выполнения теста, накопитель в обязательном порядке обновляет показания во всех атрибутах и других параметрах. Если во время выполнения внутреннего теста накопитель получит по интерфейсу новую команду, то выполнение теста прерывается и накопитель приступает к обработке поступившей команды. 1.6.1. Методы тестирования Существует два способа запуска тестов S.M.A.R.T.: автономный (off-line) или монопольный (captive). Результат теста всегда сохраняется накопителем в данных S.M.A.R.T.. При автономном запуске накопитель сообщает о успешном завершении команды ДО ее ФАКТИЧЕСКОГО исполнения и только после этого выполняет тест. При этом, по интерфейсу флаг ЗАНяТО (BSY) не выставляется и накопитель в любой момент готов приступить к выполнению очередной интерфейсной команды, приостанавливая работу теста. Фактически, тест выполняется в фоновом режиме. При запуске теста в монопольном режиме, по интерфейсу выставляется флаг ЗАНяТО (BSY) и накопитель начинает непосредственное выполнение теста в режиме реального времени. Любая интерфейсная команда во время выполнения этого теста приведет к его прерыванию и остановке, после чего накопитель приступит к обработке поступившей команды. 1.6.2. Разновидности тестов S.M.A.R.T. Официально документированы три вида внутренних тестов, однако еще существует набор так называемых "активных" тестов, функциональные особенности которых различны у разных производителей и для широкой публики не документированы. № Название теста off-line captive 1 Off-line collection + - 2 Short Self-test + + 3 Extended Self-test + + 4 Drive Activity test #1..#4 + + Время тестирования может варьироваться от 1 секунды (Quantum) до 54 минут (Fujitsu MPG3409AT). Поддержка первого теста наиболее вероятна даже в очень старых накопителях 4-5 летней давности. Второй и третий тесты появились относительно недавно, как дань внедренным сложным технологическим решениям - для полного контроля состояния накопителя пришлось реализовывать более глубокие и точные тесты. Поддержка 4-х "активных" тестов (см. таблицу, п.4) официально не документированна. Реальный набор выполняемых тестами функций можно рассмотреть на примере тестов, поддерживаемых жесткими дисками Hitachi: Функция теста Short Self test Extended Self test Off-line Collection Raw Read Error Rate Test YES YES YES Write Test YES YES NO Servo Test YES YES NO Partial Read Scanning YES NO NO Full Read Scanning NO YES YES Источник: PC JUNGLE SOFTWARE

Особенности программирования DirectX графики для видео карт nVidia (по материалам nVidia) Интро Сегодня в эру Multimedia трудно создать качественный продукт без применения современных технологий. Если для обычных офисных приложений достаточно стандартного интерфейса, а навороченный даже мешает, то для всякого рода плееров скины стали уже неписаным стандартом. Так же и программы трёхмерной графики - если ранее вполне достаточно было создать "впечатление" трёхмерности, то сейчас почти все претендуют на "фотографическое качество". На фоне всего этого необходимо отметить постоянно повышающуюся производительность видео карт и аппаратную поддержку всё большего количества операций. На сегодняшний день существует две "стандартные" библиотеки работы с 3D графикой. Microsoft DirectX и Silicon Graphics OpenGL. Это высокоуровневые, аппаратно независимые средства. С одной стороны они предоставляют доступ к 3D ускорению, а с другой не привязывают к конкретной железке. Конечно же жалко неправильно их использовать, искусственно понижая производительность видео карты. В связи с этим хочу представить перевод (немного вольный и дополненный собственным опытом) официального руководства nVidia (мамы/папы знаменитых Riva TNT 1/2, GeForce 1/2/3) по программированию графики с использованием графики DirectX. Итак, ваша программа работает медленно... Что значит медленно? Если у вас прорисовывается меньше 3000-10000 полигонов в секунду, то это медленно. Либо у вас может быть видео карта без 3D ускорения, но это не предмет данной статьи. Поэтому, далее предполагается, что у вас приличный 3D ускоритель есть! Возможные проблемы Profiling показал, что это ваша программа. Скорее всего, ваша программа что-то делает плохо... Или вы пытаетесь рисовать слишком часто... Или вы делаете то, что за вас и так делает драйвер, например отсечение или трансформации... Никогда не трансформируйте вертексы сами. Желательно, так же, рисовать индексированные полигоны, так как при этом количество трансформируемых вертексов может быть в несколько раз меньше. Profiling показал, что это драйвер. Значит, у вас хорошая программа :-). Либо вы неправильно используете методы Lock, неправильно используете VertexBuffer-ы, у вас очень простая программа, где нет ничего существенного кроме рисования (как многие примеры из DirectX SDK). Возможно так же что это особенности драйвера. Неплохо было бы (если все остальные рекомендации соблюдены) проверить программу на другой видео карте и других драйверах. Не используйте стандартные драйвера от Microsoft. Нередко они имеют ту же версию что и драйвера nVidia, но не поддерживают аппаратное ускорение. Возможно это код инициализации рисования кадра. Следующие методы должны вызываться как можно реже: ValidateDevice, CreateVertexBuffer, Optimize, CreateStateBlock. Рисование кадра выполняется минимум 20-25 раз в секунду, а это - методы распределения видео памяти и, следовательно, их применение будет по времени накладным. Нельзя однозначно сказать что лучше сразу загрузить всё в видео память или загружать помаленьку. Можно поступить так: Не загружать ничего во время рисования кадра, загружать между кадрами. Неплохо также разбить одну большую 3D сцену на несколько поменьше. В Quake например так ходишь между уровнями. Не используйте Stencil буфер, если он вам не нужен. Если вы очищаете только Z-буфер, то DirectX вынужден сохранять содержимое Stencil буфера, даже если он вам не нужен и вы его не используете. Вместо "тупой" записи значений, для каждого пикселя выполнятся цикл чтение/изменение/запись (mov mem,reg/or reg,reg/mov reg,mem). Причём это, в отличие от полной очистки, как правило, реализуется программно. Никогда не очищайте экран рисованием полигонов! Это не лучший способ, так как вы не сможете корректно очистить z-буфер. Не рисуйте никогда то, что не должно быть видно! Попытайтесь по возможности сократить количество полигонов отсылаемых вами для прорисовки. Отсекайте (просто не рисуйте) то, что сзади, то, что к вам задней (то есть невидимой) стороной, то, что слишком далеко. Если текстуры высококачественные, то создавайте для них MipMap. Есть много алгоритмов отсечения невидимых частей. Для начала, было бы неплохо включить какой-нибудь простой алгоритм отсечения того, что сзади. Затем неплохо было бы использовать какой-нибудь алгоритм умной прорисовки сцены такой, как например BSP деревья. Не используйте большое количество Pixel/Vertex Shader-ов (от 4-х). Это может быть гораздо медленнее, чем простая смена текстуры. И вообще не факт, что это поддерживается аппаратно вашей видео картой. Не рисуйте полигоны из системной памяти, используйте VertexBuffer для всего. Нет практически ни одного случая, когда рисование без использования VertexBuffer могло привести к хорошим результатам. Изменение производительности, наблюдавшееся мной, достигало 250 раз! Используйте также IndexBuffer и вообще чем более "видео", та память в которой у вас данные, тем лучше. Вы используете D3DLOCK_DISCARD и D3DLOCK_NOOVERWRITE неправильно. Не используйте оба флага одновременно - будет использован D3DLOCK_NOOVERWRITE. Как правило, вам нужен D3DLOCK_NOOVERWRITE. На самом деле, вам это не нужно, поскольку модифицировать VertexBuffer во время рисования очень, очень плохо. Заполняйте VertexBuffer с нулевого вектора и далее, пока он не будет заполнен. Не оставляйте промежутков! Не используйте маленькие (меньше 100 вертексов) и большие (больше 25000 вертексов) буферы. В маленький всё равно ничего серьёзного не влезет, да и рисовать его отдельно не очень хорошо. А большой трудно полностью, без промежутков, заполнить. Если вы используете z-буфер, То у него должна быть та же глубина что и у цвета, тот же размер что и у Render Target Surface. Для оконных приложений размер Render Target это, как правило, размер клиентской части окна, для полноэкранных - разрешение. То есть если у вас 32-х битный цвет, то и z-буфер желательно иметь тоже 32-х битный. Если у вас окно 546 на 234 то и z-буфер надо иметь такой же. Естественно, что для оконного режима это не столь существенно. Не рисуйте слишком сложные модели Не пытайтесь рисовать в реальном времени модели 3D редакторов, которые хорошо смотрятся только после 5-10 минутного рендеринга. Всегда помните - то, что вы пишите, хоть в минимальной конфигурации, должно запускаться на практически любой машине. Неплохо использовать несколько уровней качества прорисовки для аппаратуры разной мощности. Очень неплохо использовать в тех же целях модели разной детализации. Не используйте GDI. Никогда не используйте GDI, особенно для рисования текста и Bitmap-ов. Не рисуйте текст по буквам. Если уж очень приспичило рисуйте заранее (до основного цикла) в буферный surface, а потом копируйте. Или вообще храните шрифт в виде растра в файле. Несколько забавно когда с помощью GDI пытаются выводить количество кадров в секунду. От того что вы начали писать на экране с помощью GDI нечто наподобие 12.8fps, этот самый fps падает в несколько раз... Не используйте W-буфер. Он, как правило, программный, и не может быть использован вместе с кубическими текстурами. Кстати о них, все не плоские текстуры лучше тоже не использовать. Не используйте Texture BumpMap. Он аппаратно не поддерживается даже GeForce3, не говоря уже об S3. И вообще не очень реалистично выглядит, как будто поверхность пластиковая. Даже не представляю где он может понадобится. Добиться выпуклости за счёт увеличения числа полигонов гораздо быстрее и красивее. Если хотите хитро что-либо с чем-либо смешать. Используйте альфа-канал и не используйте COLORKEY. Альфа-канал очень хорошая вещь, если ею умело пользоваться. Например можно заполнять значение альфа-канала исходя из RGB значений того же пикселя. Это для многих изображений можно сделать заранее, например для всех спрайтов. А блиттинг с учётом альфа-канала на многих картах уже аппаратно поддерживается. Рисуйте минимум по 50-60 полигонов. Лучше по 200-10000. Никогда не посылайте на отрисовку 1-10 полигонов. Лучше их не нарисовать. Никогда не посылайте рисоваться столь малое количество полигонов. Освобождайте всё что только можно. Чем больше видео памяти свободно, тем лучше. Особенно если используется много текстур. В принципе DirectX сам распределяет всю память, за исключением surface-ов, а они-то и забирают львиную долю. Поэтому нещадно выгружайте и удаляйте всё что только можете. Метод Release должен стать вашим другом. Работайте на максимальной частоте обновления монитора. Помните, она теперь зачастую превышает 60 герц. Для современных мониторов она доходит и до 120/140 герц и выше. Это не только улучшит качество изображения но и позволит сделать более незаметными артефакты возникающие если вы не ждёте обратного хода луча. Редко меняйте текстуры и VertexBuffer. Когда вы устанавливаете текущую текстуру или VertexBuffer, то они, как правило, загружаются в видео память, а эта загрузка может занять много времени. Менять текстуры хуже, чем VertexBuffer, поэтому лучше все полигоны отсортировать по текстурам а потом по VertexBuffer-ам или даже не хранить в одном VertexBuffer-е вертексы полигонов с разными текстурами. Старайтесь не рисовать подряд полигоны с разным форматом вертекса. На большинстве карт не очень критично, но всё же заметно. Рекомендуется также не создавать в вертексе неиспользуемые поля. Не используйте LOCALVIEWER. Впрочем, это уже дело хозяйское, так сказать... За красоту надо платить. Кстати говоря постарайтесь не просчитывать в каждом кадре те части сцены, которые можно просчитать заранее. Это, например, освещение от статических источников света. Всегда используйте WRITEONLY/READONLY флаги. Это сократит временные расходы на компрессию/декомпрессию при записи/чтении VertexBuffer-ов и surface-ов если они не в заявленном формате (специфический для данной видеокарты). Так как отследить подобные случаи нельзя, лучше использовать Эти флаги всегда. Обычно основной цикл пишется так:while (continueMainLoop) { Physics_Of_The_Scene(); Some_AI_Or_Another_Scene_Changing(); Render_Triangles(); Copy_Back_Buffer(); Wait_Till_Time_For_One_Frame_Expired(); } А должен так: while (continueMainLoop) { Physics_Of_The_Scene(); Some_AI_Or_Another_Scene_Changing(); Wait_Till_Time_For_One_Frame_Expired(); Render_Triangles(); Copy_Back_Buffer(); } Не читайте из видео памяти. Это очень медленно даже на AGP видео картах. Процесс чтения из видеопамяти может занимать в 2-10 раз больше времени чем запись в неё. В заключение хотелось бы сказать что Direct3D это в основном средство рендеринга в играх и подобных им программах. Его использование в них весьма удобно так как в состав DirectX входят также DirectSound, DirectMusic, DirectInput, а начиная с восьмой версии DirectShow. Подобное сочетание позволяет полностью построить работоспособное приложения на основе одной группы библиотек. Безусловно что в системах научной, высокоточной графики первенство остаётся за мультиплатформенным OpenGL.

В этом небольшом, но очень увлекательном уроке мы с вами научимся перекрашивать здание небоскреба из его естественного металлического цвета в золотистые оттенки. Немного большое получилось вступление, ну ничего, дальше вы все сами поймете. Итак, приступим. Шаг 1. Откройте фотографию какого-нибудь небоскреба Шаг 2. Из верхнего меню программы выбираем Layer -> New Adjustment Layer -> Color Balance... В появившемя окошке можете назвать этот слой как-нибудь, но это необязательно. Жмем "ОК" и перед нами появится вот такое окошко, в котором последовательно измените значения уровней цвета. Как видите, для каждого Tone Balance (внизу) свои настройки. Шаг 3. Сейчас мы выделили только небо и маску, которая была изменена выше. Нажмите на глазок возле названия слоя в палитре Layers (имя слоя - Color Balance1). Когда глазок исчезнет, то и слоя также не будет видно. Теперь нажмите на фоновый слой (снизу в списке слоев), выберите инструмент Magic wand tool (или нажмите W), параметр Tolerance ставим 15, отмечаем Anti-alias, Contiguous и Sample (Use) all layer. Теперь нажимаем волшебной палочкой на небо, затем на клавишу Shift и начинаем кликать по всей площади неба, чтобы внутри его не было выделенных участков. Т.е. нам нужно выделить небо лишь по краям фотографии и здания. Шаг 4. Когда вы это сделаете, жмете опять на иконку глазка в слева от названия слоя. Наш фон неба снова появится, он будет темноватым. Теперь выделите наш слой (верхний), просто нажав на него в палитре слоев, нажмите D и потом Del. И вот о чудо - наш фон (небо) вновь стало синим, при этом здание так и осталось позолоченным. Шаг 5. Теперь нам осталось убрать выделение. Для этого нажмите комбинацию Ctrl + D. Вот и все - можете наслаждаться результатом!

В этой статье я вам расскажу, как в графическом редакторе photoshop можно изменить цвет волос на фотографии. Как правило, для изменения цвета в фотошоп достаточно инструмента Hue/Saturation и у нас получется задуманное нами. Но вот что нам делать, если мы желаем изменить коричневые/черные волосы в белые. В данном случае Hue/Saturation нам не сильно поможет, поскольку у нас получится неестественный цвет и шумы в придачу. А для того, чтобы изменить коричневый цвет волос на белый (светлый) я использую несколько методов. Шаг 1. Откройте фотографию, можете загрузить мою Шаг 2. Скопируем фон изображения (background) методом нажатия Ctrl + J на клавиатуре. Назовем этот слой "copy". Шаг 3. А вот это один из самых важных шагов в этой статье. Здесь мы должны отделить волосы модели от фона изображения. В зависимости от фотографии, для этого можно использовать несколько методов ( color, Photoshop's Extract filter, channels....). Мы же будем использвать каналы (channels...). Заходите в меню Image -> Calculations и установите значения переменных, как указано ниже: Теперь на палитре Channels (если ее нет у вас на экране, выберите ее из Window -> Channels) вы можете увидеть новый канал Alpha 1. Нажмите на нем и потом опять нажмите Ctrl + L на клавиатуре. У вас должно появится диалоговое окно Levels. Используя эти Levels, мы можем изменить количество серого на фото. Установите на этом окне следующие параметры: А сейчас с помощью инструмента кисточка (Brush Tool, B) выберите белый цвет и закрасте на фото все кроме волос. Это очень деликатная работа, но чем точнее вы выделите волосы, тем более естественной будет наше перекрашивание. Лично у меня вот что получилось: Шаг 4. Теперь, когда мы выделили волосы, можно начать их разукрашивать. Если вы до сих пор находитесь на палитре Channels, то нажмите и удерживайте Ctrl и левую клавишу мышки. Затем кликните на нашем Alpha 1 канале. В результате этого наши волосы должны выделиться контуром, которые еще называют "муравьиной тропой". Теперь в меню Channels нажмите на RGB channel и кликните на палитру слоев (Layers). Выберите слой "copy" и найдите в верхнем меню программы -> Invers и нажмите Ctrl + J, чтобы скопировать выделенные волосы в новый слой. Назовем его "hair". Шаг 5. Теперь нам осталось поработать с волосами, поэтому уберите значок газка против других слоев. Применим фильтр Filter -> Blur -> Gaussian blur и установите такие значения: Шаг 6. Сейчас мы будем изменять цвет волос. Выберите команду Image -> Adjustments -> Variations. В этом диалогом окне нас интересует только More Yellow и Lighter. Далее нажимаем на Shadows и кликаем дважды на More Yellow и также дважды на Lighter. Затем идут Midtones, Highlights - также кликаем дважды на More Yellow и Lighter в каждом из них. Выходим из этого окошка и выбираем в свойствах слоя (правый клик по слою "hair") и выбираем Blending Options -> Blending mode -> Screen и ставим параметр opacity в 80%. Шаг 7. Выбираем команду Create new adjustment -> Curves. Ну а дальше делайте, как на рисунках ниже: Параметр слоя Blending mode установите в Vivid Light и прозрачность opacity в 40%. А вот и финальное фото: Также можете поэкспериментировать с фотографией модели Eva Longoria: Удачи!

Нарисуем почтовую марку В этом руководстве я вам расскажу, как из фотографии сделать симпатичную почтовую марку. Шаг 1. Открываем нашу фотографию. В нашем случае это будет такой вот симпатичный VW Жук. Шаг 2. В данном случае важную роль играет пропорция. Для того, чтобы получились красивые края, мы должны выбрать идеальную пропорцию между шириной и высотой рисунка. Для этого выберем форму нашей кисточки - выберите инструмент Brush tool (можно нажать B). Выберите параметры кисточки, как у меня на картинке. Размер кисточки 20px, spacing 120%. Это сделает размер кисточки 24px. Нажмите Create new brush и задайте имя новой кисточке: Шаг 3. Сейчас выберите инструмент Marquee tool (M) и установите параметр Style в Fixed Size и введите число 768px для Width и 528px для Height. Почему именно такие значения ширины и высоты? Как было сказано в шаге 2, наша кисточка имеет ширину 24px, поэтому 24*32=768px и 24*22=528px. Теперь просто кликните на фото, выберите область выделения для нашей будущей марки, используем команду Image -> Crop и жмем ОК. Шаг 4. Скопируйте слой фона ("background" layer) нажатием Ctrl + J. Назовите новый слой "postal_mark". Теперь нам нужно изменить размеры марки. Нажимаете Ctrl + Alt + C и вводите значения как на рисунке ниже: Создайте новый слой и назовите его "white". Разместите его под слоем "postal_mark" и уже можно удалить слой фона ("Background"). Выбираем инструмент Paint Bucket tool (G) и заливаем слой "white" белым цветом. Шаг 5. Выберите инструмент резинка (Eraser tool) и кисточку, которую мы создали в шаге 2. Шаг 6. Нажимаем и удерживаем клавишу Ctrl на клавиатуре и нажимаем на слой "postal_mark". Так мы выделим весь слой. Сейчас кликните на палитру Paths и выберите Make work path ion Сейчас наше выделение превратится в контур (Path). Кликните на стрелочку вверху угла палитры Paths и выберите Stroke Path. Выберите инструмент Eraser tool и снимите галочку с Simulate pressure. Жмем OK и del для удаления контура (Path). Шаг 7. Выбираем инструмент Marquee tool и делаем выделение внутри слоя "postal_mark". Сделайте эту дистанцию равной от краев слоя. Инвертируйте выделение ( - Invert ion), выберите инструмент Magic Wand tool, нажмите и удерживайте ALT и кликайте на белой поверхности внутри выдленного контура. Это позволит нам выделить только края. Залейте выделение белым цветом (Ctrl + Backspace). Шаг 8. Снимите выделение нажав Ctrl + D. Сделайте правый клик на слое "postal_mark" и выберите Blending options. Установите значения согласно рисунку: Шаг 9. Напоследок вы можете добавить свой текст на вот такую замечательную марку:

Обратная связь

Имя отправителя *:
E-mail отправителя *:
Тема письма:
Текст сообщения *:
Код безопасности *:

S.M.A.R.T. (Self-Monitoring, Analysis and Reporting Technology) Страница 4. Типы атрибутов 1.3.4. Типы атрибутов. Каждый атрибут может иметь некоторый набор флагов, определяющих его функциональные особенности. Ниже приводятся все шесть основных типов и их краткие описания. Pre-failure (PF). Если атрибут имеет этот тип, то поле threshold атрибута содержит минимально допустимое значение атрибута, ниже которого не гарантируется работоспособность накопителя и резко увеличивается вероятность его выхода из строя. On-line collection (OC). Указывает, что значение данного атрибута обновляется (вычисляется) во время выполнения on-line тестов S.M.A.R.T. или же во время обоих видов тестов (on-line/off-line). В противном случае, значение атрибута обновляется только при выполнении off-line тестов. Performance related (PR). Указывает на то, что значение этого атрибута напрямую зависит от производительности накопителя по отдельным показателям (seek/throughput/etc. performance). Обычно обновляется после выполнения self-test`ов SMART. Error rate (ER). Указывает на то, что значение атрибута отражает относительную частоту ошибок по данному параметру (raw read/write, seek, etc.). Events count (EC). Указывает на то, что атрибут является счетчиком событий. Self-preserve (SP). Указывает на то, что значение атрибута обновляется и сохраняется автоматически (обычно при каждом старте накопителя и при выполнении тестов SMART).

Это - библиотека диспетчера Microsoft DirectX, чтобы оптимизировать графы и звуковые представления для Windows. Диспетчеры - жизненные элементы для большинства видеоигр например. Они также помогают, если Вы обычно взаимодействуете с мультимедийными действиями. DirectX включает в его новую версию способность контроля с 3-ьими графами, особенность, которая продвигает outstandingly. Это стоит упоминать, что, изменяя его установку, выполненные компоненты не могут быть неустановлены, поскольку они изменяют основные компоненты в системе и создают большие модификации в ее регистре.

Особенности программирования DirectX графики для видео карт nVidia (по материалам nVidia)
Интро

Сегодня в эру Multimedia трудно создать качественный продукт без применения современных технологий. Если для обычных офисных приложений достаточно стандартного интерфейса, а навороченный даже мешает, то для всякого рода плееров скины стали уже неписаным стандартом. Так же и программы трёхмерной графики - если ранее вполне достаточно было создать "впечатление" трёхмерности, то сейчас почти все претендуют на "фотографическое качество". На фоне всего этого необходимо отметить постоянно повышающуюся производительность видео карт и аппаратную поддержку всё большего количества операций. На сегодняшний день существует две "стандартные" библиотеки работы с 3D графикой. Microsoft DirectX и Silicon Graphics OpenGL. Это высокоуровневые, аппаратно независимые средства. С одной стороны они предоставляют доступ к 3D ускорению, а с другой не привязывают к конкретной железке. Конечно же жалко неправильно их использовать, искусственно понижая производительность видео карты. В связи с этим хочу представить перевод (немного вольный и дополненный собственным опытом) официального руководства nVidia (мамы/папы знаменитых Riva TNT 1/2, GeForce 1/2/3) по программированию графики с использованием графики DirectX.

Итак, ваша программа работает медленно... Что значит медленно? Если у вас прорисовывается меньше 3000-10000 полигонов в секунду, то это медленно. Либо у вас может быть видео карта без 3D ускорения, но это не предмет данной статьи. Поэтому, далее предполагается, что у вас приличный 3D ускоритель есть!
Возможные проблемы
Profiling показал, что это ваша программа.

Скорее всего, ваша программа что-то делает плохо... Или вы пытаетесь рисовать слишком часто... Или вы делаете то, что за вас и так делает драйвер, например отсечение или трансформации... Никогда не трансформируйте вертексы сами. Желательно, так же, рисовать индексированные полигоны, так как при этом количество трансформируемых вертексов может быть в несколько раз меньше.
Profiling показал, что это драйвер.

Значит, у вас хорошая программа :-). Либо вы неправильно используете методы Lock, неправильно используете VertexBuffer-ы, у вас очень простая программа, где нет ничего существенного кроме рисования (как многие примеры из DirectX SDK). Возможно так же что это особенности драйвера. Неплохо было бы (если все остальные рекомендации соблюдены) проверить программу на другой видео карте и других драйверах. Не используйте стандартные драйвера от Microsoft. Нередко они имеют ту же версию что и драйвера nVidia, но не поддерживают аппаратное ускорение.
Возможно это код инициализации рисования кадра.

Следующие методы должны вызываться как можно реже: ValidateDevice, CreateVertexBuffer, Optimize, CreateStateBlock. Рисование кадра выполняется минимум 20-25 раз в секунду, а это - методы распределения видео памяти и, следовательно, их применение будет по времени накладным. Нельзя однозначно сказать что лучше сразу загрузить всё в видео память или загружать помаленьку. Можно поступить так: Не загружать ничего во время рисования кадра, загружать между кадрами. Неплохо также разбить одну большую 3D сцену на несколько поменьше. В Quake например так ходишь между уровнями.
Не используйте Stencil буфер, если он вам не нужен.

Если вы очищаете только Z-буфер, то DirectX вынужден сохранять содержимое Stencil буфера, даже если он вам не нужен и вы его не используете. Вместо "тупой" записи значений, для каждого пикселя выполнятся цикл чтение/изменение/запись (mov mem,reg/or reg,reg/mov reg,mem). Причём это, в отличие от полной очистки, как правило, реализуется программно. Никогда не очищайте экран рисованием полигонов! Это не лучший способ, так как вы не сможете корректно очистить z-буфер.
Не рисуйте никогда то, что не должно быть видно!

Попытайтесь по возможности сократить количество полигонов отсылаемых вами для прорисовки. Отсекайте (просто не рисуйте) то, что сзади, то, что к вам задней (то есть невидимой) стороной, то, что слишком далеко. Если текстуры высококачественные, то создавайте для них MipMap. Есть много алгоритмов отсечения невидимых частей. Для начала, было бы неплохо включить какой-нибудь простой алгоритм отсечения того, что сзади. Затем неплохо было бы использовать какой-нибудь алгоритм умной прорисовки сцены такой, как например BSP деревья.
Не используйте большое количество Pixel/Vertex Shader-ов (от 4-х).

Это может быть гораздо медленнее, чем простая смена текстуры. И вообще не факт, что это поддерживается аппаратно вашей видео картой.
Не рисуйте полигоны из системной памяти, используйте VertexBuffer для всего.

Нет практически ни одного случая, когда рисование без использования VertexBuffer могло привести к хорошим результатам. Изменение производительности, наблюдавшееся мной, достигало 250 раз! Используйте также IndexBuffer и вообще чем более "видео", та память в которой у вас данные, тем лучше.
Вы используете D3DLOCK_DISCARD и D3DLOCK_NOOVERWRITE неправильно.

Не используйте оба флага одновременно - будет использован D3DLOCK_NOOVERWRITE. Как правило, вам нужен D3DLOCK_NOOVERWRITE. На самом деле, вам это не нужно, поскольку модифицировать VertexBuffer во время рисования очень, очень плохо.
Заполняйте VertexBuffer с нулевого вектора и далее, пока он не будет заполнен.

Не оставляйте промежутков! Не используйте маленькие (меньше 100 вертексов) и большие (больше 25000 вертексов) буферы. В маленький всё равно ничего серьёзного не влезет, да и рисовать его отдельно не очень хорошо. А большой трудно полностью, без промежутков, заполнить.
Если вы используете z-буфер,

То у него должна быть та же глубина что и у цвета, тот же размер что и у Render Target Surface. Для оконных приложений размер Render Target это, как правило, размер клиентской части окна, для полноэкранных - разрешение. То есть если у вас 32-х битный цвет, то и z-буфер желательно иметь тоже 32-х битный. Если у вас окно 546 на 234 то и z-буфер надо иметь такой же. Естественно, что для оконного режима это не столь существенно.
Не рисуйте слишком сложные модели
Не пытайтесь рисовать в реальном времени модели 3D редакторов, которые хорошо смотрятся только после 5-10 минутного рендеринга. Всегда помните - то, что вы пишите, хоть в минимальной конфигурации, должно запускаться на практически любой машине. Неплохо использовать несколько уровней качества прорисовки для аппаратуры разной мощности. Очень неплохо использовать в тех же целях модели разной детализации.
Не используйте GDI.

Никогда не используйте GDI, особенно для рисования текста и Bitmap-ов. Не рисуйте текст по буквам. Если уж очень приспичило рисуйте заранее (до основного цикла) в буферный surface, а потом копируйте. Или вообще храните шрифт в виде растра в файле. Несколько забавно когда с помощью GDI пытаются выводить количество кадров в секунду. От того что вы начали писать на экране с помощью GDI нечто наподобие 12.8fps, этот самый fps падает в несколько раз...
Не используйте W-буфер.

Он, как правило, программный, и не может быть использован вместе с кубическими текстурами. Кстати о них, все не плоские текстуры лучше тоже не использовать.
Не используйте Texture BumpMap.

Он аппаратно не поддерживается даже GeForce3, не говоря уже об S3. И вообще не очень реалистично выглядит, как будто поверхность пластиковая. Даже не представляю где он может понадобится. Добиться выпуклости за счёт увеличения числа полигонов гораздо быстрее и красивее.
Если хотите хитро что-либо с чем-либо смешать.

Используйте альфа-канал и не используйте COLORKEY. Альфа-канал очень хорошая вещь, если ею умело пользоваться. Например можно заполнять значение альфа-канала исходя из RGB значений того же пикселя. Это для многих изображений можно сделать заранее, например для всех спрайтов. А блиттинг с учётом альфа-канала на многих картах уже аппаратно поддерживается.
Рисуйте минимум по 50-60 полигонов.

Лучше по 200-10000. Никогда не посылайте на отрисовку 1-10 полигонов. Лучше их не нарисовать. Никогда не посылайте рисоваться столь малое количество полигонов.
Освобождайте всё что только можно.

Чем больше видео памяти свободно, тем лучше. Особенно если используется много текстур. В принципе DirectX сам распределяет всю память, за исключением surface-ов, а они-то и забирают львиную долю. Поэтому нещадно выгружайте и удаляйте всё что только можете. Метод Release должен стать вашим другом.
Работайте на максимальной частоте обновления монитора.

Помните, она теперь зачастую превышает 60 герц. Для современных мониторов она доходит и до 120/140 герц и выше. Это не только улучшит качество изображения но и позволит сделать более незаметными артефакты возникающие если вы не ждёте обратного хода луча.
Редко меняйте текстуры и VertexBuffer.

Когда вы устанавливаете текущую текстуру или VertexBuffer, то они, как правило, загружаются в видео память, а эта загрузка может занять много времени. Менять текстуры хуже, чем VertexBuffer, поэтому лучше все полигоны отсортировать по текстурам а потом по VertexBuffer-ам или даже не хранить в одном VertexBuffer-е вертексы полигонов с разными текстурами.
Старайтесь не рисовать подряд полигоны с разным форматом вертекса.

На большинстве карт не очень критично, но всё же заметно. Рекомендуется также не создавать в вертексе неиспользуемые поля.
Не используйте LOCALVIEWER.

Впрочем, это уже дело хозяйское, так сказать... За красоту надо платить. Кстати говоря постарайтесь не просчитывать в каждом кадре те части сцены, которые можно просчитать заранее. Это, например, освещение от статических источников света.
Всегда используйте WRITEONLY/READONLY флаги.

Это сократит временные расходы на компрессию/декомпрессию при записи/чтении VertexBuffer-ов и surface-ов если они не в заявленном формате (специфический для данной видеокарты). Так как отследить подобные случаи нельзя, лучше использовать Эти флаги всегда.
Обычно основной цикл пишется так:while (continueMainLoop)
{
Physics_Of_The_Scene();
Some_AI_Or_Another_Scene_Changing();
Render_Triangles();
Copy_Back_Buffer();
Wait_Till_Time_For_One_Frame_Expired();
}


А должен так: while (continueMainLoop)
{
Physics_Of_The_Scene();
Some_AI_Or_Another_Scene_Changing();
Wait_Till_Time_For_One_Frame_Expired();
Render_Triangles();
Copy_Back_Buffer();
}

Не читайте из видео памяти.

Это очень медленно даже на AGP видео картах. Процесс чтения из видеопамяти может занимать в 2-10 раз больше времени чем запись в неё.

В заключение хотелось бы сказать что Direct3D это в основном средство рендеринга в играх и подобных им программах. Его использование в них весьма удобно так как в состав DirectX входят также DirectSound, DirectMusic, DirectInput, а начиная с восьмой версии DirectShow. Подобное сочетание позволяет полностью построить работоспособное приложения на основе одной группы библиотек. Безусловно что в системах научной, высокоточной графики первенство остаётся за мультиплатформенным OpenGL.

Q. Нужен ли мне DirectX 8.0? A. Как правило, любая программа, использующая DirectX, устанавливает ту версию DirectX, которая необходима ей для работы (если, конечно, она у вас прежде не была установлена). Поэтому нет необходимости загружать DirectX 8.0 только для того, чтобы ваши уже работающие программы работали и дальше. Но новые функциональные возможности, заложенные в DirectX 8.0, могут улучшить работу ваших программ. Кроме того, многие демо-версии игр не включают в себя DirectX, поэтому DirectX 8.0 вам может понадобиться для нормального воспроизведения новейших программ. Q. Почему столь много игр требуют наличия DirectX? A. DirectX - это та основа, на которой строится работа многих игр. Подробнее о DirectX можете прочитать здесь. Q. Где я могу найти новейшую версию DirectX? A. Новейшую версию DirectX всегда можно найти на вебсайте Microsoft. Q. Какие операционные системы поддерживают DirectX 8.0? A. DirectX 8.0 может быть установлен на следующие ОС: Windows 95 (все версии) Windows 98 Windows 98 Second Edition Windows Millennium Edition Windows 2000 Professional и Server Q. Совмести м ли DirectX с Windows NT 4.0? A. Да. Но единственная версия, которую поддерживает Windows NT 4.0, это DirectX 3.0a. Кроме того, вам необходимо установить Windows NT 4.0 Service Pack 6. Q. Где найти Windows NT 4.0 Service Pack 6? A. Windows NT Service Pack 6 можно найти здесь. Q. Может ли инсталяция DirectX 8.0 привести к потере работоспособности уже установленных программ? A. Мы всегда проводим тестирование совместимости с DirectX большого количества ранее выпущенных и готовящихся к выходу программ. Лишь в очень редких случаях некоторые программы жестко связаны с определенной версией DirectX. И практически всегда подобные программы обновляются таким образом, чтобы обеспечить поддержку новейшей версии DirectX. Q. Я ищу предыдщие версии DirectX, но не могу их найти. Где они? A. С выходом DirectX 8.0 мы прекращаем поддержку предыдущих версий DirectX. Q. Иногда я получаю сообщение, что мои драйверы устарели. Что следует предпринять? A. В большинстве случаев DirectX будет работать корректно, но без поддержки аппаратного ускорения. И не забудьте проверить, не обновил ли драйверы производитель вашего компьютера, видео- или звуковой карты для обеспечения более полной поддержки DirectX. Q. Где я могу найти новейшие драйверы для моей аудио- и видеокарт? A. DirectX 8.0 не содержит никаких ни аудио- ни видеодрайверов. Посетите вебсайт производителя используемой вами карты или вебсайт Windows Hardware Compatibility. Q. Существуют ли неанглийские версии DirectX? A. Кроме английской, DirectX локализован на 14 языках - немецком, японском, испанском, французском, итальянском, портунальском, чешском, польском, русском, шведском, голландском, корейском и китайском языках. Для всех других языков следует использовать английскую версию. Q. Я знаю, что существует Панель управления DirectX, но после инсталяции я ее не могу найти. Где она? A. Панель управления DirectX - это часть инструментария (SDK), используемого разработчиками для отладки DirectX-приложений, и она не предсталяет какого-либо интереса для домашнего пользователя. Q. Где можно найти инструкции по загрузке и инсталяции DirectX? A. Посмотрите эту заметку из нашей Информационной базы. Q. Как деинсталировать DirectX? A. DirectX 8.0 - это системный компонент и он не может быть деинсталирован. Если у вас возникли проблемы с инсталяцией DirectX, необходимо закрыть все приложения и повторить инсталяцию. Если же проблемы возникли уже после инсталяции DirectX 8.0, то в большинстве случаев они решаются путем обновления драйверов к аудио- и видеокартам, а также устройствам ввода данных.

Привет всем, кто интересуется DirectX! Темой этого урока я решил сделать написание т. н. "движка". Полагая, что всегда существует определённый контингент людей, только начавших изучать мультимедийные и игровые технологии, и плавающие в загадочных понятиях, объясню, что такое "движок" и на каком бензине он работает. "Движок" - это перевод от английского "engine" - т. е. двигатель. На данный момент термин является общепризнанным, поэтому далее я буду придерживаться именно его (хотя само слово не очень стыкуется с правилами русского языка). Сначала небольшой экскурс в историю. Если кто помнит, в конце 80-х - начале 90-х годов игры не были такими огромными и сложными, каковыми они являются теперь. В те далёкие времена на экстишках и эйтишках в офисах гоняли разве что кошек и цветные кубики из "Тетриса". По объему кода, такие игры, естественно, не идут ни в какое сравнение с теми, что пишутся в наши дни, и поэтому программировались по-иному. Как? Обычно весь код такой программы писался за один "присест" и отвечал за всё - и за графику, и за звук (пищание), и за клавиатуру, и за AI, в общем за всё, что требовалось для воссоздания игрового процесса. К сожалению, принцип "написать все, затем откомпилировать и это работает" проходит только для программ определенного объема, каковыми и были игры пятнадцателетней давности. Повторное использование написанного таким образом кода весьма сомнительно, и в лучшем случае вам придётся переделывать только его половину. Вообще, одновременно с пропорциональным усложнением программ идёт пропорциональное же абстрагирование программиста от первоначального кода. Сейчас уже невозможно, например, написать полномасштабную программу на Ассемблере (вернее можно, но никто этим заниматься не будет). На помощь программисту пришли многочисленные API и библиотеки, созданные трудом многих тысяч других программистов. Движок - это ещё один уровень абстрагирования. Можно сказать, что движок - это небольшая ОС в рамках самой игры, которая отвечает за низкоуровневые операции. В маленьких движках (если не движочках) такие функции обычно отвечают за общение с "железом" - т. е. вывод данных на экран, звуковое оформление и другие подобные вещи. Теперь программиста не интересует механизм вывода, например, текста на экран - он командует PrintText() - и все хлопоты по выводу текста берёт на себя движок. Конечно, код в движке базируется на каком-либо API, и использует его методы для реализации своих "идей". В сущности, любой API - например, DirectX - это тоже в своём роде движок, так как предоставляет нам более высокоуровневую надстройку над низкоуровневыми операциями, реализованными в DLL. Проблема в том, что такие API довольно сложны по причине их гибкости, и обеспечивают только базовые функции. Цель движка - собрать рутинные последовательности команд в один вызов. Из этого, между прочем, следует, что конкретный движок пишется под конкретный жанр игр. Написание движков в настоящее время стало отдельным этапом разработки. Многие профессиональные фирмы уже не пишут движки самостоятельно, а приобретают их у других фирм, которые занимаются исключительно этой областью программирования. Такие движки представляют собой весьма сложные программы, они тщательно документируются и комплектуются демонстрационными примерами. Обычно серьёзные движки отвечают не только за работу с графикой, звуком и т.д., а реализуют ещё и специфичные функции, востребованные играми жанра. Однако мы ещё не настолько "круты", что бы делать подобные вещи, поэтому займемся пока простейшими. Я надеюсь, теперь вам понятно, что написание кода следует разбивать на отдельные этапы и постепенно реализовывать их. Движок - один из таких этапов. Реализовав этот уровень, можно приступать к написанию, скажем, самой игры. Вообще, невозможно писать игровую логику программы и одновременно заниматься поверхностями DirectDraw. Поэтапная разработка способствует тому, что проект в конце-концов будет доведён до конца, а не брошен на полпути. Перейдём от слов к делу. Итак, с чего начать? Прежде всего надо определиться со структурой движка. Для меня это был самый сложный этап, им пренебрегают очень многие. Я на собственном опыте убедился, что если не думать над структурой, вместо цельной программы получается лапша из функций и структур. Особенно тяжеловато приходится в первый раз, когда за плечами только демонстрационные примеры и кое-какие наброски. Впрочем, иногда и лапша полезна (с точки зрения "ой, какой ужас вышел"). Меня удивляют люди, которые пишут большие программы без применения модульности. Например, почти вся реализация игры Donuts из DirectX SDK 7 размещена в одном файле. Лично у меня моментально пропало желание разбирать такую программу после того, как я пару раз повозил ползунок редактора кода туда-сюда. Подобных примеров много - взять тот же DelphiX. Всё "спихнуто" в пару файлов, и разобрать что-либо в этой лапше не представляется возможным (вообще, большие модули в Object Pascal - это болезнь самого языка, немного позже я дам объяснение этому факту). Вывод очевиден - разработку программ необходимо вести с помощью модулей. В каждом модуле следует разместить только те функции и процедуры, которые выполняют узкий круг задач, т. е. разместить их по смыслу. Из личного опыта замечено, что желательно доводить разработку отдельного модуля до степени "готовности" приблизительно процентов этак на 60-80%. Иначе при огромном количестве "недоначататых" модулей начнётся настоящая "беготня" вокруг закладок (в случае с Delphi), и ба-альшие проблемы с отладкой кода. Только обеспечив необходимую функциональность одной части задачи, можно переходить к следующей. Естественно, всегда потом оказывается необходимым что-то исправить или дополнить в уже написанном коде, но сделать это будет гораздо легче. Итак, перейдём к "разбору полётов". Движок (если его вообще можно так назвать), который я выставляю на всеобщее обозрение - мой первый опыт в этой области. Подумав немного, я решил написать его без применения объектно-ориентированного программирования. Хорошо это или плохо? Лично я считаю, что ООП - это хорошо, но оно не всегда востребовано. По моему сугубо личному мнению, в программах вроде игр и движках для них процедурное программирование - ничуть не устаревший инструмент, а применение ООП - неоправдано. Правильно построенная, хорошо структурированная программа легка для понимания и последующей модификации, свободная от классов, загадок наследования и ошибок полиморфизма... Сколько я придумывал название своему движку - словами не передать. В конце концов устоялось название Simple DirectX Interface - сокращённо SDI. По примеру многочисленных библиотек (например, OpenGL) все функции движка, которые предназначены для вызова из внешней программы, начинаются с префикса "sdi", а те, что предназначены для внутреннено использования - без него. На данный момент я реализовал только графичекую составляющую. Остальные части планируется написать немного позже. Это облегчит начинающим первое знакомство со структурой программы. Графическая часть размещается в 10 модулях, остальные выполняют различные вспомогательные работы. Ниже дано перечисление модулей и краткое описание каждого: e_win.pas - отвечает за создание и удаление окна программы. В принципе, во внешней программе можно создавать окно самостоятельно, не прибегая к услугам этого модуля. В этом случае необходимо просто установить дескриптор имеющегося окна, вызвав функцию sdiSetHWnd(). e_drawc.pas - содержит базовые функции для работы с DirectDraw - инициализация и удаление, установка полноэкранного или оконного режима работы. Дополнительно есть возможность получить минимальное описание видеоадаптера и список разрешений. e_draw.pas - здесь располагаются функции, вызываемые для построения изображения на экране. e_drawu.pas - набор вспомогательных функций, которыми пользуются остальные модули графической части движка. e_bmp.pas - организует работу по загрузке файлов формата BMP. 24-битные растры загружаются низкоуровневым способом, который уже был описан мною ранее. Палитровые файлы загружаются с помощью функции LoadImage(). e_sprite.pas - функции для работы со спрайтами и текстом. При создании спрайта одновременно указывается и источник с изображением, которое должен содержать спрайт. Аналогично при создании текста указывается шрифт и сам текст. e_movie.pas - это надстройка над спрайтом. Позволяет быстро создать массив спрайтов одинакового размера и быстро загрузить в них специльным образом отредактированное изображение. Редактор прилагается. e_color.pas - предоставляет функцию sdiMakeColor() для задания, например, цветового ключа для спрайта. Т. к. формат поверхностей DirectDraw на разных видеоадаптерах и в разных разрешениях различен, значение одного и того же цвета сильно отличается для каждого случая. Используя sdiMakeColor() и указав один из 16 стандартных цветов Windows, можно избежать хлопот с некорректным цветовым ключом. e_pscrn.pas - записывает содержимое дополнительного буфера в файл BMP. Функция записи была мною несколько переработана. е_fps.pas - функция sdiGetFPS(). Выдаёт верное значение частоты смены кадров при любой скорости опроса - от 100 мс и до бесконечности. e_dxver.pas - позволяет узнать приблизительную версию DirectX. Ничего существенно нового не появилось. Модуль включён "по инерции". e_error.pas - работа с ошибками. Функция sdiGetLastError() для вывода сообщения об ошибке, происшедшей в "кишках" движка. Надеюсь, никогда не понадобится. e_close.pas - процедура sdiCloseEngine(). Вызов этой функции автоматически удаляет все ресурсы, занятые движком. По-моему, очень полезно. e_string.pas - две функции - ltos() и ltoc() для преобразования типа longint к строке string или pchar соответственно. Базируются на процедуре str() из модуля system.pas. Это здорово сокращает объём исполняемого файла по сравнению с тем, что включает в себя ссылку на sysutils.pas. Префикс "e_" в названии модулей происходит от "engine" и предназначен для обозначения принадлежности к движку. Все модули базируются только на вызове API-функций Windows и методов интерфейсов DirectX. Это обеспечивает миниатюрность получаемого кода - динамическая библиотека (DLL), содержащая в себе весь код, после компиляции имеет размер около 50 кб (для IDE Delphi версии 5). Это значительное преимущество перед другими подобными программами, написанными на Delphi с использованием VCL (я видел exe-файлы размером 1,5 Мб). Одно из правил классического программирования - это написание программ с наименьшим количеством глобальных переменных, т. е. их сокрытие, инкапсулирование. Я как мог, внимал этому правилу, но всё же иногда разным модулям нужно иметь доступ к одной и той же переменной или массиву. Например, интерфейс IDirectDraw7 требуется для многих функций, и он сделан видимым для всех модулей движка. В принципе, можно и сокрыть переменную внтри одного модуля, а доступ к ней обеспечить через функцию GetXXX(), но это нагружает код излишними конструкциями и в данном случае необязательно. Рассмотрим общий механизм работы движка на основе модулей e_bmp.pas и e_sprite.pas. Так как классы не используются, обмен данными происходит через т. н. декрипторы, т. е. идентификаторы чего-либо (это напоминает механизм, на котором базируется API Windows). Например, вот так выглядит прототип функции для загрузки BMP-файла: function sdiLoadBmp( strFileName: string ): DWORD; Как видно, функция возвращает как результат целое беззнаковое число. Его необходимо запомнить при вызове функции. По сути, эта функция аналогична (по принципу работы) функции GDI LoadImage(). Рузультатом работы обеих являтся идентификатор загруженного ресурса в списке уже существующих ресурсов, который можно использовать в дальнейшей работе. В нашем случае возвращается номер элемента вот этого динамического массива: var g_pBmp: array of SDIBMP_STRUCT = nil; где type SDIBMP_STRUCT = record pPixels: IDirectDrawSurface7; dwWidth: DWORD; dwHeight: DWORD; end; В случае ошибки функция возвращает 0, иначе любое положительное число в пределах типа longword. На самом деле возвращаемое значение всегда не 1 больше реального номера элемента в массиве, например, значение 1 будет соответствовать номеру 0 элемента массива, 2 - 1 и т.д. Это связано именно с тем, что 0 уже занят под код ошибки. Все операции по работе с массивом g_pBmp берёт на себя функция function FindBmp(): DWORD; var i: integer; begin if g_pBmp <> nil then for i := 0 to high( g_pBmp ) do if g_pBmp[ i ].pPixels = nil then begin result := i; exit; end; // первое обращение к массиву if g_pBmp = nil then begin setlength( g_pBmp, 30 ); result := 0; end else // свободный элемент в массиве не //найден, в этом случае расширяем массив begin result := high( g_pBmp ) + 1; setlength( g_pBmp, length( g_pBmp ) + 30 ); end; end; Результатом работы функции является реальный номер свободного элемента массива g_pBmp. Если массив существует в памяти, идёт поиск свободного элемента. Если массив не инициализирован, то функцией setlength() выделяется память для него и возвращается первый элемент (0). Иначе, если массив существует и свободные ячейки не найдены, необходимо расширить массив. К сожалению, при изменении длины уже существующего динамического массива сначала резервируется нужная для размещения нового массива память, затем элементы старого массива переносятся в новый, после чего освобождается память, выделенная прежнему массиву. Такие перезаёмы памяти при каждом новом изменении размера массива могут притормаживать работу программы. В данном случае это некритично, т. к. размеры одного элемента массива (и, следовательно, всего массива из этих элементов), невелики - указатель и четыре слова. Однако в более сложных случаях постоянный перезаём памяти может серьёзно "тормознуть" старт программы. Решением может служить изменение размера массива не на один элемент, а скачкообразно. Например, в моём случае - на 30 элементов сразу. Думаю, можно пожертвовать тем, что некоторая память будет постоянно заниматься напрасно, ради увеличения скорости работы. Итак, мы получили идентификатор загруженного растра. Куда его девать? Функция function sdiCreateSprite( bmp: DWORD; pr: Prect ): DWORD; как раз и требует первым параметром идентификатор загруженного растра. Передав его, мы дадим ей информацию о том, какое же изображение мы хотим использовать при создании спрайта. Получив дескриптор, функция может получить описание растра: // узнаём характеристики битовой карты if not GetBmp( bmp, @bmps ) then exit; Кстати, обратите внимание, что второй параметр передаётся через указатель. Это означает, что в структуру bmps будут записаны какие-то данные. Я советую поступать именно так и не использовать служебное слово var - в этом случае с первого взглада на программу непонятно, что происходит с таким параметром - в него что-то записывается, или наоборот, он предоставляет информацию кому-то? Получив растр и проделав свои дела, функция sdiCreateSprite() тоже возвращает идентификатор, но уже созданного спрайта. Его можно использовать, например, для вывода спрайта на экран. Для программы (например, игры) весь механизм выглядит так: id_bmp := sdiLoadBmp( 'picture.bmp' ); id_sprite := sdiCreateSprite( id_bmp, nil ); sdiDraw( id_sprite ); Правда, просто? Затрону немного тему инициализации и удаления. Во многих программах существуют всякие функции вроде InitEngine(), DeleteEngine() и т.п. Оказалось, что вполне можно обойтись без отдельной функции инициализации, а разместить её внутри тех функций, которые могут быть вызваны первыми и требовать какие-то объекты для себя. Например, функция function sdiEnumVideoModes( pvma: PSDIVIDEOMODEARRAY ): boolean; для перечисления видеорежимов самостоятельно вызывает функцию инициализации DirectDraw, если это событие ещё не произошло: if (not g_bInitDirectDraw) and (not InitDirectDraw()) then exit; В данном случае g_bInitDirectDraw - глобальная переменная-флаг, сообщающая, инициализирован объект DirectDraw или нет. Таким образом, нет нужды что-либо инициализировать из внешней программы. Правды ради надо сказать, что в гораздо более крупных программах этот шаг, наверное, всё же будет необходим, ибо делать автоматическую инициализацию для каждой функции движка накладно, легче проделать это один раз в стандартном порядке. Впрочем, ответить на вопрос, как поступать в этом случае, можно лишь самостоятельно написав что-либо фундаментальное. Единственный вызов, который должен присутствовать - это sdiCloseEngine(). Этим вызовом мы удаляем все занятые движком ресурсы. Впрочем, кое-что можно удалить и явно, например procedure sdiDestroyWindow(); Отдельный вопрос - это реализация механизма вывода сообщений об ошибках. Фантазии авторов программ здесь простираются от банального "Ошибка в программе" до "Тут длинная и интересная история об ошибке в файле таком-то, строка такая-то, код ошибки DDERR_ТАКАЯ_ТО_АББРЕВИАТУРА. Application will now exit.". Авторы программ, похоже, всерьёз задумываются над тем, как бы приукрасить окошко с ошибкой самой детальной информацией. Надо молиться, чтобы такое окошко никогда не всплыло вообще! Я решил ограничиться простым текстовым сообщением об ошибке. Функция sle() предназначена для её установки единственный раз. Если же она будет вызвана повторно (например, на более высоком уровне), запись не произойдёт: procedure sle( str: string ); begin if bBuildLog then WriteErrorToLogFile( str ); if not bAlreadySetLastError then begin strError := str; bAlreadySetLastError := true; end; end; Это гарантирует, что мы получим описание настоящей ошибки, а не ёё последствия. А вот лог-файл программы желательно должен содержать все сообщения об ошибках (для простоты "охоты" за ними). Также лог-файл обычно содержит описание всех произошедших действий, но я пока не реализовал это. Для правильного контроля в идеале необходимо проверять КАЖДУЮ вызываемую функцию на возвращаемый результат, будь то метод DirectX или функция GDI. Это повышает гарантию того, что программа, например, не "вылетит" тихо в Windows или не допустит ошибок вроде AV. Я пытался следовать этому правилу как мог, но всё же не стоит усердствовать над IDirectDrawSurface7.Unlock() или DeleteDC(). Заметьте, что я совсем не использую популярные у некоторых программистов блоки try..except. По-моему, легче проверить делитель на ноль, чем делить вслепую и потом смотреть, что получилось. Из личного опыта замечено, что с помощью try..except не всегда можно избежать краха программы, в частности иногда ошибка AV неминуема. На первом этапе работы можно контролировать только наиболее критичные участки кода. Когда движок будет практически завершён, можно "навесить" таких обработчиков побольше. Тут, как говорится, можно дать волю рукам - жёсткий контроль на каждом этапе только уменьшает шансы на принудительную остановку программы операционной системой. Вообще, контроль ошибок может быть серьёзно расширен вплоть до определения характеристик оборудования - например, DirectDraw позволяет провести опрос характеристик видеокарты. Впрочем, выделка должна стоить овчинки. Причина, по которой я так долго не выставлял материалы в Королевство - это попытка реализовать собственные эффекты. Например, изначально движок мог выводить полупрозрачные спрайты, уже описанные мною в предыдущий раз, а также масштабировать изображение и осуществлять поворот спрайта (путём "прямого" доступа к поверхноти DirectDraw). Однако скорость вывода оказалось настолько мала, что я в конце-концов вырезал всё это из кода. Получилась смешная ситуация - достаточно быстрый акселератор вроде GeForce 2MX 400 выдавал просто неприличный fps при повороте спрайта размером 256*256 пикселей. Могу посоветовать только одно - не пытайтесь сделать с помощью DirectDraw какие-либо эффекты. Аппаратно они попросту не поддерживаются ни одной видеокартой (например, поворот на произвольный угол), а если сделать всё вручную, то скорость вывода попросту очень низкая. Я написал пару тестовых примеров, призванных показать общую работу с движком. Вот какой список uses получается при подключении всех файлов движка этими примерами: uses windows, messages, // файлы движка e_win, e_drawc, e_draw, e_drawu, e_bmp, e_sprite, e_movie, e_color, e_pscrn, e_fps, e_dxver, e_error, e_close, e_string; Как видите, немаленький. Размещение всего кода в динамической библиотеке и подключение единственного заголовочного файла для работы с ней решает проблему, но это не очень красиво. Обычно поступают таким образом - весь код на последнем этапе разработки "спихивается" в один или несколько модулей, и список uses уменьшается. Например, описание API DirectX 6 от Хироюки Хори располагается в одном модуле DirectX.pas (в то время как SDK от Microsoft содержит в папке include десятки отдельных файлов). После такого "решения проблемы" программа становится трудно модифицируемой. В языках C и C++ такая ситуация не возникает - для этого можно создать отдельный модуль, например, sdi.h, и подключить в нём все необходимые файлы: #include "e_win.h" #include "e_drawc.h" #include "e_drawu.h" ... #include "e_string.h" Теперь программа станет "видеть" весь код в этих файлах после подключения единственного файла sdi.h. К сожалению, язык Object Pascal до сих пор не поддерживает такое "неявное" подключение модулей, поэтому разработка действительно больших Проектов на этом языке всегда будет сопровождаться огромным списком uses или, наоборот, огромными модулями. Если кто-то знает, как решить эту проблему, автор будет очень благодарен за совет. Возможно, единственным приемлемым решением являются всё же DLL. Несколько слов о недоработках. Первое: пример MainExample в окне в видеорежимах HighColor или TrueColor на всех компьютерах с видеокартами GeForce2 MX 400, где я его тестировал, почему-то работает некорректно. Наблюдается странное поведение всей операционной системы в виде общего замедления работы. Это можно было бы со злорадством отнести к ошибкам движка, НО: На видеокарте S3 Trid3D/2X движок работает нормально в любом режиме! На видеокарте GeForce всё работает нормально в режиме 256 цветов! Вот так. Самое удивительно - примеры из MS SDK работают у меня корректно на обеих видеокартах. Вообще, когда такая ошибка обнаружилась, я был в большом недоумении и полностью растерян. Для "чистоты эксперимента" я даже написал отдельную программу (не на движке), которая также работала в оконном режиме. К сожалению, и она работала некорректно, а ведь программный код был минимален и ошибке попросту негде было спрятаться. Поразмыслив, я пришёл к выводу, что имеет место некорректное взаимодействие программ, написанных на Delphi и драйверов Detonator. Звучит дико, но других объяснений я не нахожу. Второе: я переделал функцию сохранения изображения в файле, теперь она работает корректно для видеокарты S3. К сожалению, на GeForce в 16-битовом режиме она получается искажённой, причину я так не нашёл. Для режима 32 бита всё работает правильно. Мысли вслух: Если планируется писать какую-то игру или мультимедийное приложение, лучше написать сначала движок для неё. Разработка более-менее крупной программы после маленьких развязывает руки, позволяет "развернуться" программисту, реализовать некоторы свои амбиции. Вместе с тем работа по ловле ошибок довольно хлопотна и иногда раздражает. Уделите некоторое внимание организации вывода сообщений об ошибках - это окупится сторицей в процессе разработки. Иногда встречаются никак, совершенно, ну абсолютно необъянимые "bugs"! Это может здорово испортить жизнь. Иногда (только иногда) такие баги пропадают сами собой, если их "заморозить" недельки на две заглушкой, а потом снять %) Собственная(!) реализация всяких эффектов вроде прозрачности и поворота радует глаз, однако слишком уж они медленны и неказисты, их качество часто желает оставлять лучшего. Вдобавок, DirectDraw API постепенно становится устаревшей технологией, её развите корпорацией Microsoft уже давно остановлено. Возможно, захотев иметь в своей программе красочные спецэффекты, следует обратить своё внимание на двумерное рисование посредством таких API, как Direct3D и OpenGL.

Сделать бесплатный сайт с uCoz