⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bitmap.html

📁 非常好的在win32下用c++sdk开发的工具书
💻 HTML
📖 第 1 页 / 共 2 页
字号:
    {
        Blitter blitter (_background);
        blitter.BlitTo (canvas);
    }
private:
    Bitmap  _background;
};</pre>
<!--End Code--></font>
                       </td>
					   <td width=20>&nbsp;</td>
		</tr>
        </table>
        <!--End of yellow background-->
<hr>

<p>A <b>sprite</b> is an animated bitmap that moves over some background. We already know how to display bitmaps--we could blit the background first and then blit the sprite bitmap over it. This will work as long as the sprite is rectangular. If you want to be more sophisticated and use a non-rectangular sprite, you need a mask.
<p>The two pictures below are that of a sprite (my personal pug, Fanny) and its mask. The mask is a monochrome bitmap that has black areas where we want the sprite to be transparent. The sprite, on the other hand, must be white in these areas. What we want is to be able to see the background through these areas. 
<p><img src="images/fanny.gif" width=201 height=232 border=1 alt="Sprite" hspace=20>
<img src="images/mask.gif" width=201 height=232 border=0 alt="Mask" hspace=20>
<p>The trick is to first blit the background, then blit the mask using logical OR, and then blit the sprite over it using logical AND. 

<p>ORing a black mask pixel (all zero bits) with a background pixel will give back the background pixel. ORing a white mask pixel (all one bits) with a background will give a white pixel. So after blitting the mask, we'll have a white ghost in the shape of our sprite floating over the background. 
<p><img src="images/or.gif" width=261 height=75 border=0 alt="Background OR Mask">

<p>ANDing a white sprite pixel (all ones) with a background pixel will give back the background pixel. ANDing a non-white sprite pixel with the white (all ones) background (the ghost from previous step) will give the sprite pixel. We'll end up with the sprite superimposed on the background.
<p><img src="images/and.gif" width=258 height=80 border=0 alt="(Background OR Mask) AND Sprite">
<hr>

<p>What reamains is to implement the animation. The naive implementation would be to keep re-drawing the image: background, mask and sprite, changing the position of the mask and the sprite in each frame. The problem with this approach is that it results in unacceptable flutter. The trick with good animation is to prepare the whole picture off-line, as a single bitmap, and then blit it to screen in one quick step. This technique is called double buffering--the first buffer being the screen buffer, the second one--our bitmap.
<p>We'll also use Windows timer to time the display of frames.
         <!--Yellow background-->
        <table cellpadding=10 cellspacing=0 width=100%>
                <tr>
                      <td width=20>&nbsp;</td>
            	      <td bgcolor="#e0e080"><font color="#000000">
<pre>class <font color="#cc0066"><b>WinTimer</b></font>
{
public:
    WinTimer (HWND hwnd = 0, int id = -1) 
        : _hwnd (hwnd), _id (id)
    {}

    void Create (HWND hwnd, int id)
    {
        _hwnd = hwnd;
        _id = id;
    }

    void Set (int milliSec)
    {
        ::<font color="#000099"><b>SetTimer</b></font> (_hwnd, _id, milliSec, 0);
    }

    void Kill ()
    {
        ::<font color="#000099"><b>KillTimer</b></font> (_hwnd, _id);
    }
    int  GetId () const { return _id; }
private:
    HWND    _hwnd;
    int     _id;
};</pre>
<!--End Code--></font>
                       </td>
					   <td width=20>&nbsp;</td>
		</tr>
        </table>
        <!--End of yellow background-->
<p>We'll put the timer in our Controller object and initialize it there.

         <!--Yellow background-->
        <table cellpadding=10 cellspacing=0 width=100%>
                <tr>
                      <td width=20>&nbsp;</td>
            	      <td bgcolor="#e0e080"><font color="#000000">
<pre>class <font color="#cc0066"><b>Controller</b></font>
{
public:
    Controller(HWND hwnd, CREATESTRUCT * pCreate);
    ~Controller ();
    void    <font color="Red">Timer</font> (int id);
    void    Size (int x, int y);
    void    Paint ();
    void    Command (int cmd);

private:

    HWND        _hwnd;
    <font color="Red">WinTimer</font>    _timer;
    View        _view;
};

<font color="#cc0066"><b>Controller::Controller</b></font> (HWND hwnd, CREATESTRUCT * pCreate)
   :_hwnd (hwnd), _timer (hwnd, 1), _view (pCreate->hInstance)
{
	_timer.Set (100);
}</pre>
<!--End Code--></font>
                       </td>
					   <td width=20>&nbsp;</td>
		</tr>
        </table>
        <!--End of yellow background-->

<p>Once set, the timer sends our program timer messages and we have to process them.

         <!--Yellow background-->
        <table cellpadding=10 cellspacing=0 width=100%>
                <tr>
                      <td width=20>&nbsp;</td>
            	      <td bgcolor="#e0e080"><font color="#000000">
<pre>LRESULT CALLBACK MainWndProc
    (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    Controller * pCtrl = WinGetLong&lt;Controller *&gt; (hwnd);

    switch (message)
    {
    ...
    case WM_TIMER:
        pCtrl->Timer (wParam);
        return 0;
    ...
    }
    return ::DefWindowProc (hwnd, message, wParam, lParam);
}

void <font color="#cc0066"><b>Controller::Timer</b></font> (int id)
{
    _timer.Kill ();
    _view.Step ();
    UpdateCanvas canvas (_hwnd);
    _view.Update (canvas);
    ::<font color="#000099"><b>InvalidateRect</b></font> (_hwnd, 0, FALSE);
    _timer.Set (50);
}

void <font color="#cc0066"><b>Controller::Paint</b></font> ()
{
    PaintCanvas canvas (_hwnd);
    _view.Paint (canvas);
}</pre>
<!--End Code--></font>
                       </td>
					   <td width=20>&nbsp;</td>
		</tr>
        </table>
        <!--End of yellow background-->
