commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
205
include/framework/picture/pict.cpp
Normal file
205
include/framework/picture/pict.cpp
Normal file
@ -0,0 +1,205 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
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(); }
|
||||
//------------------------------------------------------------------------------
|
||||
420
include/framework/picture/pict_blit.cpp
Normal file
420
include/framework/picture/pict_blit.cpp
Normal file
@ -0,0 +1,420 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include <cstring>
|
||||
#include "picture/pict.h"
|
||||
#include "color/color.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Picture::Reframe(int offset_sx, int offset_sy, int offset_ex, int offset_ey, const Color *fill)
|
||||
{
|
||||
if (!GetData() || (GetPixelFormat().GetBpp() != 32))
|
||||
return false;
|
||||
|
||||
int _width = GetWidth() - offset_sx + offset_ex,
|
||||
_height = GetHeight() - offset_sy + offset_ey;
|
||||
|
||||
uint *new_data = (uint *)AllocMemory(sizeof(uint) * _width * _height), *_d = new_data;
|
||||
|
||||
if (!new_data)
|
||||
__ERR__(__LOG_E__ << "Failed to allocate destination buffer.\n", false)
|
||||
|
||||
// Fill color.
|
||||
uint _fill = fill ? GetPixelFormat().Format(fill->x, fill->y, fill->z, fill->w) : GetPixelFormat().Format(0, 0, 0);
|
||||
|
||||
// Top framing.
|
||||
for (int y = offset_sy; y < 0; ++y)
|
||||
for (int x = 0; x < _width; ++x)
|
||||
*_d++ = _fill;
|
||||
|
||||
// Blit + left/right framing.
|
||||
int blit_ex = offset_ex > 0 ? GetWidth() : GetWidth() + offset_ex,
|
||||
blit_ey = offset_ey > 0 ? GetHeight() : GetHeight() + offset_ey;
|
||||
|
||||
uint *s = (uint *)GetData();
|
||||
if (offset_sy > 0)
|
||||
s += GetWidth() * offset_sy;
|
||||
|
||||
for (int y = offset_sy > 0 ? offset_sy : 0; y < blit_ey; ++y)
|
||||
{
|
||||
uint *_s = s;
|
||||
|
||||
for (int x = offset_sx; x < 0; ++x)
|
||||
*_d++ = _fill; // Left framing
|
||||
for (int x = offset_sx > 0 ? offset_sx : 0; x < blit_ex; ++x)
|
||||
*_d++ = _s[x]; // Blit
|
||||
for (int x = 0; x < offset_ex; ++x)
|
||||
*_d++ = _fill; // Right framing
|
||||
|
||||
s += GetWidth();
|
||||
}
|
||||
|
||||
// Bottom framing.
|
||||
for (int y = 0; y < offset_ey; ++y)
|
||||
for (int x = 0; x < _width; ++x)
|
||||
*_d++ = _fill;
|
||||
|
||||
SetData(new_data, _width, _height, GetPixelFormat().GetDesc(), true);
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Picture::Flip(bool flip_h, bool flip_v)
|
||||
{
|
||||
if (!GetData() || (GetPixelFormat().GetBpp() != 32))
|
||||
return false;
|
||||
|
||||
uint *s = (uint *)GetData(),
|
||||
*d = s, t;
|
||||
|
||||
if (flip_h)
|
||||
{
|
||||
if (flip_v)
|
||||
{
|
||||
d += GetWidth() * GetHeight() - 1;
|
||||
|
||||
while (d > s)
|
||||
{
|
||||
t = *s;
|
||||
*s++ = *d;
|
||||
*d-- = t;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint n = 0; n < GetHeight(); ++n)
|
||||
{
|
||||
uint *_s = s, *_d = d + GetWidth() - 1;
|
||||
|
||||
while (_d > _s)
|
||||
{
|
||||
t = *_s;
|
||||
*_s++ = *_d;
|
||||
*_d-- = t;
|
||||
}
|
||||
s += GetWidth();
|
||||
d += GetWidth();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (flip_v)
|
||||
{
|
||||
d += GetWidth() * (GetHeight() - 1);
|
||||
while (d > s)
|
||||
{
|
||||
for (uint n = 0; n < GetWidth(); ++n)
|
||||
{
|
||||
t = s[n];
|
||||
s[n] = d[n];
|
||||
d[n] = t;
|
||||
}
|
||||
s += GetWidth();
|
||||
d -= GetWidth();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static void WindowClip(const Rect <int> *a, Rect <int> *fa, const Rect <int> *b, Rect <int> *fb)
|
||||
{
|
||||
Rect <int> _b(*b);
|
||||
_b.ex = _b.sx + a->GetWidth();
|
||||
_b.ey = _b.sy + a->GetHeight();
|
||||
|
||||
// Clip source rectangle and correct destination rectangle.
|
||||
*fa = fa->Intersection(*a);
|
||||
_b.sx += fa->sx - a->sx;
|
||||
_b.sy += fa->sy - a->sy;
|
||||
_b.ex += fa->ex - a->ex;
|
||||
_b.ey += fa->ey - a->ey;
|
||||
|
||||
// Clip destination rectangle and correct source rectangle.
|
||||
*fb = fb->Intersection(_b);
|
||||
fa->sx += fb->sx - _b.sx;
|
||||
fa->sy += fb->sy - _b.sy;
|
||||
fa->ex += fb->ex - _b.ex;
|
||||
fa->ey += fb->ey - _b.ey;
|
||||
}
|
||||
static void WindowStretch(Rect <float> *a, Rect <float> *fa, Rect <float> *b, Rect <float> *fb)
|
||||
{
|
||||
float ku = (float)b->GetWidth() / (float)a->GetWidth(),
|
||||
kv = (float)b->GetHeight() / (float)a->GetHeight();
|
||||
|
||||
// Clip source rectangle and correct destination rectangle.
|
||||
fa[0] = fa->Intersection(a[0]);
|
||||
b->sx += (fa->sx - a->sx) * ku;
|
||||
b->sy += (fa->sy - a->sy) * kv;
|
||||
b->ex += (fa->ex - a->ex) * ku;
|
||||
b->ey += (fa->ey - a->ey) * kv;
|
||||
|
||||
// Clip destination rectangle and correct source rectangle.
|
||||
fb[0] = fb->Intersection(b[0]);
|
||||
ku = 1 / ku;
|
||||
kv = 1 / kv;
|
||||
fa->sx += (fb->sx - b->sx) * ku;
|
||||
fa->sy += (fb->sy - b->sy) * kv;
|
||||
fa->ex += (fb->ex - b->ex) * ku;
|
||||
fa->ey += (fb->ey - b->ey) * kv;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Picture::BlitMask(const Picture &src, Picture &dst, Picture &msk, const Rect <int> *src_rect, const Rect <int> *dst_rect)
|
||||
{
|
||||
if (!src.GetData() || !dst.GetData())
|
||||
return false;
|
||||
|
||||
// Default blit rectangles.
|
||||
Rect <int> default_a(src.GetRect()), default_b(dst.GetRect());
|
||||
if (!src_rect)
|
||||
src_rect = &default_a;
|
||||
if (!dst_rect)
|
||||
dst_rect = &default_b;
|
||||
|
||||
// Compute blit window.
|
||||
Rect <int> frame_a(src.GetRect()), frame_b(dst.GetRect());
|
||||
WindowClip(src_rect, &frame_a, dst_rect, &frame_b);
|
||||
|
||||
// Limit to mask dimensions.
|
||||
if (frame_b.GetWidth() > (int)msk.GetWidth())
|
||||
frame_b.SetWidth(msk.GetWidth());
|
||||
if (frame_b.GetHeight() > (int)msk.GetHeight())
|
||||
frame_b.SetHeight(msk.GetHeight());
|
||||
|
||||
if ((frame_b.GetWidth() <= 0) || (frame_b.GetHeight() <= 0))
|
||||
return false;
|
||||
|
||||
PixelFormatDescription initial = dst.GetPixelFormat().GetDesc();
|
||||
dst.Convert(src.GetPixelFormat().GetDesc());
|
||||
|
||||
// Perform blit.
|
||||
uchar *psrc = src.GetDataOffset(frame_a.sx, frame_a.sy),
|
||||
*pdst = dst.GetDataOffset(frame_b.sx, frame_b.sy),
|
||||
*pmsk = msk.GetData();
|
||||
|
||||
for (int n = 0; n < frame_b.GetHeight(); n++)
|
||||
{
|
||||
uchar *_pdst = pdst, *_psrc = psrc, *_pmsk = pmsk;
|
||||
|
||||
for (int x = frame_b.GetWidth(); x--; )
|
||||
{
|
||||
uchar alpha = _pmsk[3];
|
||||
|
||||
uchar a_blend = AlphaCompositeAlpha(_pdst[3], alpha);
|
||||
_pdst[0] = AlphaCompositeColor(_pdst[0], _psrc[0], _pdst[3], alpha, a_blend);
|
||||
_pdst[1] = AlphaCompositeColor(_pdst[1], _psrc[1], _pdst[3], alpha, a_blend);
|
||||
_pdst[2] = AlphaCompositeColor(_pdst[2], _psrc[2], _pdst[3], alpha, a_blend);
|
||||
_pdst[3] = a_blend;
|
||||
|
||||
_psrc += 4;
|
||||
_pdst += 4;
|
||||
_pmsk += 4;
|
||||
}
|
||||
|
||||
psrc += src.GetPitch();
|
||||
pdst += dst.GetPitch();
|
||||
pmsk += msk.GetPitch();
|
||||
}
|
||||
dst.Convert(initial);
|
||||
return true;
|
||||
}
|
||||
bool Picture::Blit(const Picture &src, Picture &dst, const Rect <int> *src_rect, const Rect <int> *dst_rect, BlendMode mode)
|
||||
{
|
||||
if (!src.GetData() || !dst.GetData())
|
||||
return false;
|
||||
|
||||
// Default blit rectangles.
|
||||
Rect <int> default_a(src.GetRect()), default_b(dst.GetRect());
|
||||
if (!src_rect)
|
||||
src_rect = &default_a;
|
||||
if (!dst_rect)
|
||||
dst_rect = &default_b;
|
||||
|
||||
// Compute blit window.
|
||||
Rect <int> frame_a(src.GetRect()), frame_b(dst.GetRect());
|
||||
WindowClip(src_rect, &frame_a, dst_rect, &frame_b);
|
||||
|
||||
if ((frame_b.GetWidth() <= 0) || (frame_b.GetHeight() <= 0))
|
||||
return false;
|
||||
|
||||
PixelFormatDescription initial = dst.GetPixelFormat().GetDesc();
|
||||
dst.Convert(src.GetPixelFormat().GetDesc());
|
||||
|
||||
// Perform blit.
|
||||
uchar *psrc = src.GetDataOffset(frame_a.sx, frame_a.sy),
|
||||
*pdst = dst.GetDataOffset(frame_b.sx, frame_b.sy);
|
||||
|
||||
for (int n = 0; n < frame_b.GetHeight(); n++)
|
||||
{
|
||||
uchar *_pdst = pdst, *_psrc = psrc;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case RgbToAlpha:
|
||||
for (int x = frame_b.GetWidth(); x--; )
|
||||
{
|
||||
_pdst[3] = (_psrc[0] + _psrc[1] + _psrc[2]) / 3;
|
||||
_psrc += 4;
|
||||
_pdst += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case BlendReplace:
|
||||
memmove(pdst, psrc, frame_b.GetWidth() * dst.GetBpp() / 8);
|
||||
break;
|
||||
|
||||
case BlendComposeFast:
|
||||
for (int x = frame_b.GetWidth(); x--; )
|
||||
{
|
||||
int a = _psrc[3], ia = 255 - a;
|
||||
_pdst[0] = uchar((_psrc[0] * a + _pdst[0] * ia) >> 8);
|
||||
_pdst[1] = uchar((_psrc[1] * a + _pdst[1] * ia) >> 8);
|
||||
_pdst[2] = uchar((_psrc[2] * a + _pdst[2] * ia) >> 8);
|
||||
_pdst[3] = uchar(Types::Max <int> (_pdst[3], a));
|
||||
|
||||
_psrc += 4;
|
||||
_pdst += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case BlendCompose:
|
||||
for (int x = frame_b.GetWidth(); x--; )
|
||||
{
|
||||
uchar a_blend = AlphaCompositeAlpha(_pdst[3], _psrc[3]);
|
||||
_pdst[0] = AlphaCompositeColor(_pdst[0], _psrc[0], _pdst[3], _psrc[3], a_blend);
|
||||
_pdst[1] = AlphaCompositeColor(_pdst[1], _psrc[1], _pdst[3], _psrc[3], a_blend);
|
||||
_pdst[2] = AlphaCompositeColor(_pdst[2], _psrc[2], _pdst[3], _psrc[3], a_blend);
|
||||
_pdst[3] = a_blend;
|
||||
|
||||
_psrc += 4;
|
||||
_pdst += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
psrc += src.GetPitch();
|
||||
pdst += dst.GetPitch();
|
||||
}
|
||||
dst.Convert(initial);
|
||||
return true;
|
||||
}
|
||||
bool Picture::ScaleBlit(Picture &src, Picture &dst, Rect <float> *src_rect, Rect <float> *dst_rect)
|
||||
{
|
||||
if (!src.GetData() || !dst.GetData())
|
||||
return false;
|
||||
|
||||
// Default blitting rectangles.
|
||||
Rect <float> default_a(src.GetRect().AsFloat()), default_b(dst.GetRect().AsFloat());
|
||||
if (!src_rect)
|
||||
src_rect = &default_a;
|
||||
if (!dst_rect)
|
||||
dst_rect = &default_b;
|
||||
|
||||
Rect <float> frame_a(src.GetRect().AsFloat()), frame_b(dst.GetRect().AsFloat());
|
||||
WindowStretch(src_rect, &frame_a, dst_rect, &frame_b);
|
||||
|
||||
if ((frame_b.GetWidth() <= 0) || (frame_b.GetHeight() <= 0))
|
||||
return false;
|
||||
|
||||
// Apply sub-pixel/sub-texel correction.
|
||||
float ku = frame_a.GetWidth() / frame_b.GetWidth(),
|
||||
kv = frame_a.GetHeight() / frame_b.GetHeight();
|
||||
|
||||
float fb_isx = Math::Floor(frame_b.sx),
|
||||
fb_isy = Math::Floor(frame_b.sy),
|
||||
fb_iex = Math::Floor(frame_b.ex),
|
||||
fb_iey = Math::Floor(frame_b.ey);
|
||||
|
||||
float dt_su = (frame_b.sx - fb_isx),
|
||||
dt_sv = (frame_b.sy - fb_isy),
|
||||
dt_eu = (frame_b.ex - fb_iex),
|
||||
dt_ev = (frame_b.ey - fb_iey);
|
||||
|
||||
frame_a.sx -= dt_su * ku;
|
||||
frame_a.sy -= dt_sv * kv;
|
||||
frame_a.ex -= dt_eu * ku;
|
||||
frame_a.ey -= dt_ev * kv;
|
||||
|
||||
frame_b.sx = fb_isx;
|
||||
frame_b.sy = fb_isy;
|
||||
frame_b.ex = fb_iex;
|
||||
frame_b.ey = fb_iey;
|
||||
|
||||
// Convert sub pixel deltas to blending coefficients.
|
||||
dt_su = 1 - dt_su;
|
||||
dt_sv = 1 - dt_sv;
|
||||
|
||||
uint *pdst = (uint *)dst.GetDataOffset((uint)frame_b.sx, (uint)frame_b.sy);
|
||||
|
||||
int src_width = (int)frame_b.GetWidth(),
|
||||
src_height = (int)frame_b.GetHeight();
|
||||
|
||||
float v = frame_a.sy;
|
||||
for (int y = 0; y < src_height; y++)
|
||||
{
|
||||
float u = frame_a.sx;
|
||||
|
||||
// Blended or opaque scanline.
|
||||
if ((!y) || (y == (src_height - 1)))
|
||||
{
|
||||
float kfrst, kscan, klast;
|
||||
|
||||
// Set blend coefficients.
|
||||
if (!y)
|
||||
{
|
||||
kfrst = dt_su * dt_sv; // top-left
|
||||
kscan = dt_sv; // top
|
||||
klast = dt_eu * dt_sv; // top-right
|
||||
}
|
||||
else
|
||||
{
|
||||
kfrst = dt_su * dt_ev; // bottom-left
|
||||
kscan = dt_ev; // bottom
|
||||
klast = dt_eu * dt_ev; // bottom-right
|
||||
}
|
||||
|
||||
// 1st pixel, scanline, last pixel.
|
||||
pdst[0] = ColorBlend(pdst[0], src.SampleInteger(u, v), kfrst);
|
||||
u += ku;
|
||||
|
||||
int x;
|
||||
for (x = 1; x < (src_width - 1); x++)
|
||||
{
|
||||
pdst[x] = ColorBlend(pdst[x], src.SampleInteger(u, v), kscan);
|
||||
u += ku;
|
||||
}
|
||||
pdst[x] = ColorBlend(pdst[x], src.SampleInteger(u, v), klast);
|
||||
}
|
||||
else
|
||||
{
|
||||
pdst[0] = ColorBlend(pdst[0], src.SampleInteger(u, v), dt_su);
|
||||
u += ku;
|
||||
|
||||
int x;
|
||||
for (x = 1; x < (src_width - 1); x++)
|
||||
{
|
||||
pdst[x] = src.SampleInteger(u, v);
|
||||
u += ku;
|
||||
}
|
||||
pdst[x] = ColorBlend(pdst[x], src.SampleInteger(u, v), dt_eu);
|
||||
}
|
||||
|
||||
pdst += dst.GetWidth();
|
||||
v += kv;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
137
include/framework/picture/pict_bmp.cpp
Normal file
137
include/framework/picture/pict_bmp.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "picture/pict.h"
|
||||
#include "picture/pict_io.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
#define IMGBMP_BI_RGB 0
|
||||
#define IMGBMP_BI_RLE8 1
|
||||
#define IMGBMP_BI_RLE4 2
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool PictureIO::BmpLoad(Picture &picture, IO::Handle &handle)
|
||||
{
|
||||
handle.Rewind();
|
||||
size_t size = handle.GetSize();
|
||||
if (size < 10)
|
||||
return false;
|
||||
|
||||
// Magic number
|
||||
if ((handle.Read <char> () != 'B') || (handle.Read <char> () != 'M'))
|
||||
return false;
|
||||
|
||||
handle.Seek(8);
|
||||
uint OffBits = handle.Read <uint> (), width, height;
|
||||
ushort bpp;
|
||||
|
||||
if (handle.Read <uint> () == 40) // we met a BITMAPCOREHEADER
|
||||
{
|
||||
width = handle.Read <uint> ();
|
||||
height = handle.Read <uint> ();
|
||||
}
|
||||
else // we met a BITMAPINFOHEADER
|
||||
{
|
||||
width = handle.Read <ushort> ();
|
||||
height = handle.Read <ushort> ();
|
||||
}
|
||||
handle.Seek(2);
|
||||
bpp = handle.Read <ushort> ();
|
||||
|
||||
if ((bpp != 8) && (bpp != 24) && (bpp != 32))
|
||||
__ERR__(__LOG_E__ << "BMP format unhandled (neither RGB8, RGB24 or BGR8).\n", false)
|
||||
|
||||
// Decode bitmap data.
|
||||
if (!picture.AllocAs(width, height, PixelFormat::BGR8))
|
||||
__ERR__(__LOG_E__ << "Failed to allocate output buffer.\n", false)
|
||||
|
||||
uint *rgb = (uint *)picture.GetData();
|
||||
Array <uchar> bmp(size - OffBits);
|
||||
if (!bmp)
|
||||
__ERR__(__LOG_E__ << "Failed to allocate input framebuffer.\n", false)
|
||||
|
||||
uchar *_bmp = &bmp[0];
|
||||
handle.Seek(OffBits, GS::IO::Base::SeekStart);
|
||||
handle.Read((void *)_bmp, OffBits);
|
||||
|
||||
rgb += (picture.GetHeight() - 1) * picture.GetWidth();
|
||||
|
||||
// Load palette
|
||||
Array <uint> palette;
|
||||
|
||||
if (bpp < 16)
|
||||
{
|
||||
__LOG__ << "Picture is palletized.\n";
|
||||
if (palette.Allocate(1 << bpp))
|
||||
{
|
||||
char cbuf[4];
|
||||
handle.Seek(54, GS::IO::Base::SeekStart);
|
||||
for (int n = 0; n < (1 << bpp); ++n)
|
||||
{
|
||||
handle.Read(cbuf, 4);
|
||||
palette[n] = (cbuf[3] << 24) + (cbuf[2] << 16) + (cbuf[1] << 8) + cbuf[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
__ERR__(__LOG_E__ << "Failed to allocate palette.\n", false)
|
||||
}
|
||||
|
||||
// Even width
|
||||
switch (bpp)
|
||||
{
|
||||
case 8:
|
||||
{
|
||||
// 32 bit 0 padding.
|
||||
uint pad = 0;
|
||||
if (picture.GetWidth() & 3)
|
||||
pad = 4 - (picture.GetWidth() & 3);
|
||||
|
||||
for (uint c2 = 0; c2 < picture.GetHeight(); c2++)
|
||||
{
|
||||
for (uint c = 0; c < picture.GetWidth(); c++)
|
||||
rgb[c] = palette[*_bmp++];
|
||||
_bmp += pad;
|
||||
rgb -= picture.GetWidth();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 16:
|
||||
break;
|
||||
|
||||
case 24:
|
||||
for (uint c2 = 0; c2 < picture.GetHeight(); c2++)
|
||||
{
|
||||
for (uint c = 0; c < picture.GetWidth(); c++)
|
||||
{
|
||||
rgb[c] = (_bmp[2] << 16) + (_bmp[1] << 8) + _bmp[0];
|
||||
_bmp += 3;
|
||||
}
|
||||
uint dt = 3 * picture.GetWidth();
|
||||
if (dt & 3)
|
||||
_bmp += (4 - (dt & 3));
|
||||
rgb -= picture.GetWidth();
|
||||
}
|
||||
break;
|
||||
|
||||
case 32:
|
||||
for (uint c2 = 0; c2 < picture.GetHeight(); c2++)
|
||||
{
|
||||
for (uint c = 0; c < picture.GetWidth(); c++)
|
||||
{
|
||||
rgb[c] = (_bmp[2] << 16) + (_bmp[1] << 8) + _bmp[0];
|
||||
_bmp += 4;
|
||||
}
|
||||
rgb -= picture.GetWidth();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
333
include/framework/picture/pict_color_format.cpp
Normal file
333
include/framework/picture/pict_color_format.cpp
Normal file
@ -0,0 +1,333 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "picture/pict_color_format.h"
|
||||
#include "picture/pict.h"
|
||||
#include "math/nmath.h"
|
||||
#include "sort/sort.h"
|
||||
#include "memory/endian.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
PixelFormatDescription PixelFormat::NONE
|
||||
= {PixelColorSpace_NULL, 0, 0, 0, 0, 0, false};
|
||||
PixelFormatDescription PixelFormat::BGRA8
|
||||
= {PixelColorSpace_RGB, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 32, false};
|
||||
PixelFormatDescription PixelFormat::RGBA8
|
||||
= {PixelColorSpace_RGB, 0xff000000, 0x000000ff, 0x0000ff00, 0x00ff0000, 32, false};
|
||||
PixelFormatDescription PixelFormat::ARGB8
|
||||
= {PixelColorSpace_RGB, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000, 32, false};
|
||||
PixelFormatDescription PixelFormat::BGR8
|
||||
= {PixelColorSpace_RGB, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 24, false};
|
||||
PixelFormatDescription PixelFormat::RGB8
|
||||
= {PixelColorSpace_RGB, 0, 0x000000ff, 0x0000ff00,0x00ff0000, 24, false};
|
||||
PixelFormatDescription PixelFormat::RGB555
|
||||
= {PixelColorSpace_RGB, 0, 0x0000001f, 0x000003e0, 0x00007c00, 16, false};
|
||||
PixelFormatDescription PixelFormat::RGB565
|
||||
= {PixelColorSpace_RGB, 0, 0x0000001f, 0x000007e0, 0x0000f800, 16, false};
|
||||
PixelFormatDescription PixelFormat::RGBA4444
|
||||
= {PixelColorSpace_RGB, 0x0000f000, 0x0000000f, 0x000000f0, 0x00000f00, 16, false};
|
||||
PixelFormatDescription PixelFormat::RGBF
|
||||
= { PixelColorSpace_RGB, 0, 0, 1, 2, sizeof(float) * 3 * 8, true };
|
||||
PixelFormatDescription PixelFormat::RGBAF
|
||||
= { PixelColorSpace_RGB, 0xff000000, 0x000000ff, 0x0000ff00, 0x00ff0000, 4 * 16, true };
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
String PixelFormat::GetName() const
|
||||
{
|
||||
// Sort components.
|
||||
uint count[4] = { Memory::GetBitCount(desc.rmask), Memory::GetBitCount(desc.gmask), Memory::GetBitCount(desc.bmask), Memory::GetBitCount(desc.amask) },
|
||||
shift[4] = { Memory::GetShiftCount(desc.rmask), Memory::GetShiftCount(desc.gmask), Memory::GetShiftCount(desc.bmask), Memory::GetShiftCount(desc.amask) };
|
||||
|
||||
Sort<uint, uint>::Entry comp_sort[4];
|
||||
for (uint n = 0; n < 4; ++n)
|
||||
{
|
||||
comp_sort[n].v = shift[n];
|
||||
comp_sort[n].o = n;
|
||||
}
|
||||
Sort<uint, uint>::QuickSort(4, comp_sort);
|
||||
|
||||
// Build name.
|
||||
static const char *comp_name[4] = {"R", "G", "B", "A"};
|
||||
|
||||
String name;
|
||||
switch (desc.space)
|
||||
{
|
||||
case PixelColorSpace_RGB:
|
||||
{
|
||||
for (uint n = 0; n < 4; ++n)
|
||||
{
|
||||
int i = comp_sort[n].o;
|
||||
if (count[i] != 0)
|
||||
{
|
||||
name += String::Format("%s%d", comp_name[i], count[i]);
|
||||
if (desc.real)
|
||||
name += "F";
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
name = "NONE";
|
||||
break;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint PixelFormat::Format(float r, float g, float b, float a) const
|
||||
{
|
||||
switch (GetBpp())
|
||||
{
|
||||
case 32:
|
||||
return Endian::ToHost((int(r * 255) << rshift) + (int(g * 255) << gshift) + (int(b * 255) << bshift) + (int(a * 255) << ashift), Endian::Intel);
|
||||
|
||||
default:
|
||||
__LOG_W__ << "Unimplemented formatting.\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Picture::Negative(bool r, bool g, bool b, bool a)
|
||||
{
|
||||
if ((GetBpp() != 32) || (!r && !g && !b && !a) || !GetData())
|
||||
return;
|
||||
|
||||
int iia = pxformat.ashift >> 3,
|
||||
iir = pxformat.rshift >> 3,
|
||||
iig = pxformat.gshift >> 3,
|
||||
iib = pxformat.bshift >> 3;
|
||||
|
||||
unsigned char *p = GetData();
|
||||
for (uint v = 0; v < height; ++v)
|
||||
for (uint u = 0; u < width; ++u)
|
||||
{
|
||||
if (r) p[iir] = 255 - p[iir];
|
||||
if (g) p[iig] = 255 - p[iig];
|
||||
if (b) p[iib] = 255 - p[iib];
|
||||
if (a) p[iia] = 255 - p[iia];
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Picture::Fast8888Conversion(const PixelFormat &dsformat)
|
||||
{
|
||||
int iia = pxformat.ashift >> 3,
|
||||
iir = pxformat.rshift >> 3,
|
||||
iig = pxformat.gshift >> 3,
|
||||
iib = pxformat.bshift >> 3,
|
||||
dia = dsformat.ashift >> 3,
|
||||
dir = dsformat.rshift >> 3,
|
||||
dig = dsformat.gshift >> 3,
|
||||
dib = dsformat.bshift >> 3;
|
||||
|
||||
unsigned char *p = GetData();
|
||||
if (!p)
|
||||
return false;
|
||||
|
||||
// Optimized for the most common reorganizing done on 8888 ARGB data.
|
||||
unsigned char r, g, b, a;
|
||||
if (iia == dia)
|
||||
{
|
||||
if (iig == dig) // Fixed green & alpha.
|
||||
for (uint v = 0; v < GetHeight(); ++v)
|
||||
for (uint u = 0; u < GetWidth(); ++u)
|
||||
{
|
||||
r = p[iir]; b = p[iib];
|
||||
p[dir] = r; p[dib] = b;
|
||||
p += 4;
|
||||
}
|
||||
else // Fixed alpha.
|
||||
for (uint v = 0; v < GetHeight(); ++v)
|
||||
for (uint u = 0; u < GetWidth(); ++u)
|
||||
{
|
||||
r = p[iir]; g = p[iig]; b = p[iib];
|
||||
p[dir] = r; p[dig] = g; p[dib] = b;
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
else // Fully generic.
|
||||
for (uint v = 0; v < GetHeight(); ++v)
|
||||
for (uint u = 0; u < GetWidth(); ++u)
|
||||
{
|
||||
a = p[iia]; r = p[iir]; g = p[iig]; b = p[iib];
|
||||
p[dia] = a; p[dir] = r; p[dig] = g; p[dib] = b;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
pxformat = dsformat;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Picture::RealToIntegerConversion(const PixelFormat &dstfmt)
|
||||
{
|
||||
uchar *new_data = new uchar[width * height * (dstfmt.GetBpp() / 8)];
|
||||
if (!new_data)
|
||||
return false;
|
||||
|
||||
uchar *out = new_data;
|
||||
float *pdata = (float *)GetData();
|
||||
|
||||
// Convert.
|
||||
for (uint y = 0; y < GetHeight(); ++y)
|
||||
for (uint x = 0; x < GetWidth(); ++x)
|
||||
{
|
||||
uchar r = (uchar)Types::Min(pdata[2] * 255.f, 255.f), g = (uchar)Types::Min(pdata[1] * 255.f, 255.f), b = (uchar)Types::Min(pdata[0] * 255.f, 255.f), a = 255;
|
||||
pdata += 3;
|
||||
|
||||
// Convert components.
|
||||
a >>= (8 - dstfmt.acount);
|
||||
r >>= (8 - dstfmt.rcount);
|
||||
g >>= (8 - dstfmt.gcount);
|
||||
b >>= (8 - dstfmt.bcount);
|
||||
|
||||
// Repack components and output.
|
||||
uint packed;
|
||||
uchar *ppack = (uchar *)&packed;
|
||||
|
||||
packed = (a << dstfmt.ashift) + (r << dstfmt.rshift) + (g << dstfmt.gshift) + (b << dstfmt.bshift);
|
||||
|
||||
switch (dstfmt.GetBpp())
|
||||
{
|
||||
case 8: out[0] = ppack[0]; out++; break;
|
||||
case 16: out[0] = ppack[0]; out[1] = ppack[1]; out += 2; break;
|
||||
case 24: out[0] = ppack[0]; out[1] = ppack[1]; out[2] = ppack[2]; out += 3; break;
|
||||
case 32: out[0] = ppack[0]; out[1] = ppack[1]; out[2] = ppack[2]; out[3] = ppack[3]; out += 4; break;
|
||||
}
|
||||
}
|
||||
|
||||
// Replace data.
|
||||
SetData(new_data, width, height, dstfmt.GetDesc());
|
||||
return true;
|
||||
}
|
||||
bool Picture::IntegerToIntegerConversion(const PixelFormat &dsformat)
|
||||
{
|
||||
switch (pxformat.GetBpp())
|
||||
{
|
||||
case 8: case 16: case 24: case 32: break;
|
||||
default: return false; // Unsupported source mode.
|
||||
}
|
||||
|
||||
// Allocate destination buffer.
|
||||
uchar *new_data = new uchar[width * height * (dsformat.GetBpp() / 8)];
|
||||
if (!new_data)
|
||||
return false;
|
||||
|
||||
uchar *out = new_data;
|
||||
uchar *pdata = GetData();
|
||||
|
||||
// Convert.
|
||||
for (uint y = 0; y < GetHeight(); ++y)
|
||||
{
|
||||
uint packed;
|
||||
uchar *ppack = (uchar *)&packed;
|
||||
|
||||
for (uint x = 0; x < GetWidth(); ++x)
|
||||
{
|
||||
// Extract packed color.
|
||||
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;
|
||||
}
|
||||
|
||||
// Extract components.
|
||||
uint a = (uchar)(((packed & pxformat.desc.amask) >> pxformat.ashift) << (8 - pxformat.acount)),
|
||||
r = (uchar)(((packed & pxformat.desc.rmask) >> pxformat.rshift) << (8 - pxformat.rcount)),
|
||||
g = (uchar)(((packed & pxformat.desc.gmask) >> pxformat.gshift) << (8 - pxformat.gcount)),
|
||||
b = (uchar)(((packed & pxformat.desc.bmask) >> pxformat.bshift) << (8 - pxformat.bcount));
|
||||
|
||||
// Convert components.
|
||||
a >>= (8 - dsformat.acount);
|
||||
r >>= (8 - dsformat.rcount);
|
||||
g >>= (8 - dsformat.gcount);
|
||||
b >>= (8 - dsformat.bcount);
|
||||
|
||||
// Repack components and output.
|
||||
packed = Endian::ToHost((a << dsformat.ashift) + (r << dsformat.rshift) + (g << dsformat.gshift) + (b << dsformat.bshift), Endian::Intel);
|
||||
|
||||
switch (dsformat.GetBpp())
|
||||
{
|
||||
case 8: out[0] = ppack[0]; out++; break;
|
||||
case 16: out[0] = ppack[0]; out[1] = ppack[1]; out += 2; break;
|
||||
case 24: out[0] = ppack[0]; out[1] = ppack[1]; out[2] = ppack[2]; out += 3; break;
|
||||
case 32: out[0] = ppack[0]; out[1] = ppack[1]; out[2] = ppack[2]; out[3] = ppack[3]; out += 4; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replace data.
|
||||
SetData(new_data, width, height, dsformat.GetDesc(), true);
|
||||
return true;
|
||||
}
|
||||
bool Picture::Convert(const PixelFormatDescription &dsc)
|
||||
{
|
||||
if (pxformat == dsc)
|
||||
return true;
|
||||
|
||||
if (!dsc.bpp)
|
||||
{
|
||||
Free();
|
||||
return true;
|
||||
}
|
||||
|
||||
PixelFormat dsformat(dsc);
|
||||
|
||||
// Real to integer.
|
||||
if (pxformat.IsReal())
|
||||
return RealToIntegerConversion(dsformat);
|
||||
|
||||
// Fast 8888 conversion.
|
||||
if (
|
||||
(pxformat.acount == 8) && (pxformat.rcount == 8) && (pxformat.gcount == 8) && (pxformat.bcount == 8) &&
|
||||
(dsformat.acount == 8) && (dsformat.rcount == 8) && (dsformat.gcount == 8) && (dsformat.bcount == 8)
|
||||
)
|
||||
return Fast8888Conversion(dsformat);
|
||||
|
||||
// Slower generic integer->integer conversion.
|
||||
return IntegerToIntegerConversion(dsformat);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Picture::Swizzle(uchar r, uchar g, uchar b, uchar a)
|
||||
{
|
||||
// Swizzle output format...
|
||||
PixelFormatDescription out_format = GetPixelFormat().GetDesc();
|
||||
|
||||
const uint in_mask[4] = { out_format.rmask, out_format.gmask, out_format.bmask, out_format.amask };
|
||||
out_format.rmask = in_mask[r];
|
||||
out_format.gmask = in_mask[g];
|
||||
out_format.bmask = in_mask[b];
|
||||
out_format.amask = in_mask[a];
|
||||
|
||||
// ...and convert picture.
|
||||
return Convert(out_format);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Picture::SetFormat(const PixelFormatDescription &dsc)
|
||||
{
|
||||
if (dsc.bpp != pxformat.GetDesc().bpp)
|
||||
__ERR__(__LOG_E__ << "Target format requires a data conversion, see Convert().\n", false)
|
||||
|
||||
pxformat.Set(dsc);
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
94
include/framework/picture/pict_convolution.cpp
Normal file
94
include/framework/picture/pict_convolution.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "picture/pict.h"
|
||||
#include "color/color.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Picture::ApplyConvolution(uint k_width, uint k_height, const int *p_w, int weight, int pass, const Rect <int> *clip_rect)
|
||||
{
|
||||
if (GetBpp() != 32)
|
||||
__ERR__(__LOG_E__ << "Convolution filter only supported on 32bpp picture.\n", false);
|
||||
if (!k_width || !k_height)
|
||||
__ERR__(__LOG_E__ << "Invalid kernel size (" << k_width << "x" << k_height << ").\n", false);
|
||||
|
||||
if (pass <= 0)
|
||||
return true;
|
||||
|
||||
// Clipping rect.
|
||||
Rect <int> rect = GetRect();
|
||||
if (!clip_rect)
|
||||
clip_rect = ▭
|
||||
|
||||
// Setup flip chain.
|
||||
Picture tmp(*this), *src, *dst;
|
||||
|
||||
if (pass & 1)
|
||||
{ src = &tmp; dst = this; }
|
||||
else { src = this; dst = &tmp; }
|
||||
|
||||
// Perform convolution.
|
||||
for (int p = 0; p < pass; ++p)
|
||||
{
|
||||
uchar *pdata = dst->GetDataOffset(clip_rect->sx, clip_rect->sy);
|
||||
|
||||
for (int y = 0; y < clip_rect->GetHeight(); ++y)
|
||||
{
|
||||
uchar *pscan = pdata;
|
||||
|
||||
for (int x = 0; x < rect.GetWidth(); ++x)
|
||||
{
|
||||
int sx = x - k_width / 2,
|
||||
sy = y - k_height / 2;
|
||||
|
||||
int k_sx = Types::Max <int> (sx, clip_rect->sx),
|
||||
k_sy = Types::Max <int> (sy, clip_rect->sy);
|
||||
int k_ex = Types::Min <int> (k_width + x - k_width / 2, clip_rect->ex),
|
||||
k_ey = Types::Min <int> (k_height + y - k_height / 2, clip_rect->ey);
|
||||
|
||||
const int *w = p_w + Types::Max(0, clip_rect->sx - sx)
|
||||
+ Types::Max(0, clip_rect->sy - sy) * k_width;
|
||||
|
||||
int k = 0;
|
||||
int accu[4] = { 0, 0, 0, 0 };
|
||||
for (int ky = k_sy; ky < k_ey; ++ky)
|
||||
{
|
||||
const int *sw = w;
|
||||
|
||||
for (int kx = k_sx; kx < k_ex; ++kx)
|
||||
{
|
||||
uchar *psrc = src->GetDataOffset(kx, ky);
|
||||
|
||||
accu[0] += psrc[0] * *sw;
|
||||
accu[1] += psrc[1] * *sw;
|
||||
accu[2] += psrc[2] * *sw;
|
||||
accu[3] += psrc[3] * *sw;
|
||||
|
||||
k += *sw++;
|
||||
}
|
||||
w += k_width;
|
||||
}
|
||||
|
||||
k = k ? (weight << 6) / k : (weight << 6);
|
||||
pscan[0] = (uchar)Types::Clamp((accu[0] * k) >> 14, 0, 255);
|
||||
pscan[1] = (uchar)Types::Clamp((accu[1] * k) >> 14, 0, 255);
|
||||
pscan[2] = (uchar)Types::Clamp((accu[2] * k) >> 14, 0, 255);
|
||||
pscan[3] = (uchar)Types::Clamp((accu[3] * k) >> 14, 0, 255);
|
||||
|
||||
pscan += 4;
|
||||
}
|
||||
pdata += dst->GetPitch();
|
||||
}
|
||||
|
||||
Picture *swp = dst; dst = src; src = swp;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
25
include/framework/picture/pict_draw.cpp
Normal file
25
include/framework/picture/pict_draw.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "picture/pict.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uchar Picture::AlphaCompositeAlpha(uchar a, uchar b)
|
||||
{ return (uchar)Types::Clamp <int> (a + b - ((a * b) >> 8), 0, 255); }
|
||||
uchar Picture::AlphaCompositeColor(uchar u, uchar v, uchar a, uchar b, uchar k)
|
||||
{ return (uchar)Types::Clamp <int> (k ? (u * a + v * b - ((u * b * a) >> 8)) / k : 0, 0, 255); }
|
||||
void Picture::AlphaCompositePixel(uchar *data, uchar r, uchar g, uchar b, uchar a)
|
||||
{
|
||||
uchar a_blend = AlphaCompositeAlpha(data[3], a);
|
||||
data[0] = AlphaCompositeColor(data[0], r, data[3], a, a_blend);
|
||||
data[1] = AlphaCompositeColor(data[1], g, data[3], a, a_blend);
|
||||
data[2] = AlphaCompositeColor(data[2], b, data[3], a, a_blend);
|
||||
data[3] = a_blend;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
166
include/framework/picture/pict_draw_line.cpp
Normal file
166
include/framework/picture/pict_draw_line.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "picture/pict.h"
|
||||
#include "math/nmath.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Picture::LowLevelDrawLine(bool hq, float sx, float sy, float ex, float ey, float r, float g, float b, float a, const Rect <float> *clip_rect)
|
||||
{
|
||||
// Output validity.
|
||||
if (!data || (pxformat.GetBpp() != 32) || pxformat.IsReal())
|
||||
return;
|
||||
|
||||
// Clip primitive.
|
||||
float dx = ex - sx, dy = ey - sy;
|
||||
|
||||
// Sub pixel correction.
|
||||
if (Types::Abs(dy) > Types::Abs(dx))
|
||||
{
|
||||
float fsy = Math::Floor(sy);
|
||||
if (dy)
|
||||
sx -= dx * (sy - fsy) / dy; // Sub-pixel correction.
|
||||
sy = fsy;
|
||||
}
|
||||
else
|
||||
{
|
||||
float fsx = Math::Floor(sx);
|
||||
if (dx)
|
||||
sy -= dy * (sx - fsx) / dx; // Sub-pixel correction.
|
||||
sx = fsx;
|
||||
}
|
||||
|
||||
// Clipping.
|
||||
if (clip_rect)
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
#define __SwapFloat(A, B) { float swp = A; A = B; B = swp; }
|
||||
//---------------------------------------------------------------
|
||||
|
||||
if (dx)
|
||||
{
|
||||
// Flip line if it is going backward.
|
||||
if (dx < 0)
|
||||
{
|
||||
__SwapFloat(sx, ex)
|
||||
__SwapFloat(sy, ey)
|
||||
dx = ex - sx; dy = ey - sy;
|
||||
}
|
||||
float idx = 1 / dx;
|
||||
|
||||
// Clip on X axis.
|
||||
if (ex < clip_rect->sx)
|
||||
return;
|
||||
|
||||
float kee = (clip_rect->ex - sx) * idx;
|
||||
if (kee < 1)
|
||||
{
|
||||
ex = clip_rect->ex;
|
||||
ey = dy * kee + sy;
|
||||
}
|
||||
|
||||
if (sx > clip_rect->ex)
|
||||
return;
|
||||
|
||||
float kss = (clip_rect->sx - sx) * idx;
|
||||
if (kss > 0)
|
||||
{
|
||||
sx = clip_rect->sx;
|
||||
sy += dy * kss;
|
||||
}
|
||||
dx = ex - sx; dy = ey - sy;
|
||||
}
|
||||
else
|
||||
if ((sx < clip_rect->sx) || (sx > clip_rect->ex))
|
||||
return;
|
||||
|
||||
if (dy)
|
||||
{
|
||||
// Flip line if it is going backward.
|
||||
if (dy < 0)
|
||||
{
|
||||
__SwapFloat(sx, ex)
|
||||
__SwapFloat(sy, ey)
|
||||
dx = ex - sx; dy = ey - sy;
|
||||
}
|
||||
float idy = 1 / dy;
|
||||
|
||||
// Clip on Y axis.
|
||||
if (ey < clip_rect->sy)
|
||||
return;
|
||||
|
||||
float kee = (clip_rect->ey - sy) * idy;
|
||||
if (kee < 1)
|
||||
{
|
||||
ey = clip_rect->ey;
|
||||
ex = dx * kee + sx;
|
||||
}
|
||||
|
||||
if (sy > clip_rect->ey)
|
||||
return;
|
||||
|
||||
float kss = (clip_rect->sy - sy) * idy;
|
||||
if (kss > 0)
|
||||
{
|
||||
sy = clip_rect->sy;
|
||||
sx += dx * kss;
|
||||
}
|
||||
dx = ex - sx; dy = ey - sy;
|
||||
}
|
||||
else
|
||||
if ((sy < clip_rect->sy) || (sy > clip_rect->ey))
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw line.
|
||||
if (Types::Abs(dy) > Types::Abs(dx))
|
||||
{
|
||||
if (dy < 0)
|
||||
{
|
||||
dy = -dy; dx = -dx;
|
||||
float swp = ey;
|
||||
ey = sy; sy = swp; sx = ex;
|
||||
}
|
||||
|
||||
float slope = dy ? dx / dy : 0.f;
|
||||
for (; sy < ey; sy += 1.f)
|
||||
{
|
||||
if (hq)
|
||||
DrawPlotHQ(sx, sy, r, g, b, a);
|
||||
else DrawPlot(sx, sy, r, g, b, a);
|
||||
sx += slope;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dx < 0)
|
||||
{
|
||||
dx = -dx; dy = -dy;
|
||||
float swp = ex;
|
||||
ex = sx; sx = swp; sy = ey;
|
||||
}
|
||||
|
||||
float slope = dx ? dy / dx : 0.f;
|
||||
for (; sx < ex; sx += 1.f)
|
||||
{
|
||||
if (hq)
|
||||
DrawPlotHQ(sx, sy, r, g, b, a);
|
||||
else DrawPlot(sx, sy, r, g, b, a);
|
||||
sy += slope;
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Picture::DrawLine(float sx, float sy, float ex, float ey, float r, float g, float b, float a, const Rect <float> *clip_rect)
|
||||
{ LowLevelDrawLine(false, sx, sy, ex, ey, r, g, b, a, clip_rect); }
|
||||
void Picture::DrawLineHQ(float sx, float sy, float ex, float ey, float r, float g, float b, float a, const Rect <float> *clip_rect)
|
||||
{ LowLevelDrawLine(true, sx, sy, ex, ey, r, g, b, a, clip_rect); }
|
||||
//------------------------------------------------------------------------------
|
||||
60
include/framework/picture/pict_draw_plot.cpp
Normal file
60
include/framework/picture/pict_draw_plot.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "picture/pict.h"
|
||||
#include "math/nmath.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Picture::DrawPlot(float x, float y, float r, float g, float b, float a, const Rect <float> *clip_rect)
|
||||
{
|
||||
// Output validity.
|
||||
if (!data || (pxformat.GetBpp() != 32) || pxformat.IsReal())
|
||||
return;
|
||||
|
||||
// Clip primitive.
|
||||
if (clip_rect && ((x < clip_rect->sx) || (x >= clip_rect->ex) || (y < clip_rect->sy) || (y >= clip_rect->ey)))
|
||||
return;
|
||||
|
||||
// Draw.
|
||||
AlphaCompositePixel(GetDataOffset((uint)x, (uint)y), uchar(r * 255.f), uchar(g * 255.f), uchar(b * 255.f), uchar(a * 255.f));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Picture::DrawPlotHQ(float x, float y, float r, float g, float b, float a, const Rect <float> *clip_rect)
|
||||
{
|
||||
// Output validity.
|
||||
if (!data || (pxformat.GetBpp() != 32) || pxformat.IsReal())
|
||||
return;
|
||||
|
||||
// Clip primitive.
|
||||
if (clip_rect && ((x < clip_rect->sx) || (x >= (clip_rect->ex - 1)) || (y < clip_rect->sy) || (y >= (clip_rect->ey - 1))))
|
||||
return;
|
||||
|
||||
// Draw.
|
||||
uchar ir = uchar(r * 255.f),
|
||||
ig = uchar(g * 255.f),
|
||||
ib = uchar(b * 255.f),
|
||||
ia = uchar(a * 255.f);
|
||||
|
||||
float xm = Math::Floor(x),
|
||||
ym = Math::Floor(y);
|
||||
|
||||
float a0 = (xm + 1 - x) * (ym + 1 - y),
|
||||
a1 = (x - xm) * (ym + 1 - y),
|
||||
a2 = (xm + 1 - x) * (y - ym),
|
||||
a3 = (x - xm) * (y - ym);
|
||||
|
||||
uchar *output = GetDataOffset((uint)x, (uint)y);
|
||||
AlphaCompositePixel(output, ir, ig, ib, uchar(ia * a0));
|
||||
AlphaCompositePixel(output + 4, ir, ig, ib, uchar(ia * a1));
|
||||
AlphaCompositePixel(output + width * 4, ir, ig, ib, uchar(ia * a2));
|
||||
AlphaCompositePixel(output + (width + 1) * 4, ir, ig, ib, uchar(ia * a3));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
159
include/framework/picture/pict_draw_polygon.cpp
Normal file
159
include/framework/picture/pict_draw_polygon.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "picture/pict.h"
|
||||
#include "math/nmath.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
static bool ClipValueTestLess(float v, float c)
|
||||
{ return v < c; }
|
||||
static bool ClipValueTestGreater(float v, float c)
|
||||
{ return v >= c; }
|
||||
//-------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static uint ClipPolygonAxis(float clip, uint axis, bool (*ClipValueTest)(float v, float c), uint count_in, Point <float> *p_in, Point <float> *p_out)
|
||||
{
|
||||
uint p_current = 0, count_out = 0;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
#define __ClipSegment\
|
||||
{\
|
||||
float k = (clip - p_in[p_current][axis]) / (p_in[p_next][axis] - p_in[p_current][axis]);\
|
||||
if (!axis)\
|
||||
p_out[count_out++].Set (clip, (p_in[p_next].y - p_in[p_current].y) * k + p_in[p_current].y);\
|
||||
else p_out[count_out++].Set ((p_in[p_next].x - p_in[p_current].x) * k + p_in[p_current].x, clip);\
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
while (p_current < count_in)
|
||||
{
|
||||
uint p_next = p_current + 1;
|
||||
if (p_next == count_in)
|
||||
p_next = 0;
|
||||
|
||||
if (ClipValueTest(p_in[p_current][axis], clip)) // Inside.
|
||||
{
|
||||
p_out[count_out++] = p_in[p_current];
|
||||
if (!ClipValueTest(p_in[p_next][axis], clip))
|
||||
__ClipSegment
|
||||
}
|
||||
else // Outside.
|
||||
{
|
||||
if (ClipValueTest(p_in[p_next][axis], clip))
|
||||
__ClipSegment
|
||||
}
|
||||
p_current++;
|
||||
}
|
||||
return count_out;
|
||||
}
|
||||
void Picture::DrawPolygon(uint point_count, Point <float> *point, float r, float g, float b, float a, const Rect <float> *clip_rect)
|
||||
{
|
||||
// Output validity.
|
||||
if (!data || (pxformat.GetBpp() != 32) || pxformat.IsReal())
|
||||
return;
|
||||
|
||||
// Clip primitive.
|
||||
Point <float> *_point = point;
|
||||
|
||||
if (clip_rect)
|
||||
{
|
||||
_point = new Point <float> [128];
|
||||
if (!_point)
|
||||
__ERRRAW__(__LOG_E__ << "failed to allocate polygon clipping array.\n")
|
||||
|
||||
// Old boring clipping code...
|
||||
Point <float> *_point_ = _point + 64;
|
||||
point_count = ClipPolygonAxis(clip_rect->sx, 0, ClipValueTestGreater, point_count, point, _point_);
|
||||
point_count = ClipPolygonAxis(clip_rect->ex, 0, ClipValueTestLess, point_count, _point_, _point);
|
||||
point_count = ClipPolygonAxis(clip_rect->sy, 1, ClipValueTestGreater, point_count, _point, _point_);
|
||||
point_count = ClipPolygonAxis(clip_rect->ey, 1, ClipValueTestLess, point_count, _point_, _point);
|
||||
|
||||
if (point_count < 3)
|
||||
{
|
||||
_safe_delete_array(_point);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine entry vertex.
|
||||
float y_scan = _point[0].y,
|
||||
y_max = _point[0].y;
|
||||
int p_int = 0,
|
||||
p_ext = 0;
|
||||
|
||||
for (uint n = 1; n < point_count; ++n)
|
||||
{
|
||||
if (_point[n].y < y_scan)
|
||||
{
|
||||
y_scan = _point[n].y;
|
||||
p_int = p_ext = n;
|
||||
}
|
||||
if (_point[n].y > y_max)
|
||||
y_max = _point[n].y;
|
||||
}
|
||||
|
||||
// Render scanline.
|
||||
float d_int = 0,
|
||||
d_ext = 0;
|
||||
float x_int = _point[p_int].x,
|
||||
x_ext = _point[p_int].x;
|
||||
|
||||
y_scan = Math::Ceil(y_scan);
|
||||
while (y_scan < y_max)
|
||||
{
|
||||
// Update interior pointer.
|
||||
while (y_scan >= _point[p_int].y)
|
||||
{
|
||||
uint p_next = p_int - 1;
|
||||
if (p_next == -1)
|
||||
p_next = point_count - 1;
|
||||
|
||||
// Update delta.
|
||||
d_int = (_point[p_next].x - _point[p_int].x) / (_point[p_next].y - _point[p_int].y);
|
||||
x_int = d_int * (y_scan - _point[p_int].y) + _point[p_int].x;
|
||||
p_int = p_next;
|
||||
}
|
||||
|
||||
// Update exterior pointer.
|
||||
while (y_scan >= _point[p_ext].y)
|
||||
{
|
||||
uint p_next = p_ext + 1;
|
||||
if (p_next == point_count)
|
||||
p_next = 0;
|
||||
|
||||
// Update delta.
|
||||
d_ext = (_point[p_next].x - _point[p_ext].x) / (_point[p_next].y - _point[p_ext].y);
|
||||
x_ext = d_ext * (y_scan - _point[p_ext].y) + _point[p_ext].x;
|
||||
p_ext = p_next;
|
||||
}
|
||||
|
||||
// Draw scanline.
|
||||
{
|
||||
float sx, ex;
|
||||
if (x_int > x_ext)
|
||||
{ sx = x_ext; ex = x_int; }
|
||||
else { sx = x_int; ex = x_ext; }
|
||||
|
||||
for (int x = int(sx); x < int(ex); ++x)
|
||||
DrawPlot((float)x, y_scan, r, g, b, a);
|
||||
}
|
||||
|
||||
// Step scanline boundaries.
|
||||
y_scan += 1;
|
||||
x_int += d_int;
|
||||
x_ext += d_ext;
|
||||
}
|
||||
|
||||
// Release clipping point array.
|
||||
if (clip_rect)
|
||||
_safe_delete_array(_point);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
105
include/framework/picture/pict_fft.cpp
Normal file
105
include/framework/picture/pict_fft.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include "picture/pict.h"
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FFT(int size, bool inverse, float *inReal, float *inIm, float *outReal, float *outIm)
|
||||
{
|
||||
// Calculate m = log_2(n).
|
||||
int m = 0, p = 1;
|
||||
for (; p < size; ++m)
|
||||
p *= 2;
|
||||
|
||||
// Bit reversal.
|
||||
outReal[size - 1] = inReal[size - 1];
|
||||
outIm[size - 1] = inIm[size - 1];
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; i < size - 1; ++i)
|
||||
{
|
||||
outReal[i] = inReal[j];
|
||||
outIm[i] = inIm[j];
|
||||
|
||||
int k = size / 2;
|
||||
while (k <= j)
|
||||
{
|
||||
j -= k;
|
||||
k /= 2;
|
||||
}
|
||||
|
||||
j += k;
|
||||
}
|
||||
|
||||
// Calculate the FFT.
|
||||
float ca = -1.0, sa = 0.0;
|
||||
int l1 = 1, l2 = 1;
|
||||
|
||||
for (int l = 0; l < m; ++l)
|
||||
{
|
||||
l1 = l2;
|
||||
l2 *= 2;
|
||||
|
||||
float u1 = 1.0, u2 = 0.0;
|
||||
|
||||
for(int j = 0; j < l1; j++)
|
||||
{
|
||||
for(int i = j; i < size; i += l2)
|
||||
{
|
||||
int i1 = i + l1;
|
||||
|
||||
float t1 = u1 * outReal[i1] - u2 * outIm[i1],
|
||||
t2 = u1 * outIm[i1] + u2 * outReal[i1];
|
||||
|
||||
outReal[i1] = outReal[i] - t1;
|
||||
outIm[i1] = outIm[i] - t2;
|
||||
outReal[i] += t1;
|
||||
outIm[i] += t2;
|
||||
}
|
||||
|
||||
double z = u1 * ca - u2 * sa;
|
||||
u2 = u1 * sa + u2 * ca;
|
||||
u1 = (float)z;
|
||||
}
|
||||
|
||||
sa = (float)sqrt((1.f - ca) / 2.f);
|
||||
if (!inverse)
|
||||
sa = -sa;
|
||||
ca = (float)sqrt((1.f + ca) / 2.f);
|
||||
}
|
||||
|
||||
// Divide through n if it isn't the IDFT.
|
||||
if (!inverse)
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
outReal[i] /= size;
|
||||
outIm[i] /= size;
|
||||
}
|
||||
}
|
||||
|
||||
void testFFT()
|
||||
{
|
||||
float inR[8], inI[8], outR[8], outI[8];
|
||||
|
||||
for (int n = 0; n < 8; ++n)
|
||||
{
|
||||
inR[n] = 5;
|
||||
inI[n] = 2;
|
||||
}
|
||||
|
||||
FFT(8, false, inR, inI, outR, outI);
|
||||
|
||||
for (int n = 0; n < 8; ++n)
|
||||
{
|
||||
inR[n] = 0;
|
||||
inI[n] = 0;
|
||||
}
|
||||
|
||||
FFT(8, true, outR, outI, inR, inI);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
184
include/framework/picture/pict_gradient.cpp
Normal file
184
include/framework/picture/pict_gradient.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "picture/pict_gradient.h"
|
||||
#include "picture/pict.h"
|
||||
#include "metafile/nml.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static uchar ClampChannel(int v)
|
||||
{
|
||||
if (v < 0)
|
||||
return 0;
|
||||
if (v > 255)
|
||||
return 255;
|
||||
return (uchar)v;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Picture::DrawGradient(const Gradient &gradient, const Rect <int> *clip_rect)
|
||||
{
|
||||
if (!gradient.GetControlPointCount())
|
||||
return;
|
||||
|
||||
Rect <int> rect = GetRect();
|
||||
if (!clip_rect)
|
||||
clip_rect = ▭
|
||||
|
||||
uint current_control_point = 0,
|
||||
next_control_point = 1;
|
||||
if (next_control_point == gradient.GetControlPointCount())
|
||||
next_control_point = current_control_point;
|
||||
uchar *pdata = GetDataOffset(clip_rect->sx, clip_rect->sy);
|
||||
|
||||
for (int y = 0; y < clip_rect->GetHeight(); ++y)
|
||||
{
|
||||
float c_k = (float)y / clip_rect->GetHeight();
|
||||
|
||||
// Check gradient interval change.
|
||||
if ((c_k > gradient.k[next_control_point]) && (current_control_point + 1 < gradient.GetControlPointCount()))
|
||||
{
|
||||
current_control_point++;
|
||||
next_control_point++;
|
||||
if (next_control_point == gradient.GetControlPointCount())
|
||||
next_control_point = current_control_point;
|
||||
}
|
||||
|
||||
// Blend.
|
||||
Color blend_color = gradient.color[current_control_point];
|
||||
|
||||
if (current_control_point != next_control_point)
|
||||
blend_color = (gradient.color[next_control_point] - gradient.color[current_control_point]) *
|
||||
(c_k - gradient.k[current_control_point]) / (gradient.k[next_control_point] - gradient.k[current_control_point]) +
|
||||
gradient.color[current_control_point];
|
||||
|
||||
uchar *pscan = pdata,
|
||||
r = (uchar)(blend_color.x * 255),
|
||||
g = (uchar)(blend_color.y * 255),
|
||||
b = (uchar)(blend_color.z * 255),
|
||||
a = (uchar)(blend_color.w * 255);
|
||||
|
||||
switch (gradient.GetOperator())
|
||||
{
|
||||
case Picture::BlendReplace:
|
||||
for (int x = 0; x < rect.GetWidth(); ++x)
|
||||
{
|
||||
pscan[0] = r;
|
||||
pscan[1] = g;
|
||||
pscan[2] = b;
|
||||
pscan[3] = a;
|
||||
pscan += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case Picture::BlendCompose:
|
||||
for (int x = 0; x < rect.GetWidth(); ++x)
|
||||
{
|
||||
uchar a_blend = AlphaCompositeAlpha(pscan[3], a);
|
||||
pscan[0] = AlphaCompositeColor(pscan[0], r, pscan[3], a, a_blend);
|
||||
pscan[1] = AlphaCompositeColor(pscan[1], g, pscan[3], a, a_blend);
|
||||
pscan[2] = AlphaCompositeColor(pscan[2], b, pscan[3], a, a_blend);
|
||||
pscan[3] = a_blend;
|
||||
pscan += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case Picture::BlendMultiply:
|
||||
for (int x = 0; x < rect.GetWidth(); ++x)
|
||||
{
|
||||
pscan[0] = (pscan[0] * r) >> 8;
|
||||
pscan[1] = (pscan[1] * g) >> 8;
|
||||
pscan[2] = (pscan[2] * b) >> 8;
|
||||
pscan[3] = (pscan[3] * a) >> 8;
|
||||
pscan += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case Picture::BlendMultiply2x:
|
||||
for (int x = 0; x < rect.GetWidth(); ++x)
|
||||
{
|
||||
pscan[0] = ClampChannel((pscan[0] * r) >> 7);
|
||||
pscan[1] = ClampChannel((pscan[1] * g) >> 7);
|
||||
pscan[2] = ClampChannel((pscan[2] * b) >> 7);
|
||||
pscan[3] = (pscan[3] * a) >> 8;
|
||||
pscan += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case Picture::BlendAdd:
|
||||
for (int x = 0; x < rect.GetWidth(); ++x)
|
||||
{
|
||||
pscan[0] = ClampChannel(pscan[0] + r);
|
||||
pscan[1] = ClampChannel(pscan[1] + g);
|
||||
pscan[2] = ClampChannel(pscan[2] + b);
|
||||
pscan[3] = (pscan[3] * a) >> 8;
|
||||
pscan += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
pdata += GetPitch();
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Gradient::FromMetaTag(NML::Tag *tag)
|
||||
{
|
||||
control_point_count = 0;
|
||||
op = Picture::BlendMultiply;
|
||||
|
||||
NMLTagForeach(ctag, *tag)
|
||||
{
|
||||
if (ctag->name == "Operator")
|
||||
{
|
||||
String op_string(ctag->GetString());
|
||||
|
||||
if (op_string == "Replace")
|
||||
op = Picture::BlendReplace;
|
||||
else if (op_string == "Multiply")
|
||||
op = Picture::BlendMultiply;
|
||||
else if (op_string == "Multiply2x")
|
||||
op = Picture::BlendMultiply2x;
|
||||
else if (op_string == "Add")
|
||||
op = Picture::BlendAdd;
|
||||
else if (op_string == "Compose")
|
||||
op = Picture::BlendCompose;
|
||||
else __LOG_W__ << "Unknown gradient operator.\n";
|
||||
}
|
||||
else if (ctag->name == "Control")
|
||||
{
|
||||
// Control point count safety.
|
||||
if (control_point_count == 8)
|
||||
__ERR__(__LOG_E__ << "Too many control points in gradient definition.\n", false);
|
||||
|
||||
// Coordinate.
|
||||
NML::Tag *attr_tag = ctag->GetTypedTag("K", Variant::VariantFloat);
|
||||
if (!attr_tag)
|
||||
__ERR__(__LOG_E__ << "Missing tag (control point coordinate) in gradient definition.\n", false);
|
||||
k[control_point_count] = attr_tag->GetReal();
|
||||
|
||||
// Color.
|
||||
attr_tag = ctag->GetTypedTag("Color", Variant::VariantNone);
|
||||
if (!attr_tag)
|
||||
__ERR__(__LOG_E__ << "Missing tag (control point color) in gradient definition.\n", false);
|
||||
color[control_point_count].Set();
|
||||
if (!color[control_point_count].FromMetaTag(*attr_tag))
|
||||
__ERR__(__LOG_E__ << "Erroneous control point color in gradient definition.\n", false);
|
||||
|
||||
control_point_count++;
|
||||
}
|
||||
else __ERR__(__LOG_E__ << "Unexpected tag in gradient definition.\n", false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
70
include/framework/picture/pict_io.cpp
Normal file
70
include/framework/picture/pict_io.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "picture/pict_io.h"
|
||||
#include "picture/pict.h"
|
||||
#include "filesystem/io_handle.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "memory/nauto_ptr.h"
|
||||
#include "platform.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::IO;
|
||||
|
||||
template<> PictureIO *Singleton <PictureIO> ::i = NULL;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
PictureCodec *PictureIO::Codec(const char *codec_name)
|
||||
{
|
||||
ListForeachPtr(PictureCodec *, codec, codec_list)
|
||||
if (GS::String(codec->GetName()) == GS::String(codec_name))
|
||||
return codec;
|
||||
return NULL;
|
||||
}
|
||||
bool PictureIO::RegisterCodec(PictureCodec *codec, bool verbose)
|
||||
{
|
||||
if (Codec(codec->GetName()))
|
||||
return false;
|
||||
codec_list.Add(codec);
|
||||
if (verbose)
|
||||
__LOG__ << "Codec '" << codec->GetName() << "' registered successfully.\n";
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool PictureIO::Save(const Picture &picture, const char *uri, const char *codec_name)
|
||||
{
|
||||
if (PictureCodec *c = Codec(codec_name))
|
||||
{
|
||||
AutoPtr <Handle> h(Platform::Get().io->Open(uri, ModeWrite));
|
||||
if (h.IsNull())
|
||||
return false;
|
||||
|
||||
if (!c->Save(*h, picture))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool PictureIO::Load(Picture &picture, const char *uri)
|
||||
{
|
||||
AutoPtr <Handle> h(Platform::Get().io->Open(uri));
|
||||
if (h.IsNull())
|
||||
return false;
|
||||
|
||||
picture.name = uri;
|
||||
ListForeachPtr(PictureCodec *, codec, codec_list)
|
||||
if (codec->Load(*h, picture))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
183
include/framework/picture/pict_sampling.cpp
Normal file
183
include/framework/picture/pict_sampling.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "picture/pict.h"
|
||||
#include "color/color.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Picture::Sample(float u, float v, Color &out, uint _w, uint _h) const
|
||||
{
|
||||
if (!GetData())
|
||||
{
|
||||
out.Set(1, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetPixelFormat().IsReal())
|
||||
{
|
||||
uint _out;
|
||||
Sample(u, v, _out, _w, _h);
|
||||
out.FromInteger(_out);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_w) _w = GetWidth();
|
||||
if (!_h) _h = GetHeight();
|
||||
u *= _w; v *= _h;
|
||||
|
||||
if (u < 0) u = 0;
|
||||
if (v < 0) v = 0;
|
||||
if (u >= _w) u = (float)(_w - 1);
|
||||
if (v >= _h) v = (float)(_h - 1);
|
||||
|
||||
uint iu = (uint)u, iv = (uint)v;
|
||||
|
||||
Color sample[4];
|
||||
|
||||
float *pdata = (float *)GetData();
|
||||
pdata += (iu + iv * _w) * 3;
|
||||
|
||||
//---------------------------------------
|
||||
#define EXTRACT_FSAMPLE(_S_, _P_) \
|
||||
{ \
|
||||
(_S_).z = (_P_)[2]; \
|
||||
(_S_).y = (_P_)[1]; \
|
||||
(_S_).x = (_P_)[0]; \
|
||||
}
|
||||
//---------------------------------------
|
||||
|
||||
EXTRACT_FSAMPLE(sample[0], pdata + 0);
|
||||
if (iu < (_w - 1))
|
||||
EXTRACT_FSAMPLE(sample[1], pdata + 3)
|
||||
else sample[1] = sample[0];
|
||||
if (iv < (_h - 1))
|
||||
EXTRACT_FSAMPLE(sample[2], pdata + _w * 3)
|
||||
else sample[2] = sample[0];
|
||||
if ((iu < (_w - 1)) && (iv < (_h - 1)))
|
||||
EXTRACT_FSAMPLE(sample[3], pdata + (_w + 1) * 3)
|
||||
else sample[3] = sample[0];
|
||||
|
||||
// Bilinear sample.
|
||||
float k[4], uf = u - (float)iu, vf = v - (float)iv;
|
||||
|
||||
k[0] = (1.f - uf) * (1.f - vf);
|
||||
k[1] = uf * (1.f - vf);
|
||||
k[2] = (1.f - uf) * vf;
|
||||
k[3] = uf * vf;
|
||||
|
||||
out = sample[0] * k[0] + sample[1] * k[1] + sample[2] * k[2] + sample[3] * k[3];
|
||||
out.w = sample[0].w * k[0] + sample[1].w * k[1] + sample[2].w * k[2] + sample[3].w * k[3];
|
||||
}
|
||||
}
|
||||
void Picture::Sample(float u, float v, uint &out, uint _w, uint _h) const
|
||||
{
|
||||
if (!GetData())
|
||||
{
|
||||
out = 0xffff00ff;
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPixelFormat().IsReal())
|
||||
{
|
||||
Color _out;
|
||||
Sample(u, v, _out, _w, _h);
|
||||
out = _out.AsInteger();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_w) _w = GetWidth();
|
||||
if (!_h) _h = GetHeight();
|
||||
u *= _w; v *= _h;
|
||||
|
||||
if (u < 0) u = 0;
|
||||
if (v < 0) v = 0;
|
||||
if (u >= _w) u = (float)(_w - 1);
|
||||
if (v >= _h) v = (float)(_h - 1);
|
||||
|
||||
uint iu = (uint)u, iv = (uint)v;
|
||||
|
||||
struct iVector
|
||||
{
|
||||
int x, y, z, w;
|
||||
|
||||
iVector operator + (const iVector &b) const
|
||||
{ return iVector(x + b.x, y + b.y, z + b.z, w + b.w); }
|
||||
iVector operator * (const int v) const
|
||||
{ return iVector(x * v, y * v, z * v, w * v); }
|
||||
iVector operator >> (const int v) const
|
||||
{ return iVector(x >> v, y >> v, z >> v, w >> v); }
|
||||
|
||||
iVector(int _x, int _y, int _z, int _w = 255)
|
||||
{ x = _x; y = _y; z = _z; w = _w; }
|
||||
iVector()
|
||||
{}
|
||||
};
|
||||
iVector sample[4];
|
||||
|
||||
uint *pdata = (uint *)GetData();
|
||||
pdata += iu + iv * _w;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
#define EXTRACT_SAMPLE(_S_, _P_) \
|
||||
{ \
|
||||
const uchar *_t_p = (const uchar *)&(_P_); \
|
||||
(_S_).x = _t_p[0]; \
|
||||
(_S_).y = _t_p[1]; \
|
||||
(_S_).z = _t_p[2]; \
|
||||
(_S_).w = _t_p[3]; \
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
EXTRACT_SAMPLE(sample[0], pdata[0]);
|
||||
if (iu < (_w - 1))
|
||||
EXTRACT_SAMPLE(sample[1], pdata[1])
|
||||
else sample[1] = sample[0];
|
||||
if (iv < (_h - 1))
|
||||
EXTRACT_SAMPLE(sample[2], pdata[_w])
|
||||
else sample[2] = sample[0];
|
||||
if ((iu < (_w - 1)) && (iv < (_h - 1)))
|
||||
EXTRACT_SAMPLE(sample[3], pdata[_w + 1])
|
||||
else sample[3] = sample[0];
|
||||
|
||||
int k[4], uf = int((u - (float)iu) * 256), vf = int((v - (float)iv) * 256);
|
||||
|
||||
k[0] = (256 - uf) * (256 - vf); // 16bit fixed point.
|
||||
k[1] = uf * (256 - vf);
|
||||
k[2] = (256 - uf) * vf;
|
||||
k[3] = uf * vf;
|
||||
|
||||
iVector r = (sample[0] * k[0] + sample[1] * k[1] + sample[2] * k[2] + sample[3] * k[3]) >> 16;
|
||||
|
||||
uchar *_out = (uchar *)&out;
|
||||
_out[0] = (uchar)r.x;
|
||||
_out[1] = (uchar)r.y;
|
||||
_out[2] = (uchar)r.z;
|
||||
_out[3] = (uchar)r.w;
|
||||
}
|
||||
}
|
||||
void Picture::SampleRGBA(float u, float v, Color &o, uint _w, uint _h) const
|
||||
{
|
||||
Color s;
|
||||
Sample(u, v, s, _w, _h);
|
||||
|
||||
o[0] = s[pxformat.rshift >> 3];
|
||||
o[1] = s[pxformat.gshift >> 3];
|
||||
o[2] = s[pxformat.bshift >> 3];
|
||||
o[3] = s[pxformat.ashift >> 3];
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint Picture::SampleInteger(float u, float v, uint _w, uint _h) const
|
||||
{ uint s; Sample(u, v, s, _w, _h); return s; }
|
||||
Color Picture::SampleColor(float u, float v, uint _w, uint _h) const
|
||||
{ Color s; Sample(u, v, s, _w, _h); return s; }
|
||||
Color Picture::SampleRGBAColor(float u, float v, uint _w, uint _h) const
|
||||
{ Color s; SampleRGBA(u, v, s, _w, _h); return s; }
|
||||
//------------------------------------------------------------------------------
|
||||
206
include/framework/picture/pict_scaler.cpp
Normal file
206
include/framework/picture/pict_scaler.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "picture/pict.h"
|
||||
#include "color/color.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Picture::Resize(uint nwidth, uint nheight)
|
||||
{
|
||||
if (!nwidth && !nheight)
|
||||
return false;
|
||||
|
||||
if (!nwidth)
|
||||
nwidth = (GetWidth() * nheight) / GetHeight();
|
||||
if (!nheight)
|
||||
nheight = (GetHeight() * nwidth) / GetWidth();
|
||||
|
||||
if ((nwidth == GetWidth()) && (nheight == GetHeight()))
|
||||
return true;
|
||||
|
||||
if (pxformat.IsReal())
|
||||
{
|
||||
float *new_data = (float *)AllocMemory(sizeof(float) * nwidth * nheight * 3);
|
||||
if (!new_data)
|
||||
return false;
|
||||
|
||||
float *pdst = (float *)new_data;
|
||||
float ku = 1.f / (float)nwidth,
|
||||
kv = 1.f / (float)nheight;
|
||||
|
||||
Color out;
|
||||
|
||||
float v = kv * 0.5f - 0.5f / height;
|
||||
if (data)
|
||||
for (uint y = 0; y < nheight; ++y)
|
||||
{
|
||||
float u = ku * 0.5f - 0.5f / width;
|
||||
for (uint x = 0; x < nwidth; ++x)
|
||||
{
|
||||
Sample(u, v, out);
|
||||
pdst[0] = out.x;
|
||||
pdst[1] = out.y;
|
||||
pdst[2] = out.z;
|
||||
pdst += 3;
|
||||
u += ku;
|
||||
}
|
||||
v += kv;
|
||||
}
|
||||
|
||||
SetData(new_data, nwidth, nheight, PixelFormat::RGBAF, true);
|
||||
//SetData(new_data, nwidth, nheight, PixelFormat::RGBF, true);
|
||||
}
|
||||
else if (GetBpp() == 32)
|
||||
{
|
||||
uchar *new_data = (uchar *)AllocMemory(sizeof(uchar) * nwidth * nheight * 4);
|
||||
if (!new_data)
|
||||
return false;
|
||||
|
||||
uint *pdst = (uint*)new_data;
|
||||
float ku = 1.f / (float)nwidth,
|
||||
kv = 1.f / (float)nheight;
|
||||
|
||||
float v = kv * 0.5f - 0.5f / height;
|
||||
if (data)
|
||||
for (uint y = 0; y < nheight; ++y)
|
||||
{
|
||||
float u = ku * 0.5f - 0.5f / width;
|
||||
for (uint x = 0; x < nwidth; ++x)
|
||||
{
|
||||
Sample(u, v, *pdst++);
|
||||
u += ku;
|
||||
}
|
||||
v += kv;
|
||||
}
|
||||
|
||||
SetData(new_data, nwidth, nheight, GetPixelFormat().GetDesc(), true);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool Picture::Downscale(uint nwidth, uint nheight)
|
||||
{
|
||||
if (!nwidth && !nheight)
|
||||
return false;
|
||||
|
||||
if (!nwidth)
|
||||
nwidth = (GetWidth() * nheight) / GetHeight();
|
||||
if (!nheight)
|
||||
nheight = (GetHeight() * nwidth) / GetWidth();
|
||||
|
||||
if ((nwidth > GetWidth()) || (nheight > GetHeight()))
|
||||
return Resize(nwidth, nheight);
|
||||
|
||||
if (GetBpp() == 32)
|
||||
{
|
||||
uchar *new_data = (uchar *)AllocMemory(sizeof(uchar) * nwidth * nheight * 4);
|
||||
if (!new_data)
|
||||
return false;
|
||||
|
||||
uchar *pdst = new_data;
|
||||
Array <float> accu(nwidth * 4);
|
||||
|
||||
if (accu)
|
||||
{
|
||||
float ku = (float)GetWidth() / (float)nwidth,
|
||||
kv = (float)GetHeight() / (float)nheight;
|
||||
float u, v;
|
||||
|
||||
//
|
||||
v = 0.f;
|
||||
|
||||
// Accumulate scan lines.
|
||||
uchar *psrc = GetData();
|
||||
|
||||
for (uint y = 0; y < nheight; y++)
|
||||
{
|
||||
uint n;
|
||||
for (n = 0; n < (nwidth * 4); n++)
|
||||
accu[n] = 0.f;
|
||||
|
||||
float tv = kv, nv = kv;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
float k = GS::Math::Ceil(v) - v;
|
||||
tv -= k;
|
||||
if (tv < 0.f)
|
||||
k += tv; // readjust
|
||||
v += k;
|
||||
|
||||
if (v >= GetHeight())
|
||||
{
|
||||
nv -= k;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
u = 0.f;
|
||||
|
||||
// Accumulate texels.
|
||||
uchar *lsrc = psrc;
|
||||
float *paccu = accu;
|
||||
float texel[4];
|
||||
|
||||
for (uint x = 0; x < nwidth; x++)
|
||||
{
|
||||
for (n = 0; n < 4; n++)
|
||||
texel[n] = 0.f;
|
||||
|
||||
float tu = ku, nu = ku;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
float k = GS::Math::Ceil(u) - u;
|
||||
tu -= k;
|
||||
if (tu < 0.f)
|
||||
k += tu; // readjust
|
||||
u += k;
|
||||
|
||||
if (u >= GetWidth())
|
||||
{
|
||||
nu -= k;
|
||||
break;
|
||||
}
|
||||
|
||||
for (n = 0; n < 4; n++)
|
||||
texel[n] += (float)(lsrc[n]) * k;
|
||||
|
||||
if (tu < 0.f)
|
||||
break;
|
||||
|
||||
lsrc += 4;
|
||||
}
|
||||
|
||||
tu = k / nu;
|
||||
for (n = 0; n < 4; n++)
|
||||
paccu[n] += texel[n] * tu;
|
||||
paccu += 4;
|
||||
}
|
||||
if (tv < 0.f)
|
||||
break;
|
||||
|
||||
psrc += GetWidth() * 4;
|
||||
}
|
||||
|
||||
tv = 1.f / nv;
|
||||
for (n = 0; n < (nwidth * 4); n++)
|
||||
pdst[n] = (uchar)(accu[n] * tv);
|
||||
pdst += nwidth * 4;
|
||||
}
|
||||
|
||||
SetData(new_data, nwidth, nheight, GetPixelFormat().GetDesc(), true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
2644
include/framework/picture/pict_tga.cpp
Normal file
2644
include/framework/picture/pict_tga.cpp
Normal file
File diff suppressed because it is too large
Load Diff
122
include/framework/picture/pict_tools.cpp
Normal file
122
include/framework/picture/pict_tools.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "picture/pict_tools.h"
|
||||
#include "picture/pict.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
namespace GS {
|
||||
namespace PictureTools {
|
||||
|
||||
bool Compare(const Picture &a, const Picture &b, float threshold)
|
||||
{
|
||||
if ((a.GetWidth() != b.GetWidth()) || (a.GetHeight() != b.GetHeight()))
|
||||
return false;
|
||||
|
||||
float dt = 0.f;
|
||||
for (uint y = 0; y < a.GetHeight(); ++y)
|
||||
for (uint x = 0; x < a.GetWidth(); ++x)
|
||||
for (int c = 0; c < 4; ++c)
|
||||
dt += (a.GetDataOffset(x, y)[c] - b.GetDataOffset(x, y)[c]) / 255.f;
|
||||
|
||||
return asbool(dt <= threshold);
|
||||
}
|
||||
|
||||
} // PictureTools
|
||||
} // GS
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Picture::Fill(float r, float g, float b, float a, const iRect *rect, bool lock_alpha)
|
||||
{
|
||||
uint *data = (uint *)GetData();
|
||||
|
||||
if (GetBpp() != 32)
|
||||
return false;
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
// Convert color.
|
||||
uint fill = GetPixelFormat().Format(r, g, b, a);
|
||||
|
||||
uchar ur = uchar(r * 255),
|
||||
ug = uchar(g * 255),
|
||||
ub = uchar(b * 255)/*,
|
||||
ua = uchar(a * 255)*/;
|
||||
|
||||
if (rect)
|
||||
{
|
||||
Rect <int> _rect = rect->Intersection(GetRect());
|
||||
|
||||
if ((_rect.sy >= _rect.ey) || (_rect.sx >= _rect.ex))
|
||||
return false;
|
||||
|
||||
data += _rect.sx + _rect.sy * width;
|
||||
for (int y = 0; y < _rect.GetHeight(); ++y)
|
||||
{
|
||||
if (lock_alpha)
|
||||
{
|
||||
uchar *scan = (uchar *)data;
|
||||
for (int x = 0; x < _rect.GetWidth(); ++x)
|
||||
{
|
||||
scan[GetPixelFormat().rshift >> 3] = ur;
|
||||
scan[GetPixelFormat().gshift >> 3] = ug;
|
||||
scan[GetPixelFormat().bshift >> 3] = ub;
|
||||
// scan[GetPixelFormat().ashift >> 3] = ua;
|
||||
scan += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint *scan = data;
|
||||
for (int x = 0; x < _rect.GetWidth(); ++x)
|
||||
*scan++ = fill;
|
||||
}
|
||||
data += width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lock_alpha)
|
||||
{
|
||||
uchar *scan = (uchar *)data;
|
||||
for (uint n = 0; n < GetWidth() * GetHeight(); n++)
|
||||
{
|
||||
scan[GetPixelFormat().rshift >> 3] = ur;
|
||||
scan[GetPixelFormat().gshift >> 3] = ug;
|
||||
scan[GetPixelFormat().bshift >> 3] = ub;
|
||||
// scan[GetPixelFormat().ashift >> 3] = ua;
|
||||
scan += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
for (uint n = 0; n < GetWidth() * GetHeight(); n++)
|
||||
data[n] = fill;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Picture::ToGrayscale()
|
||||
{
|
||||
if (!(GetWidth() && GetHeight()))
|
||||
return false;
|
||||
if (GetBpp() != 32)
|
||||
return false;
|
||||
|
||||
uchar *ptr = GetData();
|
||||
for (uint y = 0; y < GetHeight(); y++)
|
||||
for (uint x = 0; x < GetWidth(); x++)
|
||||
{
|
||||
int v = (ptr[0] + ptr[1] + ptr[2]) / 3;
|
||||
ptr[0] = ptr[1] = ptr[2] = (uchar)v;
|
||||
ptr += 4;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
206
include/framework/picture/pict_yuv_tools.cpp
Normal file
206
include/framework/picture/pict_yuv_tools.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "picture/pict.h"
|
||||
#if __PLATFORM_WINDOWS__ && __MMX__
|
||||
#include "mmintrin.h"
|
||||
#endif
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static void mmx_yuv2rgb (uchar *py, uchar *pu, uchar *pv, uchar *image)
|
||||
{
|
||||
#if __PLATFORM_WINDOWS__ && __MMX__
|
||||
static __m64 mmx_80w = {0x0080008000800080LL};
|
||||
static __m64 mmx_U_green = {0xf37df37df37df37dLL};
|
||||
static __m64 mmx_U_blue = {0x4093409340934093LL};
|
||||
static __m64 mmx_V_red = {0x3312331233123312LL};
|
||||
static __m64 mmx_V_green = {0xe5fce5fce5fce5fcLL};
|
||||
static __m64 mmx_10w = {0x1010101010101010LL};
|
||||
static __m64 mmx_00ffw = {0x00ff00ff00ff00ffLL};
|
||||
static __m64 mmx_Y_coeff = {0x253f253f253f253fLL};
|
||||
static __m64 mmx_A_unpack = {0xffffffffffffffffLL};
|
||||
|
||||
__asm
|
||||
{
|
||||
push esi
|
||||
pxor mm4, mm4 ; mm4 = 0
|
||||
|
||||
mov esi, pu
|
||||
movd mm0, [esi] ; mm0 = 00 00 00 00 u3 u2 u1 u0
|
||||
mov esi, pv
|
||||
movd mm1, [esi] ; mm1 = 00 00 00 00 v3 v2 v1 v0
|
||||
mov esi, py
|
||||
movq mm6, [esi] ; mm6 = Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
|
||||
|
||||
; Multiply part of the conversion.
|
||||
punpcklbw mm0, mm4 ; mm0 = u3 u2 u1 u0
|
||||
punpcklbw mm1, mm4 ; mm1 = v3 v2 v1 v0
|
||||
psubsw mm0, mmx_80w ; u -= 128
|
||||
psubsw mm1, mmx_80w ; v -= 128
|
||||
psllw mm0, 3 ; promote precision
|
||||
psllw mm1, 3 ; promote precision
|
||||
movq mm2, mm0 ; mm2 = u3 u2 u1 u0
|
||||
movq mm3, mm1 ; mm3 = v3 v2 v1 v0
|
||||
pmulhw mm2, mmx_U_green ; mm2 = u * u_green
|
||||
pmulhw mm3, mmx_V_green ; mm3 = v * v_green
|
||||
pmulhw mm0, mmx_U_blue ; mm0 = chroma_b
|
||||
pmulhw mm1, mmx_V_red ; mm1 = chroma_r
|
||||
paddsw mm2, mm3 ; mm2 = chroma_g
|
||||
|
||||
psubusb mm6, mmx_10w ; Y -= 16
|
||||
movq mm7, mm6 ; mm7 = Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
|
||||
pand mm6, mmx_00ffw ; mm6 = Y6 Y4 Y2 Y0
|
||||
psrlw mm7, 8 ; mm7 = Y7 Y5 Y3 Y1
|
||||
psllw mm6, 3 ; promote precision
|
||||
psllw mm7, 3 ; promote precision
|
||||
pmulhw mm6, mmx_Y_coeff ; mm6 = luma_rgb even
|
||||
pmulhw mm7, mmx_Y_coeff ; mm7 = luma_rgb odd
|
||||
|
||||
; Addition part of the conversion for even and odd pixels.
|
||||
movq mm3, mm0 ; mm3 = chroma_b
|
||||
movq mm4, mm1 ; mm4 = chroma_r
|
||||
movq mm5, mm2 ; mm5 = chroma_g
|
||||
paddsw mm0, mm6 ; mm0 = B6 B4 B2 B0
|
||||
paddsw mm3, mm7 ; mm3 = B7 B5 B3 B1
|
||||
paddsw mm1, mm6 ; mm1 = R6 R4 R2 R0
|
||||
paddsw mm4, mm7 ; mm4 = R7 R5 R3 R1
|
||||
paddsw mm2, mm6 ; mm2 = G6 G4 G2 G0
|
||||
paddsw mm5, mm7 ; mm5 = G7 G5 G3 G1
|
||||
packuswb mm0, mm0 ; saturate to 0-255
|
||||
packuswb mm1, mm1 ; saturate to 0-255
|
||||
packuswb mm2, mm2 ; saturate to 0-255
|
||||
packuswb mm3, mm3 ; saturate to 0-255
|
||||
packuswb mm4, mm4 ; saturate to 0-255
|
||||
packuswb mm5, mm5 ; saturate to 0-255
|
||||
punpcklbw mm0, mm3 ; mm0 = B7 B6 B5 B4 B3 B2 B1 B0
|
||||
punpcklbw mm1, mm4 ; mm1 = R7 R6 R5 R4 R3 R2 R1 R0
|
||||
punpcklbw mm2, mm5 ; mm2 = G7 G6 G5 G4 G3 G2 G1 G0
|
||||
|
||||
mov esi, image
|
||||
;pxor mm3, mm3
|
||||
movq mm3, mmx_A_unpack
|
||||
movq mm6, mm0
|
||||
movq mm7, mm1
|
||||
movq mm4, mm0
|
||||
movq mm5, mm1
|
||||
punpcklbw mm6, mm2
|
||||
punpcklbw mm7, mm3
|
||||
punpcklwd mm6, mm7
|
||||
movq [esi], mm6
|
||||
movq mm6, mm0
|
||||
punpcklbw mm6, mm2
|
||||
punpckhwd mm6, mm7
|
||||
movq [esi + 8], mm6
|
||||
punpckhbw mm4, mm2
|
||||
punpckhbw mm5, mm3
|
||||
punpcklwd mm4, mm5
|
||||
movq [esi + 16], mm4
|
||||
movq mm4, mm0
|
||||
punpckhbw mm4, mm2
|
||||
punpckhwd mm4, mm5
|
||||
movq [esi + 24], mm4
|
||||
pop esi
|
||||
|
||||
emms
|
||||
}
|
||||
#endif
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Picture::YUV422toRGB32(uchar * const yuv_plane[3], uchar *rgb32, int width, int height, int dst_pitch, int dst_height)
|
||||
{
|
||||
// Default pitch if none specified.
|
||||
if (!dst_pitch)
|
||||
dst_pitch = width * 4;
|
||||
if (!dst_height)
|
||||
dst_height = height;
|
||||
|
||||
// Target resolution.
|
||||
int c_width = dst_pitch / 4;
|
||||
|
||||
if (width < c_width)
|
||||
c_width = width;
|
||||
if (height < dst_height)
|
||||
dst_height = height;
|
||||
|
||||
#pragma omp parallel for
|
||||
for (int y = 0; y < dst_height; ++y)
|
||||
{
|
||||
uchar *p_out = rgb32 + dst_pitch * y,
|
||||
*p_yuv[3] = {
|
||||
yuv_plane[0] + width * y,
|
||||
yuv_plane[1] + (width / 2) * (y / 2),
|
||||
yuv_plane[2] + (width / 2) * (y / 2)
|
||||
};
|
||||
|
||||
// Convert scan line.
|
||||
for (int x = 0; x < c_width; x += 8)
|
||||
{
|
||||
mmx_yuv2rgb(p_yuv[0], p_yuv[1], p_yuv[2], p_out);
|
||||
|
||||
p_yuv[0] += 8;
|
||||
p_yuv[1] += 4;
|
||||
p_yuv[2] += 4;
|
||||
p_out += 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
void Picture::UnpackYCbCr(uchar *y, uchar *cb, uchar *cr)
|
||||
{
|
||||
if (!y || !cb || !cr || (GetBpp() != 32))
|
||||
return;
|
||||
|
||||
uchar *pdata = GetData();
|
||||
for (uint n = 0; n < (GetHeight() * GetWidth()); ++n)
|
||||
{
|
||||
float r = (float)pdata[0], g = (float)pdata[1], b = (float)pdata[2];
|
||||
|
||||
*y++ = (uchar)( 0.2990f * r + 0.5870f * g + 0.1140f * b + 0.5f);
|
||||
*cb++ = (uchar)(-0.1687f * r - 0.3313f * g + 0.5000f * b + 128.f + 0.5f);
|
||||
*cr++ = (uchar)( 0.5000f * r - 0.4187f * g - 0.0813f * b + 128.f + 0.5f);
|
||||
pdata += 4;
|
||||
}
|
||||
}
|
||||
void Picture::PackYCbCr(uchar *y, uchar *cb, uchar *cr)
|
||||
{
|
||||
if (!y || !cb || !cr || (GetBpp() != 32))
|
||||
return;
|
||||
|
||||
uchar *pdata = GetData();
|
||||
for (uint n = 0; n < (GetHeight() * GetWidth()); ++n)
|
||||
{
|
||||
float _y = (float)*y++, _cb = ((float)*cb++) - 128.f, _cr = ((float)*cr++) - 128.f;
|
||||
|
||||
float r = _y + 1.402f * _cr;
|
||||
float g = _y - 0.34414f * _cb - 0.71414f * _cr;
|
||||
float b = _y + 1.77200f * _cb;
|
||||
|
||||
if (r < 0)
|
||||
pdata[0] = 0;
|
||||
else if (r > 255.f)
|
||||
pdata[0] = 255;
|
||||
else pdata[0] = (uchar)r;
|
||||
|
||||
if (g < 0)
|
||||
pdata[1] = 0;
|
||||
else if (g > 255.f)
|
||||
pdata[1] = 255;
|
||||
else pdata[1] = (uchar)g;
|
||||
|
||||
if (b < 0)
|
||||
pdata[2] = 0;
|
||||
else if (b > 255.f)
|
||||
pdata[2] = 255;
|
||||
else pdata[2] = (uchar)b;
|
||||
|
||||
pdata += 4;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user