diff options
author | Iyad Ahmed <iyadahmed430@gmail.com> | 2022-06-06 20:57:38 +0300 |
---|---|---|
committer | Aras Pranckevicius <aras@nesnausk.org> | 2022-06-06 20:57:38 +0300 |
commit | 7c511f1b47d857f37aa36ee6ed8107cb88eb5c39 (patch) | |
tree | d376a5e21bc21f40e0b062f9623887f4018ed61a /source/blender | |
parent | 14fc89f38f0e3ce00e4fd6fffd72eea5d998af5a (diff) |
STL: Add new C++ based STL importer
A new experimentatl STL importer, written in C++. Roughly 7-9x faster than the
Python based one.
Reviewed By: Aras Pranckevicius, Hans Goudey.
Differential Revision: https://developer.blender.org/D14941
Diffstat (limited to 'source/blender')
30 files changed, 925 insertions, 94 deletions
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt index ef093a01ff8..98438c3e959 100644 --- a/source/blender/editors/io/CMakeLists.txt +++ b/source/blender/editors/io/CMakeLists.txt @@ -13,6 +13,7 @@ set(INC ../../io/gpencil ../../io/usd ../../io/wavefront_obj + ../../io/stl ../../makesdna ../../makesrna ../../windowmanager @@ -33,6 +34,7 @@ set(SRC io_obj.c io_ops.c io_usd.c + io_stl_ops.c io_alembic.h io_cache.h @@ -41,12 +43,14 @@ set(SRC io_obj.h io_ops.h io_usd.h + io_stl_ops.h ) set(LIB bf_blenkernel bf_blenlib bf_wavefront_obj + bf_stl ) if(WITH_OPENCOLLADA) diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c index 59e8c20da04..05bccce7948 100644 --- a/source/blender/editors/io/io_obj.c +++ b/source/blender/editors/io/io_obj.c @@ -31,28 +31,11 @@ #include "DEG_depsgraph.h" +#include "IO_orientation.h" #include "IO_path_util_types.h" #include "IO_wavefront_obj.h" #include "io_obj.h" -static const EnumPropertyItem io_obj_transform_axis_forward[] = { - {OBJ_AXIS_X_FORWARD, "X_FORWARD", 0, "X", "Positive X axis"}, - {OBJ_AXIS_Y_FORWARD, "Y_FORWARD", 0, "Y", "Positive Y axis"}, - {OBJ_AXIS_Z_FORWARD, "Z_FORWARD", 0, "Z", "Positive Z axis"}, - {OBJ_AXIS_NEGATIVE_X_FORWARD, "NEGATIVE_X_FORWARD", 0, "-X", "Negative X axis"}, - {OBJ_AXIS_NEGATIVE_Y_FORWARD, "NEGATIVE_Y_FORWARD", 0, "-Y", "Negative Y axis"}, - {OBJ_AXIS_NEGATIVE_Z_FORWARD, "NEGATIVE_Z_FORWARD", 0, "-Z", "Negative Z axis"}, - {0, NULL, 0, NULL, NULL}}; - -static const EnumPropertyItem io_obj_transform_axis_up[] = { - {OBJ_AXIS_X_UP, "X_UP", 0, "X", "Positive X axis"}, - {OBJ_AXIS_Y_UP, "Y_UP", 0, "Y", "Positive Y axis"}, - {OBJ_AXIS_Z_UP, "Z_UP", 0, "Z", "Positive Z axis"}, - {OBJ_AXIS_NEGATIVE_X_UP, "NEGATIVE_X_UP", 0, "-X", "Negative X axis"}, - {OBJ_AXIS_NEGATIVE_Y_UP, "NEGATIVE_Y_UP", 0, "-Y", "Negative Y axis"}, - {OBJ_AXIS_NEGATIVE_Z_UP, "NEGATIVE_Z_UP", 0, "-Z", "Negative Z axis"}, - {0, NULL, 0, NULL, NULL}}; - static const EnumPropertyItem io_obj_export_evaluation_mode[] = { {DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"}, {DAG_EVAL_VIEWPORT, @@ -296,13 +279,9 @@ void WM_OT_obj_export(struct wmOperatorType *ot) INT_MIN, INT_MAX); /* Object transform options. */ - RNA_def_enum(ot->srna, - "forward_axis", - io_obj_transform_axis_forward, - OBJ_AXIS_NEGATIVE_Z_FORWARD, - "Forward Axis", - ""); - RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", ""); + RNA_def_enum( + ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "Forward Axis", ""); + RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", ""); RNA_def_float(ot->srna, "scaling_factor", 1.0f, @@ -480,13 +459,9 @@ void WM_OT_obj_import(struct wmOperatorType *ot) "Resize the objects to keep bounding box under this value. Value 0 disables clamping", 0.0f, 1000.0f); - RNA_def_enum(ot->srna, - "forward_axis", - io_obj_transform_axis_forward, - OBJ_AXIS_NEGATIVE_Z_FORWARD, - "Forward Axis", - ""); - RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", ""); + RNA_def_enum( + ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "Forward Axis", ""); + RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", ""); RNA_def_boolean(ot->srna, "validate_meshes", false, diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c index 094f89d1540..098186a75e3 100644 --- a/source/blender/editors/io/io_ops.c +++ b/source/blender/editors/io/io_ops.c @@ -24,6 +24,7 @@ #include "io_cache.h" #include "io_gpencil.h" #include "io_obj.h" +#include "io_stl_ops.h" void ED_operatortypes_io(void) { @@ -60,4 +61,6 @@ void ED_operatortypes_io(void) WM_operatortype_append(WM_OT_obj_export); WM_operatortype_append(WM_OT_obj_import); + + WM_operatortype_append(WM_OT_stl_import); } diff --git a/source/blender/editors/io/io_stl_ops.c b/source/blender/editors/io/io_stl_ops.c new file mode 100644 index 00000000000..d5993bc4f37 --- /dev/null +++ b/source/blender/editors/io/io_stl_ops.c @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup editor/io + */ + +#include "BKE_context.h" +#include "BKE_report.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "DNA_space_types.h" + +#include "ED_outliner.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "IO_stl.h" +#include "io_stl_ops.h" + +static int wm_stl_import_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + return WM_operator_filesel(C, op, event); +} + +static int wm_stl_import_execute(bContext *C, wmOperator *op) +{ + struct STLImportParams params; + params.forward_axis = RNA_enum_get(op->ptr, "forward_axis"); + params.up_axis = RNA_enum_get(op->ptr, "up_axis"); + params.use_facet_normal = RNA_boolean_get(op->ptr, "use_facet_normal"); + params.use_scene_unit = RNA_boolean_get(op->ptr, "use_scene_unit"); + params.global_scale = RNA_float_get(op->ptr, "global_scale"); + params.use_mesh_validate = RNA_boolean_get(op->ptr, "use_mesh_validate"); + + int files_len = RNA_collection_length(op->ptr, "files"); + + if (files_len) { + PointerRNA fileptr; + PropertyRNA *prop; + char dir_only[FILE_MAX], file_only[FILE_MAX]; + + RNA_string_get(op->ptr, "directory", dir_only); + prop = RNA_struct_find_property(op->ptr, "files"); + for (int i = 0; i < files_len; i++) { + RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr); + RNA_string_get(&fileptr, "name", file_only); + BLI_join_dirfile(params.filepath, sizeof(params.filepath), dir_only, file_only); + STL_import(C, ¶ms); + } + } + else if (RNA_struct_property_is_set(op->ptr, "filepath")) { + RNA_string_get(op->ptr, "filepath", params.filepath); + STL_import(C, ¶ms); + } + else { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + Scene *scene = CTX_data_scene(C); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); + ED_outliner_select_sync_from_object_tag(C); + + return OPERATOR_FINISHED; +} + +static bool wm_stl_import_check(bContext *UNUSED(C), wmOperator *op) +{ + const int num_axes = 3; + /* Both forward and up axes cannot be the same (or same except opposite sign). */ + if (RNA_enum_get(op->ptr, "forward_axis") % num_axes == + (RNA_enum_get(op->ptr, "up_axis") % num_axes)) { + RNA_enum_set(op->ptr, "up_axis", RNA_enum_get(op->ptr, "up_axis") % num_axes + 1); + return true; + } + return false; +} + +void WM_OT_stl_import(struct wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Import STL"; + ot->description = "Import an STL file as an object"; + ot->idname = "WM_OT_stl_import"; + + ot->invoke = wm_stl_import_invoke; + ot->exec = wm_stl_import_execute; + ot->poll = WM_operator_winactive; + ot->check = wm_stl_import_check; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER, + FILE_BLENDER, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY | + WM_FILESEL_SHOW_PROPS, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); + + RNA_def_float(ot->srna, "global_scale", 1.0f, 1e-6f, 1e6f, "Scale", "", 0.001f, 1000.0f); + RNA_def_boolean(ot->srna, + "use_scene_unit", + false, + "Scene Unit", + "Apply current scene's unit (as defined by unit scale) to imported data"); + RNA_def_boolean(ot->srna, + "use_facet_normal", + false, + "Facet Normals", + "Use (import) facet normals (note that this will still give flat shading)"); + RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", ""); + RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", ""); + RNA_def_boolean(ot->srna, + "use_mesh_validate", + false, + "Validate Mesh", + "Validate and correct imported mesh (slow)"); + + /* Only show .stl files by default. */ + prop = RNA_def_string(ot->srna, "filter_glob", "*.stl", 0, "Extension Filter", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); +} diff --git a/source/blender/editors/io/io_stl_ops.h b/source/blender/editors/io/io_stl_ops.h new file mode 100644 index 00000000000..8f548f75985 --- /dev/null +++ b/source/blender/editors/io/io_stl_ops.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup editor/io + */ + +#pragma once + +struct wmOperatorType; + +void WM_OT_stl_export(struct wmOperatorType *ot); +void WM_OT_stl_import(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 7417f1bdb12..183af0c14f5 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -2803,7 +2803,7 @@ int ED_path_extension_type(const char *path) return FILE_TYPE_ARCHIVE; } if (BLI_path_extension_check_n( - path, ".obj", ".mtl", ".3ds", ".fbx", ".glb", ".gltf", ".svg", NULL)) { + path, ".obj", ".mtl", ".3ds", ".fbx", ".glb", ".gltf", ".svg", ".stl", NULL)) { return FILE_TYPE_OBJECT_IO; } if (BLI_path_extension_check_array(path, imb_ext_image)) { diff --git a/source/blender/io/CMakeLists.txt b/source/blender/io/CMakeLists.txt index b5f2694c2da..a376ee99d77 100644 --- a/source/blender/io/CMakeLists.txt +++ b/source/blender/io/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(common) add_subdirectory(wavefront_obj) +add_subdirectory(stl) if(WITH_ALEMBIC) add_subdirectory(alembic) diff --git a/source/blender/io/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt index e80bd850825..a6818c0bf5d 100644 --- a/source/blender/io/common/CMakeLists.txt +++ b/source/blender/io/common/CMakeLists.txt @@ -8,6 +8,7 @@ set(INC ../../depsgraph ../../makesdna ../../../../intern/guardedalloc + ../../makesrna ) set(INC_SYS @@ -19,12 +20,14 @@ set(SRC intern/dupli_persistent_id.cc intern/object_identifier.cc intern/path_util.cc + intern/orientation.c IO_abstract_hierarchy_iterator.h IO_dupli_persistent_id.hh IO_path_util.hh IO_path_util_types.h IO_types.h + IO_orientation.h intern/dupli_parent_finder.hh ) diff --git a/source/blender/io/common/IO_orientation.h b/source/blender/io/common/IO_orientation.h new file mode 100644 index 00000000000..09fcbc7045c --- /dev/null +++ b/source/blender/io/common/IO_orientation.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "RNA_types.h" + +typedef enum { + IO_AXIS_X = 0, + IO_AXIS_Y = 1, + IO_AXIS_Z = 2, + IO_AXIS_NEGATIVE_X = 3, + IO_AXIS_NEGATIVE_Y = 4, + IO_AXIS_NEGATIVE_Z = 5, +} eIOAxis; + +extern const EnumPropertyItem io_transform_axis[]; diff --git a/source/blender/io/common/intern/orientation.c b/source/blender/io/common/intern/orientation.c new file mode 100644 index 00000000000..0ffbaa8fe8e --- /dev/null +++ b/source/blender/io/common/intern/orientation.c @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "RNA_types.h" + +#include "IO_orientation.h" + +const EnumPropertyItem io_transform_axis[] = { + {IO_AXIS_X, "X", 0, "X", "Positive X axis"}, + {IO_AXIS_Y, "Y", 0, "Y", "Positive Y axis"}, + {IO_AXIS_Z, "Z", 0, "Z", "Positive Z axis"}, + {IO_AXIS_NEGATIVE_X, "NEGATIVE_X", 0, "-X", "Negative X axis"}, + {IO_AXIS_NEGATIVE_Y, "NEGATIVE_Y", 0, "-Y", "Negative Y axis"}, + {IO_AXIS_NEGATIVE_Z, "NEGATIVE_Z", 0, "-Z", "Negative Z axis"}, + {0, NULL, 0, NULL, NULL}}; diff --git a/source/blender/io/stl/CMakeLists.txt b/source/blender/io/stl/CMakeLists.txt new file mode 100644 index 00000000000..e0c48bbbf7e --- /dev/null +++ b/source/blender/io/stl/CMakeLists.txt @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(INC + . + ./importer + ../common + ../../blenkernel + ../../blenlib + ../../bmesh + ../../bmesh/intern + ../../depsgraph + ../../editors/include + ../../makesdna + ../../makesrna + ../../nodes + ../../windowmanager + ../../../../extern/fast_float + ../../../../intern/guardedalloc +) + +set(INC_SYS + +) + +set(SRC + IO_stl.cc + importer/stl_import_mesh.cc + importer/stl_import_ascii_reader.cc + importer/stl_import_binary_reader.cc + importer/stl_import.cc + + IO_stl.h + importer/stl_import_mesh.hh + importer/stl_import_ascii_reader.hh + importer/stl_import_binary_reader.hh + importer/stl_import.hh +) + +set(LIB + bf_blenkernel + bf_io_common +) + +blender_add_lib(bf_stl "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/io/stl/IO_stl.cc b/source/blender/io/stl/IO_stl.cc new file mode 100644 index 00000000000..b26c1533692 --- /dev/null +++ b/source/blender/io/stl/IO_stl.cc @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#include "BLI_timeit.hh" + +#include "IO_stl.h" +#include "stl_import.hh" + +void STL_import(bContext *C, const struct STLImportParams *import_params) +{ + SCOPED_TIMER("STL Import"); + blender::io::stl::importer_main(C, *import_params); +} diff --git a/source/blender/io/stl/IO_stl.h b/source/blender/io/stl/IO_stl.h new file mode 100644 index 00000000000..bbe537948e8 --- /dev/null +++ b/source/blender/io/stl/IO_stl.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#pragma once + +#include "BKE_context.h" +#include "BLI_path_util.h" +#include "IO_orientation.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct STLImportParams { + /** Full path to the source STL file to import. */ + char filepath[FILE_MAX]; + eIOAxis forward_axis; + eIOAxis up_axis; + bool use_facet_normal; + bool use_scene_unit; + float global_scale; + bool use_mesh_validate; +}; + +/** + * C-interface for the importer. + */ +void STL_import(bContext *C, const struct STLImportParams *import_params); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/io/stl/importer/stl_import.cc b/source/blender/io/stl/importer/stl_import.cc new file mode 100644 index 00000000000..f358598a216 --- /dev/null +++ b/source/blender/io/stl/importer/stl_import.cc @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#include <cstdio> + +#include "BKE_customdata.h" +#include "BKE_layer.h" +#include "BKE_mesh.h" +#include "BKE_object.h" + +#include "DNA_collection_types.h" +#include "DNA_scene_types.h" + +#include "BLI_fileops.hh" +#include "BLI_math_vector.h" +#include "BLI_memory_utils.hh" + +#include "DNA_object_types.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +#include "stl_import.hh" +#include "stl_import_ascii_reader.hh" +#include "stl_import_binary_reader.hh" + +namespace blender::io::stl { + +void importer_main(bContext *C, const STLImportParams &import_params) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + importer_main(bmain, scene, view_layer, import_params); +} + +void importer_main(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + const STLImportParams &import_params) +{ + FILE *file = BLI_fopen(import_params.filepath, "rb"); + if (!file) { + fprintf(stderr, "Failed to open STL file:'%s'.\n", import_params.filepath); + return; + } + BLI_SCOPED_DEFER([&]() { fclose(file); }); + + /* Detect STL file type by comparing file size with expected file size, + * could check if file starts with "solid", but some files do not adhere, + * this is the same as the old Python importer. + */ + uint32_t num_tri = 0; + size_t file_size = BLI_file_size(import_params.filepath); + fseek(file, BINARY_HEADER_SIZE, SEEK_SET); + fread(&num_tri, sizeof(uint32_t), 1, file); + bool is_ascii_stl = (file_size != (BINARY_HEADER_SIZE + 4 + BINARY_STRIDE * num_tri)); + + /* Name used for both mesh and object. */ + char ob_name[FILE_MAX]; + BLI_strncpy(ob_name, BLI_path_basename(import_params.filepath), FILE_MAX); + BLI_path_extension_replace(ob_name, FILE_MAX, ""); + + Mesh *mesh; + if (is_ascii_stl) { + mesh = read_stl_ascii(import_params.filepath, bmain, ob_name, import_params.use_facet_normal); + } + else { + mesh = read_stl_binary(file, bmain, ob_name, import_params.use_facet_normal); + } + + if (import_params.use_mesh_validate) { + bool verbose_validate = false; +#ifdef DEBUG + verbose_validate = true; +#endif + BKE_mesh_validate(mesh, verbose_validate, false); + } + + BKE_view_layer_base_deselect_all(view_layer); + LayerCollection *lc = BKE_layer_collection_get_active(view_layer); + Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name); + BKE_mesh_assign_object(bmain, obj, mesh); + BKE_collection_object_add(bmain, lc->collection, obj); + Base *base = BKE_view_layer_base_find(view_layer, obj); + BKE_view_layer_base_select_and_set_active(view_layer, base); + + float global_scale = import_params.global_scale; + if ((scene->unit.system != USER_UNIT_NONE) && import_params.use_scene_unit) { + global_scale *= scene->unit.scale_length; + } + float scale_vec[3] = {global_scale, global_scale, global_scale}; + float obmat3x3[3][3]; + unit_m3(obmat3x3); + float obmat4x4[4][4]; + unit_m4(obmat4x4); + /* +Y-forward and +Z-up are the Blender's default axis settings. */ + mat3_from_axis_conversion( + IO_AXIS_Y, IO_AXIS_Z, import_params.forward_axis, import_params.up_axis, obmat3x3); + copy_m4_m3(obmat4x4, obmat3x3); + rescale_m4(obmat4x4, scale_vec); + BKE_object_apply_mat4(obj, obmat4x4, true, false); + + DEG_id_tag_update(&lc->collection->id, ID_RECALC_COPY_ON_WRITE); + int flags = ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION | + ID_RECALC_BASE_FLAGS; + DEG_id_tag_update_ex(bmain, &obj->id, flags); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + DEG_relations_tag_update(bmain); +} +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import.hh b/source/blender/io/stl/importer/stl_import.hh new file mode 100644 index 00000000000..377544c26af --- /dev/null +++ b/source/blender/io/stl/importer/stl_import.hh @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#pragma once + +#include "IO_stl.h" + +namespace blender::io::stl { + +/* Main import function used from within Blender. */ +void importer_main(bContext *C, const STLImportParams &import_params); + +/* Used from tests, where full bContext does not exist. */ +void importer_main(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + const STLImportParams &import_params); + +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.cc b/source/blender/io/stl/importer/stl_import_ascii_reader.cc new file mode 100644 index 00000000000..2f2495fa4ca --- /dev/null +++ b/source/blender/io/stl/importer/stl_import_ascii_reader.cc @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#include <cstdint> +#include <cstdio> + +#include "BKE_mesh.h" + +#include "BLI_fileops.hh" +#include "BLI_memory_utils.hh" +#include "BLI_string_ref.hh" + +#include "DNA_mesh_types.h" + +/* NOTE: we could use C++17 <charconv> from_chars to parse + * floats, but even if some compilers claim full support, + * their standard libraries are not quite there yet. + * LLVM/libc++ only has a float parser since LLVM 14, + * and gcc/libstdc++ since 11.1. So until at least these are + * the minimum spec, use an external library. */ +#include "fast_float.h" + +#include "stl_import.hh" +#include "stl_import_mesh.hh" + +namespace blender::io::stl { + +class StringBuffer { + private: + char *start; + const char *end; + + public: + StringBuffer(char *buf, size_t len) + { + start = buf; + end = start + len; + } + + bool is_empty() const + { + return start == end; + } + + void drop_leading_control_chars() + { + while ((start < end) && (*start) <= ' ') { + start++; + } + } + + void drop_leading_non_control_chars() + { + while ((start < end) && (*start) > ' ') { + start++; + } + } + + void drop_line() + { + while (start < end && *start != '\n') { + start++; + } + } + + bool parse_token(const char *token, size_t token_length) + { + drop_leading_control_chars(); + if (end - start < token_length + 1) { + return false; + } + if (memcmp(start, token, token_length) != 0) { + return false; + } + if (start[token_length] > ' ') { + return false; + } + start += token_length + 1; + return true; + } + + void drop_token() + { + drop_leading_non_control_chars(); + drop_leading_control_chars(); + } + + void parse_float(float &out) + { + drop_leading_control_chars(); + /* Skip '+' */ + if (start < end && *start == '+') { + start++; + } + fast_float::from_chars_result res = fast_float::from_chars(start, end, out); + if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) { + out = 0.0f; + } + start = const_cast<char *>(res.ptr); + } +}; + +static inline void parse_float3(StringBuffer &buf, float out[3]) +{ + for (int i = 0; i < 3; i++) { + buf.parse_float(out[i]); + } +} + +Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals) +{ + size_t buffer_len; + void *buffer = BLI_file_read_text_as_mem(filepath, 0, &buffer_len); + if (buffer == nullptr) { + fprintf(stderr, "STL Importer: cannot read from ASCII STL file: '%s'\n", filepath); + return BKE_mesh_add(bmain, mesh_name); + } + BLI_SCOPED_DEFER([&]() { MEM_freeN(buffer); }); + + int num_reserved_tris = 1024; + + StringBuffer str_buf(static_cast<char *>(buffer), buffer_len); + STLMeshHelper stl_mesh(num_reserved_tris, use_custom_normals); + float triangle_buf[3][3]; + float custom_normal_buf[3]; + str_buf.drop_line(); /* Skip header line */ + while (!str_buf.is_empty()) { + if (str_buf.parse_token("vertex", 6)) { + parse_float3(str_buf, triangle_buf[0]); + if (str_buf.parse_token("vertex", 6)) { + parse_float3(str_buf, triangle_buf[1]); + } + if (str_buf.parse_token("vertex", 6)) { + parse_float3(str_buf, triangle_buf[2]); + } + if (use_custom_normals) { + stl_mesh.add_triangle( + triangle_buf[0], triangle_buf[1], triangle_buf[2], custom_normal_buf); + } + else { + stl_mesh.add_triangle(triangle_buf[0], triangle_buf[1], triangle_buf[2]); + } + } + else if (str_buf.parse_token("facet", 5)) { + str_buf.drop_token(); /* Expecting "normal" */ + parse_float3(str_buf, custom_normal_buf); + } + else { + str_buf.drop_token(); + } + } + + return stl_mesh.to_mesh(bmain, mesh_name); +} + +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.hh b/source/blender/io/stl/importer/stl_import_ascii_reader.hh new file mode 100644 index 00000000000..b0216d98496 --- /dev/null +++ b/source/blender/io/stl/importer/stl_import_ascii_reader.hh @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#pragma once + +#include <cstdio> + +#include "BKE_mesh.h" + +#include "stl_import.hh" + +/* ASCII STL spec.: + * solid name + * facet normal ni nj nk + * outer loop + * vertex v1x v1y v1z + * vertex v2x v2y v2z + * vertex v3x v3y v3z + * endloop + * endfacet + * ... + * endsolid name + */ + +namespace blender::io::stl { + +Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals); + +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.cc b/source/blender/io/stl/importer/stl_import_binary_reader.cc new file mode 100644 index 00000000000..c05b6ad1426 --- /dev/null +++ b/source/blender/io/stl/importer/stl_import_binary_reader.cc @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#include <cstdint> +#include <cstdio> + +#include "BKE_main.h" +#include "BKE_mesh.h" + +#include "BLI_array.hh" +#include "BLI_memory_utils.hh" + +#include "DNA_mesh_types.h" + +#include "stl_import_binary_reader.hh" +#include "stl_import_mesh.hh" + +namespace blender::io::stl { + +#pragma pack(push, 1) +struct STLBinaryTriangle { + float normal[3]; + float v1[3], v2[3], v3[3]; + uint16_t attribute_byte_count; +}; +#pragma pack(pop) + +Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals) +{ + const int chunk_size = 1024; + uint32_t num_tris = 0; + fseek(file, BINARY_HEADER_SIZE, SEEK_SET); + fread(&num_tris, sizeof(uint32_t), 1, file); + if (num_tris == 0) { + return BKE_mesh_add(bmain, mesh_name); + } + + Array<STLBinaryTriangle> tris_buf(chunk_size); + STLMeshHelper stl_mesh(num_tris, use_custom_normals); + size_t num_read_tris; + while (num_read_tris = fread(tris_buf.data(), sizeof(STLBinaryTriangle), chunk_size, file)) { + for (size_t i = 0; i < num_read_tris; i++) { + if (use_custom_normals) { + stl_mesh.add_triangle(tris_buf[i].v1, tris_buf[i].v2, tris_buf[i].v3, tris_buf[i].normal); + } + else { + stl_mesh.add_triangle(tris_buf[i].v1, tris_buf[i].v2, tris_buf[i].v3); + } + } + } + + return stl_mesh.to_mesh(bmain, mesh_name); +} + +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.hh b/source/blender/io/stl/importer/stl_import_binary_reader.hh new file mode 100644 index 00000000000..71d5dbbbe58 --- /dev/null +++ b/source/blender/io/stl/importer/stl_import_binary_reader.hh @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#pragma once + +#include <cstdio> + +#include "BKE_mesh.h" + +/* Binary STL spec.: + * UINT8[80] – Header - 80 bytes + * UINT32 – Number of triangles - 4 bytes + * For each triangle - 50 bytes: + * REAL32[3] – Normal vector - 12 bytes + * REAL32[3] – Vertex 1 - 12 bytes + * REAL32[3] – Vertex 2 - 12 bytes + * REAL32[3] – Vertex 3 - 12 bytes + * UINT16 – Attribute byte count - 2 bytes + */ + +namespace blender::io::stl { + +const size_t BINARY_HEADER_SIZE = 80; +const size_t BINARY_STRIDE = 12 * 4 + 2; + +Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals); + +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc new file mode 100644 index 00000000000..5f5c2624414 --- /dev/null +++ b/source/blender/io/stl/importer/stl_import_mesh.cc @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#include "BKE_customdata.h" +#include "BKE_lib_id.h" +#include "BKE_main.h" +#include "BKE_mesh.h" + +#include "BLI_array.hh" +#include "BLI_math_vector.h" +#include "BLI_math_vector.hh" +#include "BLI_task.hh" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "stl_import_mesh.hh" + +namespace blender::io::stl { + +STLMeshHelper::STLMeshHelper(int num_tris, bool use_custom_normals) + : m_use_custom_normals(use_custom_normals) +{ + m_num_degenerate_tris = 0; + m_num_duplicate_tris = 0; + m_tris.reserve(num_tris); + /* Upper bound (all vertices are unique). */ + m_verts.reserve(num_tris * 3); + if (use_custom_normals) { + m_loop_normals.reserve(num_tris * 3); + } +} + +bool STLMeshHelper::add_triangle(const float3 &a, const float3 &b, const float3 &c) +{ + int v1_id = m_verts.index_of_or_add(a); + int v2_id = m_verts.index_of_or_add(b); + int v3_id = m_verts.index_of_or_add(c); + if ((v1_id == v2_id) || (v1_id == v3_id) || (v2_id == v3_id)) { + m_num_degenerate_tris++; + return false; + } + if (!m_tris.add({v1_id, v2_id, v3_id})) { + m_num_duplicate_tris++; + return false; + } + return true; +} + +void STLMeshHelper::add_triangle(const float3 &a, + const float3 &b, + const float3 &c, + const float3 &custom_normal) +{ + if (add_triangle(a, b, c)) { + m_loop_normals.append_n_times(custom_normal, 3); + } +} + +Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) +{ + if (m_num_degenerate_tris > 0) { + std::cout << "STL Importer: " << m_num_degenerate_tris << "degenerate triangles were removed" + << std::endl; + } + if (m_num_duplicate_tris > 0) { + std::cout << "STL Importer: " << m_num_duplicate_tris << "duplicate triangles were removed" + << std::endl; + } + + Mesh *mesh = BKE_mesh_add(bmain, mesh_name); + /* User count is already 1 here, but will be set later in #BKE_mesh_assign_object. */ + id_us_min(&mesh->id); + + mesh->totvert = m_verts.size(); + mesh->mvert = static_cast<MVert *>( + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert)); + for (int i = 0; i < mesh->totvert; i++) { + copy_v3_v3(mesh->mvert[i].co, m_verts[i]); + } + + mesh->totpoly = m_tris.size(); + mesh->totloop = m_tris.size() * 3; + mesh->mpoly = static_cast<MPoly *>( + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly)); + mesh->mloop = static_cast<MLoop *>( + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop)); + + threading::parallel_for(m_tris.index_range(), 2048, [&](IndexRange tris_range) { + for (const int i : tris_range) { + mesh->mpoly[i].loopstart = 3 * i; + mesh->mpoly[i].totloop = 3; + + mesh->mloop[3 * i].v = m_tris[i].v1; + mesh->mloop[3 * i + 1].v = m_tris[i].v2; + mesh->mloop[3 * i + 2].v = m_tris[i].v3; + } + }); + + /* NOTE: edges must be calculated first before setting custom normals. */ + BKE_mesh_calc_edges(mesh, false, false); + + if (m_use_custom_normals && m_loop_normals.size() == mesh->totloop) { + BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(m_loop_normals.data())); + mesh->flag |= ME_AUTOSMOOTH; + } + + return mesh; +} + +} // namespace blender::io::stl diff --git a/source/blender/io/stl/importer/stl_import_mesh.hh b/source/blender/io/stl/importer/stl_import_mesh.hh new file mode 100644 index 00000000000..7827d2a408c --- /dev/null +++ b/source/blender/io/stl/importer/stl_import_mesh.hh @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup stl + */ + +#pragma once + +#include <cstdint> + +#include "BLI_math_vec_types.hh" +#include "BLI_set.hh" +#include "BLI_vector.hh" +#include "BLI_vector_set.hh" + +#include "DNA_mesh_types.h" + +namespace blender::io::stl { +class Triangle { + public: + int v1, v2, v3; + /* Based on an old version of Python's frozenset hash + * https://web.archive.org/web/20220520211017/https://stackoverflow.com/questions/20832279/python-frozenset-hashing-algorithm-implementation + */ + uint64_t hash() const + { + uint64_t res = 1927868237UL; + res *= 4; + res ^= (v1 ^ (v1 << 16) ^ 89869747UL) * 3644798167UL; + res ^= (v2 ^ (v2 << 16) ^ 89869747UL) * 3644798167UL; + res ^= (v3 ^ (v3 << 16) ^ 89869747UL) * 3644798167UL; + return res * 69069U + 907133923UL; + } + friend bool operator==(const Triangle &a, const Triangle &b) + { + bool i = (a.v1 == b.v1) && (a.v2 == b.v2) && (a.v3 == b.v3); + bool j = (a.v1 == b.v1) && (a.v3 == b.v2) && (a.v2 == b.v3); + bool k = (a.v2 == b.v1) && (a.v1 == b.v2) && (a.v3 == b.v3); + + bool l = (a.v2 == b.v1) && (a.v3 == b.v2) && (a.v1 == b.v3); + bool m = (a.v3 == b.v1) && (a.v1 == b.v2) && (a.v2 == b.v3); + bool n = (a.v3 == b.v1) && (a.v2 == b.v2) && (a.v1 == b.v3); + + return i || j || k || l || m || n; + } +}; + +class STLMeshHelper { + private: + VectorSet<float3> m_verts; + VectorSet<Triangle> m_tris; + Vector<float3> m_loop_normals; + int m_num_degenerate_tris; + int m_num_duplicate_tris; + const bool m_use_custom_normals; + + public: + STLMeshHelper(int num_tris, bool use_custom_normals); + + /* Creates a new triangle from specified vertex locations, + * duplicate vertices and triangles are merged. + */ + bool add_triangle(const float3 &a, const float3 &b, const float3 &c); + void add_triangle(const float3 &a, + const float3 &b, + const float3 &c, + const float3 &custom_normal); + Mesh *to_mesh(Main *bmain, char *mesh_name); +}; + +} // namespace blender::io::stl diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h index bebad06d37f..0a78cdc714d 100644 --- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h +++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h @@ -9,30 +9,13 @@ #include "BKE_context.h" #include "BLI_path_util.h" #include "DEG_depsgraph.h" +#include "IO_orientation.h" #include "IO_path_util_types.h" #ifdef __cplusplus extern "C" { #endif -typedef enum { - OBJ_AXIS_X_UP = 0, - OBJ_AXIS_Y_UP = 1, - OBJ_AXIS_Z_UP = 2, - OBJ_AXIS_NEGATIVE_X_UP = 3, - OBJ_AXIS_NEGATIVE_Y_UP = 4, - OBJ_AXIS_NEGATIVE_Z_UP = 5, -} eTransformAxisUp; - -typedef enum { - OBJ_AXIS_X_FORWARD = 0, - OBJ_AXIS_Y_FORWARD = 1, - OBJ_AXIS_Z_FORWARD = 2, - OBJ_AXIS_NEGATIVE_X_FORWARD = 3, - OBJ_AXIS_NEGATIVE_Y_FORWARD = 4, - OBJ_AXIS_NEGATIVE_Z_FORWARD = 5, -} eTransformAxisForward; - static const int TOTAL_AXES = 3; struct OBJExportParams { @@ -52,8 +35,8 @@ struct OBJExportParams { int end_frame; /* Geometry Transform options. */ - eTransformAxisForward forward_axis; - eTransformAxisUp up_axis; + eIOAxis forward_axis; + eIOAxis up_axis; float scaling_factor; /* File Write Options. */ @@ -86,8 +69,8 @@ struct OBJImportParams { char filepath[FILE_MAX]; /** Value 0 disables clamping. */ float clamp_size; - eTransformAxisForward forward_axis; - eTransformAxisUp up_axis; + eIOAxis forward_axis; + eIOAxis up_axis; bool validate_meshes; }; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc index 092ba24db64..8556d7c275c 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -117,13 +117,12 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval() return {triangulated, true}; } -void OBJMesh::set_world_axes_transform(const eTransformAxisForward forward, - const eTransformAxisUp up) +void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis up) { float axes_transform[3][3]; unit_m3(axes_transform); /* +Y-forward and +Z-up are the default Blender axis settings. */ - mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform); + mat3_from_axis_conversion(IO_AXIS_Y, IO_AXIS_Z, forward, up, axes_transform); /* mat3_from_axis_conversion returns a transposed matrix! */ transpose_m3(axes_transform); mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.obmat); diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh index f47ca423dbc..91213ec8152 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh @@ -256,6 +256,6 @@ class OBJMesh : NonCopyable { /** * Set the final transform after applying axes settings and an Object's world transform. */ - void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up); + void set_world_axes_transform(eIOAxis forward, eIOAxis up); }; } // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc index c247048ce13..c0c29fcfdf8 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc @@ -25,13 +25,12 @@ OBJCurve::OBJCurve(const Depsgraph *depsgraph, set_world_axes_transform(export_params.forward_axis, export_params.up_axis); } -void OBJCurve::set_world_axes_transform(const eTransformAxisForward forward, - const eTransformAxisUp up) +void OBJCurve::set_world_axes_transform(const eIOAxis forward, const eIOAxis up) { float axes_transform[3][3]; unit_m3(axes_transform); /* +Y-forward and +Z-up are the Blender's default axis settings. */ - mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform); + mat3_from_axis_conversion(IO_AXIS_Y, IO_AXIS_Z, forward, up, axes_transform); /* mat3_from_axis_conversion returns a transposed matrix! */ transpose_m3(axes_transform); mul_m4_m3m4(world_axes_transform_, axes_transform, export_object_eval_->obmat); diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh index fe826725daf..65389d44f59 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh @@ -56,7 +56,7 @@ class OBJCurve : NonCopyable { /** * Set the final transform after applying axes settings and an Object's world transform. */ - void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up); + void set_world_axes_transform(eIOAxis forward, eIOAxis up); }; } // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc index 7019e67419e..3c0ef646e13 100644 --- a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc +++ b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc @@ -99,11 +99,8 @@ void transform_object(Object *object, const OBJImportParams &import_params) float obmat[4][4]; unit_m4(obmat); /* +Y-forward and +Z-up are the default Blender axis settings. */ - mat3_from_axis_conversion(import_params.forward_axis, - import_params.up_axis, - OBJ_AXIS_Y_FORWARD, - OBJ_AXIS_Z_UP, - axes_transform); + mat3_from_axis_conversion( + import_params.forward_axis, import_params.up_axis, IO_AXIS_Y, IO_AXIS_Z, axes_transform); /* mat3_from_axis_conversion returns a transposed matrix! */ transpose_m3(axes_transform); copy_m4_m3(obmat, axes_transform); diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc index 8c49af90a82..b384d934c82 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -315,8 +315,8 @@ TEST_F(obj_exporter_regression_test, all_quads) TEST_F(obj_exporter_regression_test, fgons) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; compare_obj_export_to_golden( "io_tests/blend_geometry/fgons.blend", "io_tests/obj/fgons.obj", "", _export.params); @@ -325,8 +325,8 @@ TEST_F(obj_exporter_regression_test, fgons) TEST_F(obj_exporter_regression_test, edges) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; compare_obj_export_to_golden( "io_tests/blend_geometry/edges.blend", "io_tests/obj/edges.obj", "", _export.params); @@ -335,8 +335,8 @@ TEST_F(obj_exporter_regression_test, edges) TEST_F(obj_exporter_regression_test, vertices) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; compare_obj_export_to_golden( "io_tests/blend_geometry/vertices.blend", "io_tests/obj/vertices.obj", "", _export.params); @@ -355,8 +355,8 @@ TEST_F(obj_exporter_regression_test, non_uniform_scale) TEST_F(obj_exporter_regression_test, nurbs_as_nurbs) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_curves_as_nurbs = true; compare_obj_export_to_golden( @@ -366,8 +366,8 @@ TEST_F(obj_exporter_regression_test, nurbs_as_nurbs) TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_curves_as_nurbs = true; compare_obj_export_to_golden("io_tests/blend_geometry/nurbs_curves.blend", @@ -379,8 +379,8 @@ TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs) TEST_F(obj_exporter_regression_test, nurbs_as_mesh) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_curves_as_nurbs = false; compare_obj_export_to_golden( @@ -390,8 +390,8 @@ TEST_F(obj_exporter_regression_test, nurbs_as_mesh) TEST_F(obj_exporter_regression_test, cube_all_data_triangulated) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_triangulated_mesh = true; compare_obj_export_to_golden("io_tests/blend_geometry/cube_all_data.blend", @@ -403,8 +403,8 @@ TEST_F(obj_exporter_regression_test, cube_all_data_triangulated) TEST_F(obj_exporter_regression_test, cube_normal_edit) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; compare_obj_export_to_golden("io_tests/blend_geometry/cube_normal_edit.blend", "io_tests/obj/cube_normal_edit.obj", @@ -459,8 +459,8 @@ TEST_F(obj_exporter_regression_test, cubes_with_textures_relative) TEST_F(obj_exporter_regression_test, suzanne_all_data) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_smooth_groups = true; compare_obj_export_to_golden("io_tests/blend_geometry/suzanne_all_data.blend", @@ -491,8 +491,8 @@ TEST_F(obj_exporter_regression_test, all_curves_as_nurbs) TEST_F(obj_exporter_regression_test, all_objects) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_smooth_groups = true; compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend", "io_tests/obj/all_objects.obj", @@ -503,8 +503,8 @@ TEST_F(obj_exporter_regression_test, all_objects) TEST_F(obj_exporter_regression_test, all_objects_mat_groups) { OBJExportParamsDefault _export; - _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; - _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.forward_axis = IO_AXIS_Y; + _export.params.up_axis = IO_AXIS_Z; _export.params.export_smooth_groups = true; _export.params.export_material_groups = true; compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend", diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh index ef27a65fb4b..42f7620999d 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh @@ -17,8 +17,8 @@ struct OBJExportParamsDefault { params.start_frame = 0; params.end_frame = 1; - params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD; - params.up_axis = OBJ_AXIS_Y_UP; + params.forward_axis = IO_AXIS_NEGATIVE_Z; + params.up_axis = IO_AXIS_Y; params.scaling_factor = 1.f; params.apply_modifiers = true; diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc index d7f4ce3d773..48990975416 100644 --- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc @@ -55,8 +55,8 @@ class obj_importer_test : public BlendfileLoadingBaseTest { OBJImportParams params; params.clamp_size = 0; - params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD; - params.up_axis = OBJ_AXIS_Y_UP; + params.forward_axis = IO_AXIS_NEGATIVE_Z; + params.up_axis = IO_AXIS_Y; std::string obj_path = blender::tests::flags_test_asset_dir() + "/io_tests/obj/" + path; strncpy(params.filepath, obj_path.c_str(), FILE_MAX - 1); |