描画のキャッシュ(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 ) を返してやるよりはマシだろう。
とりあえずこれでしばらくやってみます(`・ω・´)