Skip to content

Commit

Permalink
tinyply 2.2; re-write the inner loop for performance. Updated CMake. …
Browse files Browse the repository at this point in the history
…Updated example.
  • Loading branch information
ddiakopoulos committed Aug 8, 2018
1 parent 65e39e2 commit 4e85bd7
Show file tree
Hide file tree
Showing 6 changed files with 870 additions and 773 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

project(tinyply LANGUAGES CXX)
set(PROJECT_VERSION 2.0)
set(PROJECT_VERSION 2.2)

include_directories("${CMAKE_SOURCE_DIR}/source")

set(CMAKE_DEBUG_POSTFIX "d")

# Library
set( SHARED_LIB false CACHE BOOL "Wether to build as shared library")
set( SHARED_LIB false CACHE BOOL "Build as shared library")
if(${SHARED_LIB})
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_library(tinyply SHARED source/tinyply.cpp source/tinyply.h)
Expand Down
14 changes: 9 additions & 5 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
# tinyply 2.0
# tinyply 2.2

[![Release is 2.0](http://img.shields.io/badge/release-2.0-blue.svg?style=flat)](https://raw.githubusercontent.com/ddiakopoulos/tinyply/master/source/tinyply.h)
[![Release is 2.2](http://img.shields.io/badge/release-2.2-blue.svg?style=flat)](https://raw.githubusercontent.com/ddiakopoulos/tinyply/master/source/tinyply.h)
[![License is Unlicense](http://img.shields.io/badge/license-Unlicense-blue.svg?style=flat)](http://unlicense.org/)

Platform | Build Status |
-------- | ------------ |
GCC 4.9 and Clang 3.7 | [Travis CI](http://travis-ci.org): [![Build status](http://travis-ci.org/ddiakopoulos/tinyply.svg?branch=master)](https://travis-ci.org/ddiakopoulos/tinyply) |

A two-file, zero-dependency (except the C++ STL) public domain implementation of the PLY mesh file format. An overview and definition of the file format is available [here](http://paulbourke.net/dataformats/ply/). This format is often used in the computer vision community for its relative simplicity and ability to support arbitrary mesh attributes and layouts.
A two-file, zero-dependency (except the C++ STL) public domain implementation of the PLY mesh file format. An overview and definition of the file format is available [here](http://paulbourke.net/dataformats/ply/). This format is often used in the computer vision and graphics communities for its relative simplicity, ability to support arbitrary mesh attributes, and binary modes.

The library is written in C++11 and requires a recent compiler (GCC 4.8+ / VS2013+ / Clang 2.9+). Tinyply supports exporting and importing PLY files in both binary and ascii formats. Recently, `tinyply` was modified to support filesizes >= 4gb and read big-endian binary formats. The library does not directly perform file i/o for either reading or writing.
The library is written in C++11 and requires a recent compiler (GCC 4.8+ / VS2013+ / Clang 2.9+). Tinyply supports exporting and importing PLY files in both binary and ascii formats. Recently, `tinyply` was modified to support filesizes >= 4gb and to read big-endian binary formats.

Version 2.0 is mostly an API re-write, although various bits of the implementation have been changed. In fact, the changes reduce the overall speed of the library around 5%, although at much greater flexibility for further improvements to support variable length lists. One notable change is that tinyply now produces and consumes untyped byte buffers, with type information held as metadata.
Version 2.0 is mostly an API re-write to support later improvements towards variable length lists. One notable change is that tinyply now produces and consumes untyped byte buffers, with type information held as metadata.

Version 2.1 contained minor bugfixes and speed improvements.

Version 2.2 is a rewrite of the inner read/write loop. Compared to tinyply 2.0, this version reads and writes binary about five times faster. When a list size hint is given for reading, the performance is approximately comparable to rply.

## Getting Started

Expand Down
1 change: 1 addition & 0 deletions source/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ tinyply-core: tinyply.h tinyply.cpp example.cpp
.PHONY: clean
clean:
rm tinyply-core

175 changes: 90 additions & 85 deletions source/example.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// This software is in the public domain. Where that dedication is not
// recognized, you are granted a perpetual, irrevocable license to copy,
// distribute, and modify this file as you see fit.
// Authored in 2015 by Dimitri Diakopoulos (http://www.dimitridiakopoulos.com)
// https://github.com/ddiakopoulos/tinyply
// Version 2.1
// Version 2.2

#include <thread>
#include <chrono>
Expand All @@ -12,9 +11,9 @@
#include <fstream>
#include <iostream>
#include <cstring>
#include <iterator>

#include "tinyply.h"

using namespace tinyply;

class manual_timer
Expand Down Expand Up @@ -75,10 +74,15 @@ void write_ply_example(const std::string & filename)
{
geometry cube = make_cube_geometry();

std::filebuf fb;
fb.open(filename, std::ios::out | std::ios::binary);
std::ostream outstream(&fb);
if (outstream.fail()) throw std::runtime_error("failed to open " + filename);
std::filebuf fb_binary;
fb_binary.open(filename + "-binary.ply", std::ios::out | std::ios::binary);
std::ostream outstream_binary(&fb_binary);
if (outstream_binary.fail()) throw std::runtime_error("failed to open " + filename);

std::filebuf fb_ascii;
fb_ascii.open(filename + "-ascii.ply", std::ios::out);
std::ostream outstream_ascii(&fb_ascii);
if (outstream_ascii.fail()) throw std::runtime_error("failed to open " + filename);

PlyFile cube_file;

Expand All @@ -94,91 +98,92 @@ void write_ply_example(const std::string & filename)
cube_file.add_properties_to_element("face", { "vertex_indices" },
Type::UINT32, cube.triangles.size(), reinterpret_cast<uint8_t*>(cube.triangles.data()), Type::UINT8, 3);

cube_file.get_comments().push_back("generated by tinyply");
cube_file.get_comments().push_back("generated by tinyply 2.2");

cube_file.write(outstream, false); // write ascii
// Write an ASCII file
cube_file.write(outstream_ascii, false);

fb.close();
// Write a binary file
cube_file.write(outstream_binary, true);
}

void read_ply_file(const std::string & filename)
void read_ply_file(const std::string & filepath)
{
try
{
// Read the file and create a std::istringstream suitable
// for the lib -- tinyply does not perform any file i/o.
std::ifstream ss(filename, std::ios::binary);

if (ss.fail()) throw std::runtime_error("failed to open " + filename);

PlyFile file;
file.parse_header(ss);

std::cout << "........................................................................\n";
for (auto c : file.get_comments()) std::cout << "Comment: " << c << std::endl;
for (auto e : file.get_elements())
{
std::cout << "element - " << e.name << " (" << e.size << ")" << std::endl;
for (auto p : e.properties) std::cout << "\tproperty - " << p.name << " (" << tinyply::PropertyTable[p.propertyType].str << ")" << std::endl;
}
std::cout << "........................................................................\n";

// Tinyply 2.0 treats incoming data as untyped byte buffers. It's now
// up to users to treat this data as they wish. See below for examples.
std::shared_ptr<PlyData> vertices, normals, faces, texcoords;

// The header information can be used to programmatically extract properties on elements
// known to exist in the file header prior to reading the data. For brevity of this sample, properties
// like vertex position are hard-coded:
try { vertices = file.request_properties_from_element("vertex", { "x", "y", "z" }); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }

try { normals = file.request_properties_from_element("vertex", { "nx", "ny", "nz" }); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }

try { texcoords = file.request_properties_from_element("vertex", { "u", "v" }); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }

try { faces = file.request_properties_from_element("face", { "vertex_indices" }); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }

manual_timer read_timer;

read_timer.start();
file.read(ss);
read_timer.stop();

std::cout << "Parsing took " << read_timer.get() / 1000.f << " seconds: " << std::endl;
if (vertices) std::cout << "\tRead " << vertices->count << " total vertices "<< std::endl;
if (normals) std::cout << "\tRead " << normals->count << " total vertex normals " << std::endl;
if (texcoords) std::cout << "\tRead " << texcoords->count << " total vertex texcoords " << std::endl;
if (faces) std::cout << "\tRead " << faces->count << " total faces (triangles) " << std::endl;

// Example: type 'conversion' to your own native types - Option A
{
const size_t numVerticesBytes = vertices->buffer.size_bytes();
std::vector<float3> verts(vertices->count);
std::memcpy(verts.data(), vertices->buffer.get(), numVerticesBytes);
}

// Example: type 'conversion' to your own native types - Option B
{
const size_t numVerticesBytes = vertices->buffer.size_bytes();
std::vector<float3> verts_floats;
std::vector<double3> verts_doubles;
if (vertices->t == tinyply::Type::FLOAT32) { /* as floats ... */ }
if (vertices->t == tinyply::Type::FLOAT64) { /* as doubles ... */ }
}
}
catch (const std::exception & e)
{
std::cerr << "Caught tinyply exception: " << e.what() << std::endl;
}
try
{
std::ifstream ss(filepath, std::ios::binary);
if (ss.fail()) throw std::runtime_error("failed to open " + filepath);

PlyFile file;
file.parse_header(ss);

std::cout << "........................................................................\n";
for (auto c : file.get_comments()) std::cout << "Comment: " << c << std::endl;
for (auto e : file.get_elements())
{
std::cout << "element - " << e.name << " (" << e.size << ")" << std::endl;
for (auto p : e.properties) std::cout << "\tproperty - " << p.name << " (" << tinyply::PropertyTable[p.propertyType].str << ")" << std::endl;
}
std::cout << "........................................................................\n";

// Tinyply treats parsed data as untyped byte buffers. See below for examples.
std::shared_ptr<PlyData> vertices, normals, faces, texcoords;

// The header information can be used to programmatically extract properties on elements
// known to exist in the header prior to reading the data. For brevity of this sample, properties
// like vertex position are hard-coded:
try { vertices = file.request_properties_from_element("vertex", { "x", "y", "z" }); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }

try { normals = file.request_properties_from_element("vertex", { "nx", "ny", "nz" }); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }

try { texcoords = file.request_properties_from_element("vertex", { "u", "v" }); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }

// Providing a list size hint (the last argument) is a 2x performance improvement. If you have
// arbitrary ply files, it is best to leave this 0.
try { faces = file.request_properties_from_element("face", { "vertex_indices" }, 3); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }

manual_timer read_timer;

read_timer.start();
file.read(ss);
read_timer.stop();

std::cout << "Reading took " << read_timer.get() / 1000.f << " seconds." << std::endl;
if (vertices) std::cout << "\tRead " << vertices->count << " total vertices "<< std::endl;
if (normals) std::cout << "\tRead " << normals->count << " total vertex normals " << std::endl;
if (texcoords) std::cout << "\tRead " << texcoords->count << " total vertex texcoords " << std::endl;
if (faces) std::cout << "\tRead " << faces->count << " total faces (triangles) " << std::endl;

// type casting to your own native types - Option A
{
const size_t numVerticesBytes = vertices->buffer.size_bytes();
std::vector<float3> verts(vertices->count);
std::memcpy(verts.data(), vertices->buffer.get(), numVerticesBytes);
}

// type casting to your own native types - Option B
{
const size_t numVerticesBytes = vertices->buffer.size_bytes();
std::vector<float3> verts_floats;
std::vector<double3> verts_doubles;
if (vertices->t == tinyply::Type::FLOAT32) { /* as floats ... */ }
if (vertices->t == tinyply::Type::FLOAT64) { /* as doubles ... */ }
}
}
catch (const std::exception & e)
{
std::cerr << "Caught tinyply exception: " << e.what() << std::endl;
}
}

int main(int argc, char *argv[])
{
write_ply_example("example_cube.ply");
read_ply_file("example_cube.ply");
return 0;
write_ply_example("example_cube");
//read_ply_file("example_cube-ascii.ply");
//read_ply_file("example_cube-binary.ply");
return EXIT_SUCCESS;
}
Loading

0 comments on commit 4e85bd7

Please sign in to comment.