Refactoring: Corrections and unifications in mathematics vfont gizmos #107193

Closed
Iliya Katushenock wants to merge 19 commits from mod_moder/blender:tmp_fix_text_cursor_transform into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
103 changed files with 1205 additions and 593 deletions
Showing only changes of commit cb95789a7f - Show all commits

View File

@ -58,9 +58,6 @@ Static Source Code Checking
* check_cppcheck: Run blender source through cppcheck (C & C++).
* check_clang_array: Run blender source through clang array checking script (C & C++).
* check_deprecated: Check if there is any deprecated code to remove.
* check_splint: Run blenders source through splint (C only).
* check_sparse: Run blenders source through sparse (C only).
* check_smatch: Run blenders source through smatch (C only).
* check_descriptions: Check for duplicate/invalid descriptions.
* check_licenses: Check license headers follow the SPDX license specification,
using one of the accepted licenses in 'doc/license/SPDX-license-identifiers.txt'
@ -474,21 +471,6 @@ check_clang_array: .FORCE
@cd "$(BUILD_DIR)" ; \
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_clang_array.py"
check_splint: .FORCE
@$(CMAKE_CONFIG)
@cd "$(BUILD_DIR)" ; \
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_splint.py"
check_sparse: .FORCE
@$(CMAKE_CONFIG)
@cd "$(BUILD_DIR)" ; \
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_sparse.py"
check_smatch: .FORCE
@$(CMAKE_CONFIG)
@cd "$(BUILD_DIR)" ; \
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_smatch.py"
check_mypy: .FORCE
@$(PYTHON) "$(BLENDER_DIR)/tools/check_source/check_mypy.py"

View File

@ -1,58 +0,0 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
]
CHECKER_BIN = "smatch"
CHECKER_ARGS = [
"--full-path",
"--two-passes",
]
import project_source_info
import subprocess
import sys
import os
USE_QUIET = (os.environ.get("QUIET", None) is not None)
def main():
source_info = project_source_info.build_info(use_cxx=False, ignore_prefix_list=CHECKER_IGNORE_PREFIX)
source_defines = project_source_info.build_defines_as_args()
check_commands = []
for c, inc_dirs, defs in source_info:
cmd = ([CHECKER_BIN] +
CHECKER_ARGS +
[c] +
[("-I%s" % i) for i in inc_dirs] +
[("-D%s" % d) for d in defs] +
source_defines
)
check_commands.append((c, cmd))
def my_process(i, c, cmd):
if not USE_QUIET:
percent = 100.0 * (i / len(check_commands))
percent_str = "[" + ("%.2f]" % percent).rjust(7) + " %:"
sys.stdout.flush()
sys.stdout.write("%s %s\n" % (percent_str, c))
return subprocess.Popen(cmd)
process_functions = []
for i, (c, cmd) in enumerate(check_commands):
process_functions.append((my_process, (i, c, cmd)))
project_source_info.queue_processes(process_functions)
if __name__ == "__main__":
main()

View File

@ -1,56 +0,0 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
]
CHECKER_BIN = "sparse"
CHECKER_ARGS = [
]
import project_source_info
import subprocess
import sys
import os
USE_QUIET = (os.environ.get("QUIET", None) is not None)
def main():
source_info = project_source_info.build_info(use_cxx=False, ignore_prefix_list=CHECKER_IGNORE_PREFIX)
source_defines = project_source_info.build_defines_as_args()
check_commands = []
for c, inc_dirs, defs in source_info:
cmd = ([CHECKER_BIN] +
CHECKER_ARGS +
[c] +
[("-I%s" % i) for i in inc_dirs] +
[("-D%s" % d) for d in defs] +
source_defines
)
check_commands.append((c, cmd))
def my_process(i, c, cmd):
if not USE_QUIET:
percent = 100.0 * (i / len(check_commands))
percent_str = "[" + ("%.2f]" % percent).rjust(7) + " %:"
sys.stdout.flush()
sys.stdout.write("%s %s\n" % (percent_str, c))
return subprocess.Popen(cmd)
process_functions = []
for i, (c, cmd) in enumerate(check_commands):
process_functions.append((my_process, (i, c, cmd)))
project_source_info.queue_processes(process_functions)
if __name__ == "__main__":
main()

View File

@ -1,86 +0,0 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
]
CHECKER_BIN = "splint"
CHECKER_ARGS = [
"-weak",
"-posix-lib",
"-linelen", "10000",
"+ignorequals",
"+relaxtypes",
"-retvalother",
"+matchanyintegral",
"+longintegral",
"+ignoresigns",
"-nestcomment",
"-predboolothers",
"-ifempty",
"-unrecogcomments",
# we may want to remove these later
"-type",
"-fixedformalarray",
"-fullinitblock",
"-fcnuse",
"-initallelements",
"-castfcnptr",
# -forcehints,
"-bufferoverflowhigh", # warns a lot about sprintf()
# re-definitions, rna causes most of these
"-redef",
"-syntax",
# dummy, witjout this splint complains with:
# /usr/include/bits/confname.h:31:27: *** Internal Bug at cscannerHelp.c:2428: Unexpanded macro not function or constant: int _PC_MAX_CANON
"-D_PC_MAX_CANON=0",
]
import project_source_info
import subprocess
import sys
import os
USE_QUIET = (os.environ.get("QUIET", None) is not None)
def main():
source_info = project_source_info.build_info(use_cxx=False, ignore_prefix_list=CHECKER_IGNORE_PREFIX)
check_commands = []
for c, inc_dirs, defs in source_info:
cmd = ([CHECKER_BIN] +
CHECKER_ARGS +
[c] +
[("-I%s" % i) for i in inc_dirs] +
[("-D%s" % d) for d in defs]
)
check_commands.append((c, cmd))
def my_process(i, c, cmd):
if not USE_QUIET:
percent = 100.0 * (i / len(check_commands))
percent_str = "[" + ("%.2f]" % percent).rjust(7) + " %:"
sys.stdout.write("%s %s\n" % (percent_str, c))
sys.stdout.flush()
return subprocess.Popen(cmd)
process_functions = []
for i, (c, cmd) in enumerate(check_commands):
process_functions.append((my_process, (i, c, cmd)))
project_source_info.queue_processes(process_functions)
if __name__ == "__main__":
main()

View File

@ -865,29 +865,40 @@ Unfortunate Corner Cases
Besides all expected cases listed above, there are a few others that should not be
an issue but, due to internal implementation details, currently are:
- ``Object.hide_viewport``, ``Object.hide_select`` and ``Object.hide_render``:
Setting any of those Booleans will trigger a rebuild of Collection caches,
thus breaking any current iteration over ``Collection.all_objects``.
Collection Objects
^^^^^^^^^^^^^^^^^^
Changing: ``Object.hide_viewport``, ``Object.hide_select`` or ``Object.hide_render``
will trigger a rebuild of Collection caches, thus breaking any current iteration over ``Collection.all_objects``.
.. rubric:: Do not:
.. code-block:: python
# `all_objects` is an iterator. Using it directly while performing operations on its members that will update
# the memory accessed by the `all_objects` iterator will lead to invalid memory accesses and crashes.
for object in bpy.data.collections["Collection"].all_objects:
object.hide_viewport = True
.. rubric:: Do not:
.. rubric:: Do:
.. code-block:: python
.. code-block:: python
# `all_objects` is an iterator. Using it directly while performing operations on its members that will update
# the memory accessed by the `all_objects` iterator will lead to invalid memory accesses and crashes.
for object in bpy.data.collections["Collection"].all_objects:
object.hide_viewport = True
# `all_objects[:]` is an independent list generated from the iterator. As long as no objects are deleted,
# its content will remain valid even if the data accessed by the `all_objects` iterator is modified.
for object in bpy.data.collections["Collection"].all_objects[:]:
object.hide_viewport = True
.. rubric:: Do:
Data-Blocks Renaming During Iteration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: python
# `all_objects[:]` is an independent list generated from the iterator. As long as no objects are deleted,
# its content will remain valid even if the data accessed by the `all_objects` iterator is modified.
for object in bpy.data.collections["Collection"].all_objects[:]:
object.hide_viewport = True
Data-blocks accessed from ``bpy.data`` are sorted when their name is set.
Any loop that iterates of a data such as ``bpy.data.objects`` for example,
and sets the objects ``name`` must get all items from the iterator first (typically by converting to a list or tuple)
to avoid missing some objects and iterating over others multiple times.
sys.exit

View File

