NVIDIA Index example code nvidia_logo_transpbg.gif Up
create_irregular_volume.cpp
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright 2023 NVIDIA Corporation. All rights reserved.
3 *****************************************************************************/
6
7#include <mi/dice.h>
8
9// Include code shared by all examples.
10#include "utility/example_shared.h"
11
12#include <nv/index/icamera.h>
13#include <nv/index/iindex.h>
14#include <nv/index/ilight.h>
15#include <nv/index/imaterial.h>
16#include <nv/index/iirregular_volume_scene_element.h>
17#include <nv/index/iirregular_volume_subset.h>
18#include <nv/index/iscene.h>
19#include <nv/index/iconfig_settings.h>
20#include <nv/index/iscene_group.h>
21#include <nv/index/isession.h>
22#include <nv/index/icolormap.h>
23#include <nv/index/itexture.h>
24#include <nv/index/ishading_model.h>
25
26#include <nv/index/app/index_connect.h>
27#include <nv/index/app/string_dict.h>
28
29#include "utility/app_rendering_context.h"
30#include "utility/canvas_utility.h"
31
32#include <iostream>
33#include <sstream>
34
35//----------------------------------------------------------------------
37 public nv::index::app::Index_connect
38{
39public:
41 :
42 Index_connect()
43 {
44 // INFO_LOG << "DEBUG: Create_irregular_volume() ctor";
45 }
46
48 {
49 // Note: Index_connect::~Index_connect() will be called after here.
50 // INFO_LOG << "DEBUG: ~Create_irregular_volume() dtor";
51 }
52
53 // launch application
54 mi::Sint32 launch();
55
56protected:
57 virtual bool evaluate_options(nv::index::app::String_dict& sdict) CPP11_OVERRIDE;
58 // override
60 mi::neuraylib::INetwork_configuration* network_configuration,
61 nv::index::app::String_dict& options) CPP11_OVERRIDE
62 {
63 check_success(network_configuration != 0);
64
65 check_success(options.is_defined("unittest"));
66 const bool is_unittest = nv::index::app::get_bool(options.get("unittest"));
67 if (is_unittest)
68 {
69 info_cout("NETWORK: disabled networking mode.", options);
70 network_configuration->set_mode(mi::neuraylib::INetwork_configuration::MODE_OFF);
71 return true;
72 }
73
74 return initialize_networking_as_default_udp(network_configuration, options);
75 }
76 // override
78 mi::neuraylib::IDebug_configuration* debug_configuration,
79 nv::index::app::String_dict& options) CPP11_OVERRIDE
80 {
81 check_success(debug_configuration != 0);
82 debug_configuration->set_option("check_serializer_store=1");
83 return true;
84 }
85private:
86 nv::index::IColormap* create_colormap(nv::index::IScene* scene);
87
88 // Create the scene with an irregular volume.
89 //
90 // \param[in] ivol_file an irregular volume file name.
91 // \param[in] ivol_bbox bounding box of the irregular volume, this is also needed for the view computation.
92 // \param[in] ivol_max_seg_len length of the longest edge in the irregular volume mesh.
93 // \param[in] scene_edit IScene interface
94 // \param[in] dice_transaction dice transaction
95 //
96 // \return true when success
97 //
98 bool create_scene(
99 const std::string& ivol_file,
100 const mi::math::Bbox<mi::Float32, 3>& ivol_bbox,
101 const mi::Float32 ivol_max_seg_len,
102 nv::index::IScene* scene_edit,
103 mi::neuraylib::IDice_transaction* dice_transaction);
104
105 // setup camera to see this example scene
106 //
107 // \param[in] cam a camera
108 void setup_camera(nv::index::IPerspective_camera* cam) const;
109
110 void view_all_bbox(
111 const mi::math::Vector<mi::Float32, 3>& from,
112 const mi::math::Vector<mi::Float32, 3>& up,
113 const mi::math::Bbox< mi::Float32, 3 >& bbox,
114 const mi::neuraylib::Tag& camera_tag,
115 nv::index::IScene* scene_edit,
116 mi::neuraylib::IDice_transaction* dice_transaction) const;
117
118 // render a frame
119 //
120 // \param[in] output_fname output rendering image filename
121 // \return performance values
122 nv::index::IFrame_results* render_frame(const std::string& output_fname) const;
123
124
125 // This session tag
126 mi::neuraylib::Tag m_session_tag;
127 // NVIDIA IndeX cluster configuration
128 mi::base::Handle<nv::index::ICluster_configuration> m_cluster_configuration;
129 // Application layer image file canvas (a render target)
130 mi::base::Handle<nv::index::app::canvas_infrastructure::IIndex_image_file_canvas> m_image_file_canvas;
131
132 // Create_irregular_volume
133 bool m_is_unittest;
134 std::string m_ivol_file;
135 mi::Float32 m_ivol_max_seg_len;
136 mi::math::Bbox<mi::Float32,3> m_roi;
137 bool m_ivol_set_pickable;
138 std::string m_outfname;
139 std::string m_verify_image_fname;
140 bool m_supersampling;
141};
142
143//----------------------------------------------------------------------
145{
146 mi::Sint32 exit_code = 0;
147
148 // Get DiCE database components
149 {
150 m_cluster_configuration = get_index_interface()->get_api_component<nv::index::ICluster_configuration>();
151 check_success(m_cluster_configuration.is_valid_interface());
152
153 // create image canvas in application_layer
154 m_image_file_canvas = create_image_file_canvas(get_application_layer_interface());
155 check_success(m_image_file_canvas.is_valid_interface());
156
157 mi::base::Handle<nv::index::IIndex_scene_query> iindex_query(
158 get_index_interface()->get_api_component<nv::index::IIndex_scene_query>());
159 check_success(iindex_query.is_valid_interface());
160
161 // Verifying that local host has joined. This may fail when there is a license problem.
162 check_success(is_local_host_joined(m_cluster_configuration.get()));
163 {
164 // DiCE database access
165 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(
166 m_global_scope->create_transaction<mi::neuraylib::IDice_transaction>());
167 check_success(dice_transaction.is_valid_interface());
168 {
169 // Setup session information
170 m_session_tag = m_index_session->create_session(dice_transaction.get());
171 check_success(m_session_tag.is_valid());
172 mi::base::Handle<const nv::index::ISession> session(
173 dice_transaction->access<const nv::index::ISession>(m_session_tag));
174 check_success(session.is_valid_interface());
175
176 mi::base::Handle< nv::index::IScene > scene_edit(
177 dice_transaction->edit< nv::index::IScene >(session->get_scene()));
178 check_success(scene_edit.is_valid_interface());
179
180 // Enable supersampling
181 if (m_supersampling)
182 {
183 mi::base::Handle<nv::index::IConfig_settings> config_settings(
184 dice_transaction->edit<nv::index::IConfig_settings>(session->get_config()));
185 check_success(config_settings.is_valid_interface());
186
187 config_settings->set_rendering_samples(8);
188 }
189
190 //----------------------------------------------------------------------
191 // Scene setup: hierarchical scene description root node,
192 // scene parameters, camera.
193 //----------------------------------------------------------------------
194 // Create a hierarchical scene description that contains the triangle mesh
195 check_success(create_scene(m_ivol_file, m_roi, m_ivol_max_seg_len, scene_edit.get(), dice_transaction.get()));
196
197 // Create and edit a camera. Data distribution is based on
198 // the camera. (Because only visible massive data are
199 // considered)
200 mi::base::Handle< nv::index::IPerspective_camera > cam(
201 scene_edit->create_camera<nv::index::IPerspective_camera>());
202 check_success(cam.is_valid_interface());
203 setup_camera(cam.get());
204 const mi::neuraylib::Tag camera_tag = dice_transaction->store(cam.get());
205 check_success(camera_tag.is_valid());
206
207 const mi::math::Vector<mi::Uint32, 2> buffer_resolution(1024, 1024);
208 m_image_file_canvas->set_resolution(buffer_resolution);
209
210 // Set up the scene
211 // const mi::math::Bbox< mi::Float32, 3 > xyz_roi_st = m_roi;
212
213 // The the colormap to demonstrate color index color mapping.
214 mi::base::Handle<nv::index::IColormap> colormap(create_colormap(scene_edit.get()));
215 check_success(colormap.is_valid_interface());
216
217 // Store in DiCE database.
218 const mi::neuraylib::Tag colormap_tag = dice_transaction->store_for_reference_counting(
219 colormap.get(), mi::neuraylib::NULL_TAG, "colormap");
220 check_success(colormap_tag.is_valid());
221 scene_edit->prepend(colormap_tag, dice_transaction.get());
222
223 // Set the region of interest.
224 check_success(m_roi.is_volume());
225 scene_edit->set_clipped_bounding_box(m_roi);
226
227 // Set the scene global transformation matrix.
228 // only change the coordinate system
229 mi::math::Matrix<mi::Float32, 4, 4> transform_mat(
230 1.0f, 0.0f, 0.0f, 0.0f,
231 0.0f, 1.0f, 0.0f, 0.0f,
232 0.0f, 0.0f, -1.0f, 0.0f,
233 0.0f, 0.0f, 0.0f, 1.0f
234 );
235
236 scene_edit->set_transform_matrix(transform_mat);
237
238 // Set the current camera to the scene.
239 scene_edit->set_camera(camera_tag);
240
241 const mi::math::Vector<mi::Float32, 3> from(0.0f, 0.0f, 1.0f);
242 const mi::math::Vector<mi::Float32, 3> up (0.0f, 1.0f, 0.0f);
243 view_all_bbox(from, up, m_roi, camera_tag, scene_edit.get(), dice_transaction.get());
244 }
245 dice_transaction->commit();
246 }
247
248 // Rendering
249 {
250 // Render a frame and save the rendered image to a file.
251 const mi::Sint32 frame_idx = 0;
252 const std::string fname = get_output_file_name(m_outfname, frame_idx);
253
254 mi::base::Handle<nv::index::IFrame_results> frame_results(render_frame(fname));
255 const mi::base::Handle<nv::index::IError_set> err_set(frame_results->get_error_set());
256 if (err_set->any_errors())
257 {
258 std::ostringstream os;
259
260 const mi::Uint32 nb_err = err_set->get_nb_errors();
261 for (mi::Uint32 e = 0; e < nb_err; ++e)
262 {
263 if (e != 0) os << '\n';
264 const mi::base::Handle<nv::index::IError> err(err_set->get_error(e));
265 os << err->get_error_string();
266 }
267
268 ERROR_LOG << "IIndex_rendering rendering call failed with the following error(s): " << '\n'
269 << os.str();
270 exit_code = 1;
271 }
272
273 // verify the generated frame
274 if (!(verify_canvas_result(get_application_layer_interface(),
275 m_image_file_canvas.get(), m_verify_image_fname, get_options())))
276 {
277 exit_code = 1;
278 }
279 }
280 }
281
282 return exit_code;
283}
284//----------------------------------------------------------------------
285bool Create_irregular_volume::evaluate_options(nv::index::app::String_dict& sdict)
286{
287 const std::string com_name = sdict.get("command:", "<unknown_command>");
288 m_is_unittest = nv::index::app::get_bool(sdict.get("unittest", "false"));
289
290 if (m_is_unittest)
291 {
292 if (nv::index::app::get_bool(sdict.get("is_call_from_test", "false")))
293 {
294 sdict.insert("is_dump_comparison_image_when_failed", "0");
295 }
296 sdict.insert("outfname", ""); // turn off file output in the unit test mode
297 sdict.insert("dice::verbose", "2");
298 }
299
300 // Set own options
301 m_ivol_file = sdict.get("ivol_file");
302 m_ivol_max_seg_len = nv::index::app::get_float32(sdict.get("ivol_max_seg_len"));
303 m_roi = nv::index::app::get_bbox_from_string<mi::Float32,3>(std::string(sdict.get("roi")));
304 m_ivol_set_pickable = nv::index::app::get_bool(sdict.get("ivol_set_pickable"));
305 m_outfname = sdict.get("outfname", "");
306 m_verify_image_fname = sdict.get("verify_image_fname", "");
307 m_supersampling = nv::index::app::get_bool(sdict.get("supersampling"));
308
309 info_cout(std::string("running ") + com_name, sdict);
310 info_cout(std::string("outfname = [") + m_outfname +
311 "], verify_image_fname = [" + m_verify_image_fname +
312 "], dice::verbose = " + sdict.get("dice::verbose"), sdict);
313
314 // print help and exit if -h
315 if(sdict.is_defined("h"))
316 {
317 std::cout
318 << "info: Usage: " << com_name << " [option]\n"
319 << "Option: [-h]\n"
320 << " printout this message\n"
321
322 << " [-dice::verbose severity_level]\n"
323 << " verbose severity level (3 is info.). (default: " + sdict.get("dice::verbose")
324 << ")\n"
325
326 << " [-ivol_file string]\n"
327 << " name of the irregular volume file (in .ts format). When empty, the default file will be used.\n"
328 << " (default: [" << m_ivol_file << "])\n"
329
330 << " [-ivol_max_seg_len float]\n"
331 << " the length of the longest edge in the irregular volume mesh.\n"
332 << " (default: [" << m_ivol_max_seg_len << "])\n"
333
334 << " [-roi \"float float float float float float\"]\n"
335 << " the bounding box representing the region of interest (roi).\n"
336 << " (default: [" << m_roi << "])\n"
337
338 << " [-ivol_set_pickable bool]\n"
339 << " enable/disable picking for the mesh."
340 << "(default: " << m_ivol_set_pickable << ")\n"
341
342 << " [-outfname string]\n"
343 << " name of the output ppm image file. When empty, no image file will be written.\n"
344 << " A frame number and the extension (.ppm) will be added.\n"
345 << " (default: [" << m_outfname << "])\n"
346
347 << " [-verify_image_fname [image_fname]]\n"
348 << " when image_fname exist, verify the rendering image. (default: ["
349 << m_verify_image_fname << "])\n"
350
351 << " [-supersampling bool]\n"
352 << " when true then supersampling is enabled."
353 << " (default: " << m_supersampling << ")\n"
354
355 << " [-unittest bool]\n"
356 << " when true, unit test mode."
357 << " (default: " << m_is_unittest << ")"
358 << std::endl;
359 exit(1);
360 }
361 return true;
362}
363
364//----------------------------------------------------------------------
365nv::index::IColormap* Create_irregular_volume::create_colormap(nv::index::IScene* scene)
366{
367 nv::index::IColormap* colormap = scene->create_attribute<nv::index::IColormap>();
368 std::vector<mi::math::Color_struct> colormap_entries;
369
370 colormap_entries.resize(256);
371 for(mi::Uint32 i=0; i<256; ++i)
372 {
373 colormap_entries[i].r = (256.f-static_cast<mi::Float32>(i))/256.f;
374 colormap_entries[i].g = (256.f-static_cast<mi::Float32>(255 - i))/256.f;
375 colormap_entries[i].b = 1.f;
376 colormap_entries[i].a = 0.5f;
377 }
378
379 // Set colormap domain
380 colormap->set_domain_boundary_mode(nv::index::IColormap::CLAMP_TO_EDGE);
381 colormap->set_domain(0.2f, 1.0f);
382
383 // Set the the colormap values.
384 colormap->set_colormap(&(colormap_entries[0]), colormap_entries.size());
385 return colormap;
386}
387
388//----------------------------------------------------------------------
389bool Create_irregular_volume::create_scene(
390 const std::string& ivol_file,
391 const mi::math::Bbox<mi::Float32, 3>& ivol_bbox,
392 const mi::Float32 ivol_max_seg_len,
393 nv::index::IScene* scene_edit,
394 mi::neuraylib::IDice_transaction* dice_transaction)
395{
396 check_success(scene_edit != 0);
397 check_success(dice_transaction != 0);
398
399 // Irregular volume
400 std::stringstream sstr;
401 sstr << m_roi.min.x << " " << m_roi.min.y << " " << m_roi.min.z << " "
402 << m_roi.max.x << " " << m_roi.max.y << " " << m_roi.max.z;
403 const std::string roi_str = sstr.str();
404
405 nv::index::app::String_dict irregular_volume_opt;
406 irregular_volume_opt.insert("args::type", "sparse_volume");
407 irregular_volume_opt.insert("args::importer", "nv::index::plugin::base_importer.Irregular_volume_importer");
408 irregular_volume_opt.insert("args::input_file", m_ivol_file.c_str());
409 irregular_volume_opt.insert("args::bbox", roi_str.c_str());
410
411 nv::index::IDistributed_data_import_callback* importer_callback =
412 get_importer_from_application_layer(get_application_layer_interface(),
413 "nv::index::plugin::base_importer.Irregular_volume_importer",
414 irregular_volume_opt);
415
416 // Create the triangle mesh scene element
417 mi::base::Handle<nv::index::IIrregular_volume_scene_element> ivol_elem(
418 scene_edit->create_irregular_volume(ivol_bbox, ivol_max_seg_len, importer_callback, dice_transaction));
419 check_success(ivol_elem != 0);
420
421 // Scene element properties
422 ivol_elem->set_enabled(true);
423 ivol_elem->set_pickable(m_ivol_set_pickable);
424
425 // Storing the irregular volume in the data (base) store
426 mi::neuraylib::Tag ivol_tag = dice_transaction->store_for_reference_counting(ivol_elem.get());
427 check_success(ivol_tag.is_valid());
428
429 // Create a static scene group
430 mi::base::Handle<nv::index::IStatic_scene_group> static_group(
431 scene_edit->create_scene_group<nv::index::IStatic_scene_group>());
432 check_success(static_group.is_valid_interface());
433
434 // append mesh to the static scene group
435 static_group->append(ivol_tag, dice_transaction);
436
437 mi::neuraylib::Tag static_group_tag = dice_transaction->store(static_group.get());
438 check_success(static_group_tag.is_valid());
439
440 // append the static scene group to the hierachical scene description.
441 scene_edit->append(static_group_tag, dice_transaction);
442
443 return true;
444}
445
446//----------------------------------------------------------------------
447void Create_irregular_volume::setup_camera(nv::index::IPerspective_camera* cam) const
448{
449 check_success(cam != 0);
450
451 // Initialize the camera with some default parameters ...
452 const mi::math::Vector< mi::Float32, 3 > from( 0.0f, 0.0f,-5.0f);
453 const mi::math::Vector< mi::Float32, 3 > to ( 0.0f, 0.0f, 0.0f);
454 const mi::math::Vector< mi::Float32, 3 > up ( 0.0f, 1.0f, 0.0f);
455 mi::math::Vector<mi::Float32, 3> viewdir = to - from;
456 viewdir.normalize();
457
458 cam->set(from, viewdir, up);
459 cam->set_aperture(0.033f);
460 cam->set_aspect(1.0f);
461 cam->set_focal(0.03f);
462 cam->set_clip_min(10.0f);
463 cam->set_clip_max(5000.0f);
464}
465
466//----------------------------------------------------------------------
467void Create_irregular_volume::view_all_bbox(
468 const mi::math::Vector<mi::Float32, 3>& from,
469 const mi::math::Vector<mi::Float32, 3>& up,
470 const mi::math::Bbox< mi::Float32, 3 >& bbox,
471 const mi::neuraylib::Tag& camera_tag,
472 nv::index::IScene* scene_edit,
473 mi::neuraylib::IDice_transaction* dice_transaction) const
474{
475 check_success(dice_transaction != 0);
476
477 if(bbox.empty())
478 {
479 WARN_LOG << "Un-initialized bounding box and not updating the camera settings.";
480 return;
481 }
482
483 {
484 mi::base::Handle<nv::index::IPerspective_camera> camera(dice_transaction->edit<nv::index::IPerspective_camera>(camera_tag));
485 check_success(camera.is_valid_interface());
486
487 // Compute the new camera parameters
488 const mi::math::Bbox< mi::Float32, 3 >& global_roi_bbox = scene_edit->get_clipped_bounding_box();
489 const mi::math::Matrix<mi::Float32, 4, 4>& transform_mat = scene_edit->get_transform_matrix();
490 const mi::math::Vector<mi::Float32, 3> new_min(mi::math::transform_point(transform_mat, global_roi_bbox.min));
491 const mi::math::Vector<mi::Float32, 3> new_max(mi::math::transform_point(transform_mat, global_roi_bbox.max));
492 const mi::math::Bbox< mi::Float32, 3 > transformed_bbox(new_min, new_max);
493 const mi::math::Vector<mi::Float32, 3>& min = transformed_bbox.min;
494 const mi::math::Vector<mi::Float32, 3>& max = transformed_bbox.max;
495 const mi::math::Vector<mi::Float32, 3>& center = transformed_bbox.center();
496 const mi::Float32 rad = mi::math::euclidean_distance(max, min) / 2.0f;
497
498 const mi::Float32 fov_rad_2 = static_cast<mi::Float32>(camera->get_fov_y_rad() / 2.0);
499 const mi::Float32 dist = rad / static_cast<mi::Float32>(tan(fov_rad_2));
500
501 const mi::math::Vector<mi::Float32, 3> eyepos = -(1.f * dist * from) + center;
502 camera->set_eye_point(eyepos);
503 camera->set_up_direction(up);
504
505 const mi::Float32 clip_min = 0.1f * dist;
506 const mi::Float32 clip_max = 10.0f * 1.f * dist;
507
508 camera->set_clip_min(clip_min);
509 camera->set_clip_max(clip_max);
510
511 mi::math::Vector<mi::Float32, 3> viewdir = center - eyepos;
512 check_success(viewdir.normalize());
513 camera->set_view_direction(viewdir);
514 }
515}
516
517//----------------------------------------------------------------------
518nv::index::IFrame_results* Create_irregular_volume::render_frame(
519 const std::string& output_fname) const
520{
521 check_success(m_index_rendering.is_valid_interface());
522
523 // set output filename, empty string is valid
524 m_image_file_canvas->set_rgba_file_name(output_fname.c_str());
525
526 check_success(m_session_tag.is_valid());
527
528 mi::base::Handle<mi::neuraylib::IDice_transaction> dice_transaction(
529 m_global_scope->create_transaction<mi::neuraylib::IDice_transaction>());
530 check_success(dice_transaction.is_valid_interface());
531
532 m_index_session->update(m_session_tag, dice_transaction.get());
533
534 mi::base::Handle<nv::index::IFrame_results> frame_results(
535 m_index_rendering->render(
536 m_session_tag,
537 m_image_file_canvas.get(),
538 dice_transaction.get()));
539 check_success(frame_results.is_valid_interface());
540
541 dice_transaction->commit();
542
543 frame_results->retain();
544 return frame_results.get();
545}
546
547//----------------------------------------------------------------------
548int main(int argc, const char* argv[])
549{
550 nv::index::app::String_dict sdict;
551 sdict.insert("dice::verbose", "3"); // log level
552 sdict.insert("ivol_file", "../create_irregular_volume/spx.ts"); // input triangle mesh file name
553 sdict.insert("ivol_max_seg_len", "1.07534"); // maximum segment length in the irregular volume mesh
554 sdict.insert("roi", "4.061 0.000 -8.670 10.000 6.947 0.725"); // input roi
555 sdict.insert("outfname", "frame_create_irregular_volume"); // output file base name
556 sdict.insert("verify_image_fname", ""); // for unit test
557 sdict.insert("unittest", "0"); // default mode
558 sdict.insert("supersampling", "0"); // disable supersampling (default)
559 sdict.insert("ivol_set_pickable", "1"); // define is the mesh shall be pickable
560 sdict.insert("is_dump_comparison_image_when_failed", "1"); // default: dump images when failed.
561 sdict.insert("is_call_from_test", "0"); // default: not call from make check.
562
563 // Load IndeX library via Index_connect
564 sdict.insert("dice::network::mode", "OFF");
565
566 // index setting
567 sdict.insert("index::config::set_monitor_performance_values", "true");
568 sdict.insert("index::service", "rendering_and_compositing");
569 sdict.insert("index::cuda_debug_checks", "false");
570
571 // application_layer component loading
572 sdict.insert("index::app::components::application_layer::component_name_list",
573 "canvas_infrastructure image io");
574 sdict.insert("index::app::plugins::base_importer::enabled", "true");
575
576 Create_irregular_volume create_irregular_volume;
577 create_irregular_volume.initialize(argc, argv, sdict);
578
579 // launch the application. creating the scene and rendering.
580 const mi::Sint32 exit_code = create_irregular_volume.launch();
581 INFO_LOG << "Shutting down ...";
582
583 return exit_code;
584}
virtual bool initialize_debug_configuration(mi::neuraylib::IDebug_configuration *debug_configuration, nv::index::app::String_dict &options) CPP11_OVERRIDE
virtual bool initialize_networking(mi::neuraylib::INetwork_configuration *network_configuration, nv::index::app::String_dict &options) CPP11_OVERRIDE
virtual bool evaluate_options(nv::index::app::String_dict &sdict) CPP11_OVERRIDE
int main(int argc, const char *argv[])
#define check_success(expr)