MacOS: Enable support for EDR rendering #105662

Merged
Brecht Van Lommel merged 26 commits from Jason-Fielder/blender:macos_EDR_support into main 2023-08-09 14:25:23 +02:00
56 changed files with 1039 additions and 131265 deletions
Showing only changes of commit 7ffd2b3d52 - Show all commits

View File

@ -14,14 +14,14 @@ if [ `id -u` -ne 0 ]; then
fi
# Required by: config manager command below to enable powertools.
dnf install 'dnf-command(config-manager)'
dnf -y install 'dnf-command(config-manager)'
# Packages `ninja-build` and `meson` are not available unless CBR or PowerTools repositories are enabled.
# See: https://wiki.rockylinux.org/rocky/repo/#notes-on-unlisted-repositories
dnf config-manager --set-enabled powertools
# Required by: epel-release has the patchelf and rubygem-asciidoctor packages
dnf install epel-release
dnf -y install epel-release
# `yum-config-manager` does not come in the default minimal install,
# so make sure it is installed and available.

View File

@ -0,0 +1,106 @@
"""
USD Hook Example
++++++++++++++++
This example shows an implementation of ``USDHook`` to extend USD
export functionalty.
One may optionally define one or both of the following callback functions
in the ``USDHook`` subclass.
Hook function ``on_export()`` is called before the USD export finalizes,
allowing modifications to the USD stage immediately before it is
saved. This function takes as an argument an instance of an
internally defined class ``USDSceneExportContext`` which provides the
following accessors to the scene data:
- ``get_stage()`` returns the USD stage to be saved.
- ``get_depsgraph()`` returns the Blender scene dependency graph.
Hook function ``on_material_export()`` is called for each material that is exported,
allowing modifications to the USD material, such as shader generation.
It is called with three arguments:
-``export_context``: An instance of the internally defined type ``USDMaterialExportContext``.
-``bl_material``: The source Blender material.
-``usd_material``: The target USD material to be exported.
``USDMaterialExportContext`` implements a ``get_stage()`` function which returns the
USD stage to be saved.
Note that the target USD material might already have connected shaders created by the USD exporter or
by other material export hooks.
The hook functions should return ``True`` on success or ``False`` if the operation was bypasssed or
otherwise failed to complete. Exceptions raised by these functions will be reported in Blender, with
the exception details printed to the console.
The ``USDHookExample`` class in this example impements an ``on_export()`` function to add custom data to
the stage's root layer and an ``on_material_export()`` function to create a simple ``MaterialX`` shader
on the USD material.
"""
import bpy
import bpy.types
import pxr.Gf as Gf
import pxr.Sdf as Sdf
import pxr.Usd as Usd
import pxr.UsdShade as UsdShade
class USDHookExample(bpy.types.USDHook):
bl_idname = "usd_hook_example"
bl_label = "Example"
bl_description = "Example implementation of USD IO hooks"
@staticmethod
def on_export(export_context):
""" Include the Blender filepath in the root layer custom data.
"""
stage = export_context.get_stage()
if stage is None:
return False
data = bpy.data
if data is None:
return False
# Set the custom data.
rootLayer = stage.GetRootLayer()
customData = rootLayer.customLayerData
customData["blenderFilepath"] = data.filepath
rootLayer.customLayerData = customData
return True
@staticmethod
def on_material_export(export_context, bl_material, usd_material):
""" Create a simple MaterialX shader on the exported material.
"""
stage = export_context.get_stage()
# Create a MaterialX standard surface shader
mtl_path = usd_material.GetPrim().GetPath()
shader = UsdShade.Shader.Define(stage, mtl_path.AppendPath("mtlxstandard_surface"))
shader.CreateIdAttr("ND_standard_surface_surfaceshader")
# Connect the shader. MaterialX materials use "mtlx" renderContext
usd_material.CreateSurfaceOutput("mtlx").ConnectToSource(shader.ConnectableAPI(), "out")
# Set the color to the Blender material's viewport display color.
col = bl_material.diffuse_color
shader.CreateInput("base_color", Sdf.ValueTypeNames.Color3f).Set(Gf.Vec3f(col[0], col[1], col[2]))
return True
def register():
bpy.utils.register_class(USDHookExample)
def unregister():
bpy.utils.unregister_class(USDHookExample)
if __name__ == "__main__":
register()

View File

@ -19,6 +19,11 @@ float safe_modulo(float a, float b)
return (b != 0.0) ? fmod(a, b) : 0.0;
}
float safe_floored_modulo(float a, float b)
{
return (b != 0.0) ? a - floor(a / b) * b : 0.0;
}
float fract(float a)
{
return a - floor(a);

View File

@ -52,6 +52,8 @@ shader node_math(string math_type = "add",
Value = Value1 - floor(Value1);
else if (math_type == "modulo")
Value = safe_modulo(Value1, Value2);
else if (math_type == "floored_modulo")
Value = safe_floored_modulo(Value1, Value2);
else if (math_type == "trunc")
Value = trunc(Value1);
else if (math_type == "snap")

View File

@ -145,6 +145,8 @@ ccl_device float svm_math(NodeMathType type, float a, float b, float c)
return a - floorf(a);
case NODE_MATH_MODULO:
return safe_modulo(a, b);
case NODE_MATH_FLOORED_MODULO:
return safe_floored_modulo(a, b);
case NODE_MATH_TRUNC:
return a >= 0.0f ? floorf(a) : ceilf(a);
case NODE_MATH_SNAP:

View File

@ -182,6 +182,7 @@ typedef enum NodeMathType {
NODE_MATH_PINGPONG,
NODE_MATH_SMOOTH_MIN,
NODE_MATH_SMOOTH_MAX,
NODE_MATH_FLOORED_MODULO,
} NodeMathType;
typedef enum NodeVectorMathType {

View File

@ -6292,6 +6292,7 @@ NODE_DEFINE(MathNode)
type_enum.insert("less_than", NODE_MATH_LESS_THAN);
type_enum.insert("greater_than", NODE_MATH_GREATER_THAN);
type_enum.insert("modulo", NODE_MATH_MODULO);
type_enum.insert("floored_modulo", NODE_MATH_FLOORED_MODULO);
type_enum.insert("absolute", NODE_MATH_ABSOLUTE);
type_enum.insert("arctan2", NODE_MATH_ARCTAN2);
type_enum.insert("floor", NODE_MATH_FLOOR);

View File

@ -732,6 +732,11 @@ ccl_device float safe_modulo(float a, float b)
return (b != 0.0f) ? fmodf(a, b) : 0.0f;
}
ccl_device float safe_floored_modulo(float a, float b)
{
return (b != 0.0f) ? a - floorf(a / b) * b : 0.0f;
}
ccl_device_inline float sqr(float a)
{
return a * a;

View File

@ -114,8 +114,7 @@ colorspaces:
description: |
sRGB display space
isdata: false
to_reference: !<FileTransform> {src: srgb.spi1d, interpolation: linear}
from_reference: !<FileTransform> {src: srgb_inv.spi1d, interpolation: linear}
from_reference: !<ExponentWithLinearTransform> {gamma: 2.4, offset: 0.055, direction: inverse}
- !<ColorSpace>
name: Non-Color

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -676,7 +676,7 @@ const bTheme U_theme_default = {
.scene = RGBA(0x808033ff),
.audio = RGBA(0x448080ff),
.effect = RGBA(0x514a73ff),
.transition = RGBA(0x8f4571ff),
.transition = RGBA(0x50458fff),
.meta = RGBA(0x5b4d91ff),
.text_strip = RGBA(0x824c8fff),
.color_strip = RGBA(0x8f8f8fff),

View File

@ -942,6 +942,10 @@ class KeyingSetInfo(StructRNA, metaclass=RNAMeta):
__slots__ = ()
class USDHook(StructRNA, metaclass=RNAMeta):
__slots__ = ()
class AddonPreferences(StructRNA, metaclass=RNAMeta):
__slots__ = ()

View File

@ -819,6 +819,7 @@
scene_strip="#828f50"
audio_strip="#4c8f8f"
effect_strip="#4c456c"
transition_strip="#50458F"
color_strip="#8f8f8f"
meta_strip="#5b4d91"
mask_strip="#8f5656"

View File

@ -17,6 +17,7 @@
extern "C" {
#endif
struct bDeformGroup;
struct CustomData;
struct CustomDataLayer;
struct ID;
@ -117,6 +118,12 @@ void BKE_id_attributes_default_color_set(struct ID *id, const char *name);
const struct CustomDataLayer *BKE_id_attributes_color_find(const struct ID *id, const char *name);
typedef struct AttributeAndDefgroupUniqueNameData {
struct ID *id;
struct bDeformGroup *dg;
} AttributeAndDefgroupUniqueNameData;
bool BKE_id_attribute_and_defgroup_unique_name_check(void *arg, const char *name);
bool BKE_id_attribute_calc_unique_name(struct ID *id, const char *name, char *outname);
const char *BKE_uv_map_vert_select_name_get(const char *uv_map_name, char *buffer);

View File

@ -89,6 +89,7 @@ int *BKE_object_defgroup_flip_map_single(const struct Object *ob,
int BKE_object_defgroup_flip_index(const struct Object *ob, int index, bool use_default);
int BKE_object_defgroup_name_index(const struct Object *ob, const char *name);
void BKE_object_defgroup_unique_name(struct bDeformGroup *dg, struct Object *ob);
bool BKE_defgroup_unique_name_check(void *arg, const char *name);
struct MDeformWeight *BKE_defvert_find_index(const struct MDeformVert *dv, int defgroup);
/**

View File

@ -31,6 +31,7 @@
#include "BKE_attribute.hh"
#include "BKE_curves.hh"
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.hh"
#include "BKE_pointcloud.h"
@ -223,13 +224,14 @@ bool BKE_id_attribute_rename(ID *id,
return true;
}
struct AttrUniqueData {
ID *id;
};
static bool unique_name_cb(void *arg, const char *name)
bool BKE_id_attribute_and_defgroup_unique_name_check(void *arg, const char *name)
{
AttrUniqueData *data = (AttrUniqueData *)arg;
AttributeAndDefgroupUniqueNameData *data = static_cast<AttributeAndDefgroupUniqueNameData *>(
arg);
if (BKE_defgroup_unique_name_check(data, name)) {
return true;
}
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(data->id, info);
@ -254,15 +256,18 @@ static bool unique_name_cb(void *arg, const char *name)
bool BKE_id_attribute_calc_unique_name(ID *id, const char *name, char *outname)
{
AttrUniqueData data{id};
AttributeAndDefgroupUniqueNameData data{id, nullptr};
const int name_maxncpy = CustomData_name_maxncpy_calc(name);
/* Set default name if none specified.
* NOTE: We only call IFACE_() if needed to avoid locale lookup overhead. */
BLI_strncpy_utf8(outname, (name && name[0]) ? name : IFACE_("Attribute"), name_maxncpy);
/* Avoid name collisions with vertex groups and other attributes. */
const char *defname = ""; /* Dummy argument, never used as `name` is never zero length. */
return BLI_uniquename_cb(unique_name_cb, &data, defname, '.', outname, name_maxncpy);
return BLI_uniquename_cb(
BKE_id_attribute_and_defgroup_unique_name_check, &data, defname, '.', outname, name_maxncpy);
}
CustomDataLayer *BKE_id_attribute_new(ID *id,
@ -301,6 +306,10 @@ CustomDataLayer *BKE_id_attribute_new(ID *id,
attributes->add(uniquename, domain, eCustomDataType(type), AttributeInitDefaultValue());
const int index = CustomData_get_named_layer_index(customdata, type, uniquename);
if (index == -1) {
BKE_reportf(reports, RPT_WARNING, "Layer '%s' could not be created", uniquename);
}
return (index == -1) ? nullptr : &(customdata->layers[index]);
}

View File

@ -29,6 +29,7 @@
#include "BLT_translation.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h"
#include "BKE_data_transfer.h"
#include "BKE_deform.h" /* own include */
@ -681,9 +682,9 @@ int BKE_object_defgroup_flip_index(const Object *ob, int index, const bool use_d
return (flip_index == -1 && use_default) ? index : flip_index;
}
static bool defgroup_find_name_dupe(const char *name, bDeformGroup *dg, Object *ob)
static bool defgroup_find_name_dupe(const char *name, bDeformGroup *dg, ID *id)
{
const ListBase *defbase = BKE_object_defgroup_list(ob);
const ListBase *defbase = BKE_id_defgroup_list_get(id);
LISTBASE_FOREACH (bDeformGroup *, curdef, defbase) {
if (dg != curdef) {
@ -696,21 +697,31 @@ static bool defgroup_find_name_dupe(const char *name, bDeformGroup *dg, Object *
return false;
}
struct DeformGroupUniqueNameData {
Object *ob;
bDeformGroup *dg;
};
static bool defgroup_unique_check(void *arg, const char *name)
bool BKE_defgroup_unique_name_check(void *arg, const char *name)
{
DeformGroupUniqueNameData *data = static_cast<DeformGroupUniqueNameData *>(arg);
return defgroup_find_name_dupe(name, data->dg, data->ob);
AttributeAndDefgroupUniqueNameData *data = static_cast<AttributeAndDefgroupUniqueNameData *>(
arg);
return defgroup_find_name_dupe(name, data->dg, data->id);
}
void BKE_object_defgroup_unique_name(bDeformGroup *dg, Object *ob)
{
DeformGroupUniqueNameData data{ob, dg};
BLI_uniquename_cb(defgroup_unique_check, &data, DATA_("Group"), '.', dg->name, sizeof(dg->name));
/* Avoid name collisions with other vertex groups and (mesh) attributes. */
if (ob->type == OB_MESH) {
Mesh *me = static_cast<Mesh *>(ob->data);
AttributeAndDefgroupUniqueNameData data{&me->id, dg};
BLI_uniquename_cb(BKE_id_attribute_and_defgroup_unique_name_check,
&data,
DATA_("Group"),
'.',
dg->name,
sizeof(dg->name));
}
else {
AttributeAndDefgroupUniqueNameData data{static_cast<ID *>(ob->data), dg};
BLI_uniquename_cb(
BKE_defgroup_unique_name_check, &data, DATA_("Group"), '.', dg->name, sizeof(dg->name));
}
}
float BKE_defvert_find_weight(const MDeformVert *dvert, const int defgroup)

View File

@ -1728,6 +1728,14 @@ void GreasePencil::set_active_layer(const blender::bke::greasepencil::Layer *lay
reinterpret_cast<const GreasePencilLayer *>(layer));
}
bool GreasePencil::is_layer_active(const blender::bke::greasepencil::Layer *layer) const
{
if (layer == nullptr) {
return false;
}
return this->get_active_layer() == layer;
}
static blender::VectorSet<blender::StringRefNull> get_node_names(GreasePencil &grease_pencil)
{
using namespace blender;

View File

@ -4571,6 +4571,9 @@ void BKE_lib_override_library_id_unused_cleanup(ID *local)
BKE_lib_override_library_property_operation_delete(op, opop);
}
}
if (BLI_listbase_is_empty(&op->operations)) {
BKE_lib_override_library_property_delete(local->override_library, op);
}
}
}
}

View File

@ -22,6 +22,11 @@ MINLINE float safe_modf(float a, float b)
return (b != 0.0f) ? fmodf(a, b) : 0.0f;
}
MINLINE float safe_floored_modf(float a, float b)
{
return (b != 0.0f) ? a - floorf(a / b) * b : 0.0f;
}
MINLINE float safe_logf(float a, float base)
{
if (UNLIKELY(a <= 0.0f || base <= 0.0f)) {

View File

@ -126,6 +126,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
*/
{
/* Keep this block, even when empty. */
FROM_DEFAULT_V4_UCHAR(space_sequencer.transition);
}
#undef FROM_DEFAULT_V4_UCHAR

View File

@ -76,6 +76,9 @@ void MathNode::convert_to_operations(NodeConverter &converter,
case NODE_MATH_MODULO:
operation = new MathModuloOperation();
break;
case NODE_MATH_FLOORED_MODULO:
operation = new MathFlooredModuloOperation();
break;
case NODE_MATH_ABSOLUTE:
operation = new MathAbsoluteOperation();
break;

View File

@ -58,8 +58,7 @@ void KuwaharaAnisotropicOperation::execute_pixel_sampled(float output[4],
const float q = 3.0;
const float EPS = 1.0e-10;
/* For now use green channel to compute orientation. */
/* TODO: convert to HSV and compute orientation and strength on luminance channel */
/* All channels are identical. Take first channel for simplicity. */
float tmp[4];
s_xx_reader_->read(tmp, x, y, nullptr);
const float a = tmp[1];

View File

@ -589,6 +589,36 @@ void MathModuloOperation::update_memory_buffer_partial(BuffersIterator<float> &i
}
}
void MathFlooredModuloOperation::execute_pixel_sampled(float output[4],
float x,
float y,
PixelSampler sampler)
{
float input_value1[4];
float input_value2[4];
input_value1_operation_->read_sampled(input_value1, x, y, sampler);
input_value2_operation_->read_sampled(input_value2, x, y, sampler);
if (input_value2[0] == 0) {
output[0] = 0.0;
}
else {
output[0] = input_value1[0] - floorf(input_value1[0] / input_value2[0]) * input_value2[0];
}
clamp_if_needed(output);
}
void MathFlooredModuloOperation::update_memory_buffer_partial(BuffersIterator<float> &it)
{
for (; !it.is_end(); ++it) {
const float value2 = *it.in(1);
*it.out = (value2 == 0) ? 0 : *it.in(0) - floorf(*it.in(0) / value2) * value2;
clamp_when_enabled(it.out);
}
}
void MathAbsoluteOperation::execute_pixel_sampled(float output[4],
float x,
float y,

View File

@ -224,6 +224,14 @@ class MathModuloOperation : public MathBaseOperation {
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathFlooredModuloOperation : public MathBaseOperation {
public:
void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
protected:
void update_memory_buffer_partial(BuffersIterator<float> &it) override;
};
class MathAbsoluteOperation : public MathBaseOperation {
public:
void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;

View File

@ -28,6 +28,7 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_gpencil_legacy.h"
#include "BKE_grease_pencil.hh"
#include "BKE_main.h"
#include "BKE_node.h"
@ -291,9 +292,10 @@ void ANIM_sync_animchannels_to_data(const bContext *C)
animchan_sync_gplayer(ale);
break;
case ANIMTYPE_GREASE_PENCIL_LAYER:
using namespace blender::bke::greasepencil;
GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(ale->data);
if (grease_pencil->active_layer == layer) {
Layer *layer = static_cast<Layer *>(ale->data);
if (grease_pencil->is_layer_active(layer)) {
layer->base.flag |= GP_LAYER_TREE_NODE_SELECT;
}
else {

View File

@ -1767,7 +1767,7 @@ static size_t animdata_filter_grease_pencil_layers_data(ListBase *anim_data,
}
/* Only if the layer is active. */
if ((filter_mode & ANIMFILTER_ACTIVE) && (grease_pencil->active_layer == layer)) {
if ((filter_mode & ANIMFILTER_ACTIVE) && grease_pencil->is_layer_active(layer)) {
continue;
}

View File

@ -196,6 +196,7 @@ enum ThemeColorID {
TH_SEQ_SCENE,
TH_SEQ_AUDIO,
TH_SEQ_EFFECT,
TH_SEQ_TRANSITION,
TH_SEQ_META,
TH_SEQ_TEXT,
TH_SEQ_PREVIEW,

View File

@ -691,6 +691,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_SEQ_EFFECT:
cp = ts->effect;
break;
case TH_SEQ_TRANSITION:
cp = ts->transition;
break;
case TH_SEQ_META:
cp = ts->meta;
break;

View File

@ -150,9 +150,15 @@ void color3ubv_from_seq(const Scene *curscene,
case SEQ_TYPE_CROSS:
case SEQ_TYPE_GAMCROSS:
case SEQ_TYPE_WIPE:
r_col[0] = 130;
r_col[1] = 130;
r_col[2] = 130;
UI_GetThemeColor3ubv(TH_SEQ_TRANSITION, r_col);
/* Slightly offset hue to distinguish different transition types. */
if (seq->type == SEQ_TYPE_GAMCROSS) {
rgb_byte_set_hue_float_offset(r_col, 0.03);
}
else if (seq->type == SEQ_TYPE_WIPE) {
rgb_byte_set_hue_float_offset(r_col, 0.06);
}
break;
/* Effects. */
@ -642,7 +648,7 @@ static void draw_seq_handle(const Scene *scene,
uint pos,
bool seq_active,
float pixelx,
bool y_threshold)
const bool draw_strip_preview)
{
float rx1 = 0, rx2 = 0;
float x1, x2, y1, y2;
@ -693,7 +699,7 @@ static void draw_seq_handle(const Scene *scene,
}
/* Draw numbers for start and end of the strip next to its handles. */
if (y_threshold &&
if (draw_strip_preview &&
(((seq->flag & SELECT) && (G.moving & G_TRANSFORM_SEQ)) || (seq->flag & whichsel)))
{
@ -988,6 +994,21 @@ static void draw_sequence_extensions_overlay(
GPU_blend(GPU_BLEND_NONE);
}
static uchar mute_overlap_alpha_factor_get(const ListBase *channels, const Sequence *seq)
{
/* Draw muted strips semi-transparent. */
if (SEQ_render_is_muted(channels, seq)) {
return MUTE_ALPHA;
}
/* Draw background semi-transparent when overlapping strips. */
else if (seq->flag & SEQ_OVERLAP) {
return OVERLAP_ALPHA;
}
else {
return 255;
}
}
static void draw_color_strip_band(
const Scene *scene, ListBase *channels, Sequence *seq, uint pos, float text_margin_y, float y1)
{
@ -997,17 +1018,7 @@ static void draw_color_strip_band(
GPU_blend(GPU_BLEND_ALPHA);
rgb_float_to_uchar(col, colvars->col);
/* Draw muted strips semi-transparent. */
if (SEQ_render_is_muted(channels, seq)) {
col[3] = MUTE_ALPHA;
}
/* Draw background semi-transparent when overlapping strips. */
else if (seq->flag & SEQ_OVERLAP) {
col[3] = OVERLAP_ALPHA;
}
else {
col[3] = 255;
}
col[3] = mute_overlap_alpha_factor_get(channels, seq);
immUniformColor4ubv(col);
@ -1044,32 +1055,9 @@ static void draw_seq_background(Scene *scene,
uchar col[4];
GPU_blend(GPU_BLEND_ALPHA);
/* Get the correct color per strip type, transitions use their inputs ones. */
if (ELEM(seq->type, SEQ_TYPE_CROSS, SEQ_TYPE_GAMCROSS, SEQ_TYPE_WIPE)) {
Sequence *seq1 = seq->seq1;
if (seq1->type == SEQ_TYPE_COLOR) {
SolidColorVars *colvars = (SolidColorVars *)seq1->effectdata;
rgb_float_to_uchar(col, colvars->col);
}
else {
color3ubv_from_seq(scene, seq1, show_strip_color_tag, col);
}
}
else {
color3ubv_from_seq(scene, seq, show_strip_color_tag, col);
}
color3ubv_from_seq(scene, seq, show_strip_color_tag, col);
/* Draw muted strips semi-transparent. */
if (SEQ_render_is_muted(channels, seq)) {
col[3] = MUTE_ALPHA;
}
/* Draw background semi-transparent when overlapping strips. */
else if (seq->flag & SEQ_OVERLAP) {
col[3] = OVERLAP_ALPHA;
}
else {
col[3] = 255;
}
col[3] = mute_overlap_alpha_factor_get(channels, seq);
immUniformColor4ubv(col);
@ -1102,39 +1090,95 @@ static void draw_seq_background(Scene *scene,
}
}
/* Draw right half of transition strips. */
if (ELEM(seq->type, SEQ_TYPE_CROSS, SEQ_TYPE_GAMCROSS, SEQ_TYPE_WIPE)) {
float vert_pos[3][2];
Sequence *seq1 = seq->seq1;
Sequence *seq2 = seq->seq2;
GPU_blend(GPU_BLEND_NONE);
}
if (seq2->type == SEQ_TYPE_COLOR) {
SolidColorVars *colvars = (SolidColorVars *)seq2->effectdata;
rgb_float_to_uchar(col, colvars->col);
}
else {
color3ubv_from_seq(scene, seq2, show_strip_color_tag, col);
/* If the transition inputs are of the same type, draw the right side slightly darker. */
if (seq1->type == seq2->type) {
UI_GetColorPtrShade3ubv(col, col, -15);
}
}
immUniformColor4ubv(col);
typedef enum {
STRIP_TRANSITION_IN,
STRIP_TRANSITION_OUT,
} TransitionType;
static void draw_seq_transition_strip_half(const Scene *scene,
const Sequence *transition_seq,
const float x1,
const float x2,
const float y1,
const float y2,
const int timeline_overlay_flags,
const TransitionType transition_type)
{
Editing *ed = SEQ_editing_get(scene);
const ListBase *channels = SEQ_channels_displayed_get(ed);
const Sequence *seq1 = transition_seq->seq1;
const Sequence *seq2 = transition_seq->seq2;
const Sequence *target_seq = (transition_type == STRIP_TRANSITION_IN) ? seq1 : seq2;
const bool show_strip_color_tag = (timeline_overlay_flags & SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG);
float col[4];
if (target_seq->type == SEQ_TYPE_COLOR) {
SolidColorVars *colvars = (SolidColorVars *)target_seq->effectdata;
memcpy(col, colvars->col, sizeof(colvars->col));
}
else {
uchar ucol[3];
color3ubv_from_seq(scene, target_seq, show_strip_color_tag, ucol);
/* If the transition inputs are of the same type, draw the right side slightly darker. */
if ((seq1->type == seq2->type) && (transition_type == STRIP_TRANSITION_OUT)) {
UI_GetColorPtrShade3ubv(ucol, ucol, -15);
}
rgb_uchar_to_float(col, ucol);
}
col[3] = mute_overlap_alpha_factor_get(channels, transition_seq) / 255.0f;
GPU_blend(GPU_BLEND_ALPHA);
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(col);
float vert_pos[3][2];
if (transition_type == STRIP_TRANSITION_IN) {
copy_v2_fl2(vert_pos[0], x1, y1);
copy_v2_fl2(vert_pos[1], x1, y2);
copy_v2_fl2(vert_pos[2], x2, y1);
}
else {
copy_v2_fl2(vert_pos[0], x1, y2);
copy_v2_fl2(vert_pos[1], x2, y2);
copy_v2_fl2(vert_pos[2], x2, y1);
immBegin(GPU_PRIM_TRIS, 3);
immVertex2fv(pos, vert_pos[0]);
immVertex2fv(pos, vert_pos[1]);
immVertex2fv(pos, vert_pos[2]);
immEnd();
}
immBegin(GPU_PRIM_TRIS, 3);
immVertex2fv(pos, vert_pos[0]);
immVertex2fv(pos, vert_pos[1]);
immVertex2fv(pos, vert_pos[2]);
immEnd();
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
}
static void draw_seq_transition_strip(const Scene *scene,
const Sequence *seq,
const float x1,
const float x2,
const float y1,
const float y2,
const int timeline_overlay_flags)
{
draw_seq_transition_strip_half(
scene, seq, x1, x2, y1, y2, timeline_overlay_flags, STRIP_TRANSITION_IN);
draw_seq_transition_strip_half(
scene, seq, x1, x2, y1, y2, timeline_overlay_flags, STRIP_TRANSITION_OUT);
}
static void draw_seq_locked(float x1, float y1, float x2, float y2)
{
GPU_blend(GPU_BLEND_ALPHA);
@ -1327,7 +1371,14 @@ static void draw_seq_strip(const bContext *C,
x2 = max_ff(x2, SEQ_time_left_handle_frame_get(scene, seq));
float text_margin_y;
bool y_threshold;
/* Whether there is enough space for the strip preview. */
const bool draw_strip_preview = ((y2 - y1) / pixely) > 20 * UI_SCALE_FAC;
/* If there is not enough vertical space, don't draw any previews nor the title. */
const bool strip_content_none = (y2 - y1) < 8 * pixely * UI_SCALE_FAC;
/* Only a single vertical element is drawn on the strip: the waveform in the case of
* sound strips, or the strip title for most other strip types. */
bool strip_content_single;
if ((sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_NAME) ||
(sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_SOURCE) ||
(sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION))
@ -1336,13 +1387,16 @@ static void draw_seq_strip(const bContext *C,
/* Calculate height needed for drawing text on strip. */
text_margin_y = y2 - min_ff(0.40f, 20 * UI_SCALE_FAC * pixely);
/* Is there enough space for drawing something else than text? */
y_threshold = ((y2 - y1) / pixely) > 20 * UI_SCALE_FAC;
strip_content_single = !draw_strip_preview;
}
else {
text_margin_y = y2;
y_threshold = false;
strip_content_single = true;
}
/* When a text overlay is enabled and there is space for both the text and the strip content,
* draw below the text. */
/* When text is disabled or there is space for only one or the other, use entire strip area. */
const float strip_preview_y2 = strip_content_single ? y2 : text_margin_y;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
@ -1350,8 +1404,8 @@ static void draw_seq_strip(const bContext *C,
draw_seq_background(scene, seq, pos, x1, x2, y1, y2, is_single_image, show_strip_color_tag);
/* Draw a color band inside color strip. */
if (seq->type == SEQ_TYPE_COLOR && y_threshold) {
draw_color_strip_band(scene, channels, seq, pos, text_margin_y, y1);
if ((sseq->flag & SEQ_SHOW_OVERLAY) && (seq->type == SEQ_TYPE_COLOR)) {
draw_color_strip_band(scene, channels, seq, pos, strip_preview_y2, y1);
}
/* Draw strip offsets when flag is enabled or during "solo preview". */
@ -1365,32 +1419,41 @@ static void draw_seq_strip(const bContext *C,
}
immUnbindProgram();
if (draw_strip_preview && (sseq->flag & SEQ_SHOW_OVERLAY) &&
ELEM(seq->type, SEQ_TYPE_CROSS, SEQ_TYPE_GAMCROSS, SEQ_TYPE_WIPE))
{
draw_seq_transition_strip(
scene, seq, x1, x2, y1, strip_preview_y2, sseq->timeline_overlay.flag);
}
x1 = SEQ_time_left_handle_frame_get(scene, seq);
x2 = SEQ_time_right_handle_frame_get(scene, seq);
if ((seq->type == SEQ_TYPE_META) ||
((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS)))
{
drawmeta_contents(scene, seq, x1, y1, x2, y2, show_strip_color_tag);
if (draw_strip_preview && (sseq->flag & SEQ_SHOW_OVERLAY)) {
if ((seq->type == SEQ_TYPE_META) ||
((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS)))
{
drawmeta_contents(scene, seq, x1, y1, x2, strip_preview_y2, show_strip_color_tag);
}
}
if ((sseq->flag & SEQ_SHOW_OVERLAY) &&
(sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_THUMBNAILS) &&
ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE))
{
draw_seq_strip_thumbnail(
v2d, C, scene, seq, y1, y_threshold ? text_margin_y : y2, pixelx, pixely);
draw_seq_strip_thumbnail(v2d, C, scene, seq, y1, strip_preview_y2, pixelx, pixely);
}
if ((sseq->flag & SEQ_SHOW_OVERLAY) && (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_FCURVES))
if (draw_strip_preview && (sseq->flag & SEQ_SHOW_OVERLAY) &&
(sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_FCURVES))
{
draw_seq_fcurve_overlay(scene, v2d, seq, x1, y1, x2, y2, pixelx);
draw_seq_fcurve_overlay(scene, v2d, seq, x1, y1, x2, strip_preview_y2, pixelx);
}
/* Draw sound strip waveform. */
if (seq_draw_waveforms_poll(C, sseq, seq)) {
if (seq_draw_waveforms_poll(C, sseq, seq) && !strip_content_none) {
draw_seq_waveform_overlay(
C, region, seq, x1, y_threshold ? y1 + 0.05f : y1, x2, y_threshold ? text_margin_y : y2);
C, region, seq, x1, strip_content_single ? y1 : y1 + 0.05f, x2, strip_preview_y2);
}
/* Draw locked state. */
if (SEQ_transform_is_locked(channels, seq)) {
@ -1406,34 +1469,51 @@ static void draw_seq_strip(const bContext *C,
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
if (!SEQ_transform_is_locked(channels, seq)) {
draw_seq_handle(
scene, v2d, seq, handsize_clamped, SEQ_LEFTHANDLE, pos, seq_active, pixelx, y_threshold);
draw_seq_handle(
scene, v2d, seq, handsize_clamped, SEQ_RIGHTHANDLE, pos, seq_active, pixelx, y_threshold);
draw_seq_handle(scene,
v2d,
seq,
handsize_clamped,
SEQ_LEFTHANDLE,
pos,
seq_active,
pixelx,
draw_strip_preview);
draw_seq_handle(scene,
v2d,
seq,
handsize_clamped,
SEQ_RIGHTHANDLE,
pos,
seq_active,
pixelx,
draw_strip_preview);
}
draw_seq_outline(scene, seq, pos, x1, x2, y1, y2, pixelx, pixely, seq_active);
immUnbindProgram();
calculate_seq_text_offsets(scene, v2d, seq, &x1, &x2, pixelx);
/* If a waveform is drawn, avoid drawing text when there is not enough vertical space. */
if (seq->type == SEQ_TYPE_SOUND_RAM) {
if (!y_threshold && (sseq->timeline_overlay.flag & SEQ_TIMELINE_NO_WAVEFORMS) == 0 &&
((sseq->timeline_overlay.flag & SEQ_TIMELINE_ALL_WAVEFORMS) ||
(seq->flag & SEQ_AUDIO_DRAW_WAVEFORM)))
{
return;
}
/* If a waveform or a color strip is drawn,
* avoid drawing text when there is not enough vertical space. */
if (strip_content_single &&
(seq_draw_waveforms_poll(C, sseq, seq) || seq->type == SEQ_TYPE_COLOR)) {
return;
}
if (sseq->flag & SEQ_SHOW_OVERLAY) {
/* Don't draw strip if there is not enough vertical or horizontal space. */
if (((x2 - x1) > 32 * pixelx * UI_SCALE_FAC) && ((y2 - y1) > 8 * pixely * UI_SCALE_FAC)) {
/* Draw text only if there is enough horizontal or vertical space. */
if (((x2 - x1) > 32 * pixelx * UI_SCALE_FAC) && !strip_content_none) {
calculate_seq_text_offsets(scene, v2d, seq, &x1, &x2, pixelx);
/* Depending on the vertical space, draw text on top or in the center of strip. */
draw_seq_text_overlay(
scene, v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active);
draw_seq_text_overlay(scene,
v2d,
seq,
sseq,
x1,
x2,
strip_content_single ? y1 : text_margin_y,
y2,
seq_active);
}
}
}

View File

@ -650,7 +650,9 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
return false;
}
if (value == TFM_MODAL_RESIZE && t->mode == TFM_RESIZE) {
return false;
/* The tracking transform in MovieClip has an alternate resize that only affects the
* tracker size and not the search area. */
return t->data_type == &TransConvertType_Tracking;
}
if (value == TFM_MODAL_VERT_EDGE_SLIDE &&
(t->data_type != &TransConvertType_Mesh ||

View File

@ -481,7 +481,7 @@ static void flushTransTracking(TransInfo *t)
if (t->flag & T_ALT_TRANSFORM) {
if (t->mode == TFM_RESIZE) {
if (tdt->area != TRACK_AREA_PAT) {
if (tdt->area != TRACK_AREA_PAT && !(t->state == TRANS_CANCEL)) {
continue;
}
}

View File

@ -111,6 +111,11 @@ void math_modulo(float a, float b, float c, out float result)
result = compatible_fmod(a, b);
}
void math_floored_modulo(float a, float b, float c, out float result)
{
result = (b != 0.0) ? a - floor(a / b) * b : 0.0;
}
void math_trunc(float a, float b, float c, out float result)
{
result = trunc(a);

View File

@ -239,6 +239,8 @@ void imb_filetypes_init()
{
const ImFileType *type;
OIIO_init();
for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
if (type->init) {
type->init();

View File

@ -7,12 +7,24 @@
*/
#include "openimageio_api.h"
#include <OpenImageIO/imageio.h>
#include "BLI_threads.h"
OIIO_NAMESPACE_USING
extern "C" {
void OIIO_init()
{
/* Make OIIO thread pool follow Blender number of threads override. */
const int threads_override = BLI_system_num_threads_override_get();
if (threads_override) {
OIIO::attribute("threads", threads_override);
}
}
int OIIO_getVersionHex()
{
return openimageio_version();

View File

@ -12,6 +12,14 @@
extern "C" {
#endif
/*
* Initialize OpenImageIO on startup.
*/
void OIIO_init(void);
/*
* Get OpenImageIO version.
*/
int OIIO_getVersionHex(void);
#ifdef __cplusplus

View File

@ -86,6 +86,7 @@ set(SRC
intern/usd_capi_export.cc
intern/usd_capi_import.cc
intern/usd_hierarchy_iterator.cc
intern/usd_hook.cc
intern/usd_writer_abstract.cc
intern/usd_writer_camera.cc
intern/usd_writer_curves.cc
@ -116,6 +117,7 @@ set(SRC
intern/usd_asset_utils.h
intern/usd_exporter_context.h
intern/usd_hierarchy_iterator.h
intern/usd_hook.h
intern/usd_writer_abstract.h
intern/usd_writer_camera.h
intern/usd_writer_curves.h

View File

@ -5,6 +5,7 @@
#include "usd.h"
#include "usd.hh"
#include "usd_hierarchy_iterator.h"
#include "usd_hook.h"
#include <pxr/base/plug/registry.h>
#include <pxr/pxr.h>
@ -228,6 +229,9 @@ static pxr::UsdStageRefPtr export_to_stage(const USDExportParams &params,
/* For restoring the current frame after exporting animation is done. */
const int orig_frame = scene->r.cfra;
/* Ensure Python types for invoking export hooks are registered. */
register_export_hook_converters();
usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z));
ensure_root_prim(usd_stage, params);
@ -275,6 +279,8 @@ static pxr::UsdStageRefPtr export_to_stage(const USDExportParams &params,
}
}
call_export_hooks(usd_stage, depsgraph);
/* Finish up by going back to the keyframe that was current before we started. */
if (scene->r.cfra != orig_frame) {
scene->r.cfra = orig_frame;

View File

@ -0,0 +1,300 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "usd.h"
#include "usd_hook.h"
#include <boost/python/call_method.hpp>
#include <boost/python/class.hpp>
#include <boost/python/import.hpp>
#include <boost/python/object.hpp>
#include <boost/python/return_value_policy.hpp>
#include <boost/python/to_python_converter.hpp>
#include "BLI_listbase.h"
#include "RNA_access.h"
#include "RNA_prototypes.h"
#include "RNA_types.h"
#include "bpy_rna.h"
#include "WM_api.hh"
#include "WM_types.hh"
#include <list>
using namespace boost;
using USDHookList = std::list<USDHook *>;
/* USD hook type declarations */
static USDHookList g_usd_hooks;
void USD_register_hook(struct USDHook *hook)
{
if (std::find(g_usd_hooks.begin(), g_usd_hooks.end(), hook) != g_usd_hooks.end()) {
/* The hook is already in the list. */
return;
}
/* Add hook type to the list. */
g_usd_hooks.push_back(hook);
}
void USD_unregister_hook(struct USDHook *hook)
{
g_usd_hooks.remove(hook);
}
USDHook *USD_find_hook_name(const char name[])
{
/* sanity checks */
if (g_usd_hooks.empty() || (name == NULL) || (name[0] == 0)) {
return NULL;
}
USDHookList::iterator hook_iter = std::find_if(
g_usd_hooks.begin(), g_usd_hooks.end(), [name](USDHook *hook) {
return strcmp(hook->idname, name) == 0;
});
return (hook_iter == g_usd_hooks.end()) ? NULL : *hook_iter;
}
namespace blender::io::usd {
/* Convert PointerRNA to a PyObject*. */
struct PointerRNAToPython {
/* We pass the argument by value because we need
* to obtain a non-const pointer to it. */
static PyObject *convert(PointerRNA ptr)
{
return pyrna_struct_CreatePyObject(&ptr);
}
};
/* Encapsulate arguments for scene export. */
struct USDSceneExportContext {
USDSceneExportContext() : depsgraph_ptr({}) {}
USDSceneExportContext(pxr::UsdStageRefPtr in_stage, Depsgraph *depsgraph) : stage(in_stage)
{
RNA_pointer_create(NULL, &RNA_Depsgraph, depsgraph, &depsgraph_ptr);
}
pxr::UsdStageRefPtr get_stage()
{
return stage;
}
const PointerRNA &get_depsgraph() const
{
return depsgraph_ptr;
}
pxr::UsdStageRefPtr stage;
PointerRNA depsgraph_ptr;
};
/* Encapsulate arguments for material export. */
struct USDMaterialExportContext {
USDMaterialExportContext() {}
USDMaterialExportContext(pxr::UsdStageRefPtr in_stage) : stage(in_stage) {}
pxr::UsdStageRefPtr get_stage()
{
return stage;
}
pxr::UsdStageRefPtr stage;
};
void register_export_hook_converters()
{
static bool registered = false;
/* No need to register if there are no hooks. */
if (g_usd_hooks.empty()) {
return;
}
if (registered) {
return;
}
registered = true;
PyGILState_STATE gilstate = PyGILState_Ensure();
/* We must import these modules for the USD type converters to work. */
python::import("pxr.Usd");
python::import("pxr.UsdShade");
/* Register converter from PoinerRNA to a PyObject*. */
python::to_python_converter<PointerRNA, PointerRNAToPython>();
/* Register context class converters. */
python::class_<USDSceneExportContext>("USDSceneExportContext")
.def("get_stage", &USDSceneExportContext::get_stage)
.def("get_depsgraph",
&USDSceneExportContext::get_depsgraph,
python::return_value_policy<python::return_by_value>());
python::class_<USDMaterialExportContext>("USDMaterialExportContext")
.def("get_stage", &USDMaterialExportContext::get_stage);
PyGILState_Release(gilstate);
}
/* Retrieve and report the current Python error. */
static void handle_python_error(USDHook *hook)
{
if (!PyErr_Occurred()) {
return;
}
PyErr_Print();
WM_reportf(RPT_ERROR,
"An exception occurred invoking USD hook '%s'. Please see the console for details",
hook->name);
}
/* Abstract base class to facilitate calling a function with a given
* signature defined by the registered USDHook classes. Subclasses
* override virtual methods to specify the hook function name and to
* call the hook with the required arguments.
*/
class USDHookInvoker {
public:
/* Attempt to call the function, if defined by the registered hooks. */
void call() const
{
if (g_usd_hooks.empty()) {
return;
}
PyGILState_STATE gilstate = PyGILState_Ensure();
/* Iterate over the hooks and invoke the hook function, if it's defined. */
USDHookList::const_iterator hook_iter = g_usd_hooks.begin();
while (hook_iter != g_usd_hooks.end()) {
/* XXX: Not sure if this is necessary:
* Advance the iterator before invoking the callback, to guard
* against the unlikely error where the hook is deregistered in
* the callback. This would prevent a crash due to the iterator
* getting invalidated. */
USDHook *hook = *hook_iter;
++hook_iter;
if (!hook->rna_ext.data) {
continue;
}
try {
PyObject *hook_obj = static_cast<PyObject *>(hook->rna_ext.data);
if (!PyObject_HasAttrString(hook_obj, function_name())) {
continue;
}
call_hook(hook_obj);
}
catch (python::error_already_set const &) {
handle_python_error(hook);
}
catch (...) {
WM_reportf(RPT_ERROR, "An exception occurred invoking USD hook '%s'", hook->name);
}
}
PyGILState_Release(gilstate);
}
protected:
/* Override to specify the name of the function to be called. */
virtual const char *function_name() const = 0;
/* Override to call the function of the given object with the
* required arguments, e.g.,
*
* python::call_method<void>(hook_obj, function_name(), arg1, arg2); */
virtual void call_hook(PyObject *hook_obj) const = 0;
};
class OnExportInvoker : public USDHookInvoker {
private:
USDSceneExportContext hook_context_;
public:
OnExportInvoker(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph)
: hook_context_(stage, depsgraph)
{
}
protected:
const char *function_name() const override
{
return "on_export";
}
void call_hook(PyObject *hook_obj) const override
{
python::call_method<bool>(hook_obj, function_name(), hook_context_);
}
};
class OnMaterialExportInvoker : public USDHookInvoker {
private:
USDMaterialExportContext hook_context_;
pxr::UsdShadeMaterial usd_material_;
PointerRNA material_ptr_;
public:
OnMaterialExportInvoker(pxr::UsdStageRefPtr stage,
Material *material,
pxr::UsdShadeMaterial &usd_material)
: hook_context_(stage), usd_material_(usd_material)
{
RNA_pointer_create(NULL, &RNA_Material, material, &material_ptr_);
}
protected:
const char *function_name() const override
{
return "on_material_export";
}
void call_hook(PyObject *hook_obj) const override
{
python::call_method<bool>(
hook_obj, function_name(), hook_context_, material_ptr_, usd_material_);
}
};
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph)
{
if (g_usd_hooks.empty()) {
return;
}
OnExportInvoker on_export(stage, depsgraph);
on_export.call();
}
void call_material_export_hooks(pxr::UsdStageRefPtr stage,
Material *material,
pxr::UsdShadeMaterial &usd_material)
{
if (g_usd_hooks.empty()) {
return;
}
OnMaterialExportInvoker on_material_export(stage, material, usd_material);
on_material_export.call();
}
} // namespace blender::io::usd

View File

@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include <pxr/usd/usd/stage.h>
#include <pxr/usd/usdShade/material.h>
#include <string>
struct Depsgraph;
struct ExportJobData;
struct Material;
struct USDExportParams;
namespace blender::io::usd {
/* Ensure classes and type converters necessary for invoking export hook are registered. */
void register_export_hook_converters();
/* Call the 'on_export' chaser function defined in the registred USDHook classes. */
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph);
/* Call the 'on_material_export' hook functions defined in the registered USDHook classes. */
void call_material_export_hooks(pxr::UsdStageRefPtr stage,
Material *material,
pxr::UsdShadeMaterial &usd_material);
} // namespace blender::io::usd

View File

@ -113,6 +113,7 @@ pxr::UsdShadeMaterial USDAbstractWriter::ensure_usd_material(const HierarchyCont
if (usd_material) {
return usd_material;
}
std::string active_uv = get_mesh_active_uvlayer_name(context.object);
return create_usd_material(usd_export_context_, usd_path, material, active_uv);
}

View File

@ -6,6 +6,7 @@
#include "usd.h"
#include "usd_exporter_context.h"
#include "usd_hook.h"
#include "BKE_image.h"
#include "BKE_image_format.h"
@ -841,6 +842,8 @@ pxr::UsdShadeMaterial create_usd_material(const USDExporterContext &usd_export_c
create_usd_viewport_material(usd_export_context, material, usd_material);
}
call_material_export_hooks(usd_export_context.stage, material, usd_material);
return usd_material;
}

View File

@ -6,6 +6,8 @@
#include "DEG_depsgraph.h"
#include "RNA_types.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -149,6 +151,29 @@ struct CacheReader *CacheReader_open_usd_object(struct CacheArchiveHandle *handl
void USD_CacheReader_incref(struct CacheReader *reader);
void USD_CacheReader_free(struct CacheReader *reader);
/* Data for registering USD IO hooks. */
typedef struct USDHook {
/* Identifier used for class name. */
char idname[64];
/* Identifier used as label. */
char name[64];
/* Short help/description. */
char description[1024]; /* #RNA_DYN_DESCR_MAX */
/* rna_ext.data points to the USDHook class PyObject. */
struct ExtensionRNA rna_ext;
} USDHook;
void USD_register_hook(struct USDHook *hook);
/* Remove the given entry from the list of registered hooks.
* Note that this does not free the allocated memory for the
* hook instance, so a separate call to MEM_freeN(hook) is
* required. */
void USD_unregister_hook(struct USDHook *hook);
USDHook *USD_find_hook_name(const char name[]);
#ifdef __cplusplus
}
#endif

View File

@ -451,6 +451,7 @@ typedef struct GreasePencil {
const blender::bke::greasepencil::Layer *get_active_layer() const;
blender::bke::greasepencil::Layer *get_active_layer_for_write();
void set_active_layer(const blender::bke::greasepencil::Layer *layer);
bool is_layer_active(const blender::bke::greasepencil::Layer *layer) const;
blender::bke::greasepencil::Layer &add_layer(blender::bke::greasepencil::LayerGroup &group,
blender::StringRefNull name);

View File

@ -2124,6 +2124,7 @@ typedef enum NodeMathOperation {
NODE_MATH_PINGPONG = 37,
NODE_MATH_SMOOTH_MIN = 38,
NODE_MATH_SMOOTH_MAX = 39,
NODE_MATH_FLOORED_MODULO = 40,
} NodeMathOperation;
typedef enum NodeVectorMathOperation {

View File

@ -90,6 +90,13 @@ set(DEFSRC
rna_xr.cc
)
if(WITH_USD)
list(APPEND DEFSRC
rna_usd.cc
)
add_definitions(-DWITH_USD)
endif()
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_SIMULATION_DATABLOCK)
add_definitions(-DWITH_GREASE_PENCIL_V3)
@ -229,6 +236,7 @@ set(INC
../../gpu
../../ikplugin
../../imbuf
../../io/usd
../../modifiers
../../nodes
../../sequencer

View File

@ -4750,6 +4750,9 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_timeline.cc", nullptr, RNA_def_timeline_marker},
{"rna_sound.cc", "rna_sound_api.cc", RNA_def_sound},
{"rna_ui.cc", "rna_ui_api.cc", RNA_def_ui},
#ifdef WITH_USD
{"rna_usd.cc", NULL, RNA_def_usd},
#endif
{"rna_userdef.cc", nullptr, RNA_def_userdef},
{"rna_vfont.cc", "rna_vfont_api.cc", RNA_def_vfont},
{"rna_volume.cc", nullptr, RNA_def_volume},

View File

@ -202,6 +202,7 @@ void RNA_def_texture(struct BlenderRNA *brna);
void RNA_def_timeline_marker(struct BlenderRNA *brna);
void RNA_def_sound(struct BlenderRNA *brna);
void RNA_def_ui(struct BlenderRNA *brna);
void RNA_def_usd(struct BlenderRNA *brna);
void RNA_def_userdef(struct BlenderRNA *brna);
void RNA_def_vfont(struct BlenderRNA *brna);
void RNA_def_volume(struct BlenderRNA *brna);

View File

@ -223,7 +223,16 @@ const EnumPropertyItem rna_enum_node_math_items[] = {
{NODE_MATH_TRUNC, "TRUNC", 0, "Truncate", "The integer part of A, removing fractional digits"},
RNA_ENUM_ITEM_SEPR,
{NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"},
{NODE_MATH_MODULO, "MODULO", 0, "Modulo", "Modulo using fmod(A,B)"},
{NODE_MATH_MODULO,
"MODULO",
0,
"Truncated Modulo",
"The remainder of truncated division using fmod(A,B)"},
{NODE_MATH_FLOORED_MODULO,
"FLOORED_MODULO",
0,
"Floored Modulo",
"The remainder of floored division"},
{NODE_MATH_WRAP, "WRAP", 0, "Wrap", "Wrap value to range, wrap(A,B)"},
{NODE_MATH_SNAP, "SNAP", 0, "Snap", "Snap to increment, snap(A,B)"},
{NODE_MATH_PINGPONG,

View File

@ -1624,6 +1624,18 @@ static void rna_property_override_diff_propptr(Main *bmain,
&ptrdiff_ctx.rnadiff_ctx.report_flag);
ptrdiff_ctx.rnadiff_ctx.comparison = !match;
/* Regardless of whether the data from both pointers matches or not, a potentially existing
* operation on current extended rna path should be removed. This is done by tagging said
* operation as unused, while clearing the property tag (see also
* #RNA_struct_override_matches handling of #LIBOVERRIDE_PROP_OP_TAG_UNUSED). Note that a
* property with no operations will also be cleared by
* #BKE_lib_override_library_id_unused_cleanup. */
IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(liboverride,
extended_rna_path);
if (op != nullptr) {
op->tag &= ~LIBOVERRIDE_PROP_OP_TAG_UNUSED;
}
if (!ELEM(extended_rna_path, extended_rna_path_buffer, rna_path)) {
MEM_freeN(extended_rna_path);
}

View File

@ -0,0 +1,163 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup RNA
*/
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "rna_internal.h"
#include "WM_types.hh"
#include "usd.h"
#ifdef RNA_RUNTIME
# include "DNA_object_types.h"
# include "WM_api.hh"
static StructRNA *rna_USDHook_refine(PointerRNA *ptr)
{
USDHook *hook = (USDHook *)ptr->data;
return (hook->rna_ext.srna) ? hook->rna_ext.srna : &RNA_USDHook;
}
static bool rna_USDHook_unregister(Main *bmain, StructRNA *type)
{
USDHook *hook = static_cast<USDHook *>(RNA_struct_blender_type_get(type));
if (hook == NULL) {
return false;
}
/* free RNA data referencing this */
RNA_struct_free_extension(type, &hook->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
WM_main_add_notifier(NC_WINDOW, NULL);
/* unlink Blender-side data */
USD_unregister_hook(hook);
MEM_freeN(hook);
return true;
}
static StructRNA *rna_USDHook_register(Main *bmain,
ReportList *reports,
void *data,
const char *identifier,
StructValidateFunc validate,
StructCallbackFunc call,
StructFreeFunc free)
{
const char *error_prefix = "Registering USD hook class:";
USDHook dummy_hook = {NULL};
USDHook *hook;
PointerRNA dummy_hook_ptr = {NULL};
/* setup dummy type info to store static properties in */
RNA_pointer_create(NULL, &RNA_USDHook, &dummy_hook, &dummy_hook_ptr);
/* validate the python class */
if (validate(&dummy_hook_ptr, data, NULL) != 0) {
return NULL;
}
if (strlen(identifier) >= sizeof(dummy_hook.idname)) {
BKE_reportf(reports,
RPT_ERROR,
"%s '%s' is too long, maximum length is %d",
error_prefix,
identifier,
(int)sizeof(dummy_hook.idname));
return NULL;
}
/* check if we have registered this hook before, and remove it */
hook = USD_find_hook_name(dummy_hook.idname);
if (hook) {
StructRNA *srna = hook->rna_ext.srna;
if (!rna_USDHook_unregister(bmain, srna)) {
BKE_reportf(reports,
RPT_ERROR,
"%s '%s', bl_idname '%s' %s",
error_prefix,
identifier,
dummy_hook.idname,
"could not be unregistered");
return NULL;
}
}
/* create a new KeyingSetInfo type */
hook = static_cast<USDHook *>(MEM_mallocN(sizeof(USDHook), "python USD hook"));
memcpy(hook, &dummy_hook, sizeof(USDHook));
/* set RNA-extensions info */
hook->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, hook->idname, &RNA_USDHook);
hook->rna_ext.data = data;
hook->rna_ext.call = call;
hook->rna_ext.free = free;
RNA_struct_blender_type_set(hook->rna_ext.srna, hook);
/* add and register with other info as needed */
USD_register_hook(hook);
WM_main_add_notifier(NC_WINDOW, NULL);
/* return the struct-rna added */
return hook->rna_ext.srna;
}
#else
static void rna_def_usd_hook(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
FunctionRNA *func;
PropertyRNA *parm;
srna = RNA_def_struct(brna, "USDHook", NULL);
RNA_def_struct_ui_text(srna, "USD Hook", "Defines callback functions to extend USD IO");
RNA_def_struct_sdna(srna, "USDHook");
RNA_def_struct_refine_func(srna, "rna_USDHook_refine");
RNA_def_struct_register_funcs(srna, "rna_USDHook_register", "rna_USDHook_unregister", NULL);
///* Properties --------------------- */
RNA_define_verify_sdna(0); /* not in sdna */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "idname");
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop, "ID Name", "");
prop = RNA_def_property(srna, "bl_label", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "UI Name", "");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_flag(prop, PROP_REGISTER);
prop = RNA_def_property(srna, "bl_description", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "description");
RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_ui_text(prop, "Description", "A short description of the USD hook");
}
/* --- */
void RNA_def_usd(BlenderRNA *brna)
{
rna_def_usd_hook(brna);
}
#endif

View File

@ -3302,6 +3302,12 @@ static void rna_def_userdef_theme_space_seq(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Effect Strip", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "transition_strip", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "transition");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Transition Strip", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "color_strip", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Color Strip", "");

View File

@ -152,6 +152,8 @@ inline bool try_dispatch_float_math_fl_fl_to_fl(const int operation, Callback &&
return dispatch(exec_preset_fast, [](float a, float b) { return (float)(a > b); });
case NODE_MATH_MODULO:
return dispatch(exec_preset_fast, [](float a, float b) { return safe_modf(a, b); });
case NODE_MATH_FLOORED_MODULO:
return dispatch(exec_preset_fast, [](float a, float b) { return safe_floored_modf(a, b); });
case NODE_MATH_SNAP:
return dispatch(exec_preset_fast,
[](float a, float b) { return floorf(safe_divide(a, b)) * b; });

View File

@ -53,6 +53,8 @@ const FloatMathOperationInfo *get_float_math_operation_info(const int operation)
RETURN_OPERATION_INFO("Greater Than", "math_greater_than");
case NODE_MATH_MODULO:
RETURN_OPERATION_INFO("Modulo", "math_modulo");
case NODE_MATH_FLOORED_MODULO:
RETURN_OPERATION_INFO("Floored Modulo", "math_floored_modulo");
case NODE_MATH_ABSOLUTE:
RETURN_OPERATION_INFO("Absolute", "math_absolute");
case NODE_MATH_ARCTAN2:

View File

@ -175,6 +175,16 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
case NODE_MATH_FLOORED_MODULO: {
if (in1 == 0.0f) {
*out = 0.0f;
}
else {
*out = in0 - floorf(in0 / in1) * in1;
}
break;
}
case NODE_MATH_ABSOLUTE: {
*out = fabsf(in0);
break;