Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
/* SPDX-FileCopyrightText: 2008-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup freestyle
* \brief Class to perform gaussian filtering operations on an image
*/
#include <cstdlib>
#include "GaussianFilter.h"
#include "BLI_math_base.h"
namespace Freestyle {
GaussianFilter::GaussianFilter(float iSigma)
{
_sigma = iSigma;
_mask = nullptr;
computeMask();
}
GaussianFilter::GaussianFilter(const GaussianFilter &iBrother)
{
_sigma = iBrother._sigma;
_maskSize = iBrother._maskSize;
_bound = iBrother._bound;
_storedMaskSize = iBrother._storedMaskSize;
_mask = new float[_maskSize * _maskSize];
memcpy(_mask, iBrother._mask, _maskSize * _maskSize * sizeof(float));
}
GaussianFilter &GaussianFilter::operator=(const GaussianFilter &iBrother)
{
_sigma = iBrother._sigma;
_maskSize = iBrother._maskSize;
_bound = iBrother._bound;
_storedMaskSize = iBrother._storedMaskSize;
_mask = new float[_storedMaskSize * _storedMaskSize];
memcpy(_mask, iBrother._mask, _storedMaskSize * _storedMaskSize * sizeof(float));
return *this;
}
GaussianFilter::~GaussianFilter()
{
delete[] _mask;
}
int GaussianFilter::computeMaskSize(float sigma)
{
int maskSize = int(floor(4 * sigma)) + 1;
if (0 == (maskSize % 2)) {
++maskSize;
}
return maskSize;
}
void GaussianFilter::setSigma(float sigma)
{
_sigma = sigma;
computeMask();
}
void GaussianFilter::computeMask()
{
delete[] _mask;
_maskSize = computeMaskSize(_sigma);
_storedMaskSize = (_maskSize + 1) >> 1;
_bound = _storedMaskSize - 1;
float norm = _sigma * _sigma * 2.0f * M_PI;
float invNorm = 1.0f / norm;
_mask = new float[_storedMaskSize * _storedMaskSize * sizeof(float)];
for (int i = 0; i < _storedMaskSize; ++i) {
for (int j = 0; j < _storedMaskSize; ++j) {
#if 0
_mask[i * _storedMaskSize + j] = exp(-(i * i + j * j) / (2.0 * _sigma * _sigma));
#else
_mask[i * _storedMaskSize + j] = invNorm * exp(-(i * i + j * j) / (2.0 * _sigma * _sigma));
#endif
}
}
}
} /* namespace Freestyle */

View File

@@ -0,0 +1,132 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup freestyle
* \brief Class to perform gaussian filtering operations on an image
*/
#include <cstdlib> // for abs
#include <string.h> // for memcpy
#include "../system/FreestyleConfig.h"
#include "MEM_guardedalloc.h"
namespace Freestyle {
class GaussianFilter {
protected:
/* The mask is a symmetrical 2d array (with respect to the middle point).
* Thus: `M(i,j) = M(-i,j) = M(i,-j) = M(-i,-j)`.
* For this reason, to represent a NxN array (N odd),
* we only store a `((N+1)/2)x((N+1)/2)` array. */
/** The sigma value of the gaussian function. */
float _sigma;
float *_mask;
int _bound;
/* The real mask size (must be odd), the size of the mask we store is:
* `((_maskSize+1)/2)*((_maskSize+1)/2))`. */
int _maskSize;
int _storedMaskSize; // (_maskSize+1)/2)
public:
GaussianFilter(float iSigma = 1.0f);
GaussianFilter(const GaussianFilter &);
GaussianFilter &operator=(const GaussianFilter &);
virtual ~GaussianFilter();
/** Returns the value for pixel x,y of image "map" after a gaussian blur, made using the sigma
* value. The sigma value determines the mask size (~ 2 x sigma).
* \param map: The image we wish to work on.
* The Map template must implement the following methods:
* - `float pixel(uint x, uint y) const;`
* - `uint width() const;`
* - `uint height() const;`
* \param x: The abscissa of the pixel where we want to evaluate the gaussian blur.
* \param y: The ordinate of the pixel where we want to evaluate the gaussian blur.
*/
template<class Map> float getSmoothedPixel(Map *map, int x, int y);
/** Compute the mask size and returns the REAL mask size ((2*_maskSize)-1)
* This method is provided for convenience.
*/
static int computeMaskSize(float sigma);
/** accessors */
inline float sigma() const
{
return _sigma;
}
inline int maskSize() const
{
return _maskSize;
}
inline int getBound()
{
return _bound;
}
/** modifiers */
void setSigma(float sigma);
#if 0
void SetMaskSize(int size)
{
_maskSize = size;
_storedMaskSize = (_maskSize + 1) >> 1;
}
#endif
protected:
void computeMask();
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:GaussianFilter")
};
/*
* #############################################
* #############################################
* #############################################
* ###### ######
* ###### I M P L E M E N T A T I O N ######
* ###### ######
* #############################################
* #############################################
* #############################################
*/
template<class Map> float GaussianFilter::getSmoothedPixel(Map *map, int x, int y)
{
// float sum = 0.0f;
float L = 0.0f;
int w = int(map->width()); // soc
int h = int(map->height()); // soc
// Current pixel is x,y
// Sum surrounding pixels L value:
for (int i = -_bound; i <= _bound; ++i) {
if ((y + i < 0) || (y + i >= h)) {
continue;
}
for (int j = -_bound; j <= _bound; ++j) {
if ((x + j < 0) || (x + j >= w)) {
continue;
}
float tmpL = map->pixel(x + j, y + i);
float m = _mask[abs(i) * _storedMaskSize + abs(j)];
L += m * tmpL;
// sum += m;
}
}
// L /= sum;
return L;
}
} /* namespace Freestyle */

