400 likes | 593 Views
Timer, Hit Testing (again), Raster Operations (rops). Petzold Ch. 5, 8. Overview. Timer Program 4 (a bit more interesting) Hit Testing (again) Raster Operations (rops). The Windows “Timer”. Often useful to keep track of clock time
E N D
Timer, Hit Testing (again), Raster Operations (rops) Petzold Ch. 5, 8
Overview • Timer • Program 4 (a bit more interesting) • Hit Testing (again) • Raster Operations (rops)
The Windows “Timer” Often useful to keep track of clock time e.g., for clocks, create a 1 second beep every 5 seconds, animate smoothly One mechanism is to have hardware clock generate interrupts handled by program - requires assembly language programming and interface to C program Various software methods for high level language Windows uses a mechanism called “the Windows timer” Not a general purpose timer Only resolves to ~18msec, so can’t even time to 1/100 accuracy Operates by simply placing message in message queue, so program may not process it when it is generated, may have to deal with messages ahead of it in the queue Conceptually and coding-wise is simple to implement: e.g., SetTimer (hwnd, 1, 1000, NULL)), hwnd is the handle of the window to receive the WM_TIMER message 1 is the ID of the timer which is created, in wparam (1 will be enough for us) 1000 is the number of milliseconds between messages (sort of, see above)
Windows Timer - 1 second timer, Timer Setup Create a timer set to generate a WM_TIMER message ~each second WinMain ( .... ) { . : if (!SetTimer (hwnd, 1, 1000, NULL)) { MessageBox (hwnd, // a useful way to write things to screen & stop program "Couldn’t create timer.", szAppName, MB_ICONEXCLAMATION | MB_OK) ; return FALSE ; } : while (GetMessage (&msg, NULL, 0, 0)) { : }
Windows Timer - 1 second timer, WndProcNote control of “redrawing” (in WM_PAINT) using InvalidateRect Write the number of times the WM_TIMER message arrives, gives ~number of seconds since program started. WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { static int nTimerMsgs = 0; : switch (iMsg) { case WM_TIMER : nTimerMsgs++; InvalidateRect (hwnd, NULL, TRUE); // cause WM_PAINT msg to be sent return 0 ; case WM_PAINT: hdc = GetDC (hWnd); nLength = sprintf (szBuffer, " nTimerMsgs = %d", nTimerMsgs); TextOut (hdc, 20, 20, szBuffer, nLength); ReleaseDC (hWnd, hdc); return 0; : } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; }
Windows Timer – Move Figure – Share ProcessorAgain, InvalidateRect controls drawing in WM_PAINT Move (or animate) a figure, e.g., rectangle, from a starting point to an ending point, when user presses right mouse button – doesn’t “hog” resources WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { case WM_RBUTTONDOWN: // user action indicating to start movement if (bOnFigure) { iEnd.x = … // mouse x loc (need to get mouse location) iEnd.y = … // mouse y loc bMoving = TRUE; // figure out how much to move with each timer click: iMove.x, iMove.y iCurrent.x = iStart.x; iCurrent.y = iStart.y; // where figure is now : return 0; } case WM_TIMER : if (bMoving) { iOld.x = iCurrent.x; iOld.y = iCurrent.y; iCurrent.x = iCurrent.x + iMove.x; iCurrent.y = iCurrent.y + iMove.y; InvalidateRect (hwnd, NULL, TRUE ); // cause WM_PAINT msg to be sent return 0 ; case WM_PAINT: hdc = GetDC (hWnd); // erase old figure at iOld.x, iOld.x // draw figure at iCurrent.x, iCurrent.y (as calculated in last program) // check to see if have reached end, iCurrent == iEnd, and if so set bMoving = FALSE; ReleaseDC (hWnd, hdc); return 0; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; }
Petzold Bouncing Ball Program • Meant to illustrate use of timer … • “Elegant” in program simplicity • NOT in result
Bouncing Ball Program, 1, Main Nothing special in first part … WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static char szAppName[] = "Bounce" ; HWND hwnd ; MSG msg ; WNDCLASSEX wndclass ; wndclass.cbSize = sizeof (wndclass) ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; RegisterClassEx (&wndclass) ; hwnd = CreateWindow (szAppName, "Bouncing Ball", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; ( cont’d )
// set up the timer if (!SetTimer (hwnd, 1, 50, NULL)) { MessageBox (hwnd, "Too many clocks or timers!", szAppName, MB_ICONEXCLAMATION | MB_OK) ; return FALSE ; } ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } Bouncing Ball Program, 2, Main - Timer (cont’d)
Bouncing Ball Program, 3, WndProc – Scale, etc. WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { static HBITMAP hBitmap ; static int cxClient, cyClient, xCenter, yCenter, cxTotal, cyTotal, cxRadius, cyRadius, cxMove, cyMove, xPixel, yPixel ; HBRUSH hBrush ; HDC hdc, hdcMem ; int iScale ; switch (iMsg) { case WM_CREATE : hdc = GetDC (hwnd) ; xPixel = GetDeviceCaps (hdc, ASPECTX) ; // need aspect ratio to draw round yPixel = GetDeviceCaps (hdc, ASPECTY) ; // (vs. elliptical) ball ReleaseDC (hwnd, hdc) ; return 0 ; case WM_SIZE : // just “setup” here, WM_TIMER is focus xCenter = (cxClient = LOWORD (lParam)) / 2 ; yCenter = (cyClient = HIWORD (lParam)) / 2 ; iScale = min (cxClient * xPixel, cyClient * yPixel) / 16 ; // will size/scale ball to 1/16 cxRadius = iScale / xPixel ; cyRadius = iScale / yPixel ; // size of ball cxMove = max (1, cxRadius / 2) ; cyMove = max (1, cyRadius / 2) ; // size of ball movement cxTotal = 2 * (cxRadius + cxMove) ; cyTotal = 2 * (cyRadius + cyMove) ; // do bitmap stuff ( cont’d )
Bouncing Ball Program, 4, WndProc – Bitmap WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { case WM_CREATE : case WM_SIZE : // just “setup” here, below is tedious, WM_TIMER is focus xCenter = (cxClient = LOWORD (lParam)) / 2 ; yCenter = (cyClient = HIWORD (lParam)) / 2 ; iScale = min (cxClient * xPixel, cyClient * yPixel) / 16 ; // will size/scale ball to 1/16 cxRadius = iScale / xPixel ; cyRadius = iScale / yPixel ; // size of ball cxMove = max (1, cxRadius / 2) ; cyMove = max (1, cyRadius / 2) ; // size of ball movement cxTotal = 2 * (cxRadius + cxMove) ; cyTotal = 2 * (cyRadius + cyMove) ; // will use a (very simple) bitmap if (hBitmap) DeleteObject (hBitmap) ; hdc = GetDC (hwnd) ; hdcMem = CreateCompatibleDC (hdc) ; hBitmap = CreateCompatibleBitmap (hdc, cxTotal, cyTotal) ; ReleaseDC (hwnd, hdc) ; SelectObject (hdcMem, hBitmap) ; Rectangle (hdcMem, -1, -1, cxTotal + 1, cyTotal + 1) ; hBrush = CreateHatchBrush (HS_DIAGCROSS, 0L) ; // again, more bitmap stuff SelectObject (hdcMem, hBrush) ; SetBkColor (hdcMem, RGB (255, 0, 255)) ; Ellipse (hdcMem, cxMove, cyMove, cxTotal - cxMove, cyTotal - cyMove) ; DeleteDC (hdcMem) ; DeleteObject (hBrush) ; // free system resources return 0 ; ( cont’d )
Bouncing Ball Program, 5, WndProc – Move Ball case WM_TIMER : // with regularity (i.e., receipt of WM_TIMER msg, draw the ball) if (!hBitmap) break ; hdc = GetDC (hwnd) ; hdcMem = CreateCompatibleDC (hdc) ; SelectObject (hdcMem, hBitmap) ; // “bit block transfer” – with a raster operation SRCCOPY BitBlt (hdc,xCenter-cxTotal / 2, yCenter - cyTotal / 2, cxTotal, cyTotal, hdcMem, 0, 0, SRCCOPY) ; ReleaseDC (hwnd, hdc) ; DeleteDC (hdcMem) ; xCenter += cxMove ; yCenter += cyMove ; // check to see if gone past screen limits, and if so reverse direction if ((xCenter + cxRadius >= cxClient) || (xCenter - cxRadius <= 0)) cxMove = -cxMove ; if ((yCenter + cyRadius >= cyClient) || (yCenter - cyRadius <= 0)) cyMove = -cyMove ; return 0 ; case WM_DESTROY : if (hBitmap) DeleteObject (hBitmap) ; // free system resources KillTimer (hwnd, 1) ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; }
Program 4 1. Allow the user to indicate whether a figure is to be: a) added, b) deleted, or c) moved 2. Set the mouse pointer to indicate what system function (mode) is current (easy) 3. Adding a figure 4. Deleting a figure 5. Repositioning a figure 6. Animating the repositioning of a figure fast (extra credit, for now)
Hit Testing … Again “Determining if an event occurs in a region” – need multiple objects Petzold uses quite generally, Also more conventionally in “checker” program (which is complicated)
Hit Testing Example Is there a left button click in Region 1? case WM_LBUTTONDOWN: x = LOWORD (lParam); // “decode” lParam to get y = HIWORD (lParam); // x and y client area coordinates if ( ( x > 10 && x < 50 ) && // ck if point of click is in region ( y > 10 && y < 30 ) ) { // there is a hit }
Hit Testing, Some Windows Structures /* typedef struct _RECT { LONG left; LONG top; LONG right; LONG bottom; } RECT; typedef struct tagPOINT { // pt LONG x; LONG y; } POINT; */ RECT rectObj; POINT pClick; rectObj.left = 10; rectObj.right = 50; rectObj.top = 20; rectObj.bottom = 30; case WM_LBUTTONDOWN: pClick.x = LOWORD (lParam); // “decode” lParam to get pClick.y = HIWORD (lParam); // x and y client area coordinates if ( (pClick.x > rectObj.left && pClick.x < rectObj.right ) && // check (pClick.y > rectObj.top && pClick.y < rectObj.bottom ) ) { // there is a hit }
Hit Testing, A Windows Macro & Function, Elegance? RECT rectObj; POINTS pClick; // different type (but ok) rectObj.left = 10; rectObj.right = 50; rectObj.top = 20; rectObj.bottom = 30; . : case WM_LBUTTONDOWN: pClick = MAKEPOINTS (lParam); // use macro to “decode” lParam to get if ( PtInRect (&rectObj, pClick) ) // use Windows fn (or make your own) { // there is a hit }
Hit Testing, Multiple Objects – Just Keep Track of Them! 0, 0 10, 20 Region 1 50, 30 Region 2 Region 3 RECT rectObjs[10]; // now, an array of rectangles (rectangular regions) POINTS pClick; // locations kept track of when created rectObjs[0].left = 10; rectObjs[0].right = 50; rectObjs[0].top = 20; rectObjs[0].bottom = 30; rectObjs[1].left = 10; rectObjs[1].right = 50; rectObjs[1].top = 30; rectObjs[1].bottom = 50; // other assignments nObjects = 3; // keep track of as new created case WM_LBUTTONDOWN: pClick = MAKEPOINTS (lParam); // use macro to “decode” lParam to get for (i=0; i<nObjects; i++) if (PtInRect (&rectObj[i], pClick)) { // there is a hit iObjectHit = i; break; } // works great, as long as there is no overlap! // order matters, in above “simple” algorith, // could have 1st in list be the one on top // could have separate list of indices indicating z-order // could have …..
Drawing Multiple Objects - Straightforward 0, 0 10, 20 Region 1 50, 30 Region 2 Region 3 RECT rectObjs[10]; // now, an array of rectangles (rectangular regions) POINTS pClick; // locations kept track of when created rectObjs[0].left = 10; rectObjs[0].right = 50; rectObjs[0].top = 20; rectObjs[0].bottom = 30; rectObjs[1].left = 10; rectObjs[1].right = 50; rectObjs[1].top = 30; rectObjs[1].bottom = 50; // other assignments nObjects = 3; case WM_PAINT: for (i=0; i<nObjects; i++) // draw rectangle (rectObjs[i].left, top …. right, .bottom) // works great, except order of drawing determines occlusions!
Dragging Example: Drag a figure across the screen 1st erasing the old figure (by drawing it in white) at it’s old location, then drawing the figure (in black) at a new location Might use MK_LBUTTON (instead of a state variable, bDragging), but there are subtleties about moving out of window, and everyone does it with a “dragging” state
Dragging, 2Using a “state” variable, bDragging static int old_x, old_y case WM_CREATE: bDragging = FALSE; : case WM_LBUTTONDOWN // check if button press on region, i.e., a hit if (bClickOnFigure) { bDragging = TRUE; pDragStartX = LOWORD(lParam); pDragStartY = HIWORD(lParam); // might change cursor to indicate dragging state } : case WM_LBUTTONUP: bDragging = FALSE // might change cursor back to show selection or other state : case WM_MOUSEMOVE: // there is a new mouse pointer position, so save old x and y // set new mouse x and y if (bDragging) } // erase old figure at old x and old y // - use white pen // (re)draw figure at new x and new y // - use black pen, with dashed line } :
Raster Operations • “writing” or “drawing” to/on the screen is “operating on the raster”, which is the screen memory • Possible to not only just produce a screen image (pixel value) that is that which is written, • But also which has a value that is determined by the current pixel value where to be written!
Screens/Displays, Resolution, & Pixels, 1 A computer screen is, after all, just a collection of “dots” (which happen to be excited phosphors, but that’s another story) Colloquially, people would say that the “resolution” of the screen (or LCD) to the right was 32 x 24 More correctly, resolution refers to the number of dots per inch Here, if the “screen” were 1” wide and 3/4” tall, the resolution would be 32 dots per inch (dpi) A 32 x 24 collection of dots: (Maybe, think of it as a LCD display)
Screens/Displays, Resolution, & Pixels, 2 If the screen were 1/2” wide, the 32 x 24 dot array would have a resolution of 64dpi, which is a higher resolution, (things would appear sharper) A more coarse resolution
Screens/Displays, Resolution, & Pixels, 2 Let’s say that this is a picture of a house: The individual dots that are colored black, are called picture elements But, since it takes too long to say “picture elements”, the word “pixel” is used, or, the more arcane, but shorter, word “pel”
Raster OperationsThe term “raster” and it (historical) etemology Old: The hardware (electron gun) of the crt (cathode ray tube) moves from left to right, very quickly turning on and off making white dots when on and leaving dots black when off Now: just chips for leds, lcd, etc. It is from the creation of (scan) lines that the term raster is derived (a screen is a raster device) Most generally, the operations on a screen are called raster operations For our purposes we’ll be concerned with just drawing lines (though the use of bit block transfers (bitblt) is a useful topic, and is discussed in detail in Petzold)
Using Pens (Review), 1 Stock Pens // there are “stock” pens, which are solid - others can be dashed, etc. HPEN hPenWhite, hPenBlack; hPenWhite = GetStockObject (WHITE_PEN); // might do just once hPenBlack = GetStockObject (BLACK_PEN); // this is default : hdc = GetDC (hwnd); SelectObject (hdc, hPenWhite); // now, all drawing in white // draw something ReleaseDC(hdc); // until release device context : : hdc = GetDC (hwnd); SelectObject (hdc, hPenBlack); // now, all drawing in black // draw something ReleaseDC(hdc); // until release device context NOTE: Can draw a figure black and then redraw it in white to erase
Using Pens (Review), 2 The general form for creating pens: hPen = CreatePen (iPenStyle, iWidth, rgbColor) //static if not want to create & destroy iPenStyle = PS_SOLID, PS_DASH, PS_DOT, ... iWidth = 1, ... The RGB macro: rgbColor: 0 = no intensity (black), 255 = full intensity (birght red, green, blue) RGB macro: RGB (r, g, b) e.g., RGB (0, 0, 255) for a bright blue pen Examples: hPenSolidBlack = CreatePen (PS_SOLID, 1, RGB(0,0,0) ) hPenSolidWhite = CreatePen (PS_SOLID, 1, RGB(255, 255, 255) ) hPenDashedBlack = CreatePen (PS_DASH, 1, 0);
Raster Operations, Introduction Generally stated, “drawing” to the screen entails performing raster operations A “raster operation” is, well, an operation on the raster So far, the raster operation for a pixel has been “make it be the color of the pen”- The general form of raster operations considers both the values of the: source (what you specify to draw, e.g., the color of the pen), and the destination (what is already on the screen, state of the pixel currently displayed) Boolean operation is performed when pen writes to screen Consider the screen state as represented by 0 (off, black) and 1 (on, white) A black screen: House drawn (in white): 0 0 0 0 0 0 0 0 0 0 0 0 x 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 1 1 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 In this example screen (destination) is replaced with () the house (source) – note: value in screen is the 1 – color blue just to see Symbolically: D S (no matter what is already on the screen (destination), which we’ll see)
General Form “Drawing Mode” (Windows term) / Raster Operations, 1 Generally, some Boolean operation (op) is performed combining existing destination with what is to be written (source) to yield the final result at the destination (screen) D S op D The general form of raster operations considers both the values of the: source (what you specify to draw, e.g., the color of the pen), destination (what is already on screen, i.e., state of pixel currently displayed), and operation (how combine what on screen and what to be drawn) Note that this is somewhat different than presented in Petzold Ignores some windows elements, but is a more general statement
General Form “Drawing Mode” (Windows term) / Raster Operations, 2 In addition to D S, there are many ROPS: Pen (P, or S): 1 1 0 0 Boolean Destination (D): 1 0 1 0 Operation Drawing Mode Results: 0 0 0 0 0 R2_BLACK 0 0 0 1 ~(P ¦ D) R2_NOTMERGEPEN 0 0 1 0 ~P & D R2_MASKNOTPEN 0 0 1 1 ~P R2_NOTCOPYPEN 0 1 0 0 P & ~D R2_MASKPENNOT 0 1 0 1 ~D R2_NOT 0 1 1 0 P ^ D R2_XORPEN 0 1 1 1 ~(P & D) R2_NOTMASKPEN 1 0 0 0 P & D R2_MASKPEN 1 0 0 1 ~(P ^ D) R2_NOTXORPEN 1 0 1 0 D R2_NOP 1 0 1 1 ~P ¦ D R2_MERGENOTPEN (D gets S regardless 1 1 0 0 P R2_COPYPEN (default) of state/color of D) 1 1 0 1 P ¦ ~D R2_MERGEPENNOT 1 1 1 0 P ¦ D R2_MERGEPEN 1 1 1 1 1 R2_WHITE SetROP2 (hdc, iDrawMode) ;
Raster Operations, Example of Application, OR Can in fact combine Source and Destination in a number of ways D S op D, e.g., D S | D Pen (P, or S): 1 1 0 0 Boolean Destination (D):1 0 1 0 Operation Drawing Mode Results: 1 1 1 0 | “OR”, but, Windows calls R2_MERGEPEN Again, Boolean operation is performed when pen writes to screen Here, rasterop (ROP) applies “OR” logical operation to operands screen and “bitmap” Example: Draw this figure: X 0 1 0 1111 0 0 1 0 Apply (tediously!) rasterop at each pixel: Original screen: After draw: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 x 0 1 0 0 0 0 0 0 0 1 0 x 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 11110 0 0 0 0 0 11111 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Raster Operations, Another ROP, XOR, 1 Can in fact combine Source and Destination in a number of ways D S op D, e.g., D S ^ D Pen (P, or S): 1 1 0 0 Boolean Destination (D):1 0 1 0 Operation Drawing Mode 0 1 1 0 P ^ D “XOR”, R2_XORPEN Again, Boolean operation is performed when pen writes to screen Here, apply ROP XOR, and screen appears after write as if sort of “inverts” Example: Draw this figure: 0 0 1 0 1111 0 0 1 0 Apply rasterop at each pixel: Original screen: After draw: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 11 0 10 0 0 0 0 0 11111 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Raster Operations, Another ROP, XOR, 2 Can in fact combine Source and Destination in a number of ways D S op D, e.g., D S ^ D Pen (P, or S): 1 1 0 0 Boolean Destination (D):1 0 1 0 Operation Drawing Mode 0 1 1 0 P ^ D “XOR”, R2_XORPEN Again, Boolean operation is performed when pen writes to screen For XOR when it is applied again, screen is changed back to it’s original image! Example: Draw this figure: 0 0 1 0 1111 0 0 1 0 Apply rasterop at each pixel: After 1st XOR: After 2nd XOR - back to original!: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 11 0 10 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1111 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Demo Example: Draw this figure: 0 0 1 0 1111 0 0 1 0 Apply rasterop at each pixel: Original screen: After draw: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 11 0 10 0 0 0 0 0 11111 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Demo Example: Draw this figure: 0 0 1 0 1111 0 0 1 0 Apply rasterop at each pixel: After 1st XOR: After 2nd XOR - back to original!: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 11 0 10 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1111 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Demo Example: Draw this figure: 0 0 1 0 1111 0 0 1 0 Apply rasterop at each pixel: After 2nd XOR - back to original!: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Raster Operations, Another ROP, XOR, 3 The implication is that a figure can be: 1. Drawn with XOR anyplace (e.g., over other figures) - and figure is visible (though “sort of inverted” where touches other figs) - and other figures are sort of inverted 2. Drawn again with XOR at the same location to restore the original screen! Successive XOR draws and moves allows nondestructive “movement”: Draw with XOR (showing figure), redraw with XOR (erasing figure & restoring old) move to new location Draw with XOR (showing figure), redraw with XOR (erasing figure & restoring old) move to new location :
End • .