Jose's Read Only Forum 2023

IT-Consultant: José Roca (PBWIN 10+/PBCC 6+) (Archive only) => Graphics and Multimedia => DirectX => Topic started by: José Roca on August 28, 2011, 04:32:48 PM

Title: DirectX 9 Examples
Post by: José Roca on August 28, 2011, 04:32:48 PM
 
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.

Title: DX9: Initialization
Post by: José Roca on August 28, 2011, 04:34:09 PM
 
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
' ========================================================================================

Title: DX9: Alpha Blending in the Frame Buffer
Post by: José Roca on August 28, 2011, 04:43:08 PM
 
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
' ========================================================================================

Title: DX9: Alpha Blending with Materials
Post by: José Roca on August 28, 2011, 04:45:45 PM
 
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
' ========================================================================================

Title: DX9: Alpha Texture Blending
Post by: José Roca on August 28, 2011, 04:47:33 PM
 
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
' ========================================================================================

Title: DX9: Creating 2D Sprites with D3DXSprite
Post by: José Roca on August 28, 2011, 04:48:49 PM
 
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
' ========================================================================================

Title: DX9: Depth Bias
Post by: José Roca on August 28, 2011, 04:50:04 PM
 
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
' ========================================================================================

Title: DX9: Dot3 Per-Pixel Bump Mapping
Post by: José Roca on August 28, 2011, 05:17:25 PM
 
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
' ========================================================================================

Title: DX9: Fonts
Post by: José Roca on August 28, 2011, 05:19:11 PM
 
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
' ========================================================================================

Title: DX9: Indexed Geometry
Post by: José Roca on August 28, 2011, 05:20:42 PM
 
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
' ========================================================================================

Title: DX9: Lighting
Post by: José Roca on August 28, 2011, 05:22:03 PM
 
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
' ========================================================================================

Title: DX9: Manually Loading a D3DXMesh Object
Post by: José Roca on August 28, 2011, 05:23:50 PM
 
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
' ========================================================================================

Title: DX9: Materials
Post by: José Roca on August 28, 2011, 05:25:13 PM
 
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
' ========================================================================================

Title: DX9: Using the Attributes Table of D3DXMesh to Render Subsets
Post by: José Roca on August 28, 2011, 05:27:07 PM
 
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
' ========================================================================================

Title: DX9: Multiple Vertex Buffers
Post by: José Roca on August 28, 2011, 05:28:42 PM
 
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
' ========================================================================================

Title: DX9: Multi texturing
Post by: José Roca on August 28, 2011, 05:30:15 PM
 
This sample demonstrates how to perform multi-texturing under Direct3D by either modulating or adding two textures together in one rendering pass.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_MultiTexture.bas
' Contents: DX9 example
' Description: This sample demonstrates how to perfrom multitexturing with 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
' Adapted from dx9_multitexture.cpp by Kevin Harris, 02/01/05, available at
' http://www.codesampler.com/dx9src/dx9src_4.htm#dx9_multitexture
' Control Keys: F1 - Toggle between modulating or adding the two textures.
' ########################################################################################

' 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) - Multitexturing"

%FVF_Flags = %D3DFVF_XYZ OR %D3DFVF_TEX2

TYPE Vertex
   x   AS SINGLE
   y   AS SINGLE
   z   AS SINGLE
   tu1 AS SINGLE
   tv1 AS SINGLE
   tu2 AS SINGLE
   tv2 AS SINGLE
END TYPE

' ========================================================================================
' Fills a Vertex structure
' ========================================================================================
MACRO FillVertex (v, x_, y_, z_, tu1_, tv1_, tu2_, tv2_)
   v.x = x_ : v.y = y_ : v.z = z_
   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_pVertexBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_pTexture_0 AS IDirect3DTexture9
   INSTANCE m_pTexture_1 AS IDirect3DTexture9
   INSTANCE m_bModulate AS LONG
   INSTANCE m_quadVertices () AS Vertex

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      m_bModulate = %TRUE
      DIM m_quadVertices(3) AS INSTANCE Vertex
      FillVertex(m_quadVertices(0), -1.0!,  1.0!,  0.0!,  0.0!,  0.0!,  0.0!,  0.0!)
      FillVertex(m_quadVertices(1),  1.0!,  1.0!,  0.0!,  1.0!,  0.0!,  1.0!,  0.0!)
      FillVertex(m_quadVertices(2), -1.0!, -1.0!,  0.0!,  0.0!,  1.0!,  0.0!,  1.0!)
      FillVertex(m_quadVertices(3),  1.0!, -1.0!,  0.0!,  1.0!,  1.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 textures
      D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\dx9_multitexture.bmp", m_pTexture_0)
      D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\dx9_multitexture_checker.bmp", m_pTexture_1)
      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, %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)

      ' // 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)

      ' // This is how you find out how many texture stages your hardware will support
      LOCAL caps AS D3DCAPS9
      m_pD3DDevice.GetDeviceCaps(caps)
      LOCAL dwMaxTextureBlendStages AS DWORD
      dwMaxTextureBlendStages = caps.MaxTextureBlendStages

      ' // 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
      D3DXMatrixTranslation(matWorld, 0.0!, 0.0!, 4.0!)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      ' // STAGE 0
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_LINEAR)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_LINEAR)

      m_pD3DDevice.SetTextureStageState(0, %D3DTSS_TEXCOORDINDEX, 0)
      m_pD3DDevice.SetTextureStageState(0, %D3DTSS_COLOROP, %D3DTOP_MODULATE)   ' // Modulate...
      m_pD3DDevice.SetTextureStageState(0, %D3DTSS_COLORARG1, %D3DTA_TEXTURE)   ' // the texture for this stage with...
      m_pD3DDevice.SetTextureStageState(0, %D3DTSS_COLORARG2, %D3DTA_DIFFUSE)   ' // the diffuse color of the geometry.

      ' // STAGE 1
      m_pD3DDevice.SetSamplerState(1, %D3DSAMP_MINFILTER, %D3DTEXF_LINEAR)
      m_pD3DDevice.SetSamplerState(1, %D3DSAMP_MAGFILTER, %D3DTEXF_LINEAR)

      m_pD3DDevice.SetTextureStageState(1, %D3DTSS_TEXCOORDINDEX, 1)

      IF ISTRUE m_bModulate THEN
         m_pD3DDevice.SetTextureStageState(1, %D3DTSS_COLOROP, %D3DTOP_MODULATE)   ' // Modulate...
      ELSE
         m_pD3DDevice.SetTextureStageState(1, %D3DTSS_COLOROP, %D3DTOP_ADD)        ' // or Add...
      END IF

      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

      ' // Set the two textures to be used by our stages...
      m_pD3DDevice.SetTexture(0, m_pTexture_0)
      m_pD3DDevice.SetTexture(1, m_pTexture_1)

      ' // Render our quad with two sets of texture coordinates...
      m_pD3DDevice.SetStreamSource(0, m_pVertexBuffer, 0, SIZEOF(Vertex))
      m_pD3DDevice.SetFVF(%FVF_Flags)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 0, 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_pTexture_0 = NOTHING
            m_pTexture_1 = 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_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE %VK_F1
                  IF m_bModulate = 0 THEN m_bModulate = -1 ELSE m_bModulate = 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_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
' ========================================================================================

Title: DX9: Off-screen Rendering
Post by: José Roca on August 28, 2011, 05:31:37 PM
 
Demonstrates how to create dynamic textures through the use of an off-screen rendering surface under Direct3D.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_OffscreenRendering.bas
' Contents: DX9 example
' Description: Demonstrates how to create dynamic textures through off-screen rendering.
' As a demonstration, a spinning textured cube is rendered to an off-screen surface, which
' is in turn, used to create a dynamic texture. The dynamic texture is then used to
' texture a second spinning cube, which will be rendered to the application's window.
' 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_offscreen_rendering.cpp by Kevin Harris, 02/01/05, available at
' http://www.codesampler.com/dx9src/dx9src_6.htm#dx9_lighting
' Control Keys: Left Mouse Button  - Spin the large, black cube.
'               Right Mouse Button - Spin the textured cube being rendered into the p-buffer.
' ########################################################################################

' 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) - Off-Screen Rendering"

%RENDERTOSURFACE_WIDTH = 256
%RENDERTOSURFACE_HEIGHT = 256

