Line data Source code
1 : /*
2 : * Copyright (c) 2009-2015: G-CSC, Goethe University Frankfurt
3 : * Author: Sebastian Reiter
4 : *
5 : * This file is part of UG4.
6 : *
7 : * UG4 is free software: you can redistribute it and/or modify it under the
8 : * terms of the GNU Lesser General Public License version 3 (as published by the
9 : * Free Software Foundation) with the following additional attribution
10 : * requirements (according to LGPL/GPL v3 §7):
11 : *
12 : * (1) The following notice must be displayed in the Appropriate Legal Notices
13 : * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14 : *
15 : * (2) The following notice must be displayed at a prominent place in the
16 : * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17 : *
18 : * (3) The following bibliography is recommended for citation and must be
19 : * preserved in all covered files:
20 : * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21 : * parallel geometric multigrid solver on hierarchically distributed grids.
22 : * Computing and visualization in science 16, 4 (2013), 151-164"
23 : * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24 : * flexible software system for simulating pde based models on high performance
25 : * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26 : *
27 : * This program is distributed in the hope that it will be useful,
28 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 : * GNU Lesser General Public License for more details.
31 : */
32 :
33 : #include <vector>
34 : #include <fstream>
35 : #include <cstring>
36 : #include <string>
37 : #include "loader_obj.h"
38 : #include "loader_util.h"
39 :
40 : using namespace std;
41 :
42 : namespace ug
43 : {
44 : ////////////////////////////////////////////////////////////////////////////////////////////////
45 : // some string functions
46 : //TODO: IMPROVE THIS FUNCTION!!! MOVE IT TO A COMMON UTIL-FILE
47 : typedef vector<string> ParameterList;
48 0 : static void split_parameters(ParameterList* pParamList, const char* pParamString)
49 : {
50 0 : string param(pParamString);
51 :
52 0 : while(param.size())
53 : {
54 : // delete empty spaces at the front of the string
55 0 : while(param.find(" ", 0) == 0)
56 : {
57 0 : param.erase(0, 1);
58 : }
59 : // find the next empty space
60 0 : int iSpace = param.find(" ", 0);
61 0 : if(iSpace == -1)
62 : {
63 : // there is no -> the rest of the string is a parameter
64 0 : if(param.size() > 0)
65 : {
66 : /*
67 : SParameter nParam;
68 : nParam.pFirst = pParamString + PosIndex;
69 : nParam.size = param.size();
70 : */
71 : string nParam = param;
72 0 : pParamList->push_back(nParam);
73 : break;
74 : }
75 : }
76 : else
77 : {
78 : // extract the parameter from param and push back to ParamList
79 : /*
80 : SParameter nParam;
81 : nParam.pFirst = pParameterString + PosIndex;
82 : nParam.size = iSpace;
83 : */
84 : string nParam;
85 0 : nParam.assign(param, 0, iSpace);
86 0 : pParamList->push_back(nParam);
87 0 : param.erase(0, iSpace + 1);
88 : }
89 : }
90 0 : }
91 :
92 : //TODO: IMPROVE THIS FUNCTION!!! MOVE IT TO A COMMON UTIL-FILE
93 0 : string replace_chars(string& str, char cToR, char cNew)
94 : {
95 0 : char* nStr = new char[str.length() + 1];
96 : memcpy(nStr, str.c_str(), str.length());
97 0 : nStr[str.length()] = 0;
98 : char* tPtr = nStr;
99 0 : while(*tPtr)
100 : {
101 0 : if(*tPtr == cToR)
102 0 : *tPtr = cNew;
103 0 : tPtr++;
104 : }
105 0 : string Ret = nStr;
106 0 : delete[] nStr;
107 0 : return Ret;
108 : }
109 :
110 : //TODO: IMPROVE THIS FUNCTION!!! MOVE IT TO A COMMON UTIL-FILE
111 0 : string extract_path(const string& filename)
112 : {
113 : string::size_type idx1 = filename.rfind("/");
114 : string::size_type idx2 = filename.rfind("\\");
115 :
116 0 : if(idx2 < idx1)
117 : idx1 = idx2;
118 0 : return filename.substr(0, idx1+1);
119 : }
120 :
121 : /*
122 : **
123 : */
124 : ////////////////////////////////////////////////////////////////////////////////////////////////
125 : // LoaderObj implementation
126 0 : LoaderObj::~LoaderObj()
127 : {
128 0 : clear();
129 0 : }
130 :
131 0 : void LoaderObj::clear()
132 : {
133 0 : for(LoaderObj::ObjectIterator iter = m_vObjects.begin(); iter != m_vObjects.end(); iter++)
134 0 : delete (*iter);
135 : m_vObjects.clear();
136 0 : }
137 :
138 0 : bool LoaderObj::load_file(const char* strFilename, bool convertQuadsToTris)
139 : {
140 0 : clear();
141 :
142 0 : ifstream in(strFilename);
143 0 : if(!in)
144 : return false;
145 :
146 0 : string strObj = "o";
147 0 : string strPos = "v";
148 0 : string strNorm = "vn";
149 0 : string strTex1 = "vt";
150 0 : string strFace = "f";
151 0 : string strMtrl = "usemtl";
152 0 : string strMtrlLib = "mtllib";
153 :
154 : bool bGotPosition = false;
155 : bool bGotTexture = false;
156 : bool bGotNormal = false;
157 :
158 0 : Object* pActiveObject = NULL;
159 :
160 : string strCommand;
161 : char BUFFER[256];
162 0 : BUFFER[255] = 0;
163 0 : for(uint i = 0; i < 256; ++i)
164 0 : BUFFER[i] = 0;
165 : ParameterList lstParams;
166 : ParameterList::iterator PIter;
167 :
168 : int lineNumber = 0;
169 :
170 0 : while(!in.eof())
171 : {
172 0 : in.getline(BUFFER, 256);
173 0 : ++lineNumber;
174 0 : if(BUFFER[255] != 0)
175 : return false;
176 :
177 : // files that come from a windows environment always have '\r' at the end of each line.
178 : // the following code removes those '\r'. The implementation is far from optimal!!
179 : /*
180 : string tStr(BUFFER);
181 : tStr = replace_chars(tStr, '\r', '\0');
182 :
183 : lstParams.clear();
184 :
185 : split_parameters(&lstParams, tStr.c_str());
186 : */
187 0 : split_parameters(lstParams, BUFFER, " \r\t");
188 :
189 0 : if(lstParams.empty())
190 0 : continue;
191 :
192 : strCommand = *lstParams.begin();
193 : lstParams.erase(lstParams.begin());
194 :
195 0 : if(strCommand == strObj)
196 : {
197 0 : if(pActiveObject)
198 0 : m_vObjects.push_back(pActiveObject);
199 :
200 0 : pActiveObject = new LoaderObj::Object;
201 0 : pActiveObject->m_strName = *lstParams.begin();
202 0 : pActiveObject->m_iMaterialIndex = -1;
203 : }
204 0 : else if(strCommand == strMtrlLib)
205 : {// read materials
206 0 : string mtlLib = extract_path(string(strFilename));
207 : mtlLib.append(*lstParams.begin());
208 :
209 0 : string newMaterial = "newmtl";
210 0 : string colorDiffuse = "Kd";
211 0 : string textureDiffuse = "map_Kd";
212 0 : string colorAlpha = "d";
213 :
214 0 : ifstream mtlIn(mtlLib.c_str());
215 0 : if(!mtlIn)
216 : continue;
217 :
218 : Material* pActMaterial = NULL;
219 0 : while(!mtlIn.eof())
220 : {
221 0 : mtlIn.getline(BUFFER, 256);
222 0 : ++lineNumber;
223 0 : if(BUFFER[255] != 0)
224 : return false;
225 :
226 : lstParams.clear();
227 0 : split_parameters(&lstParams, BUFFER);
228 0 : if(lstParams.empty())
229 0 : continue;
230 :
231 : strCommand = *lstParams.begin();
232 : lstParams.erase(lstParams.begin());
233 :
234 0 : if(strCommand == newMaterial)
235 : {
236 0 : m_vMaterials.push_back(Material());
237 : pActMaterial = &m_vMaterials[m_vMaterials.size() - 1];
238 0 : if(!lstParams.empty())
239 0 : pActMaterial->m_strName = *lstParams.begin();
240 : }
241 0 : else if(pActMaterial)
242 : {
243 0 : if(strCommand == colorDiffuse)
244 : {
245 0 : if(lstParams.size() != 3)
246 0 : continue;
247 : PIter = lstParams.begin();
248 0 : pActMaterial->m_vDiffuse.x() = atof((*PIter).c_str());
249 : PIter++;
250 0 : pActMaterial->m_vDiffuse.y() = atof((*PIter).c_str());
251 : PIter++;
252 0 : pActMaterial->m_vDiffuse.z() = atof((*PIter).c_str());
253 : }
254 0 : else if(strCommand == colorAlpha)
255 : {
256 0 : if(lstParams.size() != 1)
257 0 : continue;
258 : PIter = lstParams.begin();
259 0 : pActMaterial->m_fAlpha = pActMaterial->m_vDiffuse.w() = atof((*PIter).c_str());
260 : }
261 0 : else if(strCommand == textureDiffuse)
262 : {
263 0 : if(lstParams.size() != 1)
264 0 : continue;
265 0 : pActMaterial->m_strTextureDiffuse = *lstParams.begin();
266 : }
267 : }
268 : }
269 0 : }
270 0 : else if(strCommand == strPos)
271 : {
272 : bGotPosition = true;
273 0 : if(lstParams.size() != 3)
274 0 : continue;
275 : vector3 v;
276 : PIter = lstParams.begin();
277 0 : v.x() = atof((*PIter).c_str());
278 : PIter++;
279 0 : v.y() = atof((*PIter).c_str());
280 : PIter++;
281 0 : v.z() = atof((*PIter).c_str());
282 0 : m_vPoints.push_back(v);
283 : }
284 0 : else if(strCommand == strNorm)
285 : {
286 : bGotNormal = true;
287 : }
288 0 : else if(strCommand == strTex1)
289 : {
290 : bGotTexture = true;
291 0 : if(lstParams.size() < 2)
292 0 : continue;
293 : vector2 v;
294 : PIter = lstParams.begin();
295 0 : v.x() = atof((*PIter).c_str());
296 : PIter++;
297 0 : v.y() = -atof((*PIter).c_str());
298 0 : m_vTexCoords.push_back(v);
299 : }
300 0 : else if(strCommand == strFace){
301 0 : if(!pActiveObject){
302 0 : pActiveObject = new LoaderObj::Object;
303 0 : pActiveObject->m_strName = "default";
304 0 : pActiveObject->m_iMaterialIndex = -1;
305 : }
306 :
307 : PIter = lstParams.begin();
308 :
309 0 : if(lstParams.size() == 2)
310 : {
311 0 : for(; PIter != lstParams.end(); PIter++)
312 : {
313 0 : string tStr = replace_chars((*PIter), '/', ' ');
314 : ParameterList lstIndexParams;
315 0 : split_parameters(&lstIndexParams, tStr.c_str());
316 : uint iCount = 0;
317 0 : if(bGotPosition && (iCount < lstIndexParams.size()))
318 : {
319 0 : pActiveObject->m_vEdgeList.push_back(atoi(lstIndexParams[iCount].c_str()) - 1);
320 : iCount++;
321 : }
322 0 : }
323 : }
324 0 : else if(lstParams.size() == 3)
325 : {
326 0 : for(; PIter != lstParams.end(); PIter++)
327 : {
328 0 : string tStr = replace_chars((*PIter), '/', ' ');
329 : ParameterList lstIndexParams;
330 0 : split_parameters(&lstIndexParams, tStr.c_str());
331 :
332 : uint iCount = 0;
333 0 : if(bGotPosition)
334 : {
335 0 : pActiveObject->m_vTriangleList.push_back(atoi(lstIndexParams[iCount].c_str()) - 1);
336 : iCount++;
337 : }
338 0 : if(bGotTexture && iCount < lstIndexParams.size())
339 : {
340 0 : pActiveObject->m_vTriangleListTex.push_back(atoi(lstIndexParams[iCount].c_str()) - 1);
341 : iCount++;
342 : }
343 : if(bGotNormal && iCount < lstIndexParams.size())
344 : {
345 : //pActiveObject->m_vTriangleList.push_back(atoi(lstIndexParams[iCount].c_str()) - 1);
346 : iCount++;
347 : }
348 :
349 :
350 0 : }
351 : }
352 0 : else if(lstParams.size() == 4)
353 : {
354 : unsigned int tInd[4];
355 : unsigned int tIndTex[4];
356 :
357 : int counter = 0;
358 0 : for(; PIter != lstParams.end(); PIter++)
359 : {
360 0 : string tStr = replace_chars((*PIter), '/', ' ');
361 : ParameterList lstIndexParams;
362 0 : split_parameters(&lstIndexParams, tStr.c_str());
363 0 : tInd[counter] = atoi((*lstIndexParams.begin()).c_str());
364 : uint iCount = 0;
365 0 : if(bGotPosition)
366 : {
367 0 : tInd[counter] = atoi(lstIndexParams[iCount].c_str());
368 : iCount++;
369 : }
370 0 : if(bGotTexture && iCount < lstIndexParams.size())
371 : {
372 0 : tIndTex[counter] = atoi(lstIndexParams[iCount].c_str());
373 : iCount++;
374 : }
375 : if(bGotNormal && iCount < lstIndexParams.size())
376 : {
377 : //iIndNorm
378 : iCount++;
379 : }
380 0 : counter++;
381 0 : }
382 0 : if(convertQuadsToTris)
383 : {
384 0 : if(bGotPosition)
385 : {
386 0 : pActiveObject->m_vTriangleList.push_back(tInd[0] - 1);
387 0 : pActiveObject->m_vTriangleList.push_back(tInd[1] - 1);
388 0 : pActiveObject->m_vTriangleList.push_back(tInd[2] - 1);
389 0 : pActiveObject->m_vTriangleList.push_back(tInd[0] - 1);
390 0 : pActiveObject->m_vTriangleList.push_back(tInd[2] - 1);
391 0 : pActiveObject->m_vTriangleList.push_back(tInd[3] - 1);
392 : }
393 0 : if(bGotTexture)
394 : {
395 0 : pActiveObject->m_vTriangleListTex.push_back(tIndTex[0] - 1);
396 0 : pActiveObject->m_vTriangleListTex.push_back(tIndTex[1] - 1);
397 0 : pActiveObject->m_vTriangleListTex.push_back(tIndTex[2] - 1);
398 0 : pActiveObject->m_vTriangleListTex.push_back(tIndTex[0] - 1);
399 0 : pActiveObject->m_vTriangleListTex.push_back(tIndTex[2] - 1);
400 0 : pActiveObject->m_vTriangleListTex.push_back(tIndTex[3] - 1);
401 : }
402 : }
403 : else
404 : {
405 0 : if(bGotPosition)
406 : {
407 0 : pActiveObject->m_vQuadList.push_back(tInd[0] - 1);
408 0 : pActiveObject->m_vQuadList.push_back(tInd[1] - 1);
409 0 : pActiveObject->m_vQuadList.push_back(tInd[2] - 1);
410 0 : pActiveObject->m_vQuadList.push_back(tInd[3] - 1);
411 : }
412 0 : if(bGotTexture)
413 : {
414 0 : pActiveObject->m_vQuadListTex.push_back(tIndTex[0] - 1);
415 0 : pActiveObject->m_vQuadListTex.push_back(tIndTex[1] - 1);
416 0 : pActiveObject->m_vQuadListTex.push_back(tIndTex[2] - 1);
417 0 : pActiveObject->m_vQuadListTex.push_back(tIndTex[3] - 1);
418 : }
419 : }
420 : }
421 : else {
422 0 : UG_LOG("WARNING: Couldn't read face in line " << lineNumber
423 : << ". Bad number of vertices: " << lstParams.size()
424 : << ". Only 3 and 4 supported.\n");
425 : }
426 : }
427 0 : else if(strCommand == strMtrl)
428 : {
429 0 : if(!pActiveObject){
430 0 : pActiveObject = new LoaderObj::Object;
431 0 : pActiveObject->m_strName = "default";
432 0 : pActiveObject->m_iMaterialIndex = -1;
433 : }
434 :
435 0 : if(lstParams.empty())
436 : {
437 0 : pActiveObject->m_strMaterialName = *lstParams.begin();
438 0 : pActiveObject->m_iMaterialIndex = get_material_index_by_name(pActiveObject->m_strMaterialName.c_str());
439 : }
440 : }
441 : }
442 :
443 0 : if(pActiveObject)
444 0 : m_vObjects.push_back(pActiveObject);
445 :
446 : return true;
447 0 : }
448 :
449 0 : int LoaderObj::get_material_index_by_name(const char* name) const
450 : {
451 : int counter = 0;
452 0 : for(MaterialVector::const_iterator iter = m_vMaterials.begin(); iter != m_vMaterials.end(); iter++)
453 : {
454 0 : if((*iter).m_strName.compare(name) == 0)
455 : return counter;
456 0 : counter++;
457 : }
458 : return -1;
459 : }
460 :
461 : }
|