0

I have this image: enter image description here

I want to generate the set of sprites, each 32x32 in size. How can I do this with C++, no library used. Texture class:

class Texture
{

protected:
    // We cannot create or copy base class texture objects
    // We will only ever have pointers or references to base
    // class texture objects used in our program (and these
    // will refer to derived class textures
    Texture() = default;
    Texture(Texture const &) = default;
    Texture & operator=(Texture const &) = default;

    virtual void LoadFromFile(std::string const & strFileName) = 0;
    virtual void LoadFromResource(unsigned int rid) = 0;

public:
    virtual ~Texture(){}

    //  virtual Rect const & GetBounds() const = 0;
    virtual int Width() const = 0;
    virtual int Height() const = 0;
};

using TEXTURE_PTR = std::shared_ptr<Texture>;

Sprite class:

class Sprite
{
private:

    virtual void draw_impl(Canvas & c) = 0;
    TEXTURE_PTR  m_pTexture;

protected:
    // Ensure that Sprite objects can only be constructed by derived classes
    explicit Sprite(TEXTURE_PTR pt = nullptr,POINT2f const & p = { 0, 0 });

    // All Sprite objects have a position state variable
    POINT2f  m_position;


    // Sprite objects can only be copied by derived class objects
    Sprite(const Sprite&) = default;
    Sprite& operator=(const Sprite&) = default;

public:

    virtual ~Sprite(){}

    void OnDraw(Canvas & c);

    void SetPosition(POINT2f const & pos);
    POINT2f const & GetPosition() const;
    void SetTexture(TEXTURE_PTR pt);

};

AND i create the sprite this way:

TEXTURE_PTR pLightning = std::make_shared<Texture>("resource//Lightning.bmp", RGB(255, 0, 255));
std::shared_ptr<Sprite> pSpark = std::make_shared<Sprite>(pLightning);

How can I generate 9 sprites from the above image with this method?

Edit I come up with these code but still doesn't work

class WinTexture : public Texture
{

protected:
    HBITMAP m_hbmImage;
    HBITMAP m_hbmMask;
    BITMAP  m_bmParam;


    virtual void LoadFromResource(UINT rid);
    virtual void LoadFromFile(std::string const & strFileName);
    void CreateMask(DWORD dwTransparent);

public:
    // Construct from Windows Resource
    WinTexture(UINT uid, COLORREF dwTransparent);

    // Constructor from file load
    WinTexture(std::string const & strFilename, COLORREF dwTransparent);

    //Contruct from other Texture
    WinTexture(std::shared_ptr<WinTexture> wt, int xStart,int yStart, int w, int h);

    virtual ~WinTexture();

    // Inherited interface
//  virtual Rect const & GetBounds() const;
    virtual int Width() const;
    virtual int Height() const;

    HBITMAP ImageHandle() const;
    HBITMAP MaskHandle() const;

};

with this, I want to make a constructor to create from other WinTexture:

WinTexture::WinTexture(std::shared_ptr<WinTexture> wt, int xStart, int yStart, int w, int h)
    : Texture(),                // as above
    m_hbmImage(NULL),
    m_hbmMask(NULL) {
    HDC hdcMem1 = CreateCompatibleDC(0);
    HDC hdcMem2 = CreateCompatibleDC(0);

    m_hbmImage = CreateBitmap(w, h, 1, 1, NULL);
    //m_hbmImage = CreateCompatibleBitmap(hdcMem2, 1, 1);
    SelectObject(hdcMem1, wt->ImageHandle());
    SelectObject(hdcMem2, m_hbmImage);
    BitBlt(hdcMem2, xStart, yStart, w, h,hdcMem1, 0, 0, SRCCOPY);
    BitBlt(hdcMem1, xStart, yStart, w, h, hdcMem2, 0, 0, SRCINVERT);
    //SaveDC(hdcMem2);
    DeleteDC(hdcMem1);
    DeleteDC(hdcMem2);
    CreateMask(RGB(0, 0, 0));
}

EDIT Currently, I have created this class from Sprite:

class TexturedSprite : public Sprite
{
    private:
        TEXTURE_PTR  m_pTexture;

        virtual void draw_impl(Canvas & c);

    protected:

    public:
        explicit TexturedSprite(TEXTURE_PTR pt = nullptr, POINT2f pos = { 32, 32});
        explicit TexturedSprite(int xStart,int yStart, int w, int h,TEXTURE_PTR pt = nullptr, POINT2f pos = { 32, 32 });

        virtual ~TexturedSprite(){}

        void SetTexture(TEXTURE_PTR pt);
};

I can't figure out how to implement the second constructor, to copy a part of input texture (pt):

TexturedSprite::TexturedSprite(int xStart, int yStart, int w, int h, TEXTURE_PTR pt , POINT2f pos )
:Sprite(pos)
{
    HDC hdcMem1 = CreateCompatibleDC(0);
    HDC hdcMem2 = CreateCompatibleDC(0);
//How to assign values to DC?
    BitBlt(hdcMem1, 32, 32, w, h, hdcMem2, xStart, yStart, SRCCOPY);
    DeleteDC(hdcMem1);
    DeleteDC(hdcMem2);
}
Le Duy Khanh
  • 1,279
  • 2
  • 14
  • 34

2 Answers2

2

At least as I read things right now, your basic intent is to load the texture, then create the individual sprites by copying 32x32 pixel pieces of the texture into the individual sprites. Unless you intend to manipulate the sprites from separate threads (which strikes me as unlikely) I'd avoid doing that.

Instead, I'd take note of a couple of the last parameters you supply to BitBlt:

BitBlt(hdcMem2, xStart, yStart, w, h,hdcMem1, 0, 0, SRCCOPY);

The 0, 0 just before the SRCCOPY specify the location in the source bitmap to use as the starting point of the BitBlt.

This lets you load the texture once, and just use that single texture for all the sprites it contains. Drawing an individual sprite at a particular location only requires that you specify the X, Y coordinates of that sprite within the source bitmap (specifically, the top, left-hand corner of that sprite) and draw a 32x32 chunk starting from there. If you want to define individual sprite objects, you can certainly do that, but each just needs to store something like a shared_ptr to the loaded texture, and the X, Y coordinates of its piece of the texture.

class Sprite {
    shared_ptr<Texture> tex;
    int x, y;
public:
    Sprite(shared_ptr<Texture> t, int x, int y) tex(t), x(x), y(y) {}

    void draw(HDC dc, int dest_x, int dest_y) { 
        BitBlt(dc, dest_x, dest_y, 32, 32, *tex, x, y, SRCCOPY);
    }
};
Jerry Coffin
  • 437,173
  • 71
  • 570
  • 1,035
  • I still don't get your answer. My drawing function is void TexturedSprite::draw_impl(Canvas & c) { c.DrawTexture(*m_pTexture, m_position); }, which will draw the whole texture. So I will definitely need to get separate sprites(or texture), but i don't really know how to do it in your answer – Le Duy Khanh Oct 02 '15 at 02:32
  • I tried copying from DC to shared_ptr but it's invalid, can you check your answer? – Le Duy Khanh Oct 02 '15 at 03:01
  • @LeDuyKhanh: Oops--you have to dereference the pointer, of course. From there, the `Texture` type needs to provide a conversion to HDC (which it would probably implement by storing a memory DC with the bitmap selected into it, and just return the handle to that DC). – Jerry Coffin Oct 02 '15 at 15:22
0

If you really don't want to use any libraries you Need to manually decode the BMP file. Look at this Wikipedia entry for more Information about the structure of the BMP file Format.

Thomas Sparber
  • 2,404
  • 2
  • 15
  • 31