Compare commits

..

215 Commits

Author SHA1 Message Date
8300ba81f2 fix portals 2021-03-31 16:54:47 +02:00
2db2afeeb6 Merge branch 'master' into temp-node-tree-pages-prototype 2021-03-31 16:33:16 +02:00
482a42c0f6 Fix T87087: attributes were removed automatically even though they are still needed
The geometry nodes modifier did not specify that it needs all custom data layers.
Therefore the modifier evaluation code tagged some layers so that they will not be
copied later on by calling `mesh_set_only_copy` in `mesh_calc_modifiers`.
2021-03-31 16:25:39 +02:00
23bd6cff81 GPencil: Avoid LineArt modifier uses negative material index
In some situations the material index could be negative, and this is wrong.
2021-03-31 16:17:31 +02:00
d55d4fee30 Fix compiler error in Windows
C7555	use of designated initializers requires at least '/std:c++latest'

This is not supported by the current Windows compiler version.
2021-03-31 16:01:18 +02:00
10272ca788 GPencil: Remove flag PROP_ID_SELF_CHECK from materials
This flag was used by error when the code of RNA object was used as base, but it's not logic in materials.
2021-03-31 15:50:48 +02:00
94079ffc7f Fix T86879 Boolean exact crash with dependency loop.
When boolean's Object also has a modifier that depends back on
the target Object, a crash occurred.
In a case like this, BKE_modifier_get_evaluated_mesh_from_evaluated_object
returns NULL, so just have to protect against that case.
2021-03-31 09:35:40 -04:00
23c1e48e19 Cleanup: naming for edit-mesh nearest distance values
- Don't use `r_` prefix for an argument that's also read from
  (this is meant for return only arguments).
- Rename variables to make it clear the distance is pixels,
  using manhattan length measurement.
2021-04-01 00:01:23 +11:00
5f787b290c Cleanup: Removed Unused Definition. 2021-03-31 14:47:38 +02:00
bc837ad14e Fix: Cryptomatte Picker on Legacy Node Failing.
The new Cryptomatte workflow assumes that the picker is used in the new
workflow. The legacy node wasn't working as it would never find a
correct cryptomatte layer. This fix will use the color sampling like we
used to do.
2021-03-31 14:43:14 +02:00
1a7b94236e Compositor: Keep WorkPackages and Data Around.
WorkPackages struct was created when scheduled. This patch keeps the
WorkPackages around and stores additional data with the workpackages.

The speedup is to small to notice, but it is needed as preparation
to introduce a faster scheduling method.
2021-03-31 14:43:14 +02:00
14901e3774 Fix T87080: Select shortest path fails in face mode
Regression in 80cbbd2843.

Unfortunately keeping selection picking behavior as well as
supporting finding the nearest face within a radius requires an
inconsistency between x-ray and back-buffer selection that
doesn't work well using the current arguments.

Resolve by adding an argument that causes the input distance
to be ignored for back-buffer selection.

This is used by selection picking but not the knife tool.

This changes behavior for path-selection in face mode,
which now uses a margin for back-buffer selection.

From my own testing this doesn't seem to be a problem like it could be
for regular selection picking.
2021-03-31 23:36:51 +11:00
d97dca5106 Fix T86947: Drag & Drop tooltip in Scene mode
The tooltip while dragging a collection in Scene mode in the Outliner
was always "Link inside Collection" even if the action performed was
different. This was because the `collection_drop_init` set the
`from_collection` always to `NULL` if the Outliner display mode was
currently set to Scene.
Commit that introduced this issue:
rB0f54c3a9b75be8f8db9022fb0aeb0f8d0d4f0299

The fix removes the check of the display mode and only sets the
`from_collection` to `NULL` if the ctrl (linking) key is held.

Reviewed By: JacquesLucke

Maniphest Tasks: T86947

Differential Revision: https://developer.blender.org/D10864
2021-03-31 14:23:08 +02:00
8d45a96789 Fix T87082: Smooth thickness not working
When using the smooth operator, the thickness would not be
smoothed on the first iteration. This was becasue the inner loop
was set to run `r * 20` times but `r` starts at 0.

The fix makes sure that "Smooth Thickness" works on the first
iteration by using  a fixed value of `20` as the loop limit. This
makes sure that for every iteration, we run the smoothing of the
thickness 20 more times.

Reviewed By: antoniov

Maniphest Tasks: T87082

Differential Revision: https://developer.blender.org/D10867
2021-03-31 14:19:01 +02:00
f02e1a77c9 Makefile: add update_code target
Convenience target for updating the code, skipping SVN.

The Python script supports it, but this wasn't exposed in the makefile.

Ref D10457
2021-03-31 22:34:11 +11:00
4d856ecb11 Cleanup: Fix warnings
Introduced in b128ffd539
2021-03-31 12:34:44 +02:00
e9616c82bd Cleanup: use constexpr for num channels.
Don't assume all compilers are smart. MSVC doesn't inline the call away like CLANG and GCC did.
2021-03-31 11:00:07 +02:00
645fc0c767 Fix build error on windows
Error was caused by using `#if` directive in `PyDoc_STRVAR` macro.

This partially reverts 1e4c35d910
2021-03-31 09:46:38 +02:00
b128ffd539 Cleanup: Remove SEQ_CURRENT_BEGIN macro
Use LISTBASE_FOREACH instead.
SEQ_CURRENT_BEGIN did null checks, so now these must be explicit.

Reviewed By: campbellbarton

Differential Revision: https://developer.blender.org/D10823
2021-03-31 09:27:31 +02:00
43369ca80e PyDoc: quiet warning with literalinclude including blank lines
Files that only contain a doc-string still included the last blank line,
since this normally contains code examples.

There are some cases where only a docstring exists
which made sphinx report warnings.
2021-03-31 17:47:31 +11:00
d5f2043ab3 PyDoc: fix indentation with multi-line property descriptions
New lines were written without indentation,
causing invalid RST to be generated.
2021-03-31 17:43:30 +11:00
1e4c35d910 PyDoc: correct sphinx syntax for gpu.state.blend_set 2021-03-31 17:42:21 +11:00
b547ac32d9 Cleanup: use early return for imbuf image loader functions
Most imbuf loaders already did this, use early exit for the remaining
loaders that didn't.
2021-03-31 17:05:57 +11:00
e7f890aa59 WM: use data-path utility functions for WM operators
Use utility functions to decompose data paths and resolve the
RNA property from a data-path.
Replaces in-line string manipulation and RNA access.

This allows more complex data paths to be used, where previously string
literals in a data path could break the simple data-path handling logic.
2021-03-31 15:29:50 +11:00
1beca76934 PyAPI: add bl_rna_utils.decompose_data_path
Utility function for splitting an RNA path, to be used by `bpy.ops.wm.*`
2021-03-31 15:03:19 +11:00
c59a7f44a1 Fix bl_rna_utils._TokenizeDataPath function argument extraction error
Converting functions with single arguments to a string
added an additional comma.
2021-03-31 15:01:44 +11:00
5678e6c2bc Cleanup: improve navigation gizmo flag use
Flag check for V3D_LOCK_CAMERA used boolean style assignment to a char,
which worked with this flag but could fail if other flags are added
that use this convention in the future.

- Add static type checks for values so any change to DNA types
  will need to be made in the navigation gizmo too.
- Move camera lock check from `rv3d` to `v3d`,
  as this isn't stored in the region data.
2021-03-31 13:04:12 +11:00
87aa514611 UI: Gizmo Button to Lock Camera to View
2D gizmo navigation button that toggles 'Lock Camera to View' while in Camera View.

Differential Revision: https://developer.blender.org/D10835

Reviewed by Campbell Barton
2021-03-30 14:09:26 -07:00
1425411249 Cleanup/Refactor: Unify functions that redraw the depth buffer
Now `ED_view3d_backbuf_depth_validate`, `ED_view3d_draw_depth` and
`ED_view3d_draw_depth_gpencil` are unified in `ED_view3d_depth_override`.

This new function replaces `ED_view3d_autodist_init`.

Also, since `ED_view3d_depth_update` depends on the render context, and
changing the context is a slow operation, that function also was removed,
and the depth buffer cached is now updated inside the new unified drawing
function when the "bool update_cache" parameter is true.

Finally `V3D_INVALID_BACKBUF` flag has been renamed and moved to
`runtime.flag`.

Differential revision: https://developer.blender.org/D10678
2021-03-30 16:23:58 -03:00
da1b002c8d UI: Skip undo steps when changing properties of the 3d cursor
Differential revision: https://developer.blender.org/D10695
2021-03-30 16:13:21 -03:00
54d7dea283 Fix: buttons whose property contains an 'owner_id' ignore rna undo check
Introduced in rBce462fa1 but harmless since curretly only `StructRNA`
without `owner_id` have the `STRUCT_UNDO` flag cleared.

So this commit does not bring any functional changes but it will be
useful for {D10695}.
2021-03-30 16:10:58 -03:00
67b40f829e Fix T87058: GPencil Cutter delete all strokes if they are selected and the layer is locked
The problem was produced because the strokes were selected, but the loop to clear this flag before applying cutter was using unlocked layers only, and the protected layer flag was not reset.

Now, the flag is reset for all layers, locked and unlocked.
2021-03-30 19:43:45 +02:00
Wannes Malfait
6ddd280b21 Nodes: Expose multi input socket in python API
It was not possible to determine if a socket was multi input previously
with BPY. This patch exposes the flag as a read-only property of a node
socket. This is important for addons which automatically add connections
between nodes.

Differential Revision: https://developer.blender.org/D10847
2021-03-30 10:15:23 -05:00
6ea09db7a1 Cleanup: Improve comment 2021-03-30 10:03:11 -05:00
e5f0d176d4 CMake: issue warnings when changing options
Only done in top level CMakeLists, and platform_apple.

Reviewed By: campbellbarton
Differential Revision: https://developer.blender.org/D10343
2021-03-30 20:28:45 +05:30
9f323e9bf7 UI: Bring back hover shortcuts for mesh modifiers
Earlier last year, the shortcuts on hover were built as a way to regain
speed lost by removing the "Apply" and "Copy" buttons from the panel.
For the active modifier concept introduced for geometry nodes, the
shortcuts were changed to only affect the active modifier.

Based on feedback, this change slowed down many people's interaction
with the modifier stack so the UI team decided to return hover shortcuts
for modifier panels.

The downside of this change is that it looks like the active modifier is
"selected" and it could be confusing that the modifier shortcuts don't
apply to it. We can explore different ways to display the active status
to address this.

Ref T87012
2021-03-30 09:56:04 -05:00
1f58a0ea3c Cleanup: use doxy sections and rearrange editmesh_knife.c 2021-03-30 11:50:05 -03:00
b1380101df Geometry Nodes: Set default grid vertices to 3 by 3
This is a relatively arbitrary value, but a good starting point-- it's
simple while also showing the possibility of the subdivisions.