View File

@@ -0,0 +1,401 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup freestyle
* \brief Class to encapsulate an array of RGB or Gray level values
*/
#include <string.h> // for memcpy
#include "MEM_guardedalloc.h"
namespace Freestyle {
//
// Image base class, for all types of images
//
///////////////////////////////////////////////////////////////////////////////
/** This class allows the storing of part of an image, while allowing a normal access to its pixel
* values. You can for example only a rectangle of sw*sh, whose lower-left corner is at (ox, oy),
* of an image of size w*h, and access these pixels using x,y coordinates specified in the whole
* image coordinate system.
*/
class FrsImage {
public:
/** Default constructor */
FrsImage()
{
_storedWidth = 0;
_storedHeight = 0;
_width = 0;
_height = 0;
_Ox = 0;
_Oy = 0;
}
/** Copy constructor */
FrsImage(const FrsImage &brother)
{
_storedWidth = brother._storedWidth;
_storedHeight = brother._storedHeight;
_width = brother._width;
_height = brother._height;
_Ox = brother._Ox;
_Oy = brother._Oy;
}
/** Builds an FrsImage from its width and height.
* The memory is allocated consequently.
*/
FrsImage(uint w, uint h)
{
_width = w;
_height = h;
_storedWidth = w;
_storedHeight = h;
_Ox = 0;
_Oy = 0;
}
/** Builds a partial-storing image.
* \param w:
* The width of the complete image
* \param h:
* The height of the complete image
* \param sw:
* The width of the rectangle that will actually be stored.
* \param sh:
* The height of the rectangle that will actually be stored.
* \param ox:
* The x-abscissa of the origin of the rectangle that will actually be stored.
* \param oy:
* The x-abscissa of the origin of the rectangle that will actually be stored.
*/
FrsImage(uint w, uint h, uint sw, uint sh, uint ox, uint oy)
{
_width = w;
_height = h;
_storedWidth = sw;
_storedHeight = sh;
_Ox = ox;
_Oy = oy;
}
/** Operator= */
FrsImage &operator=(const FrsImage &brother)
{
_width = brother._width;
_height = brother._height;
_storedWidth = brother._storedWidth;
_storedHeight = brother._storedHeight;
_Ox = brother._Ox;
_Oy = brother._Oy;
return *this;
}
/** Destructor */
virtual ~FrsImage() {}
/** Returns the width of the complete image */
inline uint width() const
{
return _width;
}
/** Returns the height of the complete image */
inline uint height() const
{
return _height;
}
/** Returns the gray value for pixel x,y */
virtual float pixel(uint x, uint y) const = 0;
/** Sets the array.
* \param array:
* The array containing the values we wish to store.
* Its size is sw*sh.
* \param width:
* The width of the complete image
* \param height:
* The height of the complete image
* \param sw:
* The width of the rectangle that will actually be stored.
* \param sh:
* The height of the rectangle that will actually be stored.
* \param x:
* The x-abscissa of the origin of the rectangle that will actually be stored.
* \param y:
* The x-abscissa of the origin of the rectangle that will actually be stored.
* \param copy:
* If true, the array is copied, otherwise the pointer is copied
*/
virtual void setArray(float *array,
uint width,
uint height,
uint sw,
uint sh,
uint x,
uint y,
bool copy = true) = 0;
/** Returns the array containing the pixels values.
* Its size is sw*sh, i.e. potentially a smaller rectangular part of the complete image.
*/
virtual float *getArray() = 0;
protected:
uint _width;
uint _height;
uint _storedWidth;
uint _storedHeight;
uint _Ox; // origin of the stored part
uint _Oy; // origin of the stored part
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FrsImage")
};
//
// RGBImage
//
///////////////////////////////////////////////////////////////////////////////
class RGBImage : public FrsImage {
public:
RGBImage() : FrsImage()
{
_rgb = 0;
}
RGBImage(const RGBImage &brother) : FrsImage(brother)
{
_rgb = new float[3 * _storedWidth * _storedHeight];
memcpy(_rgb, brother._rgb, 3 * _storedWidth * _storedHeight * sizeof(float));
}
RGBImage(uint w, uint h) : FrsImage(w, h)
{
_rgb = new float[3 * _width * _height];
}
RGBImage(float *rgb, uint w, uint h) : FrsImage(w, h)
{
_rgb = new float[3 * _width * _height];
memcpy(_rgb, rgb, 3 * _width * _height * sizeof(float));
}
/** Builds an RGB partial image from the useful part buffer.
* \param rgb:
* The array of size 3*sw*sh containing the RGB values of the sw*sh pixels we need to stored.
* These sw*sh pixels constitute a rectangular part of a bigger
* RGB image containing w*h pixels.
* \param w:
* The width of the complete image
* \param h:
* The height of the complete image
* \param sw:
* The width of the part of the image we want to store and work on
* \param sh:
* The height of the part of the image we want to store and work on
*/
RGBImage(float *rgb, uint w, uint h, uint sw, uint sh, uint ox, uint oy)
: FrsImage(w, h, sw, sh, ox, oy)
{
_rgb = new float[3 * _storedWidth * _storedHeight];
memcpy(_rgb, rgb, 3 * _storedWidth * _storedHeight * sizeof(float));
}
RGBImage &operator=(const RGBImage &brother)
{
dynamic_cast<FrsImage &>(*this) = brother;
_rgb = new float[3 * _storedWidth * _storedHeight];
memcpy(_rgb, brother._rgb, 3 * _storedWidth * _storedHeight * sizeof(float));
return *this;
}
virtual ~RGBImage()
{
if (_rgb) {
delete[] _rgb;
}
}
inline float getR(uint x, uint y) const
{
return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3];
}
inline float getG(uint x, uint y) const
{
return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3 + 1];
}
inline float getB(uint x, uint y) const
{
return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3 + 2];
}
virtual void setPixel(uint x, uint y, float r, float g, float b)
{
float *tmp = &(_rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3]);
*tmp = r;
tmp++;
*tmp = g;
tmp++;
*tmp = b;
}
virtual float pixel(uint x, uint y) const
{
float res = 0.0f;
float *tmp = &(_rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3]);
res += 11.0f * (*tmp);
tmp++;
res += 16.0f * (*tmp);
tmp++;
res += 5.0f * (*tmp);
return res / 32.0f;
}
/** Sets the RGB array.
* copy
* If true, the array is copied, otherwise the pointer is copied
*/
virtual void setArray(
float *rgb, uint width, uint height, uint sw, uint sh, uint x, uint y, bool copy = true)
{
_width = width;
_height = height;
_storedWidth = sw;
_storedHeight = sh;
_Ox = x;
_Oy = y;
if (!copy) {
_rgb = rgb;
return;
}
memcpy(_rgb, rgb, 3 * _storedWidth * _storedHeight * sizeof(float));
}
virtual float *getArray()
{
return _rgb;
}
protected:
float *_rgb;
};
//
// GrayImage
//
///////////////////////////////////////////////////////////////////////////////
class GrayImage : public FrsImage {
public:
GrayImage() : FrsImage()
{
_lvl = 0;
}
GrayImage(const GrayImage &brother) : FrsImage(brother)
{
_lvl = new float[_storedWidth * _storedHeight];
memcpy(_lvl, brother._lvl, _storedWidth * _storedHeight * sizeof(*_lvl));
}
/** Builds an empty gray image */
GrayImage(uint w, uint h) : FrsImage(w, h)
{
_lvl = new float[_width * _height];
}
GrayImage(float *lvl, uint w, uint h) : FrsImage(w, h)
{
_lvl = new float[_width * _height];
memcpy(_lvl, lvl, _width * _height * sizeof(*_lvl));
}
/** Builds a partial image from the useful part buffer.
* \param lvl:
* The array of size sw*sh containing the gray values of the sw*sh pixels we need to stored.
* These sw*sh pixels constitute a rectangular part of a bigger
* gray image containing w*h pixels.
* \param w:
* The width of the complete image
* \param h:
* The height of the complete image
* \param sw:
* The width of the part of the image we want to store and work on
* \param sh:
* The height of the part of the image we want to store and work on
*/
GrayImage(float *lvl, uint w, uint h, uint sw, uint sh, uint ox, uint oy)
: FrsImage(w, h, sw, sh, ox, oy)
{
_lvl = new float[_storedWidth * _storedHeight];
memcpy(_lvl, lvl, _storedWidth * _storedHeight * sizeof(float));
}
GrayImage &operator=(const GrayImage &brother)
{
dynamic_cast<FrsImage &>(*this) = brother;
_lvl = new float[_storedWidth * _storedHeight];
memcpy(_lvl, brother._lvl, _storedWidth * _storedHeight * sizeof(float));
return *this;
}
virtual ~GrayImage()
{
if (_lvl) {
delete[] _lvl;
}
}
inline void setPixel(uint x, uint y, float v)
{
_lvl[(y - _Oy) * _storedWidth + (x - _Ox)] = v;
}
inline float pixel(uint x, uint y) const
{
return _lvl[(y - _Oy) * _storedWidth + (x - _Ox)];
}
/** Sets the array.
* copy
* If true, the array is copied, otherwise the pounsigneder is copied
*/
void setArray(
float *lvl, uint width, uint height, uint sw, uint sh, uint x, uint y, bool copy = true)
{
_width = width;
_height = height;
_storedWidth = sw;
_storedHeight = sh;
_Ox = x;
_Oy = y;
if (!copy) {
_lvl = lvl;
return;
}
memcpy(_lvl, lvl, _storedWidth * _storedHeight * sizeof(float));
}
/** Returns the array containing the gray values. */
virtual float *getArray()
{
return _lvl;
}
protected:
float *_lvl;
};
} /* namespace Freestyle */

View File

@@ -0,0 +1,181 @@
/* SPDX-FileCopyrightText: 2008-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup freestyle
* \brief Class to represent a pyramid of images
*/
#include <iostream>
#include "GaussianFilter.h"
#include "Image.h"
#include "ImagePyramid.h"
#include "BLI_sys_types.h"
using namespace std;
namespace Freestyle {
#if 0
ImagePyramid::ImagePyramid(const GrayImage &level0, uint nbLevels)
{
BuildPyramid(level0, nbLevels);
}
#endif
ImagePyramid::ImagePyramid(const ImagePyramid & /*iBrother*/)
{
if (!_levels.empty()) {
for (vector<GrayImage *>::iterator im = _levels.begin(), imend = _levels.end(); im != imend;
++im)
{
_levels.push_back(new GrayImage(**im));
}
}
}
ImagePyramid::~ImagePyramid()
{
if (!_levels.empty()) {
for (vector<GrayImage *>::iterator im = _levels.begin(), imend = _levels.end(); im != imend;
++im)
{
delete (*im);
}
_levels.clear();
}
}
GrayImage *ImagePyramid::getLevel(int l)
{
return _levels[l];
}
float ImagePyramid::pixel(int x, int y, int level)
{
GrayImage *img = _levels[level];
if (0 == level) {
return img->pixel(x, y);
}
uint i = 1 << level;
uint sx = x >> level;
uint sy = y >> level;
if (sx >= img->width()) {
sx = img->width() - 1;
}
if (sy >= img->height()) {
sy = img->height() - 1;
}
// bilinear interpolation
float A = i * (sx + 1) - x;
float B = x - i * sx;
float C = i * (sy + 1) - y;
float D = y - i * sy;
float P1(0), P2(0);
P1 = A * img->pixel(sx, sy);
if (sx < img->width() - 1) {
if (x % i != 0) {
P1 += B * img->pixel(sx + 1, sy);
}
}
else {
P1 += B * img->pixel(sx, sy);
}
if (sy < img->height() - 1) {
if (y % i != 0) {
P2 = A * img->pixel(sx, sy + 1);
if (sx < img->width() - 1) {
if (x % i != 0) {
P2 += B * img->pixel(sx + 1, sy + 1);
}
}
else {
P2 += B * img->pixel(sx, sy + 1);
}
}
}
else {
P2 = P1;
}
return (1.0f / float(1 << (2 * level))) * (C * P1 + D * P2);
}
int ImagePyramid::width(int level)
{
return _levels[level]->width();
}
int ImagePyramid::height(int level)
{
return _levels[level]->height();
}
GaussianPyramid::GaussianPyramid(const GrayImage &level0, uint nbLevels, float iSigma)
{
_sigma = iSigma;
BuildPyramid(level0, nbLevels);
}
GaussianPyramid::GaussianPyramid(GrayImage *level0, uint nbLevels, float iSigma)
{
_sigma = iSigma;
BuildPyramid(level0, nbLevels);
}
GaussianPyramid::GaussianPyramid(const GaussianPyramid &iBrother) : ImagePyramid(iBrother)
{
_sigma = iBrother._sigma;
}
void GaussianPyramid::BuildPyramid(const GrayImage &level0, uint nbLevels)
{
GrayImage *pLevel = new GrayImage(level0);
BuildPyramid(pLevel, nbLevels);
}
void GaussianPyramid::BuildPyramid(GrayImage *level0, uint nbLevels)
{
GrayImage *pLevel = level0;
_levels.push_back(pLevel);
GaussianFilter gf(_sigma);
// build the nbLevels:
uint w = pLevel->width();
uint h = pLevel->height();
if (nbLevels != 0) {
for (uint i = 0; i < nbLevels; ++i) { // soc
w = pLevel->width() >> 1;
h = pLevel->height() >> 1;
GrayImage *img = new GrayImage(w, h);
for (uint y = 0; y < h; ++y) {
for (uint x = 0; x < w; ++x) {
float v = gf.getSmoothedPixel<GrayImage>(pLevel, 2 * x, 2 * y);
img->setPixel(x, y, v);
}
}
_levels.push_back(img);
pLevel = img;
}
}
else {
while ((w > 1) && (h > 1)) {
w = pLevel->width() >> 1;
h = pLevel->height() >> 1;
GrayImage *img = new GrayImage(w, h);
for (uint y = 0; y < h; ++y) {
for (uint x = 0; x < w; ++x) {
float v = gf.getSmoothedPixel<GrayImage>(pLevel, 2 * x, 2 * y);
img->setPixel(x, y, v);
}
}
_levels.push_back(img);
pLevel = img;
}
}
}
} /* namespace Freestyle */

