Example #1
0
    void parse_ply(const std::string& filename, PLYParser* parser) {
        p_ply ply = ply_open(filename.c_str(), NULL, 0, NULL);
        assert_success(ply != NULL);
        assert_success(ply_read_header(ply));

        const char* elem_name;
        const char* prop_name;
        long num_elements;
        p_ply_element element = ply_get_next_element(ply, NULL);
        while (element != NULL) {
            assert_success(ply_get_element_info(element, &elem_name, &num_elements));

            p_ply_property property = ply_get_next_property(element, NULL);
            while (property != NULL) {
                assert_success(ply_get_property_info(property, &prop_name, NULL, NULL, NULL));

                ply_set_read_cb(ply, elem_name, prop_name, ply_parser_call_back, parser, 0);
                parser->add_property(elem_name, prop_name, num_elements);

                property = ply_get_next_property(element, property);
            }
            element = ply_get_next_element(ply, element);
        }
        assert_success(ply_read(ply));
        ply_close(ply);
    }
Example #2
0
int loadPlyFile() {
	p_ply ply = ply_open(filename, NULL, 0, NULL);

	if (!ply) return -1;
	if (!ply_read_header(ply)) return -1;

	vertex_count = ply_set_read_cb(ply, "vertex", "x", vertex_cb, NULL, 0);
	ply_set_read_cb(ply, "vertex", "y", vertex_cb, NULL, 1);
	ply_set_read_cb(ply, "vertex", "z", vertex_cb, NULL, 2);

	ply_set_read_cb(ply, "vertex", "nx", NULL, NULL, 0);
	ply_set_read_cb(ply, "vertex", "ny", NULL, NULL, 0);
	ply_set_read_cb(ply, "vertex", "nz", NULL, NULL, 0);

	face_count = ply_set_read_cb(ply, "face", "vertex_indices", face_cb, NULL, 0);

	vertices = (double **) malloc(vertex_count * sizeof(double *));
	faces    = (int **) malloc(face_count * sizeof(int *));

	if (!ply_read(ply)) return -1;

	ply_close(ply);

	return 1;
}
Example #3
0
int main(int argc, char **argv)
{
    const char *value;
    p_ply iply, oply;
    iply = ply_open("input.ply", NULL);
    if (!iply) return 1;
    if (!ply_read_header(iply)) return 1;
    oply = ply_create("output.ply", PLY_LITTLE_ENDIAN, NULL);
    if (!oply) return 1;
    if (!setup_callbacks(iply, oply)) return 1;
    /* pass comments and obj_infos from input to output */
    value = NULL;
    while ((value = ply_get_next_comment(iply, value)))
        if (!ply_add_comment(oply, value)) return 1;
    value = NULL;
    while ((value = ply_get_next_obj_info(iply, value)))
        if (!ply_add_obj_info(oply, value)) return 1;;
    /* write output header */
    if (!ply_write_header(oply)) return 1;
    /* read input file generating callbacks that pass data to output file */
    if (!ply_read(iply)) return 1;
    /* close up, we are done */
    if (!ply_close(iply)) return 1;
    if (!ply_close(oply)) return 1;
    return 0;
}
Example #4
0
int Model::init(char filename[]){
    p_ply ply = ply_open(filename, NULL, 0, NULL);
    if (!ply) return 1;
    if (!ply_read_header(ply)) return 1;
    nvertices = ply_set_read_cb(ply, "vertex", "x", vertex_cb, NULL, 0);
    ply_set_read_cb(ply, "vertex", "y", vertex_cb, NULL, 0);
    ply_set_read_cb(ply, "vertex", "z", vertex_cb, NULL, 1);
    ntriangles = ply_set_read_cb(ply, "face", "vertex_indices", face_cb, NULL, 0);
    count_t = 0;
    count_v = 0;
    if(vertices != NULL){
		delete [] vertices;
		}
    if(triangles != NULL){
		delete [] triangles;
		}
	if(nml != NULL){
		delete [] nml;
		}
	vertices = new vertex[nvertices];
	triangles = new triangle[ntriangles];
	nml = new normal[ntriangles];
    if (!ply_read(ply)) return 1;
    ply_close(ply);
    return 0;
	}
Example #5
0
void MeshBase::loadDataFromPly( const std::string& filename )
{
  p_ply ply = ply_open( filename.c_str(), 0);
  if( !ply ) {
    throw MeshException( "Error opening ply file during second pass (" + filename + ")" );
  }

  if( !ply_read_header( ply ) ) {
    throw MeshException( "Error parsing ply header during second pass ("
                         + filename + ")" );
  }

  MeshGroup& group = getFirstGroup();

  PlyData data( m_vertex_data, m_normal_data, group.vertex_indices, group.normal_indices );

  ply_set_read_cb( ply, "vertex", "x", plyVertexLoadDataCB, &data, 0);
  ply_set_read_cb( ply, "vertex", "y", plyVertexLoadDataCB, &data, 1);
  ply_set_read_cb( ply, "vertex", "z", plyVertexLoadDataCB, &data, 2);

  ply_set_read_cb( ply, "vertex", "nx", plyVertexLoadDataCB, &data, 3);
  ply_set_read_cb( ply, "vertex", "ny", plyVertexLoadDataCB, &data, 4);
  ply_set_read_cb( ply, "vertex", "nz", plyVertexLoadDataCB, &data, 5);

  ply_set_read_cb( ply, "face", "vertex_indices", plyFaceLoadDataCB, &data, 0);

  if( !ply_read( ply ) ) {
    throw MeshException( "Error parsing ply file (" + filename + ")" );
  }
  ply_close(ply);
}
Example #6
0
/******************************************************************************
Open a polygon file for reading.

Entry:
  filename - name of file to read from

Exit:
  nelems     - number of elements in object
  elem_names - list of element names
  file_type  - file type, either ascii or binary
  version    - version number of PLY file
  returns a file identifier, used to refer to this file, or NULL if error
******************************************************************************/
PlyFile *ply_open_for_reading(char *filename, int *nelems, char ***elem_names,
                              int *file_type, float *version)
{
    assert(filename != NULL);

    FILE *fp;
    PlyFile *plyfile;

    // open the file for reading
    fp = fopen (filename, "r");
    if (fp == NULL) {
        log_error("Could not open file %s\n", filename);
        exit(1);
    }

    // create the PlyFile data structure
    plyfile = ply_read(fp, nelems, elem_names);
    assert(plyfile != NULL);

    // determine the file type and version
    *file_type = plyfile->file_type;

    *version = plyfile->version;

    // return a pointer to the file's information */
    return (plyfile);
}
Example #7
0
/* given a format mode, an input file name and an output file name,
 * convert input file to output in given format mode */
int main(int argc, char **argv) {
    const char *value = NULL;
    e_ply_storage_mode storage_mode = PLY_LITTLE_ENDIAN;
    const char *iname = NULL, *oname = NULL;
    p_ply iply = NULL, oply = NULL;
    /* parse command line arguments */
    parse_arguments(argc, argv, &storage_mode, &iname, &oname);
    /* open input file and make sure we parsed its header */
    iply = ply_open(iname, NULL, 0, NULL);
    if (!iply) error("Unable to open file '%s'", iname);
    if (!ply_read_header(iply)) error("Failed reading '%s' header", iname);
    /* create output file */
    oply = ply_create(oname, storage_mode, NULL, 0, NULL);
    if (!oply) error("Unable to create file '%s'", oname);
    /* create elements and properties in output file and 
     * setup callbacks for them in input file */
    setup_callbacks(iply, oply); 
    /* pass comments and obj_infos from input to output */
    value = NULL;
    while ((value = ply_get_next_comment(iply, value)))
        if (!ply_add_comment(oply, value))
            error("Failed adding comments");
    value = NULL;
    while ((value = ply_get_next_obj_info(iply, value)))
        if (!ply_add_obj_info(oply, value))
            error("Failed adding comments");
    /* write output header */
    if (!ply_write_header(oply)) error("Failed writing '%s' header", oname);
    /* read input file generating callbacks that pass data to output file */
    if (!ply_read(iply)) error("Conversion failed");
    /* close up, we are done */
    if (!ply_close(iply)) error("Error closing file '%s'", iname);
    if (!ply_close(oply)) error("Error closing file '%s'", oname);
    return 0;
}
	bool load(const std::string& filename) {
		p_ply ply = ply_open(filename.c_str(), nil, 0, nil) ;

		if(ply == nil) {
			Logger::err("PlyMeshLoad") << filename << ": could not open" << std::endl ;
			return false ;
		}

		if(!ply_read_header(ply)) {
			Logger::err("PlyMeshLoad") << filename << ": invalid PLY file" << std::endl ;
			ply_close(ply) ;
			return false ;
		}

		current_vertex_ = 0 ;
		current_color_  = 0 ;
		check_for_colors(ply) ;

		long nvertices = ply_set_read_cb(ply, "vertex", "x", PlyMeshLoad::vertex_cb, this, 0) ;
		ply_set_read_cb(ply, "vertex", "y", PlyMeshLoad::vertex_cb, this, 1) ;
		ply_set_read_cb(ply, "vertex", "z", PlyMeshLoad::vertex_cb, this, 2) ;

		long nfaces = ply_set_read_cb(ply, "face", "vertex_indices", PlyMeshLoad::face_cb, this, 0);
		if (nfaces == 0) {
			Logger::err("PlyMeshLoad") 
				<< "0 facet, maybe a point cloud file" << std::endl ;
			ply_close(ply) ;
			return false ;
		}

		ply_set_read_cb(ply, "tristrips", "vertex_indices", PlyMeshLoad::tristrip_cb, this, 0);

		builder_.begin_surface() ;
		builder_.create_vertices(nvertices, has_colors_) ;

		if(!ply_read(ply)) {
			Logger::err("PlyMeshLoad") 
				<< filename << ": problem occurred while parsing PLY file" << std::endl ;
			ply_close(ply) ;
			builder_.end_surface() ;
			return false ;
		}

		ply_close(ply) ;
		builder_.end_surface() ;

		if (nfaces == 0)
			return false;
		else
			return true ;
	}
Example #9
0
static bool
ply_boot_connection_read_request (ply_boot_connection_t  *connection,
                                  char                  **command,
                                  char                  **argument)
{
  uint8_t header[2];

  assert (connection != NULL);
  assert (connection->fd >= 0);

  if (!ply_read (connection->fd, header, sizeof (header)))
    return false;

  *command = calloc (2, sizeof (char));
  *command[0] = header[0];

  *argument = NULL;
  if (header[1] == '\002')
    {
      uint8_t argument_size;

      if (!ply_read (connection->fd, &argument_size, sizeof (uint8_t)))
        {
          free (*command);
          return false;
        }

      *argument = calloc (argument_size, sizeof (char));

      if (!ply_read (connection->fd, *argument, argument_size))
        {
          free (*argument);
          free (*command);
          return false;
        }
    }
  return true;
}
Example #10
0
void
reader_t::operator()(vertexes_t& vertexes, faces_t& faces) const
{
	const long nvertexes = ply_set_read_cb(_ply.get(), "vertex", "x", vertex_cb, &vertexes, 0);
	ply_set_read_cb(_ply.get(), "vertex", "y", vertex_cb, &vertexes, 1);
	ply_set_read_cb(_ply.get(), "vertex", "z", vertex_cb, &vertexes, 2);
	const long ntriangles = ply_set_read_cb(_ply.get(), "face", "vertex_indices", face_cb, &faces, 0);

	vertexes.resize(nvertexes);
	faces.resize(ntriangles);

	if (!ply_read(_ply.get()))
		throw std::runtime_error("Can't read.");
}
Example #11
0
int main(void) {
    long nvertices, ntriangles;
    p_ply ply = ply_open("input.ply", NULL);
    if (!ply) return 1;
    if (!ply_read_header(ply)) return 1;
    nvertices = ply_set_read_cb(ply, "vertex", "x", vertex_cb, NULL, 0);
    ply_set_read_cb(ply, "vertex", "y", vertex_cb, NULL, 0);
    ply_set_read_cb(ply, "vertex", "z", vertex_cb, NULL, 1);
    ntriangles = ply_set_read_cb(ply, "face", "vertex_indices", face_cb, NULL, 0);
    printf("%ld\n%ld\n", nvertices, ntriangles);
    if (!ply_read(ply)) return 1;
    ply_close(ply);
    return 0;
}
Example #12
0
bool PlyBuffer::LoadFromPlyFile(std::wstring fileName, PlyBuffer& vbOut, std::wstring error)
{
	long nvertices, ntriangles;
	// Open the file
	p_ply ply = ply_open(Helper::WStringtoString(fileName).c_str(), NULL, 0, NULL);

	// Check that file is okay
    if (!ply) 
	{
		error = L"Failed at loading file " + fileName;
		return false;
	}
    if (!ply_read_header(ply)) 
		return false;

	// Load info
    nvertices = ply_set_read_cb(ply, "vertex", "x", vertexX, NULL, 0);
    ply_set_read_cb(ply, "vertex", "y", vertexY, NULL, 0);
    ply_set_read_cb(ply, "vertex", "z", vertexZ, NULL, 0);
	ply_set_read_cb(ply, "vertex", "nx", vertexNX, NULL, 0);
	ply_set_read_cb(ply, "vertex", "ny", vertexNY, NULL, 0);
	ply_set_read_cb(ply, "vertex", "nz", vertexNZ, NULL, 0);
	ply_set_read_cb(ply, "vertex", "u", vertexU, NULL, 0);
	ply_set_read_cb(ply, "vertex", "v", vertexV, NULL, 1);

    ntriangles = ply_set_read_cb(ply, "face", "vertex_indices", face_cb, NULL, 0);

	// Set space for vertices and indices for speed
	buffer.vertices.reserve(nvertices);
	buffer.indices.reserve(ntriangles);

	// Read file
    if (!ply_read(ply))
		return false;

	// Close file
    ply_close(ply);

	//Copy it to the output
	vbOut = buffer;
	
	// Empty the vertex so that don't take up space
	buffer.vertices = std::vector<PlyBuffer::Vertex>();
	buffer.indices = std::vector<WORD>();

	return true;
}
Example #13
0
int MyGlWindow::loadply()
{

    p_ply ply = ply_open("roof.ply", NULL, 0, NULL);
    if (!ply) return 1;
    if (!ply_read_header(ply)) return 1;

    int nvertices = ply_set_read_cb(ply, "vertex", "x", vertex_cb, NULL, 0);
    ply_set_read_cb(ply, "vertex", "y", vertex_cb, NULL, 0);
    ply_set_read_cb(ply, "vertex", "z", vertex_cb, NULL, 1);
    int ntriangles = ply_set_read_cb(ply, "face", "vertex_indices", face_cb, NULL, 0);
    printf("%ld\n%ld\n", nvertices, ntriangles);
    if (!ply_read(ply)) return 1;
    ply_close(ply);

    std::cout << m_points.size() << std::endl;
}
void PlyLoader::load( const optix::Matrix4x4& transform )
{
  p_ply ply = ply_open( _filename.c_str(), 0);
  if( !ply ) {
    throw optix::Exception( "Error opening ply file (" + _filename + ")" );
  }

  if( !ply_read_header( ply ) ) {
    throw optix::Exception( "Error parsing ply header (" + _filename + ")" );
  }

  ModelData data;
  int nverts = ply_set_read_cb( ply, "vertex", "x", vertexCB, &data, 0);
  ply_set_read_cb( ply, "vertex", "y", vertexCB, &data, 1);
  ply_set_read_cb( ply, "vertex", "z", vertexCB, &data, 2);

  int ntris = ply_set_read_cb(ply, "face", "vertex_indices", faceCB, &data, 0);

  data.verts = new optix::float3[ nverts ];
  data.tris  = new optix::int3[ ntris ];

  if( !ply_read( ply ) ) {
    throw optix::Exception( "Error parsing ply file (" + _filename + ")" );
  }
  ply_close(ply);

  _aabb = data.aabb;

  /*
  std::cerr << " done.  got " << nverts << " verts and " << ntris << " tris." << std::endl;

  for( int i = 0; i < 10; ++i ) {
    std::cerr << " v: " << data.verts[i] << std::endl;
  }

  for( int i = 0; i < 10; ++i ) {
    std::cerr << " f: " << data.tris[i] << std::endl;
  }
  */

  createGeometryInstance( data.nverts, data.verts, data.ntris, data.tris );
}
Example #15
0
point_count_t PlyReader::read(PointViewPtr view, point_count_t num)
{
    CallbackContext context;
    context.view = view;
    context.dimensionMap = m_vertexDimensions;

    // It's possible that point_count_t holds a value that's larger than the
    // long that is the maximum rply (don't know about ply) point count.
    long cnt;
    cnt = Utils::inRange<long>(num) ? num : (std::numeric_limits<long>::max)();
    for (auto it : m_vertexDimensions)
    {
        ply_set_read_cb(m_ply, "vertex", it.first.c_str(), readPlyCallback,
            &context, cnt);
    }
    if (!ply_read(m_ply))
    {
        std::stringstream ss;
        ss << "Error reading " << m_filename << ".";
        throw pdal_error(ss.str());
    }
    return view->size();
}
Example #16
0
static gboolean
mash_ply_loader_load (MashDataLoader *data_loader,
                      MashDataFlags flags,
                      const gchar *filename,
                      GError **error)
{
  CoglContext *context;
  CoglIndices *indices;
  MashPlyLoader *self = MASH_PLY_LOADER (data_loader);
  MashPlyLoaderPrivate *priv;
  MashPlyLoaderData data;
  gchar *display_name;
  gboolean ret;

  priv = self->priv;

  context = es_get_cogl_context ();

  data.error = NULL;
  data.n_vertex_bytes = 0;
  data.available_props = 0;
  data.got_props = 0;
  data.vertices = g_byte_array_new ();
  data.faces = NULL;
  data.min_vertex.x = G_MAXFLOAT;
  data.min_vertex.y = G_MAXFLOAT;
  data.min_vertex.z = G_MAXFLOAT;
  data.max_vertex.x = -G_MAXFLOAT;
  data.max_vertex.y = -G_MAXFLOAT;
  data.max_vertex.z = -G_MAXFLOAT;
  data.flags = flags;

  display_name = g_filename_display_name (filename);

  if ((data.ply = ply_open (filename,
                            mash_ply_loader_error_cb,
                            &data)) == NULL)
    mash_ply_loader_check_unknown_error (&data);
  else
    {
      if (!ply_read_header (data.ply))
        mash_ply_loader_check_unknown_error (&data);
      else
        {
          int i;

          for (i = 0; i < G_N_ELEMENTS (mash_ply_loader_properties); i++)
            if (ply_set_read_cb (data.ply, "vertex",
                                 mash_ply_loader_properties[i].name,
                                 mash_ply_loader_vertex_read_cb,
                                 &data, i))
              {
                data.prop_map[i] = data.n_vertex_bytes;
                data.n_vertex_bytes += mash_ply_loader_properties[i].size;
                data.available_props |= 1 << i;
              }

          /* Align the size of a vertex to 32 bits */
          data.n_vertex_bytes = (data.n_vertex_bytes + 3) & ~(guint) 3;

          if ((data.available_props & MASH_PLY_LOADER_VERTEX_PROPS)
              != MASH_PLY_LOADER_VERTEX_PROPS)
            g_set_error (&data.error, MASH_DATA_ERROR,
                         MASH_DATA_ERROR_MISSING_PROPERTY,
                         "PLY file %s is missing the vertex properties",
                         display_name);
          else if (!ply_set_read_cb (data.ply, "face", "vertex_indices",
                                     mash_ply_loader_face_read_cb,
                                     &data, i))
            g_set_error (&data.error, MASH_DATA_ERROR,
                         MASH_DATA_ERROR_MISSING_PROPERTY,
                         "PLY file %s is missing face property "
                         "'vertex_indices'",
                         display_name);
          else if (mash_ply_loader_get_indices_type (&data, &data.error)
                   && !ply_read (data.ply))
            mash_ply_loader_check_unknown_error (&data);
        }

      ply_close (data.ply);
    }

  if (data.error)
    {
      g_propagate_error (error, data.error);
      ret = FALSE;
    }
  else if (data.faces->len < 3)
    {
      g_set_error (error, MASH_DATA_ERROR,
                   MASH_DATA_ERROR_INVALID,
                   "No faces found in %s",
                   display_name);
      ret = FALSE;
    }
  else
    {
      CoglAttributeBuffer *attribute_buffer;
      CoglAttribute *attributes[4];
      int n_attributes = 0, i;

      /* Get rid of the old primitive (if any) */
      mash_ply_loader_free_primitive (self);

      /* Create a new attribute buffer for the vertices */
      attribute_buffer = cogl_attribute_buffer_new (context,
                                                    data.vertices->len,
                                                    data.vertices->data);

      /* And describe the attributes */
      if ((data.available_props & MASH_PLY_LOADER_VERTEX_PROPS) ==
          MASH_PLY_LOADER_VERTEX_PROPS)
        {
          attributes[n_attributes++] =
            cogl_attribute_new (attribute_buffer,
                                "cogl_position_in",
                                data.n_vertex_bytes,
                                data.prop_map[0],
                                3,
                                COGL_ATTRIBUTE_TYPE_FLOAT);
        }

      if ((data.available_props & MASH_PLY_LOADER_NORMAL_PROPS) ==
          MASH_PLY_LOADER_NORMAL_PROPS)
        {
          attributes[n_attributes++] =
            cogl_attribute_new (attribute_buffer,
                                "cogl_normal_in",
                                data.n_vertex_bytes,
                                data.prop_map[3],
                                3,
                                COGL_ATTRIBUTE_TYPE_FLOAT);
        }

      if ((data.available_props & MASH_PLY_LOADER_TEX_COORD_PROPS) ==
          MASH_PLY_LOADER_TEX_COORD_PROPS)
        {
          attributes[n_attributes++] =
            cogl_attribute_new (attribute_buffer,
                                "cogl_tex_coord0_in",
                                data.n_vertex_bytes,
                                data.prop_map[6],
                                2,
                                COGL_ATTRIBUTE_TYPE_FLOAT);
        }

      if ((data.available_props & MASH_PLY_LOADER_COLOR_PROPS) ==
          MASH_PLY_LOADER_COLOR_PROPS)
        {
          attributes[n_attributes++] =
            cogl_attribute_new (attribute_buffer,
                                "cogl_color_in",
                                data.n_vertex_bytes,
                                data.prop_map[8],
                                3,
                                COGL_ATTRIBUTE_TYPE_FLOAT);
        }

      priv->primitive =
        cogl_primitive_new_with_attributes (COGL_VERTICES_MODE_TRIANGLES,
                                            data.vertices->len,
                                            attributes, n_attributes);
      for (i = 0; i < n_attributes; i++)
        cogl_object_unref (attributes[i]);

      indices = cogl_indices_new (context,
                                  data.indices_type,
                                  data.faces->data,
                                  data.faces->len);
      cogl_primitive_set_indices (priv->primitive,
                                  indices,
                                  data.faces->len);
      cogl_object_unref (indices);

      priv->min_vertex = data.min_vertex;
      priv->max_vertex = data.max_vertex;

      ret = TRUE;
    }

  g_free (display_name);
  g_byte_array_free (data.vertices, TRUE);
  if (data.faces)
    g_array_free (data.faces, TRUE);

  return ret;
}
Example #17
0
static void
ply_boot_client_process_incoming_replies (ply_boot_client_t *client)
{
  ply_list_node_t *request_node;
  ply_boot_client_request_t *request;
  bool processed_reply;
  uint8_t byte[2] = "";
  uint32_t size;

  assert (client != NULL);

  processed_reply = false;
  if (ply_list_get_length (client->requests_waiting_for_replies) == 0)
    {
      ply_error ("received unexpected response from boot status daemon");
      return;
    }

  if (!ply_read (client->socket_fd, byte, sizeof (uint8_t)))
    goto out;

  for (request_node = ply_list_get_first_node (client->requests_waiting_for_replies);
       request_node; request_node = ply_list_get_next_node (client->requests_waiting_for_replies, request_node))
    {
      assert (request_node != NULL);
      request = (ply_boot_client_request_t *) ply_list_node_get_data (request_node);
      assert (request != NULL);

      if (! strcmp (request->command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_PASSWORD)
          || ! strcmp (request->command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_QUESTION)
          || ! strcmp (request->command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_KEYSTROKE))
        {
          if (! memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ANSWER, sizeof (uint8_t))
              || ! memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NO_ANSWER, sizeof (uint8_t)))
            break;
        }
      else
        {
          if (memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ANSWER, sizeof (uint8_t))
              && memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NO_ANSWER, sizeof (uint8_t)))
            break;
        }
    }

  if (memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK, sizeof (uint8_t)) == 0)
      request->handler (request->user_data, client);
  else if (memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ANSWER, sizeof (uint8_t)) == 0)
    {
      char *answer;

      if (!ply_read_uint32 (client->socket_fd, &size))
        goto out;
      
      answer = malloc ((size+1) * sizeof(char));
      if (size > 0)
        {
          if (!ply_read (client->socket_fd, answer, size))
            goto out;
        }

      answer[size] = '\0';
      ((ply_boot_client_answer_handler_t) request->handler) (request->user_data, answer, client);
      free(answer);
    }
  else if (memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_MULTIPLE_ANSWERS, sizeof (uint8_t)) == 0)
    {
      ply_array_t *array;
      char **answers;
      char *answer;
      char *p;
      char *q;
      uint8_t i;

      array = NULL;
      answers = NULL;

      if (!ply_read_uint32 (client->socket_fd, &size))
        goto out;

      assert (size > 0);

      answer = malloc (size);

      if (!ply_read (client->socket_fd, answer, size))
        {
          free (answer);
          goto out;
        }

      array = ply_array_new ();

      p = answer;
      q = p;
      for (i = 0; i < size; i++, q++)
        {
          if (*q == '\0')
            {
              ply_array_add_element (array, strdup (p));
              p = q + 1;
            }
        }
      free (answer);

      answers = (char **) ply_array_steal_elements (array);
      ply_array_free (array);

      ((ply_boot_client_multiple_answers_handler_t) request->handler) (request->user_data, (const char * const *) answers, client);

      ply_free_string_array (answers);
    }
  else if (memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NO_ANSWER, sizeof (uint8_t)) == 0)
    {
      ((ply_boot_client_answer_handler_t) request->handler) (request->user_data, NULL, client);
    }
  else
    goto out;

  processed_reply = true;