Ref T86819
2021-03-30 09:33:42 -05:00
a4b6c222fa Fix unused variable warning caused by recent cleanup
Caused by a cleanup, rBd037fef3bd1dc.
2021-03-30 09:18:33 -05:00
88b5d7f5f3 Cleanup: remove unneeded method.
size can be accessed via instance attribute.
2021-03-30 16:03:43 +02:00
094c950915 Cleanup: clang-format. 2021-03-30 16:03:43 +02:00
88e0ed3288 Cleanup: Use constexpr. 2021-03-30 16:03:43 +02:00
b48a573adb Compositor: Fix Incorrect Attaching NodeSockets.
Introduced by recent commit.
2021-03-30 16:03:43 +02:00
04a92297dd Cleanup: Replace std::vector with blender::Vector. 2021-03-30 16:03:43 +02:00
d4e76712d4 Cryptomatte: Fix When Image based Cryptomatte Aren't On The First Render Layer.
The image user wasn't updated to reflect the correct render layer.
2021-03-30 16:03:43 +02:00
e125c9329d Fix: Compile Error COM_Debug.
We should replace `ifdef COM_Debug` with a constexpr function.
2021-03-30 16:03:43 +02:00
3ead9b2b36 Cleanup: Replace virtual methods with bitflags. 2021-03-30 16:03:43 +02:00
5a6d5d20de UI: add description methods for wm.context_* operators
Generic context operators now look-up the RNA properties to extract
their description (when it's available).

Add `bl_rna_utils.data_path.property_definition_from_data_path()`
to handle the details of accessing the RNA property definition.
2021-03-31 01:02:08 +11:00
88d94d89fa Fix T87007: Cycles Background not updated if strength is initially null
When the strength is initially set to zero, the shader graph is
optimized out to remove any node which will not be executed because of
this, which removes pretty much every single node, except for the
output. As the graph is empty, the world shader is made invisible to
rays so it is not evaluated in the kernel.

However, when the strength is then modified, the Background is not
updated as the modification happens on the Shader Node and not on the
Background Node, so it is never tagged as modified.

To fix this, we need to tag the Background as modified when its shader
is also modified so the Kernel data is properly updated.

Regression caused by rBbbe6d44928235cd4a5cfbeaf1a1de78ed861bb92.
2021-03-30 15:41:33 +02:00
f1fe42d912 Cycles: Do not allocate tile buffers on all devices when peer memory is active and denoising is not
Separate tile buffers on all devices only need to exist when denoising is active (so any overlap
being rendered simultaneously does not write to the same memory region).
When denoising is not active they can be distributed like all other memory when peer
memory support is available.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D10858
2021-03-30 14:04:56 +02:00
7fd3b07da1 Build Environment: set MAKE_THREADS as per the CPU
It is a better default.

Reviewed By: sebbas, sybren
Differential Revision: https://developer.blender.org/D10652
2021-03-30 16:42:19 +05:30
681a7d724b PyAPI: replace repr with our own escape function in animsys_refactor
Use the same string escaping logic shared by RNA path resolving code.
2021-03-30 21:57:23 +11:00
5da5a1cc2d Geometry Nodes: support multiple group input nodes
Previously this was only supported within nested node groups.
Now it is also supported for the root node group that is referenced
by the modifier.
2021-03-30 12:34:16 +02:00
05fa5ca337 Cleanup: Typo in comment. 2021-03-30 12:15:19 +02:00
Scott Wilson
74d5a93b2b Armature: Add Display Axis Offset
Display the bone axes at the head (root) of the bone by default, instead
of the tail (tip), and add a slider so that it's possible to adjust this
position.

Versioning code is in place to ensure existing files behave the same
(axes shown at tail), whereas new Armatures will be using the new
default (axes shown at head).

Reviewed By: #animation_rigging, #user_interface, Severin, Sybren

Differential Revision: https://developer.blender.org/D7685
2021-03-30 11:40:26 +02:00
0d65d27386 Python: clarify error message when accessing datablock by library
When using `bpy.data.actions[action_name, "nonexistant-library"]`,
use the term `filepath` instead of `name` in the error message.

Also increase the size to match the file path length.

Ref D10253
2021-03-30 19:31:50 +11:00
Henrik Dick
39bead4d51 Fix simple solidify wrong custom data on large ngons
Fixes an unreported issue that vertex data on large ngons (>255)
is messed up due to type conversion to char and back to int.

Ref D10734
2021-03-30 19:13:36 +11:00
fd10c21f51 Cleanup: animation, remove BONE_UNKEYED flag
Remove the `BONE_UNKEYED` flag. It was only written (set/cleared) but
never actually read.

Also remove `framechange_poses_clear_unkeyed()` as its only function was
to clear the `BONE_UNKEYED` flag. It wasn't used anywhere either.

The only code that used the flag was the `extract_pose_from_action()`,
which was removed in 2869ce6cfa (2009).

No functional changes.
2021-03-30 09:46:26 +02:00
563d513e37 Cleanup: clang-tidy warning. 2021-03-30 08:08:43 +02:00
89e46f578f Cleanup: clang-tidy warning. 2021-03-30 08:08:15 +02:00
52d09dad9c Knife: snap refactor, prepare for snap gizmo
Minor changes preparing for snap gizmo inclusion.

- Extract `knife_snap_edge_in_angle` into a utility function.
- Check the snap vertex on closest edge instead of the face.
- Add MODE_INVOKING state.
- Remove unnecessary NULL checks.
- Control 'ignore_edge_snapping' while dragging instead of checking
  dragging in `knife_snap_update_from_mval`.

Ref D8220
2021-03-30 16:19:33 +11:00
73b5afd352 Cleanup: Fix incorrect socket list name 2021-03-29 22:41:34 -05:00
d037fef3bd Cleanup: Use float4x4 type and constructor 2021-03-29 22:15:07 -05:00
f9eaf93d37 MSVC: ASAN support for VS 16.9
This enables ASAN support when used with VS 16.9
enable as usual in cmake with the WITH_COMPILER_ASAN
option, or when using make.bat just tag on `asan'
to the invocation, ie: `make lite 2019 asan`

MSVC: Asan support for 16.9

This enables ASAN support when used with VS 16.9
enable as usual in cmake with the WITH_COMPILER_ASAN
option, or when using make.bat just tag on `asan'
to the invocation, ie: `make lite 2019 asan`

Differential Revision: https://developer.blender.org/D7794
Reviewed By: brecht, sergey
2021-03-29 19:11:17 -06:00
6c33d3d01b Fix T86944: Incorrect seeking in some movies
`av_seek_frame()` failed to seek to nearest I-frame. This seems to be
a bug or not implemented feature in FFmpeg. Looks like same issue as
ticket https://trac.ffmpeg.org/ticket/1607 on ffmpeg tracker.

If seeking is done using format specific function (`read_seek2`)
field of `AVInputFormat` is set, `see av_seek_frame()`, use
`av_seek_frame()` function. Otherwise use wrapper that actively searches
for I-frame packet.

Searching is flexible and tries to do minimum amount of work. Currently
it is limited to equivalent of 25 frames, which may not be enough for
some files, but there may be files with no I-frames at all, so it is
best to keep this limit as low as possible. Previously this problem was
masked by preseek, which was hard-coded to 25 frames. This was removed
in rB88604b79b7d1.

If this approach would be unnecessary for some formats, in worst case
file would be seeked 2 times which is very fast, so there will be no
visible impact on performance.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D10845
2021-03-30 02:58:53 +02:00
ffbe803505 VSE: Add fit method to RNA API
Add fit_method argument to new movie and image RNA API functions.
This argument is optional.

ref T86925

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D10816
2021-03-30 02:58:53 +02:00
6c6f3baaa8 VSE: Fix image adding inconsistency
When adding images with operator, image file path is split into filename
and directory passed to load function in name and path fields of
SeqLoadData struct. This is because when loading images directory
and filenames are split.

RNA API function passes whole path in path filed.

Apart from loading API inconsistency, this causes initial image loading
to fail, so strip resolution is not set. Also name field of SeqLoadData
should be reserved for strip name.

Let operator code concatenate and split filepath when needed so loading
API can be consistent with RNA API and also between strip types.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D10818
2021-03-30 02:58:53 +02:00
7d467915a4 Cleanup: Decrease variable scope 2021-03-29 18:48:34 -05:00
91c44fe885 Cycles: disable NanoVDB for AMD OpenCL
It is causing issue with AMD OpenCL drivers, due to a potential driver bug.

Ref T84461
2021-03-30 00:00:17 +02:00
661e6e0966 Gizmo: Use a utility function to read snap gizmo values
No functional changes.

This makes the `ED_gizmotypes_snap_3d_update` function more specialized.
2021-03-29 14:32:48 -03:00
Germano Cavalcante
d0dd85a820 Snap Gizmo: Minor optimization when updating gizmo properties
As the Snap Gizmo properties are used as return of snapping values and
therefore updated with each change, use callbacks to get these values
through RNA properties.

Differential Revision: https://developer.blender.org/D8525
2021-03-29 14:07:51 -03:00
a702ca3faa Tests/bpy: Add installation verification test
Makes it slightly easier to test whether the installed module works
or not. Depends on D10656

Ref T86579
Reviewed By: mont29, campbellbarton
Differential Revision: https://developer.blender.org/D10665
2021-03-29 22:26:54 +05:30
fbe2c3f422 Tests: disable python tests for blender as python module
Avoid CTest errors and exit codes due to test failures which depend
on Blender executable.

Ref T86579
Reviewed By: mont29, campbellbarton
Differential Revision: https://developer.blender.org/D10656
2021-03-29 22:25:52 +05:30
241f05d53c macOS/bpy: accommodate portable builds, and multi-config generators.
Old code's `install` step did not guarantee that all script files
will be copied from source folder to build folder _before_ copying from
build folder to site-packages. That caused incomplete installation.
Fixed by copying scripts etc., only once. Also match the behavior on
Linux: install to site-packages only if `WITH_INSTALL_PORTABLE` is OFF.

Also fix install and launch issues with Xcode.
2021-03-29 22:25:13 +05:30
77ac67dae4 Cleanup/CMake: remove trailing /; whitespace. 2021-03-29 22:24:33 +05:30
2db2b7de55 Cleanup: Replace is...Operation() methods with a flag. 2021-03-29 17:10:01 +02:00
fe60062a99 Cleanup: Use Bitflags For Booleans. 2021-03-29 17:10:01 +02:00
ca516e78c4 Fix T87013: GPencil SVG export wrong svg xml header settings
The attribute was missing.
2021-03-29 17:02:25 +02:00
f99e703df3 Fix T86975: GPencil interpolate wrong stroke order
When interpolate, the stroke order was not correct because it was assumed the GHash iter would return the items in the same order of insertion, but this is false.

Now, a list is used to keep the order of the strokes and the Hash is used to get the relationship between strokes as before.
2021-03-29 17:02:25 +02:00
81fae56cb9 Fix T86298: crash when loading "corrupted" geometry node tree
The file was not really corrupted (as in, Blender did everything
correctly while saving). I only did not consider the case when
a .blend file is resaved in an older version before.
2021-03-29 16:57:03 +02:00
bc872e0c8e Fix: Line Art panel in properties showing in the wrong order with add-ons
It should set bl_order to show below panels registered by render engine add-ons
like Cycles.
2021-03-29 16:40:31 +02:00
2e7e13442c Fix T76872: Mask created after existing keyframe gets broken handles
The issue was caused by handles not being written to the new mask
spline shape: it was always written as (0, 0), which was making the
handle calculation go wrong later on.

Solved by allocating a temporary array of bezier points and calculating
handles for them. While this is an extra array allocation it is only
done for a small amount of points and it is not in the critical code
path. Having this as an extra array helps to overcome a limitation of
the current mask shape API.

Additionally, disable the interpolation for the shape change:
the spline is brand new, there is nothing to be interpolated there.
2021-03-29 16:19:22 +02:00
51f8dbe081 Mask: Fix possible nan values in the weight interpolation
Noticed while looking into animation data being created as per
steps to reproduce bug in T76872.
2021-03-29 16:19:22 +02:00
10e05bb413 GPencil Cleanup: Remove legacy key to cancel drawing
The 'E' key was set to cancel drawing. This was a change in the
old grease pencil system and is no longer used.
2021-03-29 15:56:25 +02:00
fa8269cc4e Animation: add PBONE_SELECTED macro
Add `PBONE_SELECTED` macro to determine selection state of bones, while
also taking visibility into account.
2021-03-29 15:01:45 +02:00
4d3a2ba6a9 Cleanup: clang-format. 2021-03-29 15:01:09 +02:00
8f38534300 Tracking: Avoid integer overflow in dopesheet update
Straightforward check to discard cases when dopesheet is being updated
for a movie clip which has no markers at all.

Possible bugfix for T86847.
2021-03-29 14:43:58 +02:00
e0ce76f1c5 Fix T86983: bl_description = None crash on RNA class registration 2021-03-29 22:05:05 +11:00
Jeroen Bakker
1ea5157051 Fix: Cryptomatte Metadata Trimmed to 1024.
When reading metadata from image files the metadata is trimmed to 1024.
For cryptomatte the metadata can contain json data and should not be
trimmed. Resulting additional checks in the manifest parser for
incomplete json data.

You could argue to add an exception for cryptomatte, but that would
still allows misuse. When the direction of this patch is accepted we
should consider removing `maxlen` from `IDP_AssignString` as it
doesn't seem to be used anywhere else.

Reviewed By: #images_movies, mont29, sergey

Differential Revision: https://developer.blender.org/D10825
2021-03-29 12:16:39 +02:00
35cf34de6d Fix T86851: PulseAudio randomly asserts in background rendering
Upstream fix from Audaspace with simplified PulseAudio code.

Maniphest Tasks: T86851

Differential Revision: https://developer.blender.org/D10840
2021-03-29 12:16:01 +02:00
Élie Michel
ae9d61e7fe Python API: add template for image processing
Since a few releases it is possible to process Blenders images much
more effficiently than before thanks to the `foreach_get`/`foreach_set`
methods. This new template shows how those methods can be used together
with numpy.

Differential Revision: https://developer.blender.org/D9400
2021-03-29 12:08:41 +02:00
075a19049f Cleanup: Updated Documentation Library Overrides. 2021-03-29 12:04:29 +02:00
ac6d8241fb Fix: Override Test Cases Failing With Asserts. 2021-03-29 11:51:34 +02:00
Sergey Sharybin
19f1c52269 Cleanup: Remove no-op id recalc statement
Initially this is a typo when solving merge conflict back in 2017
in commit rBf4140f2c8138.

The code was so for 3 years, so it is safer to assume that this is
the new expected design. The affected codepath only comes from the
BKE_object_modifier_update_subframe() which is discouraged from use
and have other issues.

Eventually those offending codepaths will be removed completely.

The grade-schema for now is more localized: remove ID_RECALC_ALL
which seems to be misused and is causing issues like the ones which
are described and discussed in T81340.

On user level there should be no measurable changes. In fact, no
functional changes at all are expected to happen.

Reviewed By: sybren

Differential Revision: https://developer.blender.org/D9220
2021-03-29 11:37:30 +02:00
f56fddbf9a Clang Tidy: disable WarningsAsErrors
This makes regular development more pleasant, because one does not have
to fix unrelated clang tidy mistakes when one is in the middle of something.
Before this change, I would usually turn clang-tidy off entirely, but then
forget to turn it on again.

This change has been agreed on by Sergey as well.
2021-03-29 11:04:34 +02:00
3681a619de Fix T78650: Lattice evaluation writes to shared data
Fix the data management bug where evaluation of lattice objects would
write back to the CoW copy of the Lattice ID, even when that copy was
shared between objects.

Each lattice object evaluation now stores its own evaluated data copy
via `BKE_object_eval_assign_data()`.

Reviewed By: sergey

Maniphest Tasks: T78650

Differential Revision: https://developer.blender.org/D10790
2021-03-29 11:00:32 +02:00
8034b276ba Fix T86876: cannot modify float properties of geometry nodes modifier from Python
Previously, the code expected the id property to have the `IDP_FLOAT` type.
However, when assigning a Python float (which is a double internally)
to an id property, it would change the type to `IDP_DOUBLE`.
The fix is to allow both types in the geometry nodes modifier.
2021-03-29 10:54:04 +02:00
fa1569a072 Fix T86966: crash when rendering with geometry nodes
UI hints should only be modified when the depsgraph is active.
Otherwise two threads evaluating the same object in different depsgraphs
can conflict with each other.
2021-03-29 10:14:54 +02:00
4e34baddb9 Overrides: Make Experimental API Fail On Usage.
It used to give a warning so test cases couldn't fail. This has been
changed in the test case so we could use an error here.
2021-03-29 09:57:06 +02:00
87f9405c9a Overrides: API to create an override template.
This is functionality that isn't accessible via the user interface. The
API allows the creation and modification of an override template that
holds rules that needs to be checked when overriding the asset.

The API is setup that it cannot be changed after creation. Later on when
the system is more mature we will allow changing overrides operations.

NOTE: This is an experimental feature and should not be used in productions.

Reviewed By: mont29, sebbas

Differential Revision: https://developer.blender.org/D10792
2021-03-29 09:54:34 +02:00
27fa2507a1 Fix T86972: transform node transforms shape keys 2021-03-29 09:35:19 +02:00
240f15c1b6 Comments: improve docstring for ED_view3d_clipping_test
The meaning of the return value wasn't obvious.
2021-03-29 18:30:45 +11:00
b9734f7716 Cleanup: Remove unused node.c.
Was wrongly added back with the anti aliasing node patch.
2021-03-29 09:25:08 +02:00
80cbbd2843 Knife: support vert/edge snapping when not directly over a face
Respect the distance argument to EDBM_face_find_nearest,
when zero, sample a single pixel, otherwise sample a region.

Knife uses the selection-buffer to pick a face when the ray-cast failed.
This was meant to allow snapping to nearby faces however as the margin
was ignored, it was only used in edge cases where the ray-cast missed
but the pixel didn't.

Now the face-picking threshold is working as expected.

Note that other callers to EDBM_face_find_nearest have been updated
so set their distance argument to zero so this only impacts the knife.
Regular selection and path select could be modified separately if users
prefer this behavior.
2021-03-29 18:08:57 +11:00
3659340571 Cleanup: logical error in path select picking
Resolve logical error in edbm_shortest_path_pick_invoke
where any discrepancy between EDBM_unified_findnearest and
edbm_elem_find_nearest caused the active-object to be cleared.

While it's not a problem at the moment, using a larger threshold
for path picking exposes the error.
2021-03-29 18:08:57 +11:00
8994f09a4a Knife: scale points & snapping threshold by the DPI factor
The points were too small on hi-dpi displays.
2021-03-29 18:08:57 +11:00
fc889615f7 Fix vert/edge knife snapping when the cursor wasn't over a face
In this case, the cage location was left zeroed which was then
projected back onto the screen to find the nearest screen space
edge/vertex.

This made snapping to the vertex/edge fail in some corner-cases
where it was intended to work.
2021-03-29 18:08:57 +11:00
ab26be8ff7 Cleanup: use pragma once. 2021-03-29 08:20:21 +02:00
25c02ea703 Cleanup: Add namespace to compositor. 2021-03-29 08:18:33 +02:00
9975af5ffa Cleanup: Add override Keyword. 2021-03-29 08:04:58 +02:00
Habib Gahbiche
805d947810 Compositor: Add Anti-Aliasing node
This is an implementation of Enhanced Subpixel Morphological Antialiasing (SMAA)

The algorithm was proposed by:
  Jorge Jimenez, Jose I. Echevarria, Tiago Sousa, Diego Gutierrez

This node provides only SMAA 1x mode, so the operation will be done with no spatial
multisampling nor temporal supersampling. See Patch for comparisons.

The existing AA operation seems to be used only for binary images by some other nodes.
Using SMAA for binary images needs no important parameter such as "threshold", so we
perhaps can switch the operation to SMAA, though that changes existing behavior.

Notes:
1. The program code assumes the screen coordinates are DirectX style that the
   vertical direction is upside-down, so "top" and "bottom" actually represent bottom
   and top, respectively.

Thanks for Habib Gahbiche (zazizizou) to polish and finalize this patch.

Reviewed By: jbakker

Differential Revision: https://developer.blender.org/D2411
2021-03-29 07:56:58 +02:00
6af4163a3f Knife: reduce redundant face picking queries
Reduce the maximum number of queries to find the face under the
mouse cursor from 6x to 2x on cursor motion.

Calculating the screen-space detail could perform 2x look-ups
which have already been calculated.
2021-03-29 14:31:05 +11:00
27a7b2e27a Fix T83391: Knife sometimes snaps to object center
Knife snapping logic assumed having a face under the cursor meant
the projected positions were set.

This is not always the case as failure to ray-cast uses the back-buffer
as a fallback.
2021-03-29 13:29:14 +11:00
e47f5cf197 Cleanup: deduplicate attribute creating code 2021-03-28 12:50:14 +02:00
9289c358fb Cleanup: use parentheses in macro 2021-03-28 12:50:14 +02:00
afcfc6eb08 Fix T86060: Texture Paint clone tool misleading texture UI
For projection painting tools besides the `DRAW` tool:

- Don't show the texture from viewport stencil drawing.
- Don't show the texture panel.

Based on D10564 by @lichtwerk with own changes.
2021-03-28 19:45:56 +11:00
3944560b4a Cleanup: re-order expensive checks for indirect ID use
Check for indirect ID use after other simple user count checks are made.

Also assert ED_object_base_free_and_unlink_no_indirect_check object
argument isn't indirectly used.
2021-03-28 18:48:57 +11:00
0a6bca1f75 Cleanup: revert part of da160dc32d
The grease-pencil parent check was enabled when deleting objects,
when previously it was only done when unlinking.

While harmless, the previous logic is correct.
2021-03-28 18:48:57 +11:00
46d980228b Fix T86992: Tagged ID deletion conflicts with freeing objects
Check LIB_TAG_COPIED_ON_WRITE instead of LIB_TAG_NO_MAIN,
matching the behavior of rigid-body shared data.
2021-03-28 18:16:07 +11:00
5b1980859a Workaround T86992: Tagged ID deletion conflicts with freeing objects
da160dc32d exposed a bug in
`BKE_id_multi_tagged_delete` causing a memory leak in soft-body that
made `physics_softbody` test fail.

Use a loop to remove ID's to keep tests working until T86992 is fixed.
2021-03-28 17:32:37 +11:00
a9e7d503dd Cleanup: Apply clang format 2021-03-27 15:01:41 +01:00
Marcelo Demian Gómez
e7c4c9e538 Fix T86967 : Artifacts when tracing image to Grease Pencil
Tracing images to grease pencil objects creates sometimes artifacts, as seen, for example, when tracing the attached image.  {F9910821}
I have found the same behavior both in the 2.92 release and in the current 2.93 master.
The artifacts are caused by a variable that's not initialized or updated when finding a point tagged as POTRACE_CORNER.
This patch solves this issue.

Maniphest Tasks: T86967

Differential Revision: https://developer.blender.org/D10832
2021-03-27 15:01:36 +01:00
dc873c4a7b Fix T86975: GPencil interpolate sequence error when strokes are not selected
If the selection order is not used, need to put the strokes in inverse order because the Hash Iter returns the strokes in inverse order.
2021-03-27 12:51:18 +01:00
c4ab1891cc Automated testing: selection operators test cases
added 22 more test cases for following operators:
    - edges select sharp
    - loop multi select
    - select all
    - select faces by sides
    - select interior faces
    - select less
    - select linked

{F9853218}

Reviewed By: calra, mont29

Differential Revision: https://developer.blender.org/D10400
2021-03-27 09:48:54 +01:00
Pratik Borhade
99dabc156a Cleanup: spelling and comments
- comment added in struct `KnifeTool_OpData`
- struct pointer name `lst` updated to `list` ( Guess its more readable )
- `KNF_MODEL_IGNORE_SNAP_ON` updated to `KNF_MODAL_IGNORE_SNAP_ON`
- `KNF_MODEL_IGNORE_SNAP_OFF` updated to `KNF_MODAL_IGNORE_SNAP_OFF`

Ref D10824
2021-03-27 16:21:37 +11:00
Siddhartha Jejurkar
9f3d41d4ee Fix T86924: UV Sync selection breaks individual origin calculation
Use uvedit_uv_select_test which accounts for UV Sync selection.

Ref D10830
2021-03-27 15:58:31 +11:00
a6ec2de96a Correct header rename error 10cfa75e1d 2021-03-27 15:48:59 +11:00
Fabrício Luis
8e6e8dd871 UV Editor: Add cursor center operator
This matches cursor center operator from the 3D view.

Reviewed By: campbellbarton

Resolves T70142

Ref D8271
2021-03-27 15:07:26 +11:00
414017ac86 Cleanup: clang-format 2021-03-27 14:49:59 +11:00
ee367084a7 Comment: note that structs are zeroed instead of using defaults 2021-03-27 14:48:26 +11:00
10cfa75e1d Cleanup: use .hh extension for C++ headers
Follow documented convention for file naming.
2021-03-27 14:05:30 +11:00
da160dc32d Object: faster object deletion
The `object_delete_exec` lead to `BKE_library_ID_is_indirectly_used`
being called twice. With this patch deleting is around 20% faster.

Example when deleting 10000 objects:
Current: 35.6s
This patch: 18.8s (updated, last rev 29.7s)

Reviewed By: campbellbarton

Ref D9857
2021-03-27 13:38:44 +11:00
Vincent Blankfield
9b87d3f029 Win32: Allow return from fullscreen to maximized
If window is maximized when toggling fullscreen, go back to maximized when done.

Differential Revision: https://developer.blender.org/D10813

Reviewed by Harley Acheson
2021-03-26 14:30:57 -07:00
0ec82477af macOS/bpy: install into site-packages
Reviewed By: #platform_macos, brecht
Maniphest Tasks: T86579
Differential Revision: https://developer.blender.org/D10664
2021-03-27 01:14:45 +05:30
ad31b13f91 macOS/bpy: add support for OpenMP
Changes made:
* Add OpenMP linker flags.
* Copy the libomp.dylib to `2.93/lib/libomp.dylib`.
* Change the `LC_LOAD_DYLIB` item such that
  the lib is found at `bpy.so/../../Resources/2.93/lib/libomp.dylib`.
Installation is done by D10664.

Reviewed By: #platform_macos, brecht
Maniphest Tasks: T86579
Differential Revision: https://developer.blender.org/D10657
2021-03-27 01:08:51 +05:30
35d5cc8982 Cleanup: Use enum for "in" vs. "out" node sockets 2021-03-26 14:25:52 -04:00
Vincent Blankfield
12193035ed Fix T86859: Allow covering of Taskbar when Fullscreen from Maximized
When the window is already maximized allow covering Windows Taskbar when toggling fullscreen.

Differential Revision: https://developer.blender.org/D10811

Reviewed by Harley Acheson
2021-03-26 10:19:50 -07:00
8408a8fda2 LibOverride: Fix outliner menu showing 'override editing' entries for linked overrides.
One can only resync, reset, delete etc. locl overrides, linked ones are
basically regular linked IDs and fully not editable.

Reported by Demeter from the Studio, thanks.
2021-03-26 18:15:20 +01:00
80530edcae Geometry Nodes: Rename "Plane" primitive to "Grid"
Although "Grid" may not be techincally correct since a grid could be 3D,
it was decided to rename the "Plane" primtive to "Grid". The primitive
node allows subdivisions, so the name is more consistent with the
operator in the 3D view.

Ref T86819

This commit includes a file subversion bump for the versioning.
2021-03-26 13:09:35 -04:00
Yevgeny Makarov
e684c170f9 UI: Change Usages of 'WPaint' to 'Weight Paint'
Changing to a more informative 'Weight Paint' rather than 'WPaint'.

Differential Revision: https://developer.blender.org/D9905

Reviewed by Julian Eisel
2021-03-26 09:58:07 -07:00
Charlie Jolly
70061c69b7 Geometry Nodes: Implicit conversion change for float/int/color to bool
Change `float to boolean` and `int32 to boolean` to return false for zero and negative values.

This aligns with how artists would expect these values to work. This is in contrast to what a coder would expect. It was determined on blender.chat that this was a better default. This means that a negative float value would give a boolean false.

Change `Color4f to boolean` to return false for zero and negative grayscale values.

Likewise, for color to boolean, to account for negative value colors, the grayscale value would be used for determining if a colour was false or not.

See {T86454}

Reviewed By: JacquesLucke

Differential Revision: https://developer.blender.org/D10685
2021-03-26 16:29:48 +00:00
1e855149b2 Nodes: match Multi-input socket activation distance
Activation distance for multi input sockets had different length
dependend of dpi factor. That caused jumping when activation distance
became shorter than snapping distance.

Fixed by removing activation distance and using same function
which is used to evaluate snapping.

Reviewer: Dalai Felinto

Differential Revision: https://developer.blender.org/D10809
2021-03-26 17:29:10 +01:00
f560bc90c7 OSL: add basic OSL shader template
Add a basic OSL shader that shows how inputs
and outputs work and do some simple math with
them.

This template is a happy medium between the
templates we already ship, empty_shader is a
little too bare, and the other templates are
a little "too much" and you end up having to
delete a whole bunch of stuff.

a great starting point for some experimentation!

Differential Revision: https://developer.blender.org/D9933

reviewed by: brecht
2021-03-26 10:27:31 -06:00
689d6032ff Compositor: Fix array out of bounds. 2021-03-26 17:23:14 +01:00
William Reynish
dcd90bf188 UI: Remove "Enable physics for:" text in physics properties
The "Enable physics for:" text makes no semantic sense- i.e.
"Enable physics for Fluid". Additionally, the leading text is just not
necessary, this section is just as clear without it.

Differential Revision: https://developer.blender.org/D10537
2021-03-26 12:21:03 -04:00
Leon Leno
97e212f52e Geometry Nodes: Add remaining operations to the Vector Math node
This patch adds support for the remaining operations of the Vector Math
node within Geometry Nodes.  While the operations are already available
in the UI, they hadn't been implemented, yet. With this patch the node
uses the implementation that was added for the Attribute Vector Math
node - similar to how it's handled with the Math node and Attribute
Math node.

Differential Revision: https://developer.blender.org/D10650
2021-03-26 12:15:33 -04:00
Yevgeny Makarov
63a6268e83 UI: Use unified format for "Warning" in descriptions
Warnings in tooltips were using inconsistent formatting, some in
parantheses, some not, some in caps, others not, some on new lines,
some not, etc.

This patch uses a consistent new line and no capitals for these cases.

Differential Revision: https://developer.blender.org/D9904
2021-03-26 12:07:50 -04:00
3d25669486 Cleanup: Geometry Nodes: Allow using "Auto" domain to avoid adapting
Now that we have `ATTR_DOMAIN_AUTO`, it makes sense to use it to skip
automatic domain interpolation. This can make code that depends on the
non-interpolated domain of the attribute a bit simpler.
2021-03-26 11:38:46 -04:00
Habib Gahbiche
252c87b9e8 Compositor automated testing
Added support for compositor tests. Compositor tests can be added, executed and viewed in a similar way to cycles
and other render engines tests.

Running test:
`ctest -R compositor`

Updating test:
`BLENDER_TEST_UPDATE=1 ctest -R compositor`

Viewing test results:
typically saved under `build_folder/tests/compositor/report.html`

Reviewed By: jbakker

Differential Revision: https://developer.blender.org/D6334
2021-03-26 16:15:02 +01:00
39ecf90185 LibOverride optimization; Do not compare bound box of objects.
This is runtime only data, no need to deal with it.
2021-03-26 16:13:16 +01:00
921d0851b5 Fix T86942: GPencil does not export SVG or PDF in orthographic camera
The calculation of the 2D point was wrong when using orthographic mode.

Also small cleanup in float3 variable.

Differential Revision: https://developer.blender.org/D10828
2021-03-26 16:07:02 +01:00
2371454b2d Cleanup: Replace Methode Overloading With Default Value. 2021-03-26 16:02:59 +01:00
6524ceb8cf Cleanup: Remove ptr For Owned Children. 2021-03-26 15:51:06 +01:00
930b8a3932 Cleanup: Replace std::vector With blender::Vector. 2021-03-26 15:51:06 +01:00
9d80b3a69c Cleanup: Replaced Typedef Enum With Enum Class. 2021-03-26 15:51:06 +01:00
f725f42af5 Cleanup: Remove SocketReader.
SocketReader was added as an easier to understand interface on top of
the NodeOperation. It was implemented as a base class of the
NodeOperation and adds an additional hierarchy level.

Ths change replaces the abstract class with a typedef. In the end we
want to remove the typedef but will wait for some new nodes before doing
so.
2021-03-26 15:51:06 +01:00
e5fb7eac85 Cleanup: Use Enum Class For PixelSampler. 2021-03-26 15:51:06 +01:00
23b1872d6e Cleanup: Replace std::vector with blender::Vector. 2021-03-26 15:51:06 +01:00
acc6e5c315 LineArt: Fix unreported material user count error when apply modifier
The number of users was 0 after applying the modifier.
2021-03-26 15:48:54 +01:00
4bb70e0ba5 Geometry-Nodes: Sort the Nodes Categories alphabetically
The exception is still Group and Layout to be consistent with the
other node editors. This could use a separator though.
2021-03-26 14:44:15 +01:00
1614795ae2 FFmpeg: improve threading settings
Generalize threading settings in proxy building and use them for encoding
and decoding in general. Check codec capabilities, prefer FF_THREAD_FRAME
threading over FF_THREAD_SLICE and automatic thread count over setting it
explicitly.

ffmpeg-codecs man page suggests that threads option is global and used by
codecs, that supports this option. Form some tests I have done, it seems that

`av_dict_set_int(&codec_opts, "threads", BLI_system_thread_count(), 0)`

has same effect as

```
pCodecCtx->thread_count = BLI_system_thread_count();
pCodecCtx->thread_type = FF_THREAD_FRAME;
```

Looking at `ff_frame_thread_encoder_init()` code, these cases are not
equivalent. It is probably safer to leave threading setup on libavcodec than
setting up each codec threading individually.

From what I have read all over the internet, frame multithreading should be
faster than slice multithreading. Slice multithreading is mainly used for low
latency streaming.

When running Blender with --debug-ffmpeg it complains about
`pCodecCtx->thread_count = BLI_system_thread_count()` that using thread count
above 16 is not recommended. Using too many threads can negatively affect image
quality, but I am not sure if this is the case for decoding as well - see
https://streaminglearningcenter.com/blogs/ffmpeg-command-threads-how-it-affects-quality-and-performance.html
This is fine for proxies but may be undesirable for final renders.

Number of threads is limited by image size, because of size of motion vectors,
so if it is possible let libavcodec determine optimal thread count.

Performance difference:
Proxy building: None
Playback speed: 2x better on 1920x1080 sample h264 file
Scrubbing: Hard to quantify, but it's much more responsive
Rendering speed: None on 1920x1080 sample h264 file, there is improvement with codecs that do support FF_THREAD_FRAME for encoding like MPNG

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D10791
2021-03-26 12:43:46 +01:00
847002e1f8 FFMPEG: refactor seeking
Split seeking section of `ffmpeg_fetchibuf()` function into multiple
smaller functions.

Conditional statements are moved to own funtions with human readable
names, so code flow is more clear.

To remove one branch of seeking, first frame is now decoded by
scanning, which will do only one iteration. So nothing has technically
changed.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D10638
2021-03-26 12:43:46 +01:00
Charlie Jolly
43455f3857 Geometry Nodes: Add Attribute Clamp Node
This adds a Clamp node for Geometry Nodes Attributes.

Supports both Min-Max and Range clamp modes.

Float, Vector, Color and Int data types supported.

Reviewed By: HooglyBoogly, simonthommes

Differential Revision: https://developer.blender.org/D10526
2021-03-26 10:52:50 +00:00
e867f40611 Cleanup: Replaced unneeded branch with assert. 2021-03-26 11:27:28 +01:00
fb6c29f59c Cleanup: redundant expression 2021-03-26 10:50:34 +01:00
ea12df51b8 Fix T86939: Cycles objects bounds not updated when transforming objects
As a rather premature optimization from rBbbe6d4492823, Object bounds
were only computed when either the Object or its Geometry were modified.
Prior to rB42198e9eb03b, this would work, as the Geometry was tagged as
modified if the Object's transform was also modified.

Since this tagging is not done anymore due to side effects, and since at
the time bounds are computed Objects were already processed and tag as
unmodified, the check on the modified status was always false.

For now remove this check, so the bounds are always unconditionally
updated. If this ever becomes a performance problem in large scenes with
motion blur, we will then try to find a way to nicely optimize it.

This would only affect BHV2 as OptiX and Embree handle object bounds
themselves.
2021-03-26 10:50:34 +01:00
d982ea9a9e Fix error when an addon has no __init__.py
When an addon has been removed, but its `.pyc` files are still there,
the Python module can still be loaded. However, because `__init__.py` is
missing, it becomes a namespace instead of a module, and its `__file__`
will be set to `None`. As a result, it's impossible to get the mtime
from the file (because there is none).

This should not influence any regularly uninstalled add-on, as that
would just remove the add-on's directory; I ran into the problem when
switching Git branches caused an add-on's Python files to disappear
while keeping the `__pycache__` directory around.
2021-03-26 10:46:26 +01:00
fda50625cd Cryptomatte: Fix error loading incomplete metadata.
When rendering with cycles at some point the manifest is trimmed. This
leads to incomplete/corrupted metadata. This patch will make sure that
the manifest parser doesn't crash.

This solved the issue when the manifest is trimmed at the start of a
hash. Eg '"Name":"'.
2021-03-26 09:13:46 +01:00
4425bacec4 Cleanup: Fix clang-tidy errors. 2021-03-26 08:38:58 +01:00
64d4e722a0 UV: warn when unwrapping fails
Report an error when unwrapping can't solve some UV islands,
note that edge-seams may need to be set.

Address T86936
2021-03-26 17:59:36 +11:00
8adeab4b0e Cleanup: use code doxy command for Python snippet 2021-03-26 14:58:30 +11:00
ce528d02e1 Cleanup: spelling 2021-03-26 14:55:55 +11:00
Victor-Louis De Gusseme
dda02a448a Geometry Nodes: Add Attribute Map Range Node
This commit adds a node with a "Map Range" operation for attributes
just like the non-attribute version of the node. However, unlike the
regular version of the node, it also supports operations on vectors.

Differential Revision: https://developer.blender.org/D10344
2021-03-25 23:29:33 -04:00
e18091650b Animation: action mirror RNA API using pose contents
This adds a new RNA method `Action.flip_with_pose(ob)` to flip the
action channels that control a pose.
The rest-pose is used to properly flip the bones transformation.

This is useful as a way to flip actions used in pose libraries,
so the same action need not be included for each side.

Reviewed By: sybren

Ref D10781
2021-03-26 13:37:40 +11:00
ff017df318 Animation: add BKE_fcurve_pathcache_find API
Support a cache for fast RNA path look-ups for RNA-path + index.

Unlike a regular hash lookup, this supports using a single lookup
for the RNA path which is then used to fill an array of F-curves.

Reviewed By: sybren

Ref D10781
2021-03-26 13:37:40 +11:00
6fd799c72c Animation: add BKE_fcurves_calc_keyed_frames utility
This function returns an array of keyed frames with rounding,
to avoid duplicates caused by subtle floating point difference.

Reviewed By: sybren

Ref D10781
2021-03-26 13:37:40 +11:00
758c2210ae Cleanup: clang-format 2021-03-26 12:28:49 +11:00
62f5a6bfa7 CMake: add headers to source lists, sort file-lists 2021-03-26 12:24:41 +11:00
Leon Leno
2f77252086 Fix: Geometry Nodes: Incorrect offsets for plane primitive
The recent commit that changed the size (rB83df3545246aada) left out
a few changed. This patch also adjusts the positioning and UV scale of
the generated plane accordingly.

Differential Revision: https://developer.blender.org/D10822
2021-03-25 20:59:29 -04:00
de1eeaa3d2 LibOverride: fix bad ID relationships handling during resync.
Purely local IDs would not always be used as proper barriers when
generating override hierarchy data, leading to imporperly trying to
resync override IDs from other hierarchies, which would break/cause
issues in case they would be duplicate overrides of the same linked
data.

Reported by Pablo from Sprite team, thanks.
2021-03-25 22:32:04 +01:00
2281db72b0 LibOverride: Fix mistake in recent commit.
We do not want to re-generate auto-overrides until everything that
needed to be resynced has been resynced. Otherwise it's a waste of time
and guaranteed loss of some override properties.

Mistake in rB9947f2095610 earlier today.
2021-03-25 22:32:04 +01:00
64ca286540 Cleanup: Pass instance group result vector as an argument
This will allow retrieving the instance groups from multiple geometry
sets and avoiding needing vectors of vectors to store the results.
This is useful when retrieving instances from a multi-input socket
of geometries.
2021-03-25 14:54:27 -04:00
926f7612fd Fix T86867: Node Editor: Avoid deselect-all triggering on every box-
select

In 'Set/Replace' mode this is not a problem, but 'Extend' or 'Subtract'
modes were useless with the current behavior.
The problem here is that 'node.select' fires before 'node.select_box'
(which is fine) but deselects immediately on click.

This issue has come up before in other editors, see
{T70457}
{rB395dfff103e1}
{rBa8ea1ea1b7d5}

Now delay deselection in empty space to mouse release (same as done in
before mentioned report).

also related:
ref T57918
ref T63994

Maniphest Task: T86867

Differential Revision: https://developer.blender.org/D10801
2021-03-25 17:05:35 +01:00
25c4118651 LibOverride: Silence noisy warnings in console.
That one skiped the move to CLOG a few weeks ago, could spam a lot in
the console in some cases.
2021-03-25 16:57:32 +01:00
0f13bded46 Fix T86852: Allow Font Style Changes to Affect Spreadsheet Text Size
Replacing a hard-coded font size with font style widget size so it can be set by user.

Differential Revision: https://developer.blender.org/D10819

Reviewed by Dalai Felinto
2021-03-25 08:35:36 -07:00
5ebe74e779 GPencil: Fix compiler warning when HARU and PUGIXML are disabled
The function only must be included if Haru or Pugixml is enabled.
2021-03-25 16:06:31 +01:00
1d7adb6d8a BLI: simplify using DefaultHash 2021-03-25 16:01:41 +01:00
9b42626918 BLI: fix Set.lookup_key_or_add 2021-03-25 16:01:41 +01:00
56df673be2 Fix T86796: moving the cursor in the UV Editor does not take aspect into
account

UV coords are scaled by aspects (see UVsToTransData). This also applies
for the Cursor in the UV Editor which also means that for display and
when the cursor coords are flushed (new 'recalcData_cursor_image' was
added for this), these need to be converted each time.

Maniphest Tasks: T86796

Differential Revision: https://developer.blender.org/D10817
2021-03-25 15:36:53 +01:00
a9cd90135a Make moving the cursor in UV Editor a 2d edit transform
This flags moving the cursor in the Image Editor T_2D_EDIT with the
following benefits:

- dissallowing e.g. Z constraints
- improving the header display:
-- it should not use scene units
-- now respects if we are moving in pixel coords or not

part of upcoming fix for T86796
ref D10817
2021-03-25 15:36:53 +01:00
Erik Abrahamsson
5ffbe439c6 Fix for T86613: Renaming in outliner doesn't trigger rename event
When subscribing to name-changes through the API,
the event doesn't trigger if the object is renamed in the outliner.
Fixed by publishing the RNA changes.

Reviewed By: lichtwerk

Ref D10732
2021-03-26 00:39:35 +11:00
543becac36 Fix T86921: Executing "Operator Cheat Sheet" Crashes Blender
This was only happening without an active object.

The "Operator Cheat Sheet" operator collects info about all operators,
and as part of that executes the callbacks to create dynamic enums. The
callback to enumerate the geometry operators (introduced in
rB370d6e50252b) attribute domains depends on a context object. If this
isn't available, we just have to return `DummyRNA_NULL_items`.

Maniphest Tasks: T86921

Differential Revision: https://developer.blender.org/D10814
2021-03-25 14:03:20 +01:00
0083a7615e Revert "Cleanup: Fix unused-private-field warning."
This reverts commit 43c48965d7.
It created a new warning on GCC: -Wattribute (ignored attribute) as
GCC doesn't warn about unused private fields.
2021-03-25 17:23:46 +05:30
9947f20956 LibOverride; Fix missing re-creation of auto-generated override rules after resync.
While not useful for the override system itself, this is rather
important for user feedback.
2021-03-25 12:45:01 +01:00
51b316dbc2 Fix T83390: Remove temporary, for-one-release deprecation hints
Revert "Point users to new location of "Show Group Colors" option",
commit rB6ed6741ee35930bf81fad9a5eb6bb17eea168725.

These deprecation hints were intended for one release only, and thus can
be removed now.
2021-03-25 12:15:28 +01:00
f7fa0d3974 Geometry Nodes: change order of domains in drop down
This has been requested in D10803.
2021-03-25 12:04:38 +01:00
28cf851a5c Geometry Nodes: rename attribute domains
This patch renames two domains:
* `Polygon` -> `Face`
* `Corner` -> `Face Corner`

For the change from `polygon` to `face` I did a "deep rename" where I updated
all (most?) cases where we refere to the attribute domain in code as well.
The change from `corner` to `face corner` is only a ui change. I did not see
a real need to update all code the code for that. It does not seem to improve
the code, more on the contrary.

Ref T86818.

Differential Revision: https://developer.blender.org/D10803
2021-03-25 12:02:50 +01:00
150e0553da Fix T86853: Critical bug in write code of CacheFile ID.
CacheFile writing code would not write generic ID data (call for it has
been missing since the initial commit, rB61050f75b13e).

While potentially affecting other areas (mostly CustomProperties/IDProperties),
this was a critical failure for liboverrides. Also added some workaround
code to allow opening broken files (though the override of the CacheFile
data-block will be lost).
2021-03-25 11:21:15 +01:00
3b0531154e UI: rename node editor sidebar categories
* `Node` -> `Group`
* `Item` -> `Node`

Differential Revision: https://developer.blender.org/D10804
2021-03-25 09:16:03 +01:00
9ac7946dd0 GPencil: Fix wrong file extension when exporting SVG
Due a code cleanup it was using .PDF all times.
2021-03-24 18:47:33 +01:00
43c48965d7 Cleanup: Fix unused-private-field warning. 2021-03-24 22:45:43 +05:30
e2d362757f Cleanup: Add override keyword. 2021-03-24 17:56:29 +01:00
fb7d203d21 only show one portal name 2021-03-19 10:47:37 +01:00
bcc6b87881 support moving nodes between pages by holding ctrl and clicking on page 2021-03-18 16:40:47 +01:00
1faf31f62d create paired portal 2021-03-18 16:16:12 +01:00
0f69327140 display portal names 2021-03-18 15:56:28 +01:00
497167d3a0 add more sockets to portals 2021-03-18 15:47:35 +01:00
6a82b2f4c6 start with page 1 and show current page 2021-03-18 15:37:12 +01:00
9d20624760 change portal node header color 2021-03-18 15:20:22 +01:00
b9aa7f3ce8 change ui 2021-03-18 15:14:49 +01:00
9a7f0b7fec implement copy paste of portals 2021-03-18 13:51:08 +01:00
47006dbdce use tab to switch between portals 2021-03-18 12:52:19 +01:00
d98e05f4b5 initial pages 2021-03-18 12:48:45 +01:00
64d2881650 follow portal operator 2021-03-18 12:16:22 +01:00
acef1af28d portal nodes 2021-03-18 12:01:58 +01:00
747 changed files with 12874 additions and 5360 deletions

View File

@@ -255,7 +255,6 @@ ForEachMacros:
- SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN
- SEQ_ALL_BEGIN
- SEQ_CURRENT_BEGIN
- SURFACE_QUAD_ITER_BEGIN
- foreach
- ED_screen_areas_iter

View File

@@ -43,7 +43,6 @@ Checks: >
# the windows compiler currently.
-modernize-raw-string-literal
WarningsAsErrors: '*'
CheckOptions:
- key: modernize-use-default-member-init.UseAssignment
value: 1

3
.gitignore vendored
View File

@@ -46,3 +46,6 @@ Desktop.ini
# smoke simulation noise tile (generated)
waveletNoiseTile.bin
# testing environment
/Testing

View File

@@ -236,9 +236,7 @@ option(WITH_SYSTEM_AUDASPACE "Build with external audaspace library installed on
mark_as_advanced(WITH_AUDASPACE)
mark_as_advanced(WITH_SYSTEM_AUDASPACE)
if(NOT WITH_AUDASPACE)
set(WITH_SYSTEM_AUDASPACE OFF)
endif()
set_and_warn_dependency(WITH_AUDASPACE WITH_SYSTEM_AUDASPACE OFF)
option(WITH_OPENMP "Enable OpenMP (has to be supported by the compiler)" ON)
if(UNIX AND NOT APPLE)
@@ -522,10 +520,10 @@ if(CMAKE_COMPILER_IS_GNUCC)
mark_as_advanced(WITH_LINKER_LLD)
endif()
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
option(WITH_COMPILER_ASAN "Build and link against address sanitizer (only for Debug & RelWithDebInfo targets)." OFF)
mark_as_advanced(WITH_COMPILER_ASAN)
option(WITH_COMPILER_ASAN "Build and link against address sanitizer (only for Debug & RelWithDebInfo targets)." OFF)
mark_as_advanced(WITH_COMPILER_ASAN)
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
if(WITH_COMPILER_ASAN)
set(_asan_defaults "\
-fsanitize=address \
@@ -704,13 +702,11 @@ if(WITH_PYTHON_MODULE AND WITH_PYTHON_INSTALL)
message(FATAL_ERROR "WITH_PYTHON_MODULE requires WITH_PYTHON_INSTALL to be OFF")
endif()
if(NOT WITH_PYTHON)
set(WITH_CYCLES OFF)
set(WITH_DRACO OFF)
endif()
set_and_warn_dependency(WITH_PYTHON WITH_CYCLES OFF)
set_and_warn_dependency(WITH_PYTHON WITH_DRACO OFF)
if(WITH_DRACO AND NOT WITH_PYTHON_INSTALL)
message(STATUS "WITH_DRACO requires WITH_PYTHON_INSTALL to be ON, disabling WITH_DRACO for now")
message(WARNING "WITH_DRACO requires WITH_PYTHON_INSTALL to be ON, disabling WITH_DRACO for now")
set(WITH_DRACO OFF)
endif()
@@ -729,7 +725,7 @@ set_and_warn_dependency(WITH_PUGIXML WITH_OPENIMAGEIO OFF)
if(WITH_BOOST AND NOT (WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_INTERNATIONAL OR
WITH_OPENVDB OR WITH_OPENCOLORIO OR WITH_USD OR WITH_ALEMBIC))
message(STATUS "No dependencies need 'WITH_BOOST' forcing WITH_BOOST=OFF")
message(WARNING "No dependencies need 'WITH_BOOST' forcing WITH_BOOST=OFF")
set(WITH_BOOST OFF)
endif()
@@ -779,6 +775,7 @@ if(WITH_INSTALL_PORTABLE)
endif()
if(WITH_GHOST_SDL OR WITH_HEADLESS)
message(WARNING "Disabling Ghost Wayland, X11, Input IME, and OpenXR")
set(WITH_GHOST_WAYLAND OFF)
set(WITH_GHOST_X11 OFF)
set(WITH_X11_XINPUT OFF)
@@ -809,7 +806,7 @@ endif()
if(NOT WITH_CUDA_DYNLOAD)
find_package(CUDA)
if(NOT CUDA_FOUND)
message("CUDA toolkit not found, using dynamic runtime loading of libraries instead")
message(WARNING "CUDA toolkit not found, using dynamic runtime loading of libraries (WITH_CUDA_DYNLOAD) instead")
set(WITH_CUDA_DYNLOAD ON)
endif()
endif()
@@ -1235,6 +1232,7 @@ if(WITH_OPENMP)
string(APPEND CMAKE_C_FLAGS " ${OpenMP_C_FLAGS}")
string(APPEND CMAKE_CXX_FLAGS " ${OpenMP_CXX_FLAGS}")
string(APPEND CMAKE_EXE_LINKER_FLAGS " ${OpenMP_LINKER_FLAGS}")
string(APPEND CMAKE_MODULE_LINKER_FLAGS " ${OpenMP_LINKER_FLAGS}")
else()
# Typically avoid adding flags as defines but we can't
# pass OpenMP flags to the linker for static builds, meaning
@@ -1245,6 +1243,7 @@ if(WITH_OPENMP)
find_library_static(OpenMP_LIBRARIES gomp ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES})
endif()
else()
message(WARNING "OpenMP not found, disabling WITH_OPENMP")
set(WITH_OPENMP OFF)
endif()
@@ -1320,6 +1319,7 @@ list(APPEND GL_DEFINITIONS -DGLEW_NO_GLU)
if(WITH_BULLET AND WITH_SYSTEM_BULLET)
find_package(Bullet)
if(NOT BULLET_FOUND)
message(WARNING "Bullet not found, disabling WITH_BULLET")
set(WITH_BULLET OFF)
endif()
else()

View File

@@ -129,7 +129,10 @@ Utilities
Create a compressed archive of the source code.
* update:
updates git and all submodules
Updates git and all submodules and svn.
* update_code:
Updates git and all submodules but not svn.
* format:
Format source code using clang (uses PATHS if passed in). For example::
@@ -522,6 +525,9 @@ icons_geom: .FORCE
update: .FORCE
$(PYTHON) ./build_files/utils/make_update.py
update_code: .FORCE
$(PYTHON) ./build_files/utils/make_update.py --no-libraries
format: .FORCE
PATH="../lib/${OS_NCASE}_${CPU}/llvm/bin/:../lib/${OS_NCASE}_centos7_${CPU}/llvm/bin/:../lib/${OS_NCASE}/llvm/bin/:$(PATH)" \
$(PYTHON) source/tools/utils_maintenance/clang_format_paths.py $(PATHS)

View File

@@ -21,7 +21,8 @@ if(WIN32)
endif()
option(WITH_WEBP "Enable building of oiio with webp support" OFF)
option(WITH_BOOST_PYTHON "Enable building of boost with python support" OFF)
set(MAKE_THREADS 1 CACHE STRING "Number of threads to run make with")
cmake_host_system_information(RESULT NUM_CORES QUERY NUMBER_OF_LOGICAL_CORES)
set(MAKE_THREADS ${NUM_CORES} CACHE STRING "Number of threads to run make with")
if(NOT BUILD_MODE)
set(BUILD_MODE "Release")

View File

@@ -56,6 +56,7 @@ list(APPEND ZLIB_LIBRARIES ${BZIP2_LIBRARIES})
if(WITH_OPENAL)
find_package(OpenAL)
if(NOT OPENAL_FOUND)
message(WARNING "OpenAL not found, disabling WITH_OPENAL")
set(WITH_OPENAL OFF)
endif()
endif()
@@ -65,6 +66,7 @@ if(WITH_JACK)
NAMES jackmp
)
if(NOT JACK_FRAMEWORK)
message(WARNING "JACK not found, disabling WITH_JACK")
set(WITH_JACK OFF)
else()
set(JACK_INCLUDE_DIRS ${JACK_FRAMEWORK}/headers)
@@ -146,7 +148,7 @@ if(WITH_PYTHON)
set(PYTHON_INCLUDE_DIR "${_py_framework}/include/python${PYTHON_VERSION}")
set(PYTHON_EXECUTABLE "${_py_framework}/bin/python${PYTHON_VERSION}")
set(PYTHON_LIBPATH "${_py_framework}/lib/python${PYTHON_VERSION}/config-${PYTHON_VERSION}")
set(PYTHON_LIBPATH "${_py_framework}/lib/python${PYTHON_VERSION}")
# set(PYTHON_LIBRARY python${PYTHON_VERSION})
# set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework Python") # won't build with this enabled
@@ -357,7 +359,7 @@ if(WITH_CYCLES_OSL)
if(OSL_INCLUDE_DIR AND OSL_LIBRARIES AND OSL_COMPILER AND OSL_SHADER_DIR)
set(OSL_FOUND TRUE)
else()
message(STATUS "OSL not found")
message(WARNING "OSL not found, disabling WITH_CYCLES_OSL")
set(WITH_CYCLES_OSL OFF)
endif()
endif()
@@ -413,7 +415,7 @@ if(WITH_OPENMP)
set(OpenMP_LINKER_FLAGS "-L'${LIBDIR}/openmp/lib' -lomp")
# Copy libomp.dylib to allow executables like datatoc and tests to work.
# `@executable_path/../Resources/lib/` `LC_ID_DYLIB`is added by the deps builder.
# `@executable_path/../Resources/lib/` `LC_ID_DYLIB` is added by the deps builder.
# For single config generator datatoc, tests etc.
execute_process(
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/Resources/lib

View File

@@ -149,11 +149,6 @@ add_definitions(-D_WIN32_WINNT=0x601)
include(build_files/cmake/platform/platform_win32_bundle_crt.cmake)
remove_cc_flag("/MDd" "/MD" "/Zi")
if(WITH_WINDOWS_PDB)
set(PDB_INFO_OVERRIDE_FLAGS "/Z7")
set(PDB_INFO_OVERRIDE_LINKER_FLAGS "/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO")
endif()
if(MSVC_CLANG) # Clangs version of cl doesn't support all flags
string(APPEND CMAKE_CXX_FLAGS " ${CXX_WARN_FLAGS} /nologo /J /Gd /EHsc -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference")
@@ -162,6 +157,21 @@ else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd /MP /bigobj")
endif()
# X64 ASAN is available and usable on MSVC 16.9 preview 4 and up)
if(WITH_COMPILER_ASAN AND MSVC AND NOT MSVC_CLANG)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.28.29828)
#set a flag so we don't have to do this comparison all the time
SET(MSVC_ASAN On)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address")
string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " /INCREMENTAL:NO")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_DEBUG " /INCREMENTAL:NO")
else()
message("-- ASAN not supported on MSVC ${CMAKE_CXX_COMPILER_VERSION}")
endif()
endif()
# C++ standards conformace (/permissive-) is available on msvc 15.5 (1912) and up
if(MSVC_VERSION GREATER 1911 AND NOT MSVC_CLANG)
string(APPEND CMAKE_CXX_FLAGS " /permissive-")
@@ -174,14 +184,41 @@ if(WITH_WINDOWS_SCCACHE AND CMAKE_VS_MSBUILD_COMMAND)
set(WITH_WINDOWS_SCCACHE Off)
endif()
# Debug Symbol format
# sccache # MSVC_ASAN # format # why
# On # On # Z7 # sccache will only play nice with Z7
# On # Off # Z7 # sccache will only play nice with Z7
# Off # On # Zi # Asan will not play nice with Edit and Continue
# Off # Off # ZI # Neither asan nor sscache is enabled Edit and Continue is available
# Release Symbol format
# sccache # MSVC_ASAN # format # why
# On # On # Z7 # sccache will only play nice with Z7
# On # Off # Z7 # sccache will only play nice with Z7
# Off # On # Zi # Asan will not play nice with Edit and Continue
# Off # Off # Zi # Edit and Continue disables some optimizations
if(WITH_WINDOWS_SCCACHE)
set(CMAKE_C_COMPILER_LAUNCHER sccache)
set(CMAKE_CXX_COMPILER_LAUNCHER sccache)
set(SYMBOL_FORMAT /Z7)
set(SYMBOL_FORMAT_RELEASE /Z7)
else()
unset(CMAKE_C_COMPILER_LAUNCHER)
unset(CMAKE_CXX_COMPILER_LAUNCHER)
set(SYMBOL_FORMAT /ZI)
if(MSVC_ASAN)
set(SYMBOL_FORMAT /Z7)
set(SYMBOL_FORMAT_RELEASE /Z7)
else()
set(SYMBOL_FORMAT /ZI)
set(SYMBOL_FORMAT_RELEASE /Zi)
endif()
endif()
if(WITH_WINDOWS_PDB)
set(PDB_INFO_OVERRIDE_FLAGS "${SYMBOL_FORMAT_RELEASE}")
set(PDB_INFO_OVERRIDE_LINKER_FLAGS "/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO")
endif()
string(APPEND CMAKE_CXX_FLAGS_DEBUG " /MDd ${SYMBOL_FORMAT}")
@@ -190,9 +227,11 @@ string(APPEND CMAKE_CXX_FLAGS_RELEASE " /MD ${PDB_INFO_OVERRIDE_FLAGS}")
string(APPEND CMAKE_C_FLAGS_RELEASE " /MD ${PDB_INFO_OVERRIDE_FLAGS}")
string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL " /MD ${PDB_INFO_OVERRIDE_FLAGS}")
string(APPEND CMAKE_C_FLAGS_MINSIZEREL " /MD ${PDB_INFO_OVERRIDE_FLAGS}")
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " /MD ${SYMBOL_FORMAT}")
string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO " /MD ${SYMBOL_FORMAT}")
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " /MD ${SYMBOL_FORMAT_RELEASE}")
string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO " /MD ${SYMBOL_FORMAT_RELEASE}")
unset(SYMBOL_FORMAT)
unset(SYMBOL_FORMAT_RELEASE)
# JMC is available on msvc 15.8 (1915) and up
if(MSVC_VERSION GREATER 1914 AND NOT MSVC_CLANG)
string(APPEND CMAKE_CXX_FLAGS_DEBUG " /JMC")

