1#include <IO/TinyPlyLoader/TinyPlyFileLoader.hpp>
3#include <Core/Asset/FileData.hpp>
4#include <Core/Containers/VectorArray.hpp>
5#include <Core/Geometry/StandardAttribNames.hpp>
6#include <Core/Utils/Attribs.hpp>
19using namespace Core::Utils;
20using namespace Core::Asset;
22TinyPlyFileLoader::TinyPlyFileLoader() {}
24TinyPlyFileLoader::~TinyPlyFileLoader() {}
30bool TinyPlyFileLoader::handleFileExtension(
const std::string& extension )
const {
31 return extension.
compare( plyExt ) == 0;
36 char* p_start {
nullptr };
37 char* p_end {
nullptr };
40 memory_buffer(
char const* first_elem,
size_t size_ ) :
41 p_start( const_cast<char*>( first_elem ) ), p_end( p_start + size_ ), size( size_ ) {
42 setg( p_start, p_start, p_end );
45 pos_type seekoff( off_type off, std::ios_base::seekdir dir, std::ios_base::openmode )
override {
46 if ( dir == std::ios_base::cur )
47 gbump(
static_cast<int>( off ) );
49 setg( p_start, ( dir == std::ios_base::beg ? p_start : p_end ) + off, p_end );
50 return gptr() - p_start;
53 pos_type seekpos( pos_type pos, std::ios_base::openmode which )
override {
54 return seekoff( pos, std::ios_base::beg, which );
62 if ( file.is_open() ) {
63 file.seekg( 0, std::ios::end );
64 size_t sizeBytes = file.tellg();
65 file.seekg( 0, std::ios::beg );
66 fileBufferBytes.
resize( sizeBytes );
67 if ( file.read( (
char*)fileBufferBytes.
data(), sizeBytes ) )
return fileBufferBytes;
71 return fileBufferBytes;
74struct memory_stream :
virtual memory_buffer,
public std::istream {
75 memory_stream(
char const* first_elem,
size_t size_ ) :
79template <
typename DataType>
80void copyArrayToContainer(
const uint8_t* buffer,
83 auto data =
reinterpret_cast<const DataType*
>( buffer );
85 for (
size_t i = 0; i <
count; ++i ) {
90template <
typename DataType>
91void copyArrayToContainer(
const uint8_t* buffer,
92 Ra::Core::Vector3Array& container,
94 auto data =
reinterpret_cast<const DataType*
>( buffer );
95 container.reserve( count );
96 for (
size_t i = 0; i <
count; ++i ) {
97 container.emplace_back( data[i * 3 + 0], data[i * 3 + 1], data[i * 3 + 2] );
101template <
typename ContainerType>
103 ContainerType& container ) {
104 if ( buffer && buffer->count != 0 ) {
105 switch ( buffer->t ) {
106 case tinyply::Type::FLOAT32: {
107 copyArrayToContainer<float>( buffer->buffer.get(), container, buffer->count );
109 case tinyply::Type::FLOAT64: {
110 copyArrayToContainer<double>( buffer->buffer.get(), container, buffer->count );
113 LOG( logWARNING ) <<
"[TinyPLY] copyBufferToContainer - unsupported buffer type ..."
114 << tinyply::PropertyTable[buffer->t].str;
119FileData* TinyPlyFileLoader::loadFile(
const std::string& filename ) {
127 const bool preload_into_memory =
true;
128 if ( preload_into_memory ) {
129 byte_buffer = read_file_binary( filename );
130 file_stream.
reset(
new memory_stream( (
char*)byte_buffer.
data(), byte_buffer.
size() ) );
134 if ( !file_stream || file_stream->fail() ) {
135 LOG( logINFO ) <<
"[TinyPLY] Could not open file [" << filename <<
"] Aborting"
141 tinyply::PlyFile file;
142 file.parse_header( *file_stream );
144 auto elements = file.get_elements();
145 if (
std::any_of( elements.begin(), elements.end(), [](
const auto& e ) ->
bool {
146 return e.name ==
"face" && e.size != 0;
149 LOG( logINFO ) <<
"[TinyPLY] Faces found. Aborting" <<
std::endl;
154 FileData* fileData =
new FileData( filename );
155 fileData->setVerbose(
true );
157 if ( !fileData->isInitialized() ) {
159 LOG( logINFO ) <<
"[TinyPLY] Filedata cannot be initialized...";
163 if ( fileData->isVerbose() ) {
164 LOG( logINFO ) <<
"[TinyPLY] File Loading begin...";
165 LOG( logINFO ) <<
"....................................................................";
166 for (
auto c : file.get_comments() )
167 LOG( logINFO ) <<
"Comment: " << c;
168 for (
auto e : file.get_elements() ) {
169 LOG( logINFO ) <<
"element - " << e.name <<
" (" << e.size <<
")";
170 for (
auto p : e.properties )
171 LOG( logINFO ) <<
"\tproperty - " << p.name <<
" ("
172 << tinyply::PropertyTable[p.propertyType].str <<
")";
174 LOG( logINFO ) <<
"....................................................................";
177 auto initBuffer = [&file](
const std::string& elementKey,
181 ret = file.request_properties_from_element( elementKey, propertyKeys );
185 LOG( logINFO ) <<
"[TinyPLY] " << e.what();
193 static int nameId { 0 };
194 auto geomData = std::make_unique<GeometryData>(
"PC_" +
std::to_string( ++nameId ),
195 GeometryData::POINT_CLOUD );
196 geomData->setFrame( Core::Transform::Identity() );
199 auto vertBuffer { initBuffer(
"vertex", {
"x",
"y",
"z" } ) };
201 if ( !vertBuffer || vertBuffer->count == 0 ) {
203 LOG( logINFO ) <<
"[TinyPLY] No vertex found";
208 auto normalBuffer { initBuffer(
"vertex", {
"nx",
"ny",
"nz" } ) };
209 auto alphaBuffer { initBuffer(
"vertex", {
"alpha" } ) };
210 auto colorBuffer { initBuffer(
"vertex", {
"red",
"green",
"blue" } ) };
215 "x",
"y",
"z",
"nx",
"ny",
"nz",
"alpha",
"red",
"green",
"blue" };
216 for (
const auto& e : file.get_elements() ) {
217 if ( e.name ==
"vertex" ) {
218 for (
const auto& p : e.properties ) {
219 bool exists = usedAttributes.find( p.name ) != usedAttributes.end();
221 allAttributes.
emplace_back( p.name, initBuffer(
"vertex", { p.name } ) );
229 file.read( *file_stream );
231 auto unlocker = geomData->getGeometry().vertexAttribs().getScopedLockState();
232 copyBufferToContainer( vertBuffer, geomData->getGeometry().verticesWithLock() );
233 copyBufferToContainer( normalBuffer, geomData->getGeometry().normalsWithLock() );
236 auto& vertexAttribs = geomData->getGeometry().vertexAttribs();
238 size_t colorCount = colorBuffer ? colorBuffer->
count : 0;
239 if ( colorCount != 0 ) {
240 auto handle = vertexAttribs.addAttrib<Core::Vector4>(
241 Ra::Core::Geometry::getAttribName( Ra::Core::Geometry::MeshAttrib::VERTEX_COLOR ) );
242 auto& container = vertexAttribs.getDataWithLock( handle );
244 if ( alphaBuffer && alphaBuffer->count == colorCount ) {
245 uint8_t* al = alphaBuffer->buffer.get();
246 uint8_t* colors = colorBuffer->buffer.get();
247 for (
size_t i = 0; i < colorCount; ++i, al++, colors += 3 ) {
248 container.emplace_back( Scalar( colors[0] ) / 255_ra,
249 Scalar( colors[1] ) / 255_ra,
250 Scalar( colors[2] ) / 255_ra,
251 Scalar( *al ) / 255_ra );
255 uint8_t* colors = colorBuffer->buffer.get();
256 for (
size_t i = 0; i < colorCount; ++i, colors += 3 ) {
257 container.emplace_back( Scalar( colors[0] ) / 255_ra,
258 Scalar( colors[1] ) / 255_ra,
259 Scalar( colors[2] ) / 255_ra,
263 vertexAttribs.unlock( handle );
267 for (
const auto& a : allAttributes ) {
269 if ( a.second->isList ) {
270 LOG( logWARNING ) <<
"[TinyPLY] unmanaged vector attribute " << a.first;
274 auto attribName { a.first };
275 std::replace( attribName.begin(), attribName.end(),
'-',
'_' );
276 LOG( logINFO ) <<
"[TinyPLY] Adding custom attrib with name " << attribName <<
" (was "
278 auto handle = vertexAttribs.addAttrib<Scalar>( attribName );
279 auto& container = vertexAttribs.getDataWithLock( handle );
280 copyBufferToContainer( a.second, container );
281 vertexAttribs.unlock( handle );
284 fileData->m_geometryData.clear();
285 fileData->m_geometryData.reserve( 1 );
286 fileData->m_geometryData.push_back(
std::move( geomData ) );
288 fileData->m_loadingTime = (
std::clock() - startTime ) / Scalar( CLOCKS_PER_SEC );
290 if ( fileData->isVerbose() ) {
291 LOG( logINFO ) <<
"[TinyPLY] File Loading end.";
292 fileData->displayInfo();
295 fileData->m_processed =
true;
T emplace_back(T... args)
hepler function to manage enum as underlying types in VariableSet