NTrace
GPU ray tracing framework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
MeshWavefrontIO.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009-2011, NVIDIA Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of NVIDIA Corporation nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "io/MeshWavefrontIO.hpp"
29 #include "io/File.hpp"
30 #include "base/Hash.hpp"
31 
32 using namespace FW;
33 
34 //------------------------------------------------------------------------
35 
36 #define WAVEFRONT_DEBUG 0 // 1 = fail on error, 0 = ignore errors
37 
38 //------------------------------------------------------------------------
39 
40 namespace FW
41 {
42 
44 {
46 };
47 
49 {
53 };
54 
56 {
58 
62 
65 
68 };
69 
70 template <class T> bool equals (const VertexPNT& a, const VertexPNT& b);
71 template <class T> U32 hash (const VertexPNT& value);
72 
73 static bool parseFloats (const char*& ptr, F32* values, int num);
74 static bool parseTexture (const char*& ptr, TextureSpec& value, const String& dirName);
75 
76 static void loadMtl (ImportState& s, BufferedInputStream& mtlIn, const String& dirName);
77 static void loadObj (ImportState& s, BufferedInputStream& objIn, const String& dirName);
78 
79 }
80 
81 //------------------------------------------------------------------------
82 
83 template <class T> bool FW::equals(const VertexPNT& a, const VertexPNT& b)
84 {
85  return (equals<Vec3f>(a.p, b.p) && equals<Vec3f>(a.n, b.n) && equals<Vec2f>(a.t, b.t));
86 }
87 
88 //------------------------------------------------------------------------
89 
90 template <class T> U32 FW::hash(const VertexPNT& value)
91 {
92  return hashBits(hash<Vec3f>(value.p), hash<Vec3f>(value.n), hash<Vec2f>(value.t));
93 }
94 
95 //------------------------------------------------------------------------
96 
97 bool FW::parseFloats(const char*& ptr, F32* values, int num)
98 {
99  FW_ASSERT(values);
100  const char* tmp = ptr;
101  for (int i = 0; i < num; i++)
102  {
103  if (i)
104  parseSpace(tmp);
105  if (!parseFloat(tmp, values[i]))
106  return false;
107  }
108  ptr = tmp;
109  return true;
110 }
111 
112 //------------------------------------------------------------------------
113 
114 bool FW::parseTexture(const char*& ptr, TextureSpec& value, const String& dirName)
115 {
116  // Initialize result.
117 
118  String name;
119  value.texture = Texture();
120  value.base = 0.0f;
121  value.gain = 1.0f;
122 
123  if (hasError())
124  return false;
125 
126  // Parse options.
127 
128  while (*ptr)
129  {
130  parseSpace(ptr);
131  if ((parseLiteral(ptr, "-blendu ") || parseLiteral(ptr, "-blendv ") || parseLiteral(ptr, "-cc ") || parseLiteral(ptr, "-clamp ")) && parseSpace(ptr))
132  {
133  if (!parseLiteral(ptr, "on") && !parseLiteral(ptr, "off"))
134  return false;
135  }
136  else if (parseLiteral(ptr, "-mm ") && parseSpace(ptr))
137  {
138  if (!parseFloat(ptr, value.base) || !parseSpace(ptr) || !parseFloat(ptr, value.gain))
139  return false;
140  }
141  else if ((parseLiteral(ptr, "-o ") || parseLiteral(ptr, "-s ") || parseLiteral(ptr, "-t ")) && parseSpace(ptr))
142  {
143  F32 tmp[2];
144  if (!parseFloats(ptr, tmp, 2))
145  return false;
146  parseSpace(ptr);
147  parseFloat(ptr, tmp[0]);
148  }
149  else if ((parseLiteral(ptr, "-texres ") || parseLiteral(ptr, "-bm ")) && parseSpace(ptr))
150  {
151  F32 tmp;
152  if (!parseFloat(ptr, tmp))
153  return false;
154  }
155  else if (parseLiteral(ptr, "-type ") && parseSpace(ptr))
156  {
157  if (!parseLiteral(ptr, "sphere") &&
158  !parseLiteral(ptr, "cube_top") && !parseLiteral(ptr, "cube_bottom") &&
159  !parseLiteral(ptr, "cube_front") && !parseLiteral(ptr, "cube_back") &&
160  !parseLiteral(ptr, "cube_left") && !parseLiteral(ptr, "cube_right"))
161  {
162  return false;
163  }
164  }
165  else
166  {
167  if (*ptr == '-' || name.getLength())
168  return false;
169  while (*ptr && (*ptr != '-' || !name.endsWith(' ')))
170  name.append(*ptr++);
171  }
172  }
173 
174  // Process file name.
175 
176  while (name.startsWith('/'))
177  name = name.substring(1);
178  while (name.endsWith(' '))
179  name = name.substring(0, name.getLength() - 1);
180 
181  // Zero-length file name => ignore.
182 
183  if (!name.getLength())
184  return true;
185 
186  // Import texture.
187 
188  value.texture = Texture::import(dirName + '/' + name);
189 
190 #if (!WAVEFRONT_DEBUG)
191  clearError();
192 #endif
193  return true;
194 }
195 
196 //------------------------------------------------------------------------
197 
198 void FW::loadMtl(ImportState& s, BufferedInputStream& mtlIn, const String& dirName)
199 {
200  Material* mat = NULL;
201  for (int lineNum = 1;; lineNum++)
202  {
203  const char* line = mtlIn.readLine(true, true);
204  if (!line || ((lineNum & 0xFF) == 0 && hasError()))
205  break;
206 
207  const char* ptr = line;
208  parseSpace(ptr);
209  bool valid = false;
210 
211  if (!*ptr || parseLiteral(ptr, "#"))
212  {
213  valid = true;
214  }
215  else if (parseLiteral(ptr, "newmtl ") && parseSpace(ptr) && *ptr) // material name
216  {
217  if (!s.materialHash.contains(ptr))
218  {
219  mat = &s.materialHash.add(ptr);
220  mat->submesh = -1;
221  }
222  valid = true;
223  }
224  else if (!mat)
225  {
226 #if WAVEFRONT_DEBUG
227  setError("No current material in Wavefront MTL: '%s'!", line);
228 #endif
229  }
230  else if (parseLiteral(ptr, "Ka ") && parseSpace(ptr)) // ambient color
231  {
232  F32 tmp[3];
233  if (parseLiteral(ptr, "spectral ") || parseLiteral(ptr, "xyz "))
234  valid = true;
235  else if (parseFloats(ptr, tmp, 3) && parseSpace(ptr) && !*ptr)
236  valid = true;
237  }
238  else if (parseLiteral(ptr, "Kd ") && parseSpace(ptr)) // diffuse color
239  {
240  if (parseLiteral(ptr, "spectral ") || parseLiteral(ptr, "xyz "))
241  valid = true;
242  else if (parseFloats(ptr, mat->diffuse.getPtr(), 3) && parseSpace(ptr) && !*ptr)
243  valid = true;
244  }
245  else if (parseLiteral(ptr, "Ks ") && parseSpace(ptr)) // specular color
246  {
247  if (parseLiteral(ptr, "spectral ") || parseLiteral(ptr, "xyz "))
248  valid = true;
249  else if (parseFloats(ptr, mat->specular.getPtr(), 3) && parseSpace(ptr) && !*ptr)
250  valid = true;
251  }
252  else if (parseLiteral(ptr, "d ") && parseSpace(ptr)) // alpha
253  {
254  if (parseFloat(ptr, mat->diffuse.w) && parseSpace(ptr) && !*ptr)
255  valid = true;
256  }
257  else if (parseLiteral(ptr, "Ns ") && parseSpace(ptr)) // glossiness
258  {
259  if (parseFloat(ptr, mat->glossiness) && parseSpace(ptr) && !*ptr)
260  valid = true;
261  if (mat->glossiness <= 0.0f)
262  {
263  mat->glossiness = 1.0f;
264  mat->specular.setZero();
265  }
266  }
267  else if (parseLiteral(ptr, "map_Kd ")) // diffuse texture
268  {
269  TextureSpec tex;
270  valid = parseTexture(ptr, tex, dirName);
272  }
273  else if (parseLiteral(ptr, "map_d ") || parseLiteral(ptr, "map_D ") || parseLiteral(ptr, "map_opacity ")) // alpha texture
274  {
275  TextureSpec tex;
276  valid = parseTexture(ptr, tex, dirName);
278  }
279  else if (parseLiteral(ptr, "disp ")) // displacement map
280  {
281  TextureSpec tex;
282  valid = parseTexture(ptr, tex, dirName);
283  mat->displacementCoef = tex.gain;
284  mat->displacementBias = tex.base * tex.gain;
286  }
287  else if (parseLiteral(ptr, "bump ") || parseLiteral(ptr, "map_bump ") || parseLiteral(ptr, "map_Bump ")) // bump map
288  {
289  TextureSpec tex;
290  valid = parseTexture(ptr, tex, dirName);
292  }
293  else if (parseLiteral(ptr, "refl ")) // environment map
294  {
295  TextureSpec tex;
296  valid = parseTexture(ptr, tex, dirName);
298  }
299  //---------------------------------------------------------------------------------------------------------//
300  // Added functionality for extended material properties //
301  //---------------------------------------------------------------------------------------------------------//
302  // Emissivity //
303  else if (parseLiteral(ptr, "emissivity "))
304  {
305  valid = parseFloat(ptr, mat->emissivity);
306  }
307  //---------------------------------------------------------------------------------------------------------//
308  // Reflectivity //
309  else if (parseLiteral(ptr, "reflectivity "))
310  {
311  valid = parseFloat(ptr, mat->reflectivity);
312  }
313  //---------------------------------------------------------------------------------------------------------//
314  // Refractivity //
315  else if (parseLiteral(ptr, "refractivity "))
316  {
317  valid = parseFloat(ptr, mat->refractivity);
318  }
319  //---------------------------------------------------------------------------------------------------------//
320  // Index of Refraction //
321  else if (parseLiteral(ptr, "IOR "))
322  {
323  valid = parseFloat(ptr, mat->indexOfRefraction);
324  }
325  //---------------------------------------------------------------------------------------------------------//
326  else if (
327  parseLiteral(ptr, "vp ") || // parameter space vertex
328  parseLiteral(ptr, "Kf ") || // transmission color
329  parseLiteral(ptr, "illum ") || // illumination model
330  parseLiteral(ptr, "d -halo ") || // orientation-dependent alpha
331  parseLiteral(ptr, "sharpness ") || // reflection sharpness
332  parseLiteral(ptr, "Ni ") || // index of refraction
333  parseLiteral(ptr, "map_Ks ") || // specular texture
334  parseLiteral(ptr, "map_kS ") || // ???
335  parseLiteral(ptr, "map_kA ") || // ???
336  parseLiteral(ptr, "map_Ns ") || // glossiness texture
337  parseLiteral(ptr, "map_aat ") || // texture antialiasing
338  parseLiteral(ptr, "decal ") || // blended texture
339  parseLiteral(ptr, "Km ") || // ???
340  parseLiteral(ptr, "Tr ") || // ???
341  parseLiteral(ptr, "Tf ") || // ???
342  parseLiteral(ptr, "Ke ") || // ???
343  parseLiteral(ptr, "pointgroup ") || // ???
344  parseLiteral(ptr, "pointdensity ") || // ???
345  parseLiteral(ptr, "smooth") || // ???
346  parseLiteral(ptr, "R ")) // ???
347  {
348  valid = true;
349  }
350 
351 #if WAVEFRONT_DEBUG
352  if (!valid)
353  setError("Invalid line %d in Wavefront MTL: '%s'!", lineNum, line);
354 #endif
355  }
356 }
357 
358 //------------------------------------------------------------------------
359 
360 void FW::loadObj(ImportState& s, BufferedInputStream& objIn, const String& dirName)
361 {
362  int submesh = -1;
363  int defaultSubmesh = -1;
364 
365  for (int lineNum = 1;; lineNum++)
366  {
367  const char* line = objIn.readLine(true, true);
368  if (!line || ((lineNum & 0xFF) == 0 && hasError()))
369  break;
370 
371  const char* ptr = line;
372  parseSpace(ptr);
373  bool valid = false;
374 
375  if (!*ptr || parseLiteral(ptr, "#"))
376  {
377  valid = true;
378  }
379  else if (parseLiteral(ptr, "v ") && parseSpace(ptr)) // position vertex
380  {
381  Vec3f v;
382  if (parseFloats(ptr, v.getPtr(), 3) && parseSpace(ptr) && !*ptr)
383  {
384  s.positions.add(v);
385  valid = true;
386  }
387  }
388  else if (parseLiteral(ptr, "vt ") && parseSpace(ptr)) // texture vertex
389  {
390  Vec2f v;
391  if (parseFloats(ptr, v.getPtr(), 2) && parseSpace(ptr))
392  {
393  F32 dummy;
394  while (parseFloat(ptr, dummy) && parseSpace(ptr));
395 
396  if (!*ptr)
397  {
398  s.texCoords.add(Vec2f(v.x, 1.0f - v.y));
399  valid = true;
400  }
401  }
402  }
403  else if (parseLiteral(ptr, "vn ") && parseSpace(ptr)) // normal vertex
404  {
405  Vec3f v;
406  if (parseFloats(ptr, v.getPtr(), 3) && parseSpace(ptr) && !*ptr)
407  {
408  s.normals.add(v);
409  valid = true;
410  }
411  }
412  else if (parseLiteral(ptr, "f ") && parseSpace(ptr)) // face
413  {
414  s.vertexTmp.clear();
415  while (*ptr)
416  {
417  Vec3i ptn;
418  if (!parseInt(ptr, ptn.x))
419  break;
420  for (int i = 1; i < 4 && parseLiteral(ptr, "/"); i++)
421  {
422  S32 tmp = 0;
423  parseInt(ptr, tmp);
424  if (i < 3)
425  ptn[i] = tmp;
426  }
427  parseSpace(ptr);
428 
429  Vec3i size(s.positions.getSize(), s.texCoords.getSize(), s.normals.getSize());
430  for (int i = 0; i < 3; i++)
431  {
432  if (ptn[i] < 0)
433  ptn[i] += size[i];
434  else
435  ptn[i]--;
436 
437  if (ptn[i] < 0 || ptn[i] >= size[i])
438  ptn[i] = -1;
439  }
440 
441  S32* idx = s.vertexHash.search(ptn);
442  if (idx)
443  s.vertexTmp.add(*idx);
444  else
445  {
446  s.vertexTmp.add(s.vertexHash.add(ptn, s.mesh->numVertices()));
447  VertexPNT& v = s.mesh->addVertex();
448  v.p = (ptn.x == -1) ? Vec3f(0.0f) : s.positions[ptn.x];
449  v.t = (ptn.y == -1) ? Vec2f(0.0f) : s.texCoords[ptn.y];
450  v.n = (ptn.z == -1) ? Vec3f(0.0f) : s.normals[ptn.z];
451  }
452  }
453  if (!*ptr)
454  {
455  if (submesh == -1)
456  {
457  if (defaultSubmesh == -1)
458  defaultSubmesh = s.mesh->addSubmesh();
459  submesh = defaultSubmesh;
460  }
461  for (int i = 2; i < s.vertexTmp.getSize(); i++)
462  s.indexTmp.add(Vec3i(s.vertexTmp[0], s.vertexTmp[i - 1], s.vertexTmp[i]));
463  valid = true;
464  }
465  }
466  else if (parseLiteral(ptr, "usemtl ") && parseSpace(ptr)) // material name
467  {
468  Material* mat = s.materialHash.search(ptr);
469  if (submesh != -1)
470  {
471  s.mesh->mutableIndices(submesh).add(s.indexTmp);
472  s.indexTmp.clear();
473  submesh = -1;
474  }
475  if (mat)
476  {
477  if (mat->submesh == -1)
478  {
479  mat->submesh = s.mesh->addSubmesh();
480  s.mesh->material(mat->submesh) = *mat;
481  }
482  submesh = mat->submesh;
483  s.indexTmp.clear();
484  }
485  valid = true;
486  }
487  else if (parseLiteral(ptr, "mtllib ") && parseSpace(ptr) && *ptr) // material library
488  {
489  if (dirName.getLength())
490  {
491  if (hasError())
492  break;
493 
494  String fileName = dirName + "/" + ptr;
495  File file(fileName, File::Read);
496  BufferedInputStream mtlIn(file);
497  loadMtl(s, mtlIn, fileName.getDirName());
498 
499 #if (!WAVEFRONT_DEBUG)
500  clearError();
501 #endif
502  }
503  valid = true;
504  }
505  else if (
506  parseLiteral(ptr, "vp ") || // parameter space vertex
507  parseLiteral(ptr, "deg ") || // degree
508  parseLiteral(ptr, "bmat ") || // basis matrix
509  parseLiteral(ptr, "step ") || // step size
510  parseLiteral(ptr, "cstype ") || // curve/surface type
511  parseLiteral(ptr, "p ") || // point
512  parseLiteral(ptr, "l ") || // line
513  parseLiteral(ptr, "curv ") || // curve
514  parseLiteral(ptr, "curv2 ") || // 2d curve
515  parseLiteral(ptr, "surf ") || // surface
516  parseLiteral(ptr, "parm ") || // curve/surface parameters
517  parseLiteral(ptr, "trim ") || // curve/surface outer trimming loop
518  parseLiteral(ptr, "hole ") || // curve/surface inner trimming loop
519  parseLiteral(ptr, "scrv ") || // curve/surface special curve
520  parseLiteral(ptr, "sp ") || // curve/surface special point
521  parseLiteral(ptr, "end ") || // curve/surface end statement
522  parseLiteral(ptr, "con ") || // surface connect
523  parseLiteral(ptr, "g ") || // group name
524  parseLiteral(ptr, "s ") || // smoothing group
525  parseLiteral(ptr, "mg ") || // merging group
526  parseLiteral(ptr, "o ") || // object name
527  parseLiteral(ptr, "bevel ") || // bevel interpolation
528  parseLiteral(ptr, "c_interp ") || // color interpolation
529  parseLiteral(ptr, "d_interp ") || // dissolve interpolation
530  parseLiteral(ptr, "lod ") || // level of detail
531  parseLiteral(ptr, "shadow_obj ") || // shadow casting
532  parseLiteral(ptr, "trace_obj ") || // ray tracing
533  parseLiteral(ptr, "ctech ") || // curve approximation technique
534  parseLiteral(ptr, "stech ") || // surface approximation technique
535  parseLiteral(ptr, "g")) // ???
536  {
537  valid = true;
538  }
539 
540 #if WAVEFRONT_DEBUG
541  if (!valid)
542  setError("Invalid line %d in Wavefront OBJ: '%s'!", lineNum, line);
543 #endif
544  }
545 
546  // Flush remaining indices.
547 
548  if (submesh != -1)
549  s.mesh->mutableIndices(submesh).add(s.indexTmp);
550 }
551 
552 //------------------------------------------------------------------------
553 
555 {
556  int vertexCapacity = 4 << 10;
557  int indexCapacity = 4 << 10;
558 
559  ImportState s;
560  s.mesh = new Mesh<VertexPNT>;
561  s.mesh->resizeVertices(vertexCapacity);
562  s.mesh->clearVertices();
563  s.positions.setCapacity(vertexCapacity);
564  s.texCoords.setCapacity(vertexCapacity);
565  s.normals.setCapacity(vertexCapacity);
566  s.vertexHash.setCapacity(vertexCapacity);
567  s.indexTmp.setCapacity(indexCapacity);
568 
569  loadObj(s, stream, fileName.getDirName());
570  s.mesh->compact();
571  return s.mesh;
572 }
573 
574 //------------------------------------------------------------------------
575 
576 void FW::exportWavefrontMesh(BufferedOutputStream& stream, const MeshBase* mesh, const String& fileName)
577 {
578  FW_ASSERT(mesh);
579  Mesh<VertexPNT> pnt(*mesh);
580 
581  // Extract base name.
582 
583  String dirName = fileName.getDirName();
584  String baseName = fileName.getFileName();
585  int idx = baseName.indexOf('.');
586  if (idx != -1)
587  baseName = baseName.substring(0, idx);
588 
589  // Write OBJ file.
590 
591  if (baseName.getLength())
592  {
593  stream.writef("mtllib %s.mtl\n", baseName.getPtr());
594  stream.writef("\n");
595  }
596 
597  for (int i = 0; i < pnt.numVertices(); i++)
598  {
599  const VertexPNT& v = pnt.vertex(i);
600  stream.writef("v %g %g %g\n", v.p.x, v.p.y, v.p.z);
601  }
602  stream.writef("\n");
603 
604  for (int i = 0; i < pnt.numVertices(); i++)
605  {
606  const VertexPNT& v = pnt.vertex(i);
607  stream.writef("vt %g %g\n", v.t.x, 1.0f - v.t.y);
608  }
609  stream.writef("\n");
610 
611  for (int i = 0; i < pnt.numVertices(); i++)
612  {
613  const VertexPNT& v = pnt.vertex(i);
614  stream.writef("vn %g %g %g\n", v.n.x, v.n.y, v.n.z);
615  }
616 
617  for (int i = 0; i < pnt.numSubmeshes(); i++)
618  {
619  stream.writef("\n");
620  if (baseName.getLength())
621  stream.writef("usemtl %d\n", i);
622 
623  const Array<Vec3i>& tris = pnt.indices(i);
624  for (int j = 0; j < tris.getSize(); j++)
625  {
626  Vec3i v = tris[j] + 1;
627  stream.writef("f %d/%d/%d %d/%d/%d %d/%d/%d\n",
628  v.x, v.x, v.x,
629  v.y, v.y, v.y,
630  v.z, v.z, v.z);
631  }
632  }
633 
634  // No base name => do not write materials.
635 
636  if (!baseName.getLength())
637  return;
638 
639  // Hash textures and determine file names.
640 
641  Hash<const Image*, String> texImageHash;
642  Set<String> texNameSet;
643 
644  for (int i = 0; i < pnt.numSubmeshes(); i++)
645  {
646  const MeshBase::Material& mat = pnt.material(i);
647  for (int j = 0; j < MeshBase::TextureType_Max; j++)
648  {
649  const Texture& tex = mat.textures[j];
650  if (!tex.exists() || texImageHash.contains(tex.getImage()))
651  continue;
652 
653  // Extract name from ID.
654 
655  String name = tex.getID().getFileName();
656  int idx = name.indexOf('.');
657  if (idx != -1)
658  name = name.substring(0, idx);
659 
660  // No name => generate one.
661 
662  if (!name.getLength())
663  name = sprintf("tex%d", texImageHash.getSize());
664 
665  // Ensure that the name is unique.
666 
667  String oldName = name;
668  for (int k = 0; texNameSet.contains(name); k++)
669  name = sprintf("%s_%d", oldName.getPtr(), k);
670 
671  // Append format postfix.
672 
673  name += ".png";
674 
675  // Record.
676 
677  texImageHash.add(tex.getImage(), name);
678  texNameSet.add(name);
679  }
680  }
681 
682  // Write MTL file.
683 
684  File mtlFile(dirName + '/' + baseName + ".mtl", File::Create);
685  BufferedOutputStream mtlOut(mtlFile);
686  for (int i = 0; i < pnt.numSubmeshes(); i++)
687  {
688  if (i)
689  mtlOut.writef("\n");
690 
691  const MeshBase::Material& mat = pnt.material(i);
692  mtlOut.writef("newmtl %d\n", i);
693  mtlOut.writef("Ka 0 0 0\n");
694  mtlOut.writef("Kd %g %g %g\n", mat.diffuse.x, mat.diffuse.y, mat.diffuse.z);
695  mtlOut.writef("d %g\n", mat.diffuse.w);
696  mtlOut.writef("Ks %g %g %g\n", mat.specular.x, mat.specular.y, mat.specular.z);
697  mtlOut.writef("Ns %g\n", mat.glossiness);
698 
699  if (texImageHash.contains(mat.textures[MeshBase::TextureType_Diffuse].getImage()))
700  mtlOut.writef("map_Kd %s\n", texImageHash[mat.textures[MeshBase::TextureType_Diffuse].getImage()].getPtr());
701 
702  if (texImageHash.contains(mat.textures[MeshBase::TextureType_Alpha].getImage()))
703  mtlOut.writef("map_d %s\n", texImageHash[mat.textures[MeshBase::TextureType_Alpha].getImage()].getPtr());
704 
706  mtlOut.writef("disp -mm %g %g %s\n",
708  texImageHash[mat.textures[MeshBase::TextureType_Displacement].getImage()].getPtr());
709 
710  if (texImageHash.contains(mat.textures[MeshBase::TextureType_Normal].getImage()))
711  mtlOut.writef("bump %s\n", texImageHash[mat.textures[MeshBase::TextureType_Normal].getImage()].getPtr());
712 
714  mtlOut.writef("refl -type sphere %s\n", texImageHash[mat.textures[MeshBase::TextureType_Environment].getImage()].getPtr());
715  }
716  mtlOut.flush();
717 
718  // Write textures.
719 
720  for (int i = texImageHash.firstSlot(); i != -1; i = texImageHash.nextSlot(i))
721  {
722  const Image* texImage = texImageHash.getSlot(i).key;
723  const String& texName = texImageHash.getSlot(i).value;
724  exportImage(dirName + '/' + texName, texImage);
725  }
726 }
727 
728 //------------------------------------------------------------------------
void exportImage(const String &fileName, const Image *image)
Definition: Image.cpp:1069
int nextSlot(int slot) const
Definition: Hash.hpp:150
String & append(char chr)
Definition: String.cpp:173
virtual void flush(void)
Definition: Stream.cpp:275
bool contains(const K &key) const
Definition: Hash.hpp:123
#define NULL
Definition: Defs.hpp:39
Array< Vec3f > positions
String substring(int start, int end) const
Definition: String.cpp:96
bool endsWith(const String &str) const
Definition: String.cpp:273
Mesh< VertexPNT > * mesh
const char * getPtr(void) const
Definition: String.hpp:51
String getFileName(void) const
Definition: String.cpp:284
FW_CUDA_FUNC const F32 * getPtr(void) const
Definition: Math.hpp:359
int indexOf(char chr) const
Definition: String.hpp:78
Array< Vec3f > normals
Definition: Hash.hpp:37
const Image * getImage(void) const
Definition: Texture.hpp:64
const char * name
Definition: DLLImports.cpp:42
void setError(const char *fmt,...)
Definition: Defs.cpp:253
void ** ptr
Definition: DLLImports.cpp:74
FW_CUDA_FUNC const F32 * getPtr(void) const
Definition: Math.hpp:309
int numSubmeshes(void) const
Definition: Mesh.hpp:152
String clearError(void)
Definition: Defs.cpp:269
U32 hash(const T &value)
Definition: Hash.hpp:199
const Material & material(int submesh) const
Definition: Mesh.hpp:161
void clear(void)
Definition: Array.hpp:359
Array< Vec3i > indexTmp
T & add(const T &value)
Definition: Hash.hpp:72
char * readLine(bool combineWithBackslash=false, bool normalizeWhitespace=false)
Definition: Stream.cpp:89
void exportWavefrontMesh(BufferedOutputStream &stream, const MeshBase *mesh, const String &fileName)
Vec3f p
Definition: Mesh.hpp:291
Mesh< VertexPNT > * importWavefrontMesh(BufferedInputStream &stream, const String &fileName)
bool parseLiteral(const char *&ptr, const char *str)
Definition: String.cpp:365
const Entry & getSlot(int slot) const
Definition: Hash.hpp:151
float F32
Definition: Defs.hpp:89
bool contains(const T &value) const
Definition: Hash.hpp:60
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer GLenum GLuint renderbuffer GLenum GLsizeiptr const GLvoid GLenum usage GLuint shader GLenum type GLsizei const GLuint framebuffers GLsizei const GLuint renderbuffers GLuint v
Definition: DLLImports.inl:329
static Texture import(const String &fileName)
Definition: Texture.cpp:56
Hash< Vec3i, S32 > vertexHash
const V & vertex(int idx) const
Definition: Mesh.hpp:223
#define FW_ASSERT(X)
Definition: Defs.hpp:67
signed int S32
Definition: Defs.hpp:88
int getLength(void) const
Definition: String.hpp:49
bool equals< Vec3f >(const Vec3f &a, const Vec3f &b)
Definition: Hash.hpp:256
FW_CUDA_FUNC void setZero(void)
Definition: Math.hpp:134
String getDirName(void) const
Definition: String.cpp:292
bool exists(void) const
Definition: Texture.hpp:62
Vec3f n
Definition: Mesh.hpp:292
T & add(void)
Definition: Array.hpp:384
String sprintf(const char *fmt,...)
Definition: Defs.cpp:241
bool parseInt(const char *&ptr, S32 &value)
Definition: String.cpp:384
bool equals(const T &a, const T &b)
Definition: Hash.hpp:198
FW_CUDA_FUNC const F32 * getPtr(void) const
Definition: Math.hpp:333
int getSize(void) const
Definition: Hash.hpp:122
V & add(const K &key, const V &value)
Definition: Hash.hpp:143
int numVertices(void) const
Definition: Mesh.hpp:136
Vec2f t
Definition: Mesh.hpp:293
unsigned int U32
Definition: Defs.hpp:85
bool hasError(void)
Definition: Defs.cpp:289
K key
Definition: Hash.hpp:104
U32 hashBits(U32 a, U32 b=FW_HASH_MAGIC, U32 c=0)
Definition: Hash.hpp:183
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction f
Definition: DLLImports.inl:88
const Array< Vec3i > & indices(int submesh) const
Definition: Mesh.hpp:156
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value
Definition: DLLImports.inl:84
Texture textures[TextureType_Max]
Definition: Mesh.hpp:92
bool parseFloat(const char *&ptr, F32 &value)
Definition: String.cpp:440
Array< Vec2f > texCoords
bool startsWith(const String &str) const
Definition: String.cpp:261
bool parseSpace(const char *&ptr)
Definition: String.cpp:344
Array< S32 > vertexTmp
V value
Definition: Hash.hpp:105
String getID(void) const
Definition: Texture.hpp:63
U32 hash< Vec3f >(const Vec3f &value)
Definition: Hash.hpp:267
void writef(const char *fmt,...)
Definition: Stream.cpp:239
U32 hash< Vec2f >(const Vec2f &value)
Definition: Hash.hpp:265
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer GLenum GLuint renderbuffer GLenum GLsizeiptr size
Definition: DLLImports.inl:319
S getSize(void) const
Definition: Array.hpp:188
Hash< String, Material > materialHash
bool equals< Vec2f >(const Vec2f &a, const Vec2f &b)
Definition: Hash.hpp:254
int firstSlot(void) const
Definition: Hash.hpp:149