Vulkan: Push constants #104880
|
@ -7726,22 +7726,6 @@
|
|||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccccccc" />
|
||||
</g>
|
||||
<g
|
||||
id="g3791"
|
||||
inkscape:label="CA-24">
|
||||
<path
|
||||
sodipodi:nodetypes="csssscccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path28911-6"
|
||||
d="m 489,604 v 8 c 0,0.54532 0.45468,1 1,1 h 12 c 0.54532,0 1,-0.45468 1,-1 v -8 h -1 v 8 h -12 v -8 z"
|
||||
style="opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
|
||||
<path
|
||||
sodipodi:nodetypes="ssccccsssccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
style="vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
|
||||
d="m 490,599 c -0.54532,0 -1,0.45468 -1,1 v 3 h 1 12 1 v -3 c 0,-0.54532 -0.45468,-1 -1,-1 z m 0,1 h 2 v 2 h -2 z"
|
||||
id="path28913-4" />
|
||||
</g>
|
||||
<g
|
||||
style="display:inline;enable-background:new"
|
||||
id="g28909-7"
|
||||
|
@ -7762,6 +7746,22 @@
|
|||
transform="matrix(1,0,0,-1,520,1334)"
|
||||
id="path28907-4" />
|
||||
</g>
|
||||
<g
|
||||
id="g3791"
|
||||
inkscape:label="CA-24">
|
||||
<path
|
||||
sodipodi:nodetypes="csssscccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path28911-6"
|
||||
d="m 489,604 v 8 c 0,0.54532 0.45468,1 1,1 h 12 c 0.54532,0 1,-0.45468 1,-1 v -8 h -1 v 8 h -12 v -8 z"
|
||||
style="opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
|
||||
<path
|
||||
sodipodi:nodetypes="ssccccsssccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
style="vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
|
||||
d="m 490,599 c -0.54532,0 -1,0.45468 -1,1 v 3 h 1 12 1 v -3 c 0,-0.54532 -0.45468,-1 -1,-1 z m 0,1 h 2 v 2 h -2 z"
|
||||
id="path28913-4" />
|
||||
</g>
|
||||
<g
|
||||
id="g9239"
|
||||
inkscape:label="CA-23"
|
||||
|
@ -13113,6 +13113,40 @@
|
|||
d="m 221.03217,109.33958 c 0.67621,0.01 0.67621,-1.00961 0,-1 h -2.79493 c 1.0479,-1.11729 1.7641,-1.66802 2.82812,-2.73204 0.62065,-0.56444 -0.28321,-1.46832 -0.84765,-0.84766 -1.06063,1.10128 -1.59202,1.7772 -2.68554,2.87072 v -2.79102 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 4 c 3e-5,0.27613 0.22387,0.49998 0.5,0.5 z"
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||
</g>
|
||||
<g
|
||||
id="g24638"
|
||||
inkscape:label="O-18"
|
||||
style="display:inline;enable-background:new">
|
||||
<path
|
||||
style="color:#000000;opacity:1;fill:none;stroke:#ffffff;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;-inkscape-stroke:none"
|
||||
d="m 374.12695,305.31445 c -1.10721,0 -1.93616,0.24199 -2.97851,0.63086 -1.04236,0.38888 -2.18224,0.95849 -3.30078,1.77735 -2.2371,1.63771 -4.46485,4.54533 -4.46485,8.40625 a 3.0581999,3.0581999 0 0 0 3.0586,3.05859 3.0581999,3.0581999 0 0 0 3.05859,-3.05859 c 0,-1.63187 0.77567,-2.603 1.96094,-3.47071 0.59263,-0.43385 1.26841,-0.77311 1.82422,-0.98047 0.5558,-0.20735 1.10962,-0.24804 0.84179,-0.24804 a 3.0581999,3.0581999 0 0 0 3.05664,-3.0586 3.0581999,3.0581999 0 0 0 -3.05664,-3.05664 z"
|
||||
id="path6454-6" />
|
||||
<path
|
||||
style="display:inline;opacity:0.5;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
|
||||
d="m 366.4419,316.12916 c 0,-5.49278 6.00534,-7.75723 7.68412,-7.75723"
|
||||
id="path15424"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
<g
|
||||
id="g24643"
|
||||
inkscape:label="O-17"
|
||||
style="display:inline;enable-background:new">
|
||||
<path
|
||||
style="opacity:0.5;fill:#ffffff;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 343.45275,317.52104 4.51631,-3.99333"
|
||||
id="path4694"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 342.44508,318.83525 c 14.125,0.14581 -0.42233,-12.9179 13.5429,-12.85486"
|
||||
id="path6454"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="opacity:0.5;fill:#ffffff;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 350.84964,311.18794 4.21454,-3.72502"
|
||||
id="path19640"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
<g
|
||||
style="display:inline;enable-background:new"
|
||||
id="g28812"
|
||||
|
@ -18997,36 +19031,6 @@
|
|||
id="path4817-4"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
id="g24638">
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke-linecap:round;-inkscape-stroke:none;opacity:1;stroke:#ffffff;stroke-opacity:1;stroke-linejoin:round"
|
||||
d="m 374.12695,305.31445 c -1.10721,0 -1.93616,0.24199 -2.97851,0.63086 -1.04236,0.38888 -2.18224,0.95849 -3.30078,1.77735 -2.2371,1.63771 -4.46485,4.54533 -4.46485,8.40625 a 3.0581999,3.0581999 0 0 0 3.0586,3.05859 3.0581999,3.0581999 0 0 0 3.05859,-3.05859 c 0,-1.63187 0.77567,-2.603 1.96094,-3.47071 0.59263,-0.43385 1.26841,-0.77311 1.82422,-0.98047 0.5558,-0.20735 1.10962,-0.24804 0.84179,-0.24804 a 3.0581999,3.0581999 0 0 0 3.05664,-3.0586 3.0581999,3.0581999 0 0 0 -3.05664,-3.05664 z"
|
||||
id="path6454-6" />
|
||||
<path
|
||||
style="display:inline;opacity:0.5;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
|
||||
d="m 366.4419,316.12916 c 0,-5.49278 6.00534,-7.75723 7.68412,-7.75723"
|
||||
id="path15424"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
<g
|
||||
id="g24643">
|
||||
<path
|
||||
style="opacity:0.5;fill:#ffffff;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 343.45275,317.52104 4.51631,-3.99333"
|
||||
id="path4694"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 342.44508,318.83525 c 14.125,0.14581 -0.42233,-12.9179 13.5429,-12.85486"
|
||||
id="path6454"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="opacity:0.5;fill:#ffffff;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 350.84964,311.18794 4.21454,-3.72502"
|
||||
id="path19640"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
|
|
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 2.5 MiB |
|
@ -101,7 +101,11 @@ const UserDef U_default = {
|
|||
.gp_euclideandist = 2,
|
||||
.gp_eraser = 25,
|
||||
.gp_settings = 0,
|
||||
#ifdef __APPLE__
|
||||
.gpu_backend = GPU_BACKEND_METAL,
|
||||
#else
|
||||
.gpu_backend = GPU_BACKEND_OPENGL,
|
||||
#endif
|
||||
|
||||
/** Initialized by: #BKE_studiolight_default. */
|
||||
.light_param = {{0}},
|
||||
|
|
|
@ -397,7 +397,7 @@ class ConstraintButtonsPanel:
|
|||
sub.prop(con, "invert_z", text="Z", toggle=True)
|
||||
row.label(icon='BLANK1')
|
||||
|
||||
layout.prop(con, "mix_mode", text="Mix")
|
||||
layout.prop(con, "mix_mode", text="Mix", text_ctxt=i18n_contexts.constraint)
|
||||
|
||||
self.space_template(layout, con)
|
||||
|
||||
|
@ -488,7 +488,7 @@ class ConstraintButtonsPanel:
|
|||
self.target_template(layout, con)
|
||||
|
||||
layout.prop(con, "remove_target_shear")
|
||||
layout.prop(con, "mix_mode", text="Mix")
|
||||
layout.prop(con, "mix_mode", text="Mix", text_ctxt=i18n_contexts.constraint)
|
||||
|
||||
self.space_template(layout, con)
|
||||
|
||||
|
@ -513,7 +513,7 @@ class ConstraintButtonsPanel:
|
|||
subsub.prop(con, "eval_time", text="")
|
||||
row.prop_decorator(con, "eval_time")
|
||||
|
||||
layout.prop(con, "mix_mode", text="Mix")
|
||||
layout.prop(con, "mix_mode", text="Mix", text_ctxt=i18n_contexts.constraint)
|
||||
|
||||
self.draw_influence(layout, con)
|
||||
|
||||
|
@ -1024,7 +1024,7 @@ class ConstraintButtonsSubPanel:
|
|||
col.prop(con, "to_min_z" + ext, text="Min")
|
||||
col.prop(con, "to_max_z" + ext, text="Max")
|
||||
|
||||
layout.prop(con, "mix_mode" + ext, text="Mix")
|
||||
layout.prop(con, "mix_mode" + ext, text="Mix", text_ctxt=i18n_contexts.constraint)
|
||||
|
||||
def draw_armature_bones(self, context):
|
||||
layout = self.layout
|
||||
|
|
|
@ -98,6 +98,7 @@ class NodeMultiFunctionBuilder;
|
|||
class GeoNodeExecParams;
|
||||
class NodeDeclaration;
|
||||
class NodeDeclarationBuilder;
|
||||
class GatherAddNodeSearchParams;
|
||||
class GatherLinkSearchOpParams;
|
||||
} // namespace nodes
|
||||
namespace realtime_compositor {
|
||||
|
@ -122,6 +123,10 @@ using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket
|
|||
using NodeGatherSocketLinkOperationsFunction =
|
||||
void (*)(blender::nodes::GatherLinkSearchOpParams ¶ms);
|
||||
|
||||
/* Adds node add menu operations that are specific to this node type. */
|
||||
using NodeGatherAddOperationsFunction =
|
||||
void (*)(blender::nodes::GatherAddNodeSearchParams ¶ms);
|
||||
|
||||
using NodeGetCompositorOperationFunction = blender::realtime_compositor::NodeOperation
|
||||
*(*)(blender::realtime_compositor::Context &context, blender::nodes::DNode node);
|
||||
using NodeGetCompositorShaderNodeFunction =
|
||||
|
@ -135,6 +140,7 @@ typedef void *NodeGeometryExecFunction;
|
|||
typedef void *NodeDeclareFunction;
|
||||
typedef void *NodeDeclareDynamicFunction;
|
||||
typedef void *NodeGatherSocketLinkOperationsFunction;
|
||||
typedef void *NodeGatherAddOperationsFunction;
|
||||
typedef void *SocketGetCPPTypeFunction;
|
||||
typedef void *SocketGetGeometryNodesCPPTypeFunction;
|
||||
typedef void *SocketGetGeometryNodesCPPValueFunction;
|
||||
|
@ -353,6 +359,13 @@ typedef struct bNodeType {
|
|||
*/
|
||||
NodeGatherSocketLinkOperationsFunction gather_link_search_ops;
|
||||
|
||||
/**
|
||||
* Add to the list of search items gathered by the add-node search. The default behavior of
|
||||
* adding a single item with the node name is usually enough, but node types can have any number
|
||||
* of custom search items.
|
||||
*/
|
||||
NodeGatherAddOperationsFunction gather_add_node_search_ops;
|
||||
|
||||
/** True when the node cannot be muted. */
|
||||
bool no_muting;
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include "BKE_particle.h"
|
||||
#include "BLI_kdopbvh.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "BKE_modifier.h"
|
||||
|
||||
#include "RNA_enum_types.h"
|
||||
|
@ -1607,7 +1609,7 @@ BoidRule *boid_new_rule(int type)
|
|||
|
||||
rule->type = type;
|
||||
rule->flag |= BOIDRULE_IN_AIR | BOIDRULE_ON_LAND;
|
||||
BLI_strncpy(rule->name, rna_enum_boidrule_type_items[type - 1].name, sizeof(rule->name));
|
||||
BLI_strncpy(rule->name, DATA_(rna_enum_boidrule_type_items[type - 1].name), sizeof(rule->name));
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
|
|
@ -508,6 +508,7 @@ static void prepare_inferencing_interfaces(
|
|||
|
||||
bool update_field_inferencing(const bNodeTree &tree)
|
||||
{
|
||||
BLI_assert(tree.type == NTREE_GEOMETRY);
|
||||
tree.ensure_topology_cache();
|
||||
|
||||
const Span<const bNode *> nodes = tree.all_nodes();
|
||||
|
|
|
@ -142,6 +142,18 @@ double BLI_dir_free_space(const char *dir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(
|
|||
*/
|
||||
char *BLI_current_working_dir(char *dir, size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
|
||||
eFileAttributes BLI_file_attributes(const char *path);
|
||||
/**
|
||||
* Changes the current working directory to the provided path.
|
||||
*
|
||||
* Usage of this function is strongly discouraged as it is not thread safe. It will likely cause
|
||||
* issues if there is an operation on another thread that does not expect the current working
|
||||
* directory to change. This has been added to support USDZ export, which has a problematic
|
||||
* "feature" described in this issue https://projects.blender.org/blender/blender/issues/99807. It
|
||||
* will be removed if it is possible to resolve that issue upstream in the USD library.
|
||||
*
|
||||
* \return true on success, false otherwise.
|
||||
*/
|
||||
bool BLI_change_working_dir(const char *dir);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -504,8 +504,9 @@ void _va_mul_m3_series_4(float r[3][3],
|
|||
const float m2[3][3],
|
||||
const float m3[3][3])
|
||||
{
|
||||
mul_m3_m3m3(r, m1, m2);
|
||||
mul_m3_m3m3(r, r, m3);
|
||||
float s[3][3];
|
||||
mul_m3_m3m3(s, m1, m2);
|
||||
mul_m3_m3m3(r, s, m3);
|
||||
}
|
||||
void _va_mul_m3_series_5(float r[3][3],
|
||||
const float m1[3][3],
|
||||
|
@ -513,9 +514,11 @@ void _va_mul_m3_series_5(float r[3][3],
|
|||
const float m3[3][3],
|
||||
const float m4[3][3])
|
||||
{
|
||||
mul_m3_m3m3(r, m1, m2);
|
||||
mul_m3_m3m3(r, r, m3);
|
||||
mul_m3_m3m3(r, r, m4);
|
||||
float s[3][3];
|
||||
float t[3][3];
|
||||
mul_m3_m3m3(s, m1, m2);
|
||||
mul_m3_m3m3(t, s, m3);
|
||||
mul_m3_m3m3(r, t, m4);
|
||||
}
|
||||
void _va_mul_m3_series_6(float r[3][3],
|
||||
const float m1[3][3],
|
||||
|
@ -524,10 +527,12 @@ void _va_mul_m3_series_6(float r[3][3],
|
|||
const float m4[3][3],
|
||||
const float m5[3][3])
|
||||
{
|
||||
mul_m3_m3m3(r, m1, m2);
|
||||
mul_m3_m3m3(r, r, m3);
|
||||
mul_m3_m3m3(r, r, m4);
|
||||
mul_m3_m3m3(r, r, m5);
|
||||
float s[3][3];
|
||||
float t[3][3];
|
||||
mul_m3_m3m3(s, m1, m2);
|
||||
mul_m3_m3m3(t, s, m3);
|
||||
mul_m3_m3m3(s, t, m4);
|
||||
mul_m3_m3m3(r, s, m5);
|
||||
}
|
||||
void _va_mul_m3_series_7(float r[3][3],
|
||||
const float m1[3][3],
|
||||
|
@ -537,11 +542,13 @@ void _va_mul_m3_series_7(float r[3][3],
|
|||
const float m5[3][3],
|
||||
const float m6[3][3])
|
||||
{
|
||||
mul_m3_m3m3(r, m1, m2);
|
||||
mul_m3_m3m3(r, r, m3);
|
||||
mul_m3_m3m3(r, r, m4);
|
||||
mul_m3_m3m3(r, r, m5);
|
||||
mul_m3_m3m3(r, r, m6);
|
||||
float s[3][3];
|
||||
float t[3][3];
|
||||
mul_m3_m3m3(s, m1, m2);
|
||||
mul_m3_m3m3(t, s, m3);
|
||||
mul_m3_m3m3(s, t, m4);
|
||||
mul_m3_m3m3(t, s, m5);
|
||||
mul_m3_m3m3(r, t, m6);
|
||||
}
|
||||
void _va_mul_m3_series_8(float r[3][3],
|
||||
const float m1[3][3],
|
||||
|
@ -552,12 +559,14 @@ void _va_mul_m3_series_8(float r[3][3],
|
|||
const float m6[3][3],
|
||||
const float m7[3][3])
|
||||
{
|
||||
mul_m3_m3m3(r, m1, m2);
|
||||
mul_m3_m3m3(r, r, m3);
|
||||
mul_m3_m3m3(r, r, m4);
|
||||
mul_m3_m3m3(r, r, m5);
|
||||
mul_m3_m3m3(r, r, m6);
|
||||
mul_m3_m3m3(r, r, m7);
|
||||
float s[3][3];
|
||||
float t[3][3];
|
||||
mul_m3_m3m3(s, m1, m2);
|
||||
mul_m3_m3m3(t, s, m3);
|
||||
mul_m3_m3m3(s, t, m4);
|
||||
mul_m3_m3m3(t, s, m5);
|
||||
mul_m3_m3m3(s, t, m6);
|
||||
mul_m3_m3m3(r, s, m7);
|
||||
}
|
||||
void _va_mul_m3_series_9(float r[3][3],
|
||||
const float m1[3][3],
|
||||
|
@ -569,13 +578,15 @@ void _va_mul_m3_series_9(float r[3][3],
|
|||
const float m7[3][3],
|
||||
const float m8[3][3])
|
||||
{
|
||||
mul_m3_m3m3(r, m1, m2);
|
||||
mul_m3_m3m3(r, r, m3);
|
||||
mul_m3_m3m3(r, r, m4);
|
||||
mul_m3_m3m3(r, r, m5);
|
||||
mul_m3_m3m3(r, r, m6);
|
||||
mul_m3_m3m3(r, r, m7);
|
||||
mul_m3_m3m3(r, r, m8);
|
||||
float s[3][3];
|
||||
float t[3][3];
|
||||
mul_m3_m3m3(s, m1, m2);
|
||||
mul_m3_m3m3(t, s, m3);
|
||||
mul_m3_m3m3(s, t, m4);
|
||||
mul_m3_m3m3(t, s, m5);
|
||||
mul_m3_m3m3(s, t, m6);
|
||||
mul_m3_m3m3(t, s, m7);
|
||||
mul_m3_m3m3(r, t, m8);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -593,8 +604,9 @@ void _va_mul_m4_series_4(float r[4][4],
|
|||
const float m2[4][4],
|
||||
const float m3[4][4])
|
||||
{
|
||||
mul_m4_m4m4(r, m1, m2);
|
||||
mul_m4_m4m4(r, r, m3);
|
||||
float s[4][4];
|
||||
mul_m4_m4m4(s, m1, m2);
|
||||
mul_m4_m4m4(r, s, m3);
|
||||
}
|
||||
void _va_mul_m4_series_5(float r[4][4],
|
||||
const float m1[4][4],
|
||||
|
@ -602,9 +614,11 @@ void _va_mul_m4_series_5(float r[4][4],
|
|||
const float m3[4][4],
|
||||
const float m4[4][4])
|
||||
{
|
||||
mul_m4_m4m4(r, m1, m2);
|
||||
mul_m4_m4m4(r, r, m3);
|
||||
mul_m4_m4m4(r, r, m4);
|
||||
float s[4][4];
|
||||
float t[4][4];
|
||||
mul_m4_m4m4(s, m1, m2);
|
||||
mul_m4_m4m4(t, s, m3);
|
||||
mul_m4_m4m4(r, t, m4);
|
||||
}
|
||||
void _va_mul_m4_series_6(float r[4][4],
|
||||
const float m1[4][4],
|
||||
|
@ -613,10 +627,12 @@ void _va_mul_m4_series_6(float r[4][4],
|
|||
const float m4[4][4],
|
||||
const float m5[4][4])
|
||||
{
|
||||
mul_m4_m4m4(r, m1, m2);
|
||||
mul_m4_m4m4(r, r, m3);
|
||||
mul_m4_m4m4(r, r, m4);
|
||||
mul_m4_m4m4(r, r, m5);
|
||||
float s[4][4];
|
||||
float t[4][4];
|
||||
mul_m4_m4m4(s, m1, m2);
|
||||
mul_m4_m4m4(t, s, m3);
|
||||
mul_m4_m4m4(s, t, m4);
|
||||
mul_m4_m4m4(r, s, m5);
|
||||
}
|
||||
void _va_mul_m4_series_7(float r[4][4],
|
||||
const float m1[4][4],
|
||||
|
@ -626,11 +642,13 @@ void _va_mul_m4_series_7(float r[4][4],
|
|||
const float m5[4][4],
|
||||
const float m6[4][4])
|
||||
{
|
||||
mul_m4_m4m4(r, m1, m2);
|
||||
mul_m4_m4m4(r, r, m3);
|
||||
mul_m4_m4m4(r, r, m4);
|
||||
mul_m4_m4m4(r, r, m5);
|
||||
mul_m4_m4m4(r, r, m6);
|
||||
float s[4][4];
|
||||
float t[4][4];
|
||||
mul_m4_m4m4(s, m1, m2);
|
||||
mul_m4_m4m4(t, s, m3);
|
||||
mul_m4_m4m4(s, t, m4);
|
||||
mul_m4_m4m4(t, s, m5);
|
||||
mul_m4_m4m4(r, t, m6);
|
||||
}
|
||||
void _va_mul_m4_series_8(float r[4][4],
|
||||
const float m1[4][4],
|
||||
|
@ -641,12 +659,14 @@ void _va_mul_m4_series_8(float r[4][4],
|
|||
const float m6[4][4],
|
||||
const float m7[4][4])
|
||||
{
|
||||
mul_m4_m4m4(r, m1, m2);
|
||||
mul_m4_m4m4(r, r, m3);
|
||||
mul_m4_m4m4(r, r, m4);
|
||||
mul_m4_m4m4(r, r, m5);
|
||||
mul_m4_m4m4(r, r, m6);
|
||||
mul_m4_m4m4(r, r, m7);
|
||||
float s[4][4];
|
||||
float t[4][4];
|
||||
mul_m4_m4m4(s, m1, m2);
|
||||
mul_m4_m4m4(t, s, m3);
|
||||
mul_m4_m4m4(s, t, m4);
|
||||
mul_m4_m4m4(t, s, m5);
|
||||
mul_m4_m4m4(s, t, m6);
|
||||
mul_m4_m4m4(r, s, m7);
|
||||
}
|
||||
void _va_mul_m4_series_9(float r[4][4],
|
||||
const float m1[4][4],
|
||||
|
@ -658,13 +678,15 @@ void _va_mul_m4_series_9(float r[4][4],
|
|||
const float m7[4][4],
|
||||
const float m8[4][4])
|
||||
{
|
||||
mul_m4_m4m4(r, m1, m2);
|
||||
mul_m4_m4m4(r, r, m3);
|
||||
mul_m4_m4m4(r, r, m4);
|
||||
mul_m4_m4m4(r, r, m5);
|
||||
mul_m4_m4m4(r, r, m6);
|
||||
mul_m4_m4m4(r, r, m7);
|
||||
mul_m4_m4m4(r, r, m8);
|
||||
float s[4][4];
|
||||
float t[4][4];
|
||||
mul_m4_m4m4(s, m1, m2);
|
||||
mul_m4_m4m4(t, s, m3);
|
||||
mul_m4_m4m4(s, t, m4);
|
||||
mul_m4_m4m4(t, s, m5);
|
||||
mul_m4_m4m4(s, t, m6);
|
||||
mul_m4_m4m4(t, s, m7);
|
||||
mul_m4_m4m4(r, t, m8);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -54,11 +54,36 @@
|
|||
#include "BLI_linklist.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
/* The implementation for Apple lives in storage_apple.mm.*/
|
||||
bool BLI_change_working_dir(const char *dir)
|
||||
{
|
||||
BLI_assert(BLI_thread_is_main());
|
||||
|
||||
if (!BLI_is_dir(dir)) {
|
||||
return false;
|
||||
}
|
||||
# if defined(WIN32)
|
||||
wchar_t wdir[FILE_MAX];
|
||||
if (conv_utf_8_to_16(dir, wdir, ARRAY_SIZE(wdir)) != 0) {
|
||||
return false;
|
||||
}
|
||||
return _wchdir(wdir) == 0;
|
||||
# else
|
||||
int result = chdir(dir);
|
||||
if (result == 0) {
|
||||
BLI_setenv("PWD", dir);
|
||||
}
|
||||
return result == 0;
|
||||
# endif
|
||||
}
|
||||
|
||||
char *BLI_current_working_dir(char *dir, const size_t maxncpy)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
# if defined(WIN32)
|
||||
wchar_t path[MAX_PATH];
|
||||
if (_wgetcwd(path, MAX_PATH)) {
|
||||
if (BLI_strncpy_wchar_as_utf8(dir, path, maxncpy) != maxncpy) {
|
||||
|
@ -66,7 +91,7 @@ char *BLI_current_working_dir(char *dir, const size_t maxncpy)
|
|||
}
|
||||
}
|
||||
return NULL;
|
||||
#else
|
||||
# else
|
||||
const char *pwd = BLI_getenv("PWD");
|
||||
if (pwd) {
|
||||
size_t srclen = BLI_strnlen(pwd, maxncpy);
|
||||
|
@ -77,8 +102,9 @@ char *BLI_current_working_dir(char *dir, const size_t maxncpy)
|
|||
return NULL;
|
||||
}
|
||||
return getcwd(dir, maxncpy);
|
||||
#endif
|
||||
# endif
|
||||
}
|
||||
#endif /* !defined (__APPLE__) */
|
||||
|
||||
double BLI_dir_free_space(const char *dir)
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
/* Extended file attribute used by OneDrive to mark placeholder files. */
|
||||
static const char *ONEDRIVE_RECALLONOPEN_ATTRIBUTE = "com.microsoft.OneDrive.RecallOnOpen";
|
||||
|
@ -185,3 +186,29 @@ const char *BLI_expand_tilde(const char *path_with_tilde)
|
|||
}
|
||||
return path_expanded;
|
||||
}
|
||||
|
||||
char *BLI_current_working_dir(char *dir, const size_t maxncpy)
|
||||
{
|
||||
/* Can't just copy to the *dir pointer, as [path getCString gets grumpy.*/
|
||||
static char path_expanded[PATH_MAX];
|
||||
@autoreleasepool {
|
||||
NSString *path = [[NSFileManager defaultManager] currentDirectoryPath];
|
||||
const size_t length = maxncpy > PATH_MAX ? PATH_MAX : maxncpy;
|
||||
[path getCString:path_expanded maxLength:length encoding:NSUTF8StringEncoding];
|
||||
BLI_strncpy(dir, path_expanded, maxncpy);
|
||||
return path_expanded;
|
||||
}
|
||||
}
|
||||
|
||||
bool BLI_change_working_dir(const char *dir)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSString *path = [[NSString alloc] initWithUTF8String:dir];
|
||||
if ([[NSFileManager defaultManager] changeCurrentDirectoryPath:path] == YES) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,27 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "BLI_fileops.hh"
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "BLI_fileops.hh"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_threads.h"
|
||||
|
||||
namespace blender::tests {
|
||||
|
||||
class ChangeWorkingDirectoryTest : public testing::Test {
|
||||
public:
|
||||
std::string test_temp_dir;
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
if (!test_temp_dir.empty()) {
|
||||
BLI_delete(test_temp_dir.c_str(), true, false);
|
||||
}
|
||||
|
||||
BLI_threadapi_exit();
|
||||
}
|
||||
};
|
||||
|
||||
TEST(fileops, fstream_open_string_filename)
|
||||
{
|
||||
const std::string test_files_dir = blender::tests::flags_test_asset_dir();
|
||||
|
@ -37,4 +53,43 @@ TEST(fileops, fstream_open_charptr_filename)
|
|||
/* Reading the file not tested here. That's deferred to `std::fstream` anyway. */
|
||||
}
|
||||
|
||||
TEST_F(ChangeWorkingDirectoryTest, change_working_directory)
|
||||
{
|
||||
/* Must use because BLI_change_working_dir() checks that we are on the main thread. */
|
||||
BLI_threadapi_init();
|
||||
|
||||
char original_wd[FILE_MAX];
|
||||
if (!BLI_current_working_dir(original_wd, FILE_MAX)) {
|
||||
FAIL() << "unable to get the current working directory";
|
||||
}
|
||||
|
||||
const std::string temp_file_name(std::tmpnam(nullptr));
|
||||
test_temp_dir = temp_file_name + "_новый";
|
||||
|
||||
if (BLI_exists(test_temp_dir.c_str())) {
|
||||
BLI_delete(test_temp_dir.c_str(), true, false);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(BLI_change_working_dir(test_temp_dir.c_str()))
|
||||
<< "changing directory to a non-existent directory is expected to fail.";
|
||||
|
||||
ASSERT_TRUE(BLI_dir_create_recursive(test_temp_dir.c_str()))
|
||||
<< "temporary directory should have been created successfully.";
|
||||
|
||||
ASSERT_TRUE(BLI_change_working_dir(test_temp_dir.c_str()))
|
||||
<< "temporary directory should succeed changing directory.";
|
||||
|
||||
char cwd[FILE_MAX];
|
||||
if (!BLI_current_working_dir(cwd, FILE_MAX)) {
|
||||
FAIL() << "unable to get the current working directory";
|
||||
}
|
||||
|
||||
ASSERT_EQ(BLI_path_cmp_normalized(cwd, test_temp_dir.c_str()), 0)
|
||||
<< "the path of the current working directory should equal the path of the temporary "
|
||||
"directory that was created.";
|
||||
|
||||
ASSERT_TRUE(BLI_change_working_dir(original_wd))
|
||||
<< "changing directory back to the original working directory should succeed.";
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
|
|
@ -100,6 +100,40 @@ TEST(math_matrix, interp_m3_m3m3_singularity)
|
|||
EXPECT_M3_NEAR(result, expect, 1e-5);
|
||||
}
|
||||
|
||||
TEST(math_matrix, mul_m3_series)
|
||||
{
|
||||
float matrix[3][3] = {
|
||||
{2.0f, 0.0f, 0.0f},
|
||||
{0.0f, 3.0f, 0.0f},
|
||||
{0.0f, 0.0f, 5.0f},
|
||||
};
|
||||
mul_m3_series(matrix, matrix, matrix, matrix);
|
||||
float expect[3][3] = {
|
||||
{8.0f, 0.0f, 0.0f},
|
||||
{0.0f, 27.0f, 0.0f},
|
||||
{0.0f, 0.0f, 125.0f},
|
||||
};
|
||||
EXPECT_M3_NEAR(matrix, expect, 1e-5);
|
||||
}
|
||||
|
||||
TEST(math_matrix, mul_m4_series)
|
||||
{
|
||||
float matrix[4][4] = {
|
||||
{2.0f, 0.0f, 0.0f, 0.0f},
|
||||
{0.0f, 3.0f, 0.0f, 0.0f},
|
||||
{0.0f, 0.0f, 5.0f, 0.0f},
|
||||
{0.0f, 0.0f, 0.0f, 7.0f},
|
||||
};
|
||||
mul_m4_series(matrix, matrix, matrix, matrix);
|
||||
float expect[4][4] = {
|
||||
{8.0f, 0.0f, 0.0f, 0.0f},
|
||||
{0.0f, 27.0f, 0.0f, 0.0f},
|
||||
{0.0f, 0.0f, 125.0f, 0.0f},
|
||||
{0.0f, 0.0f, 0.0f, 343.0f},
|
||||
};
|
||||
EXPECT_M4_NEAR(matrix, expect, 1e-5);
|
||||
}
|
||||
|
||||
namespace blender::tests {
|
||||
|
||||
using namespace blender::math;
|
||||
|
|
|
@ -770,7 +770,11 @@ void blo_do_versions_userdef(UserDef *userdef)
|
|||
|
||||
/* Set GPU backend to OpenGL. */
|
||||
if (!USER_VERSION_ATLEAST(305, 5)) {
|
||||
#ifdef __APPLE__
|
||||
userdef->gpu_backend = GPU_BACKEND_METAL;
|
||||
#else
|
||||
userdef->gpu_backend = GPU_BACKEND_OPENGL;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!USER_VERSION_ATLEAST(305, 10)) {
|
||||
|
|
|
@ -126,6 +126,10 @@ const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid
|
|||
#define BLT_I18NCONTEXT_EDITOR_VIEW3D "View3D"
|
||||
#define BLT_I18NCONTEXT_EDITOR_FILEBROWSER "File browser"
|
||||
|
||||
/* Generic contexts. */
|
||||
#define BLT_I18NCONTEXT_VIRTUAL_REALITY "Virtual reality"
|
||||
#define BLT_I18NCONTEXT_CONSTRAINT "Constraint"
|
||||
|
||||
/* Helper for bpy.app.i18n object... */
|
||||
typedef struct {
|
||||
const char *c_id;
|
||||
|
@ -190,6 +194,8 @@ typedef struct {
|
|||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "id_windowmanager"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_EDITOR_VIEW3D, "editor_view3d"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_EDITOR_FILEBROWSER, "editor_filebrowser"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_VIRTUAL_REALITY, "virtual_reality"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_CONSTRAINT, "constraint"), \
|
||||
{ \
|
||||
NULL, NULL, NULL \
|
||||
} \
|
||||
|
|
|
@ -1191,7 +1191,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
|||
need_edgesel |= BM_ELEM_CD_GET_BOOL(l, edgesel_offset);
|
||||
}
|
||||
}
|
||||
if (pin_layer_index) {
|
||||
if (pin_layer_index >= 0) {
|
||||
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
|
||||
need_pin |= BM_ELEM_CD_GET_BOOL(l, pin_offset);
|
||||
}
|
||||
|
|
|
@ -338,16 +338,12 @@ class ShadowPunctual : public NonCopyable, NonMovable {
|
|||
float size_x_, size_y_;
|
||||
/** Shape type. */
|
||||
eLightType light_type_;
|
||||
/** Random position on the light. In world space. */
|
||||
float3 random_offset_;
|
||||
/** Light position. */
|
||||
float3 position_;
|
||||
/** Near and far clip distances. */
|
||||
float far_, near_;
|
||||
/** Number of tile-maps needed to cover the light angular extents. */
|
||||
int tilemaps_needed_;
|
||||
/** Visibility cone angle from the light source. */
|
||||
int cone_aperture_;
|
||||
|
||||
public:
|
||||
ShadowPunctual(ShadowModule &module) : shadows_(module){};
|
||||
|
|
|
@ -164,7 +164,7 @@ DEF_ICON(NLA)
|
|||
DEF_ICON(PREFERENCES)
|
||||
DEF_ICON(TIME)
|
||||
DEF_ICON(NODETREE)
|
||||
DEF_ICON(GEOMETRY_NODES)
|
||||
DEF_ICON_MODIFIER(GEOMETRY_NODES)
|
||||
DEF_ICON(CONSOLE)
|
||||
DEF_ICON_BLANK(183)
|
||||
DEF_ICON(TRACKER)
|
||||
|
|
|
@ -3446,55 +3446,63 @@ static char *vertex_group_lock_description(bContext * /*C*/,
|
|||
int action = RNA_enum_get(params, "action");
|
||||
int mask = RNA_enum_get(params, "mask");
|
||||
|
||||
const char *action_str, *target_str;
|
||||
|
||||
/* NOTE: constructing the following string literals can be done in a less verbose way,
|
||||
* however the resulting strings can't be usefully translated, (via `TIP_`). */
|
||||
switch (action) {
|
||||
case VGROUP_LOCK:
|
||||
action_str = TIP_("Lock");
|
||||
switch (mask) {
|
||||
case VGROUP_MASK_ALL:
|
||||
return BLI_strdup(TIP_("Lock all vertex groups of the active object"));
|
||||
case VGROUP_MASK_SELECTED:
|
||||
return BLI_strdup(TIP_("Lock selected vertex groups of the active object"));
|
||||
case VGROUP_MASK_UNSELECTED:
|
||||
return BLI_strdup(TIP_("Lock unselected vertex groups of the active object"));
|
||||
case VGROUP_MASK_INVERT_UNSELECTED:
|
||||
return BLI_strdup(
|
||||
TIP_("Lock selected and unlock unselected vertex groups of the active object"));
|
||||
}
|
||||
break;
|
||||
case VGROUP_UNLOCK:
|
||||
action_str = TIP_("Unlock");
|
||||
switch (mask) {
|
||||
case VGROUP_MASK_ALL:
|
||||
return BLI_strdup(TIP_("Unlock all vertex groups of the active object"));
|
||||
case VGROUP_MASK_SELECTED:
|
||||
return BLI_strdup(TIP_("Unlock selected vertex groups of the active object"));
|
||||
case VGROUP_MASK_UNSELECTED:
|
||||
return BLI_strdup(TIP_("Unlock unselected vertex groups of the active object"));
|
||||
case VGROUP_MASK_INVERT_UNSELECTED:
|
||||
return BLI_strdup(
|
||||
TIP_("Unlock selected and lock unselected vertex groups of the active object"));
|
||||
}
|
||||
break;
|
||||
case VGROUP_TOGGLE:
|
||||
action_str = TIP_("Toggle locks of");
|
||||
switch (mask) {
|
||||
case VGROUP_MASK_ALL:
|
||||
return BLI_strdup(TIP_("Toggle locks of all vertex groups of the active object"));
|
||||
case VGROUP_MASK_SELECTED:
|
||||
return BLI_strdup(TIP_("Toggle locks of selected vertex groups of the active object"));
|
||||
case VGROUP_MASK_UNSELECTED:
|
||||
return BLI_strdup(TIP_("Toggle locks of unselected vertex groups of the active object"));
|
||||
case VGROUP_MASK_INVERT_UNSELECTED:
|
||||
return BLI_strdup(TIP_(
|
||||
"Toggle locks of all and invert unselected vertex groups of the active object"));
|
||||
}
|
||||
break;
|
||||
case VGROUP_INVERT:
|
||||
action_str = TIP_("Invert locks of");
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
switch (mask) {
|
||||
case VGROUP_MASK_ALL:
|
||||
target_str = TIP_("all");
|
||||
break;
|
||||
case VGROUP_MASK_SELECTED:
|
||||
target_str = TIP_("selected");
|
||||
break;
|
||||
case VGROUP_MASK_UNSELECTED:
|
||||
target_str = TIP_("unselected");
|
||||
break;
|
||||
case VGROUP_MASK_INVERT_UNSELECTED:
|
||||
switch (action) {
|
||||
case VGROUP_INVERT:
|
||||
target_str = TIP_("selected");
|
||||
break;
|
||||
case VGROUP_LOCK:
|
||||
target_str = TIP_("selected and unlock unselected");
|
||||
break;
|
||||
case VGROUP_UNLOCK:
|
||||
target_str = TIP_("selected and lock unselected");
|
||||
break;
|
||||
default:
|
||||
target_str = TIP_("all and invert unselected");
|
||||
switch (mask) {
|
||||
case VGROUP_MASK_ALL:
|
||||
return BLI_strdup(TIP_("Invert locks of all vertex groups of the active object"));
|
||||
case VGROUP_MASK_SELECTED:
|
||||
case VGROUP_MASK_INVERT_UNSELECTED:
|
||||
return BLI_strdup(TIP_("Invert locks of selected vertex groups of the active object"));
|
||||
case VGROUP_MASK_UNSELECTED:
|
||||
return BLI_strdup(TIP_("Invert locks of unselected vertex groups of the active object"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return BLI_sprintfN(TIP_("%s %s vertex groups of the active object"), action_str, target_str);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void OBJECT_OT_vertex_group_lock(wmOperatorType *ot)
|
||||
|
|
|
@ -195,7 +195,7 @@ static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush
|
|||
|
||||
const int automasking_flags = sculpt_automasking_mode_effective_bits(sd, brush);
|
||||
|
||||
if (automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY &&
|
||||
if (automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY && brush &&
|
||||
sculpt_automasking_is_constrained_by_radius(brush)) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -796,6 +796,40 @@ static void sculpt_mesh_filter_end(bContext *C, wmOperator * /*op*/)
|
|||
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
|
||||
}
|
||||
|
||||
static void sculpt_mesh_filter_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
PBVHNode **nodes;
|
||||
int nodes_num;
|
||||
|
||||
if (!ss || !ss->pbvh) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Gather all PBVH leaf nodes. */
|
||||
BKE_pbvh_search_gather(ss->pbvh, nullptr, nullptr, &nodes, &nodes_num);
|
||||
|
||||
for (int i : IndexRange(nodes_num)) {
|
||||
PBVHNode *node = nodes[i];
|
||||
PBVHVertexIter vd;
|
||||
|
||||
SculptOrigVertData orig_data;
|
||||
SCULPT_orig_vert_data_init(&orig_data, ob, nodes[i], SCULPT_UNDO_COORDS);
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
SCULPT_orig_vert_data_update(&orig_data, &vd);
|
||||
|
||||
copy_v3_v3(vd.co, orig_data.co);
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
|
||||
BKE_pbvh_node_mark_update(node);
|
||||
}
|
||||
|
||||
BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB);
|
||||
}
|
||||
|
||||
static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#include "WM_api.h"
|
||||
|
||||
#include "NOD_add_node_search.hh"
|
||||
|
||||
#include "ED_asset.h"
|
||||
#include "ED_node.h"
|
||||
|
||||
|
@ -36,12 +38,9 @@ struct bContext;
|
|||
namespace blender::ed::space_node {
|
||||
|
||||
struct AddNodeItem {
|
||||
std::string ui_name;
|
||||
nodes::AddNodeInfo info;
|
||||
std::string identifier;
|
||||
std::string description;
|
||||
std::optional<AssetHandle> asset;
|
||||
std::function<void(const bContext &, bNodeTree &, bNode &)> after_add_fn;
|
||||
int weight = 0;
|
||||
};
|
||||
|
||||
struct AddNodeSearchStorage {
|
||||
|
@ -77,11 +76,11 @@ static void search_items_for_asset_metadata(const bNodeTree &node_tree,
|
|||
}
|
||||
|
||||
AddNodeItem item{};
|
||||
item.ui_name = ED_asset_handle_get_name(&asset);
|
||||
item.info.ui_name = ED_asset_handle_get_name(&asset);
|
||||
item.identifier = node_tree.typeinfo->group_idname;
|
||||
item.description = asset_data.description == nullptr ? "" : asset_data.description;
|
||||
item.info.description = asset_data.description == nullptr ? "" : asset_data.description;
|
||||
item.asset = asset;
|
||||
item.after_add_fn = [asset](const bContext &C, bNodeTree &node_tree, bNode &node) {
|
||||
item.info.after_add_fn = [asset](const bContext &C, bNodeTree &node_tree, bNode &node) {
|
||||
Main &bmain = *CTX_data_main(&C);
|
||||
node.flag &= ~NODE_OPTIONS;
|
||||
node.id = asset::get_local_id_from_asset_or_append_and_reuse(bmain, asset);
|
||||
|
@ -139,9 +138,9 @@ static void gather_search_items_for_node_groups(const bContext &C,
|
|||
continue;
|
||||
}
|
||||
AddNodeItem item{};
|
||||
item.ui_name = node_group->id.name + 2;
|
||||
item.info.ui_name = node_group->id.name + 2;
|
||||
item.identifier = node_tree.typeinfo->group_idname;
|
||||
item.after_add_fn = [node_group](const bContext &C, bNodeTree &node_tree, bNode &node) {
|
||||
item.info.after_add_fn = [node_group](const bContext &C, bNodeTree &node_tree, bNode &node) {
|
||||
Main &bmain = *CTX_data_main(&C);
|
||||
node.id = &node_group->id;
|
||||
id_us_plus(node.id);
|
||||
|
@ -161,19 +160,18 @@ static void gather_add_node_operations(const bContext &C,
|
|||
if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) {
|
||||
continue;
|
||||
}
|
||||
if (StringRefNull(node_tree.typeinfo->group_idname) == node_type->idname) {
|
||||
/* Skip the empty group type. */
|
||||
if (!node_type->gather_add_node_search_ops) {
|
||||
continue;
|
||||
}
|
||||
if (StringRefNull(node_type->ui_name).endswith("(Legacy)")) {
|
||||
continue;
|
||||
Vector<nodes::AddNodeInfo> info_items;
|
||||
nodes::GatherAddNodeSearchParams params(*node_type, node_tree, info_items);
|
||||
node_type->gather_add_node_search_ops(params);
|
||||
for (nodes::AddNodeInfo &info : info_items) {
|
||||
AddNodeItem item{};
|
||||
item.info = std::move(info);
|
||||
item.identifier = node_type->idname;
|
||||
r_search_items.append(item);
|
||||
}
|
||||
|
||||
AddNodeItem item{};
|
||||
item.ui_name = IFACE_(node_type->ui_name);
|
||||
item.identifier = node_type->idname;
|
||||
item.description = TIP_(node_type->ui_description);
|
||||
r_search_items.append(std::move(item));
|
||||
}
|
||||
NODE_TYPES_END;
|
||||
|
||||
|
@ -199,7 +197,7 @@ static void add_node_search_update_fn(
|
|||
StringSearch *search = BLI_string_search_new();
|
||||
|
||||
for (AddNodeItem &item : storage.search_add_items) {
|
||||
BLI_string_search_add(search, item.ui_name.c_str(), &item, item.weight);
|
||||
BLI_string_search_add(search, item.info.ui_name.c_str(), &item, item.info.weight);
|
||||
}
|
||||
|
||||
/* Don't filter when the menu is first opened, but still run the search
|
||||
|
@ -210,7 +208,7 @@ static void add_node_search_update_fn(
|
|||
|
||||
for (const int i : IndexRange(filtered_amount)) {
|
||||
AddNodeItem &item = *filtered_items[i];
|
||||
if (!UI_search_item_add(items, item.ui_name.c_str(), &item, ICON_NONE, 0, 0)) {
|
||||
if (!UI_search_item_add(items, item.info.ui_name.c_str(), &item, ICON_NONE, 0, 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -234,8 +232,8 @@ static void add_node_search_exec_fn(bContext *C, void *arg1, void *arg2)
|
|||
bNode *new_node = nodeAddNode(C, &node_tree, item->identifier.c_str());
|
||||
BLI_assert(new_node != nullptr);
|
||||
|
||||
if (item->after_add_fn) {
|
||||
item->after_add_fn(*C, node_tree, *new_node);
|
||||
if (item->info.after_add_fn) {
|
||||
item->info.after_add_fn(*C, node_tree, *new_node);
|
||||
}
|
||||
|
||||
new_node->locx = storage.cursor.x / UI_DPI_FAC;
|
||||
|
@ -266,7 +264,7 @@ static ARegion *add_node_search_tooltip_fn(
|
|||
uiSearchItemTooltipData tooltip_data{};
|
||||
|
||||
BLI_strncpy(tooltip_data.description,
|
||||
item->asset ? item->description.c_str() : TIP_(item->description.c_str()),
|
||||
item->asset ? item->info.description.c_str() : TIP_(item->info.description.c_str()),
|
||||
sizeof(tooltip_data.description));
|
||||
|
||||
return UI_tooltip_create_from_search_item_generic(C, region, item_rect, &tooltip_data);
|
||||
|
|
|
@ -993,7 +993,9 @@ static void node_group_make_insert_selected(const bContext &C,
|
|||
}
|
||||
}
|
||||
|
||||
bke::node_field_inferencing::update_field_inferencing(group);
|
||||
if (group.type == NTREE_GEOMETRY) {
|
||||
bke::node_field_inferencing::update_field_inferencing(group);
|
||||
}
|
||||
nodes::update_node_declaration_and_sockets(ntree, *gnode);
|
||||
|
||||
/* Add new links to inputs outside of the group. */
|
||||
|
|
|
@ -1363,8 +1363,84 @@ static void rotation_set_fn(const wmGizmo * /*gz*/, wmGizmoProperty *gz_prop, co
|
|||
ggd->rotation = *(const float *)value;
|
||||
}
|
||||
|
||||
static void gizmo_3d_setup_default_matrix(wmGizmo *axis, const int axis_idx)
|
||||
{
|
||||
float matrix[3][3];
|
||||
|
||||
switch (axis_idx) {
|
||||
/* Arrow. */
|
||||
case MAN_AXIS_TRANS_X:
|
||||
case MAN_AXIS_SCALE_X:
|
||||
case MAN_AXIS_ROT_X:
|
||||
copy_v3_fl3(matrix[0], 0.0f, -1.0f, 0.0f);
|
||||
copy_v3_fl3(matrix[1], 0.0f, 0.0f, -1.0f);
|
||||
copy_v3_fl3(matrix[2], 1.0f, 0.0f, 0.0f);
|
||||
break;
|
||||
case MAN_AXIS_TRANS_Y:
|
||||
case MAN_AXIS_SCALE_Y:
|
||||
case MAN_AXIS_ROT_Y:
|
||||
copy_v3_fl3(matrix[0], 1.0f, 0.0f, 0.0f);
|
||||
copy_v3_fl3(matrix[1], 0.0f, 0.0f, -1.0f);
|
||||
copy_v3_fl3(matrix[2], 0.0f, 1.0f, 0.0f);
|
||||
break;
|
||||
case MAN_AXIS_TRANS_Z:
|
||||
case MAN_AXIS_SCALE_Z:
|
||||
case MAN_AXIS_ROT_Z:
|
||||
copy_v3_fl3(matrix[0], 1.0f, 0.0f, 0.0f);
|
||||
copy_v3_fl3(matrix[1], 0.0f, 1.0f, 0.0f);
|
||||
copy_v3_fl3(matrix[2], 0.0f, 0.0f, 1.0f);
|
||||
break;
|
||||
|
||||
case MAN_AXIS_TRANS_XY:
|
||||
case MAN_AXIS_SCALE_XY:
|
||||
copy_v3_fl3(matrix[0], MAN_AXIS_SCALE_PLANE_SCALE, 0.0f, 0.0f);
|
||||
copy_v3_fl3(matrix[1], 0.0f, MAN_AXIS_SCALE_PLANE_SCALE, 0.0f);
|
||||
copy_v3_fl3(matrix[2], 0.0f, 0.0f, MAN_AXIS_SCALE_PLANE_SCALE);
|
||||
break;
|
||||
case MAN_AXIS_TRANS_YZ:
|
||||
case MAN_AXIS_SCALE_YZ:
|
||||
copy_v3_fl3(matrix[0], 0.0f, 0.0f, MAN_AXIS_SCALE_PLANE_SCALE);
|
||||
copy_v3_fl3(matrix[1], 0.0f, MAN_AXIS_SCALE_PLANE_SCALE, 0.0f);
|
||||
copy_v3_fl3(matrix[2], -MAN_AXIS_SCALE_PLANE_SCALE, 0.0f, 0.0f);
|
||||
break;
|
||||
case MAN_AXIS_TRANS_ZX:
|
||||
case MAN_AXIS_SCALE_ZX:
|
||||
copy_v3_fl3(matrix[0], MAN_AXIS_SCALE_PLANE_SCALE, 0.0f, 0.0f);
|
||||
copy_v3_fl3(matrix[1], 0.0f, 0.0f, MAN_AXIS_SCALE_PLANE_SCALE);
|
||||
copy_v3_fl3(matrix[2], 0.0f, -MAN_AXIS_SCALE_PLANE_SCALE, 0.0f);
|
||||
break;
|
||||
|
||||
case MAN_AXIS_TRANS_C:
|
||||
case MAN_AXIS_SCALE_C:
|
||||
case MAN_AXIS_ROT_C:
|
||||
case MAN_AXIS_ROT_T:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
copy_m4_m3(axis->matrix_offset, matrix);
|
||||
|
||||
switch (axis_idx) {
|
||||
case MAN_AXIS_TRANS_XY:
|
||||
case MAN_AXIS_TRANS_YZ:
|
||||
case MAN_AXIS_TRANS_ZX:
|
||||
case MAN_AXIS_SCALE_XY:
|
||||
case MAN_AXIS_SCALE_YZ:
|
||||
case MAN_AXIS_SCALE_ZX: {
|
||||
float offs[3];
|
||||
add_v3_v3v3(offs, axis->matrix_offset[0], axis->matrix_offset[1]);
|
||||
mul_v3_fl(offs, MAN_AXIS_SCALE_PLANE_OFFSET);
|
||||
WM_gizmo_set_matrix_offset_location(axis, offs);
|
||||
} break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void gizmo_3d_setup_draw_default(wmGizmo *axis, const int axis_idx)
|
||||
{
|
||||
gizmo_3d_setup_default_matrix(axis, axis_idx);
|
||||
|
||||
switch (axis_idx) {
|
||||
/* Arrow. */
|
||||
case MAN_AXIS_TRANS_X:
|
||||
|
@ -1385,15 +1461,10 @@ static void gizmo_3d_setup_draw_default(wmGizmo *axis, const int axis_idx)
|
|||
case MAN_AXIS_TRANS_ZX:
|
||||
case MAN_AXIS_SCALE_XY:
|
||||
case MAN_AXIS_SCALE_YZ:
|
||||
case MAN_AXIS_SCALE_ZX: {
|
||||
case MAN_AXIS_SCALE_ZX:
|
||||
RNA_enum_set(axis->ptr, "draw_style", ED_GIZMO_PRIMITIVE_STYLE_PLANE);
|
||||
|
||||
const float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f};
|
||||
WM_gizmo_set_scale(axis, MAN_AXIS_SCALE_PLANE_SCALE);
|
||||
WM_gizmo_set_matrix_offset_location(axis, ofs);
|
||||
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Dial. */
|
||||
case MAN_AXIS_TRANS_C:
|
||||
|
@ -1489,12 +1560,12 @@ static void gizmo_3d_setup_draw_from_twtype(wmGizmo *axis, const int axis_idx, c
|
|||
case MAN_AXIS_SCALE_X:
|
||||
case MAN_AXIS_SCALE_Y:
|
||||
case MAN_AXIS_SCALE_Z: {
|
||||
float start_co[3] = {0.0f, 0.0f, 0.0f};
|
||||
float start;
|
||||
float end;
|
||||
gizmo_line_range(twtype, axis_type, &start_co[2], &end);
|
||||
gizmo_line_range(twtype, axis_type, &start, &end);
|
||||
madd_v3_v3fl(axis->matrix_offset[3], axis->matrix_offset[2], start);
|
||||
|
||||
WM_gizmo_set_matrix_offset_location(axis, start_co);
|
||||
RNA_float_set(axis->ptr, "length", end - start_co[2]);
|
||||
RNA_float_set(axis->ptr, "length", end - start);
|
||||
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
|
||||
break;
|
||||
}
|
||||
|
@ -1803,61 +1874,49 @@ static void gizmo_refresh_from_matrix(wmGizmo *axis,
|
|||
const short axis_type = gizmo_get_axis_type(axis_idx);
|
||||
const int aidx_norm = gizmo_orientation_axis(axis_idx, nullptr);
|
||||
|
||||
WM_gizmo_set_matrix_location(axis, twmat[3]);
|
||||
switch (axis_idx) {
|
||||
case MAN_AXIS_TRANS_X:
|
||||
case MAN_AXIS_TRANS_Y:
|
||||
case MAN_AXIS_TRANS_Z:
|
||||
case MAN_AXIS_SCALE_X:
|
||||
case MAN_AXIS_SCALE_Y:
|
||||
case MAN_AXIS_SCALE_Z: {
|
||||
const float *z_axis = twmat[aidx_norm];
|
||||
if (axis_type == MAN_AXES_SCALE) {
|
||||
/* Scale handles are cubes that don't look right when not aligned with other axes.
|
||||
* This is noticeable when the axis is rotated to something besides the global-axis. */
|
||||
const int aidx_norm_y = (aidx_norm + 2) % 3;
|
||||
const float *y_axis = twmat[aidx_norm_y];
|
||||
WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
|
||||
|
||||
if (scale) {
|
||||
float start, end;
|
||||
gizmo_line_range(twtype, axis_type, &start, &end);
|
||||
RNA_float_set(axis->ptr, "length", (end * scale[aidx_norm]) - start);
|
||||
}
|
||||
}
|
||||
else {
|
||||
WM_gizmo_set_matrix_rotation_from_z_axis(axis, z_axis);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MAN_AXIS_ROT_X:
|
||||
case MAN_AXIS_ROT_Y:
|
||||
case MAN_AXIS_ROT_Z:
|
||||
WM_gizmo_set_matrix_rotation_from_z_axis(axis, twmat[aidx_norm]);
|
||||
break;
|
||||
case MAN_AXIS_TRANS_XY:
|
||||
case MAN_AXIS_TRANS_YZ:
|
||||
case MAN_AXIS_TRANS_ZX:
|
||||
case MAN_AXIS_SCALE_XY:
|
||||
case MAN_AXIS_SCALE_YZ:
|
||||
case MAN_AXIS_SCALE_ZX: {
|
||||
const int aidx_norm_x = (aidx_norm + 1) % 3;
|
||||
const int aidx_norm_y = (aidx_norm + 2) % 3;
|
||||
const float *y_axis = twmat[aidx_norm_y];
|
||||
const float *z_axis = twmat[aidx_norm];
|
||||
WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
|
||||
|
||||
if (axis_type == MAN_AXES_SCALE) {
|
||||
float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f};
|
||||
if (scale) {
|
||||
ofs[0] *= scale[aidx_norm_x];
|
||||
ofs[1] *= scale[aidx_norm_y];
|
||||
}
|
||||
WM_gizmo_set_matrix_offset_location(axis, ofs);
|
||||
case MAN_AXIS_SCALE_ZX:
|
||||
copy_m4_m4(axis->matrix_basis, twmat);
|
||||
if (scale) {
|
||||
float offs[3];
|
||||
add_v3_v3v3(offs, axis->matrix_offset[0], axis->matrix_offset[1]);
|
||||
mul_v3_fl(offs, MAN_AXIS_SCALE_PLANE_OFFSET);
|
||||
mul_v3_v3(offs, scale);
|
||||
WM_gizmo_set_matrix_offset_location(axis, offs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MAN_AXIS_SCALE_X:
|
||||
case MAN_AXIS_SCALE_Y:
|
||||
case MAN_AXIS_SCALE_Z:
|
||||
copy_m4_m4(axis->matrix_basis, twmat);
|
||||
if (scale) {
|
||||
float start, end;
|
||||
gizmo_line_range(twtype, axis_type, &start, &end);
|
||||
RNA_float_set(axis->ptr, "length", (end - start) * scale[aidx_norm]);
|
||||
}
|
||||
break;
|
||||
case MAN_AXIS_TRANS_X:
|
||||
case MAN_AXIS_TRANS_Y:
|
||||
case MAN_AXIS_TRANS_Z:
|
||||
copy_m4_m4(axis->matrix_basis, twmat);
|
||||
break;
|
||||
case MAN_AXIS_ROT_X:
|
||||
case MAN_AXIS_ROT_Y:
|
||||
case MAN_AXIS_ROT_Z:
|
||||
copy_m4_m4(axis->matrix_basis, twmat);
|
||||
orthogonalize_m4(axis->matrix_basis, aidx_norm);
|
||||
break;
|
||||
case MAN_AXIS_SCALE_C:
|
||||
case MAN_AXIS_ROT_C:
|
||||
case MAN_AXIS_ROT_T:
|
||||
default:
|
||||
WM_gizmo_set_matrix_location(axis, twmat[3]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2076,12 +2135,16 @@ static void gizmo_3d_draw_invoke(wmGizmoGroup *gzgroup,
|
|||
}
|
||||
|
||||
if (axis == axis_active) {
|
||||
if (axis_active_type == MAN_AXES_ROTATE) {
|
||||
gizmo_3d_dial_matrixbasis_calc(region,
|
||||
axis_active->matrix_basis[2],
|
||||
axis_active->matrix_basis[3],
|
||||
mval,
|
||||
axis_active->matrix_basis);
|
||||
if (axis_active_type == MAN_AXES_ROTATE && axis_idx_active != MAN_AXIS_ROT_T) {
|
||||
float mat[3][3];
|
||||
mul_m3_m4m4(mat, axis_active->matrix_basis, axis_active->matrix_offset);
|
||||
gizmo_3d_dial_matrixbasis_calc(
|
||||
region, mat[2], axis_active->matrix_basis[3], mval, axis_active->matrix_offset);
|
||||
|
||||
copy_m3_m4(mat, axis_active->matrix_basis);
|
||||
invert_m3(mat);
|
||||
mul_m4_m3m4(axis_active->matrix_offset, mat, axis_active->matrix_offset);
|
||||
zero_v3(axis_active->matrix_offset[3]);
|
||||
}
|
||||
|
||||
gizmo_3d_setup_draw_modal(axis_active, axis_idx);
|
||||
|
|
|
@ -1754,9 +1754,8 @@ void MTLFrameBuffer::blit(uint read_slot,
|
|||
uint height,
|
||||
eGPUFrameBufferBits blit_buffers)
|
||||
{
|
||||
BLI_assert(this);
|
||||
BLI_assert(metal_fb_write);
|
||||
if (!(this && metal_fb_write)) {
|
||||
if (!metal_fb_write) {
|
||||
return;
|
||||
}
|
||||
MTLContext *mtl_context = reinterpret_cast<MTLContext *>(GPU_context_active_get());
|
||||
|
@ -1899,4 +1898,4 @@ int MTLFrameBuffer::get_height()
|
|||
return height_;
|
||||
}
|
||||
|
||||
} // blender::gpu
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -1190,11 +1190,11 @@ static void rna_ParticleTarget_name_get(PointerRNA *ptr, char *str)
|
|||
}
|
||||
}
|
||||
else {
|
||||
strcpy(str, "Invalid target!");
|
||||
strcpy(str, TIP_("Invalid target!"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
strcpy(str, "Invalid target!");
|
||||
strcpy(str, TIP_("Invalid target!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ set(INC
|
|||
|
||||
|
||||
set(SRC
|
||||
intern/add_node_search.cc
|
||||
intern/derived_node_tree.cc
|
||||
intern/geometry_nodes_lazy_function.cc
|
||||
intern/geometry_nodes_log.cc
|
||||
|
@ -54,6 +55,7 @@ set(SRC
|
|||
intern/node_util.cc
|
||||
intern/socket_search_link.cc
|
||||
|
||||
NOD_add_node_search.hh
|
||||
NOD_common.h
|
||||
NOD_composite.h
|
||||
NOD_derived_node_tree.hh
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "DNA_node_types.h" /* Necessary for eNodeSocketInOut. */
|
||||
|
||||
#include "NOD_node_declaration.hh"
|
||||
|
||||
struct bContext;
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
struct AddNodeInfo {
|
||||
using AfterAddFn = std::function<void(const bContext &C, bNodeTree &node_tree, bNode &node)>;
|
||||
std::string ui_name;
|
||||
std::string description;
|
||||
AfterAddFn after_add_fn;
|
||||
int weight = 0;
|
||||
};
|
||||
|
||||
class GatherAddNodeSearchParams {
|
||||
const bNodeType &node_type_;
|
||||
const bNodeTree &node_tree_;
|
||||
Vector<AddNodeInfo> &r_items;
|
||||
|
||||
public:
|
||||
GatherAddNodeSearchParams(const bNodeType &node_type,
|
||||
const bNodeTree &node_tree,
|
||||
Vector<AddNodeInfo> &r_items)
|
||||
: node_type_(node_type), node_tree_(node_tree), r_items(r_items)
|
||||
{
|
||||
}
|
||||
|
||||
const bNodeTree &node_tree() const
|
||||
{
|
||||
return node_tree_;
|
||||
}
|
||||
|
||||
const bNodeType &node_type() const
|
||||
{
|
||||
return node_type_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param weight: Used to customize the order when multiple search items match.
|
||||
*/
|
||||
void add_item(std::string ui_name,
|
||||
std::string description,
|
||||
AddNodeInfo::AfterAddFn fn = {},
|
||||
int weight = 0);
|
||||
};
|
||||
|
||||
void search_node_add_ops_for_basic_node(GatherAddNodeSearchParams ¶ms);
|
||||
|
||||
} // namespace blender::nodes
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "BKE_node_runtime.hh"
|
||||
|
||||
#include "NOD_add_node_search.hh"
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "node_composite_util.hh"
|
||||
|
@ -35,4 +36,5 @@ void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short ncla
|
|||
ntype->updatefunc = cmp_node_update_default;
|
||||
ntype->insert_link = node_insert_link_default;
|
||||
ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
|
||||
ntype->gather_add_node_search_ops = blender::nodes::search_node_add_ops_for_basic_node;
|
||||
}
|
||||
|
|
|
@ -428,6 +428,7 @@ void register_node_type_cmp_cryptomatte_legacy()
|
|||
node_type_storage(
|
||||
&ntype, "NodeCryptomatte", file_ns::node_free_cryptomatte, file_ns::node_copy_cryptomatte);
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
ntype.get_compositor_operation = legacy_file_ns::get_compositor_operation;
|
||||
ntype.realtime_compositor_unsupported_message = N_(
|
||||
"Node not supported in the Viewport compositor");
|
||||
|
|
|
@ -58,6 +58,7 @@ void register_node_type_cmp_sephsva()
|
|||
&ntype, CMP_NODE_SEPHSVA_LEGACY, "Separate HSVA (Legacy)", NODE_CLASS_CONVERTER);
|
||||
ntype.declare = file_ns::cmp_node_sephsva_declare;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
|
@ -112,6 +113,7 @@ void register_node_type_cmp_combhsva()
|
|||
&ntype, CMP_NODE_COMBHSVA_LEGACY, "Combine HSVA (Legacy)", NODE_CLASS_CONVERTER);
|
||||
ntype.declare = file_ns::cmp_node_combhsva_declare;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
|
|
|
@ -58,6 +58,7 @@ void register_node_type_cmp_seprgba()
|
|||
&ntype, CMP_NODE_SEPRGBA_LEGACY, "Separate RGBA (Legacy)", NODE_CLASS_CONVERTER);
|
||||
ntype.declare = file_ns::cmp_node_seprgba_declare;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
|
@ -112,6 +113,7 @@ void register_node_type_cmp_combrgba()
|
|||
&ntype, CMP_NODE_COMBRGBA_LEGACY, "Combine RGBA (Legacy)", NODE_CLASS_CONVERTER);
|
||||
ntype.declare = file_ns::cmp_node_combrgba_declare;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
|
|
|
@ -86,6 +86,7 @@ void register_node_type_cmp_sepycca()
|
|||
ntype.declare = file_ns::cmp_node_sepycca_declare;
|
||||
ntype.initfunc = file_ns::node_composit_init_mode_sepycca;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
|
@ -174,6 +175,7 @@ void register_node_type_cmp_combycca()
|
|||
ntype.declare = file_ns::cmp_node_combycca_declare;
|
||||
ntype.initfunc = file_ns::node_composit_init_mode_combycca;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
|
|
|
@ -58,6 +58,7 @@ void register_node_type_cmp_sepyuva()
|
|||
&ntype, CMP_NODE_SEPYUVA_LEGACY, "Separate YUVA (Legacy)", NODE_CLASS_CONVERTER);
|
||||
ntype.declare = file_ns::cmp_node_sepyuva_declare;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
|
@ -112,6 +113,7 @@ void register_node_type_cmp_combyuva()
|
|||
&ntype, CMP_NODE_COMBYUVA_LEGACY, "Combine YUVA (Legacy)", NODE_CLASS_CONVERTER);
|
||||
ntype.declare = file_ns::cmp_node_combyuva_declare;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "node_function_util.hh"
|
||||
#include "node_util.h"
|
||||
|
||||
#include "NOD_add_node_search.hh"
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
static bool fn_node_poll_default(const bNodeType * /*ntype*/,
|
||||
|
@ -23,4 +24,5 @@ void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclas
|
|||
ntype->poll = fn_node_poll_default;
|
||||
ntype->insert_link = node_insert_link_default;
|
||||
ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
|
||||
ntype->gather_add_node_search_ops = blender::nodes::search_node_add_ops_for_basic_node;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "BKE_mesh_runtime.h"
|
||||
#include "BKE_pointcloud.h"
|
||||
|
||||
#include "NOD_add_node_search.hh"
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
@ -58,4 +59,5 @@ void geo_node_type_base(bNodeType *ntype, int type, const char *name, short ncla
|
|||
ntype->poll = geo_node_poll_default;
|
||||
ntype->insert_link = node_insert_link_default;
|
||||
ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
|
||||
ntype->gather_add_node_search_ops = blender::nodes::search_node_add_ops_for_basic_node;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_node.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "NOD_add_node_search.hh"
|
||||
#include "NOD_node_declaration.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
void GatherAddNodeSearchParams::add_item(std::string ui_name,
|
||||
std::string description,
|
||||
AddNodeInfo::AfterAddFn fn,
|
||||
int weight)
|
||||
{
|
||||
r_items.append(AddNodeInfo{std::move(ui_name), std::move(description), std::move(fn), weight});
|
||||
}
|
||||
|
||||
void search_node_add_ops_for_basic_node(GatherAddNodeSearchParams ¶ms)
|
||||
{
|
||||
params.add_item(IFACE_(params.node_type().ui_name), TIP_(params.node_type().ui_description));
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "node_shader_util.hh"
|
||||
|
||||
#include "NOD_add_node_search.hh"
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "node_exec.h"
|
||||
|
@ -44,6 +45,7 @@ void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, shor
|
|||
ntype->poll = sh_node_poll_default;
|
||||
ntype->insert_link = node_insert_link_default;
|
||||
ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
|
||||
ntype->gather_add_node_search_ops = blender::nodes::search_node_add_ops_for_basic_node;
|
||||
}
|
||||
|
||||
void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
|
||||
|
@ -51,6 +53,7 @@ void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nc
|
|||
sh_node_type_base(ntype, type, name, nclass);
|
||||
ntype->poll = sh_fn_poll_default;
|
||||
ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
|
||||
ntype->gather_add_node_search_ops = blender::nodes::search_node_add_ops_for_basic_node;
|
||||
}
|
||||
|
||||
/* ****** */
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
|
||||
#include "node_shader_util.hh"
|
||||
|
||||
#include "NOD_add_node_search.hh"
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
namespace blender::nodes::node_sh_mix_cc {
|
||||
|
@ -223,6 +225,16 @@ static void node_mix_gather_link_searches(GatherLinkSearchOpParams ¶ms)
|
|||
}
|
||||
}
|
||||
|
||||
static void gather_add_node_searches(GatherAddNodeSearchParams ¶ms)
|
||||
{
|
||||
params.add_item(IFACE_("Mix"), params.node_type().ui_description);
|
||||
params.add_item(IFACE_("Mix Color"),
|
||||
params.node_type().ui_description,
|
||||
[](const bContext & /*C*/, bNodeTree & /*node_tree*/, bNode &node) {
|
||||
node_storage(node).data_type = SOCK_RGBA;
|
||||
});
|
||||
}
|
||||
|
||||
static void node_mix_init(bNodeTree * /*tree*/, bNode *node)
|
||||
{
|
||||
NodeShaderMix *data = MEM_cnew<NodeShaderMix>(__func__);
|
||||
|
@ -497,5 +509,6 @@ void register_node_type_sh_mix()
|
|||
ntype.draw_buttons = file_ns::sh_node_mix_layout;
|
||||
ntype.labelfunc = file_ns::sh_node_mix_label;
|
||||
ntype.gather_link_search_ops = file_ns::node_mix_gather_link_searches;
|
||||
ntype.gather_add_node_search_ops = file_ns::gather_add_node_searches;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
|
|
@ -156,5 +156,6 @@ void register_node_type_sh_mix_rgb()
|
|||
ntype.gpu_fn = file_ns::gpu_shader_mix_rgb;
|
||||
ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ void register_node_type_sh_sephsv()
|
|||
ntype.declare = file_ns::node_declare_sephsv;
|
||||
ntype.gpu_fn = file_ns::gpu_shader_sephsv;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -77,6 +78,7 @@ void register_node_type_sh_combhsv()
|
|||
ntype.declare = file_ns::node_declare_combhsv;
|
||||
ntype.gpu_fn = file_ns::gpu_shader_combhsv;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ void register_node_type_sh_seprgb()
|
|||
ntype.gpu_fn = file_ns::gpu_shader_seprgb;
|
||||
ntype.build_multi_function = file_ns::sh_node_seprgb_build_multi_function;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@ -125,6 +126,7 @@ void register_node_type_sh_combrgb()
|
|||
ntype.gpu_fn = file_ns::gpu_shader_combrgb;
|
||||
ntype.build_multi_function = file_ns::sh_node_combrgb_build_multi_function;
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ void register_node_type_sh_squeeze()
|
|||
|
||||
sh_node_type_base(&ntype, SH_NODE_SQUEEZE, "Squeeze Value (Legacy)", NODE_CLASS_CONVERTER);
|
||||
ntype.gather_link_search_ops = nullptr;
|
||||
ntype.gather_add_node_search_ops = nullptr;
|
||||
ntype.declare = file_ns::node_declare;
|
||||
ntype.gpu_fn = file_ns::gpu_shader_squeeze;
|
||||
|
||||
|
|
|
@ -933,6 +933,49 @@ if(WITH_CODEC_FFMPEG)
|
|||
)
|
||||
endif()
|
||||
|
||||
if(NOT OPENIMAGEIO_IDIFF)
|
||||
message(STATUS "Disabling ImBuf image format tests because OIIO idiff does not exist")
|
||||
else()
|
||||
SET(OPTIONAL_FORMATS "")
|
||||
if(WITH_IMAGE_CINEON)
|
||||
set(OPTIONAL_FORMATS "${OPTIONAL_FORMATS} CINEON")
|
||||
endif()
|
||||
if(WITH_IMAGE_HDR)
|
||||
set(OPTIONAL_FORMATS "${OPTIONAL_FORMATS} HDR")
|
||||
endif()
|
||||
if(WITH_IMAGE_OPENEXR)
|
||||
set(OPTIONAL_FORMATS "${OPTIONAL_FORMATS} OPENEXR")
|
||||
endif()
|
||||
if(WITH_IMAGE_OPENJPEG)
|
||||
set(OPTIONAL_FORMATS "${OPTIONAL_FORMATS} OPENJPEG")
|
||||
endif()
|
||||
if(WITH_IMAGE_TIFF)
|
||||
set(OPTIONAL_FORMATS "${OPTIONAL_FORMATS} TIFF")
|
||||
endif()
|
||||
if(WITH_IMAGE_WEBP)
|
||||
set(OPTIONAL_FORMATS "${OPTIONAL_FORMATS} WEBP")
|
||||
endif()
|
||||
|
||||
add_blender_test(
|
||||
bf_imbuf_save
|
||||
--python ${CMAKE_CURRENT_LIST_DIR}/bl_imbuf_save.py
|
||||
--
|
||||
-test_dir "${TEST_SRC_DIR}/imbuf_io"
|
||||
-output_dir "${TEST_OUT_DIR}/imbuf_io/save"
|
||||
-idiff "${OPENIMAGEIO_IDIFF}"
|
||||
-optional_formats "${OPTIONAL_FORMATS}"
|
||||
)
|
||||
|
||||
add_blender_test(
|
||||
bf_imbuf_load
|
||||
--python ${CMAKE_CURRENT_LIST_DIR}/bl_imbuf_load.py
|
||||
--
|
||||
-test_dir "${TEST_SRC_DIR}/imbuf_io"
|
||||
-output_dir "${TEST_OUT_DIR}/imbuf_io/load"
|
||||
-idiff "${OPENIMAGEIO_IDIFF}"
|
||||
-optional_formats "${OPTIONAL_FORMATS}"
|
||||
)
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# SEQUENCER RENDER TESTS
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import bpy
|
||||
|
||||
sys.path.append(str(pathlib.Path(__file__).parent.absolute()))
|
||||
from modules.colored_print import print_message
|
||||
from modules.imbuf_test import AbstractImBufTest
|
||||
|
||||
|
||||
args = None
|
||||
|
||||
|
||||
class ImBufTest(AbstractImBufTest):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
AbstractImBufTest.init(args)
|
||||
|
||||
if cls.update:
|
||||
os.makedirs(cls.reference_load_dir, exist_ok=True)
|
||||
|
||||
def _get_image_files(self, file_pattern):
|
||||
return [f for f in pathlib.Path(self.reference_dir).glob(file_pattern)]
|
||||
|
||||
def _validate_metadata(self, img, ref_metadata_path, out_metadata_path):
|
||||
channels = img.channels
|
||||
is_float = img.is_float
|
||||
colorspace = img.colorspace_settings.name
|
||||
alpha_mode = img.alpha_mode
|
||||
actual_metadata = f"{channels=} {is_float=} {colorspace=} {alpha_mode=}"
|
||||
|
||||
# Save actual metadata
|
||||
out_metadata_path.write_text(actual_metadata, encoding="utf-8")
|
||||
|
||||
if ref_metadata_path.exists():
|
||||
# Compare with expected
|
||||
try:
|
||||
expected_metadata = ref_metadata_path.read_text(encoding="utf-8")
|
||||
|
||||
failed = not (actual_metadata == expected_metadata)
|
||||
except BaseException as e:
|
||||
if self.verbose:
|
||||
print_message(e.output.decode("utf-8", 'ignore'))
|
||||
failed = True
|
||||
else:
|
||||
if not self.update:
|
||||
return False
|
||||
|
||||
failed = True
|
||||
|
||||
if failed and self.update:
|
||||
# Update reference if requested.
|
||||
ref_metadata_path.write_text(actual_metadata, encoding="utf-8")
|
||||
failed = False
|
||||
|
||||
return not failed
|
||||
|
||||
def _save_exr(self, img, out_exr_path):
|
||||
scene = bpy.data.scenes[0]
|
||||
image_settings = scene.render.image_settings
|
||||
image_settings.file_format = "OPEN_EXR"
|
||||
image_settings.color_mode = "RGBA"
|
||||
image_settings.color_depth = "32"
|
||||
image_settings.exr_codec = "ZIP"
|
||||
|
||||
img.save_render(str(out_exr_path), scene=scene)
|
||||
|
||||
def _validate_pixels(self, img, ref_exr_path, out_exr_path):
|
||||
self._save_exr(img, out_exr_path)
|
||||
|
||||
return self.call_idiff(ref_exr_path, out_exr_path)
|
||||
|
||||
def check(self, file_pattern):
|
||||
image_files = self._get_image_files(file_pattern)
|
||||
if len(image_files) == 0:
|
||||
self.fail(f"No images found for pattern {file_pattern}")
|
||||
|
||||
for image_path in image_files:
|
||||
print_message(image_path.name, 'SUCCESS', 'RUN')
|
||||
|
||||
# Load the image under test
|
||||
bpy.ops.image.open(filepath=str(image_path))
|
||||
img = bpy.data.images[image_path.name]
|
||||
|
||||
# Compare the image with our exr/metadata references
|
||||
exr_filename = image_path.with_suffix(".exr").name
|
||||
metadata_filename = image_path.with_suffix(".txt").name
|
||||
|
||||
ref_exr_path = self.reference_load_dir.joinpath(exr_filename)
|
||||
ref_metadata_path = self.reference_load_dir.joinpath(metadata_filename)
|
||||
out_exr_path = self.output_dir.joinpath(exr_filename)
|
||||
out_metadata_path = self.output_dir.joinpath(metadata_filename)
|
||||
|
||||
res1 = self._validate_metadata(img, ref_metadata_path, out_metadata_path)
|
||||
res2 = self._validate_pixels(img, ref_exr_path, out_exr_path)
|
||||
|
||||
if not res1 or not res2:
|
||||
self.errors += 1
|
||||
print_message("Results are different from reference data")
|
||||
print_message(image_path.name, 'FAILURE', 'FAILED')
|
||||
else:
|
||||
print_message(image_path.name, 'SUCCESS', 'OK')
|
||||
|
||||
|
||||
class ImBufLoadTest(ImBufTest):
|
||||
def test_load_bmp(self):
|
||||
self.check("*.bmp")
|
||||
|
||||
def test_load_png(self):
|
||||
self.check("*.png")
|
||||
|
||||
def test_load_exr(self):
|
||||
self.skip_if_format_missing("OPENEXR")
|
||||
|
||||
self.check("*.exr")
|
||||
|
||||
def test_load_hdr(self):
|
||||
self.skip_if_format_missing("HDR")
|
||||
|
||||
self.check("*.hdr")
|
||||
|
||||
def test_load_targa(self):
|
||||
self.check("*.tga")
|
||||
|
||||
def test_load_tiff(self):
|
||||
self.skip_if_format_missing("TIFF")
|
||||
|
||||
self.check("*.tif")
|
||||
|
||||
def test_load_jpeg(self):
|
||||
self.check("*.jpg")
|
||||
|
||||
def test_load_jpeg2000(self):
|
||||
self.skip_if_format_missing("OPENJPEG")
|
||||
|
||||
self.check("*.jp2")
|
||||
self.check("*.j2c")
|
||||
|
||||
def test_load_dpx(self):
|
||||
self.skip_if_format_missing("CINEON")
|
||||
|
||||
self.check("*.dpx")
|
||||
|
||||
def test_load_cineon(self):
|
||||
self.skip_if_format_missing("CINEON")
|
||||
|
||||
self.check("*.cin")
|
||||
|
||||
def test_load_webp(self):
|
||||
self.skip_if_format_missing("WEBP")
|
||||
|
||||
self.check("*.webp")
|
||||
|
||||
|
||||
def main():
|
||||
global args
|
||||
import argparse
|
||||
|
||||
if '--' in sys.argv:
|
||||
argv = [sys.argv[0]] + sys.argv[sys.argv.index('--') + 1:]
|
||||
else:
|
||||
argv = sys.argv
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-test_dir', required=True, type=pathlib.Path)
|
||||
parser.add_argument('-output_dir', required=True, type=pathlib.Path)
|
||||
parser.add_argument('-idiff', required=True, type=pathlib.Path)
|
||||
parser.add_argument('-optional_formats', required=True)
|
||||
args, remaining = parser.parse_known_args(argv)
|
||||
|
||||
unittest.main(argv=remaining)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,273 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import bpy
|
||||
|
||||
sys.path.append(str(pathlib.Path(__file__).parent.absolute()))
|
||||
from modules.colored_print import print_message
|
||||
from modules.imbuf_test import AbstractImBufTest
|
||||
|
||||
|
||||
args = None
|
||||
|
||||
TEMPLATE_RGBA08 = "template-rgba08.png"
|
||||
TEMPLATE_RGBA32 = "template-rgba32.exr"
|
||||
|
||||
|
||||
class ImBufTest(AbstractImBufTest):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
AbstractImBufTest.init(args)
|
||||
|
||||
if cls.update:
|
||||
os.makedirs(cls.reference_dir, exist_ok=True)
|
||||
|
||||
def _load_template_image(self, name, template_name):
|
||||
image_path = str(self.test_dir.joinpath(template_name))
|
||||
bpy.ops.image.open(filepath=image_path)
|
||||
img = bpy.data.images[template_name]
|
||||
img.name = name
|
||||
return img
|
||||
|
||||
def _setup_image(self, src, ext, settings):
|
||||
scene = bpy.data.scenes[0]
|
||||
image_settings = scene.render.image_settings
|
||||
|
||||
# Make an appropriate filename which embeds all relevant settings and
|
||||
# set the file output parameters for the exact configuration we want
|
||||
name = ""
|
||||
for s in settings:
|
||||
if s == "color_depth":
|
||||
name += str(settings[s]).rjust(2, '0') + "-"
|
||||
else:
|
||||
name += str(settings[s]) + "-"
|
||||
|
||||
setattr(image_settings, s, settings[s])
|
||||
|
||||
image_name = name[:-1].lower() + "__from__" + src + "." + ext
|
||||
|
||||
return image_name
|
||||
|
||||
def _save_image(self, src, image_name):
|
||||
loaders = {
|
||||
"rgba08": lambda name: self._load_template_image(name, TEMPLATE_RGBA08),
|
||||
"rgba32": lambda name: self._load_template_image(name, TEMPLATE_RGBA32),
|
||||
}
|
||||
|
||||
# Load the template image and assign it the image name
|
||||
img = loaders[src](image_name)
|
||||
|
||||
# Save the image in the desired format with the desired settings
|
||||
scene = bpy.data.scenes[0]
|
||||
ref_image_path = self.reference_dir.joinpath(img.name)
|
||||
out_image_path = self.output_dir.joinpath(img.name)
|
||||
img.save_render(str(out_image_path), scene=scene)
|
||||
|
||||
# Completely remove image in case it was modified during save
|
||||
img.user_clear()
|
||||
bpy.data.images.remove(img)
|
||||
return ref_image_path, out_image_path
|
||||
|
||||
def _validate(self, ref_image_path, out_image_path):
|
||||
return self.call_idiff(ref_image_path, out_image_path)
|
||||
|
||||
def check(self, src, ext, settings):
|
||||
image_name = self._setup_image(src, ext, settings)
|
||||
print_message(image_name, 'SUCCESS', 'RUN')
|
||||
|
||||
ref_image_path, out_image_path = self._save_image(src, image_name)
|
||||
|
||||
if not self._validate(ref_image_path, out_image_path):
|
||||
self.errors += 1
|
||||
print_message("Save result is different from reference image")
|
||||
print_message(ref_image_path.name, 'FAILURE', 'FAILED')
|
||||
else:
|
||||
print_message(ref_image_path.name, 'SUCCESS', 'OK')
|
||||
|
||||
|
||||
# autopep8: off
|
||||
class ImBufSaveTest(ImBufTest):
|
||||
def test_save_bmp(self):
|
||||
self.check(src="rgba08", ext="bmp", settings={"file_format": "BMP", "color_mode": "BW"})
|
||||
self.check(src="rgba08", ext="bmp", settings={"file_format": "BMP", "color_mode": "RGB"})
|
||||
|
||||
self.check(src="rgba32", ext="bmp", settings={"file_format": "BMP", "color_mode": "BW"})
|
||||
self.check(src="rgba32", ext="bmp", settings={"file_format": "BMP", "color_mode": "RGB"})
|
||||
|
||||
def test_save_png(self):
|
||||
self.check(src="rgba08", ext="png", settings={"file_format": "PNG", "color_mode": "BW", "color_depth": "8", "compression": 15})
|
||||
self.check(src="rgba08", ext="png", settings={"file_format": "PNG", "color_mode": "RGB", "color_depth": "8", "compression": 15})
|
||||
self.check(src="rgba08", ext="png", settings={"file_format": "PNG", "color_mode": "RGBA", "color_depth": "8", "compression": 15})
|
||||
self.check(src="rgba08", ext="png", settings={"file_format": "PNG", "color_mode": "BW", "color_depth": "16", "compression": 25})
|
||||
self.check(src="rgba08", ext="png", settings={"file_format": "PNG", "color_mode": "RGB", "color_depth": "16", "compression": 25})
|
||||
self.check(src="rgba08", ext="png", settings={"file_format": "PNG", "color_mode": "RGBA", "color_depth": "16", "compression": 25})
|
||||
|
||||
self.check(src="rgba32", ext="png", settings={"file_format": "PNG", "color_mode": "BW", "color_depth": "8", "compression": 15})
|
||||
self.check(src="rgba32", ext="png", settings={"file_format": "PNG", "color_mode": "RGB", "color_depth": "8", "compression": 15})
|
||||
self.check(src="rgba32", ext="png", settings={"file_format": "PNG", "color_mode": "RGBA", "color_depth": "8", "compression": 15})
|
||||
self.check(src="rgba32", ext="png", settings={"file_format": "PNG", "color_mode": "BW", "color_depth": "16", "compression": 25})
|
||||
self.check(src="rgba32", ext="png", settings={"file_format": "PNG", "color_mode": "RGB", "color_depth": "16", "compression": 25})
|
||||
self.check(src="rgba32", ext="png", settings={"file_format": "PNG", "color_mode": "RGBA", "color_depth": "16", "compression": 25})
|
||||
|
||||
def test_save_exr(self):
|
||||
self.skip_if_format_missing("OPENEXR")
|
||||
|
||||
self.check(src="rgba08", ext="exr", settings={"file_format": "OPEN_EXR", "color_mode": "BW", "color_depth": "16", "exr_codec": "ZIP"})
|
||||
self.check(src="rgba08", ext="exr", settings={"file_format": "OPEN_EXR", "color_mode": "RGB", "color_depth": "16", "exr_codec": "DWAA"})
|
||||
self.check(src="rgba08", ext="exr", settings={"file_format": "OPEN_EXR", "color_mode": "RGBA", "color_depth": "16", "exr_codec": "DWAB"})
|
||||
self.check(src="rgba08", ext="exr", settings={"file_format": "OPEN_EXR", "color_mode": "BW", "color_depth": "32", "exr_codec": "DWAB"})
|
||||
self.check(src="rgba08", ext="exr", settings={"file_format": "OPEN_EXR", "color_mode": "RGB", "color_depth": "32", "exr_codec": "DWAA"})
|
||||
self.check(src="rgba08", ext="exr", settings={"file_format": "OPEN_EXR", "color_mode": "RGBA", "color_depth": "32", "exr_codec": "ZIP"})
|
||||
|
||||
self.check(src="rgba32", ext="exr", settings={"file_format": "OPEN_EXR", "color_mode": "BW", "color_depth": "16", "exr_codec": "ZIP"})
|
||||
self.check(src="rgba32", ext="exr", settings={"file_format": "OPEN_EXR", "color_mode": "RGB", "color_depth": "16", "exr_codec": "DWAA"})
|
||||
self.check(src="rgba32", ext="exr", settings={"file_format": "OPEN_EXR", "color_mode": "RGBA", "color_depth": "16", "exr_codec": "DWAB"})
|
||||
self.check(src="rgba32", ext="exr", settings={"file_format": "OPEN_EXR", "color_mode": "BW", "color_depth": "32", "exr_codec": "DWAB"})
|
||||
self.check(src="rgba32", ext="exr", settings={"file_format": "OPEN_EXR", "color_mode": "RGB", "color_depth": "32", "exr_codec": "DWAA"})
|
||||
self.check(src="rgba32", ext="exr", settings={"file_format": "OPEN_EXR", "color_mode": "RGBA", "color_depth": "32", "exr_codec": "ZIP"})
|
||||
|
||||
def test_save_hdr(self):
|
||||
self.skip_if_format_missing("HDR")
|
||||
|
||||
self.check(src="rgba08", ext="hdr", settings={"file_format": "HDR", "color_mode": "BW"})
|
||||
self.check(src="rgba08", ext="hdr", settings={"file_format": "HDR", "color_mode": "RGB"})
|
||||
|
||||
self.check(src="rgba32", ext="hdr", settings={"file_format": "HDR", "color_mode": "BW"})
|
||||
self.check(src="rgba32", ext="hdr", settings={"file_format": "HDR", "color_mode": "RGB"})
|
||||
|
||||
def test_save_targa(self):
|
||||
self.check(src="rgba08", ext="tga", settings={"file_format": "TARGA", "color_mode": "BW"})
|
||||
self.check(src="rgba08", ext="tga", settings={"file_format": "TARGA", "color_mode": "RGB"})
|
||||
self.check(src="rgba08", ext="tga", settings={"file_format": "TARGA", "color_mode": "RGBA"})
|
||||
|
||||
self.check(src="rgba32", ext="tga", settings={"file_format": "TARGA", "color_mode": "BW"})
|
||||
self.check(src="rgba32", ext="tga", settings={"file_format": "TARGA", "color_mode": "RGB"})
|
||||
self.check(src="rgba32", ext="tga", settings={"file_format": "TARGA", "color_mode": "RGBA"})
|
||||
|
||||
def test_save_targa_raw(self):
|
||||
self.check(src="rgba08", ext="tga", settings={"file_format": "TARGA_RAW", "color_mode": "BW"})
|
||||
self.check(src="rgba08", ext="tga", settings={"file_format": "TARGA_RAW", "color_mode": "RGB"})
|
||||
self.check(src="rgba08", ext="tga", settings={"file_format": "TARGA_RAW", "color_mode": "RGBA"})
|
||||
|
||||
self.check(src="rgba32", ext="tga", settings={"file_format": "TARGA_RAW", "color_mode": "BW"})
|
||||
self.check(src="rgba32", ext="tga", settings={"file_format": "TARGA_RAW", "color_mode": "RGB"})
|
||||
self.check(src="rgba32", ext="tga", settings={"file_format": "TARGA_RAW", "color_mode": "RGBA"})
|
||||
|
||||
def test_save_tiff(self):
|
||||
self.skip_if_format_missing("TIFF")
|
||||
|
||||
self.check(src="rgba08", ext="tif", settings={"file_format": "TIFF", "color_mode": "BW", "color_depth": "8", "tiff_codec": "DEFLATE"})
|
||||
self.check(src="rgba08", ext="tif", settings={"file_format": "TIFF", "color_mode": "RGB", "color_depth": "8", "tiff_codec": "LZW"})
|
||||
self.check(src="rgba08", ext="tif", settings={"file_format": "TIFF", "color_mode": "RGBA", "color_depth": "8", "tiff_codec": "PACKBITS"})
|
||||
self.check(src="rgba08", ext="tif", settings={"file_format": "TIFF", "color_mode": "BW", "color_depth": "16", "tiff_codec": "PACKBITS"})
|
||||
self.check(src="rgba08", ext="tif", settings={"file_format": "TIFF", "color_mode": "RGB", "color_depth": "16", "tiff_codec": "LZW"})
|
||||
self.check(src="rgba08", ext="tif", settings={"file_format": "TIFF", "color_mode": "RGBA", "color_depth": "16", "tiff_codec": "DEFLATE"})
|
||||
|
||||
self.check(src="rgba32", ext="tif", settings={"file_format": "TIFF", "color_mode": "BW", "color_depth": "8", "tiff_codec": "DEFLATE"})
|
||||
self.check(src="rgba32", ext="tif", settings={"file_format": "TIFF", "color_mode": "RGB", "color_depth": "8", "tiff_codec": "LZW"})
|
||||
self.check(src="rgba32", ext="tif", settings={"file_format": "TIFF", "color_mode": "RGBA", "color_depth": "8", "tiff_codec": "PACKBITS"})
|
||||
self.check(src="rgba32", ext="tif", settings={"file_format": "TIFF", "color_mode": "BW", "color_depth": "16", "tiff_codec": "PACKBITS"})
|
||||
self.check(src="rgba32", ext="tif", settings={"file_format": "TIFF", "color_mode": "RGB", "color_depth": "16", "tiff_codec": "LZW"})
|
||||
self.check(src="rgba32", ext="tif", settings={"file_format": "TIFF", "color_mode": "RGBA", "color_depth": "16", "tiff_codec": "DEFLATE"})
|
||||
|
||||
def test_save_jpeg(self):
|
||||
self.check(src="rgba08", ext="jpg", settings={"file_format": "JPEG", "color_mode": "BW", "quality": 90})
|
||||
self.check(src="rgba08", ext="jpg", settings={"file_format": "JPEG", "color_mode": "RGB", "quality": 90})
|
||||
|
||||
self.check(src="rgba32", ext="jpg", settings={"file_format": "JPEG", "color_mode": "BW", "quality": 70})
|
||||
self.check(src="rgba32", ext="jpg", settings={"file_format": "JPEG", "color_mode": "RGB", "quality": 70})
|
||||
|
||||
def test_save_jpeg2000(self):
|
||||
self.skip_if_format_missing("OPENJPEG")
|
||||
|
||||
# Is there a better combination of settings we can use so there's not so many?
|
||||
# Is this a good mix?
|
||||
self.check(src="rgba08", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "BW", "color_depth": "8", "jpeg2k_codec": "JP2", "quality": 90})
|
||||
self.check(src="rgba08", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "BW", "color_depth": "12", "jpeg2k_codec": "JP2", "quality": 90})
|
||||
self.check(src="rgba08", ext="j2c", settings={"file_format": "JPEG2000", "color_mode": "BW", "color_depth": "16", "jpeg2k_codec": "J2K", "quality": 90})
|
||||
self.check(src="rgba08", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "RGB", "color_depth": "8", "jpeg2k_codec": "JP2", "quality": 90})
|
||||
self.check(src="rgba08", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "RGB", "color_depth": "12", "jpeg2k_codec": "JP2", "quality": 90})
|
||||
self.check(src="rgba08", ext="j2c", settings={"file_format": "JPEG2000", "color_mode": "RGB", "color_depth": "16", "jpeg2k_codec": "J2K", "quality": 90})
|
||||
self.check(src="rgba08", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "RGBA", "color_depth": "8", "jpeg2k_codec": "JP2", "quality": 90})
|
||||
self.check(src="rgba08", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "RGBA", "color_depth": "12", "jpeg2k_codec": "JP2", "quality": 90})
|
||||
self.check(src="rgba08", ext="j2c", settings={"file_format": "JPEG2000", "color_mode": "RGBA", "color_depth": "16", "jpeg2k_codec": "J2K", "quality": 90})
|
||||
|
||||
self.check(src="rgba32", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "BW", "color_depth": "8", "jpeg2k_codec": "JP2", "quality": 70})
|
||||
self.check(src="rgba32", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "BW", "color_depth": "12", "jpeg2k_codec": "JP2", "quality": 70})
|
||||
self.check(src="rgba32", ext="j2c", settings={"file_format": "JPEG2000", "color_mode": "BW", "color_depth": "16", "jpeg2k_codec": "J2K", "quality": 70})
|
||||
self.check(src="rgba32", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "RGB", "color_depth": "8", "jpeg2k_codec": "JP2", "quality": 70})
|
||||
self.check(src="rgba32", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "RGB", "color_depth": "12", "jpeg2k_codec": "JP2", "quality": 70})
|
||||
self.check(src="rgba32", ext="j2c", settings={"file_format": "JPEG2000", "color_mode": "RGB", "color_depth": "16", "jpeg2k_codec": "J2K", "quality": 70})
|
||||
self.check(src="rgba32", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "RGBA", "color_depth": "8", "jpeg2k_codec": "JP2", "quality": 70})
|
||||
self.check(src="rgba32", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "RGBA", "color_depth": "12", "jpeg2k_codec": "JP2", "quality": 70})
|
||||
self.check(src="rgba32", ext="j2c", settings={"file_format": "JPEG2000", "color_mode": "RGBA", "color_depth": "16", "jpeg2k_codec": "J2K", "quality": 70})
|
||||
|
||||
# Note: The 'use_jpeg2k_cinema_preset' option mandates very large images
|
||||
# self.check(src="rgba08", ext="jpg", settings={"file_format":"JPEG2000", "color_mode":"RGBA", "color_depth":"8", "jpeg2k_codec":"JP2", "use_jpeg2k_cinema_preset":True, "use_jpeg2k_cinema_48":False, "use_jpeg2k_ycc":False, "quality":70})
|
||||
# self.check(src="rgba32", ext="jpg", settings={"file_format":"JPEG2000", "color_mode":"RGBA", "color_depth":"8", "jpeg2k_codec":"JP2", "use_jpeg2k_cinema_preset":True, "use_jpeg2k_cinema_48":False, "use_jpeg2k_ycc":False, "quality":70})
|
||||
|
||||
self.check(src="rgba08", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "RGBA", "color_depth": "12", "jpeg2k_codec": "JP2", "use_jpeg2k_cinema_preset": False, "use_jpeg2k_cinema_48": True, "use_jpeg2k_ycc": False, "quality": 70})
|
||||
self.check(src="rgba32", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "RGBA", "color_depth": "12", "jpeg2k_codec": "JP2", "use_jpeg2k_cinema_preset": False, "use_jpeg2k_cinema_48": True, "use_jpeg2k_ycc": False, "quality": 70})
|
||||
|
||||
self.check(src="rgba08", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "RGBA", "color_depth": "16", "jpeg2k_codec": "JP2", "use_jpeg2k_cinema_preset": False, "use_jpeg2k_cinema_48": False, "use_jpeg2k_ycc": True, "quality": 70})
|
||||
self.check(src="rgba32", ext="jp2", settings={"file_format": "JPEG2000", "color_mode": "RGBA", "color_depth": "16", "jpeg2k_codec": "JP2", "use_jpeg2k_cinema_preset": False, "use_jpeg2k_cinema_48": False, "use_jpeg2k_ycc": True, "quality": 70})
|
||||
|
||||
def test_save_dpx(self):
|
||||
self.skip_if_format_missing("CINEON")
|
||||
|
||||
self.check(src="rgba08", ext="dpx", settings={"file_format": "DPX", "color_mode": "RGB", "color_depth": "8", "use_cineon_log": False})
|
||||
self.check(src="rgba08", ext="dpx", settings={"file_format": "DPX", "color_mode": "RGB", "color_depth": "12", "use_cineon_log": False})
|
||||
self.check(src="rgba08", ext="dpx", settings={"file_format": "DPX", "color_mode": "RGB", "color_depth": "16", "use_cineon_log": False})
|
||||
self.check(src="rgba08", ext="dpx", settings={"file_format": "DPX", "color_mode": "RGBA", "color_depth": "10", "use_cineon_log": True})
|
||||
self.check(src="rgba08", ext="dpx", settings={"file_format": "DPX", "color_mode": "RGBA", "color_depth": "12", "use_cineon_log": True})
|
||||
self.check(src="rgba08", ext="dpx", settings={"file_format": "DPX", "color_mode": "RGBA", "color_depth": "16", "use_cineon_log": True})
|
||||
|
||||
self.check(src="rgba32", ext="dpx", settings={"file_format": "DPX", "color_mode": "RGB", "color_depth": "8", "use_cineon_log": False})
|
||||
self.check(src="rgba32", ext="dpx", settings={"file_format": "DPX", "color_mode": "RGB", "color_depth": "12", "use_cineon_log": False})
|
||||
self.check(src="rgba32", ext="dpx", settings={"file_format": "DPX", "color_mode": "RGB", "color_depth": "16", "use_cineon_log": False})
|
||||
self.check(src="rgba32", ext="dpx", settings={"file_format": "DPX", "color_mode": "RGBA", "color_depth": "10", "use_cineon_log": True})
|
||||
self.check(src="rgba32", ext="dpx", settings={"file_format": "DPX", "color_mode": "RGBA", "color_depth": "12", "use_cineon_log": True})
|
||||
self.check(src="rgba32", ext="dpx", settings={"file_format": "DPX", "color_mode": "RGBA", "color_depth": "16", "use_cineon_log": True})
|
||||
|
||||
def test_save_cineon(self):
|
||||
self.skip_if_format_missing("CINEON")
|
||||
|
||||
self.check(src="rgba08", ext="cin", settings={"file_format": "CINEON", "color_mode": "RGB"})
|
||||
self.check(src="rgba32", ext="cin", settings={"file_format": "CINEON", "color_mode": "RGB"})
|
||||
|
||||
def test_save_webp(self):
|
||||
self.skip_if_format_missing("WEBP")
|
||||
|
||||
self.check(src="rgba08", ext="webp", settings={"file_format": "WEBP", "color_mode": "RGB", "quality": 90})
|
||||
self.check(src="rgba08", ext="webp", settings={"file_format": "WEBP", "color_mode": "RGBA", "quality": 90})
|
||||
|
||||
# Note: These 2 variations are problematic on MacOS ARM64 (#105006)
|
||||
# self.check(src="rgba32", ext="webp", settings={"file_format": "WEBP", "color_mode": "RGB", "quality": 70})
|
||||
# self.check(src="rgba32", ext="webp", settings={"file_format": "WEBP", "color_mode": "RGBA", "quality": 70})
|
||||
# autopep8: on
|
||||
|
||||
|
||||
def main():
|
||||
global args
|
||||
import argparse
|
||||
|
||||
if '--' in sys.argv:
|
||||
argv = [sys.argv[0]] + sys.argv[sys.argv.index('--') + 1:]
|
||||
else:
|
||||
argv = sys.argv
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-test_dir', required=True, type=pathlib.Path)
|
||||
parser.add_argument('-output_dir', required=True, type=pathlib.Path)
|
||||
parser.add_argument('-idiff', required=True, type=pathlib.Path)
|
||||
parser.add_argument('-optional_formats', required=True)
|
||||
args, remaining = parser.parse_known_args(argv)
|
||||
|
||||
unittest.main(argv=remaining)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,46 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
class COLORS_ANSI:
|
||||
RED = '\033[00;31m'
|
||||
GREEN = '\033[00;32m'
|
||||
ENDC = '\033[0m'
|
||||
|
||||
|
||||
class COLORS_NONE:
|
||||
RED = ''
|
||||
GREEN = ''
|
||||
ENDC = ''
|
||||
|
||||
|
||||
COLORS = COLORS_NONE
|
||||
|
||||
|
||||
def use_message_colors():
|
||||
global COLORS, COLORS_ANSI
|
||||
COLORS = COLORS_ANSI
|
||||
|
||||
|
||||
def print_message(message, type=None, status=''):
|
||||
if type == 'SUCCESS':
|
||||
print(COLORS.GREEN, end="")
|
||||
elif type == 'FAILURE':
|
||||
print(COLORS.RED, end="")
|
||||
status_text = ...
|
||||
if status == 'RUN':
|
||||
status_text = " RUN "
|
||||
elif status == 'OK':
|
||||
status_text = " OK "
|
||||
elif status == 'PASSED':
|
||||
status_text = " PASSED "
|
||||
elif status == 'FAILED':
|
||||
status_text = " FAILED "
|
||||
else:
|
||||
status_text = status
|
||||
if status_text:
|
||||
print("[{}]" . format(status_text), end="")
|
||||
print(COLORS.ENDC, end="")
|
||||
print(" {}" . format(message))
|
||||
sys.stdout.flush()
|
|
@ -0,0 +1,92 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import subprocess
|
||||
import unittest
|
||||
|
||||
from .colored_print import (print_message, use_message_colors)
|
||||
|
||||
|
||||
class AbstractImBufTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def init(cls, args):
|
||||
cls.test_dir = pathlib.Path(args.test_dir)
|
||||
cls.reference_dir = pathlib.Path(args.test_dir).joinpath("reference")
|
||||
cls.reference_load_dir = pathlib.Path(args.test_dir).joinpath("reference_load")
|
||||
cls.output_dir = pathlib.Path(args.output_dir)
|
||||
cls.diff_dir = pathlib.Path(args.output_dir).joinpath("diff")
|
||||
cls.idiff = pathlib.Path(args.idiff)
|
||||
cls.optional_formats = args.optional_formats
|
||||
|
||||
os.makedirs(cls.diff_dir, exist_ok=True)
|
||||
|
||||
cls.errors = 0
|
||||
cls.fail_threshold = 0.016
|
||||
cls.fail_percent = 1
|
||||
cls.verbose = os.environ.get("BLENDER_VERBOSE") is not None
|
||||
cls.update = os.getenv('BLENDER_TEST_UPDATE') is not None
|
||||
if os.environ.get("BLENDER_TEST_COLOR") is not None:
|
||||
use_message_colors()
|
||||
|
||||
def setUp(self):
|
||||
self.errors = 0
|
||||
print_message("")
|
||||
|
||||
def tearDown(self):
|
||||
if self.errors > 0:
|
||||
self.fail("{} errors encountered" . format(self.errors))
|
||||
|
||||
def skip_if_format_missing(self, format):
|
||||
if self.optional_formats.find(format) < 0:
|
||||
self.skipTest("format not available")
|
||||
|
||||
def call_idiff(self, ref_path, out_path):
|
||||
ref_filepath = str(ref_path)
|
||||
out_filepath = str(out_path)
|
||||
out_name = out_path.name
|
||||
if os.path.exists(ref_filepath):
|
||||
# Diff images test with threshold.
|
||||
command = (
|
||||
str(self.idiff),
|
||||
"-fail", str(self.fail_threshold),
|
||||
"-failpercent", str(self.fail_percent),
|
||||
ref_filepath,
|
||||
out_filepath,
|
||||
)
|
||||
try:
|
||||
subprocess.check_output(command)
|
||||
failed = False
|
||||
except subprocess.CalledProcessError as e:
|
||||
if self.verbose:
|
||||
print_message(e.output.decode("utf-8", 'ignore'))
|
||||
failed = e.returncode != 1
|
||||
else:
|
||||
if not self.update:
|
||||
return False
|
||||
|
||||
failed = True
|
||||
|
||||
if failed and self.update:
|
||||
# Update reference image if requested.
|
||||
shutil.copy(out_filepath, ref_filepath)
|
||||
failed = False
|
||||
|
||||
# Generate diff image.
|
||||
diff_img = str(self.diff_dir.joinpath(out_name + ".diff.png"))
|
||||
command = (
|
||||
str(self.idiff),
|
||||
"-o", diff_img,
|
||||
"-abs", "-scale", "16",
|
||||
ref_filepath,
|
||||
out_filepath
|
||||
)
|
||||
|
||||
try:
|
||||
subprocess.check_output(command)
|
||||
except subprocess.CalledProcessError as e:
|
||||
if self.verbose:
|
||||
print_message(e.output.decode("utf-8", 'ignore'))
|
||||
|
||||
return not failed
|
|
@ -14,44 +14,7 @@ import sys
|
|||
import time
|
||||
|
||||
from . import global_report
|
||||
|
||||
|
||||
class COLORS_ANSI:
|
||||
RED = '\033[00;31m'
|
||||
GREEN = '\033[00;32m'
|
||||
ENDC = '\033[0m'
|
||||
|
||||
|
||||
class COLORS_DUMMY:
|
||||
RED = ''
|
||||
GREEN = ''
|
||||
ENDC = ''
|
||||
|
||||
|
||||
COLORS = COLORS_DUMMY
|
||||
|
||||
|
||||
def print_message(message, type=None, status=''):
|
||||
if type == 'SUCCESS':
|
||||
print(COLORS.GREEN, end="")
|
||||
elif type == 'FAILURE':
|
||||
print(COLORS.RED, end="")
|
||||
status_text = ...
|
||||
if status == 'RUN':
|
||||
status_text = " RUN "
|
||||
elif status == 'OK':
|
||||
status_text = " OK "
|
||||
elif status == 'PASSED':
|
||||
status_text = " PASSED "
|
||||
elif status == 'FAILED':
|
||||
status_text = " FAILED "
|
||||
else:
|
||||
status_text = status
|
||||
if status_text:
|
||||
print("[{}]" . format(status_text), end="")
|
||||
print(COLORS.ENDC, end="")
|
||||
print(" {}" . format(message))
|
||||
sys.stdout.flush()
|
||||
from .colored_print import (print_message, use_message_colors)
|
||||
|
||||
|
||||
def blend_list(dirpath, device, blacklist):
|
||||
|
@ -151,8 +114,7 @@ class Report:
|
|||
self.update = os.getenv('BLENDER_TEST_UPDATE') is not None
|
||||
|
||||
if os.environ.get("BLENDER_TEST_COLOR") is not None:
|
||||
global COLORS, COLORS_ANSI
|
||||
COLORS = COLORS_ANSI
|
||||
use_message_colors()
|
||||
|
||||
self.failed_tests = ""
|
||||
self.passed_tests = ""
|
||||
|
|
Loading…
Reference in New Issue