320 likes | 580 Views
Windows GDI Programming. CIS 487/587 Bruce R. Maxim UM-Dearborn. Validating. Whenever either you or Windows disturbs a window a WM_PAINT message is sent The area to be repainted is the invalid rectangle
E N D
Windows GDI Programming CIS 487/587 Bruce R. Maxim UM-Dearborn
Validating • Whenever either you or Windows disturbs a window a WM_PAINT message is sent • The area to be repainted is the invalid rectangle • The coordinates of the invalid rectangle are shipped with the WM_PAINT message as part of the validating process
Processing WM_PAINT • BeginPaint( ) … EndPaint( ) • Advantage: all needed validating done automatically • Disadvantage: invalid rectangle is same as clipping rectangle (can’t draw outside invalid rectangle) • This approach fools Windows into believing you fixed the invalid rectangle whether you have drawn anything or not
Processing WM_PAINT • GetDC( ) … ReleaseDC( ) • Advantage:you can draw outside the invalid rectangle • Disadvantage: you need to validate every rectangle manually using ValidateRect( ) • Note: With either method you need to be sure that windows does not fill in your Background to avoid losing your drawing
Invalidating Entire Window case WM_PAINT: { // NULL is pointer to invalid rectangle // meaning entire window ValidateRect(hwnd,NULL); // simply validate the window hdc = BeginPaint(hwnd,&ps); // fixes go here EndPaint(hwnd,&ps); // end painting return(0); // return success } break;
Validating Entire Window case WM_PAINT: { // NULL is pointer to invalid rectangle // meaning entire window ValidateRect(hwnd,NULL); // simply validate the window without // doing any drawing return(0); // return success } break;
Avoid Repaint case WM_PAINT: { hdc = GetDC(hwnd); // do graphics here ReleaseDC(hwnd,hdc); // validate the window to clear message ValidateRect(hwnd,hdc); return(0); // return success } break;
Display Surface Basics • Resolutions in pixels 640x480, 800x600, 1024x768, … • Color depth (# color bits per pixel) 6, 16, 24, 32 • Color space (actual # available colors) 8 bits = 256 colors, 16 bits = 65536
Display Modes • RGB mode • True RGB values are encoded for each pixel displayed • Palletized mode • Color indirection scheme • 256 colors available • Value 0 to 255 is stored with each pixel • Color value looked up in CLUT
Color Objects • Windows uses to data structures • COLOREF: byte structure allows you to create colors on the fly • PALETTEENTRY: all creation of pallets with control flag components • Complete control of pallets is best done using DirectX
Drawing Text • TextOut( ) • No formatting or processing of text string is done before it is displayed • DrawText( ) • Allows justification, clipping, etc. prior to displaying text string
TextOut Example main_window_handle = hwnd; // save main window handle HDC hdc = GetDC(hwnd); // get the dc and hold it // set the foreground color to random SetTextColor(hdc, RGB(rand()%256,rand()%256,rand()%256)); // set the background color to black SetBkColor(hdc, RGB(0,0,0)); // finally set the transparency mode to transparent SetBkMode(hdc, TRANSPARENT); // draw some text at a random location TextOut(hdc,rand()%400,rand()%400, "GDI Text Demo!", strlen("GDI Text Demo!")); ReleaseDC(hwnd,hdc); // release the dc
What about WM_PAINT? case WM_PAINT: { // simply validate the window hdc = BeginPaint(hwnd,&ps); // you would do all your painting here EndPaint(hwnd,&ps); // return success return(0); } break;
Additional Issues • You should consider saving the old values for foreground, ground, and transparency so that you can restore them after you set them • Example we might declare the following: COLORREF old_fcolor, // old foreground old_bcolor; // old background int old_tmode; // old transparency
TextOut Example 2 main_window_handle = hwnd; // save main window handle HDC hdc = GetDC(hwnd); // get the dc and hold it // save old attributes and set new old_fcolor = SetTextColor(hdc,RGB(255,255,255)); old_bcolor = SetBkColor(hdc, RGB(0,0,0)); old_tmode= SetBkMode(hdc, TRANSPARENT); // draw some text at a random location TextOut(hdc, 120, 200, “Hello", strlen(“Hello")); // Restore the old values SetTextColor(hdc, old_fcolor); SetBkColor(hdc, old_bcolor); SetBkMode(hdc, old_tmode); ReleaseDC(hwnd,hdc); // release the dc
Text Metrics • The function GetTextMetrics can be used to query the system for things like • Font height • Average width • Max width • First character defined in font • Last character defined in font • Set of values returned in fields of a parameter of type tagTEXTMETRIC
Drawing Shapes • GDI allows you to draw things like • Points • Lines • Circles and ellipses • Rectangles • Curves • Polygons • Bitmaps • Metafiles (instructions that can be “replayed”)
Pens • Pens are GDI objects used to draw lines • Pens have two attributes • RGB color • Styles like • PS_DASH - - - - • PS_DOT . . . . • PS_DASHDOT _ . _ . • PS_NULL
Using a Pen // get the graphics device context hdc = GetDC(hwnd); // create a red colored pen HPEN red_pen = CreatePen(PS_SOLID,1,RGB(255, 0, 0)); // selecting pen and saving old value HPEN old_hpen = (HPEN)SelectObject(hdc,red_pen); // draw with pen // deleting pen SelectObject(hdc,old_hpen); DeleteObject(red_ pen); // release the device context ReleaseDC(hwnd,hdc)
Brushes • Brushes are used to fill in line objects • Examples // creating a solid brush HBRUSH blue_brush = CreateSolidBrush(RGB(0,0,255)); // creating a patterned brush HBRUSH green_brush = CreateHatchBrush(HS_DIAGCROSS, RGB(0,255,0)); // creating a bitmap brush (8x8) HBRUSH bitmap_brush = CreatePatternBrush(hBitMap);
Selecting and Destroying Brushes // select brush and save old brush HBRUSH old_brush = SelectObject(hdc, red_brush); // use the brush // restore old brush SelectObject(hdc, old_brush); DeleteObject(red_brush);
Plotting Points hdc = GetDC(hwnd); // get the dc for the window // draw 1000 pixels for (int index=0; index < 1000; index++) { // get random position int x = rand()%400; int y = rand()%300; COLORREF color = RGB(rand()%255,rand()%255,rand()%255); SetPixel(hdc, x,y, color); } // end for index ReleaseDC(hwnd, hdc); // release the dc
Drawing Lines // create pen HPEN red_pen = CreatePen(PS_SOLID,1,RGB(255, 0, 0)); // selecting pen and saving old value SelectObject(hdc,red_pen); // move to starting point MoveToEx(hdc,rand()%WINDOW_WIDTH,rand()%WINDOW_HEIGHT,NULL); // draw the line LineTo(hdc,rand()%WINDOW_WIDTH,rand()%WINDOW_HEIGHT);
Drawing Rectangles hdc = GetDC(hwnd); // get the graphics device context RECT rect; // used to hold rect info // create a random rectangle rect.left = rand()% WINDOW_WIDTH; rect.top = rand()% WINDOW_HEIGHT; rect.right = rand()% WINDOW_WIDTH; rect.bottom = rand()% WINDOW_HEIGHT; // create a random brush HBRUSH hbrush = CreateSolidBrush(RGB(100, 50, 80)); // draw either a filled rect or a wireframe rect if ((rand()%2)==1) FillRect(hdc,&rect,hbrush); else FrameRect(hdc,&rect,hbrush); DeleteObject(hbrush); // now delete the brush ReleaseDC(hwnd,hdc);// release the device context
Drawing Circles and Ellipses • Circle is special case of ellipse • To draw a circle at (100, 100) with diameter 20 Ellipse(hdc, 90, 90,110, 110); • To draw an ellipse centered at (100, 100) with major axis 100 and minor axis 60 Ellipse(hdc, 100-50, 100-30, 100+50, 100+30);
Bouncing Ball • An old computer animators trick is to • Draw an object using the foreground color • Erase object by redrawing in the background color • Change the object screen coordinates and draw again in the foreground color • We can make use of this trick and use Ellipse to draw a bouncing ball
Bouncing Ball hdc = GetDC(hwnd); // create the pens and brushes HPEN white_pen = CreatePen(PS_SOLID, 1, RGB(255,255,255)); HPEN black_pen = CreatePen(PS_SOLID, 1, RGB(0,0,0)); HBRUSH green_brush = CreateSolidBrush(RGB(0,255,0)); HBRUSH black_brush = CreateSolidBrush(RGB(0,0,0)); // starting position of ball int ball_x = WINDOW_WIDTH/2; int ball_y = WINDOW_HEIGHT/2; // initial velocity of ball int xv = -4+rand() % 8; int yv = -4+rand() % 8;
Bouncing Ball // ERASE the last position of the ball // first select the black pen and brush into context SelectObject(hdc, black_pen); SelectObject(hdc, black_brush); // draw the ball Ellipse(hdc, ball_x, ball_y, ball_x + 32, ball_y + 32); // MOVE the ball ball_x+=xv; ball_y+=yv; // test for collisions, first x-axis if (ball_x < 0 || ball_x > WINDOW_WIDTH - 32) { // invert x-velocity of ball xv=-xv; // push ball back ball_x+=xv; } // end if else // test for y-axis collisions if (ball_y < 0 || ball_y > WINDOW_HEIGHT - 32) { // invert y-velocity of ball yv=-yv; // push ball back ball_y+=yv; } // end if // now select the green and white colors for brush and pen SelectObject(hdc, white_pen); SelectObject(hdc, green_brush); // DRAW the ball Ellipse(hdc, ball_x, ball_y, ball_x + 32, ball_y + 32); // main game processing goes here if (KEYDOWN(VK_ESCAPE)) SendMessage(hwnd, WM_CLOSE, 0,0); // slow system down a little Sleep(10); } // end while // delete all the objects DeleteObject(white_pen); DeleteObject(black_pen); DeleteObject(green_brush); DeleteObject(black_brush); // release the device context ReleaseDC(hwnd,hdc);
Bouncing Ball // ERASE the last position of the ball // first select the black pen and brush into context SelectObject(hdc, black_pen); SelectObject(hdc, black_brush); // draw the ball Ellipse(hdc, ball_x, ball_y, ball_x + 32, ball_y + 32); // MOVE the ball ball_x+=xv; ball_y+=yv;
Bouncing Ball // test for collisions, first x-axis if (ball_x < 0 || ball_x > WINDOW_WIDTH - 32) { xv=-xv; // invert x-velocity of ball ball_x+=xv; // push ball back } // end if else // test for y-axis collisions if (ball_y < 0 || ball_y > WINDOW_HEIGHT - 32) { yv=-yv; // invert y-velocity of ball ball_y+=yv; // push ball back } // end if
Bouncing Ball // select the green and white colors for brush and pen SelectObject(hdc, white_pen); SelectObject(hdc, green_brush); // DRAW the ball Ellipse(hdc, ball_x, ball_y, ball_x + 32, ball_y + 32); DeleteObject(white_pen); // delete all the objects DeleteObject(black_pen); DeleteObject(green_brush); DeleteObject(black_brush); ReleaseDC(hwnd,hdc); // release the device context