home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / fball.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-15  |  17.3 KB  |  645 lines

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (c) 1992 - 1996  Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. // Bouncing Ball Source filter
  13. //
  14.  
  15. // Uses CSource & CSourceStream to generate a movie on the fly of a
  16. // bouncing ball...
  17.  
  18. #include <streams.h>
  19. #include <olectl.h>
  20. #include <initguid.h>
  21. #include <olectlid.h>
  22.  
  23. #include "balluids.h"
  24. #include "ball.h"
  25. #include "fball.h"
  26. #include "ballprop.h"
  27.  
  28. // setup data
  29.  
  30. AMOVIESETUP_MEDIATYPE sudOpPinTypes = { &MEDIATYPE_Video      // clsMajorType
  31.                                       , &MEDIASUBTYPE_NULL }; // clsMinorType
  32.  
  33. AMOVIESETUP_PIN sudOpPin = { L"Output"          // strName
  34.                            , FALSE              // bRendered
  35.                            , TRUE               // bOutput
  36.                            , FALSE              // bZero
  37.                            , FALSE              // bMany
  38.                            , &CLSID_NULL        // clsConnectsToFilter
  39.                            , NULL               // strConnectsToPin
  40.                            , 1                  // nTypes
  41.                            , &sudOpPinTypes };  // lpTypes
  42.  
  43. AMOVIESETUP_FILTER sudBallax = { &CLSID_BouncingBall  // clsID
  44.                                 , L"Bouncing Ball"    // strName
  45.                                 , MERIT_UNLIKELY      // dwMerit
  46.                                 , 1                   // nPins
  47.                                 , &sudOpPin };        // lpPin
  48.  
  49. // COM global table of objects in this dll
  50. CFactoryTemplate g_Templates[] = {
  51.   { L"Bouncing Ball"     , &CLSID_BouncingBall    , CBouncingBall::CreateInstance },
  52.   { L"Ball Property Page", &CLSID_BallPropertyPage, CBallProperties::CreateInstance }
  53. };
  54. int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
  55.  
  56.  
  57. // exported entry points for registration and
  58. // unregistration (in this case they only call
  59. // through to default implmentations).
  60. //
  61. HRESULT DllRegisterServer()
  62. {
  63.   return AMovieDllRegisterServer();
  64. }
  65.  
  66. HRESULT DllUnregisterServer()
  67. {
  68.   return AMovieDllUnregisterServer();
  69. }
  70.  
  71.  
  72. //
  73. // CreateInstance
  74. //
  75. // The only allowed way to create Bouncing ball's!
  76. CUnknown *CBouncingBall::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr) {
  77.  
  78.     CUnknown *punk = new CBouncingBall(lpunk, phr);
  79.     if (punk == NULL) {
  80.  
  81.         *phr = E_OUTOFMEMORY;
  82.     }
  83.  
  84.     return punk;
  85. }
  86.  
  87.  
  88. //
  89. // CBouncingBall::Constructor
  90. //
  91. // initialise a CBallStream object so that we have a pin.
  92. CBouncingBall::CBouncingBall(LPUNKNOWN lpunk, HRESULT *phr)
  93.     : CSource(NAME("Bouncing ball Filter"),lpunk, CLSID_BouncingBall, phr) {
  94.  
  95.     CAutoLock l(&m_cStateLock);
  96.  
  97.     m_paStreams    = (CSourceStream **) new CBallStream*[1];
  98.     if (m_paStreams == NULL) {
  99.         *phr = E_OUTOFMEMORY;
  100.     return;
  101.     }
  102.  
  103.     m_paStreams[0] = new CBallStream(phr, this, L"A Bouncing Ball!");
  104.     if (m_paStreams[0] == NULL) {
  105.         *phr = E_OUTOFMEMORY;
  106.     return;
  107.     }
  108.  
  109. }
  110.  
  111.  
  112. //
  113. // CBouncingBall::Destructor
  114. //
  115. CBouncingBall::~CBouncingBall(void) {
  116.     //
  117.     //  Base class will free our pins
  118.     //
  119. }
  120.  
  121.  
  122. //
  123. // NonDelegatingQueryInterface
  124. //
  125. // Reveal our property pages
  126. STDMETHODIMP CBouncingBall::NonDelegatingQueryInterface(REFIID riid, void **ppv) {
  127.  
  128.     CAutoLock l(&m_cStateLock);
  129.  
  130.     if (riid == IID_ISpecifyPropertyPages)
  131.         return GetInterface((ISpecifyPropertyPages *) this, ppv);
  132.  
  133.     return CSource::NonDelegatingQueryInterface(riid, ppv);
  134. }
  135.  
  136.  
  137. //
  138. // GetPages
  139. //
  140. STDMETHODIMP CBouncingBall::GetPages(CAUUID * pPages) {
  141.  
  142.     CAutoLock l(&m_cStateLock);
  143.  
  144.     pPages->cElems = 1;
  145.     pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
  146.     if (pPages->pElems == NULL) {
  147.         return E_OUTOFMEMORY;
  148.     }
  149.     *(pPages->pElems) = CLSID_BallPropertyPage;
  150.  
  151.     return NOERROR;
  152.  
  153. }
  154.  
  155.  
  156. //
  157. // GetSetupData
  158. //
  159. LPAMOVIESETUP_FILTER CBouncingBall::GetSetupData()
  160. {
  161.   return &sudBallax;
  162. }
  163.  
  164. // *
  165. // * CBallStream
  166. // *
  167.  
  168.  
  169. //
  170. // CBallStream::Constructor
  171. //
  172. // Create a default ball
  173. CBallStream::CBallStream(HRESULT *phr, CBouncingBall *pParent, LPCWSTR pPinName)
  174.     : CSourceStream(NAME("Bouncing Ball output pin manager"),phr, pParent, pPinName)
  175.     , m_iImageWidth(320)
  176.     , m_iImageHeight(240)
  177.     , m_iDefaultRepeatTime(20) {      // 50 frames per second
  178.  
  179.     CAutoLock l(&m_cSharedState);
  180.  
  181.     m_Ball = new CBall(m_iImageWidth, m_iImageHeight);
  182.     if (m_Ball == NULL) {
  183.         *phr = E_OUTOFMEMORY;
  184.         return;
  185.     }
  186. }
  187.  
  188.  
  189. //
  190. // CBallStream::Destructor
  191. //
  192. CBallStream::~CBallStream(void) {
  193.  
  194.     CAutoLock l(&m_cSharedState);
  195.  
  196.     delete m_Ball;
  197. }
  198.  
  199.  
  200. //
  201. // FillBuffer
  202. //
  203. // plots a ball into the supplied video buffer
  204. HRESULT CBallStream::FillBuffer(IMediaSample *pms) {
  205.  
  206.     BYTE    *pData;
  207.     long    lDataLen;
  208.  
  209.     pms->GetPointer(&pData);
  210.     lDataLen = pms->GetSize();
  211.  
  212.     if( m_bZeroMemory )
  213.         // If true then we clear the output buffer and don't attempt to
  214.         // erase a previous drawing of the ball
  215.         ZeroMemory( pData, lDataLen );
  216.  
  217.     {
  218.         CAutoLock lShared(&m_cSharedState);
  219.  
  220.         // If we haven't just cleared the buffer delete the old
  221.         // ball and move the ball on
  222.  
  223.         if( !m_bZeroMemory ){
  224.             BYTE aZeroes[ 4 ] = { 0, 0, 0, 0 };
  225.  
  226.             m_Ball->PlotBall(pData, aZeroes, m_iPixelSize);
  227.             m_Ball->MoveBall(m_rtSampleTime - (LONG) m_iRepeatTime);
  228.         }
  229.  
  230.         m_Ball->PlotBall(pData, m_BallPixel, m_iPixelSize);
  231.  
  232.         CRefTime rtStart  = m_rtSampleTime;        // the current time is the sample's start
  233.         m_rtSampleTime   += (LONG)m_iRepeatTime;        // increment to find the finish time
  234.                                                         // (adding mSecs to ref time)
  235.         pms->SetTime((REFERENCE_TIME *) &rtStart,
  236.                      (REFERENCE_TIME *) &m_rtSampleTime);
  237.  
  238.     }
  239.  
  240.     m_bZeroMemory = FALSE;
  241.  
  242.     pms->SetSyncPoint(TRUE);
  243.     // pms->SetDiscontinuity(FALSE);
  244.     // pms->SetPreroll(FALSE);
  245.  
  246.     return NOERROR;
  247. }
  248.  
  249.  
  250. //
  251. // Notify
  252. //
  253. // Alter the repeat rate.  Wind it up or down according to the flooding level
  254. // Skip forward if we are notified of Late-ness
  255. STDMETHODIMP CBallStream::Notify(IFilter * pSender, Quality q) {
  256.  
  257.     // Adjust the repeat rate.
  258.     if (q.Proportion<=0) {
  259.  
  260.         m_iRepeatTime = 1000;        // We don't go slower than 1 per second
  261.     }
  262.     else {
  263.  
  264.         m_iRepeatTime = m_iRepeatTime*1000/q.Proportion;
  265.         DbgLog(( LOG_TRACE, 1, TEXT("New time: %d, Proportion: %d")
  266.                , m_iRepeatTime, q.Proportion));
  267.  
  268.         if (m_iRepeatTime>1000) {
  269.             m_iRepeatTime = 1000;    // We don't go slower than 1 per second
  270.         }
  271.         else if (m_iRepeatTime<10) {
  272.             m_iRepeatTime = 10;      // We don't go faster than 100/sec
  273.         }
  274.     }
  275.  
  276.     // skip forwards
  277.     if (q.Late > 0) {
  278.         m_rtSampleTime += q.Late;
  279.     }
  280.  
  281.     return NOERROR;
  282. }
  283.  
  284.  
  285.  
  286. //
  287. // Format Support
  288. //
  289. // I _prefer_ 5 formats - 8, 16 (*2), 24 or 32 bits per pixel and
  290. // I will suggest these with an image size of 320x240. However
  291. // I can accept any image size which gives me some space to bounce.
  292. //
  293. // A bit of fun: 8 bit displays see a red ball, 16 bit displays get blue,
  294. // 24bit see green and 32 bit see yellow!
  295.  
  296.  
  297.  
  298. //
  299. // GetMediaType
  300. //
  301. // Prefered types should be ordered by quality, zero as highest quality
  302. // Therefore iPosition =
  303. // 0    return a 32bit mediatype
  304. // 1    return a 24bit mediatype
  305. // 2    return 16bit RGB565
  306. // 3    return a 16bit mediatype (rgb555)
  307. // 4    return 8 bit palettised format
  308. // iPostion > 4 is invalid.
  309. HRESULT CBallStream::GetMediaType(int iPosition, CMediaType *pmt) {
  310.  
  311.     CAutoLock l(m_pFilter->pStateLock());
  312.  
  313.     if (iPosition<0) {
  314.         return E_INVALIDARG;
  315.     }
  316.     if (iPosition>4) {
  317.         return VFW_S_NO_MORE_ITEMS;
  318.     }
  319.  
  320.     VIDEOINFO *pvi = (VIDEOINFO *) pmt->AllocFormatBuffer(sizeof(VIDEOINFO));
  321.     if (NULL == pvi) {
  322.     return(E_OUTOFMEMORY);
  323.     }
  324.     ZeroMemory(pvi, sizeof(VIDEOINFO));
  325.  
  326.     switch (iPosition) {
  327.     case 0: {    // return our highest quality 32bit format
  328.  
  329.         // Place the RGB masks as the first 3 doublewords in the palette area
  330.         for (int i = 0; i < 3; i++)
  331.         pvi->TrueColorInfo.dwBitMasks[i] = bits888[i];
  332.  
  333.         SetPaletteEntries(Yellow);
  334.  
  335.     pvi->bmiHeader.biCompression = BI_BITFIELDS;
  336.     pvi->bmiHeader.biBitCount    = 32;
  337.     }
  338.     break;
  339.  
  340.     case 1: {    // return our 24bit format
  341.  
  342.         SetPaletteEntries(Green);
  343.     pvi->bmiHeader.biCompression = BI_RGB;
  344.     pvi->bmiHeader.biBitCount    = 24;
  345.  
  346.         }
  347.     break;
  348.  
  349.     case 2: {   // 16 bit RGB565 - note that the red element is the same for both 16bit formats
  350.  
  351.         // Place the RGB masks as the first 3 doublewords in the palette area
  352.         for (int i = 0; i < 3; i++)
  353.         pvi->TrueColorInfo.dwBitMasks[i] = bits565[i];
  354.  
  355.         SetPaletteEntries(Blue);
  356.  
  357.     pvi->bmiHeader.biCompression = BI_BITFIELDS;
  358.     pvi->bmiHeader.biBitCount    = 16;
  359.     }
  360.         break;
  361.  
  362.     case 3: {    // 16 bits per pixel - RGB555
  363.  
  364.         // Place the RGB masks as the first 3 doublewords in the palette area
  365.         for (int i = 0; i < 3; i++)
  366.         pvi->TrueColorInfo.dwBitMasks[i] = bits555[i];
  367.  
  368.         SetPaletteEntries(Blue);
  369.     pvi->bmiHeader.biCompression = BI_BITFIELDS;
  370.     pvi->bmiHeader.biBitCount    = 16;
  371.  
  372.         }
  373.     break;
  374.  
  375.     case 4: {    // 8 bits palettised
  376.  
  377.         SetPaletteEntries(Red);
  378.  
  379.         pvi->bmiHeader.biCompression = BI_RGB;
  380.     pvi->bmiHeader.biBitCount    = 8;
  381.  
  382.         }
  383.     break;
  384.     }
  385.     // Adjust the parameters common to all formats.
  386.  
  387.     // put the optimal palette in place
  388.     for (int i = 0; i < iPALETTE_COLORS; i++) {
  389.         pvi->TrueColorInfo.bmiColors[i].rgbRed      = m_Palette[i].peRed;
  390.         pvi->TrueColorInfo.bmiColors[i].rgbBlue     = m_Palette[i].peBlue;
  391.         pvi->TrueColorInfo.bmiColors[i].rgbGreen    = m_Palette[i].peGreen;
  392.         pvi->TrueColorInfo.bmiColors[i].rgbReserved = 0;
  393.     }
  394.  
  395.     pvi->bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
  396.     pvi->bmiHeader.biWidth        = m_iImageWidth;
  397.     pvi->bmiHeader.biHeight        = m_iImageHeight;
  398.     pvi->bmiHeader.biPlanes        = 1;
  399.     pvi->bmiHeader.biSizeImage        = GetBitmapSize(&pvi->bmiHeader);
  400.     pvi->bmiHeader.biClrUsed        = iPALETTE_COLORS;
  401.     pvi->bmiHeader.biClrImportant    = 0;
  402.  
  403.     SetRectEmpty(&(pvi->rcSource));    // we want the whole image area rendered.
  404.     SetRectEmpty(&(pvi->rcTarget));    // no particular destination rectangle
  405.  
  406.     pmt->SetType(&MEDIATYPE_Video);
  407.     pmt->SetFormatType(&FORMAT_VideoInfo);
  408.     pmt->SetTemporalCompression(FALSE);
  409.  
  410.     // Work out the GUID for the subtype from the header info.
  411.     const GUID SubTypeGUID = GetBitmapSubtype(&pvi->bmiHeader);
  412.     pmt->SetSubtype(&SubTypeGUID);
  413.     pmt->SetSampleSize(pvi->bmiHeader.biSizeImage);
  414.  
  415.     return NOERROR;
  416. }
  417.  
  418.  
  419. //
  420. // CheckMediaType
  421. //
  422. // We will accept 8, 16, 24 or 32 bit video formats, in any
  423. // image size that gives room to bounce.
  424. // Returns E_INVALIDARG if the mediatype is not acceptable, S_OK if it is
  425. HRESULT CBallStream::CheckMediaType(const CMediaType *pMediaType)
  426. {
  427.  
  428.     CAutoLock l(m_pFilter->pStateLock());
  429.  
  430.     if (   (*(pMediaType->Type()) != MEDIATYPE_Video)    // we only output video!
  431.     || !(pMediaType->IsFixedSize()) ) {        // ...in fixed size samples
  432.         return E_INVALIDARG;
  433.     }
  434.  
  435.     // Check for the subtypes we support
  436.     const GUID *SubType = pMediaType->Subtype();
  437.     if (   (*SubType != MEDIASUBTYPE_RGB8)
  438.         && (*SubType != MEDIASUBTYPE_RGB565)
  439.     && (*SubType != MEDIASUBTYPE_RGB555)
  440.      && (*SubType != MEDIASUBTYPE_RGB24)
  441.     && (*SubType != MEDIASUBTYPE_RGB32)
  442.        ) {
  443.         return E_INVALIDARG;
  444.     }
  445.  
  446.     // Get the format area of the media type
  447.     VIDEOINFO *pvi = (VIDEOINFO *) pMediaType->Format();
  448.  
  449.     if (pvi == NULL)
  450.     return E_INVALIDARG;
  451.  
  452.     // Check the image size. As my default ball is 10 pixels big
  453.     // look for at least a 20x20 image. This is an arbitary size constraint,
  454.     // but it avoids balls that are bigger than the picture...
  455.     if (   (pvi->bmiHeader.biWidth < 20)
  456.         || (pvi->bmiHeader.biHeight < 20) ) {
  457.     return E_INVALIDARG;
  458.     }
  459.  
  460.     return S_OK;  // This format is acceptable.
  461. }
  462.  
  463.  
  464. //
  465. // DecideBufferSize
  466. //
  467. // This will always be called after the format has been sucessfully
  468. // negotiated. So we have a look at m_mt to see what size image we agreed.
  469. // Then we can ask for buffers of the correct size to contain them.
  470. HRESULT CBallStream::DecideBufferSize(IMemAllocator *pAlloc,
  471.                                       ALLOCATOR_PROPERTIES *pProperties)
  472. {
  473.     CAutoLock l(m_pFilter->pStateLock());
  474.     ASSERT(pAlloc);
  475.     ASSERT(pProperties);
  476.     HRESULT hr = NOERROR;
  477.  
  478.     VIDEOINFO *pvi = (VIDEOINFO *) m_mt.Format();
  479.     pProperties->cBuffers = 1;
  480.     pProperties->cbBuffer = pvi->bmiHeader.biSizeImage;
  481.  
  482.     ASSERT(pProperties->cbBuffer);
  483.  
  484.     // Ask the allocator to reserve us some sample memory, NOTE the function
  485.     // can succeed (that is return NOERROR) but still not have allocated the
  486.     // memory that we requested, so we must check we got whatever we wanted
  487.  
  488.     ALLOCATOR_PROPERTIES Actual;
  489.     hr = pAlloc->SetProperties(pProperties,&Actual);
  490.     if (FAILED(hr)) {
  491.         return hr;
  492.     }
  493.  
  494.     // Is this allocator unsuitable
  495.  
  496.     if (Actual.cbBuffer < pProperties->cbBuffer) {
  497.         return E_FAIL;
  498.     }
  499.  
  500.     // Make sure that we have only 1 buffer (we erase the ball in the
  501.     // old buffer to save having to zero a 200k+ buffer every time
  502.     // we draw a frame)
  503.  
  504.     ASSERT( Actual.cBuffers == 1 );
  505.  
  506.     return NOERROR;
  507. }
  508.  
  509.  
  510. //
  511. // SetMediaType
  512. //
  513. // Overriden from CBasePin. Call the base class and then set the
  514. // ball parameters that depend on media type - m_BallPixel[], m_BackPixel, iPixelSize, etc
  515. HRESULT CBallStream::SetMediaType(const CMediaType *pMediaType) {
  516.  
  517.     CAutoLock l(m_pFilter->pStateLock());
  518.  
  519.     HRESULT hr;        // return code from base class calls
  520.  
  521.     // Pass the call up to my base class
  522.     hr = CSourceStream::SetMediaType(pMediaType);
  523.     if (SUCCEEDED(hr)) {
  524.  
  525.         VIDEOINFO * pvi = (VIDEOINFO *) m_mt.Format();
  526.         switch (pvi->bmiHeader.biBitCount) {
  527.         case 8:        // make a red pixel
  528.  
  529.             m_BallPixel[0] = 10;    // 0 is palette index of red
  530.         m_iPixelSize   = 1;
  531.         SetPaletteEntries(Red);
  532.         break;
  533.  
  534.         case 16:    // make a blue pixel
  535.  
  536.             m_BallPixel[0] = 0xf8;    // 00000000 00011111 is blue in rgb555 or rgb565
  537.         m_BallPixel[1] = 0x0;    // don't forget the byte ordering within the mask word.
  538.         m_iPixelSize   = 2;
  539.         SetPaletteEntries(Blue);
  540.         break;
  541.  
  542.         case 24:    // make a green pixel
  543.  
  544.             m_BallPixel[0] = 0x0;
  545.         m_BallPixel[1] = 0xff;
  546.         m_BallPixel[2] = 0x0;
  547.         m_iPixelSize   = 3;
  548.         SetPaletteEntries(Green);
  549.         break;
  550.  
  551.     case 32:    // make a yellow pixel
  552.  
  553.             m_BallPixel[0] = 0x0;
  554.         m_BallPixel[1] = 0x0;
  555.         m_BallPixel[2] = 0xff;
  556.         m_BallPixel[3] = 0xff;
  557.         m_iPixelSize   = 4;
  558.             SetPaletteEntries(Yellow);
  559.         break;
  560.  
  561.         default:
  562.             // We should never agree any other pixel sizes
  563.         ASSERT("Tried to agree inappropriate format");
  564.  
  565.         }
  566.     return NOERROR;
  567.     }
  568.     else {
  569.         return hr;
  570.     }
  571. }
  572.  
  573.  
  574. //
  575. // OnThreadCreate
  576. //
  577. // as we go active reset the stream time to zero
  578. HRESULT CBallStream::OnThreadCreate(void) {
  579.  
  580.     CAutoLock lShared(&m_cSharedState);
  581.  
  582.     m_rtSampleTime = 0;
  583.  
  584.     // we need to also reset the repeat time in case the system
  585.     // clock is turned off after m_iRepeatTime gets very big
  586.     m_iRepeatTime = m_iDefaultRepeatTime;
  587.  
  588.     // Zero the output buffer on the first frame.
  589.     m_bZeroMemory = TRUE;
  590.  
  591.     return NOERROR;
  592. }
  593.  
  594.  
  595. //
  596. // SetPaletteEntries
  597. //
  598. // If we set our palette to the current system palette + the colour we want
  599. // the system has the least amount of work to do whilst plotting our images,
  600. // if this stream is rendered to the current display. The first 'spare'
  601. // palette slot is at m_Palette[10], so put our colour there.
  602. // Also guarantees that black is always represented by zero in the frame buffer.
  603. HRESULT CBallStream::SetPaletteEntries(Colour colour) {
  604.  
  605.     CAutoLock l(m_pFilter->pStateLock());
  606.  
  607.     HDC hdc = GetDC(NULL);    // hdc for the current display.
  608.  
  609.     UINT res = GetSystemPaletteEntries(hdc, 0, iPALETTE_COLORS, (LPPALETTEENTRY) &m_Palette);
  610.  
  611.     ReleaseDC(NULL, hdc);
  612.  
  613.     if (res == 0) {
  614.         return E_FAIL;
  615.     }
  616.  
  617.     switch (colour) {
  618.     case Red:
  619.         m_Palette[10].peBlue  = 0;
  620.         m_Palette[10].peGreen = 0;
  621.         m_Palette[10].peRed   = 0xff;
  622.         break;
  623.     case Yellow:
  624.         m_Palette[10].peBlue  = 0;
  625.         m_Palette[10].peGreen = 0xff;
  626.         m_Palette[10].peRed   = 0xff;
  627.         break;
  628.     case Blue:
  629.         m_Palette[10].peBlue  = 0xff;
  630.         m_Palette[10].peGreen = 0;
  631.         m_Palette[10].peRed   = 0;
  632.         break;
  633.     case Green:
  634.         m_Palette[10].peBlue  = 0;
  635.         m_Palette[10].peGreen = 0xff;
  636.         m_Palette[10].peRed   = 0;
  637.         break;
  638.     }
  639.  
  640.     m_Palette[10].peFlags = 0;
  641.  
  642.     return NOERROR;
  643. }
  644.  
  645.