Blender  V3.3
stl_import_ascii_reader.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <cstdint>
8 #include <cstdio>
9 
10 #include "BKE_mesh.h"
11 
12 #include "BLI_fileops.hh"
13 #include "BLI_memory_utils.hh"
14 #include "BLI_string_ref.hh"
15 
16 #include "DNA_mesh_types.h"
17 
18 /* NOTE: we could use C++17 <charconv> from_chars to parse
19  * floats, but even if some compilers claim full support,
20  * their standard libraries are not quite there yet.
21  * LLVM/libc++ only has a float parser since LLVM 14,
22  * and gcc/libstdc++ since 11.1. So until at least these are
23  * the minimum spec, use an external library. */
24 #include "fast_float.h"
25 
26 #include "stl_import.hh"
28 #include "stl_import_mesh.hh"
29 
30 namespace blender::io::stl {
31 
32 class StringBuffer {
33  private:
34  char *start;
35  const char *end;
36 
37  public:
38  StringBuffer(char *buf, size_t len)
39  {
40  start = buf;
41  end = start + len;
42  }
43 
44  bool is_empty() const
45  {
46  return start == end;
47  }
48 
50  {
51  while ((start < end) && (*start) <= ' ') {
52  start++;
53  }
54  }
55 
57  {
58  while ((start < end) && (*start) > ' ') {
59  start++;
60  }
61  }
62 
63  void drop_line()
64  {
65  while (start < end && *start != '\n') {
66  start++;
67  }
68  }
69 
70  bool parse_token(const char *token, size_t token_length)
71  {
73  if (end - start < token_length + 1) {
74  return false;
75  }
76  if (memcmp(start, token, token_length) != 0) {
77  return false;
78  }
79  if (start[token_length] > ' ') {
80  return false;
81  }
82  start += token_length + 1;
83  return true;
84  }
85 
86  void drop_token()
87  {
90  }
91 
92  void parse_float(float &out)
93  {
95  /* Skip '+' */
96  if (start < end && *start == '+') {
97  start++;
98  }
99  fast_float::from_chars_result res = fast_float::from_chars(start, end, out);
100  if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
101  out = 0.0f;
102  }
103  start = const_cast<char *>(res.ptr);
104  }
105 };
106 
107 static inline void parse_float3(StringBuffer &buf, float out[3])
108 {
109  for (int i = 0; i < 3; i++) {
110  buf.parse_float(out[i]);
111  }
112 }
113 
114 Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals)
115 {
116  size_t buffer_len;
117  void *buffer = BLI_file_read_text_as_mem(filepath, 0, &buffer_len);
118  if (buffer == nullptr) {
119  fprintf(stderr, "STL Importer: cannot read from ASCII STL file: '%s'\n", filepath);
120  return BKE_mesh_add(bmain, mesh_name);
121  }
122  BLI_SCOPED_DEFER([&]() { MEM_freeN(buffer); });
123 
124  int num_reserved_tris = 1024;
125 
126  StringBuffer str_buf(static_cast<char *>(buffer), buffer_len);
127  STLMeshHelper stl_mesh(num_reserved_tris, use_custom_normals);
128  float triangle_buf[3][3];
129  float custom_normal_buf[3];
130  str_buf.drop_line(); /* Skip header line */
131  while (!str_buf.is_empty()) {
132  if (str_buf.parse_token("vertex", 6)) {
133  parse_float3(str_buf, triangle_buf[0]);
134  if (str_buf.parse_token("vertex", 6)) {
135  parse_float3(str_buf, triangle_buf[1]);
136  }
137  if (str_buf.parse_token("vertex", 6)) {
138  parse_float3(str_buf, triangle_buf[2]);
139  }
140  if (use_custom_normals) {
141  stl_mesh.add_triangle(
142  triangle_buf[0], triangle_buf[1], triangle_buf[2], custom_normal_buf);
143  }
144  else {
145  stl_mesh.add_triangle(triangle_buf[0], triangle_buf[1], triangle_buf[2]);
146  }
147  }
148  else if (str_buf.parse_token("facet", 5)) {
149  str_buf.drop_token(); /* Expecting "normal" */
150  parse_float3(str_buf, custom_normal_buf);
151  }
152  else {
153  str_buf.drop_token();
154  }
155  }
156 
157  return stl_mesh.to_mesh(bmain, mesh_name);
158 }
159 
160 } // namespace blender::io::stl
struct Mesh * BKE_mesh_add(struct Main *bmain, const char *name)
Definition: mesh.cc:963
void * BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size)
Definition: storage.c:466
File and directory operations.
#define BLI_SCOPED_DEFER(function_to_defer)
Mesh * to_mesh(Main *bmain, char *mesh_name)
bool add_triangle(const float3 &a, const float3 &b, const float3 &c)
bool parse_token(const char *token, size_t token_length)
int len
Definition: draw_manager.c:108
ccl_global float * buffer
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
Mesh * read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals)
static void parse_float3(StringBuffer &buf, float out[3])
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
Definition: BKE_main.h:121