%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_pTestTexture AS IDirect3DTexture9
   INSTANCE m_pRenderToSurface AS ID3DXRenderToSurface
   INSTANCE m_pDynamicTexture AS IDirect3DTexture9
   INSTANCE m_pTextureSurface AS IDirect3DSurface9
   INSTANCE m_matProjection_window AS D3DXMATRIX
   INSTANCE m_matProjection_offscreenSurface AS D3DXMATRIX
   INSTANCE m_cubeVertices () AS Vertex
   INSTANCE m_fSpinX_L AS SINGLE
   INSTANCE m_fSpinY_L AS SINGLE
   INSTANCE m_fSpinX_R AS SINGLE
   INSTANCE m_fSpinY_R AS SINGLE

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

      LOCAL hr AS LONG

      ' // Loads the texture
      D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\test.bmp", m_pTestTexture)
      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_cubeVertices) - LBOUND(m_cubeVertices) + 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_cubeVertices(0)), nSize
      m_pVertexBuffer.Unlock

      ' // 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(m_matProjection_window, D3DXToRadian(45.0!), 600.0! / 400.0!, 0.1!, 100.0!)
      ' // Sets a device transformation-related state
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, m_matProjection_window)

      ' // Create our dynamic texture for use by the "render to" surface...
      hr = D3DXCreateTexture(m_pD3DDevice, _
                             %RENDERTOSURFACE_WIDTH, _
                             %RENDERTOSURFACE_HEIGHT, _
                             1, _
                             %D3DUSAGE_RENDERTARGET, _
                             %D3DFMT_A8R8G8B8, _
                             %D3DPOOL_DEFAULT, _
                             m_pDynamicTexture)
      IF FAILED(hr) THEN
         MessageBox(%NULL,"Failed to create a texture with the D3DUSAGE_RENDERTARGET usage flag set!", _
               "ERROR", %MB_OK OR %MB_ICONEXCLAMATION)
         METHOD = hr
         EXIT METHOD
      END IF

      ' // Create an off-screen "render to" surface...
      LOCAL desc AS D3DSURFACE_DESC
      m_pDynamicTexture.GetSurfaceLevel(0, m_pTextureSurface)
      m_pTextureSurface.GetDesc(desc)
      hr = D3DXCreateRenderToSurface(m_pD3DDevice, _
                                     desc.Width, _
                                     desc.Height, _
                                     desc.Format, _
                                     %TRUE, _
                                     %D3DFMT_D16, _
                                     m_pRenderToSurface)

      IF FAILED(hr) THEN
         MessageBox(%NULL,"Failed to create the off-screen render surface!", _
               "ERROR", %MB_OK OR %MB_ICONEXCLAMATION)
         METHOD = hr
         EXIT METHOD
      END IF

      ' // We'll need to create a second projection matrix, which take in account
      ' // the off-screen surface's dimensions.
      D3DXMatrixPerspectiveFovLH(m_matProjection_offscreenSurface, _
                                 D3DXToRadian(45.0!), _
                                 %RENDERTOSURFACE_WIDTH / %RENDERTOSURFACE_HEIGHT, _
                                 0.1!, 100.0!)

      ' // Return success
      METHOD = %S_OK

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

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

      LOCAL  hr AS LONG
      LOCAL matWorld AS D3DXMATRIX
      LOCAL matTranslation AS D3DXMATRIX
      LOCAL matRotation AS D3DXMATRIX

      ' //-------------------------------------------------------------------------
      ' // Use the "render to" surface for off-screen rendering
      ' //-------------------------------------------------------------------------

      m_pRenderToSurface.BeginScene(m_pTextureSurface, BYVAL %NULL)

      ' // 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)

      ' // We'll need to change the projection matrix on the device, to match the
      ' // off-screen surface's dimensions, or the cube will look wrong.
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, m_matProjection_offscreenSurface)

      ' // Let the user spin the cube about with the right mouse button, so our
      ' // dynamic texture will show motion.
      D3DXMatrixTranslation(matTranslation, 0.0!, 0.0!, 5.0!)
      D3DXMatrixRotationYawPitchRoll(matRotation, D3DXToRadian(m_fSpinX_R), D3DXToRadian(m_fSpinY_R), 0.0!)
      D3DXMatrixMultiply(matWorld, matRotation, matTranslation)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Now the render the cube to the off-screen surface
      m_pD3DDevice.SetTexture(0, m_pTestTexture)
      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)

      m_pRenderToSurface.EndScene(0)

      ' //-------------------------------------------------------------------------
      ' // Use the Direct3D device for regular rendering...
      ' //-------------------------------------------------------------------------

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

      ' // Change the projection matrix back, so it matches the window's size.
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, m_matProjection_window)

      ' // Let the user spin the cube about with the left mouse button.
      D3DXMatrixTranslation(matTranslation, 0.0!, 0.0!, 5.0!)
      D3DXMatrixRotationYawPitchRoll(matRotation, D3DXToRadian(m_fSpinX_L), D3DXToRadian(m_fSpinY_L), 0.0!)
      D3DXMatrixMultiply(matWorld, matRotation, matTranslation)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      ' // Finally, we'll use the dynamic texture like a regular static texture.
      m_pD3DDevice.SetTexture(0, m_pDynamicTexture)
      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_pRenderToSurface = NOTHING
            m_pDynamicTexture = NOTHING
            m_pTextureSurface = NOTHING
            m_pTestTexture = 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_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_L AS POINT
      STATIC ptCurrentMousePosit_L AS POINT
      STATIC bMousinm_L AS LONG

      STATIC ptLastMousePosit_R AS POINT
      STATIC ptCurrentMousePosit_R AS POINT
      STATIC bMousinm_R AS LONG

      SELECT CASE wMsg

         CASE %WM_LBUTTONDOWN
            ptLastMousePosit_L.x = LO(WORD, lParam)
            ptCurrentMousePosit_L.x = LO(WORD, lParam)
            ptLastMousePosit_L.y = HI(WORD, lParam)
            ptCurrentMousePosit_L.y = HI(WORD, lParam)
            bMousinm_L = %TRUE

         CASE %WM_LBUTTONUP
            bMousinm_L = %FALSE

         CASE %WM_RBUTTONDOWN
            ptLastMousePosit_R.x = LO(WORD, lParam)
            ptCurrentMousePosit_R.x = LO(WORD, lParam)
            ptLastMousePosit_R.y = HI(WORD, lParam)
            ptCurrentMousePosit_R.y = HI(WORD, lParam)
            bMousinm_R = %TRUE

         CASE %WM_RBUTTONUP
            bMousinm_R = %FALSE

         CASE %WM_MOUSEMOVE
            ptCurrentMousePosit_L.x = LO(WORD, lParam)
            ptCurrentMousePosit_L.y = HI(WORD, lParam)
            ptCurrentMousePosit_R.x = LO(WORD, lParam)
            ptCurrentMousePosit_R.y = HI(WORD, lParam)

            IF bMousinm_L THEN
               m_fSpinX_L = m_fSpinX_L - (ptCurrentMousePosit_L.x - ptLastMousePosit_L.x)
               m_fSpinY_L = m_fSpinY_L - (ptCurrentMousePosit_L.y - ptLastMousePosit_L.y)
            END IF

            IF bMousinm_R THEN
               m_fSpinX_R = m_fSpinX_R - (ptCurrentMousePosit_R.x - ptLastMousePosit_R.x)
               m_fSpinY_R = m_fSpinY_R - (ptCurrentMousePosit_R.y - ptLastMousePosit_R.y)
            END IF

            ptLastMousePosit_L.x = ptCurrentMousePosit_L.x
            ptLastMousePosit_L.y = ptCurrentMousePosit_L.y
            ptLastMousePosit_R.x = ptCurrentMousePosit_R.x
            ptLastMousePosit_R.y = ptCurrentMousePosit_R.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_RBUTTONDOWN, %WM_RBUTTONUP, %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
' ========================================================================================

Title: DX9: Point Lighting
Post by: José Roca on August 28, 2011, 05:33:00 PM
 
Demonstrates how to setup point lighting with Direct3D. The sample also demonstrates how the tessellation or triangle count of a mesh effects lighting.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_PointLight.bas
' Contents: DX9 example
' Description: Demonstrates how to setup point lighting with Direct3D. The sample also
' demonstrates how the tessellation or triangle count of a mesh effects lighting.
' 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_point_light.cpp by Kevin Harris, 02/17/05, available at
' http://www.codesampler.com/dx9src/dx9src_5.htm#dx9_point_light
' Control Keys: v - Decrease the mesh's tessellation or vertex count
'               V - Increase the mesh's tessellation or vertex count
'               w - Toggle wire-frame mode
'
'               r  - Decrease Range
'               R  - Increase Range
'               F1 - Decrease Attenuation0
'               F2 - Increase Attenuation0
'               F3 - Decrease Attenuation1
'               F4 - Increase Attenuation1
'               F5 - Decrease Attenuation2
'               F6 - Increase Attenuation2
'
'               Up   - Move the point light up
'               Down - Move the point light down
'
' NOTE: Please refer to the DirectX 9.0c Documentation for the more
'       information concerning the Attenuation, and Range controls.
' ########################################################################################

' 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) - Point 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
   INSTANCE m_pSphereMesh AS ID3DXMesh                   ' // A mesh to represent a point light
   INSTANCE m_light0 AS D3DLIGHT9
   INSTANCE m_meshMaterial AS D3DMATERIAL9
   INSTANCE m_sphereMaterial AS D3DMATERIAL9

   INSTANCE m_bRenderInWireFrame AS LONG
   INSTANCE m_fLightPositionY AS SINGLE
   INSTANCE m_fAttenuation0 AS SINGLE
   INSTANCE m_fAttenuation1 AS SINGLE
   INSTANCE m_fAttenuation2 AS SINGLE
   INSTANCE m_fRange AS SINGLE
   INSTANCE m_nMeshVertCount AS LONG
   INSTANCE m_nNumVerts AS LONG

   ' ====================================================================================
   ' Initializes values
   ' ====================================================================================
   CLASS METHOD Create
      m_bRenderInWireFrame = %FALSE
      m_fLightPositionY    = 2.0!
      m_fAttenuation0      = 0.0!
      m_fAttenuation1      = 0.5!
      m_fAttenuation2      = 0.0!
      m_fRange             = 10.0!
      m_nMeshVertCount     = 0
      m_nNumVerts          = 64
   END METHOD
   ' ====================================================================================

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

   ' =====================================================================================
   ' Init lighting
   ' =====================================================================================
   METHOD initLighting

      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %TRUE)
      m_pD3DDevice.LightEnable(0, %TRUE)

      ' // Set up our material...
      m_meshMaterial.Diffuse.r = 1.0!
      m_meshMaterial.Diffuse.g = 1.0!
      m_meshMaterial.Diffuse.b = 1.0!
      m_meshMaterial.Diffuse.a = 1.0!
      m_meshMaterial.Ambient.r = 1.0!
      m_meshMaterial.Ambient.g = 1.0!
      m_meshMaterial.Ambient.b = 1.0!
      m_meshMaterial.Ambient.a = 1.0!
      m_pD3DDevice.SetMaterial(m_meshMaterial)

      ' // Set up our point light...
      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_light0.Type         = %D3DLIGHT_POINT
      LOCAL v AS D3DXVECTOR3
      v.x = 0.0! : v.y = m_fLightPositionY : v.z = 0.0!
      TYPE SET m_light0.Position     = v
      m_light0.Attenuation0 = m_fAttenuation0
      m_light0.Attenuation1 = m_fAttenuation1
      m_light0.Attenuation2 = m_fAttenuation2
      m_light0.Range        = m_fRange
      m_pD3DDevice.SetLight(0, m_light0)

      ' // Enable some dim, grey ambient lighting...
      ' //m_pD3DDevice.SetRenderState(%D3DRS_AMBIENT,
      ' //                            %D3DCOLOR_COLORVALUE(0.25!, 0.25!, 0.25!, 1.0!))

      ' // Set up a yellow emissive material so our little sphere, which
      ' // represents our light, will appear to glow yellow.
      m_sphereMaterial.Emissive.r = 1.0!
      m_sphereMaterial.Emissive.g = 1.0!
      m_sphereMaterial.Emissive.b = 0.0!
      m_sphereMaterial.Emissive.a = 1.0!

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

   ' =====================================================================================
   ' Create simple mesh
   ' =====================================================================================
   METHOD createSimpleMesh (BYVAL nNumVertsAlongX AS LONG, BYVAL nNumVertsAlongZ AS LONG, _
                              BYVAL fMeshLengthAlongX AS SINGLE, BYVAL fMeshLengthAlongZ AS SINGLE) AS LONG

      LOCAL nMeshVertCount AS LONG
      nMeshVertCount = (nNumVertsAlongX-1) * (nNumVertsAlongZ-1) * 6

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

      m_pD3DDevice.CreateVertexBuffer(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 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 nNumVertsAlongZ - 2
         ' // Fill the row with quads which are composed of two triangles each...
         FOR x = 0 TO nNumVertsAlongX - 2
            ' // First triangle of the current quad
            ' // 1 ___ 2
            ' //  |  /|
            ' //  |/__|
            ' // 0

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

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

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

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

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

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

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

      m_pMeshVertices.Unlock

      METHOD = nMeshVertCount

   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

      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)

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

      ME.initLighting

      ' // Create a custom mesh to test lighting on.
      m_nMeshVertCount = ME.createSimpleMesh(m_nNumVerts, m_nNumVerts, 10.0!, 10.0!)

      ' // Create a sphere mesh to represent our light's position.
      D3DXCreateSphere(m_pD3DDevice, 0.1!, 20, 20, m_pSphereMesh, 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.0!,0.0!,0.0!,1.0!), 1.0!, 0)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

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

      ' // Set up our light and apply a material...

      m_light0.Position.y   = m_fLightPositionY
      m_light0.Attenuation0 = m_fAttenuation0
      m_light0.Attenuation1 = m_fAttenuation1
      m_light0.Attenuation2 = m_fAttenuation2
      m_light0.Range        = m_fRange

      m_pD3DDevice.SetLight(0, m_light0)
      m_pD3DDevice.LightEnable(0, %TRUE)
      m_pD3DDevice.SetMaterial(m_meshMaterial)

      ' // Render a tesselated mesh of variable resolution so we can see how its
      ' // tessleation alters our attempt to light it.

      D3DXMatrixTranslation(matTrans, -5.0!, 0.0!, -5.0!)
      D3DXMatrixRotationZ(matRotate, D3DXToRadian(0.0!))
      D3DXMatrixMultiply(matWorld, matRotate, matTrans)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      m_pD3DDevice.SetStreamSource(0, m_pMeshVertices, 0, SIZEOF(Vertex))
      m_pD3DDevice.SetFVF(%FVF_Flags)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLELIST, 0, m_nMeshVertCount / 3)

      ' // Render a little yellow sphere to represent out light's current position
      ' // in 3D space.

      m_pD3DDevice.LightEnable(0, %FALSE)
      m_pD3DDevice.SetMaterial(m_sphereMaterial)

      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_pMeshVertices = NOTHING
            m_pSphereMesh = 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 ASC("v")
                  m_nNumVerts = m_nNumVerts - 1
                  ' // Don't let the mesh's resolution get too low!
                  IF m_nNumVerts <= 1 THEN m_nNumVerts = 2
                  ' // Release the old mesh so we can create a new one.
                  m_pMeshVertices = NOTHING
                  m_nMeshVertCount = ME.createSimpleMesh(m_nNumVerts, m_nNumVerts, 10.0!, 10.0!)
               CASE ASC("V")
                  m_nNumVerts = m_nNumVerts + 1
                  ' // Release the old mesh so we can create a new one.
                  m_pMeshVertices = NOTHING
                  m_nMeshVertCount = ME.createSimpleMesh(m_nNumVerts, m_nNumVerts, 10.0!, 10.0!)
               CASE ASC("r")
                  m_fRange = m_fRange - 1.0!
               CASE ASC("R")
                  m_fRange = m_fRange + 1.0!
               CASE ASC("w"), ASC("W")
                  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

         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE %VK_F1
                  m_fAttenuation0 = m_fAttenuation0 - 0.01!
                  IF m_fAttenuation0 < 0.0! THEN m_fAttenuation0 = 0.0!
               CASE %VK_F2
                  m_fAttenuation0 = m_fAttenuation0 + 0.01!
               CASE %VK_F3
                  m_fAttenuation1 = m_fAttenuation1 - 0.01!
                  IF m_fAttenuation1 < 0.0! THEN m_fAttenuation1 = 0.0!
               CASE %VK_F3
                  m_fAttenuation1 = m_fAttenuation1+ 0.01!
               CASE %VK_F5
                  m_fAttenuation2 = m_fAttenuation2 - 0.01!
                  IF m_fAttenuation2 < 0.0! THEN m_fAttenuation2 = 0.0!
               CASE %VK_F6
                  m_fAttenuation2 = m_fAttenuation2 + 0.01!
               CASE %VK_UP
                  m_fLightPositionY = m_fLightPositionY + 0.1!
               CASE %VK_DOWN
                  m_fLightPositionY = m_fLightPositionY - 0.1!
            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, %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
' ========================================================================================

Title: DX9: Primitive Types
Post by: José Roca on August 28, 2011, 05:40:08 PM
 
This sample demonstrates how to use the 6 primitive types available under Direct3D: point list, line list, line strip, triangle list, triangle strip, and triangle fan.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_PrimitiveTypes.bas
' Contents: DX9 example
' Description: Demonstrates how to use the 6 primitive types available under Direct3D:
' point list, line list, line strip, triangle list, triangle strip, and triangle fan.
' 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_primitive_types.cpp by Kevin Harris, 06/06/05, available at
' http://www.codesampler.com/dx9src/dx9src_2.htm#dx9_primitive_types
' Control Keys: F1 - Switch the primitive type to be rendered.
'               F2 - Toggle 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) - Primitive Types"

%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_pPointList AS IDirect3DVertexBuffer9
   INSTANCE m_pLineStrip AS IDirect3DVertexBuffer9
   INSTANCE m_pLineList AS IDirect3DVertexBuffer9
   INSTANCE m_pTriangleList AS IDirect3DVertexBuffer9
   INSTANCE m_pTriangleStrip AS IDirect3DVertexBuffer9
   INSTANCE m_pTriangleFan AS IDirect3DVertexBuffer9
   INSTANCE m_bRenderInWireFrame AS LONG
   INSTANCE m_currentPrimitive AS LONG
   INSTANCE m_pointList () AS Vertex
   INSTANCE m_lineList () AS Vertex
   INSTANCE m_lineStrip () AS Vertex
   INSTANCE m_triangleList () AS Vertex
   INSTANCE m_triangleStrip () AS Vertex
   INSTANCE m_triangleFan () AS Vertex

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create

      m_currentPrimitive = %D3DPT_TRIANGLEFAN

      '// We'll store the vertex data in simple arrays until we're ready to load
      '// them into actual Direct3D Vertex Buffers. Seeing the vertices laid out
      '// like this should make it easier to understand how vertices need to be
      '// passed to be considered valid for each primitive type.

      DIM m_pointList(4) AS INSTANCE Vertex

      FillVertex(m_pointList(0),  0.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_pointList(1),  0.5!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_pointList(2), -0.5!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_pointList(3),  0.0!, -0.5!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 0.0, 1.0))
      FillVertex(m_pointList(4),  0.0!,  0.5!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 1.0, 1.0))

      DIM m_lineList(5) AS INSTANCE Vertex

      FillVertex(m_lineList(0), -1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_lineList(1),  0.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_lineList(2),  0.5!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_lineList(3),  0.5!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_lineList(4),  1.0!, -0.5!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_lineList(5), -1.0!, -0.5!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))

      DIM m_lineStrip(5) AS INSTANCE Vertex

      FillVertex(m_lineStrip(0),  0.5!,  0.5!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_lineStrip(1),  1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_lineStrip(2),  0.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_lineStrip(3), -1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 0.0, 1.0))
      FillVertex(m_lineStrip(4),  0.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 1.0, 1.0))
      FillVertex(m_lineStrip(5),  0.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))

      DIM m_triangleList(5) AS INSTANCE Vertex

      FillVertex(m_triangleList(0), -1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_triangleList(1),  0.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_triangleList(2),  1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_triangleList(3), -0.5!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 0.0, 1.0))
      FillVertex(m_triangleList(4),  0.0!, -0.5!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 1.0, 1.0))
      FillVertex(m_triangleList(5),  0.5!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))

      DIM m_triangleStrip(7) AS INSTANCE Vertex

      FillVertex(m_triangleStrip(0), -2.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_triangleStrip(1), -1.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_triangleStrip(2), -1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_triangleStrip(3),  0.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 0.0, 1.0))
      FillVertex(m_triangleStrip(4),  0.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 1.0, 1.0))
      FillVertex(m_triangleStrip(5),  1.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 1.0, 1.0))
      FillVertex(m_triangleStrip(6),  1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_triangleStrip(7),  2.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))

      DIM m_triangleFan(5) AS INSTANCE Vertex

      FillVertex(m_triangleFan(0),  0.0!, -1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 0.0, 0.0, 1.0))
      FillVertex(m_triangleFan(1), -1.0!, -0.0!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 0.0, 1.0))
      FillVertex(m_triangleFan(2), -0.5!,  0.5!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 0.0, 1.0, 1.0))
      FillVertex(m_triangleFan(3),  0.0!,  1.0!,  0.0!, D3DCOLOR_COLORVALUE(1.0, 1.0, 0.0, 1.0))
      FillVertex(m_triangleFan(4),  0.5!,  0.5!,  0.0!, D3DCOLOR_COLORVALUE(0.0, 1.0, 1.0, 1.0))
      FillVertex(m_triangleFan(5),  1.0!,  0.0!,  0.0!, D3DCOLOR_COLORVALUE(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

      LOCAL hr AS LONG
      LOCAL matProj AS D3DXMATRIX

      D3DXMatrixPerspectiveFovLH(matProj, D3DXToRadian(45.0!), 1.0!, 1.0!, 100.0!)
      m_pD3DDevice.SetTransform(%D3DTS_PROJECTION, matProj)

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

      ' // Point List
      LOCAL nSize AS LONG
      LOCAL pVertices AS Vertex PTR
      pVertices = 0
      nSize = (UBOUND(m_pointList) - LBOUND(m_pointList) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, %FVF_Flags, %D3DPOOL_DEFAULT, m_pPointList, %NULL)
      m_pPointList.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_pointList(0)), nSize
      m_pPointList.Unlock

      ' // Line List
      pVertices = 0
      nSize = (UBOUND(m_lineList) - LBOUND(m_lineList) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, %FVF_Flags, %D3DPOOL_DEFAULT, m_pLineList, %NULL)
      m_pLineList.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_lineList(0)), nSize
      m_pLineList.Unlock

      ' // Line Strip
      pVertices = 0
      nSize = (UBOUND(m_lineStrip) - LBOUND(m_lineStrip) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, %FVF_Flags, %D3DPOOL_DEFAULT, m_pLineStrip, %NULL)
      m_pLineStrip.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_lineStrip(0)), nSize
      m_pLineStrip.Unlock

      ' // Triangle List
      pVertices = 0
      nSize = (UBOUND(m_triangleList) - LBOUND(m_triangleList) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, %FVF_Flags, %D3DPOOL_DEFAULT, m_pTriangleList, %NULL)
      m_pTriangleList.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_triangleList(0)), nSize
      m_pTriangleList.Unlock

      ' // Triangle Strip
      pVertices = 0
      nSize = (UBOUND(m_triangleStrip) - LBOUND(m_triangleStrip) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, %FVF_Flags, %D3DPOOL_DEFAULT, m_pTriangleStrip, %NULL)
      m_pTriangleStrip.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_triangleStrip(0)), nSize
      m_pTriangleStrip.Unlock

      ' // Triangle Fan
      pVertices = 0
      nSize = (UBOUND(m_triangleFan) - LBOUND(m_triangleFan) + 1) * SIZEOF(Vertex)
      m_pD3DDevice.CreateVertexBuffer(nSize, 0, %FVF_Flags, %D3DPOOL_DEFAULT, m_pTriangleFan, %NULL)
      m_pTriangleFan.Lock(0, nSize, pVertices, 0)
      MoveMemory BYVAL pVertices, BYVAL VARPTR(m_triangleFan(0)), nSize
      m_pTriangleFan.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.0!,0.0!,0.0!,1.0!), 1.0!, 0)

      LOCAL mWorld AS D3DXMATRIX
      D3DXMatrixTranslation(mWorld, 0.0!, 0.0!, 5.0!)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, mWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      SELECT CASE AS LONG m_currentPrimitive

         CASE %D3DPT_POINTLIST
            m_pD3DDevice.SetStreamSource(0, m_pPointList, 0, SIZEOF(Vertex))
            m_pD3DDevice.SetFVF(%FVF_Flags)
            m_pD3DDevice.DrawPrimitive(%D3DPT_POINTLIST, 0, 5)

         CASE %D3DPT_LINELIST
            m_pD3DDevice.SetStreamSource(0, m_pLineList, 0, SIZEOF(Vertex))
            m_pD3DDevice.SetFVF(%FVF_Flags)
            m_pD3DDevice.DrawPrimitive(%D3DPT_LINELIST, 0, 3)

         CASE %D3DPT_LINESTRIP
            m_pD3DDevice.SetStreamSource(0, m_pLineStrip, 0, SIZEOF(Vertex))
            m_pD3DDevice.SetFVF(%FVF_Flags)
            m_pD3DDevice.DrawPrimitive(%D3DPT_LINESTRIP, 0, 5)

         CASE %D3DPT_TRIANGLELIST
            m_pD3DDevice.SetStreamSource(0, m_pTriangleList, 0, SIZEOF(Vertex))
            m_pD3DDevice.SetFVF(%FVF_Flags)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLELIST, 0, 2)

         CASE %D3DPT_TRIANGLESTRIP
            m_pD3DDevice.SetStreamSource(0, m_pTriangleStrip, 0, SIZEOF(Vertex))
            m_pD3DDevice.SetFVF(%FVF_Flags)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLESTRIP, 0, 6)

         CASE %D3DPT_TRIANGLEFAN
            m_pD3DDevice.SetStreamSource(0, m_pTriangleFan, 0, SIZEOF(Vertex))
            m_pD3DDevice.SetFVF(%FVF_Flags)
            m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLEFAN, 0, 4)

      END SELECT

      ' // 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_pPointList = NOTHING
            m_pLineList = NOTHING
            m_pLineStrip = NOTHING
            m_pTriangleList = NOTHING
            m_pTriangleStrip = NOTHING
            m_pTriangleFan = 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
                  IF m_currentPrimitive = %D3DPT_POINTLIST THEN
                     m_currentPrimitive = %D3DPT_LINELIST
                  ELSEIF m_currentPrimitive = %D3DPT_LINELIST THEN
                     m_currentPrimitive = %D3DPT_LINESTRIP
                  ELSEIF m_currentPrimitive = %D3DPT_LINESTRIP THEN
                     m_currentPrimitive = %D3DPT_TRIANGLELIST
                  ELSEIF m_currentPrimitive = %D3DPT_TRIANGLELIST THEN
                     m_currentPrimitive = %D3DPT_TRIANGLESTRIP
                  ELSEIF m_currentPrimitive = %D3DPT_TRIANGLESTRIP THEN
                     m_currentPrimitive = %D3DPT_TRIANGLEFAN
                  ELSEIF m_currentPrimitive = %D3DPT_TRIANGLEFAN THEN
                     m_currentPrimitive = %D3DPT_POINTLIST
                  END IF
               CASE %VK_F2
                  m_bRenderInWireFrame = NOT m_bRenderInWireFrame
                  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
