Advertisement
Guest User

Untitled

a guest
Feb 25th, 2020
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.41 KB | None | 0 0
  1. /*! \file objloader.cpp
  2. \brief Načítání Wavefront OBJ souborů.
  3. http://en.wikipedia.org/wiki/Wavefront_.obj_file
  4. */
  5.  
  6. #include "pch.h"
  7. #include "material.h"
  8. #include "utils.h"
  9. #include "surface.h"
  10. #include "mymath.h"
  11.  
  12. int MaterialIndex( std::vector<Material *> & materials, const char * material_name )
  13. {
  14. int index = 0;
  15.  
  16. for ( Material * material : materials )
  17. {
  18. if ( material->name().compare( material_name ) == 0 )
  19. {
  20. return index;
  21. }
  22.  
  23. index++;
  24. }
  25.  
  26. return -1;
  27. }
  28.  
  29. Texture * TextureProxy(const std::string & full_name, std::map<std::string, Texture*> & already_loaded_textures,
  30. const int flip = -1, const bool single_channel = false )
  31. {
  32. std::map<std::string, Texture*>::iterator already_loaded_texture = already_loaded_textures.find(full_name);
  33. Texture * texture = NULL;
  34. if (already_loaded_texture != already_loaded_textures.end())
  35. {
  36. texture = already_loaded_texture->second;
  37. }
  38. else
  39. {
  40. texture = new Texture( full_name.c_str() );// , flip, single_channel);
  41. already_loaded_textures[full_name] = texture;
  42. }
  43.  
  44. return texture;
  45. }
  46.  
  47. /*! \fn LoadMTL( const char * file_name, const char * path, std::vector<Material *> & materials )
  48. \brief Načte materiály z MTL souboru \a file_name.
  49. Soubor \a file_name se musí nacházet v cestě \a path. Načtené materiály budou vráceny přes pole \a materials.
  50. \param file_name název MTL souboru včetně přípony.
  51. \param path cesta k zadanému souboru.
  52. \param materials pole materiálů, do kterého se budou ukládat načtené materiály.
  53. */
  54. int LoadMTL( const char * file_name, const char * path, std::vector<Material *> & materials )
  55. {
  56. // otevření soouboru
  57. FILE * file = fopen( file_name, "rt" );
  58. if ( file == NULL )
  59. {
  60. printf( "File %s not found.\n", file_name );
  61.  
  62. return -1;
  63. }
  64.  
  65. // načtení celého souboru do paměti
  66. size_t file_size = static_cast<size_t>( GetFileSize64( file_name ) );
  67. char * buffer = new char[file_size + 1]; // +1 protože budeme za poslední načtený byte dávat NULL
  68. char * buffer_backup = new char[file_size + 1];
  69.  
  70. printf( "Loading materials from '%s' (%0.1f KB)...\n", file_name, file_size / 1024.0f );
  71.  
  72. size_t number_of_items_read = fread( buffer, sizeof( *buffer ), file_size, file );
  73.  
  74. // otestujeme korektnost načtení dat
  75. if ( !feof( file ) && ( number_of_items_read != file_size ) )
  76. {
  77. printf( "Unexpected end of file encountered.\n" );
  78.  
  79. fclose( file );
  80. file = NULL;
  81.  
  82. return -1;
  83. }
  84.  
  85. buffer[number_of_items_read] = 0; // zajistíme korektní ukončení řetězce
  86.  
  87. fclose( file ); // ukončíme práci se souborem
  88. file = NULL;
  89.  
  90. memcpy( buffer_backup, buffer, file_size + 1 ); // záloha bufferu
  91.  
  92. printf( "Done.\n\n");
  93.  
  94. printf( "Parsing mesh data...\n" );
  95.  
  96. char material_name[128] = { 0 };
  97. char image_file_name[256] = { 0 };
  98.  
  99. const char delim[] = "\n";
  100. char * line = strtok( buffer, delim );
  101.  
  102. std::map<std::string, Texture*> already_loaded_textures;
  103.  
  104. Material * material = NULL;
  105.  
  106. // --- načítání všech materiálů ---
  107. while ( line != NULL )
  108. {
  109. if ( line[0] != '#' )
  110. {
  111. if ( strstr( line, "newmtl" ) == line )
  112. {
  113. if ( material != NULL )
  114. {
  115. material->set_name( material_name );
  116. if ( MaterialIndex( materials, material_name ) < 0 )
  117. {
  118. materials.push_back( material );
  119. printf( "\r%I64u material(s)\t\t", materials.size() );
  120. }
  121. }
  122. material = NULL;
  123.  
  124. sscanf( line, "%*s %s", &material_name );
  125. //printf( "material name=%s\n", material_name );
  126.  
  127. material = new Material();
  128. }
  129. else
  130. {
  131. char * tmp = Trim( line );
  132. if ( strstr( tmp, "Ka" ) == tmp ) // ambient color of the material
  133. {
  134. sscanf( tmp, "%*s %f %f %f", &material->ambient_.r, &material->ambient_.g, &material->ambient_.b );
  135. material->ambient_ = material->ambient_.linear();
  136. }
  137. else if ( strstr( tmp, "Kd" ) == tmp ) // diffuse color of the material
  138. {
  139. sscanf( tmp, "%*s %f %f %f", &material->diffuse_.r, &material->diffuse_.g, &material->diffuse_.b );
  140. material->diffuse_ = material->diffuse_.linear();
  141. }
  142. else if ( strstr( tmp, "Ks" ) == tmp ) // specular color of the material
  143. {
  144. sscanf( tmp, "%*s %f %f %f", &material->specular_.r, &material->specular_.g, &material->specular_.b );
  145. material->specular_ = material->specular_.linear();
  146. }
  147. else if ( strstr( tmp, "Ke" ) == tmp ) // emission color of the material
  148. {
  149. sscanf( tmp, "%*s %f %f %f", &material->emission_.r, &material->emission_.g, &material->emission_.b );
  150. //material->emission_ = material->emission_.linear();
  151. }
  152. else if ( strstr( tmp, "Ns" ) == tmp ) // specular coefficient
  153. {
  154. sscanf( tmp, "%*s %f", &material->shininess );
  155. }
  156. else if ( strstr( tmp, "map_Kd" ) == tmp ) // diffuse map
  157. {
  158. sscanf( tmp, "%*s %s", image_file_name );
  159. std::string full_name = std::string( path ).append( image_file_name );
  160. material->set_texture( Material::kDiffuseMapSlot, TextureProxy( full_name, already_loaded_textures ) );
  161. }
  162. else if ( strstr( tmp, "map_Ks" ) == tmp ) // specular map
  163. {
  164. sscanf( tmp, "%*s %s", image_file_name );
  165. std::string full_name = std::string( path ).append( image_file_name );
  166. material->set_texture( Material::kSpecularMapSlot, TextureProxy( full_name, already_loaded_textures ) );
  167. }
  168. else if ( strstr( tmp, "map_bump" ) == tmp ) // normal map
  169. {
  170. sscanf( tmp, "%*s %s", image_file_name );
  171. std::string full_name = std::string(path).append(image_file_name);
  172. material->set_texture( Material::kNormalMapSlot, TextureProxy( full_name, already_loaded_textures ) );
  173. }
  174. else if ( strstr( tmp, "map_D" ) == tmp ) // opacity map
  175. {
  176. sscanf( tmp, "%*s %s", image_file_name );
  177. std::string full_name = std::string(path).append(image_file_name);
  178. material->set_texture( Material::kOpacityMapSlot, TextureProxy( full_name, already_loaded_textures, -1, true ) );
  179. }
  180. else if ( strstr( tmp, "map_Pr" ) == tmp ) // roughness map
  181. {
  182. sscanf( tmp, "%*s %s", image_file_name );
  183. std::string full_name = std::string( path ).append( image_file_name );
  184. material->set_texture( Material::kRoughnessMapSlot, TextureProxy( full_name, already_loaded_textures, -1, true ) );
  185. }
  186. else if ( strstr( tmp, "map_Pm" ) == tmp ) // metallicness map
  187. {
  188. sscanf( tmp, "%*s %s", image_file_name );
  189. std::string full_name = std::string( path ).append( image_file_name );
  190. material->set_texture( Material::kMetallicnessMapSlot, TextureProxy( full_name, already_loaded_textures, -1, true ) );
  191. }
  192. else if ( strstr( tmp, "shader" ) == tmp ) // used shader
  193. {
  194. int shader = 0;
  195. sscanf( tmp, "%*s %d", &shader );
  196. material->set_shader( Shader( shader ) );
  197. }
  198. else if ( strstr( tmp, "Ni" ) == tmp || strstr( tmp, "ior" ) == tmp ) // index of refraction
  199. {
  200. sscanf( tmp, "%*s %f", &material->ior );
  201. }
  202. else if ( strstr( tmp, "Pr" ) == tmp ) // roughness
  203. {
  204. sscanf( tmp, "%*s %f", &material->roughness_ );
  205. }
  206. else if ( strstr( tmp, "Pm" ) == tmp ) // metallicness
  207. {
  208. sscanf( tmp, "%*s %f", &material->metallicness );
  209. }
  210. }
  211. }
  212.  
  213. line = strtok( NULL, delim ); // načtení dalšího řádku
  214. }
  215.  
  216. if ( material != NULL )
  217. {
  218. material->set_name( material_name );
  219. materials.push_back( material );
  220. printf( "\r%I64u material(s)\t\t", materials.size() );
  221. }
  222. material = NULL;
  223.  
  224. //memcpy( buffer, buffer_backup, file_size + 1 ); // obnovení bufferu po činnosti strtok
  225. SAFE_DELETE_ARRAY( buffer_backup );
  226. SAFE_DELETE_ARRAY( buffer );
  227.  
  228. printf( "\n" );
  229.  
  230. return 0;
  231. }
  232.  
  233. int LoadOBJ( const char * file_name, std::vector<Surface *> & surfaces, std::vector<Material *> & materials,
  234. const bool flip_yz , const Vector3 default_color )
  235. {
  236. // otevření soouboru
  237. FILE * file = fopen( file_name, "rt" );
  238. if ( file == NULL )
  239. {
  240. printf( "File %s not found.\n", file_name );
  241.  
  242. return -1;
  243. }
  244.  
  245. // cesta k zadanému souboru
  246. char path[128] = { "" };
  247. const char * tmp = strrchr( file_name, '/' );
  248. if ( tmp != NULL )
  249. {
  250. memcpy( path, file_name, sizeof( char ) * ( tmp - file_name + 1 ) );
  251. }
  252.  
  253. // načtení celého souboru do paměti
  254. /*const long long*/size_t file_size = static_cast<size_t>( GetFileSize64( file_name ) );
  255. char * buffer = new char[file_size + 1]; // +1 protože budeme za poslední načtený byte dávat NULL
  256. char * buffer_backup = new char[file_size + 1];
  257.  
  258. printf( "Loading model from '%s' (%0.1f MB)...\n", file_name, file_size / sqr( 1024.0f ) );
  259.  
  260. size_t number_of_items_read = fread( buffer, sizeof( *buffer ), file_size, file );
  261.  
  262. // otestujeme korektnost načtení dat
  263. if ( !feof( file ) && ( number_of_items_read != file_size ) )
  264. {
  265. printf( "Unexpected end of file encountered.\n" );
  266.  
  267. fclose( file );
  268. file = NULL;
  269.  
  270. return -1;
  271. }
  272.  
  273. buffer[number_of_items_read] = 0; // zajistíme korektní ukončení řetězce
  274.  
  275. fclose( file ); // ukončíme práci se souborem
  276. file = NULL;
  277.  
  278. memcpy( buffer_backup, buffer, file_size + 1 ); // záloha bufferu
  279.  
  280. printf( "Done.\n\n");
  281.  
  282. printf( "Parsing material data...\n" );
  283.  
  284. char material_library[128] = { 0 };
  285.  
  286. std::vector<std::string> material_libraries;
  287.  
  288. const char delim[] = "\n";
  289. char * line = strtok( buffer, delim );
  290.  
  291. // --- načítání všech materiálových knihoven, první průchod ---
  292. while ( line != NULL )
  293. {
  294. switch ( line[0] )
  295. {
  296. case 'm': // mtllib
  297. {
  298. sscanf( line, "%*s %s", &material_library );
  299. printf( "Material library: %s\n", material_library );
  300. material_libraries.push_back( std::string( path ).append( std::string( material_library ) ) );
  301. }
  302. break;
  303. }
  304.  
  305. line = strtok( NULL, delim ); // načtení dalšího řádku
  306. }
  307.  
  308. memcpy( buffer, buffer_backup, file_size + 1 ); // obnovení bufferu po činnosti strtok
  309.  
  310. for ( int i = 0; i < static_cast<int>( material_libraries.size() ); ++i )
  311. {
  312. LoadMTL( material_libraries[i].c_str(), path, materials );
  313. }
  314.  
  315. std::vector<Vector3> vertices; // celý jeden soubor
  316. std::vector<Vector3> per_vertex_normals;
  317. std::vector<Coord2f> texture_coords;
  318.  
  319. line = strtok( buffer, delim );
  320. //line = Trim( line );
  321.  
  322. // --- načítání všech souřadnic, druhý průchod ---
  323. while ( line != NULL )
  324. {
  325. switch ( line[0] )
  326. {
  327. case 'v': // seznam vrcholů, normál nebo texturovacích souřadnic aktuální skupiny
  328. {
  329. switch ( line[1] )
  330. {
  331. case ' ': // vertex
  332. {
  333. Vector3 vertex;
  334. if ( flip_yz )
  335. {
  336. //float x, y, z;
  337. sscanf( line, "%*s %f %f %f", &vertex.x, &vertex.z, &vertex.y );
  338. vertex.y *= -1;
  339. }
  340. else
  341. {
  342. sscanf( line, "%*s %f %f %f", &vertex.x, &vertex.y, &vertex.z );
  343. }
  344.  
  345. vertices.push_back( vertex );
  346. }
  347. break;
  348.  
  349. case 'n': // normála vertexu
  350. {
  351. Vector3 normal;
  352. if ( flip_yz )
  353. {
  354. //float x, y, z;
  355. sscanf( line, "%*s %f %f %f", &normal.x, &normal.z, &normal.y );
  356. normal.y *= -1;
  357. }
  358. else
  359. {
  360. sscanf( line, "%*s %f %f %f", &normal.x, &normal.y, &normal.z );
  361. }
  362. normal.Normalize();
  363. per_vertex_normals.push_back( normal );
  364. }
  365. break;
  366.  
  367. case 't': // texturovací souřadnice
  368. {
  369. Coord2f texture_coord;
  370. float z = 0;
  371. sscanf( line, "%*s %f %f %f",
  372. &texture_coord.u, &texture_coord.v, &z );
  373. texture_coords.push_back( texture_coord );
  374. }
  375. break;
  376. }
  377. }
  378. break;
  379. }
  380.  
  381. line = strtok( NULL, delim ); // načtení dalšího řádku
  382. //line = Trim( line );
  383. }
  384.  
  385. memcpy( buffer, buffer_backup, file_size + 1 ); // obnovení bufferu po činnosti strtok
  386.  
  387. printf( "%I64u vertices, %I64u normals and %I64u texture coords.\n",
  388. vertices.size(), per_vertex_normals.size(), texture_coords.size() );
  389.  
  390. /// buffery pro načítání řetězců
  391. char group_name[128];
  392. char material_name[128];
  393. char vertices_indices[4][8 * 3 + 2]; // pomocný řetězec pro načítání indexů až 4 x "v/vt/vn"
  394. char vertex_indices[3][8]; // pomocný řetězec jednotlivých indexů "v", "vt" a "vn"
  395.  
  396. std::vector<Vertex> face_vertices; // pole všech vertexů právě načítané face
  397.  
  398. int no_surfaces = 0; // počet načtených ploch
  399.  
  400. line = strtok( buffer, delim ); // reset
  401. //line = Trim( line );
  402.  
  403. // --- načítání jednotlivých objektů (group), třetí průchod ---
  404. while ( line != NULL )
  405. {
  406. switch ( line[0] )
  407. {
  408. case 'g': // group
  409. {
  410. if ( face_vertices.size() > 0 )
  411. {
  412. surfaces.push_back( BuildSurface( std::string( group_name ), face_vertices ) );
  413. printf( "\r%I64u group(s)\t\t", surfaces.size() );
  414. ++no_surfaces;
  415. face_vertices.clear();
  416.  
  417. for ( int i = 0; i < static_cast<int>( materials.size() ); ++i )
  418. {
  419. if ( materials[i]->name().compare( material_name ) == 0 )
  420. {
  421. Surface * s = *--surfaces.end();
  422. s->set_material( materials[i] );
  423. break;
  424. }
  425. }
  426. }
  427.  
  428. sscanf( line, "%*s %s", &group_name );
  429. //printf( "Group name: %s\n", group_name );
  430. }
  431. break;
  432.  
  433. case 'u': // usemtl
  434. {
  435. sscanf( line, "%*s %s", &material_name );
  436. //printf( "Material name: %s\n", material_name );
  437. }
  438. break;
  439.  
  440. case 'f': // face
  441. {
  442. // ! předpokládáme pouze trojúhelníky !
  443. // ! předpokládáme využití všech tří položek v/vt/vn !
  444. int no_slashes = 0;
  445. for ( int i = 0; i < int( strlen( line ) ); ++i )
  446. {
  447. if ( line[i] == '/' )
  448. {
  449. ++no_slashes;
  450. }
  451. }
  452. switch ( no_slashes )
  453. {
  454. case 2*3: // triangles
  455. sscanf( line, "%*s %s %s %s",
  456. &vertices_indices[0], &vertices_indices[1], &vertices_indices[2] );
  457. break;
  458.  
  459. case 2*4: // quadrilaterals
  460. sscanf( line, "%*s %s %s %s %s",
  461. &vertices_indices[0], &vertices_indices[1], &vertices_indices[2], &vertices_indices[3] );
  462. break;
  463. }
  464.  
  465. // TODO smoothing groups
  466.  
  467. for ( int i = 0; i < 3; ++i )
  468. {
  469. if (strstr(vertices_indices[i], "//"))
  470. {
  471. sscanf(vertices_indices[i], "%[0-9]//%[0-9]",
  472. &vertex_indices[0], &vertex_indices[2]);
  473. vertex_indices[1][0] = 0;
  474. }
  475. else
  476. {
  477. sscanf(vertices_indices[i], "%[0-9]/%[0-9]/%[0-9]",
  478. &vertex_indices[0], &vertex_indices[1], &vertex_indices[2]);
  479. }
  480.  
  481. const int vertex_index = atoi( vertex_indices[0] ) - 1;
  482. const int texture_coord_index = atoi( vertex_indices[1] ) - 1;
  483. const int per_vertex_normal_index = atoi( vertex_indices[2] ) - 1;
  484.  
  485. if (texture_coord_index >= 0)
  486. {
  487. face_vertices.push_back(Vertex(vertices[vertex_index],
  488. per_vertex_normals[per_vertex_normal_index],
  489. default_color, &texture_coords[texture_coord_index]));
  490. }
  491. else
  492. {
  493. face_vertices.push_back(Vertex(vertices[vertex_index],
  494. per_vertex_normals[per_vertex_normal_index],
  495. default_color));
  496. }
  497.  
  498. }
  499.  
  500. if ( no_slashes == 2*4 )
  501. {
  502. const int i[] = { 0, 2, 3 };
  503. for ( int j = 0; j < 3; ++j )
  504. {
  505. sscanf( vertices_indices[i[j]], "%[0-9]/%[0-9]/%[0-9]",
  506. &vertex_indices[0], &vertex_indices[1], &vertex_indices[2] );
  507.  
  508. const int vertex_index = atoi( vertex_indices[0] ) - 1;
  509. const int texture_coord_index = atoi( vertex_indices[1] ) - 1;
  510. const int per_vertex_normal_index = atoi( vertex_indices[2] ) - 1;
  511.  
  512. face_vertices.push_back( Vertex( vertices[vertex_index],
  513. per_vertex_normals[per_vertex_normal_index],
  514. default_color, &texture_coords[texture_coord_index] ) );
  515. }
  516. }
  517. }
  518. break;
  519. }
  520.  
  521. line = strtok( NULL, delim ); // načtení dalšího řádku
  522. //line = Trim( line );
  523. }
  524.  
  525. if ( face_vertices.size() > 0 )
  526. {
  527. surfaces.push_back( BuildSurface( std::string( group_name ), face_vertices ) );
  528. printf( "\r%I64u group(s)\t\t", surfaces.size() );
  529. ++no_surfaces;
  530. face_vertices.clear();
  531.  
  532. for ( int i = 0; i < static_cast<int>( materials.size() ); ++i )
  533. {
  534. if ( materials[i]->name().compare( material_name ) == 0 )
  535. {
  536. Surface * s = *--surfaces.end();
  537. s->set_material( materials[i] );
  538. break;
  539. }
  540. }
  541. }
  542.  
  543. texture_coords.clear();
  544. per_vertex_normals.clear();
  545. vertices.clear();
  546.  
  547. SAFE_DELETE_ARRAY( buffer_backup );
  548. SAFE_DELETE_ARRAY( buffer );
  549.  
  550. printf( "\nDone.\n\n");
  551.  
  552. return no_surfaces;
  553. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement