mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-16 19:05:59 +08:00
Fix for whistle model. Issue 51.3
Sort patches by distance to expolygon projection depth center and add patches until expolygon is filled
This commit is contained in:
parent
f75777a948
commit
9fef0cd091
@ -373,16 +373,18 @@ bool is_over_whole_expoly(const SurfacePatch &patch,
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patch">Contain loops and vertices</param>
|
/// <param name="patch">Contain loops and vertices</param>
|
||||||
/// <param name="projection">Know how to project from 3d to 2d</param>
|
/// <param name="projection">Know how to project from 3d to 2d</param>
|
||||||
|
/// <param name="depth_range">Range of unprojected points x .. min, y .. max value</param>
|
||||||
/// <returns>Unprojected points in loops</returns>
|
/// <returns>Unprojected points in loops</returns>
|
||||||
Polygons unproject_loops(const SurfacePatch &patch, const Project &projection);
|
Polygons unproject_loops(const SurfacePatch &patch, const Project &projection, Vec2d &depth_range);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unproject points from loops and create expolygons
|
/// Unproject points from loops and create expolygons
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patch"></param>
|
/// <param name="patch">Patch to convert on expolygon</param>
|
||||||
/// <param name="projection">Convert 3d point to 2d</param>
|
/// <param name="projection">Convert 3d point to 2d</param>
|
||||||
/// <returns></returns>
|
/// <param name="depth_range">Range of unprojected points x .. min, y .. max value</param>
|
||||||
ExPolygon to_expoly(const SurfacePatch &patch, const Project &projection);
|
/// <returns>Expolygon represent patch in 2d</returns>
|
||||||
|
ExPolygon to_expoly(const SurfacePatch &patch, const Project &projection, Vec2d &depth_range);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// To select surface near projection distance
|
/// To select surface near projection distance
|
||||||
@ -3170,7 +3172,7 @@ std::vector<bool> priv::select_patches(const ProjectionDistances &best_distances
|
|||||||
{
|
{
|
||||||
// extension to cover numerical mistake made by back projection patch from 3d to 2d
|
// extension to cover numerical mistake made by back projection patch from 3d to 2d
|
||||||
const float extend_delta = 5.f / Emboss::SHAPE_SCALE; // [Font points scaled by Emboss::SHAPE_SCALE]
|
const float extend_delta = 5.f / Emboss::SHAPE_SCALE; // [Font points scaled by Emboss::SHAPE_SCALE]
|
||||||
|
|
||||||
// vector of patches for shape
|
// vector of patches for shape
|
||||||
std::vector<std::vector<uint32_t>> used_shapes_patches(shapes.size());
|
std::vector<std::vector<uint32_t>> used_shapes_patches(shapes.size());
|
||||||
std::vector<bool> in_distances(patches.size(), {false});
|
std::vector<bool> in_distances(patches.size(), {false});
|
||||||
@ -3189,115 +3191,134 @@ std::vector<bool> priv::select_patches(const ProjectionDistances &best_distances
|
|||||||
for (const SurfacePatch &patch : patches)
|
for (const SurfacePatch &patch : patches)
|
||||||
shapes_patches[patch.shape_id].push_back(&patch - &patches.front());
|
shapes_patches[patch.shape_id].push_back(&patch - &patches.front());
|
||||||
|
|
||||||
for (size_t shape_index = 0; shape_index < shapes.size(); shape_index++)
|
for (size_t shape_index = 0; shape_index < shapes.size(); shape_index++) {
|
||||||
{
|
|
||||||
const ExPolygon &shape = shapes[shape_index];
|
const ExPolygon &shape = shapes[shape_index];
|
||||||
const std::vector<uint32_t> &used_shape_patches = used_shapes_patches[shape_index];
|
std::vector<uint32_t> &used_shape_patches = used_shapes_patches[shape_index];
|
||||||
if (used_shape_patches.empty()) continue;
|
if (used_shape_patches.empty()) continue;
|
||||||
|
// is used all exist patches?
|
||||||
|
if (used_shapes_patches.size() == shapes_patches[shape_index].size()) continue;
|
||||||
if (used_shape_patches.size() == 1) {
|
if (used_shape_patches.size() == 1) {
|
||||||
uint32_t patch_index = used_shape_patches.front();
|
uint32_t patch_index = used_shape_patches.front();
|
||||||
const SurfacePatch &patch = patches[patch_index];
|
const SurfacePatch &patch = patches[patch_index];
|
||||||
if (is_over_whole_expoly(patch, shapes, cutAOIs, meshes)) continue;
|
if (is_over_whole_expoly(patch, shapes, cutAOIs, meshes)) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// only shapes contain multiple patches
|
// only shapes containing multiple patches
|
||||||
// or not full filled are hard processed
|
// or not full filled are back projected (hard processed)
|
||||||
|
|
||||||
// convert patch to 2d
|
// intersection of converted patches to 2d
|
||||||
ExPolygons fill;
|
ExPolygons fill;
|
||||||
fill.reserve(used_shape_patches.size());
|
fill.reserve(used_shape_patches.size());
|
||||||
for (uint32_t patch_index : used_shape_patches) {
|
|
||||||
ExPolygon patch_area = to_expoly(patches[patch_index], projection);
|
// Heuristics to predict which patch to be used need average patch depth
|
||||||
|
Vec2d used_patches_depth(std::numeric_limits<double>::max(), std::numeric_limits<double>::min());
|
||||||
|
for (uint32_t patch_index : used_shape_patches) {
|
||||||
|
ExPolygon patch_area = to_expoly(patches[patch_index], projection, used_patches_depth);
|
||||||
//*/
|
//*/
|
||||||
ExPolygons patch_areas = offset_ex(patch_area, extend_delta);
|
ExPolygons patch_areas = offset_ex(patch_area, extend_delta);
|
||||||
fill.insert(fill.end(), patch_areas.begin(), patch_areas.end());
|
fill.insert(fill.end(), patch_areas.begin(), patch_areas.end());
|
||||||
/*/
|
/*/
|
||||||
// without save extension
|
// without save extension
|
||||||
fill.push_back(patch_area);
|
fill.push_back(patch_area);
|
||||||
//*/
|
//*/
|
||||||
}
|
}
|
||||||
|
fill = union_ex(fill);
|
||||||
|
|
||||||
|
// not cutted area of expolygon
|
||||||
ExPolygons rest = diff_ex(ExPolygons{shape}, fill, ApplySafetyOffset::Yes);
|
ExPolygons rest = diff_ex(ExPolygons{shape}, fill, ApplySafetyOffset::Yes);
|
||||||
|
#ifdef DEBUG_OUTPUT_DIR
|
||||||
|
SVG svg(DEBUG_OUTPUT_DIR + "input_patches_" + std::to_string(shape_index) + ".svg");
|
||||||
|
svg.draw(fill, "darkgreen");
|
||||||
|
svg.draw(rest, "green");
|
||||||
|
#endif // DEBUG_OUTPUT_DIR
|
||||||
|
|
||||||
|
// already filled by multiple patches
|
||||||
if (rest.empty()) continue;
|
if (rest.empty()) continue;
|
||||||
|
|
||||||
// find patches overlaed rest area
|
// find patches overlaped rest area
|
||||||
fill = union_ex(fill);
|
|
||||||
struct PatchShape{
|
struct PatchShape{
|
||||||
uint32_t patch_index;
|
uint32_t patch_index;
|
||||||
ExPolygon shape;
|
ExPolygon shape;
|
||||||
ExPolygons intersection;
|
ExPolygons intersection;
|
||||||
|
double depth_range_center_distance; // always positive
|
||||||
};
|
};
|
||||||
using PatchShapes = std::vector<PatchShape>;
|
using PatchShapes = std::vector<PatchShape>;
|
||||||
PatchShapes patch_shapes;
|
PatchShapes patch_shapes;
|
||||||
|
|
||||||
|
double used_patches_depth_center = (used_patches_depth[0] + used_patches_depth[1]) / 2;
|
||||||
|
|
||||||
|
// sort used_patches for faster search
|
||||||
|
std::sort(used_shape_patches.begin(), used_shape_patches.end());
|
||||||
for (uint32_t patch_index : shapes_patches[shape_index]) {
|
for (uint32_t patch_index : shapes_patches[shape_index]) {
|
||||||
// check is patch already used
|
// check is patch already used
|
||||||
auto it = std::lower_bound(used_shape_patches.begin(), used_shape_patches.end(), patch_index);
|
auto it = std::lower_bound(used_shape_patches.begin(), used_shape_patches.end(), patch_index);
|
||||||
if (it != used_shape_patches.end() && *it == patch_index) continue;
|
if (it != used_shape_patches.end() && *it == patch_index) continue;
|
||||||
ExPolygon patch_shape = to_expoly(patches[patch_index], projection);
|
|
||||||
|
// Heuristics to predict which patch to be used need average patch depth
|
||||||
|
Vec2d patche_depth_range(std::numeric_limits<double>::max(), std::numeric_limits<double>::min());
|
||||||
|
ExPolygon patch_shape = to_expoly(patches[patch_index], projection, patche_depth_range);
|
||||||
|
double depth_center = (patche_depth_range[0] + patche_depth_range[1]) / 2;
|
||||||
|
double depth_range_center_distance = std::fabs(used_patches_depth_center - depth_center);
|
||||||
|
|
||||||
ExPolygons patch_intersection = intersection_ex(ExPolygons{patch_shape}, rest);
|
ExPolygons patch_intersection = intersection_ex(ExPolygons{patch_shape}, rest);
|
||||||
if (patch_intersection.empty()) continue;
|
if (patch_intersection.empty()) continue;
|
||||||
|
|
||||||
patch_shapes.push_back({patch_index, patch_shape, patch_intersection});
|
patch_shapes.push_back({patch_index, patch_shape, patch_intersection, depth_range_center_distance});
|
||||||
}
|
}
|
||||||
|
|
||||||
// how to select which patch to use
|
// nothing to add
|
||||||
//
|
if (patch_shapes.empty()) continue;
|
||||||
// by depth:
|
// only one solution to add
|
||||||
// how to calc wanted depth - idealy by depth of hole outline points
|
if (patch_shapes.size() == 1) {
|
||||||
//
|
used_shape_patches.push_back(patch_shapes.front().patch_index);
|
||||||
// how to calc patch depth - by average outline depth
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Idea: Get depth range of used patches and add patches in order by distance to used depth center
|
||||||
|
std::sort(patch_shapes.begin(), patch_shapes.end(), [](const PatchShape &a, const PatchShape &b)
|
||||||
|
{ return a.depth_range_center_distance < b.depth_range_center_distance; });
|
||||||
|
|
||||||
|
#ifdef DEBUG_OUTPUT_DIR
|
||||||
|
for (const auto &p : patch_shapes) {
|
||||||
|
int gray_level = 30 + (&p - &patch_shapes.front()) * 200 / patch_shapes.size() ;
|
||||||
|
std::stringstream color;
|
||||||
|
color << "#" << std::hex << std::setfill('0') << std::setw(2) << gray_level << gray_level << gray_level;
|
||||||
|
svg.draw(p.shape, color.str());
|
||||||
|
svg.draw(p.intersection, color.str());
|
||||||
|
}
|
||||||
|
#endif // DEBUG_OUTPUT_DIR
|
||||||
|
|
||||||
|
for (const PatchShape &patch : patch_shapes) {
|
||||||
|
// Check when exist some place to fill
|
||||||
|
ExPolygons patch_intersection = intersection_ex(patch.intersection, rest);
|
||||||
|
if (patch_intersection.empty()) continue;
|
||||||
|
|
||||||
|
// Extend for sure
|
||||||
|
ExPolygons intersection = offset_ex(patch.intersection, extend_delta);
|
||||||
|
rest = diff_ex(rest, intersection, ApplySafetyOffset::Yes);
|
||||||
|
|
||||||
|
used_shape_patches.push_back(patch.patch_index);
|
||||||
|
if (rest.empty()) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// QUESTION: How to select which patch to use? How to sort them?
|
||||||
|
// Now is used back projection distance from used patches
|
||||||
|
//
|
||||||
|
// Idealy by outline depth: (need ray cast into patches)
|
||||||
|
// how to calc wanted depth - idealy by depth of outline help to overlap
|
||||||
|
// how to calc patch depth - depth in place of outline position
|
||||||
|
// Which outline to use between
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// For sure of the bounding boxes intersection
|
|
||||||
const double bb_extension = 1e-10;
|
|
||||||
const Vec3d bb_ext(bb_extension, bb_extension, bb_extension);
|
|
||||||
auto extend_bb = [&bb_ext](const BoundingBoxf3 &bb) {
|
|
||||||
return BoundingBoxf3(
|
|
||||||
bb.min - bb_ext,
|
|
||||||
bb.max + bb_ext);
|
|
||||||
};
|
|
||||||
|
|
||||||
// queue to flood fill by patches
|
|
||||||
std::vector<size_t> patch_indices;
|
|
||||||
|
|
||||||
std::vector<bool> result(patches.size(), {false});
|
std::vector<bool> result(patches.size(), {false});
|
||||||
for (const ProjectionDistance &d : best_distances) {
|
for (const std::vector<uint32_t> &patches: used_shapes_patches)
|
||||||
// exist valid projection for shape point?
|
for (uint32_t patch_index : patches) {
|
||||||
if (d.patch_index == std::numeric_limits<uint32_t>::max()) continue;
|
assert(patch_index < result.size());
|
||||||
if (result[d.patch_index]) continue;
|
// check only onece insertation of patch
|
||||||
// Add all connected patches
|
assert(!result[patch_index]);
|
||||||
// This is way to add patche(from other models) without source shape point
|
|
||||||
// 1. Patches inside of shape
|
|
||||||
// 2. Patches crossing outline between shape points
|
|
||||||
|
|
||||||
assert(patch_indices.empty());
|
|
||||||
patch_indices.push_back(d.patch_index);
|
|
||||||
do {
|
|
||||||
size_t patch_index = patch_indices.back();
|
|
||||||
patch_indices.pop_back();
|
|
||||||
if (result[patch_index]) continue;
|
|
||||||
result[patch_index] = true;
|
result[patch_index] = true;
|
||||||
const SurfacePatch &patch = patches[patch_index];
|
}
|
||||||
BoundingBoxf3 bb = extend_bb(patch.bb);
|
|
||||||
for (const SurfacePatch &patch2 : patches) {
|
|
||||||
// IMPROVE: check patches only from same shape (ExPolygon)
|
|
||||||
size_t patch_index2 = &patch2 - &patches.front();
|
|
||||||
// is already filled?
|
|
||||||
if (result[patch_index2]) continue;
|
|
||||||
// only patches made by same shape could be connected
|
|
||||||
if (patch.shape_id != patch2.shape_id) continue;
|
|
||||||
BoundingBoxf3 bb2 = extend_bb(patch2.bb);
|
|
||||||
if (!bb.intersects(bb2)) continue;
|
|
||||||
if (!in_distances[patch_index2]) {
|
|
||||||
// TODO: check that really exist shared outline between patches
|
|
||||||
|
|
||||||
}
|
|
||||||
patch_indices.push_back(patch_index2);
|
|
||||||
}
|
|
||||||
} while (!patch_indices.empty());
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3364,7 +3385,7 @@ priv::Loops priv::create_loops(const std::vector<HI> &outlines, const CutMesh& m
|
|||||||
return loops;
|
return loops;
|
||||||
}
|
}
|
||||||
|
|
||||||
Polygons priv::unproject_loops(const SurfacePatch &patch, const Project &projection)
|
Polygons priv::unproject_loops(const SurfacePatch &patch, const Project &projection, Vec2d &depth_range)
|
||||||
{
|
{
|
||||||
assert(!patch.loops.empty());
|
assert(!patch.loops.empty());
|
||||||
if (patch.loops.empty()) return {};
|
if (patch.loops.empty()) return {};
|
||||||
@ -3374,6 +3395,11 @@ Polygons priv::unproject_loops(const SurfacePatch &patch, const Project &project
|
|||||||
polys.reserve(patch.loops.size());
|
polys.reserve(patch.loops.size());
|
||||||
// project conture into 2d space to fillconvert outlines to
|
// project conture into 2d space to fillconvert outlines to
|
||||||
|
|
||||||
|
size_t count = 0;
|
||||||
|
for (const Loop &l : patch.loops) count += l.size();
|
||||||
|
std::vector<float> depths;
|
||||||
|
depths.reserve(count);
|
||||||
|
|
||||||
Points pts;
|
Points pts;
|
||||||
for (const Loop &l : patch.loops) {
|
for (const Loop &l : patch.loops) {
|
||||||
pts.clear();
|
pts.clear();
|
||||||
@ -3381,14 +3407,17 @@ Polygons priv::unproject_loops(const SurfacePatch &patch, const Project &project
|
|||||||
for (VI vi : l) {
|
for (VI vi : l) {
|
||||||
const P3 &p3 = patch.mesh.point(vi);
|
const P3 &p3 = patch.mesh.point(vi);
|
||||||
Vec3d p(p3.x(), p3.y(), p3.z());
|
Vec3d p(p3.x(), p3.y(), p3.z());
|
||||||
std::optional<Point> p2_opt = projection.unproject(p);
|
double depth;
|
||||||
|
std::optional<Vec2d> p2_opt = projection.unproject(p, &depth);
|
||||||
|
if (depth_range[0] > depth) depth_range[0] = depth; // min
|
||||||
|
if (depth_range[1] < depth) depth_range[1] = depth; // max
|
||||||
// Check when appear that skip is enough for poit which can't be unprojected
|
// Check when appear that skip is enough for poit which can't be unprojected
|
||||||
// - it could break contour
|
// - it could break contour
|
||||||
assert(p2_opt.has_value());
|
assert(p2_opt.has_value());
|
||||||
if (!p2_opt.has_value()) continue;
|
if (!p2_opt.has_value()) continue;
|
||||||
|
|
||||||
pts.push_back(*p2_opt);
|
pts.push_back(p2_opt->cast<Point::coord_type>());
|
||||||
|
depths.push_back(static_cast<float>(depth));
|
||||||
}
|
}
|
||||||
// minimal is triangle
|
// minimal is triangle
|
||||||
assert(pts.size() >= 3);
|
assert(pts.size() >= 3);
|
||||||
@ -3401,9 +3430,9 @@ Polygons priv::unproject_loops(const SurfacePatch &patch, const Project &project
|
|||||||
return polys;
|
return polys;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExPolygon priv::to_expoly(const SurfacePatch &patch, const Project &projection)
|
ExPolygon priv::to_expoly(const SurfacePatch &patch, const Project &projection, Vec2d &depth_range)
|
||||||
{
|
{
|
||||||
Polygons polys = unproject_loops(patch, projection);
|
Polygons polys = unproject_loops(patch, projection, depth_range);
|
||||||
// should not be used when no opposit triangle are counted so should not create overlaps
|
// should not be used when no opposit triangle are counted so should not create overlaps
|
||||||
ClipperLib::PolyFillType fill_type = ClipperLib::PolyFillType::pftEvenOdd;
|
ClipperLib::PolyFillType fill_type = ClipperLib::PolyFillType::pftEvenOdd;
|
||||||
ExPolygons expolys = Slic3r::union_ex(polys, fill_type);
|
ExPolygons expolys = Slic3r::union_ex(polys, fill_type);
|
||||||
|
@ -1207,8 +1207,9 @@ Vec3d Emboss::ProjectZ::project(const Vec3d &point) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Point> Emboss::ProjectZ::unproject(const Vec3d &p) const {
|
std::optional<Vec2d> Emboss::ProjectZ::unproject(const Vec3d &p, double *depth) const {
|
||||||
return Point(p.x() / SHAPE_SCALE, p.y() / SHAPE_SCALE);
|
if (depth != nullptr) *depth /= SHAPE_SCALE;
|
||||||
|
return Vec2d(p.x() / SHAPE_SCALE, p.y() / SHAPE_SCALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform3d Emboss::create_transformation_onto_surface(const Vec3f &position,
|
Transform3d Emboss::create_transformation_onto_surface(const Vec3f &position,
|
||||||
@ -1284,7 +1285,9 @@ Vec3d Emboss::OrthoProject::project(const Vec3d &point) const
|
|||||||
return point + m_direction;
|
return point + m_direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Point> Emboss::OrthoProject::unproject(const Vec3d &p) const {
|
std::optional<Vec2d> Emboss::OrthoProject::unproject(const Vec3d &p, double *depth) const
|
||||||
|
{
|
||||||
Vec3d pp = m_matrix_inv * p;
|
Vec3d pp = m_matrix_inv * p;
|
||||||
return Point(pp.x(), pp.y());
|
if (depth != nullptr) *depth = pp.z();
|
||||||
|
return Vec2d(pp.x(), pp.y());
|
||||||
}
|
}
|
@ -259,7 +259,13 @@ public:
|
|||||||
/// </returns>
|
/// </returns>
|
||||||
virtual std::pair<Vec3d, Vec3d> create_front_back(const Point &p) const = 0;
|
virtual std::pair<Vec3d, Vec3d> create_front_back(const Point &p) const = 0;
|
||||||
|
|
||||||
virtual std::optional<Point> unproject(const Vec3d &p) const = 0;
|
/// <summary>
|
||||||
|
/// Back projection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="p">Point to project</param>
|
||||||
|
/// <param name="depth">[optional] Depth of 2d projected point. Be careful number is in 2d scale</param>
|
||||||
|
/// <returns>Uprojected point when it is possible</returns>
|
||||||
|
virtual std::optional<Vec2d> unproject(const Vec3d &p, double * depth = nullptr) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -287,7 +293,7 @@ public:
|
|||||||
// Inherited via IProject
|
// Inherited via IProject
|
||||||
std::pair<Vec3d, Vec3d> create_front_back(const Point &p) const override;
|
std::pair<Vec3d, Vec3d> create_front_back(const Point &p) const override;
|
||||||
Vec3d project(const Vec3d &point) const override;
|
Vec3d project(const Vec3d &point) const override;
|
||||||
std::optional<Point> unproject(const Vec3d &p) const override;
|
std::optional<Vec2d> unproject(const Vec3d &p, double * depth = nullptr) const override;
|
||||||
double m_depth;
|
double m_depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -309,8 +315,10 @@ public:
|
|||||||
Vec3d project(const Vec3d &point) const override{
|
Vec3d project(const Vec3d &point) const override{
|
||||||
return core->project(point);
|
return core->project(point);
|
||||||
}
|
}
|
||||||
std::optional<Point> unproject(const Vec3d &p) const override {
|
std::optional<Vec2d> unproject(const Vec3d &p, double *depth = nullptr) const override {
|
||||||
return core->unproject(p / m_scale);
|
auto res = core->unproject(p / m_scale, depth);
|
||||||
|
if (depth != nullptr) *depth *= m_scale;
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -335,7 +343,7 @@ public:
|
|||||||
// Inherited via IProject
|
// Inherited via IProject
|
||||||
std::pair<Vec3d, Vec3d> create_front_back(const Point &p) const override;
|
std::pair<Vec3d, Vec3d> create_front_back(const Point &p) const override;
|
||||||
Vec3d project(const Vec3d &point) const override;
|
Vec3d project(const Vec3d &point) const override;
|
||||||
std::optional<Point> unproject(const Vec3d &p) const override;
|
std::optional<Vec2d> unproject(const Vec3d &p, double * depth = nullptr) const override;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,6 +71,7 @@ void CreateFontImageJob::process(Ctl &ctl)
|
|||||||
m_tex_size = Point(std::ceil(size_f.x()), std::ceil(size_f.y()));
|
m_tex_size = Point(std::ceil(size_f.x()), std::ceil(size_f.y()));
|
||||||
// crop image width
|
// crop image width
|
||||||
if (m_tex_size.x() > m_input.size.x()) m_tex_size.x() = m_input.size.x();
|
if (m_tex_size.x() > m_input.size.x()) m_tex_size.x() = m_input.size.x();
|
||||||
|
if (m_tex_size.y() > m_input.size.y()) m_tex_size.y() = m_input.size.y();
|
||||||
|
|
||||||
// Set up result
|
// Set up result
|
||||||
m_result = std::vector<unsigned char>(m_tex_size.x() * m_tex_size.y() * 4, {255});
|
m_result = std::vector<unsigned char>(m_tex_size.x() * m_tex_size.y() * 4, {255});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user