out:
  if (!processed_reply)
    {
      if (request->failed_handler != NULL)
        request->failed_handler (request->user_data, client);
    }

  ply_list_remove_node (client->requests_waiting_for_replies, request_node);

  if (ply_list_get_length (client->requests_waiting_for_replies) == 0)
    {
      if (client->daemon_has_reply_watch != NULL)
        {
          assert (client->loop != NULL);
          ply_event_loop_stop_watching_fd (client->loop,
                                           client->daemon_has_reply_watch);
          client->daemon_has_reply_watch = NULL;
        }
    }
}
Example #18
0
Geometry::Geometry(const string &fileName) {
	p_ply plyfile = ply_open(fileName.c_str(), NULL);
	if (!plyfile) {
		stringstream ss;
		ss << "Unable to read PLY mesh file '" << fileName << "'";
		throw runtime_error(ss.str());
	}

	if (!ply_read_header(plyfile)) {
		stringstream ss;
		ss << "Unable to read PLY header from '" << fileName << "'";
		throw runtime_error(ss.str());
	}

	Point *p;
	long plyNbVerts = ply_set_read_cb(plyfile, "vertex", "x", VertexCB, &p, 0);
	ply_set_read_cb(plyfile, "vertex", "y", VertexCB, &p, 1);
	ply_set_read_cb(plyfile, "vertex", "z", VertexCB, &p, 2);
	if (plyNbVerts <= 0) {
		stringstream ss;
		ss << "No vertices found in '" << fileName << "'";
		throw runtime_error(ss.str());
	}

	Triangle *vi;
	long plyNbTris = ply_set_read_cb(plyfile, "face", "vertex_indices", FaceCB, &vi, 0);
	if (plyNbTris <= 0) {
		stringstream ss;
		ss << "No triangles found in '" << fileName << "'";
		throw runtime_error(ss.str());
	}

	Normal *n;
	long plyNbNormals = ply_set_read_cb(plyfile, "vertex", "nx", NormalCB, &n, 0);
	ply_set_read_cb(plyfile, "vertex", "ny", NormalCB, &n, 1);
	ply_set_read_cb(plyfile, "vertex", "nz", NormalCB, &n, 2);
	if ((plyNbNormals > 0) && (plyNbNormals != plyNbVerts)) {
		stringstream ss;
		ss << "Wrong count of normals in '" << fileName << "'";
		throw runtime_error(ss.str());
	}

	RGB *c;
	long plyNbColors = ply_set_read_cb(plyfile, "vertex", "red", ColorCB, &c, 0);
	ply_set_read_cb(plyfile, "vertex", "green", ColorCB, &c, 1);
	ply_set_read_cb(plyfile, "vertex", "blue", ColorCB, &c, 2);

	if ((plyNbColors <= 0) || ((plyNbColors > 0) && (plyNbColors != plyNbVerts))) {
		stringstream ss;
		ss << "Wrong count of colors in '" << fileName << "'";
		throw runtime_error(ss.str());
	}

	p = new Point[plyNbVerts];
	vi = new Triangle[plyNbTris];
	c = new RGB[plyNbColors];
	n = new Normal[plyNbVerts];

	if (!ply_read(plyfile)) {
		stringstream ss;
		ss << "Unable to parse PLY file '" << fileName << "'";

		delete[] p;
		delete[] vi;
		delete[] c;
		delete[] n;

		throw runtime_error(ss.str());
	}

	ply_close(plyfile);

	vertexCount = plyNbVerts;
	triangleCount = plyNbTris;
	vertices = p;
	triangles = vi;
	vertNormals = n;
	vertColors = c;

	// Scale vertex colors
	for (unsigned int i = 0; i < vertexCount; ++i)
		c[i] *= 0.75f;

	// It looks like normals exported by Blender are bugged
	for (unsigned int i = 0; i < vertexCount; ++i)
		vertNormals[i] = Normal(0.f, 0.f, 0.f);
	for (unsigned int i = 0; i < triangleCount; ++i) {
		const Vector e1 = vertices[triangles[i].v[1]] - vertices[triangles[i].v[0]];
		const Vector e2 = vertices[triangles[i].v[2]] - vertices[triangles[i].v[0]];
		const Normal n = Normal(Normalize(Cross(e1, e2)));
		vertNormals[triangles[i].v[0]] += n;
		vertNormals[triangles[i].v[1]] += n;
		vertNormals[triangles[i].v[2]] += n;
	}
	int printedWarning = 0;
	for (unsigned int i = 0; i < vertexCount; ++i) {
		vertNormals[i] = Normalize(vertNormals[i]);
		// Check for degenerate triangles/normals, they can freeze the GPU
		if (isnan(vertNormals[i].x) || isnan(vertNormals[i].y) || isnan(vertNormals[i].z)) {
			if (printedWarning < 15) {
				cerr << "The model contains a degenerate normal (index " << i << ")" << endl;
				++printedWarning;
			} else if (printedWarning == 15) {
				cerr << "The model contains more degenerate normals" << endl;
				++printedWarning;
			}
			vertNormals[i] = Normal(0.f, 0.f, 1.f);
		}
	}

	/*if (plyNbNormals <= 0) {
		// Calculate normals
		for (unsigned int i = 0; i < triangleCount; ++i) {
			const Vector e1 = vertices[triangles[i].v[1]] - vertices[triangles[i].v[0]];
			const Vector e2 = vertices[triangles[i].v[2]] - vertices[triangles[i].v[0]];
			const Normal n = Normal(Normalize(Cross(e1, e2)));
			vertNormals[triangles[i].v[0]] = n;
			vertNormals[triangles[i].v[1]] = n;
			vertNormals[triangles[i].v[2]] = n;
		}
	}*/
}
Example #19
0
void
read_file(FILE *inFile)
{
  int i,j,k;
  PlyFile *ply;
  int nprops;
  int num_elems;
  PlyProperty **plist;
  char *elem_name;
  float version;
  int get_nx,get_ny,get_nz;

  /*** Read in the original PLY object ***/


  ply  = ply_read (inFile, &nelems, &elist);
  ply_get_info (ply, &version, &file_type);

  for (i = 0; i < nelems; i++) {

    /* get the description of the first element */
    elem_name = elist[i];
    plist = ply_get_element_description (ply, elem_name, &num_elems, &nprops);

    if (equal_strings ("vertex", elem_name)) {

      /* see if vertex holds any normal information */
      get_nx = get_ny = get_nz = 0;
      for (j = 0; j < nprops; j++) {
        if (equal_strings ("nx", plist[j]->name)) get_nx = 1;
        if (equal_strings ("ny", plist[j]->name)) get_ny = 1;
        if (equal_strings ("nz", plist[j]->name)) get_nz = 1;
      }

      /* create a vertex list to hold all the vertices */
      vlist = (Vertex **) malloc (sizeof (Vertex *) * num_elems);
      nverts = num_elems;

      /* set up for getting vertex elements */

      ply_get_property (ply, elem_name, &vert_props[0]);
      ply_get_property (ply, elem_name, &vert_props[1]);
      ply_get_property (ply, elem_name, &vert_props[2]);
      if (get_nx) ply_get_property (ply, elem_name, &vert_props[3]);
      if (get_ny) ply_get_property (ply, elem_name, &vert_props[4]);
      if (get_nz) ply_get_property (ply, elem_name, &vert_props[5]);
      vert_other = ply_get_other_properties (ply, elem_name,
                     offsetof(Vertex,other_props));

      /* grab all the vertex elements */
      for (j = 0; j < num_elems; j++) {
        vlist[j] = (Vertex *) malloc (sizeof (Vertex));
        ply_get_element (ply, (void *) vlist[j]);
      }
    }
    else if (equal_strings ("face", elem_name)) {

      /* create a list to hold all the face elements */
      flist = (Face **) malloc (sizeof (Face *) * num_elems);
      nfaces = num_elems;

      /* set up for getting face elements */

      ply_get_property (ply, elem_name, &face_props[0]);
      face_other = ply_get_other_properties (ply, elem_name,
                     offsetof(Face,other_props));

      /* grab all the face elements */
      for (j = 0; j < num_elems; j++) {
        flist[j] = (Face *) malloc (sizeof (Face));
        ply_get_element (ply, (void *) flist[j]);
      }
    }
    else
      other_elements = ply_get_other_element (ply, elem_name, num_elems);
  }

  comments = ply_get_comments (ply, &num_comments);
  obj_info = ply_get_obj_info (ply, &num_obj_info);

  ply_close (ply);
}
Example #20
0
bool loadPlyFile(const QString& fileName,
                 PlyLoadInfo& info)
{
    // Read a triangulation from a .ply file
    std::unique_ptr<t_ply_, int(*)(p_ply)> ply(
            ply_open(fileName.toUtf8().constData(), NULL, 0, NULL), ply_close);
    if (!ply || !ply_read_header(ply.get()))
    {
        g_logger.error("Could not open ply or read header");
        return false;
    }
    long nvertices = ply_set_read_cb(ply.get(), "vertex", "x", vertex_cb, &info, 0);
    if (ply_set_read_cb(ply.get(), "vertex", "y", vertex_cb, &info, 1) != nvertices ||
        ply_set_read_cb(ply.get(), "vertex", "z", vertex_cb, &info, 2) != nvertices)
    {
        g_logger.error("Expected vertex properties (x,y,z) in ply file");
        return false;
    }
    info.verts.reserve(3*nvertices);
    long ncolors = ply_set_read_cb(ply.get(), "color", "r", color_cb, &info, 0);
    if (ncolors != 0)
    {
        ply_set_read_cb(ply.get(), "color", "g", color_cb, &info, 1);
        ply_set_read_cb(ply.get(), "color", "b", color_cb, &info, 2);
        info.colors.reserve(3*nvertices);
    }
    if (ncolors == 0)
    {
        ncolors = ply_set_read_cb(ply.get(), "vertex", "r", color_cb, &info, 0);
        if (ncolors != 0)
        {
            ply_set_read_cb(ply.get(), "vertex", "g", color_cb, &info, 1);
            ply_set_read_cb(ply.get(), "vertex", "b", color_cb, &info, 2);
            info.colors.reserve(3*nvertices);
        }
    }
    // Attempt to load attributes with names face/vertex_index or face/vertex_indices
    // There doesn't seem to be a real standard here...
    long nfaces = ply_set_read_cb(ply.get(), "face", "vertex_index", face_cb, &info, 1);
    if (nfaces == 0)
        nfaces = ply_set_read_cb(ply.get(), "face", "vertex_indices", face_cb, &info, 1);
    if (nfaces == 0)
    {
        nfaces = ply_set_read_cb(ply.get(), "triangle", "v1", face_cb, &info, 0);
        if (nfaces != 0 &&
            (ply_set_read_cb(ply.get(), "triangle", "v2", face_cb, &info, 0) != nfaces ||
             ply_set_read_cb(ply.get(), "triangle", "v3", face_cb, &info, 0) != nfaces))
        {
            g_logger.error("Expected triangle properties (v1,v2,v3) in ply file");
            return false;
        }
    }

    long nedges = ply_set_read_cb(ply.get(), "edge", "vertex_index", edge_cb, &info, 0);
    if (nedges == 0)
        nedges = ply_set_read_cb(ply.get(), "edge", "vertex_indices", edge_cb, &info, 0);

    // Support for specific Roames Ply format
    std::vector<unsigned int> innerPolygonVertexCount;
    std::vector<unsigned int> innerVertexIndices;
    if (nedges == 0)
    {
        nedges = ply_set_read_cb(ply.get(), "polygon", "outer_vertex_index", edge_cb, &info, 1);
        nedges += ply_set_read_cb(ply.get(), "hullxy", "vertex_index", edge_cb, &info, 1);
        nedges += ply_set_read_cb(ply.get(), "polygon", "inner_polygon_vertex_counts", list_cb, &innerPolygonVertexCount, 0);
        ply_set_read_cb(ply.get(), "polygon", "inner_vertex_index", list_cb, &innerVertexIndices, 0);
    }

    if (nedges <= 0 && nfaces <= 0)
    {
        g_logger.error("Expected more than zero edges or faces in ply file");
        return false;
    }
    if (nfaces > 0)
    {
        // Ply file contains a mesh - load as triangle mesh
        info.faces.reserve(3*nfaces);
    }
    if (nedges > 0)
    {
        // Ply file contains a set of edges
        info.edges.reserve(2*nedges);
    }
    if (!ply_read(ply.get()))
    {
        g_logger.error("Error reading ply file data section");
        return false;
    }
    if (info.colors.size() != info.verts.size())
        info.colors.clear();

    // Reconstruct inner polygons
    for (size_t i = 0, j = 0; i < innerPolygonVertexCount.size(); ++i)
    {
        size_t count = innerPolygonVertexCount[i];
        for (size_t k = 0; k < count; ++k)
        {
            info.edges.push_back(innerVertexIndices[j + k]);
            info.edges.push_back(innerVertexIndices[j + (k+1) % count]);
        }
        j += count;
    }

    return true;
}
Example #21
0
void ReadFile( MFIList *mfi, Model *model )
{
	int i,j;
	PlyFile *ply;
	int nprops;
	int num_elems;
	PlyProperty **plist;
	char *elem_name;
	float version;
	FILE *fp;

	if ((fp = fopen(mfi->file_info.path, "rb")) == NULL)
	{
		crError( "Can't open %s for reading!", mfi->file_info.path );
	}

	ply  = ply_read (fp, &nelems, &elist);
	ply_get_info (ply, &version, &file_type);

	for (i = 0; i < nelems; i++) 
	{
		/* get the description of the first element */
		elem_name = elist[i];
		plist = ply_get_element_description (ply, elem_name, &num_elems, &nprops);

		if (equal_strings ("vertex", elem_name)) {

			/* see if vertex holds any normal information */
			globals.has_nx = globals.has_ny = globals.has_nz = 0;
			globals.has_r = globals.has_g = globals.has_b = 0;
			for (j = 0; j < nprops; j++) {
				if (equal_strings ("nx", plist[j]->name)) globals.has_nx = 1;
				if (equal_strings ("ny", plist[j]->name)) globals.has_ny = 1;
				if (equal_strings ("nz", plist[j]->name)) globals.has_nz = 1;
				if (equal_strings ("red", plist[j]->name)) globals.has_r = 1;
				if (equal_strings ("green", plist[j]->name)) globals.has_g = 1;
				if (equal_strings ("blue", plist[j]->name)) globals.has_b = 1;
			}

			/* create a vertex list to hold all the vertices */
			model->vlist = (Vertex *) crAlloc (sizeof (*(model->vlist)) * num_elems);
			model->nverts = num_elems;

			/* set up for getting vertex elements */

			ply_get_property (ply, elem_name, &vert_props[0]);
			ply_get_property (ply, elem_name, &vert_props[1]);
			ply_get_property (ply, elem_name, &vert_props[2]);
			if (globals.has_r) ply_get_property (ply, elem_name, &vert_props[3]);
			if (globals.has_g) ply_get_property (ply, elem_name, &vert_props[4]);
			if (globals.has_b) ply_get_property (ply, elem_name, &vert_props[5]);
			if (globals.has_nx) ply_get_property (ply, elem_name, &vert_props[6]);
			if (globals.has_ny) ply_get_property (ply, elem_name, &vert_props[7]);
			if (globals.has_nz) ply_get_property (ply, elem_name, &vert_props[8]);

			/* grab all the vertex elements */
			for (j = 0; j < num_elems; j++) {
				model->vlist[j].r = 1.0f;
				model->vlist[j].g = 1.0f;
				model->vlist[j].b = 1.0f;
				model->vlist[j].nx = 1.0f;
				model->vlist[j].ny = 1.0f;
				model->vlist[j].nz = 1.0f;
				ply_get_element (ply, model->vlist+j);
				model->vlist[j].r /= 255.0f;
				model->vlist[j].g /= 255.0f;
				model->vlist[j].b /= 255.0f;
			}
		}
		else if (equal_strings ("face", elem_name)) {

			/* create a list to hold all the face elements */
			model->flist = (Face *) crAlloc (sizeof (*(model->flist)) * num_elems);
			model->nfaces = num_elems;

			/* set up for getting face elements */

			ply_get_property (ply, elem_name, &face_props[0]);

			/* grab all the face elements */
			crDebug( "Reading %s (%d faces)", mfi->file_info.path, model->nfaces );
			model->faces = (unsigned int *) crAlloc( model->nfaces * 3 * sizeof( *(model->faces) ) );
			for (j = 0; j < num_elems; j++) {
				ply_get_element (ply, model->flist + j);
				model->faces[j*3+0] = model->flist[j].verts[0];
				model->faces[j*3+1] = model->flist[j].verts[1];
				model->faces[j*3+2] = model->flist[j].verts[2];
			}
		}
	}

	ply_close (ply);
}
Example #22
0
std::vector<std::shared_ptr<Shape>> CreatePLYMesh(
    const Transform *o2w, const Transform *w2o, bool reverseOrientation,
    const ParamSet &params,
    std::map<std::string, std::shared_ptr<Texture<Float>>> *floatTextures) {
    const std::string filename = params.FindOneFilename("filename", "");
    p_ply ply = ply_open(filename.c_str(), rply_message_callback, 0, nullptr);
    if (!ply) {
        Error("Couldn't open PLY file \"%s\"", filename.c_str());
        return std::vector<std::shared_ptr<Shape>>();
    }

    if (!ply_read_header(ply)) {
        Error("Unable to read the header of PLY file \"%s\"", filename.c_str());
        return std::vector<std::shared_ptr<Shape>>();
    }

    p_ply_element element = nullptr;
    long vertexCount = 0, faceCount = 0;

    /* Inspect the structure of the PLY file */
    while ((element = ply_get_next_element(ply, element)) != nullptr) {
        const char *name;
        long nInstances;

        ply_get_element_info(element, &name, &nInstances);
        if (!strcmp(name, "vertex"))
            vertexCount = nInstances;
        else if (!strcmp(name, "face"))
            faceCount = nInstances;
    }

    if (vertexCount == 0 || faceCount == 0) {
        Error("PLY file \"%s\" is invalid! No face/vertex elements found!",
              filename.c_str());
        return std::vector<std::shared_ptr<Shape>>();
    }

    CallbackContext context;

    if (ply_set_read_cb(ply, "vertex", "x", rply_vertex_callback, &context,
                        0x030) &&
        ply_set_read_cb(ply, "vertex", "y", rply_vertex_callback, &context,
                        0x031) &&
        ply_set_read_cb(ply, "vertex", "z", rply_vertex_callback, &context,
                        0x032)) {
        context.p = new Point3f[vertexCount];
    } else {
        Error("PLY file \"%s\": Vertex coordinate property not found!",
              filename.c_str());
        return std::vector<std::shared_ptr<Shape>>();
    }

    if (ply_set_read_cb(ply, "vertex", "nx", rply_vertex_callback, &context,
                        0x130) &&
        ply_set_read_cb(ply, "vertex", "ny", rply_vertex_callback, &context,
                        0x131) &&
        ply_set_read_cb(ply, "vertex", "nz", rply_vertex_callback, &context,
                        0x132))
        context.n = new Normal3f[vertexCount];

    /* There seem to be lots of different conventions regarding UV coordinate
     * names */
    if ((ply_set_read_cb(ply, "vertex", "u", rply_vertex_callback, &context,
                         0x220) &&
         ply_set_read_cb(ply, "vertex", "v", rply_vertex_callback, &context,
                         0x221)) ||
        (ply_set_read_cb(ply, "vertex", "s", rply_vertex_callback, &context,
                         0x220) &&
         ply_set_read_cb(ply, "vertex", "t", rply_vertex_callback, &context,
                         0x221)) ||
        (ply_set_read_cb(ply, "vertex", "texture_u", rply_vertex_callback,
                         &context, 0x220) &&
         ply_set_read_cb(ply, "vertex", "texture_v", rply_vertex_callback,
                         &context, 0x221)) ||
        (ply_set_read_cb(ply, "vertex", "texture_s", rply_vertex_callback,
                         &context, 0x220) &&
         ply_set_read_cb(ply, "vertex", "texture_t", rply_vertex_callback,
                         &context, 0x221)))
        context.uv = new Point2f[vertexCount];

    /* Allocate enough space in case all faces are quads */
    context.indices = new int[faceCount * 6];
    context.vertexCount = vertexCount;

    ply_set_read_cb(ply, "face", "vertex_indices", rply_face_callback, &context,
                    0);

    if (!ply_read(ply)) {
        Error("Unable to read the contents of PLY file \"%s\"",
              filename.c_str());
        ply_close(ply);
        return std::vector<std::shared_ptr<Shape>>();
    }

    ply_close(ply);

    if (context.error) return std::vector<std::shared_ptr<Shape>>();

    // Look up an alpha texture, if applicable
    std::shared_ptr<Texture<Float>> alphaTex;
    std::string alphaTexName = params.FindTexture("alpha");
    if (alphaTexName != "") {
        if (floatTextures->find(alphaTexName) != floatTextures->end())
            alphaTex = (*floatTextures)[alphaTexName];
        else
            Error("Couldn't find float texture \"%s\" for \"alpha\" parameter",
                  alphaTexName.c_str());
    } else if (params.FindOneFloat("alpha", 1.f) == 0.f) {
        alphaTex.reset(new ConstantTexture<Float>(0.f));
    }

    std::shared_ptr<Texture<Float>> shadowAlphaTex;
    std::string shadowAlphaTexName = params.FindTexture("shadowalpha");
    if (shadowAlphaTexName != "") {
        if (floatTextures->find(shadowAlphaTexName) != floatTextures->end())
            shadowAlphaTex = (*floatTextures)[shadowAlphaTexName];
        else
            Error(
                "Couldn't find float texture \"%s\" for \"shadowalpha\" "
                "parameter",
                shadowAlphaTexName.c_str());
    } else if (params.FindOneFloat("shadowalpha", 1.f) == 0.f)
        shadowAlphaTex.reset(new ConstantTexture<Float>(0.f));

    return CreateTriangleMesh(o2w, w2o, reverseOrientation,
                              context.indexCtr / 3, context.indices,
                              vertexCount, context.p, nullptr, context.n,
                              context.uv, alphaTex, shadowAlphaTex);
}
Example #23
0
/*******************************************************************************
 *         Name:  loadPly
 *  Description:  Load a ply file into memory.
 ******************************************************************************/
void loadPly( char * filename, size_t idx ) {

	printf( "Loading »%s«…\n", filename );

	p_ply ply = ply_open( filename, NULL, 0, NULL );

	if ( !ply ) {
		fprintf( stderr, "error: Could not open »%s«.\n", filename );
		exit( EXIT_FAILURE );
	}
	if ( !ply_read_header( ply ) ) {
		fprintf( stderr, "error: Could not read header.\n" );
		exit( EXIT_FAILURE );
	}

	/* Check if there are vertices and get the amount of vertices. */
	char buf[256] = "";
	char elemname[256] = "point";
	const char * name = buf;
	long int nvertices = 0;
	long int count = 0;
	p_ply_element elem = NULL;
	while ( ( elem = ply_get_next_element( ply, elem ) ) ) {
		ply_get_element_info( elem, &name, &count );
		if ( !strcmp( name, "vertex" ) ) {
			nvertices = count;
			strcpy( elemname, "vertex" );
			p_ply_property prop = NULL;
			if ( g_clouds[ idx ].colors ) {
				free( g_clouds[ idx ].colors );
			}
			while ( ( prop = ply_get_next_property( elem, prop ) ) ) {
				ply_get_property_info( prop, &name, NULL, NULL, NULL );
				if ( !strcmp( name, "red" ) ) {
					/* We have color information */
					g_clouds[ idx ].colors = ( uint8_t * ) 
						realloc( g_clouds[ idx ].colors, nvertices * 3 * sizeof(uint8_t) );
				}
			}
		} else if ( !strcmp( name, "point" ) ) {
			nvertices = count;
			strcpy( elemname, "point" );
			p_ply_property prop = NULL;
			if ( g_clouds[ idx ].colors ) {
				free( g_clouds[ idx ].colors );
			}
			while ( ( prop = ply_get_next_property( elem, prop ) ) ) {
				ply_get_property_info( prop, &name, NULL, NULL, NULL );
				if ( !strcmp( name, "red" ) ) {
					/* We have color information */
					g_clouds[ idx ].colors = ( uint8_t * ) 
						realloc( g_clouds[ idx ].colors, nvertices * 3 * sizeof(uint8_t) );
				}
			}
			/* Point is more important than vertex. Thus we can stop immediately if
			 * we got this element. */
			break;
		}
	}
	if ( !nvertices ) {
		fprintf( stderr, "warning: No vertices in ply.\n" );
		return;
	}

	/* Allocate memory. */
	g_clouds[ idx ].pointcount = nvertices;
	nvertices++;
	g_clouds[ idx ].vertices = (float*) malloc( nvertices * 3 * sizeof(float) );
	
	uint8_t* color  = g_clouds[ idx ].colors;
	g_clouds[ idx ].boundingbox.min.x = DBL_MAX;
	g_clouds[ idx ].boundingbox.min.y = DBL_MAX;
	g_clouds[ idx ].boundingbox.min.z = DBL_MAX;
	g_clouds[ idx ].boundingbox.max.x = DBL_MIN;
	g_clouds[ idx ].boundingbox.max.y = DBL_MIN;
	g_clouds[ idx ].boundingbox.max.z = DBL_MIN;
	struct { float* v; boundingbox_t* b; } d = { 
		g_clouds[ idx ].vertices, &g_clouds[ idx ].boundingbox };

	/* Set callbacks. */
	nvertices = ply_set_read_cb( ply, elemname, "x", plyVertexCb, &d, 0 );
	            ply_set_read_cb( ply, elemname, "y", plyVertexCb, &d, 1 );
	            ply_set_read_cb( ply, elemname, "z", plyVertexCb, &d, 2 );

	if ( color ) {
		ply_set_read_cb( ply, elemname, "red",   plyColorCb, &color, 0 );
		ply_set_read_cb( ply, elemname, "green", plyColorCb, &color, 1 );
		ply_set_read_cb( ply, elemname, "blue",  plyColorCb, &color, 2 );
	}

	/* Read ply file. */
	if ( !ply_read( ply ) ) {
		fprintf( stderr, "error: could not read »%s«.\n", filename );
		exit( EXIT_FAILURE );
	}
	ply_close( ply );

	printf( "%ld values read.\nPoint cloud loaded.", nvertices );

	g_maxdim = max( max( max( g_maxdim, d.b->max.x - d.b->min.x ), 
				d.b->max.y - d.b->min.y ), d.b->max.z - d.b->min.z ); 
	g_bb.max.x = max( g_bb.max.x, d.b->max.x );
	g_bb.max.y = max( g_bb.max.y, d.b->max.y );
	g_bb.max.z = max( g_bb.max.z, d.b->max.z );
	g_bb.min.x = min( g_bb.min.x, d.b->min.x );
	g_bb.min.y = min( g_bb.min.y, d.b->min.y );
	g_bb.min.z = min( g_bb.min.z, d.b->min.z );

}
Example #24
0
bool loadPlyFile(const QString& fileName,
                 PlyLoadInfo& info)
{
    // Read a triangulation from a .ply file
    std::unique_ptr<t_ply_, int(*)(p_ply)> ply(
            ply_open(fileName.toUtf8().constData(), logRplyError, 0, NULL), ply_close);
    if (!ply || !ply_read_header(ply.get()))
    {
        g_logger.error("Could not open ply or read header");
        return false;
    }
    long nvertices = ply_set_read_cb(ply.get(), "vertex", "x", vertex_cb, &info, 0);
    if (ply_set_read_cb(ply.get(), "vertex", "y", vertex_cb, &info, 1) != nvertices ||
        ply_set_read_cb(ply.get(), "vertex", "z", vertex_cb, &info, 2) != nvertices)
    {
        g_logger.error("Expected vertex properties (x,y,z) in ply file");
        return false;
    }
    info.nvertices = nvertices;
    info.currPoly.setVertexCount(nvertices);
    info.verts.reserve(3*nvertices);
    long ncolors = ply_set_read_cb(ply.get(), "color", "r", color_cb, &info, 0);
    if (ncolors != 0)
    {
        ply_set_read_cb(ply.get(), "color", "g", color_cb, &info, 1);
        ply_set_read_cb(ply.get(), "color", "b", color_cb, &info, 2);
        info.colors.reserve(3*nvertices);
    }
    if (ncolors == 0)
    {
        ncolors = ply_set_read_cb(ply.get(), "vertex", "r", color_cb, &info, 0);
        if (ncolors != 0)
        {
            ply_set_read_cb(ply.get(), "vertex", "g", color_cb, &info, 1);
            ply_set_read_cb(ply.get(), "vertex", "b", color_cb, &info, 2);
            info.colors.reserve(3*nvertices);
        }
    }
    long ntexcoords = ply_set_read_cb(ply.get(), "vertex", "u", texcoord_cb, &info, 0);
    if (ntexcoords != 0)
    {
        if (ply_set_read_cb(ply.get(), "vertex", "v", texcoord_cb, &info, 1) == ntexcoords)
            info.texcoords.reserve(2*nvertices);
        else
            ntexcoords = 0;
    }

    const char* cmt = NULL;
    while (true)
    {
        cmt = ply_get_next_comment(ply.get(), cmt);
        if (!cmt)
            break;
        QList<QString> tokens = QString(cmt).split(" ");
        if (tokens[0] == "TextureFile" && tokens.size() > 1)
        {
            QDir d = QFileInfo(fileName).dir();
            info.textureFileName = d.absoluteFilePath(tokens[1]);
        }
    }

    long nfaces = 0;
    long nedges = 0;

    // Attach callbacks for faces.  Try both face.vertex_index and
    // face.vertex_indices since there doesn't seem to be a real standard.
    nfaces += ply_set_read_cb(ply.get(), "face", "vertex_index",
                              face_cb, &info, PolygonBuilder::OuterRingInds);
    nfaces += ply_set_read_cb(ply.get(), "face", "vertex_indices",
                              face_cb, &info, PolygonBuilder::OuterRingInds);

    // Attach callbacks for polygons with holes.
    // This isn't a standard at all, it's something I just made up :-/
    long npolygons = 0;
    npolygons += ply_set_read_cb(ply.get(), "polygon", "vertex_index",
                                 face_cb, &info, PolygonBuilder::OuterRingInds);
    npolygons += ply_set_read_cb(ply.get(), "polygon", "outer_vertex_index",
                                 face_cb, &info, PolygonBuilder::OuterRingInds); // DEPRECATED
    nfaces += npolygons;
    if (npolygons > 0)
    {
        // Holes
        if (ply_set_read_cb(ply.get(), "polygon", "inner_vertex_counts",
                            face_cb, &info, PolygonBuilder::InnerRingSizes))
        {
            if (!ply_set_read_cb(ply.get(), "polygon", "inner_vertex_index",
                                 face_cb, &info, PolygonBuilder::InnerRingInds))
            {
                g_logger.error("Found ply property polygon.inner_vertex_counts "
                               "without polygon.inner_vertex_index");
                return false;
            }
            info.currPoly.setPropertiesAvailable(PolygonBuilder::OuterRingInds |
                                                 PolygonBuilder::InnerRingSizes |
                                                 PolygonBuilder::InnerRingInds);
        }
    }

    // Attach callbacks for edges.  AFAIK this isn't really a standard, I'm
    // just copying the semi-standard people use for faces.
    nedges += ply_set_read_cb(ply.get(), "edge", "vertex_index",   edge_cb, &info, 0);
    nedges += ply_set_read_cb(ply.get(), "edge", "vertex_indices", edge_cb, &info, 0);

    if (nedges <= 0 && nfaces <= 0)
    {
        g_logger.error("Expected more than zero edges or faces in ply file");
        return false;
    }

    if (!ply_read(ply.get()))
    {
        g_logger.error("Error reading ply file data section");
        return false;
    }
    info.postprocess();
    if (info.colors.size() != info.verts.size())
        info.colors.clear();

    return true;
}
Example #25
0
void load_ply(const std::string &filename, MatrixXu &F, MatrixXf &V, bool load_faces,
              const ProgressCallback &progress) {
    auto message_cb = [](p_ply ply, const char *msg) {
        cerr << "rply: " << msg << endl;
    };

    Timer<> timer;
    cout << "Loading \"" << filename << "\" .. ";
    cout.flush();

    p_ply ply = ply_open(filename.c_str(), message_cb, 0, nullptr);
    if (!ply)
        throw std::runtime_error("Unable to open PLY file \"" + filename + "\"!");

    if (!ply_read_header(ply)) {
        ply_close(ply);
        throw std::runtime_error("Unable to open PLY header of \"" + filename + "\"!");
    }

    p_ply_element element = nullptr;
    uint32_t vertexCount = 0, faceCount = 0;

    /* Inspect the structure of the PLY file */
    while ((element = ply_get_next_element(ply, element)) != nullptr) {
        const char *name;
        long nInstances;

        ply_get_element_info(element, &name, &nInstances);
        if (!strcmp(name, "vertex"))
            vertexCount = (uint32_t) nInstances;
        else if (!strcmp(name, "face"))
            faceCount = (uint32_t) nInstances;
    }

    if (vertexCount == 0 && faceCount == 0)
        throw std::runtime_error("PLY file \"" + filename + "\" is invalid! No face/vertex/elements found!");

    if (load_faces)
        F.resize(3, faceCount);
    V.resize(3, vertexCount);

    struct VertexCallbackData {
        MatrixXf &V;
        const ProgressCallback &progress;
        VertexCallbackData(MatrixXf &V, const ProgressCallback &progress)
            : V(V), progress(progress) {}
    };

    struct FaceCallbackData {
        MatrixXu &F;
        const ProgressCallback &progress;
        FaceCallbackData(MatrixXu &F, const ProgressCallback &progress)
            : F(F), progress(progress) {}
    };

    auto rply_vertex_cb = [](p_ply_argument argument) -> int {
        VertexCallbackData *data;
        long index, coord;
        ply_get_argument_user_data(argument, (void **) &data, &coord);
        ply_get_argument_element(argument, nullptr, &index);
        data->V(coord, index) = (Float) ply_get_argument_value(argument);
        if (data->progress && coord == 0 && index % 500000 == 0)
            data->progress("Loading vertex data", index / (Float) data->V.cols());
        return 1;
    };

    auto rply_index_cb = [](p_ply_argument argument) -> int {
        FaceCallbackData *data;
        long length, value_index, index;
        ply_get_argument_property(argument, nullptr, &length, &value_index);

        if (length != 3)
            throw std::runtime_error("Only triangle faces are supported!");

        ply_get_argument_user_data(argument, (void **) &data, nullptr);
        ply_get_argument_element(argument, nullptr, &index);

        if (value_index >= 0)
            data->F(value_index, index) = (uint32_t) ply_get_argument_value(argument);

        if (data->progress && value_index == 0 && index % 500000 == 0)
            data->progress("Loading face data", index / (Float) data->F.cols());

        return 1;
    };

    VertexCallbackData vcbData(V, progress);
    FaceCallbackData fcbData(F, progress);

    if (!ply_set_read_cb(ply, "vertex", "x", rply_vertex_cb, &vcbData, 0) ||
            !ply_set_read_cb(ply, "vertex", "y", rply_vertex_cb, &vcbData, 1) ||
            !ply_set_read_cb(ply, "vertex", "z", rply_vertex_cb, &vcbData, 2)) {
        ply_close(ply);
        throw std::runtime_error("PLY file \"" + filename + "\" does not contain vertex position data!");
    }

    if (load_faces) {
        if (!ply_set_read_cb(ply, "face", "vertex_indices", rply_index_cb, &fcbData, 0)) {
            ply_close(ply);
            throw std::runtime_error("PLY file \"" + filename + "\" does not contain vertex indices!");
        }
    }

    if (!ply_read(ply)) {
        ply_close(ply);
        throw std::runtime_error("Error while loading PLY data from \"" + filename + "\"!");
    }

    ply_close(ply);
    cout << "done. (V=" << vertexCount;
    if (load_faces)
        cout << ", F=" << faceCount;
    cout << ", took " << timeString(timer.value()) << ")" << endl;
}
Example #26
0
int
main(int argc, char **argv)
{
    int nelems;
    char **elist;
    int file_type;
    float version;
    char header[MAX_HEADER_LENGTH];
    PlyFile *ply;
    char *end;
    char *progname;
    char *inName = NULL;
    FILE *inFile = stdin;

    progname = argv[0];
    argc--; 
    argv++;

    /* Print usage? */
    if (argc > 0 && !strcmp(argv[0], "-h")) {
      usage(progname);
      exit(-1);
    }

   /* optional input file (if not, read stdin ) */
   if (argc > 0 && *argv[0] != '-') {
       inName = argv[0];
       inFile = fopen(inName, "r");
       if (inFile == NULL) {
           fprintf(stderr, "Error: Couldn't open input file %s\n", inName);
           usage(progname);
	   exit(-1);
       }
       argc --;
       argv ++;
   } 

   /* Check no extra args */
   if (argc > 0) {
     fprintf(stderr, "Error: Unhandled arg: %s\n", argv[0]);
     usage(progname);
     exit(-1);
   }
   
   /* If it's a file, open it twice (first time checks it's a valid
    * ply file).  If it's on stdin, just assume valid ply file, and
    * get the header in a single pass.
    */
   if (inFile != stdin) {
     ply = ply_read(inFile, &nelems, &elist);

     if (!ply) {
       fprintf(stderr, "Not a Ply file.\n");
       exit(1);
     }

     ply_close(ply);
    
     inFile = fopen(inName, "r");
   }

    fread(header, 1, MAX_HEADER_LENGTH, inFile);
    header[MAX_HEADER_LENGTH-1] = 0;

    end = strstr(header, "end_header");

    if (end == NULL) {
	fprintf(stderr, "Did not find end of header within the first ");
	fprintf(stderr, "%d bytes of the file.\n",  MAX_HEADER_LENGTH);
	exit(1);
    }

    *(end+strlen("end_header")+1) = 0;

    printf("\n%s\n", header);
}
Example #27
0
DeformModel::DeformModel(const std::string &fname, unsigned int num_frame, float ply_scale)
{
	Init();

// 	char ply_fname[256];

	_num_frame = num_frame;
	for (unsigned int cur_f = 0; cur_f < _num_frame; cur_f++) {
        std::stringstream ply_fname;
        ply_fname << fname << cur_f << ".ply";
// 		sprintf(ply_fname, "%s%d.ply", fname, cur_f);
        std::cout << "Opening " << ply_fname.str() << std::endl;
		FILE *fp = fopen(ply_fname.str().c_str(), "rb");
		assert(fp);

		// PLY object:
		PlyFile *ply;

		// PLY properties:
		char **elist;
		int nelems;

		// hand over the stream to the ply functions:
		ply = ply_read(fp, &nelems, &elist);
		assert(ply);

		int file_type;
		float version;
		ply_get_info(ply, &version, &file_type);

		for (int i=0; i<nelems; i++) {
			char *elem_name = elist[i];

			int num_elems, nprops;
			PlyProperty **plist = ply_get_element_description(ply, elem_name, &num_elems, &nprops);

			bool has_vertex_x = false, has_vertex_y = false, has_vertex_z = false, has_colors = false;
			unsigned char color_components = 0;

			// this is a vertex:
			if (equal_strings ("vertex", elem_name)) {
				for (int j=0; j<nprops; j++)
				{
					if (equal_strings("x", plist[j]->name))
					{
						ply_get_property (ply, elem_name, &vert_props[0]);  /* x */
						has_vertex_x = true;
					}
					else if (equal_strings("y", plist[j]->name))
					{
						ply_get_property (ply, elem_name, &vert_props[1]);  /* y */
						has_vertex_y = true;
					}
					else if (equal_strings("z", plist[j]->name))
					{
						ply_get_property (ply, elem_name, &vert_props[2]);  /* z */
						has_vertex_z = true;
					}
					else if (equal_strings("red", plist[j]->name))
					{
						ply_get_property (ply, elem_name, &vert_props[3]);  /* z */
						color_components++;
					}
					else if (equal_strings("green", plist[j]->name))
					{
						ply_get_property (ply, elem_name, &vert_props[4]);  /* z */
						color_components++;
					}
					else if (equal_strings("blue", plist[j]->name))
					{
						ply_get_property (ply, elem_name, &vert_props[5]);  /* z */
						color_components++;
					}
				}

				has_colors = color_components == 3;
				// test for necessary properties
				if ((!has_vertex_x) || (!has_vertex_y) || (!has_vertex_z))
				{
					logger->update("Warning: Vertex with less than 3 coordinated detected. Output will most likely be corrupt!");
					continue;
				}

				// must be first frame, initialize structures:
				if (_num_vtx == 0) {
					_num_vtx = num_elems;
					_vtxs = new vec3f[_num_vtx*_num_frame];
					_cur_vtxs = new vec3f[_num_vtx];
					_prev_vtxs = new vec3f[_num_vtx];
					_vtx_boxes = new BOX[_num_vtx];
					_nrms = new vec3f[_num_vtx];
					_vtx_fids = new id_list[_num_vtx];
					cout << "Vtx # = " << _num_vtx << endl;

					if (has_colors)
						_colors = new color3[_num_vtx];
				}

				// grab all the vertex elements
				PLYVertex plyNewVertex;
				for (int j=0; j<num_elems; j++) {
					ply_get_element(ply, (void *)&plyNewVertex);

					if (has_colors && cur_f == 0) {
						_colors[j].set(plyNewVertex.color);
					}

					_vtxs[cur_f*_num_vtx+j] = vec3f(plyNewVertex.coords) * ply_scale;
					if (cur_f == 0) {
						_prev_vtxs[j] = _cur_vtxs[j] = _vtxs[j];
					}

					if (j != 0 && j%1000000 == 0) {
						cout << " - " << j << " of " << num_elems << " loaded." << endl;
					}
				}
			}

			// this is a face (and, hopefully, a triangle):
			else if (equal_strings ("face", elem_name) && _tris == NULL) {
				// I need this for..., otherwise error ...
				for (int j=0; j<nprops; j++)
				{
					if (equal_strings("vertex_indices", plist[j]->name))
					{
						ply_get_property (ply, elem_name, &face_props[0]);  /* vertex_indices */
					}
				}

				/* grab all the face elements */
				PLYFace plyFace;
				plyFace.other_props = NULL;

				list<edge2f> edgelist_temp;
				vector<tri3f> trilist_temp;

				for (int j = 0; j < num_elems; j++) {
					ply_get_element(ply, (void *)&plyFace);
					for (int fi = 0; fi < plyFace.nverts-2; fi++) {
						//
						// make a triangle in our format from PLY face + vertices
						//
						// copy vertex indices
						unsigned int id0, id1, id2;

						id0 = plyFace.verts[0];
						id1 = plyFace.verts[fi+1];
						id2 = plyFace.verts[fi+2];

						tri3f tri(id0, id1, id2);

						// insert triangle into list
						trilist_temp.push_back(tri);
						unsigned int fid = (unsigned int)trilist_temp.size()-1;

						edgelist_temp.push_back(edge2f(id0, id1, fid));
						edgelist_temp.push_back(edge2f(id1, id2, fid));
						edgelist_temp.push_back(edge2f(id2, id0, fid));
					}
					free(plyFace.verts);

					if (j != 0 && j%500000 == 0) {
						cout << " - " << j << " of " << num_elems << " loaded." << endl;
					}
				}

				edgelist_temp.sort();

				list<edge2f> edge_unqie;
				for (list<edge2f>::iterator it=edgelist_temp.begin(); it!=edgelist_temp.end(); it++) {
					if (!edge_unqie.empty() && *it == edge_unqie.back()) { // find duplicated with other fid
							unsigned int fid = (*it).fid(0);
							assert(fid != -1);
							edge_unqie.back().set_fid2(fid);
						} else
							edge_unqie.push_back(*it);
				}

				edgelist_temp.clear();
				vector<edge2f> edge_array;

				_num_edge = (unsigned int)edge_unqie.size();
				_edges = new edge2f[_num_edge];
				_edg_boxes = new BOX[_num_edge];

				unsigned int t=0;
				for (list<edge2f>::iterator it=edge_unqie.begin(); it != edge_unqie.end(); it++)
				{
					_edges[t++] = *it;
					edge_array.push_back(*it);
				}

				// copy over temp list to static array
				_num_tri = (unsigned int)trilist_temp.size();
				cout << "Allocating " << _num_tri*sizeof(tri3f) << " bytes of storage for triangles." << endl;
				_tris = new tri3f[_num_tri];
				_tri_nrms = new vec3f[_num_tri];
				_old_tri_nrms = NULL;

				_tri_edges = new tri3e[_num_tri];
				_fac_boxes = new BOX[_num_tri];
				_tri_flags = new char[_num_tri];

				vector <edge2f>::iterator first = edge_array.begin();
				vector <edge2f>::iterator last = edge_array.end();
				for (t = 0; t < _num_tri; t++) {
					_tris[t] = trilist_temp[t];

					vector <edge2f>::iterator it1 = lower_bound(first, last, edge2f(_tris[t].id0(), _tris[t].id1(), 0));
					vector <edge2f>::iterator it2 = lower_bound(first, last, edge2f(_tris[t].id1(), _tris[t].id2(), 0));
					vector <edge2f>::iterator it3 = lower_bound(first, last, edge2f(_tris[t].id2(), _tris[t].id0(), 0));

					_tri_edges[t].set(it1-first, it2-first, it3-first);
				}

				cout << "Edge # = " << _num_edge << endl;
				cout << "Tri # = " << _num_tri << endl;
			}

			else // otherwise: skip all further
				NULL;
		}

		// PLY parsing ended, clean up vertex buffer and close the file
// 		fclose(fp);
		ply_close(ply);
	}

	UpdateTriNorm();

	for (unsigned t = 0; t < _num_tri; t++)
		for (int i=0; i<3; i++) {
			unsigned int vid = _tris[t].id(i);
			_vtx_fids[vid].push_back(t);
		}

	BufferAdjacent();
}
Example #28
0
ExtTriangleMesh *ExtTriangleMesh::LoadExtTriangleMesh(const std::string &fileName, const bool usePlyNormals) {
	p_ply plyfile = ply_open(fileName.c_str(), NULL);
	if (!plyfile) {
		std::stringstream ss;
		ss << "Unable to read PLY mesh file '" << fileName << "'";
		throw std::runtime_error(ss.str());
	}

	if (!ply_read_header(plyfile)) {
		std::stringstream ss;
		ss << "Unable to read PLY header from '" << fileName << "'";
		throw std::runtime_error(ss.str());
	}

	Point *p;
	long plyNbVerts = ply_set_read_cb(plyfile, "vertex", "x", VertexCB, &p, 0);
	ply_set_read_cb(plyfile, "vertex", "y", VertexCB, &p, 1);
	ply_set_read_cb(plyfile, "vertex", "z", VertexCB, &p, 2);
	if (plyNbVerts <= 0) {
		std::stringstream ss;
		ss << "No vertices found in '" << fileName << "'";
		throw std::runtime_error(ss.str());
	}

	Triangle *vi;
	long plyNbTris = ply_set_read_cb(plyfile, "face", "vertex_indices", FaceCB, &vi, 0);
	if (plyNbTris <= 0) {
		std::stringstream ss;
		ss << "No triangles found in '" << fileName << "'";
		throw std::runtime_error(ss.str());
	}

	Normal *n;
	long plyNbNormals = ply_set_read_cb(plyfile, "vertex", "nx", NormalCB, &n, 0);
	ply_set_read_cb(plyfile, "vertex", "ny", NormalCB, &n, 1);
	ply_set_read_cb(plyfile, "vertex", "nz", NormalCB, &n, 2);
	if (((plyNbNormals > 0) || usePlyNormals) && (plyNbNormals != plyNbVerts)) {
		std::stringstream ss;
		ss << "Wrong count of normals in '" << fileName << "'";
		throw std::runtime_error(ss.str());
	}

	Spectrum *c;
	long plyNbColors = ply_set_read_cb(plyfile, "vertex", "red", ColorCB, &c, 0);
	ply_set_read_cb(plyfile, "vertex", "green", ColorCB, &c, 1);
	ply_set_read_cb(plyfile, "vertex", "blue", ColorCB, &c, 2);

	UV *uv;
	long plyNbUVs = ply_set_read_cb(plyfile, "vertex", "s", UVCB, &uv, 0);
	ply_set_read_cb(plyfile, "vertex", "t", UVCB, &uv, 1);

	p = new Point[plyNbVerts];
	vi = new Triangle[plyNbTris];
	if (plyNbColors == 0)
		c = NULL;
	else
		c = new Spectrum[plyNbVerts];
	n = new Normal[plyNbVerts];
	if (plyNbUVs == 0)
		uv = NULL;
	else
		uv = new UV[plyNbUVs];

	if (!ply_read(plyfile)) {
		std::stringstream ss;
		ss << "Unable to parse PLY file '" << fileName << "'";

		delete[] p;
		delete[] vi;
		delete[] c;
		delete[] n;
		delete[] uv;

		throw std::runtime_error(ss.str());
	}

	ply_close(plyfile);

	const unsigned int vertexCount = plyNbVerts;
	const unsigned int triangleCount = plyNbTris;
	Point *vertices = p;
	Triangle *triangles = vi;
	Normal *vertNormals = n;
	Spectrum *vertColors = c;
	UV *vertUV = uv;

	if (!usePlyNormals) {
		// It looks like normals exported by Blender are bugged
		for (unsigned int i = 0; i < vertexCount; ++i)
			vertNormals[i] = Normal(0.f, 0.f, 0.f);
		for (unsigned int i = 0; i < triangleCount; ++i) {
			const Vector e1 = vertices[triangles[i].v[1]] - vertices[triangles[i].v[0]];
			const Vector e2 = vertices[triangles[i].v[2]] - vertices[triangles[i].v[0]];
			const Normal N = Normal(Normalize(Cross(e1, e2)));
			vertNormals[triangles[i].v[0]] += N;
			vertNormals[triangles[i].v[1]] += N;
			vertNormals[triangles[i].v[2]] += N;
		}
		//int printedWarning = 0;
		for (unsigned int i = 0; i < vertexCount; ++i) {
			vertNormals[i] = Normalize(vertNormals[i]);
			// Check for degenerate triangles/normals, they can freeze the GPU
			if (isnan(vertNormals[i].x) || isnan(vertNormals[i].y) || isnan(vertNormals[i].z)) {
				/*if (printedWarning < 15) {
					SDL_LOG("The model contains a degenerate normal (index " << i << ")");
					++printedWarning;
				} else if (printedWarning == 15) {
					SDL_LOG("The model contains more degenerate normals");
					++printedWarning;
				}*/
				vertNormals[i] = Normal(0.f, 0.f, 1.f);
			}
		}
	}

	return new ExtTriangleMesh(vertexCount, triangleCount, vertices, triangles, vertNormals, vertColors, vertUV);
}