#pragma once #include #include #include #include #include #include struct indexed_triangle_set; namespace Slic3r { class TriangleMesh; class ModelVolume; struct TextureImage { int width = 0; int height = 0; int channels = 4; std::vector data; }; struct TexturedMesh { std::vector> vertices; std::vector> indices; std::vector> uvs; std::vector textures; std::vector material_ids; // material index -> index in textures[] (-1 if no texture, use material_colors) std::vector material_texture_map; // per-material baseColorFactor (RGBA 0-1), indexed by material index std::vector> material_colors; // Per-face independent UV support (for OBJ where the same vertex can have // different texture coordinates on different faces). std::vector> uv_coords; // UV coordinate pool std::vector> uv_indices; // per-face UV indices into uv_coords bool has_face_uvs() const { return !uv_indices.empty() && !uv_coords.empty(); } // Pre-computed per-face colors (e.g. from OBJ vertex colors or MTL Kd). // When non-empty, the pipeline skips texture decode/sample/oversample and // consumes these instead of sampling a texture. // Each entry is {R, G, B} in [0..255]. std::vector> precomputed_face_colors; // Per-vertex colors from OBJ (RGBA, [0..1]), indexed by vertex index. // On a low-poly mesh these are quantized into a small palette and the mesh is // split along the resulting cluster boundaries, so color borders stay sharp // instead of being averaged away into a single color per face. std::vector> precomputed_vertex_colors; }; struct PaintedMesh { std::vector> vertices; std::vector> indices; std::vector> face_colors; // per-face RGB [0..255] std::vector> cluster_colors; }; using PaintProgressCallback = std::function; using PaintCancelCallback = std::function; using PaintMeshRepairCallback = std::function progress_callback, std::function cancel_callback, std::string* error_message)>; struct TexturePaintingSettings { std::size_t target_colors_num = 4; double smooth_weight = 0.5; std::size_t oversampling_iters = 0; enum class MeshRepairDecision { Ask, ImportWithoutRepair, RepairAndImport }; MeshRepairDecision mesh_repair_decision = MeshRepairDecision::ImportWithoutRepair; bool* mesh_repair_decision_required = nullptr; PaintMeshRepairCallback mesh_repair_callback; }; struct FilamentMatch { int cluster_index = -1; int filament_index = -1; double delta_e = 0.0; std::array cluster_color = {0,0,0}; std::array filament_color = {0,0,0,1}; }; bool texture_to_painting( const TexturedMesh& textured, PaintedMesh& painted, const TexturePaintingSettings& settings = {}, PaintProgressCallback progress = nullptr, PaintCancelCallback cancel = nullptr); // Turn pre-computed per-face colors into a painted mesh, skipping texture decode // and UV sampling. A low-poly mesh that also carries precomputed_vertex_colors is // split along quantized color boundaries, which replaces its geometry. bool face_colors_to_painting( const TexturedMesh& mesh, PaintedMesh& painted, const TexturePaintingSettings& settings = {}, PaintProgressCallback progress = nullptr, PaintCancelCallback cancel = nullptr); std::vector match_clusters_to_filaments( const std::vector>& cluster_colors, const std::vector>& filament_colors, const std::vector& filament_names); double compute_delta_e( const std::array& rgb1, const std::array& rgba2); bool apply_painted_mesh_to_volume( const PaintedMesh& painted, const std::vector& matches, ModelVolume& volume); // Decode a TextureImage (which may contain raw PNG/JPEG bytes) into BGR pixel data. // On success, populates out_pixels (BGR, 3 bytes/pixel) and sets out_w/out_h. bool decode_texture_to_pixels( const TextureImage& img, std::vector& out_pixels, int& out_w, int& out_h); // Sample per-face colors from the correct texture per material_ids. // Uses material_texture_map / material_colors for multi-material GLBs. // Falls back to textures[0] when the mapping is absent. bool sample_original_face_colors( const TexturedMesh& textured, std::vector>& out_face_colors); } // namespace Slic3r