Merge branch 'blender-v4.3-release'

This commit is contained in:
Julian Eisel
2024-11-07 15:50:10 +01:00
6 changed files with 73 additions and 9 deletions

View File

@@ -2918,16 +2918,16 @@ void GreasePencil::remove_drawings_with_no_users()
Array<int> drawing_index_map(drawings.size(), unchanged_index);
int first_unused_drawing = -1;
int last_used_drawing = drawings.size();
int last_used_drawing = drawings.size() - 1;
/* 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 {
} while (first_unused_drawing <= last_used_drawing && is_drawing_used(first_unused_drawing));
while (last_used_drawing >= 0 && !is_drawing_used(last_used_drawing)) {
--last_used_drawing;
} while (first_unused_drawing < last_used_drawing && !is_drawing_used(last_used_drawing));
}
return first_unused_drawing < last_used_drawing;
};
@@ -2938,10 +2938,25 @@ void GreasePencil::remove_drawings_with_no_users()
drawing_index_map[last_used_drawing] = first_unused_drawing;
}
/* `last_used_drawing` is expected to be exactly the item before the first unused drawing, once
* the loop above is fully done and all unused drawings are supposed to be at the end of the
* array. */
BLI_assert(last_used_drawing == first_unused_drawing - 1);
#ifndef NDEBUG
for (const int i : drawings.index_range()) {
if (i < first_unused_drawing) {
BLI_assert(is_drawing_used(i));
}
else {
BLI_assert(!is_drawing_used(i));
}
}
#endif
/* Tail range of unused drawings that can be removed. */
const IndexRange drawings_to_remove = (first_unused_drawing > 0) ?
drawings.index_range().drop_front(last_used_drawing +
1) :
drawings.index_range().drop_front(
first_unused_drawing) :
drawings.index_range();
if (drawings_to_remove.is_empty()) {
return;

View File

@@ -91,6 +91,36 @@ TEST(greasepencil, remove_drawings)
expected_frames_pairs_layer0[1][1]);
}
TEST(greasepencil, remove_drawings_last_unused)
{
GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(
BKE_id_new_nomain(ID_GP, "Grease Pencil test"));
/* Regression test for #129900: unused drawing at the end causes crash. */
grease_pencil->add_empty_drawings(2);
reinterpret_cast<const GreasePencilDrawing *>(grease_pencil->drawing(0))->wrap().remove_user();
reinterpret_cast<const GreasePencilDrawing *>(grease_pencil->drawing(1))->wrap().remove_user();
Layer &layer_a = grease_pencil->add_layer("LayerA");
layer_a.add_frame(10)->drawing_index = 0;
const GreasePencilDrawingBase *used_drawing = grease_pencil->drawings()[0];
grease_pencil->update_drawing_users_for_layer(layer_a);
EXPECT_EQ(layer_a.frames().size(), 1);
EXPECT_EQ(layer_a.frames().lookup(10).drawing_index, 0);
/* Test DNA storage data too. */
layer_a.prepare_for_dna_write();
EXPECT_EQ(layer_a.frames_storage.num, 1);
EXPECT_EQ(layer_a.frames_storage.values[0].drawing_index, 0);
grease_pencil->remove_drawings_with_no_users();
EXPECT_EQ(grease_pencil->drawings().size(), 1);
EXPECT_EQ(grease_pencil->drawings()[0], used_drawing);
BKE_id_free(nullptr, grease_pencil);
}
/* --------------------------------------------------------------------------------------------- */
/* Layer Tree Tests. */

View File

@@ -299,6 +299,10 @@ class JsonFormatter : public Formatter {
public:
void serialize(std::ostream &os, const Value &value) override;
/**
* \return The deserialized value or null on failure to parse the JSON contents. Typically this
* indicates a malformed file.
*/
std::unique_ptr<Value> deserialize(std::istream &is) override;
};

View File

@@ -363,8 +363,13 @@ void JsonFormatter::serialize(std::ostream &os, const Value &value)
std::unique_ptr<Value> JsonFormatter::deserialize(std::istream &is)
{
nlohmann::ordered_json j;
is >> j;
return convert_from_json(j);
try {
is >> j;
return convert_from_json(j);
}
catch (...) {
return nullptr;
}
}
void write_json_file(const StringRef path, const Value &value)

View File

@@ -566,8 +566,12 @@ class AssetIndexFile : public AbstractFile {
JsonFormatter formatter;
std::ifstream is;
is.open(this->filename);
BLI_SCOPED_DEFER([&]() { is.close(); });
std::unique_ptr<Value> read_data = formatter.deserialize(is);
is.close();
if (!read_data) {
return nullptr;
}
return std::make_unique<AssetIndex>(read_data);
}
@@ -680,6 +684,11 @@ static eFileIndexerResult read_index(const char *filename,
}
std::unique_ptr<AssetIndex> contents = asset_index_file.read_contents();
if (!contents) {
CLOG_INFO(&LOG, 3, "Asset file index is ignored; failed to read contents.");
return FILE_INDEXER_NEEDS_UPDATE;
}
if (!contents->is_latest_version()) {
CLOG_INFO(&LOG,
3,

View File

@@ -274,6 +274,7 @@ class StepObject {
if (grease_pencil.root_group_ptr) {
MEM_delete(&grease_pencil.root_group());
}
grease_pencil.set_active_node(nullptr);
grease_pencil.root_group_ptr = MEM_new<bke::greasepencil::LayerGroup>(__func__, root_group_);
BLI_assert(layers_num_ == grease_pencil.layers().size());