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