commit x64 compilation from lulu cause the other branch dont seems to compile properly at home

This commit is contained in:
2026-07-17 16:08:20 +02:00
parent c0f3eeb00d
commit 0efa4ee6f7
625 changed files with 117283 additions and 4426 deletions

View 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(); }
//------------------------------------------------------------------------------

View 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;
}
//------------------------------------------------------------------------------

View 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;
}
//-----------------------------------------------------------------------------

View 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;
}
//------------------------------------------------------------------------------

View 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 = &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;
}
//------------------------------------------------------------------------------

View 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;
}
//------------------------------------------------------------------------------

View 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); }
//------------------------------------------------------------------------------

View 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));
}
//------------------------------------------------------------------------------

View 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);
}
//------------------------------------------------------------------------------

View 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);
}
//------------------------------------------------------------------------------

View 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 = &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;
}
//------------------------------------------------------------------------------

View 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;
}
//------------------------------------------------------------------------------

View 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; }
//------------------------------------------------------------------------------

View 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;
}
//------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View 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;
}
//------------------------------------------------------------------------------

View 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;
}
}
//------------------------------------------------------------------------------