' ========================================================================================

Title: DX9: Resizing a DirectX 9 Window
Post by: José Roca on August 28, 2011, 05:41:24 PM
 
This sample demonstrates how to respond to the app's window getting resized by resizing the front and back buffers of the Direct3D device to match it. If you don't do this, Direct3D will be forced to perform a stretch blit when the window is enlarged and everything rendered will appear course and blocky. For example, if the initial window size and Direct3D device are set to 640x480 and you enlarge the window to be 1024x768, the Direct3D device will continue to render at 640x480 unless its front back buffers are resized accordingly.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_ResizeWindow.bas
' Contents: DX9 example
' Compilers: PBWIN 10.02+, PBCC 6.02+
' Headers: Windows API headers 2.04+
' Copyright (c) 2011 José Roca. Freeware. Use at your own risk
' Description: how to respond to the app's window getting resized by resizing the front
' and back buffers of the Direct3D device to match it. If you don't do this, Direct3D will
' be forced to perform a stretch blit when the window is enlarged and everything rendered
' will appear course and blocky. For example, if the initial window size and Direct3D
' device are set to 640x480 and you enlarge the window to be 1024x768, the Direct3D device
' will continue to render at 640x480 unless its front and back buffers are resized accordingly.
' To see what happens when you don't handle resizing properly, run the sample and maximize
' the window. Once maximized, note how smooth the teapot is and how clean the texturing on
' the quad is. Next, grab the window's corner and considerably reduce the window's size
' and hit F1 to toggle off the handling code and maximize it again. When the window is
' maximized the teapot and textured quad should appear highly pixilated.
' Adapted from dx9_resize_window.cpp by Kevin Harris, 06/16/05,
' available at http://www.codesampler.com/dx9src/dx9src_6.htm#dx9_resize_window
' Control Keys: F1 - Toggle handling of WM_SIZE window message
'               Left Mouse Button - Spin the teapot and textured quad
' ########################################################################################

' 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) - Resize Window"

%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_pTeapotMesh AS ID3DXMesh
   INSTANCE m_teapotMtrl AS D3DMATERIAL9
   INSTANCE m_pVertexBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_pTexture AS IDirect3DTexture9
   INSTANCE m_quadMtrl AS D3DMATERIAL9
   INSTANCE m_pLight0 AS D3DLIGHT9
   INSTANCE m_bHandleWindowResize AS LONG
   INSTANCE m_fSpinX AS SINGLE
   INSTANCE m_fSpinY AS SINGLE
   INSTANCE m_quadVertices () AS Vertex

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      m_bHandleWindowResize = -1
      DIM m_quadVertices(3) AS INSTANCE Vertex
      FillVertex(m_quadVertices(0), -1.0!, 1.0!, 0.0!,  0.0!, 0.0!, -1.0!,  0.0!,0.0!)
      FillVertex(m_quadVertices(1),  1.0!, 1.0!, 0.0!,  0.0!, 0.0!, -1.0!,  1.0!,0.0!)
      FillVertex(m_quadVertices(2), -1.0!,-1.0!, 0.0!,  0.0!, 0.0!, -1.0!,  0.0!,1.0!)
      FillVertex(m_quadVertices(3),  1.0!,-1.0!, 0.0!,  0.0!, 0.0!, -1.0!,  1.0!,1.0!)
      ' // Setup a material for the teapot
      m_teapotMtrl.Diffuse.r  = 0.0!
      m_teapotMtrl.Diffuse.g  = 1.0!
      m_teapotMtrl.Diffuse.b  = 1.0!
      m_teapotMtrl.Diffuse.a  = 1.0!
      m_teapotMtrl.Specular.r = 1.0!
      m_teapotMtrl.Specular.g = 1.0!
      m_teapotMtrl.Specular.b = 1.0!
      m_teapotMtrl.Specular.a = 1.0!
      m_teapotMtrl.Power      = 40.0!
      ' // Setup a material for the textured quad
      m_quadMtrl.Diffuse.r  = 1.0!
      m_quadMtrl.Diffuse.g  = 1.0!
      m_quadMtrl.Diffuse.b  = 1.0!
      m_quadMtrl.Diffuse.a  = 1.0!
      m_quadMtrl.Specular.r = 1.0!
      m_quadMtrl.Specular.g = 1.0!
      m_quadMtrl.Specular.b = 1.0!
      m_quadMtrl.Specular.a = 1.0!
      m_quadMtrl.Power      = 40.0!
      ' // Setup a simple directional light and some ambient
      m_pLight0.Type = %D3DLIGHT_DIRECTIONAL
      m_pLight0.Direction.x  = 1.0!
      m_pLight0.Direction.y  = 0.0!
      m_pLight0.Direction.z  = 1.0!
      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!
   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

      ' // 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)

      ' // Sets the device render-state parameters
      m_pd3dDevice.SetRenderState(%D3DRS_ZENABLE, %TRUE)
      m_pd3dDevice.SetRenderState(%D3DRS_LIGHTING, %TRUE)
      m_pd3dDevice.SetRenderState(%D3DRS_SPECULARENABLE, %TRUE)

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

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

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

      ' // Creates a vertex buffer
      ' // NOTE: When a device is lost, vertex buffers created using D3DPOOL_DEFAULT
      ' // must be released properly before calling IDirect3DDevice9.Reset.
      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, %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

      ' // Create a mesh object...
      ' //
      ' // NOTE: When a device is lost, meshes created using D3DXMESH_DYNAMIC
      ' // must be released properly before calling IDirect3DDevice9.Reset.
      D3DXLoadMeshFromX(".\Resources\teapot.x", _
                        %D3DXMESH_DYNAMIC, _    ' // Must be Released properly before calling IDirect3DDevice9.Reset
                        m_pd3dDevice, _
                        BYVAL %NULL, BYVAL %NULL, BYVAL %NULL, BYVAL %NULL, m_pTeapotMesh)

      ' // 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)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      LOCAL matView AS D3DXMATRIX
      LOCAL matWorld AS D3DXMATRIX
      LOCAL matRotation AS D3DXMATRIX
      LOCAL matTranslation AS D3DXMATRIX

      D3DXMatrixIdentity(matView)
      m_pD3DDevice.SetTransform(%D3DTS_VIEW, matView)

      ' // Place and render first teapot...
      D3DXMatrixRotationYawPitchRoll(matRotation, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)
      D3DXMatrixTranslation(matTranslation, 1.4!, 0.0!, 6.0!)
      D3DXMatrixMultiply(matWorld, matRotation, matTranslation)
      m_pd3dDevice.SetTransform(%D3DTS_WORLD, matWorld)

      m_pd3dDevice.SetMaterial(m_teapotMtrl)
      m_pTeapotMesh.DrawSubset(0)

      ' // Place and render textured quad...
      D3DXMatrixTranslation(matTranslation, -1.6!, 0.0!, 6.0!)
      D3DXMatrixMultiply(matWorld, matRotation, matTranslation)
      m_pd3dDevice.SetTransform(%D3DTS_WORLD, matWorld)

      m_pd3dDevice.SetMaterial(m_quadMtrl)
      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)

      ' // 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_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
   ' =====================================================================================

   ' =====================================================================================
   ' Handle window resizing
   ' =====================================================================================
   METHOD ResizeWindow (BYVAL hwnd AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG)
      LOCAL hr AS LONG
      IF ISFALSE m_bHandleWindowResize THEN EXIT METHOD
      ' // If the device is not NULL and the WM_SIZE message is not a
      ' // SIZE_MINIMIZED event, resize the device's swap buffers to match
      ' // the new window size.
      IF ISOBJECT(m_pd3dDevice) AND wParam <> %SIZE_MINIMIZED THEN
         ' // Invalidate device objects
         m_pTexture = NOTHING
         m_pVertexBuffer = NOTHING
         m_pTeapotMesh = NOTHING
         m_d3dpp.BackBufferWidth  = LO(WORD, lParam)
         m_d3dpp.BackBufferHeight = HI(WORD, lParam)
         hr = m_pd3dDevice.Reset(m_d3dpp)
         IF hr = %D3DERR_INVALIDCALL THEN
            MessageBox %NULL, "Call to Reset() failed with D3DERR_INVALIDCALL! ", _
               "ERROR", %MB_OK OR %MB_ICONEXCLAMATION
         END IF
         ME.CreateDeviceObjects
      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_bHandleWindowResize = NOT m_bHandleWindowResize
            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_SIZE
         IF ISOBJECT(pDX9) THEN pDX9.ResizeWindow hwnd, 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
' ========================================================================================

Title: DX9: Spot Light
Post by: José Roca on August 28, 2011, 05:42:51 PM
 
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_SpotLight.bas
' Contents: DX9 example
' Description: Demonstrates how to setup a spot light with Direct3D. The sample also
' demonstrates how the tessellation or triangle count of a mesh effects lighting.
' 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/17/05, available at
' http://www.codesampler.com/dx9src/dx9src_5.htm#dx9_spot_light
' Control Keys: v - Decrease the mesh's tessellation or vertex count
'               V - Increase the mesh's tessellation or vertex count
'               w - Toggle wire-frame mode
'
'               r  - Decrease Range
'               R  - Increase Range
'               t  - Decrease Theta
'               T  - Increase Theta
'               p  - Decrease Phi
'               P  - Increase Phi
'               f  - Decrease Falloff
'               F  - Increase Falloff
'               F1 - Decrease Attenuation0
'               F2 - Increase Attenuation0
'               F3 - Decrease Attenuation1
'               F4 - Increase Attenuation1
'               F5 - Decrease Attenuation2
'               F6 - Increase Attenuation2
'
'               Up   - Move the point light up
'               Down - Move the point light down
'               Left  - Swing the spot to the left
'               Right - Swing the spot to the right
'
' NOTE: Please refer to the DirectX 9.0c Documentation for the more
'       information concerning the Attenuation, Theta, Phi, and Falloff controls.
' ########################################################################################

