Compare commits
127 Commits
temp-geome
...
temp-any-i
Author | SHA1 | Date | |
---|---|---|---|
d546905f1d | |||
90959c2372 | |||
98721c8543 | |||
59d3ec1eef | |||
56da5ae2ac | |||
b19bd3692d | |||
95a2549d90 | |||
d0f05bfbcd | |||
3d5239ff40 | |||
d5a705873e | |||
f65a3172a8 | |||
3433d1b7f4 | |||
c81dfa2426 | |||
![]() |
8b3f5f755e | ||
![]() |
3d9ee83d88 | ||
![]() |
1c095203c2 | ||
![]() |
913b71bb8b | ||
![]() |
7bf977e9f0 | ||
![]() |
bfad8deb0b | ||
![]() |
4158405c0b | ||
01f028a677 | |||
3494946560 | |||
087f8a78f8 | |||
2dd055b2d4 | |||
250a69ee82 | |||
00215692d1 | |||
48731f45c2 | |||
b96acd0663 | |||
89ef0da551 | |||
355f884b2f | |||
0a0f737f91 | |||
54f52cac7c | |||
884f934a85 | |||
fb3e5b7f98 | |||
17a5db7303 | |||
9de8c2fa18 | |||
dd7feb09c9 | |||
9b806c49d0 | |||
a6ab232f8a | |||
cff4445a86 | |||
3420c3d8c6 | |||
a00249dd22 | |||
a9e64d8613 | |||
b9d2e2ec97 | |||
9f86933f2e | |||
31d5c5078c | |||
8cb1089795 | |||
dc9aea9903 | |||
260e50ed82 | |||
c905dd24b6 | |||
b9447ab053 | |||
e5ffefe606 | |||
b5f70d92c2 | |||
9c2d4ffbc1 | |||
de504e6dec | |||
50c5435438 | |||
18b87e2e0b | |||
eb7a601e1b | |||
dbe45073d2 | |||
97b83b6a67 | |||
a7f4270748 | |||
d235f6a48e | |||
![]() |
ae650b016f | ||
de296e8429 | |||
ef944b5020 | |||
64a413b0c7 | |||
a7455ae5f8 | |||
74609bfd51 | |||
36deb8a48e | |||
![]() |
fc62d38ce1 | ||
![]() |
7e3efac9a8 | ||
894e8b18e4 | |||
b1150fa1f5 | |||
51c7ff9222 | |||
1e1d96f0a8 | |||
cddfd11581 | |||
1919b104d3 | |||
59f92a218a | |||
07f9a73a8f | |||
06351c0504 | |||
7ee365d8c7 | |||
2dd040a349 | |||
248d9809ca | |||
f75d690ee4 | |||
6f7e632a6f | |||
3f0cd3fcc1 | |||
1b05948e4d | |||
d39a1e3cab | |||
c114c78f57 | |||
df28063795 | |||
d7fb38ddd4 | |||
8ab52daa3a | |||
aeff59073b | |||
decfd5c169 | |||
30b5fd1a3c | |||
bb6765f28f | |||
0c58ad8a34 | |||
de6d6e171e | |||
a41d3c0ebe | |||
1cc427ce2b | |||
be33d3eccd | |||
0ff3f96a1b | |||
e9eb08fea1 | |||
bf620020f1 | |||
256da1c4b9 | |||
0bae3002cf | |||
7f769567d0 | |||
0f1482279c | |||
4de7dc42c9 | |||
9cf25b9c44 | |||
296984b40e | |||
![]() |
266cd7bb82 | ||
20bf736ff8 | |||
![]() |
2a4bde04c5 | ||
1185708911 | |||
3157c3680b | |||
633f1cdec9 | |||
e6bdd57191 | |||
ac60e64745 | |||
e00a47ffd6 | |||
e91dd645a9 | |||
187f358f33 | |||
97defd9cd7 | |||
f4639276ee | |||
d512fe441b | |||
277e9b4355 | |||
e8f6c65b44 |
60
extern/audaspace/plugins/wasapi/WASAPIDevice.cpp
vendored
60
extern/audaspace/plugins/wasapi/WASAPIDevice.cpp
vendored
@@ -35,7 +35,11 @@ void WASAPIDevice::start()
|
||||
{
|
||||
lock();
|
||||
|
||||
if(!m_playing)
|
||||
// thread is still running, we can abort stopping it
|
||||
if(m_stop)
|
||||
m_stop = false;
|
||||
// thread is not running, let's start it
|
||||
else if(!m_playing)
|
||||
{
|
||||
if(m_thread.joinable())
|
||||
m_thread.join();
|
||||
@@ -53,20 +57,35 @@ void WASAPIDevice::updateStream()
|
||||
UINT32 buffer_size;
|
||||
data_t* buffer;
|
||||
|
||||
lock();
|
||||
|
||||
if(FAILED(m_audio_client->GetBufferSize(&buffer_size)))
|
||||
{
|
||||
m_playing = false;
|
||||
m_stop = false;
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
IAudioRenderClient* render_client = nullptr;
|
||||
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
|
||||
|
||||
if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client))))
|
||||
{
|
||||
m_playing = false;
|
||||
m_stop = false;
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
UINT32 padding;
|
||||
|
||||
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
|
||||
{
|
||||
SafeRelease(&render_client);
|
||||
m_playing = false;
|
||||
m_stop = false;
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,31 +94,40 @@ void WASAPIDevice::updateStream()
|
||||
if(FAILED(render_client->GetBuffer(length, &buffer)))
|
||||
{
|
||||
SafeRelease(&render_client);
|
||||
m_playing = false;
|
||||
m_stop = false;
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
lock();
|
||||
|
||||
mix((data_t*)buffer, length);
|
||||
|
||||
unlock();
|
||||
|
||||
if(FAILED(render_client->ReleaseBuffer(length, 0)))
|
||||
{
|
||||
SafeRelease(&render_client);
|
||||
m_playing = false;
|
||||
m_stop = false;
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
unlock();
|
||||
|
||||
m_audio_client->Start();
|
||||
|
||||
auto sleepDuration = std::chrono::milliseconds(buffer_size * 1000 / int(m_specs.rate) / 2);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
lock();
|
||||
|
||||
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
|
||||
{
|
||||
m_audio_client->Stop();
|
||||
SafeRelease(&render_client);
|
||||
m_playing = false;
|
||||
m_stop = false;
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -109,44 +137,52 @@ void WASAPIDevice::updateStream()
|
||||
{
|
||||
m_audio_client->Stop();
|
||||
SafeRelease(&render_client);
|
||||
m_playing = false;
|
||||
m_stop = false;
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
lock();
|
||||
|
||||
mix((data_t*)buffer, length);
|
||||
|
||||
unlock();
|
||||
|
||||
if(FAILED(render_client->ReleaseBuffer(length, 0)))
|
||||
{
|
||||
m_audio_client->Stop();
|
||||
SafeRelease(&render_client);
|
||||
m_playing = false;
|
||||
m_stop = false;
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
// stop thread
|
||||
if(!m_playing)
|
||||
if(m_stop)
|
||||
{
|
||||
m_audio_client->Stop();
|
||||
SafeRelease(&render_client);
|
||||
m_playing = false;
|
||||
m_stop = false;
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
unlock();
|
||||
|
||||
std::this_thread::sleep_for(sleepDuration);
|
||||
}
|
||||
}
|
||||
|
||||
void WASAPIDevice::playing(bool playing)
|
||||
{
|
||||
if(!m_playing && playing)
|
||||
if((!m_playing || m_stop) && playing)
|
||||
start();
|
||||
else
|
||||
m_playing = playing;
|
||||
m_stop = true;
|
||||
}
|
||||
|
||||
WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) :
|
||||
m_playing(false),
|
||||
m_stop(false),
|
||||
|
||||
m_imm_device_enumerator(nullptr),
|
||||
m_imm_device(nullptr),
|
||||
|
@@ -48,6 +48,11 @@ private:
|
||||
*/
|
||||
bool m_playing;
|
||||
|
||||
/**
|
||||
* Whether the current playback should stop.
|
||||
*/
|
||||
bool m_stop;
|
||||
|
||||
IMMDeviceEnumerator* m_imm_device_enumerator;
|
||||
IMMDevice* m_imm_device;
|
||||
IAudioClient* m_audio_client;
|
||||
|
@@ -1234,7 +1234,8 @@ static void add_nodes(Scene *scene,
|
||||
for (BL::NodeLink &b_link : b_ntree.links) {
|
||||
/* Ignore invalid links to avoid unwanted cycles created in graph.
|
||||
* Also ignore links with unavailable sockets. */
|
||||
if (!(b_link.is_valid() && b_link.from_socket().enabled() && b_link.to_socket().enabled())) {
|
||||
if (!(b_link.is_valid() && b_link.from_socket().enabled() && b_link.to_socket().enabled()) ||
|
||||
b_link.is_muted()) {
|
||||
continue;
|
||||
}
|
||||
/* get blender link data */
|
||||
|
@@ -640,6 +640,12 @@ ccl_device_noinline
|
||||
/* If we hit the surface, we are done. */
|
||||
break;
|
||||
}
|
||||
else if (throughput.x < VOLUME_THROUGHPUT_EPSILON &&
|
||||
throughput.y < VOLUME_THROUGHPUT_EPSILON &&
|
||||
throughput.z < VOLUME_THROUGHPUT_EPSILON) {
|
||||
/* Avoid unnecessary work and precision issue when throughput gets really small. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kernel_assert(isfinite_safe(throughput.x) && isfinite_safe(throughput.y) &&
|
||||
|
@@ -16,6 +16,12 @@
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Ignore paths that have volume throughput below this value, to avoid unnecessary work
|
||||
* and precision issues.
|
||||
* todo: this value could be tweaked or turned into a probability to avoid unnecessary
|
||||
* work in volumes and subsurface scattering. */
|
||||
#define VOLUME_THROUGHPUT_EPSILON 1e-6f
|
||||
|
||||
/* Events for probalistic scattering */
|
||||
|
||||
typedef enum VolumeIntegrateResult {
|
||||
@@ -226,7 +232,6 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg,
|
||||
const float object_step_size)
|
||||
{
|
||||
float3 tp = *throughput;
|
||||
const float tp_eps = 1e-6f; /* todo: this is likely not the right value */
|
||||
|
||||
/* Prepare for stepping.
|
||||
* For shadows we do not offset all segments, since the starting point is
|
||||
@@ -254,13 +259,15 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg,
|
||||
/* compute attenuation over segment */
|
||||
if (volume_shader_extinction_sample(kg, sd, state, new_P, &sigma_t)) {
|
||||
/* Compute expf() only for every Nth step, to save some calculations
|
||||
* because exp(a)*exp(b) = exp(a+b), also do a quick tp_eps check then. */
|
||||
* because exp(a)*exp(b) = exp(a+b), also do a quick VOLUME_THROUGHPUT_EPSILON
|
||||
* check then. */
|
||||
sum += (-sigma_t * dt);
|
||||
if ((i & 0x07) == 0) { /* ToDo: Other interval? */
|
||||
tp = *throughput * exp3(sum);
|
||||
|
||||
/* stop if nearly all light is blocked */
|
||||
if (tp.x < tp_eps && tp.y < tp_eps && tp.z < tp_eps)
|
||||
if (tp.x < VOLUME_THROUGHPUT_EPSILON && tp.y < VOLUME_THROUGHPUT_EPSILON &&
|
||||
tp.z < VOLUME_THROUGHPUT_EPSILON)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -572,7 +579,6 @@ kernel_volume_integrate_heterogeneous_distance(KernelGlobals *kg,
|
||||
const float object_step_size)
|
||||
{
|
||||
float3 tp = *throughput;
|
||||
const float tp_eps = 1e-6f; /* todo: this is likely not the right value */
|
||||
|
||||
/* Prepare for stepping.
|
||||
* Using a different step offset for the first step avoids banding artifacts. */
|
||||
@@ -669,7 +675,8 @@ kernel_volume_integrate_heterogeneous_distance(KernelGlobals *kg,
|
||||
tp = new_tp;
|
||||
|
||||
/* stop if nearly all light blocked */
|
||||
if (tp.x < tp_eps && tp.y < tp_eps && tp.z < tp_eps) {
|
||||
if (tp.x < VOLUME_THROUGHPUT_EPSILON && tp.y < VOLUME_THROUGHPUT_EPSILON &&
|
||||
tp.z < VOLUME_THROUGHPUT_EPSILON) {
|
||||
tp = zero_float3();
|
||||
break;
|
||||
}
|
||||
@@ -770,8 +777,6 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg,
|
||||
VolumeSegment *segment,
|
||||
const float object_step_size)
|
||||
{
|
||||
const float tp_eps = 1e-6f; /* todo: this is likely not the right value */
|
||||
|
||||
/* prepare for volume stepping */
|
||||
int max_steps;
|
||||
float step_size, step_shade_offset, steps_offset;
|
||||
@@ -895,8 +900,9 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg,
|
||||
break;
|
||||
|
||||
/* stop if nearly all light blocked */
|
||||
if (accum_transmittance.x < tp_eps && accum_transmittance.y < tp_eps &&
|
||||
accum_transmittance.z < tp_eps)
|
||||
if (accum_transmittance.x < VOLUME_THROUGHPUT_EPSILON &&
|
||||
accum_transmittance.y < VOLUME_THROUGHPUT_EPSILON &&
|
||||
accum_transmittance.z < VOLUME_THROUGHPUT_EPSILON)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -26,7 +26,7 @@ ccl_device void kernel_path_init(KernelGlobals *kg)
|
||||
int ray_index = ccl_global_id(0) + ccl_global_id(1) * ccl_global_size(0);
|
||||
|
||||
/* This is the first assignment to ray_state;
|
||||
* So we dont use ASSIGN_RAY_STATE macro.
|
||||
* So we don't use ASSIGN_RAY_STATE macro.
|
||||
*/
|
||||
kernel_split_state.ray_state[ray_index] = RAY_ACTIVE;
|
||||
|
||||
|
@@ -282,7 +282,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
||||
m_wintab.maxAzimuth = Orientation[0].axMax;
|
||||
m_wintab.maxAltitude = Orientation[1].axMax;
|
||||
}
|
||||
else { /* no so dont do tilt stuff */
|
||||
else { /* No so don't do tilt stuff. */
|
||||
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
|
||||
}
|
||||
}
|
||||
@@ -1057,7 +1057,7 @@ void GHOST_WindowWin32::processWin32TabletInitEvent()
|
||||
m_wintab.maxAzimuth = Orientation[0].axMax;
|
||||
m_wintab.maxAltitude = Orientation[1].axMax;
|
||||
}
|
||||
else { /* no so dont do tilt stuff */
|
||||
else { /* No so don't do tilt stuff. */
|
||||
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
|
||||
}
|
||||
}
|
||||
|
@@ -51,7 +51,7 @@
|
||||
|
||||
#include <stdio.h> /* needed for FILE* */
|
||||
|
||||
/* needed for uintptr_t and attributes, exception, dont use BLI anywhere else in MEM_* */
|
||||
/* Needed for uintptr_t and attributes, exception, don't use BLI anywhere else in `MEM_*` */
|
||||
#include "../../source/blender/blenlib/BLI_compiler_attrs.h"
|
||||
#include "../../source/blender/blenlib/BLI_sys_types.h"
|
||||
|
||||
|
Submodule release/datafiles/locale updated: b06e7fe345...ef74c1b861
@@ -825,6 +825,7 @@ const bTheme U_theme_default = {
|
||||
.vertex_size = 3,
|
||||
.outline_width = 1,
|
||||
.facedot_size = 4,
|
||||
.noodle_curving = 4,
|
||||
.grid_levels = 2,
|
||||
.syntaxl = RGBA(0x565656ff),
|
||||
.syntaxs = RGBA(0x975b5bff),
|
||||
|
Submodule release/scripts/addons updated: ef3104dae3...6dfba91574
Submodule release/scripts/addons_contrib updated: 70b649775e...ef6ef414d2
@@ -953,7 +953,7 @@
|
||||
frame_node="#9b9b9ba0"
|
||||
matte_node="#977474"
|
||||
distor_node="#749797"
|
||||
noodle_curving="0"
|
||||
noodle_curving="4"
|
||||
grid_levels="2"
|
||||
input_node="#cb3d4a"
|
||||
output_node="#cb3d4a"
|
||||
|
@@ -1844,6 +1844,7 @@ def km_node_editor(params):
|
||||
("node.resize", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
|
||||
("node.add_reroute", {"type": 'EVT_TWEAK_L' if params.legacy else 'EVT_TWEAK_R', "value": 'ANY', "shift": True}, None),
|
||||
("node.links_cut", {"type": 'EVT_TWEAK_L' if params.legacy else 'EVT_TWEAK_R', "value": 'ANY', "ctrl": True}, None),
|
||||
("node.links_mute", {"type": 'EVT_TWEAK_R', "value": 'ANY', "ctrl": True, "alt": True}, None),
|
||||
("node.select_link_viewer", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None),
|
||||
("node.backimage_move", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "alt": True}, None),
|
||||
("node.backimage_zoom", {"type": 'V', "value": 'PRESS', "repeat": True},
|
||||
@@ -6627,7 +6628,7 @@ def km_3d_view_tool_sculpt_color_filter(params):
|
||||
|
||||
def km_3d_view_tool_sculpt_mask_by_color(params):
|
||||
return (
|
||||
"3D View Tool: Sculpt, Mask By Color",
|
||||
"3D View Tool: Sculpt, Mask by Color",
|
||||
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
|
||||
{"items": [
|
||||
("sculpt.mask_by_color", {"type": params.tool_mouse, "value": 'ANY'},
|
||||
|
@@ -1113,6 +1113,7 @@ def km_node_editor(params):
|
||||
("node.resize", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
|
||||
("node.add_reroute", {"type": params.action_tweak, "value": 'ANY', "shift": True}, None),
|
||||
("node.links_cut", {"type": params.action_tweak, "value": 'ANY', "ctrl": True}, None),
|
||||
("node.links_mute", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None),
|
||||
("node.select_link_viewer", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None),
|
||||
("node.backimage_fit", {"type": 'A', "value": 'PRESS', "alt": True}, None),
|
||||
("node.backimage_sample", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, None),
|
||||
|
@@ -91,7 +91,32 @@ class NewGeometryNodeTreeAssign(bpy.types.Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class CopyGeometryNodeTreeAssign(bpy.types.Operator):
|
||||
"""Copy the active geometry node group and assign it to the active modifier"""
|
||||
|
||||
bl_idname = "node.copy_geometry_node_group_assign"
|
||||
bl_label = "Copy Geometry Node Group"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return geometry_modifier_poll(context)
|
||||
|
||||
def execute(self, context):
|
||||
modifier = context.object.modifiers.active
|
||||
if modifier is None:
|
||||
return {'CANCELLED'}
|
||||
|
||||
group = modifier.node_group
|
||||
if group is None:
|
||||
return {'CANCELLED'}
|
||||
|
||||
modifier.node_group = group.copy()
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
classes = (
|
||||
NewGeometryNodesModifier,
|
||||
NewGeometryNodeTreeAssign,
|
||||
CopyGeometryNodeTreeAssign,
|
||||
)
|
||||
|
@@ -441,6 +441,7 @@ class QuickSmoke(ObjectModeOperator, Operator):
|
||||
|
||||
|
||||
class QuickLiquid(Operator):
|
||||
"""Make selected objects liquid"""
|
||||
bl_idname = "object.quick_liquid"
|
||||
bl_label = "Quick Liquid"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
@@ -62,18 +62,6 @@ class COLLECTION_PT_collection_flags(CollectionButtonsPanel, Panel):
|
||||
col.prop(vlc, "indirect_only", toggle=False)
|
||||
|
||||
|
||||
class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel):
|
||||
bl_label = "Line Art"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
collection = context.collection
|
||||
|
||||
row = layout.row()
|
||||
row.prop(collection, "lineart_usage")
|
||||
|
||||
class COLLECTION_PT_instancing(CollectionButtonsPanel, Panel):
|
||||
bl_label = "Instancing"
|
||||
|
||||
@@ -86,10 +74,24 @@ class COLLECTION_PT_instancing(CollectionButtonsPanel, Panel):
|
||||
row = layout.row()
|
||||
row.prop(collection, "instance_offset")
|
||||
|
||||
|
||||
class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel):
|
||||
bl_label = "Line Art"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
collection = context.collection
|
||||
|
||||
row = layout.row()
|
||||
row.prop(collection, "lineart_usage")
|
||||
|
||||
|
||||
classes = (
|
||||
COLLECTION_PT_collection_flags,
|
||||
COLLECTION_PT_lineart_collection,
|
||||
COLLECTION_PT_instancing,
|
||||
COLLECTION_PT_lineart_collection,
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
|
@@ -97,7 +97,12 @@ class DATA_PT_EEVEE_light(DataButtonsPanel, Panel):
|
||||
col = layout.column()
|
||||
col.prop(light, "color")
|
||||
col.prop(light, "energy")
|
||||
|
||||
col.separator()
|
||||
|
||||
col.prop(light, "diffuse_factor", text="Diffuse")
|
||||
col.prop(light, "specular_factor", text="Specular")
|
||||
col.prop(light, "volume_factor", text="Volume")
|
||||
|
||||
col.separator()
|
||||
|
||||
|
@@ -245,8 +245,8 @@ class MATERIAL_PT_gpencil_custom_props(GPMaterialButtonsPanel, PropertyPanel, Pa
|
||||
_property_type = bpy.types.Material
|
||||
|
||||
|
||||
class MATERIAL_PT_gpencil_options(GPMaterialButtonsPanel, Panel):
|
||||
bl_label = "Options"
|
||||
class MATERIAL_PT_gpencil_settings(GPMaterialButtonsPanel, Panel):
|
||||
bl_label = "Settings"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
@@ -275,7 +275,7 @@ classes = (
|
||||
MATERIAL_PT_gpencil_surface,
|
||||
MATERIAL_PT_gpencil_strokecolor,
|
||||
MATERIAL_PT_gpencil_fillcolor,
|
||||
MATERIAL_PT_gpencil_options,
|
||||
MATERIAL_PT_gpencil_settings,
|
||||
MATERIAL_PT_gpencil_custom_props,
|
||||
)
|
||||
|
||||
|
@@ -164,7 +164,10 @@ class NODE_HT_header(Header):
|
||||
elif ob:
|
||||
active_modifier = ob.modifiers.active
|
||||
if active_modifier and active_modifier.type == "NODES":
|
||||
row.template_ID(active_modifier, "node_group", new="node.new_geometry_node_group_assign")
|
||||
if active_modifier.node_group:
|
||||
row.template_ID(active_modifier, "node_group", new="node.copy_geometry_node_group_assign")
|
||||
else:
|
||||
row.template_ID(active_modifier, "node_group", new="node.new_geometry_node_group_assign")
|
||||
else:
|
||||
row.template_ID(snode, "node_tree", new="node.new_geometry_nodes_modifier")
|
||||
|
||||
@@ -331,6 +334,7 @@ class NODE_MT_node(Menu):
|
||||
layout.operator("node.link_make", text="Make and Replace Links").replace = True
|
||||
layout.operator("node.links_cut")
|
||||
layout.operator("node.links_detach")
|
||||
layout.operator("node.links_mute")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@@ -352,8 +352,12 @@ class SEQUENCER_MT_view(Menu):
|
||||
if is_sequencer_view:
|
||||
layout.prop(st, "show_region_hud")
|
||||
|
||||
layout.separator()
|
||||
|
||||
if st.view_type == 'SEQUENCER':
|
||||
layout.prop(st, "show_backdrop", text="Preview as Backdrop")
|
||||
if is_preview or st.show_backdrop:
|
||||
layout.prop(st, "show_transform_preview", text="Preview During Transform")
|
||||
|
||||
layout.separator()
|
||||
|
||||
@@ -724,6 +728,7 @@ class SEQUENCER_MT_strip_image_transform(Menu):
|
||||
layout.operator("sequencer.strip_transform_clear", text="Clear Rotation").property = 'ROTATION'
|
||||
layout.operator("sequencer.strip_transform_clear", text="Clear All").property = 'ALL'
|
||||
|
||||
|
||||
class SEQUENCER_MT_strip_transform(Menu):
|
||||
bl_label = "Transform"
|
||||
|
||||
@@ -1271,7 +1276,13 @@ class SEQUENCER_PT_effect_text_style(SequencerButtonsPanel, Panel):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
col = layout.column()
|
||||
col.template_ID(strip, "font", open="font.open", unlink="font.unlink")
|
||||
|
||||
row = col.row(align=True)
|
||||
row.use_property_decorate = False
|
||||
row.template_ID(strip, "font", open="font.open", unlink="font.unlink")
|
||||
row.prop(strip, "use_bold", text="", icon="BOLD")
|
||||
row.prop(strip, "use_italic", text="", icon="ITALIC")
|
||||
|
||||
col.prop(strip, "font_size")
|
||||
col.prop(strip, "color")
|
||||
|
||||
@@ -1294,7 +1305,6 @@ class SEQUENCER_PT_effect_text_style(SequencerButtonsPanel, Panel):
|
||||
row.prop_decorator(strip, "box_color")
|
||||
|
||||
row = layout.row(align=True, heading="Box Margin")
|
||||
row.use_property_decorate = False
|
||||
sub = row.row(align=True)
|
||||
sub.prop(strip, "box_margin")
|
||||
sub.active = strip.use_box and (not strip.mute)
|
||||
@@ -1415,36 +1425,36 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
|
||||
return (strip.type == 'SCENE')
|
||||
|
||||
def draw(self, context):
|
||||
strip = act_strip(context)
|
||||
scene = strip.scene
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
strip = act_strip(context)
|
||||
|
||||
layout.active = not strip.mute
|
||||
|
||||
layout.template_ID(strip, "scene")
|
||||
|
||||
scene = strip.scene
|
||||
layout.prop(strip, "scene_input")
|
||||
|
||||
if scene:
|
||||
layout.prop(scene, "audio_volume", text="Volume")
|
||||
layout.template_ID(strip, "scene", text="Scene")
|
||||
layout.prop(strip, "scene_input", text="Input")
|
||||
|
||||
if strip.scene_input == 'CAMERA':
|
||||
layout.alignment = 'RIGHT'
|
||||
sub = layout.column(align=True)
|
||||
split = sub.split(factor=0.5, align=True)
|
||||
layout.template_ID(strip, "scene_camera", text="Camera")
|
||||
|
||||
if scene:
|
||||
# Build a manual split layout as a hack to get proper alignment with the rest of the buttons.
|
||||
sub = layout.row(align=True)
|
||||
sub.use_property_decorate = True
|
||||
split = sub.split(factor=0.4, align=True)
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="Camera")
|
||||
split.template_ID(strip, "scene_camera")
|
||||
|
||||
layout.prop(strip, "use_grease_pencil", text="Show Grease Pencil")
|
||||
split.label(text="Volume")
|
||||
split.prop(scene, "audio_volume", text="")
|
||||
sub.use_property_decorate = False
|
||||
|
||||
if strip.scene_input == 'CAMERA':
|
||||
layout = layout.column(heading="Show")
|
||||
layout.prop(strip, "use_grease_pencil", text="Grease Pencil")
|
||||
if scene:
|
||||
# Warning, this is not a good convention to follow.
|
||||
# Expose here because setting the alpha from the 'Render' menu is very inconvenient.
|
||||
# layout.label(text="Preview")
|
||||
layout.prop(scene.render, "film_transparent")
|
||||
|
||||
|
||||
|
@@ -34,7 +34,8 @@ class SPREADSHEET_HT_header(bpy.types.Header):
|
||||
layout.prop(space, "object_eval_state", text="")
|
||||
if space.object_eval_state != "ORIGINAL":
|
||||
layout.prop(space, "geometry_component_type", text="")
|
||||
layout.prop(space, "attribute_domain", text="")
|
||||
if space.geometry_component_type != 'INSTANCES':
|
||||
layout.prop(space, "attribute_domain", text="")
|
||||
|
||||
if used_id:
|
||||
layout.label(text=used_id.name, icon="OBJECT_DATA")
|
||||
|
@@ -3144,7 +3144,7 @@ class VIEW3D_MT_face_sets(Menu):
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.menu("VIEW3D_MT_face_sets_init", text="Init Face Sets")
|
||||
layout.menu("VIEW3D_MT_face_sets_init", text="Initialize Face Sets")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@@ -518,7 +518,7 @@ geometry_node_categories = [
|
||||
NodeItem("GeometryNodeBoolean"),
|
||||
NodeItem("GeometryNodeTriangulate"),
|
||||
NodeItem("GeometryNodeEdgeSplit"),
|
||||
NodeItem("GeometryNodeSubdivideSmooth"),
|
||||
NodeItem("GeometryNodeSubdivisionSurface"),
|
||||
NodeItem("GeometryNodeSubdivide"),
|
||||
|
||||
# These should be in a sub-menu, but that requires a refactor to build the add menu manually.
|
||||
|
@@ -201,11 +201,6 @@ void BKE_pose_apply_action(struct Object *ob,
|
||||
struct bAction *action,
|
||||
struct AnimationEvalContext *anim_eval_context);
|
||||
|
||||
/* get_objectspace_bone_matrix has to be removed still */
|
||||
void get_objectspace_bone_matrix(struct Bone *bone,
|
||||
float M_accumulatedMatrix[4][4],
|
||||
int root,
|
||||
int posed);
|
||||
void vec_roll_to_mat3(const float vec[3], const float roll, float r_mat[3][3]);
|
||||
void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_mat[3][3]);
|
||||
void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll);
|
||||
|
@@ -39,7 +39,7 @@ extern "C" {
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 12
|
||||
#define BLENDER_FILE_SUBVERSION 13
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
|
@@ -66,6 +66,8 @@ void BKE_curveprofile_selected_handle_set(struct CurveProfile *profile, int type
|
||||
|
||||
void BKE_curveprofile_reverse(struct CurveProfile *profile);
|
||||
|
||||
void BKE_curveprofile_reset_view(struct CurveProfile *profile);
|
||||
|
||||
void BKE_curveprofile_reset(struct CurveProfile *profile);
|
||||
|
||||
void BKE_curveprofile_create_samples(struct CurveProfile *profile,
|
||||
|
@@ -49,16 +49,6 @@ enum class GeometryOwnershipType {
|
||||
ReadOnly = 2,
|
||||
};
|
||||
|
||||
/* Make it possible to use the component type as key in hash tables. */
|
||||
namespace blender {
|
||||
template<> struct DefaultHash<GeometryComponentType> {
|
||||
uint64_t operator()(const GeometryComponentType &value) const
|
||||
{
|
||||
return (uint64_t)value;
|
||||
}
|
||||
};
|
||||
} // namespace blender
|
||||
|
||||
namespace blender::bke {
|
||||
class ComponentAttributeProviders;
|
||||
}
|
||||
|
@@ -42,6 +42,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Collection;
|
||||
struct ID;
|
||||
struct IDOverrideLibrary;
|
||||
struct IDOverrideLibraryProperty;
|
||||
@@ -81,6 +82,7 @@ bool BKE_lib_override_library_resync(struct Main *bmain,
|
||||
struct Scene *scene,
|
||||
struct ViewLayer *view_layer,
|
||||
struct ID *id_root,
|
||||
struct Collection *override_resync_residual_storage,
|
||||
const bool do_hierarchy_enforce);
|
||||
void BKE_lib_override_library_main_resync(struct Main *bmain,
|
||||
struct Scene *scene,
|
||||
|
@@ -627,6 +627,7 @@ struct bNodeLink *nodeAddLink(struct bNodeTree *ntree,
|
||||
struct bNodeSocket *tosock);
|
||||
void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link);
|
||||
void nodeRemSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock);
|
||||
void nodeMuteLinkToggle(struct bNodeTree *ntree, struct bNodeLink *link);
|
||||
bool nodeLinkIsHidden(const struct bNodeLink *link);
|
||||
void nodeInternalRelink(struct bNodeTree *ntree, struct bNode *node);
|
||||
|
||||
@@ -1289,10 +1290,11 @@ void ntreeCompositCryptomatteSyncFromRemove(bNode *node);
|
||||
bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node);
|
||||
int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node);
|
||||
void ntreeCompositCryptomatteLayerPrefix(const bNode *node, char *r_prefix, size_t prefix_len);
|
||||
|
||||
/* Update the runtime layer names with the cryptomatte layer names of the references
|
||||
* render layer or image. */
|
||||
void ntreeCompositCryptomatteUpdateLayerNames(bNode *node);
|
||||
struct CryptomatteSession *ntreeCompositCryptomatteSession(bNode *node);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -1358,7 +1360,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
|
||||
#define GEO_NODE_BOOLEAN 1003
|
||||
#define GEO_NODE_POINT_DISTRIBUTE 1004
|
||||
#define GEO_NODE_POINT_INSTANCE 1005
|
||||
#define GEO_NODE_SUBDIVIDE_SMOOTH 1006
|
||||
#define GEO_NODE_SUBDIVISION_SURFACE 1006
|
||||
#define GEO_NODE_OBJECT_INFO 1007
|
||||
#define GEO_NODE_ATTRIBUTE_RANDOMIZE 1008
|
||||
#define GEO_NODE_ATTRIBUTE_MATH 1009
|
||||
|
@@ -20,13 +20,17 @@
|
||||
|
||||
#include "BLI_hash.hh"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_multi_value_map.hh"
|
||||
#include "BLI_session_uuid.h"
|
||||
#include "BLI_set.hh"
|
||||
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_customdata_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_session_uuid_types.h"
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
|
||||
struct ModifierData;
|
||||
struct Object;
|
||||
struct bNode;
|
||||
@@ -77,9 +81,26 @@ struct NodeWarning {
|
||||
std::string message;
|
||||
};
|
||||
|
||||
struct AvailableAttributeInfo {
|
||||
AttributeDomain domain;
|
||||
CustomDataType data_type;
|
||||
|
||||
uint64_t hash() const
|
||||
{
|
||||
uint64_t domain_hash = (uint64_t)domain;
|
||||
uint64_t data_type_hash = (uint64_t)data_type;
|
||||
return (domain_hash * 33) ^ (data_type_hash * 89);
|
||||
}
|
||||
|
||||
friend bool operator==(const AvailableAttributeInfo &a, const AvailableAttributeInfo &b)
|
||||
{
|
||||
return a.domain == b.domain && a.data_type == b.data_type;
|
||||
}
|
||||
};
|
||||
|
||||
struct NodeUIStorage {
|
||||
blender::Vector<NodeWarning> warnings;
|
||||
blender::Set<std::string> attribute_name_hints;
|
||||
blender::MultiValueMap<std::string, AvailableAttributeInfo> attribute_hints;
|
||||
};
|
||||
|
||||
struct NodeTreeUIStorage {
|
||||
@@ -103,4 +124,6 @@ void BKE_nodetree_error_message_add(bNodeTree &ntree,
|
||||
void BKE_nodetree_attribute_hint_add(bNodeTree &ntree,
|
||||
const NodeTreeEvaluationContext &context,
|
||||
const bNode &node,
|
||||
const blender::StringRef attribute_name);
|
||||
const blender::StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type);
|
||||
|
@@ -359,7 +359,7 @@ void DM_init(DerivedMesh *dm,
|
||||
dm->needsFree = 1;
|
||||
dm->dirty = (DMDirtyFlag)0;
|
||||
|
||||
/* don't use CustomData_reset(...); because we dont want to touch customdata */
|
||||
/* Don't use CustomData_reset(...); because we don't want to touch custom-data. */
|
||||
copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
|
||||
copy_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1);
|
||||
copy_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1);
|
||||
|
@@ -1532,14 +1532,6 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan,
|
||||
/** \name Bone Space to Space Conversion API
|
||||
* \{ */
|
||||
|
||||
void get_objectspace_bone_matrix(struct Bone *bone,
|
||||
float M_accumulatedMatrix[4][4],
|
||||
int UNUSED(root),
|
||||
int UNUSED(posed))
|
||||
{
|
||||
copy_m4_m4(M_accumulatedMatrix, bone->arm_mat);
|
||||
}
|
||||
|
||||
/* Convert World-Space Matrix to Pose-Space Matrix */
|
||||
void BKE_armature_mat_world_to_pose(Object *ob, const float inmat[4][4], float outmat[4][4])
|
||||
{
|
||||
|
@@ -674,9 +674,10 @@ bool NamedLegacyCustomDataProvider::foreach_attribute(
|
||||
return true;
|
||||
}
|
||||
|
||||
void NamedLegacyCustomDataProvider::supported_domains(Vector<AttributeDomain> &r_domains) const
|
||||
void NamedLegacyCustomDataProvider::foreach_domain(
|
||||
const FunctionRef<void(AttributeDomain)> callback) const
|
||||
{
|
||||
r_domains.append_non_duplicates(domain_);
|
||||
callback(domain_);
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
@@ -18,6 +18,9 @@
|
||||
#include "BLI_span.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_vector.hh"
|
||||
#include "BLI_vector_set.hh"
|
||||
|
||||
#include "BKE_geometry_set.hh"
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
@@ -105,7 +108,7 @@ template<typename T> class OwnedArrayReadAttribute final : public ReadAttribute
|
||||
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
|
||||
class DerivedArrayReadAttribute final : public ReadAttribute {
|
||||
private:
|
||||
blender::Span<StructT> data_;
|
||||
Span<StructT> data_;
|
||||
|
||||
public:
|
||||
DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data)
|
||||
@@ -159,10 +162,10 @@ template<typename StructT,
|
||||
void (*SetFunc)(StructT &, const ElemT &)>
|
||||
class DerivedArrayWriteAttribute final : public WriteAttribute {
|
||||
private:
|
||||
blender::MutableSpan<StructT> data_;
|
||||
MutableSpan<StructT> data_;
|
||||
|
||||
public:
|
||||
DerivedArrayWriteAttribute(AttributeDomain domain, blender::MutableSpan<StructT> data)
|
||||
DerivedArrayWriteAttribute(AttributeDomain domain, MutableSpan<StructT> data)
|
||||
: WriteAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
|
||||
{
|
||||
}
|
||||
@@ -247,7 +250,7 @@ class BuiltinAttributeProvider {
|
||||
virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0;
|
||||
virtual bool exists(const GeometryComponent &component) const = 0;
|
||||
|
||||
blender::StringRefNull name() const
|
||||
StringRefNull name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
@@ -270,13 +273,12 @@ class BuiltinAttributeProvider {
|
||||
class DynamicAttributesProvider {
|
||||
public:
|
||||
virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component,
|
||||
const blender::StringRef attribute_name) const = 0;
|
||||
const StringRef attribute_name) const = 0;
|
||||
virtual WriteAttributePtr try_get_for_write(GeometryComponent &component,
|
||||
const blender::StringRef attribute_name) const = 0;
|
||||
virtual bool try_delete(GeometryComponent &component,
|
||||
const blender::StringRef attribute_name) const = 0;
|
||||
const StringRef attribute_name) const = 0;
|
||||
virtual bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0;
|
||||
virtual bool try_create(GeometryComponent &UNUSED(component),
|
||||
const blender::StringRef UNUSED(attribute_name),
|
||||
const StringRef UNUSED(attribute_name),
|
||||
const AttributeDomain UNUSED(domain),
|
||||
const CustomDataType UNUSED(data_type)) const
|
||||
{
|
||||
@@ -286,7 +288,7 @@ class DynamicAttributesProvider {
|
||||
|
||||
virtual bool foreach_attribute(const GeometryComponent &component,
|
||||
const AttributeForeachCallback callback) const = 0;
|
||||
virtual void supported_domains(blender::Vector<AttributeDomain> &r_domains) const = 0;
|
||||
virtual void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -308,25 +310,24 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
|
||||
}
|
||||
|
||||
ReadAttributePtr try_get_for_read(const GeometryComponent &component,
|
||||
const blender::StringRef attribute_name) const final;
|
||||
const StringRef attribute_name) const final;
|
||||
|
||||
WriteAttributePtr try_get_for_write(GeometryComponent &component,
|
||||
const blender::StringRef attribute_name) const final;
|
||||
const StringRef attribute_name) const final;
|
||||
|
||||
bool try_delete(GeometryComponent &component,
|
||||
const blender::StringRef attribute_name) const final;
|
||||
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
|
||||
|
||||
bool try_create(GeometryComponent &component,
|
||||
const blender::StringRef attribute_name,
|
||||
const StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type) const final;
|
||||
|
||||
bool foreach_attribute(const GeometryComponent &component,
|
||||
const AttributeForeachCallback callback) const final;
|
||||
|
||||
void supported_domains(blender::Vector<AttributeDomain> &r_domains) const final
|
||||
void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final
|
||||
{
|
||||
r_domains.append_non_duplicates(domain_);
|
||||
callback(domain_);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -388,7 +389,7 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
|
||||
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
|
||||
bool foreach_attribute(const GeometryComponent &component,
|
||||
const AttributeForeachCallback callback) const final;
|
||||
void supported_domains(Vector<AttributeDomain> &r_domains) const final;
|
||||
void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -448,49 +449,46 @@ class ComponentAttributeProviders {
|
||||
* higher priority when an attribute name is looked up. Usually, that means that builtin
|
||||
* providers are checked before dynamic ones.
|
||||
*/
|
||||
blender::Map<std::string, const BuiltinAttributeProvider *> builtin_attribute_providers_;
|
||||
Map<std::string, const BuiltinAttributeProvider *> builtin_attribute_providers_;
|
||||
/**
|
||||
* An ordered list of dynamic attribute providers. The order is important because that is order
|
||||
* in which they are checked when an attribute is looked up.
|
||||
*/
|
||||
blender::Vector<const DynamicAttributesProvider *> dynamic_attribute_providers_;
|
||||
Vector<const DynamicAttributesProvider *> dynamic_attribute_providers_;
|
||||
/**
|
||||
* All the domains that are supported by at least one of the providers above.
|
||||
*/
|
||||
blender::Vector<AttributeDomain> supported_domains_;
|
||||
VectorSet<AttributeDomain> supported_domains_;
|
||||
|
||||
public:
|
||||
ComponentAttributeProviders(
|
||||
blender::Span<const BuiltinAttributeProvider *> builtin_attribute_providers,
|
||||
blender::Span<const DynamicAttributesProvider *> dynamic_attribute_providers)
|
||||
ComponentAttributeProviders(Span<const BuiltinAttributeProvider *> builtin_attribute_providers,
|
||||
Span<const DynamicAttributesProvider *> dynamic_attribute_providers)
|
||||
: dynamic_attribute_providers_(dynamic_attribute_providers)
|
||||
{
|
||||
blender::Set<AttributeDomain> domains;
|
||||
for (const BuiltinAttributeProvider *provider : builtin_attribute_providers) {
|
||||
/* Use #add_new to make sure that no two builtin attributes have the same name. */
|
||||
builtin_attribute_providers_.add_new(provider->name(), provider);
|
||||
supported_domains_.append_non_duplicates(provider->domain());
|
||||
supported_domains_.add(provider->domain());
|
||||
}
|
||||
for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) {
|
||||
provider->supported_domains(supported_domains_);
|
||||
provider->foreach_domain([&](AttributeDomain domain) { supported_domains_.add(domain); });
|
||||
}
|
||||
}
|
||||
|
||||
const blender::Map<std::string, const BuiltinAttributeProvider *> &builtin_attribute_providers()
|
||||
const
|
||||
const Map<std::string, const BuiltinAttributeProvider *> &builtin_attribute_providers() const
|
||||
{
|
||||
return builtin_attribute_providers_;
|
||||
}
|
||||
|
||||
blender::Span<const DynamicAttributesProvider *> dynamic_attribute_providers() const
|
||||
Span<const DynamicAttributesProvider *> dynamic_attribute_providers() const
|
||||
{
|
||||
return dynamic_attribute_providers_;
|
||||
}
|
||||
|
||||
blender::Span<AttributeDomain> supported_domains() const
|
||||
Span<AttributeDomain> supported_domains() const
|
||||
{
|
||||
return supported_domains_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::bke
|
||||
} // namespace blender::bke
|
||||
|
@@ -485,6 +485,11 @@ void BKE_collection_add_from_collection(Main *bmain,
|
||||
collection_child_add(collection, collection_dst, 0, true);
|
||||
is_instantiated = true;
|
||||
}
|
||||
else if (!is_instantiated && collection_find_child(collection, collection_dst)) {
|
||||
/* If given collection_dst is already instantiated in scene, even if its 'model' src one is
|
||||
* not, do not add it to master scene collection. */
|
||||
is_instantiated = true;
|
||||
}
|
||||
}
|
||||
FOREACH_SCENE_COLLECTION_END;
|
||||
|
||||
|
@@ -435,6 +435,14 @@ static void curveprofile_build_steps(CurveProfile *profile)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the view to the clipping rectangle.
|
||||
*/
|
||||
void BKE_curveprofile_reset_view(CurveProfile *profile)
|
||||
{
|
||||
profile->view_rect = profile->clip_rect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the profile to the current preset.
|
||||
*
|
||||
|
@@ -341,7 +341,7 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
|
||||
|
||||
/* map faces to quads */
|
||||
if (em->tottri != bm->totface) {
|
||||
/* over alloc, since we dont know how many ngon or quads we have */
|
||||
/* Over allocate, since we don't know how many ngon or quads we have. */
|
||||
|
||||
/* map fake face index to looptri */
|
||||
face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
|
||||
|
@@ -2310,7 +2310,7 @@ static void adaptive_domain_adjust(
|
||||
z - fds->res_min[2]);
|
||||
max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
|
||||
|
||||
/* check high resolution bounds if max density isnt already high enough */
|
||||
/* Check high resolution bounds if max density isn't already high enough. */
|
||||
if (max_den < fds->adapt_threshold && fds->flags & FLUID_DOMAIN_USE_NOISE && fds->fluid) {
|
||||
int i, j, k;
|
||||
/* high res grid index */
|
||||
|
@@ -296,6 +296,47 @@ static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh,
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
|
||||
Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totedge);
|
||||
attribute_math::DefaultMixer<T> mixer(r_values);
|
||||
|
||||
for (const int poly_index : IndexRange(mesh.totpoly)) {
|
||||
const MPoly &poly = mesh.mpoly[poly_index];
|
||||
|
||||
/* For every edge, mix values from the two adjacent corners (the current and next corner). */
|
||||
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
|
||||
const int loop_index_next = (loop_index + 1) % poly.totloop;
|
||||
const MLoop &loop = mesh.mloop[loop_index];
|
||||
const int edge_index = loop.e;
|
||||
mixer.mix_in(edge_index, old_values[loop_index]);
|
||||
mixer.mix_in(edge_index, old_values[loop_index_next]);
|
||||
}
|
||||
}
|
||||
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static ReadAttributePtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totedge);
|
||||
adapt_mesh_domain_corner_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh,
|
||||
Span<T> old_values,
|
||||
@@ -365,6 +406,42 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh,
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void adapt_mesh_domain_polygon_to_edge_impl(const Mesh &mesh,
|
||||
const Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totedge);
|
||||
attribute_math::DefaultMixer<T> mixer(r_values);
|
||||
|
||||
for (const int poly_index : IndexRange(mesh.totpoly)) {
|
||||
const MPoly &poly = mesh.mpoly[poly_index];
|
||||
const T value = old_values[poly_index];
|
||||
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
|
||||
const MLoop &loop = mesh.mloop[loop_index];
|
||||
mixer.mix_in(loop.e, value);
|
||||
}
|
||||
}
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totedge);
|
||||
adapt_mesh_domain_polygon_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* \note Theoretically this interpolation does not need to compute all values at once.
|
||||
* However, doing that makes the implementation simpler, and this can be optimized in the future if
|
||||
@@ -406,6 +483,162 @@ static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh,
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* \note Theoretically this interpolation does not need to compute all values at once.
|
||||
* However, doing that makes the implementation simpler, and this can be optimized in the future if
|
||||
* only some values are required.
|
||||
*/
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
|
||||
const Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totedge);
|
||||
attribute_math::DefaultMixer<T> mixer(r_values);
|
||||
|
||||
for (const int edge_index : IndexRange(mesh.totedge)) {
|
||||
const MEdge &edge = mesh.medge[edge_index];
|
||||
mixer.mix_in(edge_index, old_values[edge.v1]);
|
||||
mixer.mix_in(edge_index, old_values[edge.v2]);
|
||||
}
|
||||
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static ReadAttributePtr adapt_mesh_domain_point_to_edge(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totedge);
|
||||
adapt_mesh_domain_point_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
|
||||
const Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totloop);
|
||||
attribute_math::DefaultMixer<T> mixer(r_values);
|
||||
|
||||
for (const int poly_index : IndexRange(mesh.totpoly)) {
|
||||
const MPoly &poly = mesh.mpoly[poly_index];
|
||||
|
||||
/* For every corner, mix the values from the adjacent edges on the polygon. */
|
||||
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
|
||||
const int loop_index_prev = (loop_index - 1) % poly.totloop;
|
||||
const MLoop &loop = mesh.mloop[loop_index];
|
||||
const MLoop &loop_prev = mesh.mloop[loop_index_prev];
|
||||
mixer.mix_in(loop_index, old_values[loop.e]);
|
||||
mixer.mix_in(loop_index, old_values[loop_prev.e]);
|
||||
}
|
||||
}
|
||||
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static ReadAttributePtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totloop);
|
||||
adapt_mesh_domain_edge_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
|
||||
const Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totvert);
|
||||
attribute_math::DefaultMixer<T> mixer(r_values);
|
||||
|
||||
for (const int edge_index : IndexRange(mesh.totedge)) {
|
||||
const MEdge &edge = mesh.medge[edge_index];
|
||||
const T value = old_values[edge_index];
|
||||
mixer.mix_in(edge.v1, value);
|
||||
mixer.mix_in(edge.v2, value);
|
||||
}
|
||||
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totvert);
|
||||
adapt_mesh_domain_edge_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* \note Theoretically this interpolation does not need to compute all values at once.
|
||||
* However, doing that makes the implementation simpler, and this can be optimized in the future if
|
||||
* only some values are required.
|
||||
*/
|
||||
template<typename T>
|
||||
static void adapt_mesh_domain_edge_to_polygon_impl(const Mesh &mesh,
|
||||
const Span<T> old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
BLI_assert(r_values.size() == mesh.totpoly);
|
||||
attribute_math::DefaultMixer<T> mixer(r_values);
|
||||
|
||||
for (const int poly_index : IndexRange(mesh.totpoly)) {
|
||||
const MPoly &poly = mesh.mpoly[poly_index];
|
||||
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
|
||||
const MLoop &loop = mesh.mloop[loop_index];
|
||||
mixer.mix_in(poly_index, old_values[loop.e]);
|
||||
}
|
||||
}
|
||||
|
||||
mixer.finalize();
|
||||
}
|
||||
|
||||
static ReadAttributePtr adapt_mesh_domain_edge_to_polygon(const Mesh &mesh,
|
||||
ReadAttributePtr attribute)
|
||||
{
|
||||
ReadAttributePtr new_attribute;
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
|
||||
Array<T> values(mesh.totpoly);
|
||||
adapt_mesh_domain_edge_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
|
||||
new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
|
||||
std::move(values));
|
||||
}
|
||||
});
|
||||
return new_attribute;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute,
|
||||
@@ -429,7 +662,10 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
|
||||
return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_POLYGON:
|
||||
return blender::bke::adapt_mesh_domain_corner_to_polygon(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute));
|
||||
default:
|
||||
BLI_assert(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -440,7 +676,10 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
|
||||
return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_POLYGON:
|
||||
return blender::bke::adapt_mesh_domain_point_to_polygon(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute));
|
||||
default:
|
||||
BLI_assert(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -451,12 +690,30 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
|
||||
return blender::bke::adapt_mesh_domain_polygon_to_point(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
return blender::bke::adapt_mesh_domain_polygon_to_corner(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
return blender::bke::adapt_mesh_domain_polygon_to_edge(*mesh_, std::move(attribute));
|
||||
default:
|
||||
BLI_assert(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
switch (new_domain) {
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_POINT:
|
||||
return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(attribute));
|
||||
case ATTR_DOMAIN_POLYGON:
|
||||
return blender::bke::adapt_mesh_domain_edge_to_polygon(*mesh_, std::move(attribute));
|
||||
default:
|
||||
BLI_assert(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -782,9 +1039,9 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
|
||||
return true;
|
||||
}
|
||||
|
||||
void supported_domains(Vector<AttributeDomain> &r_domains) const final
|
||||
void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final
|
||||
{
|
||||
r_domains.append_non_duplicates(ATTR_DOMAIN_POINT);
|
||||
callback(ATTR_DOMAIN_POINT);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -230,6 +230,11 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGrou
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't create an empty mesh. */
|
||||
if ((totverts + totloops + totedges + totpolys) == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
|
||||
/* Copy settings from the first input geometry set with a mesh. */
|
||||
for (const GeometryInstanceGroup &set_group : set_groups) {
|
||||
@@ -366,6 +371,9 @@ static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups,
|
||||
{
|
||||
Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(set_groups,
|
||||
convert_points_to_vertices);
|
||||
if (new_mesh == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
MeshComponent &dst_component = result.get_component_for_write<MeshComponent>();
|
||||
dst_component.replace(new_mesh);
|
||||
@@ -397,6 +405,9 @@ static void join_instance_groups_pointcloud(Span<GeometryInstanceGroup> set_grou
|
||||
totpoint += component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
}
|
||||
}
|
||||
if (totpoint == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
|
||||
PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoint);
|
||||
|
@@ -663,6 +663,7 @@ static void lib_override_library_create_post_process(Main *bmain,
|
||||
ViewLayer *view_layer,
|
||||
ID *id_root,
|
||||
ID *id_reference,
|
||||
Collection *residual_storage,
|
||||
const bool is_resync)
|
||||
{
|
||||
BKE_main_collection_sync(bmain);
|
||||
@@ -718,7 +719,12 @@ static void lib_override_library_create_post_process(Main *bmain,
|
||||
Object *ob_new = (Object *)id_root->newid;
|
||||
if (!lib_override_library_create_post_process_object_is_instantiated(
|
||||
view_layer, ob_new, is_resync)) {
|
||||
BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ob_new);
|
||||
if (is_resync && residual_storage != NULL) {
|
||||
BKE_collection_object_add(bmain, residual_storage, ob_new);
|
||||
}
|
||||
else {
|
||||
BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ob_new);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -734,7 +740,7 @@ static void lib_override_library_create_post_process(Main *bmain,
|
||||
BLI_assert(ob_new->id.override_library != NULL &&
|
||||
ob_new->id.override_library->reference == &ob->id);
|
||||
|
||||
Collection *default_instantiating_collection = NULL;
|
||||
Collection *default_instantiating_collection = residual_storage;
|
||||
if (!lib_override_library_create_post_process_object_is_instantiated(
|
||||
view_layer, ob_new, is_resync)) {
|
||||
if (default_instantiating_collection == NULL) {
|
||||
@@ -799,7 +805,8 @@ bool BKE_lib_override_library_create(
|
||||
return success;
|
||||
}
|
||||
|
||||
lib_override_library_create_post_process(bmain, scene, view_layer, id_root, id_reference, false);
|
||||
lib_override_library_create_post_process(
|
||||
bmain, scene, view_layer, id_root, id_reference, NULL, false);
|
||||
|
||||
/* Cleanup. */
|
||||
BKE_main_id_clear_newpoins(bmain);
|
||||
@@ -858,10 +865,15 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain,
|
||||
* \param id_root: The root liboverride ID to resync from.
|
||||
* \return true if override was successfully resynced.
|
||||
*/
|
||||
bool BKE_lib_override_library_resync(
|
||||
Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root, const bool do_hierarchy_enforce)
|
||||
bool BKE_lib_override_library_resync(Main *bmain,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
ID *id_root,
|
||||
Collection *override_resync_residual_storage,
|
||||
const bool do_hierarchy_enforce)
|
||||
{
|
||||
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
|
||||
BLI_assert(!ID_IS_LINKED(id_root));
|
||||
|
||||
ID *id_root_reference = id_root->override_library->reference;
|
||||
|
||||
@@ -1069,8 +1081,13 @@ bool BKE_lib_override_library_resync(
|
||||
* since we already relinked old root override collection to new resync'ed one above. So this
|
||||
* call is not expected to instantiate this new resync'ed collection anywhere, just to ensure
|
||||
* that we do not have any stray objects. */
|
||||
lib_override_library_create_post_process(
|
||||
bmain, scene, view_layer, id_root_reference, id_root, true);
|
||||
lib_override_library_create_post_process(bmain,
|
||||
scene,
|
||||
view_layer,
|
||||
id_root_reference,
|
||||
id_root,
|
||||
override_resync_residual_storage,
|
||||
true);
|
||||
|
||||
/* Cleanup. */
|
||||
BLI_ghash_free(linkedref_to_old_override, NULL, NULL);
|
||||
@@ -1097,6 +1114,23 @@ bool BKE_lib_override_library_resync(
|
||||
*/
|
||||
void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer *view_layer)
|
||||
{
|
||||
/* We use a specific collection to gather/store all 'orphaned' override collections and objects
|
||||
* generated by resyncprocess. This avoids putting them in scene's master collection. */
|
||||
#define OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME "OVERRIDE_RESYNC_LEFTOVERS"
|
||||
Collection *override_resync_residual_storage = BLI_findstring(
|
||||
&bmain->collections, OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME, offsetof(ID, name) + 2);
|
||||
if (override_resync_residual_storage != NULL &&
|
||||
override_resync_residual_storage->id.lib != NULL) {
|
||||
override_resync_residual_storage = NULL;
|
||||
}
|
||||
if (override_resync_residual_storage == NULL) {
|
||||
override_resync_residual_storage = BKE_collection_add(
|
||||
bmain, scene->master_collection, OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME);
|
||||
/* Hide the collection from viewport and render. */
|
||||
override_resync_residual_storage->flag |= COLLECTION_RESTRICT_VIEWPORT |
|
||||
COLLECTION_RESTRICT_RENDER;
|
||||
}
|
||||
|
||||
BKE_main_relations_create(bmain, 0);
|
||||
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
|
||||
|
||||
@@ -1108,7 +1142,7 @@ void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer *
|
||||
* those used by current existing overrides. */
|
||||
ID *id;
|
||||
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
||||
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
|
||||
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || ID_IS_LINKED(id)) {
|
||||
continue;
|
||||
}
|
||||
if (id->tag & (LIB_TAG_DOIT | LIB_TAG_MISSING)) {
|
||||
@@ -1130,7 +1164,7 @@ void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer *
|
||||
/* Now check existing overrides, those needing resync will be the one either already tagged as
|
||||
* such, or the one using linked data that is now tagged as needing override. */
|
||||
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
||||
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
|
||||
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || ID_IS_LINKED(id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1180,9 +1214,14 @@ void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer *
|
||||
if ((id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0) {
|
||||
continue;
|
||||
}
|
||||
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id));
|
||||
if (ID_IS_LINKED(id)) {
|
||||
continue;
|
||||
}
|
||||
do_continue = true;
|
||||
CLOG_INFO(&LOG, 2, "Resyncing %s...", id->name);
|
||||
const bool success = BKE_lib_override_library_resync(bmain, scene, view_layer, id, false);
|
||||
const bool success = BKE_lib_override_library_resync(
|
||||
bmain, scene, view_layer, id, override_resync_residual_storage, false);
|
||||
CLOG_INFO(&LOG, 2, "\tSuccess: %d", success);
|
||||
break;
|
||||
}
|
||||
@@ -1193,6 +1232,10 @@ void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer *
|
||||
}
|
||||
FOREACH_MAIN_LISTBASE_END;
|
||||
}
|
||||
|
||||
if (BKE_collection_is_empty(override_resync_residual_storage)) {
|
||||
BKE_collection_delete(bmain, override_resync_residual_storage, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2240,10 +2283,11 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
|
||||
|
||||
local->tag |= LIB_TAG_OVERRIDE_LIBRARY_REFOK;
|
||||
|
||||
/* Full rebuild of Depsgraph! */
|
||||
/* Note: this is really brute force, in theory updates from RNA should have handled this already,
|
||||
* but for now let's play it safe. */
|
||||
DEG_id_tag_update_ex(bmain, local, ID_RECALC_COPY_ON_WRITE);
|
||||
/* Note: Since we reload full content from linked ID here, potentially from edited local
|
||||
* override, we do not really have a way to know *what* is changed, so we need to rely on the
|
||||
* massive destruction weapon of `ID_RECALC_ALL` here. */
|
||||
DEG_id_tag_update_ex(bmain, local, ID_RECALC_ALL);
|
||||
/* For same reason as above, also assume that the relationships between IDs changed. */
|
||||
DEG_relations_tag_update(bmain);
|
||||
}
|
||||
|
||||
|
@@ -881,7 +881,7 @@ Mesh *BKE_mesh_new_nomain(
|
||||
NULL, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE);
|
||||
BKE_libblock_init_empty(&mesh->id);
|
||||
|
||||
/* don't use CustomData_reset(...); because we dont want to touch customdata */
|
||||
/* Don't use CustomData_reset(...); because we don't want to touch custom-data. */
|
||||
copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1);
|
||||
copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1);
|
||||
copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1);
|
||||
|
@@ -635,7 +635,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
|
||||
|
||||
/* map faces to quads */
|
||||
if (looptri_len != mpoly_len) {
|
||||
/* over alloc, since we dont know how many ngon or quads we have */
|
||||
/* Over allocate, since we don't know how many ngon or quads we have. */
|
||||
|
||||
/* map fake face index to looptri */
|
||||
face_as_quad_map = MEM_mallocN(sizeof(int) * looptri_len, __func__);
|
||||
|
@@ -107,6 +107,9 @@ static void node_free_node(bNodeTree *ntree, bNode *node);
|
||||
static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
|
||||
bNodeSocket *sock,
|
||||
const bool do_id_user);
|
||||
static void nodeMuteRerouteOutputLinks(struct bNodeTree *ntree,
|
||||
struct bNode *node,
|
||||
const bool mute);
|
||||
|
||||
static void ntree_init_data(ID *id)
|
||||
{
|
||||
@@ -2215,6 +2218,106 @@ void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if all output links are muted or not. */
|
||||
static bool nodeMuteFromSocketLinks(const bNodeTree *ntree, const bNodeSocket *sock)
|
||||
{
|
||||
int tot = 0;
|
||||
int muted = 0;
|
||||
LISTBASE_FOREACH (const bNodeLink *, link, &ntree->links) {
|
||||
if (link->fromsock == sock) {
|
||||
tot++;
|
||||
if (link->flag & NODE_LINK_MUTED) {
|
||||
muted++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tot == muted;
|
||||
}
|
||||
|
||||
static void nodeMuteLink(bNodeLink *link)
|
||||
{
|
||||
link->flag |= NODE_LINK_MUTED;
|
||||
link->flag |= NODE_LINK_TEST;
|
||||
if (!(link->tosock->flag & SOCK_MULTI_INPUT)) {
|
||||
link->tosock->flag &= ~SOCK_IN_USE;
|
||||
}
|
||||
}
|
||||
|
||||
static void nodeUnMuteLink(bNodeLink *link)
|
||||
{
|
||||
link->flag &= ~NODE_LINK_MUTED;
|
||||
link->flag |= NODE_LINK_TEST;
|
||||
link->tosock->flag |= SOCK_IN_USE;
|
||||
}
|
||||
|
||||
/* Upstream muting. Always happens when unmuting but checks when muting. O(n^2) algorithm.*/
|
||||
static void nodeMuteRerouteInputLinks(bNodeTree *ntree, bNode *node, const bool mute)
|
||||
{
|
||||
if (node->type != NODE_REROUTE) {
|
||||
return;
|
||||
}
|
||||
if (!mute || nodeMuteFromSocketLinks(ntree, (bNodeSocket *)node->outputs.first)) {
|
||||
bNodeSocket *sock = (bNodeSocket *)node->inputs.first;
|
||||
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
|
||||
if (!(link->flag & NODE_LINK_VALID) || (link->tosock != sock)) {
|
||||
continue;
|
||||
}
|
||||
if (mute) {
|
||||
nodeMuteLink(link);
|
||||
}
|
||||
else {
|
||||
nodeUnMuteLink(link);
|
||||
}
|
||||
nodeMuteRerouteInputLinks(ntree, link->fromnode, mute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Downstream muting propagates when reaching reroute nodes. O(n^2) algorithm.*/
|
||||
static void nodeMuteRerouteOutputLinks(bNodeTree *ntree, bNode *node, const bool mute)
|
||||
{
|
||||
if (node->type != NODE_REROUTE) {
|
||||
return;
|
||||
}
|
||||
bNodeSocket *sock;
|
||||
sock = (bNodeSocket *)node->outputs.first;
|
||||
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
|
||||
if (!(link->flag & NODE_LINK_VALID) || (link->fromsock != sock)) {
|
||||
continue;
|
||||
}
|
||||
if (mute) {
|
||||
nodeMuteLink(link);
|
||||
}
|
||||
else {
|
||||
nodeUnMuteLink(link);
|
||||
}
|
||||
nodeMuteRerouteOutputLinks(ntree, link->tonode, mute);
|
||||
}
|
||||
}
|
||||
|
||||
void nodeMuteLinkToggle(bNodeTree *ntree, bNodeLink *link)
|
||||
{
|
||||
if (link->tosock) {
|
||||
bool mute = !(link->flag & NODE_LINK_MUTED);
|
||||
if (mute) {
|
||||
nodeMuteLink(link);
|
||||
}
|
||||
else {
|
||||
nodeUnMuteLink(link);
|
||||
}
|
||||
if (link->tonode->type == NODE_REROUTE) {
|
||||
nodeMuteRerouteOutputLinks(ntree, link->tonode, mute);
|
||||
}
|
||||
if (link->fromnode->type == NODE_REROUTE) {
|
||||
nodeMuteRerouteInputLinks(ntree, link->fromnode, mute);
|
||||
}
|
||||
}
|
||||
|
||||
if (ntree) {
|
||||
ntree->update |= NTREE_UPDATE_LINKS;
|
||||
}
|
||||
}
|
||||
|
||||
void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
|
||||
{
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
|
||||
@@ -2257,6 +2360,10 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
|
||||
link->flag &= ~NODE_LINK_VALID;
|
||||
}
|
||||
|
||||
if (fromlink->flag & NODE_LINK_MUTED) {
|
||||
link->flag |= NODE_LINK_MUTED;
|
||||
}
|
||||
|
||||
ntree->update |= NTREE_UPDATE_LINKS;
|
||||
}
|
||||
else {
|
||||
@@ -4014,7 +4121,9 @@ void ntreeTagUsedSockets(bNodeTree *ntree)
|
||||
|
||||
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
|
||||
link->fromsock->flag |= SOCK_IN_USE;
|
||||
link->tosock->flag |= SOCK_IN_USE;
|
||||
if (!(link->flag & NODE_LINK_MUTED)) {
|
||||
link->tosock->flag |= SOCK_IN_USE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4828,8 +4937,8 @@ static void registerGeometryNodes()
|
||||
register_node_type_geo_point_translate();
|
||||
register_node_type_geo_points_to_volume();
|
||||
register_node_type_geo_sample_texture();
|
||||
register_node_type_geo_subdivide_smooth();
|
||||
register_node_type_geo_subdivide();
|
||||
register_node_type_geo_subdivision_surface();
|
||||
register_node_type_geo_transform();
|
||||
register_node_type_geo_triangulate();
|
||||
register_node_type_geo_volume_to_mesh();
|
||||
|
@@ -158,8 +158,11 @@ void BKE_nodetree_error_message_add(bNodeTree &ntree,
|
||||
void BKE_nodetree_attribute_hint_add(bNodeTree &ntree,
|
||||
const NodeTreeEvaluationContext &context,
|
||||
const bNode &node,
|
||||
const StringRef attribute_name)
|
||||
const StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type)
|
||||
{
|
||||
NodeUIStorage &node_ui_storage = node_ui_storage_ensure(ntree, context, node);
|
||||
node_ui_storage.attribute_name_hints.add_as(attribute_name);
|
||||
node_ui_storage.attribute_hints.add_as(attribute_name,
|
||||
AvailableAttributeInfo{domain, data_type});
|
||||
}
|
||||
|
@@ -60,6 +60,16 @@ template<
|
||||
*/
|
||||
typename Allocator = GuardedAllocator>
|
||||
class Array {
|
||||
public:
|
||||
using value_type = T;
|
||||
using pointer = T *;
|
||||
using const_pointer = const T *;
|
||||
using reference = T &;
|
||||
using const_reference = const T &;
|
||||
using iterator = T *;
|
||||
using const_iterator = const T *;
|
||||
using size_type = int64_t;
|
||||
|
||||
private:
|
||||
/** The beginning of the array. It might point into the inline buffer. */
|
||||
T *data_;
|
||||
|
@@ -22,7 +22,7 @@ extern "C" {
|
||||
|
||||
/* only include from header */
|
||||
#ifndef __BLI_ENDIAN_SWITCH_H__
|
||||
# error "this file isnt to be directly included"
|
||||
# error "this file isn't to be directly included"
|
||||
#endif
|
||||
|
||||
/** \file
|
||||
|
@@ -35,6 +35,16 @@ struct float4x4 {
|
||||
{
|
||||
}
|
||||
|
||||
/* Assumes an XYZ euler order. */
|
||||
static float4x4 from_loc_eul_scale(const float3 location,
|
||||
const float3 rotation,
|
||||
const float3 scale)
|
||||
{
|
||||
float4x4 mat;
|
||||
loc_eul_size_to_mat4(mat.values, location, rotation, scale);
|
||||
return mat;
|
||||
}
|
||||
|
||||
operator float *()
|
||||
{
|
||||
return &values[0][0];
|
||||
@@ -79,6 +89,26 @@ struct float4x4 {
|
||||
return m * float3(v);
|
||||
}
|
||||
|
||||
float3 translation() const
|
||||
{
|
||||
return float3(values[3]);
|
||||
}
|
||||
|
||||
/* Assumes XYZ rotation order. */
|
||||
float3 to_euler() const
|
||||
{
|
||||
float3 euler;
|
||||
mat4_to_eul(euler, values);
|
||||
return euler;
|
||||
}
|
||||
|
||||
float3 scale() const
|
||||
{
|
||||
float3 scale;
|
||||
mat4_to_size(scale, values);
|
||||
return scale;
|
||||
}
|
||||
|
||||
float4x4 inverted() const
|
||||
{
|
||||
float4x4 result;
|
||||
|
@@ -88,11 +88,18 @@ namespace blender {
|
||||
* If there is no other specialization of #DefaultHash for a given type, try to call `hash()` on
|
||||
* the value. If there is no such method, this will result in a compiler error. Usually that means
|
||||
* that you have to implement a hash function using one of three strategies listed above.
|
||||
*
|
||||
* In the case of an enum type, the default hash is just to cast the enum value to an integer.
|
||||
*/
|
||||
template<typename T> struct DefaultHash {
|
||||
uint64_t operator()(const T &value) const
|
||||
{
|
||||
return value.hash();
|
||||
if constexpr (std::is_enum_v<T>) {
|
||||
return (uint64_t)value;
|
||||
}
|
||||
else {
|
||||
return value.hash();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -82,11 +82,18 @@ class IndexRange {
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = int64_t;
|
||||
using pointer = const int64_t *;
|
||||
using reference = const int64_t &;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
private:
|
||||
int64_t current_;
|
||||
|
||||
public:
|
||||
constexpr Iterator(int64_t current) : current_(current)
|
||||
constexpr explicit Iterator(int64_t current) : current_(current)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -96,9 +103,21 @@ class IndexRange {
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const Iterator &iterator) const
|
||||
constexpr Iterator operator++(int) const
|
||||
{
|
||||
return current_ != iterator.current_;
|
||||
Iterator copied_iterator = *this;
|
||||
++copied_iterator;
|
||||
return copied_iterator;
|
||||
}
|
||||
|
||||
constexpr friend bool operator!=(const Iterator &a, const Iterator &b)
|
||||
{
|
||||
return a.current_ != b.current_;
|
||||
}
|
||||
|
||||
constexpr friend bool operator==(const Iterator &a, const Iterator &b)
|
||||
{
|
||||
return a.current_ == b.current_;
|
||||
}
|
||||
|
||||
constexpr int64_t operator*() const
|
||||
|
@@ -21,7 +21,7 @@
|
||||
* \brief Single link-list utility macros. (header only api).
|
||||
*
|
||||
* Use this api when the structure defines its own ``next`` pointer
|
||||
* and a double linked list such as #ListBase isnt needed.
|
||||
* and a double linked list such as #ListBase isn't needed.
|
||||
*/
|
||||
|
||||
#define BLI_LINKS_PREPEND(list, link) \
|
||||
|
@@ -120,6 +120,9 @@ template<
|
||||
*/
|
||||
typename Allocator = GuardedAllocator>
|
||||
class Map {
|
||||
public:
|
||||
using size_type = int64_t;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Slots are either empty, occupied or removed. The number of occupied slots can be computed by
|
||||
@@ -623,6 +626,9 @@ class Map {
|
||||
* This uses the "curiously recurring template pattern" (CRTP).
|
||||
*/
|
||||
template<typename SubIterator> struct BaseIterator {
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
Slot *slots_;
|
||||
int64_t total_slots_;
|
||||
int64_t current_slot_;
|
||||
@@ -642,6 +648,13 @@ class Map {
|
||||
return *this;
|
||||
}
|
||||
|
||||
BaseIterator operator++(int) const
|
||||
{
|
||||
BaseIterator copied_iterator = *this;
|
||||
++copied_iterator;
|
||||
return copied_iterator;
|
||||
}
|
||||
|
||||
friend bool operator!=(const BaseIterator &a, const BaseIterator &b)
|
||||
{
|
||||
BLI_assert(a.slots_ == b.slots_);
|
||||
@@ -649,6 +662,11 @@ class Map {
|
||||
return a.current_slot_ != b.current_slot_;
|
||||
}
|
||||
|
||||
friend bool operator==(const BaseIterator &a, const BaseIterator &b)
|
||||
{
|
||||
return !(a != b);
|
||||
}
|
||||
|
||||
SubIterator begin() const
|
||||
{
|
||||
for (int64_t i = 0; i < total_slots_; i++) {
|
||||
@@ -672,6 +690,10 @@ class Map {
|
||||
|
||||
class KeyIterator final : public BaseIterator<KeyIterator> {
|
||||
public:
|
||||
using value_type = Key;
|
||||
using pointer = const Key *;
|
||||
using reference = const Key &;
|
||||
|
||||
KeyIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
|
||||
: BaseIterator<KeyIterator>(slots, total_slots, current_slot)
|
||||
{
|
||||
@@ -685,6 +707,10 @@ class Map {
|
||||
|
||||
class ValueIterator final : public BaseIterator<ValueIterator> {
|
||||
public:
|
||||
using value_type = Value;
|
||||
using pointer = const Value *;
|
||||
using reference = const Value &;
|
||||
|
||||
ValueIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
|
||||
: BaseIterator<ValueIterator>(slots, total_slots, current_slot)
|
||||
{
|
||||
@@ -698,6 +724,10 @@ class Map {
|
||||
|
||||
class MutableValueIterator final : public BaseIterator<MutableValueIterator> {
|
||||
public:
|
||||
using value_type = Value;
|
||||
using pointer = Value *;
|
||||
using reference = Value &;
|
||||
|
||||
MutableValueIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
|
||||
: BaseIterator<MutableValueIterator>(slots, total_slots, current_slot)
|
||||
{
|
||||
@@ -726,6 +756,10 @@ class Map {
|
||||
|
||||
class ItemIterator final : public BaseIterator<ItemIterator> {
|
||||
public:
|
||||
using value_type = Item;
|
||||
using pointer = Item *;
|
||||
using reference = Item &;
|
||||
|
||||
ItemIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
|
||||
: BaseIterator<ItemIterator>(slots, total_slots, current_slot)
|
||||
{
|
||||
@@ -740,6 +774,10 @@ class Map {
|
||||
|
||||
class MutableItemIterator final : public BaseIterator<MutableItemIterator> {
|
||||
public:
|
||||
using value_type = MutableItem;
|
||||
using pointer = MutableItem *;
|
||||
using reference = MutableItem &;
|
||||
|
||||
MutableItemIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
|
||||
: BaseIterator<MutableItemIterator>(slots, total_slots, current_slot)
|
||||
{
|
||||
|
@@ -38,6 +38,9 @@
|
||||
namespace blender {
|
||||
|
||||
template<typename Key, typename Value> class MultiValueMap {
|
||||
public:
|
||||
using size_type = int64_t;
|
||||
|
||||
private:
|
||||
using MapType = Map<Key, Vector<Value>>;
|
||||
MapType map_;
|
||||
|
@@ -119,6 +119,16 @@ template<
|
||||
*/
|
||||
typename Allocator = GuardedAllocator>
|
||||
class Set {
|
||||
public:
|
||||
class Iterator;
|
||||
using value_type = Key;
|
||||
using pointer = Key *;
|
||||
using const_pointer = const Key *;
|
||||
using reference = Key &;
|
||||
using const_reference = const Key &;
|
||||
using iterator = Iterator;
|
||||
using size_type = int64_t;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Slots are either empty, occupied or removed. The number of occupied slots can be computed by
|
||||
@@ -401,6 +411,13 @@ class Set {
|
||||
* also change their hash.
|
||||
*/
|
||||
class Iterator {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = Key;
|
||||
using pointer = const Key *;
|
||||
using reference = const Key &;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
private:
|
||||
const Slot *slots_;
|
||||
int64_t total_slots_;
|
||||
@@ -422,17 +439,34 @@ class Set {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int) const
|
||||
{
|
||||
Iterator copied_iterator = *this;
|
||||
++copied_iterator;
|
||||
return copied_iterator;
|
||||
}
|
||||
|
||||
const Key &operator*() const
|
||||
{
|
||||
return *slots_[current_slot_].key();
|
||||
}
|
||||
|
||||
const Key *operator->() const
|
||||
{
|
||||
return slots_[current_slot_].key();
|
||||
}
|
||||
|
||||
friend bool operator!=(const Iterator &a, const Iterator &b)
|
||||
{
|
||||
BLI_assert(a.slots_ == b.slots_);
|
||||
BLI_assert(a.total_slots_ == b.total_slots_);
|
||||
return a.current_slot_ != b.current_slot_;
|
||||
}
|
||||
|
||||
friend bool operator==(const Iterator &a, const Iterator &b)
|
||||
{
|
||||
return !(a != b);
|
||||
}
|
||||
};
|
||||
|
||||
Iterator begin() const
|
||||
|
@@ -85,6 +85,15 @@ namespace blender {
|
||||
* modified.
|
||||
*/
|
||||
template<typename T> class Span {
|
||||
public:
|
||||
using value_type = T;
|
||||
using pointer = T *;
|
||||
using const_pointer = const T *;
|
||||
using reference = T &;
|
||||
using const_reference = const T &;
|
||||
using iterator = const T *;
|
||||
using size_type = int64_t;
|
||||
|
||||
private:
|
||||
const T *data_ = nullptr;
|
||||
int64_t size_ = 0;
|
||||
@@ -132,12 +141,11 @@ template<typename T> class Span {
|
||||
}
|
||||
|
||||
/**
|
||||
* Support implicit conversions like the ones below:
|
||||
* Support implicit conversions like the one below:
|
||||
* Span<T *> -> Span<const T *>
|
||||
*/
|
||||
|
||||
template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
|
||||
constexpr Span(Span<U> array) : data_(static_cast<const T *>(array.data())), size_(array.size())
|
||||
constexpr Span(Span<U> span) : data_(static_cast<const T *>(span.data())), size_(span.size())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -418,6 +426,19 @@ template<typename T> class Span {
|
||||
return Span<NewT>(reinterpret_cast<const NewT *>(data_), new_size);
|
||||
}
|
||||
|
||||
friend bool operator==(const Span<T> a, const Span<T> b)
|
||||
{
|
||||
if (a.size() != b.size()) {
|
||||
return false;
|
||||
}
|
||||
return std::equal(a.begin(), a.end(), b.begin());
|
||||
}
|
||||
|
||||
friend bool operator!=(const Span<T> a, const Span<T> b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/**
|
||||
* A debug utility to print the content of the Span. Every element will be printed on a
|
||||
* separate line using the given callback.
|
||||
@@ -447,6 +468,15 @@ template<typename T> class Span {
|
||||
* MutableSpan.
|
||||
*/
|
||||
template<typename T> class MutableSpan {
|
||||
public:
|
||||
using value_type = T;
|
||||
using pointer = T *;
|
||||
using const_pointer = const T *;
|
||||
using reference = T &;
|
||||
using const_reference = const T &;
|
||||
using iterator = T *;
|
||||
using size_type = int64_t;
|
||||
|
||||
private:
|
||||
T *data_;
|
||||
int64_t size_;
|
||||
@@ -467,11 +497,27 @@ template<typename T> class MutableSpan {
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Support implicit conversions like the one below:
|
||||
* MutableSpan<T *> -> MutableSpan<const T *>
|
||||
*/
|
||||
template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
|
||||
constexpr MutableSpan(MutableSpan<U> span)
|
||||
: data_(static_cast<T *>(span.data())), size_(span.size())
|
||||
{
|
||||
}
|
||||
|
||||
constexpr operator Span<T>() const
|
||||
{
|
||||
return Span<T>(data_, size_);
|
||||
}
|
||||
|
||||
template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
|
||||
constexpr operator Span<U>() const
|
||||
{
|
||||
return Span<U>(static_cast<const U *>(data_), size_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in the array.
|
||||
*/
|
||||
@@ -653,12 +699,13 @@ template<typename T> class MutableSpan {
|
||||
|
||||
/**
|
||||
* Returns a new span to the same underlying memory buffer. No conversions are done.
|
||||
* The caller is responsible for making sure that the type cast is valid.
|
||||
*/
|
||||
template<typename NewT> constexpr MutableSpan<NewT> cast() const
|
||||
{
|
||||
BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0);
|
||||
int64_t new_size = size_ * sizeof(T) / sizeof(NewT);
|
||||
return MutableSpan<NewT>(reinterpret_cast<NewT *>(data_), new_size);
|
||||
return MutableSpan<NewT>((NewT *)data_, new_size);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -80,6 +80,14 @@ template<
|
||||
*/
|
||||
typename Allocator = GuardedAllocator>
|
||||
class Stack {
|
||||
public:
|
||||
using value_type = T;
|
||||
using pointer = T *;
|
||||
using const_pointer = const T *;
|
||||
using reference = T &;
|
||||
using const_reference = const T &;
|
||||
using size_type = int64_t;
|
||||
|
||||
private:
|
||||
using Chunk = StackChunk<T>;
|
||||
|
||||
|
@@ -76,6 +76,16 @@ template<
|
||||
*/
|
||||
typename Allocator = GuardedAllocator>
|
||||
class Vector {
|
||||
public:
|
||||
using value_type = T;
|
||||
using pointer = T *;
|
||||
using const_pointer = const T *;
|
||||
using reference = T &;
|
||||
using const_reference = const T &;
|
||||
using iterator = T *;
|
||||
using const_iterator = const T *;
|
||||
using size_type = int64_t;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Use pointers instead of storing the size explicitly. This reduces the number of instructions
|
||||
@@ -879,6 +889,16 @@ class Vector {
|
||||
return IndexRange(this->size());
|
||||
}
|
||||
|
||||
friend bool operator==(const Vector &a, const Vector &b)
|
||||
{
|
||||
return a.as_span() == b.as_span();
|
||||
}
|
||||
|
||||
friend bool operator!=(const Vector &a, const Vector &b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print some debug information about the vector.
|
||||
*/
|
||||
|
@@ -100,6 +100,16 @@ template<
|
||||
*/
|
||||
typename Allocator = GuardedAllocator>
|
||||
class VectorSet {
|
||||
public:
|
||||
using value_type = Key;
|
||||
using pointer = Key *;
|
||||
using const_pointer = const Key *;
|
||||
using reference = Key &;
|
||||
using const_reference = const Key &;
|
||||
using iterator = Key *;
|
||||
using const_iterator = const Key *;
|
||||
using size_type = int64_t;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Slots are either empty, occupied or removed. The number of occupied slots can be computed by
|
||||
|
@@ -58,7 +58,7 @@ typedef intptr_t offset_t;
|
||||
* typically we rely on the 'count' to avoid iterating past the end. */
|
||||
// #define USE_TERMINATE_PARANOID
|
||||
|
||||
/* Currently totalloc isnt used. */
|
||||
/* Currently totalloc isn't used. */
|
||||
// #define USE_TOTALLOC
|
||||
|
||||
/* pad must be power of two */
|
||||
|
@@ -76,7 +76,7 @@
|
||||
*/
|
||||
#define USEDWORD MAKE_ID('u', 's', 'e', 'd')
|
||||
|
||||
/* currently totalloc isnt used */
|
||||
/* Currently totalloc isn't used. */
|
||||
// #define USE_TOTALLOC
|
||||
|
||||
/* optimize pool size */
|
||||
|
@@ -1289,7 +1289,7 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info,
|
||||
|
||||
BLI_assert(i_prev <= data_len);
|
||||
for (size_t i = i_prev; i < data_len;) {
|
||||
/* Assumes exiting chunk isnt a match! */
|
||||
/* Assumes exiting chunk isn't a match! */
|
||||
|
||||
const BChunkRef *cref_found = table_lookup(
|
||||
info, table, table_len, i_table_start, data, data_len, i, table_hash_array);
|
||||
@@ -1317,7 +1317,7 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info,
|
||||
BChunk *chunk_found = cref_found->link;
|
||||
|
||||
if (bchunk_data_compare(chunk_found, data, data_len, i_prev)) {
|
||||
/* may be useful to remove table data, assuming we dont have
|
||||
/* May be useful to remove table data, assuming we don't have
|
||||
* repeating memory where it would be useful to re-use chunks. */
|
||||
i += chunk_found->data_len;
|
||||
bchunk_list_append(info, bs_mem, chunk_list, chunk_found);
|
||||
|
@@ -193,7 +193,7 @@ void _bli_array_binary_or(
|
||||
* \param span_step: Indices to iterate over,
|
||||
* initialize both values to the array length to initialize iteration.
|
||||
* \param r_span_len: The length of the span, useful when \a use_wrap is enabled,
|
||||
* where calculating the length isnt a simple subtraction.
|
||||
* where calculating the length isn't a simple subtraction.
|
||||
*/
|
||||
bool _bli_array_iter_span(const void *arr,
|
||||
unsigned int arr_len,
|
||||
|
@@ -167,7 +167,7 @@ bool BLI_tridiagonal_solve_cyclic(
|
||||
return false;
|
||||
}
|
||||
|
||||
/* prepare the noncyclic system; relies on tridiagonal_solve ignoring values */
|
||||
/* Prepare the non-cyclic system; relies on tridiagonal_solve ignoring values. */
|
||||
memcpy(b2, b, bytes);
|
||||
b2[0] -= a0;
|
||||
b2[count - 1] -= cN;
|
||||
|
@@ -147,4 +147,13 @@ TEST(index_range, constexpr_)
|
||||
BLI_STATIC_ASSERT(range.size() == 1, "");
|
||||
EXPECT_EQ(compiles[0], 1);
|
||||
}
|
||||
|
||||
TEST(index_range, GenericAlgorithms)
|
||||
{
|
||||
IndexRange range{4, 10};
|
||||
EXPECT_TRUE(std::any_of(range.begin(), range.end(), [](int v) { return v == 6; }));
|
||||
EXPECT_FALSE(std::any_of(range.begin(), range.end(), [](int v) { return v == 20; }));
|
||||
EXPECT_EQ(std::count_if(range.begin(), range.end(), [](int v) { return v < 7; }), 3);
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
@@ -565,6 +565,45 @@ TEST(map, AddOrModifyExceptions)
|
||||
EXPECT_ANY_THROW({ map.add_or_modify(3, create_fn, modify_fn); });
|
||||
}
|
||||
|
||||
namespace {
|
||||
enum class TestEnum {
|
||||
A = 0,
|
||||
B = 1,
|
||||
C = 2,
|
||||
D = 1,
|
||||
};
|
||||
}
|
||||
|
||||
TEST(map, EnumKey)
|
||||
{
|
||||
Map<TestEnum, int> map;
|
||||
map.add(TestEnum::A, 4);
|
||||
map.add(TestEnum::B, 6);
|
||||
EXPECT_EQ(map.lookup(TestEnum::A), 4);
|
||||
EXPECT_EQ(map.lookup(TestEnum::B), 6);
|
||||
EXPECT_EQ(map.lookup(TestEnum::D), 6);
|
||||
EXPECT_FALSE(map.contains(TestEnum::C));
|
||||
map.lookup(TestEnum::D) = 10;
|
||||
EXPECT_EQ(map.lookup(TestEnum::B), 10);
|
||||
}
|
||||
|
||||
TEST(map, GenericAlgorithms)
|
||||
{
|
||||
Map<int, int> map;
|
||||
map.add(5, 2);
|
||||
map.add(1, 4);
|
||||
map.add(2, 2);
|
||||
map.add(7, 1);
|
||||
map.add(8, 6);
|
||||
EXPECT_TRUE(std::any_of(map.keys().begin(), map.keys().end(), [](int v) { return v == 1; }));
|
||||
EXPECT_TRUE(std::any_of(map.values().begin(), map.values().end(), [](int v) { return v == 1; }));
|
||||
EXPECT_TRUE(std::any_of(
|
||||
map.items().begin(), map.items().end(), [](auto item) { return item.value == 1; }));
|
||||
EXPECT_EQ(std::count(map.values().begin(), map.values().end(), 2), 2);
|
||||
EXPECT_EQ(std::count(map.values().begin(), map.values().end(), 4), 1);
|
||||
EXPECT_EQ(std::count(map.keys().begin(), map.keys().end(), 7), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot.
|
||||
*/
|
||||
|
@@ -526,6 +526,24 @@ TEST(set, AddExceptions)
|
||||
EXPECT_EQ(set.size(), 0);
|
||||
}
|
||||
|
||||
TEST(set, ForwardIterator)
|
||||
{
|
||||
Set<int> set = {5, 2, 6, 4, 1};
|
||||
Set<int>::iterator iter1 = set.begin();
|
||||
int value1 = *iter1;
|
||||
Set<int>::iterator iter2 = iter1++;
|
||||
EXPECT_EQ(*iter1, value1);
|
||||
EXPECT_EQ(*iter2, *(++iter1));
|
||||
}
|
||||
|
||||
TEST(set, GenericAlgorithms)
|
||||
{
|
||||
Set<int> set = {1, 20, 30, 40};
|
||||
EXPECT_FALSE(std::any_of(set.begin(), set.end(), [](int v) { return v == 5; }));
|
||||
EXPECT_TRUE(std::any_of(set.begin(), set.end(), [](int v) { return v == 30; }));
|
||||
EXPECT_EQ(std::count(set.begin(), set.end(), 20), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot.
|
||||
*/
|
||||
|
@@ -392,4 +392,33 @@ TEST(span, Constexpr)
|
||||
EXPECT_EQ(span.slice(1, 2).size(), 2);
|
||||
}
|
||||
|
||||
TEST(span, ImplicitConversions)
|
||||
{
|
||||
BLI_STATIC_ASSERT((std::is_convertible_v<MutableSpan<int>, Span<int>>), "");
|
||||
BLI_STATIC_ASSERT((std::is_convertible_v<Span<int *>, Span<const int *>>), "");
|
||||
BLI_STATIC_ASSERT((std::is_convertible_v<MutableSpan<int *>, Span<int *>>), "");
|
||||
BLI_STATIC_ASSERT((std::is_convertible_v<MutableSpan<int *>, Span<const int *>>), "");
|
||||
BLI_STATIC_ASSERT((std::is_convertible_v<MutableSpan<int *>, MutableSpan<const int *>>), "");
|
||||
BLI_STATIC_ASSERT((!std::is_convertible_v<MutableSpan<const int *>, MutableSpan<int *>>), "");
|
||||
BLI_STATIC_ASSERT((!std::is_convertible_v<Span<const int *>, Span<int *>>), "");
|
||||
BLI_STATIC_ASSERT((!std::is_convertible_v<Span<int *>, MutableSpan<const int *>>), "");
|
||||
}
|
||||
|
||||
TEST(span, Comparison)
|
||||
{
|
||||
std::array<int, 3> a = {3, 4, 5};
|
||||
std::array<int, 4> b = {3, 4, 5, 6};
|
||||
|
||||
EXPECT_FALSE(Span(a) == Span(b));
|
||||
EXPECT_FALSE(Span(b) == Span(a));
|
||||
EXPECT_TRUE(Span(a) == Span(b).take_front(3));
|
||||
EXPECT_TRUE(Span(a) == Span(a));
|
||||
EXPECT_TRUE(Span(b) == Span(b));
|
||||
|
||||
EXPECT_TRUE(Span(a) != Span(b));
|
||||
EXPECT_TRUE(Span(b) != Span(a));
|
||||
EXPECT_FALSE(Span(a) != Span(b).take_front(3));
|
||||
EXPECT_FALSE(Span(a) != Span(a));
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
/** \file
|
||||
@@ -221,6 +222,26 @@ void BLO_library_link_end(struct Main *mainl,
|
||||
|
||||
int BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh, const uint64_t id_types_mask);
|
||||
|
||||
/**
|
||||
* Struct for temporarily loading datablocks from a blend file.
|
||||
*/
|
||||
typedef struct TempLibraryContext {
|
||||
struct Main *temp_main;
|
||||
struct BlendHandle *blendhandle;
|
||||
struct LibraryLink_Params liblink_params;
|
||||
struct Library *lib;
|
||||
|
||||
/* The ID datablock that was loaded. Is NULL if loading failed. */
|
||||
struct ID *temp_id;
|
||||
} TempLibraryContext;
|
||||
|
||||
TempLibraryContext *BLO_library_temp_load_id(struct Main *real_main,
|
||||
const char *blend_file_path,
|
||||
const short idcode,
|
||||
const char *idname,
|
||||
struct ReportList *reports);
|
||||
void BLO_library_temp_free(TempLibraryContext *temp_lib_ctx);
|
||||
|
||||
/** \} */
|
||||
|
||||
void *BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char *blockname);
|
||||
|
@@ -50,6 +50,7 @@ set(SRC
|
||||
intern/blend_validate.c
|
||||
intern/readblenentry.c
|
||||
intern/readfile.c
|
||||
intern/readfile_tempload.c
|
||||
intern/undofile.c
|
||||
intern/versioning_250.c
|
||||
intern/versioning_260.c
|
||||
|
58
source/blender/blenloader/intern/readfile_tempload.c
Normal file
58
source/blender/blenloader/intern/readfile_tempload.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup blenloader
|
||||
*/
|
||||
#include "BLO_readfile.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "DNA_ID.h"
|
||||
|
||||
TempLibraryContext *BLO_library_temp_load_id(struct Main *real_main,
|
||||
const char *blend_file_path,
|
||||
const short idcode,
|
||||
const char *idname,
|
||||
struct ReportList *reports)
|
||||
{
|
||||
TempLibraryContext *temp_lib_ctx = MEM_callocN(sizeof(*temp_lib_ctx), __func__);
|
||||
|
||||
temp_lib_ctx->blendhandle = BLO_blendhandle_from_file(blend_file_path, reports);
|
||||
|
||||
BLO_library_link_params_init(&temp_lib_ctx->liblink_params, real_main, 0, LIB_TAG_TEMP_MAIN);
|
||||
|
||||
temp_lib_ctx->temp_main = BLO_library_link_begin(
|
||||
&temp_lib_ctx->blendhandle, blend_file_path, &temp_lib_ctx->liblink_params);
|
||||
|
||||
temp_lib_ctx->temp_id = BLO_library_link_named_part(temp_lib_ctx->temp_main,
|
||||
&temp_lib_ctx->blendhandle,
|
||||
idcode,
|
||||
idname,
|
||||
&temp_lib_ctx->liblink_params);
|
||||
|
||||
return temp_lib_ctx;
|
||||
}
|
||||
|
||||
void BLO_library_temp_free(TempLibraryContext *temp_lib_ctx)
|
||||
{
|
||||
BLO_library_link_end(
|
||||
temp_lib_ctx->temp_main, &temp_lib_ctx->blendhandle, &temp_lib_ctx->liblink_params);
|
||||
BLO_blendhandle_close(temp_lib_ctx->blendhandle);
|
||||
MEM_freeN(temp_lib_ctx);
|
||||
}
|
@@ -36,6 +36,7 @@
|
||||
#include "DNA_gpencil_modifier_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_hair_types.h"
|
||||
#include "DNA_light_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
@@ -1892,6 +1893,18 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 293, 13)) {
|
||||
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
|
||||
if (ntree->type == NTREE_GEOMETRY) {
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
if (STREQ(node->idname, "GeometryNodeSubdivideSmooth")) {
|
||||
STRNCPY(node->idname, "GeometryNodeSubdivisionSurface");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
@@ -1903,5 +1916,12 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
*/
|
||||
{
|
||||
/* Keep this block, even when empty. */
|
||||
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "diff_fac")) {
|
||||
LISTBASE_FOREACH (Light *, light, &bmain->lights) {
|
||||
light->diff_fac = 1.0f;
|
||||
light->volume_fac = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -939,7 +939,7 @@ void BM_data_layer_free(BMesh *bm, CustomData *data, int type)
|
||||
data->pool = NULL;
|
||||
|
||||
has_layer = CustomData_free_layer_active(data, type, 0);
|
||||
/* assert because its expensive to realloc - better not do if layer isnt present */
|
||||
/* Assert because its expensive to realloc - better not do if layer isn't present. */
|
||||
BLI_assert(has_layer != false);
|
||||
UNUSED_VARS_NDEBUG(has_layer);
|
||||
|
||||
@@ -961,7 +961,7 @@ void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n)
|
||||
data->pool = NULL;
|
||||
|
||||
has_layer = CustomData_free_layer(data, type, 0, CustomData_get_layer_index_n(data, type, n));
|
||||
/* assert because its expensive to realloc - better not do if layer isnt present */
|
||||
/* Assert because its expensive to realloc - better not do if layer isn't present. */
|
||||
BLI_assert(has_layer != false);
|
||||
UNUSED_VARS_NDEBUG(has_layer);
|
||||
|
||||
|
@@ -158,7 +158,7 @@ int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
|
||||
/**
|
||||
* \brief Iterator as Array
|
||||
*
|
||||
* Allocates a new array, has the advantage that you dont need to know the size ahead of time.
|
||||
* Allocates a new array, has the advantage that you don't need to know the size ahead of time.
|
||||
*
|
||||
* Takes advantage of less common iterator usage to avoid counting twice,
|
||||
* which you might end up doing when #BM_iter_as_array is used.
|
||||
@@ -410,7 +410,7 @@ int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const
|
||||
*/
|
||||
|
||||
/* see bug T36923 for why we need this,
|
||||
* allow adding but not removing, this isnt _totally_ safe since
|
||||
* allow adding but not removing, this isn't _totally_ safe since
|
||||
* you could add/remove within the same loop, but catches common cases
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
|
@@ -58,7 +58,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera
|
||||
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
||||
do {
|
||||
if (BMO_vert_flag_test(bm, l_iter->v, VERT_INPUT) &&
|
||||
/* ensure this vertex isnt part of a contiguous group */
|
||||
/* Ensure this vertex isn't part of a contiguous group. */
|
||||
((BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) ||
|
||||
(BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0))) {
|
||||
if (!l_tag_prev) {
|
||||
|
@@ -586,8 +586,8 @@ static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
|
||||
|
||||
static bool bm_edge_test_rail_cb(BMEdge *e, void *UNUSED(bm_v))
|
||||
{
|
||||
/* normally operators dont check for hidden state
|
||||
* but alternative would be to pass slot of rail edges */
|
||||
/* Normally operators don't check for hidden state
|
||||
* but alternative would be to pass slot of rail edges. */
|
||||
if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
|
||||
return false;
|
||||
}
|
||||
|
@@ -599,7 +599,7 @@ void bmo_collapse_uvs_exec(BMesh *bm, BMOperator *op)
|
||||
const short oflag = EDGE_MARK;
|
||||
int i;
|
||||
|
||||
/* check flags dont change once set */
|
||||
/* Check flags don't change once set. */
|
||||
#ifndef NDEBUG
|
||||
int tot_test;
|
||||
#endif
|
||||
|
@@ -1344,7 +1344,7 @@ void BM_mesh_esubdivide(BMesh *bm,
|
||||
{
|
||||
BMOperator op;
|
||||
|
||||
/* use_sphere isnt exposed here since its only used for new primitives */
|
||||
/* `use_sphere` isn't exposed here since its only used for new primitives. */
|
||||
BMO_op_initf(bm,
|
||||
&op,
|
||||
BMO_FLAG_DEFAULTS,
|
||||
|
@@ -932,7 +932,7 @@ static void bm_edgering_pair_order(BMesh *bm,
|
||||
BLI_assert(bm_edgering_pair_order_is_flipped(bm, el_store_a, el_store_b) == false);
|
||||
}
|
||||
else {
|
||||
/* if we dont share and edge - flip */
|
||||
/* If we don't share and edge - flip. */
|
||||
BMEdge *e = BM_edge_exists(((LinkData *)lb_a->first)->data, ((LinkData *)lb_b->first)->data);
|
||||
if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_RING)) {
|
||||
BM_edgeloop_flip(bm, el_store_b);
|
||||
|
@@ -939,7 +939,7 @@ static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
|
||||
* intended for speed over flexibility.
|
||||
* can only collapse edges connected to (1, 2) tris.
|
||||
*
|
||||
* Important - dont add vert/edge/face data on collapsing!
|
||||
* Important - don't add vert/edge/face data on collapsing!
|
||||
*
|
||||
* \param r_e_clear_other: Let caller know what edges we remove besides \a e_clear
|
||||
* \param customdata_flag: Merge factor, scales from 0 - 1 ('v_clear' -> 'v_other')
|
||||
@@ -1394,7 +1394,7 @@ void BM_mesh_decimate_collapse(BMesh *bm,
|
||||
* \note
|
||||
* - `eheap_table[e_index_mirr]` is only removed from the heap at the last moment
|
||||
* since its possible (in theory) for collapsing `e` to remove `e_mirr`.
|
||||
* - edges sharing a vertex are ignored, so the pivot vertex isnt moved to one side.
|
||||
* - edges sharing a vertex are ignored, so the pivot vertex isn't moved to one side.
|
||||
*/
|
||||
|
||||
BMEdge *e = BLI_heap_pop_min(eheap);
|
||||
|
@@ -401,7 +401,7 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm,
|
||||
earray[i] = e_iter;
|
||||
}
|
||||
/* Remove all edges/verts left behind from dissolving,
|
||||
* NULL'ing the vertex array so we dont re-use. */
|
||||
* NULL'ing the vertex array so we don't re-use. */
|
||||
for (i = bm->totedge - 1; i != -1; i--) {
|
||||
e_iter = earray[i];
|
||||
|
||||
|
@@ -77,12 +77,12 @@ static bool bm_vert_dissolve_fan_test(BMVert *v)
|
||||
|
||||
static bool bm_vert_dissolve_fan(BMesh *bm, BMVert *v)
|
||||
{
|
||||
/* collapse under 2 conditions.
|
||||
/* Collapse under 2 conditions:
|
||||
* - vert connects to 4 manifold edges (and 4 faces).
|
||||
* - vert connects to 1 manifold edge, 2 boundary edges (and 2 faces).
|
||||
*
|
||||
* This covers boundary verts of a quad grid and center verts.
|
||||
* note that surrounding faces dont have to be quads.
|
||||
* note that surrounding faces don't have to be quads.
|
||||
*/
|
||||
|
||||
BMIter iter;
|
||||
|
@@ -102,13 +102,13 @@ extern "C" {
|
||||
* ExecutionGroups that have no viewer-node,
|
||||
* will use a default one.
|
||||
* There are several possible chunk orders
|
||||
* - [@ref OrderOfChunks.COM_TO_CENTER_OUT]:
|
||||
* - [@ref ChunkOrdering.CenterOut]:
|
||||
* Start calculating from a configurable point and order by nearest chunk.
|
||||
* - [@ref OrderOfChunks.COM_TO_RANDOM]:
|
||||
* - [@ref ChunkOrdering.Random]:
|
||||
* Randomize all chunks.
|
||||
* - [@ref OrderOfChunks.COM_TO_TOP_DOWN]:
|
||||
* - [@ref ChunkOrdering.TopDown]:
|
||||
* Start calculation from the bottom to the top of the image.
|
||||
* - [@ref OrderOfChunks.COM_TO_RULE_OF_THIRDS]:
|
||||
* - [@ref ChunkOrdering.RuleOfThirds]:
|
||||
* Experimental order based on 9 hot-spots in the image.
|
||||
*
|
||||
* When the chunk-order is determined, the first few chunks will be checked if they can be scheduled.
|
||||
@@ -122,7 +122,7 @@ extern "C" {
|
||||
*
|
||||
* \see ExecutionGroup.execute
|
||||
* \see ViewerOperation.getChunkOrder
|
||||
* \see OrderOfChunks
|
||||
* \see ChunkOrdering
|
||||
*
|
||||
* \section interest Area of interest
|
||||
* An ExecutionGroup can have dependencies to other ExecutionGroup's.
|
||||
|
@@ -22,41 +22,41 @@
|
||||
* \brief possible data types for sockets
|
||||
* \ingroup Model
|
||||
*/
|
||||
typedef enum DataType {
|
||||
enum class DataType {
|
||||
/** \brief Value data type */
|
||||
COM_DT_VALUE = 1,
|
||||
Value = 0,
|
||||
/** \brief Vector data type */
|
||||
COM_DT_VECTOR = 2,
|
||||
Vector = 1,
|
||||
/** \brief Color data type */
|
||||
COM_DT_COLOR = 4,
|
||||
} DataType;
|
||||
Color = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Possible quality settings
|
||||
* \see CompositorContext.quality
|
||||
* \ingroup Execution
|
||||
*/
|
||||
typedef enum CompositorQuality {
|
||||
enum class CompositorQuality {
|
||||
/** \brief High quality setting */
|
||||
COM_QUALITY_HIGH = 0,
|
||||
High = 0,
|
||||
/** \brief Medium quality setting */
|
||||
COM_QUALITY_MEDIUM = 1,
|
||||
Medium = 1,
|
||||
/** \brief Low quality setting */
|
||||
COM_QUALITY_LOW = 2,
|
||||
} CompositorQuality;
|
||||
Low = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Possible priority settings
|
||||
* \ingroup Execution
|
||||
*/
|
||||
typedef enum CompositorPriority {
|
||||
enum class CompositorPriority {
|
||||
/** \brief High quality setting */
|
||||
COM_PRIORITY_HIGH = 2,
|
||||
High = 2,
|
||||
/** \brief Medium quality setting */
|
||||
COM_PRIORITY_MEDIUM = 1,
|
||||
Medium = 1,
|
||||
/** \brief Low quality setting */
|
||||
COM_PRIORITY_LOW = 0,
|
||||
} CompositorPriority;
|
||||
Low = 0,
|
||||
};
|
||||
|
||||
// configurable items
|
||||
|
||||
@@ -87,18 +87,18 @@ typedef enum CompositorPriority {
|
||||
* \brief The order of chunks to be scheduled
|
||||
* \ingroup Execution
|
||||
*/
|
||||
typedef enum OrderOfChunks {
|
||||
enum class ChunkOrdering {
|
||||
/** \brief order from a distance to centerX/centerY */
|
||||
COM_TO_CENTER_OUT = 0,
|
||||
CenterOut = 0,
|
||||
/** \brief order randomly */
|
||||
COM_TO_RANDOM = 1,
|
||||
Random = 1,
|
||||
/** \brief no ordering */
|
||||
COM_TO_TOP_DOWN = 2,
|
||||
/** \brief experimental ordering with 9 hotspots */
|
||||
COM_TO_RULE_OF_THIRDS = 3,
|
||||
} OrderOfChunks;
|
||||
TopDown = 2,
|
||||
/** \brief experimental ordering with 9 hot-spots. */
|
||||
RuleOfThirds = 3,
|
||||
|
||||
#define COM_ORDER_OF_CHUNKS_DEFAULT COM_TO_CENTER_OUT
|
||||
Default = ChunkOrdering::CenterOut,
|
||||
};
|
||||
|
||||
#define COM_RULE_OF_THIRDS_DIVIDER 100.0f
|
||||
|
||||
|
@@ -17,22 +17,14 @@
|
||||
*/
|
||||
|
||||
#include "COM_ChunkOrder.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
|
||||
ChunkOrder::ChunkOrder()
|
||||
void ChunkOrder::update_distance(ChunkOrderHotspot *hotspots, unsigned int len_hotspots)
|
||||
{
|
||||
distance = 0.0;
|
||||
number = 0;
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
void ChunkOrder::update_distance(ChunkOrderHotspot **hotspots, unsigned int len_hotspots)
|
||||
{
|
||||
double new_distance = FLT_MAX;
|
||||
double new_distance = DBL_MAX;
|
||||
for (int index = 0; index < len_hotspots; index++) {
|
||||
ChunkOrderHotspot *hotspot = hotspots[index];
|
||||
double distance_to_hotspot = hotspot->calc_distance(x, y);
|
||||
double distance_to_hotspot = hotspots[index].calc_distance(x, y);
|
||||
if (distance_to_hotspot < new_distance) {
|
||||
new_distance = distance_to_hotspot;
|
||||
}
|
||||
|
@@ -23,17 +23,17 @@
|
||||
#endif
|
||||
|
||||
#include "COM_ChunkOrderHotspot.h"
|
||||
struct ChunkOrder {
|
||||
unsigned int number;
|
||||
int x;
|
||||
int y;
|
||||
double distance;
|
||||
|
||||
ChunkOrder();
|
||||
/** Helper to determine the order how chunks are prioritized during execution. */
|
||||
struct ChunkOrder {
|
||||
unsigned int index = 0;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
double distance = 0.0;
|
||||
|
||||
friend bool operator<(const ChunkOrder &a, const ChunkOrder &b);
|
||||
|
||||
void update_distance(ChunkOrderHotspot **hotspots, unsigned int len_hotspots);
|
||||
void update_distance(ChunkOrderHotspot *hotspots, unsigned int len_hotspots);
|
||||
|
||||
#ifdef WITH_CXX_GUARDEDALLOC
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("COM:ChunkOrderHotspot")
|
||||
|
@@ -24,7 +24,7 @@ CompositorContext::CompositorContext()
|
||||
{
|
||||
this->m_scene = nullptr;
|
||||
this->m_rd = nullptr;
|
||||
this->m_quality = COM_QUALITY_HIGH;
|
||||
this->m_quality = CompositorQuality::High;
|
||||
this->m_hasActiveOpenCLDevices = false;
|
||||
this->m_fastCalculation = false;
|
||||
this->m_viewSettings = nullptr;
|
||||
|
@@ -428,22 +428,22 @@ NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, const Node
|
||||
const DataType src_data_type = from.getDataType();
|
||||
const DataType dst_data_type = to.getDataType();
|
||||
|
||||
if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_COLOR) {
|
||||
if (src_data_type == DataType::Value && dst_data_type == DataType::Color) {
|
||||
return new ConvertValueToColorOperation();
|
||||
}
|
||||
if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_VECTOR) {
|
||||
if (src_data_type == DataType::Value && dst_data_type == DataType::Vector) {
|
||||
return new ConvertValueToVectorOperation();
|
||||
}
|
||||
if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VALUE) {
|
||||
if (src_data_type == DataType::Color && dst_data_type == DataType::Value) {
|
||||
return new ConvertColorToValueOperation();
|
||||
}
|
||||
if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VECTOR) {
|
||||
if (src_data_type == DataType::Color && dst_data_type == DataType::Vector) {
|
||||
return new ConvertColorToVectorOperation();
|
||||
}
|
||||
if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_VALUE) {
|
||||
if (src_data_type == DataType::Vector && dst_data_type == DataType::Value) {
|
||||
return new ConvertVectorToValueOperation();
|
||||
}
|
||||
if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_COLOR) {
|
||||
if (src_data_type == DataType::Vector && dst_data_type == DataType::Color) {
|
||||
return new ConvertVectorToColorOperation();
|
||||
}
|
||||
|
||||
|
@@ -165,13 +165,13 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system,
|
||||
}
|
||||
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<IN_%p>", socket);
|
||||
switch (socket->getDataType()) {
|
||||
case COM_DT_VALUE:
|
||||
case DataType::Value:
|
||||
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Value");
|
||||
break;
|
||||
case COM_DT_VECTOR:
|
||||
case DataType::Vector:
|
||||
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Vector");
|
||||
break;
|
||||
case COM_DT_COLOR:
|
||||
case DataType::Color:
|
||||
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Color");
|
||||
break;
|
||||
}
|
||||
@@ -203,13 +203,13 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system,
|
||||
}
|
||||
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<OUT_%p>", socket);
|
||||
switch (socket->getDataType()) {
|
||||
case COM_DT_VALUE:
|
||||
case DataType::Value:
|
||||
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Value");
|
||||
break;
|
||||
case COM_DT_VECTOR:
|
||||
case DataType::Vector:
|
||||
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Vector");
|
||||
break;
|
||||
case COM_DT_COLOR:
|
||||
case DataType::Color:
|
||||
len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Color");
|
||||
break;
|
||||
}
|
||||
@@ -390,13 +390,13 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma
|
||||
|
||||
std::string color;
|
||||
switch (from->getDataType()) {
|
||||
case COM_DT_VALUE:
|
||||
case DataType::Value:
|
||||
color = "gray";
|
||||
break;
|
||||
case COM_DT_VECTOR:
|
||||
case DataType::Vector:
|
||||
color = "blue";
|
||||
break;
|
||||
case COM_DT_COLOR:
|
||||
case DataType::Color:
|
||||
color = "orange";
|
||||
break;
|
||||
}
|
||||
|
@@ -34,10 +34,15 @@
|
||||
#include "COM_defines.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_rand.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "PIL_time.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
@@ -65,19 +70,19 @@ CompositorPriority ExecutionGroup::getRenderPriotrity()
|
||||
return this->getOutputOperation()->getRenderPriority();
|
||||
}
|
||||
|
||||
bool ExecutionGroup::canContainOperation(NodeOperation *operation)
|
||||
bool ExecutionGroup::can_contain(NodeOperation &operation)
|
||||
{
|
||||
if (!this->m_initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (operation->isReadBufferOperation()) {
|
||||
if (operation.isReadBufferOperation()) {
|
||||
return true;
|
||||
}
|
||||
if (operation->isWriteBufferOperation()) {
|
||||
if (operation.isWriteBufferOperation()) {
|
||||
return false;
|
||||
}
|
||||
if (operation->isSetOperation()) {
|
||||
if (operation.isSetOperation()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -87,7 +92,7 @@ bool ExecutionGroup::canContainOperation(NodeOperation *operation)
|
||||
}
|
||||
/* complex ops can't be added to other groups (except their own, which they initialize, see
|
||||
* above) */
|
||||
if (operation->isComplex()) {
|
||||
if (operation.isComplex()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -96,7 +101,7 @@ bool ExecutionGroup::canContainOperation(NodeOperation *operation)
|
||||
|
||||
bool ExecutionGroup::addOperation(NodeOperation *operation)
|
||||
{
|
||||
if (!canContainOperation(operation)) {
|
||||
if (!can_contain(*operation)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -178,6 +183,103 @@ void ExecutionGroup::determineNumberOfChunks()
|
||||
}
|
||||
}
|
||||
|
||||
blender::Array<unsigned int> ExecutionGroup::determine_chunk_execution_order() const
|
||||
{
|
||||
int index;
|
||||
blender::Array<unsigned int> chunk_order(m_chunks_len);
|
||||
for (int chunk_index = 0; chunk_index < this->m_chunks_len; chunk_index++) {
|
||||
chunk_order[chunk_index] = chunk_index;
|
||||
}
|
||||
|
||||
NodeOperation *operation = this->getOutputOperation();
|
||||
float centerX = 0.5f;
|
||||
float centerY = 0.5f;
|
||||
ChunkOrdering order_type = ChunkOrdering::Default;
|
||||
|
||||
if (operation->isViewerOperation()) {
|
||||
ViewerOperation *viewer = (ViewerOperation *)operation;
|
||||
centerX = viewer->getCenterX();
|
||||
centerY = viewer->getCenterY();
|
||||
order_type = viewer->getChunkOrder();
|
||||
}
|
||||
|
||||
const int border_width = BLI_rcti_size_x(&this->m_viewerBorder);
|
||||
const int border_height = BLI_rcti_size_y(&this->m_viewerBorder);
|
||||
|
||||
switch (order_type) {
|
||||
case ChunkOrdering::Random: {
|
||||
static blender::RandomNumberGenerator rng;
|
||||
blender::MutableSpan<unsigned int> span = chunk_order.as_mutable_span();
|
||||
/* Shuffle twice to make it more random. */
|
||||
rng.shuffle(span);
|
||||
rng.shuffle(span);
|
||||
break;
|
||||
}
|
||||
case ChunkOrdering::CenterOut: {
|
||||
ChunkOrderHotspot hotspot(border_width * centerX, border_height * centerY, 0.0f);
|
||||
blender::Array<ChunkOrder> chunk_orders(m_chunks_len);
|
||||
for (index = 0; index < this->m_chunks_len; index++) {
|
||||
rcti rect;
|
||||
determineChunkRect(&rect, index);
|
||||
chunk_orders[index].index = index;
|
||||
chunk_orders[index].x = rect.xmin - this->m_viewerBorder.xmin;
|
||||
chunk_orders[index].y = rect.ymin - this->m_viewerBorder.ymin;
|
||||
chunk_orders[index].update_distance(&hotspot, 1);
|
||||
}
|
||||
|
||||
std::sort(&chunk_orders[0], &chunk_orders[this->m_chunks_len - 1]);
|
||||
for (index = 0; index < this->m_chunks_len; index++) {
|
||||
chunk_order[index] = chunk_orders[index].index;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ChunkOrdering::RuleOfThirds: {
|
||||
unsigned int tx = border_width / 6;
|
||||
unsigned int ty = border_height / 6;
|
||||
unsigned int mx = border_width / 2;
|
||||
unsigned int my = border_height / 2;
|
||||
unsigned int bx = mx + 2 * tx;
|
||||
unsigned int by = my + 2 * ty;
|
||||
float addition = this->m_chunks_len / COM_RULE_OF_THIRDS_DIVIDER;
|
||||
|
||||
ChunkOrderHotspot hotspots[9]{
|
||||
ChunkOrderHotspot(mx, my, addition * 0),
|
||||
ChunkOrderHotspot(tx, my, addition * 1),
|
||||
ChunkOrderHotspot(bx, my, addition * 2),
|
||||
ChunkOrderHotspot(bx, by, addition * 3),
|
||||
ChunkOrderHotspot(tx, ty, addition * 4),
|
||||
ChunkOrderHotspot(bx, ty, addition * 5),
|
||||
ChunkOrderHotspot(tx, by, addition * 6),
|
||||
ChunkOrderHotspot(mx, ty, addition * 7),
|
||||
ChunkOrderHotspot(mx, by, addition * 8),
|
||||
};
|
||||
|
||||
blender::Array<ChunkOrder> chunk_orders(m_chunks_len);
|
||||
for (index = 0; index < this->m_chunks_len; index++) {
|
||||
rcti rect;
|
||||
determineChunkRect(&rect, index);
|
||||
chunk_orders[index].index = index;
|
||||
chunk_orders[index].x = rect.xmin - this->m_viewerBorder.xmin;
|
||||
chunk_orders[index].y = rect.ymin - this->m_viewerBorder.ymin;
|
||||
chunk_orders[index].update_distance(hotspots, 9);
|
||||
}
|
||||
|
||||
std::sort(&chunk_orders[0], &chunk_orders[this->m_chunks_len]);
|
||||
|
||||
for (index = 0; index < this->m_chunks_len; index++) {
|
||||
chunk_order[index] = chunk_orders[index].index;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ChunkOrdering::TopDown:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return chunk_order;
|
||||
}
|
||||
|
||||
/**
|
||||
* this method is called for the top execution groups. containing the compositor node or the
|
||||
* preview node or the viewer node)
|
||||
@@ -195,119 +297,15 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
|
||||
if (this->m_chunks_len == 0) {
|
||||
return;
|
||||
} /** \note Early break out. */
|
||||
unsigned int chunkNumber;
|
||||
unsigned int chunk_index;
|
||||
|
||||
this->m_executionStartTime = PIL_check_seconds_timer();
|
||||
|
||||
this->m_chunks_finished = 0;
|
||||
this->m_bTree = bTree;
|
||||
unsigned int index;
|
||||
unsigned int *chunkOrder = (unsigned int *)MEM_mallocN(sizeof(unsigned int) * this->m_chunks_len,
|
||||
__func__);
|
||||
|
||||
for (chunkNumber = 0; chunkNumber < this->m_chunks_len; chunkNumber++) {
|
||||
chunkOrder[chunkNumber] = chunkNumber;
|
||||
}
|
||||
NodeOperation *operation = this->getOutputOperation();
|
||||
float centerX = 0.5;
|
||||
float centerY = 0.5;
|
||||
OrderOfChunks chunkorder = COM_ORDER_OF_CHUNKS_DEFAULT;
|
||||
|
||||
if (operation->isViewerOperation()) {
|
||||
ViewerOperation *viewer = (ViewerOperation *)operation;
|
||||
centerX = viewer->getCenterX();
|
||||
centerY = viewer->getCenterY();
|
||||
chunkorder = viewer->getChunkOrder();
|
||||
}
|
||||
|
||||
const int border_width = BLI_rcti_size_x(&this->m_viewerBorder);
|
||||
const int border_height = BLI_rcti_size_y(&this->m_viewerBorder);
|
||||
|
||||
switch (chunkorder) {
|
||||
case COM_TO_RANDOM:
|
||||
for (index = 0; index < 2 * this->m_chunks_len; index++) {
|
||||
int index1 = rand() % this->m_chunks_len;
|
||||
int index2 = rand() % this->m_chunks_len;
|
||||
int s = chunkOrder[index1];
|
||||
chunkOrder[index1] = chunkOrder[index2];
|
||||
chunkOrder[index2] = s;
|
||||
}
|
||||
break;
|
||||
case COM_TO_CENTER_OUT: {
|
||||
ChunkOrderHotspot *hotspots[1];
|
||||
hotspots[0] = new ChunkOrderHotspot(border_width * centerX, border_height * centerY, 0.0f);
|
||||
rcti rect;
|
||||
ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len,
|
||||
__func__);
|
||||
for (index = 0; index < this->m_chunks_len; index++) {
|
||||
determineChunkRect(&rect, index);
|
||||
chunkOrders[index].number = index;
|
||||
chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin;
|
||||
chunkOrders[index].y = rect.ymin - this->m_viewerBorder.ymin;
|
||||
chunkOrders[index].update_distance(hotspots, 1);
|
||||
}
|
||||
|
||||
std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len - 1]);
|
||||
for (index = 0; index < this->m_chunks_len; index++) {
|
||||
chunkOrder[index] = chunkOrders[index].number;
|
||||
}
|
||||
|
||||
delete hotspots[0];
|
||||
MEM_freeN(chunkOrders);
|
||||
break;
|
||||
}
|
||||
case COM_TO_RULE_OF_THIRDS: {
|
||||
ChunkOrderHotspot *hotspots[9];
|
||||
unsigned int tx = border_width / 6;
|
||||
unsigned int ty = border_height / 6;
|
||||
unsigned int mx = border_width / 2;
|
||||
unsigned int my = border_height / 2;
|
||||
unsigned int bx = mx + 2 * tx;
|
||||
unsigned int by = my + 2 * ty;
|
||||
|
||||
float addition = this->m_chunks_len / COM_RULE_OF_THIRDS_DIVIDER;
|
||||
hotspots[0] = new ChunkOrderHotspot(mx, my, addition * 0);
|
||||
hotspots[1] = new ChunkOrderHotspot(tx, my, addition * 1);
|
||||
hotspots[2] = new ChunkOrderHotspot(bx, my, addition * 2);
|
||||
hotspots[3] = new ChunkOrderHotspot(bx, by, addition * 3);
|
||||
hotspots[4] = new ChunkOrderHotspot(tx, ty, addition * 4);
|
||||
hotspots[5] = new ChunkOrderHotspot(bx, ty, addition * 5);
|
||||
hotspots[6] = new ChunkOrderHotspot(tx, by, addition * 6);
|
||||
hotspots[7] = new ChunkOrderHotspot(mx, ty, addition * 7);
|
||||
hotspots[8] = new ChunkOrderHotspot(mx, by, addition * 8);
|
||||
rcti rect;
|
||||
ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len,
|
||||
__func__);
|
||||
for (index = 0; index < this->m_chunks_len; index++) {
|
||||
determineChunkRect(&rect, index);
|
||||
chunkOrders[index].number = index;
|
||||
chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin;
|
||||
chunkOrders[index].y = rect.ymin - this->m_viewerBorder.ymin;
|
||||
chunkOrders[index].update_distance(hotspots, 9);
|
||||
}
|
||||
|
||||
std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len]);
|
||||
|
||||
for (index = 0; index < this->m_chunks_len; index++) {
|
||||
chunkOrder[index] = chunkOrders[index].number;
|
||||
}
|
||||
|
||||
delete hotspots[0];
|
||||
delete hotspots[1];
|
||||
delete hotspots[2];
|
||||
delete hotspots[3];
|
||||
delete hotspots[4];
|
||||
delete hotspots[5];
|
||||
delete hotspots[6];
|
||||
delete hotspots[7];
|
||||
delete hotspots[8];
|
||||
MEM_freeN(chunkOrders);
|
||||
break;
|
||||
}
|
||||
case COM_TO_TOP_DOWN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
blender::Array<unsigned int> chunk_order = determine_chunk_execution_order();
|
||||
|
||||
DebugInfo::execution_group_started(this);
|
||||
DebugInfo::graphviz(graph);
|
||||
@@ -324,10 +322,10 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
|
||||
|
||||
for (index = startIndex; index < this->m_chunks_len && numberEvaluated < maxNumberEvaluated;
|
||||
index++) {
|
||||
chunkNumber = chunkOrder[index];
|
||||
int yChunk = chunkNumber / this->m_x_chunks_len;
|
||||
int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len);
|
||||
switch (m_chunk_execution_states[chunkNumber]) {
|
||||
chunk_index = chunk_order[index];
|
||||
int yChunk = chunk_index / this->m_x_chunks_len;
|
||||
int xChunk = chunk_index - (yChunk * this->m_x_chunks_len);
|
||||
switch (m_chunk_execution_states[chunk_index]) {
|
||||
case eChunkExecutionState::NOT_SCHEDULED: {
|
||||
scheduleChunkWhenPossible(graph, xChunk, yChunk);
|
||||
finished = false;
|
||||
@@ -361,17 +359,13 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
|
||||
}
|
||||
DebugInfo::execution_group_finished(this);
|
||||
DebugInfo::graphviz(graph);
|
||||
|
||||
MEM_freeN(chunkOrder);
|
||||
}
|
||||
|
||||
MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber)
|
||||
{
|
||||
rcti rect;
|
||||
std::vector<MemoryProxy *> memoryproxies;
|
||||
determineChunkRect(&rect, chunkNumber);
|
||||
|
||||
this->determineDependingMemoryProxies(&memoryproxies);
|
||||
MemoryBuffer **memoryBuffers = (MemoryBuffer **)MEM_callocN(
|
||||
sizeof(MemoryBuffer *) * this->m_max_read_buffer_offset, __func__);
|
||||
rcti output;
|
||||
@@ -379,18 +373,18 @@ MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber)
|
||||
MemoryProxy *memoryProxy = readOperation->getMemoryProxy();
|
||||
this->determineDependingAreaOfInterest(&rect, readOperation, &output);
|
||||
MemoryBuffer *memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer(
|
||||
memoryProxy, &output);
|
||||
*memoryProxy, output);
|
||||
memoryBuffers[readOperation->getOffset()] = memoryBuffer;
|
||||
}
|
||||
return memoryBuffers;
|
||||
}
|
||||
|
||||
MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *memoryProxy,
|
||||
rcti *rect)
|
||||
MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy &memoryProxy,
|
||||
rcti &rect)
|
||||
{
|
||||
MemoryBuffer *imageBuffer = memoryProxy->getBuffer();
|
||||
MemoryBuffer *result = new MemoryBuffer(memoryProxy, rect);
|
||||
result->copyContentFrom(imageBuffer);
|
||||
MemoryBuffer *imageBuffer = memoryProxy.getBuffer();
|
||||
MemoryBuffer *result = new MemoryBuffer(&memoryProxy, rect, MemoryBufferState::Temporary);
|
||||
result->fill_from(*imageBuffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -460,13 +454,14 @@ void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumb
|
||||
determineChunkRect(rect, xChunk, yChunk);
|
||||
}
|
||||
|
||||
MemoryBuffer *ExecutionGroup::allocateOutputBuffer(int /*chunkNumber*/, rcti *rect)
|
||||
MemoryBuffer *ExecutionGroup::allocateOutputBuffer(rcti &rect)
|
||||
{
|
||||
// we assume that this method is only called from complex execution groups.
|
||||
NodeOperation *operation = this->getOutputOperation();
|
||||
if (operation->isWriteBufferOperation()) {
|
||||
WriteBufferOperation *writeOperation = (WriteBufferOperation *)operation;
|
||||
MemoryBuffer *buffer = new MemoryBuffer(writeOperation->getMemoryProxy(), rect);
|
||||
MemoryBuffer *buffer = new MemoryBuffer(
|
||||
writeOperation->getMemoryProxy(), rect, MemoryBufferState::Temporary);
|
||||
return buffer;
|
||||
}
|
||||
return nullptr;
|
||||
@@ -516,54 +511,44 @@ bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk)
|
||||
bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph,
|
||||
const int chunk_x,
|
||||
const int chunk_y)
|
||||
{
|
||||
if (xChunk < 0 || xChunk >= (int)this->m_x_chunks_len) {
|
||||
if (chunk_x < 0 || chunk_x >= (int)this->m_x_chunks_len) {
|
||||
return true;
|
||||
}
|
||||
if (yChunk < 0 || yChunk >= (int)this->m_y_chunks_len) {
|
||||
return true;
|
||||
}
|
||||
int chunkNumber = yChunk * this->m_x_chunks_len + xChunk;
|
||||
// chunk is already executed
|
||||
if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::EXECUTED) {
|
||||
if (chunk_y < 0 || chunk_y >= (int)this->m_y_chunks_len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// chunk is scheduled, but not executed
|
||||
if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) {
|
||||
// Check if chunk is already executed or scheduled and not yet executed.
|
||||
const int chunk_index = chunk_y * this->m_x_chunks_len + chunk_x;
|
||||
if (this->m_chunk_execution_states[chunk_index] == eChunkExecutionState::EXECUTED) {
|
||||
return true;
|
||||
}
|
||||
if (this->m_chunk_execution_states[chunk_index] == eChunkExecutionState::SCHEDULED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// chunk is nor executed nor scheduled.
|
||||
std::vector<MemoryProxy *> memoryProxies;
|
||||
this->determineDependingMemoryProxies(&memoryProxies);
|
||||
|
||||
rcti rect;
|
||||
determineChunkRect(&rect, xChunk, yChunk);
|
||||
unsigned int index;
|
||||
bool canBeExecuted = true;
|
||||
determineChunkRect(&rect, chunk_x, chunk_y);
|
||||
bool can_be_executed = true;
|
||||
rcti area;
|
||||
|
||||
for (index = 0; index < m_read_operations.size(); index++) {
|
||||
ReadBufferOperation *readOperation = m_read_operations[index];
|
||||
for (ReadBufferOperation *read_operation : m_read_operations) {
|
||||
BLI_rcti_init(&area, 0, 0, 0, 0);
|
||||
MemoryProxy *memoryProxy = memoryProxies[index];
|
||||
determineDependingAreaOfInterest(&rect, readOperation, &area);
|
||||
ExecutionGroup *group = memoryProxy->getExecutor();
|
||||
MemoryProxy *memory_proxy = read_operation->getMemoryProxy();
|
||||
determineDependingAreaOfInterest(&rect, read_operation, &area);
|
||||
ExecutionGroup *group = memory_proxy->getExecutor();
|
||||
|
||||
if (group != nullptr) {
|
||||
if (!group->scheduleAreaWhenPossible(graph, &area)) {
|
||||
canBeExecuted = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw "ERROR";
|
||||
if (!group->scheduleAreaWhenPossible(graph, &area)) {
|
||||
can_be_executed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (canBeExecuted) {
|
||||
scheduleChunk(chunkNumber);
|
||||
if (can_be_executed) {
|
||||
scheduleChunk(chunk_index);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -576,13 +561,6 @@ void ExecutionGroup::determineDependingAreaOfInterest(rcti *input,
|
||||
this->getOutputOperation()->determineDependingAreaOfInterest(input, readOperation, output);
|
||||
}
|
||||
|
||||
void ExecutionGroup::determineDependingMemoryProxies(std::vector<MemoryProxy *> *memoryProxies)
|
||||
{
|
||||
for (ReadBufferOperation *readOperation : m_read_operations) {
|
||||
memoryProxies->push_back(readOperation->getMemoryProxy());
|
||||
}
|
||||
}
|
||||
|
||||
bool ExecutionGroup::isOpenCL()
|
||||
{
|
||||
return this->m_openCL;
|
||||
|
@@ -22,6 +22,7 @@
|
||||
# include "MEM_guardedalloc.h"
|
||||
#endif
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
@@ -183,7 +184,7 @@ class ExecutionGroup {
|
||||
* \brief check whether parameter operation can be added to the execution group
|
||||
* \param operation: the operation to be added
|
||||
*/
|
||||
bool canContainOperation(NodeOperation *operation);
|
||||
bool can_contain(NodeOperation &operation);
|
||||
|
||||
/**
|
||||
* \brief calculate the actual chunk size of this execution group.
|
||||
@@ -217,7 +218,7 @@ class ExecutionGroup {
|
||||
* true: package(s) are scheduled
|
||||
* false: scheduling is deferred (depending workpackages are scheduled)
|
||||
*/
|
||||
bool scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk);
|
||||
bool scheduleChunkWhenPossible(ExecutionSystem *graph, const int chunk_x, const int chunk_y);
|
||||
|
||||
/**
|
||||
* \brief try to schedule a specific area.
|
||||
@@ -248,6 +249,11 @@ class ExecutionGroup {
|
||||
ReadBufferOperation *readOperation,
|
||||
rcti *output);
|
||||
|
||||
/**
|
||||
* Return the execution order of the user visible chunks.
|
||||
*/
|
||||
blender::Array<unsigned int> determine_chunk_execution_order() const;
|
||||
|
||||
public:
|
||||
// constructors
|
||||
ExecutionGroup();
|
||||
@@ -333,7 +339,7 @@ class ExecutionGroup {
|
||||
* \brief compose multiple chunks into a single chunk
|
||||
* \return Memorybuffer *consolidated chunk
|
||||
*/
|
||||
MemoryBuffer *constructConsolidatedMemoryBuffer(MemoryProxy *memoryProxy, rcti *rect);
|
||||
MemoryBuffer *constructConsolidatedMemoryBuffer(MemoryProxy &memoryProxy, rcti &rect);
|
||||
|
||||
/**
|
||||
* \brief initExecution is called just before the execution of the whole graph will be done.
|
||||
@@ -363,7 +369,7 @@ class ExecutionGroup {
|
||||
* \param rect: the rect of that chunk
|
||||
* \see determineChunkRect
|
||||
*/
|
||||
MemoryBuffer *allocateOutputBuffer(int chunkNumber, rcti *rect);
|
||||
MemoryBuffer *allocateOutputBuffer(rcti &rect);
|
||||
|
||||
/**
|
||||
* \brief after a chunk is executed the needed resources can be freed or unlocked.
|
||||
@@ -396,14 +402,6 @@ class ExecutionGroup {
|
||||
*/
|
||||
void execute(ExecutionSystem *graph);
|
||||
|
||||
/**
|
||||
* \brief this method determines the MemoryProxy's where this execution group depends on.
|
||||
* \note After this method determineDependingAreaOfInterest can be called to determine
|
||||
* \note the area of the MemoryProxy.creator that has to be executed.
|
||||
* \param memoryProxies: result
|
||||
*/
|
||||
void determineDependingMemoryProxies(std::vector<MemoryProxy *> *memoryProxies);
|
||||
|
||||
/**
|
||||
* \brief Determine the rect (minx, maxx, miny, maxy) of a chunk.
|
||||
* \note Only gives useful results after the determination of the chunksize
|
||||
|
@@ -177,10 +177,10 @@ void ExecutionSystem::execute()
|
||||
|
||||
WorkScheduler::start(this->m_context);
|
||||
|
||||
execute_groups(COM_PRIORITY_HIGH);
|
||||
execute_groups(CompositorPriority::High);
|
||||
if (!this->getContext().isFastCalculation()) {
|
||||
execute_groups(COM_PRIORITY_MEDIUM);
|
||||
execute_groups(COM_PRIORITY_LOW);
|
||||
execute_groups(CompositorPriority::Medium);
|
||||
execute_groups(CompositorPriority::Low);
|
||||
}
|
||||
|
||||
WorkScheduler::finish();
|
||||
|
@@ -64,8 +64,8 @@ class ExecutionGroup;
|
||||
* \see NodeOperation base class for all operations in the system
|
||||
*
|
||||
* \section EM_Step3 Step3: add additional conversions to the operation system
|
||||
* - Data type conversions: the system has 3 data types COM_DT_VALUE, COM_DT_VECTOR,
|
||||
* COM_DT_COLOR. The user can connect a Value socket to a color socket. As values are ordered
|
||||
* - Data type conversions: the system has 3 data types DataType::Value, DataType::Vector,
|
||||
* DataType::Color. The user can connect a Value socket to a color socket. As values are ordered
|
||||
* differently than colors a conversion happens.
|
||||
*
|
||||
* - Image size conversions: the system can automatically convert when resolutions do not match.
|
||||
|
@@ -23,88 +23,53 @@
|
||||
static unsigned int determine_num_channels(DataType datatype)
|
||||
{
|
||||
switch (datatype) {
|
||||
case COM_DT_VALUE:
|
||||
case DataType::Value:
|
||||
return COM_NUM_CHANNELS_VALUE;
|
||||
case COM_DT_VECTOR:
|
||||
case DataType::Vector:
|
||||
return COM_NUM_CHANNELS_VECTOR;
|
||||
case COM_DT_COLOR:
|
||||
case DataType::Color:
|
||||
default:
|
||||
return COM_NUM_CHANNELS_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int MemoryBuffer::determineBufferSize()
|
||||
MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, const rcti &rect, MemoryBufferState state)
|
||||
{
|
||||
return getWidth() * getHeight();
|
||||
}
|
||||
|
||||
int MemoryBuffer::getWidth() const
|
||||
{
|
||||
return this->m_width;
|
||||
}
|
||||
int MemoryBuffer::getHeight() const
|
||||
{
|
||||
return this->m_height;
|
||||
}
|
||||
|
||||
MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, unsigned int chunkNumber, rcti *rect)
|
||||
{
|
||||
BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
|
||||
this->m_width = BLI_rcti_size_x(&this->m_rect);
|
||||
this->m_height = BLI_rcti_size_y(&this->m_rect);
|
||||
m_rect = rect;
|
||||
this->m_memoryProxy = memoryProxy;
|
||||
this->m_chunkNumber = chunkNumber;
|
||||
this->m_num_channels = determine_num_channels(memoryProxy->getDataType());
|
||||
this->m_buffer = (float *)MEM_mallocN_aligned(
|
||||
sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer");
|
||||
this->m_state = COM_MB_ALLOCATED;
|
||||
sizeof(float) * buffer_len() * this->m_num_channels, 16, "COM_MemoryBuffer");
|
||||
this->m_state = state;
|
||||
this->m_datatype = memoryProxy->getDataType();
|
||||
}
|
||||
|
||||
MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, rcti *rect)
|
||||
MemoryBuffer::MemoryBuffer(DataType dataType, const rcti &rect)
|
||||
{
|
||||
BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
|
||||
this->m_width = BLI_rcti_size_x(&this->m_rect);
|
||||
this->m_height = BLI_rcti_size_y(&this->m_rect);
|
||||
this->m_memoryProxy = memoryProxy;
|
||||
this->m_chunkNumber = -1;
|
||||
this->m_num_channels = determine_num_channels(memoryProxy->getDataType());
|
||||
this->m_buffer = (float *)MEM_mallocN_aligned(
|
||||
sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer");
|
||||
this->m_state = COM_MB_TEMPORARILY;
|
||||
this->m_datatype = memoryProxy->getDataType();
|
||||
}
|
||||
MemoryBuffer::MemoryBuffer(DataType dataType, rcti *rect)
|
||||
{
|
||||
BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
|
||||
this->m_width = BLI_rcti_size_x(&this->m_rect);
|
||||
this->m_height = BLI_rcti_size_y(&this->m_rect);
|
||||
this->m_height = this->m_rect.ymax - this->m_rect.ymin;
|
||||
m_rect = rect;
|
||||
this->m_memoryProxy = nullptr;
|
||||
this->m_chunkNumber = -1;
|
||||
this->m_num_channels = determine_num_channels(dataType);
|
||||
this->m_buffer = (float *)MEM_mallocN_aligned(
|
||||
sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer");
|
||||
this->m_state = COM_MB_TEMPORARILY;
|
||||
sizeof(float) * buffer_len() * this->m_num_channels, 16, "COM_MemoryBuffer");
|
||||
this->m_state = MemoryBufferState::Temporary;
|
||||
this->m_datatype = dataType;
|
||||
}
|
||||
MemoryBuffer *MemoryBuffer::duplicate()
|
||||
|
||||
MemoryBuffer::MemoryBuffer(const MemoryBuffer &src)
|
||||
: MemoryBuffer(src.m_memoryProxy, src.m_rect, MemoryBufferState::Temporary)
|
||||
{
|
||||
MemoryBuffer *result = new MemoryBuffer(this->m_memoryProxy, &this->m_rect);
|
||||
memcpy(result->m_buffer,
|
||||
this->m_buffer,
|
||||
this->determineBufferSize() * this->m_num_channels * sizeof(float));
|
||||
return result;
|
||||
}
|
||||
void MemoryBuffer::clear()
|
||||
{
|
||||
memset(this->m_buffer, 0, this->determineBufferSize() * this->m_num_channels * sizeof(float));
|
||||
memcpy(m_buffer, src.m_buffer, buffer_len() * m_num_channels * sizeof(float));
|
||||
}
|
||||
|
||||
float MemoryBuffer::getMaximumValue()
|
||||
void MemoryBuffer::clear()
|
||||
{
|
||||
memset(m_buffer, 0, buffer_len() * m_num_channels * sizeof(float));
|
||||
}
|
||||
|
||||
float MemoryBuffer::get_max_value() const
|
||||
{
|
||||
float result = this->m_buffer[0];
|
||||
const unsigned int size = this->determineBufferSize();
|
||||
const unsigned int size = this->buffer_len();
|
||||
unsigned int i;
|
||||
|
||||
const float *fp_src = this->m_buffer;
|
||||
@@ -119,19 +84,17 @@ float MemoryBuffer::getMaximumValue()
|
||||
return result;
|
||||
}
|
||||
|
||||
float MemoryBuffer::getMaximumValue(rcti *rect)
|
||||
float MemoryBuffer::get_max_value(const rcti &rect) const
|
||||
{
|
||||
rcti rect_clamp;
|
||||
|
||||
/* first clamp the rect by the bounds or we get un-initialized values */
|
||||
BLI_rcti_isect(rect, &this->m_rect, &rect_clamp);
|
||||
BLI_rcti_isect(&rect, &this->m_rect, &rect_clamp);
|
||||
|
||||
if (!BLI_rcti_is_empty(&rect_clamp)) {
|
||||
MemoryBuffer *temp = new MemoryBuffer(this->m_datatype, &rect_clamp);
|
||||
temp->copyContentFrom(this);
|
||||
float result = temp->getMaximumValue();
|
||||
delete temp;
|
||||
return result;
|
||||
MemoryBuffer temp_buffer(this->m_datatype, rect_clamp);
|
||||
temp_buffer.fill_from(*this);
|
||||
return temp_buffer.get_max_value();
|
||||
}
|
||||
|
||||
BLI_assert(0);
|
||||
@@ -146,28 +109,23 @@ MemoryBuffer::~MemoryBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryBuffer::copyContentFrom(MemoryBuffer *otherBuffer)
|
||||
void MemoryBuffer::fill_from(const MemoryBuffer &src)
|
||||
{
|
||||
if (!otherBuffer) {
|
||||
BLI_assert(0);
|
||||
return;
|
||||
}
|
||||
unsigned int otherY;
|
||||
unsigned int minX = MAX2(this->m_rect.xmin, otherBuffer->m_rect.xmin);
|
||||
unsigned int maxX = MIN2(this->m_rect.xmax, otherBuffer->m_rect.xmax);
|
||||
unsigned int minY = MAX2(this->m_rect.ymin, otherBuffer->m_rect.ymin);
|
||||
unsigned int maxY = MIN2(this->m_rect.ymax, otherBuffer->m_rect.ymax);
|
||||
unsigned int minX = MAX2(this->m_rect.xmin, src.m_rect.xmin);
|
||||
unsigned int maxX = MIN2(this->m_rect.xmax, src.m_rect.xmax);
|
||||
unsigned int minY = MAX2(this->m_rect.ymin, src.m_rect.ymin);
|
||||
unsigned int maxY = MIN2(this->m_rect.ymax, src.m_rect.ymax);
|
||||
int offset;
|
||||
int otherOffset;
|
||||
|
||||
for (otherY = minY; otherY < maxY; otherY++) {
|
||||
otherOffset = ((otherY - otherBuffer->m_rect.ymin) * otherBuffer->m_width + minX -
|
||||
otherBuffer->m_rect.xmin) *
|
||||
otherOffset = ((otherY - src.m_rect.ymin) * src.getWidth() + minX - src.m_rect.xmin) *
|
||||
this->m_num_channels;
|
||||
offset = ((otherY - this->m_rect.ymin) * this->m_width + minX - this->m_rect.xmin) *
|
||||
offset = ((otherY - this->m_rect.ymin) * getWidth() + minX - this->m_rect.xmin) *
|
||||
this->m_num_channels;
|
||||
memcpy(&this->m_buffer[offset],
|
||||
&otherBuffer->m_buffer[otherOffset],
|
||||
&src.m_buffer[otherOffset],
|
||||
(maxX - minX) * this->m_num_channels * sizeof(float));
|
||||
}
|
||||
}
|
||||
@@ -176,7 +134,7 @@ void MemoryBuffer::writePixel(int x, int y, const float color[4])
|
||||
{
|
||||
if (x >= this->m_rect.xmin && x < this->m_rect.xmax && y >= this->m_rect.ymin &&
|
||||
y < this->m_rect.ymax) {
|
||||
const int offset = (this->m_width * (y - this->m_rect.ymin) + x - this->m_rect.xmin) *
|
||||
const int offset = (getWidth() * (y - this->m_rect.ymin) + x - this->m_rect.xmin) *
|
||||
this->m_num_channels;
|
||||
memcpy(&this->m_buffer[offset], color, sizeof(float) * this->m_num_channels);
|
||||
}
|
||||
@@ -186,7 +144,7 @@ void MemoryBuffer::addPixel(int x, int y, const float color[4])
|
||||
{
|
||||
if (x >= this->m_rect.xmin && x < this->m_rect.xmax && y >= this->m_rect.ymin &&
|
||||
y < this->m_rect.ymax) {
|
||||
const int offset = (this->m_width * (y - this->m_rect.ymin) + x - this->m_rect.xmin) *
|
||||
const int offset = (getWidth() * (y - this->m_rect.ymin) + x - this->m_rect.xmin) *
|
||||
this->m_num_channels;
|
||||
float *dst = &this->m_buffer[offset];
|
||||
const float *src = color;
|
||||
@@ -204,7 +162,7 @@ static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4]
|
||||
|
||||
void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivatives[2][2])
|
||||
{
|
||||
BLI_assert(this->m_datatype == COM_DT_COLOR);
|
||||
BLI_assert(this->m_datatype == DataType::Color);
|
||||
float inv_width = 1.0f / (float)this->getWidth(), inv_height = 1.0f / (float)this->getHeight();
|
||||
/* TODO(sergey): Render pipeline uses normalized coordinates and derivatives,
|
||||
* but compositor uses pixel space. For now let's just divide the values and
|
||||
|
@@ -31,21 +31,19 @@ class MemoryBuffer;
|
||||
* \brief state of a memory buffer
|
||||
* \ingroup Memory
|
||||
*/
|
||||
typedef enum MemoryBufferState {
|
||||
enum class MemoryBufferState {
|
||||
/** \brief memory has been allocated on creator device and CPU machine,
|
||||
* but kernel has not been executed */
|
||||
COM_MB_ALLOCATED = 1,
|
||||
/** \brief memory is available for use, content has been created */
|
||||
COM_MB_AVAILABLE = 2,
|
||||
Default = 0,
|
||||
/** \brief chunk is consolidated from other chunks. special state.*/
|
||||
COM_MB_TEMPORARILY = 6,
|
||||
} MemoryBufferState;
|
||||
Temporary = 6,
|
||||
};
|
||||
|
||||
typedef enum MemoryBufferExtend {
|
||||
COM_MB_CLIP,
|
||||
COM_MB_EXTEND,
|
||||
COM_MB_REPEAT,
|
||||
} MemoryBufferExtend;
|
||||
enum class MemoryBufferExtend {
|
||||
Clip,
|
||||
Extend,
|
||||
Repeat,
|
||||
};
|
||||
|
||||
class MemoryProxy;
|
||||
|
||||
@@ -60,7 +58,7 @@ class MemoryBuffer {
|
||||
MemoryProxy *m_memoryProxy;
|
||||
|
||||
/**
|
||||
* \brief the type of buffer COM_DT_VALUE, COM_DT_VECTOR, COM_DT_COLOR
|
||||
* \brief the type of buffer DataType::Value, DataType::Vector, DataType::Color
|
||||
*/
|
||||
DataType m_datatype;
|
||||
|
||||
@@ -69,12 +67,6 @@ class MemoryBuffer {
|
||||
*/
|
||||
rcti m_rect;
|
||||
|
||||
/**
|
||||
* brief refers to the chunk-number within the execution-group where related to the MemoryProxy
|
||||
* \see memoryProxy
|
||||
*/
|
||||
unsigned int m_chunkNumber;
|
||||
|
||||
/**
|
||||
* \brief state of the buffer
|
||||
*/
|
||||
@@ -89,41 +81,30 @@ class MemoryBuffer {
|
||||
* \brief the number of channels of a single value in the buffer.
|
||||
* For value buffers this is 1, vector 3 and color 4
|
||||
*/
|
||||
unsigned int m_num_channels;
|
||||
|
||||
int m_width;
|
||||
int m_height;
|
||||
uint8_t m_num_channels;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \brief construct new MemoryBuffer for a chunk
|
||||
* \brief construct new temporarily MemoryBuffer for an area
|
||||
*/
|
||||
MemoryBuffer(MemoryProxy *memoryProxy, unsigned int chunkNumber, rcti *rect);
|
||||
MemoryBuffer(MemoryProxy *memoryProxy, const rcti &rect, MemoryBufferState state);
|
||||
|
||||
/**
|
||||
* \brief construct new temporarily MemoryBuffer for an area
|
||||
*/
|
||||
MemoryBuffer(MemoryProxy *memoryProxy, rcti *rect);
|
||||
MemoryBuffer(DataType datatype, const rcti &rect);
|
||||
|
||||
/**
|
||||
* \brief construct new temporarily MemoryBuffer for an area
|
||||
* Copy constructor
|
||||
*/
|
||||
MemoryBuffer(DataType datatype, rcti *rect);
|
||||
MemoryBuffer(const MemoryBuffer &src);
|
||||
|
||||
/**
|
||||
* \brief destructor
|
||||
*/
|
||||
~MemoryBuffer();
|
||||
|
||||
/**
|
||||
* \brief read the ChunkNumber of this MemoryBuffer
|
||||
*/
|
||||
unsigned int getChunkNumber()
|
||||
{
|
||||
return this->m_chunkNumber;
|
||||
}
|
||||
|
||||
unsigned int get_num_channels()
|
||||
uint8_t get_num_channels()
|
||||
{
|
||||
return this->m_num_channels;
|
||||
}
|
||||
@@ -137,25 +118,17 @@ class MemoryBuffer {
|
||||
return this->m_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief after execution the state will be set to available by calling this method
|
||||
*/
|
||||
void setCreatedState()
|
||||
{
|
||||
this->m_state = COM_MB_AVAILABLE;
|
||||
}
|
||||
|
||||
inline void wrap_pixel(int &x, int &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y)
|
||||
{
|
||||
int w = this->m_width;
|
||||
int h = this->m_height;
|
||||
const int w = getWidth();
|
||||
const int h = getHeight();
|
||||
x = x - m_rect.xmin;
|
||||
y = y - m_rect.ymin;
|
||||
|
||||
switch (extend_x) {
|
||||
case COM_MB_CLIP:
|
||||
case MemoryBufferExtend::Clip:
|
||||
break;
|
||||
case COM_MB_EXTEND:
|
||||
case MemoryBufferExtend::Extend:
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
}
|
||||
@@ -163,15 +136,15 @@ class MemoryBuffer {
|
||||
x = w;
|
||||
}
|
||||
break;
|
||||
case COM_MB_REPEAT:
|
||||
case MemoryBufferExtend::Repeat:
|
||||
x = (x >= 0.0f ? (x % w) : (x % w) + w);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (extend_y) {
|
||||
case COM_MB_CLIP:
|
||||
case MemoryBufferExtend::Clip:
|
||||
break;
|
||||
case COM_MB_EXTEND:
|
||||
case MemoryBufferExtend::Extend:
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
}
|
||||
@@ -179,7 +152,7 @@ class MemoryBuffer {
|
||||
y = h;
|
||||
}
|
||||
break;
|
||||
case COM_MB_REPEAT:
|
||||
case MemoryBufferExtend::Repeat:
|
||||
y = (y >= 0.0f ? (y % h) : (y % h) + h);
|
||||
break;
|
||||
}
|
||||
@@ -190,15 +163,15 @@ class MemoryBuffer {
|
||||
MemoryBufferExtend extend_x,
|
||||
MemoryBufferExtend extend_y)
|
||||
{
|
||||
float w = (float)this->m_width;
|
||||
float h = (float)this->m_height;
|
||||
const float w = (float)getWidth();
|
||||
const float h = (float)getHeight();
|
||||
x = x - m_rect.xmin;
|
||||
y = y - m_rect.ymin;
|
||||
|
||||
switch (extend_x) {
|
||||
case COM_MB_CLIP:
|
||||
case MemoryBufferExtend::Clip:
|
||||
break;
|
||||
case COM_MB_EXTEND:
|
||||
case MemoryBufferExtend::Extend:
|
||||
if (x < 0) {
|
||||
x = 0.0f;
|
||||
}
|
||||
@@ -206,15 +179,15 @@ class MemoryBuffer {
|
||||
x = w;
|
||||
}
|
||||
break;
|
||||
case COM_MB_REPEAT:
|
||||
case MemoryBufferExtend::Repeat:
|
||||
x = fmodf(x, w);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (extend_y) {
|
||||
case COM_MB_CLIP:
|
||||
case MemoryBufferExtend::Clip:
|
||||
break;
|
||||
case COM_MB_EXTEND:
|
||||
case MemoryBufferExtend::Extend:
|
||||
if (y < 0) {
|
||||
y = 0.0f;
|
||||
}
|
||||
@@ -222,7 +195,7 @@ class MemoryBuffer {
|
||||
y = h;
|
||||
}
|
||||
break;
|
||||
case COM_MB_REPEAT:
|
||||
case MemoryBufferExtend::Repeat:
|
||||
y = fmodf(y, h);
|
||||
break;
|
||||
}
|
||||
@@ -231,11 +204,11 @@ class MemoryBuffer {
|
||||
inline void read(float *result,
|
||||
int x,
|
||||
int y,
|
||||
MemoryBufferExtend extend_x = COM_MB_CLIP,
|
||||
MemoryBufferExtend extend_y = COM_MB_CLIP)
|
||||
MemoryBufferExtend extend_x = MemoryBufferExtend::Clip,
|
||||
MemoryBufferExtend extend_y = MemoryBufferExtend::Clip)
|
||||
{
|
||||
bool clip_x = (extend_x == COM_MB_CLIP && (x < m_rect.xmin || x >= m_rect.xmax));
|
||||
bool clip_y = (extend_y == COM_MB_CLIP && (y < m_rect.ymin || y >= m_rect.ymax));
|
||||
bool clip_x = (extend_x == MemoryBufferExtend::Clip && (x < m_rect.xmin || x >= m_rect.xmax));
|
||||
bool clip_y = (extend_y == MemoryBufferExtend::Clip && (y < m_rect.ymin || y >= m_rect.ymax));
|
||||
if (clip_x || clip_y) {
|
||||
/* clip result outside rect is zero */
|
||||
memset(result, 0, this->m_num_channels * sizeof(float));
|
||||
@@ -244,7 +217,7 @@ class MemoryBuffer {
|
||||
int u = x;
|
||||
int v = y;
|
||||
this->wrap_pixel(u, v, extend_x, extend_y);
|
||||
const int offset = (this->m_width * y + x) * this->m_num_channels;
|
||||
const int offset = (getWidth() * y + x) * this->m_num_channels;
|
||||
float *buffer = &this->m_buffer[offset];
|
||||
memcpy(result, buffer, sizeof(float) * this->m_num_channels);
|
||||
}
|
||||
@@ -253,19 +226,19 @@ class MemoryBuffer {
|
||||
inline void readNoCheck(float *result,
|
||||
int x,
|
||||
int y,
|
||||
MemoryBufferExtend extend_x = COM_MB_CLIP,
|
||||
MemoryBufferExtend extend_y = COM_MB_CLIP)
|
||||
MemoryBufferExtend extend_x = MemoryBufferExtend::Clip,
|
||||
MemoryBufferExtend extend_y = MemoryBufferExtend::Clip)
|
||||
{
|
||||
int u = x;
|
||||
int v = y;
|
||||
|
||||
this->wrap_pixel(u, v, extend_x, extend_y);
|
||||
const int offset = (this->m_width * v + u) * this->m_num_channels;
|
||||
const int offset = (getWidth() * v + u) * this->m_num_channels;
|
||||
|
||||
BLI_assert(offset >= 0);
|
||||
BLI_assert(offset < this->determineBufferSize() * this->m_num_channels);
|
||||
BLI_assert(!(extend_x == COM_MB_CLIP && (u < m_rect.xmin || u >= m_rect.xmax)) &&
|
||||
!(extend_y == COM_MB_CLIP && (v < m_rect.ymin || v >= m_rect.ymax)));
|
||||
BLI_assert(offset < this->buffer_len() * this->m_num_channels);
|
||||
BLI_assert(!(extend_x == MemoryBufferExtend::Clip && (u < m_rect.xmin || u >= m_rect.xmax)) &&
|
||||
!(extend_y == MemoryBufferExtend::Clip && (v < m_rect.ymin || v >= m_rect.ymax)));
|
||||
float *buffer = &this->m_buffer[offset];
|
||||
memcpy(result, buffer, sizeof(float) * this->m_num_channels);
|
||||
}
|
||||
@@ -275,26 +248,26 @@ class MemoryBuffer {
|
||||
inline void readBilinear(float *result,
|
||||
float x,
|
||||
float y,
|
||||
MemoryBufferExtend extend_x = COM_MB_CLIP,
|
||||
MemoryBufferExtend extend_y = COM_MB_CLIP)
|
||||
MemoryBufferExtend extend_x = MemoryBufferExtend::Clip,
|
||||
MemoryBufferExtend extend_y = MemoryBufferExtend::Clip)
|
||||
{
|
||||
float u = x;
|
||||
float v = y;
|
||||
this->wrap_pixel(u, v, extend_x, extend_y);
|
||||
if ((extend_x != COM_MB_REPEAT && (u < 0.0f || u >= this->m_width)) ||
|
||||
(extend_y != COM_MB_REPEAT && (v < 0.0f || v >= this->m_height))) {
|
||||
if ((extend_x != MemoryBufferExtend::Repeat && (u < 0.0f || u >= getWidth())) ||
|
||||
(extend_y != MemoryBufferExtend::Repeat && (v < 0.0f || v >= getHeight()))) {
|
||||
copy_vn_fl(result, this->m_num_channels, 0.0f);
|
||||
return;
|
||||
}
|
||||
BLI_bilinear_interpolation_wrap_fl(this->m_buffer,
|
||||
result,
|
||||
this->m_width,
|
||||
this->m_height,
|
||||
getWidth(),
|
||||
getHeight(),
|
||||
this->m_num_channels,
|
||||
u,
|
||||
v,
|
||||
extend_x == COM_MB_REPEAT,
|
||||
extend_y == COM_MB_REPEAT);
|
||||
extend_x == MemoryBufferExtend::Repeat,
|
||||
extend_y == MemoryBufferExtend::Repeat);
|
||||
}
|
||||
|
||||
void readEWA(float *result, const float uv[2], const float derivatives[2][2]);
|
||||
@@ -304,7 +277,7 @@ class MemoryBuffer {
|
||||
*/
|
||||
inline bool isTemporarily() const
|
||||
{
|
||||
return this->m_state == COM_MB_TEMPORARILY;
|
||||
return this->m_state == MemoryBufferState::Temporary;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,38 +287,45 @@ class MemoryBuffer {
|
||||
* \note take care when running this on a new buffer since it wont fill in
|
||||
* uninitialized values in areas where the buffers don't overlap.
|
||||
*/
|
||||
void copyContentFrom(MemoryBuffer *otherBuffer);
|
||||
void fill_from(const MemoryBuffer &src);
|
||||
|
||||
/**
|
||||
* \brief get the rect of this MemoryBuffer
|
||||
*/
|
||||
rcti *getRect()
|
||||
const rcti &get_rect() const
|
||||
{
|
||||
return &this->m_rect;
|
||||
return this->m_rect;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief get the width of this MemoryBuffer
|
||||
*/
|
||||
int getWidth() const;
|
||||
const int getWidth() const
|
||||
{
|
||||
return BLI_rcti_size_x(&m_rect);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief get the height of this MemoryBuffer
|
||||
*/
|
||||
int getHeight() const;
|
||||
const int getHeight() const
|
||||
{
|
||||
return BLI_rcti_size_y(&m_rect);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief clear the buffer. Make all pixels black transparent.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
MemoryBuffer *duplicate();
|
||||
|
||||
float getMaximumValue();
|
||||
float getMaximumValue(rcti *rect);
|
||||
float get_max_value() const;
|
||||
float get_max_value(const rcti &rect) const;
|
||||
|
||||
private:
|
||||
unsigned int determineBufferSize();
|
||||
const int buffer_len() const
|
||||
{
|
||||
return getWidth() * getHeight();
|
||||
}
|
||||
|
||||
#ifdef WITH_CXX_GUARDEDALLOC
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("COM:MemoryBuffer")
|
||||
|
@@ -33,7 +33,7 @@ void MemoryProxy::allocate(unsigned int width, unsigned int height)
|
||||
result.ymin = 0;
|
||||
result.ymax = height;
|
||||
|
||||
this->m_buffer = new MemoryBuffer(this, 1, &result);
|
||||
this->m_buffer = new MemoryBuffer(this, result, MemoryBufferState::Default);
|
||||
}
|
||||
|
||||
void MemoryProxy::free()
|
||||
|
@@ -45,12 +45,12 @@ Node::Node(bNode *editorNode, bool create_sockets)
|
||||
if (create_sockets) {
|
||||
bNodeSocket *input = (bNodeSocket *)editorNode->inputs.first;
|
||||
while (input != nullptr) {
|
||||
DataType dt = COM_DT_VALUE;
|
||||
DataType dt = DataType::Value;
|
||||
if (input->type == SOCK_RGBA) {
|
||||
dt = COM_DT_COLOR;
|
||||
dt = DataType::Color;
|
||||
}
|
||||
if (input->type == SOCK_VECTOR) {
|
||||
dt = COM_DT_VECTOR;
|
||||
dt = DataType::Vector;
|
||||
}
|
||||
|
||||
this->addInputSocket(dt, input);
|
||||
@@ -58,12 +58,12 @@ Node::Node(bNode *editorNode, bool create_sockets)
|
||||
}
|
||||
bNodeSocket *output = (bNodeSocket *)editorNode->outputs.first;
|
||||
while (output != nullptr) {
|
||||
DataType dt = COM_DT_VALUE;
|
||||
DataType dt = DataType::Value;
|
||||
if (output->type == SOCK_RGBA) {
|
||||
dt = COM_DT_COLOR;
|
||||
dt = DataType::Color;
|
||||
}
|
||||
if (output->type == SOCK_VECTOR) {
|
||||
dt = COM_DT_VECTOR;
|
||||
dt = DataType::Vector;
|
||||
}
|
||||
|
||||
this->addOutputSocket(dt, output);
|
||||
@@ -158,21 +158,21 @@ void NodeInput::setLink(NodeOutput *link)
|
||||
m_link = link;
|
||||
}
|
||||
|
||||
float NodeInput::getEditorValueFloat()
|
||||
float NodeInput::getEditorValueFloat() const
|
||||
{
|
||||
PointerRNA ptr;
|
||||
RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr);
|
||||
return RNA_float_get(&ptr, "default_value");
|
||||
}
|
||||
|
||||
void NodeInput::getEditorValueColor(float *value)
|
||||
void NodeInput::getEditorValueColor(float *value) const
|
||||
{
|
||||
PointerRNA ptr;
|
||||
RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr);
|
||||
return RNA_float_get_array(&ptr, "default_value", value);
|
||||
}
|
||||
|
||||
void NodeInput::getEditorValueVector(float *value)
|
||||
void NodeInput::getEditorValueVector(float *value) const
|
||||
{
|
||||
PointerRNA ptr;
|
||||
RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr);
|
||||
|
@@ -281,9 +281,9 @@ class NodeInput {
|
||||
return m_link;
|
||||
}
|
||||
|
||||
float getEditorValueFloat();
|
||||
void getEditorValueColor(float *value);
|
||||
void getEditorValueVector(float *value);
|
||||
float getEditorValueFloat() const;
|
||||
void getEditorValueColor(float *value) const;
|
||||
void getEditorValueVector(float *value) const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -188,7 +188,8 @@ void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink
|
||||
if (!(b_nodelink->flag & NODE_LINK_VALID)) {
|
||||
return;
|
||||
}
|
||||
if ((b_nodelink->fromsock->flag & SOCK_UNAVAIL) || (b_nodelink->tosock->flag & SOCK_UNAVAIL)) {
|
||||
if ((b_nodelink->fromsock->flag & SOCK_UNAVAIL) || (b_nodelink->tosock->flag & SOCK_UNAVAIL) ||
|
||||
(b_nodelink->flag & NODE_LINK_MUTED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user