6. После всех манипуляций окно Solution Explorer должно иметь следующий вид (рис.4).
Для редактирования произведите двойной щелчок мышью на именах функций. Введите следующий текст в файлы MyFunction.h и MyFunction.ccp: // #include "afx.h" MFC не используется ////////////////////////////MyFunction.h//////////////////////// extern "C" LONG PASCAL EXPORT AddLong(LPLONG a,LPLONG b); extern "C" void PASCAL EXPORT DrawCircl(HWND hOkna); ////////////////////////////MyFunction.ccp///////////////////// #include "StdAfx.h" //Необходимые директивы препроцессора #include "MyFunction.h" extern "C" LONG PASCAL EXPORT AddLong(LPLONG a,LPLONG b) { return (*a + *b); } extern "C" void PASCAL EXPORT DrawCircl(HWND hOkna) { ::HDC hdc = ::GetDC(hOkna); ::Ellipse(hdc,10,10,50,50); ::ReleaseDC(hOkna, hdc); } Редактированию необходимо подвергнуть и файл VCDLLVB.def, в нем хранятся имена экспортируемых функций. Так должен выглядеть этот файл: ; VCDLLVB.def : Declares the module parameters for the DLL. LIBRARY "VCDLLVB" EXPORTS ; Explicit exports can go here AddLong DrawCircl 7. Измените режим компиляции с Debug на Release и выполните команду Build/Build VCDLLVB. В результате (если этап компиляции пройдет успешно) в папке “Release” проекта появится файл VCDLLVB.DLL. (файлы проекта в архиве исходного кода Graphics1). Теперь эту библиотеку можно протестировать в VB. 8. Для создания тестового
приложения запустите VB и создайте проект Standard EXE.
Введите следующий код: Option Explicit Private Declare Function Ellipse& Lib "gdi32" (ByVal hDC As Long, ByVal X1 As Long, _ ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) Private Declare Function AddLong Lib "VCDLLVB.DLL" (ByRef v1 As Long, _ ByRef v2 As Long) As Long Private Declare Sub DrawCircl Lib "VCDLLVB.DLL" (ByVal hWND As Long) Private Sub Form_Load() Dim L As Long Dim L1 As Long Dim L2 As Long L1 = 2 L2 = 1 Text1.Text = AddLong(L2, L1) End Sub Private Sub Command1_Click() DrawCircl Form1.hWND End Sub Private Sub Command2_Click() Ellipse Form1.hDC, 10, 50, 50, 90 End Sub 9. Сохраните проект. Поместите файл VCDLLVB.DLL в папку проекта (файлы проекта см. Graphics1). Если запустить приложение на выполнение и нажать в появившейся форме кнопки, его вид должен соответствовать рис. 6.
10. Оба круга нарисованы одной и той же функцией Win32 API, а число три получилось сложением внутри DLL параметров, переданных по ссылке из VB. В прототипе функции для сложения AddLong явно указано, с помощью ключевого слова ByRef, что мы передаем значение по ссылке. Единственный параметр функции для рисования круга в DrawCircl объявлен как ByVal, то есть параметр передается по значению. В прототипе API функции Ellipse первый параметр имеет вид ByVal hDC, значит он тоже передается по значению. Оба параметра являются описателями – первый окна(формы), а второй контекста устройства. Использование описателей находится под контролем ядра Windows, а в параметрах функций API они передаются как обычные 32-разрядные числа, поэтому и применяется ByVal. Для программирования с помощью команды Declare нужно только разобраться с передачей параметров из VB в API-функции. Рассмотрим простой пример работы с графическими функциями API в среде Visual Basic (файлы проекта см. Graphics2). Создайте проект типа Standard EXE. Поместите в форму четыре кнопки. Введите в раздел General после Option Explicit следующий код: Option Explicit Dim Lim As Long Dim BackVal As Long Dim RecordDC As Long Dim DCWin As Long Dim WindHandle As Long Dim DCPicture As Long Private Type POINTAPI X As Long Y As Long End Type Private ArrayPoint() As POINTAPI Private Declare Function CreateSolidBrush& Lib "gdi32" (ByVal crColor As Long) Private Declare Function SelectObject& Lib "gdi32" (ByVal hDC As Long, ByVal hObject As Long) Private Declare Function DeleteObject& Lib "gdi32" (ByVal hObject As Long) Private Declare Function SaveDC& Lib "gdi32" (ByVal hDC As Long) Private Declare Function RestoreDC& Lib "gdi32" (ByVal hDC As Long, ByVal nSavedDC As Long) Private Declare Function SetPixel& Lib "gdi32" (ByVal hDC As Long, ByVal X As Long, _ ByVal Y As Long, ByVal crColor As Long) Private Declare Function GetWindowDC& Lib "user32" (ByVal hwnd As Long) Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDC As Long) _ As Long Private Declare Function Rectangle& Lib "gdi32" (ByVal hDC As Long, ByVal X1 As Long, _ ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) Private Declare Function Polygon& Lib "gdi32" (ByVal hDC As Long, lpPoint As _ POINTAPI, ByVal nCount As Long) Обратите внимание на пользовательский тип POINTAPI. Так как объявление Type POINTAPI можно считать синонимом структуры в языке C, значит Private ArrayPoint() As POINTAPI – это массив структур в которых будут хранятся координаты точек для функции API Polygon, которая принимает по ссылке (по умолчанию в VB параметры передаются по ссылке) в качестве параметра указатель(адрес) на массив структур POINTAPI. Аналогичная функция на C выглядит следующим образом - Polygon(HDC hdc, CONST POINT*ipPoints, int nCount), а массив структур POINT, указатель на который ей надо передать, можно создать так - POINT points[5]={0x,0y,1x,1y,2x,2y,3x,3y,4x,4y}. Переменная int nCount указывает на число используемых вершин в многоугольнике. В обработчики событий формы введите следующий код: Private Sub Form_Load() Lim = 0 WindHandle = Form1.hwnd DCPicture = Form1.hDC End Sub Private Sub Form_Paint() Dim oldBrush As Long Dim BrushBlue As Long Dim iCount As Long Dim iCountX As Long Dim iCountY As Long BrushBlue = CreateSolidBrush(QBColor(11)) oldBrush = SelectObject&(DCPicture, BrushBlue) For iCount = 0 To 15 Step 1 iCountX = iCountX + Lim For iCountX = iCountX To iCountX + 5 Step 1 SetPixel DCPicture, iCountX, 25, QBColor(iCount) For iCountY = 26 To 38 Step 1 SetPixel DCPicture, iCountX, iCountY, QBColor(iCount) Next iCountY Next iCountX Next iCount Rectangle Form1.hDC, 3, 3, 290, 20 BrushBlue = SelectObject&(DCPicture, oldBrush) BackVal = DeleteObject&(BrushBlue) End Sub Private Sub Command1_Click() DCWin = GetWindowDC(WindHandle) Rectangle DCWin, 3, 3, 290, 20 ReleaseDC WindHandle, DCWin End Sub Private Sub Command2_Click() Lim = Lim + 1 Form1.Refresh End Sub Private Sub Command3_Click() Lim = Lim - 1 Form1.Refresh End Sub Private Sub Command4_Click() Dim oldBrush As Long Dim BrushRed As Long ReDim Preserve ArrayPoint(4) ArrayPoint(0).X = 3 ArrayPoint(0).Y = 89 ''''' ArrayPoint(1).X = 151 ArrayPoint(1).Y = 101 ''''' ArrayPoint(2).X = 295 ArrayPoint(2).Y = 84 ''''' ArrayPoint(3).X = 301 ArrayPoint(3).Y = 130 ''''' ArrayPoint(4).X = 25 ArrayPoint(4).Y = 115 BrushRed = CreateSolidBrush(QBColor(12)) oldBrush = SelectObject&(DCPicture, BrushRed) Polygon DCPicture, ArrayPoint(0), 5 BrushRed = SelectObject&(DCPicture, oldBrush) BackVal = DeleteObject&(BrushRed) End Sub Обратите внимание на код в обработчике
события Private Sub Command4_Click(). В нем происходит передача массива
структур функции Polygon. Контекст устройства хранится в глобальной переменной
DCPicture, ее инициализация происходит в событии Private Sub Form_Load.
Если теперь передвинуть форму за левый край экрана, а потом вернуть восстановятся только те графические элементы, которые были помещены в событии Private Sub Form_Paint() (рис.8) . Цветные столбики нарисованы в тройном
вложенном цикле и выводятся по одной точке(пикселю) функцией SetPixel
DCPicture, iCountX, iCountY, QBColor(iCount).
Найдите в примере строку Form1.Refresh – это значит, что событие Form_Paint применяется ко всей форме. Если форма будет с большим количеством графики чем сейчас Вы заметите нежелательное дрожание(которое и сейчас заметно). Для перерисовки только ограниченной части формы (например прямоугольной области вокруг цветных столбиков) воспользуйтесь функцией Private Declare Function InvalidateRect& Lib "user32" (ByVal hwnd As Long, lpRect As RECT, ByVal bErase As Long). После этого красный многоугольник перестанет исчезать при нажатии на кнопку “Плюс”, а дрожание всей формы исчезнет. Пример офисного программирования В завершении темы GDI32 и Visual Basic
приводится пример офисного программирования с использованием очень простой
базы данных созданной в Microsoft Access 97. Данные из БД согласуются с картой
небольшого города (например Соснового Бора Ленинградской области с населением
около 70 тыс. человек).
В папку WINDOWS/FONTS необходимо
поместить файл с шрифтом TC05002T, так как при создании рисунка в формате WMF(из
которого состоит карта) в некоторых надписях был применен этот шрифт.
Приведу только некоторые пояснения: Public Declare Function SetMapMode& Lib "gdi32" (ByVal hDC As Long, ByVal nMapMode As Long)
Public Declare Function SetWindowExtEx& Lib "gdi32" (ByVal hDC As Long, ByVal nX As _
Long, ByVal nY As Long, lpSize As SIZE)
Public Declare Function SetWindowOrgEx& Lib "gdi32" (ByVal hDC As Long, ByVal nX As _
Long, ByVal nY As Long, lpPoint As POINTAPI)
Public Declare Function SetViewportExtEx& Lib "gdi32" (ByVal hDC As Long, ByVal nX _
As Long, ByVal nY As Long, lpSize As SIZE)
Public Declare Function SetViewportOrgEx& Lib "gdi32" (ByVal hDC As Long, ByVal nX _
As Long, ByVal nY As Long, lpPoint As POINTAPI)
Public Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDC As Long, ByVal nIndex _
As Long) As Long
DirectXВ API GDI32 предусмотрены функции для работы с изображениями на основе массива пикселей, но для быстрой работы с битовой графикой Microsoft предлагает API DirectX, основанный на технологии COM. Хорошую основу для изучения DirectX7 в среде VB закладывают статьи Сергея Никифорова представленные на сайте http://www.vbstreets.ru.В седьмой версии DirectX за работу с битовой графикой отвечает интерфейс DirectDraw. Гнаться за последней версией DirectX(версии 8, 9 и выше) совсем не обязательно, так как имеет большое значение аппаратная поддержка (последней версии шейдеров) этой технологии видео картами, установленными в компьютеры пользователей, использующих Ваши программы.
Для работы с DirectX часто достаточно только интерфейса отвечающего за битовую графику, а именно DirectDraw. Инициализация DirectDraw требует ряда поэтапных стандартных действий, описанных в приведенной ниже простой программе.
2. Введите в раздел General после Option Explicit следующий код: Option Explicit Dim dx As New DirectX7 Dim dd As DirectDraw7 Dim di As DirectInput ''''''''''''''''''''' Dim diDev As DirectInputDevice Dim diState As DIKEYBOARDSTATE ''''''''''''''''''''' Dim Prim As DirectDrawSurface7 Dim PrimBufer As DirectDrawSurface7 Dim OsnovaBMP As DirectDrawSurface7 Dim SpriteBMP As DirectDrawSurface7 ''''''''''''''''''''' Dim ddsdPrim As DDSURFACEDESC2 Dim ddsdPrimBufer As DDSURFACEDESC2 Dim ddsdOsnovaBMP As DDSURFACEDESC2 Dim ddsdSpriteBMP As DDSURFACEDESC2 Dim ddsdcapsPrimBufer As DDSCAPS2 '''''''''''''''''''' Dim Key As DDCOLORKEY В переменной dx хранится ссылка на
“верхний” объект – собственно на всю библиотеку DirectX7. Объектная переменная
dd нужна для получения доступа к сервисам предоставляемым интерфейсом
DirectDraw, а переменная di для доступа к DirectInput – интерфейсу
обеспечивающему работу мыши и клавиатуры. Private Sub Form_Load() Set dd = dx.DirectDrawCreate("") Set di = dx.DirectInputCreate() Set diDev = di.CreateDevice("GUID_SysKeyboard") '''''''''''''''''''''' dd.SetCooperativeLevel Me.hWnd, DDSCL_FULLSCREEN _ Or DDSCL_ALLOWMODEX Or DDSCL_EXCLUSIVE dd.SetDisplayMode 800, 600, 16, 0, DDSDM_DEFAULT '''''''''''''''''''''' diDev.SetCommonDataFormat (DIFORMAT_KEYBOARD) diDev.SetCooperativeLevel Form1.hWnd, DISCL_NONEXCLUSIVE _ Or DISCL_BACKGROUND diDev.Acquire '''''''''''''''''''''' ddsdPrim.lFlags = DDSD_CAPS Or DDSD_BACKBUFFERCOUNT ddsdPrim.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE _ Or DDSCAPS_FLIP Or DDSCAPS_COMPLEX ddsdPrim.lBackBufferCount = 1 Set Prim = dd.CreateSurface(ddsdPrim) '''''''''''''''''''''' ddsdcapsPrimBufer.lCaps = DDSCAPS_BACKBUFFER Set PrimBufer = Prim.GetAttachedSurface(ddsdcapsPrimBufer) PrimBufer.GetSurfaceDesc ddsdPrimBufer '''''''''''''''''''''' ddsdOsnovaBMP.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH ddsdOsnovaBMP.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN ddsdOsnovaBMP.lWidth = 800 'ddsdPrimBufer.lWidth ddsdOsnovaBMP.lHeight = 600 'ddsdPrimBufer.lWidth Set OsnovaBMP = dd.CreateSurfaceFromFile(App.Path & "\Osnova.bmp", ddsdOsnovaBMP) '''''''''''''''''''''' ddsdSpriteBMP.lFlags = DDSD_CAPS ddsdSpriteBMP.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Set SpriteBMP = dd.CreateSurfaceFromFile(App.Path & "\Fase.bmp", ddsdSpriteBMP) '''''''''''''''''''''' Key.low = 0 Key.high = 0 SpriteBMP.SetColorKey DDCKEY_SRCBLT, Key Dim Kvadrat As RECT Dim Kvadrat1 As RECT Kvadrat.Top = 0 Kvadrat.Left = 0 Kvadrat.Bottom = 600 'ddsdPrimBufer.lHeight Kvadrat.Right = 800 'ddsdPrimBufer.lWidth Kvadrat1.Top = 0 Kvadrat1.Left = 0 Kvadrat1.Bottom = ddsdSpriteBMP.lHeight Kvadrat1.Right = ddsdSpriteBMP.lWidth PrimBufer.BltFast 0, 0, OsnovaBMP, Kvadrat, DDBLTFAST_WAIT 'PrimBufer.BltFast 50, 50, OsnovaBMP, Kvadrat, DDBLTFAST_WAIT PrimBufer.BltFast 0, 0, SpriteBMP, Kvadrat1, DDBLTFAST_SRCCOLORKEY Or DDBLTFAST_WAIT Prim.Flip Nothing, DDFLIP_WAIT End Sub В первой части кода приведенного в событии Form_Load производится инициализация объектных переменных dd,di и diDev. Интерфейс доступ к которому предоставляет переменная diDev отвечает в данном случае за клавиатуру (флаг GUID_SysKeyboard). От di можно так же “родить” мышь и джойстик которые являются устройствами (DEVICE) поддерживаемыми технологией DirectX(тип - Dim diDev As DirectInputDevice ).
В функции SetCooperativeLevel устанавливается разрешение экрана 800/600 пикселей и цветовой режим 16 бит на пиксель.
Найдите функции Set OsnovaBMP =
dd.CreateSurfaceFromFile(App.Path & "\Osnova.bmp", ddsdOsnovaBMP) и Set
SpriteBMP = dd.CreateSurfaceFromFile(App.Path & "\Fase.bmp", ddsdSpriteBMP),
прежде чем ими воспользоваться и загрузить массивы пикселей в память из
файлов, необходимо создать поверхности с которыми может работать DirectDraw
(тип - DirectDrawSurface7). В данном примере будет четыре поверхности: Dim
Prim As DirectDrawSurface7-первичная поверхность; Dim PrimBufer As
DirectDrawSurface7- буфер прикрепленный к первичной поверхности на котором в
памяти строится картинка перед выводом; Dim OsnovaBMP As DirectDrawSurface7 -
картинка для фона созданная из файла (Osnova.bmp); Dim SpriteBMP As
DirectDrawSurface7 - картинка для лица человечка (Fase.bmp). Private Sub Timer1_Timer() Dim iKeyCounter As Integer Dim Kvadrat As RECT Dim Kvadrat1 As RECT Kvadrat.Top = 0 Kvadrat.Left = 0 Kvadrat.Bottom = 600 'ddsdPrimBufer.lHeight Kvadrat.Right = 800 'ddsdPrimBufer.lWidth Kvadrat1.Top = 0 Kvadrat1.Left = 0 Kvadrat1.Bottom = ddsdSpriteBMP.lHeight Kvadrat1.Right = ddsdSpriteBMP.lWidth diDev.GetDeviceStateKeyboard diState If diState.Key(2) Then '1'<> 0 Then PrimBufer.BltFast 0, 0, OsnovaBMP, Kvadrat, DDBLTFAST_WAIT PrimBufer.BltFast 100, 100, SpriteBMP, Kvadrat1, DDBLTFAST_SRCCOLORKEY Or DDBLTFAST_WAIT Prim.Flip Nothing, DDFLIP_WAIT End If If diState.Key(3) Then '1'<> 0 Then PrimBufer.BltFast 0, 0, OsnovaBMP, Kvadrat, DDBLTFAST_WAIT PrimBufer.BltFast 0, 0, SpriteBMP, Kvadrat1, DDBLTFAST_SRCCOLORKEY Or DDBLTFAST_WAIT Prim.Flip Nothing, DDFLIP_WAIT End If End Sub Нажимая на клавиши “1” и “2” лицо человечка будет перемещаться. Обратите внимание, что один глаз у человечка “закрыт”. Происходит это потому, что прозрачными будут только черные пиксели файла из файла Fase.bmp. Отвечает за прозрачность черного цвета следующий код: Key.low = 0 Key.high = 0 SpriteBMP.SetColorKey DDCKEY_SRCBLT, Key 5. Что бы безопасно выйти из приложения, с помощью клавиши “Esc”, добавьте следующий обработчик : Private Sub Form_KeyPress(KeyAscii As Integer) If KeyAscii = 27 Then diDev.Unacquire dd.RestoreDisplayMode dd.SetCooperativeLevel Me.hWnd, DDSCL_NORMAL End End If End Sub Если не хотите связываться с DirectInput
обработку нажатия клавиш для перемещения человечка можно поместить в событие
Form_KeyPress (коды клавиш: “Esc”- код 27; “1”- код 49; ”2”- код 50). На
рис. 12 представлено работающее приложение, описанное выше, оно не
предусматривает наличие привычного для Windows-программы окна (файлы проекта
см. Graphics4).
Оконные приложения DirectXДля создания оконных приложений DirectX, последовательность действий должна быть несколько иной. Приведем простой пример приложения DirectX обладающего окном(файлы проекта см. Graphics5). Приложение в работе представлено на рис. 13 и 14.
При нажатии на кнопку “PageUp”(стрелка вверх) винтовка начинает стрелять. Как и для безоконного приложения для каждого спрайт нужно создать поверхность. Для спрайта выстрела создается последовательность рисунков. На рис. 15 представлена последовательность из файла “gun.bmp”.
Полностью код приложения Вы можете просмотреть в среде Visual Basic. Приведем ключевые моменты. Основные глобальные объекты создаются как было показано в прошлом примере, но отсутствует DirectInput. Добавляется глобальное объявление переменной Dim objDDClip As DirectDrawClipper которая инициализируется в событии Form_Load: Call objDD.SetCooperativeLevel(Me.hWnd, DDSCL_NORMAL) ddsdScreen.lFlags = DDSD_CAPS ddsdScreen.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Set objDDScreen = objDD.CreateSurface(ddsdScreen) Set objDDClip = objDD.CreateClipper(0) objDDClip.SetHWnd Picture1.hWnd objDDScreen.SetClipper objDDClip Это нужно для
ограничения области вывода графики прямоугольной областью которое занимает окно
(так как приложение оконное). Обратите внимание как изменились флаги в функции
SetCooperativeLevel, а так же на вызов функции SetClipper через объект
поверхности objDDScreen (которой соответствует первичная поверхность Prim из
прошлого примера). После считывания этого кода приложение знает о существовании
и размерах окна на которое выводится графика. Пример тренажера технического процессаВ следующем примере на этом принципе построено приложения которое может являться прототипом несложного тренажера или системой подсказки оператора, управляющего техническим процессом. Приведем относительно простой пример - за основу возьмем ввод в действие гипотетической атомного установки. Экран программы приведен на рисунке 16(файлы проекта см. Graphics6).
Код этой программы имеет значительный размер по сравнению с приложениями приведенными ранее, поэтому рассмотрим только некоторые из его отличительных особенностей. Программа разделена на четыре модуля – модуль инициализации DirectDraw; модуль для всех функций BltFast выводящих спрайты на буфер; модуль для объявления функций API, переменных и структур(тип RECT и POINTAPI); модуль в котором находится стартовая функция Main(), загружается форма и включается “бесконечный” цикл Do While. Программа состоит из трех форм Visual Basic. Первая форма реагирует на стандартные события мыши и клавиатуры, на ней так же установлены два таймера(имитируют многопоточность). Две другие формы служат хранилищами ресурсов графики.
Ресурсы нужны для создания поверхностей DirectDraw. В каталоге приложения Вы не найдете файлов типа *.BMP и соответственно поверхности не могут быть созданы с помощью функции CreateSurfaceFromFile, в место этого применен функция CreateSurface. В тексте программы это выглядит так: ddsdResBMP.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH ddsdResBMP.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN ddsdResBMP.lWidth = 742 ddsdResBMP.lHeight = 313 Set ResBMP = dd.CreateSurface(ddsdResBMP) ddrDC1 = ResBMP.GetDC() BitBlt ddrDC1, 0, 0, 742, 313, Form3.hDC, 0, 0, &HCC0020 ResBMP.ReleaseDC ddrDC1 Как видите и у поверхности DirectDraw имеется контекст устройства. Получить доступ к ресурсам вспомогательных форм можно было бы и таким способом: MBM = CreateCompatibleBitmap(Form2.hDC, 800, 600) 'Образ в памяти MDC = CreateCompatibleDC(Form2.hDC) 'Создание контекста BitBlt(ddrDC1, 216, 58, 65, 130, MDC, 64, 0, &HCC0020). В этом случае в памяти создается образ из
массива пикселей на основе которого строится совместимый контекст памяти,
передаваемый функции API BitBlt. Эта функция заполняет поверхность DirectDraw
пикселями. With MassivTotsek2(0) .x = ((Cos(ugpovRes1 / 180 * 3.14) * -2) - (Sin(ugpovRes1 / 180 * 3.14) * 10)) + 475 'CLng(0) .y = ((Sin(ugpovRes1 / 180 * 3.14) * -2) + (Cos(ugpovRes1 / 180 * 3.14) * 10)) + 554 'CLng(-30) 'вверх End With With MassivTotsek2(1) .x = ((Cos(ugpovRes1 / 180 * 3.14) * 0) - (Sin(ugpovRes1 / 180 * 3.14) * 30)) + 475 ' - 74 'CLng(30) 'право .y = ((Sin(ugpovRes1 / 180 * 3.14) * 0) + (Cos(ugpovRes1 / 180 * 3.14) * 30)) + 554 '- 74 'CLng(30) 'вниз End With ''''' With MassivTotsek2(2) .x = ((Cos(ugpovRes1 / 180 * 3.14) * 2) - (Sin(ugpovRes1 / 180 * 3.14) * 10)) + 475 ' - 74 'CLng(30) 'право .y = ((Sin(ugpovRes1 / 180 * 3.14) * 2) + (Cos(ugpovRes1 / 180 * 3.14) * 10)) + 554 '- 74 'CLng(30) 'вниз End With Все навыки которые Вы получите изучая
графические примитивы GDI с большой пользой можно использовать и в DirectDraw.
Если бы не удалось воспользоваться GDI для рисования стрелок, пришлось бы
применять спрайт для каждого положения шкалы кругового прибора или “придумывать
математику” вращения изображения попиксельно, а без искажений сделать это очень
трудно.
Работа с файлами трехмерной графики *.Х По мимо вывода битовой графики технология
DirectX обладает интерфейсами, реализующими работу с трехмерными объектами. В
этой статье будут рассмотрены только возможности DirectX по работе с популярным
форматом файла трехмерной графики *.X. Самое замечательное, что готовую
трехмерную сцену можно нарисовать в программах типа 3D Studio/MAX или LightWawe.
Главное чтобы программа которую Вы используете для создания трехмерной графики
могла экспортировать сцену в файл формата *.3DS. После создания файла *.3DS его
легко перевести с помощью утилиты “conv3ds” в формат .X, который “понимает”
интерфейс Direct3D Retained Mode.
Инициализация D3DRM (как и DirectDraw) требует ряда поэтапных стандартных действий, описанных в приведенной ниже простой программе(файлы проекта см. Graphics7). 1. Создайте проект Standard EXE. Добавьте в форму элемент
PictureBox. Подключите к проекту библиотеку типов DirectX(как и для DirectDraw -
Project/References/DirectX7 for VB Type Library). Option Explicit Public DxVer7 As New DirectX7 'Самый главный Public DDrawVer7 As DirectDraw7 '''''''''''''''''''''''''''''''''' Public D3DRMVer3 As Direct3DRM3 'Для основной работы и -.X Public UstrRender As Direct3DRMDevice3 'Устр Рендеринга Public Viewport As Direct3DRMViewport2 ' Public BuilderKubik As Direct3DRMMeshBuilder3 Public BuilderSar As Direct3DRMMeshBuilder3 Public Scene As Direct3DRMFrame3 Public Camera As Direct3DRMFrame3 Public Kubik As Direct3DRMFrame3 Public Sar As Direct3DRMFrame3 Public SvetFrm As Direct3DRMFrame3 Public Svet As Direct3DRMLight '''''''''''''''''''''''''''''''''' Public OtsetsenieWndCliper As DirectDrawClipper Public Sub IniVseObjectDX7(VBPict As PictureBox) Set DDrawVer7 = DxVer7.DirectDrawCreate("") 'Первый всегда DDraw Set D3DRMVer3 = DxVer7.Direct3DRMCreate 'Создаем 3DRM ''''''''''''''''''''''''''''''''''''''''''''''''''''' Set OtsetsenieWndCliper = DDrawVer7.CreateClipper(0) 'Так как прилоение оконное With VBPict OtsetsenieWndCliper.SetHWnd .hWnd ''''''''''''''''''''''''''''''''''''''''''''''''''''' Set UstrRender = D3DRMVer3.CreateDeviceFromClipper(OtsetsenieWndCliper, _ "", .ScaleWidth, .ScaleHeight) UstrRender.SetQuality D3DRMRENDER_GOURAUD Set Scene = D3DRMVer3.CreateFrame(Nothing) 'Родитель для камеры Scene.AddLight D3DRMVer3.CreateLight(D3DRMLIGHT_AMBIENT, _ DxVer7.CreateColorRGB(0, 1, 0)) 'Создали свет для Scene Set Camera = D3DRMVer3.CreateFrame(Scene) 'Прекрепляем камеру к порту просмотра Set Kubik = D3DRMVer3.CreateFrame(Scene) Set Sar = D3DRMVer3.CreateFrame(Scene) ''''''''''Svet Set SvetFrm = D3DRMVer3.CreateFrame(Scene) Set Svet = D3DRMVer3.CreateLightRGB(D3DRMLIGHT_DIRECTIONAL, 4, 0, 0) SvetFrm.AddLight Svet Set Viewport = D3DRMVer3.CreateViewport(UstrRender, _ Camera, 0, 0, .ScaleWidth, .ScaleHeight) 'Создали порт просмотра End With End Sub Public Sub CreateMyObject() Set BuilderKubik = D3DRMVer3.CreateMeshBuilder BuilderKubik.LoadFromFile App.Path & "\n2.x", 0, D3DRMLOAD_FROMFILE, Nothing, Nothing Kubik.AddVisual BuilderKubik Set BuilderSar = D3DRMVer3.CreateMeshBuilder BuilderSar.LoadFromFile App.Path & "\sar.x", 0, D3DRMLOAD_FROMFILE, Nothing, Nothing BuilderSar.ScaleMesh 0.4, 0.4, 0.4 Sar.AddVisual BuilderSar End Sub Инициализация объектов происходит в
функции которой передается по ссылке окно вывода - Public Sub IniVseObjectDX7(VBPict
As PictureBox). Обратите внимание на присутствии интерфейса DirectDraw который
нужен для создания отсечения. После создания интерфейса DirectDraw создается
интерфейс D3DRM. Он необходим для порождения таких типов как: Direct3DRMDevice3
– устройство рендеринга; Direct3DRMViewport2 – порт просмотра(просмотр привязан
к фрейму камеры); Direct3DRMMeshBuilder3 – “строитель” фрейма в сцене;
Direct3DRMFrame3 –объект обладающий координатами(возможно формой и размерами или
другими характеристиками); Direct3DRMLight – объект для освещения фреймов
имеющих форму. Все фреймы при создании прикрепляются к “главному” фрейму сцены
методом - D3DRMVer3.CreateFrame(Scene). Option Explicit Dim FlagPaint As Long Dim Xp As Long Dim Zp As Long Dim Yp As Long Private Sub Form_Load() Zp = -20 Xp = -5 Yp = -5 Dim Flag As Boolean Flag = True FlagPaint = 0 Show 'Принудительный показ DoEvents ModD3D.IniVseObjectDX7 Picture1 FlagPaint = 1 '''Инициализация закончена''' ''''''Создание объектов'''''' ModD3D.CreateMyObject ''Настройка Kubik.SetColor &HFFFF6060 Kubik.SetMaterialMode D3DRMMATERIAL_FROMFRAME Do While Flag = True DoEvents D3DRMVer3.Tick 1 Camera.SetPosition Scene, 0, 0, -40 Kubik.SetPosition Scene, Xp, Yp, Zp Loop ''''''''''''''''''''''''''''' End Sub Private Sub Picture1_KeyDown(KeyCode As Integer, Shift As Integer) Dim TempVector As D3DVECTOR If KeyCode = 38 Then 'Вверх Zp = Zp + 1 ElseIf KeyCode = 40 Then Zp = Zp - 1 ElseIf KeyCode = 39 Then Xp = Xp + 1 ElseIf KeyCode = 37 Then Xp = Xp - 1 ElseIf KeyCode = 89 Then Yp = Yp + 1 ElseIf KeyCode = 72 Then Yp = Yp - 1 End If End Sub Private Sub Form_Paint() If FlagPaint = 1 Then ModD3D.UstrRender.HandlePaint Picture1.hDC End Sub Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer) Set BuilderKubik = Nothing Set Viewport = Nothing Set Kubik = Nothing Set Svet = Nothing Set SvetFrm = Nothing Set Camera = Nothing Set Scene = Nothing Set UstrRender = Nothing Set OtsetsenieWndCliper = Nothing Set D3DRMVer3 = Nothing Set DDrawVer7 = Nothing End End Sub В разделе формы General, после Option Explicit представлены три переменные для хранения координат кубика. В событии Private Sub Form_Load() вызываются две функции из модуля. Для инициализации объектов D3DRM вызывается ModD3D.IniVseObjectDX7 Picture1, а для загрузки файлов *.X вызывается ModD3D.CreateMyObject. Фрейму кубика назначается красный цвет в строках: Kubik.SetColor &HFFFF6060 Kubik.SetMaterialMode D3DRMMATERIAL_FROMFRAME После функций вступает в работу “бесконечный” цикл. В за один проход “бесконечный” цикл выполняет рендеринг сцены с помощью метода D3DRMVer3.Tick 1. Завершается цикл установкой фреймов камеры и кубика. Камере назначен порт просмотра - через него мы обозреваем сцену. Камера статична, а координаты кубика изменяются кнопками клавиатуры в событии Private Sub Picture1_KeyDown(KeyCode As Integer, Shift As Integer). Кнопки со стрелками перемещают кубик по горизонтали, а кнопки “Y” и “H” по вертикале. На рис. 17, 18 и 19 можно видеть приложение в работе. Рис. 18 показывает, что произойдет если исключить событие Private Sub Form_Paint().
Пример построения трехмерного технического объектаВ заключении приведем пример использования интерфейса D3DRM на базе которого можно построить трехмерное представление технического объекта, например воображаемый отсек подводной лодки. Приложение в работе представлено на рисунке 20 (файлы проекта см. Graphics8).
Перемещение по трехмерной сцене
производится с помощью кнопок клавиатуры. Просмотр осуществляется через фрейм
камеры, но в данном случае камера неподвижна. Фреймы применяются и для
источников освещения. Качеством отображения можно управлять меняя значения “Уд”
и “Хор”(более сглаженные углы).
Важным отличием от предыдущего примера является наличие текстур. На текстурах можно нарисовать элементы, которые придадут больше реализма трехмерной сцене. В данном случае текстуры нанесены на воображаемый пульт управления и переборку между отсеками. Самое сложное правильно растянуть текстуры по объекту. Для текстур используется тип - Direct3DRMTexture3, а для натяжения на объект тип - Direct3DRMWrap. Создать текстуру можно из файла или поверхности DirectDraw(в данном приложении текстура создана из поверхности). Код по созданию и наложению текстуры может иметь вид: Set PultTexture = D3DRMVer3.CreateTextureFromSurface(OsnovaBMP1) 'Set PultTexture = D3DRMVer3.LoadTexture("pult1.bmp") Set RastiaskaPult = D3DRMVer3.CreateWrap(D3DRMWRAP_FLAT, _ Nothing, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0.09, _ 0,1 / 26, 1 / 20) RastiaskaPult.Apply BuilderPult BuilderPult.SetTexture PultTexture
Заключение Среда Visual Basic достаточно проста в
освоении, имеет дружественный и интуитивно понятный интерфейс, одновременно с
этим Visual Basic начиная с версии 5 отвечает запросам самых требовательных
Windows-разработчиков. |