http://seprize.narod.ru |
|
Блитинг< Часть 1 | Часть 2 | Часть 3 > Вспомогательная поверхность создана и заполнена растром размером 256x256 пикселов. Среди аргументов операции блиттинга присутствуют структуры типа trect, задающие местоположение в принимающей поверхности и копируемую область. Поэтому код обработчика перерисовки окна дополнился переменными dstRect и srcRect типа trect. Заполняем их поля с помощью API-функции SetRect:
SetRect (dstRect, 100, 100, 356, 356); // Для принимающей поверхности SetRect (srcRect, 0, 0, 256, 256); // Для источника Теоретически эта операция также может привести к провалу. Для важных приложений рекомендую здесь анализировать возвращаемое булево значение. К тому же соглашусь, что в данном примере оптимальным решением было бы использование глобальных переменных, заполняемых один раз, а не при каждой перерисовке окна. Просто код в таком виде удобнее читать, а перерисовка не станет производиться интенсивно. Канву для вывода растра не используем, делаем теперь все традиционным для DirectDraw способом: while True do begin // Возможно, придется производить неоднократно hRet := FDDSPrimary.Blt (@dstRect, FDDSImage, @srcRect, DDBLT_WAIT, nil); // Собственно блиттинг if hRet = DDERR_SURFACELOST then begin // Поверхность потеряна if Failed (RestoreAll) then Exit; // Пытаемся восстановить end else Break; // Или все прошло успешно, или неустранимая ошибка end; Потеря любой поверхности является верным признаком того, что надо восстанавливать все поверхности. Поэтому каждый раз в случае ошибки обращаемся к пользовательской функции RestoreAll: function TfrmDD.RestoreAll : HRESULT; begin Result := DD_FALSE; // Определяемся с результатом // Пытаемся восстановить первичную поверхность if Succeeded (FDDSPrimary._Restore) then begin // Пытаемся восстановить вторичную поверхность if Failed (FDDSImage._Restore) then Exit; Result := DD_OK; // Все прошло успешно end; end; Нажав комбинацию клавиш <Alt>+<Tab>, переключитесь с этого приложения, а затем верните ему фокус. Если восстановление поверхностей прошло успешно, вы увидите картинку с пейзажем. Но если это получилось с вашей картой, совсем не обязательно, что это произойдет и с другими. На иных компьютерах пользователи в такой ситуации могут получить бессмысленный узор. Согласно рекомендациям разработчиков, поверхности, содержащие растр, при восстановлении должны заново заполняться. Если это окно из рассматриваемого примера у вас восстанавливается без потерь, можете двигаться дальше. Если же у вас картинка при восстановлении портится, функцию восстановления исправьте следующим образом: function TfrmDD.RestoreAll : HRESULT; var hRet : HRESULT; begin hRet := FDDSPrimary._Restore; if Succeeded (hRet) then begin hRet := FDDSImage._Restore; if Failed (hRet) then begin Result := hRet; Exit; end; // Перезагружаем на поверхность содержимое растра Result := DDReLoadBitmap(FDDSImage, imageBMP); end else Result := hRet; end; Теперь мы можем узнать смысл первых трех аргументов метода Blt поверхности. Первый из них — указатель на структуру типа trect, задающую местоположение и размер области, в которую происходит копирование. Второй параметр — поверхность источника. Третий аргумент — указатель на структуру типа trect, задающую местоположение и размер области, из которой происходит копирование. Флагом задаем константу ddblt_wait, не комбинацию значений. Дополнительные параметры пока не указываем, поэтому последний аргумент метода устанавливаем в nil. Пример простой, но очень важный. Осмыслим изученное. Естественным для DirectDraw способом воспроизведения является блиттинг. На вспомогательных поверхностях размещаем нужные нам образы, а в определенный момент времени копируем требуемые области с одной поверхности на другую, в простейшем случае — со вспомогательных поверхностей на первичную, связанную с экраном. Вторичных поверхностей создают столько, сколько требуется приложению. Разработчик сам решает, что и где ему располагать, но здесь надо учесть небольшую тонкость: если видеокарта имеет малый размер памяти, то вторичную поверхность не получится создать размером больше первичной. Может быть, это происходит только с конкретными картами, но я действительно встречался с такой ситуацией. Поверхностей вы можете создавать сколько угодно, но чем их меньше, тем быстрее будет осуществляться блиттинг. Поэтому лучше не плодить множество поверхностей, а, в идеальном случае, располагать все образы на одной большой поверхности. В общем случае операция копирования блоков из системной памяти в видеопамять осуществляется медленнее, чем из видеопамяти в видеопамять. Поэтому образы, выводимые наиболее часто, старайтесь размещать в видеопамяти, а при ее нехватке те из образов, которые редко будут появляться, например заставки или меню, следует размещать в системной памяти. Поддержка AGP если и стирает разницу в скоростях обмена, то незначительно. Если бы скорости работы с видеопамятью и системной памятью сосовпадали или были близки друг к другу, не было бы нужды производителям карт выпускать модели, различающиеся размером видеопамяти, а пользователям оставалось лишь наращивать размер системной памяти. Для поверхности, создаваемой в видеопамяти, надо использовать комбинацию флагов DDSCAPS_OFFSCREENPLAIN or DDSCAPS_VIDEOMEMORY. И Наоборот, флаг ddscaps_systemmemory указывает, что поверхность должна располагаться в системной памяти. Метод GetAvailablevidMem главного объекта DirectDraw позволяет выяснить, сколько видеопамяти осталось в распоряжении приложения. При нехватке видеопамяти операция создания поверхности завершится провалом, код соответствующей ошибки — dderr_outofvideomemory. В этом случае необходимо поменять флаг и заново попытаться создать поверхность. Теперь обсудим вопросы масштабирования растров. Вспомогательная функция копирования растра поддерживает масштабирование. Задайте размер. вторичной поверхности больше, чем размер используемого растра, например, так: ddsd.dwWidth := wrkBitmap.Width * 2; Теперь при воспроизведении мы увидим картинку, растянутую вдоль экрана, но не всю, а только ее половину. Для того чтобы вывести ее целиком, надо изменить значение поля Right структуры dstRect: SetRect (dstRect, 100, 100, 100 + 256 * 2, 356);
P.S. Данная статья будет подправлена, обогащена примерами, но пока я считаю что многих она заинтересует < Часть 1 | Часть 2 | Часть 3 >
|
|
Если вы используете материалы с данного сайта, то сообщите
владельцу по почте |
© Сайт открылся 04.09.2002 Дата последнего обновления 09.10.2002 |