Geometry Nodes: add simulation support #104924
|
@ -5782,8 +5782,14 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co
|
|||
}
|
||||
const GWL_ModifierInfo &mod_info = g_modifier_info_table[i];
|
||||
const bool val = (state & (1 << seat->xkb_keymap_mod_index[i])) != 0;
|
||||
bool val_l = seat->key_depressed.mods[GHOST_KEY_MODIFIER_TO_INDEX(mod_info.key_l)] > 0;
|
||||
bool val_r = seat->key_depressed.mods[GHOST_KEY_MODIFIER_TO_INDEX(mod_info.key_r)] > 0;
|
||||
/* NOTE(@ideasman42): it's important to write the XKB state back to #GWL_KeyboardDepressedState
|
||||
* otherwise changes to modifiers in the future wont generate events.
|
||||
* This can cause modifiers to be stuck when switching between windows in GNOME because
|
||||
* window activation is handled before the keyboard enter callback runs, see: #107314. */
|
||||
int16_t &depressed_l = seat->key_depressed.mods[GHOST_KEY_MODIFIER_TO_INDEX(mod_info.key_l)];
|
||||
int16_t &depressed_r = seat->key_depressed.mods[GHOST_KEY_MODIFIER_TO_INDEX(mod_info.key_r)];
|
||||
bool val_l = depressed_l > 0;
|
||||
bool val_r = depressed_r > 0;
|
||||
|
||||
/* This shouldn't be needed, but guard against any possibility of modifiers being stuck.
|
||||
* Warn so if this happens it can be investigated. */
|
||||
|
@ -5796,6 +5802,7 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co
|
|||
}
|
||||
/* Picking the left is arbitrary. */
|
||||
val_l = true;
|
||||
depressed_l = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -5807,6 +5814,8 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co
|
|||
}
|
||||
val_l = false;
|
||||
val_r = false;
|
||||
depressed_l = 0;
|
||||
depressed_r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,9 +47,10 @@ def get_context_modifier(context):
|
|||
if context.area.type == 'PROPERTIES':
|
||||
modifier = context.modifier
|
||||
else:
|
||||
if context.object is None:
|
||||
ob = context.object
|
||||
if ob is None:
|
||||
return False
|
||||
modifier = context.object.modifiers.active
|
||||
modifier = ob.modifiers.active
|
||||
if modifier is None or modifier.type != 'NODES':
|
||||
return None
|
||||
return modifier
|
||||
|
@ -211,7 +212,8 @@ class NewGeometryNodesModifier(Operator):
|
|||
return geometry_modifier_poll(context)
|
||||
|
||||
def execute(self, context):
|
||||
modifier = context.object.modifiers.new(data_("GeometryNodes"), "NODES")
|
||||
ob = context.object
|
||||
modifier = ob.modifiers.new(data_("GeometryNodes"), 'NODES')
|
||||
if not modifier:
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
|
|
@ -1345,6 +1345,7 @@ rna_custom_property_name = StringProperty(
|
|||
maxlen=63,
|
||||
)
|
||||
|
||||
# Most useful entries of rna_enum_property_subtype_items:
|
||||
rna_custom_property_type_items = (
|
||||
('FLOAT', "Float", "A single floating-point value"),
|
||||
('FLOAT_ARRAY', "Float Array", "An array of floating-point values"),
|
||||
|
@ -1356,9 +1357,22 @@ rna_custom_property_type_items = (
|
|||
('PYTHON', "Python", "Edit a python value directly, for unsupported property types"),
|
||||
)
|
||||
|
||||
# Most useful entries of rna_enum_property_subtype_items for number arrays:
|
||||
rna_vector_subtype_items = (
|
||||
('NONE', "Plain Data", "Data values without special behavior"),
|
||||
rna_custom_property_subtype_none_item = ('NONE', "Plain Data", "Data values without special behavior")
|
||||
|
||||
rna_custom_property_subtype_number_items = (
|
||||
rna_custom_property_subtype_none_item,
|
||||
('PIXEL', "Pixel", ""),
|
||||
('PERCENTAGE', "Percentage", ""),
|
||||
('FACTOR', "Factor", ""),
|
||||
('ANGLE', "Angle", ""),
|
||||
('TIME_ABSOLUTE', "Time", "Time specified in seconds"),
|
||||
('DISTANCE', "Distance", ""),
|
||||
('POWER', "Power", ""),
|
||||
('TEMPERATURE', "Temperature", ""),
|
||||
)
|
||||
|
||||
rna_custom_property_subtype_vector_items = (
|
||||
rna_custom_property_subtype_none_item,
|
||||
('COLOR', "Linear Color", "Color in the linear space"),
|
||||
('COLOR_GAMMA', "Gamma-Corrected Color", "Color in the gamma corrected space"),
|
||||
('EULER', "Euler Angles", "Euler rotation angles in radians"),
|
||||
|
@ -1373,6 +1387,17 @@ class WM_OT_properties_edit(Operator):
|
|||
# register only because invoke_props_popup requires.
|
||||
bl_options = {'REGISTER', 'INTERNAL'}
|
||||
|
||||
def subtype_items_cb(self, context):
|
||||
match self.property_type:
|
||||
case 'FLOAT':
|
||||
return rna_custom_property_subtype_number_items
|
||||
case 'FLOAT_ARRAY':
|
||||
return rna_custom_property_subtype_vector_items
|
||||
return ()
|
||||
|
||||
def property_type_update_cb(self, context):
|
||||
self.subtype = 'NONE'
|
||||
|
||||
# Common settings used for all property types. Generally, separate properties are used for each
|
||||
# type to improve the experience when choosing UI data values.
|
||||
|
||||
|
@ -1381,6 +1406,7 @@ class WM_OT_properties_edit(Operator):
|
|||
property_type: EnumProperty(
|
||||
name="Type",
|
||||
items=rna_custom_property_type_items,
|
||||
update=property_type_update_cb
|
||||
)
|
||||
is_overridable_library: BoolProperty(
|
||||
name="Library Overridable",
|
||||
|
@ -1481,7 +1507,7 @@ class WM_OT_properties_edit(Operator):
|
|||
)
|
||||
subtype: EnumProperty(
|
||||
name="Subtype",
|
||||
items=WM_OT_properties_edit.subtype_items,
|
||||
items=subtype_items_cb,
|
||||
)
|
||||
|
||||
# String properties.
|
||||
|
@ -1497,9 +1523,6 @@ class WM_OT_properties_edit(Operator):
|
|||
description="Python value for unsupported custom property types",
|
||||
)
|
||||
|
||||
type_items = rna_custom_property_type_items
|
||||
subtype_items = rna_vector_subtype_items
|
||||
|
||||
# Helper method to avoid repetitive code to retrieve a single value from sequences and non-sequences.
|
||||
@staticmethod
|
||||
def _convert_new_value_single(old_value, new_type):
|
||||
|
@ -1567,15 +1590,7 @@ class WM_OT_properties_edit(Operator):
|
|||
return 'PYTHON'
|
||||
|
||||
def _init_subtype(self, subtype):
|
||||
subtype = subtype or 'NONE'
|
||||
subtype_items = rna_vector_subtype_items
|
||||
|
||||
# Add a temporary enum entry to preserve unknown subtypes
|
||||
if not any(subtype == item[0] for item in subtype_items):
|
||||
subtype_items += ((subtype, subtype, ""),)
|
||||
|
||||
WM_OT_properties_edit.subtype_items = subtype_items
|
||||
self.subtype = subtype
|
||||
self.subtype = subtype or 'NONE'
|
||||
|
||||
# Fill the operator's properties with the UI data properties from the existing custom property.
|
||||
# Note that if the UI data doesn't exist yet, the access will create it and use those default values.
|
||||
|
@ -1904,9 +1919,7 @@ class WM_OT_properties_edit(Operator):
|
|||
layout.prop(self, "step_float")
|
||||
layout.prop(self, "precision")
|
||||
|
||||
# Subtype is only supported for float properties currently.
|
||||
if self.property_type != 'FLOAT':
|
||||
layout.prop(self, "subtype")
|
||||
layout.prop(self, "subtype")
|
||||
elif self.property_type in {'INT', 'INT_ARRAY'}:
|
||||
if self.property_type == 'INT_ARRAY':
|
||||
layout.prop(self, "array_length")
|
||||
|
|
|
@ -110,7 +110,8 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel):
|
|||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.object and context.object.type == 'ARMATURE' and context.object.pose)
|
||||
ob = context.object
|
||||
return (ob and ob.type == 'ARMATURE' and ob.pose)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
|
|
@ -288,7 +288,7 @@ class OBJECT_PT_instancing_size(ObjectButtonsPanel, Panel):
|
|||
@classmethod
|
||||
def poll(cls, context):
|
||||
ob = context.object
|
||||
return ob.instance_type == 'FACES'
|
||||
return (ob is not None) and (ob.instance_type == 'FACES')
|
||||
|
||||
def draw_header(self, context):
|
||||
|
||||
|
@ -316,7 +316,8 @@ class OBJECT_PT_lineart(ObjectButtonsPanel, Panel):
|
|||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
lineart = context.object.lineart
|
||||
ob = context.object
|
||||
lineart = ob.lineart
|
||||
|
||||
layout.use_property_split = True
|
||||
|
||||
|
@ -397,7 +398,7 @@ class OBJECT_PT_visibility(ObjectButtonsPanel, Panel):
|
|||
col.prop(ob, "hide_viewport", text="Viewports", toggle=False, invert_checkbox=True)
|
||||
col.prop(ob, "hide_render", text="Renders", toggle=False, invert_checkbox=True)
|
||||
|
||||
if context.object.type == 'GPENCIL':
|
||||
if ob.type == 'GPENCIL':
|
||||
col = layout.column(heading="Grease Pencil")
|
||||
col.prop(ob, "use_grease_pencil_lights", toggle=False)
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "BKE_customdata.h"
|
||||
#include "BKE_mesh_types.h"
|
||||
|
||||
struct BLI_Stack;
|
||||
struct BMesh;
|
||||
struct BMeshCreateParams;
|
||||
struct BMeshFromMeshParams;
|
||||
|
@ -44,13 +43,6 @@ struct Scene;
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* setting zero so we can catch bugs in OpenMP/BMesh */
|
||||
#ifdef DEBUG
|
||||
# define BKE_MESH_OMP_LIMIT 0
|
||||
#else
|
||||
# define BKE_MESH_OMP_LIMIT 10000
|
||||
#endif
|
||||
|
||||
/* mesh_runtime.cc */
|
||||
|
||||
/**
|
||||
|
|
|
@ -412,7 +412,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
|
|||
data.tree = calc->tree;
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
|
||||
settings.use_threading = (calc->numVerts > 10000);
|
||||
settings.userdata_chunk = &nearest;
|
||||
settings.userdata_chunk_size = sizeof(nearest);
|
||||
BLI_task_parallel_range(
|
||||
|
@ -691,7 +691,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
|
|||
data.local2aux = &local2aux;
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
|
||||
settings.use_threading = (calc->numVerts > 10000);
|
||||
settings.userdata_chunk = &hit;
|
||||
settings.userdata_chunk_size = sizeof(hit);
|
||||
BLI_task_parallel_range(
|
||||
|
@ -1363,7 +1363,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
|
|||
data.tree = calc->tree;
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
|
||||
settings.use_threading = (calc->numVerts > 10000);
|
||||
settings.userdata_chunk = &nearest;
|
||||
settings.userdata_chunk_size = sizeof(nearest);
|
||||
BLI_task_parallel_range(
|
||||
|
|
|
@ -1269,15 +1269,21 @@ int BKE_unit_base_of_type_get(int system, int type)
|
|||
|
||||
const char *BKE_unit_name_get(const void *usys_pt, int index)
|
||||
{
|
||||
return ((bUnitCollection *)usys_pt)->units[index].name;
|
||||
const bUnitCollection *usys = usys_pt;
|
||||
BLI_assert((uint)index < (uint)usys->length);
|
||||
return usys->units[index].name;
|
||||
}
|
||||
const char *BKE_unit_display_name_get(const void *usys_pt, int index)
|
||||
{
|
||||
return ((bUnitCollection *)usys_pt)->units[index].name_display;
|
||||
const bUnitCollection *usys = usys_pt;
|
||||
BLI_assert((uint)index < (uint)usys->length);
|
||||
return usys->units[index].name_display;
|
||||
}
|
||||
const char *BKE_unit_identifier_get(const void *usys_pt, int index)
|
||||
{
|
||||
const bUnitDef *unit = ((const bUnitCollection *)usys_pt)->units + index;
|
||||
const bUnitCollection *usys = usys_pt;
|
||||
BLI_assert((uint)index < (uint)usys->length);
|
||||
const bUnitDef *unit = &usys->units[index];
|
||||
if (unit->identifier == NULL) {
|
||||
BLI_assert_msg(0, "identifier for this unit is not specified yet");
|
||||
}
|
||||
|
@ -1286,10 +1292,14 @@ const char *BKE_unit_identifier_get(const void *usys_pt, int index)
|
|||
|
||||
double BKE_unit_scalar_get(const void *usys_pt, int index)
|
||||
{
|
||||
return ((bUnitCollection *)usys_pt)->units[index].scalar;
|
||||
const bUnitCollection *usys = usys_pt;
|
||||
BLI_assert((uint)index < (uint)usys->length);
|
||||
return usys->units[index].scalar;
|
||||
}
|
||||
|
||||
bool BKE_unit_is_suppressed(const void *usys_pt, int index)
|
||||
{
|
||||
return (((bUnitCollection *)usys_pt)->units[index].flag & B_UNIT_DEF_SUPPRESS) != 0;
|
||||
const bUnitCollection *usys = usys_pt;
|
||||
BLI_assert((uint)index < (uint)usys->length);
|
||||
return (usys->units[index].flag & B_UNIT_DEF_SUPPRESS) != 0;
|
||||
}
|
||||
|
|
|
@ -810,7 +810,7 @@ static bool vfont_to_curve(Object *ob,
|
|||
VChar *che;
|
||||
struct CharTrans *chartransdata = NULL, *ct;
|
||||
struct TempLineInfo *lineinfo;
|
||||
float *f, xof, yof, xtrax, linedist;
|
||||
float xof, yof, xtrax, linedist;
|
||||
float twidth = 0, maxlen = 0;
|
||||
int i, slen, j;
|
||||
int curbox;
|
||||
|
@ -1536,25 +1536,59 @@ static bool vfont_to_curve(Object *ob,
|
|||
|
||||
/* Cursor first. */
|
||||
if (ef) {
|
||||
float si, co;
|
||||
|
||||
ct = &chartransdata[ef->pos];
|
||||
si = sinf(ct->rot);
|
||||
co = cosf(ct->rot);
|
||||
const float cursor_width = 0.04f;
|
||||
const float cursor_half = 0.02f;
|
||||
const float xoffset = ct->xof;
|
||||
const float yoffset = ct->yof;
|
||||
|
||||
f = ef->textcurs[0];
|
||||
/* By default the cursor is exactly between the characters
|
||||
* and matches the rotation of the character to the right. */
|
||||
float cursor_left = 0.0f - cursor_half;
|
||||
float rotation = ct->rot;
|
||||
|
||||
f[0] = font_size * (-0.02f * co + ct->xof);
|
||||
f[1] = font_size * (0.1f * si - (0.25f * co) + ct->yof);
|
||||
if (ef->selboxes) {
|
||||
if (ef->selend >= ef->selstart) {
|
||||
/* Cursor at right edge of a text selection. Match rotation to the character at the
|
||||
* end of selection. Cursor is further right to show the selected characters better. */
|
||||
rotation = chartransdata[ef->selend - 1].rot;
|
||||
cursor_left = 0.0f;
|
||||
}
|
||||
else {
|
||||
/* Cursor at the left edge of a text selection. Cursor
|
||||
* is further left to show the selected characters better. */
|
||||
cursor_left = 0.0f - cursor_width;
|
||||
}
|
||||
}
|
||||
else if ((ef->pos == ef->len) && (ef->len > 0)) {
|
||||
/* Nothing selected, but at the end of the string. Match rotation to previous character. */
|
||||
rotation = chartransdata[ef->len - 1].rot;
|
||||
}
|
||||
|
||||
f[2] = font_size * (0.02f * co + ct->xof);
|
||||
f[3] = font_size * (-0.1f * si - (0.25f * co) + ct->yof);
|
||||
/* We need the rotation to be around the bottom-left corner. So we make
|
||||
* that the zero point before rotation, rotate, then apply offsets afterward. */
|
||||
|
||||
f[4] = font_size * (0.02f * co + 0.8f * si + ct->xof);
|
||||
f[5] = font_size * (-0.1f * si + 0.75f * co + ct->yof);
|
||||
/* Bottom left. */
|
||||
ef->textcurs[0][0] = cursor_left;
|
||||
ef->textcurs[0][1] = 0.0f;
|
||||
/* Bottom right. */
|
||||
ef->textcurs[1][0] = cursor_left + cursor_width;
|
||||
ef->textcurs[1][1] = 0.0f;
|
||||
/* Top left. */
|
||||
ef->textcurs[3][0] = cursor_left;
|
||||
ef->textcurs[3][1] = 1.0f;
|
||||
/* Top right. */
|
||||
ef->textcurs[2][0] = cursor_left + cursor_width;
|
||||
ef->textcurs[2][1] = 1.0f;
|
||||
|
||||
f[6] = font_size * (-0.02f * co + 0.8f * si + ct->xof);
|
||||
f[7] = font_size * (0.1f * si + 0.75f * co + ct->yof);
|
||||
for (int vert = 0; vert < 4; vert++) {
|
||||
float temp_fl[2];
|
||||
/* Rotate around the cursor's bottom-left corner. */
|
||||
rotate_v2_v2fl(temp_fl, &ef->textcurs[vert][0], -rotation);
|
||||
ef->textcurs[vert][0] = font_size * (xoffset + temp_fl[0]);
|
||||
/* Shift down vertically so we are 25% below and 75% above baseline. */
|
||||
ef->textcurs[vert][1] = font_size * (yoffset + temp_fl[1] - 0.25f);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == FO_SELCHANGE) {
|
||||
|
|
|
@ -321,12 +321,25 @@ void BLI_path_sequence_encode(
|
|||
char *string, const char *head, const char *tail, unsigned short numlen, int pic);
|
||||
|
||||
/**
|
||||
* Remove redundant characters from \a path and optionally make absolute.
|
||||
* Remove redundant characters from \a path.
|
||||
*
|
||||
* \param path: Can be any input, and this function converts it to a regular full path.
|
||||
* Also removes garbage from directory paths, like `/../` or double slashes etc.
|
||||
* The following operations are performed:
|
||||
* - Redundant path components such as `//`, `/./` & `./` (prefix) are stripped.
|
||||
* (with the exception of `//` prefix used for blend-file relative paths).
|
||||
* - `..` are resolved so `<parent>/../<child>/` resolves to `<child>/`.
|
||||
* Note that the resulting path may begin with `..` if it's relative.
|
||||
*
|
||||
* \note \a path isn't protected for max string names.
|
||||
* Details:
|
||||
* - The slash direction is expected to be native (see #SEP).
|
||||
* When calculating a canonical paths you may need to run #BLI_path_slash_native first.
|
||||
* #BLI_path_cmp_normalized can be used for canonical path comparison.
|
||||
* - Trailing slashes are left intact (unlike Python which strips them).
|
||||
* - Handling paths beginning with `..` depends on them being absolute or relative.
|
||||
* For absolute paths they are removed (e.g. `/../path` becomes `/path`).
|
||||
* For relative paths they are kept as it's valid to reference paths above a relative location
|
||||
* such as `//../parent` or `../parent`.
|
||||
*
|
||||
* \param path: The path to a file or directory which can be absolute or relative.
|
||||
*/
|
||||
void BLI_path_normalize(char *path) ATTR_NONNULL(1);
|
||||
/**
|
||||
|
|
|
@ -106,8 +106,8 @@ typedef struct BLI_mempool_chunk {
|
|||
* The mempool, stores and tracks memory \a chunks and elements within those chunks \a free.
|
||||
*/
|
||||
struct BLI_mempool {
|
||||
/* Serialize access to mempools when debugging wih ASAN. */
|
||||
#ifdef WITH_ASAN
|
||||
/** Serialize access to memory-pools when debugging with ASAN. */
|
||||
ThreadMutex mutex;
|
||||
#endif
|
||||
/** Single linked list of allocated chunks. */
|
||||
|
|
|
@ -115,13 +115,12 @@ void BLI_path_sequence_encode(
|
|||
void BLI_path_normalize(char *path)
|
||||
{
|
||||
const char *path_orig = path;
|
||||
int path_len;
|
||||
|
||||
ptrdiff_t a;
|
||||
char *start, *eind;
|
||||
|
||||
path_len = strlen(path);
|
||||
int path_len = strlen(path);
|
||||
|
||||
/*
|
||||
* Skip absolute prefix.
|
||||
* ---------------------
|
||||
*/
|
||||
if (path[0] == '/' && path[1] == '/') {
|
||||
path = path + 2; /* Leave the initial `//` untouched. */
|
||||
path_len -= 2;
|
||||
|
@ -157,10 +156,14 @@ void BLI_path_normalize(char *path)
|
|||
}
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
|
||||
/* Works on WIN32 as well, because the drive component is skipped. */
|
||||
const bool is_relative = path[0] && (path[0] != SEP);
|
||||
|
||||
/*
|
||||
* Strip redundant path components.
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
/* NOTE(@ideasman42):
|
||||
* `memmove(start, eind, strlen(eind) + 1);`
|
||||
* is the same as
|
||||
|
@ -189,7 +192,6 @@ void BLI_path_normalize(char *path)
|
|||
else {
|
||||
break;
|
||||
}
|
||||
|
||||
} while (i > 0);
|
||||
|
||||
if (i < i_end) {
|
||||
|
@ -200,8 +202,7 @@ void BLI_path_normalize(char *path)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove redundant `./` prefix, while it could be kept, it confuses the loop below. */
|
||||
/* Remove redundant `./` prefix as it's redundant & complicates collapsing directories. */
|
||||
if (is_relative) {
|
||||
if ((path_len > 2) && (path[0] == '.') && (path[1] == SEP)) {
|
||||
memmove(path, path + 2, (path_len - 2) + 1);
|
||||
|
@ -209,69 +210,127 @@ void BLI_path_normalize(char *path)
|
|||
}
|
||||
}
|
||||
|
||||
const ptrdiff_t a_start = is_relative ? 0 : 1;
|
||||
start = path;
|
||||
while ((start = strstr(start, SEP_STR ".."))) {
|
||||
if (!ELEM(start[3], SEP, '\0')) {
|
||||
start += 3;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Collapse Parent Directories.
|
||||
* ----------------------------
|
||||
*
|
||||
* Example: `<parent>/<child>/../` -> `<parent>/`
|
||||
*
|
||||
* Notes:
|
||||
* - Leading `../` are skipped as they cannot be collapsed (see `start_base`).
|
||||
* - Multiple parent directories are handled at once to reduce number of `memmove` calls.
|
||||
*/
|
||||
|
||||
a = (start - path) - 1;
|
||||
if (a >= a_start) {
|
||||
/* `<prefix>/<parent>/../<postfix> => <prefix>/<postfix>`. */
|
||||
eind = start + (4 - 1) /* `strlen("/../") - 1` */; /* Strip "/.." and keep the char after. */
|
||||
while (a > 0 && path[a] != SEP) { /* Find start of `<parent>`. */
|
||||
a--;
|
||||
}
|
||||
#define IS_PARENT_DIR(p) ((p)[0] == '.' && (p)[1] == '.' && ELEM((p)[2], SEP, '\0'))
|
||||
|
||||
if (is_relative && (a == 0) && *eind) {
|
||||
/* When the path does not start with a slash, don't copy the first `/` to the destination
|
||||
* as it will make a relative path into an absolute path. */
|
||||
eind += 1;
|
||||
}
|
||||
const size_t eind_len = path_len - (eind - path);
|
||||
BLI_assert(eind_len == strlen(eind));
|
||||
|
||||
/* Only remove the parent if it's not also a `..`. */
|
||||
if (is_relative && STRPREFIX(path + ((path[a] == SEP) ? a + 1 : a), ".." SEP_STR)) {
|
||||
start += 3 /* `strlen("/..")` */;
|
||||
}
|
||||
else {
|
||||
start = path + a;
|
||||
BLI_assert(start < eind);
|
||||
memmove(start, eind, eind_len + 1);
|
||||
path_len -= (eind - start);
|
||||
BLI_assert(strlen(path) == path_len);
|
||||
BLI_assert(!is_relative || (path[0] != SEP));
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Support for odd paths: eg `/../home/me` --> `/home/me`
|
||||
* this is a valid path in blender but we can't handle this the usual way below
|
||||
* simply strip this prefix then evaluate the path as usual.
|
||||
* Python's `os.path.normpath()` does this. */
|
||||
|
||||
/* NOTE: previous version of following call used an offset of 3 instead of 4,
|
||||
* which meant that the `/../home/me` example actually became `home/me`.
|
||||
* Using offset of 3 gives behavior consistent with the aforementioned
|
||||
* Python routine. */
|
||||
eind = start + 3;
|
||||
const size_t eind_len = path_len - (eind - path);
|
||||
memmove(start, eind, eind_len + 1);
|
||||
path_len -= 3;
|
||||
BLI_assert(strlen(path) == path_len);
|
||||
BLI_assert(!is_relative || (path[0] != SEP));
|
||||
}
|
||||
/* First non prefix path component. */
|
||||
char *path_first_non_slash_part = path;
|
||||
while (*path_first_non_slash_part && *path_first_non_slash_part == SEP) {
|
||||
path_first_non_slash_part++;
|
||||
}
|
||||
|
||||
if (is_relative && path_len == 0 && (path == path_orig)) {
|
||||
path[0] = '.';
|
||||
path[1] = '\0';
|
||||
path_len += 1;
|
||||
/* Maintain a pointer to the end of leading `..` component.
|
||||
* Skip leading parent directories because logically they cannot be collapsed. */
|
||||
char *start_base = path_first_non_slash_part;
|
||||
while (IS_PARENT_DIR(start_base)) {
|
||||
start_base += 3;
|
||||
}
|
||||
|
||||
/* It's possible the entire path is made of up `../`,
|
||||
* in this case there is nothing to do. */
|
||||
if (start_base < path + path_len) {
|
||||
/* Step over directories, always starting out on the character after the slash. */
|
||||
char *start = start_base;
|
||||
char *start_temp;
|
||||
while (((start_temp = strstr(start, SEP_STR ".." SEP_STR)) ||
|
||||
/* Check if the string ends with `/..` & assign when found, else NULL. */
|
||||
(start_temp = ((start <= &path[path_len - 3]) &&
|
||||
STREQ(&path[path_len - 3], SEP_STR "..")) ?
|
||||
&path[path_len - 3] :
|
||||
NULL))) {
|
||||
start = start_temp + 1; /* Skip the `/`. */
|
||||
BLI_assert(start_base != start);
|
||||
|
||||
/* Step `end_all` forwards (over all `..`). */
|
||||
char *end_all = start;
|
||||
do {
|
||||
BLI_assert(IS_PARENT_DIR(end_all));
|
||||
end_all += 3;
|
||||
BLI_assert(end_all <= path + path_len + 1);
|
||||
} while (IS_PARENT_DIR(end_all));
|
||||
|
||||
/* Step `start` backwards (until `end` meets `end_all` or `start` meets `start_base`). */
|
||||
char *end = start;
|
||||
do {
|
||||
BLI_assert(start_base < start);
|
||||
BLI_assert(*(start - 1) == SEP);
|
||||
/* Step `start` backwards one. */
|
||||
do {
|
||||
start--;
|
||||
} while (start_base < start && *(start - 1) != SEP);
|
||||
BLI_assert(*start != SEP); /* Ensure the loop ran at least once. */
|
||||
BLI_assert(!IS_PARENT_DIR(start)); /* Clamping by `start_base` prevents this. */
|
||||
end += 3;
|
||||
} while ((start != start_base) && (end < end_all));
|
||||
|
||||
if (end > path + path_len) {
|
||||
BLI_assert(*(end - 1) == '\0');
|
||||
end--;
|
||||
end_all--;
|
||||
}
|
||||
BLI_assert(start < end && start >= start_base);
|
||||
const size_t start_len = path_len - (end - path);
|
||||
memmove(start, end, start_len + 1);
|
||||
path_len -= end - start;
|
||||
BLI_assert(strlen(path) == path_len);
|
||||
/* Other `..` directories may have been moved to the front, step `start_base` past them. */
|
||||
if (UNLIKELY(start == start_base && (end != end_all))) {
|
||||
start_base += (end_all - end);
|
||||
start = (start_base < path + path_len) ? start_base : start_base - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(strlen(path) == path_len);
|
||||
/* Characters before the `start_base` must *only* be `../../../` (multiples of 3). */
|
||||
BLI_assert((start_base - path_first_non_slash_part) % 3 == 0);
|
||||
/* All `..` ahead of `start_base` were collapsed (including trailing `/..`). */
|
||||
BLI_assert(!(start_base < path + path_len) ||
|
||||
(!strstr(start_base, SEP_STR ".." SEP_STR) &&
|
||||
!(path_len >= 3 && STREQ(&path[path_len - 3], SEP_STR ".."))));
|
||||
|
||||
/*
|
||||
* Final Prefix Cleanup.
|
||||
* ---------------------
|
||||
*/
|
||||
if (is_relative) {
|
||||
if (path_len == 0 && (path == path_orig)) {
|
||||
path[0] = '.';
|
||||
path[1] = '\0';
|
||||
path_len = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Support for odd paths: eg `/../home/me` --> `/home/me`
|
||||
* this is a valid path in blender but we can't handle this the usual way below
|
||||
* simply strip this prefix then evaluate the path as usual.
|
||||
* Python's `os.path.normpath()` does this. */
|
||||
if (start_base != path_first_non_slash_part) {
|
||||
char *start = start_base > path + path_len ? start_base - 1 : start_base;
|
||||
/* As long as `start` is set correctly, it should never begin with `../`
|
||||
* as these directories are expected to be skipped. */
|
||||
BLI_assert(!IS_PARENT_DIR(start));
|
||||
const size_t start_len = path_len - (start - path);
|
||||
memmove(path_first_non_slash_part, start, start_len + 1);
|
||||
BLI_assert(strlen(start) == start_len);
|
||||
path_len -= start - path_first_non_slash_part;
|
||||
BLI_assert(strlen(path) == path_len);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(strlen(path) == path_len);
|
||||
|
||||
#undef IS_PARENT_DIR
|
||||
}
|
||||
|
||||
void BLI_path_normalize_dir(char *dir, size_t dir_maxlen)
|
||||
|
|
|
@ -84,11 +84,16 @@ TEST(path_util, Normalize_Dot)
|
|||
NORMALIZE("/a/./././b/", "/a/b/");
|
||||
}
|
||||
/* #BLI_path_normalize: complex "/./" -> "/", "//" -> "/", "./path/../" -> "./". */
|
||||
TEST(path_util, Normalize_Complex)
|
||||
TEST(path_util, Normalize_ComplexAbsolute)
|
||||
{
|
||||
NORMALIZE("/a/./b/./c/./.././.././", "/a/");
|
||||
NORMALIZE("/a//.//b//.//c//.//..//.//..//.//", "/a/");
|
||||
}
|
||||
TEST(path_util, Normalize_ComplexRelative)
|
||||
{
|
||||
NORMALIZE("a/b/c/d/e/f/g/../a/../b/../../c/../../../d/../../../..", ".");
|
||||
NORMALIZE("a/b/c/d/e/f/g/../a/../../../../b/../../../c/../../d/..", ".");
|
||||
}
|
||||
/* #BLI_path_normalize: "//" -> "/" */
|
||||
TEST(path_util, Normalize_DoubleSlash)
|
||||
{
|
||||
|
|
|
@ -71,18 +71,12 @@ static const DTreeContext *find_active_context(const DerivedNodeTree &tree)
|
|||
}
|
||||
|
||||
/* Return the output node which is marked as NODE_DO_OUTPUT. If multiple types of output nodes are
|
||||
* marked, then the preference will be CMP_NODE_COMPOSITE > CMP_NODE_VIEWER > CMP_NODE_SPLITVIEWER.
|
||||
* marked, then the preference will be CMP_NODE_VIEWER > CMP_NODE_SPLITVIEWER > CMP_NODE_COMPOSITE.
|
||||
* If no output node exists, a null node will be returned. */
|
||||
static DNode find_output_in_context(const DTreeContext *context)
|
||||
{
|
||||
const bNodeTree &tree = context->btree();
|
||||
|
||||
for (const bNode *node : tree.nodes_by_type("CompositorNodeComposite")) {
|
||||
if (node->flag & NODE_DO_OUTPUT) {
|
||||
return DNode(context, node);
|
||||
}
|
||||
}
|
||||
|
||||
for (const bNode *node : tree.nodes_by_type("CompositorNodeViewer")) {
|
||||
if (node->flag & NODE_DO_OUTPUT) {
|
||||
return DNode(context, node);
|
||||
|
@ -95,6 +89,12 @@ static DNode find_output_in_context(const DTreeContext *context)
|
|||
}
|
||||
}
|
||||
|
||||
for (const bNode *node : tree.nodes_by_type("CompositorNodeComposite")) {
|
||||
if (node->flag & NODE_DO_OUTPUT) {
|
||||
return DNode(context, node);
|
||||
}
|
||||
}
|
||||
|
||||
return DNode();
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ void node_composite_separate_rgba(vec4 color, out float r, out float g, out floa
|
|||
void node_composite_combine_hsva(float h, float s, float v, float a, out vec4 color)
|
||||
{
|
||||
hsv_to_rgb(vec4(h, s, v, a), color);
|
||||
color.rgb = max(color.rgb, vec3(0.0));
|
||||
}
|
||||
|
||||
void node_composite_separate_hsva(vec4 color, out float h, out float s, out float v, out float a)
|
||||
|
@ -51,6 +52,7 @@ void node_composite_separate_hsva(vec4 color, out float h, out float s, out floa
|
|||
void node_composite_combine_hsla(float h, float s, float l, float a, out vec4 color)
|
||||
{
|
||||
hsl_to_rgb(vec4(h, s, l, a), color);
|
||||
color.rgb = max(color.rgb, vec3(0.0));
|
||||
}
|
||||
|
||||
void node_composite_separate_hsla(vec4 color, out float h, out float s, out float l, out float a)
|
||||
|
|
|
@ -184,29 +184,29 @@ BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me)
|
|||
|
||||
BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx)
|
||||
{
|
||||
return ((mr->p_origindex != NULL) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
|
||||
return ((mr->p_origindex != nullptr) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
|
||||
BM_face_at_index(mr->bm, mr->p_origindex[idx]) :
|
||||
NULL;
|
||||
nullptr;
|
||||
}
|
||||
|
||||
BLI_INLINE BMEdge *bm_original_edge_get(const MeshRenderData *mr, int idx)
|
||||
{
|
||||
return ((mr->e_origindex != NULL) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
|
||||
return ((mr->e_origindex != nullptr) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
|
||||
BM_edge_at_index(mr->bm, mr->e_origindex[idx]) :
|
||||
NULL;
|
||||
nullptr;
|
||||
}
|
||||
|
||||
BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx)
|
||||
{
|
||||
return ((mr->v_origindex != NULL) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
|
||||
return ((mr->v_origindex != nullptr) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
|
||||
BM_vert_at_index(mr->bm, mr->v_origindex[idx]) :
|
||||
NULL;
|
||||
nullptr;
|
||||
}
|
||||
|
||||
BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve)
|
||||
{
|
||||
const float(*vert_coords)[3] = mr->bm_vert_coords;
|
||||
if (vert_coords != NULL) {
|
||||
if (vert_coords != nullptr) {
|
||||
return vert_coords[BM_elem_index_get(eve)];
|
||||
}
|
||||
|
||||
|
@ -217,7 +217,7 @@ BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *e
|
|||
BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve)
|
||||
{
|
||||
const float(*vert_normals)[3] = mr->bm_vert_normals;
|
||||
if (vert_normals != NULL) {
|
||||
if (vert_normals != nullptr) {
|
||||
return vert_normals[BM_elem_index_get(eve)];
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,7 @@ BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *e
|
|||
BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa)
|
||||
{
|
||||
const float(*poly_normals)[3] = mr->bm_poly_normals;
|
||||
if (poly_normals != NULL) {
|
||||
if (poly_normals != nullptr) {
|
||||
return poly_normals[BM_elem_index_get(efa)];
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "BLI_linklist.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_memory_utils.hh"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
|
@ -378,6 +379,7 @@ static std::string get_in_memory_texture_filename(Image *ima)
|
|||
|
||||
ImageFormatData imageFormat;
|
||||
BKE_image_format_from_imbuf(&imageFormat, imbuf);
|
||||
BKE_image_release_ibuf(ima, imbuf, nullptr);
|
||||
|
||||
char file_name[FILE_MAX];
|
||||
/* Use the image name for the file name. */
|
||||
|
@ -405,6 +407,7 @@ static void export_in_memory_texture(Image *ima,
|
|||
}
|
||||
|
||||
ImBuf *imbuf = BKE_image_acquire_ibuf(ima, nullptr, nullptr);
|
||||
BLI_SCOPED_DEFER([&]() { BKE_image_release_ibuf(ima, imbuf, nullptr); });
|
||||
if (!imbuf) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -687,10 +687,12 @@ typedef struct FluidDomainSettings {
|
|||
int viewsettings;
|
||||
char _pad12[4]; /* Unused. */
|
||||
|
||||
/* Pointcache options. */
|
||||
/* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading
|
||||
* old files. */
|
||||
struct PointCache *point_cache[2]; /* Definition is in DNA_object_force_types.h. */
|
||||
/**
|
||||
* Point-cache options.
|
||||
* Smoke uses only one cache from now on (index [0]),
|
||||
* but keeping the array for now for reading old files.
|
||||
*/
|
||||
struct PointCache *point_cache[2];
|
||||
struct ListBase ptcaches[2];
|
||||
int cache_comp;
|
||||
int cache_high_comp;
|
||||
|
|
|
@ -79,6 +79,7 @@ dict_custom = {
|
|||
"decrement",
|
||||
"decrementing",
|
||||
"deduplicate",
|
||||
"deduplicates",
|
||||
"deduplicating",
|
||||
"deduplication",
|
||||
"defocus",
|
||||
|
@ -88,6 +89,7 @@ dict_custom = {
|
|||
"denoised",
|
||||
"denoiser",
|
||||
"denoising",
|
||||
"denormalized",
|
||||
"dereference",
|
||||
"dereferenced",
|
||||
"dereferences",
|
||||
|
|
Loading…
Reference in New Issue