home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / w3_prog / ddjwin.arj / BITBLT.ASC next >
Encoding:
Text File  |  1991-11-14  |  15.1 KB  |  492 lines

  1. _QUICK APPROXIMATIONS OF POLYGONAL AREAS USING BITBLT_
  2. by Nancy Nicolaisen
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7.  
  8. ; Parameters:
  9. ; BP+6 = Offset to bits
  10. ; BP+8 = Bitmap Height in scan lines
  11. ; BP+10 = Bitmap width in pixels
  12. ; Local Data
  13. ; BP-2 = hiword of the bit count
  14. ; BP-4 = loword of the bit count
  15.  
  16. .8086
  17. .MODEL    MEDIUM
  18. memM    EQU 1
  19. INCLUDE CMACROS.INC
  20.  
  21. .CODE
  22.     PUBLIC  _COUNT_BITS
  23.  
  24. _COUNT_BITS  PROC
  25.         PUSH    BP        ; Preserve BP
  26.         MOV    BP, SP        ; Set stack frame pointer
  27.         SUB    SP, 4        ; This will hold our byte count
  28.         PUSH    DI        ; Preserve DI
  29.         PUSH    SI        ; Preserve SI
  30.  
  31.         SUB    AX, AX        ;Zero the accumulator reg
  32.         MOV    [BP-2], AX    ;Zero the local
  33.         MOV    [BP-4], AX    ; storage
  34.         MOV    DI, [BP+8]    ;Height of the bitmap in scan lines
  35.         MOV    SI, [BP+6]    ;DS:offset to bits
  36.  
  37. scanning_line:    MOV    DX, [BP+10]    ;Number of bits to check in each
  38.                     ; scan line
  39. scanning_bytes: MOV    BX, [SI]
  40.         XCHG    BH, BL        ;Get a word
  41.         MOV    CL, 16        ;prepare to scan 16 bits
  42. shifting_bits:    SAL    BX,1        ;shift most significant remaining bit
  43.         JC    shift_again    ;if it was set, shift again
  44.         INC    AX        ;increment ax for each 0 bit
  45.  
  46. shift_again:    DEC    DX        ;Decrement bits/line
  47.         JZ    new_line    ;Process a new scan line?
  48.         DEC    CL        ;do we have bits left in this word?
  49.         JNZ    shifting_bits    ;keep shifting this word
  50.         INC    SI        ;if not, advance to the
  51.         INC    SI        ; next word
  52.         JMP    scanning_bytes    ; and look for black bits
  53.  
  54. new_line:    ADD    [BP-4], AX    ;Add this line's total to our
  55.         ADC    WORD PTR [BP-2], 0
  56.                     ; accumulator
  57.  
  58.         DEC    DI        ;Decrement the line counter
  59.         JZ    pass_bit_count    ;If were done, do exit things
  60.         INC    SI        ;Else bump the pointer to bits
  61.         INC    SI        ; past the word we just scanned
  62.                     ; and any pad bytes
  63.         SUB    AX, AX        ;Zero the accumulator
  64.         JMP    scanning_line    ;Do the next line
  65.  
  66. pass_bit_count:
  67.         POP    SI        ;Restore SI
  68.         POP    DI        ;Restore DI
  69.         POP    AX        ;Loword of bitcount
  70.         POP    DX        ;Hiword of bitcount
  71.         POP    BP        ;Restore BP
  72.  
  73.         RET            ;Return the bit count in DX:AX
  74.                     ; and let the caller clear the stack
  75.  
  76. _COUNT_BITS    ENDP
  77. END
  78.  
  79.  
  80.  
  81.  
  82. [LISTING TWO]
  83.  
  84. /***************************************************************************/
  85. /*            I N C L U D E    F I L E S               */
  86. /***************************************************************************/
  87.  
  88. #include "\windev\include\windows.h"
  89. #include "areas.h"
  90.  
  91.  
  92. /***************************************************************************/
  93. /*    T H E    P R O G R A M ' S   G L O B A L   V A R I A B L E S        */
  94. /***************************************************************************/
  95.  
  96. static    HANDLE    hInst;          /*  Data that can be referenced thruout  */
  97. static    HWND    hWnd;          /*    the program, but is not normally   */
  98. long    float    fAreaPerPixel;
  99. HDC        hDCMem;
  100. HBITMAP     hOldBitmap;
  101. /***************************************************************************/
  102. /*             M A I N   P R O G R A M               */
  103. /***************************************************************************/
  104.  
  105. int PASCAL WinMain (hInstance,
  106.             hPrevInstance,
  107.             lpszCmdLine,
  108.             cmdShow)
  109.  
  110. HANDLE hInstance, hPrevInstance;
  111. LPSTR  lpszCmdLine;              /*  Length of the command line.  */
  112. int    cmdShow;               /*  Iconic or Tiled when start.  */
  113. {
  114.   MSG    msg;
  115.  
  116.   hInst = hInstance;
  117.  if( hPrevInstance )
  118.    {
  119.    return (FALSE);
  120.    }
  121.  
  122.   Init (hInstance, cmdShow);            /* Initialization rtn.*/
  123.  
  124.   while                     /*  The main loop:       */
  125.     (GetMessage((LPMSG)&msg, NULL, 0, 0))    /*  (terminated by a QUIT) */
  126.       {
  127.      TranslateMessage(&msg);        /*  Have Windows translate */
  128.      DispatchMessage(&msg);         /*  Have Windows give mess */
  129.                         /*  to the window proc.    */
  130.       }
  131.   exit(msg.wParam);                /*  End of the program.    */
  132. }
  133.  
  134. /***************************************************************************/
  135. /*               I N I T I A L I Z A T I O N               */
  136. /***************************************************************************/
  137.  
  138. int  FAR PASCAL Init (hInstance, cmdShow)
  139.  
  140. HANDLE hInstance;
  141. int    cmdShow;
  142. {
  143.     WNDCLASS   rClass;               /* Window class structure.       */
  144.     int        FullScreenX;
  145.     int        FullScreenY;
  146.  
  147.     rClass.lpszClassName = (LPSTR) "NN:AREA";
  148.     rClass.hInstance     = hInstance;
  149.     rClass.lpfnWndProc     = WindowProc;
  150.     rClass.hCursor     = LoadCursor (NULL, IDC_ARROW) ;
  151.     rClass.hIcon     = LoadIcon (hInstance, "AREAS");
  152.     rClass.lpszMenuName  = (LPSTR) "AreaFinder";
  153.     rClass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
  154.     rClass.style     = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
  155.     rClass.cbClsExtra     = 0;
  156.     rClass.cbWndExtra     = sizeof( WORD );
  157.  
  158.     RegisterClass ( &rClass); /*  Register the class. */
  159.  
  160.     hInst = hInstance;
  161.     FullScreenY = GetSystemMetrics( SM_CYFULLSCREEN );
  162.     FullScreenX = GetSystemMetrics( SM_CXFULLSCREEN );
  163.     hWnd = CreateWindow((LPSTR) "NN:AREA",  /*    Window class name.     */
  164.             "Using BitBlt to Estimate Areas - Dr. Dobbs",
  165.                           /* Window Title           */
  166.             WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,
  167.                           /*  Type of window.       */
  168.             0,              /*  Where the window should  */
  169.             0,              /*  go when the app opens... */
  170.             (FullScreenX  / 16 ) * 16,
  171.                           /* Make a scan line fill an  */
  172.                           /*  even # words           */
  173.             FullScreenY,          /*               */
  174.             NULL,              /*  No parent for this wind  */
  175.             NULL,              /*  Use the class menu.       */
  176.             hInstance,          /*  Who created this window. */
  177.             NULL              /*  No params to pass on.    */
  178.                ) ;
  179.     ShowWindow( hWnd, cmdShow );
  180.     return TRUE;
  181.  }
  182.  
  183.  
  184.  /***************************************************************************/
  185.  /*         T H E    W I N D O W   P R O C E D U R E                */
  186.  /***************************************************************************/
  187.  
  188.  
  189. long FAR PASCAL WindowProc (hWnd, message, wParam, lParam )
  190.  
  191. HWND       hWnd;                 /*  Handle of the window  */
  192. unsigned   message;                 /*  Message type       */
  193. WORD       wParam;                 /*  Message 16 bit param  */
  194. LONG       lParam;                 /*  Message 32 bit param  */
  195. {
  196.  
  197.  
  198.     switch (message)                 /*  Check the mess type   */
  199.     {
  200.     case WM_COMMAND:
  201.       switch(wParam)
  202.         {                 /* Store wParam in the    */
  203.         case ID_AREA1:             /*  WindowWord and tell   */
  204.         case ID_AREA2:             /*   the paint proc about */
  205.         case ID_UNION:             /*   it...           */
  206.         case ID_INTERSECTION:
  207.         case ID_EXCLUSIVE:
  208.         case ID_OUTSIDE:
  209.         case ID_SHOWPOLYS:
  210.          SetWindowWord(hWnd, 0, wParam );
  211.          InvalidateRect( hWnd, NULL, TRUE );
  212.          UpdateWindow( hWnd );
  213.          break;
  214.  
  215.         default:
  216.            break;
  217.         }
  218.       break;
  219.  
  220.     case WM_CREATE:
  221.         InvalidateRect( hWnd, NULL, TRUE );
  222.         UpdateWindow( hWnd );
  223.         break;
  224.  
  225.     case WM_PAINT:
  226.         PaintAreaWindow( hWnd );
  227.         break;
  228.  
  229.     case WM_SIZE:                   /* Dont let the window change */
  230.         break;                   /*  size...             */
  231.  
  232.     case WM_DESTROY:
  233.         PostQuitMessage(0);            /*    send yourself a QUIT  */
  234.         break;                   /*    message.           */
  235.  
  236.     default:
  237.         return(DefWindowProc(hWnd, message, wParam, lParam));
  238.         break;
  239.     }
  240.     return(0L);
  241. }
  242. RECT         rWorkRect;
  243. /***************************************************************************/
  244. /*          T H E   P A I N T   P R O C E D U R E            */
  245. /***************************************************************************/
  246.  
  247. int FAR PASCAL PaintAreaWindow (hWnd)
  248.  
  249. HWND          hWnd;                /*    Handle of the window.       */
  250. {
  251.  
  252. PAINTSTRUCT  ps;
  253. HDC         hDC;
  254. HANDLE         hArea1Meta;
  255. HANDLE         hArea2Meta;
  256. HBITMAP      hArea1;
  257. HBITMAP      hArea2;
  258.  
  259.  
  260. WORD         WhatToEstimate;
  261.  
  262.  
  263. hDC = BeginPaint( hWnd, &ps);
  264. GetClientRect( hWnd, &rWorkRect );
  265. SetMapMode( hDC, MM_ANISOTROPIC );     /* X and Y are dimensionally  equal */
  266. SetViewportOrg( hDC, 0, rWorkRect.bottom  );
  267.                      /* The viewport origin is at the    */
  268.                      /*  left corner of the screen...    */
  269. SetViewportExt( hDC, rWorkRect.right, -rWorkRect.bottom );
  270.                      /*  X increases to the right and Y  */
  271.                      /*   increases going up...         */
  272. SetWindowOrg( hDC, X_ORIGIN, Y_ORIGIN );
  273. SetWindowExt( hDC, X_EXTENT, Y_EXTENT );
  274.                      /* Logical dimensions depend on the */
  275.                      /*  data which defines the areas.   */
  276.                      /*  The constants are defined in    */
  277.                      /*  Areas.h                 */
  278. hDCMem = CreateCompatibleDC( hDC );
  279. SetMapMode( hDCMem, MM_ISOTROPIC );
  280.  
  281. SetViewportOrg( hDCMem, 0, rWorkRect.bottom  );
  282. SetViewportExt( hDCMem, rWorkRect.right, -rWorkRect.bottom );
  283. SetWindowOrg( hDCMem, X_ORIGIN, Y_ORIGIN );
  284. SetWindowExt( hDCMem, X_EXTENT, Y_EXTENT );
  285.                      /* Create a memory display context  */
  286.                      /*  that simulates the visible DC...*/
  287.  
  288. hArea1 =
  289.  CreateCompatibleBitmap( hDCMem, rWorkRect.right , rWorkRect.bottom );
  290. hOldBitmap = SelectObject( hDCMem, hArea1 );
  291.                      /* Create a bitmap with the same    */
  292.                      /*  organization as this device and */
  293.                      /*  select it into the memory DC... */
  294. hArea1Meta = GetMetaFile( "Area1.bas" );
  295. SaveDC( hDCMem );
  296. PlayMetaFile( hDCMem, hArea1Meta );
  297. RestoreDC( hDCMem, -1 );
  298. DeleteMetaFile( hArea1Meta );
  299.  
  300. hArea2 =
  301.  CreateCompatibleBitmap( hDCMem, rWorkRect.right, rWorkRect.bottom );
  302. SelectObject( hDCMem, hArea2 );
  303. hArea2Meta = GetMetaFile( "Area2.bas" );   /* For convenience, we'll construct */
  304. SaveDC( hDCMem );               /*  our area bitmaps using pre-     */
  305. PlayMetaFile( hDCMem, hArea2Meta );       /*  recorded metafiles.  Since the  */
  306. RestoreDC( hDCMem, -1 );           /*  metafile can change the attrib- */
  307. DeleteMetaFile( hArea2Meta );           /*  utes of the DC, its often a good*/
  308.                        /*  practice to use the context     */
  309.                        /*  stack to preserve the DC before */
  310.                        /*  playing the metafile, and       */
  311.                        /*  restore it afterward...           */
  312. fAreaPerPixel =
  313.  ( (float)X_EXTENT / (float)rWorkRect.right ) *
  314.  ( (float)Y_EXTENT / (float)rWorkRect.bottom );
  315.                      /* Calculate the area of 1 Pixel... */
  316.  
  317.  
  318. WhatToEstimate = GetWindowWord( hWnd, 0 );
  319. switch( WhatToEstimate )
  320.  {
  321.   case ID_AREA1:
  322.    SelectObject( hDCMem, hArea1 );
  323.    DeleteObject( hArea2 );
  324.    BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  325.        hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
  326.    SelectObject( hDCMem, hOldBitmap );
  327.    DeleteObject( hArea1 );
  328.    FindArea( hDC, &rWorkRect );
  329.    break;                /* Estimate the area of Area 1         */
  330.  
  331.   case ID_AREA2:
  332.    DeleteObject( hArea1 );
  333.    BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  334.        hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
  335.    SelectObject( hDCMem, hOldBitmap );
  336.    DeleteObject( hArea2 );
  337.    FindArea( hDC, &rWorkRect );     /* Estimate the area of Area 2...    */
  338.    break;
  339.  
  340.   case ID_UNION:
  341.    SelectObject( hDCMem, hArea1 );
  342.    BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  343.        hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
  344.    SelectObject( hDCMem, hArea2 );
  345.    DeleteObject( hArea1 );
  346.  
  347.    BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  348.        hDCMem, X_ORIGIN, Y_ORIGIN, SRCAND );
  349.    SelectObject( hDCMem, hOldBitmap );
  350.    DeleteObject( hArea2 );
  351.    FindArea( hDC, &rWorkRect );      /* Estimate the area of the union   */
  352.    break;
  353.  
  354.   case ID_INTERSECTION:
  355.    SelectObject( hDCMem, hArea1 );
  356.    BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  357.        hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
  358.    SelectObject( hDCMem, hArea2 );
  359.    DeleteObject( hArea1 );
  360.    BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  361.        hDCMem, X_ORIGIN, Y_ORIGIN, SRCPAINT );
  362.    SelectObject( hDCMem, hOldBitmap );
  363.    DeleteObject( hArea2 );
  364.    FindArea( hDC, &rWorkRect );     /* Estimate the area of the intersec-
  365.                         tion... */
  366.    break;
  367.  
  368.   case ID_EXCLUSIVE:
  369.    SelectObject( hDCMem, hArea1 );
  370.    BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  371.        hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
  372.    SelectObject( hDCMem, hArea2 );
  373.    DeleteObject( hArea1 );
  374.  
  375.    BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  376.        hDCMem, X_ORIGIN, Y_ORIGIN, 0x990066 );
  377.    SelectObject( hDCMem, hOldBitmap );
  378.    DeleteObject( hArea2 );
  379.    FindArea( hDC, &rWorkRect );     /* Estimate the area of an exclusive
  380.                         combination... */
  381.    break;
  382.  
  383.   case ID_OUTSIDE:
  384.    SelectObject( hDCMem, hArea1 );
  385.    BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  386.        hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
  387.    SelectObject( hDCMem, hArea2 );
  388.    DeleteObject( hArea1 );
  389.  
  390.    BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  391.        hDCMem, X_ORIGIN, Y_ORIGIN, 0x7700e6 );
  392.    SelectObject( hDCMem, hOldBitmap );
  393.    DeleteObject( hArea2 );
  394.    FindArea( hDC, &rWorkRect );     /* Estimate the area outside the
  395.                         combined areas...*/
  396.    break;
  397.  
  398.   case ID_SHOWPOLYS:
  399.    SelectObject( hDCMem, hArea1 );
  400.  
  401.    BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  402.        hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
  403.    MessageBox(hWnd, "This is Area 1... ", "Areas", MB_OK );
  404.    SelectObject( hDCMem, hArea2 );
  405.    DeleteObject( hArea1 );
  406.  
  407.    BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  408.        hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY );
  409.    SelectObject( hDCMem, hOldBitmap );
  410.    DeleteObject( hArea2 );
  411.    MessageBox(hWnd, "This is Area 2... ", "Areas", MB_OK );
  412.                     /* Lets have a look at the areas... */
  413.    break;
  414.  
  415.  
  416.  default:
  417.    break;
  418.  }
  419. DeleteDC( hDCMem );      /* Always relinquish GDI leftovers!! */
  420. DeleteObject( hOldBitmap );
  421. ValidateRect( hWnd, NULL );
  422.               /* Validate the client area...       */
  423. EndPaint (hWnd, &ps);      /* Finished painting for now.        */
  424. SetWindowWord(hWnd, 0, NULL );
  425. return TRUE;
  426. }
  427.  
  428. /***************************************************************************/
  429. /*    F I N D   A R E A                           */
  430. /***************************************************************************/
  431. void PASCAL FindArea( hDC, lprWork )
  432.  
  433.  HDC           hDC;
  434.  LPRECT        lprWork;
  435.  
  436. {
  437.  
  438.  HBITMAP       hArea;
  439.  HANDLE        hAreaMemory;
  440.  BITMAP        bmArea;
  441.  PSTR           pAreaBits;
  442.  unsigned int  NumberBytes;
  443.  
  444.  
  445.  long    float  fArea;
  446.  long           SetBits;
  447.  char           szApproxArea[12];
  448.  
  449.  
  450.  
  451.  hArea = CreateBitmap( lprWork->right, lprWork->bottom, 1, 1, NULL );
  452.                     /* Create a monochrome bitmap with the
  453.                     same dimensions as the client area...
  454.                     */
  455.  SelectObject( hDCMem, hArea );
  456.  
  457.  BitBlt( hDCMem, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
  458.      hDC, X_ORIGIN, Y_ORIGIN, SRCCOPY);
  459.                     /* Select it into the memory DC and copy
  460.                     the client area to it...
  461.                     */
  462.  GetObject( hArea, sizeof( BITMAP ), &bmArea );
  463.                     /* Get the dimensions and color organization
  464.                     information about the monochrome bitmap...
  465.                     */
  466.  
  467.  NumberBytes = bmArea.bmPlanes * bmArea.bmHeight * bmArea.bmWidthBytes;
  468.  hAreaMemory = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, NumberBytes );
  469.  if( hAreaMemory == NULL )
  470.   {
  471.    MessageBox(hWnd, "Try closing other windows or resizing Areas...","Unable to allocte memory!", MB_OK | MB_ICONHAND );
  472.    return;
  473.   }
  474.  pAreaBits = LocalLock( hAreaMemory );
  475.  GetBitmapBits( hArea, (DWORD)NumberBytes, (LPSTR)pAreaBits );
  476.                     /* Allocate memory and get bits... */
  477.  SetBits = COUNT_BITS( pAreaBits, bmArea.bmHeight, bmArea.bmWidth);
  478.  
  479.                    /* Count the Black ( 0H ) bits...  */
  480.  LocalUnlock( hAreaMemory );       /* Release memory...           */
  481.  LocalFree( hAreaMemory );
  482.  SelectObject( hDCMem, hOldBitmap );
  483.  DeleteObject( hArea );
  484.                    /* Delete the monochrome bitmap... */
  485.  fArea = SetBits * fAreaPerPixel;
  486.  sprintf( szApproxArea, "%.2f", fArea );
  487.  MessageBox(hWnd, szApproxArea, "Approximate area in square meters... ", MB_OK );
  488.                     /* Calculate and display area... */
  489.  return;
  490. }
  491.  
  492.