1
1

Compare commits

..

147 Commits

Author SHA1 Message Date
0176b0f217 add missing include 2021-04-17 14:49:00 +02:00
54adef5ac4 cleanup 2021-04-17 14:47:10 +02:00
a45e9ad95a cleanup 2021-04-17 14:24:04 +02:00
d9df155004 cleanup 2021-04-17 14:23:21 +02:00
dc87e3e2f4 Merge branch 'master' into virtual-array-attributes 2021-04-17 13:53:52 +02:00
e524a6ecf7 Snap Gizmo: Improve event comparison code
Better distinction between modifier key events and mouse position events.

No functional changes.
2021-04-16 14:44:10 -03:00
fc37b265c8 Merge branch 'blender-v2.93-release' 2021-04-16 11:42:36 -05:00
b2a0f69275 Fix T87555: Incorrect view transform default in startup file
This was another error in rBac90c8a7743f. It turns out it's quite
important to use a full build to save the file, which I didn't do then.
2021-04-16 11:41:49 -05:00
7eda4cde71 Merge branch 'blender-v2.93-release' 2021-04-16 18:00:38 +02:00
463b38b0e0 GPencil: Remove Grease Pencil menu options in UV editor
Differential Revision: https://developer.blender.org/D10993
2021-04-16 18:00:18 +02:00
cf6d10ef46 Merge branch 'blender-v2.93-release' 2021-04-16 17:44:36 +02:00
0f81dafe6c Fix T87010: VSE: adding strips crashes in certain files
Caused by {rB571362642201} where versioning code for new sequencer tool
settings was only done for scenes already having sequencer scene->ed.

If scene->ed was not present, sequencer tool settings were never
initalized for this scene [if the VSE was then used later], leading to
crashes in some places.

Now just use the versioning code to initalize sequencer tool settings
for all scenes not having them yet.

Maniphest Tasks: T87010

Differential Revision: https://developer.blender.org/D10996
2021-04-16 17:42:10 +02:00
537460b86d Merge branch 'blender-v2.93-release' 2021-04-17 01:32:28 +10:00
0bf630493f Fix missing owner_id values from 919558854d
This prevented dynamic enum callbacks being called.
2021-04-17 01:29:51 +10:00
c7a8bcfa37 Merge branch 'blender-v2.93-release' 2021-04-17 00:21:30 +10:00
fa4b2d25cb WM: remove redundant click-drag offset for gizmo highlight checking
Tweak and click-drag events already apply this offset, this was a no-op.
2021-04-17 00:20:19 +10:00
bfc0f483c6 Merge branch 'blender-v2.93-release' 2021-04-16 23:53:04 +10:00
7bbead1e87 WM: prevent drag events being continually tested
Click-drag events that weren't handled would continually be tested
for each mouse-motion event.

As well as being redundant, this added the overhead of querying
gizmos twice per motion event.

Now click-drag is only tested once when the drag threshold is reached.

This mitigates T87511, although the single drag test still causes
the snap gizmo to flicker.
2021-04-16 23:50:05 +10:00
ddeaa42a35 Geometry Nodes: Use virtual arrays in internal attribute api (WIP).
Differential Revision: https://developer.blender.org/D10994
2021-04-16 15:47:04 +02:00
fc719e98aa check for empty attribute name 2021-04-16 15:42:03 +02:00
cff359cdff cleanup 2021-04-16 15:27:06 +02:00
649803ea55 cleanup 2021-04-16 15:24:46 +02:00
83cd472416 fix 2021-04-16 15:08:07 +02:00
76d7e3a0cc rename apply to save 2021-04-16 15:03:41 +02:00
43b56426f6 Merge branch 'master' into virtual-array-attributes 2021-04-16 14:54:06 +02:00
7aa38de085 Merge branch 'blender-v2.93-release' 2021-04-16 22:14:56 +10:00
0edfa5350e Merge branch 'blender-v2.93-release' 2021-04-16 22:14:53 +10:00
278b19745b Cleanup: clang-format 2021-04-16 22:13:05 +10:00
afd8e4bce7 Fix BLO_library_temp_load_id loading temporary ID's into G.main
The intention with this API function was to temporarily load
ID's tagged LIB_TAG_TEMP_MAIN,
however the way the `real_main` was used,
these ID's were loaded into the G.main.
2021-04-16 22:13:05 +10:00
be34d14575 Merge branch 'blender-v2.93-release' 2021-04-16 13:46:21 +02:00
68c4ba3482 Fix T87522: frame selected does not take instances into account
`ob->runtime.geometry_set_eval` can contain instances as well.

This only affected instances generated by geometry nodes.
We should probably have a separate function that tells us if an object
has instances or not..
2021-04-16 13:43:29 +02:00
1266df87c8 Fix unreported: instances disappear when instanced mesh is in edit mode
The issue is that for historic reasons, `geometry_set_eval` does not contain
the mesh component when the object is in edit mode.
2021-04-16 13:05:49 +02:00
bb9c83b9ff Remove unneeded code from previous commit. 2021-04-16 13:04:45 +02:00
ea7eff1cc8 Fix OCIO Shader Compilation Error.
Compilation fails when our OCIO wrapper creates a shader that
transfer first to scene ref and directly after that to display.
This cause is that the GPU resources of both transfers had the same
name. This is fixed by prefixing the resources.

This can be reproduced by loading a movie file (mkv) in the VSE editor.
Reported by Sergey Sharybin.
2021-04-16 12:54:53 +02:00
4bef49e32b Fix T87169: support attribute search on group nodes 2021-04-16 11:56:04 +02:00
ca37d8485c Fix T87217: improve impact of seed in point distribute node
Incrementing the seed just by one did not mix things up enough.
2021-04-16 11:43:16 +02:00
Wannes Malfait
58818cba40 Fix T87359: set group output in geometry node tree update callback
This also fixes T85511.

Differential Revision: https://developer.blender.org/D10970
2021-04-16 11:37:49 +02:00
a2e4d81849 Fix T87441: don't remove custom attributes automatically
In the past, custom attributes were rarely used in practice, because the
only way to use them was from Python. Since geometry nodes, more
users started to add their own attributes. Those attributes should not
be removed automatically. It is still possible to remove them in
geometry nodes explictly to improve performance.
2021-04-16 11:28:23 +02:00
382b06c80c Fix T85691: attributes used by geometry nodes were removed automatically
This has technically been fixed by rB3e87d8a4315d794efff659e40f0bb9e34e2aec8a,
but the fix there is questionable, because it disables an optimization for vertex groups
entirely. This fix is a little bit more precise in that it only disables the optimization when
the object is used by some geometry nodes modifier.
2021-04-16 11:23:28 +02:00
45eafd6562 Merge branch 'blender-v2.93-release' 2021-04-16 15:10:57 +10:00
073ef4d265 Merge branch 'blender-v2.93-release' 2021-04-16 15:10:52 +10:00
919558854d Fix T65064: Keymaps items controlling dynamic enums fail to export
Keymap UI and import/export could depend on the current
context for dynamic enum's.

Use STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID for OperatorProperties.
2021-04-16 15:08:49 +10:00
43b08d0578 RNA: add STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID flag
This flag is needed so PointerRNA structs that aren't
part of the current context can access enum values
without inspecting the context.

This is needed for keymap access, so the keymap UI and keymap
export doesn't depend on the current context.
2021-04-16 15:04:37 +10:00
cb4646a6df Merge branch 'blender-v2.93-release' 2021-04-16 12:20:38 +10:00
dc8a43c875 Fix RNA enum item callbacks not checking for NULL context
The NULL context is used to extract items for document generation.
2021-04-16 12:19:02 +10:00
0567f2b0bb Merge branch 'blender-v2.93-release' 2021-04-15 23:15:24 -03:00
43baf38758 Snap Gizmo: Minor optimization in detecting toggle inversion
Do not compare the x and y values of the mouse to check inversion.

Also remove "Lazy Initialization".
2021-04-15 23:13:59 -03:00
62bff15377 Fix various Blender 3.0 versioning issues
This changes the following items:

- package name is now `blender-3.0.0-git.09eb04c0a865-windows64`
  rather than `blender-3.00.0-git.09eb04c0a865-windows64`
- Fix version resource for blender.exe not building
- Data directories are now `3.0\...` rather than `3.00\....`
- User prefs are now in:
  `c:\Users\users\AppData\Roaming\Blender Foundation\Blender\3.0\`
  rather than:
  `c:\Users\users\AppData\Roaming\Blender Foundation\Blender\3.00\`
- Updating startup & preferences from previous release
  has a special exception for 3.0 to check for 3.93 and older.

See T87532

Ref D10986
2021-04-16 11:23:34 +10:00
ec241eb0d0 Merge branch 'blender-v2.93-release' 2021-04-15 19:14:23 +02:00
fa8d566c3b GPencil: Avoid invisible strokes in PDF export
There were still some invisible strokes.
2021-04-15 19:14:00 +02:00
018fa1fce3 Cleanup: Use correct float format 2021-04-15 19:14:00 +02:00
32d3b07b03 RNA: Silence warning when building without audaspace
`make lite` does not use audaspace, so some files will pollute the console with
tons of warnings about audio values not defined.

Reviewed By: nexyon, campbellbarton

Differential Revision: https://developer.blender.org/D10981
2021-04-15 17:50:58 +02:00
09eb04c0a8 Merge branch 'blender-v2.93-release' 2021-04-15 17:26:18 +02:00
5425388e60 GPencil: Fix unreported error exporting big files in PDF
The exporting was creating a pdf state for each stroke, but this was necessary only for strokes with opacity.

Now, the state is only created when needed and remove the state variable from class.

Also, avoid exporting invisible strokes.
2021-04-15 17:25:24 +02:00
fa4265517a cleanup 2021-04-15 17:12:27 +02:00
57f87a22b2 cleanups and fixes 2021-04-15 17:04:38 +02:00
f0cdfa3539 rename to get_internal_single 2021-04-15 16:45:40 +02:00
a26f710d62 rename to get_internal_span 2021-04-15 16:44:05 +02:00
b117fe7817 fix some bugs 2021-04-15 16:41:59 +02:00
ced26bacb7 Merge branch 'blender-v2.93-release' 2021-04-15 09:17:12 -05:00
a4877f9e54 Fix text in startup file python console
This was a mistake in rBac90c8a7743f6d0
2021-04-15 09:16:00 -05:00
32849bb7b9 implement mutable converted virtual array 2021-04-15 16:12:57 +02:00
3b71133dc5 better output attribute 2021-04-15 16:02:20 +02:00
27005f58c5 Blender Python version string to use the new version number system 2021-04-15 16:01:50 +02:00
bd8fd78b40 Merge branch 'blender-v2.93-release' 2021-04-15 15:52:44 +02:00
5b2353b230 Blender 2.93 splascreen
Credit: Erindale Woodford - youtube.com/erindale /
twitter.com/erindale_xyz
2021-04-15 15:47:07 +02:00
51991ffd38 Blender 2.93 bcon3 (beta) version bump 2021-04-15 15:46:45 +02:00
6e39da7948 Blender 3.0 version bump
Blender 3.0 is now in bcon1 (alpha).

There are likely a few places in Blender and the automated building pipeline
that may fail since we are switching our versioning number system.

For example, at the moment the splash and the status bar are showing
3.00.0, and it should show 3.1.0.

I suspect the Python API, version used to report a bug, buildname, are
all wrong too. These will be handled later.
2021-04-15 15:42:41 +02:00
659dc3f593 cleanup 2021-04-15 15:39:16 +02:00
d169314f9b Bump subversion before starting the next release cycle 2021-04-15 15:32:48 +02:00
61c3d7aa2c Bump subversion before starting the next release cycle 2021-04-15 15:32:17 +02:00
ecc2db8a3a UI: Rename itmes in point cloud add attribute menu
Since these were added, we decided that builtin and reserved name
attributes start with a lowercase letter. We also use "id" already in
a few nodes, so this change will be consistent with that.
2021-04-15 07:53:45 -05:00
27e13a608f GPencil: Change UI text and tooltip
The text was not changed in the refactor and had the old text.
2021-04-15 14:22:57 +02:00
5c067189e3 Fix T87434: spreadsheet shows same column more than once 2021-04-15 13:19:27 +02:00
d2c047999b start implementing output attribute 2021-04-15 13:07:52 +02:00
6e29a9459b bring back type conversion 2021-04-15 12:04:31 +02:00
4cf3010714 Fix T87171: Update multi input socket indices
When inserting a node on top of a link, the multi input socket
indices weren't updated. This fixes that and keeps the relative
order of the links the same.

Author: Wannes Malfait

Reviewed By: Fabian Schempp

Differential Revision: https://developer.blender.org/D10969
2021-04-15 11:38:46 +02:00
6243ddd265 Merge branch 'master' into virtual-array-attributes 2021-04-15 11:34:19 +02:00
05dbbd83f0 Geometry Nodes: refactor implicit conversions
This refactor simplifies having standalone function pointer that
does a single conversion. It also speeds up implicit type conversion
of attributes.
2021-04-15 11:21:48 +02:00
87da0a30a0 Merge branch 'master' into virtual-array-attributes 2021-04-15 09:38:14 +02:00
413da88b89 Merge branch 'master' into virtual-array-attributes 2021-04-15 09:21:58 +02:00
9eaec84655 cleanup 2021-04-14 12:49:10 +02:00
8c720c2771 rename 2021-04-14 12:41:26 +02:00
cd6a5b1b19 simplify generic virtual array span 2021-04-14 12:38:00 +02:00
0ca666880d simplify virtual array spans 2021-04-14 12:06:11 +02:00
f3c257cc06 Merge branch 'master' into virtual-array-attributes 2021-04-14 11:15:37 +02:00
e4da3694ab fix compilation errors 2021-04-13 17:34:30 +02:00
0a6b03ef08 progress 2021-04-13 16:49:06 +02:00
2d5aef8af8 Merge branch 'master' into virtual-array-attributes 2021-04-13 16:40:34 +02:00
4f110ac739 fix some compilation issues 2021-04-13 13:25:36 +02:00
77496742d9 progress 2021-04-13 13:21:39 +02:00
8ea0243916 cleanup 2021-04-13 13:15:00 +02:00
e37bc4e28d progress 2021-04-13 12:58:53 +02:00
30fe7038bc progress 2021-04-13 12:53:10 +02:00
d9859ef766 cleanup 2021-04-13 12:23:59 +02:00
99289e8d51 cleanup 2021-04-13 12:23:04 +02:00
4226d550c0 fixes 2021-04-13 11:56:17 +02:00
0d68a1dc77 Merge branch 'master' into virtual-array-attributes 2021-04-13 11:51:32 +02:00
d1c39eb90f cleanup 2021-04-13 09:01:42 +02:00
6ba48a78d2 initial typed output attribute 2021-04-13 08:38:01 +02:00
90791063eb rename 2021-04-13 08:28:16 +02:00
626b7e4556 add materialize parameter 2021-04-13 08:26:43 +02:00
5a079d42ab cleanup 2021-04-12 18:27:41 +02:00
2091edbda6 Merge branch 'master' into virtual-array-attributes 2021-04-12 18:22:35 +02:00
e891fc8f11 progress 2021-04-12 18:21:37 +02:00
3ce30fa159 progress 2021-04-12 18:04:29 +02:00
6e08dcd5d3 progress 2021-04-12 17:59:47 +02:00
af504c01b7 progress 2021-04-12 17:53:18 +02:00
df2c96e8a9 progress 2021-04-12 17:35:38 +02:00
37da2b60fe progress 2021-04-12 17:20:26 +02:00
5239a774c5 progress 2021-04-12 16:55:52 +02:00
ccce11d651 support optional ownership 2021-04-11 12:21:24 +02:00
0b8c280d99 cleanup 2021-04-11 12:19:54 +02:00
19389787ff support typed 2021-04-11 12:13:33 +02:00
61cafa7605 cleanup naming 2021-04-11 12:08:34 +02:00
f07159485e cleanup naming 2021-04-11 12:07:52 +02:00
81a5c6f826 cleanup naming 2021-04-11 12:05:46 +02:00
534977ad3a improve conversion to typed 2021-04-11 12:03:50 +02:00
d609705cb9 cleanup 2021-04-11 11:48:29 +02:00
36446b587b add typed ref utilities 2021-04-11 11:47:46 +02:00
ff00a89a69 Merge branch 'master' into virtual-array-attributes 2021-04-11 11:26:59 +02:00
a3dfcd003a cleanup 2021-04-10 18:55:07 +02:00
c6a96dcaf9 move more to implementation file 2021-04-10 18:50:54 +02:00
e439cc5e69 add GVArray_For_SingleValue 2021-04-10 18:48:44 +02:00
8116372289 cleanup 2021-04-10 18:43:06 +02:00
14c3f379c9 add utility classes 2021-04-10 18:35:58 +02:00
5f40621496 add as generic span classe 2021-04-10 18:04:40 +02:00
569dc4e7f0 cleanup 2021-04-10 17:54:29 +02:00
4bddffbeb8 gspan conversion 2021-04-10 17:52:50 +02:00
c8f93066e3 cleanup 2021-04-10 17:51:44 +02:00
2367dd2a81 cleanup 2021-04-10 17:42:52 +02:00
5f564f2f55 cleanup naming 2021-04-10 17:42:03 +02:00
5b12dacb11 cleanup 2021-04-10 17:19:37 +02:00
1352e7bb25 cleanup 2021-04-10 17:15:48 +02:00
c0b7b16167 add GVMutableArrayForVMutableArray 2021-04-10 17:11:40 +02:00
406424e09d cleanup 2021-04-10 17:03:44 +02:00
bfb6ba2fa7 cleanup 2021-04-10 17:00:00 +02:00
bb579c4964 simplify 2021-04-10 16:56:28 +02:00
45883793e5 add VMutableArrayForGVMutableArray 2021-04-10 16:46:40 +02:00
99921148e2 add optional ownership 2021-04-10 16:37:28 +02:00
d4e3b8c356 derived span 2021-04-10 16:34:31 +02:00
418d364836 add optional ownership 2021-04-10 16:16:18 +02:00
7df5a34580 add GVArrayForEmbeddedVArray 2021-04-10 16:13:36 +02:00
4be6da2586 generic mutable array 2021-04-10 16:01:23 +02:00
f19e83f347 add typed mutable virtual array 2021-04-10 14:11:29 +02:00
488fc4eb50 more virtual arrays 2021-04-10 13:55:11 +02:00
5b9cad04c6 add virtual array for container 2021-04-10 13:14:42 +02:00
97 changed files with 3298 additions and 2553 deletions

View File

@@ -85,8 +85,8 @@ class VersionInfo:
version_number = int(self._parse_header_file(blender_h, 'BLENDER_VERSION'))
version_number_patch = int(self._parse_header_file(blender_h, 'BLENDER_VERSION_PATCH'))
version_numbers = (version_number // 100, version_number % 100, version_number_patch)
self.short_version = "%d.%02d" % (version_numbers[0], version_numbers[1])
self.version = "%d.%02d.%d" % version_numbers
self.short_version = "%d.%d" % (version_numbers[0], version_numbers[1])
self.version = "%d.%d.%d" % version_numbers
self.version_cycle = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE')
self.hash = self._parse_header_file(buildinfo_h, 'BUILD_HASH')[1:-1]

View File

@@ -923,10 +923,6 @@ function(get_blender_version)
math(EXPR _out_version_major "${_out_version} / 100")
math(EXPR _out_version_minor "${_out_version} % 100")
# Zero pad the minor version so `_out_version_minor` is always two characters.
# This is needed if the minor version is a single digit.
string(REGEX REPLACE "^([0-9])$" "0\\1" _out_version_minor "${_out_version_minor}")
# output vars
set(BLENDER_VERSION "${_out_version_major}.${_out_version_minor}" PARENT_SCOPE)
set(BLENDER_VERSION_MAJOR "${_out_version_major}" PARENT_SCOPE)

View File

@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = "V2.93"
PROJECT_NUMBER = "V3.0"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

View File

@@ -561,6 +561,7 @@ static OCIO_GPUDisplayShader &getGPUDisplayShader(
GpuShaderDescRcPtr shaderdesc_to_scene_linear = GpuShaderDesc::CreateShaderDesc();
shaderdesc_to_scene_linear->setLanguage(GPU_LANGUAGE_GLSL_1_3);
shaderdesc_to_scene_linear->setFunctionName("OCIO_to_scene_linear");
shaderdesc_to_scene_linear->setResourcePrefix("to_scene");
(*(ConstProcessorRcPtr *)processor_to_scene_linear)
->getDefaultGPUProcessor()
->extractGpuShaderInfo(shaderdesc_to_scene_linear);
@@ -569,6 +570,7 @@ static OCIO_GPUDisplayShader &getGPUDisplayShader(
GpuShaderDescRcPtr shaderdesc_to_display = GpuShaderDesc::CreateShaderDesc();
shaderdesc_to_display->setLanguage(GPU_LANGUAGE_GLSL_1_3);
shaderdesc_to_display->setFunctionName("OCIO_to_display");
shaderdesc_to_scene_linear->setResourcePrefix("to_display");
(*(ConstProcessorRcPtr *)processor_to_display)
->getDefaultGPUProcessor()
->extractGpuShaderInfo(shaderdesc_to_display);

Binary file not shown.

View File

@@ -99,6 +99,15 @@ class PREFERENCES_OT_copy_prev(Operator):
version = bpy.app.version
version_new = ((version[0] * 100) + version[1])
version_old = ((version[0] * 100) + version[1]) - 1
# Special case, remove when the version is > 3.0.
if version_new == 300:
version_new = 294
version_old = 293
else:
print("TODO: remove exception!")
# End special case.
# Ensure we only try to copy files from a point release.
# The check below ensures the second numbers match.
while (version_new % 100) // 10 == (version_old % 100) // 10:

View File

@@ -71,10 +71,10 @@ class POINTCLOUD_MT_add_attribute(Menu):
layout = self.layout
pointcloud = context.pointcloud
self.add_standard_attribute(layout, pointcloud, 'Radius', 'FLOAT', 'POINT')
self.add_standard_attribute(layout, pointcloud, 'Color', 'FLOAT_COLOR', 'POINT')
self.add_standard_attribute(layout, pointcloud, 'Particle ID', 'INT', 'POINT')
self.add_standard_attribute(layout, pointcloud, 'Velocity', 'FLOAT_VECTOR', 'POINT')
self.add_standard_attribute(layout, pointcloud, 'radius', 'FLOAT', 'POINT')
self.add_standard_attribute(layout, pointcloud, 'color', 'FLOAT_COLOR', 'POINT')
self.add_standard_attribute(layout, pointcloud, 'id', 'INT', 'POINT')
self.add_standard_attribute(layout, pointcloud, 'velocity', 'FLOAT_VECTOR', 'POINT')
layout.separator()

View File

@@ -246,11 +246,12 @@ class IMAGE_MT_image(Menu):
layout.separator()
layout.operator("image.pack", text="Pack")
if ima:
if ima and context.area.ui_type == 'IMAGE_EDITOR':
layout.separator()
layout.operator("palette.extract_from_image", text="Extract Palette")
layout.operator("gpencil.image_to_grease_pencil", text="Generate Grease Pencil")
class IMAGE_MT_image_flip(Menu):
bl_label = "Flip"

View File

@@ -20,6 +20,7 @@
#include "FN_cpp_type.hh"
#include "FN_generic_span.hh"
#include "FN_generic_virtual_array.hh"
#include "BKE_attribute.h"
@@ -30,49 +31,78 @@
namespace blender::bke {
using fn::CPPType;
using fn::GVArray;
using fn::GVMutableArray;
const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_types);
AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains);
/**
* This class offers an indirection for reading an attribute.
* This is useful for the following reasons:
* - Blender does not store all attributes the same way.
* The simplest case are custom data layers with primitive types.
* A bit more complex are mesh attributes like the position of vertices,
* which are embedded into the MVert struct.
* Even more complex to access are vertex weights.
* - Sometimes attributes are stored on one domain, but we want to access
* the attribute on a different domain. Therefore, we have to interpolate
* between the domains.
*/
class ReadAttribute {
protected:
const AttributeDomain domain_;
const CPPType &cpp_type_;
const CustomDataType custom_data_type_;
const int64_t size_;
struct ReadAttributeLookup {
std::unique_ptr<GVArray> varray;
AttributeDomain domain;
/* Protects the span below, so that no two threads initialize it at the same time. */
mutable std::mutex span_mutex_;
/* When it is not null, it points to the attribute array or a temporary array that contains all
* the attribute values. */
mutable void *array_buffer_ = nullptr;
/* Is true when the buffer above is owned by the attribute accessor. */
mutable bool array_is_temporary_ = false;
operator bool() const
{
return this->varray.get() != nullptr;
}
};
struct WriteAttributeLookup {
std::unique_ptr<GVMutableArray> varray;
AttributeDomain domain;
operator bool() const
{
return this->varray.get() != nullptr;
}
};
class OutputAttribute {
public:
using SaveFn = std::function<void(OutputAttribute &)>;
private:
std::unique_ptr<GVMutableArray> varray_;
AttributeDomain domain_;
SaveFn save_;
std::optional<fn::GVMutableArray_GSpan> optional_span_varray_;
bool ignore_old_values_ = false;
public:
ReadAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size)
: domain_(domain),
cpp_type_(cpp_type),
custom_data_type_(cpp_type_to_custom_data_type(cpp_type)),
size_(size)
OutputAttribute() = default;
OutputAttribute(std::unique_ptr<GVMutableArray> varray,
AttributeDomain domain,
SaveFn save,
const bool ignore_old_values)
: varray_(std::move(varray)),
domain_(domain),
save_(std::move(save)),
ignore_old_values_(ignore_old_values)
{
}
virtual ~ReadAttribute();
operator bool() const
{
return varray_.get() != nullptr;
}
GVMutableArray &operator*()
{
return *varray_;
}
GVMutableArray *operator->()
{
return varray_.get();
}
GVMutableArray &varray()
{
return *varray_;
}
AttributeDomain domain() const
{
@@ -81,238 +111,91 @@ class ReadAttribute {
const CPPType &cpp_type() const
{
return cpp_type_;
return varray_->type();
}
CustomDataType custom_data_type() const
{
return custom_data_type_;
return cpp_type_to_custom_data_type(this->cpp_type());
}
int64_t size() const
fn::GMutableSpan as_span()
{
return size_;
if (!optional_span_varray_.has_value()) {
const bool materialize_old_values = !ignore_old_values_;
optional_span_varray_.emplace(*varray_, materialize_old_values);
}
fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_;
return span_varray;
}
void get(const int64_t index, void *r_value) const
template<typename T> MutableSpan<T> as_span()
{
BLI_assert(index < size_);
this->get_internal(index, r_value);
return this->as_span().typed<T>();
}
/* Get a span that contains all attribute values. */
fn::GSpan get_span() const;
template<typename T> Span<T> get_span() const
{
return this->get_span().typed<T>();
}
protected:
/* r_value is expected to be uninitialized. */
virtual void get_internal(const int64_t index, void *r_value) const = 0;
virtual void initialize_span() const;
void save();
};
/**
* This exists for similar reasons as the ReadAttribute class, except that
* it does not deal with interpolation between domains.
*/
class WriteAttribute {
protected:
const AttributeDomain domain_;
const CPPType &cpp_type_;
const CustomDataType custom_data_type_;
const int64_t size_;
/* When not null, this points either to the attribute array or to a temporary array. */
void *array_buffer_ = nullptr;
/* True, when the buffer points to a temporary array. */
bool array_is_temporary_ = false;
/* This helps to protect against forgetting to apply changes done to the array. */
bool array_should_be_applied_ = false;
template<typename T> class OutputAttribute_Typed {
private:
OutputAttribute attribute_;
std::optional<fn::GVMutableArray_Typed<T>> optional_varray_;
VMutableArray<T> *varray_ = nullptr;
public:
WriteAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size)
: domain_(domain),
cpp_type_(cpp_type),
custom_data_type_(cpp_type_to_custom_data_type(cpp_type)),
size_(size)
OutputAttribute_Typed(OutputAttribute attribute) : attribute_(std::move(attribute))
{
if (attribute_) {
optional_varray_.emplace(attribute_.varray());
varray_ = &**optional_varray_;
}
}
virtual ~WriteAttribute();
operator bool() const
{
return varray_ != nullptr;
}
VMutableArray<T> &operator*()
{
return *varray_;
}
VMutableArray<T> *operator->()
{
return varray_;
}
VMutableArray<T> &varray()
{
return *varray_;
}
AttributeDomain domain() const
{
return domain_;
return attribute_.domain();
}
const CPPType &cpp_type() const
{
return cpp_type_;
return CPPType::get<T>();
}
CustomDataType custom_data_type() const
{
return custom_data_type_;
return cpp_type_to_custom_data_type(this->cpp_type());
}
int64_t size() const
MutableSpan<T> as_span()
{
return size_;
return attribute_.as_span<T>();
}
void get(const int64_t index, void *r_value) const
void save()
{
BLI_assert(index < size_);
this->get_internal(index, r_value);
}
void set(const int64_t index, const void *value)
{
BLI_assert(index < size_);
this->set_internal(index, value);
}
/* Get a span that new attribute values can be written into. When all values have been changed,
* #apply_span has to be called. */
fn::GMutableSpan get_span();
/* The span returned by this method might not contain the current attribute values. */
fn::GMutableSpan get_span_for_write_only();
/* Write the changes to the span into the actual attribute, if they aren't already. */
void apply_span();
template<typename T> MutableSpan<T> get_span()
{
return this->get_span().typed<T>();
}
template<typename T> MutableSpan<T> get_span_for_write_only()
{
return this->get_span_for_write_only().typed<T>();
}
protected:
virtual void get_internal(const int64_t index, void *r_value) const = 0;
virtual void set_internal(const int64_t index, const void *value) = 0;
virtual void initialize_span(const bool write_only);
virtual void apply_span_if_necessary();
};
using ReadAttributePtr = std::unique_ptr<ReadAttribute>;
using WriteAttributePtr = std::unique_ptr<WriteAttribute>;
/* This provides type safe access to an attribute.
* The underlying ReadAttribute is owned optionally. */
template<typename T> class TypedReadAttribute {
private:
std::unique_ptr<const ReadAttribute> owned_attribute_;
const ReadAttribute *attribute_;
public:
TypedReadAttribute(ReadAttributePtr attribute) : TypedReadAttribute(*attribute)
{
owned_attribute_ = std::move(attribute);
BLI_assert(owned_attribute_);
}
TypedReadAttribute(const ReadAttribute &attribute) : attribute_(&attribute)
{
BLI_assert(attribute_->cpp_type().is<T>());
}
int64_t size() const
{
return attribute_->size();
}
T operator[](const int64_t index) const
{
BLI_assert(index < attribute_->size());
T value;
value.~T();
attribute_->get(index, &value);
return value;
}
/* Get a span to that contains all attribute values for faster and more convenient access. */
Span<T> get_span() const
{
return attribute_->get_span().template typed<T>();
attribute_.save();
}
};
/* This provides type safe access to an attribute.
* The underlying WriteAttribute is owned optionally. */
template<typename T> class TypedWriteAttribute {
private:
std::unique_ptr<WriteAttribute> owned_attribute_;
WriteAttribute *attribute_;
public:
TypedWriteAttribute(WriteAttributePtr attribute) : TypedWriteAttribute(*attribute)
{
owned_attribute_ = std::move(attribute);
BLI_assert(owned_attribute_);
}
TypedWriteAttribute(WriteAttribute &attribute) : attribute_(&attribute)
{
BLI_assert(attribute_->cpp_type().is<T>());
}
int64_t size() const
{
return attribute_->size();
}
T operator[](const int64_t index) const
{
BLI_assert(index < attribute_->size());
T value;
value.~T();
attribute_->get(index, &value);
return value;
}
void set(const int64_t index, const T &value)
{
attribute_->set(index, &value);
}
/* Get a span that new values can be written into. Once all values have been updated #apply_span
* has to be called. */
MutableSpan<T> get_span()
{
return attribute_->get_span().typed<T>();
}
/* The span returned by this method might not contain the current attribute values. */
MutableSpan<T> get_span_for_write_only()
{
return attribute_->get_span_for_write_only().typed<T>();
}
/* Write back all changes to the actual attribute, if necessary. */
void apply_span()
{
attribute_->apply_span();
}
};
using BooleanReadAttribute = TypedReadAttribute<bool>;
using FloatReadAttribute = TypedReadAttribute<float>;
using Float2ReadAttribute = TypedReadAttribute<float2>;
using Float3ReadAttribute = TypedReadAttribute<float3>;
using Int32ReadAttribute = TypedReadAttribute<int>;
using Color4fReadAttribute = TypedReadAttribute<Color4f>;
using BooleanWriteAttribute = TypedWriteAttribute<bool>;
using FloatWriteAttribute = TypedWriteAttribute<float>;
using Float2WriteAttribute = TypedWriteAttribute<float2>;
using Float3WriteAttribute = TypedWriteAttribute<float3>;
using Int32WriteAttribute = TypedWriteAttribute<int>;
using Color4fWriteAttribute = TypedWriteAttribute<Color4f>;
} // namespace blender::bke

View File

@@ -31,7 +31,7 @@ extern "C" {
*/
/* Blender major and minor version. */
#define BLENDER_VERSION 293
#define BLENDER_VERSION 300
/* Blender patch version for bugfix releases. */
#define BLENDER_VERSION_PATCH 0
/** Blender release cycle stage: alpha/beta/rc/release. */
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 17
#define BLENDER_FILE_SUBVERSION 0
/* 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

@@ -55,60 +55,6 @@ class ComponentAttributeProviders;
class GeometryComponent;
/**
* An #OutputAttributePtr wraps a #WriteAttributePtr that might not be stored in its final
* destination yet. Therefore, once the attribute has been filled with data, the #save method has
* to be called, to store the attribute where it belongs (possibly by replacing an existing
* attribute with the same name).
*
* This is useful for example in the Attribute Color Ramp node, when the same attribute name is
* used as input and output. Typically the input is a float attribute, and the output is a color.
* Those two attributes cannot exist at the same time, due to a name collision. To handle this
* situation well, first the output colors have to be computed before the input floats are deleted.
* Therefore, the outputs have to be written to a temporary buffer that replaces the existing
* attribute once all computations are done.
*/
class OutputAttributePtr {
private:
blender::bke::WriteAttributePtr attribute_;
public:
OutputAttributePtr() = default;
OutputAttributePtr(blender::bke::WriteAttributePtr attribute);
OutputAttributePtr(GeometryComponent &component,
AttributeDomain domain,
std::string name,
CustomDataType data_type);
~OutputAttributePtr();
/* Returns false, when this wrapper is empty. */
operator bool() const
{
return static_cast<bool>(attribute_);
}
/* Get a reference to the underlying #WriteAttribute. */
blender::bke::WriteAttribute &get()
{
BLI_assert(attribute_);
return *attribute_;
}
blender::bke::WriteAttribute &operator*()
{
return *attribute_;
}
blender::bke::WriteAttribute *operator->()
{
return attribute_.get();
}
void save();
void apply_span_and_save();
};
/**
* Contains information about an attribute in a geometry component.
* More information can be added in the future. E.g. whether the attribute is builtin and how it is
@@ -161,21 +107,25 @@ class GeometryComponent {
/* Can only be used with supported domain types. */
virtual int attribute_domain_size(const AttributeDomain domain) const;
bool attribute_is_builtin(const blender::StringRef attribute_name) const;
/* Get read-only access to the highest priority attribute with the given name.
* Returns null if the attribute does not exist. */
blender::bke::ReadAttributePtr attribute_try_get_for_read(
blender::bke::ReadAttributeLookup attribute_try_get_for_read(
const blender::StringRef attribute_name) const;
/* Get read and write access to the highest priority attribute with the given name.
* Returns null if the attribute does not exist. */
blender::bke::WriteAttributePtr attribute_try_get_for_write(
blender::bke::WriteAttributeLookup attribute_try_get_for_write(
const blender::StringRef attribute_name);
/* Get a read-only attribute for the domain based on the given attribute. This can be used to
* interpolate from one domain to another.
* Returns null if the interpolation is not implemented. */
virtual blender::bke::ReadAttributePtr attribute_try_adapt_domain(
blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const;
virtual std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain(
std::unique_ptr<blender::fn::GVArray> varray,
const AttributeDomain from_domain,
const AttributeDomain to_domain) const;
/* Returns true when the attribute has been deleted. */
bool attribute_try_delete(const blender::StringRef attribute_name);
@@ -185,80 +135,94 @@ class GeometryComponent {
const AttributeDomain domain,
const CustomDataType data_type);
/* Try to create the builtin attribute with the given name. No data type or domain has to be
* provided, because those are fixed for builtin attributes. */
bool attribute_try_create_builtin(const blender::StringRef attribute_name);
blender::Set<std::string> attribute_names() const;
bool attribute_foreach(const AttributeForeachCallback callback) const;
virtual bool is_empty() const;
/* Get a read-only attribute for the given domain and data type.
* Returns null when it does not exist. */
blender::bke::ReadAttributePtr attribute_try_get_for_read(
/* Get a virtual array to read the data of an attribute on the given domain and data type.
* Returns null when the attribute does not exist or cannot be converted to the requested domain
* and data type. */
std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read(
const blender::StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type) const;
/* Get a read-only attribute interpolated to the input domain, leaving the data type unchanged.
* Returns null when the attribute does not exist. */
blender::bke::ReadAttributePtr attribute_try_get_for_read(
/* Get a virtual array to read the data of an attribute on the given domain. The data type is
* left unchanged. Returns null when the attribute does not exist or cannot be adapted to the
* requested domain. */
std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read(
const blender::StringRef attribute_name, const AttributeDomain domain) const;
/* Get a read-only attribute for the given domain and data type.
* Returns a constant attribute based on the default value if the attribute does not exist.
* Never returns null. */
blender::bke::ReadAttributePtr attribute_get_for_read(const blender::StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type,
const void *default_value) const;
/* Get a typed read-only attribute for the given domain and type. */
template<typename T>
blender::bke::TypedReadAttribute<T> attribute_get_for_read(
/* Get a virtual array to read the data of an attribute. If that is not possible, the returned
* virtual array will contain a default value. This never returns null. */
std::unique_ptr<blender::fn::GVArray> attribute_get_for_read(
const blender::StringRef attribute_name,
const AttributeDomain domain,
const T &default_value) const
{
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
return this->attribute_get_for_read(attribute_name, domain, type, &default_value);
}
const CustomDataType data_type,
const void *default_value = nullptr) const;
/* Get a read-only dummy attribute that always returns the same value. */
blender::bke::ReadAttributePtr attribute_get_constant_for_read(const AttributeDomain domain,
const CustomDataType data_type,
const void *value) const;
/* Create a read-only dummy attribute that always returns the same value.
* The given value is converted to the correct type if necessary. */
blender::bke::ReadAttributePtr attribute_get_constant_for_read_converted(
const AttributeDomain domain,
const CustomDataType in_data_type,
const CustomDataType out_data_type,
const void *value) const;
/* Get a read-only dummy attribute that always returns the same value. */
/* Should be used instead of the method above when the requested data type is known at compile
* time for better type safety. */
template<typename T>
blender::bke::TypedReadAttribute<T> attribute_get_constant_for_read(const AttributeDomain domain,
const T &value) const
blender::fn::GVArray_Typed<T> attribute_get_for_read(const blender::StringRef attribute_name,
const AttributeDomain domain,
const T &default_value) const
{
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
return this->attribute_get_constant_for_read(domain, type, &value);
std::unique_ptr varray = this->attribute_get_for_read(
attribute_name, domain, type, &default_value);
return blender::fn::GVArray_Typed<T>(std::move(varray));
}
/**
* If an attribute with the given params exist, it is returned.
* If no attribute with the given name exists, create it and
* fill it with the default value if it is provided.
* If an attribute with the given name but different domain or type exists, a temporary attribute
* is created that has to be saved after the output has been computed. This avoids deleting
* another attribute, before a computation is finished.
* Returns an "output attribute", which is essentially a mutable virtual array with some commonly
* used convience features. The returned output attribute might be empty if requested attribute
* cannot exist on the geometry.
*
* This might return no attribute when the attribute cannot exist on the component.
* The included convenience features are:
* - Implicit type conversion when writing to builtin attributes.
* - If the attribute name exists already, but has a different type/domain, a temporary attribute
* is created that will overwrite the existing attribute in the end.
*/
OutputAttributePtr attribute_try_get_for_output(const blender::StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type,
const void *default_value = nullptr);
blender::bke::OutputAttribute attribute_try_get_for_output(
const blender::StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type,
const void *default_value = nullptr);
/* Same as attribute_try_get_for_output, but should be used when the original values in the
* attributes are not read, i.e. the attribute is used only for output. Since values are not read
* from this attribute, no default value is necessary. */
blender::bke::OutputAttribute attribute_try_get_for_output_only(
const blender::StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type);
/* Statically typed method corresponding to the equally named generic one. */
template<typename T>
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output(
const blender::StringRef attribute_name, const AttributeDomain domain, const T default_value)
{
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
return this->attribute_try_get_for_output(attribute_name, domain, data_type, &default_value);
}
/* Statically typed method corresponding to the equally named generic one. */
template<typename T>
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only(
const blender::StringRef attribute_name, const AttributeDomain domain)
{
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
return this->attribute_try_get_for_output_only(attribute_name, domain, data_type);
}
private:
virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const;
@@ -377,8 +341,10 @@ class MeshComponent : public GeometryComponent {
Mesh *get_for_write();
int attribute_domain_size(const AttributeDomain domain) const final;
blender::bke::ReadAttributePtr attribute_try_adapt_domain(
blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const final;
std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain(
std::unique_ptr<blender::fn::GVArray> varray,
const AttributeDomain from_domain,
const AttributeDomain to_domain) const final;
bool is_empty() const final;

View File

@@ -137,7 +137,7 @@ static char *blender_version_decimal(const int version)
{
static char version_str[5];
BLI_assert(version < 1000);
BLI_snprintf(version_str, sizeof(version_str), "%d.%02d", version / 100, version % 100);
BLI_snprintf(version_str, sizeof(version_str), "%d.%d", version / 100, version % 100);
return version_str;
}

View File

@@ -44,194 +44,10 @@ using blender::float3;
using blender::Set;
using blender::StringRef;
using blender::StringRefNull;
using blender::bke::ReadAttributePtr;
using blender::bke::WriteAttributePtr;
using blender::fn::GMutableSpan;
namespace blender::bke {
/* -------------------------------------------------------------------- */
/** \name Attribute Accessor implementations
* \{ */
ReadAttribute::~ReadAttribute()
{
if (array_is_temporary_ && array_buffer_ != nullptr) {
cpp_type_.destruct_n(array_buffer_, size_);
MEM_freeN(array_buffer_);
}
}
fn::GSpan ReadAttribute::get_span() const
{
if (size_ == 0) {
return fn::GSpan(cpp_type_);
}
if (array_buffer_ == nullptr) {
std::lock_guard lock{span_mutex_};
if (array_buffer_ == nullptr) {
this->initialize_span();
}
}
return fn::GSpan(cpp_type_, array_buffer_, size_);
}
void ReadAttribute::initialize_span() const
{
const int element_size = cpp_type_.size();
array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
array_is_temporary_ = true;
for (const int i : IndexRange(size_)) {
this->get_internal(i, POINTER_OFFSET(array_buffer_, i * element_size));
}
}
WriteAttribute::~WriteAttribute()
{
if (array_should_be_applied_) {
CLOG_ERROR(&LOG, "Forgot to call apply_span.");
}
if (array_is_temporary_ && array_buffer_ != nullptr) {
cpp_type_.destruct_n(array_buffer_, size_);
MEM_freeN(array_buffer_);
}
}
/**
* Get a mutable span that can be modified. When all modifications to the attribute are done,
* #apply_span should be called. */
fn::GMutableSpan WriteAttribute::get_span()
{
if (size_ == 0) {
return fn::GMutableSpan(cpp_type_);
}
if (array_buffer_ == nullptr) {
this->initialize_span(false);
}
array_should_be_applied_ = true;
return fn::GMutableSpan(cpp_type_, array_buffer_, size_);
}
fn::GMutableSpan WriteAttribute::get_span_for_write_only()
{
if (size_ == 0) {
return fn::GMutableSpan(cpp_type_);
}
if (array_buffer_ == nullptr) {
this->initialize_span(true);
}
array_should_be_applied_ = true;
return fn::GMutableSpan(cpp_type_, array_buffer_, size_);
}
void WriteAttribute::initialize_span(const bool write_only)
{
const int element_size = cpp_type_.size();
array_buffer_ = MEM_mallocN_aligned(element_size * size_, cpp_type_.alignment(), __func__);
array_is_temporary_ = true;
if (write_only) {
/* This does nothing for trivial types, but is necessary for general correctness. */
cpp_type_.construct_default_n(array_buffer_, size_);
}
else {
for (const int i : IndexRange(size_)) {
this->get(i, POINTER_OFFSET(array_buffer_, i * element_size));
}
}
}
void WriteAttribute::apply_span()
{
this->apply_span_if_necessary();
array_should_be_applied_ = false;
}
void WriteAttribute::apply_span_if_necessary()
{
/* Only works when the span has been initialized beforehand. */
BLI_assert(array_buffer_ != nullptr);
const int element_size = cpp_type_.size();
for (const int i : IndexRange(size_)) {
this->set_internal(i, POINTER_OFFSET(array_buffer_, i * element_size));
}
}
/* This is used by the #OutputAttributePtr class. */
class TemporaryWriteAttribute final : public WriteAttribute {
public:
GMutableSpan data;
GeometryComponent &component;
std::string final_name;
TemporaryWriteAttribute(AttributeDomain domain,
GMutableSpan data,
GeometryComponent &component,
std::string final_name)
: WriteAttribute(domain, data.type(), data.size()),
data(data),
component(component),
final_name(std::move(final_name))
{
}
~TemporaryWriteAttribute() override
{
if (data.data() != nullptr) {
cpp_type_.destruct_n(data.data(), data.size());
MEM_freeN(data.data());
}
}
void get_internal(const int64_t index, void *r_value) const override
{
data.type().copy_to_uninitialized(data[index], r_value);
}
void set_internal(const int64_t index, const void *value) override
{
data.type().copy_to_initialized(value, data[index]);
}
void initialize_span(const bool UNUSED(write_only)) override
{
array_buffer_ = data.data();
array_is_temporary_ = false;
}
void apply_span_if_necessary() override
{
/* Do nothing, because the span contains the attribute itself already. */
}
};
class ConvertedReadAttribute final : public ReadAttribute {
private:
const CPPType &from_type_;
const CPPType &to_type_;
ReadAttributePtr base_attribute_;
const nodes::DataTypeConversions &conversions_;
public:
ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type)
: ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()),
from_type_(base_attribute->cpp_type()),
to_type_(to_type),
base_attribute_(std::move(base_attribute)),
conversions_(nodes::get_implicit_type_conversions())
{
}
void get_internal(const int64_t index, void *r_value) const override
{
BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
base_attribute_->get(index, buffer);
conversions_.convert(from_type_, to_type_, buffer, r_value);
}
};
/** \} */
const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
{
switch (type) {
@@ -366,7 +182,17 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
return highest_priority_domain;
}
ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read(
void OutputAttribute::save()
{
if (optional_span_varray_.has_value()) {
optional_span_varray_->save();
}
if (save_) {
save_(*this);
}
}
std::unique_ptr<GVArray> BuiltinCustomDataLayerProvider::try_get_for_read(
const GeometryComponent &component) const
{
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
@@ -382,7 +208,7 @@ ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read(
return as_read_attribute_(data, domain_size);
}
WriteAttributePtr BuiltinCustomDataLayerProvider::try_get_for_write(
std::unique_ptr<GVMutableArray> BuiltinCustomDataLayerProvider::try_get_for_write(
GeometryComponent &component) const
{
if (writable_ != Writable) {
@@ -461,7 +287,7 @@ bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component)
return data != nullptr;
}
ReadAttributePtr CustomDataAttributeProvider::try_get_for_read(
ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
const GeometryComponent &component, const StringRef attribute_name) const
{
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
@@ -494,7 +320,7 @@ ReadAttributePtr CustomDataAttributeProvider::try_get_for_read(
return {};
}
WriteAttributePtr CustomDataAttributeProvider::try_get_for_write(
WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write(
GeometryComponent &component, const StringRef attribute_name) const
{
CustomData *custom_data = custom_data_access_.get_custom_data(component);
@@ -593,7 +419,7 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com
return true;
}
ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read(
ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
const GeometryComponent &component, const StringRef attribute_name) const
{
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
@@ -604,14 +430,14 @@ ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read(
if (layer.type == stored_type_) {
if (layer.name == attribute_name) {
const int domain_size = component.attribute_domain_size(domain_);
return as_read_attribute_(layer.data, domain_size);
return {as_read_attribute_(layer.data, domain_size), domain_};
}
}
}
return {};
}
WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write(
WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
GeometryComponent &component, const StringRef attribute_name) const
{
CustomData *custom_data = custom_data_access_.get_custom_data(component);
@@ -628,7 +454,7 @@ WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write(
if (data_old != data_new) {
custom_data_access_.update_custom_data_pointers(component);
}
return as_write_attribute_(layer.data, domain_size);
return {as_write_attribute_(layer.data, domain_size), domain_};
}
}
}
@@ -706,7 +532,17 @@ int GeometryComponent::attribute_domain_size(const AttributeDomain UNUSED(domain
return 0;
}
ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
bool GeometryComponent::attribute_is_builtin(const blender::StringRef attribute_name) const
{
using namespace blender::bke;
const ComponentAttributeProviders *providers = this->get_attribute_providers();
if (providers == nullptr) {
return false;
}
return providers->builtin_attribute_providers().contains_as(attribute_name);
}
blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
const StringRef attribute_name) const
{
using namespace blender::bke;
@@ -717,11 +553,11 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
const BuiltinAttributeProvider *builtin_provider =
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
if (builtin_provider != nullptr) {
return builtin_provider->try_get_for_read(*this);
return {builtin_provider->try_get_for_read(*this), builtin_provider->domain()};
}
for (const DynamicAttributesProvider *dynamic_provider :
providers->dynamic_attribute_providers()) {
ReadAttributePtr attribute = dynamic_provider->try_get_for_read(*this, attribute_name);
ReadAttributeLookup attribute = dynamic_provider->try_get_for_read(*this, attribute_name);
if (attribute) {
return attribute;
}
@@ -729,16 +565,19 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
return {};
}
ReadAttributePtr GeometryComponent::attribute_try_adapt_domain(
ReadAttributePtr attribute, const AttributeDomain new_domain) const
std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_adapt_domain(
std::unique_ptr<blender::fn::GVArray> varray,
const AttributeDomain from_domain,
const AttributeDomain to_domain) const
{
if (attribute && attribute->domain() == new_domain) {
return attribute;
if (from_domain == to_domain) {
return varray;
}
return {};
}
WriteAttributePtr GeometryComponent::attribute_try_get_for_write(const StringRef attribute_name)
blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_write(
const StringRef attribute_name)
{
using namespace blender::bke;
const ComponentAttributeProviders *providers = this->get_attribute_providers();
@@ -748,11 +587,11 @@ WriteAttributePtr GeometryComponent::attribute_try_get_for_write(const StringRef
const BuiltinAttributeProvider *builtin_provider =
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
if (builtin_provider != nullptr) {
return builtin_provider->try_get_for_write(*this);
return {builtin_provider->try_get_for_write(*this), builtin_provider->domain()};
}
for (const DynamicAttributesProvider *dynamic_provider :
providers->dynamic_attribute_providers()) {
WriteAttributePtr attribute = dynamic_provider->try_get_for_write(*this, attribute_name);
WriteAttributeLookup attribute = dynamic_provider->try_get_for_write(*this, attribute_name);
if (attribute) {
return attribute;
}
@@ -812,6 +651,24 @@ bool GeometryComponent::attribute_try_create(const StringRef attribute_name,
return false;
}
bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name)
{
using namespace blender::bke;
if (attribute_name.is_empty()) {
return false;
}
const ComponentAttributeProviders *providers = this->get_attribute_providers();
if (providers == nullptr) {
return false;
}
const BuiltinAttributeProvider *builtin_provider =
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
if (builtin_provider == nullptr) {
return false;
}
return builtin_provider->try_create(*this);
}
Set<std::string> GeometryComponent::attribute_names() const
{
Set<std::string> attributes;
@@ -865,264 +722,235 @@ bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callbac
bool GeometryComponent::attribute_exists(const blender::StringRef attribute_name) const
{
ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
if (attribute) {
return true;
}
return false;
}
static ReadAttributePtr try_adapt_data_type(ReadAttributePtr attribute,
const blender::fn::CPPType &to_type)
static std::unique_ptr<blender::fn::GVArray> try_adapt_data_type(
std::unique_ptr<blender::fn::GVArray> varray, const blender::fn::CPPType &to_type)
{
const blender::fn::CPPType &from_type = attribute->cpp_type();
if (from_type == to_type) {
return attribute;
}
const blender::nodes::DataTypeConversions &conversions =
blender::nodes::get_implicit_type_conversions();
if (!conversions.is_convertible(from_type, to_type)) {
return {};
}
return std::make_unique<blender::bke::ConvertedReadAttribute>(std::move(attribute), to_type);
return conversions.try_convert(std::move(varray), to_type);
}
ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_read(
const StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type) const
{
ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
if (!attribute) {
return {};
}
if (domain != ATTR_DOMAIN_AUTO && attribute->domain() != domain) {
attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
if (!attribute) {
std::unique_ptr<blender::fn::GVArray> varray = std::move(attribute.varray);
if (domain != ATTR_DOMAIN_AUTO && attribute.domain != domain) {
varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain);
if (!varray) {
return {};
}
}
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
if (attribute->cpp_type() != *cpp_type) {
attribute = try_adapt_data_type(std::move(attribute), *cpp_type);
if (!attribute) {
if (varray->type() != *cpp_type) {
varray = try_adapt_data_type(std::move(varray), *cpp_type);
if (!varray) {
return {};
}
}
return attribute;
return varray;
}
ReadAttributePtr GeometryComponent::attribute_try_get_for_read(const StringRef attribute_name,
const AttributeDomain domain) const
std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_try_get_for_read(
const StringRef attribute_name, const AttributeDomain domain) const
{
if (!this->attribute_domain_supported(domain)) {
return {};
}
ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
if (!attribute) {
return {};
}
if (attribute->domain() != domain) {
attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
if (attribute.domain != domain) {
return this->attribute_try_adapt_domain(std::move(attribute.varray), attribute.domain, domain);
}
return std::move(attribute.varray);
}
std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read(
const StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type,
const void *default_value) const
{
std::unique_ptr<blender::bke::GVArray> varray = this->attribute_try_get_for_read(
attribute_name, domain, data_type);
if (varray) {
return varray;
}
const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
if (default_value == nullptr) {
default_value = type->default_value();
}
const int domain_size = this->attribute_domain_size(domain);
return std::make_unique<blender::fn::GVArray_For_SingleValue>(*type, domain_size, default_value);
}
class GVMutableAttribute_For_OutputAttribute
: public blender::fn::GVMutableArray_For_GMutableSpan {
public:
GeometryComponent *component;
std::string final_name;
GVMutableAttribute_For_OutputAttribute(GMutableSpan data,
GeometryComponent &component,
std::string final_name)
: blender::fn::GVMutableArray_For_GMutableSpan(data),
component(&component),
final_name(std::move(final_name))
{
}
~GVMutableAttribute_For_OutputAttribute() override
{
type_->destruct_n(data_, size_);
MEM_freeN(data_);
}
};
static void save_output_attribute(blender::bke::OutputAttribute &output_attribute)
{
using namespace blender;
using namespace blender::fn;
using namespace blender::bke;
GVMutableAttribute_For_OutputAttribute &varray =
dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(output_attribute.varray());
GeometryComponent &component = *varray.component;
const StringRefNull name = varray.final_name;
const AttributeDomain domain = output_attribute.domain();
const CustomDataType data_type = output_attribute.custom_data_type();
const CPPType &cpp_type = output_attribute.cpp_type();
component.attribute_try_delete(name);
if (!component.attribute_try_create(varray.final_name, domain, data_type)) {
CLOG_WARN(&LOG,
"Could not create the '%s' attribute with type '%s'.",
name.c_str(),
cpp_type.name().c_str());
return;
}
WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(name);
BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), buffer);
for (const int i : IndexRange(varray.size())) {
varray.get(i, buffer);
write_attribute.varray->set_by_relocate(i, buffer);
}
}
static blender::bke::OutputAttribute create_output_attribute(
GeometryComponent &component,
const blender::StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type,
const bool ignore_old_values,
const void *default_value)
{
using namespace blender;
using namespace blender::fn;
using namespace blender::bke;
if (attribute_name.is_empty()) {
return {};
}
const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
if (component.attribute_is_builtin(attribute_name)) {
WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
if (!attribute) {
component.attribute_try_create_builtin(attribute_name);
attribute = component.attribute_try_get_for_write(attribute_name);
if (!attribute) {
/* Builtin attribute does not exist and can't be created. */
return {};
}
}
if (attribute.domain != domain) {
/* Builtin attribute is on different domain. */
return {};
}
std::unique_ptr<GVMutableArray> varray = std::move(attribute.varray);
if (varray->type() == *cpp_type) {
/* Builtin attribute matches exactly. */
return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
}
/* Builtin attribute is on the same domain but has a different data type. */
varray = conversions.try_convert(std::move(varray), *cpp_type);
return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
}
WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
if (!attribute) {
component.attribute_try_create(attribute_name, domain, data_type);
attribute = component.attribute_try_get_for_write(attribute_name);
if (!attribute) {
/* Can't create the attribute. */
return {};
}
}
return attribute;
}
ReadAttributePtr GeometryComponent::attribute_get_for_read(const StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type,
const void *default_value) const
{
ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name, domain, data_type);
if (attribute) {
return attribute;
if (attribute.domain == domain && attribute.varray->type() == *cpp_type) {
/* Existing generic attribute matches exactly. */
return OutputAttribute(std::move(attribute.varray), domain, {}, ignore_old_values);
}
return this->attribute_get_constant_for_read(domain, data_type, default_value);
}
blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read(
const AttributeDomain domain, const CustomDataType data_type, const void *value) const
{
BLI_assert(this->attribute_domain_supported(domain));
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
if (value == nullptr) {
value = cpp_type->default_value();
}
const int domain_size = this->attribute_domain_size(domain);
return std::make_unique<blender::bke::ConstantReadAttribute>(
domain, domain_size, *cpp_type, value);
}
blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read_converted(
const AttributeDomain domain,
const CustomDataType in_data_type,
const CustomDataType out_data_type,
const void *value) const
{
BLI_assert(this->attribute_domain_supported(domain));
if (value == nullptr || in_data_type == out_data_type) {
return this->attribute_get_constant_for_read(domain, out_data_type, value);
}
const blender::fn::CPPType *in_cpp_type = blender::bke::custom_data_type_to_cpp_type(
in_data_type);
const blender::fn::CPPType *out_cpp_type = blender::bke::custom_data_type_to_cpp_type(
out_data_type);
BLI_assert(in_cpp_type != nullptr);
BLI_assert(out_cpp_type != nullptr);
const blender::nodes::DataTypeConversions &conversions =
blender::nodes::get_implicit_type_conversions();
BLI_assert(conversions.is_convertible(*in_cpp_type, *out_cpp_type));
void *out_value = alloca(out_cpp_type->size());
conversions.convert(*in_cpp_type, *out_cpp_type, value, out_value);
const int domain_size = this->attribute_domain_size(domain);
blender::bke::ReadAttributePtr attribute = std::make_unique<blender::bke::ConstantReadAttribute>(
domain, domain_size, *out_cpp_type, out_value);
out_cpp_type->destruct(out_value);
return attribute;
}
OutputAttributePtr GeometryComponent::attribute_try_get_for_output(const StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type,
const void *default_value)
{
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
WriteAttributePtr attribute = this->attribute_try_get_for_write(attribute_name);
/* If the attribute doesn't exist, make a new one with the correct type. */
if (!attribute) {
this->attribute_try_create(attribute_name, domain, data_type);
attribute = this->attribute_try_get_for_write(attribute_name);
if (attribute && default_value != nullptr) {
void *data = attribute->get_span_for_write_only().data();
cpp_type->fill_initialized(default_value, data, attribute->size());
attribute->apply_span();
}
return OutputAttributePtr(std::move(attribute));
}
/* If an existing attribute has a matching domain and type, just use that. */
if (attribute->domain() == domain && attribute->cpp_type() == *cpp_type) {
return OutputAttributePtr(std::move(attribute));
}
/* Otherwise create a temporary buffer to use before saving the new attribute. */
return OutputAttributePtr(*this, domain, attribute_name, data_type);
}
/* Construct from an attribute that already exists in the geometry component. */
OutputAttributePtr::OutputAttributePtr(WriteAttributePtr attribute)
: attribute_(std::move(attribute))
{
}
/* Construct a temporary attribute that has to replace an existing one later on. */
OutputAttributePtr::OutputAttributePtr(GeometryComponent &component,
AttributeDomain domain,
std::string final_name,
CustomDataType data_type)
{
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
const int domain_size = component.attribute_domain_size(domain);
void *buffer = MEM_malloc_arrayN(domain_size, cpp_type->size(), __func__);
GMutableSpan new_span{*cpp_type, buffer, domain_size};
/* Copy converted values from conflicting attribute, in case the value is read.
* TODO: An optimization could be to not do this, when the caller says that the attribute will
* only be written. */
ReadAttributePtr src_attribute = component.attribute_get_for_read(
final_name, domain, data_type, nullptr);
for (const int i : blender::IndexRange(domain_size)) {
src_attribute->get(i, new_span[i]);
/* Allocate a new array that lives next to the existing attribute. It will overwrite the existing
* attribute after processing is done. */
void *data = MEM_mallocN_aligned(
cpp_type->size() * domain_size, cpp_type->alignment(), __func__);
if (ignore_old_values) {
/* This does nothing for trivially constructible types, but is necessary for correctness. */
cpp_type->construct_default_n(data, domain);
}
else {
/* Fill the temporary array with values from the existing attribute. */
std::unique_ptr<GVArray> old_varray = component.attribute_get_for_read(
attribute_name, domain, data_type, default_value);
old_varray->materialize_to_uninitialized(IndexRange(domain_size), data);
}
std::unique_ptr<GVMutableArray> varray =
std::make_unique<GVMutableAttribute_For_OutputAttribute>(
GMutableSpan{*cpp_type, data, domain_size}, component, attribute_name);
attribute_ = std::make_unique<blender::bke::TemporaryWriteAttribute>(
domain, new_span, component, std::move(final_name));
return OutputAttribute(std::move(varray), domain, save_output_attribute, true);
}
/* Store the computed attribute. If it was stored from the beginning already, nothing is done. This
* might delete another attribute with the same name. */
void OutputAttributePtr::save()
blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output(
const StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type,
const void *default_value)
{
if (!attribute_) {
CLOG_WARN(&LOG, "Trying to save an attribute that does not exist anymore.");
return;
}
blender::bke::TemporaryWriteAttribute *attribute =
dynamic_cast<blender::bke::TemporaryWriteAttribute *>(attribute_.get());
if (attribute == nullptr) {
/* The attribute is saved already. */
attribute_.reset();
return;
}
StringRefNull name = attribute->final_name;
const blender::fn::CPPType &cpp_type = attribute->cpp_type();
/* Delete an existing attribute with the same name if necessary. */
attribute->component.attribute_try_delete(name);
if (!attribute->component.attribute_try_create(
name, attribute_->domain(), attribute_->custom_data_type())) {
/* Cannot create the target attribute for some reason. */
CLOG_WARN(&LOG,
"Creating the '%s' attribute with type '%s' failed.",
name.c_str(),
cpp_type.name().c_str());
attribute_.reset();
return;
}
WriteAttributePtr new_attribute = attribute->component.attribute_try_get_for_write(name);
GMutableSpan temp_span = attribute->data;
GMutableSpan new_span = new_attribute->get_span_for_write_only();
BLI_assert(temp_span.size() == new_span.size());
/* Currently we copy over the attribute. In the future we want to reuse the buffer. */
cpp_type.move_to_initialized_n(temp_span.data(), new_span.data(), new_span.size());
new_attribute->apply_span();
attribute_.reset();
return create_output_attribute(*this, attribute_name, domain, data_type, false, default_value);
}
OutputAttributePtr::~OutputAttributePtr()
blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
const blender::StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type)
{
if (attribute_) {
CLOG_ERROR(&LOG, "Forgot to call #save or #apply_span_and_save.");
}
return create_output_attribute(*this, attribute_name, domain, data_type, true, nullptr);
}
/* Utility function to call #apply_span and #save in the right order. */
void OutputAttributePtr::apply_span_and_save()
{
BLI_assert(attribute_);
attribute_->apply_span();
this->save();
}
/** \} */

View File

@@ -24,167 +24,6 @@
namespace blender::bke {
class ConstantReadAttribute final : public ReadAttribute {
private:
void *value_;
public:
ConstantReadAttribute(AttributeDomain domain,
const int64_t size,
const CPPType &type,
const void *value)
: ReadAttribute(domain, type, size)
{
value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
type.copy_to_uninitialized(value, value_);
}
~ConstantReadAttribute() override
{
this->cpp_type_.destruct(value_);
MEM_freeN(value_);
}
void get_internal(const int64_t UNUSED(index), void *r_value) const override
{
this->cpp_type_.copy_to_uninitialized(value_, r_value);
}
void initialize_span() const override
{
const int element_size = cpp_type_.size();
array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
array_is_temporary_ = true;
cpp_type_.fill_uninitialized(value_, array_buffer_, size_);
}
};
template<typename T> class ArrayReadAttribute final : public ReadAttribute {
private:
Span<T> data_;
public:
ArrayReadAttribute(AttributeDomain domain, Span<T> data)
: ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
{
}
void get_internal(const int64_t index, void *r_value) const override
{
new (r_value) T(data_[index]);
}
void initialize_span() const override
{
/* The data will not be modified, so this const_cast is fine. */
array_buffer_ = const_cast<T *>(data_.data());
array_is_temporary_ = false;
}
};
template<typename T> class OwnedArrayReadAttribute final : public ReadAttribute {
private:
Array<T> data_;
public:
OwnedArrayReadAttribute(AttributeDomain domain, Array<T> data)
: ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(std::move(data))
{
}
void get_internal(const int64_t index, void *r_value) const override
{
new (r_value) T(data_[index]);
}
void initialize_span() const override
{
/* The data will not be modified, so this const_cast is fine. */
array_buffer_ = const_cast<T *>(data_.data());
array_is_temporary_ = false;
}
};
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
class DerivedArrayReadAttribute final : public ReadAttribute {
private:
Span<StructT> data_;
public:
DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data)
: ReadAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
{
}
void get_internal(const int64_t index, void *r_value) const override
{
const StructT &struct_value = data_[index];
const ElemT value = GetFunc(struct_value);
new (r_value) ElemT(value);
}
};
template<typename T> class ArrayWriteAttribute final : public WriteAttribute {
private:
MutableSpan<T> data_;
public:
ArrayWriteAttribute(AttributeDomain domain, MutableSpan<T> data)
: WriteAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
{
}
void get_internal(const int64_t index, void *r_value) const override
{
new (r_value) T(data_[index]);
}
void set_internal(const int64_t index, const void *value) override
{
data_[index] = *reinterpret_cast<const T *>(value);
}
void initialize_span(const bool UNUSED(write_only)) override
{
array_buffer_ = data_.data();
array_is_temporary_ = false;
}
void apply_span_if_necessary() override
{
/* Do nothing, because the span contains the attribute itself already. */
}
};
template<typename StructT,
typename ElemT,
ElemT (*GetFunc)(const StructT &),
void (*SetFunc)(StructT &, const ElemT &)>
class DerivedArrayWriteAttribute final : public WriteAttribute {
private:
MutableSpan<StructT> data_;
public:
DerivedArrayWriteAttribute(AttributeDomain domain, MutableSpan<StructT> data)
: WriteAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
{
}
void get_internal(const int64_t index, void *r_value) const override
{
const StructT &struct_value = data_[index];
const ElemT value = GetFunc(struct_value);
new (r_value) ElemT(value);
}
void set_internal(const int64_t index, const void *value) override
{
StructT &struct_value = data_[index];
const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value);
SetFunc(struct_value, typed_value);
}
};
/**
* Utility to group together multiple functions that are used to access custom data on geometry
* components in a generic way.
@@ -244,8 +83,9 @@ class BuiltinAttributeProvider {
{
}
virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0;
virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0;
virtual std::unique_ptr<GVArray> try_get_for_read(const GeometryComponent &component) const = 0;
virtual std::unique_ptr<GVMutableArray> try_get_for_write(
GeometryComponent &component) const = 0;
virtual bool try_delete(GeometryComponent &component) const = 0;
virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0;
virtual bool exists(const GeometryComponent &component) const = 0;
@@ -272,10 +112,10 @@ class BuiltinAttributeProvider {
*/
class DynamicAttributesProvider {
public:
virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component,
const StringRef attribute_name) const = 0;
virtual WriteAttributePtr try_get_for_write(GeometryComponent &component,
const StringRef attribute_name) const = 0;
virtual ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
const StringRef attribute_name) const = 0;
virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component,
const StringRef attribute_name) const = 0;
virtual bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0;
virtual bool try_create(GeometryComponent &UNUSED(component),
const StringRef UNUSED(attribute_name),
@@ -309,11 +149,11 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
{
}
ReadAttributePtr try_get_for_read(const GeometryComponent &component,
const StringRef attribute_name) const final;
ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
const StringRef attribute_name) const final;
WriteAttributePtr try_get_for_write(GeometryComponent &component,
const StringRef attribute_name) const final;
WriteAttributeLookup try_get_for_write(GeometryComponent &component,
const StringRef attribute_name) const final;
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
@@ -332,18 +172,21 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
private:
template<typename T>
ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer,
const int domain_size) const
ReadAttributeLookup layer_to_read_attribute(const CustomDataLayer &layer,
const int domain_size) const
{
return std::make_unique<ArrayReadAttribute<T>>(
domain_, Span(static_cast<const T *>(layer.data), domain_size));
return {std::make_unique<fn::GVArray_For_Span<T>>(
Span(static_cast<const T *>(layer.data), domain_size)),
domain_};
}
template<typename T>
WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const
WriteAttributeLookup layer_to_write_attribute(CustomDataLayer &layer,
const int domain_size) const
{
return std::make_unique<ArrayWriteAttribute<T>>(
domain_, MutableSpan(static_cast<T *>(layer.data), domain_size));
return {std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>(
MutableSpan(static_cast<T *>(layer.data), domain_size)),
domain_};
}
bool type_is_supported(CustomDataType data_type) const
@@ -357,8 +200,8 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
*/
class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
private:
using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
using AsReadAttribute = std::unique_ptr<GVArray> (*)(const void *data, const int domain_size);
using AsWriteAttribute = std::unique_ptr<GVMutableArray> (*)(void *data, const int domain_size);
const AttributeDomain domain_;
const CustomDataType attribute_type_;
const CustomDataType stored_type_;
@@ -382,10 +225,10 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
{
}
ReadAttributePtr try_get_for_read(const GeometryComponent &component,
const StringRef attribute_name) const final;
WriteAttributePtr try_get_for_write(GeometryComponent &component,
const StringRef attribute_name) const final;
ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
const StringRef attribute_name) const final;
WriteAttributeLookup try_get_for_write(GeometryComponent &component,
const StringRef attribute_name) const final;
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
bool foreach_attribute(const GeometryComponent &component,
const AttributeForeachCallback callback) const final;
@@ -398,8 +241,8 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
* the #MVert struct, but is exposed as float3 attribute.
*/
class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
using AsReadAttribute = std::unique_ptr<GVArray> (*)(const void *data, const int domain_size);
using AsWriteAttribute = std::unique_ptr<GVMutableArray> (*)(void *data, const int domain_size);
using UpdateOnRead = void (*)(const GeometryComponent &component);
using UpdateOnWrite = void (*)(GeometryComponent &component);
const CustomDataType stored_type_;
@@ -430,8 +273,8 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
{
}
ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final;
WriteAttributePtr try_get_for_write(GeometryComponent &component) const final;
std::unique_ptr<GVArray> try_get_for_read(const GeometryComponent &component) const final;
std::unique_ptr<GVMutableArray> try_get_for_write(GeometryComponent &component) const final;
bool try_delete(GeometryComponent &component) const final;
bool try_create(GeometryComponent &component) const final;
bool exists(const GeometryComponent &component) const final;

View File

@@ -132,7 +132,7 @@ static void blender_version_init(void)
BLI_snprintf(blender_version_string,
ARRAY_SIZE(blender_version_string),
"%d.%02d.%d%s",
"%d.%01d.%d%s",
BLENDER_VERSION / 100,
BLENDER_VERSION % 100,
BLENDER_VERSION_PATCH,

View File

@@ -32,7 +32,7 @@
/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
using blender::bke::ReadAttributePtr;
using blender::fn::GVArray;
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -201,14 +201,14 @@ namespace blender::bke {
template<typename T>
static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
const TypedReadAttribute<T> &attribute,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totvert);
attribute_math::DefaultMixer<T> mixer(r_values);
for (const int loop_index : IndexRange(mesh.totloop)) {
const T value = attribute[loop_index];
const T value = old_values[loop_index];
const MLoop &loop = mesh.mloop[loop_index];
const int point_index = loop.v;
mixer.mix_in(point_index, value);
@@ -216,43 +216,42 @@ static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh,
ReadAttributePtr attribute)
static std::unique_ptr<GVArray> adapt_mesh_domain_corner_to_point(const Mesh &mesh,
std::unique_ptr<GVArray> varray)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
std::unique_ptr<GVArray> new_varray;
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
/* We compute all interpolated values at once, because for this interpolation, one has to
* iterate over all loops anyway. */
Array<T> values(mesh.totvert);
adapt_mesh_domain_corner_to_point_impl<T>(mesh, *attribute, values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
return new_attribute;
return new_varray;
}
template<typename T>
static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh,
const TypedReadAttribute<T> &attribute,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totloop);
for (const int loop_index : IndexRange(mesh.totloop)) {
const int vertex_index = mesh.mloop[loop_index].v;
r_values[loop_index] = attribute[vertex_index];
r_values[loop_index] = old_values[vertex_index];
}
}
static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
ReadAttributePtr attribute)
static std::unique_ptr<GVArray> adapt_mesh_domain_point_to_corner(const Mesh &mesh,
std::unique_ptr<GVArray> varray)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
std::unique_ptr<GVArray> new_varray;
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
/* It is not strictly necessary to compute the value for all corners here. Instead one could
@@ -260,11 +259,10 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
* when an algorithm only accesses very few of the corner values. However, for the algorithms
* we currently have, precomputing the array is fine. Also, it is easier to implement. */
Array<T> values(mesh.totloop);
adapt_mesh_domain_point_to_corner_impl<T>(mesh, *attribute, values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_CORNER,
std::move(values));
adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
});
return new_attribute;
return new_varray;
}
/**
@@ -274,7 +272,7 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
*/
template<typename T>
static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
Span<T> old_values,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
@@ -291,26 +289,25 @@ static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_corner_to_face(const Mesh &mesh,
ReadAttributePtr attribute)
static std::unique_ptr<GVArray> adapt_mesh_domain_corner_to_face(const Mesh &mesh,
std::unique_ptr<GVArray> varray)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
std::unique_ptr<GVArray> new_varray;
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
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));
adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
return new_attribute;
return new_varray;
}
template<typename T>
static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
Span<T> old_values,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totedge);
@@ -332,26 +329,25 @@ static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh,
ReadAttributePtr attribute)
static std::unique_ptr<GVArray> adapt_mesh_domain_corner_to_edge(const Mesh &mesh,
std::unique_ptr<GVArray> varray)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
std::unique_ptr<GVArray> new_varray;
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
adapt_mesh_domain_corner_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
return new_attribute;
return new_varray;
}
template<typename T>
void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
Span<T> old_values,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totvert);
@@ -370,26 +366,25 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_face_to_point(const Mesh &mesh,
ReadAttributePtr attribute)
static std::unique_ptr<GVArray> adapt_mesh_domain_face_to_point(const Mesh &mesh,
std::unique_ptr<GVArray> varray)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
std::unique_ptr<GVArray> new_varray;
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totvert);
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));
adapt_mesh_domain_face_to_point_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
return new_attribute;
return new_varray;
}
template<typename T>
void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
const Span<T> old_values,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totloop);
@@ -401,26 +396,25 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
}
}
static ReadAttributePtr adapt_mesh_domain_face_to_corner(const Mesh &mesh,
ReadAttributePtr attribute)
static std::unique_ptr<GVArray> adapt_mesh_domain_face_to_corner(const Mesh &mesh,
std::unique_ptr<GVArray> varray)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
std::unique_ptr<GVArray> new_varray;
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totloop);
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));
adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
return new_attribute;
return new_varray;
}
template<typename T>
void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
const Span<T> old_values,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totedge);
@@ -437,21 +431,20 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh,
ReadAttributePtr attribute)
static std::unique_ptr<GVArray> adapt_mesh_domain_face_to_edge(const Mesh &mesh,
std::unique_ptr<GVArray> varray)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
std::unique_ptr<GVArray> new_varray;
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
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));
adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
return new_attribute;
return new_varray;
}
/**
@@ -461,7 +454,7 @@ static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh,
*/
template<typename T>
static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
const Span<T> old_values,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
@@ -478,21 +471,20 @@ static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh,
ReadAttributePtr attribute)
static std::unique_ptr<GVArray> adapt_mesh_domain_point_to_face(const Mesh &mesh,
std::unique_ptr<GVArray> varray)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
std::unique_ptr<GVArray> new_varray;
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
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));
adapt_mesh_domain_point_to_face_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
return new_attribute;
return new_varray;
}
/**
@@ -502,7 +494,7 @@ static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh,
*/
template<typename T>
static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
const Span<T> old_values,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totedge);
@@ -517,26 +509,25 @@ static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_point_to_edge(const Mesh &mesh,
ReadAttributePtr attribute)
static std::unique_ptr<GVArray> adapt_mesh_domain_point_to_edge(const Mesh &mesh,
std::unique_ptr<GVArray> varray)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
std::unique_ptr<GVArray> new_varray;
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
adapt_mesh_domain_point_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
return new_attribute;
return new_varray;
}
template<typename T>
void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
const Span<T> old_values,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totloop);
@@ -558,26 +549,25 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh,
ReadAttributePtr attribute)
static std::unique_ptr<GVArray> adapt_mesh_domain_edge_to_corner(const Mesh &mesh,
std::unique_ptr<GVArray> varray)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
std::unique_ptr<GVArray> new_varray;
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totloop);
adapt_mesh_domain_edge_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
return new_attribute;
return new_varray;
}
template<typename T>
static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
const Span<T> old_values,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totvert);
@@ -593,21 +583,20 @@ static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh,
ReadAttributePtr attribute)
static std::unique_ptr<GVArray> adapt_mesh_domain_edge_to_point(const Mesh &mesh,
std::unique_ptr<GVArray> varray)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
std::unique_ptr<GVArray> new_varray;
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totvert);
adapt_mesh_domain_edge_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
std::move(values));
adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
return new_attribute;
return new_varray;
}
/**
@@ -617,7 +606,7 @@ static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh,
*/
template<typename T>
static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
const Span<T> old_values,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
@@ -634,87 +623,87 @@ static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
mixer.finalize();
}
static ReadAttributePtr adapt_mesh_domain_edge_to_face(const Mesh &mesh,
ReadAttributePtr attribute)
static std::unique_ptr<GVArray> adapt_mesh_domain_edge_to_face(const Mesh &mesh,
std::unique_ptr<GVArray> varray)
{
ReadAttributePtr new_attribute;
const CustomDataType data_type = attribute->custom_data_type();
std::unique_ptr<GVArray> new_varray;
const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
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));
adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray->typed<T>(), values);
new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
return new_attribute;
return new_varray;
}
} // namespace blender::bke
ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute,
const AttributeDomain new_domain) const
std::unique_ptr<GVArray> MeshComponent::attribute_try_adapt_domain(
std::unique_ptr<GVArray> varray,
const AttributeDomain from_domain,
const AttributeDomain to_domain) const
{
if (!attribute) {
if (!varray) {
return {};
}
if (attribute->size() == 0) {
if (varray->size() == 0) {
return {};
}
const AttributeDomain old_domain = attribute->domain();
if (old_domain == new_domain) {
return attribute;
if (from_domain == to_domain) {
return varray;
}
switch (old_domain) {
switch (from_domain) {
case ATTR_DOMAIN_CORNER: {
switch (new_domain) {
switch (to_domain) {
case ATTR_DOMAIN_POINT:
return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(varray));
case ATTR_DOMAIN_FACE:
return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(varray));
case ATTR_DOMAIN_EDGE:
return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(varray));
default:
break;
}
break;
}
case ATTR_DOMAIN_POINT: {
switch (new_domain) {
switch (to_domain) {
case ATTR_DOMAIN_CORNER:
return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(varray));
case ATTR_DOMAIN_FACE:
return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(varray));
case ATTR_DOMAIN_EDGE:
return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(varray));
default:
break;
}
break;
}
case ATTR_DOMAIN_FACE: {
switch (new_domain) {
switch (to_domain) {
case ATTR_DOMAIN_POINT:
return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(varray));
case ATTR_DOMAIN_CORNER:
return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(varray));
case ATTR_DOMAIN_EDGE:
return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(varray));
default:
break;
}
break;
}
case ATTR_DOMAIN_EDGE: {
switch (new_domain) {
switch (to_domain) {
case ATTR_DOMAIN_CORNER:
return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(varray));
case ATTR_DOMAIN_POINT:
return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(varray));
case ATTR_DOMAIN_FACE:
return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(attribute));
return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(varray));
default:
break;
}
@@ -743,25 +732,23 @@ 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)
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
static std::unique_ptr<GVArray> 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));
return std::make_unique<fn::GVArray_For_DerivedSpan<StructT, ElemT, GetFunc>>(
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)
void (*SetFunc)(StructT &, ElemT)>
static std::unique_ptr<GVMutableArray> 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));
return std::make_unique<fn::GVMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(
MutableSpan<StructT>((StructT *)data, domain_size));
}
static float3 get_vertex_position(const MVert &vert)
@@ -769,7 +756,7 @@ static float3 get_vertex_position(const MVert &vert)
return float3(vert.co);
}
static void set_vertex_position(MVert &vert, const float3 &position)
static void set_vertex_position(MVert &vert, float3 position)
{
copy_v3_v3(vert.co, position);
}
@@ -787,7 +774,7 @@ static int get_material_index(const MPoly &mpoly)
return static_cast<int>(mpoly.mat_nr);
}
static void set_material_index(MPoly &mpoly, const int &index)
static void set_material_index(MPoly &mpoly, int index)
{
mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX));
}
@@ -797,7 +784,7 @@ static bool get_shade_smooth(const MPoly &mpoly)
return mpoly.flag & ME_SMOOTH;
}
static void set_shade_smooth(MPoly &mpoly, const bool &value)
static void set_shade_smooth(MPoly &mpoly, bool value)
{
SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH);
}
@@ -807,7 +794,7 @@ static float2 get_loop_uv(const MLoopUV &uv)
return float2(uv.uv);
}
static void set_loop_uv(MLoopUV &uv, const float2 &co)
static void set_loop_uv(MLoopUV &uv, float2 co)
{
copy_v2_v2(uv.uv, co);
}
@@ -821,7 +808,7 @@ static Color4f get_loop_color(const MLoopCol &col)
return linear_color;
}
static void set_loop_color(MLoopCol &col, const Color4f &linear_color)
static void set_loop_color(MLoopCol &col, Color4f linear_color)
{
linearrgb_to_srgb_uchar4(&col.r, linear_color);
}
@@ -831,71 +818,62 @@ static float get_crease(const MEdge &edge)
return edge.crease / 255.0f;
}
static void set_crease(MEdge &edge, const float &value)
static void set_crease(MEdge &edge, float value)
{
edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
}
class VertexWeightWriteAttribute final : public WriteAttribute {
class VMutableArray_For_VertexWeights final : public VMutableArray<float> {
private:
MDeformVert *dverts_;
const int dvert_index_;
public:
VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index)
: WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
dverts_(dverts),
dvert_index_(dvert_index)
VMutableArray_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index)
: VMutableArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
{
}
void get_internal(const int64_t index, void *r_value) const override
float get_impl(const int64_t index) const override
{
get_internal(dverts_, dvert_index_, index, r_value);
return get_internal(dverts_, dvert_index_, index);
}
void set_internal(const int64_t index, const void *value) override
void set_impl(const int64_t index, const float value) override
{
MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
weight->weight = *reinterpret_cast<const float *>(value);
weight->weight = value;
}
static void get_internal(const MDeformVert *dverts,
const int dvert_index,
const int64_t index,
void *r_value)
static float get_internal(const MDeformVert *dverts, const int dvert_index, const int64_t index)
{
if (dverts == nullptr) {
*(float *)r_value = 0.0f;
return;
return 0.0f;
}
const MDeformVert &dvert = dverts[index];
for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
if (weight.def_nr == dvert_index) {
*(float *)r_value = weight.weight;
return;
return weight.weight;
}
}
*(float *)r_value = 0.0f;
return 0.0f;
}
};
class VertexWeightReadAttribute final : public ReadAttribute {
class VArray_For_VertexWeights final : public VArray<float> {
private:
const MDeformVert *dverts_;
const int dvert_index_;
public:
VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index)
: ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
dverts_(dverts),
dvert_index_(dvert_index)
VArray_For_VertexWeights(const MDeformVert *dverts, const int totvert, const int dvert_index)
: VArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
{
}
void get_internal(const int64_t index, void *r_value) const override
float get_impl(const int64_t index) const override
{
VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value);
return VMutableArray_For_VertexWeights::get_internal(dverts_, dvert_index_, index);
}
};
@@ -904,8 +882,8 @@ class VertexWeightReadAttribute final : public ReadAttribute {
*/
class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
public:
ReadAttributePtr try_get_for_read(const GeometryComponent &component,
const StringRef attribute_name) const final
ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
const StringRef attribute_name) const final
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
@@ -917,15 +895,17 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
}
if (mesh == nullptr || mesh->dvert == nullptr) {
static const float default_value = 0.0f;
return std::make_unique<ConstantReadAttribute>(
ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get<float>(), &default_value);
return {std::make_unique<fn::GVArray_For_SingleValueRef>(
CPPType::get<float>(), mesh->totvert, &default_value),
ATTR_DOMAIN_POINT};
}
return std::make_unique<VertexWeightReadAttribute>(
mesh->dvert, mesh->totvert, vertex_group_index);
return {std::make_unique<fn::GVArray_For_EmbeddedVArray<float, VArray_For_VertexWeights>>(
mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index),
ATTR_DOMAIN_POINT};
}
WriteAttributePtr try_get_for_write(GeometryComponent &component,
const StringRef attribute_name) const final
WriteAttributeLookup try_get_for_write(GeometryComponent &component,
const StringRef attribute_name) const final
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
@@ -946,8 +926,11 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer(
&mesh->vdata, CD_MDEFORMVERT, mesh->totvert);
}
return std::make_unique<blender::bke::VertexWeightWriteAttribute>(
mesh->dvert, mesh->totvert, vertex_group_index);
return {
std::make_unique<
fn::GVMutableArray_For_EmbeddedVMutableArray<float, VMutableArray_For_VertexWeights>>(
mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index),
ATTR_DOMAIN_POINT};
}
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
@@ -1009,7 +992,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
{
}
ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final
std::unique_ptr<GVArray> try_get_for_read(const GeometryComponent &component) const final
{
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
const Mesh *mesh = mesh_component.get_for_read();
@@ -1022,8 +1005,8 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
return std::make_unique<ArrayReadAttribute<float3>>(
ATTR_DOMAIN_FACE, Span<float3>((const float3 *)data, mesh->totpoly));
return std::make_unique<fn::GVArray_For_Span<float3>>(
Span<float3>((const float3 *)data, mesh->totpoly));
}
Array<float3> normals(mesh->totpoly);
@@ -1032,10 +1015,11 @@ 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_FACE, std::move(normals));
return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals));
}
WriteAttributePtr try_get_for_write(GeometryComponent &UNUSED(component)) const final
std::unique_ptr<GVMutableArray> try_get_for_write(
GeometryComponent &UNUSED(component)) const final
{
return {};
}
@@ -1105,12 +1089,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
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>,
make_derived_read_attribute<MVert, float3, get_vertex_position>,
make_derived_write_attribute<MVert, float3, get_vertex_position, set_vertex_position>,
tag_normals_dirty_when_writing_position);
static NormalAttributeProvider normal;
@@ -1124,12 +1104,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
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>,
make_derived_read_attribute<MPoly, int, get_material_index>,
make_derived_write_attribute<MPoly, int, get_material_index, set_material_index>,
nullptr);
static BuiltinCustomDataLayerProvider shade_smooth(
@@ -1141,12 +1117,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
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>,
make_derived_read_attribute<MPoly, bool, get_shade_smooth>,
make_derived_write_attribute<MPoly, bool, get_shade_smooth, set_shade_smooth>,
nullptr);
static BuiltinCustomDataLayerProvider crease(
@@ -1158,8 +1130,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
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>,
make_derived_read_attribute<MEdge, float, get_crease>,
make_derived_write_attribute<MEdge, float, get_crease, set_crease>,
nullptr);
static NamedLegacyCustomDataProvider uvs(
@@ -1167,20 +1139,16 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
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>);
make_derived_read_attribute<MLoopUV, float2, get_loop_uv>,
make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv>);
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>);
make_derived_read_attribute<MLoopCol, Color4f, get_loop_color>,
make_derived_write_attribute<MLoopCol, Color4f, get_loop_color, set_loop_color>);
static VertexGroupsAttributeProvider vertex_groups;
static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);

View File

@@ -140,16 +140,18 @@ int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) con
namespace blender::bke {
template<typename T, AttributeDomain Domain>
static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size)
template<typename T>
static std::unique_ptr<GVArray> make_array_read_attribute(const void *data, const int domain_size)
{
return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size));
return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size));
}
template<typename T, AttributeDomain Domain>
static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size)
template<typename T>
static std::unique_ptr<GVMutableArray> make_array_write_attribute(void *data,
const int domain_size)
{
return std::make_unique<ArrayWriteAttribute<T>>(Domain, MutableSpan<T>((T *)data, domain_size));
return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>(
MutableSpan<T>((T *)data, domain_size));
}
/**
@@ -179,30 +181,28 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
},
update_custom_data_pointers};
static BuiltinCustomDataLayerProvider position(
"position",
ATTR_DOMAIN_POINT,
CD_PROP_FLOAT3,
CD_PROP_FLOAT3,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
point_access,
make_array_read_attribute<float3, ATTR_DOMAIN_POINT>,
make_array_write_attribute<float3, ATTR_DOMAIN_POINT>,
nullptr);
static BuiltinCustomDataLayerProvider radius(
"radius",
ATTR_DOMAIN_POINT,
CD_PROP_FLOAT,
CD_PROP_FLOAT,
BuiltinAttributeProvider::Creatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::Deletable,
point_access,
make_array_read_attribute<float, ATTR_DOMAIN_POINT>,
make_array_write_attribute<float, ATTR_DOMAIN_POINT>,
nullptr);
static BuiltinCustomDataLayerProvider position("position",
ATTR_DOMAIN_POINT,
CD_PROP_FLOAT3,
CD_PROP_FLOAT3,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
point_access,
make_array_read_attribute<float3>,
make_array_write_attribute<float3>,
nullptr);
static BuiltinCustomDataLayerProvider radius("radius",
ATTR_DOMAIN_POINT,
CD_PROP_FLOAT,
CD_PROP_FLOAT,
BuiltinAttributeProvider::Creatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::Deletable,
point_access,
make_array_read_attribute<float>,
make_array_write_attribute<float>,
nullptr);
static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
return ComponentAttributeProviders({&position, &radius}, {&point_custom_data});
}

View File

@@ -36,30 +36,42 @@ static void geometry_set_collect_recursive_collection(const Collection &collecti
const float4x4 &transform,
Vector<GeometryInstanceGroup> &r_sets);
static void add_final_mesh_as_geometry_component(const Object &object, GeometrySet &geometry_set)
{
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(&const_cast<Object &>(object),
false);
if (mesh != nullptr) {
BKE_mesh_wrapper_ensure_mdata(mesh);
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
mesh_component.copy_vertex_group_names_from_object(object);
}
}
/**
* \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
*/
static GeometrySet object_get_geometry_set_for_read(const Object &object)
{
/* Objects evaluated with a nodes modifier will have a geometry set already. */
if (object.type == OB_MESH && object.mode == OB_MODE_EDIT) {
GeometrySet geometry_set;
if (object.runtime.geometry_set_eval != nullptr) {
/* `geometry_set_eval` only contains non-mesh components, see `editbmesh_build_data`. */
geometry_set = *object.runtime.geometry_set_eval;
}
add_final_mesh_as_geometry_component(object, geometry_set);
return geometry_set;
}
if (object.runtime.geometry_set_eval != nullptr) {
return *object.runtime.geometry_set_eval;
}
/* Otherwise, construct a new geometry set with the component based on the object type. */
GeometrySet new_geometry_set;
GeometrySet geometry_set;
if (object.type == OB_MESH) {
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(
&const_cast<Object &>(object), false);
if (mesh != nullptr) {
BKE_mesh_wrapper_ensure_mdata(mesh);
MeshComponent &mesh_component = new_geometry_set.get_component_for_write<MeshComponent>();
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
mesh_component.copy_vertex_group_names_from_object(object);
}
add_final_mesh_as_geometry_component(object, geometry_set);
}
/* TODO: Cover the case of point-clouds without modifiers-- they may not be covered by the
@@ -68,7 +80,7 @@ static GeometrySet object_get_geometry_set_for_read(const Object &object)
/* TODO: Add volume support. */
/* Return by value since there is not always an existing geometry set owned elsewhere to use. */
return new_geometry_set;
return geometry_set;
}
static void geometry_set_collect_recursive_collection_instance(
@@ -438,12 +450,13 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
BLI_assert(cpp_type != nullptr);
result.attribute_try_create(entry.key, domain_output, data_type_output);
WriteAttributePtr write_attribute = result.attribute_try_get_for_write(name);
if (!write_attribute || &write_attribute->cpp_type() != cpp_type ||
write_attribute->domain() != domain_output) {
WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(name);
if (!write_attribute || &write_attribute.varray->type() != cpp_type ||
write_attribute.domain != domain_output) {
continue;
}
fn::GMutableSpan dst_span = write_attribute->get_span_for_write_only();
fn::GVMutableArray_GSpan dst_span{*write_attribute.varray};
int offset = 0;
for (const GeometryInstanceGroup &set_group : set_groups) {
@@ -455,11 +468,11 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
if (domain_size == 0) {
continue; /* Domain size is 0, so no need to increment the offset. */
}
ReadAttributePtr source_attribute = component.attribute_try_get_for_read(
std::unique_ptr<GVArray> source_attribute = component.attribute_try_get_for_read(
name, domain_output, data_type_output);
if (source_attribute) {
fn::GSpan src_span = source_attribute->get_span();
fn::GVArray_GSpan src_span{*source_attribute};
const void *src_buffer = src_span.data();
for (const int UNUSED(i) : set_group.transforms.index_range()) {
void *dst_buffer = dst_span[offset];
@@ -474,7 +487,7 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
}
}
write_attribute->apply_span();
dst_span.save();
}
}

View File

@@ -4135,7 +4135,7 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
const bool use_hidden)
{
bool ok = false;
if ((ob->transflag & OB_DUPLI) == 0) {
if ((ob->transflag & OB_DUPLI) == 0 && ob->runtime.geometry_set_eval == NULL) {
return ok;
}

View File

@@ -176,6 +176,13 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
CustomData_MeshMasks cddata_masks = scene->customdata_mask;
CustomData_MeshMasks_update(&cddata_masks, &CD_MASK_BAREMESH);
/* Custom attributes should not be removed automatically. They might be used by the render
* engine or scripts. They can still be removed explicitly using geometry nodes. */
cddata_masks.vmask |= CD_MASK_PROP_ALL;
cddata_masks.emask |= CD_MASK_PROP_ALL;
cddata_masks.fmask |= CD_MASK_PROP_ALL;
cddata_masks.pmask |= CD_MASK_PROP_ALL;
cddata_masks.lmask |= CD_MASK_PROP_ALL;
/* Make sure Freestyle edge/face marks appear in DM for render (see T40315).
* Due to Line Art implementation, edge marks should also be shown in viewport. */
#ifdef WITH_FREESTYLE

View File

@@ -94,7 +94,7 @@ template<typename T> class Span {
using iterator = const T *;
using size_type = int64_t;
private:
protected:
const T *data_ = nullptr;
int64_t size_ = 0;
@@ -477,7 +477,7 @@ template<typename T> class MutableSpan {
using iterator = T *;
using size_type = int64_t;
private:
protected:
T *data_;
int64_t size_;

View File

@@ -37,6 +37,7 @@
* see of the increased compile time and binary size is worth it.
*/
#include "BLI_array.hh"
#include "BLI_span.hh"
namespace blender {
@@ -71,6 +72,11 @@ template<typename T> class VArray {
return size_ == 0;
}
IndexRange index_range() const
{
return IndexRange(size_);
}
/* Returns true when the virtual array is stored as a span internally. */
bool is_span() const
{
@@ -82,13 +88,13 @@ template<typename T> class VArray {
/* Returns the internally used span of the virtual array. This invokes undefined behavior is the
* virtual array is not stored as a span internally. */
Span<T> get_span() const
Span<T> get_internal_span() const
{
BLI_assert(this->is_span());
if (size_ == 0) {
return {};
}
return this->get_span_impl();
return this->get_internal_span_impl();
}
/* Returns true when the virtual array returns the same value for every index. */
@@ -102,20 +108,35 @@ template<typename T> class VArray {
/* Returns the value that is returned for every index. This invokes undefined behavior if the
* virtual array would not return the same value for every index. */
T get_single() const
T get_internal_single() const
{
BLI_assert(this->is_single());
if (size_ == 1) {
return this->get(0);
}
return this->get_single_impl();
return this->get_internal_single_impl();
}
/* Get the element at a specific index. Note that this operator cannot be used to assign values
* to an index, because the return value is not a reference. */
T operator[](const int64_t index) const
{
return this->get(index);
}
/* Copy the entire virtual array into a span. */
void materialize(MutableSpan<T> r_span) const
{
BLI_assert(size_ == r_span.size());
this->materialize_impl(r_span);
}
void materialize_to_uninitialized(MutableSpan<T> r_span) const
{
BLI_assert(size_ == r_span.size());
this->materialize_to_uninitialized_impl(r_span);
}
protected:
virtual T get_impl(const int64_t index) const = 0;
@@ -124,7 +145,7 @@ template<typename T> class VArray {
return false;
}
virtual Span<T> get_span_impl() const
virtual Span<T> get_internal_span_impl() const
{
BLI_assert_unreachable();
return {};
@@ -135,56 +156,198 @@ template<typename T> class VArray {
return false;
}
virtual T get_single_impl() const
virtual T get_internal_single_impl() const
{
/* Provide a default implementation, so that subclasses don't have to provide it. This method
* should never be called because `is_single_impl` returns false by default. */
BLI_assert_unreachable();
return T();
}
virtual void materialize_impl(MutableSpan<T> r_span) const
{
if (this->is_span()) {
const Span<T> span = this->get_internal_span();
initialized_copy_n(span.data(), size_, r_span.data());
}
else if (this->is_single()) {
const T single = this->get_internal_single();
initialized_fill_n(r_span.data(), size_, single);
}
else {
const int64_t size = size_;
for (int64_t i = 0; i < size; i++) {
r_span[i] = this->get(i);
}
}
}
virtual void materialize_to_uninitialized_impl(MutableSpan<T> r_span) const
{
if (this->is_span()) {
const Span<T> span = this->get_internal_span();
uninitialized_copy_n(span.data(), size_, r_span.data());
}
else if (this->is_single()) {
const T single = this->get_internal_single();
uninitialized_fill_n(r_span.data(), size_, single);
}
else {
const int64_t size = size_;
T *dst = r_span.data();
for (int64_t i = 0; i < size; i++) {
new (dst + i) T(this->get(i));
}
}
}
};
/* Similar to VArray, but the elements are mutable. */
template<typename T> class VMutableArray : public VArray<T> {
public:
VMutableArray(const int64_t size) : VArray<T>(size)
{
}
void set(const int64_t index, T value)
{
BLI_assert(index >= 0);
BLI_assert(index < this->size_);
this->set_impl(index, std::move(value));
}
/* Copy the values from the source span to all elements in the virtual array. */
void set_all(Span<T> src)
{
BLI_assert(src.size() == this->size_);
this->set_all_impl(src);
}
MutableSpan<T> get_internal_span()
{
BLI_assert(this->is_span());
Span<T> span = static_cast<const VArray<T> *>(this)->get_internal_span();
return MutableSpan<T>(const_cast<T *>(span.data()), span.size());
}
protected:
virtual void set_impl(const int64_t index, T value) = 0;
virtual void set_all_impl(Span<T> src)
{
if (this->is_span()) {
const MutableSpan<T> span = this->get_internal_span();
initialized_copy_n(src.data(), this->size_, span.data());
}
else {
const int64_t size = this->size_;
for (int64_t i = 0; i < size; i++) {
this->set(i, src[i]);
}
}
}
};
/**
* A virtual array implementation for a span. This class is final so that it can be devirtualized
* by the compiler in some cases (e.g. when #devirtualize_varray is used).
* A virtual array implementation for a span. Methods in this class are final so that it can be
* devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is used).
*/
template<typename T> class VArrayForSpan final : public VArray<T> {
private:
const T *data_;
template<typename T> class VArray_For_Span : public VArray<T> {
protected:
const T *data_ = nullptr;
public:
VArrayForSpan(const Span<T> data) : VArray<T>(data.size()), data_(data.data())
VArray_For_Span(const Span<T> data) : VArray<T>(data.size()), data_(data.data())
{
}
protected:
T get_impl(const int64_t index) const override
VArray_For_Span(const int64_t size) : VArray<T>(size)
{
}
T get_impl(const int64_t index) const final
{
return data_[index];
}
bool is_span_impl() const final
{
return true;
}
Span<T> get_internal_span_impl() const final
{
return Span<T>(data_, this->size_);
}
};
template<typename T> class VMutableArray_For_MutableSpan : public VMutableArray<T> {
protected:
T *data_ = nullptr;
public:
VMutableArray_For_MutableSpan(const MutableSpan<T> data)
: VMutableArray<T>(data.size()), data_(data.data())
{
}
protected:
VMutableArray_For_MutableSpan(const int64_t size) : VMutableArray<T>(size)
{
}
T get_impl(const int64_t index) const final
{
return data_[index];
}
void set_impl(const int64_t index, T value) final
{
data_[index] = value;
}
bool is_span_impl() const override
{
return true;
}
Span<T> get_span_impl() const override
Span<T> get_internal_span_impl() const override
{
return Span<T>(data_, this->size_);
}
};
/**
* A variant of `VArray_For_Span` that owns the underlying data.
* The `Container` type has to implement a `size()` and `data()` method.
* The `data()` method has to return a pointer to the first element in the continuous array of
* elements.
*/
template<typename Container, typename T = typename Container::value_type>
class VArray_For_ArrayContainer : public VArray_For_Span<T> {
private:
Container container_;
public:
VArray_For_ArrayContainer(Container container)
: VArray_For_Span<T>((int64_t)container.size()), container_(std::move(container))
{
this->data_ = container_.data();
}
};
/**
* A virtual array implementation that returns the same value for every index. This class is final
* so that it can be devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is
* used).
*/
template<typename T> class VArrayForSingle final : public VArray<T> {
template<typename T> class VArray_For_Single final : public VArray<T> {
private:
T value_;
public:
VArrayForSingle(T value, const int64_t size) : VArray<T>(size), value_(std::move(value))
VArray_For_Single(T value, const int64_t size) : VArray<T>(size), value_(std::move(value))
{
}
@@ -199,7 +362,7 @@ template<typename T> class VArrayForSingle final : public VArray<T> {
return this->size_ == 1;
}
Span<T> get_span_impl() const override
Span<T> get_internal_span_impl() const override
{
return Span<T>(&value_, 1);
}
@@ -209,12 +372,170 @@ template<typename T> class VArrayForSingle final : public VArray<T> {
return true;
}
T get_single_impl() const override
T get_internal_single_impl() const override
{
return value_;
}
};
/**
* In many cases a virtual array is a span internally. In those cases, access to individual could
* be much more efficient than calling a virtual method. When the underlying virtual array is not a
* span, this class allocates a new array and copies the values over.
*
* This should be used in those cases:
* - All elements in the virtual array are accessed multiple times.
* - In most cases, the underlying virtual array is a span, so no copy is necessary to benefit
* from faster access.
* - An API is called, that does not accept virtual arrays, but only spans.
*/
template<typename T> class VArray_Span final : public Span<T> {
private:
const VArray<T> &varray_;
Array<T> owned_data_;
public:
VArray_Span(const VArray<T> &varray) : Span<T>(), varray_(varray)
{
this->size_ = varray_.size();
if (varray_.is_span()) {
this->data_ = varray_.get_internal_span().data();
}
else {
owned_data_.~Array();
new (&owned_data_) Array<T>(varray_.size(), NoInitialization{});
varray_.materialize_to_uninitialized(owned_data_);
this->data_ = owned_data_.data();
}
}
};
/**
* Same as VArray_Span, but for a mutable span.
* The important thing to note is that when changing this span, the results might not be
* immediately reflected in the underlying virtual array (only when the virtual array is a span
* internally). The #save method can be used to write all changes to the underlying virtual array,
* if necessary.
*/
template<typename T> class VMutableArray_Span final : public MutableSpan<T> {
private:
VMutableArray<T> &varray_;
Array<T> owned_data_;
bool save_has_been_called_ = false;
bool show_not_saved_warning_ = true;
public:
/* Create a span for any virtual array. This is cheap when the virtual array is a span itself. If
* not, a new array has to be allocated as a wrapper for the underlying virtual array. */
VMutableArray_Span(VMutableArray<T> &varray, const bool copy_values_to_span = true)
: MutableSpan<T>(), varray_(varray)
{
this->size_ = varray_.size();
if (varray_.is_span()) {
this->data_ = varray_.get_internal_span().data();
}
else {
if (copy_values_to_span) {
owned_data_.~Array();
new (&owned_data_) Array<T>(varray_.size(), NoInitialization{});
varray_.materialize_to_uninitialized(owned_data_);
}
else {
owned_data_.reinitialize(varray_.size());
}
this->data_ = owned_data_.data();
}
}
~VMutableArray_Span()
{
if (show_not_saved_warning_) {
if (!save_has_been_called_) {
std::cout << "Warning: Call `save()` to make sure that changes persist in all cases.\n";
}
}
}
/* Write back all values from a temporary allocated array to the underlying virtual array. */
void save()
{
save_has_been_called_ = true;
if (this->data_ != owned_data_.data()) {
return;
}
varray_.set_all(owned_data_);
}
void disable_not_applied_warning()
{
show_not_saved_warning_ = false;
}
};
/**
* This class makes it easy to create a virtual array for an existing function or lambda. The
* `GetFunc` should take a single `index` argument and return the value at that index.
*/
template<typename T, typename GetFunc> class VArray_For_Func final : public VArray<T> {
private:
GetFunc get_func_;
public:
VArray_For_Func(const int64_t size, GetFunc get_func)
: VArray<T>(size), get_func_(std::move(get_func))
{
}
private:
T get_impl(const int64_t index) const override
{
return get_func_(index);
}
};
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
class VArray_For_DerivedSpan : public VArray<ElemT> {
private:
const StructT *data_;
public:
VArray_For_DerivedSpan(const Span<StructT> data) : VArray<ElemT>(data.size()), data_(data.data())
{
}
private:
ElemT get_impl(const int64_t index) const override
{
return GetFunc(data_[index]);
}
};
template<typename StructT,
typename ElemT,
ElemT (*GetFunc)(const StructT &),
void (*SetFunc)(StructT &, ElemT)>
class VMutableArray_For_DerivedSpan : public VMutableArray<ElemT> {
private:
StructT *data_;
public:
VMutableArray_For_DerivedSpan(const MutableSpan<StructT> data)
: VMutableArray<ElemT>(data.size()), data_(data.data())
{
}
private:
ElemT get_impl(const int64_t index) const override
{
return GetFunc(data_[index]);
}
void set_impl(const int64_t index, ElemT value) override
{
SetFunc(data_[index], std::move(value));
}
};
/**
* Generate multiple versions of the given function optimized for different virtual arrays.
* One has to be careful with nesting multiple devirtualizations, because that results in an
@@ -229,14 +550,14 @@ inline void devirtualize_varray(const VArray<T> &varray, const Func &func, bool
/* Support disabling the devirtualization to simplify benchmarking. */
if (enable) {
if (varray.is_single()) {
/* `VArrayForSingle` can be used for devirtualization, because it is declared `final`. */
const VArrayForSingle<T> varray_single{varray.get_single(), varray.size()};
/* `VArray_For_Single` can be used for devirtualization, because it is declared `final`. */
const VArray_For_Single<T> varray_single{varray.get_internal_single(), varray.size()};
func(varray_single);
return;
}
if (varray.is_span()) {
/* `VArrayForSpan` can be used for devirtualization, because it is declared `final`. */
const VArrayForSpan<T> varray_span{varray.get_span()};
/* `VArray_For_Span` can be used for devirtualization, because it is declared `final`. */
const VArray_For_Span<T> varray_span{varray.get_internal_span()};
func(varray_span);
return;
}
@@ -262,26 +583,26 @@ inline void devirtualize_varray2(const VArray<T1> &varray1,
const bool is_single1 = varray1.is_single();
const bool is_single2 = varray2.is_single();
if (is_span1 && is_span2) {
const VArrayForSpan<T1> varray1_span{varray1.get_span()};
const VArrayForSpan<T2> varray2_span{varray2.get_span()};
const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
func(varray1_span, varray2_span);
return;
}
if (is_span1 && is_single2) {
const VArrayForSpan<T1> varray1_span{varray1.get_span()};
const VArrayForSingle<T2> varray2_single{varray2.get_single(), varray2.size()};
const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
func(varray1_span, varray2_single);
return;
}
if (is_single1 && is_span2) {
const VArrayForSingle<T1> varray1_single{varray1.get_single(), varray1.size()};
const VArrayForSpan<T2> varray2_span{varray2.get_span()};
const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
func(varray1_single, varray2_span);
return;
}
if (is_single1 && is_single2) {
const VArrayForSingle<T1> varray1_single{varray1.get_single(), varray1.size()};
const VArrayForSingle<T2> varray2_single{varray2.get_single(), varray2.size()};
const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
func(varray1_single, varray2_single);
return;
}

View File

@@ -1,26 +1,29 @@
/* Apache License, Version 2.0 */
#include "BLI_array.hh"
#include "BLI_strict_flags.h"
#include "BLI_vector.hh"
#include "BLI_vector_set.hh"
#include "BLI_virtual_array.hh"
#include "testing/testing.h"
namespace blender::tests {
TEST(virtual_array, ForSpan)
TEST(virtual_array, Span)
{
std::array<int, 5> data = {3, 4, 5, 6, 7};
VArrayForSpan<int> varray{data};
VArray_For_Span<int> varray{data};
EXPECT_EQ(varray.size(), 5);
EXPECT_EQ(varray.get(0), 3);
EXPECT_EQ(varray.get(4), 7);
EXPECT_TRUE(varray.is_span());
EXPECT_FALSE(varray.is_single());
EXPECT_EQ(varray.get_span().data(), data.data());
EXPECT_EQ(varray.get_internal_span().data(), data.data());
}
TEST(virtual_array, ForSingle)
TEST(virtual_array, Single)
{
VArrayForSingle<int> varray{10, 4};
VArray_For_Single<int> varray{10, 4};
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray.get(0), 10);
EXPECT_EQ(varray.get(3), 10);
@@ -28,4 +31,124 @@ TEST(virtual_array, ForSingle)
EXPECT_TRUE(varray.is_single());
}
TEST(virtual_array, Array)
{
Array<int> array = {1, 2, 3, 5, 8};
{
VArray_For_ArrayContainer varray{array};
EXPECT_EQ(varray.size(), 5);
EXPECT_EQ(varray[0], 1);
EXPECT_EQ(varray[2], 3);
EXPECT_EQ(varray[3], 5);
EXPECT_TRUE(varray.is_span());
}
{
VArray_For_ArrayContainer varray{std::move(array)};
EXPECT_EQ(varray.size(), 5);
EXPECT_EQ(varray[0], 1);
EXPECT_EQ(varray[2], 3);
EXPECT_EQ(varray[3], 5);
EXPECT_TRUE(varray.is_span());
}
{
VArray_For_ArrayContainer varray{array}; /* NOLINT: bugprone-use-after-move */
EXPECT_TRUE(varray.is_empty());
}
}
TEST(virtual_array, Vector)
{
Vector<int> vector = {9, 8, 7, 6};
VArray_For_ArrayContainer varray{std::move(vector)};
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray[0], 9);
EXPECT_EQ(varray[3], 6);
}
TEST(virtual_array, StdVector)
{
std::vector<int> vector = {5, 6, 7, 8};
VArray_For_ArrayContainer varray{std::move(vector)};
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray[0], 5);
EXPECT_EQ(varray[1], 6);
}
TEST(virtual_array, StdArray)
{
std::array<int, 4> array = {2, 3, 4, 5};
VArray_For_ArrayContainer varray{array};
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray[0], 2);
EXPECT_EQ(varray[1], 3);
}
TEST(virtual_array, VectorSet)
{
VectorSet<int> vector_set = {5, 3, 7, 3, 3, 5, 1};
VArray_For_ArrayContainer varray{std::move(vector_set)};
EXPECT_TRUE(vector_set.is_empty()); /* NOLINT: bugprone-use-after-move. */
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray[0], 5);
EXPECT_EQ(varray[1], 3);
EXPECT_EQ(varray[2], 7);
EXPECT_EQ(varray[3], 1);
}
TEST(virtual_array, Func)
{
auto func = [](int64_t index) { return (int)(index * index); };
VArray_For_Func<int, decltype(func)> varray{10, func};
EXPECT_EQ(varray.size(), 10);
EXPECT_EQ(varray[0], 0);
EXPECT_EQ(varray[3], 9);
EXPECT_EQ(varray[9], 81);
}
TEST(virtual_array, AsSpan)
{
auto func = [](int64_t index) { return (int)(10 * index); };
VArray_For_Func<int, decltype(func)> func_varray{10, func};
VArray_Span span_varray{func_varray};
EXPECT_EQ(span_varray.size(), 10);
Span<int> span = span_varray;
EXPECT_EQ(span.size(), 10);
EXPECT_EQ(span[0], 0);
EXPECT_EQ(span[3], 30);
EXPECT_EQ(span[6], 60);
}
static int get_x(const std::array<int, 3> &item)
{
return item[0];
}
static void set_x(std::array<int, 3> &item, int value)
{
item[0] = value;
}
TEST(virtual_array, DerivedSpan)
{
Vector<std::array<int, 3>> vector;
vector.append({3, 4, 5});
vector.append({1, 1, 1});
{
VArray_For_DerivedSpan<std::array<int, 3>, int, get_x> varray{vector};
EXPECT_EQ(varray.size(), 2);
EXPECT_EQ(varray[0], 3);
EXPECT_EQ(varray[1], 1);
}
{
VMutableArray_For_DerivedSpan<std::array<int, 3>, int, get_x, set_x> varray{vector};
EXPECT_EQ(varray.size(), 2);
EXPECT_EQ(varray[0], 3);
EXPECT_EQ(varray[1], 1);
varray.set(0, 10);
varray.set(1, 20);
EXPECT_EQ(vector[0][0], 10);
EXPECT_EQ(vector[1][0], 20);
}
}
} // namespace blender::tests

View File

@@ -226,7 +226,10 @@ int BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh, const uint64
* Struct for temporarily loading datablocks from a blend file.
*/
typedef struct TempLibraryContext {
struct Main *temp_main;
/** Temporary main used for library data. */
struct Main *bmain_lib;
/** Temporary main used to load data into (currently initialized from `real_main`). */
struct Main *bmain_base;
struct BlendHandle *blendhandle;
struct LibraryLink_Params liblink_params;
struct Library *lib;

View File

@@ -21,6 +21,9 @@
#include "MEM_guardedalloc.h"
#include "BLI_string.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "DNA_ID.h"
@@ -32,15 +35,20 @@ TempLibraryContext *BLO_library_temp_load_id(struct Main *real_main,
struct ReportList *reports)
{
TempLibraryContext *temp_lib_ctx = MEM_callocN(sizeof(*temp_lib_ctx), __func__);
temp_lib_ctx->bmain_base = BKE_main_new();
/* Copy the file path so any path remapping is performed properly. */
STRNCPY(temp_lib_ctx->bmain_base->name, real_main->name);
temp_lib_ctx->blendhandle = BLO_blendhandle_from_file(blend_file_path, reports);
BLO_library_link_params_init(&temp_lib_ctx->liblink_params, real_main, 0, LIB_TAG_TEMP_MAIN);
BLO_library_link_params_init(
&temp_lib_ctx->liblink_params, temp_lib_ctx->bmain_base, 0, LIB_TAG_TEMP_MAIN);
temp_lib_ctx->temp_main = BLO_library_link_begin(
temp_lib_ctx->bmain_lib = BLO_library_link_begin(
&temp_lib_ctx->blendhandle, blend_file_path, &temp_lib_ctx->liblink_params);
temp_lib_ctx->temp_id = BLO_library_link_named_part(temp_lib_ctx->temp_main,
temp_lib_ctx->temp_id = BLO_library_link_named_part(temp_lib_ctx->bmain_lib,
&temp_lib_ctx->blendhandle,
idcode,
idname,
@@ -51,8 +59,13 @@ TempLibraryContext *BLO_library_temp_load_id(struct Main *real_main,
void BLO_library_temp_free(TempLibraryContext *temp_lib_ctx)
{
/* This moves the temporary ID and any indirectly loaded data into `bmain_base`
* only to free `bmain_base`, while redundant this is the typical code-path for library linking,
* it's more convenient to follow this convention rather than create a new code-path for this
* one-off use case. */
BLO_library_link_end(
temp_lib_ctx->temp_main, &temp_lib_ctx->blendhandle, &temp_lib_ctx->liblink_params);
temp_lib_ctx->bmain_lib, &temp_lib_ctx->blendhandle, &temp_lib_ctx->liblink_params);
BLO_blendhandle_close(temp_lib_ctx->blendhandle);
BKE_main_free(temp_lib_ctx->bmain_base);
MEM_freeN(temp_lib_ctx);
}

View File

@@ -1574,7 +1574,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->ed != NULL) {
if (scene->toolsettings->sequencer_tool_settings == NULL) {
scene->toolsettings->sequencer_tool_settings = SEQ_tool_settings_init();
}
}
@@ -2009,18 +2009,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - "versioning_userdef.c", #blo_do_versions_userdef
* - "versioning_userdef.c", #do_versions_theme
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
if (!MAIN_VERSION_ATLEAST(bmain, 293, 18)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
version_node_socket_name(ntree, GEO_NODE_VOLUME_TO_MESH, "Grid", "Density");
@@ -2069,4 +2058,17 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - "versioning_userdef.c", #blo_do_versions_userdef
* - "versioning_userdef.c", #do_versions_theme
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
}
}

View File

@@ -19,7 +19,6 @@ set(INC
../include
../../blenkernel
../../blenlib
../../blenfont
../../blentranslation
../../depsgraph
../../gpu

View File

@@ -33,7 +33,6 @@
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_vec_types.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
@@ -51,27 +50,15 @@
#include "WM_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "ED_armature.h"
#include "ED_keyframes_draw.h"
#include "ED_markers.h"
#include "ED_numinput.h"
#include "ED_screen.h"
#include "ED_space_api.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
#include "armature_intern.h"
#include "BLF_api.h"
/* Pixel distance from 0% to 100%. */
#define SLIDE_PIXEL_DISTANCE (300 * U.dpi_fac)
/* **************************************************** */
/* == POSE 'SLIDING' TOOLS ==
*
@@ -123,43 +110,15 @@ typedef struct tPoseSlideOp {
/** unused for now, but can later get used for storing runtime settings.... */
short flag;
/* Store overlay settings when invoking the operator. Bones will be temporarily hidden. */
int overlay_flag;
/** which transforms/channels are affected (ePoseSlide_Channels) */
short channels;
/** axis-limits for transforms (ePoseSlide_AxisLock) */
short axislock;
/* Allow overshoot or clamp between 0% and 100%. */
bool overshoot;
/* Reduces percentage delta from mouse movement. */
bool precision;
/* Move percentage in 10% steps. */
bool increments;
/* Pixel value in area space where the slider starts. */
int slider_start[2];
/* Draw callback handler. */
void *draw_handle;
/* Accumulative, unclamped and unrounded percentage. */
float raw_percentage;
/* 0-1 value for determining the influence of whatever is relevant. */
/** 0-1 value for determining the influence of whatever is relevant */
float percentage;
/* Cursor position in region space. */
int cursor_region_x;
int cursor_region_y;
/* Last cursor position in screen space used for mouse movement delta calculation. */
int last_cursor_x;
/* Numeric input. */
/** numeric input */
NumInput num;
struct tPoseSlideObject *ob_data_array;
@@ -228,135 +187,6 @@ static const EnumPropertyItem prop_axis_lock_types[] = {
/* ------------------------------------ */
/* Draw a given string centered at the given coordinates. */
static void draw_centered_string_with_background(
const char *string, const float x, const float y, const uchar color_bg[4], const int fontid)
{
const int bg_margin = 5 * U.dpi_fac;
float string_pixel_size[2];
/* Get width and height of printed string to center above ticks. */
BLF_width_and_height(
fontid, string, sizeof(string), &string_pixel_size[0], &string_pixel_size[1]);
const unsigned char col[3] = {color_bg[0], color_bg[1], color_bg[2]};
const rctf background_rect = {.xmin = x - string_pixel_size[0] / 2 - bg_margin,
.xmax = x + string_pixel_size[0] / 2 + bg_margin,
.ymin = y - string_pixel_size[1] / 2 - bg_margin,
.ymax = y + string_pixel_size[1] / 2 + bg_margin};
UI_draw_roundbox_3ub_alpha(&background_rect, true, 4.0f, col, color_bg[3]);
BLF_position(fontid, x - string_pixel_size[0] / 2, y - string_pixel_size[1] / 2, 0.0f);
BLF_draw(fontid, string, sizeof(string));
}
/* Draw an on screen Slider for a Pose Slide Operator. */
static void pose_slide_draw_2d_slider(const struct bContext *UNUSED(C), ARegion *region, void *arg)
{
tPoseSlideOp *pso = arg;
/* Only draw in region from which the Operator was started. */
if (region != pso->region) {
return;
}
uchar color_text[4];
uchar color_line[4];
uchar color_handle[4];
uchar color_bg[4];
char percentage_string[256];
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* Get theme colors. Text gets a different color when the value is clamped.*/
UI_GetThemeColor4ubv(TH_TEXT, color_text);
UI_GetThemeColor4ubv(TH_TEXT, color_line);
UI_GetThemeColor4ubv(TH_ACTIVE, color_handle);
UI_GetThemeColor4ubv(TH_HEADER, color_bg);
color_bg[3] = 160;
/* Get the default font. */
const uiStyle *style = UI_style_get();
const uiFontStyle *fstyle = &style->widget;
const int fontid = fstyle->uifont_id;
BLF_color3ubv(fontid, color_text);
BLF_rotation(fontid, 0.0f);
const float line_width = 4 * U.dpi_fac;
const float base_tick_height = 16.0 * U.dpi_fac;
const float text_offset = 24.0 * U.dpi_fac;
const float overshoot_range_delta = 0.2;
int initial_tick_percentage;
int handle_pos_x;
float overshoot_length_delta;
if (pso->overshoot) {
initial_tick_percentage = (int)((pso->percentage - 0.5f - overshoot_range_delta) * 100);
handle_pos_x = pso->slider_start[0] + (SLIDE_PIXEL_DISTANCE / 2);
overshoot_length_delta = SLIDE_PIXEL_DISTANCE * overshoot_range_delta;
}
else {
initial_tick_percentage = 0;
handle_pos_x = pso->slider_start[0] + SLIDE_PIXEL_DISTANCE * pso->percentage;
overshoot_length_delta = 0;
}
/* Draw main line. */
const struct rctf main_line_rect = {.xmin = pso->slider_start[0] - overshoot_length_delta,
.xmax = pso->slider_start[0] + SLIDE_PIXEL_DISTANCE +
overshoot_length_delta,
.ymin = pso->slider_start[1] - line_width / 2,
.ymax = pso->slider_start[1] + line_width / 2};
UI_draw_roundbox_3ub_alpha(&main_line_rect, true, 0, color_line, 255);
UI_draw_roundbox_3ub_alpha(&main_line_rect, false, 0, color_bg, 255);
/* Draw percentage ticks. */
const int tick_increment = 10;
const int percentage_range = pso->overshoot ? 100 + 100 * overshoot_range_delta * 2 : 100;
/* Round initial_tick_percentage up to the next tick_increment. */
int tick_percentage = ceil((float)initial_tick_percentage / tick_increment) * tick_increment;
for (; tick_percentage <= initial_tick_percentage + percentage_range;
tick_percentage += tick_increment) {
const float x = handle_pos_x +
SLIDE_PIXEL_DISTANCE * (((float)tick_percentage / 100) - pso->percentage);
/* 0.5 steps are considered main ticks and are drawn thicker with
* percentage indicator string below. */
const bool is_main_tick = tick_percentage % 50 == 0;
const float tick_height = is_main_tick ? base_tick_height : base_tick_height / 2;
const struct rctf tick_rect = {.xmin = x - (line_width / 2),
.xmax = x + (line_width / 2),
.ymin = pso->slider_start[1] - (tick_height / 2),
.ymax = pso->slider_start[1] + (tick_height / 2)};
UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_line, 255);
UI_draw_roundbox_3ub_alpha(&tick_rect, false, 1, color_bg, 255);
/* Draw percentage on main ticks. */
if (is_main_tick) {
BLI_snprintf(percentage_string, sizeof(percentage_string), "%d%%", tick_percentage);
draw_centered_string_with_background(
percentage_string, x, pso->slider_start[1] - text_offset, color_bg, fontid);
}
}
/* Draw handle indicating current percentage. */
const struct rctf handle_rect = {.xmin = handle_pos_x - (line_width),
.xmax = handle_pos_x + (line_width),
.ymin = pso->slider_start[1] - (base_tick_height / 2),
.ymax = pso->slider_start[1] + (base_tick_height / 2)};
UI_draw_roundbox_3ub_alpha(&handle_rect, true, 1, color_handle, 255);
UI_draw_roundbox_3ub_alpha(&handle_rect, false, 1, color_bg, 255);
BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", pso->percentage * 100);
draw_centered_string_with_background(
percentage_string, handle_pos_x, pso->slider_start[1] + text_offset, color_bg, fontid);
GPU_blend(GPU_BLEND_NONE);
immUnbindProgram();
}
/* operator init */
static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
{
@@ -375,7 +205,6 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
/* set range info from property values - these may get overridden for the invoke() */
pso->percentage = RNA_float_get(op->ptr, "percentage");
pso->raw_percentage = pso->percentage;
pso->prevFrame = RNA_int_get(op->ptr, "prev_frame");
pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
@@ -428,10 +257,6 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
pso->num.val_flag[0] |= NUM_NO_NEGATIVE;
pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */
/* Register UI drawing callback. */
pso->draw_handle = ED_region_draw_cb_activate(
pso->region->type, pose_slide_draw_2d_slider, pso, REGION_DRAW_POST_PIXEL);
/* return status is whether we've got all the data we were requested to get */
return 1;
}
@@ -441,13 +266,6 @@ static void pose_slide_exit(wmOperator *op)
{
tPoseSlideOp *pso = op->customdata;
/* Hide Bone Overlay. */
View3D *v3d = pso->area->spacedata.first;
v3d->overlay.flag = pso->overlay_flag;
/* Remove UI drawing callback. */
ED_region_draw_cb_exit(pso->region->type, pso->draw_handle);
/* if data exists, clear its data and exit */
if (pso) {
/* free the temp pchan links and their data */
@@ -784,7 +602,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], float default_value)
{
/* We only slide to the rest pose. So only use the default rest pose value. */
/* We only slide to the rest pose. So only use the default rest pose value */
const int lock = pso->axislock;
for (int idx = 0; idx < 3; idx++) {
if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) ||
@@ -803,7 +621,7 @@ static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], flo
static void pose_slide_rest_pose_apply_other_rot(tPoseSlideOp *pso, float vec[4], bool quat)
{
/* We only slide to the rest pose. So only use the default rest pose value. */
/* We only slide to the rest pose. So only use the default rest pose value */
float default_values[] = {1.0f, 0.0f, 0.0f, 0.0f};
if (!quat) {
/* Axis Angle */
@@ -971,18 +789,14 @@ static void pose_slide_reset(tPoseSlideOp *pso)
/* ------------------------------------ */
/* Draw percentage indicator in workspace footer. */
/* draw percentage indicator in header */
/* TODO: Include hints about locks here... */
static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
static void pose_slide_draw_status(tPoseSlideOp *pso)
{
char status_str[UI_MAX_DRAW_STR];
char limits_str[UI_MAX_DRAW_STR];
char axis_str[50];
char mode_str[32];
char overshoot_str[50];
char precision_str[50];
char increments_str[50];
char bone_vis_str[50];
switch (pso->mode) {
case POSESLIDE_PUSH:
@@ -1057,51 +871,25 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
break;
}
if (pso->overshoot) {
BLI_strncpy(overshoot_str, TIP_("[E] - Disable overshoot"), sizeof(overshoot_str));
}
else {
BLI_strncpy(overshoot_str, TIP_("E - Enable overshoot"), sizeof(overshoot_str));
}
if (pso->precision) {
BLI_strncpy(precision_str, TIP_("[Shift] - Precision active"), sizeof(precision_str));
}
else {
BLI_strncpy(precision_str, TIP_("Shift - Hold for precision"), sizeof(precision_str));
}
if (pso->increments) {
BLI_strncpy(increments_str, TIP_("[Ctrl] - Increments active"), sizeof(increments_str));
}
else {
BLI_strncpy(increments_str, TIP_("Ctrl - Hold for 10% increments"), sizeof(increments_str));
}
BLI_strncpy(bone_vis_str, TIP_("[H] - Toggle bone visibility"), sizeof(increments_str));
if (hasNumInput(&pso->num)) {
Scene *scene = pso->scene;
char str_offs[NUM_STR_REP_LEN];
char str_ofs[NUM_STR_REP_LEN];
outputNumInput(&pso->num, str_offs, &scene->unit);
outputNumInput(&pso->num, str_ofs, &scene->unit);
BLI_snprintf(status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str);
BLI_snprintf(
status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_ofs, limits_str);
}
else {
BLI_snprintf(status_str,
sizeof(status_str),
"%s: %d %% | %s | %s | %s | %s | %s",
mode_str,
(int)(pso->percentage * 100.0f),
limits_str,
overshoot_str,
precision_str,
increments_str,
bone_vis_str);
sizeof(status_str),
"%s: %d %% | %s",
mode_str,
(int)(pso->percentage * 100.0f),
limits_str);
}
ED_workspace_status_text(C, status_str);
ED_area_status_text(pso->area, status_str);
}
/* common code for invoke() methods */
@@ -1187,74 +975,24 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL);
/* header print */
pose_slide_draw_status(C, pso);
pose_slide_draw_status(pso);
/* add a modal handler for this operator */
WM_event_add_modal_handler(C, op);
/* Hide Bone Overlay. */
View3D *v3d = pso->area->spacedata.first;
pso->overlay_flag = v3d->overlay.flag;
v3d->overlay.flag |= V3D_OVERLAY_HIDE_BONES;
return OPERATOR_RUNNING_MODAL;
}
/* Calculate percentage based on mouse movement, clamp or round to increments if
* enabled by the user. Store the new percentage value.
/* calculate percentage based on position of mouse (we only use x-axis for now.
* since this is more convenient for users to do), and store new percentage value
*/
static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso,
wmOperator *op,
const wmEvent *event)
{
const float percentage_delta = (event->x - pso->last_cursor_x) / ((float)(SLIDE_PIXEL_DISTANCE));
/* Reduced percentage delta in precision mode (shift held). */
pso->raw_percentage += pso->precision ? (percentage_delta / 8) : percentage_delta;
pso->percentage = pso->raw_percentage;
pso->last_cursor_x = event->x;
/* Modulo mval so the value wraps properly in area space with the cursor. */
if (event->mval[0] > 0) {
pso->cursor_region_x = event->mval[0] % pso->region->winx;
}
else {
pso->cursor_region_x = (event->mval[0] % pso->region->winx) + pso->region->winx;
}
pso->cursor_region_y = event->mval[1];
if (!pso->overshoot) {
pso->percentage = clamp_f(pso->percentage, 0, 1);
}
if (pso->increments) {
pso->percentage = round(pso->percentage * 10) / 10;
}
pso->percentage = (event->x - pso->region->winrct.xmin) / ((float)pso->region->winx);
RNA_float_set(op->ptr, "percentage", pso->percentage);
}
/* Calculate the starting percentage so that 0% or 100% will always be in the area. */
static void pose_slide_calculate_start_percentage(tPoseSlideOp *pso, const wmEvent *event)
{
pso->last_cursor_x = event->x;
/* A bit of padding to both sides so the text stays on screen. */
const int padding = 16 * U.dpi_fac;
/* Clamp it so 0% or 100% is always on screen. */
/* Catching edge case where slider doesn't fit in window. */
if (padding < pso->region->winx - SLIDE_PIXEL_DISTANCE - padding) {
pso->last_cursor_x = clamp_i(pso->last_cursor_x,
pso->region->winrct.xmin + padding + SLIDE_PIXEL_DISTANCE / 2,
pso->region->winrct.xmax - padding - SLIDE_PIXEL_DISTANCE / 2);
}
else {
pso->last_cursor_x = clamp_i(pso->last_cursor_x,
pso->region->winrct.xmin + padding + SLIDE_PIXEL_DISTANCE / 2,
INT_MAX);
}
pso->slider_start[0] = (pso->region->winx / 2) - (SLIDE_PIXEL_DISTANCE / 2);
pso->slider_start[1] = 64 * U.dpi_fac;
}
/* handle an event to toggle channels mode */
static void pose_slide_toggle_channels_mode(wmOperator *op,
tPoseSlideOp *pso,
@@ -1318,12 +1056,9 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case EVT_PADENTER: {
if (event->val == KM_PRESS) {
/* return to normal cursor and header status */
ED_workspace_status_text(C, NULL);
ED_area_status_text(pso->area, NULL);
WM_cursor_modal_restore(win);
/* Depsgraph updates + redraws. Redraw needed to remove UI. */
pose_slide_refresh(C, pso);
/* insert keyframes as required... */
pose_slide_autoKeyframe(C, pso);
pose_slide_exit(op);
@@ -1338,13 +1073,13 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case RIGHTMOUSE: {
if (event->val == KM_PRESS) {
/* return to normal cursor and header status */
ED_workspace_status_text(C, NULL);
ED_area_status_text(pso->area, NULL);
WM_cursor_modal_restore(win);
/* reset transforms back to original state */
pose_slide_reset(pso);
/* Depsgraph updates + redraws.*/
/* depsgraph updates + redraws */
pose_slide_refresh(C, pso);
/* clean up temp data */
@@ -1443,58 +1178,10 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
/* Overshoot. */
case EVT_EKEY: {
pso->overshoot = !pso->overshoot;
do_pose_update = true;
break;
}
/* Precision mode. */
case EVT_LEFTSHIFTKEY:
case EVT_RIGHTSHIFTKEY: {
pso->precision = true;
do_pose_update = true;
break;
}
/* Increments mode. */
case EVT_LEFTCTRLKEY:
case EVT_RIGHTCTRLKEY: {
pso->increments = true;
do_pose_update = true;
break;
}
/* Toggle Bone visibility. */
case EVT_HKEY: {
View3D *v3d = pso->area->spacedata.first;
v3d->overlay.flag ^= V3D_OVERLAY_HIDE_BONES;
}
default: /* Some other unhandled key... */
break;
}
}
/* Precision and stepping only active while button is held. */
else if (event->val == KM_RELEASE) {
switch (event->type) {
case EVT_LEFTSHIFTKEY:
case EVT_RIGHTSHIFTKEY: {
pso->precision = false;
do_pose_update = true;
break;
}
case EVT_LEFTCTRLKEY:
case EVT_RIGHTCTRLKEY: {
pso->increments = false;
do_pose_update = true;
break;
}
default:
break;
}
}
else {
/* unhandled event - maybe it was some view manipulation? */
/* allow to pass through */
@@ -1506,10 +1193,8 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Perform pose updates - in response to some user action
* (e.g. pressing a key or moving the mouse). */
if (do_pose_update) {
pose_slide_mouse_update_percentage(pso, op, event);
/* update percentage indicator in header */
pose_slide_draw_status(C, pso);
pose_slide_draw_status(pso);
/* reset transforms (to avoid accumulation errors) */
pose_slide_reset(pso);
@@ -1562,11 +1247,11 @@ static void pose_slide_opdef_properties(wmOperatorType *ot)
PropertyRNA *prop;
prop = RNA_def_float_factor(ot->srna,
"percentage",
"factor",
0.5f,
0.0f,
1.0f,
"Percentage",
"Factor",
"Weighting factor for which keyframe is favored more",
0.0,
1.0);
@@ -1625,8 +1310,6 @@ static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *ev
pso = op->customdata;
pose_slide_calculate_start_percentage(pso, event);
/* Initialize percentage so that it won't pop on first mouse move. */
pose_slide_mouse_update_percentage(pso, op, event);
@@ -1666,7 +1349,7 @@ void POSE_OT_push(wmOperatorType *ot)
ot->poll = ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* Properties */
pose_slide_opdef_properties(ot);
@@ -1687,8 +1370,6 @@ static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *e
pso = op->customdata;
pose_slide_calculate_start_percentage(pso, event);
/* Initialize percentage so that it won't pop on first mouse move. */
pose_slide_mouse_update_percentage(pso, op, event);
@@ -1728,7 +1409,7 @@ void POSE_OT_relax(wmOperatorType *ot)
ot->poll = ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* Properties */
pose_slide_opdef_properties(ot);
@@ -1748,8 +1429,6 @@ static int pose_slide_push_rest_invoke(bContext *C, wmOperator *op, const wmEven
pso = op->customdata;
pso->last_cursor_x = event->x;
/* Initialize percentage so that it won't pop on first mouse move. */
pose_slide_mouse_update_percentage(pso, op, event);
@@ -1789,7 +1468,7 @@ void POSE_OT_push_rest(wmOperatorType *ot)
ot->poll = ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* Properties */
pose_slide_opdef_properties(ot);
@@ -1810,8 +1489,6 @@ static int pose_slide_relax_rest_invoke(bContext *C, wmOperator *op, const wmEve
pso = op->customdata;
pose_slide_calculate_start_percentage(pso, event);
/* Initialize percentage so that it won't pop on first mouse move. */
pose_slide_mouse_update_percentage(pso, op, event);
@@ -1851,7 +1528,7 @@ void POSE_OT_relax_rest(wmOperatorType *ot)
ot->poll = ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* Properties */
pose_slide_opdef_properties(ot);
@@ -1872,8 +1549,6 @@ static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEven
pso = op->customdata;
pose_slide_calculate_start_percentage(pso, event);
/* Initialize percentage so that it won't pop on first mouse move. */
pose_slide_mouse_update_percentage(pso, op, event);
@@ -1913,7 +1588,7 @@ void POSE_OT_breakdown(wmOperatorType *ot)
ot->poll = ED_operator_posemode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* Properties */
pose_slide_opdef_properties(ot);

View File

@@ -68,7 +68,9 @@ typedef struct SnapGizmo3D {
struct {
int x;
int y;
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
short shift, ctrl, alt, oskey;
#endif
} last_eventstate;
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
@@ -93,39 +95,36 @@ typedef struct SnapGizmo3D {
bool is_enabled;
} SnapGizmo3D;
static bool eventstate_cmp(SnapGizmo3D *snap_gizmo, const wmEvent *event)
{
if ((event->x == snap_gizmo->last_eventstate.x) && (event->y == snap_gizmo->last_eventstate.y) &&
(event->ctrl == snap_gizmo->last_eventstate.ctrl) &&
(event->shift == snap_gizmo->last_eventstate.shift) &&
(event->alt == snap_gizmo->last_eventstate.alt) &&
(event->oskey == snap_gizmo->last_eventstate.oskey)) {
return true;
}
return false;
}
/* Checks if the current event is different from the one captured in the last update. */
static bool eventstate_has_changed(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
{
if (wm && wm->winactive) {
const wmEvent *event = wm->winactive->eventstate;
return eventstate_cmp(snap_gizmo, event) == false;
if ((event->x != snap_gizmo->last_eventstate.x) ||
(event->y != snap_gizmo->last_eventstate.y)) {
return true;
}
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
if (!(snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE)) {
if ((event->ctrl != snap_gizmo->last_eventstate.ctrl) ||
(event->shift != snap_gizmo->last_eventstate.shift) ||
(event->alt != snap_gizmo->last_eventstate.alt) ||
(event->oskey != snap_gizmo->last_eventstate.oskey)) {
return true;
}
}
#endif
}
return false;
}
/* Copies the current eventstate. */
static void eventstate_save(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
static void eventstate_save_xy(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
{
if (wm && wm->winactive) {
const wmEvent *event = wm->winactive->eventstate;
snap_gizmo->last_eventstate.x = event->x;
snap_gizmo->last_eventstate.y = event->y;
snap_gizmo->last_eventstate.ctrl = event->ctrl;
snap_gizmo->last_eventstate.shift = event->shift;
snap_gizmo->last_eventstate.alt = event->alt;
snap_gizmo->last_eventstate.oskey = event->oskey;
}
}
@@ -137,16 +136,20 @@ static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
}
const wmEvent *event = wm->winactive->eventstate;
if (eventstate_cmp(snap_gizmo, event)) {
if ((event->ctrl == snap_gizmo->last_eventstate.ctrl) &&
(event->shift == snap_gizmo->last_eventstate.shift) &&
(event->alt == snap_gizmo->last_eventstate.alt) &&
(event->oskey == snap_gizmo->last_eventstate.oskey)) {
/* Nothing has changed. */
return snap_gizmo->invert_snap;
}
if (snap_gizmo->keymap == NULL) {
/* Lazy initialization. */
snap_gizmo->keymap = WM_modalkeymap_find(wm->defaultconf, "Generic Gizmo Tweak Modal Map");
RNA_enum_value_from_id(snap_gizmo->keymap->modal_items, "SNAP_ON", &snap_gizmo->snap_on);
}
/* Save new eventstate. */
snap_gizmo->last_eventstate.ctrl = event->ctrl;
snap_gizmo->last_eventstate.shift = event->shift;
snap_gizmo->last_eventstate.alt = event->alt;
snap_gizmo->last_eventstate.oskey = event->oskey;
const int snap_on = snap_gizmo->snap_on;
wmKeyMap *keymap = WM_keymap_active(wm, snap_gizmo->keymap);
@@ -335,8 +338,9 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz,
Scene *scene = DEG_get_input_scene(depsgraph);
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
if ((snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE) == 0) {
if (!(snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE)) {
snap_gizmo->invert_snap = invert_snap(snap_gizmo, wm);
const ToolSettings *ts = scene->toolsettings;
if (snap_gizmo->invert_snap != !(ts->snap_flag & SCE_SNAP)) {
snap_gizmo->snap_elem = 0;
@@ -344,8 +348,7 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz,
}
}
#endif
eventstate_save(snap_gizmo, wm);
eventstate_save_xy(snap_gizmo, wm);
snap_gizmo->is_enabled = true;
@@ -555,8 +558,14 @@ static void gizmo_snap_rna_snap_elem_index_get_fn(struct PointerRNA *ptr,
static void snap_gizmo_setup(wmGizmo *gz)
{
/* Flags. */
gz->flag |= WM_GIZMO_NO_TOOLTIP;
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz;
snap_gizmo->keymap = WM_modalkeymap_find(gz->parent_gzgroup->type->keyconf,
"Generic Gizmo Tweak Modal Map");
RNA_enum_value_from_id(snap_gizmo->keymap->modal_items, "SNAP_ON", &snap_gizmo->snap_on);
#endif
}
static void snap_gizmo_draw(const bContext *C, wmGizmo *gz)

View File

@@ -228,7 +228,7 @@ static void pick_link(const bContext *C,
BLI_assert(nldrag->last_node_hovered_while_dragging_a_link != NULL);
sort_multi_input_socket_links(
snode, nldrag->last_node_hovered_while_dragging_a_link, NULL,NULL);
snode, nldrag->last_node_hovered_while_dragging_a_link, NULL, NULL);
/* Send changed event to original link->tonode. */
if (node) {
@@ -901,7 +901,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
existing_link_connected_to_fromsock->multi_input_socket_index;
continue;
}
if(link->tosock && link->tosock->flag & SOCK_MULTI_INPUT){
if (link->tosock && link->tosock->flag & SOCK_MULTI_INPUT) {
sort_multi_input_socket_links(snode, tnode, link, cursor);
}
}
@@ -2260,7 +2260,12 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
node_remove_extra_links(snode, link);
link->flag &= ~NODE_LINKFLAG_HILITE;
nodeAddLink(snode->edittree, select, best_output, node, sockto);
bNodeLink *new_link = nodeAddLink(snode->edittree, select, best_output, node, sockto);
/* Copy the socket index for the new link, and reset it for the old link. This way the
* relative order of links is preserved, and the links get drawn in the right place. */
new_link->multi_input_socket_index = link->multi_input_socket_index;
link->multi_input_socket_index = 0;
/* set up insert offset data, it needs stuff from here */
if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
@@ -2277,8 +2282,6 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
snode_update(snode, select);
ED_node_tag_update_id((ID *)snode->edittree);
ED_node_tag_update_id(snode->id);
sort_multi_input_socket_links(snode, node, NULL, NULL);
}
}
}

View File

@@ -665,6 +665,10 @@ static const EnumPropertyItem *outliner_id_itemf(bContext *C,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
if (C == NULL) {
return DummyRNA_NULL_items;
}
EnumPropertyItem item_tmp = {0}, *item = NULL;
int totitem = 0;
int i = 0;

View File

@@ -78,35 +78,45 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
{
std::lock_guard lock{mutex_};
bke::ReadAttributePtr attribute_ptr = component_->attribute_try_get_for_read(column_id.name);
if (!attribute_ptr) {
bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name);
if (!attribute) {
return {};
}
const bke::ReadAttribute *attribute = scope_.add(std::move(attribute_ptr), __func__);
if (attribute->domain() != domain_) {
const fn::GVArray *varray = scope_.add(std::move(attribute.varray), __func__);
if (attribute.domain != domain_) {
return {};
}
int domain_size = attribute->size();
switch (attribute->custom_data_type()) {
int domain_size = varray->size();
const CustomDataType type = bke::cpp_type_to_custom_data_type(varray->type());
switch (type) {
case CD_PROP_FLOAT:
if (column_id.index != -1) {
return {};
}
return column_values_from_function(
column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
float value;
attribute->get(index, &value);
varray->get(index, &value);
r_cell_value.value_float = value;
});
case CD_PROP_INT32:
if (column_id.index != -1) {
return {};
}
return column_values_from_function(
column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
int value;
attribute->get(index, &value);
varray->get(index, &value);
r_cell_value.value_int = value;
});
case CD_PROP_BOOL:
if (column_id.index != -1) {
return {};
}
return column_values_from_function(
column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
bool value;
attribute->get(index, &value);
varray->get(index, &value);
r_cell_value.value_bool = value;
});
case CD_PROP_FLOAT2: {
@@ -116,11 +126,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const std::array<const char *, 2> suffixes = {" X", " Y"};
const std::string name = StringRef(column_id.name) + suffixes[column_id.index];
return column_values_from_function(
name,
domain_size,
[attribute, axis = column_id.index](int index, CellValue &r_cell_value) {
name, domain_size, [varray, axis = column_id.index](int index, CellValue &r_cell_value) {
float2 value;
attribute->get(index, &value);
varray->get(index, &value);
r_cell_value.value_float = value[axis];
});
}
@@ -131,11 +139,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const std::array<const char *, 3> suffixes = {" X", " Y", " Z"};
const std::string name = StringRef(column_id.name) + suffixes[column_id.index];
return column_values_from_function(
name,
domain_size,
[attribute, axis = column_id.index](int index, CellValue &r_cell_value) {
name, domain_size, [varray, axis = column_id.index](int index, CellValue &r_cell_value) {
float3 value;
attribute->get(index, &value);
varray->get(index, &value);
r_cell_value.value_float = value[axis];
});
}
@@ -146,11 +152,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const std::array<const char *, 4> suffixes = {" R", " G", " B", " A"};
const std::string name = StringRef(column_id.name) + suffixes[column_id.index];
return column_values_from_function(
name,
domain_size,
[attribute, axis = column_id.index](int index, CellValue &r_cell_value) {
name, domain_size, [varray, axis = column_id.index](int index, CellValue &r_cell_value) {
Color4f value;
attribute->get(index, &value);
varray->get(index, &value);
r_cell_value.value_float = value[axis];
});
}

View File

@@ -30,7 +30,7 @@ namespace blender::fn {
* A generic span. It behaves just like a blender::Span<T>, but the type is only known at run-time.
*/
class GSpan {
private:
protected:
const CPPType *type_;
const void *data_;
int64_t size_;
@@ -92,7 +92,7 @@ class GSpan {
* known at run-time.
*/
class GMutableSpan {
private:
protected:
const CPPType *type_;
void *data_;
int64_t size_;

View File

@@ -123,7 +123,7 @@ template<typename T> class GVectorArray_TypedMutableRef {
void extend(const int64_t index, const VArray<T> &values)
{
GVArrayForVArray<T> array{values};
GVArray_For_VArray<T> array{values};
this->extend(index, array);
}
@@ -134,12 +134,12 @@ template<typename T> class GVectorArray_TypedMutableRef {
};
/* A generic virtual vector array implementation for a `GVectorArray`. */
class GVVectorArrayForGVectorArray : public GVVectorArray {
class GVVectorArray_For_GVectorArray : public GVVectorArray {
private:
const GVectorArray &vector_array_;
public:
GVVectorArrayForGVectorArray(const GVectorArray &vector_array)
GVVectorArray_For_GVectorArray(const GVectorArray &vector_array)
: GVVectorArray(vector_array.type(), vector_array.size()), vector_array_(vector_array)
{
}

View File

@@ -23,12 +23,17 @@
* the data type is only known at runtime.
*/
#include <optional>
#include "BLI_virtual_array.hh"
#include "FN_generic_span.hh"
namespace blender::fn {
template<typename T> class GVArray_Typed;
template<typename T> class GVMutableArray_Typed;
/* A generically typed version of `VArray<T>`. */
class GVArray {
protected:
@@ -86,13 +91,13 @@ class GVArray {
/* Returns the internally used span of the virtual array. This invokes undefined behavior is the
* virtual array is not stored as a span internally. */
GSpan get_span() const
GSpan get_internal_span() const
{
BLI_assert(this->is_span());
if (size_ == 0) {
return GSpan(*type_);
}
return this->get_span_impl();
return this->get_internal_span_impl();
}
/* Returns true when the virtual array returns the same value for every index. */
@@ -107,57 +112,133 @@ class GVArray {
/* Copies the value that is used for every element into `r_value`, which is expected to point to
* initialized memory. This invokes undefined behavior if the virtual array would not return the
* same value for every index. */
void get_single(void *r_value) const
void get_internal_single(void *r_value) const
{
BLI_assert(this->is_single());
if (size_ == 1) {
this->get(0, r_value);
}
this->get_single_impl(r_value);
this->get_internal_single_impl(r_value);
}
/* Same as `get_single`, but `r_value` points to initialized memory. */
/* Same as `get_internal_single`, but `r_value` points to initialized memory. */
void get_single_to_uninitialized(void *r_value) const
{
type_->construct_default(r_value);
this->get_single(r_value);
this->get_internal_single(r_value);
}
void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
template<typename T> const VArray<T> *try_get_internal_varray() const
{
BLI_assert(type_->is<T>());
return (const VArray<T> *)this->try_get_internal_varray_impl();
}
/* Create a typed virtual array for this generic virtual array. */
template<typename T> GVArray_Typed<T> typed() const
{
return GVArray_Typed<T>(*this);
}
protected:
virtual void get_impl(const int64_t index, void *r_value) const;
virtual void get_to_uninitialized_impl(const int64_t index, void *r_value) const = 0;
virtual bool is_span_impl() const;
virtual GSpan get_span_impl() const;
virtual GSpan get_internal_span_impl() const;
virtual bool is_single_impl() const;
virtual void get_single_impl(void *UNUSED(r_value)) const;
virtual void get_internal_single_impl(void *UNUSED(r_value)) const;
virtual const void *try_get_internal_varray_impl() const;
};
class GVArrayForGSpan : public GVArray {
/* Similar to GVArray, but supports changing the elements in the virtual array. */
class GVMutableArray : public GVArray {
public:
GVMutableArray(const CPPType &type, const int64_t size) : GVArray(type, size)
{
}
void set_by_copy(const int64_t index, const void *value)
{
BLI_assert(index >= 0);
BLI_assert(index < size_);
this->set_by_copy_impl(index, value);
}
void set_by_move(const int64_t index, void *value)
{
BLI_assert(index >= 0);
BLI_assert(index < size_);
this->set_by_move_impl(index, value);
}
void set_by_relocate(const int64_t index, void *value)
{
BLI_assert(index >= 0);
BLI_assert(index < size_);
this->set_by_relocate_impl(index, value);
}
GMutableSpan get_internal_span()
{
BLI_assert(this->is_span());
GSpan span = static_cast<const GVArray *>(this)->get_internal_span();
return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size());
}
template<typename T> VMutableArray<T> *try_get_internal_mutable_varray()
{
BLI_assert(type_->is<T>());
return (VMutableArray<T> *)this->try_get_internal_mutable_varray_impl();
}
/* Create a typed virtual array for this generic virtual array. */
template<typename T> GVMutableArray_Typed<T> typed()
{
return GVMutableArray_Typed<T>(*this);
}
void fill(const void *value);
protected:
const void *data_;
virtual void set_by_copy_impl(const int64_t index, const void *value);
virtual void set_by_relocate_impl(const int64_t index, void *value);
virtual void set_by_move_impl(const int64_t index, void *value) = 0;
virtual void *try_get_internal_mutable_varray_impl();
};
class GVArray_For_GSpan : public GVArray {
protected:
const void *data_ = nullptr;
const int64_t element_size_;
public:
GVArrayForGSpan(const GSpan span)
GVArray_For_GSpan(const GSpan span)
: GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size())
{
}
protected:
GVArray_For_GSpan(const CPPType &type, const int64_t size)
: GVArray(type, size), element_size_(type.size())
{
}
void get_impl(const int64_t index, void *r_value) const override;
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
bool is_span_impl() const override;
GSpan get_span_impl() const override;
GSpan get_internal_span_impl() const override;
};
class GVArrayForEmpty : public GVArray {
class GVArray_For_Empty : public GVArray {
public:
GVArrayForEmpty(const CPPType &type) : GVArray(type, 0)
GVArray_For_Empty(const CPPType &type) : GVArray(type, 0)
{
}
@@ -168,108 +249,618 @@ class GVArrayForEmpty : public GVArray {
}
};
class GVArrayForSingleValueRef : public GVArray {
private:
const void *value_;
class GVMutableArray_For_GMutableSpan : public GVMutableArray {
protected:
void *data_ = nullptr;
const int64_t element_size_;
public:
GVArrayForSingleValueRef(const CPPType &type, const int64_t size, const void *value)
GVMutableArray_For_GMutableSpan(const GMutableSpan span)
: GVMutableArray(span.type(), span.size()),
data_(span.data()),
element_size_(span.type().size())
{
}
protected:
GVMutableArray_For_GMutableSpan(const CPPType &type, const int64_t size)
: GVMutableArray(type, size), element_size_(type.size())
{
}
void get_impl(const int64_t index, void *r_value) const override;
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
void set_by_copy_impl(const int64_t index, const void *value) override;
void set_by_move_impl(const int64_t index, void *value) override;
void set_by_relocate_impl(const int64_t index, void *value) override;
bool is_span_impl() const override;
GSpan get_internal_span_impl() const override;
};
/* Generic virtual array where each element has the same value. The value is not owned. */
class GVArray_For_SingleValueRef : public GVArray {
protected:
const void *value_ = nullptr;
public:
GVArray_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
: GVArray(type, size), value_(value)
{
}
protected:
GVArray_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArray(type, size)
{
}
void get_impl(const int64_t index, void *r_value) const override;
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
bool is_span_impl() const override;
GSpan get_span_impl() const override;
GSpan get_internal_span_impl() const override;
bool is_single_impl() const override;
void get_single_impl(void *r_value) const override;
void get_internal_single_impl(void *r_value) const override;
};
template<typename T> class GVArrayForVArray : public GVArray {
private:
const VArray<T> &array_;
/* Same as GVArray_For_SingleValueRef, but the value is owned. */
class GVArray_For_SingleValue : public GVArray_For_SingleValueRef {
public:
GVArray_For_SingleValue(const CPPType &type, const int64_t size, const void *value);
~GVArray_For_SingleValue();
};
/* Used to convert a typed virtual array into a generic one. */
template<typename T> class GVArray_For_VArray : public GVArray {
protected:
const VArray<T> *varray_ = nullptr;
public:
GVArrayForVArray(const VArray<T> &array)
: GVArray(CPPType::get<T>(), array.size()), array_(array)
GVArray_For_VArray(const VArray<T> &varray)
: GVArray(CPPType::get<T>(), varray.size()), varray_(&varray)
{
}
protected:
GVArray_For_VArray(const int64_t size) : GVArray(CPPType::get<T>(), size)
{
}
void get_impl(const int64_t index, void *r_value) const override
{
*(T *)r_value = array_.get(index);
*(T *)r_value = varray_->get(index);
}
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
{
new (r_value) T(array_.get(index));
new (r_value) T(varray_->get(index));
}
bool is_span_impl() const override
{
return array_.is_span();
return varray_->is_span();
}
GSpan get_span_impl() const override
GSpan get_internal_span_impl() const override
{
return GSpan(array_.get_span());
return GSpan(varray_->get_internal_span());
}
bool is_single_impl() const override
{
return array_.is_single();
return varray_->is_single();
}
void get_single_impl(void *r_value) const override
void get_internal_single_impl(void *r_value) const override
{
*(T *)r_value = array_.get_single();
*(T *)r_value = varray_->get_internal_single();
}
const void *try_get_internal_varray_impl() const override
{
return varray_;
}
};
template<typename T> class VArrayForGVArray : public VArray<T> {
private:
const GVArray &array_;
/* Used to convert any generic virtual array into a typed one. */
template<typename T> class VArray_For_GVArray : public VArray<T> {
protected:
const GVArray *varray_ = nullptr;
public:
VArrayForGVArray(const GVArray &array) : VArray<T>(array.size()), array_(array)
VArray_For_GVArray(const GVArray &varray) : VArray<T>(varray.size()), varray_(&varray)
{
BLI_assert(array_.type().template is<T>());
BLI_assert(varray_->type().template is<T>());
}
protected:
VArray_For_GVArray(const int64_t size) : VArray<T>(size)
{
}
T get_impl(const int64_t index) const override
{
T value;
array_.get(index, &value);
varray_->get(index, &value);
return value;
}
bool is_span_impl() const override
{
return array_.is_span();
return varray_->is_span();
}
Span<T> get_span_impl() const override
Span<T> get_internal_span_impl() const override
{
return array_.get_span().template typed<T>();
return varray_->get_internal_span().template typed<T>();
}
bool is_single_impl() const override
{
return array_.is_single();
return varray_->is_single();
}
T get_single_impl() const override
T get_internal_single_impl() const override
{
T value;
array_.get_single(&value);
varray_->get_internal_single(&value);
return value;
}
};
/* Used to convert an generic mutable virtual array into a typed one. */
template<typename T> class VMutableArray_For_GVMutableArray : public VMutableArray<T> {
protected:
GVMutableArray *varray_ = nullptr;
public:
VMutableArray_For_GVMutableArray(GVMutableArray &varray)
: VMutableArray<T>(varray.size()), varray_(&varray)
{
BLI_assert(varray.type().template is<T>());
}
VMutableArray_For_GVMutableArray(const int64_t size) : VMutableArray<T>(size)
{
}
private:
T get_impl(const int64_t index) const override
{
T value;
varray_->get(index, &value);
return value;
}
void set_impl(const int64_t index, T value) override
{
varray_->set_by_relocate(index, &value);
}
bool is_span_impl() const override
{
return varray_->is_span();
}
Span<T> get_internal_span_impl() const override
{
return varray_->get_internal_span().template typed<T>();
}
bool is_single_impl() const override
{
return varray_->is_single();
}
T get_internal_single_impl() const override
{
T value;
varray_->get_internal_single(&value);
return value;
}
};
/* Used to convert any typed virtual mutable array into a generic one. */
template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableArray {
protected:
VMutableArray<T> *varray_ = nullptr;
public:
GVMutableArray_For_VMutableArray(VMutableArray<T> &varray)
: GVMutableArray(CPPType::get<T>(), varray.size()), varray_(&varray)
{
}
protected:
GVMutableArray_For_VMutableArray(const int64_t size) : GVMutableArray(CPPType::get<T>(), size)
{
}
void get_impl(const int64_t index, void *r_value) const override
{
*(T *)r_value = varray_->get(index);
}
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
{
new (r_value) T(varray_->get(index));
}
bool is_span_impl() const override
{
return varray_->is_span();
}
GSpan get_internal_span_impl() const override
{
Span<T> span = varray_->get_internal_span();
return span;
}
bool is_single_impl() const override
{
return varray_->is_single();
}
void get_internal_single_impl(void *r_value) const override
{
*(T *)r_value = varray_->get_internal_single();
}
void set_by_copy_impl(const int64_t index, const void *value) override
{
const T &value_ = *(const T *)value;
varray_->set(index, value_);
}
void set_by_relocate_impl(const int64_t index, void *value) override
{
T &value_ = *(T *)value;
varray_->set(index, std::move(value_));
value_.~T();
}
void set_by_move_impl(const int64_t index, void *value) override
{
T &value_ = *(T *)value;
varray_->set(index, std::move(value_));
}
const void *try_get_internal_varray_impl() const override
{
return (const VArray<T> *)varray_;
}
void *try_get_internal_mutable_varray_impl() override
{
return varray_;
}
};
/* A generic version of VArray_Span. */
class GVArray_GSpan : public GSpan {
private:
const GVArray &varray_;
void *owned_data_ = nullptr;
public:
GVArray_GSpan(const GVArray &varray);
~GVArray_GSpan();
};
/* A generic version of VMutableArray_Span. */
class GVMutableArray_GSpan : public GMutableSpan {
private:
GVMutableArray &varray_;
void *owned_data_ = nullptr;
bool save_has_been_called_ = false;
bool show_not_saved_warning_ = true;
public:
GVMutableArray_GSpan(GVMutableArray &varray, bool copy_values_to_span = true);
~GVMutableArray_GSpan();
void save();
void disable_not_applied_warning();
};
/* Similar to GVArray_GSpan, but the resulting span is typed. */
template<typename T> class GVArray_Span : public Span<T> {
private:
GVArray_GSpan varray_gspan_;
public:
GVArray_Span(const GVArray &varray) : varray_gspan_(varray)
{
BLI_assert(varray.type().is<T>());
this->data_ = (const T *)varray_gspan_.data();
this->size_ = varray_gspan_.size();
}
};
template<typename T> class GVArray_For_OwnedVArray : public GVArray_For_VArray<T> {
private:
std::unique_ptr<VArray<T>> owned_varray_;
public:
/* Takes ownership of varray and passes a reference to the base class. */
GVArray_For_OwnedVArray(std::unique_ptr<VArray<T>> varray)
: GVArray_For_VArray<T>(*varray), owned_varray_(std::move(varray))
{
}
};
template<typename T> class VArray_For_OwnedGVArray : public VArray_For_GVArray<T> {
private:
std::unique_ptr<VArray<T>> owned_varray_;
public:
/* Takes ownership of varray and passes a reference to the base class. */
VArray_For_OwnedGVArray(std::unique_ptr<GVArray> varray)
: VArray_For_GVArray<T>(*varray), owned_varray_(std::move(varray))
{
}
};
template<typename T>
class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
private:
std::unique_ptr<VMutableArray<T>> owned_varray_;
public:
/* Takes ownership of varray and passes a reference to the base class. */
GVMutableArray_For_OwnedVMutableArray(std::unique_ptr<VMutableArray<T>> varray)
: GVMutableArray_For_VMutableArray<T>(*varray), owned_varray_(std::move(varray))
{
}
};
template<typename T>
class VMutableArray_For_OwnedGVMutableArray : public VMutableArray_For_GVMutableArray<T> {
private:
std::unique_ptr<GVMutableArray> owned_varray_;
public:
/* Takes ownership of varray and passes a reference to the base class. */
VMutableArray_For_OwnedGVMutableArray(std::unique_ptr<GVMutableArray> varray)
: VMutableArray_For_GVMutableArray<T>(*varray), owned_varray_(std::move(varray))
{
}
};
/* Utility to embed a typed virtual array into a generic one. This avoids one allocation and give
* the compiler more opportunity to optimize the generic virtual array. */
template<typename T, typename VArrayT>
class GVArray_For_EmbeddedVArray : public GVArray_For_VArray<T> {
private:
VArrayT embedded_varray_;
public:
template<typename... Args>
GVArray_For_EmbeddedVArray(const int64_t size, Args &&... args)
: GVArray_For_VArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
{
this->varray_ = &embedded_varray_;
}
};
/* Same as GVArray_For_EmbeddedVArray, but for mutable virtual arrays. */
template<typename T, typename VMutableArrayT>
class GVMutableArray_For_EmbeddedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
private:
VMutableArrayT embedded_varray_;
public:
template<typename... Args>
GVMutableArray_For_EmbeddedVMutableArray(const int64_t size, Args &&... args)
: GVMutableArray_For_VMutableArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
{
this->varray_ = &embedded_varray_;
}
};
/* Same as VArray_For_ArrayContainer, but for a generic virtual array. */
template<typename Container, typename T = typename Container::value_type>
class GVArray_For_ArrayContainer
: public GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>> {
public:
GVArray_For_ArrayContainer(Container container)
: GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>>(
container.size(), std::move(container))
{
}
};
/* Same as VArray_For_DerivedSpan, but for a generic virtual array. */
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
class GVArray_For_DerivedSpan
: public GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>> {
public:
GVArray_For_DerivedSpan(const Span<StructT> data)
: GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>>(
data.size(), data)
{
}
};
/* Same as VMutableArray_For_DerivedSpan, but for a generic virtual array. */
template<typename StructT,
typename ElemT,
ElemT (*GetFunc)(const StructT &),
void (*SetFunc)(StructT &, ElemT)>
class GVMutableArray_For_DerivedSpan
: public GVMutableArray_For_EmbeddedVMutableArray<
ElemT,
VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>> {
public:
GVMutableArray_For_DerivedSpan(const MutableSpan<StructT> data)
: GVMutableArray_For_EmbeddedVMutableArray<
ElemT,
VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(data.size(), data)
{
}
};
/* Same as VArray_For_Span, but for a generic virtual array. */
template<typename T>
class GVArray_For_Span : public GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>> {
public:
GVArray_For_Span(const Span<T> data)
: GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>>(data.size(), data)
{
}
};
/* Same as VMutableArray_For_MutableSpan, but for a generic virtual array. */
template<typename T>
class GVMutableArray_For_MutableSpan
: public GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>> {
public:
GVMutableArray_For_MutableSpan(const MutableSpan<T> data)
: GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>>(data.size(),
data)
{
}
};
/**
* Utility class to create the "best" typed virtual array for a given generic virtual array.
* In most cases we don't just want to use VArray_For_GVArray, because it adds an additional
* indirection on element-access that can be avoided in many cases (e.g. when the virtual array is
* just a span or single value).
*
* This is not a virtual array itself, but is used to get a virtual array.
*/
template<typename T> class GVArray_Typed {
private:
const VArray<T> *varray_;
/* Of these optional virtual arrays, at most one is constructed at any time. */
std::optional<VArray_For_Span<T>> varray_span_;
std::optional<VArray_For_Single<T>> varray_single_;
std::optional<VArray_For_GVArray<T>> varray_any_;
std::unique_ptr<GVArray> owned_gvarray_;
public:
explicit GVArray_Typed(const GVArray &gvarray)
{
BLI_assert(gvarray.type().is<T>());
if (gvarray.is_span()) {
const GSpan span = gvarray.get_internal_span();
varray_span_.emplace(span.typed<T>());
varray_ = &*varray_span_;
}
else if (gvarray.is_single()) {
T single_value;
gvarray.get_internal_single(&single_value);
varray_single_.emplace(single_value, gvarray.size());
varray_ = &*varray_single_;
}
else if (const VArray<T> *internal_varray = gvarray.try_get_internal_varray<T>()) {
varray_ = internal_varray;
}
else {
varray_any_.emplace(gvarray);
varray_ = &*varray_any_;
}
}
/* Same as the constructor above, but also takes ownership of the passed in virtual array. */
explicit GVArray_Typed(std::unique_ptr<GVArray> gvarray) : GVArray_Typed(*gvarray)
{
owned_gvarray_ = std::move(gvarray);
}
const VArray<T> &operator*() const
{
return *varray_;
}
const VArray<T> *operator->() const
{
return varray_;
}
/* Support implicit cast to the typed virtual array for convenience when `varray->typed<T>()` is
* used within an expression. */
operator const VArray<T> &() const
{
return *varray_;
}
T operator[](const int64_t index) const
{
return varray_->get(index);
}
int64_t size() const
{
return varray_->size();
}
IndexRange index_range() const
{
return IndexRange(this->size());
}
};
/* Same as GVArray_Typed, but for mutable virtual arrays. */
template<typename T> class GVMutableArray_Typed {
private:
VMutableArray<T> *varray_;
std::optional<VMutableArray_For_MutableSpan<T>> varray_span_;
std::optional<VMutableArray_For_GVMutableArray<T>> varray_any_;
std::unique_ptr<GVMutableArray> owned_gvarray_;
public:
explicit GVMutableArray_Typed(GVMutableArray &gvarray)
{
BLI_assert(gvarray.type().is<T>());
if (gvarray.is_span()) {
const GMutableSpan span = gvarray.get_internal_span();
varray_span_.emplace(span.typed<T>());
varray_ = &*varray_span_;
}
else if (VMutableArray<T> *internal_varray = gvarray.try_get_internal_mutable_varray<T>()) {
varray_ = internal_varray;
}
else {
varray_any_.emplace(gvarray);
varray_ = &*varray_any_;
}
}
explicit GVMutableArray_Typed(std::unique_ptr<GVMutableArray> gvarray)
: GVMutableArray_Typed(*gvarray)
{
owned_gvarray_ = std::move(gvarray);
}
VMutableArray<T> &operator*()
{
return *varray_;
}
VMutableArray<T> *operator->()
{
return varray_;
}
operator VMutableArray<T> &()
{
return *varray_;
}
T operator[](const int64_t index) const
{
return varray_->get(index);
}
int64_t size() const
{
return varray_->size();
}
};
} // namespace blender::fn

View File

@@ -100,13 +100,13 @@ class GVVectorArray {
}
};
class GVArrayForGVVectorArrayIndex : public GVArray {
class GVArray_For_GVVectorArrayIndex : public GVArray {
private:
const GVVectorArray &vector_array_;
const int64_t index_;
public:
GVArrayForGVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index)
GVArray_For_GVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index)
: GVArray(vector_array.type(), vector_array.get_vector_size(index)),
vector_array_(vector_array),
index_(index)
@@ -118,12 +118,12 @@ class GVArrayForGVVectorArrayIndex : public GVArray {
void get_to_uninitialized_impl(const int64_t index_in_vector, void *r_value) const override;
};
class GVVectorArrayForSingleGVArray : public GVVectorArray {
class GVVectorArray_For_SingleGVArray : public GVVectorArray {
private:
const GVArray &array_;
public:
GVVectorArrayForSingleGVArray(const GVArray &array, const int64_t size)
GVVectorArray_For_SingleGVArray(const GVArray &array, const int64_t size)
: GVVectorArray(array.type(), size), array_(array)
{
}
@@ -137,12 +137,12 @@ class GVVectorArrayForSingleGVArray : public GVVectorArray {
bool is_single_vector_impl() const override;
};
class GVVectorArrayForSingleGSpan : public GVVectorArray {
class GVVectorArray_For_SingleGSpan : public GVVectorArray {
private:
const GSpan span_;
public:
GVVectorArrayForSingleGSpan(const GSpan span, const int64_t size)
GVVectorArray_For_SingleGSpan(const GSpan span, const int64_t size)
: GVVectorArray(span.type(), size), span_(span)
{
}
@@ -156,12 +156,12 @@ class GVVectorArrayForSingleGSpan : public GVVectorArray {
bool is_single_vector_impl() const override;
};
template<typename T> class VVectorArrayForGVVectorArray : public VVectorArray<T> {
template<typename T> class VVectorArray_For_GVVectorArray : public VVectorArray<T> {
private:
const GVVectorArray &vector_array_;
public:
VVectorArrayForGVVectorArray(const GVVectorArray &vector_array)
VVectorArray_For_GVVectorArray(const GVVectorArray &vector_array)
: VVectorArray<T>(vector_array.size()), vector_array_(vector_array)
{
}

View File

@@ -55,13 +55,13 @@ class MFParamsBuilder {
template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "")
{
this->add_readonly_single_input(scope_.construct<GVArrayForSingleValueRef>(
this->add_readonly_single_input(scope_.construct<GVArray_For_SingleValueRef>(
__func__, CPPType::get<T>(), min_array_size_, value),
expected_name);
}
void add_readonly_single_input(const GSpan span, StringRef expected_name = "")
{
this->add_readonly_single_input(scope_.construct<GVArrayForGSpan>(__func__, span),
this->add_readonly_single_input(scope_.construct<GVArray_For_GSpan>(__func__, span),
expected_name);
}
void add_readonly_single_input(const GVArray &ref, StringRef expected_name = "")
@@ -74,7 +74,7 @@ class MFParamsBuilder {
void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "")
{
this->add_readonly_vector_input(
scope_.construct<GVVectorArrayForGVectorArray>(__func__, vector_array), expected_name);
scope_.construct<GVVectorArray_For_GVectorArray>(__func__, vector_array), expected_name);
}
void add_readonly_vector_input(const GVVectorArray &ref, StringRef expected_name = "")
{
@@ -177,7 +177,7 @@ class MFParams {
template<typename T> const VArray<T> &readonly_single_input(int param_index, StringRef name = "")
{
const GVArray &array = this->readonly_single_input(param_index, name);
return builder_->scope_.construct<VArrayForGVArray<T>>(__func__, array);
return builder_->scope_.construct<VArray_For_GVArray<T>>(__func__, array);
}
const GVArray &readonly_single_input(int param_index, StringRef name = "")
{
@@ -202,7 +202,7 @@ class MFParams {
const VVectorArray<T> &readonly_vector_input(int param_index, StringRef name = "")
{
const GVVectorArray &vector_array = this->readonly_vector_input(param_index, name);
return builder_->scope_.construct<VVectorArrayForGVVectorArray<T>>(__func__, vector_array);
return builder_->scope_.construct<VVectorArray_For_GVVectorArray<T>>(__func__, vector_array);
}
const GVVectorArray &readonly_vector_input(int param_index, StringRef name = "")
{

View File

@@ -60,21 +60,21 @@ void GVectorArray::extend(const int64_t index, const GVArray &values)
void GVectorArray::extend(const int64_t index, const GSpan values)
{
GVArrayForGSpan varray{values};
GVArray_For_GSpan varray{values};
this->extend(index, varray);
}
void GVectorArray::extend(IndexMask mask, const GVVectorArray &values)
{
for (const int i : mask) {
GVArrayForGVVectorArrayIndex array{values, i};
GVArray_For_GVVectorArrayIndex array{values, i};
this->extend(i, array);
}
}
void GVectorArray::extend(IndexMask mask, const GVectorArray &values)
{
GVVectorArrayForGVectorArray virtual_values{values};
GVVectorArray_For_GVectorArray virtual_values{values};
this->extend(mask, virtual_values);
}

View File

@@ -18,6 +18,10 @@
namespace blender::fn {
/* --------------------------------------------------------------------
* GVArray.
*/
void GVArray::materialize_to_uninitialized(const IndexMask mask, void *dst) const
{
for (const int64_t i : mask) {
@@ -37,7 +41,7 @@ bool GVArray::is_span_impl() const
return false;
}
GSpan GVArray::get_span_impl() const
GSpan GVArray::get_internal_span_impl() const
{
BLI_assert(false);
return GSpan(*type_);
@@ -48,60 +52,246 @@ bool GVArray::is_single_impl() const
return false;
}
void GVArray::get_single_impl(void *UNUSED(r_value)) const
void GVArray::get_internal_single_impl(void *UNUSED(r_value)) const
{
BLI_assert(false);
}
void GVArrayForGSpan::get_impl(const int64_t index, void *r_value) const
const void *GVArray::try_get_internal_varray_impl() const
{
return nullptr;
}
/* --------------------------------------------------------------------
* GVMutableArray.
*/
void GVMutableArray::set_by_copy_impl(const int64_t index, const void *value)
{
BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer);
type_->copy_to_uninitialized(value, buffer);
this->set_by_move_impl(index, buffer);
type_->destruct(buffer);
}
void GVMutableArray::set_by_relocate_impl(const int64_t index, void *value)
{
this->set_by_move_impl(index, value);
type_->destruct(value);
}
void *GVMutableArray::try_get_internal_mutable_varray_impl()
{
return nullptr;
}
void GVMutableArray::fill(const void *value)
{
if (this->is_span()) {
const GMutableSpan span = this->get_internal_span();
type_->fill_initialized(value, span.data(), size_);
}
else {
for (int64_t i : IndexRange(size_)) {
this->set_by_copy(i, value);
}
}
}
/* --------------------------------------------------------------------
* GVArray_For_GSpan.
*/
void GVArray_For_GSpan::get_impl(const int64_t index, void *r_value) const
{
type_->copy_to_initialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
void GVArrayForGSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const
void GVArray_For_GSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const
{
type_->copy_to_uninitialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
bool GVArrayForGSpan::is_span_impl() const
bool GVArray_For_GSpan::is_span_impl() const
{
return true;
}
GSpan GVArrayForGSpan::get_span_impl() const
GSpan GVArray_For_GSpan::get_internal_span_impl() const
{
return GSpan(*type_, data_, size_);
}
void GVArrayForSingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const
/* --------------------------------------------------------------------
* GVMutableArray_For_GMutableSpan.
*/
void GVMutableArray_For_GMutableSpan::get_impl(const int64_t index, void *r_value) const
{
type_->copy_to_initialized(value_, r_value);
type_->copy_to_initialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
void GVArrayForSingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index),
void *r_value) const
void GVMutableArray_For_GMutableSpan::get_to_uninitialized_impl(const int64_t index,
void *r_value) const
{
type_->copy_to_uninitialized(value_, r_value);
type_->copy_to_uninitialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
bool GVArrayForSingleValueRef::is_span_impl() const
void GVMutableArray_For_GMutableSpan::set_by_copy_impl(const int64_t index, const void *value)
{
return size_ == 1;
type_->copy_to_initialized(value, POINTER_OFFSET(data_, element_size_ * index));
}
GSpan GVArrayForSingleValueRef::get_span_impl() const
void GVMutableArray_For_GMutableSpan::set_by_move_impl(const int64_t index, void *value)
{
return GSpan{*type_, value_, 1};
type_->move_to_initialized(value, POINTER_OFFSET(data_, element_size_ * index));
}
bool GVArrayForSingleValueRef::is_single_impl() const
void GVMutableArray_For_GMutableSpan::set_by_relocate_impl(const int64_t index, void *value)
{
type_->relocate_to_initialized(value, POINTER_OFFSET(data_, element_size_ * index));
}
bool GVMutableArray_For_GMutableSpan::is_span_impl() const
{
return true;
}
void GVArrayForSingleValueRef::get_single_impl(void *r_value) const
GSpan GVMutableArray_For_GMutableSpan::get_internal_span_impl() const
{
return GSpan(*type_, data_, size_);
}
/* --------------------------------------------------------------------
* GVArray_For_SingleValueRef.
*/
void GVArray_For_SingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const
{
type_->copy_to_initialized(value_, r_value);
}
void GVArray_For_SingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index),
void *r_value) const
{
type_->copy_to_uninitialized(value_, r_value);
}
bool GVArray_For_SingleValueRef::is_span_impl() const
{
return size_ == 1;
}
GSpan GVArray_For_SingleValueRef::get_internal_span_impl() const
{
return GSpan{*type_, value_, 1};
}
bool GVArray_For_SingleValueRef::is_single_impl() const
{
return true;
}
void GVArray_For_SingleValueRef::get_internal_single_impl(void *r_value) const
{
type_->copy_to_initialized(value_, r_value);
}
/* --------------------------------------------------------------------
* GVArray_For_SingleValue.
*/
GVArray_For_SingleValue::GVArray_For_SingleValue(const CPPType &type,
const int64_t size,
const void *value)
: GVArray_For_SingleValueRef(type, size)
{
value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
type.copy_to_uninitialized(value, (void *)value_);
}
GVArray_For_SingleValue::~GVArray_For_SingleValue()
{
type_->destruct((void *)value_);
MEM_freeN((void *)value_);
}
/* --------------------------------------------------------------------
* GVArray_GSpan.
*/
GVArray_GSpan::GVArray_GSpan(const GVArray &varray) : GSpan(varray.type()), varray_(varray)
{
size_ = varray_.size();
if (varray_.is_span()) {
data_ = varray_.get_internal_span().data();
}
else {
owned_data_ = MEM_mallocN_aligned(type_->size() * size_, type_->alignment(), __func__);
varray_.materialize_to_uninitialized(IndexRange(size_), owned_data_);
data_ = owned_data_;
}
}
GVArray_GSpan::~GVArray_GSpan()
{
if (owned_data_ != nullptr) {
type_->destruct_n(owned_data_, size_);
MEM_freeN(owned_data_);
}
}
/* --------------------------------------------------------------------
* GVMutableArray_GSpan.
*/
GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray &varray, const bool copy_values_to_span)
: GMutableSpan(varray.type()), varray_(varray)
{
size_ = varray_.size();
if (varray_.is_span()) {
data_ = varray_.get_internal_span().data();
}
else {
owned_data_ = MEM_mallocN_aligned(type_->size() * size_, type_->alignment(), __func__);
if (copy_values_to_span) {
varray_.materialize_to_uninitialized(IndexRange(size_), owned_data_);
}
else {
type_->construct_default_n(owned_data_, size_);
}
data_ = owned_data_;
}
}
GVMutableArray_GSpan::~GVMutableArray_GSpan()
{
if (show_not_saved_warning_) {
if (!save_has_been_called_) {
std::cout << "Warning: Call `apply()` to make sure that changes persist in all cases.\n";
}
}
if (owned_data_ != nullptr) {
type_->destruct_n(owned_data_, size_);
MEM_freeN(owned_data_);
}
}
void GVMutableArray_GSpan::save()
{
save_has_been_called_ = true;
if (data_ != owned_data_) {
return;
}
const int64_t element_size = type_->size();
for (int64_t i : IndexRange(size_)) {
varray_.set_by_copy(i, POINTER_OFFSET(owned_data_, element_size * i));
}
}
void GVMutableArray_GSpan::disable_not_applied_warning()
{
show_not_saved_warning_ = false;
}
} // namespace blender::fn

View File

@@ -18,48 +18,48 @@
namespace blender::fn {
void GVArrayForGVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const
void GVArray_For_GVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const
{
vector_array_.get_vector_element(index_, index_in_vector, r_value);
}
void GVArrayForGVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector,
void *r_value) const
void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector,
void *r_value) const
{
type_->construct_default(r_value);
vector_array_.get_vector_element(index_, index_in_vector, r_value);
}
int64_t GVVectorArrayForSingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const
int64_t GVVectorArray_For_SingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const
{
return array_.size();
}
void GVVectorArrayForSingleGVArray::get_vector_element_impl(const int64_t UNUSED(index),
const int64_t index_in_vector,
void *r_value) const
void GVVectorArray_For_SingleGVArray::get_vector_element_impl(const int64_t UNUSED(index),
const int64_t index_in_vector,
void *r_value) const
{
array_.get(index_in_vector, r_value);
}
bool GVVectorArrayForSingleGVArray::is_single_vector_impl() const
bool GVVectorArray_For_SingleGVArray::is_single_vector_impl() const
{
return true;
}
int64_t GVVectorArrayForSingleGSpan::get_vector_size_impl(const int64_t UNUSED(index)) const
int64_t GVVectorArray_For_SingleGSpan::get_vector_size_impl(const int64_t UNUSED(index)) const
{
return span_.size();
}
void GVVectorArrayForSingleGSpan::get_vector_element_impl(const int64_t UNUSED(index),
const int64_t index_in_vector,
void *r_value) const
void GVVectorArray_For_SingleGSpan::get_vector_element_impl(const int64_t UNUSED(index),
const int64_t index_in_vector,
void *r_value) const
{
type_->copy_to_initialized(span_[index_in_vector], r_value);
}
bool GVVectorArrayForSingleGSpan::is_single_vector_impl() const
bool GVVectorArray_For_SingleGSpan::is_single_vector_impl() const
{
return true;
}

View File

@@ -974,11 +974,11 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__full(const MFInputS
if (any_value->type == ValueType::OwnSingle) {
OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value);
if (value->is_single_allocated) {
return scope.construct<GVArrayForSingleValueRef>(
return scope.construct<GVArray_For_SingleValueRef>(
__func__, value->span.type(), min_array_size_, value->span.data());
}
return scope.construct<GVArrayForGSpan>(__func__, value->span);
return scope.construct<GVArray_For_GSpan>(__func__, value->span);
}
if (any_value->type == ValueType::InputSingle) {
InputSingleValue *value = static_cast<InputSingleValue *>(any_value);
@@ -987,11 +987,11 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__full(const MFInputS
if (any_value->type == ValueType::OutputSingle) {
OutputSingleValue *value = static_cast<OutputSingleValue *>(any_value);
BLI_assert(value->is_computed);
return scope.construct<GVArrayForGSpan>(__func__, value->span);
return scope.construct<GVArray_For_GSpan>(__func__, value->span);
}
BLI_assert(false);
return scope.construct<GVArrayForEmpty>(__func__, CPPType::get<float>());
return scope.construct<GVArray_For_Empty>(__func__, CPPType::get<float>());
}
const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInputSocket &socket,
@@ -1004,7 +1004,7 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInpu
if (any_value->type == ValueType::OwnSingle) {
OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value);
BLI_assert(value->span.size() == 1);
return scope.construct<GVArrayForGSpan>(__func__, value->span);
return scope.construct<GVArray_For_GSpan>(__func__, value->span);
}
if (any_value->type == ValueType::InputSingle) {
InputSingleValue *value = static_cast<InputSingleValue *>(any_value);
@@ -1015,11 +1015,11 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInpu
OutputSingleValue *value = static_cast<OutputSingleValue *>(any_value);
BLI_assert(value->is_computed);
BLI_assert(value->span.size() == 1);
return scope.construct<GVArrayForGSpan>(__func__, value->span);
return scope.construct<GVArray_For_GSpan>(__func__, value->span);
}
BLI_assert(false);
return scope.construct<GVArrayForEmpty>(__func__, CPPType::get<float>());
return scope.construct<GVArray_For_Empty>(__func__, CPPType::get<float>());
}
const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full(
@@ -1033,10 +1033,10 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full(
OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value);
if (value->vector_array->size() == 1) {
GSpan span = (*value->vector_array)[0];
return scope.construct<GVVectorArrayForSingleGSpan>(__func__, span, min_array_size_);
return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, span, min_array_size_);
}
return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
}
if (any_value->type == ValueType::InputVector) {
InputVectorValue *value = static_cast<InputVectorValue *>(any_value);
@@ -1044,11 +1044,11 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full(
}
if (any_value->type == ValueType::OutputVector) {
OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value);
return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
}
BLI_assert(false);
return scope.construct<GVVectorArrayForSingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
}
const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single(
@@ -1061,7 +1061,7 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single(
if (any_value->type == ValueType::OwnVector) {
OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value);
BLI_assert(value->vector_array->size() == 1);
return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
}
if (any_value->type == ValueType::InputVector) {
InputVectorValue *value = static_cast<InputVectorValue *>(any_value);
@@ -1071,11 +1071,11 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single(
if (any_value->type == ValueType::OutputVector) {
OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value);
BLI_assert(value->vector_array->size() == 1);
return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
}
BLI_assert(false);
return scope.construct<GVVectorArrayForSingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
}
/** \} */

View File

@@ -223,7 +223,7 @@ TEST(multi_function_network, Test2)
Array<int> output_value_2(5, -1);
MFParamsBuilder params(network_fn, 5);
GVVectorArrayForSingleGSpan inputs_1{input_value_1.as_span(), 5};
GVVectorArray_For_SingleGSpan inputs_1{input_value_1.as_span(), 5};
params.add_readonly_vector_input(inputs_1);
params.add_readonly_single_input(&input_value_2);
params.add_vector_output(output_value_1);

View File

@@ -303,7 +303,7 @@ void GpencilIO::prepare_stroke_export_colors(Object *ob, bGPDstroke *gps)
/* Stroke color. */
copy_v4_v4(stroke_color_, gp_style->stroke_rgba);
avg_opacity_ = 0;
avg_opacity_ = 0.0f;
/* Get average vertex color and apply. */
float avg_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
for (const bGPDspoint &pt : Span(gps->points, gps->totpoints)) {

View File

@@ -69,7 +69,6 @@ GpencilExporterPDF::GpencilExporterPDF(const char *filename, const GpencilIOPara
pdf_ = nullptr;
page_ = nullptr;
gstate_ = nullptr;
}
bool GpencilExporterPDF::new_document()
@@ -169,16 +168,29 @@ void GpencilExporterPDF::export_gpencil_layers()
if (!ED_gpencil_stroke_material_visible(ob, gps)) {
continue;
}
/* Duplicate the stroke to apply any layer thickness change. */
bGPDstroke *gps_duplicate = BKE_gpencil_stroke_duplicate(gps, true, false);
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob,
gps_duplicate->mat_nr + 1);
/* Skip invisible lines. */
prepare_stroke_export_colors(ob, gps);
const float fill_opacity = fill_color_[3] * gpl->opacity;
const float stroke_opacity = stroke_color_[3] * stroke_average_opacity_get() *
gpl->opacity;
if ((fill_opacity < GPENCIL_ALPHA_OPACITY_THRESH) &&
(stroke_opacity < GPENCIL_ALPHA_OPACITY_THRESH)) {
continue;
}
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
const bool is_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) &&
(gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH));
(gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) &&
(stroke_opacity > GPENCIL_ALPHA_OPACITY_THRESH));
const bool is_fill = ((gp_style->flag & GP_MATERIAL_FILL_SHOW) &&
(gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH));
prepare_stroke_export_colors(ob, gps_duplicate);
if ((!is_stroke) && (!is_fill)) {
continue;
}
/* Duplicate the stroke to apply any layer thickness change. */
bGPDstroke *gps_duplicate = BKE_gpencil_stroke_duplicate(gps, true, false);
/* Apply layer thickness change. */
gps_duplicate->thickness += gpl->line_change;
@@ -283,29 +295,35 @@ void GpencilExporterPDF::color_set(bGPDlayer *gpl, const bool do_fill)
{
const float fill_opacity = fill_color_[3] * gpl->opacity;
const float stroke_opacity = stroke_color_[3] * stroke_average_opacity_get() * gpl->opacity;
const bool need_state = (do_fill && fill_opacity < 1.0f) || (stroke_opacity < 1.0f);
HPDF_Page_GSave(page_);
gstate_ = HPDF_CreateExtGState(pdf_);
HPDF_ExtGState gstate = (need_state) ? HPDF_CreateExtGState(pdf_) : nullptr;
float col[3];
if (do_fill) {
interp_v3_v3v3(col, fill_color_, gpl->tintcolor, gpl->tintcolor[3]);
linearrgb_to_srgb_v3_v3(col, col);
CLAMP3(col, 0.0f, 1.0f);
HPDF_ExtGState_SetAlphaFill(gstate_, clamp_f(fill_opacity, 0.0f, 1.0f));
HPDF_Page_SetRGBFill(page_, col[0], col[1], col[2]);
if (gstate) {
HPDF_ExtGState_SetAlphaFill(gstate, clamp_f(fill_opacity, 0.0f, 1.0f));
}
}
else {
interp_v3_v3v3(col, stroke_color_, gpl->tintcolor, gpl->tintcolor[3]);
linearrgb_to_srgb_v3_v3(col, col);
CLAMP3(col, 0.0f, 1.0f);
HPDF_ExtGState_SetAlphaFill(gstate_, clamp_f(stroke_opacity, 0.0f, 1.0f));
HPDF_ExtGState_SetAlphaStroke(gstate_, clamp_f(stroke_opacity, 0.0f, 1.0f));
HPDF_Page_SetRGBFill(page_, col[0], col[1], col[2]);
HPDF_Page_SetRGBStroke(page_, col[0], col[1], col[2]);
if (gstate) {
HPDF_ExtGState_SetAlphaFill(gstate, clamp_f(stroke_opacity, 0.0f, 1.0f));
HPDF_ExtGState_SetAlphaStroke(gstate, clamp_f(stroke_opacity, 0.0f, 1.0f));
}
}
if (gstate) {
HPDF_Page_SetExtGState(page_, gstate);
}
HPDF_Page_SetExtGState(page_, gstate_);
}
} // namespace blender::io::gpencil

View File

@@ -49,8 +49,6 @@ class GpencilExporterPDF : public GpencilExporter {
HPDF_Doc pdf_;
/* PDF page. */
HPDF_Page page_;
/* State. */
HPDF_ExtGState gstate_;
bool create_document();
bool add_page();

View File

@@ -278,8 +278,14 @@ typedef struct wmWindow {
char event_queue_check_click;
/** Enable when #KM_PRESS events are not handled (keyboard/mouse-buttons only). */
char event_queue_check_drag;
/**
* Enable when the drag was handled,
* to avoid mouse-motion continually triggering drag events which are not handled
* but add overhead to gizmo handling (for example), see T87511.
*/
char event_queue_check_drag_handled;
char _pad0[2];
char _pad0[1];
/** Internal, lock pie creation from this event until released. */
short pie_event_type_lock;
@@ -374,7 +380,12 @@ typedef struct wmKeyMapItem {
/** Unique identifier. Positive for kmi that override builtins, negative otherwise. */
short id;
char _pad[2];
/** Rna pointer to access properties. */
/**
* RNA pointer to access properties.
*
* \note The `ptr.owner_id` value must be NULL, as a signal not to use the context
* when running property callbacks such as ENUM item functions.
*/
struct PointerRNA *ptr;
} wmKeyMapItem;

View File

@@ -636,6 +636,12 @@ typedef enum StructFlag {
STRUCT_PUBLIC_NAMESPACE = (1 << 9),
/** All subtypes are added too. */
STRUCT_PUBLIC_NAMESPACE_INHERIT = (1 << 10),
/**
* When the #PointerRNA.owner_id is NULL, this signifies the property should be accessed
* without any context (the key-map UI and import/export for example).
* So accessing the property should not read from the current context to derive values/limits.
*/
STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID = (1 << 11),
} StructFlag;
typedef int (*StructValidateFunc)(struct PointerRNA *ptr, void *data, int *have_function);

View File

@@ -1623,35 +1623,35 @@ void RNA_property_enum_items_ex(bContext *C,
*r_free = false;
if (!use_static && eprop->item_fn && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
const EnumPropertyItem *item;
if (!use_static && (eprop->item_fn != NULL)) {
const bool no_context = (prop->flag & PROP_ENUM_NO_CONTEXT) ||
((ptr->type->flag & STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID) &&
(ptr->owner_id == NULL));
if (C != NULL || no_context) {
const EnumPropertyItem *item;
if (prop->flag & PROP_ENUM_NO_CONTEXT) {
item = eprop->item_fn(NULL, ptr, prop, r_free);
}
else {
item = eprop->item_fn(C, ptr, prop, r_free);
}
item = eprop->item_fn(no_context ? NULL : C, ptr, prop, r_free);
/* any callbacks returning NULL should be fixed */
BLI_assert(item != NULL);
/* any callbacks returning NULL should be fixed */
BLI_assert(item != NULL);
if (r_totitem) {
int tot;
for (tot = 0; item[tot].identifier; tot++) {
/* pass */
if (r_totitem) {
int tot;
for (tot = 0; item[tot].identifier; tot++) {
/* pass */
}
*r_totitem = tot;
}
*r_totitem = tot;
}
*r_item = item;
}
else {
*r_item = eprop->item;
if (r_totitem) {
*r_totitem = eprop->totitem;
*r_item = item;
return;
}
}
*r_item = eprop->item;
if (r_totitem) {
*r_totitem = eprop->totitem;
}
}
void RNA_property_enum_items(bContext *C,
@@ -1753,43 +1753,43 @@ void RNA_property_enum_items_gettexted_all(bContext *C,
*r_totitem = eprop->totitem;
}
if (eprop->item_fn && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
const EnumPropertyItem *item;
int i;
bool free = false;
if (eprop->item_fn != NULL) {
const bool no_context = (prop->flag & PROP_ENUM_NO_CONTEXT) ||
((ptr->type->flag & STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID) &&
(ptr->owner_id == NULL));
if (C != NULL || no_context) {
const EnumPropertyItem *item;
int i;
bool free = false;
if (prop->flag & PROP_ENUM_NO_CONTEXT) {
item = eprop->item_fn(NULL, ptr, prop, &free);
}
else {
item = eprop->item_fn(C, ptr, prop, &free);
}
item = eprop->item_fn(no_context ? NULL : NULL, ptr, prop, &free);
/* any callbacks returning NULL should be fixed */
BLI_assert(item != NULL);
/* any callbacks returning NULL should be fixed */
BLI_assert(item != NULL);
for (i = 0; i < eprop->totitem; i++) {
bool exists = false;
int i_fixed;
for (i = 0; i < eprop->totitem; i++) {
bool exists = false;
int i_fixed;
/* Items that do not exist on list are returned,
* but have their names/identifiers NULL'ed out. */
for (i_fixed = 0; item[i_fixed].identifier; i_fixed++) {
if (STREQ(item[i_fixed].identifier, item_array[i].identifier)) {
exists = true;
break;
/* Items that do not exist on list are returned,
* but have their names/identifiers NULL'ed out. */
for (i_fixed = 0; item[i_fixed].identifier; i_fixed++) {
if (STREQ(item[i_fixed].identifier, item_array[i].identifier)) {
exists = true;
break;
}
}
if (!exists) {
item_array[i].name = NULL;
item_array[i].identifier = "";
}
}
if (!exists) {
item_array[i].name = NULL;
item_array[i].identifier = "";
if (free) {
MEM_freeN((void *)item);
}
}
if (free) {
MEM_freeN((void *)item);
}
}
#ifdef WITH_INTERNATIONAL

View File

@@ -2197,7 +2197,10 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mask_layer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_MASK);
RNA_def_property_ui_text(prop, "Mask Layer", "Mask pixels from underlying layers drawing");
RNA_def_property_ui_text(
prop,
"Use Mask",
"The visibility of drawings on this layer is affected by the layers in its masks list");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "use_lights", PROP_BOOLEAN, PROP_NONE);

View File

@@ -2483,6 +2483,10 @@ const EnumPropertyItem *rna_TransformOrientation_itemf(bContext *C,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
if (C == NULL) {
return rna_enum_transform_orientation_items;
}
Scene *scene;
if (ptr->owner_id && (GS(ptr->owner_id->name) == ID_SCE)) {
scene = (Scene *)ptr->owner_id;
@@ -2493,11 +2497,15 @@ const EnumPropertyItem *rna_TransformOrientation_itemf(bContext *C,
return rna_TransformOrientation_impl_itemf(scene, false, r_free);
}
const EnumPropertyItem *rna_TransformOrientation_with_scene_itemf(bContext *UNUSED(C),
const EnumPropertyItem *rna_TransformOrientation_with_scene_itemf(bContext *C,
PointerRNA *ptr,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
if (C == NULL) {
return rna_enum_transform_orientation_items;
}
Scene *scene = (Scene *)ptr->owner_id;
TransformOrientationSlot *orient_slot = ptr->data;
bool include_default = (orient_slot != &scene->orientation_slots[SCE_ORIENT_DEFAULT]);

View File

@@ -779,7 +779,7 @@ static const EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C
RNA_enum_item_add(&item, &totitem, &new_item);
}
# ifndef NDEBUG
# if !defined(NDEBUG) || !defined(WITH_AUDASPACE)
if (i == 0) {
EnumPropertyItem new_item = {i, "SOUND_NONE", 0, "No Sound", ""};
RNA_enum_item_add(&item, &totitem, &new_item);

View File

@@ -880,6 +880,7 @@ static PointerRNA rna_KeyMapItem_properties_get(PointerRNA *ptr)
wmKeyMapItem *kmi = ptr->data;
if (kmi->ptr) {
BLI_assert(kmi->ptr->owner_id == NULL);
return *(kmi->ptr);
}
@@ -1974,7 +1975,7 @@ static void rna_def_operator(BlenderRNA *brna)
RNA_def_struct_refine_func(srna, "rna_OperatorProperties_refine");
RNA_def_struct_idprops_func(srna, "rna_OperatorProperties_idprops");
RNA_def_struct_property_tags(srna, rna_enum_operator_property_tags);
RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES | STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID);
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
}

View File

@@ -179,6 +179,14 @@ static void add_object_relation(const ModifierUpdateDepsgraphContext *ctx, Objec
}
else if (ELEM(object.type, OB_MESH, OB_POINTCLOUD, OB_VOLUME)) {
DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_GEOMETRY, "Nodes Modifier");
/* We don't know exactly what attributes from the other object we will need. */
CustomData_MeshMasks mask;
mask.vmask = CD_MASK_PROP_ALL | CD_MASK_MDEFORMVERT;
mask.pmask = CD_MASK_PROP_ALL;
mask.lmask = CD_MASK_PROP_ALL;
mask.fmask = CD_MASK_PROP_ALL;
mask.emask = CD_MASK_PROP_ALL;
DEG_add_customdata_mask(ctx->node, &object, &mask);
}
}
}
@@ -454,10 +462,6 @@ class GeometryNodesEvaluator {
{
const bNode &bnode = params.node();
if (DEG_is_active(depsgraph_)) {
this->store_ui_hints(node, params);
}
/* Use the geometry-node-execute callback if it exists. */
if (bnode.typeinfo->geometry_node_execute != nullptr) {
bnode.typeinfo->geometry_node_execute(params);
@@ -475,41 +479,6 @@ class GeometryNodesEvaluator {
this->execute_unknown_node(node, params);
}
void store_ui_hints(const DNode node, GeoNodeExecParams params) const
{
for (const InputSocketRef *socket_ref : node->inputs()) {
if (!socket_ref->is_available()) {
continue;
}
if (socket_ref->bsocket()->type != SOCK_GEOMETRY) {
continue;
}
if (socket_ref->is_multi_input_socket()) {
/* Not needed currently. */
continue;
}
bNodeTree *btree_cow = node->btree();
bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
const NodeTreeEvaluationContext context(*self_object_, *modifier_);
const GeometrySet &geometry_set = params.get_input<GeometrySet>(socket_ref->identifier());
blender::bke::geometry_set_instances_attribute_foreach(
geometry_set,
[&](StringRefNull attribute_name, const AttributeMetaData &meta_data) {
BKE_nodetree_attribute_hint_add(*btree_original,
context,
*node->bnode(),
attribute_name,
meta_data.domain,
meta_data.data_type);
return true;
},
8);
}
}
void execute_multi_function_node(const DNode node,
GeoNodeExecParams params,
const MultiFunction &fn)
@@ -583,7 +552,8 @@ class GeometryNodesEvaluator {
else {
void *buffer = allocator_.allocate(to_type.size(), to_type.alignment());
if (conversions_.is_convertible(from_type, to_type)) {
conversions_.convert(from_type, to_type, value_to_forward.get(), buffer);
conversions_.convert_to_uninitialized(
from_type, to_type, value_to_forward.get(), buffer);
}
else {
to_type.copy_to_uninitialized(to_type.default_value(), buffer);
@@ -653,7 +623,7 @@ class GeometryNodesEvaluator {
if (conversions_.is_convertible(type, required_type)) {
void *converted_buffer = allocator_.allocate(required_type.size(),
required_type.alignment());
conversions_.convert(type, required_type, buffer, converted_buffer);
conversions_.convert_to_uninitialized(type, required_type, buffer, converted_buffer);
type.destruct(buffer);
return {required_type, converted_buffer};
}
@@ -1230,6 +1200,37 @@ static void log_preview_socket_value(const Span<GPointer> values,
}
}
static void log_ui_hints(const DSocket socket,
const Span<GPointer> values,
Object *self_object,
NodesModifierData *nmd)
{
const DNode node = socket.node();
if (node->is_reroute_node() || socket->typeinfo()->type != SOCK_GEOMETRY) {
return;
}
bNodeTree *btree_cow = node->btree();
bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
const NodeTreeEvaluationContext context{*self_object, nmd->modifier};
for (const GPointer data : values) {
if (data.type() == &CPPType::get<GeometrySet>()) {
const GeometrySet &geometry_set = *(const GeometrySet *)data.get();
blender::bke::geometry_set_instances_attribute_foreach(
geometry_set,
[&](StringRefNull attribute_name, const AttributeMetaData &meta_data) {
BKE_nodetree_attribute_hint_add(*btree_original,
context,
*node->bnode(),
attribute_name,
meta_data.domain,
meta_data.data_type);
return true;
},
8);
}
}
}
/**
* Evaluate a node group to compute the output geometry.
* Currently, this uses a fairly basic and inefficient algorithm that might compute things more
@@ -1296,6 +1297,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
if (!keys.is_empty()) {
log_preview_socket_value(values, ctx->object, keys);
}
log_ui_hints(socket, values, ctx->object, nmd);
};
GeometryNodesEvaluator evaluator{group_inputs,

View File

@@ -33,29 +33,26 @@ struct ModifierData;
namespace blender::nodes {
using bke::BooleanReadAttribute;
using bke::BooleanWriteAttribute;
using bke::Color4fReadAttribute;
using bke::Color4fWriteAttribute;
using bke::Float2ReadAttribute;
using bke::Float2WriteAttribute;
using bke::Float3ReadAttribute;
using bke::Float3WriteAttribute;
using bke::FloatReadAttribute;
using bke::FloatWriteAttribute;
using bke::geometry_set_realize_instances;
using bke::Int32ReadAttribute;
using bke::Int32WriteAttribute;
using bke::OutputAttribute;
using bke::OutputAttribute_Typed;
using bke::PersistentDataHandleMap;
using bke::PersistentObjectHandle;
using bke::ReadAttribute;
using bke::ReadAttributePtr;
using bke::WriteAttribute;
using bke::WriteAttributePtr;
using bke::ReadAttributeLookup;
using bke::WriteAttributeLookup;
using fn::CPPType;
using fn::GMutablePointer;
using fn::GMutableSpan;
using fn::GPointer;
using fn::GSpan;
using fn::GValueMap;
using fn::GVArray;
using fn::GVArray_GSpan;
using fn::GVArray_Span;
using fn::GVArray_Typed;
using fn::GVMutableArray;
using fn::GVMutableArray_GSpan;
using fn::GVMutableArray_Typed;
class GeoNodeExecParams {
private:
@@ -217,20 +214,22 @@ class GeoNodeExecParams {
* \note This will add an error message if the string socket is active and
* the input attribute does not exist.
*/
ReadAttributePtr get_input_attribute(const StringRef name,
const GeometryComponent &component,
const AttributeDomain domain,
const CustomDataType type,
const void *default_value) const;
std::unique_ptr<GVArray> get_input_attribute(const StringRef name,
const GeometryComponent &component,
const AttributeDomain domain,
const CustomDataType type,
const void *default_value) const;
template<typename T>
bke::TypedReadAttribute<T> get_input_attribute(const StringRef name,
const GeometryComponent &component,
const AttributeDomain domain,
const T &default_value) const
GVArray_Typed<T> get_input_attribute(const StringRef name,
const GeometryComponent &component,
const AttributeDomain domain,
const T &default_value) const
{
const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>());
return this->get_input_attribute(name, component, domain, type, &default_value);
std::unique_ptr<GVArray> varray = this->get_input_attribute(
name, component, domain, type, &default_value);
return GVArray_Typed<T>(std::move(varray));
}
/**

View File

@@ -21,20 +21,45 @@
namespace blender::nodes {
using fn::CPPType;
using fn::GVArray;
struct ConversionFunctions {
const fn::MultiFunction *multi_function;
void (*convert_single_to_initialized)(const void *src, void *dst);
void (*convert_single_to_uninitialized)(const void *src, void *dst);
};
class DataTypeConversions {
private:
Map<std::pair<fn::MFDataType, fn::MFDataType>, const fn::MultiFunction *> conversions_;
Map<std::pair<fn::MFDataType, fn::MFDataType>, ConversionFunctions> conversions_;
public:
void add(fn::MFDataType from_type, fn::MFDataType to_type, const fn::MultiFunction &fn)
void add(fn::MFDataType from_type,
fn::MFDataType to_type,
const fn::MultiFunction &fn,
void (*convert_single_to_initialized)(const void *src, void *dst),
void (*convert_single_to_uninitialized)(const void *src, void *dst))
{
conversions_.add_new({from_type, to_type}, &fn);
conversions_.add_new({from_type, to_type},
{&fn, convert_single_to_initialized, convert_single_to_uninitialized});
}
const fn::MultiFunction *get_conversion(fn::MFDataType from, fn::MFDataType to) const
const ConversionFunctions *get_conversion_functions(fn::MFDataType from, fn::MFDataType to) const
{
return conversions_.lookup_default({from, to}, nullptr);
return conversions_.lookup_ptr({from, to});
}
const ConversionFunctions *get_conversion_functions(const CPPType &from, const CPPType &to) const
{
return this->get_conversion_functions(fn::MFDataType::ForSingle(from),
fn::MFDataType::ForSingle(to));
}
const fn::MultiFunction *get_conversion_multi_function(fn::MFDataType from,
fn::MFDataType to) const
{
const ConversionFunctions *functions = this->get_conversion_functions(from, to);
return functions ? functions->multi_function : nullptr;
}
bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
@@ -43,10 +68,16 @@ class DataTypeConversions {
{fn::MFDataType::ForSingle(from_type), fn::MFDataType::ForSingle(to_type)});
}
void convert(const CPPType &from_type,
const CPPType &to_type,
const void *from_value,
void *to_value) const;
void convert_to_uninitialized(const CPPType &from_type,
const CPPType &to_type,
const void *from_value,
void *to_value) const;
std::unique_ptr<fn::GVArray> try_convert(std::unique_ptr<fn::GVArray> varray,
const CPPType &to_type) const;
std::unique_ptr<fn::GVMutableArray> try_convert(std::unique_ptr<fn::GVMutableArray> varray,
const CPPType &to_type) const;
};
const DataTypeConversions &get_implicit_type_conversions();

View File

@@ -67,6 +67,8 @@ static void geometry_node_tree_get_from_context(const bContext *C,
static void geometry_node_tree_update(bNodeTree *ntree)
{
ntreeSetOutput(ntree);
/* Needed to give correct types to reroutes. */
ntree_update_reroute_nodes(ntree);
}

View File

@@ -50,10 +50,10 @@ static void geo_node_align_rotation_to_vector_layout(uiLayout *layout,
namespace blender::nodes {
static void align_rotations_auto_pivot(const Float3ReadAttribute &vectors,
const FloatReadAttribute &factors,
static void align_rotations_auto_pivot(const VArray<float3> &vectors,
const VArray<float> &factors,
const float3 local_main_axis,
MutableSpan<float3> rotations)
const MutableSpan<float3> rotations)
{
for (const int i : IndexRange(vectors.size())) {
const float3 vector = vectors[i];
@@ -93,11 +93,11 @@ static void align_rotations_auto_pivot(const Float3ReadAttribute &vectors,
}
}
static void align_rotations_fixed_pivot(const Float3ReadAttribute &vectors,
const FloatReadAttribute &factors,
static void align_rotations_fixed_pivot(const VArray<float3> &vectors,
const VArray<float> &factors,
const float3 local_main_axis,
const float3 local_pivot_axis,
MutableSpan<float3> rotations)
const MutableSpan<float3> rotations)
{
if (local_main_axis == local_pivot_axis) {
/* Can't compute any meaningful rotation angle in this case. */
@@ -144,30 +144,30 @@ static void align_rotations_on_component(GeometryComponent &component,
const NodeGeometryAlignRotationToVector &storage = *(const NodeGeometryAlignRotationToVector *)
node.storage;
OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
"rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
if (!rotation_attribute) {
OutputAttribute_Typed<float3> rotations = component.attribute_try_get_for_output<float3>(
"rotation", ATTR_DOMAIN_POINT, {0, 0, 0});
if (!rotations) {
return;
}
MutableSpan<float3> rotations = rotation_attribute->get_span<float3>();
FloatReadAttribute factors = params.get_input_attribute<float>(
GVArray_Typed<float> factors = params.get_input_attribute<float>(
"Factor", component, ATTR_DOMAIN_POINT, 1.0f);
Float3ReadAttribute vectors = params.get_input_attribute<float3>(
GVArray_Typed<float3> vectors = params.get_input_attribute<float3>(
"Vector", component, ATTR_DOMAIN_POINT, {0, 0, 1});
float3 local_main_axis{0, 0, 0};
local_main_axis[storage.axis] = 1;
if (storage.pivot_axis == GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_AUTO) {
align_rotations_auto_pivot(vectors, factors, local_main_axis, rotations);
align_rotations_auto_pivot(vectors, factors, local_main_axis, rotations.as_span());
}
else {
float3 local_pivot_axis{0, 0, 0};
local_pivot_axis[storage.pivot_axis - 1] = 1;
align_rotations_fixed_pivot(vectors, factors, local_main_axis, local_pivot_axis, rotations);
align_rotations_fixed_pivot(
vectors, factors, local_main_axis, local_pivot_axis, rotations.as_span());
}
rotation_attribute.apply_span_and_save();
rotations.save();
}
static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params)

View File

@@ -112,10 +112,13 @@ template<> inline Color4f clamp_value(const Color4f val, const Color4f min, cons
}
template<typename T>
static void clamp_attribute(Span<T> read_span, MutableSpan<T> span, const T min, const T max)
static void clamp_attribute(const VArray<T> &inputs,
const MutableSpan<T> outputs,
const T min,
const T max)
{
for (const int i : span.index_range()) {
span[i] = clamp_value<T>(read_span[i], min, max);
for (const int i : IndexRange(outputs.size())) {
outputs[i] = clamp_value<T>(inputs[i], min, max);
}
}
@@ -123,13 +126,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef source_name,
StringRef result_name)
{
ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
return result_attribute->domain();
return result_attribute.domain;
}
ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name);
ReadAttributeLookup source_attribute = component.attribute_try_get_for_read(source_name);
if (source_attribute) {
return source_attribute->domain();
return source_attribute.domain;
}
return ATTR_DOMAIN_POINT;
}
@@ -154,10 +157,10 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
const AttributeDomain domain = get_result_domain(component, attribute_name, result_name);
const int operation = static_cast<int>(storage.operation);
ReadAttributePtr attribute_input = component.attribute_try_get_for_read(
std::unique_ptr<GVArray> attribute_input = component.attribute_try_get_for_read(
attribute_name, domain, data_type);
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, domain, data_type);
if (!attribute_result) {
@@ -169,8 +172,6 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
switch (data_type) {
case CD_PROP_FLOAT3: {
Span<float3> read_span = attribute_input->get_span<float3>();
MutableSpan<float3> span = attribute_result->get_span_for_write_only<float3>();
float3 min = params.get_input<float3>("Min");
float3 max = params.get_input<float3>("Max");
if (operation == NODE_CLAMP_RANGE) {
@@ -184,38 +185,35 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
std::swap(min.z, max.z);
}
}
clamp_attribute<float3>(read_span, span, min, max);
MutableSpan<float3> results = attribute_result.as_span<float3>();
clamp_attribute<float3>(attribute_input->typed<float3>(), results, min, max);
break;
}
case CD_PROP_FLOAT: {
Span<float> read_span = attribute_input->get_span<float>();
MutableSpan<float> span = attribute_result->get_span_for_write_only<float>();
const float min = params.get_input<float>("Min_001");
const float max = params.get_input<float>("Max_001");
MutableSpan<float> results = attribute_result.as_span<float>();
if (operation == NODE_CLAMP_RANGE && min > max) {
clamp_attribute<float>(read_span, span, max, min);
clamp_attribute<float>(attribute_input->typed<float>(), results, max, min);
}
else {
clamp_attribute<float>(read_span, span, min, max);
clamp_attribute<float>(attribute_input->typed<float>(), results, min, max);
}
break;
}
case CD_PROP_INT32: {
Span<int> read_span = attribute_input->get_span<int>();
MutableSpan<int> span = attribute_result->get_span_for_write_only<int>();
const int min = params.get_input<int>("Min_002");
const int max = params.get_input<int>("Max_002");
MutableSpan<int> results = attribute_result.as_span<int>();
if (operation == NODE_CLAMP_RANGE && min > max) {
clamp_attribute<int>(read_span, span, max, min);
clamp_attribute<int>(attribute_input->typed<int>(), results, max, min);
}
else {
clamp_attribute<int>(read_span, span, min, max);
clamp_attribute<int>(attribute_input->typed<int>(), results, min, max);
}
break;
}
case CD_PROP_COLOR: {
Span<Color4f> read_span = attribute_input->get_span<Color4f>();
MutableSpan<Color4f> span = attribute_result->get_span_for_write_only<Color4f>();
Color4f min = params.get_input<Color4f>("Min_003");
Color4f max = params.get_input<Color4f>("Max_003");
if (operation == NODE_CLAMP_RANGE) {
@@ -232,7 +230,8 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
std::swap(min.a, max.a);
}
}
clamp_attribute<Color4f>(read_span, span, min, max);
MutableSpan<Color4f> results = attribute_result.as_span<Color4f>();
clamp_attribute<Color4f>(attribute_input->typed<Color4f>(), results, min, max);
break;
}
default: {
@@ -241,7 +240,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
}
}
attribute_result.apply_span_and_save();
attribute_result.save();
}
static void geo_node_attribute_clamp_exec(GeoNodeExecParams params)

View File

@@ -47,15 +47,15 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
return result_attribute->domain();
return result_attribute.domain;
}
/* Otherwise use the input attribute's domain if it exists. */
ReadAttributePtr input_attribute = component.attribute_try_get_for_read(input_name);
ReadAttributeLookup input_attribute = component.attribute_try_get_for_read(input_name);
if (input_attribute) {
return input_attribute->domain();
return input_attribute.domain;
}
return ATTR_DOMAIN_POINT;
@@ -71,27 +71,25 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
/* Always output a color attribute for now. We might want to allow users to customize.
* Using the type of an existing attribute could work, but does not have a real benefit
* currently. */
const CustomDataType result_type = CD_PROP_COLOR;
const AttributeDomain result_domain = get_result_domain(component, input_name, result_name);
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
OutputAttribute_Typed<Color4f> attribute_result =
component.attribute_try_get_for_output_only<Color4f>(result_name, result_domain);
if (!attribute_result) {
return;
}
FloatReadAttribute attribute_in = component.attribute_get_for_read<float>(
GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>(
input_name, result_domain, 0.0f);
Span<float> data_in = attribute_in.get_span();
MutableSpan<Color4f> data_out = attribute_result->get_span_for_write_only<Color4f>();
MutableSpan<Color4f> results = attribute_result.as_span();
ColorBand *color_ramp = &node_storage->color_ramp;
for (const int i : data_in.index_range()) {
BKE_colorband_evaluate(color_ramp, data_in[i], data_out[i]);
for (const int i : IndexRange(attribute_in.size())) {
BKE_colorband_evaluate(color_ramp, attribute_in[i], results[i]);
}
attribute_result.apply_span_and_save();
attribute_result.save();
}
static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params)

View File

@@ -77,9 +77,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
return result_attribute->domain();
return result_attribute.domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -94,27 +94,24 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa
}
const AttributeDomain result_domain = get_result_domain(component, params, result_name);
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, CD_PROP_FLOAT3);
OutputAttribute_Typed<float3> attribute_result =
component.attribute_try_get_for_output_only<float3>(result_name, result_domain);
if (!attribute_result) {
return;
}
FloatReadAttribute attribute_x = params.get_input_attribute<float>(
GVArray_Typed<float> attribute_x = params.get_input_attribute<float>(
"X", component, result_domain, 0.0f);
FloatReadAttribute attribute_y = params.get_input_attribute<float>(
GVArray_Typed<float> attribute_y = params.get_input_attribute<float>(
"Y", component, result_domain, 0.0f);
FloatReadAttribute attribute_z = params.get_input_attribute<float>(
GVArray_Typed<float> attribute_z = params.get_input_attribute<float>(
"Z", component, result_domain, 0.0f);
MutableSpan<float3> results = attribute_result->get_span_for_write_only<float3>();
for (const int i : results.index_range()) {
for (const int i : IndexRange(attribute_result->size())) {
const float x = attribute_x[i];
const float y = attribute_y[i];
const float z = attribute_z[i];
const float3 result = float3(x, y, z);
results[i] = result;
attribute_result->set(i, {x, y, z});
}
attribute_result.apply_span_and_save();
}
static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params)

View File

@@ -81,21 +81,18 @@ static void geo_node_attribute_compare_update(bNodeTree *UNUSED(ntree), bNode *n
nodeSetSocketAvailability(socket_threshold, operation_tests_equality(*node_storage));
}
static void do_math_operation(const FloatReadAttribute &input_a,
const FloatReadAttribute &input_b,
static void do_math_operation(const VArray<float> &input_a,
const VArray<float> &input_b,
const FloatCompareOperation operation,
MutableSpan<bool> span_result)
{
const int size = input_a.size();
Span<float> span_a = input_a.get_span();
Span<float> span_b = input_b.get_span();
if (try_dispatch_float_math_fl_fl_to_bool(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
for (const int i : IndexRange(size)) {
const float a = span_a[i];
const float b = span_b[i];
const float a = input_a[i];
const float b = input_b[i];
const bool out = math_function(a, b);
span_result[i] = out;
}
@@ -107,8 +104,8 @@ static void do_math_operation(const FloatReadAttribute &input_a,
BLI_assert(false);
}
static void do_equal_operation_float(const FloatReadAttribute &input_a,
const FloatReadAttribute &input_b,
static void do_equal_operation_float(const VArray<float> &input_a,
const VArray<float> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -120,8 +117,8 @@ static void do_equal_operation_float(const FloatReadAttribute &input_a,
}
}
static void do_equal_operation_float3(const Float3ReadAttribute &input_a,
const Float3ReadAttribute &input_b,
static void do_equal_operation_float3(const VArray<float3> &input_a,
const VArray<float3> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -134,8 +131,8 @@ static void do_equal_operation_float3(const Float3ReadAttribute &input_a,
}
}
static void do_equal_operation_color4f(const Color4fReadAttribute &input_a,
const Color4fReadAttribute &input_b,
static void do_equal_operation_color4f(const VArray<Color4f> &input_a,
const VArray<Color4f> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -148,8 +145,8 @@ static void do_equal_operation_color4f(const Color4fReadAttribute &input_a,
}
}
static void do_equal_operation_bool(const BooleanReadAttribute &input_a,
const BooleanReadAttribute &input_b,
static void do_equal_operation_bool(const VArray<bool> &input_a,
const VArray<bool> &input_b,
const float UNUSED(threshold),
MutableSpan<bool> span_result)
{
@@ -161,8 +158,8 @@ static void do_equal_operation_bool(const BooleanReadAttribute &input_a,
}
}
static void do_not_equal_operation_float(const FloatReadAttribute &input_a,
const FloatReadAttribute &input_b,
static void do_not_equal_operation_float(const VArray<float> &input_a,
const VArray<float> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -174,8 +171,8 @@ static void do_not_equal_operation_float(const FloatReadAttribute &input_a,
}
}
static void do_not_equal_operation_float3(const Float3ReadAttribute &input_a,
const Float3ReadAttribute &input_b,
static void do_not_equal_operation_float3(const VArray<float3> &input_a,
const VArray<float3> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -188,8 +185,8 @@ static void do_not_equal_operation_float3(const Float3ReadAttribute &input_a,
}
}
static void do_not_equal_operation_color4f(const Color4fReadAttribute &input_a,
const Color4fReadAttribute &input_b,
static void do_not_equal_operation_color4f(const VArray<Color4f> &input_a,
const VArray<Color4f> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -202,8 +199,8 @@ static void do_not_equal_operation_color4f(const Color4fReadAttribute &input_a,
}
}
static void do_not_equal_operation_bool(const BooleanReadAttribute &input_a,
const BooleanReadAttribute &input_b,
static void do_not_equal_operation_bool(const VArray<bool> &input_a,
const VArray<bool> &input_b,
const float UNUSED(threshold),
MutableSpan<bool> span_result)
{
@@ -237,9 +234,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
return result_attribute->domain();
return result_attribute.domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -254,20 +251,19 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
node_storage->operation);
const std::string result_name = params.get_input<std::string>("Result");
const CustomDataType result_type = CD_PROP_BOOL;
const AttributeDomain result_domain = get_result_domain(component, params, result_name);
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
OutputAttribute_Typed<bool> attribute_result = component.attribute_try_get_for_output_only<bool>(
result_name, result_domain);
if (!attribute_result) {
return;
}
const CustomDataType input_data_type = get_data_type(component, params, *node_storage);
ReadAttributePtr attribute_a = params.get_input_attribute(
std::unique_ptr<GVArray> attribute_a = params.get_input_attribute(
"A", component, result_domain, input_data_type, nullptr);
ReadAttributePtr attribute_b = params.get_input_attribute(
std::unique_ptr<GVArray> attribute_b = params.get_input_attribute(
"B", component, result_domain, input_data_type, nullptr);
if (!attribute_a || !attribute_b) {
@@ -275,7 +271,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
return;
}
MutableSpan<bool> result_span = attribute_result->get_span_for_write_only<bool>();
MutableSpan<bool> result_span = attribute_result.as_span();
/* Use specific types for correct equality operations, but for other operations we use implicit
* conversions and float comparison. In other words, the comparison is not element-wise. */
@@ -283,38 +279,47 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
const float threshold = params.get_input<float>("Threshold");
if (operation == NODE_FLOAT_COMPARE_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
do_equal_operation_float(*attribute_a, *attribute_b, threshold, result_span);
do_equal_operation_float(
attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_FLOAT3) {
do_equal_operation_float3(*attribute_a, *attribute_b, threshold, result_span);
do_equal_operation_float3(
attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
do_equal_operation_color4f(*attribute_a, *attribute_b, threshold, result_span);
do_equal_operation_color4f(
attribute_a->typed<Color4f>(), attribute_b->typed<Color4f>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
do_equal_operation_bool(*attribute_a, *attribute_b, threshold, result_span);
do_equal_operation_bool(
attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span);
}
}
else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
do_not_equal_operation_float(*attribute_a, *attribute_b, threshold, result_span);
do_not_equal_operation_float(
attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_FLOAT3) {
do_not_equal_operation_float3(*attribute_a, *attribute_b, threshold, result_span);
do_not_equal_operation_float3(
attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
do_not_equal_operation_color4f(*attribute_a, *attribute_b, threshold, result_span);
do_not_equal_operation_color4f(
attribute_a->typed<Color4f>(), attribute_b->typed<Color4f>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
do_not_equal_operation_bool(*attribute_a, *attribute_b, threshold, result_span);
do_not_equal_operation_bool(
attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span);
}
}
}
else {
do_math_operation(*attribute_a, *attribute_b, operation, result_span);
do_math_operation(
attribute_a->typed<float>(), attribute_b->typed<float>(), operation, result_span);
}
attribute_result.apply_span_and_save();
attribute_result.save();
}
static void geo_node_attribute_compare_exec(GeoNodeExecParams params)

View File

@@ -55,13 +55,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef source_name,
StringRef result_name)
{
ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
return result_attribute->domain();
return result_attribute.domain;
}
ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name);
ReadAttributeLookup source_attribute = component.attribute_try_get_for_read(source_name);
if (source_attribute) {
return source_attribute->domain();
return source_attribute.domain;
}
return ATTR_DOMAIN_POINT;
}
@@ -78,7 +78,7 @@ static void attribute_convert_calc(GeometryComponent &component,
component, source_name, result_name) :
domain;
ReadAttributePtr source_attribute = component.attribute_try_get_for_read(
std::unique_ptr<GVArray> source_attribute = component.attribute_try_get_for_read(
source_name, result_domain, result_type);
if (!source_attribute) {
params.error_message_add(NodeWarningType::Error,
@@ -86,25 +86,22 @@ static void attribute_convert_calc(GeometryComponent &component,
return;
}
OutputAttributePtr result_attribute = component.attribute_try_get_for_output(
OutputAttribute result_attribute = component.attribute_try_get_for_output_only(
result_name, result_domain, result_type);
if (!result_attribute) {
return;
}
fn::GSpan source_span = source_attribute->get_span();
fn::GMutableSpan result_span = result_attribute->get_span_for_write_only();
if (source_span.is_empty() || result_span.is_empty()) {
return;
}
GVArray_GSpan source_span{*source_attribute};
GMutableSpan result_span = result_attribute.as_span();
BLI_assert(source_span.size() == result_span.size());
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(result_type);
BLI_assert(cpp_type != nullptr);
cpp_type->copy_to_initialized_n(source_span.data(), result_span.data(), result_span.size());
result_attribute.apply_span_and_save();
result_attribute.save();
}
static void geo_node_attribute_convert_exec(GeoNodeExecParams params)

View File

@@ -72,9 +72,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef attribute_name)
{
/* Use the domain of the result attribute if it already exists. */
ReadAttributePtr result_attribute = component.attribute_try_get_for_read(attribute_name);
ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(attribute_name);
if (result_attribute) {
return result_attribute->domain();
return result_attribute.domain;
}
return ATTR_DOMAIN_POINT;
}
@@ -93,7 +93,7 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
get_result_domain(component, attribute_name) :
domain;
OutputAttributePtr attribute = component.attribute_try_get_for_output(
OutputAttribute attribute = component.attribute_try_get_for_output_only(
attribute_name, result_domain, data_type);
if (!attribute) {
return;
@@ -102,38 +102,34 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
switch (data_type) {
case CD_PROP_FLOAT: {
const float value = params.get_input<float>("Value_001");
MutableSpan<float> attribute_span = attribute->get_span_for_write_only<float>();
attribute_span.fill(value);
attribute->fill(&value);
break;
}
case CD_PROP_FLOAT3: {
const float3 value = params.get_input<float3>("Value");
MutableSpan<float3> attribute_span = attribute->get_span_for_write_only<float3>();
attribute_span.fill(value);
attribute->fill(&value);
break;
}
case CD_PROP_COLOR: {
const Color4f value = params.get_input<Color4f>("Value_002");
MutableSpan<Color4f> attribute_span = attribute->get_span_for_write_only<Color4f>();
attribute_span.fill(value);
attribute->fill(&value);
break;
}
case CD_PROP_BOOL: {
const bool value = params.get_input<bool>("Value_003");
MutableSpan<bool> attribute_span = attribute->get_span_for_write_only<bool>();
attribute_span.fill(value);
attribute->fill(&value);
break;
}
case CD_PROP_INT32: {
const int value = params.get_input<int>("Value_004");
MutableSpan<int> attribute_span = attribute->get_span_for_write_only<int>();
attribute_span.fill(value);
attribute->fill(&value);
break;
}
default:
break;
}
attribute.apply_span_and_save();
attribute.save();
}
static void geo_node_attribute_fill_exec(GeoNodeExecParams params)

View File

@@ -192,8 +192,8 @@ static float map_smootherstep(const float value,
return min_to + factor_mapped * (max_to - min_to);
}
static void map_range_float(FloatReadAttribute attribute_input,
FloatWriteAttribute attribute_result,
static void map_range_float(const VArray<float> &attribute_input,
MutableSpan<float> results,
const GeoNodeExecParams &params)
{
const bNode &node = params.node();
@@ -204,32 +204,31 @@ static void map_range_float(FloatReadAttribute attribute_input,
const float min_to = params.get_input<float>("To Min");
const float max_to = params.get_input<float>("To Max");
Span<float> span = attribute_input.get_span();
MutableSpan<float> result_span = attribute_result.get_span();
VArray_Span<float> span{attribute_input};
switch (interpolation_type) {
case NODE_MAP_RANGE_LINEAR: {
for (int i : span.index_range()) {
result_span[i] = map_linear(span[i], min_from, max_from, min_to, max_to);
results[i] = map_linear(span[i], min_from, max_from, min_to, max_to);
}
break;
}
case NODE_MAP_RANGE_STEPPED: {
const float steps = params.get_input<float>("Steps");
for (int i : span.index_range()) {
result_span[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps);
results[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps);
}
break;
}
case NODE_MAP_RANGE_SMOOTHSTEP: {
for (int i : span.index_range()) {
result_span[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to);
results[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to);
}
break;
}
case NODE_MAP_RANGE_SMOOTHERSTEP: {
for (int i : span.index_range()) {
result_span[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to);
results[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to);
}
break;
}
@@ -241,14 +240,14 @@ static void map_range_float(FloatReadAttribute attribute_input,
const float clamp_min = min_to < max_to ? min_to : max_to;
const float clamp_max = min_to < max_to ? max_to : min_to;
for (int i : result_span.index_range()) {
result_span[i] = std::clamp(result_span[i], clamp_min, clamp_max);
for (int i : results.index_range()) {
results[i] = std::clamp(results[i], clamp_min, clamp_max);
}
}
}
static void map_range_float3(Float3ReadAttribute attribute_input,
Float3WriteAttribute attribute_result,
static void map_range_float3(const VArray<float3> &attribute_input,
const MutableSpan<float3> results,
const GeoNodeExecParams &params)
{
const bNode &node = params.node();
@@ -259,43 +258,39 @@ static void map_range_float3(Float3ReadAttribute attribute_input,
const float3 min_to = params.get_input<float3>("To Min_001");
const float3 max_to = params.get_input<float3>("To Max_001");
Span<float3> span = attribute_input.get_span();
MutableSpan<float3> result_span = attribute_result.get_span();
VArray_Span<float3> span{attribute_input};
switch (interpolation_type) {
case NODE_MAP_RANGE_LINEAR: {
for (int i : span.index_range()) {
result_span[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
result_span[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
result_span[i].z = map_linear(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
results[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
results[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
results[i].z = map_linear(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
}
break;
}
case NODE_MAP_RANGE_STEPPED: {
const float3 steps = params.get_input<float3>("Steps_001");
for (int i : span.index_range()) {
result_span[i].x = map_stepped(
span[i].x, min_from.x, max_from.x, min_to.x, max_to.x, steps.x);
result_span[i].y = map_stepped(
span[i].y, min_from.y, max_from.y, min_to.y, max_to.y, steps.y);
result_span[i].z = map_stepped(
span[i].z, min_from.z, max_from.z, min_to.z, max_to.z, steps.z);
results[i].x = map_stepped(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x, steps.x);
results[i].y = map_stepped(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y, steps.y);
results[i].z = map_stepped(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z, steps.z);
}
break;
}
case NODE_MAP_RANGE_SMOOTHSTEP: {
for (int i : span.index_range()) {
result_span[i].x = map_smoothstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
result_span[i].y = map_smoothstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
result_span[i].z = map_smoothstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
results[i].x = map_smoothstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
results[i].y = map_smoothstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
results[i].z = map_smoothstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
}
break;
}
case NODE_MAP_RANGE_SMOOTHERSTEP: {
for (int i : span.index_range()) {
result_span[i].x = map_smootherstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
result_span[i].y = map_smootherstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
result_span[i].z = map_smootherstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
results[i].x = map_smootherstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
results[i].y = map_smootherstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
results[i].z = map_smootherstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
}
break;
}
@@ -313,8 +308,8 @@ static void map_range_float3(Float3ReadAttribute attribute_input,
clamp_min.z = min_to.z < max_to.z ? min_to.z : max_to.z;
clamp_max.z = min_to.z < max_to.z ? max_to.z : min_to.z;
for (int i : result_span.index_range()) {
clamp_v3_v3v3(result_span[i], clamp_min, clamp_max);
for (int i : results.index_range()) {
clamp_v3_v3v3(results[i], clamp_min, clamp_max);
}
}
}
@@ -323,13 +318,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef source_name,
StringRef result_name)
{
ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
return result_attribute->domain();
return result_attribute.domain;
}
ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name);
ReadAttributeLookup source_attribute = component.attribute_try_get_for_read(source_name);
if (source_attribute) {
return source_attribute->domain();
return source_attribute.domain;
}
return ATTR_DOMAIN_POINT;
}
@@ -349,7 +344,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
const AttributeDomain domain = get_result_domain(component, input_name, result_name);
ReadAttributePtr attribute_input = component.attribute_try_get_for_read(
std::unique_ptr<GVArray> attribute_input = component.attribute_try_get_for_read(
input_name, domain, data_type);
if (!attribute_input) {
@@ -358,7 +353,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
return;
}
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, domain, data_type);
if (!attribute_result) {
params.error_message_add(NodeWarningType::Error,
@@ -369,18 +364,19 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
switch (data_type) {
case CD_PROP_FLOAT: {
map_range_float(*attribute_input, *attribute_result, params);
map_range_float(attribute_input->typed<float>(), attribute_result.as_span<float>(), params);
break;
}
case CD_PROP_FLOAT3: {
map_range_float3(*attribute_input, *attribute_result, params);
map_range_float3(
attribute_input->typed<float3>(), attribute_result.as_span<float3>(), params);
break;
}
default:
BLI_assert_unreachable();
}
attribute_result.apply_span_and_save();
attribute_result.save();
}
static void geo_node_attribute_map_range_exec(GeoNodeExecParams params)

View File

@@ -149,9 +149,9 @@ static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node
operation_use_input_c(operation));
}
static void do_math_operation(Span<float> span_a,
Span<float> span_b,
Span<float> span_c,
static void do_math_operation(const VArray<float> &span_a,
const VArray<float> &span_b,
const VArray<float> &span_c,
MutableSpan<float> span_result,
const NodeMathOperation operation)
{
@@ -165,8 +165,8 @@ static void do_math_operation(Span<float> span_a,
UNUSED_VARS_NDEBUG(success);
}
static void do_math_operation(Span<float> span_a,
Span<float> span_b,
static void do_math_operation(const VArray<float> &span_a,
const VArray<float> &span_b,
MutableSpan<float> span_result,
const NodeMathOperation operation)
{
@@ -180,7 +180,7 @@ static void do_math_operation(Span<float> span_a,
UNUSED_VARS_NDEBUG(success);
}
static void do_math_operation(Span<float> span_input,
static void do_math_operation(const VArray<float> &span_input,
MutableSpan<float> span_result,
const NodeMathOperation operation)
{
@@ -200,9 +200,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
return result_attribute->domain();
return result_attribute.domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -224,56 +224,39 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
const std::string result_name = params.get_input<std::string>("Result");
/* The result type of this node is always float. */
const CustomDataType result_type = CD_PROP_FLOAT;
const AttributeDomain result_domain = get_result_domain(
component, params, operation, result_name);
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
OutputAttribute_Typed<float> attribute_result =
component.attribute_try_get_for_output_only<float>(result_name, result_domain);
if (!attribute_result) {
return;
}
ReadAttributePtr attribute_a = params.get_input_attribute(
"A", component, result_domain, result_type, nullptr);
if (!attribute_a) {
return;
}
GVArray_Typed<float> attribute_a = params.get_input_attribute<float>(
"A", component, result_domain, 0.0f);
/* Note that passing the data with `get_span<float>()` works
MutableSpan<float> result_span = attribute_result.as_span();
/* Note that passing the data with `get_internal_span<float>()` works
* because the attributes were accessed with #CD_PROP_FLOAT. */
if (operation_use_input_b(operation)) {
ReadAttributePtr attribute_b = params.get_input_attribute(
"B", component, result_domain, result_type, nullptr);
if (!attribute_b) {
return;
}
GVArray_Typed<float> attribute_b = params.get_input_attribute<float>(
"B", component, result_domain, 0.0f);
if (operation_use_input_c(operation)) {
ReadAttributePtr attribute_c = params.get_input_attribute(
"C", component, result_domain, result_type, nullptr);
if (!attribute_c) {
return;
}
do_math_operation(attribute_a->get_span<float>(),
attribute_b->get_span<float>(),
attribute_c->get_span<float>(),
attribute_result->get_span_for_write_only<float>(),
operation);
GVArray_Typed<float> attribute_c = params.get_input_attribute<float>(
"C", component, result_domain, 0.0f);
do_math_operation(attribute_a, attribute_b, attribute_c, result_span, operation);
}
else {
do_math_operation(attribute_a->get_span<float>(),
attribute_b->get_span<float>(),
attribute_result->get_span_for_write_only<float>(),
operation);
do_math_operation(attribute_a, attribute_b, result_span, operation);
}
}
else {
do_math_operation(attribute_a->get_span<float>(),
attribute_result->get_span_for_write_only<float>(),
operation);
do_math_operation(attribute_a, result_span, operation);
}
attribute_result.apply_span_and_save();
attribute_result.save();
}
static void geo_node_attribute_math_exec(GeoNodeExecParams params)

View File

@@ -58,10 +58,10 @@ static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C),
namespace blender::nodes {
static void do_mix_operation_float(const int blend_mode,
const FloatReadAttribute &factors,
const FloatReadAttribute &inputs_a,
const FloatReadAttribute &inputs_b,
FloatWriteAttribute results)
const VArray<float> &factors,
const VArray<float> &inputs_a,
const VArray<float> &inputs_b,
VMutableArray<float> &results)
{
const int size = results.size();
for (const int i : IndexRange(size)) {
@@ -75,10 +75,10 @@ static void do_mix_operation_float(const int blend_mode,
}
static void do_mix_operation_float3(const int blend_mode,
const FloatReadAttribute &factors,
const Float3ReadAttribute &inputs_a,
const Float3ReadAttribute &inputs_b,
Float3WriteAttribute results)
const VArray<float> &factors,
const VArray<float3> &inputs_a,
const VArray<float3> &inputs_b,
VMutableArray<float3> &results)
{
const int size = results.size();
for (const int i : IndexRange(size)) {
@@ -91,10 +91,10 @@ static void do_mix_operation_float3(const int blend_mode,
}
static void do_mix_operation_color4f(const int blend_mode,
const FloatReadAttribute &factors,
const Color4fReadAttribute &inputs_a,
const Color4fReadAttribute &inputs_b,
Color4fWriteAttribute results)
const VArray<float> &factors,
const VArray<Color4f> &inputs_a,
const VArray<Color4f> &inputs_b,
VMutableArray<Color4f> &results)
{
const int size = results.size();
for (const int i : IndexRange(size)) {
@@ -108,22 +108,31 @@ static void do_mix_operation_color4f(const int blend_mode,
static void do_mix_operation(const CustomDataType result_type,
int blend_mode,
const FloatReadAttribute &attribute_factor,
const ReadAttribute &attribute_a,
const ReadAttribute &attribute_b,
WriteAttribute &attribute_result)
const VArray<float> &attribute_factor,
const GVArray &attribute_a,
const GVArray &attribute_b,
GVMutableArray &attribute_result)
{
if (result_type == CD_PROP_FLOAT) {
do_mix_operation_float(
blend_mode, attribute_factor, attribute_a, attribute_b, attribute_result);
do_mix_operation_float(blend_mode,
attribute_factor,
attribute_a.typed<float>(),
attribute_b.typed<float>(),
attribute_result.typed<float>());
}
else if (result_type == CD_PROP_FLOAT3) {
do_mix_operation_float3(
blend_mode, attribute_factor, attribute_a, attribute_b, attribute_result);
do_mix_operation_float3(blend_mode,
attribute_factor,
attribute_a.typed<float3>(),
attribute_b.typed<float3>(),
attribute_result.typed<float3>());
}
else if (result_type == CD_PROP_COLOR) {
do_mix_operation_color4f(
blend_mode, attribute_factor, attribute_a, attribute_b, attribute_result);
do_mix_operation_color4f(blend_mode,
attribute_factor,
attribute_a.typed<Color4f>(),
attribute_b.typed<Color4f>(),
attribute_result.typed<Color4f>());
}
}
@@ -132,9 +141,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
return result_attribute->domain();
return result_attribute.domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -158,17 +167,17 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa
const AttributeDomain result_domain = get_result_domain(component, params, result_name);
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
}
FloatReadAttribute attribute_factor = params.get_input_attribute<float>(
GVArray_Typed<float> attribute_factor = params.get_input_attribute<float>(
"Factor", component, result_domain, 0.5f);
ReadAttributePtr attribute_a = params.get_input_attribute(
std::unique_ptr<GVArray> attribute_a = params.get_input_attribute(
"A", component, result_domain, result_type, nullptr);
ReadAttributePtr attribute_b = params.get_input_attribute(
std::unique_ptr<GVArray> attribute_b = params.get_input_attribute(
"B", component, result_domain, result_type, nullptr);
do_mix_operation(result_type,

View File

@@ -62,7 +62,7 @@ namespace blender::nodes {
static void proximity_calc(MutableSpan<float> distance_span,
MutableSpan<float3> location_span,
Span<float3> positions,
const VArray<float3> &positions,
BVHTreeFromMesh &tree_data_mesh,
BVHTreeFromPointCloud &tree_data_pointcloud,
const bool bvh_mesh_success,
@@ -169,19 +169,18 @@ static void attribute_calc_proximity(GeometryComponent &component,
const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
const std::string distance_attribute_name = params.get_input<std::string>("Distance");
OutputAttributePtr distance_attribute = component.attribute_try_get_for_output(
distance_attribute_name, result_domain, CD_PROP_FLOAT);
OutputAttribute_Typed<float> distance_attribute =
component.attribute_try_get_for_output_only<float>(distance_attribute_name, result_domain);
const std::string location_attribute_name = params.get_input<std::string>("Position");
OutputAttributePtr location_attribute = component.attribute_try_get_for_output(
location_attribute_name, result_domain, CD_PROP_FLOAT3);
ReadAttributePtr position_attribute = component.attribute_try_get_for_read("position");
BLI_assert(position_attribute->custom_data_type() == CD_PROP_FLOAT3);
OutputAttribute_Typed<float3> location_attribute =
component.attribute_try_get_for_output_only<float3>(location_attribute_name, result_domain);
ReadAttributeLookup position_attribute = component.attribute_try_get_for_read("position");
if (!position_attribute || (!distance_attribute && !location_attribute)) {
return;
}
BLI_assert(position_attribute.varray->type().is<float3>());
const bNode &node = params.node();
const NodeGeometryAttributeProximity &storage = *(const NodeGeometryAttributeProximity *)
@@ -204,18 +203,15 @@ static void attribute_calc_proximity(GeometryComponent &component,
tree_data_pointcloud);
}
Span<float3> position_span = position_attribute->get_span<float3>();
MutableSpan<float> distance_span = distance_attribute ?
distance_attribute->get_span_for_write_only<float>() :
MutableSpan<float>();
MutableSpan<float3> location_span = location_attribute ?
location_attribute->get_span_for_write_only<float3>() :
MutableSpan<float3>();
GVArray_Typed<float3> positions{*position_attribute.varray};
MutableSpan<float> distance_span = distance_attribute ? distance_attribute.as_span() :
MutableSpan<float>();
MutableSpan<float3> location_span = location_attribute ? location_attribute.as_span() :
MutableSpan<float3>();
proximity_calc(distance_span,
location_span,
position_span,
positions,
tree_data_mesh,
tree_data_pointcloud,
bvh_mesh_success,
@@ -231,10 +227,10 @@ static void attribute_calc_proximity(GeometryComponent &component,
}
if (distance_attribute) {
distance_attribute.apply_span_and_save();
distance_attribute.save();
}
if (location_attribute) {
location_attribute.apply_span_and_save();
location_attribute.save();
}
}

View File

@@ -173,12 +173,12 @@ Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &compo
const int domain_size = component.attribute_domain_size(domain);
/* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */
ReadAttributePtr hash_attribute = component.attribute_try_get_for_read("id", domain);
std::unique_ptr<GVArray> hash_attribute = component.attribute_try_get_for_read("id", domain);
Array<uint32_t> hashes(domain_size);
if (hash_attribute) {
BLI_assert(hashes.size() == hash_attribute->size());
const CPPType &cpp_type = hash_attribute->cpp_type();
fn::GSpan items = hash_attribute->get_span();
const CPPType &cpp_type = hash_attribute->type();
GVArray_GSpan items{*hash_attribute};
for (const int i : hashes.index_range()) {
hashes[i] = cpp_type.hash(items[i]);
}
@@ -199,9 +199,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef attribute_name)
{
/* Use the domain of the result attribute if it already exists. */
ReadAttributePtr result_attribute = component.attribute_try_get_for_read(attribute_name);
ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(attribute_name);
if (result_attribute) {
return result_attribute->domain();
return result_attribute.domain;
}
/* Otherwise use the input domain chosen in the interface. */
@@ -228,15 +228,13 @@ static void randomize_attribute_on_component(GeometryComponent &component,
const AttributeDomain domain = get_result_domain(component, params, attribute_name);
OutputAttributePtr attribute = component.attribute_try_get_for_output(
OutputAttribute attribute = component.attribute_try_get_for_output(
attribute_name, domain, data_type);
if (!attribute) {
return;
}
fn::GMutableSpan span = (operation == GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE) ?
attribute->get_span_for_write_only() :
attribute->get_span();
GMutableSpan span = attribute.as_span();
Array<uint32_t> hashes = get_geometry_element_ids_as_uints(component, domain);
@@ -269,8 +267,8 @@ static void randomize_attribute_on_component(GeometryComponent &component,
}
}
attribute.apply_span_and_save();
} // namespace blender::nodes
attribute.save();
}
static void geo_node_random_attribute_exec(GeoNodeExecParams params)
{

View File

@@ -53,15 +53,16 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef map_attribute_name)
{
/* Use the domain of the result attribute if it already exists. */
ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_attribute_name);
ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(
result_attribute_name);
if (result_attribute) {
return result_attribute->domain();
return result_attribute.domain;
}
/* Otherwise use the name of the map attribute. */
ReadAttributePtr map_attribute = component.attribute_try_get_for_read(map_attribute_name);
ReadAttributeLookup map_attribute = component.attribute_try_get_for_read(map_attribute_name);
if (map_attribute) {
return map_attribute->domain();
return map_attribute.domain;
}
/* The node won't execute in this case, but we still have to return a value. */
@@ -85,16 +86,16 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
const AttributeDomain result_domain = get_result_domain(
component, result_attribute_name, mapping_name);
OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
result_attribute_name, result_domain, CD_PROP_COLOR);
OutputAttribute_Typed<Color4f> attribute_out =
component.attribute_try_get_for_output_only<Color4f>(result_attribute_name, result_domain);
if (!attribute_out) {
return;
}
Float3ReadAttribute mapping_attribute = component.attribute_get_for_read<float3>(
GVArray_Typed<float3> mapping_attribute = component.attribute_get_for_read<float3>(
mapping_name, result_domain, {0, 0, 0});
MutableSpan<Color4f> colors = attribute_out->get_span<Color4f>();
MutableSpan<Color4f> colors = attribute_out.as_span();
for (const int i : IndexRange(mapping_attribute.size())) {
TexResult texture_result = {0};
const float3 position = mapping_attribute[i];
@@ -103,7 +104,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
BKE_texture_get_value(nullptr, texture, remapped_position, &texture_result, false);
colors[i] = {texture_result.tr, texture_result.tg, texture_result.tb, texture_result.ta};
}
attribute_out.apply_span_and_save();
attribute_out.save();
}
static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params)

View File

@@ -77,17 +77,17 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
{
/* Use the highest priority domain from any existing attribute outputs. */
Vector<AttributeDomain, 3> output_domains;
ReadAttributePtr attribute_x = component.attribute_try_get_for_read(result_name_x);
ReadAttributePtr attribute_y = component.attribute_try_get_for_read(result_name_y);
ReadAttributePtr attribute_z = component.attribute_try_get_for_read(result_name_z);
ReadAttributeLookup attribute_x = component.attribute_try_get_for_read(result_name_x);
ReadAttributeLookup attribute_y = component.attribute_try_get_for_read(result_name_y);
ReadAttributeLookup attribute_z = component.attribute_try_get_for_read(result_name_z);
if (attribute_x) {
output_domains.append(attribute_x->domain());
output_domains.append(attribute_x.domain);
}
if (attribute_y) {
output_domains.append(attribute_y->domain());
output_domains.append(attribute_y.domain);
}
if (attribute_z) {
output_domains.append(attribute_z->domain());
output_domains.append(attribute_z.domain);
}
if (output_domains.size() > 0) {
return bke::attribute_domain_highest_priority(output_domains);
@@ -107,37 +107,32 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa
}
/* The node is only for float3 to float conversions. */
const CustomDataType input_type = CD_PROP_FLOAT3;
const CustomDataType result_type = CD_PROP_FLOAT;
const AttributeDomain result_domain = get_result_domain(
component, params, result_name_x, result_name_y, result_name_z);
ReadAttributePtr attribute_input = params.get_input_attribute(
"Vector", component, result_domain, input_type, nullptr);
if (!attribute_input) {
return;
}
const Span<float3> input_span = attribute_input->get_span<float3>();
GVArray_Typed<float3> attribute_input = params.get_input_attribute<float3>(
"Vector", component, result_domain, {0, 0, 0});
VArray_Span<float3> input_span{*attribute_input};
OutputAttributePtr attribute_result_x = component.attribute_try_get_for_output(
result_name_x, result_domain, result_type);
OutputAttributePtr attribute_result_y = component.attribute_try_get_for_output(
result_name_y, result_domain, result_type);
OutputAttributePtr attribute_result_z = component.attribute_try_get_for_output(
result_name_z, result_domain, result_type);
OutputAttribute_Typed<float> attribute_result_x =
component.attribute_try_get_for_output_only<float>(result_name_x, result_domain);
OutputAttribute_Typed<float> attribute_result_y =
component.attribute_try_get_for_output_only<float>(result_name_y, result_domain);
OutputAttribute_Typed<float> attribute_result_z =
component.attribute_try_get_for_output_only<float>(result_name_z, result_domain);
/* Only extract the components for the outputs with a given attribute. */
if (attribute_result_x) {
extract_input(0, input_span, attribute_result_x->get_span_for_write_only<float>());
attribute_result_x.apply_span_and_save();
extract_input(0, input_span, attribute_result_x.as_span());
attribute_result_x.save();
}
if (attribute_result_y) {
extract_input(1, input_span, attribute_result_y->get_span_for_write_only<float>());
attribute_result_y.apply_span_and_save();
extract_input(1, input_span, attribute_result_y.as_span());
attribute_result_y.save();
}
if (attribute_result_z) {
extract_input(2, input_span, attribute_result_z->get_span_for_write_only<float>());
attribute_result_z.apply_span_and_save();
extract_input(2, input_span, attribute_result_z.as_span());
attribute_result_z.save();
}
}

View File

@@ -168,16 +168,16 @@ static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNod
operation_use_input_c(operation));
}
static void do_math_operation_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a,
const Float3ReadAttribute &input_b,
Float3WriteAttribute result,
static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a,
const VArray<float3> &input_b,
VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
Span<float3> span_a = input_a.get_span();
Span<float3> span_b = input_b.get_span();
MutableSpan<float3> span_result = result.get_span_for_write_only();
VArray_Span<float3> span_a{input_a};
VArray_Span<float3> span_b{input_b};
VMutableArray_Span<float3> span_result{result, false};
bool success = try_dispatch_float_math_fl3_fl3_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -189,25 +189,25 @@ static void do_math_operation_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a,
}
});
result.apply_span();
span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
static void do_math_operation_fl3_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a,
const Float3ReadAttribute &input_b,
const Float3ReadAttribute &input_c,
Float3WriteAttribute result,
static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a,
const VArray<float3> &input_b,
const VArray<float3> &input_c,
VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
Span<float3> span_a = input_a.get_span();
Span<float3> span_b = input_b.get_span();
Span<float3> span_c = input_c.get_span();
MutableSpan<float3> span_result = result.get_span_for_write_only();
VArray_Span<float3> span_a{input_a};
VArray_Span<float3> span_b{input_b};
VArray_Span<float3> span_c{input_c};
VMutableArray_Span<float3> span_result{result};
bool success = try_dispatch_float_math_fl3_fl3_fl3_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -220,25 +220,25 @@ static void do_math_operation_fl3_fl3_fl3_to_fl3(const Float3ReadAttribute &inpu
}
});
result.apply_span();
span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
static void do_math_operation_fl3_fl3_fl_to_fl3(const Float3ReadAttribute &input_a,
const Float3ReadAttribute &input_b,
const FloatReadAttribute &input_c,
Float3WriteAttribute result,
static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a,
const VArray<float3> &input_b,
const VArray<float> &input_c,
VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
Span<float3> span_a = input_a.get_span();
Span<float3> span_b = input_b.get_span();
Span<float> span_c = input_c.get_span();
MutableSpan<float3> span_result = result.get_span_for_write_only();
VArray_Span<float3> span_a{input_a};
VArray_Span<float3> span_b{input_b};
VArray_Span<float> span_c{input_c};
VMutableArray_Span<float3> span_result{result, false};
bool success = try_dispatch_float_math_fl3_fl3_fl_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -251,23 +251,23 @@ static void do_math_operation_fl3_fl3_fl_to_fl3(const Float3ReadAttribute &input
}
});
result.apply_span();
span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
static void do_math_operation_fl3_fl3_to_fl(const Float3ReadAttribute &input_a,
const Float3ReadAttribute &input_b,
FloatWriteAttribute result,
static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a,
const VArray<float3> &input_b,
VMutableArray<float> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
Span<float3> span_a = input_a.get_span();
Span<float3> span_b = input_b.get_span();
MutableSpan<float> span_result = result.get_span_for_write_only();
VArray_Span<float3> span_a{input_a};
VArray_Span<float3> span_b{input_b};
VMutableArray_Span<float> span_result{result, false};
bool success = try_dispatch_float_math_fl3_fl3_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -279,23 +279,23 @@ static void do_math_operation_fl3_fl3_to_fl(const Float3ReadAttribute &input_a,
}
});
result.apply_span();
span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
static void do_math_operation_fl3_fl_to_fl3(const Float3ReadAttribute &input_a,
const FloatReadAttribute &input_b,
Float3WriteAttribute result,
static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a,
const VArray<float> &input_b,
VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
Span<float3> span_a = input_a.get_span();
Span<float> span_b = input_b.get_span();
MutableSpan<float3> span_result = result.get_span_for_write_only();
VArray_Span<float3> span_a{input_a};
VArray_Span<float> span_b{input_b};
VMutableArray_Span<float3> span_result{result, false};
bool success = try_dispatch_float_math_fl3_fl_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -307,21 +307,21 @@ static void do_math_operation_fl3_fl_to_fl3(const Float3ReadAttribute &input_a,
}
});
result.apply_span();
span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
static void do_math_operation_fl3_to_fl3(const Float3ReadAttribute &input_a,
Float3WriteAttribute result,
static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a,
VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
Span<float3> span_a = input_a.get_span();
MutableSpan<float3> span_result = result.get_span_for_write_only();
VArray_Span<float3> span_a{input_a};
VMutableArray_Span<float3> span_result{result, false};
bool success = try_dispatch_float_math_fl3_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -332,21 +332,21 @@ static void do_math_operation_fl3_to_fl3(const Float3ReadAttribute &input_a,
}
});
result.apply_span();
span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
static void do_math_operation_fl3_to_fl(const Float3ReadAttribute &input_a,
FloatWriteAttribute result,
static void do_math_operation_fl3_to_fl(const VArray<float3> &input_a,
VMutableArray<float> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
Span<float3> span_a = input_a.get_span();
MutableSpan<float> span_result = result.get_span_for_write_only();
VArray_Span<float3> span_a{input_a};
VMutableArray_Span<float> span_result{result, false};
bool success = try_dispatch_float_math_fl3_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -357,7 +357,7 @@ static void do_math_operation_fl3_to_fl(const Float3ReadAttribute &input_a,
}
});
result.apply_span();
span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
@@ -370,9 +370,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
return result_attribute->domain();
return result_attribute.domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -406,13 +406,13 @@ static void attribute_vector_math_calc(GeometryComponent &component,
const AttributeDomain result_domain = get_result_domain(
component, params, operation, result_name);
ReadAttributePtr attribute_a = params.get_input_attribute(
std::unique_ptr<GVArray> attribute_a = params.get_input_attribute(
"A", component, result_domain, read_type_a, nullptr);
if (!attribute_a) {
return;
}
ReadAttributePtr attribute_b;
ReadAttributePtr attribute_c;
std::unique_ptr<GVArray> attribute_b;
std::unique_ptr<GVArray> attribute_c;
if (use_input_b) {
attribute_b = params.get_input_attribute("B", component, result_domain, read_type_b, nullptr);
if (!attribute_b) {
@@ -427,7 +427,7 @@ static void attribute_vector_math_calc(GeometryComponent &component,
}
/* Get result attribute first, in case it has to overwrite one of the existing attributes. */
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
@@ -445,17 +445,27 @@ static void attribute_vector_math_calc(GeometryComponent &component,
case NODE_VECTOR_MATH_MODULO:
case NODE_VECTOR_MATH_MINIMUM:
case NODE_VECTOR_MATH_MAXIMUM:
do_math_operation_fl3_fl3_to_fl3(*attribute_a, *attribute_b, *attribute_result, operation);
do_math_operation_fl3_fl3_to_fl3(attribute_a->typed<float3>(),
attribute_b->typed<float3>(),
attribute_result->typed<float3>(),
operation);
break;
case NODE_VECTOR_MATH_DOT_PRODUCT:
case NODE_VECTOR_MATH_DISTANCE:
do_math_operation_fl3_fl3_to_fl(*attribute_a, *attribute_b, *attribute_result, operation);
do_math_operation_fl3_fl3_to_fl(attribute_a->typed<float3>(),
attribute_b->typed<float3>(),
attribute_result->typed<float>(),
operation);
break;
case NODE_VECTOR_MATH_LENGTH:
do_math_operation_fl3_to_fl(*attribute_a, *attribute_result, operation);
do_math_operation_fl3_to_fl(
attribute_a->typed<float3>(), attribute_result->typed<float>(), operation);
break;
case NODE_VECTOR_MATH_SCALE:
do_math_operation_fl3_fl_to_fl3(*attribute_a, *attribute_b, *attribute_result, operation);
do_math_operation_fl3_fl_to_fl3(attribute_a->typed<float3>(),
attribute_b->typed<float>(),
attribute_result->typed<float3>(),
operation);
break;
case NODE_VECTOR_MATH_NORMALIZE:
case NODE_VECTOR_MATH_FLOOR:
@@ -465,16 +475,23 @@ static void attribute_vector_math_calc(GeometryComponent &component,
case NODE_VECTOR_MATH_SINE:
case NODE_VECTOR_MATH_COSINE:
case NODE_VECTOR_MATH_TANGENT:
do_math_operation_fl3_to_fl3(*attribute_a, *attribute_result, operation);
do_math_operation_fl3_to_fl3(
attribute_a->typed<float3>(), attribute_result->typed<float3>(), operation);
break;
case NODE_VECTOR_MATH_WRAP:
case NODE_VECTOR_MATH_FACEFORWARD:
do_math_operation_fl3_fl3_fl3_to_fl3(
*attribute_a, *attribute_b, *attribute_c, *attribute_result, operation);
do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a->typed<float3>(),
attribute_b->typed<float3>(),
attribute_c->typed<float3>(),
attribute_result->typed<float3>(),
operation);
break;
case NODE_VECTOR_MATH_REFRACT:
do_math_operation_fl3_fl3_fl_to_fl3(
*attribute_a, *attribute_b, *attribute_c, *attribute_result, operation);
do_math_operation_fl3_fl3_fl_to_fl3(attribute_a->typed<float3>(),
attribute_b->typed<float3>(),
attribute_c->typed<float>(),
attribute_result->typed<float3>(),
operation);
break;
}
attribute_result.save();

View File

@@ -39,15 +39,12 @@ static void compute_min_max_from_position_and_transform(const GeometryComponent
float3 &r_min,
float3 &r_max)
{
ReadAttributePtr position_attribute = component.attribute_try_get_for_read("position");
if (!position_attribute) {
BLI_assert(component.attribute_domain_size(ATTR_DOMAIN_POINT) == 0);
return;
}
Span<float3> positions = position_attribute->get_span<float3>();
GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
for (const float4x4 &transform : transforms) {
for (const float3 &position : positions) {
for (const int i : positions.index_range()) {
const float3 position = positions[i];
const float3 transformed_position = transform * position;
minmax_v3v3_v3(r_min, r_max, transformed_position);
}

View File

@@ -149,10 +149,10 @@ static void determine_final_data_type_and_domain(Span<const GeometryComponent *>
Vector<CustomDataType> data_types;
Vector<AttributeDomain> domains;
for (const GeometryComponent *component : components) {
ReadAttributePtr attribute = component->attribute_try_get_for_read(attribute_name);
ReadAttributeLookup attribute = component->attribute_try_get_for_read(attribute_name);
if (attribute) {
data_types.append(attribute->custom_data_type());
domains.append(attribute->domain());
data_types.append(bke::cpp_type_to_custom_data_type(attribute.varray->type()));
domains.append(attribute.domain);
}
}
@@ -164,7 +164,7 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
StringRef attribute_name,
const CustomDataType data_type,
const AttributeDomain domain,
fn::GMutableSpan dst_span)
GMutableSpan dst_span)
{
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
@@ -175,10 +175,10 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
if (domain_size == 0) {
continue;
}
ReadAttributePtr read_attribute = component->attribute_get_for_read(
std::unique_ptr<GVArray> read_attribute = component->attribute_get_for_read(
attribute_name, domain, data_type, nullptr);
fn::GSpan src_span = read_attribute->get_span();
GVArray_GSpan src_span{*read_attribute};
const void *src_buffer = src_span.data();
void *dst_buffer = dst_span[offset];
cpp_type->copy_to_initialized_n(src_buffer, dst_buffer, domain_size);
@@ -201,16 +201,14 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
AttributeDomain domain;
determine_final_data_type_and_domain(src_components, attribute_name, &data_type, &domain);
OutputAttributePtr write_attribute = result.attribute_try_get_for_output(
OutputAttribute write_attribute = result.attribute_try_get_for_output_only(
attribute_name, domain, data_type);
if (!write_attribute ||
&write_attribute->cpp_type() != bke::custom_data_type_to_cpp_type(data_type) ||
write_attribute->domain() != domain) {
if (!write_attribute) {
continue;
}
fn::GMutableSpan dst_span = write_attribute->get_span_for_write_only();
GMutableSpan dst_span = write_attribute.as_span();
fill_new_attribute(src_components, attribute_name, data_type, domain, dst_span);
write_attribute.apply_span_and_save();
write_attribute.save();
}
}

View File

@@ -194,9 +194,9 @@ static void calculate_uvs(Mesh *mesh,
{
MeshComponent mesh_component;
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
"uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
OutputAttribute_Typed<float2> uv_attribute =
mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
MutableSpan<float2> uvs = uv_attribute.as_span();
Array<float2> circle(verts_num);
float angle = 0.0f;
@@ -271,7 +271,7 @@ static void calculate_uvs(Mesh *mesh,
}
}
uv_attribute.apply_span_and_save();
uv_attribute.save();
}
Mesh *create_cylinder_or_cone_mesh(const float radius_top,

View File

@@ -44,9 +44,9 @@ static void calculate_uvs(
{
MeshComponent mesh_component;
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
"uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
OutputAttribute_Typed<float2> uv_attribute =
mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
MutableSpan<float2> uvs = uv_attribute.as_span();
const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x;
const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y;
@@ -56,7 +56,7 @@ static void calculate_uvs(
uvs[i].y = (co.y + size_y * 0.5f) * dy;
}
uv_attribute.apply_span_and_save();
uv_attribute.save();
}
static Mesh *create_grid_mesh(const int verts_x,

View File

@@ -224,9 +224,9 @@ static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float r
{
MeshComponent mesh_component;
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
"uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
OutputAttribute_Typed<float2> uv_attribute =
mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
MutableSpan<float2> uvs = uv_attribute.as_span();
int loop_index = 0;
const float dy = 1.0f / rings;
@@ -256,7 +256,7 @@ static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float r
uvs[loop_index++] = float2(segment / segments, 1.0f - dy);
}
uv_attribute.apply_span_and_save();
uv_attribute.save();
}
static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const int rings)

View File

@@ -91,7 +91,7 @@ static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
static void sample_mesh_surface(const Mesh &mesh,
const float4x4 &transform,
const float base_density,
const FloatReadAttribute *density_factors,
const VArray<float> *density_factors,
const int seed,
Vector<float3> &r_positions,
Vector<float3> &r_bary_coords,
@@ -113,9 +113,9 @@ static void sample_mesh_surface(const Mesh &mesh,
float looptri_density_factor = 1.0f;
if (density_factors != nullptr) {
const float v0_density_factor = std::max(0.0f, (*density_factors)[v0_loop]);
const float v1_density_factor = std::max(0.0f, (*density_factors)[v1_loop]);
const float v2_density_factor = std::max(0.0f, (*density_factors)[v2_loop]);
const float v0_density_factor = std::max(0.0f, density_factors->get(v0_loop));
const float v1_density_factor = std::max(0.0f, density_factors->get(v1_loop));
const float v2_density_factor = std::max(0.0f, density_factors->get(v2_loop));
looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f;
}
const float area = area_tri_v3(v0_pos, v1_pos, v2_pos);
@@ -203,7 +203,7 @@ BLI_NOINLINE static void update_elimination_mask_for_close_points(
BLI_NOINLINE static void update_elimination_mask_based_on_density_factors(
const Mesh &mesh,
const FloatReadAttribute &density_factors,
const VArray<float> &density_factors,
Span<float3> bary_coords,
Span<int> looptri_indices,
MutableSpan<bool> elimination_mask)
@@ -363,13 +363,13 @@ BLI_NOINLINE static void interpolate_existing_attributes(
StringRef attribute_name = entry.key;
const CustomDataType output_data_type = entry.value.data_type;
/* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
OutputAttribute attribute_out = component.attribute_try_get_for_output_only(
attribute_name, ATTR_DOMAIN_POINT, output_data_type);
if (!attribute_out) {
continue;
}
fn::GMutableSpan out_span = attribute_out->get_span_for_write_only();
GMutableSpan out_span = attribute_out.as_span();
int i_instance = 0;
for (const GeometryInstanceGroup &set_group : set_groups) {
@@ -380,44 +380,41 @@ BLI_NOINLINE static void interpolate_existing_attributes(
/* Use a dummy read without specifying a domain or data type in order to
* get the existing attribute's domain. Interpolation is done manually based
* on the bary coords in #interpolate_attribute. */
ReadAttributePtr dummy_attribute = source_component.attribute_try_get_for_read(
ReadAttributeLookup dummy_attribute = source_component.attribute_try_get_for_read(
attribute_name);
if (!dummy_attribute) {
i_instance += set_group.transforms.size();
continue;
}
const AttributeDomain source_domain = dummy_attribute->domain();
ReadAttributePtr source_attribute = source_component.attribute_get_for_read(
const AttributeDomain source_domain = dummy_attribute.domain;
std::unique_ptr<GVArray> source_attribute = source_component.attribute_get_for_read(
attribute_name, source_domain, output_data_type, nullptr);
if (!source_attribute) {
i_instance += set_group.transforms.size();
continue;
}
fn::GSpan source_span = source_attribute->get_span();
attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) {
using T = decltype(dummy);
GVArray_Span<T> source_span{*source_attribute};
for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
const int offset = instance_start_offsets[i_instance];
Span<float3> bary_coords = bary_coords_array[i_instance];
Span<int> looptri_indices = looptri_indices_array[i_instance];
MutableSpan<T> instance_span = out_span.typed<T>().slice(offset, bary_coords.size());
interpolate_attribute<T>(mesh,
bary_coords,
looptri_indices,
source_domain,
source_span.typed<T>(),
instance_span);
interpolate_attribute<T>(
mesh, bary_coords, looptri_indices, source_domain, source_span, instance_span);
i_instance++;
}
});
}
attribute_out.apply_span_and_save();
attribute_out.save();
}
}
@@ -427,16 +424,16 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup>
Span<Vector<float3>> bary_coords_array,
Span<Vector<int>> looptri_indices_array)
{
OutputAttributePtr id_attribute = component.attribute_try_get_for_output(
"id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
OutputAttributePtr normal_attribute = component.attribute_try_get_for_output(
"normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
"rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
"id", ATTR_DOMAIN_POINT);
OutputAttribute_Typed<float3> normal_attribute =
component.attribute_try_get_for_output_only<float3>("normal", ATTR_DOMAIN_POINT);
OutputAttribute_Typed<float3> rotation_attribute =
component.attribute_try_get_for_output_only<float3>("rotation", ATTR_DOMAIN_POINT);
MutableSpan<int> result_ids = id_attribute->get_span_for_write_only<int>();
MutableSpan<float3> result_normals = normal_attribute->get_span_for_write_only<float3>();
MutableSpan<float3> result_rotations = rotation_attribute->get_span_for_write_only<float3>();
MutableSpan<int> result_ids = id_attribute.as_span();
MutableSpan<float3> result_normals = normal_attribute.as_span();
MutableSpan<float3> result_rotations = rotation_attribute.as_span();
int i_instance = 0;
for (const GeometryInstanceGroup &set_group : sets) {
@@ -480,9 +477,9 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup>
}
}
id_attribute.apply_span_and_save();
normal_attribute.apply_span_and_save();
rotation_attribute.apply_span_and_save();
id_attribute.save();
normal_attribute.save();
rotation_attribute.save();
}
BLI_NOINLINE static void add_remaining_point_attributes(
@@ -520,7 +517,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups,
for (const GeometryInstanceGroup &set_group : set_groups) {
const GeometrySet &set = set_group.geometry_set;
const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>(
density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
const Mesh &mesh = *component.get_for_read();
for (const float4x4 &transform : set_group.transforms) {
@@ -530,7 +527,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups,
sample_mesh_surface(mesh,
transform,
density,
&density_factors,
&*density_factors,
seed,
positions,
bary_coords,
@@ -589,7 +586,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group
const GeometrySet &set = set_group.geometry_set;
const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
const Mesh &mesh = *component.get_for_read();
const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
const GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>(
density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
@@ -622,7 +619,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
const GeometryNodePointDistributeMode distribute_method =
static_cast<GeometryNodePointDistributeMode>(params.node().custom1);
const int seed = params.get_input<int>("Seed");
const int seed = params.get_input<int>("Seed") * 5383843;
const float density = params.extract_input<float>("Density Max");
const std::string density_attribute_name = params.extract_input<std::string>(
"Density Attribute");

View File

@@ -174,13 +174,13 @@ static void add_instances_from_geometry_component(InstancesComponent &instances,
Array<std::optional<InstancedData>> instances_data = get_instanced_data(
params, src_geometry, domain_size);
Float3ReadAttribute positions = src_geometry.attribute_get_for_read<float3>(
GVArray_Typed<float3> positions = src_geometry.attribute_get_for_read<float3>(
"position", domain, {0, 0, 0});
Float3ReadAttribute rotations = src_geometry.attribute_get_for_read<float3>(
GVArray_Typed<float3> rotations = src_geometry.attribute_get_for_read<float3>(
"rotation", domain, {0, 0, 0});
Float3ReadAttribute scales = src_geometry.attribute_get_for_read<float3>(
GVArray_Typed<float3> scales = src_geometry.attribute_get_for_read<float3>(
"scale", domain, {1, 1, 1});
Int32ReadAttribute ids = src_geometry.attribute_get_for_read<int>("id", domain, -1);
GVArray_Typed<int> ids = src_geometry.attribute_get_for_read<int>("id", domain, -1);
for (const int i : IndexRange(domain_size)) {
if (instances_data[i].has_value()) {

View File

@@ -60,8 +60,8 @@ static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C),
namespace blender::nodes {
static void point_rotate__axis_angle__object_space(const int domain_size,
const Float3ReadAttribute &axis,
const FloatReadAttribute &angles,
const VArray<float3> &axis,
const VArray<float> &angles,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
@@ -76,8 +76,8 @@ static void point_rotate__axis_angle__object_space(const int domain_size,
}
static void point_rotate__axis_angle__point_space(const int domain_size,
const Float3ReadAttribute &axis,
const FloatReadAttribute &angles,
const VArray<float3> &axis,
const VArray<float> &angles,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
@@ -92,7 +92,7 @@ static void point_rotate__axis_angle__point_space(const int domain_size,
}
static void point_rotate__euler__object_space(const int domain_size,
const Float3ReadAttribute &eulers,
const VArray<float3> &eulers,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
@@ -107,7 +107,7 @@ static void point_rotate__euler__object_space(const int domain_size,
}
static void point_rotate__euler__point_space(const int domain_size,
const Float3ReadAttribute &eulers,
const VArray<float3> &eulers,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
@@ -127,19 +127,19 @@ static void point_rotate_on_component(GeometryComponent &component,
const bNode &node = params.node();
const NodeGeometryRotatePoints &storage = *(const NodeGeometryRotatePoints *)node.storage;
OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
"rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
OutputAttribute_Typed<float3> rotation_attribute =
component.attribute_try_get_for_output<float3>("rotation", ATTR_DOMAIN_POINT, {0, 0, 0});
if (!rotation_attribute) {
return;
}
MutableSpan<float3> rotations = rotation_attribute->get_span<float3>();
MutableSpan<float3> rotations = rotation_attribute.as_span();
const int domain_size = rotations.size();
if (storage.type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE) {
Float3ReadAttribute axis = params.get_input_attribute<float3>(
GVArray_Typed<float3> axis = params.get_input_attribute<float3>(
"Axis", component, ATTR_DOMAIN_POINT, {0, 0, 1});
FloatReadAttribute angles = params.get_input_attribute<float>(
GVArray_Typed<float> angles = params.get_input_attribute<float>(
"Angle", component, ATTR_DOMAIN_POINT, 0);
if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) {
@@ -150,7 +150,7 @@ static void point_rotate_on_component(GeometryComponent &component,
}
}
else {
Float3ReadAttribute eulers = params.get_input_attribute<float3>(
GVArray_Typed<float3> eulers = params.get_input_attribute<float3>(
"Rotation", component, ATTR_DOMAIN_POINT, {0, 0, 0});
if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) {
@@ -161,7 +161,7 @@ static void point_rotate_on_component(GeometryComponent &component,
}
}
rotation_attribute.apply_span_and_save();
rotation_attribute.save();
}
static void geo_node_point_rotate_exec(GeoNodeExecParams params)

View File

@@ -50,7 +50,7 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
* for the factor. But for it's simpler to simply always use float3, since that is usually
* expected anyway. */
static const float3 scale_default = float3(1.0f);
OutputAttributePtr scale_attribute = component.attribute_try_get_for_output(
OutputAttribute_Typed<float3> scale_attribute = component.attribute_try_get_for_output(
"scale", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, &scale_default);
if (!scale_attribute) {
return;
@@ -63,27 +63,27 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
const CustomDataType data_type = (input_type == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ? CD_PROP_FLOAT :
CD_PROP_FLOAT3;
ReadAttributePtr attribute = params.get_input_attribute(
std::unique_ptr<GVArray> attribute = params.get_input_attribute(
"Factor", component, ATTR_DOMAIN_POINT, data_type, nullptr);
if (!attribute) {
return;
}
MutableSpan<float3> scale_span = scale_attribute->get_span<float3>();
MutableSpan<float3> scale_span = scale_attribute.as_span();
if (data_type == CD_PROP_FLOAT) {
Span<float> factors = attribute->get_span<float>();
GVArray_Typed<float> factors{*attribute};
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] * factors[i];
}
}
else if (data_type == CD_PROP_FLOAT3) {
Span<float3> factors = attribute->get_span<float3>();
GVArray_Typed<float3> factors{*attribute};
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] * factors[i];
}
}
scale_attribute.apply_span_and_save();
scale_attribute.save();
}
static void geo_node_point_scale_exec(GeoNodeExecParams params)

View File

@@ -58,27 +58,27 @@ static void copy_attributes_based_on_mask(const GeometryComponent &in_component,
const bool invert)
{
for (const std::string &name : in_component.attribute_names()) {
ReadAttributePtr attribute = in_component.attribute_try_get_for_read(name);
const CustomDataType data_type = attribute->custom_data_type();
ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(name);
const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type());
/* Only copy point attributes. Theoretically this could interpolate attributes on other
* domains to the point domain, but that would conflict with attributes that are built-in
* on other domains, which causes creating the attributes to fail. */
if (attribute->domain() != ATTR_DOMAIN_POINT) {
if (attribute.domain != ATTR_DOMAIN_POINT) {
continue;
}
OutputAttributePtr result_attribute = result_component.attribute_try_get_for_output(
OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
name, ATTR_DOMAIN_POINT, data_type);
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
Span<T> span = attribute->get_span<T>();
MutableSpan<T> out_span = result_attribute->get_span_for_write_only<T>();
GVArray_Span<T> span{*attribute.varray};
MutableSpan<T> out_span = result_attribute.as_span<T>();
copy_data_based_on_mask(span, masks, invert, out_span);
});
result_attribute.apply_span_and_save();
result_attribute.save();
}
}
@@ -107,9 +107,9 @@ static void separate_points_from_component(const GeometryComponent &in_component
return;
}
const BooleanReadAttribute mask_attribute = in_component.attribute_get_for_read<bool>(
const GVArray_Typed<bool> mask_attribute = in_component.attribute_get_for_read<bool>(
mask_name, ATTR_DOMAIN_POINT, false);
Span<bool> masks = mask_attribute.get_span();
VArray_Span<bool> masks{mask_attribute};
const int total = masks.count(!invert);
if (total == 0) {

View File

@@ -42,24 +42,19 @@ namespace blender::nodes {
static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component)
{
OutputAttributePtr position_attribute = component.attribute_try_get_for_output(
"position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
OutputAttribute_Typed<float3> position_attribute =
component.attribute_try_get_for_output<float3>("position", ATTR_DOMAIN_POINT, {0, 0, 0});
if (!position_attribute) {
return;
}
ReadAttributePtr attribute = params.get_input_attribute(
"Translation", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr);
if (!attribute) {
return;
GVArray_Typed<float3> attribute = params.get_input_attribute<float3>(
"Translation", component, ATTR_DOMAIN_POINT, {0, 0, 0});
for (const int i : IndexRange(attribute.size())) {
position_attribute->set(i, position_attribute->get(i) + attribute[i]);
}
Span<float3> data = attribute->get_span<float3>();
MutableSpan<float3> scale_span = position_attribute->get_span<float3>();
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] + data[i];
}
position_attribute.apply_span_and_save();
position_attribute.save();
}
static void geo_node_point_translate_exec(GeoNodeExecParams params)

View File

@@ -147,13 +147,15 @@ static void gather_point_data_from_component(const GeoNodeExecParams &params,
Vector<float3> &r_positions,
Vector<float> &r_radii)
{
Float3ReadAttribute positions = component.attribute_get_for_read<float3>(
GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
FloatReadAttribute radii = params.get_input_attribute<float>(
GVArray_Typed<float> radii = params.get_input_attribute<float>(
"Radius", component, ATTR_DOMAIN_POINT, 0.0f);
r_positions.extend(positions.get_span());
r_radii.extend(radii.get_span());
for (const int i : IndexRange(positions.size())) {
r_positions.append(positions[i]);
r_radii.append(radii[i]);
}
}
static void convert_to_grid_index_space(const float voxel_size,

View File

@@ -22,6 +22,7 @@
#include "NOD_geometry_exec.hh"
#include "NOD_type_callbacks.hh"
#include "NOD_type_conversions.hh"
#include "node_geometry_util.hh"
@@ -53,22 +54,29 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name
return nullptr;
}
ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name,
const GeometryComponent &component,
const AttributeDomain domain,
const CustomDataType type,
const void *default_value) const
std::unique_ptr<GVArray> GeoNodeExecParams::get_input_attribute(const StringRef name,
const GeometryComponent &component,
const AttributeDomain domain,
const CustomDataType type,
const void *default_value) const
{
const bNodeSocket *found_socket = this->find_available_socket(name);
BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(type);
const int64_t domain_size = component.attribute_domain_size(domain);
if (default_value == nullptr) {
default_value = cpp_type->default_value();
}
if (found_socket == nullptr) {
return component.attribute_get_constant_for_read(domain, type, default_value);
return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value);
}
if (found_socket->type == SOCK_STRING) {
const std::string name = this->get_input<std::string>(found_socket->identifier);
/* Try getting the attribute without the default value. */
ReadAttributePtr attribute = component.attribute_try_get_for_read(name, domain, type);
std::unique_ptr<GVArray> attribute = component.attribute_try_get_for_read(name, domain, type);
if (attribute) {
return attribute;
}
@@ -80,25 +88,29 @@ ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name,
this->error_message_add(NodeWarningType::Error,
TIP_("No attribute with name \"") + name + "\"");
}
return component.attribute_get_constant_for_read(domain, type, default_value);
return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value);
}
const DataTypeConversions &conversions = get_implicit_type_conversions();
if (found_socket->type == SOCK_FLOAT) {
const float value = this->get_input<float>(found_socket->identifier);
return component.attribute_get_constant_for_read_converted(
domain, CD_PROP_FLOAT, type, &value);
BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer);
return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
}
if (found_socket->type == SOCK_VECTOR) {
const float3 value = this->get_input<float3>(found_socket->identifier);
return component.attribute_get_constant_for_read_converted(
domain, CD_PROP_FLOAT3, type, &value);
BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
conversions.convert_to_uninitialized(CPPType::get<float3>(), *cpp_type, &value, buffer);
return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
}
if (found_socket->type == SOCK_RGBA) {
const Color4f value = this->get_input<Color4f>(found_socket->identifier);
return component.attribute_get_constant_for_read_converted(
domain, CD_PROP_COLOR, type, &value);
BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
conversions.convert_to_uninitialized(CPPType::get<Color4f>(), *cpp_type, &value, buffer);
return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
}
BLI_assert(false);
return component.attribute_get_constant_for_read(domain, type, default_value);
return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value);
}
CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
@@ -114,11 +126,11 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
if (found_socket->type == SOCK_STRING) {
const std::string name = this->get_input<std::string>(found_socket->identifier);
ReadAttributePtr attribute = component.attribute_try_get_for_read(name);
ReadAttributeLookup attribute = component.attribute_try_get_for_read(name);
if (!attribute) {
return default_type;
}
return attribute->custom_data_type();
return bke::cpp_type_to_custom_data_type(attribute.varray->type());
}
if (found_socket->type == SOCK_FLOAT) {
return CD_PROP_FLOAT;
@@ -157,9 +169,9 @@ AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain(
if (found_socket->type == SOCK_STRING) {
const std::string name = this->get_input<std::string>(found_socket->identifier);
ReadAttributePtr attribute = component.attribute_try_get_for_read(name);
ReadAttributeLookup attribute = component.attribute_try_get_for_read(name);
if (attribute) {
input_domains.append(attribute->domain());
input_domains.append(attribute.domain);
}
}
}

View File

@@ -219,8 +219,8 @@ static void insert_links_and_unlinked_inputs(CommonMFNetworkBuilderData &common)
const fn::MFDataType from_type = from_socket->data_type();
if (from_type != to_type) {
const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion(
from_type, to_type);
const fn::MultiFunction *conversion_fn =
get_implicit_type_conversions().get_conversion_multi_function(from_type, to_type);
if (conversion_fn != nullptr) {
fn::MFNode &node = common.network.add_function(*conversion_fn);
common.network.add_link(*from_socket, node.input(0));

View File

@@ -24,85 +24,195 @@
namespace blender::nodes {
using fn::GVMutableArray;
using fn::MFDataType;
template<typename From, typename To>
template<typename From, typename To, To (*ConversionF)(const From &)>
static void add_implicit_conversion(DataTypeConversions &conversions)
{
static fn::CustomMF_Convert<From, To> function;
conversions.add(fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>(), function);
const CPPType &from_type = CPPType::get<From>();
const CPPType &to_type = CPPType::get<To>();
const std::string conversion_name = from_type.name() + " to " + to_type.name();
static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name, ConversionF};
static auto convert_single_to_initialized = [](const void *src, void *dst) {
*(To *)dst = ConversionF(*(const From *)src);
};
static auto convert_single_to_uninitialized = [](const void *src, void *dst) {
new (dst) To(ConversionF(*(const From *)src));
};
conversions.add(fn::MFDataType::ForSingle<From>(),
fn::MFDataType::ForSingle<To>(),
multi_function,
convert_single_to_initialized,
convert_single_to_uninitialized);
}
template<typename From, typename To, typename ConversionF>
static void add_implicit_conversion(DataTypeConversions &conversions,
StringRef name,
ConversionF conversion)
static float2 float_to_float2(const float &a)
{
static fn::CustomMF_SI_SO<From, To> function{name, conversion};
conversions.add(fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>(), function);
return float2(a);
}
static float3 float_to_float3(const float &a)
{
return float3(a);
}
static int32_t float_to_int(const float &a)
{
return (int32_t)a;
}
static bool float_to_bool(const float &a)
{
return a > 0.0f;
}
static Color4f float_to_color(const float &a)
{
return Color4f(a, a, a, 1.0f);
}
static float3 float2_to_float3(const float2 &a)
{
return float3(a.x, a.y, 0.0f);
}
static float float2_to_float(const float2 &a)
{
return (a.x + a.y) / 2.0f;
}
static int float2_to_int(const float2 &a)
{
return (int32_t)((a.x + a.y) / 2.0f);
}
static bool float2_to_bool(const float2 &a)
{
return !is_zero_v2(a);
}
static Color4f float2_to_color(const float2 &a)
{
return Color4f(a.x, a.y, 0.0f, 1.0f);
}
static bool float3_to_bool(const float3 &a)
{
return !is_zero_v3(a);
}
static float float3_to_float(const float3 &a)
{
return (a.x + a.y + a.z) / 3.0f;
}
static int float3_to_int(const float3 &a)
{
return (int)((a.x + a.y + a.z) / 3.0f);
}
static float2 float3_to_float2(const float3 &a)
{
return float2(a);
}
static Color4f float3_to_color(const float3 &a)
{
return Color4f(a.x, a.y, a.z, 1.0f);
}
static bool int_to_bool(const int32_t &a)
{
return a > 0;
}
static float int_to_float(const int32_t &a)
{
return (float)a;
}
static float2 int_to_float2(const int32_t &a)
{
return float2((float)a);
}
static float3 int_to_float3(const int32_t &a)
{
return float3((float)a);
}
static Color4f int_to_color(const int32_t &a)
{
return Color4f((float)a, (float)a, (float)a, 1.0f);
}
static float bool_to_float(const bool &a)
{
return (bool)a;
}
static int32_t bool_to_int(const bool &a)
{
return (int32_t)a;
}
static float2 bool_to_float2(const bool &a)
{
return (a) ? float2(1.0f) : float2(0.0f);
}
static float3 bool_to_float3(const bool &a)
{
return (a) ? float3(1.0f) : float3(0.0f);
}
static Color4f bool_to_color(const bool &a)
{
return (a) ? Color4f(1.0f, 1.0f, 1.0f, 1.0f) : Color4f(0.0f, 0.0f, 0.0f, 1.0f);
}
static bool color_to_bool(const Color4f &a)
{
return rgb_to_grayscale(a) > 0.0f;
}
static float color_to_float(const Color4f &a)
{
return rgb_to_grayscale(a);
}
static int32_t color_to_int(const Color4f &a)
{
return (int)rgb_to_grayscale(a);
}
static float2 color_to_float2(const Color4f &a)
{
return float2(a.r, a.g);
}
static float3 color_to_float3(const Color4f &a)
{
return float3(a.r, a.g, a.b);
}
static DataTypeConversions create_implicit_conversions()
{
DataTypeConversions conversions;
add_implicit_conversion<float, float2>(conversions);
add_implicit_conversion<float, float3>(conversions);
add_implicit_conversion<float, int32_t>(conversions);
add_implicit_conversion<float, bool>(
conversions, "float to boolean", [](float a) { return a > 0.0f; });
add_implicit_conversion<float, Color4f>(
conversions, "float to Color4f", [](float a) { return Color4f(a, a, a, 1.0f); });
add_implicit_conversion<float2, float3>(
conversions, "float2 to float3", [](float2 a) { return float3(a.x, a.y, 0.0f); });
add_implicit_conversion<float2, float>(
conversions, "float2 to float", [](float2 a) { return (a.x + a.y) / 2.0f; });
add_implicit_conversion<float2, int32_t>(
conversions, "float2 to int32_t", [](float2 a) { return (int32_t)((a.x + a.y) / 2.0f); });
add_implicit_conversion<float2, bool>(
conversions, "float2 to bool", [](float2 a) { return !is_zero_v2(a); });
add_implicit_conversion<float2, Color4f>(
conversions, "float2 to Color4f", [](float2 a) { return Color4f(a.x, a.y, 0.0f, 1.0f); });
add_implicit_conversion<float, float2, float_to_float2>(conversions);
add_implicit_conversion<float, float3, float_to_float3>(conversions);
add_implicit_conversion<float, int32_t, float_to_int>(conversions);
add_implicit_conversion<float, bool, float_to_bool>(conversions);
add_implicit_conversion<float, Color4f, float_to_color>(conversions);
add_implicit_conversion<float3, bool>(
conversions, "float3 to boolean", [](float3 a) { return !is_zero_v3(a); });
add_implicit_conversion<float3, float>(
conversions, "float3 to float", [](float3 a) { return (a.x + a.y + a.z) / 3.0f; });
add_implicit_conversion<float3, int32_t>(
conversions, "float3 to int32_t", [](float3 a) { return (int)((a.x + a.y + a.z) / 3.0f); });
add_implicit_conversion<float3, float2>(conversions);
add_implicit_conversion<float3, Color4f>(
conversions, "float3 to Color4f", [](float3 a) { return Color4f(a.x, a.y, a.z, 1.0f); });
add_implicit_conversion<float2, float3, float2_to_float3>(conversions);
add_implicit_conversion<float2, float, float2_to_float>(conversions);
add_implicit_conversion<float2, int32_t, float2_to_int>(conversions);
add_implicit_conversion<float2, bool, float2_to_bool>(conversions);
add_implicit_conversion<float2, Color4f, float2_to_color>(conversions);
add_implicit_conversion<int32_t, bool>(
conversions, "int32 to boolean", [](int32_t a) { return a > 0; });
add_implicit_conversion<int32_t, float>(conversions);
add_implicit_conversion<int32_t, float2>(
conversions, "int32 to float2", [](int32_t a) { return float2((float)a); });
add_implicit_conversion<int32_t, float3>(
conversions, "int32 to float3", [](int32_t a) { return float3((float)a); });
add_implicit_conversion<int32_t, Color4f>(conversions, "int32 to Color4f", [](int32_t a) {
return Color4f((float)a, (float)a, (float)a, 1.0f);
});
add_implicit_conversion<float3, bool, float3_to_bool>(conversions);
add_implicit_conversion<float3, float, float3_to_float>(conversions);
add_implicit_conversion<float3, int32_t, float3_to_int>(conversions);
add_implicit_conversion<float3, float2, float3_to_float2>(conversions);
add_implicit_conversion<float3, Color4f, float3_to_color>(conversions);
add_implicit_conversion<bool, float>(conversions);
add_implicit_conversion<bool, int32_t>(conversions);
add_implicit_conversion<bool, float2>(
conversions, "boolean to float2", [](bool a) { return (a) ? float2(1.0f) : float2(0.0f); });
add_implicit_conversion<bool, float3>(
conversions, "boolean to float3", [](bool a) { return (a) ? float3(1.0f) : float3(0.0f); });
add_implicit_conversion<bool, Color4f>(conversions, "boolean to Color4f", [](bool a) {
return (a) ? Color4f(1.0f, 1.0f, 1.0f, 1.0f) : Color4f(0.0f, 0.0f, 0.0f, 1.0f);
});
add_implicit_conversion<int32_t, bool, int_to_bool>(conversions);
add_implicit_conversion<int32_t, float, int_to_float>(conversions);
add_implicit_conversion<int32_t, float2, int_to_float2>(conversions);
add_implicit_conversion<int32_t, float3, int_to_float3>(conversions);
add_implicit_conversion<int32_t, Color4f, int_to_color>(conversions);
add_implicit_conversion<Color4f, bool>(
conversions, "Color4f to boolean", [](Color4f a) { return rgb_to_grayscale(a) > 0.0f; });
add_implicit_conversion<Color4f, float>(
conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); });
add_implicit_conversion<Color4f, float2>(
conversions, "Color4f to float2", [](Color4f a) { return float2(a.r, a.g); });
add_implicit_conversion<Color4f, float3>(
conversions, "Color4f to float3", [](Color4f a) { return float3(a.r, a.g, a.b); });
add_implicit_conversion<bool, float, bool_to_float>(conversions);
add_implicit_conversion<bool, int32_t, bool_to_int>(conversions);
add_implicit_conversion<bool, float2, bool_to_float2>(conversions);
add_implicit_conversion<bool, float3, bool_to_float3>(conversions);
add_implicit_conversion<bool, Color4f, bool_to_color>(conversions);
add_implicit_conversion<Color4f, bool, color_to_bool>(conversions);
add_implicit_conversion<Color4f, float, color_to_float>(conversions);
add_implicit_conversion<Color4f, int32_t, color_to_int>(conversions);
add_implicit_conversion<Color4f, float2, color_to_float2>(conversions);
add_implicit_conversion<Color4f, float3, color_to_float3>(conversions);
return conversions;
}
@@ -113,20 +223,125 @@ const DataTypeConversions &get_implicit_type_conversions()
return conversions;
}
void DataTypeConversions::convert(const CPPType &from_type,
const CPPType &to_type,
const void *from_value,
void *to_value) const
void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type,
const CPPType &to_type,
const void *from_value,
void *to_value) const
{
const fn::MultiFunction *fn = this->get_conversion(MFDataType::ForSingle(from_type),
MFDataType::ForSingle(to_type));
BLI_assert(fn != nullptr);
if (from_type == to_type) {
from_type.copy_to_uninitialized(from_value, to_value);
return;
}
fn::MFContextBuilder context;
fn::MFParamsBuilder params{*fn, 1};
params.add_readonly_single_input(fn::GSpan(from_type, from_value, 1));
params.add_uninitialized_single_output(fn::GMutableSpan(to_type, to_value, 1));
fn->call({0}, params, context);
const ConversionFunctions *functions = this->get_conversion_functions(
MFDataType::ForSingle(from_type), MFDataType::ForSingle(to_type));
BLI_assert(functions != nullptr);
functions->convert_single_to_uninitialized(from_value, to_value);
}
class GVArray_For_ConvertedGVArray : public GVArray {
private:
std::unique_ptr<GVArray> varray_;
const CPPType &from_type_;
ConversionFunctions old_to_new_conversions_;
public:
GVArray_For_ConvertedGVArray(std::unique_ptr<GVArray> varray,
const CPPType &to_type,
const DataTypeConversions &conversions)
: GVArray(to_type, varray->size()), varray_(std::move(varray)), from_type_(varray_->type())
{
old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type);
}
private:
void get_impl(const int64_t index, void *r_value) const override
{
BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
varray_->get(index, buffer);
old_to_new_conversions_.convert_single_to_initialized(buffer, r_value);
from_type_.destruct(buffer);
}
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
{
BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
varray_->get(index, buffer);
old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value);
from_type_.destruct(buffer);
}
};
class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArray {
private:
std::unique_ptr<GVMutableArray> varray_;
const CPPType &from_type_;
ConversionFunctions old_to_new_conversions_;
ConversionFunctions new_to_old_conversions_;
public:
GVMutableArray_For_ConvertedGVMutableArray(std::unique_ptr<GVMutableArray> varray,
const CPPType &to_type,
const DataTypeConversions &conversions)
: GVMutableArray(to_type, varray->size()),
varray_(std::move(varray)),
from_type_(varray_->type())
{
old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type);
new_to_old_conversions_ = *conversions.get_conversion_functions(to_type, from_type_);
}
private:
void get_impl(const int64_t index, void *r_value) const override
{
BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
varray_->get(index, buffer);
old_to_new_conversions_.convert_single_to_initialized(buffer, r_value);
from_type_.destruct(buffer);
}
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
{
BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
varray_->get(index, buffer);
old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value);
from_type_.destruct(buffer);
}
void set_by_move_impl(const int64_t index, void *value) override
{
BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
new_to_old_conversions_.convert_single_to_uninitialized(value, buffer);
varray_->set_by_relocate(index, buffer);
}
};
std::unique_ptr<fn::GVArray> DataTypeConversions::try_convert(std::unique_ptr<fn::GVArray> varray,
const CPPType &to_type) const
{
const CPPType &from_type = varray->type();
if (from_type == to_type) {
return varray;
}
if (!this->is_convertible(from_type, to_type)) {
return {};
}
return std::make_unique<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this);
}
std::unique_ptr<fn::GVMutableArray> DataTypeConversions::try_convert(
std::unique_ptr<fn::GVMutableArray> varray, const CPPType &to_type) const
{
const CPPType &from_type = varray->type();
if (from_type == to_type) {
return varray;
}
if (!this->is_convertible(from_type, to_type)) {
return {};
}
return std::make_unique<GVMutableArray_For_ConvertedGVMutableArray>(
std::move(varray), to_type, *this);
}
} // namespace blender::nodes

View File

@@ -731,15 +731,6 @@ wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
BLI_buffer_declare_static(wmGizmo *, visible_3d_gizmos, BLI_BUFFER_NOP, 128);
bool do_step[WM_GIZMOMAP_DRAWSTEP_MAX];
int mval[2] = {UNPACK2(event->mval)};
/* Ensure for drag events we use the location where the user clicked.
* Without this click-dragging on a gizmo can accidentally act on the wrong gizmo. */
if (WM_event_is_mouse_drag(event)) {
mval[0] += event->x - event->prevclickx;
mval[1] += event->y - event->prevclicky;
}
for (int i = 0; i < ARRAY_SIZE(do_step); i++) {
do_step[i] = WM_gizmo_context_check_drawstep(C, i);
}
@@ -775,7 +766,7 @@ wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
}
else if (step == WM_GIZMOMAP_DRAWSTEP_2D) {
if ((gz = wm_gizmogroup_find_intersected_gizmo(
wm, gzgroup, C, event_modifier, mval, r_part))) {
wm, gzgroup, C, event_modifier, event->mval, r_part))) {
break;
}
}
@@ -787,7 +778,7 @@ wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
/* 2D gizmos get priority. */
if (gz == NULL) {
gz = gizmo_find_intersected_3d(
C, mval, visible_3d_gizmos.data, visible_3d_gizmos.count, r_part);
C, event->mval, visible_3d_gizmos.data, visible_3d_gizmos.count, r_part);
}
}
BLI_buffer_free(&visible_3d_gizmos);

View File

@@ -186,6 +186,7 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
win->addmousemove = true;
win->event_queue_check_click = 0;
win->event_queue_check_drag = 0;
win->event_queue_check_drag_handled = 0;
BLO_read_data_address(reader, &win->stereo3d_format);
/* Multi-view always fallback to anaglyph at file opening

View File

@@ -1621,7 +1621,7 @@ int WM_operator_name_call_with_properties(struct bContext *C,
{
PointerRNA props_ptr;
wmOperatorType *ot = WM_operatortype_find(opstring, false);
RNA_pointer_create(NULL, ot->srna, properties, &props_ptr);
RNA_pointer_create(G_MAIN->wm.first, ot->srna, properties, &props_ptr);
return WM_operator_name_call_ptr(C, ot, context, &props_ptr);
}
@@ -2941,6 +2941,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
if (wm_action_not_handled(action)) {
if (win->event_queue_check_drag) {
if (WM_event_drag_test(event, &event->prevclickx)) {
win->event_queue_check_drag_handled = true;
int x = event->x;
int y = event->y;
short val = event->val;
@@ -2984,6 +2986,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
if (event->is_repeat == false) {
win->event_queue_check_click = true;
win->event_queue_check_drag = true;
win->event_queue_check_drag_handled = false;
}
}
else if (event->val == KM_RELEASE) {
@@ -3470,6 +3473,13 @@ void wm_event_do_handlers(bContext *C)
win->event_queue_check_click = false;
}
/* If the drag even was handled, don't attempt to keep re-handing the same
* drag event on every cursor motion, see: T87511. */
if (win->event_queue_check_drag_handled) {
win->event_queue_check_drag = false;
win->event_queue_check_drag_handled = false;
}
/* Update previous mouse position for following events to use. */
win->eventstate->prevx = event->x;
win->eventstate->prevy = event->y;

View File

@@ -80,6 +80,9 @@ static wmKeyMapItem *wm_keymap_item_copy(wmKeyMapItem *kmi)
kmin->ptr = MEM_callocN(sizeof(PointerRNA), "UserKeyMapItemPtr");
WM_operator_properties_create(kmin->ptr, kmin->idname);
/* Signal for no context, see #STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID. */
kmin->ptr->owner_id = NULL;
kmin->properties = IDP_CopyProperty(kmin->properties);
kmin->ptr->data = kmin->properties;
}
@@ -106,6 +109,9 @@ static void wm_keymap_item_properties_set(wmKeyMapItem *kmi)
{
WM_operator_properties_alloc(&(kmi->ptr), &(kmi->properties), kmi->idname);
WM_operator_properties_sanitize(kmi->ptr, 1);
/* Signal for no context, see #STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID. */
kmi->ptr->owner_id = NULL;
}
/**
@@ -136,6 +142,9 @@ static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi)
kmi->ptr->data = kmi->properties;
}
WM_operator_properties_sanitize(kmi->ptr, 1);
/* Signal for no context, see #STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID. */
kmi->ptr->owner_id = NULL;
}
}
else {

View File

@@ -252,7 +252,7 @@ void WM_operatortype_props_advanced_end(wmOperatorType *ot)
return;
}
RNA_pointer_create(NULL, ot->srna, NULL, &struct_ptr);
WM_operator_properties_create_ptr(&struct_ptr, ot);
RNA_STRUCT_BEGIN (&struct_ptr, prop) {
counter++;

View File

@@ -583,7 +583,8 @@ char *WM_prop_pystring_assign(bContext *C, PointerRNA *ptr, PropertyRNA *prop, i
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
{
RNA_pointer_create(NULL, ot->srna, NULL, ptr);
/* Set the ID so the context can be accessed: see #STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID. */
RNA_pointer_create(G_MAIN->wm.first, ot->srna, NULL, ptr);
}
void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
@@ -594,7 +595,8 @@ void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
WM_operator_properties_create_ptr(ptr, ot);
}
else {
RNA_pointer_create(NULL, &RNA_OperatorProperties, NULL, ptr);
/* Set the ID so the context can be accessed: see #STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID. */
RNA_pointer_create(G_MAIN->wm.first, &RNA_OperatorProperties, NULL, ptr);
}
}
@@ -1205,7 +1207,7 @@ IDProperty *WM_operator_last_properties_ensure_idprops(wmOperatorType *ot)
void WM_operator_last_properties_ensure(wmOperatorType *ot, PointerRNA *ptr)
{
IDProperty *props = WM_operator_last_properties_ensure_idprops(ot);
RNA_pointer_create(NULL, ot->srna, props, ptr);
RNA_pointer_create(G_MAIN->wm.first, ot->srna, props, ptr);
}
/**

View File

@@ -130,14 +130,11 @@ set(SRC
# MSVC 2010 gives linking errors with the manifest
if(WIN32 AND NOT UNIX)
string(SUBSTRING ${BLENDER_VERSION} 0 1 bver1)
string(SUBSTRING ${BLENDER_VERSION} 2 1 bver2)
string(SUBSTRING ${BLENDER_VERSION} 3 1 bver3)
add_definitions(
-DBLEN_VER_RC_STR="${BLENDER_VERSION}"
-DBLEN_VER_RC_1=${bver1}
-DBLEN_VER_RC_2=${bver2}
-DBLEN_VER_RC_3=${bver3}
-DBLEN_VER_RC_1=${BLENDER_VERSION_MAJOR}
-DBLEN_VER_RC_2=${BLENDER_VERSION_MINOR}
-DBLEN_VER_RC_3=${BLENDER_VERSION_PATCH}
-DBLEN_VER_RC_4=0
)

View File

@@ -72,7 +72,7 @@ enum {
/* for the callbacks: */
#ifndef WITH_PYTHON_MODULE
# define BLEND_VERSION_FMT "Blender %d.%02d.%d"
# define BLEND_VERSION_FMT "Blender %d.%d.%d"
# define BLEND_VERSION_ARG (BLENDER_VERSION / 100), (BLENDER_VERSION % 100), BLENDER_VERSION_PATCH
#endif