View File

@@ -9,14 +9,10 @@ if "%BUILD_WITH_SCCACHE%"=="1" (
if "%WITH_CLANG%"=="1" (
set CLANG_CMAKE_ARGS=-T"llvm"
if "%WITH_ASAN%"=="1" (
)
if "%WITH_ASAN%"=="1" (
set ASAN_CMAKE_ARGS=-DWITH_COMPILER_ASAN=On
)
) else (
if "%WITH_ASAN%"=="1" (
echo ASAN is only supported with clang.
exit /b 1
)
)
if "%WITH_PYDEBUG%"=="1" (

View File

@@ -46,16 +46,10 @@ set LLVM_DIR=
set CFLAGS=-m64 -fmsc-version=1914
set CXXFLAGS=-m64 -fmsc-version=1914
)
if "%WITH_ASAN%"=="1" (
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_COMPILER_ASAN=On
)
)
if "%WITH_ASAN%"=="1" (
if "%WITH_CLANG%" == "" (
echo ASAN is only supported with clang.
exit /b 1
)
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_COMPILER_ASAN=On
)
if NOT "%verbose%" == "" (

View File

@@ -553,7 +553,7 @@ def example_extract_docstring(filepath):
line_no += 1
else:
file.close()
return "", 0
return "", 0, False
for line in file:
line_no += 1
@@ -563,15 +563,17 @@ def example_extract_docstring(filepath):
text.append(line.rstrip())
line_no += 1
line_no_has_content = False
# Skip over blank lines so the Python code doesn't have blank lines at the top.
for line in file:
if line.strip():
line_no_has_content = True
break
line_no += 1
file.close()
return "\n".join(text), line_no
return "\n".join(text), line_no, line_no_has_content
def title_string(text, heading_char, double=False):
@@ -590,16 +592,18 @@ def write_example_ref(ident, fw, example_id, ext="py"):
filepath = os.path.join("..", "examples", "%s.%s" % (example_id, ext))
filepath_full = os.path.join(os.path.dirname(fw.__self__.name), filepath)
text, line_no = example_extract_docstring(filepath_full)
text, line_no, line_no_has_content = example_extract_docstring(filepath_full)
for line in text.split("\n"):
fw("%s\n" % (ident + line).rstrip())
fw("\n")
fw("%s.. literalinclude:: %s\n" % (ident, filepath))
if line_no > 0:
fw("%s :lines: %d-\n" % (ident, line_no))
fw("\n")
# Some files only contain a doc-string.
if line_no_has_content:
fw("%s.. literalinclude:: %s\n" % (ident, filepath))
if line_no > 0:
fw("%s :lines: %d-\n" % (ident, line_no))
fw("\n")
EXAMPLE_SET_USED.add(example_id)
else:
if bpy.app.debug:
@@ -1408,7 +1412,8 @@ def pyrna2sphinx(basepath):
else:
fw(" .. attribute:: %s\n\n" % prop.identifier)
if prop.description:
fw(" %s\n\n" % prop.description)
write_indented_lines(" ", fw, prop.description, False)
fw("\n")
# special exception, can't use generic code here for enums
if prop.type == "enum":

View File

@@ -109,3 +109,7 @@ endif()
if(WITH_MOD_FLUID)
add_subdirectory(mantaflow)
endif()
if (WITH_COMPOSITOR)
add_subdirectory(smaa_areatex)
endif()

View File

@@ -42,6 +42,7 @@ set(SRC
src/devices/NULLDevice.cpp
src/devices/ReadDevice.cpp
src/devices/SoftwareDevice.cpp
src/devices/ThreadedDevice.cpp
src/Exception.cpp
src/file/File.cpp
src/file/FileManager.cpp
@@ -148,6 +149,7 @@ set(PUBLIC_HDR
include/devices/NULLDevice.h
include/devices/ReadDevice.h
include/devices/SoftwareDevice.h
include/devices/ThreadedDevice.h
include/Exception.h
include/file/File.h
include/file/FileManager.h

View File

@@ -255,6 +255,7 @@ protected:
/**
* This function tells the device, to start or pause playback.
* \param playing True if device should playback.
* \note This method is only called when the device is locked.
*/
virtual void playing(bool playing)=0;

View File

@@ -0,0 +1,95 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#pragma once
/**
* @file ThreadedDevice.h
* @ingroup plugin
* The ThreadedDevice class.
*/
#include "devices/SoftwareDevice.h"
#include <thread>
AUD_NAMESPACE_BEGIN
/**
* This device extends the SoftwareDevice with code for running mixing in a separate thread.
*/
class AUD_PLUGIN_API ThreadedDevice : public SoftwareDevice
{
private:
/**
* Whether there is currently playback.
*/
bool m_playing;
/**
* Whether the current playback should stop.
*/
bool m_stop;
/**
* The streaming thread.
*/
std::thread m_thread;
/**
* Starts the streaming thread.
*/
AUD_LOCAL void start();
/**
* Streaming thread main function.
*/
AUD_LOCAL virtual void runMixingThread()=0;
// delete copy constructor and operator=
ThreadedDevice(const ThreadedDevice&) = delete;
ThreadedDevice& operator=(const ThreadedDevice&) = delete;
protected:
virtual void playing(bool playing);
/**
* Empty default constructor. To setup the device call the function create()
* and to uninitialize call destroy().
*/
ThreadedDevice();
/**
* Indicates that the mixing thread should be stopped.
* \return Whether the mixing thread should be stopping.
* \warning For thread safety, the device needs to be locked, when this method is called.
*/
inline bool shouldStop() { return m_stop; }
/**
* This method needs to be called when the mixing thread is stopping.
* \warning For thread safety, the device needs to be locked, when this method is called.
*/
inline void doStop() { m_stop = m_playing = false; }
/**
* Stops all playback and notifies the mixing thread to stop.
* \warning The device has to be unlocked to not run into a deadlock.
*/
void stopMixingThread();
};
AUD_NAMESPACE_END

View File

@@ -27,9 +27,9 @@ void PulseAudioDevice::PulseAudio_state_callback(pa_context *context, void *data
{
PulseAudioDevice* device = (PulseAudioDevice*)data;
device->m_state = AUD_pa_context_get_state(context);
std::lock_guard<ILockable> lock(*device);
AUD_pa_threaded_mainloop_signal(device->m_mainloop, 0);
device->m_state = AUD_pa_context_get_state(context);
}
void PulseAudioDevice::PulseAudio_request(pa_stream *stream, size_t num_bytes, void *data)
@@ -68,29 +68,40 @@ void PulseAudioDevice::PulseAudio_underflow(pa_stream *stream, void *data)
}
}
void PulseAudioDevice::playing(bool playing)
void PulseAudioDevice::runMixingThread()
{
m_playback = playing;
for(;;)
{
{
std::lock_guard<ILockable> lock(*this);
AUD_pa_stream_cork(m_stream, playing ? 0 : 1, nullptr, nullptr);
if(shouldStop())
{
AUD_pa_stream_cork(m_stream, 1, nullptr, nullptr);
doStop();
return;
}
}
if(AUD_pa_stream_is_corked(m_stream))
AUD_pa_stream_cork(m_stream, 0, nullptr, nullptr);
AUD_pa_mainloop_iterate(m_mainloop, true, nullptr);
}
}
PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buffersize) :
m_playback(false),
m_state(PA_CONTEXT_UNCONNECTED),
m_buffersize(buffersize),
m_underflows(0)
{
m_mainloop = AUD_pa_threaded_mainloop_new();
m_mainloop = AUD_pa_mainloop_new();
AUD_pa_threaded_mainloop_lock(m_mainloop);
m_context = AUD_pa_context_new(AUD_pa_threaded_mainloop_get_api(m_mainloop), name.c_str());
m_context = AUD_pa_context_new(AUD_pa_mainloop_get_api(m_mainloop), name.c_str());
if(!m_context)
{
AUD_pa_threaded_mainloop_unlock(m_mainloop);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_pa_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
}
@@ -99,26 +110,21 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
AUD_pa_context_connect(m_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr);
AUD_pa_threaded_mainloop_start(m_mainloop);
while(m_state != PA_CONTEXT_READY)
{
switch(m_state)
{
case PA_CONTEXT_FAILED:
case PA_CONTEXT_TERMINATED:
AUD_pa_threaded_mainloop_unlock(m_mainloop);
AUD_pa_threaded_mainloop_stop(m_mainloop);
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_pa_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
break;
default:
AUD_pa_threaded_mainloop_wait(m_mainloop);
AUD_pa_mainloop_iterate(m_mainloop, true, nullptr);
break;
}
}
@@ -166,13 +172,10 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
if(!m_stream)
{
AUD_pa_threaded_mainloop_unlock(m_mainloop);
AUD_pa_threaded_mainloop_stop(m_mainloop);
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_pa_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not create PulseAudio stream.");
}
@@ -188,32 +191,27 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
buffer_attr.prebuf = -1U;
buffer_attr.tlength = buffersize;
if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
{
AUD_pa_threaded_mainloop_unlock(m_mainloop);
AUD_pa_threaded_mainloop_stop(m_mainloop);
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_pa_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect PulseAudio stream.");
}
AUD_pa_threaded_mainloop_unlock(m_mainloop);
create();
}
PulseAudioDevice::~PulseAudioDevice()
{
AUD_pa_threaded_mainloop_stop(m_mainloop);
stopMixingThread();
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_pa_mainloop_free(m_mainloop);
destroy();
}

View File

@@ -26,7 +26,7 @@
* The PulseAudioDevice class.
*/
#include "devices/SoftwareDevice.h"
#include "devices/ThreadedDevice.h"
#include <pulse/pulseaudio.h>
@@ -35,15 +35,10 @@ AUD_NAMESPACE_BEGIN
/**
* This device plays back through PulseAudio, the simple direct media layer.
*/
class AUD_PLUGIN_API PulseAudioDevice : public SoftwareDevice
class AUD_PLUGIN_API PulseAudioDevice : public ThreadedDevice
{
private:
/**
* Whether there is currently playback.
*/
volatile bool m_playback;
pa_threaded_mainloop* m_mainloop;
pa_mainloop* m_mainloop;
pa_context* m_context;
pa_stream* m_stream;
pa_context_state_t m_state;
@@ -74,13 +69,15 @@ private:
*/
AUD_LOCAL static void PulseAudio_underflow(pa_stream* stream, void* data);
/**
* Streaming thread main function.
*/
AUD_LOCAL void runMixingThread();
// delete copy constructor and operator=
PulseAudioDevice(const PulseAudioDevice&) = delete;
PulseAudioDevice& operator=(const PulseAudioDevice&) = delete;
protected:
virtual void playing(bool playing);
public:
/**
* Opens the PulseAudio audio device for playback.

View File

@@ -24,18 +24,14 @@ PULSEAUDIO_SYMBOL(pa_context_unref);
PULSEAUDIO_SYMBOL(pa_stream_begin_write);
PULSEAUDIO_SYMBOL(pa_stream_connect_playback);
PULSEAUDIO_SYMBOL(pa_stream_cork);
PULSEAUDIO_SYMBOL(pa_stream_is_corked);
PULSEAUDIO_SYMBOL(pa_stream_new);
PULSEAUDIO_SYMBOL(pa_stream_set_buffer_attr);
PULSEAUDIO_SYMBOL(pa_stream_set_underflow_callback);
PULSEAUDIO_SYMBOL(pa_stream_set_write_callback);
PULSEAUDIO_SYMBOL(pa_stream_write);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_free);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_get_api);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_lock);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_new);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_signal);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_start);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_stop);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_unlock);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_wait);
PULSEAUDIO_SYMBOL(pa_mainloop_free);
PULSEAUDIO_SYMBOL(pa_mainloop_get_api);
PULSEAUDIO_SYMBOL(pa_mainloop_new);
PULSEAUDIO_SYMBOL(pa_mainloop_iterate);

View File

@@ -31,159 +31,83 @@ template <class T> void SafeRelease(T **ppT)
}
}
void WASAPIDevice::start()
{
lock();
// thread is still running, we can abort stopping it
if(m_stop)
m_stop = false;
// thread is not running, let's start it
else if(!m_playing)
{
if(m_thread.joinable())
m_thread.join();
m_playing = true;
m_thread = std::thread(&WASAPIDevice::updateStream, this);
}
unlock();
}
void WASAPIDevice::updateStream()
void WASAPIDevice::runMixingThread()
{
UINT32 buffer_size;
UINT32 padding;
UINT32 length;
data_t* buffer;
lock();
if(FAILED(m_audio_client->GetBufferSize(&buffer_size)))
{
m_playing = false;
m_stop = false;
unlock();
return;
}
IAudioRenderClient* render_client = nullptr;
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client))))
{
m_playing = false;
m_stop = false;
unlock();
return;
std::lock_guard<ILockable> lock(*this);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
if(FAILED(m_audio_client->GetBufferSize(&buffer_size)))
goto init_error;
if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client))))
goto init_error;
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
goto init_error;
length = buffer_size - padding;
if(FAILED(render_client->GetBuffer(length, &buffer)))
goto init_error;
mix((data_t*)buffer, length);
if(FAILED(render_client->ReleaseBuffer(length, 0)))
{
init_error:
SafeRelease(&render_client);
doStop();
return;
}
}
UINT32 padding;
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
{
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
UINT32 length = buffer_size - padding;
if(FAILED(render_client->GetBuffer(length, &buffer)))
{
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
mix((data_t*)buffer, length);
if(FAILED(render_client->ReleaseBuffer(length, 0)))
{
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
unlock();
m_audio_client->Start();
auto sleepDuration = std::chrono::milliseconds(buffer_size * 1000 / int(m_specs.rate) / 2);
for(;;)
{
lock();
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
{
m_audio_client->Stop();
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
std::lock_guard<ILockable> lock(*this);
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
goto stop_thread;
length = buffer_size - padding;
if(FAILED(render_client->GetBuffer(length, &buffer)))
goto stop_thread;
mix((data_t*)buffer, length);
if(FAILED(render_client->ReleaseBuffer(length, 0)))
goto stop_thread;
// stop thread
if(shouldStop())
{
stop_thread:
m_audio_client->Stop();
SafeRelease(&render_client);
doStop();
return;
}
}
length = buffer_size - padding;
if(FAILED(render_client->GetBuffer(length, &buffer)))
{
m_audio_client->Stop();
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
mix((data_t*)buffer, length);
if(FAILED(render_client->ReleaseBuffer(length, 0)))
{
m_audio_client->Stop();
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
// stop thread
if(m_stop)
{
m_audio_client->Stop();
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
unlock();
std::this_thread::sleep_for(sleepDuration);
}
}
void WASAPIDevice::playing(bool playing)
{
if((!m_playing || m_stop) && playing)
start();
else
m_stop = true;
}
WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) :
m_playing(false),
m_stop(false),
m_imm_device_enumerator(nullptr),
m_imm_device(nullptr),
m_audio_client(nullptr),
@@ -361,14 +285,7 @@ WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) :
WASAPIDevice::~WASAPIDevice()
{
lock();
stopAll();
unlock();
if(m_thread.joinable())
m_thread.join();
stopMixingThread();
SafeRelease(&m_audio_client);
SafeRelease(&m_imm_device);

View File

@@ -26,7 +26,7 @@
* The WASAPIDevice class.
*/
#include "devices/SoftwareDevice.h"
#include "devices/ThreadedDevice.h"
#include <thread>
@@ -40,46 +40,23 @@ AUD_NAMESPACE_BEGIN
/**
* This device plays back through WASAPI, the Windows audio API.
*/
class AUD_PLUGIN_API WASAPIDevice : public SoftwareDevice
class AUD_PLUGIN_API WASAPIDevice : public ThreadedDevice
{
private:
/**
* Whether there is currently playback.
*/
bool m_playing;
/**
* Whether the current playback should stop.
*/
bool m_stop;
IMMDeviceEnumerator* m_imm_device_enumerator;
IMMDevice* m_imm_device;
IAudioClient* m_audio_client;
WAVEFORMATEXTENSIBLE m_wave_format_extensible;
/**
* The streaming thread.
*/
std::thread m_thread;
/**
* Starts the streaming thread.
*/
AUD_LOCAL void start();
/**
* Streaming thread main function.
*/
AUD_LOCAL void updateStream();
AUD_LOCAL void runMixingThread();
// delete copy constructor and operator=
WASAPIDevice(const WASAPIDevice&) = delete;
WASAPIDevice& operator=(const WASAPIDevice&) = delete;
protected:
virtual void playing(bool playing);
public:
/**
* Opens the WASAPI audio device for playback.

View File

@@ -737,7 +737,7 @@ void SoftwareDevice::mix(data_t* buffer, int length)
{
m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_specs));
std::lock_guard<std::recursive_mutex> lock(m_mutex);
std::lock_guard<ILockable> lock(*this);
{
std::shared_ptr<SoftwareDevice::SoftwareHandle> sound;
@@ -880,7 +880,7 @@ std::shared_ptr<IHandle> SoftwareDevice::play(std::shared_ptr<IReader> reader, b
// play sound
std::shared_ptr<SoftwareDevice::SoftwareHandle> sound = std::shared_ptr<SoftwareDevice::SoftwareHandle>(new SoftwareDevice::SoftwareHandle(this, reader, pitch, resampler, mapper, keep));
std::lock_guard<std::recursive_mutex> lock(m_mutex);
std::lock_guard<ILockable> lock(*this);
m_playingSounds.push_back(sound);
@@ -897,7 +897,7 @@ std::shared_ptr<IHandle> SoftwareDevice::play(std::shared_ptr<ISound> sound, boo
void SoftwareDevice::stopAll()
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
std::lock_guard<ILockable> lock(*this);
while(!m_playingSounds.empty())
m_playingSounds.front()->stop();

View File

@@ -0,0 +1,65 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "devices/ThreadedDevice.h"
#include <mutex>
AUD_NAMESPACE_BEGIN
void ThreadedDevice::start()
{
std::lock_guard<ILockable> lock(*this);
// thread is still running, we can abort stopping it
if(m_stop)
m_stop = false;
// thread is not running, let's start it
else if(!m_playing)
{
if(m_thread.joinable())
m_thread.join();
m_playing = true;
m_thread = std::thread(&ThreadedDevice::runMixingThread, this);
}
}
void ThreadedDevice::playing(bool playing)
{
if((!m_playing || m_stop) && playing)
start();
else
m_stop = true;
}
ThreadedDevice::ThreadedDevice() :
m_playing(false),
m_stop(false)
{
}
void aud::ThreadedDevice::stopMixingThread()
{
stopAll();
if(m_thread.joinable())
m_thread.join();
}
AUD_NAMESPACE_END

26
extern/smaa_areatex/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,26 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2017, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): IRIE Shinsuke
#
# ***** END GPL LICENSE BLOCK *****
add_executable(smaa_areatex smaa_areatex.cpp)

5
extern/smaa_areatex/README.blender vendored Normal file
View File

@@ -0,0 +1,5 @@
Project: smaa-cpp
URL: https://github.com/iRi-E/smaa-cpp
License: MIT
Upstream version: 0.4.0
Local modifications:

1208
extern/smaa_areatex/smaa_areatex.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@ BlenderImageLoader::BlenderImageLoader(BL::Image b_image, int frame)
{
}
bool BlenderImageLoader::load_metadata(ImageMetaData &metadata)
bool BlenderImageLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
{
metadata.width = b_image.size()[0];
metadata.height = b_image.size()[1];
@@ -171,7 +171,7 @@ BlenderPointDensityLoader::BlenderPointDensityLoader(BL::Depsgraph b_depsgraph,
{
}
bool BlenderPointDensityLoader::load_metadata(ImageMetaData &metadata)
bool BlenderPointDensityLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
{
metadata.channels = 4;
metadata.width = b_node.resolution();

View File

@@ -27,7 +27,7 @@ class BlenderImageLoader : public ImageLoader {
public:
BlenderImageLoader(BL::Image b_image, int frame);
bool load_metadata(ImageMetaData &metadata) override;
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
bool load_pixels(const ImageMetaData &metadata,
void *pixels,
const size_t pixels_size,
@@ -44,7 +44,7 @@ class BlenderPointDensityLoader : public ImageLoader {
public:
BlenderPointDensityLoader(BL::Depsgraph depsgraph, BL::ShaderNodeTexPointDensity b_node);
bool load_metadata(ImageMetaData &metadata) override;
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
bool load_pixels(const ImageMetaData &metadata,
void *pixels,
const size_t pixels_size,

View File

@@ -375,7 +375,7 @@ static void attr_create_generic(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool
case BL::Attribute::domain_POINT:
element = ATTR_ELEMENT_VERTEX;
break;
case BL::Attribute::domain_POLYGON:
case BL::Attribute::domain_FACE:
element = ATTR_ELEMENT_FACE;
break;
default:

View File

@@ -41,7 +41,7 @@ class BlenderSmokeLoader : public ImageLoader {
mesh_texture_space(b_mesh, texspace_loc, texspace_size);
}
bool load_metadata(ImageMetaData &metadata) override
bool load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata) override
{
if (!b_domain) {
return false;

View File

@@ -619,6 +619,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
info.num = 0;
info.has_half_images = true;
info.has_nanovdb = true;
info.has_volume_decoupled = true;
info.has_branched_path = true;
info.has_adaptive_stop_per_sample = true;
@@ -665,6 +666,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
/* Accumulate device info. */
info.has_half_images &= device.has_half_images;
info.has_nanovdb &= device.has_nanovdb;
info.has_volume_decoupled &= device.has_volume_decoupled;
info.has_branched_path &= device.has_branched_path;
info.has_adaptive_stop_per_sample &= device.has_adaptive_stop_per_sample;

View File

@@ -78,6 +78,7 @@ class DeviceInfo {
int num;
bool display_device; /* GPU is used as a display device. */
bool has_half_images; /* Support half-float textures. */
bool has_nanovdb; /* Support NanoVDB volumes. */
bool has_volume_decoupled; /* Decoupled volume shading. */
bool has_branched_path; /* Supports branched path tracing. */
bool has_adaptive_stop_per_sample; /* Per-sample adaptive sampling stopping. */
@@ -99,6 +100,7 @@ class DeviceInfo {
cpu_threads = 0;
display_device = false;
has_half_images = false;
has_nanovdb = false;
has_volume_decoupled = false;
has_branched_path = true;
has_adaptive_stop_per_sample = false;

View File

@@ -1654,6 +1654,7 @@ void device_cpu_info(vector<DeviceInfo> &devices)
info.has_adaptive_stop_per_sample = true;
info.has_osl = true;
info.has_half_images = true;
info.has_nanovdb = true;
info.has_profiling = true;
info.denoisers = DENOISER_NLM;
if (openimagedenoise_supported()) {

View File

@@ -128,6 +128,7 @@ void device_cuda_info(vector<DeviceInfo> &devices)
info.num = num;
info.has_half_images = (major >= 3);
info.has_nanovdb = true;
info.has_volume_decoupled = false;
info.has_adaptive_stop_per_sample = false;
info.denoisers = DENOISER_NLM;

View File

@@ -46,10 +46,13 @@ class MultiDevice : public Device {
list<SubDevice> devices, denoising_devices;
device_ptr unique_key;
vector<vector<SubDevice *>> peer_islands;
bool use_denoising;
bool matching_rendering_and_denoising_devices;
MultiDevice(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background_)
: Device(info, stats, profiler, background_), unique_key(1)
: Device(info, stats, profiler, background_),
unique_key(1),
use_denoising(!info.denoising_devices.empty())
{
foreach (DeviceInfo &subinfo, info.multi_devices) {
/* Always add CPU devices at the back since GPU devices can change
@@ -194,6 +197,7 @@ class MultiDevice : public Device {
if (!sub.device->load_kernels(requested_features))
return false;
use_denoising = requested_features.use_denoising;
if (requested_features.use_denoising) {
/* Only need denoising feature, everything else is unused. */
DeviceRequestedFeatures denoising_features;
@@ -400,7 +404,7 @@ class MultiDevice : public Device {
size_t existing_size = mem.device_size;
/* The tile buffers are allocated on each device (see below), so copy to all of them */
if (strcmp(mem.name, "RenderBuffers") == 0) {
if (strcmp(mem.name, "RenderBuffers") == 0 && use_denoising) {
foreach (SubDevice &sub, devices) {
mem.device = sub.device;
mem.device_pointer = (existing_key) ? sub.ptr_map[existing_key] : 0;
@@ -466,7 +470,7 @@ class MultiDevice : public Device {
/* This is a hack to only allocate the tile buffers on denoising devices
* Similarly the tile buffers also need to be allocated separately on all devices so any
* overlap rendered for denoising does not interfere with each other */
if (strcmp(mem.name, "RenderBuffers") == 0) {
if (strcmp(mem.name, "RenderBuffers") == 0 && use_denoising) {
vector<device_ptr> device_pointers;
device_pointers.reserve(devices.size());
@@ -518,7 +522,7 @@ class MultiDevice : public Device {
size_t existing_size = mem.device_size;
/* Free memory that was allocated for all devices (see above) on each device */
if (strcmp(mem.name, "RenderBuffers") == 0 || mem.type == MEM_PIXELS) {
if (mem.type == MEM_PIXELS || (strcmp(mem.name, "RenderBuffers") == 0 && use_denoising)) {
foreach (SubDevice &sub, devices) {
mem.device = sub.device;
mem.device_pointer = sub.ptr_map[key];

View File

@@ -126,6 +126,9 @@ void device_opencl_info(vector<DeviceInfo> &devices)
/* Check OpenCL extensions */
info.has_half_images = platform_device.device_extensions.find("cl_khr_fp16") != string::npos;
/* Disabled for now due to apparent AMD driver bug. */
info.has_nanovdb = platform_name != "AMD Accelerated Parallel Processing";
devices.push_back(info);
num_devices++;
}

View File

@@ -2036,7 +2036,9 @@ string OpenCLDevice::kernel_build_options(const string *debug_src)
# endif
# ifdef WITH_NANOVDB
build_options += "-DWITH_NANOVDB ";
if (info.has_nanovdb) {
build_options += "-DWITH_NANOVDB ";
}
# endif
return build_options;

View File

@@ -242,12 +242,15 @@ ccl_device float3 svm_math_blackbody_color(float t)
return make_float3(4.70366907f, 0.0f, 0.0f);
}
/* Manually align for readability. */
/* clang-format off */
int i = (t >= 6365.0f) ? 5 :
(t >= 3315.0f) ? 4 :
(t >= 1902.0f) ? 3 :
(t >= 1449.0f) ? 2 :
(t >= 1167.0f) ? 1 :
0;
/* clang-format on */
ccl_constant float *r = blackbody_table_r[i];
ccl_constant float *g = blackbody_table_g[i];

View File

@@ -130,6 +130,14 @@ void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
void Background::tag_update(Scene *scene)
{
Shader *bg_shader = get_shader(scene);
if (bg_shader && bg_shader->is_modified()) {
/* Tag as modified to update the KernelBackground visibility information.
* We only tag the use_shader socket as modified as it is related to the shader
* and to avoid doing unnecessary updates anywhere else. */
tag_use_shader_modified();
}
if (ao_factor_is_modified() || use_ao_is_modified()) {
scene->integrator->tag_update(scene, Integrator::BACKGROUND_AO_MODIFIED);
}

View File

@@ -1584,7 +1584,6 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
dscene->tri_vnormal.tag_realloc();
dscene->tri_vindex.tag_realloc();
dscene->tri_patch.tag_realloc();
dscene->tri_vnormal.tag_realloc();
dscene->tri_patch_uv.tag_realloc();
dscene->tri_shader.tag_realloc();
dscene->patches.tag_realloc();

View File

@@ -303,7 +303,8 @@ ImageManager::ImageManager(const DeviceInfo &info)
animation_frame = 0;
/* Set image limits */
has_half_images = info.has_half_images;
features.has_half_float = info.has_half_images;
features.has_nanovdb = info.has_nanovdb;
}
ImageManager::~ImageManager()
@@ -347,7 +348,7 @@ void ImageManager::load_image_metadata(Image *img)
metadata = ImageMetaData();
metadata.colorspace = img->params.colorspace;
if (img->loader->load_metadata(metadata)) {
if (img->loader->load_metadata(features, metadata)) {
assert(metadata.type != IMAGE_DATA_NUM_TYPES);
}
else {
@@ -356,15 +357,10 @@ void ImageManager::load_image_metadata(Image *img)
metadata.detect_colorspace();
/* No half textures on OpenCL, use full float instead. */
if (!has_half_images) {
if (metadata.type == IMAGE_DATA_TYPE_HALF4) {
metadata.type = IMAGE_DATA_TYPE_FLOAT4;
}
else if (metadata.type == IMAGE_DATA_TYPE_HALF) {
metadata.type = IMAGE_DATA_TYPE_FLOAT;
}
}
assert(features.has_half_float ||
(metadata.type != IMAGE_DATA_TYPE_HALF4 && metadata.type != IMAGE_DATA_TYPE_HALF));
assert(features.has_nanovdb || (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT ||
metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3));
img->need_metadata = false;
}

View File

@@ -97,6 +97,13 @@ class ImageMetaData {
void detect_colorspace();
};
/* Information about supported features that Image loaders can use. */
class ImageDeviceFeatures {
public:
bool has_half_float;
bool has_nanovdb;
};
/* Image loader base class, that can be subclassed to load image data
* from custom sources (file, memory, procedurally generated, etc). */
class ImageLoader {
@@ -105,7 +112,7 @@ class ImageLoader {
virtual ~ImageLoader(){};
/* Load metadata without actual image yet, should be fast. */
virtual bool load_metadata(ImageMetaData &metadata) = 0;
virtual bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) = 0;
/* Load actual image contents. */
virtual bool load_pixels(const ImageMetaData &metadata,
@@ -212,7 +219,8 @@ class ImageManager {
private:
bool need_update_;
bool has_half_images;
ImageDeviceFeatures features;
thread_mutex device_mutex;
thread_mutex images_mutex;

View File

@@ -30,7 +30,7 @@ OIIOImageLoader::~OIIOImageLoader()
{
}
bool OIIOImageLoader::load_metadata(ImageMetaData &metadata)
bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata)
{
/* Perform preliminary checks, with meaningful logging. */
if (!path_exists(filepath.string())) {
@@ -76,7 +76,7 @@ bool OIIOImageLoader::load_metadata(ImageMetaData &metadata)
}
/* check if it's half float */
if (spec.format == TypeDesc::HALF) {
if (spec.format == TypeDesc::HALF && features.has_half_float) {
is_half = true;
}

View File

@@ -26,7 +26,7 @@ class OIIOImageLoader : public ImageLoader {
OIIOImageLoader(const string &filepath);
~OIIOImageLoader();
bool load_metadata(ImageMetaData &metadata) override;
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
bool load_pixels(const ImageMetaData &metadata,
void *pixels,

View File

@@ -40,7 +40,7 @@ SkyLoader::SkyLoader(float sun_elevation,
SkyLoader::~SkyLoader(){};
bool SkyLoader::load_metadata(ImageMetaData &metadata)
bool SkyLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
{
metadata.width = 512;
metadata.height = 128;

View File

@@ -34,7 +34,7 @@ class SkyLoader : public ImageLoader {
float ozone_density);
~SkyLoader();
bool load_metadata(ImageMetaData &metadata) override;
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
bool load_pixels(const ImageMetaData &metadata,
void *pixels,

View File

@@ -34,7 +34,7 @@ VDBImageLoader::~VDBImageLoader()
{
}
bool VDBImageLoader::load_metadata(ImageMetaData &metadata)
bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata)
{
#ifdef WITH_OPENVDB
if (!grid) {
@@ -56,55 +56,71 @@ bool VDBImageLoader::load_metadata(ImageMetaData &metadata)
if (grid->isType<openvdb::FloatGrid>()) {
metadata.channels = 1;
# ifdef WITH_NANOVDB
nanogrid = nanovdb::openToNanoVDB(*openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid));
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(*openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid));
}
# endif
}
else if (grid->isType<openvdb::Vec3fGrid>()) {
metadata.channels = 3;
# ifdef WITH_NANOVDB
nanogrid = nanovdb::openToNanoVDB(*openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid));
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(*openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid));
}
# endif
}
else if (grid->isType<openvdb::BoolGrid>()) {
metadata.channels = 1;
# ifdef WITH_NANOVDB
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::BoolGrid>(grid)));
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::BoolGrid>(grid)));
}
# endif
}
else if (grid->isType<openvdb::DoubleGrid>()) {
metadata.channels = 1;
# ifdef WITH_NANOVDB
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::DoubleGrid>(grid)));
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::DoubleGrid>(grid)));
}
# endif
}
else if (grid->isType<openvdb::Int32Grid>()) {
metadata.channels = 1;
# ifdef WITH_NANOVDB
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::Int32Grid>(grid)));
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::Int32Grid>(grid)));
}
# endif
}
else if (grid->isType<openvdb::Int64Grid>()) {
metadata.channels = 1;
# ifdef WITH_NANOVDB
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::Int64Grid>(grid)));
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::Int64Grid>(grid)));
}
# endif
}
else if (grid->isType<openvdb::Vec3IGrid>()) {
metadata.channels = 3;
# ifdef WITH_NANOVDB
nanogrid = nanovdb::openToNanoVDB(
openvdb::Vec3fGrid(*openvdb::gridConstPtrCast<openvdb::Vec3IGrid>(grid)));
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(
openvdb::Vec3fGrid(*openvdb::gridConstPtrCast<openvdb::Vec3IGrid>(grid)));
}
# endif
}
else if (grid->isType<openvdb::Vec3dGrid>()) {
metadata.channels = 3;
# ifdef WITH_NANOVDB
nanogrid = nanovdb::openToNanoVDB(
openvdb::Vec3fGrid(*openvdb::gridConstPtrCast<openvdb::Vec3dGrid>(grid)));
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(
openvdb::Vec3fGrid(*openvdb::gridConstPtrCast<openvdb::Vec3dGrid>(grid)));
}
# endif
}
else if (grid->isType<openvdb::MaskGrid>()) {
@@ -118,21 +134,25 @@ bool VDBImageLoader::load_metadata(ImageMetaData &metadata)
}
# ifdef WITH_NANOVDB
metadata.byte_size = nanogrid.size();
if (metadata.channels == 1) {
metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT;
}
else {
metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT3;
}
# else
if (metadata.channels == 1) {
metadata.type = IMAGE_DATA_TYPE_FLOAT;
}
else {
metadata.type = IMAGE_DATA_TYPE_FLOAT4;
if (nanogrid) {
metadata.byte_size = nanogrid.size();
if (metadata.channels == 1) {
metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT;
}
else {
metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT3;
}
}
else
# endif
{
if (metadata.channels == 1) {
metadata.type = IMAGE_DATA_TYPE_FLOAT;
}
else {
metadata.type = IMAGE_DATA_TYPE_FLOAT4;
}
}
/* Set transform from object space to voxel index. */
openvdb::math::Mat4f grid_matrix = grid->transform().baseMap()->getAffineMap()->getMat4();
@@ -143,13 +163,18 @@ bool VDBImageLoader::load_metadata(ImageMetaData &metadata)
}
}
Transform texture_to_index;
# ifdef WITH_NANOVDB
Transform texture_to_index = transform_identity();
# else
openvdb::Coord min = bbox.min();
Transform texture_to_index = transform_translate(min.x(), min.y(), min.z()) *
transform_scale(dim.x(), dim.y(), dim.z());
if (nanogrid) {
texture_to_index = transform_identity();
}
else
# endif
{
openvdb::Coord min = bbox.min();
texture_to_index = transform_translate(min.x(), min.y(), min.z()) *
transform_scale(dim.x(), dim.y(), dim.z());
}
metadata.transform_3d = transform_inverse(index_to_object * texture_to_index);
metadata.use_transform_3d = true;
@@ -165,48 +190,52 @@ bool VDBImageLoader::load_pixels(const ImageMetaData &, void *pixels, const size
{
#ifdef WITH_OPENVDB
# ifdef WITH_NANOVDB
memcpy(pixels, nanogrid.data(), nanogrid.size());
# else
if (grid->isType<openvdb::FloatGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid), dense);
}
else if (grid->isType<openvdb::Vec3fGrid>()) {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid), dense);
}
else if (grid->isType<openvdb::BoolGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::BoolGrid>(grid), dense);
}
else if (grid->isType<openvdb::DoubleGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::DoubleGrid>(grid), dense);
}
else if (grid->isType<openvdb::Int32Grid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Int32Grid>(grid), dense);
}
else if (grid->isType<openvdb::Int64Grid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Int64Grid>(grid), dense);
}
else if (grid->isType<openvdb::Vec3IGrid>()) {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3IGrid>(grid), dense);
}
else if (grid->isType<openvdb::Vec3dGrid>()) {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3dGrid>(grid), dense);
}
else if (grid->isType<openvdb::MaskGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::MaskGrid>(grid), dense);
if (nanogrid) {
memcpy(pixels, nanogrid.data(), nanogrid.size());
}
else
# endif
{
if (grid->isType<openvdb::FloatGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid), dense);
}
else if (grid->isType<openvdb::Vec3fGrid>()) {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid), dense);
}
else if (grid->isType<openvdb::BoolGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::BoolGrid>(grid), dense);
}
else if (grid->isType<openvdb::DoubleGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::DoubleGrid>(grid), dense);
}
else if (grid->isType<openvdb::Int32Grid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Int32Grid>(grid), dense);
}
else if (grid->isType<openvdb::Int64Grid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Int64Grid>(grid), dense);
}
else if (grid->isType<openvdb::Vec3IGrid>()) {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3IGrid>(grid), dense);
}
else if (grid->isType<openvdb::Vec3dGrid>()) {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3dGrid>(grid), dense);
}
else if (grid->isType<openvdb::MaskGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::MaskGrid>(grid), dense);
}
}
return true;
#else
(void)pixels;

View File

@@ -33,7 +33,8 @@ class VDBImageLoader : public ImageLoader {
VDBImageLoader(const string &grid_name);
~VDBImageLoader();
virtual bool load_metadata(ImageMetaData &metadata) override;
virtual bool load_metadata(const ImageDeviceFeatures &features,
ImageMetaData &metadata) override;
virtual bool load_pixels(const ImageMetaData &metadata,
void *pixels,

View File

@@ -153,10 +153,6 @@ void Object::update_motion()
void Object::compute_bounds(bool motion_blur)
{
if (!is_modified() && !geometry->is_modified()) {
return;
}
BoundBox mbounds = geometry->bounds;
if (motion_blur && use_motion()) {

View File

@@ -24,7 +24,8 @@
#pragma once
/*
/**
* \code{.py}
* import bpy
* import textwrap
*
@@ -42,6 +43,7 @@
* print("%d,%d," % (w, h))
* text = ", ".join(["0x%x" % p for p in pixels])
* print(textwrap.fill(text, width=120), end=",\n")
* \endcode
*/
/**

View File

@@ -533,11 +533,18 @@ GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
wp.showCmd = SW_SHOWMAXIMIZED;
wp.ptMaxPosition.x = 0;
wp.ptMaxPosition.y = 0;
style &= ~WS_CAPTION;
style &= ~(WS_CAPTION | WS_MAXIMIZE);
break;
case GHOST_kWindowStateNormal:
default:
wp.showCmd = SW_SHOWNORMAL;
if (curstate == GHOST_kWindowStateFullScreen &&
m_normal_state == GHOST_kWindowStateMaximized) {
wp.showCmd = SW_SHOWMAXIMIZED;
m_normal_state = GHOST_kWindowStateNormal;
}
else {
wp.showCmd = SW_SHOWNORMAL;
}
break;
}
::SetWindowLongPtr(m_hWnd, GWL_STYLE, style);

View File

@@ -349,6 +349,10 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
# 1) try import
try:
mod = __import__(module_name)
if mod.__file__ is None:
# This can happen when the addon has been removed but there are
# residual `.pyc` files left behind.
raise ImportError(name=module_name)
mod.__time__ = os.path.getmtime(mod.__file__)
mod.__addon_enabled__ = False
except Exception as ex:

View File

@@ -32,12 +32,6 @@ import bpy
IS_TESTING = False
def drepr(string):
# is there a less crappy way to do this in python?, re.escape also escapes
# single quotes strings so can't use it.
return '"%s"' % repr(string)[1:-1].replace("\"", "\\\"").replace("\\'", "'")
def classes_recursive(base_type, clss=None):
if clss is None:
clss = [base_type]
@@ -66,7 +60,7 @@ class DataPathBuilder:
if type(key) is int:
str_value = '[%d]' % key
elif type(key) is str:
str_value = '[%s]' % drepr(key)
str_value = '["%s"]' % bpy.utils.escape_identifier(key)
else:
raise Exception("unsupported accessor %r of type %r (internal error)" % (key, type(key)))
return DataPathBuilder(self.data_path + (str_value, ))

View File

@@ -0,0 +1,91 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
__all__ = (
"property_definition_from_data_path",
"decompose_data_path",
)
class _TokenizeDataPath:
"""
Class to split up tokens of a data-path.
Note that almost all access generates new objects with additional paths,
with the exception of iteration which is the intended way to access the resulting data."""
__slots__ = (
"data_path",
)
def __init__(self, attrs):
self.data_path = attrs
def __getattr__(self, attr):
return _TokenizeDataPath(self.data_path + ((".%s" % attr),))
def __getitem__(self, key):
return _TokenizeDataPath(self.data_path + (("[%r]" % (key,)),))
def __call__(self, *args, **kw):
value_str = ", ".join([
val for val in (
", ".join(repr(value) for value in args),
", ".join(["%s=%r" % (key, value) for key, value in kw.items()]),
) if val])
return _TokenizeDataPath(self.data_path + ('(%s)' % value_str, ))
def __iter__(self):
return iter(self.data_path)
def decompose_data_path(data_path):
"""
Return the components of a data path split into a list.
"""
ns = {"base": _TokenizeDataPath(())}
return list(eval("base" + data_path, ns, ns))
def property_definition_from_data_path(base, data_path):
"""
Return an RNA property definition from an object and a data path.
In Blender this is often used with ``context`` as the base and a
path that it references, for example ``.space_data.lock_camera``.
"""
data = decompose_data_path(data_path)
while data and (not data[-1].startswith(".")):
data.pop()
if (not data) or (not data[-1].startswith(".")) or (len(data) < 2):
return None
data_path_head = "".join(data[:-1])
data_path_tail = data[-1]
value_head = eval("base" + data_path_head)
value_head_rna = getattr(value_head, "bl_rna", None)
if value_head_rna is None:
return None
value_tail = value_head.bl_rna.properties.get(data_path_tail[1:])
if not value_tail:
return None
return value_tail

View File

@@ -1694,6 +1694,7 @@ def km_image(params):
("image.view_all", {"type": 'HOME', "value": 'PRESS', "shift": True},
{"properties": [("fit_view", True)]}),
("image.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
("image.view_cursor_center", {"type": 'C', "value": 'PRESS', "shift": True}, None),
("image.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None),
("image.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True}, None),
("image.view_pan", {"type": 'TRACKPADPAN', "value": 'ANY'}, None),
@@ -1830,6 +1831,7 @@ def km_node_editor(params):
])
items.extend([
("node.follow_portal", {"type": 'TAB', "value": 'PRESS'}, None),
("node.select_box", {"type": params.select_tweak, "value": 'ANY'},
{"properties": [("tweak", True)]}),
("node.select_lasso", {"type": 'EVT_TWEAK_L', "value": 'ANY', "ctrl": True, "alt": True},

View File

@@ -355,7 +355,8 @@ class UpdateAnimatedTransformConstraint(Operator):
use_convert_to_radians: BoolProperty(
name="Convert to Radians",
description="Convert fcurves/drivers affecting rotations to radians (Warning: use this only once!)",
description="Convert f-curves/drivers affecting rotations to radians.\n"
"Warning: Use this only once",
default=True,
)
@@ -430,22 +431,9 @@ class UpdateAnimatedTransformConstraint(Operator):
return {'FINISHED'}
class ANIM_OT_show_group_colors_deprecated(Operator):
"""This option moved to Preferences > Animation"""
bl_idname = "anim.show_group_colors_deprecated"
bl_label = "Show Group Colors"
bl_options = {'REGISTER'}
@classmethod
def poll(cls, _context):
return False
classes = (
ANIM_OT_keying_set_export,
NLA_OT_bake,
ClearUselessActions,
UpdateAnimatedTransformConstraint,
ANIM_OT_show_group_colors_deprecated,
)

View File

@@ -21,6 +21,7 @@ from __future__ import annotations
import bpy
import nodeitems_utils
from mathutils import Vector
from bpy.types import (
Operator,
PropertyGroup,
@@ -303,6 +304,187 @@ class NODE_OT_tree_path_parent(Operator):
return {'FINISHED'}
class NODE_OT_follow_portal(Operator):
'''Follow portal'''
bl_idname = "node.follow_portal"
bl_label = "Follow Portal"
@classmethod
def poll(cls, context):
space = context.space_data
return (space.type == 'NODE_EDITOR'
and space.node_tree
and space.node_tree.nodes.active.bl_idname in ('NodePortalIn', 'NodePortalOut'))
def execute(self, context):
space = context.space_data
ntree = space.node_tree
old_active_node = ntree.nodes.active
portal_id = old_active_node.portal_id
if old_active_node.bl_idname == 'NodePortalIn':
out_nodes = [n for n in ntree.nodes if n.bl_idname == 'NodePortalOut' and n.portal_id == portal_id]
if len(out_nodes) != 1:
return {'CANCELLED'}
out_node = out_nodes[0]
for node in ntree.nodes:
node.select = False
out_node.select = True
ntree.nodes.active = out_node
if old_active_node.bl_idname == 'NodePortalOut':
in_nodes = [n for n in ntree.nodes if n.bl_idname == 'NodePortalIn' and n.portal_id == portal_id]
if len(in_nodes) != 1:
return {'CANCELLED'}
in_node = in_nodes[0]
for node in ntree.nodes:
node.select = False
in_node.select = True
ntree.nodes.active = in_node
bpy.ops.node.view_selected()
return {'FINISHED'}
PAGE_SIZE = 20000
def get_page_center(page):
return Vector(((page - 1) * PAGE_SIZE, 0))
def position_is_on_page(pos, page):
page_center = get_page_center(page)
return (abs(page_center.x - pos[0]) < PAGE_SIZE / 2
and abs(page_center.y - pos[1]) < PAGE_SIZE / 2)
def node_is_on_page(node, page):
return position_is_on_page(node.location, page)
def get_nodes_on_page(ntree, page):
return [n for n in ntree.nodes if node_is_on_page(n, page)]
def get_current_page(context):
for region in context.area.regions:
if region.type != 'WINDOW':
continue
pos = region.view2d.region_to_view(0, 0)
for page in range(10):
if position_is_on_page(pos, page):
return page
return None
class NODE_OT_view_page(Operator):
'''View page'''
bl_idname = "node.view_page"
bl_label = "View Page"
page: bpy.props.IntProperty(default=0)
@classmethod
def poll(cls, context):
space = context.space_data
return space.type == 'NODE_EDITOR'
def invoke(self, context, event):
if event.ctrl:
bpy.ops.node.move_to_page('INVOKE_DEFAULT', page=self.page)
return {'FINISHED'}
return self.execute(context)
def execute(self, context):
space = context.space_data
ntree = space.node_tree
for node in ntree.nodes:
node.select = False
nodes_on_page = get_nodes_on_page(ntree, self.page)
if len(nodes_on_page) > 0:
for node in nodes_on_page:
node.select = True
bpy.ops.node.view_selected()
for node in nodes_on_page:
node.select = False
ntree.nodes.active = None
else:
page_center = get_page_center(self.page)
new_node = ntree.nodes.new('NodeReroute')
new_node.select = True
new_node.location = page_center
context_copy = context.copy()
def update_after_draw():
bpy.ops.node.view_selected(context_copy)
ntree.nodes.remove(new_node)
bpy.app.timers.register(update_after_draw, first_interval=0.01)
return {'FINISHED'}
class NODE_OT_move_to_page(Operator):
'''Move to page'''
bl_idname = "node.move_to_page"
bl_label = "Move to Page"
page: IntProperty()
@classmethod
def poll(cls, context):
space = context.space_data
return space.type == 'NODE_EDITOR'
def execute(self, context):
ntree = context.space_data.node_tree
nodes_to_move = [n for n in ntree.nodes if n.select]
if len(nodes_to_move) == 0:
return {'CANCELLED'}
old_center = sum((n.location for n in nodes_to_move), Vector((0, 0))) / len(nodes_to_move)
new_center = get_page_center(self.page)
offset = new_center - old_center
view2d = context.region.view2d
old_center_region = Vector(view2d.view_to_region(old_center.x, old_center.y, clip=False))
new_center_region = Vector(view2d.view_to_region(new_center.x, new_center.y, clip=False))
offset_region = new_center_region - old_center_region
for node in nodes_to_move:
node.location += offset
bpy.ops.view2d.pan(deltax=offset_region.x, deltay=offset_region.y)
return {'FINISHED'}
class NODE_OT_add_portal(Operator):
'''Add portal'''
bl_idname = "node.add_portal"
bl_label = "Add Portal"
@classmethod
def poll(cls, context):
if context.space_data.type != 'NODE_EDITOR':
return False
ntree = context.space_data.node_tree
if ntree is None:
return False
return True
def invoke(self, context, event):
ntree = context.space_data.node_tree
bpy.ops.node.add_and_link_node(type="NodePortalIn")
portal_in = ntree.nodes[-1]
bpy.ops.node.add_and_link_node(type="NodePortalOut")
portal_out = ntree.nodes[-1]
portal_in.location.x -= 200
portal_out.location.x += 60
for node in ntree.nodes:
node.select = False
portal_in.select = True
portal_out.select = True
portal_out.portal_id = portal_in.portal_id
bpy.ops.node.translate_attach("INVOKE_DEFAULT")
return {'FINISHED'}
classes = (
NodeSetting,
@@ -311,4 +493,8 @@ classes = (
NODE_OT_add_search,
NODE_OT_collapse_hide_unused_toggle,
NODE_OT_tree_path_parent,
NODE_OT_follow_portal,
NODE_OT_view_page,
NODE_OT_add_portal,
NODE_OT_move_to_page,
)

View File

@@ -95,6 +95,76 @@ def context_path_validate(context, data_path):
return value
def context_path_to_rna_property(context, data_path):
from bl_rna_utils.data_path import property_definition_from_data_path
rna_prop = property_definition_from_data_path(context, "." + data_path)
if rna_prop is not None:
return rna_prop
return None
def context_path_decompose(data_path):
# Decompose a data_path into 3 components:
# base_path, prop_attr, prop_item, where:
# `"foo.bar["baz"].fiz().bob.buz[10][2]"`, returns...
# `("foo.bar["baz"].fiz().bob", "buz", "[10][2]")`
#
# This is useful as we often want the base and the property, ignoring any item access.
# Note that item access includes function calls since these aren't properties.
#
# Note that the `.` is removed from the start of the first and second values,
# this is done because `.attr` isn't convenient to use as an argument,
# also the convention is not to include this within the data paths or the operator logic for `bpy.ops.wm.*`.
from bl_rna_utils.data_path import decompose_data_path
path_split = decompose_data_path("." + data_path)
# Find the last property that isn't a function call.
value_prev = ""
i = len(path_split)
while (i := i - 1) >= 0:
value = path_split[i]
if value.startswith("."):
if not value_prev.startswith("("):
break
value_prev = value
if i != -1:
base_path = "".join(path_split[:i])
prop_attr = path_split[i]
prop_item = "".join(path_split[i + 1:])
if base_path:
assert(base_path.startswith("."))
base_path= base_path[1:]
if prop_attr:
assert(prop_attr.startswith("."))
prop_attr = prop_attr[1:]
else:
# If there are no properties, everything is an item.
# Note that should not happen in practice with values which are added onto `context`,
# include since it's correct to account for this case and not doing so will create a confusing exception.
base_path = ""
prop_attr = ""
prop_item = "".join(path_split)
return (base_path, prop_attr, prop_item)
def description_from_data_path(base, data_path, *, prefix, value=Ellipsis):
if context_path_validate(base, data_path) is Ellipsis:
return None
if (
(rna_prop := context_path_to_rna_property(base, data_path)) and
(description := rna_prop.description)
):
description = "%s: %s" % (prefix, description)
if value != Ellipsis:
description = "%s\n%s: %s" % (description, iface_("Value"), str(value))
return description
return None
def operator_value_is_undo(value):
if value in {None, Ellipsis}:
return False
@@ -120,12 +190,9 @@ def operator_value_is_undo(value):
def operator_path_is_undo(context, data_path):
# note that if we have data paths that use strings this could fail
# luckily we don't do this!
#
# When we can't find the data owner assume no undo is needed.
data_path_head = data_path.rpartition(".")[0]
data_path_head, _, _ = context_path_decompose(data_path)
# When we can't find the data owner assume no undo is needed.
if not data_path_head:
return False
@@ -168,6 +235,10 @@ class WM_OT_context_set_boolean(Operator):
default=True,
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
execute = execute_context_assign
@@ -185,6 +256,10 @@ class WM_OT_context_set_int(Operator): # same as enum
)
relative: rna_relative_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix="Assign", value=props.value)
execute = execute_context_assign
@@ -201,6 +276,10 @@ class WM_OT_context_scale_float(Operator):
default=1.0,
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Scale"), value=props.value)
def execute(self, context):
data_path = self.data_path
if context_path_validate(context, data_path) is Ellipsis:
@@ -235,6 +314,10 @@ class WM_OT_context_scale_int(Operator):
options={'SKIP_SAVE'},
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Scale"), value=props.value)
def execute(self, context):
data_path = self.data_path
if context_path_validate(context, data_path) is Ellipsis:
@@ -274,6 +357,10 @@ class WM_OT_context_set_float(Operator): # same as enum
)
relative: rna_relative_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix="Assign", value=props.value)
execute = execute_context_assign
@@ -290,6 +377,10 @@ class WM_OT_context_set_string(Operator): # same as enum
maxlen=1024,
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
execute = execute_context_assign
@@ -306,6 +397,10 @@ class WM_OT_context_set_enum(Operator):
maxlen=1024,
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
execute = execute_context_assign
@@ -322,6 +417,10 @@ class WM_OT_context_set_value(Operator):
maxlen=1024,
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
def execute(self, context):
data_path = self.data_path
if context_path_validate(context, data_path) is Ellipsis:
@@ -339,6 +438,13 @@ class WM_OT_context_toggle(Operator):
data_path: rna_path_prop
module: rna_module_prop
@classmethod
def description(cls, context, props):
# Currently unsupported, it might be possible to extract this.
if props.module:
return None
return description_from_data_path(context, props.data_path, prefix=iface_("Toggle"))
def execute(self, context):
data_path = self.data_path
@@ -375,6 +481,11 @@ class WM_OT_context_toggle_enum(Operator):
maxlen=1024,
)
@classmethod
def description(cls, context, props):
value = "(%r, %r)" % (props.value_1, props.value_2)
return description_from_data_path(context, props.data_path, prefix=iface_("Toggle"), value=value)
def execute(self, context):
data_path = self.data_path
@@ -406,6 +517,10 @@ class WM_OT_context_cycle_int(Operator):
reverse: rna_reverse_prop
wrap: rna_wrap_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Cycle"))
def execute(self, context):
data_path = self.data_path
value = context_path_validate(context, data_path)
@@ -442,6 +557,10 @@ class WM_OT_context_cycle_enum(Operator):
reverse: rna_reverse_prop
wrap: rna_wrap_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Cycle"))
def execute(self, context):
data_path = self.data_path
value = context_path_validate(context, data_path)
@@ -450,22 +569,11 @@ class WM_OT_context_cycle_enum(Operator):
orig_value = value
# Have to get rna enum values
rna_struct_str, rna_prop_str = data_path.rsplit('.', 1)
i = rna_prop_str.find('[')
# just in case we get "context.foo.bar[0]"
if i != -1:
rna_prop_str = rna_prop_str[0:i]
rna_struct = eval("context.%s.rna_type" % rna_struct_str)
rna_prop = rna_struct.properties[rna_prop_str]
rna_prop = context_path_to_rna_property(context, data_path)
if type(rna_prop) != bpy.types.EnumProperty:
raise Exception("expected an enum property")
enums = rna_struct.properties[rna_prop_str].enum_items.keys()
enums = rna_prop.enum_items.keys()
orig_index = enums.index(orig_value)
# Have the info we need, advance to the next item.
@@ -498,6 +606,10 @@ class WM_OT_context_cycle_array(Operator):
data_path: rna_path_prop
reverse: rna_reverse_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Cycle"))
def execute(self, context):
data_path = self.data_path
value = context_path_validate(context, data_path)
@@ -523,6 +635,10 @@ class WM_OT_context_menu_enum(Operator):
data_path: rna_path_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Menu"))
def execute(self, context):
data_path = self.data_path
value = context_path_validate(context, data_path)
@@ -530,15 +646,15 @@ class WM_OT_context_menu_enum(Operator):
if value is Ellipsis:
return {'PASS_THROUGH'}
base_path, prop_string = data_path.rsplit(".", 1)
base_path, prop_attr, _ = context_path_decompose(data_path)
value_base = context_path_validate(context, base_path)
prop = value_base.bl_rna.properties[prop_string]
rna_prop = context_path_to_rna_property(context, data_path)
def draw_cb(self, context):
layout = self.layout
layout.prop(value_base, prop_string, expand=True)
layout.prop(value_base, prop_attr, expand=True)
context.window_manager.popup_menu(draw_func=draw_cb, title=prop.name, icon=prop.icon)
context.window_manager.popup_menu(draw_func=draw_cb, title=rna_prop.name, icon=rna_prop.icon)
return {'FINISHED'}
@@ -550,6 +666,10 @@ class WM_OT_context_pie_enum(Operator):
data_path: rna_path_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Pie Menu"))
def invoke(self, context, event):
wm = context.window_manager
data_path = self.data_path
@@ -558,15 +678,15 @@ class WM_OT_context_pie_enum(Operator):
if value is Ellipsis:
return {'PASS_THROUGH'}
base_path, prop_string = data_path.rsplit(".", 1)
base_path, prop_attr, _ = context_path_decompose(data_path)
value_base = context_path_validate(context, base_path)
prop = value_base.bl_rna.properties[prop_string]
rna_prop = context_path_to_rna_property(context, data_path)
def draw_cb(self, context):
layout = self.layout
layout.prop(value_base, prop_string, expand=True)
layout.prop(value_base, prop_attr, expand=True)
wm.popup_menu_pie(draw_func=draw_cb, title=prop.name, icon=prop.icon, event=event)
wm.popup_menu_pie(draw_func=draw_cb, title=rna_prop.name, icon=rna_prop.icon, event=event)
return {'FINISHED'}
@@ -587,11 +707,15 @@ class WM_OT_operator_pie_enum(Operator):
maxlen=1024,
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Pie Menu"))
def invoke(self, context, event):
wm = context.window_manager
data_path = self.data_path
prop_string = self.prop_string
prop_attr = self.prop_string
# same as eval("bpy.ops." + data_path)
op_mod_str, ob_id_str = data_path.split(".", 1)
@@ -607,7 +731,7 @@ class WM_OT_operator_pie_enum(Operator):
def draw_cb(self, context):
layout = self.layout
pie = layout.menu_pie()
pie.operator_enum(data_path, prop_string)
pie.operator_enum(data_path, prop_attr)
wm.popup_menu_pie(draw_func=draw_cb, title=op_rna.name, event=event)
@@ -631,17 +755,17 @@ class WM_OT_context_set_id(Operator):
value = self.value
data_path = self.data_path
# match the pointer type from the target property to bpy.data.*
# Match the pointer type from the target property to `bpy.data.*`
# so we lookup the correct list.
data_path_base, data_path_prop = data_path.rsplit(".", 1)
data_prop_rna = eval("context.%s" % data_path_base).rna_type.properties[data_path_prop]
data_prop_rna_type = data_prop_rna.fixed_type
rna_prop = context_path_to_rna_property(context, data_path)
rna_prop_fixed_type = rna_prop.fixed_type
id_iter = None
for prop in bpy.data.rna_type.properties:
if prop.rna_type.identifier == "CollectionProperty":
if prop.fixed_type == data_prop_rna_type:
if prop.fixed_type == rna_prop_fixed_type:
id_iter = prop.identifier
break

View File

@@ -77,6 +77,7 @@ class COLLECTION_PT_instancing(CollectionButtonsPanel, Panel):
class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel):
bl_label = "Line Art"
bl_order = 10
def draw(self, context):
layout = self.layout

View File

@@ -86,12 +86,19 @@ class DATA_PT_display(ArmatureButtonsPanel, Panel):
col = layout.column(heading="Show")
col.prop(arm, "show_names", text="Names")
col.prop(arm, "show_axes", text="Axes")
col.prop(arm, "show_bone_custom_shapes", text="Shapes")
col.prop(arm, "show_group_colors", text="Group Colors")
if ob:
col.prop(ob, "show_in_front", text="In Front")
col = layout.column(align=False, heading="Axes")
row = col.row(align=True)
row.prop(arm, "show_axes", text="")
sub = row.row(align=True)
sub.active = arm.show_axes
sub.prop(arm, "axes_position", text="Position")
class DATA_MT_bone_group_context_menu(Menu):
bl_label = "Bone Group Specials"

View File

@@ -277,6 +277,7 @@ class MATERIAL_PT_viewport(MaterialButtonsPanel, Panel):
class MATERIAL_PT_lineart(MaterialButtonsPanel, Panel):
bl_label = "Line Art"
bl_options = {'DEFAULT_CLOSED'}
bl_order = 10
@classmethod
def poll(cls, context):

View File

@@ -311,6 +311,7 @@ class OBJECT_PT_instancing_size(ObjectButtonsPanel, Panel):
class OBJECT_PT_lineart(ObjectButtonsPanel, Panel):
bl_label = "Line Art"
bl_options = {'DEFAULT_CLOSED'}
bl_order = 10
@classmethod
def poll(cls, context):

View File

@@ -74,10 +74,6 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
row = layout.row(align=True)
row.alignment = 'LEFT'
row.label(text="Enable physics for:")
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
obj = context.object

View File

@@ -348,8 +348,6 @@ class DOPESHEET_MT_view(Menu):
col.active = context.space_data.mode != 'SHAPEKEY'
col.prop(st, "show_sliders")
if bpy.app.version < (2, 93):
layout.operator("anim.show_group_colors_deprecated", icon='CHECKBOX_HLT')
layout.prop(st, "show_interpolation")
layout.prop(st, "show_extremes")
layout.prop(st, "use_auto_merge_keyframes")

View File

@@ -18,7 +18,6 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bl_ui.space_dopesheet import (
DopesheetFilterPopoverBase,
@@ -120,10 +119,6 @@ class GRAPH_MT_view(Menu):
layout.prop(st, "use_realtime_update")
layout.prop(st, "show_cursor")
layout.prop(st, "show_sliders")
if bpy.app.version < (2, 93):
layout.operator("anim.show_group_colors_deprecated", icon='CHECKBOX_HLT')
layout.prop(st, "use_auto_merge_keyframes")
if st.mode != 'DRIVERS':

View File

@@ -171,6 +171,16 @@ class NODE_HT_header(Header):
else:
row.template_ID(snode, "node_tree", new="node.new_geometry_nodes_modifier")
import bl_operators.node as node_module
current_page = node_module.get_current_page(context)
row = layout.row(align=True)
for page in range(1, 6):
subrow = row.row(align=True)
subrow.enabled = page != current_page
props = subrow.operator("node.view_page", text=str(page))
props.page = page
else:
# Custom node tree is edited as independent ID block
NODE_MT_editor_menus.draw_collapsible(context, layout)
@@ -238,6 +248,8 @@ class NODE_MT_add(bpy.types.Menu):
# actual node submenus are defined by draw functions from node categories
nodeitems_utils.draw_node_categories_menu(self, context)
layout.operator("node.add_portal")
class NODE_MT_view(Menu):
bl_label = "View"
@@ -481,7 +493,7 @@ class NODE_MT_context_menu(Menu):
class NODE_PT_active_node_generic(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Item"
bl_category = "Node"
bl_label = "Node"
@classmethod
@@ -499,7 +511,7 @@ class NODE_PT_active_node_generic(Panel):
class NODE_PT_active_node_color(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Item"
bl_category = "Node"
bl_label = "Color"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = 'NODE_PT_active_node_generic'
@@ -529,7 +541,7 @@ class NODE_PT_active_node_color(Panel):
class NODE_PT_active_node_properties(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Item"
bl_category = "Node"
bl_label = "Properties"
bl_options = {'DEFAULT_CLOSED'}
@@ -570,7 +582,7 @@ class NODE_PT_active_node_properties(Panel):
class NODE_PT_texture_mapping(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Item"
bl_category = "Node"
bl_label = "Texture Mapping"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}

View File

@@ -2244,6 +2244,7 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
({"property": "use_switch_object_operator"}, "T80402"),
({"property": "use_sculpt_tools_tilt"}, "T82877"),
({"property": "use_asset_browser"}, ("project/profile/124/", "Milestone 1")),
({"property": "use_override_templates"}, ("T73318", "Milestone 4")),
),
)

View File

@@ -622,9 +622,15 @@ class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel):
@classmethod
def poll(cls, context):
settings = cls.paint_settings(context)
return (settings and settings.brush and
(context.sculpt_object or context.image_paint_object or context.vertex_paint_object))
if (
(settings := cls.paint_settings(context)) and
(brush := settings.brush)
):
if context.sculpt_object or context.vertex_paint_object:
return True
elif context.image_paint_object:
return (brush.image_tool == 'DRAW')
return False
def draw(self, context):
layout = self.layout

View File

@@ -368,6 +368,7 @@ compositor_node_categories = [
NodeItem("CompositorNodePixelate"),
NodeItem("CompositorNodeSunBeams"),
NodeItem("CompositorNodeDenoise"),
NodeItem("CompositorNodeAntiAliasing"),
]),
CompositorNodeCategory("CMP_OP_VECTOR", "Vector", items=[
NodeItem("CompositorNodeNormal"),
@@ -484,6 +485,7 @@ geometry_node_categories = [
GeometryNodeCategory("GEO_ATTRIBUTE", "Attribute", items=[
NodeItem("GeometryNodeAttributeRandomize"),
NodeItem("GeometryNodeAttributeMath"),
NodeItem("GeometryNodeAttributeClamp"),
NodeItem("GeometryNodeAttributeCompare"),
NodeItem("GeometryNodeAttributeConvert"),
NodeItem("GeometryNodeAttributeFill"),
@@ -495,7 +497,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeCombineXYZ"),
NodeItem("GeometryNodeAttributeSeparateXYZ"),
NodeItem("GeometryNodeAttributeRemove"),
NodeItem("FunctionNodeGroup"),
NodeItem("GeometryNodeAttributeMapRange"),
]),
GeometryNodeCategory("GEO_COLOR", "Color", items=[
NodeItem("ShaderNodeValToRGB"),
@@ -521,7 +523,16 @@ geometry_node_categories = [
NodeItem("GeometryNodeEdgeSplit"),
NodeItem("GeometryNodeSubdivisionSurface"),
NodeItem("GeometryNodeSubdivide"),
]),
GeometryNodeCategory("GEO_PRIMITIVES", "Mesh Primitives", items=[
NodeItem("GeometryNodeMeshCircle"),
NodeItem("GeometryNodeMeshCone"),
NodeItem("GeometryNodeMeshCube"),
NodeItem("GeometryNodeMeshCylinder"),
NodeItem("GeometryNodeMeshGrid"),
NodeItem("GeometryNodeMeshIcoSphere"),
NodeItem("GeometryNodeMeshLine"),
NodeItem("GeometryNodeMeshUVSphere"),
]),
GeometryNodeCategory("GEO_POINT", "Point", items=[
NodeItem("GeometryNodePointDistribute"),
@@ -532,20 +543,6 @@ geometry_node_categories = [
NodeItem("GeometryNodeRotatePoints"),
NodeItem("GeometryNodeAlignRotationToVector"),
]),
GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
NodeItem("GeometryNodePointsToVolume"),
NodeItem("GeometryNodeVolumeToMesh"),
]),
GeometryNodeCategory("GEO_PRIMITIVES", "Mesh Primitives", items=[
NodeItem("GeometryNodeMeshCube"),
NodeItem("GeometryNodeMeshCircle"),
NodeItem("GeometryNodeMeshUVSphere"),
NodeItem("GeometryNodeMeshIcoSphere"),
NodeItem("GeometryNodeMeshCylinder"),
NodeItem("GeometryNodeMeshCone"),
NodeItem("GeometryNodeMeshLine"),
NodeItem("GeometryNodeMeshPlane"),
]),
GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
NodeItem("ShaderNodeMapRange"),
NodeItem("ShaderNodeClamp"),
@@ -559,10 +556,16 @@ geometry_node_categories = [
NodeItem("ShaderNodeVectorMath"),
NodeItem("ShaderNodeVectorRotate"),
]),
GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
NodeItem("GeometryNodePointsToVolume"),
NodeItem("GeometryNodeVolumeToMesh"),
]),
GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
GeometryNodeCategory("GEO_LAYOUT", "Layout", items=[
NodeItem("NodeFrame"),
NodeItem("NodeReroute"),
NodeItem("NodePortalIn"),
NodeItem("NodePortalOut"),
]),
]

View File

@@ -0,0 +1,10 @@
shader basic_shader(
float in_float = 1.0,
color in_color = color(1.0, 1.0, 1.0),
output float out_float = 0.0,
output color out_color = color(0.0, 0.0, 0.0)
)
{
out_float = in_float * 2.0;
out_color = in_color * 2.0;
}

View File

@@ -0,0 +1,35 @@
# This sample shows the an efficient way of doing image processing
# over Blender's images using Python.
import bpy
import numpy as np
input_image_name = "Image"
output_image_name = "NewImage"
# Retrieve input image.
input_image = bpy.data.images[input_image_name]
w, h = input_image.size
# Allocate a numpy array to manipulate pixel data.
pixel_data = np.zeros((w, h, 4), 'f')
# Fast copy of pixel data from bpy.data to numpy array.
input_image.pixels.foreach_get(pixel_data.ravel())
# Do whatever image processing you want using numpy here:
# Example 1: Inverse red green and blue channels.
pixel_data[:,:,:3] = 1.0 - pixel_data[:,:,:3]
# Example 2: Change gamma on the red channel.
pixel_data[:,:,0] = np.power(pixel_data[:,:,0], 1.5)
# Create output image.
if output_image_name in bpy.data.images:
output_image = bpy.data.images[output_image_name]
else:
output_image = bpy.data.images.new(output_image_name, width=w, height=h)
# Copy of pixel data from numpy array back to the output image.
output_image.pixels.foreach_set(pixel_data.ravel())
output_image.update()

View File

@@ -31,6 +31,7 @@ set(SRC
string(APPEND CMAKE_SHARED_LINKER_FLAGS_DEBUG " /nodefaultlib:MSVCRT.lib")
add_library(BlendThumb SHARED ${SRC})
setup_platform_linker_flags(BlendThumb)
target_link_libraries(BlendThumb ${ZLIB_LIBRARIES})
install(

View File

@@ -188,10 +188,6 @@ void BKE_pose_itasc_init(struct bItasc *itasc);
/* Checks if a bone is part of an IK chain or not */
bool BKE_pose_channel_in_IK_chain(struct Object *ob, struct bPoseChannel *pchan);
/* clears BONE_UNKEYED flags for frame changing */
// XXX to be deprecated for a more general solution in animsys...
void framechange_poses_clear_unkeyed(struct Main *bmain);
/* Bone Groups API --------------------- */
/* Adds a new bone-group */
@@ -227,6 +223,9 @@ void BKE_pose_blend_read_data(struct BlendDataReader *reader, struct bPose *pose
void BKE_pose_blend_read_lib(struct BlendLibReader *reader, struct Object *ob, struct bPose *pose);
void BKE_pose_blend_read_expand(struct BlendExpander *expander, struct bPose *pose);
/* action_mirror.c */
void BKE_action_flip_with_pose(struct bAction *act, struct Object *ob_arm);
#ifdef __cplusplus
};
#endif

View File

@@ -342,6 +342,8 @@ void BKE_pchan_bbone_deform_segment_index(const struct bPoseChannel *pchan,
#define PBONE_SELECTABLE(arm, bone) \
(PBONE_VISIBLE(arm, bone) && !((bone)->flag & BONE_UNSELECTABLE))
#define PBONE_SELECTED(arm, bone) (((bone)->flag & BONE_SELECTED) & PBONE_VISIBLE(arm, bone))
/* context.selected_pose_bones */
#define FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN(_ob, _pchan) \
for (bPoseChannel *_pchan = (_ob)->pose->chanbase.first; _pchan; _pchan = _pchan->next) { \

View File

@@ -39,12 +39,12 @@ struct ReportList;
/* Attribute.domain */
typedef enum AttributeDomain {
ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */
ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */
ATTR_DOMAIN_CORNER = 2, /* Mesh Corner */
ATTR_DOMAIN_POLYGON = 3, /* Mesh Polygon */
ATTR_DOMAIN_CURVE = 4, /* Hair Curve */
ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */
ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */
ATTR_DOMAIN_CORNER = 2, /* Mesh Corner */
ATTR_DOMAIN_FACE = 3, /* Mesh Face */
ATTR_DOMAIN_CURVE = 4, /* Hair Curve */
ATTR_DOMAIN_NUM
} AttributeDomain;

View File

@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 14
#define BLENDER_FILE_SUBVERSION 15
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@@ -232,6 +232,19 @@ int BKE_fcurve_bezt_binarysearch_index(struct BezTriple array[],
int arraylen,
bool *r_replace);
/* fcurve_cache.c */
/* Cached f-curve look-ups, use when this needs to be done many times. */
struct FCurvePathCache;
struct FCurvePathCache *BKE_fcurve_pathcache_create(ListBase *list);
void BKE_fcurve_pathcache_destroy(struct FCurvePathCache *fcache);
struct FCurve *BKE_fcurve_pathcache_find(struct FCurvePathCache *fcache,
const char rna_path[],
const int array_index);
int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
const char *rna_path,
struct FCurve **fcurve_result,
int fcurve_result_len);
/* get the time extents for F-Curve */
bool BKE_fcurve_calc_range(
struct FCurve *fcu, float *min, float *max, const bool do_sel_only, const bool do_min_length);
@@ -245,6 +258,14 @@ bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
const bool do_sel_only,
const bool include_handles);
float *BKE_fcurves_calc_keyed_frames_ex(struct FCurve **fcurve_array,
const int fcurve_array_len,
const float interval,
int *r_frames_len);
float *BKE_fcurves_calc_keyed_frames(struct FCurve **fcurve_array,
const int fcurve_array_len,
int *r_frames_len);
void BKE_fcurve_active_keyframe_set(struct FCurve *fcu, const struct BezTriple *active_bezt);
int BKE_fcurve_active_keyframe_index(const struct FCurve *fcu);

View File

@@ -313,6 +313,8 @@ struct GeometrySet {
friend bool operator==(const GeometrySet &a, const GeometrySet &b);
uint64_t hash() const;
void clear();
/* Utility methods for creation. */
static GeometrySet create_with_mesh(
Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);

View File

@@ -39,7 +39,8 @@ struct GeometryInstanceGroup {
Vector<float4x4> transforms;
};
Vector<GeometryInstanceGroup> geometry_set_gather_instances(const GeometrySet &geometry_set);
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups);
GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set);
GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set);

View File

@@ -74,6 +74,7 @@ bool BKE_lib_override_library_create(struct Main *bmain,
struct ViewLayer *view_layer,
struct ID *id_root,
struct ID *id_reference);
bool BKE_lib_override_library_template_create(struct ID *id);
bool BKE_lib_override_library_proxy_convert(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,

View File

@@ -483,14 +483,14 @@ void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntre
/** \name Node Tree Interface
* \{ */
struct bNodeSocket *ntreeFindSocketInterface(struct bNodeTree *ntree,
int in_out,
eNodeSocketInOut in_out,
const char *identifier);
struct bNodeSocket *ntreeAddSocketInterface(struct bNodeTree *ntree,
int in_out,
eNodeSocketInOut in_out,
const char *idname,
const char *name);
struct bNodeSocket *ntreeInsertSocketInterface(struct bNodeTree *ntree,
int in_out,
eNodeSocketInOut in_out,
const char *idname,
struct bNodeSocket *next_sock,
const char *name);
@@ -556,30 +556,32 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype);
} \
((void)0)
struct bNodeSocket *nodeFindSocket(const struct bNode *node, int in_out, const char *identifier);
struct bNodeSocket *nodeFindSocket(const struct bNode *node,
eNodeSocketInOut in_out,
const char *identifier);
struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree,
struct bNode *node,
int in_out,
eNodeSocketInOut in_out,
const char *idname,
const char *identifier,
const char *name);
struct bNodeSocket *nodeInsertSocket(struct bNodeTree *ntree,
struct bNode *node,
int in_out,
eNodeSocketInOut in_out,
const char *idname,
struct bNodeSocket *next_sock,
const char *identifier,
const char *name);
struct bNodeSocket *nodeAddStaticSocket(struct bNodeTree *ntree,
struct bNode *node,
int in_out,
eNodeSocketInOut in_out,
int type,
int subtype,
const char *identifier,
const char *name);
struct bNodeSocket *nodeInsertStaticSocket(struct bNodeTree *ntree,
struct bNode *node,
int in_out,
eNodeSocketInOut in_out,
int type,
int subtype,
struct bNodeSocket *next_sock,
@@ -858,6 +860,8 @@ bool BKE_node_is_connected_to_output(struct bNodeTree *ntree, struct bNode *node
#define NODE_GROUP_INPUT 7
#define NODE_GROUP_OUTPUT 8
#define NODE_CUSTOM_GROUP 9
#define NODE_PORTAL_IN 10
#define NODE_PORTAL_OUT 11
void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree);
@@ -1188,6 +1192,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
#define CMP_NODE_TRACKPOS 271
#define CMP_NODE_INPAINT 272
#define CMP_NODE_DESPECKLE 273
#define CMP_NODE_ANTIALIASING 274
#define CMP_NODE_GLARE 301
#define CMP_NODE_TONEMAP 302
@@ -1393,7 +1398,9 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE 1036
#define GEO_NODE_MESH_PRIMITIVE_CONE 1037
#define GEO_NODE_MESH_PRIMITIVE_LINE 1038
#define GEO_NODE_MESH_PRIMITIVE_PLANE 1039
#define GEO_NODE_MESH_PRIMITIVE_GRID 1039
#define GEO_NODE_ATTRIBUTE_MAP_RANGE 1040
#define GEO_NODE_ATTRIBUTE_CLAMP 1041
/** \} */

View File

@@ -58,9 +58,7 @@ class NodeTreeEvaluationContext {
uint64_t hash() const
{
const uint64_t hash1 = blender::DefaultHash<std::string>{}(object_name_);
const uint64_t hash2 = BLI_session_uuid_hash_uint64(&modifier_session_uuid_);
return hash1 ^ (hash2 * 33); /* Copied from DefaultHash for std::pair. */
return blender::get_default_hash_2(object_name_, modifier_session_uuid_);
}
friend bool operator==(const NodeTreeEvaluationContext &a, const NodeTreeEvaluationContext &b)

View File

@@ -336,6 +336,12 @@ struct Mesh *BKE_object_get_evaluated_mesh(struct Object *object);
struct Mesh *BKE_object_get_pre_modified_mesh(struct Object *object);
struct Mesh *BKE_object_get_original_mesh(struct Object *object);
/* Lattice accessors.
* These functions return either the regular lattice, or the edit-mode lattice,
* whichever is currently in use. */
struct Lattice *BKE_object_get_lattice(const struct Object *object);
struct Lattice *BKE_object_get_evaluated_lattice(const struct Object *object);
int BKE_object_insert_ptcache(struct Object *ob);
void BKE_object_delete_ptcache(struct Object *ob, int index);
struct KeyBlock *BKE_object_shapekey_insert(struct Main *bmain,

View File

@@ -69,6 +69,7 @@ set(SRC
intern/CCGSubSurf_util.c
intern/DerivedMesh.cc
intern/action.c
intern/action_mirror.c
intern/addon.c
intern/anim_data.c
intern/anim_path.c
@@ -126,6 +127,7 @@ set(SRC
intern/editmesh_tangent.c
intern/effect.c
intern/fcurve.c
intern/fcurve_cache.c
intern/fcurve_driver.c
intern/fluid.c
intern/fmodifier.c
@@ -385,6 +387,7 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
BKE_node_ui_storage.hh
BKE_object.h
BKE_object_deform.h
BKE_object_facemap.h
@@ -434,10 +437,10 @@ set(SRC
nla_private.h
particle_private.h
tracking_private.h
intern/attribute_access_intern.hh
intern/CCGSubSurf.h
intern/CCGSubSurf_inline.h
intern/CCGSubSurf_intern.h
intern/attribute_access_intern.hh
intern/data_transfer_intern.h
intern/lib_intern.h
intern/multires_inline.h
@@ -742,7 +745,7 @@ if(WITH_GMP)
list(APPEND INC_SYS
${GMP_INCLUDE_DIRS}
)
endif()
endif()
# # Warnings as errors, this is too strict!
# if(MSVC)

View File

@@ -1316,30 +1316,6 @@ void BKE_pose_tag_update_constraint_flags(bPose *pose)
pose->flag |= POSE_CONSTRAINTS_NEED_UPDATE_FLAGS;
}
/* Clears all BONE_UNKEYED flags for every pose channel in every pose
* This should only be called on frame changing, when it is acceptable to
* do this. Otherwise, these flags should not get cleared as poses may get lost.
*/
void framechange_poses_clear_unkeyed(Main *bmain)
{
Object *ob;
bPose *pose;
bPoseChannel *pchan;
/* This needs to be done for each object that has a pose */
/* TODO: proxies may/may not be correctly handled here... (this needs checking) */
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
/* we only need to do this on objects with a pose */
if ((pose = ob->pose)) {
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->bone) {
pchan->bone->flag &= ~BONE_UNKEYED;
}
}
}
}
}
/* ************************** Bone Groups ************************** */
/* Adds a new bone-group (name may be NULL) */

View File

@@ -0,0 +1,457 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bke
*
* Mirror/Symmetry functions applying to actions.
*/
#include <math.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_fcurve.h"
#include "DEG_depsgraph.h"
/* -------------------------------------------------------------------- */
/** \name Flip the Action (Armature/Pose Objects)
*
* This flips the action using the rest pose (not the evaluated pose).
*
* Details:
*
* - Key-frames are modified in-place, creating new key-frames is not yet supported.
* That could be useful if a user for example only has 2x rotation channels set.
* In practice users typically keyframe all rotation channels or none.
*
* - F-curve modifiers are disabled for evaluation,
* so the values written back to the keyframes don't include modifier offsets.
*
* - Sub-frame key-frames aren't supported,
* this could be added if needed without much trouble.
*
* - F-curves must have a #FCurve.bezt array (sampled curves aren't supported).
* \{ */
/**
* This structure is created for each pose channels F-curve,
* an action be evaluated and stored in `fcurve_eval`,
* with the mirrored values written into `bezt_array`.
*
* Store F-curve evaluated values, constructed with a sorted array of rounded keyed-frames,
* passed to #action_flip_pchan_cache_init.
*/
struct FCurve_KeyCache {
/**
* When NULL, ignore this channel.
*/
FCurve *fcurve;
/**
* Cached evaluated F-curve values (without modifiers).
*/
float *fcurve_eval;
/**
* Cached #FCurve.bezt values, NULL when no key-frame exists on this frame.
*
* \note The case where two keyframes round to the same frame isn't supported.
* In this case only the first will be used.
*/
BezTriple **bezt_array;
};
/**
* Assign `fkc` path, using a `path` lookup for a single value.
*/
static void action_flip_pchan_cache_fcurve_assign_value(struct FCurve_KeyCache *fkc,
int index,
const char *path,
struct FCurvePathCache *fcache)
{
FCurve *fcu = BKE_fcurve_pathcache_find(fcache, path, index);
if (fcu && fcu->bezt) {
fkc->fcurve = fcu;
}
}
/**
* Assign #FCurve_KeyCache.fcurve path, using a `path` lookup for an array.
*/
static void action_flip_pchan_cache_fcurve_assign_array(struct FCurve_KeyCache *fkc,
int fkc_len,
const char *path,
struct FCurvePathCache *fcache)
{
FCurve **fcurves = alloca(sizeof(*fcurves) * fkc_len);
if (BKE_fcurve_pathcache_find_array(fcache, path, fcurves, fkc_len)) {
for (int i = 0; i < fkc_len; i++) {
if (fcurves[i] && fcurves[i]->bezt) {
fkc[i].fcurve = fcurves[i];
}
}
}
}
/**
* Fill in pose channel cache for each frame in `keyed_frames`.
*
* \param keyed_frames: An array of keyed_frames to evaluate,
* note that each frame is rounded to the nearest int.
* \param keyed_frames_len: The length of the `keyed_frames` array.
*/
static void action_flip_pchan_cache_init(struct FCurve_KeyCache *fkc,
const float *keyed_frames,
int keyed_frames_len)
{
BLI_assert(fkc->fcurve != NULL);
/* Cache the F-curve values for `keyed_frames`. */
const int fcurve_flag = fkc->fcurve->flag;
fkc->fcurve->flag |= FCURVE_MOD_OFF;
fkc->fcurve_eval = MEM_mallocN(sizeof(float) * keyed_frames_len, __func__);
for (int frame_index = 0; frame_index < keyed_frames_len; frame_index++) {
const float evaltime = keyed_frames[frame_index];
fkc->fcurve_eval[frame_index] = evaluate_fcurve_only_curve(fkc->fcurve, evaltime);
}
fkc->fcurve->flag = fcurve_flag;
/* Cache the #BezTriple for `keyed_frames`, or leave as NULL. */
fkc->bezt_array = MEM_mallocN(sizeof(*fkc->bezt_array) * keyed_frames_len, __func__);
BezTriple *bezt = fkc->fcurve->bezt;
BezTriple *bezt_end = fkc->fcurve->bezt + fkc->fcurve->totvert;
int frame_index = 0;
while (frame_index < keyed_frames_len) {
const float evaltime = keyed_frames[frame_index];
const float bezt_time = roundf(bezt->vec[1][0]);
if (bezt_time > evaltime) {
fkc->bezt_array[frame_index++] = NULL;
}
else {
if (bezt_time == evaltime) {
fkc->bezt_array[frame_index++] = bezt;
}
bezt++;
if (bezt == bezt_end) {
break;
}
}
}
/* Clear remaining unset keyed_frames (if-any). */
while (frame_index < keyed_frames_len) {
fkc->bezt_array[frame_index++] = NULL;
}
}
/**
*/
static void action_flip_pchan(Object *ob_arm,
const bPoseChannel *pchan,
struct FCurvePathCache *fcache)
{
/* Begin F-Curve pose channel value extraction. */
/* Use a fixed buffer size as it's known this can only be at most:
* `pose.bones["{MAXBONENAME}"].rotation_quaternion`. */
char path_xform[256];
char pchan_name_esc[sizeof(((bActionChannel *)NULL)->name) * 2];
BLI_str_escape(pchan_name_esc, pchan->name, sizeof(pchan_name_esc));
const int path_xform_prefix_len = SNPRINTF(path_xform, "pose.bones[\"%s\"]", pchan_name_esc);
char *path_xform_suffix = path_xform + path_xform_prefix_len;
const int path_xform_suffix_len = sizeof(path_xform) - path_xform_prefix_len;
/* Lookup and assign all available #FCurve channels,
* unavailable channels are left NULL. */
/**
* Structure to store transformation F-curves corresponding to a pose bones transformation.
* Match struct member names from #bPoseChannel so macros avoid repetition.
*
* \note There is no need to read values unless they influence the 4x4 transform matrix,
* and no need to write values back unless they would be changed by a modified matrix.
* So `rotmode` needs to be read, but doesn't need to be written back to.
*
* Most bendy-bone settings don't need to be included either, flipping their RNA paths is enough.
* Although the X/Y settings could make sense to transform, in practice it would only
* work well if the rotation happened to swap X/Y alignment, leave this for now.
*/
struct {
struct FCurve_KeyCache loc[3], eul[3], quat[4], rotAxis[3], rotAngle, size[3], rotmode;
} fkc_pchan = {{{NULL}}};
#define FCURVE_ASSIGN_VALUE(id, path_test_suffix, index) \
BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_len); \
action_flip_pchan_cache_fcurve_assign_value(&fkc_pchan.id, index, path_xform, fcache)
#define FCURVE_ASSIGN_ARRAY(id, path_test_suffix) \
BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_len); \
action_flip_pchan_cache_fcurve_assign_array( \
fkc_pchan.id, ARRAY_SIZE(fkc_pchan.id), path_xform, fcache)
FCURVE_ASSIGN_ARRAY(loc, ".location");
FCURVE_ASSIGN_ARRAY(eul, ".rotation_euler");
FCURVE_ASSIGN_ARRAY(quat, ".rotation_quaternion");
FCURVE_ASSIGN_ARRAY(rotAxis, ".rotation_axis_angle");
FCURVE_ASSIGN_VALUE(rotAngle, ".rotation_axis_angle", 3);
FCURVE_ASSIGN_ARRAY(size, ".scale");
FCURVE_ASSIGN_VALUE(rotmode, ".rotation_mode", 0);
#undef FCURVE_ASSIGN_VALUE
#undef FCURVE_ASSIGN_ARRAY
/* Array of F-curves, for convenient access. */
#define FCURVE_CHANNEL_LEN (sizeof(fkc_pchan) / sizeof(struct FCurve_KeyCache))
FCurve *fcurve_array[FCURVE_CHANNEL_LEN];
int fcurve_array_len = 0;
for (int chan = 0; chan < FCURVE_CHANNEL_LEN; chan++) {
struct FCurve_KeyCache *fkc = (struct FCurve_KeyCache *)(&fkc_pchan) + chan;
if (fkc->fcurve != NULL) {
fcurve_array[fcurve_array_len++] = fkc->fcurve;
}
}
/* If this pose has no transform channels, there is nothing to do. */
if (fcurve_array_len == 0) {
return;
}
/* Calculate an array of frames used by any of the key-frames in `fcurve_array`. */
int keyed_frames_len;
const float *keyed_frames = BKE_fcurves_calc_keyed_frames(
fcurve_array, fcurve_array_len, &keyed_frames_len);
/* Initialize the pose channel curve cache from the F-curve. */
for (int chan = 0; chan < FCURVE_CHANNEL_LEN; chan++) {
struct FCurve_KeyCache *fkc = (struct FCurve_KeyCache *)(&fkc_pchan) + chan;
if (fkc->fcurve == NULL) {
continue;
}
action_flip_pchan_cache_init(fkc, keyed_frames, keyed_frames_len);
}
/* X-axis flipping matrix. */
float flip_mtx[4][4];
unit_m4(flip_mtx);
flip_mtx[0][0] = -1;
bPoseChannel *pchan_flip = NULL;
char pchan_name_flip[MAXBONENAME];
BLI_string_flip_side_name(pchan_name_flip, pchan->name, false, sizeof(pchan_name_flip));
if (!STREQ(pchan_name_flip, pchan->name)) {
pchan_flip = BKE_pose_channel_find_name(ob_arm->pose, pchan_name_flip);
}
float arm_mat_inv[4][4];
invert_m4_m4(arm_mat_inv, pchan_flip ? pchan_flip->bone->arm_mat : pchan->bone->arm_mat);
/* Now flip the transformation & write it back to the F-curves in `fkc_pchan`. */
for (int frame_index = 0; frame_index < keyed_frames_len; frame_index++) {
/* Temporary pose channel to write values into,
* using the `fkc_pchan` values, falling back to the values in the pose channel. */
bPoseChannel pchan_temp = *pchan;
/* Load the values into the channel. */
#define READ_VALUE_FLT(id) \
if (fkc_pchan.id.fcurve_eval != NULL) { \
pchan_temp.id = fkc_pchan.id.fcurve_eval[frame_index]; \
} \
((void)0)
#define READ_VALUE_INT(id) \
if (fkc_pchan.id.fcurve_eval != NULL) { \
pchan_temp.id = floorf(fkc_pchan.id.fcurve_eval[frame_index] + 0.5f); \
} \
((void)0)
#define READ_ARRAY_FLT(id) \
for (int i = 0; i < ARRAY_SIZE(pchan_temp.id); i++) { \
READ_VALUE_FLT(id[i]); \
} \
((void)0)
READ_ARRAY_FLT(loc);
READ_ARRAY_FLT(eul);
READ_ARRAY_FLT(quat);
READ_ARRAY_FLT(rotAxis);
READ_VALUE_FLT(rotAngle);
READ_ARRAY_FLT(size);
READ_VALUE_INT(rotmode);
#undef READ_ARRAY_FLT
#undef READ_VALUE_FLT
#undef READ_VALUE_INT
float chan_mat[4][4];
BKE_pchan_to_mat4(&pchan_temp, chan_mat);
/* Move to the pose-space. */
mul_m4_m4m4(chan_mat, pchan->bone->arm_mat, chan_mat);
/* Flip the matrix. */
mul_m4_m4m4(chan_mat, chan_mat, flip_mtx);
mul_m4_m4m4(chan_mat, flip_mtx, chan_mat);
/* Move back to bone-space space, using the flipped bone if it exists. */
mul_m4_m4m4(chan_mat, arm_mat_inv, chan_mat);
BKE_pchan_apply_mat4(&pchan_temp, chan_mat, false);
/* Write the values back to the F-curves. */
#define WRITE_VALUE_FLT(id) \
if (fkc_pchan.id.fcurve_eval != NULL) { \
BezTriple *bezt = fkc_pchan.id.bezt_array[frame_index]; \
if (bezt != NULL) { \
const float delta = pchan_temp.id - bezt->vec[1][1]; \
bezt->vec[0][1] += delta; \
bezt->vec[1][1] += delta; \
bezt->vec[2][1] += delta; \
} \
} \
((void)0)
#define WRITE_ARRAY_FLT(id) \
for (int i = 0; i < ARRAY_SIZE(pchan_temp.id); i++) { \
WRITE_VALUE_FLT(id[i]); \
} \
((void)0)
/* Write the values back the the F-curves. */
WRITE_ARRAY_FLT(loc);
WRITE_ARRAY_FLT(eul);
WRITE_ARRAY_FLT(quat);
WRITE_ARRAY_FLT(rotAxis);
WRITE_VALUE_FLT(rotAngle);
WRITE_ARRAY_FLT(size);
/* No need to write back 'rotmode' as it can't be transformed. */
#undef WRITE_ARRAY_FLT
#undef WRITE_VALUE_FLT
}
/* Recalculate handles. */
for (int i = 0; i < fcurve_array_len; i++) {
calchandles_fcurve_ex(fcurve_array[i], 0);
}
MEM_freeN((void *)keyed_frames);
for (int chan = 0; chan < FCURVE_CHANNEL_LEN; chan++) {
struct FCurve_KeyCache *fkc = (struct FCurve_KeyCache *)(&fkc_pchan) + chan;
if (fkc->fcurve_eval) {
MEM_freeN(fkc->fcurve_eval);
}
if (fkc->bezt_array) {
MEM_freeN(fkc->bezt_array);
}
}
}
/**
* Swap all RNA paths left/right.
*/
static void action_flip_pchan_rna_paths(struct bAction *act)
{
const char *path_pose_prefix = "pose.bones[\"";
const int path_pose_prefix_len = strlen(path_pose_prefix);
/* Tag curves that have renamed f-curves. */
LISTBASE_FOREACH (bActionGroup *, agrp, &act->groups) {
agrp->flag &= ~AGRP_TEMP;
}
LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
if (!STRPREFIX(fcu->rna_path, path_pose_prefix)) {
continue;
}
const char *name_esc = fcu->rna_path + path_pose_prefix_len;
const char *name_esc_end = BLI_str_escape_find_quote(name_esc);
/* While unlikely, an RNA path could be malformed. */
if (UNLIKELY(name_esc_end == NULL)) {
continue;
}
char name[MAXBONENAME];
const size_t name_esc_len = (size_t)(name_esc_end - name_esc);
const size_t name_len = BLI_str_unescape(name, name_esc, name_esc_len);
/* While unlikely, data paths could be constructed that have longer names than
* are currently supported. */
if (UNLIKELY(name_len >= sizeof(name))) {
continue;
}
/* When the flipped name differs, perform the rename. */
char name_flip[MAXBONENAME];
BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
if (!STREQ(name_flip, name)) {
char name_flip_esc[MAXBONENAME * 2];
BLI_str_escape(name_flip_esc, name_flip, sizeof(name_flip_esc));
char *path_flip = BLI_sprintfN("pose.bones[\"%s%s", name_flip_esc, name_esc_end);
MEM_freeN(fcu->rna_path);
fcu->rna_path = path_flip;
if (fcu->grp != NULL) {
fcu->grp->flag |= AGRP_TEMP;
}
}
}
/* Rename tagged groups. */
LISTBASE_FOREACH (bActionGroup *, agrp, &act->groups) {
if ((agrp->flag & AGRP_TEMP) == 0) {
continue;
}
agrp->flag &= ~AGRP_TEMP;
char name_flip[MAXBONENAME];
BLI_string_flip_side_name(name_flip, agrp->name, false, sizeof(name_flip));
if (!STREQ(name_flip, agrp->name)) {
STRNCPY(agrp->name, name_flip);
}
}
}
void BKE_action_flip_with_pose(struct bAction *act, struct Object *ob_arm)
{
struct FCurvePathCache *fcache = BKE_fcurve_pathcache_create(&act->curves);
int i;
LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob_arm->pose->chanbase, i) {
action_flip_pchan(ob_arm, pchan, fcache);
}
BKE_fcurve_pathcache_destroy(fcache);
action_flip_pchan_rna_paths(act);
DEG_id_tag_update(&act->id, ID_RECALC_COPY_ON_WRITE);
}
/** \} */

View File

@@ -39,7 +39,7 @@ namespace {
using BoneNameSet = blender::Set<std::string>;
// Forward declarations.
BoneNameSet pose_apply_find_selected_bones(const bPose *pose);
BoneNameSet pose_apply_find_selected_bones(const bArmature *armature, const bPose *pose);
void pose_apply_disable_fcurves_for_unselected_bones(bAction *action,
const BoneNameSet &selected_bone_names);
void pose_apply_restore_fcurves(bAction *action);
@@ -54,7 +54,8 @@ void BKE_pose_apply_action(struct Object *ob,
return;
}
const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(pose);
const bArmature *armature = (bArmature *)ob->data;
const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(armature, pose);
const bool limit_to_selected_bones = !selected_bone_names.is_empty();
if (limit_to_selected_bones) {
@@ -74,15 +75,14 @@ void BKE_pose_apply_action(struct Object *ob,
}
namespace {
BoneNameSet pose_apply_find_selected_bones(const bPose *pose)
BoneNameSet pose_apply_find_selected_bones(const bArmature *armature, const bPose *pose)
{
BoneNameSet selected_bone_names;
bool all_bones_selected = true;
bool no_bones_selected = true;
LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
const bool is_selected = (pchan->bone->flag & BONE_SELECTED) != 0 &&
(pchan->bone->flag & BONE_HIDDEN_P) == 0;
const bool is_selected = PBONE_SELECTED(armature, pchan->bone);
all_bones_selected &= is_selected;
no_bones_selected &= !is_selected;

View File

@@ -69,8 +69,8 @@ static void get_domains(ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
info[ATTR_DOMAIN_EDGE].length = mesh->totedge;
info[ATTR_DOMAIN_CORNER].customdata = &mesh->ldata;
info[ATTR_DOMAIN_CORNER].length = mesh->totloop;
info[ATTR_DOMAIN_POLYGON].customdata = &mesh->pdata;
info[ATTR_DOMAIN_POLYGON].length = mesh->totpoly;
info[ATTR_DOMAIN_FACE].customdata = &mesh->pdata;
info[ATTR_DOMAIN_FACE].length = mesh->totpoly;
break;
}
case ID_HA: {

View File

@@ -331,7 +331,7 @@ static int attribute_domain_priority(const AttributeDomain domain)
case ATTR_DOMAIN_CURVE:
return 0;
#endif
case ATTR_DOMAIN_POLYGON:
case ATTR_DOMAIN_FACE:
return 1;
case ATTR_DOMAIN_EDGE:
return 2;
@@ -893,7 +893,7 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
return {};
}
if (attribute->domain() != domain) {
if (domain != ATTR_DOMAIN_AUTO && attribute->domain() != domain) {
attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
if (!attribute) {
return {};

View File

@@ -400,6 +400,8 @@ static void setup_app_data(bContext *C,
bmain,
curscene,
bfd->cur_view_layer ? bfd->cur_view_layer : BKE_view_layer_default_view(curscene));
/* We need to rebuild some of the deleted override rules (for UI feedback purpose). */
BKE_lib_override_library_main_operations_create(bmain, true);
}
}

View File

@@ -574,8 +574,8 @@ bool BKE_brush_delete(Main *bmain, Brush *brush)
if (brush->id.tag & LIB_TAG_INDIRECT) {
return false;
}
if (BKE_library_ID_is_indirectly_used(bmain, brush) && ID_REAL_USERS(brush) <= 1 &&
ID_EXTRA_USERS(brush) == 0) {
if (ID_REAL_USERS(brush) <= 1 && ID_EXTRA_USERS(brush) == 0 &&
BKE_library_ID_is_indirectly_used(bmain, brush)) {
return false;
}

View File

@@ -99,6 +99,7 @@ static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_a
cache_file->handle_readers = NULL;
BLO_write_id_struct(writer, CacheFile, id_address, &cache_file->id);
BKE_id_blend_write(writer, &cache_file->id);
if (cache_file->adt) {
BKE_animdata_blend_write(writer, cache_file->adt);

View File

@@ -425,6 +425,9 @@ static bool from_manifest(CryptomatteLayer &layer, blender::StringRefNull manife
}
const int quoted_hash_len = quoted_string_len_(ref);
if (quoted_hash_len < 2) {
return false;
}
const int hash_len = quoted_hash_len - 2;
CryptomatteHash hash = CryptomatteHash::from_hex_encoded(ref.substr(1, hash_len));
ref = ref.drop_prefix(quoted_hash_len);

View File

@@ -35,7 +35,9 @@
#include "BLI_blenlib.h"
#include "BLI_easing.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_sort_utils.h"
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
@@ -290,6 +292,12 @@ FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_i
return NULL;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name FCurve Iteration
* \{ */
/* Quick way to loop over all fcurves of a given 'path'. */
FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
{
@@ -829,6 +837,56 @@ bool BKE_fcurve_calc_range(
return foundvert;
}
/**
* Return an array of keyed frames, rounded to `interval`.
*
* \param interval: Set to 1.0 to round to whole keyframes, 0.5 for in-between key-frames, etc.
*
* \note An interval of zero could be supported (this implies no rounding at all),
* however this risks very small differences in float values being treated as separate keyframes.
*/
float *BKE_fcurves_calc_keyed_frames_ex(FCurve **fcurve_array,
int fcurve_array_len,
const float interval,
int *r_frames_len)
{
/* Use `1e-3f` as the smallest possible value since these are converted to integers
* and we can be sure `MAXFRAME / 1e-3f < INT_MAX` as it's around half the size. */
const double interval_db = max_ff(interval, 1e-3f);
GSet *frames_unique = BLI_gset_int_new(__func__);
for (int fcurve_index = 0; fcurve_index < fcurve_array_len; fcurve_index++) {
const FCurve *fcu = fcurve_array[fcurve_index];
for (int i = 0; i < fcu->totvert; i++) {
const BezTriple *bezt = &fcu->bezt[i];
const double value = round((double)bezt->vec[1][0] / interval_db);
BLI_assert(value > INT_MIN && value < INT_MAX);
BLI_gset_add(frames_unique, POINTER_FROM_INT((int)value));
}
}
const size_t frames_len = BLI_gset_len(frames_unique);
float *frames = MEM_mallocN(sizeof(*frames) * frames_len, __func__);
GSetIterator gs_iter;
int i = 0;
GSET_ITER_INDEX (gs_iter, frames_unique, i) {
const int value = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
frames[i] = (double)value * interval_db;
}
BLI_gset_free(frames_unique, NULL);
qsort(frames, frames_len, sizeof(*frames), BLI_sortutil_cmp_float);
*r_frames_len = frames_len;
return frames;
}
float *BKE_fcurves_calc_keyed_frames(FCurve **fcurve_array,
int fcurve_array_len,
int *r_frames_len)
{
return BKE_fcurves_calc_keyed_frames_ex(fcurve_array, fcurve_array_len, 1.0f, r_frames_len);
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -0,0 +1,189 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bke
*
* Cache F-Curve look-ups.
*/
#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BKE_fcurve.h"
/* -------------------------------------------------------------------- */
/** \name F-Curve Path Cache
*
* Cache for finding curves by RNA path & array index.
* \{ */
struct FCurvePathCache_Span {
/** Index in the #FCurvePathCache.fcurve_array indicating the start of the span. */
uint index;
/** Number of items in the span in #FCurvePathCache.fcurve_array that share an RNA path. */
uint len;
};
struct FCurvePathCache {
/** All curves sorted by (#FCurve.rna_path, #FCurve.array_index) */
FCurve **fcurve_array;
uint fcurve_array_len;
/** Storage for values of `span_from_rna_path`. */
struct FCurvePathCache_Span *span_table;
/** Map `FCurve.rna_path` to elements in #FCurvePathCache.span_table */
GHash *span_from_rna_path;
};
/**
* #qsort callback for an #FCurve array.
*/
static int fcurve_cmp_for_cache(const void *fcu_a_p, const void *fcu_b_p)
{
const FCurve *fcu_a = *((const FCurve **)fcu_a_p);
const FCurve *fcu_b = *((const FCurve **)fcu_b_p);
const int cmp = strcmp(fcu_a->rna_path, fcu_b->rna_path);
if (cmp != 0) {
return cmp;
}
if (fcu_a->array_index < fcu_b->array_index) {
return -1;
}
if (fcu_a->array_index > fcu_b->array_index) {
return 1;
}
return 0;
}
struct FCurvePathCache *BKE_fcurve_pathcache_create(ListBase *list)
{
const uint fcurve_array_len = BLI_listbase_count(list);
FCurve **fcurve_array = MEM_mallocN(sizeof(*fcurve_array) * fcurve_array_len, __func__);
uint i;
LISTBASE_FOREACH_INDEX (FCurve *, fcu, list, i) {
fcurve_array[i] = fcu;
}
qsort(fcurve_array, fcurve_array_len, sizeof(FCurve *), fcurve_cmp_for_cache);
/* Allow for the case no F-curves share an RNA-path, otherwise this is over-allocated.
* Although in practice it's likely to only be 3-4x as large as is needed
* (with transform channels for e.g.). */
struct FCurvePathCache_Span *span_table = MEM_mallocN(sizeof(*span_table) * fcurve_array_len,
__func__);
/* May over reserve, harmless. */
GHash *span_from_rna_path = BLI_ghash_str_new_ex(__func__, fcurve_array_len);
uint span_index = 0;
i = 0;
while (i < fcurve_array_len) {
uint i_end;
for (i_end = i + 1; i_end < fcurve_array_len; i_end++) {
/* As the indices are sorted, we know a decrease means a new RNA path is found. */
if (fcurve_array[i]->array_index > fcurve_array[i_end]->array_index) {
BLI_assert(!STREQ(fcurve_array[i]->rna_path, fcurve_array[i_end]->rna_path));
break;
}
if (!STREQ(fcurve_array[i]->rna_path, fcurve_array[i_end]->rna_path)) {
break;
}
}
struct FCurvePathCache_Span *span = &span_table[span_index++];
span->index = i;
span->len = i_end - i;
BLI_ghash_insert(span_from_rna_path, fcurve_array[i]->rna_path, span);
i = i_end;
}
struct FCurvePathCache *fcache = MEM_callocN(sizeof(struct FCurvePathCache), __func__);
fcache->fcurve_array = fcurve_array;
fcache->fcurve_array_len = fcurve_array_len;
fcache->span_table = span_table;
fcache->span_from_rna_path = span_from_rna_path;
return fcache;
}
void BKE_fcurve_pathcache_destroy(struct FCurvePathCache *fcache)
{
MEM_freeN(fcache->fcurve_array);
MEM_freeN(fcache->span_table);
BLI_ghash_free(fcache->span_from_rna_path, NULL, NULL);
MEM_freeN(fcache);
}
FCurve *BKE_fcurve_pathcache_find(struct FCurvePathCache *fcache,
const char *rna_path,
const int array_index)
{
const struct FCurvePathCache_Span *span = BLI_ghash_lookup(fcache->span_from_rna_path, rna_path);
if (span == NULL) {
return NULL;
}
FCurve **fcurve = fcache->fcurve_array + span->index;
const uint len = span->len;
for (int i = 0; i < len; i++) {
if (fcurve[i]->array_index == array_index) {
return fcurve[i];
}
/* As these are sorted, early exit. */
if (fcurve[i]->array_index > array_index) {
break;
}
}
return NULL;
}
/**
* Fill in an array of F-Curve, leave NULL when not found.
*
* \return The number of F-Curves found.
*/
int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
const char *rna_path,
FCurve **fcurve_result,
int fcurve_result_len)
{
memset(fcurve_result, 0x0, sizeof(*fcurve_result) * fcurve_result_len);
const struct FCurvePathCache_Span *span = BLI_ghash_lookup(fcache->span_from_rna_path, rna_path);
if (span == NULL) {
return 0;
}
int found = 0;
FCurve **fcurve = fcache->fcurve_array + span->index;
const uint len = span->len;
for (int i = 0; i < len; i++) {
/* As these are sorted, early exit. */
if ((uint)fcurve[i]->array_index > (uint)fcurve_result_len) {
break;
}
fcurve_result[fcurve[i]->array_index] = fcurve[i];
found += 1;
}
return found;
}
/** \} */

View File

@@ -175,7 +175,7 @@ int MeshComponent::attribute_domain_size(const AttributeDomain domain) const
return mesh_->totvert;
case ATTR_DOMAIN_EDGE:
return mesh_->totedge;
case ATTR_DOMAIN_POLYGON:
case ATTR_DOMAIN_FACE:
return mesh_->totpoly;
default:
break;
@@ -259,9 +259,9 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
* only some values are required.
*/
template<typename T>
static void adapt_mesh_domain_corner_to_polygon_impl(const Mesh &mesh,
Span<T> old_values,
MutableSpan<T> r_values)
static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
Span<T> old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
attribute_math::DefaultMixer<T> mixer(r_values);
@@ -277,8 +277,8 @@ static void adapt_mesh_domain_corner_to_polygon_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh,
ReadAttributePtr attribute)
static ReadAttributePtr adapt_mesh_domain_corner_to_face(const Mesh &mesh,
ReadAttributePtr attribute)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
@@ -286,7 +286,7 @@ static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh,
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
adapt_mesh_domain_corner_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
adapt_mesh_domain_corner_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
}
@@ -336,9 +336,9 @@ static ReadAttributePtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh,
}
template<typename T>
void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh,
Span<T> old_values,
MutableSpan<T> r_values)
void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
Span<T> old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totvert);
attribute_math::DefaultMixer<T> mixer(r_values);
@@ -356,8 +356,8 @@ void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh,
ReadAttributePtr attribute)
static ReadAttributePtr adapt_mesh_domain_face_to_point(const Mesh &mesh,
ReadAttributePtr attribute)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
@@ -365,7 +365,7 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh,
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totvert);
adapt_mesh_domain_polygon_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
adapt_mesh_domain_face_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
}
@@ -374,9 +374,9 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh,
}
template<typename T>
void adapt_mesh_domain_polygon_to_corner_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totloop);
@@ -387,8 +387,8 @@ void adapt_mesh_domain_polygon_to_corner_impl(const Mesh &mesh,
}
}
static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh,
ReadAttributePtr attribute)
static ReadAttributePtr adapt_mesh_domain_face_to_corner(const Mesh &mesh,
ReadAttributePtr attribute)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
@@ -396,7 +396,7 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh,
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totloop);
adapt_mesh_domain_polygon_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
adapt_mesh_domain_face_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
}
@@ -405,9 +405,9 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh,
}
template<typename T>
void adapt_mesh_domain_polygon_to_edge_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totedge);
attribute_math::DefaultMixer<T> mixer(r_values);
@@ -423,8 +423,8 @@ void adapt_mesh_domain_polygon_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh,
ReadAttributePtr attribute)
static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh,
ReadAttributePtr attribute)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
@@ -432,7 +432,7 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh,
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
adapt_mesh_domain_polygon_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
adapt_mesh_domain_face_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
}
@@ -446,9 +446,9 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh,
* only some values are required.
*/
template<typename T>
static void adapt_mesh_domain_point_to_polygon_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
attribute_math::DefaultMixer<T> mixer(r_values);
@@ -464,8 +464,8 @@ static void adapt_mesh_domain_point_to_polygon_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh,
ReadAttributePtr attribute)
static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh,
ReadAttributePtr attribute)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
@@ -473,7 +473,7 @@ static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh,
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
adapt_mesh_domain_point_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
adapt_mesh_domain_point_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
}
@@ -531,7 +531,7 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
for (const int poly_index : IndexRange(mesh.totpoly)) {
const MPoly &poly = mesh.mpoly[poly_index];
/* For every corner, mix the values from the adjacent edges on the polygon. */
/* For every corner, mix the values from the adjacent edges on the face. */
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
const int loop_index_prev = (loop_index - 1) % poly.totloop;
const MLoop &loop = mesh.mloop[loop_index];
@@ -602,9 +602,9 @@ static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh,
* only some values are required.
*/
template<typename T>
static void adapt_mesh_domain_edge_to_polygon_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
const Span<T> old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
attribute_math::DefaultMixer<T> mixer(r_values);
@@ -620,8 +620,8 @@ static void adapt_mesh_domain_edge_to_polygon_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_edge_to_polygon(const Mesh &mesh,
ReadAttributePtr attribute)
static ReadAttributePtr adapt_mesh_domain_edge_to_face(const Mesh &mesh,
ReadAttributePtr attribute)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
@@ -629,7 +629,7 @@ static ReadAttributePtr adapt_mesh_domain_edge_to_polygon(const Mesh &mesh,
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
adapt_mesh_domain_edge_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
adapt_mesh_domain_edge_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
}
@@ -658,8 +658,8 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
switch (new_domain) {
case ATTR_DOMAIN_POINT:
return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
case ATTR_DOMAIN_POLYGON:
return blender::bke::adapt_mesh_domain_corner_to_polygon(*mesh_, std::move(attribute));
case ATTR_DOMAIN_FACE:
return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(attribute));
case ATTR_DOMAIN_EDGE:
return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute));
default:
@@ -671,8 +671,8 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
switch (new_domain) {
case ATTR_DOMAIN_CORNER:
return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
case ATTR_DOMAIN_POLYGON:
return blender::bke::adapt_mesh_domain_point_to_polygon(*mesh_, std::move(attribute));
case ATTR_DOMAIN_FACE:
return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(attribute));
case ATTR_DOMAIN_EDGE:
return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute));
default:
@@ -680,14 +680,14 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
}
break;
}
case ATTR_DOMAIN_POLYGON: {
case ATTR_DOMAIN_FACE: {
switch (new_domain) {
case ATTR_DOMAIN_POINT:
return blender::bke::adapt_mesh_domain_polygon_to_point(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(attribute));
case ATTR_DOMAIN_CORNER:
return blender::bke::adapt_mesh_domain_polygon_to_corner(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(attribute));
case ATTR_DOMAIN_EDGE:
return blender::bke::adapt_mesh_domain_polygon_to_edge(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(attribute));
default:
break;
}
@@ -699,8 +699,8 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(attribute));
case ATTR_DOMAIN_POINT:
return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(attribute));
case ATTR_DOMAIN_POLYGON:
return blender::bke::adapt_mesh_domain_edge_to_polygon(*mesh_, std::move(attribute));
case ATTR_DOMAIN_FACE:
return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(attribute));
default:
break;
}
@@ -729,6 +729,27 @@ static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &com
namespace blender::bke {
template<typename StructT,
typename ElemT,
ElemT (*GetFunc)(const StructT &),
AttributeDomain Domain>
static ReadAttributePtr make_derived_read_attribute(const void *data, const int domain_size)
{
return std::make_unique<DerivedArrayReadAttribute<StructT, ElemT, GetFunc>>(
Domain, Span<StructT>((const StructT *)data, domain_size));
}
template<typename StructT,
typename ElemT,
ElemT (*GetFunc)(const StructT &),
void (*SetFunc)(StructT &, const ElemT &),
AttributeDomain Domain>
static WriteAttributePtr make_derived_write_attribute(void *data, const int domain_size)
{
return std::make_unique<DerivedArrayWriteAttribute<StructT, ElemT, GetFunc, SetFunc>>(
Domain, MutableSpan<StructT>((StructT *)data, domain_size));
}
static float3 get_vertex_position(const MVert &vert)
{
return float3(vert.co);
@@ -739,20 +760,6 @@ static void set_vertex_position(MVert &vert, const float3 &position)
copy_v3_v3(vert.co, position);
}
static ReadAttributePtr make_vertex_position_read_attribute(const void *data,
const int domain_size)
{
return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_position>>(
ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size));
}
static WriteAttributePtr make_vertex_position_write_attribute(void *data, const int domain_size)
{
return std::make_unique<
DerivedArrayWriteAttribute<MVert, float3, get_vertex_position, set_vertex_position>>(
ATTR_DOMAIN_POINT, MutableSpan<MVert>((MVert *)data, domain_size));
}
static void tag_normals_dirty_when_writing_position(GeometryComponent &component)
{
Mesh *mesh = get_mesh_from_component_for_write(component);
@@ -771,19 +778,6 @@ static void set_material_index(MPoly &mpoly, const int &index)
mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX));
}
static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size)
{
return std::make_unique<DerivedArrayReadAttribute<MPoly, int, get_material_index>>(
ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size));
}
static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size)
{
return std::make_unique<
DerivedArrayWriteAttribute<MPoly, int, get_material_index, set_material_index>>(
ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size));
}
static bool get_shade_smooth(const MPoly &mpoly)
{
return mpoly.flag & ME_SMOOTH;
@@ -794,19 +788,6 @@ static void set_shade_smooth(MPoly &mpoly, const bool &value)
SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH);
}
static ReadAttributePtr make_shade_smooth_read_attribute(const void *data, const int domain_size)
{
return std::make_unique<DerivedArrayReadAttribute<MPoly, bool, get_shade_smooth>>(
ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size));
}
static WriteAttributePtr make_shade_smooth_write_attribute(void *data, const int domain_size)
{
return std::make_unique<
DerivedArrayWriteAttribute<MPoly, bool, get_shade_smooth, set_shade_smooth>>(
ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size));
}
static float2 get_loop_uv(const MLoopUV &uv)
{
return float2(uv.uv);
@@ -817,18 +798,6 @@ static void set_loop_uv(MLoopUV &uv, const float2 &co)
copy_v2_v2(uv.uv, co);
}
static ReadAttributePtr make_uvs_read_attribute(const void *data, const int domain_size)
{
return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, get_loop_uv>>(
ATTR_DOMAIN_CORNER, Span((const MLoopUV *)data, domain_size));
}
static WriteAttributePtr make_uvs_write_attribute(void *data, const int domain_size)
{
return std::make_unique<DerivedArrayWriteAttribute<MLoopUV, float2, get_loop_uv, set_loop_uv>>(
ATTR_DOMAIN_CORNER, MutableSpan((MLoopUV *)data, domain_size));
}
static Color4f get_loop_color(const MLoopCol &col)
{
Color4f value;
@@ -841,19 +810,6 @@ static void set_loop_color(MLoopCol &col, const Color4f &value)
rgba_float_to_uchar(&col.r, value);
}
static ReadAttributePtr make_vertex_color_read_attribute(const void *data, const int domain_size)
{
return std::make_unique<DerivedArrayReadAttribute<MLoopCol, Color4f, get_loop_color>>(
ATTR_DOMAIN_CORNER, Span((const MLoopCol *)data, domain_size));
}
static WriteAttributePtr make_vertex_color_write_attribute(void *data, const int domain_size)
{
return std::make_unique<
DerivedArrayWriteAttribute<MLoopCol, Color4f, get_loop_color, set_loop_color>>(
ATTR_DOMAIN_CORNER, MutableSpan((MLoopCol *)data, domain_size));
}
static float get_crease(const MEdge &edge)
{
return edge.crease / 255.0f;
@@ -864,18 +820,6 @@ static void set_crease(MEdge &edge, const float &value)
edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
}
static ReadAttributePtr make_crease_read_attribute(const void *data, const int domain_size)
{
return std::make_unique<DerivedArrayReadAttribute<MEdge, float, get_crease>>(
ATTR_DOMAIN_EDGE, Span((const MEdge *)data, domain_size));
}
static WriteAttributePtr make_crease_write_attribute(void *data, const int domain_size)
{
return std::make_unique<DerivedArrayWriteAttribute<MEdge, float, get_crease, set_crease>>(
ATTR_DOMAIN_EDGE, MutableSpan((MEdge *)data, domain_size));
}
class VertexWeightWriteAttribute final : public WriteAttribute {
private:
MDeformVert *dverts_;
@@ -1045,7 +989,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
public:
NormalAttributeProvider()
: BuiltinAttributeProvider(
"normal", ATTR_DOMAIN_POLYGON, CD_PROP_FLOAT3, NonCreatable, Readonly, NonDeletable)
"normal", ATTR_DOMAIN_FACE, CD_PROP_FLOAT3, NonCreatable, Readonly, NonDeletable)
{
}
@@ -1063,7 +1007,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
return std::make_unique<ArrayReadAttribute<float3>>(
ATTR_DOMAIN_POLYGON, Span<float3>((const float3 *)data, mesh->totpoly));
ATTR_DOMAIN_FACE, Span<float3>((const float3 *)data, mesh->totpoly));
}
Array<float3> normals(mesh->totpoly);
@@ -1072,8 +1016,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]);
}
return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_POLYGON,
std::move(normals));
return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_FACE, std::move(normals));
}
WriteAttributePtr try_get_for_write(GeometryComponent &UNUSED(component)) const final
@@ -1093,7 +1036,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
bool exists(const GeometryComponent &component) const final
{
return component.attribute_domain_size(ATTR_DOMAIN_POLYGON) != 0;
return component.attribute_domain_size(ATTR_DOMAIN_FACE) != 0;
}
};
@@ -1130,82 +1073,104 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata),
MAKE_CONST_CUSTOM_DATA_GETTER(edata),
update_custom_data_pointers};
static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata),
MAKE_CONST_CUSTOM_DATA_GETTER(pdata),
update_custom_data_pointers};
static CustomDataAccessInfo face_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata),
MAKE_CONST_CUSTOM_DATA_GETTER(pdata),
update_custom_data_pointers};
#undef MAKE_CONST_CUSTOM_DATA_GETTER
#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER
static BuiltinCustomDataLayerProvider position("position",
ATTR_DOMAIN_POINT,
CD_PROP_FLOAT3,
CD_MVERT,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
point_access,
make_vertex_position_read_attribute,
make_vertex_position_write_attribute,
tag_normals_dirty_when_writing_position);
static BuiltinCustomDataLayerProvider position(
"position",
ATTR_DOMAIN_POINT,
CD_PROP_FLOAT3,
CD_MVERT,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
point_access,
make_derived_read_attribute<MVert, float3, get_vertex_position, ATTR_DOMAIN_POINT>,
make_derived_write_attribute<MVert,
float3,
get_vertex_position,
set_vertex_position,
ATTR_DOMAIN_POINT>,
tag_normals_dirty_when_writing_position);
static NormalAttributeProvider normal;
static BuiltinCustomDataLayerProvider material_index("material_index",
ATTR_DOMAIN_POLYGON,
CD_PROP_INT32,
CD_MPOLY,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
polygon_access,
make_material_index_read_attribute,
make_material_index_write_attribute,
nullptr);
static BuiltinCustomDataLayerProvider material_index(
"material_index",
ATTR_DOMAIN_FACE,
CD_PROP_INT32,
CD_MPOLY,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
face_access,
make_derived_read_attribute<MPoly, int, get_material_index, ATTR_DOMAIN_FACE>,
make_derived_write_attribute<MPoly,
int,
get_material_index,
set_material_index,
ATTR_DOMAIN_FACE>,
nullptr);
static BuiltinCustomDataLayerProvider shade_smooth("shade_smooth",
ATTR_DOMAIN_POLYGON,
CD_PROP_BOOL,
CD_MPOLY,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
polygon_access,
make_shade_smooth_read_attribute,
make_shade_smooth_write_attribute,
nullptr);
static BuiltinCustomDataLayerProvider shade_smooth(
"shade_smooth",
ATTR_DOMAIN_FACE,
CD_PROP_BOOL,
CD_MPOLY,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
face_access,
make_derived_read_attribute<MPoly, bool, get_shade_smooth, ATTR_DOMAIN_FACE>,
make_derived_write_attribute<MPoly,
bool,
get_shade_smooth,
set_shade_smooth,
ATTR_DOMAIN_FACE>,
nullptr);
static BuiltinCustomDataLayerProvider crease("crease",
ATTR_DOMAIN_EDGE,
CD_PROP_FLOAT,
CD_MEDGE,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
edge_access,
make_crease_read_attribute,
make_crease_write_attribute,
nullptr);
static BuiltinCustomDataLayerProvider crease(
"crease",
ATTR_DOMAIN_EDGE,
CD_PROP_FLOAT,
CD_MEDGE,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
edge_access,
make_derived_read_attribute<MEdge, float, get_crease, ATTR_DOMAIN_EDGE>,
make_derived_write_attribute<MEdge, float, get_crease, set_crease, ATTR_DOMAIN_EDGE>,
nullptr);
static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER,
CD_PROP_FLOAT2,
CD_MLOOPUV,
corner_access,
make_uvs_read_attribute,
make_uvs_write_attribute);
static NamedLegacyCustomDataProvider uvs(
ATTR_DOMAIN_CORNER,
CD_PROP_FLOAT2,
CD_MLOOPUV,
corner_access,
make_derived_read_attribute<MLoopUV, float2, get_loop_uv, ATTR_DOMAIN_CORNER>,
make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv, ATTR_DOMAIN_CORNER>);
static NamedLegacyCustomDataProvider vertex_colors(ATTR_DOMAIN_CORNER,
CD_PROP_COLOR,
CD_MLOOPCOL,
corner_access,
make_vertex_color_read_attribute,
make_vertex_color_write_attribute);
static NamedLegacyCustomDataProvider vertex_colors(
ATTR_DOMAIN_CORNER,
CD_PROP_COLOR,
CD_MLOOPCOL,
corner_access,
make_derived_read_attribute<MLoopCol, Color4f, get_loop_color, ATTR_DOMAIN_CORNER>,
make_derived_write_attribute<MLoopCol,
Color4f,
get_loop_color,
set_loop_color,
ATTR_DOMAIN_CORNER>);
static VertexGroupsAttributeProvider vertex_groups;
static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access);
static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access);
static CustomDataAttributeProvider face_custom_data(ATTR_DOMAIN_FACE, face_access);
return ComponentAttributeProviders({&position, &material_index, &shade_smooth, &normal, &crease},
{&uvs,
@@ -1214,7 +1179,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
&vertex_groups,
&point_custom_data,
&edge_custom_data,
&polygon_custom_data});
&face_custom_data});
}
} // namespace blender::bke

