home *** CD-ROM | disk | FTP | other *** search
- _QUICK APPROXIMATIONS OF POLYGONAL AREAS USING BITBLT_
- by Nancy Nicolaisen
-
-
- [LISTING ONE]
-
-
- ; Parameters:
- ; BP+6 = Offset to bits
- ; BP+8 = Bitmap Height in scan lines
- ; BP+10 = Bitmap width in pixels
- ; Local Data
- ; BP-2 = hiword of the bit count
- ; BP-4 = loword of the bit count
-
- .8086
- .MODEL MEDIUM
- memM EQU 1
- INCLUDE CMACROS.INC
-
- .CODE
- PUBLIC _COUNT_BITS
-
- _COUNT_BITS PROC
- PUSH BP ; Preserve BP
- MOV BP, SP ; Set stack frame pointer
- SUB SP, 4 ; This will hold our byte count
- PUSH DI ; Preserve DI
- PUSH SI ; Preserve SI
-
- SUB AX, AX ;Zero the accumulator reg
- MOV [BP-2], AX ;Zero the local
- MOV [BP-4], AX ; storage
- MOV DI, [BP+8] ;Height of the bitmap in scan lines
- MOV SI, [BP+6] ;DS:offset to bits
-
- scanning_line: MOV DX, [BP+10] ;Number of bits to check in each
- ; scan line
- scanning_bytes: MOV BX, [SI]
- XCHG BH, BL ;Get a word
- MOV CL, 16 ;prepare to scan 16 bits
- shifting_bits: SAL BX,1 ;shift most significant remaining bit
- JC shift_again ;if it was set, shift again
- INC AX ;increment ax for each 0 bit
-
- shift_again: DEC DX ;Decrement bits/line
- JZ new_line ;Process a new scan line?
- DEC CL ;do we have bits left in this word?
- JNZ shifting_bits ;keep shifting this word
- INC SI ;if not, advance to the
- INC SI ; next word
- JMP scanning_bytes ; and look for black bits
-
- new_line: ADD [BP-4], AX ;Add this line's total to our
- ADC WORD PTR [BP-2], 0
- ; accumulator
-
- DEC DI ;Decrement the line counter
- JZ pass_bit_count ;If were done, do exit things
- INC SI ;Else bump the pointer to bits
- INC SI ; past the word we just scanned
- ; and any pad bytes
- SUB AX, AX ;Zero the accumulator
- JMP scanning_line ;Do the next line
-
- pass_bit_count:
- POP SI ;Restore SI
- POP DI ;Restore DI
- POP AX ;Loword of bitcount
- POP DX ;Hiword of bitcount
- POP BP ;Restore BP
-
- RET ;Return the bit count in DX:AX
- ; and let the caller clear the stack
-
- _COUNT_BITS ENDP
- END
-
-
-
-
- [LISTING TWO]
-
- /***************************************************************************/
- /* I N C L U D E F I L E S */
- /***************************************************************************/
-
- #include "\windev\include\windows.h"
- #include "areas.h"
-
-
- /***************************************************************************/
- /* 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 */
- /***************************************************************************/
-
- static HANDLE hInst; /* Data that can be referenced thruout */
- static HWND hWnd; /* the program, but is not normally */
- long float fAreaPerPixel;
- HDC hDCMem;
- HBITMAP hOldBitmap;
- /***************************************************************************/
- /* M A I N P R O G R A M */
- /***************************************************************************/
-
- int PASCAL WinMain (hInstance,
- hPrevInstance,
- lpszCmdLine,
- cmdShow)
-
- HANDLE hInstance, hPrevInstance;
- LPSTR lpszCmdLine; /* Length of the command line. */
- int cmdShow; /* Iconic or Tiled when start. */
- {
- MSG msg;
-
- hInst = hInstance;
- if( hPrevInstance )
- {
- return (FALSE);
- }
-
- Init (hInstance, cmdShow); /* Initialization rtn.*/
-
- while /* The main loop: */
- (GetMessage((LPMSG)&msg, NULL, 0, 0)) /* (terminated by a QUIT) */
- {
- TranslateMessage(&msg); /* Have Windows translate */
- DispatchMessage(&msg); /* Have Windows give mess */
- /* to the window proc. */
- }
- exit(msg.wParam); /* End of the program. */
- }
-
- /***************************************************************************/
- /* I N I T I A L I Z A T I O N */
- /***************************************************************************/
-
- int FAR PASCAL Init (hInstance, cmdShow)
-
- HANDLE hInstance;
- int cmdShow;
- {
- WNDCLASS rClass; /* Window class structure. */
- int FullScreenX;
- int FullScreenY;
-
- rClass.lpszClassName = (LPSTR) "NN:AREA";
- rClass.hInstance = hInstance;
- rClass.lpfnWndProc = WindowProc;
- rClass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
- rClass.hIcon = LoadIcon (hInstance, "AREAS");
- rClass.lpszMenuName = (LPSTR) "AreaFinder";
- rClass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
- rClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
- rClass.cbClsExtra = 0;
- rClass.cbWndExtra = sizeof( WORD );
-
- RegisterClass ( &rClass); /* Register the class. */
-
- hInst = hInstance;
- FullScreenY = GetSystemMetrics( SM_CYFULLSCREEN );
- FullScreenX = GetSystemMetrics( SM_CXFULLSCREEN );
- hWnd = CreateWindow((LPSTR) "NN:AREA", /* Window class name. */
- "Using BitBlt to Estimate Areas - Dr. Dobbs",
- /* Window Title */
- WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,
- /* Type of window. */
- 0, /* Where the window should */
- 0, /* go when the app opens... */
- (FullScreenX / 16 ) * 16,
- /* Make a scan line fill an */
- /* even # words */
- FullScreenY, /* */
- NULL, /* No parent for this wind */
- NULL, /* Use the class menu. */
- hInstance, /* Who created this window. */
- NULL /* No params to pass on. */
- ) ;
- ShowWindow( hWnd, cmdShow );
- return TRUE;
- }
-
-
- /***************************************************************************/
- /* T H E W I N D O W P R O C E D U R E */
- /***************************************************************************/
-
-
- long FAR PASCAL WindowProc (hWnd, message, wParam, lParam )
-
- HWND hWnd; /* Handle of the window */
- unsigned message; /* Message type */
- WORD wParam; /* Message 16 bit param */
- LONG lParam; /* Message 32 bit param */
- {
-
-
- switch (message) /* Check the mess type */
- {
- case WM_COMMAND:
- switch(wParam)
- { /* Store wParam in the */
- case ID_AREA1: /* WindowWord and tell */
- case ID_AREA2: /* the paint proc about */
- case ID_UNION: /* it... */
- case ID_INTERSECTION:
- case ID_EXCLUSIVE:
- case ID_OUTSIDE:
- case ID_SHOWPOLYS:
- SetWindowWord(hWnd, 0, wParam );
- InvalidateRect( hWnd, NULL, TRUE );
- UpdateWindow( hWnd );
- break;
-
- default:
- break;
- }
- break;
-
- case WM_CREATE:
- InvalidateRect( hWnd, NULL, TRUE );
- UpdateWindow( hWnd );
- break;
-
- case WM_PAINT:
- PaintAreaWindow( hWnd );
- break;
-
- case WM_SIZE: /* Dont let the window change */
- break; /* size... */
-
- case WM_DESTROY:
- PostQuitMessage(0); /* send yourself a QUIT */
- break; /* message. */
-
- default:
- return(DefWindowProc(hWnd, message, wParam, lParam));
- break;
- }
- return(0L);
- }
- RECT rWorkRect;
- /***************************************************************************/
- /* T H E P A I N T P R O C E D U R E */
- /***************************************************************************/
-
- int FAR PASCAL PaintAreaWindow (hWnd)
-
- HWND hWnd; /* Handle of the window. */
- {
-
- PAINTSTRUCT ps;
- HDC hDC;
- HANDLE hArea1Meta;
- HANDLE hArea2Meta;
- HBITMAP hArea1;
- HBITMAP hArea2;
-
-
- WORD WhatToEstimate;
-
-
- hDC = BeginPaint( hWnd, &ps);
- GetClientRect( hWnd, &rWorkRect );
- SetMapMode( hDC, MM_ANISOTROPIC ); /* X and Y are dimensionally equal */
- SetViewportOrg( hDC, 0, rWorkRect.bottom );
- /* The viewport origin is at the */
- /* left corner of the screen... */
- SetViewportExt( hDC, rWorkRect.right, -rWorkRect.bottom );
- /* X increases to the right and Y */
- /* increases going up... */
- SetWindowOrg( hDC, X_ORIGIN, Y_ORIGIN );
- SetWindowExt( hDC, X_EXTENT, Y_EXTENT );
- /* Logical dimensions depend on the */
- /* data which defines the areas. */
- /* The constants are defined in */
- /* Areas.h */
- hDCMem = CreateCompatibleDC( hDC );
- SetMapMode( hDCMem, MM_ISOTROPIC );
-
- SetViewportOrg( hDCMem, 0, rWorkRect.bottom );
- SetViewportExt( hDCMem, rWorkRect.right, -rWorkRect.bottom );
- SetWindowOrg( hDCMem, X_ORIGIN, Y_ORIGIN );
- SetWindowExt( hDCMem, X_EXTENT, Y_EXTENT );
- /* Create a memory display context */
- /* that simulates the visible DC...*/
-
- hArea1 =
- CreateCompatibleBitmap( hDCMem, rWorkRect.right , rWorkRect.bottom );
- hOldBitmap = SelectObject( hDCMem, hArea1 );
- /* Create a bitmap with the same */
- /* organization as this device and */
- /* select it into the memory DC... */
- hArea1Meta = GetMetaFile( "Area1.bas" );
- SaveDC( hDCMem );
- PlayMetaFile( hDCMem, hArea1Meta );
- RestoreDC( hDCMem, -1 );
- DeleteMetaFile( hArea1Meta );
-
- hArea2 =
- CreateCompatibleBitmap( hDCMem, rWorkRect.right, rWorkRect.bottom );
- SelectObject( hDCMem, hArea2 );
- hArea2Meta = GetMetaFile( "Area2.bas" ); /* For convenience, we'll construct */
- SaveDC( hDCMem ); /* our area bitmaps using pre- */
- PlayMetaFile( hDCMem, hArea2Meta ); /* recorded metafiles. Since the */
- RestoreDC( hDCMem, -1 ); /* metafile can change the attrib- */
- DeleteMetaFile( hArea2Meta ); /* utes of the DC, its often a good*/
- /* practice to use the context */
- /* stack to preserve the DC before */
- /* playing the metafile, and */
- /* restore it afterward... */
- fAreaPerPixel =
- ( (float)X_EXTENT / (float)rWorkRect.right ) *
- ( (float)Y_EXTENT / (float)rWorkRect.bottom );
- /* Calculate the area of 1 Pixel... */
-
-
- WhatToEstimate = GetWindowWord( hWnd, 0 );
- switch( WhatToEstimate )
- {
- case ID_AREA1:
- SelectObject( hDCMem, hArea1 );
- DeleteObject( hArea2 );
- BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
- SelectObject( hDCMem, hOldBitmap );
- DeleteObject( hArea1 );
- FindArea( hDC, &rWorkRect );
- break; /* Estimate the area of Area 1 */
-
- case ID_AREA2:
- DeleteObject( hArea1 );
- BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
- SelectObject( hDCMem, hOldBitmap );
- DeleteObject( hArea2 );
- FindArea( hDC, &rWorkRect ); /* Estimate the area of Area 2... */
- break;
-
- case ID_UNION:
- SelectObject( hDCMem, hArea1 );
- BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
- SelectObject( hDCMem, hArea2 );
- DeleteObject( hArea1 );
-
- BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDCMem, X_ORIGIN, Y_ORIGIN, SRCAND );
- SelectObject( hDCMem, hOldBitmap );
- DeleteObject( hArea2 );
- FindArea( hDC, &rWorkRect ); /* Estimate the area of the union */
- break;
-
- case ID_INTERSECTION:
- SelectObject( hDCMem, hArea1 );
- BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
- SelectObject( hDCMem, hArea2 );
- DeleteObject( hArea1 );
- BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDCMem, X_ORIGIN, Y_ORIGIN, SRCPAINT );
- SelectObject( hDCMem, hOldBitmap );
- DeleteObject( hArea2 );
- FindArea( hDC, &rWorkRect ); /* Estimate the area of the intersec-
- tion... */
- break;
-
- case ID_EXCLUSIVE:
- SelectObject( hDCMem, hArea1 );
- BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
- SelectObject( hDCMem, hArea2 );
- DeleteObject( hArea1 );
-
- BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDCMem, X_ORIGIN, Y_ORIGIN, 0x990066 );
- SelectObject( hDCMem, hOldBitmap );
- DeleteObject( hArea2 );
- FindArea( hDC, &rWorkRect ); /* Estimate the area of an exclusive
- combination... */
- break;
-
- case ID_OUTSIDE:
- SelectObject( hDCMem, hArea1 );
- BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
- SelectObject( hDCMem, hArea2 );
- DeleteObject( hArea1 );
-
- BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDCMem, X_ORIGIN, Y_ORIGIN, 0x7700e6 );
- SelectObject( hDCMem, hOldBitmap );
- DeleteObject( hArea2 );
- FindArea( hDC, &rWorkRect ); /* Estimate the area outside the
- combined areas...*/
- break;
-
- case ID_SHOWPOLYS:
- SelectObject( hDCMem, hArea1 );
-
- BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY);
- MessageBox(hWnd, "This is Area 1... ", "Areas", MB_OK );
- SelectObject( hDCMem, hArea2 );
- DeleteObject( hArea1 );
-
- BitBlt( hDC, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDCMem, X_ORIGIN, Y_ORIGIN, SRCCOPY );
- SelectObject( hDCMem, hOldBitmap );
- DeleteObject( hArea2 );
- MessageBox(hWnd, "This is Area 2... ", "Areas", MB_OK );
- /* Lets have a look at the areas... */
- break;
-
-
- default:
- break;
- }
- DeleteDC( hDCMem ); /* Always relinquish GDI leftovers!! */
- DeleteObject( hOldBitmap );
- ValidateRect( hWnd, NULL );
- /* Validate the client area... */
- EndPaint (hWnd, &ps); /* Finished painting for now. */
- SetWindowWord(hWnd, 0, NULL );
- return TRUE;
- }
-
- /***************************************************************************/
- /* F I N D A R E A */
- /***************************************************************************/
- void PASCAL FindArea( hDC, lprWork )
-
- HDC hDC;
- LPRECT lprWork;
-
- {
-
- HBITMAP hArea;
- HANDLE hAreaMemory;
- BITMAP bmArea;
- PSTR pAreaBits;
- unsigned int NumberBytes;
-
-
- long float fArea;
- long SetBits;
- char szApproxArea[12];
-
-
-
- hArea = CreateBitmap( lprWork->right, lprWork->bottom, 1, 1, NULL );
- /* Create a monochrome bitmap with the
- same dimensions as the client area...
- */
- SelectObject( hDCMem, hArea );
-
- BitBlt( hDCMem, X_ORIGIN, Y_ORIGIN, X_EXTENT, Y_EXTENT,
- hDC, X_ORIGIN, Y_ORIGIN, SRCCOPY);
- /* Select it into the memory DC and copy
- the client area to it...
- */
- GetObject( hArea, sizeof( BITMAP ), &bmArea );
- /* Get the dimensions and color organization
- information about the monochrome bitmap...
- */
-
- NumberBytes = bmArea.bmPlanes * bmArea.bmHeight * bmArea.bmWidthBytes;
- hAreaMemory = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, NumberBytes );
- if( hAreaMemory == NULL )
- {
- MessageBox(hWnd, "Try closing other windows or resizing Areas...","Unable to allocte memory!", MB_OK | MB_ICONHAND );
- return;
- }
- pAreaBits = LocalLock( hAreaMemory );
- GetBitmapBits( hArea, (DWORD)NumberBytes, (LPSTR)pAreaBits );
- /* Allocate memory and get bits... */
- SetBits = COUNT_BITS( pAreaBits, bmArea.bmHeight, bmArea.bmWidth);
-
- /* Count the Black ( 0H ) bits... */
- LocalUnlock( hAreaMemory ); /* Release memory... */
- LocalFree( hAreaMemory );
- SelectObject( hDCMem, hOldBitmap );
- DeleteObject( hArea );
- /* Delete the monochrome bitmap... */
- fArea = SetBits * fAreaPerPixel;
- sprintf( szApproxArea, "%.2f", fArea );
- MessageBox(hWnd, szApproxArea, "Approximate area in square meters... ", MB_OK );
- /* Calculate and display area... */
- return;
- }
-