WIP: Brush assets project #106303
|
@ -30,7 +30,7 @@ but some areas are still being extended and improved.
|
|||
Before Starting
|
||||
===============
|
||||
|
||||
This document its intended to familiarize you with Blender Python API
|
||||
This document is intended to familiarize you with Blender Python API
|
||||
but not to fully cover each topic.
|
||||
|
||||
A quick list of helpful things to know before starting:
|
||||
|
|
|
@ -406,7 +406,12 @@ def draw_keymaps(context, layout):
|
|||
rowsubsub = rowsub.row(align=True)
|
||||
if not ok:
|
||||
rowsubsub.alert = True
|
||||
rowsubsub.prop(spref, "filter_text", text="", icon='VIEWZOOM')
|
||||
search_placeholder = ""
|
||||
if spref.filter_type == 'NAME':
|
||||
search_placeholder = iface_("Search by Name")
|
||||
elif spref.filter_type == 'KEY':
|
||||
search_placeholder = iface_("Search by Key-Binding")
|
||||
rowsubsub.prop(spref, "filter_text", text="", icon='VIEWZOOM', placeholder=search_placeholder)
|
||||
|
||||
if not filter_text:
|
||||
# When the keyconfig defines its own preferences.
|
||||
|
|
|
@ -435,6 +435,7 @@ void BKE_crazyspace_build_sculpt(Depsgraph *depsgraph,
|
|||
VirtualModifierData virtual_modifier_data;
|
||||
Object object_eval;
|
||||
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
|
||||
BLI_SCOPED_DEFER([&]() { MEM_delete(object_eval.runtime); });
|
||||
ModifierData *md = BKE_modifiers_get_virtual_modifierlist(&object_eval,
|
||||
&virtual_modifier_data);
|
||||
const ModifierEvalContext mectx = {depsgraph, &object_eval, ModifierApplyFlag(0)};
|
||||
|
|
|
@ -2233,91 +2233,97 @@ bool GreasePencil::remove_frames(blender::bke::greasepencil::Layer &layer,
|
|||
return false;
|
||||
}
|
||||
|
||||
static void remove_drawings_unchecked(GreasePencil &grease_pencil,
|
||||
Span<int64_t> sorted_indices_to_remove)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
if (grease_pencil.drawing_array_num == 0 || sorted_indices_to_remove.is_empty()) {
|
||||
return;
|
||||
}
|
||||
const int64_t drawings_to_remove = sorted_indices_to_remove.size();
|
||||
const blender::IndexRange last_drawings_range(
|
||||
grease_pencil.drawings().size() - drawings_to_remove, drawings_to_remove);
|
||||
|
||||
/* We keep track of the next available index (for swapping) by iterating from the end and
|
||||
* skipping over drawings that are already in the range to be removed. */
|
||||
auto next_available_index = last_drawings_range.last();
|
||||
auto greatest_index_to_remove_it = std::rbegin(sorted_indices_to_remove);
|
||||
auto get_next_available_index = [&]() {
|
||||
while (next_available_index == *greatest_index_to_remove_it) {
|
||||
greatest_index_to_remove_it = std::prev(greatest_index_to_remove_it);
|
||||
next_available_index--;
|
||||
}
|
||||
return next_available_index;
|
||||
};
|
||||
|
||||
/* Move the drawings to be removed to the end of the array by swapping the pointers. Make sure to
|
||||
* remap any frames pointing to the drawings being swapped. */
|
||||
for (const int64_t index_to_remove : sorted_indices_to_remove) {
|
||||
if (index_to_remove >= last_drawings_range.first()) {
|
||||
/* This drawing and all the next drawings are already in the range to be removed. */
|
||||
break;
|
||||
}
|
||||
const int64_t swap_index = get_next_available_index();
|
||||
/* Remap the drawing_index for frames that point to the drawing to be swapped with. */
|
||||
for (Layer *layer : grease_pencil.layers_for_write()) {
|
||||
for (auto [key, value] : layer->frames_for_write().items()) {
|
||||
if (value.drawing_index == swap_index) {
|
||||
value.drawing_index = index_to_remove;
|
||||
layer->tag_frames_map_changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Swap the pointers to the drawings in the drawing array. */
|
||||
std::swap(grease_pencil.drawing_array[index_to_remove],
|
||||
grease_pencil.drawing_array[swap_index]);
|
||||
next_available_index--;
|
||||
}
|
||||
|
||||
/* Free the last drawings. */
|
||||
for (const int64_t drawing_index : last_drawings_range) {
|
||||
GreasePencilDrawingBase *drawing_base_to_remove = grease_pencil.drawing(drawing_index);
|
||||
switch (drawing_base_to_remove->type) {
|
||||
case GP_DRAWING: {
|
||||
GreasePencilDrawing *drawing_to_remove = reinterpret_cast<GreasePencilDrawing *>(
|
||||
drawing_base_to_remove);
|
||||
MEM_delete(&drawing_to_remove->wrap());
|
||||
break;
|
||||
}
|
||||
case GP_DRAWING_REFERENCE: {
|
||||
GreasePencilDrawingReference *drawing_reference_to_remove =
|
||||
reinterpret_cast<GreasePencilDrawingReference *>(drawing_base_to_remove);
|
||||
MEM_delete(&drawing_reference_to_remove->wrap());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Shrink drawing array. */
|
||||
shrink_array<GreasePencilDrawingBase *>(
|
||||
&grease_pencil.drawing_array, &grease_pencil.drawing_array_num, drawings_to_remove);
|
||||
}
|
||||
|
||||
void GreasePencil::remove_drawings_with_no_users()
|
||||
{
|
||||
using namespace blender;
|
||||
Vector<int64_t> drawings_to_be_removed;
|
||||
for (const int64_t drawing_i : this->drawings().index_range()) {
|
||||
GreasePencilDrawingBase *drawing_base = this->drawing(drawing_i);
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
/* Compress the drawings array by finding unused drawings.
|
||||
* In every step two indices are found:
|
||||
* - The next unused drawing from the start
|
||||
* - The last used drawing from the end
|
||||
* These two drawings are then swapped. Rinse and repeat until both iterators meet somewhere in
|
||||
* the middle. At this point the drawings array is fully compressed.
|
||||
* Then the drawing indices in frame data are remapped. */
|
||||
|
||||
const MutableSpan<GreasePencilDrawingBase *> drawings = this->drawings();
|
||||
if (drawings.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto is_drawing_used = [&](const int drawing_index) {
|
||||
GreasePencilDrawingBase *drawing_base = drawings[drawing_index];
|
||||
/* Note: GreasePencilDrawingReference does not have a user count currently, but should
|
||||
* eventually be counted like GreasePencilDrawing. */
|
||||
if (drawing_base->type != GP_DRAWING) {
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
|
||||
if (!drawing->wrap().has_users()) {
|
||||
drawings_to_be_removed.append(drawing_i);
|
||||
return drawing->wrap().has_users();
|
||||
};
|
||||
|
||||
/* Index map to remap drawing indices in frame data.
|
||||
* Index -1 indicates that the drawing has not been moved. */
|
||||
constexpr const int unchanged_index = -1;
|
||||
Array<int> drawing_index_map(drawings.size(), unchanged_index);
|
||||
|
||||
int first_unused_drawing = -1;
|
||||
int last_used_drawing = drawings.size();
|
||||
/* Advance head and tail iterators to the next unused/used drawing respectively.
|
||||
* Returns true if an index pair was found that needs to be swapped. */
|
||||
auto find_next_swap_index = [&]() -> bool {
|
||||
do {
|
||||
++first_unused_drawing;
|
||||
} while (first_unused_drawing < last_used_drawing && is_drawing_used(first_unused_drawing));
|
||||
do {
|
||||
--last_used_drawing;
|
||||
} while (first_unused_drawing < last_used_drawing && !is_drawing_used(last_used_drawing));
|
||||
|
||||
return first_unused_drawing < last_used_drawing;
|
||||
};
|
||||
|
||||
while (find_next_swap_index()) {
|
||||
/* Found two valid iterators, now swap drawings. */
|
||||
std::swap(drawings[first_unused_drawing], drawings[last_used_drawing]);
|
||||
drawing_index_map[last_used_drawing] = first_unused_drawing;
|
||||
}
|
||||
|
||||
/* Tail range of unused drawings that can be removed. */
|
||||
const IndexRange drawings_to_remove = drawings.index_range().drop_front(last_used_drawing + 1);
|
||||
if (drawings_to_remove.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Free the unused drawings. */
|
||||
for (const int i : drawings_to_remove) {
|
||||
GreasePencilDrawingBase *unused_drawing_base = drawings[i];
|
||||
switch (unused_drawing_base->type) {
|
||||
case GP_DRAWING: {
|
||||
auto *unused_drawing = reinterpret_cast<GreasePencilDrawing *>(unused_drawing_base);
|
||||
MEM_delete(&unused_drawing->wrap());
|
||||
break;
|
||||
}
|
||||
case GP_DRAWING_REFERENCE: {
|
||||
auto *unused_drawing_ref = reinterpret_cast<GreasePencilDrawingReference *>(
|
||||
unused_drawing_base);
|
||||
MEM_delete(&unused_drawing_ref->wrap());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
shrink_array<GreasePencilDrawingBase *>(
|
||||
&this->drawing_array, &this->drawing_array_num, drawings_to_remove.size());
|
||||
|
||||
/* Remap drawing indices in frame data. */
|
||||
for (Layer *layer : this->layers_for_write()) {
|
||||
for (auto [key, value] : layer->frames_for_write().items()) {
|
||||
const int new_drawing_index = drawing_index_map[value.drawing_index];
|
||||
if (new_drawing_index != unchanged_index) {
|
||||
value.drawing_index = new_drawing_index;
|
||||
layer->tag_frames_map_changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
remove_drawings_unchecked(*this, drawings_to_be_removed.as_span());
|
||||
}
|
||||
|
||||
void GreasePencil::update_drawing_users_for_layer(const blender::bke::greasepencil::Layer &layer)
|
||||
|
|
|
@ -929,27 +929,26 @@ Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain,
|
|||
return mesh_in_bmain;
|
||||
}
|
||||
|
||||
/* Make sure mesh only points original data-blocks, also increase users of materials and other
|
||||
* possibly referenced data-blocks.
|
||||
/* Make sure mesh only points to original data-blocks. Also increase user count of materials and
|
||||
* other possibly referenced data-blocks.
|
||||
*
|
||||
* Going to original data-blocks is required to have bmain in a consistent state, where
|
||||
* Changing to original data-blocks is required to have bmain in a consistent state, where
|
||||
* everything is only allowed to reference original data-blocks.
|
||||
*
|
||||
* Note that user-count updates has to be done *after* mesh has been transferred to Main database
|
||||
* (since doing reference-counting on non-Main IDs is forbidden). */
|
||||
* Note that user-count updates have to be done *after* the mesh has been transferred to Main
|
||||
* database (since doing reference-counting on non-Main IDs is forbidden). */
|
||||
BKE_library_foreach_ID_link(
|
||||
nullptr, &mesh->id, foreach_libblock_make_original_callback, nullptr, IDWALK_NOP);
|
||||
|
||||
/* Append the mesh to 'bmain'.
|
||||
* We do it a bit longer way since there is no simple and clear way of adding existing data-block
|
||||
* to the 'bmain'. So we allocate new empty mesh in the 'bmain' (which guarantees all the naming
|
||||
* and orders and flags) and move the temporary mesh in place there. */
|
||||
/* Add the mesh to 'bmain'. We do it in a bit longer way since there is no simple and clear way
|
||||
* of adding existing data-blocks to the 'bmain'. So we create new empty mesh (which guarantees
|
||||
* all the naming and order and flags) and move the temporary mesh in place there. */
|
||||
Mesh *mesh_in_bmain = BKE_mesh_add(bmain, mesh->id.name + 2);
|
||||
|
||||
/* NOTE: BKE_mesh_nomain_to_mesh() does not copy materials and instead it preserves them in the
|
||||
/* NOTE: BKE_mesh_nomain_to_mesh() does not copy materials and instead preserves them in the
|
||||
* destination mesh. So we "steal" materials before calling it.
|
||||
*
|
||||
* TODO(sergey): We really better have a function which gets and ID and accepts it for the bmain.
|
||||
* TODO(sergey): We really ought to have a function which gets an ID and accepts it into #Main.
|
||||
*/
|
||||
mesh_in_bmain->mat = mesh->mat;
|
||||
mesh_in_bmain->totcol = mesh->totcol;
|
||||
|
|
|
@ -408,8 +408,8 @@ template<typename T>
|
|||
/**
|
||||
* \brief Create an orthographic projection matrix using OpenGL coordinate convention:
|
||||
* Maps each axis range to [-1..1] range for all axes except Z.
|
||||
* The Z axis is collapsed to 0 which eliminates the depth component. So it cannot be used with
|
||||
* depth testing.
|
||||
* The Z axis is almost collapsed to 0 which eliminates the depth component.
|
||||
* So it should not be used with depth testing.
|
||||
* The resulting matrix can be used with either #project_point or #transform_point.
|
||||
*/
|
||||
template<typename T> MatBase<T, 4, 4> orthographic_infinite(T left, T right, T bottom, T top);
|
||||
|
@ -1581,7 +1581,8 @@ MatBase<T, 4, 4> orthographic(T left, T right, T bottom, T top, T near_clip, T f
|
|||
return mat;
|
||||
}
|
||||
|
||||
template<typename T> MatBase<T, 4, 4> orthographic_infinite(T left, T right, T bottom, T top)
|
||||
template<typename T>
|
||||
MatBase<T, 4, 4> orthographic_infinite(T left, T right, T bottom, T top, T near_clip)
|
||||
{
|
||||
const T x_delta = right - left;
|
||||
const T y_delta = top - bottom;
|
||||
|
@ -1592,8 +1593,13 @@ template<typename T> MatBase<T, 4, 4> orthographic_infinite(T left, T right, T b
|
|||
mat[3][0] = -(right + left) / x_delta;
|
||||
mat[1][1] = T(2.0) / y_delta;
|
||||
mat[3][1] = -(top + bottom) / y_delta;
|
||||
mat[2][2] = 0.0f;
|
||||
mat[3][2] = 0.0f;
|
||||
/* Page 17. Choosing an epsilon for 32 bit floating-point precision. */
|
||||
constexpr float eps = 2.4e-7f;
|
||||
/* From "Projection Matrix Tricks" by Eric Lengyel GDC 2007.
|
||||
* Following same procedure as the reference but for orthographic matrix.
|
||||
* This avoids degenerate matrix (0 determinant). */
|
||||
mat[2][2] = -eps;
|
||||
mat[3][2] = -1.0f - eps * near_clip;
|
||||
}
|
||||
return mat;
|
||||
}
|
||||
|
|
|
@ -406,6 +406,12 @@ void DepsgraphNodeBuilder::begin_build()
|
|||
saved_entry_tags_.append_as(op_node);
|
||||
}
|
||||
|
||||
for (const OperationNode *op_node : graph_->operations) {
|
||||
if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
|
||||
needs_update_operations_.append_as(op_node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure graph has no nodes left from previous state. */
|
||||
graph_->clear_all_nodes();
|
||||
graph_->operations.clear();
|
||||
|
@ -537,6 +543,16 @@ void DepsgraphNodeBuilder::tag_previously_tagged_nodes()
|
|||
* that originally node was explicitly tagged for user update. */
|
||||
operation_node->tag_update(graph_, DEG_UPDATE_SOURCE_USER_EDIT);
|
||||
}
|
||||
|
||||
/* Restore needs-update flags since the previous state of the dependency graph, ensuring the
|
||||
* previously-skipped operations are properly re-evaluated when needed. */
|
||||
for (const OperationKey &operation_key : needs_update_operations_) {
|
||||
OperationNode *operation_node = find_operation_node(operation_key);
|
||||
if (operation_node == nullptr) {
|
||||
continue;
|
||||
}
|
||||
operation_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::end_build()
|
||||
|
|
|
@ -291,9 +291,14 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
|
|||
};
|
||||
|
||||
protected:
|
||||
/* Entry tags from the previous state of the dependency graph.
|
||||
/* Entry tags and non-updated operations from the previous state of the dependency graph.
|
||||
* The entry tags are operations which were directly tagged, the matching operations from the
|
||||
* new dependency graph will be tagged. The needs-update operations are possibly indirectly
|
||||
* modified operations, whose complementary part from the new dependency graph will only be
|
||||
* marked as needs-update.
|
||||
* Stored before the graph is re-created so that they can be transferred over. */
|
||||
Vector<PersistentOperationKey> saved_entry_tags_;
|
||||
Vector<PersistentOperationKey> needs_update_operations_;
|
||||
|
||||
struct BuilderWalkUserData {
|
||||
DepsgraphNodeBuilder *builder;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "eevee_pipeline.hh"
|
||||
|
||||
#include "eevee_volume.hh"
|
||||
#include <iostream>
|
||||
|
||||
namespace blender::eevee {
|
||||
|
||||
|
@ -333,7 +332,7 @@ void VolumeModule::draw_prepass(View &main_view)
|
|||
* way, surfaces that are further away than the far clip plane will still be voxelized.*/
|
||||
winmat_infinite = main_view.is_persp() ?
|
||||
math::projection::perspective_infinite(left, right, bottom, top, near) :
|
||||
math::projection::orthographic_infinite(left, right, bottom, top);
|
||||
math::projection::orthographic_infinite(left, right, bottom, top, near);
|
||||
/* We still need a bounded projection matrix to get correct froxel location. */
|
||||
winmat_finite = main_view.is_persp() ?
|
||||
math::projection::perspective(left, right, bottom, top, near, far) :
|
||||
|
|
|
@ -111,18 +111,36 @@ static void extract_normals_mesh(const MeshRenderData &mr, MutableSpan<GPUType>
|
|||
template<typename GPUType>
|
||||
static void extract_paint_overlay_flags(const MeshRenderData &mr, MutableSpan<GPUType> normals)
|
||||
{
|
||||
if (mr.select_poly.is_empty() && mr.hide_poly.is_empty() && (!mr.edit_bmesh || !mr.v_origindex))
|
||||
{
|
||||
const bool use_face_select = (mr.mesh->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
|
||||
Span<bool> selection;
|
||||
if (mr.mesh->editflag & ME_EDIT_PAINT_FACE_SEL) {
|
||||
selection = mr.select_poly;
|
||||
}
|
||||
else if (mr.mesh->editflag & ME_EDIT_PAINT_VERT_SEL) {
|
||||
selection = mr.select_vert;
|
||||
}
|
||||
if (selection.is_empty() && mr.hide_poly.is_empty() && (!mr.edit_bmesh || !mr.v_origindex)) {
|
||||
return;
|
||||
}
|
||||
const OffsetIndices faces = mr.faces;
|
||||
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
|
||||
if (!mr.select_poly.is_empty()) {
|
||||
const Span<bool> select_poly = mr.select_poly;
|
||||
for (const int face : range) {
|
||||
if (select_poly[face]) {
|
||||
if (!selection.is_empty()) {
|
||||
if (use_face_select) {
|
||||
for (const int face : range) {
|
||||
if (selection[face]) {
|
||||
for (const int corner : faces[face]) {
|
||||
normals[corner].w = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const Span<int> corner_verts = mr.corner_verts;
|
||||
for (const int face : range) {
|
||||
for (const int corner : faces[face]) {
|
||||
normals[corner].w = 1;
|
||||
if (selection[corner_verts[corner]]) {
|
||||
normals[corner].w = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,6 +129,8 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op)
|
|||
|
||||
params.global_scale = RNA_float_get(op->ptr, "global_scale");
|
||||
|
||||
RNA_string_get(op->ptr, "collection", params.collection);
|
||||
|
||||
/* Take some defaults from the scene, if not specified explicitly. */
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
if (params.frame_start == INT_MIN) {
|
||||
|
@ -144,7 +146,7 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op)
|
|||
return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
|
||||
static void ui_alembic_export_settings(const bContext *C, uiLayout *layout, PointerRNA *imfptr)
|
||||
{
|
||||
uiLayout *box, *row, *col, *sub;
|
||||
|
||||
|
@ -185,9 +187,12 @@ static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
|
|||
IFACE_("Custom Properties"),
|
||||
ICON_NONE);
|
||||
|
||||
sub = uiLayoutColumnWithHeading(col, true, IFACE_("Only"));
|
||||
uiItemR(sub, imfptr, "selected", UI_ITEM_NONE, IFACE_("Selected Objects"), ICON_NONE);
|
||||
uiItemR(sub, imfptr, "visible_objects_only", UI_ITEM_NONE, IFACE_("Visible Objects"), ICON_NONE);
|
||||
if (CTX_wm_space_file(C)) {
|
||||
sub = uiLayoutColumnWithHeading(col, true, IFACE_("Only"));
|
||||
uiItemR(sub, imfptr, "selected", UI_ITEM_NONE, IFACE_("Selected Objects"), ICON_NONE);
|
||||
uiItemR(
|
||||
sub, imfptr, "visible_objects_only", UI_ITEM_NONE, IFACE_("Visible Objects"), ICON_NONE);
|
||||
}
|
||||
|
||||
col = uiLayoutColumn(box, true);
|
||||
uiItemR(col, imfptr, "evaluation_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
|
@ -247,7 +252,7 @@ static void wm_alembic_export_draw(bContext *C, wmOperator *op)
|
|||
RNA_boolean_set(op->ptr, "init_scene_frame_range", false);
|
||||
}
|
||||
|
||||
ui_alembic_export_settings(op->layout, op->ptr);
|
||||
ui_alembic_export_settings(C, op->layout, op->ptr);
|
||||
}
|
||||
|
||||
static bool wm_alembic_export_check(bContext * /*C*/, wmOperator *op)
|
||||
|
@ -365,6 +370,9 @@ void WM_OT_alembic_export(wmOperatorType *ot)
|
|||
"Flatten Hierarchy",
|
||||
"Do not preserve objects' parent/children relationship");
|
||||
|
||||
prop = RNA_def_string(ot->srna, "collection", nullptr, MAX_IDPROP_NAME, "Collection", nullptr);
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
|
||||
RNA_def_boolean(ot->srna, "uvs", true, "UVs", "Export UVs");
|
||||
|
||||
RNA_def_boolean(ot->srna, "packuv", true, "Pack UV Islands", "Export UVs with packed island");
|
||||
|
@ -724,6 +732,7 @@ void alembic_file_handler_add()
|
|||
auto fh = std::make_unique<blender::bke::FileHandlerType>();
|
||||
STRNCPY(fh->idname, "IO_FH_alembic");
|
||||
STRNCPY(fh->import_operator, "WM_OT_alembic_import");
|
||||
STRNCPY(fh->export_operator, "WM_OT_alembic_export");
|
||||
STRNCPY(fh->label, "Alembic");
|
||||
STRNCPY(fh->file_extensions_str, ".abc");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
|
|
|
@ -225,9 +225,7 @@ static const char *node_socket_get_translation_context(const bNodeSocket &socket
|
|||
return translation_context.data();
|
||||
}
|
||||
|
||||
static void node_socket_add_tooltip_in_node_editor(const bNodeTree &ntree,
|
||||
const bNodeSocket &sock,
|
||||
uiLayout &layout);
|
||||
static void node_socket_add_tooltip_in_node_editor(const bNodeSocket &sock, uiLayout &layout);
|
||||
|
||||
/** Return true when \a a should be behind \a b and false otherwise. */
|
||||
static bool compare_node_depth(const bNode *a, const bNode *b)
|
||||
|
@ -520,12 +518,12 @@ static bool node_update_basis_socket(const bContext &C,
|
|||
}
|
||||
|
||||
if (input_socket) {
|
||||
node_socket_add_tooltip_in_node_editor(ntree, *input_socket, *row);
|
||||
node_socket_add_tooltip_in_node_editor(*input_socket, *row);
|
||||
/* Round the socket location to stop it from jiggling. */
|
||||
input_socket->runtime->location = float2(round(locx), round(locy - NODE_DYS));
|
||||
}
|
||||
if (output_socket) {
|
||||
node_socket_add_tooltip_in_node_editor(ntree, *output_socket, *row);
|
||||
node_socket_add_tooltip_in_node_editor(*output_socket, *row);
|
||||
/* Round the socket location to stop it from jiggling. */
|
||||
output_socket->runtime->location = float2(round(locx + NODE_WIDTH(node)),
|
||||
round(locy - NODE_DYS));
|
||||
|
@ -1579,20 +1577,6 @@ static std::optional<std::string> create_socket_inspection_string(
|
|||
return str;
|
||||
}
|
||||
|
||||
static bool node_socket_has_tooltip(const bNodeTree &ntree, const bNodeSocket &socket)
|
||||
{
|
||||
if (ntree.type == NTREE_GEOMETRY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (socket.runtime->declaration != nullptr) {
|
||||
const nodes::SocketDeclaration &socket_decl = *socket.runtime->declaration;
|
||||
return !socket_decl.description.empty();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string node_socket_get_tooltip(const SpaceNode *snode,
|
||||
const bNodeTree &ntree,
|
||||
const bNodeSocket &socket)
|
||||
|
@ -1647,13 +1631,8 @@ static std::string node_socket_get_tooltip(const SpaceNode *snode,
|
|||
return output.str();
|
||||
}
|
||||
|
||||
static void node_socket_add_tooltip_in_node_editor(const bNodeTree &ntree,
|
||||
const bNodeSocket &sock,
|
||||
uiLayout &layout)
|
||||
static void node_socket_add_tooltip_in_node_editor(const bNodeSocket &sock, uiLayout &layout)
|
||||
{
|
||||
if (!node_socket_has_tooltip(ntree, sock)) {
|
||||
return;
|
||||
}
|
||||
uiLayoutSetTooltipFunc(
|
||||
&layout,
|
||||
[](bContext *C, void *argN, const char * /*tip*/) {
|
||||
|
@ -1670,10 +1649,6 @@ static void node_socket_add_tooltip_in_node_editor(const bNodeTree &ntree,
|
|||
|
||||
void node_socket_add_tooltip(const bNodeTree &ntree, const bNodeSocket &sock, uiLayout &layout)
|
||||
{
|
||||
if (!node_socket_has_tooltip(ntree, sock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct SocketTooltipData {
|
||||
const bNodeTree *ntree;
|
||||
const bNodeSocket *socket;
|
||||
|
@ -1727,10 +1702,6 @@ static void node_socket_draw_nested(const bContext &C,
|
|||
size_id,
|
||||
outline_col_id);
|
||||
|
||||
if (!node_socket_has_tooltip(ntree, sock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ideally sockets themselves should be buttons, but they aren't currently. So add an invisible
|
||||
* button on top of them for the tooltip. */
|
||||
const eUIEmbossType old_emboss = UI_block_emboss_get(&block);
|
||||
|
|
|
@ -60,6 +60,8 @@ struct AlembicExportParams {
|
|||
int ngon_method;
|
||||
|
||||
float global_scale;
|
||||
|
||||
char collection[MAX_IDPROP_NAME] = "";
|
||||
};
|
||||
|
||||
struct AlembicImportParams {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_global.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_main.hh"
|
||||
#include "BKE_scene.hh"
|
||||
|
||||
|
@ -49,14 +50,27 @@ struct ExportJobData {
|
|||
namespace blender::io::alembic {
|
||||
|
||||
/* Construct the depsgraph for exporting. */
|
||||
static void build_depsgraph(Depsgraph *depsgraph, const bool visible_objects_only)
|
||||
static bool build_depsgraph(ExportJobData *job)
|
||||
{
|
||||
if (visible_objects_only) {
|
||||
DEG_graph_build_from_view_layer(depsgraph);
|
||||
if (strlen(job->params.collection) > 0) {
|
||||
Collection *collection = reinterpret_cast<Collection *>(
|
||||
BKE_libblock_find_name(job->bmain, ID_GR, job->params.collection));
|
||||
if (!collection) {
|
||||
WM_reportf(
|
||||
RPT_ERROR, "Alembic Export: Unable to find collection '%s'", job->params.collection);
|
||||
return false;
|
||||
}
|
||||
|
||||
DEG_graph_build_from_collection(job->depsgraph, collection);
|
||||
}
|
||||
else if (job->params.visible_objects_only) {
|
||||
DEG_graph_build_from_view_layer(job->depsgraph);
|
||||
}
|
||||
else {
|
||||
DEG_graph_build_for_all_objects(depsgraph);
|
||||
DEG_graph_build_for_all_objects(job->depsgraph);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void report_job_duration(const ExportJobData *data)
|
||||
|
@ -208,7 +222,9 @@ bool ABC_export(Scene *scene,
|
|||
*
|
||||
* Has to be done from main thread currently, as it may affect Main original data (e.g. when
|
||||
* doing deferred update of the view-layers, see #112534 for details). */
|
||||
blender::io::alembic::build_depsgraph(job->depsgraph, job->params.visible_objects_only);
|
||||
if (!blender::io::alembic::build_depsgraph(job)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool export_ok = false;
|
||||
if (as_background_job) {
|
||||
|
|
|
@ -322,7 +322,7 @@ static Sequence *sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase
|
|||
}
|
||||
|
||||
if (seq->type == SEQ_TYPE_SCENE && (seq->flag & SEQ_SCENE_STRIPS)) {
|
||||
if (sequencer_check_scene_recursion(scene, &seq->scene->ed->seqbase)) {
|
||||
if (seq->scene->ed && sequencer_check_scene_recursion(scene, &seq->scene->ed->seqbase)) {
|
||||
return seq;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue