home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / video / textout / txtout.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  15KB  |  533 lines

  1. /****************************************************************************
  2.  *
  3.  *   TxtOut.c
  4.  *
  5.  *   TXTOUT is a sample installable compressor for AVI 1.0.
  6.  *
  7.  ***************************************************************************/
  8. /**************************************************************************
  9.  *
  10.  *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  11.  *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  12.  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  13.  *  PURPOSE.
  14.  *
  15.  *  Copyright (C) 1992 - 1997 Microsoft Corporation.  All Rights Reserved.
  16.  *
  17.  **************************************************************************/
  18.  
  19. #define INC_OLE2
  20. #include <windows.h>
  21. #include <windowsx.h>
  22. #include <mmsystem.h>
  23. #include <vfw.h>
  24. #include <stdlib.h> // for mbstowcs
  25. #include <memory.h> // for _fmemcpy
  26. #include <stdarg.h> // for va_list
  27.  
  28. #include "TxtOut.h"
  29.  
  30. /*****************************************************************************
  31.  *
  32.  *
  33.  ****************************************************************************/
  34.  
  35. #define MODNAME         "TXTOUT"
  36. #define FOURCC_SAMP mmioFOURCC('D','R','A','W')
  37.  
  38. #define VERSION_SAMP    0x00010000 // 1.00
  39.  
  40. extern HANDLE ghModule;
  41.  
  42.  
  43. /*****************************************************************************
  44.  *
  45.  * DefaultState holds the compression options that will be used if the user
  46.  * compresses an image without configuring us at all first. In the case of
  47.  * the sample compressor, it is the pixel keep ratio.
  48.  *
  49.  ****************************************************************************/
  50.  
  51. ICSTATE DefaultState = {2};
  52.  
  53.  
  54. /*****************************************************************************
  55.  *
  56.  * Load() is called from the ICM_LOAD message.
  57.  *
  58.  * Tasks such as allocating global memory that is non-instance specific
  59.  * or initializing coprocessor hardware may be performed here.
  60.  *
  61.  * Our simple case needs none of this.
  62.  *
  63.  ****************************************************************************/
  64. BOOL NEAR PASCAL Load(void)
  65. {
  66.     DPF2("Load()");
  67.     return TRUE;
  68. }
  69.  
  70. /*****************************************************************************
  71.  *
  72.  * Free() is called from the ICM_FREE message.
  73.  *
  74.  * It should totally reverse the effects of Load() in preparation for
  75.  * the DRV being removed from memory.
  76.  *
  77.  ****************************************************************************/
  78. void NEAR PASCAL Free(void)
  79. {
  80.     DPF2("Free()");
  81. }
  82.  
  83. /*****************************************************************************
  84.  *
  85.  * Open() is called from the ICM_OPEN message
  86.  *
  87.  * This message will be sent for a particular compress/decompress session.
  88.  * Our code must verify that we are indeed being called as a video
  89.  * compressor and create/initialize a state structure. The ICM will
  90.  * give us back the pointer to that structure on every message dealing
  91.  * with this session.
  92.  *
  93.  ****************************************************************************/
  94. INSTINFO * NEAR PASCAL Open(
  95.     ICOPEN FAR * icinfo)
  96. {
  97.     INSTINFO * pinst;
  98.  
  99.     DPF2("Open('%4.4hs', '%4.4hs')", &icinfo->fccType, &icinfo->fccHandler);
  100.  
  101.     //
  102.     // refuse to open if we are not being opened as a Video compressor
  103.     //
  104.     if (icinfo->fccType != streamtypeTEXT) {
  105.         DPF2("Open rejected: not TEXT");
  106.         return NULL;
  107.     }
  108.  
  109.     pinst = (INSTINFO *)LocalAlloc(LPTR, sizeof(INSTINFO));
  110.  
  111.     if (!pinst) {
  112.         icinfo->dwError = ICERR_MEMORY;
  113.         DPF2("Open rejected: no memory");
  114.         return NULL;
  115.     }
  116.  
  117.     //
  118.     // init structure
  119.     //
  120.     pinst->dwFlags = icinfo->dwFlags;
  121.     pinst->nDraw = 0;
  122.     pinst->hfont = GetStockFont(ANSI_VAR_FONT);
  123.  
  124.     //
  125.     // set the default state.
  126.     //
  127.     SetState(pinst, NULL, 0);
  128.  
  129.     //
  130.     // return success.
  131.     //
  132.     icinfo->dwError = ICERR_OK;
  133.  
  134.     DPF2("Open succeeded!");
  135.     return pinst;
  136. }
  137.  
  138. /*****************************************************************************
  139.  *
  140.  * Close() is called on the ICM_CLOSE message.
  141.  *
  142.  * This message is the complement to ICM_OPEN and marks the end
  143.  * of a compress/decompress session. We kill any in-progress operations
  144.  * (although this shouldn't be needed) and free our instance structure.
  145.  *
  146.  ****************************************************************************/
  147. LRESULT NEAR PASCAL Close(
  148.     INSTINFO * pinst)
  149. {
  150.     DPF2("Close()");
  151.  
  152.     while (pinst->nDraw > 0)
  153.         DrawEnd(pinst);
  154.     LocalFree((HLOCAL)pinst);
  155.     return 1;
  156. }
  157.  
  158. /*****************************************************************************
  159.  *
  160.  * QueryAbout() and About() handle the ICM_ABOUT message.
  161.  *
  162.  * QueryAbout() returns TRUE to indicate we support an about box.
  163.  * About() displays the box.
  164.  *
  165.  ****************************************************************************/
  166. BOOL NEAR PASCAL QueryAbout(
  167.     INSTINFO * pinst)
  168. {
  169.     DPF2("QueryAbout()");
  170.  
  171.     return TRUE;
  172. }
  173.  
  174. LRESULT NEAR PASCAL About(
  175.     INSTINFO * pinst,
  176.     HWND hwnd)
  177. {
  178.     char sztempName[50];
  179.     char sztempDesc[50];
  180.  
  181.     LoadString(ghModule, IDS_NAME, sztempName, sizeof sztempName);
  182.     LoadString(ghModule, IDS_DESCRIPTION, sztempDesc, sizeof sztempDesc);
  183.     DPF2("About()");
  184.     MessageBox(hwnd, sztempDesc, sztempName, MB_OK|MB_ICONINFORMATION);
  185.     return ICERR_OK;
  186. }
  187.  
  188. /*****************************************************************************
  189.  *
  190.  * QueryConfigure() and Configure() implement the ICM_CONFIGURE message.
  191.  *
  192.  * These functions put up a dialog that allows the user, if he so
  193.  * chooses, to modify the configuration portion of our state info.
  194.  *
  195.  ****************************************************************************/
  196. BOOL NEAR PASCAL QueryConfigure(
  197.     INSTINFO * pinst)
  198. {
  199.     DPF2("QueryConfigure()");
  200.     return FALSE;
  201. }
  202.  
  203. LRESULT NEAR PASCAL Configure(
  204.     INSTINFO * pinst,
  205.     HWND hwnd)
  206. {
  207.     DPF2("Configure()");
  208.     return DialogBoxParam(ghModule,"Configure",hwnd,ConfigureDlgProc, (LONG)(UINT)pinst);
  209. }
  210.  
  211. /*****************************************************************************
  212.  *
  213.  * GetState() implements the ICM_GETSTATE message.
  214.  *
  215.  * We copy our configuration information and return how many bytes it took.
  216.  *
  217.  ****************************************************************************/
  218. LRESULT NEAR PASCAL GetState(
  219.     INSTINFO * pinst,
  220.     LPVOID pv,
  221.     DWORD dwSize)
  222. {
  223.     DPF2("GetState(%08lX, %ld)", pv, dwSize);
  224.  
  225.     if (pv == NULL || dwSize == 0)
  226.         return sizeof(ICSTATE);
  227.  
  228.     if (dwSize < sizeof(ICSTATE))
  229.         return 0;
  230.  
  231.     *((ICSTATE FAR *)pv) = pinst->CurrentState;
  232.  
  233.     // return number of bytes copied
  234.     return sizeof(ICSTATE);
  235. }
  236.  
  237. /*****************************************************************************
  238.  *
  239.  * SetState() implements the ICM_SETSTATE message.
  240.  *
  241.  * The ICM is giving us configuration information saved by GetState()
  242.  * earlier.
  243.  *
  244.  ****************************************************************************/
  245. LRESULT NEAR PASCAL SetState(
  246.     INSTINFO * pinst,
  247.     LPVOID pv,
  248.     DWORD dwSize)
  249. {
  250.     DPF2("SetState(%08lX, %ld)", pv, dwSize);
  251.  
  252.     if (pv == NULL)
  253.         pinst->CurrentState = DefaultState;
  254.     else if (dwSize >= sizeof(ICSTATE))
  255.         pinst->CurrentState = *((ICSTATE FAR *)pv);
  256.     else
  257.         return 0;
  258.  
  259.     // return number of bytes copied
  260.     return sizeof(ICSTATE);
  261. }
  262.  
  263. /*****************************************************************************
  264.  *
  265.  * GetInfo() implements the ICM_GETINFO message
  266.  *
  267.  * We just fill in the structure to tell the ICM what we can do. The flags
  268.  * (none of which this sample supports) mean the following :
  269.  *
  270.  * VIDCF_QUALITY - we support the quality variable. This means we look at
  271.  *                 dwQuality in the ICINFO structure when compressing and
  272.  *                 make a concious decision to trade quality for space.
  273.  *                 (higher values of dwQuality mean quality is more
  274.  *                 important). dwQuality is set by the ICM.
  275.  *
  276.  * VIDCF_TEMPORAL - We do interframe compression. In this algorithm, not
  277.  *                  every frame is a "key frame"; some frames depend on
  278.  *                  other frames to be generated. An example of this might
  279.  *                  be to store frame buffer differences until the
  280.  *                  differences are big enough to no longer make this
  281.  *                  worthwhile, then storing another complete frame and
  282.  *                  starting over. In this case, the complete frames that
  283.  *                  are stored are key frames and should be flagged as
  284.  *                  such.
  285.  *
  286.  * VIDCF_DRAW -     We will draw the decompressed image on our own. This is
  287.  *                  useful if the decompression is assisted by the video
  288.  *                  hardware.
  289.  *
  290.  ****************************************************************************/
  291. LRESULT NEAR PASCAL GetInfo(
  292.     INSTINFO * pinst,
  293.     ICINFO FAR *icinfo,
  294.     DWORD dwSize)
  295. {
  296.     char sztempName[50];
  297.     char sztempDesc[50];
  298.  
  299.     LoadString(ghModule, IDS_NAME, sztempName, sizeof sztempName);
  300.     LoadString(ghModule, IDS_DESCRIPTION, sztempDesc, sizeof sztempDesc);
  301.     DPF2("GetInfo()");
  302.  
  303.     if (icinfo == NULL)
  304.         return sizeof(ICINFO);
  305.  
  306.     if (dwSize < sizeof(ICINFO))
  307.         return 0;
  308.  
  309.     icinfo->dwSize      = sizeof(ICINFO);
  310.     icinfo->fccType     = streamtypeTEXT;
  311.     icinfo->fccHandler  = FOURCC_SAMP;
  312.     icinfo->dwFlags     = VIDCF_DRAW;
  313.  
  314.                 // VIDCF_QUALITY    // supports quality
  315.                 // VIDCF_TEMPORAL   // supports inter-frame
  316.                 // VIDCF_DRAW       // supports drawing
  317.  
  318.     icinfo->dwVersion   = VERSION_SAMP;
  319.     icinfo->dwVersionICM    = ICVERSION;
  320.     mbstowcs(icinfo->szDescription, sztempDesc, sizeof sztempDesc);
  321.     mbstowcs(icinfo->szName, sztempName, sizeof sztempName);
  322.  
  323.     return sizeof(ICINFO);
  324. }
  325.  
  326.  
  327. LRESULT NEAR PASCAL DrawQuery(
  328.     INSTINFO * pinst,
  329.     LPVOID FAR * lpFormat)
  330. {
  331.     return ICERR_OK;
  332. }
  333.  
  334. /*****************************************************************************
  335.  *
  336.  * DrawBegin() implements ICM_DRAW_BEGIN
  337.  *
  338.  * This is just like DecompressBegin() except that we also must prepare to
  339.  * actually draw the bitmap on the screen. ICDRAWBEGIN provides info specific
  340.  * to this task.
  341.  *
  342.  ****************************************************************************/
  343. LRESULT NEAR PASCAL DrawBegin(
  344.     INSTINFO * pinst,
  345.     ICDRAWBEGIN FAR *icinfo,
  346.     DWORD dwSize)
  347. {
  348.     DPF2("DrawBegin()");
  349.  
  350.     if (pinst->nDraw++ > 0)
  351.         return ICERR_OK;
  352.  
  353.     //
  354.     // get ready to draw
  355.     //
  356.     pinst->db = *icinfo;
  357.     SetRect(&pinst->rc, icinfo->xDst, icinfo->yDst,
  358.         icinfo->xDst + icinfo->dxDst, icinfo->yDst + icinfo->dyDst);
  359.  
  360.     return ICERR_OK;
  361. }
  362.  
  363. /*****************************************************************************
  364.  *
  365.  * Draw implements ICM_DRAW
  366.  *
  367.  * Decompress and draw
  368.  *
  369.  ****************************************************************************/
  370. LRESULT NEAR PASCAL Draw(
  371.     INSTINFO * pinst,
  372.     ICDRAW FAR *icinfo,
  373.     DWORD dwSize)
  374. {
  375.     HFONT hfont;
  376.  
  377.     DPF2("Draw()");
  378.  
  379.     if (icinfo->lpData && icinfo->cbData) {
  380.         pinst->iLen = min((int) icinfo->cbData,
  381.                 (int) _fstrlen((LPSTR) icinfo->lpData));
  382.         pinst->iLen = min(pinst->iLen, BUFFER_SIZE - 1);
  383.         hmemcpy(pinst->achBuffer, icinfo->lpData, pinst->iLen);
  384.         pinst->achBuffer[pinst->iLen] = '\0';
  385.     } else if (!(icinfo->dwFlags & ICDRAW_UPDATE))
  386.         return ICERR_OK;
  387.     if (pinst->nDraw == 0)
  388.         return ICERR_ERROR;
  389.  
  390.     hfont = SelectFont(pinst->db.hdc, pinst->hfont);
  391.  
  392.     ExtTextOut(pinst->db.hdc,
  393.         pinst->db.xDst, pinst->db.yDst,
  394.         ETO_OPAQUE,
  395.         &pinst->rc,
  396.         (LPSTR) pinst->achBuffer,
  397.         pinst->iLen,
  398.         NULL);
  399.  
  400.     SelectFont(pinst->db.hdc, hfont);
  401.  
  402.     return ICERR_OK;
  403. }
  404.  
  405. /*****************************************************************************
  406.  *
  407.  * DrawEnd() implements ICM_DRAW_END
  408.  *
  409.  * See DecompressEnd()
  410.  *
  411.  ****************************************************************************/
  412. LRESULT NEAR PASCAL DrawEnd(
  413.     INSTINFO * pinst)
  414. {
  415.     DPF2("DrawEnd()");
  416.  
  417.     if (pinst->nDraw == 0)
  418.         return ICERR_ERROR;
  419.  
  420.     if (--pinst->nDraw > 0)
  421.         return ICERR_OK;
  422.  
  423.     //
  424.     // but if we did we would clean up here
  425.     //
  426.  
  427.     return ICERR_OK;
  428. }
  429.  
  430. /*****************************************************************************
  431.  *
  432.  * ConfigureDlgProc() is called by Configure
  433.  *
  434.  * This is a standard dialog proc which allows the user to
  435.  * pick config options for the driver.
  436.  *
  437.  ****************************************************************************/
  438. BOOL CALLBACK ConfigureDlgProc(
  439.     HWND hdlg,
  440.     UINT msg,
  441.     WPARAM wParam,
  442.     LPARAM lParam)
  443. {
  444.     switch (msg)
  445.     {
  446.     case WM_COMMAND:
  447.         switch LOWORD((wParam))
  448.         {
  449.             case IDOK:
  450.                 EndDialog(hdlg,TRUE);
  451.                 break;
  452.  
  453.             case IDCANCEL:
  454.                 EndDialog(hdlg,FALSE);
  455.                 break;
  456.         }
  457.         break;
  458.     }
  459.     return FALSE;
  460. }
  461.  
  462. /*****************************************************************************
  463.  *
  464.  * dprintf() is called by the DPF macro if DEBUG is defined at compile time.
  465.  *
  466.  * The messages will be send to COM1: like any debug message. To
  467.  * enable debug output, add the following to WIN.INI :
  468.  *
  469.  * [debug]
  470.  * TXTOUT=1
  471.  *
  472.  ****************************************************************************/
  473.  
  474. #ifdef DEBUG
  475. static int iDebug = -1;
  476.  
  477. void FAR cdecl dprintf(
  478.     LPSTR szFormat,
  479.     ...)
  480. {
  481.     char ach[128];
  482.  
  483.     if (iDebug == -1)
  484.         iDebug = GetProfileInt("Debug", MODNAME, FALSE);
  485.  
  486.     if (!iDebug)
  487.         return;
  488.  
  489.     lstrcpy(ach, MODNAME ": ");
  490.  
  491.     {
  492.         va_list va;
  493.  
  494.         va_start(va, szFormat);
  495.         wvsprintf(ach+lstrlen(ach), szFormat, va);
  496.         va_end(va);
  497.  
  498.     }
  499.  
  500.     lstrcat(ach, "\r\n");
  501.     OutputDebugString(ach);
  502. }
  503.  
  504. void FAR cdecl dprintf2(
  505.     LPSTR szFormat,
  506.     ...)
  507. {
  508.     char ach[128];
  509.  
  510.     if (iDebug == -1)
  511.         iDebug = GetProfileInt("Debug", MODNAME, FALSE);
  512.  
  513.     if (iDebug < 2)
  514.         return;
  515.  
  516.     lstrcpy(ach, MODNAME ": ");
  517.  
  518.     {
  519.         va_list va;
  520.  
  521.         va_start(va, szFormat);
  522.         wvsprintf(ach+lstrlen(ach), szFormat, va);
  523.         va_end(va);
  524.  
  525.     }
  526.  
  527.     lstrcat(ach, "\r\n");
  528.  
  529.     OutputDebugString(ach);
  530. }
  531.  
  532. #endif
  533.