描画キャッシュ(2)

OO的にキャッシュするのであれば、こんな感じだろうか。

class CacheObject{
public:
    virtual ~CacheObject(){}
    virtual void Draw() = 0;
    virtual int GetPriority() = 0;
};

class DrawCache{
public:
    DrawCache() : _count( 0 ){}
    
    void Draw( CacheObject* obj ){
        if( obj == null ) return;
        if( _count < OBJ_MAX ){
            _cache[ _count ] = obj;
            _count++;
        }
    }
    
    // プライオリティに基づいてソート
    void sort();
    
    void Flush(){
        sort();
        for( int i = 0 ; i < _count ; i++ ){
            _cache[ i ]->Draw();
        }
        _count = 0;
    }
private:
    enum{
        OBJ_MAX = 100 ,
    };
    CacheObject*    _cache[ OBJ_MAX ];
    
    int             _count;
};
class DrawImageCacheObject : public CacheObject{
public:
    DrawImageCacheObject( Image dst , int dx , int dy , Image src , int priority ){
        _dst        = dst;
        _dx         = dx;
        _dy         = dy;
        _src        = src;
        _priority   = priority;
    }
    
    virtual void Draw(){
        Graphics::DrawImage( _dst , _dx , _dy , _src );
    }
    
    virtual int GetPriority(){
        return _priority;
    }
private:
    Image       _dst;
    int         _dx;
    int         _dy;
    Image       _src;
    int         _priority;
};

class FillRectCacheObject : public CacheObject{
public:
    FillRectCacheObject( Image dst , int dx , int dy , int dw , int dh ,
                            uint32 color , int priority ){
        _dst        = dst;
        _dx         = dx;
        _dy         = dy;
        _dw         = dw;
        _dh         = dh;
        _color      = color;
        _priority   = priority;
    }
    
    virtual void Draw(){
        Graphics::FillRect( _dst , _dx , _dy , _dw , _dh , _color );
    }
    
    virtual int GetPriority(){
        return _priority;
    }
private:
    Image       _dst;
    int         _dx;
    int         _dy;
    int         _dw;
    int         _dh;
    uint32      _color;
    int         _priority;
};

CacheObject インターフェースクラスを作り、その下に実際の描画処理を入れることによって、ユーザ側でキャッシュオブジェクトを拡張することが出来るようになる。
また、DrawCache クラスはオブジェクトへのポインタしか持たないので、メモリも最低限しか取らない。


ただ、描画をキャッシュするときにポインタを渡しているので、ユーザ側でキャッシュオブジェクトが存在していることを保証しなければならない。
これをスマートポインタにして、

DrawCache cache;
cache.Draw(
    smart_ptr< CacheObject >(
        new DrawImageCacheObject( dst , dx , dy , src , priority )
    )
);

こうやってキャッシュする方法も考えられるけど、これだとキャッシュするたびに new しているので、(BREW は)new で null を返す可能性があるし、動的なメモリの確保は速度的にも気になる。


結局メンバとかにキャッシュオブジェクトを置いて、そのポインタ(またはスマートポインタ)を渡すことになるんだろうけど、その場合は DrawCache を wrap したクラスでキャッシュオブジェクトを生成して、そのキャッシュオブジェクトを使用して DrawCache に委譲するクラスを作ると思う。

class DrawCacheImpl{
public:
    DrawCacheImpl()
        : _drawImageCount( 0 ) , _fillRectCount( 0 ) , _myDrawCount( 0 ){}
    
    void DrawImage( Image dst , int dx , int dy , Image src , int priority ){
        if( _drawImageCount < MAX_DRAWIMAGE ){
            _drawImageCache[ _drawImageCount ].Set(
                dst , dx , dy , src , priority );
            _drawCache.Draw( &_drawImageCache[ _drawImageCount ] );
            _drawImageCount++;
        }
    }
    
    void FillRect( Image dst , int dx , int dy , int dw , int dy ,
                    uint32 color , int priority ){
        if( _fillRectCount < MAX_FILLRECT ){
            _fillRectCache[ _fillRectCount ].Set(
                dst , dx , dy , dw , dy , color , priority );
            _drawCache.Draw( &_fillRectCache[ _fillRectCount ] );
            _fillRectCount++;
        }
    }
    
    // このプロジェクトでしか使用しない描画オブジェクト
    void MyDraw( Image dst , int dx , int dy ){
        if( _myDrawCount < MAX_MYDRAW ){
            _myDrawCache[ _myDrawCount ].Set( dst , dx , dy );
            _drawCache.Draw( &_myDrawCache[ _myDrawCount ] );
            _myDrawCount++;
        }
    }
    
    void Flush(){
        _drawCache.Flush();
        _drawImageCount = 0;
        _fillRectCount = 0;
        _myDrawCount = 0;
    }
    
private:
    enum{
        MAX_DRAWIMAGE = 100 ,
        MAX_FILLRECT = 50 ,
        MAX_MYDRAW = 10 ,
    };
    
    DrawImageCacheObject    _drawImageCache[ MAX_DRAWIMAGE ];
    int                     _drawImageCount;
    
    FillRectCacheObject     _fillRectCache[ MAX_FILLRECT ];
    int                     _fillRectCount;
    
    MyDrawCacheObject       _myDrawCache[ MAX_MYDRAW ];
    int                     _myDrawCount;
    
    DrawCache               _drawCache;
};

こんな感じだろうか。
ただ、そんな面倒なことを毎回やりたくないので、出来ればライブラリ側にキャッシュオブジェクトを置いてやりたい。


で、ここでどうしたらいいかわからなくなる。
……どうするかなぁ(;´Д`)