1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5
6 Copyright (c) 2006-2017, assimp team
7
8
9 All rights reserved.
10
11 Redistribution and use of this software in source and binary forms,
12 with or without modification, are permitted provided that the following
13 conditions are met:
14
15 * Redistributions of source code must retain the above
16 copyright notice, this list of conditions and the
17 following disclaimer.
18
19 * Redistributions in binary form must reproduce the above
20 copyright notice, this list of conditions and the
21 following disclaimer in the documentation and/or other
22 materials provided with the distribution.
23
24 * Neither the name of the assimp team, nor the names of its
25 contributors may be used to endorse or promote products
26 derived from this software without specific prior
27 written permission of the assimp team.
28
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 ---------------------------------------------------------------------------
41 */
42
43 /// \file AMFImporter_Material.cpp
44 /// \brief Parsing data from material nodes.
45 /// \date 2016
46 /// \author smal.root@gmail.com
47
48 #ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
49
50 #include "AMFImporter.hpp"
51 #include "AMFImporter_Macro.hpp"
52
53 namespace Assimp
54 {
55
56 // <color
57 // profile="" - The ICC color space used to interpret the three color channels <r>, <g> and <b>.
58 // >
59 // </color>
60 // A color definition.
61 // Multi elements - No.
62 // Parent element - <material>, <object>, <volume>, <vertex>, <triangle>.
63 //
64 // "profile" can be one of "sRGB", "AdobeRGB", "Wide-Gamut-RGB", "CIERGB", "CIELAB", or "CIEXYZ".
65 // Children elements:
66 // <r>, <g>, <b>, <a>
67 // Multi elements - No.
68 // Red, Greed, Blue and Alpha (transparency) component of a color in sRGB space, values ranging from 0 to 1. The
69 // values can be specified as constants, or as a formula depending on the coordinates.
ParseNode_Color()70 void AMFImporter::ParseNode_Color()
71 {
72 std::string profile;
73 CAMFImporter_NodeElement* ne;
74
75 // Read attributes for node <color>.
76 MACRO_ATTRREAD_LOOPBEG;
77 MACRO_ATTRREAD_CHECK_RET("profile", profile, mReader->getAttributeValue);
78 MACRO_ATTRREAD_LOOPEND;
79
80 // create new color object.
81 ne = new CAMFImporter_NodeElement_Color(mNodeElement_Cur);
82
83 CAMFImporter_NodeElement_Color& als = *((CAMFImporter_NodeElement_Color*)ne);// alias for convenience
84
85 als.Profile = profile;
86 // Check for child nodes
87 if(!mReader->isEmptyElement())
88 {
89 bool read_flag[4] = { false, false, false, false };
90
91 ParseHelper_Node_Enter(ne);
92 MACRO_NODECHECK_LOOPBEGIN("color");
93 MACRO_NODECHECK_READCOMP_F("r", read_flag[0], als.Color.r);
94 MACRO_NODECHECK_READCOMP_F("g", read_flag[1], als.Color.g);
95 MACRO_NODECHECK_READCOMP_F("b", read_flag[2], als.Color.b);
96 MACRO_NODECHECK_READCOMP_F("a", read_flag[3], als.Color.a);
97 MACRO_NODECHECK_LOOPEND("color");
98 ParseHelper_Node_Exit();
99 // check that all components was defined
100 if(!(read_flag[0] && read_flag[1] && read_flag[2])) throw DeadlyImportError("Not all color components are defined.");
101 // check if <a> is absent. Then manualy add "a == 1".
102 if(!read_flag[3]) als.Color.a = 1;
103
104 }// if(!mReader->isEmptyElement())
105 else
106 {
107 mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
108 }// if(!mReader->isEmptyElement()) else
109
110 als.Composed = false;
111 mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
112 }
113
114 // <material
115 // id="" - A unique material id. material ID "0" is reserved to denote no material (void) or sacrificial material.
116 // >
117 // </material>
118 // An available material.
119 // Multi elements - Yes.
120 // Parent element - <amf>.
ParseNode_Material()121 void AMFImporter::ParseNode_Material()
122 {
123 std::string id;
124 CAMFImporter_NodeElement* ne;
125
126 // Read attributes for node <color>.
127 MACRO_ATTRREAD_LOOPBEG;
128 MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
129 MACRO_ATTRREAD_LOOPEND;
130
131 // create new object.
132 ne = new CAMFImporter_NodeElement_Material(mNodeElement_Cur);
133 // and assign read data
134 ((CAMFImporter_NodeElement_Material*)ne)->ID = id;
135 // Check for child nodes
136 if(!mReader->isEmptyElement())
137 {
138 bool col_read = false;
139
140 ParseHelper_Node_Enter(ne);
141 MACRO_NODECHECK_LOOPBEGIN("material");
142 if(XML_CheckNode_NameEqual("color"))
143 {
144 // Check if data already defined.
145 if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <material>.");
146 // read data and set flag about it
147 ParseNode_Color();
148 col_read = true;
149
150 continue;
151 }
152
153 if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
154 MACRO_NODECHECK_LOOPEND("material");
155 ParseHelper_Node_Exit();
156 }// if(!mReader->isEmptyElement())
157 else
158 {
159 mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
160 }// if(!mReader->isEmptyElement()) else
161
162 mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
163 }
164
165 // <texture
166 // id="" - Assigns a unique texture id for the new texture.
167 // width="" - Width (horizontal size, x) of the texture, in pixels.
168 // height="" - Height (lateral size, y) of the texture, in pixels.
169 // depth="" - Depth (vertical size, z) of the texture, in pixels.
170 // type="" - Encoding of the data in the texture. Currently allowed values are "grayscale" only. In grayscale mode, each pixel is represented by one byte
171 // in the range of 0-255. When the texture is referenced using the tex function, these values are converted into a single floating point number in the
172 // range of 0-1 (see Annex 2). A full color graphics will typically require three textures, one for each of the color channels. A graphic involving
173 // transparency may require a fourth channel.
174 // tiled="" - If true then texture repeated when UV-coordinates is greater than 1.
175 // >
176 // </triangle>
177 // Specifies an texture data to be used as a map. Lists a sequence of Base64 values specifying values for pixels from left to right then top to bottom,
178 // then layer by layer.
179 // Multi elements - Yes.
180 // Parent element - <amf>.
ParseNode_Texture()181 void AMFImporter::ParseNode_Texture()
182 {
183 std::string id;
184 uint32_t width = 0;
185 uint32_t height = 0;
186 uint32_t depth = 1;
187 std::string type;
188 bool tiled = false;
189 std::string enc64_data;
190 CAMFImporter_NodeElement* ne;
191
192 // Read attributes for node <color>.
193 MACRO_ATTRREAD_LOOPBEG;
194 MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
195 MACRO_ATTRREAD_CHECK_RET("width", width, XML_ReadNode_GetAttrVal_AsU32);
196 MACRO_ATTRREAD_CHECK_RET("height", height, XML_ReadNode_GetAttrVal_AsU32);
197 MACRO_ATTRREAD_CHECK_RET("depth", depth, XML_ReadNode_GetAttrVal_AsU32);
198 MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
199 MACRO_ATTRREAD_CHECK_RET("tiled", tiled, XML_ReadNode_GetAttrVal_AsBool);
200 MACRO_ATTRREAD_LOOPEND;
201
202 // create new texture object.
203 ne = new CAMFImporter_NodeElement_Texture(mNodeElement_Cur);
204
205 CAMFImporter_NodeElement_Texture& als = *((CAMFImporter_NodeElement_Texture*)ne);// alias for convenience
206
207 // Check for child nodes
208 if(!mReader->isEmptyElement()) XML_ReadNode_GetVal_AsString(enc64_data);
209
210 // check that all components was defined
211 if(id.empty()) throw DeadlyImportError("ID for texture must be defined.");
212 if(width < 1) Throw_IncorrectAttrValue("width");
213 if(height < 1) Throw_IncorrectAttrValue("height");
214 if(depth < 1) Throw_IncorrectAttrValue("depth");
215 if(type != "grayscale") Throw_IncorrectAttrValue("type");
216 if(enc64_data.empty()) throw DeadlyImportError("Texture data not defined.");
217 // copy data
218 als.ID = id;
219 als.Width = width;
220 als.Height = height;
221 als.Depth = depth;
222 als.Tiled = tiled;
223 ParseHelper_Decode_Base64(enc64_data, als.Data);
224 // check data size
225 if((width * height * depth) != als.Data.size()) throw DeadlyImportError("Texture has incorrect data size.");
226
227 mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
228 mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
229 }
230
231 // <texmap
232 // rtexid="" - Texture ID for red color component.
233 // gtexid="" - Texture ID for green color component.
234 // btexid="" - Texture ID for blue color component.
235 // atexid="" - Texture ID for alpha color component. Optional.
236 // >
237 // </texmap>, old name: <map>
238 // Specifies texture coordinates for triangle.
239 // Multi elements - No.
240 // Parent element - <triangle>.
241 // Children elements:
242 // <utex1>, <utex2>, <utex3>, <vtex1>, <vtex2>, <vtex3>. Old name: <u1>, <u2>, <u3>, <v1>, <v2>, <v3>.
243 // Multi elements - No.
244 // Texture coordinates for every vertex of triangle.
ParseNode_TexMap(const bool pUseOldName)245 void AMFImporter::ParseNode_TexMap(const bool pUseOldName)
246 {
247 std::string rtexid, gtexid, btexid, atexid;
248 CAMFImporter_NodeElement* ne;
249
250 // Read attributes for node <color>.
251 MACRO_ATTRREAD_LOOPBEG;
252 MACRO_ATTRREAD_CHECK_RET("rtexid", rtexid, mReader->getAttributeValue);
253 MACRO_ATTRREAD_CHECK_RET("gtexid", gtexid, mReader->getAttributeValue);
254 MACRO_ATTRREAD_CHECK_RET("btexid", btexid, mReader->getAttributeValue);
255 MACRO_ATTRREAD_CHECK_RET("atexid", atexid, mReader->getAttributeValue);
256 MACRO_ATTRREAD_LOOPEND;
257
258 // create new texture coordinates object.
259 ne = new CAMFImporter_NodeElement_TexMap(mNodeElement_Cur);
260
261 CAMFImporter_NodeElement_TexMap& als = *((CAMFImporter_NodeElement_TexMap*)ne);// alias for convenience
262 // check data
263 if(rtexid.empty() && gtexid.empty() && btexid.empty()) throw DeadlyImportError("ParseNode_TexMap. At least one texture ID must be defined.");
264 // Check for children nodes
265 XML_CheckNode_MustHaveChildren();
266 // read children nodes
267 bool read_flag[6] = { false, false, false, false, false, false };
268
269 ParseHelper_Node_Enter(ne);
270 if(!pUseOldName)
271 {
272 MACRO_NODECHECK_LOOPBEGIN("texmap");
273 MACRO_NODECHECK_READCOMP_F("utex1", read_flag[0], als.TextureCoordinate[0].x);
274 MACRO_NODECHECK_READCOMP_F("utex2", read_flag[1], als.TextureCoordinate[1].x);
275 MACRO_NODECHECK_READCOMP_F("utex3", read_flag[2], als.TextureCoordinate[2].x);
276 MACRO_NODECHECK_READCOMP_F("vtex1", read_flag[3], als.TextureCoordinate[0].y);
277 MACRO_NODECHECK_READCOMP_F("vtex2", read_flag[4], als.TextureCoordinate[1].y);
278 MACRO_NODECHECK_READCOMP_F("vtex3", read_flag[5], als.TextureCoordinate[2].y);
279 MACRO_NODECHECK_LOOPEND("texmap");
280 }
281 else
282 {
283 MACRO_NODECHECK_LOOPBEGIN("map");
284 MACRO_NODECHECK_READCOMP_F("u1", read_flag[0], als.TextureCoordinate[0].x);
285 MACRO_NODECHECK_READCOMP_F("u2", read_flag[1], als.TextureCoordinate[1].x);
286 MACRO_NODECHECK_READCOMP_F("u3", read_flag[2], als.TextureCoordinate[2].x);
287 MACRO_NODECHECK_READCOMP_F("v1", read_flag[3], als.TextureCoordinate[0].y);
288 MACRO_NODECHECK_READCOMP_F("v2", read_flag[4], als.TextureCoordinate[1].y);
289 MACRO_NODECHECK_READCOMP_F("v3", read_flag[5], als.TextureCoordinate[2].y);
290 MACRO_NODECHECK_LOOPEND("map");
291 }// if(!pUseOldName) else
292
293 ParseHelper_Node_Exit();
294
295 // check that all components was defined
296 if(!(read_flag[0] && read_flag[1] && read_flag[2] && read_flag[3] && read_flag[4] && read_flag[5]))
297 throw DeadlyImportError("Not all texture coordinates are defined.");
298
299 // copy attributes data
300 als.TextureID_R = rtexid;
301 als.TextureID_G = gtexid;
302 als.TextureID_B = btexid;
303 als.TextureID_A = atexid;
304
305 mNodeElement_List.push_back(ne);// add to node element list because its a new object in graph.
306 }
307
308 }// namespace Assimp
309
310 #endif // !ASSIMP_BUILD_NO_AMF_IMPORTER
311