' 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) - Spot 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
   INSTANCE m_pConeMesh AS ID3DXMesh                   ' // A mesh to represent a spot light
   INSTANCE m_light0 AS D3DLIGHT9
   INSTANCE m_meshMaterial AS D3DMATERIAL9
   INSTANCE m_coneMaterial AS D3DMATERIAL9
   INSTANCE m_bRenderInWireFrame AS LONG
   INSTANCE m_fLightPositionY AS SINGLE
   INSTANCE m_fLightDirectionX AS SINGLE
   INSTANCE m_fAttenuation0 AS SINGLE
   INSTANCE m_fAttenuation1 AS SINGLE
   INSTANCE m_fAttenuation2 AS SINGLE
   INSTANCE m_fRange AS SINGLE
   INSTANCE m_fTheta AS SINGLE
   INSTANCE m_fPhi AS SINGLE
   INSTANCE m_fFalloff AS SINGLE
   INSTANCE m_nMeshVertCount AS LONG
   INSTANCE m_nNumVerts AS LONG

   ' ====================================================================================
   ' Initializes values
   ' ====================================================================================
   CLASS METHOD Create
      m_bRenderInWireFrame = %FALSE
      m_fLightPositionY    = 3.0!
      m_fLightDirectionX   = 0.0!
      m_fAttenuation0      = 0.0!
      m_fAttenuation1      = 0.5!
      m_fAttenuation2      = 0.0!
      m_fRange             = 10.0!
      m_fTheta             = 0.5!
      m_fPhi               = 1.0!
      m_fFalloff           = 1.0!
      m_nMeshVertCount     = 0
      m_nNumVerts          = 64
   END METHOD
   ' ====================================================================================

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

   ' =====================================================================================
   ' Init lighting
   ' =====================================================================================
   METHOD initLighting

      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %TRUE)
      m_pD3DDevice.LightEnable(0, %TRUE)

      ' // Set up our material...
      m_meshMaterial.Diffuse.r = 1.0!
      m_meshMaterial.Diffuse.g = 1.0!
      m_meshMaterial.Diffuse.b = 1.0!
      m_meshMaterial.Diffuse.a = 1.0!
      m_meshMaterial.Ambient.r = 1.0!
      m_meshMaterial.Ambient.g = 1.0!
      m_meshMaterial.Ambient.b = 1.0!
      m_meshMaterial.Ambient.a = 1.0!
      m_pD3DDevice.SetMaterial(m_meshMaterial)

      ' // Set up our point light...
      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_light0.Type         = %D3DLIGHT_SPOT
      LOCAL v AS D3DXVECTOR3
      v.x = 0.0! : v.y = m_fLightPositionY : v.z = 0.0!
      TYPE SET m_light0.Position = v
      v.x = m_fLightDirectionX : v.y = -1.0! : v.z = -0.1!
      TYPE SET m_light0.Direction = v
      m_light0.Attenuation0 = m_fAttenuation0
      m_light0.Attenuation1 = m_fAttenuation1
      m_light0.Attenuation2 = m_fAttenuation2
      m_light0.Range        = m_fRange
      m_light0.Theta        = m_fTheta
      m_light0.Phi          = m_fPhi
      m_light0.Falloff      = m_fFalloff
      m_pD3DDevice.SetLight(0, m_light0)

      ' // Enable some dim, grey ambient lighting...
      m_pD3DDevice.SetRenderState(%D3DRS_AMBIENT, _
                                  D3DCOLOR_COLORVALUE(0.25, 0.25, 0.25, 1.0))

      ' // Set up a yellow emissive material so our little sphere, which
      ' // represents our light, will appear to glow yellow.
      m_coneMaterial.Emissive.r = 1.0!
      m_coneMaterial.Emissive.g = 1.0!
      m_coneMaterial.Emissive.b = 0.0!
      m_coneMaterial.Emissive.a = 1.0!

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

   ' =====================================================================================
   ' Create simple mesh
   ' =====================================================================================
   METHOD createSimpleMesh (BYVAL nNumVertsAlongX AS LONG, BYVAL nNumVertsAlongZ AS LONG, _
                              BYVAL fMeshLengthAlongX AS SINGLE, BYVAL fMeshLengthAlongZ AS SINGLE) AS LONG

      LOCAL nMeshVertCount AS LONG
      nMeshVertCount = (nNumVertsAlongX-1) * (nNumVertsAlongZ-1) * 6

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

      m_pD3DDevice.CreateVertexBuffer(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 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 nNumVertsAlongZ - 2
         ' // Fill the row with quads which are composed of two triangles each...
         FOR x = 0 TO nNumVertsAlongX - 2
            ' // First triangle of the current quad
            ' // 1 ___ 2
            ' //  |  /|
            ' //  |/__|
            ' // 0

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

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

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

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

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

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

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

      m_pMeshVertices.Unlock

      METHOD = nMeshVertCount

   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

      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)

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

      ME.initLighting

      ' // Create a custom mesh to test lighting on.
      m_nMeshVertCount = ME.createSimpleMesh(m_nNumVerts, m_nNumVerts, 10.0!, 10.0!)

      ' // Create a sphere mesh to represent our spot light's position and direction.
      D3DXCreateCylinder(m_pd3dDevice, 0.0!, 0.25!, 0.5!, 20, 20, m_pConeMesh, 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.0!,0.0!,0.0!,1.0!), 1.0!, 0)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

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

      ' // Set up our light and apply a material...
      m_light0.Position.y   = m_fLightPositionY
      m_light0.Direction.x  = m_fLightDirectionX
      m_light0.Attenuation0 = m_fAttenuation0
      m_light0.Attenuation1 = m_fAttenuation1
      m_light0.Attenuation2 = m_fAttenuation2
      m_light0.Range        = m_fRange
      m_light0.Range        = m_fRange
      m_light0.Theta        = m_fTheta
      m_light0.Phi          = m_fPhi
      m_light0.Falloff      = m_fFalloff

      m_pD3DDevice.SetLight(0, m_light0)
      m_pD3DDevice.LightEnable(0, %TRUE)
      m_pD3DDevice.SetMaterial(m_meshMaterial)

      ' // Render a tesselated mesh of variable resolution so we can see how its
      ' // tessleation alters our attempt to light it.

      D3DXMatrixTranslation(matTrans, -5.0!, 0.0!, -5.0!)
      D3DXMatrixRotationZ(matRotate, D3DXToRadian(0.0!))
      D3DXMatrixMultiply(matWorld, matRotate, matTrans)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      m_pD3DDevice.SetStreamSource(0, m_pMeshVertices, 0, SIZEOF(Vertex))
      m_pD3DDevice.SetFVF(%FVF_Flags)
      m_pD3DDevice.DrawPrimitive(%D3DPT_TRIANGLELIST, 0, m_nMeshVertCount / 3)

      ' // Render a little yellow cone to represent out spot light's current
      ' // position and direction in 3D space.

      m_pD3DDevice.LightEnable(0, %FALSE)
      m_pD3DDevice.SetMaterial(m_coneMaterial)

      ' // Position the spot light and then point it in the light's direction
      LOCAL vecFrom, vecAt, vecUp AS D3DXVECTOR3
      vecFrom.x = m_light0.Position.x
      vecFrom.y = m_light0.Position.y
      vecFrom.z = m_light0.Position.z
      vecAt.x = m_light0.Position.x + m_light0.Direction.x
      vecAt.y = m_light0.Position.y + m_light0.Direction.y
      vecAt.z = m_light0.Position.z + m_light0.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)

      ' // 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_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_CHAR
            SELECT CASE wParam
               CASE ASC("v")
                  m_nNumVerts = m_nNumVerts - 1
                  ' // Don't let the mesh's resolution get too low!
                  IF m_nNumVerts <= 1 THEN m_nNumVerts = 2
                  ' // Release the old mesh so we can create a new one.
                  m_pMeshVertices = NOTHING
                  m_nMeshVertCount = ME.createSimpleMesh(m_nNumVerts, m_nNumVerts, 10.0!, 10.0!)
               CASE ASC("V")
                  m_nNumVerts = m_nNumVerts + 1
                  ' // Release the old mesh so we can create a new one.
                  m_pMeshVertices = NOTHING
                  m_nMeshVertCount = ME.createSimpleMesh(m_nNumVerts, m_nNumVerts, 10.0!, 10.0!)
               CASE ASC("r")
                  m_fRange = m_fRange - 1.0!
               CASE ASC("R")
                  m_fRange = m_fRange + 1.0!
               CASE ASC("t")
                  m_fTheta = m_fTheta - 0.01!
                  IF m_fTheta < 0.0! THEN m_fTheta = 0.0!
               CASE ASC("T")
                  m_fTheta = m_fTheta + 0.01!
               CASE ASC("p")
                  m_fPhi = m_fPhi - 0.01!
                  IF m_fPhi < 0.0! THEN m_fPhi = 0.0!
               CASE ASC("P")
                  m_fPhi = m_fPhi + 0.01!
               CASE ASC("f")
                  m_fFalloff = m_fFalloff - 0.01!
                  IF m_fFalloff < 0.0! THEN m_fFalloff = 0.0!
               CASE ASC("F")
                  m_fFalloff = m_fFalloff + 0.01!
               CASE ASC("w"), ASC("W")
                  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

         CASE %WM_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE %VK_F1
                  m_fAttenuation0 = m_fAttenuation0 - 0.01!
                  IF m_fAttenuation0 < 0.0! THEN m_fAttenuation0 = 0.0!
               CASE %VK_F2
                  m_fAttenuation0 = m_fAttenuation0 + 0.01!
               CASE %VK_F3
                  m_fAttenuation1 = m_fAttenuation1 - 0.01!
                  IF m_fAttenuation1 < 0.0! THEN m_fAttenuation1 = 0.0!
               CASE %VK_F3
                  m_fAttenuation1 = m_fAttenuation1+ 0.01!
               CASE %VK_F5
                  m_fAttenuation2 = m_fAttenuation2 - 0.01!
                  IF m_fAttenuation2 < 0.0! THEN m_fAttenuation2 = 0.0!
               CASE %VK_F6
                  m_fAttenuation2 = m_fAttenuation2 + 0.01!
               CASE %VK_UP
                  m_fLightPositionY = m_fLightPositionY + 0.1!
               CASE %VK_DOWN
                  m_fLightPositionY = m_fLightPositionY - 0.1!
               CASE %VK_LEFT
                  m_fLightDirectionX = m_fLightDirectionX - 0.1!
               CASE %VK_RIGHT
                  m_fLightDirectionX = m_fLightDirectionX + 0.1!
            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, %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
' ========================================================================================

Title: DX9: Texture Mapping
Post by: José Roca on August 28, 2011, 05:44:58 PM
 
Demonstrates basic texture mapping using a textured quad and a bitmap of some wooden floor tiles.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_Texture.bas
' Contents: DX9 example
' Description: Demonstrates basic texture mapping using a textured quad and a bitmap of
' some wooden floor tiles.
' 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_3.htm#dx9_texture
' ########################################################################################

' 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) - Texturing"

%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_quadVertices () AS Vertex

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      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
      D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\woodfloor.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_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

      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
      D3DXMatrixTranslation(matWorld, 0.0!, 0.0!, 4.0!)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      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)

      ' // 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
   ' =====================================================================================

   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
         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
' ========================================================================================

Title: DX9: Texture Filtering
Post by: José Roca on August 28, 2011, 05:46:33 PM
 