View File

@@ -205,6 +205,12 @@ uint64_t GeometrySet::hash() const
return reinterpret_cast<uint64_t>(this);
}
/* Remove all geometry components from the geometry set. */
void GeometrySet::clear()
{
components_.clear();
}
/* Returns a read-only mesh or null. */
const Mesh *GeometrySet::get_mesh_for_read() const
{

View File

@@ -153,16 +153,13 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
*
* \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
*/
Vector<GeometryInstanceGroup> geometry_set_gather_instances(const GeometrySet &geometry_set)
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups)
{
Vector<GeometryInstanceGroup> result_vector;
float4x4 unit_transform;
unit_m4(unit_transform.values);
geometry_set_collect_recursive(geometry_set, unit_transform, result_vector);
return result_vector;
geometry_set_collect_recursive(geometry_set, unit_transform, r_instance_groups);
}
void gather_attribute_info(Map<std::string, AttributeKind> &attributes,
@@ -436,7 +433,8 @@ GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_s
}
GeometrySet new_geometry_set = geometry_set;
Vector<GeometryInstanceGroup> set_groups = geometry_set_gather_instances(geometry_set);
Vector<GeometryInstanceGroup> set_groups;
geometry_set_gather_instances(geometry_set, set_groups);
join_instance_groups_mesh(set_groups, true, new_geometry_set);
/* Remove all instances, even though some might contain other non-mesh data. We can't really
* keep only non-mesh instances in general. */
@@ -454,7 +452,8 @@ GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
GeometrySet new_geometry_set;
Vector<GeometryInstanceGroup> set_groups = geometry_set_gather_instances(geometry_set);
Vector<GeometryInstanceGroup> set_groups;
geometry_set_gather_instances(geometry_set, set_groups);
join_instance_groups_mesh(set_groups, false, new_geometry_set);
join_instance_groups_pointcloud(set_groups, new_geometry_set);
join_instance_groups_volume(set_groups, new_geometry_set);

