lite-xl/src/agg_pixfmt_bgra32_lcd.h

275 lines
9.6 KiB
C
Raw Normal View History

//----------------------------------------------------------------------------
// Anti-Grain Geometry (AGG) - Version 2.5
// A high quality rendering engine for C++
// Copyright (C) 2002-2006 Maxim Shemanarev
// Contact: mcseem@antigrain.com
// mcseemagg@yahoo.com
// http://antigrain.com
//
// AGG is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// AGG is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with AGG; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301, USA.
//----------------------------------------------------------------------------
#ifndef AGG_PIXFMT_BGRA32_LCD_INCLUDED
#define AGG_PIXFMT_BGRA32_LCD_INCLUDED
#include <string.h>
#include "agg_basics.h"
#include "agg_color_rgba.h"
#include "agg_rendering_buffer.h"
namespace agg
{
//=====================================================lcd_distribution_lut
class lcd_distribution_lut
{
public:
lcd_distribution_lut(double prim, double second, double tert)
{
double norm = 1.0 / (prim + second*2 + tert*2);
prim *= norm;
second *= norm;
tert *= norm;
for(unsigned i = 0; i < 256; i++)
{
unsigned b = (i << 8);
unsigned s = round(second * b);
unsigned t = round(tert * b);
unsigned p = b - (2*s + 2*t);
m_data[3*i + 1] = s; /* secondary */
m_data[3*i + 2] = t; /* tertiary */
m_data[3*i ] = p; /* primary */
}
}
unsigned convolution(const int8u* covers, int i0, int i_min, int i_max) const
{
unsigned sum = 0;
int k_min = (i0 >= i_min + 2 ? -2 : i_min - i0);
int k_max = (i0 <= i_max - 2 ? 2 : i_max - i0);
for (int k = k_min; k <= k_max; k++)
{
/* select the primary, secondary or tertiary channel */
int channel = abs(k) % 3;
int8u c = covers[i0 + k];
sum += m_data[3*c + channel];
}
return (sum + 128) >> 8;
}
private:
unsigned short m_data[256*3];
};
//========================================================pixfmt_bgra32_lcd
class pixfmt_bgra32_lcd
{
public:
typedef rgba8 color_type;
typedef rendering_buffer::row_data row_data;
typedef color_type::value_type value_type;
typedef color_type::calc_type calc_type;
//--------------------------------------------------------------------
pixfmt_bgra32_lcd(rendering_buffer& rb, const lcd_distribution_lut& lut)
: m_rbuf(&rb), m_lut(&lut)
{
}
//--------------------------------------------------------------------
unsigned width() const {
return m_rbuf->width() * 3;
}
unsigned height() const {
return m_rbuf->height();
}
// This method should never be called when using the scanline_u8.
// The use of scanline_p8 should be avoided because if does not works
// properly for rendering fonts because single hspan are split in many
// hline/hspan elements and pixel whitening happens.
void blend_hline(int x, int y, unsigned len,
const color_type& c, int8u cover)
{ }
void copy_hline(int x, int y, unsigned len, const color_type& c)
{
int8u* p = m_rbuf->row_ptr(y) + (x / 3) * 4;
for (int ilen = len; ilen > 0; p += 4, ilen -= 3)
{
p[0] = c.b;
p[1] = c.g;
p[2] = c.r;
p[3] = 0xff;
}
}
//--------------------------------------------------------------------
void blend_solid_hspan(int x, int y,
unsigned len,
const color_type& c,
const int8u* covers)
{
unsigned rowlen = width();
int cx = (x - 2 >= 0 ? -2 : -x);
int cx_max = (len + 2 <= rowlen ? len + 1 : rowlen - 1);
int i = (x + cx) % 3;
const int8u rgb[3] = { c.r, c.g, c.b };
int8u* p = m_rbuf->row_ptr(y) + (x + cx);
const int pixel_index[3] = {2, 1, 0};
for (/* */; cx <= cx_max; cx += 3)
{
unsigned c_conv, alpha, dst_col, src_col;
c_conv = m_lut->convolution(covers, cx, 0, len - 1);
alpha = (c_conv + 1) * (c.a + 1);
dst_col = rgb[i];
src_col = *(p + pixel_index[i]);
*(p + pixel_index[i]) = (int8u)((((dst_col - src_col) * alpha) + (src_col << 16)) >> 16);
i = (i + 1) % 3;
c_conv = m_lut->convolution(covers, cx + 1, 0, len - 1);
alpha = (c_conv + 1) * (c.a + 1);
dst_col = rgb[i];
src_col = *(p + pixel_index[i]);
*(p + pixel_index[i]) = (int8u)((((dst_col - src_col) * alpha) + (src_col << 16)) >> 16);
i = (i + 1) % 3;
c_conv = m_lut->convolution(covers, cx + 2, 0, len - 1);
alpha = (c_conv + 1) * (c.a + 1);
dst_col = rgb[i];
src_col = *(p + pixel_index[i]);
*(p + pixel_index[i]) = (int8u)((((dst_col - src_col) * alpha) + (src_col << 16)) >> 16);
i = (i + 1) % 3;
p[3] = 0xff;
p += 4;
}
}
private:
rendering_buffer* m_rbuf;
const lcd_distribution_lut* m_lut;
};
template <class Gamma>
class pixfmt_bgra32_lcd_gamma
{
public:
typedef rgba8 color_type;
typedef rendering_buffer::row_data row_data;
typedef color_type::value_type value_type;
typedef color_type::calc_type calc_type;
//--------------------------------------------------------------------
pixfmt_bgra32_lcd_gamma(rendering_buffer& rb, const lcd_distribution_lut& lut, const Gamma& gamma)
: m_rbuf(&rb), m_lut(&lut), m_gamma(gamma)
{
}
//--------------------------------------------------------------------
unsigned width() const {
return m_rbuf->width() * 3;
}
unsigned height() const {
return m_rbuf->height();
}
// This method should never be called when using the scanline_u8.
// The use of scanline_p8 should be avoided because if does not works
// properly for rendering fonts because single hspan are split in many
// hline/hspan elements and pixel whitening happens.
void blend_hline(int x, int y, unsigned len,
const color_type& c, int8u cover)
{ }
void copy_hline(int x, int y, unsigned len, const color_type& c)
{
int8u* p = m_rbuf->row_ptr(y) + (x / 3) * 4;
for (int ilen = len; ilen > 0; p += 4, ilen -= 3)
{
p[0] = c.r;
p[1] = c.g;
p[2] = c.b;
p[3] = 0xff;
}
}
//--------------------------------------------------------------------
void blend_solid_hspan(int x, int y,
unsigned len,
const color_type& c,
const int8u* covers)
{
unsigned rowlen = width();
int cx = (x - 2 >= 0 ? -2 : -x);
int cx_max = (len + 2 <= rowlen ? len + 1 : rowlen - 1);
int i = (x + cx) % 3;
const int8u rgb[3] = { c.r, c.g, c.b };
int8u* p = m_rbuf->row_ptr(y) + (x + cx);
const int pixel_index[3] = {2, 1, 0};
for (/* */; cx <= cx_max; cx += 3)
{
unsigned c_conv, alpha, dst_col, src_col;
c_conv = m_lut->convolution(covers, cx, 0, len - 1);
alpha = (c_conv + 1) * (c.a + 1);
dst_col = m_gamma.dir(rgb[i]);
src_col = m_gamma.dir(*(p + pixel_index[i]));
*(p + pixel_index[i]) = m_gamma.inv((((dst_col - src_col) * alpha) + (src_col << 16)) >> 16);
i = (i + 1) % 3;
c_conv = m_lut->convolution(covers, cx + 1, 0, len - 1);
alpha = (c_conv + 1) * (c.a + 1);
dst_col = m_gamma.dir(rgb[i]);
src_col = m_gamma.dir(*(p + pixel_index[i]));
*(p + pixel_index[i]) = m_gamma.inv((((dst_col - src_col) * alpha) + (src_col << 16)) >> 16);
i = (i + 1) % 3;
c_conv = m_lut->convolution(covers, cx + 2, 0, len - 1);
alpha = (c_conv + 1) * (c.a + 1);
dst_col = m_gamma.dir(rgb[i]);
src_col = m_gamma.dir(*(p + pixel_index[i]));
*(p + pixel_index[i]) = m_gamma.inv((((dst_col - src_col) * alpha) + (src_col << 16)) >> 16);
i = (i + 1) % 3;
p[3] = 0xff;
p += 4;
}
}
private:
rendering_buffer* m_rbuf;
const lcd_distribution_lut* m_lut;
const Gamma& m_gamma;
};
}
#endif