Demonstrates how to filter out unwanted graphical artifacts from Direct3D textures.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_TextureFiltering.bas
' Contents: DX9 example
' Description: Demonstrates how to filter out unwanted graphical artifacts from Direct3D textures.
' Direct3D texture filtering is controlled by calling SetSamplerState() and setting either
' D3DSAMP_MINFILTER, D3DSAMP_MAGFILTER, or D3DSAMP_MIPFILTER to one of the following filtering modes:
'    D3DTEXF_NONE
'    D3DTEXF_POINT
'    D3DTEXF_LINEAR
'    D3DTEXF_ANISOTROPIC
'    D3DTEXF_FLATCUBIC
'    D3DTEXF_GAUSSIANCUBIC
' 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_filtering.cpp by Kevin Harris, 03/24/05, available at
' http://www.codesampler.com/dx9src/dx9src_3.htm#dx9_texture_filtering
' Control Keys: F1 - Change Minification filter
'               F2 - Change Magnification filter
'               F3 - Change Mip-Map filter
'               F4 - Increase Mip-Map LOD Bias
'               F5 - Decrease Mip-Map LOD Bias
'               F6 - Increase Max Anisotropy value
'               F7 - Decrease Max Anisotropy value
'               Left Mouse Button - Spin the view
'               Up Arrow - Move the test quad closer
'               Down Arrow - Move the test quad 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 filtering"

%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
' ========================================================================================

%FILTER_TYPE_NONE        = 0
%FILTER_TYPE_POINT       = 1
%FILTER_TYPE_LINEAR      = 2
%FILTER_TYPE_ANISOTROPIC = 3

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
   INSTANCE m_pVertexBuffer AS IDirect3DVertexBuffer9
   INSTANCE m_pTexture AS IDirect3DTexture9
   INSTANCE m_fDistance AS SINGLE
   INSTANCE m_fSpinX AS SINGLE
   INSTANCE m_fSpinY AS SINGLE
   INSTANCE m_MinFilterType AS LONG
   INSTANCE m_MagFilterType AS LONG
   INSTANCE m_MipFilterType AS LONG
   INSTANCE m_nAnisotropy AS LONG
   INSTANCE m_fMipMapLodBias AS LONG
   INSTANCE m_bChangeFilters AS LONG
   INSTANCE m_quadVertices () AS Vertex

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      m_fDistance      = 4.0!
      m_MinFilterType  = %FILTER_TYPE_NONE
      m_MagFilterType  = %FILTER_TYPE_NONE
      m_MipFilterType  = %FILTER_TYPE_NONE
      m_nAnisotropy    = 1
      m_fMipMapLodBias = 0.0!
      m_bChangeFilters = %TRUE
      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

   '  // To create a Windows friendly font using only a point size, an
   '  // application must calculate the logical height of the font.
   '  //
   '  // This is because functions like createFont() and createFontIndirect()
   '  // only use logical units to specify height.
   '  //
   '  // Here's the formula to find the height in logical pixels:
   '  //
   '  //             -( point_size * LOGPIXELSY )
   '  //    height = ----------------------------
   '  //                          72

      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
   ' =====================================================================================

   ' =====================================================================================
   ' Sets minification filter
   ' =====================================================================================
   METHOD setMinificationFilter

      SELECT CASE AS LONG m_MinFilterType
         CASE 0
            m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_NONE)
         CASE 1
            m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_POINT)
         CASE 2
            m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_LINEAR)
         CASE 3
            m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_ANISOTROPIC)
      END SELECT

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

   ' =====================================================================================
   ' Sets magnification filter
   ' =====================================================================================
   METHOD setMagnificationFilter

      SELECT CASE AS LONG m_MagFilterType
         CASE 0
            m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_NONE)
         CASE 1
            m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_POINT)
         CASE 2
            m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_LINEAR)
         CASE 3
            m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_ANISOTROPIC)
      END SELECT

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

   ' =====================================================================================
   ' Sets mip filter
   ' =====================================================================================
   METHOD setMipMapFilter

      SELECT CASE AS LONG m_MipFilterType
         CASE 0
            m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MIPFILTER, %D3DTEXF_NONE)
         CASE 1
            m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MIPFILTER, %D3DTEXF_POINT)
         CASE 2
            m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MIPFILTER, %D3DTEXF_LINEAR)
         CASE 3
            m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MIPFILTER, %D3DTEXF_ANISOTROPIC)
      END SELECT

   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

      LOCAL hr AS LONG

      ' // Load the texture
      D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\texture_filtering.bmp", m_pTexture)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_NONE)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_NONE)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MIPFILTER, %D3DTEXF_NONE)

      ' // Create the font
      ME.createD3DXFont

      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

      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)

      ' // 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 matTrans AS D3DXMATRIX
      LOCAL matRot AS D3DXMATRIX
      LOCAL matWorld AS D3DXMATRIX

      D3DXMatrixTranslation(matTrans, 0.0!, 0.0!, m_fDistance)
      D3DXMatrixRotationYawPitchRoll(matRot, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)
      D3DXMatrixMultiply(matWorld, matRot, matTrans)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      IF ISTRUE m_bChangeFilters THEN
         ME.setMinificationFilter
         ME.setMagnificationFilter
         ME.setMipMapFilter
         m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAXANISOTROPY, m_nAnisotropy)
         m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MIPMAPLODBIAS, m_fMipMapLodBias)
         m_bChangeFilters = %FALSE
      END IF

      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)

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

      STATIC szMinFilter AS ASCIIZ * 255
      STATIC szMagFilter AS ASCIIZ * 255
      STATIC szMipFilter AS ASCIIZ * 255

      SELECT CASE AS LONG m_MinFilterType
         CASE %FILTER_TYPE_NONE
            szMinFilter = "D3DSAMP_MINFILTER = D3DTEXF_NONE    (Change: F1)"
         CASE %FILTER_TYPE_POINT
            szMinFilter = "D3DSAMP_MINFILTER = D3DTEXF_POINT    (Change: F1)"
         CASE %FILTER_TYPE_LINEAR
            szMinFilter = "D3DSAMP_MINFILTER = D3DTEXF_LINEAR    (Change: F1)"
         CASE %FILTER_TYPE_ANISOTROPIC
            szMinFilter = "D3DSAMP_MINFILTER = D3DTEXF_ANISOTROPIC    (Change: F1)"
      END SELECT

      SELECT CASE AS LONG m_MagFilterType
         CASE %FILTER_TYPE_NONE
            szMagFilter = "D3DSAMP_MAGFILTER = D3DTEXF_NONE    (Change: F2)"
         CASE %FILTER_TYPE_POINT
            szMagFilter = "D3DSAMP_MAGFILTER = D3DTEXF_POINT    (Change: F2)"
         CASE %FILTER_TYPE_LINEAR
            szMagFilter = "D3DSAMP_MAGFILTER = D3DTEXF_LINEAR    (Change: F2)"
         CASE %FILTER_TYPE_ANISOTROPIC
            szMagFilter = "D3DSAMP_MAGFILTER = D3DTEXF_ANISOTROPIC    (Change: F2)"
      END SELECT

      SELECT CASE AS LONG m_MipFilterType
         CASE %FILTER_TYPE_NONE
            szMipFilter = "D3DSAMP_MIPFILTER = D3DTEXF_NONE    (Change: F3)"
         CASE %FILTER_TYPE_POINT
            szMipFilter = "D3DSAMP_MIPFILTER = D3DTEXF_POINT    (Change: F3)"
         CASE %FILTER_TYPE_LINEAR
            szMipFilter = "D3DSAMP_MIPFILTER = D3DTEXF_LINEAR    (Change: F3)"
         CASE %FILTER_TYPE_ANISOTROPIC
            szMipFilter = "D3DSAMP_MIPFILTER = D3DTEXF_ANISOTROPIC    (Change: F3)"
      END SELECT

      m_pD3DXFont.DrawTextA(NOTHING, szMinFilter, -1, destRect1, %DT_NOCLIP, _
                           D3DCOLOR_COLORVALUE(1.0!, 1.0!, 1.0!, 1.0!))
      m_pD3DXFont.DrawTextA(NOTHING, szMagFilter, -1, destRect2, %DT_NOCLIP, _
                           D3DCOLOR_COLORVALUE( 1.0!, 1.0!, 1.0!, 1.0!))
      m_pD3DXFont.DrawTextA(NOTHING, szMipFilter, -1, destRect3, %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_pD3DXFont = 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_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE %VK_F1
                  m_MinFilterType = m_MinFilterType + 1
                  IF m_MinFilterType > 3 THEN m_MinFilterType = 0
                  m_bChangeFilters = %TRUE
               CASE %VK_F2
                  m_MagFilterType = m_MagFilterType + 1
                  IF m_MagFilterType > 3 THEN m_MagFilterType = 0
                  m_bChangeFilters = %TRUE
               CASE %VK_F3
                  m_MipFilterType = m_MipFilterType + 1
                  IF m_MipFilterType > 3 THEN m_MipFilterType = 0
                  m_bChangeFilters = %TRUE
               CASE %VK_F4
                  m_fMipMapLodBias = m_fMipMapLodBias + 1.0!
                  m_bChangeFilters = %TRUE
               CASE %VK_F5
                  m_fMipMapLodBias = m_fMipMapLodBias - 1.0!
                  m_bChangeFilters = %TRUE
               CASE %VK_F6
                  m_nAnisotropy = m_nAnisotropy + 1.0!
                  m_bChangeFilters = %TRUE
               CASE %VK_F7
                  m_nAnisotropy = m_nAnisotropy - 1.0!
                  m_bChangeFilters = %TRUE
               CASE 38   ' // Up Arrow Key
                  m_fDistance = m_fDistance - 1.0!
               CASE 40   ' // Down Arrow Key
                  m_fDistance = m_fDistance + 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

   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
         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
' ========================================================================================

Title: DX9: Texture subloading
Post by: José Roca on August 28, 2011, 05:48:31 PM
 
Demonstrates how texture sub-loading works under Direct3D by copying a smaller texture over the texel data of a larger texture.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_TextureSubloading.bas
' Contents: DX9 example
' Description: Demonstrates how texture sub-loading works under Direct3D by copying a
' smaller texture over the texel data of a larger texture.
' 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_subloading.cpp by Kevin Harris, 02/01/05, available at
' http://www.codesampler.com/dx9src/dx9src_3.htm#dx9_texture_subloading
' Control Keys: F1 - Toggle subloading
' ########################################################################################

' 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 subloading"

%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_quadVertices () AS Vertex
   INSTANCE m_bAlterTexture AS LONG
   INSTANCE m_bDoSubload AS LONG

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      m_bAlterTexture = %TRUE
      m_bDoSubload = %TRUE
      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
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the texture
   ' =====================================================================================
   METHOD LoadTexture () AS LONG
      LOCAL hr AS LONG
      m_pTexture = NOTHING
      hr = D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\tex128.bmp", m_pTexture)
      IF hr <> %D3D_OK THEN METHOD = hr : EXIT METHOD
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MINFILTER, %D3DTEXF_LINEAR)
      m_pD3DDevice.SetSamplerState(0, %D3DSAMP_MAGFILTER, %D3DTEXF_LINEAR)
   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   ' Loads the subtexture
   ' =====================================================================================
   METHOD LoadSubTexture () AS LONG

      LOCAL hr AS LONG
      LOCAL pSubTexture AS IDirect3DTexture9
      LOCAL pDestSurface AS IDirect3DSurface9
      LOCAL pSrcSurface AS IDirect3DSurface9
      LOCAL srcRect AS RECT
      LOCAL destRect AS RECT

      hr = D3DXCreateTextureFromFile(m_pD3DDevice, ".\Resources\tex64.bmp", pSubTexture)
      IF hr <> %D3D_OK THEN METHOD = hr : EXIT METHOD
      m_pTexture.GetSurfaceLevel(0, pDestSurface)
      pSubTexture.GetSurfaceLevel(0, pSrcSurface)

      SetRect(srcRect, 0, 0, 64, 64)
      SetRect(destRect, 32, 32, 96, 96)

      D3DXLoadSurfaceFromSurface(pDestSurface, BYVAL %NULL, destRect, _
                                 pSrcSurface,  BYVAL %NULL, srcRect, _
                                 %D3DX_DEFAULT, 0)

      pSrcSurface = NOTHING
      pDestSurface = NOTHING
      pSubTexture = NOTHING

   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

      LOCAL hr AS LONG

      ' // Load the texture
      ME.LoadTexture

      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, %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

      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)

      ' // 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
      D3DXMatrixTranslation(matWorld, 0.0!, 0.0!, 4.0!)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      IF ISTRUE m_bAlterTexture THEN
         IF ISTRUE m_bDoSubload THEN
            ME.LoadSubTexture
         ELSE
            ME.LoadTexture
         END IF
         m_bAlterTexture = %FALSE
      END IF

      ' // Begins the scene
      m_pD3DDevice.BeginScene

      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)

      ' // 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_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_KEYDOWN
            SELECT CASE LO(WORD, wParam)
               CASE %VK_ESCAPE
                  SendMessage hwnd, %WM_CLOSE, 0, 0
               CASE %VK_F1
                  IF m_bDoSubload = 0 THEN m_bDoSubload = -1 ELSE m_bDoSubload = 0
                  m_bAlterTexture = %TRUE
            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

   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
         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
