Skip to content

Commit 0569c87

Browse files
authored
Merge pull request #57 from Ultimaker/CURA-12544_saving-and-loading-painted-files-in-Cura
CURA-12544 saving and loading painted files in cura
2 parents c9fecec + 8db6981 commit 0569c87

18 files changed

Lines changed: 693 additions & 131 deletions

.clang-format

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ BreakBeforeBraces: Allman
3838
BreakBeforeTernaryOperators: true
3939
BreakConstructorInitializers: BeforeComma
4040
BreakStringLiterals: true
41-
ColumnLimit: 240
41+
ColumnLimit: 180
4242
CommentPragmas: '^ IWYU pragma:'
4343
CompactNamespaces: false
4444
PackConstructorInitializers: CurrentLine

CMakeLists.txt

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,34 @@ set(savitar_SRCS
1313
src/MeshData.cpp
1414
src/Vertex.cpp
1515
src/Face.cpp
16-
)
16+
src/UVCoordinate.cpp
17+
src/UVCoordinatesIndices.cpp
18+
src/TextureData.cpp
19+
)
1720

18-
if(BUILD_SHARED_LIBS)
21+
if (BUILD_SHARED_LIBS)
1922
add_library(Savitar SHARED ${savitar_SRCS})
20-
if(WIN32)
23+
if (WIN32)
2124
set_target_properties(Savitar PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
22-
endif()
23-
else()
25+
endif ()
26+
else ()
2427
add_library(Savitar STATIC ${savitar_SRCS})
25-
endif()
28+
endif ()
2629

2730
set_project_warnings(Savitar)
2831

2932
target_link_libraries(Savitar PUBLIC pugixml::pugixml)
3033

3134
target_include_directories(Savitar
3235
PUBLIC
33-
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
34-
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
36+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
37+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
3538
PRIVATE
36-
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
37-
)
39+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
40+
)
3841

3942
option(ENABLE_TESTING "Enable unit-testing" OFF)
4043
if (ENABLE_TESTING)
4144
enable_testing()
4245
add_subdirectory(tests)
43-
endif()
46+
endif ()

include/Savitar/Face.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,38 @@
44
#ifndef FACE_H
55
#define FACE_H
66

7+
#include "Savitar/UVCoordinatesIndices.h"
8+
9+
#include <optional>
10+
711
namespace Savitar
812
{
913
class Face
1014
{
1115
public:
1216
/**
13-
* A face uses the index of 3 vertices to describe a triangle
17+
* A face uses the index of 3 vertices to describe a triangle, and possibly indices of UV coordinates
1418
*/
15-
Face(int v1, int v2, int v3);
19+
Face(int v1, int v2, int v3, const std::optional<UVCoordinatesIndices>& uv_coordinates = std::nullopt);
1620
~Face() = default;
1721

1822
[[nodiscard]] int getV1() const;
23+
void setV1(const int v1);
24+
1925
[[nodiscard]] int getV2() const;
26+
void setV2(const int v2);
27+
2028
[[nodiscard]] int getV3() const;
29+
void setV3(const int v3);
30+
31+
[[nodiscard]] const std::optional<UVCoordinatesIndices>& getUVCoordinates() const;
32+
void setUVCoordinates(const std::optional<UVCoordinatesIndices>& uv_coordinates);
2133

2234
private:
2335
int vertex_1_index_;
2436
int vertex_2_index_;
2537
int vertex_3_index_;
38+
std::optional<UVCoordinatesIndices> uv_coordinates_;
2639
};
2740
} // namespace Savitar
2841

include/Savitar/MeshData.h

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
#ifndef MESHDATA_H
55
#define MESHDATA_H
66

7-
#include <cstdint>
8-
#include <string>
97
#include <vector>
108

119
#include "Savitar/Face.h"
@@ -16,6 +14,9 @@
1614

