summaryrefslogblamecommitdiffstatshomepage
path: root/src/lib/util/bitmap.cpp
blob: 87cf8a27b768258f7260b9f39646200ba00747b0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                                





                                                                            

                                                                            

                   

                   
              
 

 
                                                                            
                  
                                                                            
 
                                                   
                                                 
                                                   
 
                                                                
 
                                 



                                                   

                                                



                                                        
                                                                             


 



































                                                   




                                                                            















                                          
   
                                                                                                          
  


                                                              
  





                                                
   
 





                                                                                                  
 

                               
                                               
                                              

 
   
                                                                                                               
  
                        
  





                                                        
   
 










                                                                                                       
 
                               
 
 
   
                                                                                                         
  
                        
  



                                                        
   
 


                                                                                                 
                                                                  






                                                                     
 

                                          


                                                    
   
                             
  


                                                              
   
 


                                    
                

 















                                              
   
                                                                            
  



                                                                                          
  



                               
   
 
                                                                    
 


                                                                        
                                    
                
 


                                        
 
                            
                                                      

                          
                                                    
 
                                                
                                                                        
                                                 

                                
                                               

                           


                                   
   
                                                                          
  



                                                                                                
  



                               
   











                                                                        
                                                                                   
 

                                               





                                                      
 







                                                    

 
   
                              
  


                                                                               
   
 
                      
 
                                    
                             
                        
                         
 



                           
                                     

 
   
                                                                             
  


                                                                                        
  



                                                  
   
 
                                                                     
 

                                    
 




                                     


                                                        
   
                                                                             
  



                                                                                                 
  

                                   
   
 
                                                                     
 



                                                    

                                    
 
                               
                                                                  


                                         

                                                        

 
   
                                                      
  


                                                              
  
                                                     
   
 
                                              
 
                                                 
                                 
         
                                   
                                    

         
                                         
                               
         
                               
                                    


         
   
                                                                      
  


                                                              
  

                                     
   
 
                                                              
 



                                                     

                       

                                         
         
                       
                                                  

                                                                                                 

                              
                        
                                                                      
                                                                  
                         

                                                                                                             


                            
                                                                   


                                                                                     
 
                                                                               

                                                                                          
                                 
                                                                                  
                                                                                    




                                 
                                                                      
                                                                                                                  
                         

                                                                                                                  


                            
                                                                   


                                                                                     
 
                                                                               

                                                                                              
                                 
                                                                                  
                                                                                    


                                 

                        
                                                                      
                                                                                                                                                                                                         
                         

                                                                                                                  


                            
                                                                   


                                                                                     
 
                                                                               

                                                                                              
                                 
                                                                                  
                                                                                    


                                 

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

    bitmap.c

    Core bitmap routines.

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

#include <assert.h>

#include "bitmap.h"

#include <new>



//**************************************************************************
//  INLINE HELPERS
//**************************************************************************

//-------------------------------------------------
//  compute_rowpixels - compute a rowpixels value
//-------------------------------------------------

inline int32_t bitmap_t::compute_rowpixels(int width, int xslop)
{
	return width + 2 * xslop;
}


//-------------------------------------------------
//  compute_base - compute a bitmap base address
//  with the given slop values
//-------------------------------------------------

inline void bitmap_t::compute_base(int xslop, int yslop)
{
	m_base = m_alloc.get() + (m_rowpixels * yslop + xslop) * (m_bpp / 8);
}


//-------------------------------------------------
//  valid_format - return true if the bitmap format
//  is valid and agrees with the BPP
//-------------------------------------------------

inline bool bitmap_t::valid_format() const
{
	switch (m_format)
	{
	// invalid format
	case BITMAP_FORMAT_INVALID:
		return false;

	// 8bpp formats
	case BITMAP_FORMAT_IND8:
		return m_bpp == 8;

	// 16bpp formats
	case BITMAP_FORMAT_IND16:
	case BITMAP_FORMAT_YUY16:
		return m_bpp == 16;

	// 32bpp formats
	case BITMAP_FORMAT_IND32:
	case BITMAP_FORMAT_RGB32:
	case BITMAP_FORMAT_ARGB32:
		return m_bpp == 32;

	// 64bpp formats
	case BITMAP_FORMAT_IND64:
		return m_bpp == 64;
	}

	return false;
}


//**************************************************************************
//  BITMAP ALLOCATION/CONFIGURATION
//**************************************************************************