View File

@@ -0,0 +1,94 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup freestyle
* \brief Class to represent a pyramid of images
*/
#include <vector>
#include "../system/FreestyleConfig.h"
#include "MEM_guardedalloc.h"
namespace Freestyle {
class GrayImage;
class ImagePyramid {
protected:
std::vector<GrayImage *> _levels;
public:
ImagePyramid() {}
ImagePyramid(const ImagePyramid &iBrother);
// ImagePyramid(const GrayImage& level0, uint nbLevels);
virtual ~ImagePyramid();
/** Builds the pyramid.
* must be overloaded by inherited classes.
* if nbLevels==0, the complete pyramid is built
*/
virtual void BuildPyramid(const GrayImage &level0, uint nbLevels) = 0;
/** Builds a pyramid without copying the base level */
virtual void BuildPyramid(GrayImage *level0, uint nbLevels) = 0;
virtual GrayImage *getLevel(int l);
/** Returns the pixel x,y using bilinear interpolation.
* \param x:
* the abscissa specified in the finest level coordinate system
* \param y:
* the ordinate specified in the finest level coordinate system
* \param level:
* the level from which we want the pixel to be evaluated
*/
virtual float pixel(int x, int y, int level = 0);
/** Returns the width of the level-th level image */
virtual int width(int level = 0);
/** Returns the height of the level-th level image */
virtual int height(int level = 0);
/** Returns the number of levels in the pyramid */
inline int getNumberOfLevels() const
{
return _levels.size();
}
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:ImagePyramid")
};
class GaussianPyramid : public ImagePyramid {
protected:
float _sigma;
public:
GaussianPyramid(float iSigma = 1.0f) : ImagePyramid()
{
_sigma = iSigma;
}
GaussianPyramid(const GrayImage &level0, uint nbLevels, float iSigma = 1.0f);
GaussianPyramid(GrayImage *level0, uint nbLevels, float iSigma = 1.0f);
GaussianPyramid(const GaussianPyramid &iBrother);
virtual ~GaussianPyramid() {}
virtual void BuildPyramid(const GrayImage &level0, uint nbLevels);
virtual void BuildPyramid(GrayImage *level0, uint nbLevels);
/* accessors */
inline float getSigma() const
{
return _sigma;
}
/* modifiers */
};
} /* namespace Freestyle */