Tricks of the Windows Game Programming Gurus:Advanced DirectDraw and Bitmapped Graphics

All ITKnowledge Source Code Search Tips Advanced Search |

| Tricks of the Windows Game Programming Gurus by Andre LaMothe Sams, Macmillan Computer Publishing ISBN: 0672313618 Pub Date: 09/27/99

Search this book:

Previous | Table of Contents | Next

#### Clipping Pixels to a Viewport

Figure 7.17 gives you a visual of the problem. You want to clip a pixel with coordinates (x,y) to a viewport located at (x1,y1) to (x2,y2). If (x,y) is within the rectangle defined by (x1,y1) to (x2,y2), render it; otherwise, don’t. Simple enough?

Figure 7.17 A detailed view of the clipping region.

Here’s the code for a 640×480 linear 8-bit mode:

    // assume clipping rectangle is global

    int x1,y1,x2,y2; // these are defined somewhere

    void Plot_Pixel_Clip8(int x, int y,

                          UCHAR color,

                          UCHAR *video_buffer)

    {

    // test the pixel to see if it’s in range

    if (x>=x1 && x<=x2 && y>=y1 && y<=y2)

        video_buffer[x+y*640] = color;

    } // end if

Of course, there’s a lot of room for optimization, but you get the point—you’ve created a software filter on the pixel coordinates. Only pixel coordinate values that satisfy the `if` statement pass through the filter—interesting concept, huh? Now, the preceding clipper is very general, but in many cases, the window or viewport is located at (0,0) and has dimensions (`win_width`, `win_height`). This simplifies your code a little:

    // assume clipping rectangle is global

    int x1,y1,x2,y2; // these are defined somewhere

    void Plot_Pixel2_Clip8(int x, int y,

                           UCHAR color,

                           UCHAR *video_buffer)

    {

    // test the pixel to see if it’s in range

    if (x>=0 && x<win_width && y>=0 && y<=win_height)

        video_buffer[x+y*640] = color;

    } // end if

See? In addition, more optimizations can be made whenever zeros are around. Now that you get the point of clipping and know how to do it, I’ll show you how to clip an entire bitmap.

#### Clipping Bitmaps the Hard Way

Clipping bitmaps is as simple as clipping pixels. There are two ways to approach it:

  • Method 1: Clip each pixel of the bitmap on a independent basis as it’s generated. Simple, but slow.
  • Method 2: Clip the bounding rectangle of the bitmap to the viewport, and then only draw the portion of the bitmap that’s within the viewport. More complex, but very fast, with almost no performance loss and no hit at all in the inner loop.

Obviously, you’re going to use Method 2, which is shown graphically in Figure 7.18. Also, I’m going to generalize a little and assume that the screen extends from (0,0) to (`SCREEN_WIDTH-1`, `SCREEN_HEIGHT-1`), that your bitmap has it’s upper-left corner at (x,y), and that it’s exactly so many width×height pixels in dimension—or in other words, the bitmap extends from (x,y) to (x+width-1, y+height-1). Please take a minute and make sure you see the reasoning for the “-1” factors. Basically, if a bitmap is 1×1, it has a width of 1 and a height of 1. Therefore, if the origin of the bitmap is at (x,y), the bitmap extends from (x,y) to (x+1-1,y+1-1) or (x,y). This is because it’s only 1×1 pixels, so the “-1” factor is needed, as shown by this base case.

Figure 7.18 How to clip the bounding box of a bitmap.

The plan of attack for clipping is simple—you just clip the virtual rectangle of the bitmap to the viewport and then draw only the portions of the bitmap that are in the clipped bitmap. Here’s the code for a 640×480×8 linear mode:

    // dimensions of window or viewport (0,0) is origin

    #define SCREEN_WIDTH  640

    #define SCREEN_HEIGHT 480

    void Blit_Clipped(int x, int y,          // position to draw bitmap

              int width, int height, // size of bitmap in pixels

              UCHAR *bitmap,         // pointer to bitmap data

              UCHAR *video_buffer)   // pointer to video buffer surface

    {

    // this function blits and clips the image sent in bitmap to the

    // destination surface pointed to by video_buffer

    // the function assumes a 640x480x8 mode with linear pitch

    // first do trivial rejections of bitmap, is it totally invisible?

    if ((x >= SCREEN_WIDTH) || (y>= SCREEN_HEIGHT) ||

        ((x + width) <= 0) || ((y + height) <= 0))

    return;

    // clip source rectangle

    // pre-compute the bounding rect to make life easy

    int x1 = x;

    int y1 = y;

    int x2 = x1 + width - 1;

    int y2 = y1 + height -1;

    // upper left hand corner first

    if (x1 < 0)

       x1 = 0;

    if (y1 < 0)

       y1 = 0;

    // now lower left hand corner

    if (x2 >= SCREEN_WIDTH)

        x2 = SCREEN_WIDTH-1;

    if (y2 >= SCREEN_HEIGHT)

        y2 = SCREEN_HEIGHT-1;

    // now we know to draw only the portions

    // of the bitmap from (x1,y1) to (x2,y2)

    // compute offsets into bitmap on x,y axes,

    // we need this to compute starting point

    // to rasterize from

    int x_off = x1 - x;

    int y_off = y1 - y;

    // compute number of columns and rows to blit

    int dx = x2 - x1 + 1;

    int dy = y2 - y1 + 1;

    // compute starting address in video_buffer

    video_buffer += (x1 + y1*640);

    // compute starting address in bitmap to scan data from

    bitmap += (x_off + y_off*width);

    // at this point bitmap is pointing to the first

    // pixel in the bitmap that needs to

    // be blitted, and video_buffer is pointing to

    // the memory location on the destination

    // buffer to put it, so now enter rasterizer loop

    UCHAR pixel; // used to read/write pixels

    for (int index_y = 0; index_y < dy; index_y++)

         {

         // inner loop, where the action takes place

         for (int index_x = 0; index_x < dx; index_x++)

              {

              // read pixel from source bitmap,

              // test for transparency and plot

              if ((pixel = bitmap[index_x]))

                  video_buffer[index_x] = pixel;

              } // end for index_x

              // advance pointers

              video_buffer+=640;   // bytes per scanline

              bitmap      +=width; // bytes per bitmap row

         } // end for index_y

    } // end Blit_Clipped

Previous | Table of Contents | Next

Copyright © Macmillan Computer Publishing, Inc.

Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.