<p>The Update method of View is the workhorse of our program. It creates the image in the buffer. We then call <font color="#000099"><b>InvalidateRectangle</b></font> to force the repaint of our window (the last parameter, FALSE, tells Windows not to clear the previous image--we don't want it to flash white before every frame). 
<p>Here's the class View, with the three bitmaps.

         <!--Yellow background-->
        <table cellpadding=10 cellspacing=0 width=100%>
                <tr>
                      <td width=20>&nbsp;</td>
            	      <td bgcolor="#e0e080"><font color="#000000">
<pre>class View
{
public:
    View (HINSTANCE hInst);

    void SetSize (int cxNew, int cyNew)
    {
        _cx = cxNew;
        _cy = cyNew;
    }
    void Step () { ++_tick; }
    void Update (Canvas &amp; canvas);
    void Paint (Canvas &amp; canvas);

private:
    int     _cx, _cy;
    int     _tick;
    Bitmap  _bitmapBuf; // for double buffering

    Bitmap  <font color="Red">_background</font>;
    int     _widthBkg, _heightBkg;
    Bitmap  <font color="Red">_sprite</font>;
    Bitmap  <font color="Red">_mask</font>;
    int     _widthSprite, _heightSprite;
};

View::View (HINSTANCE hInst)
: _tick (0)
{
    // Load bitmap from file
    _background.Load ("picture.bmp");
    // Load bitmap from resource
    _background.GetSize (_widthBkg, _heightBkg);
    // Load bitmaps from resources
    _sprite.Load (hInst, IDB_FANNY);
    _mask.Load (hInst, IDB_MASK);
    _sprite.GetSize (_widthSprite, _heightSprite);

    DesktopCanvas canvas;
    _bitmapBuf.CreateCompatible (canvas, 1, 1);
    _cx = 1;
    _cy = 1;
}</pre>
<!--End Code--></font>
                       </td>
					   <td width=20>&nbsp;</td>
		</tr>
        </table>
        <!--End of yellow background-->
<p>And here's the implementation of Update. We create a bitmap canvas in memory, making it compatible with the current display canvas. We blit the background image into it, then blit the mask and the sprite (notice the change of position for each frame). Finally, we transfer the complete bitmap into our buffer (overloaded assignment operator at work!).

         <!--Yellow background-->
        <table cellpadding=10 cellspacing=0 width=100%>
                <tr>
                      <td width=20>&nbsp;</td>
            	      <td bgcolor="#e0e080"><font color="#000000">
<pre>void View::Update (Canvas &amp; canvas)
{
    const double speed = 0.01;
    Bitmap bmp (canvas, _cx, _cy);
    BitmapCanvas bmpCanvas (canvas, bmp);

    RECT rect = { 0, 0, _cx, _cy};
    bmpCanvas.WhiteWash (rect);
    // Do the off-line drawing
    Blitter bltBkg (_background);
    bltBkg.BlitTo (bmpCanvas);

    int xRange = (_widthBkg - _widthSprite) / 2;
    int yRange = (_heightBkg - _heightSprite) / 2;
    int x = xRange + static_cast&lt;int&gt; (xRange * sin (speed * _tick));
    int y = yRange + static_cast&lt;int&gt; (yRange * cos (4 * speed * _tick));
    Blitter bltMask (_mask);
    bltMask.SetMode (SRCPAINT);
    bltMask.SetDest (x, y);
    bltMask.BlitTo (bmpCanvas);

    Blitter bltSprite (_sprite);
    bltSprite.SetMode (SRCAND);
    bltSprite.SetDest (x, y);
    bltSprite.BlitTo (bmpCanvas);
    // update the buffer
    _bitmapBuf = bmp;
}</pre>
<!--End Code--></font>
                       </td>
					   <td width=20>&nbsp;</td>
		</tr>
        </table>
        <!--End of yellow background-->
<p>For completness, here's the definition of bitmap canvas. You draw directly on this canvas using standard canvas methods, like Line, Text, SetPixel, etc... Here we only blit bitmaps into it.

         <!--Yellow background-->
        <table cellpadding=10 cellspacing=0 width=100%>
                <tr>
                      <td width=20>&nbsp;</td>
            	      <td bgcolor="#e0e080"><font color="#000000">
<pre>class <font color="#cc0066"><b>BitmapCanvas</b></font>: public <font color="#cc0066"><b>MemCanvas</b></font>
{
public:
    BitmapCanvas (HDC hdc, HBITMAP hBitmap)
        : MemCanvas (hdc)
    {
        // convert bitmap to format compatible with canvas
        _hOldBitmap = reinterpret_cast<HBITMAP> (::<font color="#000099"><b>SelectObject</b></font> (_hdc, hBitmap));
    }
    ~BitmapCanvas ()
    {
        ::<font color="#000099"><b>SelectObject</b></font> (_hdc, _hOldBitmap);
    }
private:
    HBITMAP _hOldBitmap;
};

class <font color="#cc0066"><b>MemCanvas</b></font>: public <font color="#cc0066"><b>Canvas</b></font>
{
public:
    MemCanvas (HDC hdc) 
        : Canvas (::<font color="#000099"><b>CreateCompatibleDC</b></font> (hdc))
    {}

    ~MemCanvas ()
    {
        ::<font color="#000099"><b>DeleteDC</b></font>(_hdc); 
    }
};</pre>
<!--End Code--></font>
                       </td>
                       <td width=20>&nbsp;</td>
        </tr>
        </table>
        <!--End of yellow background-->
<hr>
<img src="images/brace.gif" width=16 height=16 border=0 alt="">As usual, you can <a href="source/bitmap.zip">download</a> the complete source code of the application that was used in this example. Remember to put the file picture.bmp in the same directory in which you run the compiled program.
<p>Now, if you want more speed, read about <a href="direct.html">DirectDraw</a>.
<hr>


   <!-- end main box -->
   </td></tr>
   </table>
   </td>
   <td width=10><!-- Right margin -->&nbsp;</td>
   </tr>
</table> <!-- End main table -->

<layer src="http://www.spidersoft.com/ads/bwz468_60.htm" visibility=hidden id=a1 width=600 onload="moveToAbsolute(ad1.pageX,ad1.pageY); a1.clip.height=60;visibility='show';"></layer>
</body>
</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -