[Bf-blender-cvs] [df984b1dd67] obj-import-experiments: parse face information

Jacques Lucke noreply at git.blender.org
Sun Mar 22 16:17:39 CET 2020


Commit: df984b1dd6758e0b8edf415be501f2b95b9fba25
Author: Jacques Lucke
Date:   Sun Mar 22 14:12:45 2020 +0100
Branches: obj-import-experiments
https://developer.blender.org/rBdf984b1dd6758e0b8edf415be501f2b95b9fba25

parse face information

===================================================================

M	source/blender/blenlib/BLI_string_ref.h
M	source/blender/editors/object/object_obj_import.cc

===================================================================

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);



More information about the Bf-blender-cvs mailing list