' ========================================================================================

Title: DX9: Transforms
Post by: José Roca on August 28, 2011, 05:50:31 PM
 
Demonstrates how to use concatenated translation, rotation, and scaling matrices to create a simulated solar system. And as a small bonus, the sample also demonstrates how to optimize Direct3D applications using a matrix stack to prevent continuous changes to the view matrix, which can kill your apps draw time.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_Transforms.bas
' Contents: DX9 example
' Description: how to use translation, rotation, and scaling matrices to create a simulated solar system.
' 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_transforms.cpp by Kevin Harris, 06/28/05, available at
' http://www.codesampler.com/dx9src/dx9src_2.htm#dx9_transforms
' Control Keys: F1    - Speed up rotations
'               F2    - Slow down rotations
'               Space - Toggle orbiting on/off
' ########################################################################################

' 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) - Transforms"

%FVF_Flags = %D3DFVF_XYZ OR %D3DFVF_DIFFUSE

TYPE Vertex
   x       AS SINGLE
   y       AS SINGLE
   z       AS SINGLE
   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_pSunMesh AS ID3DXMesh
   INSTANCE m_pEarthMesh AS ID3DXMesh
   INSTANCE m_pMoonMesh AS ID3DXMesh
   INSTANCE m_matrixStack AS ID3DXMatrixStack
   INSTANCE m_fSpeedmodifier AS SINGLE
   INSTANCE m_bOrbitOn AS LONG

   ' ====================================================================================
   ' Initializes values
   ' ====================================================================================
   CLASS METHOD Create
      m_fSpeedmodifier = 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)
      m_pD3DDevice.SetRenderState(%D3DRS_FILLMODE, %D3DFILL_WIREFRAME)

      ' // We'll use the D3DXCreateSphere utility function to create three simple
      ' // sphere meshes to experiment with.
      LOCAL pTempEarthMesh AS ID3DXMesh
      LOCAL pTempSunMesh AS ID3DXMesh

      D3DXCreateSphere(m_pD3DDevice, 1.0!, 20, 20, pTempSunMesh, BYVAL %NULL)
      D3DXCreateSphere(m_pD3DDevice, 1.0!, 10, 10, pTempEarthMesh, BYVAL %NULL)
      D3DXCreateSphere(m_pD3DDevice, 0.5!, 8, 8, m_pMoonMesh, BYVAL %NULL)

      ' // Unfortunately, the D3DXCreateSphere utility function creates a mesh
      ' // with no color, so we'll need to make a clone of the original meshes
      ' // using a FVF code that does include color so we can set up the Earth
      ' // and Sun with color.
      ' //
      ' // Once that's been done, we'll need to set the color values to something
      ' // appropriate for our solar system model.

      ' // Clone the original Earth mesh and make it blue...

      LOCAL i AS LONG
      LOCAL pTempVertexBuffer AS IDirect3DVertexBuffer9
      LOCAL nNumVerts AS LONG
      LOCAL pVertices AS Vertex PTR

      pTempEarthMesh.CloneMeshFVF(0, %FVF_Flags, m_pD3DDevice, m_pEarthMesh)
      IF SUCCEEDED(m_pEarthMesh.GetVertexBuffer(pTempVertexBuffer)) THEN
         nNumVerts = m_pEarthMesh.GetNumVertices
         pTempVertexBuffer.Lock(0, 0, pVertices, 0)
         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

      ' // Clone the original Sun mesh and make it yellow...
      pVertices = %NULL
      pTempSunMesh.CloneMeshFVF(0, %FVF_Flags, m_pD3DDevice, m_pSunMesh)
      IF SUCCEEDED(m_pSunMesh.GetVertexBuffer(pTempVertexBuffer)) THEN
         nNumVerts = m_pSunMesh.GetNumVertices
         pTempVertexBuffer.Lock(0, 0, pVertices, 0)
         FOR i = 0 TO nNumVerts - 1
            @pVertices[i].diffuse = D3DCOLOR_COLORVALUE(1.0, 1.0, 0.0, 1.0 )
         NEXT
         pTempVertexBuffer.Unlock
         pTempVertexBuffer = NOTHING
      END IF

      ' // The temp meshes are no longer needed...
      pTempEarthMesh = NOTHING
      pTempSunMesh = NOTHING

      ' // Create a matrix stack...
      D3DXCreateMatrixStack(0, m_matrixStack)

      ' // Return success
      METHOD = %S_OK

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

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

      LOCAL hr AS LONG
      STATIC fElpasedTime AS SINGLE
      STATIC dCurrentTime AS DOUBLE
      STATIC dLastTime    AS DOUBLE
      STATIC fSunSpin     AS SINGLE
      STATIC fEarthSpin   AS SINGLE
      STATIC fEarthOrbit  AS SINGLE
      STATIC fMoonSpin    AS SINGLE
      STATIC fMoonOrbit   AS SINGLE

      ' // 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

      ' // Have the view matrix move the view move us to a good vantage point so
      ' // we can see the Sun sitting at the origin while the Earth orbits it.

      LOCAL matView AS D3DXMATRIX
      LOCAL v1, v2, v3 AS D3DXVECTOR3

      v1.x = 0.0! : v1.y = 2.0! : v1.z = -25.0!   ' Camera position
      v2.x = 0.0! : v2.y = 0.0! : 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)

      m_matrixStack.LoadIdentity()
      m_matrixStack.LoadMatrix(matView)

      ' // Cache rotational positions between frames...
      dCurrentTime = timeGetTime
      fElpasedTime = (dCurrentTime - dLastTime) * 0.001
      dLastTime    = dCurrentTime

      IF ISTRUE m_bOrbitOn THEN
         fSunSpin = fSunSpin + m_fSpeedmodifier * (fElpasedTime * 10.0!)
         fEarthSpin = fEarthSpin + m_fSpeedmodifier * (fElpasedTime * 100.0!)
         fEarthOrbit = fEarthOrbit + m_fSpeedmodifier * (fElpasedTime * 20.0!)
         fMoonSpin = fMoonSpin + m_fSpeedmodifier * (fElpasedTime * 50.0!)
         fMoonOrbit = fMoonOrbit + m_fSpeedmodifier * (fElpasedTime * 200.0!)
      END IF

      ' // The Sun is easy because the mesh for it is initially created centered
      ' // at origin. All we have to do is spin it by rotating it about the Y axis
      ' // and scale it by 5.0f.

      LOCAL mSunScale AS D3DXMATRIX
      LOCAL mSunSpinRotation AS D3DXMATRIX
      LOCAL mSunMatrix AS D3DXMATRIX

      D3DXMatrixRotationY(mSunSpinRotation, D3DXToRadian(fSunSpin))
      D3DXMatrixScaling(mSunScale, 5.0!, 5.0!, 5.0!)

      ' // Now, concatenate them together...

      ' // Uniformly scale the Sun up in size and then spin it on its axis.
      D3DXMatrixMultiply(mSunMatrix, mSunScale, mSunSpinRotation)

      m_pD3DDevice.SetTransform(%D3DTS_WORLD, mSunMatrix)
      m_pSunMesh.DrawSubset(0)

      ' // The Earth is a little more complicated since it needs to spin as well
      ' // as orbit the Sun. This can be done by combining three transformations
      ' // together.

      LOCAL mEarthTranslationToOrbit AS D3DXMATRIX
      LOCAL mEarthSpinRotation AS D3DXMATRIX
      LOCAL mEarthOrbitRotation AS D3DXMATRIX
      LOCAL mEarthMatrix AS D3DXMATRIX
      LOCAL mTmpMatrix AS D3DXMATRIX

      D3DXMatrixRotationY(mEarthSpinRotation, D3DXToRadian(fEarthSpin))
      D3DXMatrixTranslation(mEarthTranslationToOrbit, 0.0!, 0.0!, 12.0!)
      D3DXMatrixRotationY(mEarthOrbitRotation, D3DXToRadian( fEarthOrbit))

      ' // Now, concatenate them together...

      ' mEarthMatrix = mEarthSpinRotation *       // 1. Spin the Earth on its own axis.
      '                mEarthTranslationToOrbit * // 2. Then translate it away from the origin (where the Sun's at)
      '                mEarthOrbitRotation;       // 3. and rotate it again to make it orbit the origin (or the Sun).

      D3DXMatrixMultiply(mTmpMatrix, mEarthSpinRotation, mEarthTranslationToOrbit)
      D3DXMatrixMultiply(mEarthMatrix, mTmpMatrix, mEarthOrbitRotation)

      m_pD3DDevice.SetTransform(%D3DTS_WORLD, mEarthMatrix)
      m_pEarthMesh.DrawSubset(0)

      ' // The Moon is the hardest to understand since it needs to not only spin on
      ' // its own axis and orbit the Earth, but needs to follow the Earth,
      ' // which is orbiting the Sun.
      ' //
      ' // This can be done by combining five transformations together with the last
      ' // two being borrowed from the Earth's transformation.

      LOCAL mMoonTranslationToOrbit AS D3DXMATRIX
      LOCAL mMoonSpinRotation AS D3DXMATRIX
      LOCAL mMoonOrbitRotation AS D3DXMATRIX
      LOCAL mMoonMatrix AS D3DXMATRIX

      D3DXMatrixRotationY(mMoonSpinRotation, D3DXToRadian(fMoonSpin))
      D3DXMatrixRotationY(mMoonOrbitRotation, D3DXToRadian(fMoonOrbit))
      D3DXMatrixTranslation(mMoonTranslationToOrbit, 0.0!, 0.0!, 2.0!)

      ' // The key to understanding the first three transforms is to pretend that
      ' // the Earth is located at the origin. We know it's not, but if we pretend
      ' // that it is, we can set up the Moon just like the we did the Earth since
      ' // the Moon orbits the Earth just like the Earth orbits the Sun.
      ' //
      ' // Once the Moon's transforms are set up we simply reuse the Earth's
      ' // translation and rotation matrix, which placed it in orbit, to offset
      ' // the Moon out to where it should be... following the Earth.

      ' // Now, concatenate them together...

      ' mMoonMatrix = mMoonSpinRotation *        // 1. Spin the Moon on its own axis.
      '               mMoonTranslationToOrbit *  // 2. Then translate it away from the origin (pretending that the Earth is there)
      '               mMoonOrbitRotation *       // 3. and rotate it again to make it orbit the origin (or the pretend Earth).

      '               mEarthTranslationToOrbit * // 4. Now, translate out to where the Earth is really at
      '               mEarthOrbitRotation;       // 5. and move with it by matching its orbit of the Earth.

      LOCAL mTmpMatrix2 AS D3DXMATRIX
      LOCAL mTmpMatrix3 AS D3DXMATRIX

      D3DXMatrixMultiply(mTmpMatrix2, mMoonSpinRotation, mMoonTranslationToOrbit)
      D3DXMatrixMultiply(mTmpMatrix3, mMoonOrbitRotation, mEarthTranslationToOrbit)
      D3DXMatrixMultiply(mTmpMatrix, mTmpMatrix2, mTmpMatrix3)
      D3DXMatrixMultiply(mMoonMatrix, mTmpMatrix, mEarthOrbitRotation)

      m_pD3DDevice.SetTransform(%D3DTS_WORLD, mMoonMatrix)
      m_pMoonMesh.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_matrixStack = NOTHING
            m_pSunMesh = NOTHING
            m_pEarthMesh = NOTHING
            m_pD3DDevice = NOTHING
            m_pD3D = 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_SPACE
                  m_bOrbitOn = NOT m_bOrbitOn
               CASE %VK_F1
                  m_fSpeedmodifier = m_fSpeedmodifier + 1
               CASE %VK_F2
                  m_fSpeedmodifier = m_fSpeedmodifier - 1
            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
' ========================================================================================

Title: DX9: Vertex Data (Vertex Buffers)
Post by: José Roca on August 28, 2011, 05:52:27 PM
 
Demonstrates how to use Vertex Buffers for the storage of model data. The sample creates a textured cube as an example.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_VertexData.bas
' Contents: DX9 example
' Description: Demonstrates how to use Vertex Buffers for the storage of model data.
' 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, 06/06/05,
' downloadable at http://www.codesampler.com/dx9src/dx9src_2.htm#dx9_vertex_data
' ########################################################################################

' 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) - Vertex Data"

%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_cubeVertices () AS Vertex

   ' ====================================================================================
   ' Initializes the vertex array
   ' ====================================================================================
   CLASS METHOD Create
      DIM m_cubeVertices(23) AS INSTANCE Vertex
      FillVertex(m_cubeVertices( 0), -1.0!,  1.0!, -1.0!,  0.0!,  0.0!)
      FillVertex(m_cubeVertices( 1),  1.0!,  1.0!, -1.0!,  1.0!,  0.0!)
      FillVertex(m_cubeVertices( 2), -1.0!, -1.0!, -1.0!,  0.0!,  1.0!)
      FillVertex(m_cubeVertices( 3),  1.0!, -1.0!, -1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices( 4), -1.0!,  1.0!,  1.0!,  1.0!,  0.0!)
      FillVertex(m_cubeVertices( 5), -1.0!, -1.0!,  1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices( 6),  1.0!,  1.0!,  1.0!,  0.0!,  0.0!)
      FillVertex(m_cubeVertices( 7),  1.0!, -1.0!,  1.0!,  0.0!,  1.0!)
      FillVertex(m_cubeVertices( 8), -1.0!,  1.0!,  1.0!,  0.0!,  0.0!)
      FillVertex(m_cubeVertices( 9),  1.0!,  1.0!,  1.0!,  1.0!,  0.0!)
      FillVertex(m_cubeVertices(10), -1.0!,  1.0!, -1.0!,  0.0!,  1.0!)
      FillVertex(m_cubeVertices(11),  1.0!,  1.0!, -1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices(12), -1.0!, -1.0!,  1.0!,  0.0!,  0.0!)
      FillVertex(m_cubeVertices(13), -1.0!, -1.0!, -1.0!,  1.0!,  0.0!)
      FillVertex(m_cubeVertices(14),  1.0!, -1.0!,  1.0!,  0.0!,  1.0!)
      FillVertex(m_cubeVertices(15),  1.0!, -1.0!, -1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices(16),  1.0!,  1.0!, -1.0!,  0.0!,  0.0!)
      FillVertex(m_cubeVertices(17),  1.0!,  1.0!,  1.0!,  1.0!,  0.0!)
      FillVertex(m_cubeVertices(18),  1.0!, -1.0!, -1.0!,  0.0!,  1.0!)
      FillVertex(m_cubeVertices(19),  1.0!, -1.0!,  1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices(20), -1.0!,  1.0!, -1.0!,  1.0!,  0.0!)
      FillVertex(m_cubeVertices(21), -1.0!, -1.0!, -1.0!,  1.0!,  1.0!)
      FillVertex(m_cubeVertices(22), -1.0!,  1.0!,  1.0!,  0.0!,  0.0!)
      FillVertex(m_cubeVertices(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\Vertex_Data.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_cubeVertices) - LBOUND(m_cubeVertices) + 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_cubeVertices(0)), nSize
      m_pVertexBuffer.Unlock

      ' // 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)

      ' // 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

      ' // 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
   ' =====================================================================================

   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
         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
' ========================================================================================

Title: DX9: View Ports
Post by: José Roca on August 28, 2011, 05:54:05 PM
 
The following example demonstrates how to set multiple view ports using DirectX 9.0.


' ########################################################################################
' Microsoft Windows
' File: CW_DX9_ViewPorts.bas
' Contents: DX9 example
' Description: Demonstrates how to set multiple view ports with DirectX 9.0.
' 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_view_ports.cpp by Kevin Harris, 06/02/05, available at
' http://www.codesampler.com/dx9src/dx9src_1.htm#dx9_view_ports
' Control Keys: Left Mouse Button - Spin the teapot
' ########################################################################################

' 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) - Setting Multiple View Ports"

%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

' ========================================================================================
' 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_pTeapotMesh AS ID3DXMesh
   INSTANCE m_teapotMtrl AS D3DMATERIAL9
   INSTANCE m_pLight0 AS D3DLIGHT9
   INSTANCE m_dwBackBufferWidth AS DWORD
   INSTANCE m_dwBackBufferHeight AS DWORD
   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

      ' // 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)

      ' // Se5ts the render states
      m_pD3DDevice.SetRenderState(%D3DRS_ZENABLE, %TRUE)
      m_pD3DDevice.SetRenderState(%D3DRS_LIGHTING, %TRUE)
      m_pD3DDevice.SetRenderState(%D3DRS_SPECULARENABLE, %TRUE)
      m_pD3DDevice.SetRenderState(%D3DRS_CULLMODE, %FALSE)

      ' // Setup a simple directional light and some ambient...
      LOCAL v AS D3DVECTOR
      v.x = 1.0! : v.y = 0.0! : v.x = 1.0!
      m_pLight0.Type = %D3DLIGHT_DIRECTIONAL
      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)

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

      ' // Setup a material for the teapot
      m_teapotMtrl.Diffuse.r = 1.0!
      m_teapotMtrl.Diffuse.g = 1.0!
      m_teapotMtrl.Diffuse.b = 1.0!
      m_teapotMtrl.Diffuse.a = 1.0!

      ' // Load up the teapot mesh...
      D3DXLoadMeshFromX(".\Resources\teapot.x", %D3DXMESH_SYSTEMMEM, m_pD3DDevice, _
                        BYVAL %NULL, BYVAL %NULL, BYVAL %NULL, BYVAL %NULL, m_pTeapotMesh)

      ' // Cache the width & height of the back-buffer...
      LOCAL pBackBuffer AS IDirect3DSurface9
      LOCAL d3dsd AS D3DSURFACE_DESC
      m_pD3DDevice.GetBackBuffer(0, 0, %D3DBACKBUFFER_TYPE_MONO, pBackBuffer)
      pBackBuffer.GetDesc(d3dsd)
      pBackBuffer = NOTHING
      m_dwBackBufferWidth  = d3dsd.Width
      m_dwBackBufferHeight = d3dsd.Height

      ' // Return success
      METHOD = %S_OK

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

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

      LOCAL  hr AS LONG
      LOCAL matView AS D3DXMATRIX
      LOCAL matWorld AS D3DXMATRIX
      LOCAL matRotation AS D3DXMATRIX
      LOCAL matTranslation AS D3DXMATRIX

      ' // Render to the left viewport
      LOCAL leftViewPort AS D3DVIEWPORT9

      leftViewPort.X      = 0
      leftViewPort.Y      = 0
      leftViewPort.Width  = m_dwBackBufferWidth \ 2
      leftViewPort.Height = m_dwBackBufferHeight
      leftViewPort.MinZ   = 0.0!
      leftViewPort.MaxZ   = 1.0!

      m_pD3DDevice.SetViewport(leftViewPort)

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

      ' // Begin the scene
      m_pD3DDevice.BeginScene

      ' // For the left view-port, leave the view at the origin...
      D3DXMatrixIdentity(matView )
      m_pD3DDevice.SetTransform(%D3DTS_VIEW, matView)

      ' // ... and use the world matrix to spin and translate the teapot
      ' // out where we can see it...
      D3DXMatrixRotationYawPitchRoll(matRotation, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)
      D3DXMatrixTranslation(matTranslation, 0.0!, 0.0!, 5.0!)
      D3DXMatrixMultiply(matWorld, matRotation, matTranslation)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

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

      ' // Ends the scene
      m_pD3DDevice.EndScene

      ' // Render to the right viewport
      LOCAL rightViewPort AS D3DVIEWPORT9

      rightViewPort.X      = m_dwBackBufferWidth \ 2
      rightViewPort.Y      = 0
      rightViewPort.Width  = m_dwBackBufferWidth \ 2
      rightViewPort.Height = m_dwBackBufferHeight
      rightViewPort.MinZ   = 0.0!
      rightViewPort.MaxZ   = 1.0!

      m_pD3DDevice.SetViewport(rightViewPort)

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

      ' // Begin the scene
      m_pD3DDevice.BeginScene

      ' // For the right view-port, translate and rotate the view around
      ' // the teapot so we can see it...
      D3DXMatrixRotationYawPitchRoll(matRotation, D3DXToRadian(m_fSpinX), D3DXToRadian(m_fSpinY), 0.0!)
      D3DXMatrixTranslation(matTranslation, 0.0!, 0.0!, 5.0!)
      D3DXMatrixMultiply(matView, matRotation, matTranslation)
      m_pD3DDevice.SetTransform(%D3DTS_VIEW, matView)

      ' // ... and don't bother with the world matrix at all.
      D3DXMatrixIdentity(matWorld)
      m_pD3DDevice.SetTransform(%D3DTS_WORLD, matWorld)

      m_pD3DDevice.SetMaterial(m_teapotMtrl)
      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 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
         SELECT CASE LO(WORD, wParam)
            CASE %VK_ESCAPE
               SendMessage hwnd, %WM_CLOSE, 0, 0
               EXIT FUNCTION
         END SELECT

      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
' ========================================================================================