• Welcome to PowerBasic Museum 2020-A.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

DirectX 9 Examples

Started by José Roca, August 28, 2011, 04:32:48 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

José Roca

 
Microsoft DirectX graphics provides a set of APIs that you can use to create games and other high-performance multimedia applications. DirectX graphics includes support for high-performance 2-D and 3-D graphics.


José Roca

 
The following example demonstrates how to initialize Direct3D.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_Initialization.bas
' Contents: DX9 example
' Description: Demonstrates how to initialize Direct3D.
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Initialization"

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      ' // TO DO: Respond to failure of Direct3DCreate9
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Retrieves the current display mode of the adapter
      LOCAL d3ddm AS D3DDISPLAYMODE
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      ' // TO DO: Respond to failure of GetAdapterDisplayMode
      IF hr <> %D3D_OK THEN EXIT METHOD

      hr = m_pD3D.CheckDeviceFormat(%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, _
                                    d3ddm.Format, %D3DUSAGE_DEPTHSTENCIL, _
                                    %D3DRTYPE_SURFACE, %D3DFMT_D16)
      IF FAILED(hr) THEN
         IF hr = %D3DERR_NOTAVAILABLE THEN
            ' // POTENTIAL PROBLEM: We need at least a 16-bit z-buffer!
            EXIT METHOD
         END IF
      END IF

      ' // Do we support hardware vertex processing? if so, use it.
      ' // If not, downgrade to software.
      LOCAL dCaps AS D3DCAPS9
      IF FAILED(m_pD3D.GetDeviceCaps(%D3DADAPTER_DEFAULT, _
                                     %D3DDEVTYPE_HAL, dCaps)) THEN
         ' // TO DO: Respond to failure of GetDeviceCaps
         EXIT METHOD
      END IF

      LOCAL dwBehaviorFlags AS DWORD
      IF dCaps.VertexProcessingCaps <> 0 THEN
         dwBehaviorFlags = %D3DCREATE_HARDWARE_VERTEXPROCESSING
      ELSE
         dwBehaviorFlags = %D3DCREATE_SOFTWARE_VERTEXPROCESSING
      END IF

      ' // Everything checks out - create a simple, windowed device.

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      ' // TO DO: Respond to failure of CreateDevice
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene

      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
         D3DCOLOR_COLORVALUE(0.0!,0.0!,1.0!,1.0!), 1.0!, 0)

      m_pD3DDevice.BeginScene

      ' // Render geometry here...

      m_pD3DDevice.EndScene

      m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)

   END METHOD
   ' =====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   STATIC pWindow AS IWindow        ' // Reference to the IWindow interface

   SELECT CASE wMsg

      CASE %WM_CREATE
         ' // Get a reference to the IWindow interface from the CREATESTRUCT structure
         pWindow = CWindow_GetObjectFromCreateStruct(lParam)
         EXIT FUNCTION

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene
         EXIT FUNCTION

      CASE %WM_KEYDOWN
         SELECT CASE LO(WORD, wParam)
            CASE %VK_ESCAPE
               SendMessage hwnd, %WM_CLOSE, 0, 0
               EXIT FUNCTION
         END SELECT

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to perform alpha-blending in the frame-buffer. The sample renders a textured cube which is alpha-blended into the frame-buffer in such a way as to create a translucent effect.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_AlphaBlendingFrameBuffer.bas
' Contents: DX9 example
' Description: Demonstrates how to perform alpha-blending in the frame-buffer. The sample
' renders a textured cube which is alpha-blended into the frame-buffer in such a way as to
' create a translucent effect.
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from dx9_alpha_blending_framebuffer.cpp, by Kevin Harris, 25 Mar 2005,
' downloadable at http://www.codesampler.com/dx9src/dx9src_4.htm#dx9_alpha_blending_framebuffer
' Control Keys: b - Toggle blending
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Alpha Blending with the Frame Buffer"

%D3DFVF_CUSTOMVERTEX = %D3DFVF_XYZ OR %D3DFVF_TEX1

TYPE Vertex
   x  AS SINGLE
   y  AS SINGLE
   z  AS SINGLE
   tu AS SINGLE
   tv AS SINGLE
END TYPE

' ========================================================================================
' Fills a Vertex structure
' ========================================================================================
MACRO FillVertex (v, x_, y_, z_, tu_, tv_)
   v.x = x_ : v.y = y_ : v.z = z_ : v.tu = tu_ : v.tv = tv_
END MACRO
' ========================================================================================

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS
   INSTANCE m_pVertexBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_pTexture AS IDirect3DTexture9
   INSTANCE m_bBlending AS LONG
   INSTANCE m_quadVertices () AS Vertex

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      m_bBlending = -1
      DIM m_quadVertices(23) AS INSTANCE Vertex
      FillVertex(m_quadVertices( 0), -1.0!,  1.0!, -1.0!, 0.0!, 0.0!)
      FillVertex(m_quadVertices( 1),  1.0!,  1.0!, -1.0!, 1.0!, 0.0!)
      FillVertex(m_quadVertices( 2), -1.0!, -1.0!, -1.0!, 0.0!, 1.0!)
      FillVertex(m_quadVertices( 3),  1.0!, -1.0!, -1.0!, 1.0!, 1.0!)
      FillVertex(m_quadVertices( 4), -1.0!,  1.0!,  1.0!, 1.0!, 0.0!)
      FillVertex(m_quadVertices( 5), -1.0!, -1.0!,  1.0!, 1.0!, 1.0!)
      FillVertex(m_quadVertices( 6),  1.0!,  1.0!,  1.0!, 0.0!, 0.0!)
      FillVertex(m_quadVertices( 7),  1.0!, -1.0!,  1.0!, 0.0!, 1.0!)
      FillVertex(m_quadVertices( 8), -1.0!,  1.0!,  1.0!, 0.0!, 0.0!)
      FillVertex(m_quadVertices( 9),  1.0!,  1.0!,  1.0!, 1.0!, 0.0!)
      FillVertex(m_quadVertices(10), -1.0!,  1.0!, -1.0!, 0.0!, 1.0!)
      FillVertex(m_quadVertices(11),  1.0!,  1.0!, -1.0!, 1.0!, 1.0!)
      FillVertex(m_quadVertices(12), -1.0!, -1.0!,  1.0!, 0.0!, 1.0!)
      FillVertex(m_quadVertices(13), -1.0!, -1.0!, -1.0!, 0.0!, 0.0!)
      FillVertex(m_quadVertices(14),  1.0!, -1.0!,  1.0!, 1.0!, 1.0!)
      FillVertex(m_quadVertices(15),  1.0!, -1.0!, -1.0!, 1.0!, 0.0!)
      FillVertex(m_quadVertices(16),  1.0!,  1.0!, -1.0!, 0.0!, 0.0!)
      FillVertex(m_quadVertices(17),  1.0!,  1.0!,  1.0!, 1.0!, 0.0!)
      FillVertex(m_quadVertices(18),  1.0!, -1.0!, -1.0!, 0.0!, 1.0!)
      FillVertex(m_quadVertices(19),  1.0!, -1.0!,  1.0!, 1.0!, 1.0!)
      FillVertex(m_quadVertices(20), -1.0!,  1.0!, -1.0!, 1.0!, 0.0!)
      FillVertex(m_quadVertices(21), -1.0!, -1.0!, -1.0!, 1.0!, 1.0!)
      FillVertex(m_quadVertices(22), -1.0!,  1.0!,  1.0!, 0.0!, 0.0!)
      FillVertex(m_quadVertices(23), -1.0!, -1.0!,  1.0!, 0.0!, 1.0!)
   END METHOD
   ' ====================================================================================

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      '// Create the device objects
      ME.CreateDeviceObjects

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture and creates the vertex buffers
   ' =====================================================================================
   METHOD CreateDeviceObjects () AS LONG

      ' // Loads the texture
      D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\Glass.bmp", m_pTexture)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_LINEAR)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_LINEAR)

      ' // Creates a vertex buffer
      LOCAL nSize AS LONG
      LOCAL pVertices AS Vertex PTR
      nSize = (UBOUND(m_quadVertices) - LBOUND(m_quadVertices) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, %D3DFVF_CUSTOMVERTEX, %D3DPOOL_DEFAULT, m_pVertexBuffer, %NULL)
      m_pVertexBuffer.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_quadVertices(0)), nSize
      m_pVertexBuffer.Unlock

      ' // Sets a device render-state parameter
      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %FALSE)

      ' // Builds a left-handed perspective projection matrix based on a field of view
      LOCAL matProj AS D3DXMATRIX
      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 600.0! / 400.0!, 0.1!, 100.0!)
      ' // Sets a device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

      ' // Return success
      METHOD = %S_OK

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene

      LOCAL  hr AS LONG
      STATIC fXrot AS SINGLE
      STATIC fYrot AS SINGLE
      STATIC fZrot AS SINGLE
      STATIC fElpasedTime AS SINGLE
      STATIC dCurrentTime AS DOUBLE
      STATIC dLastTime AS DOUBLE

      dCurrentTime = timeGetTime
      fElpasedTime = (dCurrentTime - dLastTime) * 0.001
      dLastTime    = dCurrentTime

      fXrot = fXrot + 10.1! * fElpasedTime
      fYrot = fYrot + 10.2! * fElpasedTime
      fZrot = fZrot + 10.3! * fElpasedTime

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.0!,0.0!,0.0!,1.0!), 1.0!, 0)

      LOCAL matWorld AS D3DXMATRIX
      LOCAL matTrans AS D3DXMATRIX
      LOCAL matRot AS D3DXMATRIX

      ' // Builds a matrix using the specified offsets
      D3DXMatrixTranslation(matTrans, 0.0!, 0.0!, 5.0!)
      ' // Builds a matrix with a specified yaw, pitch, and roll
      D3DXMatrixRotationYawPitchRoll(matRot, D3DXToRadian(fXrot), D3DXToRadian(fYrot), D3DXToRadian(fZrot))
      ' // Determines the product of the two matrices
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      ' // Sets the device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      IF ISTRUE m_bBlending THEN
         ' // Sets the device render-state parameters
         m_pD3DDevice.SetRenderState(%D3DRS_CULLMODE, %D3DCULL_NONE)
         m_pD3DDevice.SetRenderState(%D3DRS_ZENABLE, %FALSE)
         m_pD3DDevice.SetRenderState(%D3DRS_ALPHABLENDENABLE, %TRUE)
         m_pD3DDevice.SetRenderState(%D3DRS_SRCBLEND, %D3DBLEND_SRCALPHA)
         m_pD3DDevice.SetRenderState(%D3DRS_DESTBLEND, %D3DBLEND_ONE)
      ELSE
         ' // Sets the device render-state parameters
         m_pD3DDevice.SetRenderState(%D3DRS_ALPHABLENDENABLE, %FALSE)
         m_pD3DDevice.SetRenderState(%D3DRS_ZENABLE, %TRUE)
      END IF

      ' // Assigns the texture to a stage for the device
      m_pD3DDevice.SetTexture(0, m_pTexture)
      ' // Binds a vertex buffer to a device data stream
      m_pD3DDevice.SetStreamSource(0, m_pVertexBuffer, 0, SIZEOF(Vertex))
      ' // Sets the current vertex stream declaration
      m_pD3DDevice.SetFVF(%D3DFVF_CUSTOMVERTEX)

      ' // Renders a sequence of nonindexed, geometric primitives of the
      ' // specified type from the current set of data input streams.
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  0, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  4, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  8, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 12, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 16, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 20, 2)

      ' // Ends the scene
      m_pD3DDevice.EndScene

      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the device objects
            m_pVertexBuffer = NOTHING
            m_pTexture = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the device objects
            ME.CreateDeviceObjects
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   ' ====================================================================================
   ' Processes keystrokes
   ' ====================================================================================
   METHOD ProcessKeys (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)
      SELECT CASE wMsg
         CASE %WM_CHAR
            SELECT CASE wParam
               CASE 66, 98    ' B, b
                  m_bBlending = NOT m_bBlending
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
            END SELECT
      END SELECT
   END METHOD
   ' ====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   SELECT CASE wMsg

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene
         EXIT FUNCTION

      CASE %WM_CHAR
         pDX9.ProcessKeys hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to perform alpha-blending using a material. This alpha-blending technique is widely used to make entire objects fade out of existence over some amount of time.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_AlphaBlendingMaterial.bas
' Contents: DX9 example
' Description: Demonstrates how to perform alpha-blending using a material.
' This alpha-blending technique is widely used to make entire objects fade out of
' existence over some amount of time.
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from dx9_alpha_blending_material.cpp by Kevin Harris, 04/04/05, available at
' http://www.codesampler.com/dx9src/dx9src_4.htm#dx9_alpha_blending_material
' Control Keys: b - Toggle blending
'               a - Reduce alpha on the materials Diffuse color
'               A - Increase alpha on the materials Diffuse color
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Alpha Blending with a Material"

%FVF_Flags = %D3DFVF_XYZ OR %D3DFVF_NORMAL OR %D3DFVF_TEX1

TYPE Vertex
   x  AS SINGLE
   y  AS SINGLE
   z  AS SINGLE
   nx AS SINGLE
   ny AS SINGLE
   nz AS SINGLE
   tu AS SINGLE
   tv AS SINGLE
END TYPE

' ========================================================================================
' Fills a Vertex structure
' ========================================================================================
MACRO FillVertex (v, x_, y_, z_, nx_, ny_, nz_, tu_, tv_)
   v.x = x_ : v.y = y_ : v.z = z_ : v.nx = nx_ : v.ny = ny_ : v.nz = nz_ : v.tu = tu_ : v.tv = tv_
