Initial Grease Pencil 3.0 stage #106848

Merged
Falk David merged 224 commits from filedescriptor/blender:grease-pencil-v3 into main 2023-05-30 11:14:22 +02:00
5 changed files with 100 additions and 88 deletions
Showing only changes of commit de60ebe156 - Show all commits

View File

@ -415,7 +415,7 @@ using namespace blender::bke::gpencil;
class GreasePencilDrawingRuntime {
public:
Vector<uint3> triangles_cache;
mutable SharedCache<Vector<uint3>> triangles_cache;
};
class GreasePencilRuntime {
@ -446,7 +446,6 @@ struct Object;
void *BKE_grease_pencil_add(Main *bmain, const char *name);
GreasePencil *BKE_grease_pencil_new_nomain();
BoundBox *BKE_grease_pencil_boundbox_get(Object *ob);
void BKE_grease_pencil_eval_geometry(Depsgraph *depsgraph, GreasePencil &grease_pencil);
void BKE_grease_pencil_data_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *object);

View File

@ -33,6 +33,7 @@
using blender::float3;
using blender::Span;
using blender::uint3;
using blender::Vector;
static void grease_pencil_init_data(ID *id)
@ -79,6 +80,7 @@ static void grease_pencil_copy_data(Main * /*bmain*/,
new (&dst_drawing->geometry) bke::CurvesGeometry(src_drawing->geometry.wrap());
dst_drawing->runtime = MEM_new<bke::GreasePencilDrawingRuntime>(__func__);
dst_drawing->runtime->triangles_cache = src_drawing->runtime->triangles_cache;
break;
}
case GREASE_PENCIL_DRAWING_REFERENCE: {
@ -332,75 +334,6 @@ void BKE_grease_pencil_data_update(struct Depsgraph *depsgraph, struct Scene *sc
grease_pencil_eval = BKE_grease_pencil_new_nomain();
BKE_object_eval_assign_data(object, &grease_pencil_eval->id, true);
}
else {
BKE_object_eval_assign_data(object, &grease_pencil_eval->id, false);
}
}
static void grease_pencil_drawing_calculate_fill_triangles(GreasePencilDrawing &drawing)
{
using namespace blender;
MemArena *pf_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
bke::CurvesGeometry &curves = drawing.geometry.wrap();
Span<float3> positions = curves.positions();
offset_indices::OffsetIndices<int> points_by_curve = curves.points_by_curve();
for (int curve_i : curves.curves_range()) {
IndexRange points = points_by_curve[curve_i];
if (points.size() < 3) {
continue;
}
int tot_verts = points.size();
int tot_tris = tot_verts - 2;
uint(*tris)[3] = static_cast<uint(*)[3]>(
BLI_memarena_alloc(pf_arena, sizeof(*tris) * size_t(tot_tris)));
float(*projverts)[2] = static_cast<float(*)[2]>(
BLI_memarena_alloc(pf_arena, sizeof(*projverts) * size_t(tot_verts)));
/* TODO: calculate axis_mat properly. */
float3x3 axis_mat;
axis_dominant_v3_to_m3(axis_mat.ptr(), float3(0.0f, -1.0f, 0.0f));
for (const int i : IndexRange(tot_verts)) {
mul_v2_m3v3(projverts[i], axis_mat.ptr(), positions[points[i]]);
}
BLI_polyfill_calc_arena(projverts, tot_verts, 0, tris, pf_arena);
for (const int i : IndexRange(tot_tris)) {
drawing.runtime->triangles_cache.append(uint3(tris[i]));
}
BLI_memarena_clear(pf_arena);
}
BLI_memarena_free(pf_arena);
}
void BKE_grease_pencil_eval_geometry(Depsgraph * /*depsgraph*/, GreasePencil &grease_pencil)
{
printf("BKE_grease_pencil_eval_geometry\n");
for (int i = 0; i < grease_pencil.drawing_array_size; i++) {
GreasePencilDrawingOrReference *drawing_or_ref = grease_pencil.drawing_array[i];
switch (drawing_or_ref->type) {
case GREASE_PENCIL_DRAWING: {
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_or_ref);
BLI_assert(drawing->runtime != nullptr);
drawing->runtime->triangles_cache.clear_and_shrink();
grease_pencil_drawing_calculate_fill_triangles(*drawing);
break;
}
case GREASE_PENCIL_DRAWING_REFERENCE: {
/* Pass. */
break;
}
}
}
}
/* Draw Cache */
@ -422,6 +355,76 @@ void BKE_grease_pencil_batch_cache_free(GreasePencil *grease_pencil)
}
}
/* GreasePencilDrawing API */
blender::Span<blender::uint3> GreasePencilDrawing::triangles() const
{
using namespace blender;
const bke::GreasePencilDrawingRuntime &runtime = *this->runtime;
runtime.triangles_cache.ensure([&](Vector<uint3> &cache) {
MemArena *pf_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
const bke::CurvesGeometry &curves = this->geometry.wrap();
const Span<float3> positions = curves.positions();
const offset_indices::OffsetIndices<int> points_by_curve = curves.points_by_curve();
int total_triangles = 0;
for (int curve_i : curves.curves_range()) {
IndexRange points = points_by_curve[curve_i];
if (points.size() > 2) {
total_triangles += points.size() - 2;
}
}
cache.resize(total_triangles);
int t = 0;
for (int curve_i : curves.curves_range()) {
const IndexRange points = points_by_curve[curve_i];
if (points.size() < 3) {
continue;
}
const int num_trinagles = points.size() - 2;
uint(*tris)[3] = static_cast<uint(*)[3]>(
BLI_memarena_alloc(pf_arena, sizeof(*tris) * size_t(num_trinagles)));
float(*projverts)[2] = static_cast<float(*)[2]>(
BLI_memarena_alloc(pf_arena, sizeof(*projverts) * size_t(points.size())));
/* TODO: calculate axis_mat properly. */
float3x3 axis_mat;
axis_dominant_v3_to_m3(axis_mat.ptr(), float3(0.0f, -1.0f, 0.0f));
for (const int i : IndexRange(points.size())) {
mul_v2_m3v3(projverts[i], axis_mat.ptr(), positions[points[i]]);
}
BLI_polyfill_calc_arena(projverts, points.size(), 0, tris, pf_arena);
for (const int i : IndexRange(num_trinagles)) {
cache[t] = uint3(tris[i]);
t++;
}
BLI_memarena_clear(pf_arena);
}
BLI_memarena_free(pf_arena);

Since this is making a copy of the frame, the argument might as well be a const reference rather than a non-const one.

Since this is making a copy of the frame, the argument might as well be a const reference rather than a non-const one.
});
return this->runtime->triangles_cache.data().as_span();
}
void GreasePencilDrawing::tag_positions_changed()
{

Forget if we talked about this already, but without std::move in the function, there doesn't seem to be much of a point to this second override. Usually there is one for a const reference and one for an rvalue, I haven't seen a non-const reference override like this before.

Forget if we talked about this already, but without `std::move` in the function, there doesn't seem to be much of a point to this second override. Usually there is one for a const reference and one for an rvalue, I haven't seen a non-const reference override like this before.

Maybe @JacquesLucke can clarify here, but I believe sine add_overwrite has an implementation with an r-value reference that does the std::move I think this is fine?

Maybe @JacquesLucke can clarify here, but I believe sine `add_overwrite` has an implementation with an r-value reference that does the `std::move` I think this is fine?

I recommend just using a debugger to see if this calls the function you intend to call (the one with an rvalue reference). Haven't tried right now, but it will probably call the const reference version without std::move.

I recommend just using a debugger to see if this calls the function you intend to call (the one with an rvalue reference). Haven't tried right now, but it will probably call the const reference version without `std::move`.
this->geometry.wrap().tag_positions_changed();
this->runtime->triangles_cache.tag_dirty();
}
/* GreasePencil API */

Any reason to call clear_and_shrink here? Might as well call reinitialize if not

Any reason to call `clear_and_shrink` here? Might as well call `reinitialize` if not
blender::Span<GreasePencilDrawingOrReference *> GreasePencil::drawings() const
{
return blender::Span<GreasePencilDrawingOrReference *>{this->drawing_array,
@ -468,6 +471,7 @@ void GreasePencil::read_drawing_array(BlendDataReader *reader)
drawing->geometry.runtime = MEM_new<blender::bke::CurvesGeometryRuntime>(__func__);
drawing->geometry.wrap().update_curve_types();
drawing->runtime = MEM_new<blender::bke::GreasePencilDrawingRuntime>(__func__);
drawing->runtime->triangles_cache.tag_dirty();
break;
}
case GREASE_PENCIL_DRAWING_REFERENCE: {
@ -514,6 +518,7 @@ void GreasePencil::free_drawing_array()
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_or_ref);
drawing->geometry.wrap().~CurvesGeometry();
MEM_delete(drawing->runtime);
drawing->runtime = nullptr;
MEM_freeN(drawing);
break;
}

View File

@ -1659,13 +1659,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata)
break;
}
case ID_GP: {
op_node = add_operation_node(obdata,
NodeType::GEOMETRY,
OperationCode::GEOMETRY_EVAL,
[obdata_cow](::Depsgraph *depsgraph) {
BKE_grease_pencil_eval_geometry(depsgraph,
*(GreasePencil *)obdata_cow);
});
op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL);
op_node->set_as_entry();
break;
}