1715
namespace Savitar
1816
{
17+
18+
class Scene;
19+
1920
class MeshData
2021
{
2122
public:
@@ -56,6 +57,28 @@ class MeshData
5657
*/
5758
[[nodiscard]] bytearray getFlatVerticesAsBytes();
5859

60+
/**
61+
* Retrieves the list of actual UV coordinates for each vertex of each face, as a raw byte array
62+
* @param scene The scene which actually holds the UV coordinates set (can be shared amongst meshes)
63+
* @return The coordinates array, or an empty array if the mesh doesn't have texture data
64+
*/
65+
[[nodiscard]] bytearray getUVCoordinatesPerVertexAsBytes(const Scene* scene) const;
66+
67+
/**
68+
* Sets the UV coordinates from a raw byte array, containing the actual coordinates for each vertex of each face
69+
* @param data The raw coordinates data
70+
* @param texture_path The path of the texture file te be stored besides the model description
71+
* @param scene The scene which actually holds the UV coordinates set (can be shared amongst meshes)
72+
*/
73+
void setUVCoordinatesPerVertexAsBytes(const bytearray& data, const std::string& texture_path, Scene* scene);
74+
75+
/**
76+
* Get the path of the texture used by this mesh
77+
* @param scene The scene which actually contains the list of stored textures (can be shared amongst models)
78+
* @return The texture path, or an empty string if the mesh doesn't have texture data
79+
*/
80+
[[nodiscard]] std::string getTexturePath(const Scene* scene) const;
81+
5982
/**
6083
* Set the vertices of the meshdata by bytearray (as set from python)
6184
*
@@ -77,9 +100,19 @@ class MeshData
77100
*/
78101
void clear();
79102

103+
private:
104+
/**
105+
* @tparam T The type of data to be exported
106+
* @param data The byte array containing the exported raw data
107+
* @param value The value to be exported as raw data in the byte array
108+
*/
109+
template<typename T>
110+
static void exportToByteArray(bytearray& data, const T value);
111+
80112
private:
81113
std::vector<Vertex> vertices_;
82114
std::vector<Face> faces_;
115+
int uv_group_id_{ -1 };
83116
};
84117
} // namespace Savitar
85118

include/Savitar/Scene.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define SCENE_H
66

77
#include "Savitar/SceneNode.h"
8+
#include "TextureData.h"
89

910
#include <map> // For std::map
1011
#include <string> // For std::string
@@ -29,7 +30,7 @@ class Scene
2930
*/
3031
[[nodiscard]] std::vector<SceneNode*> getSceneNodes();
3132

32-
[[nodiscard]] std::vector<SceneNode*> getAllSceneNodes();
33+
[[nodiscard]] std::vector<SceneNode*> getAllSceneNodes() const;
3334

3435
/**
3536
* Add a scene node to the scene.
@@ -42,6 +43,11 @@ class Scene
4243
*/
4344
void fillByXMLNode(pugi::xml_node xml_node);
4445

46+
/**
47+
* Serialise the scene to model_node
48+
*/
49+
void toXmlNode(pugi::xml_node& model_node);
50+
4551
/**
4652
* Store a metadata entry as metadata.
4753
* @param key The key of the metadata.
@@ -68,6 +74,12 @@ class Scene
6874
*/
6975
[[nodiscard]] const std::map<std::string, MetadataEntry>& getMetadata() const;
7076

77+
/**
78+
* Find the next available resource ID amongst actually stored texture, UV coordinates and scene nodes. This should be called before
79+
* adding any of these resources, so that IDs are unique in the end.
80+
*/
81+
[[nodiscard]] int getNextAvailableResourceId() const;
82+
7183
/**
7284
* Get the unit (milimeter, inch, etc) of the scene.
7385
* This is in milimeter by default.
@@ -76,10 +88,25 @@ class Scene
7688

7789
void setUnit(std::string unit);
7890

91+
[[nodiscard]] std::string getTexturePathFromGroupId(const int uv_group_id) const;
92+
93+
[[nodiscard]] const TextureData::UVCoordinatesGroup* getUVCoordinatesGroup(const int uv_group_id) const;
94+
95+
void addTexturePath(const std::string& texture_path, const int texture_id);
96+
97+
/**
98+
* Stores a UV coordinates group from raw data
99+
* @param data The raw data to be stored
100+
* @param texture_id The ID of the associated texture
101+
* @param group_id The ID of the newly created coordinates group
102+
*/
103+
void setUVCoordinatesGroupFromBytes(const bytearray& data, const int texture_id, const int group_id);
104+
79105
private:
80106
std::vector<SceneNode*> scene_nodes_;
81107
std::map<std::string, MetadataEntry> metadata_;
82108
std::string unit_{ "millimeter" };
109+
TextureData texture_data_;
83110

84111
/**
85112
* Used to recursively create SceneNode objects based on xml nodes.

include/Savitar/SceneNode.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ class SceneNode
4444
/**
4545
* Get the (unique) identifier of the node.
4646
*/
47-
[[nodiscard]] std::string getId();
47+
[[nodiscard]] int getId() const;
4848

49-
void setId(std::string id);
49+
void setId(int id);
5050

