|
"Графика для Windows средствами DirectDraw" Приложение А. Информация для разработчиков Вот и все - книга подходит к концу.
Однако наше внимание было настолько приковано к DirectDraw (и DirectInput),
что некоторые важные темы так и не были рассмотрены. Например, в DirectDraw
есть несколько досадных недочетов, о которых необходимо знать (если
вы еще не успели столкнуться с ними). Свои недостатки есть и у Visual C++.
Кроме того, некоторые особенности программного кода на CD-ROM могут
представлять для вас интерес. Во время работы над программами я отобрал
ряд полезных советов. Наконец, у меня есть несколько общих замечаний,
которые не удалось привязать к основному тексту. Все эти темы рассматриваются
в приложении.
Говорят, некоторым программистам нравится
отлаживать свои программы — я не отношусь к их числу. Приятно узнать,
почему ваша программа постоянно «зависает» или почему спрайт неправильно
выводится на экран — но я охотно поменял бы это чувство удовлетворения
на те напрасно потраченные часы и дни, когда я скрежетал зубами, заново
компилировал свои программы и в сотый раз перезагружал компьютер. Отладить полноэкранное приложение намного
сложнее, чем любое другое, и для этого есть несколько причин. Самая
очевидная из них — раз приложение занимает весь экран, вы не сможете
изменить точки прерывания, просмотреть код программы или значения переменных.
Дело усложняется переключением страниц. Если программа должна вывести
проверочное сообщение или отладочное окно, нельзя гарантировать, что
оно действительно появится на экране, потому что Windows может вывести
информацию во вторичном буфере. И даже если вам повезет и вы сможете
увидеть это окно (при использовании буферизации ваши шансы — 50
на 50), вероятно, его все равно не удастся толком разглядеть из-за различий
между текущей и системной палитрой. Первый шаг в великой битве с багами
— переход на Windows NT (если вы еще не успели этого сделать).
Разумеется, вам не придется отказываться от поддержки Windows 95,
но для разработки NT подходит лучше, а приложения DirectX переносятся
из NT в 95 без перекомпиляции. Просто Windows NT работает более
устойчиво, чем Windows 95. NT редко ( очень редко) требует
перезагрузки, тогда как в 95 это вполне обычное явление. Visual C++ (как и многие другие
среды разработки) содержит макросы, предназначенные специально для отладки.
Например, макросы TRACE(), ASSERT() и VERIFY() приносят
огромную пользу в процессе разработки. Они предназначены для разных
целей, но у всех трех макросов есть нечто общее — они не отягощают
итоговый выполняемый файл. При построении отладочных версий вашей программы
макросы ведут себя так, как им положено. Однако в «окончательной» версии
они удаляются из программы (вместе с теми возможностями, которые ими
обеспечивались). #define ASSERT(f) \ do \ { \ if (!(f) && AfxAssertFailedLine(THIS_FILE, __LINE__)) \ AfxDebugBreak(); \ } while (0) \ Выглядит довольно странно. Но вместо
того, чтобы пытаться расшифровать логику его работы, мы согласимся с
тем, что макрос работает, и попытаемся изменить его так, чтобы он правильно
работал в приложениях DirectDraw. Однако перед этим следует заметить,
что вывод диалогового окна и завершение приложения выполняются с помощью
вызова AfxAssertFailedLine() . Следовательно, любой код, добавленный
в этот условный оператор (что на первый взгляд кажется логичным), выполняться
не будет. #define ASSERT(f) \ do \ { \ if (!(f)) \ { \ if (GetDDWin()) \ { \ GetDDWin()->GetDDraw()->RestoreDisplayMode(); \ GetDDWin()->GetDDraw()->Release(); \ } \ AfxAssertFailedLine(THIS_FILE, __LINE__); \ AfxDebugBreak(); \ } \ } while (0) \ Для работы с объектом DirectDraw применяются
функции GetDDWin() и GetDDraw() (которые соответственно
возвращают указатели на объект DirectDrawWin и интерфейс
DirectDraw ). Помимо вызова функции RestoreDisplayMode()
мы для приличия освобождаем объект DirectDraw . Также обратите
внимание на перестановку, в результате которой наш код будет выполняться
перед вызовом функции AfxAssertFailedLine() . #define VERIFY(f) ASSERT(f) Вспомните — в отладочной версии ASSERT() и VERIFY() ведут себя одинаково. Раз ASSERT() и VERIFY() реализуются одним макросом, VERIFY() можно оставить без изменений. Сказанное относится и к окончательным версиям макросов ASSERT() и VERIFY() , потому что нам не потребуется изменять их поведение. При компиляции окончательной версии ASSERT() и VERIFY() определяются так: #define ASSERT(f) ((void)0) #define VERIFY(f) ((void)(f)) Как было сказано выше, выражение, передаваемое
макросу ASSERT() , удаляется из окончательной версии (в действительности
оно заменяется выражением ((void)0) , которое игнорируется
компилятором). Выражения, передаваемые VERIFY() , остаются
в коде программы, однако их значение больше не проверяется. #ifdef _DEBUG#undef ASSERT#define ASSERT(f) \ do \ { \ if (!(f)) \ { \ if (GetDDWin()) \ { \ GetDDWin()->GetDDraw()->RestoreDisplayMode(); \ GetDDWin()->GetDDraw()->Release(); \ } \ AfxAssertFailedLine(THIS_FILE, __LINE__); \ AfxDebugBreak(); \ } \ } while (0) \ #endif _DEBUG Модифицированный макрос находится на CD-ROM и готов к работе, поэтому если вы захотите внести изменения в какую-нибудь программу, то можете свободно пользоваться макросами TRACE() , ASSERT() и VERIFY() . Кроме того, этот код автоматически генерируется и включается в проекты, создаваемые DirectDraw AppWizard. Процесс отладки упрощается, если вам
повезло и в вашем распоряжении оказались два компьютера, объединенных
в локальную сеть. В этом случае возможна удаленная отладка, при которой
на одном компьютере работает отлаживаемая программа, а на другом —
отладчик Visual C++. При удаленной отладке исчезают все проблемы,
связанные с переключением страниц, палитрами и отображением отладчика.
Отладчик всегда присутствует на экране и с ним можно работать, потому
что отладчик и приложение работают на разных компьютерах. Даже если
ваша программа «сломается», ее состояние можно будет просмотреть в отладчике.
Поскольку удаленная отладка обладает такими преимуществами (и при этом
так плохо документирована), мы поговорим о том, как происходит ее настройка.
Если эта тема вас не интересует, можете пропустить этот раздел. Вероятно, вы уже заметили, что при
запуске приложений DirectX в окне вывода отладчика Visual C++ появляются
диагностические сообщения. По умолчанию отладочные версии компонентов
DirectX сообщают таким образом о важных внутренних событиях — например,
об ошибках. Типичное окно вывода для приложения DirectDraw изображено
на рис. А.10 .
Листинг А.1 . Подробный отладочный протокол DirectDraw DDraw:====> ENTER: DLLMAIN(baaa12c0): Process Attach: fff00c89, tid=fff04bf1 DDraw:Thunk connects DDraw:Signalling DDHELP that a new process has connected DDraw:====> EXIT: DLLMAIN(baaa12c0): Process Attach: fff00c89 DDraw:createDC(R3D) DDraw:Enumerating GUID aba52f41-f744-11cf-b4-52-00-00-1d-1b-41-26 DDraw: Driver Name = R3D DDraw: Description = Righteous 3D DirectX II Driver DDraw:DeleteDC 0x179e DDraw:createDC(mm3dfx) DDraw:Enumerating GUID 3a0cfd01-9320-11cf-ac-a1-00-a0-24-13-c2-e2 DDraw: Driver Name = mm3dfx DDraw: Description = 3Dfx Interactive DirectX Driver DDraw:DeleteDC 0x179e DDraw:Only one Display device in the current system. DDraw:DirectDrawCreate entered DDraw: GUID *:00000000, LPLPDD:0064f870, pUnkOuter:00000000 DDraw:Registry already scanned, not doing it again DDraw:full name = C:\SAMPLE\DEBUG\SAMPLE.EXE DDraw:name = SAMPLE.EXE DDraw:DirectDrawCreate: pid = fff00c89 DDraw:Reading Registry DDraw: ModeXOnly: 0 DDraw: EmulationOnly: 0 DDraw: ShowFrameRate: 0 DDraw: EnablePrintScreen: 0 DDraw: DisableMMX: 0 DDraw: DisableWiderSurfaces:0 DDraw: DisableNoSysLock:0 DDraw: ForceNoSysLock:0 DDraw:Signalling DDHELP to create a new DC DDraw:createDC(display) DDraw:DIRECTDRAW driver is wrong version, got 0x5250, expected 0x0100 DDraw:getDisplayMode: DDraw: bpp=8, refresh=0 DDraw: dwHeight=600, dwWidth=800 DDraw: lStride=0 DDraw:Driver says nummodes=9 DDraw:Enum Display Settings says nummodes=9 DDraw:dwModeIndex = 1 DDraw:Masks for current mode are: 00000000 00000000 00000000 DDraw:DirectDrawObjectCreate: oldpdd == 00000000, reset=0 DDraw:DIRECTDRAW object passed in = 00000000 DDraw:oldpdd == 00000000, reset=0 DDraw:Driver Object: 2256 base bytes DDraw:dwReserved3 of DDrawGbl is set to 0x0 DDraw:oldpdd == NULL || reset DDraw:Driver can't blt DDraw:pddd->lp16DD = 40cf0000 DDraw:Adding ModeX mode 320x200x8 (standard VGA flag is 0) DDraw:Adding ModeX mode 320x240x8 (standard VGA flag is 0) DDraw:Adding ModeX mode 320x200x8 (standard VGA flag is 1) DDraw:All video memory heaps have been disabled. OS has no AGP support DDraw:Current and Original Mode = 1 DDraw:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ MODE INDEX = 1 DDraw:DDHALInfo contains D3D pointers: 00000000 00000000 DDraw:createDC(display) DDraw:NOT Setting DDCAPS_BANKSWITCHED DDraw:DeleteDC 0x179e DDraw:Taking the Win16 lock may not be necessary for VRAM locks DDraw:DirectDrawObjectCreate: Returning global object 82dc11f8 DDraw:createDC(display) DDraw:createDC(display) DDraw:DeleteDC 0x175e DDraw:DeleteDC 0x179e DDraw:Primary's rect is 0, 0, 800, 600 DDraw:HELInit for DISPLAY Driver: Reference Count = 1 DDraw:createDC(display) DDraw:DeleteDC 0x179e DDraw:createDC(display) DDraw:createDC(display) DDraw:DeleteDC 0x175e DDraw:DeleteDC 0x179e DDraw:***New local allocated 82dc1b1c for global pdrv 82dc11f8 DDraw:New driver object created, interface ptr = 82dc1b84 DDraw: DirectDrawCreate succeeds, and returns ddraw pointer 82dc1b84 DDraw:New driver interface created, 82dc1bb0 DDraw:DD_AddRef, pid=fff00c89, obj=82dc1bb0 DDraw:DD_AddRef, Reference Count: Global = 2 Local = 2 Int = 1 DDraw:DD_Release, pid=fff00c89, obj=82dc1b84 DDraw:DD_Release, Ref Count: Global = 1 Local = 1 Interface = 0 DDraw:*********** ALLOWING MODE X AND VGA MODES DDraw:DD_GetDeviceRect: display [0 0 800 600] DDraw:Subclassing window 00000aac DDraw:StartExclusiveMode DDraw:******** invalidating all surfaces DDraw:Enumerating mode 0. 640x480 DDraw:Enumerating mode 1. 800x600 DDraw:Enumerating mode 2. 1024x768 DDraw:Enumerating mode 3. 1280x1024 DDraw:Enumerating mode 4. 640x480 DDraw:Enumerating mode 5. 800x600 DDraw:Enumerating mode 6. 1024x768 DDraw:Enumerating mode 7. 640x480 DDraw:Enumerating mode 8. 800x600 DDraw:Enumerating mode 9. 320x200 DDraw:Enumerating mode 10. 320x240 DDraw:Enumerating mode 11. 320x200 DDraw:Looking for 640x480x8 DDraw:Found 640x480x8x (flags = 1) DDraw:Found 800x600x8x (flags = 1) DDraw:Found 1024x768x8x (flags = 1) DDraw:Found 1280x1024x8x (flags = 1) DDraw:Found 640x480x16x (flags = 0) DDraw:Found 800x600x16x (flags = 0) DDraw:Found 1024x768x16x (flags = 0) DDraw:Found 640x480x32x (flags = 0) DDraw:Found 800x600x32x (flags = 0) DDraw:Found 320x200x8x (flags = 3) DDraw:Found 320x240x8x (flags = 3) DDraw:Found 320x200x8x (flags = 11) DDraw:Calling HEL SetMode DDraw:width = 640 DDraw:height = 480 DDraw:bpp = 8 DDraw:WM_DISPLAYCHANGE: 640x480x8 DDraw:DD_GetDeviceRect: display [0 0 640 480] DDraw:WM_SIZE hWnd=AAC wp=0000, lp=01E00280 DDraw:WM_SIZE: Window restored, NOT sending WM_ACTIVATEAPP DDraw:createDC(display) DDraw:DeleteDC 0x1712 DDraw:createDC(display) DDraw:createDC(display) DDraw:DeleteDC 0x179e DDraw:DeleteDC 0x1712 DDraw:createDC(display) DDraw:getDisplayMode: DDraw: bpp=8, refresh=0 DDraw: dwHeight=480, dwWidth=640 DDraw: lStride=0 DDraw:Driver says nummodes=9 DDraw:Enum Display Settings says nummodes=9 DDraw:dwModeIndex = 0 DDraw:Masks for current mode are: 00000000 00000000 00000000 DDraw:DirectDrawObjectCreate: oldpdd == 82dc11f8, reset=1 DDraw:DIRECTDRAW object passed in = 82dc11f8 DDraw:oldpdd == 82dc11f8, reset=1 DDraw:Driver Object: 2256 base bytes DDraw:dwReserved3 of DDrawGbl is set to 0x0 DDraw:oldpdd == NULL || reset DDraw:Driver can't blt DDraw:******** invalidating all surfaces DDraw:All video memory heaps have been disabled. OS has no AGP support DDraw:Current and Original Mode = 0 DDraw:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ MODE INDEX = 0 DDraw:DDHALInfo contains D3D pointers: 00000000 00000000 DDraw:createDC(display) DDraw:NOT Setting DDCAPS_BANKSWITCHED DDraw:DeleteDC 0x179e DDraw:Taking the Win16 lock may not be necessary for VRAM locks DDraw:DirectDrawObjectCreate: Returning global object 82dc11f8 DDraw:createDC(display) DDraw:createDC(display) DDraw:DeleteDC 0x1776 DDraw:DeleteDC 0x179e DDraw:Primary's rect is 0, 0, 640, 480 DDraw:DeleteDC 0x1712 DDraw:Looking for 640x480x16 DDraw:Found 640x480x8x (flags = 1) DDraw:Found 800x600x8x (flags = 1) DDraw:Found 1024x768x8x (flags = 1) DDraw:Found 1280x1024x8x (flags = 1) DDraw:Found 640x480x16x (flags = 0) DDraw:Found 800x600x16x (flags = 0) DDraw:Found 1024x768x16x (flags = 0) DDraw:Found 640x480x32x (flags = 0) DDraw:Found 800x600x32x (flags = 0) DDraw:Found 320x200x8x (flags = 3) DDraw:Found 320x240x8x (flags = 3) DDraw:Found 320x200x8x (flags = 11) DDraw:Calling HEL SetMode DDraw:width = 640 DDraw:height = 480 DDraw:bpp = 16 DDraw:Window 00000ac4 is on top of us!! DDraw:Window 00000ac4 is on top of us!! DDraw:Window 00000ac4 is on top of us!! DDraw:WM_DISPLAYCHANGE: 640x480x16 DDraw:DD_GetDeviceRect: display [0 0 640 480] DDraw:createDC(display) DDraw:DeleteDC 0x172a DDraw:createDC(display) DDraw:createDC(display) DDraw:DeleteDC 0xc96 DDraw:DeleteDC 0x172a DDraw:createDC(display) DDraw:getDisplayMode: DDraw: bpp=16, refresh=0 DDraw: dwHeight=480, dwWidth=640 DDraw: lStride=0 DDraw:Driver says nummodes=9 DDraw:Enum Display Settings says nummodes=9 DDraw:dwModeIndex = 4 DDraw:Masks for current mode are: 00007c00 000003e0 0000001f DDraw:DirectDrawObjectCreate: oldpdd == 82dc11f8, reset=1 DDraw:DIRECTDRAW object passed in = 82dc11f8 DDraw:oldpdd == 82dc11f8, reset=1 DDraw:Driver Object: 2256 base bytes DDraw:dwReserved3 of DDrawGbl is set to 0x0 DDraw:oldpdd == NULL || reset DDraw:Driver can't blt DDraw:******** invalidating all surfaces DDraw:All video memory heaps have been disabled. OS has no AGP support DDraw:Current and Original Mode = 4 DDraw:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ MODE INDEX = 4 DDraw:DDHALInfo contains D3D pointers: 00000000 00000000 DDraw:createDC(display) DDraw:NOT Setting DDCAPS_BANKSWITCHED DDraw:DeleteDC 0xc96 DDraw:Taking the Win16 lock may not be necessary for VRAM locks DDraw:DirectDrawObjectCreate: Returning global object 82dc11f8 DDraw:createDC(display) DDraw:createDC(display) DDraw:DeleteDC 0x179e DDraw:DeleteDC 0xc96 DDraw:Primary's rect is 0, 0, 640, 480 DDraw:DeleteDC 0x172a DDraw:82dc1bb0->CreateSurface DDraw: DDSURFACEDESC->dwBackBufferCount = 1 DDraw: DDSURFACEDESC->lpSurface = 00000000 DDraw: DDSCAPS_COMPLEX DDraw: DDSCAPS_FLIP DDraw: DDSCAPS_PRIMARYSURFACE DDraw:******** invalidating all primary surfaces DDraw:#### Using GDI screen bpp = 16 DDraw:*** allocating primary surface DDraw:createDC(display) DDraw:createDC(display) DDraw:DeleteDC 0x179e DDraw:DeleteDC 0xc96 DDraw:#### Using GDI screen bpp = 16 DDraw:*** allocating a backbuffer DDraw:HEL:About to allocate 614400 bytes for the surface DDraw:DD_Surface_AddRef, Reference Count: Global = 1 Local = 1 Int = 1 DDraw:DD_Surface_AddRef, Reference Count: Global = 1 Local = 1 Int = 1 DDraw: CreateSurface returns 00000000 (0) DDraw:DD_Surface_AddRef, Reference Count: Global = 2 Local = 2 Int = 2 DDraw:82dc1bb0->CreateSurface DDraw: DDSURFACEDESC->dwHeight = 240 DDraw: DDSURFACEDESC->dwWidth = 320 DDraw: DDSURFACEDESC->lpSurface = 00000000 DDraw: DDSCAPS_OFFSCREENPLAIN DDraw: DDSCAPS_VIDEOMEMORY DDraw:No hardware support DDraw: CreateSurface returns 88760233 (563) DDraw:82dc1bb0->CreateSurface DDraw: DDSURFACEDESC->dwHeight = 240 DDraw: DDSURFACEDESC->dwWidth = 320 DDraw: DDSURFACEDESC->lpSurface = 00000000 DDraw: DDSCAPS_OFFSCREENPLAIN DDraw: DDSCAPS_SYSTEMMEMORY DDraw:Forcing pixel format for explicit system memory surface DDraw:#### Got surface pixel format bpp = 16 DDraw:*** allocating a surface 320x240x16 DDraw:HEL: About to allocate 153600 bytes for the surface of 640x240 with alignemnt 8 DDraw:DD_Surface_AddRef, Reference Count: Global = 1 Local = 1 Int = 1 DDraw: CreateSurface returns 00000000 (0) DDraw:82dc1f74->Lock DDraw: DDSURFACEDESC->dwHeight = 240 DDraw: DDSURFACEDESC->dwWidth = 320 DDraw: DDSURFACEDESC->lPitch = 640 DDraw: DDSURFACEDESC->lpSurface = 004b7118 DDraw:Flags: DDraw: DDPF_RGB DDraw: BitCount:16 DDraw: Bitmasks: R/Y:00007c00, G/U:000003e0, B/V:0000001f, Alpha/Z:00000000 DDraw: DDSCAPS_OFFSCREENPLAIN DDraw: DDSCAPS_SYSTEMMEMORY DDraw:WM_SIZE hWnd=AAC wp=0000, lp=01E00280 DDraw:WM_SIZE: Window restored, sending WM_ACTIVATEAPP DDraw:WM_ACTIVATEAPP: BEGIN Activating app pid=fff00c89, tid=fff04bf1 DDraw:*** Already activated DDraw:WM_ACTIVATEAPP: DONE Activating app pid=fff00c89, tid=fff04bf1 DDraw:Bringing window to top DDraw:WM_ACTIVATEAPP: BEGIN Deactivating app pid=fff00c89, tid=fff04bf1 DDraw:*** Active state changing DDraw:******** invalidating all surfaces DDraw:INACTIVE: fff00c89: Restoring original mode (1) DDraw:In RestoreDisplayMode DDraw:Turning off DCI in mySetMode DDraw:WM_DISPLAYCHANGE: 800x600x8 DDraw:DD_GetDeviceRect: display [0 0 800 600] DDraw:WM_SIZE hWnd=AAC wp=0000, lp=02580320 DDraw:WM_SIZE: Window restored, NOT sending WM_ACTIVATEAPP DDraw:WM_ACTIVATEAPP: BEGIN Deactivating app pid=fff00c89, tid=fff04bf1 DDraw:*** Already deactivated DDraw:WM_ACTIVATEAPP: DONE Deactivating app pid=fff00c89, tid=fff04bf1 DDraw:createDC(display) DDraw:createDC(display) DDraw:DeleteDC 0x159a DDraw:DeleteDC 0xa4a DDraw:RestoreDisplayMode: Process fff00c89 Mode = 4 DDraw:createDC(display) DDraw:getDisplayMode: DDraw: bpp=8, refresh=0 DDraw: dwHeight=600, dwWidth=800 DDraw: lStride=0 DDraw:Driver says nummodes=9 DDraw:Enum Display Settings says nummodes=9 DDraw:dwModeIndex = 1 DDraw:Masks for current mode are: 00000000 00000000 00000000 DDraw:DirectDrawObjectCreate: oldpdd == 82dc11f8, reset=1 DDraw:DIRECTDRAW object passed in = 82dc11f8 DDraw:oldpdd == 82dc11f8, reset=1 DDraw:Driver Object: 2256 base bytes DDraw:dwReserved3 of DDrawGbl is set to 0x0 DDraw:oldpdd == NULL || reset DDraw:Driver can't blt DDraw:******** invalidating all surfaces DDraw:All video memory heaps have been disabled. OS has no AGP support DDraw:Current and Original Mode = 1 DDraw:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ MODE INDEX = 1 DDraw:DDHALInfo contains D3D pointers: 00000000 00000000 DDraw:createDC(display) DDraw:NOT Setting DDCAPS_BANKSWITCHED DDraw:DeleteDC 0x170a DDraw:Taking the Win16 lock may not be necessary for VRAM locks DDraw:DirectDrawObjectCreate: Returning global object 82dc11f8 DDraw:createDC(display) DDraw:createDC(display) DDraw:DeleteDC 0xaa2 DDraw:DeleteDC 0x170a DDraw:Primary's rect is 0, 0, 800, 600 DDraw:DeleteDC 0x13ba DDraw:Redrawing all windows DDraw:DoneExclusiveMode DDraw:Enabling error mode, hotkeys DDraw:Mode was never changed by this app DDraw:WM_ACTIVATEAPP: DONE Deactivating app pid=fff00c89, tid=fff04bf1 DDraw:DD_Surface_Release, Reference Count: Global = 0 Local = 0 Int = 0 DDraw:Deleting attachment from 82dc1e98 to 82dc1b84 (implicit = 1) DDraw:DeleteOneAttachment: 82dc1b84,82dc1e98 DDraw:DD_Surface_AddRef, Reference Count: Global = 3 Local = 3 Int = 3 DDraw:Leaving AddRef early to prevent recursion DDraw:DeleteOneLink: 82dc1e98,82dc1b84 DDraw:DeleteOneLink: 82dc1b84,82dc1e98 DDraw:DD_Surface_Release, Reference Count: Global = 2 Local = 2 Int = 2 DDraw:Leaving Release early to prevent recursion DDraw:DD_Surface_Release, Reference Count: Global = 1 Local = 1 Int = 1 DDraw:DD_Surface_Release, Reference Count: Global = 0 Local = 0 Int = 0 DDraw:Freeing pointer 0042110c DDraw:DD_Release, pid=fff00c89, obj=82dc1bb0 DDraw:DD_Release, Ref Count: Global = 0 Local = 0 Interface = 0 DDraw:Unsubclassing window 00000aac DDraw:ProcessSurfaceCleanup DDraw:Process fff00c89 had 1 accesses to surface 82dc1f74 DDraw:DD_Surface_Release, Reference Count: Global = 0 Local = 0 Int = 0 DDraw:Freeing pointer 004b7118 DDraw:Leaving ProcessSurfaceCleanup DDraw:ProcessPaletteCleanup, ppal=00000000 DDraw:ProcessClipperCleanup DDraw:Cleaning up clippers owned by driver object 0x82dc11f8 DDraw:Not cleaning up clippers not owned by a driver object DDraw:ProcessVideoPortCleanup DDraw:Leaving ProcessVideoPortCleanup DDraw:Mode was never changed by this app DDraw:FREEING DRIVER OBJECT DDraw:Calling HEL DestroyDriver DDraw:HEL DestroyDriver: dwHELRefCnt=0 DDraw:3 surfaces allocated - 768000 bytes total DDraw:*********** DDHEL TIMING INFO ************ DDraw:myFlip: 30 calls, 1.365 sec (0.045) DDraw:myLock: 1 calls, 0.000 sec (0.000) DDraw:myUnlock: 1 calls, 0.000 sec (0.000) DDraw:****************************************** DDraw:Frequency(cycles/second)(0) 1193180 DDraw:Blt16_SrcCopy(32): SUM = 264860 DDraw:Blt16_SrcCopy(32): COUNT = 30 DDraw:Blt16_SrcCopy(32): AVG = 8828 DDraw:Blt16_SrcCopy(32): MIN = 8572 DDraw:Blt16_SrcCopy(32): MAX = 9964 DDraw:Blt16_SrcCopy(32): Dst MB/sec = 17 DDraw:Blt16_ColorFill(47): SUM = 716435 DDraw:Blt16_ColorFill(47): COUNT = 32 DDraw:Blt16_ColorFill(47): AVG = 22388 DDraw:Blt16_ColorFill(47): MIN = 15855 DDraw:Blt16_ColorFill(47): MAX = 55858 DDraw:Blt16_ColorFill(47): Dst MB/sec = 27 DDraw:P6SrcCopy(Bypass Blt16_SrcCopy)(88): SUM = 263495 DDraw:P6SrcCopy(Bypass Blt16_SrcCopy)(88): COUNT = 30 DDraw:P6SrcCopy(Bypass Blt16_SrcCopy)(88): AVG = 8783 DDraw:P6SrcCopy(Bypass Blt16_SrcCopy)(88): MIN = 8528 DDraw:P6SrcCopy(Bypass Blt16_SrcCopy)(88): MAX = 9917 DDraw:P6SrcCopy(Bypass Blt16_SrcCopy)(88): Dst MB/sec = 17 DDraw:Driver is now FREE DDraw:====> ENTER: DLLMAIN(baaa12c0): Process Detach fff00c89, tid=fff04bf1 DDraw:MemState DDraw:Memory still allocated! Alloc count = 11 DDraw:Current Process (pid) = fff00c89 DDraw:82dc100c: dwSize=00000008, lpAddr=baaa1bbc (pid=fff1b349) DDraw:82dc1054: dwSize=0000001d, lpAddr=baae5093 (pid=fff18e61) DDraw:82dc1090: dwSize=00000019, lpAddr=baae5093 (pid=fff18e61) DDraw:82dc10c8: dwSize=00000019, lpAddr=baae5093 (pid=fff18e61) DDraw:82dc1100: dwSize=0000001d, lpAddr=baae5093 (pid=fff18e61) DDraw:82dc113c: dwSize=00000018, lpAddr=baae5093 (pid=fff18e61) DDraw:82dc1170: dwSize=00000019, lpAddr=baae5093 (pid=fff18e61) DDraw:82dc11a8: dwSize=0000001c, lpAddr=baae52c8 (pid=fff18e61) DDraw:82dc1030: dwSize=00000008, lpAddr=baaa1bbc (pid=fff04a0d) DDraw:82dc1fc0: dwSize=00000008, lpAddr=baaa1bbc (pid=fff04a0d) DDraw:82dc1c3c: dwSize=00000008, lpAddr=baaa1bbc (pid=fff00c89) DDraw:Total Memory Unfreed From Current Process = 8 bytes DDraw:====> EXIT: DLLMAIN(baaa12c0): Process Detach fff00c89
Как бы вы ни относились к Visual C++,
приходится признать: это чрезвычайно мощный пакет. В нем объединены
компилятор, компоновщик, отладчик, профайлер и редактор ресурсов — я
перечислил лишь основные компоненты. С каждой новой версией он становится
все больше и мощнее. Однако сказанное относилось только к C++! Сам по
себе Visual C++ является интегрированным компонентом Developer
Studio — многоцелевой и многоязыковой платформы разработчика, с
которой мне никогда не надоедает работать. Лично я — горячий поклонник прекомпилированных
заголовков. Настроить их нетрудно, а компиляция проектов Visual C++
проходит намного быстрее обычного. Если вам придется компилировать большой
проект без прекомпилированных заголовков, то к концу компиляции вы успеете
забыть, что же именно изменилось в вашей программе. Начиная с версии 4.2, Visual C++
содержит DirectX SDK. К сожалению, обычно в Visual C++ входит
относительно старая версия SDK (Visual C++ 4.2 поставляется
с DirectX 2 SDK, а Visual C++ 5.0 — с DirectX 3
SDK). Скорее всего, из-за этого вы будете работать с версией DirectX SDK,
полученной в другом месте (например, на Web-узле Microsoft).
Первый вариант нежелателен, потому
что стандартные файлы Visual C++ обычно не стоит изменять. Кроме
того, вам придется заново копировать файлы с выходом каждой новой версии
Visual C++ или DirectX SDK. ClassView — древовидный элемент окна
рабочей области, в котором отображается список классов, входящих в проект
(он достаточно удобен для перемещения по проекту). Узлы дерева соответствуют
классам; раскрывая их, вы можете просмотреть члены класса. Хотя на первый
взгляд ClassView Visual C++ 5.0 ничем не отличается от предыдущих
версий, на самом деле он ведет себя несколько иначе. Хотя Visual C++ 4.0 не используется
в этой книге напрямую, ничто не помешает вам работать с ним. Но так
как на CD-ROM находятся файлы проектов только для Visual C++ 5.0
(для которого обратная совместимость не предусмотрена), вам придется
создать файлы рабочей области самостоятельно. Это делается так:
Заодно можно настроить прекомпилированные
заголовки (см. выше ). Проект готов к компиляции.
И последнее замечание о Visual C++. Поскольку этот продукт выпускается в трех вариантах (Learning, Professional и Enterprise), иногда читателям не удается скомпилировать проект. Для написания и тестирования программ этой книги я пользовался вариантом Professional, так что при работе с другими вариантами могут возникнуть проблемы. Впрочем, в основном это проблемы мелкие и легко излечимые. Если у вас возникнут трудности и вы решите обратиться ко мне, пожалуйста, укажите версию и вариант Visual C++.
В этом разделе рассматривается несколько
не связанных друг с другом, но полезных тем. Сначала мы поговорим об
одной ошибке DirectDraw, а затем узнаем кое-что о файлах DirectX. Напоследок
я скажу пару слов о видеокартах на базе чипов 3Dfx. Ошибка переключения режимов DirectDraw В DirectDraw есть одна ошибка, связанная
с переключением режимов, которую никак не может исправить Microsoft
(или тот, кто для них пишет видеодрайверы). Впервые я столкнулся с ней
во время работы над предыдущей книгой. Я надеялся, что к моменту написания
этой книги ошибку уже исправят, но она так и осталась. DDHEL: ChangeDisplaySettings LIED!!! DDHEL: Wanted 640x480x16 got 1024x768x8 DDHEL: ChangeDisplaySettings FAILED: returned -1 К счастью, это происходит только при
первой попытке изменения видеорежима. Если эта попытка удалась, после
этого можно установить любой видеорежим. Следовательно, у нас появляется
обходной путь: если текущий видеорежим отличается по глубине пикселей
от желаемого, переключение следует производить в два этапа; сначала
перейдите к видеорежиму, который совпадает по глубине пикселей с текущим,
а затем — к видеорежиму, нужному вам. int SampleWin::SelectInitialDisplayMode() { DWORD curdepth=GetDisplayDepth(); int i, nummodes=GetNumDisplayModes(); DWORD w,h,d; if (curdepth!=16) ddraw2->SetDisplayMode(640, 480, curdepth, 0, 0 ); // Искать режим 640x480x16 после смены видеорежима for (i=0;i>nummodes;i++) { GetDisplayModeDimensions( i, w, h, d ); if (w==640 && h==480 && d==16) return i; } return -1; } Мы проверяем глубину пикселей текущего
видеорежима Windows функцией DirectDrawWin::GetDisplayDepth()
. Нас интересует режим с 16-битными пикселями, поэтому при использовании
другой глубины мы активизируем режим 640x480 с текущей глубиной, вызывая
функцию SetDisplayMode() интерфейса DirectDraw . Затем
можно переходить к поиску нужного режима в традиционном цикле. int SwitchWin::SelectInitialDisplayMode() { DWORD curdepth=GetDisplayDepth(); int i, nummodes=GetNumDisplayModes(); DWORD w,h,d; // Искать режим 640x480 с текущей глубиной пикселей for (i=0;i<nummodes;i++) { GetDisplayModeDimensions( i, w, h, d ); if (w==640 && h==480 && d==curdepth) return i; } return 0; } Эта функция ищет режим 640x480 с текущей
глубиной пикселей. Такой режим наверняка найдется, потому что 640x480 —
«общий знаменатель» для всех видеорежимов и нам известно, что нужная
глубина пикселей уже установлена в Windows. Как вы уже знаете, библиотека DirectX
построена на базе спецификации COM, а для однозначной и систематизированной
идентификации интерфейсов в COM применяются GUID. Один из заголовочных
файлов COM содержит код, в котором инициализируются все конструкции,
относящиеся к GUID. Такой метод инициализации COM требует, чтобы символическая
константа INITGUID была определена в одном и только одном кодовом
модуле, до включения заголовочных файлов COM (для DirectX заголовочные
файлы COM включаются косвенно, из заголовочных файлов DirectX). Следовательно,
в некоторых программах можно встретить константу INITGUID .
Этот метод вызывает немало хлопот, особенно при работе с прекомпилированными
заголовками, потому что он не позволяет включить заголовочные файлы
DirectX в состав прекомпилированного заголовка. Одна из широко разрекламированных возможностей
COM — управление версиями. COM-объекты устроены так, что доступ
к ним может осуществляться только через строго определенные интерфейсы.
В соответствии с правилами COM, интерфейс не может изменяться после
его определения. Вместо этого приходится вводить новый интерфейс, который
поддерживает как старые, так и новые возможности. При этом новые программы
могут без опасений пользоваться новыми возможностями, а старые —
работать со старыми интерфейсами, которые заведомо не изменятся. Эта
схема неплохо работает и помогает обеспечить совместимость приложений
DirectX со старыми и новыми runtime-частями библиотеки.
Коммерческие программы (особенно пакеты,
распространяемые на CD-ROM) в основном используют первый вариант. Он
прост и позволяет всегда работать с новейшими возможностями DirectX.
С другой стороны, runtime-часть DirectX 5 занимает 135 Мбайт.
Это значит, что для настоящего продукта на CD-ROM остается меньше места,
или вам придется поставлять дополнительный диск с DirectX. Разумеется,
этот вариант не подходит для приложений, распространяемых без CD-ROM
или через Internet. #define DIRECTDRAW_VERSION 0x300 #include <ddraw.h> то определяемые структуры будут идентичны
тем, что определялись в DirectX 3 SDK, даже если на самом
деле вы работаете с DirectX 5 SDK. Я уже написал две книги, в которых
используется DirectX, и большинство вопросов от читателей было связано
с DirectX SDK. Одни жаловались на то, что SDK не прилагается к
книге, а другие просто хотели знать, где его можно достать. Я отвечал,
что DirectX SDK можно бесплатно получить на
Web-узле Microsoft . |
Дизайн и техническая
поддержка: Мишин Олег (mishinoleg@mail.ru)
При использовании информации ссылка на автора обязательна. Коммерческое использование информации без согласия автора запрещается. |