Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2020-03-22 16:12:45 +0300
committerJacques Lucke <jacques@blender.org>2020-03-22 16:12:45 +0300
commitdf984b1dd6758e0b8edf415be501f2b95b9fba25 (patch)
tree5c76c2b4ec53368404784238276bd1f99091377f
parenta4d1acf1ce3cc339c5b956a9f905de2c8f660a37 (diff)
parse face information
-rw-r--r--source/blender/blenlib/BLI_string_ref.h40
-rw-r--r--source/blender/editors/object/object_obj_import.cc127
2 files changed, 115 insertions, 52 deletions
diff --git a/source/blender/blenlib/BLI_string_ref.h b/source/blender/blenlib/BLI_string_ref.h
index e43b8d59035..eb2b5308ecd 100644
--- a/source/blender/blenlib/BLI_string_ref.h
+++ b/source/blender/blenlib/BLI_string_ref.h
@@ -121,6 +121,12 @@ class StringRefBase {
StringRef strip(ArrayRef<char> chars = {' ', '\t', '\n', '\r'}) const;
float to_float(bool *r_success = nullptr) const;
+ int to_int(bool *r_success = nullptr) const;
+
+ bool contains(char c) const;
+
+ uint first_index_of(char c, uint start = 0) const;
+ int try_first_index_of(char c, uint start = 0) const;
};
/**
@@ -368,6 +374,40 @@ inline float StringRefBase::to_float(bool *r_success) const
return value;
}
+inline int StringRefBase::to_int(bool *r_success) const
+{
+ char *str_with_null = (char *)alloca(m_size + 1);
+ this->copy_to__with_null(str_with_null);
+ char *end;
+ int value = std::strtol(str_with_null, &end, 10);
+ if (r_success) {
+ *r_success = str_with_null != end;
+ }
+ return value;
+}
+
+inline bool StringRefBase::contains(char c) const
+{
+ return this->try_first_index_of(c) >= 0;
+}
+
+inline uint StringRefBase::first_index_of(char c, uint start) const
+{
+ int index = this->try_first_index_of(c, start);
+ BLI_assert(index >= 0);
+ return (uint)index;
+}
+
+inline int StringRefBase::try_first_index_of(char c, uint start) const
+{
+ for (uint i = start; i < m_size; i++) {
+ if (m_data[i] == c) {
+ return i;
+ }
+ }
+ return -1;
+}
+
} // namespace BLI
#endif /* __BLI_STRING_REF_H__ */
diff --git a/source/blender/editors/object/object_obj_import.cc b/source/blender/editors/object/object_obj_import.cc
index 2b89f1dbda7..988abf742ce 100644
--- a/source/blender/editors/object/object_obj_import.cc
+++ b/source/blender/editors/object/object_obj_import.cc
@@ -57,7 +57,7 @@ class TextLinesReader {
}
/* The returned string does not necessarily contain the final newline. */
- StringRef read_next_line_chunk(uint approximate_size)
+ BLI_NOINLINE StringRef read_next_line_chunk(uint approximate_size)
{
SCOPED_TIMER(__func__);
std::lock_guard<std::mutex> lock(m_mutex);
@@ -195,9 +195,9 @@ struct ObjFileSegment_f : public ObjFileSegment {
Vector<uint> face_offsets;
Vector<uint> vertex_counts;
- Vector<uint> position_indices;
- Vector<uint> uv_indices;
- Vector<uint> normal_indices;
+ Vector<int> v_indices;
+ Vector<int> vt_indices;
+ Vector<int> vn_indices;
ObjFileSegment_f() : ObjFileSegment(ObjFileSegmentType::f)
{
@@ -222,42 +222,6 @@ template<typename FuncT> static uint count_while(StringRef str, const FuncT &fun
return count;
}
-static bool is_whitespace(char c)
-{
- return ELEM(c, ' ', '\t', '\r');
-}
-
-static bool is_not_newline(char c)
-{
- return c != '\n';
-}
-
-static bool is_newline(char c)
-{
- return c == '\n';
-}
-
-static std::pair<uint, uint> find_next_word_in_line(StringRef str)
-{
- uint offset = 0;
- for (char c : str) {
- if (!is_whitespace(c)) {
- break;
- }
- offset++;
- }
-
- uint length = 0;
- for (char c : str.drop_prefix(offset)) {
- if (is_whitespace(c) || c == '\n') {
- break;
- }
- length++;
- }
-
- return {offset, length};
-}
-
class StringRefStream {
private:
const char *m_current;
@@ -369,9 +333,16 @@ class StringRefStream {
return value;
}
+ int extract_next_int(bool *r_success = nullptr)
+ {
+ StringRef str = this->extract_next_word();
+ int value = str.to_int(r_success);
+ return value;
+ }
+
void forward_over_whitespace()
{
- while (m_current < m_end && is_whitespace(*m_current)) {
+ while (m_current < m_end && ELEM(*m_current, ' ', '\t', '\r')) {
m_current++;
}
}
@@ -472,7 +443,60 @@ BLI_NOINLINE static void parse_uvs(StringRefStream &stream, Vector<float2> &r_uv
}
}
-static std::unique_ptr<ObjFileSegments> parse_obj_lines(StringRef orig_str)
+BLI_NOINLINE static void parse_faces(StringRefStream &stream, ObjFileSegment_f &segment)
+{
+ while (stream.peek_word() == "f") {
+ StringRefStream line = stream.extract_line().drop_prefix("f");
+ uint count = 0;
+
+ segment.face_offsets.append(segment.v_indices.size());
+
+ while (true) {
+ StringRef face_corner = line.extract_next_word();
+ if (face_corner.size() == 0) {
+ break;
+ }
+
+ int v_index, vt_index, vn_index;
+
+ if (face_corner.contains('/')) {
+ uint index1 = face_corner.first_index_of('/');
+ StringRef first_str = face_corner.substr(0, index1);
+ v_index = first_str.to_int();
+ StringRef remaining_str = face_corner.drop_prefix(index1 + 1);
+ int index2 = remaining_str.try_first_index_of('/');
+ if (index2 == -1) {
+ vt_index = remaining_str.to_int();
+ vn_index = -1;
+ }
+ else if (index2 == 0) {
+ StringRef second_str = remaining_str.drop_prefix('/');
+ vt_index = -1;
+ vn_index = second_str.to_int();
+ }
+ else {
+ StringRef second_str = remaining_str.substr(0, index2);
+ StringRef third_str = remaining_str.drop_prefix(index2 + 1);
+ vt_index = second_str.to_int();
+ vn_index = third_str.to_int();
+ }
+ }
+ else {
+ v_index = face_corner.to_int();
+ vt_index = -1;
+ vn_index = -1;
+ }
+
+ segment.v_indices.append(v_index);
+ segment.vt_indices.append(vt_index);
+ segment.vn_indices.append(vn_index);
+ count++;
+ }
+ segment.vertex_counts.append(count);
+ }
+}
+
+BLI_NOINLINE static std::unique_ptr<ObjFileSegments> parse_obj_lines(StringRef orig_str)
{
SCOPED_TIMER(__func__);
StringRefStream stream(orig_str);
@@ -494,24 +518,18 @@ static std::unique_ptr<ObjFileSegments> parse_obj_lines(StringRef orig_str)
segments->segments.append(std::move(segment));
}
else if (first_word == "v") {
- Vector<float3> positions;
- parse_positions(stream, positions);
auto segment = BLI::make_unique<ObjFileSegment_v>();
- segment->positions = std::move(positions);
+ parse_positions(stream, segment->positions);
segments->segments.append(std::move(segment));
}
else if (first_word == "vn") {
- Vector<float3> normals;
- parse_normals(stream, normals);
auto segment = BLI::make_unique<ObjFileSegment_vn>();
- segment->normals = std::move(normals);
+ parse_normals(stream, segment->normals);
segments->segments.append(std::move(segment));
}
else if (first_word == "vt") {
- Vector<float2> uvs;
- parse_uvs(stream, uvs);
auto segment = BLI::make_unique<ObjFileSegment_vt>();
- segment->uvs = std::move(uvs);
+ parse_uvs(stream, segment->uvs);
segments->segments.append(std::move(segment));
}
else if (first_word == "usemtl") {
@@ -526,6 +544,11 @@ static std::unique_ptr<ObjFileSegments> parse_obj_lines(StringRef orig_str)
auto segment = BLI::make_unique<ObjFileSegment_s>(smoothing_group_name);
segments->segments.append(std::move(segment));
}
+ else if (first_word == "f") {
+ auto segment = BLI::make_unique<ObjFileSegment_f>();
+ parse_faces(stream, *segment);
+ segments->segments.append(std::move(segment));
+ }
else {
stream.extract_line();
}
@@ -534,7 +557,7 @@ static std::unique_ptr<ObjFileSegments> parse_obj_lines(StringRef orig_str)
return segments;
}
-static void import_obj(bContext *UNUSED(C), StringRef file_path)
+BLI_NOINLINE static void import_obj(bContext *UNUSED(C), StringRef file_path)
{
std::ifstream input_stream;
input_stream.open(file_path, std::ios::binary);