0030953: Data Exchange - implement export of mesh data into glTF 2.0 format
[occt.git] / src / RWMesh / RWMesh_MaterialMap.cxx
1 // Copyright (c) 2017-2019 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <RWMesh_MaterialMap.hxx>
15
16 #include <Message.hxx>
17 #include <Message_Messenger.hxx>
18 #include <OSD_Directory.hxx>
19 #include <OSD_File.hxx>
20 #include <OSD_Path.hxx>
21 #include <OSD_Protection.hxx>
22 #include <TDataStd_Name.hxx>
23 #include <TDF_Label.hxx>
24
25 // =======================================================================
26 // function : RWMesh_MaterialMap
27 // purpose  :
28 // =======================================================================
29 RWMesh_MaterialMap::RWMesh_MaterialMap (const TCollection_AsciiString& theFile)
30 : myFileName (theFile),
31   myKeyPrefix ("mat_"),
32   myNbMaterials (0),
33   myIsFailed (false),
34   myMatNameAsKey (true)
35 {
36   TCollection_AsciiString aFileName, aFileExt;
37   OSD_Path::FolderAndFileFromPath (theFile, myFolder, aFileName);
38   OSD_Path::FileNameAndExtension (aFileName, myShortFileNameBase, aFileExt);
39 }
40
41 // =======================================================================
42 // function : ~RWMesh_MaterialMap
43 // purpose  :
44 // =======================================================================
45 RWMesh_MaterialMap::~RWMesh_MaterialMap()
46 {
47   //
48 }
49
50 // =======================================================================
51 // function : AddMaterial
52 // purpose  :
53 // =======================================================================
54 TCollection_AsciiString RWMesh_MaterialMap::AddMaterial (const XCAFPrs_Style& theStyle)
55 {
56   if (myStyles.IsBound1 (theStyle))
57   {
58     return myStyles.Find1 (theStyle);
59   }
60
61   TCollection_AsciiString aMatKey, aMatName, aMatNameSuffix;
62   int  aCounter    = 0;
63   int* aCounterPtr = &myNbMaterials;
64   if (myMatNameAsKey)
65   {
66     if (!theStyle.Material().IsNull()
67      && !theStyle.Material()->IsEmpty())
68     {
69       aCounterPtr = &aCounter;
70       Handle(TDataStd_Name) aNodeName;
71       if (!theStyle.Material()->Label().IsNull()
72        &&  theStyle.Material()->Label().FindAttribute (TDataStd_Name::GetID(), aNodeName))
73       {
74         aMatName = aNodeName->Get();
75       }
76       else
77       {
78         aMatName = "mat";
79       }
80       aMatNameSuffix = aMatName;
81     }
82     else
83     {
84       ++myNbMaterials;
85       aMatNameSuffix = myKeyPrefix;
86       aMatName = aMatNameSuffix + myNbMaterials;
87     }
88     aMatKey = aMatName;
89   }
90   else
91   {
92     aMatKey        = myNbMaterials++; // starts from 0
93     aMatNameSuffix = myKeyPrefix;
94     aMatName       = aMatNameSuffix + aMatKey;
95   }
96
97   for (;; ++(*aCounterPtr))
98   {
99     if (myStyles.IsBound2 (aMatKey))
100     {
101       if (myMatNameAsKey)
102       {
103         aMatName = aMatNameSuffix + (*aCounterPtr);
104         aMatKey  = aMatName;
105       }
106       else
107       {
108         aMatKey  = *aCounterPtr;
109         aMatName = aMatNameSuffix + aMatKey;
110       }
111       continue;
112     }
113     break;
114   }
115
116   myStyles.Bind (theStyle, aMatKey);
117   DefineMaterial (theStyle, aMatKey, aMatName);
118   return aMatKey;
119 }
120
121 // =======================================================================
122 // function : copyFileTo
123 // purpose  :
124 // =======================================================================
125 bool RWMesh_MaterialMap::copyFileTo (const TCollection_AsciiString& theFileSrc,
126                                      const TCollection_AsciiString& theFileDst)
127 {
128   if (theFileSrc.IsEmpty()
129    || theFileDst.IsEmpty())
130   {
131     return false;
132   }
133   else if (theFileSrc == theFileDst)
134   {
135     return true;
136   }
137
138   try
139   {
140     OSD_Path aSrcPath (theFileSrc);
141     OSD_Path aDstPath (theFileDst);
142     OSD_File aFileSrc (aSrcPath);
143     if (!aFileSrc.Exists())
144     {
145       Message::DefaultMessenger()->Send (TCollection_AsciiString("Failed to copy file - source file '")
146                                        + theFileSrc + "' does not exist\n", Message_Fail);
147       return false;
148     }
149     aFileSrc.Copy (aDstPath);
150     return !aFileSrc.Failed();
151   }
152   catch (Standard_Failure const& theException)
153   {
154     Message::DefaultMessenger()->Send (TCollection_AsciiString("Failed to copy file\n") +
155                                        theException.GetMessageString(), Message_Fail);
156     return false;
157   }
158 }
159
160 // =======================================================================
161 // function : CopyTexture
162 // purpose  :
163 // =======================================================================
164 bool RWMesh_MaterialMap::CopyTexture (TCollection_AsciiString& theResTexture,
165                                       const Handle(Image_Texture)& theTexture,
166                                       const TCollection_AsciiString& theKey)
167 {
168   CreateTextureFolder();
169
170   TCollection_AsciiString aTexFileName;
171   TCollection_AsciiString aTextureSrc = theTexture->FilePath();
172   if (!aTextureSrc.IsEmpty())
173   {
174     TCollection_AsciiString aSrcTexFolder;
175     OSD_Path::FolderAndFileFromPath (aTextureSrc, aSrcTexFolder, aTexFileName);
176     const TCollection_AsciiString aResTexFile = myTexFolder + aTexFileName;
177     theResTexture = myTexFolderShort + aTexFileName;
178     return copyFileTo (aTextureSrc, aResTexFile);
179   }
180
181   TCollection_AsciiString anExt = theTexture->ProbeImageFileFormat();
182   if (anExt.IsEmpty())
183   {
184     anExt = "bin";
185   }
186   aTexFileName = theKey + "." + anExt;
187
188   const TCollection_AsciiString aResTexFile = myTexFolder + aTexFileName;
189   theResTexture = myTexFolderShort + aTexFileName;
190   return theTexture->WriteImage (aResTexFile);
191 }
192
193 // =======================================================================
194 // function : CreateTextureFolder
195 // purpose  :
196 // =======================================================================
197 bool RWMesh_MaterialMap::CreateTextureFolder()
198 {
199   if (!myTexFolder.IsEmpty())
200   {
201     return true;
202   }
203
204   myTexFolderShort = myShortFileNameBase + "_textures/";
205   myTexFolder      = myFolder + "/" + myTexFolderShort;
206   OSD_Path aTexFolderPath (myTexFolder);
207   OSD_Directory aTexDir (aTexFolderPath);
208   if (aTexDir.Exists())
209   {
210     return true;
211   }
212
213   OSD_Path aResFolderPath (myFolder);
214   OSD_Directory aResDir (aResFolderPath);
215   if (!aResDir.Exists())
216   {
217     return false;
218   }
219   const OSD_Protection aParentProt = aResDir.Protection();
220   OSD_Protection aProt = aParentProt;
221   if (aProt.User() == OSD_None)
222   {
223     aProt.SetUser (OSD_RWXD);
224   }
225   if (aProt.System() == OSD_None)
226   {
227     aProt.SetSystem (OSD_RWXD);
228   }
229
230   aTexDir.Build (aProt);
231   if (aTexDir.Failed())
232   {
233     // fallback to the same folder as output model file
234     myTexFolder = myFolder;
235     myTexFolderShort.Clear();
236     return true;
237   }
238   return true;
239 }