VB:编写DirectX7.0游戏(下)
    2.3 设置显示模式 
  设置显示模式是使用SetDispalyMode函数实现的,函数的定义如下: 
   object.SetDisplayMode( _ 
   w As Long, _ 
   h As Long, _ 
   bpp As Long, _ 
   ref As Long, _ 
   mode As CONST_DDSDMFLAGS) 
  其中参数w、h分别指定屏幕的宽度和高度,bpp指定屏幕显示的颜色位数,参数ref指定屏幕的刷新频率,设置为0使用显示驱动的缺省刷新频率,mode指定附加的参数。要获得系统支持的显示模式,可以使用DirectDraw对象的GetDisplayModesEnum函数来遍历所有支持的显示模式。 
  2.4 建立平面对象 
  一个平面或者说DirectDrawSurface对象是DirectDraw中图形显示和绘制对象。用户可以在DirectDrawSurface上贴位图、绘制图形,还可以直接操作DirectDrawSurface对象使用显存里的内容。利用DirectDraw对象的CreateSurface方法可以建立一个DirectDrawSurface7对象。例如: 
  Public DDSFrontDesc As DDSURFACEDESC2 
   With DDSFrontDesc 
  .lFlags = DDSD_CAPS 
  .ddsCaps.lCaps=DDSCAPS_PRIMARYSURFACE 
   End With 
  Set DDSFront = DDraw.CreateSurface(DDSFrontDesc) 
  也可以利用DirectDraw对象的CreateSurfaceFromFile函数或者CreateSurfaceFromResource函数建立一个DirectDrawSurface7对象,同时将图像文件或者资源文件中的图像装入建立的DirectDrawSurface中。如果上面的函数调用成功,函数将返回一个DirectDrawSurface对象。如果在设定DirectDraw对象的协作层时将其设置为全屏幕模式的话,为了改善图像性能,可以设立一个主平面和若干个屏下缓冲平面,首先在屏下平面中生成图像,然后将图像翻转到主平面上,这样可以有效地避免图像闪烁。 
  下面通过一个具体的范例来对DirectDraw进行说明:这个范例建立一个全屏幕的DirectDraw对象,通过操作主显示平面的显示内存在屏幕上显示火焰字的特效,然后按Enter键可以将DirectDraw平面中的图形保存起来。程序的具体实现如下: 
  建立一个新的工程文件,点击菜单中的 Project | Reference 选项,打开Object Library 列表窗口,将DirectX 7.0 For Visual Basic Type Library 加入工程文件。将Form1的Name属性改变为MainForm,在MainForm中加入一个PictureBox控件,将其的Visible属性设置为False。然后在MainForm的代码窗口中加入以下代码: 
  Private Sub Form_KeyPress(KeyAscii As Integer) 
   Dim sRect As RECT 
   Dim hdcSrc As Long 
   If KeyAscii = 27 Then 
   ExitLoop = True 
   'End 
   ElseIf KeyAscii = vbKeyReturn Then 
  DDSFront.BltToDC Picture1.hDC, sRect, sRect 
   With Picture1 
   '获得与主显示平面兼容的图形设备句柄 
   hdcSrc = DDSFront.GetDC 
   '保存图像 
   Set .Picture = SaveTohBmp(hdcSrc, 0, 0, 640, 480) 
   '释放图形句柄 
   DDSFront.ReleaseDC hdcSrc 
   SavePicture Picture1, “c:\a.bmp” 
   End With 
   End If 
  End Sub 
   
  Public Sub Form_Paint() 
   BlitRect.Right = DDSBackDesc.lWidth 
   BlitRect.Bottom = DDSBackDesc.lHeight 
   DDSFront.Blt BlitRect, DDSBack, BlitRect, DDBLT_WAIT 
  End Sub 
  在工程文件中加入一个Module文件,这个文件中DirectDraw操作做出了定义,在这个Module中加入以下代码: 
  Option Explicit 
  Public DX As New DirectX7 
  Public DDraw As DirectDraw7 
  Public DDSFront As DirectDrawSurface7 
  Public DDSFrontDesc As DDSURFACEDESC2 
  Public DDSBack As DirectDrawSurface7 
  Public DDSBackDesc As DDSURFACEDESC2 
  Public Clipper As DirectDrawClipper 
  Dim Pict() As Byte 
  Dim AlphaRect As RECT 
  Dim X As Long, Y As Long 
  Dim Temp As Long 
  Dim Index As Long 
  Dim Index2 As Long 
  Dim Pos As Long 
  Dim PosPlus1 As Long 
  Dim PosPlus2 As Long 
  Dim PosPlus3 As Long 
  Public Pal(255) As PALETTEENTRY 
  Public Palette As DirectDrawPalette 
  Public BlitRect As RECT 
  Public FullSize As Boolean 
  Public ExitLoop As Boolean 
  Dim Accum As Long 
  Dim Msg(9) As String 
  Dim Counter As Long 
  Dim MsgIndex As Long 
  Dim bDrawText As Boolean 
  Dim lastTime As Long 
  Dim XPos As Long, YPos As Long 
  Dim wait As Long 
  Dim Angle As Single 
  Dim Flag As Boolean 
  Dim Count As Long 
  Dim CurModeActiveStatus As Boolean 
  Dim bRestore As Boolean 
  Dim Mode As Boolean 
  Private Sub Main() 
   InitializeDX 
  '初始化Picture1以获得DirectDraw界面图像 
   With MainForm.Picture1 
   .Width = 640 * Screen.TwipsPerPixelX 
   .Height = 480 * Screen.TwipsPerPixelY 
   End With 
  DDSBack.SetForeColor RGB(255, 255, 255) 
   MainForm.Font.Name = “宋体” 
   DDSBack.SetFont MainForm.Font 
  Msg(0) =“一个显示火焰字的演示” 
  Msg(1) =“演示” 
  Msg(2) =“利用VB阵列” 
  Msg(3) =“对显示内存” 
  Msg(4) =“进行直接存取” 
  Msg(5) =“{Esc}键退出” 
   '设置8位的调色板 
   For Index = 0 To 84 
   Pal(Index + 1).red = Index * 3 + 3 
   Pal(Index + 1).green = 0 
   Pal(Index + 1).blue = 0 
   
   Pal(Index + 86).red = 255 
   Pal(Index + 86).green = Index * 3 + 3 
   Pal(Index + 86).blue = 0 
   
   Pal(Index + 171).red = 255 
   Pal(Index + 171).green = 255 
   Pal(Index + 171).blue = Index * 3 + 3 
   Next 
  Set Palette = DDraw.CreatePalette(DDPCAPS_8BIT _ Or DDPCAPS_ALLOW256, Pal()) 
   DDSFront.SetPalette Palette 
  AlphaRect.Right = DDSBackDesc.lWidth - 1 
  AlphaRect.Bottom=DDSBackDesc.lHeight- 1 
   
   DDSBack.Lock AlphaRect, DDSBackDesc, DDLOCK_WAIT, 0 
   
   DDSBack.GetLockedArray Pict() 
   For X = 0 To 639 
   For Y = 0 To 479 
   Pict(X, Y) = 0 
   Next 
   Next 
   'Corresponding unlock 
   DDSBack.Unlock AlphaRect 
   While Not ExitLoop 
   Mode = ExModeActive 
   bRestore = False 
   Do Until ExModeActive 
   DoEvents 
   bRestore = True 
   Loop 
   DoEvents 
   If bRestore Then 
   bRestore = False 
   DDraw.RestoreAllSurfaces 
   End If 
   DDSBack.Lock AlphaRect, DDSBackDesc, DDLOCK_WAIT, 0 
   DDSBack.GetLockedArray Pict() 
   For Y = 0 To 479 
   Pict(0, Y) = 0 
   Pict(639, Y) = 0 
   Next 
   For X = 0 To 639 
   Pict(X, 477) = Rnd * 220 + 35 
   Pict(X, 478) = Rnd * 220 + 35 
   Pict(X, 479) = Rnd * 220 + 35 
   Next 
   Accum = 0 
   For X = 1 To 638 
   For Y = 0 To 477 
   Accum = (Accum + Pict(X, Y + 1) _ 
   + Pict(X, Y + 2) _ 
   + Pict(X + 1, Y + 1) _ 
   + Pict(X - 1, Y + 1)) \ 5 
   If Accum < 0 Then 
   Accum = 0 
   ElseIf Accum > 255 Then 
   Accum = 255 
   End If 
   Pict(X, Y) = Accum 
   Next 
   Next 
   For X = 0 To 639 
   Pict(X, 0) = 0 
   Pict(X, 1) = 0 
   Next 
   X = Rnd * 639 
   For Y = 50 To 439 
   Next 
   'Unlock 
   DDSBack.Unlock AlphaRect 
  If DX.TickCount() - lastTime > wait Then 
   If Counter = 0 Then 
   bDrawText = True 
   Counter = 1 
   XPos = Rnd * 200 
   YPos = 300 + Rnd * 140 
   wait = 400 
   ElseIf Counter = 1 Then 
   MsgIndex = MsgIndex + 1 
   If MsgIndex > 5 Then MsgIndex = 0 
   bDrawText = False 
   Counter = 0 
   wait = 2000 
   End If 
   lastTime = DX.TickCount 
   End If 
   
   'Draw Text to the backbuffer 
   If bDrawText Then 
   On Error Resume Next 
   DDSBack.DrawText XPos, YPos, Msg(MsgIndex), False 
   On Error GoTo 0 
   End If 
   
   MainForm.Form_Paint 
   Wend 
   TerminateDX 
   End 
  End Sub 
  Function ExModeActive() As Boolean 
   Dim TestCoopRes As Long 
  TestCoopRes = DDraw.TestCooperativeLevel 
   Select Case TestCoopRes 
   Case DDERR_NOEXCLUSIVEMODE 
   ExModeActive = False 
   Case DD_OK 
   ExModeActive = True 
   End Select 
  End Function 
  Public Sub InitializeDX() 
  MainForm.Left = 0 
  MainForm.Top = 0 
  MainForm.Height =640 * Screen.TwipsPerPixelY 
  MainForm.Width = 480 * Screen.TwipsPerPixelX 
  MainForm.Show 
   '建立DirectDraw对象 
   Set DDraw = DX.DirectDrawCreate(“”) 
   '设定DirectDraw对象的协作层 
   DDraw.SetCooperativeLevel MainForm.hWnd, DDSCL_EXCLUSIVE Or DDSCL_FULLSCREEN ' DDSCL_NORMAL 
   '设定显示模式位640×480×8位颜色 
   DDraw.SetDisplayMode 640, 480, 8, 0, DDSDM_DEFAULT 
   
   '设定DDSFrontDesc为主平面 
   With DDSFrontDesc 
  .lFlags = DDSD_CAPS 
  .ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE 'Or DDSCAPS_SYSTEMMEMORY 
   End With 
   '设定DDSBackDesc为后台缓冲平面 
   With DDSBackDesc 
  .ddsCaps.lCaps = DDSCAPS_SYSTEMMEMORY 
  .lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT 
  .lWidth = 640 
  .lHeight = 480 
   End With 
   '建立平面 
   Set DDSFront = DDraw.CreateSurface(DDSFrontDesc) 
   Set DDSBack = DDraw.CreateSurface(DDSBackDesc) 
   Set Clipper = DDraw.CreateClipper(0) 
   Clipper.SetHWnd MainForm.hWnd 
   DDSFront.SetClipper Clipper 
   DDSBack.SetClipper Clipper 
   DoEvents 
   Exit Sub 
  ERRoUT: 
   If Not (DDraw Is Nothing) Then 
   DDraw.RestoreDisplayMode 
   DDraw.SetCooperativeLevel MainForm.hWnd, DDSCL_NORMAL 
   DoEvents 
   End If 
   MsgBox “无法对DirectDraw进行初始化 ”+Chr(13)+“也许你的显示卡不支持 640×480×8 显示模式 ” 
   End 
  End Sub 
  Public Sub TerminateDX() 
   '子程序TerminateDX回复原来的显示模式并且释放所有的DirectDraw有关对象 
   DDraw.RestoreDisplayMode 
   DDraw.SetCooperativeLevel MainForm.hWnd, DDSCL_NORMAL 
   DoEvents 
   Set Clipper = Nothing 
   Set DDSBack = Nothing 
   Set DDSFront = Nothing 
   Set DDraw = Nothing 
   Set DX = Nothing 
  End Sub 
  在工程文件中再加入一个Module,这个Module主要定义与图像保存相关的操作,在建立的Module中加入以下代码: 
   Option Explicit 
  Option Base 0 
  Private Type PALETTEENTRY 
   peRed As Byte 
   peGreen As Byte 
   peBlue As Byte 
   peFlags As Byte 
  End Type 
   
  Private Type LOGPALETTE 
   palVersion As Integer 
   palNumEntries As Integer 
   palPalEntry(255) As PALETTEENTRY ' Enough for 256 colors. 
  End Type 
   
  Private Type GUID 
   Data1 As Long 
   Data2 As Integer 
   Data3 As Integer 
   Data4(7) As Byte 
  End Type 
  Private Const RASTERCAPS As Long = 38 
  Private Const RC_PALETTE As Long = &H100 
  Private Const SIZEPALETTE As Long = 104 
   
  Private Declare Function CreateCompatibleDC Lib “GDI32” (ByVal hDC As Long) As Long 
  Private Declare Function CreateCompatibleBitmap Lib “GDI32” (ByVal hDC As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long 
  Private Declare Function GetDeviceCaps Lib “GDI32” (ByVal hDC As Long, ByVal iCapabilitiy As Long) As Long 
  Private Declare Function GetSystemPaletteEntries Lib “GDI32” (ByVal hDC As Long, ByVal wStartIndex As Long, ByVal wNumEntries As Long, lpPaletteEntries As PALETTEENTRY) As Long 
  Private Declare Function CreatePalette Lib “GDI32”(lpLogPalette As LOGPALETTE) As Long 
  Private Declare Function SelectObject Lib “GDI32”(ByVal hDC As Long, ByVal hObject As Long) As Long 
  Private Declare Function BitBlt Lib “GDI32”(ByVal hDCDest As Long, ByVal XDest As Long, ByVal YDest As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hdcSrc As Long, ByVal XSrc As Long, ByVal YSrc As Long, ByVal dwRop As Long) As Long 
  Private Declare Function DeleteDC Lib “GDI32”(ByVal hDC As Long) As Long 
  Private Declare Function GetForegroundWindow Lib “USER32” () As Long 
  Private Declare Function SelectPalette Lib “GDI32”(ByVal hDC As Long, ByVal hPalette As Long, ByVal bForceBackground As Long) As Long 
  Private Declare Function RealizePalette Lib “GDI32” (ByVal hDC As Long) As Long 
  Private Declare Function GetWindowDC Lib “USER32” (ByVal hWnd As Long) As Long 
  Private Declare Function GetDC Lib “USER32"(ByVal hWnd As Long) As Long 
  Private Declare Function GetWindowRect Lib “USER32”(ByVal hWnd As Long, lpRect As RECT) As Long 
  Private Declare Function ReleaseDC Lib “USER32”(ByVal hWnd As Long, ByVal hDC As Long) As Long 
  Private Declare Function GetDesktopWindow Lib “{USER32"() As Long 
   
  Private Type PicBmp 
   Size As Long 
   Type As Long 
   hBmp As Long 
   hPal As Long
   Reserved As Long 
  End Type 
  Private Declare Function OleCreatePictureIndirect Lib “olepro32.dll” (PicDesc As PicBmp, RefIID As GUID, ByVal fPictureOwnsHandle As Long, IPic As IPicture) As Long 
   
  Public Function SaveTohBmp(ByVal hdcSrc As Long, ByVal LeftSrc As Long, _ 
   ByVal TopSrc As Long, ByVal WidthSrc As Long, ByVal HeightSrc As Long) As Picture 
   
   Dim hDCMemory As Long 
   Dim hBmp As Long 
   Dim hBmpPrev As Long 
   Dim r As Long 
   Dim hPal As Long 
   Dim hPalPrev As Long 
   Dim RasterCapsScrn As Long 
   Dim HasPaletteScrn As Long 
   Dim PaletteSizeScrn As Long 
   Dim LogPal As LOOGPALETTE 
   ' 
   '建立一个内存图形设备句柄 
  hDCMemory=CreateCompatibleDC(hdcSrc) 
  '建立一个bitmap并保存到hDCMemory中 
  hBmp = CreateCompatibleBitmap(hdcSrc, WidthSrc, HeightSrc) 
   hBmpPrev = SelectObject(hDCMemory, hBmp) 
   ' Get screen properties. 
   RasterCapsScrn = GetDeviceCaps(hdcSrc, RASTE图CAPS) 'rRaste 
  ' capablies. 
   HasPaletteScrn = RasterCapsScrn And RC_PALtTTEic1 ' Palette 
  ' support. 
   PaletteSizeScrn = GetDeviceCaps(hdcSrc, SIZEPALETTE) ' Size of 
  ' palette. 
   If HasPaletteScrn And (PaletteSizeScrn = 256) Then 
   '建立系统调色板的拷贝 
   LogPal.palVersion = &H300 
   LogPal.palNumEntries = 256 
   r = GetSystemPaletteEntries(hdcSrc, 0, 256, LogPal.palPalEntry(0)) 
   hPal = CreatePalette(LogPal) 
   hPalPrev = SelectPalette(hDCMemory, hPal, 0) 
   r = RealizePalette(hDCMemory) 
   End If 
   
   '将屏幕图形拷贝到内存图形设备句柄中 
   r = BitBlt(hDCMemory, 0, 0, WidthSrc, HeightSrc, hdcSrc, LeftSrc, TopSrc, vbSrcCopy) 
   
   hBmp = SelectObject(hDCMemory, hBmpPrev) 
   
   If HasPaletteScrn And (PaletteSizeScrn = 256) Then 
   hPal = SelectPalette(hDCMemory, hPalPrev, 0) 
   End If 
   
   '释放图形设备句柄 
   r = DeleteDC(hDCMemory) 
   Debug.Print r 
   
   '调用CreateBitmapPicture函数从指定的bitmap对象和调色板中建立一个picture对象 
   Set SaveTohBmp = CreateBitmapPicture(hBmp, hPal) 
  End Function 
  Public Function CreateBitmapPicture(ByVal hBmp As Long, ByVal hPal As Long) As Picture 
   Dim r As Long 
   Dim Pic As PicBmp 
   Dim IPic As IPicture 
   Dim IID_IDispatch As GUID 
   
   '填充IDispatch界面 
   With IID_IDispatch 
   .Data1 = &H20400 
   .Data4(0) = &HC0 
   .Data4(7) = &H46 
   End With 
   
   '填充Pic结构 
   With Pic 
   .Size = Len(Pic) ' Length of structure. 
   .Type = vbPicTypeBitmap ' Type of Picture (bitmap). 
   .hBmp = hBmp ' Handle to bitmap. 
   .hPal = hPal ' Handle to palette (may be null). 
   End With 
   
   '建立Picture对象 
   r = OleCreatePictureIndirect(Pic, IID_IDispatch, 1, IPic) 
   
   '返回Picture对象 
   Set CreateBitmapPicture = IPic 
  End Function 
  运行程序,在屏幕上会出现一些火焰字的特效,按Enter键可以将屏幕保存到“c:\a.bmp”中,按Esc键退出程序回到Windows。 
  在上面的程序中,程序首先建立一个DirectDraw对象,然后设置该对象的协作层为全屏协作模式,接下来设置显示模式为640×480×8位颜色,建立一个前台DirectDrawSurface对象和一个后台缓冲DirectDrawSurface对象,建立和设置DirectDrawClipper对象。 
  在主程序段中,程序首先对前台绘图平面的调色板(DirectDrawPalette 
  )对象进行操作以改变显示的文字的颜色,然后对后台缓冲绘图平面进行字节操作,以产生文字弥散的效果,然后再将后台缓冲绘图平面翻转到前台。当用户按下Enter键之后,程序获得与前台绘图平面相兼容的图形设备句柄,然后再调用Windows API函数将绘图平面内存中的内容保存到Windows位图文件中。 
  上面粗略地介绍了DirectX7 SDK的新特性以及初步的DirectDraw编程,希望对大家能有所帮助。以上的程序在Windows98、VB6.0下运行通过。 

>


 

回首页