38 Vector<std::unique_ptr<Geometry>> &r_all_geometries)
40 auto new_geometry = [&]() {
41 r_all_geometries.append(std::make_unique<Geometry>());
42 Geometry *g = r_all_geometries.last().get();
52 return new_geometry();
68 return new_geometry();
71 return new_geometry();
79 r_global_vertices.
vertices.append(vert);
86 if (srgb.x >= 0 && srgb.y >= 0 && srgb.z >= 0) {
101 const int mrgb_length = 8;
102 while (p + mrgb_length <= end) {
104 std::from_chars_result res = std::from_chars(p, p + mrgb_length, value, 16);
105 if (
ELEM(res.ec, std::errc::invalid_argument, std::errc::result_out_of_range)) {
109 srgb[0] = (value >> 16) & 0xFF;
110 srgb[1] = (value >> 8) & 0xFF;
111 srgb[2] = value & 0xFF;
116 r_global_vertices.
mrgb_block.append(
float3(linear[0], linear[1], linear[2]));
153 r_index += r_index < 0 ? n_elems : -1;
154 if (r_index < 0 || r_index >= n_elems) {
155 fprintf(stderr,
"Invalid vertex index %i (valid range [0, %zu))\n", r_index, n_elems);
176 int last_vertex_index;
181 fprintf(stderr,
"Skipping invalid OBJ polyline.\n");
199 geom->
edges_.append({last_vertex_index, vertex_index});
201 last_vertex_index = vertex_index;
209 const int material_index,
210 const int group_index,
211 const bool shaded_smooth)
216 if (group_index >= 0) {
224 bool face_valid =
true;
226 while (p < end && face_valid) {
228 bool got_uv =
false, got_normal =
false;
237 face_valid &= corner.vert_index !=
INT32_MAX;
238 if (p < end && *p ==
'/') {
241 if (p < end && *p !=
'/') {
243 got_uv = corner.uv_vert_index !=
INT32_MAX;
246 if (p < end && *p ==
'/') {
249 got_normal = corner.vertex_normal_index !=
INT32_MAX;
253 corner.vert_index += corner.vert_index < 0 ? global_vertices.
vertices.size() : -1;
254 if (corner.vert_index < 0 || corner.vert_index >= global_vertices.
vertices.size()) {
256 "Invalid vertex index %i (valid range [0, %zu)), ignoring face\n",
258 size_t(global_vertices.
vertices.size()));
265 if (got_uv && !global_vertices.
uv_vertices.is_empty()) {
266 corner.uv_vert_index += corner.uv_vert_index < 0 ? global_vertices.
uv_vertices.size() : -1;
267 if (corner.uv_vert_index < 0 || corner.uv_vert_index >= global_vertices.
uv_vertices.size()) {
269 "Invalid UV index %i (valid range [0, %zu)), ignoring face\n",
270 corner.uv_vert_index,
278 if (got_normal && !global_vertices.
vert_normals.is_empty()) {
279 corner.vertex_normal_index += corner.vertex_normal_index < 0 ?
282 if (corner.vertex_normal_index < 0 ||
283 corner.vertex_normal_index >= global_vertices.
vert_normals.size())
286 "Invalid normal index %i (valid range [0, %zu)), ignoring face\n",
287 corner.vertex_normal_index,
316 Vector<std::unique_ptr<Geometry>> &r_all_geometries)
319 if (!
StringRef(p, end).startswith(
"bspline")) {
320 std::cerr <<
"Curve type not supported: '" << std::string(p, end) <<
"'" << std::endl;
348 index += index < 0 ? global_vertices.
vertices.size() : -1;
357 std::cerr <<
"Invalid OBJ curve parm line" << std::endl;
361 std::cerr <<
"OBJ curve surfaces are not supported: '" << *p <<
"'" << std::endl;
373 std::cerr <<
"OBJ curve parm line has invalid number" << std::endl;
381 if (rest_line.
find(
"off") != string::npos || rest_line.
find(
"null") != string::npos ||
382 rest_line.
find(
"default") != string::npos)
388 r_group_name = rest_line;
396 if (line ==
"0" || line.startswith(
"off") || line.startswith(
"null")) {
397 r_state_shaded_smooth =
false;
403 r_state_shaded_smooth = smooth != 0;
408 bool &r_state_shaded_smooth,
409 std::string &r_state_group_name,
410 int &r_state_material_index,
412 Vector<std::unique_ptr<Geometry>> &r_all_geometries)
414 r_state_shaded_smooth =
false;
415 r_state_group_name =
"";
419 r_state_material_index = -1;
425 : import_params_(import_params), read_buffer_size_(read_buffer_size)
429 fprintf(stderr,
"Cannot read from OBJ file:'%s'.\n", import_params_.
filepath);
432 "OBJ Import: Cannot open file '%s'",
448 const size_t keyword_len = keyword.
size();
449 if (end - p < keyword_len + 1) {
452 if (memcmp(p, keyword.
data(), keyword_len) != 0) {
457 if (p[keyword_len] >
' ') {
460 p += keyword_len + 1;
467 const Span<std::unique_ptr<Geometry>> all_geometries,
471 if (std::all_of(all_geometries.begin(),
472 all_geometries.end(),
473 [](
const std::unique_ptr<Geometry> &g) { return g->get_vertex_count() == 0; }))
496 bool state_shaded_smooth =
false;
497 string state_group_name;
498 int state_group_index = -1;
499 string state_material_name;
500 int state_material_index = -1;
506 size_t buffer_offset = 0;
507 size_t line_number = 0;
510 size_t bytes_read = fread(buffer.
data() + buffer_offset, 1, read_buffer_size_, obj_file_);
511 if (bytes_read == 0 && buffer_offset == 0) {
518 buffer.
data() + buffer_offset + bytes_read);
521 if (bytes_read < read_buffer_size_) {
522 if (bytes_read == 0 || buffer[buffer_offset + bytes_read - 1] !=
'\n') {
523 buffer[buffer_offset + bytes_read] =
'\n';
528 size_t buffer_end = buffer_offset + bytes_read;
529 if (buffer_end == 0) {
534 size_t last_nl = buffer_end;
535 while (last_nl > 0) {
537 if (buffer[last_nl] ==
'\n') {
541 if (buffer[last_nl] !=
'\n') {
544 "OBJ file contains a line #%zu that is too long (max. length %zu)\n",
554 while (!buffer_str.is_empty()) {
556 const char *p = line.begin(), *end = line.end();
578 if (state_material_index == -1 && !state_material_name.empty() &&
583 state_material_index = 0;
590 state_material_index,
592 state_shaded_smooth);
605 state_material_index,
617 state_material_index,
625 if (new_index == state_group_index) {
640 if (new_mat_index == state_material_index) {
645 add_mtl_library(
StringRef(p, end).trim());
651 else if (*p ==
'#') {
667 else if (
StringRef(p, end).startswith(
"end")) {
671 std::cout <<
"OBJ element not recognized: '" << std::string(p, end) <<
"'" << std::endl;
677 size_t left_size = buffer_end - last_nl;
678 memmove(buffer.
data(), buffer.
data() + last_nl, left_size);
679 buffer_offset = left_size;
684 add_default_mtl_library();
751 p =
parse_float(p, end, 1.0f, material->normal_strength,
true,
true);
759 if (!line.startswith(
"sphere")) {
760 std::cerr <<
"OBJ import: only sphere MTL projection type is supported: '" << line <<
"'"
770 for (
int i = 0; i < opt.second; ++i) {
784 const char *mtl_dir_path)
787 bool is_map = line.startswith(
"map_");
788 bool is_refl = line.startswith(
"refl");
789 bool is_bump = line.startswith(
"bump");
790 if (!is_map && !is_refl && !is_bump) {
796 std::cerr <<
"OBJ import: MTL texture map type not supported: '" << line <<
"'" << std::endl;
799 MTLTexMap &tex_map = material->tex_map_of_type(key);
812 return mtl_libraries_;
815void OBJParser::add_mtl_library(
StringRef path)
822 if (!mtl_libraries_.
contains(path)) {
823 mtl_libraries_.
append(path);
827void OBJParser::add_default_mtl_library()
840 add_mtl_library(mtl_file_base);
856 if (buffer ==
nullptr) {
857 fprintf(stderr,
"OBJ import: cannot read from MTL file: '%s'\n", mtl_file_path_);
864 while (!buffer_str.is_empty()) {
866 const char *p = line.begin(), *end = line.end();
874 if (r_materials.contains(mat_name)) {
879 r_materials.lookup_or_add(
string(mat_name), std::make_unique<MTLMaterial>()).get();
882 else if (material !=
nullptr) {
884 parse_float(p, end, 324.0f, material->spec_exponent);
896 parse_floats(p, end, 0.0f, material->emission_color, 3);
908 material->illum_mode = val;
932 parse_floats(p, end, 0.0f, material->transmit_color, 3);
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void * BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size)
File and directory operations.
MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4])
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
MINLINE float normalize_v3(float n[3])
bool bool BLI_path_extension_strip(char *path) ATTR_NONNULL(1)
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool BLI_path_extension_replace(char *path, size_t path_maxncpy, const char *ext) ATTR_NONNULL(1
#define BLI_path_join(...)
void void void BLI_path_split_file_part(const char *filepath, char *file, size_t file_maxncpy) ATTR_NONNULL(1
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
#define STRNCPY(dst, src)
void add_new(const Key &key, const Value &value)
Value & lookup_or_add(const Key &key, const Value &value)
constexpr int64_t find(char c, int64_t pos=0) const
constexpr bool startswith(StringRef prefix) const
constexpr bool endswith(StringRef suffix) const
constexpr int64_t size() const
constexpr StringRef trim() const
constexpr const char * data() const
constexpr StringRef drop_prefix(int64_t n) const
constexpr StringRef drop_suffix(int64_t n) const
bool contains(const T &value) const
void append(const T &value)
void parse_and_store(Map< std::string, std::unique_ptr< MTLMaterial > > &r_materials)
MTLParser(StringRefNull mtl_library_, StringRefNull obj_filepath)
Span< std::string > mtl_libraries() const
OBJParser(const OBJImportParams &import_params, size_t read_buffer_size)
void parse(Vector< std::unique_ptr< Geometry > > &r_all_geometries, GlobalVertices &r_global_vertices)
void MEM_freeN(void *vmemh)
static void use_all_vertices_if_no_faces(Geometry *geom, const Span< std::unique_ptr< Geometry > > all_geometries, const GlobalVertices &global_vertices)
static void geom_new_object(const char *p, const char *end, bool &r_state_shaded_smooth, std::string &r_state_group_name, int &r_state_material_index, Geometry *&r_curr_geom, Vector< std::unique_ptr< Geometry > > &r_all_geometries)
static void geom_add_curve_vertex_indices(Geometry *geom, const char *p, const char *end, const GlobalVertices &global_vertices)
static void geom_add_vertex(const char *p, const char *end, GlobalVertices &r_global_vertices)
static void geom_add_mrgb_colors(const char *p, const char *end, GlobalVertices &r_global_vertices)
static void parse_texture_map(const char *p, const char *end, MTLMaterial *material, const char *mtl_dir_path)
const char * parse_floats(const char *p, const char *end, float fallback, float *dst, int count, bool require_trailing_space)
void fixup_line_continuations(char *p, char *end)
static void geom_add_uv_vertex(const char *p, const char *end, GlobalVertices &r_global_vertices)
static const char * parse_vertex_index(const char *p, const char *end, size_t n_elems, int &r_index)
static MTLTexMapType mtl_line_start_to_texture_type(const char *&p, const char *end)
const char * drop_non_whitespace(const char *p, const char *end)
static void geom_add_polyline(Geometry *geom, const char *p, const char *end, GlobalVertices &r_global_vertices)
static bool parse_keyword(const char *&p, const char *end, StringRef keyword)
const char * parse_int(const char *p, const char *end, int fallback, int &dst, bool skip_space)
const char * drop_whitespace(const char *p, const char *end)
static bool parse_texture_option(const char *&p, const char *end, MTLMaterial *material, MTLTexMap &tex_map)
static void geom_add_vertex_normal(const char *p, const char *end, GlobalVertices &r_global_vertices)
static void geom_add_curve_parameters(Geometry *geom, const char *p, const char *end)
static void geom_set_curve_degree(Geometry *geom, const char *p, const char *end)
StringRef read_next_line(StringRef &buffer)
static void geom_update_smooth_group(const char *p, const char *end, bool &r_state_shaded_smooth)
static void geom_update_group(const StringRef rest_line, std::string &r_group_name)
static Geometry * geom_set_curve_type(Geometry *geom, const char *p, const char *end, const StringRef group_name, Vector< std::unique_ptr< Geometry > > &r_all_geometries)
static const std::pair< StringRef, int > unsupported_texture_options[]
const char * parse_float(const char *p, const char *end, float fallback, float &dst, bool skip_space, bool require_trailing_space)
static void geom_add_polygon(Geometry *geom, const char *p, const char *end, const GlobalVertices &global_vertices, const int material_index, const int group_index, const bool shaded_smooth)
static Geometry * create_geometry(Geometry *const prev_geometry, const eGeometryType new_type, StringRef name, Vector< std::unique_ptr< Geometry > > &r_all_geometries)
VecBase< float, 3 > float3
void track_all_vertices(int count)
Vector< std::string > material_order_
Vector< FaceCorner > face_corners_
Map< std::string, int > group_indices_
NurbsElement nurbs_element_
Vector< std::string > group_order_
Map< std::string, int > material_indices_
void track_vertex_index(int index)
std::string geometry_name_
Vector< FaceElem > face_elements_
void set_vertex_color(size_t index, float3 color)
Vector< float3 > vertices
Vector< float2 > uv_vertices
Vector< float3 > vert_normals
Vector< float3 > mrgb_block
Vector< int > curv_indices