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