Versioning function to replace legacy instancing panel by geometry node modifier #105494
|
@ -2,4 +2,4 @@ ${CommitTitle}
|
|||
|
||||
${CommitBody}
|
||||
|
||||
Pull Request #${PullRequestIndex}
|
||||
Pull Request: https://projects.blender.org/blender/blender/pulls/${PullRequestIndex}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
${PullRequestTitle}
|
||||
|
||||
Pull Request #${PullRequestIndex}
|
||||
Pull Request: https://projects.blender.org/blender/blender/pulls/${PullRequestIndex}
|
||||
|
|
|
@ -1673,7 +1673,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
|||
driver_version = "470"
|
||||
col.label(text=iface_("Requires NVIDIA GPU with compute capability %s") % compute_capability,
|
||||
icon='BLANK1', translate=False)
|
||||
col.label(text="and NVIDIA driver version %s or newer" % driver_version,
|
||||
col.label(text=iface_("and NVIDIA driver version %s or newer") % driver_version,
|
||||
icon='BLANK1', translate=False)
|
||||
elif device_type == 'HIP':
|
||||
if True:
|
||||
|
@ -1719,7 +1719,8 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
|||
.replace('(TM)', unicodedata.lookup('TRADE MARK SIGN'))
|
||||
.replace('(tm)', unicodedata.lookup('TRADE MARK SIGN'))
|
||||
.replace('(R)', unicodedata.lookup('REGISTERED SIGN'))
|
||||
.replace('(C)', unicodedata.lookup('COPYRIGHT SIGN'))
|
||||
.replace('(C)', unicodedata.lookup('COPYRIGHT SIGN')),
|
||||
translate=False
|
||||
)
|
||||
|
||||
def draw_impl(self, layout, context):
|
||||
|
|
|
@ -35,7 +35,7 @@ struct BVHReferenceCompare {
|
|||
|
||||
/* Compare two references.
|
||||
*
|
||||
* Returns value is similar to return value of strcmp().
|
||||
* Returns value is similar to return value of `strcmp()`.
|
||||
*/
|
||||
__forceinline int compare(const BVHReference &ra, const BVHReference &rb) const
|
||||
{
|
||||
|
|
|
@ -494,7 +494,7 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc,
|
|||
|
||||
float3 H;
|
||||
float cos_NH, cos_HI;
|
||||
float3 local_H, local_I, X, Y; /* Nneeded for anisotropic microfacets later. */
|
||||
float3 local_H, local_I, X, Y; /* Needed for anisotropic microfacets later. */
|
||||
if (m_singular) {
|
||||
H = N;
|
||||
cos_NH = 1.0f;
|
||||
|
|
|
@ -979,7 +979,7 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg,
|
|||
for (int ci = 0; ci < sd_mnee->num_closure; ci++) {
|
||||
ccl_private ShaderClosure *bsdf = &sd_mnee->closure[ci];
|
||||
if (CLOSURE_IS_REFRACTIVE(bsdf->type)) {
|
||||
/* Note that Glass closures are treates as refractive further below. */
|
||||
/* Note that Glass closures are treated as refractive further below. */
|
||||
|
||||
found_refractive_microfacet_bsdf = true;
|
||||
ccl_private MicrofacetBsdf *microfacet_bsdf = (ccl_private MicrofacetBsdf *)bsdf;
|
||||
|
|
|
@ -177,20 +177,53 @@ typedef enum {
|
|||
typedef enum {
|
||||
GHOST_kEventUnknown = 0,
|
||||
|
||||
GHOST_kEventCursorMove, /* Mouse move event. */
|
||||
GHOST_kEventButtonDown, /* Mouse button event. */
|
||||
GHOST_kEventButtonUp, /* Mouse button event. */
|
||||
GHOST_kEventWheel, /* Mouse wheel event. */
|
||||
GHOST_kEventTrackpad, /* Trackpad event. */
|
||||
/** Mouse move event.
|
||||
*
|
||||
* \note #GHOST_GetEventData returns #GHOST_TEventCursorData.
|
||||
*/
|
||||
GHOST_kEventCursorMove,
|
||||
/** Mouse button down event. */
|
||||
GHOST_kEventButtonDown,
|
||||
/** Mouse button up event. */
|
||||
GHOST_kEventButtonUp,
|
||||
/**
|
||||
* Mouse wheel event.
|
||||
*
|
||||
* \note #GHOST_GetEventData returns #GHOST_TEventWheelData.
|
||||
*/
|
||||
GHOST_kEventWheel,
|
||||
/**
|
||||
* Trackpad event.
|
||||
*
|
||||
* \note #GHOST_GetEventData returns #GHOST_TEventTrackpadData.
|
||||
*/
|
||||
GHOST_kEventTrackpad,
|
||||
|
||||
#ifdef WITH_INPUT_NDOF
|
||||
GHOST_kEventNDOFMotion, /* N degree of freedom device motion event. */
|
||||
GHOST_kEventNDOFButton, /* N degree of freedom device button event. */
|
||||
/**
|
||||
* N degree of freedom device motion event.
|
||||
*
|
||||
* \note #GHOST_GetEventData returns #GHOST_TEventNDOFMotionData.
|
||||
*/
|
||||
GHOST_kEventNDOFMotion,
|
||||
/**
|
||||
* N degree of freedom device button event.
|
||||
*
|
||||
* \note #GHOST_GetEventData returns #GHOST_TEventNDOFButtonData.
|
||||
*/
|
||||
GHOST_kEventNDOFButton,
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Keyboard up/down events.
|
||||
*
|
||||
* Includes repeat events, check #GHOST_TEventKeyData::is_repeat
|
||||
* if detecting repeat events is needed.
|
||||
*
|
||||
* \note #GHOST_GetEventData returns #GHOST_TEventKeyData.
|
||||
*/
|
||||
GHOST_kEventKeyDown,
|
||||
GHOST_kEventKeyUp,
|
||||
// GHOST_kEventKeyAuto,
|
||||
|
||||
GHOST_kEventQuitRequest,
|
||||
|
||||
|
|
|
@ -20,11 +20,13 @@ enum TransformType {
|
|||
TRANSFORM_SRGB_TO_LINEAR,
|
||||
TRANSFORM_SCALE,
|
||||
TRANSFORM_EXPONENT,
|
||||
TRANSFORM_NONE,
|
||||
TRANSFORM_UNKNOWN,
|
||||
};
|
||||
|
||||
#define COLORSPACE_LINEAR ((OCIO_ConstColorSpaceRcPtr *)1)
|
||||
#define COLORSPACE_SRGB ((OCIO_ConstColorSpaceRcPtr *)2)
|
||||
#define COLORSPACE_DATA ((OCIO_ConstColorSpaceRcPtr *)3)
|
||||
|
||||
typedef struct OCIO_PackedImageDescription {
|
||||
float *data;
|
||||
|
@ -165,6 +167,8 @@ OCIO_ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(OCIO_ConstConfigRcP
|
|||
return COLORSPACE_LINEAR;
|
||||
else if (strcmp(name, "sRGB") == 0)
|
||||
return COLORSPACE_SRGB;
|
||||
else if (strcmp(name, "data") == 0)
|
||||
return COLORSPACE_DATA;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -179,6 +183,9 @@ int FallbackImpl::configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, con
|
|||
else if (cs == COLORSPACE_SRGB) {
|
||||
return 1;
|
||||
}
|
||||
else if (cs == COLORSPACE_DATA) {
|
||||
return 2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -314,7 +321,10 @@ OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames(OCIO_ConstCo
|
|||
OCIO_ConstColorSpaceRcPtr *cs_src = configGetColorSpace(config, srcName);
|
||||
OCIO_ConstColorSpaceRcPtr *cs_dst = configGetColorSpace(config, dstName);
|
||||
FallbackTransform transform;
|
||||
if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB) {
|
||||
if (cs_src == COLORSPACE_DATA || cs_dst == COLORSPACE_DATA) {
|
||||
transform.type = TRANSFORM_NONE;
|
||||
}
|
||||
else if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB) {
|
||||
transform.type = TRANSFORM_LINEAR_TO_SRGB;
|
||||
}
|
||||
else if (cs_src == COLORSPACE_SRGB && cs_dst == COLORSPACE_LINEAR) {
|
||||
|
@ -433,6 +443,9 @@ const char *FallbackImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs)
|
|||
else if (cs == COLORSPACE_SRGB) {
|
||||
return "sRGB";
|
||||
}
|
||||
else if (cs == COLORSPACE_DATA) {
|
||||
return "data";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -501,9 +501,7 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
|
|||
Recursively get strings, needed in case we have "Blah" + "Blah", passed as an argument in that case it won't
|
||||
evaluate to a string. However, break on some kind of stopper nodes, like e.g. Subscript.
|
||||
"""
|
||||
# New in py 3.8: all constants are of type 'ast.Constant'.
|
||||
# 'ast.Str' will have to be removed when we officially switch to this version.
|
||||
if type(node) in {ast.Str, getattr(ast, "Constant", None)}:
|
||||
if type(node) == ast.Constant:
|
||||
eval_str = ast.literal_eval(node)
|
||||
if eval_str and type(eval_str) == str:
|
||||
yield (is_split, eval_str, (node,))
|
||||
|
@ -692,6 +690,15 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
|
|||
else:
|
||||
continue
|
||||
|
||||
# Skip function if it's marked as not translatable.
|
||||
do_translate = True
|
||||
for kw in node.keywords:
|
||||
if kw.arg == "translate" and not kw.value.value:
|
||||
do_translate = False
|
||||
break
|
||||
if not do_translate:
|
||||
continue
|
||||
|
||||
func_args = func_translate_args.get(func_id, {})
|
||||
|
||||
# First try to get i18n contexts, for every possible msgid id.
|
||||
|
|
|
@ -13,8 +13,8 @@ from bpy.props import (
|
|||
|
||||
|
||||
class SCENE_OT_freestyle_fill_range_by_selection(Operator):
|
||||
"""Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object """
|
||||
"""(either a user-specified object or the active camera)"""
|
||||
"""Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object """ \
|
||||
"""(either a user-specified object or the active camera)"""
|
||||
bl_idname = "scene.freestyle_fill_range_by_selection"
|
||||
bl_label = "Fill Range by Selection"
|
||||
bl_options = {'INTERNAL'}
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
import bpy
|
||||
from bpy.types import Menu
|
||||
from bl_ui import node_add_menu
|
||||
from bpy.app.translations import pgettext_iface as iface_
|
||||
from bpy.app.translations import (
|
||||
pgettext_iface as iface_,
|
||||
contexts as i18n_contexts,
|
||||
)
|
||||
|
||||
|
||||
class NODE_MT_geometry_node_GEO_ATTRIBUTE(Menu):
|
||||
|
@ -238,6 +241,7 @@ class NODE_MT_geometry_node_GEO_INPUT(Menu):
|
|||
class NODE_MT_geometry_node_GEO_INPUT_CONSTANT(Menu):
|
||||
bl_idname = "NODE_MT_geometry_node_GEO_INPUT_CONSTANT"
|
||||
bl_label = "Constant"
|
||||
bl_translation_context = i18n_contexts.id_nodetree
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
|
|
@ -79,6 +79,7 @@ class TEXT_HT_footer(Header):
|
|||
text=iface_("Text: External")
|
||||
if text.library
|
||||
else iface_("Text: Internal"),
|
||||
translate=False
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -2832,7 +2832,9 @@ class VIEW3D_MT_object_parent(Menu):
|
|||
layout.separator()
|
||||
|
||||
layout.operator_context = 'EXEC_REGION_WIN'
|
||||
layout.operator("object.parent_no_inverse_set")
|
||||
layout.operator("object.parent_no_inverse_set").keep_transform = False
|
||||
props = layout.operator("object.parent_no_inverse_set", text="Make Parent without Inverse (Keep Transform)")
|
||||
props.keep_transform = True
|
||||
layout.operator_context = operator_context_default
|
||||
|
||||
layout.separator()
|
||||
|
@ -6376,6 +6378,9 @@ class VIEW3D_PT_overlay_object(Panel):
|
|||
|
||||
sub = split.column(align=True)
|
||||
sub.prop(overlay, "show_extras", text="Extras")
|
||||
subsub = sub.column()
|
||||
subsub.active = overlay.show_extras
|
||||
subsub.prop(overlay, "show_light_colors")
|
||||
sub.prop(overlay, "show_relationship_lines")
|
||||
sub.prop(overlay, "show_outline_selected")
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ struct FCurve;
|
|||
struct PathResolvedRNA;
|
||||
struct PointerRNA;
|
||||
struct PropertyRNA;
|
||||
struct Scene;
|
||||
struct ViewLayer;
|
||||
|
||||
/* ************** F-Curve Drivers ***************** */
|
||||
|
||||
|
@ -59,6 +61,32 @@ void fcurve_free_driver(struct FCurve *fcu);
|
|||
*/
|
||||
struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver);
|
||||
|
||||
/**
|
||||
* Get property from which the specific property can be found from.
|
||||
*
|
||||
* This depends on the type of `dvar`:
|
||||
*
|
||||
* - For the Single Property the `r_prop` is a pointer to an ID, which is used to resolve the
|
||||
* target rna_path.
|
||||
*
|
||||
* - For Transform Channel, Rotational Difference, Distance the `r_prop` is a pointer to an
|
||||
* object from which transformation is read.
|
||||
*
|
||||
* - For Context Property the `r_prop` points to a resolved data corresponding to the
|
||||
* dtar->context_property accessed from the given evaluated context. This could either be an ID
|
||||
* property for Active Scene, or a data property for Active View Layer.
|
||||
*
|
||||
* If the target property can not be resolved false is returned.
|
||||
*/
|
||||
typedef struct DriverTargetContext {
|
||||
struct Scene *scene;
|
||||
struct ViewLayer *view_layer;
|
||||
} DriverTargetContext;
|
||||
bool driver_get_target_property(const DriverTargetContext *driver_target_context,
|
||||
struct DriverVar *dvar,
|
||||
struct DriverTarget *dtar,
|
||||
struct PointerRNA *r_prop);
|
||||
|
||||
/**
|
||||
* Copy driver variables from src_vars list to dst_vars list.
|
||||
*/
|
||||
|
@ -102,11 +130,15 @@ struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
|
|||
/**
|
||||
* Evaluate a Driver Variable to get a value that contributes to the final.
|
||||
*/
|
||||
float driver_get_variable_value(struct ChannelDriver *driver, struct DriverVar *dvar);
|
||||
float driver_get_variable_value(const struct AnimationEvalContext *anim_eval_context,
|
||||
struct ChannelDriver *driver,
|
||||
struct DriverVar *dvar);
|
||||
/**
|
||||
* Same as 'dtar_get_prop_val'. but get the RNA property.
|
||||
*/
|
||||
bool driver_get_variable_property(struct ChannelDriver *driver,
|
||||
bool driver_get_variable_property(const struct AnimationEvalContext *anim_eval_context,
|
||||
struct ChannelDriver *driver,
|
||||
struct DriverVar *dvar,
|
||||
struct DriverTarget *dtar,
|
||||
struct PointerRNA *r_ptr,
|
||||
struct PropertyRNA **r_prop,
|
||||
|
|
|
@ -271,9 +271,20 @@ typedef struct bNodeType {
|
|||
/** Check and update if internal ID data has changed. */
|
||||
void (*group_update_func)(struct bNodeTree *ntree, struct bNode *node);
|
||||
|
||||
/** Initialize a new node instance of this type after creation. */
|
||||
/**
|
||||
* Initialize a new node instance of this type after creation.
|
||||
*
|
||||
* \note Assignments to `node->id` must not increment the user of the ID.
|
||||
* This is handled by the caller of this callback.
|
||||
*/
|
||||
void (*initfunc)(struct bNodeTree *ntree, struct bNode *node);
|
||||
/** Free the node instance. */
|
||||
/**
|
||||
* Free the node instance.
|
||||
*
|
||||
* \note Access to `node->id` must be avoided in this function as this is called
|
||||
* while freeing #Main, the state of this ID is undefined.
|
||||
* Higher level logic to remove the node handles the user-count.
|
||||
*/
|
||||
void (*freefunc)(struct bNode *node);
|
||||
/** Make a copy of the node instance. */
|
||||
void (*copyfunc)(struct bNodeTree *dest_ntree,
|
||||
|
|
|
@ -409,6 +409,9 @@ void BKE_curve_init(Curve *cu, const short curve_type)
|
|||
cu->resolv = 4;
|
||||
}
|
||||
cu->bevel_profile = nullptr;
|
||||
/* Initialize the offset to 1.0, to compensate for it being set to -1.0
|
||||
in the property getter. */
|
||||
cu->offset = 1.0f;
|
||||
}
|
||||
|
||||
Curve *BKE_curve_add(Main *bmain, const char *name, int type)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "DNA_anim_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_alloca.h"
|
||||
#include "BLI_expr_pylike_eval.h"
|
||||
|
@ -31,11 +32,14 @@
|
|||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_path.h"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "atomic_ops.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
# include "BPY_extern.h"
|
||||
#endif
|
||||
|
@ -53,7 +57,9 @@ static CLG_LogRef LOG = {"bke.fcurve"};
|
|||
/* TypeInfo for Driver Variables (dvti) */
|
||||
typedef struct DriverVarTypeInfo {
|
||||
/* Evaluation callback. */
|
||||
float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
|
||||
float (*get_value)(const AnimationEvalContext *anim_eval_context,
|
||||
ChannelDriver *driver,
|
||||
DriverVar *dvar);
|
||||
|
||||
/* Allocation of target slots. */
|
||||
int num_targets; /* Number of target slots required. */
|
||||
|
@ -73,27 +79,89 @@ typedef struct DriverVarTypeInfo {
|
|||
/** \name Driver Target Utilities
|
||||
* \{ */
|
||||
|
||||
static DriverTargetContext driver_target_context_from_animation_context(
|
||||
const AnimationEvalContext *anim_eval_context)
|
||||
{
|
||||
DriverTargetContext driver_target_context;
|
||||
|
||||
driver_target_context.scene = DEG_get_evaluated_scene(anim_eval_context->depsgraph);
|
||||
driver_target_context.view_layer = DEG_get_evaluated_view_layer(anim_eval_context->depsgraph);
|
||||
|
||||
return driver_target_context;
|
||||
}
|
||||
|
||||
/* Specialized implementation of driver_get_target_property() used for the
|
||||
* DVAR_TYPE_CONTEXT_PROP variable type. */
|
||||
static bool driver_get_target_context_property(const DriverTargetContext *driver_target_context,
|
||||
DriverTarget *dtar,
|
||||
PointerRNA *r_property_ptr)
|
||||
{
|
||||
switch (dtar->context_property) {
|
||||
case DTAR_CONTEXT_PROPERTY_ACTIVE_SCENE:
|
||||
RNA_id_pointer_create(&driver_target_context->scene->id, r_property_ptr);
|
||||
return true;
|
||||
|
||||
case DTAR_CONTEXT_PROPERTY_ACTIVE_VIEW_LAYER: {
|
||||
RNA_pointer_create(&driver_target_context->scene->id,
|
||||
&RNA_ViewLayer,
|
||||
driver_target_context->view_layer,
|
||||
r_property_ptr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
|
||||
/* Reset to a NULL RNA pointer.
|
||||
* This allows to more gracefully handle issues with unsupported configuration (forward
|
||||
* compatibility. for example). */
|
||||
/* TODO(sergey): Replace with utility null-RNA-pointer creation once that is available. */
|
||||
r_property_ptr->data = NULL;
|
||||
r_property_ptr->type = NULL;
|
||||
r_property_ptr->owner_id = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool driver_get_target_property(const DriverTargetContext *driver_target_context,
|
||||
DriverVar *dvar,
|
||||
DriverTarget *dtar,
|
||||
PointerRNA *r_prop)
|
||||
{
|
||||
if (dvar->type == DVAR_TYPE_CONTEXT_PROP) {
|
||||
return driver_get_target_context_property(driver_target_context, dtar, r_prop);
|
||||
}
|
||||
|
||||
if (dtar->id == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RNA_id_pointer_create(dtar->id, r_prop);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to obtain a value using RNA from the specified source
|
||||
* (for evaluating drivers).
|
||||
*/
|
||||
static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
|
||||
static float dtar_get_prop_val(const AnimationEvalContext *anim_eval_context,
|
||||
ChannelDriver *driver,
|
||||
DriverVar *dvar,
|
||||
DriverTarget *dtar)
|
||||
{
|
||||
PointerRNA id_ptr, ptr;
|
||||
PropertyRNA *prop;
|
||||
ID *id;
|
||||
int index = -1;
|
||||
float value = 0.0f;
|
||||
|
||||
/* Sanity check. */
|
||||
if (ELEM(NULL, driver, dtar)) {
|
||||
if (driver == NULL) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
id = dtar->id;
|
||||
|
||||
/* Error check for missing pointer. */
|
||||
if (id == NULL) {
|
||||
/* Get property to resolve the target from.
|
||||
* Naming is a bit confusing, but this is what is exposed as "Prop" or "Context Property" in
|
||||
* interface. */
|
||||
const DriverTargetContext driver_target_context = driver_target_context_from_animation_context(
|
||||
anim_eval_context);
|
||||
PointerRNA property_ptr;
|
||||
if (!driver_get_target_property(&driver_target_context, dvar, dtar, &property_ptr)) {
|
||||
if (G.debug & G_DEBUG) {
|
||||
CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
|
||||
}
|
||||
|
@ -103,16 +171,18 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
|
|||
return 0.0f;
|
||||
}
|
||||
|
||||
/* Get RNA-pointer for the ID-block given in target. */
|
||||
RNA_id_pointer_create(id, &id_ptr);
|
||||
|
||||
/* Get property to read from, and get value as appropriate. */
|
||||
if (!RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
|
||||
PointerRNA value_ptr;
|
||||
PropertyRNA *value_prop;
|
||||
int index = -1;
|
||||
float value = 0.0f;
|
||||
if (!RNA_path_resolve_property_full(
|
||||
&property_ptr, dtar->rna_path, &value_ptr, &value_prop, &index)) {
|
||||
/* Path couldn't be resolved. */
|
||||
if (G.debug & G_DEBUG) {
|
||||
CLOG_ERROR(&LOG,
|
||||
"Driver Evaluation Error: cannot resolve target for %s -> %s",
|
||||
id->name,
|
||||
property_ptr.owner_id->name,
|
||||
dtar->rna_path);
|
||||
}
|
||||
|
||||
|
@ -121,14 +191,14 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
|
|||
return 0.0f;
|
||||
}
|
||||
|
||||
if (RNA_property_array_check(prop)) {
|
||||
if (RNA_property_array_check(value_prop)) {
|
||||
/* Array. */
|
||||
if (index < 0 || index >= RNA_property_array_length(&ptr, prop)) {
|
||||
if (index < 0 || index >= RNA_property_array_length(&value_ptr, value_prop)) {
|
||||
/* Out of bounds. */
|
||||
if (G.debug & G_DEBUG) {
|
||||
CLOG_ERROR(&LOG,
|
||||
"Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
|
||||
id->name,
|
||||
property_ptr.owner_id->name,
|
||||
dtar->rna_path,
|
||||
index);
|
||||
}
|
||||
|
@ -138,15 +208,15 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
|
|||
return 0.0f;
|
||||
}
|
||||
|
||||
switch (RNA_property_type(prop)) {
|
||||
switch (RNA_property_type(value_prop)) {
|
||||
case PROP_BOOLEAN:
|
||||
value = (float)RNA_property_boolean_get_index(&ptr, prop, index);
|
||||
value = (float)RNA_property_boolean_get_index(&value_ptr, value_prop, index);
|
||||
break;
|
||||
case PROP_INT:
|
||||
value = (float)RNA_property_int_get_index(&ptr, prop, index);
|
||||
value = (float)RNA_property_int_get_index(&value_ptr, value_prop, index);
|
||||
break;
|
||||
case PROP_FLOAT:
|
||||
value = RNA_property_float_get_index(&ptr, prop, index);
|
||||
value = RNA_property_float_get_index(&value_ptr, value_prop, index);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -154,18 +224,18 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
|
|||
}
|
||||
else {
|
||||
/* Not an array. */
|
||||
switch (RNA_property_type(prop)) {
|
||||
switch (RNA_property_type(value_prop)) {
|
||||
case PROP_BOOLEAN:
|
||||
value = (float)RNA_property_boolean_get(&ptr, prop);
|
||||
value = (float)RNA_property_boolean_get(&value_ptr, value_prop);
|
||||
break;
|
||||
case PROP_INT:
|
||||
value = (float)RNA_property_int_get(&ptr, prop);
|
||||
value = (float)RNA_property_int_get(&value_ptr, value_prop);
|
||||
break;
|
||||
case PROP_FLOAT:
|
||||
value = RNA_property_float_get(&ptr, prop);
|
||||
value = RNA_property_float_get(&value_ptr, value_prop);
|
||||
break;
|
||||
case PROP_ENUM:
|
||||
value = (float)RNA_property_enum_get(&ptr, prop);
|
||||
value = (float)RNA_property_enum_get(&value_ptr, value_prop);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -177,16 +247,16 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
|
|||
return value;
|
||||
}
|
||||
|
||||
bool driver_get_variable_property(ChannelDriver *driver,
|
||||
bool driver_get_variable_property(const AnimationEvalContext *anim_eval_context,
|
||||
ChannelDriver *driver,
|
||||
DriverVar *dvar,
|
||||
DriverTarget *dtar,
|
||||
PointerRNA *r_ptr,
|
||||
PropertyRNA **r_prop,
|
||||
int *r_index)
|
||||
{
|
||||
PointerRNA id_ptr;
|
||||
PointerRNA ptr;
|
||||
PropertyRNA *prop;
|
||||
ID *id;
|
||||
int index = -1;
|
||||
|
||||
/* Sanity check. */
|
||||
|
@ -194,10 +264,11 @@ bool driver_get_variable_property(ChannelDriver *driver,
|
|||
return false;
|
||||
}
|
||||
|
||||
id = dtar->id;
|
||||
|
||||
/* Error check for missing pointer. */
|
||||
if (id == NULL) {
|
||||
/* Get RNA-pointer for the data-block given in target. */
|
||||
const DriverTargetContext driver_target_context = driver_target_context_from_animation_context(
|
||||
anim_eval_context);
|
||||
PointerRNA target_ptr;
|
||||
if (!driver_get_target_property(&driver_target_context, dvar, dtar, &target_ptr)) {
|
||||
if (G.debug & G_DEBUG) {
|
||||
CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
|
||||
}
|
||||
|
@ -207,15 +278,12 @@ bool driver_get_variable_property(ChannelDriver *driver,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Get RNA-pointer for the ID-block given in target. */
|
||||
RNA_id_pointer_create(id, &id_ptr);
|
||||
|
||||
/* Get property to read from, and get value as appropriate. */
|
||||
if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
|
||||
ptr = PointerRNA_NULL;
|
||||
prop = NULL; /* OK. */
|
||||
}
|
||||
else if (RNA_path_resolve_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
|
||||
else if (RNA_path_resolve_full(&target_ptr, dtar->rna_path, &ptr, &prop, &index)) {
|
||||
/* OK. */
|
||||
}
|
||||
else {
|
||||
|
@ -223,7 +291,7 @@ bool driver_get_variable_property(ChannelDriver *driver,
|
|||
if (G.debug & G_DEBUG) {
|
||||
CLOG_ERROR(&LOG,
|
||||
"Driver Evaluation Error: cannot resolve target for %s -> %s",
|
||||
id->name,
|
||||
target_ptr.owner_id->name,
|
||||
dtar->rna_path);
|
||||
}
|
||||
|
||||
|
@ -276,14 +344,18 @@ static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
|
|||
* \{ */
|
||||
|
||||
/* Evaluate 'single prop' driver variable. */
|
||||
static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
|
||||
static float dvar_eval_singleProp(const AnimationEvalContext *anim_eval_context,
|
||||
ChannelDriver *driver,
|
||||
DriverVar *dvar)
|
||||
{
|
||||
/* Just evaluate the first target slot. */
|
||||
return dtar_get_prop_val(driver, &dvar->targets[0]);
|
||||
return dtar_get_prop_val(anim_eval_context, driver, dvar, &dvar->targets[0]);
|
||||
}
|
||||
|
||||
/* Evaluate 'rotation difference' driver variable. */
|
||||
static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
|
||||
static float dvar_eval_rotDiff(const AnimationEvalContext *UNUSED(anim_eval_context),
|
||||
ChannelDriver *driver,
|
||||
DriverVar *dvar)
|
||||
{
|
||||
short valid_targets = driver_check_valid_targets(driver, dvar);
|
||||
|
||||
|
@ -344,7 +416,9 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
|
|||
*
|
||||
* TODO: this needs to take into account space conversions.
|
||||
*/
|
||||
static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
|
||||
static float dvar_eval_locDiff(const AnimationEvalContext *UNUSED(anim_eval_context),
|
||||
ChannelDriver *driver,
|
||||
DriverVar *dvar)
|
||||
{
|
||||
float loc1[3] = {0.0f, 0.0f, 0.0f};
|
||||
float loc2[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
@ -446,7 +520,9 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
|
|||
/**
|
||||
* Evaluate 'transform channel' driver variable.
|
||||
*/
|
||||
static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
||||
static float dvar_eval_transChan(const AnimationEvalContext *UNUSED(anim_eval_context),
|
||||
ChannelDriver *driver,
|
||||
DriverVar *dvar)
|
||||
{
|
||||
DriverTarget *dtar = &dvar->targets[0];
|
||||
Object *ob = (Object *)dtar->id;
|
||||
|
@ -578,6 +654,15 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
|||
return mat[3][dtar->transChan];
|
||||
}
|
||||
|
||||
/* Evaluate 'context prop' driver variable. */
|
||||
static float dvar_eval_contextProp(const AnimationEvalContext *anim_eval_context,
|
||||
ChannelDriver *driver,
|
||||
DriverVar *dvar)
|
||||
{
|
||||
/* Just evaluate the first target slot. */
|
||||
return dtar_get_prop_val(anim_eval_context, driver, dvar, &dvar->targets[0]);
|
||||
}
|
||||
|
||||
/* Convert a quaternion to pseudo-angles representing the weighted amount of rotation. */
|
||||
static void quaternion_to_angles(float quat[4], int channel)
|
||||
{
|
||||
|
@ -675,6 +760,12 @@ static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
|
|||
{"Object/Bone"}, /* UI names for targets */
|
||||
{DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* Flags. */
|
||||
END_DVAR_TYPEDEF,
|
||||
|
||||
BEGIN_DVAR_TYPEDEF(DVAR_TYPE_CONTEXT_PROP) dvar_eval_contextProp, /* Eval callback. */
|
||||
1, /* Number of targets used. */
|
||||
{"Property"}, /* UI names for targets */
|
||||
{0} /* Flags. */
|
||||
END_DVAR_TYPEDEF,
|
||||
};
|
||||
|
||||
/* Get driver variable typeinfo */
|
||||
|
@ -972,7 +1063,8 @@ static bool driver_check_simple_expr_depends_on_time(ExprPyLike_Parsed *expr)
|
|||
return BLI_expr_pylike_is_using_param(expr, VAR_INDEX_FRAME);
|
||||
}
|
||||
|
||||
static bool driver_evaluate_simple_expr(ChannelDriver *driver,
|
||||
static bool driver_evaluate_simple_expr(const AnimationEvalContext *anim_eval_context,
|
||||
ChannelDriver *driver,
|
||||
ExprPyLike_Parsed *expr,
|
||||
float *result,
|
||||
float time)
|
||||
|
@ -985,7 +1077,7 @@ static bool driver_evaluate_simple_expr(ChannelDriver *driver,
|
|||
vars[VAR_INDEX_FRAME] = time;
|
||||
|
||||
LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
|
||||
vars[i++] = driver_get_variable_value(driver, dvar);
|
||||
vars[i++] = driver_get_variable_value(anim_eval_context, driver, dvar);
|
||||
}
|
||||
|
||||
/* Evaluate expression. */
|
||||
|
@ -1042,7 +1134,8 @@ static bool driver_compile_simple_expr(ChannelDriver *driver)
|
|||
|
||||
/* Try using the simple expression evaluator to compute the result of the driver.
|
||||
* On success, stores the result and returns true; on failure result is set to 0. */
|
||||
static bool driver_try_evaluate_simple_expr(ChannelDriver *driver,
|
||||
static bool driver_try_evaluate_simple_expr(const AnimationEvalContext *anim_eval_context,
|
||||
ChannelDriver *driver,
|
||||
ChannelDriver *driver_orig,
|
||||
float *result,
|
||||
float time)
|
||||
|
@ -1051,7 +1144,8 @@ static bool driver_try_evaluate_simple_expr(ChannelDriver *driver,
|
|||
|
||||
return driver_compile_simple_expr(driver_orig) &&
|
||||
BLI_expr_pylike_is_valid(driver_orig->expr_simple) &&
|
||||
driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time);
|
||||
driver_evaluate_simple_expr(
|
||||
anim_eval_context, driver, driver_orig->expr_simple, result, time);
|
||||
}
|
||||
|
||||
bool BKE_driver_has_simple_expression(ChannelDriver *driver)
|
||||
|
@ -1121,7 +1215,9 @@ void BKE_driver_invalidate_expression(ChannelDriver *driver,
|
|||
/** \name Driver Evaluation
|
||||
* \{ */
|
||||
|
||||
float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
|
||||
float driver_get_variable_value(const AnimationEvalContext *anim_eval_context,
|
||||
ChannelDriver *driver,
|
||||
DriverVar *dvar)
|
||||
{
|
||||
const DriverVarTypeInfo *dvti;
|
||||
|
||||
|
@ -1136,7 +1232,7 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
|
|||
dvti = get_dvar_typeinfo(dvar->type);
|
||||
|
||||
if (dvti && dvti->get_value) {
|
||||
dvar->curval = dvti->get_value(driver, dvar);
|
||||
dvar->curval = dvti->get_value(anim_eval_context, driver, dvar);
|
||||
}
|
||||
else {
|
||||
dvar->curval = 0.0f;
|
||||
|
@ -1145,7 +1241,8 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
|
|||
return dvar->curval;
|
||||
}
|
||||
|
||||
static void evaluate_driver_sum(ChannelDriver *driver)
|
||||
static void evaluate_driver_sum(const AnimationEvalContext *anim_eval_context,
|
||||
ChannelDriver *driver)
|
||||
{
|
||||
DriverVar *dvar;
|
||||
|
||||
|
@ -1153,7 +1250,7 @@ static void evaluate_driver_sum(ChannelDriver *driver)
|
|||
if (BLI_listbase_is_single(&driver->variables)) {
|
||||
/* Just one target, so just use that. */
|
||||
dvar = driver->variables.first;
|
||||
driver->curval = driver_get_variable_value(driver, dvar);
|
||||
driver->curval = driver_get_variable_value(anim_eval_context, driver, dvar);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1163,7 +1260,7 @@ static void evaluate_driver_sum(ChannelDriver *driver)
|
|||
|
||||
/* Loop through targets, adding (hopefully we don't get any overflow!). */
|
||||
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
|
||||
value += driver_get_variable_value(driver, dvar);
|
||||
value += driver_get_variable_value(anim_eval_context, driver, dvar);
|
||||
tot++;
|
||||
}
|
||||
|
||||
|
@ -1176,7 +1273,8 @@ static void evaluate_driver_sum(ChannelDriver *driver)
|
|||
}
|
||||
}
|
||||
|
||||
static void evaluate_driver_min_max(ChannelDriver *driver)
|
||||
static void evaluate_driver_min_max(const AnimationEvalContext *anim_eval_context,
|
||||
ChannelDriver *driver)
|
||||
{
|
||||
DriverVar *dvar;
|
||||
float value = 0.0f;
|
||||
|
@ -1184,7 +1282,7 @@ static void evaluate_driver_min_max(ChannelDriver *driver)
|
|||
/* Loop through the variables, getting the values and comparing them to existing ones. */
|
||||
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
|
||||
/* Get value. */
|
||||
float tmp_val = driver_get_variable_value(driver, dvar);
|
||||
float tmp_val = driver_get_variable_value(anim_eval_context, driver, dvar);
|
||||
|
||||
/* Store this value if appropriate. */
|
||||
if (dvar->prev) {
|
||||
|
@ -1221,8 +1319,11 @@ static void evaluate_driver_python(PathResolvedRNA *anim_rna,
|
|||
if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) {
|
||||
driver->curval = 0.0f;
|
||||
}
|
||||
else if (!driver_try_evaluate_simple_expr(
|
||||
driver, driver_orig, &driver->curval, anim_eval_context->eval_time)) {
|
||||
else if (!driver_try_evaluate_simple_expr(anim_eval_context,
|
||||
driver,
|
||||
driver_orig,
|
||||
&driver->curval,
|
||||
anim_eval_context->eval_time)) {
|
||||
#ifdef WITH_PYTHON
|
||||
/* This evaluates the expression using Python, and returns its result:
|
||||
* - on errors it reports, then returns 0.0f. */
|
||||
|
@ -1250,11 +1351,11 @@ float evaluate_driver(PathResolvedRNA *anim_rna,
|
|||
switch (driver->type) {
|
||||
case DRIVER_TYPE_AVERAGE: /* Average values of driver targets. */
|
||||
case DRIVER_TYPE_SUM: /* Sum values of driver targets. */
|
||||
evaluate_driver_sum(driver);
|
||||
evaluate_driver_sum(anim_eval_context, driver);
|
||||
break;
|
||||
case DRIVER_TYPE_MIN: /* Smallest value. */
|
||||
case DRIVER_TYPE_MAX: /* Largest value. */
|
||||
evaluate_driver_min_max(driver);
|
||||
evaluate_driver_min_max(anim_eval_context, driver);
|
||||
break;
|
||||
case DRIVER_TYPE_PYTHON: /* Expression. */
|
||||
evaluate_driver_python(anim_rna, driver, driver_orig, anim_eval_context);
|
||||
|
|
|
@ -342,7 +342,7 @@ MaskLayer *BKE_mask_layer_new(Mask *mask, const char *name)
|
|||
BLI_strncpy(masklay->name, name, sizeof(masklay->name));
|
||||
}
|
||||
else {
|
||||
strcpy(masklay->name, "MaskLayer");
|
||||
strcpy(masklay->name, DATA_("MaskLayer"));
|
||||
}
|
||||
|
||||
BLI_addtail(&mask->masklayers, masklay);
|
||||
|
|
|
@ -2053,19 +2053,22 @@ bool nodeFindNodeTry(bNodeTree *ntree, bNodeSocket *sock, bNode **r_node, int *r
|
|||
|
||||
bNode *nodeFindRootParent(bNode *node)
|
||||
{
|
||||
if (node->parent) {
|
||||
return nodeFindRootParent(node->parent);
|
||||
bNode *parent_iter = node;
|
||||
while (parent_iter->parent != nullptr) {
|
||||
parent_iter = parent_iter->parent;
|
||||
}
|
||||
return node->type == NODE_FRAME ? node : nullptr;
|
||||
if (parent_iter->type != NODE_FRAME) {
|
||||
return nullptr;
|
||||
}
|
||||
return parent_iter;
|
||||
}
|
||||
|
||||
bool nodeIsParentAndChild(const bNode *parent, const bNode *child)
|
||||
{
|
||||
if (parent == child) {
|
||||
return true;
|
||||
}
|
||||
if (child->parent) {
|
||||
return nodeIsParentAndChild(parent, child->parent);
|
||||
for (const bNode *child_iter = child; child_iter; child_iter = child_iter->parent) {
|
||||
if (child_iter == parent) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -2551,26 +2554,26 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
|
|||
|
||||
void nodeToView(const bNode *node, const float x, const float y, float *rx, float *ry)
|
||||
{
|
||||
if (node->parent) {
|
||||
nodeToView(node->parent, x + node->locx, y + node->locy, rx, ry);
|
||||
}
|
||||
else {
|
||||
*rx = x + node->locx;
|
||||
*ry = y + node->locy;
|
||||
float mapping_x = 0.0f;
|
||||
float mapping_y = 0.0f;
|
||||
for (const bNode *node_iter = node; node_iter; node_iter = node_iter->parent) {
|
||||
mapping_x += node_iter->locx;
|
||||
mapping_y += node_iter->locy;
|
||||
}
|
||||
*rx = mapping_x + x;
|
||||
*ry = mapping_y + y;
|
||||
}
|
||||
|
||||
void nodeFromView(const bNode *node, const float x, const float y, float *rx, float *ry)
|
||||
{
|
||||
if (node->parent) {
|
||||
nodeFromView(node->parent, x, y, rx, ry);
|
||||
*rx -= node->locx;
|
||||
*ry -= node->locy;
|
||||
}
|
||||
else {
|
||||
*rx = x - node->locx;
|
||||
*ry = y - node->locy;
|
||||
float mapping_x = 0.0f;
|
||||
float mapping_y = 0.0f;
|
||||
for (const bNode *node_iter = node; node_iter; node_iter = node_iter->parent) {
|
||||
mapping_x += node_iter->locx;
|
||||
mapping_y += node_iter->locy;
|
||||
}
|
||||
*rx = -mapping_x + x;
|
||||
*ry = -mapping_y + y;
|
||||
}
|
||||
|
||||
void nodeAttachNode(bNodeTree *ntree, bNode *node, bNode *parent)
|
||||
|
|
|
@ -1517,10 +1517,9 @@ void BKE_tracking_marker_get_subframe_position(MovieTrackingTrack *track,
|
|||
MovieTrackingMarker *marker_next = marker + 1;
|
||||
|
||||
if (marker_next->framenr == marker->framenr + 1) {
|
||||
/* currently only do subframing inside tracked ranges, do not extrapolate tracked segments
|
||||
/* Currently only do sub-framing inside tracked ranges, do not extrapolate tracked segments
|
||||
* could be changed when / if mask parent would be interpolating position in-between
|
||||
* tracked segments
|
||||
*/
|
||||
* tracked segments. */
|
||||
|
||||
float fac = (framenr - int(framenr)) / (marker_next->framenr - marker->framenr);
|
||||
|
||||
|
|
|
@ -310,7 +310,7 @@ static bool tracking_check_marker_margin(const libmv_Marker *libmv_marker,
|
|||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Autotrack context initialization.
|
||||
/** \name Auto-Track Context Initialization
|
||||
* \{ */
|
||||
|
||||
static bool autotrack_is_marker_usable(const MovieTrackingMarker *marker)
|
||||
|
|
|
@ -383,7 +383,7 @@ static AVFrame *generate_video_frame(FFMpegContext *context, const uint8_t *pixe
|
|||
rgb_frame = context->current_frame;
|
||||
}
|
||||
|
||||
/* Copy the Blender pixels into the FFmpeg datastructure, taking care of endianness and flipping
|
||||
/* Copy the Blender pixels into the FFMPEG data-structure, taking care of endianness and flipping
|
||||
* the image vertically. */
|
||||
int linesize = rgb_frame->linesize[0];
|
||||
for (int y = 0; y < height; y++) {
|
||||
|
|
|
@ -16,27 +16,27 @@
|
|||
|
||||
namespace blender {
|
||||
|
||||
template<typename T> class ListBaseWrapper {
|
||||
template<typename LB, typename T> class ListBaseWrapperTemplate {
|
||||
private:
|
||||
ListBase *listbase_;
|
||||
LB *listbase_;
|
||||
|
||||
public:
|
||||
ListBaseWrapper(ListBase *listbase) : listbase_(listbase)
|
||||
ListBaseWrapperTemplate(LB *listbase) : listbase_(listbase)
|
||||
{
|
||||
BLI_assert(listbase);
|
||||
}
|
||||
|
||||
ListBaseWrapper(ListBase &listbase) : ListBaseWrapper(&listbase)
|
||||
ListBaseWrapperTemplate(LB &listbase) : ListBaseWrapperTemplate(&listbase)
|
||||
{
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
private:
|
||||
ListBase *listbase_;
|
||||
LB *listbase_;
|
||||
T *current_;
|
||||
|
||||
public:
|
||||
Iterator(ListBase *listbase, T *current) : listbase_(listbase), current_(current)
|
||||
Iterator(LB *listbase, T *current) : listbase_(listbase), current_(current)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -96,4 +96,7 @@ template<typename T> class ListBaseWrapper {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T> using ListBaseWrapper = ListBaseWrapperTemplate<ListBase, T>;
|
||||
template<typename T> using ConstListBaseWrapper = ListBaseWrapperTemplate<const ListBase, const T>;
|
||||
|
||||
} /* namespace blender */
|
||||
|
|
|
@ -130,6 +130,8 @@ const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid
|
|||
#define BLT_I18NCONTEXT_VIRTUAL_REALITY "Virtual reality"
|
||||
#define BLT_I18NCONTEXT_CONSTRAINT "Constraint"
|
||||
#define BLT_I18NCONTEXT_COLOR "Color"
|
||||
#define BLT_I18NCONTEXT_AMOUNT "Amount"
|
||||
#define BLT_I18NCONTEXT_UNIT "Unit"
|
||||
|
||||
/* Helper for bpy.app.i18n object... */
|
||||
typedef struct {
|
||||
|
@ -198,6 +200,8 @@ typedef struct {
|
|||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_VIRTUAL_REALITY, "virtual_reality"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_CONSTRAINT, "constraint"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_COLOR, "color"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_AMOUNT, "amount"), \
|
||||
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_UNIT, "unit"), \
|
||||
{ \
|
||||
NULL, NULL, NULL \
|
||||
} \
|
||||
|
|
|
@ -6,6 +6,7 @@ set(INC
|
|||
cached_resources
|
||||
../../blenkernel
|
||||
../../blenlib
|
||||
../../blentranslation
|
||||
../../gpu
|
||||
../../imbuf
|
||||
../../makesdna
|
||||
|
|
|
@ -1192,29 +1192,46 @@ void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index
|
|||
|
||||
void DepsgraphNodeBuilder::build_driver_variables(ID *id, FCurve *fcurve)
|
||||
{
|
||||
build_driver_id_property(id, fcurve->rna_path);
|
||||
PointerRNA id_ptr;
|
||||
RNA_id_pointer_create(id, &id_ptr);
|
||||
|
||||
build_driver_id_property(id_ptr, fcurve->rna_path);
|
||||
|
||||
DriverTargetContext driver_target_context;
|
||||
driver_target_context.scene = graph_->scene;
|
||||
driver_target_context.view_layer = graph_->view_layer;
|
||||
|
||||
LISTBASE_FOREACH (DriverVar *, dvar, &fcurve->driver->variables) {
|
||||
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
|
||||
if (dtar->id == nullptr) {
|
||||
PointerRNA target_prop;
|
||||
if (!driver_get_target_property(&driver_target_context, dvar, dtar, &target_prop)) {
|
||||
continue;
|
||||
}
|
||||
build_id(dtar->id);
|
||||
build_driver_id_property(dtar->id, dtar->rna_path);
|
||||
|
||||
/* Property is always expected to be resolved to a non-null RNA property, which is always
|
||||
* relative to some ID. */
|
||||
BLI_assert(target_prop.owner_id);
|
||||
|
||||
ID *target_id = target_prop.owner_id;
|
||||
|
||||
build_id(target_id);
|
||||
build_driver_id_property(target_prop, dtar->rna_path);
|
||||
}
|
||||
DRIVER_TARGETS_LOOPER_END;
|
||||
}
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path)
|
||||
void DepsgraphNodeBuilder::build_driver_id_property(const PointerRNA &target_prop,
|
||||
const char *rna_path_from_target_prop)
|
||||
{
|
||||
if (id == nullptr || rna_path == nullptr) {
|
||||
if (rna_path_from_target_prop == nullptr || rna_path_from_target_prop[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
PointerRNA id_ptr, ptr;
|
||||
|
||||
PointerRNA ptr;
|
||||
PropertyRNA *prop;
|
||||
int index;
|
||||
RNA_id_pointer_create(id, &id_ptr);
|
||||
if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, &index)) {
|
||||
if (!RNA_path_resolve_full(&target_prop, rna_path_from_target_prop, &ptr, &prop, &index)) {
|
||||
return;
|
||||
}
|
||||
if (prop == nullptr) {
|
||||
|
|
|
@ -49,6 +49,7 @@ struct bNodeSocket;
|
|||
struct bNodeTree;
|
||||
struct bPoseChannel;
|
||||
struct bSound;
|
||||
struct PointerRNA;
|
||||
|
||||
namespace blender::deg {
|
||||
|
||||
|
@ -207,6 +208,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
|
|||
*/
|
||||
virtual void build_animation_images(ID *id);
|
||||
virtual void build_action(bAction *action);
|
||||
|
||||
/**
|
||||
* Build graph node(s) for Driver
|
||||
* \param id: ID-Block that driver is attached to
|
||||
|
@ -214,8 +216,22 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
|
|||
* \param driver_index: Index in animation data drivers list
|
||||
*/
|
||||
virtual void build_driver(ID *id, FCurve *fcurve, int driver_index);
|
||||
|
||||
virtual void build_driver_variables(ID *id, FCurve *fcurve);
|
||||
virtual void build_driver_id_property(ID *id, const char *rna_path);
|
||||
|
||||
/* Build operations of a property value from which is read by a driver target.
|
||||
*
|
||||
* The driver target points to a data-block (or a sub-data-block like View Layer).
|
||||
* This data-block is presented in the interface as a "Prop" and its resolved RNA pointer is
|
||||
* passed here as `target_prop`.
|
||||
*
|
||||
* The tricky part (and a bit confusing naming) is that the driver target accesses a property of
|
||||
* the `target_prop` to get its value. The property which is read to give an actual target value
|
||||
* is denoted by its RNA path relative to the `target_prop`. In the interface it is called "Path"
|
||||
* and here it is called `rna_path_from_target_prop`. */
|
||||
virtual void build_driver_id_property(const PointerRNA &target_prop,
|
||||
const char *rna_path_from_target_prop);
|
||||
|
||||
virtual void build_parameters(ID *id);
|
||||
virtual void build_dimensions(Object *object);
|
||||
virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
|
||||
|
|
|
@ -1743,16 +1743,30 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
|
|||
fcu->rna_path ? fcu->rna_path : "",
|
||||
fcu->array_index);
|
||||
const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
|
||||
|
||||
const RNAPathKey self_key(id, rna_path, RNAPointerSource::ENTRY);
|
||||
|
||||
DriverTargetContext driver_target_context;
|
||||
driver_target_context.scene = graph_->scene;
|
||||
driver_target_context.view_layer = graph_->view_layer;
|
||||
|
||||
LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
|
||||
/* Only used targets. */
|
||||
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
|
||||
ID *target_id = dtar->id;
|
||||
if (target_id == nullptr) {
|
||||
PointerRNA target_prop;
|
||||
if (!driver_get_target_property(&driver_target_context, dvar, dtar, &target_prop)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Property is always expected to be resolved to a non-null RNA property, which is always
|
||||
* relative to some ID. */
|
||||
BLI_assert(target_prop.owner_id);
|
||||
|
||||
ID *target_id = target_prop.owner_id;
|
||||
|
||||
build_id(target_id);
|
||||
build_driver_id_property(target_id, dtar->rna_path);
|
||||
build_driver_id_property(target_prop, dtar->rna_path);
|
||||
|
||||
Object *object = nullptr;
|
||||
if (GS(target_id->name) == ID_OB) {
|
||||
object = (Object *)target_id;
|
||||
|
@ -1849,16 +1863,17 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
|
|||
}
|
||||
}
|
||||
|
||||
void DepsgraphRelationBuilder::build_driver_id_property(ID *id, const char *rna_path)
|
||||
void DepsgraphRelationBuilder::build_driver_id_property(const PointerRNA &target_prop,
|
||||
const char *rna_path_from_target_prop)
|
||||
{
|
||||
if (id == nullptr || rna_path == nullptr) {
|
||||
if (rna_path_from_target_prop == nullptr || rna_path_from_target_prop[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
PointerRNA id_ptr, ptr;
|
||||
|
||||
PointerRNA ptr;
|
||||
PropertyRNA *prop;
|
||||
int index;
|
||||
RNA_id_pointer_create(id, &id_ptr);
|
||||
if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, &index)) {
|
||||
if (!RNA_path_resolve_full(&target_prop, rna_path_from_target_prop, &ptr, &prop, &index)) {
|
||||
return;
|
||||
}
|
||||
if (prop == nullptr) {
|
||||
|
|
|
@ -171,7 +171,20 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
|
|||
virtual void build_driver(ID *id, FCurve *fcurve);
|
||||
virtual void build_driver_data(ID *id, FCurve *fcurve);
|
||||
virtual void build_driver_variables(ID *id, FCurve *fcurve);
|
||||
virtual void build_driver_id_property(ID *id, const char *rna_path);
|
||||
|
||||
/* Build operations of a property value from which is read by a driver target.
|
||||
*
|
||||
* The driver target points to a data-block (or a sub-data-block like View Layer).
|
||||
* This data-block is presented in the interface as a "Prop" and its resolved RNA pointer is
|
||||
* passed here as `target_prop`.
|
||||
*
|
||||
* The tricky part (and a bit confusing naming) is that the driver target accesses a property of
|
||||
* the `target_prop` to get its value. The property which is read to give an actual target value
|
||||
* is denoted by its RNA path relative to the `target_prop`. In the interface it is called "Path"
|
||||
* and here it is called `rna_path_from_target_prop`. */
|
||||
virtual void build_driver_id_property(const PointerRNA &target_prop,
|
||||
const char *rna_path_from_target_prop);
|
||||
|
||||
virtual void build_parameters(ID *id);
|
||||
virtual void build_dimensions(Object *object);
|
||||
virtual void build_world(World *world);
|
||||
|
|
|
@ -241,7 +241,7 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
|
|||
}
|
||||
|
||||
/**
|
||||
* Reset for each "redraw". When rendering using ogl render,
|
||||
* Reset for each "redraw". When rendering using OpenGL render,
|
||||
* we accumulate the redraw inside the drawing loop in eevee_draw_scene().
|
||||
*/
|
||||
if (DRW_state_is_opengl_render()) {
|
||||
|
|
|
@ -233,7 +233,7 @@ void MotionBlurModule::render(View &view, GPUTexture **input_tx, GPUTexture **ou
|
|||
|
||||
tiles_tx_.acquire(tiles_extent, GPU_RGBA16F);
|
||||
|
||||
GPU_storagebuf_clear_to_zero(tile_indirection_buf_);
|
||||
tile_indirection_buf_.clear_to_zero();
|
||||
|
||||
inst_.manager->submit(motion_blur_ps_, view);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "DRW_render.h"
|
||||
|
||||
#include "BLI_listbase_wrapper.hh"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
|
@ -46,6 +47,8 @@
|
|||
|
||||
#define PT_DEFAULT_RAD 0.05f /* radius of the point batch. */
|
||||
|
||||
using namespace blender;
|
||||
|
||||
struct ArmatureDrawContext {
|
||||
/* Current armature object */
|
||||
Object *ob;
|
||||
|
@ -2355,7 +2358,7 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
|
|||
const Object *obact_orig = DEG_get_original_object(draw_ctx->obact);
|
||||
|
||||
const ListBase *defbase = BKE_object_defgroup_list(obact_orig);
|
||||
LISTBASE_FOREACH (const bDeformGroup *, dg, defbase) {
|
||||
for (const bDeformGroup *dg : ConstListBaseWrapper<bDeformGroup>(defbase)) {
|
||||
if (dg->flag & DG_LOCK_WEIGHT) {
|
||||
pchan = BKE_pose_channel_find_name(ob->pose, dg->name);
|
||||
|
||||
|
@ -2437,7 +2440,7 @@ static void draw_armature_pose(ArmatureDrawContext *ctx)
|
|||
draw_bone_box(ctx, nullptr, pchan, arm, boneflag, constflag, select_id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (arm->drawtype == ARM_OCTA) {
|
||||
draw_bone_update_disp_matrix_default(nullptr, pchan);
|
||||
if (!is_pose_select || pchan_culling_test_octohedral(view, ob, pchan)) {
|
||||
draw_bone_octahedral(ctx, nullptr, pchan, arm, boneflag, constflag, select_id);
|
||||
|
|
|
@ -106,7 +106,7 @@ void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata)
|
|||
/* Complementary Depth Pass */
|
||||
state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
|
||||
if (show_retopology) {
|
||||
/* Do not cull backfaces for retopology depth pass.
|
||||
/* Do not cull back-faces for retopology depth pass.
|
||||
* This prevents edit overlays from appearing behind any faces.
|
||||
* Doing so reduces visual clutter. */
|
||||
state &= ~DRW_STATE_CULL_BACK;
|
||||
|
@ -162,9 +162,9 @@ void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata)
|
|||
&pd->edit_mesh_faces_cage_grp[i];
|
||||
state = state_common;
|
||||
if (show_retopology) {
|
||||
/* Cull backfaces for retopology face pass.
|
||||
* This makes it so backfaces are not drawn.
|
||||
* Doing so lets us distinguish backfaces from frontfaces. */
|
||||
/* Cull back-faces for retopology face pass.
|
||||
* This makes it so back-faces are not drawn.
|
||||
* Doing so lets us distinguish back-faces from front-faces. */
|
||||
state |= DRW_STATE_CULL_BACK;
|
||||
}
|
||||
DRW_PASS_CREATE(*edit_face_ps, state | pd->clipping_state);
|
||||
|
|
|
@ -123,6 +123,9 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
|
|||
cb->field_tube_limit = BUF_INSTANCE(grp_sub, format, DRW_cache_field_tube_limit_get());
|
||||
cb->field_vortex = BUF_INSTANCE(grp_sub, format, DRW_cache_field_vortex_get());
|
||||
cb->field_wind = BUF_INSTANCE(grp_sub, format, DRW_cache_field_wind_get());
|
||||
cb->light_icon_inner = BUF_INSTANCE(grp_sub, format, DRW_cache_light_icon_inner_lines_get());
|
||||
cb->light_icon_outer = BUF_INSTANCE(grp_sub, format, DRW_cache_light_icon_outer_lines_get());
|
||||
cb->light_icon_sun_rays = BUF_INSTANCE(grp_sub, format, DRW_cache_light_icon_sun_rays_get());
|
||||
cb->light_area[0] = BUF_INSTANCE(grp_sub, format, DRW_cache_light_area_disk_lines_get());
|
||||
cb->light_area[1] = BUF_INSTANCE(grp_sub, format, DRW_cache_light_area_square_lines_get());
|
||||
cb->light_point = BUF_INSTANCE(grp_sub, format, DRW_cache_light_point_lines_get());
|
||||
|
@ -605,8 +608,9 @@ void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
|
|||
Light *la = static_cast<Light *>(ob->data);
|
||||
float *color_p;
|
||||
DRW_object_wire_theme_get(ob, view_layer, &color_p);
|
||||
|
||||
/* Remove the alpha. */
|
||||
float color[4] = {UNPACK3(color_p), 1.0f};
|
||||
float theme_color[4] = {UNPACK3(color_p), 1.0f};
|
||||
/* Pack render data into object matrix. */
|
||||
union {
|
||||
float mat[4][4];
|
||||
|
@ -636,12 +640,25 @@ void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
|
|||
|
||||
DRW_buffer_add_entry(cb->groundline, instdata.pos);
|
||||
|
||||
float light_color[4] = {1.0f};
|
||||
const bool show_light_colors = vedata->stl->pd->overlay.flag & V3D_OVERLAY_SHOW_LIGHT_COLORS;
|
||||
if (show_light_colors) {
|
||||
copy_v3_v3(light_color, &la->r);
|
||||
}
|
||||
|
||||
/* Draw the outer ring of the light icon and the sun rays in `light_color`, if required. */
|
||||
DRW_buffer_add_entry(
|
||||
cb->light_icon_outer, show_light_colors ? light_color : theme_color, &instdata);
|
||||
DRW_buffer_add_entry(cb->light_icon_inner, theme_color, &instdata);
|
||||
|
||||
if (la->type == LA_LOCAL) {
|
||||
instdata.area_size_x = instdata.area_size_y = la->radius;
|
||||
DRW_buffer_add_entry(cb->light_point, color, &instdata);
|
||||
DRW_buffer_add_entry(cb->light_point, theme_color, &instdata);
|
||||
}
|
||||
else if (la->type == LA_SUN) {
|
||||
DRW_buffer_add_entry(cb->light_sun, color, &instdata);
|
||||
DRW_buffer_add_entry(cb->light_sun, theme_color, &instdata);
|
||||
DRW_buffer_add_entry(
|
||||
cb->light_icon_sun_rays, show_light_colors ? light_color : theme_color, &instdata);
|
||||
}
|
||||
else if (la->type == LA_SPOT) {
|
||||
/* Previous implementation was using the clip-end distance as cone size.
|
||||
|
@ -664,8 +681,8 @@ void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
|
|||
instdata.spot_blend = sqrtf((a2 - a2 * c2) / (c2 - a2 * c2));
|
||||
instdata.spot_cosine = a;
|
||||
/* HACK: We pack the area size in alpha color. This is decoded by the shader. */
|
||||
color[3] = -max_ff(la->radius, FLT_MIN);
|
||||
DRW_buffer_add_entry(cb->light_spot, color, &instdata);
|
||||
theme_color[3] = -max_ff(la->radius, FLT_MIN);
|
||||
DRW_buffer_add_entry(cb->light_spot, theme_color, &instdata);
|
||||
|
||||
if ((la->mode & LA_SHOW_CONE) && !DRW_state_is_select()) {
|
||||
const float color_inside[4] = {0.0f, 0.0f, 0.0f, 0.5f};
|
||||
|
@ -679,7 +696,7 @@ void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
|
|||
int sqr = ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_RECT);
|
||||
instdata.area_size_x = la->area_size;
|
||||
instdata.area_size_y = uniform_scale ? la->area_size : la->area_sizey;
|
||||
DRW_buffer_add_entry(cb->light_area[sqr], color, &instdata);
|
||||
DRW_buffer_add_entry(cb->light_area[sqr], theme_color, &instdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -178,6 +178,9 @@ typedef struct OVERLAY_ExtraCallBuffers {
|
|||
|
||||
DRWCallBuffer *groundline;
|
||||
|
||||
DRWCallBuffer *light_icon_inner;
|
||||
DRWCallBuffer *light_icon_outer;
|
||||
DRWCallBuffer *light_icon_sun_rays;
|
||||
DRWCallBuffer *light_point;
|
||||
DRWCallBuffer *light_sun;
|
||||
DRWCallBuffer *light_spot;
|
||||
|
|
|
@ -577,7 +577,7 @@ static void write_render_z_output(struct RenderLayer *layer,
|
|||
|
||||
int pix_num = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
|
||||
|
||||
/* Convert ogl depth [0..1] to view Z [near..far] */
|
||||
/* Convert GPU depth [0..1] to view Z [near..far] */
|
||||
if (DRW_view_is_persp_get(nullptr)) {
|
||||
for (float &z : MutableSpan(rp->rect, pix_num)) {
|
||||
if (z == 1.0f) {
|
||||
|
|
|
@ -120,7 +120,7 @@ static void workbench_render_result_z(struct RenderLayer *rl,
|
|||
|
||||
int pix_num = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
|
||||
|
||||
/* Convert ogl depth [0..1] to view Z [near..far] */
|
||||
/* Convert GPU depth [0..1] to view Z [near..far] */
|
||||
if (DRW_view_is_persp_get(NULL)) {
|
||||
for (int i = 0; i < pix_num; i++) {
|
||||
if (rp->rect[i] == 1.0f) {
|
||||
|
|
|
@ -116,6 +116,9 @@ static struct DRWShapeCache {
|
|||
GPUBatch *drw_field_cone_limit;
|
||||
GPUBatch *drw_field_sphere_limit;
|
||||
GPUBatch *drw_ground_line;
|
||||
GPUBatch *drw_light_icon_inner_lines;
|
||||
GPUBatch *drw_light_icon_outer_lines;
|
||||
GPUBatch *drw_light_icon_sun_rays;
|
||||
GPUBatch *drw_light_point_lines;
|
||||
GPUBatch *drw_light_sun_lines;
|
||||
GPUBatch *drw_light_spot_lines;
|
||||
|
@ -1461,21 +1464,90 @@ GPUBatch *DRW_cache_groundline_get(void)
|
|||
return SHC.drw_ground_line;
|
||||
}
|
||||
|
||||
GPUBatch *DRW_cache_light_point_lines_get(void)
|
||||
GPUBatch *DRW_cache_light_icon_inner_lines_get(void)
|
||||
{
|
||||
if (!SHC.drw_light_point_lines) {
|
||||
if (!SHC.drw_light_icon_inner_lines) {
|
||||
GPUVertFormat format = extra_vert_format();
|
||||
|
||||
int v_len = 2 * (DIAMOND_NSEGMENTS + INNER_NSEGMENTS + OUTER_NSEGMENTS + CIRCLE_NSEGMENTS);
|
||||
int v_len = 2 * (DIAMOND_NSEGMENTS + INNER_NSEGMENTS);
|
||||
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
|
||||
GPU_vertbuf_data_alloc(vbo, v_len);
|
||||
|
||||
const float r = 9.0f;
|
||||
int v = 0;
|
||||
/* Light Icon */
|
||||
|
||||
circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
|
||||
circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
|
||||
|
||||
SHC.drw_light_icon_inner_lines = GPU_batch_create_ex(
|
||||
GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
|
||||
}
|
||||
return SHC.drw_light_icon_inner_lines;
|
||||
}
|
||||
|
||||
GPUBatch *DRW_cache_light_icon_outer_lines_get(void)
|
||||
{
|
||||
if (!SHC.drw_light_icon_outer_lines) {
|
||||
GPUVertFormat format = extra_vert_format();
|
||||
|
||||
int v_len = 2 * OUTER_NSEGMENTS;
|
||||
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
|
||||
GPU_vertbuf_data_alloc(vbo, v_len);
|
||||
|
||||
const float r = 9.0f;
|
||||
int v = 0;
|
||||
|
||||
circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
|
||||
|
||||
SHC.drw_light_icon_outer_lines = GPU_batch_create_ex(
|
||||
GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
|
||||
}
|
||||
return SHC.drw_light_icon_outer_lines;
|
||||
}
|
||||
|
||||
GPUBatch *DRW_cache_light_icon_sun_rays_get(void)
|
||||
{
|
||||
if (!SHC.drw_light_icon_sun_rays) {
|
||||
GPUVertFormat format = extra_vert_format();
|
||||
|
||||
const int num_rays = 8;
|
||||
int v_len = 4 * num_rays;
|
||||
|
||||
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
|
||||
GPU_vertbuf_data_alloc(vbo, v_len);
|
||||
|
||||
const float r = 9.0f;
|
||||
|
||||
int v = 0;
|
||||
|
||||
/* Sun Rays */
|
||||
for (int a = 0; a < num_rays; a++) {
|
||||
float angle = (2.0f * M_PI * a) / (float)num_rays;
|
||||
float s = sinf(angle) * r;
|
||||
float c = cosf(angle) * r;
|
||||
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 1.6f, c * 1.6f, 0.0f}, VCLASS_SCREENSPACE});
|
||||
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 1.9f, c * 1.9f, 0.0f}, VCLASS_SCREENSPACE});
|
||||
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 2.2f, c * 2.2f, 0.0f}, VCLASS_SCREENSPACE});
|
||||
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 2.5f, c * 2.5f, 0.0f}, VCLASS_SCREENSPACE});
|
||||
}
|
||||
|
||||
SHC.drw_light_icon_sun_rays = GPU_batch_create_ex(
|
||||
GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
|
||||
}
|
||||
return SHC.drw_light_icon_sun_rays;
|
||||
}
|
||||
|
||||
GPUBatch *DRW_cache_light_point_lines_get(void)
|
||||
{
|
||||
if (!SHC.drw_light_point_lines) {
|
||||
GPUVertFormat format = extra_vert_format();
|
||||
|
||||
int v_len = 2 * CIRCLE_NSEGMENTS;
|
||||
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
|
||||
GPU_vertbuf_data_alloc(vbo, v_len);
|
||||
|
||||
int v = 0;
|
||||
|
||||
/* Light area */
|
||||
int flag = VCLASS_SCREENALIGNED | VCLASS_LIGHT_AREA_SHAPE;
|
||||
circle_verts(vbo, &v, CIRCLE_NSEGMENTS, 1.0f, 0.0f, flag);
|
||||
|
@ -1490,26 +1562,12 @@ GPUBatch *DRW_cache_light_sun_lines_get(void)
|
|||
if (!SHC.drw_light_sun_lines) {
|
||||
GPUVertFormat format = extra_vert_format();
|
||||
|
||||
int v_len = 2 * (DIAMOND_NSEGMENTS + INNER_NSEGMENTS + OUTER_NSEGMENTS + 8 * 2 + 1);
|
||||
int v_len = 2;
|
||||
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
|
||||
GPU_vertbuf_data_alloc(vbo, v_len);
|
||||
|
||||
const float r = 9.0f;
|
||||
int v = 0;
|
||||
/* Light Icon */
|
||||
circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
|
||||
circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
|
||||
circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
|
||||
/* Sun Rays */
|
||||
for (int a = 0; a < 8; a++) {
|
||||
float angle = (2.0f * M_PI * a) / 8.0f;
|
||||
float s = sinf(angle) * r;
|
||||
float c = cosf(angle) * r;
|
||||
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 1.6f, c * 1.6f, 0.0f}, VCLASS_SCREENSPACE});
|
||||
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 1.9f, c * 1.9f, 0.0f}, VCLASS_SCREENSPACE});
|
||||
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 2.2f, c * 2.2f, 0.0f}, VCLASS_SCREENSPACE});
|
||||
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{s * 2.5f, c * 2.5f, 0.0f}, VCLASS_SCREENSPACE});
|
||||
}
|
||||
|
||||
/* Direction Line */
|
||||
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, 0.0}, 0});
|
||||
GPU_vertbuf_vert_set(vbo, v++, &(Vert){{0.0, 0.0, -20.0}, 0}); /* Good default. */
|
||||
|
@ -1524,17 +1582,12 @@ GPUBatch *DRW_cache_light_spot_lines_get(void)
|
|||
if (!SHC.drw_light_spot_lines) {
|
||||
GPUVertFormat format = extra_vert_format();
|
||||
|
||||
int v_len = 2 * (DIAMOND_NSEGMENTS * 3 + INNER_NSEGMENTS + OUTER_NSEGMENTS +
|
||||
CIRCLE_NSEGMENTS * 4 + 1);
|
||||
int v_len = 2 * (DIAMOND_NSEGMENTS * 2 + CIRCLE_NSEGMENTS * 4 + 1);
|
||||
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
|
||||
GPU_vertbuf_data_alloc(vbo, v_len);
|
||||
|
||||
const float r = 9.0f;
|
||||
int v = 0;
|
||||
/* Light Icon */
|
||||
circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
|
||||
circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
|
||||
circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
|
||||
|
||||
/* Light area */
|
||||
int flag = VCLASS_SCREENALIGNED | VCLASS_LIGHT_AREA_SHAPE;
|
||||
circle_verts(vbo, &v, CIRCLE_NSEGMENTS, 1.0f, 0.0f, flag);
|
||||
|
@ -1597,17 +1650,12 @@ GPUBatch *DRW_cache_light_area_disk_lines_get(void)
|
|||
if (!SHC.drw_light_area_disk_lines) {
|
||||
GPUVertFormat format = extra_vert_format();
|
||||
|
||||
int v_len = 2 *
|
||||
(DIAMOND_NSEGMENTS * 3 + INNER_NSEGMENTS + OUTER_NSEGMENTS + CIRCLE_NSEGMENTS + 1);
|
||||
int v_len = 2 * (DIAMOND_NSEGMENTS * 2 + CIRCLE_NSEGMENTS + 1);
|
||||
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
|
||||
GPU_vertbuf_data_alloc(vbo, v_len);
|
||||
|
||||
const float r = 9.0f;
|
||||
int v = 0;
|
||||
/* Light Icon */
|
||||
circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
|
||||
circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
|
||||
circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
|
||||
|
||||
/* Light area */
|
||||
circle_verts(vbo, &v, CIRCLE_NSEGMENTS, 0.5f, 0.0f, VCLASS_LIGHT_AREA_SHAPE);
|
||||
/* Direction Line */
|
||||
|
@ -1630,15 +1678,11 @@ GPUBatch *DRW_cache_light_area_square_lines_get(void)
|
|||
GPUVertFormat format = extra_vert_format();
|
||||
|
||||
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
|
||||
int v_len = 2 * (DIAMOND_NSEGMENTS * 3 + INNER_NSEGMENTS + OUTER_NSEGMENTS + 4 + 1);
|
||||
int v_len = 2 * (DIAMOND_NSEGMENTS * 2 + 4 + 1);
|
||||
GPU_vertbuf_data_alloc(vbo, v_len);
|
||||
|
||||
const float r = 9.0f;
|
||||
int v = 0;
|
||||
/* Light Icon */
|
||||
circle_verts(vbo, &v, DIAMOND_NSEGMENTS, r * 0.3f, 0.0f, VCLASS_SCREENSPACE);
|
||||
circle_dashed_verts(vbo, &v, INNER_NSEGMENTS, r * 1.0f, 0.0f, VCLASS_SCREENSPACE);
|
||||
circle_dashed_verts(vbo, &v, OUTER_NSEGMENTS, r * 1.33f, 0.0f, VCLASS_SCREENSPACE);
|
||||
|
||||
/* Light area */
|
||||
int flag = VCLASS_LIGHT_AREA_SHAPE;
|
||||
for (int a = 0; a < 4; a++) {
|
||||
|
|
|
@ -106,6 +106,9 @@ struct GPUBatch *DRW_cache_field_sphere_limit_get(void);
|
|||
|
||||
/* Lights */
|
||||
|
||||
struct GPUBatch *DRW_cache_light_icon_inner_lines_get(void);
|
||||
struct GPUBatch *DRW_cache_light_icon_outer_lines_get(void);
|
||||
struct GPUBatch *DRW_cache_light_icon_sun_rays_get(void);
|
||||
struct GPUBatch *DRW_cache_light_point_lines_get(void);
|
||||
struct GPUBatch *DRW_cache_light_sun_lines_get(void);
|
||||
struct GPUBatch *DRW_cache_light_spot_lines_get(void);
|
||||
|
|
|
@ -580,12 +580,19 @@ static void cage2d_draw_circle_wire(const float color[3],
|
|||
immUnbindProgram();
|
||||
}
|
||||
|
||||
static void cage2d_draw_rect_handles(const rctf *r,
|
||||
const float margin[2],
|
||||
const float color[3],
|
||||
const int transform_flag,
|
||||
bool solid)
|
||||
static void cage2d_draw_rect_corner_handles(const rctf *r,
|
||||
const int highlighted,
|
||||
const float margin[2],
|
||||
const float color[3],
|
||||
const int transform_flag,
|
||||
bool solid)
|
||||
{
|
||||
/* Only draw corner handles when hovering over the corners. */
|
||||
if (highlighted < ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y ||
|
||||
highlighted > ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
void (*circle_fn)(uint, float, float, float, float, int) = (solid) ?
|
||||
imm_draw_circle_fill_aspect_2d :
|
||||
|
@ -615,6 +622,38 @@ static void cage2d_draw_rect_handles(const rctf *r,
|
|||
immUnbindProgram();
|
||||
}
|
||||
|
||||
static void cage2d_draw_rect_edge_handles(const rctf *r,
|
||||
const int highlighted,
|
||||
const float size[2],
|
||||
const float margin[2],
|
||||
const float color[3],
|
||||
bool solid)
|
||||
{
|
||||
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
|
||||
immUniformColor3fv(color);
|
||||
|
||||
switch (highlighted) {
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X:
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X: {
|
||||
const float rad[2] = {0.2f * margin[0], 0.4f * size[1]};
|
||||
imm_draw_point_aspect_2d(pos, r->xmin, 0.f, rad[0], rad[1], solid);
|
||||
imm_draw_point_aspect_2d(pos, r->xmax, 0.f, rad[0], rad[1], solid);
|
||||
break;
|
||||
}
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y:
|
||||
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y: {
|
||||
const float rad[2] = {0.4f * size[0], 0.2f * margin[1]};
|
||||
imm_draw_point_aspect_2d(pos, 0.f, r->ymin, rad[0], rad[1], solid);
|
||||
imm_draw_point_aspect_2d(pos, 0.f, r->ymax, rad[0], rad[1], solid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
immUnbindProgram();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
static void gizmo_cage2d_draw_intern(wmGizmo *gz,
|
||||
|
@ -665,15 +704,15 @@ static void gizmo_cage2d_draw_intern(wmGizmo *gz,
|
|||
else {
|
||||
if (transform_flag & ED_GIZMO_CAGE_XFORM_FLAG_SCALE) {
|
||||
int scale_parts[] = {
|
||||
ED_GIZMO_CAGE2D_PART_SCALE_MIN_X,
|
||||
ED_GIZMO_CAGE2D_PART_SCALE_MAX_X,
|
||||
ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y,
|
||||
ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y,
|
||||
|
||||
ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y,
|
||||
ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y,
|
||||
ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y,
|
||||
ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y,
|
||||
|
||||
ED_GIZMO_CAGE2D_PART_SCALE_MIN_X,
|
||||
ED_GIZMO_CAGE2D_PART_SCALE_MAX_X,
|
||||
ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y,
|
||||
ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y,
|
||||
};
|
||||
for (int i = 0; i < ARRAY_SIZE(scale_parts); i++) {
|
||||
GPU_select_load_id(select_id | scale_parts[i]);
|
||||
|
@ -754,9 +793,15 @@ static void gizmo_cage2d_draw_intern(wmGizmo *gz,
|
|||
cage2d_draw_rect_wire(&r, margin, black, transform_flag, draw_options, outline_line_width);
|
||||
cage2d_draw_rect_wire(&r, margin, color, transform_flag, draw_options, gz->line_width);
|
||||
|
||||
/* Corner gizmos. */
|
||||
cage2d_draw_rect_handles(&r, margin, black, transform_flag, false);
|
||||
cage2d_draw_rect_handles(&r, margin, color, transform_flag, true);
|
||||
/* Edge handles. */
|
||||
cage2d_draw_rect_edge_handles(&r, gz->highlight_part, size_real, margin, color, true);
|
||||
cage2d_draw_rect_edge_handles(&r, gz->highlight_part, size_real, margin, black, false);
|
||||
|
||||
/* Corner handles. */
|
||||
cage2d_draw_rect_corner_handles(
|
||||
&r, gz->highlight_part, margin, color, transform_flag, true);
|
||||
cage2d_draw_rect_corner_handles(
|
||||
&r, gz->highlight_part, margin, black, transform_flag, false);
|
||||
}
|
||||
else if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
|
||||
cage2d_draw_circle_wire(black, size_real, margin, outline_line_width);
|
||||
|
|
|
@ -252,6 +252,7 @@ void ED_gpencil_trace_data_to_strokes(Main *bmain,
|
|||
float start_point[2], last[2];
|
||||
start_point[0] = c[n - 1][2].x;
|
||||
start_point[1] = c[n - 1][2].y;
|
||||
zero_v2(last);
|
||||
|
||||
for (int32_t i = 0; i < n; i++) {
|
||||
switch (tag[i]) {
|
||||
|
|
|
@ -3877,7 +3877,7 @@ static void ui_but_update_ex(uiBut *but, const bool validate)
|
|||
case UI_BTYPE_KEY_EVENT: {
|
||||
const char *str;
|
||||
if (but->flag & UI_SELECT) {
|
||||
str = "Press a key";
|
||||
str = IFACE_("Press a key");
|
||||
}
|
||||
else {
|
||||
UI_GET_BUT_VALUE_INIT(but, value);
|
||||
|
@ -3910,7 +3910,7 @@ static void ui_but_update_ex(uiBut *but, const bool validate)
|
|||
(void)str; /* UNUSED */
|
||||
}
|
||||
else {
|
||||
BLI_strncpy(but->drawstr, "Press a key", UI_MAX_DRAW_STR);
|
||||
BLI_strncpy(but->drawstr, IFACE_("Press a key"), UI_MAX_DRAW_STR);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -902,6 +902,29 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar
|
|||
uiItemR(sub, &dtar_ptr, "transform_space", 0, IFACE_("Space"), ICON_NONE);
|
||||
}
|
||||
|
||||
/* Settings for 'Context Property' driver variable type. */
|
||||
static void graph_panel_driverVar__contextProp(uiLayout *layout, ID *id, DriverVar *dvar)
|
||||
{
|
||||
DriverTarget *dtar = &dvar->targets[0];
|
||||
|
||||
/* Initialize RNA pointer to the target. */
|
||||
PointerRNA dtar_ptr;
|
||||
RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
|
||||
|
||||
/* Target Property. */
|
||||
{
|
||||
uiLayout *row = uiLayoutRow(layout, false);
|
||||
uiItemR(row, &dtar_ptr, "context_property", 0, NULL, ICON_NONE);
|
||||
}
|
||||
|
||||
/* Target Path */
|
||||
{
|
||||
uiLayout *col = uiLayoutColumn(layout, true);
|
||||
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID));
|
||||
uiTemplatePathBuilder(col, &dtar_ptr, "data_path", NULL, IFACE_("Path"));
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
/* property driven by the driver - duplicates Active FCurve, but useful for clarity */
|
||||
|
@ -1213,6 +1236,9 @@ static void graph_draw_driver_settings_panel(uiLayout *layout,
|
|||
case DVAR_TYPE_TRANSFORM_CHAN: /* transform channel */
|
||||
graph_panel_driverVar__transChan(box, id, dvar);
|
||||
break;
|
||||
case DVAR_TYPE_CONTEXT_PROP: /* context property */
|
||||
graph_panel_driverVar__contextProp(box, id, dvar);
|
||||
break;
|
||||
}
|
||||
|
||||
/* 3) value of variable */
|
||||
|
|
|
@ -181,6 +181,23 @@ void ED_node_tag_update_id(ID *id)
|
|||
|
||||
namespace blender::ed::space_node {
|
||||
|
||||
static const char *node_socket_get_translation_context(const bNodeSocket &socket)
|
||||
{
|
||||
/* The node is not explicitly defined. */
|
||||
if (socket.runtime->declaration == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
blender::StringRefNull translation_context = socket.runtime->declaration->translation_context;
|
||||
|
||||
/* Default context. */
|
||||
if (translation_context.is_empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return translation_context.data();
|
||||
}
|
||||
|
||||
static void node_socket_add_tooltip_in_node_editor(const bNodeTree &ntree,
|
||||
const bNodeSocket &sock,
|
||||
uiLayout &layout);
|
||||
|
@ -380,8 +397,14 @@ static void node_update_basis(const bContext &C,
|
|||
/* Align output buttons to the right. */
|
||||
uiLayout *row = uiLayoutRow(layout, true);
|
||||
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
|
||||
|
||||
const char *socket_label = nodeSocketLabel(socket);
|
||||
socket->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
|
||||
const char *socket_translation_context = node_socket_get_translation_context(*socket);
|
||||
socket->typeinfo->draw((bContext *)&C,
|
||||
row,
|
||||
&sockptr,
|
||||
&nodeptr,
|
||||
CTX_IFACE_(socket_translation_context, socket_label));
|
||||
|
||||
node_socket_add_tooltip_in_node_editor(ntree, *socket, *row);
|
||||
|
||||
|
@ -514,7 +537,12 @@ static void node_update_basis(const bContext &C,
|
|||
uiLayout *row = uiLayoutRow(layout, true);
|
||||
|
||||
const char *socket_label = nodeSocketLabel(socket);
|
||||
socket->typeinfo->draw((bContext *)&C, row, &sockptr, &nodeptr, IFACE_(socket_label));
|
||||
const char *socket_translation_context = node_socket_get_translation_context(*socket);
|
||||
socket->typeinfo->draw((bContext *)&C,
|
||||
row,
|
||||
&sockptr,
|
||||
&nodeptr,
|
||||
CTX_IFACE_(socket_translation_context, socket_label));
|
||||
|
||||
node_socket_add_tooltip_in_node_editor(ntree, *socket, *row);
|
||||
|
||||
|
|
|
@ -2810,8 +2810,10 @@ void TEXT_OT_scroll(wmOperatorType *ot)
|
|||
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_INTERNAL;
|
||||
|
||||
/* properties */
|
||||
RNA_def_int(
|
||||
PropertyRNA *prop;
|
||||
prop = RNA_def_int(
|
||||
ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_TEXT);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -2915,8 +2917,10 @@ void TEXT_OT_scroll_bar(wmOperatorType *ot)
|
|||
ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
|
||||
|
||||
/* properties */
|
||||
RNA_def_int(
|
||||
PropertyRNA *prop;
|
||||
prop = RNA_def_int(
|
||||
ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_TEXT);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -51,6 +51,7 @@ set(SRC
|
|||
transform_convert_sequencer.c
|
||||
transform_convert_sequencer_image.c
|
||||
transform_convert_tracking.c
|
||||
transform_convert_tracking_curves.c
|
||||
transform_draw_cursors.c
|
||||
transform_generics.c
|
||||
transform_gizmo_2d.c
|
||||
|
|
|
@ -624,7 +624,9 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
|
|||
return false;
|
||||
}
|
||||
if (value == TFM_MODAL_TRANSLATE && t->mode == TFM_TRANSLATION) {
|
||||
return false;
|
||||
/* The tracking transform in MovieClip has an alternate translate that modifies the offset
|
||||
* of the tracks. */
|
||||
return t->data_type == &TransConvertType_Tracking;
|
||||
}
|
||||
if (value == TFM_MODAL_ROTATE && t->mode == TFM_ROTATION) {
|
||||
return false;
|
||||
|
@ -987,16 +989,16 @@ int transformEvent(TransInfo *t, const wmEvent *event)
|
|||
t->redraw |= TREDRAW_HARD;
|
||||
handled = true;
|
||||
}
|
||||
else if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
|
||||
restoreTransObjects(t);
|
||||
|
||||
t->flag ^= T_ALT_TRANSFORM;
|
||||
t->redraw |= TREDRAW_HARD;
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (t->mode == TFM_TRANSLATION) {
|
||||
if (t->data_type == &TransConvertType_Tracking) {
|
||||
restoreTransObjects(t);
|
||||
|
||||
t->flag ^= T_ALT_TRANSFORM;
|
||||
t->redraw |= TREDRAW_HARD;
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
restoreTransObjects(t);
|
||||
|
|
|
@ -932,6 +932,9 @@ static TransConvertTypeInfo *convert_type_get(const TransInfo *t, Object **r_obj
|
|||
}
|
||||
if (t->spacetype == SPACE_CLIP) {
|
||||
if (t->options & CTX_MOVIECLIP) {
|
||||
if (t->region->regiontype == RGN_TYPE_PREVIEW) {
|
||||
return &TransConvertType_TrackingCurves;
|
||||
}
|
||||
return &TransConvertType_Tracking;
|
||||
}
|
||||
if (t->options & CTX_MASK) {
|
||||
|
|
|
@ -276,6 +276,10 @@ extern TransConvertTypeInfo TransConvertType_SequencerImage;
|
|||
|
||||
extern TransConvertTypeInfo TransConvertType_Tracking;
|
||||
|
||||
/* transform_convert_tracking_curves.c */
|
||||
|
||||
extern TransConvertTypeInfo TransConvertType_TrackingCurves;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -9,26 +9,24 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_movieclip.h"
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_node_tree_update.h"
|
||||
#include "BKE_tracking.h"
|
||||
|
||||
#include "ED_clip.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "transform.h"
|
||||
#include "transform_convert.h"
|
||||
|
||||
typedef struct TransDataTracking {
|
||||
int mode, flag;
|
||||
int mode;
|
||||
int flag;
|
||||
|
||||
/* tracks transformation from main window */
|
||||
int area;
|
||||
|
@ -41,18 +39,13 @@ typedef struct TransDataTracking {
|
|||
int framenr;
|
||||
MovieTrackingMarker *markers;
|
||||
|
||||
/* marker transformation from curves editor */
|
||||
float *prev_pos, scale;
|
||||
short coord;
|
||||
|
||||
MovieTrackingTrack *track;
|
||||
MovieTrackingPlaneTrack *plane_track;
|
||||
} TransDataTracking;
|
||||
|
||||
enum transDataTracking_Mode {
|
||||
transDataTracking_ModeTracks = 0,
|
||||
transDataTracking_ModeCurves = 1,
|
||||
transDataTracking_ModePlaneTracks = 2,
|
||||
transDataTracking_ModePlaneTracks = 1,
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -379,139 +372,8 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
|
|||
}
|
||||
}
|
||||
|
||||
static void markerToTransCurveDataInit(TransData *td,
|
||||
TransData2D *td2d,
|
||||
TransDataTracking *tdt,
|
||||
MovieTrackingTrack *track,
|
||||
MovieTrackingMarker *marker,
|
||||
MovieTrackingMarker *prev_marker,
|
||||
short coord,
|
||||
float size)
|
||||
{
|
||||
float frames_delta = (marker->framenr - prev_marker->framenr);
|
||||
|
||||
tdt->flag = marker->flag;
|
||||
marker->flag &= ~MARKER_TRACKED;
|
||||
|
||||
tdt->mode = transDataTracking_ModeCurves;
|
||||
tdt->coord = coord;
|
||||
tdt->scale = 1.0f / size * frames_delta;
|
||||
tdt->prev_pos = prev_marker->pos;
|
||||
tdt->track = track;
|
||||
|
||||
/* calculate values depending on marker's speed */
|
||||
td2d->loc[0] = marker->framenr;
|
||||
td2d->loc[1] = (marker->pos[coord] - prev_marker->pos[coord]) * size / frames_delta;
|
||||
td2d->loc[2] = 0.0f;
|
||||
|
||||
td2d->loc2d = marker->pos; /* current location */
|
||||
|
||||
td->flag = 0;
|
||||
td->loc = td2d->loc;
|
||||
copy_v3_v3(td->center, td->loc);
|
||||
copy_v3_v3(td->iloc, td->loc);
|
||||
|
||||
memset(td->axismtx, 0, sizeof(td->axismtx));
|
||||
td->axismtx[2][2] = 1.0f;
|
||||
|
||||
td->ext = NULL;
|
||||
td->val = NULL;
|
||||
|
||||
td->flag |= TD_SELECTED;
|
||||
td->dist = 0.0;
|
||||
|
||||
unit_m3(td->mtx);
|
||||
unit_m3(td->smtx);
|
||||
}
|
||||
|
||||
static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
|
||||
{
|
||||
TransData *td;
|
||||
TransData2D *td2d;
|
||||
SpaceClip *sc = CTX_wm_space_clip(C);
|
||||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
|
||||
TransDataTracking *tdt;
|
||||
|
||||
int width, height;
|
||||
BKE_movieclip_get_size(clip, &sc->user, &width, &height);
|
||||
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
|
||||
/* count */
|
||||
tc->data_len = 0;
|
||||
|
||||
if ((sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
|
||||
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
|
||||
for (int i = 1; i < track->markersnr; i++) {
|
||||
const MovieTrackingMarker *marker = &track->markers[i];
|
||||
const MovieTrackingMarker *prev_marker = &track->markers[i - 1];
|
||||
|
||||
if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (marker->flag & MARKER_GRAPH_SEL_X) {
|
||||
tc->data_len += 1;
|
||||
}
|
||||
|
||||
if (marker->flag & MARKER_GRAPH_SEL_Y) {
|
||||
tc->data_len += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tc->data_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
|
||||
td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
|
||||
"TransTracking TransData2D");
|
||||
tc->custom.type.data = tdt = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
|
||||
"TransTracking TransDataTracking");
|
||||
tc->custom.type.free_cb = transDataTrackingFree;
|
||||
|
||||
/* create actual data */
|
||||
LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
|
||||
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
|
||||
for (int i = 1; i < track->markersnr; i++) {
|
||||
MovieTrackingMarker *marker = &track->markers[i];
|
||||
MovieTrackingMarker *prev_marker = &track->markers[i - 1];
|
||||
|
||||
if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (marker->flag & MARKER_GRAPH_SEL_X) {
|
||||
markerToTransCurveDataInit(
|
||||
td, td2d, tdt, track, marker, &track->markers[i - 1], 0, width);
|
||||
td += 1;
|
||||
td2d += 1;
|
||||
tdt += 1;
|
||||
}
|
||||
|
||||
if (marker->flag & MARKER_GRAPH_SEL_Y) {
|
||||
markerToTransCurveDataInit(
|
||||
td, td2d, tdt, track, marker, &track->markers[i - 1], 1, height);
|
||||
|
||||
td += 1;
|
||||
td2d += 1;
|
||||
tdt += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void createTransTrackingData(bContext *C, TransInfo *t)
|
||||
{
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
SpaceClip *sc = CTX_wm_space_clip(C);
|
||||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
int width, height;
|
||||
|
@ -530,13 +392,7 @@ static void createTransTrackingData(bContext *C, TransInfo *t)
|
|||
return;
|
||||
}
|
||||
|
||||
if (region->regiontype == RGN_TYPE_PREVIEW) {
|
||||
/* transformation was called from graph editor */
|
||||
createTransTrackingCurvesData(C, t);
|
||||
}
|
||||
else {
|
||||
createTransTrackingTracksData(C, t);
|
||||
}
|
||||
createTransTrackingTracksData(C, t);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -574,24 +430,6 @@ static void cancelTransTracking(TransInfo *t)
|
|||
i += 2;
|
||||
}
|
||||
}
|
||||
else if (tdt->mode == transDataTracking_ModeCurves) {
|
||||
MovieTrackingTrack *track = tdt->track;
|
||||
MovieTrackingMarker *marker, *prev_marker;
|
||||
int a;
|
||||
|
||||
for (a = 1; a < track->markersnr; a++) {
|
||||
marker = &track->markers[a];
|
||||
prev_marker = &track->markers[a - 1];
|
||||
|
||||
if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (marker->flag & (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y)) {
|
||||
marker->flag = tdt->flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tdt->mode == transDataTracking_ModePlaneTracks) {
|
||||
MovieTrackingPlaneTrack *plane_track = tdt->plane_track;
|
||||
MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get_exact(plane_track,
|
||||
|
@ -675,9 +513,6 @@ static void flushTransTracking(TransInfo *t)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (tdt->mode == transDataTracking_ModeCurves) {
|
||||
td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale;
|
||||
}
|
||||
else if (tdt->mode == transDataTracking_ModePlaneTracks) {
|
||||
td2d->loc2d[0] = td2d->loc[0] / t->aspect[0];
|
||||
td2d->loc2d[1] = td2d->loc[1] / t->aspect[1];
|
||||
|
|
|
@ -0,0 +1,300 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup edtransform
|
||||
*/
|
||||
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_movieclip.h"
|
||||
#include "BKE_node_tree_update.h"
|
||||
#include "BKE_tracking.h"
|
||||
|
||||
#include "ED_clip.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
#include "transform.h"
|
||||
#include "transform_convert.h"
|
||||
|
||||
typedef struct TransDataTrackingCurves {
|
||||
int flag;
|
||||
|
||||
/* marker transformation from curves editor */
|
||||
float *prev_pos;
|
||||
float scale;
|
||||
short coord;
|
||||
|
||||
MovieTrackingTrack *track;
|
||||
} TransDataTrackingCurves;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Clip Editor Motion Tracking Transform Creation
|
||||
* \{ */
|
||||
|
||||
static void markerToTransCurveDataInit(TransData *td,
|
||||
TransData2D *td2d,
|
||||
TransDataTrackingCurves *tdt,
|
||||
MovieTrackingTrack *track,
|
||||
MovieTrackingMarker *marker,
|
||||
MovieTrackingMarker *prev_marker,
|
||||
short coord,
|
||||
float size)
|
||||
{
|
||||
float frames_delta = (marker->framenr - prev_marker->framenr);
|
||||
|
||||
tdt->flag = marker->flag;
|
||||
marker->flag &= ~MARKER_TRACKED;
|
||||
|
||||
tdt->coord = coord;
|
||||
tdt->scale = 1.0f / size * frames_delta;
|
||||
tdt->prev_pos = prev_marker->pos;
|
||||
tdt->track = track;
|
||||
|
||||
/* calculate values depending on marker's speed */
|
||||
td2d->loc[0] = marker->framenr;
|
||||
td2d->loc[1] = (marker->pos[coord] - prev_marker->pos[coord]) * size / frames_delta;
|
||||
td2d->loc[2] = 0.0f;
|
||||
|
||||
td2d->loc2d = marker->pos; /* current location */
|
||||
|
||||
td->flag = 0;
|
||||
td->loc = td2d->loc;
|
||||
copy_v3_v3(td->center, td->loc);
|
||||
copy_v3_v3(td->iloc, td->loc);
|
||||
|
||||
memset(td->axismtx, 0, sizeof(td->axismtx));
|
||||
td->axismtx[2][2] = 1.0f;
|
||||
|
||||
td->ext = NULL;
|
||||
td->val = NULL;
|
||||
|
||||
td->flag |= TD_SELECTED;
|
||||
td->dist = 0.0;
|
||||
|
||||
unit_m3(td->mtx);
|
||||
unit_m3(td->smtx);
|
||||
}
|
||||
|
||||
static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
|
||||
{
|
||||
TransData *td;
|
||||
TransData2D *td2d;
|
||||
SpaceClip *sc = CTX_wm_space_clip(C);
|
||||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
|
||||
TransDataTrackingCurves *tdt;
|
||||
|
||||
int width, height;
|
||||
BKE_movieclip_get_size(clip, &sc->user, &width, &height);
|
||||
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
|
||||
/* count */
|
||||
tc->data_len = 0;
|
||||
|
||||
if ((sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
|
||||
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
|
||||
for (int i = 1; i < track->markersnr; i++) {
|
||||
const MovieTrackingMarker *marker = &track->markers[i];
|
||||
const MovieTrackingMarker *prev_marker = &track->markers[i - 1];
|
||||
|
||||
if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (marker->flag & MARKER_GRAPH_SEL_X) {
|
||||
tc->data_len += 1;
|
||||
}
|
||||
|
||||
if (marker->flag & MARKER_GRAPH_SEL_Y) {
|
||||
tc->data_len += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tc->data_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
|
||||
td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
|
||||
"TransTracking TransData2D");
|
||||
tc->custom.type.data = tdt = MEM_callocN(tc->data_len * sizeof(TransDataTrackingCurves),
|
||||
"TransTracking TransDataTracking");
|
||||
tc->custom.type.free_cb = NULL;
|
||||
|
||||
/* create actual data */
|
||||
LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
|
||||
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
|
||||
for (int i = 1; i < track->markersnr; i++) {
|
||||
MovieTrackingMarker *marker = &track->markers[i];
|
||||
MovieTrackingMarker *prev_marker = &track->markers[i - 1];
|
||||
|
||||
if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (marker->flag & MARKER_GRAPH_SEL_X) {
|
||||
markerToTransCurveDataInit(
|
||||
td, td2d, tdt, track, marker, &track->markers[i - 1], 0, width);
|
||||
td += 1;
|
||||
td2d += 1;
|
||||
tdt += 1;
|
||||
}
|
||||
|
||||
if (marker->flag & MARKER_GRAPH_SEL_Y) {
|
||||
markerToTransCurveDataInit(
|
||||
td, td2d, tdt, track, marker, &track->markers[i - 1], 1, height);
|
||||
|
||||
td += 1;
|
||||
td2d += 1;
|
||||
tdt += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void createTransTrackingCurves(bContext *C, TransInfo *t)
|
||||
{
|
||||
SpaceClip *sc = CTX_wm_space_clip(C);
|
||||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
int width, height;
|
||||
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
|
||||
tc->data_len = 0;
|
||||
|
||||
if (!clip) {
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_movieclip_get_size(clip, &sc->user, &width, &height);
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* transformation was called from graph editor */
|
||||
BLI_assert(CTX_wm_region(C)->regiontype == RGN_TYPE_PREVIEW);
|
||||
createTransTrackingCurvesData(C, t);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name recalc Motion Tracking TransData
|
||||
* \{ */
|
||||
|
||||
static void cancelTransTrackingCurves(TransInfo *t)
|
||||
{
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
TransDataTrackingCurves *tdt_array = tc->custom.type.data;
|
||||
|
||||
int i = 0;
|
||||
while (i < tc->data_len) {
|
||||
TransDataTrackingCurves *tdt = &tdt_array[i];
|
||||
|
||||
{
|
||||
MovieTrackingTrack *track = tdt->track;
|
||||
MovieTrackingMarker *marker, *prev_marker;
|
||||
int a;
|
||||
|
||||
for (a = 1; a < track->markersnr; a++) {
|
||||
marker = &track->markers[a];
|
||||
prev_marker = &track->markers[a - 1];
|
||||
|
||||
if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (marker->flag & (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y)) {
|
||||
marker->flag = tdt->flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
static void flushTransTrackingCurves(TransInfo *t)
|
||||
{
|
||||
TransData *td;
|
||||
TransData2D *td2d;
|
||||
TransDataTrackingCurves *tdt;
|
||||
int td_index;
|
||||
|
||||
if (t->state == TRANS_CANCEL) {
|
||||
cancelTransTrackingCurves(t);
|
||||
}
|
||||
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
|
||||
/* flush to 2d vector from internally used 3d vector */
|
||||
for (td_index = 0, td = tc->data, td2d = tc->data_2d, tdt = tc->custom.type.data;
|
||||
td_index < tc->data_len;
|
||||
td_index++, td2d++, td++, tdt++) {
|
||||
{
|
||||
td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void recalcData_tracking_curves(TransInfo *t)
|
||||
{
|
||||
SpaceClip *sc = t->area->spacedata.first;
|
||||
|
||||
if (ED_space_clip_check_show_trackedit(sc)) {
|
||||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
|
||||
flushTransTrackingCurves(t);
|
||||
|
||||
DEG_id_tag_update(&clip->id, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Special After Transform Tracking
|
||||
* \{ */
|
||||
|
||||
static void special_aftertrans_update__movieclip_for_curves(bContext *C, TransInfo *t)
|
||||
{
|
||||
SpaceClip *sc = t->area->spacedata.first;
|
||||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
if (t->scene->nodetree != NULL) {
|
||||
/* Tracks can be used for stabilization nodes,
|
||||
* flush update for such nodes.
|
||||
*/
|
||||
if (t->context != NULL) {
|
||||
Main *bmain = CTX_data_main(C);
|
||||
BKE_ntree_update_tag_id_changed(bmain, &clip->id);
|
||||
BKE_ntree_update_main(bmain, NULL);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
TransConvertTypeInfo TransConvertType_TrackingCurves = {
|
||||
/*flags*/ (T_POINTS | T_2D_EDIT),
|
||||
/*createTransData*/ createTransTrackingCurves,
|
||||
/*recalcData*/ recalcData_tracking_curves,
|
||||
/*special_aftertrans_update*/ special_aftertrans_update__movieclip_for_curves,
|
||||
};
|
|
@ -594,7 +594,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
|
|||
Object *ob,
|
||||
BMEditMesh *em,
|
||||
const UnwrapOptions *options,
|
||||
UnwrapResultInfo *result_info)
|
||||
int *r_count_failed = nullptr)
|
||||
{
|
||||
/* pointers to modifier data for unwrap control */
|
||||
SubsurfModifierData *smd_real;
|
||||
|
@ -666,8 +666,8 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
|
|||
nullptr;
|
||||
}
|
||||
|
||||
/* Prepare and feed faces to the solver */
|
||||
for (const int i : subsurf_polys.index_range()) {
|
||||
/* Prepare and feed faces to the solver. */
|
||||
for (const int64_t i : subsurf_polys.index_range()) {
|
||||
const MPoly &poly = subsurf_polys[i];
|
||||
ParamKey key, vkeys[4];
|
||||
bool pin[4], select[4];
|
||||
|
@ -717,8 +717,8 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
|
|||
blender::geometry::uv_parametrizer_face_add(handle, key, 4, vkeys, co, uv, pin, select);
|
||||
}
|
||||
|
||||
/* these are calculated from original mesh too */
|
||||
for (const int i : subsurf_edges.index_range()) {
|
||||
/* These are calculated from original mesh too. */
|
||||
for (const int64_t i : subsurf_edges.index_range()) {
|
||||
if ((edgeMap[i] != nullptr) && BM_elem_flag_test(edgeMap[i], BM_ELEM_SEAM)) {
|
||||
const MEdge *edge = &subsurf_edges[i];
|
||||
ParamKey vkeys[2];
|
||||
|
@ -728,11 +728,8 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
|
|||
}
|
||||
}
|
||||
|
||||
blender::geometry::uv_parametrizer_construct_end(handle,
|
||||
options->fill_holes,
|
||||
options->topology_from_uvs,
|
||||
result_info ? &result_info->count_failed :
|
||||
nullptr);
|
||||
blender::geometry::uv_parametrizer_construct_end(
|
||||
handle, options->fill_holes, options->topology_from_uvs, r_count_failed);
|
||||
|
||||
/* cleanup */
|
||||
MEM_freeN(faceMap);
|
||||
|
@ -1804,7 +1801,8 @@ static void uvedit_unwrap(const Scene *scene,
|
|||
|
||||
ParamHandle *handle;
|
||||
if (use_subsurf) {
|
||||
handle = construct_param_handle_subsurfed(scene, obedit, em, options, result_info);
|
||||
handle = construct_param_handle_subsurfed(
|
||||
scene, obedit, em, options, result_info ? &result_info->count_failed : nullptr);
|
||||
}
|
||||
else {
|
||||
handle = construct_param_handle(
|
||||
|
|
|
@ -146,12 +146,21 @@ void solve_length_and_collision_constraints(const OffsetIndices<int> points_by_c
|
|||
float slide_direction_length_cu;
|
||||
const float3 normalized_slide_direction_cu = math::normalize_and_get_length(
|
||||
slide_direction_cu, slide_direction_length_cu);
|
||||
const float slide_normal_length_sq_cu = math::length_squared(slide_normal_cu);
|
||||
|
||||
/* Use pythagorian theorem to determine how far to slide. */
|
||||
const float slide_distance_cu = std::sqrt(pow2f(goal_segment_length_cu) -
|
||||
math::length_squared(slide_normal_cu)) -
|
||||
slide_direction_length_cu;
|
||||
positions_cu[point_i] = plane_pos_cu + normalized_slide_direction_cu * slide_distance_cu;
|
||||
if (pow2f(goal_segment_length_cu) > slide_normal_length_sq_cu) {
|
||||
/* Use pythagorian theorem to determine how far to slide. */
|
||||
const float slide_distance_cu = std::sqrt(pow2f(goal_segment_length_cu) -
|
||||
slide_normal_length_sq_cu) -
|
||||
slide_direction_length_cu;
|
||||
positions_cu[point_i] = plane_pos_cu +
|
||||
normalized_slide_direction_cu * slide_distance_cu;
|
||||
}
|
||||
else {
|
||||
/* Minimum distance is larger than allowed segment length.
|
||||
* The unilateral collision constraint is satisfied by just clamping segment length. */
|
||||
positions_cu[point_i] = prev_pos_cu + math::normalize(old_pos_su - prev_pos_cu) * goal_segment_length_cu;
|
||||
}
|
||||
}
|
||||
if (used_iterations == max_collisions) {
|
||||
revert_curve = true;
|
||||
|
|
|
@ -28,12 +28,12 @@ static float pack_islands_scale_margin(const Span<PackIsland *> &island_vector,
|
|||
for (const int64_t index : island_vector.index_range()) {
|
||||
PackIsland *island = island_vector[index];
|
||||
BoxPack *box = &box_array[index];
|
||||
box->index = (int)index;
|
||||
box->index = int(index);
|
||||
box->w = BLI_rctf_size_x(&island->bounds_rect) * scale + 2 * margin;
|
||||
box->h = BLI_rctf_size_y(&island->bounds_rect) * scale + 2 * margin;
|
||||
}
|
||||
float max_u, max_v;
|
||||
BLI_box_pack_2d(box_array, (int)island_vector.size(), &max_u, &max_v);
|
||||
BLI_box_pack_2d(box_array, int(island_vector.size()), &max_u, &max_v);
|
||||
return max_ff(max_u, max_v);
|
||||
}
|
||||
|
||||
|
|
|
@ -201,9 +201,11 @@ set(VULKAN_SRC
|
|||
vulkan/vk_fence.cc
|
||||
vulkan/vk_framebuffer.cc
|
||||
vulkan/vk_index_buffer.cc
|
||||
vulkan/vk_memory_layout.cc
|
||||
vulkan/vk_memory.cc
|
||||
vulkan/vk_pipeline.cc
|
||||
vulkan/vk_pixel_buffer.cc
|
||||
vulkan/vk_push_constants.cc
|
||||
vulkan/vk_query.cc
|
||||
vulkan/vk_shader.cc
|
||||
vulkan/vk_shader_interface.cc
|
||||
|
@ -226,9 +228,11 @@ set(VULKAN_SRC
|
|||
vulkan/vk_fence.hh
|
||||
vulkan/vk_framebuffer.hh
|
||||
vulkan/vk_index_buffer.hh
|
||||
vulkan/vk_memory_layout.hh
|
||||
vulkan/vk_memory.hh
|
||||
vulkan/vk_pipeline.hh
|
||||
vulkan/vk_pixel_buffer.hh
|
||||
vulkan/vk_push_constants.hh
|
||||
vulkan/vk_query.hh
|
||||
vulkan/vk_shader.hh
|
||||
vulkan/vk_shader_interface.hh
|
||||
|
@ -532,6 +536,7 @@ set(GLSL_SRC_TEST
|
|||
tests/shaders/gpu_compute_ssbo_test.glsl
|
||||
tests/shaders/gpu_compute_vbo_test.glsl
|
||||
tests/shaders/gpu_compute_dummy_test.glsl
|
||||
tests/shaders/gpu_push_constants_test.glsl
|
||||
)
|
||||
|
||||
set(MTL_BACKEND_GLSL_SRC
|
||||
|
@ -804,12 +809,19 @@ if(WITH_GTESTS)
|
|||
tests/gpu_testing.cc
|
||||
|
||||
tests/gpu_index_buffer_test.cc
|
||||
tests/gpu_push_constants_test.cc
|
||||
tests/gpu_shader_builtin_test.cc
|
||||
tests/gpu_shader_test.cc
|
||||
tests/gpu_storage_buffer_test.cc
|
||||
|
||||
tests/gpu_testing.hh
|
||||
)
|
||||
if(WITH_VULKAN_BACKEND)
|
||||
list(APPEND TEST_SRC
|
||||
tests/memory_layout_test.cc
|
||||
)
|
||||
endif()
|
||||
|
||||
set(TEST_INC
|
||||
)
|
||||
set(TEST_LIB
|
||||
|
|
|
@ -313,15 +313,15 @@ bool GPU_framebuffer_check_valid(GPUFrameBuffer *framebuffer, char err_out[256])
|
|||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Empty framebuffer
|
||||
/** \name Empty frame-buffer
|
||||
*
|
||||
* An empty framebuffer is a framebuffer with no attachments. This allow to rasterize geometry
|
||||
* An empty frame-buffer is a frame-buffer with no attachments. This allow to rasterize geometry
|
||||
* without creating any dummy attachments and write some computation results using other means
|
||||
* (SSBOs, Images).
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Default size is used if the framebuffer contains no attachments.
|
||||
* Default size is used if the frame-buffer contains no attachments.
|
||||
* It needs to be re-specified each time an attachment is added.
|
||||
*/
|
||||
void GPU_framebuffer_default_size(GPUFrameBuffer *framebuffer, int width, int height);
|
||||
|
@ -349,7 +349,7 @@ void GPU_framebuffer_viewport_set(
|
|||
void GPU_framebuffer_viewport_get(GPUFrameBuffer *framebuffer, int r_viewport[4]);
|
||||
|
||||
/**
|
||||
* Reset a framebuffer viewport bounds to its attachment(s) size.
|
||||
* Reset a frame-buffer viewport bounds to its attachment(s) size.
|
||||
* \note Viewport and scissor size is stored per frame-buffer.
|
||||
*/
|
||||
void GPU_framebuffer_viewport_reset(GPUFrameBuffer *framebuffer);
|
||||
|
@ -361,7 +361,7 @@ void GPU_framebuffer_viewport_reset(GPUFrameBuffer *framebuffer);
|
|||
* \{ */
|
||||
|
||||
/**
|
||||
* Clear the framebuffer attachments.
|
||||
* Clear the frame-buffer attachments.
|
||||
* \a buffers controls the types of attachments to clear. Setting GPU_COLOR_BIT will clear *all*
|
||||
* the color attachment.
|
||||
* Each attachment gets cleared to the value of its type:
|
||||
|
@ -438,19 +438,19 @@ void GPU_framebuffer_clear_color_depth_stencil(GPUFrameBuffer *fb,
|
|||
void GPU_framebuffer_multi_clear(GPUFrameBuffer *framebuffer, const float (*clear_colors)[4]);
|
||||
|
||||
/**
|
||||
* Clear all color attachment textures of the active framebuffer with the given red, green, blue,
|
||||
* Clear all color attachment textures of the active frame-buffer with the given red, green, blue,
|
||||
* alpha values.
|
||||
* \note `GPU_write_mask`, and stencil test do not affect this command.
|
||||
* \note Viewport and scissor regions affect this command but are not efficient nor recommended.
|
||||
* DEPRECATED: Use `GPU_framebuffer_clear_color` with explicit framebuffer.
|
||||
* DEPRECATED: Use `GPU_framebuffer_clear_color` with explicit frame-buffer.
|
||||
*/
|
||||
void GPU_clear_color(float red, float green, float blue, float alpha);
|
||||
|
||||
/**
|
||||
* Clear the depth attachment texture of the active framebuffer with the given depth value.
|
||||
* Clear the depth attachment texture of the active frame-buffer with the given depth value.
|
||||
* \note `GPU_write_mask`, and stencil test do not affect this command.
|
||||
* \note Viewport and scissor regions affect this command but are not efficient nor recommended.
|
||||
* DEPRECATED: Use `GPU_framebuffer_clear_color` with explicit framebuffer.
|
||||
* DEPRECATED: Use `GPU_framebuffer_clear_color` with explicit frame-buffer.
|
||||
*/
|
||||
void GPU_clear_depth(float depth);
|
||||
|
||||
|
@ -467,7 +467,7 @@ const char *GPU_framebuffer_get_name(GPUFrameBuffer *framebuffer);
|
|||
/* -------------------------------------------------------------------- */
|
||||
/** \name Python API & meta-data
|
||||
*
|
||||
* These are not intrinsic properties of a framebuffer but they are stored inside the
|
||||
* These are not intrinsic properties of a frame-buffer but they are stored inside the
|
||||
* gpu::FrameBuffer structure for tracking purpose.
|
||||
* \{ */
|
||||
|
||||
|
@ -481,8 +481,8 @@ void GPU_framebuffer_py_reference_set(GPUFrameBuffer *framebuffer, void **py_ref
|
|||
#endif
|
||||
|
||||
/**
|
||||
* Keep a stack of bound framebuffer to allow scoped binding of framebuffer in python.
|
||||
* This is also used by #GPUOffScreen to save/restore the current framebuffers.
|
||||
* Keep a stack of bound frame-buffer to allow scoped binding of frame-buffer in python.
|
||||
* This is also used by #GPUOffScreen to save/restore the current frame-buffers.
|
||||
* \note This isn't thread safe.
|
||||
*/
|
||||
/* TODO(fclem): This has nothing to do with the GPU module and should be move to the pyGPU module.
|
||||
|
@ -547,7 +547,7 @@ void GPU_frontbuffer_read_pixels(
|
|||
* The attachments types are chosen by \a blit_buffers .
|
||||
* Only one color buffer can by copied at a time and its index is chosen by \a read_slot and \a
|
||||
* write_slot.
|
||||
* The source and destination framebuffers dimensions have to match.
|
||||
* The source and destination frame-buffers dimensions have to match.
|
||||
* DEPRECATED: Prefer using `GPU_texture_copy()`.
|
||||
*/
|
||||
void GPU_framebuffer_blit(GPUFrameBuffer *fb_read,
|
||||
|
|
|
@ -417,7 +417,7 @@ void GPU_framebuffer_clear_color(GPUFrameBuffer *fb, const float clear_col[4])
|
|||
|
||||
void GPU_framebuffer_clear_depth(GPUFrameBuffer *fb, float clear_depth)
|
||||
{
|
||||
GPU_framebuffer_clear(fb, GPU_DEPTH_BIT, NULL, clear_depth, 0x00);
|
||||
GPU_framebuffer_clear(fb, GPU_DEPTH_BIT, nullptr, clear_depth, 0x00);
|
||||
}
|
||||
|
||||
void GPU_framebuffer_clear_color_depth(GPUFrameBuffer *fb,
|
||||
|
@ -429,12 +429,12 @@ void GPU_framebuffer_clear_color_depth(GPUFrameBuffer *fb,
|
|||
|
||||
void GPU_framebuffer_clear_stencil(GPUFrameBuffer *fb, uint clear_stencil)
|
||||
{
|
||||
GPU_framebuffer_clear(fb, GPU_STENCIL_BIT, NULL, 0.0f, clear_stencil);
|
||||
GPU_framebuffer_clear(fb, GPU_STENCIL_BIT, nullptr, 0.0f, clear_stencil);
|
||||
}
|
||||
|
||||
void GPU_framebuffer_clear_depth_stencil(GPUFrameBuffer *fb, float clear_depth, uint clear_stencil)
|
||||
{
|
||||
GPU_framebuffer_clear(fb, GPU_DEPTH_BIT | GPU_STENCIL_BIT, NULL, clear_depth, clear_stencil);
|
||||
GPU_framebuffer_clear(fb, GPU_DEPTH_BIT | GPU_STENCIL_BIT, nullptr, clear_depth, clear_stencil);
|
||||
}
|
||||
|
||||
void GPU_framebuffer_clear_color_depth_stencil(GPUFrameBuffer *fb,
|
||||
|
|
|
@ -55,6 +55,36 @@ GPU_SHADER_CREATE_INFO(gpu_compute_ssbo_binding_test)
|
|||
.compute_source("gpu_compute_dummy_test.glsl")
|
||||
.do_static_compilation(true);
|
||||
|
||||
/* Push constants*/
|
||||
GPU_SHADER_CREATE_INFO(gpu_push_constants_base_test)
|
||||
.local_group_size(1)
|
||||
.storage_buf(0, Qualifier::WRITE, "float", "data_out[]")
|
||||
.compute_source("gpu_push_constants_test.glsl");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_push_constants_test)
|
||||
.additional_info("gpu_push_constants_base_test")
|
||||
.push_constant(Type::FLOAT, "float_in")
|
||||
.push_constant(Type::VEC2, "vec2_in")
|
||||
.push_constant(Type::VEC3, "vec3_in")
|
||||
.push_constant(Type::VEC4, "vec4_in")
|
||||
.do_static_compilation(true);
|
||||
|
||||
/* Push constants size test. */
|
||||
GPU_SHADER_CREATE_INFO(gpu_push_constants_128bytes_test)
|
||||
.additional_info("gpu_push_constants_test")
|
||||
.push_constant(Type::FLOAT, "filler", 20)
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_push_constants_256bytes_test)
|
||||
.additional_info("gpu_push_constants_128bytes_test")
|
||||
.push_constant(Type::FLOAT, "filler2", 32)
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_push_constants_512bytes_test)
|
||||
.additional_info("gpu_push_constants_256bytes_test")
|
||||
.push_constant(Type::FLOAT, "filler3", 64)
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_shadow_test)
|
||||
.fragment_source("eevee_shadow_test.glsl")
|
||||
.additional_info("gpu_shader_test")
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "GPU_capabilities.h"
|
||||
#include "GPU_compute.h"
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_storage_buffer.h"
|
||||
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_utility_mixins.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
namespace blender::gpu::tests {
|
||||
struct CallData {
|
||||
GPUStorageBuf *ssbo = nullptr;
|
||||
Vector<float> data;
|
||||
|
||||
float float_in;
|
||||
float2 vec2_in;
|
||||
float3 vec3_in;
|
||||
float4 vec4_in;
|
||||
|
||||
void init_ssbo(size_t num_floats)
|
||||
{
|
||||
if (ssbo == nullptr) {
|
||||
ssbo = GPU_storagebuf_create_ex(
|
||||
num_floats * sizeof(float), nullptr, GPU_USAGE_DEVICE_ONLY, __func__);
|
||||
data.resize(num_floats);
|
||||
}
|
||||
}
|
||||
|
||||
~CallData()
|
||||
{
|
||||
if (ssbo != nullptr) {
|
||||
GPU_storagebuf_free(ssbo);
|
||||
ssbo = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_test_data(const float vector_mul, const float scalar_mul)
|
||||
{
|
||||
float_in = vector_mul;
|
||||
vec2_in = float2(vector_mul * 2.0, vector_mul * 2.0 + scalar_mul);
|
||||
vec3_in = float3(
|
||||
vector_mul * 3.0, vector_mul * 3.0 + scalar_mul, vector_mul * 3.0 + scalar_mul * 2.0);
|
||||
vec4_in = float4(vector_mul * 4.0,
|
||||
vector_mul * 4.0 + scalar_mul,
|
||||
vector_mul * 4.0 + scalar_mul * 2.0,
|
||||
vector_mul * 4.0 + scalar_mul * 3.0);
|
||||
}
|
||||
|
||||
void read_back()
|
||||
{
|
||||
GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||
GPU_storagebuf_read(ssbo, data.data());
|
||||
}
|
||||
|
||||
void validate()
|
||||
{
|
||||
/* Check the results. */
|
||||
EXPECT_EQ(data[0], float_in);
|
||||
EXPECT_EQ(data[1], vec2_in.x);
|
||||
EXPECT_EQ(data[2], vec2_in.y);
|
||||
EXPECT_EQ(data[3], vec3_in.x);
|
||||
EXPECT_EQ(data[4], vec3_in.y);
|
||||
EXPECT_EQ(data[5], vec3_in.z);
|
||||
EXPECT_EQ(data[6], vec4_in.x);
|
||||
EXPECT_EQ(data[7], vec4_in.y);
|
||||
EXPECT_EQ(data[8], vec4_in.z);
|
||||
EXPECT_EQ(data[9], vec4_in.w);
|
||||
}
|
||||
};
|
||||
|
||||
struct Shader {
|
||||
GPUShader *shader = nullptr;
|
||||
Vector<CallData> call_datas;
|
||||
|
||||
~Shader()
|
||||
{
|
||||
if (shader != nullptr) {
|
||||
GPU_shader_unbind();
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
}
|
||||
|
||||
void init_shader(const char *info_name)
|
||||
{
|
||||
if (shader == nullptr) {
|
||||
shader = GPU_shader_create_from_info_name(info_name);
|
||||
EXPECT_NE(shader, nullptr);
|
||||
GPU_shader_bind(shader);
|
||||
}
|
||||
}
|
||||
|
||||
CallData &new_call()
|
||||
{
|
||||
CallData call_data;
|
||||
call_datas.append(call_data);
|
||||
return call_datas.last();
|
||||
}
|
||||
|
||||
void bind(CallData &call_data)
|
||||
{
|
||||
GPU_storagebuf_bind(call_data.ssbo, GPU_shader_get_ssbo_binding(shader, "data_out"));
|
||||
}
|
||||
|
||||
void update_push_constants(const CallData &call_data)
|
||||
{
|
||||
GPU_shader_uniform_1f(shader, "float_in", call_data.float_in);
|
||||
GPU_shader_uniform_2fv(shader, "vec2_in", call_data.vec2_in);
|
||||
GPU_shader_uniform_3fv(shader, "vec3_in", call_data.vec3_in);
|
||||
GPU_shader_uniform_4fv(shader, "vec4_in", call_data.vec4_in);
|
||||
}
|
||||
|
||||
void dispatch()
|
||||
{
|
||||
GPU_compute_dispatch(shader, 1, 1, 1);
|
||||
}
|
||||
};
|
||||
|
||||
/** Test the given info when doing a single call. */
|
||||
static void do_push_constants_test(const char *info_name, const int num_calls_simultaneously = 1)
|
||||
{
|
||||
if (!GPU_compute_shader_support() && !GPU_shader_storage_buffer_objects_support()) {
|
||||
/* We can't test as a the platform does not support compute shaders. */
|
||||
std::cout << "Skipping test: platform not supported";
|
||||
return;
|
||||
}
|
||||
|
||||
static constexpr uint SIZE = 16;
|
||||
|
||||
Shader shader;
|
||||
shader.init_shader(info_name);
|
||||
|
||||
for (const int call_index : IndexRange(num_calls_simultaneously)) {
|
||||
CallData &call_data = shader.new_call();
|
||||
call_data.generate_test_data(call_index * 10.0, call_index * 1.0);
|
||||
call_data.init_ssbo(SIZE);
|
||||
shader.bind(call_data);
|
||||
shader.update_push_constants(call_data);
|
||||
shader.dispatch();
|
||||
}
|
||||
/* All calls will be "simultaneously" in flight. First read-back will wait until the dispatches
|
||||
* have finished execution. */
|
||||
for (const int call_index : IndexRange(num_calls_simultaneously)) {
|
||||
CallData &call_data = shader.call_datas[call_index];
|
||||
call_data.read_back();
|
||||
call_data.validate();
|
||||
}
|
||||
}
|
||||
|
||||
/* Test case with single call as sanity check, before we make it more interesting. */
|
||||
static void test_push_constants()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_test");
|
||||
}
|
||||
GPU_TEST(push_constants)
|
||||
|
||||
static void test_push_constants_128bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_128bytes_test");
|
||||
}
|
||||
GPU_TEST(push_constants_128bytes)
|
||||
|
||||
static void test_push_constants_256bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_256bytes_test");
|
||||
}
|
||||
GPU_TEST(push_constants_256bytes)
|
||||
|
||||
static void test_push_constants_512bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_512bytes_test");
|
||||
}
|
||||
GPU_TEST(push_constants_512bytes)
|
||||
|
||||
#if 0
|
||||
/* Schedule multiple simultaneously. */
|
||||
/* These test have been disabled for now as this will to be solved in a separate PR.
|
||||
* - `DescriptorSets` may not be altered, when they are in the command queue or being executed.
|
||||
*/
|
||||
static void test_push_constants_multiple()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_test", 10);
|
||||
}
|
||||
GPU_TEST(push_constants_multiple)
|
||||
|
||||
static void test_push_constants_multiple_128bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_128bytes_test", 10);
|
||||
}
|
||||
GPU_TEST(push_constants_multiple_128bytes)
|
||||
|
||||
static void test_push_constants_multiple_256bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_256bytes_test", 10);
|
||||
}
|
||||
GPU_TEST(push_constants_multiple_256bytes)
|
||||
|
||||
static void test_push_constants_multiple_512bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_512bytes_test", 10);
|
||||
}
|
||||
GPU_TEST(push_constants_multiple_512bytes)
|
||||
#endif
|
||||
|
||||
} // namespace blender::gpu::tests
|
|
@ -0,0 +1,100 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "../vulkan/vk_memory_layout.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
template<typename Layout>
|
||||
static void def_attr(const shader::Type type,
|
||||
const int array_size,
|
||||
const uint32_t expected_alignment,
|
||||
const uint32_t expected_reserve,
|
||||
uint32_t *r_offset)
|
||||
{
|
||||
align<Layout>(type, array_size, r_offset);
|
||||
EXPECT_EQ(*r_offset, expected_alignment);
|
||||
reserve<Layout>(type, array_size, r_offset);
|
||||
EXPECT_EQ(*r_offset, expected_reserve);
|
||||
}
|
||||
|
||||
TEST(std140, fl)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
|
||||
def_attr<Std140>(shader::Type::FLOAT, 0, 0, 4, &offset);
|
||||
|
||||
align_end_of_struct<Std140>(&offset);
|
||||
EXPECT_EQ(offset, 16);
|
||||
}
|
||||
|
||||
TEST(std140, _2fl)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
|
||||
def_attr<Std140>(shader::Type::FLOAT, 0, 0, 4, &offset);
|
||||
def_attr<Std140>(shader::Type::FLOAT, 0, 4, 8, &offset);
|
||||
|
||||
align_end_of_struct<Std140>(&offset);
|
||||
EXPECT_EQ(offset, 16);
|
||||
}
|
||||
|
||||
TEST(std140, _3fl)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
|
||||
def_attr<Std140>(shader::Type::FLOAT, 0, 0, 4, &offset);
|
||||
def_attr<Std140>(shader::Type::FLOAT, 0, 4, 8, &offset);
|
||||
def_attr<Std140>(shader::Type::FLOAT, 0, 8, 12, &offset);
|
||||
|
||||
align_end_of_struct<Std140>(&offset);
|
||||
EXPECT_EQ(offset, 16);
|
||||
}
|
||||
|
||||
TEST(std140, _4fl)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
|
||||
def_attr<Std140>(shader::Type::FLOAT, 0, 0, 4, &offset);
|
||||
def_attr<Std140>(shader::Type::FLOAT, 0, 4, 8, &offset);
|
||||
def_attr<Std140>(shader::Type::FLOAT, 0, 8, 12, &offset);
|
||||
def_attr<Std140>(shader::Type::FLOAT, 0, 12, 16, &offset);
|
||||
|
||||
align_end_of_struct<Std140>(&offset);
|
||||
EXPECT_EQ(offset, 16);
|
||||
}
|
||||
|
||||
TEST(std140, fl2)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
|
||||
def_attr<Std140>(shader::Type::FLOAT, 2, 0, 32, &offset);
|
||||
|
||||
align_end_of_struct<Std140>(&offset);
|
||||
EXPECT_EQ(offset, 32);
|
||||
}
|
||||
|
||||
TEST(std140, fl_fl2)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
|
||||
def_attr<Std140>(shader::Type::FLOAT, 0, 0, 4, &offset);
|
||||
def_attr<Std140>(shader::Type::FLOAT, 2, 16, 48, &offset);
|
||||
|
||||
align_end_of_struct<Std140>(&offset);
|
||||
EXPECT_EQ(offset, 48);
|
||||
}
|
||||
|
||||
TEST(std140, fl_vec2)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
|
||||
def_attr<Std140>(shader::Type::FLOAT, 0, 0, 4, &offset);
|
||||
def_attr<Std140>(shader::Type::VEC2, 0, 8, 16, &offset);
|
||||
|
||||
align_end_of_struct<Std140>(&offset);
|
||||
EXPECT_EQ(offset, 16);
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -0,0 +1,16 @@
|
|||
void main()
|
||||
{
|
||||
data_out[0] = float_in;
|
||||
|
||||
data_out[1] = vec2_in.x;
|
||||
data_out[2] = vec2_in.y;
|
||||
|
||||
data_out[3] = vec3_in.x;
|
||||
data_out[4] = vec3_in.y;
|
||||
data_out[5] = vec3_in.z;
|
||||
|
||||
data_out[6] = vec4_in.x;
|
||||
data_out[7] = vec4_in.y;
|
||||
data_out[8] = vec4_in.z;
|
||||
data_out[9] = vec4_in.w;
|
||||
}
|
|
@ -67,6 +67,9 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_
|
|||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||
VKPipeline &pipeline = shader->pipeline_get();
|
||||
VKDescriptorSet &descriptor_set = pipeline.descriptor_set_get();
|
||||
VKPushConstants &push_constants = pipeline.push_constants_get();
|
||||
|
||||
push_constants.update(context);
|
||||
descriptor_set.update(context.device_get());
|
||||
command_buffer.bind(
|
||||
descriptor_set, shader->vk_pipeline_layout_get(), VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "vk_buffer.hh"
|
||||
#include "vk_context.hh"
|
||||
#include "vk_memory.hh"
|
||||
#include "vk_pipeline.hh"
|
||||
#include "vk_texture.hh"
|
||||
|
||||
#include "BLI_assert.h"
|
||||
|
@ -71,6 +72,20 @@ void VKCommandBuffer::bind(const VKDescriptorSet &descriptor_set,
|
|||
vk_command_buffer_, bind_point, vk_pipeline_layout, 0, 1, &vk_descriptor_set, 0, 0);
|
||||
}
|
||||
|
||||
void VKCommandBuffer::push_constants(const VKPushConstants &push_constants,
|
||||
const VkPipelineLayout vk_pipeline_layout,
|
||||
const VkShaderStageFlags vk_shader_stages)
|
||||
{
|
||||
BLI_assert(push_constants.layout_get().storage_type_get() ==
|
||||
VKPushConstants::StorageType::PUSH_CONSTANTS);
|
||||
vkCmdPushConstants(vk_command_buffer_,
|
||||
vk_pipeline_layout,
|
||||
vk_shader_stages,
|
||||
push_constants.offset(),
|
||||
push_constants.layout_get().size_in_bytes(),
|
||||
push_constants.data());
|
||||
}
|
||||
|
||||
void VKCommandBuffer::copy(VKBuffer &dst_buffer,
|
||||
VKTexture &src_texture,
|
||||
Span<VkBufferImageCopy> regions)
|
||||
|
|
|
@ -8,11 +8,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "vk_common.hh"
|
||||
#include "vk_pipeline.hh"
|
||||
|
||||
#include "BLI_utility_mixins.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKBuffer;
|
||||
class VKTexture;
|
||||
class VKPushConstants;
|
||||
class VKPipeline;
|
||||
class VKDescriptorSet;
|
||||
|
||||
/** Command buffer to keep track of the life-time of a command buffer. */
|
||||
class VKCommandBuffer : NonCopyable, NonMovable {
|
||||
|
@ -33,6 +37,14 @@ class VKCommandBuffer : NonCopyable, NonMovable {
|
|||
void bind(const VKDescriptorSet &descriptor_set,
|
||||
const VkPipelineLayout vk_pipeline_layout,
|
||||
VkPipelineBindPoint bind_point);
|
||||
/**
|
||||
* Add a push constant command to the command buffer.
|
||||
*
|
||||
* Only valid when the storage type of push_constants is StorageType::PUSH_CONSTANTS.
|
||||
*/
|
||||
void push_constants(const VKPushConstants &push_constants,
|
||||
const VkPipelineLayout vk_pipeline_layout,
|
||||
const VkShaderStageFlags vk_shader_stages);
|
||||
void dispatch(int groups_x_len, int groups_y_len, int groups_z_len);
|
||||
/** Copy the contents of a texture MIP level to the dst buffer. */
|
||||
void copy(VKBuffer &dst_buffer, VKTexture &src_texture, Span<VkBufferImageCopy> regions);
|
||||
|
|
|
@ -15,6 +15,15 @@
|
|||
#include "BLI_assert.h"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
VKDescriptorSet::VKDescriptorSet(VKDescriptorSet &&other)
|
||||
: vk_descriptor_pool_(other.vk_descriptor_pool_),
|
||||
vk_descriptor_set_(other.vk_descriptor_set_),
|
||||
bindings_(std::move(other.bindings_))
|
||||
{
|
||||
other.mark_freed();
|
||||
}
|
||||
|
||||
VKDescriptorSet::~VKDescriptorSet()
|
||||
{
|
||||
if (vk_descriptor_set_ != VK_NULL_HANDLE) {
|
||||
|
|
|
@ -111,6 +111,7 @@ class VKDescriptorSet : NonCopyable {
|
|||
: vk_descriptor_pool_(vk_descriptor_pool), vk_descriptor_set_(vk_descriptor_set)
|
||||
{
|
||||
}
|
||||
VKDescriptorSet(VKDescriptorSet &&other);
|
||||
virtual ~VKDescriptorSet();
|
||||
|
||||
VKDescriptorSet &operator=(VKDescriptorSet &&other)
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "vk_memory_layout.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
uint32_t Std430::component_mem_size(const shader::Type /*type*/)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
uint32_t Std430::element_alignment(const shader::Type type, const bool is_array)
|
||||
{
|
||||
if (is_array) {
|
||||
return 16;
|
||||
}
|
||||
switch (type) {
|
||||
case shader::Type::FLOAT:
|
||||
case shader::Type::UINT:
|
||||
case shader::Type::INT:
|
||||
case shader::Type::BOOL:
|
||||
return 4;
|
||||
case shader::Type::VEC2:
|
||||
case shader::Type::UVEC2:
|
||||
case shader::Type::IVEC2:
|
||||
return 8;
|
||||
case shader::Type::VEC3:
|
||||
case shader::Type::UVEC3:
|
||||
case shader::Type::IVEC3:
|
||||
case shader::Type::VEC4:
|
||||
case shader::Type::UVEC4:
|
||||
case shader::Type::IVEC4:
|
||||
case shader::Type::MAT3:
|
||||
case shader::Type::MAT4:
|
||||
return 16;
|
||||
default:
|
||||
BLI_assert_msg(false, "Type not supported in dynamic structs.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Std430::element_components_len(const shader::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case shader::Type::FLOAT:
|
||||
case shader::Type::UINT:
|
||||
case shader::Type::INT:
|
||||
case shader::Type::BOOL:
|
||||
return 1;
|
||||
case shader::Type::VEC2:
|
||||
case shader::Type::UVEC2:
|
||||
case shader::Type::IVEC2:
|
||||
return 2;
|
||||
case shader::Type::VEC3:
|
||||
case shader::Type::UVEC3:
|
||||
case shader::Type::IVEC3:
|
||||
case shader::Type::VEC4:
|
||||
case shader::Type::UVEC4:
|
||||
case shader::Type::IVEC4:
|
||||
return 4;
|
||||
case shader::Type::MAT3:
|
||||
return 12;
|
||||
case shader::Type::MAT4:
|
||||
return 16;
|
||||
default:
|
||||
BLI_assert_msg(false, "Type not supported in dynamic structs.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Std430::array_components_len(const shader::Type type)
|
||||
{
|
||||
return Std430::element_components_len(type);
|
||||
}
|
||||
|
||||
uint32_t Std140::component_mem_size(const shader::Type /*type*/)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
uint32_t Std140::element_alignment(const shader::Type type, const bool is_array)
|
||||
{
|
||||
if (is_array) {
|
||||
return 16;
|
||||
}
|
||||
switch (type) {
|
||||
case shader::Type::FLOAT:
|
||||
case shader::Type::UINT:
|
||||
case shader::Type::INT:
|
||||
case shader::Type::BOOL:
|
||||
return 4;
|
||||
case shader::Type::VEC2:
|
||||
case shader::Type::UVEC2:
|
||||
case shader::Type::IVEC2:
|
||||
return 8;
|
||||
case shader::Type::VEC3:
|
||||
case shader::Type::UVEC3:
|
||||
case shader::Type::IVEC3:
|
||||
case shader::Type::VEC4:
|
||||
case shader::Type::UVEC4:
|
||||
case shader::Type::IVEC4:
|
||||
case shader::Type::MAT3:
|
||||
case shader::Type::MAT4:
|
||||
return 16;
|
||||
default:
|
||||
BLI_assert_msg(false, "Type not supported in dynamic structs.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Std140::element_components_len(const shader::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case shader::Type::FLOAT:
|
||||
case shader::Type::UINT:
|
||||
case shader::Type::INT:
|
||||
case shader::Type::BOOL:
|
||||
return 1;
|
||||
case shader::Type::VEC2:
|
||||
case shader::Type::UVEC2:
|
||||
case shader::Type::IVEC2:
|
||||
return 2;
|
||||
case shader::Type::VEC3:
|
||||
case shader::Type::UVEC3:
|
||||
case shader::Type::IVEC3:
|
||||
case shader::Type::VEC4:
|
||||
case shader::Type::UVEC4:
|
||||
case shader::Type::IVEC4:
|
||||
return 4;
|
||||
case shader::Type::MAT3:
|
||||
return 12;
|
||||
case shader::Type::MAT4:
|
||||
return 16;
|
||||
default:
|
||||
BLI_assert_msg(false, "Type not supported in dynamic structs.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Std140::array_components_len(const shader::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case shader::Type::FLOAT:
|
||||
case shader::Type::UINT:
|
||||
case shader::Type::INT:
|
||||
case shader::Type::BOOL:
|
||||
case shader::Type::VEC2:
|
||||
case shader::Type::UVEC2:
|
||||
case shader::Type::IVEC2:
|
||||
case shader::Type::VEC3:
|
||||
case shader::Type::UVEC3:
|
||||
case shader::Type::IVEC3:
|
||||
case shader::Type::VEC4:
|
||||
case shader::Type::UVEC4:
|
||||
case shader::Type::IVEC4:
|
||||
return 4;
|
||||
case shader::Type::MAT3:
|
||||
return 12;
|
||||
case shader::Type::MAT4:
|
||||
return 16;
|
||||
default:
|
||||
BLI_assert_msg(false, "Type not supported in dynamic structs.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -0,0 +1,105 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
/**
|
||||
* Information about alignment/components and memory size for types when using std140 layout.
|
||||
*/
|
||||
struct Std140 {
|
||||
/** Get the memory size in bytes of a single component using by the given type.*/
|
||||
static uint32_t component_mem_size(const shader::Type type);
|
||||
/** Get to alignment of the given type in bytes.*/
|
||||
static uint32_t element_alignment(const shader::Type type, bool is_array);
|
||||
/** Get the number of components that should be allocated for the given type.*/
|
||||
static uint32_t element_components_len(const shader::Type type);
|
||||
/** Get the number of components of the given type when used in an array.*/
|
||||
static uint32_t array_components_len(const shader::Type type);
|
||||
};
|
||||
|
||||
/**
|
||||
* Information about alignment/components and memory size for types when using std430 layout.
|
||||
*/
|
||||
struct Std430 {
|
||||
/** Get the memory size in bytes of a single component using by the given type.*/
|
||||
static uint32_t component_mem_size(const shader::Type type);
|
||||
/** Get to alignment of the given type in bytes.*/
|
||||
static uint32_t element_alignment(const shader::Type type, bool is_array);
|
||||
/** Get the number of components that should be allocated for the given type.*/
|
||||
static uint32_t element_components_len(const shader::Type type);
|
||||
/** Get the number of components of the given type when used in an array.*/
|
||||
static uint32_t array_components_len(const shader::Type type);
|
||||
};
|
||||
|
||||
template<typename LayoutT> static uint32_t element_stride(const shader::Type type)
|
||||
{
|
||||
return LayoutT::element_components_len(type) * LayoutT::component_mem_size(type);
|
||||
}
|
||||
|
||||
template<typename LayoutT> static uint32_t array_stride(const shader::Type type)
|
||||
{
|
||||
return LayoutT::array_components_len(type) * LayoutT::component_mem_size(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the r_offset to the next alignment where the given type+array_size can be
|
||||
* reserved.
|
||||
*
|
||||
* 'type': The type that needs to be aligned.
|
||||
* 'array_size': The array_size that needs to be aligned. (0=no array).
|
||||
* 'r_offset': After the call it will point to the byte where the reservation
|
||||
* can happen.
|
||||
*/
|
||||
template<typename LayoutT>
|
||||
static void align(const shader::Type &type, const int32_t array_size, uint32_t *r_offset)
|
||||
{
|
||||
uint32_t alignment = LayoutT::element_alignment(type, array_size != 0);
|
||||
uint32_t alignment_mask = alignment - 1;
|
||||
uint32_t offset = *r_offset;
|
||||
if ((offset & alignment_mask) != 0) {
|
||||
offset &= ~alignment_mask;
|
||||
offset += alignment;
|
||||
*r_offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve space for the given type and array size.
|
||||
*
|
||||
* This function doesn't handle alignment this needs to be done up front by calling
|
||||
* 'align<Layout>' function. Caller is responsible for this.
|
||||
*
|
||||
* 'type': The type that needs to be reserved.
|
||||
* 'array_size': The array_size that needs to be reserved. (0=no array).
|
||||
* 'r_offset': When calling needs to be pointing to the aligned location where to
|
||||
* reserve space. After the call it will point to the byte just after reserved
|
||||
* space.
|
||||
*/
|
||||
template<typename LayoutT>
|
||||
static void reserve(const shader::Type type, int32_t array_size, uint32_t *r_offset)
|
||||
{
|
||||
uint32_t size = array_size == 0 ? element_stride<LayoutT>(type) :
|
||||
array_stride<LayoutT>(type) * array_size;
|
||||
*r_offset += size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update 'r_offset' to be aligned to the end of the struct.
|
||||
*
|
||||
* Call this function when all attributes have been added to make sure that the struct size is
|
||||
* correct.
|
||||
*/
|
||||
template<typename LayoutT> static void align_end_of_struct(uint32_t *r_offset)
|
||||
{
|
||||
align<LayoutT>(shader::Type::VEC4, 0, r_offset);
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -11,10 +11,13 @@
|
|||
|
||||
namespace blender::gpu {
|
||||
|
||||
VKPipeline::VKPipeline(VkPipeline vk_pipeline, VKDescriptorSet &&vk_descriptor_set)
|
||||
: vk_pipeline_(vk_pipeline)
|
||||
VKPipeline::VKPipeline(VkPipeline vk_pipeline,
|
||||
VKDescriptorSet &&descriptor_set,
|
||||
VKPushConstants &&push_constants)
|
||||
: vk_pipeline_(vk_pipeline),
|
||||
descriptor_set_(std::move(descriptor_set)),
|
||||
push_constants_(std::move(push_constants))
|
||||
{
|
||||
descriptor_set_ = std::move(vk_descriptor_set);
|
||||
}
|
||||
|
||||
VKPipeline::~VKPipeline()
|
||||
|
@ -26,10 +29,12 @@ VKPipeline::~VKPipeline()
|
|||
}
|
||||
}
|
||||
|
||||
VKPipeline VKPipeline::create_compute_pipeline(VKContext &context,
|
||||
VkShaderModule compute_module,
|
||||
VkDescriptorSetLayout &descriptor_set_layout,
|
||||
VkPipelineLayout &pipeline_layout)
|
||||
VKPipeline VKPipeline::create_compute_pipeline(
|
||||
VKContext &context,
|
||||
VkShaderModule compute_module,
|
||||
VkDescriptorSetLayout &descriptor_set_layout,
|
||||
VkPipelineLayout &pipeline_layout,
|
||||
const VKPushConstants::Layout &push_constants_layout)
|
||||
{
|
||||
VK_ALLOCATION_CALLBACKS
|
||||
VkDevice vk_device = context.device_get();
|
||||
|
@ -44,15 +49,16 @@ VKPipeline VKPipeline::create_compute_pipeline(VKContext &context,
|
|||
pipeline_info.layout = pipeline_layout;
|
||||
pipeline_info.stage.pName = "main";
|
||||
|
||||
VkPipeline pipeline;
|
||||
VkPipeline vk_pipeline;
|
||||
if (vkCreateComputePipelines(
|
||||
vk_device, nullptr, 1, &pipeline_info, vk_allocation_callbacks, &pipeline) !=
|
||||
vk_device, nullptr, 1, &pipeline_info, vk_allocation_callbacks, &vk_pipeline) !=
|
||||
VK_SUCCESS) {
|
||||
return VKPipeline();
|
||||
}
|
||||
|
||||
VKDescriptorSet descriptor_set = context.descriptor_pools_get().allocate(descriptor_set_layout);
|
||||
return VKPipeline(pipeline, std::move(descriptor_set));
|
||||
VKPushConstants push_constants(&push_constants_layout);
|
||||
return VKPipeline(vk_pipeline, std::move(descriptor_set), std::move(push_constants));
|
||||
}
|
||||
|
||||
VkPipeline VKPipeline::vk_handle() const
|
||||
|
|
|
@ -7,42 +7,55 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "BLI_utility_mixins.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "vk_common.hh"
|
||||
#include "vk_descriptor_set.hh"
|
||||
#include "vk_push_constants.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKContext;
|
||||
|
||||
class VKPipeline : NonCopyable {
|
||||
VKDescriptorSet descriptor_set_;
|
||||
VkPipeline vk_pipeline_ = VK_NULL_HANDLE;
|
||||
VKDescriptorSet descriptor_set_;
|
||||
VKPushConstants push_constants_;
|
||||
|
||||
public:
|
||||
VKPipeline() = default;
|
||||
|
||||
virtual ~VKPipeline();
|
||||
VKPipeline(VkPipeline vk_pipeline, VKDescriptorSet &&vk_descriptor_set);
|
||||
VKPipeline(VkPipeline vk_pipeline,
|
||||
VKDescriptorSet &&vk_descriptor_set,
|
||||
VKPushConstants &&push_constants);
|
||||
VKPipeline &operator=(VKPipeline &&other)
|
||||
{
|
||||
vk_pipeline_ = other.vk_pipeline_;
|
||||
other.vk_pipeline_ = VK_NULL_HANDLE;
|
||||
descriptor_set_ = std::move(other.descriptor_set_);
|
||||
push_constants_ = std::move(other.push_constants_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
static VKPipeline create_compute_pipeline(VKContext &context,
|
||||
VkShaderModule compute_module,
|
||||
VkDescriptorSetLayout &descriptor_set_layout,
|
||||
VkPipelineLayout &pipeline_layouts);
|
||||
VkPipelineLayout &pipeline_layouts,
|
||||
const VKPushConstants::Layout &push_constants_layout);
|
||||
|
||||
VKDescriptorSet &descriptor_set_get()
|
||||
{
|
||||
return descriptor_set_;
|
||||
}
|
||||
|
||||
VKPushConstants &push_constants_get()
|
||||
{
|
||||
return push_constants_;
|
||||
}
|
||||
|
||||
VkPipeline vk_handle() const;
|
||||
bool is_valid() const;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "vk_push_constants.hh"
|
||||
#include "vk_backend.hh"
|
||||
#include "vk_memory_layout.hh"
|
||||
#include "vk_shader.hh"
|
||||
#include "vk_shader_interface.hh"
|
||||
#include "vk_storage_buffer.hh"
|
||||
#include "vk_uniform_buffer.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
template<typename LayoutT>
|
||||
static VKPushConstants::Layout::PushConstant init_constant(
|
||||
const shader::ShaderCreateInfo::PushConst &push_constant,
|
||||
const ShaderInput &shader_input,
|
||||
uint32_t *r_offset)
|
||||
{
|
||||
align<LayoutT>(push_constant.type, push_constant.array_size, r_offset);
|
||||
|
||||
VKPushConstants::Layout::PushConstant layout;
|
||||
layout.location = shader_input.location;
|
||||
layout.type = push_constant.type;
|
||||
layout.array_size = push_constant.array_size;
|
||||
layout.offset = *r_offset;
|
||||
|
||||
reserve<LayoutT>(push_constant.type, push_constant.array_size, r_offset);
|
||||
return layout;
|
||||
}
|
||||
|
||||
template<typename LayoutT>
|
||||
uint32_t struct_size(Span<shader::ShaderCreateInfo::PushConst> push_constants)
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
for (const shader::ShaderCreateInfo::PushConst &push_constant : push_constants) {
|
||||
align<LayoutT>(push_constant.type, push_constant.array_size, &offset);
|
||||
reserve<LayoutT>(push_constant.type, push_constant.array_size, &offset);
|
||||
}
|
||||
|
||||
align_end_of_struct<LayoutT>(&offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
VKPushConstants::StorageType VKPushConstants::Layout::determine_storage_type(
|
||||
const shader::ShaderCreateInfo &info, const VkPhysicalDeviceLimits &vk_physical_device_limits)
|
||||
{
|
||||
if (info.push_constants_.is_empty()) {
|
||||
return StorageType::NONE;
|
||||
}
|
||||
|
||||
uint32_t size = struct_size<Std430>(info.push_constants_);
|
||||
return size <= vk_physical_device_limits.maxPushConstantsSize ? STORAGE_TYPE_DEFAULT :
|
||||
STORAGE_TYPE_FALLBACK;
|
||||
}
|
||||
|
||||
template<typename LayoutT>
|
||||
void init_struct(const shader::ShaderCreateInfo &info,
|
||||
const VKShaderInterface &interface,
|
||||
Vector<VKPushConstants::Layout::PushConstant> &r_struct,
|
||||
uint32_t *r_offset)
|
||||
{
|
||||
for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) {
|
||||
const ShaderInput *shader_input = interface.uniform_get(push_constant.name.c_str());
|
||||
r_struct.append(init_constant<LayoutT>(push_constant, *shader_input, r_offset));
|
||||
}
|
||||
align_end_of_struct<Std140>(r_offset);
|
||||
}
|
||||
|
||||
void VKPushConstants::Layout::init(const shader::ShaderCreateInfo &info,
|
||||
const VKShaderInterface &interface,
|
||||
const StorageType storage_type,
|
||||
const VKDescriptorSet::Location location)
|
||||
{
|
||||
BLI_assert(push_constants.is_empty());
|
||||
storage_type_ = storage_type;
|
||||
|
||||
size_in_bytes_ = 0;
|
||||
if (storage_type == StorageType::UNIFORM_BUFFER) {
|
||||
descriptor_set_location_ = location;
|
||||
init_struct<Std140>(info, interface, push_constants, &size_in_bytes_);
|
||||
}
|
||||
else {
|
||||
init_struct<Std430>(info, interface, push_constants, &size_in_bytes_);
|
||||
}
|
||||
}
|
||||
|
||||
const VKPushConstants::Layout::PushConstant *VKPushConstants::Layout::find(int32_t location) const
|
||||
{
|
||||
for (const PushConstant &push_constant : push_constants) {
|
||||
if (push_constant.location == location) {
|
||||
return &push_constant;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VKPushConstants::VKPushConstants() = default;
|
||||
VKPushConstants::VKPushConstants(const Layout *layout) : layout_(layout)
|
||||
{
|
||||
data_ = MEM_mallocN(layout->size_in_bytes(), __func__);
|
||||
switch (layout_->storage_type_get()) {
|
||||
case StorageType::UNIFORM_BUFFER:
|
||||
uniform_buffer_ = new VKUniformBuffer(layout_->size_in_bytes(), __func__);
|
||||
break;
|
||||
|
||||
case StorageType::PUSH_CONSTANTS:
|
||||
case StorageType::NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VKPushConstants::VKPushConstants(VKPushConstants &&other) : layout_(other.layout_)
|
||||
{
|
||||
data_ = other.data_;
|
||||
other.data_ = nullptr;
|
||||
|
||||
uniform_buffer_ = other.uniform_buffer_;
|
||||
other.uniform_buffer_ = nullptr;
|
||||
}
|
||||
|
||||
VKPushConstants::~VKPushConstants()
|
||||
{
|
||||
if (data_ != nullptr) {
|
||||
MEM_freeN(data_);
|
||||
data_ = nullptr;
|
||||
}
|
||||
|
||||
delete uniform_buffer_;
|
||||
uniform_buffer_ = nullptr;
|
||||
}
|
||||
|
||||
VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other)
|
||||
{
|
||||
layout_ = other.layout_;
|
||||
|
||||
data_ = other.data_;
|
||||
other.data_ = nullptr;
|
||||
|
||||
uniform_buffer_ = other.uniform_buffer_;
|
||||
other.uniform_buffer_ = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void VKPushConstants::update(VKContext &context)
|
||||
{
|
||||
VKShader *shader = static_cast<VKShader *>(context.shader);
|
||||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||
VKPipeline &pipeline = shader->pipeline_get();
|
||||
BLI_assert_msg(&pipeline.push_constants_get() == this,
|
||||
"Invalid state detected. Push constants doesn't belong to the active shader of "
|
||||
"the given context.");
|
||||
VKDescriptorSet &descriptor_set = pipeline.descriptor_set_get();
|
||||
|
||||
switch (layout_get().storage_type_get()) {
|
||||
case VKPushConstants::StorageType::NONE:
|
||||
break;
|
||||
|
||||
case VKPushConstants::StorageType::PUSH_CONSTANTS:
|
||||
command_buffer.push_constants(*this, shader->vk_pipeline_layout_get(), VK_SHADER_STAGE_ALL);
|
||||
break;
|
||||
|
||||
case VKPushConstants::StorageType::UNIFORM_BUFFER:
|
||||
update_uniform_buffer();
|
||||
descriptor_set.bind(uniform_buffer_get(), layout_get().descriptor_set_location_get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VKPushConstants::update_uniform_buffer()
|
||||
{
|
||||
BLI_assert(layout_->storage_type_get() == StorageType::UNIFORM_BUFFER);
|
||||
BLI_assert(uniform_buffer_ != nullptr);
|
||||
BLI_assert(data_ != nullptr);
|
||||
uniform_buffer_->update(data_);
|
||||
}
|
||||
|
||||
VKUniformBuffer &VKPushConstants::uniform_buffer_get()
|
||||
{
|
||||
BLI_assert(layout_->storage_type_get() == StorageType::UNIFORM_BUFFER);
|
||||
BLI_assert(uniform_buffer_ != nullptr);
|
||||
return *uniform_buffer_;
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -0,0 +1,249 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*
|
||||
* Push constants is a way to quickly provide a small amount of uniform data to shaders. It should
|
||||
* be much quicker than UBOs but a huge limitation is the size of data - spec requires 128 bytes to
|
||||
* be available for a push constant range. Hardware vendors may support more, but compared to other
|
||||
* means it is still very little (for example 256 bytes).
|
||||
*
|
||||
* Due to this size requirements we try to use push constants when it fits on the device. If it
|
||||
* doesn't fit we fallback to use an uniform buffer.
|
||||
*
|
||||
* Shader developers are responsible to fine-tune the performance of the shader. One way to do this
|
||||
* is to tailor what will be sent as a push constant to keep the push constants within the limits.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_utility_mixins.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
#include "vk_common.hh"
|
||||
#include "vk_descriptor_set.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKShaderInterface;
|
||||
class VKUniformBuffer;
|
||||
class VKContext;
|
||||
|
||||
/**
|
||||
* Container to store push constants in a buffer.
|
||||
*
|
||||
* Can handle buffers with different memory layouts (std140/std430)
|
||||
* Which memory layout is used is based on the storage type.
|
||||
*
|
||||
* VKPushConstantsLayout only describes the buffer, an instance of this
|
||||
* class can handle setting/modifying/duplicating push constants.
|
||||
*
|
||||
* It should also keep track of the submissions in order to reuse the allocated
|
||||
* data.
|
||||
*/
|
||||
class VKPushConstants : NonCopyable {
|
||||
public:
|
||||
/** Different methods to store push constants.*/
|
||||
enum class StorageType {
|
||||
/** Push constants aren't in use.*/
|
||||
NONE,
|
||||
|
||||
/** Store push constants as regular vulkan push constants.*/
|
||||
PUSH_CONSTANTS,
|
||||
|
||||
/**
|
||||
* Fallback when push constants doesn't meet the device requirements.
|
||||
*/
|
||||
UNIFORM_BUFFER,
|
||||
};
|
||||
|
||||
/**
|
||||
* Describe the layout of the push constants and the storage type that should be used.
|
||||
*/
|
||||
struct Layout {
|
||||
static constexpr StorageType STORAGE_TYPE_DEFAULT = StorageType::PUSH_CONSTANTS;
|
||||
static constexpr StorageType STORAGE_TYPE_FALLBACK = StorageType::UNIFORM_BUFFER;
|
||||
|
||||
struct PushConstant {
|
||||
/* Used as lookup based on ShaderInput.*/
|
||||
int32_t location;
|
||||
|
||||
/** Offset in the push constant data (in bytes). */
|
||||
uint32_t offset;
|
||||
shader::Type type;
|
||||
int array_size;
|
||||
};
|
||||
|
||||
private:
|
||||
Vector<PushConstant> push_constants;
|
||||
uint32_t size_in_bytes_ = 0;
|
||||
StorageType storage_type_ = StorageType::NONE;
|
||||
/**
|
||||
* Binding index in the descriptor set when the push constants use an uniform buffer.
|
||||
*/
|
||||
VKDescriptorSet::Location descriptor_set_location_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Return the desired storage type that can fit the push constants of the given shader create
|
||||
* info, matching the device limits.
|
||||
*
|
||||
* Returns:
|
||||
* - StorageType::NONE: No push constants are needed.
|
||||
* - StorageType::PUSH_CONSTANTS: Regular vulkan push constants can be used.
|
||||
* - StorageType::UNIFORM_BUFFER: The push constants don't fit in the limits of the given
|
||||
* device. A uniform buffer should be used as a fallback method.
|
||||
*/
|
||||
static StorageType determine_storage_type(
|
||||
const shader::ShaderCreateInfo &info,
|
||||
const VkPhysicalDeviceLimits &vk_physical_device_limits);
|
||||
|
||||
/**
|
||||
* Initialize the push constants of the given shader create info with the
|
||||
* binding location.
|
||||
*
|
||||
* interface: Uniform locations of the interface are used as lookup key.
|
||||
* storage_type: The type of storage for push constants to use.
|
||||
* location: When storage_type=StorageType::UNIFORM_BUFFER this contains
|
||||
* the location in the descriptor set where the uniform buffer can be
|
||||
* bound.
|
||||
*/
|
||||
void init(const shader::ShaderCreateInfo &info,
|
||||
const VKShaderInterface &interface,
|
||||
StorageType storage_type,
|
||||
VKDescriptorSet::Location location);
|
||||
|
||||
/**
|
||||
* Return the storage type that is used.
|
||||
*/
|
||||
StorageType storage_type_get() const
|
||||
{
|
||||
return storage_type_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the binding location for the uniform buffer.
|
||||
*
|
||||
* Only valid when storage_type=StorageType::UNIFORM_BUFFER.
|
||||
*/
|
||||
VKDescriptorSet::Location descriptor_set_location_get() const
|
||||
{
|
||||
return descriptor_set_location_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size needed to store the push constants.
|
||||
*/
|
||||
uint32_t size_in_bytes() const
|
||||
{
|
||||
return size_in_bytes_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the push constant layout for the given location.
|
||||
* Location = ShaderInput.location.
|
||||
*/
|
||||
const PushConstant *find(int32_t location) const;
|
||||
};
|
||||
|
||||
private:
|
||||
const Layout *layout_ = nullptr;
|
||||
void *data_ = nullptr;
|
||||
VKUniformBuffer *uniform_buffer_ = nullptr;
|
||||
|
||||
public:
|
||||
VKPushConstants();
|
||||
VKPushConstants(const Layout *layout);
|
||||
VKPushConstants(VKPushConstants &&other);
|
||||
virtual ~VKPushConstants();
|
||||
|
||||
VKPushConstants &operator=(VKPushConstants &&other);
|
||||
|
||||
size_t offset() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Layout &layout_get() const
|
||||
{
|
||||
return *layout_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reference to the active data.
|
||||
*
|
||||
* Data can get inactive when push constants are modified, after being added to the command
|
||||
* queue. We still keep track of the old data for reuse and make sure we don't overwrite data
|
||||
* that is still not on the GPU.
|
||||
*/
|
||||
const void *data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify a push constant.
|
||||
*
|
||||
* location: ShaderInput.location of the push constant to update.
|
||||
* comp_len: number of components has the data type that is being updated.
|
||||
* array_size: number of elements when an array to update. (0=no array)
|
||||
* input_data: packed source data to use.
|
||||
*/
|
||||
template<typename T>
|
||||
void push_constant_set(int32_t location,
|
||||
int32_t comp_len,
|
||||
int32_t array_size,
|
||||
const T *input_data)
|
||||
{
|
||||
const Layout::PushConstant *push_constant_layout = layout_->find(location);
|
||||
BLI_assert(push_constant_layout);
|
||||
|
||||
uint8_t *bytes = static_cast<uint8_t *>(data_);
|
||||
T *dst = static_cast<T *>(static_cast<void *>(&bytes[push_constant_layout->offset]));
|
||||
const bool is_tightly_std140_packed = (comp_len % 4) == 0;
|
||||
if (layout_->storage_type_get() == StorageType::PUSH_CONSTANTS || array_size == 0 ||
|
||||
is_tightly_std140_packed) {
|
||||
BLI_assert_msg(push_constant_layout->offset + comp_len * array_size * sizeof(T) <=
|
||||
layout_->size_in_bytes(),
|
||||
"Tried to write outside the push constant allocated memory.");
|
||||
memcpy(dst, input_data, comp_len * array_size * sizeof(T));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store elements in uniform buffer as array. In Std140 arrays have an element stride of 16
|
||||
* bytes.*/
|
||||
BLI_assert(sizeof(T) == 4);
|
||||
const T *src = input_data;
|
||||
for (const int i : IndexRange(array_size)) {
|
||||
UNUSED_VARS(i);
|
||||
memcpy(dst, src, comp_len * sizeof(T));
|
||||
src += comp_len;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the GPU resources with the latest push constants.
|
||||
*/
|
||||
void update(VKContext &context);
|
||||
|
||||
private:
|
||||
/**
|
||||
* When storage type = StorageType::UNIFORM_BUFFER use this method to update the uniform
|
||||
* buffer.
|
||||
*
|
||||
* It must be called just before adding a draw/compute command to the command queue.
|
||||
*/
|
||||
void update_uniform_buffer();
|
||||
|
||||
/**
|
||||
* Get a reference to the uniform buffer.
|
||||
*
|
||||
* Only valid when storage type = StorageType::UNIFORM_BUFFER.
|
||||
*/
|
||||
VKUniformBuffer &uniform_buffer_get();
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -676,7 +676,7 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info)
|
|||
if (!finalize_descriptor_set_layouts(vk_device, *vk_interface, *info)) {
|
||||
return false;
|
||||
}
|
||||
if (!finalize_pipeline_layout(vk_device, *info)) {
|
||||
if (!finalize_pipeline_layout(vk_device, *vk_interface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -695,7 +695,11 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info)
|
|||
BLI_assert(fragment_module_ == VK_NULL_HANDLE);
|
||||
BLI_assert(compute_module_ != VK_NULL_HANDLE);
|
||||
compute_pipeline_ = VKPipeline::create_compute_pipeline(
|
||||
*context_, compute_module_, layout_, pipeline_layout_);
|
||||
*context_,
|
||||
compute_module_,
|
||||
layout_,
|
||||
pipeline_layout_,
|
||||
vk_interface->push_constants_layout_get());
|
||||
result = compute_pipeline_.is_valid();
|
||||
}
|
||||
|
||||
|
@ -739,17 +743,29 @@ bool VKShader::finalize_graphics_pipeline(VkDevice /*vk_device */)
|
|||
}
|
||||
|
||||
bool VKShader::finalize_pipeline_layout(VkDevice vk_device,
|
||||
const shader::ShaderCreateInfo & /*info*/)
|
||||
const VKShaderInterface &shader_interface)
|
||||
{
|
||||
VK_ALLOCATION_CALLBACKS
|
||||
|
||||
const uint32_t layout_count = layout_ == VK_NULL_HANDLE ? 0 : 1;
|
||||
VkPipelineLayoutCreateInfo pipeline_info = {};
|
||||
VkPushConstantRange push_constant_range = {};
|
||||
pipeline_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipeline_info.flags = 0;
|
||||
pipeline_info.setLayoutCount = layout_count;
|
||||
pipeline_info.pSetLayouts = &layout_;
|
||||
|
||||
/* Setup push constants. */
|
||||
const VKPushConstants::Layout &push_constants_layout =
|
||||
shader_interface.push_constants_layout_get();
|
||||
if (push_constants_layout.storage_type_get() == VKPushConstants::StorageType::PUSH_CONSTANTS) {
|
||||
push_constant_range.offset = 0;
|
||||
push_constant_range.size = push_constants_layout.size_in_bytes();
|
||||
push_constant_range.stageFlags = VK_SHADER_STAGE_ALL;
|
||||
pipeline_info.pushConstantRangeCount = 1;
|
||||
pipeline_info.pPushConstantRanges = &push_constant_range;
|
||||
}
|
||||
|
||||
if (vkCreatePipelineLayout(
|
||||
vk_device, &pipeline_info, vk_allocation_callbacks, &pipeline_layout_) != VK_SUCCESS) {
|
||||
return false;
|
||||
|
@ -868,6 +884,21 @@ static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding(
|
|||
return binding;
|
||||
}
|
||||
|
||||
static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding(
|
||||
const VKPushConstants::Layout &push_constants_layout)
|
||||
{
|
||||
BLI_assert(push_constants_layout.storage_type_get() ==
|
||||
VKPushConstants::StorageType::UNIFORM_BUFFER);
|
||||
VkDescriptorSetLayoutBinding binding = {};
|
||||
binding.binding = push_constants_layout.descriptor_set_location_get();
|
||||
binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
binding.descriptorCount = 1;
|
||||
binding.stageFlags = VK_SHADER_STAGE_ALL;
|
||||
binding.pImmutableSamplers = nullptr;
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
static void add_descriptor_set_layout_bindings(
|
||||
const VKShaderInterface &interface,
|
||||
const Vector<shader::ShaderCreateInfo::Resource> &resources,
|
||||
|
@ -877,6 +908,12 @@ static void add_descriptor_set_layout_bindings(
|
|||
const VKDescriptorSet::Location location = interface.descriptor_set_location(resource);
|
||||
r_bindings.append(create_descriptor_set_layout_binding(location, resource));
|
||||
}
|
||||
|
||||
/* Add push constants to the descriptor when push constants are stored in an uniform buffer.*/
|
||||
const VKPushConstants::Layout &push_constants_layout = interface.push_constants_layout_get();
|
||||
if (push_constants_layout.storage_type_get() == VKPushConstants::StorageType::UNIFORM_BUFFER) {
|
||||
r_bindings.append(create_descriptor_set_layout_binding(push_constants_layout));
|
||||
}
|
||||
}
|
||||
|
||||
static VkDescriptorSetLayoutCreateInfo create_descriptor_set_layout(
|
||||
|
@ -894,11 +931,19 @@ static VkDescriptorSetLayoutCreateInfo create_descriptor_set_layout(
|
|||
return set_info;
|
||||
}
|
||||
|
||||
static bool descriptor_sets_needed(const VKShaderInterface &shader_interface,
|
||||
const shader::ShaderCreateInfo &info)
|
||||
{
|
||||
return !info.pass_resources_.is_empty() || !info.batch_resources_.is_empty() ||
|
||||
shader_interface.push_constants_layout_get().storage_type_get() ==
|
||||
VKPushConstants::StorageType::UNIFORM_BUFFER;
|
||||
}
|
||||
|
||||
bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device,
|
||||
const VKShaderInterface &shader_interface,
|
||||
const shader::ShaderCreateInfo &info)
|
||||
{
|
||||
if (info.pass_resources_.is_empty() && info.batch_resources_.is_empty()) {
|
||||
if (!descriptor_sets_needed(shader_interface, info)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -958,17 +1003,14 @@ void VKShader::unbind()
|
|||
}
|
||||
}
|
||||
|
||||
void VKShader::uniform_float(int /*location*/,
|
||||
int /*comp_len*/,
|
||||
int /*array_size*/,
|
||||
const float * /*data*/)
|
||||
void VKShader::uniform_float(int location, int comp_len, int array_size, const float *data)
|
||||
{
|
||||
pipeline_get().push_constants_get().push_constant_set(location, comp_len, array_size, data);
|
||||
}
|
||||
void VKShader::uniform_int(int /*location*/,
|
||||
int /*comp_len*/,
|
||||
int /*array_size*/,
|
||||
const int * /*data*/)
|
||||
|
||||
void VKShader::uniform_int(int location, int comp_len, int array_size, const int *data)
|
||||
{
|
||||
pipeline_get().push_constants_get().push_constant_set(location, comp_len, array_size, data);
|
||||
}
|
||||
|
||||
std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) const
|
||||
|
@ -993,9 +1035,19 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co
|
|||
print_resource_alias(ss, res);
|
||||
}
|
||||
|
||||
if (!info.push_constants_.is_empty()) {
|
||||
/* Push constants. */
|
||||
const VKPushConstants::Layout &push_constants_layout = interface.push_constants_layout_get();
|
||||
const VKPushConstants::StorageType push_constants_storage =
|
||||
push_constants_layout.storage_type_get();
|
||||
if (push_constants_storage != VKPushConstants::StorageType::NONE) {
|
||||
ss << "\n/* Push Constants. */\n";
|
||||
ss << "layout(push_constant) uniform constants\n";
|
||||
if (push_constants_storage == VKPushConstants::StorageType::PUSH_CONSTANTS) {
|
||||
ss << "layout(push_constant) uniform constants\n";
|
||||
}
|
||||
else if (push_constants_storage == VKPushConstants::StorageType::UNIFORM_BUFFER) {
|
||||
ss << "layout(binding = " << push_constants_layout.descriptor_set_location_get()
|
||||
<< ", std140) uniform constants\n";
|
||||
}
|
||||
ss << "{\n";
|
||||
for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) {
|
||||
ss << " " << to_string(uniform.type) << " pc_" << uniform.name;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "vk_backend.hh"
|
||||
#include "vk_context.hh"
|
||||
#include "vk_pipeline.hh"
|
||||
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
|
@ -78,7 +79,7 @@ class VKShader : public Shader {
|
|||
bool finalize_descriptor_set_layouts(VkDevice vk_device,
|
||||
const VKShaderInterface &shader_interface,
|
||||
const shader::ShaderCreateInfo &info);
|
||||
bool finalize_pipeline_layout(VkDevice vk_device, const shader::ShaderCreateInfo &info);
|
||||
bool finalize_pipeline_layout(VkDevice vk_device, const VKShaderInterface &shader_interface);
|
||||
bool finalize_graphics_pipeline(VkDevice vk_device);
|
||||
|
||||
bool is_graphics_shader() const
|
||||
|
|
|
@ -6,15 +6,19 @@
|
|||
*/
|
||||
|
||||
#include "vk_shader_interface.hh"
|
||||
#include "vk_context.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
|
||||
{
|
||||
static char PUSH_CONSTANTS_FALLBACK_NAME[] = "push_constants_fallback";
|
||||
static size_t PUSH_CONSTANTS_FALLBACK_NAME_LEN = strlen(PUSH_CONSTANTS_FALLBACK_NAME);
|
||||
|
||||
using namespace blender::gpu::shader;
|
||||
|
||||
attr_len_ = 0;
|
||||
uniform_len_ = 0;
|
||||
uniform_len_ = info.push_constants_.size();
|
||||
ssbo_len_ = 0;
|
||||
ubo_len_ = 0;
|
||||
image_offset_ = -1;
|
||||
|
@ -40,6 +44,17 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reserve 1 uniform buffer for push constants fallback. */
|
||||
size_t names_size = info.interface_names_size_;
|
||||
VKContext &context = *VKContext::get();
|
||||
const VKPushConstants::StorageType push_constants_storage_type =
|
||||
VKPushConstants::Layout::determine_storage_type(info, context.physical_device_limits_get());
|
||||
if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) {
|
||||
ubo_len_++;
|
||||
names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1;
|
||||
}
|
||||
|
||||
/* Make sure that the image slots don't overlap with the sampler slots. */
|
||||
image_offset_++;
|
||||
|
||||
|
@ -48,7 +63,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
|
|||
MEM_calloc_arrayN(input_tot_len, sizeof(ShaderInput), __func__));
|
||||
ShaderInput *input = inputs_;
|
||||
|
||||
name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_, "name_buffer");
|
||||
name_buffer_ = (char *)MEM_mallocN(names_size, "name_buffer");
|
||||
uint32_t name_buffer_offset = 0;
|
||||
|
||||
/* Uniform blocks */
|
||||
|
@ -59,6 +74,13 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
|
|||
input++;
|
||||
}
|
||||
}
|
||||
/* Add push constant when using uniform buffer as fallback. */
|
||||
int32_t push_constants_fallback_location = -1;
|
||||
if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) {
|
||||
copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset);
|
||||
input->location = input->binding = -1;
|
||||
input++;
|
||||
}
|
||||
|
||||
/* Images, Samplers and buffers. */
|
||||
for (const ShaderCreateInfo::Resource &res : all_resources) {
|
||||
|
@ -74,6 +96,15 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
|
|||
}
|
||||
}
|
||||
|
||||
/* Push constants. */
|
||||
int32_t push_constant_location = 1024;
|
||||
for (const ShaderCreateInfo::PushConst &push_constant : info.push_constants_) {
|
||||
copy_input_name(input, push_constant.name, name_buffer_, name_buffer_offset);
|
||||
input->location = push_constant_location++;
|
||||
input->binding = -1;
|
||||
input++;
|
||||
}
|
||||
|
||||
/* Storage buffers */
|
||||
for (const ShaderCreateInfo::Resource &res : all_resources) {
|
||||
if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) {
|
||||
|
@ -106,6 +137,17 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
|
|||
const ShaderInput *input = shader_input_get(res);
|
||||
descriptor_set_location_update(input, descriptor_set_location++);
|
||||
}
|
||||
|
||||
/* Post initializing push constants.*/
|
||||
/* Determine the binding location of push constants fallback buffer.*/
|
||||
int32_t push_constant_descriptor_set_location = -1;
|
||||
if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) {
|
||||
push_constant_descriptor_set_location = descriptor_set_location++;
|
||||
const ShaderInput *push_constant_input = ubo_get(PUSH_CONSTANTS_FALLBACK_NAME);
|
||||
descriptor_set_location_update(push_constant_input, push_constants_fallback_location);
|
||||
}
|
||||
push_constants_layout_.init(
|
||||
info, *this, push_constants_storage_type, push_constant_descriptor_set_location);
|
||||
}
|
||||
|
||||
static int32_t shader_input_index(const ShaderInput *shader_inputs,
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
#include "gpu_shader_create_info.hh"
|
||||
#include "gpu_shader_interface.hh"
|
||||
|
||||
#include "vk_descriptor_set.hh"
|
||||
#include "BLI_array.hh"
|
||||
|
||||
#include "vk_push_constants.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKShaderInterface : public ShaderInterface {
|
||||
|
@ -27,6 +29,8 @@ class VKShaderInterface : public ShaderInterface {
|
|||
uint32_t image_offset_ = 0;
|
||||
Array<VKDescriptorSet::Location> descriptor_set_locations_;
|
||||
|
||||
VKPushConstants::Layout push_constants_layout_;
|
||||
|
||||
public:
|
||||
VKShaderInterface() = default;
|
||||
|
||||
|
@ -37,6 +41,12 @@ class VKShaderInterface : public ShaderInterface {
|
|||
const VKDescriptorSet::Location descriptor_set_location(
|
||||
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const;
|
||||
|
||||
/** Get the Layout of the shader.*/
|
||||
const VKPushConstants::Layout &push_constants_layout_get() const
|
||||
{
|
||||
return push_constants_layout_;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Retrieve the shader input for the given resource.
|
||||
|
|
|
@ -23,10 +23,10 @@ namespace blender::io::ply {
|
|||
std::unique_ptr<PlyData> import_ply_ascii(fstream &file, PlyHeader *header);
|
||||
|
||||
/**
|
||||
* Loads the information from the PLY file in ASCII format to the PlyData datastructure.
|
||||
* Loads the information from the PLY file in ASCII format to the #PlyData data-structure.
|
||||
* \param file: The PLY file that was opened.
|
||||
* \param header: The information in the PLY header.
|
||||
* \return The PlyData datastructure that can be used for conversion to a Mesh.
|
||||
* \return The #PlyData data-structure that can be used for conversion to a Mesh.
|
||||
*/
|
||||
PlyData load_ply_ascii(fstream &file, const PlyHeader *header);
|
||||
|
||||
|
|
|
@ -17,15 +17,15 @@ namespace blender::io::ply {
|
|||
* The function that gets called from the importer.
|
||||
* \param file: The PLY file that was opened.
|
||||
* \param header: The information in the PLY header.
|
||||
* \return The PlyData datastructure that can be used for conversion to a Mesh.
|
||||
* \return The #PlyData data-structure that can be used for conversion to a #Mesh.
|
||||
*/
|
||||
std::unique_ptr<PlyData> import_ply_binary(fstream &file, const PlyHeader *header);
|
||||
|
||||
/**
|
||||
* Loads the information from the PLY file in binary format to the PlyData datastructure.
|
||||
* Loads the information from the PLY file in binary format to the #PlyData data-structure.
|
||||
* \param file: The PLY file that was opened.
|
||||
* \param header: The information in the PLY header.
|
||||
* \return The PlyData datastructure that can be used for conversion to a Mesh.
|
||||
* \return The #PlyData data-structure that can be used for conversion to a Mesh.
|
||||
*/
|
||||
PlyData load_ply_binary(fstream &file, const PlyHeader *header);
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
namespace blender::io::ply {
|
||||
|
||||
/**
|
||||
* Converts the PlyData datastructure to a mesh.
|
||||
* Converts the #PlyData data-structure to a mesh.
|
||||
* \param data: The PLY data.
|
||||
* \return The mesh that can be used inside blender.
|
||||
*/
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "testing/testing.h"
|
||||
#include "tests/blendfile_loading_base_test.h"
|
||||
|
||||
#include "BKE_appdir.h"
|
||||
#include "BKE_blender_version.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
@ -31,6 +32,26 @@ class PlyExportTest : public BlendfileLoadingBaseTest {
|
|||
depsgraph_create(eval_mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
BlendfileLoadingBaseTest::SetUp();
|
||||
|
||||
BKE_tempdir_init("");
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
BlendfileLoadingBaseTest::TearDown();
|
||||
|
||||
BKE_tempdir_session_purge();
|
||||
}
|
||||
|
||||
std::string get_temp_ply_filename(const std::string &filename)
|
||||
{
|
||||
return std::string(BKE_tempdir_session()) + "/" + filename;
|
||||
}
|
||||
};
|
||||
|
||||
static std::unique_ptr<PlyData> load_cube(PLYExportParams ¶ms)
|
||||
|
@ -103,7 +124,7 @@ static std::vector<char> read_temp_file_in_vectorchar(const std::string &file_pa
|
|||
|
||||
TEST_F(PlyExportTest, WriteHeaderAscii)
|
||||
{
|
||||
std::string filePath = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
|
||||
std::string filePath = get_temp_ply_filename(temp_file_path);
|
||||
PLYExportParams _params;
|
||||
_params.ascii_format = true;
|
||||
_params.export_normals = false;
|
||||
|
@ -141,7 +162,7 @@ TEST_F(PlyExportTest, WriteHeaderAscii)
|
|||
|
||||
TEST_F(PlyExportTest, WriteHeaderBinary)
|
||||
{
|
||||
std::string filePath = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
|
||||
std::string filePath = get_temp_ply_filename(temp_file_path);
|
||||
PLYExportParams _params;
|
||||
_params.ascii_format = false;
|
||||
_params.export_normals = false;
|
||||
|
@ -179,7 +200,7 @@ TEST_F(PlyExportTest, WriteHeaderBinary)
|
|||
|
||||
TEST_F(PlyExportTest, WriteVerticesAscii)
|
||||
{
|
||||
std::string filePath = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
|
||||
std::string filePath = get_temp_ply_filename(temp_file_path);
|
||||
PLYExportParams _params;
|
||||
_params.ascii_format = true;
|
||||
_params.export_normals = false;
|
||||
|
@ -211,7 +232,7 @@ TEST_F(PlyExportTest, WriteVerticesAscii)
|
|||
|
||||
TEST_F(PlyExportTest, WriteVerticesBinary)
|
||||
{
|
||||
std::string filePath = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
|
||||
std::string filePath = get_temp_ply_filename(temp_file_path);
|
||||
PLYExportParams _params;
|
||||
_params.ascii_format = false;
|
||||
_params.export_normals = false;
|
||||
|
@ -253,7 +274,7 @@ TEST_F(PlyExportTest, WriteVerticesBinary)
|
|||
|
||||
TEST_F(PlyExportTest, WriteFacesAscii)
|
||||
{
|
||||
std::string filePath = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
|
||||
std::string filePath = get_temp_ply_filename(temp_file_path);
|
||||
PLYExportParams _params;
|
||||
_params.ascii_format = true;
|
||||
_params.export_normals = false;
|
||||
|
@ -283,7 +304,7 @@ TEST_F(PlyExportTest, WriteFacesAscii)
|
|||
|
||||
TEST_F(PlyExportTest, WriteFacesBinary)
|
||||
{
|
||||
std::string filePath = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
|
||||
std::string filePath = get_temp_ply_filename(temp_file_path);
|
||||
PLYExportParams _params;
|
||||
_params.ascii_format = false;
|
||||
_params.export_normals = false;
|
||||
|
@ -326,7 +347,7 @@ TEST_F(PlyExportTest, WriteFacesBinary)
|
|||
|
||||
TEST_F(PlyExportTest, WriteVertexNormalsAscii)
|
||||
{
|
||||
std::string filePath = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
|
||||
std::string filePath = get_temp_ply_filename(temp_file_path);
|
||||
PLYExportParams _params;
|
||||
_params.ascii_format = true;
|
||||
_params.export_normals = true;
|
||||
|
@ -358,7 +379,7 @@ TEST_F(PlyExportTest, WriteVertexNormalsAscii)
|
|||
|
||||
TEST_F(PlyExportTest, WriteVertexNormalsBinary)
|
||||
{
|
||||
std::string filePath = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
|
||||
std::string filePath = get_temp_ply_filename(temp_file_path);
|
||||
PLYExportParams _params;
|
||||
_params.ascii_format = false;
|
||||
_params.export_normals = true;
|
||||
|
|
|
@ -322,6 +322,13 @@ typedef struct DriverTarget {
|
|||
short flag;
|
||||
/** Type of ID-block that this target can use. */
|
||||
int idtype;
|
||||
|
||||
/* Context-dependent property of a "Context Property" type target.
|
||||
* The `rna_path` of this property is used as a target.
|
||||
* This is a value of enumerator #eDriverTarget_ContextProperty. */
|
||||
int context_property;
|
||||
|
||||
int _pad1;
|
||||
} DriverTarget;
|
||||
|
||||
/** Driver Target flags. */
|
||||
|
@ -386,6 +393,11 @@ typedef enum eDriverTarget_RotationMode {
|
|||
DTAR_ROTMODE_EULER_MAX = DTAR_ROTMODE_EULER_ZYX,
|
||||
} eDriverTarget_RotationMode;
|
||||
|
||||
typedef enum eDriverTarget_ContextProperty {
|
||||
DTAR_CONTEXT_PROPERTY_ACTIVE_SCENE = 0,
|
||||
DTAR_CONTEXT_PROPERTY_ACTIVE_VIEW_LAYER = 1,
|
||||
} eDriverTarget_ContextProperty;
|
||||
|
||||
/* --- */
|
||||
|
||||
/* maximum number of driver targets per variable */
|
||||
|
@ -432,6 +444,8 @@ typedef enum eDriverVar_Types {
|
|||
DVAR_TYPE_LOC_DIFF,
|
||||
/** 'final' transform for object/bones */
|
||||
DVAR_TYPE_TRANSFORM_CHAN,
|
||||
/** Property within a current evaluation context */
|
||||
DVAR_TYPE_CONTEXT_PROP,
|
||||
|
||||
/**
|
||||
* Maximum number of variable types.
|
||||
|
|
|
@ -243,7 +243,7 @@ typedef struct bArmatureConstraint {
|
|||
ListBase targets;
|
||||
} bArmatureConstraint;
|
||||
|
||||
/* Single-target subobject constraints --------------------- */
|
||||
/* Single-target sub-object constraints --------------------- */
|
||||
|
||||
/* Track To Constraint */
|
||||
typedef struct bTrackToConstraint {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
.pathlen = 100, \
|
||||
.resolu = 12, \
|
||||
.resolv = 12, \
|
||||
.offset = 1.0, \
|
||||
.offset = 0.0, \
|
||||
.wordspace = 1.0, \
|
||||
.spacing = 1.0f, \
|
||||
.linedist = 1.0, \
|
||||
|
|
|
@ -330,7 +330,11 @@ typedef struct bNode {
|
|||
int16_t custom1, custom2;
|
||||
float custom3, custom4;
|
||||
|
||||
/** Optional link to libdata. */
|
||||
/**
|
||||
* Optional link to libdata.
|
||||
*
|
||||
* \see #bNodeType::initfunc & #bNodeType::freefunc for details on ID user-count.
|
||||
*/
|
||||
struct ID *id;
|
||||
|
||||
/** Custom data struct for node properties for storage in files. */
|
||||
|
|
|
@ -552,6 +552,7 @@ enum {
|
|||
V3D_OVERLAY_SCULPT_SHOW_MASK = (1 << 14),
|
||||
V3D_OVERLAY_SCULPT_SHOW_FACE_SETS = (1 << 15),
|
||||
V3D_OVERLAY_SCULPT_CURVES_CAGE = (1 << 16),
|
||||
V3D_OVERLAY_SHOW_LIGHT_COLORS = (1 << 17),
|
||||
};
|
||||
|
||||
/** #View3DOverlay.edit_flag */
|
||||
|
|
|
@ -2556,6 +2556,8 @@ static void rna_def_brush(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "curve_preset", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, brush_curve_preset_items);
|
||||
RNA_def_property_ui_text(prop, "Curve Preset", "");
|
||||
RNA_def_property_translation_context(prop,
|
||||
BLT_I18NCONTEXT_ID_CURVES); /* Abusing id_curves :/ */
|
||||
RNA_def_property_update(prop, 0, "rna_Brush_update");
|
||||
|
||||
prop = RNA_def_property(srna, "deform_target", PROP_ENUM, PROP_NONE);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
@ -364,6 +366,7 @@ static void rna_def_cachefile(BlenderRNA *brna)
|
|||
"Velocity Unit",
|
||||
"Define how the velocity vectors are interpreted with regard to time, 'frame' means "
|
||||
"the delta time is 1 frame, 'second' means the delta time is 1 / FPS");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UNIT);
|
||||
RNA_def_property_update(prop, 0, "rna_CacheFile_update");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
|
||||
|
|
|
@ -161,6 +161,20 @@ const EnumPropertyItem rna_enum_driver_target_rotation_mode_items[] = {
|
|||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
const EnumPropertyItem rna_enum_driver_target_context_property_items[] = {
|
||||
{DTAR_CONTEXT_PROPERTY_ACTIVE_SCENE,
|
||||
"ACTIVE_SCENE",
|
||||
ICON_NONE,
|
||||
"Active Scene",
|
||||
"Currently evaluating scene"},
|
||||
{DTAR_CONTEXT_PROPERTY_ACTIVE_VIEW_LAYER,
|
||||
"ACTIVE_VIEW_LAYER",
|
||||
ICON_NONE,
|
||||
"Active View Layer",
|
||||
"Currently evaluating view layer"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
#ifdef RNA_RUNTIME
|
||||
|
||||
# include "WM_api.h"
|
||||
|
@ -1879,6 +1893,14 @@ static void rna_def_drivertarget(BlenderRNA *brna)
|
|||
RNA_def_property_enum_items(prop, prop_local_space_items);
|
||||
RNA_def_property_ui_text(prop, "Transform Space", "Space in which transforms are used");
|
||||
RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
|
||||
|
||||
prop = RNA_def_property(srna, "context_property", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "context_property");
|
||||
RNA_def_property_enum_items(prop, rna_enum_driver_target_context_property_items);
|
||||
RNA_def_property_enum_default(prop, DTAR_CONTEXT_PROPERTY_ACTIVE_SCENE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Context Property", "Type of a context-dependent data-block to access property from");
|
||||
RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
|
||||
}
|
||||
|
||||
static void rna_def_drivervar(BlenderRNA *brna)
|
||||
|
@ -1907,6 +1929,11 @@ static void rna_def_drivervar(BlenderRNA *brna)
|
|||
ICON_DRIVER_DISTANCE,
|
||||
"Distance",
|
||||
"Distance between two bones or objects"},
|
||||
{DVAR_TYPE_CONTEXT_PROP,
|
||||
"CONTEXT_PROP",
|
||||
ICON_RNA,
|
||||
"Context Property",
|
||||
"Use the value from some RNA property within the current evaluation context"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -1821,6 +1821,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
|
|||
RNA_def_property_range(prop, 1, 5);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Number", "Particle number factor (higher value results in more particles)");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_AMOUNT);
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
|
||||
|
||||
prop = RNA_def_property(srna, "particle_min", PROP_INT, PROP_NONE);
|
||||
|
|
|
@ -2948,6 +2948,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
|
|||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_range(prop, 0, 1000000, 1, -1);
|
||||
RNA_def_property_ui_text(prop, "Number", "Total number of particles");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_AMOUNT);
|
||||
RNA_def_property_update(prop, 0, "rna_Particle_reset");
|
||||
|
||||
prop = RNA_def_property(
|
||||
|
|
|
@ -6440,6 +6440,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "hair_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, hair_shape_type_items);
|
||||
RNA_def_property_ui_text(prop, "Curves Shape Type", "Curves shape type");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVES);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_render_update");
|
||||
|
||||
prop = RNA_def_property(srna, "hair_subdiv", PROP_INT, PROP_NONE);
|
||||
|
|
|
@ -4407,6 +4407,11 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
|
|||
prop, "Extras", "Object details, including empty wire, cameras and other visual guides");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_light_colors", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_SHOW_LIGHT_COLORS);
|
||||
RNA_def_property_ui_text(prop, "Light Colors", "Show light colors");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_bones", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_BONES);
|
||||
RNA_def_property_ui_text(
|
||||
|
|
|
@ -237,6 +237,7 @@ static void rna_def_text(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "lines", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "TextLine");
|
||||
RNA_def_property_ui_text(prop, "Lines", "Lines of text");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_TEXT);
|
||||
|
||||
prop = RNA_def_property(srna, "current_line", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
||||
|
|
|
@ -664,6 +664,7 @@ static void rna_def_volume(BlenderRNA *brna)
|
|||
"Velocity Unit",
|
||||
"Define how the velocity vectors are interpreted with regard to time, 'frame' means "
|
||||
"the delta time is 1 frame, 'second' means the delta time is 1 / FPS");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UNIT);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
|
||||
prop = RNA_def_property(srna, "velocity_scale", PROP_FLOAT, PROP_NONE);
|
||||
|
|
|
@ -16,14 +16,14 @@
|
|||
*
|
||||
* The main missing features in this code compared to the paper are:
|
||||
*
|
||||
* + No mesh evolution. The paper suggests iteratively subsurfing the
|
||||
* - No mesh evolution. The paper suggests iteratively subdivision-surfacing the
|
||||
* skin output and adapting the output to better conform with the
|
||||
* spheres of influence surrounding each vertex.
|
||||
*
|
||||
* + No mesh fairing. The paper suggests re-aligning output edges to
|
||||
* - No mesh fairing. The paper suggests re-aligning output edges to
|
||||
* follow principal mesh curvatures.
|
||||
*
|
||||
* + No auxiliary balls. These would serve to influence mesh
|
||||
* - No auxiliary balls. These would serve to influence mesh
|
||||
* evolution, which as noted above is not implemented.
|
||||
*
|
||||
* The code also adds some features not present in the paper:
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
struct bNode;
|
||||
|
@ -145,6 +147,7 @@ class SocketDeclaration {
|
|||
std::string name;
|
||||
std::string identifier;
|
||||
std::string description;
|
||||
std::string translation_context;
|
||||
/** Defined by whether the socket is part of the node's input or
|
||||
* output socket declaration list. Included here for convenience. */
|
||||
eNodeSocketInOut in_out;
|
||||
|
@ -275,6 +278,12 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
|
|||
return *(Self *)this;
|
||||
}
|
||||
|
||||
Self &translation_context(std::string value = BLT_I18NCONTEXT_DEFAULT)
|
||||
{
|
||||
decl_->translation_context = std::move(value);
|
||||
return *(Self *)this;
|
||||
}
|
||||
|
||||
Self &no_muted_links(bool value = true)
|
||||
{
|
||||
decl_->no_mute_links = value;
|
||||
|
|
|
@ -33,7 +33,8 @@ namespace blender::nodes::node_composite_keyingscreen_cc {
|
|||
|
||||
static void cmp_node_keyingscreen_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_output<decl::Color>(N_("Screen"));
|
||||
b.add_output<decl::Color>(CTX_N_(BLT_I18NCONTEXT_ID_SCREEN, "Screen"))
|
||||
.translation_context(BLT_I18NCONTEXT_ID_SCREEN);
|
||||
}
|
||||
|
||||
static void node_composit_init_keyingscreen(const bContext *C, PointerRNA *ptr)
|
||||
|
|
|
@ -688,7 +688,8 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
|
|||
/* Support for any RNA data. */
|
||||
#ifdef USE_RNA_AS_PYOBJECT
|
||||
if (dvar->type == DVAR_TYPE_SINGLE_PROP) {
|
||||
driver_arg = pyrna_driver_get_variable_value(driver, &dvar->targets[0]);
|
||||
driver_arg = pyrna_driver_get_variable_value(
|
||||
anim_eval_context, driver, dvar, &dvar->targets[0]);
|
||||
|
||||
if (driver_arg == NULL) {
|
||||
driver_arg = PyFloat_FromDouble(0.0);
|
||||
|
@ -714,7 +715,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
|
|||
#endif
|
||||
{
|
||||
/* Try to get variable value. */
|
||||
const float tval = driver_get_variable_value(driver, dvar);
|
||||
const float tval = driver_get_variable_value(anim_eval_context, driver, dvar);
|
||||
driver_arg = PyFloat_FromDouble((double)tval);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,14 +20,17 @@
|
|||
|
||||
#include "bpy_rna_driver.h" /* own include */
|
||||
|
||||
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar)
|
||||
PyObject *pyrna_driver_get_variable_value(const struct AnimationEvalContext *anim_eval_context,
|
||||
struct ChannelDriver *driver,
|
||||
struct DriverVar *dvar,
|
||||
struct DriverTarget *dtar)
|
||||
{
|
||||
PyObject *driver_arg = NULL;
|
||||
PointerRNA ptr;
|
||||
PropertyRNA *prop = NULL;
|
||||
int index;
|
||||
|
||||
if (driver_get_variable_property(driver, dtar, &ptr, &prop, &index)) {
|
||||
if (driver_get_variable_property(anim_eval_context, driver, dvar, dtar, &ptr, &prop, &index)) {
|
||||
if (prop) {
|
||||
if (index != -1) {
|
||||
if (index < RNA_property_array_length(&ptr, prop) && index >= 0) {
|
||||
|
|
|
@ -17,7 +17,10 @@ extern "C" {
|
|||
/**
|
||||
* A version of #driver_get_variable_value which returns a #PyObject.
|
||||
*/
|
||||
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar);
|
||||
PyObject *pyrna_driver_get_variable_value(const struct AnimationEvalContext *anim_eval_context,
|
||||
struct ChannelDriver *driver,
|
||||
struct DriverVar *dvar,
|
||||
struct DriverTarget *dtar);
|
||||
|
||||
PyObject *pyrna_driver_self_from_anim_rna(struct PathResolvedRNA *anim_rna);
|
||||
bool pyrna_driver_is_equal_anim_rna(const struct PathResolvedRNA *anim_rna,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue