Compare commits

...

50 Commits

Author SHA1 Message Date
83ccca8675 cleanup 2021-04-01 14:53:30 +02:00
77c8070b11 Spreadsheet: Show data of active node (WIP).
Differential Revision: https://developer.blender.org/D10875
2021-04-01 14:52:51 +02:00
1db976521e Merge branch 'master' into spreadsheet-active-node 2021-04-01 14:39:39 +02:00
b00727950c Nodes: separate node name and display name in bNodeTreePath
Previously, `node_name` was rarely actually a name of a node. It is set
correctly as node name in `ED_node_tree_push`. However, later on it
was overwritten by the name of an id data block in `node_draw_space`.

Now, the node_name stays the name of the "parent" node. Whereas
display_name is the name that will be displayed in the breadcrumbs.

With this change, the `node_name` can be used to reconstruct the
actual path from the root node tree to the currently visible tree.

Differential Revision: https://developer.blender.org/D10874
2021-04-01 14:39:12 +02:00
f053bc2ddf fix 2021-04-01 14:31:05 +02:00
51b4162fed direct data ownership 2021-04-01 14:30:51 +02:00
1bdceb813c Cleanup: spelling 2021-04-01 22:20:53 +11:00
4a7736ce1d Merge branch 'master' into spreadsheet-active-node 2021-04-01 13:16:48 +02:00
2a5c0c3491 Geometry Nodes: add socket value logging capability
The node tree evaluator now calls a callback for every used socket with
its corresponding value(s). Right now the callback does nothing.
However, we can use it to collect attribute name hints, socket values
for debugging or data that will be displayed in the spreadsheet.

The main difficulty here was to also call the callback for sockets in
nodes that are not directly executed (such as group nodes, muted
nodes and reroutes).

No functional changes are expected.
2021-04-01 13:10:22 +02:00
26071531d0 cleanup 2021-04-01 12:52:57 +02:00
131550dac1 Merge branch 'master' into spreadsheet-active-node 2021-04-01 12:45:55 +02:00
328b39335e BLI: add call_safe method for FunctionRef
This is useful to avoid nullity checks in some places.
2021-04-01 12:38:14 +02:00
fa50edc999 BLI: return early when copying empty array 2021-04-01 12:38:14 +02:00
0ffbcc4416 Fix "unused variable" warning when compiling without nanovdb 2021-04-01 12:36:23 +02:00
496df39e6f LineArt: Remove "soft selection" option.
After some back and forth with the GP module and some artists, this
option was deemed not that useful. The use case was considered too
obscure so we'll remove it.

It is still posible to have this functionality by using the vertex
weight modiifers or manually clamping the weights.
2021-04-01 12:36:23 +02:00
e1b2cf887f LineArt: Remove resampling settings.
This can be done with an other GP modifier already.
2021-04-01 12:36:23 +02:00
d5cefc1844 Fix T50103: Transform not working if scale is zero
If any axis of the scale of an object was zero, transforming failed.
This was because `td->smtx` was set to a zero matrix.

orthogonalize_m3_zero_axes is used to fill in the zeroed axes.

Thanks to @filedescriptor for the initial fix: D10869.
2021-04-01 21:35:19 +11:00
8a144b73c0 BLI_math: add orthogonalize_m#_zero_axes
Expose a this function to initialize any zeroed axes
to an orthogonal vector based on other non-zeroed axes.

This functionality already existed for `invert_m#_m#_safe_ortho`,
expose as a public function as it's useful to be able to fill in zeroed
axes of transformation matrices since they may be used in matrix
multiplication which would create degenerate matrices.
2021-04-01 21:34:35 +11:00
3f24cfb958 Cycles: light spread importance sampling for rectangular area lights
Compute a subset of the area light that actually affects the shading point
and only samples points within that.

It's not perfect as the real subset is a circle instead of a rectangle, and
the attenuation is not accounted for. However it massively reduces noise for
shading points near the area light anyway.

Ellipse shaped area lights do not have this importance sampling, but do not
have solid angle importance sampling either.

Ref D10594
2021-04-01 12:31:01 +02:00
Matteo Falduto
a4260ac219 Cycles: add a spread setting for area lights
This simulates the effect of a honeycomb or grid placed in front of a softbox.
In practice, it works by attenuating rays coming off-angle as a function of the
provided spread angle parameter.

Setting the parameter to 180 degrees poses no restrictions to the rays, making
the light behave the same way as before this patch.

The total light power is normalized based on the spread angle, so that the
light strength remains the same.

Differential Revision: https://developer.blender.org/D10594
2021-04-01 12:31:01 +02:00
c859e1afa0 Fix: incorrect versioning code for lights properties
Due to T64791 we must still use the old Lamp name rather than Light, work
around that for now.
2021-04-01 12:31:01 +02:00
Nikita Sirgienko
b30cc7071b Fix Cycles build error with "make developer" on some CPUs
The combination of building unit tests and WITH_CYCLES_NATIVE_ONLY did not
correctly detect when AVX/AVX2 support is available.

Differential Revision: https://developer.blender.org/D8201
2021-04-01 12:31:01 +02:00
64538532d4 Fix T87056: Segfault in GPU_batch_clear() involing Lattice evaluation
Fix a segfault by setting the `batch_cache` pointer to `NULL` when copying
a Lattice. That way the copy can get its own batch cache when needed,
preventing a use-after-free.
2021-04-01 12:28:26 +02:00
7bcd0e01af cleanup 2021-04-01 12:18:49 +02:00
d6fcecc471 cleanup 2021-04-01 12:12:18 +02:00
e945564068 Merge branch 'master' into spreadsheet-active-node 2021-04-01 11:55:34 +02:00
1598d57663 cleanup 2021-04-01 11:55:07 +02:00
42a40f4e7c support showing data of group input/output nodes 2021-04-01 11:41:30 +02:00
80865399a8 cleanup 2021-04-01 11:32:58 +02:00
d904271d09 Libmv: Add clang-format for third party sources
Got ignored in the initial commit of clang-format support to the Libmv.
2021-04-01 11:32:47 +02:00
7faf5b0e02 Fix condition for ffmpeg seek workaround
This condition was in contradiction with comment for function
`ffmpeg_generic_seek_workaround()`.

I have noticed, that formats that seeked well used this workaround.
Problem was that I misunderstood code from `av_seek_frame()` - formats
with `read_seek()` function stil don't use generic seeking method.
This is defined in `seek_frame_internal()`
2021-04-01 11:30:11 +02:00
9ed2a7e680 improved handling of skipped sockets 2021-04-01 11:22:06 +02:00
546fa9a759 Fix T87037: Add tooltip for "Paste Flipped"
The "Paste Flipped" operator was missing its own tooltip.

This patch adds the tooltip by implementing the `get_description` callback for
`GRAPH_OT_paste` and `ACTION_OT_paste`.

Reviewed By: sybren

Maniphest Tasks: T87037

Differential Revision: https://developer.blender.org/D10859
2021-04-01 11:04:05 +02:00
6fe2d6b8c8 Fix freezed proxy frames
`ffmpeg_generic_seek_workaround()` applied negative offset for seqrched
packet timestamp, but proxies always start from 0 and timestamp can be
 negative.

Limit timestamp value to 0, because `av_seek_frame()` doesn't accept
negative timestamps and returns with error. This prevents seeking from
working correctly.
2021-04-01 10:45:53 +02:00
3af1903ac7 log more socket values 2021-04-01 10:38:19 +02:00
214a49aae4 refactor 2021-04-01 10:28:36 +02:00
45aa341dd4 initial callback 2021-04-01 10:18:44 +02:00
e0aab87f54 initial node group support 2021-04-01 10:07:59 +02:00
fca8d0f91f separate node from display name 2021-04-01 09:29:01 +02:00
a9fc5be5fa Fix T86331: Preferences menu inaccessible until window resize
The RGN_TYPE_EXECUTE region was zero height - with the "Load & Save"
button drawing outside of those bounds - so it didn't respond to events.

This is because the region started off this size and does not change
with simply adding the buttons. Although it has RGN_FLAG_DYNAMIC_SIZE,
delayed reinit of regions is only currently supported on headers.

This gives the execute region an initial (minimum) vertical size but
also makes the region **hidden** by default.

- Showing Prefs as an editor among others it will show the header
  but not the execute region.

- Showing the Prefs in a popup window, hides the header region
  and shows the execute region.

Ref D10636
2021-04-01 17:42:01 +11:00
ab652c2c90 Cleanup: method naming. 2021-04-01 08:16:43 +02:00
4b595de5e6 Cleanup: Split up methods. 2021-04-01 08:16:43 +02:00
d5c6485372 Cleanup: clang format 2021-04-01 11:18:26 +11:00
93972c8910 Clang Format: bump the minimum version to 8
Make use of `StatementMacros` so Python structs are formatted correctly.

The comment about STRINGIFY doesn't seem to be valid anymore,
so this has been left out.
2021-04-01 11:18:05 +11:00
a641e08227 Cleanup: Use const arguments in curve code 2021-03-31 18:07:15 -05:00
8262c2577e cleanup 2021-03-31 12:52:45 +02:00
993e8af943 cleanup 2021-03-31 12:41:26 +02:00
a535c07417 avoid some copies 2021-03-31 12:24:14 +02:00
5cbecde9c7 node in spreadsheet 2021-03-31 12:16:01 +02:00
4472178094 initial code 2021-03-31 12:03:26 +02:00
82 changed files with 995 additions and 378 deletions

View File

@@ -2,7 +2,7 @@
# Configuration of clang-format
# =============================
#
# Tested to work with versions: 6 to 8.
# Tested to work with versions: 8 to 11.
# This causes parameters on continuations to align to the opening brace.
#
@@ -263,8 +263,5 @@ ForEachMacros:
- MAP_SLOT_PROBING_BEGIN
- VECTOR_SET_SLOT_PROBING_BEGIN
# Use once we bump the minimum version to version 8.
# # Without this string literals that in-line 'STRINGIFY' behave strangely (a bug?).
# StatementMacros:
# - PyObject_VAR_HEAD
# - STRINGIFY
StatementMacros:
- PyObject_VAR_HEAD

View File

@@ -1409,15 +1409,15 @@ class CYCLES_LIGHT_PT_nodes(CyclesButtonsPanel, Panel):
panel_node_draw(layout, light, 'OUTPUT_LIGHT', 'Surface')
class CYCLES_LIGHT_PT_spot(CyclesButtonsPanel, Panel):
bl_label = "Spot Shape"
class CYCLES_LIGHT_PT_beam_shape(CyclesButtonsPanel, Panel):
bl_label = "Beam Shape"
bl_parent_id = "CYCLES_LIGHT_PT_light"
bl_context = "data"
@classmethod
def poll(cls, context):
light = context.light
return (light and light.type == 'SPOT') and CyclesButtonsPanel.poll(context)
if context.light.type in {'SPOT', 'AREA'}:
return context.light and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
@@ -1425,9 +1425,12 @@ class CYCLES_LIGHT_PT_spot(CyclesButtonsPanel, Panel):
layout.use_property_split = True
col = layout.column()
col.prop(light, "spot_size", text="Size")
col.prop(light, "spot_blend", text="Blend", slider=True)
col.prop(light, "show_cone")
if light.type == 'SPOT':
col.prop(light, "spot_size", text="Spot Size")
col.prop(light, "spot_blend", text="Blend", slider=True)
col.prop(light, "show_cone")
elif light.type == 'AREA':
col.prop(light, "spread", text="Spread")
class CYCLES_WORLD_PT_preview(CyclesButtonsPanel, Panel):
@@ -2284,7 +2287,7 @@ classes = (
CYCLES_LIGHT_PT_preview,
CYCLES_LIGHT_PT_light,
CYCLES_LIGHT_PT_nodes,
CYCLES_LIGHT_PT_spot,
CYCLES_LIGHT_PT_beam_shape,
CYCLES_WORLD_PT_preview,
CYCLES_WORLD_PT_surface,
CYCLES_WORLD_PT_volume,
@@ -2314,7 +2317,7 @@ classes = (
node_panel(CYCLES_WORLD_PT_settings_surface),
node_panel(CYCLES_WORLD_PT_settings_volume),
node_panel(CYCLES_LIGHT_PT_light),
node_panel(CYCLES_LIGHT_PT_spot),
node_panel(CYCLES_LIGHT_PT_beam_shape)
)

View File

@@ -82,6 +82,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
light->set_axisu(transform_get_column(&tfm, 0));
light->set_axisv(transform_get_column(&tfm, 1));
light->set_sizeu(b_area_light.size());
light->set_spread(b_area_light.spread());
switch (b_area_light.shape()) {
case BL::AreaLight::shape_SQUARE:
light->set_sizev(light->get_sizeu());

View File

@@ -119,11 +119,11 @@ ccl_device_inline bool lamp_light_sample(
klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
float3 axisv = make_float3(
klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
float3 D = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
float invarea = fabsf(klight->area.invarea);
bool is_round = (klight->area.invarea < 0.0f);
if (dot(ls->P - P, D) > 0.0f) {
if (dot(ls->P - P, Ng) > 0.0f) {
return false;
}
@@ -135,20 +135,37 @@ ccl_device_inline bool lamp_light_sample(
ls->pdf = invarea;
}
else {
float3 sample_axisu = axisu;
float3 sample_axisv = axisv;
if (klight->area.tan_spread > 0.0f) {
if (!light_spread_clamp_area_light(
P, Ng, &ls->P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) {
return false;
}
}
inplane = ls->P;
ls->pdf = rect_light_sample(P, &ls->P, axisu, axisv, randu, randv, true);
ls->pdf = rect_light_sample(P, &ls->P, sample_axisu, sample_axisv, randu, randv, true);
inplane = ls->P - inplane;
}
ls->u = dot(inplane, axisu) * (1.0f / dot(axisu, axisu)) + 0.5f;
ls->v = dot(inplane, axisv) * (1.0f / dot(axisv, axisv)) + 0.5f;
ls->Ng = D;
ls->Ng = Ng;
ls->D = normalize_len(ls->P - P, &ls->t);
ls->eval_fac = 0.25f * invarea;
if (klight->area.tan_spread > 0.0f) {
/* Area Light spread angle attenuation */
ls->eval_fac *= light_spread_attenuation(
ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread);
}
if (is_round) {
ls->pdf *= lamp_light_pdf(kg, D, -ls->D, ls->t);
ls->pdf *= lamp_light_pdf(kg, Ng, -ls->D, ls->t);
}
}
}
@@ -283,9 +300,28 @@ ccl_device bool lamp_light_eval(
ls->pdf = invarea * lamp_light_pdf(kg, Ng, -D, ls->t);
}
else {
ls->pdf = rect_light_sample(P, &light_P, axisu, axisv, 0, 0, false);
float3 sample_axisu = axisu;
float3 sample_axisv = axisv;
if (klight->area.tan_spread > 0.0f) {
if (!light_spread_clamp_area_light(
P, Ng, &light_P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) {
return false;
}
}
ls->pdf = rect_light_sample(P, &light_P, sample_axisu, sample_axisv, 0, 0, false);
}
ls->eval_fac = 0.25f * invarea;
if (klight->area.tan_spread > 0.0f) {
/* Area Light spread angle attenuation */
ls->eval_fac *= light_spread_attenuation(
ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread);
if (ls->eval_fac == 0.0f) {
return false;
}
}
}
else {
return false;

View File

@@ -146,6 +146,70 @@ ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot
return attenuation;
}
ccl_device float light_spread_attenuation(const float3 D,
const float3 lightNg,
const float tan_spread,
const float normalize_spread)
{
/* Model a soft-box grid, computing the ratio of light not hidden by the
* slats of the grid at a given angle. (see D10594). */
const float cos_a = -dot(D, lightNg);
const float sin_a = safe_sqrtf(1.0f - sqr(cos_a));
const float tan_a = sin_a / cos_a;
return max((1.0f - (tan_spread * tan_a)) * normalize_spread, 0.0f);
}
/* Compute subset of area light that actually has an influence on the shading point, to
* reduce noise with low spread. */
ccl_device bool light_spread_clamp_area_light(const float3 P,
const float3 lightNg,
float3 *lightP,
float3 *axisu,
float3 *axisv,
const float tan_spread)
{
/* Closest point in area light plane and distance to that plane. */
const float3 closest_P = P - dot(lightNg, P - *lightP) * lightNg;
const float t = len(closest_P - P);
/* Radius of circle on area light that actually affects the shading point. */
const float radius = t / tan_spread;
/* TODO: would be faster to store as normalized vector + length, also in rect_light_sample. */
float len_u, len_v;
const float3 u = normalize_len(*axisu, &len_u);
const float3 v = normalize_len(*axisv, &len_v);
/* Local uv coordinates of closest point. */
const float closest_u = dot(u, closest_P - *lightP);
const float closest_v = dot(v, closest_P - *lightP);
/* Compute rectangle encompassing the circle that affects the shading point,
* clamped to the bounds of the area light. */
const float min_u = max(closest_u - radius, -len_u * 0.5f);
const float max_u = min(closest_u + radius, len_u * 0.5f);
const float min_v = max(closest_v - radius, -len_v * 0.5f);
const float max_v = min(closest_v + radius, len_v * 0.5f);
/* Skip if rectangle is empty. */
if (min_u >= max_u || min_v >= max_v) {
return false;
}
/* Compute new area light center position and axes from rectangle in local
* uv coordinates. */
const float new_center_u = 0.5f * (min_u + max_u);
const float new_center_v = 0.5f * (min_v + max_v);
const float new_len_u = 0.5f * (max_u - min_u);
const float new_len_v = 0.5f * (max_v - min_v);
*lightP = *lightP + new_center_u * u + new_center_v * v;
*axisu = u * new_len_u * 2.0f;
*axisv = v * new_len_v * 2.0f;
return true;
}
ccl_device float lamp_light_pdf(KernelGlobals *kg, const float3 Ng, const float3 I, float t)
{
float cos_pi = dot(Ng, I);

View File

@@ -1501,9 +1501,9 @@ typedef struct KernelAreaLight {
float axisu[3];
float invarea;
float axisv[3];
float pad1;
float tan_spread;
float dir[3];
float pad2;
float normalize_spread;
} KernelAreaLight;
typedef struct KernelDistantLight {

View File

@@ -179,9 +179,13 @@ bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMet
metadata.transform_3d = transform_inverse(index_to_object * texture_to_index);
metadata.use_transform_3d = true;
# ifndef WITH_NANOVDB
(void)features;
# endif
return true;
#else
(void)metadata;
(void)features;
return false;
#endif
}

View File

@@ -129,6 +129,7 @@ NODE_DEFINE(Light)
SOCKET_VECTOR(axisv, "Axis V", zero_float3());
SOCKET_FLOAT(sizev, "Size V", 1.0f);
SOCKET_BOOLEAN(round, "Round", false);
SOCKET_FLOAT(spread, "Spread", M_PI_F);
SOCKET_INT(map_resolution, "Map Resolution", 0);
@@ -858,6 +859,15 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
float invarea = (area != 0.0f) ? 1.0f / area : 1.0f;
float3 dir = light->dir;
/* Convert from spread angle 0..180 to 90..0, clamping to a minimum
* angle to avoid excessive noise. */
const float min_spread_angle = 1.0f * M_PI_F / 180.0f;
const float spread_angle = 0.5f * (M_PI_F - max(light->spread, min_spread_angle));
/* Normalization computed using:
* integrate cos(x) (1 - tan(x) * tan(a)) * sin(x) from x = a to pi/2. */
const float tan_spread = tanf(spread_angle);
const float normalize_spread = 2.0f / (2.0f + (2.0f * spread_angle - M_PI_F) * tan_spread);
dir = safe_normalize(dir);
if (light->use_mis && area != 0.0f)
@@ -877,6 +887,8 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
klights[light_index].area.dir[0] = dir.x;
klights[light_index].area.dir[1] = dir.y;
klights[light_index].area.dir[2] = dir.z;
klights[light_index].area.tan_spread = tan_spread;
klights[light_index].area.normalize_spread = normalize_spread;
}
else if (light->light_type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;

View File

@@ -58,6 +58,7 @@ class Light : public Node {
NODE_SOCKET_API(float3, axisv)
NODE_SOCKET_API(float, sizev)
NODE_SOCKET_API(bool, round)
NODE_SOCKET_API(float, spread)
NODE_SOCKET_API(Transform, tfm)

View File

@@ -18,6 +18,7 @@
#define TEST_CATEGORY_NAME util_avx2
#if defined(i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
#if (defined(i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)) && \
defined(__AVX2__)
# include "util_avxf_test.h"
#endif

View File

@@ -18,6 +18,7 @@
#define TEST_CATEGORY_NAME util_avx
#if defined(i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
#if (defined(i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)) && \
defined(__AVX__)
# include "util_avxf_test.h"
#endif

View File

@@ -0,0 +1,2 @@
DisableFormat: true
SortIncludes: false

View File

@@ -108,7 +108,7 @@ void BKE_curve_transform(struct Curve *cu,
const bool do_props);
void BKE_curve_translate(struct Curve *cu, const float offset[3], const bool do_keys);
void BKE_curve_material_index_remove(struct Curve *cu, int index);
bool BKE_curve_material_index_used(struct Curve *cu, int index);
bool BKE_curve_material_index_used(const struct Curve *cu, int index);
void BKE_curve_material_index_clear(struct Curve *cu);
bool BKE_curve_material_index_validate(struct Curve *cu);
void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsigned int remap_len);
@@ -125,8 +125,10 @@ void BKE_curve_nurb_vert_active_set(struct Curve *cu, const struct Nurb *nu, con
bool BKE_curve_nurb_vert_active_get(struct Curve *cu, struct Nurb **r_nu, void **r_vert);
void BKE_curve_nurb_vert_active_validate(struct Curve *cu);
float (*BKE_curve_nurbs_vert_coords_alloc(struct ListBase *lb, int *r_vert_len))[3];
void BKE_curve_nurbs_vert_coords_get(struct ListBase *lb, float (*vert_coords)[3], int vert_len);
float (*BKE_curve_nurbs_vert_coords_alloc(const struct ListBase *lb, int *r_vert_len))[3];
void BKE_curve_nurbs_vert_coords_get(const struct ListBase *lb,
float (*vert_coords)[3],
int vert_len);
void BKE_curve_nurbs_vert_coords_apply_with_mat4(struct ListBase *lb,
const float (*vert_coords)[3],
@@ -137,7 +139,7 @@ void BKE_curve_nurbs_vert_coords_apply(struct ListBase *lb,
const float (*vert_coords)[3],
const bool constrain_2d);
float (*BKE_curve_nurbs_key_vert_coords_alloc(struct ListBase *lb,
float (*BKE_curve_nurbs_key_vert_coords_alloc(const struct ListBase *lb,
float *key,
int *r_vert_len))[3];
void BKE_curve_nurbs_key_vert_tilts_apply(struct ListBase *lb, const float *key);
@@ -166,8 +168,8 @@ void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], cons
bool BKE_nurbList_index_get_co(struct ListBase *editnurb, const int index, float r_co[3]);
int BKE_nurbList_verts_count(struct ListBase *nurb);
int BKE_nurbList_verts_count_without_handles(struct ListBase *nurb);
int BKE_nurbList_verts_count(const struct ListBase *nurb);
int BKE_nurbList_verts_count_without_handles(const struct ListBase *nurb);
void BKE_nurbList_free(struct ListBase *lb);
void BKE_nurbList_duplicate(struct ListBase *lb1, const struct ListBase *lb2);
@@ -185,7 +187,7 @@ struct Nurb *BKE_nurb_duplicate(const struct Nurb *nu);
struct Nurb *BKE_nurb_copy(struct Nurb *src, int pntsu, int pntsv);
void BKE_nurb_test_2d(struct Nurb *nu);
void BKE_nurb_minmax(struct Nurb *nu, bool use_radius, float min[3], float max[3]);
void BKE_nurb_minmax(const struct Nurb *nu, bool use_radius, float min[3], float max[3]);
float BKE_nurb_calc_length(const struct Nurb *nu, int resolution);
void BKE_nurb_makeFaces(

View File

@@ -77,29 +77,29 @@ typedef struct DispList {
int totindex; /* indexed array drawing surfaces */
} DispList;
void BKE_displist_copy(struct ListBase *lbn, struct ListBase *lb);
void BKE_displist_copy(struct ListBase *lbn, const struct ListBase *lb);
void BKE_displist_elem_free(DispList *dl);
DispList *BKE_displist_find_or_create(struct ListBase *lb, int type);
DispList *BKE_displist_find(struct ListBase *lb, int type);
void BKE_displist_normals_add(struct ListBase *lb);
void BKE_displist_count(struct ListBase *lb, int *totvert, int *totface, int *tottri);
void BKE_displist_count(const struct ListBase *lb, int *totvert, int *totface, int *tottri);
void BKE_displist_free(struct ListBase *lb);
bool BKE_displist_has_faces(struct ListBase *lb);
bool BKE_displist_has_faces(const struct ListBase *lb);
void BKE_displist_make_surf(struct Depsgraph *depsgraph,
struct Scene *scene,
const struct Scene *scene,
struct Object *ob,
struct ListBase *dispbase,
struct Mesh **r_final,
const bool for_render,
const bool for_orco);
void BKE_displist_make_curveTypes(struct Depsgraph *depsgraph,
struct Scene *scene,
const struct Scene *scene,
struct Object *ob,
const bool for_render,
const bool for_orco);
void BKE_displist_make_curveTypes_forRender(struct Depsgraph *depsgraph,
struct Scene *scene,
const struct Scene *scene,
struct Object *ob,
struct ListBase *dispbase,
struct Mesh **r_final,
@@ -111,22 +111,26 @@ void BKE_displist_make_mball_forRender(struct Depsgraph *depsgraph,
struct ListBase *dispbase);
bool BKE_curve_calc_modifiers_pre(struct Depsgraph *depsgraph,
struct Scene *scene,
const struct Scene *scene,
struct Object *ob,
struct ListBase *source_nurb,
struct ListBase *target_nurb,
const bool for_render);
bool BKE_displist_surfindex_get(
const struct DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4);
bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4);
void BKE_displist_fill(const struct ListBase *dispbase,
struct ListBase *to,
const float normal_proj[3],
const bool flip_normal);
float BKE_displist_calc_taper(
struct Depsgraph *depsgraph, struct Scene *scene, struct Object *taperobj, int cur, int tot);
float BKE_displist_calc_taper(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Object *taperobj,
int cur,
int tot);
void BKE_displist_minmax(struct ListBase *dispbase, float min[3], float max[3]);
void BKE_displist_minmax(const struct ListBase *dispbase, float min[3], float max[3]);
#ifdef __cplusplus
}

View File

@@ -141,6 +141,12 @@ class GeometryComponent {
/* The returned component should be of the same type as the type this is called on. */
virtual GeometryComponent *copy() const = 0;
/* Direct data is everything except for instances of objects/collections.
* If this returns true, the geometry set can be cached and is still valid after e.g. modifier
* evaluation ends. Instances can only be valid as long as the data they instance is valid. */
virtual bool owns_direct_data() const = 0;
virtual void ensure_owns_direct_data() = 0;
void user_add() const;
void user_remove() const;
bool is_mutable() const;
@@ -315,6 +321,8 @@ struct GeometrySet {
void clear();
void ensure_owns_direct_data();
/* Utility methods for creation. */
static GeometrySet create_with_mesh(
Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
@@ -374,6 +382,9 @@ class MeshComponent : public GeometryComponent {
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_MESH;
private:
@@ -404,6 +415,9 @@ class PointCloudComponent : public GeometryComponent {
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_POINT_CLOUD;
private:
@@ -444,6 +458,9 @@ class InstancesComponent : public GeometryComponent {
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES;
};
@@ -466,5 +483,8 @@ class VolumeComponent : public GeometryComponent {
const Volume *get_for_read() const;
Volume *get_for_write();
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_VOLUME;
};

View File

@@ -34,6 +34,7 @@ struct Base;
struct BoundBox;
struct Curve;
struct Depsgraph;
struct GeometrySet;
struct GpencilModifierData;
struct HookGpencilModifierData;
struct HookModifierData;
@@ -69,6 +70,8 @@ void BKE_object_free_curve_cache(struct Object *ob);
void BKE_object_free_derived_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
void BKE_object_preview_geometry_set(struct Object *ob, struct GeometrySet *geometry_set);
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
void BKE_object_modifier_gpencil_hook_reset(struct Object *ob,
struct HookGpencilModifierData *hmd);

View File

@@ -596,11 +596,11 @@ bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3])
return false;
}
int BKE_nurbList_verts_count(ListBase *nurb)
int BKE_nurbList_verts_count(const ListBase *nurb)
{
int tot = 0;
LISTBASE_FOREACH (Nurb *, nu, nurb) {
LISTBASE_FOREACH (const Nurb *, nu, nurb) {
if (nu->bezt) {
tot += 3 * nu->pntsu;
}
@@ -612,7 +612,7 @@ int BKE_nurbList_verts_count(ListBase *nurb)
return tot;
}
int BKE_nurbList_verts_count_without_handles(ListBase *nurb)
int BKE_nurbList_verts_count_without_handles(const ListBase *nurb)
{
int tot = 0;
@@ -779,7 +779,7 @@ void BKE_nurb_test_2d(Nurb *nu)
* if use_radius is truth, minmax will take points' radius into account,
* which will make boundbox closer to beveled curve.
*/
void BKE_nurb_minmax(Nurb *nu, bool use_radius, float min[3], float max[3])
void BKE_nurb_minmax(const Nurb *nu, bool use_radius, float min[3], float max[3])
{
BezTriple *bezt;
BPoint *bp;
@@ -1928,7 +1928,7 @@ static int cu_isectLL(const float v1[3],
return 0;
}
static bool bevelinside(BevList *bl1, BevList *bl2)
static bool bevelinside(const BevList *bl1, const BevList *bl2)
{
/* is bl2 INSIDE bl1 ? with left-right method and "lambda's" */
/* returns '1' if correct hole */
@@ -2052,8 +2052,8 @@ static void calc_bevel_sin_cos(
*r_cosa = x3 / t02;
}
static void tilt_bezpart(BezTriple *prevbezt,
BezTriple *bezt,
static void tilt_bezpart(const BezTriple *prevbezt,
const BezTriple *bezt,
Nurb *nu,
float *tilt_array,
float *radius_array,
@@ -2061,7 +2061,7 @@ static void tilt_bezpart(BezTriple *prevbezt,
int resolu,
int stride)
{
BezTriple *pprev, *next, *last;
const BezTriple *pprev, *next, *last;
float fac, dfac, t[4];
int a;
@@ -4664,12 +4664,12 @@ void BKE_nurb_direction_switch(Nurb *nu)
}
}
void BKE_curve_nurbs_vert_coords_get(ListBase *lb, float (*vert_coords)[3], int vert_len)
void BKE_curve_nurbs_vert_coords_get(const ListBase *lb, float (*vert_coords)[3], int vert_len)
{
float *co = vert_coords[0];
LISTBASE_FOREACH (Nurb *, nu, lb) {
LISTBASE_FOREACH (const Nurb *, nu, lb) {
if (nu->type == CU_BEZIER) {
BezTriple *bezt = nu->bezt;
const BezTriple *bezt = nu->bezt;
for (int i = 0; i < nu->pntsu; i++, bezt++) {
copy_v3_v3(co, bezt->vec[0]);
co += 3;
@@ -4680,7 +4680,7 @@ void BKE_curve_nurbs_vert_coords_get(ListBase *lb, float (*vert_coords)[3], int
}
}
else {
BPoint *bp = nu->bp;
const BPoint *bp = nu->bp;
for (int i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
copy_v3_v3(co, bp->vec);
co += 3;
@@ -4691,7 +4691,7 @@ void BKE_curve_nurbs_vert_coords_get(ListBase *lb, float (*vert_coords)[3], int
UNUSED_VARS_NDEBUG(vert_len);
}
float (*BKE_curve_nurbs_vert_coords_alloc(ListBase *lb, int *r_vert_len))[3]
float (*BKE_curve_nurbs_vert_coords_alloc(const ListBase *lb, int *r_vert_len))[3]
{
const int vert_len = BKE_nurbList_verts_count(lb);
float(*vert_coords)[3] = MEM_malloc_arrayN(vert_len, sizeof(*vert_coords), __func__);
@@ -4777,15 +4777,15 @@ void BKE_curve_nurbs_vert_coords_apply(ListBase *lb,
}
}
float (*BKE_curve_nurbs_key_vert_coords_alloc(ListBase *lb, float *key, int *r_vert_len))[3]
float (*BKE_curve_nurbs_key_vert_coords_alloc(const ListBase *lb, float *key, int *r_vert_len))[3]
{
int vert_len = BKE_nurbList_verts_count(lb);
float(*cos)[3] = MEM_malloc_arrayN(vert_len, sizeof(*cos), __func__);
float *co = cos[0];
LISTBASE_FOREACH (Nurb *, nu, lb) {
LISTBASE_FOREACH (const Nurb *, nu, lb) {
if (nu->type == CU_BEZIER) {
BezTriple *bezt = nu->bezt;
const BezTriple *bezt = nu->bezt;
for (int i = 0; i < nu->pntsu; i++, bezt++) {
copy_v3_v3(co, &key[0]);
@@ -4798,7 +4798,7 @@ float (*BKE_curve_nurbs_key_vert_coords_alloc(ListBase *lb, float *key, int *r_v
}
}
else {
BPoint *bp = nu->bp;
const BPoint *bp = nu->bp;
for (int i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
copy_v3_v3(co, key);
@@ -5216,7 +5216,7 @@ bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
use_radius = false;
}
/* Do bounding box based on splines. */
LISTBASE_FOREACH (Nurb *, nu, nurb_lb) {
LISTBASE_FOREACH (const Nurb *, nu, nurb_lb) {
BKE_nurb_minmax(nu, use_radius, min, max);
}
const bool result = (BLI_listbase_is_empty(nurb_lb) == false);
@@ -5412,12 +5412,12 @@ void BKE_curve_material_index_remove(Curve *cu, int index)
}
}
bool BKE_curve_material_index_used(Curve *cu, int index)
bool BKE_curve_material_index_used(const Curve *cu, int index)
{
const int curvetype = BKE_curve_type_get(cu);
if (curvetype == OB_FONT) {
struct CharInfo *info = cu->strinfo;
const struct CharInfo *info = cu->strinfo;
for (int i = cu->len_char32 - 1; i >= 0; i--, info++) {
if (info->mat_nr == index) {
return true;
@@ -5425,7 +5425,7 @@ bool BKE_curve_material_index_used(Curve *cu, int index)
}
}
else {
LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
LISTBASE_FOREACH (const Nurb *, nu, &cu->nurb) {
if (nu->mat_nr == index) {
return true;
}

View File

@@ -113,9 +113,9 @@ DispList *BKE_displist_find(ListBase *lb, int type)
return NULL;
}
bool BKE_displist_has_faces(ListBase *lb)
bool BKE_displist_has_faces(const ListBase *lb)
{
LISTBASE_FOREACH (DispList *, dl, lb) {
LISTBASE_FOREACH (const DispList *, dl, lb) {
if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
return true;
}
@@ -124,7 +124,7 @@ bool BKE_displist_has_faces(ListBase *lb)
return false;
}
void BKE_displist_copy(ListBase *lbn, ListBase *lb)
void BKE_displist_copy(ListBase *lbn, const ListBase *lb)
{
BKE_displist_free(lbn);
@@ -208,9 +208,9 @@ void BKE_displist_normals_add(ListBase *lb)
}
}
void BKE_displist_count(ListBase *lb, int *totvert, int *totface, int *tottri)
void BKE_displist_count(const ListBase *lb, int *totvert, int *totface, int *tottri)
{
LISTBASE_FOREACH (DispList *, dl, lb) {
LISTBASE_FOREACH (const DispList *, dl, lb) {
int vert_tot = 0;
int face_tot = 0;
int tri_tot = 0;
@@ -251,7 +251,8 @@ void BKE_displist_count(ListBase *lb, int *totvert, int *totface, int *tottri)
}
}
bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4)
bool BKE_displist_surfindex_get(
const DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4)
{
if ((dl->flag & DL_CYCL_V) == 0 && a == (dl->parts) - 1) {
return false;
@@ -608,7 +609,7 @@ static void bevels_to_filledpoly(const Curve *cu, ListBase *dispbase)
BKE_displist_fill(dispbase, dispbase, z_up, false);
}
static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dispbase)
static void curve_to_filledpoly(const Curve *cu, ListBase *dispbase)
{
if (!CU_DO_2DFILL(cu)) {
return;
@@ -628,7 +629,10 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis
* - first point left, last point right
* - based on subdivided points in original curve, not on points in taper curve (still)
*/
static float displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, float fac)
static float displist_calc_taper(Depsgraph *depsgraph,
const Scene *scene,
Object *taperobj,
float fac)
{
DispList *dl;
@@ -671,7 +675,7 @@ static float displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *tap
}
float BKE_displist_calc_taper(
Depsgraph *depsgraph, Scene *scene, Object *taperobj, int cur, int tot)
Depsgraph *depsgraph, const Scene *scene, Object *taperobj, int cur, int tot)
{
float fac = ((float)cur) / (float)(tot - 1);
@@ -713,8 +717,8 @@ void BKE_displist_make_mball_forRender(Depsgraph *depsgraph,
object_deform_mball(ob, dispbase);
}
static ModifierData *curve_get_tessellate_point(Scene *scene,
Object *ob,
static ModifierData *curve_get_tessellate_point(const Scene *scene,
const Object *ob,
const bool for_render,
const bool editmode)
{
@@ -764,7 +768,7 @@ static ModifierData *curve_get_tessellate_point(Scene *scene,
/* Return true if any modifier was applied. */
bool BKE_curve_calc_modifiers_pre(Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
ListBase *source_nurb,
ListBase *target_nurb,
@@ -876,7 +880,7 @@ static float (*displist_vert_coords_alloc(ListBase *dispbase, int *r_vert_len))[
return allverts;
}
static void displist_vert_coords_apply(ListBase *dispbase, float (*allverts)[3])
static void displist_vert_coords_apply(ListBase *dispbase, const float (*allverts)[3])
{
const float *fp;
@@ -889,9 +893,8 @@ static void displist_vert_coords_apply(ListBase *dispbase, float (*allverts)[3])
}
static void curve_calc_modifiers_post(Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
ListBase *nurb,
ListBase *dispbase,
Mesh **r_final,
const bool for_render,
@@ -900,7 +903,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
VirtualModifierData virtualModifierData;
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
ModifierData *pretessellatePoint;
Curve *cu = ob->data;
const Curve *cu = ob->data;
int required_mode = 0, totvert = 0;
const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
Mesh *modified = NULL, *mesh_applied;
@@ -952,7 +955,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
}
if (ELEM(ob->type, OB_CURVE, OB_FONT) && (cu->flag & CU_DEFORM_FILL)) {
curve_to_filledpoly(cu, nurb, dispbase);
curve_to_filledpoly(cu, dispbase);
}
modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
@@ -1001,7 +1004,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
}
if (ELEM(ob->type, OB_CURVE, OB_FONT) && (cu->flag & CU_DEFORM_FILL)) {
curve_to_filledpoly(cu, nurb, dispbase);
curve_to_filledpoly(cu, dispbase);
}
modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
@@ -1126,7 +1129,7 @@ static void displist_surf_indices(DispList *dl)
}
void BKE_displist_make_surf(Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
ListBase *dispbase,
Mesh **r_final,
@@ -1230,7 +1233,7 @@ void BKE_displist_make_surf(Depsgraph *depsgraph,
if (!for_orco) {
BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
curve_calc_modifiers_post(
depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, force_mesh_conversion);
depsgraph, scene, ob, dispbase, r_final, for_render, force_mesh_conversion);
}
BKE_nurbList_free(&nubase);
@@ -1297,7 +1300,10 @@ static void rotateBevelPiece(const Curve *cu,
*r_data = data;
}
static void fillBevelCap(Nurb *nu, DispList *dlb, float *prev_fp, ListBase *dispbase)
static void fillBevelCap(const Nurb *nu,
const DispList *dlb,
const float *prev_fp,
ListBase *dispbase)
{
DispList *dl;
@@ -1320,7 +1326,7 @@ static void fillBevelCap(Nurb *nu, DispList *dlb, float *prev_fp, ListBase *disp
}
static void calc_bevfac_segment_mapping(
BevList *bl, float bevfac, float spline_length, int *r_bev, float *r_blend)
const BevList *bl, float bevfac, float spline_length, int *r_bev, float *r_blend)
{
float normlen, normsum = 0.0f;
float *seglen = bl->seglen;
@@ -1346,7 +1352,7 @@ static void calc_bevfac_segment_mapping(
}
static void calc_bevfac_spline_mapping(
BevList *bl, float bevfac, float spline_length, int *r_bev, float *r_blend)
const BevList *bl, float bevfac, float spline_length, int *r_bev, float *r_blend)
{
const float len_target = bevfac * spline_length;
BevPoint *bevp = bl->bevpoints;
@@ -1368,7 +1374,7 @@ static void calc_bevfac_spline_mapping(
}
static void calc_bevfac_mapping_default(
BevList *bl, int *r_start, float *r_firstblend, int *r_steps, float *r_lastblend)
const BevList *bl, int *r_start, float *r_firstblend, int *r_steps, float *r_lastblend)
{
*r_start = 0;
*r_steps = bl->nr;
@@ -1376,9 +1382,9 @@ static void calc_bevfac_mapping_default(
*r_lastblend = 1.0f;
}
static void calc_bevfac_mapping(Curve *cu,
BevList *bl,
Nurb *nu,
static void calc_bevfac_mapping(const Curve *cu,
const BevList *bl,
const Nurb *nu,
int *r_start,
float *r_firstblend,
int *r_steps,
@@ -1456,7 +1462,7 @@ static void calc_bevfac_mapping(Curve *cu,
}
static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
ListBase *dispbase,
const bool for_render,
@@ -1691,7 +1697,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
}
if (!(cu->flag & CU_DEFORM_FILL)) {
curve_to_filledpoly(cu, &nubase, dispbase);
curve_to_filledpoly(cu, dispbase);
}
if (!for_orco) {
@@ -1702,19 +1708,22 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
curve_calc_modifiers_post(
depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, force_mesh_conversion);
depsgraph, scene, ob, dispbase, r_final, for_render, force_mesh_conversion);
}
if (cu->flag & CU_DEFORM_FILL && !ob->runtime.data_eval) {
curve_to_filledpoly(cu, &nubase, dispbase);
curve_to_filledpoly(cu, dispbase);
}
BKE_nurbList_free(&nubase);
}
}
void BKE_displist_make_curveTypes(
Depsgraph *depsgraph, Scene *scene, Object *ob, const bool for_render, const bool for_orco)
void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
const bool for_render,
const bool for_orco)
{
ListBase *dispbase;
@@ -1744,7 +1753,7 @@ void BKE_displist_make_curveTypes(
}
void BKE_displist_make_curveTypes_forRender(Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
ListBase *dispbase,
Mesh **r_final,
@@ -1757,13 +1766,13 @@ void BKE_displist_make_curveTypes_forRender(Depsgraph *depsgraph,
do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, true, for_orco, r_final);
}
void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3])
void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3])
{
const float *vert;
int a, tot = 0;
int doit = 0;
LISTBASE_FOREACH (DispList *, dl, dispbase) {
LISTBASE_FOREACH (const DispList *, dl, dispbase) {
tot = (dl->type == DL_INDEX3) ? dl->nr : dl->nr * dl->parts;
vert = dl->verts;
for (a = 0; a < tot; a++, vert += 3) {

View File

@@ -108,6 +108,16 @@ bool InstancesComponent::is_empty() const
return transforms_.size() == 0;
}
bool InstancesComponent::owns_direct_data() const
{
return true;
}
void InstancesComponent::ensure_owns_direct_data()
{
BLI_assert(this->is_mutable());
}
static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
{
using namespace blender;

View File

@@ -157,6 +157,20 @@ bool MeshComponent::is_empty() const
return mesh_ == nullptr;
}
bool MeshComponent::owns_direct_data() const
{
return ownership_ == GeometryOwnershipType::Owned;
}
void MeshComponent::ensure_owns_direct_data()
{
BLI_assert(this->is_mutable());
if (ownership_ != GeometryOwnershipType::Owned) {
mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
ownership_ = GeometryOwnershipType::Owned;
}
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -107,6 +107,20 @@ bool PointCloudComponent::is_empty() const
return pointcloud_ == nullptr;
}
bool PointCloudComponent::owns_direct_data() const
{
return ownership_ == GeometryOwnershipType::Owned;
}
void PointCloudComponent::ensure_owns_direct_data()
{
BLI_assert(this->is_mutable());
if (ownership_ != GeometryOwnershipType::Owned) {
pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
ownership_ = GeometryOwnershipType::Owned;
}
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -97,4 +97,18 @@ Volume *VolumeComponent::get_for_write()
return volume_;
}
bool VolumeComponent::owns_direct_data() const
{
return ownership_ == GeometryOwnershipType::Owned;
}
void VolumeComponent::ensure_owns_direct_data()
{
BLI_assert(this->is_mutable());
if (ownership_ != GeometryOwnershipType::Owned) {
volume_ = BKE_volume_copy_for_eval(volume_, false);
ownership_ = GeometryOwnershipType::Owned;
}
}
/** \} */

View File

@@ -211,6 +211,19 @@ void GeometrySet::clear()
components_.clear();
}
/* Make sure that the geometry can be cached. This does not ensure ownership of object/collection
* instances. */
void GeometrySet::ensure_owns_direct_data()
{
for (GeometryComponentType type : components_.keys()) {
const GeometryComponent *component = this->get_component_for_read(type);
if (!component->owns_direct_data()) {
GeometryComponent &component_for_write = this->get_component_for_write(type);
component_for_write.ensure_owns_direct_data();
}
}
}
/* Returns a read-only mesh or null. */
const Mesh *GeometrySet::get_mesh_for_read() const
{

View File

@@ -94,6 +94,7 @@ static void lattice_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const i
}
lattice_dst->editlatt = NULL;
lattice_dst->batch_cache = NULL;
}
static void lattice_free_data(ID *id)

View File

@@ -1756,6 +1756,10 @@ void BKE_object_free_derived_caches(Object *ob)
BKE_geometry_set_free(ob->runtime.geometry_set_eval);
ob->runtime.geometry_set_eval = NULL;
}
if (ob->runtime.geometry_set_preview != NULL) {
BKE_geometry_set_free(ob->runtime.geometry_set_preview);
ob->runtime.geometry_set_preview = NULL;
}
}
void BKE_object_free_caches(Object *object)
@@ -1806,6 +1810,18 @@ void BKE_object_free_caches(Object *object)
}
}
/* Can be called from multiple threads. */
void BKE_object_preview_geometry_set(Object *ob, struct GeometrySet *geometry_set)
{
static ThreadMutex mutex = BLI_MUTEX_INITIALIZER;
BLI_mutex_lock(&mutex);
if (ob->runtime.geometry_set_preview != NULL) {
BKE_geometry_set_free(ob->runtime.geometry_set_preview);
}
ob->runtime.geometry_set_preview = geometry_set;
BLI_mutex_unlock(&mutex);
}
/**
* Actual check for internal data, not context or flags.
*/

View File

@@ -16,6 +16,7 @@
#pragma once
#include <optional>
#include <type_traits>
#include <utility>
@@ -139,6 +140,29 @@ template<typename Ret, typename... Params> class FunctionRef<Ret(Params...)> {
return callback_(callable_, std::forward<Params>(params)...);
}
using OptionalReturnValue = std::conditional_t<std::is_void_v<Ret>, void, std::optional<Ret>>;
/**
* Calls the referenced function if it is available.
* The return value is of type `std::optional<Ret>` if `Ret` is not `void`.
* Otherwise the return type is `void`.
*/
OptionalReturnValue call_safe(Params... params) const
{
if constexpr (std::is_void_v<Ret>) {
if (callback_ == nullptr) {
return;
}
callback_(callable_, std::forward<Params>(params)...);
}
else {
if (callback_ == nullptr) {
return {};
}
return callback_(callable_, std::forward<Params>(params)...);
}
}
/**
* Returns true, when the `FunctionRef` references a function currently.
* If this returns false, the `FunctionRef` must not be called.

View File

@@ -133,6 +133,9 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
*/
template<typename T> MutableSpan<T> construct_array_copy(Span<T> src)
{
if (src.is_empty()) {
return {};
}
MutableSpan<T> dst = this->allocate_array<T>(src.size());
uninitialized_copy_n(src.data(), src.size(), dst.data());
return dst;

View File

@@ -266,6 +266,9 @@ void orthogonalize_m4(float R[4][4], int axis);
void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize);
void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize);
bool orthogonalize_m3_zero_axes(float R[3][3], const float unit_length);
bool orthogonalize_m4_zero_axes(float R[4][4], const float unit_length);
bool is_orthogonal_m3(const float mat[3][3]);
bool is_orthogonal_m4(const float mat[4][4]);
bool is_orthonormal_m3(const float mat[3][3]);

View File

@@ -17,13 +17,13 @@
/** \file
* \ingroup bli
*
* Common implementation of linked-list a non-recursive mergesort.
* Common implementation of linked-list a non-recursive merge-sort.
*
* Originally from Mono's eglib, adapted for portable inclusion.
* Originally from Mono's `eglib`, adapted for portable inclusion.
* This file is to be directly included in C-source,
* with defines to control its use.
*
* This code requires a typedef named `SORT_IMPL_LINKTYPE` for the list node.
* This code requires a `typedef` named `SORT_IMPL_LINKTYPE` for the list node.
* It is assumed that the list type is the type of a pointer to a list
* node, and that the node has a field named 'next' that implements to
* the linked list. No additional invariant is maintained

View File

@@ -1700,6 +1700,89 @@ void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize)
}
}
/* -------------------------------------------------------------------- */
/** \name Orthogonalize Matrix Zeroed Axes
*
* Set any zeroed axes to an orthogonal vector in relation to the other axes.
*
* Typically used so matrix inversion can be performed.
*
* \note If an object has a zero scaled axis, this function can be used to "clean" the matrix
* to behave as if the scale on that axis was `unit_length`. So it can be inverted
* or used in matrix multiply without creating degenerate matrices, see: T50103
* \{ */
/**
* \return true if any axis needed to be modified.
*/
static bool orthogonalize_m3_zero_axes_impl(float *mat[3], const float unit_length)
{
enum { X = 1 << 0, Y = 1 << 1, Z = 1 << 2 };
int flag = 0;
for (int i = 0; i < 3; i++) {
flag |= (len_squared_v3(mat[i]) == 0.0f) ? (1 << i) : 0;
}
/* Either all or none are zero, either way we can't properly resolve this
* since we need to fill invalid axes from valid ones. */
if (ELEM(flag, 0, X | Y | Z)) {
return false;
}
switch (flag) {
case X | Y: {
ortho_v3_v3(mat[1], mat[2]);
ATTR_FALLTHROUGH;
}
case X: {
cross_v3_v3v3(mat[0], mat[1], mat[2]);
break;
}
case Y | Z: {
ortho_v3_v3(mat[2], mat[0]);
ATTR_FALLTHROUGH;
}
case Y: {
cross_v3_v3v3(mat[1], mat[0], mat[2]);
break;
}
case Z | X: {
ortho_v3_v3(mat[0], mat[1]);
ATTR_FALLTHROUGH;
}
case Z: {
cross_v3_v3v3(mat[2], mat[0], mat[1]);
break;
}
default: {
BLI_assert(0); /* Unreachable! */
}
}
for (int i = 0; i < 3; i++) {
if (flag & (1 << i)) {
if (UNLIKELY(normalize_v3_length(mat[i], unit_length) == 0.0f)) {
mat[i][i] = unit_length;
}
}
}
return true;
}
bool orthogonalize_m3_zero_axes(float m[3][3], const float unit_length)
{
return orthogonalize_m3_zero_axes_impl((float *[3]){UNPACK3(m)}, unit_length);
}
bool orthogonalize_m4_zero_axes(float m[4][4], const float unit_length)
{
return orthogonalize_m3_zero_axes_impl((float *[3]){UNPACK3(m)}, unit_length);
}
/** \} */
bool is_orthogonal_m3(const float m[3][3])
{
int i, j;
@@ -3195,68 +3278,6 @@ void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4])
* where we want to specify the length of the degenerate axes.
* \{ */
/**
* Return true if invert should be attempted again.
*
* \note Takes an array of points to be usable from 3x3 and 4x4 matrices.
*/
static bool invert_m3_m3_safe_ortho_prepare(float *mat[3])
{
enum { X = 1 << 0, Y = 1 << 1, Z = 1 << 2 };
int flag = 0;
for (int i = 0; i < 3; i++) {
flag |= (len_squared_v3(mat[i]) == 0.0f) ? (1 << i) : 0;
}
/* Either all or none are zero, either way we can't properly resolve this
* since we need to fill invalid axes from valid ones. */
if (ELEM(flag, 0, X | Y | Z)) {
return false;
}
switch (flag) {
case X | Y: {
ortho_v3_v3(mat[1], mat[2]);
ATTR_FALLTHROUGH;
}
case X: {
cross_v3_v3v3(mat[0], mat[1], mat[2]);
break;
}
case Y | Z: {
ortho_v3_v3(mat[2], mat[0]);
ATTR_FALLTHROUGH;
}
case Y: {
cross_v3_v3v3(mat[1], mat[0], mat[2]);
break;
}
case Z | X: {
ortho_v3_v3(mat[0], mat[1]);
ATTR_FALLTHROUGH;
}
case Z: {
cross_v3_v3v3(mat[2], mat[0], mat[1]);
break;
}
default: {
BLI_assert(0); /* Unreachable! */
}
}
for (int i = 0; i < 3; i++) {
if (flag & (1 << i)) {
if (UNLIKELY(normalize_v3(mat[i]) == 0.0f)) {
mat[i][i] = 1.0f;
}
}
}
return true;
}
/**
* A safe version of invert that uses valid axes, calculating the zero'd axis
* based on the non-zero ones.
@@ -3268,8 +3289,7 @@ void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4])
if (UNLIKELY(!invert_m4_m4(Ainv, A))) {
float Atemp[4][4];
copy_m4_m4(Atemp, A);
if (UNLIKELY(!(invert_m3_m3_safe_ortho_prepare((float *[3]){UNPACK3(Atemp)}) &&
invert_m4_m4(Ainv, Atemp)))) {
if (UNLIKELY(!(orthogonalize_m4_zero_axes(Atemp, 1.0f) && invert_m4_m4(Ainv, Atemp)))) {
unit_m4(Ainv);
}
}
@@ -3280,8 +3300,7 @@ void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3])
if (UNLIKELY(!invert_m3_m3(Ainv, A))) {
float Atemp[3][3];
copy_m3_m3(Atemp, A);
if (UNLIKELY(!(invert_m3_m3_safe_ortho_prepare((float *[3]){UNPACK3(Atemp)}) &&
invert_m3_m3(Ainv, Atemp)))) {
if (UNLIKELY(!(orthogonalize_m3_zero_axes(Atemp, 1.0f) && invert_m3_m3(Ainv, Atemp)))) {
unit_m3(Ainv);
}
}

View File

@@ -1121,7 +1121,7 @@ static float voronoi_CrS(float x, float y, float z)
/** \name Cell-Noise Implementation
* \{ */
/* returns unsigned cellnoise */
/** Returns unsigned cell-noise. */
static float BLI_cellNoiseU(float x, float y, float z)
{
/* avoid precision issues on unit coordinates */
@@ -1166,7 +1166,9 @@ void BLI_noise_cell_v3(float x, float y, float z, float ca[3])
/** \name Public API's
* \{ */
/* newnoise: generic noise function for use with different noisebases */
/**
* newnoise: generic noise function for use with different `noisebasis`.
*/
float BLI_noise_generic_noise(
float noisesize, float x, float y, float z, bool hard, int noisebasis)
{

View File

@@ -1044,17 +1044,17 @@ bool BLI_path_abs(char *path, const char *basepath)
#else
BLI_strncpy(tmp, path, sizeof(tmp));
/* Check for loading a windows path on a posix system
* in this case, there is no use in trying C:/ since it
* will never exist on a unix os.
/* Check for loading a MS-Windows path on a POSIX system
* in this case, there is no use in trying `C:/` since it
* will never exist on a Unix system.
*
* Add a '/' prefix and lowercase the drive-letter, remove the ':'.
* C:\foo.JPG -> /c/foo.JPG */
* Add a `/` prefix and lowercase the drive-letter, remove the `:`.
* `C:\foo.JPG` -> `/c/foo.JPG` */
if (isalpha(tmp[0]) && (tmp[1] == ':') && ELEM(tmp[2], '\\', '/')) {
tmp[1] = tolower(tmp[0]); /* Replace ':' with drive-letter. */
tmp[0] = '/';
/* '\' the slash will be converted later */
/* `\` the slash will be converted later. */
}
#endif

View File

@@ -99,4 +99,29 @@ TEST(function_ref, ReferenceAnotherFunctionRef)
EXPECT_EQ(y(), 2);
}
TEST(function_ref, CallSafe)
{
FunctionRef<int()> f;
EXPECT_FALSE(f.call_safe().has_value());
auto func = []() { return 10; };
f = func;
EXPECT_TRUE(f.call_safe().has_value());
EXPECT_EQ(*f.call_safe(), 10);
f = {};
EXPECT_FALSE(f.call_safe().has_value());
BLI_STATIC_ASSERT((std::is_same_v<decltype(f.call_safe()), std::optional<int>>), "");
}
TEST(function_ref, CallSafeVoid)
{
FunctionRef<void()> f;
BLI_STATIC_ASSERT((std::is_same_v<decltype(f.call_safe()), void>), "");
f.call_safe();
int value = 0;
auto func = [&]() { value++; };
f = func;
f.call_safe();
EXPECT_EQ(value, 1);
}
} // namespace blender::tests

View File

@@ -1814,7 +1814,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) {
if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "bleedexp")) {
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "bleedexp")) {
for (Light *la = bmain->lights.first; la; la = la->id.next) {
la->bleedexp = 2.5f;
}
@@ -1840,7 +1840,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) {
if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "cascade_max_dist")) {
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "cascade_max_dist")) {
for (Light *la = bmain->lights.first; la; la = la->id.next) {
la->cascade_max_dist = 1000.0f;
la->cascade_count = 4;
@@ -1849,7 +1849,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "contact_dist")) {
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "contact_dist")) {
for (Light *la = bmain->lights.first; la; la = la->id.next) {
la->contact_dist = 0.2f;
la->contact_bias = 0.03f;
@@ -2185,7 +2185,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 13)) {
/* Initialize specular factor. */
if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "spec_fac")) {
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "spec_fac")) {
for (Light *la = bmain->lights.first; la; la = la->id.next) {
la->spec_fac = 1.0f;
}
@@ -3135,7 +3135,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "att_dist")) {
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "att_dist")) {
for (Light *la = bmain->lights.first; la; la = la->id.next) {
la->att_dist = la->clipend;
}
@@ -4051,7 +4051,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
/* Initializes sun lights with the new angular diameter property */
if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "sun_angle")) {
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "sun_angle")) {
LISTBASE_FOREACH (Light *, light, &bmain->lights) {
light->sun_angle = 2.0f * atanf(light->area_size);
}

View File

@@ -1908,7 +1908,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 293, 14)) {
if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "diff_fac")) {
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "diff_fac")) {
LISTBASE_FOREACH (Light *, light, &bmain->lights) {
light->diff_fac = 1.0f;
light->volume_fac = 1.0f;
@@ -1963,5 +1963,25 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
arm->axes_position = 1.0;
}
}
/* Initialize the spread parameter for area lights*/
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "area_spread")) {
LISTBASE_FOREACH (Light *, la, &bmain->lights) {
la->area_spread = DEG2RADF(180.0f);
}
}
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) {
STRNCPY(path->display_name, path->node_name);
}
}
}
}
}
}
}

View File

@@ -121,11 +121,9 @@ NodeOperation *ExecutionGroup::getOutputOperation() const
->m_operations[0]; /* the first operation of the group is always the output operation. */
}
void ExecutionGroup::initExecution()
void ExecutionGroup::init_work_packages()
{
m_work_packages.clear();
determineNumberOfChunks();
if (this->m_chunks_len != 0) {
m_work_packages.resize(this->m_chunks_len);
for (unsigned int index = 0; index < m_chunks_len; index++) {
@@ -135,9 +133,11 @@ void ExecutionGroup::initExecution()
determineChunkRect(&m_work_packages[index].rect, index);
}
}
}
void ExecutionGroup::init_read_buffer_operations()
{
unsigned int max_offset = 0;
for (NodeOperation *operation : m_operations) {
if (operation->get_flags().is_read_buffer_operation) {
ReadBufferOperation *readOperation = static_cast<ReadBufferOperation *>(operation);
@@ -149,6 +149,13 @@ void ExecutionGroup::initExecution()
this->m_max_read_buffer_offset = max_offset;
}
void ExecutionGroup::initExecution()
{
init_number_of_chunks();
init_work_packages();
init_read_buffer_operations();
}
void ExecutionGroup::deinitExecution()
{
m_work_packages.clear();
@@ -158,6 +165,7 @@ void ExecutionGroup::deinitExecution()
this->m_read_operations.clear();
this->m_bTree = nullptr;
}
void ExecutionGroup::determineResolution(unsigned int resolution[2])
{
NodeOperation *operation = this->getOutputOperation();
@@ -167,7 +175,7 @@ void ExecutionGroup::determineResolution(unsigned int resolution[2])
BLI_rcti_init(&this->m_viewerBorder, 0, this->m_width, 0, this->m_height);
}
void ExecutionGroup::determineNumberOfChunks()
void ExecutionGroup::init_number_of_chunks()
{
if (this->m_flags.single_threaded) {
this->m_x_chunks_len = 1;
@@ -184,7 +192,7 @@ void ExecutionGroup::determineNumberOfChunks()
}
}
blender::Array<unsigned int> ExecutionGroup::determine_chunk_execution_order() const
blender::Array<unsigned int> ExecutionGroup::get_execution_order() const
{
blender::Array<unsigned int> chunk_order(m_chunks_len);
for (int chunk_index = 0; chunk_index < this->m_chunks_len; chunk_index++) {
@@ -302,7 +310,7 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
this->m_chunks_finished = 0;
this->m_bTree = bTree;
blender::Array<unsigned int> chunk_order = determine_chunk_execution_order();
blender::Array<unsigned int> chunk_order = get_execution_order();
DebugInfo::execution_group_started(this);
DebugInfo::graphviz(graph);

View File

@@ -178,7 +178,7 @@ class ExecutionGroup {
* \brief determine the number of chunks, based on the chunkSize, width and height.
* \note The result are stored in the fields numberOfChunks, numberOfXChunks, numberOfYChunks
*/
void determineNumberOfChunks();
void init_number_of_chunks();
/**
* \brief try to schedule a specific chunk.
@@ -225,7 +225,10 @@ class ExecutionGroup {
/**
* Return the execution order of the user visible chunks.
*/
blender::Array<unsigned int> determine_chunk_execution_order() const;
blender::Array<unsigned int> get_execution_order() const;
void init_read_buffer_operations();
void init_work_packages();
public:
// constructors

View File

@@ -63,12 +63,12 @@ class Node {
protected:
/**
* \brief the list of actual inputsockets \see NodeInput
* \brief the list of actual input-sockets \see NodeInput
*/
blender::Vector<NodeInput *> inputs;
/**
* \brief the list of actual outputsockets \see NodeOutput
* \brief the list of actual output-sockets \see NodeOutput
*/
blender::Vector<NodeOutput *> outputs;
@@ -184,7 +184,7 @@ class Node {
protected:
/**
* \brief add an NodeInput to the collection of inputsockets
* \brief add an NodeInput to the collection of input-sockets
* \note may only be called in an constructor
* \param socket: the NodeInput to add
*/
@@ -192,7 +192,7 @@ class Node {
void addInputSocket(DataType datatype, bNodeSocket *socket);
/**
* \brief add an NodeOutput to the collection of outputsockets
* \brief add an NodeOutput to the collection of output-sockets
* \note may only be called in an constructor
* \param socket: the NodeOutput to add
*/

View File

@@ -4863,6 +4863,11 @@ static int userpref_show_exec(bContext *C, wmOperator *op)
region->flag |= RGN_FLAG_HIDDEN;
ED_region_visibility_change_update(C, area, region);
/* And also show the region with "Load & Save" buttons. */
region = BKE_area_find_region_type(area, RGN_TYPE_EXECUTE);
region->flag &= ~RGN_FLAG_HIDDEN;
ED_region_visibility_change_update(C, area, region);
return OPERATOR_FINISHED;
}
BKE_report(op->reports, RPT_ERROR, "Failed to open window!");

View File

@@ -648,6 +648,19 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static char *actkeys_paste_description(bContext *UNUSED(C),
wmOperatorType *UNUSED(op),
PointerRNA *ptr)
{
/* Custom description if the 'flipped' option is used. */
if (RNA_boolean_get(ptr, "flipped")) {
return BLI_strdup("Paste keyframes from mirrored bones if they exist");
}
/* Use the default description in the other cases. */
return NULL;
}
void ACTION_OT_paste(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -660,6 +673,7 @@ void ACTION_OT_paste(wmOperatorType *ot)
/* api callbacks */
// ot->invoke = WM_operator_props_popup; // better wait for action redo panel
ot->get_description = actkeys_paste_description;
ot->exec = actkeys_paste_exec;
ot->poll = ED_operator_action_active;

View File

@@ -578,6 +578,19 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static char *graphkeys_paste_description(bContext *UNUSED(C),
wmOperatorType *UNUSED(op),
PointerRNA *ptr)
{
/* Custom description if the 'flipped' option is used. */
if (RNA_boolean_get(ptr, "flipped")) {
return BLI_strdup("Paste keyframes from mirrored bones if they exist");
}
/* Use the default description in the other cases. */
return NULL;
}
void GRAPH_OT_paste(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -592,6 +605,7 @@ void GRAPH_OT_paste(wmOperatorType *ot)
/* API callbacks */
// ot->invoke = WM_operator_props_popup; /* better wait for graph redo panel */
ot->get_description = graphkeys_paste_description;
ot->exec = graphkeys_paste_exec;
ot->poll = graphop_editable_keyframes_poll;

View File

@@ -1959,8 +1959,8 @@ void node_draw_space(const bContext *C, ARegion *region)
ID *name_id = (path->nodetree && path->nodetree != snode->nodetree) ? &path->nodetree->id :
snode->id;
if (name_id && UNLIKELY(!STREQ(path->node_name, name_id->name + 2))) {
BLI_strncpy(path->node_name, name_id->name + 2, sizeof(path->node_name));
if (name_id && UNLIKELY(!STREQ(path->display_name, name_id->name + 2))) {
BLI_strncpy(path->display_name, name_id->name + 2, sizeof(path->display_name));
}
/* Current View2D center, will be set temporarily for parent node trees. */

View File

@@ -41,6 +41,7 @@
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -670,6 +671,21 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti
nodeSetActive(ntree, node);
/* Tag for update, so that dependend objects are reevaluated. This is necessary when a
* spreadsheet editor displays data from a node. */
LISTBASE_FOREACH (wmWindow *, window, &((wmWindowManager *)bmain->wm.first)->windows) {
bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area->spacetype == SPACE_SPREADSHEET) {
SpaceSpreadsheet *sspreadsheet = area->spacedata.first;
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_NODE) {
DEG_id_tag_update(&ntree->id, ID_RECALC_COPY_ON_WRITE);
ED_area_tag_redraw(area);
}
}
}
}
if (node->type != NODE_GROUP) {
const bool was_output = (node->flag & NODE_DO_OUTPUT) != 0;
bool do_update = false;

View File

@@ -74,7 +74,7 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
copy_v2_v2(path->view_center, ntree->view_center);
if (id) {
BLI_strncpy(path->node_name, id->name + 2, sizeof(path->node_name));
BLI_strncpy(path->display_name, id->name + 2, sizeof(path->display_name));
}
BLI_addtail(&snode->treepath, path);
@@ -111,6 +111,7 @@ void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
}
BLI_strncpy(path->node_name, gnode->name, sizeof(path->node_name));
BLI_strncpy(path->display_name, gnode->name, sizeof(path->display_name));
}
else {
path->parent_key = NODE_INSTANCE_KEY_BASE;
@@ -175,7 +176,7 @@ int ED_node_tree_path_length(SpaceNode *snode)
int length = 0;
int i = 0;
LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) {
length += strlen(path->node_name);
length += strlen(path->display_name);
if (i > 0) {
length += 1; /* for separator char */
}
@@ -190,12 +191,12 @@ void ED_node_tree_path_get(SpaceNode *snode, char *value)
value[0] = '\0';
LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) {
if (i == 0) {
strcpy(value, path->node_name);
value += strlen(path->node_name);
strcpy(value, path->display_name);
value += strlen(path->display_name);
}
else {
sprintf(value, "/%s", path->node_name);
value += strlen(path->node_name) + 1;
sprintf(value, "/%s", path->display_name);
value += strlen(path->display_name) + 1;
}
}
}
@@ -208,10 +209,10 @@ void ED_node_tree_path_get_fixedbuf(SpaceNode *snode, char *value, int max_lengt
int i = 0;
LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) {
if (i == 0) {
size = BLI_strncpy_rlen(value, path->node_name, max_length);
size = BLI_strncpy_rlen(value, path->display_name, max_length);
}
else {
size = BLI_snprintf_rlen(value, max_length, "/%s", path->node_name);
size = BLI_snprintf_rlen(value, max_length, "/%s", path->display_name);
}
max_length -= size;
if (max_length <= 0) {

View File

@@ -1104,7 +1104,7 @@ static bool collection_drop_init(bContext *C,
const wmEvent *event,
CollectionDrop *data)
{
/* Get collection to drop into. */
/* Get collection to drop into. */
TreeElementInsertType insert_type;
TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type);
if (!te) {

View File

@@ -200,25 +200,7 @@ static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet,
const GeometryComponentType used_component_type)
{
GeometrySet geometry_set;
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) {
if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) {
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
if (mesh == nullptr) {
return geometry_set;
}
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_eval);
}
else {
if (object_eval->runtime.geometry_set_eval != nullptr) {
/* This does not copy the geometry data itself. */
geometry_set = *object_eval->runtime.geometry_set_eval;
}
}
}
else {
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
Object *object_orig = DEG_get_original_object(object_eval);
if (object_orig->type == OB_MESH) {
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
@@ -247,6 +229,30 @@ static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet,
pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly);
}
}
else {
if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) {
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
if (mesh == nullptr) {
return geometry_set;
}
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_eval);
}
else {
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_NODE) {
if (object_eval->runtime.geometry_set_preview != nullptr) {
geometry_set = *object_eval->runtime.geometry_set_preview;
}
}
else if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) {
if (object_eval->runtime.geometry_set_eval != nullptr) {
geometry_set = *object_eval->runtime.geometry_set_eval;
}
}
}
}
return geometry_set;
}
@@ -377,7 +383,7 @@ static Span<int64_t> filter_mesh_elements_by_selection(const bContext *C,
static GeometryComponentType get_display_component_type(const bContext *C, Object *object_eval)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) {
if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
return (GeometryComponentType)sspreadsheet->geometry_component_type;
}
if (object_eval->type == OB_POINTCLOUD) {

View File

@@ -79,7 +79,7 @@ static SpaceLink *userpref_create(const ScrArea *area, const Scene *UNUSED(scene
BLI_addtail(&spref->regionbase, region);
region->regiontype = RGN_TYPE_EXECUTE;
region->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
region->flag |= RGN_FLAG_DYNAMIC_SIZE;
region->flag |= RGN_FLAG_DYNAMIC_SIZE | RGN_FLAG_HIDDEN;
/* main region */
region = MEM_callocN(sizeof(ARegion), "main region for userpref");
@@ -251,6 +251,7 @@ void ED_spacetype_userpref(void)
/* regions: execution window */
art = MEM_callocN(sizeof(ARegionType), "spacetype userpref region");
art->regionid = RGN_TYPE_EXECUTE;
art->prefsizey = HEADERY;
art->init = userpref_execute_region_init;
art->layout = ED_region_panels_layout;
art->draw = ED_region_panels_draw;

View File

@@ -282,9 +282,17 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
*/
BKE_object_to_mat3(ob, obmtx);
copy_m3_m4(totmat, ob->obmat);
invert_m3_m3(obinv, totmat);
/* If the object scale is zero on any axis, this might result in a zero matrix.
* In this case, the transformation would not do anything, see: T50103. */
orthogonalize_m3_zero_axes(obmtx, 1.0f);
orthogonalize_m3_zero_axes(totmat, 1.0f);
/* Use safe invert even though the input matrices have had zero axes set to unit length,
* in the unlikely case of failure (float precision for eg) this uses unit matrix fallback. */
invert_m3_m3_safe_ortho(obinv, totmat);
mul_m3_m3m3(td->smtx, obmtx, obinv);
invert_m3_m3(td->mtx, td->smtx);
invert_m3_m3_safe_ortho(td->mtx, td->smtx);
}
else {
/* no conversion to/from dataspace */

View File

@@ -103,7 +103,6 @@ static void generate_strokes_actual(
lmd->transparency_mask,
lmd->thickness,
lmd->opacity,
lmd->resample_length,
lmd->source_vertex_group,
lmd->vgname,
lmd->flags);
@@ -381,8 +380,6 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "chaining_image_threshold", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "resample_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemR(layout, ptr, "split_angle", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
@@ -411,8 +408,6 @@ static void vgroup_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemPointerR(
col, ptr, "vertex_group", &ob_ptr, "vertex_groups", IFACE_("Target"), ICON_NONE);
}
uiItemR(col, ptr, "use_soft_selection", 0, NULL, ICON_NONE);
}
static void baking_panel_draw(const bContext *UNUSED(C), Panel *panel)

View File

@@ -560,7 +560,6 @@ void MOD_lineart_gpencil_generate(LineartRenderBuffer *rb,
unsigned char transparency_mask,
short thickness,
float opacity,
float resample_length,
const char *source_vgname,
const char *vgname,
int modifier_flags);

View File

@@ -3768,7 +3768,6 @@ static void lineart_gpencil_generate(LineartRenderBuffer *rb,
uchar transparency_mask,
short thickness,
float opacity,
float resample_length,
const char *source_vgname,
const char *vgname,
int modifier_flags)
@@ -3802,7 +3801,6 @@ static void lineart_gpencil_generate(LineartRenderBuffer *rb,
int enabled_types = lineart_rb_edge_types(rb);
bool invert_input = modifier_flags & LRT_GPENCIL_INVERT_SOURCE_VGROUP;
bool match_output = modifier_flags & LRT_GPENCIL_MATCH_OUTPUT_VGROUP;
bool preserve_weight = modifier_flags & LRT_GPENCIL_SOFT_SELECTION;
LISTBASE_FOREACH (LineartLineChain *, rlc, &rb->chains) {
@@ -3886,18 +3884,13 @@ static void lineart_gpencil_generate(LineartRenderBuffer *rb,
}
MDeformWeight *mdw = BKE_defvert_ensure_index(&me->dvert[vindex], dindex);
MDeformWeight *gdw = BKE_defvert_ensure_index(&gps->dvert[sindex], gpdg);
if (preserve_weight) {
float use_weight = mdw->weight;
if (invert_input) {
use_weight = 1 - use_weight;
}
gdw->weight = MAX2(use_weight, gdw->weight);
}
else {
if (mdw->weight > 0.999f) {
gdw->weight = 1.0f;
}
float use_weight = mdw->weight;
if (invert_input) {
use_weight = 1 - use_weight;
}
gdw->weight = MAX2(use_weight, gdw->weight);
sindex++;
}
}
@@ -3908,9 +3901,6 @@ static void lineart_gpencil_generate(LineartRenderBuffer *rb,
}
}
if (resample_length > 0.0001) {
BKE_gpencil_stroke_sample(gpencil_object->data, gps, resample_length, false);
}
if (G.debug_value == 4000) {
BKE_gpencil_stroke_set_random_color(gps);
}
@@ -3941,7 +3931,6 @@ void MOD_lineart_gpencil_generate(LineartRenderBuffer *rb,
uchar transparency_mask,
short thickness,
float opacity,
float resample_length,
const char *source_vgname,
const char *vgname,
int modifier_flags)
@@ -3991,7 +3980,6 @@ void MOD_lineart_gpencil_generate(LineartRenderBuffer *rb,
transparency_mask,
thickness,
opacity,
resample_length,
source_vgname,
vgname,
modifier_flags);

View File

@@ -131,7 +131,6 @@ static bool bake_strokes(Object *ob, Depsgraph *dg, GpencilModifierData *md, int
lmd->transparency_mask,
lmd->thickness,
lmd->opacity,
lmd->resample_length,
lmd->source_vertex_group,
lmd->vgname,
lmd->flags);

View File

@@ -1140,6 +1140,7 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim, int64_t requested_p
* small. */
for (int offset = 5; offset < 25; offset++) {
current_pos = requested_pos - ((int64_t)(offset)*AV_TIME_BASE / frame_rate);
current_pos = max_ii(current_pos, 0);
/* Seek to timestamp. */
if (av_seek_frame(anim->pFormatCtx, -1, current_pos, AVSEEK_FLAG_BACKWARD) < 0) {
@@ -1218,8 +1219,7 @@ static void ffmpeg_seek_and_decode(struct anim *anim, int position, struct anim_
AVFormatContext *format_ctx = anim->pFormatCtx;
/* Condition based on av_seek_frame() code. */
if (format_ctx->iformat->read_seek2 && !format_ctx->iformat->read_seek) {
if (format_ctx->iformat->read_seek2 || format_ctx->iformat->read_seek) {
ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
}
else {

View File

@@ -288,7 +288,7 @@
.edge_types = LRT_EDGE_FLAG_ALL_TYPE, \
.thickness = 25, \
.opacity = 1.0f, \
.flags = LRT_GPENCIL_MATCH_OUTPUT_VGROUP | LRT_GPENCIL_SOFT_SELECTION, \
.flags = LRT_GPENCIL_MATCH_OUTPUT_VGROUP, \
.crease_threshold = DEG2RAD(140.0f), \
.calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_ALLOW_CLIPPING_BOUNDARIES, \
.angle_splitting_threshold = DEG2RAD(60.0f), \

View File

@@ -819,7 +819,7 @@ typedef enum eLineartGpencilModifierSource {
typedef enum eLineArtGPencilModifierFlags {
LRT_GPENCIL_INVERT_SOURCE_VGROUP = (1 << 0),
LRT_GPENCIL_MATCH_OUTPUT_VGROUP = (1 << 1),
LRT_GPENCIL_SOFT_SELECTION = (1 << 2),
LRT_GPENCIL_BINARY_WEIGHTS = (1 << 2) /* Deprecated, this is removed for lack of use case. */,
LRT_GPENCIL_IS_BAKED = (1 << 3),
} eLineArtGPencilModifierFlags;
@@ -868,7 +868,7 @@ typedef struct LineartGpencilModifierData {
/* CPU mode */
float chaining_image_threshold;
float resample_length;
int _pad;
/* Ported from SceneLineArt flags. */
int calculation_flags;

View File

@@ -68,6 +68,7 @@
.volume_fac = 1.0f, \
.att_dist = 40.0f, \
.sun_angle = DEG2RADF(0.526f), \
.area_spread = DEG2RADF(180.0f), \
}
/** \} */

View File

@@ -70,9 +70,9 @@ typedef struct Light {
short area_shape;
float area_size, area_sizey, area_sizez;
float area_spread;
float sun_angle;
char _pad3[4];
/* texact is for buttons */
short texact, shadhalostep;

View File

@@ -168,6 +168,11 @@ typedef struct Object_Runtime {
*/
struct GeometrySet *geometry_set_eval;
/**
* Data from this geometry set is previewed in the spreadsheet editor.
*/
struct GeometrySet *geometry_set_preview;
/**
* Mesh structure created during object evaluation.
* It has deformation only modifiers applied on it.

View File

@@ -1520,6 +1520,7 @@ typedef struct bNodeTreePath {
/** MAX_NAME. */
char node_name[64];
char display_name[64];
} bNodeTreePath;
typedef struct SpaceNode {
@@ -1885,6 +1886,7 @@ typedef enum eSpaceSpreadsheet_FilterFlag {
typedef enum eSpaceSpreadsheet_ObjectEvalState {
SPREADSHEET_OBJECT_EVAL_STATE_FINAL = 0,
SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL = 1,
SPREADSHEET_OBJECT_EVAL_STATE_NODE = 2,
} eSpaceSpreadsheet_Context;
/* -------------------------------------------------------------------- */

View File

@@ -2501,12 +2501,6 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Match Output", "Match output vertex group based on name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_soft_selection", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_SOFT_SELECTION);
RNA_def_property_ui_text(
prop, "Clip", "Preserve original vertex weight instead of clipping to 0/1");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "is_baked", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_IS_BAKED);
RNA_def_property_ui_text(prop, "Is Baked", "This modifier has baked data");
@@ -2524,15 +2518,6 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "resample_length", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_ui_text(prop,
"Resample Length",
"Resample the strokes so that the stroke points have the specified "
"length between them. Zero length disables the resampling");
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01f, 2);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_transparency", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transparency_flags", LRT_GPENCIL_TRANSPARENCY_ENABLE);
RNA_def_property_ui_text(

View File

@@ -480,6 +480,15 @@ static void rna_def_area_light(BlenderRNA *brna)
"Size Y",
"Size of the area of the area light in the Y direction for rectangle shapes");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "spread", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "area_spread");
RNA_def_property_range(prop, DEG2RADF(1.0f), DEG2RADF(180.0f));
RNA_def_property_ui_text(
prop,
"Spread",
"How widely the emitted light fans out, as in the case of a gridded softbox");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
}
static void rna_def_spot_light(BlenderRNA *brna)

View File

@@ -7344,6 +7344,11 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
ICON_NONE,
"Original",
"Use data from original object without any modifiers applied"},
{SPREADSHEET_OBJECT_EVAL_STATE_NODE,
"NODE",
ICON_NONE,
"Node",
"Use data from the first geometry output of the active node"},
{0, NULL, 0, NULL, NULL},
};

View File

@@ -43,17 +43,22 @@
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_node_ui_storage.hh"
#include "BKE_object.h"
#include "BKE_pointcloud.h"
#include "BKE_screen.h"
#include "BKE_simulation.h"
#include "BKE_workspace.h"
#include "BLO_read_write.h"
@@ -89,6 +94,7 @@ using blender::bke::PersistentCollectionHandle;
using blender::bke::PersistentDataHandleMap;
using blender::bke::PersistentObjectHandle;
using blender::fn::GMutablePointer;
using blender::fn::GPointer;
using blender::fn::GValueMap;
using blender::nodes::GeoNodeExecParams;
using namespace blender::fn::multi_function_types;
@@ -253,6 +259,9 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
}
class GeometryNodesEvaluator {
public:
using LogSocketValueFn = std::function<void(DSocket, Span<GPointer>)>;
private:
blender::LinearAllocator<> allocator_;
Map<std::pair<DInputSocket, DOutputSocket>, GMutablePointer> value_by_input_;
@@ -263,6 +272,7 @@ class GeometryNodesEvaluator {
const Object *self_object_;
const ModifierData *modifier_;
Depsgraph *depsgraph_;
LogSocketValueFn log_socket_value_fn_;
public:
GeometryNodesEvaluator(const Map<DOutputSocket, GMutablePointer> &group_input_data,
@@ -271,16 +281,19 @@ class GeometryNodesEvaluator {
const PersistentDataHandleMap &handle_map,
const Object *self_object,
const ModifierData *modifier,
Depsgraph *depsgraph)
Depsgraph *depsgraph,
LogSocketValueFn log_socket_value_fn)
: group_outputs_(std::move(group_outputs)),
mf_by_node_(mf_by_node),
conversions_(blender::nodes::get_implicit_type_conversions()),
handle_map_(handle_map),
self_object_(self_object),
modifier_(modifier),
depsgraph_(depsgraph)
depsgraph_(depsgraph),
log_socket_value_fn_(std::move(log_socket_value_fn))
{
for (auto item : group_input_data.items()) {
this->log_socket_value(item.key, item.value);
this->forward_to_inputs(item.key, item.value);
}
}
@@ -290,6 +303,7 @@ class GeometryNodesEvaluator {
Vector<GMutablePointer> results;
for (const DInputSocket &group_output : group_outputs_) {
Vector<GMutablePointer> result = this->get_input_values(group_output);
this->log_socket_value(group_output, result);
results.append(result[0]);
}
for (GMutablePointer value : value_by_input_.values()) {
@@ -384,7 +398,9 @@ class GeometryNodesEvaluator {
GValueMap<StringRef> node_inputs_map{allocator_};
for (const InputSocketRef *input_socket : node->inputs()) {
if (input_socket->is_available()) {
Vector<GMutablePointer> values = this->get_input_values({node.context(), input_socket});
DInputSocket dsocket{node.context(), input_socket};
Vector<GMutablePointer> values = this->get_input_values(dsocket);
this->log_socket_value(dsocket, values);
for (int i = 0; i < values.size(); ++i) {
/* Values from Multi Input Sockets are stored in input map with the format
* <identifier>[<index>]. */
@@ -404,12 +420,31 @@ class GeometryNodesEvaluator {
/* Forward computed outputs to linked input sockets. */
for (const OutputSocketRef *output_socket : node->outputs()) {
if (output_socket->is_available()) {
const DOutputSocket dsocket{node.context(), output_socket};
GMutablePointer value = node_outputs_map.extract(output_socket->identifier());
this->forward_to_inputs({node.context(), output_socket}, value);
this->log_socket_value(dsocket, value);
this->forward_to_inputs(dsocket, value);
}
}
}
void log_socket_value(const DSocket socket, Span<GPointer> values)
{
if (log_socket_value_fn_) {
log_socket_value_fn_(socket, values);
}
}
void log_socket_value(const DSocket socket, Span<GMutablePointer> values)
{
this->log_socket_value(socket, values.cast<GPointer>());
}
void log_socket_value(const DSocket socket, GPointer value)
{
this->log_socket_value(socket, Span<GPointer>(&value, 1));
}
void execute_node(const DNode node, GeoNodeExecParams params)
{
const bNode &bnode = params.node();
@@ -523,8 +558,15 @@ class GeometryNodesEvaluator {
{
/* For all sockets that are linked with the from_socket push the value to their node. */
Vector<DInputSocket> to_sockets_all;
from_socket.foreach_target_socket(
[&](DInputSocket to_socket) { to_sockets_all.append_non_duplicates(to_socket); });
auto handle_target_socket_fn = [&](DInputSocket to_socket) {
to_sockets_all.append_non_duplicates(to_socket);
};
auto handle_skipped_socket_fn = [&, this](DSocket socket) {
this->log_socket_value(socket, value_to_forward);
};
from_socket.foreach_target_socket(handle_target_socket_fn, handle_skipped_socket_fn);
const CPPType &from_type = *value_to_forward.type();
Vector<DInputSocket> to_sockets_same_type;
@@ -1051,6 +1093,71 @@ static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> tree
}
}
static DNode find_matching_active_derived_node(const SpaceNode &snode, const DerivedNodeTree &tree)
{
const DTreeContext &root_context = tree.root_context();
bNodeTree *root_tree_eval = root_context.tree().btree();
bNodeTree *root_tree_orig = (bNodeTree *)DEG_get_original_id(&root_tree_eval->id);
if (snode.nodetree != root_tree_orig) {
return {};
}
const DTreeContext *current_context = &root_context;
bool is_first = true;
LISTBASE_FOREACH (const bNodeTreePath *, path, &snode.treepath) {
if (is_first) {
is_first = false;
continue;
}
StringRef parent_node_name = path->node_name;
const NodeTreeRef &tree_ref = current_context->tree();
const NodeRef *parent_node_ref = nullptr;
for (const NodeRef *node_ref : tree_ref.nodes()) {
if (node_ref->name() == parent_node_name) {
parent_node_ref = node_ref;
break;
}
}
if (parent_node_ref == nullptr) {
return {};
}
current_context = current_context->child_context(*parent_node_ref);
if (current_context == nullptr) {
return {};
}
}
const NodeTreeRef &tree_ref = current_context->tree();
for (const NodeRef *node_ref : tree_ref.nodes()) {
if (node_ref->bnode()->flag & NODE_ACTIVE) {
return {current_context, node_ref};
}
}
return {};
}
static DNode find_matching_active_derived_node(Depsgraph *depsgraph, const DerivedNodeTree &tree)
{
Main *bmain = DEG_get_bmain(depsgraph);
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
SpaceLink *sl = (SpaceLink *)area->spacedata.first;
if (sl->spacetype != SPACE_NODE) {
continue;
}
SpaceNode *snode = (SpaceNode *)sl;
DNode active_node = find_matching_active_derived_node(*snode, tree);
if (!active_node) {
continue;
}
return active_node;
}
}
return {};
}
/**
* Evaluate a node group to compute the output geometry.
* Currently, this uses a fairly basic and inefficient algorithm that might compute things more
@@ -1106,13 +1213,36 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
Vector<DInputSocket> group_outputs;
group_outputs.append({root_context, &socket_to_compute});
const DNode active_node = find_matching_active_derived_node(ctx->depsgraph, tree);
auto log_socket_value = [&](const DSocket socket, const Span<GPointer> values) {
const DNode node = socket.node();
if (node != active_node) {
return;
}
if (socket->is_input() && !node->outputs().is_empty()) {
return;
}
if (values.size() != 1) {
return;
}
const GPointer value = values[0];
if (*value.type() != CPPType::get<GeometrySet>()) {
return;
}
GeometrySet geometry_set = *(const GeometrySet *)value.get();
geometry_set.ensure_owns_direct_data();
BKE_object_preview_geometry_set(ctx->object, new GeometrySet(std::move(geometry_set)));
};
GeometryNodesEvaluator evaluator{group_inputs,
group_outputs,
mf_by_node,
handle_map,
ctx->object,
(ModifierData *)nmd,
ctx->depsgraph};
ctx->depsgraph,
log_socket_value};
Vector<GMutablePointer> results = evaluator.execute();
BLI_assert(results.size() == 1);

View File

@@ -59,6 +59,7 @@ class DTreeContext {
const NodeTreeRef *tree_;
/* All the children contexts of this context. */
Map<const NodeRef *, DTreeContext *> children_;
DerivedNodeTree *derived_tree_;
friend DerivedNodeTree;
@@ -67,6 +68,7 @@ class DTreeContext {
const DTreeContext *parent_context() const;
const NodeRef *parent_node() const;
const DTreeContext *child_context(const NodeRef &node) const;
const DerivedNodeTree &derived_tree() const;
bool is_root() const;
};
@@ -117,6 +119,8 @@ class DSocket {
operator bool() const;
uint64_t hash() const;
DNode node() const;
};
/* A (nullable) reference to an input socket and the context it is in. */
@@ -132,7 +136,7 @@ class DInputSocket : public DSocket {
DOutputSocket get_corresponding_group_node_output() const;
Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const;
void foreach_origin_socket(FunctionRef<void(DSocket)> callback) const;
void foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const;
};
/* A (nullable) reference to an output socket and the context it is in. */
@@ -148,7 +152,8 @@ class DOutputSocket : public DSocket {
DInputSocket get_corresponding_group_node_input() const;
DInputSocket get_active_corresponding_group_output_socket() const;
void foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const;
void foreach_target_socket(FunctionRef<void(DInputSocket)> target_fn,
FunctionRef<void(DSocket)> skipped_fn) const;
};
class DerivedNodeTree {
@@ -214,6 +219,11 @@ inline const DTreeContext *DTreeContext::child_context(const NodeRef &node) cons
return children_.lookup_default(&node, nullptr);
}
inline const DerivedNodeTree &DTreeContext::derived_tree() const
{
return *derived_tree_;
}
inline bool DTreeContext::is_root() const
{
return parent_context_ == nullptr;
@@ -319,6 +329,12 @@ inline uint64_t DSocket::hash() const
return get_default_hash_2(context_, socket_ref_);
}
inline DNode DSocket::node() const
{
BLI_assert(socket_ref_ != nullptr);
return {context_, &socket_ref_->node()};
}
/* --------------------------------------------------------------------
* DInputSocket inline methods.
*/

View File

@@ -81,15 +81,19 @@ class SocketRef : NonCopyable, NonMovable {
Vector<LinkRef *> directly_linked_links_;
/* These sockets are linked directly, i.e. with a single link in between. */
MutableSpan<SocketRef *> directly_linked_sockets_;
MutableSpan<const SocketRef *> directly_linked_sockets_;
/* These sockets are linked when reroutes, muted links and muted nodes have been taken into
* account. */
MutableSpan<SocketRef *> logically_linked_sockets_;
MutableSpan<const SocketRef *> logically_linked_sockets_;
/* These are the sockets that have been skipped when searching for logically linked sockets.
* That includes for example the input and output socket of an intermediate reroute node. */
MutableSpan<const SocketRef *> logically_linked_skipped_sockets_;
friend NodeTreeRef;
public:
Span<const SocketRef *> logically_linked_sockets() const;
Span<const SocketRef *> logically_linked_skipped_sockets() const;
Span<const SocketRef *> directly_linked_sockets() const;
Span<const LinkRef *> directly_linked_links() const;
@@ -132,12 +136,19 @@ class InputSocketRef final : public SocketRef {
Span<const OutputSocketRef *> directly_linked_sockets() const;
bool is_multi_input_socket() const;
void foreach_logical_origin(FunctionRef<void(const OutputSocketRef &)> origin_fn,
FunctionRef<void(const SocketRef &)> skipped_fn,
bool only_follow_first_input_link = false) const;
};
class OutputSocketRef final : public SocketRef {
public:
Span<const InputSocketRef *> logically_linked_sockets() const;
Span<const InputSocketRef *> directly_linked_sockets() const;
void foreach_logical_target(FunctionRef<void(const InputSocketRef &)> target_fn,
FunctionRef<void(const SocketRef &)> skipped_fn) const;
};
class NodeRef : NonCopyable, NonMovable {
@@ -257,12 +268,6 @@ class NodeTreeRef : NonCopyable, NonMovable {
bNodeSocket *bsocket);
void create_linked_socket_caches();
void foreach_logical_origin(InputSocketRef &socket,
FunctionRef<void(OutputSocketRef &)> callback,
bool only_follow_first_input_link = false);
void foreach_logical_target(OutputSocketRef &socket,
FunctionRef<void(InputSocketRef &)> callback);
};
using NodeTreeRefMap = Map<bNodeTree *, std::unique_ptr<const NodeTreeRef>>;
@@ -287,6 +292,11 @@ inline Span<const SocketRef *> SocketRef::logically_linked_sockets() const
return logically_linked_sockets_;
}
inline Span<const SocketRef *> SocketRef::logically_linked_skipped_sockets() const
{
return logically_linked_skipped_sockets_;
}
inline Span<const SocketRef *> SocketRef::directly_linked_sockets() const
{
return directly_linked_sockets_;

View File

@@ -40,6 +40,7 @@ DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *paren
DTreeContext &context = *allocator_.construct<DTreeContext>().release();
context.parent_context_ = parent_context;
context.parent_node_ = parent_node;
context.derived_tree_ = this;
context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree);
used_node_tree_refs_.add(context.tree_);
@@ -167,10 +168,10 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const
return {};
}
/* Call the given callback for every "real" origin socket. "Real" means that reroutes, muted nodes
/* Call `origin_fn` for every "real" origin socket. "Real" means that reroutes, muted nodes
* and node groups are handled by this function. Origin sockets are ones where a node gets its
* inputs from. */
void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> callback) const
void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const
{
BLI_assert(*this);
for (const OutputSocketRef *linked_socket : socket_ref_->as_input().logically_linked_sockets()) {
@@ -180,18 +181,18 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> callback) co
if (linked_node.is_group_input_node()) {
if (context_->is_root()) {
/* This is a group input in the root node group. */
callback(linked_dsocket);
origin_fn(linked_dsocket);
}
else {
DInputSocket socket_in_parent_group = linked_dsocket.get_corresponding_group_node_input();
if (socket_in_parent_group->is_logically_linked()) {
/* Follow the links coming into the corresponding socket on the parent group node. */
socket_in_parent_group.foreach_origin_socket(callback);
socket_in_parent_group.foreach_origin_socket(origin_fn);
}
else {
/* The corresponding input on the parent group node is not connected. Therefore, we use
* the value of that input socket directly. */
callback(socket_in_parent_group);
origin_fn(socket_in_parent_group);
}
}
}
@@ -200,27 +201,32 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> callback) co
if (socket_in_group) {
if (socket_in_group->is_logically_linked()) {
/* Follow the links coming into the group output node of the child node group. */
socket_in_group.foreach_origin_socket(callback);
socket_in_group.foreach_origin_socket(origin_fn);
}
else {
/* The output of the child node group is not connected, so we have to get the value from
* that socket. */
callback(socket_in_group);
origin_fn(socket_in_group);
}
}
}
else {
/* The normal case: just use the value of a linked output socket. */
callback(linked_dsocket);
origin_fn(linked_dsocket);
}
}
}
/* Calls the given callback for every "real" target socket. "Real" means that reroutes, muted nodes
/* Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes
* and node groups are handled by this function. Target sockets are on the nodes that use the value
* from this socket. */
void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const
* from this socket. The `skipped_fn` function is called for sockets that have been skipped during
* the search for target sockets (e.g. reroutes). */
void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> target_fn,
FunctionRef<void(DSocket)> skipped_fn) const
{
for (const SocketRef *skipped_socket : socket_ref_->logically_linked_skipped_sockets()) {
skipped_fn.call_safe({context_, skipped_socket});
}
for (const InputSocketRef *linked_socket : socket_ref_->as_output().logically_linked_sockets()) {
const NodeRef &linked_node = linked_socket->node();
DInputSocket linked_dsocket{context_, linked_socket};
@@ -228,26 +234,30 @@ void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> callba
if (linked_node.is_group_output_node()) {
if (context_->is_root()) {
/* This is a group output in the root node group. */
callback(linked_dsocket);
target_fn(linked_dsocket);
}
else {
/* Follow the links going out of the group node in the parent node group. */
DOutputSocket socket_in_parent_group =
linked_dsocket.get_corresponding_group_node_output();
socket_in_parent_group.foreach_target_socket(callback);
skipped_fn.call_safe(linked_dsocket);
skipped_fn.call_safe(socket_in_parent_group);
socket_in_parent_group.foreach_target_socket(target_fn, skipped_fn);
}
}
else if (linked_node.is_group_node()) {
/* Follow the links within the nested node group. */
Vector<DOutputSocket> sockets_in_group =
linked_dsocket.get_corresponding_group_input_sockets();
skipped_fn.call_safe(linked_dsocket);
for (DOutputSocket socket_in_group : sockets_in_group) {
socket_in_group.foreach_target_socket(callback);
skipped_fn.call_safe(socket_in_group);
socket_in_group.foreach_target_socket(target_fn, skipped_fn);
}
}
else {
/* The normal case: just use the linked input socket as target. */
callback(linked_dsocket);
target_fn(linked_dsocket);
}
}
}

View File

@@ -163,7 +163,7 @@ void NodeTreeRef::create_linked_socket_caches()
{
for (InputSocketRef *socket : input_sockets_) {
/* Find directly linked socket based on incident links. */
Vector<SocketRef *> directly_linked_sockets;
Vector<const SocketRef *> directly_linked_sockets;
for (LinkRef *link : socket->directly_linked_links_) {
directly_linked_sockets.append(link->from_);
}
@@ -171,9 +171,11 @@ void NodeTreeRef::create_linked_socket_caches()
directly_linked_sockets.as_span());
/* Find logically linked sockets. */
Vector<SocketRef *> logically_linked_sockets;
this->foreach_logical_origin(
*socket, [&](OutputSocketRef &origin) { logically_linked_sockets.append(&origin); });
Vector<const SocketRef *> logically_linked_sockets;
Vector<const SocketRef *> logically_linked_skipped_sockets;
socket->foreach_logical_origin(
[&](const OutputSocketRef &origin) { logically_linked_sockets.append(&origin); },
[&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); });
if (logically_linked_sockets == directly_linked_sockets) {
socket->logically_linked_sockets_ = socket->directly_linked_sockets_;
}
@@ -181,11 +183,13 @@ void NodeTreeRef::create_linked_socket_caches()
socket->logically_linked_sockets_ = allocator_.construct_array_copy(
logically_linked_sockets.as_span());
}
socket->logically_linked_skipped_sockets_ = allocator_.construct_array_copy(
logically_linked_skipped_sockets.as_span());
}
for (OutputSocketRef *socket : output_sockets_) {
/* Find directly linked socket based on incident links. */
Vector<SocketRef *> directly_linked_sockets;
Vector<const SocketRef *> directly_linked_sockets;
for (LinkRef *link : socket->directly_linked_links_) {
directly_linked_sockets.append(link->to_);
}
@@ -193,9 +197,11 @@ void NodeTreeRef::create_linked_socket_caches()
directly_linked_sockets.as_span());
/* Find logically linked sockets. */
Vector<SocketRef *> logically_linked_sockets;
this->foreach_logical_target(
*socket, [&](InputSocketRef &target) { logically_linked_sockets.append(&target); });
Vector<const SocketRef *> logically_linked_sockets;
Vector<const SocketRef *> logically_linked_skipped_sockets;
socket->foreach_logical_target(
[&](const InputSocketRef &target) { logically_linked_sockets.append(&target); },
[&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); });
if (logically_linked_sockets == directly_linked_sockets) {
socket->logically_linked_sockets_ = socket->directly_linked_sockets_;
}
@@ -203,61 +209,77 @@ void NodeTreeRef::create_linked_socket_caches()
socket->logically_linked_sockets_ = allocator_.construct_array_copy(
logically_linked_sockets.as_span());
}
socket->logically_linked_skipped_sockets_ = allocator_.construct_array_copy(
logically_linked_skipped_sockets.as_span());
}
}
void NodeTreeRef::foreach_logical_origin(InputSocketRef &socket,
FunctionRef<void(OutputSocketRef &)> callback,
bool only_follow_first_input_link)
void InputSocketRef::foreach_logical_origin(FunctionRef<void(const OutputSocketRef &)> origin_fn,
FunctionRef<void(const SocketRef &)> skipped_fn,
bool only_follow_first_input_link) const
{
Span<LinkRef *> links_to_check = socket.directly_linked_links_;
Span<const LinkRef *> links_to_check = this->directly_linked_links();
if (only_follow_first_input_link) {
links_to_check = links_to_check.take_front(1);
}
for (LinkRef *link : links_to_check) {
for (const LinkRef *link : links_to_check) {
if (link->is_muted()) {
continue;
}
OutputSocketRef *origin = link->from_;
NodeRef *origin_node = origin->node_;
if (origin_node->is_reroute_node()) {
this->foreach_logical_origin(*origin_node->inputs_[0], callback, false);
const OutputSocketRef &origin = link->from();
const NodeRef &origin_node = origin.node();
if (origin_node.is_reroute_node()) {
const InputSocketRef &reroute_input = origin_node.input(0);
const OutputSocketRef &reroute_output = origin_node.output(0);
skipped_fn.call_safe(reroute_input);
skipped_fn.call_safe(reroute_output);
reroute_input.foreach_logical_origin(origin_fn, skipped_fn, false);
}
else if (origin_node->is_muted()) {
for (InternalLinkRef *internal_link : origin_node->internal_links_) {
if (internal_link->to_ == origin) {
this->foreach_logical_origin(*internal_link->from_, callback, true);
else if (origin_node.is_muted()) {
for (const InternalLinkRef *internal_link : origin_node.internal_links()) {
if (&internal_link->to() == &origin) {
const InputSocketRef &mute_input = internal_link->from();
skipped_fn.call_safe(origin);
skipped_fn.call_safe(mute_input);
mute_input.foreach_logical_origin(origin_fn, skipped_fn, true);
break;
}
}
}
else {
callback(*origin);
origin_fn(origin);
}
}
}
void NodeTreeRef::foreach_logical_target(OutputSocketRef &socket,
FunctionRef<void(InputSocketRef &)> callback)
void OutputSocketRef::foreach_logical_target(FunctionRef<void(const InputSocketRef &)> target_fn,
FunctionRef<void(const SocketRef &)> skipped_fn) const
{
for (LinkRef *link : socket.directly_linked_links_) {
for (const LinkRef *link : this->directly_linked_links()) {
if (link->is_muted()) {
continue;
}
InputSocketRef *target = link->to_;
NodeRef *target_node = target->node_;
if (target_node->is_reroute_node()) {
this->foreach_logical_target(*target_node->outputs_[0], callback);
const InputSocketRef &target = link->to();
const NodeRef &target_node = target.node();
if (target_node.is_reroute_node()) {
const OutputSocketRef &reroute_output = target_node.output(0);
skipped_fn.call_safe(target);
skipped_fn.call_safe(reroute_output);
reroute_output.foreach_logical_target(target_fn, skipped_fn);
}
else if (target_node->is_muted()) {
for (InternalLinkRef *internal_link : target_node->internal_links_) {
if (internal_link->from_ == target) {
this->foreach_logical_target(*internal_link->to_, callback);
else if (target_node.is_muted()) {
skipped_fn.call_safe(target);
for (const InternalLinkRef *internal_link : target_node.internal_links()) {
if (&internal_link->from() == &target) {
const OutputSocketRef &mute_output = internal_link->to();
skipped_fn.call_safe(target);
skipped_fn.call_safe(mute_output);
mute_output.foreach_logical_target(target_fn, skipped_fn);
}
}
}
else {
callback(*target);
target_fn(target);
}
}
}

View File

@@ -53,38 +53,45 @@ extern PyTypeObject BPy_BMIter_Type;
/* cast from _any_ bmesh type - they all have BMesh first */
typedef struct BPy_BMGeneric {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
} BPy_BMGeneric;
/* BPy_BMVert/BPy_BMEdge/BPy_BMFace/BPy_BMLoop can cast to this */
typedef struct BPy_BMElem {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
struct BMElem *ele;
} BPy_BMElem;
typedef struct BPy_BMesh {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
int flag;
} BPy_BMesh;
/* element types */
typedef struct BPy_BMVert {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
struct BMVert *v;
} BPy_BMVert;
typedef struct BPy_BMEdge {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
struct BMEdge *e;
} BPy_BMEdge;
typedef struct BPy_BMFace {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
struct BMFace *f;
} BPy_BMFace;
typedef struct BPy_BMLoop {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
struct BMLoop *l;
} BPy_BMLoop;
@@ -98,7 +105,8 @@ typedef struct BPy_BMLoop {
* - BPy_BMLoopSeq_Type
*/
typedef struct BPy_BMElemSeq {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
/* if this is a sequence on an existing element,
* loops of faces for eg.
@@ -114,7 +122,8 @@ typedef struct BPy_BMElemSeq {
} BPy_BMElemSeq;
typedef struct BPy_BMIter {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
BMIter iter;
} BPy_BMIter;

View File

@@ -38,20 +38,23 @@ extern PyTypeObject BPy_BMLayerItem_Type;
/* all layers for vert/edge/face/loop */
typedef struct BPy_BMLayerAccess {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
char htype;
} BPy_BMLayerAccess;
/* access different layer types deform/uv/vertexcolor */
typedef struct BPy_BMLayerCollection {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
char htype;
int type; /* customdata type - CD_XXX */
} BPy_BMLayerCollection;
/* access a specific layer directly */
typedef struct BPy_BMLayerItem {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
char htype;
int type; /* customdata type - CD_XXX */
int index; /* index of this layer type */

View File

@@ -48,7 +48,8 @@
#define BPy_BMLoopUV_Check(v) (Py_TYPE(v) == &BPy_BMLoopUV_Type)
typedef struct BPy_BMLoopUV {
PyObject_VAR_HEAD MLoopUV *data;
PyObject_VAR_HEAD
MLoopUV *data;
} BPy_BMLoopUV;
PyDoc_STRVAR(bpy_bmloopuv_uv_doc,
@@ -155,7 +156,8 @@ PyObject *BPy_BMLoopUV_CreatePyObject(struct MLoopUV *mloopuv)
#define BPy_BMVertSkin_Check(v) (Py_TYPE(v) == &BPy_BMVertSkin_Type)
typedef struct BPy_BMVertSkin {
PyObject_VAR_HEAD MVertSkin *data;
PyObject_VAR_HEAD
MVertSkin *data;
} BPy_BMVertSkin;
PyDoc_STRVAR(bpy_bmvertskin_radius_doc,
@@ -392,7 +394,8 @@ PyObject *BPy_BMLoopColor_CreatePyObject(struct MLoopCol *mloopcol)
#define BPy_BMDeformVert_Check(v) (Py_TYPE(v) == &BPy_BMDeformVert_Type)
typedef struct BPy_BMDeformVert {
PyObject_VAR_HEAD MDeformVert *data;
PyObject_VAR_HEAD
MDeformVert *data;
} BPy_BMDeformVert;
/* Mapping Protocols

View File

@@ -29,7 +29,8 @@ extern PyTypeObject BPy_BMDeformVert_Type;
#define BPy_BMLoopUV_Check(v) (Py_TYPE(v) == &BPy_BMLoopUV_Type)
typedef struct BPy_BMGenericMeshData {
PyObject_VAR_HEAD void *data;
PyObject_VAR_HEAD
void *data;
} BPy_BMGenericMeshData;
struct MDeformVert;

View File

@@ -32,11 +32,13 @@ extern PyTypeObject BPy_BMEditSelIter_Type;
#define BPy_BMSelectHistoryIter_Check(v) (Py_TYPE(v) == &BPy_BMEditSelIter_Type)
typedef struct BPy_BMEditSelSeq {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
} BPy_BMEditSelSeq;
typedef struct BPy_BMEditSelIter {
PyObject_VAR_HEAD struct BMesh *bm; /* keep first */
PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */
struct BMEditSelection *ese;
} BPy_BMEditSelIter;

View File

@@ -32,7 +32,8 @@ int BGL_typeSize(int type);
* For Python access to OpenGL functions requiring a pointer.
*/
typedef struct _Buffer {
PyObject_VAR_HEAD PyObject *parent;
PyObject_VAR_HEAD
PyObject *parent;
int type; /* GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT */
int ndimensions;

View File

@@ -36,19 +36,22 @@ extern PyTypeObject BPy_IDGroup_Type;
#define BPy_IDGroup_CheckExact(v) (Py_TYPE(v) == &BPy_IDGroup_Type)
typedef struct BPy_IDProperty {
PyObject_VAR_HEAD struct ID *id; /* can be NULL */
struct IDProperty *prop; /* must be second member */
PyObject_VAR_HEAD
struct ID *id; /* can be NULL */
struct IDProperty *prop; /* must be second member */
struct IDProperty *parent;
PyObject *data_wrap;
} BPy_IDProperty;
typedef struct BPy_IDArray {
PyObject_VAR_HEAD struct ID *id; /* can be NULL */
struct IDProperty *prop; /* must be second member */
PyObject_VAR_HEAD
struct ID *id; /* can be NULL */
struct IDProperty *prop; /* must be second member */
} BPy_IDArray;
typedef struct BPy_IDGroup_Iter {
PyObject_VAR_HEAD BPy_IDProperty *group;
PyObject_VAR_HEAD
BPy_IDProperty *group;
struct IDProperty *cur;
int mode;
} BPy_IDGroup_Iter;

View File

@@ -50,8 +50,8 @@ static PyObject *Py_ImBuf_CreatePyObject(ImBuf *ibuf);
typedef struct Py_ImBuf {
PyObject_VAR_HEAD
/* can be NULL */
ImBuf *ibuf;
/* can be NULL */
ImBuf *ibuf;
} Py_ImBuf;
static int py_imbuf_valid_check(Py_ImBuf *self)

View File

@@ -30,8 +30,8 @@ extern PyTypeObject BPyGPUBatch_Type;
typedef struct BPyGPUBatch {
PyObject_VAR_HEAD
/* The batch is owned, we may support thin wrapped batches later. */
struct GPUBatch *batch;
/* The batch is owned, we may support thin wrapped batches later. */
struct GPUBatch *batch;
#ifdef USE_GPU_PY_REFERENCES
/* Just to keep a user to prevent freeing buf's we're using */
PyObject *references;

View File

@@ -30,7 +30,8 @@ extern PyTypeObject BPyGPU_BufferType;
* For Python access to GPU functions requiring a pointer.
*/
typedef struct BPyGPUBuffer {
PyObject_VAR_HEAD PyObject *parent;
PyObject_VAR_HEAD
PyObject *parent;
int format;
int shape_len;

View File

@@ -25,7 +25,8 @@ extern PyTypeObject BPyGPUIndexBuf_Type;
#define BPyGPUIndexBuf_Check(v) (Py_TYPE(v) == &BPyGPUIndexBuf_Type)
typedef struct BPyGPUIndexBuf {
PyObject_VAR_HEAD struct GPUIndexBuf *elem;
PyObject_VAR_HEAD
struct GPUIndexBuf *elem;
} BPyGPUIndexBuf;
PyObject *BPyGPUIndexBuf_CreatePyObject(struct GPUIndexBuf *elem);

View File

@@ -25,7 +25,8 @@ extern PyTypeObject BPyGPUShader_Type;
#define BPyGPUShader_Check(v) (Py_TYPE(v) == &BPyGPUShader_Type)
typedef struct BPyGPUShader {
PyObject_VAR_HEAD struct GPUShader *shader;
PyObject_VAR_HEAD
struct GPUShader *shader;
bool is_builtin;
} BPyGPUShader;

View File

@@ -28,8 +28,8 @@ extern PyTypeObject BPyGPUVertBuf_Type;
typedef struct BPyGPUVertBuf {
PyObject_VAR_HEAD
/* The buf is owned, we may support thin wrapped batches later. */
struct GPUVertBuf *buf;
/* The buf is owned, we may support thin wrapped batches later. */
struct GPUVertBuf *buf;
} BPyGPUVertBuf;
PyObject *BPyGPUVertBuf_CreatePyObject(struct GPUVertBuf *buf) ATTR_NONNULL(1);

View File

@@ -27,7 +27,8 @@ extern PyTypeObject BPyGPUVertFormat_Type;
#define BPyGPUVertFormat_Check(v) (Py_TYPE(v) == &BPyGPUVertFormat_Type)
typedef struct BPyGPUVertFormat {
PyObject_VAR_HEAD struct GPUVertFormat fmt;
PyObject_VAR_HEAD
struct GPUVertFormat fmt;
} BPyGPUVertFormat;
PyObject *BPyGPUVertFormat_CreatePyObject(struct GPUVertFormat *fmt);

View File

@@ -52,7 +52,8 @@ enum {
#define BASE_MATH_MEMBERS(_data) \
/** Array of data (alias), wrapped status depends on wrapped status. */ \
PyObject_VAR_HEAD float *_data; \
PyObject_VAR_HEAD \
float *_data; \
/** If this vector references another object, otherwise NULL, *Note* this owns its reference */ \
PyObject *cb_user; \
/** Which user funcs do we adhere to, RNA, etc */ \