END MACRO
' ========================================================================================

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS
   INSTANCE m_pVertexBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_pTexture AS IDirect3DTexture9
   INSTANCE m_alphaMaterial AS D3DMATERIAL9
   INSTANCE m_bBlending AS LONG
   INSTANCE m_quadVertices () AS Vertex
   INSTANCE m_fDistance AS SINGLE
   INSTANCE m_fSpinX AS SINGLE
   INSTANCE m_fSpinY AS SINGLE

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      m_bBlending = -1
      m_fDistance = 4.5!
      DIM m_quadVertices(23) AS INSTANCE Vertex
      ' // Front Face
      FillVertex(m_quadVertices( 0), -1.0!,  1.0!, -1.0!,  0.0!,  0.0!, -1.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices( 1),  1.0!,  1.0!, -1.0!,  0.0!,  0.0!, -1.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices( 2), -1.0!, -1.0!, -1.0!,  0.0!,  0.0!, -1.0!,  0.0!,  1.0!)
      FillVertex(m_quadVertices( 3),  1.0!, -1.0!, -1.0!,  0.0!,  0.0!, -1.0!,  1.0!,  1.0!)
      ' // Back Face
      FillVertex(m_quadVertices( 4), -1.0!,  1.0!,  1.0!,  0.0!,  0.0!,  1.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices( 5), -1.0!, -1.0!,  1.0!,  0.0!,  0.0!,  1.0!,  1.0!,  1.0!)
      FillVertex(m_quadVertices( 6),  1.0!,  1.0!,  1.0!,  0.0!,  0.0!,  1.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices( 7),  1.0!, -1.0!,  1.0!,  0.0!,  0.0!,  1.0!,  0.0!,  1.0!)
      ' // Top Face
      FillVertex(m_quadVertices( 8), -1.0!,  1.0!,  1.0!,  0.0!,  1.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices( 9),  1.0!,  1.0!,  1.0!,  0.0!,  1.0!,  0.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices(10), -1.0!,  1.0!, -1.0!,  0.0!,  1.0!,  0.0!,  0.0!,  1.0!)
      FillVertex(m_quadVertices(11),  1.0!,  1.0!, -1.0!,  0.0!,  1.0!,  0.0!,  1.0!,  1.0!)
      ' // Bottom Face
      FillVertex(m_quadVertices(12), -1.0!, -1.0!,  1.0!,  0.0!, -1.0!,  0.0!,  0.0!,  1.0!)
      FillVertex(m_quadVertices(13), -1.0!, -1.0!, -1.0!,  0.0!, -1.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices(14),  1.0!, -1.0!,  1.0!,  0.0!, -1.0!,  0.0!,  1.0!,  1.0!)
      FillVertex(m_quadVertices(15),  1.0!, -1.0!, -1.0!,  0.0!, -1.0!,  0.0!,  1.0!,  0.0!)
      ' // Right Face
      FillVertex(m_quadVertices(16),  1.0!,  1.0!, -1.0!,  1.0!,  0.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices(17),  1.0!,  1.0!,  1.0!,  1.0!,  0.0!,  0.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices(18),  1.0!, -1.0!, -1.0!,  1.0!,  0.0!,  0.0!,  0.0!,  1.0!)
      FillVertex(m_quadVertices(19),  1.0!, -1.0!,  1.0!,  1.0!,  0.0!,  0.0!,  1.0!,  1.0!)
      ' // Left Face
      FillVertex(m_quadVertices(20), -1.0!,  1.0!, -1.0!, -1.0!,  0.0!,  0.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices(21), -1.0!, -1.0!, -1.0!, -1.0!,  0.0!,  0.0!,  1.0!,  1.0!)
      FillVertex(m_quadVertices(22), -1.0!,  1.0!,  1.0!, -1.0!,  0.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices(23), -1.0!, -1.0!,  1.0!, -1.0!,  0.0!,  0.0!,  0.0!,  1.0!)
   END METHOD
   ' ====================================================================================

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      '// Create the device objects
      ME.CreateDeviceObjects

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture and creates the vertex buffers
   ' =====================================================================================
   METHOD CreateDeviceObjects () AS LONG

      ' // Loads the texture
      D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\Glass.bmp", m_pTexture)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_LINEAR)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_LINEAR)

      ' // Creates a vertex buffer
      LOCAL nSize AS LONG
      LOCAL pVertices AS Vertex PTR
      nSize = (UBOUND(m_quadVertices) - LBOUND(m_quadVertices) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, %FVF_Flags, %D3DPOOL_DEFAULT, m_pVertexBuffer, %NULL)
      m_pVertexBuffer.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_quadVertices(0)), nSize
      m_pVertexBuffer.Unlock

      ' // Sets a device render-state parameter
      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %TRUE)

      ' // Builds a left-handed perspective projection matrix based on a field of view
      LOCAL matProj AS D3DXMATRIX
      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 600.0! / 400.0!, 0.1!, 100.0!)
      ' // Sets a device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

      ' // Set up our alpha material...
      m_alphaMaterial.Diffuse.r = 1.0!
      m_alphaMaterial.Diffuse.g = 1.0!
      m_alphaMaterial.Diffuse.b = 1.0!
      m_alphaMaterial.Diffuse.a = 0.5!
      m_pD3DDevice.SetMaterial(m_alphaMaterial)

      ' // Set light 0 to be a pure white directional light
      LOCAL light0 AS D3DLIGHT9
      light0.Type = %D3DLIGHT_DIRECTIONAL
      light0.Direction.x = 0.0!
      light0.Direction.y = 0.0!
      light0.Direction.z = 1.0!
      light0.Diffuse.r = 1.0!
      light0.Diffuse.g = 1.0!
      light0.Diffuse.b = 1.0!
      light0.Diffuse.a = 1.0!
      m_pD3DDevice.SetLight(0, light0)
      m_pD3DDevice.LightEnable(0, %TRUE)

      ' // Return success
      METHOD = %S_OK

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene

      LOCAL  hr AS LONG

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.35!,0.53!,0.7!,1.0!), 1.0!, 0)

      LOCAL matWorld AS D3DXMATRIX
      LOCAL matTrans AS D3DXMATRIX
      LOCAL matRot AS D3DXMATRIX

      ' // Builds a matrix using the specified offsets
      D3DXMatrixTranslation(matTrans, 0.0!, 0.0!, m_fDistance)
      ' // Builds a matrix with a specified yaw, pitch, and roll
      D3DXMatrixRotationYawPitchRoll(matRot, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)
      ' // Determines the product of the two matrices
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      ' // Sets the device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      IF ISTRUE m_bBlending THEN
         ' // Sets the device render-state parameters
         m_pD3DDevice.SetRenderState(%D3DRS_ALPHABLENDENABLE, %TRUE)
         m_pD3DDevice.SetMaterial(m_alphaMaterial)
         ' // Use material's alpha
         m_pD3DDevice.SetRenderState(%D3DRS_DIFFUSEMATERIALSOURCE, %D3DMCS_MATERIAL)
         m_pD3DDevice.SetTextureStageState(0, %D3DTSS_ALPHAARG1, %D3DTA_DIFFUSE)
         m_pD3DDevice.SetTextureStageState(0, %D3DTSS_ALPHAOP, %D3DTOP_SELECTARG1)
         ' // Use alpha for transparency
         m_pD3DDevice.SetRenderState(%D3DRS_SRCBLEND, %D3DBLEND_SRCALPHA)
         m_pD3DDevice.SetRenderState(%D3DRS_DESTBLEND, %D3DBLEND_INVSRCALPHA)
      ELSE
         ' // Sets the device render-state parameters
         m_pD3DDevice.SetRenderState(%D3DRS_ALPHABLENDENABLE, %FALSE)
      END IF

      ' // Render the cube
      m_pD3DDevice.SetTexture(0, m_pTexture)
      m_pD3DDevice.SetStreamSource(0, m_pVertexBuffer, 0, SIZEOF(Vertex))
      m_pD3DDevice.SetFVF(%FVF_Flags)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  0, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  4, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  8, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 12, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 16, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 20, 2)

      ' // Ends the scene
      m_pD3DDevice.EndScene

      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the device objects
            m_pVertexBuffer = NOTHING
            m_pTexture = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the device objects
            ME.CreateDeviceObjects
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   ' ====================================================================================
   ' Processes keystrokes
   ' ====================================================================================
   METHOD ProcessKeys (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      SELECT CASE wMsg

         CASE %WM_CHAR
            SELECT CASE wParam
               CASE 66, 98    ' B, b
                  m_bBlending = NOT m_bBlending
               CASE 97        ' a
                  m_alphaMaterial.Diffuse.a = m_alphaMaterial.Diffuse.a - 0.1!
               CASE 65        ' A
                  m_alphaMaterial.Diffuse.a = m_alphaMaterial.Diffuse.a + 0.1!
            END SELECT

         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE 38   ' // Up Arrow Key
                  m_fDistance = m_fDistance - 0.1!
               CASE 40   ' // Down Arrow Key
                  m_fDistance = m_fDistance + 0.1!
            END SELECT

      END SELECT

   END METHOD
   ' ====================================================================================

   ' ====================================================================================
   ' Processes mouse
   ' ====================================================================================
   METHOD ProcessMouse (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      STATIC ptLastMousePosit AS POINT
      STATIC ptCurrentMousePosit AS POINT
      STATIC bMousing AS LONG

      SELECT CASE wMsg

         CASE %WM_LBUTTONDOWN
            ptLastMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptLastMousePosit.y = HI(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            bMousing = %TRUE

         CASE %WM_LBUTTONUP
            bMousing = %FALSE

         CASE %WM_MOUSEMOVE
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            IF bMousing THEN
               m_fSpinX = m_fSpinX - (ptCurrentMousePosit.x - ptLastMousePosit.x)
               m_fSpinY = m_fSpinY - (ptCurrentMousePosit.y - ptLastMousePosit.y)
            END IF
            ptLastMousePosit.x = ptCurrentMousePosit.x
            ptLastMousePosit.y = ptCurrentMousePosit.y

      END SELECT

   END METHOD
   ' ====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   SELECT CASE wMsg

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene
         EXIT FUNCTION

      CASE %WM_CHAR, %WM_KEYDOWN, %WM_KEYUP
         pDX9.ProcessKeys hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_LBUTTONDOWN, %WM_LBUTTONUP, %WM_MOUSEMOVE
         pDX9.ProcessMouse hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to perform alpha blending using the alpha channel of a standard .tga texture. For proper alpha blending, the sample uses a cull-mode sorting trick to ensure the sides of the textured cube get rendered in back-to-front order.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_AlphaBlendingTexture.bas
' Contents: DX9 example
' Description: Demonstrates how to perform alpha blending using the alpha channel of a
' standard .tga texture. For proper alpha blending, the sample uses a cull-mode sorting trick
' to ensure the sides of the textured cube get rendered in back-to-front order.
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from dx9_alpha_blending_texture.cpp by Kevin Harris, 03/27/05, available at
' http://www.codesampler.com/dx9src/dx9src_4.htm#dx9_alpha_blending_texture
' Control Keys: b - Toggle blending
'               s - Toggle usage of cull-mode sorting trick
'               Up Arrow - Move the test cube closer
'               Down Arrow - Move the test cube away
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Texture Alpha Blending"

%FVF_Flags = %D3DFVF_XYZ OR %D3DFVF_TEX1

TYPE Vertex
   x  AS SINGLE
   y  AS SINGLE
   z  AS SINGLE
   tu AS SINGLE
   tv AS SINGLE
END TYPE

' ========================================================================================
' Fills a Vertex structure
' ========================================================================================
MACRO FillVertex (v, x_, y_, z_, tu_, tv_)
   v.x = x_ : v.y = y_ : v.z = z_ : v.tu = tu_ : v.tv = tv_
END MACRO
' ========================================================================================

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS
   INSTANCE m_pVertexBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_pTexture AS IDirect3DTexture9
   INSTANCE m_alphaMaterial AS D3DMATERIAL9
   INSTANCE m_bBlending AS LONG
   INSTANCE m_quadVertices () AS Vertex
   INSTANCE m_fDistance AS SINGLE
   INSTANCE m_fSpinX AS SINGLE
   INSTANCE m_fSpinY AS SINGLE
   INSTANCE m_bSortUsingCullModeTrick AS LONG

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      m_bBlending = -1
      m_bSortUsingCullModeTrick = -1
      m_fDistance = 4.5!
      DIM m_quadVertices(23) AS INSTANCE Vertex
      FillVertex(m_quadVertices( 0), -1.0!,  1.0!, -1.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices( 1),  1.0!,  1.0!, -1.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices( 2), -1.0!, -1.0!, -1.0!,  0.0!,  1.0!)
      FillVertex(m_quadVertices( 3),  1.0!, -1.0!, -1.0!,  1.0!,  1.0!)
      FillVertex(m_quadVertices( 4), -1.0!,  1.0!,  1.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices( 5), -1.0!, -1.0!,  1.0!,  1.0!,  1.0!)
      FillVertex(m_quadVertices( 6),  1.0!,  1.0!,  1.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices( 7),  1.0!, -1.0!,  1.0!,  0.0!,  1.0!)
      FillVertex(m_quadVertices( 8), -1.0!,  1.0!,  1.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices( 9),  1.0!,  1.0!,  1.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices(10), -1.0!,  1.0!, -1.0!,  0.0!,  1.0!)
      FillVertex(m_quadVertices(11),  1.0!,  1.0!, -1.0!,  1.0!,  1.0!)
      FillVertex(m_quadVertices(12), -1.0!, -1.0!,  1.0!,  0.0!,  1.0!)
      FillVertex(m_quadVertices(13), -1.0!, -1.0!, -1.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices(14),  1.0!, -1.0!,  1.0!,  1.0!,  1.0!)
      FillVertex(m_quadVertices(15),  1.0!, -1.0!, -1.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices(16),  1.0!,  1.0!, -1.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices(17),  1.0!,  1.0!,  1.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices(18),  1.0!, -1.0!, -1.0!,  0.0!,  1.0!)
      FillVertex(m_quadVertices(19),  1.0!, -1.0!,  1.0!,  1.0!,  1.0!)
      FillVertex(m_quadVertices(20), -1.0!,  1.0!, -1.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices(21), -1.0!, -1.0!, -1.0!,  1.0!,  1.0!)
      FillVertex(m_quadVertices(22), -1.0!,  1.0!,  1.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices(23), -1.0!, -1.0!,  1.0!,  0.0!,  1.0!)
   END METHOD
   ' ====================================================================================

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      '// Create the device objects
      ME.CreateDeviceObjects

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture and creates the vertex buffers
   ' =====================================================================================
   METHOD CreateDeviceObjects () AS LONG

      ' // Loads the texture
      D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\Radiation_Box.tga", m_pTexture)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_LINEAR)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_LINEAR)

      ' // Creates a vertex buffer
      LOCAL nSize AS LONG
      LOCAL pVertices AS Vertex PTR
      nSize = (UBOUND(m_quadVertices) - LBOUND(m_quadVertices) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, %FVF_Flags, %D3DPOOL_DEFAULT, m_pVertexBuffer, %NULL)
      m_pVertexBuffer.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_quadVertices(0)), nSize
      m_pVertexBuffer.Unlock

      ' // Sets a device render-state parameter
      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %FALSE)
      m_pD3DDevice.SetRenderState(%D3DRS_CULLMODE, %D3DCULL_NONE)

      ' // Builds a left-handed perspective projection matrix based on a field of view
      LOCAL matProj AS D3DXMATRIX
      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 600.0! / 400.0!, 0.1!, 100.0!)
      ' // Sets a device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

      ' // Return success
      METHOD = %S_OK

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene

      LOCAL  hr AS LONG

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.35!,0.53!,0.7!,1.0!), 1.0!, 0)

      LOCAL matWorld AS D3DXMATRIX
      LOCAL matTrans AS D3DXMATRIX
      LOCAL matRot AS D3DXMATRIX

      ' // Builds a matrix using the specified offsets
      D3DXMatrixTranslation(matTrans, 0.0!, 0.0!, m_fDistance)
      ' // Builds a matrix with a specified yaw, pitch, and roll
      D3DXMatrixRotationYawPitchRoll(matRot, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)
      ' // Determines the product of the two matrices
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      ' // Sets the device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      ' // Transparency sorting for our cube...
      ' //
      ' // If you have a single transparent object, or multiple transparent objects
      ' // which do not overlap in screen space (i.e., each screen pixel is touched
      ' // by at most one of the transparent objects), there's a sorting short-cut
      ' // which can be used under certain conditions.
      ' //
      ' // If your transparent objects are closed, convex, and viewed from the
      ' // outside, culling may be used to draw the back-facing polygons prior to
      ' // the front-facing polygons. This will accomplish the same thing
      ' // as sorting your objects or polygons into back-to-front order.
      ' // Fortunately for us, our cube is a perfect candidate for this sorting
      ' // trick.
      ' //
      ' // On the other hand, If we can't use the cull-mode sorting trick, we would
      ' // need to sort our objects manually, which would require us to transform
      ' // the geometry into eye-space so we could compare their final position
      ' // along the z axis. Only then, could we could render them in the proper
      ' // back-to-front order for alpha blending.
      ' //
      ' // Also, if transparent objects intersect in any way, the individual
      ' // triangles of the objects touching will have to be sorted and drawn
      ' // individually from back-to-front. And is some rare cases, triangles that
      ' // intersect each other may have to be broken into smaller triangles so they
      ' // no longer intersect or blending artifacts will persist regardless of our
      ' // sorting efforts.
      ' //
      ' // It's plain to see, transparency sorting can become a big, hairy mess real quick.
      ' //
      ' // http://www.opengl.org/resources/tutorials/sig99/advanced99/notes/node204.html
      IF ISTRUE m_bBlending THEN
         ' // Use the texture's alpha channel to blend it with whatever's already in the frame-buffer.
         m_pD3DDevice.SetRenderState(%D3DRS_ALPHABLENDENABLE, %TRUE)
         m_pD3DDevice.SetRenderState(%D3DRS_SRCBLEND, %D3DBLEND_SRCALPHA)
         m_pD3DDevice.SetRenderState(%D3DRS_DESTBLEND, %D3DBLEND_INVSRCALPHA)
         m_pD3DDevice.SetTexture(0, m_pTexture)
         m_pD3DDevice.SetStreamSource(0, m_pVertexBuffer, 0, SIZEOF(Vertex))
         m_pD3DDevice.SetFVF(%FVF_Flags)
         IF m_bSortUsingCullModeTrick THEN
            ' // Use the cull-mode sorting trick for convex non-overlapping geometry.
            ' // Render the cube but only render the back-facing polygons.
            m_pD3DDevice.SetRenderState(%D3DRS_CULLMODE, %D3DCULL_CW)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  0, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  4, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  8, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 12, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 16, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 20, 2)
            ' // Render the cube again, but this time we only render the front-facing polygons.
            m_pD3DDevice.SetRenderState(%D3DRS_CULLMODE, %D3DCULL_CCW)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  0, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  4, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  8, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 12, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 16, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 20, 2)
         ELSE
            ' // Do no sorting and hope for the best. From certain viewing
            ' // positions the cube's sides will appear sorted correctly, but this
            ' // is typically rare and the cube will not look right most of the
            ' // time.
            m_pD3DDevice.SetRenderState(%D3DRS_CULLMODE, %D3DCULL_NONE)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  0, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  4, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  8, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 12, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 16, 2)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 20, 2)
         END IF
      ELSE
         ' // Render the cube, but do no blending...
         m_pD3DDevice.SetRenderState(%D3DRS_ALPHABLENDENABLE, %FALSE)
         m_pD3DDevice.SetRenderState(%D3DRS_ZENABLE, %TRUE)
         m_pD3DDevice.SetTexture(0, m_pTexture)
         m_pD3DDevice.SetStreamSource(0, m_pVertexBuffer, 0, SIZEOF(Vertex))
         m_pD3DDevice.SetFVF(%FVF_Flags)
         m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  0, 2)
         m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  4, 2)
         m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  8, 2)
         m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 12, 2)
         m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 16, 2)
         m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 20, 2)
      END IF

      ' // Ends the scene
      m_pD3DDevice.EndScene

      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the device objects
            m_pVertexBuffer = NOTHING
            m_pTexture = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the device objects
            ME.CreateDeviceObjects
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   ' ====================================================================================
   ' Processes keystrokes
   ' ====================================================================================
   METHOD ProcessKeys (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      SELECT CASE wMsg

         CASE %WM_CHAR
            SELECT CASE wParam
               CASE 66, 98    ' B, b
                  m_bBlending = NOT m_bBlending
               CASE 83, 115   ' S, s
                  m_bSortUsingCullModeTrick = NOT m_bSortUsingCullModeTrick
            END SELECT

         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE 38   ' // Up Arrow Key
                  m_fDistance = m_fDistance - 0.1!
               CASE 40   ' // Down Arrow Key
                  m_fDistance = m_fDistance + 0.1!
            END SELECT

      END SELECT

   END METHOD
   ' ====================================================================================

   ' ====================================================================================
   ' Processes mouse
   ' ====================================================================================
   METHOD ProcessMouse (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      STATIC ptLastMousePosit AS POINT
      STATIC ptCurrentMousePosit AS POINT
      STATIC bMousing AS LONG

      SELECT CASE wMsg

         CASE %WM_LBUTTONDOWN
            ptLastMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptLastMousePosit.y = HI(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            bMousing = %TRUE

         CASE %WM_LBUTTONUP
            bMousing = %FALSE

         CASE %WM_MOUSEMOVE
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            IF bMousing THEN
               m_fSpinX = m_fSpinX - (ptCurrentMousePosit.x - ptLastMousePosit.x)
               m_fSpinY = m_fSpinY - (ptCurrentMousePosit.y - ptLastMousePosit.y)
            END IF
            ptLastMousePosit.x = ptCurrentMousePosit.x
            ptLastMousePosit.y = ptCurrentMousePosit.y

      END SELECT

   END METHOD
   ' ====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   SELECT CASE wMsg

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene
         EXIT FUNCTION

      CASE %WM_CHAR, %WM_KEYDOWN, %WM_KEYUP
         pDX9.ProcessKeys hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_LBUTTONDOWN, %WM_LBUTTONUP, %WM_MOUSEMOVE
         pDX9.ProcessMouse hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to create an animated 2D sprite using D3DXSprite which is hardware accelerated and fully compatible with 3D generated content.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_D3DXSprite.bas
' Contents: DX9 example
' Description: Demonstrates how to create a animated 2D sprite using D3DXSprite which is
' hardware accelerated and fully compatible with 3D generated content.
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from dx9_spot_d3dxsprite.cpp by Kevin Harris, 02/01/05, available at
' http://www.codesampler.com/dx9src/dx9src_8.htm#dx9_d3dxsprite
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Creating 2D Sprites with D3DXSPRITE"

%D3DFVF_CUSTOMVERTEX = %D3DFVF_XYZ OR %D3DFVF_TEX1

TYPE Vertex
   x  AS SINGLE
   y  AS SINGLE
   z  AS SINGLE
   tu AS SINGLE
   tv AS SINGLE
END TYPE

' ========================================================================================
' Fills a Vertex structure
' ========================================================================================
MACRO FillVertex (v, x_, y_, z_, tu_, tv_)
   v.x = x_ : v.y = y_ : v.z = z_ : v.tu = tu_ : v.tv = tv_
END MACRO
' ========================================================================================

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS
   INSTANCE m_pVertexBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_pDonutTexture AS IDirect3DTexture9
   INSTANCE m_pDonutSprite AS ID3DXSprite
   INSTANCE m_quadVertices () AS Vertex
   INSTANCE m_fMoveSpeed AS SINGLE
   INSTANCE m_fSpinX AS SINGLE
   INSTANCE m_fSpinY AS SINGLE

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      m_fMoveSpeed = 50.0!
      DIM m_quadVertices(3) AS INSTANCE Vertex
      FillVertex(m_quadVertices(0), -1.0!,  1.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices(1),  1.0!,  1.0!,  0.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices(2), -1.0!, -1.0!,  0.0!,  0.0!,  1.0!)
      FillVertex(m_quadVertices(3),  1.0!, -1.0!,  0.0!,  1.0!,  1.0!)
   END METHOD
   ' ====================================================================================

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      '// Create the device objects
      ME.CreateDeviceObjects

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture and creates the vertex buffers
   ' =====================================================================================
   METHOD CreateDeviceObjects () AS LONG

      ' // Loads the texture
      LOCAL d3dxImageInfo AS D3DXIMAGE_INFO
      D3DXCreateTextureFromFileEx(m_pD3DDevice, _
                                  ".\Resources\Donut.bmp", _
                                  320, _  ' // I had to set width manually. D3DPOOL_DEFAULT works for textures but causes problems for D3DXSPRITE.
                                  384, _  ' // I had to set height manually. D3DPOOL_DEFAULT works for textures but causes problems for D3DXSPRITE.
                                  1,   _  ' // Don't create mip-maps when you plan on using D3DXSPRITE. It throws off the pixel math for sprite animation.
                                  %D3DPOOL_DEFAULT, _
                                  %D3DFMT_UNKNOWN, _
                                  %D3DPOOL_DEFAULT, _
                                  %D3DX_DEFAULT, _
                                  %D3DX_DEFAULT, _
                                  D3DCOLOR_COLORVALUE(0.0!,0.0!,0.0!,1.0!), _
                                  d3dxImageInfo, _
                                  BYVAL %NULL, _
                                  m_pDonutTexture)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_LINEAR)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_LINEAR)

      ' // Creates a vertex buffer
      LOCAL nSize AS LONG
      LOCAL pVertices AS Vertex PTR
      nSize = (UBOUND(m_quadVertices) - LBOUND(m_quadVertices) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, %D3DUSAGE_WRITEONLY, %D3DFVF_CUSTOMVERTEX, %D3DPOOL_DEFAULT, m_pVertexBuffer, %NULL)
      m_pVertexBuffer.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_quadVertices(0)), nSize
      m_pVertexBuffer.Unlock

      ' // Sets a device render-state parameter
      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %FALSE)
      m_pD3DDevice.SetRenderState(%D3DRS_CULLMODE, %D3DCULL_NONE)

      ' // Builds a left-handed perspective projection matrix based on a field of view
      LOCAL matProj AS D3DXMATRIX
      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 600.0! / 400.0!, 0.1!, 100.0!)
      ' // Sets a device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

      ' // Create our sprite...
      D3DXCreateSprite(m_pD3DDevice, m_pDonutSprite)

      ' // Return success
      METHOD = %S_OK

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene

      STATIC fElapsedTime AS SINGLE
      STATIC dCurTime AS DOUBLE
      STATIC dLastTime AS DOUBLE

      dCurTime     = timeGetTime
      fElapsedTime = (dCurTime - dLastTime) * 0.001
      dLastTime    = dCurTime

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.35!,0.53!,0.7!,1.0!), 1.0!, 0)

      LOCAL hr AS LONG
      LOCAL matWorld AS D3DXMATRIX
      LOCAL matTrans AS D3DXMATRIX
      LOCAL matRot AS D3DXMATRIX

      ' // Builds a matrix using the specified offsets
      D3DXMatrixTranslation(matTrans, 0.0!, 0.0!, 4.0!)
      ' // Builds a matrix with a specified yaw, pitch, and roll
      D3DXMatrixRotationYawPitchRoll(matRot, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)
      ' // Determines the product of the two matrices
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      ' // Sets the device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      ' // Render a simple quad using the whole donut texture...
      m_pD3DDevice.SetTexture(0, m_pDonutTexture)
      m_pD3DDevice.SetStreamSource(0, m_pVertexBuffer, 0, SIZEOF(Vertex))
      m_pD3DDevice.SetFVF(%D3DFVF_CUSTOMVERTEX)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 0, 2)

      ' // Render our sprite, which only uses only a single frame from the dount
      ' // texture per update. This will create an animated sprite.

      STATIC fPosition AS SINGLE
      STATIC nFrame AS LONG

      ' // Build a source RECT which will copy only a small portion of the texture.
      LOCAL srcRect AS RECT
      srcRect.nTop    = (nFrame \ 5 ) * 64
      srcRect.nLeft   = (nFrame MOD 5 ) * 64
      srcRect.nBottom = srcRect.nTop  + 64
      srcRect.nRight  = srcRect.nLeft + 64

      LOCAL vCenter, vPosition AS D3DXVECTOR3
      vCenter.x = 0.0! : vCenter.y = 0.0! : vCenter.z = 0.0!
      vPosition.x = fPosition : vPosition.y = 170.0! : vPosition.z = 0.0!

      m_pDonutSprite.Begin(%D3DXSPRITE_ALPHABLEND)
      m_pDonutSprite.Draw(m_pDonutTexture, _
                          srcRect, _
                          vCenter, _
                          vPosition, _
                          D3DCOLOR_COLORVALUE(1.0!,1.0!,1.0!,1.0!))
      m_pDonutSprite.End

      ' // Ends the scene
      m_pD3DDevice.EndScene

      ' // Increment the sprite's frame number. Our sprite's animation sequence
      ' // consists of 30 frames (0-29).

      STATIC fAnimationTimer AS SINGLE
      fAnimationTimer = fAnimationTimer + fElapsedTime

      IF fAnimationTimer > 0.01! THEN
         nFrame = nFrame + 1
         IF nFrame > 29 THEN nFrame = 0
         fAnimationTimer = 0.0!
      END IF

      ' // Slowly move our sprite across the screen. This demonstrates how to use
      ' // the Draw method of a D3DXSPRITE to place a sprite on the screen.
      fPosition = fPosition + m_fMoveSpeed * fElapsedTime
      IF fPosition > 600.0! THEN fPosition = 0.0!

      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the device objects
            m_pVertexBuffer = NOTHING
            m_pDonutTexture = NOTHING
            m_pDonutSprite = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the device objects
            ME.CreateDeviceObjects
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   ' ====================================================================================
   ' Processes keystrokes
   ' ====================================================================================
   METHOD ProcessKeys (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      SELECT CASE wMsg

         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
            END SELECT

      END SELECT

   END METHOD
   ' ====================================================================================

   ' ====================================================================================
   ' Processes mouse
   ' ====================================================================================
   METHOD ProcessMouse (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      STATIC ptLastMousePosit AS POINT
      STATIC ptCurrentMousePosit AS POINT
      STATIC bMousing AS LONG

      SELECT CASE wMsg

         CASE %WM_LBUTTONDOWN
            ptLastMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptLastMousePosit.y = HI(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            bMousing = %TRUE

         CASE %WM_LBUTTONUP
            bMousing = %FALSE

         CASE %WM_MOUSEMOVE
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            IF bMousing THEN
               m_fSpinX = m_fSpinX - (ptCurrentMousePosit.x - ptLastMousePosit.x)
               m_fSpinY = m_fSpinY - (ptCurrentMousePosit.y - ptLastMousePosit.y)
            END IF
            ptLastMousePosit.x = ptCurrentMousePosit.x
            ptLastMousePosit.y = ptCurrentMousePosit.y

      END SELECT

   END METHOD
   ' ====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   SELECT CASE wMsg

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene
         EXIT FUNCTION

      CASE %WM_CHAR, %WM_KEYDOWN, %WM_KEYUP
         pDX9.ProcessKeys hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_LBUTTONDOWN, %WM_LBUTTONUP, %WM_MOUSEMOVE
         pDX9.ProcessMouse hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to eliminate z-fighting when rendering polygons directly on top of other polygons  by using Direct3D's D3DRS_SLOPESCALEDEPTHBIAS and D3DRS_DEPTHBIAS render states.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_DepthBias.bas
' Contents: DX9 example
' Description: Demonstrates how to eliminate z-fighting when rendering polygons directly
' on top of other polygons by using Direct3D's D3DRS_SLOPESCALEDEPTHBIAS and
' D3DRS_DEPTHBIAS render states.
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from dx9_texture.cpp by Kevin Harris, 02/01/05, available at
' http://www.codesampler.com/dx9src/dx9src_5.htm#dx9_depth_bias
' Control Keys: Left Mouse Button - Spin the view
'               F1 - Increase Z-Slope Scale
'               F2 - Decrease Z-Slope Scale
'               F3 - Increase Depth Bias
'               F4 - Decrease Depth Bias
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Depth Bias"

%FVF_Flags = %D3DFVF_XYZ OR %D3DFVF_TEX1

TYPE Vertex
   x  AS SINGLE
   y  AS SINGLE
   z  AS SINGLE
   tu AS SINGLE
   tv AS SINGLE
END TYPE

' ========================================================================================
' Converts a float to a dword
' Note: An alternate way is to use MEMORY COPY:
' MEMORY COPY dw, f, 4
' ========================================================================================
FUNCTION F2DW (BYVAL f AS SINGLE) AS DWORD
   LOCAL pdw AS DWORD PTR
   pdw = VARPTR(f)
   FUNCTION = @pdw
END FUNCTION
' ========================================================================================

' ========================================================================================
' Fills a Vertex structure
' ========================================================================================
MACRO FillVertex (v, x_, y_, z_, tu_, tv_)
   v.x = x_ : v.y = y_ : v.z = z_ : v.tu = tu_ : v.tv = tv_
END MACRO
' ========================================================================================

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS
   INSTANCE m_pVertexBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_pTexture AS IDirect3DTexture9
   INSTANCE m_pD3DXFont AS ID3DXFont
   INSTANCE m_quadVertices () AS Vertex
   INSTANCE m_fSpinX AS SINGLE
   INSTANCE m_fSpinY AS SINGLE
   INSTANCE m_fZSlopeScale AS SINGLE
   INSTANCE m_fDepthBias AS SINGLE

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      m_fZSlopeScale = -0.1!
      DIM m_quadVertices(3) AS INSTANCE Vertex
      FillVertex(m_quadVertices(0), -1.0!,  1.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices(1),  1.0!,  1.0!,  0.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices(2), -1.0!, -1.0!,  0.0!,  0.0!,  1.0!)
      FillVertex(m_quadVertices(3),  1.0!, -1.0!,  0.0!,  1.0!,  1.0!)
   END METHOD
   ' ====================================================================================

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Creates the font
   ' =====================================================================================
   METHOD CreateD3DXFont

      LOCAL hr AS LONG
      LOCAL hDC AS DWORD
      LOCAL nHeight AS LONG
      LOCAL nPointSize AS LONG

      nPointSize = 9

      hDC = GetDC(%NULL)
      nHeight = -(MulDiv(nPointSize, GetDeviceCaps(hDC, %LOGPIXELSY), 72))
      ReleaseDC(%NULL, hDC)

      ' // Create a font for statistics and help output
      hr = D3DXCreateFont(m_pD3DDevice, nHeight, 0, %FW_BOLD, 0, %FALSE, _
                          %DEFAULT_CHARSET, %OUT_DEFAULT_PRECIS, %DEFAULT_QUALITY, _
                          %DEFAULT_PITCH OR %FF_DONTCARE, "Arial", m_pD3DXFont)

      IF FAILED(hr) THEN
         MessageBox(%NULL,"Call to D3DXCreateFont failed!", "ERROR", %MB_OK OR %MB_ICONEXCLAMATION)
      END IF

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      '// Create the device objects
      ME.CreateDeviceObjects

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture and creates the vertex buffers
   ' =====================================================================================
   METHOD CreateDeviceObjects () AS LONG

      ' // Creates the font
      ME.CreateD3DXFont

      ' // Loads the texture
      D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\Checker.bmp", m_pTexture)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_LINEAR)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_LINEAR)

      ' // Creates a vertex buffer
      LOCAL nSize AS LONG
      LOCAL pVertices AS Vertex PTR
      nSize = (UBOUND(m_quadVertices) - LBOUND(m_quadVertices) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, %FVF_Flags, %D3DPOOL_DEFAULT, m_pVertexBuffer, %NULL)
      m_pVertexBuffer.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_quadVertices(0)), nSize
      m_pVertexBuffer.Unlock

      ' // Sets a device render-state parameter
      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %FALSE)
      m_pD3DDevice.SetRenderState(%D3DRS_CULLMODE, %D3DCULL_NONE)
      m_pD3DDevice.SetRenderState(%D3DRS_ZENABLE, %TRUE)

      ' // Builds a left-handed perspective projection matrix based on a field of view
      LOCAL matProj AS D3DXMATRIX
      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 600.0! / 400.0!, 0.1!, 100.0!)
      ' // Sets a device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

      ' // Return success
      METHOD = %S_OK

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene (BYVAL pWindow AS IWindow)

      LOCAL  hr AS LONG

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.0!,0.0!,0.0!,1.0!), 1.0!, 0)

      LOCAL matWorld AS D3DXMATRIX
      LOCAL matTrans AS D3DXMATRIX
      LOCAL matRot AS D3DXMATRIX

      ' // Builds a matrix using the specified offsets
      D3DXMatrixTranslation(matTrans, 0.0!, 0.0!, 4.0!)
      ' // Builds a matrix with a specified yaw, pitch, and roll
      D3DXMatrixRotationYawPitchRoll(matRot, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)
      ' // Determines the product of the two matrices
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      ' // Sets the device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      ' // Set up the world matrix for spinning the quads about and render the
      ' // larger textured quad first.
      m_pD3DDevice.SetTexture(0, m_pTexture)
      m_pD3DDevice.SetStreamSource(0, m_pVertexBuffer, 0, SIZEOF(Vertex))
      m_pD3DDevice.SetFVF(%FVF_Flags)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 0, 2)

      ' // Now, for the second quad, scale it down a bit but use the same
      ' // translation and rotation matrices so we render it right on top of the
      ' // first quad. This will, of course, cause some z-fighting issues, which
      ' // we will fix via D3DRS_SLOPESCALEDEPTHBIAS and D3DRS_DEPTHBIAS.

      ' // Use depth bias
      m_pD3DDevice.SetRenderState(%D3DRS_SLOPESCALEDEPTHBIAS, F2DW(m_fZSlopeScale))
      m_pD3DDevice.SetRenderState(%D3DRS_DEPTHBIAS, F2DW(m_fDepthBias))

      LOCAL matScale AS D3DXMATRIX
      LOCAL matTemp AS D3DXMATRIX

      D3DXMatrixScaling(matScale, 0.5!, 0.5!, 0.0!)
      D3DXMatrixMultiply(matTemp, matScale, matRot)
      D3DXMatrixMultiply(matWorld, matTemp, matTrans)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      m_pD3DDevice.SetTexture(0, NOTHING)
      m_pD3DDevice.SetStreamSource(0, m_pVertexBuffer, 0, SIZEOF(Vertex))
      m_pD3DDevice.SetFVF(%FVF_Flags)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 0, 2)

      ' // Turn off depth bias
      m_pD3DDevice.SetRenderState(%D3DRS_SLOPESCALEDEPTHBIAS, F2DW(0.0!))
      m_pD3DDevice.SetRenderState(%D3DRS_DEPTHBIAS, F2DW(0.0!))

      ' // Output the current settings...
      LOCAL destRect1, destRect2 AS RECT
      SetRect(destRect1, 5 * pWindow.rxRatio, 5 * pWindow.ryRatio, 0, 0)
      SetRect(destRect2, 5 * pWindow.rxRatio, 20 * pWindow.ryRatio, 0, 0)

      LOCAL szZSlope AS ASCIIZ * 255
      LOCAL szDepthBias AS ASCIIZ * 255

      szZSlope = "Z-Slope Scale = " & FORMAT$(m_fZSlopeScale, "#.00") & "    (Change: F1 and F2)"
      szDepthBias = "Depth Bias = " & FORMAT$(m_fDepthBias, "#.00") & "    (Change: F3 and F4)"
      m_pD3DXFont.DrawTextA(NOTHING, szZSlope, -1, destRect1, %DT_NOCLIP, _
                           D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!))
      m_pD3DXFont.DrawTextA(NOTHING, szDepthBias, -1, destRect2, %DT_NOCLIP, _
                           D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!))

      ' // Ends the scene
      m_pD3DDevice.EndScene

      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the device objects
            m_pVertexBuffer = NOTHING
            m_pTexture = NOTHING
            m_pD3DXFont = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the device objects
            ME.CreateDeviceObjects
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   ' ====================================================================================
   ' Processes keystrokes
   ' ====================================================================================
   METHOD ProcessKeys (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      SELECT CASE wMsg

         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE %VK_F1
                  m_fZSlopeScale += 0.05!
               CASE %VK_F2
                  m_fZSlopeScale -= 0.05!
               CASE %VK_F3
                  m_fDepthBias += 0.005!
               CASE %VK_F4
                  m_fDepthBias -= 0.005!
            END SELECT

      END SELECT

   END METHOD
   ' ====================================================================================

   ' ====================================================================================
   ' Processes mouse
   ' ====================================================================================
   METHOD ProcessMouse (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      STATIC ptLastMousePosit AS POINT
      STATIC ptCurrentMousePosit AS POINT
      STATIC bMousing AS LONG

      SELECT CASE wMsg

         CASE %WM_LBUTTONDOWN
            ptLastMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptLastMousePosit.y = HI(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            bMousing = %TRUE

         CASE %WM_LBUTTONUP
            bMousing = %FALSE

         CASE %WM_MOUSEMOVE
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            IF bMousing THEN
               m_fSpinX = m_fSpinX - (ptCurrentMousePosit.x - ptLastMousePosit.x)
               m_fSpinY = m_fSpinY - (ptCurrentMousePosit.y - ptLastMousePosit.y)
            END IF
            ptLastMousePosit.x = ptCurrentMousePosit.x
            ptLastMousePosit.y = ptCurrentMousePosit.y

      END SELECT

   END METHOD
   ' ====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   STATIC pWindow AS IWindow        ' // Reference to the IWindow interface

   SELECT CASE wMsg

      CASE %WM_CREATE
         ' // Get a reference to the IWindow interface from the CREATESTRUCT structure
         pWindow = CWindow_GetObjectFromCreateStruct(lParam)
         EXIT FUNCTION

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene(pWindow)
         EXIT FUNCTION

      CASE %WM_CHAR, %WM_KEYDOWN, %WM_KEYUP
         pDX9.ProcessKeys hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_LBUTTONDOWN, %WM_LBUTTONUP, %WM_MOUSEMOVE
         pDX9.ProcessMouse hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to perform Dot3 per-pixel bump mapping using a normal map and the D3DTOP_DOTPRODUCT3 texture-blending operation. This technique is sometimes referred to as per-pixel lighting or per-pixel attenuation, but Dot3 per-pixel bump-mapping is what most programmers know it as.


' ########################################################################################
' Control Keys: d/D - Toggle Dot3 bump mapping
'               l/L - Toggle the usage of regular lighting in addition
'                     to the per-pixel lighting effect of bump mapping.
'               m/M - Toggle motion of point light
'               Up Arrow - Move the test cube closer
'               Down Arrow - Move the test cube away
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Dot3 Per-Pixel Bump-Mapping"

%FVF_Flags = %D3DFVF_XYZ OR %D3DFVF_NORMAL OR %D3DFVF_DIFFUSE OR %D3DFVF_TEX2

TYPE Vertex
   x       AS SINGLE
   y       AS SINGLE
   z       AS SINGLE
   nx      AS SINGLE
   ny      AS SINGLE
   nz      AS SINGLE
   diffuse AS DWORD
   tu1     AS SINGLE
   tv1     AS SINGLE
   tu2     AS SINGLE
   tv2     AS SINGLE
END TYPE

%NUM_VERTICES = 24

' ========================================================================================
' Fills a Vertex structure
' ========================================================================================
MACRO FillVertex (v, x_, y_, z_, nx_, ny_, nz_, diffuse_, tu1_, tv1_, tu2_, tv2_)
   v.x = x_ : v.y = y_ : v.z = z_
   v.nx = nx_ : v.ny = ny_ : v.nz = nz_
   v.diffuse = diffuse_
   v.tu1 = tu1_ : v.tv1 = tv1_
   v.tu2 = tu2_ : v.tv2 = tv2_
END MACRO
' ========================================================================================

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS
   INSTANCE m_deviceType AS DWORD
   INSTANCE m_pVertexBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_pSphereMesh AS ID3DXMesh
   INSTANCE m_pTexture AS IDirect3DTexture9
   INSTANCE m_pNormalMapTexture AS IDirect3DTexture9
   INSTANCE m_bDoDot3BumpMapping AS LONG
   INSTANCE m_bMoveLightAbout AS LONG
   INSTANCE m_bToggleRegularLighting AS LONG
   INSTANCE m_light0 AS D3DLIGHT9
   INSTANCE m_fDistance AS SINGLE
   INSTANCE m_fSpinX AS SINGLE
   INSTANCE m_fSpinY AS SINGLE
   INSTANCE m_cubeVertices () AS Vertex
   INSTANCE m_vTangents () AS D3DXVECTOR3
   INSTANCE m_vBiNormals () AS D3DXVECTOR3
   INSTANCE m_vNormals () AS D3DXVECTOR3

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      m_bDoDot3BumpMapping = %TRUE
      m_bMoveLightAbout = %TRUE
      m_bToggleRegularLighting = %FALSE
      m_deviceType = %D3DDEVTYPE_HAL
      m_fDistance = 5.0!
      DIM m_cubeVertices(%NUM_VERTICES - 1) AS INSTANCE Vertex
      ' // Front Face
      FillVertex(m_cubeVertices( 0), -1.0!,  1.0!, -1.0!,  0.0!,  0.0!, -1.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  0.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_cubeVertices( 1),  1.0!,  1.0!, -1.0!,  0.0!,  0.0!, -1.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  1.0!,  0.0!,  1.0!,  0.0!)
      FillVertex(m_cubeVertices( 2), -1.0!, -1.0!, -1.0!,  0.0!,  0.0!, -1.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  0.0!,  1.0!,  0.0!,  1.0!)
      FillVertex(m_cubeVertices( 3),  1.0!, -1.0!, -1.0!,  0.0!,  0.0!, -1.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  1.0!,  1.0!,  1.0!,  1.0!)
      ' // Back Face
      FillVertex(m_cubeVertices( 4), -1.0!,  1.0!,  1.0!,  0.0!,  0.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  1.0!,  0.0!,  1.0!,  0.0!)
      FillVertex(m_cubeVertices( 5), -1.0!, -1.0!,  1.0!,  0.0!,  0.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  1.0!,  1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices( 6),  1.0!,  1.0!,  1.0!,  0.0!,  0.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  0.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_cubeVertices( 7),  1.0!, -1.0!,  1.0!,  0.0!,  0.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  0.0!,  1.0!,  0.0!,  1.0!)
      ' // Top Face
      FillVertex(m_cubeVertices( 8), -1.0!,  1.0!,  1.0!,  0.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  0.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_cubeVertices( 9),  1.0!,  1.0!,  1.0!,  0.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  1.0!,  0.0!,  1.0!,  0.0!)
      FillVertex(m_cubeVertices(10), -1.0!,  1.0!, -1.0!,  0.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  0.0!,  1.0!,  0.0!,  1.0!)
      FillVertex(m_cubeVertices(11),  1.0!,  1.0!, -1.0!,  0.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  1.0!,  1.0!,  1.0!,  1.0!)
      ' // Bottom Face
      FillVertex(m_cubeVertices(12), -1.0!, -1.0!,  1.0!,  0.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  0.0!,  1.0!,  0.0!,  1.0!)
      FillVertex(m_cubeVertices(13), -1.0!, -1.0!, -1.0!,  0.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  0.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_cubeVertices(14),  1.0!, -1.0!,  1.0!,  0.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  1.0!,  1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices(15),  1.0!, -1.0!, -1.0!,  0.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  1.0!,  0.0!,  1.0!,  0.0!)
      ' // Right Face
      FillVertex(m_cubeVertices(16),  1.0!,  1.0!, -1.0!,  1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  0.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_cubeVertices(17),  1.0!,  1.0!,  1.0!,  1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  1.0!,  0.0!,  1.0!,  0.0!)
      FillVertex(m_cubeVertices(18),  1.0!, -1.0!, -1.0!,  1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  0.0!,  1.0!,  0.0!,  1.0!)
      FillVertex(m_cubeVertices(19),  1.0!, -1.0!,  1.0!,  1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  1.0!,  1.0!,  1.0!,  1.0!)
      ' // Left Face
      FillVertex(m_cubeVertices(20), -1.0!,  1.0!, -1.0!, -1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  1.0!,  0.0!,  1.0!,  0.0!)
      FillVertex(m_cubeVertices(21), -1.0!, -1.0!, -1.0!, -1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  1.0!,  1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices(22), -1.0!,  1.0!,  1.0!, -1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  0.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_cubeVertices(23), -1.0!, -1.0!,  1.0!, -1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!),  0.0!,  1.0!,  0.0!,  1.0!)
      ' // For each vertex defined above, we'll need to create a Tangent, BiNormal, and
      ' // Normal vector, which together define a tangent matrix for Dot3 bump mapping.
      DIM m_vTangents (%NUM_VERTICES - 1) AS INSTANCE D3DXVECTOR3
      DIM m_vBiNormals (%NUM_VERTICES - 1) AS INSTANCE D3DXVECTOR3
      DIM m_vNormals (%NUM_VERTICES - 1) AS INSTANCE D3DXVECTOR3
   END METHOD
   ' ====================================================================================

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   METHOD EncodeVectorAsDWORDColor(BYREF vVector AS D3DXVECTOR3) AS DWORD
      LOCAL dwRed, dwGreen, dwBlue AS DWORD
      dwRed   = 127 * vVector.x + 128
      dwGreen = 127 * vVector.y + 128
      dwBlue  = 127 * vVector.z + 128
      SHIFT LEFT dwRed, 16
      SHIFT LEFT dwGreen, 8
      METHOD = &Hff000000 + dwRed + dwGreen + dwBlue
   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   '// Name: CreateTangentSpaceVectors()
   '// Desc: Given a vertex (v1) and two other vertices (v2 & v3) which define a
   '//       triangle, this function will return Tangent, BiNormal, and Normal,
   '//       vectors which can be used to define the tangent matrix for the first
   '//       vertex's position (v1).
   '//
   '// Args: v1        - vertex 1
   '//       v2        - vertex 2
   '//       v3        - vertex 3
   '//       v1u, v1v  - texture-coordinates of vertex 1
   '//       v2u, v2v  - texture-coordinates of vertex 2
   '//       v3u, v3v  - texture-coordinates of vertex 3
   '//       vTangent  - When the function returns, this will be set as the tangent vector
   '//       vBiNormal - When the function returns, this will be set as the binormal vector
   '//       vNormal   - When the function returns, this will be set as the normal vector
   '//
   '// Note: This function is based on an article by By Jakob Gath and Sbren Dreijer.
   '// http://www.blacksmith-studios.dk/projects/downloads/tangent_matrix_derivation.php
   ' =====================================================================================
   METHOD CreateTangentSpaceVectors(BYREF v1 AS D3DXVECTOR3, _
                                    BYREF v2 AS D3DXVECTOR3, _
                                    BYREF v3 AS D3DXVECTOR3, _
                                    BYVAL v1u AS SINGLE, BYVAL v1v AS SINGLE, _
                                    BYVAL v2u AS SINGLE, BYVAL v2v AS SINGLE, _
                                    BYVAL v3u AS SINGLE, BYVAL v3v AS SINGLE, _
                                    BYREF vTangent AS D3DXVECTOR3, _
                                    BYREF vBiNormal AS D3DXVECTOR3, _
                                    BYREF vNormal AS D3DXVECTOR3)

      ' // Create edge vectors from vertex 1 to vectors 2 and 3.
      LOCAL vDirVec_v2_to_v1, vDirVec_v3_to_v1 AS D3DXVECTOR3

      vDirVec_v2_to_v1.x = v2.x - v1.x : vDirVec_v2_to_v1.y = v2.y - v1.y : vDirVec_v2_to_v1.z = v2.z - v1.z
      vDirVec_v3_to_v1.x = v3.x - v1.x : vDirVec_v3_to_v1.y = v3.y - v1.y : vDirVec_v3_to_v1.z = v3.z - v1.z

      ' // Create edge vectors from the texture coordinates of vertex 1 to vector 2.
      LOCAL vDirVec_v2u_to_v1u, vDirVec_v2v_to_v1v AS SINGLE
      vDirVec_v2u_to_v1u = v2u - v1u : vDirVec_v2v_to_v1v = v2v - v1v

      ' // Create edge vectors from the texture coordinates of vertex 1 to vector 3.
      LOCAL vDirVec_v3u_to_v1u, vDirVec_v3v_to_v1v AS SINGLE
      vDirVec_v3u_to_v1u = v3u - v1u : vDirVec_v3v_to_v1v = v3v - v1v

      LOCAL fDenominator AS SINGLE
      fDenominator = vDirVec_v2u_to_v1u * vDirVec_v3v_to_v1v - vDirVec_v3u_to_v1u * vDirVec_v2v_to_v1v

      IF fDenominator < 0.0001! AND fDenominator > -0.0001! THEN
         ' // We're too close to zero and we're at risk of a divide-by-zero!
         ' // Set the tangent matrix to the identity matrix and do nothing.
         vTangent.x = 1.0! : vTangent.y = 0.0! : vTangent.z = 0.0!
         vBiNormal.x = 0.0! : vBiNormal.y = 1.0! : vBiNormal.z = 0.0!
         vNormal.x = 0.0! : vNormal.y = 0.0! : vNormal.z = 1.0!
      ELSE
         ' // Calculate and cache the reciprocal value
         LOCAL fScale1 AS SINGLE
         fScale1 = 1.0! / fDenominator
         LOCAL T, B, N AS D3DXVECTOR3

         T.x = (vDirVec_v3v_to_v1v * vDirVec_v2_to_v1.x - vDirVec_v2v_to_v1v * vDirVec_v3_to_v1.x) * fScale1
         T.y = (vDirVec_v3v_to_v1v * vDirVec_v2_to_v1.y - vDirVec_v2v_to_v1v * vDirVec_v3_to_v1.y) * fScale1
         T.z = (vDirVec_v3v_to_v1v * vDirVec_v2_to_v1.z - vDirVec_v2v_to_v1v * vDirVec_v3_to_v1.z) * fScale1

         B.x = (-vDirVec_v3u_to_v1u * vDirVec_v2_to_v1.x + vDirVec_v2u_to_v1u * vDirVec_v3_to_v1.x) * fScale1
         B.y = (-vDirVec_v3u_to_v1u * vDirVec_v2_to_v1.y + vDirVec_v2u_to_v1u * vDirVec_v3_to_v1.y) * fScale1
         B.z = (-vDirVec_v3u_to_v1u * vDirVec_v2_to_v1.z + vDirVec_v2u_to_v1u * vDirVec_v3_to_v1.z) * fScale1

         ' // The normal N is calculated as the cross product between T and B
         D3DXVec3Cross(N, T, B)

         ' // Calculate and cache the reciprocal value
         LOCAL fScale2 AS SINGLE
         fScale2 = 1.0! / ((T.x * B.y * N.z - T.z * B.y * N.x) + (B.x * N.y * T.z - B.z * N.y * T.x) + (N.x * T.y * B.z - N.z * T.y * B.x))

         ' // Use the temporary T (Tangent), (B) Binormal, and N (Normal) vectors
         ' // to calculate the inverse of the tangent matrix that they represent.
         ' // The inverse of the tangent matrix is what we want since we need that
         ' // to transform the light's vector into tangent-space.

         LOCAL vTemp AS D3DXVECTOR3

         D3DXVec3Cross(vTemp, B, N) : vTangent.x = vTemp.x * fScale2
         D3DXVec3Cross(vTemp, N, T) : vTangent.y = -(vTemp.x * fScale2)
         D3DXVec3Cross(vTemp, T, B) : vTangent.z = vTemp.x * fScale2
         D3DXVec3Normalize(vTangent, vTangent)

         D3DXVec3Cross(vTemp, B, N) : vBiNormal.x = vTemp.y * fScale2
         D3DXVec3Cross(vTemp, N, T) : vBiNormal.y = vTemp.y * fScale2
         D3DXVec3Cross(vTemp, T, B) : vBiNormal.z = -(vTemp.y * fScale2)
         D3DXVec3Normalize(vBiNormal, vBiNormal)

         D3DXVec3Cross(vTemp, B, N) : vNormal.x = vTemp.z * fScale2
         D3DXVec3Cross(vTemp, N, T) : vNormal.y = -(vTemp.z * fScale2)
         D3DXVec3Cross(vTemp, T, B) : vNormal.z = vTemp.z * fScale2
         D3DXVec3Normalize(vNormal, vNormal)

         ' // NOTE: Since the texture-space of Direct3D and OpenGL are laid-out
         ' //       differently, a single normal map can't look right in both
         ' //       unless you make some adjustments somewhere.
         ' //
         ' //       You can adjust or fix this problem in three ways:
         ' //
         ' //       1. Create two normal maps: one for OpenGL and one for Direct3D.
         ' //       2. Flip the normal map image over as you load it into a texture
         ' //          object.
         ' //       3. Flip the binormal over when computing the tangent-space
         ' //          matrix.
         ' //
         ' // Since the normal map used by this sample was created for Direct3D,
         ' // no adjustment is necessary.
         ' //
         ' //*vBiNormal = *vBiNormal * -1.0f;
      END IF

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD ComputeTangentsMatricesForEachVertex

      LOCAL v1, v2, v3, vTangent, vBiNormal, vNormal AS D3DXVECTOR3
      LOCAL i AS LONG

      ' // For each cube face defined in the vertex array, compute a tangent matrix
      ' // for each of the four vertices that define it.
      FOR i = 0 TO %NUM_VERTICES - 1 STEP 4   ' // Use += 4 to process 1 face at a time
         ' //
         ' // Vertex 0 of current cube face...
         ' //
         ' //  v2
         ' //    3----2
         ' //    |    |
         ' //    |    |
         ' //    0----1
         ' //  v1      v3
         ' //

         v1.x = m_cubeVertices(i).x   : v1.y = m_cubeVertices(i).y   : v1.z = m_cubeVertices(i).z
         v2.x = m_cubeVertices(i+3).x : v2.y = m_cubeVertices(i+3).y : v2.z = m_cubeVertices(i+3).z
         v3.x = m_cubeVertices(i+1).x : v3.y = m_cubeVertices(i+1).y : v3.z = m_cubeVertices(i+1).z

         ME.CreateTangentSpaceVectors(v1, v2, v3, _
                                      m_cubeVertices(i).tu1, m_cubeVertices(i).tv1, _
                                      m_cubeVertices(i+3).tu1, m_cubeVertices(i+3).tv1, _
                                      m_cubeVertices(i+1).tu1, m_cubeVertices(i+1).tv1, _
                                      vTangent, vBiNormal, vNormal)
         m_vTangents(i)  = vTangent : m_vBiNormals(i) = vBiNormal : m_vNormals(i)   = vNormal

         ' // Vertex 1 of current cube face...
         ' //
         ' //          v3
         ' //    3----2
         ' //    |    |
         ' //    |    |
         ' //    0----1
         ' //  v2      v1

         v1.x = m_cubeVertices(i+1).x : v1.y = m_cubeVertices(i+1).y : v1.z = m_cubeVertices(i+1).z
         v2.x = m_cubeVertices(i).x   : v2.y = m_cubeVertices(i).y   : v2.z = m_cubeVertices(i).z
         v3.x = m_cubeVertices(i+2).x : v3.y = m_cubeVertices(i+2).y : v3.z = m_cubeVertices(i+2).z

         ME.CreateTangentSpaceVectors(v1, v2, v3, _
                                      m_cubeVertices(i+1).tu1, m_cubeVertices(i+1).tv1, _
                                      m_cubeVertices(i).tu1, m_cubeVertices(i).tv1, _
                                      m_cubeVertices(i+2).tu1, m_cubeVertices(i+2).tv1, _
                                      vTangent, vBiNormal, vNormal)

         m_vTangents(i+1)  = vTangent : m_vBiNormals(i+1) = vBiNormal : m_vNormals(i+1)   = vNormal

         '  // Vertex 2 of current cube face...
         '  //
         '  //  v3      v1
         '  //    3----2
         '  //    |    |
         '  //    |    |
         '  //    0----1
         '  //          v2

         v1.x = m_cubeVertices(i+2).x : v1.y = m_cubeVertices(i+2).y : v1.z = m_cubeVertices(i+2).z
         v2.x = m_cubeVertices(i+1).x : v2.y = m_cubeVertices(i+1).y : v2.x = m_cubeVertices(i+1).z
         v3.x = m_cubeVertices(i+3).x : v3.y = m_cubeVertices(i+3).y : v3.z = m_cubeVertices(i+3).z

         ME.CreateTangentSpaceVectors(v1, v2, v3, _
                                      m_cubeVertices(i+2).tu1, m_cubeVertices(i+2).tv1, _
                                      m_cubeVertices(i+1).tu1, m_cubeVertices(i+1).tv1, _
                                      m_cubeVertices(i+3).tu1, m_cubeVertices(i+3).tv1, _
                                      vTangent, vBiNormal, vNormal)

         m_vTangents(i+2)  = vTangent : m_vBiNormals(i+2) = vBiNormal : m_vNormals(i+2)   = vNormal

         ' // Vertex 3 of current cube face...
         ' //
         ' //  v1      v2
         ' //    3----2
         ' //    |    |
         ' //    |    |
         ' //    0----1
         ' //  v3

         v1.x = m_cubeVertices(i+3).x : v1.y = m_cubeVertices(i+3).y : v1.z = m_cubeVertices(i+3).z
         v2.x = m_cubeVertices(i+2).x : v2.y = m_cubeVertices(i+2).y : v2.z = m_cubeVertices(i+2).z
         v3.x = m_cubeVertices(i).x   : v3.y = m_cubeVertices(i).y   : v3.z = m_cubeVertices(i).z

         ME.CreateTangentSpaceVectors(v1, v2, v3, _
                                      m_cubeVertices(i+3).tu1, m_cubeVertices(i+3).tv1, _
                                      m_cubeVertices(i+2).tu1, m_cubeVertices(i+2).tv1, _
                                      m_cubeVertices(i).tu1, m_cubeVertices(i).tv1, _
                                      vTangent, vBiNormal, vNormal)

         m_vTangents(i+3)  = vTangent : m_vBiNormals(i+3) = vBiNormal : m_vNormals(i+3)   = vNormal
      NEXT

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Check Direct3D driver for hardware support...
      LOCAL d3dCaps AS D3DCAPS9
      IF FAILED(m_pD3D.GetDeviceCaps(%D3DADAPTER_DEFAULT, _
                                     %D3DDEVTYPE_HAL, d3dCaps)) THEN
         ' // Respond to failure of GetDeviceCaps
         MessageBox(%NULL, "Call to GetDeviceCaps failed!", _
              "WARNING", %MB_OK OR %MB_ICONEXCLAMATION)
         EXIT METHOD
      END IF

      ' // Does this device support the D3DTOP_DOTPRODUCT3 texture-blending operation?
      IF (d3dCaps.TextureOpCaps AND %D3DTOP_DOTPRODUCT3) = 0 THEN
         MessageBox(%NULL, "Current Direct3D driver does not support the " & $CRLF & _
               "D3DTOP_DOTPRODUCT3 texture-blending operation!" & $CRLF & _
               "Switching to reference rasterizer!", "WARNING", %MB_OK OR %MB_ICONEXCLAMATION)
         m_deviceType = %D3DDEVTYPE_REF
      END IF

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      '// Create the device objects
      ME.CreateDeviceObjects

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture and creates the vertex buffers
   ' =====================================================================================
   METHOD CreateDeviceObjects () AS LONG

      ' // Load the normal map...
      D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\stone_wall_normal_map.bmp", m_pNormalMapTexture)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_LINEAR)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_LINEAR)

      ' // Load the base texture
      D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\stone_wall.bmp", m_pTexture)
      m_pD3DDevice.SetSamplerState(1, %D3DSAMP_MINFILTER, %D3DTEXF_LINEAR)
      m_pD3DDevice.SetSamplerState(1, %D3DSAMP_MAGFILTER, %D3DTEXF_LINEAR)

      LOCAL nSize AS LONG
      LOCAL pVertices AS Vertex PTR
      nSize = (UBOUND(m_cubeVertices) - LBOUND(m_cubeVertices) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, %D3DUSAGE_DYNAMIC, _
         %FVF_Flags, %D3DPOOL_DEFAULT, m_pVertexBuffer, %NULL)
      m_pVertexBuffer.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_cubeVertices(0)), nSize
      m_pVertexBuffer.Unlock

      LOCAL matProj AS D3DXMATRIX
      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 640.0! / 480.0!, 0.1!, 100.0!)
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

      m_pD3DDevice.SetRenderState(%D3DRS_ZENABLE, %TRUE)
      ' m_pD3DDevice.SetRenderState(%D3DRS_SHADEMODE, %D3DSHADE_FLAT)   ' // Direct3d doesn't like this at all when doing Dot3.
      m_pD3DDevice.SetRenderState(%D3DRS_SHADEMODE, %D3DSHADE_GOURAUD)

      ' // Set up lighting...
      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %TRUE)

      ' // Set up our alpha material...
      LOCAL mtrl AS D3DMATERIAL9
      mtrl.Diffuse.r = 1.0! : mtrl.Diffuse.g = 1.0! : mtrl.Diffuse.b = 1.0! : mtrl.Diffuse.a = 1.0!
      mtrl.Ambient.r = 1.0! : mtrl.Ambient.g = 1.0! : mtrl.Ambient.b = 1.0! : mtrl.Ambient.a = 1.0!
      m_pD3DDevice.SetMaterial(mtrl)

      ' // Set light 0 to be a pure white point light
      LOCAL m_light0 AS D3DLIGHT9
      m_light0.Type = %D3DLIGHT_POINT
      m_light0.Position.x = 0.0! : m_light0.Position.y = 0.0! : m_light0.Position.z = 0.0!
      ' //m_light0.Range = 10.0!
      ' //m_light0.Attenuation1 = 0.4!
      m_light0.Diffuse.r = 1.0! : m_light0.Diffuse.g = 1.0! : m_light0.Diffuse.b = 1.0! : m_light0.Diffuse.a = 1.0!
      m_pD3DDevice.SetLight(0, m_light0)
      m_pD3DDevice.LightEnable(0, %TRUE)

      ' // Create a sphere mesh to represent a point light.
      D3DXCreateSphere(m_pD3DDevice, 0.05!, 8, 8, m_pSphereMesh, BYVAL %NULL)

      ' // For each vertex, create a tangent vector, binormal, and normal
      ' // Initialize the inverse tangent matrix for each vertex to the identity
      ' // matrix before we get started.
      LOCAL i AS LONG
      FOR i = 0 TO %NUM_VERTICES - 1
         m_vTangents(i).x = 1.0! : m_vTangents(i).y = 0.0! : m_vTangents(i).z = 0.0!
         m_vBiNormals(i).x = 0.0! : m_vBiNormals(i).y = 1.0! : m_vBiNormals(i).z = 0.0!
         m_vNormals(i).x = 0.0! : m_vNormals(i).y = 0.0! : m_vNormals(i).z = 1.0!
      NEXT

      ME.ComputeTangentsMatricesForEachVertex

      ' // Return success
      METHOD = %S_OK

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene

      LOCAL  hr AS LONG
      STATIC fElapsedTime AS SINGLE
      STATIC dCurTime AS DOUBLE
      STATIC dLastTime AS DOUBLE

      dCurTime     = timeGetTime
      fElapsedTime = (dCurTime - dLastTime) * 0.001!
      dLastTime    = dCurTime

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.35!,0.53!,0.7!,1.0!), 1.0!, 0)

      IF ISTRUE m_bMoveLightAbout THEN
         ' //
         ' // Spin our point light around the cube...
         ' //

         STATIC fAngle AS SINGLE
         fAngle = fAngle + 60 * fElapsedTime
         ' // Wrap it around, if it gets too big
         WHILE fAngle > 360.0!
            fAngle = fAngle - 360.0!
         WEND
         WHILE fAngle < 0.0!
            fAngle = fAngle + 360.0!
         WEND
         LOCAL x, y AS SINGLE
         x = SIN(D3DXToRadian(fAngle))
         y = COS(D3DXToRadian(fAngle))

         ' // This will place the light directly into world-space
         m_light0.Position.x = 1.2! * x
         m_light0.Position.y = 1.2! * y
         m_light0.Position.z = m_fDistance - 2.0!
         m_pD3DDevice.SetLight(0, m_light0)
      END IF

      LOCAL matWorld, matView, matProj, matTrans, matRot AS D3DXMATRIX

      D3DXMatrixTranslation(matTrans, 0.0!, 0.0!, m_fDistance)
      D3DXMatrixRotationYawPitchRoll(matRot, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)

      ' // This sample is not really making use of a view matrix
      D3DXMatrixIdentity(matView)
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begin the scene
      m_pD3DDevice.BeginScene

      IF ISTRUE m_bToggleRegularLighting THEN
         m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %TRUE)
      ELSE
         m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %FALSE)
      END IF

      LOCAL i AS LONG
      LOCAL pVertices AS Vertex PTR
      pVertices = %NULL

      IF ISTRUE m_bDoDot3BumpMapping THEN
         ' // Render a Dot3 bump mapped cube...
         ' // Transform the light's position from world-space to model-space
         LOCAL vLightPosWS AS D3DXVECTOR3    ' // Light position (in world-space)
         LOCAL vLightPosMS AS D3DXVECTOR3    ' // Light position (in model-space)
         LOCAL vVertToLightMS AS D3DXVECTOR3 ' // L vector of N.L (in model-space)
         LOCAL vVertToLightTS AS D3DXVECTOR3 ' // L vector of N.L (in tangent-space)

         ' // Get the light's current position, which is in world-space.
         TYPE SET vLightPosWS = m_light0.Position

         ' // Transform the light's position into model-space
         LOCAL worldInverse AS D3DXMATRIX
         D3DXMatrixInverse(worldInverse, BYVAL %NULL, matWorld)
         D3DXVec3TransformCoord(vLightPosMS, vLightPosWS, worldInverse)

         ' // Since our cube's vertex data is stored in a Vertex Buffer, we will
         ' // need to lock it briefly so we can encode the new tangent-space
         ' // L vectors that we're going to create into the diffuse color of each
         ' // vertex.
         m_pVertexBuffer.Lock(0, 0, pVertices, 0)

         FOR i = 0 TO %NUM_VERTICES - 1
            ' // For each vertex, rotate L (of N.L) into tangent-space and
            ' // pass it into Direct3D's texture blending system by packing it
            ' // into the vertex's diffuse color.

            LOCAL vCurrentVertex AS D3DXVECTOR3
            vCurrentVertex.x = m_cubeVertices(i).x
            vCurrentVertex.y = m_cubeVertices(i).y
            vCurrentVertex.z = m_cubeVertices(i).z

            vVertToLightMS.x = vLightPosMS.x - vCurrentVertex.x
            vVertToLightMS.y = vLightPosMS.y - vCurrentVertex.y
            vVertToLightMS.z = vLightPosMS.z - vCurrentVertex.z

            D3DXVec3Normalize(vVertToLightMS, vVertToLightMS)

            ' // Build up an inverse tangent-space matrix using the Tangent,
            ' // Binormal, and Normal calculated for the current vertex and
            ' // then use it to transform our L vector (of N.L), which is in
            ' // model-space, into tangent-space.
            ' //
            ' // A tangent matrix is of the form:
            ' //
            ' // |Tx Bx Nx 0|
            ' // |Ty By Ny 0|
            ' // |Tz Bz Nz 0|
            ' // |0  0  0  1|
            ' //
            ' // Note: Our vectors have already been inverted, so there is no
            ' // need to invert our tangent matrix once we build it up.

            ' //                           Tangent           Binormal           Normal
            LOCAL invTangentMatrix AS D3DXMATRIX

            invTangentMatrix.m11 = m_vTangents(i).x
            invTangentMatrix.m12 = m_vBiNormals(i).x
            invTangentMatrix.m13 = m_vNormals(i).x
            invTangentMatrix.m14 = 0.0!

            invTangentMatrix.m21 = m_vTangents(i).y
            invTangentMatrix.m22 = m_vBiNormals(i).y
            invTangentMatrix.m23 = m_vNormals(i).y
            invTangentMatrix.m24 = 0.0!

            invTangentMatrix.m31 = m_vTangents(i).z
            invTangentMatrix.m32 = m_vBiNormals(i).z
            invTangentMatrix.m33 = m_vNormals(i).z
            invTangentMatrix.m34 = 0.0!

            invTangentMatrix.m41 = 0.0!
            invTangentMatrix.m42 = 0.0!
            invTangentMatrix.m43 = 0.0!
            invTangentMatrix.m44 = 1.0!

            D3DXVec3TransformNormal(vVertToLightTS, vVertToLightMS, invTangentMatrix)

            ' // Last but not least, we must encode our new L vector as a DWORD
            ' // value so we can set it as the new vertex color. Of course, the
            ' // hardware assumes that we are  going to do this, so it will
            ' // simply decode the original vector back out by reversing the
            ' // DOWRD encdoing we've performed here.

            @pVertices[i].diffuse = ME.EncodeVectorAsDWORDColor(vVertToLightTS)

         NEXT

         m_pVertexBuffer.Unlock

         ' // STAGE 0
         ' //
         ' // Use D3DTOP_DOTPRODUCT3 to find the dot-product of (N.L), where N is
         ' // stored in the normal map, and L is passed in as the vertex color -
         ' // D3DTA_DIFFUSE.

         m_pD3DDevice.SetTexture(0, m_pNormalMapTexture)
         m_pD3DDevice.SetTextureStageState(0, %D3DTSS_TEXCOORDINDEX, 0)

         m_pD3DDevice.SetTextureStageState(0, %D3DTSS_COLOROP, %D3DTOP_DOTPRODUCT3) ' // Perform a Dot3 operation...
         m_pD3DDevice.SetTextureStageState(0, %D3DTSS_COLORARG1, %D3DTA_TEXTURE)    ' // between the N (of N.L) which is stored in a normal map texture...
         m_pD3DDevice.SetTextureStageState(0, %D3DTSS_COLORARG2, %D3DTA_DIFFUSE)    ' // with the L (of N.L) which is stored in the vertex's diffuse color.

         ' // STAGE 1
         ' //
         ' // Modulate the base texture by N.L calculated in STAGE 0.

         m_pD3DDevice.SetTexture(1, m_pTexture)
         m_pD3DDevice.SetTextureStageState(1, %D3DTSS_TEXCOORDINDEX, 1)

         m_pD3DDevice.SetTextureStageState(1, %D3DTSS_COLOROP, %D3DTOP_MODULATE) ' // Modulate...
         m_pD3DDevice.SetTextureStageState(1, %D3DTSS_COLORARG1, %D3DTA_TEXTURE) ' // the texture for this stage with...
         m_pD3DDevice.SetTextureStageState(1, %D3DTSS_COLORARG2, %D3DTA_CURRENT) ' // the current argument passed down from stage 0

      ELSE

         ' // Render a regular textured cube with no Dot3 bump mapping...
         ' // Reset the vertex colors back to pure white...
         m_pVertexBuffer.Lock(0, 0, pVertices, 0)
         FOR i = 0 TO %NUM_VERTICES - 1
            @pVertices[i].diffuse = D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!)
         NEXT
         m_pVertexBuffer.Unlock

         ' // STAGE 0
         m_pD3DDevice.SetTexture(0, m_pTexture)

         m_pD3DDevice.SetTextureStageState(0, %D3DTSS_TEXCOORDINDEX, 0)
         m_pD3DDevice.SetTextureStageState(0, %D3DTSS_COLOROP,   %D3DTOP_MODULATE)
         m_pD3DDevice.SetTextureStageState(0, %D3DTSS_COLORARG1, %D3DTA_TEXTURE)
         m_pD3DDevice.SetTextureStageState(0, %D3DTSS_COLORARG2, %D3DTA_DIFFUSE)

         ' // STAGE 1
         m_pD3DDevice.SetTexture(1, NOTHING)

         m_pD3DDevice.SetTextureStageState(1, %D3DTSS_COLOROP,   %D3DTOP_MODULATE)
         m_pD3DDevice.SetTextureStageState(1, %D3DTSS_COLORARG1, %D3DTA_TEXTURE)
         m_pD3DDevice.SetTextureStageState(1, %D3DTSS_COLORARG2, %D3DTA_CURRENT)

      END IF

      ' // Now, render our textured test cube, which consists of 6 cube faces...
      m_pD3DDevice.SetStreamSource(0, m_pVertexBuffer, 0, SIZEOF(Vertex))
      m_pD3DDevice.SetFVF(%FVF_Flags)

      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  0, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  4, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  8, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 12, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 16, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 20, 2)

      ' // Render a small white sphere to mark the point light's position...
      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %FALSE)

      m_pD3DDevice.SetTexture(0, NOTHING)
      m_pD3DDevice.SetTexture(1, NOTHING)

      D3DXMatrixIdentity(matWorld)
      D3DXMatrixTranslation(matWorld, m_light0.Position.x, _
                                      m_light0.Position.y, _
                                      m_light0.Position.z)

      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)
      m_pSphereMesh.DrawSubset(0)

      ' // Ends the scene
      m_pD3DDevice.EndScene

      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the device objects
            m_pSphereMesh = NOTHING
            m_pNormalMapTexture = NOTHING
            m_pTexture = NOTHING
            m_pVertexBuffer = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the device objects
            ME.CreateDeviceObjects
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   ' ====================================================================================
   ' Processes keystrokes
   ' ====================================================================================
   METHOD ProcessKeys (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)
      SELECT CASE wMsg
         CASE %WM_CHAR
            SELECT CASE wParam
               CASE 68, 100   ' D, d
                  m_bDoDot3BumpMapping = IIF&(m_bDoDot3BumpMapping = 0, -1, 0)
               CASE 76, 108   ' L, l
                  m_bToggleRegularLighting = IIF&(m_bToggleRegularLighting = 0, -1, 0)
               CASE 77, 109   ' M, m
                  m_bMoveLightAbout = IIF&(m_bMoveLightAbout = 0, -1, 0)
            END SELECT
         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE 38   ' // Up Arrow Key
                  m_fDistance = m_fDistance - 0.1!
               CASE 40   ' // Down Arrow Key
                  m_fDistance = m_fDistance + 0.1!
            END SELECT
      END SELECT
   END METHOD
   ' ====================================================================================

   ' ====================================================================================
   ' Processes mouse
   ' ====================================================================================
   METHOD ProcessMouse (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)
      STATIC ptLastMousePosit AS POINT
      STATIC ptCurrentMousePosit AS POINT
      STATIC bMousing AS LONG
      SELECT CASE wMsg
         CASE %WM_LBUTTONDOWN
            ptLastMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptLastMousePosit.y = HI(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            bMousing = %TRUE
         CASE %WM_LBUTTONUP
            bMousing = %FALSE
         CASE %WM_MOUSEMOVE
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            IF bMousing THEN
               m_fSpinX = m_fSpinX - (ptCurrentMousePosit.x - ptLastMousePosit.x)
               m_fSpinY = m_fSpinY - (ptCurrentMousePosit.y - ptLastMousePosit.y)
            END IF
            ptLastMousePosit.x = ptCurrentMousePosit.x
            ptLastMousePosit.y = ptCurrentMousePosit.y
      END SELECT
   END METHOD
   ' ====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   SELECT CASE wMsg

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene
         EXIT FUNCTION

      CASE %WM_CHAR, %WM_KEYDOWN
         pDX9.ProcessKeys hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_LBUTTONDOWN, %WM_LBUTTONUP, %WM_MOUSEMOVE
         pDX9.ProcessMouse hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to render text to the screen using Direct3D's ID3DXFont interface.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_Fonts.bas
' Contents: DX9 example
' Description: Demonstrates how to render text to the screen using Direct3D's ID3DXFont class.
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from dx9_fonts.cpp by Kevin Harris, 02/01/05, available at
' http://www.codesampler.com/dx9src/dx9src_5.htm#dx9_fonts
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Fonts"

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS
   INSTANCE m_pD3DXFont AS ID3DXFont

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Creates the font
   ' =====================================================================================
   METHOD CreateD3DXFont

      LOCAL hr AS LONG
      LOCAL hDC AS DWORD
      LOCAL nHeight AS LONG
      LOCAL nPointSize AS LONG

      nPointSize = 18

      hDC = GetDC(%NULL)
      nHeight = -(MulDiv(nPointSize, GetDeviceCaps(hDC, %LOGPIXELSY), 72))
      ReleaseDC(%NULL, hDC)

      ' // Create a font for statistics and help output
      hr = D3DXCreateFont(m_pD3DDevice, nHeight, 0, %FW_BOLD, 0, %FALSE, _
                          %DEFAULT_CHARSET, %OUT_DEFAULT_PRECIS, %DEFAULT_QUALITY, _
                          %DEFAULT_PITCH OR %FF_DONTCARE, "Arial", m_pD3DXFont)

      IF FAILED(hr) THEN
         MessageBox(%NULL,"Call to D3DXCreateFont failed!", "ERROR", %MB_OK OR %MB_ICONEXCLAMATION)
      END IF

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates the font
      ME.CreateD3DXFont

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene (BYVAL pWindow AS IWindow)

      LOCAL  hr AS LONG

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.0!,0.0!,0.0!,1.0!), 1.0!, 0)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      ' // Render some text using our new font...
      LOCAL destRect1, destRect2, destRect3 AS RECT
      SetRect(destRect1, 100 * pWindow.rxRatio, 100 * pWindow.ryRatio, 0, 0)
      SetRect(destRect2, 200 * pWindow.rxRatio, 200 * pWindow.ryRatio, 0, 0)
      SetRect(destRect3, 300 * pWindow.rxRatio, 300 * pWindow.ryRatio, 0, 0)

      m_pD3DXFont.DrawTextA(NOTHING, "This is line 1", -1, destRect1, %DT_NOCLIP, _
                          D3DCOLOR_COLORVALUE(1.0!, 0.0!, 0.0!, 1.0!))
      m_pD3DXFont.DrawTextA(NOTHING, "This is line 2", -1, destRect2, %DT_NOCLIP, _
                          D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!))
      m_pD3DXFont.DrawTextA(NOTHING, "This is line 3", -1, destRect3, %DT_NOCLIP, _
                          D3DCOLOR_COLORVALUE(0.0!, 0.0!, 1.0!, 1.0!))

      ' // Ends the scene
      m_pD3DDevice.EndScene

      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the font
            m_pD3DXFont = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the font
            ME.CreateD3DXFont
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   STATIC pWindow AS IWindow        ' // Reference to the IWindow interface

   SELECT CASE wMsg

      CASE %WM_CREATE
         ' // Get a reference to the IWindow interface from the CREATESTRUCT structure
         pWindow = CWindow_GetObjectFromCreateStruct(lParam)
         EXIT FUNCTION

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene(pWindow)
         EXIT FUNCTION

      CASE %WM_KEYDOWN
         SELECT CASE LO(WORD, wParam)
            CASE %VK_ESCAPE
               SendMessage hwnd, %WM_CLOSE, 0, 0
               EXIT FUNCTION
         END SELECT

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to optimize performance by using indexed geometry. As a demonstration, the sample reduces the vertex count of a simple cube from 24 to 8 by redefining the cube's geometry using an indices array.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_IndexedGeometry.bas
' Contents: DX9 example
' Description: Demonstrates how to optimize performance by using indexed geometry. As a
' demonstration, the sample reduces the vertex count of a simple cube from 24 to 8 by
' redefining the cube's geometry using an indices array.
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from dx9_indexed_geometry.cpp by Kevin Harris, 06/15/05, available at
' http://www.codesampler.com/dx9src/dx9src_2.htm#dx9_indexed_geometry
' Control Keys: F1 - Toggles between indexed and non-indexed geometry.
'                    Shouldn't produce any noticeable change since they render the same cube.
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Indexed Geometry"

