Cleanup: Move BKE_node.h to C++ #107790

Merged
Hans Goudey merged 16 commits from mod_moder/blender:tmp_move_node_on_cpp into main 2023-05-15 15:14:30 +02:00
69 changed files with 1596 additions and 502 deletions
Showing only changes of commit dfd081fbef - Show all commits

View File

@ -126,6 +126,7 @@ bool OneapiDevice::can_use_hardware_raytracing_for_features(uint requested_featu
# if defined(RTC_VERSION) && RTC_VERSION < 40100
return !(requested_features & (KERNEL_FEATURE_MNEE | KERNEL_FEATURE_NODE_RAYTRACE));
# else
(void)requested_features;
return true;
# endif
}

View File

@ -20,7 +20,7 @@ from bpy.app.translations import pgettext_tip as tip_
class ANIM_OT_keying_set_export(Operator):
"""Export Keying Set to a python script"""
"""Export Keying Set to a Python script"""
bl_idname = "anim.keying_set_export"
bl_label = "Export Keying Set..."
@ -38,7 +38,7 @@ class ANIM_OT_keying_set_export(Operator):
options={'HIDDEN'},
)
filter_python: BoolProperty(
name="Filter python",
name="Filter Python",
default=True,
options={'HIDDEN'},
)

View File

@ -16,7 +16,7 @@ def _lang_module_get(sc):
class ConsoleExec(Operator):
"""Execute the current console line as a python expression"""
"""Execute the current console line as a Python expression"""
bl_idname = "console.execute"
bl_label = "Console Execute"
bl_options = {'UNDO_GROUPED'}

View File

@ -78,7 +78,7 @@ class WM_OT_previews_batch_generate(Operator):
use_trusted: BoolProperty(
default=False,
name="Trusted Blend Files",
description="Enable python evaluation for selected files",
description="Enable Python evaluation for selected files",
)
use_backups: BoolProperty(
default=True,
@ -188,7 +188,7 @@ class WM_OT_previews_batch_clear(Operator):
use_trusted: BoolProperty(
default=False,
name="Trusted Blend Files",
description="Enable python evaluation for selected files",
description="Enable Python evaluation for selected files",
)
use_backups: BoolProperty(
default=True,

View File

@ -173,7 +173,7 @@ class PREFERENCES_OT_keyconfig_test(Operator):
class PREFERENCES_OT_keyconfig_import(Operator):
"""Import key configuration from a python script"""
"""Import key configuration from a Python script"""
bl_idname = "preferences.keyconfig_import"
bl_label = "Import Key Configuration..."
@ -192,7 +192,7 @@ class PREFERENCES_OT_keyconfig_import(Operator):
options={'HIDDEN'},
)
filter_python: BoolProperty(
name="Filter python",
name="Filter Python",
default=True,
options={'HIDDEN'},
)
@ -244,7 +244,7 @@ class PREFERENCES_OT_keyconfig_import(Operator):
class PREFERENCES_OT_keyconfig_export(Operator):
"""Export key configuration to a python script"""
"""Export key configuration to a Python script"""
bl_idname = "preferences.keyconfig_export"
bl_label = "Export Key Configuration..."
@ -268,7 +268,7 @@ class PREFERENCES_OT_keyconfig_export(Operator):
options={'HIDDEN'},
)
filter_python: BoolProperty(
name="Filter python",
name="Filter Python",
default=True,
options={'HIDDEN'},
)
@ -610,7 +610,7 @@ class PREFERENCES_OT_addon_install(Operator):
options={'HIDDEN'},
)
filter_python: BoolProperty(
name="Filter python",
name="Filter Python",
default=True,
options={'HIDDEN'},
)

View File

@ -746,7 +746,7 @@ class WM_OT_operator_pie_enum(Operator):
data_path: StringProperty(
name="Operator",
description="Operator name (in python as string)",
description="Operator name (in Python as string)",
maxlen=1024,
)
prop_string: StringProperty(
@ -1381,7 +1381,7 @@ rna_custom_property_type_items = (
('BOOL', "Boolean", "A true or false value"),
('BOOL_ARRAY', "Boolean Array", "An array of true or false values"),
('STRING', "String", "A string value"),
('PYTHON', "Python", "Edit a python value directly, for unsupported property types"),
('PYTHON', "Python", "Edit a Python value directly, for unsupported property types"),
)
rna_custom_property_subtype_none_item = ('NONE', "Plain Data", "Data values without special behavior")

View File

@ -831,7 +831,7 @@ class ConstraintButtonsPanel:
def draw_python_constraint(self, _context):
layout = self.layout
layout.label(text="Blender 2.6 doesn't support python constraints yet")
layout.label(text="Blender 2.6 doesn't support Python constraints yet")
def draw_armature(self, context):
layout = self.layout

View File

@ -192,6 +192,7 @@ class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, Panel):
if itasc:
layout.prop(itasc, "mode")
layout.prop(itasc, "translate_root_bones")
simulation = (itasc.mode == 'SIMULATION')
if simulation:
layout.prop(itasc, "reiteration_method", expand=False)

View File

@ -25,13 +25,13 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 8
#define BLENDER_FILE_SUBVERSION 9
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
* was written with too new a version. */
#define BLENDER_FILE_MIN_VERSION 305
#define BLENDER_FILE_MIN_SUBVERSION 10
#define BLENDER_FILE_MIN_SUBVERSION 9
/** User readable version string. */
const char *BKE_blender_version_string(void);

View File

@ -1666,6 +1666,10 @@ void BKE_main_id_refcount_recompute(struct Main *bmain, const bool do_linked_onl
id->tag &= ~(LIB_TAG_EXTRAUSER | LIB_TAG_EXTRAUSER_SET);
id_us_ensure_real(id);
}
if (ELEM(GS(id->name), ID_SCE, ID_WM, ID_WS)) {
/* These IDs should always have a 'virtual' user. */
id_us_ensure_real(id);
}
}
FOREACH_MAIN_ID_END;

View File

@ -949,12 +949,12 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
if (ob->id.lib) {
BLO_reportf_wrap(reports,
RPT_INFO,
TIP_("Can't find object data of %s lib %s\n"),
TIP_("Can't find object data of %s lib %s"),
ob->id.name + 2,
ob->id.lib->filepath);
}
else {
BLO_reportf_wrap(reports, RPT_INFO, TIP_("Object %s lost data\n"), ob->id.name + 2);
BLO_reportf_wrap(reports, RPT_INFO, TIP_("Object %s lost data"), ob->id.name + 2);
}
reports->count.missing_obdata++;
}

View File

