34#include <fmt/format.h>
53static std::string
get_layer_id(
const NSVGshape &shape,
const int prefix)
55 return (shape.id_parent[0] ==
'\0') ? fmt::format(
"Layer_{:03d}", prefix) :
56 fmt::format(
"{:s}", shape.id_parent);
62 const uchar4 rgb_u = {uint8_t(((pack) >> 0) & 0xFF),
63 uint8_t(((pack) >> 8) & 0xFF),
64 uint8_t(((pack) >> 16) & 0xFF),
65 uint8_t(((pack) >> 24) & 0xFF)};
67 float(rgb_u[1]) / 255.0f,
68 float(rgb_u[2]) / 255.0f,
69 float(rgb_u[3]) / 255.0f};
89 avg_color /= stops.
size();
100 switch (NSVGpaintType(svg_paint.type)) {
101 case NSVG_PAINT_UNDEF:
103 case NSVG_PAINT_NONE:
105 case NSVG_PAINT_COLOR:
107 case NSVG_PAINT_LINEAR_GRADIENT:
109 case NSVG_PAINT_RADIAL_GRADIENT:
122 const int old_curves_num = curves.
curves_num();
123 const int old_points_num = curves.
points_num();
128 for (NSVGpath *path = shape.paths; path; path = path->next) {
129 if (path->npts == 0) {
132 BLI_assert(path->npts >= 1 && path->npts ==
int(path->npts / 3) * 3 + 1);
135 const int point_num = (path->npts + 2) / 3;
136 new_curve_offsets.
append(point_num);
141 new_curve_offsets.
append(0);
143 new_curve_offsets, old_points_num);
145 const IndexRange new_curves_range = {old_curves_num, new_points_by_curve.
size()};
147 const int points_num = new_points_by_curve.
total_size() + old_points_num;
150 if (old_curves_num > 0) {
154 .slice(old_curves_num, new_curve_offsets.
size())
155 .copy_from(new_curve_offsets);
157 curves.
resize(points_num, curves_num);
162 return new_curves_range;
166 const NSVGshape &shape,
169 const int material_index)
202 materials.
span.slice(curves_range).fill(material_index);
205 fill_colors.
span.slice(curves_range).fill(shape_color);
207 if (fill_opacities) {
208 fill_opacities.span.slice(curves_range).fill(shape_color.
a);
211 int curve_index = curves_range.
start();
212 for (NSVGpath *path = shape.paths; path; path = path->next) {
213 if (path->npts == 0) {
217 cyclic[curve_index] = bool(path->closed);
222 const IndexRange points = points_by_curve[curve_index];
223 for (
const int i : points.index_range()) {
224 const int point_index = points[
i];
225 const float2 pos_center = svg_path_data[
i * 3];
226 const float2 pos_handle_left = (
i > 0) ? svg_path_data[
i * 3 - 1] : pos_center;
227 const float2 pos_handle_right = (
i < points.size() - 1) ? svg_path_data[
i * 3 + 1] :
231 float3(pos_handle_left, 0.0f));
233 float3(pos_handle_right, 0.0f));
237 radii.
span[point_index] = shape.strokeWidth * path_width_scale;
241 vertex_colors.span[point_index] = point_color;
243 if (point_opacities) {
244 point_opacities.span[point_index] = point_color.
a;
253 fill_opacities.finish();
255 vertex_colors.finish();
256 point_opacities.finish();
263 const std::optional<Bounds<float3>>
bounds = [&]() {
264 std::optional<Bounds<float3>>
bounds;
292 constexpr const char *svg_units =
"mm";
293 constexpr float svg_dpi = 96.0f;
299 NSVGimage *svg_data =
nullptr;
300 svg_data = nsvgParseFromFile(abs_filepath, svg_units, svg_dpi);
301 if (svg_data ==
nullptr) {
312 nsvgDelete(svg_data);
322 const float svg_scale = 0.001f * scene_unit_scale *
params_.scale;
328 bool has_color_gradient =
false;
331 std::string prv_id =
"*";
333 for (NSVGshape *shape = svg_data->shapes; shape; shape = shape->next) {
335 if (prv_id != layer_id) {
344 if (layer_node && layer_node->
is_layer()) {
355 if (drawing ==
nullptr) {
363 const bool is_fill = bool(shape->fill.type);
364 const bool is_stroke = bool(shape->stroke.type) || !is_fill;
365 const StringRefNull mat_name = (is_stroke ? (is_fill ?
"Both" :
"Stroke") :
"Fill");
366 const int material_index =
create_material(mat_name, is_stroke, is_fill);
368 if (
ELEM(shape->fill.type, NSVG_PAINT_LINEAR_GRADIENT, NSVG_PAINT_RADIAL_GRADIENT)) {
369 has_color_gradient =
true;
383 nsvgDelete(svg_data);
390 if (has_color_gradient) {
393 "SVG has gradients, Grease Pencil color will be approximated");
402 return importer.
read(filepath);
Low-level operations for curves.
Low-level operations for grease pencil.
const char * BKE_main_blendfile_path_from_global()
void BKE_report(ReportList *reports, eReportType type, const char *message)
#define BLI_assert_unreachable()
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
void void void BLI_path_split_file_part(const char *filepath, char *file, size_t file_maxncpy) ATTR_NONNULL(1
char * STRNCPY(char(&dst)[N], const char *src)
@ GP_LAYER_TREE_NODE_USE_LIGHTS
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
constexpr void copy_from(Span< T > values) const
MutableSpan< T > as_mutable_span()
constexpr int64_t one_after_last() const
constexpr bool is_empty() const
constexpr int64_t start() const
Span< NewT > constexpr cast() const
constexpr Span drop_back(int64_t n) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
constexpr const char * c_str() const
void append(const T &value)
MutableSpan< float3 > positions_for_write()
void translate(const float3 &translation)
OffsetIndices< int > points_by_curve() const
MutableSpan< int8_t > handle_types_right_for_write()
void update_curve_types()
MutableSpan< int8_t > curve_types_for_write()
MutableSpan< float3 > handle_positions_left_for_write()
MutableAttributeAccessor attributes_for_write()
MutableSpan< float3 > handle_positions_right_for_write()
Span< int > offsets() const
void tag_topology_changed()
void resize(int points_num, int curves_num)
void tag_positions_changed()
MutableSpan< int > offsets_for_write()
std::optional< Bounds< float3 > > bounds_min_max(bool use_radius=true) const
MutableSpan< bool > cyclic_for_write()
MutableSpan< int8_t > handle_types_left_for_write()
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
void tag_positions_changed()
const TreeNode & as_node() const
const Layer & as_layer() const
GreasePencilImporter(const IOContext &context, const ImportParams ¶ms)
int32_t create_material(StringRefNull name, bool stroke, bool fill)
Object * create_object(StringRefNull name)
const ImportParams params_
GreasePencilImporter(const IOContext &context, const ImportParams ¶ms)
bool read(StringRefNull filepath)
Bounds< T > merge(const Bounds< T > &a, const Bounds< T > &b)
static void shape_attributes_to_curves(bke::CurvesGeometry &curves, const NSVGshape &shape, const IndexRange curves_range, const float4x4 &transform, const int material_index)
static void shift_to_bounds_center(GreasePencil &grease_pencil)
static ColorGeometry4f average_gradient_color(const NSVGgradient &svg_gradient)
bool import_svg(const IOContext &context, const ImportParams ¶ms, StringRefNull filepath)
static ColorGeometry4f unpack_nano_color(const uint pack)
static ColorGeometry4f convert_svg_color(const NSVGpaint &svg_paint)
static IndexRange extend_curves_geometry(bke::CurvesGeometry &curves, const NSVGshape &shape)
static std::string get_layer_id(const NSVGshape &shape, const int prefix)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
EulerXYZBase< float > EulerXYZ
T average(const VecBase< T, Size > &a)
VecBase< T, 3 > to_scale(const MatBase< T, NumCol, NumRow > &mat)
MatT from_rotation(const RotationT &rotation)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
MatBase< float, 4, 4 > float4x4
blender::VecBase< uint8_t, 4 > uchar4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
float wrap(float value, float max, float min)
MutableVArraySpan< T > span