Blender V4.3
obj_exporter_tests.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include <gtest/gtest.h>
6#include <ios>
7#include <memory>
8#include <string>
9#include <system_error>
10
11#include "testing/testing.h"
13
14#include "BKE_appdir.hh"
15#include "BKE_blender_version.h"
16#include "BKE_main.hh"
17
18#include "BLI_fileops.h"
19#include "BLI_index_range.hh"
20#include "BLI_string.h"
21#include "BLI_string_utf8.h"
22#include "BLI_vector.hh"
23
24#include "BLO_readfile.hh"
25
26#include "DEG_depsgraph.hh"
27
29#include "obj_export_mesh.hh"
30#include "obj_export_nurbs.hh"
31#include "obj_exporter.hh"
32
33#include "obj_exporter_tests.hh"
34
35namespace blender::io::obj {
36/* Set this true to keep comparison-failing test output in temp file directory. */
37constexpr bool save_failing_test_output = false;
38
39/* This is also the test name. */
41 public:
45 bool load_file_and_depsgraph(const std::string &filepath,
46 const eEvaluationMode eval_mode = DAG_EVAL_VIEWPORT)
47 {
48 if (!blendfile_load(filepath.c_str())) {
49 return false;
50 }
51 depsgraph_create(eval_mode);
52 return true;
53 }
54};
55
56const std::string all_objects_file = "io_tests" SEP_STR "blend_scene" SEP_STR "all_objects.blend";
57
58TEST_F(OBJExportTest, filter_objects_curves_as_mesh)
59{
61 if (!load_file_and_depsgraph(all_objects_file)) {
62 ADD_FAILURE();
63 return;
64 }
65 auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
66 EXPECT_EQ(objmeshes.size(), 21);
67 EXPECT_EQ(objcurves.size(), 0);
68}
69
70TEST_F(OBJExportTest, filter_objects_curves_as_nurbs)
71{
73 if (!load_file_and_depsgraph(all_objects_file)) {
74 ADD_FAILURE();
75 return;
76 }
77 _export.params.export_curves_as_nurbs = true;
78 auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
79 EXPECT_EQ(objmeshes.size(), 18);
80 EXPECT_EQ(objcurves.size(), 3);
81}
82
83TEST_F(OBJExportTest, filter_objects_selected)
84{
86 if (!load_file_and_depsgraph(all_objects_file)) {
87 ADD_FAILURE();
88 return;
89 }
90 _export.params.export_selected_objects = true;
91 _export.params.export_curves_as_nurbs = true;
92 auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
93 EXPECT_EQ(objmeshes.size(), 1);
94 EXPECT_EQ(objcurves.size(), 0);
95}
96
97TEST(obj_exporter_utils, append_negative_frame_to_filename)
98{
99 const char path_original[FILE_MAX] = SEP_STR "my_file.obj";
100 const char path_truth[FILE_MAX] = SEP_STR "my_file-0012.obj";
101 const int frame = -12;
102 char path_with_frame[FILE_MAX] = {0};
103 const bool ok = append_frame_to_filename(path_original, frame, path_with_frame);
104 EXPECT_TRUE(ok);
105 EXPECT_STREQ(path_with_frame, path_truth);
106}
107
108TEST(obj_exporter_utils, append_positive_frame_to_filename)
109{
110 const char path_original[FILE_MAX] = SEP_STR "my_file.obj";
111 const char path_truth[FILE_MAX] = SEP_STR "my_file0012.obj";
112 const int frame = 12;
113 char path_with_frame[FILE_MAX] = {0};
114 const bool ok = append_frame_to_filename(path_original, frame, path_with_frame);
115 EXPECT_TRUE(ok);
116 EXPECT_STREQ(path_with_frame, path_truth);
117}
118
119TEST(obj_exporter_utils, append_large_positive_frame_to_filename)
120{
121 const char path_original[FILE_MAX] = SEP_STR "my_file.obj";
122 const char path_truth[FILE_MAX] = SEP_STR "my_file1234567.obj";
123 const int frame = 1234567;
124 char path_with_frame[FILE_MAX] = {0};
125 const bool ok = append_frame_to_filename(path_original, frame, path_with_frame);
126 EXPECT_TRUE(ok);
127 EXPECT_STREQ(path_with_frame, path_truth);
128}
129
130static std::string read_temp_file_in_string(const std::string &file_path)
131{
132 std::string res;
133 size_t buffer_len;
134 void *buffer = BLI_file_read_text_as_mem(file_path.c_str(), 0, &buffer_len);
135 if (buffer != nullptr) {
136 res.assign((const char *)buffer, buffer_len);
137 MEM_freeN(buffer);
138 }
139 return res;
140}
141
142class ObjExporterWriterTest : public testing::Test {
143 protected:
144 void SetUp() override
145 {
146 BKE_tempdir_init(nullptr);
147 }
148
149 void TearDown() override
150 {
152 }
153
155 {
156 /* Use Latin Capital Letter A with Ogonek, Cyrillic Capital Letter Zhe
157 * at the end, to test I/O on non-English file names. */
158 const char *const temp_file_path = "output\xc4\x84\xd0\x96.OBJ";
159
160 return std::string(BKE_tempdir_session()) + SEP_STR + std::string(temp_file_path);
161 }
162
163 std::unique_ptr<OBJWriter> init_writer(const OBJExportParams &params,
164 const std::string &out_filepath)
165 {
166 try {
167 auto writer = std::make_unique<OBJWriter>(out_filepath.c_str(), params);
168 return writer;
169 }
170 catch (const std::system_error &ex) {
171 std::cerr << ex.code().category().name() << ": " << ex.what() << ": " << ex.code().message()
172 << std::endl;
173 return nullptr;
174 }
175 }
176};
177
179{
180 /* Because testing doesn't fully initialize Blender, we need the following. */
181 BKE_tempdir_init(nullptr);
182 std::string out_file_path = get_temp_obj_filename();
183 {
185 std::unique_ptr<OBJWriter> writer = init_writer(_export.params, out_file_path);
186 if (!writer) {
187 ADD_FAILURE();
188 return;
189 }
190 writer->write_header();
191 }
192 const std::string result = read_temp_file_in_string(out_file_path);
193 using namespace std::string_literals;
194 ASSERT_EQ(result, "# Blender "s + BKE_blender_version_string() + "\n" + "# www.blender.org\n");
195}
196
198{
199 std::string out_file_path = get_temp_obj_filename();
200 {
202 std::unique_ptr<OBJWriter> writer = init_writer(_export.params, out_file_path);
203 if (!writer) {
204 ADD_FAILURE();
205 return;
206 }
207 writer->write_mtllib_name("/Users/blah.mtl");
208 writer->write_mtllib_name("\\C:\\blah.mtl");
209 }
210 const std::string result = read_temp_file_in_string(out_file_path);
211 ASSERT_EQ(result, "mtllib blah.mtl\nmtllib blah.mtl\n");
212}
213
214TEST(obj_exporter_writer, format_handler_buffer_chunking)
215{
216 /* Use a tiny buffer chunk size, so that the test below ends up creating several blocks. */
217 FormatHandler h(16);
218 h.write_obj_object("abc");
219 h.write_obj_object("abcd");
220 h.write_obj_object("abcde");
221 h.write_obj_object("abcdef");
222 h.write_obj_object("012345678901234567890123456789abcd");
223 h.write_obj_object("123");
228
229 size_t got_blocks = h.get_block_count();
230 ASSERT_EQ(got_blocks, 7);
231
232 std::string got_string = h.get_as_string();
233 using namespace std::string_literals;
234 const char *expected = R"(o abc
235o abcd
236o abcde
237o abcdef
238o 012345678901234567890123456789abcd
239o 123
240curv 0.0 1.0
241parm u 0.0
242)";
243 ASSERT_EQ(got_string, expected);
244}
245
246/* Return true if string #a and string #b are equal after their first newline. */
247static bool strings_equal_after_first_lines(const std::string &a, const std::string &b)
248{
249 const size_t a_len = a.size();
250 const size_t b_len = b.size();
251 const size_t a_next = a.find_first_of('\n');
252 const size_t b_next = b.find_first_of('\n');
253 if (a_next == std::string::npos || b_next == std::string::npos) {
254 std::cout << "Couldn't find newline in one of args\n";
255 return false;
256 }
257 if (a.compare(a_next, a_len - a_next, b, b_next, b_len - b_next) != 0) {
258 for (int i = 0; i < a_len - a_next && i < b_len - b_next; ++i) {
259 if (a[a_next + i] != b[b_next + i]) {
260 std::cout << "Difference found at pos " << a_next + i << " of a\n";
261 std::cout << "a: " << a.substr(a_next + i, 100) << " ...\n";
262 std::cout << "b: " << b.substr(b_next + i, 100) << " ... \n";
263 return false;
264 }
265 }
266 return false;
267 }
268 return true;
269}
270
271/* From here on, tests are whole file tests, testing for golden output. */
273 public:
281 void compare_obj_export_to_golden(const std::string &blendfile,
282 const std::string &golden_obj,
283 const std::string &golden_mtl,
285 {
286 if (!load_file_and_depsgraph(blendfile)) {
287 return;
288 }
289 /* Because testing doesn't fully initialize Blender, we need the following. */
290 BKE_tempdir_init(nullptr);
291 std::string tempdir = std::string(BKE_tempdir_base());
292 std::string out_file_path = tempdir + BLI_path_basename(golden_obj.c_str());
293 STRNCPY(params.filepath, out_file_path.c_str());
294 params.blen_filepath = bfile->main->filepath;
295 std::string golden_file_path = blender::tests::flags_test_asset_dir() + SEP_STR + golden_obj;
297 golden_file_path.c_str(), params.file_base_for_tests, sizeof(params.file_base_for_tests));
298 export_frame(depsgraph, params, out_file_path.c_str());
299 std::string output_str = read_temp_file_in_string(out_file_path);
300
301 std::string golden_str = read_temp_file_in_string(golden_file_path);
302 bool are_equal = strings_equal_after_first_lines(output_str, golden_str);
303 if (save_failing_test_output && !are_equal) {
304 printf("failing test output in %s\n", out_file_path.c_str());
305 }
306 ASSERT_TRUE(are_equal);
307 if (!save_failing_test_output || are_equal) {
308 BLI_delete(out_file_path.c_str(), false, false);
309 }
310 if (!golden_mtl.empty()) {
311 std::string out_mtl_file_path = tempdir + BLI_path_basename(golden_mtl.c_str());
312 std::string output_mtl_str = read_temp_file_in_string(out_mtl_file_path);
313 std::string golden_mtl_file_path = blender::tests::flags_test_asset_dir() + SEP_STR +
314 golden_mtl;
315 std::string golden_mtl_str = read_temp_file_in_string(golden_mtl_file_path);
316 are_equal = strings_equal_after_first_lines(output_mtl_str, golden_mtl_str);
317 if (save_failing_test_output && !are_equal) {
318 printf("failing test output in %s\n", out_mtl_file_path.c_str());
319 }
320 ASSERT_TRUE(are_equal);
321 if (!save_failing_test_output || are_equal) {
322 BLI_delete(out_mtl_file_path.c_str(), false, false);
323 }
324 }
325 }
326};
327
329{
331 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "all_tris.blend",
332 "io_tests" SEP_STR "obj" SEP_STR "all_tris.obj",
333 "io_tests" SEP_STR "obj" SEP_STR "all_tris.mtl",
334 _export.params);
335}
336
338{
340 _export.params.global_scale = 2.0f;
341 _export.params.export_materials = false;
342 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "all_quads.blend",
343 "io_tests" SEP_STR "obj" SEP_STR "all_quads.obj",
344 "",
345 _export.params);
346}
347
349{
351 _export.params.forward_axis = IO_AXIS_Y;
352 _export.params.up_axis = IO_AXIS_Z;
353 _export.params.export_materials = false;
354 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "fgons.blend",
355 "io_tests" SEP_STR "obj" SEP_STR "fgons.obj",
356 "",
357 _export.params);
358}
359
361{
363 _export.params.forward_axis = IO_AXIS_Y;
364 _export.params.up_axis = IO_AXIS_Z;
365 _export.params.export_materials = false;
366 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "edges.blend",
367 "io_tests" SEP_STR "obj" SEP_STR "edges.obj",
368 "",
369 _export.params);
370}
371
373{
375 _export.params.forward_axis = IO_AXIS_Y;
376 _export.params.up_axis = IO_AXIS_Z;
377 _export.params.export_materials = false;
378 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR
379 "cube_loose_edges_verts.blend",
380 "io_tests" SEP_STR "obj" SEP_STR "cube_loose_edges_verts.obj",
381 "",
382 _export.params);
383}
384
386{
388 _export.params.forward_axis = IO_AXIS_Y;
389 _export.params.up_axis = IO_AXIS_Z;
390 _export.params.export_materials = false;
391 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "vertices.blend",
392 "io_tests" SEP_STR "obj" SEP_STR "vertices.obj",
393 "",
394 _export.params);
395}
396
398{
400 _export.params.export_materials = false;
401 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR
402 "non_uniform_scale.blend",
403 "io_tests" SEP_STR "obj" SEP_STR "non_uniform_scale.obj",
404 "",
405 _export.params);
406}
407
409{
411 _export.params.forward_axis = IO_AXIS_Y;
412 _export.params.up_axis = IO_AXIS_Z;
413 _export.params.export_materials = false;
414 _export.params.export_curves_as_nurbs = true;
415 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "nurbs.blend",
416 "io_tests" SEP_STR "obj" SEP_STR "nurbs.obj",
417 "",
418 _export.params);
419}
420
421TEST_F(OBJExportRegressionTest, nurbs_curves_as_nurbs)
422{
424 _export.params.forward_axis = IO_AXIS_Y;
425 _export.params.up_axis = IO_AXIS_Z;
426 _export.params.export_materials = false;
427 _export.params.export_curves_as_nurbs = true;
428 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "nurbs_curves.blend",
429 "io_tests" SEP_STR "obj" SEP_STR "nurbs_curves.obj",
430 "",
431 _export.params);
432}
433
435{
437 _export.params.forward_axis = IO_AXIS_Y;
438 _export.params.up_axis = IO_AXIS_Z;
439 _export.params.export_materials = false;
440 _export.params.export_curves_as_nurbs = false;
441 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "nurbs.blend",
442 "io_tests" SEP_STR "obj" SEP_STR "nurbs_mesh.obj",
443 "",
444 _export.params);
445}
446
447TEST_F(OBJExportRegressionTest, cube_all_data_triangulated)
448{
450 _export.params.forward_axis = IO_AXIS_Y;
451 _export.params.up_axis = IO_AXIS_Z;
452 _export.params.export_materials = false;
453 _export.params.export_triangulated_mesh = true;
454 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "cube_all_data.blend",
455 "io_tests" SEP_STR "obj" SEP_STR "cube_all_data_triangulated.obj",
456 "",
457 _export.params);
458}
459
461{
463 _export.params.forward_axis = IO_AXIS_Y;
464 _export.params.up_axis = IO_AXIS_Z;
465 _export.params.export_materials = false;
466 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR
467 "cube_normal_edit.blend",
468 "io_tests" SEP_STR "obj" SEP_STR "cube_normal_edit.obj",
469 "",
470 _export.params);
471}
472
473TEST_F(OBJExportRegressionTest, cube_vertex_groups)
474{
476 _export.params.export_materials = false;
477 _export.params.export_normals = false;
478 _export.params.export_uv = false;
479 _export.params.export_vertex_groups = true;
480 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR
481 "cube_vertex_groups.blend",
482 "io_tests" SEP_STR "obj" SEP_STR "cube_vertex_groups.obj",
483 "",
484 _export.params);
485}
486
488{
490 _export.params.export_materials = false;
491 _export.params.global_scale = 2.0f;
492 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR
493 "cubes_positioned.blend",
494 "io_tests" SEP_STR "obj" SEP_STR "cubes_positioned.obj",
495 "",
496 _export.params);
497}
498
499TEST_F(OBJExportRegressionTest, cubes_vertex_colors)
500{
502 _export.params.export_colors = true;
503 _export.params.export_normals = false;
504 _export.params.export_uv = false;
505 _export.params.export_materials = false;
506 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR
507 "cubes_vertex_colors.blend",
508 "io_tests" SEP_STR "obj" SEP_STR "cubes_vertex_colors.obj",
509 "",
510 _export.params);
511}
512
513TEST_F(OBJExportRegressionTest, cubes_with_textures_strip)
514{
517 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR
518 "cubes_with_textures.blend",
519 "io_tests" SEP_STR "obj" SEP_STR "cubes_with_textures.obj",
520 "io_tests" SEP_STR "obj" SEP_STR "cubes_with_textures.mtl",
521 _export.params);
522}
523
524TEST_F(OBJExportRegressionTest, cubes_with_textures_relative)
525{
528 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR
529 "cubes_with_textures.blend",
530 "io_tests" SEP_STR "obj" SEP_STR "cubes_with_textures_rel.obj",
531 "io_tests" SEP_STR "obj" SEP_STR "cubes_with_textures_rel.mtl",
532 _export.params);
533}
534
536{
538 _export.params.forward_axis = IO_AXIS_Y;
539 _export.params.up_axis = IO_AXIS_Z;
540 _export.params.export_materials = false;
541 _export.params.export_smooth_groups = true;
542 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR
543 "suzanne_all_data.blend",
544 "io_tests" SEP_STR "obj" SEP_STR "suzanne_all_data.obj",
545 "",
546 _export.params);
547}
548
550{
552 _export.params.export_materials = false;
553 compare_obj_export_to_golden("io_tests" SEP_STR "blend_scene" SEP_STR "all_curves.blend",
554 "io_tests" SEP_STR "obj" SEP_STR "all_curves.obj",
555 "",
556 _export.params);
557}
558
559TEST_F(OBJExportRegressionTest, all_curves_as_nurbs)
560{
562 _export.params.export_materials = false;
563 _export.params.export_curves_as_nurbs = true;
564 compare_obj_export_to_golden("io_tests" SEP_STR "blend_scene" SEP_STR "all_curves.blend",
565 "io_tests" SEP_STR "obj" SEP_STR "all_curves_as_nurbs.obj",
566 "",
567 _export.params);
568}
569
571{
573 _export.params.forward_axis = IO_AXIS_Y;
574 _export.params.up_axis = IO_AXIS_Z;
575 _export.params.export_smooth_groups = true;
576 _export.params.export_colors = true;
577 compare_obj_export_to_golden("io_tests" SEP_STR "blend_scene" SEP_STR "all_objects.blend",
578 "io_tests" SEP_STR "obj" SEP_STR "all_objects.obj",
579 "io_tests" SEP_STR "obj" SEP_STR "all_objects.mtl",
580 _export.params);
581}
582
583TEST_F(OBJExportRegressionTest, all_objects_mat_groups)
584{
586 _export.params.forward_axis = IO_AXIS_Y;
587 _export.params.up_axis = IO_AXIS_Z;
588 _export.params.export_smooth_groups = true;
589 _export.params.export_material_groups = true;
590 compare_obj_export_to_golden("io_tests" SEP_STR "blend_scene" SEP_STR "all_objects.blend",
591 "io_tests" SEP_STR "obj" SEP_STR "all_objects_mat_groups.obj",
592 "io_tests" SEP_STR "obj" SEP_STR "all_objects_mat_groups.mtl",
593 _export.params);
594}
595
596TEST_F(OBJExportRegressionTest, materials_without_pbr)
597{
599 _export.params.export_normals = false;
601 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "materials_pbr.blend",
602 "io_tests" SEP_STR "obj" SEP_STR "materials_without_pbr.obj",
603 "io_tests" SEP_STR "obj" SEP_STR "materials_without_pbr.mtl",
604 _export.params);
605}
606
608{
610 _export.params.export_normals = false;
612 _export.params.export_pbr_extensions = true;
613 compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "materials_pbr.blend",
614 "io_tests" SEP_STR "obj" SEP_STR "materials_pbr.obj",
615 "io_tests" SEP_STR "obj" SEP_STR "materials_pbr.mtl",
616 _export.params);
617}
618
619} // namespace blender::io::obj
void BKE_tempdir_init(const char *userdir)
Definition appdir.cc:1190
const char * BKE_tempdir_base() ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition appdir.cc:1211
void BKE_tempdir_session_purge()
Definition appdir.cc:1216
const char * BKE_blender_version_string(void)
Definition blender.cc:139
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
File and directory operations.
int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL()
void * BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size)
Definition storage.cc:502
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAX
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
#define STRNCPY(dst, src)
Definition BLI_string.h:593
external readfile function prototypes.
eEvaluationMode
@ DAG_EVAL_VIEWPORT
@ IO_AXIS_Y
@ IO_AXIS_Z
@ PATH_REFERENCE_RELATIVE
@ PATH_REFERENCE_STRIP
virtual void depsgraph_create(eEvaluationMode depsgraph_evaluation_mode)
bool blendfile_load(const char *filepath)
std::string get_as_string() const
void compare_obj_export_to_golden(const std::string &blendfile, const std::string &golden_obj, const std::string &golden_mtl, OBJExportParams &params)
bool load_file_and_depsgraph(const std::string &filepath, const eEvaluationMode eval_mode=DAG_EVAL_VIEWPORT)
std::unique_ptr< OBJWriter > init_writer(const OBJExportParams &params, const std::string &out_filepath)
local_group_size(16, 16) .push_constant(Type b
#define printf
const Depsgraph * depsgraph
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
bool append_frame_to_filename(const char *filepath, const int frame, char r_filepath_with_frames[1024])
static bool strings_equal_after_first_lines(const std::string &a, const std::string &b)
TEST_F(OBJExportTest, filter_objects_curves_as_mesh)
TEST(obj_exporter_utils, append_negative_frame_to_filename)
constexpr bool save_failing_test_output
const std::string all_objects_file
static std::string read_temp_file_in_string(const std::string &file_path)
std::pair< Vector< std::unique_ptr< OBJMesh > >, Vector< std::unique_ptr< OBJCurve > > > filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_params)
void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, const char *filepath)
char filepath[1024]
Definition BKE_main.hh:136
ePathReferenceMode path_mode
void * BKE_tempdir_session
Definition stubs.c:38
#define SEP_STR
Definition unit.cc:39