@ -164,13 +164,13 @@ static void filepath_avi(char *filepath, const RenderData *rd, bool preview, con
if (rd->scemode & R_EXTENSION) {
if (!BLI_path_extension_check(filepath, ".avi")) {
BLI_path_frame_range(filepath, sfra, efra, 4);
BLI_path_frame_range(filepath, FILE_MAX, sfra, efra, 4);
BLI_strncat(filepath, ".avi", FILE_MAX);
}
}
else {
if (BLI_path_frame_check_chars(filepath)) {
BLI_path_frame_range(filepath, sfra, efra, 4);
BLI_path_frame_range(filepath, FILE_MAX, sfra, efra, 4);
}
}

View File

@ -1406,7 +1406,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context,
if (*fe == NULL) {
BLI_strncat(string, autosplit, FILE_MAX);
BLI_path_frame_range(string, sfra, efra, 4);
BLI_path_frame_range(string, FILE_MAX, sfra, efra, 4);
BLI_strncat(string, *exts, FILE_MAX);
}
else {
@ -1417,7 +1417,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context,
}
else {
if (BLI_path_frame_check_chars(string)) {
BLI_path_frame_range(string, sfra, efra, 4);
BLI_path_frame_range(string, FILE_MAX, sfra, efra, 4);
}
BLI_strncat(string, autosplit, FILE_MAX);

View File

@ -15,27 +15,219 @@
extern "C" {
#endif
/* -------------------------------------------------------------------- */
/** \name Path Queries
* \{ */
/**
* Sets the specified environment variable to the specified value,
* and clears it if `val == NULL`.
*/
void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1);
/**
* Only set an environment variable if already not there.
* Like Unix `setenv(env, val, 0);`
* Get an element of the path at an index, eg:
* `/some/path/file.txt` where an index of:
* - 0 or -3: `some`
* - 1 or -2: `path`
* - 2 or -1: `file.txt`
*
* (not used anywhere).
* Ignored elements in the path:
* - Multiple slashes at any point in the path (including start/end).
* - Single '.' in the path: `/./` except for the beginning of the path
* where it's used to signify a $PWD relative path.
*/
void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
bool BLI_path_name_at_index(const char *__restrict path,
int index,
int *__restrict r_offset,
int *__restrict r_len) ATTR_NONNULL(1, 3, 4) ATTR_WARN_UNUSED_RESULT;
/**
* Get an environment variable, result has to be used immediately.
*
* On windows #getenv gets its variables from a static copy of the environment variables taken at
* process start-up, causing it to not pick up on environment variables created during runtime.
* This function uses an alternative method to get environment variables that does pick up on
* runtime environment variables. The result will be UTF-8 encoded.
* Return true if the path is a UNC share.
*/
const char *BLI_getenv(const char *env) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
bool BLI_path_is_unc(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/** \} */
/* -------------------------------------------------------------------- */
/** \name Path Parent Operations
* \{ */
/**
* Go back one directory.
*
* Replaces path with the path of its parent directory, returning true if
* it was able to find a parent directory within the path.
*
* On success, the resulting path will always have a trailing slash.
*/
bool BLI_path_parent_dir(char *path) ATTR_NONNULL(1);
/**
* Go back until the directory is found.
*
* Strips off nonexistent (or non-accessible) sub-directories from the end of `dir`,
* leaving the path of the lowest-level directory that does exist and we can read.
*/
bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL(1);
/**
* In the simple case this is similar to `BLI_path_slash_rfind(dirname)`
* however it behaves differently when there are redundant characters:
*
* `/test///dir/./file`
* ^
* `/test/dir/subdir//file`
* ^
* \return The position after the parent paths last character or NULL on failure.
* Neither `path` or `&path[path_len - 1]` are ever returned.
*/
const char *BLI_path_parent_dir_end(const char *path, size_t path_len)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/** \} */
/* -------------------------------------------------------------------- */
/** \name Path Make Safe / Sanitize
* \{ */
/**
* Make given name safe to be used in paths.
*
* \param allow_tokens: Permit the usage of '<' and '>' characters. This can be
* leveraged by higher layers to support "virtual filenames" which contain
* substitution markers delineated between the two characters.
*
* \return true if \a fname was changed, false otherwise.
*
* For now, simply replaces reserved chars (as listed in
* https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
* by underscores ('_').
*
* \note Space case ' ' is a bit of an edge case here - in theory it is allowed,
* but again can be an issue in some cases, so we simply replace it by an underscore too
* (good practice anyway).
* REMOVED based on popular demand (see #45900).
* Percent '%' char is a bit same case - not recommended to use it,
* but supported by all decent file-systems/operating-systems around.
*
* \note On Windows, it also ensures there is no '.' (dot char) at the end of the file,
* this can lead to issues.
*
* \note On Windows, it also checks for forbidden names
* (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
*/
bool BLI_path_make_safe_filename_ex(char *fname, bool allow_tokens) ATTR_NONNULL(1);
bool BLI_path_make_safe_filename(char *fname) ATTR_NONNULL(1);
/**
* Make given path OS-safe.
*
* \return true if \a path was changed, false otherwise.
*/
bool BLI_path_make_safe(char *path) ATTR_NONNULL(1);
/**
* Creates a display string from path to be used menus and the user interface.
* Like `bpy.path.display_name()`.
*/
void BLI_path_to_display_name(char *display_name, int display_name_maxncpy, const char *name)
ATTR_NONNULL(1, 3);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Path Normalize
* \{ */
/**
* Remove redundant characters from \a path.
*
* 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.
*
* 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);
/**
* Cleanup file-path ensuring a trailing slash.
*
* \note Same as #BLI_path_normalize but adds a trailing slash.
*/
void BLI_path_normalize_dir(char *dir, size_t dir_maxncpy) ATTR_NONNULL(1);
#if defined(WIN32)
void BLI_path_normalize_unc_16(wchar_t *path_16);
void BLI_path_normalize_unc(char *path, int path_maxncpy);
#endif
/** \} */
/* -------------------------------------------------------------------- */
/** \name Path FileName Manipulation
* \{ */
/**
* Ensure `filepath` has a file component, adding `filename` when it's empty or ends with a slash.
* \return true if the `filename` was appended to `filepath`.
*/
bool BLI_path_filename_ensure(char *filepath, size_t filepath_maxncpy, const char *filename)
ATTR_NONNULL(1, 3);
/**
* Appends a suffix to the `path`, fitting it before the extension
*
* path = `Foo.png`, suffix = `123`, separator = `_`.
* `Foo.png` -> `Foo_123.png`.
*
* \param path: original (and final) string.
* \param path_maxncpy: Maximum length of path.
* \param suffix: String to append to the original path.
* \param sep: Optional separator character.
* \return true if succeeded.
*/
bool BLI_path_suffix(char *path, size_t path_maxncpy, const char *suffix, const char *sep)
ATTR_NONNULL(1, 3, 4);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Path Slash Utilities
* \{ */
/**
* \return pointer to the leftmost path separator in path (or NULL when not found).
*/
const char *BLI_path_slash_find(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* \return pointer to the rightmost path separator in path (or NULL when not found).
*/
const char *BLI_path_slash_rfind(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Appends a slash to path if there isn't one there already.
* Returns the new length of the path.
*/
int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1);
/**
* Removes the last slash and everything after it to the end of path, if there is one.
*/
void BLI_path_slash_rstrip(char *path) ATTR_NONNULL(1);
/**
* Changes to the path separators to the native ones for this OS.
*/
void BLI_path_slash_native(char *path) ATTR_NONNULL(1);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Path Directory/FileName Split
* \{ */
/**
* Copies directory and file components from `filepath` into `dir` and `file`, e.g.
@ -58,17 +250,20 @@ void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy
*/
void BLI_path_split_file_part(const char *filepath, char *file, size_t file_maxncpy)
ATTR_NONNULL(1, 2);
/**
* Returns a pointer to the last extension (e.g. the position of the last period).
* Returns a pointer to the nil byte when no extension is found.
* Like Python's `os.path.basename()`
*
* \return The pointer into \a path string immediately after last slash,
* or start of \a path if none found.
*/
const char *BLI_path_extension_or_end(const char *filepath)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
/**
* Returns a pointer to the last extension (e.g. the position of the last period).
* Returns NULL if there is no extension.
*/
const char *BLI_path_extension(const char *filepath) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
const char *BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/** \} */
/* -------------------------------------------------------------------- */
/** \name Path Append
* \{ */
/**
* Append a filename to a dir, ensuring slash separates.
@ -83,6 +278,12 @@ size_t BLI_path_append(char *__restrict dst, size_t dst_maxncpy, const char *__r
size_t BLI_path_append_dir(char *__restrict dst, size_t dst_maxncpy, const char *__restrict dir)
ATTR_NONNULL(1, 3);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Path Join
* \{ */
/**
* See #BLI_path_join doc-string.
*/
@ -192,65 +393,23 @@ BLI_INLINE size_t _BLI_path_join_12(_BLI_PATH_JOIN_ARGS_10)
#undef _BLI_PATH_JOIN_ARGS_9
#undef _BLI_PATH_JOIN_ARGS_10
/**
* Like Python's `os.path.basename()`
*
* \return The pointer into \a path string immediately after last slash,
* or start of \a path if none found.
*/
const char *BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Get an element of the path at an index, eg:
* `/some/path/file.txt` where an index of:
* - 0 or -3: `some`
* - 1 or -2: `path`
* - 2 or -1: `file.txt`
*
* Ignored elements in the path:
* - Multiple slashes at any point in the path (including start/end).
* - Single '.' in the path: `/./` except for the beginning of the path
* where it's used to signify a $PWD relative path.
*/
bool BLI_path_name_at_index(const char *__restrict path,
int index,
int *__restrict r_offset,
int *__restrict r_len) ATTR_NONNULL(1, 3, 4) ATTR_WARN_UNUSED_RESULT;
/** \} */
/** Return true only if #containee_path is contained in #container_path. */
bool BLI_path_contains(const char *container_path, const char *containee_path)
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
/* -------------------------------------------------------------------- */
/** \name Path File Extensions
* \{ */
/**
* \return pointer to the leftmost path separator in path (or NULL when not found).
* Returns a pointer to the last extension (e.g. the position of the last period).
* Returns a pointer to the nil byte when no extension is found.
*/
const char *BLI_path_slash_find(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
const char *BLI_path_extension_or_end(const char *filepath)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
/**
* \return pointer to the rightmost path separator in path (or NULL when not found).
* Returns a pointer to the last extension (e.g. the position of the last period).
* Returns NULL if there is no extension.
*/
const char *BLI_path_slash_rfind(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Appends a slash to path if there isn't one there already.
* Returns the new length of the path.
*/
int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1);
/**
* Removes the last slash and everything after it to the end of path, if there is one.
*/
void BLI_path_slash_rstrip(char *path) ATTR_NONNULL(1);
/**
* Changes to the path separators to the native ones for this OS.
*/
void BLI_path_slash_native(char *path) ATTR_NONNULL(1);
#ifdef _WIN32
bool BLI_path_program_extensions_add_win32(char *program_name, size_t program_name_maxncpy);
#endif
/**
* Search for a binary (executable)
*/
bool BLI_path_program_search(char *program_filepath,
size_t program_filepath_maxncpy,
const char *program_name) ATTR_NONNULL(1, 3);
const char *BLI_path_extension(const char *filepath) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* \return true when `path` end with `ext` (case insensitive).
@ -295,230 +454,12 @@ bool BLI_path_extension_strip(char *path) ATTR_NONNULL(1);
*/
bool BLI_path_extension_ensure(char *path, size_t path_maxncpy, const char *ext)
ATTR_NONNULL(1, 3);
/**
* Ensure `filepath` has a file component, adding `filename` when it's empty or ends with a slash.
* \return true if the `filename` was appended to `filepath`.
*/
bool BLI_path_filename_ensure(char *filepath, size_t filepath_maxncpy, const char *filename)
ATTR_NONNULL(1, 3);
/**
* Looks for a sequence of decimal digits in `path`, preceding any filename extension,
* returning the integer value if found, or 0 if not.
*
* \param path: String to scan.
* \param head: Optional area to return copy of part of `path` prior to digits,
* or before dot if no digits.
* \param tail: Optional area to return copy of part of `path` following digits,
* or from dot if no digits.
* \param r_digits_len: Optional to return number of digits found.
*/
int BLI_path_sequence_decode(const char *path,
char *head,
size_t head_maxncpy,
char *tail,
size_t tail_maxncpy,
unsigned short *r_digits_len);
/**
* Returns in area pointed to by `path` a string of the form `<head><pic><tail>`,
* where pic is formatted as `numlen` digits with leading zeroes.
*/
void BLI_path_sequence_encode(char *path,
size_t path_maxncpy,
const char *head,
const char *tail,
unsigned short numlen,
int pic);
/**
* Remove redundant characters from \a path.
*
* 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.
*
* 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);
/**
* Cleanup file-path ensuring a trailing slash.
*
* \note Same as #BLI_path_normalize but adds a trailing slash.
*/
void BLI_path_normalize_dir(char *dir, size_t dir_maxncpy) ATTR_NONNULL(1);
/** \} */
/**
* Make given name safe to be used in paths.
*
* \param allow_tokens: Permit the usage of '<' and '>' characters. This can be
* leveraged by higher layers to support "virtual filenames" which contain
* substitution markers delineated between the two characters.
*
* \return true if \a fname was changed, false otherwise.
*
* For now, simply replaces reserved chars (as listed in
* https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
* by underscores ('_').
*
* \note Space case ' ' is a bit of an edge case here - in theory it is allowed,
* but again can be an issue in some cases, so we simply replace it by an underscore too
* (good practice anyway).
* REMOVED based on popular demand (see #45900).
* Percent '%' char is a bit same case - not recommended to use it,
* but supported by all decent file-systems/operating-systems around.
*
* \note On Windows, it also ensures there is no '.' (dot char) at the end of the file,
* this can lead to issues.
*
* \note On Windows, it also checks for forbidden names
* (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
*/
bool BLI_path_make_safe_filename_ex(char *fname, bool allow_tokens) ATTR_NONNULL(1);
bool BLI_path_make_safe_filename(char *fname) ATTR_NONNULL(1);
/**
* Make given path OS-safe.
*
* \return true if \a path was changed, false otherwise.
*/
bool BLI_path_make_safe(char *path) ATTR_NONNULL(1);
/**
* Go back one directory.
*
* Replaces path with the path of its parent directory, returning true if
* it was able to find a parent directory within the path.
*
* On success, the resulting path will always have a trailing slash.
*/
bool BLI_path_parent_dir(char *path) ATTR_NONNULL(1);
/**
* Go back until the directory is found.
*
* Strips off nonexistent (or non-accessible) sub-directories from the end of `dir`,
* leaving the path of the lowest-level directory that does exist and we can read.
*/
bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL(1);
/**
* In the simple case this is similar to `BLI_path_slash_rfind(dirname)`
* however it behaves differently when there are redundant characters:
*
* `/test///dir/./file`
* ^
* `/test/dir/subdir//file`
* ^
* \return The position after the parent paths last character or NULL on failure.
* Neither `path` or `&path[path_len - 1]` are ever returned.
*/
const char *BLI_path_parent_dir_end(const char *path, size_t path_len)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* If path begins with "//", strips that and replaces it with `basepath` directory.
*
* \note Also converts drive-letter prefix to something more sensible
* if this is a non-drive-letter-based system.
*
* \param path: The path to convert.
* \param basepath: The directory to base relative paths with.
* \return true if the path was relative (started with "//").
*/
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL(1, 2);
/**
* Replaces "#" character sequence in last slash-separated component of `path`
* with frame as decimal integer, with leading zeroes as necessary, to make digits.
*/
bool BLI_path_frame(char *path, size_t path_maxncpy, int frame, int digits) ATTR_NONNULL(1);
/**
* Replaces "#" character sequence in last slash-separated component of `path`
* with sta and end as decimal integers, with leading zeroes as necessary, to make digits
* digits each, with a hyphen in-between.
*/
bool BLI_path_frame_range(char *path, int sta, int end, int digits) ATTR_NONNULL(1);
/**
* Get the frame from a filename formatted by blender's frame scheme
*/
bool BLI_path_frame_get(const char *path, int *r_frame, int *r_digits_len) ATTR_NONNULL(1, 2, 3);
/**
* Given a `path` with digits representing frame numbers, replace the digits with the '#'
* character and extract the extension.
* So: `/some/path_123.jpeg`
* Becomes: `/some/path_###` with `r_ext` set to `.jpeg`.
*/
void BLI_path_frame_strip(char *path, char *r_ext, size_t ext_maxncpy) ATTR_NONNULL(1, 2);
/**
* Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
*/
bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Checks for a relative path (ignoring Blender's "//") prefix
* (unlike `!BLI_path_is_rel(path)`).
* When false, #BLI_path_abs_from_cwd would expand the absolute path.
*/
bool BLI_path_is_abs_from_cwd(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Checks for relative path, expanding them relative to the current working directory.
* \returns true if the expansion was performed.
*
* \note Should only be called with command line paths.
* This is _not_ something Blender's internal paths support, instead they use the "//" prefix.
* In most cases #BLI_path_abs should be used instead.
*/
bool BLI_path_abs_from_cwd(char *path, size_t path_maxncpy) ATTR_NONNULL(1);
/**
* Replaces `file` with a relative version (prefixed by "//") such that #BLI_path_abs, given
* the same `basename`, will convert it back to its original value.
*/
void BLI_path_rel(char *path, const char *basename) ATTR_NONNULL(1);
/**
* Does path begin with the special "//" prefix that Blender uses to indicate
* a path relative to the .blend file.
*/
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Return true if the path is a UNC share.
*/
bool BLI_path_is_unc(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Creates a display string from path to be used menus and the user interface.
* Like `bpy.path.display_name()`.
*/
void BLI_path_to_display_name(char *display_name, int display_name_maxncpy, const char *name)
ATTR_NONNULL(1, 3);
#if defined(WIN32)
void BLI_path_normalize_unc_16(wchar_t *path_16);
void BLI_path_normalize_unc(char *path, int path_maxncpy);
#endif
/**
* Appends a suffix to the `path`, fitting it before the extension
*
* path = `Foo.png`, suffix = `123`, separator = `_`.
* `Foo.png` -> `Foo_123.png`.
*
* \param path: original (and final) string.
* \param path_maxncpy: Maximum length of path.
* \param suffix: String to append to the original path.
* \param sep: Optional separator character.
* \return true if succeeded.
*/
bool BLI_path_suffix(char *path, size_t path_maxncpy, const char *suffix, const char *sep)
ATTR_NONNULL(1, 3, 4);
/* -------------------------------------------------------------------- */
/** \name Path Comparison / Contains
* \{ */
/* Path string comparisons: case-insensitive for Windows, case-sensitive otherwise. */
#if defined(WIN32)
@ -543,14 +484,172 @@ bool BLI_path_suffix(char *path, size_t path_maxncpy, const char *suffix, const
int BLI_path_cmp_normalized(const char *p1, const char *p2)
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
/* These values need to be hard-coded in structs, dna does not recognize defines */
/* also defined in `DNA_space_types.h`. */
/** Return true only if #containee_path is contained in #container_path. */
bool BLI_path_contains(const char *container_path, const char *containee_path)
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
/** \} */
/* -------------------------------------------------------------------- */
/** \name Program Specific Path Functions
* \{ */
#ifdef _WIN32
bool BLI_path_program_extensions_add_win32(char *program_name, size_t program_name_maxncpy);
#endif
/**
* Search for a binary (executable)
*/
bool BLI_path_program_search(char *program_filepath,
size_t program_filepath_maxncpy,
const char *program_name) ATTR_NONNULL(1, 3);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Blender Specific Frame Sequence Encode/Decode
* \{ */
/**
* Returns in area pointed to by `path` a string of the form `<head><pic><tail>`,
* where pic is formatted as `numlen` digits with leading zeroes.
*/
void BLI_path_sequence_encode(char *path,
size_t path_maxncpy,
const char *head,
const char *tail,
unsigned short numlen,
int pic);
/**
* Looks for a sequence of decimal digits in `path`, preceding any filename extension,
* returning the integer value if found, or 0 if not.
*
* \param path: String to scan.
* \param head: Optional area to return copy of part of `path` prior to digits,
* or before dot if no digits.
* \param tail: Optional area to return copy of part of `path` following digits,
* or from dot if no digits.
* \param r_digits_len: Optional to return number of digits found.
*/
int BLI_path_sequence_decode(const char *path,
char *head,
size_t head_maxncpy,
char *tail,
size_t tail_maxncpy,
unsigned short *r_digits_len);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Blender Specific Frame Number Apply/Strip
* \{ */
/**
* Replaces "#" character sequence in last slash-separated component of `path`
* with frame as decimal integer, with leading zeroes as necessary, to make digits.
*/
bool BLI_path_frame(char *path, size_t path_maxncpy, int frame, int digits) ATTR_NONNULL(1);
/**
* Replaces "#" character sequence in last slash-separated component of `path`
* with sta and end as decimal integers, with leading zeroes as necessary, to make digits
* digits each, with a hyphen in-between.
*/
bool BLI_path_frame_range(char *path, size_t path_maxncpy, int sta, int end, int digits)
ATTR_NONNULL(1);
/**
* Get the frame from a filename formatted by blender's frame scheme
*/
bool BLI_path_frame_get(const char *path, int *r_frame, int *r_digits_len) ATTR_NONNULL(1, 2, 3);
/**
* Given a `path` with digits representing frame numbers, replace the digits with the '#'
* character and extract the extension.
* So: `/some/path_123.jpeg`
* Becomes: `/some/path_###` with `r_ext` set to `.jpeg`.
*/
void BLI_path_frame_strip(char *path, char *r_ext, size_t ext_maxncpy) ATTR_NONNULL(1, 2);
/**
* Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
*/
bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/** \} */
/* -------------------------------------------------------------------- */
/** \name Blender Spesific File Relative Paths
* \{ */
/**
* These values need to be hard-coded in structs, dna does not recognize defines
* (also defined in `DNA_space_types.h`).
*
* \note In general path functions should *not* depend on these hard coded limits,
* there is an exception for:
* - #BLI_path_abs
* - #BLI_path_rel
* These functions deal specifically with `.blend` file paths,
* where #FILE_MAX assumed to be the limit of all paths passes into these functions.
*
* Some parts of the API which use #FILE_MAX which aren't specifically handling blend file paths,
* in most cases these can be updated to use #PATH_MAX or a platform specific limit.
*/
#ifndef FILE_MAXDIR
# define FILE_MAXDIR 768
# define FILE_MAXFILE 256
# define FILE_MAX 1024
#endif
/**
* If path begins with "//", strips that and replaces it with `basepath` directory.
*
* \note Also converts drive-letter prefix to something more sensible
* if this is a non-drive-letter-based system.
*
* \param path: The path to convert.
* \param basepath: The directory to base relative paths with.
* \return true if the path was relative (started with "//").
*/
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1, 2);
/**
* Replaces `path` with a relative version (prefixed by "//") such that #BLI_path_abs, given
* the same `basepath`, will convert it back to its original value.
*/
void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1);
/**
* Does path begin with the special "//" prefix that Blender uses to indicate
* a path relative to the .blend file.
*/
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/** \} */
/* -------------------------------------------------------------------- */
/** \name Current Working Directory Specific Paths
* \{ */
/**
* Checks for a relative path (ignoring Blender's "//") prefix
* (unlike `!BLI_path_is_rel(path)`).
* When false, #BLI_path_abs_from_cwd would expand the absolute path.
*/
bool BLI_path_is_abs_from_cwd(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Checks for relative path, expanding them relative to the current working directory.
* \returns true if the expansion was performed.
*
* \note Should only be called with command line paths.
* This is _not_ something Blender's internal paths support, instead they use the "//" prefix.
* In most cases #BLI_path_abs should be used instead.
*/
bool BLI_path_abs_from_cwd(char *path, size_t path_maxncpy) ATTR_NONNULL(1);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Native Slash Defines & Checks
* \{ */
#ifdef WIN32
# define SEP '\\'
# define ALTSEP '/'
@ -581,6 +680,42 @@ BLI_INLINE bool BLI_path_slash_is_native_compat(const char ch)
return false;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name OS Level Wrappers
*
* TODO: move these to a different module, they are not path functions.
* \{ */
/**
* Sets the specified environment variable to the specified value,
* and clears it if `val == NULL`.
*/
void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1);
/**
* Only set an environment variable if already not there.
* Like Unix `setenv(env, val, 0);`
*
* (not used anywhere).
*/
void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
/**
* Get an environment variable, result has to be used immediately.
*
* On windows #getenv gets its variables from a static copy of the environment variables taken at
* process start-up, causing it to not pick up on environment variables created during runtime.
* This function uses an alternative method to get environment variables that does pick up on
* runtime environment variables. The result will be UTF-8 encoded.
*/
const char *BLI_getenv(const char *env) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/** \} */
/* -------------------------------------------------------------------- */
/** \name Current & Parent Directory Defines/Macros
* \{ */
/* Parent and current dir helpers. */
#define FILENAME_PARENT ".."
#define FILENAME_CURRENT "."
@ -591,6 +726,8 @@ BLI_INLINE bool BLI_path_slash_is_native_compat(const char ch)
#define FILENAME_IS_CURRPAR(_n) \
(((_n)[0] == '.') && (((_n)[1] == '\0') || (((_n)[1] == '.') && ((_n)[2] == '\0'))))
/** \} */
#ifdef __cplusplus
}
#endif

View File

@ -191,6 +191,15 @@ bool BLI_str_replace_table_exact(char *string,
const char *replace_table[][2],
int replace_table_len);
/**
* Write `dst` into the range between `src_beg` & `src_end`,
* resize within `string_maxncpy` limits, ensure null terminated.
*
* \return the length of `string`.
*/
size_t BLI_str_replace_range(
char *string, size_t string_maxncpy, int src_beg, int src_end, const char *dst);
/**
* Portable replacement for #snprintf
*/

View File

@ -42,6 +42,26 @@ void BLI_str_cursor_step_utf32(const char32_t *str,
eStrCursorJumpType jump,
bool use_init_step);
/**
* Given a position within a string,
* return the start and end of the closest sequence of delimited characters.
* Typically a word, but can be a sequence of characters (including spaces).
*
* \note When used for word-selection the caller should set the cursor to `r_end` (by convention).
*
* \param str: The string with a cursor position
* \param str_maxlen: The maximum characters to consider
* \param pos: The starting cursor position.
* \param r_start: returned start of word/sequence boundary (0-based)
* \param r_end: returned end of word/sequence boundary (0-based)
*/
void BLI_str_cursor_step_bounds_utf8(
const char *str, const size_t str_maxlen, int pos, int *r_start, int *r_end);
/** A UTF32 version of #BLI_str_cursor_step_bounds_utf8 */
void BLI_str_cursor_step_bounds_utf32(
const char32_t *str, const size_t str_maxlen, int pos, int *r_start, int *r_end);
#ifdef __cplusplus
}
#endif

View File

@ -45,6 +45,14 @@ static int BLI_path_unc_prefix_len(const char *path);
static bool BLI_path_is_abs_win32(const char *path);
#endif /* WIN32 */
/**
* The maximum number of `#` characters expanded for #BLI_path_frame & #BLI_path_frame_range
* Typically 12 is enough and even 16 is very large.
* Use a much larger value so hitting the upper limit is not an issue.
* Exceeding this limit won't fail either, it will just not insert so many leading zeros.
*/
#define FILENAME_FRAME_CHARS_MAX FILE_MAX
int BLI_path_sequence_decode(const char *path,
char *head,
const size_t head_maxncpy,
@ -89,7 +97,7 @@ int BLI_path_sequence_decode(const char *path,
const long long int ret = strtoll(&(path[nums]), NULL, 10);
if (ret >= INT_MIN && ret <= INT_MAX) {
if (tail) {
strcpy(tail, &path[nume + 1]);
BLI_strncpy(tail, &path[nume + 1], tail_maxncpy);
}
if (head) {
BLI_strncpy(head, path, MIN2(head_maxncpy, nums + 1));
@ -584,7 +592,7 @@ void BLI_path_normalize_unc_16(wchar_t *path_16)
}
#endif
void BLI_path_rel(char *path, const char *basename)
void BLI_path_rel(char path[FILE_MAX], const char *basepath)
{
BLI_string_debug_size_after_nil(path, FILE_MAX);
@ -598,24 +606,24 @@ void BLI_path_rel(char *path, const char *basename)
}
/* Also bail out if relative path is not set. */
if (basename[0] == '\0') {
if (basepath[0] == '\0') {
return;
}
#ifdef WIN32
if (BLI_strnlen(basename, 3) > 2 && !BLI_path_is_abs_win32(basename)) {
if (BLI_strnlen(basepath, 3) > 2 && !BLI_path_is_abs_win32(basepath)) {
char *ptemp;
/* Fix missing volume name in relative base,
* can happen with old `recent-files.txt` files. */
BLI_windows_get_default_root_dir(temp);
ptemp = &temp[2];
if (!ELEM(basename[0], '\\', '/')) {
if (!ELEM(basepath[0], '\\', '/')) {
ptemp++;
}
BLI_strncpy(ptemp, basename, FILE_MAX - 3);
BLI_strncpy(ptemp, basepath, FILE_MAX - 3);
}
else {
BLI_strncpy(temp, basename, FILE_MAX);
BLI_strncpy(temp, basepath, FILE_MAX);
}
if (BLI_strnlen(path, 3) > 2) {
@ -645,7 +653,7 @@ void BLI_path_rel(char *path, const char *basename)
}
}
#else
STRNCPY(temp, basename);
STRNCPY(temp, basepath);
#endif
BLI_str_replace_char(temp + BLI_path_unc_prefix_len(temp), '\\', '/');
@ -819,9 +827,14 @@ bool BLI_path_parent_dir_until_exists(char *dir)
/**
* Looks for a sequence of "#" characters in the last slash-separated component of `path`,
* returning the indexes of the first and one past the last character in the sequence in
* `char_start` and `char_end` respectively. Returns true if such a sequence was found.
* `char_start` and `char_end` respectively.
*
* \param char_start: The first `#` character.
* \param char_end: The last `#` character +1.
*
* \return true if a frame sequence range was found.
*/
static bool stringframe_chars(const char *path, int *char_start, int *char_end)
static bool path_frame_chars_find_range(const char *path, int *char_start, int *char_end)
{
uint ch_sta, ch_end, i;
/* Insert current frame: `file###` -> `file001`. */
@ -885,18 +898,19 @@ bool BLI_path_frame(char *path, size_t path_maxncpy, int frame, int digits)
ensure_digits(path, digits);
}
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* Warning: `ch_end` is the last # +1. */
char tmp[FILE_MAX];
SNPRINTF(tmp, "%.*s%.*d%s", ch_sta, path, ch_end - ch_sta, frame, path + ch_end);
BLI_strncpy(path, tmp, path_maxncpy);
if (path_frame_chars_find_range(path, &ch_sta, &ch_end)) {
char frame_str[FILENAME_FRAME_CHARS_MAX + 1]; /* One for null. */
const int ch_span = MIN2(ch_end - ch_sta, FILENAME_FRAME_CHARS_MAX);
BLI_snprintf(frame_str, sizeof(frame_str), "%.*d", ch_span, frame);
BLI_str_replace_range(path, path_maxncpy, ch_sta, ch_end, frame_str);
return true;
}
return false;
}
bool BLI_path_frame_range(char *path, int sta, int end, int digits)
bool BLI_path_frame_range(char *path, size_t path_maxncpy, int sta, int end, int digits)
{
BLI_string_debug_size_after_nil(path, FILE_MAX);
BLI_string_debug_size_after_nil(path, path_maxncpy);
int ch_sta, ch_end;
@ -904,18 +918,11 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits)
ensure_digits(path, digits);
}
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* Warning: `ch_end` is the last # +1. */
char tmp[FILE_MAX];
SNPRINTF(tmp,
"%.*s%.*d-%.*d%s",
ch_sta,
path,
ch_end - ch_sta,
sta,
ch_end - ch_sta,
end,
path + ch_end);
BLI_strncpy(path, tmp, FILE_MAX);
if (path_frame_chars_find_range(path, &ch_sta, &ch_end)) {
char frame_str[(FILENAME_FRAME_CHARS_MAX * 2) + 1 + 1]; /* One for null, one for the '-' */
const int ch_span = MIN2(ch_end - ch_sta, FILENAME_FRAME_CHARS_MAX);
BLI_snprintf(frame_str, sizeof(frame_str), "%.*d-%.*d", ch_span, sta, ch_span, end);
BLI_str_replace_range(path, path_maxncpy, ch_sta, ch_end, frame_str);
return true;
}
return false;
@ -981,7 +988,7 @@ void BLI_path_frame_strip(char *path, char *r_ext, const size_t ext_maxncpy)
bool BLI_path_frame_check_chars(const char *path)
{
int ch_sta_dummy, ch_end_dummy;
return stringframe_chars(path, &ch_sta_dummy, &ch_end_dummy);
return path_frame_chars_find_range(path, &ch_sta_dummy, &ch_end_dummy);
}
void BLI_path_to_display_name(char *display_name, int display_name_maxncpy, const char *name)
@ -1023,7 +1030,7 @@ void BLI_path_to_display_name(char *display_name, int display_name_maxncpy, cons
}
}
bool BLI_path_abs(char *path, const char *basepath)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath)
{
BLI_string_debug_size_after_nil(path, FILE_MAX);
@ -1146,10 +1153,10 @@ bool BLI_path_abs_from_cwd(char *path, const size_t path_maxncpy)
BLI_string_debug_size_after_nil(path, path_maxncpy);
if (!BLI_path_is_abs_from_cwd(path)) {
char cwd[FILE_MAX];
char cwd[PATH_MAX];
/* In case the full path to the blend isn't used. */
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
char origpath[FILE_MAX];
char origpath[PATH_MAX];
STRNCPY(origpath, path);
BLI_path_join(path, path_maxncpy, cwd, origpath);
}
@ -1232,7 +1239,7 @@ bool BLI_path_program_search(char *program_filepath,
path = BLI_getenv("PATH");
if (path) {
char filepath_test[FILE_MAX];
char filepath_test[PATH_MAX];
const char *temp;
do {
@ -1484,13 +1491,13 @@ bool BLI_path_extension_ensure(char *path, size_t path_maxncpy, const char *ext)
return true;
}
bool BLI_path_filename_ensure(char *filepath, size_t filepath_maxncpy, const char *file)
bool BLI_path_filename_ensure(char *filepath, size_t filepath_maxncpy, const char *filename)
{
BLI_string_debug_size_after_nil(filepath, filepath_maxncpy);
char *c = (char *)BLI_path_slash_rfind(filepath);
if (!c || ((c - filepath) < filepath_maxncpy - (strlen(file) + 1))) {
strcpy(c ? &c[1] : filepath, file);
char *c = (char *)BLI_path_basename(filepath);
const size_t filename_size = strlen(filename) + 1;
if (filename_size <= filepath_maxncpy - (c - filepath)) {
memcpy(c, filename, filename_size);
return true;
}
return false;
@ -1911,11 +1918,17 @@ int BLI_path_cmp_normalized(const char *p1, const char *p2)
BLI_assert_msg(!BLI_path_is_rel(p1) && !BLI_path_is_rel(p2), "Paths arguments must be absolute");
/* Normalize the paths so we can compare them. */
char norm_p1[FILE_MAX];
char norm_p2[FILE_MAX];
char norm_p1_buf[256];
char norm_p2_buf[256];
STRNCPY(norm_p1, p1);
STRNCPY(norm_p2, p2);
const size_t p1_size = strlen(p1) + 1;
const size_t p2_size = strlen(p2) + 1;
char *norm_p1 = (p1_size <= sizeof(norm_p1_buf)) ? norm_p1_buf : MEM_mallocN(p1_size, __func__);
char *norm_p2 = (p2_size <= sizeof(norm_p2_buf)) ? norm_p2_buf : MEM_mallocN(p2_size, __func__);
memcpy(norm_p1, p1, p1_size);
memcpy(norm_p2, p2, p2_size);
BLI_path_slash_native(norm_p1);
BLI_path_slash_native(norm_p2);
@ -1923,5 +1936,13 @@ int BLI_path_cmp_normalized(const char *p1, const char *p2)
BLI_path_normalize(norm_p1);
BLI_path_normalize(norm_p2);
return BLI_path_cmp(norm_p1, norm_p2);
const int result = BLI_path_cmp(norm_p1, norm_p2);
if (norm_p1 != norm_p1_buf) {
MEM_freeN(norm_p1);
}
if (norm_p2 != norm_p2_buf) {
MEM_freeN(norm_p2);
}
return result;
}

View File

@ -552,6 +552,55 @@ bool BLI_str_replace_table_exact(char *string,
return false;
}
size_t BLI_str_replace_range(
char *string, size_t string_maxncpy, int src_beg, int src_end, const char *dst)
{
int string_len = strlen(string);
BLI_assert(src_beg <= src_end);
BLI_assert(src_end <= string_len);
const int src_len = src_end - src_beg;
int dst_len = strlen(dst);
if (src_len < dst_len) {
/* Grow, first handle special cases. */
/* Special case, the src_end is entirely clipped. */
if (UNLIKELY(string_maxncpy <= src_beg + dst_len)) {
/* There is only room for the destination. */
dst_len = ((int)string_maxncpy - src_beg) - 1;
string_len = src_end;
string[string_len] = '\0';
}
const int ofs = dst_len - src_len;
/* Clip the string when inserting the destination string exceeds `string_maxncpy`. */
if (string_len + ofs >= string_maxncpy) {
string_len = ((int)string_maxncpy - ofs) - 1;
string[string_len] = '\0';
BLI_assert(src_end <= string_len);
}
/* Grow. */
memmove(string + (src_end + ofs), string + src_end, (size_t)(string_len - src_end) + 1);
string_len += ofs;
}
else if (src_len > dst_len) {
/* Shrink. */
const int ofs = src_len - dst_len;
memmove(string + (src_end - ofs), string + src_end, (size_t)(string_len - src_end) + 1);
string_len -= ofs;
}
else { /* Simple case, no resizing. */
BLI_assert(src_len == dst_len);
}
if (dst_len > 0) {
memcpy(string + src_beg, dst, (size_t)dst_len);
}
BLI_assert(string[string_len] == '\0');
return (size_t)string_len;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -17,6 +17,18 @@
# pragma GCC diagnostic error "-Wsign-conversion"
#endif
/**
* The category of character as returned by #cursor_delim_type_unicode.
*
* \note Don't compare with any values besides #STRCUR_DELIM_NONE as cursor motion
* should only delimit on changes, not treat some groups differently.
*
* For range calculation the order prioritizes expansion direction,
* when the cursor is between two different categories, "hug" the smaller values.
* Where white-space gets lowest priority. See #BLI_str_cursor_step_bounds_utf8.
* This is done so expanding the range at a word boundary always chooses the word instead
* of the white-space before or after it.
*/
typedef enum eStrCursorDelimType {
STRCUR_DELIM_NONE,
STRCUR_DELIM_ALPHANUMERIC,
@ -24,8 +36,8 @@ typedef enum eStrCursorDelimType {
STRCUR_DELIM_BRACE,
STRCUR_DELIM_OPERATOR,
STRCUR_DELIM_QUOTE,
STRCUR_DELIM_WHITESPACE,
STRCUR_DELIM_OTHER,
STRCUR_DELIM_WHITESPACE,
} eStrCursorDelimType;
static eStrCursorDelimType cursor_delim_type_unicode(const uint uch)
@ -314,3 +326,46 @@ void BLI_str_cursor_step_utf32(const char32_t *str,
BLI_assert_unreachable();
}
}
void BLI_str_cursor_step_bounds_utf8(
const char *str, const size_t str_maxlen, const int pos, int *r_start, int *r_end)
{
/* Identify the type of characters are on either side of the current cursor position. */
const eStrCursorDelimType prev = (pos > 0) ? cursor_delim_type_utf8(str, str_maxlen, pos - 1) :
STRCUR_DELIM_NONE;
const eStrCursorDelimType next = (pos < str_maxlen) ?
cursor_delim_type_utf8(str, str_maxlen, pos) :
STRCUR_DELIM_NONE;
*r_start = pos;
*r_end = pos;
if ((prev <= next) && (prev != STRCUR_DELIM_NONE)) {
/* Expand backward if we are between similar content. */
BLI_str_cursor_step_utf8(str, str_maxlen, r_start, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, false);
}
if ((prev >= next) && (next != STRCUR_DELIM_NONE)) {
/* Expand forward if we are between similar content, after whitespace, or at beginning. */
BLI_str_cursor_step_utf8(str, str_maxlen, r_end, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, false);
}
}
void BLI_str_cursor_step_bounds_utf32(
const char32_t *str, const size_t str_maxlen, const int pos, int *r_start, int *r_end)
{
/* Identify the type of characters are on either side of the current cursor position. */
const eStrCursorDelimType prev = (pos > 0) ? cursor_delim_type_unicode(str[pos - 1]) :
STRCUR_DELIM_NONE;
const eStrCursorDelimType next = (pos < str_maxlen) ? cursor_delim_type_unicode(str[pos]) :
STRCUR_DELIM_NONE;
*r_start = pos;
*r_end = pos;
if ((prev <= next) && (prev != STRCUR_DELIM_NONE)) {
/* Expand backward if we are between similar content, before whitespace, or at end. */
BLI_str_cursor_step_utf32(str, str_maxlen, r_start, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, false);
}
if ((prev >= next) && (next != STRCUR_DELIM_NONE)) {
/* Expand forward if we are between similar content, after whitespace, or at beginning. */
BLI_str_cursor_step_utf32(str, str_maxlen, r_end, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, false);
}
}

View File

@ -638,6 +638,15 @@ TEST(path_util, Frame)
EXPECT_TRUE(ret);
EXPECT_STREQ(path, "test_-0100");
}
/* Ensure very large ranges work. */
{
char path[FILE_MAX * 2];
memset(path, '#', sizeof(path));
path[sizeof(path) - 1] = '\0';
ret = BLI_path_frame(path, sizeof(path), 123456789, 0);
EXPECT_TRUE(BLI_str_endswith(path, "0123456789"));
}
}
/** \} */
@ -987,7 +996,7 @@ TEST(path_util, FrameCheckChars)
char path[FILE_MAX]; \
bool ret; \
STRNCPY(path, input_path); \
ret = BLI_path_frame_range(path, sta, end, digits); \
ret = BLI_path_frame_range(path, sizeof(path), sta, end, digits); \
if (expect_outpath == nullptr) { \
EXPECT_FALSE(ret); \
} \

View File

@ -122,6 +122,47 @@ TEST(string, StrCopyUTF8_TerminateEncodingEarly)
/** \} */
/* -------------------------------------------------------------------- */
/** \name String Replace
* \{ */
TEST(string, StrReplaceRange)
{
#define STR_REPLACE_RANGE(src, size, beg, end, dst, result_expect) \
{ \
char string[size] = src; \
BLI_str_replace_range(string, sizeof(string), beg, end, dst); \
EXPECT_STREQ(string, result_expect); \
}
STR_REPLACE_RANGE("a ", 5, 2, 2, "b!", "a b!");
STR_REPLACE_RANGE("a ", 4, 2, 2, "b!", "a b");
STR_REPLACE_RANGE("a ", 5, 1, 2, "b!", "ab!");
STR_REPLACE_RANGE("XYZ", 5, 1, 1, "A", "XAYZ");
STR_REPLACE_RANGE("XYZ", 5, 1, 1, "AB", "XABY");
STR_REPLACE_RANGE("XYZ", 5, 1, 1, "ABC", "XABC");
/* Add at the end when there is no room (no-op). */
STR_REPLACE_RANGE("XYZA", 5, 4, 4, "?", "XYZA");
/* Add at the start, replace all contents. */
STR_REPLACE_RANGE("XYZ", 4, 0, 0, "ABC", "ABC");
STR_REPLACE_RANGE("XYZ", 7, 0, 0, "ABC", "ABCXYZ");
/* Only remove. */
STR_REPLACE_RANGE("XYZ", 4, 1, 3, "", "X");
STR_REPLACE_RANGE("XYZ", 4, 0, 2, "", "Z");
STR_REPLACE_RANGE("XYZ", 4, 0, 3, "", "");
/* Only Add. */
STR_REPLACE_RANGE("", 4, 0, 0, "XYZ", "XYZ");
STR_REPLACE_RANGE("", 4, 0, 0, "XYZ?", "XYZ");
/* Do nothing. */
STR_REPLACE_RANGE("", 1, 0, 0, "?", "");
STR_REPLACE_RANGE("", 1, 0, 0, "", "");
#undef STR_REPLACE_RANGE
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name String Partition
* \{ */

View File

@ -239,7 +239,8 @@ static const char *library_parent_filepath(Library *lib)
struct NewAddress {
void *newp;
/* `nr` is "user count" for data, and ID code for libdata. */
/** `nr` is "user count" for data, and ID code for libdata. */
int nr;
};
@ -261,9 +262,9 @@ static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr,
onm->map.add_overwrite(oldaddr, NewAddress{newaddr, nr});
}
static void oldnewmap_lib_insert(FileData *fd, const void *oldaddr, ID *newaddr, int nr)
static void oldnewmap_lib_insert(FileData *fd, const void *oldaddr, ID *newaddr, int id_code)
{
oldnewmap_insert(fd->libmap, oldaddr, newaddr, nr);
oldnewmap_insert(fd->libmap, oldaddr, newaddr, id_code);
}
void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
@ -1297,8 +1298,8 @@ void blo_filedata_free(FileData *fd)
if (fd->libmap && !(fd->flags & FD_FLAGS_NOT_MY_LIBMAP)) {
oldnewmap_free(fd->libmap);
}
if (fd->old_idmap != nullptr) {
BKE_main_idmap_destroy(fd->old_idmap);
if (fd->old_idmap_uuid != nullptr) {
BKE_main_idmap_destroy(fd->old_idmap_uuid);
}
blo_cache_storage_end(fd);
if (fd->bheadmap) {
@ -1533,10 +1534,10 @@ void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
void blo_make_old_idmap_from_main(FileData *fd, Main *bmain)
{
if (fd->old_idmap != nullptr) {
BKE_main_idmap_destroy(fd->old_idmap);
if (fd->old_idmap_uuid != nullptr) {
BKE_main_idmap_destroy(fd->old_idmap_uuid);
}
fd->old_idmap = BKE_main_idmap_create(bmain, false, nullptr, MAIN_IDMAP_TYPE_UUID);
fd->old_idmap_uuid = BKE_main_idmap_create(bmain, false, nullptr, MAIN_IDMAP_TYPE_UUID);
}
struct BLOCacheStorage {
@ -1898,7 +1899,7 @@ static void direct_link_id_override_property_cb(BlendDataReader *reader, void *d
}
static void direct_link_id_common(
BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int tag);
BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int id_tag);
static void direct_link_id_embedded_id(BlendDataReader *reader,
Library *current_library,
@ -1990,7 +1991,7 @@ static int direct_link_id_restore_recalc(const FileData *fd,
}
static void direct_link_id_common(
BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int tag)
BlendDataReader *reader, Library *current_library, ID *id, ID *id_old, const int id_tag)
{
if (!BLO_read_data_is_undo(reader)) {
/* When actually reading a file, we do want to reset/re-generate session UUIDS.
@ -1998,7 +1999,7 @@ static void direct_link_id_common(
id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
}
if ((tag & LIB_TAG_TEMP_MAIN) == 0) {
if ((id_tag & LIB_TAG_TEMP_MAIN) == 0) {
BKE_lib_libblock_session_uuid_ensure(id);
}
@ -2011,10 +2012,10 @@ static void direct_link_id_common(
/* Initialize with provided tag. */
if (BLO_read_data_is_undo(reader)) {
id->tag = tag | (id->tag & LIB_TAG_KEEP_ON_UNDO);
id->tag = (id_tag & ~LIB_TAG_KEEP_ON_UNDO) | (id->tag & LIB_TAG_KEEP_ON_UNDO);
}
else {
id->tag = tag;
id->tag = id_tag;
}
if (ID_IS_LINKED(id)) {
@ -2024,7 +2025,7 @@ static void direct_link_id_common(
BLO_read_data_address(reader, &id->library_weak_reference);
}
if (tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
if (id_tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
/* For placeholder we only need to set the tag and properly initialize generic ID fields above,
* no further data to read. */
return;
@ -3071,13 +3072,13 @@ static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID
/* For undo, restore unchanged datablock from old main. */
static void read_libblock_undo_restore_identical(
FileData *fd, Main *main, const ID * /*id*/, ID *id_old, const int tag)
FileData *fd, Main *main, const ID * /*id*/, ID *id_old, const int id_tag)
{
BLI_assert((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0);
BLI_assert(id_old != nullptr);
/* Some tags need to be preserved here. */
id_old->tag = tag | (id_old->tag & LIB_TAG_KEEP_ON_UNDO);
id_old->tag = (id_tag & ~LIB_TAG_KEEP_ON_UNDO) | (id_old->tag & LIB_TAG_KEEP_ON_UNDO);
id_old->lib = main->curlib;
id_old->us = ID_FAKE_USERS(id_old);
/* Do not reset id->icon_id here, memory allocated for it remains valid. */
@ -3146,7 +3147,7 @@ static void read_libblock_undo_restore_at_old_address(FileData *fd, Main *main,
}
static bool read_libblock_undo_restore(
FileData *fd, Main *main, BHead *bhead, const int tag, ID **r_id_old)
FileData *fd, Main *main, BHead *bhead, int id_tag, ID **r_id_old)
{
/* Get pointer to memory of new ID that we will be reading. */
const ID *id = static_cast<const ID *>(peek_struct_undo(fd, bhead));
@ -3181,8 +3182,8 @@ static bool read_libblock_undo_restore(
/* Find the 'current' existing ID we want to reuse instead of the one we
* would read from the undo memfile. */
BLI_assert(fd->old_idmap != nullptr);
id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid);
BLI_assert(fd->old_idmap_uuid != nullptr);
id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap_uuid, id->session_uuid);
}
if (id_old != nullptr && read_libblock_is_identical(fd, bhead)) {
@ -3198,7 +3199,7 @@ static bool read_libblock_undo_restore(
* it will tell us which ID is re-used from old Main, and which one is actually new. */
/* Also do not add LIB_TAG_NEED_LINK, those IDs will never be re-liblinked, hence that tag will
* never be cleared, leading to critical issue in link/append code. */
const int id_tag = tag | LIB_TAG_UNDO_OLD_ID_REUSED;
id_tag |= LIB_TAG_UNDO_OLD_ID_REUSED_UNCHANGED;
read_libblock_undo_restore_identical(fd, main, id, id_old, id_tag);
/* Insert into library map for lookup by newly read datablocks (with pointer value bhead->old).
@ -3236,7 +3237,7 @@ static bool read_libblock_undo_restore(
static BHead *read_libblock(FileData *fd,
Main *main,
BHead *bhead,
const int tag,
int id_tag,
const bool placeholder_set_indirect_extern,
ID **r_id)
{
@ -3257,7 +3258,7 @@ static BHead *read_libblock(FileData *fd,
* So undo case does not seem to be affected by this. A future cleanup should try to remove
* most of this related code in the future, and instead assert that both `r_id` and
* `main->id_map` are `nullptr`. */
if (read_libblock_undo_restore(fd, main, bhead, tag, &id_old)) {
if (read_libblock_undo_restore(fd, main, bhead, id_tag, &id_old)) {
if (r_id) {
*r_id = id_old;
}
@ -3307,7 +3308,7 @@ static BHead *read_libblock(FileData *fd,
/* Set tag for new datablock to indicate lib linking and versioning needs
* to be done still. */
int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
id_tag |= (LIB_TAG_NEED_LINK | LIB_TAG_NEW);
if (bhead->code == ID_LINK_PLACEHOLDER) {
/* Read placeholder for linked datablock. */
@ -3598,7 +3599,7 @@ static void lib_link_all(FileData *fd, Main *bmain)
}
if ((fd->flags & FD_FLAGS_IS_MEMFILE) && do_partial_undo &&
(id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) != 0)
(id->tag & LIB_TAG_UNDO_OLD_ID_REUSED_UNCHANGED) != 0)
{
/* This ID has been re-used from 'old' bmain. Since it was therefore unchanged across
* current undo step, and old IDs re-use their old memory address, we do not need to liblink
@ -4567,7 +4568,7 @@ static void library_link_end(Main *mainl, FileData **fd, const int flag)
/* Some versioning code does expect some proper userrefcounting, e.g. in conversion from
* groups to collections... We could optimize out that first call when we are reading a
* current version file, but again this is really not a bottle neck currently. so not worth
* current version file, but again this is really not a bottle neck currently. So not worth
* it. */
BKE_main_id_refcount_recompute(mainvar, false);

View File

@ -94,7 +94,14 @@ typedef struct FileData {
struct OldNewMap *datamap;
struct OldNewMap *globmap;
/**
* Store mapping from old ID pointers (the values they have in the .blend file) to new ones,
* typically from value in `bhead->old` to address in memory where the ID was read.
* Used during liblinking process (see #lib_link_all).
*/
struct OldNewMap *libmap;
struct OldNewMap *packedmap;
struct BLOCacheStorage *cache_storage;
@ -107,7 +114,10 @@ typedef struct FileData {
ListBase *mainlist;
/** Used for undo. */
ListBase *old_mainlist;
struct IDNameLib_Map *old_idmap;
/**
* IDMap using uuids as keys of all the old IDs in the old bmain. Used during undo to find a
* matching old data when reading a new ID. */
struct IDNameLib_Map *old_idmap_uuid;
struct BlendFileReadReport *reports;
} FileData;
@ -119,7 +129,7 @@ struct Main;
void blo_join_main(ListBase *mainlist);
void blo_split_main(ListBase *mainlist, struct Main *main);
BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath);
struct BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath);
/**
* On each new library added, it now checks for the current #FileData and expands relativeness

View File

@ -4374,6 +4374,20 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
}
/* Enable the iTaSC ITASC_TRANSLATE_ROOT_BONES flag for backward compatibility.
* See #104606. */
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
if (ob->type != OB_ARMATURE || ob->pose == nullptr) {
continue;
}
bPose *pose = ob->pose;
if (pose->iksolver != IKSOLVER_ITASC || pose->ikparam == nullptr) {
continue;
}
bItasc *ikparam = (bItasc *)pose->ikparam;
ikparam->flag |= ITASC_TRANSLATE_ROOT_BONES;
}
}
/**

View File

@ -73,6 +73,7 @@ set(SRC
cached_resources/intern/cached_mask.cc
cached_resources/intern/cached_texture.cc
cached_resources/intern/morphological_distance_feather_weights.cc
cached_resources/intern/ocio_color_space_conversion_shader.cc
cached_resources/intern/smaa_precomputed_textures.cc
cached_resources/intern/symmetric_blur_weights.cc
cached_resources/intern/symmetric_separable_blur_weights.cc
@ -81,6 +82,7 @@ set(SRC
cached_resources/COM_cached_resource.hh
cached_resources/COM_cached_texture.hh
cached_resources/COM_morphological_distance_feather_weights.hh
cached_resources/COM_ocio_color_space_conversion_shader.hh
cached_resources/COM_smaa_precomputed_textures.hh
cached_resources/COM_symmetric_blur_weights.hh
cached_resources/COM_symmetric_separable_blur_weights.hh
@ -173,6 +175,7 @@ set(GLSL_SRC
shaders/library/gpu_shader_compositor_main.glsl
shaders/library/gpu_shader_compositor_map_value.glsl
shaders/library/gpu_shader_compositor_normal.glsl
shaders/library/gpu_shader_compositor_ocio_processor.glsl
shaders/library/gpu_shader_compositor_posterize.glsl
shaders/library/gpu_shader_compositor_separate_combine.glsl
shaders/library/gpu_shader_compositor_set_alpha.glsl
@ -268,4 +271,18 @@ if(WITH_TBB)
endif()
endif()
if(WITH_OPENCOLORIO)
add_definitions(
-DWITH_OCIO
)
list(APPEND INC_SYS
${OPENCOLORIO_INCLUDE_DIRS}
)
list(APPEND LIB
${OPENCOLORIO_LIBRARIES}
)
endif()
blender_add_lib(bf_realtime_compositor "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@ -5,6 +5,7 @@
#include "COM_cached_mask.hh"
#include "COM_cached_texture.hh"
#include "COM_morphological_distance_feather_weights.hh"
#include "COM_ocio_color_space_conversion_shader.hh"
#include "COM_smaa_precomputed_textures.hh"
#include "COM_symmetric_blur_weights.hh"
#include "COM_symmetric_separable_blur_weights.hh"
@ -41,6 +42,7 @@ class StaticCacheManager {
CachedTextureContainer cached_textures;
CachedMaskContainer cached_masks;
SMAAPrecomputedTexturesContainer smaa_precomputed_textures;
OCIOColorSpaceConversionShaderContainer ocio_color_space_conversion_shaders;
/* Reset the cache manager by deleting the cached resources that are no longer needed because
* they weren't used in the last evaluation and prepare the remaining cached resources to track

View File

@ -0,0 +1,71 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include <cstdint>
#include <string>
#include "COM_cached_resource.hh"
namespace blender::realtime_compositor {
/* ------------------------------------------------------------------------------------------------
* OCIO Color Space Conversion Shader Key.
*/
class OCIOColorSpaceConversionShaderKey {
public:
std::string source;
std::string target;
std::string config_cache_id;
OCIOColorSpaceConversionShaderKey(std::string source,
std::string target,
std::string config_cache_id);
uint64_t hash() const;
};
bool operator==(const OCIOColorSpaceConversionShaderKey &a,
const OCIOColorSpaceConversionShaderKey &b);
class GPUShaderCreator;
/* -------------------------------------------------------------------------------------------------
* OCIO Color Space Conversion Shader.
*
* A cached resource that creates and caches a GPU shader that converts the source OCIO color space
* of an image into a different target OCIO color space. */
class OCIOColorSpaceConversionShader : public CachedResource {
private:
std::shared_ptr<GPUShaderCreator> shader_creator_;
public:
OCIOColorSpaceConversionShader(std::string source, std::string target);
GPUShader *bind_shader_and_resources();
void unbind_shader_and_resources();
const char *input_sampler_name();
const char *output_image_name();
};
/* ------------------------------------------------------------------------------------------------
* OCIO Color Space Conversion Shader Container.
*/
class OCIOColorSpaceConversionShaderContainer : CachedResourceContainer {
private:
Map<OCIOColorSpaceConversionShaderKey, std::unique_ptr<OCIOColorSpaceConversionShader>> map_;
public:
void reset() override;
/* Check if there is an available OCIOColorSpaceConversionShader cached resource with the given
* parameters in the container, if one exists, return it, otherwise, return a newly created one
* and add it to the container. In both cases, tag the cached resource as needed to keep it
* cached for the next evaluation. */
OCIOColorSpaceConversionShader &get(std::string source, std::string target);
};
} // namespace blender::realtime_compositor

View File

@ -0,0 +1,502 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <cstdint>
#include <memory>
#include <string>
#include "BLI_assert.h"
#include "BLI_hash.hh"
#include "BLI_map.hh"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
#include "BLI_vector_set.hh"
#include "GPU_capabilities.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
#include "GPU_uniform_buffer.h"
#include "gpu_shader_create_info.hh"
#include "COM_ocio_color_space_conversion_shader.hh"
#if defined(WITH_OCIO)
# include <OpenColorIO/OpenColorIO.h>
#endif
namespace blender::realtime_compositor {
/* ------------------------------------------------------------------------------------------------
* OCIO Color Space Conversion Shader Key.
*/
OCIOColorSpaceConversionShaderKey::OCIOColorSpaceConversionShaderKey(std::string source,
std::string target,
std::string config_cache_id)
: source(source), target(target), config_cache_id(config_cache_id)
{
}
uint64_t OCIOColorSpaceConversionShaderKey::hash() const
{
return get_default_hash_3(source, target, config_cache_id);
}
bool operator==(const OCIOColorSpaceConversionShaderKey &a,
const OCIOColorSpaceConversionShaderKey &b)
{
return a.source == b.source && a.target == b.target && a.config_cache_id == b.config_cache_id;
}
/* --------------------------------------------------------------------
* GPU Shader Creator.
*/
#if defined(WITH_OCIO)
namespace OCIO = OCIO_NAMESPACE;
using namespace blender::gpu::shader;
/* A subclass of OCIO::GpuShaderCreator that constructs the shader using a ShaderCreateInfo. The
* Create method should be used to construct the creator, then the extractGpuShaderInfo() method of
* the appropriate OCIO::GPUProcessor should be called passing in the creator. After construction,
* the constructed compute shader can be used by calling the bind_shader_and_resources() method,
* followed by binding the input texture and output image using their names input_sampler_name()
* and output_image_name(), following by dispatching the shader on the domain of the input, and
* finally calling the unbind_shader_and_resources() method.
*
* Upon calling the extractGpuShaderInfo(), all the transforms in the GPU processor will add their
* needed resources by calling the respective addUniform() and add[3D]Texture() methods. Then, the
* shader code of all transforms will be generated and passed to the createShaderText() method,
* generating the full code of the processor. Finally, the finalize() method will be called to
* finally create the shader. */
class GPUShaderCreator : public OCIO::GpuShaderCreator {
public:
static std::shared_ptr<GPUShaderCreator> Create()
{
std::shared_ptr<GPUShaderCreator> instance = std::make_shared<GPUShaderCreator>();
instance->setLanguage(OCIO::GPU_LANGUAGE_GLSL_4_0);
return instance;
}
/* Not used, but needs to be overridden, so return a nullptr. */
OCIO::GpuShaderCreatorRcPtr clone() const override
{
return OCIO::GpuShaderCreatorRcPtr();
}
/* This is ignored since we query using our own GPU capabilities system. */
void setTextureMaxWidth(unsigned max_width) override {}
unsigned getTextureMaxWidth() const noexcept override
{
return GPU_max_texture_size();
}
bool addUniform(const char *name, const DoubleGetter &get_double) override
{
/* Check if a resource exists with the same name and assert if it is the case, returning false
* indicates failure to add the uniform for the shader creator. */
if (!resource_names_.add(std::make_unique<std::string>(name))) {
BLI_assert_unreachable();
return false;
}
/* Don't use the name argument directly since ShaderCreateInfo only stores references to
* resource names, instead, use the name that is stored in resource_names_. */
std::string &resource_name = *resource_names_[resource_names_.size() - 1];
shader_create_info_.push_constant(Type::FLOAT, resource_name);
float_uniforms_.add(resource_name, get_double);
return true;
}
bool addUniform(const char *name, const BoolGetter &get_bool) override
{
/* Check if a resource exists with the same name and assert if it is the case, returning false
* indicates failure to add the uniform for the shader creator. */
if (!resource_names_.add(std::make_unique<std::string>(name))) {
BLI_assert_unreachable();
return false;
}
/* Don't use the name argument directly since ShaderCreateInfo only stores references to
* resource names, instead, use the name that is stored in resource_names_. */
std::string &resource_name = *resource_names_[resource_names_.size() - 1];
shader_create_info_.push_constant(Type::BOOL, resource_name);
boolean_uniforms_.add(name, get_bool);
return true;
}
bool addUniform(const char *name, const Float3Getter &get_float3) override
{
/* Check if a resource exists with the same name and assert if it is the case, returning false
* indicates failure to add the uniform for the shader creator. */
if (!resource_names_.add(std::make_unique<std::string>(name))) {
BLI_assert_unreachable();
return false;
}
/* Don't use the name argument directly since ShaderCreateInfo only stores references to
* resource names, instead, use the name that is stored in resource_names_. */
std::string &resource_name = *resource_names_[resource_names_.size() - 1];
shader_create_info_.push_constant(Type::VEC3, resource_name);
vector_uniforms_.add(resource_name, get_float3);
return true;
}
bool addUniform(const char *name,
const SizeGetter &get_size,
const VectorFloatGetter &get_vector_float) override
{
/* Check if a resource exists with the same name and assert if it is the case, returning false
* indicates failure to add the uniform for the shader creator. */
if (!resource_names_.add(std::make_unique<std::string>(name))) {
BLI_assert_unreachable();
return false;
}
/* Don't use the name argument directly since ShaderCreateInfo only stores references to
* resource names, instead, use the name that is stored in resource_names_. */
std::string &resource_name = *resource_names_[resource_names_.size() - 1];
shader_create_info_.uniform_buf(buffers_sizes_.size(), "float", resource_name);
float_buffers_.add(resource_name, get_vector_float);
buffers_sizes_.add(resource_name, get_size);
return true;
}
bool addUniform(const char *name,
const SizeGetter &get_size,
const VectorIntGetter &get_vector_int) override
{
/* Check if a resource exists with the same name and assert if it is the case, returning false
* indicates failure to add the uniform for the shader creator. */
if (!resource_names_.add(std::make_unique<std::string>(name))) {
BLI_assert_unreachable();
return false;
}
/* Don't use the name argument directly since ShaderCreateInfo only stores references to
* resource names, instead, use the name that is stored in resource_names_. */
std::string &resource_name = *resource_names_[resource_names_.size() - 1];
shader_create_info_.uniform_buf(buffers_sizes_.size(), "int", resource_name);
int_buffers_.add(name, get_vector_int);
buffers_sizes_.add(name, get_size);
return true;
}
void addTexture(const char *texture_name,
const char *sampler_name,
unsigned width,
unsigned height,
TextureType channel,
OCIO::Interpolation interpolation,
const float *values) override
{
/* Check if a resource exists with the same name and assert if it is the case. */
if (!resource_names_.add(std::make_unique<std::string>(sampler_name))) {
BLI_assert_unreachable();
}
/* Don't use the name argument directly since ShaderCreateInfo only stores references to
* resource names, instead, use the name that is stored in resource_names_. */
std::string &resource_name = *resource_names_[resource_names_.size() - 1];
GPUTexture *texture;
eGPUTextureFormat texture_format = (channel == TEXTURE_RGB_CHANNEL) ? GPU_RGB16F : GPU_R16F;
/* A height of 1 indicates a 1D texture according to the OCIO API. */
if (height == 1) {
texture = GPU_texture_create_1d(
texture_name, width, 1, texture_format, GPU_TEXTURE_USAGE_SHADER_READ, values);
shader_create_info_.sampler(textures_.size() + 1, ImageType::FLOAT_1D, resource_name);
}
else {
texture = GPU_texture_create_2d(
texture_name, width, height, 1, texture_format, GPU_TEXTURE_USAGE_SHADER_READ, values);
shader_create_info_.sampler(textures_.size() + 1, ImageType::FLOAT_2D, resource_name);
}
GPU_texture_filter_mode(texture, interpolation != OCIO::INTERP_NEAREST);
textures_.add(sampler_name, texture);
}
void add3DTexture(const char *texture_name,
const char *sampler_name,
unsigned size,
OCIO::Interpolation interpolation,
const float *values) override
{
/* Check if a resource exists with the same name and assert if it is the case. */
if (!resource_names_.add(std::make_unique<std::string>(sampler_name))) {
BLI_assert_unreachable();
}
/* Don't use the name argument directly since ShaderCreateInfo only stores references to
* resource names, instead, use the name that is stored in resource_names_. */
std::string &resource_name = *resource_names_[resource_names_.size() - 1];
shader_create_info_.sampler(textures_.size() + 1, ImageType::FLOAT_3D, resource_name);
GPUTexture *texture = GPU_texture_create_3d(
texture_name, size, size, size, 1, GPU_RGB16F, GPU_TEXTURE_USAGE_SHADER_READ, values);
GPU_texture_filter_mode(texture, interpolation != OCIO::INTERP_NEAREST);
textures_.add(sampler_name, texture);
}
/* This gets called before the finalize() method to construct the shader code. We just
* concatenate the code except for the declarations section. That's because the ShaderCreateInfo
* will add the declaration itself. */
void createShaderText(const char *declarations,
const char *helper_methods,
const char *function_header,
const char *function_body,
const char *function_footer) override
{
shader_code_ += helper_methods;
shader_code_ += function_header;
shader_code_ += function_body;
shader_code_ += function_footer;
}
/* This gets called when all resources were added using the respective addUniform() or
* add[3D]Texture() methods and the shader code was generated using the createShaderText()
* method. That is, we are ready to complete the ShaderCreateInfo and create a shader from it. */
void finalize() override
{
GpuShaderCreator::finalize();
shader_create_info_.local_group_size(16, 16);
shader_create_info_.sampler(0, ImageType::FLOAT_2D, input_sampler_name());
shader_create_info_.image(
0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, output_image_name());
shader_create_info_.compute_source("gpu_shader_compositor_ocio_processor.glsl");
shader_create_info_.compute_source_generated += shader_code_;
GPUShaderCreateInfo *info = reinterpret_cast<GPUShaderCreateInfo *>(&shader_create_info_);
shader_ = GPU_shader_create_from_info(info);
}
GPUShader *bind_shader_and_resources()
{
GPU_shader_bind(shader_);
for (auto item : float_uniforms_.items()) {
GPU_shader_uniform_1f(shader_, item.key.c_str(), item.value());
}
for (auto item : boolean_uniforms_.items()) {
GPU_shader_uniform_1b(shader_, item.key.c_str(), item.value());
}
for (auto item : vector_uniforms_.items()) {
GPU_shader_uniform_3fv(shader_, item.key.c_str(), item.value().data());
}
for (auto item : float_buffers_.items()) {
GPUUniformBuf *buffer = GPU_uniformbuf_create_ex(
buffers_sizes_.lookup(item.key)(), item.value(), item.key.c_str());
const int ubo_location = GPU_shader_get_ubo_binding(shader_, item.key.c_str());
GPU_uniformbuf_bind(buffer, ubo_location);
uniform_buffers_.append(buffer);
}
for (auto item : int_buffers_.items()) {
GPUUniformBuf *buffer = GPU_uniformbuf_create_ex(
buffers_sizes_.lookup(item.key)(), item.value(), item.key.c_str());
const int ubo_location = GPU_shader_get_ubo_binding(shader_, item.key.c_str());
GPU_uniformbuf_bind(buffer, ubo_location);
uniform_buffers_.append(buffer);
}
for (auto item : textures_.items()) {
const int texture_image_unit = GPU_shader_get_sampler_binding(shader_, item.key.c_str());
GPU_texture_bind(item.value, texture_image_unit);
}
return shader_;
}
void unbind_shader_and_resources()
{
for (GPUUniformBuf *buffer : uniform_buffers_) {
GPU_uniformbuf_unbind(buffer);
GPU_uniformbuf_free(buffer);
}
for (GPUTexture *texture : textures_.values()) {
GPU_texture_unbind(texture);
}
GPU_shader_unbind();
}
const char *input_sampler_name()
{
return "input_tx";
}
const char *output_image_name()
{
return "output_img";
}
~GPUShaderCreator() override
{
for (GPUTexture *texture : textures_.values()) {
GPU_texture_free(texture);
}
GPU_shader_free(shader_);
}
private:
/* The processor shader and the ShaderCreateInfo used to construct it. Constructed and
* initialized in the finalize() method. */
GPUShader *shader_ = nullptr;
ShaderCreateInfo shader_create_info_ = ShaderCreateInfo("OCIO Processor");
/* Stores the generated OCIOMain function as well as a number of helper functions. Initialized in
* the createShaderText() method. */
std::string shader_code_;
/* Maps that associates the name of a uniform with a getter function that returns its value.
* Initialized in the respective addUniform() methods. */
Map<std::string, DoubleGetter> float_uniforms_;
Map<std::string, BoolGetter> boolean_uniforms_;
Map<std::string, Float3Getter> vector_uniforms_;
/* Maps that associates the name of uniform buffer objects with a getter function that returns
* its values. Initialized in the respective addUniform() methods. */
Map<std::string, VectorFloatGetter> float_buffers_;
Map<std::string, VectorIntGetter> int_buffers_;
/* A map that associates the name of uniform buffer objects with a getter functions that returns
* its number of elements. Initialized in the respective addUniform() methods. */
Map<std::string, SizeGetter> buffers_sizes_;
/* A map that associates the name of a sampler with its corresponding texture. Initialized in the
* addTexture() and add3DTexture() methods. */
Map<std::string, GPUTexture *> textures_;
/* A vector set that stores the names of all the resources used by the shader. This is used to:
* 1. Check for name collisions when adding new resources.
* 2. Store the resource names throughout the construction of the shader since the
* ShaderCreateInfo class only stores references to resources names. */
VectorSet<std::unique_ptr<std::string>> resource_names_;
/* A vectors that stores the created uniform buffers when bind_shader_and_resources() is called,
* so that they can be properly unbound and freed in the unbind_shader_and_resources() method. */
Vector<GPUUniformBuf *> uniform_buffers_;
};
#else
/* A stub implementation in case OCIO is disabled at build time. */
class GPUShaderCreator {
public:
GPUShader *bind_shader_and_resources()
{
return nullptr;
}
void unbind_shader_and_resources() {}
const char *input_sampler_name()
{
return nullptr;
}
const char *output_image_name()
{
return nullptr;
}
};
#endif
/* --------------------------------------------------------------------
* OCIO Color Space Conversion Shader.
*/
OCIOColorSpaceConversionShader::OCIOColorSpaceConversionShader(std::string source,
std::string target)
{
#if defined(WITH_OCIO)
/* Get a GPU processor that transforms the source color space to the target color space. */
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
OCIO::ConstProcessorRcPtr processor = config->getProcessor(source.c_str(), target.c_str());
OCIO::ConstGPUProcessorRcPtr gpu_processor = processor->getDefaultGPUProcessor();
/* Create a GPU shader creator and construct it based on the transforms in the default GPU
* processor. */
shader_creator_ = GPUShaderCreator::Create();
auto ocio_shader_creator = std::static_pointer_cast<OCIO::GpuShaderCreator>(shader_creator_);
gpu_processor->extractGpuShaderInfo(ocio_shader_creator);
#endif
}
GPUShader *OCIOColorSpaceConversionShader::bind_shader_and_resources()
{
return shader_creator_->bind_shader_and_resources();
}
void OCIOColorSpaceConversionShader::unbind_shader_and_resources()
{
shader_creator_->unbind_shader_and_resources();
}
const char *OCIOColorSpaceConversionShader::input_sampler_name()
{
return shader_creator_->input_sampler_name();
}
const char *OCIOColorSpaceConversionShader::output_image_name()
{
return shader_creator_->output_image_name();
}
/* --------------------------------------------------------------------
* OCIO Color Space Conversion Shader Container.
*/
void OCIOColorSpaceConversionShaderContainer::reset()
{
/* First, delete all resources that are no longer needed. */
map_.remove_if([](auto item) { return !item.value->needed; });
/* Second, reset the needed status of the remaining resources to false to ready them to track
* their needed status for the next evaluation. */
for (auto &value : map_.values()) {
value->needed = false;
}
}
OCIOColorSpaceConversionShader &OCIOColorSpaceConversionShaderContainer::get(std::string source,
std::string target)
{
#if defined(WITH_OCIO)
/* Use the config cache ID in the cache key in case the configuration changed at runtime. */
std::string config_cache_id = OCIO::GetCurrentConfig()->getCacheID();
#else
std::string config_cache_id;
#endif
const OCIOColorSpaceConversionShaderKey key(source, target, config_cache_id);
OCIOColorSpaceConversionShader &shader = *map_.lookup_or_add_cb(
key, [&]() { return std::make_unique<OCIOColorSpaceConversionShader>(source, target); });
shader.needed = true;
return shader;
}
} // namespace blender::realtime_compositor

View File

@ -12,6 +12,7 @@ void StaticCacheManager::reset()
cached_textures.reset();
cached_masks.reset();
smaa_precomputed_textures.reset();
ocio_color_space_conversion_shaders.reset();
}
} // namespace blender::realtime_compositor

View File

@ -0,0 +1,14 @@
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
/* OCIOMain will be dynamically generated in the OCIOColorSpaceConversionShader class and appended
* at the end of this file, so forward declare it. Such forward declarations are not supported nor
* needed on Metal. */
#if !defined(GPU_METAL)
vec4 OCIOMain(vec4 inPixel);
#endif
void main()
{
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
imageStore(output_img, texel, OCIOMain(texture_load(input_tx, texel)));
}

View File

@ -1920,9 +1920,19 @@ void FONT_OT_selection_set(struct wmOperatorType *ot)
static int font_select_word_exec(bContext *C, wmOperator *UNUSED(op))
{
move_cursor(C, NEXT_CHAR, false);
move_cursor(C, PREV_WORD, false);
move_cursor(C, NEXT_WORD, true);
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
BLI_str_cursor_step_bounds_utf32(ef->textbuf, ef->len, ef->pos, &ef->selstart, &ef->selend);
ef->pos = ef->selend;
/* XXX: Text object selection start is 1-based, unlike text processing elsewhere in Blender. */
ef->selstart += 1;
font_select_update_primary_clipboard(obedit);
text_update_edited(C, obedit, FO_CURS);
return OPERATOR_FINISHED;
}

View File

@ -3730,8 +3730,11 @@ static void ui_do_but_textedit(
/* only select a word in button if there was no selection before */
if (event->val == KM_DBL_CLICK && had_selection == false) {
ui_textedit_move(but, data, STRCUR_DIR_PREV, false, STRCUR_JUMP_DELIM);
ui_textedit_move(but, data, STRCUR_DIR_NEXT, true, STRCUR_JUMP_DELIM);
int selsta, selend;
BLI_str_cursor_step_bounds_utf8(data->str, strlen(data->str), but->pos, &selsta, &selend);
but->pos = (short)selend;
but->selsta = (short)selsta;
but->selend = (short)selend;
retval = WM_UI_HANDLER_BREAK;
changed = true;
}

View File

@ -386,6 +386,11 @@ static int hide_show_exec(bContext *C, wmOperator *op)
BKE_pbvh_update_hide_attributes_from_mesh(pbvh);
}
RegionView3D *rv3d = CTX_wm_region_view3d(C);
if (!BKE_sculptsession_use_pbvh_draw(ob, rv3d)) {
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
ED_region_tag_redraw(region);

View File

@ -3029,7 +3029,10 @@ static void calc_brush_local_mat(const float rotation,
/* Square tips should scale by square root of 2. */
if (BKE_brush_has_cube_tip(cache->brush, PAINT_MODE_SCULPT)) {
radius += (radius * M_SQRT2 - radius) * (1.0f - cache->brush->tip_roundness);
radius += (radius / M_SQRT2 - radius) * cache->brush->tip_roundness;
}
else {
radius /= M_SQRT2;
}
normalize_m4(mat);
@ -3670,7 +3673,10 @@ static void do_brush_action(Sculpt *sd,
sd, ob, nodes, ss->cache->cloth_sim, ss->cache->location, FLT_MAX);
}
bool invert = ss->cache->pen_flip || ss->cache->invert || brush->flag & BRUSH_DIR_IN;
bool invert = ss->cache->pen_flip || ss->cache->invert;
if (brush->flag & BRUSH_DIR_IN) {
invert = !invert;
}
/* Apply one type of brush action. */
switch (brush->sculpt_tool) {

View File

@ -1258,9 +1258,7 @@ static int console_selectword_invoke(bContext *C, wmOperator *UNUSED(op), const
if (console_line_column_from_index(sc, pos, &cl, &offset, &n)) {
int sel[2] = {n, n};
BLI_str_cursor_step_utf8(cl->line, cl->len, &sel[0], STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, true);
BLI_str_cursor_step_utf8(cl->line, cl->len, &sel[1], STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, true);
BLI_str_cursor_step_bounds_utf8(cl->line, cl->len, n, &sel[0], &sel[1]);
sel[0] = offset - sel[0];
sel[1] = offset - sel[1];

View File

@ -494,6 +494,9 @@ static void outliner_space_blend_read_lib(BlendLibReader *reader,
if (TSE_IS_REAL_ID(tselem)) {
BLO_read_id_address(reader, nullptr, &tselem->id);
}
else {
tselem->id = nullptr;
}
}
/* rebuild hash table, because it depends on ids too */
space_outliner->storeflag |= SO_TREESTORE_REBUILD;

View File

@ -15,6 +15,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_math_base.h"
#include "BLI_string_cursor_utf8.h"
#include "BLT_translation.h"
@ -1577,11 +1578,9 @@ void TEXT_OT_select_line(wmOperatorType *ot)
static int text_select_word_exec(bContext *C, wmOperator *UNUSED(op))
{
Text *text = CTX_data_edit_text(C);
/* don't advance cursor before stepping */
const bool use_init_step = false;
txt_jump_left(text, false, use_init_step);
txt_jump_right(text, true, use_init_step);
BLI_str_cursor_step_bounds_utf8(
text->curl->line, text->curl->len, text->selc, &text->curc, &text->selc);
text_update_cursor_moved(C);
text_select_update_primary_clipboard(text);

View File

@ -101,10 +101,11 @@ static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data)
{
ID *id_self = cb_data->id_self;
ID **id_pointer = cb_data->id_pointer;
BLI_assert((id_self->tag & LIB_TAG_UNDO_OLD_ID_REUSED) != 0);
BLI_assert((id_self->tag & LIB_TAG_UNDO_OLD_ID_REUSED_UNCHANGED) != 0);
ID *id = *id_pointer;
if (id != nullptr && !ID_IS_LINKED(id) && (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) == 0) {
if (id != nullptr && !ID_IS_LINKED(id) && (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED_UNCHANGED) == 0)
{
bool do_stop_iter = true;
if (GS(id_self->name) == ID_OB) {
Object *ob_self = (Object *)id_self;
@ -234,7 +235,7 @@ static void memfile_undosys_step_decode(struct bContext *C,
* data-blocks, at least COW evaluated copies need to be updated... */
ID *id = nullptr;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) {
if (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED_UNCHANGED) {
BKE_library_foreach_ID_link(
bmain, id, memfile_undosys_step_id_reused_cb, nullptr, IDWALK_READONLY);
}
@ -282,7 +283,7 @@ static void memfile_undosys_step_decode(struct bContext *C,
FOREACH_MAIN_ID_BEGIN (bmain, id) {
/* Clear temporary tag. */
id->tag &= ~(LIB_TAG_UNDO_OLD_ID_REUSED | LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE);
id->tag &= ~(LIB_TAG_UNDO_OLD_ID_REUSED_UNCHANGED | LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE);
/* We only start accumulating from this point, any tags set up to here
* are already part of the current undo state. This is done in a second

View File

@ -1184,6 +1184,9 @@ static int64_t pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
MutableSpan<uv_phi> r_phis,
rctf *r_extent)
{
if (params.shape_method == ED_UVPACK_SHAPE_AABB) {
return 0; /* Not yet supported. */
}
blender::Array<uv_phi> phis(r_phis.size());
Occupancy occupancy(guess_initial_scale(islands, scale, margin));
rctf extent = {0.0f, 0.0f, 0.0f, 0.0f};
@ -1446,7 +1449,7 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
});
}
/* Partition `islands`, largest islands will go to a slow packer, the rest alpaca_turbo.
/* Partition `islands`, largest islands will go to a slow packer, the rest the fast packer.
* See discussion above for details. */
int64_t alpaca_cutoff = 1024; /* Regular situation, pack `32 * 32` islands with slow packer. */
int64_t alpaca_cutoff_fast = 81; /* Reduce problem size, only `N = 9 * 9` with slow packer. */
@ -1455,53 +1458,39 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
alpaca_cutoff = alpaca_cutoff_fast;
}
}
int64_t max_box_pack = std::min(alpaca_cutoff, islands.size());
Span<UVAABBIsland *> slow_aabbs = aabbs.as_span().take_front(
std::min(alpaca_cutoff, islands.size()));
rctf extent = {0.0f, 1e30f, 0.0f, 1e30f};
if (all_can_translate) {
pack_islands_fast(0,
aabbs.as_span().take_front(max_box_pack),
all_can_rotate,
params.target_aspect_y,
r_phis,
&extent);
pack_islands_fast(0, slow_aabbs, all_can_rotate, params.target_aspect_y, r_phis, &extent);
}
if (all_can_translate) {
pack_islands_optimal_pack(aabbs.as_span().take_front(max_box_pack), params, r_phis, &extent);
pack_islands_optimal_pack(slow_aabbs, params, r_phis, &extent);
}
/* Call box_pack_2d (slow for large N.) */
if (all_can_translate) {
pack_island_box_pack_2d(aabbs.as_span().take_front(max_box_pack), params, r_phis, &extent);
pack_island_box_pack_2d(slow_aabbs, params, r_phis, &extent);
}
/* Call xatlas (slow for large N.) */
switch (params.shape_method) {
case ED_UVPACK_SHAPE_CONVEX:
case ED_UVPACK_SHAPE_CONCAVE:
max_box_pack = pack_island_xatlas(aabbs.as_span().take_front(max_box_pack),
islands,
scale,
margin,
params,
r_phis,
&extent);
break;
default:
break;
int64_t max_xatlas = pack_island_xatlas(
slow_aabbs, islands, scale, margin, params, r_phis, &extent);
if (max_xatlas) {
slow_aabbs = aabbs.as_span().take_front(max_xatlas);
}
/* At this stage, `max_u` and `max_v` contain the box_pack/xatlas UVs. */
/* At this stage, `extent` contains the optimal/box_pack/xatlas UVs. */
if (all_can_rotate) {
rotate_inside_square(
aabbs.as_span().take_front(max_box_pack), islands, params, scale, margin, r_phis, &extent);
rotate_inside_square(slow_aabbs, islands, params, scale, margin, r_phis, &extent);
}
/* Call fast packer for remaining islands. */
pack_islands_fast(max_box_pack, aabbs, all_can_rotate, params.target_aspect_y, r_phis, &extent);
pack_islands_fast(
slow_aabbs.size(), aabbs, all_can_rotate, params.target_aspect_y, r_phis, &extent);
return get_aspect_scaled_extent(extent, params);
}

View File

@ -441,6 +441,11 @@ struct GPUSource {
int64_t cursor = -1;
StringRef func_return_type, func_name, func_args;
while (function_parse(input, cursor, func_return_type, func_name, func_args)) {
/* Main functions needn't be handled because they are the entry point of the shader. */
if (func_name == "main") {
continue;
}
GPUFunction *func = MEM_new<GPUFunction>(__func__);
func_name.copy(func->name, sizeof(func->name));
func->source = reinterpret_cast<void *>(this);

View File

@ -1227,9 +1227,12 @@ static IK_Scene *convert_tree(
if (pchan->parent) {
sub_v3_v3v3(start, pchan->pose_head, pchan->parent->pose_tail);
}
else {
else if (ikparam->flag & ITASC_TRANSLATE_ROOT_BONES) {
start[0] = start[1] = start[2] = 0.0f;
}
else {
copy_v3_v3(start, pchan->pose_head);
}
invert_m3_m3(iR_parmat, R_parmat);
normalize_m3(iR_parmat);
mul_m3_v3(iR_parmat, start);

View File

@ -855,11 +855,13 @@ enum {
LIB_TAG_NEED_LINK = 1 << 16,
/**
* ID is being re-used from the old Main (instead of read from memfile), during memfile undo
* processing.
* processing, because it was detected as unchanged.
*
* \note: Also means that such ID does not need to be lib-linked during undo readfile process.
*
* RESET_AFTER_USE
*/
LIB_TAG_UNDO_OLD_ID_REUSED = 1 << 17,
LIB_TAG_UNDO_OLD_ID_REUSED_UNCHANGED = 1 << 17,
/**
* ID has be re-read in-place, the ID address is the same as in the old BMain, but the content is
* different.

View File

@ -567,6 +567,10 @@ typedef enum eItasc_Flags {
ITASC_INITIAL_REITERATION = (1 << 1),
ITASC_REITERATION = (1 << 2),
ITASC_SIMULATION = (1 << 3),
/* Set this flag to always translate root bones (i.e. bones without a parent) to (0, 0, 0).
* This was the pre-3.6 behaviour, and this flag was introduced for backward compatibility. */
ITASC_TRANSLATE_ROOT_BONES = (1 << 4),
} eItasc_Flags;
/* bItasc->solver */

View File

@ -1561,9 +1561,9 @@ static void rna_def_armature(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "layer_protected", 1);
RNA_def_property_array(prop, 32);
RNA_def_property_ui_text(prop,
"Layer Proxy Protection",
"Protected layers in Proxy Instances are restored to Proxy settings "
"on file reload and undo");
"Layer Override Protection",
"Protected layers in overridden instances are restored to "
"their original settings on file reload and undo");
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
/* flag */

View File

@ -3484,7 +3484,10 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_plane_trim", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_PLANE_TRIM);
RNA_def_property_ui_text(prop, "Use Plane Trim", "Enable Plane Trim");
RNA_def_property_ui_text(
prop,
"Use Plane Trim",
"Limit the distance from the offset plane that a vertex can be affected");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "use_frontface", PROP_BOOLEAN, PROP_NONE);

View File

@ -1018,7 +1018,7 @@ static void rna_def_path(BlenderRNA *UNUSED(brna), StructRNA *srna)
prop = RNA_def_property(srna, "use_path_follow", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CU_FOLLOW);
RNA_def_property_ui_text(prop, "Follow", "Make curve path children to rotate along the path");
RNA_def_property_ui_text(prop, "Follow", "Make curve path children rotate along the path");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "use_path_clamp", PROP_BOOLEAN, PROP_NONE);
@ -1034,7 +1034,7 @@ static void rna_def_path(BlenderRNA *UNUSED(brna), StructRNA *srna)
RNA_def_property_ui_text(prop,
"Stretch",
"Option for curve-deform: "
"make deformed child to stretch along entire path");
"make deformed child stretch along entire path");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "use_deform_bounds", PROP_BOOLEAN, PROP_NONE);
@ -1050,7 +1050,8 @@ static void rna_def_path(BlenderRNA *UNUSED(brna), StructRNA *srna)
RNA_def_property_ui_text(prop,
"Radius",
"Option for paths and curve-deform: "
"apply the curve radius with path following it and deforming");
"apply the curve radius to objects following it "
"and to deformed objects");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
}

View File

@ -574,7 +574,7 @@ static int rna_validate_identifier(const char *identifier, char *error, bool pro
for (a = 0; kwlist[a]; a++) {
if (STREQ(identifier, kwlist[a])) {
strcpy(error, "this keyword is reserved by python");
strcpy(error, "this keyword is reserved by Python");
return 0;
}
}
@ -591,7 +591,7 @@ static int rna_validate_identifier(const char *identifier, char *error, bool pro
for (a = 0; kwlist_prop[a]; a++) {
if (STREQ(identifier, kwlist_prop[a])) {
strcpy(error, "this keyword is reserved by python");
strcpy(error, "this keyword is reserved by Python");
return 0;
}
}
@ -784,7 +784,7 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna)
# if 0
if (srna->flag & STRUCT_RUNTIME) {
if (RNA_struct_py_type_get(srna)) {
fprintf(stderr, "%s '%s' freed while holding a python reference.", srna->identifier);
fprintf(stderr, "%s '%s' freed while holding a Python reference.", srna->identifier);
}
}
# endif

View File

@ -2148,7 +2148,7 @@ static void rna_def_channeldriver(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"Simple Expression",
"The scripted expression can be evaluated without using the full python interpreter");
"The scripted expression can be evaluated without using the full Python interpreter");
/* Functions */
RNA_api_drivers(srna);

View File

@ -2957,7 +2957,7 @@ static void rna_def_modifier_gpencilhook(BlenderRNA *brna)
prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curfalloff");
RNA_def_property_ui_text(prop, "Falloff Curve", "Custom light falloff curve");
RNA_def_property_ui_text(prop, "Falloff Curve", "Custom falloff curve");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE);
@ -3870,7 +3870,8 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "target_layer", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Layer", "Grease Pencil layer assigned to the generated strokes");
RNA_def_property_ui_text(
prop, "Layer", "Grease Pencil layer to which assign the generated strokes");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "source_vertex_group", PROP_STRING, PROP_NONE);

View File

@ -9958,7 +9958,7 @@ static void rna_def_simulation_state_item(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"Attribute Domain",
"Attribute domain where the attribute domain is stored in the simulation state");
"Attribute domain where the attribute is stored in the simulation state");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_SimulationStateItem_update");

View File

@ -3796,8 +3796,7 @@ static void rna_def_object(BlenderRNA *brna)
/* shape keys */
prop = RNA_def_property(srna, "show_only_shape_key", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "shapeflag", OB_SHAPE_LOCK);
RNA_def_property_ui_text(
prop, "Shape Key Lock", "Always show the current shape for this object");
RNA_def_property_ui_text(prop, "Shape Key Lock", "Only show the active shape at full strength");
RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
RNA_def_property_update(prop, 0, "rna_Object_internal_update_data");

View File

@ -1512,6 +1512,12 @@ static void rna_def_pose_itasc(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Num Steps", "Divide the frame interval into this many steps");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
prop = RNA_def_property(srna, "translate_root_bones", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ITASC_TRANSLATE_ROOT_BONES);
RNA_def_property_ui_text(
prop, "Translate Roots", "Translate root (i.e. parentless) bones to the armature origin");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_itasc_mode_items);

View File

@ -376,7 +376,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain,
}
/* create a new engine type */
et = MEM_mallocN(sizeof(RenderEngineType), "python render engine");
et = MEM_mallocN(sizeof(RenderEngineType), "Python render engine");
memcpy(et, &dummy_et, sizeof(dummy_et));
et->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, et->idname, &RNA_RenderEngine);

View File

@ -3159,7 +3159,7 @@ static void rna_def_function(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"No Self",
"Function does not pass itself as an argument (becomes a static method in python)");
"Function does not pass itself as an argument (becomes a static method in Python)");
prop = RNA_def_property(srna, "use_self_type", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@ -3167,7 +3167,7 @@ static void rna_def_function(BlenderRNA *brna)
RNA_def_property_ui_text(prop,
"Use Self Type",
"Function passes itself type as an argument (becomes a class method "
"in python if use_self is false)");
"in Python if use_self is false)");
}
static void rna_def_number_property(StructRNA *srna, PropertyType type)

View File

@ -7956,7 +7956,7 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"Current Frame",
"Current frame, to update animation data from python frame_set() instead");
"Current frame, to update animation data from Python frame_set() instead");
RNA_def_property_update(prop, NC_SCENE | ND_FRAME, "rna_Scene_frame_update");
prop = RNA_def_property(srna, "frame_subframe", PROP_FLOAT, PROP_TIME);

View File

@ -6112,7 +6112,7 @@ static void rna_def_space_text(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_live_edit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "live_edit", 1);
RNA_def_property_ui_text(prop, "Live Edit", "Run python while editing");
RNA_def_property_ui_text(prop, "Live Edit", "Run Python while editing");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
/* find */
@ -6558,7 +6558,7 @@ static void rna_def_space_console(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SpaceConsole", "Space");
RNA_def_struct_sdna(srna, "SpaceConsole");
RNA_def_struct_ui_text(srna, "Space Console", "Interactive python console");
RNA_def_struct_ui_text(srna, "Space Console", "Interactive Python console");
/* display */
prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_NONE); /* copied from text editor */

View File

@ -362,7 +362,7 @@ static StructRNA *rna_Panel_register(Main *bmain,
description_size = strlen(_panel_descr) + 1;
over_alloc += description_size;
}
pt = MEM_callocN(sizeof(PanelType) + over_alloc, "python buttons panel");
pt = MEM_callocN(sizeof(PanelType) + over_alloc, "Python buttons panel");
memcpy(pt, &dummy_pt, sizeof(dummy_pt));
if (_panel_descr[0]) {
@ -867,7 +867,7 @@ static StructRNA *rna_Header_register(Main *bmain,
}
/* create a new header type */
ht = MEM_mallocN(sizeof(HeaderType), "python buttons header");
ht = MEM_mallocN(sizeof(HeaderType), "Python buttons header");
memcpy(ht, &dummy_ht, sizeof(dummy_ht));
ht->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, ht->idname, &RNA_Header);
@ -1024,7 +1024,7 @@ static StructRNA *rna_Menu_register(Main *bmain,
over_alloc += description_size;
}
mt = MEM_callocN(sizeof(MenuType) + over_alloc, "python buttons menu");
mt = MEM_callocN(sizeof(MenuType) + over_alloc, "Python buttons menu");
memcpy(mt, &dummy_mt, sizeof(dummy_mt));
if (_menu_descr[0]) {

View File

@ -6315,14 +6315,14 @@ static void rna_def_userdef_script_directory_collection(BlenderRNA *brna, Proper
func = RNA_def_function(srna, "new", "rna_userdef_script_directory_new");
RNA_def_function_flag(func, FUNC_NO_SELF);
RNA_def_function_ui_description(func, "Add a new python script directory");
RNA_def_function_ui_description(func, "Add a new Python script directory");
/* return type */
parm = RNA_def_pointer(func, "script_directory", "ScriptDirectory", "", "");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_userdef_script_directory_remove");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a python script directory");
RNA_def_function_ui_description(func, "Remove a Python script directory");
parm = RNA_def_pointer(func, "script_directory", "ScriptDirectory", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
@ -6631,7 +6631,7 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_override_templates", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_override_templates", 1);
RNA_def_property_ui_text(
prop, "Override Templates", "Enable library override template in the python API");
prop, "Override Templates", "Enable library override template in the Python API");
prop = RNA_def_property(srna, "enable_eevee_next", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "enable_eevee_next", 1);

View File

@ -324,6 +324,6 @@ def main():
if __name__ == '__main__':
import sys
if sys.version_info.major < 3:
print("Incorrect python version, use Python 3 or newer!")
print("Incorrect Python version, use Python 3 or newer!")
else:
main()

View File

@ -5,8 +5,6 @@
* \ingroup cmpnodes
*/
#include "node_composite_util.hh"
#include "BLT_translation.h"
#include "RNA_access.h"
@ -16,13 +14,23 @@
#include "IMB_colormanagement.h"
#include "GPU_shader.h"
#include "COM_node_operation.hh"
#include "COM_ocio_color_space_conversion_shader.hh"
#include "COM_utilities.hh"
#include "node_composite_util.hh"
namespace blender::nodes::node_composite_convert_color_space_cc {
NODE_STORAGE_FUNCS(NodeConvertColorSpace)
static void CMP_NODE_CONVERT_COLOR_SPACE_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
b.add_input<decl::Color>(N_("Image"))
.default_value({1.0f, 1.0f, 1.0f, 1.0f})
.compositor_domain_priority(0);
b.add_output<decl::Color>(N_("Image"));
}
@ -59,8 +67,79 @@ class ConvertColorSpaceOperation : public NodeOperation {
void execute() override
{
get_input("Image").pass_through(get_result("Image"));
context().set_info_message("Viewport compositor setup not fully supported");
Result &input_image = get_input("Image");
Result &output_image = get_result("Image");
if (is_identity()) {
input_image.pass_through(output_image);
return;
}
if (input_image.is_single_value()) {
execute_single();
return;
}
const char *source = node_storage(bnode()).from_color_space;
const char *target = node_storage(bnode()).to_color_space;
OCIOColorSpaceConversionShader &ocio_shader =
context().cache_manager().ocio_color_space_conversion_shaders.get(source, target);
GPUShader *shader = ocio_shader.bind_shader_and_resources();
/* A null shader indicates that the conversion shader is just a stub implementation since OCIO
* is disabled at compile time, so pass the input through in that case. */
if (!shader) {
input_image.pass_through(output_image);
return;
}
input_image.bind_as_texture(shader, ocio_shader.input_sampler_name());
const Domain domain = compute_domain();
output_image.allocate_texture(domain);
output_image.bind_as_image(shader, ocio_shader.output_image_name());
compute_dispatch_threads_at_least(shader, domain.size);
input_image.unbind_as_texture();
output_image.unbind_as_image();
ocio_shader.unbind_shader_and_resources();
}
void execute_single()
{
const char *source = node_storage(bnode()).from_color_space;
const char *target = node_storage(bnode()).to_color_space;
ColormanageProcessor *color_processor = IMB_colormanagement_colorspace_processor_new(source,
target);
Result &input_image = get_input("Image");
float4 color = input_image.get_color_value();
IMB_colormanagement_processor_apply_pixel(color_processor, color, 3);
IMB_colormanagement_processor_free(color_processor);
Result &output_image = get_result("Image");
output_image.allocate_single_value();
output_image.set_color_value(color);
}
bool is_identity()
{
const char *source = node_storage(bnode()).from_color_space;
const char *target = node_storage(bnode()).to_color_space;
if (STREQ(source, target)) {
return true;
}
/* Data color spaces ignore any color transformation that gets applied to them. */
if (IMB_colormanagement_space_name_is_data(source)) {
return true;
}
return false;
}
};
@ -85,8 +164,6 @@ void register_node_type_cmp_convert_color_space(void)
node_type_storage(
&ntype, "NodeConvertColorSpace", node_free_standard_storage, node_copy_standard_storage);
ntype.get_compositor_operation = file_ns::get_compositor_operation;
ntype.realtime_compositor_unsupported_message = N_(
"Node not supported in the Viewport compositor");
nodeRegisterType(&ntype);
}

View File

@ -558,7 +558,7 @@ PyDoc_STRVAR(bpy_bmlayercollection_keys_doc,
".. method:: keys()\n"
"\n"
" Return the identifiers of collection members\n"
" (matching pythons dict.keys() functionality).\n"
" (matching Python's dict.keys() functionality).\n"
"\n"
" :return: the identifiers for each member of this collection.\n"
" :rtype: list of strings\n");
@ -593,7 +593,7 @@ PyDoc_STRVAR(bpy_bmlayercollection_items_doc,
".. method:: items()\n"
"\n"
" Return the identifiers of collection members\n"
" (matching pythons dict.items() functionality).\n"
" (matching Python's dict.items() functionality).\n"
"\n"
" :return: (key, value) pairs for each member of this collection.\n"
" :rtype: list of tuples\n");
@ -628,7 +628,7 @@ PyDoc_STRVAR(bpy_bmlayercollection_values_doc,
".. method:: values()\n"
"\n"
" Return the values of collection\n"
" (matching pythons dict.values() functionality).\n"
" (matching Python's dict.values() functionality).\n"
"\n"
" :return: the members of this collection.\n"
" :rtype: list\n");
@ -660,7 +660,7 @@ PyDoc_STRVAR(bpy_bmlayercollection_get_doc,
".. method:: get(key, default=None)\n"
"\n"
" Returns the value of the layer matching the key or default\n"
" when not found (matches pythons dictionary function of the same name).\n"
" when not found (matches Python's dictionary function of the same name).\n"
"\n"
" :arg key: The key associated with the layer.\n"
" :type key: string\n"
@ -929,7 +929,7 @@ PyDoc_STRVAR(bpy_bmlayeraccess_type_doc, "Exposes custom-data layer attributes."
PyDoc_STRVAR(bpy_bmlayercollection_type_doc,
"Gives access to a collection of custom-data layers of the same type and behaves "
"like python dictionaries, "
"like Python dictionaries, "
"except for the ability to do list like index access.");
PyDoc_STRVAR(bpy_bmlayeritem_type_doc,

View File

@ -600,7 +600,7 @@ PyDoc_STRVAR(bpy_bmdeformvert_keys_doc,
".. method:: keys()\n"
"\n"
" Return the group indices used by this vertex\n"
" (matching pythons dict.keys() functionality).\n"
" (matching Python's dict.keys() functionality).\n"
"\n"
" :return: the deform group this vertex uses\n"
" :rtype: list of ints\n");
@ -622,7 +622,7 @@ PyDoc_STRVAR(bpy_bmdeformvert_values_doc,
".. method:: values()\n"
"\n"
" Return the weights of the deform vertex\n"
" (matching pythons dict.values() functionality).\n"
" (matching Python's dict.values() functionality).\n"
"\n"
" :return: The weights that influence this vertex\n"
" :rtype: list of floats\n");
@ -644,7 +644,7 @@ PyDoc_STRVAR(bpy_bmdeformvert_items_doc,
".. method:: items()\n"
"\n"
" Return (group, weight) pairs for this vertex\n"
" (matching pythons dict.items() functionality).\n"
" (matching Python's dict.items() functionality).\n"
"\n"
" :return: (key, value) pairs for each deform weight of this vertex.\n"
" :rtype: list of tuples\n");
@ -669,7 +669,7 @@ PyDoc_STRVAR(bpy_bmdeformvert_get_doc,
".. method:: get(key, default=None)\n"
"\n"
" Returns the deform weight matching the key or default\n"
" when not found (matches pythons dictionary function of the same name).\n"
" when not found (matches Python's dictionary function of the same name).\n"
"\n"
" :arg key: The key associated with deform weight.\n"
" :type key: int\n"

View File

@ -1553,7 +1553,7 @@ static PyObject *BPy_IDGroup_update(BPy_IDProperty *self, PyObject *value)
PyDoc_STRVAR(BPy_IDGroup_to_dict_doc,
".. method:: to_dict()\n"
"\n"
" Return a purely python version of the group.\n");
" Return a purely Python version of the group.\n");
static PyObject *BPy_IDGroup_to_dict(BPy_IDProperty *self)
{
return BPy_IDGroup_MapDataToPy(self->prop);

View File

@ -607,7 +607,7 @@ void PyC_LineSpit(void)
/* NOTE: allow calling from outside python (RNA). */
if (!PyC_IsInterpreterActive()) {
fprintf(stderr, "python line lookup failed, interpreter inactive\n");
fprintf(stderr, "Python line lookup failed, interpreter inactive\n");
return;
}
@ -621,7 +621,7 @@ void PyC_StackSpit(void)
{
/* NOTE: allow calling from outside python (RNA). */
if (!PyC_IsInterpreterActive()) {
fprintf(stderr, "python line lookup failed, interpreter inactive\n");
fprintf(stderr, "Python line lookup failed, interpreter inactive\n");
return;
}

View File

@ -410,7 +410,7 @@ void BPY_python_start(bContext *C, int argc, const char **argv)
else {
/* Set to `sys.executable = None` below (we can't do before Python is initialized). */
fprintf(stderr,
"Unable to find the python binary, "
"Unable to find the Python binary, "
"the multiprocessing module may not be functional!\n");
}
}
@ -427,7 +427,7 @@ void BPY_python_start(bContext *C, int argc, const char **argv)
if (strchr(py_path_bundle, ':')) {
fprintf(stderr,
"Warning! Blender application is located in a path containing ':' or '/' chars\n"
"This may make python import function fail\n");
"This may make Python import function fail\n");
}
# endif /* __APPLE__ */

View File

@ -156,7 +156,7 @@ PyDoc_STRVAR(
" :type str_ref_unit: string or None\n"
" :return: The converted/interpreted value.\n"
" :rtype: float\n"
" :raises ValueError: if conversion fails to generate a valid python float value.\n");
" :raises ValueError: if conversion fails to generate a valid Python float value.\n");
static PyObject *bpyunits_to_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
char *usys_str = NULL, *ucat_str = NULL, *inpt = NULL, *uref = NULL;
@ -243,7 +243,7 @@ PyDoc_STRVAR(bpyunits_to_string_doc,
" :type compatible_unit: bool\n"
" :return: The converted string.\n"
" :rtype: str\n"
" :raises ValueError: if conversion fails to generate a valid python string.\n");
" :raises ValueError: if conversion fails to generate a valid Python string.\n");
static PyObject *bpyunits_to_string(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
char *usys_str = NULL, *ucat_str = NULL;

View File

@ -475,7 +475,7 @@ static PyObject *Vector_resize(VectorObject *self, PyObject *value)
if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize(): "
"cannot resize wrapped data - only python vectors");
"cannot resize wrapped data - only Python vectors");
return NULL;
}
if (self->cb_user) {
@ -559,7 +559,7 @@ static PyObject *Vector_resize_2d(VectorObject *self)
if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize_2d(): "
"cannot resize wrapped data - only python vectors");
"cannot resize wrapped data - only Python vectors");
return NULL;
}
if (self->cb_user) {
@ -590,7 +590,7 @@ static PyObject *Vector_resize_3d(VectorObject *self)
if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize_3d(): "
"cannot resize wrapped data - only python vectors");
"cannot resize wrapped data - only Python vectors");
return NULL;
}
if (self->cb_user) {
@ -625,7 +625,7 @@ static PyObject *Vector_resize_4d(VectorObject *self)
if (self->flag & BASE_MATH_FLAG_IS_WRAP) {
PyErr_SetString(PyExc_TypeError,
"Vector.resize_4d(): "
"cannot resize wrapped data - only python vectors");
"cannot resize wrapped data - only Python vectors");
return NULL;
}
if (self->cb_user) {

View File

@ -299,7 +299,7 @@ static void wm_window_match_keep_current_wm(const bContext *C,
BKE_workspace_active_set(win->workspace_hook, workspace);
win->scene = CTX_data_scene(C);
/* all windows get active screen from file */
/* All windows get active screen from file. */
if (screen->winid == 0) {
WM_window_set_active_screen(win, workspace, screen);
}

View File

@ -145,7 +145,7 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
ot->srna, "filter_movie", (filter & FILE_TYPE_MOVIE) != 0, "Filter movie files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna, "filter_python", (filter & FILE_TYPE_PYSCRIPT) != 0, "Filter python files", "");
ot->srna, "filter_python", (filter & FILE_TYPE_PYSCRIPT) != 0, "Filter Python files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna, "filter_font", (filter & FILE_TYPE_FTFONT) != 0, "Filter font files", "");