Example #1
0
void MainWindow::createActions() {
    newObjFileAction_ = new QAction("Load OBJ Model", this);
    newObjFileAction_->setShortcut(QKeySequence::New);
    newObjFileAction_->setIcon(QIcon(":/assets/images/obj.png"));
    newObjFileAction_->setStatusTip("Loads OBJ Model into the Main View");
    connect(newObjFileAction_, SIGNAL(triggered()), this, SLOT(openObjFile()));

    exitAction_ = new QAction("Exit", this);
    exitAction_->setShortcut(QKeySequence::Quit);
    exitAction_->setStatusTip("Exit the application");
    connect(exitAction_, SIGNAL(triggered()), this, SLOT(close()));
}
Example #2
0
void MeshBase::loadDataFromObj( const std::string& filename )
{
  FILE* file = openObjFile(filename);

  int vertices_index            = 0;
  int normals_index             = 0;
  int colors_index              = 0;
  int texture_coordinates_index = 0;
  int triangles_index           = 0;

  float*         vertices            = m_vertex_data;
  float*         normals             = m_normal_data;
  unsigned char* colors              = m_color_data;
  float*         texture_coordinates = m_texture_coordinate_data;

  // 0 as a stride signals compact data
  int v_stride = m_vertex_stride == 0 ? 3 : m_vertex_stride;
  int n_stride = m_normal_stride == 0 ? 3 : m_normal_stride;
  int c_stride = m_color_stride  == 0 ? 3 : m_color_stride;
  int t_stride = m_texture_coordinate_stride == 0
                                    ? 2 : m_texture_coordinate_stride;

  bool        is_loading_curr_group = false;
  std::string curr_group_name       = default_group_name;
  std::string curr_group_base_name  = default_group_name;
  MeshGroup*  curr_group_data       = 0;

  MeshGroupMap::const_iterator default_group_iter
    = m_mesh_groups.find(default_group_name);
  if( default_group_iter == m_mesh_groups.end() ) {
    is_loading_curr_group = false;
    curr_group_data = 0;
  }
  else {
    is_loading_curr_group = true;
    curr_group_data       = &m_mesh_groups[default_group_name];
  }

  std::string curr_material_name = default_material_name;
  int curr_material_number = 0;

  // Init. the current group triangle index to 0 for each group, so the current
  // triangle index of each can be tracked.
  std::map<std::string, int> groups_triangles_index;
  forEachGroup( GroupCurrentIndexInitFunctor(groups_triangles_index) );

  // For improved speed, so that we don't need a lookup in groups_triangles_index
  // for every single face--only when the group changes.
  int* curr_group_triangles_index = &groups_triangles_index[default_group_name];

  bool uses_vertices = ( m_num_vertices > 0 && vertices != 0 );
  bool uses_normals  = ( m_num_normals  > 0 && normals  != 0 );
  bool uses_colors   = ( m_num_colors   > 0 && colors   != 0 );
  bool uses_texture_coordinates
                     = ( m_num_texture_coordinates > 0
                         && texture_coordinates != 0 );

  int   v[3], n[3], t[3];
  float f[3];
  char  buf[2048];

  while(fscanf(file, "%s", buf) != EOF) {
    switch(buf[0]) {
      case '#':       /* comment */
        /* eat up rest of line */
        fgets(buf, sizeof(buf), file);
        break;

      case 'v':       /* v, vn, vt */
        switch(buf[1]) {
          case '\0':      /* vertex */
            if( !uses_colors ) {
              fscanf( file, "%f %f %f", &f[0], &f[1], &f[2] );
              if( uses_vertices ) {
                for( int i = 0; i < 3; ++i ) {
                  vertices[v_stride*vertices_index + i] = f[i];
                }
                ++vertices_index;
              }
            }
            else {
              int c[3];
              fscanf( file, "%f %f %f %d %d %d",
                      &f[0], &f[1], &f[2],
                      &c[0], &c[1], &c[2] );
              if( uses_vertices ) {
                for( int i = 0; i < 3; ++i ) {
                  vertices[v_stride*vertices_index + i] = f[i];
                }
                ++vertices_index;
              }
              if( uses_colors ) {
                for( int i = 0; i < 3; ++i ) {
                  colors[c_stride*colors_index + i] = static_cast<unsigned char>( c[i] );
                  ++colors_index;
                }
              }
            }
            break;

          case 'n':       /* normal */
            fscanf( file, "%f %f %f",
                    &f[0], &f[1], &f[2] );
            if( uses_normals ) {
              for( int i = 0; i < 3; ++i ) {
                normals[n_stride*normals_index + i] = f[i];
              }
              ++normals_index;
            }
            break;

          case 't':       /* texcoord */
            fscanf( file, "%f %f",
                    &f[0], &f[1] );
            if( uses_texture_coordinates ) {
              for( int i = 0; i < 2; ++i ) {
                texture_coordinates[t_stride*texture_coordinates_index + i] = f[i];
              }
              ++texture_coordinates_index;
            }
            break;
        }
        break;

      case 'u': /* "usemtl <name>" */
        fgets(buf, sizeof(buf), file);
        sscanf(buf, "%s %s", buf, buf);
        curr_material_name   = buf;
        curr_material_number = m_material_numbers_by_name.at(curr_material_name);

        curr_group_name = groupMaterialName( curr_group_base_name, curr_material_name );
        // Set up a valid current group only if the new group hasn't been excluded from loading
        if( m_mesh_groups.find(curr_group_name) != m_mesh_groups.end() ) {
          is_loading_curr_group = true;
          curr_group_data = &m_mesh_groups[curr_group_name];
          curr_group_triangles_index = &groups_triangles_index[curr_group_name];

          curr_group_data->material_number = curr_material_number;
        }
        else {
          is_loading_curr_group = false;
          curr_group_data = 0;
          curr_group_triangles_index = 0;
        }
        break;

      case 'o': /* "o <object name>" */
        /* eat up rest of line */
        fgets(buf, sizeof(buf), file);
        break;

      case 'g': /* "g <group name>" */
        /* eat up rest of line */
        fgets(buf, sizeof(buf), file);
        sscanf(buf, "%s", buf);

        curr_group_base_name = buf;
        curr_group_name = groupMaterialName( curr_group_base_name,
                                             curr_material_name );
        // Set up a valid current group only if the new group hasn't been excluded from loading
        if( m_mesh_groups.find( curr_group_name ) != m_mesh_groups.end() ) {
          is_loading_curr_group = true;
          curr_group_data = &m_mesh_groups[curr_group_name];
          curr_group_triangles_index = &groups_triangles_index[curr_group_name];
          curr_group_data->material_number = curr_material_number;
        }
        else {
          is_loading_curr_group = false;
          curr_group_data = 0;
          curr_group_triangles_index = 0;
        }
        break;

      case 'm': /* "mtllib <material library name>" */
        fgets(buf, sizeof(buf), file);
        sscanf(buf, "%s %s", buf, buf);
        {
          std::string dir = directoryOfFilePath( filename );
          std::stringstream ss_material_library_name;
          ss_material_library_name << dir << m_material_library_name;
          loadMaterials( ss_material_library_name.str() );
        }
        break;

      case 'f':       /* face */

        #define NEWEST_INDEX(indices, vertex_offset) \
                curr_group_data->indices[3*(*curr_group_triangles_index) + (vertex_offset)]
        #define PREVIOUS_INDEX(indices, vertex_offset) \
                curr_group_data->indices[3*(*curr_group_triangles_index - 1) + (vertex_offset)]

        for (int i = 0; i < 3; ++i) {
          v[i] = n[i] = t[i] = 0;
        }

        fscanf(file, "%s", buf);
        /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
        if( strstr(buf, "//" )) {
          /* v//n */
          sscanf(buf,  "%d//%d", &v[0], &n[0]);
          fscanf(file, "%d//%d", &v[1], &n[1]);
          fscanf(file, "%d//%d", &v[2], &n[2]);
          // We still need to advance through the file, but don't store
          // what is parsed for groups we've been told not to load
          if( is_loading_curr_group ) {
            if( uses_vertices ) {
              for (int i = 0; i < 3; ++i) {
                NEWEST_INDEX(vertex_indices, i)
                  = (v[i] >= 0) ? v[i] - 1 : (vertices_index + v[i]);
              }
            }
            if( uses_normals ) {
              for (int i = 0; i < 3; ++i) {
                NEWEST_INDEX(normal_indices, i) = n[i] - 1;
              }
            }
            if( uses_texture_coordinates ) {
              for (int i = 0; i < 3; ++i) {
                NEWEST_INDEX(texture_coordinate_indices, i)
                  = MESH_ATTRIBUTE_NOT_PROVIDED;
              }
            }
            ++(*curr_group_triangles_index);
            ++triangles_index;
          }
          // Load face as a triangle fan when there are more than three indices
          while(fscanf(file, "%d//%d", &v[0], &n[0]) > 0) {
            if( is_loading_curr_group ) {
              if( uses_vertices ) {
                NEWEST_INDEX(vertex_indices, 0) = PREVIOUS_INDEX(vertex_indices, 0);
                NEWEST_INDEX(vertex_indices, 1) = PREVIOUS_INDEX(vertex_indices, 2);
                NEWEST_INDEX(vertex_indices, 2) = (v[0] >= 0)
                                                ? v[0] - 1: (vertices_index + v[0]);
              }
              if( uses_normals ) {
                NEWEST_INDEX(normal_indices, 0) = PREVIOUS_INDEX(normal_indices, 0);
                NEWEST_INDEX(normal_indices, 1) = PREVIOUS_INDEX(normal_indices, 2);
                NEWEST_INDEX(normal_indices, 2) = n[0] - 1;
              }
              if( uses_texture_coordinates ) {
                for (int i = 0; i < 3; ++i) {
                  NEWEST_INDEX(texture_coordinate_indices, i)
                    = MESH_ATTRIBUTE_NOT_PROVIDED;
                }
              }
              ++(*curr_group_triangles_index);
              ++triangles_index;
            }
          }
        }
        else if( sscanf(buf, "%d/%d/%d", &v[0], &t[0], &n[0] ) == 3) {
          /* v/t/n */
          fscanf(file, "%d/%d/%d", &v[1], &t[1], &n[1]);
          fscanf(file, "%d/%d/%d", &v[2], &t[2], &n[2]);
          if( is_loading_curr_group ) {
            if( uses_vertices ) {
              for( int i = 0; i < 3; ++i ) {
                NEWEST_INDEX(vertex_indices, i)
                  = (v[i] >= 0) ? v[i] - 1 : (vertices_index + v[i]);
              }
            }
            if( uses_normals ) {
              for( int i = 0; i < 3; ++i ) {
                NEWEST_INDEX(normal_indices, i) = n[i] - 1;
              }
            }
            if( uses_texture_coordinates ) {
              for( int i = 0; i < 3; ++i ) {
                NEWEST_INDEX(texture_coordinate_indices, i) = t[i] - 1;
              }
            }
            ++(*curr_group_triangles_index);
            ++triangles_index;
          }
          // Load face as a triangle fan when there are more than three indices
          while(fscanf(file, "%d/%d/%d", &v[0], &t[0], &n[0]) > 0) {
            if( is_loading_curr_group ) {
              if( uses_vertices ) {
                NEWEST_INDEX(vertex_indices, 0) = PREVIOUS_INDEX(vertex_indices, 0);
                NEWEST_INDEX(vertex_indices, 1) = PREVIOUS_INDEX(vertex_indices, 2);
                NEWEST_INDEX(vertex_indices, 2) = (v[0] >= 0)
                                                ? v[0] - 1 : (vertices_index + v[0]);
              }
              if( uses_normals ) {
                NEWEST_INDEX(normal_indices, 0) = PREVIOUS_INDEX(normal_indices, 0);
                NEWEST_INDEX(normal_indices, 1) = PREVIOUS_INDEX(normal_indices, 2);
                NEWEST_INDEX(normal_indices, 2) = n[0] - 1;
              }
              if( uses_texture_coordinates ) {
                NEWEST_INDEX(texture_coordinate_indices, 0)
                  = PREVIOUS_INDEX(texture_coordinate_indices, 0);
                NEWEST_INDEX(texture_coordinate_indices, 1)
                  = PREVIOUS_INDEX(texture_coordinate_indices, 2);
                NEWEST_INDEX(texture_coordinate_indices, 2) = t[0] - 1;
              }
              ++(*curr_group_triangles_index);
              ++triangles_index;
            }
          }
        }
        else if( sscanf(buf, "%d/%d", &v[0], &t[0] ) == 2) {
          /* v/t */
          fscanf(file, "%d/%d", &v[1], &t[1]);
          fscanf(file, "%d/%d", &v[2], &t[2]);
          if( is_loading_curr_group ) {
            if( uses_vertices ) {
              for( int i = 0; i < 3; ++i ) {
                NEWEST_INDEX(vertex_indices, i)
                  = (v[i] >= 0) ? v[i] - 1 : (vertices_index + v[i]);
              }
            }
            if( uses_normals ) {
              for( int i = 0; i < 3; ++i ) {
                NEWEST_INDEX(normal_indices, i) = MESH_ATTRIBUTE_NOT_PROVIDED;
              }
            }
            if( uses_texture_coordinates ) {
              for( int i = 0; i < 3; ++i ) {
                NEWEST_INDEX(texture_coordinate_indices, i) = t[i] - 1;
              }
            }
            ++(*curr_group_triangles_index);
            ++triangles_index;
          }
          // Load face as triangle fan when more than three indices
          while(fscanf(file, "%d/%d", &v[0], &t[0]) > 0) {
            if( is_loading_curr_group ) {
              if( uses_vertices ) {
                NEWEST_INDEX(vertex_indices, 0) = PREVIOUS_INDEX(vertex_indices, 0);
                NEWEST_INDEX(vertex_indices, 1) = PREVIOUS_INDEX(vertex_indices, 2);
                NEWEST_INDEX(vertex_indices, 2) = (v[0] >= 0)
                                                ? v[0] - 1 : (vertices_index + v[0]);
              }
              if( uses_normals ) {
                for( int i = 0; i < 3; ++i ) {
                  NEWEST_INDEX(normal_indices, i) = MESH_ATTRIBUTE_NOT_PROVIDED;
                }
              }
              if( uses_texture_coordinates ) {
                NEWEST_INDEX(texture_coordinate_indices, 0)
                  = PREVIOUS_INDEX(texture_coordinate_indices, 0);
                NEWEST_INDEX(texture_coordinate_indices, 1)
                  = PREVIOUS_INDEX(texture_coordinate_indices, 2);
                NEWEST_INDEX(texture_coordinate_indices, 2)
                  = t[0] - 1;
              }
              ++(*curr_group_triangles_index);
              ++triangles_index;
            }
          }
        }
        else {
          /* v */
          sscanf(buf, "%d", &v[0]);
          fscanf(file, "%d", &v[1]);
          fscanf(file, "%d", &v[2]);
          if( is_loading_curr_group ) {
            if( uses_vertices ) {
              for( int i = 0; i < 3; ++i ) {
                NEWEST_INDEX(vertex_indices, i)
                  = (v[i] >= 0) ? v[i] - 1 : (vertices_index + v[i]);
              }
            }
            if( uses_normals ) {
              for( int i = 0; i < 3; ++i ) {
                NEWEST_INDEX(normal_indices, i) = MESH_ATTRIBUTE_NOT_PROVIDED;
              }
            }
            if( uses_texture_coordinates ) {
              for( int i = 0; i < 3; ++i ) {
                NEWEST_INDEX(texture_coordinate_indices, i)
                  = MESH_ATTRIBUTE_NOT_PROVIDED;
              }
            }
            ++(*curr_group_triangles_index);
            ++triangles_index;
          }
          // Load face with more than three indices as a triangle fan
          while(fscanf(file, "%d", &v[0]) > 0) {
            if( is_loading_curr_group ) {
              if( uses_vertices ) {
                NEWEST_INDEX(vertex_indices, 0) = PREVIOUS_INDEX(vertex_indices, 0);
                NEWEST_INDEX(vertex_indices, 1) = PREVIOUS_INDEX(vertex_indices, 2);
                NEWEST_INDEX(vertex_indices, 2) = (v[0] >= 0)
                                                ? v[0] - 1 : (vertices_index + v[0]);
              }
              if( uses_normals ) {
                for( int i = 0; i < 3; ++i ) {
                  NEWEST_INDEX(normal_indices, i) = MESH_ATTRIBUTE_NOT_PROVIDED;
                }
              }
              if( uses_texture_coordinates ) {
                for( int i = 0; i < 3; ++i ) {
                  NEWEST_INDEX(texture_coordinate_indices, i)
                    = MESH_ATTRIBUTE_NOT_PROVIDED;
                }
              }
              ++(*curr_group_triangles_index);
              triangles_index++;
            }
          }
        }

        #undef PREVIOUS_INDEX
        #undef NEWEST_INDEX

        break;

      default:
        /* eat up rest of line */
        fgets(buf, sizeof(buf), file);
        break;
    }
  }

#if 0
  /* announce the memory requirements */
  printf(" Memory: %d bytes\n",
      vertices_index  * 3*sizeof(float) +
      numnormals   * 3*sizeof(float) * (numnormals ? 1 : 0) +
      numtexcoords * 3*sizeof(float) * (numtexcoords ? 1 : 0) +
      numtriangles * sizeof(GLMtriangle));
#endif

  // It happens that in a .obj, all the color indices are identical to the
  // vertex indices, so we simply copy them
  if( uses_colors ) {
    forEachGroup( VertexIndexToColorIndexCopyFunctor() );
  }
}
Example #3
0
// TODO: It sure would be nice to clean up or refactor the old GLM-style 
// parsing paragraphs into helper functions, or even a class in its own right.
void MeshBase::loadInfoFromObj(const std::string& filename)
{
  FILE* file = openObjFile(filename);

  m_num_vertices            = 0;
  m_num_normals             = 0;
  m_num_colors              = 0;
  m_num_texture_coordinates = 0;
  m_num_triangles           = 0;

  // Make a default group
  std::string curr_group_name      = default_group_name;
  MeshGroup*  curr_group           = &getOrAddGroup( curr_group_name );
  std::string curr_group_base_name = curr_group_name;

  int material_count = 0;
  std::string curr_material_name = default_material_name;
  m_material_numbers_by_name[curr_material_name] = material_count;
  ++material_count;

  int       v, n, t;
  char      buf[2048];

  while(fscanf(file, "%s", buf) != EOF) {
    switch(buf[0]) {
      case '#':     /* comment */
        /* eat up rest of line */
        fgets(buf, sizeof(buf), file);
        break;

      case 'v':     /* v, vn, vt */
        switch(buf[1]) {
          case '\0':  { /* vertex */
                        /* eat up rest of line */
                        fgets(buf, sizeof(buf), file);

                        float vx,vy,vz;
                        int   val = -1;
                        sscanf(buf,"%f %f %f %d",&vx, &vy, &vz, &val);
                        if( val >= 0 ) {
                          ++m_num_colors;
                        }

                        ++m_num_vertices;
                        break;
                      }
          case 'n':   /* normal */
                      /* eat up rest of line */
                      fgets(buf, sizeof(buf), file);
                      ++m_num_normals;
                      break;
          case 't':   /* texcoord */
                      /* eat up rest of line */
                      fgets(buf, sizeof(buf), file);
                      ++m_num_texture_coordinates;
                      break;
          default:
                      printf("meshLoaderLoadInfoFromObj(): Unknown token \"%s\".\n", buf);
                      /* Could error out here, but we'll just skip it for now.*/
                      break;
        }
        break;

      case 'm': /* "mtllib <name>" */
        fgets(buf, sizeof(buf), file);
        sscanf(buf, "%s %s", buf, buf);
        m_material_library_name = buf;
        break;

      case 'u': /* "usemtl <name>" */
        /* We need to create groups with their own materials */
        fgets(buf, sizeof(buf), file);
        sscanf(buf, "%s %s", buf, buf);
        curr_material_name = buf;

        if( m_material_numbers_by_name.find(curr_material_name)
            == m_material_numbers_by_name.end() )
        {
          m_material_numbers_by_name[curr_material_name] = material_count;
          ++material_count;
        }

        curr_group = &getOrAddGroup( groupMaterialName(curr_group_base_name,
                                                       curr_material_name)   );
        break;

      case 'o': /* "o <object name>" */
        /* eat up rest of line */
        fgets(buf, sizeof(buf), file);
        break;

      case 'g': /* "g <group name>" */
        fgets(buf, sizeof(buf), file);
        sscanf(buf, "%s", buf);
        curr_group_base_name = buf;
        curr_group = &getOrAddGroup( groupMaterialName(curr_group_base_name,
                                                       curr_material_name)   );
        break;

      case 'f': /* face */
        v = n = t = 0;
        fscanf(file, "%s", buf);
        /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
        if( strstr(buf, "//" )) {
          /* v//n */
          sscanf(buf, "%d//%d", &v, &n);
          fscanf(file, "%d//%d", &v, &n);
          fscanf(file, "%d//%d", &v, &n);
          ++m_num_triangles;
          ++curr_group->num_triangles;
          while(fscanf(file, "%d//%d", &v, &n) > 0) {
            ++m_num_triangles;
            ++curr_group->num_triangles;
          }
        }
        else if( sscanf(buf, "%d/%d/%d", &v, &t, &n ) == 3) {
          /* v/t/n */
          fscanf(file, "%d/%d/%d", &v, &t, &n);
          fscanf(file, "%d/%d/%d", &v, &t, &n);
          ++m_num_triangles;
          ++curr_group->num_triangles;
          while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) {
            ++m_num_triangles;
            ++curr_group->num_triangles;
          }
        }
        else if( sscanf(buf, "%d/%d", &v, &t ) == 2) {
          /* v/t */
          fscanf(file, "%d/%d", &v, &t);
          fscanf(file, "%d/%d", &v, &t);
          ++m_num_triangles;
          ++curr_group->num_triangles;
          while(fscanf(file, "%d/%d", &v, &t) > 0) {
            ++m_num_triangles;
            ++curr_group->num_triangles;
          }
        }
        else {
          /* v */
          fscanf(file, "%d", &v);
          fscanf(file, "%d", &v);
          ++m_num_triangles;
          ++curr_group->num_triangles;
          while(fscanf(file, "%d", &v) > 0) {
            ++m_num_triangles;
            ++curr_group->num_triangles;
          }
        }
        break;

      default:
        /* eat up rest of line */
        fgets(buf, sizeof(buf), file);
        break;
    }
  }
  
  // Prune out groups with 0 triangles;
  forEachGroup( PruneEmptyGroupsFunctor(m_mesh_groups) );
}