Merge branch 'master' into asset-browser-grid-view
This commit is contained in:
commit
11d0c91ba5
|
@ -157,8 +157,9 @@ option(WITH_BLENDER "Build blender (disable to build only the blender player)" O
|
|||
mark_as_advanced(WITH_BLENDER)
|
||||
|
||||
if(APPLE)
|
||||
# Currently this causes a build error linking, disable.
|
||||
set(WITH_BLENDER_THUMBNAILER OFF)
|
||||
# In future, can be used with `quicklookthumbnailing/qlthumbnailreply` to create file
|
||||
# thumbnails for say Finder. Turn it off for now.
|
||||
option(WITH_BLENDER_THUMBNAILER "Build \"blender-thumbnailer\" thumbnail extraction utility" OFF)
|
||||
elseif(WIN32)
|
||||
option(WITH_BLENDER_THUMBNAILER "Build \"BlendThumb.dll\" helper for Windows explorer integration" ON)
|
||||
else()
|
||||
|
|
|
@ -417,7 +417,8 @@ MODULE_GROUPING = {
|
|||
BLENDER_REVISION = str(bpy.app.build_hash, 'utf_8')
|
||||
|
||||
# '2.83.0 Beta' or '2.83.0' or '2.83.1'
|
||||
BLENDER_VERSION_DOTS = bpy.app.version_string
|
||||
BLENDER_VERSION_STRING = bpy.app.version_string
|
||||
BLENDER_VERSION_DOTS = "%d.%d" % (bpy.app.version[0], bpy.app.version[1])
|
||||
|
||||
if BLENDER_REVISION != "Unknown":
|
||||
# SHA1 Git hash
|
||||
|
@ -1724,11 +1725,11 @@ def write_sphinx_conf_py(basepath):
|
|||
fw("import sys, os\n\n")
|
||||
fw("extensions = ['sphinx.ext.intersphinx']\n\n")
|
||||
fw("intersphinx_mapping = {'blender_manual': ('https://docs.blender.org/manual/en/dev/', None)}\n\n")
|
||||
fw("project = 'Blender %s Python API'\n" % BLENDER_VERSION_DOTS)
|
||||
fw("project = 'Blender %s Python API'\n" % BLENDER_VERSION_STRING)
|
||||
fw("master_doc = 'index'\n")
|
||||
fw("copyright = u'Blender Foundation'\n")
|
||||
fw("version = '%s'\n" % BLENDER_VERSION_HASH)
|
||||
fw("release = '%s'\n" % BLENDER_VERSION_HASH)
|
||||
fw("version = '%s'\n" % BLENDER_VERSION_DOTS)
|
||||
fw("release = '%s'\n" % BLENDER_VERSION_DOTS)
|
||||
|
||||
# Quiet file not in table-of-contents warnings.
|
||||
fw("exclude_patterns = [\n")
|
||||
|
@ -1749,6 +1750,7 @@ except ModuleNotFoundError:
|
|||
|
||||
fw("if html_theme == 'sphinx_rtd_theme':\n")
|
||||
fw(" html_theme_options = {\n")
|
||||
fw(" 'display_version': False,\n")
|
||||
# fw(" 'analytics_id': '',\n")
|
||||
# fw(" 'collapse_navigation': True,\n")
|
||||
fw(" 'sticky_navigation': False,\n")
|
||||
|
@ -1765,10 +1767,15 @@ except ModuleNotFoundError:
|
|||
fw("html_show_search_summary = True\n")
|
||||
fw("html_split_index = True\n")
|
||||
fw("html_static_path = ['static']\n")
|
||||
fw("templates_path = ['templates']\n")
|
||||
fw("html_context = {'commit': '%s'}\n" % BLENDER_VERSION_HASH)
|
||||
fw("html_extra_path = ['static/favicon.ico', 'static/blender_logo.svg']\n")
|
||||
fw("html_favicon = 'static/favicon.ico'\n")
|
||||
fw("html_logo = 'static/blender_logo.svg'\n")
|
||||
fw("html_last_updated_fmt = '%m/%d/%Y'\n\n")
|
||||
fw("if html_theme == 'sphinx_rtd_theme':\n")
|
||||
fw(" html_css_files = ['css/version_switch.css']\n")
|
||||
fw(" html_js_files = ['js/version_switch.js']\n")
|
||||
|
||||
# needed for latex, pdf gen
|
||||
fw("latex_elements = {\n")
|
||||
|
@ -2125,6 +2132,9 @@ def copy_theme_assets(basepath):
|
|||
shutil.copytree(os.path.join(SCRIPT_DIR, "static"),
|
||||
os.path.join(basepath, "static"),
|
||||
copy_function=shutil.copy)
|
||||
shutil.copytree(os.path.join(SCRIPT_DIR, "templates"),
|
||||
os.path.join(basepath, "templates"),
|
||||
copy_function=shutil.copy)
|
||||
|
||||
|
||||
def rna2sphinx(basepath):
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/* Override RTD theme */
|
||||
.rst-versions {
|
||||
border-top: 0px;
|
||||
overflow: visible;
|
||||
}
|
||||
.version-btn.vdeact {
|
||||
cursor: default;
|
||||
color: dimgray;
|
||||
}
|
||||
|
||||
.version-btn.vdeact::after {
|
||||
content: "";
|
||||
}
|
||||
#versionwrap {
|
||||
display: flex;
|
||||
padding-top: 2px;
|
||||
font-size: 90%;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.version-btn {
|
||||
display: inline-block;
|
||||
background-color: #272525;
|
||||
width: 140px;
|
||||
text-align: center;
|
||||
padding: 3px 10px;
|
||||
margin: 0px 5px 4px;
|
||||
vertical-align: middle;
|
||||
color: #27AE60;
|
||||
border: solid 1px #444444;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
z-index: 400;
|
||||
transition: border-color 0.4s;
|
||||
}
|
||||
.version-btn::after {
|
||||
content:"\f0d8";
|
||||
display: inline;
|
||||
font: normal normal normal 16px/1 FontAwesome;
|
||||
color: #8d8c8c;
|
||||
vertical-align: top;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
.version-btn-open::after {
|
||||
color: gray;
|
||||
}
|
||||
.version-btn:hover, .version-btn:focus {
|
||||
border-color: #525252;
|
||||
}
|
||||
.version-btn-open {
|
||||
color: gray;
|
||||
border: solid 1px gray;
|
||||
}
|
||||
.version-btn.wait {
|
||||
cursor: wait;
|
||||
}
|
||||
.version-btn.disabled {
|
||||
cursor: not-allowed;
|
||||
color: dimgray;
|
||||
}
|
||||
.version-dialog {
|
||||
display: none;
|
||||
position: absolute;
|
||||
bottom: 28px;
|
||||
width: 140px;
|
||||
margin: 0 5px;
|
||||
padding-bottom: 4px;
|
||||
background-color: #0003;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 6px #000C;
|
||||
z-index: 999;
|
||||
max-height: calc(100vh - 30px);
|
||||
overflow-y: auto;
|
||||
cursor: default;
|
||||
}
|
||||
.version-title {
|
||||
padding: 5px;
|
||||
color: black;
|
||||
text-align: center;
|
||||
font-size: 102%;
|
||||
background-color: #27ae60;
|
||||
border-bottom: solid 1.5px #444;
|
||||
}
|
||||
.version-list {
|
||||
margin-bottom: 4px;
|
||||
text-align: center;
|
||||
background-color: #000C;
|
||||
border: solid 1px gray;
|
||||
border-radius: 0px 0px 3px 3px;
|
||||
}
|
||||
.version-list a, .version-list span, .version-list li {
|
||||
position: relative;
|
||||
display: block;
|
||||
font-size: 98%;
|
||||
line-height: 1.15;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 4px 0px;
|
||||
color: #404040;
|
||||
}
|
||||
.version-list li {
|
||||
background-color: #ede9e9;
|
||||
color: #404040;
|
||||
padding: 1px;
|
||||
}
|
||||
.version-list li:hover, .version-list li a:focus {
|
||||
background-color: #b9cfda;
|
||||
}
|
||||
.version-list li.selected, .version-list li.selected:hover {
|
||||
background-color: #8d8c8c;
|
||||
}
|
||||
.version-list li.selected span {
|
||||
cursor: default;
|
||||
outline-color: red;
|
||||
}
|
||||
.version-arrow {
|
||||
position: absolute;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
left: 50%;
|
||||
bottom: 4px;
|
||||
margin-left: -4px;
|
||||
transform: rotate(225deg);
|
||||
background: #ede9e9;
|
||||
border: 1px solid gray;
|
||||
border-width: 1px 0 0 1px;
|
||||
}
|
|
@ -0,0 +1,323 @@
|
|||
(function() { // switch: v1.2
|
||||
"use strict";
|
||||
|
||||
var versionsFileUrl = "https://docs.blender.org/PROD/versions.json"
|
||||
|
||||
var all_versions;
|
||||
|
||||
var Popover = function() {
|
||||
function Popover(id)
|
||||
{
|
||||
this.isOpen = false;
|
||||
this.type = (id === "version-popover");
|
||||
this.$btn = $('#' + id);
|
||||
this.$dialog = this.$btn.next();
|
||||
this.$list = this.$dialog.children("ul");
|
||||
this.sel = null;
|
||||
this.beforeInit();
|
||||
}
|
||||
|
||||
Popover.prototype = {
|
||||
beforeInit : function() {
|
||||
var that = this;
|
||||
this.$btn.on("click", function(e) {
|
||||
that.init();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
this.$btn.on("keydown", function(e) {
|
||||
if (that.btnKeyFilter(e)) {
|
||||
that.init();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
},
|
||||
init : function() {
|
||||
this.$btn.off("click");
|
||||
this.$btn.off("keydown");
|
||||
|
||||
if (all_versions === undefined) {
|
||||
this.$btn.addClass("wait");
|
||||
this.loadVL(this);
|
||||
}
|
||||
else {
|
||||
this.afterLoad();
|
||||
}
|
||||
},
|
||||
loadVL : function(that) {
|
||||
$.getJSON(versionsFileUrl, function(data) {
|
||||
all_versions = data;
|
||||
that.afterLoad();
|
||||
return true;
|
||||
}).fail(function() {
|
||||
console.log("Version Switch Error: versions.json could not be loaded.");
|
||||
that.$btn.addClass("disabled");
|
||||
return false;
|
||||
});
|
||||
},
|
||||
afterLoad : function() {
|
||||
var release = DOCUMENTATION_OPTIONS.VERSION;
|
||||
const m = release.match(/\d\.\d+/g);
|
||||
if (m) {
|
||||
release = m[0];
|
||||
}
|
||||
|
||||
this.warnOld(release, all_versions);
|
||||
|
||||
var version = this.getNamed(release);
|
||||
var list = this.buildList(version);
|
||||
|
||||
this.$list.children(":first-child").remove();
|
||||
this.$list.append(list);
|
||||
var that = this;
|
||||
this.$list.on("keydown", function(e) {
|
||||
that.keyMove(e);
|
||||
});
|
||||
|
||||
this.$btn.removeClass("wait");
|
||||
this.btnOpenHandler();
|
||||
this.$btn.on("mousedown", function(e) {
|
||||
that.btnOpenHandler();
|
||||
e.preventDefault()
|
||||
});
|
||||
this.$btn.on("keydown", function(e) {
|
||||
if (that.btnKeyFilter(e)) {
|
||||
that.btnOpenHandler();
|
||||
}
|
||||
});
|
||||
},
|
||||
warnOld : function(release, all_versions) {
|
||||
// Note this is effectively disabled now, two issues must fixed:
|
||||
// * versions.js does not contain a current entry, because that leads to
|
||||
// duplicate version numbers in the menu. These need to be deduplicated.
|
||||
// * It only shows the warning after opening the menu to switch version
|
||||
// when versions.js is loaded. This is too late to be useful.
|
||||
var current = all_versions.current
|
||||
if (!current)
|
||||
{
|
||||
// console.log("Version Switch Error: no 'current' in version.json.");
|
||||
return;
|
||||
}
|
||||
const m = current.match(/\d\.\d+/g);
|
||||
if (m) {
|
||||
current = parseFloat(m[0]);
|
||||
}
|
||||
if (release < current) {
|
||||
var currentURL = window.location.pathname.replace(release, current);
|
||||
var warning = $('<div class="admonition warning"> ' +
|
||||
'<p class="first admonition-title">Note</p> ' +
|
||||
'<p class="last"> ' +
|
||||
'You are not using the most up to date version of the documentation. ' +
|
||||
'<a href="#"></a> is the newest version.' +
|
||||
'</p>' +
|
||||
'</div>');
|
||||
|
||||
warning.find('a').attr('href', currentURL).text(current);
|
||||
|
||||
var body = $("div.body");
|
||||
if (!body.length) {
|
||||
body = $("div.document");
|
||||
}
|
||||
body.prepend(warning);
|
||||
}
|
||||
},
|
||||
buildList : function(v) {
|
||||
var url = new URL(window.location.href);
|
||||
let pathSplit = [ "", "api", v ];
|
||||
if (url.pathname.startsWith("/api/")) {
|
||||
pathSplit.push(url.pathname.split('/').slice(3).join('/'));
|
||||
}
|
||||
else {
|
||||
pathSplit.push(url.pathname.substring(1));
|
||||
}
|
||||
if (this.type) {
|
||||
var dyn = all_versions;
|
||||
var cur = v;
|
||||
}
|
||||
var buf = [];
|
||||
var that = this;
|
||||
$.each(dyn, function(ix, title) {
|
||||
buf.push("<li");
|
||||
if (ix === cur) {
|
||||
buf.push(
|
||||
' class="selected" tabindex="-1" role="presentation"><span tabindex="-1" role="menuitem" aria-current="page">' +
|
||||
title + '</spanp></li>');
|
||||
}
|
||||
else {
|
||||
pathSplit[2 + that.type] = ix;
|
||||
var href = new URL(url);
|
||||
href.pathname = pathSplit.join('/');
|
||||
buf.push(' tabindex="-1" role="presentation"><a href ="' + href + '" tabindex="-1">' +
|
||||
title + '</a></li>');
|
||||
}
|
||||
});
|
||||
return buf.join('');
|
||||
},
|
||||
getNamed : function(v) {
|
||||
$.each(all_versions, function(ix, title) {
|
||||
if (ix === "master" || ix === "latest") {
|
||||
var m = title.match(/\d\.\d[\w\d\.]*/)[0];
|
||||
if (parseFloat(m) == v) {
|
||||
v = ix;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
return v;
|
||||
},
|
||||
dialogToggle : function(speed) {
|
||||
var wasClose = !this.isOpen;
|
||||
var that = this;
|
||||
if (!this.isOpen) {
|
||||
this.$btn.addClass("version-btn-open");
|
||||
this.$btn.attr("aria-pressed", true);
|
||||
this.$dialog.attr("aria-hidden", false);
|
||||
this.$dialog.fadeIn(speed, function() {
|
||||
that.$btn.parent().on("focusout", function(e) {
|
||||
that.focusoutHandler();
|
||||
e.stopImmediatePropagation();
|
||||
})
|
||||
that.$btn.parent().on("mouseleave", function(e) {
|
||||
that.mouseoutHandler();
|
||||
e.stopImmediatePropagation();
|
||||
});
|
||||
});
|
||||
this.isOpen = true;
|
||||
}
|
||||
else {
|
||||
this.$btn.removeClass("version-btn-open");
|
||||
this.$btn.attr("aria-pressed", false);
|
||||
this.$dialog.attr("aria-hidden", true);
|
||||
this.$btn.parent().off("focusout");
|
||||
this.$btn.parent().off("mouseleave");
|
||||
this.$dialog.fadeOut(speed, function() {
|
||||
if (this.$sel) {
|
||||
this.$sel.attr("tabindex", -1);
|
||||
}
|
||||
that.$btn.attr("tabindex", 0);
|
||||
if (document.activeElement !== null && document.activeElement !== document &&
|
||||
document.activeElement !== document.body) {
|
||||
that.$btn.focus();
|
||||
}
|
||||
});
|
||||
this.isOpen = false;
|
||||
}
|
||||
|
||||
if (wasClose) {
|
||||
if (this.$sel) {
|
||||
this.$sel.attr("tabindex", -1);
|
||||
}
|
||||
if (document.activeElement !== null && document.activeElement !== document &&
|
||||
document.activeElement !== document.body) {
|
||||
var $nw = this.listEnter();
|
||||
$nw.attr("tabindex", 0);
|
||||
$nw.focus();
|
||||
this.$sel = $nw;
|
||||
}
|
||||
}
|
||||
},
|
||||
btnOpenHandler : function() {
|
||||
this.dialogToggle(300);
|
||||
},
|
||||
focusoutHandler : function() {
|
||||
var list = this.$list;
|
||||
var that = this;
|
||||
setTimeout(function() {
|
||||
if (list.find(":focus").length === 0) {
|
||||
that.dialogToggle(200);
|
||||
}
|
||||
}, 200);
|
||||
},
|
||||
mouseoutHandler : function() {
|
||||
this.dialogToggle(200);
|
||||
},
|
||||
btnKeyFilter : function(e) {
|
||||
if (e.ctrlKey || e.shiftKey) {
|
||||
return false;
|
||||
}
|
||||
if (e.key === " " || e.key === "Enter" || (e.key === "ArrowDown" && e.altKey) ||
|
||||
e.key === "ArrowDown" || e.key === "ArrowUp") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
keyMove : function(e) {
|
||||
if (e.ctrlKey || e.shiftKey) {
|
||||
return true;
|
||||
}
|
||||
var p = true;
|
||||
var $nw = $(e.target);
|
||||
switch (e.key) {
|
||||
case "ArrowUp":
|
||||
$nw = this.listPrev($nw);
|
||||
break;
|
||||
case "ArrowDown":
|
||||
$nw = this.listNext($nw);
|
||||
break;
|
||||
case "Home":
|
||||
$nw = this.listFirst();
|
||||
break;
|
||||
case "End":
|
||||
$nw = this.listLast();
|
||||
break;
|
||||
case "Escape":
|
||||
$nw = this.listExit();
|
||||
break;
|
||||
case "ArrowLeft":
|
||||
$nw = this.listExit();
|
||||
break;
|
||||
case "ArrowRight":
|
||||
$nw = this.listExit();
|
||||
break;
|
||||
default:
|
||||
p = false;
|
||||
}
|
||||
if (p) {
|
||||
$nw.attr("tabindex", 0);
|
||||
$nw.focus();
|
||||
if (this.$sel) {
|
||||
this.$sel.attr("tabindex", -1);
|
||||
}
|
||||
this.$sel = $nw;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
},
|
||||
listPrev : function($nw) {
|
||||
if ($nw.parent().prev().length !== 0) {
|
||||
return $nw.parent().prev().children(":first-child");
|
||||
}
|
||||
else {
|
||||
return this.listLast();
|
||||
}
|
||||
},
|
||||
listNext : function($nw) {
|
||||
if ($nw.parent().next().length !== 0) {
|
||||
return $nw.parent().next().children(":first-child");
|
||||
}
|
||||
else {
|
||||
return this.listFirst();
|
||||
}
|
||||
},
|
||||
listFirst : function() {
|
||||
return this.$list.children(":first-child").children(":first-child");
|
||||
},
|
||||
listLast : function() {
|
||||
return this.$list.children(":last-child").children(":first-child");
|
||||
},
|
||||
listExit : function() {
|
||||
this.mouseoutHandler();
|
||||
return this.$btn;
|
||||
},
|
||||
listEnter : function() {
|
||||
return this.$list.children(":first-child").children(":first-child");
|
||||
}
|
||||
};
|
||||
return Popover
|
||||
}();
|
||||
|
||||
$(document).ready(function() {
|
||||
var lng_popover = new Popover("version-popover");
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,17 @@
|
|||
<div class="rst-versions" data-toggle="rst-versions" role="note" aria-label="document versions">
|
||||
<ul id="versionwrap" role="presentation">
|
||||
<li role="presentation">
|
||||
<span id="version-popover" class="version-btn" tabindex="0" role="button" aria-label="versions selector" aria-haspopup="true" aria-controls="version-vsnlist" aria-disabled="true">
|
||||
{{ release }}
|
||||
</span>
|
||||
<div class="version-dialog" aria-hidden="true">
|
||||
<div class="version-arrow" aria-hidden="true"></div>
|
||||
<div class="version-title">Versions</div>
|
||||
<ul id="version-vsnlist" class="version-list" role="menu" aria-labelledby="version-popover" aria-hidden="true">
|
||||
<li role="presentation">Loading...</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -669,7 +669,7 @@ class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Pa
|
|||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return not use_optix(context) or has_multi_device(context)
|
||||
return not use_optix(context) or use_multi_device(context)
|
||||
|
||||
def draw(self, context):
|
||||
import _cycles
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "blender/sync.h"
|
||||
#include "blender/util.h"
|
||||
|
||||
|
@ -625,14 +627,35 @@ void BlenderSync::sync_particle_hair(
|
|||
}
|
||||
|
||||
#ifdef WITH_HAIR_NODES
|
||||
static float4 hair_point_as_float4(BL::HairPoint b_point)
|
||||
|
||||
static std::optional<BL::FloatAttribute> find_curves_radius_attribute(BL::Hair b_hair)
|
||||
{
|
||||
float4 mP = float3_to_float4(get_float3(b_point.co()));
|
||||
mP.w = b_point.radius();
|
||||
for (BL::Attribute &b_attribute : b_hair.attributes) {
|
||||
if (b_attribute.name() != "radius") {
|
||||
continue;
|
||||
}
|
||||
if (b_attribute.domain() != BL::Attribute::domain_POINT) {
|
||||
continue;
|
||||
}
|
||||
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
|
||||
continue;
|
||||
}
|
||||
return BL::FloatAttribute{b_attribute};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static float4 hair_point_as_float4(BL::Hair b_hair,
|
||||
std::optional<BL::FloatAttribute> b_attr_radius,
|
||||
const int index)
|
||||
{
|
||||
float4 mP = float3_to_float4(get_float3(b_hair.position_data[index].vector()));
|
||||
mP.w = b_attr_radius ? b_attr_radius->data[index].value() : 0.0f;
|
||||
return mP;
|
||||
}
|
||||
|
||||
static float4 interpolate_hair_points(BL::Hair b_hair,
|
||||
std::optional<BL::FloatAttribute> b_attr_radius,
|
||||
const int first_point_index,
|
||||
const int num_points,
|
||||
const float step)
|
||||
|
@ -641,8 +664,8 @@ static float4 interpolate_hair_points(BL::Hair b_hair,
|
|||
const int point_a = clamp((int)curve_t, 0, num_points - 1);
|
||||
const int point_b = min(point_a + 1, num_points - 1);
|
||||
const float t = curve_t - (float)point_a;
|
||||
return lerp(hair_point_as_float4(b_hair.points[first_point_index + point_a]),
|
||||
hair_point_as_float4(b_hair.points[first_point_index + point_b]),
|
||||
return lerp(hair_point_as_float4(b_hair, b_attr_radius, first_point_index + point_a),
|
||||
hair_point_as_float4(b_hair, b_attr_radius, first_point_index + point_b),
|
||||
t);
|
||||
}
|
||||
|
||||
|
@ -671,12 +694,14 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
|
|||
|
||||
hair->reserve_curves(num_curves, num_keys);
|
||||
|
||||
std::optional<BL::FloatAttribute> b_attr_radius = find_curves_radius_attribute(b_hair);
|
||||
|
||||
/* Export curves and points. */
|
||||
vector<float> points_length;
|
||||
|
||||
for (BL::HairCurve &b_curve : b_hair.curves) {
|
||||
const int first_point_index = b_curve.first_point_index();
|
||||
const int num_points = b_curve.num_points();
|
||||
for (int i = 0; i < num_curves; i++) {
|
||||
const int first_point_index = b_hair.curve_offset_data[i].value();
|
||||
const int num_points = b_hair.curve_offset_data[i + 1].value() - first_point_index;
|
||||
|
||||
float3 prev_co = zero_float3();
|
||||
float length = 0.0f;
|
||||
|
@ -687,10 +712,9 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
|
|||
|
||||
/* Position and radius. */
|
||||
for (int i = 0; i < num_points; i++) {
|
||||
BL::HairPoint b_point = b_hair.points[first_point_index + i];
|
||||
|
||||
const float3 co = get_float3(b_point.co());
|
||||
const float radius = b_point.radius();
|
||||
const float3 co = get_float3(b_hair.position_data[first_point_index + i].vector());
|
||||
const float radius = b_attr_radius ? b_attr_radius->data[first_point_index + i].value() :
|
||||
0.0f;
|
||||
hair->add_curve_key(co, radius);
|
||||
|
||||
if (attr_intercept) {
|
||||
|
@ -715,7 +739,7 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
|
|||
|
||||
/* Random number per curve. */
|
||||
if (attr_random != NULL) {
|
||||
attr_random->add(hash_uint2_to_float(b_curve.index(), 0));
|
||||
attr_random->add(hash_uint2_to_float(i, 0));
|
||||
}
|
||||
|
||||
/* Curve. */
|
||||
|
@ -737,14 +761,17 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
|
|||
|
||||
/* Export motion keys. */
|
||||
const int num_keys = hair->get_curve_keys().size();
|
||||
const int num_curves = b_hair.curves.length();
|
||||
float4 *mP = attr_mP->data_float4() + motion_step * num_keys;
|
||||
bool have_motion = false;
|
||||
int num_motion_keys = 0;
|
||||
int curve_index = 0;
|
||||
|
||||
for (BL::HairCurve &b_curve : b_hair.curves) {
|
||||
const int first_point_index = b_curve.first_point_index();
|
||||
const int num_points = b_curve.num_points();
|
||||
std::optional<BL::FloatAttribute> b_attr_radius = find_curves_radius_attribute(b_hair);
|
||||
|
||||
for (int i = 0; i < num_curves; i++) {
|
||||
const int first_point_index = b_hair.curve_offset_data[i].value();
|
||||
const int num_points = b_hair.curve_offset_data[i + 1].value() - first_point_index;
|
||||
|
||||
Hair::Curve curve = hair->get_curve(curve_index);
|
||||
curve_index++;
|
||||
|
@ -755,7 +782,7 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
|
|||
int point_index = first_point_index + i;
|
||||
|
||||
if (point_index < num_keys) {
|
||||
mP[num_motion_keys] = hair_point_as_float4(b_hair.points[point_index]);
|
||||
mP[num_motion_keys] = hair_point_as_float4(b_hair, b_attr_radius, point_index);
|
||||
num_motion_keys++;
|
||||
|
||||
if (!have_motion) {
|
||||
|
@ -774,7 +801,8 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
|
|||
const float step_size = curve.num_keys > 1 ? 1.0f / (curve.num_keys - 1) : 0.0f;
|
||||
for (int i = 0; i < curve.num_keys; i++) {
|
||||
const float step = i * step_size;
|
||||
mP[num_motion_keys] = interpolate_hair_points(b_hair, first_point_index, num_points, step);
|
||||
mP[num_motion_keys] = interpolate_hair_points(
|
||||
b_hair, b_attr_radius, first_point_index, num_points, step);
|
||||
num_motion_keys++;
|
||||
}
|
||||
have_motion = true;
|
||||
|
|
|
@ -113,22 +113,30 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
|
|||
ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
|
||||
|
||||
if (type == LIGHT_SPOT) {
|
||||
ls->Ng = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
|
||||
float radius = klight->spot.radius;
|
||||
const float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
|
||||
const float radius = klight->spot.radius;
|
||||
const float3 dir = make_float3(
|
||||
klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
|
||||
/* disk oriented normal */
|
||||
const float3 lightN = normalize(P - center);
|
||||
ls->P = center;
|
||||
|
||||
if (radius > 0.0f)
|
||||
/* sphere light */
|
||||
ls->P += disk_light_sample(ls->Ng, randu, randv) * radius;
|
||||
/* disk light */
|
||||
ls->P += disk_light_sample(lightN, randu, randv) * radius;
|
||||
|
||||
const float invarea = klight->spot.invarea;
|
||||
ls->pdf = invarea;
|
||||
|
||||
ls->D = normalize_len(ls->P - P, &ls->t);
|
||||
/* we set the light normal to the outgoing direction to support texturing */
|
||||
ls->Ng = -ls->D;
|
||||
|
||||
float invarea = klight->spot.invarea;
|
||||
ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
|
||||
ls->pdf = invarea;
|
||||
|
||||
/* spot light attenuation */
|
||||
ls->eval_fac *= spot_light_attenuation(
|
||||
ls->Ng, klight->spot.spot_angle, klight->spot.spot_smooth, -ls->D);
|
||||
dir, klight->spot.spot_angle, klight->spot.spot_smooth, -ls->D);
|
||||
if (!in_volume_segment && ls->eval_fac == 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
@ -137,32 +145,33 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
|
|||
ls->u = uv.x;
|
||||
ls->v = uv.y;
|
||||
|
||||
ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
|
||||
ls->pdf *= lamp_light_pdf(kg, lightN, -ls->D, ls->t);
|
||||
}
|
||||
else if (type == LIGHT_POINT) {
|
||||
float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
|
||||
float radius = klight->spot.radius;
|
||||
/* disk oriented normal */
|
||||
const float3 lightN = normalize(P - center);
|
||||
ls->P = center;
|
||||
float pdf = 1.0;
|
||||
|
||||
if (radius > 0.0f) {
|
||||
ls->Ng = normalize(P - center);
|
||||
ls->P += disk_light_sample(ls->Ng, randu, randv) * radius;
|
||||
pdf = klight->spot.invarea;
|
||||
ls->D = normalize_len(ls->P - P, &ls->t);
|
||||
}
|
||||
else {
|
||||
ls->Ng = normalize(P - center);
|
||||
ls->P += disk_light_sample(lightN, randu, randv) * radius;
|
||||
}
|
||||
ls->pdf = klight->spot.invarea;
|
||||
|
||||
ls->D = normalize_len(ls->P - P, &ls->t);
|
||||
ls->pdf = pdf;
|
||||
/* we set the light normal to the outgoing direction to support texturing */
|
||||
ls->Ng = -ls->D;
|
||||
|
||||
ls->eval_fac = M_1_PI_F * 0.25f * klight->spot.invarea;
|
||||
if (!in_volume_segment && ls->eval_fac == 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float2 uv = map_to_sphere(ls->Ng);
|
||||
ls->u = uv.x;
|
||||
ls->v = uv.y;
|
||||
ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
|
||||
ls->pdf *= lamp_light_pdf(kg, lightN, -ls->D, ls->t);
|
||||
}
|
||||
else {
|
||||
/* area light */
|
||||
|
@ -263,14 +272,16 @@ ccl_device bool lights_intersect(KernelGlobals kg,
|
|||
|
||||
if (type == LIGHT_SPOT) {
|
||||
/* Spot/Disk light. */
|
||||
const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
|
||||
const float3 ray_P = ray->P - ray->D * mis_ray_t;
|
||||
|
||||
const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
|
||||
const float3 lightN = make_float3(
|
||||
klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
|
||||
const float radius = klight->spot.radius;
|
||||
if (radius == 0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* disk oriented normal */
|
||||
const float3 lightN = normalize(ray_P - lightP);
|
||||
/* One sided. */
|
||||
if (dot(ray->D, lightN) >= 0.0f) {
|
||||
continue;
|
||||
|
@ -292,9 +303,10 @@ ccl_device bool lights_intersect(KernelGlobals kg,
|
|||
continue;
|
||||
}
|
||||
|
||||
/* disk oriented normal */
|
||||
const float3 lightN = normalize(ray_P - lightP);
|
||||
float3 P;
|
||||
const float3 lsN = normalize(ray_P - lightP);
|
||||
if (!ray_disk_intersect(ray->P, ray->D, ray->t, lightP, lsN, radius, &P, &t)) {
|
||||
if (!ray_disk_intersect(ray->P, ray->D, ray->t, lightP, lightN, radius, &P, &t)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -427,7 +439,12 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg,
|
|||
ls->D = ray_D;
|
||||
|
||||
if (type == LIGHT_SPOT) {
|
||||
ls->Ng = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
|
||||
const float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
|
||||
const float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
|
||||
/* the normal of the oriented disk */
|
||||
const float3 lightN = normalize(ray_P - center);
|
||||
/* we set the light normal to the outgoing direction to support texturing*/
|
||||
ls->Ng = -ls->D;
|
||||
|
||||
float invarea = klight->spot.invarea;
|
||||
ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
|
||||
|
@ -435,7 +452,7 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg,
|
|||
|
||||
/* spot light attenuation */
|
||||
ls->eval_fac *= spot_light_attenuation(
|
||||
ls->Ng, klight->spot.spot_angle, klight->spot.spot_smooth, -ls->D);
|
||||
dir, klight->spot.spot_angle, klight->spot.spot_smooth, -ls->D);
|
||||
|
||||
if (ls->eval_fac == 0.0f) {
|
||||
return false;
|
||||
|
@ -447,23 +464,32 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg,
|
|||
|
||||
/* compute pdf */
|
||||
if (ls->t != FLT_MAX)
|
||||
ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
|
||||
ls->pdf *= lamp_light_pdf(kg, lightN, -ls->D, ls->t);
|
||||
else
|
||||
ls->pdf = 0.f;
|
||||
}
|
||||
else if (type == LIGHT_POINT) {
|
||||
float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
|
||||
const float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
|
||||
const float3 lighN = normalize(ray_P - center);
|
||||
|
||||
/* we set the light normal to the outgoing direction to support texturing*/
|
||||
ls->Ng = -ls->D;
|
||||
|
||||
ls->Ng = normalize(ray_P - center);
|
||||
float invarea = klight->spot.invarea;
|
||||
ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
|
||||
ls->pdf = invarea;
|
||||
|
||||
if (ls->eval_fac == 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float2 uv = map_to_sphere(ls->Ng);
|
||||
ls->u = uv.x;
|
||||
ls->v = uv.y;
|
||||
|
||||
/* compute pdf */
|
||||
if (ls->t != FLT_MAX)
|
||||
ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
|
||||
ls->pdf *= lamp_light_pdf(kg, lighN, -ls->D, ls->t);
|
||||
else
|
||||
ls->pdf = 0.f;
|
||||
}
|
||||
|
@ -921,4 +947,4 @@ ccl_device_inline bool light_distribution_sample_new_position(KernelGlobals kg,
|
|||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
CCL_NAMESPACE_END
|
|
@ -268,6 +268,12 @@ void MEM_use_guarded_allocator(void);
|
|||
* Allocate new memory for and constructs an object of type #T.
|
||||
* #MEM_delete should be used to delete the object. Just calling #MEM_freeN is not enough when #T
|
||||
* is not a trivial type.
|
||||
*
|
||||
* Note that when no arguments are passed, C++ will do recursive member-wise value initialization.
|
||||
* That is because C++ differentiates between creating an object with `T` (default initialization)
|
||||
* and `T()` (value initialization), whereby this function does the latter. Value initialization
|
||||
* rules are complex, but for C-style structs, memory will be zero-initialized. So this doesn't
|
||||
* match a `malloc()`, but a `calloc()` call in this case. See https://stackoverflow.com/a/4982720.
|
||||
*/
|
||||
template<typename T, typename... Args>
|
||||
inline T *MEM_new(const char *allocation_name, Args &&...args)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 620b85f16d03a6aadd7cae56969c9c29b06b992d
|
||||
Subproject commit 050058417452bfba0cc9ae8692173eb02ac1ef3a
|
|
@ -1 +1 @@
|
|||
Subproject commit 67f1fbca1482d9d9362a4001332e785c3fd5d230
|
||||
Subproject commit faa9fc7f98e19be54a715c24061185b04dff5b6c
|
|
@ -1 +1 @@
|
|||
Subproject commit 7936dde9ece881d531b1a2ee6c45ddb56d30038c
|
||||
Subproject commit 61e45814503f51963c91c51aaf764612e7c5dc72
|
|
@ -677,7 +677,6 @@ url_manual_mapping = (
|
|||
("bpy.ops.gpencil.stroke_merge_by_distance*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-stroke-merge-by-distance"),
|
||||
("bpy.ops.node.collapse_hide_unused_toggle*", "interface/controls/nodes/editing.html#bpy-ops-node-collapse-hide-unused-toggle"),
|
||||
("bpy.ops.object.anim_transforms_to_deltas*", "scene_layout/object/editing/apply.html#bpy-ops-object-anim-transforms-to-deltas"),
|
||||
("bpy.ops.object.convert_proxy_to_override*", "files/linked_libraries/library_overrides.html#bpy-ops-object-convert-proxy-to-override"),
|
||||
("bpy.ops.object.modifier_copy_to_selected*", "modeling/modifiers/introduction.html#bpy-ops-object-modifier-copy-to-selected"),
|
||||
("bpy.ops.preferences.app_template_install*", "advanced/app_templates.html#bpy-ops-preferences-app-template-install"),
|
||||
("bpy.types.actionposemarkers.active_index*", "animation/armatures/properties/pose_library.html#bpy-types-actionposemarkers-active-index"),
|
||||
|
|
|
@ -298,7 +298,7 @@ def xml2rna(
|
|||
del value_xml_split
|
||||
tp_name = 'ARRAY'
|
||||
|
||||
# print(" %s.%s (%s) --- %s" % (type(value).__name__, attr, tp_name, subvalue_type))
|
||||
# print(" %s.%s (%s) --- %s" % (type(value).__name__, attr, tp_name, subvalue_type))
|
||||
try:
|
||||
setattr(value, attr, value_xml_coerce)
|
||||
except ValueError:
|
||||
|
@ -340,7 +340,6 @@ def xml2rna(
|
|||
|
||||
else:
|
||||
# print(elems)
|
||||
|
||||
if len(elems) == 1:
|
||||
# sub node named by its type
|
||||
child_xml_real, = elems
|
||||
|
@ -376,7 +375,6 @@ def _get_context_val(context, path):
|
|||
|
||||
|
||||
def xml_file_run(context, filepath, rna_map):
|
||||
|
||||
import xml.dom.minidom
|
||||
|
||||
xml_nodes = xml.dom.minidom.parse(filepath)
|
||||
|
@ -391,27 +389,25 @@ def xml_file_run(context, filepath, rna_map):
|
|||
value = _get_context_val(context, rna_path)
|
||||
|
||||
if value is not Ellipsis and value is not None:
|
||||
print(" loading XML: %r -> %r" % (filepath, rna_path))
|
||||
# print(" loading XML: %r -> %r" % (filepath, rna_path))
|
||||
xml2rna(xml_node, root_rna=value)
|
||||
|
||||
|
||||
def xml_file_write(context, filepath, rna_map, *, skip_typemap=None):
|
||||
with open(filepath, "w", encoding="utf-8") as file:
|
||||
fw = file.write
|
||||
fw("<bpy>\n")
|
||||
|
||||
file = open(filepath, "w", encoding="utf-8")
|
||||
fw = file.write
|
||||
|
||||
fw("<bpy>\n")
|
||||
|
||||
for rna_path, _xml_tag in rna_map:
|
||||
# xml_tag is ignored, we get this from the rna
|
||||
value = _get_context_val(context, rna_path)
|
||||
rna2xml(fw,
|
||||
for rna_path, _xml_tag in rna_map:
|
||||
# xml_tag is ignored, we get this from the rna
|
||||
value = _get_context_val(context, rna_path)
|
||||
rna2xml(
|
||||
fw=fw,
|
||||
root_rna=value,
|
||||
method='ATTR',
|
||||
root_ident=" ",
|
||||
ident_val=" ",
|
||||
skip_typemap=skip_typemap,
|
||||
)
|
||||
)
|
||||
|
||||
fw("</bpy>\n")
|
||||
file.close()
|
||||
fw("</bpy>\n")
|
||||
|
|
|
@ -318,7 +318,8 @@ def load():
|
|||
use_v3d_tab_menu=kc_prefs.use_v3d_tab_menu,
|
||||
use_v3d_shade_ex_pie=kc_prefs.use_v3d_shade_ex_pie,
|
||||
use_gizmo_drag=(is_select_left and kc_prefs.gizmo_action == 'DRAG'),
|
||||
use_fallback_tool=(True if is_select_left else (kc_prefs.rmb_action == 'FALLBACK_TOOL')),
|
||||
use_fallback_tool=True,
|
||||
use_fallback_tool_rmb=(False if is_select_left else kc_prefs.rmb_action == 'FALLBACK_TOOL'),
|
||||
use_alt_tool_or_cursor=(
|
||||
(not use_mouse_emulate_3_button) and
|
||||
(kc_prefs.use_alt_tool if is_select_left else kc_prefs.use_alt_cursor)
|
||||
|
|
|
@ -16,6 +16,16 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Developer Notes
|
||||
#
|
||||
# - This script should run without Blender (no references to the `bpy` module for example).
|
||||
# - All configuration must be passed into the `generate_keymaps` function (via `Params`).
|
||||
# - Supporting some combinations of options is becoming increasingly complex,
|
||||
# especially `Params.select_mouse` & `Params.use_fallback_tool_rmb`.
|
||||
# To ensure changes don't unintentionally break other configurations, see:
|
||||
# `source/tools/utils/blender_keyconfig_export_permutations.py --help`
|
||||
#
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Configurable Parameters
|
||||
|
@ -48,6 +58,8 @@ class Params:
|
|||
"use_gizmo_drag",
|
||||
# Use the fallback tool instead of tweak for RMB select.
|
||||
"use_fallback_tool",
|
||||
# Only set for RMB select.
|
||||
"use_fallback_tool_rmb",
|
||||
# Use pie menu for tab by default (swap 'Tab/Ctrl-Tab').
|
||||
"use_v3d_tab_menu",
|
||||
# Use extended pie menu for shading.
|
||||
|
@ -65,15 +77,16 @@ class Params:
|
|||
"v3d_tilde_action",
|
||||
# Alt-MMB axis switching 'RELATIVE' or 'ABSOLUTE' axis switching.
|
||||
"v3d_alt_mmb_drag_action",
|
||||
|
||||
# File selector actions on single click.
|
||||
"use_file_single_click",
|
||||
|
||||
# Convenience variables:
|
||||
# (derived from other settings).
|
||||
#
|
||||
# This case needs to be checked often,
|
||||
# Shorthand for: `(params.use_fallback_tool if params.select_mouse == 'RIGHTMOUSE' else False)`.
|
||||
"use_fallback_tool_rmb",
|
||||
# Shorthand for: `('CLICK' if params.use_fallback_tool_rmb else params.select_mouse_value)`.
|
||||
# The fallback tool is activated on the same button as selection.
|
||||
# Shorthand for: `(True if (select_mouse == 'LEFT') else self.use_fallback_tool_rmb)`
|
||||
"use_fallback_tool_select_mouse",
|
||||
# Shorthand for: `('CLICK' if self.use_fallback_tool_rmb else self.select_mouse_value)`.
|
||||
"select_mouse_value_fallback",
|
||||
# Shorthand for: `{"type": params.select_tweak, "value": 'ANY'}`.
|
||||
"select_tweak_event",
|
||||
|
@ -103,6 +116,7 @@ class Params:
|
|||
use_select_all_toggle=False,
|
||||
use_gizmo_drag=True,
|
||||
use_fallback_tool=False,
|
||||
use_fallback_tool_rmb=False,
|
||||
use_v3d_tab_menu=False,
|
||||
use_v3d_shade_ex_pie=False,
|
||||
use_v3d_mmb_pan=False,
|
||||
|
@ -146,7 +160,6 @@ class Params:
|
|||
self.cursor_set_event = {"type": 'LEFTMOUSE', "value": 'CLICK'}
|
||||
self.cursor_tweak_event = None
|
||||
|
||||
self.use_fallback_tool = use_fallback_tool
|
||||
self.tool_modifier = {}
|
||||
else:
|
||||
# Left mouse select uses Click event for selection. This is a little
|
||||
|
@ -169,7 +182,6 @@ class Params:
|
|||
|
||||
self.cursor_set_event = {"type": 'RIGHTMOUSE', "value": 'PRESS', "shift": True}
|
||||
self.cursor_tweak_event = {"type": 'EVT_TWEAK_R', "value": 'ANY', "shift": True}
|
||||
self.use_fallback_tool = True
|
||||
|
||||
# Use the "tool" functionality for LMB select.
|
||||
if use_alt_tool_or_cursor:
|
||||
|
@ -197,8 +209,11 @@ class Params:
|
|||
|
||||
self.use_file_single_click = use_file_single_click
|
||||
|
||||
self.use_fallback_tool = use_fallback_tool
|
||||
self.use_fallback_tool_rmb = use_fallback_tool_rmb
|
||||
|
||||
# Convenience variables:
|
||||
self.use_fallback_tool_rmb = self.use_fallback_tool if select_mouse == 'RIGHT' else False
|
||||
self.use_fallback_tool_select_mouse = True if (select_mouse == 'LEFT') else self.use_fallback_tool_rmb
|
||||
self.select_mouse_value_fallback = 'CLICK' if self.use_fallback_tool_rmb else self.select_mouse_value
|
||||
self.select_tweak_event = {"type": self.select_tweak, "value": 'ANY'}
|
||||
self.pie_value = 'CLICK_DRAG' if use_pie_click_drag else 'PRESS'
|
||||
|
@ -1149,11 +1164,7 @@ def km_uv_editor(params):
|
|||
items.extend([
|
||||
# Selection modes.
|
||||
*_template_items_uv_select_mode(params),
|
||||
*_template_uv_select(
|
||||
type=params.select_mouse,
|
||||
value=('CLICK' if params.use_fallback_tool_rmb else params.select_mouse_value),
|
||||
legacy=params.legacy,
|
||||
),
|
||||
*_template_uv_select(type=params.select_mouse, value=params.select_mouse_value_fallback, legacy=params.legacy),
|
||||
("uv.mark_seam", {"type": 'E', "value": 'PRESS', "ctrl": True}, None),
|
||||
("uv.select_loop",
|
||||
{"type": params.select_mouse, "value": params.select_mouse_value, "alt": True}, None),
|
||||
|
@ -6283,7 +6294,8 @@ def km_image_editor_tool_uv_select_box(params, *, fallback):
|
|||
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions_simple(
|
||||
"uv.select_box",
|
||||
# Don't use `tool_maybe_tweak_event`, see comment for this slot.
|
||||
**(params.select_tweak_event if fallback else params.tool_tweak_event))),
|
||||
**(params.select_tweak_event if (fallback and params.use_fallback_tool_select_mouse) else
|
||||
params.tool_tweak_event))),
|
||||
]},
|
||||
)
|
||||
|
||||
|
@ -6295,7 +6307,8 @@ def km_image_editor_tool_uv_select_circle(params, *, fallback):
|
|||
{"items": [
|
||||
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions_simple(
|
||||
"uv.select_circle",
|
||||
**(params.select_tweak_event if fallback else {"type": params.tool_mouse, "value": 'PRESS'}),
|
||||
**(params.select_tweak_event if (fallback and params.use_fallback_tool_select_mouse) else
|
||||
{"type": params.tool_mouse, "value": 'PRESS'}),
|
||||
properties=[("wait_for_input", False)])),
|
||||
# No selection fallback since this operates on press.
|
||||
]},
|
||||
|
@ -6310,7 +6323,8 @@ def km_image_editor_tool_uv_select_lasso(params, *, fallback):
|
|||
{"items": [
|
||||
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions_simple(
|
||||
"uv.select_lasso",
|
||||
**(params.select_tweak_event if fallback else params.tool_tweak_event))),
|
||||
**(params.select_tweak_event if (fallback and params.use_fallback_tool_select_mouse) else
|
||||
params.tool_tweak_event))),
|
||||
]},
|
||||
)
|
||||
|
||||
|
@ -6402,7 +6416,8 @@ def km_node_editor_tool_select_box(params, *, fallback):
|
|||
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions_simple(
|
||||
"node.select_box",
|
||||
# Don't use `tool_maybe_tweak_event`, see comment for this slot.
|
||||
**(params.select_tweak_event if fallback else params.tool_tweak_event),
|
||||
**(params.select_tweak_event if (fallback and params.use_fallback_tool_select_mouse) else
|
||||
params.tool_tweak_event),
|
||||
properties=[("tweak", True)],
|
||||
)),
|
||||
]},
|
||||
|
@ -6415,7 +6430,9 @@ def km_node_editor_tool_select_lasso(params, *, fallback):
|
|||
{"space_type": 'NODE_EDITOR', "region_type": 'WINDOW'},
|
||||
{"items": [
|
||||
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions_simple(
|
||||
"node.select_lasso", **(params.select_tweak_event if fallback else params.tool_tweak_event),
|
||||
"node.select_lasso",
|
||||
**(params.select_tweak_event if (fallback and params.use_fallback_tool_select_mouse) else
|
||||
params.tool_tweak_event),
|
||||
properties=[("tweak", True)]))
|
||||
]},
|
||||
)
|
||||
|
@ -6430,7 +6447,7 @@ def km_node_editor_tool_select_circle(params, *, fallback):
|
|||
"node.select_circle",
|
||||
# Why circle select should be used on tweak?
|
||||
# So that RMB or Shift-RMB is still able to set an element as active.
|
||||
type=params.select_tweak if fallback else params.tool_mouse,
|
||||
type=params.select_tweak if (fallback and params.use_fallback_tool_select_mouse) else params.tool_mouse,
|
||||
value='ANY' if fallback else 'PRESS',
|
||||
properties=[("wait_for_input", False)])),
|
||||
]},
|
||||
|
@ -6484,7 +6501,8 @@ def km_3d_view_tool_select_box(params, *, fallback):
|
|||
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions(
|
||||
"view3d.select_box",
|
||||
# Don't use `tool_maybe_tweak_event`, see comment for this slot.
|
||||
**(params.select_tweak_event if fallback else params.tool_tweak_event))),
|
||||
**(params.select_tweak_event if (fallback and params.use_fallback_tool_select_mouse) else
|
||||
params.tool_tweak_event))),
|
||||
]},
|
||||
)
|
||||
|
||||
|
@ -6498,7 +6516,7 @@ def km_3d_view_tool_select_circle(params, *, fallback):
|
|||
"view3d.select_circle",
|
||||
# Why circle select should be used on tweak?
|
||||
# So that RMB or Shift-RMB is still able to set an element as active.
|
||||
type=params.select_tweak if fallback else params.tool_mouse,
|
||||
type=params.select_tweak if (fallback and params.use_fallback_tool_select_mouse) else params.tool_mouse,
|
||||
value='ANY' if fallback else 'PRESS',
|
||||
properties=[("wait_for_input", False)])),
|
||||
]},
|
||||
|
@ -6512,7 +6530,8 @@ def km_3d_view_tool_select_lasso(params, *, fallback):
|
|||
{"items": [
|
||||
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions(
|
||||
"view3d.select_lasso",
|
||||
**(params.select_tweak_event if fallback else params.tool_tweak_event))),
|
||||
**(params.select_tweak_event if (fallback and params.use_fallback_tool_select_mouse) else
|
||||
params.tool_tweak_event))),
|
||||
]}
|
||||
)
|
||||
|
||||
|
@ -7394,7 +7413,8 @@ def km_3d_view_tool_edit_gpencil_select_box(params, *, fallback):
|
|||
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions(
|
||||
"gpencil.select_box",
|
||||
# Don't use `tool_maybe_tweak_event`, see comment for this slot.
|
||||
**(params.select_tweak_event if fallback else params.tool_tweak_event))),
|
||||
**(params.select_tweak_event if (fallback and params.use_fallback_tool_select_mouse) else
|
||||
params.tool_tweak_event))),
|
||||
]},
|
||||
)
|
||||
|
||||
|
@ -7408,7 +7428,7 @@ def km_3d_view_tool_edit_gpencil_select_circle(params, *, fallback):
|
|||
"gpencil.select_circle",
|
||||
# Why circle select should be used on tweak?
|
||||
# So that RMB or Shift-RMB is still able to set an element as active.
|
||||
type=params.select_tweak if fallback else params.tool_mouse,
|
||||
type=params.select_tweak if (fallback and params.use_fallback_tool_select_mouse) else params.tool_mouse,
|
||||
value='ANY' if fallback else 'PRESS',
|
||||
properties=[("wait_for_input", False)])),
|
||||
]},
|
||||
|
@ -7422,7 +7442,8 @@ def km_3d_view_tool_edit_gpencil_select_lasso(params, *, fallback):
|
|||
{"items": [
|
||||
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions(
|
||||
"gpencil.select_lasso",
|
||||
**(params.select_tweak_event if fallback else params.tool_tweak_event))),
|
||||
**(params.select_tweak_event if (fallback and params.use_fallback_tool_select_mouse) else
|
||||
params.tool_tweak_event))),
|
||||
]}
|
||||
)
|
||||
|
||||
|
@ -7573,7 +7594,8 @@ def km_sequencer_editor_tool_generic_select_box(params, *, fallback):
|
|||
# Don't use `tool_maybe_tweak_event`, see comment for this slot.
|
||||
*([] if (fallback and not params.use_fallback_tool) else _template_items_tool_select_actions_simple(
|
||||
"sequencer.select_box",
|
||||
**(params.select_tweak_event if fallback else params.tool_tweak_event),
|
||||
**(params.select_tweak_event if (fallback and params.use_fallback_tool_select_mouse) else
|
||||
params.tool_tweak_event),
|
||||
properties=[("tweak", params.select_mouse == 'LEFTMOUSE')])),
|
||||
|
||||
# RMB select can already set the frame, match the tweak tool.
|
||||
|
|
|
@ -2961,93 +2961,75 @@ class WM_MT_splash_quick_setup(Menu):
|
|||
bl_label = "Quick Setup"
|
||||
|
||||
def draw(self, context):
|
||||
wm = context.window_manager
|
||||
# prefs = context.preferences
|
||||
|
||||
layout = self.layout
|
||||
|
||||
layout.operator_context = 'EXEC_DEFAULT'
|
||||
|
||||
layout.label(text="Quick Setup")
|
||||
|
||||
split = layout.split(factor=0.25)
|
||||
split = layout.split(factor=0.14) # Left margin.
|
||||
split.label()
|
||||
split = split.split(factor=2.0 / 3.0)
|
||||
split = split.split(factor=0.73) # Content width.
|
||||
|
||||
col = split.column()
|
||||
|
||||
col.use_property_split = True
|
||||
col.use_property_decorate = False
|
||||
|
||||
# Languages.
|
||||
if bpy.app.build_options.international:
|
||||
sub = col.split(factor=0.35)
|
||||
row = sub.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Language")
|
||||
prefs = context.preferences
|
||||
sub.prop(prefs.view, "language", text="")
|
||||
col.prop(prefs.view, "language")
|
||||
col.separator()
|
||||
|
||||
col.separator()
|
||||
# Shortcuts.
|
||||
wm = context.window_manager
|
||||
kc = wm.keyconfigs.active
|
||||
kc_prefs = kc.preferences
|
||||
|
||||
sub = col.split(factor=0.35)
|
||||
row = sub.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Shortcuts")
|
||||
text = bpy.path.display_name(wm.keyconfigs.active.name)
|
||||
sub = col.column(heading="Shortcuts")
|
||||
text = bpy.path.display_name(kc.name)
|
||||
if not text:
|
||||
text = "Blender"
|
||||
sub.menu("USERPREF_MT_keyconfigs", text=text)
|
||||
|
||||
kc = wm.keyconfigs.active
|
||||
kc_prefs = kc.preferences
|
||||
has_select_mouse = hasattr(kc_prefs, "select_mouse")
|
||||
if has_select_mouse:
|
||||
sub = col.split(factor=0.35)
|
||||
row = sub.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Select With")
|
||||
sub.row().prop(kc_prefs, "select_mouse", expand=True)
|
||||
has_select_mouse = True
|
||||
col.row().prop(kc_prefs, "select_mouse", text="Select With", expand=True)
|
||||
|
||||
has_spacebar_action = hasattr(kc_prefs, "spacebar_action")
|
||||
if has_spacebar_action:
|
||||
sub = col.split(factor=0.35)
|
||||
row = sub.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Spacebar")
|
||||
sub.row().prop(kc_prefs, "spacebar_action", expand=True)
|
||||
has_select_mouse = True
|
||||
col.row().prop(kc_prefs, "spacebar_action", text="Spacebar")
|
||||
|
||||
col.separator()
|
||||
|
||||
sub = col.split(factor=0.35)
|
||||
row = sub.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Theme")
|
||||
# Themes.
|
||||
sub = col.column(heading="Theme")
|
||||
label = bpy.types.USERPREF_MT_interface_theme_presets.bl_label
|
||||
if label == "Presets":
|
||||
label = "Blender Dark"
|
||||
sub.menu("USERPREF_MT_interface_theme_presets", text=label)
|
||||
|
||||
# Keep height constant
|
||||
# Keep height constant.
|
||||
if not has_select_mouse:
|
||||
col.label()
|
||||
if not has_spacebar_action:
|
||||
col.label()
|
||||
|
||||
layout.label()
|
||||
layout.separator(factor=2.0)
|
||||
|
||||
row = layout.row()
|
||||
# Save settings buttons.
|
||||
sub = layout.row()
|
||||
|
||||
sub = row.row()
|
||||
old_version = bpy.types.PREFERENCES_OT_copy_prev.previous_version()
|
||||
if bpy.types.PREFERENCES_OT_copy_prev.poll(context) and old_version:
|
||||
sub.operator("preferences.copy_prev", text=iface_("Load %d.%d Settings", "Operator") % old_version)
|
||||
sub.operator("preferences.copy_prev", text="Load %d.%d Settings" % old_version)
|
||||
sub.operator("wm.save_userpref", text="Save New Settings")
|
||||
else:
|
||||
sub.label()
|
||||
sub.label()
|
||||
sub.operator("wm.save_userpref", text="Next")
|
||||
|
||||
layout.separator()
|
||||
layout.separator()
|
||||
layout.separator(factor=2.4)
|
||||
|
||||
|
||||
class WM_MT_splash(Menu):
|
||||
|
|
|
@ -291,6 +291,9 @@ class NLA_MT_context_menu(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
props = layout.operator("wm.call_panel", text="Rename...")
|
||||
props.name = "TOPBAR_PT_name"
|
||||
props.keep_open = False
|
||||
layout.operator("nla.duplicate", text="Duplicate").linked = False
|
||||
layout.operator("nla.duplicate", text="Linked Duplicate").linked = True
|
||||
|
||||
|
|
|
@ -481,7 +481,7 @@ class TOPBAR_MT_file_export(Menu):
|
|||
bl_owner_use_filter = False
|
||||
|
||||
def draw(self, _context):
|
||||
self.layout.operator("wm.obj_export", text="Wavefront OBJ (.obj) - New")
|
||||
self.layout.operator("wm.obj_export", text="Wavefront OBJ (.obj)")
|
||||
if bpy.app.build_options.collada:
|
||||
self.layout.operator("wm.collada_export",
|
||||
text="Collada (Default) (.dae)")
|
||||
|
@ -832,6 +832,14 @@ class TOPBAR_PT_name(Panel):
|
|||
row = row_with_icon(layout, 'NODE')
|
||||
row.prop(item, "label", text="")
|
||||
found = True
|
||||
elif space_type == 'NLA_EDITOR':
|
||||
layout.label(text="NLA Strip Name")
|
||||
item = next(
|
||||
(strip for strip in context.selected_nla_strips if strip.active), None)
|
||||
if item:
|
||||
row = row_with_icon(layout, 'NLA')
|
||||
row.prop(item, "name", text="")
|
||||
found = True
|
||||
else:
|
||||
if mode == 'POSE' or (mode == 'WEIGHT_PAINT' and context.pose_object):
|
||||
layout.label(text="Bone Name")
|
||||
|
|
|
@ -2316,7 +2316,6 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
|
|||
context, (
|
||||
({"property": "use_undo_legacy"}, "T60695"),
|
||||
({"property": "override_auto_resync"}, "T83811"),
|
||||
({"property": "proxy_to_override_auto_conversion"}, "T91671"),
|
||||
({"property": "use_cycles_debug"}, None),
|
||||
({"property": "use_geometry_nodes_legacy"}, "T91274"),
|
||||
({"property": "show_asset_debug_info"}, None),
|
||||
|
|
|
@ -2228,8 +2228,6 @@ class VIEW3D_MT_object_relations(Menu):
|
|||
|
||||
layout.operator("object.make_override_library", text="Make Library Override...")
|
||||
|
||||
layout.operator("object.convert_proxy_to_override")
|
||||
|
||||
layout.operator("object.make_dupli_face")
|
||||
|
||||
layout.separator()
|
||||
|
|
|
@ -547,6 +547,8 @@ compositor_node_categories = [
|
|||
NodeItem("CompositorNodeCombYUVA"),
|
||||
NodeItem("CompositorNodeSepYCCA"),
|
||||
NodeItem("CompositorNodeCombYCCA"),
|
||||
NodeItem("CompositorNodeSeparateXYZ"),
|
||||
NodeItem("CompositorNodeCombineXYZ"),
|
||||
NodeItem("CompositorNodeSwitchView"),
|
||||
NodeItem("CompositorNodeConvertColorSpace"),
|
||||
]),
|
||||
|
|
|
@ -65,6 +65,7 @@ else()
|
|||
)
|
||||
|
||||
add_executable(blender-thumbnailer ${SRC} ${SRC_CMD})
|
||||
setup_platform_linker_flags(blender-thumbnailer)
|
||||
target_link_libraries(blender-thumbnailer bf_blenlib)
|
||||
target_link_libraries(blender-thumbnailer ${PTHREADS_LIBRARIES})
|
||||
endif()
|
||||
|
|
|
@ -334,11 +334,6 @@ void makeDerivedMesh(struct Depsgraph *depsgraph,
|
|||
struct Object *ob,
|
||||
const struct CustomData_MeshMasks *dataMask);
|
||||
|
||||
void DM_calc_loop_tangents(DerivedMesh *dm,
|
||||
bool calc_active_tangent,
|
||||
const char (*tangent_names)[MAX_NAME],
|
||||
int tangent_names_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -365,7 +365,6 @@ void what_does_obaction(struct Object *ob,
|
|||
char groupname[],
|
||||
const struct AnimationEvalContext *anim_eval_context);
|
||||
|
||||
/* for proxy */
|
||||
void BKE_pose_copy_pchan_result(struct bPoseChannel *pchanto,
|
||||
const struct bPoseChannel *pchanfrom);
|
||||
/**
|
||||
|
|
|
@ -619,14 +619,6 @@ void BKE_pose_eval_cleanup(struct Depsgraph *depsgraph,
|
|||
struct Scene *scene,
|
||||
struct Object *object);
|
||||
|
||||
void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph, struct Object *object);
|
||||
void BKE_pose_eval_proxy_done(struct Depsgraph *depsgraph, struct Object *object);
|
||||
void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph, struct Object *object);
|
||||
|
||||
void BKE_pose_eval_proxy_copy_bone(struct Depsgraph *depsgraph,
|
||||
struct Object *object,
|
||||
int pchan_index);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Deform 3D Coordinates by Armature (armature_deform.c)
|
||||
* \{ */
|
||||
|
|
|
@ -39,7 +39,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 0
|
||||
#define BLENDER_FILE_SUBVERSION 1
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -123,11 +123,20 @@ struct Collection *BKE_collection_object_find(struct Main *bmain,
|
|||
bool BKE_collection_is_empty(const struct Collection *collection);
|
||||
|
||||
/**
|
||||
* Add object to collection
|
||||
* Add object to given collection, ensuring this collection is 'editable' (i.e. local and not a
|
||||
* liboverride), and finding a suitable parent one otherwise.
|
||||
*/
|
||||
bool BKE_collection_object_add(struct Main *bmain,
|
||||
struct Collection *collection,
|
||||
struct Object *ob);
|
||||
/**
|
||||
* Same as #BKE_collection_object_add, but unconditionally adds the object to the given collection.
|
||||
*
|
||||
* NOTE: required in certain cases, like do-versioning or complex ID management tasks.
|
||||
*/
|
||||
bool BKE_collection_object_add_notest(struct Main *bmain,
|
||||
struct Collection *collection,
|
||||
struct Object *ob);
|
||||
/**
|
||||
* Add \a ob_dst to all scene collections that reference object \a ob_src is in.
|
||||
* Used for copying objects.
|
||||
|
|
|
@ -278,18 +278,6 @@ bool BKE_constraint_apply_and_remove_for_pose(struct Depsgraph *depsgraph,
|
|||
|
||||
void BKE_constraint_panel_expand(struct bConstraint *con);
|
||||
|
||||
/* Constraints + Proxies function prototypes */
|
||||
|
||||
/**
|
||||
* Rescue all constraints tagged as being #CONSTRAINT_PROXY_LOCAL
|
||||
* (i.e. added to bone that's proxy-synced in this file).
|
||||
*/
|
||||
void BKE_constraints_proxylocal_extract(struct ListBase *dst, struct ListBase *src);
|
||||
/**
|
||||
* Returns if the owner of the constraint is proxy-protected.
|
||||
*/
|
||||
bool BKE_constraints_proxylocked_owner(struct Object *ob, struct bPoseChannel *pchan);
|
||||
|
||||
/* Constraint Evaluation function prototypes */
|
||||
|
||||
/**
|
||||
|
|
|
@ -253,6 +253,11 @@ bool CustomData_free_layer_active(struct CustomData *data, int type, int totelem
|
|||
*/
|
||||
void CustomData_free_layers(struct CustomData *data, int type, int totelem);
|
||||
|
||||
/**
|
||||
* Free all anonymous attributes.
|
||||
*/
|
||||
void CustomData_free_layers_anonymous(struct CustomData *data, int totelem);
|
||||
|
||||
/**
|
||||
* Returns true if a layer with the specified type exists.
|
||||
*/
|
||||
|
|
|
@ -376,10 +376,6 @@ enum {
|
|||
/** Clear asset data (in case the ID can actually be made local, in copy case asset data is never
|
||||
* copied over). */
|
||||
LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR = 1 << 3,
|
||||
|
||||
/* Special type-specific options. */
|
||||
/** For Objects, do not clear the proxy pointers while making the data-block local. */
|
||||
LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING = 1 << 16,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -100,6 +100,9 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
|
|||
* main. You can add more local IDs to be remapped to use new overriding ones by setting their
|
||||
* LIB_TAG_DOIT tag.
|
||||
*
|
||||
* \param owner_library: the library in which the overrides should be created. Besides versioning
|
||||
* and resync code path, this should always be NULL (i.e. the local .blend file).
|
||||
*
|
||||
* \param reference_library: the library from which the linked data being overridden come from
|
||||
* (i.e. the library of the linked reference ID).
|
||||
*
|
||||
|
@ -109,6 +112,7 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
|
|||
* \return \a true on success, \a false otherwise.
|
||||
*/
|
||||
bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
|
||||
struct Library *owner_library,
|
||||
const struct Library *reference_library,
|
||||
bool do_no_main);
|
||||
/**
|
||||
|
@ -122,16 +126,24 @@ bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
|
|||
*
|
||||
* \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
|
||||
* which case \a scene's master collection children hierarchy is used instead).
|
||||
*
|
||||
* \param owner_library: the library in which the overrides should be created. Besides versioning
|
||||
* and resync code path, this should always be NULL (i.e. the local .blend file).
|
||||
*
|
||||
* \param id_root: The root ID to create an override from.
|
||||
*
|
||||
* \param id_reference: Some reference ID used to do some post-processing after overrides have been
|
||||
* created, may be NULL. Typically, the Empty object instantiating the linked collection we
|
||||
* override, currently.
|
||||
*
|
||||
* \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
|
||||
*
|
||||
* \return true if override was successfully created.
|
||||
*/
|
||||
bool BKE_lib_override_library_create(struct Main *bmain,
|
||||
struct Scene *scene,
|
||||
struct ViewLayer *view_layer,
|
||||
struct Library *owner_library,
|
||||
struct ID *id_root,
|
||||
struct ID *id_reference,
|
||||
struct ID **r_id_root_override);
|
||||
|
|
|
@ -63,7 +63,7 @@ enum {
|
|||
|
||||
/**
|
||||
* That ID is not really used by its owner, it's just an internal hint/helper.
|
||||
* This addresses Their Highest Ugliness the 'from' pointers: Object->from_proxy and Key->from.
|
||||
* This marks the 'from' pointers issue, like Key->from.
|
||||
* How to handle that kind of cases totally depends on what caller code is doing... */
|
||||
IDWALK_CB_LOOPBACK = (1 << 4),
|
||||
|
||||
|
@ -135,7 +135,6 @@ enum {
|
|||
/** Do not process ID pointers inside embedded IDs. Needed by depsgraph processing e.g. */
|
||||
IDWALK_IGNORE_EMBEDDED_ID = (1 << 3),
|
||||
|
||||
IDWALK_NO_INDIRECT_PROXY_DATA_USAGE = (1 << 8), /* Ugly special case :(((( */
|
||||
/** Also process internal ID pointers like `ID.newid` or `ID.orig_id`.
|
||||
* WARNING: Dangerous, use with caution. */
|
||||
IDWALK_DO_INTERNAL_RUNTIME_POINTERS = (1 << 9),
|
||||
|
|
|
@ -68,15 +68,6 @@ enum {
|
|||
* and can cause crashes very easily!
|
||||
*/
|
||||
ID_REMAP_FORCE_NEVER_NULL_USAGE = 1 << 3,
|
||||
/**
|
||||
* Do not consider proxy/_group pointers of local objects as indirect usages...
|
||||
* Our oh-so-beloved proxies again...
|
||||
* Do not consider data used by local proxy object as indirect usage.
|
||||
* This is needed e.g. in reload scenario,
|
||||
* since we have to ensure remapping of Armature data of local proxy
|
||||
* is also performed. Usual nightmare...
|
||||
*/
|
||||
ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4,
|
||||
/** Do not remap library override pointers. */
|
||||
ID_REMAP_SKIP_OVERRIDE_LIBRARY = 1 << 5,
|
||||
/** Don't touch the user count (use for low level actions such as swapping pointers). */
|
||||
|
|
|
@ -466,6 +466,8 @@ void BKE_modifiers_foreach_tex_link(struct Object *ob, TexWalkFunc walk, void *u
|
|||
|
||||
struct ModifierData *BKE_modifiers_findby_type(const struct Object *ob, ModifierType type);
|
||||
struct ModifierData *BKE_modifiers_findby_name(const struct Object *ob, const char *name);
|
||||
struct ModifierData *BKE_modifiers_findby_session_uuid(const struct Object *ob,
|
||||
const SessionUUID *session_uuid);
|
||||
void BKE_modifiers_clear_errors(struct Object *ob);
|
||||
/**
|
||||
* used for buttons, to find out if the 'draw deformed in edit-mode option is there.
|
||||
|
@ -564,7 +566,8 @@ const char *BKE_modifier_path_relbase_from_global(struct Object *ob);
|
|||
* For a given modifier data, get corresponding original one.
|
||||
* If the modifier data is already original, return it as-is.
|
||||
*/
|
||||
struct ModifierData *BKE_modifier_get_original(struct ModifierData *md);
|
||||
struct ModifierData *BKE_modifier_get_original(const struct Object *object,
|
||||
struct ModifierData *md);
|
||||
struct ModifierData *BKE_modifier_get_evaluated(struct Depsgraph *depsgraph,
|
||||
struct Object *object,
|
||||
struct ModifierData *md);
|
||||
|
|
|
@ -1291,6 +1291,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
|||
#define CMP_NODE_POSTERIZE 327
|
||||
#define CMP_NODE_CONVERT_COLOR_SPACE 328
|
||||
#define CMP_NODE_SCENE_TIME 329
|
||||
#define CMP_NODE_SEPARATE_XYZ 330
|
||||
#define CMP_NODE_COMBINE_XYZ 331
|
||||
|
||||
/* channel toggles */
|
||||
#define CMP_CHAN_RGB 1
|
||||
|
|
|
@ -144,18 +144,6 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
|
|||
void BKE_object_free_modifiers(struct Object *ob, int flag);
|
||||
void BKE_object_free_shaderfx(struct Object *ob, int flag);
|
||||
|
||||
/**
|
||||
* Proxy rule:
|
||||
* - `lib_object->proxy_from` == the one we borrow from, set temporally while object_update.
|
||||
* - `local_object->proxy` == pointer to library object, saved in files and read.
|
||||
* - `local_object->proxy_group` == pointer to collection dupli-object, saved in files and read.
|
||||
*/
|
||||
void BKE_object_make_proxy(struct Main *bmain,
|
||||
struct Object *ob,
|
||||
struct Object *target,
|
||||
struct Object *cob);
|
||||
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
|
||||
|
||||
bool BKE_object_exists_check(struct Main *bmain, const struct Object *obtest);
|
||||
/**
|
||||
* Actual check for internal data, not context or flags.
|
||||
|
@ -444,7 +432,6 @@ void BKE_object_eval_constraints(struct Depsgraph *depsgraph,
|
|||
struct Object *ob);
|
||||
void BKE_object_eval_transform_final(struct Depsgraph *depsgraph, struct Object *ob);
|
||||
|
||||
bool BKE_object_eval_proxy_copy(struct Depsgraph *depsgraph, struct Object *object);
|
||||
void BKE_object_eval_uber_transform(struct Depsgraph *depsgraph, struct Object *ob);
|
||||
void BKE_object_eval_uber_data(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
|
@ -486,12 +473,6 @@ void BKE_object_handle_data_update(struct Depsgraph *depsgraph,
|
|||
*/
|
||||
void BKE_object_handle_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
|
||||
/**
|
||||
* Proxy rule:
|
||||
* - lib_object->proxy_from == the one we borrow from, only set temporal and cleared here.
|
||||
* - local_object->proxy == pointer to library object, saved in files and read.
|
||||
*
|
||||
* Function below is polluted with proxy exceptions, cleanup will follow!
|
||||
*
|
||||
* The main object update call, for object matrix, constraints, keys and #DispList (modifiers)
|
||||
* requires flags to be set!
|
||||
*
|
||||
|
@ -501,8 +482,7 @@ void BKE_object_handle_update(struct Depsgraph *depsgraph, struct Scene *scene,
|
|||
void BKE_object_handle_update_ex(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct Object *ob,
|
||||
struct RigidBodyWorld *rbw,
|
||||
bool do_proxy_update);
|
||||
struct RigidBodyWorld *rbw);
|
||||
|
||||
void BKE_object_sculpt_data_create(struct Object *ob);
|
||||
|
||||
|
|
|
@ -499,7 +499,6 @@ typedef struct SculptSession {
|
|||
|
||||
/* These are always assigned to base mesh data when using PBVH_FACES and PBVH_GRIDS. */
|
||||
struct MVert *mvert;
|
||||
const float (*vert_normals)[3];
|
||||
struct MPoly *mpoly;
|
||||
struct MLoop *mloop;
|
||||
|
||||
|
|
|
@ -182,6 +182,7 @@ set(SRC
|
|||
intern/lib_id_eval.c
|
||||
intern/lib_id_remapper.cc
|
||||
intern/lib_override.c
|
||||
intern/lib_override_proxy_conversion.c
|
||||
intern/lib_query.c
|
||||
intern/lib_remap.c
|
||||
intern/library.c
|
||||
|
|
|
@ -1998,32 +1998,6 @@ void mesh_get_mapped_verts_coords(Mesh *me_eval, float (*r_cos)[3], const int to
|
|||
}
|
||||
}
|
||||
|
||||
void DM_calc_loop_tangents(DerivedMesh *dm,
|
||||
bool calc_active_tangent,
|
||||
const char (*tangent_names)[MAX_NAME],
|
||||
int tangent_names_len)
|
||||
{
|
||||
BKE_mesh_calc_loop_tangent_ex(
|
||||
dm->getVertArray(dm),
|
||||
dm->getPolyArray(dm),
|
||||
dm->getNumPolys(dm),
|
||||
dm->getLoopArray(dm),
|
||||
dm->getLoopTriArray(dm),
|
||||
dm->getNumLoopTri(dm),
|
||||
&dm->loopData,
|
||||
calc_active_tangent,
|
||||
tangent_names,
|
||||
tangent_names_len,
|
||||
(const float(*)[3])CustomData_get_layer(&dm->vertData, CD_NORMAL),
|
||||
(const float(*)[3])CustomData_get_layer(&dm->polyData, CD_NORMAL),
|
||||
(const float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL),
|
||||
(const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* may be nullptr */
|
||||
/* result */
|
||||
&dm->loopData,
|
||||
dm->getNumLoops(dm),
|
||||
&dm->tangent_mask);
|
||||
}
|
||||
|
||||
static void mesh_init_origspace(Mesh *mesh)
|
||||
{
|
||||
const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
|
||||
|
|
|
@ -1956,30 +1956,15 @@ void BKE_pose_blend_read_lib(BlendLibReader *reader, Object *ob, bPose *pose)
|
|||
return;
|
||||
}
|
||||
|
||||
/* always rebuild to match proxy or lib changes, but on Undo */
|
||||
/* Always rebuild to match library changes, except on Undo. */
|
||||
bool rebuild = false;
|
||||
|
||||
if (!BLO_read_lib_is_undo(reader)) {
|
||||
if (ob->proxy || ob->id.lib != arm->id.lib) {
|
||||
if (ob->id.lib != arm->id.lib) {
|
||||
rebuild = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ob->proxy) {
|
||||
/* sync proxy layer */
|
||||
if (pose->proxy_layer) {
|
||||
arm->layer = pose->proxy_layer;
|
||||
}
|
||||
|
||||
/* sync proxy active bone */
|
||||
if (pose->proxy_act_bone[0]) {
|
||||
Bone *bone = BKE_armature_find_bone_name(arm, pose->proxy_act_bone);
|
||||
if (bone) {
|
||||
arm->act_bone = bone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
|
||||
BKE_constraint_blend_read_lib(reader, (ID *)ob, &pchan->constraints);
|
||||
|
||||
|
|
|
@ -69,8 +69,6 @@
|
|||
|
||||
#include "CLG_log.h"
|
||||
|
||||
static CLG_LogRef LOG = {"bke.armature"};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Prototypes
|
||||
* \{ */
|
||||
|
@ -2296,161 +2294,6 @@ void BKE_armature_where_is(bArmature *arm)
|
|||
/** \name Pose Rebuild
|
||||
* \{ */
|
||||
|
||||
/* if bone layer is protected, copy the data from from->pose
|
||||
* when used with linked libraries this copies from the linked pose into the local pose */
|
||||
static void pose_proxy_sync(Object *ob, Object *from, int layer_protected)
|
||||
{
|
||||
bPose *pose = ob->pose, *frompose = from->pose;
|
||||
bPoseChannel *pchan, *pchanp;
|
||||
bConstraint *con;
|
||||
int error = 0;
|
||||
|
||||
if (frompose == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* in some cases when rigs change, we can't synchronize
|
||||
* to avoid crashing check for possible errors here */
|
||||
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
if (pchan->bone->layer & layer_protected) {
|
||||
if (BKE_pose_channel_find_name(frompose, pchan->name) == NULL) {
|
||||
CLOG_ERROR(&LOG,
|
||||
"failed to sync proxy armature because '%s' is missing pose channel '%s'",
|
||||
from->id.name,
|
||||
pchan->name);
|
||||
error = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* clear all transformation values from library */
|
||||
BKE_pose_rest(frompose, false);
|
||||
|
||||
/* copy over all of the proxy's bone groups */
|
||||
/* TODO: for later
|
||||
* - implement 'local' bone groups as for constraints
|
||||
* NOTE: this isn't trivial, as bones reference groups by index not by pointer,
|
||||
* so syncing things correctly needs careful attention */
|
||||
BLI_freelistN(&pose->agroups);
|
||||
BLI_duplicatelist(&pose->agroups, &frompose->agroups);
|
||||
pose->active_group = frompose->active_group;
|
||||
|
||||
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
pchanp = BKE_pose_channel_find_name(frompose, pchan->name);
|
||||
|
||||
if (UNLIKELY(pchanp == NULL)) {
|
||||
/* happens for proxies that become invalid because of a missing link
|
||||
* for regular cases it shouldn't happen at all */
|
||||
}
|
||||
else if (pchan->bone->layer & layer_protected) {
|
||||
ListBase proxylocal_constraints = {NULL, NULL};
|
||||
bPoseChannel pchanw;
|
||||
|
||||
/* copy posechannel to temp, but restore important pointers */
|
||||
pchanw = *pchanp;
|
||||
pchanw.bone = pchan->bone;
|
||||
pchanw.prev = pchan->prev;
|
||||
pchanw.next = pchan->next;
|
||||
pchanw.parent = pchan->parent;
|
||||
pchanw.child = pchan->child;
|
||||
pchanw.custom_tx = pchan->custom_tx;
|
||||
pchanw.bbone_prev = pchan->bbone_prev;
|
||||
pchanw.bbone_next = pchan->bbone_next;
|
||||
|
||||
pchanw.mpath = pchan->mpath;
|
||||
pchan->mpath = NULL;
|
||||
|
||||
/* Reset runtime data, we don't want to share that with the proxy. */
|
||||
BKE_pose_channel_runtime_reset_on_copy(&pchanw.runtime);
|
||||
|
||||
/* this is freed so copy a copy, else undo crashes */
|
||||
if (pchanw.prop) {
|
||||
pchanw.prop = IDP_CopyProperty(pchanw.prop);
|
||||
|
||||
/* use the values from the existing props */
|
||||
if (pchan->prop) {
|
||||
IDP_SyncGroupValues(pchanw.prop, pchan->prop);
|
||||
}
|
||||
}
|
||||
|
||||
/* Constraints - proxy constraints are flushed... local ones are added after
|
||||
* 1: extract constraints not from proxy (CONSTRAINT_PROXY_LOCAL) from pchan's constraints.
|
||||
* 2: copy proxy-pchan's constraints on-to new.
|
||||
* 3: add extracted local constraints back on top.
|
||||
*
|
||||
* Note for BKE_constraints_copy:
|
||||
* When copying constraints, disable 'do_extern' otherwise
|
||||
* we get the libs direct linked in this blend.
|
||||
*/
|
||||
BKE_constraints_proxylocal_extract(&proxylocal_constraints, &pchan->constraints);
|
||||
BKE_constraints_copy(&pchanw.constraints, &pchanp->constraints, false);
|
||||
BLI_movelisttolist(&pchanw.constraints, &proxylocal_constraints);
|
||||
|
||||
/* constraints - set target ob pointer to own object */
|
||||
for (con = pchanw.constraints.first; con; con = con->next) {
|
||||
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
|
||||
ListBase targets = {NULL, NULL};
|
||||
bConstraintTarget *ct;
|
||||
|
||||
if (cti && cti->get_constraint_targets) {
|
||||
cti->get_constraint_targets(con, &targets);
|
||||
|
||||
for (ct = targets.first; ct; ct = ct->next) {
|
||||
if (ct->tar == from) {
|
||||
ct->tar = ob;
|
||||
}
|
||||
}
|
||||
|
||||
if (cti->flush_constraint_targets) {
|
||||
cti->flush_constraint_targets(con, &targets, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* free stuff from current channel */
|
||||
BKE_pose_channel_free(pchan);
|
||||
|
||||
/* copy data in temp back over to the cleaned-out (but still allocated) original channel */
|
||||
*pchan = pchanw;
|
||||
if (pchan->custom) {
|
||||
id_us_plus(&pchan->custom->id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* always copy custom shape */
|
||||
pchan->custom = pchanp->custom;
|
||||
if (pchan->custom) {
|
||||
id_us_plus(&pchan->custom->id);
|
||||
}
|
||||
if (pchanp->custom_tx) {
|
||||
pchan->custom_tx = BKE_pose_channel_find_name(pose, pchanp->custom_tx->name);
|
||||
}
|
||||
|
||||
/* ID-Property Syncing */
|
||||
{
|
||||
IDProperty *prop_orig = pchan->prop;
|
||||
if (pchanp->prop) {
|
||||
pchan->prop = IDP_CopyProperty(pchanp->prop);
|
||||
if (prop_orig) {
|
||||
/* copy existing values across when types match */
|
||||
IDP_SyncGroupValues(pchan->prop, prop_orig);
|
||||
}
|
||||
}
|
||||
else {
|
||||
pchan->prop = NULL;
|
||||
}
|
||||
if (prop_orig) {
|
||||
IDP_FreeProperty(prop_orig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \param r_last_visited_bone_p: The last bone handled by the last call to this function.
|
||||
*/
|
||||
|
@ -2579,16 +2422,6 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_
|
|||
|
||||
// printf("rebuild pose %s, %d bones\n", ob->id.name, counter);
|
||||
|
||||
/* synchronize protected layers with proxy */
|
||||
/* HACK! To preserve 2.7x behavior that you always can pose even locked bones,
|
||||
* do not do any restoration if this is a COW temp copy! */
|
||||
/* Switched back to just NO_MAIN tag, for some reasons (c)
|
||||
* using COW tag was working this morning, but not anymore... */
|
||||
if (ob->proxy != NULL && (ob->id.tag & LIB_TAG_NO_MAIN) == 0) {
|
||||
BKE_object_copy_proxy_drivers(ob, ob->proxy);
|
||||
pose_proxy_sync(ob, ob->proxy, arm->layer_protected);
|
||||
}
|
||||
|
||||
BKE_pose_update_constraint_flags(pose); /* for IK detection for example */
|
||||
|
||||
pose->flag &= ~POSE_RECALC;
|
||||
|
|
|
@ -850,10 +850,6 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph, Scene *UNUSED(scene), Objec
|
|||
}
|
||||
|
||||
BLI_assert(pose->chan_array != NULL || BLI_listbase_is_empty(&pose->chanbase));
|
||||
|
||||
if (object->proxy != NULL) {
|
||||
object->proxy->proxy_from = object;
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph, Scene *scene, Object *object)
|
||||
|
@ -1070,57 +1066,3 @@ void BKE_pose_eval_cleanup(struct Depsgraph *depsgraph, Scene *scene, Object *ob
|
|||
BIK_release_tree(scene, object, ctime);
|
||||
pose_eval_cleanup_common(object);
|
||||
}
|
||||
|
||||
void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph, Object *object)
|
||||
{
|
||||
BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
|
||||
DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
|
||||
|
||||
BLI_assert(object->pose->chan_array != NULL || BLI_listbase_is_empty(&object->pose->chanbase));
|
||||
}
|
||||
|
||||
void BKE_pose_eval_proxy_done(struct Depsgraph *depsgraph, Object *object)
|
||||
{
|
||||
BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
|
||||
DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
|
||||
}
|
||||
|
||||
void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph, Object *object)
|
||||
{
|
||||
BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
|
||||
DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
|
||||
pose_eval_cleanup_common(object);
|
||||
}
|
||||
|
||||
void BKE_pose_eval_proxy_copy_bone(struct Depsgraph *depsgraph, Object *object, int pchan_index)
|
||||
{
|
||||
const bArmature *armature = (bArmature *)object->data;
|
||||
if (armature->edbo != NULL) {
|
||||
return;
|
||||
}
|
||||
BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
|
||||
bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
|
||||
BLI_assert(pchan != NULL);
|
||||
DEG_debug_print_eval_subdata(
|
||||
depsgraph, __func__, object->id.name, object, "pchan", pchan->name, pchan);
|
||||
/* TODO(sergey): Use indexed lookup, once it's guaranteed to be kept
|
||||
* around for the time while proxies are evaluating.
|
||||
*/
|
||||
#if 0
|
||||
bPoseChannel *pchan_from = pose_pchan_get_indexed(object->proxy_from, pchan_index);
|
||||
#else
|
||||
bPoseChannel *pchan_from = BKE_pose_channel_find_name(object->proxy_from->pose, pchan->name);
|
||||
#endif
|
||||
if (pchan_from == NULL) {
|
||||
printf(
|
||||
"WARNING: Could not find bone %s in linked ID anymore... "
|
||||
"You should delete and re-generate your proxy.\n",
|
||||
pchan->name);
|
||||
return;
|
||||
}
|
||||
BKE_pose_copy_pchan_result(pchan, pchan_from);
|
||||
copy_dq_dq(&pchan->runtime.deform_dual_quat, &pchan_from->runtime.deform_dual_quat);
|
||||
BKE_pchan_bbone_segments_cache_copy(pchan, pchan_from);
|
||||
|
||||
pose_channel_flush_to_orig_if_needed(depsgraph, object, pchan);
|
||||
}
|
||||
|
|
|
@ -90,10 +90,10 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
|
|||
}
|
||||
case ID_HA: {
|
||||
Hair *hair = (Hair *)id;
|
||||
info[ATTR_DOMAIN_POINT].customdata = &hair->pdata;
|
||||
info[ATTR_DOMAIN_POINT].length = hair->totpoint;
|
||||
info[ATTR_DOMAIN_CURVE].customdata = &hair->cdata;
|
||||
info[ATTR_DOMAIN_CURVE].length = hair->totcurve;
|
||||
info[ATTR_DOMAIN_POINT].customdata = &hair->geometry.point_data;
|
||||
info[ATTR_DOMAIN_POINT].length = hair->geometry.point_size;
|
||||
info[ATTR_DOMAIN_CURVE].customdata = &hair->geometry.curve_data;
|
||||
info[ATTR_DOMAIN_CURVE].length = hair->geometry.curve_size;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -78,6 +78,23 @@
|
|||
/** \name High Level `.blend` file read/write.
|
||||
* \{ */
|
||||
|
||||
static bool blendfile_or_libraries_versions_atleast(Main *bmain,
|
||||
const short versionfile,
|
||||
const short subversionfile)
|
||||
{
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, versionfile, subversionfile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Library *, library, &bmain->libraries) {
|
||||
if (!MAIN_VERSION_ATLEAST(library, versionfile, subversionfile)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool foreach_path_clean_cb(BPathForeachPathData *UNUSED(bpath_data),
|
||||
char *path_dst,
|
||||
const char *path_src)
|
||||
|
@ -349,10 +366,11 @@ static void setup_app_data(bContext *C,
|
|||
do_versions_ipos_to_animato(bmain);
|
||||
}
|
||||
|
||||
/* FIXME: Same as above, readfile's `do_version` do not allow to create new IDs. */
|
||||
/* TODO: Once this is definitively validated for 3.0 and option to not do it is removed, add a
|
||||
* version bump and check here. */
|
||||
if (mode != LOAD_UNDO && !USER_EXPERIMENTAL_TEST(&U, no_proxy_to_override_conversion)) {
|
||||
/* NOTE: readfile's `do_version` does not allow to create new IDs, and only operates on a single
|
||||
* library at a time. This code needs to operate on the whole Main at once. */
|
||||
/* NOTE: Check bmain version (i.e. current blend file version), AND the versions of all the
|
||||
* linked libraries. */
|
||||
if (mode != LOAD_UNDO && !blendfile_or_libraries_versions_atleast(bmain, 302, 1)) {
|
||||
BKE_lib_override_library_main_proxy_convert(bmain, reports);
|
||||
}
|
||||
|
||||
|
@ -603,12 +621,12 @@ UserDef *BKE_blendfile_userdef_from_defaults(void)
|
|||
const char *addons[] = {
|
||||
"io_anim_bvh",
|
||||
"io_curve_svg",
|
||||
"io_import_obj",
|
||||
"io_mesh_ply",
|
||||
"io_mesh_stl",
|
||||
"io_mesh_uv_layout",
|
||||
"io_scene_fbx",
|
||||
"io_scene_gltf2",
|
||||
"io_scene_obj",
|
||||
"io_scene_x3d",
|
||||
"cycles",
|
||||
"pose_library",
|
||||
|
|
|
@ -993,6 +993,27 @@ static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_d
|
|||
/** \name Library link/append code.
|
||||
* \{ */
|
||||
|
||||
static void blendfile_link_append_proxies_convert(Main *bmain, ReportList *reports)
|
||||
{
|
||||
/* NOTE: Do not bother checking file versions here, if there are no proxies to convert this code
|
||||
* is quite fast anyway. */
|
||||
|
||||
BlendFileReadReport bf_reports = {.reports = reports};
|
||||
BKE_lib_override_library_main_proxy_convert(bmain, &bf_reports);
|
||||
|
||||
if (bf_reports.count.proxies_to_lib_overrides_success != 0 ||
|
||||
bf_reports.count.proxies_to_lib_overrides_failures != 0) {
|
||||
BKE_reportf(
|
||||
bf_reports.reports,
|
||||
RPT_WARNING,
|
||||
"Proxies have been removed from Blender (%d proxies were automatically converted "
|
||||
"to library overrides, %d proxies could not be converted and were cleared). "
|
||||
"Please consider re-saving any library .blend file with the newest Blender version.",
|
||||
bf_reports.count.proxies_to_lib_overrides_success,
|
||||
bf_reports.count.proxies_to_lib_overrides_failures);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
|
||||
{
|
||||
if (lapp_context->num_items == 0) {
|
||||
|
@ -1040,10 +1061,6 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
|
|||
if (item->action != LINK_APPEND_ACT_UNSET) {
|
||||
/* Already set, pass. */
|
||||
}
|
||||
if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) {
|
||||
CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name);
|
||||
item->action = LINK_APPEND_ACT_KEEP_LINKED;
|
||||
}
|
||||
else if (do_reuse_local_id && existing_local_id != NULL) {
|
||||
CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name);
|
||||
item->action = LINK_APPEND_ACT_REUSE_LOCAL;
|
||||
|
@ -1098,10 +1115,7 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
|
|||
local_appended_new_id = id->newid;
|
||||
break;
|
||||
case LINK_APPEND_ACT_MAKE_LOCAL:
|
||||
BKE_lib_id_make_local(bmain,
|
||||
id,
|
||||
make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL |
|
||||
LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
|
||||
BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL);
|
||||
BLI_assert(id->newid == NULL);
|
||||
local_appended_new_id = id;
|
||||
break;
|
||||
|
@ -1210,55 +1224,11 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
|
|||
continue;
|
||||
}
|
||||
BLI_assert(ID_IS_LINKED(id));
|
||||
|
||||
/* Attempt to re-link copied proxy objects. This allows appending of an entire scene
|
||||
* from another blend file into this one, even when that blend file contains proxified
|
||||
* armatures that have local references. Since the proxified object needs to be linked
|
||||
* (not local), this will only work when the "Localize all" checkbox is disabled.
|
||||
* TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
|
||||
if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
|
||||
Object *ob = (Object *)id;
|
||||
Object *ob_new = (Object *)id->newid;
|
||||
bool is_local = false, is_lib = false;
|
||||
|
||||
/* Proxies only work when the proxified object is linked-in from a library. */
|
||||
if (!ID_IS_LINKED(ob->proxy)) {
|
||||
CLOG_WARN(&LOG,
|
||||
"Proxy object %s will lose its link to %s, because the "
|
||||
"proxified object is local",
|
||||
id->newid->name,
|
||||
ob->proxy->id.name);
|
||||
continue;
|
||||
}
|
||||
|
||||
BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
|
||||
|
||||
/* We can only switch the proxy'ing to a made-local proxy if it is no longer
|
||||
* referred to from a library. Not checking for local use; if new local proxy
|
||||
* was not used locally would be a nasty bug! */
|
||||
if (is_local || is_lib) {
|
||||
CLOG_WARN(&LOG,
|
||||
"Made-local proxy object %s will lose its link to %s, "
|
||||
"because the linked-in proxy is referenced (is_local=%i, is_lib=%i)",
|
||||
id->newid->name,
|
||||
ob->proxy->id.name,
|
||||
is_local,
|
||||
is_lib);
|
||||
}
|
||||
else {
|
||||
/* we can switch the proxy'ing from the linked-in to the made-local proxy.
|
||||
* BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
|
||||
* was already allocated by object_make_local() (which called BKE_object_copy). */
|
||||
ob_new->proxy = ob->proxy;
|
||||
ob_new->proxy_group = ob->proxy_group;
|
||||
ob_new->proxy_from = ob->proxy_from;
|
||||
ob_new->proxy->proxy_from = ob_new;
|
||||
ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BKE_main_id_newptr_and_tag_clear(bmain);
|
||||
|
||||
blendfile_link_append_proxies_convert(bmain, reports);
|
||||
}
|
||||
|
||||
void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
|
||||
|
@ -1361,6 +1331,10 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re
|
|||
.active_collection = NULL};
|
||||
loose_data_instantiate(&instantiate_context);
|
||||
}
|
||||
|
||||
if ((lapp_context->params->flag & FILE_LINK) != 0) {
|
||||
blendfile_link_append_proxies_convert(lapp_context->params->bmain, reports);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -1541,7 +1515,6 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
|
|||
|
||||
/* Note that in reload case, we also want to replace indirect usages. */
|
||||
const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
|
||||
ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE |
|
||||
(do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
|
||||
for (item_idx = 0, itemlink = lapp_context->items.list; itemlink;
|
||||
item_idx++, itemlink = itemlink->next) {
|
||||
|
|
|
@ -1094,14 +1094,12 @@ static bool collection_object_remove(Main *bmain,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
|
||||
bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Object *ob)
|
||||
{
|
||||
if (ELEM(NULL, collection, ob)) {
|
||||
if (ob == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
collection = collection_parent_editable_find_recursive(collection);
|
||||
|
||||
/* Only case where this pointer can be NULL is when scene itself is linked, this case should
|
||||
* never be reached. */
|
||||
BLI_assert(collection != NULL);
|
||||
|
@ -1122,6 +1120,17 @@ bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
|
||||
{
|
||||
if (collection == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
collection = collection_parent_editable_find_recursive(collection);
|
||||
|
||||
return BKE_collection_object_add_notest(bmain, collection, ob);
|
||||
}
|
||||
|
||||
void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
|
||||
{
|
||||
bool is_instantiated = false;
|
||||
|
|
|
@ -5850,14 +5850,6 @@ static void add_new_constraint_to_list(Object *ob, bPoseChannel *pchan, bConstra
|
|||
BLI_addtail(list, con);
|
||||
BKE_constraint_unique_name(con, list);
|
||||
|
||||
/* if the target list is a list on some PoseChannel belonging to a proxy-protected
|
||||
* Armature layer, we must tag newly added constraints with a flag which allows them
|
||||
* to persist after proxy syncing has been done
|
||||
*/
|
||||
if (BKE_constraints_proxylocked_owner(ob, pchan)) {
|
||||
con->flag |= CONSTRAINT_PROXY_LOCAL;
|
||||
}
|
||||
|
||||
/* make this constraint the active one */
|
||||
BKE_constraints_active_set(list, con);
|
||||
}
|
||||
|
@ -6213,45 +6205,6 @@ bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstrai
|
|||
(con == NULL || (con->flag & CONSTRAINT_OVERRIDE_LIBRARY_LOCAL) == 0));
|
||||
}
|
||||
|
||||
/* -------- Constraints and Proxies ------- */
|
||||
|
||||
void BKE_constraints_proxylocal_extract(ListBase *dst, ListBase *src)
|
||||
{
|
||||
bConstraint *con, *next;
|
||||
|
||||
/* for each tagged constraint, remove from src and move to dst */
|
||||
for (con = src->first; con; con = next) {
|
||||
next = con->next;
|
||||
|
||||
/* check if tagged */
|
||||
if (con->flag & CONSTRAINT_PROXY_LOCAL) {
|
||||
BLI_remlink(src, con);
|
||||
BLI_addtail(dst, con);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
|
||||
{
|
||||
/* Currently, constraints can only be on object or bone level */
|
||||
if (ob && ob->proxy) {
|
||||
if (ob->pose && pchan) {
|
||||
bArmature *arm = ob->data;
|
||||
|
||||
/* On bone-level, check if bone is on proxy-protected layer */
|
||||
if ((pchan->bone) && (pchan->bone->layer & arm->layer_protected)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* FIXME: constraints on object-level are not handled well yet */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------- Target-Matrix Stuff ------- */
|
||||
|
||||
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
|
||||
|
|
|
@ -899,7 +899,7 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
|
|||
pntsit = points + 3;
|
||||
}
|
||||
|
||||
while (--b) {
|
||||
while (--b > 0) {
|
||||
length += len_v3v3(prevpntsit, pntsit);
|
||||
prevpntsit = pntsit;
|
||||
pntsit += 3;
|
||||
|
|
|
@ -1793,10 +1793,10 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
|||
{sizeof(float[3]), "vec3f", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 44: CD_RADIUS */
|
||||
{sizeof(float), "MFloatProperty", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 45: CD_HAIRCURVE */
|
||||
{sizeof(HairCurve), "HairCurve", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 46: CD_HAIRMAPPING */
|
||||
{sizeof(HairMapping), "HairMapping", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 45: CD_HAIRCURVE */ /* UNUSED */
|
||||
{-1, "", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 46: CD_HAIRMAPPING */ /* UNUSED */
|
||||
{-1, "", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
|
||||
/* 47: CD_PROP_COLOR */
|
||||
{sizeof(MPropCol),
|
||||
"MPropCol",
|
||||
|
@ -2431,7 +2431,7 @@ const char *CustomData_get_active_layer_name(const struct CustomData *data, cons
|
|||
{
|
||||
/* Get the layer index of the active layer of this type. */
|
||||
const int layer_index = CustomData_get_active_layer_index(data, type);
|
||||
return layer_index < 0 ? NULL : data->layers[layer_index].name;
|
||||
return layer_index < 0 ? nullptr : data->layers[layer_index].name;
|
||||
}
|
||||
|
||||
void CustomData_set_layer_active(CustomData *data, int type, int n)
|
||||
|
@ -2780,6 +2780,24 @@ void CustomData_free_layers(CustomData *data, int type, int totelem)
|
|||
}
|
||||
}
|
||||
|
||||
void CustomData_free_layers_anonymous(struct CustomData *data, int totelem)
|
||||
{
|
||||
while (true) {
|
||||
bool found_anonymous_layer = false;
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
const CustomDataLayer *layer = &data->layers[i];
|
||||
if (layer->anonymous_id != nullptr) {
|
||||
CustomData_free_layer(data, layer->type, totelem, i);
|
||||
found_anonymous_layer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found_anonymous_layer) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CustomData_has_layer(const CustomData *data, int type)
|
||||
{
|
||||
return (CustomData_get_layer_index(data, type) != -1);
|
||||
|
|
|
@ -88,14 +88,6 @@ typedef struct DriverVarTypeInfo {
|
|||
/** \name Driver Target Utilities
|
||||
* \{ */
|
||||
|
||||
static ID *dtar_id_ensure_proxy_from(ID *id)
|
||||
{
|
||||
if (id && GS(id->name) == ID_OB && ((Object *)id)->proxy_from) {
|
||||
return (ID *)(((Object *)id)->proxy_from);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to obtain a value using RNA from the specified source
|
||||
* (for evaluating drivers).
|
||||
|
@ -113,7 +105,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
|
|||
return 0.0f;
|
||||
}
|
||||
|
||||
id = dtar_id_ensure_proxy_from(dtar->id);
|
||||
id = dtar->id;
|
||||
|
||||
/* Error check for missing pointer. */
|
||||
if (id == NULL) {
|
||||
|
@ -217,7 +209,7 @@ bool driver_get_variable_property(ChannelDriver *driver,
|
|||
return false;
|
||||
}
|
||||
|
||||
id = dtar_id_ensure_proxy_from(dtar->id);
|
||||
id = dtar->id;
|
||||
|
||||
/* Error check for missing pointer. */
|
||||
if (id == NULL) {
|
||||
|
@ -273,7 +265,7 @@ static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
|
|||
short valid_targets = 0;
|
||||
|
||||
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
|
||||
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
|
||||
Object *ob = (Object *)dtar->id;
|
||||
|
||||
/* Check if this target has valid data. */
|
||||
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
|
||||
|
@ -328,7 +320,7 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
|
|||
for (int i = 0; i < 2; i++) {
|
||||
/* Get pointer to loc values to store in. */
|
||||
DriverTarget *dtar = &dvar->targets[i];
|
||||
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
|
||||
Object *ob = (Object *)dtar->id;
|
||||
bPoseChannel *pchan;
|
||||
|
||||
/* After the checks above, the targets should be valid here. */
|
||||
|
@ -389,7 +381,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
|
|||
/* NOTE: for now, these are all just world-space */
|
||||
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
|
||||
/* Get pointer to loc values to store in. */
|
||||
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
|
||||
Object *ob = (Object *)dtar->id;
|
||||
bPoseChannel *pchan;
|
||||
float tmp_loc[3];
|
||||
|
||||
|
@ -472,7 +464,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
|
|||
static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
||||
{
|
||||
DriverTarget *dtar = &dvar->targets[0];
|
||||
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
|
||||
Object *ob = (Object *)dtar->id;
|
||||
bPoseChannel *pchan;
|
||||
float mat[4][4];
|
||||
float oldEul[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
|
|
@ -28,10 +28,11 @@
|
|||
#include "DNA_material_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_math_vec_types.hh"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_rand.hh"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
|
@ -54,6 +55,9 @@
|
|||
#include "BLO_read_write.h"
|
||||
|
||||
using blender::float3;
|
||||
using blender::IndexRange;
|
||||
using blender::MutableSpan;
|
||||
using blender::RandomNumberGenerator;
|
||||
|
||||
static const char *HAIR_ATTR_POSITION = "position";
|
||||
static const char *HAIR_ATTR_RADIUS = "radius";
|
||||
|
@ -69,14 +73,22 @@ static void hair_init_data(ID *id)
|
|||
|
||||
MEMCPY_STRUCT_AFTER(hair, DNA_struct_default_get(Hair), id);
|
||||
|
||||
CustomData_reset(&hair->pdata);
|
||||
CustomData_reset(&hair->cdata);
|
||||
CustomData_reset(&hair->geometry.point_data);
|
||||
CustomData_reset(&hair->geometry.curve_data);
|
||||
|
||||
CustomData_add_layer_named(&hair->geometry.point_data,
|
||||
CD_PROP_FLOAT3,
|
||||
CD_CALLOC,
|
||||
nullptr,
|
||||
hair->geometry.point_size,
|
||||
HAIR_ATTR_POSITION);
|
||||
CustomData_add_layer_named(&hair->geometry.point_data,
|
||||
CD_PROP_FLOAT,
|
||||
CD_CALLOC,
|
||||
nullptr,
|
||||
hair->geometry.point_size,
|
||||
HAIR_ATTR_RADIUS);
|
||||
|
||||
CustomData_add_layer_named(
|
||||
&hair->pdata, CD_PROP_FLOAT3, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_POSITION);
|
||||
CustomData_add_layer_named(
|
||||
&hair->pdata, CD_PROP_FLOAT, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_RADIUS);
|
||||
CustomData_add_layer(&hair->cdata, CD_HAIRCURVE, CD_CALLOC, nullptr, hair->totcurve);
|
||||
BKE_hair_update_customdata_pointers(hair);
|
||||
|
||||
hair_random(hair);
|
||||
|
@ -88,11 +100,24 @@ static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, co
|
|||
const Hair *hair_src = (const Hair *)id_src;
|
||||
hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat));
|
||||
|
||||
hair_dst->geometry.point_size = hair_src->geometry.point_size;
|
||||
hair_dst->geometry.curve_size = hair_src->geometry.curve_size;
|
||||
|
||||
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
|
||||
CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, alloc_type, hair_dst->totpoint);
|
||||
CustomData_copy(&hair_src->cdata, &hair_dst->cdata, CD_MASK_ALL, alloc_type, hair_dst->totcurve);
|
||||
CustomData_copy(&hair_src->geometry.point_data,
|
||||
&hair_dst->geometry.point_data,
|
||||
CD_MASK_ALL,
|
||||
alloc_type,
|
||||
hair_dst->geometry.point_size);
|
||||
CustomData_copy(&hair_src->geometry.curve_data,
|
||||
&hair_dst->geometry.curve_data,
|
||||
CD_MASK_ALL,
|
||||
alloc_type,
|
||||
hair_dst->geometry.curve_size);
|
||||
BKE_hair_update_customdata_pointers(hair_dst);
|
||||
|
||||
hair_dst->geometry.offsets = static_cast<int *>(MEM_dupallocN(hair_src->geometry.offsets));
|
||||
|
||||
hair_dst->batch_cache = nullptr;
|
||||
}
|
||||
|
||||
|
@ -103,8 +128,10 @@ static void hair_free_data(ID *id)
|
|||
|
||||
BKE_hair_batch_cache_free(hair);
|
||||
|
||||
CustomData_free(&hair->pdata, hair->totpoint);
|
||||
CustomData_free(&hair->cdata, hair->totcurve);
|
||||
CustomData_free(&hair->geometry.point_data, hair->geometry.point_size);
|
||||
CustomData_free(&hair->geometry.curve_data, hair->geometry.curve_size);
|
||||
|
||||
MEM_SAFE_FREE(hair->geometry.offsets);
|
||||
|
||||
MEM_SAFE_FREE(hair->mat);
|
||||
}
|
||||
|
@ -123,16 +150,30 @@ static void hair_blend_write(BlendWriter *writer, ID *id, const void *id_address
|
|||
|
||||
CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE];
|
||||
CustomDataLayer *clayers = nullptr, clayers_buff[CD_TEMP_CHUNK_SIZE];
|
||||
CustomData_blend_write_prepare(&hair->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
|
||||
CustomData_blend_write_prepare(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff));
|
||||
CustomData_blend_write_prepare(
|
||||
&hair->geometry.point_data, &players, players_buff, ARRAY_SIZE(players_buff));
|
||||
CustomData_blend_write_prepare(
|
||||
&hair->geometry.curve_data, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff));
|
||||
|
||||
/* Write LibData */
|
||||
BLO_write_id_struct(writer, Hair, id_address, &hair->id);
|
||||
BKE_id_blend_write(writer, &hair->id);
|
||||
|
||||
/* Direct data */
|
||||
CustomData_blend_write(writer, &hair->pdata, players, hair->totpoint, CD_MASK_ALL, &hair->id);
|
||||
CustomData_blend_write(writer, &hair->cdata, clayers, hair->totcurve, CD_MASK_ALL, &hair->id);
|
||||
CustomData_blend_write(writer,
|
||||
&hair->geometry.point_data,
|
||||
players,
|
||||
hair->geometry.point_size,
|
||||
CD_MASK_ALL,
|
||||
&hair->id);
|
||||
CustomData_blend_write(writer,
|
||||
&hair->geometry.curve_data,
|
||||
clayers,
|
||||
hair->geometry.curve_size,
|
||||
CD_MASK_ALL,
|
||||
&hair->id);
|
||||
|
||||
BLO_write_int32_array(writer, hair->geometry.curve_size + 1, hair->geometry.offsets);
|
||||
|
||||
BLO_write_pointer_array(writer, hair->totcol, hair->mat);
|
||||
if (hair->adt) {
|
||||
|
@ -155,10 +196,12 @@ static void hair_blend_read_data(BlendDataReader *reader, ID *id)
|
|||
BKE_animdata_blend_read_data(reader, hair->adt);
|
||||
|
||||
/* Geometry */
|
||||
CustomData_blend_read(reader, &hair->pdata, hair->totpoint);
|
||||
CustomData_blend_read(reader, &hair->cdata, hair->totcurve);
|
||||
CustomData_blend_read(reader, &hair->geometry.point_data, hair->geometry.point_size);
|
||||
CustomData_blend_read(reader, &hair->geometry.curve_data, hair->geometry.point_size);
|
||||
BKE_hair_update_customdata_pointers(hair);
|
||||
|
||||
BLO_read_int32_array(reader, hair->geometry.curve_size + 1, &hair->geometry.offsets);
|
||||
|
||||
/* Materials */
|
||||
BLO_read_pointer_array(reader, (void **)&hair->mat);
|
||||
}
|
||||
|
@ -211,47 +254,51 @@ IDTypeInfo IDType_ID_HA = {
|
|||
|
||||
static void hair_random(Hair *hair)
|
||||
{
|
||||
CurvesGeometry &geometry = hair->geometry;
|
||||
const int numpoints = 8;
|
||||
|
||||
hair->totcurve = 500;
|
||||
hair->totpoint = hair->totcurve * numpoints;
|
||||
geometry.curve_size = 500;
|
||||
|
||||
CustomData_realloc(&hair->pdata, hair->totpoint);
|
||||
CustomData_realloc(&hair->cdata, hair->totcurve);
|
||||
geometry.curve_size = 500;
|
||||
geometry.point_size = geometry.curve_size * numpoints;
|
||||
|
||||
hair->geometry.offsets = (int *)MEM_calloc_arrayN(
|
||||
hair->geometry.curve_size + 1, sizeof(int), __func__);
|
||||
CustomData_realloc(&geometry.point_data, geometry.point_size);
|
||||
CustomData_realloc(&geometry.curve_data, geometry.curve_size);
|
||||
BKE_hair_update_customdata_pointers(hair);
|
||||
|
||||
RNG *rng = BLI_rng_new(0);
|
||||
MutableSpan<int> offsets{geometry.offsets, geometry.curve_size + 1};
|
||||
MutableSpan<float3> positions{(float3 *)geometry.position, geometry.point_size};
|
||||
MutableSpan<float> radii{geometry.radius, geometry.point_size};
|
||||
|
||||
for (int i = 0; i < hair->totcurve; i++) {
|
||||
HairCurve *curve = &hair->curves[i];
|
||||
curve->firstpoint = i * numpoints;
|
||||
curve->numpoints = numpoints;
|
||||
|
||||
float theta = 2.0f * M_PI * BLI_rng_get_float(rng);
|
||||
float phi = saacosf(2.0f * BLI_rng_get_float(rng) - 1.0f);
|
||||
|
||||
float no[3] = {sinf(theta) * sinf(phi), cosf(theta) * sinf(phi), cosf(phi)};
|
||||
normalize_v3(no);
|
||||
|
||||
float co[3];
|
||||
copy_v3_v3(co, no);
|
||||
|
||||
float(*curve_co)[3] = hair->co + curve->firstpoint;
|
||||
float *curve_radius = hair->radius + curve->firstpoint;
|
||||
for (int key = 0; key < numpoints; key++) {
|
||||
float t = key / (float)(numpoints - 1);
|
||||
copy_v3_v3(curve_co[key], co);
|
||||
curve_radius[key] = 0.02f * (1.0f - t);
|
||||
|
||||
float offset[3] = {2.0f * BLI_rng_get_float(rng) - 1.0f,
|
||||
2.0f * BLI_rng_get_float(rng) - 1.0f,
|
||||
2.0f * BLI_rng_get_float(rng) - 1.0f};
|
||||
add_v3_v3(offset, no);
|
||||
madd_v3_v3fl(co, offset, 1.0f / numpoints);
|
||||
}
|
||||
for (const int i : offsets.index_range()) {
|
||||
geometry.offsets[i] = numpoints * i;
|
||||
}
|
||||
|
||||
BLI_rng_free(rng);
|
||||
RandomNumberGenerator rng;
|
||||
|
||||
for (int i = 0; i < geometry.curve_size; i++) {
|
||||
const IndexRange curve_range(offsets[i], offsets[i + 1] - offsets[i]);
|
||||
MutableSpan<float3> curve_positions = positions.slice(curve_range);
|
||||
MutableSpan<float> curve_radii = radii.slice(curve_range);
|
||||
|
||||
const float theta = 2.0f * M_PI * rng.get_float();
|
||||
const float phi = saacosf(2.0f * rng.get_float() - 1.0f);
|
||||
|
||||
float3 no = {std::sin(theta) * std::sin(phi), std::cos(theta) * std::sin(phi), std::cos(phi)};
|
||||
no = blender::math::normalize(no);
|
||||
|
||||
float3 co = no;
|
||||
for (int key = 0; key < numpoints; key++) {
|
||||
float t = key / (float)(numpoints - 1);
|
||||
curve_positions[key] = co;
|
||||
curve_radii[key] = 0.02f * (1.0f - t);
|
||||
|
||||
float3 offset = float3(rng.get_float(), rng.get_float(), rng.get_float()) * 2.0f - 1.0f;
|
||||
co += (offset + no) / numpoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *BKE_hair_add(Main *bmain, const char *name)
|
||||
|
@ -276,9 +323,9 @@ BoundBox *BKE_hair_boundbox_get(Object *ob)
|
|||
float min[3], max[3];
|
||||
INIT_MINMAX(min, max);
|
||||
|
||||
float(*hair_co)[3] = hair->co;
|
||||
float *hair_radius = hair->radius;
|
||||
for (int a = 0; a < hair->totpoint; a++) {
|
||||
float(*hair_co)[3] = hair->geometry.position;
|
||||
float *hair_radius = hair->geometry.radius;
|
||||
for (int a = 0; a < hair->geometry.point_size; a++) {
|
||||
float *co = hair_co[a];
|
||||
float radius = (hair_radius) ? hair_radius[a] : 0.0f;
|
||||
const float co_min[3] = {co[0] - radius, co[1] - radius, co[2] - radius};
|
||||
|
@ -295,12 +342,10 @@ BoundBox *BKE_hair_boundbox_get(Object *ob)
|
|||
|
||||
void BKE_hair_update_customdata_pointers(Hair *hair)
|
||||
{
|
||||
hair->co = (float(*)[3])CustomData_get_layer_named(
|
||||
&hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION);
|
||||
hair->radius = (float *)CustomData_get_layer_named(
|
||||
&hair->pdata, CD_PROP_FLOAT, HAIR_ATTR_RADIUS);
|
||||
hair->curves = (HairCurve *)CustomData_get_layer(&hair->cdata, CD_HAIRCURVE);
|
||||
hair->mapping = (HairMaping *)CustomData_get_layer(&hair->cdata, CD_HAIRMAPPING);
|
||||
hair->geometry.position = (float(*)[3])CustomData_get_layer_named(
|
||||
&hair->geometry.point_data, CD_PROP_FLOAT3, HAIR_ATTR_POSITION);
|
||||
hair->geometry.radius = (float *)CustomData_get_layer_named(
|
||||
&hair->geometry.point_data, CD_PROP_FLOAT, HAIR_ATTR_RADIUS);
|
||||
}
|
||||
|
||||
bool BKE_hair_customdata_required(Hair *UNUSED(hair), CustomDataLayer *layer)
|
||||
|
@ -318,10 +363,18 @@ Hair *BKE_hair_new_for_eval(const Hair *hair_src, int totpoint, int totcurve)
|
|||
hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat));
|
||||
hair_dst->totcol = hair_src->totcol;
|
||||
|
||||
hair_dst->totpoint = totpoint;
|
||||
hair_dst->totcurve = totcurve;
|
||||
CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, CD_CALLOC, totpoint);
|
||||
CustomData_copy(&hair_src->cdata, &hair_dst->cdata, CD_MASK_ALL, CD_CALLOC, totcurve);
|
||||
hair_dst->geometry.point_size = totpoint;
|
||||
hair_dst->geometry.curve_size = totcurve;
|
||||
CustomData_copy(&hair_src->geometry.point_data,
|
||||
&hair_dst->geometry.point_data,
|
||||
CD_MASK_ALL,
|
||||
CD_CALLOC,
|
||||
totpoint);
|
||||
CustomData_copy(&hair_src->geometry.curve_data,
|
||||
&hair_dst->geometry.curve_data,
|
||||
CD_MASK_ALL,
|
||||
CD_CALLOC,
|
||||
totcurve);
|
||||
BKE_hair_update_customdata_pointers(hair_dst);
|
||||
|
||||
return hair_dst;
|
||||
|
@ -373,12 +426,14 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
|
|||
}
|
||||
|
||||
/* Ensure we are not overwriting referenced data. */
|
||||
CustomData_duplicate_referenced_layer_named(
|
||||
&hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION, hair->totpoint);
|
||||
CustomData_duplicate_referenced_layer_named(&hair->geometry.point_data,
|
||||
CD_PROP_FLOAT3,
|
||||
HAIR_ATTR_POSITION,
|
||||
hair->geometry.point_size);
|
||||
BKE_hair_update_customdata_pointers(hair);
|
||||
|
||||
/* Created deformed coordinates array on demand. */
|
||||
mti->deformVerts(md, &mectx, nullptr, hair->co, hair->totpoint);
|
||||
mti->deformVerts(md, &mectx, nullptr, hair->geometry.position, hair->geometry.point_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -273,7 +273,8 @@ struct TileChangeset {
|
|||
const int previous_chunk_len = chunk_dirty_flags_.size();
|
||||
|
||||
chunk_dirty_flags_.resize(chunk_len);
|
||||
/* Fast exit. When the changeset was already empty no need to re-init the chunk_validity. */
|
||||
/* Fast exit. When the changeset was already empty no need to
|
||||
* re-initialize the chunk_validity. */
|
||||
if (!has_dirty_chunks()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1918,7 +1918,6 @@ void BKE_library_make_local(Main *bmain,
|
|||
* but complicates slightly the pre-processing of relations between IDs at step 2... */
|
||||
else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
|
||||
ELEM(lib, NULL, id->lib) &&
|
||||
!(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) &&
|
||||
((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING))) {
|
||||
BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem);
|
||||
id->tag |= LIB_TAG_DOIT;
|
||||
|
@ -1982,12 +1981,8 @@ void BKE_library_make_local(Main *bmain,
|
|||
}
|
||||
}
|
||||
else {
|
||||
/* In this specific case, we do want to make ID local even if it has no local usage yet...
|
||||
* Note that for objects, we don't want proxy pointers to be cleared yet. This will happen
|
||||
* down the road in this function.
|
||||
*/
|
||||
BKE_lib_id_make_local(
|
||||
bmain, id, LIB_ID_MAKELOCAL_FULL_LIBRARY | LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING);
|
||||
/* In this specific case, we do want to make ID local even if it has no local usage yet... */
|
||||
BKE_lib_id_make_local(bmain, id, LIB_ID_MAKELOCAL_FULL_LIBRARY);
|
||||
|
||||
if (id->newid) {
|
||||
if (GS(id->newid->name) == ID_OB) {
|
||||
|
@ -2049,62 +2044,6 @@ void BKE_library_make_local(Main *bmain,
|
|||
TIMEIT_VALUE_PRINT(make_local);
|
||||
#endif
|
||||
|
||||
/* Step 5: proxy 'remapping' hack. */
|
||||
for (LinkNode *it = copied_ids; it; it = it->next) {
|
||||
ID *id = it->link;
|
||||
|
||||
/* Attempt to re-link copied proxy objects. This allows appending of an entire scene
|
||||
* from another blend file into this one, even when that blend file contains proxified
|
||||
* armatures that have local references. Since the proxified object needs to be linked
|
||||
* (not local), this will only work when the "Localize all" checkbox is disabled.
|
||||
* TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
|
||||
if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
|
||||
Object *ob = (Object *)id;
|
||||
Object *ob_new = (Object *)id->newid;
|
||||
bool is_local = false, is_lib = false;
|
||||
|
||||
/* Proxies only work when the proxified object is linked-in from a library. */
|
||||
if (!ID_IS_LINKED(ob->proxy)) {
|
||||
CLOG_WARN(&LOG,
|
||||
"proxy object %s will lose its link to %s, because the "
|
||||
"proxified object is local.",
|
||||
id->newid->name,
|
||||
ob->proxy->id.name);
|
||||
continue;
|
||||
}
|
||||
|
||||
BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
|
||||
|
||||
/* We can only switch the proxy'ing to a made-local proxy if it is no longer
|
||||
* referred to from a library. Not checking for local use; if new local proxy
|
||||
* was not used locally would be a nasty bug! */
|
||||
if (is_local || is_lib) {
|
||||
CLOG_WARN(&LOG,
|
||||
"made-local proxy object %s will lose its link to %s, "
|
||||
"because the linked-in proxy is referenced (is_local=%i, is_lib=%i).",
|
||||
id->newid->name,
|
||||
ob->proxy->id.name,
|
||||
is_local,
|
||||
is_lib);
|
||||
}
|
||||
else {
|
||||
/* we can switch the proxy'ing from the linked-in to the made-local proxy.
|
||||
* BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
|
||||
* was already allocated by object_make_local() (which called BKE_object_copy). */
|
||||
ob_new->proxy = ob->proxy;
|
||||
ob_new->proxy_group = ob->proxy_group;
|
||||
ob_new->proxy_from = ob->proxy_from;
|
||||
ob_new->proxy->proxy_from = ob_new;
|
||||
ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TIME
|
||||
printf("Step 5: Proxy 'remapping' hack: Done.\n");
|
||||
TIMEIT_VALUE_PRINT(make_local);
|
||||
#endif
|
||||
|
||||
/* This is probably more of a hack than something we should do here, but...
|
||||
* Issue is, the whole copying + remapping done in complex cases above may leave pose-channels
|
||||
* of armatures in complete invalid state (more precisely, the bone pointers of the
|
||||
|
|
|
@ -265,8 +265,8 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
|
|||
}
|
||||
for (id = last_remapped_id->next; id; id = id->next) {
|
||||
/* Will tag 'never NULL' users of this ID too.
|
||||
* Note that we cannot use BKE_libblock_unlink() here,
|
||||
* since it would ignore indirect (and proxy!)
|
||||
*
|
||||
* NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect
|
||||
* links, this can lead to nasty crashing here in second, actual deleting loop.
|
||||
* Also, this will also flag users of deleted data that cannot be unlinked
|
||||
* (object using deleted obdata, etc.), so that they also get deleted. */
|
||||
|
@ -315,9 +315,9 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
|
|||
}
|
||||
|
||||
/* Will tag 'never NULL' users of this ID too.
|
||||
* Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect
|
||||
* (and proxy!) links, this can lead to nasty crashing here in second,
|
||||
* actual deleting loop.
|
||||
*
|
||||
* NOTE: #BKE_libblock_unlink() cannot be used here, since it would ignore indirect
|
||||
* links, this can lead to nasty crashing here in second, actual deleting loop.
|
||||
* Also, this will also flag users of deleted data that cannot be unlinked
|
||||
* (object using deleted obdata, etc.), so that they also get deleted. */
|
||||
BKE_libblock_remap_multiple_locked(bmain,
|
||||
|
|
|
@ -211,6 +211,7 @@ void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bo
|
|||
}
|
||||
|
||||
static ID *lib_override_library_create_from(Main *bmain,
|
||||
Library *owner_library,
|
||||
ID *reference_id,
|
||||
const int lib_id_copy_flags)
|
||||
{
|
||||
|
@ -227,6 +228,12 @@ static ID *lib_override_library_create_from(Main *bmain,
|
|||
}
|
||||
id_us_min(local_id);
|
||||
|
||||
/* TODO: Handle this properly in LIB_NO_MAIN case as well (i.e. resync case). Or offload to
|
||||
* generic ID copy code? */
|
||||
if ((lib_id_copy_flags & LIB_ID_CREATE_NO_MAIN) == 0) {
|
||||
local_id->lib = owner_library;
|
||||
}
|
||||
|
||||
BKE_lib_override_library_init(local_id, reference_id);
|
||||
|
||||
/* NOTE: From liboverride perspective (and RNA one), shape keys are considered as local embedded
|
||||
|
@ -281,7 +288,7 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
|
|||
BLI_assert(reference_id != NULL);
|
||||
BLI_assert(ID_IS_LINKED(reference_id));
|
||||
|
||||
ID *local_id = lib_override_library_create_from(bmain, reference_id, 0);
|
||||
ID *local_id = lib_override_library_create_from(bmain, NULL, reference_id, 0);
|
||||
/* We cannot allow automatic hierarchy resync on this ID, it is highly likely to generate a giant
|
||||
* mess in case there are a lot of hidden, non-instantiated, non-properly organized dependencies.
|
||||
* Ref T94650. */
|
||||
|
@ -320,6 +327,7 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
|
|||
}
|
||||
|
||||
bool BKE_lib_override_library_create_from_tag(Main *bmain,
|
||||
Library *owner_library,
|
||||
const Library *reference_library,
|
||||
const bool do_no_main)
|
||||
{
|
||||
|
@ -351,7 +359,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
|
|||
* This requires extra care further down the resync process,
|
||||
* see: #BKE_lib_override_library_resync. */
|
||||
reference_id->newid = lib_override_library_create_from(
|
||||
bmain, reference_id, do_no_main ? LIB_ID_CREATE_NO_MAIN : 0);
|
||||
bmain, owner_library, reference_id, do_no_main ? LIB_ID_CREATE_NO_MAIN : 0);
|
||||
if (reference_id->newid == NULL) {
|
||||
success = false;
|
||||
break;
|
||||
|
@ -616,6 +624,35 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
|
|||
}
|
||||
}
|
||||
|
||||
static bool lib_override_linked_group_tag_collections_keep_tagged_check_recursive(
|
||||
LibOverrideGroupTagData *data, Collection *collection)
|
||||
{
|
||||
/* NOTE: Collection's object cache (using bases, as returned by #BKE_collection_object_cache_get)
|
||||
* is not usable here, as it may have become invalid from some previous operation and it should
|
||||
* not be updated here. So instead only use collections' reliable 'raw' data to check if some
|
||||
* object in the hierarchy of the given collection is still tagged for override. */
|
||||
for (CollectionObject *collection_object = collection->gobject.first; collection_object != NULL;
|
||||
collection_object = collection_object->next) {
|
||||
Object *object = collection_object->ob;
|
||||
if (object == NULL) {
|
||||
continue;
|
||||
}
|
||||
if ((object->id.tag & data->tag) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (CollectionChild *collection_child = collection->children.first; collection_child != NULL;
|
||||
collection_child = collection_child->next) {
|
||||
if (lib_override_linked_group_tag_collections_keep_tagged_check_recursive(
|
||||
data, collection_child->collection)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGroupTagData *data)
|
||||
{
|
||||
Main *bmain = data->bmain;
|
||||
|
@ -638,15 +675,8 @@ static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGr
|
|||
if ((collection->id.tag & data->tag) == 0) {
|
||||
continue;
|
||||
}
|
||||
bool keep_tagged = false;
|
||||
const ListBase object_bases = BKE_collection_object_cache_get(collection);
|
||||
LISTBASE_FOREACH (Base *, base, &object_bases) {
|
||||
if ((base->object->id.tag & data->tag) != 0) {
|
||||
keep_tagged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!keep_tagged) {
|
||||
|
||||
if (!lib_override_linked_group_tag_collections_keep_tagged_check_recursive(data, collection)) {
|
||||
collection->id.tag &= ~data->tag;
|
||||
}
|
||||
}
|
||||
|
@ -813,7 +843,10 @@ static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data)
|
|||
lib_override_overrides_group_tag_recursive(data);
|
||||
}
|
||||
|
||||
static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_root)
|
||||
static bool lib_override_library_create_do(Main *bmain,
|
||||
Scene *scene,
|
||||
Library *owner_library,
|
||||
ID *id_root)
|
||||
{
|
||||
BKE_main_relations_create(bmain, 0);
|
||||
LibOverrideGroupTagData data = {.bmain = bmain,
|
||||
|
@ -832,12 +865,13 @@ static bool lib_override_library_create_do(Main *bmain, Scene *scene, ID *id_roo
|
|||
BKE_main_relations_free(bmain);
|
||||
lib_override_group_tag_data_clear(&data);
|
||||
|
||||
return BKE_lib_override_library_create_from_tag(bmain, id_root->lib, false);
|
||||
return BKE_lib_override_library_create_from_tag(bmain, owner_library, id_root->lib, false);
|
||||
}
|
||||
|
||||
static void lib_override_library_create_post_process(Main *bmain,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
const Library *owner_library,
|
||||
ID *id_root,
|
||||
ID *id_reference,
|
||||
Collection *residual_storage,
|
||||
|
@ -859,7 +893,8 @@ static void lib_override_library_create_post_process(Main *bmain,
|
|||
|
||||
/* Instantiating the root collection or object should never be needed in resync case, since the
|
||||
* old override would be remapped to the new one. */
|
||||
if (!is_resync && id_root != NULL && id_root->newid != NULL && !ID_IS_LINKED(id_root->newid)) {
|
||||
if (!is_resync && id_root != NULL && id_root->newid != NULL &&
|
||||
(!ID_IS_LINKED(id_root->newid) || id_root->newid->lib == owner_library)) {
|
||||
switch (GS(id_root->name)) {
|
||||
case ID_GR: {
|
||||
Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ?
|
||||
|
@ -904,7 +939,7 @@ static void lib_override_library_create_post_process(Main *bmain,
|
|||
Collection *default_instantiating_collection = residual_storage;
|
||||
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
|
||||
Object *ob_new = (Object *)ob->id.newid;
|
||||
if (ob_new == NULL || ID_IS_LINKED(ob_new)) {
|
||||
if (ob_new == NULL || (ID_IS_LINKED(ob_new) && ob_new->id.lib != owner_library)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -967,6 +1002,7 @@ static void lib_override_library_create_post_process(Main *bmain,
|
|||
bool BKE_lib_override_library_create(Main *bmain,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
Library *owner_library,
|
||||
ID *id_root,
|
||||
ID *id_reference,
|
||||
ID **r_id_root_override)
|
||||
|
@ -975,7 +1011,7 @@ bool BKE_lib_override_library_create(Main *bmain,
|
|||
*r_id_root_override = NULL;
|
||||
}
|
||||
|
||||
const bool success = lib_override_library_create_do(bmain, scene, id_root);
|
||||
const bool success = lib_override_library_create_do(bmain, scene, owner_library, id_root);
|
||||
|
||||
if (!success) {
|
||||
return success;
|
||||
|
@ -986,7 +1022,7 @@ bool BKE_lib_override_library_create(Main *bmain,
|
|||
}
|
||||
|
||||
lib_override_library_create_post_process(
|
||||
bmain, scene, view_layer, id_root, id_reference, NULL, false);
|
||||
bmain, scene, view_layer, owner_library, id_root, id_reference, NULL, false);
|
||||
|
||||
/* Cleanup. */
|
||||
BKE_main_id_newptr_and_tag_clear(bmain);
|
||||
|
@ -1011,116 +1047,6 @@ bool BKE_lib_override_library_template_create(struct ID *id)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BKE_lib_override_library_proxy_convert(Main *bmain,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
Object *ob_proxy)
|
||||
{
|
||||
/* `proxy_group`, if defined, is the empty instantiating the collection from which the proxy is
|
||||
* coming. */
|
||||
Object *ob_proxy_group = ob_proxy->proxy_group;
|
||||
const bool is_override_instancing_object = ob_proxy_group != NULL;
|
||||
ID *id_root = is_override_instancing_object ? &ob_proxy_group->instance_collection->id :
|
||||
&ob_proxy->proxy->id;
|
||||
ID *id_reference = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id;
|
||||
|
||||
/* In some cases the instance collection of a proxy object may be local (see e.g. T83875). Not
|
||||
* sure this is a valid state, but for now just abort the overriding process. */
|
||||
if (!ID_IS_OVERRIDABLE_LIBRARY(id_root)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We manually convert the proxy object into a library override, further override handling will
|
||||
* then be handled by `BKE_lib_override_library_create()` just as for a regular override
|
||||
* creation.
|
||||
*/
|
||||
ob_proxy->proxy->id.tag |= LIB_TAG_DOIT;
|
||||
ob_proxy->proxy->id.newid = &ob_proxy->id;
|
||||
BKE_lib_override_library_init(&ob_proxy->id, &ob_proxy->proxy->id);
|
||||
|
||||
ob_proxy->proxy->proxy_from = NULL;
|
||||
ob_proxy->proxy = ob_proxy->proxy_group = NULL;
|
||||
|
||||
DEG_id_tag_update(&ob_proxy->id, ID_RECALC_COPY_ON_WRITE);
|
||||
|
||||
/* In case of proxy conversion, remap all local ID usages to linked IDs to their newly created
|
||||
* overrides.
|
||||
* While this might not be 100% the desired behavior, it is likely to be the case most of the
|
||||
* time. Ref: T91711. */
|
||||
ID *id_iter;
|
||||
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
|
||||
if (!ID_IS_LINKED(id_iter)) {
|
||||
id_iter->tag |= LIB_TAG_DOIT;
|
||||
}
|
||||
}
|
||||
FOREACH_MAIN_ID_END;
|
||||
|
||||
return BKE_lib_override_library_create(bmain, scene, view_layer, id_root, id_reference, NULL);
|
||||
}
|
||||
|
||||
static void lib_override_library_proxy_convert_do(Main *bmain,
|
||||
Scene *scene,
|
||||
Object *ob_proxy,
|
||||
BlendFileReadReport *reports)
|
||||
{
|
||||
Object *ob_proxy_group = ob_proxy->proxy_group;
|
||||
const bool is_override_instancing_object = ob_proxy_group != NULL;
|
||||
|
||||
const bool success = BKE_lib_override_library_proxy_convert(bmain, scene, NULL, ob_proxy);
|
||||
|
||||
if (success) {
|
||||
CLOG_INFO(&LOG,
|
||||
4,
|
||||
"Proxy object '%s' successfully converted to library overrides",
|
||||
ob_proxy->id.name);
|
||||
/* Remove the instance empty from this scene, the items now have an overridden collection
|
||||
* instead. */
|
||||
if (is_override_instancing_object) {
|
||||
BKE_scene_collections_object_remove(bmain, scene, ob_proxy_group, true);
|
||||
}
|
||||
reports->count.proxies_to_lib_overrides_success++;
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadReport *reports)
|
||||
{
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
FOREACH_SCENE_OBJECT_BEGIN (scene, object) {
|
||||
if (object->proxy_group == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lib_override_library_proxy_convert_do(bmain, scene, object, reports);
|
||||
}
|
||||
FOREACH_SCENE_OBJECT_END;
|
||||
|
||||
FOREACH_SCENE_OBJECT_BEGIN (scene, object) {
|
||||
if (object->proxy == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lib_override_library_proxy_convert_do(bmain, scene, object, reports);
|
||||
}
|
||||
FOREACH_SCENE_OBJECT_END;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Object *, object, &bmain->objects) {
|
||||
if (ID_IS_LINKED(object)) {
|
||||
if (object->proxy != NULL) {
|
||||
CLOG_WARN(&LOG, "Did not try to convert linked proxy object '%s'", object->id.name);
|
||||
reports->count.linked_proxies++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (object->proxy_group != NULL || object->proxy != NULL) {
|
||||
CLOG_WARN(
|
||||
&LOG, "Proxy object '%s' failed to be converted to library override", object->id.name);
|
||||
reports->count.proxies_to_lib_overrides_failures++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void lib_override_library_remap(Main *bmain,
|
||||
const ID *id_root_reference,
|
||||
GHash *linkedref_to_old_override)
|
||||
|
@ -1288,7 +1214,7 @@ static bool lib_override_library_resync(Main *bmain,
|
|||
* override IDs (including within the old overrides themselves, since those are tagged too
|
||||
* above). */
|
||||
const bool success = BKE_lib_override_library_create_from_tag(
|
||||
bmain, id_root_reference->lib, true);
|
||||
bmain, NULL, id_root_reference->lib, true);
|
||||
|
||||
if (!success) {
|
||||
return success;
|
||||
|
@ -1502,6 +1428,7 @@ static bool lib_override_library_resync(Main *bmain,
|
|||
lib_override_library_create_post_process(bmain,
|
||||
scene,
|
||||
view_layer,
|
||||
NULL,
|
||||
id_root_reference,
|
||||
id_root,
|
||||
override_resync_residual_storage,
|
||||
|
@ -1926,7 +1853,7 @@ void BKE_lib_override_library_main_resync(Main *bmain,
|
|||
|
||||
/* Essentially ensures that potentially new overrides of new objects will be instantiated. */
|
||||
lib_override_library_create_post_process(
|
||||
bmain, scene, view_layer, NULL, NULL, override_resync_residual_storage, true);
|
||||
bmain, scene, view_layer, NULL, NULL, NULL, override_resync_residual_storage, true);
|
||||
|
||||
if (BKE_collection_is_empty(override_resync_residual_storage)) {
|
||||
BKE_collection_delete(bmain, override_resync_residual_storage, true);
|
||||
|
@ -2979,10 +2906,6 @@ void BKE_lib_override_library_main_update(Main *bmain)
|
|||
|
||||
bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id)
|
||||
{
|
||||
if (!(ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY(id))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The only strong known case currently are objects used by override collections. */
|
||||
/* TODO: There are most likely other cases... This may need to be addressed in a better way at
|
||||
* some point. */
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 by Blender Foundation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_linklist.h"
|
||||
|
||||
/* Required for proxy to liboverrides conversion code. */
|
||||
#define DNA_DEPRECATED_ALLOW
|
||||
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
||||
#include "BKE_collection.h"
|
||||
#include "BKE_idtype.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lib_override.h"
|
||||
#include "BKE_main.h"
|
||||
|
||||
#include "BLO_readfile.h"
|
||||
|
||||
static CLG_LogRef LOG = {"bke.liboverride_proxy_conversion"};
|
||||
|
||||
bool BKE_lib_override_library_proxy_convert(Main *bmain,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
Object *ob_proxy)
|
||||
{
|
||||
/* `proxy_group`, if defined, is the empty instantiating the collection from which the proxy is
|
||||
* coming. */
|
||||
Object *ob_proxy_group = ob_proxy->proxy_group;
|
||||
const bool is_override_instancing_object = ob_proxy_group != NULL;
|
||||
ID *id_root = is_override_instancing_object ? &ob_proxy_group->instance_collection->id :
|
||||
&ob_proxy->proxy->id;
|
||||
ID *id_reference = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id;
|
||||
|
||||
/* In some cases the instance collection of a proxy object may be local (see e.g. T83875). Not
|
||||
* sure this is a valid state, but for now just abort the overriding process. */
|
||||
if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id_root)) {
|
||||
if (ob_proxy->proxy != NULL) {
|
||||
ob_proxy->proxy->proxy_from = NULL;
|
||||
}
|
||||
id_us_min((ID *)ob_proxy->proxy);
|
||||
ob_proxy->proxy = ob_proxy->proxy_group = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We manually convert the proxy object into a library override, further override handling will
|
||||
* then be handled by `BKE_lib_override_library_create()` just as for a regular override
|
||||
* creation.
|
||||
*/
|
||||
ob_proxy->proxy->id.tag |= LIB_TAG_DOIT;
|
||||
ob_proxy->proxy->id.newid = &ob_proxy->id;
|
||||
BKE_lib_override_library_init(&ob_proxy->id, &ob_proxy->proxy->id);
|
||||
|
||||
ob_proxy->proxy->proxy_from = NULL;
|
||||
ob_proxy->proxy = ob_proxy->proxy_group = NULL;
|
||||
|
||||
DEG_id_tag_update(&ob_proxy->id, ID_RECALC_COPY_ON_WRITE);
|
||||
|
||||
/* In case of proxy conversion, remap all local ID usages to linked IDs to their newly created
|
||||
* overrides. Also do that for the IDs from the same lib as the proxy in case it is linked.
|
||||
* While this might not be 100% the desired behavior, it is likely to be the case most of the
|
||||
* time. Ref: T91711. */
|
||||
ID *id_iter;
|
||||
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
|
||||
if (!ID_IS_LINKED(id_iter) || id_iter->lib == ob_proxy->id.lib) {
|
||||
id_iter->tag |= LIB_TAG_DOIT;
|
||||
}
|
||||
}
|
||||
FOREACH_MAIN_ID_END;
|
||||
|
||||
return BKE_lib_override_library_create(
|
||||
bmain, scene, view_layer, ob_proxy->id.lib, id_root, id_reference, NULL);
|
||||
}
|
||||
|
||||
static void lib_override_library_proxy_convert_do(Main *bmain,
|
||||
Scene *scene,
|
||||
Object *ob_proxy,
|
||||
BlendFileReadReport *reports)
|
||||
{
|
||||
Object *ob_proxy_group = ob_proxy->proxy_group;
|
||||
const bool is_override_instancing_object = ob_proxy_group != NULL;
|
||||
|
||||
const bool success = BKE_lib_override_library_proxy_convert(bmain, scene, NULL, ob_proxy);
|
||||
|
||||
if (success) {
|
||||
CLOG_INFO(&LOG,
|
||||
4,
|
||||
"Proxy object '%s' successfully converted to library overrides",
|
||||
ob_proxy->id.name);
|
||||
/* Remove the instance empty from this scene, the items now have an overridden collection
|
||||
* instead. */
|
||||
if (is_override_instancing_object) {
|
||||
BKE_scene_collections_object_remove(bmain, scene, ob_proxy_group, true);
|
||||
}
|
||||
reports->count.proxies_to_lib_overrides_success++;
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadReport *reports)
|
||||
{
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
LinkNodePair proxy_objects = {NULL};
|
||||
|
||||
FOREACH_SCENE_OBJECT_BEGIN (scene, object) {
|
||||
if (object->proxy_group != NULL) {
|
||||
BLI_linklist_append(&proxy_objects, object);
|
||||
}
|
||||
}
|
||||
FOREACH_SCENE_OBJECT_END;
|
||||
|
||||
FOREACH_SCENE_OBJECT_BEGIN (scene, object) {
|
||||
if (object->proxy != NULL && object->proxy_group == NULL) {
|
||||
BLI_linklist_append(&proxy_objects, object);
|
||||
}
|
||||
}
|
||||
FOREACH_SCENE_OBJECT_END;
|
||||
|
||||
for (LinkNode *proxy_object_iter = proxy_objects.list; proxy_object_iter != NULL;
|
||||
proxy_object_iter = proxy_object_iter->next) {
|
||||
Object *proxy_object = proxy_object_iter->link;
|
||||
lib_override_library_proxy_convert_do(bmain, scene, proxy_object, reports);
|
||||
}
|
||||
|
||||
BLI_linklist_free(proxy_objects.list, NULL);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Object *, object, &bmain->objects) {
|
||||
if (object->proxy_group != NULL || object->proxy != NULL) {
|
||||
if (ID_IS_LINKED(object)) {
|
||||
CLOG_WARN(&LOG,
|
||||
"Linked proxy object '%s' from '%s' failed to be converted to library override",
|
||||
object->id.name + 2,
|
||||
object->id.lib->filepath);
|
||||
}
|
||||
else {
|
||||
CLOG_WARN(&LOG,
|
||||
"Proxy object '%s' failed to be converted to library override",
|
||||
object->id.name + 2);
|
||||
}
|
||||
reports->count.proxies_to_lib_overrides_failures++;
|
||||
if (object->proxy != NULL) {
|
||||
object->proxy->proxy_from = NULL;
|
||||
}
|
||||
id_us_min((ID *)object->proxy);
|
||||
object->proxy = object->proxy_group = NULL;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -517,7 +517,7 @@ static int foreach_libblock_id_users_callback(LibraryIDLinkCallbackData *cb_data
|
|||
IDUsersIter *iter = cb_data->user_data;
|
||||
|
||||
if (*id_p) {
|
||||
/* 'Loopback' ID pointers (the ugly 'from' ones, Object->proxy_from and Key->from).
|
||||
/* 'Loopback' ID pointers (the ugly 'from' ones, like Key->from).
|
||||
* Those are not actually ID usage, we can ignore them here.
|
||||
*/
|
||||
if (cb_flag & IDWALK_CB_LOOPBACK) {
|
||||
|
@ -768,7 +768,7 @@ static int foreach_libblock_used_linked_data_tag_clear_cb(LibraryIDLinkCallbackD
|
|||
bool *is_changed = cb_data->user_data;
|
||||
|
||||
if (*id_p) {
|
||||
/* The infamous 'from' pointers (Key.from, Object.proxy_from, ...).
|
||||
/* The infamous 'from' pointers (Key.from, ...).
|
||||
* those are not actually ID usage, so we ignore them here. */
|
||||
if (cb_flag & IDWALK_CB_LOOPBACK) {
|
||||
return IDWALK_RET_NOP;
|
||||
|
|
|
@ -91,26 +91,18 @@ enum {
|
|||
ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */
|
||||
};
|
||||
|
||||
static void foreach_libblock_remap_callback_skip(const ID *id_owner,
|
||||
ID **id_ptr,
|
||||
static void foreach_libblock_remap_callback_skip(const ID *UNUSED(id_owner),
|
||||
ID **UNUSED(id_ptr),
|
||||
IDRemap *id_remap_data,
|
||||
const int cb_flag,
|
||||
const bool is_indirect,
|
||||
const bool is_reference,
|
||||
const bool is_never_null,
|
||||
const bool is_obj,
|
||||
const bool UNUSED(is_obj),
|
||||
const bool is_obj_editmode)
|
||||
{
|
||||
if (is_indirect) {
|
||||
id_remap_data->skipped_indirect++;
|
||||
if (is_obj) {
|
||||
Object *ob = (Object *)id_owner;
|
||||
if (ob->data == *id_ptr && ob->proxy != NULL) {
|
||||
/* And another 'Proudly brought to you by Proxy Hell' hack!
|
||||
* This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */
|
||||
id_remap_data->skipped_direct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_never_null || is_obj_editmode || is_reference) {
|
||||
id_remap_data->skipped_direct++;
|
||||
|
@ -136,8 +128,7 @@ static void foreach_libblock_remap_callback_apply(ID *id_owner,
|
|||
const int cb_flag,
|
||||
const bool is_indirect,
|
||||
const bool is_never_null,
|
||||
const bool force_user_refcount,
|
||||
const bool is_obj_proxy)
|
||||
const bool force_user_refcount)
|
||||
{
|
||||
if (!is_never_null) {
|
||||
*id_ptr = new_id;
|
||||
|
@ -170,16 +161,9 @@ static void foreach_libblock_remap_callback_apply(ID *id_owner,
|
|||
/* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET)
|
||||
* are assumed to be set as needed, that extra user is processed in final handling. */
|
||||
}
|
||||
if (!is_indirect || is_obj_proxy) {
|
||||
if (!is_indirect) {
|
||||
id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
|
||||
}
|
||||
/* We need to remap proxy_from pointer of remapped proxy... sigh. */
|
||||
if (is_obj_proxy && new_id != NULL) {
|
||||
Object *ob = (Object *)id_owner;
|
||||
if (ob->proxy == (Object *)new_id) {
|
||||
ob->proxy->proxy_from = ob;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
|
||||
|
@ -221,12 +205,9 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
|
|||
const bool is_reference = (cb_flag & IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE) != 0;
|
||||
const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
|
||||
const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
|
||||
/* NOTE: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
|
||||
* on the other hand since they get reset to lib data on file open/reload it is indirect too.
|
||||
* Edit Mode is also a 'skip direct' case. */
|
||||
const bool is_obj = (GS(id_owner->name) == ID_OB);
|
||||
const bool is_obj_proxy = (is_obj &&
|
||||
(((Object *)id_owner)->proxy || ((Object *)id_owner)->proxy_group));
|
||||
/* NOTE: Edit Mode is a 'skip direct' case, unless specifically requested, obdata should not be
|
||||
* remapped in this situation. */
|
||||
const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner) &&
|
||||
(id_remap_data->flag & ID_REMAP_FORCE_OBDATA_IN_EDITMODE) == 0);
|
||||
const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) &&
|
||||
|
@ -281,8 +262,7 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
|
|||
cb_flag,
|
||||
is_indirect,
|
||||
is_never_null,
|
||||
force_user_refcount,
|
||||
is_obj_proxy);
|
||||
force_user_refcount);
|
||||
}
|
||||
|
||||
return IDWALK_RET_NOP;
|
||||
|
@ -430,10 +410,7 @@ static void libblock_remap_data(
|
|||
Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data)
|
||||
{
|
||||
IDRemap id_remap_data;
|
||||
const int foreach_id_flags = ((remap_flags & ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE) != 0 ?
|
||||
IDWALK_NO_INDIRECT_PROXY_DATA_USAGE :
|
||||
IDWALK_NOP) |
|
||||
((remap_flags & ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS) != 0 ?
|
||||
const int foreach_id_flags = ((remap_flags & ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS) != 0 ?
|
||||
IDWALK_DO_INTERNAL_RUNTIME_POINTERS :
|
||||
IDWALK_NOP);
|
||||
|
||||
|
|
|
@ -34,19 +34,29 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
/* General note on iterating verts/loops/edges/polys and end mode.
|
||||
*
|
||||
* The edit mesh pointer is set for both final and cage meshes in both cases when there are
|
||||
* modifiers applied and not. This helps consistency of checks in the draw manager, where the
|
||||
* existence of the edit mesh pointer does not depend on object configuration.
|
||||
*
|
||||
* For the iterating, however, we need to follow the `CD_ORIGINDEX` code paths when there are
|
||||
* modifiers applied on the cage. In the code terms it means that the check for the edit mode code
|
||||
* path needs to consist of both edit mesh and edit data checks. */
|
||||
|
||||
void BKE_mesh_foreach_mapped_vert(
|
||||
Mesh *mesh,
|
||||
void (*func)(void *userData, int index, const float co[3], const float no[3]),
|
||||
void *userData,
|
||||
MeshForeachFlag flag)
|
||||
{
|
||||
if (mesh->edit_mesh != NULL) {
|
||||
if (mesh->edit_mesh != NULL && mesh->runtime.edit_data != NULL) {
|
||||
BMEditMesh *em = mesh->edit_mesh;
|
||||
BMesh *bm = em->bm;
|
||||
BMIter iter;
|
||||
BMVert *eve;
|
||||
int i;
|
||||
if (mesh->runtime.edit_data != NULL && mesh->runtime.edit_data->vertexCos != NULL) {
|
||||
if (mesh->runtime.edit_data->vertexCos != NULL) {
|
||||
const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
|
||||
const float(*vertexNos)[3];
|
||||
if (flag & MESH_FOREACH_USE_NORMAL) {
|
||||
|
@ -100,13 +110,13 @@ void BKE_mesh_foreach_mapped_edge(
|
|||
void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
|
||||
void *userData)
|
||||
{
|
||||
if (mesh->edit_mesh != NULL) {
|
||||
if (mesh->edit_mesh != NULL && mesh->runtime.edit_data) {
|
||||
BMEditMesh *em = mesh->edit_mesh;
|
||||
BMesh *bm = em->bm;
|
||||
BMIter iter;
|
||||
BMEdge *eed;
|
||||
int i;
|
||||
if (mesh->runtime.edit_data != NULL && mesh->runtime.edit_data->vertexCos != NULL) {
|
||||
if (mesh->runtime.edit_data->vertexCos != NULL) {
|
||||
const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
|
||||
BM_mesh_elem_index_ensure(bm, BM_VERT);
|
||||
|
||||
|
@ -158,14 +168,13 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
|
|||
/* We can't use dm->getLoopDataLayout(dm) here,
|
||||
* we want to always access dm->loopData, EditDerivedBMesh would
|
||||
* return loop data from bmesh itself. */
|
||||
if (mesh->edit_mesh != NULL) {
|
||||
if (mesh->edit_mesh != NULL && mesh->runtime.edit_data) {
|
||||
BMEditMesh *em = mesh->edit_mesh;
|
||||
BMesh *bm = em->bm;
|
||||
BMIter iter;
|
||||
BMFace *efa;
|
||||
|
||||
const float(*vertexCos)[3] = mesh->runtime.edit_data ? mesh->runtime.edit_data->vertexCos :
|
||||
NULL;
|
||||
const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
|
||||
|
||||
/* XXX: investigate using EditMesh data. */
|
||||
const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
|
||||
|
|
|
@ -290,6 +290,16 @@ ModifierData *BKE_modifiers_findby_name(const Object *ob, const char *name)
|
|||
return BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name));
|
||||
}
|
||||
|
||||
ModifierData *BKE_modifiers_findby_session_uuid(const Object *ob, const SessionUUID *session_uuid)
|
||||
{
|
||||
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
||||
if (BLI_session_uuid_is_equal(&md->session_uuid, session_uuid)) {
|
||||
return md;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void BKE_modifiers_clear_errors(Object *ob)
|
||||
{
|
||||
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
||||
|
@ -439,9 +449,7 @@ void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *_for
|
|||
#ifndef NDEBUG
|
||||
if ((md->mode & eModifierMode_Virtual) == 0) {
|
||||
/* Ensure correct object is passed in. */
|
||||
const Object *ob_orig = (Object *)DEG_get_original_id((ID *)&ob->id);
|
||||
const ModifierData *md_orig = md->orig_modifier_data ? md->orig_modifier_data : md;
|
||||
BLI_assert(BLI_findindex(&ob_orig->modifiers, md_orig) != -1);
|
||||
BLI_assert(BKE_modifier_get_original(ob, md) != NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1052,12 +1060,10 @@ Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval,
|
|||
return me;
|
||||
}
|
||||
|
||||
ModifierData *BKE_modifier_get_original(ModifierData *md)
|
||||
ModifierData *BKE_modifier_get_original(const Object *object, ModifierData *md)
|
||||
{
|
||||
if (md->orig_modifier_data == NULL) {
|
||||
return md;
|
||||
}
|
||||
return md->orig_modifier_data;
|
||||
const Object *object_orig = DEG_get_original_object((Object *)object);
|
||||
return BKE_modifiers_findby_session_uuid(object_orig, &md->session_uuid);
|
||||
}
|
||||
|
||||
struct ModifierData *BKE_modifier_get_evaluated(Depsgraph *depsgraph,
|
||||
|
@ -1068,7 +1074,7 @@ struct ModifierData *BKE_modifier_get_evaluated(Depsgraph *depsgraph,
|
|||
if (object_eval == object) {
|
||||
return md;
|
||||
}
|
||||
return BKE_modifiers_findby_name(object_eval, md->name);
|
||||
return BKE_modifiers_findby_session_uuid(object_eval, &md->session_uuid);
|
||||
}
|
||||
|
||||
void BKE_modifier_check_uuids_unique_and_report(const Object *object)
|
||||
|
@ -1182,8 +1188,8 @@ void BKE_modifier_blend_write(BlendWriter *writer, ListBase *modbase)
|
|||
|
||||
#if 0
|
||||
CollisionModifierData *collmd = (CollisionModifierData *)md;
|
||||
// TODO: CollisionModifier should use pointcache
|
||||
// + have proper reset events before enabling this
|
||||
/* TODO: CollisionModifier should use pointcache
|
||||
* + have proper reset events before enabling this. */
|
||||
writestruct(wd, DATA, MVert, collmd->numverts, collmd->x);
|
||||
writestruct(wd, DATA, MVert, collmd->numverts, collmd->xnew);
|
||||
writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces);
|
||||
|
|
|
@ -4503,6 +4503,8 @@ static void registerCompositNodes()
|
|||
register_node_type_cmp_sepycca();
|
||||
register_node_type_cmp_combycca();
|
||||
register_node_type_cmp_premulkey();
|
||||
register_node_type_cmp_separate_xyz();
|
||||
register_node_type_cmp_combine_xyz();
|
||||
|
||||
register_node_type_cmp_diff_matte();
|
||||
register_node_type_cmp_distance_matte();
|
||||
|
|
|
@ -325,45 +325,6 @@ static void object_free_data(ID *id)
|
|||
BKE_previewimg_free(&ob->preview);
|
||||
}
|
||||
|
||||
static void object_make_local(Main *bmain, ID *id, const int flags)
|
||||
{
|
||||
if (!ID_IS_LINKED(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object *ob = (Object *)id;
|
||||
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
|
||||
const bool clear_proxy = (flags & LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING) == 0;
|
||||
|
||||
bool force_local, force_copy;
|
||||
BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
|
||||
|
||||
if (force_local) {
|
||||
BKE_lib_id_clear_library_data(bmain, &ob->id, flags);
|
||||
BKE_lib_id_expand_local(bmain, &ob->id, flags);
|
||||
if (clear_proxy) {
|
||||
if (ob->proxy_from != nullptr) {
|
||||
ob->proxy_from->proxy = nullptr;
|
||||
ob->proxy_from->proxy_group = nullptr;
|
||||
}
|
||||
ob->proxy = ob->proxy_from = ob->proxy_group = nullptr;
|
||||
}
|
||||
}
|
||||
else if (force_copy) {
|
||||
Object *ob_new = (Object *)BKE_id_copy(bmain, &ob->id);
|
||||
id_us_min(&ob_new->id);
|
||||
|
||||
ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = nullptr;
|
||||
|
||||
/* setting newid is mandatory for complex make_lib_local logic... */
|
||||
ID_NEW_SET(ob, ob_new);
|
||||
|
||||
if (!lib_local) {
|
||||
BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void library_foreach_modifiersForeachIDLink(void *user_data,
|
||||
Object *UNUSED(object),
|
||||
ID **id_pointer,
|
||||
|
@ -419,51 +380,25 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
|
|||
{
|
||||
Object *object = (Object *)id;
|
||||
|
||||
/* Object is special, proxies make things hard... */
|
||||
const int proxy_cb_flag = ((BKE_lib_query_foreachid_process_flags_get(data) &
|
||||
IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 &&
|
||||
(object->proxy || object->proxy_group)) ?
|
||||
IDWALK_CB_INDIRECT_USAGE :
|
||||
0;
|
||||
|
||||
/* object data special case */
|
||||
if (object->type == OB_EMPTY) {
|
||||
/* empty can have nullptr or Image */
|
||||
BKE_LIB_FOREACHID_PROCESS_ID(data, object->data, proxy_cb_flag | IDWALK_CB_USER);
|
||||
BKE_LIB_FOREACHID_PROCESS_ID(data, object->data, IDWALK_CB_USER);
|
||||
}
|
||||
else {
|
||||
/* when set, this can't be nullptr */
|
||||
if (object->data) {
|
||||
BKE_LIB_FOREACHID_PROCESS_ID(
|
||||
data, object->data, proxy_cb_flag | IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
|
||||
BKE_LIB_FOREACHID_PROCESS_ID(data, object->data, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->parent, IDWALK_CB_NEVER_SELF);
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->track, IDWALK_CB_NEVER_SELF);
|
||||
/* object->proxy is refcounted, but not object->proxy_group... *sigh* */
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF);
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->proxy_group, IDWALK_CB_NOP);
|
||||
|
||||
/* Special case!
|
||||
* Since this field is set/owned by 'user' of this ID (and not ID itself),
|
||||
* it is only indirect usage if proxy object is linked... Twisted. */
|
||||
{
|
||||
const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override(
|
||||
data,
|
||||
(object->proxy_from != nullptr && ID_IS_LINKED(object->proxy_from)) ?
|
||||
IDWALK_CB_INDIRECT_USAGE :
|
||||
0,
|
||||
true);
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
|
||||
data, object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF);
|
||||
BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true);
|
||||
}
|
||||
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->poselib, IDWALK_CB_USER);
|
||||
|
||||
for (int i = 0; i < object->totcol; i++) {
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->mat[i], proxy_cb_flag | IDWALK_CB_USER);
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->mat[i], IDWALK_CB_USER);
|
||||
}
|
||||
|
||||
/* Note that ob->gpd is deprecated, so no need to handle it here. */
|
||||
|
@ -476,8 +411,6 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
|
|||
/* Note that ob->effect is deprecated, so no need to handle it here. */
|
||||
|
||||
if (object->pose) {
|
||||
const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override(
|
||||
data, proxy_cb_flag, false);
|
||||
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
|
||||
BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(
|
||||
data,
|
||||
|
@ -492,7 +425,6 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
|
|||
BKE_constraints_id_loop(
|
||||
&pchan->constraints, library_foreach_constraintObjectLooper, data));
|
||||
}
|
||||
BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true);
|
||||
}
|
||||
|
||||
if (object->rigidbody_constraint) {
|
||||
|
@ -627,9 +559,6 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre
|
|||
bArmature *arm = nullptr;
|
||||
if (ob->type == OB_ARMATURE) {
|
||||
arm = (bArmature *)ob->data;
|
||||
if (arm && ob->pose && arm->act_bone) {
|
||||
BLI_strncpy(ob->pose->proxy_act_bone, arm->act_bone->name, sizeof(ob->pose->proxy_act_bone));
|
||||
}
|
||||
}
|
||||
|
||||
BKE_pose_blend_write(writer, ob->pose, arm);
|
||||
|
@ -1305,7 +1234,7 @@ IDTypeInfo IDType_ID_OB = {
|
|||
/* init_data */ object_init_data,
|
||||
/* copy_data */ object_copy_data,
|
||||
/* free_data */ object_free_data,
|
||||
/* make_local */ object_make_local,
|
||||
/* make_local */ nullptr,
|
||||
/* foreach_id */ object_foreach_id,
|
||||
/* foreach_cache */ nullptr,
|
||||
/* foreach_path */ object_foreach_path,
|
||||
|
@ -2873,161 +2802,6 @@ bool BKE_object_obdata_is_libdata(const Object *ob)
|
|||
return (ob && ob->data && ID_IS_LINKED(ob->data));
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Object Proxy API
|
||||
* \{ */
|
||||
|
||||
/* when you make proxy, ensure the exposed layers are extern */
|
||||
static void armature_set_id_extern(Object *ob)
|
||||
{
|
||||
bArmature *arm = (bArmature *)ob->data;
|
||||
unsigned int lay = arm->layer_protected;
|
||||
|
||||
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
|
||||
if (!(pchan->bone->layer & lay)) {
|
||||
id_lib_extern((ID *)pchan->custom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
|
||||
{
|
||||
if ((target->adt) && (target->adt->drivers.first)) {
|
||||
|
||||
/* add new animdata block */
|
||||
if (!ob->adt) {
|
||||
ob->adt = BKE_animdata_ensure_id(&ob->id);
|
||||
}
|
||||
|
||||
/* make a copy of all the drivers (for now), then correct any links that need fixing */
|
||||
BKE_fcurves_free(&ob->adt->drivers);
|
||||
BKE_fcurves_copy(&ob->adt->drivers, &target->adt->drivers);
|
||||
|
||||
LISTBASE_FOREACH (FCurve *, fcu, &ob->adt->drivers) {
|
||||
ChannelDriver *driver = fcu->driver;
|
||||
|
||||
LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
|
||||
/* all drivers */
|
||||
DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
|
||||
if (dtar->id) {
|
||||
if ((Object *)dtar->id == target) {
|
||||
dtar->id = (ID *)ob;
|
||||
}
|
||||
else {
|
||||
/* only on local objects because this causes indirect links
|
||||
* 'a -> b -> c', blend to point directly to a.blend
|
||||
* when a.blend has a proxy that's linked into `c.blend`. */
|
||||
if (!ID_IS_LINKED(ob)) {
|
||||
id_lib_extern((ID *)dtar->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DRIVER_TARGETS_LOOPER_END;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
|
||||
{
|
||||
/* paranoia checks */
|
||||
if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) {
|
||||
CLOG_ERROR(&LOG, "cannot make proxy");
|
||||
return;
|
||||
}
|
||||
|
||||
ob->proxy = target;
|
||||
id_us_plus(&target->id);
|
||||
ob->proxy_group = cob;
|
||||
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
|
||||
DEG_id_tag_update(&target->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
|
||||
|
||||
/* copy transform
|
||||
* - cob means this proxy comes from a collection, just apply the matrix
|
||||
* so the object won't move from its dupli-transform.
|
||||
*
|
||||
* - no cob means this is being made from a linked object,
|
||||
* this is closer to making a copy of the object - in-place. */
|
||||
if (cob) {
|
||||
ob->rotmode = target->rotmode;
|
||||
mul_m4_m4m4(ob->obmat, cob->obmat, target->obmat);
|
||||
if (cob->instance_collection) { /* should always be true */
|
||||
float tvec[3];
|
||||
mul_v3_mat3_m4v3(tvec, ob->obmat, cob->instance_collection->instance_offset);
|
||||
sub_v3_v3(ob->obmat[3], tvec);
|
||||
}
|
||||
BKE_object_apply_mat4(ob, ob->obmat, false, true);
|
||||
}
|
||||
else {
|
||||
BKE_object_transform_copy(ob, target);
|
||||
ob->parent = target->parent; /* libdata */
|
||||
copy_m4_m4(ob->parentinv, target->parentinv);
|
||||
}
|
||||
|
||||
/* copy animdata stuff - drivers only for now... */
|
||||
BKE_object_copy_proxy_drivers(ob, target);
|
||||
|
||||
/* skip constraints? */
|
||||
/* FIXME: this is considered by many as a bug */
|
||||
|
||||
/* set object type and link to data */
|
||||
ob->type = target->type;
|
||||
ob->data = target->data;
|
||||
id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */
|
||||
|
||||
/* copy material and index information */
|
||||
ob->actcol = ob->totcol = 0;
|
||||
if (ob->mat) {
|
||||
MEM_freeN(ob->mat);
|
||||
}
|
||||
if (ob->matbits) {
|
||||
MEM_freeN(ob->matbits);
|
||||
}
|
||||
ob->mat = nullptr;
|
||||
ob->matbits = nullptr;
|
||||
if ((target->totcol) && (target->mat) && OB_TYPE_SUPPORT_MATERIAL(ob->type)) {
|
||||
int i;
|
||||
|
||||
ob->actcol = target->actcol;
|
||||
ob->totcol = target->totcol;
|
||||
|
||||
ob->mat = (Material **)MEM_dupallocN(target->mat);
|
||||
ob->matbits = (char *)MEM_dupallocN(target->matbits);
|
||||
for (i = 0; i < target->totcol; i++) {
|
||||
/* don't need to run BKE_object_materials_test
|
||||
* since we know this object is new and not used elsewhere */
|
||||
id_us_plus((ID *)ob->mat[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* type conversions */
|
||||
if (target->type == OB_ARMATURE) {
|
||||
copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */
|
||||
BKE_pose_rest(ob->pose, false); /* clear all transforms in channels */
|
||||
BKE_pose_rebuild(bmain, ob, (bArmature *)ob->data, true); /* set all internal links */
|
||||
|
||||
armature_set_id_extern(ob);
|
||||
}
|
||||
else if (target->type == OB_EMPTY) {
|
||||
ob->empty_drawtype = target->empty_drawtype;
|
||||
ob->empty_drawsize = target->empty_drawsize;
|
||||
}
|
||||
|
||||
/* copy IDProperties */
|
||||
if (ob->id.properties) {
|
||||
IDP_FreeProperty(ob->id.properties);
|
||||
ob->id.properties = nullptr;
|
||||
}
|
||||
if (target->id.properties) {
|
||||
ob->id.properties = IDP_CopyProperty(target->id.properties);
|
||||
}
|
||||
|
||||
/* copy drawtype info */
|
||||
ob->dt = target->dt;
|
||||
}
|
||||
|
||||
void BKE_object_obdata_size_init(struct Object *ob, const float size)
|
||||
{
|
||||
/* apply radius as a scale to types that support it */
|
||||
|
@ -3069,8 +2843,6 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size)
|
|||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Object Matrix Get/Set API
|
||||
* \{ */
|
||||
|
@ -4186,7 +3958,11 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
|
|||
/* pass */
|
||||
}
|
||||
else {
|
||||
BoundBox *bb = BKE_object_boundbox_get(dob->ob);
|
||||
Object temp_ob = *dob->ob;
|
||||
/* Do not modify the original boundbox. */
|
||||
temp_ob.runtime.bb = nullptr;
|
||||
BKE_object_replace_data_on_shallow_copy(&temp_ob, dob->ob_data);
|
||||
BoundBox *bb = BKE_object_boundbox_get(&temp_ob);
|
||||
|
||||
if (bb) {
|
||||
int i;
|
||||
|
@ -4198,6 +3974,8 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
|
|||
|
||||
ok = true;
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(temp_ob.runtime.bb);
|
||||
}
|
||||
}
|
||||
free_object_duplilist(lb); /* does restore */
|
||||
|
@ -4356,33 +4134,10 @@ void BKE_object_tfm_restore(Object *ob, void *obtfm_pt)
|
|||
/** \name Object Evaluation/Update API
|
||||
* \{ */
|
||||
|
||||
static void object_handle_update_proxy(Depsgraph *depsgraph,
|
||||
Scene *scene,
|
||||
Object *object,
|
||||
const bool do_proxy_update)
|
||||
{
|
||||
/* The case when this is a collection proxy, object_update is called in collection.c */
|
||||
if (object->proxy == nullptr) {
|
||||
return;
|
||||
}
|
||||
/* set pointer in library proxy target, for copying, but restore it */
|
||||
object->proxy->proxy_from = object;
|
||||
// printf("set proxy pointer for later collection stuff %s\n", ob->id.name);
|
||||
|
||||
/* the no-group proxy case, we call update */
|
||||
if (object->proxy_group == nullptr) {
|
||||
if (do_proxy_update) {
|
||||
// printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name);
|
||||
BKE_object_handle_update(depsgraph, scene, object->proxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_object_handle_update_ex(Depsgraph *depsgraph,
|
||||
Scene *scene,
|
||||
Object *ob,
|
||||
RigidBodyWorld *rbw,
|
||||
const bool do_proxy_update)
|
||||
RigidBodyWorld *rbw)
|
||||
{
|
||||
const ID *object_data = (ID *)ob->data;
|
||||
const bool recalc_object = (ob->id.recalc & ID_RECALC_ALL) != 0;
|
||||
|
@ -4390,7 +4145,6 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph,
|
|||
((object_data->recalc & ID_RECALC_ALL) != 0) :
|
||||
false;
|
||||
if (!recalc_object && !recalc_data) {
|
||||
object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
|
||||
return;
|
||||
}
|
||||
/* Speed optimization for animation lookups. */
|
||||
|
@ -4419,22 +4173,17 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph,
|
|||
if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
|
||||
printf("recalcob %s\n", ob->id.name + 2);
|
||||
}
|
||||
/* Handle proxy copy for target. */
|
||||
if (!BKE_object_eval_proxy_copy(depsgraph, ob)) {
|
||||
BKE_object_where_is_calc_ex(depsgraph, scene, rbw, ob, nullptr);
|
||||
}
|
||||
BKE_object_where_is_calc_ex(depsgraph, scene, rbw, ob, nullptr);
|
||||
}
|
||||
|
||||
if (recalc_data) {
|
||||
BKE_object_handle_data_update(depsgraph, scene, ob);
|
||||
}
|
||||
|
||||
object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
|
||||
}
|
||||
|
||||
void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
|
||||
{
|
||||
BKE_object_handle_update_ex(depsgraph, scene, ob, nullptr, true);
|
||||
BKE_object_handle_update_ex(depsgraph, scene, ob, nullptr);
|
||||
}
|
||||
|
||||
void BKE_object_sculpt_data_create(Object *ob)
|
||||
|
|
|
@ -190,16 +190,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
|
|||
break;
|
||||
}
|
||||
case OB_ARMATURE:
|
||||
if (ID_IS_LINKED(ob) && ob->proxy_from) {
|
||||
if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
|
||||
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
|
||||
ob->id.name + 2,
|
||||
ob->proxy_from->id.name + 2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BKE_pose_where_is(depsgraph, scene, ob);
|
||||
}
|
||||
BKE_pose_where_is(depsgraph, scene, ob);
|
||||
break;
|
||||
|
||||
case OB_MBALL:
|
||||
|
@ -311,33 +302,9 @@ void BKE_object_sync_to_original(Depsgraph *depsgraph, Object *object)
|
|||
object_sync_boundbox_to_original(object_orig, object);
|
||||
}
|
||||
|
||||
bool BKE_object_eval_proxy_copy(Depsgraph *depsgraph, Object *object)
|
||||
void BKE_object_eval_uber_transform(Depsgraph *UNUSED(depsgraph), Object *UNUSED(object))
|
||||
{
|
||||
/* Handle proxy copy for target, */
|
||||
if (ID_IS_LINKED(object) && object->proxy_from) {
|
||||
DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
|
||||
if (object->proxy_from->proxy_group) {
|
||||
/* Transform proxy into group space. */
|
||||
Object *obg = object->proxy_from->proxy_group;
|
||||
float imat[4][4];
|
||||
invert_m4_m4(imat, obg->obmat);
|
||||
mul_m4_m4m4(object->obmat, imat, object->proxy_from->obmat);
|
||||
/* Should always be true. */
|
||||
if (obg->instance_collection) {
|
||||
add_v3_v3(object->obmat[3], obg->instance_collection->instance_offset);
|
||||
}
|
||||
}
|
||||
else {
|
||||
copy_m4_m4(object->obmat, object->proxy_from->obmat);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BKE_object_eval_uber_transform(Depsgraph *depsgraph, Object *object)
|
||||
{
|
||||
BKE_object_eval_proxy_copy(depsgraph, object);
|
||||
return;
|
||||
}
|
||||
|
||||
void BKE_object_data_batch_cache_dirty_tag(ID *object_data)
|
||||
|
|
|
@ -1648,7 +1648,6 @@ static void sculpt_update_object(Depsgraph *depsgraph,
|
|||
ss->totvert = me->totvert;
|
||||
ss->totpoly = me->totpoly;
|
||||
ss->totfaces = me->totpoly;
|
||||
ss->vert_normals = BKE_mesh_vertex_normals_ensure(me);
|
||||
ss->mvert = me->mvert;
|
||||
ss->mpoly = me->mpoly;
|
||||
ss->mloop = me->mloop;
|
||||
|
|
|
@ -1007,6 +1007,28 @@ typedef struct PBVHUpdateData {
|
|||
bool show_sculpt_face_sets;
|
||||
} PBVHUpdateData;
|
||||
|
||||
static void pbvh_update_normals_clear_task_cb(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
PBVHUpdateData *data = userdata;
|
||||
PBVH *pbvh = data->pbvh;
|
||||
PBVHNode *node = data->nodes[n];
|
||||
float(*vnors)[3] = data->vnors;
|
||||
|
||||
if (node->flag & PBVH_UpdateNormals) {
|
||||
const int *verts = node->vert_indices;
|
||||
const int totvert = node->uniq_verts;
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
const int v = verts[i];
|
||||
const MVert *mvert = &pbvh->verts[v];
|
||||
if (mvert->flag & ME_VERT_PBVH_UPDATE) {
|
||||
zero_v3(vnors[v]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
|
@ -1107,6 +1129,8 @@ static void pbvh_faces_update_normals(PBVH *pbvh, PBVHNode **nodes, int totnode)
|
|||
TaskParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
|
||||
|
||||
/* Zero normals before accumulation. */
|
||||
BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_clear_task_cb, &settings);
|
||||
BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
|
||||
BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
|
||||
}
|
||||
|
|
|
@ -2522,7 +2522,7 @@ void BKE_scene_update_sound(Depsgraph *depsgraph, Main *bmain)
|
|||
Scene *scene = DEG_get_evaluated_scene(depsgraph);
|
||||
const int recalc = scene->id.recalc;
|
||||
BKE_sound_ensure_scene(scene);
|
||||
if (recalc & ID_RECALC_AUDIO_SEEK) {
|
||||
if (recalc & ID_RECALC_FRAME_CHANGE) {
|
||||
BKE_sound_seek_scene(bmain, scene);
|
||||
}
|
||||
if (recalc & ID_RECALC_AUDIO_FPS) {
|
||||
|
|
|
@ -726,14 +726,12 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
|
|||
}
|
||||
}
|
||||
|
||||
if (codec_id == AV_CODEC_ID_VP9) {
|
||||
if (rd->im_format.planes == R_IMF_PLANES_RGBA) {
|
||||
c->pix_fmt = AV_PIX_FMT_YUVA420P;
|
||||
}
|
||||
if (codec_id == AV_CODEC_ID_VP9 && rd->im_format.planes == R_IMF_PLANES_RGBA) {
|
||||
c->pix_fmt = AV_PIX_FMT_YUVA420P;
|
||||
}
|
||||
|
||||
/* Use 4:4:4 instead of 4:2:0 pixel format for lossless rendering. */
|
||||
if ((codec_id == AV_CODEC_ID_H264 || codec_id == AV_CODEC_ID_VP9) && context->ffmpeg_crf == 0) {
|
||||
else if ((codec_id == AV_CODEC_ID_H264 || codec_id == AV_CODEC_ID_VP9) &&
|
||||
context->ffmpeg_crf == 0) {
|
||||
/* Use 4:4:4 instead of 4:2:0 pixel format for lossless rendering. */
|
||||
c->pix_fmt = AV_PIX_FMT_YUV444P;
|
||||
}
|
||||
|
||||
|
|
|
@ -358,7 +358,9 @@ constexpr int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) con
|
|||
|
||||
constexpr int64_t StringRefBase::find_first_of(char c, int64_t pos) const
|
||||
{
|
||||
return this->find_first_of(StringRef(&c, 1), pos);
|
||||
BLI_assert(pos >= 0);
|
||||
return index_or_npos_to_int64(
|
||||
std::string_view(*this).find_first_of(c, static_cast<size_t>(pos)));
|
||||
}
|
||||
|
||||
constexpr int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const
|
||||
|
@ -370,7 +372,9 @@ constexpr int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) cons
|
|||
|
||||
constexpr int64_t StringRefBase::find_last_of(char c, int64_t pos) const
|
||||
{
|
||||
return this->find_last_of(StringRef(&c, 1), pos);
|
||||
BLI_assert(pos >= 0);
|
||||
return index_or_npos_to_int64(
|
||||
std::string_view(*this).find_last_of(c, static_cast<size_t>(pos)));
|
||||
}
|
||||
|
||||
constexpr int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const
|
||||
|
@ -382,7 +386,9 @@ constexpr int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos)
|
|||
|
||||
constexpr int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const
|
||||
{
|
||||
return this->find_first_not_of(StringRef(&c, 1), pos);
|
||||
BLI_assert(pos >= 0);
|
||||
return index_or_npos_to_int64(
|
||||
std::string_view(*this).find_first_not_of(c, static_cast<size_t>(pos)));
|
||||
}
|
||||
|
||||
constexpr int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const
|
||||
|
@ -394,7 +400,9 @@ constexpr int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos)
|
|||
|
||||
constexpr int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const
|
||||
{
|
||||
return this->find_last_not_of(StringRef(&c, 1), pos);
|
||||
BLI_assert(pos >= 0);
|
||||
return index_or_npos_to_int64(
|
||||
std::string_view(*this).find_last_not_of(c, static_cast<size_t>(pos)));
|
||||
}
|
||||
|
||||
constexpr StringRef StringRefBase::trim() const
|
||||
|
|
|
@ -570,6 +570,10 @@ class VectorSet {
|
|||
if (this->size() == 0) {
|
||||
try {
|
||||
slots_.reinitialize(total_slots);
|
||||
if (keys_ != nullptr) {
|
||||
this->deallocate_keys_array(keys_);
|
||||
keys_ = nullptr;
|
||||
}
|
||||
keys_ = this->allocate_keys_array(usable_slots);
|
||||
}
|
||||
catch (...) {
|
||||
|
|
|
@ -271,4 +271,14 @@ TEST(vector_set, LookupKey)
|
|||
EXPECT_EQ(set.lookup_key_ptr("a"), set.lookup_key_ptr_as("a"));
|
||||
}
|
||||
|
||||
TEST(vector_set, GrowWhenEmpty)
|
||||
{
|
||||
/* Tests that the internal keys array is freed correctly when growing an empty set. */
|
||||
VectorSet<int> set;
|
||||
set.add(4);
|
||||
set.remove(4);
|
||||
EXPECT_TRUE(set.is_empty());
|
||||
set.reserve(100);
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
|
|
@ -117,8 +117,6 @@ typedef struct BlendFileReadReport {
|
|||
/* Number of root override IDs that were resynced. */
|
||||
int resynced_lib_overrides;
|
||||
|
||||
/* Number of (non-converted) linked proxies. */
|
||||
int linked_proxies;
|
||||
/* Number of proxies converted to library overrides. */
|
||||
int proxies_to_lib_overrides_success;
|
||||
/* Number of proxies that failed to convert to library overrides. */
|
||||
|
|
|
@ -419,9 +419,6 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain,
|
|||
fd->skip_flags = params->skip_flags;
|
||||
BLI_strncpy(fd->relabase, filename, sizeof(fd->relabase));
|
||||
|
||||
/* clear ob->proxy_from pointers in old main */
|
||||
blo_clear_proxy_pointers_from_lib(oldmain);
|
||||
|
||||
/* separate libraries from old main */
|
||||
blo_split_main(&old_mainlist, oldmain);
|
||||
/* add the library pointers in oldmap lookup */
|
||||
|
|
|
@ -1580,15 +1580,6 @@ static void change_link_placeholder_to_real_ID_pointer(ListBase *mainlist,
|
|||
}
|
||||
}
|
||||
|
||||
void blo_clear_proxy_pointers_from_lib(Main *oldmain)
|
||||
{
|
||||
LISTBASE_FOREACH (Object *, ob, &oldmain->objects) {
|
||||
if (ID_IS_LINKED(ob) && ob->proxy_from != NULL && !ID_IS_LINKED(ob->proxy_from)) {
|
||||
ob->proxy_from = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX disabled this feature - packed files also belong in temp saves and quit.blend,
|
||||
* to make restore work. */
|
||||
|
||||
|
@ -3207,18 +3198,8 @@ static void read_libblock_undo_restore_identical(
|
|||
id_old->recalc |= direct_link_id_restore_recalc_exceptions(id_old);
|
||||
id_old->recalc_after_undo_push = 0;
|
||||
|
||||
/* As usual, proxies require some special love...
|
||||
* In `blo_clear_proxy_pointers_from_lib()` we clear all `proxy_from` pointers to local IDs, for
|
||||
* undo. This is required since we do not re-read linked data in that case, so we also do not
|
||||
* re-'lib_link' their pointers.
|
||||
* Those `proxy_from` pointers are then re-defined properly when lib_linking the newly read local
|
||||
* object. However, in case of re-used data 'as-is', we never lib_link it again, so we have to
|
||||
* fix those backward pointers here. */
|
||||
if (GS(id_old->name) == ID_OB) {
|
||||
Object *ob = (Object *)id_old;
|
||||
if (ob->proxy != NULL) {
|
||||
ob->proxy->proxy_from = ob;
|
||||
}
|
||||
/* For undo we stay in object mode during undo presses, so keep editmode disabled for re-used
|
||||
* data-blocks too. */
|
||||
ob->mode &= ~OB_MODE_EDIT;
|
||||
|
|
|
@ -144,14 +144,6 @@ FileData *blo_filedata_from_memfile(struct MemFile *memfile,
|
|||
const struct BlendFileReadParams *params,
|
||||
struct BlendFileReadReport *reports);
|
||||
|
||||
/**
|
||||
* Lib linked proxy objects point to our local data, we need
|
||||
* to clear that pointer before reading the undo memfile since
|
||||
* the object might be removed, it is set again in reading
|
||||
* if the local object still exists.
|
||||
* This is only valid for local proxy objects though, linked ones should not be affected here.
|
||||
*/
|
||||
void blo_clear_proxy_pointers_from_lib(struct Main *oldmain);
|
||||
void blo_make_packed_pointer_map(FileData *fd, struct Main *oldmain);
|
||||
/**
|
||||
* Set old main packed data to zero if it has been restored
|
||||
|
|
|
@ -349,7 +349,7 @@ static void do_version_scene_collection_convert(
|
|||
LISTBASE_FOREACH (LinkData *, link, &sc->objects) {
|
||||
Object *ob = link->data;
|
||||
if (ob) {
|
||||
BKE_collection_object_add(bmain, collection, ob);
|
||||
BKE_collection_object_add_notest(bmain, collection, ob);
|
||||
id_us_min(&ob->id);
|
||||
}
|
||||
}
|
||||
|
@ -459,7 +459,7 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
|
|||
|
||||
/* Note usually this would do slow collection syncing for view layers,
|
||||
* but since no view layers exists yet at this point it's fast. */
|
||||
BKE_collection_object_add(bmain, collections[layer], base->object);
|
||||
BKE_collection_object_add_notest(bmain, collections[layer], base->object);
|
||||
}
|
||||
|
||||
if (base->flag & SELECT) {
|
||||
|
@ -1235,7 +1235,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
|
|||
(*collection_hidden)->flag |= COLLECTION_HIDE_VIEWPORT | COLLECTION_HIDE_RENDER;
|
||||
}
|
||||
|
||||
BKE_collection_object_add(bmain, *collection_hidden, ob);
|
||||
BKE_collection_object_add_notest(bmain, *collection_hidden, ob);
|
||||
BKE_collection_object_remove(bmain, collection, ob, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1122,7 +1122,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
|
||||
/* Hair and PointCloud attributes. */
|
||||
for (Hair *hair = bmain->hairs.first; hair != NULL; hair = hair->id.next) {
|
||||
do_versions_point_attributes(&hair->pdata);
|
||||
do_versions_point_attributes(&hair->geometry.point_data);
|
||||
}
|
||||
for (PointCloud *pointcloud = bmain->pointclouds.first; pointcloud != NULL;
|
||||
pointcloud = pointcloud->id.next) {
|
||||
|
@ -1424,7 +1424,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
|
||||
/* Hair and PointCloud attributes names. */
|
||||
LISTBASE_FOREACH (Hair *, hair, &bmain->hairs) {
|
||||
do_versions_point_attribute_names(&hair->pdata);
|
||||
do_versions_point_attribute_names(&hair->geometry.point_data);
|
||||
}
|
||||
LISTBASE_FOREACH (PointCloud *, pointcloud, &bmain->pointclouds) {
|
||||
do_versions_point_attribute_names(&pointcloud->pdata);
|
||||
|
|
|
@ -974,6 +974,13 @@ void blo_do_versions_userdef(UserDef *userdef)
|
|||
*/
|
||||
{
|
||||
/* Keep this block, even when empty. */
|
||||
if (!USER_VERSION_ATLEAST(301, 7)) {
|
||||
/* io_scene_obj directory is gone, split into io_import_obj and io_export_obj,
|
||||
* with io_import_obj enabled by default and io_export_obj replaced by the C++ version.
|
||||
*/
|
||||
BKE_addon_remove_safe(&userdef->addons, "io_scene_obj");
|
||||
BKE_addon_ensure(&userdef->addons, "io_import_obj");
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) {
|
||||
|
|
|
@ -192,12 +192,12 @@ static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out, bool keep_hidden
|
|||
BM_elem_flag_enable(bmv, KEEP_FLAG);
|
||||
}
|
||||
else {
|
||||
new_bmvs[v] = NULL;
|
||||
new_bmvs[v] = nullptr;
|
||||
}
|
||||
}
|
||||
for (int v : m_out.vert_index_range()) {
|
||||
const Vert *vertp = m_out.vert(v);
|
||||
if (new_bmvs[v] == NULL) {
|
||||
if (new_bmvs[v] == nullptr) {
|
||||
float co[3];
|
||||
const double3 &d_co = vertp->co;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
|
|
|
@ -274,10 +274,14 @@ set(SRC
|
|||
# converter nodes
|
||||
nodes/COM_CombineColorNode.cc
|
||||
nodes/COM_CombineColorNode.h
|
||||
nodes/COM_CombineXYZNode.cc
|
||||
nodes/COM_CombineXYZNode.h
|
||||
nodes/COM_IDMaskNode.cc
|
||||
nodes/COM_IDMaskNode.h
|
||||
nodes/COM_SeparateColorNode.cc
|
||||
nodes/COM_SeparateColorNode.h
|
||||
nodes/COM_SeparateXYZNode.cc
|
||||
nodes/COM_SeparateXYZNode.h
|
||||
|
||||
nodes/COM_MapRangeNode.cc
|
||||
nodes/COM_MapRangeNode.h
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "COM_ColorSpillNode.h"
|
||||
#include "COM_ColorToBWNode.h"
|
||||
#include "COM_CombineColorNode.h"
|
||||
#include "COM_CombineXYZNode.h"
|
||||
#include "COM_CompositorNode.h"
|
||||
#include "COM_ConvertAlphaNode.h"
|
||||
#include "COM_ConvertColorSpaceNode.h"
|
||||
|
@ -96,6 +97,7 @@
|
|||
#include "COM_ScaleOperation.h"
|
||||
#include "COM_SceneTimeNode.h"
|
||||
#include "COM_SeparateColorNode.h"
|
||||
#include "COM_SeparateXYZNode.h"
|
||||
#include "COM_SetAlphaNode.h"
|
||||
#include "COM_SetValueOperation.h"
|
||||
#include "COM_SplitViewerNode.h"
|
||||
|
@ -434,6 +436,12 @@ Node *COM_convert_bnode(bNode *b_node)
|
|||
case CMP_NODE_CONVERT_COLOR_SPACE:
|
||||
node = new ConvertColorSpaceNode(b_node);
|
||||
break;
|
||||
case CMP_NODE_SEPARATE_XYZ:
|
||||
node = new SeparateXYZNode(b_node);
|
||||
break;
|
||||
case CMP_NODE_COMBINE_XYZ:
|
||||
node = new CombineXYZNode(b_node);
|
||||
break;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright 2021, Blender Foundation.
|
||||
*/
|
||||
|
||||
#include "COM_CombineXYZNode.h"
|
||||
|
||||
#include "COM_ConvertOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
CombineXYZNode::CombineXYZNode(bNode *editor_node) : Node(editor_node)
|
||||
{
|
||||
}
|
||||
|
||||
void CombineXYZNode::convert_to_operations(NodeConverter &converter,
|
||||
const CompositorContext &UNUSED(context)) const
|
||||
{
|
||||
NodeInput *input_x_socket = this->get_input_socket(0);
|
||||
NodeInput *input_y_socket = this->get_input_socket(1);
|
||||
NodeInput *input_z_socket = this->get_input_socket(2);
|
||||
NodeOutput *output_socket = this->get_output_socket(0);
|
||||
|
||||
CombineChannelsOperation *operation = new CombineChannelsOperation();
|
||||
if (input_x_socket->is_linked()) {
|
||||
operation->set_canvas_input_index(0);
|
||||
}
|
||||
else if (input_y_socket->is_linked()) {
|
||||
operation->set_canvas_input_index(1);
|
||||
}
|
||||
else {
|
||||
operation->set_canvas_input_index(2);
|
||||
}
|
||||
converter.add_operation(operation);
|
||||
|
||||
converter.map_input_socket(input_x_socket, operation->get_input_socket(0));
|
||||
converter.map_input_socket(input_y_socket, operation->get_input_socket(1));
|
||||
converter.map_input_socket(input_z_socket, operation->get_input_socket(2));
|
||||
converter.map_output_socket(output_socket, operation->get_output_socket());
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright 2021, Blender Foundation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COM_Node.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
/**
|
||||
* \brief SeparateXYZNode
|
||||
* \ingroup Node
|
||||
*/
|
||||
class CombineXYZNode : public Node {
|
||||
public:
|
||||
CombineXYZNode(bNode *editor_node);
|
||||
void convert_to_operations(NodeConverter &converter,
|
||||
const CompositorContext &context) const override;
|
||||
};
|
||||
|
||||
} // namespace blender::compositor
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright 2021, Blender Foundation.
|
||||
*/
|
||||
|
||||
#include "COM_SeparateXYZNode.h"
|
||||
|
||||
#include "COM_ConvertOperation.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
SeparateXYZNode::SeparateXYZNode(bNode *editor_node) : Node(editor_node)
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void SeparateXYZNode::convert_to_operations(NodeConverter &converter,
|
||||
const CompositorContext &UNUSED(context)) const
|
||||
{
|
||||
NodeInput *vector_socket = this->get_input_socket(0);
|
||||
NodeOutput *output_x_socket = this->get_output_socket(0);
|
||||
NodeOutput *output_y_socket = this->get_output_socket(1);
|
||||
NodeOutput *output_z_socket = this->get_output_socket(2);
|
||||
|
||||
{
|
||||
SeparateChannelOperation *operation = new SeparateChannelOperation();
|
||||
operation->set_channel(0);
|
||||
converter.add_operation(operation);
|
||||
converter.map_input_socket(vector_socket, operation->get_input_socket(0));
|
||||
converter.map_output_socket(output_x_socket, operation->get_output_socket(0));
|
||||
}
|
||||
|
||||
{
|
||||
SeparateChannelOperation *operation = new SeparateChannelOperation();
|
||||
operation->set_channel(1);
|
||||
converter.add_operation(operation);
|
||||
converter.map_input_socket(vector_socket, operation->get_input_socket(0));
|
||||
converter.map_output_socket(output_y_socket, operation->get_output_socket(0));
|
||||
}
|
||||
|
||||
{
|
||||
SeparateChannelOperation *operation = new SeparateChannelOperation();
|
||||
operation->set_channel(2);
|
||||
converter.add_operation(operation);
|
||||
converter.map_input_socket(vector_socket, operation->get_input_socket(0));
|
||||
converter.map_output_socket(output_z_socket, operation->get_output_socket(0));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright 2021, Blender Foundation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COM_Node.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
/**
|
||||
* \brief SeparateXYZNode
|
||||
* \ingroup Node
|
||||
*/
|
||||
class SeparateXYZNode : public Node {
|
||||
public:
|
||||
SeparateXYZNode(bNode *editor_node);
|
||||
void convert_to_operations(NodeConverter &converter,
|
||||
const CompositorContext &context) const override;
|
||||
};
|
||||
|
||||
} // namespace blender::compositor
|
|
@ -111,9 +111,6 @@ typedef enum eDepsObjectComponentType {
|
|||
/* Parameters Component - Default when nothing else fits
|
||||
* (i.e. just SDNA property setting). */
|
||||
DEG_OB_COMP_PARAMETERS,
|
||||
/* Generic "Proxy-Inherit" Component.
|
||||
* TODO(sergey): Also for instancing of subgraphs? */
|
||||
DEG_OB_COMP_PROXY,
|
||||
/* Animation Component.
|
||||
*
|
||||
* TODO(sergey): merge in with parameters? */
|
||||
|
|
|
@ -125,10 +125,6 @@ bool DepsgraphBuilder::check_pchan_has_bbone(Object *object, const bPoseChannel
|
|||
|
||||
bool DepsgraphBuilder::check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan)
|
||||
{
|
||||
/* Proxies don't have BONE_SEGMENTS */
|
||||
if (ID_IS_LINKED(object) && object->proxy_from != nullptr) {
|
||||
return false;
|
||||
}
|
||||
return check_pchan_has_bbone(object, pchan);
|
||||
}
|
||||
|
||||
|
|
|
@ -726,9 +726,6 @@ void DepsgraphNodeBuilder::build_object(int base_index,
|
|||
eDepsNode_LinkedState_Type linked_state,
|
||||
bool is_visible)
|
||||
{
|
||||
if (object->proxy != nullptr) {
|
||||
object->proxy->proxy_from = object;
|
||||
}
|
||||
const bool has_object = built_map_.checkIsBuiltAndTag(object);
|
||||
|
||||
/* When there is already object in the dependency graph accumulate visibility an linked state
|
||||
|
@ -819,9 +816,6 @@ void DepsgraphNodeBuilder::build_object(int base_index,
|
|||
(object->pd->tex != nullptr)) {
|
||||
build_texture(object->pd->tex);
|
||||
}
|
||||
/* Proxy object to copy from. */
|
||||
build_object_proxy_from(object, is_visible);
|
||||
build_object_proxy_group(object, is_visible);
|
||||
/* Object dupligroup. */
|
||||
if (object->instance_collection != nullptr) {
|
||||
build_object_instance_collection(object, is_visible);
|
||||
|
@ -875,22 +869,6 @@ void DepsgraphNodeBuilder::build_object_flags(int base_index,
|
|||
});
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_object_proxy_from(Object *object, bool is_object_visible)
|
||||
{
|
||||
if (object->proxy_from == nullptr) {
|
||||
return;
|
||||
}
|
||||
build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_object_proxy_group(Object *object, bool is_object_visible)
|
||||
{
|
||||
if (object->proxy_group == nullptr) {
|
||||
return;
|
||||
}
|
||||
build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_object_instance_collection(Object *object, bool is_object_visible)
|
||||
{
|
||||
if (object->instance_collection == nullptr) {
|
||||
|
@ -922,12 +900,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object)
|
|||
build_object_data_geometry(object);
|
||||
break;
|
||||
case OB_ARMATURE:
|
||||
if (ID_IS_LINKED(object) && object->proxy_from != nullptr) {
|
||||
build_proxy_rig(object);
|
||||
}
|
||||
else {
|
||||
build_rig(object);
|
||||
}
|
||||
build_rig(object);
|
||||
break;
|
||||
case OB_LAMP:
|
||||
build_object_data_light(object);
|
||||
|
@ -1183,12 +1156,6 @@ void DepsgraphNodeBuilder::build_driver_variables(ID *id, FCurve *fcurve)
|
|||
}
|
||||
build_id(dtar->id);
|
||||
build_driver_id_property(dtar->id, dtar->rna_path);
|
||||
/* Corresponds to dtar_id_ensure_proxy_from(). */
|
||||
if ((GS(dtar->id->name) == ID_OB) && (((Object *)dtar->id)->proxy_from != nullptr)) {
|
||||
Object *proxy_from = ((Object *)dtar->id)->proxy_from;
|
||||
build_id(&proxy_from->id);
|
||||
build_driver_id_property(&proxy_from->id, dtar->rna_path);
|
||||
}
|
||||
}
|
||||
DRIVER_TARGETS_LOOPER_END;
|
||||
}
|
||||
|
|
|
@ -184,8 +184,6 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
|
|||
Object *object,
|
||||
eDepsNode_LinkedState_Type linked_state,
|
||||
bool is_visible);
|
||||
virtual void build_object_proxy_from(Object *object, bool is_object_visible);
|
||||
virtual void build_object_proxy_group(Object *object, bool is_object_visible);
|
||||
virtual void build_object_instance_collection(Object *object, bool is_object_visible);
|
||||
virtual void build_object_from_layer(int base_index,
|
||||
Object *object,
|
||||
|
@ -232,7 +230,6 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
|
|||
virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
|
||||
virtual void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
|
||||
virtual void build_rig(Object *object);
|
||||
virtual void build_proxy_rig(Object *object);
|
||||
virtual void build_armature(bArmature *armature);
|
||||
virtual void build_armature_bones(ListBase *bones);
|
||||
virtual void build_shapekeys(Key *key);
|
||||
|
|
|
@ -306,72 +306,4 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
|
|||
}
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
|
||||
{
|
||||
bArmature *armature = (bArmature *)object->data;
|
||||
OperationNode *op_node;
|
||||
Object *object_cow = get_cow_datablock(object);
|
||||
/* Sanity check. */
|
||||
BLI_assert(object->pose != nullptr);
|
||||
/* Armature. */
|
||||
build_armature(armature);
|
||||
/* speed optimization for animation lookups */
|
||||
BKE_pose_channels_hash_ensure(object->pose);
|
||||
if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
|
||||
BKE_pose_update_constraint_flags(object->pose);
|
||||
}
|
||||
op_node = add_operation_node(
|
||||
&object->id,
|
||||
NodeType::EVAL_POSE,
|
||||
OperationCode::POSE_INIT,
|
||||
[object_cow](::Depsgraph *depsgraph) { BKE_pose_eval_proxy_init(depsgraph, object_cow); });
|
||||
op_node->set_as_entry();
|
||||
|
||||
int pchan_index = 0;
|
||||
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
|
||||
op_node = add_operation_node(
|
||||
&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
|
||||
op_node->set_as_entry();
|
||||
/* Bone is ready for solvers. */
|
||||
add_operation_node(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY);
|
||||
/* Bone is fully evaluated. */
|
||||
op_node = add_operation_node(&object->id,
|
||||
NodeType::BONE,
|
||||
pchan->name,
|
||||
OperationCode::BONE_DONE,
|
||||
[object_cow, pchan_index](::Depsgraph *depsgraph) {
|
||||
BKE_pose_eval_proxy_copy_bone(
|
||||
depsgraph, object_cow, pchan_index);
|
||||
});
|
||||
op_node->set_as_exit();
|
||||
|
||||
/* Custom properties. */
|
||||
if (pchan->prop != nullptr) {
|
||||
build_idproperties(pchan->prop);
|
||||
add_operation_node(
|
||||
&object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name);
|
||||
}
|
||||
|
||||
/* Custom shape. */
|
||||
if (pchan->custom != nullptr) {
|
||||
/* NOTE: The relation builder will ensure visibility of the custom shape object. */
|
||||
build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, false);
|
||||
}
|
||||
|
||||
pchan_index++;
|
||||
}
|
||||
op_node = add_operation_node(&object->id,
|
||||
NodeType::EVAL_POSE,
|
||||
OperationCode::POSE_CLEANUP,
|
||||
[object_cow](::Depsgraph *depsgraph) {
|
||||
BKE_pose_eval_proxy_cleanup(depsgraph, object_cow);
|
||||
});
|
||||
op_node = add_operation_node(
|
||||
&object->id,
|
||||
NodeType::EVAL_POSE,
|
||||
OperationCode::POSE_DONE,
|
||||
[object_cow](::Depsgraph *depsgraph) { BKE_pose_eval_proxy_done(depsgraph, object_cow); });
|
||||
op_node->set_as_exit();
|
||||
}
|
||||
|
||||
} // namespace blender::deg
|
||||
|
|
|
@ -787,9 +787,6 @@ void DepsgraphRelationBuilder::build_object(Object *object)
|
|||
(object->pd->tex != nullptr)) {
|
||||
build_texture(object->pd->tex);
|
||||
}
|
||||
/* Proxy object to copy from. */
|
||||
build_object_proxy_from(object);
|
||||
build_object_proxy_group(object);
|
||||
/* Object dupligroup. */
|
||||
if (object->instance_collection != nullptr) {
|
||||
build_collection(nullptr, object, object->instance_collection);
|
||||
|
@ -804,31 +801,6 @@ void DepsgraphRelationBuilder::build_object(Object *object)
|
|||
build_parameters(&object->id);
|
||||
}
|
||||
|
||||
void DepsgraphRelationBuilder::build_object_proxy_from(Object *object)
|
||||
{
|
||||
if (object->proxy_from == nullptr) {
|
||||
return;
|
||||
}
|
||||
/* Object is linked here (comes from the library). */
|
||||
build_object(object->proxy_from);
|
||||
ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM);
|
||||
ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM);
|
||||
add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform");
|
||||
}
|
||||
|
||||
void DepsgraphRelationBuilder::build_object_proxy_group(Object *object)
|
||||
{
|
||||
if (ELEM(object->proxy_group, nullptr, object->proxy)) {
|
||||
return;
|
||||
}
|
||||
/* Object is local here (local in .blend file, users interacts with it). */
|
||||
build_object(object->proxy_group);
|
||||
OperationKey proxy_group_eval_key(
|
||||
&object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
|
||||
OperationKey transform_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
|
||||
add_relation(proxy_group_eval_key, transform_eval_key, "Proxy Group Transform");
|
||||
}
|
||||
|
||||
void DepsgraphRelationBuilder::build_object_from_layer_relations(Object *object)
|
||||
{
|
||||
OperationKey object_from_layer_entry_key(
|
||||
|
@ -895,12 +867,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object)
|
|||
break;
|
||||
}
|
||||
case OB_ARMATURE:
|
||||
if (ID_IS_LINKED(object) && object->proxy_from != nullptr) {
|
||||
build_proxy_rig(object);
|
||||
}
|
||||
else {
|
||||
build_rig(object);
|
||||
}
|
||||
build_rig(object);
|
||||
break;
|
||||
case OB_LAMP:
|
||||
build_object_data_light(object);
|
||||
|
@ -1663,18 +1630,9 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
|
|||
}
|
||||
build_id(target_id);
|
||||
build_driver_id_property(target_id, dtar->rna_path);
|
||||
/* Look up the proxy - matches dtar_id_ensure_proxy_from during evaluation. */
|
||||
Object *object = nullptr;
|
||||
if (GS(target_id->name) == ID_OB) {
|
||||
object = (Object *)target_id;
|
||||
if (object->proxy_from != nullptr) {
|
||||
/* Redirect the target to the proxy, like in evaluation. */
|
||||
object = object->proxy_from;
|
||||
target_id = &object->id;
|
||||
/* Prepare the redirected target. */
|
||||
build_id(target_id);
|
||||
build_driver_id_property(target_id, dtar->rna_path);
|
||||
}
|
||||
}
|
||||
/* Special handling for directly-named bones. */
|
||||
if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (object && object->type == OB_ARMATURE) &&
|
||||
|
|
|
@ -216,8 +216,6 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
|
|||
Object *object,
|
||||
Collection *collection);
|
||||
virtual void build_object(Object *object);
|
||||
virtual void build_object_proxy_from(Object *object);
|
||||
virtual void build_object_proxy_group(Object *object);
|
||||
virtual void build_object_from_layer_relations(Object *object);
|
||||
virtual void build_object_data(Object *object);
|
||||
virtual void build_object_data_camera(Object *object);
|
||||
|
@ -273,7 +271,6 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
|
|||
const bPoseChannel *rootchan,
|
||||
const RootPChanMap *root_map);
|
||||
virtual void build_rig(Object *object);
|
||||
virtual void build_proxy_rig(Object *object);
|
||||
virtual void build_shapekeys(Key *key);
|
||||
virtual void build_armature(bArmature *armature);
|
||||
virtual void build_armature_bones(ListBase *bones);
|
||||
|
|
|
@ -471,65 +471,4 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
|
|||
}
|
||||
}
|
||||
|
||||
void DepsgraphRelationBuilder::build_proxy_rig(Object *object)
|
||||
{
|
||||
bArmature *armature = (bArmature *)object->data;
|
||||
Object *proxy_from = object->proxy_from;
|
||||
build_armature(armature);
|
||||
OperationKey pose_init_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT);
|
||||
OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE);
|
||||
OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP);
|
||||
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
|
||||
build_idproperties(pchan->prop);
|
||||
OperationKey bone_local_key(
|
||||
&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
|
||||
OperationKey bone_ready_key(
|
||||
&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY);
|
||||
OperationKey bone_done_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE);
|
||||
OperationKey from_bone_done_key(
|
||||
&proxy_from->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE);
|
||||
add_relation(pose_init_key, bone_local_key, "Pose Init -> Bone Local");
|
||||
add_relation(bone_local_key, bone_ready_key, "Local -> Ready");
|
||||
add_relation(bone_ready_key, bone_done_key, "Ready -> Done");
|
||||
add_relation(bone_done_key, pose_cleanup_key, "Bone Done -> Pose Cleanup");
|
||||
add_relation(bone_done_key, pose_done_key, "Bone Done -> Pose Done", RELATION_FLAG_GODMODE);
|
||||
/* Make sure bone in the proxy is not done before its FROM is done. */
|
||||
if (check_pchan_has_bbone(object, pchan)) {
|
||||
OperationKey from_bone_segments_key(
|
||||
&proxy_from->id, NodeType::BONE, pchan->name, OperationCode::BONE_SEGMENTS);
|
||||
add_relation(from_bone_segments_key,
|
||||
bone_done_key,
|
||||
"Bone Segments -> Bone Done",
|
||||
RELATION_FLAG_GODMODE);
|
||||
}
|
||||
else {
|
||||
add_relation(from_bone_done_key, bone_done_key, "Bone Done -> Bone Done");
|
||||
}
|
||||
|
||||
/* Parent relation: even though the proxy bone itself doesn't need
|
||||
* the parent bone, some users expect the parent to be ready if the
|
||||
* bone itself is (e.g. for computing the local space matrix).
|
||||
*/
|
||||
if (pchan->parent != nullptr) {
|
||||
OperationKey parent_key(
|
||||
&object->id, NodeType::BONE, pchan->parent->name, OperationCode::BONE_DONE);
|
||||
add_relation(parent_key, bone_done_key, "Parent Bone -> Child Bone");
|
||||
}
|
||||
|
||||
if (pchan->prop != nullptr) {
|
||||
OperationKey bone_parameters(
|
||||
&object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name);
|
||||
OperationKey from_bone_parameters(
|
||||
&proxy_from->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name);
|
||||
add_relation(from_bone_parameters, bone_parameters, "Proxy Bone Parameters");
|
||||
}
|
||||
|
||||
/* Custom shape. */
|
||||
if (pchan->custom != nullptr) {
|
||||
build_object(pchan->custom);
|
||||
add_visibility_relation(&pchan->custom->id, &armature->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::deg
|
||||
|
|
|
@ -63,17 +63,6 @@ class DepsgraphFromIDsNodeBuilder : public DepsgraphNodeBuilder {
|
|||
return DepsgraphNodeBuilder::need_pull_base_into_graph(base);
|
||||
}
|
||||
|
||||
void build_object_proxy_group(Object *object, bool is_visible) override
|
||||
{
|
||||
if (object->proxy_group == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (!filter_.contains(&object->proxy_group->id)) {
|
||||
return;
|
||||
}
|
||||
DepsgraphNodeBuilder::build_object_proxy_group(object, is_visible);
|
||||
}
|
||||
|
||||
protected:
|
||||
DepsgraphFromIDsFilter filter_;
|
||||
};
|
||||
|
@ -96,17 +85,6 @@ class DepsgraphFromIDsRelationBuilder : public DepsgraphRelationBuilder {
|
|||
return DepsgraphRelationBuilder::need_pull_base_into_graph(base);
|
||||
}
|
||||
|
||||
void build_object_proxy_group(Object *object) override
|
||||
{
|
||||
if (object->proxy_group == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (!filter_.contains(&object->proxy_group->id)) {
|
||||
return;
|
||||
}
|
||||
DepsgraphRelationBuilder::build_object_proxy_group(object);
|
||||
}
|
||||
|
||||
protected:
|
||||
DepsgraphFromIDsFilter filter_;
|
||||
};
|
||||
|
|
|
@ -36,10 +36,7 @@ namespace deg {
|
|||
* visibility and other flags assigned to the objects.
|
||||
* All other bases (the ones which points to object which is outside of the set of IDs) are
|
||||
* completely ignored.
|
||||
*
|
||||
* - Proxy groups pointing to objects which are outside of the IDs set are also ignored.
|
||||
* This way we avoid high-poly character body pulled into the dependency graph when it's coming
|
||||
* from a library into an animation file and the dependency graph constructed for a proxy rig. */
|
||||
*/
|
||||
|
||||
class FromIDsBuilderPipeline : public AbstractBuilderPipeline {
|
||||
public:
|
||||
|
|
|
@ -99,7 +99,6 @@ static const int deg_debug_node_type_color_map[][2] = {
|
|||
|
||||
/* Outer Types */
|
||||
{NodeType::PARAMETERS, 2},
|
||||
{NodeType::PROXY, 3},
|
||||
{NodeType::ANIMATION, 4},
|
||||
{NodeType::TRANSFORM, 5},
|
||||
{NodeType::GEOMETRY, 6},
|
||||
|
@ -404,7 +403,6 @@ static void deg_debug_graphviz_node(DotExportContext &ctx,
|
|||
case NodeType::PARAMETERS:
|
||||
case NodeType::ANIMATION:
|
||||
case NodeType::TRANSFORM:
|
||||
case NodeType::PROXY:
|
||||
case NodeType::GEOMETRY:
|
||||
case NodeType::SEQUENCER:
|
||||
case NodeType::EVAL_POSE:
|
||||
|
|
|
@ -72,6 +72,14 @@ void DEG_evaluate_on_refresh(Depsgraph *graph)
|
|||
deg_graph->frame = frame;
|
||||
deg_graph->ctime = ctime;
|
||||
}
|
||||
else if (scene->id.recalc & ID_RECALC_FRAME_CHANGE) {
|
||||
/* Comparing depsgraph & scene frame fails in the case of undo,
|
||||
* since the undo state is stored before updates from the frame change have been applied.
|
||||
* In this case reading back the undo state will behave as if no updates on frame change
|
||||
* is needed as the #Depsgraph.ctime & frame will match the values in the input scene.
|
||||
* Use #ID_RECALC_FRAME_CHANGE to detect that recalculation is necessary. see: T66913. */
|
||||
deg_graph->tag_time_source();
|
||||
}
|
||||
|
||||
deg_flush_updates_and_refresh(deg_graph);
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ void depsgraph_tag_to_component_opcode(const ID *id,
|
|||
case ID_RECALC_SEQUENCER_STRIPS:
|
||||
*component_type = NodeType::SEQUENCER;
|
||||
break;
|
||||
case ID_RECALC_AUDIO_SEEK:
|
||||
case ID_RECALC_FRAME_CHANGE:
|
||||
case ID_RECALC_AUDIO_FPS:
|
||||
case ID_RECALC_AUDIO_VOLUME:
|
||||
case ID_RECALC_AUDIO_MUTE:
|
||||
|
@ -284,6 +284,7 @@ void depsgraph_tag_component(Depsgraph *graph,
|
|||
* here. */
|
||||
if (component_node == nullptr) {
|
||||
if (component_type == NodeType::ANIMATION) {
|
||||
id_node->is_cow_explicitly_tagged = true;
|
||||
depsgraph_id_tag_copy_on_write(graph, id_node, update_source);
|
||||
}
|
||||
return;
|
||||
|
@ -301,6 +302,9 @@ void depsgraph_tag_component(Depsgraph *graph,
|
|||
if (component_node->need_tag_cow_before_update()) {
|
||||
depsgraph_id_tag_copy_on_write(graph, id_node, update_source);
|
||||
}
|
||||
if (component_type == NodeType::COPY_ON_WRITE) {
|
||||
id_node->is_cow_explicitly_tagged = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is a tag compatibility with legacy code.
|
||||
|
@ -522,12 +526,6 @@ void graph_tag_ids_for_visible_update(Depsgraph *graph)
|
|||
* this. */
|
||||
for (deg::IDNode *id_node : graph->id_nodes) {
|
||||
const ID_Type id_type = GS(id_node->id_orig->name);
|
||||
if (id_type == ID_OB) {
|
||||
Object *object_orig = reinterpret_cast<Object *>(id_node->id_orig);
|
||||
if (object_orig->proxy != nullptr) {
|
||||
object_orig->proxy->proxy_from = object_orig;
|
||||
}
|
||||
}
|
||||
|
||||
if (!id_node->visible_components_mask) {
|
||||
/* ID has no components which affects anything visible.
|
||||
|
@ -733,8 +731,8 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
|
|||
return "EDITORS";
|
||||
case ID_RECALC_SEQUENCER_STRIPS:
|
||||
return "SEQUENCER_STRIPS";
|
||||
case ID_RECALC_AUDIO_SEEK:
|
||||
return "AUDIO_SEEK";
|
||||
case ID_RECALC_FRAME_CHANGE:
|
||||
return "FRAME_CHANGE";
|
||||
case ID_RECALC_AUDIO_FPS:
|
||||
return "AUDIO_FPS";
|
||||
case ID_RECALC_AUDIO_VOLUME:
|
||||
|
@ -888,6 +886,7 @@ void DEG_ids_clear_recalc(Depsgraph *depsgraph, const bool backup)
|
|||
* correctly when there are multiple depsgraph with others still using
|
||||
* the recalc flag. */
|
||||
id_node->is_user_modified = false;
|
||||
id_node->is_cow_explicitly_tagged = false;
|
||||
deg_graph_clear_id_recalc_flags(id_node->id_cow);
|
||||
if (deg_graph->is_active) {
|
||||
deg_graph_clear_id_recalc_flags(id_node->id_orig);
|
||||
|
|
|
@ -674,12 +674,6 @@ void update_pose_orig_pointers(const bPose *pose_orig, bPose *pose_cow)
|
|||
update_list_orig_pointers(&pose_orig->chanbase, &pose_cow->chanbase, &bPoseChannel::orig_pchan);
|
||||
}
|
||||
|
||||
void update_modifiers_orig_pointers(const Object *object_orig, Object *object_cow)
|
||||
{
|
||||
update_list_orig_pointers(
|
||||
&object_orig->modifiers, &object_cow->modifiers, &ModifierData::orig_modifier_data);
|
||||
}
|
||||
|
||||
void update_nla_strips_orig_pointers(const ListBase *strips_orig, ListBase *strips_cow)
|
||||
{
|
||||
NlaStrip *strip_orig = reinterpret_cast<NlaStrip *>(strips_orig->first);
|
||||
|
@ -714,25 +708,6 @@ void update_animation_data_after_copy(const ID *id_orig, ID *id_cow)
|
|||
update_nla_tracks_orig_pointers(&anim_data_orig->nla_tracks, &anim_data_cow->nla_tracks);
|
||||
}
|
||||
|
||||
/* Some builders (like motion path one) will ignore proxies from being built. This code makes it so
|
||||
* proxy and proxy_group pointers never point to an original objects, preventing evaluation code
|
||||
* from assign evaluated pointer to an original proxy->proxy_from. */
|
||||
void update_proxy_pointers_after_copy(const Depsgraph *depsgraph,
|
||||
const Object *object_orig,
|
||||
Object *object_cow)
|
||||
{
|
||||
if (object_cow->proxy != nullptr) {
|
||||
if (!deg_check_id_in_depsgraph(depsgraph, &object_orig->proxy->id)) {
|
||||
object_cow->proxy = nullptr;
|
||||
}
|
||||
}
|
||||
if (object_cow->proxy_group != nullptr) {
|
||||
if (!deg_check_id_in_depsgraph(depsgraph, &object_orig->proxy_group->id)) {
|
||||
object_cow->proxy_group = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Do some special treatment of data transfer from original ID to its
|
||||
* CoW complementary part.
|
||||
*
|
||||
|
@ -766,8 +741,6 @@ void update_id_after_copy(const Depsgraph *depsgraph,
|
|||
BKE_gpencil_update_orig_pointers(object_orig, object_cow);
|
||||
}
|
||||
update_particles_after_copy(depsgraph, object_orig, object_cow);
|
||||
update_modifiers_orig_pointers(object_orig, object_cow);
|
||||
update_proxy_pointers_after_copy(depsgraph, object_orig, object_cow);
|
||||
break;
|
||||
}
|
||||
case ID_SCE: {
|
||||
|
@ -904,7 +877,7 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode
|
|||
* modifiers.
|
||||
*
|
||||
* TODO: Investigate modes besides edit-mode. */
|
||||
if (check_datablock_expanded(id_cow)) {
|
||||
if (check_datablock_expanded(id_cow) && !id_node->is_cow_explicitly_tagged) {
|
||||
const ID_Type id_type = GS(id_orig->name);
|
||||
if (OB_DATA_SUPPORT_EDITMODE(id_type) && BKE_object_data_is_in_editmode(id_orig)) {
|
||||
/* Make sure pointers in the edit mode data are updated in the copy.
|
||||
|
|
|
@ -71,7 +71,6 @@ void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object)
|
|||
const SessionUUID &session_uuid = modifier_data->session_uuid;
|
||||
BLI_assert(BLI_session_uuid_is_generated(&session_uuid));
|
||||
|
||||
BLI_assert(modifier_data->orig_modifier_data != nullptr);
|
||||
modifier_runtime_data.add(session_uuid, ModifierDataBackup(modifier_data));
|
||||
modifier_data->runtime = nullptr;
|
||||
}
|
||||
|
@ -150,8 +149,9 @@ void ObjectRuntimeBackup::restore_to_object(Object *object)
|
|||
void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object)
|
||||
{
|
||||
LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) {
|
||||
BLI_assert(modifier_data->orig_modifier_data != nullptr);
|
||||
const SessionUUID &session_uuid = modifier_data->session_uuid;
|
||||
BLI_assert(BLI_session_uuid_is_generated(&session_uuid));
|
||||
|
||||
optional<ModifierDataBackup> backup = modifier_runtime_data.pop_try(session_uuid);
|
||||
if (backup.has_value()) {
|
||||
modifier_data->runtime = backup->runtime;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue