home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / gdi / textfx / fx.c next >
C/C++ Source or Header  |  1997-10-05  |  13KB  |  321 lines

  1. /*****************************************************************************\
  2. *       This is a part of the Microsoft Source Code Samples.
  3. *       Copyright (C) 1992-1997 Microsoft Corporation.
  4. *       All rights reserved.
  5. *       This source code is only intended as a supplement to
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the
  8. *       Microsoft samples programs.
  9. \*****************************************************************************/
  10. /*****************************************************************************
  11.  *                                                                             *
  12.  *    FX.C                                                                      *
  13.  *                                                                             *
  14.  *    PURPOSE:  Routines for rendering text with stange effects                *
  15.  *                                                                             *
  16.  *                                                                             *
  17.  *    FillOut               - Converts an array of line segments into an array of *
  18.  *                       all the points in the segments                         *
  19.  *                                                                             *
  20.  *    RenderPathPoints   - Renders the outline of points returned from GetPath * 
  21.  *                                                                             *
  22.  *    RenderAndFillPath  - Renders the points returned from GetPath as a       *
  23.  *                       filled polygon                                         *
  24.  *                                                                             *
  25.  *    TextEffect         - Draws a string of text between two guide lines      *
  26.  *                                                                             *
  27.  *****************************************************************************/
  28.  
  29. #include <windows.h>
  30. #include "fx.h"
  31.  
  32. // This structure is used by FillOut for passing data into LineDDA
  33. typedef struct tagSEG {
  34.   DWORD dwPos;
  35.   LPPOINT lpPoints; 
  36. } PTS;
  37.  
  38. /**********************************************************************
  39.  *                                                                    *
  40.  * AddSegment - used with LineDDA to add points from a line segment   *
  41.  *    to an array containing all the points on a set of line segments *
  42.  *                                                                    *
  43.  *********************************************************************/
  44. VOID CALLBACK AddSegment(int x, int y, PTS *pts)
  45. {
  46.    pts->lpPoints[pts->dwPos].x = x;
  47.    pts->lpPoints[pts->dwPos].y = y;
  48.    pts->dwPos++;
  49.  
  50. /**********************************************************************
  51.  *                                                                    *
  52.  * CountPoints - used with LineDDA to determine the number of points  *
  53.  *    needed to store all the points on a set of line segments        *
  54.  *                                                                    *
  55.  *********************************************************************/
  56. VOID CALLBACK CountPoints(int x, int y, LPDWORD lpdwNumPts)
  57. {
  58.    (*lpdwNumPts)++;
  59.  
  60.    UNREFERENCED_PARAMETER(x);
  61.    UNREFERENCED_PARAMETER(y);
  62.  
  63.  
  64. /**********************************************************************
  65.  *                                                                    *
  66.  * FUNCTION:  FillOut(LPPOINT, LPDWORD)                               *
  67.  *                                                                      *
  68.  * PURPOSE:   Converts an array of line segments into an array of all *
  69.  *            of the points comprising the line segments.             *
  70.  *                                                                    *
  71.  *********************************************************************/
  72. BOOL FillOut(LPPOINT *lpPoints, LPDWORD lpdwNumPts)
  73. {
  74.    DWORD i;
  75.    LPPOINT lpPts = *lpPoints;
  76.    PTS pts;
  77.    DWORD dwNumPts = 0;
  78.  
  79.    // Make sure we have at least two points
  80.    if (*lpdwNumPts < 2) {
  81.      MessageBox(NULL, "You need at least two points for a guide line.", "Not enough points!", MB_ICONSTOP);
  82.      *lpdwNumPts = 0;
  83.      return FALSE;
  84.    }
  85.  
  86.    // Find out how namy points are on the segments
  87.    for (i=0; i<*lpdwNumPts - 1; i++) 
  88.      LineDDA(lpPts[i].x, lpPts[i].y, lpPts[i+1].x, lpPts[i+1].y, (LINEDDAPROC)CountPoints, (LPARAM)&dwNumPts);
  89.    
  90.    // If there are too many points, print an anoying message so the user doesnt do it again
  91.    if (dwNumPts > MAXFILLPOINTS) {
  92.      MessageBox(NULL, "Make your guide lines a bit shorter please!", "Too many points!", MB_ICONSTOP);
  93.      *lpdwNumPts = 0;
  94.      return FALSE;  // Bail
  95.    }
  96.    
  97.    // Allocate memory for the the points and initialize our "last point" index
  98.    pts.lpPoints = (LPPOINT)GlobalAlloc(GPTR, dwNumPts * sizeof(POINT));
  99.    pts.dwPos = 0;
  100.                                                                     
  101.    // Convert the segments to points
  102.    for (i=0; i<*lpdwNumPts - 1; i++) 
  103.      LineDDA(lpPts[i].x, lpPts[i].y, lpPts[i+1].x, lpPts[i+1].y, (LINEDDAPROC)AddSegment, (LPARAM)&pts);
  104.    
  105.    // Get rid of the original array of segments...
  106.    GlobalFree(lpPts);
  107.  
  108.    // ... and replace it with the new points
  109.    *lpPoints = pts.lpPoints;
  110.    *lpdwNumPts = pts.dwPos;
  111.    
  112.    // Check to see if anything hit the fan
  113.    if (!pts.dwPos)
  114.      return FALSE;
  115.  
  116.    return TRUE;  
  117. }
  118.  
  119. /**********************************************************************
  120.  *                                                                    *
  121.  * FUNCTION:  PolyDraw95(HDC, LPPOINT, LPBYTE, int)                   *
  122.  *                                                                      *
  123.  * PURPOSE:   Draws the points returned from a call to GetPath()      *
  124.  *            to an HDC                                               *
  125.  *                                                                    *
  126.  * NOTES:     This function is similar to the Windows NT function     *
  127.  *            PolyDraw which draws a set of line segments and BΘzier  *
  128.  *            curves.  Since PolyDraw is not supported on Windows 95  *
  129.  *            this PolyDraw95 is used instead.                        *  
  130.  *                                                                    *
  131.  *********************************************************************/
  132. BOOL PolyDraw95(HDC  hdc,              // handle of a device context 
  133.                 CONST LPPOINT lppt,       // address of array of points 
  134.                 CONST LPBYTE lpbTypes, // address of line and curve identifiers  
  135.                 int  cCount)            // count of points 
  136. {
  137.   int i;
  138.   
  139.   for (i=0; i<cCount; i++) 
  140.     switch (lpbTypes[i]) {
  141.       case PT_MOVETO : 
  142.          MoveToEx(hdc, lppt[i].x, lppt[i].y, NULL); 
  143.          break;
  144.       
  145.       case PT_LINETO | PT_CLOSEFIGURE:
  146.       case PT_LINETO : 
  147.          LineTo(hdc, lppt[i].x, lppt[i].y); 
  148.          break;
  149.       
  150.       case PT_BEZIERTO | PT_CLOSEFIGURE:
  151.       case PT_BEZIERTO :
  152.          PolyBezierTo(hdc, &lppt[i], 3);
  153.          i+=2;
  154.          break;
  155.    }
  156.  
  157.    return TRUE;
  158. }  
  159.  
  160.  
  161. /**********************************************************************
  162.  *                                                                    *
  163.  * FUNCTION:  RenderPathPoints(HDC, LPPOINT, LPBYTE, int, BOOL)          *
  164.  *                                                                      *
  165.  * PURPOSE:   Renders the points returned from a call to GetPath()    *
  166.  *            by converting them back into a path and calling either  *
  167.  *            FillPath or StrokePath to display them.                 *
  168.  *                                                                    *
  169.  * NOTE:      The R2_MERGEPENNOT is used here so that things like the *
  170.  *            inside of and "a" or an "o" get painted correctly when  *
  171.  *            using FillPath.                                         *
  172.  *                                                                    *
  173.  *********************************************************************/
  174. BOOL RenderPathPoints(HDC hDC, LPPOINT lpPoints, LPBYTE lpTypes, int iNumPts, BOOL bOutline)
  175. {
  176.   BeginPath(hDC); // Draw into a path so that we can use FillPath()
  177.  
  178.   PolyDraw95(hDC, lpPoints, lpTypes, iNumPts);
  179.  
  180.   CloseFigure(hDC);
  181.   EndPath(hDC);   
  182.  
  183.   // Draw the path
  184.   if (bOutline)  
  185.     StrokePath(hDC); // As an outline
  186.   else 
  187.       {              // As solid figures
  188.         int iROP2 = SetROP2(hDC, R2_MERGEPENNOT);
  189.         HPEN hPen = SelectObject(hDC, GetStockObject(NULL_PEN)); // Just say "no" to outlines
  190.         HBRUSH hBrush = SelectObject(hDC, GetStockObject(BLACK_BRUSH)); // Paint It Black
  191.  
  192.         FillPath(hDC);  
  193.  
  194.         // Restore the DC to its previous state
  195.         SetROP2(hDC, iROP2);        
  196.         SelectObject(hDC, hPen);
  197.         SelectObject(hDC, hBrush);
  198.       } 
  199.   
  200.   return TRUE;
  201. }
  202.  
  203.  
  204. /**********************************************************************
  205.  *                                                                    *
  206.  * FUNCTION:  GetRealTextExtent(LPPOINT, int, LPSIZE)                 *
  207.  *                                                                      *
  208.  * PURPOSE:   Makes sure that the extents in a SIZE are large enough  *
  209.  *            to bound the points in an array.                        *
  210.  *                                                                    *
  211.  * NOTES:     Why not just use GetTextExtentPoint32?  Well, the text  *
  212.  *            extents returned by GetTextExtentPoint32 dont include   *
  213.  *            the overhang of an italics character into the next      *
  214.  *            cell.  This function expands the extents to include     *
  215.  *            the greatest x, and y extents of the string data.       *
  216.  *                                                                    *
  217.  *********************************************************************/
  218. void GetRealTextExtent(LPPOINT lpPoints, int iNumPts, LPSIZE size)
  219. {
  220.   int i;
  221.  
  222.   for (i=0; i<iNumPts; i++) {
  223.     if (lpPoints[i].x > size->cx) size->cx = lpPoints[i].x;
  224.     if (lpPoints[i].y > size->cy) size->cy = lpPoints[i].y;
  225.   }
  226. }
  227.  
  228. /**********************************************************************
  229.  *                                                                    *
  230.  * FUNCTION:  TextEffect(HDC, LPPOINT, LPPOINT, DWORD, DWORD,         *
  231.  *                            LPSTR, BOOL)                            *
  232.  *                                                                      *
  233.  * PURPOSE:   Draws a string of text in the currently selected font   *
  234.  *            using two arrays of points as guide lines for orienting *
  235.  *            the text.  The text can be displayed either as outlines *
  236.  *            or as filled characters.                                *
  237.  *                                                                    *
  238.  *********************************************************************/
  239. BOOL TextEffect(HDC hDC,            // DC to display into
  240.                 LPPOINT lpTop,      // Top guide line
  241.                 LPPOINT lpBot,         // Bottom guide line
  242.                 DWORD dwTopPts,     // Number of points in top guide
  243.                 DWORD dwBotPts,     // Number of points in bottom guide
  244.                 LPSTR szText,         // Text string to apply effects to
  245.                 BOOL bOutlineOnly)  // Print as outline or as solid text
  246. {
  247.    LPPOINT lpPoints;          // Path data points
  248.    LPBYTE lpTypes;              // Path data types
  249.    int i, iNumPts;
  250.    SIZE size;                  // Text size info
  251.    float fXScale, fYScale;      // Scaling values
  252.    int iTopInd, iBotInd;      // Guide array indices
  253.  
  254.    // Set to transparent so we dont get an outline around the text string
  255.    SetBkMode(hDC, TRANSPARENT);
  256.       
  257.    // Output the text into a path
  258.    BeginPath(hDC);
  259.    TextOut(hDC, 0, 0, szText, strlen(szText));
  260.    EndPath(hDC);    
  261.       
  262.    // How many points are in the path
  263.    iNumPts = GetPath(hDC, NULL, NULL, 0);
  264.    if (iNumPts == -1) return FALSE;
  265.  
  266.    // Allocate room for the points
  267.    lpPoints = (LPPOINT)GlobalAlloc(GPTR, sizeof(POINT) * iNumPts);
  268.    if (!lpPoints) return FALSE;
  269.  
  270.    // Allocate room for the point types
  271.    lpTypes = GlobalAlloc(GPTR, iNumPts);
  272.    if (!lpTypes) {
  273.      GlobalFree(lpPoints);
  274.        return FALSE;
  275.    }
  276.    
  277.    // Get the points and types from the current path
  278.    iNumPts = GetPath(hDC, lpPoints, lpTypes, iNumPts);
  279.  
  280.    // Even more error checking
  281.    if (iNumPts == -1) {
  282.      GlobalFree(lpTypes);
  283.      GlobalFree(lpPoints);
  284.      return FALSE;
  285.    }
  286.    
  287.    //Get extents of the text string for scaling purposes  
  288.    GetTextExtentPoint32(hDC, szText, strlen(szText), &size);
  289.  
  290.    // OK, but lets make sure our extents are big enough (handle italics fonts)
  291.    GetRealTextExtent(lpPoints, iNumPts, &size);
  292.    
  293.    // Relocate the points in the path based on the guide lines
  294.    for (i=0; i < iNumPts; i++) {
  295.         // How far along is this point on the x-axis
  296.      fXScale = (float)lpPoints[i].x / (float)size.cx;
  297.  
  298.      // What point on the top guide does this coorespond to
  299.      iTopInd = (int)(fXScale * (dwTopPts-1));
  300.      // What point on the bottom guide does this coorespond to
  301.      iBotInd = (int)(fXScale * (dwBotPts-1));
  302.  
  303.      // How far along is this point on the y-axis
  304.      fYScale = (float)lpPoints[i].y / (float)size.cy;
  305.  
  306.      // Scale the points to their new locations
  307.      lpPoints[i].x = (int)((lpBot[iBotInd].x * fYScale) + (lpTop[iTopInd].x * (1.0f-fYScale)));
  308.      lpPoints[i].y = (int)((lpBot[iBotInd].y * fYScale) + (lpTop[iTopInd].y * (1.0f-fYScale)));
  309.    }
  310.  
  311.    // Draw the new path 
  312.    RenderPathPoints(hDC, lpPoints, lpTypes, iNumPts, bOutlineOnly);
  313.    
  314.    GlobalFree(lpPoints);
  315.    GlobalFree(lpTypes);
  316.  
  317.    return TRUE;
  318. }
  319.