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 <fstream>
34 : #include <vector>
35 : #include <cstring>
36 : #include <string>
37 : #include "file_io_obj.h"
38 : #include "../lg_base.h"
39 : #include "common/util/loader/loader_obj.h"
40 : #include "common/error.h"
41 :
42 : using namespace std;
43 :
44 : namespace ug
45 : {
46 : //TODO: disable automatic triangulation. create edges. create quads.
47 : ////////////////////////////////////////////////////////////////////////
48 : // LoadGridFromOBJ
49 : /// Loads a file from a wavefront '.obj' file. Fills optional subset-infos.
50 0 : bool LoadGridFromOBJ(Grid& grid, const char* filename, AVector3& aPos,
51 : AVector2* paTexCoord,
52 : ISubsetHandler* pSubsetHandler,
53 : std::vector<OBJMaterial>* pvMaterials)
54 : {
55 : LoaderObj loader;
56 :
57 0 : if(!loader.load_file(filename, false))
58 : return false;
59 :
60 0 : if(loader.num_points() == 0)
61 : return false;
62 :
63 : // attach data and attachment accessors
64 0 : if(!grid.has_vertex_attachment(aPos))
65 0 : grid.attach_to_vertices(aPos);
66 : Grid::VertexAttachmentAccessor<AVector3> aaPosVRT(grid, aPos);
67 :
68 : // create vertices and assign position data.
69 : // Store pointers in a vector so that they can be accessed by index.
70 : vector<RegularVertex*> vVertices;
71 0 : vVertices.reserve(loader.num_points());
72 : {
73 0 : for(uint i = 0; i < (uint)loader.num_points(); ++i)
74 : {
75 0 : RegularVertex* pVrt = *grid.create<RegularVertex>();
76 0 : vVertices.push_back(pVrt);
77 0 : aaPosVRT[pVrt] = *loader.point(i);
78 : }
79 : // if a subset handler was specified, we'll push all vertices into subset 0
80 0 : if(pSubsetHandler){
81 : pSubsetHandler->assign_subset(grid.begin<RegularVertex>(), grid.end<RegularVertex>(), 0);
82 : }
83 : }
84 :
85 : // iterate through the objects in loader and add edges and faces to grid.
86 : // assign subsets and material indices at the same time.
87 : {
88 : int objCounter = 0;
89 0 : for(LoaderObj::ObjectIterator oIter = loader.objects_begin();
90 0 : oIter != loader.objects_end(); ++oIter, ++objCounter)
91 : {
92 0 : LoaderObj::Object& obj = *(*oIter);
93 : // set the subset-info of this object - if requested.
94 0 : if(pSubsetHandler != NULL)
95 : {
96 0 : SubsetInfo si = pSubsetHandler->subset_info(objCounter);
97 0 : si.materialIndex = obj.m_iMaterialIndex;
98 0 : si.name = obj.m_strName;
99 :
100 0 : pSubsetHandler->set_subset_info(objCounter, si);
101 : }
102 :
103 : // create edges and faces.
104 : // creation differs if a subset handler is supplied.
105 0 : if(pSubsetHandler == NULL)
106 : {
107 : // create edges
108 0 : for(size_t i = 0; i < obj.m_vEdgeList.size(); i+=2){
109 0 : for(size_t j = i; j < i+2; ++j){
110 0 : if(obj.m_vEdgeList[j] < 0 || obj.m_vEdgeList[j] >= (int)vVertices.size()){
111 0 : UG_THROW("Bad vertex index in edge " << i / 2 << ": " << obj.m_vEdgeList[i] + 1);
112 : }
113 : }
114 0 : grid.create<RegularEdge>(EdgeDescriptor(vVertices[obj.m_vEdgeList[i]],
115 0 : vVertices[obj.m_vEdgeList[i+1]]));
116 : }
117 : // create triangles
118 0 : for(size_t i = 0; i < obj.m_vTriangleList.size(); i+=3){
119 0 : for(size_t j = i; j < i+3; ++j){
120 0 : if(obj.m_vTriangleList[j] < 0 || obj.m_vTriangleList[j] >= (int)vVertices.size()){
121 0 : UG_THROW("Bad vertex index in triangle " << i / 3 << ": " << obj.m_vTriangleList[i] + 1);
122 : }
123 : }
124 0 : grid.create<Triangle>(TriangleDescriptor(vVertices[obj.m_vTriangleList[i]],
125 0 : vVertices[obj.m_vTriangleList[i+1]], vVertices[obj.m_vTriangleList[i+2]]));
126 : }
127 :
128 : // create quads
129 0 : for(size_t i = 0; i < obj.m_vQuadList.size(); i+=4){
130 0 : for(size_t j = i; j < i+4; ++j){
131 0 : if(obj.m_vQuadList[j] < 0 || obj.m_vQuadList[j] >= (int)vVertices.size()){
132 0 : UG_THROW("Bad vertex index in quadrilateral " << i / 4 << ": " << obj.m_vQuadList[i] + 1);
133 : }
134 : }
135 0 : grid.create<Quadrilateral>(QuadrilateralDescriptor(vVertices[obj.m_vQuadList[i]],
136 0 : vVertices[obj.m_vQuadList[i+1]], vVertices[obj.m_vQuadList[i+2]],
137 0 : vVertices[obj.m_vQuadList[i+3]]));
138 : }
139 : }
140 : else
141 : {
142 : // create edges
143 0 : for(size_t i = 0; i < obj.m_vEdgeList.size(); i+=2)
144 : {
145 0 : for(size_t j = i; j < i+2; ++j){
146 0 : if(obj.m_vEdgeList[j] < 0 || obj.m_vEdgeList[j] >= (int)vVertices.size()){
147 0 : UG_THROW("Bad vertex index in edge " << i / 2 << ": " << obj.m_vEdgeList[i] + 1);
148 : }
149 : }
150 0 : RegularEdge* e = *grid.create<RegularEdge>(EdgeDescriptor(vVertices[obj.m_vEdgeList[i]],
151 0 : vVertices[obj.m_vEdgeList[i+1]]));
152 0 : pSubsetHandler->assign_subset(e, objCounter);
153 : }
154 :
155 : // create triangles
156 0 : for(size_t i = 0; i < obj.m_vTriangleList.size(); i+=3)
157 : {
158 0 : for(size_t j = i; j < i+3; ++j){
159 0 : if(obj.m_vTriangleList[j] < 0 || obj.m_vTriangleList[j] >= (int)vVertices.size()){
160 0 : UG_THROW("Bad vertex index in triangle " << i / 3 << ": " << obj.m_vTriangleList[i] + 1);
161 : }
162 : }
163 0 : Triangle* tri = *grid.create<Triangle>(TriangleDescriptor(vVertices[obj.m_vTriangleList[i]],
164 0 : vVertices[obj.m_vTriangleList[i+1]], vVertices[obj.m_vTriangleList[i+2]]));
165 0 : pSubsetHandler->assign_subset(tri, objCounter);
166 : }
167 :
168 : // create quads
169 0 : for(size_t i = 0; i < obj.m_vQuadList.size(); i+=4)
170 : {
171 0 : for(size_t j = i; j < i+4; ++j){
172 0 : if(obj.m_vQuadList[j] < 0 || obj.m_vQuadList[j] >= (int)vVertices.size()){
173 0 : UG_THROW("Bad vertex index in quadrilateral " << i / 4 << ": " << obj.m_vQuadList[i] + 1);
174 : }
175 : }
176 0 : Quadrilateral* q = *grid.create<Quadrilateral>(QuadrilateralDescriptor(vVertices[obj.m_vQuadList[i]],
177 0 : vVertices[obj.m_vQuadList[i+1]], vVertices[obj.m_vQuadList[i+2]],
178 0 : vVertices[obj.m_vQuadList[i+3]]));
179 0 : pSubsetHandler->assign_subset(q, objCounter);
180 : }
181 : }
182 :
183 : // assign texture coords if the corresponding attachment is supplied
184 0 : if(paTexCoord != NULL)
185 : {
186 : // since you can specify texture coords for each face from the .obj specification,
187 : // and since libGrid only supports one texture coord per vertex, we reduce
188 : // the supplied information.
189 : Grid::VertexAttachmentAccessor<AVector2> aaTexVRT(grid, *paTexCoord);
190 0 : for(int i= 0; i < (int)obj.m_vTriangleListTex.size(); ++i)
191 0 : aaTexVRT[vVertices[i]] = *loader.uv(obj.m_vTriangleListTex[i]);
192 : }
193 : }
194 : }
195 :
196 : // copy materials to pvMaterials - if supplied
197 0 : if(pvMaterials != NULL)
198 : {
199 0 : pvMaterials->resize(loader.num_materials());
200 0 : for(int i = 0; i < loader.num_materials(); ++i)
201 : {
202 : const LoaderObj::Material& mat = loader.get_material(i);
203 0 : (*pvMaterials)[i].m_strName = mat.m_strName;
204 0 : (*pvMaterials)[i].m_strTextureDiffuse = mat.m_strTextureDiffuse;
205 : (*pvMaterials)[i].m_vDiffuse = mat.m_vDiffuse;
206 0 : (*pvMaterials)[i].m_fAlpha = mat.m_fAlpha;
207 : }
208 : }
209 :
210 : return true;
211 0 : }
212 :
213 :
214 0 : static void WriteEdges(ofstream& out, EdgeIterator edgesBegin, EdgeIterator edgesEnd,
215 : int indexDimension, Grid::VertexAttachmentAccessor<AInt>& aaInt)
216 : {
217 0 : while(edgesBegin != edgesEnd)
218 : {
219 : Edge* e = *edgesBegin;
220 0 : out << "f";
221 0 : for(uint i = 0; i < 2; ++i)
222 : {
223 0 : out << " " << aaInt[e->vertex(i)];
224 0 : for(int j = 1; j < indexDimension; ++j)
225 0 : out << '/' << aaInt[e->vertex(i)];
226 : }
227 : ++edgesBegin;
228 : out << endl;
229 : }
230 0 : }
231 :
232 0 : static void WriteFaces(ofstream& out, FaceIterator facesBegin, FaceIterator facesEnd,
233 : int indexDimension, Grid::VertexAttachmentAccessor<AInt>& aaInt)
234 : {
235 0 : while(facesBegin != facesEnd)
236 : {
237 : Face* f = *facesBegin;
238 0 : out << "f";
239 0 : for(uint i = 0; i < f->num_vertices(); ++i)
240 : {
241 0 : out << " " << aaInt[f->vertex(i)];
242 0 : for(int j = 1; j < indexDimension; ++j)
243 0 : out << '/' << aaInt[f->vertex(i)];
244 : }
245 : ++facesBegin;
246 : out << endl;
247 : }
248 0 : }
249 :
250 0 : bool SaveGridToOBJ(Grid& grid, const char* filename, AVector3& aPos,
251 : AVector2* paTexCoord,
252 : ISubsetHandler* pSubsetHandler,
253 : std::vector<OBJMaterial>* pvMaterials)
254 : {
255 : // check whether the grid has vertex-position data. If not, return false
256 0 : if(!grid.has_vertex_attachment(aPos)){
257 : UG_LOG("ERROR in SaveGridToOBJ: Position attachment missing.\n");
258 0 : return false;
259 : }
260 :
261 : string mtrlFullFilename;
262 : string mtrlFilename;
263 :
264 : // check if there are materials
265 0 : if(pvMaterials)
266 : {
267 : // we have to construct the material-file name.
268 : mtrlFullFilename = filename;
269 0 : if(mtrlFullFilename.at(mtrlFullFilename.size() - 4) == '.')
270 0 : mtrlFullFilename.erase(mtrlFullFilename.size() - 4, 4);
271 0 : mtrlFullFilename.append(".mtl");
272 :
273 : // extract the name of the file and store it in mtrlFilename
274 : string::size_type ind1, ind2;
275 0 : ind1 = mtrlFullFilename.find_last_of('\\');
276 0 : ind2 = mtrlFullFilename.find_last_of('/');
277 0 : if(ind1 == string::npos)
278 0 : ind1 = ind2;
279 0 : else if(ind2 != string::npos)
280 0 : ind1 = max(ind1, ind2);
281 :
282 : // assign the filename
283 0 : if(ind1 == string::npos)
284 : mtrlFilename = mtrlFullFilename;
285 : else
286 0 : mtrlFilename.assign(mtrlFullFilename, ind1, mtrlFullFilename.size() - ind1);
287 : }
288 :
289 : // write the .obj file
290 : {
291 0 : ofstream out(filename);
292 :
293 : // write the header
294 : out << "# exported from libGrid" << endl;
295 :
296 : // write material file
297 0 : if(pvMaterials)
298 : out << "mtllib " << mtrlFilename << endl;
299 :
300 : int indexDimension = 1;
301 :
302 : // store indices in the vertices
303 : AInt aInt;
304 : grid.attach_to_vertices(aInt);
305 : Grid::VertexAttachmentAccessor<AInt> aaInt(grid, aInt);
306 :
307 : // write vertex data
308 : {
309 : int counter = 1;
310 : Grid::VertexAttachmentAccessor<AVector3> aaPos(grid, aPos);
311 0 : for(VertexIterator iter = grid.vertices_begin(); iter != grid.vertices_end(); ++iter, ++counter)
312 : {
313 0 : out << "v " << aaPos[*iter].x() << " " << aaPos[*iter].y() << " " <<
314 0 : aaPos[*iter].z() << endl;
315 0 : aaInt[*iter] = counter;
316 : }
317 : }
318 :
319 : // if texture data is supplied we have to write it too
320 0 : if(paTexCoord != NULL)
321 : {
322 : indexDimension++;
323 : Grid::VertexAttachmentAccessor<AVector2> aaTex(grid, *paTexCoord);
324 0 : for(VertexIterator iter = grid.vertices_begin(); iter != grid.vertices_end(); ++iter)
325 : {
326 0 : out << "vt " << aaTex[*iter].x() << " " <<
327 0 : aaTex[*iter].y() << " 0.0" << endl;
328 : }
329 : }
330 :
331 : // if a subset handler is supplied, we'll export each subset as a separate object.
332 0 : if(pSubsetHandler)
333 : {
334 0 : for(int i = 0; i < pSubsetHandler->num_subsets(); ++i)
335 : {
336 : // write object
337 0 : if(pSubsetHandler->subset_info(i).name.size() > 0)
338 0 : out << "o " << pSubsetHandler->subset_info(i).name << endl;
339 : else
340 0 : out << "o " << "sub_" << i << endl;
341 :
342 : // write material reference
343 0 : if((pvMaterials != NULL) && (pSubsetHandler->subset_info(i).materialIndex != -1))
344 0 : out << "usemtl " << (*pvMaterials)[pSubsetHandler->subset_info(i).materialIndex].m_strName << endl;
345 : else
346 : out << "usemtl (null)" << endl;
347 :
348 : // get the goc
349 : GridObjectCollection goc = pSubsetHandler->
350 0 : get_grid_objects_in_subset(i);
351 :
352 0 : for(size_t lvl = 0; lvl < goc.num_levels(); ++lvl){
353 : // write the edges of this subset
354 0 : WriteEdges(out, goc.begin<Edge>(lvl),
355 0 : goc.end<Edge>(lvl), indexDimension, aaInt);
356 :
357 : // write the faces of this subset
358 0 : WriteFaces(out, goc.begin<Face>(lvl), goc.end<Face>(lvl),
359 : indexDimension, aaInt);
360 : }
361 : }
362 : }
363 : else
364 : {
365 : // since no subset handler was supplied, we'll treat the whole grid as on object.
366 : out << "o nonameknown" << endl;
367 : out << "usemtl (null)" << endl;
368 : // write the edges
369 0 : WriteEdges(out, grid.edges_begin(), grid.edges_end(), indexDimension, aaInt);
370 :
371 : // write the faces
372 0 : WriteFaces(out, grid.faces_begin(), grid.faces_end(), indexDimension, aaInt);
373 : }
374 :
375 : // clean up
376 : grid.detach_from_vertices(aInt);
377 : // .obj done
378 0 : out.close();
379 0 : }
380 :
381 : // write the material file
382 0 : if(pvMaterials)
383 : {
384 0 : ofstream out(mtrlFullFilename.c_str());
385 : out << "# exported from libMesh" << endl;
386 : out << "# Material Count: " << pvMaterials->size() << endl;
387 :
388 0 : for(uint i = 0; i < pvMaterials->size(); ++i)
389 : {
390 : vector4& vD = (*pvMaterials)[i].m_vDiffuse;
391 : out << "newmtl " << (*pvMaterials)[i].m_strName << endl;
392 0 : out << "Kd " << vD.x() << " " << vD.y() << " " << vD.z() << endl;
393 0 : out << "d " << vD.w() << endl;
394 0 : if((*pvMaterials)[i].m_strTextureDiffuse.size() > 0)
395 : out << "map_Kd " << (*pvMaterials)[i].m_strTextureDiffuse << endl;
396 : }
397 :
398 : // done
399 0 : out.close();
400 0 : }
401 :
402 : return true;
403 : }
404 :
405 : }// end of namespace
|