home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Jumpstart / Multimedia Microsoft Jumpstart Version 1.1a (Microsoft).BIN / develpmt / source / hotspot / viewer / drawhot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-27  |  12.5 KB  |  491 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) 1993  Microsoft Corporation.  All Rights Reserved.
  9.  * 
  10.  **************************************************************************/
  11.  
  12.  
  13. /*
  14.  * This file contains an AVI DrawProc, and various functions that the
  15.  * DrawProc calls (see the list of forward declars for a list of these
  16.  * functions; the ICAVIDrawProc is the only function visible outside
  17.  * this file).
  18.  *
  19.  * The drawproc draws red rectangles on an AVI to represent hotspots.
  20.  * The drawproc also slows down the AVI playback, because it copies the
  21.  * entire image onto a device-dependent bitmap for drawing the rectangles
  22.  *
  23.  */
  24.  
  25. #include <windows.h>
  26. #include <windowsx.h>
  27. #include <vfw.h>
  28.  
  29. #include "hotspot.h"
  30.  
  31. // junk for AVIDrawGetInfo
  32. #define SZCODE char _based(_segname("_CODE"))
  33. static SZCODE szDescription[] = "Microsoft Hotspot Draw handler";
  34. static SZCODE szName[]        = "MS Hotspot";
  35. #define FOURCC_AVIDraw      mmioFOURCC('H','O','T','T')
  36. #define VERSION_AVIDraw     0x00010000
  37.  
  38. #ifndef HUGE
  39. #define HUGE _huge
  40. #endif
  41.  
  42. // this is the structure that video for windows hangs on to for us.
  43. // We allocate it and give vfw a pointer when the drawproc is
  44. // opened, and it gives it back while the frames are being drawn.
  45. // We store such things as our DC and our pen to draw the rectangles
  46. // with in here.
  47. typedef struct
  48. {
  49.     HDRAWDIB            hdd;
  50.     HDC                 hdc;
  51.     int                 xDst;
  52.     int                 yDst;
  53.     int                 dxDst;
  54.     int                 dyDst;
  55.     int                 xSrc;
  56.     int                 ySrc;
  57.     int                 dxSrc;
  58.     int                 dySrc;
  59.     HBITMAP                hddb;
  60.     HDC                    hMemdc;
  61.     HBITMAP                hOldbmp;
  62.     HBRUSH                hBrush;
  63.     HBRUSH                hOldBrush;
  64.     HPEN                hPen;
  65.     HPEN                hOldPen;
  66.     HANDLE                hMovie;
  67.     PMOVIEINFO            lpMovie;
  68. } INSTINFO, FAR * PINSTINFO;
  69.  
  70.  
  71. // forward declars
  72. LONG FAR PASCAL _export ICAVIDrawProc(DWORD id, HDRVR hDriver,
  73.     UINT uiMessage, LPARAM lParam1, LPARAM lParam2);
  74. static LONG NEAR PASCAL AVIDrawOpen(ICOPEN FAR * icopen);
  75. static LONG NEAR PASCAL AVIDrawClose(PINSTINFO pi);
  76. static LONG NEAR PASCAL AVIDrawGetInfo(ICINFO FAR *icinfo, LONG lSize);
  77. static LONG NEAR PASCAL AVIDrawQuery(PINSTINFO pi, LPBITMAPINFOHEADER lpbiIn);
  78. static LONG NEAR PASCAL AVIDrawSuggestFormat(PINSTINFO pi, ICDRAWSUGGEST FAR *lpicd, LONG cbicd);
  79. static LONG NEAR PASCAL AVIDrawBegin(PINSTINFO pi, ICDRAWBEGIN FAR *lpicd, LONG cbicd);
  80. static LONG NEAR PASCAL AVIDraw(PINSTINFO pi, ICDRAW FAR *lpicd, LONG cbicd);
  81. static LONG NEAR PASCAL AVIDrawEnd(PINSTINFO pi);
  82. static LONG NEAR PASCAL AVIDrawChangePalette(PINSTINFO pi, LPBITMAPINFOHEADER lpbi);
  83.  
  84. // macros used by DIB stuff.
  85. // hey, we're not using DIB stuff anymore...
  86. #define WIDTHBYTES(i)     ((unsigned)((i+31)&(~31))/8)
  87. #define DIBWIDTHBYTES(bi) (DWORD)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
  88.  
  89. // Here we create a device-dependent bitmap in memory to draw into.
  90. // We'll copy the DIB onto this bitmap, draw rects on it, then copy
  91. // the result to the screen.  This can be done more efficiently using
  92. // the DIB driver that comes with Windows 3.1, if anybody wants to 
  93. // recode it...
  94. // We also create our red pen here, as well as a brush for doing
  95. // =hollow= rectangles
  96. void CreateMemoryDC(PINSTINFO pi)
  97. {
  98.     LOGBRUSH lb;
  99.     pi->hddb = CreateCompatibleBitmap(pi->hdc,pi->dxDst,pi->dyDst);
  100.     pi->hMemdc = CreateCompatibleDC(pi->hdc);
  101.     pi->hOldbmp = SelectObject(pi->hMemdc,pi->hddb);
  102.     lb.lbStyle = BS_NULL;
  103.     pi->hBrush = CreateBrushIndirect(&lb);
  104.     pi->hOldBrush = SelectObject(pi->hMemdc,pi->hBrush);
  105.     pi->hPen = CreatePen(PS_SOLID,0,RGB(255,0,0));
  106.     pi->hOldPen = SelectObject(pi->hMemdc,pi->hPen);
  107. }
  108.  
  109. // here we undo everything CreateMemoryDC did.
  110. void DisintegrateMemoryDC(PINSTINFO pi)
  111. {
  112.     SelectObject(pi->hMemdc,pi->hOldPen);
  113.     DeleteObject(pi->hPen);
  114.     SelectObject(pi->hMemdc,pi->hOldBrush);
  115.     DeleteObject(pi->hBrush);
  116.     SelectObject(pi->hMemdc,pi->hOldbmp);
  117.     DeleteObject(pi->hddb);
  118.     DeleteDC(pi->hMemdc);
  119. }
  120.  
  121. // this is the drawproc that vfw calls.  It basically just hands
  122. // stuff off to other functions later in this file.  A few things
  123. // are handled here.  This is message-handling proc just like a
  124. // Window Proc or a VBX Control Proc...
  125. LONG FAR PASCAL _export ICAVIDrawProc(DWORD id, HDRVR hDriver,
  126.     UINT uiMessage, LPARAM lParam1, LPARAM lParam2)
  127. {
  128.     PINSTINFO pi = (PINSTINFO)id;
  129.  
  130.     switch (uiMessage)
  131.     {
  132.     case DRV_LOAD:
  133.     case DRV_FREE:
  134.         return 1;
  135.     
  136.     case DRV_OPEN:
  137.         if (lParam2 == 0L)
  138.         {
  139.             // Uh-oh, no data to use...
  140.             return 1;
  141.         }
  142.         return AVIDrawOpen((ICOPEN FAR *)lParam2);
  143.     
  144.     case DRV_CLOSE:
  145.         return AVIDrawClose(pi);
  146.     
  147.     case DRV_QUERYCONFIGURE:
  148.         return 0;
  149.     case DRV_CONFIGURE:
  150.         return 1;
  151.     case ICM_CONFIGURE:
  152.     case ICM_ABOUT:
  153.         return ICERR_UNSUPPORTED;
  154.     case ICM_GETSTATE:
  155.         return 0L;
  156.         
  157.     case ICM_GETINFO:
  158.         return AVIDrawGetInfo((ICINFO FAR *)lParam1, lParam2);
  159.     
  160.     case ICM_DRAW_QUERY:
  161.         return AVIDrawQuery(pi, (LPBITMAPINFOHEADER)lParam1);
  162.     
  163.     case ICM_DRAW_SUGGESTFORMAT:
  164.         return AVIDrawSuggestFormat(pi, (ICDRAWSUGGEST FAR *) lParam1, lParam2);
  165.     
  166.     case ICM_DRAW_BEGIN:
  167.         return AVIDrawBegin(pi, (ICDRAWBEGIN FAR *) lParam1, lParam2);
  168.     
  169.     case ICM_DRAW_REALIZE:
  170.         pi->hdc = (HDC) lParam1;
  171.         if (!pi->hdc || !pi->hdd)
  172.         {
  173.             // we aren't initialized yet.
  174.             break;
  175.         }
  176.         return DrawDibRealize(pi->hdd, pi->hdc, (BOOL) lParam2);
  177.     
  178.     case ICM_DRAW_GET_PALETTE:
  179.         if (!pi->hdd)
  180.         {
  181.             break;
  182.         }
  183.         return (LONG) (UINT) DrawDibGetPalette(pi->hdd);
  184.     
  185.     case ICM_DRAW:
  186.         return AVIDraw(pi, (ICDRAW FAR *)lParam1, lParam2);
  187.     
  188.     case ICM_DRAW_CHANGEPALETTE:
  189.         return AVIDrawChangePalette(pi, (LPBITMAPINFOHEADER) lParam1);
  190.     
  191.     case ICM_DRAW_END:
  192.         return AVIDrawEnd(pi);
  193.     
  194.     case DRV_DISABLE:
  195.     case DRV_ENABLE:
  196.         return 1;
  197.     case DRV_INSTALL:
  198.     case DRV_REMOVE:
  199.         return 1;
  200.     }
  201.     if (uiMessage < DRV_USER)
  202.     {
  203.         return DefDriverProc(id,hDriver,uiMessage,lParam1,lParam2);
  204.     }
  205.     else
  206.     {
  207.         return ICERR_UNSUPPORTED;
  208.     }
  209. }
  210.  
  211.  
  212. // This basically allocates our "instance info" (that struct defined
  213. // at the beginning of this file).
  214. static LONG NEAR PASCAL AVIDrawOpen(ICOPEN FAR * icopen)
  215. {
  216.     PINSTINFO pinst;
  217.  
  218.     if (icopen->fccType != streamtypeVIDEO)
  219.     {
  220.         return 0;
  221.     }
  222.     if (icopen->dwFlags == ICMODE_COMPRESS)
  223.     {
  224.         return 0;
  225.     }
  226.     if (icopen->dwFlags == ICMODE_DECOMPRESS)
  227.     {
  228.         return 0;
  229.     }
  230.     pinst = (PINSTINFO)GlobalAllocPtr(GHND, sizeof(INSTINFO));
  231.     if (!pinst)
  232.     {
  233.         icopen->dwError = ICERR_MEMORY;
  234.         return NULL;
  235.     }
  236.     pinst->hdd = DrawDibOpen();
  237.     pinst->hddb = NULL;
  238.     icopen->dwError = ICERR_OK;
  239.     return (LONG) pinst;
  240. }
  241.  
  242. // This frees our instance structure, and everything within the
  243. // structure.
  244. static LONG NEAR PASCAL AVIDrawClose(PINSTINFO pi)
  245. {
  246.     if (pi->hdd)
  247.     {
  248.         DrawDibClose(pi->hdd);
  249.     }
  250.     if (pi->hddb)
  251.     {
  252.         DisintegrateMemoryDC(pi);
  253.     }
  254.     GlobalFreePtr(pi);
  255.     return 1;
  256. }
  257.  
  258. // When AVI gets nosy, it goes here.  We pass it those strings and
  259. // stuff defined at the top of this file.
  260. static LONG NEAR PASCAL AVIDrawGetInfo(ICINFO FAR *icinfo, LONG lSize)
  261. {
  262.     if (icinfo == NULL)
  263.     {
  264.         return sizeof(ICINFO);
  265.     }
  266.     if (lSize < sizeof(ICINFO))
  267.     {
  268.         return 0;
  269.     }
  270.     icinfo->dwSize        = sizeof(ICINFO);
  271.     icinfo->fccType        = ICTYPE_VIDEO;
  272.     icinfo->fccHandler      = FOURCC_AVIDraw;
  273.     icinfo->dwFlags        = VIDCF_DRAW;
  274.     icinfo->dwVersion       = VERSION_AVIDraw;
  275.     icinfo->dwVersionICM    = ICVERSION;
  276.     lstrcpy(icinfo->szDescription, szDescription);
  277.     lstrcpy(icinfo->szName, szName);
  278.     return sizeof(ICINFO);
  279. }
  280.  
  281. // Make sure we can handle the format given.
  282. static LONG NEAR PASCAL AVIDrawQuery(PINSTINFO pi,
  283.     LPBITMAPINFOHEADER lpbiIn)
  284. {
  285.     if (lpbiIn == NULL)
  286.     {
  287.         return ICERR_BADFORMAT;
  288.     }
  289.     if (lpbiIn->biCompression != BI_RGB)
  290.     {
  291.         return ICERR_BADFORMAT;
  292.     }
  293.     return ICERR_OK;
  294. }
  295.  
  296. // suggest BI_RGB
  297. static LONG NEAR PASCAL AVIDrawSuggestFormat(PINSTINFO pi,
  298.     ICDRAWSUGGEST FAR *lpicd, LONG cbicd)
  299. {
  300.     HIC hic;
  301.     if (lpicd->lpbiSuggest == NULL)
  302.     {
  303.         return sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
  304.     }
  305.     hic = ICGetDisplayFormat(NULL, lpicd->lpbiIn, lpicd->lpbiSuggest,
  306.         0, lpicd->dxDst, lpicd->dyDst);
  307.     if (hic)
  308.     {
  309.         ICClose(hic);
  310.     }
  311.     if (lpicd->lpbiSuggest)
  312.     {
  313.         if (lpicd->lpbiSuggest->biCompression == BI_RLE8)
  314.         {
  315.             lpicd->lpbiSuggest->biCompression = BI_RGB;
  316.         }
  317.     }
  318.     return sizeof(BITMAPINFOHEADER) + lpicd->lpbiSuggest->biClrUsed * sizeof(RGBQUAD);
  319. }
  320.  
  321. // Here, we grab DC's and stuff from vfw and stash it into our own
  322. // instance info.  We also get our movieinfo, which is the structure
  323. // that has the actual hotspots in it.  A handle to it has been stuck
  324. // on the window with SetProp, so we get the window handle and snag it
  325. // with GetProp.
  326. static LONG NEAR PASCAL AVIDrawBegin(PINSTINFO pi, ICDRAWBEGIN FAR *lpicd, LONG cbicd)
  327. {
  328.     LONG    l;
  329.  
  330.     l = AVIDrawQuery(pi, lpicd->lpbi);
  331.     if ((l != 0) || (lpicd->dwFlags & ICDRAW_QUERY))
  332.     {
  333.         return l;
  334.     }
  335.     pi->hdc = lpicd->hdc;
  336.     pi->xDst = lpicd->xDst;
  337.     pi->yDst = lpicd->yDst;
  338.     pi->dxDst = lpicd->dxDst;
  339.     pi->dyDst = lpicd->dyDst;
  340.     pi->xSrc = lpicd->xSrc;
  341.     pi->ySrc = lpicd->ySrc;
  342.     pi->dxSrc = lpicd->dxSrc;
  343.     pi->dySrc = lpicd->dySrc;
  344.     SetStretchBltMode(pi->hdc, COLORONCOLOR);
  345.     if (!DrawDibBegin(pi->hdd, pi->hdc,
  346.             pi->dxDst, pi->dyDst,
  347.             lpicd->lpbi,
  348.             pi->dxSrc, pi->dySrc,
  349.             0))
  350.     {
  351.         return ICERR_UNSUPPORTED;
  352.     }
  353.     if (pi->hddb)
  354.     {
  355.         DisintegrateMemoryDC(pi);
  356.     }
  357.     CreateMemoryDC(pi);
  358.     {
  359.         HANDLE    hglb;
  360.         hglb = GetProp(lpicd->hwnd,szDrawPropName);
  361.         if (hglb)
  362.         {
  363.             pi->lpMovie = (PMOVIEINFO) GlobalLock(hglb);
  364.             pi->hMovie = hglb;
  365.         }
  366.         else
  367.         {
  368.             pi->lpMovie = NULL;
  369.             pi->hMovie = NULL;
  370.         }
  371.     }
  372.     return ICERR_OK;
  373. }
  374.  
  375. // Several interesting things happen here:  1) We copy the DIB onto
  376. // our own bitmap (hMemDC), with DrawDibDraw, then we draw rectangles
  377. // onto that bitmap (or not) as we walk down the hotspot list (with
  378. // Rectangle), then we BitBlt the result onto the screen.  I've heard
  379. // rumors that this could be done with the DIB driver and get rid of
  380. // the extra image copy.
  381. static LONG NEAR PASCAL AVIDraw(PINSTINFO pi, ICDRAW FAR *lpicd, LONG cbicd)
  382. {
  383.     UINT  wFlags;
  384.  
  385.     wFlags = DDF_SAME_HDC;
  386.     if ((lpicd->dwFlags & ICDRAW_NULLFRAME) || lpicd->lpData == NULL)
  387.     {
  388.         if (lpicd->dwFlags & ICDRAW_UPDATE)
  389.         {
  390.             wFlags |= DDF_UPDATE;
  391.         }
  392.         else
  393.         {
  394.             return ICERR_OK;
  395.         }
  396.     }
  397.     if (lpicd->dwFlags & ICDRAW_PREROLL)
  398.     {
  399.         wFlags |= DDF_DONTDRAW;
  400.     }
  401.     if (lpicd->dwFlags & ICDRAW_HURRYUP)
  402.     {
  403.         wFlags |= DDF_HURRYUP;
  404.     }
  405.     if (pi->lpMovie)
  406.     {
  407.         if(!DrawDibDraw(pi->hdd, pi->hMemdc,
  408.                 0,0,
  409.                 pi->dxDst, pi->dyDst,
  410.                 lpicd->lpFormat,
  411.                 lpicd->lpData,
  412.                 pi->xSrc, pi->ySrc,
  413.                 pi->dxSrc, pi->dySrc,
  414.                 wFlags))
  415.         {
  416.             OutputDebugString("Error: DrawDibDraw Bombed!\n");
  417.         }
  418.         else
  419.         {
  420.             PHOTSPOT pHotspot;
  421.  
  422.             pHotspot = (pi->lpMovie)->pHotspotList;
  423.             while (pHotspot)
  424.             {
  425.                 if ((pHotspot->BeginFrame < lpicd->lTime) &&
  426.                         (pHotspot->EndFrame > lpicd->lTime))
  427.                 {
  428.                     Rectangle(pi->hMemdc,
  429.                         pHotspot->rc.left,
  430.                         pHotspot->rc.top,
  431.                         pHotspot->rc.right,
  432.                         pHotspot->rc.bottom);
  433.                 }
  434.                 pHotspot = pHotspot->pNext;
  435.             }
  436.             BitBlt(pi->hdc,pi->xDst,pi->yDst,pi->dxDst,pi->dyDst,
  437.                 pi->hMemdc,0,0,SRCCOPY);
  438.         }
  439.     }
  440.     else if (!DrawDibDraw(pi->hdd, pi->hdc,
  441.             pi->xDst, pi->yDst,
  442.             pi->dxDst, pi->dyDst,
  443.             lpicd->lpFormat,
  444.             lpicd->lpData,
  445.             pi->xSrc, pi->ySrc,
  446.             pi->dxSrc, pi->dySrc,
  447.             wFlags))
  448.     {
  449.         if (wFlags & DDF_UPDATE)
  450.         {
  451.             return ICERR_CANTUPDATE;
  452.         }
  453.         else
  454.         {
  455.             return ICERR_UNSUPPORTED;
  456.         }
  457.     }
  458.     return ICERR_OK;
  459. }
  460.  
  461. // Give the pallette back to vfw with DrawDibChangePallette
  462. static LONG NEAR PASCAL AVIDrawChangePalette(PINSTINFO pi, LPBITMAPINFOHEADER lpbi)
  463. {
  464.     PALETTEENTRY    ape[256];
  465.     LPRGBQUAD        lprgb;
  466.     int i;
  467.  
  468.     lprgb = (LPRGBQUAD) ((LPBYTE) lpbi + lpbi->biSize);
  469.     for (i = 0; i < (int) lpbi->biClrUsed; i++)
  470.     {
  471.         ape[i].peRed = lprgb[i].rgbRed;
  472.         ape[i].peGreen = lprgb[i].rgbGreen;
  473.         ape[i].peBlue = lprgb[i].rgbBlue;
  474.         ape[i].peFlags = 0;
  475.     }
  476.     DrawDibChangePalette(pi->hdd, 0, (int) lpbi->biClrUsed,
  477.         (LPPALETTEENTRY)ape);
  478.     return ICERR_OK;
  479. }
  480.  
  481. // Here we unlock the movie we locked in AVIDrawBegin.  Everything
  482. // else is freed in AVIDrawClose.
  483. static LONG NEAR PASCAL AVIDrawEnd(PINSTINFO pi)
  484. {
  485.     if (pi->hMovie)
  486.     {
  487.         GlobalUnlock(pi->hMovie);
  488.     }
  489.     return ICERR_OK;
  490. }
  491.