summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/video/sprite.h
blob: 93cd38190a650867c098b3263268ba84a3cd5a9e (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                                



                                                                            

                                                                            

                           
 
            





                                            
 


                                                    
                                                

                                                                
 

                         
                                   











                                                                        
                                                                         
                                                                                                          
                                                                             
                                                                    
 

                                                                                                          
                                                                             





                                                                                                                                         
                           
                                           
 




                                                                             





                                                             













                                                         






                                                                                                                                   





                              

                                                     



                                                                                                                     

                                                                                                  
                                                         
 
                        



                                                                                                                                                                                
 

                                                                                   
 



                                                    
                                                                                                                              


                                                 
 












                                                                                                   

                                                                                            


                                                                                         
 


                                        
 





                                                                                                                                                                                                
 





                                        
                                            


                                                                   
                                         
                 
                                                                                                                
 


                                                  
         
 




                                                                                                                    
                                                                                                                                                                              
 

                        

                                                                                         

                                      
                                                                                               
                                                                                                
                                                                                                                
 
                  

                                                                               

  


                                                                    
 


                                                                    

 
                             
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    General sprite handling helpers

***************************************************************************/

#ifndef MAME_VIDEO_SPRITE_H
#define MAME_VIDEO_SPRITE_H

#pragma once


// ======================> sparse_dirty_rect

// class representing a single dirty region
class sparse_dirty_rect : public rectangle
{
	friend class simple_list<sparse_dirty_rect>;

public:
	sparse_dirty_rect(): m_next(nullptr) { }
	// getters
	const sparse_dirty_rect *next() const { return m_next; }

private:
	// internal state
	sparse_dirty_rect * m_next;
};


// ======================> sparse_dirty_bitmap

class sparse_dirty_bitmap
{
public:
	// construction/destruction
	sparse_dirty_bitmap(int granularity = 3);
	sparse_dirty_bitmap(int width, int height, int granularity = 3);

	// dirtying operations - partially intersecting tiles are dirtied
	void dirty(const rectangle &rect) { dirty(rect.left(), rect.right(), rect.top(), rect.bottom()); }
	void dirty(int32_t left, int32_t right, int32_t top, int32_t bottom);
	void dirty_all() { dirty(0, m_width - 1, 0, m_height - 1); }

	// cleaning operations - partially intersecting tiles are NOT cleaned
	void clean(const rectangle &rect) { clean(rect.left(), rect.right(), rect.top(), rect.bottom()); }
	void clean(int32_t left, int32_t right, int32_t top, int32_t bottom);
	void clean_all() { clean(0, m_width - 1, 0, m_height - 1); }

	// convert to rect list
	sparse_dirty_rect *first_dirty_rect() { rectangle fullrect(0, m_width - 1, 0, m_height - 1); return first_dirty_rect(fullrect); }
	sparse_dirty_rect *first_dirty_rect(const rectangle &cliprect);

	// dynamic resizing
	void resize(int width, int height);

private:
	// invalidate cached rect list
	void invalidate_rect_list() { m_rect_list_bounds.set(0, -1, 0, -1); }

	// internal state
	int                     m_width;
	int                     m_height;
	int                     m_granularity;
	bitmap_ind8             m_bitmap;
	rectangle               m_rect_list_bounds;
	fixed_allocator<sparse_dirty_rect>  m_rect_allocator;
	simple_list<sparse_dirty_rect> m_rect_list;
};


// ======================> sprite_device

template<typename _SpriteRAMType, class _BitmapType>
class sprite_device : public device_t
{
	// constants
	static const int BITMAP_SLOP = 16;

protected:
	// construction/destruction - only for subclasses
	sprite_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, int dirty_granularity = 3)
		: device_t(mconfig, type, tag, owner, 0)
		, m_xorigin(0)
		, m_yorigin(0)
		, m_spriteram(nullptr)
		, m_spriteram_bytes(0)
		, m_dirty(dirty_granularity)
	{
		force_clear();
	}

public:
	// getters
	int32_t xorigin() const { return m_xorigin; }
	int32_t yorigin() const { return m_yorigin; }
	_BitmapType &bitmap() { return m_bitmap; }
	sparse_dirty_rect *first_dirty_rect() { return m_dirty.first_dirty_rect(); }
	sparse_dirty_rect *first_dirty_rect(const rectangle &cliprect) { return m_dirty.first_dirty_rect(cliprect); }
	_SpriteRAMType *spriteram() const { return m_spriteram; }
	uint32_t spriteram_bytes() const { return m_spriteram_bytes; }
	uint32_t spriteram_elements() const { return m_spriteram_bytes / sizeof(_SpriteRAMType); }
	_SpriteRAMType *buffer() { return &m_buffer[0]; }

	// configuration
	void set_spriteram(_SpriteRAMType *base, uint32_t bytes) { m_spriteram = base; m_spriteram_bytes = bytes; m_buffer.resize(m_spriteram_bytes / sizeof(_SpriteRAMType)); }
	void set_origin(int32_t xorigin = 0, int32_t yorigin = 0) { m_xorigin = xorigin; m_yorigin = yorigin; }
	void set_xorigin(int32_t xorigin) { m_xorigin = xorigin; }
	void set_yorigin(int32_t yorigin) { m_yorigin = yorigin; }

	// buffering
	void copy_to_buffer() { memcpy(m_buffer, m_spriteram, m_spriteram_bytes); }

	// clearing
	void clear() { clear(m_bitmap.cliprect()); }
	void clear(const rectangle &cliprect)
	{
		for (const sparse_dirty_rect *rect = m_dirty.first_dirty_rect(cliprect); rect != nullptr; rect = rect->next())
			m_bitmap.fill(~0, *rect);
		m_dirty.clean(cliprect);
	}

	// force clear (don't use dirty rects)
	void force_clear()
	{
		m_bitmap.fill(~0);
		m_dirty.clean_all();
	}

	// drawing
	void draw_async(const rectangle &cliprect, bool clearit = true)
	{
		// if the cliprect exceeds our current bitmap dimensions, expand
		if (cliprect.right() >= m_bitmap.width() || cliprect.bottom() >= m_bitmap.height())
		{
			int new_width = std::max(cliprect.right() + 1, m_bitmap.width());
			int new_height = std::max(cliprect.bottom() + 1, m_bitmap.height());
			m_bitmap.resize(new_width, new_height, BITMAP_SLOP, BITMAP_SLOP);
			m_dirty.resize(new_width, new_height);
		}

		// clear out the region
		if (clearit)
			clear(cliprect);

		// wrap the bitmap, adjusting for x/y origins
		_BitmapType wrapped(&m_bitmap.pix(0) - m_xorigin - m_yorigin * m_bitmap.rowpixels(), m_xorigin + cliprect.right() + 1, m_yorigin + cliprect.bottom() + 1, m_bitmap.rowpixels());

		// compute adjusted cliprect in source space
		rectangle adjusted = cliprect;
		adjusted.offset(m_xorigin, m_yorigin);

		// render
		draw(wrapped, adjusted);
	}

protected:
	// device-level overrides
	virtual void device_start() override
	{
		// find spriteram
		memory_share *spriteram = owner()->memshare(tag());
		if (spriteram != nullptr)
		{
			set_spriteram(reinterpret_cast<_SpriteRAMType *>(spriteram->ptr()), spriteram->bytes());

			// save states
			save_item(NAME(m_buffer));
		}
	}

	// subclass overrides
	virtual void draw(_BitmapType &bitmap, const rectangle &cliprect) = 0;

	// subclass helpers
	void mark_dirty(const rectangle &rect) { mark_dirty(rect.left(), rect.right(), rect.top(), rect.bottom()); }
	void mark_dirty(int32_t left, int32_t right, int32_t top, int32_t bottom) { m_dirty.dirty(left - m_xorigin, right - m_xorigin, top - m_yorigin, bottom - m_yorigin); }

private:
	// configuration
	int32_t                           m_xorigin;              // X origin for drawing
	int32_t                           m_yorigin;              // Y origin for drawing

	// memory pointers and buffers
	_SpriteRAMType *                m_spriteram;            // pointer to spriteram pointer
	int32_t                           m_spriteram_bytes;      // size of sprite RAM in bytes
	std::vector<_SpriteRAMType>          m_buffer;               // buffered spriteram for those that use it

	// bitmaps
	_BitmapType                     m_bitmap;               // live bitmap
	sparse_dirty_bitmap             m_dirty;                // dirty bitmap
};

typedef sprite_device<uint8_t, bitmap_ind16> sprite8_device_ind16;
typedef sprite_device<uint16_t, bitmap_ind16> sprite16_device_ind16;
typedef sprite_device<uint32_t, bitmap_ind16> sprite32_device_ind16;

typedef sprite_device<uint8_t, bitmap_ind32> sprite8_device_ind32;
typedef sprite_device<uint16_t, bitmap_ind32> sprite16_device_ind32;
typedef sprite_device<uint32_t, bitmap_ind32> sprite32_device_ind32;


#endif // MAME_VIDEO_SPRITE_H