Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenlib')
-rw-r--r--source/blender/blenlib/BLI_color.hh2
-rw-r--r--source/blender/blenlib/BLI_color_mix.hh1051
-rw-r--r--source/blender/blenlib/BLI_generic_virtual_array.hh16
-rw-r--r--source/blender/blenlib/BLI_math_base.hh5
-rw-r--r--source/blender/blenlib/BLI_math_color.hh19
-rw-r--r--source/blender/blenlib/BLI_math_vec_types.hh8
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh6
-rw-r--r--source/blender/blenlib/CMakeLists.txt1
-rw-r--r--source/blender/blenlib/intern/fileops.c92
9 files changed, 1138 insertions, 62 deletions
diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh
index 0754221eb65..98fd7d0f15d 100644
--- a/source/blender/blenlib/BLI_color.hh
+++ b/source/blender/blenlib/BLI_color.hh
@@ -345,5 +345,7 @@ BLI_color_convert_to_theme4b(const ColorSceneLinear4f<eAlpha::Straight> &scene_l
using ColorGeometry4f = ColorSceneLinear4f<eAlpha::Premultiplied>;
using ColorGeometry4b = ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>;
+using ColorPaint4f = ColorSceneLinear4f<eAlpha::Straight>;
+using ColorPaint4b = ColorSceneLinearByteEncoded4b<eAlpha::Straight>;
} // namespace blender
diff --git a/source/blender/blenlib/BLI_color_mix.hh b/source/blender/blenlib/BLI_color_mix.hh
new file mode 100644
index 00000000000..4989ddc609e
--- /dev/null
+++ b/source/blender/blenlib/BLI_color_mix.hh
@@ -0,0 +1,1051 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
+
+/** \file
+ * \ingroup blenlib
+ *
+ * Contains color mixing utilities.
+ */
+
+#include "BLI_color.hh"
+#include "BLI_math_base.h"
+#include "BLI_math_color.h"
+#include "BLI_sys_types.h"
+
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
+
+#include <type_traits>
+
+namespace blender::color {
+
+struct ByteTraits {
+ using ValueType = uchar;
+ using BlendType = int;
+
+ inline static const uchar range = 255; /* Zero-based maximum value. */
+ inline static const float frange = 255.0f; /* Convenient floating-point version of range. */
+ inline static const int cmpRange = 254;
+ inline static const int expandedRange = 256; /* One-based maximum value. */
+
+ inline static const int bytes = 1;
+ inline static const float unit = 255.0f;
+
+ static inline BlendType divide_round(BlendType a, BlendType b)
+ {
+ return divide_round_i(a, b);
+ }
+
+ static inline BlendType min(BlendType a, BlendType b)
+ {
+ return min_ii(a, b);
+ }
+
+ static inline BlendType max(BlendType a, BlendType b)
+ {
+ return max_ii(a, b);
+ }
+ /* Discretizes in steps of 1.0 / range */
+ static inline ValueType round(float f)
+ {
+ return round_fl_to_uchar(f);
+ }
+};
+
+struct FloatTraits {
+ using ValueType = float;
+ using BlendType = float;
+
+ inline const static float range = 1.0f;
+ inline const static float frange = 1.0f;
+ inline const static float cmpRange = 0.9999f;
+ inline static const int expandedRange = 1.0f;
+
+ inline const static float unit = 1.0f;
+ inline const static int bytes = 4;
+
+ static inline BlendType divide_round(BlendType a, BlendType b)
+ {
+ return a / b;
+ }
+
+ static inline BlendType min(BlendType a, BlendType b)
+ {
+ return min_ff(a, b);
+ }
+
+ static inline BlendType max(BlendType a, BlendType b)
+ {
+ return min_ff(a, b);
+ }
+
+ /* Discretizes in steps of 1.0 / range */
+ static inline ValueType round(float f)
+ {
+ return f;
+ }
+};
+
+static float get_luminance(ColorPaint4f c)
+{
+ return IMB_colormanagement_get_luminance(&c.r);
+}
+
+static int get_luminance(ColorPaint4b c)
+{
+ return IMB_colormanagement_get_luminance_byte(&c.r);
+}
+
+#define EPS_SATURATION 0.0005f
+
+/* -------------------------------------------------------------------- */
+/** \name Color Blending Modes
+ * \{ */
+
+template<typename Color, typename Traits>
+static Color mix_blend(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Color col_mix(0, 0, 0, 0);
+ Blend mfac;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ if (fac >= Traits::range) {
+ return col_dst;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = &col_src.r;
+ cp_dst = &col_dst.r;
+ cp_mix = &col_mix.r;
+
+ /* Updated to use the rgb squared color model which blends nicer. */
+ Blend r1 = cp_src[0] * cp_src[0];
+ Blend g1 = cp_src[1] * cp_src[1];
+ Blend b1 = cp_src[2] * cp_src[2];
+ Blend a1 = cp_src[3] * cp_src[3];
+
+ Blend r2 = cp_dst[0] * cp_dst[0];
+ Blend g2 = cp_dst[1] * cp_dst[1];
+ Blend b2 = cp_dst[2] * cp_dst[2];
+ Blend a2 = cp_dst[3] * cp_dst[3];
+
+ cp_mix[0] = Traits::round(sqrtf(Traits::divide_round((mfac * r1 + fac * r2), Traits::range)));
+ cp_mix[1] = Traits::round(sqrtf(Traits::divide_round((mfac * g1 + fac * g2), Traits::range)));
+ cp_mix[2] = Traits::round(sqrtf(Traits::divide_round((mfac * b1 + fac * b2), Traits::range)));
+ cp_mix[3] = Traits::round(sqrtf(Traits::divide_round((mfac * a1 + fac * a2), Traits::range)));
+ return Color(col_mix[0], col_mix[1], col_mix[2], col_mix[3]);
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_add(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ cp_src = (Value *)&col_src.r;
+ cp_dst = (Value *)&col_dst.r;
+ cp_mix = (Value *)&col_mix.r;
+
+ temp = cp_src[0] + Traits::divide_round((fac * cp_dst[0]), Traits::range);
+ cp_mix[0] = (temp > Traits::cmpRange) ? Traits::range : temp;
+ temp = cp_src[1] + Traits::divide_round((fac * cp_dst[1]), Traits::range);
+ cp_mix[1] = (temp > Traits::cmpRange) ? Traits::range : temp;
+ temp = cp_src[2] + Traits::divide_round((fac * cp_dst[2]), Traits::range);
+ cp_mix[2] = (temp > Traits::cmpRange) ? Traits::range : temp;
+ temp = cp_src[3] + Traits::divide_round((fac * cp_dst[3]), Traits::range);
+ cp_mix[3] = (temp > Traits::cmpRange) ? Traits::range : temp;
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_sub(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend temp;
+ Color col_mix(0, 0, 0, 0);
+
+ cp_src = (Value *)&col_src.r;
+ cp_dst = (Value *)&col_dst.r;
+ cp_mix = (Value *)&col_mix.r;
+
+ temp = cp_src[0] - Traits::divide_round((fac * cp_dst[0]), Traits::range);
+ cp_mix[0] = (temp < 0) ? 0 : temp;
+ temp = cp_src[1] - Traits::divide_round((fac * cp_dst[1]), Traits::range);
+ cp_mix[1] = (temp < 0) ? 0 : temp;
+ temp = cp_src[2] - Traits::divide_round((fac * cp_dst[2]), Traits::range);
+ cp_mix[2] = (temp < 0) ? 0 : temp;
+ temp = cp_src[3] - Traits::divide_round((fac * cp_dst[3]), Traits::range);
+ cp_mix[3] = (temp < 0) ? 0 : temp;
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_mul(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ /* first mul, then blend the fac */
+ cp_mix[0] = Traits::divide_round(mfac * cp_src[0] * Traits::range + fac * cp_dst[0] * cp_src[0],
+ Traits::range * Traits::range);
+ cp_mix[1] = Traits::divide_round(mfac * cp_src[1] * Traits::range + fac * cp_dst[1] * cp_src[1],
+ Traits::range * Traits::range);
+ cp_mix[2] = Traits::divide_round(mfac * cp_src[2] * Traits::range + fac * cp_dst[2] * cp_src[2],
+ Traits::range * Traits::range);
+ cp_mix[3] = Traits::divide_round(mfac * cp_src[3] * Traits::range + fac * cp_dst[3] * cp_src[3],
+ Traits::range * Traits::range);
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_lighten(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+ if (fac >= Traits::range) {
+ return col_dst;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ /* See if we're lighter, if so mix, else don't do anything.
+ * if the paint color is darker then the original, then ignore */
+ if (get_luminance(cp_src) > get_luminance(cp_dst)) {
+ return col_src;
+ }
+
+ cp_mix[0] = Traits::divide_round(mfac * cp_src[0] + fac * cp_dst[0], Traits::range);
+ cp_mix[1] = Traits::divide_round(mfac * cp_src[1] + fac * cp_dst[1], Traits::range);
+ cp_mix[2] = Traits::divide_round(mfac * cp_src[2] + fac * cp_dst[2], Traits::range);
+ cp_mix[3] = Traits::divide_round(mfac * cp_src[3] + fac * cp_dst[3], Traits::range);
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_darken(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+ if (fac >= Traits::range) {
+ return col_dst;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ /* See if we're darker, if so mix, else don't do anything.
+ * if the paint color is brighter then the original, then ignore */
+ if (get_luminance(cp_src) < get_luminance(cp_dst)) {
+ return col_src;
+ }
+
+ cp_mix[0] = Traits::divide_round((mfac * cp_src[0] + fac * cp_dst[0]), Traits::range);
+ cp_mix[1] = Traits::divide_round((mfac * cp_src[1] + fac * cp_dst[1]), Traits::range);
+ cp_mix[2] = Traits::divide_round((mfac * cp_src[2] + fac * cp_dst[2]), Traits::range);
+ cp_mix[3] = Traits::divide_round((mfac * cp_src[3] + fac * cp_dst[3]), Traits::range);
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_colordodge(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ Blend dodgefac = (Blend)((float)Traits::range * 0.885f); /* ~225/255 */
+
+ temp = (cp_dst[0] == Traits::range) ?
+ Traits::range :
+ Traits::min((cp_src[0] * dodgefac) / (Traits::range - cp_dst[0]), Traits::range);
+ cp_mix[0] = (mfac * cp_src[0] + temp * fac) / Traits::range;
+ temp = (cp_dst[1] == Traits::range) ?
+ Traits::range :
+ Traits::min((cp_src[1] * dodgefac) / (Traits::range - cp_dst[1]), Traits::range);
+ cp_mix[1] = (mfac * cp_src[1] + temp * fac) / Traits::range;
+ temp = (cp_dst[2] == Traits::range) ?
+ Traits::range :
+ Traits::min((cp_src[2] * dodgefac) / (Traits::range - cp_dst[2]), Traits::range);
+ cp_mix[2] = (mfac * cp_src[2] + temp * fac) / Traits::range;
+ temp = (cp_dst[3] == Traits::range) ?
+ Traits::range :
+ Traits::min((cp_src[3] * dodgefac) / (Traits::range - cp_dst[3]), Traits::range);
+ cp_mix[3] = (mfac * cp_src[3] + temp * fac) / Traits::range;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_difference(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ temp = abs(cp_src[0] - cp_dst[0]);
+ cp_mix[0] = (mfac * cp_src[0] + temp * fac) / Traits::range;
+ temp = abs(cp_src[1] - cp_dst[1]);
+ cp_mix[1] = (mfac * cp_src[1] + temp * fac) / Traits::range;
+ temp = abs(cp_src[2] - cp_dst[2]);
+ cp_mix[2] = (mfac * cp_src[2] + temp * fac) / Traits::range;
+ temp = abs(cp_src[3] - cp_dst[3]);
+ cp_mix[3] = (mfac * cp_src[3] + temp * fac) / Traits::range;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_screen(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ temp = Traits::max(Traits::range - (((Traits::range - cp_src[0]) * (Traits::range - cp_dst[0])) /
+ Traits::range),
+ 0);
+ cp_mix[0] = (mfac * cp_src[0] + temp * fac) / Traits::range;
+ temp = Traits::max(Traits::range - (((Traits::range - cp_src[1]) * (Traits::range - cp_dst[1])) /
+ Traits::range),
+ 0);
+ cp_mix[1] = (mfac * cp_src[1] + temp * fac) / Traits::range;
+ temp = Traits::max(Traits::range - (((Traits::range - cp_src[2]) * (Traits::range - cp_dst[2])) /
+ Traits::range),
+ 0);
+ cp_mix[2] = (mfac * cp_src[2] + temp * fac) / Traits::range;
+ temp = Traits::max(Traits::range - (((Traits::range - cp_src[3]) * (Traits::range - cp_dst[3])) /
+ Traits::range),
+ 0);
+ cp_mix[3] = (mfac * cp_src[3] + temp * fac) / Traits::range;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_hardlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (cp_dst[i] > (Traits::range / 2)) {
+ temp = Traits::range - ((Traits::range - 2 * (cp_dst[i] - (Traits::range / 2))) *
+ (Traits::range - cp_src[i]) / Traits::range);
+ }
+ else {
+ temp = (2 * cp_dst[i] * cp_src[i]) / Traits::expandedRange;
+ }
+ cp_mix[i] = Traits::min((mfac * cp_src[i] + temp * fac) / Traits::range, Traits::range);
+ }
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_overlay(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (cp_src[i] > (Traits::range / 2)) {
+ temp = Traits::range - ((Traits::range - 2 * (cp_src[i] - (Traits::range / 2))) *
+ (Traits::range - cp_dst[i]) / Traits::range);
+ }
+ else {
+ temp = (2 * cp_dst[i] * cp_src[i]) / Traits::expandedRange;
+ }
+ cp_mix[i] = Traits::min((mfac * cp_src[i] + temp * fac) / Traits::range, Traits::range);
+ }
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_softlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ /* Use divide_round so we don't alter original byte equations. */
+ const int add = Traits::divide_round(Traits::range, 4);
+
+ for (int i = 0; i < 4; i++) {
+ if (cp_src[i] < (Traits::range / 2)) {
+ temp = ((2 * ((cp_dst[i] / 2) + add)) * cp_src[i]) / Traits::range;
+ }
+ else {
+ temp = Traits::range - (2 * (Traits::range - ((cp_dst[i] / 2) + add)) *
+ (Traits::range - cp_src[i]) / Traits::range);
+ }
+ cp_mix[i] = (temp * fac + cp_src[i] * mfac) / Traits::range;
+ }
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_exclusion(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac, temp;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ int i = 0;
+
+ for (i = 0; i < 4; i++) {
+ temp = (Traits::range / 2) -
+ ((2 * (cp_src[i] - (Traits::range / 2)) * (cp_dst[i] - (Traits::range / 2))) /
+ Traits::range);
+ cp_mix[i] = (temp * fac + cp_src[i] * mfac) / Traits::range;
+ }
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_luminosity(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(cp_src[0] / Traits::frange,
+ cp_src[1] / Traits::frange,
+ cp_src[2] / Traits::frange,
+ &h1,
+ &s1,
+ &v1);
+ rgb_to_hsv(cp_dst[0] / Traits::frange,
+ cp_dst[1] / Traits::frange,
+ cp_dst[2] / Traits::frange,
+ &h2,
+ &s2,
+ &v2);
+
+ v1 = v2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ cp_mix[0] = ((Blend)(r * Traits::frange) * fac + mfac * cp_src[0]) / Traits::range;
+ cp_mix[1] = ((Blend)(g * Traits::frange) * fac + mfac * cp_src[1]) / Traits::range;
+ cp_mix[2] = ((Blend)(b * Traits::frange) * fac + mfac * cp_src[2]) / Traits::range;
+ cp_mix[3] = ((Blend)(cp_dst[3]) * fac + mfac * cp_src[3]) / Traits::range;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_saturation(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(cp_src[0] / Traits::frange,
+ cp_src[1] / Traits::frange,
+ cp_src[2] / Traits::frange,
+ &h1,
+ &s1,
+ &v1);
+ rgb_to_hsv(cp_dst[0] / Traits::frange,
+ cp_dst[1] / Traits::frange,
+ cp_dst[2] / Traits::frange,
+ &h2,
+ &s2,
+ &v2);
+
+ if (s1 > EPS_SATURATION) {
+ s1 = s2;
+ }
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ cp_mix[0] = ((Blend)(r * Traits::frange) * fac + mfac * cp_src[0]) / Traits::range;
+ cp_mix[1] = ((Blend)(g * Traits::frange) * fac + mfac * cp_src[1]) / Traits::range;
+ cp_mix[2] = ((Blend)(b * Traits::frange) * fac + mfac * cp_src[2]) / Traits::range;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_hue(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(cp_src[0] / Traits::frange,
+ cp_src[1] / Traits::frange,
+ cp_src[2] / Traits::frange,
+ &h1,
+ &s1,
+ &v1);
+ rgb_to_hsv(cp_dst[0] / Traits::frange,
+ cp_dst[1] / Traits::frange,
+ cp_dst[2] / Traits::frange,
+ &h2,
+ &s2,
+ &v2);
+
+ h1 = h2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ cp_mix[0] = ((Blend)(r * Traits::frange) * fac + mfac * cp_src[0]) / Traits::range;
+ cp_mix[1] = ((Blend)(g * Traits::frange) * fac + mfac * cp_src[1]) / Traits::range;
+ cp_mix[2] = ((Blend)(b * Traits::frange) * fac + mfac * cp_src[2]) / Traits::range;
+ cp_mix[3] = ((Blend)(cp_dst[3]) * fac + mfac * cp_src[3]) / Traits::range;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_alpha_add(Color col_src, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_mix;
+ Blend temp;
+ Color col_mix = col_src;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ cp_src = (Value *)&col_src;
+ cp_mix = (Value *)&col_mix;
+
+ temp = cp_src[3] + fac;
+ cp_mix[3] = (temp > Traits::cmpRange) ? Traits::range : temp;
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_alpha_sub(Color col_src, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_mix;
+ Blend temp;
+ Color col_mix = col_src;
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ cp_src = (Value *)&col_src;
+ cp_mix = (Value *)&col_mix;
+
+ temp = cp_src[3] - fac;
+ cp_mix[3] = temp < 0 ? 0 : temp;
+
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_pinlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ const Blend cmp = Traits::range / 2;
+
+ int i = 3;
+ Blend temp;
+
+ while (i--) {
+ if (cp_dst[i] > cmp) {
+ temp = Traits::max(2 * (cp_dst[i] - cmp), cp_src[i]);
+ }
+ else {
+ temp = Traits::min(2 * cp_dst[i], cp_src[i]);
+ }
+ cp_mix[i] = (Value)((Traits::min(temp, Traits::range) * fac + cp_src[i] * mfac) /
+ Traits::range);
+ }
+
+ col_mix.a = col_src.a;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_linearlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ const Blend cmp = Traits::range / 2;
+
+ int i = 3;
+ while (i--) {
+ Blend temp;
+
+ if (cp_dst[i] > cmp) {
+ temp = Traits::min(cp_src[i] + 2 * (cp_dst[i] - cmp), Traits::range);
+ }
+ else {
+ temp = Traits::max(cp_src[i] + 2 * cp_dst[i] - Traits::range, 0);
+ }
+
+ cp_mix[i] = (Value)((temp * fac + cp_src[i] * mfac) / Traits::range);
+ }
+
+ col_mix.a = col_src.a;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_vividlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+
+ const Blend cmp = Traits::range / 2;
+
+ int i = 3;
+
+ while (i--) {
+ Blend temp;
+
+ if (cp_dst[i] == Traits::range) {
+ temp = (cp_src[i] == 0) ? cmp : Traits::range;
+ }
+ else if (cp_dst[i] == 0) {
+ temp = (cp_src[i] == Traits::range) ? cmp : 0;
+ }
+ else if (cp_dst[i] > cmp) {
+ temp = Traits::min(((cp_src[i]) * Traits::range) / (2 * (Traits::range - cp_dst[i])),
+ Traits::range);
+ }
+ else {
+ temp = Traits::max(
+ Traits::range - ((Traits::range - cp_src[i]) * Traits::range / (2 * cp_dst[i])), 0);
+ }
+ col_mix[i] = (Value)((temp * fac + cp_src[i] * mfac) / Traits::range);
+ }
+
+ col_mix.a = col_src.a;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_color(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+
+ rgb_to_hsv(cp_src[0] / Traits::frange,
+ cp_src[1] / Traits::frange,
+ cp_src[2] / Traits::frange,
+ &h1,
+ &s1,
+ &v1);
+ rgb_to_hsv(cp_dst[0] / Traits::frange,
+ cp_dst[1] / Traits::frange,
+ cp_dst[2] / Traits::frange,
+ &h2,
+ &s2,
+ &v2);
+
+ h1 = h2;
+ s1 = s2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ cp_mix[0] = (Value)(((Blend)(r * Traits::frange) * fac + cp_src[0] * mfac) / Traits::range);
+ cp_mix[1] = (Value)(((Blend)(g * Traits::frange) * fac + cp_src[1] * mfac) / Traits::range);
+ cp_mix[2] = (Value)(((Blend)(b * Traits::frange) * fac + cp_src[2] * mfac) / Traits::range);
+
+ col_mix.a = col_src.a;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_colorburn(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ int i = 3;
+
+ while (i--) {
+ const Blend temp =
+ (cp_dst[i] == 0) ?
+ 0 :
+ Traits::max(Traits::range - ((Traits::range - cp_src[i]) * Traits::range) / cp_dst[i],
+ 0);
+ cp_mix[i] = (Value)((temp * fac + cp_src[i] * mfac) / Traits::range);
+ }
+
+ col_mix.a = col_src.a;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+static Color mix_linearburn(Color col_src, Color col_dst, typename Traits::BlendType fac)
+{
+ using Value = typename Traits::ValueType;
+ using Blend = typename Traits::BlendType;
+
+ Value *cp_src, *cp_dst, *cp_mix;
+ Blend mfac;
+ Color col_mix(0, 0, 0, 0);
+
+ if (fac == 0) {
+ return col_src;
+ }
+
+ mfac = Traits::range - fac;
+
+ cp_src = (Value *)&col_src;
+ cp_dst = (Value *)&col_dst;
+ cp_mix = (Value *)&col_mix;
+
+ int i = 3;
+
+ while (i--) {
+ const Blend temp = Traits::max(cp_src[i] + cp_dst[i] - Traits::range, 0);
+ cp_mix[i] = (Value)((temp * fac + cp_src[i] * mfac) / Traits::range);
+ }
+
+ col_mix.a = col_src.a;
+ return col_mix;
+}
+
+template<typename Color, typename Traits>
+BLI_INLINE Color BLI_mix_colors(const IMB_BlendMode tool,
+ const Color a,
+ const Color b,
+ const typename Traits::BlendType alpha)
+{
+ switch ((IMB_BlendMode)tool) {
+ case IMB_BLEND_MIX:
+ return mix_blend<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_ADD:
+ return mix_add<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_SUB:
+ return mix_sub<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_MUL:
+ return mix_mul<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_LIGHTEN:
+ return mix_lighten<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_DARKEN:
+ return mix_darken<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_COLORDODGE:
+ return mix_colordodge<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_COLORBURN:
+ return mix_colorburn<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_DIFFERENCE:
+ return mix_difference<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_SCREEN:
+ return mix_screen<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_HARDLIGHT:
+ return mix_hardlight<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_OVERLAY:
+ return mix_overlay<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_SOFTLIGHT:
+ return mix_softlight<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_EXCLUSION:
+ return mix_exclusion<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_LUMINOSITY:
+ return mix_luminosity<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_SATURATION:
+ return mix_saturation<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_HUE:
+ return mix_hue<Color, Traits>(a, b, alpha);
+ /* non-color */
+ case IMB_BLEND_ERASE_ALPHA:
+ return mix_alpha_sub<Color, Traits>(a, alpha);
+ case IMB_BLEND_ADD_ALPHA:
+ return mix_alpha_add<Color, Traits>(a, alpha);
+ case IMB_BLEND_PINLIGHT:
+ return mix_pinlight<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_LINEARLIGHT:
+ return mix_linearlight<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_VIVIDLIGHT:
+ return mix_vividlight<Color, Traits>(a, b, alpha);
+ case IMB_BLEND_COLOR:
+ return mix_color<Color, Traits>(a, b, alpha);
+ default:
+ BLI_assert(0);
+ return Color(0, 0, 0, 0);
+ }
+}
+/** \} */
+
+} // namespace blender::color
diff --git a/source/blender/blenlib/BLI_generic_virtual_array.hh b/source/blender/blenlib/BLI_generic_virtual_array.hh
index 4aed1caf796..2e756e912f9 100644
--- a/source/blender/blenlib/BLI_generic_virtual_array.hh
+++ b/source/blender/blenlib/BLI_generic_virtual_array.hh
@@ -854,14 +854,14 @@ template<typename T> inline GVArray::GVArray(const VArray<T> &varray)
if (varray.may_have_ownership()) {
*this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
}
- else if (varray.is_span()) {
- Span<T> data = varray.get_internal_span();
- *this = GVArray::ForSpan(data);
- }
else if (varray.is_single()) {
T value = varray.get_internal_single();
*this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), &value);
}
+ else if (varray.is_span()) {
+ Span<T> data = varray.get_internal_span();
+ *this = GVArray::ForSpan(data);
+ }
else {
*this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
}
@@ -880,15 +880,15 @@ template<typename T> inline VArray<T> GVArray::typed() const
if (this->may_have_ownership()) {
return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
}
- if (this->is_span()) {
- const Span<T> span = this->get_internal_span().typed<T>();
- return VArray<T>::ForSpan(span);
- }
if (this->is_single()) {
T value;
this->get_internal_single(&value);
return VArray<T>::ForSingle(value, this->size());
}
+ if (this->is_span()) {
+ const Span<T> span = this->get_internal_span().typed<T>();
+ return VArray<T>::ForSpan(span);
+ }
return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
}
diff --git a/source/blender/blenlib/BLI_math_base.hh b/source/blender/blenlib/BLI_math_base.hh
index 83f414f853a..81f5343056e 100644
--- a/source/blender/blenlib/BLI_math_base.hh
+++ b/source/blender/blenlib/BLI_math_base.hh
@@ -102,7 +102,10 @@ template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> inline T fract(cons
return a - std::floor(a);
}
-template<typename T, typename FactorT, BLI_ENABLE_IF((is_math_float_type<FactorT>))>
+template<typename T,
+ typename FactorT,
+ BLI_ENABLE_IF((std::is_arithmetic_v<T>)),
+ BLI_ENABLE_IF((is_math_float_type<FactorT>))>
inline T interpolate(const T &a, const T &b, const FactorT &t)
{
return a * (1 - t) + b * t;
diff --git a/source/blender/blenlib/BLI_math_color.hh b/source/blender/blenlib/BLI_math_color.hh
index 5195cfb6238..b16053509cf 100644
--- a/source/blender/blenlib/BLI_math_color.hh
+++ b/source/blender/blenlib/BLI_math_color.hh
@@ -15,9 +15,22 @@
namespace blender::math {
-inline ColorGeometry4f interpolate(const ColorGeometry4f &a,
- const ColorGeometry4f &b,
- const float t)
+template<eAlpha Alpha>
+inline ColorSceneLinear4f<Alpha> interpolate(const ColorSceneLinear4f<Alpha> &a,
+ const ColorSceneLinear4f<Alpha> &b,
+ const float t)
+{
+ return {math::interpolate(a.r, b.r, t),
+ math::interpolate(a.g, b.g, t),
+ math::interpolate(a.b, b.b, t),
+ math::interpolate(a.a, b.a, t)};
+}
+
+template<eAlpha Alpha>
+inline ColorSceneLinearByteEncoded4b<Alpha> interpolate(
+ const ColorSceneLinearByteEncoded4b<Alpha> &a,
+ const ColorSceneLinearByteEncoded4b<Alpha> &b,
+ const float t)
{
return {math::interpolate(a.r, b.r, t),
math::interpolate(a.g, b.g, t),
diff --git a/source/blender/blenlib/BLI_math_vec_types.hh b/source/blender/blenlib/BLI_math_vec_types.hh
index 0850864d86f..e36bbedee32 100644
--- a/source/blender/blenlib/BLI_math_vec_types.hh
+++ b/source/blender/blenlib/BLI_math_vec_types.hh
@@ -201,6 +201,14 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size>
}
}
+ template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
+ explicit vec_base(const U *ptr)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = ptr[i];
+ }
+ }
+
vec_base(const T (*ptr)[Size]) : vec_base(static_cast<const T *>(ptr[0]))
{
}
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index 27bb04f5796..453ca67b1e0 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -780,9 +780,6 @@ template<typename T> class VArrayCommon {
Span<T> get_internal_span() const
{
BLI_assert(this->is_span());
- if (this->is_empty()) {
- return {};
- }
return impl_->get_internal_span();
}
@@ -800,9 +797,6 @@ template<typename T> class VArrayCommon {
T get_internal_single() const
{
BLI_assert(this->is_single());
- if (impl_->size() == 1) {
- return impl_->get(0);
- }
return impl_->get_internal_single();
}
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index e8a3851e082..446a027b03b 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -171,6 +171,7 @@ set(SRC
BLI_boxpack_2d.h
BLI_buffer.h
BLI_color.hh
+ BLI_color_mix.hh
BLI_compiler_attrs.h
BLI_compiler_compat.h
BLI_compiler_typecheck.h
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 26a0479f445..5ca6fe2efd0 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -301,56 +301,60 @@ static bool delete_soft(const wchar_t *path_16, const char **error_message)
/* Deletes file or directory to recycling bin. The latter moves all contained files and
* directories recursively to the recycling bin as well. */
IFileOperation *pfo;
- IShellItem *pSI;
+ IShellItem *psi;
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
- if (FAILED(hr)) {
- *error_message = "Failed to initialize COM";
- goto error_1;
- }
-
- hr = CoCreateInstance(
- &CLSID_FileOperation, NULL, CLSCTX_ALL, &IID_IFileOperation, (void **)&pfo);
- if (FAILED(hr)) {
- *error_message = "Failed to create FileOperation instance";
- goto error_2;
- }
-
- /* Flags for deletion:
- * FOF_ALLOWUNDO: Enables moving file to recycling bin.
- * FOF_SILENT: Don't show progress dialog box.
- * FOF_WANTNUKEWARNING: Show dialog box if file can't be moved to recycling bin. */
- hr = pfo->lpVtbl->SetOperationFlags(pfo, FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING);
-
- if (FAILED(hr)) {
- *error_message = "Failed to set operation flags";
- goto error_2;
- }
-
- hr = SHCreateItemFromParsingName(path_16, NULL, &IID_IShellItem, (void **)&pSI);
- if (FAILED(hr)) {
- *error_message = "Failed to parse path";
- goto error_2;
- }
-
- hr = pfo->lpVtbl->DeleteItem(pfo, pSI, NULL);
- if (FAILED(hr)) {
- *error_message = "Failed to prepare delete operation";
- goto error_2;
+ if (SUCCEEDED(hr)) {
+ /* This is also the case when COM was previously initialized and CoInitializeEx returns
+ * S_FALSE, which is not an error. Both HRESULT values S_OK and S_FALSE indicate success. */
+
+ hr = CoCreateInstance(
+ &CLSID_FileOperation, NULL, CLSCTX_ALL, &IID_IFileOperation, (void **)&pfo);
+
+ if (SUCCEEDED(hr)) {
+ /* Flags for deletion:
+ * FOF_ALLOWUNDO: Enables moving file to recycling bin.
+ * FOF_SILENT: Don't show progress dialog box.
+ * FOF_WANTNUKEWARNING: Show dialog box if file can't be moved to recycling bin. */
+ hr = pfo->lpVtbl->SetOperationFlags(pfo, FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING);
+
+ if (SUCCEEDED(hr)) {
+ hr = SHCreateItemFromParsingName(path_16, NULL, &IID_IShellItem, (void **)&psi);
+
+ if (SUCCEEDED(hr)) {
+ hr = pfo->lpVtbl->DeleteItem(pfo, psi, NULL);
+
+ if (SUCCEEDED(hr)) {
+ hr = pfo->lpVtbl->PerformOperations(pfo);
+
+ if (FAILED(hr)) {
+ *error_message = "Failed to prepare delete operation";
+ }
+ }
+ else {
+ *error_message = "Failed to prepare delete operation";
+ }
+ psi->lpVtbl->Release(psi);
+ }
+ else {
+ *error_message = "Failed to parse path";
+ }
+ }
+ else {
+ *error_message = "Failed to set operation flags";
+ }
+ pfo->lpVtbl->Release(pfo);
+ }
+ else {
+ *error_message = "Failed to create FileOperation instance";
+ }
+ CoUninitialize();
}
-
- hr = pfo->lpVtbl->PerformOperations(pfo);
-
- if (FAILED(hr)) {
- *error_message = "Failed to delete file or directory";
+ else {
+ *error_message = "Failed to initialize COM";
}
-error_2:
- pfo->lpVtbl->Release(pfo);
- CoUninitialize(); /* Has to be uninitialized when CoInitializeEx returns either S_OK or S_FALSE
- */
-error_1:
return FAILED(hr);
}