206 lines
6.0 KiB
C++
206 lines
6.0 KiB
C++
/* -----------------------------------------------------------------------------
|
|
GSFramework
|
|
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
#include <cstring>
|
|
#include <iostream>
|
|
#include "picture/pict.h"
|
|
#include "log/log.h"
|
|
|
|
using namespace GS;
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool Picture::HasAlpha() const
|
|
{
|
|
uchar *pdata = GetData();
|
|
if (!pdata || !width || !height)
|
|
return false;
|
|
|
|
for (uint y = 0; y < height; y++)
|
|
for (uint x = 0; x < width; x++)
|
|
{
|
|
union
|
|
{
|
|
uint packed;
|
|
uchar ppack[4];
|
|
};
|
|
|
|
switch (pxformat.GetBpp())
|
|
{
|
|
case 8: ppack[0] = pdata[0]; pdata++; break;
|
|
case 16: ppack[0] = pdata[0]; ppack[1] = pdata[1]; pdata += 2; break;
|
|
case 24: ppack[0] = pdata[0]; ppack[1] = pdata[1]; ppack[2] = pdata[2]; pdata += 3; break;
|
|
case 32: ppack[0] = pdata[0]; ppack[1] = pdata[1]; ppack[2] = pdata[2]; ppack[3] = pdata[3]; pdata += 4; break;
|
|
}
|
|
|
|
int a = (int)(((packed & pxformat.desc.amask) >> pxformat.ashift) << (8 - pxformat.acount));
|
|
if (a < ((1 << pxformat.acount) - 1))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint Picture::ColorBlend(uint u, uint v, float opacity)
|
|
{
|
|
int fk = (int)(opacity * 65536),
|
|
ik = 65536 - fk;
|
|
|
|
uint ta = ((u >> 24) & 0xff) * ik + ((v >> 24) & 0xff) * fk,
|
|
tr = ((u >> 16) & 0xff) * ik + ((v >> 16) & 0xff) * fk,
|
|
tg = ((u >> 8) & 0xff) * ik + ((v >> 8) & 0xff) * fk,
|
|
tb = (u & 0xff) * ik + (v & 0xff) * fk;
|
|
|
|
return ((ta << 8) & 0xff000000) + (tr & 0xff0000) + ((tg >> 8) & 0xff00) + (tb >> 16);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool Picture::Compare(const Picture &picture) const
|
|
{
|
|
if (pxformat != picture.GetPixelFormat().GetDesc())
|
|
return false;
|
|
// Binary comparison.
|
|
return !Memory::Compare(data, picture.GetData(), width * height * (pxformat.GetBpp() >> 3));
|
|
}
|
|
bool Picture::ComputeHash()
|
|
{
|
|
uchar *pdata = GetData();
|
|
if (!pdata || !width || !height)
|
|
return false;
|
|
|
|
hash = 0;
|
|
for (uint y = 0; y < height; y++)
|
|
for (uint x = 0; x < width; x++)
|
|
{
|
|
union
|
|
{
|
|
uint packed;
|
|
uchar ppack[4];
|
|
};
|
|
|
|
switch (pxformat.GetBpp())
|
|
{
|
|
case 8: ppack[0] = pdata[0]; pdata++; break;
|
|
case 16: ppack[0] = pdata[0]; ppack[1] = pdata[1]; pdata += 2; break;
|
|
case 24: ppack[0] = pdata[0]; ppack[1] = pdata[1]; ppack[2] = pdata[2]; pdata += 3; break;
|
|
case 32: ppack[0] = pdata[0]; ppack[1] = pdata[1]; ppack[2] = pdata[2]; ppack[3] = pdata[3]; pdata += 4; break;
|
|
}
|
|
|
|
int a = (int)(((packed & pxformat.desc.amask) >> pxformat.ashift) << (8 - pxformat.acount));
|
|
int r = (int)(((packed & pxformat.desc.rmask) >> pxformat.rshift) << (8 - pxformat.rcount));
|
|
int g = (int)(((packed & pxformat.desc.gmask) >> pxformat.gshift) << (8 - pxformat.gcount));
|
|
int b = (int)(((packed & pxformat.desc.bmask) >> pxformat.bshift) << (8 - pxformat.bcount));
|
|
|
|
hash += (a << 24) + (r << 16) + (g << 8) + b;
|
|
}
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Picture::SetData(void *ud, uint w, uint h, const PixelFormatDescription &fmt, bool take_ownership)
|
|
{
|
|
if (!ud)
|
|
return;
|
|
|
|
FreeData();
|
|
hash = 0;
|
|
|
|
data = (uchar *)ud;
|
|
if (!take_ownership)
|
|
pic_flag.Set(HasForeignData);
|
|
|
|
width = w;
|
|
height = h;
|
|
pxformat.Set(fmt);
|
|
}
|
|
bool Picture::AllocAs(uint w, uint h, const PixelFormatDescription &fmt)
|
|
{
|
|
if (!pic_flag.IsSet(HasForeignData) && data && (width == w) && (height == h) && (pxformat.GetBpp() == fmt.bpp))
|
|
{
|
|
pxformat.Set(fmt);
|
|
return true;
|
|
}
|
|
|
|
FreeData();
|
|
|
|
if (w && h && fmt.bpp)
|
|
{
|
|
size_t count = w * h * (fmt.bpp / 8);
|
|
|
|
data = AllocMemory(count);
|
|
if (data)
|
|
memset(data, 0, sizeof(uchar) * count);
|
|
else
|
|
__ERR__(__LOG_E__ << "Failed to allocate picture buffer (" << w << "x" << h << "@" << fmt.bpp << "bpp).\n", false);
|
|
|
|
width = w;
|
|
height = h;
|
|
pxformat.Set(fmt);
|
|
}
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Picture::Clone(const Picture &src, bool clone_data)
|
|
{
|
|
Free();
|
|
|
|
if (src.IsStub())
|
|
Stub(src.GetWidth(), src.GetHeight());
|
|
else
|
|
{
|
|
if (clone_data)
|
|
{
|
|
if (AllocAs(src.GetWidth(), src.GetHeight(), src.pxformat.GetDesc()))
|
|
Memory::Copy((char *)data, (char *)src.GetData(), width * height * (pxformat.GetBpp() / 8));
|
|
}
|
|
else
|
|
SetData(src.GetData(), src.GetWidth(), src.GetHeight(), src.pxformat.GetDesc(), false);
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void Picture::Stub(uint w, uint h)
|
|
{
|
|
Free();
|
|
protected_flag.Set(PictureIsStub);
|
|
width = w;
|
|
height = h;
|
|
}
|
|
void Picture::Zeroify()
|
|
{
|
|
data = NULL;
|
|
hash = 0;
|
|
width = height = 0;
|
|
pxformat.Set(PixelFormat::NONE);
|
|
pic_flag = 0;
|
|
protected_flag = 0;
|
|
}
|
|
void Picture::FreeData()
|
|
{
|
|
if (!pic_flag.IsSet(HasForeignData))
|
|
FreeMemory(data);
|
|
data = NULL;
|
|
pic_flag.Remove(HasForeignData);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
uchar *Picture::AllocMemory(size_t size)
|
|
{ return (uchar *)Alloc::DefaultAllocator::Alloc(size, Alloc::Picture); }
|
|
void Picture::FreeMemory(uchar *data)
|
|
{ Alloc::DefaultAllocator::Delete(data, Alloc::Picture); }
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
Picture::~Picture() { Free(); }
|
|
//------------------------------------------------------------------------------
|