%FVF_Flags = %D3DFVF_XYZ OR %D3DFVF_DIFFUSE

TYPE Vertex
   x       AS SINGLE
   y       AS SINGLE
   z       AS SINGLE
   dwColor AS DWORD
END TYPE

' ========================================================================================
' Fills a Vertex structure
' ========================================================================================
MACRO FillVertex (v, x_, y_, z_, dwColor_)
   v.x = x_ : v.y = y_ : v.z = z_ : v.dwColor = dwColor_
END MACRO
' ========================================================================================

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS
   INSTANCE m_pVertexBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_pVertexBuffer_Indexed AS IDirect3DVertexBuffer9
   INSTANCE m_pIndexBuffer AS IDirect3DIndexBuffer9
   INSTANCE m_cubeVertices () AS Vertex
   INSTANCE m_cubeVertices_indexed () AS Vertex
   INSTANCE m_cubeIndices () AS WORD
   INSTANCE m_bUseIndexedGeometry AS LONG
   INSTANCE m_fSpinX AS SINGLE
   INSTANCE m_fSpinY AS SINGLE

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      DIM m_cubeVertices(23) AS INSTANCE Vertex
      ' Quad 0
      FillVertex(m_cubeVertices( 0), -1.0!,  1.0!, -1.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_cubeVertices( 1),  1.0!,  1.0!, -1.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_cubeVertices( 2), -1.0!, -1.0!, -1.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_cubeVertices( 3),  1.0!, -1.0!, -1.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 0.0, 1.0))
      ' Quad 1
      FillVertex(m_cubeVertices( 4), -1.0!,  1.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 1.0, 1.0))
      FillVertex(m_cubeVertices( 5), -1.0!, -1.0!,  1.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 1.0, 1.0))
      FillVertex(m_cubeVertices( 6),  1.0!,  1.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 1.0, 1.0))
      FillVertex(m_cubeVertices( 7),  1.0!, -1.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      ' Quad 2
      FillVertex(m_cubeVertices( 8), -1.0!,  1.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 1.0, 1.0))
      FillVertex(m_cubeVertices( 9),  1.0!,  1.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 1.0, 1.0))
      FillVertex(m_cubeVertices(10), -1.0!,  1.0!, -1.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_cubeVertices(11),  1.0!,  1.0!, -1.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      ' Quad 3
      FillVertex(m_cubeVertices(12), -1.0!, -1.0!,  1.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 1.0, 1.0))
      FillVertex(m_cubeVertices(13), -1.0!, -1.0!, -1.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_cubeVertices(14),  1.0!, -1.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_cubeVertices(15),  1.0!, -1.0!, -1.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 0.0, 1.0))
      ' Quad 4
      FillVertex(m_cubeVertices(16),  1.0!,  1.0!, -1.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_cubeVertices(17),  1.0!,  1.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 1.0, 1.0))
      FillVertex(m_cubeVertices(18),  1.0!, -1.0!, -1.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 0.0, 1.0))
      FillVertex(m_cubeVertices(19),  1.0!, -1.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      ' Quad 5
      FillVertex(m_cubeVertices(20), -1.0!,  1.0!, -1.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_cubeVertices(21), -1.0!, -1.0!, -1.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_cubeVertices(22), -1.0!,  1.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 1.0, 1.0))
      FillVertex(m_cubeVertices(23), -1.0!, -1.0!,  1.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 1.0, 1.0))
      '// Now, to save ourselves the bandwidth of passing a bunch or redundant vertices
      '// down the graphics pipeline, we shorten our vertex list and pass only the
      '// unique vertices. We then create a indices array, which contains index values
      '// that reference vertices in our vertex array.
      '//
      '// In other words, the vertex array doens't actually define our cube anymore,
      '// it only holds the unique vertices; it's the indices array that now defines
      '// the cube's geometry.
      DIM m_cubeVertices_indexed(7)
      FillVertex(m_cubeVertices_indexed(0), -1.0!,  1.0!, -1.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_cubeVertices_indexed(1),  1.0!,  1.0!, -1.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_cubeVertices_indexed(2), -1.0!, -1.0!, -1.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_cubeVertices_indexed(3),  1.0!, -1.0!, -1.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 0.0, 1.0))
      FillVertex(m_cubeVertices_indexed(4), -1.0!,  1.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 1.0, 1.0))
      FillVertex(m_cubeVertices_indexed(5), -1.0!, -1.0!,  1.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 1.0, 1.0))
      FillVertex(m_cubeVertices_indexed(6),  1.0!,  1.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 1.0, 1.0))
      FillVertex(m_cubeVertices_indexed(7),  1.0!, -1.0!,  1.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      DIM m_cubeIndices(23)
      ARRAY ASSIGN m_cubeIndices() = 0, 1, 2, 3, 4, 5, 6, 7, 4, 6, 0, 1, 5, 2, 7, 3, 1, 6, 3, 7, 0, 2, 4, 5
   END METHOD
   ' ====================================================================================

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      '// Create the device objects
      ME.CreateDeviceObjects

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture and creates the vertex buffers
   ' =====================================================================================
   METHOD CreateDeviceObjects () AS LONG

      ' // Sets a device render-state parameter
      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %FALSE)
      m_pD3DDevice.SetRenderState(%D3DRS_ZENABLE, %TRUE)

      ' // Builds a left-handed perspective projection matrix based on a field of view
      LOCAL matProj AS D3DXMATRIX
      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 600.0! / 400.0!, 0.1!, 100.0!)
      ' // Sets a device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

      ' // Create a vertex buffer...

      LOCAL nSize AS LONG
      LOCAL pVertices AS DWORD
      nSize = (UBOUND(m_cubeVertices) - LBOUND(m_cubeVertices) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, %D3DUSAGE_WRITEONLY, _
         %FVF_Flags, %D3DPOOL_DEFAULT, m_pVertexBuffer, %NULL)
      m_pVertexBuffer.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_cubeVertices(0)), nSize
      m_pVertexBuffer.Unlock

      ' // Create a vertex buffer, which contains indexed geometry...

      pVertices = 0
      nSize = (UBOUND(m_cubeVertices_indexed) - LBOUND(m_cubeVertices_indexed) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, %D3DUSAGE_WRITEONLY, _
         %FVF_Flags, %D3DPOOL_DEFAULT, m_pVertexBuffer_Indexed, %NULL)
      m_pVertexBuffer_Indexed.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_cubeVertices_indexed(0)), nSize
      m_pVertexBuffer_Indexed.Unlock

      ' // Create an index buffer to use with our indexed vertex buffer...

      LOCAL pIndices AS DWORD
      nSize = (UBOUND(m_cubeIndices) - LBOUND(m_cubeIndices) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateIndexBuffer(nSize, %D3DUSAGE_WRITEONLY, _
         %D3DFMT_INDEX16, %D3DPOOL_DEFAULT, m_pIndexBuffer, %NULL)
      m_pIndexBuffer.Lock(0, nSize, pIndices, 0)
      MoveMemory BYVAL pIndices, BYVAL VARPTR(m_cubeIndices(0)), nSize
      m_pIndexBuffer.Unlock

      ' // Return success
      METHOD = %S_OK

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene

      LOCAL  hr AS LONG

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.35!,0.53!,0.7!,1.0!), 1.0!, 0)

      LOCAL matWorld AS D3DXMATRIX
      LOCAL matTrans AS D3DXMATRIX
      LOCAL matRot AS D3DXMATRIX

      ' // Builds a matrix using the specified offsets
      D3DXMatrixTranslation(matTrans, 0.0!, 0.0!, 5.0!)
      ' // Builds a matrix with a specified yaw, pitch, and roll
      D3DXMatrixRotationYawPitchRoll(matRot, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)
      ' // Determines the product of the two matrices
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      ' // Sets the device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      IF ISTRUE m_bUseIndexedGeometry THEN
         m_pD3DDevice.SetStreamSource(0, m_pVertexBuffer_Indexed, 0, SIZEOF(Vertex))
         m_pD3DDevice.SetIndices(m_pIndexBuffer)
         m_pD3DDevice.SetFVF(%FVF_Flags)
         m_pD3DDevice.DrawIndexedPrimitive(%D3DPT_TRIANGLESTRIP, 0, 0, 8,  0, 2)
         m_pD3DDevice.DrawIndexedPrimitive(%D3DPT_TRIANGLESTRIP, 0, 0, 8,  4, 2)
         m_pD3DDevice.DrawIndexedPrimitive(%D3DPT_TRIANGLESTRIP, 0, 0, 8,  8, 2)
         m_pD3DDevice.DrawIndexedPrimitive(%D3DPT_TRIANGLESTRIP, 0, 0, 8, 12, 2)
         m_pD3DDevice.DrawIndexedPrimitive(%D3DPT_TRIANGLESTRIP, 0, 0, 8, 16, 2)
         m_pD3DDevice.DrawIndexedPrimitive(%D3DPT_TRIANGLESTRIP, 0, 0, 8, 20, 2)
      ELSE
         m_pD3DDevice.SetStreamSource(0, m_pVertexBuffer, 0, SIZEOF(Vertex))
         m_pD3DDevice.SetFVF(%FVF_Flags)
         m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  0, 2)
         m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  4, 2)
         m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  8, 2)
         m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 12, 2)
         m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 16, 2)
         m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 20, 2)
      END IF

      ' // Ends the scene
      m_pD3DDevice.EndScene
      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the device objects
            m_pVertexBuffer = NOTHING
            m_pVertexBuffer_Indexed = NOTHING
            m_pIndexBuffer = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the device objects
            ME.CreateDeviceObjects
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   ' ====================================================================================
   ' Processes keystrokes
   ' ====================================================================================
   METHOD ProcessKeys (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      SELECT CASE wMsg

         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE %VK_F1
                  m_bUseIndexedGeometry = NOT m_bUseIndexedGeometry
            END SELECT

      END SELECT

   END METHOD
   ' ====================================================================================

   ' ====================================================================================
   ' Processes mouse
   ' ====================================================================================
   METHOD ProcessMouse (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      STATIC ptLastMousePosit AS POINT
      STATIC ptCurrentMousePosit AS POINT
      STATIC bMousing AS LONG

      SELECT CASE wMsg

         CASE %WM_LBUTTONDOWN
            ptLastMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptLastMousePosit.y = HI(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            bMousing = %TRUE

         CASE %WM_LBUTTONUP
            bMousing = %FALSE

         CASE %WM_MOUSEMOVE
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            IF bMousing THEN
               m_fSpinX = m_fSpinX - (ptCurrentMousePosit.x - ptLastMousePosit.x)
               m_fSpinY = m_fSpinY - (ptCurrentMousePosit.y - ptLastMousePosit.y)
            END IF
            ptLastMousePosit.x = ptCurrentMousePosit.x
            ptLastMousePosit.y = ptCurrentMousePosit.y

      END SELECT

   END METHOD
   ' ====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   SELECT CASE wMsg

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene
         EXIT FUNCTION

      CASE %WM_KEYDOWN
         pDX9.ProcessKeys hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_LBUTTONDOWN, %WM_LBUTTONUP, %WM_MOUSEMOVE
         pDX9.ProcessMouse hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to setup a spot light with Direct3D. The sample also demonstrates how the tessellation or triangle count of a mesh effects lighting.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_Lighting.bas
' Contents: DX9 example
' Description: Demonstrates the three basic types of lights that are available in
' Direct3D: directional, spot, and point.
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from dx9_spot_light.cpp by Kevin Harris, 02/01/05, available at
' http://www.codesampler.com/dx9src/dx9src_6.htm#dx9_lighting
' Control Keys: F1 - Changes the light's type
'               F2 - Toggles wire frame mode
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Lighting"

%FVF_Flags = %D3DFVF_XYZ OR %D3DFVF_NORMAL OR %D3DFVF_DIFFUSE

TYPE Vertex
   ' Position of vertex in 3D space
   x       AS SINGLE
   y       AS SINGLE
   z       AS SINGLE
   ' Normal for lighting calculations
   nx      AS SINGLE
   ny      AS SINGLE
   nz      AS SINGLE
   ' Diffuse color of vertex
   diffuse AS DWORD
END TYPE

' enum LightTypes
%LIGHT_TYPE_DIRECTIONAL = 0
%LIGHT_TYPE_SPOT        = 1
%LIGHT_TYPE_POINT       = 2

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS

   INSTANCE m_pMeshVertices AS IDirect3DVertexBuffer9    ' // Vertex buffer for the walls and floor
   INSTANCE m_pSphereMesh AS ID3DXMesh                   ' // A mesh to represent a point light
   INSTANCE m_pConeMesh AS ID3DXMesh                     ' // A mesh to represent a directional or spot light
   INSTANCE m_bRenderInWireFrame AS LONG
   INSTANCE m_lightType AS LONG

   '// Mesh properties...
   INSTANCE m_nNumVertsAlongX AS LONG
   INSTANCE m_nNumVertsAlongZ AS LONG
   INSTANCE m_fMeshLengthAlongX AS SINGLE
   INSTANCE m_fMeshLengthAlongZ AS SINGLE
   INSTANCE m_nMeshVertCount AS LONG

   ' ====================================================================================
   ' Initializes values
   ' ====================================================================================
   CLASS METHOD Create
      m_bRenderInWireFrame = %FALSE
      m_nNumVertsAlongX    = 32
      m_nNumVertsAlongZ    = 32
      m_fMeshLengthAlongX  = 10.0!
      m_fMeshLengthAlongZ  = 10.0!
      m_nMeshVertCount     = (m_nNumVertsAlongX - 1) * (m_nNumVertsAlongZ - 1) * 6
      m_lightType          = %LIGHT_TYPE_DIRECTIONAL
   END METHOD
   ' ====================================================================================

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Init lights
   ' =====================================================================================
   METHOD initLights

      ' // Set up a material
      LOCAL mtrl AS D3DMATERIAL9
      mtrl.Diffuse.r = 1.0!
      mtrl.Diffuse.g = 1.0!
      mtrl.Diffuse.b = 1.0!
      mtrl.Diffuse.a = 1.0!
      mtrl.Ambient.r = 1.0!
      mtrl.Ambient.g = 1.0!
      mtrl.Ambient.b = 1.0!
      mtrl.Ambient.a = 1.0!
      m_pD3DDevice.SetMaterial(mtrl)

      ' // Set light 0 to be a simple, bright directional light to use
      ' // on the mesh that will represent light 2
      LOCAL v AS D3DXVECTOR3
      LOCAL light_0 AS  D3DLIGHT9
      light_0.Type = %D3DLIGHT_DIRECTIONAL
      v.x = 0.5! : v.y = -0.5! : v.z = 0.5!
      TYPE SET light_0.Direction = v
      light_0.Diffuse.r = 1.0!
      light_0.Diffuse.g = 1.0!
      light_0.Diffuse.b = 1.0!
      m_pD3DDevice.SetLight(0, light_0)

      ' // Set light 1 to be a simple, faint grey directional light so
      ' // the walls and floor are slightly different shades of grey
      LOCAL light_1 AS D3DLIGHT9
      light_1.Type = %D3DLIGHT_DIRECTIONAL
      v.x = 0.3! : v.y = -0.5! : v.z = 0.2!
      TYPE SET light_1.Direction = v
      light_1.Diffuse.r = 0.25!
      light_1.Diffuse.g = 0.25!
      light_1.Diffuse.b = 0.25!
      m_pD3DDevice.SetLight(1, light_1)

      ' // Light #2 will be the demo light used to light the floor and walls.
      ' // It will be set up in render() since its type can be changed at
      ' // run-time.

      ' // Enable some dim, grey ambient lighting so objects that are not lit
      ' // by the other lights are not completely black.
      m_pD3DDevice.SetRenderState(%D3DRS_AMBIENT, _
                                  D3DCOLOR_COLORVALUE(0.25, 0.25, 0.25, 1.0))

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Create mesh
   ' =====================================================================================
   METHOD createMesh

      ' // Compute position deltas for moving down the X, and Z axis during mesh creation
      LOCAL dX, dZ AS SINGLE
      dX = 1.0! / (m_nNumVertsAlongX - 1)
      dZ = 1.0! / (m_nNumVertsAlongZ - 1)

      m_pD3DDevice.CreateVertexBuffer(m_nMeshVertCount * SIZEOF(Vertex), _
                                      %D3DUSAGE_WRITEONLY, %FVF_Flags, _
                                      %D3DPOOL_MANAGED, m_pMeshVertices, %NULL)

      LOCAL i, x, z AS LONG
      LOCAL v AS Vertex PTR

      m_pMeshVertices.Lock(0, 0, v, 0)

      ' // These are all the same...
      FOR i = 0 TO m_nMeshVertCount - 1
         ' // Mesh tesselation occurs in the X,Z plane, so Y is always zero
         @v[i].nx = 0.0!
         @v[i].ny = 1.0!
         @v[i].nz = 0.0!
         @v[i].diffuse = D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!)
      NEXT

      ' // Create all the vertex points required by the mesh...
      ' //
      ' // Note: Mesh tesselation occurs in the X,Z plane.

      ' // For each row of our mesh...
      i = 0
      FOR z = 0 TO m_nNumVertsAlongZ - 2
         ' // Fill the row with quads which are composed of two triangles each...
         FOR x = 0 TO m_nNumVertsAlongX - 2
            ' // First triangle of the current quad
            ' // 1 ___ 2
            ' //  |  /|
            ' //  |/__|
            ' // 0

            ' // 0
            @v[i].x = m_fMeshLengthAlongX * x * dX
            @v[i].z = m_fMeshLengthAlongZ * z * dZ
            i = i + 1

            ' // 1
            @v[i].x = m_fMeshLengthAlongX * x * dX
            @v[i].z = m_fMeshLengthAlongZ * (z + 1) * dZ
            i = i + 1

            ' // 2
            @v[i].x = m_fMeshLengthAlongX * (x + 1) * dX
            @v[i].z = m_fMeshLengthAlongZ * (z + 1) * dZ
            i = i + 1

            ' // Second triangle of the current quad
            ' //   ___ 1
            ' //  |  /|
            ' //  |/__|
            ' // 0     2

            ' // 0
            @v[i].x = m_fMeshLengthAlongX * x * dX
            @v[i].z = m_fMeshLengthAlongZ * z * dZ
            i = i + 1

            ' // 1
            @v[i].x = m_fMeshLengthAlongX * (x + 1) * dX
            @v[i].z = m_fMeshLengthAlongZ * (z + 1) * dZ
            i = i + 1

            ' // 2
            @v[i].x = m_fMeshLengthAlongX * (x + 1) * dX
            @v[i].z = m_fMeshLengthAlongZ * z * dZ
            i = i + 1
         NEXT
      NEXT

      m_pMeshVertices.Unlock

      ' // Create a sphere mesh to represent a point light.
      D3DXCreateSphere(m_pD3DDevice, 0.25!, 20, 20, m_pSphereMesh, BYVAL %NULL)

      ' // Create a cone mesh to represent a directional or spot light.
      D3DXCreateCylinder(m_pD3DDevice, 0.0!, 0.25!, 0.5!, 20, 20, m_pConeMesh, BYVAL %NULL)

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      LOCAL dCaps AS D3DCAPS9
      m_pD3D.GetDeviceCaps(%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, dCaps)
      IF (dCaps.VertexProcessingCaps AND %D3DVTXPCAPS_POSITIONALLIGHTS) = 0 THEN
         ' // If D3DVTXPCAPS_POSITIONALLIGHTS is not set, the device does
         ' // not support point or spot lights and the demo won't run properly.
         ' //MessageBox( g_hWnd, "This hardware doesn't support spot or point lights!",
         '             //"Direct3D Lighting", MB_OK );
      END IF

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      '// Create the device objects
      ME.CreateDeviceObjects

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture and creates the vertex buffers
   ' =====================================================================================
   METHOD CreateDeviceObjects () AS LONG

      LOCAL hr AS LONG
      LOCAL matProj AS D3DXMATRIX

      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 600.0! / 400.0!, 0.1!, 100.0!)
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %TRUE)
      m_pD3DDevice.SetRenderState(%D3DRS_ZENABLE, %FALSE)
      m_pD3DDevice.SetRenderState(%D3DRS_DITHERENABLE, %FALSE)
      m_pD3DDevice.SetRenderState(%D3DRS_SPECULARENABLE, %FALSE)

      LOCAL matView AS D3DXMATRIX
      LOCAL v1, v2, v3 AS D3DXVECTOR3
      v1.x = -12.0! : v1.y = 12.0! : v1.z = -12.0!   ' // Camera position
      v2.x =   0.0! : v2.y = -1.5! : v2.z =   0.0!   ' // Look-at point
      v3.x =   0.0! : v3.y =  1.0! : v3.z =   0.0!   ' // Up vector
      D3DXMatrixLookAtLH(matView, v1, v2, v3)
      m_pD3DDevice.SetTransform(%D3DTS_VIEW, matView)

      ME.initLights
      ME.createMesh

      ' // Return success
      METHOD = %S_OK

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene

      LOCAL hr AS LONG

      ' // Create light 2 at run-time based on the light type the user has selected.

      STATIC fElapsedAppTime AS SINGLE
      STATIC dStartTime AS DOUBLE

      IF dStartTime = 0 THEN dStartTime = timeGetTime
      fElapsedAppTime = (timeGetTime - dStartTime) * 0.001!

      LOCAL x, y, z AS SINGLE

      x = SIN(fElapsedAppTime * 2.000!)
      y = SIN(fElapsedAppTime * 2.246!)
      z = SIN(fElapsedAppTime * 2.640!)

      LOCAL light_2 AS D3DLIGHT9

      light_2.Diffuse.r = 1.0!
      light_2.Diffuse.g = 1.0!
      light_2.Diffuse.b = 1.0!
      light_2.Range     = 100.0!

      ' // While both Direct3D and OpenGL use the same formula for lighting
      ' // attenuation, they call the variables by different names when setting
      ' // them through the API. The following two formulas are the same and
      ' // only differ by the API names used for each variable.
      ' //
      ' // Direct3D:
      ' //
      ' // attenuation = 1 / ( Attenuation0 +
      ' //                     Attenuation1 * d +
      ' //                     Attenuation2 * d2 )
      ' //
      ' // OpenGL:
      ' //
      ' // attenuation = 1 / ( GL_CONSTANT_ATTENUATION  +
      ' //                     GL_LINEAR_ATTENUATION    * d +
      ' //                     GL_QUADRATIC_ATTENUATION * d2 )
      ' //
      ' // Where:  d = Distance from vertex position to light position
      ' //        d2 = d squared

      LOCAL v AS D3DXVECTOR3

      SELECT CASE AS LONG m_lightType
         CASE %LIGHT_TYPE_DIRECTIONAL
            light_2.Type      = %D3DLIGHT_DIRECTIONAL
            v.x = x : v.y = y : v.z = z
            TYPE SET light_2.Direction = v
         CASE %LIGHT_TYPE_SPOT
            light_2.Type         = %D3DLIGHT_SPOT
            v.x = x * 2.0! : v.y = y * 2.0! : v.z = z * 2.0!
            TYPE SET light_2.Position = v
            v.x = x : v.y = y : v.z = z
            TYPE SET light_2.Direction = v
            light_2.Theta        = 0.5!
            light_2.Phi          = 1.0!
            light_2.Falloff      = 1.0!
            light_2.Attenuation0 = 1.0!
         CASE %LIGHT_TYPE_POINT
            light_2.Type         = %D3DLIGHT_POINT
            v.x = x * 4.5! : v.y = y * 4.5! : v.z = z * 4.5!
            TYPE SET light_2.Position = v
            light_2.Attenuation1 = 0.4!
      END SELECT

      m_pD3DDevice.SetLight(2, light_2)

      ' // Render...

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.0!,0.0!,0.0!,1.0!), 1.0!, 0)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      m_pD3DDevice.SetStreamSource(0, m_pMeshVertices, 0, SIZEOF(Vertex))
      m_pD3DDevice.SetFVF(%FVF_Flags)

      LOCAL matWorld AS D3DXMATRIX
      LOCAL matTrans AS D3DXMATRIX
      LOCAL matRotate AS D3DXMATRIX

      ' // The first thing we draw is our walls. The walls are to be lit
      ' // by lights 1 and 2 only, so we need to turn on lights 1 and 2,
      ' // and turn off light 0. Light 0 will be used later for the meshes.

      m_pD3DDevice.LightEnable(0, %FALSE)
      m_pD3DDevice.LightEnable(1, %TRUE)
      m_pD3DDevice.LightEnable(2, %TRUE)

      ' // Draw the floor
      D3DXMatrixTranslation(matTrans, -5.0!, -5.0!, -5.0!)
      D3DXMatrixRotationZ(matRotate, 0.0!)
      D3DXMatrixMultiply(matWorld, matRotate, matTrans)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLELIST, 0, m_nMeshVertCount / 3)

      ' // Draw the back wall
      D3DXMatrixTranslation(matTrans, 5.0!,-5.0!, -5.0!)
      D3DXMatrixRotationZ(matRotate, D3DXToRadian(90.0))
      D3DXMatrixMultiply(matWorld, matRotate, matTrans)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLELIST, 0, m_nMeshVertCount / 3)

      ' // Draw the side wall
      D3DXMatrixTranslation(matTrans, -5.0!, -5.0!, 5.0!)
      D3DXMatrixRotationX(matRotate,  -D3DXToRadian(90.0))
      D3DXMatrixMultiply(matWorld, matRotate, matTrans)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLELIST, 0, m_nMeshVertCount / 3)

      ' // We're finished drawing the walls, we'll now draw the mesh that
      ' // represents the light's type. We'll use a little cone for a
      ' // directional or spot light and a little sphere for a point light.
      ' // Light 0 is just for our little meshes, so turn on light 0, and
      ' // turn off lights 1 and 2 before rendering.

      m_pD3DDevice.LightEnable(0, %TRUE)
      m_pD3DDevice.LightEnable(1, %FALSE)
      m_pD3DDevice.LightEnable(2, %FALSE)

      ' // Draw the correct mesh representing the current light type...
      IF m_lightType = %LIGHT_TYPE_POINT THEN
         ' // Just position the point light - no need to orient it
         D3DXMatrixTranslation(matWorld, light_2.Position.x, _
               light_2.Position.y, light_2.Position.z)
         m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)
         m_pSphereMesh.DrawSubset(0)
      ELSE
         ' // Position the light and then point it in the light's direction
         LOCAL vecFrom, vecAt, vecUp AS D3DXVECTOR3
         vecFrom.x = light_2.Position.x
         vecFrom.y = light_2.Position.y
         vecFrom.z = light_2.Position.z
         vecAt.x   = light_2.Position.x + light_2.Direction.x
         vecAt.y   = light_2.Position.y + light_2.Direction.y
         vecAt.z   = light_2.Position.z + light_2.Direction.z
         vecUp.x = 0.0! : vecUp.y = 1.0! : vecUp.z = 0.0!
         LOCAL matWorldInv AS D3DXMATRIX
         D3DXMatrixLookAtLH(matWorldInv, vecFrom, vecAt, vecUp)
         D3DXMatrixInverse(matWorld, BYVAL %NULL, matWorldInv)
         m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)
         m_pConeMesh.DrawSubset(0)
      END IF

      ' // Ends the scene
      m_pD3DDevice.EndScene

      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the device objects
            m_pMeshVertices = NOTHING
            m_pSphereMesh = NOTHING
            m_pConeMesh = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the device objects
            ME.CreateDeviceObjects
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   ' ====================================================================================
   ' Processes keystrokes
   ' ====================================================================================
   METHOD ProcessKeys (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      SELECT CASE wMsg

         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE %VK_F1
                  m_lightType = m_lightType + 1
                  IF m_lightType > 2 THEN m_lightType = 0
               CASE %VK_F2
                  m_bRenderInWireFrame = IIF&(m_bRenderInWireFrame = 0, -1, 0)
                  IF ISTRUE m_bRenderInWireFrame THEN
                     m_pD3DDevice.SetRenderState(%D3DRS_FILLMODE, %D3DFILL_WIREFRAME)
                  ELSE
                     m_pD3DDevice.SetRenderState(%D3DRS_FILLMODE, %D3DFILL_SOLID)
                  END IF
            END SELECT

      END SELECT

   END METHOD
   ' ====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   SELECT CASE wMsg

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene
         EXIT FUNCTION

      CASE %WM_KEYDOWN
         pDX9.ProcessKeys hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to manually load the vertex buffer of a D3DXMesh object.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_LoadingMesh.bas
' Contents: DX9 example
' Description: Demonstrates how to manually load the vertex buffer of a D3DXMesh object.
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from dx9_loading_mesh_vb.cpp by Kevin Harris, 05/22/05, available at
' http://www.codesampler.com/dx9src/dx9src_11.htm#dx9_mesh_loading_vb
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Loading Mesh Vertex Buffers"

%FVF_Flags = %D3DFVF_XYZ OR %D3DFVF_DIFFUSE

TYPE Vertex
   x       AS SINGLE
   y       AS SINGLE
   z       AS SINGLE
   dwColor AS DWORD
END TYPE

' ========================================================================================
' Fills a Vertex structure
' ========================================================================================
MACRO FillVertex (v, x_, y_, z_, dwColor_)
   v.x = x_ : v.y = y_ : v.z = z_ : v.dwColor = dwColor_
END MACRO
' ========================================================================================

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS
   INSTANCE m_pMesh AS ID3DXMesh
   INSTANCE m_quadVertices () AS Vertex
   INSTANCE m_fDistance AS SINGLE
   INSTANCE m_fSpinX AS SINGLE
   INSTANCE m_fSpinY AS SINGLE

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      m_fDistance = 4.0!
      DIM m_quadVertices(3) AS INSTANCE Vertex
      ' // Bottom-Left,  color = yellow
      FillVertex(m_quadVertices(0), -1.0!, -1.0!,  0.0!, &Hffffff00)
      ' // Bottom-Right, color = green
      FillVertex(m_quadVertices(1),  1.0!, -1.0!,  0.0!, &Hff00ff00)
      ' // Top-Right,    color = red
      FillVertex(m_quadVertices(2),  1.0!,  1.0!,  0.0!, &Hffff0000)
      ' // Top-Left,     color = blue
      FillVertex(m_quadVertices(3), -1.0!,  1.0!,  0.0!, &Hff0000ff)
   END METHOD
   ' ====================================================================================

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      '// Create the device objects
      ME.CreateDeviceObjects

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture and creates the vertex buffers
   ' =====================================================================================
   METHOD CreateDeviceObjects () AS LONG

      LOCAL hr AS LONG
      LOCAL matProj AS D3DXMATRIX

      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 600.0! / 400.0!, 0.1!, 100.0!)
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %FALSE)
      m_pD3DDevice.SetRenderState(%D3DRS_CULLMODE, %D3DCULL_NONE)

      ' // Create a mesh container...
      hr = D3DXCreateMeshFVF(2, _  ' // Our quads has 2 faces or triangles...
                             4, _  ' // which require 4 vertices to define.
                             %D3DXMESH_MANAGED, %FVF_Flags, _
                             m_pd3dDevice, m_pMesh)

      ' // Load our quad's vertices...
      LOCAL pVertices AS Vertex PTR
      m_pMesh.LockVertexBuffer(0, pVertices)

      @pVertices[0] = m_quadVertices(0)
      @pVertices[1] = m_quadVertices(1)
      @pVertices[2] = m_quadVertices(2)
      @pVertices[3] = m_quadVertices(3)

      ' // If you wanted, you could also memcpy the whole thing in like so.
      ' //memcpy( pVertices, m_quadVertices, sizeof(m_quadVertices) );
      ' nSize = (UBOUND(m_quadVertices) - LBOUND(m_quadVertices) + 1) * SIZEOF(Vertex)
      ' MoveMemory BYVAL pVertices, BYVAL VARPTR(m_quadVertices(0)), nSize

      m_pMesh.UnlockVertexBuffer

      ' //
      ' // Define our quad's indices...
      ' //

      LOCAL pIndices AS WORD PTR
      m_pMesh.LockIndexBuffer(0, pIndices)

      ' // First triangle of quad
      @pIndices[0] = 0
      @pIndices[1] = 1
      @pIndices[2] = 2

      ' // Second triangle of quad
      @pIndices[3] = 0
      @pIndices[4] = 2
      @pIndices[5] = 3

      m_pMesh.UnlockIndexBuffer

      ' // Return success
      METHOD = %S_OK

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.35!,0.53!,0.7!,1.0!), 1.0!, 0)

      LOCAL hr AS LONG
      LOCAL matWorld AS D3DXMATRIX
      LOCAL matTrans AS D3DXMATRIX
      LOCAL matRot AS D3DXMATRIX

      ' // Builds a matrix using the specified offsets
      D3DXMatrixTranslation(matTrans, 0.0!, 0.0!, m_fdistance)
      ' // Builds a matrix with a specified yaw, pitch, and roll
      D3DXMatrixRotationYawPitchRoll(matRot, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)
      ' // Determines the product of the two matrices
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      ' // Sets the device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      ' // Now, lets render something with our newly loaded mesh object...
      m_pMesh.DrawSubset(0)

      ' // Ends the scene
      m_pD3DDevice.EndScene

      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the device objects
            m_pMesh = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the device objects
            ME.CreateDeviceObjects
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   ' ====================================================================================
   ' Processes keystrokes
   ' ====================================================================================
   METHOD ProcessKeys (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      SELECT CASE wMsg

         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE 38   ' // Up Arrow Key
                  m_fDistance = m_fDistance - 0.1!
               CASE 40   ' // Down Arrow Key
                  m_fDistance = m_fDistance + 0.1!
            END SELECT

      END SELECT

   END METHOD
   ' ====================================================================================

   ' ====================================================================================
   ' Processes mouse
   ' ====================================================================================
   METHOD ProcessMouse (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      STATIC ptLastMousePosit AS POINT
      STATIC ptCurrentMousePosit AS POINT
      STATIC bMousing AS LONG

      SELECT CASE wMsg

         CASE %WM_LBUTTONDOWN
            ptLastMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptLastMousePosit.y = HI(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            bMousing = %TRUE

         CASE %WM_LBUTTONUP
            bMousing = %FALSE

         CASE %WM_MOUSEMOVE
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            IF bMousing THEN
               m_fSpinX = m_fSpinX - (ptCurrentMousePosit.x - ptLastMousePosit.x)
               m_fSpinY = m_fSpinY - (ptCurrentMousePosit.y - ptLastMousePosit.y)
            END IF
            ptLastMousePosit.x = ptCurrentMousePosit.x
            ptLastMousePosit.y = ptCurrentMousePosit.y

      END SELECT

   END METHOD
   ' ====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   SELECT CASE wMsg

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene
         EXIT FUNCTION

      CASE %WM_CHAR, %WM_KEYDOWN, %WM_KEYUP
         pDX9.ProcessKeys hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_LBUTTONDOWN, %WM_LBUTTONUP, %WM_MOUSEMOVE
         pDX9.ProcessMouse hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to use materials with lighting to produce different surface effects.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_Material.bas
' Contents: DX9 example
' Description: Demonstrates how to use materials with lighting to produce different surface effects.
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from dx9_material.cpp by Kevin Harris, 02/01/05, available at
' http://www.codesampler.com/dx9src/dx9src_6.htm#dx9_material
' Control Keys: Left Mouse Button - Spin the view
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Material"

%FVF_Flags = %D3DFVF_XYZ OR %D3DFVF_NORMAL OR %D3DFVF_DIFFUSE

TYPE Vertex
   ' Position of vertex in 3D space
   x       AS SINGLE
   y       AS SINGLE
   z       AS SINGLE
   ' Normal for lighting calculations
   nx      AS SINGLE
   ny      AS SINGLE
   nz      AS SINGLE
   ' Diffuse color of vertex
   diffuse AS DWORD
END TYPE

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS
   INSTANCE m_pTeapotMesh AS ID3DXMesh
   INSTANCE m_pLight0 AS D3DLIGHT9
   INSTANCE m_redClayMtrl AS D3DMATERIAL9
   INSTANCE m_greenPlasticMtrl AS D3DMATERIAL9
   INSTANCE m_silverMetalMtrl AS D3DMATERIAL9
   INSTANCE m_fSpinX AS SINGLE
   INSTANCE m_fSpinY AS SINGLE

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      '// Create the device objects
      ME.CreateDeviceObjects

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture and creates the vertex buffers
   ' =====================================================================================
   METHOD CreateDeviceObjects () AS LONG

      LOCAL hr AS LONG
      LOCAL matProj AS D3DXMATRIX

      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 600.0! / 400.0!, 0.1!, 100.0!)
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

      m_pD3DDevice.SetRenderState(%D3DRS_ZENABLE, %TRUE)
      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %TRUE)
      m_pD3DDevice.SetRenderState(%D3DRS_SPECULARENABLE, %TRUE)

      ' //-------------------------------------------------------------------------
      ' // Setup material - Used to create a reddish clay teapot
      ' //-------------------------------------------------------------------------

      ' // A matte clay look is easy. All we really have to do is set the color to
      ' // look like clay pottery.
      m_redClayMtrl.Diffuse.r = 1.0!
      m_redClayMtrl.Diffuse.g = 0.5!
      m_redClayMtrl.Diffuse.b = 0.2!
      m_redClayMtrl.Diffuse.a = 1.0!

      ' //-------------------------------------------------------------------------
      ' // Setup material - Used to create a green plastic teapot
      ' //-------------------------------------------------------------------------

      ' // Set the material's main color to green.
      m_greenPlasticMtrl.Diffuse.r = 0.0!
      m_greenPlasticMtrl.Diffuse.g = 1.0!
      m_greenPlasticMtrl.Diffuse.b = 0.0!
      m_greenPlasticMtrl.Diffuse.a = 1.0!

      ' // Lets favor the ambient's green over the other colors. Why? I don't know.
      ' // It just looks better to me. Using materials is some what more artistic
      ' // than scientific, so just play around till you get what you want.
      m_greenPlasticMtrl.Ambient.r = 0.5!
      m_greenPlasticMtrl.Ambient.g = 1.0!
      m_greenPlasticMtrl.Ambient.b = 0.5!
      m_greenPlasticMtrl.Ambient.a = 1.0!

      ' // Plastic can be shiny, but we don't want it too shiny are it will look
      ' // more like glass or metal. We'll have the material reflect back more
      ' // green than red and blue so the highlights won't be pure white.
      m_greenPlasticMtrl.Specular.r = 0.5!
      m_greenPlasticMtrl.Specular.g = 1.0!
      m_greenPlasticMtrl.Specular.b = 0.5!
      m_greenPlasticMtrl.Specular.a = 1.0!

      ' // It seems backwards, but increasing the Power value reduces the
      ' // highlight's size
      m_greenPlasticMtrl.Power = 40.0!

      ' //-------------------------------------------------------------------------
      ' // Setup material - Used to create a silver metallic teapot
      ' //-------------------------------------------------------------------------

      ' // Set the material's main color to a silver-like gray color.
      m_silverMetalMtrl.Diffuse.r = 0.5!
      m_silverMetalMtrl.Diffuse.g = 0.5!
      m_silverMetalMtrl.Diffuse.b = 0.5!
      m_silverMetalMtrl.Diffuse.a = 1.0!

      ' // A silver metal would be very shiny, so we'll reflect back all ambient.
      m_silverMetalMtrl.Ambient.r = 1.0!
      m_silverMetalMtrl.Ambient.g = 1.0!
      m_silverMetalMtrl.Ambient.b = 1.0!
      m_silverMetalMtrl.Ambient.a = 1.0!

      ' // We can make it seem extra shiny by having it actually emit some light
      ' // of its own... but not too much are we'll wash the color out.
      m_silverMetalMtrl.Emissive.r = 0.1!
      m_silverMetalMtrl.Emissive.g = 0.1!
      m_silverMetalMtrl.Emissive.b = 0.1!
      m_silverMetalMtrl.Emissive.a = 1.0!

      ' // Polished silver can reflect back pure white highlights, so set the
      ' // specular to pure white.
      m_silverMetalMtrl.Specular.r = 1.0!
      m_silverMetalMtrl.Specular.g = 1.0!
      m_silverMetalMtrl.Specular.b = 1.0!
      m_silverMetalMtrl.Specular.a = 1.0!

      ' // Set the Power value to a small number to make the highlight's size bigger.
      m_silverMetalMtrl.Power = 5.0!

      ' //
      ' // If you're dealing with a model that provides its own per-vertex colors,
      ' // you'll probably need to disable the usage of vertex colors by Direct3D's
      ' // lighting calculations to get the right effect. This can be accomplished
      ' // by setting D3DRS_COLORVERTEX to FALSE like so...
      ' //
      ' // Comment out this line to use the teapot's real color, which is blue.
      ' //

      m_pD3DDevice.SetRenderState(%D3DRS_COLORVERTEX, %FALSE)

      ' // Another way to ignore per-vertex colors is to simply force all lighting
      ' // calculations to use your material settings explicitly like so...

      ' //m_pD3DDevice->SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL );
      ' //m_pD3DDevice->SetRenderState( D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL );
      ' //m_pD3DDevice->SetRenderState( D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL );
      ' //m_pD3DDevice->SetRenderState( D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL );

      ' //
      ' // Setup a simple directional light and some ambient...
      ' //

      m_pLight0.Type = %D3DLIGHT_DIRECTIONAL
      LOCAL v AS D3DXVECTOR3
      v.x = 1.0! : v.y = 0.0! : v.z = 1.0!
      TYPE SET m_pLight0.Direction = v

      m_pLight0.Diffuse.r = 1.0!
      m_pLight0.Diffuse.g = 1.0!
      m_pLight0.Diffuse.b = 1.0!
      m_pLight0.Diffuse.a = 1.0!

      m_pLight0.Specular.r = 1.0!
      m_pLight0.Specular.g = 1.0!
      m_pLight0.Specular.b = 1.0!
      m_pLight0.Specular.a = 1.0!

      m_pD3DDevice.SetLight(0, m_pLight0)
      m_pD3DDevice.LightEnable(0, %TRUE)

      ' // Be careful when setting up ambient lighting. You can very easily wash
      ' // out the material's specular highlights.

      m_pD3DDevice.SetRenderState(%D3DRS_AMBIENT, D3DCOLOR_COLORVALUE(0.2!, 0.2!, 0.2!, 1.0!))

      ' //
      ' // Load up the teapot mesh and then clone it so we can add per-vertex
      ' // colors to it. I'm only doing this so I can demonstrate what happens if
      ' // we fail to ignore vertex colors when using materials. Failure to
      ' // understand this causes many beginners a lot of headaches.
      ' //

      LOCAL pTempTeapotMesh AS ID3DXMesh

      D3DXLoadMeshFromX(".\Resources\teapot.x", %D3DXMESH_SYSTEMMEM, m_pD3DDevice, _
                        BYVAL %NULL, BYVAL %NULL, BYVAL %NULL, BYVAL %NULL, pTempTeapotMesh)

      LOCAL pTempVertexBuffer AS IDirect3DVertexBuffer9

      pTempTeapotMesh.CloneMeshFVF(0, %FVF_Flags, m_pD3DDevice, m_pTeapotMesh)

      IF SUCCEEDED(m_pTeapotMesh.GetVertexBuffer(pTempVertexBuffer)) THEN
         LOCAL nNumVerts AS LONG
         nNumVerts = m_pTeapotMesh.GetNumVertices
         LOCAL pVertices AS Vertex PTR
         pTempVertexBuffer.Lock(0, 0, pVertices, 0)
         ' // Make each vertex blue
         LOCAL i AS LONG
         FOR i = 0 TO nNumVerts - 1
            @pVertices[i].diffuse = D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0)
         NEXT
         pTempVertexBuffer.Unlock
         pTempVertexBuffer = NOTHING
      END IF

      pTempTeapotMesh = NOTHING

      ' // Return success
      METHOD = %S_OK

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene

      LOCAL hr AS LONG

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.0!,0.0!,0.0!,1.0!), 1.0!, 0)

      LOCAL matView AS D3DXMATRIX
      LOCAL matWorld AS D3DXMATRIX
      LOCAL matTrans AS D3DXMATRIX
      LOCAL matRot AS D3DXMATRIX

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      D3DXMatrixTranslation(matTrans, 0.0!, 0.0!, 6.5!)
      matView = matTrans
      m_pD3DDevice.SetTransform(%D3DTS_VIEW, matView)

      ' // We'll reuse this rotation for all three teapots
      D3DXMatrixRotationYawPitchRoll(matRot, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)

      ' // Render the first teapot using a red clay material
      D3DXMatrixTranslation(matTrans, 0.0!, 1.2!, 0.0!)
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      m_pD3DDevice.SetMaterial(m_redClayMtrl)
      m_pTeapotMesh.DrawSubset(0)

      ' // Render the second teapot using a green plastic material
      D3DXMatrixTranslation(matTrans, 1.7!, -0.8!, 0.0!)
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      m_pD3DDevice.SetMaterial(m_greenPlasticMtrl)
      m_pTeapotMesh.DrawSubset(0)

      ' // Render the third teapot using a silver metallic material
      D3DXMatrixTranslation(matTrans, -1.7!, -0.8!, 0.0!)
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      m_pD3DDevice.SetMaterial(m_silverMetalMtrl)
      m_pTeapotMesh.DrawSubset(0)

      ' // Ends the scene
      m_pD3DDevice.EndScene

      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the device objects
            m_pTeapotMesh = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the device objects
            ME.CreateDeviceObjects
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   ' ====================================================================================
   ' Processes keystrokes
   ' ====================================================================================
   METHOD ProcessKeys (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      SELECT CASE wMsg

         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
            END SELECT

      END SELECT

   END METHOD
   ' ====================================================================================

   ' ====================================================================================
   ' Processes mouse
   ' ====================================================================================
   METHOD ProcessMouse (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      STATIC ptLastMousePosit AS POINT
      STATIC ptCurrentMousePosit AS POINT
      STATIC bMousing AS LONG

      SELECT CASE wMsg

         CASE %WM_LBUTTONDOWN
            ptLastMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptLastMousePosit.y = HI(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            bMousing = %TRUE

         CASE %WM_LBUTTONUP
            bMousing = %FALSE

         CASE %WM_MOUSEMOVE
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            IF bMousing THEN
               m_fSpinX = m_fSpinX - (ptCurrentMousePosit.x - ptLastMousePosit.x)
               m_fSpinY = m_fSpinY - (ptCurrentMousePosit.y - ptLastMousePosit.y)
            END IF
            ptLastMousePosit.x = ptCurrentMousePosit.x
            ptLastMousePosit.y = ptCurrentMousePosit.y

      END SELECT

   END METHOD
   ' ====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   SELECT CASE wMsg

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene
         EXIT FUNCTION

      CASE %WM_KEYDOWN
         pDX9.ProcessKeys hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_LBUTTONDOWN, %WM_LBUTTONUP, %WM_MOUSEMOVE
         pDX9.ProcessMouse hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to manually load the vertex buffer of a single ID3DXMesh object with three separate colored quads. We then use an attribute table to ID these three quads so we can render them separately as subsets of  the mesh using DrawSubset.

The example also demonstrates how to use the ID3DXMesh methods GenerateAdjacency and OptimizeInplace to optimize our test mesh.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_MeshAttributes.bas
' Contents: DX9 example
' Description: Demonstrates how to manually load the vertex buffer of a single ID3DXMesh
' object with three separate colored quads. We then use an attribute table to ID these
' three quads so we can render them separately as subsets of the mesh using DrawSubset.
' The sample also demonstrates how to use the ID3DXMesh methods GenerateAdjacency and
' OptimizeInplace to optimize our test mesh.
' http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndrive/html/directx11192002.asp
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from dx9_mesh_attributes.cpp by Kevin Harris, 05/22/05, available at
' http://www.codesampler.com/dx9src/dx9src_11.htm#dx9_mesh_attributes
' Control Keys: Left Mouse Button - Spin the view
'               F1 - Toggle rendering of subset #0 of mesh object
'               F2 - Toggle rendering of subset #1 of mesh object
'               F3 - Toggle rendering of subset #2 of mesh object
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Using Mesh Attributes to Render Subsets"

%FVF_Flags = %D3DFVF_XYZ OR %D3DFVF_DIFFUSE

TYPE Vertex
   x       AS SINGLE
   y       AS SINGLE
   z       AS SINGLE
   dwColor AS DWORD
END TYPE

GLOBAL pDX9 AS IDX9

' ========================================================================================
' Fills a Vertex structure
' ========================================================================================
MACRO FillVertex (v, x_, y_, z_, dwColor_)
   v.x = x_ : v.y = y_ : v.z = z_ : v.dwColor = dwColor_
END MACRO
' ========================================================================================

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS
   INSTANCE m_pMesh AS ID3DXMesh
   INSTANCE m_fSpinX AS SINGLE
   INSTANCE m_fSpinY AS SINGLE
   INSTANCE m_bRenderSubset0 AS LONG
   INSTANCE m_bRenderSubset1 AS LONG
   INSTANCE m_bRenderSubset2 AS LONG
   INSTANCE m_verticesFor3Quads () AS Vertex

   ' ====================================================================================
   ' Initializes values
   ' ====================================================================================
   CLASS METHOD Create

      m_bRenderSubset0 = %TRUE
      m_bRenderSubset1 = %TRUE
      m_bRenderSubset2 = %TRUE

      '// Define three quads and create each one from two separate triangles.
      '// Using two separate triangles will give us redundant or repeated vertices,
      '// which is bad practice, but this will let us test out the OptimizeInplace
      '// method of ID3DXMesh.

      DIM m_verticesFor3Quads(17) AS INSTANCE Vertex

      ' // Bottom-Left,  color = yellow
      FillVertex(m_verticesFor3Quads( 0), -1.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_verticesFor3Quads( 1),  1.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_verticesFor3Quads( 2),  1.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))

      ' // Second triangle of quad #1
      FillVertex(m_verticesFor3Quads( 3), -1.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_verticesFor3Quads( 4),  1.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_verticesFor3Quads( 5), -1.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))

      ' // First triangle of quad #2
      FillVertex(m_verticesFor3Quads( 6),  1.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_verticesFor3Quads( 7),  3.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_verticesFor3Quads( 8),  3.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))

      ' // Second triangle of quad #2
      FillVertex(m_verticesFor3Quads( 9),  1.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_verticesFor3Quads(10),  3.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_verticesFor3Quads(11),  1.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))

      ' // First triangle of quad #3
      FillVertex(m_verticesFor3Quads(12), -3.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_verticesFor3Quads(13), -1.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_verticesFor3Quads(14), -1.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))

      ' // Second triangle of quad #3
      FillVertex(m_verticesFor3Quads(15), -3.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_verticesFor3Quads(16), -1.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_verticesFor3Quads(17), -3.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))

   END METHOD
   ' ====================================================================================

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      '// Create the device objects
      ME.CreateDeviceObjects

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture and creates the vertex buffers
   ' =====================================================================================
   METHOD CreateDeviceObjects () AS LONG

      LOCAL hr AS LONG

      LOCAL matProj AS D3DXMATRIX
      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 600.0! / 400.0!, 0.1!, 100.0!)
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %FALSE)
      m_pD3DDevice.SetRenderState(%D3DRS_CULLMODE, %D3DCULL_NONE)

      ' // Create a mesh container...
      hr = D3DXCreateMeshFVF(6, _   ' // Our 3 quads have a total of 6 faces or triangles (3 quads * 2 triangles each)
                             19, _  ' // which will require 18 vertices to define them.
                             %D3DXMESH_MANAGED, _
                             %FVF_Flags, _   ' // This is how each vertex is laid out.
                             m_pd3dDevice, _
                             m_pMesh)

      ' // Load our vertices...
      LOCAL pVertices AS Vertex PTR
      m_pMesh.LockVertexBuffer(0, pVertices)

      ' // First triangle of quad #1
      @pVertices[0] = m_verticesFor3Quads(0)
      @pVertices[1] = m_verticesFor3Quads(1)
      @pVertices[2] = m_verticesFor3Quads(2)
      ' // Second triangle of quad #1
      @pVertices[3] = m_verticesFor3Quads(3)
      @pVertices[4] = m_verticesFor3Quads(4)
      @pVertices[5] = m_verticesFor3Quads(5)

      ' // First triangle of quad #2
      @pVertices[6] = m_verticesFor3Quads(6)
      @pVertices[7] = m_verticesFor3Quads(7)
      @pVertices[8] = m_verticesFor3Quads(8)
      ' // Second triangle of quad #2
      @pVertices[9]  = m_verticesFor3Quads(9)
      @pVertices[10] = m_verticesFor3Quads(10)
      @pVertices[11] = m_verticesFor3Quads(11)

      ' // First triangle of quad #3
      @pVertices[12] = m_verticesFor3Quads(12)
      @pVertices[13] = m_verticesFor3Quads(13)
      @pVertices[14] = m_verticesFor3Quads(14)
      ' // Second triangle of quad #3
      @pVertices[15] = m_verticesFor3Quads(15)
      @pVertices[16] = m_verticesFor3Quads(16)
      @pVertices[17] = m_verticesFor3Quads(17)

      ' // If you wanted, you could also memcpy the whole thing in like so.
      ' //memcpy( pVertices, m_verticesFor3Quads, sizeof(m_verticesFor3Quads) );
      ' nSize = (UBOUND(m_verticesFor3Quads) - LBOUND(m_verticesFor3Quads) + 1) * SIZEOF(Vertex)
      ' MoveMemory BYVAL pVertices, BYVAL VARPTR(m_verticesFor3Quads(0)), nSize

      m_pMesh.UnlockVertexBuffer

      ' // Define our indices...
      LOCAL pIndices AS WORD PTR
      m_pMesh.LockIndexBuffer(0, pIndices)

      ' // First triangle of quad #1
      @pIndices[0] = 0
      @pIndices[1] = 1
      @pIndices[2] = 2
      ' // Second triangle of quad #1
      @pIndices[3] = 3
      @pIndices[4] = 4
      @pIndices[5] = 5

      ' // First triangle of quad #2
      @pIndices[6] = 6
      @pIndices[7] = 7
      @pIndices[8] = 8
      ' // Second triangle of quad #2
      @pIndices[9]  = 9
      @pIndices[10] = 10
      @pIndices[11] = 11

      ' // First triangle of quad #3
      @pIndices[12] = 12
      @pIndices[13] = 13
      @pIndices[14] = 14
      ' // Second triangle of quad #3
      @pIndices[15] = 15
      @pIndices[16] = 16
      @pIndices[17] = 17

      m_pMesh.UnlockIndexBuffer

      ' //
      ' // Now, if you would like to render each quad separately, you can use an
      ' // attribute buffer to ID them. We'll use ID #0 for the first quad, ID #1
      ' // for second quad, and ID #2 for the third quad. This way, we can use
      ' // DrawSubset to pick which quad we want to render. This is very useful if
      ' // our quads use different textures, or materials which need to be applied
      ' // to each one before rendering. Otherwise, we would not have an
      ' // opportunity to switch textures or materials once the mesh object starts
      ' // rendering them.
      ' //
      ' // NOTE: Keep in mind that defining attributes hinders our ability to
      ' //       optimize the mesh with a call to OptimizeInplace. This is because
      ' //       attributes are meant to isolate one subset of a mesh from another
      ' //       subset for rendering purposes, and vertices can't be shared among
      ' //       subsets. Therefore, even if a mesh can be rearranged into a
      ' //       nice long tri-strip, which can be rendered in one call, it will
      ' //       have to be broken into multiple pieces to support calling
      ' //       DrawSubset with a attribute ID.
      ' //

      LOCAL pAttributes AS DWORD PTR
      m_pMesh.LockAttributeBuffer(0, pAttributes)

      @pAttributes[0] = 0  ' // First face or triangle of quad #1
      @pAttributes[1] = 0  ' // First face or triangle of quad #1

      @pAttributes[2] = 1  ' // First face or triangle of quad #2
      @pAttributes[3] = 1  ' // First face or triangle of quad #2

      @pAttributes[4] = 2  ' // First face or triangle of quad #3
      @pAttributes[5] = 2  ' // First face or triangle of quad #3

      m_pMesh.UnlockAttributeBuffer

      ' //
      ' // The last step for our mesh object is to optimize the mesh. To assist in
      ' // the optimization step, we need to create a special buffer to hold the
      ' // adjacency information concerning each triangle face present in the mesh.
      ' // Since each triangle can have up to 3 neighbors, which are adjacent, we
      ' // need a buffer of size (numFaces * 3).
      ' //

      ' // Create an adjacency buffer
      REDIM rgAdjacencyBuffer ((m_pMesh.GetNumFaces * 3 * 4) - 1) AS DWORD

      ' // Using a vertex positional tolerance of 0.0!, ask the mesh for its
      ' // adjacency information.
      m_pMesh.GenerateAdjacency(0.0!, rgAdjacencyBuffer(0))

      ' // Now, tell the mesh to attempt an optimization based on that
      ' // adjacency information.
      hr = m_pMesh.OptimizeInplace(%D3DXMESHOPT_VERTEXCACHE OR _  ' // Reorders faces to increase the cache hit rate of vertex caches.
                                   %D3DXMESHOPT_IGNOREVERTS, _    ' // Optimize the faces only; do not optimize the vertices.
                                   rgAdjacencyBuffer(0), _
                                   BYVAL %NULL, BYVAL %NULL, BYVAL %NULL)

      ' // Return success
      METHOD = %S_OK

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene

      LOCAL hr AS LONG

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.35!,0.53!,0.7!,1.0!), 1.0!, 0)

      LOCAL matTrans AS D3DXMATRIX
      LOCAL matRot AS D3DXMATRIX
      LOCAL matWorld AS D3DXMATRIX

      D3DXMatrixRotationYawPitchRoll(matRot, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)
      D3DXMatrixTranslation(matTrans, 0.0!, 0.0!, 6.5!)
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      ' // Now, lets render the three quads in our mesh via their attribute IDs.
      IF ISTRUE m_bRenderSubset0 THEN
         m_pMesh.DrawSubset(0)
      END IF
      IF ISTRUE m_bRenderSubset1 THEN
         m_pMesh.DrawSubset(1)
      END IF
      IF ISTRUE m_bRenderSubset2 THEN
         m_pMesh.DrawSubset(2)
      END IF

      ' // Ends the scene
      m_pD3DDevice.EndScene

      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the device objects
            m_pMesh = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the device objects
            ME.CreateDeviceObjects
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   ' ====================================================================================
   ' Processes keystrokes
   ' ====================================================================================
   METHOD ProcessKeys (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      SELECT CASE wMsg

         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE %VK_F1
                  m_bRenderSubset0 = IIF&(m_bRenderSubset0 = 0, -1, 0)
               CASE %VK_F2
                  m_bRenderSubset1 = IIF&(m_bRenderSubset1 = 0, -1, 0)
               CASE %VK_F3
                  m_bRenderSubset2 = IIF&(m_bRenderSubset2 = 0, -1, 0)
            END SELECT

      END SELECT

   END METHOD
   ' ====================================================================================

   ' ====================================================================================
   ' Processes mouse
   ' ====================================================================================
   METHOD ProcessMouse (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      STATIC ptLastMousePosit AS POINT
      STATIC ptCurrentMousePosit AS POINT
      STATIC bMousing AS LONG

      SELECT CASE wMsg

         CASE %WM_LBUTTONDOWN
            ptLastMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptLastMousePosit.y = HI(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            bMousing = %TRUE

         CASE %WM_LBUTTONUP
            bMousing = %FALSE

         CASE %WM_MOUSEMOVE
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            IF bMousing THEN
               m_fSpinX = m_fSpinX - (ptCurrentMousePosit.x - ptLastMousePosit.x)
               m_fSpinY = m_fSpinY - (ptCurrentMousePosit.y - ptLastMousePosit.y)
            END IF
            ptLastMousePosit.x = ptCurrentMousePosit.x
            ptLastMousePosit.y = ptCurrentMousePosit.y

      END SELECT

   END METHOD
   ' ====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   SELECT CASE wMsg

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene
         EXIT FUNCTION

      CASE %WM_KEYDOWN
         pDX9.ProcessKeys hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_LBUTTONDOWN, %WM_LBUTTONUP, %WM_MOUSEMOVE
         pDX9.ProcessMouse hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================


José Roca

 
Demonstrates how to create 3D geometry with Direct3D by loading vertex data into multiple vertex nuffers.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_MultipleVertexBuffers.bas
' Contents: DX9 example
' Description: Demonstrates how to create 3D geometry with Direct3D by loading vertex data
' into multiple Vertex Buffers.
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Adapted from dx9_vertex_data.cpp by Kevin Harris, 02/01/05, available at
' http://www.codesampler.com/dx9src/dx9src_2.htm#dx9_multiple_vertex_buffers
' ########################################################################################

' CSED_PBWIN - Use the PBWIN compiler
#COMPILE EXE
#DIM ALL
%UNICODE = 1

#INCLUDE ONCE "CWindow.inc"
' DirectX End-User Runtimes (June 2010)
' http://www.microsoft.com/download/en/confirmation.aspx?id=8109
$D3DX_DLLNAME = "d3dx9_43.dll"   ' --> change as needed
#INCLUDE ONCE "D3DX9.INC"

$WindowCaption = "Direct3D (DX9) - Multiple Vertex Buffers"

TYPE Vertex
   x  AS SINGLE
   y  AS SINGLE
   z  AS SINGLE
END TYPE

TYPE tagColor
   dwcolor AS DWORD
END TYPE

TYPE TexCoord
   tu AS SINGLE
   tv AS SINGLE
END TYPE

' ========================================================================================
' Fills a Vertex structure
' ========================================================================================
MACRO FillVertex (v, x_, y_, z_)
   v.x = x_ : v.y = y_ : v.z = z_
END MACRO
' ========================================================================================

' ========================================================================================
' Fills a TexCoord structure
' ========================================================================================
MACRO FillTexCoord (t, tu_, tv_)
   t.tu = tu_ : t.tv = tv_
END MACRO
' ========================================================================================

GLOBAL pDX9 AS IDX9

' =======================================================================================
' DX9 class
' =======================================================================================
CLASS CDX9

   INSTANCE m_pD3D AS IDirect3D9
   INSTANCE m_pD3DDevice AS IDirect3DDevice9
   INSTANCE m_d3ddm AS D3DDISPLAYMODE
   INSTANCE m_d3dpp AS D3DPRESENT_PARAMETERS
   INSTANCE m_pVertexBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_pTexture AS IDirect3DTexture9
   INSTANCE m_pVertexDeclaration AS IDirect3DVertexDeclaration9
   INSTANCE m_pColorBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_pTexCoordBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_fSpinX AS SINGLE
   INSTANCE m_fSpinY AS SINGLE
   INSTANCE m_cubeVertices () AS Vertex
   INSTANCE m_cubeColors () AS tagColor
   INSTANCE m_cubeTexCoords() AS TexCoord
   INSTANCE dwDecl() AS D3DVERTEXELEMENT9

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create

      DIM m_cubeVertices(23) AS INSTANCE Vertex

      FillVertex(m_cubeVertices( 0), -1.0!,  1.0!, -1.0!)
      FillVertex(m_cubeVertices( 1),  1.0!,  1.0!, -1.0!)
      FillVertex(m_cubeVertices( 2), -1.0!, -1.0!, -1.0!)
      FillVertex(m_cubeVertices( 3),  1.0!, -1.0!, -1.0!)
      FillVertex(m_cubeVertices( 4), -1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices( 5), -1.0!, -1.0!,  1.0!)
      FillVertex(m_cubeVertices( 6),  1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices( 7),  1.0!, -1.0!,  1.0!)
      FillVertex(m_cubeVertices( 8), -1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices( 9),  1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices(10), -1.0!,  1.0!, -1.0!)
      FillVertex(m_cubeVertices(11),  1.0!,  1.0!, -1.0!)
      FillVertex(m_cubeVertices(12), -1.0!, -1.0!,  1.0!)
      FillVertex(m_cubeVertices(13), -1.0!, -1.0!, -1.0!)
      FillVertex(m_cubeVertices(14),  1.0!, -1.0!,  1.0!)
      FillVertex(m_cubeVertices(15),  1.0!, -1.0!, -1.0!)
      FillVertex(m_cubeVertices(16),  1.0!,  1.0!, -1.0!)
      FillVertex(m_cubeVertices(17),  1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices(18),  1.0!, -1.0!, -1.0!)
      FillVertex(m_cubeVertices(19),  1.0!, -1.0!,  1.0!)
      FillVertex(m_cubeVertices(20), -1.0!,  1.0!, -1.0!)
      FillVertex(m_cubeVertices(21), -1.0!, -1.0!, -1.0!)
      FillVertex(m_cubeVertices(22), -1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices(23), -1.0!, -1.0!,  1.0!)

      DIM m_cubeColors(23) AS INSTANCE tagColor

      m_cubeColors( 0).dwColor = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 )
      m_cubeColors( 1).dwColor = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 )
      m_cubeColors( 2).dwColor = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 )
      m_cubeColors( 3).dwColor = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 )

      m_cubeColors( 4).dwColor = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 )
      m_cubeColors( 5).dwColor = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 )
      m_cubeColors( 6).dwColor = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 )
      m_cubeColors( 7).dwColor = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 )

      m_cubeColors( 8).dwColor = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 )
      m_cubeColors( 9).dwColor = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 )
      m_cubeColors(10).dwColor = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 )
      m_cubeColors(11).dwColor = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 )

      m_cubeColors(12).dwColor = D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 )
      m_cubeColors(13).dwColor = D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 )
      m_cubeColors(14).dwColor = D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 )
      m_cubeColors(15).dwColor = D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 )

      m_cubeColors(16).dwColor = D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 )
      m_cubeColors(17).dwColor = D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 )
      m_cubeColors(18).dwColor = D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 )
      m_cubeColors(19).dwColor = D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 )

      m_cubeColors(20).dwColor = D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 )
      m_cubeColors(21).dwColor = D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 )
      m_cubeColors(22).dwColor = D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 )
      m_cubeColors(23).dwColor = D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 )

      DIM m_cubeTexCoords(23) AS INSTANCE TexCoord

      FillTexCoord(m_cubeTexCoords( 0),  0.0!,  0.0!)
      FillTexCoord(m_cubeTexCoords( 1),  1.0!,  0.0!)
      FillTexCoord(m_cubeTexCoords( 2),  0.0!,  1.0!)
      FillTexCoord(m_cubeTexCoords( 3),  1.0!,  1.0!)

      FillTexCoord(m_cubeTexCoords( 4),  1.0!,  0.0!)
      FillTexCoord(m_cubeTexCoords( 5),  1.0!,  1.0!)
      FillTexCoord(m_cubeTexCoords( 6),  0.0!,  0.0!)
      FillTexCoord(m_cubeTexCoords( 7),  0.0!,  1.0!)

      FillTexCoord(m_cubeTexCoords( 8),  0.0!,  0.0!)
      FillTexCoord(m_cubeTexCoords( 9),  1.0!,  0.0!)
      FillTexCoord(m_cubeTexCoords(10),  0.0!,  1.0!)
      FillTexCoord(m_cubeTexCoords(11),  1.0!,  1.0!)

      FillTexCoord(m_cubeTexCoords(12),  0.0!,  0.0!)
      FillTexCoord(m_cubeTexCoords(13),  1.0!,  0.0!)
      FillTexCoord(m_cubeTexCoords(14),  0.0!,  1.0!)
      FillTexCoord(m_cubeTexCoords(15),  1.0!,  1.0!)

      FillTexCoord(m_cubeTexCoords(16),  0.0!,  0.0!)
      FillTexCoord(m_cubeTexCoords(17),  1.0!,  0.0!)
      FillTexCoord(m_cubeTexCoords(18),  0.0!,  1.0!)
      FillTexCoord(m_cubeTexCoords(19),  1.0!,  1.0!)

      FillTexCoord(m_cubeTexCoords(20),  1.0!,  0.0!)
      FillTexCoord(m_cubeTexCoords(21),  1.0!,  1.0!)
      FillTexCoord(m_cubeTexCoords(22),  0.0!,  0.0!)
      FillTexCoord(m_cubeTexCoords(23),  0.0!,  1.0!)

   END METHOD
   ' ====================================================================================

   ' =====================================================================================
   INTERFACE IDX9 : INHERIT IUnknown
   ' =====================================================================================

   ' =====================================================================================
   ' Initializes DirectX9
   ' =====================================================================================
   METHOD InitD3D (BYVAL hwnd AS DWORD) AS LONG

      LOCAL hr AS LONG

      ' // Creates an IDirect3D9 object and returns an interface to it
      m_pD3D = Direct3DCreate9(%D3D_SDK_VERSION)
      IF ISNOTHING(m_pD3D) THEN EXIT METHOD

      ' // Retrieves the current display mode of the adapter
      hr = m_pD3D.GetAdapterDisplayMode(%D3DADAPTER_DEFAULT, m_d3ddm)
      IF hr <> %D3D_OK THEN EXIT METHOD

      ' // Creates a device to represent the display adapter
      m_d3dpp.Windowed               = %TRUE
      m_d3dpp.SwapEffect             = %D3DSWAPEFFECT_DISCARD
      m_d3dpp.BackBufferFormat       = m_d3ddm.Format
      m_d3dpp.EnableAutoDepthStencil = %TRUE
      m_d3dpp.AutoDepthStencilFormat = %D3DFMT_D16
      m_d3dpp.PresentationInterval   = %D3DPRESENT_INTERVAL_IMMEDIATE

      hr = m_pD3D.CreateDevice (%D3DADAPTER_DEFAULT, %D3DDEVTYPE_HAL, hwnd, _
                                %D3DCREATE_SOFTWARE_VERTEXPROCESSING, m_d3dpp, m_pD3DDevice)
      IF hr <> %D3D_OK THEN EXIT METHOD

      '// Create the device objects
      ME.CreateDeviceObjects

      ' // Return success
      METHOD = %TRUE

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture and creates the vertex buffers
   ' =====================================================================================
   METHOD CreateDeviceObjects () AS LONG

      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %FALSE)
      m_pD3DDevice.SetRenderState(%D3DRS_ZENABLE, %TRUE)

      ' // Loads the texture
      D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\vertex_data.bmp", m_pTexture)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_LINEAR)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_LINEAR)

      ' // Builds a left-handed perspective projection matrix based on a field of view
      LOCAL matProj AS D3DXMATRIX
      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 600.0! / 400.0!, 0.1!, 100.0!)
      ' // Sets a device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

      ' // Create a vertex buffer that contains only the cube's vertex data
      LOCAL nSize AS LONG
      LOCAL pVertices AS Vertex PTR
      nSize = (UBOUND(m_cubeVertices) - LBOUND(m_cubeVertices) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, 0, %D3DPOOL_DEFAULT, m_pVertexBuffer, %NULL)
      m_pVertexBuffer.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_cubeVertices(0)), nSize
      m_pVertexBuffer.Unlock

      ' // Create a vertex buffer that contains only the cube's color data
      LOCAL pColors AS tagColor PTR
      nSize = (UBOUND(m_cubeColors) - LBOUND(m_cubeColors) + 1) * SIZEOF(tagColor)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, 0, %D3DPOOL_DEFAULT, m_pColorBuffer, %NULL)
      m_pColorBuffer.Lock(0, nSize, pColors, 0)
      MoveMemory BYVAL pColors, BYVAL VARPTR(m_cubeColors(0)), nSize
      m_pColorBuffer.Unlock

      ' // Create a vertex buffer that contains only the cube's texture coordinate data
      LOCAL pTexCoords AS TexCoord PTR
      nSize = (UBOUND(m_cubeTexCoords) - LBOUND(m_cubeTexCoords) + 1) * SIZEOF(TexCoord)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, 0, %D3DPOOL_DEFAULT, m_pTexCoordBuffer, %NULL)
      m_pTexCoordBuffer.Lock(0, nSize, pTexCoords, 0)
      MoveMemory BYVAL pTexCoords, BYVAL VARPTR(m_cubeTexCoords(0)), nSize
      m_pTexCoordBuffer.Unlock

   ' // Create a vertex declaration so we can describe to Direct3D how we'll
   ' // be passing our data to it.

      DIM dwDecl(3) AS INSTANCE D3DVERTEXELEMENT9

      dwDecl(0).Stream = 0
      dwDecl(0).Offset = 0
      dwDecl(0).Type = %D3DDECLTYPE_FLOAT3
      dwDecl(0).Method = %D3DDECLMETHOD_DEFAULT
      dwDecl(0).Usage = %D3DDECLUSAGE_POSITION
      dwDecl(0).UsageIndex = 0

      dwDecl(1).Stream = 1
      dwDecl(1).Offset = 0
      dwDecl(1).Type = %D3DDECLTYPE_D3DCOLOR
      dwDecl(1).Method = %D3DDECLMETHOD_DEFAULT
      dwDecl(1).Usage = %D3DDECLUSAGE_COLOR
      dwDecl(1).UsageIndex = 0

      dwDecl(2).Stream = 2
      dwDecl(2).Offset = 0
      dwDecl(2).Type = %D3DDECLTYPE_FLOAT2
      dwDecl(2).Method = %D3DDECLMETHOD_DEFAULT
      dwDecl(2).Usage = %D3DDECLUSAGE_TEXCOORD
      dwDecl(2).UsageIndex = 0

      dwDecl(3).Stream = &HFF
      dwDecl(3).Offset = 0
      dwDecl(3).Type = %D3DDECLTYPE_UNUSED
      dwDecl(3).Method = 0
      dwDecl(3).Usage = 0
      dwDecl(3).UsageIndex = 0

      m_pD3DDevice.CreateVertexDeclaration(dwDecl(0), m_pVertexDeclaration)

      ' // Return success
      METHOD = %S_OK

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Renders the scene
   ' =====================================================================================
   METHOD RenderD3DScene

      LOCAL  hr AS LONG

      ' // Clears the surface
      m_pD3DDevice.Clear(0, BYVAL %NULL, %D3DCLEAR_TARGET OR %D3DCLEAR_ZBUFFER, _
                         D3DCOLOR_COLORVALUE(0.0!,0.0!,0.0!,1.0!), 1.0!, 0)

      LOCAL matWorld AS D3DXMATRIX
      LOCAL matTrans AS D3DXMATRIX
      LOCAL matRot AS D3DXMATRIX

      ' // Builds a matrix using the specified offsets
      D3DXMatrixTranslation(matTrans, 0.0!, 0.0!, 5.0!)
      ' // Builds a matrix with a specified yaw, pitch, and roll
      D3DXMatrixRotationYawPitchRoll(matRot, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)
      ' // Determines the product of the two matrices
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      ' // Sets the device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      m_pD3DDevice.SetTexture(0, m_pTexture)
      m_pD3DDevice.SetVertexDeclaration(m_pVertexDeclaration)

      m_pD3DDevice.SetStreamSource(0, m_pVertexBuffer,   0, SIZEOF(Vertex))
      m_pD3DDevice.SetStreamSource(1, m_pColorBuffer,    0, SIZEOF(tagColor))
      m_pD3DDevice.SetStreamSource(2, m_pTexCoordBuffer, 0, SIZEOF(TexCoord))

      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  0, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  4, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP,  8, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 12, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 16, 2)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 20, 2)

      ' // Ends the scene
      m_pD3DDevice.EndScene
      ' // Presents the contents of the next buffer in the sequence of back buffers owned by the device
      hr = m_pD3DDevice.Present(BYVAL %NULL, BYVAL %NULL, %NULL, BYVAL %NULL)
      IF hr = %D3DERR_DEVICELOST THEN
         ' // The application can determine what to do on encountering a lost device
         ' // by querying the return value of the TestCooperativeLevel method.
         hr = m_pD3DDevice.TestCooperativeLevel
         IF hr = %D3DERR_DEVICENOTRESET THEN
            ' // Invalidate the device objects
            m_pVertexBuffer = NOTHING
            m_pTexture = NOTHING
            m_pColorBuffer = NOTHING
            m_pTexCoordBuffer = NOTHING
            ' // Reset the type, size, and format of the swap chain
            m_pD3DDevice.Reset(m_d3dpp)
            ' // Recreate the device objects
            ME.CreateDeviceObjects
         END IF
      END IF

   END METHOD
   ' =====================================================================================

   ' ====================================================================================
   ' Processes keystrokes
   ' ====================================================================================
   METHOD ProcessKeys (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      SELECT CASE wMsg

         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
            END SELECT

      END SELECT

   END METHOD
   ' ====================================================================================

   ' ====================================================================================
   ' Processes mouse
   ' ====================================================================================
   METHOD ProcessMouse (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)

      STATIC ptLastMousePosit AS POINT
      STATIC ptCurrentMousePosit AS POINT
      STATIC bMousing AS LONG

      SELECT CASE wMsg

         CASE %WM_LBUTTONDOWN
            ptLastMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptLastMousePosit.y = HI(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            bMousing = %TRUE

         CASE %WM_LBUTTONUP
            bMousing = %FALSE

         CASE %WM_MOUSEMOVE
            ptCurrentMousePosit.x = LO(WORD, lParam)
            ptCurrentMousePosit.y = HI(WORD, lParam)
            IF bMousing THEN
               m_fSpinX = m_fSpinX - (ptCurrentMousePosit.x - ptLastMousePosit.x)
               m_fSpinY = m_fSpinY - (ptCurrentMousePosit.y - ptLastMousePosit.y)
            END IF
            ptLastMousePosit.x = ptCurrentMousePosit.x
            ptLastMousePosit.y = ptCurrentMousePosit.y

      END SELECT

   END METHOD
   ' ====================================================================================

   END INTERFACE

END CLASS
' =======================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI Aware
'   SetProcessDPIAware

   ' // Create an instance of the DX9 class
   pDX9 = CLASS "CDX9"
   IF ISNOTHING(pDX9) THEN EXIT FUNCTION

   ' // Create an instance of the CWindow class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD
   hwnd = pWindow.CreateWindow(%NULL, $WindowCaption, 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Change the class style to remove flicker
   pWindow.ClassStyle = %CS_DBLCLKS
   ' // Set the client size
   pWindow.SetClientSize 600, 400
   ' // Center the window
   pWindow.CenterWindow

   ' // Initialize DX9
   IF ISFALSE pDX9.InitD3D(hwnd) THEN EXIT FUNCTION

   ' // Set the timer
   SetTimer(hwnd, 1, 0, %NULL)

   ' // Show the window
   ShowWindow hwnd, nCmdShow
   UpdateWindow hwnd

   ' // Message loop
   LOCAL uMsg AS tagMsg
   WHILE GetMessage(uMsg, %NULL, 0, 0)
      TranslateMessage uMsg
      DispatchMessage uMsg
   WEND

   ' // Kill the timer
   KillTimer(hwnd, 1)

   FUNCTION = uMsg.wParam

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main window procedure callback
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   SELECT CASE wMsg

      CASE %WM_SYSCOMMAND
         ' // Disable the Windows screensaver
         IF (wParam AND &HFFF0) = %SC_SCREENSAVE THEN EXIT FUNCTION
         ' // Close the window
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_TIMER
         ' // Render the scene
         pDX9.RenderD3DScene
         EXIT FUNCTION

      CASE %WM_KEYDOWN
         pDX9.ProcessKeys hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_LBUTTONDOWN, %WM_LBUTTONUP, %WM_MOUSEMOVE
         pDX9.ProcessMouse hwnd, wMsg, wParam, lParam
         EXIT FUNCTION

      CASE %WM_DESTROY
         ' // Destroy the class
         pDX9 = NOTHING
         ' // Close the application by sending a WM_QUIT message
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)

END FUNCTION
' ========================================================================================