1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4 
5     bitmap.c
6 
7     Core bitmap routines.
8 
9 ***************************************************************************/
10 
11 #include "bitmap.h"
12 
13 #include <cassert>
14 #include <new>
15 
16 
17 //**************************************************************************
18 //  INLINE HELPERS
19 //**************************************************************************
20 
21 //-------------------------------------------------
22 //  compute_rowpixels - compute a rowpixels value
23 //-------------------------------------------------
24 
compute_rowpixels(int width,int xslop)25 inline int32_t bitmap_t::compute_rowpixels(int width, int xslop)
26 {
27 	return width + 2 * xslop;
28 }
29 
30 
31 //-------------------------------------------------
32 //  compute_base - compute a bitmap base address
33 //  with the given slop values
34 //-------------------------------------------------
35 
compute_base(int xslop,int yslop)36 inline void bitmap_t::compute_base(int xslop, int yslop)
37 {
38 	m_base = m_alloc.get() + (m_rowpixels * yslop + xslop) * (m_bpp / 8);
39 }
40 
41 
42 //-------------------------------------------------
43 //  valid_format - return true if the bitmap format
44 //  is valid and agrees with the BPP
45 //-------------------------------------------------
46 
valid_format() const47 inline bool bitmap_t::valid_format() const
48 {
49 	switch (m_format)
50 	{
51 	// invalid format
52 	case BITMAP_FORMAT_INVALID:
53 		return false;
54 
55 	// 8bpp formats
56 	case BITMAP_FORMAT_IND8:
57 		return m_bpp == 8;
58 
59 	// 16bpp formats
60 	case BITMAP_FORMAT_IND16:
61 	case BITMAP_FORMAT_YUY16:
62 		return m_bpp == 16;
63 
64 	// 32bpp formats
65 	case BITMAP_FORMAT_IND32:
66 	case BITMAP_FORMAT_RGB32:
67 	case BITMAP_FORMAT_ARGB32:
68 		return m_bpp == 32;
69 
70 	// 64bpp formats
71 	case BITMAP_FORMAT_IND64:
72 		return m_bpp == 64;
73 	}
74 
75 	return false;
76 }
77 
78 
79 //**************************************************************************
80 //  BITMAP ALLOCATION/CONFIGURATION
81 //**************************************************************************
82 
bitmap_t(bitmap_t && that)83 bitmap_t::bitmap_t(bitmap_t &&that)
84 	: m_alloc(std::move(that.m_alloc))
85 	, m_allocbytes(that.m_allocbytes)
86 	, m_base(that.m_base)
87 	, m_rowpixels(that.m_rowpixels)
88 	, m_width(that.m_width)
89 	, m_height(that.m_height)
90 	, m_format(that.m_format)
91 	, m_bpp(that.m_bpp)
92 	, m_palette(nullptr)
93 	, m_cliprect(that.m_cliprect)
94 {
95 	set_palette(that.m_palette);
96 	that.reset();
97 }
98 
99 /**
100  * @fn  bitmap_t::bitmap_t(bitmap_format format, uint8_t bpp, int width, int height, int xslop, int yslop)
101  *
102  * @brief   -------------------------------------------------
103  *            bitmap_t - basic constructor
104  *          -------------------------------------------------.
105  *
106  * @param   format  Describes the format to use.
107  * @param   bpp     The bits per pixel.
108  * @param   width   The width.
109  * @param   height  The height.
110  * @param   xslop   The xslop.
111  * @param   yslop   The yslop.
112  */
113 
bitmap_t(bitmap_format format,uint8_t bpp,int width,int height,int xslop,int yslop)114 bitmap_t::bitmap_t(bitmap_format format, uint8_t bpp, int width, int height, int xslop, int yslop)
115 	: m_alloc()
116 	, m_allocbytes(0)
117 	, m_format(format)
118 	, m_bpp(bpp)
119 	, m_palette(nullptr)
120 {
121 	assert(valid_format());
122 
123 	// allocate intializes all other fields
124 	allocate(width, height, xslop, yslop);
125 }
126 
127 /**
128  * @fn  bitmap_t::bitmap_t(bitmap_format format, uint8_t bpp, void *base, int width, int height, int rowpixels)
129  *
130  * @brief   Constructor.
131  *
132  * @param   format          Describes the format to use.
133  * @param   bpp             The bits per pixel.
134  * @param [in,out]  base    If non-null, the base.
135  * @param   width           The width.
136  * @param   height          The height.
137  * @param   rowpixels       The rowpixels.
138  */
139 
bitmap_t(bitmap_format format,uint8_t bpp,void * base,int width,int height,int rowpixels)140 bitmap_t::bitmap_t(bitmap_format format, uint8_t bpp, void *base, int width, int height, int rowpixels)
141 	: m_alloc()
142 	, m_allocbytes(0)
143 	, m_base(base)
144 	, m_rowpixels(rowpixels)
145 	, m_width(width)
146 	, m_height(height)
147 	, m_format(format)
148 	, m_bpp(bpp)
149 	, m_palette(nullptr)
150 	, m_cliprect(0, width - 1, 0, height - 1)
151 {
152 	assert(valid_format());
153 }
154 
155 /**
156  * @fn  bitmap_t::bitmap_t(bitmap_format format, uint8_t bpp, bitmap_t &source, const rectangle &subrect)
157  *
158  * @brief   Constructor.
159  *
160  * @param   format          Describes the format to use.
161  * @param   bpp             The bits per pixel.
162  * @param [in,out]  source  Source for the.
163  * @param   subrect         The subrect.
164  */
165 
bitmap_t(bitmap_format format,uint8_t bpp,bitmap_t & source,const rectangle & subrect)166 bitmap_t::bitmap_t(bitmap_format format, uint8_t bpp, bitmap_t &source, const rectangle &subrect)
167 	: m_alloc()
168 	, m_allocbytes(0)
169 	, m_base(source.raw_pixptr(subrect.top(), subrect.left()))
170 	, m_rowpixels(source.m_rowpixels)
171 	, m_width(subrect.width())
172 	, m_height(subrect.height())
173 	, m_format(format)
174 	, m_bpp(bpp)
175 	, m_palette(nullptr)
176 	, m_cliprect(0, subrect.width() - 1, 0, subrect.height() - 1)
177 {
178 	assert(format == source.m_format);
179 	assert(bpp == source.m_bpp);
180 	assert(source.cliprect().contains(subrect));
181 }
182 
183 /**
184  * @fn  bitmap_t::~bitmap_t()
185  *
186  * @brief   -------------------------------------------------
187  *            ~bitmap_t - basic destructor
188  *          -------------------------------------------------.
189  */
190 
~bitmap_t()191 bitmap_t::~bitmap_t()
192 {
193 	// delete any existing stuff
194 	reset();
195 }
196 
operator =(bitmap_t && that)197 bitmap_t &bitmap_t::operator=(bitmap_t &&that)
198 {
199 	m_alloc = std::move(that.m_alloc);
200 	m_allocbytes = that.m_allocbytes;
201 	m_base = that.m_base;
202 	m_rowpixels = that.m_rowpixels;
203 	m_width = that.m_width;
204 	m_height = that.m_height;
205 	m_format = that.m_format;
206 	m_bpp = that.m_bpp;
207 	set_palette(that.m_palette);
208 	m_cliprect = that.m_cliprect;
209 	that.reset();
210 	return *this;
211 }
212 
213 /**
214  * @fn  void bitmap_t::allocate(int width, int height, int xslop, int yslop)
215  *
216  * @brief   -------------------------------------------------
217  *            allocate -- (re)allocate memory for the bitmap at the given size, destroying
218  *            anything that already exists
219  *          -------------------------------------------------.
220  *
221  * @param   width   The width.
222  * @param   height  The height.
223  * @param   xslop   The xslop.
224  * @param   yslop   The yslop.
225  */
226 
allocate(int width,int height,int xslop,int yslop)227 void bitmap_t::allocate(int width, int height, int xslop, int yslop)
228 {
229 	assert(m_format != BITMAP_FORMAT_INVALID);
230 	assert(m_bpp == 8 || m_bpp == 16 || m_bpp == 32 || m_bpp == 64);
231 
232 	// delete any existing stuff
233 	reset();
234 
235 	// handle empty requests cleanly
236 	if (width <= 0 || height <= 0)
237 		return;
238 
239 	// initialize fields
240 	m_rowpixels = compute_rowpixels(width, xslop);
241 	m_width = width;
242 	m_height = height;
243 	m_cliprect.set(0, width - 1, 0, height - 1);
244 
245 	// allocate memory for the bitmap itself
246 	m_allocbytes = m_rowpixels * (m_height + 2 * yslop) * m_bpp / 8;
247 	m_alloc.reset(new uint8_t[m_allocbytes]);
248 
249 	// clear to 0 by default
250 	memset(m_alloc.get(), 0, m_allocbytes);
251 
252 	// compute the base
253 	compute_base(xslop, yslop);
254 }
255 
256 /**
257  * @fn  void bitmap_t::resize(int width, int height, int xslop, int yslop)
258  *
259  * @brief   -------------------------------------------------
260  *            resize -- resize a bitmap, reusing existing memory if the new size is smaller than
261  *            the current size
262  *          -------------------------------------------------.
263  *
264  * @param   width   The width.
265  * @param   height  The height.
266  * @param   xslop   The xslop.
267  * @param   yslop   The yslop.
268  */
269 
resize(int width,int height,int xslop,int yslop)270 void bitmap_t::resize(int width, int height, int xslop, int yslop)
271 {
272 	assert(m_format != BITMAP_FORMAT_INVALID);
273 	assert(m_bpp == 8 || m_bpp == 16 || m_bpp == 32 || m_bpp == 64);
274 
275 	// handle empty requests cleanly
276 	if (width <= 0 || height <= 0)
277 		width = height = 0;
278 
279 	// determine how much memory we need for the new bitmap
280 	int new_rowpixels = compute_rowpixels(width, xslop);
281 	uint32_t new_allocbytes = new_rowpixels * (height + 2 * yslop) * m_bpp / 8;
282 
283 	// if we need more memory, just realloc
284 	if (new_allocbytes > m_allocbytes)
285 	{
286 		palette_t *palette = m_palette;
287 		allocate(width, height, xslop, yslop);
288 		set_palette(palette);
289 		return;
290 	}
291 
292 	// otherwise, reconfigure
293 	m_rowpixels = new_rowpixels;
294 	m_width = width;
295 	m_height = height;
296 	m_cliprect.set(0, width - 1, 0, height - 1);
297 
298 	// re-compute the base
299 	compute_base(xslop, yslop);
300 }
301 
302 /**
303  * @fn  void bitmap_t::reset()
304  *
305  * @brief   -------------------------------------------------
306  *            reset -- reset to an invalid bitmap, deleting all allocated stuff
307  *          -------------------------------------------------.
308  */
309 
reset()310 void bitmap_t::reset()
311 {
312 	// delete any existing stuff
313 	set_palette(nullptr);
314 	m_alloc.reset();
315 	m_base = nullptr;
316 
317 	// reset all fields
318 	m_rowpixels = 0;
319 	m_width = 0;
320 	m_height = 0;
321 	m_cliprect.set(0, -1, 0, -1);
322 }
323 
324 /**
325  * @fn  void bitmap_t::wrap(void *base, int width, int height, int rowpixels)
326  *
327  * @brief   -------------------------------------------------
328  *            wrap -- wrap an array of memory; the target bitmap does not own the memory
329  *          -------------------------------------------------.
330  *
331  * @param [in,out]  base    If non-null, the base.
332  * @param   width           The width.
333  * @param   height          The height.
334  * @param   rowpixels       The rowpixels.
335  */
336 
wrap(void * base,int width,int height,int rowpixels)337 void bitmap_t::wrap(void *base, int width, int height, int rowpixels)
338 {
339 	// delete any existing stuff
340 	reset();
341 
342 	// initialize relevant fields
343 	m_base = base;
344 	m_rowpixels = rowpixels;
345 	m_width = width;
346 	m_height = height;
347 	m_cliprect.set(0, m_width - 1, 0, m_height - 1);
348 }
349 
350 /**
351  * @fn  void bitmap_t::wrap(const bitmap_t &source, const rectangle &subrect)
352  *
353  * @brief   -------------------------------------------------
354  *            wrap -- wrap a subrectangle of an existing bitmap by copying its fields; the target
355  *            bitmap does not own the memory
356  *          -------------------------------------------------.
357  *
358  * @param   source  Source for the.
359  * @param   subrect The subrect.
360  */
361 
wrap(bitmap_t & source,const rectangle & subrect)362 void bitmap_t::wrap(bitmap_t &source, const rectangle &subrect)
363 {
364 	assert(m_format == source.m_format);
365 	assert(m_bpp == source.m_bpp);
366 	assert(source.cliprect().contains(subrect));
367 
368 	// delete any existing stuff
369 	reset();
370 
371 	// copy relevant fields
372 	m_base = source.raw_pixptr(subrect.top(), subrect.left());
373 	m_rowpixels = source.m_rowpixels;
374 	m_width = subrect.width();
375 	m_height = subrect.height();
376 	set_palette(source.m_palette);
377 	m_cliprect.set(0, m_width - 1, 0, m_height - 1);
378 }
379 
380 /**
381  * @fn  void bitmap_t::set_palette(palette_t *palette)
382  *
383  * @brief   -------------------------------------------------
384  *            set_palette -- associate a palette with a bitmap
385  *          -------------------------------------------------.
386  *
387  * @param [in,out]  palette If non-null, the palette.
388  */
389 
set_palette(palette_t * palette)390 void bitmap_t::set_palette(palette_t *palette)
391 {
392 	// first dereference any existing palette
393 	if (m_palette != nullptr)
394 	{
395 		m_palette->deref();
396 		m_palette = nullptr;
397 	}
398 
399 	// then reference any new palette
400 	if (palette != nullptr)
401 	{
402 		palette->ref();
403 		m_palette = palette;
404 	}
405 }
406 
407 /**
408  * @fn  void bitmap_t::fill(uint64_t color, const rectangle &bounds)
409  *
410  * @brief   -------------------------------------------------
411  *            fill -- fill a bitmap with a solid color
412  *          -------------------------------------------------.
413  *
414  * @param   color       The color.
415  * @param   cliprect    The cliprect.
416  */
417 
fill(uint64_t color,const rectangle & bounds)418 void bitmap_t::fill(uint64_t color, const rectangle &bounds)
419 {
420 	// if we have a cliprect, intersect with that
421 	rectangle fill(bounds);
422 	fill &= m_cliprect;
423 	if (!fill.empty())
424 	{
425 		// based on the bpp go from there
426 		switch (m_bpp)
427 		{
428 		case 8:
429 			for (int32_t y = fill.top(); y <= fill.bottom(); y++)
430 				std::fill_n(&pixt<uint8_t>(y, fill.left()), fill.width(), uint8_t(color));
431 			break;
432 
433 		case 16:
434 			for (int32_t y = fill.top(); y <= fill.bottom(); ++y)
435 				std::fill_n(&pixt<uint16_t>(y, fill.left()), fill.width(), uint16_t(color));
436 			break;
437 
438 		case 32:
439 			for (int32_t y = fill.top(); y <= fill.bottom(); ++y)
440 				std::fill_n(&pixt<uint32_t>(y, fill.left()), fill.width(), uint32_t(color));
441 			break;
442 
443 		case 64:
444 			for (int32_t y = fill.top(); y <= fill.bottom(); ++y)
445 				std::fill_n(&pixt<uint64_t>(y, fill.left()), fill.width(), uint64_t(color));
446 			break;
447 		}
448 	}
449 }
450 
451 
452 //**************************************************************************
453 //  EXPLICIT TEMPLATE INSTANTIATIONS
454 //**************************************************************************
455 
456 template class bitmap_specific<uint8_t>;
457 template class bitmap_specific<uint16_t>;
458 template class bitmap_specific<uint32_t>;
459 template class bitmap_specific<uint64_t>;
460