Implemented feedback from Hans and Aras #2

Merged
Nathan Rozendaal merged 1 commits from super_jo_nathan-patch-1 into D16792 2023-02-27 19:01:37 +01:00
21 changed files with 312 additions and 305 deletions

View File

@ -77,7 +77,7 @@ static void ui_ply_export_settings(uiLayout *layout, PointerRNA *imfptr)
uiLayoutSetPropSep(layout, true); uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false); uiLayoutSetPropDecorate(layout, false);
uiLayout *box, *col, *sub, *row; uiLayout *box, *col, *sub;
/* Object Transform options. */ /* Object Transform options. */
box = uiLayoutBox(layout); box = uiLayoutBox(layout);
@ -88,10 +88,8 @@ static void ui_ply_export_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE); uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE);
uiItemR(sub, imfptr, "global_scale", 0, NULL, ICON_NONE); uiItemR(sub, imfptr, "global_scale", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false); uiItemR(sub, imfptr, "forward_axis", 0, IFACE_("Forward Axis"), ICON_NONE);
uiItemR(row, imfptr, "forward_axis", 0, IFACE_("Forward Axis"), ICON_NONE); uiItemR(sub, imfptr, "up_axis", 0, IFACE_("Up Axis"), ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "up_axis", 0, IFACE_("Up Axis"), ICON_NONE);
col = uiLayoutColumn(box, false); col = uiLayoutColumn(box, false);
sub = uiLayoutColumn(col, false); sub = uiLayoutColumn(col, false);

View File

@ -23,29 +23,33 @@ set(INC_SYS
) )
set(SRC set(SRC
IO_ply.cc
exporter/ply_export.cc
importer/ply_import.cc
importer/ply_import_binary.cc
importer/ply_import_ascii.cc
importer/ply_import_mesh.cc
exporter/ply_export_header.cc
exporter/ply_export_data.cc exporter/ply_export_data.cc
exporter/ply_export_header.cc
exporter/ply_export_load_plydata.cc exporter/ply_export_load_plydata.cc
exporter/ply_export.cc
exporter/ply_file_buffer_ascii.cc
exporter/ply_file_buffer_binary.cc
exporter/ply_file_buffer.cc
importer/ply_import_ascii.cc
importer/ply_import_binary.cc
importer/ply_import_mesh.cc
importer/ply_import.cc
IO_ply.cc
IO_ply.h
exporter/ply_export.hh
exporter/ply_export_header.hh
exporter/ply_export_data.hh exporter/ply_export_data.hh
exporter/ply_export_header.hh
exporter/ply_export_load_plydata.hh
exporter/ply_export.hh
exporter/ply_file_buffer_ascii.hh exporter/ply_file_buffer_ascii.hh
exporter/ply_file_buffer_binary.hh exporter/ply_file_buffer_binary.hh
exporter/ply_export_load_plydata.hh exporter/ply_file_buffer.hh
importer/ply_import.hh
importer/ply_import_binary.hh
importer/ply_import_ascii.hh importer/ply_import_ascii.hh
importer/ply_import_binary.hh
importer/ply_import_mesh.hh importer/ply_import_mesh.hh
importer/ply_import.hh
IO_ply.h
intern/ply_data.hh intern/ply_data.hh
intern/ply_functions.hh intern/ply_functions.hh

View File

@ -35,11 +35,9 @@ void exporter_main(Main *bmain,
bContext *C, bContext *C,
const PLYExportParams &export_params) const PLYExportParams &export_params)
{ {
/* Load mesh data into PlyData struct. */
std::unique_ptr<blender::io::ply::PlyData> plyData = std::make_unique<PlyData>(); std::unique_ptr<blender::io::ply::PlyData> plyData = std::make_unique<PlyData>();
load_plydata(*plyData, CTX_data_ensure_evaluated_depsgraph(C), export_params); load_plydata(*plyData, CTX_data_ensure_evaluated_depsgraph(C), export_params);
/* Get filebuffer. */
std::unique_ptr<FileBuffer> buffer; std::unique_ptr<FileBuffer> buffer;
if (export_params.ascii_format) { if (export_params.ascii_format) {
@ -49,19 +47,14 @@ void exporter_main(Main *bmain,
buffer = std::make_unique<FileBufferBinary>(export_params.filepath); buffer = std::make_unique<FileBufferBinary>(export_params.filepath);
} }
/* Generate and write header. */
write_header(*buffer.get(), *plyData.get(), export_params); write_header(*buffer.get(), *plyData.get(), export_params);
/* Generate and write vertices. */
write_vertices(*buffer.get(), *plyData.get()); write_vertices(*buffer.get(), *plyData.get());
/* Generate and write faces. */
write_faces(*buffer.get(), *plyData.get()); write_faces(*buffer.get(), *plyData.get());
/* Generate and write edges. */
write_edges(*buffer.get(), *plyData.get()); write_edges(*buffer.get(), *plyData.get());
/* Clean up. */
buffer->close_file(); buffer->close_file();
} }
} // namespace blender::io::ply } // namespace blender::io::ply

View File

@ -174,7 +174,7 @@ void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams
const Span<float3> vert_normals = mesh->vertex_normals(); const Span<float3> vert_normals = mesh->vertex_normals();
for (int i = 0; i < vertex_map.size(); i++) { for (int i = 0; i < vertex_map.size(); i++) {
mul_m3_v3(world_and_axes_normal_transform_, mul_m3_v3(world_and_axes_normal_transform_,
(float3)vert_normals[mesh_vertex_index_LUT[i]]); float3(vert_normals[mesh_vertex_index_LUT[i]]));
plyData.vertex_normals.append(vert_normals[mesh_vertex_index_LUT[i]]); plyData.vertex_normals.append(vert_normals[mesh_vertex_index_LUT[i]]);
} }
} }

View File

@ -0,0 +1,82 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup ply
*/
#include "ply_file_buffer.hh"
namespace blender::io::ply {
FileBuffer::FileBuffer(const char *filepath, size_t buffer_chunk_size)
: buffer_chunk_size_(buffer_chunk_size), filepath_(filepath)
{
outfile_ = BLI_fopen(filepath, "wb");
if (!outfile_) {
throw std::system_error(
errno, std::system_category(), "Cannot open file " + std::string(filepath) + ".");
}
}
void FileBuffer::write_to_file()
{
for (const VectorChar &b : blocks_)
fwrite(b.data(), 1, b.size(), this->outfile_);
blocks_.clear();
}
void FileBuffer::close_file()
{
int close_status = std::fclose(outfile_);
if (close_status == EOF) {
return;
}
if (outfile_ && close_status) {
std::cerr << "Error: could not close the file '" << this->filepath_
<< "' properly, it may be corrupted." << std::endl;
}
}
void FileBuffer::write_header_element(StringRef name, int count)
{
write_fstring("element {} {}\n", name, count);
}
void FileBuffer::write_header_scalar_property(StringRef dataType, StringRef name)
{
write_fstring("property {} {}\n", dataType, name);
}
void FileBuffer::write_header_list_property(StringRef countType,
StringRef dataType,
StringRef name)
{
write_fstring("property list {} {} {}\n", countType, dataType, name);
}
void FileBuffer::write_string(StringRef s)
{
write_fstring("{}\n", s);
}
void FileBuffer::write_newline()
{
write_fstring("\n");
}
void FileBuffer::ensure_space(size_t at_least)
{
if (blocks_.is_empty() || (blocks_.last().capacity() - blocks_.last().size() < at_least)) {
blocks_.append(VectorChar());
blocks_.reserve(std::max(at_least, buffer_chunk_size_));
}
}
void FileBuffer::write_bytes(Span<char> bytes)
{
ensure_space(bytes.size());
VectorChar &bb = blocks_.last();
bb.insert(bb.end(), bytes.begin(), bytes.end());
}
} // namespace blender::io::ply

View File

