Chapter 7.Clipper Fundamentals

Clipper Fundamentals
   
DirectDraw can help with the bitmaps as long as the bitmaps are in the form of DirectDraw surfaces, or IDirectDrawSurface(s) to be exact.

Clipping Bitmaps the Hard Way
    1、Clip each pixel of the bitmap on a independent basis as it's generated. Simple, but slow.
    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

Making a DirectDraw Clip with IDirectDrawClipper

  1. Create a DirectDraw clipper object.
  2. Create a clipping list.
  3. Send the clipping list data to the clipper with IDIRECTDRAWCLIPPER::SetClipList().
  4. Attach the clipper to a window and/or surface with IDIRECTDRAWSURFACE7::SetClipper().

HRESULT IDIRECTDRAW7::CreateClipper(DWORD dwFlags, // control flags
        LPDIRECTDRAWCLIPPER FAR *lplpDDClipper, // address of interface pointer
        IUnknown FAR *pUnkOuter); // COM stuff

LPDIRECTDRAWCLIPPER lpddclipper = NULL; // hold the clipper

if (FAILED(lpdd->CreateClipper(0,&lpddclipper,NULL)))
    return(0);

typedef struct _RGNDATA
        { /* rgnd */
        RGNDATAHEADER rdh; // header info
        char Buffer[1];    // the actual RECT list
        } RGNDATA;

typedef struct _RGNDATAHEADER
        { // rgndh
        DWORD dwSize;   // size of this header in bytes
        DWORD iType;    // type of region data
        DWORD nCount;   // number of RECT'S in Buffer[]
        DWORD nRgnSize; // size of Buffer[]
        RECT  rcBound;  // a bounding box around all RECTS
        } RGNDATAHEADER;


HRESULT SetClipList(LPRGNDATA lpClipList, // ptr to RGNDATA
                    DWORD dwFlags);  // flags, always 0

HRESULT SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper);

In most cases, lpddsurface would be your offscreen rendering surface, such as the back buffer surface. Usually, you don't attach a clipper to the primary surface.

LPDIRECTDRAWCLIPPER DDraw_Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds,
int num_rects,
LPRECT clip_list)
{
// this function creates a clipper from the sent clip list and attaches
// it to the sent surface

int index; // looping var
LPDIRECTDRAWCLIPPER lpddclipper; // pointer to the newly
// created dd clipper
LPRGNDATA region_data; // pointer to the region
// data that contains
// the header and clip list

// first create the direct draw clipper
if (FAILED(lpdd->CreateClipper(0,&lpddclipper,NULL)))
return(NULL);

// now create the clip list from the sent data

// first allocate memory for region data
region_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+
num_rects*sizeof(RECT));

// now copy the rects into region data
memcpy(region_data->Buffer, clip_list, sizeof(RECT)*num_rects);

// set up fields of header
region_data->rdh.dwSize = sizeof(RGNDATAHEADER);
region_data->rdh.iType = RDH_RECTANGLES;
region_data->rdh.nCount = num_rects;
region_data->rdh.nRgnSize = num_rects*sizeof(RECT);
region_data->rdh.rcBound.left = 64000;
region_data->rdh.rcBound.top = 64000;
region_data->rdh.rcBound.right = -64000;
region_data->rdh.rcBound.bottom = -64000;

// find bounds of all clipping regions
for (index=0; index<num_rects; index++)
{
// test if the next rectangle unioned with
// the current bound is larger
if (clip_list[index].left < region_data->rdh.rcBound.left)
region_data->rdh.rcBound.left = clip_list[index].left;

if (clip_list[index].right > region_data->rdh.rcBound.right)
region_data->rdh.rcBound.right = clip_list[index].right;

if (clip_list[index].top < region_data->rdh.rcBound.top)
region_data->rdh.rcBound.top = clip_list[index].top;

if (clip_list[index].bottom > region_data->rdh.rcBound.bottom)
region_data->rdh.rcBound.bottom = clip_list[index].bottom;

} // end for index

// now we have computed the bounding rectangle region and set up the data
// now let's set the clipping list

if (FAILED(lpddclipper->SetClipList(region_data, 0)))
{
// release memory and return error
free(region_data);
return(NULL);
} // end if

// now attach the clipper to the surface
if (FAILED(lpdds->SetClipper(lpddclipper)))
{
// release memory and return error
free(region_data);
return(NULL);
} // end if

// all is well, so release memory and
// send back the pointer to the new clipper
free(region_data);
return(lpddclipper);

} // end DDraw_Attach_Clipper

The function is almost trivial to use. Let's say you have an animation system with a primary surface called lpddsprimary and a secondary back buffer called lpddsback, to which you want to attach a clipper with the following RECT list:

RECT rect_list[3] = {{10,10,50,50},
{100,100,200,200},
{300,300, 500, 450}};

Here's the call to do it:

LPDIRECTDRAWCLIPPER lpddclipper =
DDraw_Attach_Clipper(lpddsback,3,rect_list);

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值