如何从bmp图像C ++纹理中获取一组精灵

时间:2015-09-30 10:53:26

标签: c++ textures

我有这个图片: enter image description here

我想生成一组精灵,每个精灵大小为32x32。如何使用C ++执行此操作,不使用库。 纹理类:

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 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);

};

我以这种方式创建精灵:

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

如何使用此方法从上面的图像生成9个精灵?

修改 我想出了这些代码,但仍然没有工作

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;

};

有了这个,我想创建一个构造函数来创建其他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));
}

修改 目前,我已经从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);
};

我无法弄清楚如何实现第二个构造函数,复制输入纹理的一部分(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);
}

2 个答案:

答案 0 :(得分:2)

至少在我现在阅读的时候,你的基本意图是加载纹理,然后通过将纹理的32x32像素块复制到各个精灵中来创建单个精灵。除非你打算从单独的线程中操纵精灵(这让我觉得不太可能),否则我会避免这样做。

相反,我注意到你提供给BitBlt的几个最后一个参数:

var pipeline = [
        {
            "$group": {
                "_id": "$beatmapset_id",
                "count": { "$sum": 1 },
                "uniqueIds": { "$addToSet": "$_id" },
                "maxRating": { "$max": "$difficultyrating" }
            }
        },
        { 
            "$match": { 
                "count": { "$gte": 2 } 
            } 
        },
        { 
            "$sort" : { "count" : -1 } 
        }
    ],
    counter = 0,
    bulk = db.collection.initializeOrderedBulkOp();

db.collection.aggregate(pipeline).forEach(function(doc) {
    bulk.find({ 
        "_id": { "$in": doc.uniqueIds },
        "difficultyrating": { "$lt": doc.maxRating }    
    }).remove();

    counter++;
    if ( counter % 500 == 0 ) {
        // Execute per 500 operations and re-init.
        bulk.execute(); 
        bulk = db.mycollection.initializeOrderedBulkOp(); 
    }
});

// Catch any under or over the 500's and clean up queues
if (counter % 500 != 0)
    bulk.execute(); 

BitBlt(hdcMem2, xStart, yStart, w, h,hdcMem1, 0, 0, SRCCOPY); 之前的0, 0指定源位图中的位置,以用作SRCCOPY的起点。

这使您可以加载纹理一次,并将该单个纹理用于​​它包含的所有精灵。在特定位置绘制单个精灵只需要在源位图(特别是该精灵的左上角)中指定该精灵的X,Y坐标,并从那里开始绘制一个32x32块。如果你想定义单独的精灵对象,你当然可以这样做,但每个只需要将BitBlt这样的东西存储到加载的纹理,以及它的纹理片段的X,Y坐标。

shared_ptr

答案 1 :(得分:0)

如果您真的不想使用任何库,则需要手动解码BMP文件。查看this Wikipedia条目,了解有关BMP文件格式结构的更多信息。