描画のキャッシュ(4)

昨日のをさらに改善してみました(`・ω・´)

class CacheObject{
public:
    virtual ~CacheObject(){}
    virtual void Draw() = 0;
    virtual int GetPriority() const = 0;
    
    virtual uint32 GetSize() const = 0;
    virtual void CopyConstructor( CacheObject& obj ) const = 0;
};

class DrawCache{
public:
    static DrawCache* Create( uint32 cacheSize , uint32 cacheNum ){
        DrawCache* cache = new DrawCache( cacheSize , cacheNum );
        if( cache == null ) return null;
        
        if( cache->_cache == null || cache->_pCache == null ){
            Release( cache );
        }
        
        return cache;
    }
    
    static void Release( DrawCache*& cache ){
        if( cache != null ){
            delete cache;
            cache = null;
        }
    }
    
private:
    DrawCache( uint32 cacheSize , uint32 cacheNum ) :
        _maxSize( cacheSize ) , _maxNum( cacheNum ) ,
        _cache( new byte[ cacheSize ] ) , _pObj( new CacheObject*[ cacheNum ] ) ,
        _size( 0 ) , _count( 0 ){
    }
    
    ~DrawCache(){
        if( _cache != null ){
            delete _cache;
        }
        if( _pCache != null ){
            delete _pCache;
        }
    }
    
public:
    void Draw( const CacheObject& obj ){
        uint32 size = obj.GetSize();
        if( _size + size <= _maxSize && _count < _maxNum ){
            obj.CopyConstructor( *(CacheObject*)&_cache[ _size ] );
            pObj[ _count ] = (CacheObject*)&_cache[ _size ];
            
            _size += size;
            _count++;
        }
    }
    
    // プライオリティに基づいてソート
    void sort();
    
    void Flush(){
        sort();
        for( int i = 0 ; i < _count ; i++ ){
            _pObj[ i ]->Draw();
        }
        _size = 0;
        _count = 0;
    }
    
private:
    byte*           _cache;
    uint32          _size;
    uint32          _maxSize;
    CacheObject**   _pObj;
    uint32          _count;
    uint32          _maxNum;
};
template< class T >
class CacheObjectHelper : public CacheObject{
public:
    virtual int GetSize() const{
        return sizeof( T );
    }
    
    virtual void CopyConstructor( CacheObject& obj ) const{
        new( (T*)&obj ) T( *(const T*)this );
    }
};
class DrawImageCacheObject : public CacheObjectHelper< DrawImageCacheObject >{
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() const{
        return _priority;
    }
private:
    Image       _dst;
    int         _dx;
    int         _dy;
    Image       _src;
    int         _priority;
};


class FillRectCacheObject : public CacheObjectHelper< FillRectCacheObject >{
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() const{
        return _priority;
    }
private:
    Image       _dst;
    int         _dx;
    int         _dy;
    int         _dw;
    int         _dh;
    uint32      _color;
    int         _priority;
};

昨日とあまり変わってないのだけれど、CacheObject インターフェースクラスに CopyConstructor() というインターフェースが追加された。
これは、キャッシュするときに memcpy() でコピーしているとコピーコンストラクタが呼ばれずに挙動がおかしくなる問題を解決するために追加してみた。
テンプレートを使用して、CopyConstructor() の引数である obj を this で初期化する。
こうすることによって(ただの byte 配列に対して)無事コピーコンストラクタが呼ばれて初期化される。


で、CacheObjectHelper は、その名の通りヘルパクラスで、本当は実装に当たってこのクラスは必要ない。
ただ、この実装を全てのオブジェクトに対して行うのは面倒なので、このヘルパクラスにその面倒な、型さえ分かれば実装出来るインターフェースを実装してやる。
で、CacheObject 実装クラスは CacheObjectHelper テンプレートを継承して、残りの Draw() と GetPriority() を実装すれば完成。
CacheObjectHelper を実体化するのが面倒だけれども、昨日の、GetSize() を使用して sizeof( T ) を返してやるよりはマシだろう。


とりあえずこれでしばらくやってみます(`・ω・´)