5151
/**
5252
* Get the (non-unique) display name of the node.
@@ -81,7 +81,7 @@ class SceneNode
8181
std::vector<SceneNode*> children_;
8282
MeshData mesh_data_;
8383
std::map<std::string, MetadataEntry> settings_;
84-
std::string id_;
84+
int id_{ -1 };
8585
std::string name_;
8686
std::string type_{ "model" };
8787
std::string component_path_;

include/Savitar/TextureData.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) 2025 Ultimaker B.V.
2+
// libSavitar is released under the terms of the LGPLv3 or higher.
3+
4+
#ifndef TEXTUREDATA_H
5+
#define TEXTUREDATA_H
6+
7+
#include "Types.h"
8+
#include "UVCoordinate.h"
9+
10+
#include <map>
11+
#include <pugixml.hpp>
12+
#include <string>
13+
#include <vector>
14+
15+
namespace Savitar
16+
{
17+
/**
18+
* The TextureData stores UV coordinates groups and textures paths, that will end-up as resources in the global model description
19+
*/
20+
class TextureData
21+
{
22+
public:
23+
struct UVCoordinatesGroup
24+
{
25+
int texture_id; // The ID of the associated texture
26+
std::vector<UVCoordinate> coordinates; // The actual UV coordinates of the group
27+
};
28+
29+
TextureData();
30+
virtual ~TextureData() = default;
31+
32+
void fillByXMLNode(pugi::xml_node xml_node);
33+
34+
void toXmlNode(pugi::xml_node& resources_node);
35+
36+
[[nodiscard]] std::string getTexturePath(const int texture_id) const;
37+
38+
[[nodiscard]] const UVCoordinatesGroup* getUVCoordinatesGroup(const int id) const;
39+
40+
/**
41+
* Loads a UV coordinates group from raw data
42+
* @param data The actual UV coordinates as an array of floats
43+
* @param texture_id The ID of the associated texture
44+
* @param group_id The ID of the newly created group
45+
*/
46+
void setUVCoordinatesGroupFromBytes(const bytearray& data, const int texture_id, const int group_id);
47+
48+
void addTexturePath(const std::string& texture_path, const int id);
49+
50+
[[nodiscard]] std::string getTexturePathFromGroupId(const int uv_group_id) const;
51+
52+
/**
53+
* Find the next available resource ID amongst actually stored texture and UV coordinates. This should be called before
54+
* adding any of these resources, so that IDs are unique in the end.
55+
*/
56+
[[nodiscard]] int getNextAvailableResourceId() const;
57+
58+
private:
59+
std::map<int, std::string> textures_paths_;
60+
std::map<int, UVCoordinatesGroup> uv_coordinates_;
61+
};
62+
} // namespace Savitar
63+
64+
#endif

include/Savitar/UVCoordinate.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) 2025 Ultimaker B.V.
2+
// libSavitar is released under the terms of the LGPLv3 or higher.
3+
4+
#ifndef UVCOORDINATE_H
5+
#define UVCOORDINATE_H
6+
7+
namespace Savitar
8+
{
9+
class UVCoordinate
10+
{
11+
public:
12+
/**
13+
* A UV coordinate represents the position of the point on a texture image.
14+
*/
15+
UVCoordinate(float u, float v);
16+
virtual ~UVCoordinate() = default;
17+
18+
[[nodiscard]] float getU() const;
19+
[[nodiscard]] float getV() const;
20+
21+
private:
22+
float u_;
23+
float v_;
24+
};
25+
} // namespace Savitar
26+
27+
#endif
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) 2025 Ultimaker B.V.
2+
// libSavitar is released under the terms of the LGPLv3 or higher.
3+
4+
#ifndef UVCOORDINATESINDICES_H
5+
#define UVCOORDINATESINDICES_H
6+
7+
namespace Savitar
8+
{
9+
/**
10+
* UV coordinates indices contains the UV group ID and associated indices for each point of a face. A single mesh may contain indices
11+
* from multiple texture.
12+
*/
13+
class UVCoordinatesIndices
14+
{
15+
public:
16+
UVCoordinatesIndices(int group_index, int vertex_1_index, int vertex_2_index, int vertex_3_index);
17+
virtual ~UVCoordinatesIndices() = default;
18+
19+
[[nodiscard]] int getGroupIndex() const;
20+
[[nodiscard]] int getV1() const;
21+
[[nodiscard]] int getV2() const;
22+
[[nodiscard]] int getV3() const;
23+
24+
private:
25+
int group_index_{};
26+
int vertex_1_index_{};
27+
int vertex_2_index_{};
28+
int vertex_3_index_{};
29+
};
30+
} // namespace Savitar
31+
32+
#endif

0 commit comments

Comments
 (0)