@ -903,13 +903,14 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
auto extensions_available = getExtensionsAvailable();
vector<const char *> layers_enabled;
if (m_debug) {
enableLayer(layers_available, layers_enabled, VkLayer::KHRONOS_validation, m_debug);
}
vector<const char *> extensions_device;
vector<const char *> extensions_enabled;
if (m_debug) {
enableLayer(layers_available, layers_enabled, VkLayer::KHRONOS_validation, m_debug);
requireExtension(extensions_available, extensions_enabled, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
if (use_window_surface) {
const char *native_surface_extension_name = getPlatformSpecificSurfaceExtension();

View File

@ -99,7 +99,12 @@ static bool use_xwayland_hack = false;
using namespace std;
GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(nullptr), m_start_time(0)
GHOST_SystemX11::GHOST_SystemX11()
: GHOST_System(),
m_xkb_descr(nullptr),
m_start_time(0),
m_keyboard_vector{0},
m_keycode_last_repeat_key(uint(-1))
{
XInitThreads();
m_display = XOpenDisplay(nullptr);
@ -897,7 +902,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
#endif /* WITH_X11_XINPUT */
switch (xe->type) {
case Expose: {
XExposeEvent &xee = xe->xexpose;
const XExposeEvent &xee = xe->xexpose;
if (xee.count == 0) {
/* Only generate a single expose event
@ -909,7 +914,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
}
case MotionNotify: {
XMotionEvent &xme = xe->xmotion;
const XMotionEvent &xme = xe->xmotion;
bool is_tablet = window->GetTabletData().Active != GHOST_kTabletModeNone;
@ -1235,7 +1240,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
case ButtonPress:
case ButtonRelease: {
XButtonEvent &xbe = xe->xbutton;
const XButtonEvent &xbe = xe->xbutton;
GHOST_TButton gbmask = GHOST_kButtonMaskLeft;
GHOST_TEventType type = (xbe.type == ButtonPress) ? GHOST_kEventButtonDown :
GHOST_kEventButtonUp;
@ -1290,14 +1295,14 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
/* change of size, border, layer etc. */
case ConfigureNotify: {
// XConfigureEvent & xce = xe->xconfigure;
// const XConfigureEvent & xce = xe->xconfigure;
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window);
break;
}
case FocusIn:
case FocusOut: {
XFocusChangeEvent &xfe = xe->xfocus;
const XFocusChangeEvent &xfe = xe->xfocus;
/* TODO: make sure this is the correct place for activate/deactivate */
// printf("X: focus %s for window %d\n",
@ -1385,7 +1390,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
* (really crossing between windows) since some window-managers
* also send grab/un-grab crossings for mouse-wheel events.
*/
XCrossingEvent &xce = xe->xcrossing;
const XCrossingEvent &xce = xe->xcrossing;
if (xce.mode == NotifyNormal) {
g_event = new GHOST_EventCursor(getMilliSeconds(),
GHOST_kEventCursorMove,
@ -2376,7 +2381,7 @@ class DialogData {
}
/* Is the mouse inside the given button */
bool isInsideButton(XEvent &e, uint button_num)
bool isInsideButton(const XEvent &e, uint button_num)
{
return (
(e.xmotion.y > int(height - padding_y - button_height)) &&

View File

@ -21,22 +21,21 @@ GHOST_Window::GHOST_Window(uint32_t width,
const bool wantStereoVisual,
const bool /*exclusive*/)
: m_drawingContextType(GHOST_kDrawingContextTypeNone),
m_userData(nullptr),
m_cursorVisible(true),
m_cursorGrab(GHOST_kGrabDisable),
m_cursorGrabAxis(GHOST_kAxisNone),
m_cursorGrabInitPos{0, 0},
m_cursorGrabAccumPos{0, 0},
m_cursorShape(GHOST_kStandardCursorDefault),
m_progressBarVisible(false),
m_canAcceptDragOperation(false),
m_isUnsavedChanges(false),
m_wantStereoVisual(wantStereoVisual),
m_nativePixelSize(1.0f),
m_context(new GHOST_ContextNone(false))
{
m_isUnsavedChanges = false;
m_canAcceptDragOperation = false;
m_progressBarVisible = false;
m_cursorGrabAccumPos[0] = 0;
m_cursorGrabAccumPos[1] = 0;
m_nativePixelSize = 1.0f;
m_fullScreen = state == GHOST_kWindowStateFullScreen;
if (m_fullScreen) {

View File

@ -6848,6 +6848,17 @@ def km_3d_view_tool_cursor(params):
)
def km_3d_view_tool_text_select(params):
return (
"3D View Tool: Edit Text, Select Text",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
("font.selection_set", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
("font.select_word", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
]},
)
def km_3d_view_tool_select(params, *, fallback):
if params.use_tweak_select_passthrough:
operator_props = (("vert_without_handles", True),)
@ -8264,6 +8275,7 @@ def generate_keymaps(params=None):
*(km_node_editor_tool_select_circle(params, fallback=fallback) for fallback in (False, True)),
km_node_editor_tool_links_cut(params),
km_3d_view_tool_cursor(params),
km_3d_view_tool_text_select(params),
*(km_3d_view_tool_select(params, fallback=fallback) for fallback in (False, True)),
*(km_3d_view_tool_select_box(params, fallback=fallback) for fallback in (False, True)),
*(km_3d_view_tool_select_circle(params, fallback=fallback) for fallback in (False, True)),

View File

@ -1284,6 +1284,20 @@ class _defs_edit_curve:
)
class _defs_edit_text:
@ToolDef.from_fn
def select_text():
return dict(
idname="builtin.select_text",
label="Select Text",
cursor='TEXT',
icon="ops.generic.select_box",
widget=None,
keymap=(),
)
class _defs_pose:
@ToolDef.from_fn
@ -2980,6 +2994,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
_defs_transform.shear,
],
'EDIT_TEXT': [
_defs_edit_text.select_text,
_defs_view3d_generic.cursor,
None,
*_tools_annotate,

View File

@ -29,7 +29,7 @@ namespace blender::bke {
*
* Once created, #AnonymousAttributeID is immutable. Also it is intrinsically reference counted so
* that it can have shared ownership. `std::shared_ptr` can't be used for that purpose here,
* because that is not available in C code. If possible, the #AutoAnonymousAttributeID wrapper
* because that is not available in C code. If possible, the #AnonymousAttributeIDPtr wrapper
* should be used to avoid manual reference counting in C++ code.
*/
class AnonymousAttributeID : public ImplicitSharingMixin {
@ -54,7 +54,7 @@ class AnonymousAttributeID : public ImplicitSharingMixin {
};
/** Wrapper for #AnonymousAttributeID that avoids manual reference counting. */
using AutoAnonymousAttributeID = ImplicitSharingPtr<const AnonymousAttributeID>;
using AnonymousAttributeIDPtr = ImplicitSharingPtr<const AnonymousAttributeID>;
/**
* A set of anonymous attribute names that is passed around in geometry nodes.

View File

@ -55,7 +55,7 @@ struct BasisCache {
class CurvesGeometryRuntime {
public:
/** Implicit sharing user count for #CurvesGeometry::curve_offsets. */
ImplicitSharingInfo *curve_offsets_sharing_info = nullptr;
const ImplicitSharingInfo *curve_offsets_sharing_info = nullptr;
/**
* The cached number of curves with each type. Unlike other caches here, this is not computed

View File

@ -259,11 +259,11 @@ class NormalFieldInput : public GeometryFieldInput {
class AnonymousAttributeFieldInput : public GeometryFieldInput {
private:
AutoAnonymousAttributeID anonymous_id_;
AnonymousAttributeIDPtr anonymous_id_;
std::string producer_name_;
public:
AnonymousAttributeFieldInput(AutoAnonymousAttributeID anonymous_id,
AnonymousAttributeFieldInput(AnonymousAttributeIDPtr anonymous_id,
const CPPType &type,
std::string producer_name)
: GeometryFieldInput(type, anonymous_id->user_name()),
@ -274,7 +274,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
}
template<typename T>
static fn::Field<T> Create(AutoAnonymousAttributeID anonymous_id, std::string producer_name)
static fn::Field<T> Create(AnonymousAttributeIDPtr anonymous_id, std::string producer_name)
{
const CPPType &type = CPPType::get<T>();
auto field_input = std::make_shared<AnonymousAttributeFieldInput>(
@ -282,7 +282,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
return fn::Field<T>{field_input};
}
const AutoAnonymousAttributeID &anonymous_id() const
const AnonymousAttributeIDPtr &anonymous_id() const
{
return anonymous_id_;
}

View File

@ -98,7 +98,7 @@ struct MeshRuntime {
std::mutex render_mutex;
/** Implicit sharing user count for #Mesh::poly_offset_indices. */
ImplicitSharingInfoHandle *poly_offsets_sharing_info;
const ImplicitSharingInfoHandle *poly_offsets_sharing_info;
/**
* A cache of bounds shared between data-blocks with unchanged positions. When changing positions

View File

@ -154,6 +154,11 @@ void BKE_sound_set_scene_sound_volume(void *handle, float volume, char animated)
void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated);
void BKE_sound_set_scene_sound_pitch_constant_range(void *handle,
int frame_start,
int frame_end,
float pitch);
void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated);
void BKE_sound_update_sequencer(struct Main *main, struct bSound *sound);

View File

@ -89,6 +89,9 @@ bool BKE_vfont_to_curve_ex(struct Object *ob,
bool *r_text_free,
struct CharTrans **r_chartransdata);
bool BKE_vfont_to_curve_nubase(struct Object *ob, int mode, struct ListBase *r_nubase);
int BKE_vfont_cursor_to_text_index(struct Object *ob, float cursor_location[2]);
/**
* \warning Expects to have access to evaluated data (i.e. passed object should be evaluated one).
*/

View File

@ -833,8 +833,7 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree(float epsilon,
}
static BVHTree *bvhtree_from_mesh_edges_create_tree(const float (*positions)[3],
const blender::int2 *edge,
const int edge_num,
blender::Span<blender::int2> edges,
const BitSpan edges_mask,
int edges_num_active,
float epsilon,
@ -842,10 +841,10 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(const float (*positions)[3],
int axis)
{
if (!edges_mask.is_empty()) {
BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num));
BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges.size()));
}
else {
edges_num_active = edge_num;
edges_num_active = edges.size();
}
if (edges_num_active == 0) {
return nullptr;
@ -857,13 +856,13 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(const float (*positions)[3],
return nullptr;
}
for (int i = 0; i < edge_num; i++) {
for (const int i : edges.index_range()) {
if (!edges_mask.is_empty() && !edges_mask[i]) {
continue;
}
float co[2][3];
copy_v3_v3(co[0], positions[edge[i][0]]);
copy_v3_v3(co[1], positions[edge[i][1]]);
copy_v3_v3(co[0], positions[edges[i][0]]);
copy_v3_v3(co[1], positions[edges[i][1]]);
BLI_bvhtree_insert(tree, i, co[0], 2);
}
@ -908,7 +907,7 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
int axis)
{
BVHTree *tree = bvhtree_from_mesh_edges_create_tree(
vert_positions, edge, edges_num, edges_mask, edges_num_active, epsilon, tree_type, axis);
vert_positions, {edge, edges_num}, edges_mask, edges_num_active, epsilon, tree_type, axis);
bvhtree_balance(tree, false);
@ -1166,14 +1165,6 @@ static BitVector<> loose_verts_map_get(const Span<blender::int2> edges,
return loose_verts_mask;
}
static BitVector<> loose_edges_map_get(const Mesh &mesh, int *r_loose_edge_len)
{
using namespace blender::bke;
const LooseEdgeCache &loose_edges = mesh.loose_edges();
*r_loose_edge_len = loose_edges.count;
return loose_edges.is_loose_bits;
}
static BitVector<> looptri_no_hidden_map_get(const blender::OffsetIndices<int> polys,
const VArray<bool> &hide_poly,
const int looptri_len,
@ -1243,27 +1234,32 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
}
/* Create BVHTree. */
BitVector<> mask;
int mask_bits_act_len = -1;
switch (bvh_cache_type) {
case BVHTREE_FROM_LOOSEVERTS:
mask = loose_verts_map_get(edges, mesh->totvert, &mask_bits_act_len);
ATTR_FALLTHROUGH;
case BVHTREE_FROM_VERTS:
case BVHTREE_FROM_LOOSEVERTS: {
int mask_bits_act_len = -1;
const BitVector<> mask = loose_verts_map_get(edges, mesh->totvert, &mask_bits_act_len);
data->tree = bvhtree_from_mesh_verts_create_tree(
0.0f, tree_type, 6, positions, mesh->totvert, mask, mask_bits_act_len);
break;
case BVHTREE_FROM_LOOSEEDGES:
mask = loose_edges_map_get(*mesh, &mask_bits_act_len);
ATTR_FALLTHROUGH;
case BVHTREE_FROM_EDGES:
data->tree = bvhtree_from_mesh_edges_create_tree(
positions, edges.data(), mesh->totedge, mask, mask_bits_act_len, 0.0f, tree_type, 6);
}
case BVHTREE_FROM_VERTS: {
data->tree = bvhtree_from_mesh_verts_create_tree(
0.0f, tree_type, 6, positions, mesh->totvert, {}, -1);
break;
case BVHTREE_FROM_FACES:
}
case BVHTREE_FROM_LOOSEEDGES: {
const blender::bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
data->tree = bvhtree_from_mesh_edges_create_tree(
positions, edges, loose_edges.is_loose_bits, loose_edges.count, 0.0f, tree_type, 6);
break;
}
case BVHTREE_FROM_EDGES: {
data->tree = bvhtree_from_mesh_edges_create_tree(
positions, edges, {}, -1, 0.0f, tree_type, 6);
break;
}
case BVHTREE_FROM_FACES: {
BLI_assert(!(mesh->totface == 0 && mesh->totpoly != 0));
data->tree = bvhtree_from_mesh_faces_create_tree(
0.0f,
@ -1275,25 +1271,29 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
{},
-1);
break;
}
case BVHTREE_FROM_LOOPTRI_NO_HIDDEN: {
blender::bke::AttributeAccessor attributes = mesh->attributes();
mask = looptri_no_hidden_map_get(
int mask_bits_act_len = -1;
const BitVector<> mask = looptri_no_hidden_map_get(
mesh->polys(),
*attributes.lookup_or_default(".hide_poly", ATTR_DOMAIN_FACE, false),
looptris.size(),
&mask_bits_act_len);
ATTR_FALLTHROUGH;
}
case BVHTREE_FROM_LOOPTRI:
data->tree = bvhtree_from_mesh_looptri_create_tree(
0.0f, tree_type, 6, positions, corner_verts.data(), looptris, mask, mask_bits_act_len);
break;
}
case BVHTREE_FROM_LOOPTRI: {
data->tree = bvhtree_from_mesh_looptri_create_tree(
0.0f, tree_type, 6, positions, corner_verts.data(), looptris, {}, -1);
break;
}
case BVHTREE_FROM_EM_VERTS:
case BVHTREE_FROM_EM_EDGES:
case BVHTREE_FROM_EM_LOOPTRI:
case BVHTREE_MAX_ITEM:
BLI_assert(false);
BLI_assert_unreachable();
break;
}

View File

@ -198,7 +198,7 @@ static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
* anyway... */
const int cb_flag = ((parent->collection != NULL &&
(parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
IDWALK_CB_EMBEDDED :
IDWALK_CB_EMBEDDED_NOT_OWNING :
IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag);

View File

@ -2376,9 +2376,9 @@ class CustomDataLayerImplicitSharing : public ImplicitSharingInfo {
};
/** Create a #ImplicitSharingInfo that takes ownership of the data. */
static ImplicitSharingInfo *make_implicit_sharing_info_for_layer(const eCustomDataType type,
const void *data,
const int totelem)
static const ImplicitSharingInfo *make_implicit_sharing_info_for_layer(const eCustomDataType type,
const void *data,
const int totelem)
{
return MEM_new<CustomDataLayerImplicitSharing>(__func__, data, totelem, type);
}

View File

@ -431,7 +431,9 @@ CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t
/* expand array */
newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer");
memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
if (cdf->totlayer > 0) {
memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
}
cdf->layer = newlayer;
cdf->totlayer++;

View File

@ -63,20 +63,10 @@ BLI_INLINE void mesh_calc_tessellation_for_face_impl(const Span<int> corner_vert
MLoopTri *mlt_a = mlt++;
create_tri(0, 2, 3);
MLoopTri *mlt_b = mlt;
if (UNLIKELY(face_normal ? is_quad_flip_v3_first_third_fast_with_normal(
/* Simpler calculation (using the normal). */
positions[corner_verts[mlt_a->tri[0]]],
positions[corner_verts[mlt_a->tri[1]]],
positions[corner_verts[mlt_a->tri[2]]],
positions[corner_verts[mlt_b->tri[2]]],
normal_precalc) :
is_quad_flip_v3_first_third_fast(
/* Expensive calculation (no normal). */
positions[corner_verts[mlt_a->tri[0]]],
positions[corner_verts[mlt_a->tri[1]]],
positions[corner_verts[mlt_a->tri[2]]],
positions[corner_verts[mlt_b->tri[2]]]))) {
if (UNLIKELY(is_quad_flip_v3_first_third_fast(positions[corner_verts[mlt_a->tri[0]]],
positions[corner_verts[mlt_a->tri[1]]],
positions[corner_verts[mlt_a->tri[2]]],
positions[corner_verts[mlt_b->tri[2]]]))) {
/* Flip out of degenerate 0-2 state. */
mlt_a->tri[2] = mlt_b->tri[2];
mlt_b->tri[0] = mlt_a->tri[1];

View File

@ -819,6 +819,15 @@ void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated)
AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, sound_cfra, &pitch, animated);
}
void BKE_sound_set_scene_sound_pitch_constant_range(void *handle,
int frame_start,
int frame_end,
float pitch)
{
AUD_SequenceEntry_setConstantRangeAnimationData(
handle, AUD_AP_PITCH, frame_start, frame_end, &pitch);
}
void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated)
{
AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated);
@ -1369,6 +1378,12 @@ void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle),
char UNUSED(animated))
{
}
void BKE_sound_set_scene_sound_pitch_constant_range(void *UNUSED(handle),
int UNUSED(frame_start),
int UNUSED(frame_end),
float UNUSED(pitch))
{
}
float BKE_sound_get_length(struct Main *UNUSED(bmain), bSound *UNUSED(sound))
{
return 0;

View File

@ -734,6 +734,25 @@ typedef struct VFontToCurveIter {
int status;
} VFontToCurveIter;
/** \} */
/* -------------------------------------------------------------------- */
/** \name VFont Mouse Cursor to Text Offset
*
* This is an optional argument to `vfont_to_curve` for getting the text
* offset into the string at a mouse cursor location. Used for getting
* text cursor (caret) position or selection range.
* \{ */
/* Used when translating a mouse cursor location to a position within the string. */
typedef struct VFontCursor_Params {
/* Mouse cursor location in Object coordinate space as input. */
float cursor_location[2];
/* Character position within EditFont::textbuf as output. */
int r_string_offset;
} VFontCursor_Params;
/** \} */
enum {
VFONT_TO_CURVE_INIT = 0,
VFONT_TO_CURVE_BISECT,
@ -774,6 +793,7 @@ static bool vfont_to_curve(Object *ob,
Curve *cu,
int mode,
VFontToCurveIter *iter_data,
struct VFontCursor_Params *cursor_params,
ListBase *r_nubase,
const char32_t **r_text,
int *r_text_len,
@ -1441,6 +1461,35 @@ static bool vfont_to_curve(Object *ob,
}
}
if (cursor_params) {
cursor_params->r_string_offset = -1;
for (i = 0; i <= slen; i++, ct++) {
info = &custrinfo[i];
ascii = mem[i];
if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
ascii = towupper(ascii);
}
ct = &chartransdata[i];
che = find_vfont_char(vfd, ascii);
float charwidth = char_width(cu, che, info);
float charhalf = (charwidth / 2.0f);
if (cursor_params->cursor_location[1] >= ct->yof - (0.25f * linedist) &&
cursor_params->cursor_location[1] <= (ct->yof + (0.75f * linedist))) {
/* On this row. */
if (cursor_params->cursor_location[0] >= (ct->xof) &&
cursor_params->cursor_location[0] <= (ct->xof + charhalf)) {
/* Left half of character. */
cursor_params->r_string_offset = i;
}
else if (cursor_params->cursor_location[0] >= (ct->xof + charhalf) &&
cursor_params->cursor_location[0] <= (ct->xof + charwidth)) {
/* Right half of character. */
cursor_params->r_string_offset = i + 1;
}
}
}
}
if (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN) &&
iter_data->status == VFONT_TO_CURVE_INIT) {
ct = &chartransdata[ef->pos];
@ -1751,13 +1800,49 @@ bool BKE_vfont_to_curve_ex(Object *ob,
};
do {
data.ok &= vfont_to_curve(
ob, cu, mode, &data, r_nubase, r_text, r_text_len, r_text_free, r_chartransdata);
data.ok &= vfont_to_curve(ob,
cu,
mode,
&data,
NULL,
r_nubase,
r_text,
r_text_len,
r_text_free,
r_chartransdata);
} while (data.ok && ELEM(data.status, VFONT_TO_CURVE_SCALE_ONCE, VFONT_TO_CURVE_BISECT));
return data.ok;
}
int BKE_vfont_cursor_to_text_index(Object *ob, float cursor_location[2])
{
Curve *cu = (Curve *)ob->data;
ListBase *r_nubase = &cu->nurb;
/* TODO: iterating to calculate the scale can be avoided. */
VFontToCurveIter data = {
.iteraction = cu->totbox * FONT_TO_CURVE_SCALE_ITERATIONS,
.scale_to_fit = 1.0f,
.word_wrap = true,
.ok = true,
.status = VFONT_TO_CURVE_INIT,
};
VFontCursor_Params cursor_params = {
.cursor_location = {cursor_location[0], cursor_location[1]},
.r_string_offset = -1,
};
do {
data.ok &= vfont_to_curve(
ob, cu, FO_CURS, &data, &cursor_params, r_nubase, NULL, NULL, NULL, NULL);
} while (data.ok && ELEM(data.status, VFONT_TO_CURVE_SCALE_ONCE, VFONT_TO_CURVE_BISECT));
return cursor_params.r_string_offset;
}
#undef FONT_TO_CURVE_SCALE_ITERATIONS
#undef FONT_TO_CURVE_SCALE_THRESHOLD

View File

@ -110,11 +110,11 @@ void *resize_trivial_array_impl(void *old_data,
int64_t old_size,
int64_t new_size,
int64_t alignment,
ImplicitSharingInfo **sharing_info);
const ImplicitSharingInfo **sharing_info);
void *make_trivial_data_mutable_impl(void *old_data,
int64_t size,
int64_t alignment,
ImplicitSharingInfo **sharing_info);
const ImplicitSharingInfo **sharing_info);
} // namespace detail
@ -124,9 +124,9 @@ void *make_trivial_data_mutable_impl(void *old_data,
*/
template<typename T>
void copy_shared_pointer(T *src_ptr,
ImplicitSharingInfo *src_sharing_info,
const ImplicitSharingInfo *src_sharing_info,
T **r_dst_ptr,
ImplicitSharingInfo **r_dst_sharing_info)
const ImplicitSharingInfo **r_dst_sharing_info)
{
*r_dst_ptr = src_ptr;
*r_dst_sharing_info = src_sharing_info;
@ -139,7 +139,7 @@ void copy_shared_pointer(T *src_ptr,
/**
* Remove this reference to the shared data and remove dangling pointers.
*/
template<typename T> void free_shared_data(T **data, ImplicitSharingInfo **sharing_info)
template<typename T> void free_shared_data(T **data, const ImplicitSharingInfo **sharing_info)
{
if (*sharing_info) {
BLI_assert(*data != nullptr);
@ -153,13 +153,15 @@ template<typename T> void free_shared_data(T **data, ImplicitSharingInfo **shari
* Create an implicit sharing object that takes ownership of the data, allowing it to be shared.
* When it is no longer used, the data is freed with #MEM_freeN, so it must be a trivial type.
*/
ImplicitSharingInfo *info_for_mem_free(void *data);
const ImplicitSharingInfo *info_for_mem_free(void *data);
/**
* Make data mutable (single-user) if it is shared. For trivially-copyable data only.
*/
template<typename T>
void make_trivial_data_mutable(T **data, ImplicitSharingInfo **sharing_info, const int64_t size)
void make_trivial_data_mutable(T **data,
const ImplicitSharingInfo **sharing_info,
const int64_t size)
{
*data = static_cast<T *>(
detail::make_trivial_data_mutable_impl(*data, sizeof(T) * size, alignof(T), sharing_info));
@ -171,7 +173,7 @@ void make_trivial_data_mutable(T **data, ImplicitSharingInfo **sharing_info, con
*/
template<typename T>
void resize_trivial_array(T **data,
ImplicitSharingInfo **sharing_info,
const ImplicitSharingInfo **sharing_info,
int64_t old_size,
int64_t new_size)
{

View File

@ -145,11 +145,6 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3]);
bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3],
const float normal[3]);
/** \} */

View File

@ -26,7 +26,7 @@ class MEMFreeImplicitSharing : public ImplicitSharingInfo {
}
};
ImplicitSharingInfo *info_for_mem_free(void *data)
const ImplicitSharingInfo *info_for_mem_free(void *data)
{
return MEM_new<MEMFreeImplicitSharing>(__func__, data);
}
@ -36,7 +36,7 @@ namespace detail {
void *make_trivial_data_mutable_impl(void *old_data,
const int64_t size,
const int64_t alignment,
ImplicitSharingInfo **sharing_info)
const ImplicitSharingInfo **sharing_info)
{
if (!old_data) {
BLI_assert(size == 0);
@ -59,7 +59,7 @@ void *resize_trivial_array_impl(void *old_data,
const int64_t old_size,
const int64_t new_size,
const int64_t alignment,
ImplicitSharingInfo **sharing_info)
const ImplicitSharingInfo **sharing_info)
{
if (new_size == 0) {
if (*sharing_info) {
@ -79,7 +79,8 @@ void *resize_trivial_array_impl(void *old_data,
BLI_assert(old_size != 0);
if ((*sharing_info)->is_mutable()) {
if (auto *info = dynamic_cast<MEMFreeImplicitSharing *>(*sharing_info)) {
if (auto *info = const_cast<MEMFreeImplicitSharing *>(
dynamic_cast<const MEMFreeImplicitSharing *>(*sharing_info))) {
/* If the array was allocated with the MEM allocator, we can use realloc directly, which
* could theoretically give better performance if the data can be reused in place. */
void *new_data = static_cast<int *>(MEM_reallocN(old_data, new_size));

View File

@ -5889,6 +5889,9 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
const float v3[3],
const float v4[3])
{
/* NOTE: if the faces normal has been calculated it's possible to simplify the following checks,
* however this means the solution may be different depending on the existence of normals
* causing tessellation to be "unstable" depending on the existence of normals, see #106469. */
float d_12[3], d_13[3], d_14[3];
float cross_a[3], cross_b[3];
sub_v3_v3v3(d_12, v2, v1);
@ -5899,19 +5902,6 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
return dot_v3v3(cross_a, cross_b) > 0.0f;
}
bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3],
const float normal[3])
{
float dir_v3v1[3], tangent[3];
sub_v3_v3v3(dir_v3v1, v3, v1);
cross_v3_v3v3(tangent, dir_v3v1, normal);
const float dot = dot_v3v3(v1, tangent);
return (dot_v3v3(v4, tangent) >= dot) || (dot_v3v3(v2, tangent) <= dot);
}
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
{
BLI_ASSERT_UNIT_V3(tan_l);

View File

@ -2728,7 +2728,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
e[k + 1] += 1.0f;
}
e[k] = -e[k];
if ((k + 1 < m) & (e[k] != 0.0f)) {
if ((k + 1 < m) && (e[k] != 0.0f)) {
float invek1;
/* Apply the transformation. */
@ -2812,7 +2812,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
/* If required, generate V. */
for (k = n - 1; k >= 0; k--) {
if ((k < nrt) & (e[k] != 0.0f)) {
if ((k < nrt) && (e[k] != 0.0f)) {
for (j = k + 1; j < nu; j++) {
float t = 0;
for (i = k + 1; i < n; i++) {

View File

@ -1962,17 +1962,19 @@ static Face *cdt_tri_as_imesh_face(
return facep;
}
/* Like BLI_math's is_quad_flip_v3_first_third_fast_with_normal, with const double3's. */
/* Like BLI_math's is_quad_flip_v3_first_third_fast, with const double3's. */
static bool is_quad_flip_first_third(const double3 &v1,
const double3 &v2,
const double3 &v3,
const double3 &v4,
const double3 &normal)
const double3 &v4)
{
double3 dir_v3v1 = v3 - v1;
double3 tangent = math::cross(dir_v3v1, normal);
double dot = math::dot(v1, tangent);
return (math::dot(v4, tangent) >= dot) || (math::dot(v2, tangent) <= dot);
const double3 d_12 = v2 - v1;
const double3 d_13 = v3 - v1;
const double3 d_14 = v4 - v1;
const double3 cross_a = math::cross(d_12, d_13);
const double3 cross_b = math::cross(d_14, d_13);
return math::dot(cross_a, cross_b) > 0.0f;
}
/**
@ -2008,7 +2010,7 @@ static Array<Face *> polyfill_triangulate_poly(Face *f, IMeshArena *arena)
int eo_23 = f->edge_orig[2];
int eo_30 = f->edge_orig[3];
Face *f0, *f1;
if (UNLIKELY(is_quad_flip_first_third(v0->co, v1->co, v2->co, v3->co, f->plane->norm))) {
if (UNLIKELY(is_quad_flip_first_third(v0->co, v1->co, v2->co, v3->co))) {
f0 = arena->add_face({v0, v1, v3}, f->orig, {eo_01, -1, eo_30}, {false, false, false});
f1 = arena->add_face({v1, v2, v3}, f->orig, {eo_12, eo_23, -1}, {false, false, false});
}

View File

@ -37,22 +37,16 @@
#include "MEM_guardedalloc.h"
/* Declarations */
/* Declarations. */
static int BLI_path_unc_prefix_len(const char *path);
#ifdef WIN32
/**
* Return true if the path is absolute ie starts with a drive specifier
* (eg A:\) or is a UNC path.
*/
static bool BLI_path_is_abs(const char *name);
static bool BLI_path_is_abs_win32(const char *name);
#endif /* WIN32 */
// #define DEBUG_STRSIZE
/* implementation */
int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort *r_digits_len)
{
uint nums = 0, nume = 0;
@ -102,9 +96,8 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
strcpy(tail, string + name_end);
}
if (head) {
/* name_end points to last character of head,
* make it +1 so null-terminator is nicely placed
*/
/* Name_end points to last character of head,
* make it +1 so null-terminator is nicely placed. */
BLI_strncpy(head, string, name_end + 1);
}
if (r_digits_len) {
@ -119,8 +112,6 @@ void BLI_path_sequence_encode(
BLI_sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
}
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
void BLI_path_normalize(const char *relabase, char *path)
{
ptrdiff_t a;
@ -131,19 +122,18 @@ void BLI_path_normalize(const char *relabase, char *path)
else {
if (path[0] == '/' && path[1] == '/') {
if (path[2] == '\0') {
return; /* path is "//" - can't clean it */
return; /* Path is `//` - can't clean it. */
}
path = path + 2; /* leave the initial "//" untouched */
path = path + 2; /* Leave the initial `//` untouched. */
}
}
/* Note
* memmove(start, eind, strlen(eind) + 1);
/* NOTE(@ideasman42):
* `memmove(start, eind, strlen(eind) + 1);`
* is the same as
* strcpy(start, eind);
* except strcpy should not be used because there is overlap,
* so use memmove's slightly more obscure syntax - Campbell
*/
* `strcpy(start, eind);`
* except `strcpy` should not be used because there is overlap,
* so use `memmove` 's slightly more obscure syntax. */
#ifdef WIN32
@ -152,8 +142,8 @@ void BLI_path_normalize(const char *relabase, char *path)
memmove(start, eind, strlen(eind) + 1);
}
/* remove two consecutive backslashes, but skip the UNC prefix,
* which needs to be preserved */
/* Remove two consecutive backslashes, but skip the UNC prefix,
* which needs to be preserved. */
while ((start = strstr(path + BLI_path_unc_prefix_len(path), "\\\\"))) {
eind = start + strlen("\\\\") - 1;
memmove(start, eind, strlen(eind) + 1);
@ -179,21 +169,21 @@ void BLI_path_normalize(const char *relabase, char *path)
#else
while ((start = strstr(path, "/./"))) {
eind = start + (3 - 1) /* strlen("/./") - 1 */;
eind = start + (3 - 1) /* `strlen("/./") - 1` */;
memmove(start, eind, strlen(eind) + 1);
}
while ((start = strstr(path, "//"))) {
eind = start + (2 - 1) /* strlen("//") - 1 */;
eind = start + (2 - 1) /* `strlen("//") - 1` */;
memmove(start, eind, strlen(eind) + 1);
}
while ((start = strstr(path, "/../"))) {
a = start - path - 1;
if (a > 0) {
/* <prefix>/<parent>/../<postfix> => <prefix>/<postfix> */
eind = start + (4 - 1) /* strlen("/../") - 1 */; /* strip "/.." and keep last "/" */
while (a > 0 && path[a] != '/') { /* find start of <parent> */
/* `<prefix>/<parent>/../<postfix> => <prefix>/<postfix>`. */
eind = start + (4 - 1) /* `strlen("/../") - 1` */; /* Strip "/.." and keep last "/". */
while (a > 0 && path[a] != '/') { /* Find start of `<parent>`. */
a--;
}
memmove(path + a, eind, strlen(eind) + 1);
@ -253,7 +243,7 @@ bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens)
/* Forbid only dots. */
for (fn = fname; *fn == '.'; fn++) {
/* pass */
/* Pass. */
}
if (*fn == '\0') {
*fname = '_';
@ -279,15 +269,14 @@ bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens)
/* Check for forbidden names - not we have to check all combination
* of upper and lower cases, hence the usage of lower_fname
* (more efficient than using BLI_strcasestr repeatedly). */
* (more efficient than using #BLI_strcasestr repeatedly). */
BLI_str_tolower_ascii(lower_fname, len);
for (iname = invalid_names; *iname; iname++) {
if (strstr(lower_fname, *iname) == lower_fname) {
const size_t iname_len = strlen(*iname);
/* Only invalid if the whole name is made of the invalid chunk, or it has an
* (assumed extension) dot just after. This means it will also catch 'valid'
* names like 'aux.foo.bar', but should be
* good enough for us! */
* (assumed extension) dot just after. This means it will also catch *valid*
* names like `aux.foo.bar`, but should be good enough for us! */
if ((iname_len == len) || (lower_fname[iname_len] == '.')) {
*fname = '_';
changed = true;
@ -311,14 +300,14 @@ bool BLI_filename_make_safe(char *fname)
bool BLI_path_make_safe(char *path)
{
/* Simply apply #BLI_filename_make_safe() over each component of the path.
* Luckily enough, same 'safe' rules applies to file & directory names. */
* Luckily enough, same *safe* rules applies to file & directory names. */
char *curr_slash, *curr_path = path;
bool changed = false;
bool skip_first = false;
#ifdef WIN32
if (BLI_path_is_abs(path)) {
/* Do not make safe 'C:' in 'C:\foo\bar'... */
if (BLI_path_is_abs_win32(path)) {
/* Do not make safe `C:` in `C:\foo\bar`. */
skip_first = true;
}
#endif
@ -361,7 +350,7 @@ static int BLI_path_unc_prefix_len(const char *path)
{
if (BLI_path_is_unc(path)) {
if ((path[2] == '?') && (path[3] == '\\')) {
/* we assume long UNC path like \\?\server\share\folder etc... */
/* We assume long UNC path like `\\?\server\share\folder` etc. */
return 4;
}
@ -374,10 +363,14 @@ static int BLI_path_unc_prefix_len(const char *path)
#if defined(WIN32)
/**
* Return true if the path is absolute ie starts with a drive specifier
* (eg A:\) or is a UNC path.
* Return true if the path is an absolute path on a WIN32 file-system, it either:
* - Starts with a drive specifier* (eg `A:\`).
* - Is a UNC path.
*
* \note Not to be confused with the opposite of #BLI_path_is_rel which checks for the
* Blender specific convention of using `//` prefix for blend-file relative paths.
*/
static bool BLI_path_is_abs(const char *name)
static bool BLI_path_is_abs_win32(const char *name)
{
return (name[1] == ':' && ELEM(name[2], '\\', '/')) || BLI_path_is_unc(name);
}
@ -409,9 +402,10 @@ static void BLI_path_unc_to_short(wchar_t *unc)
wchar_t tmp[PATH_MAX];
int len = wcslen(unc);
/* convert:
* \\?\UNC\server\share\folder\... to \\server\share\folder\...
* \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
/* Convert:
* - `\\?\UNC\server\share\folder\...` to `\\server\share\folder\...`
* - `\\?\C:\` to `C:\`
* - `\\?\C:\folder\...` to `C:\folder\...`
*/
if ((len > 3) && (unc[0] == L'\\') && (unc[1] == L'\\') && (unc[2] == L'?') &&
ELEM(unc[3], L'\\', L'/')) {
@ -450,18 +444,18 @@ void BLI_path_rel(char *file, const char *relfile)
char temp[FILE_MAX];
char res[FILE_MAX];
/* if file is already relative, bail out */
/* If file is already relative, bail out. */
if (BLI_path_is_rel(file)) {
return;
}
/* also bail out if relative path is not set */
/* Also bail out if relative path is not set. */
if (relfile[0] == '\0') {
return;
}
#ifdef WIN32
if (BLI_strnlen(relfile, 3) > 2 && !BLI_path_is_abs(relfile)) {
if (BLI_strnlen(relfile, 3) > 2 && !BLI_path_is_abs_win32(relfile)) {
char *ptemp;
/* Fix missing volume name in relative base,
* can happen with old `recent-files.txt` files. */
@ -479,12 +473,12 @@ void BLI_path_rel(char *file, const char *relfile)
if (BLI_strnlen(file, 3) > 2) {
bool is_unc = BLI_path_is_unc(file);
/* Ensure paths are both UNC paths or are both drives */
/* Ensure paths are both UNC paths or are both drives. */
if (BLI_path_is_unc(temp) != is_unc) {
return;
}
/* Ensure both UNC paths are on the same share */
/* Ensure both UNC paths are on the same share. */
if (is_unc) {
int off;
int slash = 0;
@ -509,16 +503,16 @@ void BLI_path_rel(char *file, const char *relfile)
BLI_str_replace_char(temp + BLI_path_unc_prefix_len(temp), '\\', '/');
BLI_str_replace_char(file + BLI_path_unc_prefix_len(file), '\\', '/');
/* remove /./ which confuse the following slash counting... */
/* Remove `/./` which confuse the following slash counting. */
BLI_path_normalize(NULL, file);
BLI_path_normalize(NULL, temp);
/* the last slash in the file indicates where the path part ends */
/* The last slash in the file indicates where the path part ends. */
lslash = BLI_path_slash_rfind(temp);
if (lslash) {
/* find the prefix of the filename that is equal for both filenames.
* This is replaced by the two slashes at the beginning */
/* Find the prefix of the filename that is equal for both filenames.
* This is replaced by the two slashes at the beginning. */
const char *p = temp;
const char *q = file;
char *r = res;
@ -532,16 +526,14 @@ void BLI_path_rel(char *file, const char *relfile)
p++;
q++;
/* don't search beyond the end of the string
* in the rare case they match */
/* Don't search beyond the end of the string in the rare case they match. */
if ((*p == '\0') || (*q == '\0')) {
break;
}
}
/* we might have passed the slash when the beginning of a dir matches
* so we rewind. Only check on the actual filename
*/
/* We might have passed the slash when the beginning of a dir matches
* so we rewind. Only check on the actual filename. */
if (*q != '/') {
while ((q >= file) && (*q != '/')) {
q--;
@ -557,11 +549,10 @@ void BLI_path_rel(char *file, const char *relfile)
r += BLI_strcpy_rlen(r, "//");
/* p now points to the slash that is at the beginning of the part
/* `p` now points to the slash that is at the beginning of the part
* where the path is different from the relative path.
* We count the number of directories we need to go up in the
* hierarchy to arrive at the common 'prefix' of the path
*/
* hierarchy to arrive at the common prefix of the path. */
if (p < temp) {
p = temp;
}
@ -572,7 +563,7 @@ void BLI_path_rel(char *file, const char *relfile)
p++;
}
/* don't copy the slash at the beginning */
/* Don't copy the slash at the beginning. */
r += BLI_strncpy_rlen(r, q + 1, FILE_MAX - (r - res));
#ifdef WIN32
@ -627,7 +618,7 @@ bool BLI_path_parent_dir(char *path)
return false;
}
if (tail_len == 1) {
/* Last path is ".", as normalize should remove this, it's safe to assume failure.
/* Last path is `.`, as normalize should remove this, it's safe to assume failure.
* This happens when the input a single period (possibly with slashes before or after). */
if (path[tail_ofs] == '.') {
return false;
@ -646,7 +637,7 @@ bool BLI_path_parent_dir_until_exists(char *dir)
/* Loop as long as cur path is not a dir, and we can get a parent path. */
while ((BLI_access(dir, R_OK) != 0) && (valid_path = BLI_path_parent_dir(dir))) {
/* pass */
/* Pass. */
}
return (valid_path && dir[0]);
}
@ -659,11 +650,11 @@ bool BLI_path_parent_dir_until_exists(char *dir)
static bool stringframe_chars(const char *path, int *char_start, int *char_end)
{
uint ch_sta, ch_end, i;
/* Insert current frame: file### -> file001 */
/* Insert current frame: `file###` -> `file001`. */
ch_sta = ch_end = 0;
for (i = 0; path[i] != '\0'; i++) {
if (ELEM(path[i], '\\', '/')) {
ch_end = 0; /* this is a directory name, don't use any hashes we found */
ch_end = 0; /* This is a directory name, don't use any hashes we found. */
}
else if (path[i] == '#') {
ch_sta = i;
@ -671,9 +662,9 @@ static bool stringframe_chars(const char *path, int *char_start, int *char_end)
while (path[ch_end] == '#') {
ch_end++;
}
i = ch_end - 1; /* keep searching */
i = ch_end - 1; /* Keep searching. */
/* don't break, there may be a slash after this that invalidates the previous #'s */
/* Don't break, there may be a slash after this that invalidates the previous #'s. */
}
}
@ -718,7 +709,7 @@ bool BLI_path_frame(char *path, int frame, int digits)
ensure_digits(path, digits);
}
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* Warning: `ch_end` is the last # +1. */
char tmp[FILE_MAX];
BLI_snprintf(
tmp, sizeof(tmp), "%.*s%.*d%s", ch_sta, path, ch_end - ch_sta, frame, path + ch_end);
@ -736,7 +727,7 @@ 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 */
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* Warning: `ch_end` is the last # +1. */
char tmp[FILE_MAX];
BLI_snprintf(tmp,
sizeof(tmp),
@ -812,8 +803,8 @@ void BLI_path_frame_strip(char *path, char *r_ext, const size_t ext_maxlen)
bool BLI_path_frame_check_chars(const char *path)
{
int ch_sta, ch_end; /* dummy args */
return stringframe_chars(path, &ch_sta, &ch_end);
int ch_sta_dummy, ch_end_dummy;
return stringframe_chars(path, &ch_sta_dummy, &ch_end_dummy);
}
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
@ -860,16 +851,14 @@ bool BLI_path_abs(char *path, const char *basepath)
char base[FILE_MAX];
#ifdef WIN32
/* without this: "" --> "C:\" */
/* Without this, an empty string converts to: `C:\` */
if (*path == '\0') {
return wasrelative;
}
/* we are checking here if we have an absolute path that is not in the current
* blend file as a lib main - we are basically checking for the case that a
* UNIX root '/' is passed.
*/
if (!wasrelative && !BLI_path_is_abs(path)) {
/* We are checking here if we have an absolute path that is not in the current `.blend` file
* as a lib main - we are basically checking for the case that a UNIX root `/` is passed. */
if (!wasrelative && !BLI_path_is_abs_win32(path)) {
char *p = path;
BLI_windows_get_default_root_dir(tmp);
/* Get rid of the slashes at the beginning of the path. */
@ -892,7 +881,7 @@ bool BLI_path_abs(char *path, const char *basepath)
* `C:\foo.JPG` -> `/c/foo.JPG` */
if (isalpha(tmp[0]) && (tmp[1] == ':') && ELEM(tmp[2], '\\', '/')) {
tmp[1] = tolower(tmp[0]); /* Replace ':' with drive-letter. */
tmp[1] = tolower(tmp[0]); /* Replace `:` with drive-letter. */
tmp[0] = '/';
/* `\` the slash will be converted later. */
}
@ -916,28 +905,28 @@ bool BLI_path_abs(char *path, const char *basepath)
const char *lslash;
BLI_strncpy(base, basepath, sizeof(base));
/* file component is ignored, so don't bother with the trailing slash */
/* File component is ignored, so don't bother with the trailing slash. */
BLI_path_normalize(NULL, base);
lslash = BLI_path_slash_rfind(base);
BLI_str_replace_char(base + BLI_path_unc_prefix_len(base), '\\', '/');
if (lslash) {
/* length up to and including last "/" */
/* Length up to and including last `/`. */
const int baselen = (int)(lslash - base) + 1;
/* use path for temp storage here, we copy back over it right away */
BLI_strncpy(path, tmp + 2, FILE_MAX); /* strip "//" */
/* Use path for temp storage here, we copy back over it right away. */
BLI_strncpy(path, tmp + 2, FILE_MAX); /* Strip `//` prefix. */
memcpy(tmp, base, baselen); /* prefix with base up to last "/" */
BLI_strncpy(tmp + baselen, path, sizeof(tmp) - baselen); /* append path after "//" */
BLI_strncpy(path, tmp, FILE_MAX); /* return as result */
memcpy(tmp, base, baselen); /* Prefix with base up to last `/`. */
BLI_strncpy(tmp + baselen, path, sizeof(tmp) - baselen); /* Append path after `//`. */
BLI_strncpy(path, tmp, FILE_MAX); /* Return as result. */
}
else {
/* base doesn't seem to be a directory--ignore it and just strip "//" prefix on path */
/* Base doesn't seem to be a directory, ignore it and just strip `//` prefix on path. */
BLI_strncpy(path, tmp + 2, FILE_MAX);
}
}
else {
/* base ignored */
/* Base ignored. */
BLI_strncpy(path, tmp, FILE_MAX);
}
@ -948,7 +937,7 @@ bool BLI_path_abs(char *path, const char *basepath)
BLI_str_replace_char(path + 2, '/', '\\');
#endif
/* ensure this is after correcting for path switch */
/* Ensure this is after correcting for path switch. */
BLI_path_normalize(NULL, path);
return wasrelative;
@ -960,7 +949,7 @@ bool BLI_path_is_abs_from_cwd(const char *path)
const int path_len_clamp = BLI_strnlen(path, 3);
#ifdef WIN32
if ((path_len_clamp >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path)) {
if ((path_len_clamp >= 3 && BLI_path_is_abs_win32(path)) || BLI_path_is_unc(path)) {
is_abs = true;
}
#else
@ -979,7 +968,7 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
if (!BLI_path_is_abs_from_cwd(path)) {
char cwd[FILE_MAX];
/* in case the full path to the blend isn't used */
/* In case the full path to the blend isn't used. */
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
char origpath[FILE_MAX];
BLI_strncpy(origpath, path, FILE_MAX);
@ -996,7 +985,7 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
#ifdef _WIN32
/**
* Tries appending each of the semicolon-separated extensions in the PATHEXT
* Tries appending each of the semicolon-separated extensions in the `PATHEXT`
* environment variable (Windows-only) onto `name` in turn until such a file is found.
* Returns success/failure.
*/
@ -1007,7 +996,7 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
type = BLI_exists(name);
if ((type == 0) || S_ISDIR(type)) {
/* typically 3-5, ".EXE", ".BAT"... etc */
/* Typically 3-5, ".EXE", ".BAT"... etc. */
const int ext_max = 12;
const char *ext = BLI_getenv("PATHEXT");
if (ext) {
@ -1016,7 +1005,7 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
char *filename_ext;
const char *ext_next;
/* null terminated in the loop */
/* Null terminated in the loop. */
memcpy(filename, name, name_len);
filename_ext = filename + name_len;
@ -1101,11 +1090,9 @@ bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *na
void BLI_setenv(const char *env, const char *val)
{
/* free windows */
#if (defined(_WIN32) || defined(_WIN64))
/* MS-Windows. */
uputenv(env, val);
#else
/* Linux/macOS/BSD */
if (val) {
@ -1158,7 +1145,7 @@ bool BLI_make_existing_file(const char *name)
char di[FILE_MAX];
BLI_split_dir_part(name, di, sizeof(di));
/* make if the dir doesn't exist */
/* Make if the dir doesn't exist. */
return BLI_dir_create_recursive(di);
}
@ -1260,7 +1247,7 @@ bool BLI_path_extension_glob_validate(char *ext_fnmatch)
/* Non-wildcard char, we can break here and consider the pattern valid. */
return false;
}
/* So far, only wildcards in last group of the pattern... */
/* So far, only wildcards in last group of the pattern. */
only_wildcards = true;
}
/* Only one group in the pattern, so even if its only made of wildcard(s),
@ -1352,7 +1339,7 @@ void BLI_split_dirfile(
if (dir) {
if (lslash) {
/* +1 to include the slash and the last char */
/* +1 to include the slash and the last char. */
BLI_strncpy(dir, string, MIN2(dirlen, lslash + 1));
}
else {
@ -1429,7 +1416,7 @@ size_t BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__
}
if (dirlen >= maxlen) {
return dirlen; /* fills the path */
return dirlen; /* Fills the path. */
}
return dirlen + BLI_strncpy_rlen(dst + dirlen, file, maxlen - dirlen);
@ -1470,7 +1457,7 @@ size_t BLI_path_join_array(char *__restrict dst,
}
#ifdef WIN32
/* Special case "//" for relative paths, don't use separator #SEP
/* Special case `//` for relative paths, don't use separator #SEP
* as this has a special meaning on both WIN32 & UNIX.
* Without this check joining `"//", "path"`. results in `"//\path"`. */
if (ofs != 0) {
@ -1519,7 +1506,7 @@ size_t BLI_path_join_array(char *__restrict dst,
}
if (len != 0) {
/* the very first path may have a slash at the end */
/* The very first path may have a slash at the end. */
if (ofs && !BLI_path_slash_is_native_compat(dst[ofs - 1])) {
dst[ofs++] = SEP;
if (ofs == dst_last) {
@ -1574,7 +1561,7 @@ static bool path_name_at_index_forward(const char *__restrict path,
if ((c == '\0') || BLI_path_slash_is_native_compat(c)) {
if (prev + 1 != i) {
prev += 1;
/* Skip '/./' (behave as if they don't exist). */
/* Skip `/./` (behave as if they don't exist). */
if (!((i - prev == 1) && (prev != 0) && (path[prev] == '.'))) {
if (index_step == index) {
*r_offset = prev;
@ -1609,7 +1596,7 @@ static bool path_name_at_index_backward(const char *__restrict path,
if ((c == '\0') || BLI_path_slash_is_native_compat(c)) {
if (prev - 1 != i) {
i += 1;
/* Skip '/./' (behave as if they don't exist). */
/* Skip `/./` (behave as if they don't exist). */
if (!((prev - i == 1) && (i != 0) && (path[i] == '.'))) {
if (index_step == index) {
*r_offset = i;
@ -1644,7 +1631,7 @@ bool BLI_path_contains(const char *container_path, const char *containee_path)
char containee_native[PATH_MAX];
/* Keep space for a trailing slash. If the path is truncated by this, the containee path is
* longer than PATH_MAX and the result is ill-defined. */
* longer than #PATH_MAX and the result is ill-defined. */
BLI_strncpy(container_native, container_path, PATH_MAX - 1);
BLI_strncpy(containee_native, containee_path, PATH_MAX);

View File

@ -413,7 +413,9 @@ char32_t BLI_str_utf32_char_to_upper(const char32_t wc)
{
if (wc < U'\xFF') { /* Latin. */
if ((wc <= U'z' && wc >= U'a') || (wc <= U'\xF6' && wc >= U'\xE0') ||
(wc <= U'\xFE' && wc >= U'\xF8')) {
/* Correct but the first case is know, only check the second */
// (wc <= U'\xFE' && wc >= U'\xF8')
(wc >= U'\xF8')) {
return wc - 32;
}
return wc;

View File

@ -81,11 +81,8 @@ BLI_INLINE void bmesh_calc_tessellation_for_face_impl(BMLoop *(*looptris)[3],
efa->no, l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co);
}
if (UNLIKELY(is_quad_flip_v3_first_third_fast_with_normal(l_ptr_a[0]->v->co,
l_ptr_a[1]->v->co,
l_ptr_a[2]->v->co,
l_ptr_b[2]->v->co,
efa->no))) {
if (UNLIKELY(is_quad_flip_v3_first_third_fast(
l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co))) {
/* Flip out of degenerate 0-2 state. */
l_ptr_a[2] = l_ptr_b[2];
l_ptr_b[0] = l_ptr_a[1];

View File

@ -19,6 +19,8 @@
#include "DNA_world_types.h"
#include "GPU_context.h"
#include "IMB_imbuf.h"
#include "eevee_private.h"
@ -348,6 +350,16 @@ static void eevee_draw_scene(void *vedata)
EEVEE_temporal_sampling_reset(vedata);
stl->effects->ssr_was_valid_double_buffer = stl->g_data->valid_double_buffer;
}
/* Perform render step between samples to allow flushing of freed temporary GPUBackend
* resources. This prevents the GPU backend accumulating a high amount of in-flight memory when
* performing renders using eevee_draw_scene. e.g. During file thumbnail generation. */
if (loop_len > 2) {
if (GPU_backend_get_type() == GPU_BACKEND_METAL) {
GPU_flush();
GPU_render_step();
}
}
}
if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_COMBINED) != 0) {

View File

@ -166,7 +166,8 @@ void DepthOfField::sync()
/* Now that we know the maximum render resolution of every view, using depth of field, allocate
* the reduced buffers. Color needs to be signed format here. See note in shader for
* explanation. Do not use texture pool because of needs mipmaps. */
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT |
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW;
reduced_color_tx_.ensure_2d(GPU_RGBA16F, reduce_size, usage, nullptr, DOF_MIP_COUNT);
reduced_coc_tx_.ensure_2d(GPU_R16F, reduce_size, usage, nullptr, DOF_MIP_COUNT);
reduced_color_tx_.ensure_mip_views();

View File

@ -24,7 +24,8 @@ void HiZBuffer::sync()
int2 hiz_extent = math::ceil_to_multiple(render_extent, int2(1u << (HIZ_MIP_COUNT - 1)));
int2 dispatch_size = math::divide_ceil(hiz_extent, int2(HIZ_GROUP_SIZE));
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW;
hiz_tx_.ensure_2d(GPU_R32F, hiz_extent, usage, nullptr, HIZ_MIP_COUNT);
hiz_tx_.ensure_mip_views();
GPU_texture_mipmap_mode(hiz_tx_, true, false);

View File

@ -628,7 +628,7 @@ struct LightData {
float radius_squared;
/** NOTE: It is ok to use float3 here. A float is declared right after it.
* float3 is also aligned to 16 bytes. */
float3 color;
packed_float3 color;
/** Light Type. */
eLightType type;
/** Spot size. Aligned to size of float2. */

View File

@ -257,7 +257,8 @@ class ShadowModule {
/** Tile to physical page mapping. This is an array texture with one layer per view. */
Texture render_map_tx_ = {"ShadowRenderMap",
GPU_R32UI,
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE,
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW,
int2(SHADOW_TILEMAP_RES),
64,
nullptr,

View File

@ -12,7 +12,7 @@ void main()
/* Display backfacing surfels with a transparent checkerboard grid. */
if (!gl_FrontFacing) {
ivec2 grid_uv = ivec2(gl_FragCoord) / 5;
ivec2 grid_uv = ivec2(gl_FragCoord.xy) / 5;
if ((grid_uv.x + grid_uv.y) % 2 == 0) {
discard;
return;

View File

@ -45,7 +45,8 @@ void main()
case LIGHT_RECT:
case LIGHT_ELLIPSE:
case LIGHT_POINT:
sphere = Sphere(light._position, light.influence_radius_max);
sphere.center = light._position;
sphere.radius = light.influence_radius_max;
break;
}

View File

@ -110,7 +110,7 @@ bool debug_tilemaps(vec3 P, LightData light)
out_color_add = vec4(debug_tile_state_color(tile), 0.0);
out_color_mul = vec4(0.0);
if (ivec2(gl_FragCoord.xy) == ivec2(0)) {
if (all(equal(ivec2(gl_FragCoord.xy), ivec2(0)))) {
drw_print(light.object_mat);
}
return true;

View File

@ -25,7 +25,9 @@
#pragma BLENDER_REQUIRE(eevee_shadow_tilemap_lib.glsl)
/* TODO(@fclem): Implement. */
#define assert(check)
#ifndef GPU_METAL
# define assert(check)
#endif
/* Remove page ownership from the tile and append it to the cache. */
void shadow_page_free(inout ShadowTileData tile)

View File

@ -45,7 +45,7 @@ float pixel_size_at(float linear_depth)
if (is_persp) {
pixel_size *= max(0.01, linear_depth);
}
return pixel_size * exp2(fb_lod);
return pixel_size * exp2(float(fb_lod));
}
void step_bounding_sphere(vec3 vs_near_plane,
@ -117,6 +117,7 @@ void main()
step_bounding_sphere(vs_near_plane, vs_view_direction, t, t + step_size, P, step_radius);
vec3 vP = point_world_to_view(P);
shadow_tag_usage(vP, P, ws_view_direction, step_radius, t, gl_FragCoord.xy * exp2(fb_lod));
shadow_tag_usage(
vP, P, ws_view_direction, step_radius, t, gl_FragCoord.xy * exp2(float(fb_lod)));
}
}

View File

@ -17,7 +17,7 @@ void inflate_bounds(vec3 ls_center, inout vec3 P, inout vec3 lP)
{
vec3 vP = point_world_to_view(P);
float inflate_scale = pixel_world_radius * exp2(fb_lod);
float inflate_scale = pixel_world_radius * exp2(float(fb_lod));
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
if (is_persp) {
inflate_scale *= -vP.z;

View File

@ -45,6 +45,8 @@ void write_depth(ivec2 texel_co, const int lod, ivec2 tile_co, float depth)
/* Quantization bias. Equivalent to nextafter in C without all the safety. 1 is not enough. */
u_depth += 2;
/* TOOD(Metal): For Metal, textures will need to be viewed as buffers to workaround missing image
* atomics support. */
imageAtomicMin(shadow_atlas_img, out_texel, u_depth);
}

View File

@ -8,6 +8,11 @@
/** \name Shadow pipeline
* \{ */
/* NOTE(Metal): As this is implemented using a fundamental data type, this needs to be specified
* explicitly as uint for code generation, as the MSLShaderGenerator needs to be able to
* distinguish between classes and fundamental types during code generation. */
#define SHADOW_TILE_DATA_PACKED "uint"
GPU_SHADER_CREATE_INFO(eevee_shadow_clipmap_clear)
.do_static_compilation(true)
.local_group_size(SHADOW_CLIPMAP_GROUP_SIZE)
@ -34,7 +39,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_init)
.do_static_compilation(true)
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.storage_buf(2, Qualifier::READ_WRITE, "ShadowTileMapClip", "tilemaps_clip_buf[]")
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
.additional_info("eevee_shared")
@ -44,7 +49,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_update)
.do_static_compilation(true)
.local_group_size(1, 1, 1)
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.storage_buf(5, Qualifier::READ, "ObjectBounds", "bounds_buf[]")
.storage_buf(6, Qualifier::READ, "uint", "resource_ids_buf[]")
.additional_info("eevee_shared", "draw_view", "draw_view_culling")
@ -55,7 +60,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_opaque)
.local_group_size(SHADOW_DEPTH_SCAN_GROUP_SIZE, SHADOW_DEPTH_SCAN_GROUP_SIZE)
.sampler(0, ImageType::DEPTH_2D, "depth_tx")
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(6, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
.additional_info("eevee_shared", "draw_view", "draw_view_culling", "eevee_light_data")
.compute_source("eevee_shadow_tag_usage_comp.glsl");
@ -71,7 +76,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent)
.vertex_in(0, Type::VEC3, "pos")
.storage_buf(4, Qualifier::READ, "ObjectBounds", "bounds_buf[]")
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(6, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
.push_constant(Type::FLOAT, "pixel_world_radius")
.push_constant(Type::IVEC2, "fb_resolution")
@ -91,7 +96,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_mask)
.do_static_compilation(true)
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
.storage_buf(0, Qualifier::READ, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.additional_info("eevee_shared")
.compute_source("eevee_shadow_page_mask_comp.glsl");
@ -99,7 +104,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_free)
.do_static_compilation(true)
.local_group_size(SHADOW_TILEMAP_LOD0_LEN)
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
.storage_buf(3, Qualifier::READ_WRITE, "uint", "pages_free_buf[]")
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
@ -110,7 +115,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_defrag)
.do_static_compilation(true)
.local_group_size(1)
.typedef_source("draw_shader_shared.h")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
.storage_buf(3, Qualifier::READ_WRITE, "uint", "pages_free_buf[]")
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
@ -124,7 +129,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_allocate)
.local_group_size(SHADOW_TILEMAP_LOD0_LEN)
.typedef_source("draw_shader_shared.h")
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
.storage_buf(3, Qualifier::READ_WRITE, "uint", "pages_free_buf[]")
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
@ -137,7 +142,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_finalize)
.typedef_source("draw_shader_shared.h")
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
.storage_buf(3, Qualifier::WRITE, "ViewMatrices", "view_infos_buf[64]")
.storage_buf(4, Qualifier::READ_WRITE, "ShadowStatistics", "statistics_buf")
@ -183,11 +188,12 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_debug)
.do_static_compilation(true)
.additional_info("eevee_shared")
.storage_buf(5, Qualifier::READ, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(6, Qualifier::READ, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(6, Qualifier::READ, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.fragment_out(0, Type::VEC4, "out_color_add", DualBlend::SRC_0)
.fragment_out(0, Type::VEC4, "out_color_mul", DualBlend::SRC_1)
.push_constant(Type::INT, "debug_mode")
.push_constant(Type::INT, "debug_tilemap_index")
.depth_write(DepthWrite::ANY)
.fragment_source("eevee_shadow_debug_frag.glsl")
.additional_info(
"draw_fullscreen", "draw_view", "eevee_hiz_data", "eevee_light_data", "eevee_shadow_data");

View File

@ -33,7 +33,12 @@
BLI_INLINE eParticleRefineShaderType drw_curves_shader_type_get()
{
if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support()) {
/* NOTE: Curve refine is faster using transform feedback via vertex processing pipeline with
* Metal and Apple Silicon GPUs. This is also because vertex work can more easily be executed in
* parallel with fragment work, whereas compute inserts an explicit dependency,
* due to switching of command encoder types. */
if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support() &&
(GPU_backend_get_type() != GPU_BACKEND_METAL)) {
return PART_REFINE_SHADER_COMPUTE;
}
if (GPU_transform_feedback_support()) {

View File

@ -36,7 +36,12 @@
BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get()
{
if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support()) {
/* NOTE: Hair refine is faster using transform feedback via vertex processing pipeline with Metal
* and Apple Silicon GPUs. This is also because vertex work can more easily be executed in
* parallel with fragment work, whereas compute inserts an explicit dependency,
* due to switching of command encoder types. */
if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support() &&
(GPU_backend_get_type() != GPU_BACKEND_METAL)) {
return PART_REFINE_SHADER_COMPUTE;
}
if (GPU_transform_feedback_support()) {

View File

@ -350,6 +350,16 @@ struct DRWDebugVert {
};
BLI_STATIC_ASSERT_ALIGN(DRWDebugVert, 16)
inline DRWDebugVert debug_vert_make(uint in_pos0, uint in_pos1, uint in_pos2, uint in_vert_color)
{
DRWDebugVert debug_vert;
debug_vert.pos0 = in_pos0;
debug_vert.pos1 = in_pos1;
debug_vert.pos2 = in_pos2;
debug_vert.vert_color = in_vert_color;
return debug_vert;
}
/* Take the header (DrawCommand) into account. */
#define DRW_DEBUG_DRAW_VERT_MAX (64 * 8192) - 1

View File

@ -34,9 +34,9 @@ uint drw_debug_color_pack(vec4 v_color)
void drw_debug_line(inout uint vertid, vec3 v1, vec3 v2, uint v_color)
{
drw_debug_verts_buf[vertid++] = DRWDebugVert(
drw_debug_verts_buf[vertid++] = debug_vert_make(
floatBitsToUint(v1.x), floatBitsToUint(v1.y), floatBitsToUint(v1.z), v_color);
drw_debug_verts_buf[vertid++] = DRWDebugVert(
drw_debug_verts_buf[vertid++] = debug_vert_make(
floatBitsToUint(v2.x), floatBitsToUint(v2.y), floatBitsToUint(v2.z), v_color);
}

View File

@ -86,6 +86,9 @@ void FONT_OT_text_cut(struct wmOperatorType *ot);
void FONT_OT_text_paste(struct wmOperatorType *ot);
void FONT_OT_text_paste_from_file(struct wmOperatorType *ot);
void FONT_OT_selection_set(struct wmOperatorType *ot);
void FONT_OT_select_word(struct wmOperatorType *ot);
void FONT_OT_move(struct wmOperatorType *ot);
void FONT_OT_move_select(struct wmOperatorType *ot);
void FONT_OT_delete(struct wmOperatorType *ot);

View File

@ -40,6 +40,9 @@ void ED_operatortypes_curve(void)
WM_operatortype_append(FONT_OT_text_paste);
WM_operatortype_append(FONT_OT_text_paste_from_file);
WM_operatortype_append(FONT_OT_selection_set);
WM_operatortype_append(FONT_OT_select_word);
WM_operatortype_append(FONT_OT_move);
WM_operatortype_append(FONT_OT_move_select);
WM_operatortype_append(FONT_OT_delete);

View File

@ -1805,6 +1805,142 @@ void FONT_OT_text_insert(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Font Selection Operator
* \{ */
static int font_cursor_text_index_from_event(bContext *C, Object *obedit, const wmEvent *event)
{
Curve *cu = obedit->data;
/* Calculate a plane from the text object's orientation. */
float plane[4];
plane_from_point_normal_v3(plane, obedit->object_to_world[3], obedit->object_to_world[2]);
/* Convert Mouse location in region to 3D location in world space. */
float mal_fl[2] = {(float)event->mval[0], (float)event->mval[1]};
float mouse_loc[3];
ED_view3d_win_to_3d_on_plane(CTX_wm_region(C), plane, mal_fl, true, mouse_loc);
/* Convert to object space and scale by font size. */
mul_m4_v3(obedit->world_to_object, mouse_loc);
float curs_loc[2] = {mouse_loc[0] / cu->fsize, mouse_loc[1] / cu->fsize};
return BKE_vfont_cursor_to_text_index(obedit, curs_loc);
}
static void font_cursor_set_apply(bContext *C, const wmEvent *event)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob = DEG_get_evaluated_object(depsgraph, CTX_data_active_object(C));
Curve *cu = ob->data;
EditFont *ef = cu->editfont;
BLI_assert(ef->len >= 0);
const int string_offset = font_cursor_text_index_from_event(C, ob, event);
if (string_offset > ef->len || string_offset < 0) {
return;
}
cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0];
if (ob->totcol > 0) {
ob->actcol = cu->curinfo.mat_nr;
if (ob->actcol < 1) {
ob->actcol = 1;
}
}
if (!ef->selboxes && (ef->selstart == 0)) {
if (ef->pos == 0) {
ef->selstart = ef->selend = 1;
}
else {
ef->selstart = ef->selend = string_offset + 1;
}
}
ef->selend = string_offset;
ef->pos = string_offset;
DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
}
static int font_selection_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *obedit = CTX_data_active_object(C);
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
font_cursor_set_apply(C, event);
ef->selstart = 0;
ef->selend = 0;
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
static int font_selection_set_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
switch (event->type) {
case LEFTMOUSE:
if (event->val == KM_RELEASE) {
font_cursor_set_apply(C, event);
return OPERATOR_FINISHED;
}
break;
case MIDDLEMOUSE:
case RIGHTMOUSE:
return OPERATOR_FINISHED;
case MOUSEMOVE:
font_cursor_set_apply(C, event);
break;
}
return OPERATOR_RUNNING_MODAL;
}
void FONT_OT_selection_set(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Set Selection";
ot->idname = "FONT_OT_selection_set";
ot->description = "Set cursor selection";
/* api callbacks */
ot->invoke = font_selection_set_invoke;
ot->modal = font_selection_set_modal;
ot->poll = ED_operator_editfont;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Select Word Operator
* \{ */
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);
return OPERATOR_FINISHED;
}
void FONT_OT_select_word(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Word";
ot->idname = "FONT_OT_select_word";
ot->description = "Select word under cursor";
/* api callbacks */
ot->exec = font_select_word_exec;
ot->poll = ED_operator_editfont;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Text-Box Add Operator
* \{ */

View File

@ -154,7 +154,7 @@ struct SculptUndoNodeGeometry {
CustomData ldata;
CustomData pdata;
int *poly_offset_indices;
blender::ImplicitSharingInfo *poly_offsets_sharing_info;
const blender::ImplicitSharingInfo *poly_offsets_sharing_info;
int totvert;
int totedge;
int totloop;

View File

@ -413,7 +413,6 @@ static void draw_seq_waveform_overlay(
const float frames_per_pixel = BLI_rctf_size_x(&region->v2d.cur) / region->winx;
const float samples_per_frame = SOUND_WAVE_SAMPLES_PER_SECOND / FPS;
float samples_per_pixel = samples_per_frame * frames_per_pixel;
/* Align strip start with nearest pixel to prevent waveform flickering. */
const float x1_aligned = align_frame_with_pixel(x1, frames_per_pixel);
@ -439,15 +438,17 @@ static void draw_seq_waveform_overlay(
size_t wave_data_len = 0;
/* Offset must be also aligned, otherwise waveform flickers when moving left handle. */
const float strip_offset = align_frame_with_pixel(seq->startofs + seq->anim_startofs,
frames_per_pixel);
float start_sample = strip_offset * samples_per_frame;
start_sample += seq->sound->offset_time * SOUND_WAVE_SAMPLES_PER_SECOND;
float start_frame = SEQ_time_left_handle_frame_get(scene, seq);
/* Add off-screen part of strip to offset. */
start_sample += (frame_start - x1_aligned) * samples_per_frame;
start_frame += (frame_start - x1_aligned);
start_frame += seq->sound->offset_time / FPS;
for (int i = 0; i < pixels_to_draw; i++) {
float sample = start_sample + i * samples_per_pixel;
float timeline_frame = start_frame + i * frames_per_pixel;
/* TODO: Use linear interpolation between frames to avoid bad drawing quality. */
float frame_index = SEQ_give_frame_index(scene, seq, timeline_frame);
float sample = frame_index * samples_per_frame;
int sample_index = round_fl_to_int(sample);
if (sample_index < 0) {
@ -468,6 +469,8 @@ static void draw_seq_waveform_overlay(
value_min = (1.0f - f) * value_min + f * waveform->data[sample_index * 3 + 3];
value_max = (1.0f - f) * value_max + f * waveform->data[sample_index * 3 + 4];
rms = (1.0f - f) * rms + f * waveform->data[sample_index * 3 + 5];
float samples_per_pixel = samples_per_frame * frames_per_pixel;
if (samples_per_pixel > 1.0f) {
/* We need to sum up the values we skip over until the next step. */
float next_pos = sample + samples_per_pixel;

View File

@ -510,7 +510,7 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
}
}
else {
if (BLI_listbase_count(&sspreadsheet->viewer_path.path) == 1) {
if (BLI_listbase_is_single(&sspreadsheet->viewer_path.path)) {
if (const GeometrySet *geometry_eval = object_eval->runtime.geometry_set_eval) {
geometry_set = *geometry_eval;
}

View File

@ -3181,7 +3181,7 @@ static float uv_sphere_project(const Scene *scene,
const float branch_init)
{
float max_u = 0.0f;
if (BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
if (use_seams && BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
return max_u;
}
@ -3358,7 +3358,7 @@ static float uv_cylinder_project(const Scene *scene,
const float branch_init)
{
float max_u = 0.0f;
if (BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
if (use_seams && BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
return max_u;
}

View File

@ -73,7 +73,7 @@ static void add_new_edges(Mesh &mesh,
/* Store a copy of the IDs locally since we will remove the existing attributes which
* can also free the names, since the API does not provide pointer stability. */
Vector<std::string> named_ids;
Vector<bke::AutoAnonymousAttributeID> anonymous_ids;
Vector<bke::AnonymousAttributeIDPtr> anonymous_ids;
for (const bke::AttributeIDRef &id : attributes.all_ids()) {
if (attributes.lookup_meta_data(id)->domain != ATTR_DOMAIN_EDGE) {
continue;
@ -95,7 +95,7 @@ static void add_new_edges(Mesh &mesh,
for (const StringRef name : named_ids) {
local_edge_ids.append(name);
}
for (const bke::AutoAnonymousAttributeID &id : anonymous_ids) {
for (const bke::AnonymousAttributeIDPtr &id : anonymous_ids) {
local_edge_ids.append(*id);
}

View File

@ -235,6 +235,7 @@ set(VULKAN_SRC
vulkan/vk_common.hh
vulkan/vk_context.hh
vulkan/vk_data_conversion.hh
vulkan/vk_debug.hh
vulkan/vk_descriptor_pools.hh
vulkan/vk_descriptor_set.hh
vulkan/vk_drawlist.hh

View File

@ -458,6 +458,9 @@ GPUTexture *GPU_texture_create_view(const char *name,
{
BLI_assert(mip_len > 0);
BLI_assert(layer_len > 0);
BLI_assert_msg(
GPU_texture_usage(src) & GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW,
"Source texture of TextureView must have GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW usage flag.");
Texture *view = GPUBackend::get()->texture_alloc(name);
view->init_view(src,
format,

View File

@ -189,6 +189,16 @@ MTLContext::MTLContext(void *ghost_window, void *ghost_context)
[this->queue retain];
[this->device retain];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-method-access"
/* Enable increased concurrent shader compiler limit.
* Note: Disable warning for missing method when building on older OS's, as compiled code will
* still work correctly when run on a system with the API available. */
if (@available(macOS 13.3, *)) {
[this->device setShouldMaximizeConcurrentCompilation:YES];
}
#pragma clang diagnostic pop
/* Register present callback. */
this->ghost_context_->metalRegisterPresentCallback(&present);

View File

@ -83,9 +83,7 @@ struct constexp_uvec3 {
uint3 xyz;
};
constexpr constexp_uvec3(uint _x, uint _y, uint _z) : x(_x), y(_y), z(_z)
{
}
constexpr constexp_uvec3(uint _x, uint _y, uint _z) : x(_x), y(_y), z(_z) {}
constexpr uint operator[](int i)
{
/* Note: Need to switch on each elem value as array accessor triggers
@ -294,6 +292,8 @@ struct SStruct {
#define textureGather3(__tex, __uv, __comp) _texture_gather_internal(__tex, __uv, __comp)
#define textureGatherOffset(__tex, __offset, __uv, __comp) \
_texture_gather_internal(__tex, __uv, __comp, __offset)
#define textureGrad(__tex, __uv, __dpdx, __dpdy) \
_texture_grad_internal(__tex, __uv, __dpdx, __dpdy)
#define TEXURE_MACRO(_1, _2, _3, TEXNAME, ...) TEXNAME
#define texture(...) TEXURE_MACRO(__VA_ARGS__, texture3, texture2)(__VA_ARGS__)
@ -849,6 +849,34 @@ inline vec<T, 4> _texture_gather_internal(
return tex.texture->gather(*tex.samp, uva.xy, uint(uva.z), offset);
}
/* Texture Grad. */
inline float4 _texture_grad_internal(
thread _mtl_combined_image_sampler_2d<float, access::sample> tex,
float2 uv,
float2 dpdx,
float2 dpdy)
{
return tex.texture->sample(*tex.samp, uv, gradient2d(dpdx, dpdy));
}
inline float4 _texture_grad_internal(
thread _mtl_combined_image_sampler_2d_array<float, access::sample> tex,
float3 uva,
float2 dpdx,
float2 dpdy)
{
return tex.texture->sample(*tex.samp, uva.xy, uint(uva.z), gradient2d(dpdx, dpdy));
}
inline float4 _texture_grad_internal(
thread _mtl_combined_image_sampler_3d<float, access::sample> tex,
float3 uvw,
float3 dpdx,
float3 dpdy)
{
return tex.texture->sample(*tex.samp, uvw, gradient3d(dpdx, dpdy));
}
/* Texture write support. */
template<typename S, typename T, access A>
inline void _texture_write_internal(thread _mtl_combined_image_sampler_1d<S, A> tex,

View File

@ -145,7 +145,7 @@ static void test_shader_compute_vbo()
GPU_shader_bind(shader);
/* Construct VBO. */
static GPUVertFormat format = {0};
GPUVertFormat format = {0};
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_DEVICE_ONLY);
GPU_vertbuf_data_alloc(vbo, SIZE);

View File

@ -7,6 +7,8 @@
#pragma once
#include <typeinfo>
#ifdef __APPLE__
# include <MoltenVK/vk_mvk_moltenvk.h>
#else
@ -26,4 +28,66 @@ VkImageViewType to_vk_image_view_type(const eGPUTextureType type);
VkImageType to_vk_image_type(const eGPUTextureType type);
VkClearColorValue to_vk_clear_color_value(const eGPUDataFormat format, const void *data);
template<typename T> VkObjectType to_vk_object_type(T /*vk_obj*/)
{
const std::type_info &tid = typeid(T);
#define VK_EQ_TYPEID(name, name2) \
if (tid == typeid(name)) { \
return VK_OBJECT_TYPE_##name2; \
}
VK_EQ_TYPEID(VkInstance, INSTANCE);
VK_EQ_TYPEID(VkPhysicalDevice, PHYSICAL_DEVICE);
VK_EQ_TYPEID(VkDevice, DEVICE);
VK_EQ_TYPEID(VkQueue, QUEUE);
VK_EQ_TYPEID(VkSemaphore, SEMAPHORE);
VK_EQ_TYPEID(VkCommandBuffer, COMMAND_BUFFER);
VK_EQ_TYPEID(VkFence, FENCE);
VK_EQ_TYPEID(VkDeviceMemory, DEVICE_MEMORY);
VK_EQ_TYPEID(VkBuffer, BUFFER);
VK_EQ_TYPEID(VkImage, IMAGE);
VK_EQ_TYPEID(VkEvent, EVENT);
VK_EQ_TYPEID(VkQueryPool, QUERY_POOL);
VK_EQ_TYPEID(VkBufferView, BUFFER_VIEW);
VK_EQ_TYPEID(VkImageView, IMAGE_VIEW);
VK_EQ_TYPEID(VkShaderModule, SHADER_MODULE);
VK_EQ_TYPEID(VkPipelineCache, PIPELINE_CACHE);
VK_EQ_TYPEID(VkPipelineLayout, PIPELINE_LAYOUT);
VK_EQ_TYPEID(VkRenderPass, RENDER_PASS);
VK_EQ_TYPEID(VkPipeline, PIPELINE);
VK_EQ_TYPEID(VkDescriptorSetLayout, DESCRIPTOR_SET_LAYOUT);
VK_EQ_TYPEID(VkSampler, SAMPLER);
VK_EQ_TYPEID(VkDescriptorPool, DESCRIPTOR_POOL);
VK_EQ_TYPEID(VkDescriptorSet, DESCRIPTOR_SET);
VK_EQ_TYPEID(VkFramebuffer, FRAMEBUFFER);
VK_EQ_TYPEID(VkCommandPool, COMMAND_POOL);
VK_EQ_TYPEID(VkSamplerYcbcrConversion, SAMPLER_YCBCR_CONVERSION);
VK_EQ_TYPEID(VkDescriptorUpdateTemplate, DESCRIPTOR_UPDATE_TEMPLATE);
VK_EQ_TYPEID(VkSurfaceKHR, SURFACE_KHR);
VK_EQ_TYPEID(VkSwapchainKHR, SWAPCHAIN_KHR);
VK_EQ_TYPEID(VkDisplayKHR, DISPLAY_KHR);
VK_EQ_TYPEID(VkDisplayModeKHR, DISPLAY_MODE_KHR);
VK_EQ_TYPEID(VkDebugReportCallbackEXT, DEBUG_REPORT_CALLBACK_EXT);
#ifdef VK_ENABLE_BETA_EXTENSIONS
VK_EQ_TYPEID(VkVideoSessionKHR, VIDEO_SESSION_KHR);
#endif
#ifdef VK_ENABLE_BETA_EXTENSIONS
VK_EQ_TYPEID(VkVideoSessionParametersKHR, VIDEO_SESSION_PARAMETERS_KHR);
#endif
VK_EQ_TYPEID(VkCuModuleNVX, CU_MODULE_NVX);
VK_EQ_TYPEID(VkCuFunctionNVX, CU_FUNCTION_NVX);
VK_EQ_TYPEID(VkDebugUtilsMessengerEXT, DEBUG_UTILS_MESSENGER_EXT);
VK_EQ_TYPEID(VkAccelerationStructureKHR, ACCELERATION_STRUCTURE_KHR);
VK_EQ_TYPEID(VkValidationCacheEXT, VALIDATION_CACHE_EXT);
VK_EQ_TYPEID(VkAccelerationStructureNV, ACCELERATION_STRUCTURE_NV);
VK_EQ_TYPEID(VkPerformanceConfigurationINTEL, PERFORMANCE_CONFIGURATION_INTEL);
VK_EQ_TYPEID(VkDeferredOperationKHR, DEFERRED_OPERATION_KHR);
VK_EQ_TYPEID(VkIndirectCommandsLayoutNV, INDIRECT_COMMANDS_LAYOUT_NV);
VK_EQ_TYPEID(VkPrivateDataSlotEXT, PRIVATE_DATA_SLOT_EXT);
BLI_assert_unreachable();
#undef VK_EQ_TYPEID
return VK_OBJECT_TYPE_UNKNOWN;
}
} // namespace blender::gpu

View File

@ -4,8 +4,8 @@
/** \file
* \ingroup gpu
*/
#include "vk_context.hh"
#include "vk_debug.hh"
#include "vk_backend.hh"
#include "vk_framebuffer.hh"
@ -31,8 +31,12 @@ VKContext::VKContext(void *ghost_window, void *ghost_context)
&vk_device_,
&vk_queue_family_,
&vk_queue_);
debug::init_callbacks(this, vkGetInstanceProcAddr);
init_physical_device_limits();
debug::object_label(this, vk_device_, "LogicalDevice");
debug::object_label(this, vk_queue_, "GenericQueue");
/* Initialize the memory allocator. */
VmaAllocatorCreateInfo info = {};
/* Should use same vulkan version as GHOST (1.2), but set to 1.0 as 1.2 requires
@ -57,6 +61,7 @@ VKContext::VKContext(void *ghost_window, void *ghost_context)
VKContext::~VKContext()
{
vmaDestroyAllocator(mem_allocator_);
debug::destroy_callbacks(this);
}
void VKContext::init_physical_device_limits()

View File

@ -8,8 +8,9 @@
#pragma once
#include "gpu_context_private.hh"
#include "vk_command_buffer.hh"
#include "vk_common.hh"
#include "vk_debug.hh"
#include "vk_descriptor_pools.hh"
namespace blender::gpu {
@ -32,6 +33,9 @@ class VKContext : public Context {
/** Limits of the device linked to this context. */
VkPhysicalDeviceLimits vk_physical_device_limits_;
/** Functions of vk_ext_debugutils to use in this context. */
debug::VKDebuggingTools debugging_tools_;
void *ghost_context_;
public:
@ -74,6 +78,11 @@ class VKContext : public Context {
return vk_physical_device_limits_;
}
VkInstance instance_get() const
{
return vk_instance_;
};
VkDevice device_get() const
{
return vk_device_;
@ -104,6 +113,16 @@ class VKContext : public Context {
return mem_allocator_;
}
debug::VKDebuggingTools &debugging_tools_get()
{
return debugging_tools_;
}
const debug::VKDebuggingTools &debugging_tools_get() const
{
return debugging_tools_;
}
private:
void init_physical_device_limits();

View File

@ -5,13 +5,22 @@
* \ingroup gpu
*/
#include "BKE_global.h"
#include "vk_backend.hh"
#include "vk_context.hh"
#include "vk_debug.hh"
namespace blender::gpu {
void VKContext::debug_group_begin(const char *, int) {}
void VKContext::debug_group_begin(const char *name, int)
{
debug::push_marker(this, vk_queue_, name);
}
void VKContext::debug_group_end() {}
void VKContext::debug_group_end()
{
debug::pop_marker(this, vk_queue_);
}
bool VKContext::debug_capture_begin()
{
@ -54,3 +63,164 @@ bool VKContext::debug_capture_scope_begin(void * /*scope*/)
void VKContext::debug_capture_scope_end(void * /*scope*/) {}
} // namespace blender::gpu
namespace blender::gpu::debug {
static void load_dynamic_functions(VKContext *context,
PFN_vkGetInstanceProcAddr instance_proc_addr)
{
VKDebuggingTools &debugging_tools = context->debugging_tools_get();
VkInstance vk_instance = context->instance_get();
if (instance_proc_addr) {
debugging_tools.enabled = false;
debugging_tools.vkCmdBeginDebugUtilsLabelEXT_r = (PFN_vkCmdBeginDebugUtilsLabelEXT)
instance_proc_addr(vk_instance, "vkCmdBeginDebugUtilsLabelEXT");
debugging_tools.vkCmdEndDebugUtilsLabelEXT_r = (PFN_vkCmdEndDebugUtilsLabelEXT)
instance_proc_addr(vk_instance, "vkCmdEndDebugUtilsLabelEXT");
debugging_tools.vkCmdInsertDebugUtilsLabelEXT_r = (PFN_vkCmdInsertDebugUtilsLabelEXT)
instance_proc_addr(vk_instance, "vkCmdInsertDebugUtilsLabelEXT");
debugging_tools.vkCreateDebugUtilsMessengerEXT_r = (PFN_vkCreateDebugUtilsMessengerEXT)
instance_proc_addr(vk_instance, "vkCreateDebugUtilsMessengerEXT");
debugging_tools.vkDestroyDebugUtilsMessengerEXT_r = (PFN_vkDestroyDebugUtilsMessengerEXT)
instance_proc_addr(vk_instance, "vkDestroyDebugUtilsMessengerEXT");
debugging_tools.vkQueueBeginDebugUtilsLabelEXT_r = (PFN_vkQueueBeginDebugUtilsLabelEXT)
instance_proc_addr(vk_instance, "vkQueueBeginDebugUtilsLabelEXT");
debugging_tools.vkQueueEndDebugUtilsLabelEXT_r = (PFN_vkQueueEndDebugUtilsLabelEXT)
instance_proc_addr(vk_instance, "vkQueueEndDebugUtilsLabelEXT");
debugging_tools.vkQueueInsertDebugUtilsLabelEXT_r = (PFN_vkQueueInsertDebugUtilsLabelEXT)
instance_proc_addr(vk_instance, "vkQueueInsertDebugUtilsLabelEXT");
debugging_tools.vkSetDebugUtilsObjectNameEXT_r = (PFN_vkSetDebugUtilsObjectNameEXT)
instance_proc_addr(vk_instance, "vkSetDebugUtilsObjectNameEXT");
debugging_tools.vkSetDebugUtilsObjectTagEXT_r = (PFN_vkSetDebugUtilsObjectTagEXT)
instance_proc_addr(vk_instance, "vkSetDebugUtilsObjectTagEXT");
debugging_tools.vkSubmitDebugUtilsMessageEXT_r = (PFN_vkSubmitDebugUtilsMessageEXT)
instance_proc_addr(vk_instance, "vkSubmitDebugUtilsMessageEXT");
if (debugging_tools.vkCmdBeginDebugUtilsLabelEXT_r) {
debugging_tools.enabled = true;
}
}
else {
debugging_tools.vkCmdBeginDebugUtilsLabelEXT_r = nullptr;
debugging_tools.vkCmdEndDebugUtilsLabelEXT_r = nullptr;
debugging_tools.vkCmdInsertDebugUtilsLabelEXT_r = nullptr;
debugging_tools.vkCreateDebugUtilsMessengerEXT_r = nullptr;
debugging_tools.vkDestroyDebugUtilsMessengerEXT_r = nullptr;
debugging_tools.vkQueueBeginDebugUtilsLabelEXT_r = nullptr;
debugging_tools.vkQueueEndDebugUtilsLabelEXT_r = nullptr;
debugging_tools.vkQueueInsertDebugUtilsLabelEXT_r = nullptr;
debugging_tools.vkSetDebugUtilsObjectNameEXT_r = nullptr;
debugging_tools.vkSetDebugUtilsObjectTagEXT_r = nullptr;
debugging_tools.vkSubmitDebugUtilsMessageEXT_r = nullptr;
debugging_tools.enabled = false;
}
}
bool init_callbacks(VKContext *context, PFN_vkGetInstanceProcAddr instance_proc_addr)
{
if (instance_proc_addr) {
load_dynamic_functions(context, instance_proc_addr);
return true;
};
return false;
}
void destroy_callbacks(VKContext *context)
{
VKDebuggingTools &debugging_tools = context->debugging_tools_get();
if (debugging_tools.enabled) {
load_dynamic_functions(context, nullptr);
}
}
void object_label(VKContext *context,
VkObjectType vk_object_type,
uint64_t object_handle,
const char *name)
{
if (G.debug & G_DEBUG_GPU) {
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
if (debugging_tools.enabled) {
VkDebugUtilsObjectNameInfoEXT info = {};
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
info.objectType = vk_object_type;
info.objectHandle = object_handle;
info.pObjectName = name;
debugging_tools.vkSetDebugUtilsObjectNameEXT_r(context->device_get(), &info);
}
}
}
void push_marker(VKContext *context, VkCommandBuffer vk_command_buffer, const char *name)
{
if (G.debug & G_DEBUG_GPU) {
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
if (debugging_tools.enabled) {
VkDebugUtilsLabelEXT info = {};
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
info.pLabelName = name;
debugging_tools.vkCmdBeginDebugUtilsLabelEXT_r(vk_command_buffer, &info);
}
}
}
void set_marker(VKContext *context, VkCommandBuffer vk_command_buffer, const char *name)
{
if (G.debug & G_DEBUG_GPU) {
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
if (debugging_tools.enabled) {
VkDebugUtilsLabelEXT info = {};
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
info.pLabelName = name;
debugging_tools.vkCmdInsertDebugUtilsLabelEXT_r(vk_command_buffer, &info);
}
}
}
void pop_marker(VKContext *context, VkCommandBuffer vk_command_buffer)
{
if (G.debug & G_DEBUG_GPU) {
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
if (debugging_tools.enabled) {
debugging_tools.vkCmdEndDebugUtilsLabelEXT_r(vk_command_buffer);
}
}
}
void push_marker(VKContext *context, VkQueue vk_queue, const char *name)
{
if (G.debug & G_DEBUG_GPU) {
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
if (debugging_tools.enabled) {
VkDebugUtilsLabelEXT info = {};
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
info.pLabelName = name;
debugging_tools.vkQueueBeginDebugUtilsLabelEXT_r(vk_queue, &info);
}
}
}
void set_marker(VKContext *context, VkQueue vk_queue, const char *name)
{
if (G.debug & G_DEBUG_GPU) {
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
if (debugging_tools.enabled) {
VkDebugUtilsLabelEXT info = {};
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
info.pLabelName = name;
debugging_tools.vkQueueInsertDebugUtilsLabelEXT_r(vk_queue, &info);
}
}
}
void pop_marker(VKContext *context, VkQueue vk_queue)
{
if (G.debug & G_DEBUG_GPU) {
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
if (debugging_tools.enabled) {
debugging_tools.vkQueueEndDebugUtilsLabelEXT_r(vk_queue);
}
}
}
} // namespace blender::gpu::debug

View File

@ -0,0 +1,60 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2023 Blender Foundation. All rights reserved. */
/** \file
* \ingroup gpu
*/
#pragma once
#include "BKE_global.h"
#include "BLI_string.h"
#include "vk_common.hh"
#include <typeindex>
namespace blender::gpu {
class VKContext;
namespace debug {
typedef struct VKDebuggingTools {
bool enabled = false;
/* Function pointer definitions. */
PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT_r = nullptr;
PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT_r = nullptr;
PFN_vkSubmitDebugUtilsMessageEXT vkSubmitDebugUtilsMessageEXT_r = nullptr;
PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT_r = nullptr;
PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT_r = nullptr;
PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT_r = nullptr;
PFN_vkQueueBeginDebugUtilsLabelEXT vkQueueBeginDebugUtilsLabelEXT_r = nullptr;
PFN_vkQueueEndDebugUtilsLabelEXT vkQueueEndDebugUtilsLabelEXT_r = nullptr;
PFN_vkQueueInsertDebugUtilsLabelEXT vkQueueInsertDebugUtilsLabelEXT_r = nullptr;
PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT_r = nullptr;
PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT_r = nullptr;
} VKDebuggingTools;
bool init_callbacks(VKContext *context, PFN_vkGetInstanceProcAddr instance_proc_addr);
void destroy_callbacks(VKContext *context);
void object_label(VKContext *context, VkObjectType vk_object_type, uint64_t object_handle, const char *name);
template<typename T> void object_label(VKContext *context, T vk_object_type, const char *name)
{
if (!(G.debug & G_DEBUG_GPU)) {
return;
}
const size_t label_size = 64;
char label[label_size];
memset(label, 0, label_size);
static int stats = 0;
SNPRINTF(label, "%s_%d", name, stats++);
object_label(context, to_vk_object_type(vk_object_type), (uint64_t)vk_object_type, (const char *)label);
};
void push_marker(VKContext *context, VkCommandBuffer vk_command_buffer, const char *name);
void set_marker(VKContext *context, VkCommandBuffer vk_command_buffer, const char *name);
void pop_marker(VKContext *context, VkCommandBuffer vk_command_buffer);
void push_marker(VKContext *context, VkQueue vk_queue, const char *name);
void set_marker(VKContext *context, VkQueue vk_queue, const char *name);
void pop_marker(VKContext *context, VkQueue vk_queue);
} // namespace debug
} // namespace blender::gpu

View File

@ -230,7 +230,7 @@ static void FlipDXTCImage(ImBuf *ibuf)
const uint8_t *data_end = data + data_size;
for (uint i = 0; i < levels; i++) {
for (uint level = 0; level < levels; level++) {
uint blocks_per_row = (mip_width + 3) / 4;
uint blocks_per_col = (mip_height + 3) / 4;
uint blocks = blocks_per_row * blocks_per_col;
@ -238,7 +238,7 @@ static void FlipDXTCImage(ImBuf *ibuf)
if (data + block_bytes * blocks > data_end) {
/* Stop flipping when running out of data to be modified, avoiding possible buffer overrun
* on a malformed files. */
*num_valid_levels = i;
*num_valid_levels = level;
break;
}

View File

@ -753,6 +753,7 @@ static void rna_def_attribute_float(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "FloatAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -785,6 +786,7 @@ static void rna_def_attribute_float_vector(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "FloatVectorAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -823,6 +825,7 @@ static void rna_def_attribute_float_color(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "FloatColorAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -870,6 +873,7 @@ static void rna_def_attribute_byte_color(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "ByteColorAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -918,6 +922,7 @@ static void rna_def_attribute_int(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "IntAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -947,6 +952,7 @@ static void rna_def_attribute_string(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "StringAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -976,6 +982,7 @@ static void rna_def_attribute_bool(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "BoolAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -1005,6 +1012,7 @@ static void rna_def_attribute_int8(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "ByteIntAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -1036,6 +1044,7 @@ static void rna_def_attribute_int2(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Int2AttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -1071,6 +1080,7 @@ static void rna_def_attribute_float2(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Float2AttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",

View File

@ -345,6 +345,7 @@ static void rna_def_curves_curve(BlenderRNA *brna)
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "CurvePoint");
RNA_def_property_ui_text(prop, "Points", "Control points of the curve");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_CurveSlice_points_begin",
"rna_iterator_array_next",
@ -384,6 +385,7 @@ static void rna_def_curves(BlenderRNA *brna)
/* Point and Curve RNA API helpers. */
prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Curves_curves_begin",
"rna_iterator_array_next",
@ -398,6 +400,7 @@ static void rna_def_curves(BlenderRNA *brna)
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "CurvePoint");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Curves_position_data_begin",
"rna_iterator_array_next",
@ -412,6 +415,7 @@ static void rna_def_curves(BlenderRNA *brna)
/* Direct access to built-in attributes. */
prop = RNA_def_property(srna, "position_data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Curves_position_data_begin",
"rna_iterator_array_next",
@ -426,6 +430,7 @@ static void rna_def_curves(BlenderRNA *brna)
prop = RNA_def_property(srna, "curve_offset_data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "IntAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Curves_curve_offset_data_begin",
"rna_iterator_array_next",
@ -440,6 +445,7 @@ static void rna_def_curves(BlenderRNA *brna)
rna_def_read_only_float_vector(brna);
prop = RNA_def_property(srna, "normals", PROP_COLLECTION, PROP_NONE);
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_struct_type(prop, "FloatVectorValueReadOnly");
/* `lookup_int` isn't provided since the entire normals array is allocated and calculated when
* it's accessed. */

View File

@ -3107,6 +3107,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
prop,
"MeshUVLoop (Deprecated)",
"Deprecated, use 'uv', 'vertex_select', 'edge_select' or 'pin' properties instead");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_data_begin",
"rna_iterator_array_next",
@ -3147,6 +3148,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
prop = RNA_def_property(srna, "uv", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Float2AttributeValue");
RNA_def_property_ui_text(prop, "UV", "UV coordinates on face corners");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_uv_begin",
"rna_iterator_array_next",
@ -3161,6 +3163,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "BoolAttributeValue");
RNA_def_property_ui_text(
prop, "UV Vertex Selection", "Selection state of the face corner the UV editor");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_vert_select_begin",
"rna_iterator_array_next",
@ -3175,6 +3178,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "BoolAttributeValue");
RNA_def_property_ui_text(
prop, "UV Edge Selection", "Selection state of the edge in the UV editor");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_edge_select_begin",
"rna_iterator_array_next",
@ -3188,6 +3192,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
prop = RNA_def_property(srna, "pin", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "BoolAttributeValue");
RNA_def_property_ui_text(prop, "UV Pin", "UV pinned state in the UV editor");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_pin_begin",
"rna_iterator_array_next",
@ -3256,6 +3261,7 @@ static void rna_def_mloopcol(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshLoopColor");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshLoopColorLayer_data_begin",
"rna_iterator_array_next",
@ -3317,6 +3323,7 @@ static void rna_def_MPropCol(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshVertColor");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshVertColorLayer_data_begin",
"rna_iterator_array_next",
@ -3362,6 +3369,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
RNA_def_property_struct_type(prop, "Mesh" elemname "FloatProperty"); \
RNA_def_property_ui_text(prop, "Data", ""); \
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); \
RNA_def_property_collection_funcs(prop, \
"rna_Mesh" elemname "FloatPropertyLayer_data_begin", \
"rna_iterator_array_next", \
@ -3405,6 +3413,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
RNA_def_property_struct_type(prop, "Mesh" elemname "IntProperty"); \
RNA_def_property_ui_text(prop, "Data", ""); \
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); \
RNA_def_property_collection_funcs(prop, \
"rna_Mesh" elemname "IntPropertyLayer_data_begin", \
"rna_iterator_array_next", \
@ -3447,6 +3456,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
RNA_def_property_struct_type(prop, "Mesh" elemname "StringProperty"); \
RNA_def_property_ui_text(prop, "Data", ""); \
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); \
RNA_def_property_collection_funcs(prop, \
"rna_Mesh" elemname "StringPropertyLayer_data_begin", \
"rna_iterator_array_next", \
@ -3955,6 +3965,7 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshSkinVertex");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshSkinVertexLayer_data_begin",
"rna_iterator_array_next",
@ -4008,6 +4019,7 @@ static void rna_def_vertex_creases(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshVertexCrease");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshVertexCreaseLayer_data_begin",
"rna_iterator_array_next",
@ -4042,6 +4054,7 @@ static void rna_def_edge_creases(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshEdgeCrease");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshEdgeCreaseLayer_data_begin",
"rna_iterator_array_next",

View File

@ -177,6 +177,7 @@ static void rna_def_pointcloud(BlenderRNA *brna)
/* geometry */
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Point");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_PointCloud_points_begin",
"rna_iterator_array_next",

View File

@ -116,9 +116,6 @@ static bool meshcache_read_mdd_range_from_time(FILE *fp,
return false;
}
if (i == mdd_head.frame_tot) {
frame = (float)(mdd_head.frame_tot - 1);
}
if (UNLIKELY(f_time_prev == FLT_MAX)) {
frame = 0.0f;
}

View File

@ -18,6 +18,7 @@ namespace blender::nodes {
using bke::AnonymousAttributeFieldInput;
using bke::AnonymousAttributeID;
using bke::AnonymousAttributeIDPtr;
using bke::AnonymousAttributePropagationInfo;
using bke::AttributeAccessor;
using bke::AttributeFieldInput;
@ -26,7 +27,6 @@ using bke::AttributeKind;
using bke::AttributeMetaData;
using bke::AttributeReader;
using bke::AttributeWriter;
using bke::AutoAnonymousAttributeID;
using bke::GAttributeReader;
using bke::GAttributeWriter;
using bke::GSpanAttributeWriter;
@ -259,7 +259,7 @@ class GeoNodeExecParams {
* Return a new anonymous attribute id for the given output. None is returned if the anonymous
* attribute is not needed.
*/
AutoAnonymousAttributeID get_output_anonymous_attribute_id_if_needed(
AnonymousAttributeIDPtr get_output_anonymous_attribute_id_if_needed(
const StringRef output_identifier, const bool force_create = false)
{
if (!this->anonymous_attribute_output_is_required(output_identifier) && !force_create) {

View File

@ -56,10 +56,10 @@ Mesh *create_grid_mesh(
int verts_x, int verts_y, float size_x, float size_y, const AttributeIDRef &uv_map_id);
struct ConeAttributeOutputs {
AutoAnonymousAttributeID top_id;
AutoAnonymousAttributeID bottom_id;
AutoAnonymousAttributeID side_id;
AutoAnonymousAttributeID uv_map_id;
AnonymousAttributeIDPtr top_id;
AnonymousAttributeIDPtr bottom_id;
AnonymousAttributeIDPtr side_id;
AnonymousAttributeIDPtr uv_map_id;
};
Mesh *create_cylinder_or_cone_mesh(float radius_top,

View File

@ -142,7 +142,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const eAttrDomain domain = eAttrDomain(storage.domain);
const std::string output_identifier = "Attribute" + identifier_suffix(data_type);
AutoAnonymousAttributeID attribute_id = params.get_output_anonymous_attribute_id_if_needed(
AnonymousAttributeIDPtr attribute_id = params.get_output_anonymous_attribute_id_if_needed(
output_identifier);
if (!attribute_id) {

View File

@ -30,7 +30,7 @@ static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
}
struct AttributeOutputs {
AutoAnonymousAttributeID intersecting_edges_id;
AnonymousAttributeIDPtr intersecting_edges_id;
};
static void node_update(bNodeTree *ntree, bNode *node)

View File

@ -59,7 +59,7 @@ static Curves *create_star_curve(const float inner_radius,
}
static void create_selection_output(CurveComponent &component,
AutoAnonymousAttributeID &r_attribute)
AnonymousAttributeIDPtr &r_attribute)
{
SpanAttributeWriter<bool> selection =
component.attributes_for_write()->lookup_or_add_for_write_only_span<bool>(*r_attribute,
@ -78,8 +78,8 @@ static void node_geo_exec(GeoNodeExecParams params)
std::max(params.extract_input<int>("Points"), 3));
GeometrySet output = GeometrySet::create_with_curves(curves);
if (AutoAnonymousAttributeID outer_points_id =
params.get_output_anonymous_attribute_id_if_needed("Outer Points")) {
if (AnonymousAttributeIDPtr outer_points_id = params.get_output_anonymous_attribute_id_if_needed(
"Outer Points")) {
create_selection_output(output.get_component_for_write<CurveComponent>(), outer_points_id);
params.set_output("Outer Points",
AnonymousAttributeFieldInput::Create<bool>(

View File

@ -43,15 +43,15 @@ static void node_declare(NodeDeclarationBuilder &b)
node_storage(node).use_all_curves = false;
});
b.add_output<decl::Float>(N_("Value"), "Value_Float").dependent_field();
b.add_output<decl::Int>(N_("Value"), "Value_Int").dependent_field();
b.add_output<decl::Vector>(N_("Value"), "Value_Vector").dependent_field();
b.add_output<decl::Color>(N_("Value"), "Value_Color").dependent_field();
b.add_output<decl::Bool>(N_("Value"), "Value_Bool").dependent_field();
b.add_output<decl::Float>(N_("Value"), "Value_Float").dependent_field({6, 7, 8});
b.add_output<decl::Int>(N_("Value"), "Value_Int").dependent_field({6, 7, 8});
b.add_output<decl::Vector>(N_("Value"), "Value_Vector").dependent_field({6, 7, 8});
b.add_output<decl::Color>(N_("Value"), "Value_Color").dependent_field({6, 7, 8});
b.add_output<decl::Bool>(N_("Value"), "Value_Bool").dependent_field({6, 7, 8});
b.add_output<decl::Vector>(N_("Position")).dependent_field();
b.add_output<decl::Vector>(N_("Tangent")).dependent_field();
b.add_output<decl::Vector>(N_("Normal")).dependent_field();
b.add_output<decl::Vector>(N_("Position")).dependent_field({6, 7, 8});
b.add_output<decl::Vector>(N_("Tangent")).dependent_field({6, 7, 8});
b.add_output<decl::Vector>(N_("Normal")).dependent_field({6, 7, 8});
}
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)

View File

@ -135,13 +135,13 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(geometry_set);
AutoAnonymousAttributeID rotation_anonymous_id =
AnonymousAttributeIDPtr rotation_anonymous_id =
params.get_output_anonymous_attribute_id_if_needed("Rotation");
const bool need_tangent_and_normal = bool(rotation_anonymous_id);
AutoAnonymousAttributeID tangent_anonymous_id =
AnonymousAttributeIDPtr tangent_anonymous_id =
params.get_output_anonymous_attribute_id_if_needed("Tangent", need_tangent_and_normal);
AutoAnonymousAttributeID normal_anonymous_id =
params.get_output_anonymous_attribute_id_if_needed("Normal", need_tangent_and_normal);
AnonymousAttributeIDPtr normal_anonymous_id = params.get_output_anonymous_attribute_id_if_needed(
"Normal", need_tangent_and_normal);
geometry::ResampleCurvesOutputAttributeIDs resample_attributes;
resample_attributes.tangent_id = tangent_anonymous_id.get();

View File

@ -322,8 +322,8 @@ BLI_NOINLINE static void propagate_existing_attributes(
namespace {
struct AttributeOutputs {
AutoAnonymousAttributeID normal_id;
AutoAnonymousAttributeID rotation_id;
AnonymousAttributeIDPtr normal_id;
AnonymousAttributeIDPtr rotation_id;
};
} // namespace

View File

@ -57,7 +57,7 @@ static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
}
struct IndexAttributes {
AutoAnonymousAttributeID duplicate_index;
AnonymousAttributeIDPtr duplicate_index;
};
/* -------------------------------------------------------------------- */

View File

@ -62,8 +62,8 @@ static void node_update(bNodeTree *ntree, bNode *node)
}
struct AttributeOutputs {
AutoAnonymousAttributeID top_id;
AutoAnonymousAttributeID side_id;
AnonymousAttributeIDPtr top_id;
AnonymousAttributeIDPtr side_id;
};
static void save_selection_as_attribute(Mesh &mesh,

View File

@ -593,8 +593,8 @@ static void interpolate_curve_attributes(bke::CurvesGeometry &child_curves,
}
static void store_output_attributes(bke::CurvesGeometry &child_curves,
const AutoAnonymousAttributeID weight_attribute_id,
const AutoAnonymousAttributeID index_attribute_id,
const AnonymousAttributeIDPtr weight_attribute_id,
const AnonymousAttributeIDPtr index_attribute_id,
const int max_neighbors,
const Span<int> all_neighbor_counts,
const Span<int> all_neighbor_indices,
@ -658,8 +658,8 @@ static GeometrySet generate_interpolated_curves(
const VArray<int> &point_group_ids,
const int max_neighbors,
const AnonymousAttributePropagationInfo &propagation_info,
const AutoAnonymousAttributeID &index_attribute_id,
const AutoAnonymousAttributeID &weight_attribute_id)
const AnonymousAttributeIDPtr &index_attribute_id,
const AnonymousAttributeIDPtr &weight_attribute_id)
{
const bke::CurvesGeometry &guide_curves = guide_curves_id.geometry.wrap();
@ -813,10 +813,10 @@ static void node_geo_exec(GeoNodeExecParams params)
const AnonymousAttributePropagationInfo propagation_info = params.get_output_propagation_info(
"Curves");
AutoAnonymousAttributeID index_attribute_id = params.get_output_anonymous_attribute_id_if_needed(
AnonymousAttributeIDPtr index_attribute_id = params.get_output_anonymous_attribute_id_if_needed(
"Closest Index");
AutoAnonymousAttributeID weight_attribute_id =
params.get_output_anonymous_attribute_id_if_needed("Closest Weight");
AnonymousAttributeIDPtr weight_attribute_id = params.get_output_anonymous_attribute_id_if_needed(
"Closest Weight");
GeometrySet new_curves = generate_interpolated_curves(guide_curves_id,
*points_component->attributes(),

View File

@ -107,8 +107,7 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
AutoAnonymousAttributeID uv_map_id = params.get_output_anonymous_attribute_id_if_needed(
"UV Map");
AnonymousAttributeIDPtr uv_map_id = params.get_output_anonymous_attribute_id_if_needed("UV Map");
Mesh *mesh = create_cube_mesh(size, verts_x, verts_y, verts_z, uv_map_id.get());

View File

@ -198,8 +198,7 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
AutoAnonymousAttributeID uv_map_id = params.get_output_anonymous_attribute_id_if_needed(
"UV Map");
AnonymousAttributeIDPtr uv_map_id = params.get_output_anonymous_attribute_id_if_needed("UV Map");
Mesh *mesh = create_grid_mesh(verts_x, verts_y, size_x, size_y, uv_map_id.get());
BKE_id_material_eval_ensure_default_slot(&mesh->id);

View File

@ -111,8 +111,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const int subdivisions = std::min(params.extract_input<int>("Subdivisions"), 10);
const float radius = params.extract_input<float>("Radius");
AutoAnonymousAttributeID uv_map_id = params.get_output_anonymous_attribute_id_if_needed(
"UV Map");
AnonymousAttributeIDPtr uv_map_id = params.get_output_anonymous_attribute_id_if_needed("UV Map");
Mesh *mesh = create_ico_sphere_mesh(subdivisions, radius, uv_map_id.get());
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));

View File

@ -358,8 +358,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const float radius = params.extract_input<float>("Radius");
AutoAnonymousAttributeID uv_map_id = params.get_output_anonymous_attribute_id_if_needed(
"UV Map");
AnonymousAttributeIDPtr uv_map_id = params.get_output_anonymous_attribute_id_if_needed("UV Map");
Mesh *mesh = create_uv_sphere_mesh(radius, segments_num, rings_num, uv_map_id.get());
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));

View File

@ -342,7 +342,7 @@ static void create_attributes(GeoNodeExecParams &params,
{
MutableAttributeAccessor attributes = instances.attributes_for_write();
if (AutoAnonymousAttributeID line_id = params.get_output_anonymous_attribute_id_if_needed(
if (AnonymousAttributeIDPtr line_id = params.get_output_anonymous_attribute_id_if_needed(
"Line")) {
SpanAttributeWriter<int> line_attribute = attributes.lookup_or_add_for_write_only_span<int>(
*line_id, ATTR_DOMAIN_INSTANCE);
@ -353,7 +353,7 @@ static void create_attributes(GeoNodeExecParams &params,
params.attribute_producer_name()));
}
if (AutoAnonymousAttributeID pivot_id = params.get_output_anonymous_attribute_id_if_needed(
if (AnonymousAttributeIDPtr pivot_id = params.get_output_anonymous_attribute_id_if_needed(
"Pivot Point")) {
SpanAttributeWriter<float3> pivot_attribute =
attributes.lookup_or_add_for_write_only_span<float3>(*pivot_id, ATTR_DOMAIN_INSTANCE);

View File

@ -138,7 +138,7 @@ static std::function<ID *(const bNode &node)> get_default_id_getter(const bNodeT
return nullptr;
}
const bNodeTree &ntree = *reinterpret_cast<const bNodeTree *>(node.id);
const bNodeSocket *io_socket;
const bNodeSocket *io_socket = nullptr;
if (in_out == SOCK_IN) {
/* Better be safe than sorry when the underlying node group changed. */
if (socket_index < ntree.interface_inputs().size()) {

View File

@ -39,6 +39,7 @@ float SEQ_retiming_handle_speed_get(const struct Sequence *seq,
const struct SeqRetimingHandle *handle);
int SEQ_retiming_handle_index_get(const struct Sequence *seq,
const struct SeqRetimingHandle *handle);
void SEQ_retiming_sound_animation_data_set(const struct Scene *scene, const struct Sequence *seq);
float SEQ_retiming_handle_timeline_frame_get(const struct Scene *scene,
const struct Sequence *seq,
const struct SeqRetimingHandle *handle);

View File

@ -73,6 +73,8 @@ int SEQ_time_find_next_prev_edit(struct Scene *scene,
bool SEQ_time_strip_intersects_frame(const struct Scene *scene,
const struct Sequence *seq,
int timeline_frame);
/* Convert timeline frame so strip frame index. */
float SEQ_give_frame_index(const struct Scene *scene, struct Sequence *seq, float timeline_frame);
/**
* Returns true if strip has frames without content to render.
*/

View File

@ -2614,7 +2614,7 @@ float seq_speed_effect_target_frame_get(Scene *scene,
}
SEQ_effect_handle_get(seq_speed); /* Ensure, that data are initialized. */
int frame_index = seq_give_frame_index(scene, seq_speed, timeline_frame);
int frame_index = SEQ_give_frame_index(scene, seq_speed, timeline_frame);
SpeedControlVars *s = (SpeedControlVars *)seq_speed->effectdata;
const Sequence *source = seq_speed->seq1;

View File

@ -142,7 +142,7 @@ static float seq_cache_timeline_frame_to_frame_index(Scene *scene,
* images or extended frame range of movies will only generate one cache entry. No special
* treatment in converting frame index to timeline_frame is needed. */
if (ELEM(type, SEQ_CACHE_STORE_RAW, SEQ_CACHE_STORE_THUMBNAIL)) {
return seq_give_frame_index(scene, seq, timeline_frame);
return SEQ_give_frame_index(scene, seq, timeline_frame);
}
return timeline_frame - SEQ_time_start_frame_get(seq);

View File

@ -209,7 +209,7 @@ ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int timeline
}
if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
int frameno = (int)seq_give_frame_index(context->scene, seq, timeline_frame) +
int frameno = (int)SEQ_give_frame_index(context->scene, seq, timeline_frame) +
seq->anim_startofs;
if (proxy->anim == NULL) {
if (seq_proxy_get_fname(

View File

@ -238,7 +238,7 @@ StripElem *SEQ_render_give_stripelem(const Scene *scene, Sequence *seq, int time
* all other strips don't use this...
*/
int frame_index = (int)seq_give_frame_index(scene, seq, timeline_frame);
int frame_index = (int)SEQ_give_frame_index(scene, seq, timeline_frame);
if (frame_index == -1 || se == NULL) {
return NULL;
@ -1042,7 +1042,7 @@ static ImBuf *seq_render_movie_strip_custom_file_proxy(const SeqRenderData *cont
}
}
int frameno = (int)seq_give_frame_index(context->scene, seq, timeline_frame) +
int frameno = (int)SEQ_give_frame_index(context->scene, seq, timeline_frame) +
seq->anim_startofs;
return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
}
@ -1658,7 +1658,7 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
bool *r_is_proxy_image)
{
ImBuf *ibuf = NULL;
float frame_index = seq_give_frame_index(context->scene, seq, timeline_frame);
float frame_index = SEQ_give_frame_index(context->scene, seq, timeline_frame);
int type = (seq->type & SEQ_TYPE_EFFECT) ? SEQ_TYPE_EFFECT : seq->type;
switch (type) {
case SEQ_TYPE_META: {

View File

@ -990,9 +990,7 @@ static bool seq_update_seq_cb(Sequence *seq, void *user_data)
}
BKE_sound_set_scene_sound_volume(
seq->scene_sound, seq->volume, (seq->flag & SEQ_AUDIO_VOLUME_ANIMATED) != 0);
BKE_sound_set_scene_sound_pitch(seq->scene_sound,
SEQ_sound_pitch_get(scene, seq),
(seq->flag & SEQ_AUDIO_PITCH_ANIMATED) != 0);
SEQ_retiming_sound_animation_data_set(scene, seq);
BKE_sound_set_scene_sound_pan(
seq->scene_sound, seq->pan, (seq->flag & SEQ_AUDIO_PAN_ANIMATED) != 0);
}

View File

@ -438,6 +438,7 @@ Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
if (load_data->flags & SEQ_LOAD_MOVIE_SYNC_FPS) {
scene->r.frs_sec = fps_denom;
scene->r.frs_sec_base = fps_num;
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_FPS | ID_RECALC_SEQUENCER_STRIPS);
}
load_data->r_video_stream_start = IMD_anim_get_offset(anim_arr[0]);

View File

@ -13,6 +13,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_span.hh"
#include "BLI_vector.hh"
#include "BKE_fcurve.h"
#include "BKE_movieclip.h"
@ -118,6 +119,7 @@ bool SEQ_retiming_is_active(const Sequence *seq)
bool SEQ_retiming_is_allowed(const Sequence *seq)
{
return ELEM(seq->type,
SEQ_TYPE_SOUND_RAM,
SEQ_TYPE_IMAGE,
SEQ_TYPE_META,
SEQ_TYPE_SCENE,
@ -126,7 +128,7 @@ bool SEQ_retiming_is_allowed(const Sequence *seq)
SEQ_TYPE_MASK);
}
float seq_retiming_evaluate(const Sequence *seq, const int frame_index)
float seq_retiming_evaluate(const Sequence *seq, const float frame_index)
{
const SeqRetimingHandle *previous_handle = retiming_find_segment_start_handle(seq, frame_index);
const SeqRetimingHandle *next_handle = previous_handle + 1;
@ -140,9 +142,8 @@ float seq_retiming_evaluate(const Sequence *seq, const int frame_index)
}
const int segment_length = next_handle->strip_frame_index - previous_handle->strip_frame_index;
const int segment_frame_index = frame_index - previous_handle->strip_frame_index;
const float segment_fac = segment_frame_index / float(segment_length);
const float segment_frame_index = frame_index - previous_handle->strip_frame_index;
const float segment_fac = segment_frame_index / (float)segment_length;
const float target_diff = next_handle->retiming_factor - previous_handle->retiming_factor;
return previous_handle->retiming_factor + (target_diff * segment_fac);
}
@ -245,6 +246,130 @@ float SEQ_retiming_handle_speed_get(const Sequence *seq, const SeqRetimingHandle
return speed;
}
class RetimingRange {
public:
int start, end;
float speed;
enum eIntersectType {
FULL,
PARTIAL_START,
PARTIAL_END,
INSIDE,
NONE,
};
RetimingRange(int start_frame, int end_frame, float speed)
: start(start_frame), end(end_frame), speed(speed)
{
}
const eIntersectType intersect_type(const RetimingRange &other) const
{
if (other.start <= start && other.end >= end) {
return FULL;
}
if (other.start > start && other.start < end && other.end > start && other.end < end) {
return INSIDE;
}
if (other.start > start && other.start < end) {
return PARTIAL_END;
}
if (other.end > start && other.end < end) {
return PARTIAL_START;
}
return NONE;
}
};
class RetimingRangeData {
public:
blender::Vector<RetimingRange> ranges;
RetimingRangeData(const Sequence *seq)
{
MutableSpan handles = SEQ_retiming_handles_get(seq);
for (const SeqRetimingHandle &handle : handles) {
if (handle.strip_frame_index == 0) {
continue;
}
const SeqRetimingHandle *handle_prev = &handle - 1;
float speed = SEQ_retiming_handle_speed_get(seq, &handle);
int frame_start = SEQ_time_start_frame_get(seq) + handle_prev->strip_frame_index;
int frame_end = SEQ_time_start_frame_get(seq) + handle.strip_frame_index;
RetimingRange range = RetimingRange(frame_start, frame_end, speed);
ranges.append(range);
}
}
RetimingRangeData &operator*=(const RetimingRangeData rhs)
{
if (ranges.is_empty()) {
for (const RetimingRange &rhs_range : rhs.ranges) {
RetimingRange range = RetimingRange(rhs_range.start, rhs_range.end, rhs_range.speed);
ranges.append(range);
}
return *this;
}
for (int i = 0; i < ranges.size(); i++) {
RetimingRange &range = ranges[i];
for (const RetimingRange &rhs_range : rhs.ranges) {
if (range.intersect_type(rhs_range) == range.NONE) {
continue;
}
else if (range.intersect_type(rhs_range) == range.FULL) {
range.speed *= rhs_range.speed;
}
else if (range.intersect_type(rhs_range) == range.PARTIAL_START) {
RetimingRange range_left = RetimingRange(
range.start, rhs_range.end, range.speed * rhs_range.speed);
range.start = rhs_range.end + 1;
ranges.insert(i, range_left);
}
else if (range.intersect_type(rhs_range) == range.PARTIAL_END) {
RetimingRange range_left = RetimingRange(range.start, rhs_range.start - 1, range.speed);
range.start = rhs_range.start;
ranges.insert(i, range_left);
}
else if (range.intersect_type(rhs_range) == range.INSIDE) {
RetimingRange range_left = RetimingRange(range.start, rhs_range.start - 1, range.speed);
RetimingRange range_mid = RetimingRange(
rhs_range.start, rhs_range.start, rhs_range.speed * range.speed);
range.start = rhs_range.end + 1;
ranges.insert(i, range_left);
ranges.insert(i, range_mid);
break;
}
}
}
return *this;
}
};
static RetimingRangeData seq_retiming_range_data_get(const Scene *scene, const Sequence *seq)
{
RetimingRangeData strip_retiming_data = RetimingRangeData(seq);
const Sequence *meta_parent = seq_sequence_lookup_meta_by_seq(scene, seq);
if (meta_parent == nullptr) {
return strip_retiming_data;
}
RetimingRangeData meta_retiming_data = RetimingRangeData(meta_parent);
strip_retiming_data *= meta_retiming_data;
return strip_retiming_data;
}
void SEQ_retiming_sound_animation_data_set(const Scene *scene, const Sequence *seq)
{
RetimingRangeData retiming_data = seq_retiming_range_data_get(scene, seq);
for (const RetimingRange &range : retiming_data.ranges) {
BKE_sound_set_scene_sound_pitch_constant_range(
seq->scene_sound, range.start, range.end, range.speed);
}
}
float SEQ_retiming_handle_timeline_frame_get(const Scene *scene,
const Sequence *seq,
const SeqRetimingHandle *handle)

View File

@ -53,7 +53,16 @@ float seq_time_media_playback_rate_factor_get(const Scene *scene, const Sequence
return seq->media_playback_rate / scene_playback_rate;
}
float seq_give_frame_index(const Scene *scene, Sequence *seq, float timeline_frame)
int seq_time_strip_original_content_length_get(const Scene *scene, const Sequence *seq)
{
if (seq->type == SEQ_TYPE_SOUND_RAM) {
return seq->len;
}
return seq->len / seq_time_media_playback_rate_factor_get(scene, seq);
}
float SEQ_give_frame_index(const Scene *scene, Sequence *seq, float timeline_frame)
{
float frame_index;
float sta = SEQ_time_start_frame_get(seq);
@ -494,10 +503,6 @@ bool SEQ_time_has_still_frames(const Scene *scene, const Sequence *seq)
int SEQ_time_strip_length_get(const Scene *scene, const Sequence *seq)
{
if (seq->type == SEQ_TYPE_SOUND_RAM) {
return seq->len;
}
if (SEQ_retiming_is_active(seq)) {
SeqRetimingHandle *handle_start = seq->retiming_handles;
SeqRetimingHandle *handle_end = seq->retiming_handles + (SEQ_retiming_handles_count(seq) - 1);

Some files were not shown because too many files have changed in this diff Show More