bitmap_t::bitmap_t(bitmap_t &&that)
	: m_alloc(std::move(that.m_alloc))
	, m_allocbytes(that.m_allocbytes)
	, m_base(that.m_base)
	, m_rowpixels(that.m_rowpixels)
	, m_width(that.m_width)
	, m_height(that.m_height)
	, m_format(that.m_format)
	, m_bpp(that.m_bpp)
	, m_palette(nullptr)
	, m_cliprect(that.m_cliprect)
{
	set_palette(that.m_palette);
	that.reset();
}

/**
 * @fn  bitmap_t::bitmap_t(bitmap_format format, uint8_t bpp, int width, int height, int xslop, int yslop)
 *
 * @brief   -------------------------------------------------
 *            bitmap_t - basic constructor
 *          -------------------------------------------------.
 *
 * @param   format  Describes the format to use.
 * @param   bpp     The bits per pixel.
 * @param   width   The width.
 * @param   height  The height.
 * @param   xslop   The xslop.
 * @param   yslop   The yslop.
 */

bitmap_t::bitmap_t(bitmap_format format, uint8_t bpp, int width, int height, int xslop, int yslop)
	: m_alloc()
	, m_allocbytes(0)
	, m_format(format)
	, m_bpp(bpp)
	, m_palette(nullptr)
{
	assert(valid_format());

	// allocate intializes all other fields
	allocate(width, height, xslop, yslop);
}

/**
 * @fn  bitmap_t::bitmap_t(bitmap_format format, uint8_t bpp, void *base, int width, int height, int rowpixels)
 *
 * @brief   Constructor.
 *
 * @param   format          Describes the format to use.
 * @param   bpp             The bits per pixel.
 * @param [in,out]  base    If non-null, the base.
 * @param   width           The width.
 * @param   height          The height.
 * @param   rowpixels       The rowpixels.
 */

bitmap_t::bitmap_t(bitmap_format format, uint8_t bpp, void *base, int width, int height, int rowpixels)
	: m_alloc()
	, m_allocbytes(0)
	, m_base(base)
	, m_rowpixels(rowpixels)
	, m_width(width)
	, m_height(height)
	, m_format(format)
	, m_bpp(bpp)
	, m_palette(nullptr)
	, m_cliprect(0, width - 1, 0, height - 1)
{
	assert(valid_format());
}

/**
 * @fn  bitmap_t::bitmap_t(bitmap_format format, uint8_t bpp, bitmap_t &source, const rectangle &subrect)
 *
 * @brief   Constructor.
 *
 * @param   format          Describes the format to use.
 * @param   bpp             The bits per pixel.
 * @param [in,out]  source  Source for the.
 * @param   subrect         The subrect.
 */

bitmap_t::bitmap_t(bitmap_format format, uint8_t bpp, bitmap_t &source, const rectangle &subrect)
	: m_alloc()
	, m_allocbytes(0)
	, m_base(source.raw_pixptr(subrect.top(), subrect.left()))
	, m_rowpixels(source.m_rowpixels)
	, m_width(subrect.width())
	, m_height(subrect.height())
	, m_format(format)
	, m_bpp(bpp)
	, m_palette(nullptr)
	, m_cliprect(0, subrect.width() - 1, 0, subrect.height() - 1)
{
	assert(format == source.m_format);
	assert(bpp == source.m_bpp);
	assert(source.cliprect().contains(subrect));
}

/**
 * @fn  bitmap_t::~bitmap_t()
 *
 * @brief   -------------------------------------------------
 *            ~bitmap_t - basic destructor
 *          -------------------------------------------------.
 */

bitmap_t::~bitmap_t()
{
	// delete any existing stuff
	reset();
}

bitmap_t &bitmap_t::operator=(bitmap_t &&that)
{
	m_alloc = std::move(that.m_alloc);
	m_allocbytes = that.m_allocbytes;
	m_base = that.m_base;
	m_rowpixels = that.m_rowpixels;
	m_width = that.m_width;
	m_height = that.m_height;
	m_format = that.m_format;
	m_bpp = that.m_bpp;
	set_palette(that.m_palette);
	m_cliprect = that.m_cliprect;
	that.reset();
	return *this;
}

/**
 * @fn  void bitmap_t::allocate(int width, int height, int xslop, int yslop)
 *
 * @brief   -------------------------------------------------
 *            allocate -- (re)allocate memory for the bitmap at the given size, destroying
 *            anything that already exists
 *          -------------------------------------------------.
 *
 * @param   width   The width.
 * @param   height  The height.
 * @param   xslop   The xslop.
 * @param   yslop   The yslop.
 */