View File

@ -234,24 +234,23 @@ static void grease_pencil_batches_ensure(GreasePencil &grease_pencil, int cfra)
Vector<Vector<int>> verts_start_offsets_per_visible_drawing;
Vector<Vector<int>> tris_start_offsets_per_visible_drawing;
grease_pencil.foreach_visible_drawing(cfra, [&](GreasePencilDrawing &drawing) {
bke::CurvesGeometry &curves = drawing.geometry.wrap();
offset_indices::OffsetIndices<int> points_by_curve = curves.points_by_curve();
const bke::CurvesGeometry &curves = drawing.geometry.wrap();
const offset_indices::OffsetIndices<int> points_by_curve = curves.points_by_curve();
const VArray<bool> cyclic = curves.cyclic();
Vector<int> verts_start_offsets(curves.curves_num());
Vector<int> tris_start_offsets(curves.curves_num());
int num_cyclic = count_cyclic_curves(curves);
/* One vertex is stored before and after as padding. Cyclic strokes have one extra
* vertex.*/
total_points_num += curves.points_num() + num_cyclic + curves.curves_num() * 2;
total_triangles_num += (curves.points_num() + num_cyclic) * 2;
total_triangles_num += drawing.runtime->triangles_cache.size();
/* Calculate the vertex and triangle offsets for all the curves. */
int t = 0;
int num_cyclic = 0;
for (const int curve_i : curves.curves_range()) {
IndexRange points = points_by_curve[curve_i];
const bool is_cyclic = cyclic[curve_i];
if (is_cyclic) {
num_cyclic++;
}
tris_start_offsets[curve_i] = t;
if (points.size() >= 3) {
t += points.size() - 2;
@ -260,6 +259,13 @@ static void grease_pencil_batches_ensure(GreasePencil &grease_pencil, int cfra)
verts_start_offsets[curve_i] = v;
v += 1 + points.size() + (is_cyclic ? 1 : 0) + 1;
}
/* One vertex is stored before and after as padding. Cyclic strokes have one extra
* vertex.*/
total_points_num += curves.points_num() + num_cyclic + curves.curves_num() * 2;
total_triangles_num += (curves.points_num() + num_cyclic) * 2;
total_triangles_num += drawing.triangles().size();
verts_start_offsets_per_visible_drawing.append(std::move(verts_start_offsets));
tris_start_offsets_per_visible_drawing.append(std::move(tris_start_offsets));
});
@ -298,7 +304,7 @@ static void grease_pencil_batches_ensure(GreasePencil &grease_pencil, int cfra)
"opacity", ATTR_DOMAIN_POINT, 1.0f);
const VArray<int> materials = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_CURVE, -1);

Add details about TODO. Something that helps others to pick up a task, or to understand that specific case is not expected to be yet working.

Add details about TODO. Something that helps others to pick up a task, or to understand that specific case is not expected to be yet working.
const Span<uint3> tris = drawing.runtime->triangles_cache.as_span();
const Span<uint3> triangles = drawing.triangles();
const Span<int> verts_start_offsets =
verts_start_offsets_per_visible_drawing[drawing_i].as_span();
const Span<int> tris_start_offsets =
@ -352,7 +358,7 @@ static void grease_pencil_batches_ensure(GreasePencil &grease_pencil, int cfra)
/* If the stroke has more than 2 points, add the triangle indices to the index buffer. */
if (points.size() >= 3) {
const Span<uint3> tris_slice = tris.slice(tris_start_offset, points.size() - 2);
const Span<uint3> tris_slice = triangles.slice(tris_start_offset, points.size() - 2);
for (const uint3 tri : tris_slice) {
GPU_indexbuf_add_tri_verts(&ibo,
(verts_range[1] + tri.x) << GP_VERTEX_ID_SHIFT,

View File

@ -12,6 +12,7 @@
#ifdef __cplusplus
# include "BLI_function_ref.hh"
# include "BLI_map.hh"
# include "BLI_math_vector_types.hh"
# include "BLI_span.hh"
namespace blender::bke {
class GreasePencilRuntime;
@ -63,6 +64,13 @@ typedef struct GreasePencilDrawing {
* The stroke data for this drawing.
*/
CurvesGeometry geometry;
#ifdef __cplusplus
/**
* The triangles for all the fills in the geometry.
filedescriptor marked this conversation as resolved Outdated

Move below runtime data pointer.

Move below runtime data pointer.
*/
blender::Span<blender::uint3> triangles() const;
void tag_positions_changed();
#endif
/**
* Runtime data on the drawing.
*/