View File

@@ -3663,7 +3663,7 @@ static int generate_perimeter_cap(const float point[4],
/**
* Calculate the perimeter (outline) of a stroke as list of tPerimeterPoint.
* \param subdivisions: Number of subdivions for the start and end caps
* \param subdivisions: Number of subdivisions for the start and end caps
* \return: list of tPerimeterPoint
*/
static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
@@ -3710,7 +3710,7 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
copy_v3_v3(first_next_pt, &first_next->x);
copy_v3_v3(last_prev_pt, &last_prev->x);
/* edgecase if single point */
/* Edge-case if single point. */
if (gps->totpoints == 1) {
first_next_pt[0] += 1.0f;
last_prev_pt[0] -= 1.0f;
@@ -3784,7 +3784,7 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
negate_v2(vec_miter_right);
float angle = dot_v2v2(vec_next, nvec_prev);
/* add two points if angle is close to beeing straight */
/* Add two points if angle is close to being straight. */
if (fabsf(angle) < 0.0001f) {
normalize_v2_length(nvec_prev, radius);
normalize_v2_length(nvec_next, radius);
@@ -3910,7 +3910,7 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
/**
* Calculates the perimeter of a stroke projected from the view and
* returns it as a new stroke.
* \param subdivisions: Number of subdivions for the start and end caps
* \param subdivisions: Number of subdivisions for the start and end caps
* \return: bGPDstroke pointer to stroke perimeter
*/
bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,

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