home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2004 March / PCWELT_3_2004.ISO / pcwsoft / flaskmpeg_078_39_src.z.exe / flaskmpeg / VideoRenderer.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-10-28  |  15.5 KB  |  599 lines

  1. /* 
  2.  *  VideoRenderer.cpp
  3.  *
  4.  *    Copyright (C) Alberto Vigata - July 2000 - ultraflask@yahoo.com
  5.  *
  6.  *  This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
  7.  *    
  8.  *  FlasKMPEG is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published by
  10.  *  the Free Software Foundation; either version 2, or (at your option)
  11.  *  any later version.
  12.  *   
  13.  *  FlasKMPEG is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *   
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with GNU Make; see the file COPYING.  If not, write to
  20.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  21.  *
  22.  */
  23.  
  24. #define INITGUID
  25. #include "VideoRenderer.h"
  26.  
  27. #include <stdlib.h>
  28. #include "error.h"
  29. #include "FlMemcpy.h"
  30. #include "Debug.h"
  31.  
  32.  
  33. //////////////////////////////////////////////////////////////////////
  34. // Construction/Destruction
  35. //////////////////////////////////////////////////////////////////////
  36.  
  37. CVideoRenderer::CVideoRenderer(HWND hRenderWnd,bool bFixedFormat, int nFixedFormat)
  38. {
  39.   m_hRenderWnd = hRenderWnd;
  40.   m_nWidth = 0;
  41.   m_nHeight = 0;
  42.   fTime = 0;
  43.  
  44.   m_bOverlayFlag = m_bDirectDrawFlag = false;
  45.  
  46.   m_nCurrentFormat = bFixedFormat ? nFixedFormat : FRAME_RGB32;
  47.   m_bFixedFormat = bFixedFormat;
  48.  
  49.   m_pDD = NULL;
  50.   m_pDD2= NULL;
  51.   m_pDDSPrimary = NULL;
  52.   m_pDDSOverlay = NULL;
  53.  
  54.   PaintKey();
  55.   StopPlaying();
  56. }
  57.  
  58. CVideoRenderer::~CVideoRenderer()
  59. {
  60.   CloseOverlay();
  61.   CloseDirectDraw();
  62. }
  63.  
  64. bool CVideoRenderer::OpenDirectDraw()
  65. {
  66.   HRESULT hError;
  67.   try
  68.   {
  69.     //Close all
  70.     CloseDirectDraw();
  71.     
  72.     m_bDirectDrawFlag = false; 
  73.     ZeroMemory(&m_pDD, sizeof(m_pDD));
  74.     // Create the main DirectDraw object
  75.     if(hError=DirectDrawCreate( NULL, &m_pDD,  NULL )==DD_OK) 
  76.     {
  77.  
  78.       ZeroMemory(&m_pDD2, sizeof(m_pDD2));
  79.       
  80.       if (hError=m_pDD->QueryInterface(IID_IDirectDraw2, (LPVOID*)&m_pDD2)==DD_OK)
  81.       {
  82.         
  83.         // Request normal cooperative level to put us in windowed mode
  84.         if(hError=m_pDD2->SetCooperativeLevel( m_hRenderWnd, DDSCL_NORMAL )==DD_OK) 
  85.         {
  86.           // Get driver capabilities to determine Overlay support.
  87.           ZeroMemory( &m_ddcaps, sizeof(m_ddcaps) );
  88.           m_ddcaps.dwSize = sizeof(m_ddcaps);
  89.           
  90.           // Create the primary surface, which in windowed mode is the desktop.
  91.           ZeroMemory(&m_ddsd,sizeof(m_ddsd));
  92.           m_ddsd.dwSize         = sizeof(m_ddsd);
  93.           m_ddsd.dwFlags        = DDSD_CAPS;
  94.           m_ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  95.           if(hError=m_pDD2->CreateSurface( &m_ddsd, &m_pDDSPrimary, NULL )==DD_OK)
  96.           {
  97.             m_bDirectDrawFlag = true;
  98.             return true;
  99.           }
  100.           else
  101.           {
  102.             //DirectDraw initialized, destroy it
  103.             if (m_pDD)  SafeRelease( m_pDD);
  104.             if (m_pDD2)  SafeRelease( m_pDD2);
  105.             return false;
  106.           }
  107.         }
  108.         else
  109.         {
  110.           if (m_pDD)  SafeRelease( m_pDD);
  111.           if (m_pDD2)  SafeRelease( m_pDD2);
  112.           return false;
  113.         }
  114.       }
  115.       else
  116.         if (m_pDD)  SafeRelease( m_pDD);
  117.         return false;
  118.     }
  119.     else
  120.       return false;
  121.   } 
  122.   catch(...) {return false;}  
  123. }
  124.  
  125. void CVideoRenderer::CloseDirectDraw()
  126. {
  127.   m_bDirectDrawFlag = false;
  128.   m_bOverlayFlag = false;
  129.   if(m_pDDSOverlay) SafeRelease(m_pDDSOverlay);
  130.   if (m_pDDSPrimary) SafeRelease( m_pDDSPrimary );
  131.   if (m_pDD)  SafeRelease( m_pDD);
  132.   if (m_pDD2)  SafeRelease( m_pDD2);
  133. }
  134.  
  135. bool CVideoRenderer::GetInfoOverlay(DWORD * FccCodes, DDCAPS * Caps)
  136. {
  137.   
  138.   bool m_bKeepDDrawOpened = m_bDirectDrawFlag;
  139.   
  140.   if (!m_bDirectDrawFlag)
  141.     OpenDirectDraw();
  142.         
  143.   if (m_bDirectDrawFlag)
  144.   {
  145.     ZeroMemory(Caps, sizeof(DDCAPS));
  146.     Caps->dwSize = sizeof(DDCAPS);
  147.     DWORD NbrCodes;
  148.     
  149.     if (!(m_pDD2->GetCaps(Caps, NULL)==DD_OK) || 
  150.         !(m_pDD2->GetFourCCCodes(&NbrCodes,FccCodes)==DD_OK))
  151.     {
  152.       if (!m_bKeepDDrawOpened)
  153.         CloseDirectDraw();
  154.       return false;
  155.     }
  156.     
  157.     if (!m_bKeepDDrawOpened)
  158.       CloseDirectDraw();
  159.     return true;
  160.   }
  161.   else
  162.     return false;
  163.   
  164. }
  165.  
  166. bool CVideoRenderer::SetOverlay(int nWidth, int nHeight, long StoreFormat)
  167. {
  168.   if (OpenDirectDraw())
  169.     if (OpenOverlay(StoreFormat, nWidth, nHeight))
  170.       PaintKey();
  171.  
  172.       return true;
  173.   
  174.     return false;
  175. }
  176.  
  177. bool CVideoRenderer::OpenOverlay(long StoreFormat,int nWidth, int nHeight)
  178. {
  179.   HRESULT hError;
  180.     //Close any other overlay
  181.     CloseOverlay();
  182.     
  183.     DDPIXELFORMAT  ddpfOverlayFormat;
  184.     
  185.     bool bSuccess = false;
  186.     //Init Flag
  187.     m_bOverlayFlag = false;
  188.     
  189.     if(m_bDirectDrawFlag)
  190.     {
  191.       ZeroMemory( &ddpfOverlayFormat, sizeof(ddpfOverlayFormat) );
  192.       ddpfOverlayFormat.dwSize        = sizeof(ddpfOverlayFormat);
  193.       
  194.       switch(StoreFormat)
  195.       {
  196.       case FRAME_YUY2:
  197.         ddpfOverlayFormat.dwFlags       = DDPF_FOURCC;
  198.         ddpfOverlayFormat.dwFourCC      = mmioFOURCC('Y','U','Y','2');
  199.         ddpfOverlayFormat.dwYUVBitCount = 16; 
  200.         break;
  201.       case FRAME_YV12:
  202.         ddpfOverlayFormat.dwFlags       = DDPF_FOURCC;
  203.         ddpfOverlayFormat.dwFourCC      = mmioFOURCC('Y','V','1','2');
  204.         break;
  205.       case FRAME_RGB32:
  206.         ddpfOverlayFormat.dwFlags       = DDPF_RGB;
  207.         ddpfOverlayFormat.dwRGBBitCount = 32;
  208.         ddpfOverlayFormat.dwRBitMask  = 0x00FF0000;
  209.         ddpfOverlayFormat.dwGBitMask  = 0x0000FF00;
  210.         ddpfOverlayFormat.dwBBitMask  = 0x000000FF;
  211.         break;
  212.       }
  213.       
  214.       // Setup the overlay surface's attributes in the surface descriptor
  215.       ZeroMemory( &m_ddsd, sizeof(m_ddsd) );
  216.       m_ddsd.dwSize            = sizeof(m_ddsd);
  217.       m_ddsd.dwFlags           = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  218.       m_ddsd.ddsCaps.dwCaps    = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
  219.       m_ddsd.dwWidth           = nWidth;
  220.       m_ddsd.dwHeight          = nHeight;
  221.       m_ddsd.ddpfPixelFormat   = ddpfOverlayFormat;  
  222.       
  223.       // Attempt to create the surface with theses settings
  224.       if(hError=m_pDD2->CreateSurface( &m_ddsd, &m_pDDSOverlay, NULL)==DD_OK) 
  225.       {
  226.         bSuccess = true;
  227.         m_bOverlayFlag = true;
  228.         
  229.         ZeroMemory(&m_OverlayFX, sizeof(DDOVERLAYFX));
  230.         m_OverlayFX.dwSize = sizeof(DDOVERLAYFX);
  231.         
  232.         m_OverlayFX.dckDestColorkey.dwColorSpaceLowValue = DDColorMatch(m_pDDSPrimary, MASKCOLOR);
  233.         m_OverlayFX.dckDestColorkey.dwColorSpaceHighValue = m_OverlayFX.dckDestColorkey.dwColorSpaceLowValue;
  234.     
  235.         if( !m_bFixedFormat )
  236.           m_nCurrentFormat = StoreFormat;
  237.         
  238.       }
  239.       return bSuccess;
  240.     }
  241.     else
  242.       return bSuccess;
  243.   }
  244.  
  245. // Match the color 
  246. DWORD CVideoRenderer::DDColorMatch(LPDIRECTDRAWSURFACE pdds, COLORREF rgb)
  247. {
  248.   COLORREF    rgbT;
  249.   DWORD        dw = CLR_INVALID;
  250.   HRESULT        hres;
  251.   HDC            hdc;
  252.   
  253.   
  254.   if (IDirectDrawSurface_GetDC(pdds, &hdc)==DD_OK)
  255.   {
  256.     rgbT = GetPixel(hdc, 0, 0);
  257.     SetPixel(hdc, 0, 0, rgb);
  258.     IDirectDrawSurface_ReleaseDC(pdds, hdc);
  259.   }
  260.   
  261.   ZeroMemory(&m_ddsd, sizeof(DDSURFACEDESC));
  262.   m_ddsd.dwSize = sizeof(DDSURFACEDESC);
  263.   while ((hres = IDirectDrawSurface_Lock(pdds, NULL, &m_ddsd, DDLOCK_WAIT, NULL)) == DDERR_WASSTILLDRAWING);
  264.   
  265.   if (hres==DD_OK)
  266.   {
  267.     dw = *(DWORD *) m_ddsd.lpSurface;
  268.     if (m_ddsd.ddpfPixelFormat.dwRGBBitCount < 32)
  269.       dw &= (1 << m_ddsd.ddpfPixelFormat.dwRGBBitCount) - 1;
  270.     IDirectDrawSurface_Unlock(pdds, NULL);
  271.   }
  272.   
  273.   if (IDirectDrawSurface_GetDC(pdds, &hdc)==DD_OK)
  274.   {
  275.     SetPixel(hdc, 0, 0, rgbT);
  276.     IDirectDrawSurface_ReleaseDC(pdds, hdc);
  277.   }
  278.   
  279.   return dw;
  280. }
  281.  
  282. void CVideoRenderer::CloseOverlay()
  283. {
  284.   if(m_pDDSOverlay) SafeRelease(m_pDDSOverlay);
  285.   m_bOverlayFlag = false;
  286.   
  287.   if( !m_bFixedFormat )
  288.     m_nCurrentFormat = FRAME_RGB32;
  289. }
  290.  
  291. void CVideoRenderer::SetStaticFrame(CFrame *pFrame)
  292. {
  293.  
  294.   if(!pFrame)
  295.     return; 
  296.   if(!pFrame->IsValid())
  297.     return;
  298.   m_oStaticFrame = *pFrame;
  299. }
  300.  
  301. void CVideoRenderer::Update()
  302. {
  303.   CFlAutoLock lock(&m_csDirectDraw);
  304.   if(m_bOverlayFlag)
  305.   {
  306.     PaintKey();
  307.     UpdateOverlay();
  308.   }
  309.  
  310.  
  311.   if( m_nState == Stopped )
  312.     Draw(&m_oStaticFrame);
  313.      
  314. }
  315.  
  316. // Paint the window with the color key
  317. void CVideoRenderer::PaintKey()
  318. {
  319.   HPEN hpen, hpenOld;
  320.   HBRUSH hbrush, hbrushOld;
  321.   
  322.   HDC hDC = GetDC( m_hRenderWnd );
  323.   // Create a  pen.
  324.   hpen = CreatePen(PS_SOLID, 1, MASKCOLOR);
  325.   // Create a brush.
  326.   hbrush = CreateSolidBrush(MASKCOLOR);
  327.   
  328.   // Select the new pen and brush, and then draw.
  329.   hpenOld = (HPEN )SelectObject(hDC, hpen);
  330.   hbrushOld = (HBRUSH )SelectObject(hDC, hbrush);
  331.   
  332.   RECT sRect;
  333.   GetClientRect( m_hRenderWnd, &sRect );
  334.     
  335.   Rectangle( hDC, sRect.left, sRect.top, 
  336.     sRect.right,
  337.     sRect.bottom );
  338.   
  339.   // Do not forget to clean up.
  340.   SelectObject(hDC, hpenOld);
  341.   DeleteObject(hpen);
  342.   SelectObject(hDC, hbrushOld);
  343.   DeleteObject(hbrush);
  344.  
  345.   ReleaseDC( m_hRenderWnd, hDC);
  346.  
  347.   return;
  348. }
  349.  
  350.  
  351. void CVideoRenderer::UpdateOverlay()
  352. {
  353.   POINT point = {0, 0};
  354.   RECT orect,prect;
  355.  
  356.   CFlAutoLock lock(&m_csDirectDraw);
  357.   
  358.   if(!m_bOverlayFlag) return;
  359.  
  360.   SetRect(&orect, 0, 0, m_nWidth, m_nHeight);
  361.   
  362.   ClientToScreen(m_hRenderWnd, &point);
  363.   prect.left = point.x;
  364.   prect.right = point.x + m_nWidth;
  365.   prect.top = point.y;
  366.   prect.bottom = point.y + m_nHeight;
  367.   
  368.   if (prect.left < 0)
  369.   {
  370.     orect.left = -prect.left;
  371.     prect.left = 0;
  372.   }
  373.   
  374.   if (prect.top < 0)
  375.   {
  376.     orect.top = -prect.top;
  377.     prect.top = 0;
  378.   }
  379.   
  380.   if (prect.right > GetSystemMetrics(SM_CXSCREEN))
  381.   {
  382.     orect.right = m_nWidth + GetSystemMetrics(SM_CXSCREEN) - prect.right;
  383.     prect.right = GetSystemMetrics(SM_CXSCREEN);
  384.   }
  385.   
  386.   if (prect.bottom > GetSystemMetrics(SM_CYSCREEN))
  387.   {
  388.     orect.bottom = m_nHeight + GetSystemMetrics(SM_CYSCREEN) - prect.bottom;
  389.     prect.bottom = GetSystemMetrics(SM_CYSCREEN);
  390.   }
  391.   
  392.   m_pDDSOverlay->UpdateOverlay(&orect, m_pDDSPrimary, &prect,
  393.     DDOVER_SHOW | DDOVER_DDFX | DDOVER_KEYDESTOVERRIDE , &m_OverlayFX);
  394. }
  395.  
  396.  
  397. void CVideoRenderer::Draw(CFrame *pFrame, int flags )
  398. {
  399.   HRESULT res;
  400.   DWORD lckflags = flags&VR_WAITFORLOCK ? DDLOCK_WAIT : 0;
  401.  
  402.   if(!pFrame)
  403.     return;
  404.  
  405.   if(!pFrame->IsValid())
  406.     return;
  407.  
  408.   int nWidth = pFrame->GetWidth();
  409.   int nHeight = pFrame->GetHeight();
  410.   int nFrameFormat = pFrame->GetFormat();
  411.  
  412.   CFlAutoLock lock(&m_csDirectDraw);
  413.  
  414.   // if there has been a change in resolution
  415.   // update the overlay
  416.   if(nWidth  != m_nWidth  ||
  417.      nHeight != m_nHeight )
  418.   {
  419.     SetOverlay( nWidth, nHeight, m_bFixedFormat ? m_nCurrentFormat : nFrameFormat );
  420.      m_nWidth = nWidth;
  421.      m_nHeight = nHeight;
  422.      // Update the rgb frame size
  423.      m_oRgbFrame.Set( m_nWidth, m_nHeight, m_nCurrentFormat );
  424.   }
  425.  
  426.   if( m_nCurrentFormat != nFrameFormat && !m_bFixedFormat )
  427.   {
  428.     SetOverlay( nWidth, nHeight, nFrameFormat );
  429.   }
  430.   
  431.  
  432.  
  433.   switch(nFrameFormat)
  434.   {
  435.     case FRAME_RGB32:
  436.         
  437.         if( 1 ) //For RGB dont use overlays
  438.         { 
  439.             HDC hDC;
  440.             hDC = GetDC(m_hRenderWnd);
  441.             SetDIBitsToDevice((HDC) hDC,0,0,nWidth,nHeight,
  442.              0,0,0,nHeight, pFrame->GetBuffer(), pFrame->GetBmpInfo(), DIB_RGB_COLORS);
  443.             ReleaseDC( m_hRenderWnd, (HDC)hDC);
  444.         }
  445.         else
  446.         {
  447.             try
  448.             {
  449.                 int w = nWidth;
  450.                 int ww = w*4;
  451.                 int h = nHeight;
  452.             
  453.                 
  454.                 ZeroMemory(&m_ddsd, sizeof(DDSURFACEDESC));
  455.                 m_ddsd.dwSize = sizeof(DDSURFACEDESC);
  456.  
  457.                 if (m_pDDSOverlay->Lock(0, &m_ddsd, lckflags , 0)==DD_OK)
  458.                 {
  459.                     unsigned char * src = (unsigned char *)pFrame->GetBuffer() + w*h*4 ;
  460.                     unsigned char * dst = (unsigned char *)m_ddsd.lpSurface;
  461.                     long Pitch = m_ddsd.lPitch-ww;
  462.  
  463.                     for (int i=0; i<h; i++)
  464.                     {
  465.                         src -= ww;
  466.                         flmemcpy(dst, src, ww); 
  467.                         dst += m_ddsd.lPitch;
  468.                     }
  469.                     if( m_pDDSOverlay->Unlock(0)==DD_OK ) UpdateOverlay();        
  470.                 }
  471.             }    
  472.             catch(...)
  473.             {
  474.                     throw (MyError("RGB DirectDraw Error"));
  475.             }
  476.         }
  477.       break;
  478.  
  479.     case FRAME_YUY2:
  480.         switch( m_nCurrentFormat )
  481.     {
  482.     case FRAME_YUY2:
  483.       try
  484.       {
  485.         int w = nWidth;
  486.         int ww = w*2;
  487.         int h = nHeight;
  488.         
  489.         ZeroMemory(&m_ddsd, sizeof(DDSURFACEDESC));
  490.         m_ddsd.dwSize = sizeof(DDSURFACEDESC);
  491.         
  492.         if (m_pDDSOverlay->Lock(0, &m_ddsd, lckflags, 0)==DD_OK)
  493.         {
  494.           unsigned char *src = (unsigned char *)pFrame->GetBuffer();
  495.           unsigned char *dst = (unsigned char *)m_ddsd.lpSurface;
  496.           long Pitch = m_ddsd.lPitch-ww;
  497.           
  498.           if( Pitch ) 
  499.           {
  500.             for (int i=0; i<h; i++)
  501.             {
  502.               flmemcpy(dst, src, ww);
  503.               src += ww;
  504.               dst += m_ddsd.lPitch;
  505.             }
  506.           }
  507.           else
  508.           {
  509.             flmemcpy( dst, src, ww*h);
  510.           }
  511.           
  512.           if( m_pDDSOverlay->Unlock(0)==DD_OK ) UpdateOverlay();
  513.         }
  514.       }
  515.       catch(...)
  516.       {
  517.         throw (MyError("YUY2 DirectDraw Error"));
  518.       }
  519.       break;
  520.     }
  521.     break;
  522.     case FRAME_YV12:
  523.         switch( m_nCurrentFormat )
  524.     {
  525.     case FRAME_YV12:
  526.       try
  527.       {
  528.         int w = nWidth;
  529.         int halfW = w >> 1;
  530.         int h = nHeight;
  531.         
  532.         
  533.         ZeroMemory(&m_ddsd, sizeof(DDSURFACEDESC));
  534.         m_ddsd.dwSize = sizeof(DDSURFACEDESC);
  535.         
  536.         if ( (res = m_pDDSOverlay->Lock(0, &m_ddsd,  lckflags, 0))==DD_OK )
  537.         {
  538.           unsigned char *src = (unsigned char *)pFrame->GetBuffer();
  539.           unsigned char *src2 = (unsigned char *)pFrame->GetBuffer()+h*w;
  540.           unsigned char *src3 = (unsigned char *)pFrame->GetBuffer()+h*w+ ((h*w)>>2);
  541.           unsigned char *dst = (unsigned char *)m_ddsd.lpSurface;
  542.           int Decal = ((m_ddsd.lPitch-w)>>1);
  543.           
  544.           for (int i=0; i<h; i++)
  545.           {
  546.             flmemcpy(dst, src, w);
  547.             src += w;
  548.             dst += m_ddsd.lPitch;
  549.           }
  550.           
  551.           
  552.           for (i=0; i<h>>1; i+=2)
  553.           {
  554.             flmemcpy(dst,src2, halfW);
  555.             flmemcpy(dst + halfW + Decal,src2, halfW);
  556.             src2 += w;
  557.             dst +=m_ddsd.lPitch;
  558.           }
  559.           
  560.           
  561.           for (i=0; i<h>>1; i+=2)
  562.           {
  563.             flmemcpy(dst,src3, halfW);
  564.             flmemcpy(dst + halfW + Decal,src3, halfW);
  565.             src3 += w;
  566.             dst +=m_ddsd.lPitch;
  567.           }
  568.           
  569.           if( m_pDDSOverlay->Unlock(0)==DD_OK ) UpdateOverlay();    
  570.           
  571.         }
  572.         else
  573.         {
  574.           DBG_STR((str, "VideoRenderer - Couldnt lock surface. Was still drawing: %d\n", res==DDERR_WASSTILLDRAWING))
  575.         }
  576.       }
  577.       catch(...) 
  578.       {
  579.         throw (MyError("YV12 DirectDraw Error"));
  580.       }      
  581.       break;
  582.     case FRAME_RGB32:
  583.       FLASSERT( m_oRgbFrame.GetWidth() == pFrame->GetWidth()  &&
  584.                 m_oRgbFrame.GetHeight() == pFrame->GetHeight() )
  585.       // Use the RGB frame to do the conversion
  586.       m_oRgbFrame.SetFrame( pFrame );
  587.       // Draw it
  588.       HDC hDC;
  589.       hDC = GetDC(m_hRenderWnd);
  590.       SetDIBitsToDevice((HDC) hDC,0,0,nWidth,nHeight,
  591.         0,0,0,nHeight, m_oRgbFrame.GetBuffer(),m_oRgbFrame.GetBmpInfo(), DIB_RGB_COLORS);
  592.       ReleaseDC( m_hRenderWnd, (HDC)hDC);
  593.       
  594.       break;
  595.     }
  596.     break;
  597.   }
  598. }
  599.