1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4 
5     General sprite handling helpers
6 
7 ***************************************************************************/
8 
9 #ifndef MAME_VIDEO_SPRITE_H
10 #define MAME_VIDEO_SPRITE_H
11 
12 #pragma once
13 
14 
15 // ======================> sparse_dirty_rect
16 
17 // class representing a single dirty region
18 class sparse_dirty_rect : public rectangle
19 {
20 	friend class simple_list<sparse_dirty_rect>;
21 
22 public:
sparse_dirty_rect()23 	sparse_dirty_rect(): m_next(nullptr) { }
24 	// getters
next()25 	const sparse_dirty_rect *next() const { return m_next; }
26 
27 private:
28 	// internal state
29 	sparse_dirty_rect * m_next;
30 };
31 
32 
33 // ======================> sparse_dirty_bitmap
34 
35 class sparse_dirty_bitmap
36 {
37 public:
38 	// construction/destruction
39 	sparse_dirty_bitmap(int granularity = 3);
40 	sparse_dirty_bitmap(int width, int height, int granularity = 3);
41 
42 	// dirtying operations - partially intersecting tiles are dirtied
dirty(const rectangle & rect)43 	void dirty(const rectangle &rect) { dirty(rect.left(), rect.right(), rect.top(), rect.bottom()); }
44 	void dirty(int32_t left, int32_t right, int32_t top, int32_t bottom);
dirty_all()45 	void dirty_all() { dirty(0, m_width - 1, 0, m_height - 1); }
46 
47 	// cleaning operations - partially intersecting tiles are NOT cleaned
clean(const rectangle & rect)48 	void clean(const rectangle &rect) { clean(rect.left(), rect.right(), rect.top(), rect.bottom()); }
49 	void clean(int32_t left, int32_t right, int32_t top, int32_t bottom);
clean_all()50 	void clean_all() { clean(0, m_width - 1, 0, m_height - 1); }
51 
52 	// convert to rect list
first_dirty_rect()53 	sparse_dirty_rect *first_dirty_rect() { rectangle fullrect(0, m_width - 1, 0, m_height - 1); return first_dirty_rect(fullrect); }
54 	sparse_dirty_rect *first_dirty_rect(const rectangle &cliprect);
55 
56 	// dynamic resizing
57 	void resize(int width, int height);
58 
59 private:
60 	// invalidate cached rect list
invalidate_rect_list()61 	void invalidate_rect_list() { m_rect_list_bounds.set(0, -1, 0, -1); }
62 
63 	// internal state
64 	int                     m_width;
65 	int                     m_height;
66 	int                     m_granularity;
67 	bitmap_ind8             m_bitmap;
68 	rectangle               m_rect_list_bounds;
69 	fixed_allocator<sparse_dirty_rect>  m_rect_allocator;
70 	simple_list<sparse_dirty_rect> m_rect_list;
71 };
72 
73 
74 // ======================> sprite_device
75 
76 template<typename _SpriteRAMType, class _BitmapType>
77 class sprite_device : public device_t
78 {
79 	// constants
80 	static const int BITMAP_SLOP = 16;
81 
82 protected:
83 	// construction/destruction - only for subclasses
84 	sprite_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, int dirty_granularity = 3)
85 		: device_t(mconfig, type, tag, owner, 0)
86 		, m_xorigin(0)
87 		, m_yorigin(0)
88 		, m_spriteram(nullptr)
89 		, m_spriteram_bytes(0)
90 		, m_dirty(dirty_granularity)
91 	{
92 		force_clear();
93 	}
94 
95 public:
96 	// getters
xorigin()97 	int32_t xorigin() const { return m_xorigin; }
yorigin()98 	int32_t yorigin() const { return m_yorigin; }
bitmap()99 	_BitmapType &bitmap() { return m_bitmap; }
first_dirty_rect()100 	sparse_dirty_rect *first_dirty_rect() { return m_dirty.first_dirty_rect(); }
first_dirty_rect(const rectangle & cliprect)101 	sparse_dirty_rect *first_dirty_rect(const rectangle &cliprect) { return m_dirty.first_dirty_rect(cliprect); }
spriteram()102 	_SpriteRAMType *spriteram() const { return m_spriteram; }
spriteram_bytes()103 	uint32_t spriteram_bytes() const { return m_spriteram_bytes; }
spriteram_elements()104 	uint32_t spriteram_elements() const { return m_spriteram_bytes / sizeof(_SpriteRAMType); }
buffer()105 	_SpriteRAMType *buffer() { return &m_buffer[0]; }
106 
107 	// configuration
set_spriteram(_SpriteRAMType * base,uint32_t bytes)108 	void set_spriteram(_SpriteRAMType *base, uint32_t bytes) { assert(base != nullptr && bytes != 0); m_spriteram = base; m_spriteram_bytes = bytes; m_buffer.resize(m_spriteram_bytes / sizeof(_SpriteRAMType)); }
109 	void set_origin(int32_t xorigin = 0, int32_t yorigin = 0) { m_xorigin = xorigin; m_yorigin = yorigin; }
set_xorigin(int32_t xorigin)110 	void set_xorigin(int32_t xorigin) { m_xorigin = xorigin; }
set_yorigin(int32_t yorigin)111 	void set_yorigin(int32_t yorigin) { m_yorigin = yorigin; }
112 
113 	// buffering
copy_to_buffer()114 	void copy_to_buffer() { assert(m_spriteram != nullptr); memcpy(m_buffer, m_spriteram, m_spriteram_bytes); }
115 
116 	// clearing
clear()117 	void clear() { clear(m_bitmap.cliprect()); }
clear(const rectangle & cliprect)118 	void clear(const rectangle &cliprect)
119 	{
120 		for (const sparse_dirty_rect *rect = m_dirty.first_dirty_rect(cliprect); rect != nullptr; rect = rect->next())
121 			m_bitmap.fill(~0, *rect);
122 		m_dirty.clean(cliprect);
123 	}
124 
125 	// force clear (don't use dirty rects)
force_clear()126 	void force_clear()
127 	{
128 		m_bitmap.fill(~0);
129 		m_dirty.clean_all();
130 	}
131 
132 	// drawing
133 	void draw_async(const rectangle &cliprect, bool clearit = true)
134 	{
135 		// if the cliprect exceeds our current bitmap dimensions, expand
136 		if (cliprect.right() >= m_bitmap.width() || cliprect.bottom() >= m_bitmap.height())
137 		{
138 			int new_width = std::max(cliprect.right() + 1, m_bitmap.width());
139 			int new_height = std::max(cliprect.bottom() + 1, m_bitmap.height());
140 			m_bitmap.resize(new_width, new_height, BITMAP_SLOP, BITMAP_SLOP);
141 			m_dirty.resize(new_width, new_height);
142 		}
143 
144 		// clear out the region
145 		if (clearit)
146 			clear(cliprect);
147 
148 		// wrap the bitmap, adjusting for x/y origins
149 		_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());
150 
151 		// compute adjusted cliprect in source space
152 		rectangle adjusted = cliprect;
153 		adjusted.offset(m_xorigin, m_yorigin);
154 
155 		// render
156 		draw(wrapped, adjusted);
157 	}
158 
159 protected:
160 	// device-level overrides
device_start()161 	virtual void device_start() override
162 	{
163 		// find spriteram
164 		memory_share *spriteram = owner()->memshare(tag());
165 		if (spriteram != nullptr)
166 		{
167 			set_spriteram(reinterpret_cast<_SpriteRAMType *>(spriteram->ptr()), spriteram->bytes());
168 
169 			// save states
170 			save_item(NAME(m_buffer));
171 		}
172 	}
173 
174 	// subclass overrides
175 	virtual void draw(_BitmapType &bitmap, const rectangle &cliprect) = 0;
176 
177 	// subclass helpers
mark_dirty(const rectangle & rect)178 	void mark_dirty(const rectangle &rect) { mark_dirty(rect.left(), rect.right(), rect.top(), rect.bottom()); }
mark_dirty(int32_t left,int32_t right,int32_t top,int32_t bottom)179 	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); }
180 
181 private:
182 	// configuration
183 	int32_t                           m_xorigin;              // X origin for drawing
184 	int32_t                           m_yorigin;              // Y origin for drawing
185 
186 	// memory pointers and buffers
187 	_SpriteRAMType *                m_spriteram;            // pointer to spriteram pointer
188 	int32_t                           m_spriteram_bytes;      // size of sprite RAM in bytes
189 	std::vector<_SpriteRAMType>          m_buffer;               // buffered spriteram for those that use it
190 
191 	// bitmaps
192 	_BitmapType                     m_bitmap;               // live bitmap
193 	sparse_dirty_bitmap             m_dirty;                // dirty bitmap
194 };
195 
196 typedef sprite_device<uint8_t, bitmap_ind16> sprite8_device_ind16;
197 typedef sprite_device<uint16_t, bitmap_ind16> sprite16_device_ind16;
198 typedef sprite_device<uint32_t, bitmap_ind16> sprite32_device_ind16;
199 
200 typedef sprite_device<uint8_t, bitmap_ind32> sprite8_device_ind32;
201 typedef sprite_device<uint16_t, bitmap_ind32> sprite16_device_ind32;
202 typedef sprite_device<uint32_t, bitmap_ind32> sprite32_device_ind32;
203 
204 
205 #endif // MAME_VIDEO_SPRITE_H
206