1/*
2---------------------------------------------------------------------------
3Open Asset Import Library (assimp)
4---------------------------------------------------------------------------
5
6Copyright (c) 2006-2017, assimp team
7
8
9All rights reserved.
10
11Redistribution and use of this software in source and binary forms,
12with or without modification, are permitted provided that the following
13conditions are met:
14
15* Redistributions of source code must retain the above
16copyright notice, this list of conditions and the
17following disclaimer.
18
19* Redistributions in binary form must reproduce the above
20copyright notice, this list of conditions and the
21following disclaimer in the documentation and/or other
22materials provided with the distribution.
23
24* Neither the name of the assimp team, nor the names of its
25contributors may be used to endorse or promote products
26derived from this software without specific prior
27written permission of the assimp team.
28
29THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39OF 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
53namespace 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.
70void AMFImporter::ParseNode_Color()
71{
72std::string profile;
73CAMFImporter_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>.
121void AMFImporter::ParseNode_Material()
122{
123std::string id;
124CAMFImporter_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>.
181void AMFImporter::ParseNode_Texture()
182{
183std::string id;
184uint32_t width = 0;
185uint32_t height = 0;
186uint32_t depth = 1;
187std::string type;
188bool tiled = false;
189std::string enc64_data;
190CAMFImporter_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.
245void AMFImporter::ParseNode_TexMap(const bool pUseOldName)
246{
247std::string rtexid, gtexid, btexid, atexid;
248CAMFImporter_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