Files
Webcam/include/framework/picture/pict_gradient.cpp

185 lines
5.4 KiB
C++

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