Blender V5.0
grease_pencil_io.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_bounds.hh"
6#include "BLI_color.hh"
7#include "BLI_listbase.h"
8#include "BLI_math_matrix.hh"
9#include "BLI_math_vector.h"
10#include "BLI_math_vector.hh"
11
12#include "BKE_attribute.hh"
13#include "BKE_camera.h"
14#include "BKE_context.hh"
15#include "BKE_crazyspace.hh"
16#include "BKE_curves.hh"
17#include "BKE_grease_pencil.hh"
18#include "BKE_layer.hh"
19#include "BKE_material.hh"
20#include "BKE_scene.hh"
21
23#include "DNA_material_types.h"
24#include "DNA_object_types.h"
25#include "DNA_scene_types.h"
26#include "DNA_view3d_types.h"
27
29
31
32#include "ED_grease_pencil.hh"
33#include "ED_object.hh"
34#include "ED_view3d.hh"
35
36#include "UI_view2d.hh"
37
39
40#include <fmt/format.h>
41#include <numeric>
42#include <optional>
43
47
49
50static float get_average(const Span<float> values)
51{
52 return values.is_empty() ? 0.0f :
53 std::accumulate(values.begin(), values.end(), 0.0f) / values.size();
54}
55
57{
58 if (values.is_empty()) {
59 return ColorGeometry4f(nullptr);
60 }
61 /* ColorGeometry4f does not support arithmetic directly. */
62 Span<float4> rgba_values = values.cast<float4>();
63 float4 avg_rgba = std::accumulate(rgba_values.begin(), rgba_values.end(), float4(0)) /
64 values.size();
65 return ColorGeometry4f(avg_rgba);
67
82
87
89{
90 const float3 cur_loc = context_.scene->cursor.location;
91 const float3 rot = float3(0.0f);
92 const ushort local_view_bits = (context_.v3d && context_.v3d->localvd) ?
93 context_.v3d->local_view_uid :
94 ushort(0);
95
97 &context_.C, OB_GREASE_PENCIL, name.c_str(), cur_loc, rot, false, local_view_bits);
98
99 return ob_gpencil;
100}
101
103 const bool stroke,
104 const bool fill)
105{
106 const ColorGeometry4f default_stroke_color = {0.0f, 0.0f, 0.0f, 1.0f};
107 const ColorGeometry4f default_fill_color = {0.5f, 0.5f, 0.5f, 1.0f};
109 /* Stroke and Fill material. */
110 if (mat_index == -1) {
111 Main *bmain = CTX_data_main(&context_.C);
112 int new_idx;
114 bmain, object_, name.c_str(), &new_idx);
115 MaterialGPencilStyle *gp_style = mat_gp->gp_style;
116 gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
117 gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
118
119 copy_v4_v4(gp_style->stroke_rgba, default_stroke_color);
120 copy_v4_v4(gp_style->fill_rgba, default_fill_color);
121 if (stroke) {
122 gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
123 }
124 if (fill) {
125 gp_style->flag |= GP_MATERIAL_FILL_SHOW;
126 }
127 mat_index = object_->totcol - 1;
128 }
129
130 return mat_index;
131}
132
137
138std::optional<Bounds<float2>> GreasePencilExporter::compute_screen_space_drawing_bounds(
139 const RegionView3D &rv3d,
140 Object &object,
141 const int layer_index,
142 const bke::greasepencil::Drawing &drawing)
143{
146
147 std::optional<Bounds<float2>> drawing_bounds = std::nullopt;
148
149 BLI_assert(object.type == OB_GREASE_PENCIL);
150 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
151
152 const Layer &layer = *grease_pencil.layers()[layer_index];
153 const float4x4 layer_to_world = layer.to_world_space(object);
154 const VArray<float> radii = drawing.radii();
155 const bke::CurvesGeometry &strokes = drawing.strokes();
156 const Span<float3> positions = strokes.positions();
157
158 IndexMaskMemory memory;
160 object, drawing, memory);
161
162 visible_strokes.foreach_index(GrainSize(512), [&](const int curve_i) {
163 const IndexRange points = strokes.points_by_curve()[curve_i];
164
165 for (const int point_i : points) {
166 const float2 screen_co = this->project_to_screen(layer_to_world, positions[point_i]);
167
168 if (screen_co.x != V2D_IS_CLIPPED) {
169 const float3 world_pos = math::transform_point(layer_to_world, positions[point_i]);
170 const float pixels = radii[point_i] / ED_view3d_pixel_size(&rv3d, world_pos);
171
172 std::optional<Bounds<float2>> point_bounds = Bounds<float2>(screen_co);
173 point_bounds->pad(pixels);
174 drawing_bounds = bounds::merge(drawing_bounds, point_bounds);
175 }
176 }
177 });
178
179 return drawing_bounds;
180}
181
182std::optional<Bounds<float2>> GreasePencilExporter::compute_objects_bounds(
183 const RegionView3D &rv3d,
184 const Depsgraph &depsgraph,
185 const Span<GreasePencilExporter::ObjectInfo> objects,
186 const int frame_number)
187{
188 using bke::greasepencil::Drawing;
189 using bke::greasepencil::Layer;
190 using ObjectInfo = GreasePencilExporter::ObjectInfo;
191
192 constexpr float gap = 10.0f;
193
194 std::optional<Bounds<float2>> full_bounds = std::nullopt;
195
196 for (const ObjectInfo &info : objects) {
197 Object *object_eval = DEG_get_evaluated(&depsgraph, info.object);
198 const GreasePencil &grease_pencil_eval = *static_cast<GreasePencil *>(object_eval->data);
199
200 for (const int layer_index : grease_pencil_eval.layers().index_range()) {
201 const Layer &layer = *grease_pencil_eval.layers()[layer_index];
202 const Drawing *drawing = grease_pencil_eval.get_drawing_at(layer, frame_number);
203 if (drawing == nullptr) {
204 continue;
205 }
206
207 std::optional<Bounds<float2>> layer_bounds = this->compute_screen_space_drawing_bounds(
208 rv3d, *object_eval, layer_index, *drawing);
209
210 full_bounds = bounds::merge(full_bounds, layer_bounds);
211 }
212 }
213
214 /* Add small gap. */
215 full_bounds->pad(gap);
216
217 return full_bounds;
218}
219
221{
222 /* Ensure camera switch is applied. */
224
225 /* Calculate camera matrix. */
226 Object *cam_ob = scene.camera;
227 if (cam_ob == nullptr) {
228 /* XXX not sure when this could ever happen if v3d camera is not null,
229 * conditions are from GPv2 and not explained anywhere. */
230 return float4x4::identity();
231 }
232
233 /* Set up parameters. */
237
238 /* Compute matrix, view-plane, etc. */
240 &params, scene.r.xsch, scene.r.ysch, scene.r.xasp, scene.r.yasp);
242
243 float4x4 viewmat = math::invert(cam_ob->object_to_world());
244 return float4x4(params.winmat) * viewmat;
245}
246
247void GreasePencilExporter::prepare_render_params(Scene &scene, const int frame_number)
248{
249 const bool use_camera_view = (context_.rv3d->persp == RV3D_CAMOB) &&
250 (context_.v3d->camera != nullptr);
251
252 if (use_camera_view) {
253 /* Camera rectangle (in screen space). */
254 rctf camera_rect;
256 context_.depsgraph,
257 context_.region,
258 context_.v3d,
259 context_.rv3d,
260 true,
261 &camera_rect);
262 screen_rect_ = {{camera_rect.xmin, camera_rect.ymin}, {camera_rect.xmax, camera_rect.ymax}};
264
265 /* Output resolution (when in camera view). */
266 int width, height;
267 BKE_render_resolution(&scene.r, false, &width, &height);
268 camera_rect_ = {{0.0f, 0.0f}, {float(width), float(height)}};
269 /* Compute factor that remaps screen_rect to final output resolution. */
270 BLI_assert(screen_rect_.size() != float2(0.0f));
272 }
273 else {
274 Vector<ObjectInfo> objects = this->retrieve_objects();
275 std::optional<Bounds<float2>> full_bounds = this->compute_objects_bounds(
276 *context_.rv3d, *context_.depsgraph, objects, frame_number);
277 screen_rect_ = full_bounds ? *full_bounds : Bounds<float2>(float2(0.0f));
278 camera_persmat_ = std::nullopt;
279 }
280}
281
283 const Material &material, const Span<ColorGeometry4f> vertex_colors)
284{
285 const MaterialGPencilStyle &gp_style = *material.gp_style;
286
287 const ColorGeometry4f material_color = ColorGeometry4f(gp_style.stroke_rgba);
288 const ColorGeometry4f avg_vertex_color = get_average(vertex_colors);
289 return math::interpolate(material_color, avg_vertex_color, avg_vertex_color.a);
290}
291
293{
294 return get_average(opacities);
295}
296
298 const RegionView3D &rv3d, const Span<float3> world_positions, const Span<float> radii)
299{
300 if (world_positions.is_empty()) {
301 return std::nullopt;
302 }
303 BLI_assert(world_positions.size() == radii.size());
304 Array<float> widths(world_positions.size());
305 threading::parallel_for(widths.index_range(), 4096, [&](const IndexRange range) {
306 for (const int index : range) {
307 const float3 &pos = world_positions[index];
308 const float radius = radii[index];
309 /* Compute the width in screen space by dividing by the pixel size at the point position. */
310 widths[index] = 2.0f * radius / ED_view3d_pixel_size(&rv3d, pos);
311 }
312 });
313 return get_average(widths);
314}
315
317{
318 using SelectMode = ExportParams::SelectMode;
319
320 Scene &scene = *CTX_data_scene(&context_.C);
321 ViewLayer *view_layer = CTX_data_view_layer(&context_.C);
322 const float3 camera_z_axis = float3(context_.rv3d->viewinv[2]);
323
324 BKE_view_layer_synced_ensure(&scene, view_layer);
325
326 Vector<ObjectInfo> objects;
327 auto add_object = [&](Object *object) {
328 if (object == nullptr || object->type != OB_GREASE_PENCIL) {
329 return;
330 }
331
332 const float3 position = object->object_to_world().location();
333
334 /* Save z-depth from view to sort from back to front. */
335 const bool use_ortho_depth = camera_persmat_ || !context_.rv3d->is_persp;
336 const float depth = use_ortho_depth ? math::dot(camera_z_axis, position) :
337 -ED_view3d_calc_zfac(context_.rv3d, position);
338 objects.append({object, depth});
339 };
340
341 switch (params_.select_mode) {
342 case SelectMode::Active:
343 add_object(params_.object);
344 break;
345 case SelectMode::Selected:
347 if (base->flag & BASE_SELECTED) {
348 add_object(base->object);
349 }
350 }
351 break;
352 case SelectMode::Visible:
354 if ((base->flag & BASE_ENABLED_RENDER) != 0) {
355 add_object(base->object);
356 }
357 }
358 break;
359 }
360
361 /* Sort list of objects from point of view. */
362 std::sort(objects.begin(), objects.end(), [](const ObjectInfo &info1, const ObjectInfo &info2) {
363 return info1.depth < info2.depth;
364 });
365
366 return objects;
367}
368
370 const bke::greasepencil::Layer &layer,
371 const bke::greasepencil::Drawing &drawing,
372 WriteStrokeFn stroke_fn)
373{
375
376 const float4x4 layer_to_world = layer.to_world_space(object);
377 const float4x4 viewmat = float4x4(context_.rv3d->viewmat);
378 const float4x4 layer_to_view = viewmat * layer_to_world;
379
380 const bke::CurvesGeometry &curves = drawing.strokes();
381 const bke::AttributeAccessor attributes = curves.attributes();
382 /* Curve attributes. */
383 const OffsetIndices points_by_curve = curves.points_by_curve();
384 const VArray<bool> cyclic = curves.cyclic();
385 const VArraySpan<int> material_indices = *attributes.lookup_or_default<int>(
386 "material_index", bke::AttrDomain::Curve, 0);
387 const VArraySpan<ColorGeometry4f> fill_colors = drawing.fill_colors();
388 const VArray<int8_t> start_caps = *attributes.lookup_or_default<int8_t>(
390 const VArray<int8_t> end_caps = *attributes.lookup_or_default<int8_t>(
391 "end_cap", bke::AttrDomain::Curve, 0);
392 /* Point attributes. */
393 const Span<float3> positions = curves.positions();
394 const Span<float3> positions_left = *curves.handle_positions_left();
395 const Span<float3> positions_right = *curves.handle_positions_right();
396 const VArray<int8_t> types = curves.curve_types();
397 const VArraySpan<float> radii = drawing.radii();
398 const VArraySpan<float> opacities = drawing.opacities();
399 const VArraySpan<ColorGeometry4f> vertex_colors = drawing.vertex_colors();
400
401 Array<float3> world_positions(positions.size());
402 math::transform_points(positions, layer_to_world, world_positions);
403
404 for (const int i_curve : curves.curves_range()) {
405 const IndexRange points = points_by_curve[i_curve];
406 const int8_t type = types[i_curve];
407 if (points.size() < 2) {
408 continue;
409 }
410
411 const bool is_cyclic = cyclic[i_curve];
412 const int material_index = material_indices[i_curve];
413 const Material *material = [&]() {
414 const Material *material = BKE_object_material_get(const_cast<Object *>(&object),
415 material_index + 1);
416 if (!material) {
417 const Material *material_default = BKE_material_default_gpencil();
418 return material_default;
419 }
420 return material;
421 }();
422
423 BLI_assert(material->gp_style != nullptr);
424 if (material->gp_style->flag & GP_MATERIAL_HIDE) {
425 continue;
426 }
427 const bool is_stroke_material = (material->gp_style->flag & GP_MATERIAL_STROKE_SHOW);
428 const bool is_fill_material = (material->gp_style->flag & GP_MATERIAL_FILL_SHOW);
429
430 /* Fill. */
431 if (is_fill_material && params_.export_fill_materials) {
432 const ColorGeometry4f material_fill_color = ColorGeometry4f(material->gp_style->fill_rgba);
433 const ColorGeometry4f fill_color = math::interpolate(
434 material_fill_color, fill_colors[i_curve], fill_colors[i_curve].a);
435 stroke_fn(positions.slice(points),
436 positions_left.slice_safe(points),
437 positions_right.slice_safe(points),
438 is_cyclic,
439 type,
440 fill_color,
441 layer.opacity,
442 std::nullopt,
443 false,
444 false);
445 }
446
447 /* Stroke. */
448 if (is_stroke_material && params_.export_stroke_materials) {
450 *material, vertex_colors.slice(points));
451 const float stroke_opacity = compute_average_stroke_opacity(opacities.slice(points)) *
452 layer.opacity;
453 const std::optional<float> uniform_width = params_.use_uniform_width ?
455 *context_.rv3d,
456 world_positions.as_span().slice(points),
457 radii.slice(points)) :
458 std::nullopt;
459 if (uniform_width) {
460 const GreasePencilStrokeCapType start_cap = GreasePencilStrokeCapType(start_caps[i_curve]);
461 const GreasePencilStrokeCapType end_cap = GreasePencilStrokeCapType(end_caps[i_curve]);
462 const bool round_cap = start_cap == GP_STROKE_CAP_TYPE_ROUND ||
463 end_cap == GP_STROKE_CAP_TYPE_ROUND;
464
465 stroke_fn(positions.slice(points),
466 positions_left.slice_safe(points),
467 positions_right.slice_safe(points),
468 is_cyclic,
469 type,
470 stroke_color,
471 stroke_opacity,
472 uniform_width,
473 round_cap,
474 false);
475 }
476 else {
477 const IndexMask single_curve_mask = IndexRange::from_single(i_curve);
478
479 constexpr int corner_subdivisions = 3;
480 constexpr float outline_radius = 0.0f;
481 constexpr float outline_offset = 0.0f;
483 single_curve_mask,
484 layer_to_view,
485 corner_subdivisions,
486 outline_radius,
487 outline_offset,
488 material_index);
489
490 /* Sample the outline stroke. */
491 if (params_.outline_resample_length > 0.0f) {
492 VArray<float> resample_lengths = VArray<float>::from_single(
493 params_.outline_resample_length, outline.curves_num());
495 outline, outline.curves_range(), resample_lengths);
496 }
497
498 const OffsetIndices outline_points_by_curve = outline.points_by_curve();
499 const Span<float3> outline_positions = outline.positions();
500 const Span<float3> outline_positions_left = *curves.handle_positions_left();
501 const Span<float3> outline_positions_right = *curves.handle_positions_right();
502
503 for (const int i_outline_curve : outline.curves_range()) {
504 const IndexRange outline_points = outline_points_by_curve[i_outline_curve];
505 /* Use stroke color to fill the outline. */
506 stroke_fn(outline_positions.slice(outline_points),
507 outline_positions_left.slice_safe(outline_points),
508 outline_positions_right.slice_safe(outline_points),
509 true,
510 type,
511 stroke_color,
512 stroke_opacity,
513 std::nullopt,
514 false,
515 true);
516 }
517 }
518 }
519 }
520}
521
523 const float3 &position) const
524{
525 const float3 world_pos = math::transform_point(transform, position);
526
527 if (camera_persmat_) {
528 /* Use camera render space. */
529 const float2 cam_space = (float2(math::project_point(*camera_persmat_, world_pos)) + 1.0f) /
530 2.0f * float2(screen_rect_.size());
531 return cam_space * camera_fac_;
532 }
533
534 /* Use 3D view screen space. */
535 float2 screen_co;
536 if (ED_view3d_project_float_global(context_.region, world_pos, screen_co, V3D_PROJ_TEST_NOP) ==
538 {
539 if (!ELEM(V2D_IS_CLIPPED, screen_co.x, screen_co.y)) {
540 /* Apply offset and scale. */
541 return screen_co - screen_rect_.min;
542 }
543 }
544
545 return float2(V2D_IS_CLIPPED);
546}
547
549 const int frame_number) const
550{
551 for (const bke::greasepencil::Layer *layer : grease_pencil.layers()) {
552 if (layer->is_visible()) {
553 const GreasePencilFrame *frame = layer->frame_at(frame_number);
554 if ((frame != nullptr) && frame->is_selected()) {
555 return true;
556 }
557 }
558 }
559 return false;
560}
561
562std::string GreasePencilExporter::coord_to_svg_string(const float2 &screen_co) const
563{
564 /* SVG has inverted Y axis. */
565 if (camera_persmat_) {
566 return fmt::format("{},{}", screen_co.x, camera_rect_.size().y - screen_co.y);
567 }
568 return fmt::format("{},{}", screen_co.x, screen_rect_.size().y - screen_co.y);
569}
570
571} // namespace blender::io::grease_pencil
Camera data-block and utility functions.
void BKE_camera_params_init(CameraParams *params)
void BKE_camera_params_from_object(CameraParams *params, const struct Object *cam_ob)
void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy)
void BKE_camera_params_compute_matrix(CameraParams *params)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
Material * BKE_grease_pencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index)
int BKE_grease_pencil_object_material_index_get_by_name(Object *ob, const char *name)
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
General operations, lookup, etc. for materials.
Material * BKE_material_default_gpencil()
Material * BKE_object_material_get(Object *ob, short act)
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2915
bool BKE_scene_camera_switch_update(Scene *scene)
Definition scene.cc:2265
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
MINLINE void copy_v4_v4(float r[4], const float a[4])
unsigned short ushort
#define ELEM(...)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
GreasePencilStrokeCapType
@ GP_STROKE_CAP_TYPE_ROUND
struct GreasePencil GreasePencil
@ BASE_ENABLED_RENDER
@ GP_MATERIAL_HIDE
@ GP_MATERIAL_STROKE_SHOW
@ GP_MATERIAL_FILL_SHOW
Object is a sort of wrapper for general info.
@ OB_GREASE_PENCIL
struct Object Object
#define BASE_SELECTED(v3d, base)
struct RegionView3D RegionView3D
@ RV3D_CAMOB
@ V3D_PROJ_TEST_NOP
Definition ED_view3d.hh:279
float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
@ V3D_PROJ_RET_OK
Definition ED_view3d.hh:256
float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3])
void ED_view3d_calc_camera_border(const Scene *scene, const Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, const RegionView3D *rv3d, bool no_shift, rctf *r_viewborder)
eV3DProjStatus ED_view3d_project_float_global(const ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
#define V2D_IS_CLIPPED
Definition UI_view2d.hh:21
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
const GreasePencilFrame * frame_at(const int frame_number) const
Span< T > as_span() const
Definition BLI_array.hh:243
IndexRange index_range() const
Definition BLI_array.hh:360
ChannelStorageType a
constexpr int64_t size() const
static constexpr IndexRange from_single(const int64_t index)
Span< NewT > constexpr cast() const
Definition BLI_span.hh:418
constexpr Span slice_safe(const int64_t start, const int64_t size) const
Definition BLI_span.hh:154
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr const T * end() const
Definition BLI_span.hh:224
constexpr const T * begin() const
Definition BLI_span.hh:220
constexpr bool is_empty() const
Definition BLI_span.hh:260
static VArray from_single(T value, const int64_t size)
void append(const T &value)
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
OffsetIndices< int > points_by_curve() const
IndexRange curves_range() const
std::optional< Span< float3 > > handle_positions_left() const
Span< float3 > positions() const
std::optional< Span< float3 > > handle_positions_right() const
AttributeAccessor attributes() const
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
VArray< ColorGeometry4f > vertex_colors() const
const bke::CurvesGeometry & strokes() const
VArray< ColorGeometry4f > fill_colors() const
VArray< float > opacities() const
float4x4 to_world_space(const Object &object) const
void foreach_index(Fn &&fn) const
GreasePencilExporter(const IOContext &context, const ExportParams &params)
std::string coord_to_svg_string(const float2 &screen_co) const
static std::optional< float > try_get_uniform_point_width(const RegionView3D &rv3d, const Span< float3 > world_positions, const Span< float > radii)
FunctionRef< void(const Span< float3 > positions, const Span< float3 > positions_left, const Span< float3 > positions_right, bool cyclic, int8_t type, const ColorGeometry4f &color, float opacity, std::optional< float > width, bool round_cap, bool is_outline)> WriteStrokeFn
static ColorGeometry4f compute_average_stroke_color(const Material &material, const Span< ColorGeometry4f > vertex_colors)
void prepare_render_params(Scene &scene, int frame_number)
void foreach_stroke_in_layer(const Object &object, const bke::greasepencil::Layer &layer, const bke::greasepencil::Drawing &drawing, WriteStrokeFn stroke_fn)
bool is_selected_frame(const GreasePencil &grease_pencil, int frame_number) const
static float compute_average_stroke_opacity(const Span< float > opacities)
float2 project_to_screen(const float4x4 &transform, const float3 &position) const
GreasePencilImporter(const IOContext &context, const ImportParams &params)
int32_t create_material(StringRefNull name, bool stroke, bool fill)
nullptr float
static bool is_cyclic(const Nurb *nu)
#define rot(x, k)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static char ** types
Definition makesdna.cc:71
Bounds< T > merge(const Bounds< T > &a, const Bounds< T > &b)
Definition BLI_bounds.hh:26
IndexMask retrieve_visible_strokes(Object &object, const bke::greasepencil::Drawing &drawing, IndexMaskMemory &memory)
bke::CurvesGeometry create_curves_outline(const bke::greasepencil::Drawing &drawing, const IndexMask &strokes, const float4x4 &transform, const int corner_subdivisions, const float outline_radius, const float outline_offset, const int material_index)
Object * add_type(bContext *C, int type, const char *name, const float loc[3], const float rot[3], bool enter_editmode, unsigned short local_view_bits) ATTR_NONNULL(1) ATTR_RETURNS_NONNULL
CurvesGeometry resample_to_length(const CurvesGeometry &src_curves, const IndexMask &selection, const VArray< float > &sample_lengths, const ResampleCurvesOutputAttributeIDs &output_ids={}, bool keep_last_segment=false)
static float4x4 persmat_from_camera_object(Scene &scene)
static float get_average(const Span< float > values)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
CartesianBasis invert(const CartesianBasis &basis)
VectorT project_point(const MatT &mat, const VectorT &point)
T interpolate(const T &a, const T &b, const FactorT &t)
void transform_points(const float4x4 &transform, MutableSpan< float3 > points, bool use_threading=true)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
const char * name
struct MaterialGPencilStyle * gp_style
struct RenderData r
struct Object * camera
IOContext(bContext &C, const ARegion *region, const View3D *v3d, const RegionView3D *rv3d, ReportList *reports)
float xmax
float xmin
float ymax
float ymin