home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / DirectX8 / dx8a_sdk.exe / samples / multimedia / direct3d / dxtex / dxtexview.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-22  |  29.1 KB  |  1,055 lines

  1. // dxtexView.cpp : implementation of the CDxtexView class
  2. //
  3.  
  4. #include "stdafx.h"
  5. #include "dxtex.h"
  6. #include "dxtexDoc.h"
  7. #include "dxtexView.h"
  8.  
  9. #ifdef _DEBUG
  10. #define new DEBUG_NEW
  11. #undef THIS_FILE
  12. static char THIS_FILE[] = __FILE__;
  13. #endif
  14.  
  15. // Our custom vertex type
  16. struct CUSTOMVERTEX
  17. {
  18.     FLOAT x, y, z;
  19.     FLOAT rhw;
  20.     DWORD color;
  21.     FLOAT tu, tv;   // The texture coordinates
  22. };
  23.  
  24. #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
  25.  
  26.  
  27. IMPLEMENT_DYNCREATE(CDxtexView, CScrollView)
  28.  
  29. BEGIN_MESSAGE_MAP(CDxtexView, CScrollView)
  30.     //{{AFX_MSG_MAP(CDxtexView)
  31.     ON_WM_LBUTTONUP()
  32.     ON_COMMAND(ID_FILE_OPENSUBSURFACE, OnFileOpenSubsurface)
  33.     ON_COMMAND(ID_FILE_OPENALPHASUBSURFACE, OnFileOpenAlphaSubsurface)
  34.     ON_COMMAND(ID_FILE_OPENFACE, OnFileOpenFace)
  35.     ON_COMMAND(ID_FILE_OPENALPHAFACE, OnFileOpenAlphaFace)
  36.     ON_COMMAND(ID_VIEW_ORIGINAL, OnViewOriginal)
  37.     ON_COMMAND(ID_VIEW_COMPRESSED, OnViewCompressed)
  38.     ON_COMMAND(ID_VIEW_SMALLERMIPLEVEL, OnViewSmallerMipLevel)
  39.     ON_COMMAND(ID_VIEW_LARGERMIPLEVEL, OnViewLargerMipLevel)
  40.     ON_COMMAND(ID_VIEW_ALPHACHANNEL, OnViewAlphaChannel)
  41.     ON_COMMAND(ID_VIEW_ZOOMIN, OnViewZoomIn)
  42.     ON_COMMAND(ID_VIEW_ZOOMOUT, OnViewZoomOut)
  43.     ON_COMMAND(ID_VIEW_CHANGEBACKGROUNDCOLOR, OnViewChangeBackgroundColor)
  44.     ON_COMMAND(ID_VIEW_NEGX, OnViewNegX)
  45.     ON_COMMAND(ID_VIEW_POSX, OnViewPosX)
  46.     ON_COMMAND(ID_VIEW_NEGY, OnViewNegY)
  47.     ON_COMMAND(ID_VIEW_POSY, OnViewPosY)
  48.     ON_COMMAND(ID_VIEW_NEGZ, OnViewNegZ)
  49.     ON_COMMAND(ID_VIEW_POSZ, OnViewPosZ)
  50.     ON_COMMAND(ID_VIEW_HIGHERVOLUMESLICE, OnViewHigherVolumeSlice)
  51.     ON_COMMAND(ID_VIEW_LOWERVOLUMESLICE, OnViewLowerVolumeSlice)
  52.     ON_UPDATE_COMMAND_UI(ID_FILE_OPENSUBSURFACE, OnUpdateFileOpenSubsurface)
  53.     ON_UPDATE_COMMAND_UI(ID_FILE_OPENALPHASUBSURFACE, OnUpdateFileOpenAlphaSubsurface)
  54.     ON_UPDATE_COMMAND_UI(ID_FILE_OPENFACE, OnUpdateFileOpenFace)
  55.     ON_UPDATE_COMMAND_UI(ID_FILE_OPENALPHAFACE, OnUpdateFileOpenAlphaFace)
  56.     ON_UPDATE_COMMAND_UI(ID_VIEW_ORIGINAL, OnUpdateViewOriginal)
  57.     ON_UPDATE_COMMAND_UI(ID_VIEW_COMPRESSED, OnUpdateViewCompressed)
  58.     ON_UPDATE_COMMAND_UI(ID_VIEW_ALPHACHANNEL, OnUpdateViewAlphaChannel)
  59.     ON_UPDATE_COMMAND_UI(ID_VIEW_LARGERMIPLEVEL, OnUpdateViewLargerMipLevel)
  60.     ON_UPDATE_COMMAND_UI(ID_VIEW_SMALLERMIPLEVEL, OnUpdateViewSmallerMipLevel)
  61.     ON_UPDATE_COMMAND_UI(ID_VIEW_ZOOMIN, OnUpdateViewZoomIn)
  62.     ON_UPDATE_COMMAND_UI(ID_VIEW_ZOOMOUT, OnUpdateViewZoomOut)
  63.     ON_UPDATE_COMMAND_UI(ID_VIEW_NEGX, OnUpdateViewNegX)
  64.     ON_UPDATE_COMMAND_UI(ID_VIEW_POSX, OnUpdateViewPosX)
  65.     ON_UPDATE_COMMAND_UI(ID_VIEW_NEGY, OnUpdateViewNegY)
  66.     ON_UPDATE_COMMAND_UI(ID_VIEW_POSY, OnUpdateViewPosY)
  67.     ON_UPDATE_COMMAND_UI(ID_VIEW_NEGZ, OnUpdateViewNegZ)
  68.     ON_UPDATE_COMMAND_UI(ID_VIEW_POSZ, OnUpdateViewPosZ)
  69.     ON_UPDATE_COMMAND_UI(ID_VIEW_HIGHERVOLUMESLICE, OnUpdateViewHigherVolumeSlice)
  70.     ON_UPDATE_COMMAND_UI(ID_VIEW_LOWERVOLUMESLICE, OnUpdateViewLowerVolumeSlice)
  71.     //}}AFX_MSG_MAP
  72. END_MESSAGE_MAP()
  73.  
  74.  
  75. CDxtexView::CDxtexView()
  76. {
  77.     m_ptexCur = NULL;
  78.     m_pSwapChain = NULL;
  79.     m_lwMipCur = 0;
  80.     m_CubeFaceCur = D3DCUBEMAP_FACE_FORCE_DWORD;
  81.     m_lwSliceCur = -1;
  82.     m_fZoom = 1.0f;
  83.     m_bViewOrig = TRUE;
  84.     m_bViewAlpha = FALSE;
  85. }
  86.  
  87.  
  88. CDxtexView::~CDxtexView()
  89. {
  90.     ReleasePpo(&m_pVB);
  91.     ReleasePpo(&m_ptexCur);
  92.     ReleasePpo(&m_pSwapChain);
  93. }
  94.  
  95.  
  96. // Note: repaints don't require re-rendering, just recopy from back buffer to view's DC
  97. void CDxtexView::OnDraw(CDC* pDC)
  98. {
  99.     CDxtexDoc* pDoc = GetDocument();
  100.     ASSERT_VALID(pDoc);
  101.  
  102.     HRESULT hr;
  103.     CRect rcSrc;
  104.     CRect rcDest;
  105.  
  106.     rcSrc = m_rcSrc;
  107.     rcDest = m_rcDest;
  108.  
  109.     rcDest.OffsetRect(pDC->GetViewportOrg());
  110.  
  111.     // REVIEW: only update dirty region?
  112.     if (m_pSwapChain != NULL)
  113.         hr = m_pSwapChain->Present(&rcSrc, &rcDest, GetSafeHwnd(), NULL);
  114. }
  115.  
  116.  
  117. #ifdef _DEBUG
  118. void CDxtexView::AssertValid() const
  119. {
  120.     CScrollView::AssertValid();
  121. }
  122.  
  123.  
  124. void CDxtexView::Dump(CDumpContext& dc) const
  125. {
  126.     CScrollView::Dump(dc);
  127. }
  128.  
  129.  
  130. CDxtexDoc* CDxtexView::GetDocument() // non-debug version is inline
  131. {
  132.     ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDxtexDoc)));
  133.     return (CDxtexDoc*)m_pDocument;
  134. }
  135. #endif //_DEBUG
  136.  
  137.  
  138. void CDxtexView::OnLButtonUp(UINT nFlags, CPoint point)
  139. {
  140.     // Button click means toggle compressed / uncompressed view
  141.     if (m_bViewOrig)
  142.         OnViewCompressed();
  143.     else
  144.         OnViewOriginal();
  145.  
  146.     CScrollView::OnLButtonUp(nFlags, point);
  147. }
  148.  
  149.  
  150. void CDxtexView::OnInitialUpdate()
  151. {
  152. #ifdef _WIN64
  153.     SetClassLongPtr(GetSafeHwnd(), GCLP_HBRBACKGROUND, (LONG_PTR)CreateSolidBrush(RGB(100, 100, 120)));
  154. #else
  155.     SetClassLong(GetSafeHwnd(), GCL_HBRBACKGROUND, (LONG)CreateSolidBrush(RGB(100, 100, 120)));
  156. #endif
  157.  
  158.     if (GetDocument()->IsCubeMap())
  159.         m_CubeFaceCur = D3DCUBEMAP_FACE_POSITIVE_X;
  160.     else
  161.         m_CubeFaceCur = D3DCUBEMAP_FACE_FORCE_DWORD;
  162.     if (GetDocument()->IsVolumeMap())
  163.         m_lwSliceCur = 0;
  164.     BuildViewSurface(m_bViewOrig, m_CubeFaceCur, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  165.     UpdateDevice();
  166.     CreateVertexBuffer();
  167.     RenderScene();
  168.  
  169.     SetScrollSizes(MM_TEXT, CSize(m_rcDest.Width(), m_rcDest.Height()));
  170.     ResizeParentToFit();
  171.  
  172.     CScrollView::OnInitialUpdate();
  173.  
  174.     m_bTitleModsChanged = TRUE; // force title bar update
  175. }
  176.  
  177.  
  178. VOID CDxtexView::GetImageInfo(CString& strInfo)
  179. {
  180.     LPDIRECT3DBASETEXTURE8 ptex;
  181.     D3DSURFACE_DESC sd;
  182.     D3DVOLUME_DESC vd;
  183.     D3DFORMAT fmt;
  184.     DWORD dwWidth;
  185.     DWORD dwHeight;
  186.     DWORD dwDepth;
  187.     CString strFormat;
  188.     TCHAR sz[100];
  189.     DWORD dwBytes = 0;
  190.     UINT iLevel;
  191.  
  192.     if (m_bViewOrig)
  193.         ptex = GetDocument()->PtexOrig();
  194.     else
  195.         ptex = GetDocument()->PtexNew();
  196.  
  197.     if (GetDocument()->IsVolumeMap())
  198.     {
  199.         ((LPDIRECT3DVOLUMETEXTURE8)ptex)->GetLevelDesc(0, &vd);
  200.         fmt = vd.Format;
  201.         dwWidth = vd.Width;
  202.         dwHeight = vd.Height;
  203.         dwDepth = vd.Depth;
  204.     }
  205.     else if (!GetDocument()->IsCubeMap())
  206.     {
  207.         ((LPDIRECT3DTEXTURE8)ptex)->GetLevelDesc(0, &sd);
  208.         fmt = sd.Format;
  209.         dwWidth = sd.Width;
  210.         dwHeight = sd.Height;
  211.         dwDepth = 0;
  212.     }
  213.     else
  214.     {
  215.         ((LPDIRECT3DCUBETEXTURE8)ptex)->GetLevelDesc(0, &sd);
  216.         fmt = sd.Format;
  217.         dwWidth = sd.Width;
  218.         dwHeight = sd.Height;
  219.         dwDepth = 0;
  220.     }
  221.  
  222.     strFormat = FormatName(fmt);
  223.  
  224.     // Count bytes in main surface chain
  225.     if (GetDocument()->IsVolumeMap())
  226.     {
  227.         for (iLevel = 0; iLevel < GetDocument()->NumMips(); iLevel++)
  228.         {
  229.             ((LPDIRECT3DVOLUMETEXTURE8)ptex)->GetLevelDesc(iLevel, &vd);
  230.             dwBytes += vd.Size;
  231.         }
  232.     }
  233.     else if (!GetDocument()->IsCubeMap())
  234.     {
  235.         dwBytes += NumBytesInSurfaces(D3DCUBEMAP_FACE_FORCE_DWORD, ptex);
  236.     }
  237.     else
  238.     {
  239.         dwBytes += NumBytesInSurfaces(D3DCUBEMAP_FACE_POSITIVE_X, ptex);
  240.         dwBytes += NumBytesInSurfaces(D3DCUBEMAP_FACE_NEGATIVE_X, ptex);
  241.         dwBytes += NumBytesInSurfaces(D3DCUBEMAP_FACE_POSITIVE_Y, ptex);
  242.         dwBytes += NumBytesInSurfaces(D3DCUBEMAP_FACE_NEGATIVE_Y, ptex);
  243.         dwBytes += NumBytesInSurfaces(D3DCUBEMAP_FACE_POSITIVE_Z, ptex);
  244.         dwBytes += NumBytesInSurfaces(D3DCUBEMAP_FACE_NEGATIVE_Z, ptex);
  245.     }
  246.  
  247.     if (dwDepth == 0)
  248.         wsprintf(sz, "%d x %d, %s, %d bytes", dwWidth, dwHeight, strFormat, dwBytes);
  249.     else
  250.         wsprintf(sz, "%d x %d x %d, %s, %d bytes", dwWidth, dwHeight, dwDepth, strFormat, dwBytes);
  251.     strInfo = sz;
  252. }
  253.  
  254.  
  255. DWORD CDxtexView::NumBytesInSurfaces(D3DCUBEMAP_FACES FaceType, LPDIRECT3DBASETEXTURE8 ptex)
  256. {
  257.     DWORD dwBytes = 0;
  258.     LPDIRECT3DTEXTURE8 pmiptex = NULL;
  259.     LPDIRECT3DCUBETEXTURE8 pcubetex = NULL;
  260.     D3DSURFACE_DESC sd;
  261.     DWORD iLevel;
  262.  
  263.     if (FaceType == D3DCUBEMAP_FACE_FORCE_DWORD)
  264.         pmiptex = (LPDIRECT3DTEXTURE8)ptex;
  265.     else
  266.         pcubetex = (LPDIRECT3DCUBETEXTURE8)ptex;
  267.  
  268.     for (iLevel = 0; iLevel < GetDocument()->NumMips(); iLevel++)
  269.     {
  270.         if (pmiptex != NULL)
  271.             pmiptex->GetLevelDesc(iLevel, &sd);
  272.         else
  273.             pcubetex->GetLevelDesc(iLevel, &sd);
  274.         dwBytes += sd.Size;
  275.     }
  276.  
  277.     return dwBytes;
  278. }
  279.  
  280.  
  281. HRESULT CDxtexView::UpdateDevice(VOID)
  282. {
  283.     HRESULT hr;
  284.     LPDIRECT3D8 pd3d = PDxtexApp()->Pd3d();
  285.     LPDIRECT3DDEVICE8 pd3ddev = PDxtexApp()->Pd3ddev();
  286.     D3DDISPLAYMODE dispMode;
  287.     D3DPRESENT_PARAMETERS presentParams;
  288.  
  289.     pd3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dispMode);
  290.  
  291.     ReleasePpo(&m_pSwapChain);
  292.     ZeroMemory(&presentParams, sizeof(presentParams));
  293.     presentParams.Windowed = TRUE;
  294.     presentParams.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC;
  295.     presentParams.BackBufferWidth = m_rcSrc.Width();
  296.     presentParams.BackBufferHeight = m_rcSrc.Height();
  297.     presentParams.BackBufferFormat = dispMode.Format;
  298.  
  299.     if (FAILED(hr = pd3ddev->CreateAdditionalSwapChain(&presentParams, &m_pSwapChain)))
  300.         return hr;
  301.  
  302.     COLORREF crBkgd;
  303.     crBkgd = PDxtexApp()->GetProfileInt("Settings", "Background Color", RGB(0, 255, 255));
  304.     m_dwClearColor = D3DCOLOR_RGBA(GetRValue(crBkgd), GetGValue(crBkgd), GetBValue(crBkgd), 255);
  305.  
  306.     return S_OK;
  307. }
  308.  
  309.  
  310. HRESULT CDxtexView::CreateVertexBuffer(VOID)
  311. {
  312.     LPDIRECT3DDEVICE8 pd3ddev = PDxtexApp()->Pd3ddev();
  313.  
  314.     // Create the the vertex buffer
  315.     if( FAILED( pd3ddev->CreateVertexBuffer( 6 * sizeof(CUSTOMVERTEX),
  316.         0 /* Usage */, D3DFVF_CUSTOMVERTEX, 
  317.         D3DPOOL_DEFAULT, &m_pVB ) ) )
  318.     {
  319.         return E_FAIL;
  320.     }
  321.  
  322.     return S_OK;
  323. }
  324.  
  325.  
  326. HRESULT CDxtexView::RenderScene(VOID)
  327. {
  328.     CWaitCursor waitCursor;
  329.     HRESULT hr;
  330.     LPDIRECT3DDEVICE8 pd3ddev = PDxtexApp()->Pd3ddev();
  331.  
  332.     LPDIRECT3DSURFACE8 psurf;
  333.  
  334.     if (m_pSwapChain == NULL)
  335.         return E_FAIL;
  336.  
  337.     // Vertices for our quad
  338.     CUSTOMVERTEX vertexArray[] =
  339.     {
  340.         // x, y, z, rhw, color
  341.         { 0.0f,                                 0.0f,                              0.5f, 1.0f, 0xffffffff, 0.0, 0.0, },
  342.         { (FLOAT)m_rcSrc.right, 0.0f,                              0.5f, 1.0f, 0xffffffff, 1.0, 0.0, },
  343.         { (FLOAT)m_rcSrc.right, (FLOAT)m_rcSrc.bottom, 0.5f, 1.0f, 0xffffffff, 1.0, 1.0, },
  344.  
  345.         { (FLOAT)m_rcSrc.right, (FLOAT)m_rcSrc.bottom, 0.5f, 1.0f, 0xffffffff, 1.0, 1.0, },
  346.         { 0.0f,                                 (FLOAT)m_rcSrc.bottom, 0.5f, 1.0f, 0xffffffff, 0.0, 1.0, },
  347.         { 0.0f,                                 0.0f,                              0.5f, 1.0f, 0xffffffff, 0.0, 0.0, },
  348.     };
  349.  
  350.     // Copy the global vertex data into the vertex buffer
  351.     VOID* pVertices;
  352.     if( FAILED( m_pVB->Lock( 0, sizeof(vertexArray), (BYTE**)&pVertices, 0 ) ) )
  353.         return E_FAIL;
  354.     memcpy( pVertices, vertexArray, sizeof(vertexArray) );
  355.     m_pVB->Unlock();
  356.  
  357.     hr = m_pSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &psurf);
  358.  
  359.     hr = pd3ddev->SetRenderTarget(psurf, NULL);
  360.  
  361.     ReleasePpo(&psurf);
  362.  
  363.     hr = pd3ddev->Clear(0, NULL, D3DCLEAR_TARGET, m_dwClearColor, 0.0f, 0);
  364.  
  365.     hr = pd3ddev->BeginScene();
  366.  
  367.     // If the texture uses premultiplied alpha, the source blend should be D3DBLEND_ONE
  368.     // since RGB is already at the level we want.  With nonpremultiplied alpha, the
  369.     // source blend should be D3DBLEND_SRCALPHA.
  370.     D3DSURFACE_DESC sd;
  371.     m_ptexCur->GetLevelDesc(0, &sd);
  372.     if (!m_bViewAlpha && (sd.Format == D3DFMT_DXT2 || sd.Format == D3DFMT_DXT4))
  373.     {
  374.         if (FAILED(hr = pd3ddev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE)))
  375.             return hr;
  376.     }
  377.     else
  378.     {
  379.         if (FAILED(hr = pd3ddev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA)))
  380.             return hr;
  381.     }
  382.     hr = pd3ddev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  383.     hr = pd3ddev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
  384.  
  385.     pd3ddev->SetTexture(0, m_ptexCur);
  386.     pd3ddev->SetStreamSource( 0, m_pVB, sizeof(CUSTOMVERTEX) );
  387.     pd3ddev->SetVertexShader( D3DFVF_CUSTOMVERTEX );
  388.     pd3ddev->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );
  389.     pd3ddev->SetTexture(0, NULL);
  390.  
  391.     hr = pd3ddev->EndScene();
  392.  
  393.     return S_OK;
  394. }
  395.  
  396.  
  397. void CDxtexView::OnViewOriginal()
  398. {
  399.     if (GetDocument()->PtexOrig() == NULL)
  400.         return;
  401.     BuildViewSurface(TRUE, m_CubeFaceCur, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  402.     RenderScene();
  403.     m_bTitleModsChanged = TRUE; // force title bar update
  404.     InvalidateRect(&m_rcDest, FALSE); // force redraw of this view
  405. }
  406.  
  407.  
  408. void CDxtexView::OnViewCompressed()
  409. {
  410.     if (GetDocument()->PtexNew() == NULL)
  411.         return;
  412.     BuildViewSurface(FALSE, m_CubeFaceCur, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  413.     RenderScene();
  414.     m_bTitleModsChanged = TRUE; // force title bar update
  415.     InvalidateRect(&m_rcDest, FALSE); // force redraw of this view
  416. }
  417.  
  418.  
  419. void CDxtexView::OnUpdateViewOriginal(CCmdUI* pCmdUI)
  420. {
  421.     if (GetDocument()->PtexOrig() == NULL)
  422.     {
  423.         pCmdUI->Enable(FALSE);
  424.         pCmdUI->SetCheck(0);
  425.     }
  426.     else
  427.     {
  428.         pCmdUI->Enable(TRUE);
  429.         pCmdUI->SetCheck(m_bViewOrig);
  430.     }
  431. }
  432.  
  433.  
  434. void CDxtexView::OnUpdateViewCompressed(CCmdUI* pCmdUI)
  435. {
  436.     if (GetDocument()->PtexNew() == NULL)
  437.     {
  438.         pCmdUI->Enable(FALSE);
  439.         pCmdUI->SetCheck(0);
  440.     }
  441.     else
  442.     {
  443.         pCmdUI->Enable(TRUE);
  444.         pCmdUI->SetCheck(!m_bViewOrig);
  445.     }
  446. }
  447.  
  448.  
  449. void CDxtexView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
  450. {
  451.     m_bTitleModsChanged = TRUE; // force title bar update
  452.     if (lHint == 1)
  453.     {
  454.         BuildViewSurface(m_bViewOrig, m_CubeFaceCur, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  455.         RenderScene();
  456.     }
  457.     else if (lHint == 2)
  458.     {
  459.         UpdateDevice();
  460.         RenderScene();
  461.     }
  462.     else if (lHint == 3)
  463.     {
  464.         RenderScene();
  465.     }
  466.  
  467.     CScrollView::OnUpdate(pSender, lHint, pHint);
  468. }
  469.  
  470.  
  471. void CDxtexView::OnViewSmallerMipLevel()
  472. {
  473.     m_lwMipCur++;
  474.     if (m_lwSliceCur > 0)
  475.         m_lwSliceCur /= 2;
  476.     BuildViewSurface(m_bViewOrig, m_CubeFaceCur, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  477.     UpdateDevice();
  478.     RenderScene();
  479.     m_bTitleModsChanged = TRUE; // force title bar update
  480.     SetScrollSizes(MM_TEXT, CSize(m_rcDest.Width(), m_rcDest.Height()));
  481.     Invalidate(); // force redraw of this view
  482. }
  483.  
  484.  
  485. void CDxtexView::OnViewLargerMipLevel()
  486. {
  487.     m_lwMipCur--;
  488.     if (m_lwSliceCur > 0)
  489.         m_lwSliceCur *= 2;
  490.     BuildViewSurface(m_bViewOrig, m_CubeFaceCur, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  491.     UpdateDevice();
  492.     RenderScene();
  493.     m_bTitleModsChanged = TRUE; // force title bar update
  494.     SetScrollSizes(MM_TEXT, CSize(m_rcDest.Width(), m_rcDest.Height()));
  495.     Invalidate(); // force redraw of this view
  496. }
  497.  
  498.  
  499. void CDxtexView::OnViewAlphaChannel(VOID)
  500. {
  501.     BuildViewSurface(m_bViewOrig, m_CubeFaceCur, m_lwSliceCur, m_lwMipCur, !m_bViewAlpha);
  502.     RenderScene();
  503.     Invalidate(); // force redraw of this view
  504.     m_bTitleModsChanged = TRUE; // force title bar update
  505. }
  506.  
  507.  
  508. void CDxtexView::OnUpdateViewAlphaChannel(CCmdUI* pCmdUI)
  509. {
  510.     pCmdUI->SetCheck(m_bViewAlpha);
  511. }
  512.  
  513.  
  514. void CDxtexView::OnUpdateViewLargerMipLevel(CCmdUI* pCmdUI)
  515. {
  516.     if (m_lwMipCur > 0)
  517.         pCmdUI->Enable(TRUE);
  518.     else
  519.         pCmdUI->Enable(FALSE);
  520. }
  521.  
  522.  
  523. void CDxtexView::OnUpdateViewSmallerMipLevel(CCmdUI* pCmdUI)
  524. {
  525.     if (m_lwMipCur < (LONG)GetDocument()->NumMips() - 1)
  526.         pCmdUI->Enable(TRUE);
  527.     else
  528.         pCmdUI->Enable(FALSE);
  529. }
  530.  
  531.  
  532. void CDxtexView::OnViewZoomIn()
  533. {
  534.     if (m_fZoom < 8.0f)
  535.         m_fZoom *= 2.0f;
  536.     m_rcDest.right = (LONG)(m_rcSrc.right * m_fZoom);
  537.     m_rcDest.bottom = (LONG)(m_rcSrc.bottom * m_fZoom);
  538.     SetScrollSizes(MM_TEXT, CSize(m_rcDest.Width(), m_rcDest.Height()));
  539.     m_bTitleModsChanged = TRUE; // force title bar update
  540.     Invalidate(); // force redraw of this view
  541. }
  542.  
  543.  
  544. void CDxtexView::OnViewZoomOut()
  545. {
  546.     if (m_fZoom > 0.125f)
  547.         m_fZoom /= 2.0f;
  548.     m_rcDest.right = (LONG)(m_rcSrc.right * m_fZoom);
  549.     m_rcDest.bottom = (LONG)(m_rcSrc.bottom * m_fZoom);
  550.     SetScrollSizes(MM_TEXT, CSize(m_rcDest.Width(), m_rcDest.Height()));
  551.     m_bTitleModsChanged = TRUE; // force title bar update
  552.     Invalidate(); // force redraw of this view
  553. }
  554.  
  555.  
  556. void CDxtexView::OnUpdateViewZoomIn(CCmdUI* pCmdUI)
  557. {
  558.     pCmdUI->Enable(m_fZoom < 8.0f);
  559. }
  560.  
  561.  
  562. void CDxtexView::OnUpdateViewZoomOut(CCmdUI* pCmdUI)
  563. {
  564.     pCmdUI->Enable(m_fZoom > 0.125f);
  565. }
  566.  
  567.  
  568. CString CDxtexView::GetStrTitleMods(VOID)
  569. {
  570.     CString strTitleMods;
  571.     strTitleMods = "(";
  572.  
  573.     // Append alpha, if in alpha mode
  574.     if (m_bViewAlpha)
  575.             strTitleMods += "Alpha, ";
  576.  
  577.     // Show format
  578.     LPDIRECT3DBASETEXTURE8 ptex;
  579.     CString strFormat;
  580.     D3DFORMAT fmt;
  581.  
  582.     if (m_bViewOrig)
  583.         ptex = GetDocument()->PtexOrig();
  584.     else
  585.         ptex = GetDocument()->PtexNew();
  586.  
  587.     if (GetDocument()->IsVolumeMap())
  588.     {
  589.         D3DVOLUME_DESC vd;
  590.         ((LPDIRECT3DVOLUMETEXTURE8)ptex)->GetLevelDesc(0, &vd);
  591.         fmt = vd.Format;
  592.     }
  593.     else if (!GetDocument()->IsCubeMap())
  594.     {
  595.         D3DSURFACE_DESC sd;
  596.         ((LPDIRECT3DTEXTURE8)ptex)->GetLevelDesc(0, &sd);
  597.         fmt = sd.Format;
  598.     }
  599.     else
  600.     {
  601.         D3DSURFACE_DESC sd;
  602.         ((LPDIRECT3DCUBETEXTURE8)ptex)->GetLevelDesc(0, &sd);
  603.         fmt = sd.Format;
  604.     }
  605.  
  606.     strTitleMods += FormatName(fmt);
  607.     strTitleMods += TEXT(", ");
  608.  
  609.     // Append cube map info, if a cube map
  610.     switch (m_CubeFaceCur)
  611.     {
  612.     case D3DCUBEMAP_FACE_NEGATIVE_X:
  613.         strTitleMods += "Negative X, ";
  614.         break;
  615.     case D3DCUBEMAP_FACE_POSITIVE_X:
  616.         strTitleMods += "Positive X, ";
  617.         break;
  618.     case D3DCUBEMAP_FACE_NEGATIVE_Y:
  619.         strTitleMods += "Negative Y, ";
  620.         break;
  621.     case D3DCUBEMAP_FACE_POSITIVE_Y:
  622.         strTitleMods += "Positive Y, ";
  623.         break;
  624.     case D3DCUBEMAP_FACE_NEGATIVE_Z:
  625.         strTitleMods += "Negative Z, ";
  626.         break;
  627.     case D3DCUBEMAP_FACE_POSITIVE_Z:
  628.         strTitleMods += "Positive Z, ";
  629.         break;
  630.     }
  631.  
  632.     if (m_lwSliceCur >= 0)
  633.     {
  634.         CString strSlice;
  635.         strSlice.Format("Slice %d of %d, ", m_lwSliceCur + 1, GetDocument()->DwDepthAt(m_lwMipCur));
  636.         strTitleMods += strSlice;
  637.     }
  638.  
  639.     // Append mip info, if multiple mip levels
  640.     DWORD dwNumMips = GetDocument()->NumMips();
  641.     if (dwNumMips > 1)
  642.     {
  643.         CString strMipInfo;
  644.         strMipInfo.Format("Mip %d of %d, ", m_lwMipCur + 1, dwNumMips);
  645.         strTitleMods += strMipInfo;
  646.     }
  647.  
  648.     // Append view magnification
  649.     CString strView;
  650.     strView.Format("%d", (LONG)(100 * m_fZoom));
  651.     strTitleMods += strView + "%";
  652.  
  653.     strTitleMods += ")";
  654.     return strTitleMods;
  655. }
  656.  
  657.  
  658. CString CDxtexView::FormatName(D3DFORMAT fmt)
  659. {
  660.     CString str;
  661.     switch (fmt)
  662.     {
  663.     case D3DFMT_A8R8G8B8:
  664.         str = TEXT("A8R8G8B8");
  665.         break;
  666.     case D3DFMT_A1R5G5B5:
  667.         str = TEXT("A1R5G5B5");
  668.         break;
  669.     case D3DFMT_A4R4G4B4:
  670.         str = TEXT("A4R4G4B4");
  671.         break;
  672.     case D3DFMT_R8G8B8:
  673.         str = TEXT("R8G8B8");
  674.         break;
  675.     case D3DFMT_R5G6B5:
  676.         str = TEXT("R5G6B5");
  677.         break;
  678.     case D3DFMT_DXT1:
  679.         str = TEXT("DXT1");
  680.         break;
  681.     case D3DFMT_DXT2:
  682.         str = TEXT("DXT2");
  683.         break;
  684.     case D3DFMT_DXT3:
  685.         str = TEXT("DXT3");
  686.         break;
  687.     case D3DFMT_DXT4:
  688.         str = TEXT("DXT4");
  689.         break;
  690.     case D3DFMT_DXT5:
  691.         str = TEXT("DXT5");
  692.         break;
  693.     default:
  694.         str = TEXT("unknown fmt");
  695.         break;
  696.     }
  697.     return str;
  698. }
  699.  
  700. void CDxtexView::OnViewChangeBackgroundColor()
  701. {
  702.     CHOOSECOLOR cc;
  703.     COLORREF crArray[16];
  704.  
  705.     ZeroMemory(&cc, sizeof(cc));
  706.     cc.lStructSize = sizeof(cc);
  707.     cc.hwndOwner = GetSafeHwnd();
  708.     cc.rgbResult = PDxtexApp()->GetProfileInt("Settings", "Background Color", RGB(0, 255, 255));
  709.     cc.lpCustColors = crArray;
  710.     cc.Flags = CC_RGBINIT | CC_ANYCOLOR | CC_FULLOPEN;
  711.  
  712.     if (ChooseColor(&cc))
  713.     {
  714.         PDxtexApp()->WriteProfileInt("Settings", "Background Color", cc.rgbResult);
  715.  
  716.         // Update all views of all documents of our one doc template
  717.         POSITION posTemp = PDxtexApp()->GetFirstDocTemplatePosition();
  718.         CDocTemplate* pDocTemplate = PDxtexApp()->GetNextDocTemplate(posTemp);
  719.         CDocument* pdoc;
  720.         POSITION pos = pDocTemplate->GetFirstDocPosition();
  721.         while (pos != NULL)
  722.         {
  723.             pdoc = pDocTemplate->GetNextDoc(pos);
  724.             pdoc->UpdateAllViews(NULL, 2);
  725.         }
  726.     }
  727. }
  728.  
  729.  
  730. void CDxtexView::OnFileOpenSubsurface()
  731. {
  732.     GetDocument()->OpenSubsurface(m_CubeFaceCur, m_lwMipCur, m_lwSliceCur);
  733. }
  734.  
  735.  
  736. void CDxtexView::OnUpdateFileOpenSubsurface(CCmdUI* pCmdUI)
  737. {
  738.     pCmdUI->Enable(TRUE);
  739. }
  740.  
  741.  
  742. void CDxtexView::OnFileOpenAlphaSubsurface()
  743. {
  744.     GetDocument()->OpenAlphaSubsurface(m_CubeFaceCur, m_lwMipCur, m_lwSliceCur);
  745. }
  746.  
  747.  
  748. void CDxtexView::OnUpdateFileOpenAlphaSubsurface(CCmdUI* pCmdUI)
  749. {
  750.     pCmdUI->Enable(TRUE);
  751. }
  752.  
  753.  
  754. HRESULT CDxtexView::BuildViewSurface(BOOL bOrig, D3DCUBEMAP_FACES FaceType, LONG lwSlice, LONG lwMip, BOOL bViewAlpha)
  755. {
  756.     HRESULT hr;
  757.     LPDIRECT3DDEVICE8 pd3ddev = PDxtexApp()->Pd3ddev();
  758.     LPDIRECT3DBASETEXTURE8 ptex;
  759.     BOOL bIsCubeMap = GetDocument()->IsCubeMap();
  760.     BOOL bIsVolumeMap = GetDocument()->IsVolumeMap();
  761.     D3DSURFACE_DESC sd;
  762.     D3DVOLUME_DESC vd;
  763.  
  764.     ReleasePpo(&m_ptexCur);
  765.  
  766.     if (bIsVolumeMap && lwSlice == -1)
  767.         lwSlice = 0;
  768.  
  769.     if (bIsCubeMap && FaceType == D3DCUBEMAP_FACE_FORCE_DWORD)
  770.         FaceType = D3DCUBEMAP_FACE_POSITIVE_X;
  771.  
  772.     m_bViewOrig = bOrig;
  773.     m_bViewAlpha = bViewAlpha;
  774.     m_lwSliceCur = lwSlice;
  775.     m_lwMipCur = lwMip;
  776.     m_CubeFaceCur = FaceType;
  777.  
  778.     if (bOrig)
  779.         ptex = GetDocument()->PtexOrig();
  780.     else
  781.         ptex = GetDocument()->PtexNew();
  782.  
  783.     if (bIsVolumeMap)
  784.     {
  785.         ((LPDIRECT3DVOLUMETEXTURE8)ptex)->GetLevelDesc(m_lwMipCur, &vd);
  786.         sd.Width = vd.Width;
  787.         sd.Height = vd.Height;
  788.     }
  789.     else if (!bIsCubeMap)
  790.     {
  791.         ((LPDIRECT3DTEXTURE8)ptex)->GetLevelDesc(m_lwMipCur, &sd);
  792.     }
  793.     else
  794.     {
  795.         ((LPDIRECT3DCUBETEXTURE8)ptex)->GetLevelDesc(m_lwMipCur, &sd);
  796.     }
  797.  
  798.     hr = pd3ddev->CreateTexture(sd.Width, sd.Height, 1,
  799.          0 /* Usage */, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_ptexCur);
  800.     if (FAILED(hr))
  801.         return hr;
  802.  
  803.     m_rcSrc.SetRect(0, 0, sd.Width, sd.Height);
  804.     m_rcDest.SetRect(0, 0, (INT)(sd.Width * m_fZoom), (INT)(sd.Height * m_fZoom));
  805.  
  806.     LPDIRECT3DSURFACE8 psurfSrc = NULL;
  807.     LPDIRECT3DSURFACE8 psurfDest = NULL;
  808.  
  809.     hr = m_ptexCur->GetSurfaceLevel(0, &psurfDest);
  810.  
  811.     if (bIsVolumeMap)
  812.     {
  813.         LPDIRECT3DVOLUME8 pvolSrc;
  814.         hr = ((LPDIRECT3DVOLUMETEXTURE8)ptex)->GetVolumeLevel(m_lwMipCur, &pvolSrc);
  815.         hr = LoadSurfaceFromVolumeSlice(pvolSrc, m_lwSliceCur, psurfDest);
  816.         ReleasePpo(&pvolSrc);
  817.     }
  818.     else if (!bIsCubeMap)
  819.     {
  820.         hr = ((LPDIRECT3DTEXTURE8)ptex)->GetSurfaceLevel(m_lwMipCur, &psurfSrc);
  821.         hr = D3DXLoadSurfaceFromSurface(psurfDest, NULL, NULL, psurfSrc, NULL, NULL,
  822.             D3DX_FILTER_TRIANGLE, 0);
  823.     }
  824.     else
  825.     {
  826.         hr = ((LPDIRECT3DCUBETEXTURE8)ptex)->GetCubeMapSurface(FaceType, m_lwMipCur, &psurfSrc);
  827.         hr = D3DXLoadSurfaceFromSurface(psurfDest, NULL, NULL, psurfSrc, NULL, NULL,
  828.             D3DX_FILTER_TRIANGLE, 0);
  829.     }
  830.  
  831.  
  832.     if (bViewAlpha)
  833.     {
  834.         // Move alpha channels into RGB (and set alpha to 0xff)
  835.         D3DLOCKED_RECT lr;
  836.  
  837.         hr = psurfDest->LockRect(&lr, NULL, 0);
  838.  
  839.         DWORD xp;
  840.         DWORD yp;
  841.         DWORD* pdwRow = (DWORD*)lr.pBits;
  842.         DWORD* pdw;
  843.         DWORD dwAlpha;
  844.         LONG dataBytesPerRow = 4 * sd.Width;
  845.  
  846.         for (yp = 0; yp < sd.Height; yp++)
  847.         {
  848.             pdw = pdwRow;
  849.             for (xp = 0; xp < sd.Width; xp++)
  850.             {
  851.                 dwAlpha = *pdw >> 24;
  852.                 *pdw = 0xff000000 | (dwAlpha << 16) | (dwAlpha << 8) | (dwAlpha);
  853.                 pdw++;
  854.             }
  855.             pdwRow += lr.Pitch / 4;
  856.         }
  857.         psurfDest->UnlockRect();
  858.     }
  859.  
  860.     ReleasePpo(&psurfSrc);
  861.     ReleasePpo(&psurfDest);
  862.  
  863.     return S_OK;
  864. }
  865.  
  866.  
  867. HRESULT CDxtexView::LoadSurfaceFromVolumeSlice(LPDIRECT3DVOLUME8 pVolume, UINT iSlice, LPDIRECT3DSURFACE8 psurf)
  868. {
  869.     HRESULT hr;
  870.     D3DVOLUME_DESC vd;
  871.     D3DLOCKED_BOX lb;
  872.     D3DBOX box;
  873.     RECT rc;
  874.  
  875.     pVolume->GetDesc(&vd);
  876.  
  877.     box.Left = 0;
  878.     box.Right = vd.Width;
  879.     box.Top = 0;
  880.     box.Bottom = vd.Height;
  881.     box.Front = iSlice;
  882.     box.Back = iSlice + 1;
  883.  
  884.     rc.left = 0;
  885.     rc.right = vd.Width;
  886.     rc.top = 0;
  887.     rc.bottom = vd.Height;
  888.  
  889.     hr = pVolume->LockBox(&lb, &box, 0);
  890.     if (FAILED(hr))
  891.         return hr;
  892.  
  893.     hr = D3DXLoadSurfaceFromMemory(psurf, NULL, NULL, lb.pBits, vd.Format, lb.RowPitch,
  894.         NULL, &rc, D3DX_FILTER_TRIANGLE, 0);
  895.  
  896.     pVolume->UnlockBox();
  897.  
  898.     return hr;
  899. }
  900.  
  901.  
  902. void CDxtexView::OnViewNegX()
  903. {
  904.     BuildViewSurface(m_bViewOrig, D3DCUBEMAP_FACE_NEGATIVE_X, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  905.     m_bTitleModsChanged = TRUE; // force title bar update
  906.     RenderScene();
  907.     Invalidate(); // force redraw of this view
  908. }
  909.  
  910.  
  911. void CDxtexView::OnUpdateViewNegX(CCmdUI* pCmdUI)
  912. {
  913.     BOOL bEnable = GetDocument()->IsCubeMap();
  914.     pCmdUI->Enable(bEnable);
  915.     pCmdUI->SetCheck(m_CubeFaceCur == D3DCUBEMAP_FACE_NEGATIVE_X);
  916. }
  917.  
  918.  
  919. void CDxtexView::OnViewPosX()
  920. {
  921.     BuildViewSurface(m_bViewOrig, D3DCUBEMAP_FACE_POSITIVE_X, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  922.     m_bTitleModsChanged = TRUE; // force title bar update
  923.     RenderScene();
  924.     Invalidate(); // force redraw of this view
  925. }
  926.  
  927.  
  928. void CDxtexView::OnUpdateViewPosX(CCmdUI* pCmdUI)
  929. {
  930.     BOOL bEnable = GetDocument()->IsCubeMap();
  931.     pCmdUI->Enable(bEnable);
  932.     pCmdUI->SetCheck(m_CubeFaceCur == D3DCUBEMAP_FACE_POSITIVE_X);
  933. }
  934.  
  935.  
  936. void CDxtexView::OnViewNegY()
  937. {
  938.     BuildViewSurface(m_bViewOrig, D3DCUBEMAP_FACE_NEGATIVE_Y, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  939.     m_bTitleModsChanged = TRUE; // force title bar update
  940.     RenderScene();
  941.     Invalidate(); // force redraw of this view
  942. }
  943.  
  944.  
  945. void CDxtexView::OnUpdateViewNegY(CCmdUI* pCmdUI)
  946. {
  947.     BOOL bEnable = GetDocument()->IsCubeMap();
  948.     pCmdUI->Enable(bEnable);
  949.     pCmdUI->SetCheck(m_CubeFaceCur == D3DCUBEMAP_FACE_NEGATIVE_Y);
  950. }
  951.  
  952.  
  953. void CDxtexView::OnViewPosY()
  954. {
  955.     BuildViewSurface(m_bViewOrig, D3DCUBEMAP_FACE_POSITIVE_Y, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  956.     m_bTitleModsChanged = TRUE; // force title bar update
  957.     RenderScene();
  958.     Invalidate(); // force redraw of this view
  959. }
  960.  
  961.  
  962. void CDxtexView::OnUpdateViewPosY(CCmdUI* pCmdUI)
  963. {
  964.     BOOL bEnable = GetDocument()->IsCubeMap();
  965.     pCmdUI->Enable(bEnable);
  966.     pCmdUI->SetCheck(m_CubeFaceCur == D3DCUBEMAP_FACE_POSITIVE_Y);
  967. }
  968.  
  969.  
  970. void CDxtexView::OnViewNegZ()
  971. {
  972.     BuildViewSurface(m_bViewOrig, D3DCUBEMAP_FACE_NEGATIVE_Z, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  973.     m_bTitleModsChanged = TRUE; // force title bar update
  974.     RenderScene();
  975.     Invalidate(); // force redraw of this view
  976. }
  977.  
  978.  
  979. void CDxtexView::OnUpdateViewNegZ(CCmdUI* pCmdUI)
  980. {
  981.     BOOL bEnable = GetDocument()->IsCubeMap();
  982.     pCmdUI->Enable(bEnable);
  983.     pCmdUI->SetCheck(m_CubeFaceCur == D3DCUBEMAP_FACE_NEGATIVE_Z);
  984. }
  985.  
  986.  
  987. void CDxtexView::OnViewPosZ()
  988. {
  989.     BuildViewSurface(m_bViewOrig, D3DCUBEMAP_FACE_POSITIVE_Z, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  990.     m_bTitleModsChanged = TRUE; // force title bar update
  991.     RenderScene();
  992.     Invalidate(); // force redraw of this view
  993. }
  994.  
  995.  
  996. void CDxtexView::OnUpdateViewPosZ(CCmdUI* pCmdUI)
  997. {
  998.     BOOL bEnable = GetDocument()->IsCubeMap();
  999.     pCmdUI->Enable(bEnable);
  1000.     pCmdUI->SetCheck(m_CubeFaceCur == D3DCUBEMAP_FACE_POSITIVE_Z);
  1001. }
  1002.  
  1003. void CDxtexView::OnFileOpenFace()
  1004. {
  1005.     GetDocument()->OpenCubeFace(m_CubeFaceCur);
  1006. }
  1007.  
  1008. void CDxtexView::OnUpdateFileOpenFace(CCmdUI* pCmdUI)
  1009. {
  1010.     BOOL bEnable = (m_CubeFaceCur != D3DCUBEMAP_FACE_FORCE_DWORD);
  1011.     pCmdUI->Enable(bEnable);
  1012. }
  1013.  
  1014. void CDxtexView::OnFileOpenAlphaFace()
  1015. {
  1016.     GetDocument()->OpenAlphaCubeFace(m_CubeFaceCur);
  1017. }
  1018.  
  1019. void CDxtexView::OnUpdateFileOpenAlphaFace(CCmdUI* pCmdUI)
  1020. {
  1021.     BOOL bEnable = (m_CubeFaceCur != D3DCUBEMAP_FACE_FORCE_DWORD);
  1022.     pCmdUI->Enable(bEnable);
  1023. }
  1024.  
  1025. void CDxtexView::OnViewHigherVolumeSlice()
  1026. {
  1027.     m_lwSliceCur++;
  1028.     BuildViewSurface(m_bViewOrig, m_CubeFaceCur, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  1029.     UpdateDevice();
  1030.     RenderScene();
  1031.     m_bTitleModsChanged = TRUE; // force title bar update
  1032.     Invalidate(); // force redraw of this view
  1033. }
  1034.  
  1035. void CDxtexView::OnUpdateViewHigherVolumeSlice(CCmdUI* pCmdUI)
  1036. {
  1037.     pCmdUI->Enable(GetDocument()->IsVolumeMap() && m_lwSliceCur < (LONG)GetDocument()->DwDepthAt(m_lwMipCur) - 1);
  1038. }
  1039.  
  1040. void CDxtexView::OnViewLowerVolumeSlice()
  1041. {
  1042.     m_lwSliceCur--;
  1043.     BuildViewSurface(m_bViewOrig, m_CubeFaceCur, m_lwSliceCur, m_lwMipCur, m_bViewAlpha);
  1044.     UpdateDevice();
  1045.     RenderScene();
  1046.     m_bTitleModsChanged = TRUE; // force title bar update
  1047.     Invalidate(); // force redraw of this view
  1048. }
  1049.  
  1050. void CDxtexView::OnUpdateViewLowerVolumeSlice(CCmdUI* pCmdUI)
  1051. {
  1052.     pCmdUI->Enable(GetDocument()->IsVolumeMap() && m_lwSliceCur > 0);
  1053. }
  1054.  
  1055.