@ -28,11 +28,10 @@ namespace blender::io::ply {
* File buffer writer. * File buffer writer.
* All writes are done into an internal chunked memory buffer * All writes are done into an internal chunked memory buffer
* (list of default 64 kilobyte blocks). * (list of default 64 kilobyte blocks).
* Call write_fo_file once in a while to write the memory buffer(s) * Call write_to_file once in a while to write the memory buffer(s)
* into the given file. * into the given file.
*/ */
class FileBuffer : private NonMovable { class FileBuffer : private NonMovable {
private:
using VectorChar = Vector<char>; using VectorChar = Vector<char>;
Vector<VectorChar> blocks_; Vector<VectorChar> blocks_;
size_t buffer_chunk_size_; size_t buffer_chunk_size_;
@ -40,57 +39,14 @@ class FileBuffer : private NonMovable {
FILE *outfile_; FILE *outfile_;
public: public:
FileBuffer(const char *filepath, size_t buffer_chunk_size = 64 * 1024) FileBuffer(const char *filepath, size_t buffer_chunk_size = 64 * 1024);
: buffer_chunk_size_(buffer_chunk_size), filepath_(filepath)
{
outfile_ = BLI_fopen(filepath, "wb");
if (!outfile_) {
throw std::system_error(
errno, std::system_category(), "Cannot open file " + std::string(filepath) + ".");
}
}
virtual ~FileBuffer() = default; virtual ~FileBuffer() = default;
/* Write contents to the buffer(s) into a file, and clear the buffers. */ /* Write contents to the buffer(s) into a file, and clear the buffers. */
void write_to_file() void write_to_file();
{
for (const auto &b : blocks_)
fwrite(b.data(), 1, b.size(), this->outfile_);
blocks_.clear();
}
void close_file() void close_file();
{
auto close_status = std::fclose(outfile_);
if (close_status == EOF) {
return;
}
if (outfile_ && close_status) {
std::cerr << "Error: could not close the file '" << this->filepath_
<< "' properly, it may be corrupted." << std::endl;
}
}
std::string get_as_string() const
{
std::string s;
for (const auto &b : blocks_)
s.append(b.data(), b.size());
return s;
}
size_t get_block_count() const
{
return blocks_.size();
}
void append_from(FileBuffer &v)
{
blocks_.insert(blocks_.end(),
std::make_move_iterator(v.blocks_.begin()),
std::make_move_iterator(v.blocks_.end()));
v.blocks_.clear();
}
virtual void write_vertex(float x, float y, float z) = 0; virtual void write_vertex(float x, float y, float z) = 0;
@ -106,41 +62,20 @@ class FileBuffer : private NonMovable {
virtual void write_edge(int first, int second) = 0; virtual void write_edge(int first, int second) = 0;
void write_header_element(StringRef name, int count) void write_header_element(StringRef name, int count);
{
write_fstring("element {} {}\n", name, count);
}
void write_header_scalar_property(StringRef dataType, StringRef name)
{
write_fstring("property {} {}\n", dataType, name);
}
void write_header_list_property(StringRef countType, StringRef dataType, StringRef name) void write_header_scalar_property(StringRef dataType, StringRef name);
{
write_fstring("property list {} {} {}\n", countType, dataType, name);
}
void write_string(StringRef s) void write_header_list_property(StringRef countType, StringRef dataType, StringRef name);
{
write_fstring("{}\n", s);
}
void write_newline() void write_string(StringRef s);
{
write_fstring("\n"); void write_newline();
}
protected: protected:
/* Ensure the last block contains at least this amount of free space. /* Ensure the last block contains at least this amount of free space.
* If not, add a new block with max of block size & the amount of space needed. */ * If not, add a new block with max of block size & the amount of space needed. */
void ensure_space(size_t at_least) void ensure_space(size_t at_least);
{
if (blocks_.is_empty() || (blocks_.last().capacity() - blocks_.last().size() < at_least)) {
blocks_.append(VectorChar());
blocks_.reserve(std::max(at_least, buffer_chunk_size_));
}
}
template<typename... T> void write_fstring(const char *fmt, T &&...args) template<typename... T> void write_fstring(const char *fmt, T &&...args)
{ {
@ -153,12 +88,7 @@ class FileBuffer : private NonMovable {
bb.insert(bb.end(), buf.begin(), buf.end()); bb.insert(bb.end(), buf.begin(), buf.end());
} }
void write_bytes(Span<char> bytes) void write_bytes(Span<char> bytes);
{
ensure_space(bytes.size());
VectorChar &bb = blocks_.last();
bb.insert(bb.end(), bytes.begin(), bytes.end());
}
}; };
} // namespace blender::io::ply } // namespace blender::io::ply

View File

@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup ply
*/
#include "ply_file_buffer_ascii.hh"
namespace blender::io::ply {
void FileBufferAscii::write_vertex(float x, float y, float z)
{
write_fstring("{} {} {}", x, y, z);
}
void FileBufferAscii::write_UV(float u, float v)
{
write_fstring(" {} {}", u, v);
}
void FileBufferAscii::write_vertex_normal(float nx, float ny, float nz)
{
write_fstring(" {} {} {}", nx, ny, nz);
}
void FileBufferAscii::write_vertex_color(uchar r, uchar g, uchar b, uchar a)
{
write_fstring(" {} {} {} {}", r, g, b, a);
}
void FileBufferAscii::write_vertex_end()
{
write_fstring("\n");
}
void FileBufferAscii::write_face(char count, Array<uint32_t> const &vertex_indices)
{
write_fstring("{}", int(count));
for (const uint32_t v : vertex_indices) {
write_fstring(" {}", v);
}
write_newline();
}
void FileBufferAscii::write_edge(int first, int second)
{
write_fstring("{} {}", first, second);
write_newline();
}
} // namespace blender::io::ply

View File

@ -6,65 +6,25 @@
#pragma once #pragma once
#include <string>
#include <type_traits>
#include "BLI_array.hh"
#include "BLI_compiler_attrs.h"
#include "BLI_fileops.h"
#include "BLI_string_ref.hh"
#include "BLI_utility_mixins.hh"
#include "ply_file_buffer.hh" #include "ply_file_buffer.hh"
/* SEP macro from BLI path utils clashes with SEP symbol in fmt headers. */
#undef SEP
#define FMT_HEADER_ONLY
#include <fmt/format.h>
namespace blender::io::ply { namespace blender::io::ply {
class FileBufferAscii : public FileBuffer { class FileBufferAscii : public FileBuffer {
public:
using FileBuffer::FileBuffer; using FileBuffer::FileBuffer;
void write_vertex(float x, float y, float z) override public:
{ void write_vertex(float x, float y, float z) override;
write_fstring("{} {} {}", x, y, z);
}
void write_UV(float u, float v) override void write_UV(float u, float v) override;
{
write_fstring(" {} {}", u, v);
}
void write_vertex_normal(float nx, float ny, float nz) override void write_vertex_normal(float nx, float ny, float nz) override;
{
write_fstring(" {} {} {}", nx, ny, nz);
}
void write_vertex_color(uchar r, uchar g, uchar b, uchar a) override void write_vertex_color(uchar r, uchar g, uchar b, uchar a) override;
{
write_fstring(" {} {} {} {}", r, g, b, a);
}
void write_vertex_end() override void write_vertex_end() override;
{
write_fstring("\n");
}
void write_face(char count, Array<uint32_t> const &vertex_indices) override void write_face(char count, Array<uint32_t> const &vertex_indices) override;
{
write_fstring("{}", int(count));
for (auto &&v : vertex_indices) { void write_edge(int first, int second) override;
write_fstring(" {}", v);
}
write_newline();
}
void write_edge(int first, int second) override
{
write_fstring("{} {}", first, second);
write_newline();
}
}; };
} // namespace blender::io::ply } // namespace blender::io::ply

View File

@ -0,0 +1,68 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup ply
*/
#include "ply_file_buffer_binary.hh"
namespace blender::io::ply {
void FileBufferBinary::write_vertex(float x, float y, float z)
{
float3 vector(x, y, z);
char *bits = reinterpret_cast<char *>(&vector);
Span<char> span(bits, sizeof(float3));
write_bytes(span);
}
void FileBufferBinary::write_UV(float u, float v)
{
float2 vector(u, v);
char *bits = reinterpret_cast<char *>(&vector);
Span<char> span(bits, sizeof(float2));
write_bytes(span);
}
void FileBufferBinary::write_vertex_normal(float nx, float ny, float nz)
{
float3 vector(nx, ny, nz);
char *bits = reinterpret_cast<char *>(&vector);
Span<char> span(bits, sizeof(float3));
write_bytes(span);
}
void FileBufferBinary::write_vertex_color(uchar r, uchar g, uchar b, uchar a)
{
uchar4 vector(r, g, b, a);
char *bits = reinterpret_cast<char *>(&vector);
Span<char> span(bits, sizeof(uchar4));
write_bytes(span);
}
void FileBufferBinary::write_vertex_end()
{
/* In binary, there is no end to a vertex. */
}
void FileBufferBinary::write_face(char size, Array<uint32_t> const &vertex_indices)
{
write_bytes(Span<char>({size}));
Span<char> dataSpan(reinterpret_cast<const char *>(vertex_indices.data()),
vertex_indices.size() * sizeof(uint32_t));
write_bytes(dataSpan);
}
void FileBufferBinary::write_edge(int first, int second)
{
int2 vector(first, second);
char *bits = reinterpret_cast<char *>(&vector);
Span<char> span(bits, sizeof(int2));
write_bytes(span);
}
} // namespace blender::io::ply

View File

@ -18,74 +18,25 @@
#include "ply_file_buffer.hh" #include "ply_file_buffer.hh"
/* SEP macro from BLI path utils clashes with SEP symbol in fmt headers. */
#undef SEP
#define FMT_HEADER_ONLY
#include <bitset> #include <bitset>
#include <fmt/format.h>
namespace blender::io::ply { namespace blender::io::ply {
class FileBufferBinary : public FileBuffer { class FileBufferBinary : public FileBuffer {
public:
using FileBuffer::FileBuffer; using FileBuffer::FileBuffer;
void write_vertex(float x, float y, float z) override public:
{ void write_vertex(float x, float y, float z) override;
float3 vector(x, y, z);
char *bits = reinterpret_cast<char *>(&vector);
Span<char> span(bits, sizeof(float3));
write_bytes(span); void write_UV(float u, float v) override;
}
void write_UV(float u, float v) override void write_vertex_normal(float nx, float ny, float nz) override;
{
float2 vector(u, v);
char *bits = reinterpret_cast<char *>(&vector);
Span<char> span(bits, sizeof(float2));
write_bytes(span); void write_vertex_color(uchar r, uchar g, uchar b, uchar a) override;
}
void write_vertex_normal(float nx, float ny, float nz) override void write_vertex_end() override;
{
float3 vector(nx, ny, nz);
char *bits = reinterpret_cast<char *>(&vector);
Span<char> span(bits, sizeof(float3));
write_bytes(span); void write_face(char size, Array<uint32_t> const &vertex_indices) override;
}
void write_vertex_color(uchar r, uchar g, uchar b, uchar a) override void write_edge(int first, int second) override;
{
uchar4 vector(r, g, b, a);
char *bits = reinterpret_cast<char *>(&vector);
Span<char> span(bits, sizeof(uchar4));
write_bytes(span);
}
void write_vertex_end() override
{
/* In binary, there is no end to a vertex. */
}
void write_face(char size, Array<uint32_t> const &vertex_indices) override
{
write_bytes(Span<char>({size}));
Span<char> dataSpan(reinterpret_cast<const char *>(vertex_indices.data()),
vertex_indices.size() * sizeof(uint32_t));
write_bytes(dataSpan);
}
void write_edge(int first, int second) override
{
int2 vector(first, second);
char *bits = reinterpret_cast<char *>(&vector);
Span<char> span(bits, sizeof(int2));
write_bytes(span);
}
}; };
} // namespace blender::io::ply } // namespace blender::io::ply

View File

@ -14,6 +14,7 @@
#include "DNA_object_types.h" #include "DNA_object_types.h"
#include "DNA_scene_types.h" #include "DNA_scene_types.h"
#include "BLI_fileops.hh"
#include "BLI_math_vector.h" #include "BLI_math_vector.h"
#include "BLI_memory_utils.hh" #include "BLI_memory_utils.hh"
@ -86,11 +87,11 @@ void importer_main(Main *bmain,
{ {
std::string line; std::string line;
std::ifstream infile(import_params.filepath, std::ios::binary); fstream infile(import_params.filepath, std::ios::in | std::ios::binary);
PlyHeader header; PlyHeader header;
while (true) { // We break when end_header is encountered. while (true) { /* We break when end_header is encountered. */
safe_getline(infile, line); safe_getline(infile, line);
if (header.header_size == 0 && line != "ply") { if (header.header_size == 0 && line != "ply") {
fprintf(stderr, "PLY Importer: failed to read file. Invalid PLY header.\n"); fprintf(stderr, "PLY Importer: failed to read file. Invalid PLY header.\n");
@ -141,7 +142,6 @@ void importer_main(Main *bmain,
else if ((words[0][0] >= '0' && words[0][0] <= '9') || words[0][0] == '-' || line.empty() || else if ((words[0][0] >= '0' && words[0][0] <= '9') || words[0][0] == '-' || line.empty() ||
infile.eof()) { infile.eof()) {
/* A value was found before we broke out of the loop. No end_header. */ /* A value was found before we broke out of the loop. No end_header. */
fprintf(stderr, "PLY Importer: failed to read file. No end_header.\n");
BKE_report(op->reports, RPT_ERROR, "PLY Importer: No end_header"); BKE_report(op->reports, RPT_ERROR, "PLY Importer: No end_header");
return; return;
} }

View File

@ -12,14 +12,13 @@
namespace blender::io::ply { namespace blender::io::ply {
std::unique_ptr<PlyData> import_ply_ascii(std::ifstream &file, PlyHeader *header) std::unique_ptr<PlyData> import_ply_ascii(fstream &file, PlyHeader *header)
{ {
std::unique_ptr<PlyData> data = std::make_unique<PlyData>(); std::unique_ptr<PlyData> data = std::make_unique<PlyData>(load_ply_ascii(file, header));
*data = load_ply_ascii(file, header);
return data; return data;
} }
PlyData load_ply_ascii(std::ifstream &file, const PlyHeader *header) PlyData load_ply_ascii(fstream &file, const PlyHeader *header)
{ {
PlyData data; PlyData data;
/* Check if header contains alpha. */ /* Check if header contains alpha. */

View File

@ -6,6 +6,8 @@
#pragma once #pragma once
#include "BLI_fileops.hh"
#include "DNA_mesh_types.h" #include "DNA_mesh_types.h"
#include "IO_ply.h" #include "IO_ply.h"
@ -18,7 +20,7 @@ namespace blender::io::ply {
* \param file: The PLY file that was opened. * \param file: The PLY file that was opened.
* \param header: The information in the PLY header. * \param header: The information in the PLY header.
*/ */
std::unique_ptr<PlyData> import_ply_ascii(std::ifstream &file, PlyHeader *header); std::unique_ptr<PlyData> import_ply_ascii(fstream &file, PlyHeader *header);
/** /**
* Loads the information from the PLY file in ASCII format to the PlyData datastructure. * Loads the information from the PLY file in ASCII format to the PlyData datastructure.
@ -26,7 +28,7 @@ std::unique_ptr<PlyData> import_ply_ascii(std::ifstream &file, PlyHeader *header
* \param header: The information in the PLY header. * \param header: The information in the PLY header.
* \return The PlyData datastructure that can be used for conversion to a Mesh. * \return The PlyData datastructure that can be used for conversion to a Mesh.
*/ */
PlyData load_ply_ascii(std::ifstream &file, const PlyHeader *header); PlyData load_ply_ascii(fstream &file, const PlyHeader *header);
int3 get_vertex_index(const PlyHeader *header); int3 get_vertex_index(const PlyHeader *header);
int3 get_color_index(const PlyHeader *header); int3 get_color_index(const PlyHeader *header);

View File

@ -10,14 +10,13 @@
#include <fstream> #include <fstream>
namespace blender::io::ply { namespace blender::io::ply {
std::unique_ptr<PlyData> import_ply_binary(std::ifstream &file, const PlyHeader *header) std::unique_ptr<PlyData> import_ply_binary(fstream &file, const PlyHeader *header)
{ {
std::unique_ptr<PlyData> data = std::make_unique<PlyData>(); std::unique_ptr<PlyData> data = std::make_unique<PlyData>(load_ply_binary(file, header));
*data = load_ply_binary(file, header);
return data; return data;
} }
template<typename T> T read(std::ifstream &file, bool isBigEndian) template<typename T> T read(fstream &file, bool isBigEndian)
{ {
T returnVal; T returnVal;
file.read((char *)&returnVal, sizeof(returnVal)); file.read((char *)&returnVal, sizeof(returnVal));
@ -28,16 +27,16 @@ template<typename T> T read(std::ifstream &file, bool isBigEndian)
return returnVal; return returnVal;
} }
template uint8_t read<uint8_t>(std::ifstream &file, bool isBigEndian); template uint8_t read<uint8_t>(fstream &file, bool isBigEndian);
template int8_t read<int8_t>(std::ifstream &file, bool isBigEndian); template int8_t read<int8_t>(fstream &file, bool isBigEndian);
template uint16_t read<uint16_t>(std::ifstream &file, bool isBigEndian); template uint16_t read<uint16_t>(fstream &file, bool isBigEndian);
template int16_t read<int16_t>(std::ifstream &file, bool isBigEndian); template int16_t read<int16_t>(fstream &file, bool isBigEndian);
template uint32_t read<uint32_t>(std::ifstream &file, bool isBigEndian); template uint32_t read<uint32_t>(fstream &file, bool isBigEndian);
template int32_t read<int32_t>(std::ifstream &file, bool isBigEndian); template int32_t read<int32_t>(fstream &file, bool isBigEndian);
template float read<float>(std::ifstream &file, bool isBigEndian); template float read<float>(fstream &file, bool isBigEndian);
template double read<double>(std::ifstream &file, bool isBigEndian); template double read<double>(fstream &file, bool isBigEndian);
void check_file_errors(const std::ifstream &file) void check_file_errors(const fstream &file)
{ {
if (file.bad()) { if (file.bad()) {
throw std::ios_base::failure("Read/Write error on io operation"); throw std::ios_base::failure("Read/Write error on io operation");
@ -50,7 +49,7 @@ void check_file_errors(const std::ifstream &file)
} }
} }
void discard_value(std::ifstream &file, const PlyDataTypes type) void discard_value(fstream &file, const PlyDataTypes type)
{ {
switch (type) { switch (type) {
case CHAR: case CHAR:
@ -80,7 +79,7 @@ void discard_value(std::ifstream &file, const PlyDataTypes type)
} }
} }
PlyData load_ply_binary(std::ifstream &file, const PlyHeader *header) PlyData load_ply_binary(fstream &file, const PlyHeader *header)
{ {
PlyData data; PlyData data;
bool isBigEndian = header->type == PlyFormatType::BINARY_BE; bool isBigEndian = header->type == PlyFormatType::BINARY_BE;
@ -141,7 +140,7 @@ PlyData load_ply_binary(std::ifstream &file, const PlyHeader *header)
return data; return data;
} }
void load_vertex_data(std::ifstream &file, const PlyHeader *header, PlyData *r_data, int index) void load_vertex_data(fstream &file, const PlyHeader *header, PlyData *r_data, int index)
{ {
bool hasNormal = false; bool hasNormal = false;
bool hasColor = false; bool hasColor = false;

View File

@ -6,6 +6,9 @@
#pragma once #pragma once
#include "BLI_endian_switch.h"
#include "BLI_fileops.hh"
#include "ply_data.hh" #include "ply_data.hh"
namespace blender::io::ply { namespace blender::io::ply {
@ -16,7 +19,7 @@ namespace blender::io::ply {
* \param header: The information in the PLY header. * \param header: The information in the PLY header.
* \return The PlyData datastructure that can be used for conversion to a Mesh. * \return The PlyData datastructure that can be used for conversion to a Mesh.
*/ */
std::unique_ptr<PlyData> import_ply_binary(std::ifstream &file, const PlyHeader *header); std::unique_ptr<PlyData> import_ply_binary(fstream &file, const PlyHeader *header);
/** /**
* Loads the information from the PLY file in binary format to the PlyData datastructure. * Loads the information from the PLY file in binary format to the PlyData datastructure.
@ -24,13 +27,13 @@ std::unique_ptr<PlyData> import_ply_binary(std::ifstream &file, const PlyHeader
* \param header: The information in the PLY header. * \param header: The information in the PLY header.
* \return The PlyData datastructure that can be used for conversion to a Mesh. * \return The PlyData datastructure that can be used for conversion to a Mesh.
*/ */
PlyData load_ply_binary(std::ifstream &file, const PlyHeader *header); PlyData load_ply_binary(fstream &file, const PlyHeader *header);
void load_vertex_data(std::ifstream &file, const PlyHeader *header, PlyData *r_data, int index); void load_vertex_data(fstream &file, const PlyHeader *header, PlyData *r_data, int index);
void check_file_errors(const std::ifstream &file); void check_file_errors(const fstream &file);
void discard_value(std::ifstream &file, const PlyDataTypes type); void discard_value(fstream &file, const PlyDataTypes type);
template<typename T> T swap_bytes(T input) template<typename T> T swap_bytes(T input)
{ {
@ -42,34 +45,27 @@ template<typename T> T swap_bytes(T input)
return input; return input;
} }
if (sizeof(T) == 2) { if constexpr (sizeof(T) == 2) {
uint16_t newInput = uint16_t(input); uint16_t value = reinterpret_cast<uint16_t &>(input);
return (T)(((newInput & 0xFF) << 8) | ((newInput >> 8) & 0xFF)); BLI_endian_switch_uint16(&value);
return reinterpret_cast<T &>(value);
} }
if (sizeof(T) == 4) { if constexpr (sizeof(T) == 4) {
/* Reinterpret this data as uint32 for easy rearranging of bytes. */ /* Reinterpret this data as uint32 for easy rearranging of bytes. */
uint32_t newInput = *(uint32_t *)&input; uint32_t value = reinterpret_cast<uint32_t &>(input);
uint32_t output = 0; BLI_endian_switch_uint32(&value);
for (int i = 0; i < 4; i++) { return reinterpret_cast<T &>(value);
output |= ((newInput >> i * 8) & 0xFF) << (24 - i * 8);
}
T value = *(T *)&output;
return value; /* Reinterpret the bytes of output as a T value. */
} }
if (sizeof(T) == 8) { if constexpr (sizeof(T) == 8) {
/* Reinterpret this data as uint64 for easy rearranging of bytes. */ /* Reinterpret this data as uint64 for easy rearranging of bytes. */
uint64_t newInput = *(uint64_t *)&input; uint64_t value = reinterpret_cast<uint64_t &>(input);
uint64_t output = 0; BLI_endian_switch_uint64(&value);
for (int i = 0; i < 8; i++) { return reinterpret_cast<T &>(value);
output |= ((newInput >> i * 8) & 0xFF) << (56 - i * 8);
}
T value = *(T *)&output;
return value; /* Reinterpret the bytes of output as a T value. */
} }
} }
template<typename T> T read(std::ifstream &file, bool isBigEndian); template<typename T> T read(fstream &file, bool isBigEndian);
} // namespace blender::io::ply } // namespace blender::io::ply

View File

@ -38,13 +38,13 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams &para
} }
} }
/* Add faces and edges to the mesh. */ /* Add faces to the mesh. */
if (!data.faces.is_empty()) { if (!data.faces.is_empty()) {
/* Specify amount of total faces. */ /* Specify amount of total faces. */
mesh->totpoly = int(data.faces.size()); mesh->totpoly = int(data.faces.size());
mesh->totloop = 0; mesh->totloop = 0;
for (int i = 0; i < data.faces.size(); i++) { for (int i = 0; i < data.faces.size(); i++) {
/* Add number of edges to the amount of edges. */ /* Add number of loops from the vertex indices in the face. */
mesh->totloop += data.faces[i].size(); mesh->totloop += data.faces[i].size();
} }
CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly);
@ -87,7 +87,7 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams &para
int counter = 0; int counter = 0;
for (int i = 0; i < data.faces.size(); i++) { for (int i = 0; i < data.faces.size(); i++) {
for (int j = 0; j < data.faces[i].size(); j++) { for (int j = 0; j < data.faces[i].size(); j++) {
copy_v2_v2(uv_map.span[counter], data.UV_coordinates[data.faces[i][j]]); uv_map.span[counter] = data.UV_coordinates[data.faces[i][j]];
counter++; counter++;
} }
} }

View File

@ -13,7 +13,7 @@ namespace blender::io::ply {
/** /**
* Converts the PlyData datastructure to a mesh. * Converts the PlyData datastructure to a mesh.
* \param data The PLY data. * \param data: The PLY data.
* \return The mesh that can be used inside blender. * \return The mesh that can be used inside blender.
*/ */
Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams &params); Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams &params);

View File

@ -4,13 +4,11 @@
* \ingroup ply * \ingroup ply
*/ */
#include <iostream>
#include "ply_functions.hh" #include "ply_functions.hh"
namespace blender::io::ply { namespace blender::io::ply {
line_ending safe_getline(std::ifstream &file, std::string &line) line_ending safe_getline(fstream &file, std::string &line)
{ {
line.clear(); line.clear();
std::streambuf *sb = file.rdbuf(); std::streambuf *sb = file.rdbuf();
@ -19,7 +17,7 @@ line_ending safe_getline(std::ifstream &file, std::string &line)
line_ending possible = UNSET; line_ending possible = UNSET;
char c; char c;
while (sb->sgetc() != std::streambuf::traits_type::eof()) { while (sb->sgetc() != std::streambuf::traits_type::eof()) {
c = (char)sb->sgetc(); c = char(sb->sgetc());
switch (c) { switch (c) {
case '\n': case '\n':
if (possible == UNSET) { if (possible == UNSET) {

View File

@ -6,7 +6,7 @@
#pragma once #pragma once
#include <fstream> #include "BLI_fileops.hh"
#include <string> #include <string>
namespace blender::io::ply { namespace blender::io::ply {
@ -17,10 +17,10 @@ enum line_ending { CR_LF, LF, CR, LF_CR, UNSET };
* Reads a line in the ply file in a line-ending safe manner. All different line endings are * Reads a line in the ply file in a line-ending safe manner. All different line endings are
* supported. This also supports a mix of different line endings in the same file. CR (\\r), LF * supported. This also supports a mix of different line endings in the same file. CR (\\r), LF
* (\\n), CR/LF (\\r\\n), LF/CR (\\n\\r). * (\\n), CR/LF (\\r\\n), LF/CR (\\n\\r).
* @param file The file stream. * \param file: The file stream.
* @param line The string you want to read to. * \param line: The string you want to read to.
* @return The line ending enum if you're interested. * \return The line ending enum if you're interested.
*/ */
line_ending safe_getline(std::ifstream &file, std::string &line); line_ending safe_getline(fstream &file, std::string &line);
} // namespace blender::io::ply } // namespace blender::io::ply

View File

@ -1,23 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "testing/testing.h" #include "testing/testing.h"
#include "tests/blendfile_loading_base_test.h" #include "tests/blendfile_loading_base_test.h"
#include "BKE_blender_version.h" #include "BKE_blender_version.h"
#include "BKE_curve.h"
#include "BKE_main.h"
#include "BKE_scene.h"
#include "BLI_fileops.h"
#include "BLO_readfile.h"
#include "DEG_depsgraph.h" #include "DEG_depsgraph.h"
#include "DNA_curve_types.h"
#include "DNA_material_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
#include "IO_ply.h" #include "IO_ply.h"
#include "intern/ply_data.hh" #include "intern/ply_data.hh"
@ -463,7 +452,7 @@ TEST_F(ply_exporter_ply_data_test, SuzanneLoadPLYDataUV)
params.export_uv = true; params.export_uv = true;
PlyData plyData = load_ply_data_from_blendfile("io_tests/blend_geometry/suzanne_all_data.blend", PlyData plyData = load_ply_data_from_blendfile("io_tests/blend_geometry/suzanne_all_data.blend",
params); params);
EXPECT_EQ(plyData.UV_coordinates.size(), 541); EXPECT_EQ(plyData.UV_coordinates.size(), 542);
} }
TEST_F(ply_exporter_ply_data_test, CubeLoadPLYDataUVDisabled) TEST_F(ply_exporter_ply_data_test, CubeLoadPLYDataUVDisabled)

View File

@ -1,28 +1,15 @@
#include "testing/testing.h" /* SPDX-License-Identifier: GPL-2.0-or-later */
#include "tests/blendfile_loading_base_test.h" #include "tests/blendfile_loading_base_test.h"
#include "BKE_attribute.hh" #include "BKE_attribute.hh"
#include "BKE_curve.h"
#include "BKE_main.h"
#include "BKE_mesh.h" #include "BKE_mesh.h"
#include "BKE_object.h" #include "BKE_object.h"
#include "BKE_scene.h"
#include "BLI_math_vector_types.hh"
#include "BLO_readfile.h" #include "BLO_readfile.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h" #include "DEG_depsgraph_query.h"
#include "DNA_curve_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
#include "IO_ply.h" #include "IO_ply.h"
#include "ply_data.hh" #include "ply_data.hh"
#include "ply_import.hh" #include "ply_import.hh"