void bitmap_t::allocate(int width, int height, int xslop, int yslop)
{
	assert(m_format != BITMAP_FORMAT_INVALID);
	assert(m_bpp == 8 || m_bpp == 16 || m_bpp == 32 || m_bpp == 64);

	// delete any existing stuff
	reset();

	// handle empty requests cleanly
	if (width <= 0 || height <= 0)
		return;

	// initialize fields
	m_rowpixels = compute_rowpixels(width, xslop);
	m_width = width;
	m_height = height;
	m_cliprect.set(0, width - 1, 0, height - 1);

	// allocate memory for the bitmap itself
	m_allocbytes = m_rowpixels * (m_height + 2 * yslop) * m_bpp / 8;
	m_alloc.reset(new uint8_t[m_allocbytes]);

	// clear to 0 by default
	memset(m_alloc.get(), 0, m_allocbytes);

	// compute the base
	compute_base(xslop, yslop);
}

/**
 * @fn  void bitmap_t::resize(int width, int height, int xslop, int yslop)
 *
 * @brief   -------------------------------------------------
 *            resize -- resize a bitmap, reusing existing memory if the new size is smaller than
 *            the current size
 *          -------------------------------------------------.
 *
 * @param   width   The width.
 * @param   height  The height.
 * @param   xslop   The xslop.
 * @param   yslop   The yslop.
 */

void bitmap_t::resize(int width, int height, int xslop, int yslop)
{
	assert(m_format != BITMAP_FORMAT_INVALID);
	assert(m_bpp == 8 || m_bpp == 16 || m_bpp == 32 || m_bpp == 64);

	// handle empty requests cleanly
	if (width <= 0 || height <= 0)
		width = height = 0;

	// determine how much memory we need for the new bitmap
	int new_rowpixels = compute_rowpixels(width, xslop);
	uint32_t new_allocbytes = new_rowpixels * (height + 2 * yslop) * m_bpp / 8;

	// if we need more memory, just realloc
	if (new_allocbytes > m_allocbytes)
	{
		palette_t *palette = m_palette;
		allocate(width, height, xslop, yslop);
		set_palette(palette);
		return;
	}

	// otherwise, reconfigure
	m_rowpixels = new_rowpixels;
	m_width = width;
	m_height = height;
	m_cliprect.set(0, width - 1, 0, height - 1);

	// re-compute the base
	compute_base(xslop, yslop);
}

/**
 * @fn  void bitmap_t::reset()
 *
 * @brief   -------------------------------------------------
 *            reset -- reset to an invalid bitmap, deleting all allocated stuff
 *          -------------------------------------------------.
 */

void bitmap_t::reset()
{
	// delete any existing stuff
	set_palette(nullptr);
	m_alloc.reset();
	m_base = nullptr;

	// reset all fields
	m_rowpixels = 0;
	m_width = 0;
	m_height = 0;
	m_cliprect.set(0, -1, 0, -1);
}

/**
 * @fn  void bitmap_t::wrap(void *base, int width, int height, int rowpixels)
 *
 * @brief   -------------------------------------------------
 *            wrap -- wrap an array of memory; the target bitmap does not own the memory
 *          -------------------------------------------------.
 *
 * @param [in,out]  base    If non-null, the base.
 * @param   width           The width.
 * @param   height          The height.
 * @param   rowpixels       The rowpixels.
 */

void bitmap_t::wrap(void *base, int width, int height, int rowpixels)
{
	// delete any existing stuff
	reset();

	// initialize relevant fields
	m_base = base;
	m_rowpixels = rowpixels;
	m_width = width;
	m_height = height;
	m_cliprect.set(0, m_width - 1, 0, m_height - 1);
}

/**
 * @fn  void bitmap_t::wrap(const bitmap_t &source, const rectangle &subrect)
 *
 * @brief   -------------------------------------------------
 *            wrap -- wrap a subrectangle of an existing bitmap by copying its fields; the target
 *            bitmap does not own the memory
 *          -------------------------------------------------.
 *
 * @param   source  Source for the.
 * @param   subrect The subrect.
 */

void bitmap_t::wrap(const bitmap_t &source, const rectangle &subrect)
{
	assert(m_format == source.m_format);
	assert(m_bpp == source.m_bpp);
	assert(source.cliprect().contains(subrect));

	// delete any existing stuff
	reset();

	// copy relevant fields
	m_base = source.raw_pixptr(subrect.top(), subrect.left());
	m_rowpixels = source.m_rowpixels;
	m_width = subrect.width();
	m_height = subrect.height();
	set_palette(source.m_palette);
	m_cliprect.set(0, m_width - 1, 0, m_height - 1);
}

/**
 * @fn  void bitmap_t::set_palette(palette_t *palette)
 *
 * @brief   -------------------------------------------------
 *            set_palette -- associate a palette with a bitmap
 *          -------------------------------------------------.
 *
 * @param [in,out]  palette If non-null, the palette.
 */

void bitmap_t::set_palette(palette_t *palette)
{
	// first dereference any existing palette
	if (m_palette != nullptr)
	{
		m_palette->deref();
		m_palette = nullptr;
	}

	// then reference any new palette
	if (palette != nullptr)
	{
		palette->ref();
		m_palette = palette;
	}
}

/**
 * @fn  void bitmap_t::fill(uint32_t color, const rectangle &cliprect)
 *
 * @brief   -------------------------------------------------
 *            fill -- fill a bitmap with a solid color
 *          -------------------------------------------------.
 *
 * @param   color       The color.
 * @param   cliprect    The cliprect.
 */

void bitmap_t::fill(uint32_t color, const rectangle &cliprect)
{
	// if we have a cliprect, intersect with that
	rectangle fill = cliprect;
	fill &= m_cliprect;
	if (fill.empty())
		return;

	// based on the bpp go from there
	switch (m_bpp)
	{
		case 8:
			// 8bpp always uses memset
			for (int32_t y = fill.top(); y <= fill.bottom(); y++)
				memset(raw_pixptr(y, fill.left()), uint8_t(color), fill.width());
			break;

		case 16:
			// 16bpp can use memset if the bytes are equal
			if (uint8_t(color >> 8) == uint8_t(color))
			{
				for (int32_t y = fill.top(); y <= fill.bottom(); y++)
					memset(raw_pixptr(y, fill.left()), uint8_t(color), fill.width() * 2);
			}
			else
			{
				// Fill the first line the hard way
				uint16_t *destrow = &pixt<uint16_t>(fill.top());
				for (int32_t x = fill.left(); x <= fill.right(); x++)
					destrow[x] = uint16_t(color);

				// For the other lines, just copy the first one
				void *destrow0 = &pixt<uint16_t>(fill.top(), fill.left());
				for (int32_t y = fill.top() + 1; y <= fill.bottom(); y++)
				{
					destrow = &pixt<uint16_t>(y, fill.left());
					memcpy(destrow, destrow0, fill.width() * 2);
				}
			}
			break;

		case 32:
			// 32bpp can use memset if the bytes are equal
			if ((uint8_t)(color >> 8) == (uint8_t)color && (uint16_t)(color >> 16) == (uint16_t)color)
			{
				for (int32_t y = fill.top(); y <= fill.bottom(); y++)
					memset(&pixt<uint32_t>(y, fill.left()), uint8_t(color), fill.width() * 4);
			}
			else
			{
				// Fill the first line the hard way
				uint32_t *destrow  = &pixt<uint32_t>(fill.top());
				for (int32_t x = fill.left(); x <= fill.right(); x++)
					destrow[x] = uint32_t(color);

				// For the other lines, just copy the first one
				uint32_t *destrow0 = &pixt<uint32_t>(fill.top(), fill.left());
				for (int32_t y = fill.top() + 1; y <= fill.bottom(); y++)
				{
					destrow = &pixt<uint32_t>(y, fill.left());
					memcpy(destrow, destrow0, fill.width() * 4);
				}
			}
			break;

		case 64:
			// 64bpp can use memset if the bytes are equal
			if (uint8_t(color >> 8) == uint8_t(color) && uint16_t(color >> 16) == uint16_t(color)) // FIXME: really?  wat about the upper bits that would be zeroed when done the "hard way"?
			{
				for (int32_t y = fill.top(); y <= fill.bottom(); y++)
					memset(&pixt<uint64_t>(y, fill.left()), uint8_t(color), fill.width() * 8);
			}
			else
			{
				// Fill the first line the hard way
				uint64_t *destrow  = &pixt<uint64_t>(fill.top());
				for (int32_t x = fill.left(); x <= fill.right(); x++)
					destrow[x] = uint64_t(color);

				// For the other lines, just copy the first one
				uint64_t *destrow0 = &pixt<uint64_t>(fill.top(), fill.left());
				for (int32_t y = fill.top() + 1; y <= fill.bottom(); y++)
				{
					destrow = &pixt<uint64_t>(y, fill.left());
					memcpy(destrow, destrow0, fill.width() * 8);
				}
			}
			break;
	}
}